source: rtems/c/src/libchip/network/greth.c @ ac5b81c3

4.104.114.84.95
Last change on this file since ac5b81c3 was ac5b81c3, checked in by Joel Sherrill <joel.sherrill@…>, on 09/01/06 at 21:20:47

2006-09-01 Joel Sherrill <joel@…>

  • libchip/network/greth.c, libchip/network/open_eth.c, libchip/network/smc91111.c: Remove warnings and correct prototype added earlier today.
  • Property mode set to 100644
File size: 15.9 KB
Line 
1/*
2 *  RTEMS driver for Opencores Ethernet Controller
3 *
4 *  Weakly based on dec21140 rtems driver and open_eth linux driver
5 *  Written by Jiri Gaisler, Gaisler Research
6 *
7 *  The license and distribution terms for this file may be
8 *  found in found in the file LICENSE in this distribution or at
9 *  http://www.OARcorp.com/rtems/license.html.
10 *
11 *  $Id$
12 */
13
14#include <rtems.h>
15
16#define GRETH_SUPPORTED
17#include <bsp.h>
18
19#include <inttypes.h>
20#include <errno.h>
21#include <stdlib.h>
22#include <stdio.h>
23#include <stdarg.h>
24#include <rtems/error.h>
25#include <rtems/rtems_bsdnet.h>
26#include "greth.h"
27
28#include <sys/param.h>
29#include <sys/mbuf.h>
30
31#include <sys/socket.h>
32#include <sys/sockio.h>
33#include <net/if.h>
34#include <netinet/in.h>
35#include <netinet/if_ether.h>
36
37#ifdef malloc
38#undef malloc
39#endif
40#ifdef free
41#undef free
42#endif
43
44extern rtems_isr_entry set_vector( rtems_isr_entry, rtems_vector_number, int );
45
46/*
47#define GRETH_DEBUG
48*/
49
50#ifdef CPU_U32_FIX
51extern void ipalign(struct mbuf *m);
52#endif
53
54/*
55 * Number of OCs supported by this driver
56 */
57#define NOCDRIVER       1
58
59/*
60 * Receive buffer size -- Allow for a full ethernet packet including CRC
61 */
62#define RBUF_SIZE 1518
63
64#define ET_MINLEN 64            /* minimum message length */
65
66/*
67 * RTEMS event used by interrupt handler to signal driver tasks.
68 * This must not be any of the events used by the network task synchronization.
69 */
70#define INTERRUPT_EVENT RTEMS_EVENT_1
71
72/*
73 * RTEMS event used to start transmit daemon.
74 * This must not be the same as INTERRUPT_EVENT.
75 */
76#define START_TRANSMIT_EVENT    RTEMS_EVENT_2
77
78 /* event to send when tx buffers become available */
79#define GRETH_TX_WAIT_EVENT  RTEMS_EVENT_3
80
81 /* suspend when all TX descriptors exhausted */
82 /*
83#define GRETH_SUSPEND_NOTXBUF
84 */
85
86#if (MCLBYTES < RBUF_SIZE)
87# error "Driver must have MCLBYTES > RBUF_SIZE"
88#endif
89
90/* Ethernet buffer descriptor */
91
92typedef struct _greth_rxtxdesc {
93   volatile uint32_t ctrl; /* Length and status */
94   uint32_t *addr;         /* Buffer pointer */
95} greth_rxtxdesc;
96
97/*
98 * Per-device data
99 */
100struct greth_softc
101{
102
103   struct arpcom arpcom;
104   
105   greth_regs *regs;
106   
107   int acceptBroadcast;
108   rtems_id rxDaemonTid;
109   rtems_id txDaemonTid;
110   
111   unsigned int tx_ptr;
112   unsigned int rx_ptr;
113   unsigned int txbufs;
114   unsigned int rxbufs;
115   greth_rxtxdesc *txdesc;
116   greth_rxtxdesc *rxdesc;
117   struct mbuf **rxmbuf;
118   rtems_vector_number vector;
119   
120   /*
121    * Statistics
122    */
123   unsigned long rxInterrupts;
124   
125   unsigned long rxPackets;
126   unsigned long rxLengthError;
127   unsigned long rxNonOctet;
128   unsigned long rxBadCRC;
129   unsigned long rxOverrun;
130   
131   unsigned long txInterrupts;
132   
133   unsigned long txDeferred;
134   unsigned long txHeartbeat;
135   unsigned long txLateCollision;
136   unsigned long txRetryLimit;
137   unsigned long txUnderrun;
138};
139
140static struct greth_softc greth;
141
142static char *almalloc(int sz)
143{
144        char *tmp;
145        tmp = calloc(1,2*sz);
146        tmp = (char *) (((int)tmp+sz) & ~(sz -1));
147        return(tmp);
148}
149
150/* GRETH interrupt handler */
151
152static rtems_isr
153greth_interrupt_handler (rtems_vector_number v)
154{
155    uint32_t status;
156    /* read and clear interrupt cause */
157
158    status = greth.regs->status;
159    greth.regs->status = status;
160
161    /* Frame received? */
162    if (status & (GRETH_STATUS_RXERR | GRETH_STATUS_RXIRQ))
163      {
164        greth.rxInterrupts++;
165        rtems_event_send (greth.rxDaemonTid, INTERRUPT_EVENT);
166      }
167#ifdef GRETH_SUSPEND_NOTXBUF
168    if (status & (GRETH_STATUS_TXERR | GRETH_STATUS_TXIRQ))
169      {
170        greth.txInterrupts++;
171        rtems_event_send (greth.txDaemonTid, GRETH_TX_WAIT_EVENT);
172      }
173#endif
174      /*
175#ifdef __leon__
176      LEON_Clear_interrupt(v-0x10);
177#endif
178      */
179}
180
181static uint32_t read_mii(uint32_t addr)
182{
183    while (greth.regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
184    greth.regs->mdio_ctrl = addr << 6 | GRETH_MDIO_READ;
185    while (greth.regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
186    if (!(greth.regs->mdio_ctrl & GRETH_MDIO_LINKFAIL))
187        return((greth.regs->mdio_ctrl >> 16) & 0xFFFF);
188    else {
189        printf("greth: failed to read mii\n");
190        return (0);
191    }
192}
193
194static void write_mii(uint32_t addr, uint32_t data)
195{
196    while (greth.regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
197    greth.regs->mdio_ctrl =
198    ((data & 0xFFFF) << 16) | (addr << 8) | GRETH_MDIO_WRITE;
199    while (greth.regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
200}
201/*
202 * Initialize the ethernet hardware
203 */
204static void
205greth_initialize_hardware (struct greth_softc *sc)
206{
207    struct mbuf *m;
208    int i;
209    int fd;
210   
211    greth_regs *regs;
212
213    regs = sc->regs;
214
215    /* Reset the controller.  */
216    greth.rxInterrupts = 0;
217    greth.rxPackets = 0;
218
219    regs->ctrl = 0;
220    regs->ctrl = GRETH_CTRL_RST;        /* Reset ON */
221    regs->ctrl = 0;                     /* Reset OFF */
222   
223    /* reset PHY and wait for complettion */
224    /*
225    */
226    write_mii(0, 0x8000);
227    while (read_mii(0) & 0x8000) {}
228    fd = regs->mdio_ctrl >> 24; /*duplex mode*/
229    printf(
230      "greth: driver attached, PHY config: 0x%04" PRIx32 "\n", read_mii(0));
231
232    /* Initialize rx/tx descriptor pointers */
233    sc->txdesc = (greth_rxtxdesc *) almalloc(1024);
234    sc->rxdesc = (greth_rxtxdesc *) almalloc(1024);
235    sc->tx_ptr = 0;
236    sc->rx_ptr = 0;
237    regs->txdesc = (int) sc->txdesc;
238    regs->rxdesc = (int) sc->rxdesc;
239   
240    sc->rxmbuf = calloc(sc->rxbufs, sizeof(*sc->rxmbuf));
241
242    for (i = 0; i < sc->txbufs; i++)
243      {
244          sc->txdesc[i].addr = (uint32_t *) calloc(1, GRETH_MAXBUF_LEN);
245#ifdef GRETH_DEBUG
246          printf("TXBUF: %08x\n", (int) sc->txdesc[i].addr);
247#endif
248      }
249    /*printf("RXbufs: %i\n", sc->rxbufs);*/
250    for (i = 0; i < sc->rxbufs; i++)
251      {
252
253          MGETHDR (m, M_WAIT, MT_DATA);
254          MCLGET (m, M_WAIT);
255          m->m_pkthdr.rcvif = &sc->arpcom.ac_if;
256          sc->rxmbuf[i] = m;
257          sc->rxdesc[i].addr = (uint32_t *) mtod(m, uint32_t *);
258          sc->rxdesc[i].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ;
259#ifdef GRETH_DEBUG
260          printf("RXBUF: %08x\n", (int) sc->rxdesc[i].addr);
261#endif
262      }
263    sc->rxdesc[sc->rxbufs - 1].ctrl |= GRETH_RXD_WRAP;
264
265    /* set ethernet address.  */
266    regs->mac_addr_msb =
267      sc->arpcom.ac_enaddr[0] << 8 | sc->arpcom.ac_enaddr[1];
268    regs->mac_addr_lsb =
269      sc->arpcom.ac_enaddr[2] << 24 | sc->arpcom.ac_enaddr[3] << 16 |
270      sc->arpcom.ac_enaddr[4] << 8 | sc->arpcom.ac_enaddr[5];
271
272    /* install interrupt vector */
273    set_vector(greth_interrupt_handler, sc->vector, 1);
274
275    /* clear all pending interrupts */
276
277    regs->status = 0xffffffff;
278
279#ifdef GRETH_SUSPEND_NOTXBUF
280    regs->ctrl |= GRETH_CTRL_TXIRQ;
281#endif
282
283    regs->ctrl |= GRETH_CTRL_RXEN | (fd << 4) | GRETH_CTRL_RXIRQ;
284}
285
286static void
287greth_rxDaemon (void *arg)
288{
289    struct ether_header *eh;
290    struct greth_softc *dp = (struct greth_softc *) &greth;
291    struct ifnet *ifp = &dp->arpcom.ac_if;
292    struct mbuf *m;
293    unsigned int len, len_status, bad;
294    rtems_event_set events;
295   
296    /*printf("Started RxDaemon\n");*/
297    for (;;)
298      {
299        rtems_bsdnet_event_receive (INTERRUPT_EVENT,
300                                    RTEMS_WAIT | RTEMS_EVENT_ANY,
301                                    RTEMS_NO_TIMEOUT, &events);
302       
303#ifdef GRETH_ETH_DEBUG
304    printf ("r\n");
305#endif
306    /*printf("Packet received\n");*/
307            while (!((len_status =
308                   dp->rxdesc[dp->rx_ptr].ctrl) & GRETH_RXD_ENABLE))
309            {
310              /*printf("Status: %x\n", dp->rxdesc[dp->rx_ptr].ctrl);*/
311                bad = 0;
312
313                if (len_status & GRETH_RXD_TOOLONG)
314                  {
315                      dp->rxLengthError++;
316                      bad = 1;
317                  }
318                if (len_status & GRETH_RXD_DRIBBLE)
319                  {
320                      dp->rxNonOctet++;
321                      bad = 1;
322                  }
323                if (len_status & GRETH_RXD_CRCERR)
324                  {
325                      dp->rxBadCRC++;
326                      bad = 1;
327                  }
328                if (len_status & GRETH_RXD_OVERRUN)
329                  {
330                      dp->rxOverrun++;
331                      bad = 1;
332                  }
333                if (!bad)
334                  {
335                    /*printf("Received Ok packet\n");*/
336                      /* pass on the packet in the receive buffer */
337                    len = len_status & 0x7FF;
338                    m = dp->rxmbuf[dp->rx_ptr];
339                    m->m_len = m->m_pkthdr.len =
340                      len - sizeof (struct ether_header);
341                    /*printf("Packet of length: %i\n", len);*/
342                    eh = mtod (m, struct ether_header *);
343                    m->m_data += sizeof (struct ether_header);
344                    /*printf("Mbuf handling done\n");*/
345#ifdef CPU_U32_FIX
346                    /*printf("Ip aligning\n");*/
347                    ipalign(m); /* Align packet on 32-bit boundary */
348#endif
349                    /*printf("Calling stack\n");*/
350                    /*printf("Ifp: %x, Eh: %x, M: %x\n", (int)ifp, (int)eh, (int)m);*/
351                    ether_input (ifp, eh, m);
352                    /*printf("Returned from stack\n");*/
353                    /* get a new mbuf */
354                    /*printf("Getting new mbuf\n");*/
355                    MGETHDR (m, M_WAIT, MT_DATA);
356                    MCLGET (m, M_WAIT);
357                    /*printf("Got new mbuf\n");*/
358                    dp->rxmbuf[dp->rx_ptr] = m;
359                    m->m_pkthdr.rcvif = ifp;
360                    dp->rxdesc[dp->rx_ptr].addr =
361                      (uint32_t *) mtod (m, uint32_t *);
362                    dp->rxPackets++;
363                  }
364                /*printf("Reenabling desc\n");*/
365                dp->rxdesc[dp->rx_ptr].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ;
366                if (dp->rx_ptr == dp->rxbufs - 1) {
367                  dp->rxdesc[dp->rx_ptr].ctrl |= GRETH_RXD_WRAP;
368                }
369                dp->regs->ctrl |= GRETH_CTRL_RXEN;
370                /*printf("rxptr: %i\n", dp->rx_ptr);*/
371                dp->rx_ptr = (dp->rx_ptr + 1) % dp->rxbufs;
372                /*printf("RxDesc reenabled\n");*/
373            }
374      }
375   
376}
377
378static int inside = 0;
379static void
380sendpacket (struct ifnet *ifp, struct mbuf *m)
381{
382    struct greth_softc *dp = ifp->if_softc;
383    unsigned char *temp;
384    struct mbuf *n;
385    unsigned int len;
386   
387    /*printf("Send packet entered\n");*/
388    if (inside) printf ("error: sendpacket re-entered!!\n");
389    inside = 1;
390    /*
391     * Waiting for Transmitter ready
392     */
393    n = m;
394
395    while (dp->txdesc[dp->tx_ptr].ctrl & GRETH_TXD_ENABLE)
396      {
397#ifdef GRETH_SUSPEND_NOTXBUF
398        dp->txdesc[dp->tx_ptr].ctrl |= GRETH_TXD_IRQ;
399        rtems_event_set events;
400        rtems_bsdnet_event_receive (GRETH_TX_WAIT_EVENT,
401                                    RTEMS_WAIT | RTEMS_EVENT_ANY,
402                                    TOD_MILLISECONDS_TO_TICKS(500), &events);
403#endif
404      }
405
406    len = 0;
407    temp = (unsigned char *) dp->txdesc[dp->tx_ptr].addr;
408#ifdef GRETH_DEBUG
409    printf("TXD: 0x%08x\n", (int) m->m_data);
410#endif
411    for (;;)
412        {
413#ifdef GRETH_DEBUG
414          int i;
415          printf("MBUF: 0x%08x : ", (int) m->m_data);
416          for (i=0;i<m->m_len;i++)
417            printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
418          printf("\n");
419#endif
420          len += m->m_len;
421          if (len <= RBUF_SIZE)
422            memcpy ((void *) temp, (char *) m->m_data, m->m_len);
423          temp += m->m_len;
424          if ((m = m->m_next) == NULL)
425              break;
426        }
427
428    m_freem (n);
429
430    /* don't send long packets */
431
432    if (len <= GRETH_MAXBUF_LEN) {
433      if (dp->tx_ptr < dp->txbufs-1) {
434        dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_ENABLE | len;
435      } else {
436        dp->txdesc[dp->tx_ptr].ctrl =
437          GRETH_TXD_WRAP | GRETH_TXD_ENABLE | len;
438      }
439      dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
440      dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
441    }
442    inside = 0;
443}
444
445/*
446 * Driver transmit daemon
447 */
448void
449greth_txDaemon (void *arg)
450{
451    struct greth_softc *sc = (struct greth_softc *) arg;
452    struct ifnet *ifp = &sc->arpcom.ac_if;
453    struct mbuf *m;
454    rtems_event_set events;
455   
456    for (;;)
457      {
458          /*
459           * Wait for packet
460           */
461
462        rtems_bsdnet_event_receive (START_TRANSMIT_EVENT,
463                                      RTEMS_EVENT_ANY | RTEMS_WAIT,
464                                      RTEMS_NO_TIMEOUT, &events);
465#ifdef GRETH_DEBUG
466    printf ("t\n");
467#endif
468
469          /*
470           * Send packets till queue is empty
471           */
472          for (;;)
473            {
474                /*
475                 * Get the next mbuf chain to transmit.
476                 */
477                IF_DEQUEUE (&ifp->if_snd, m);
478                if (!m)
479                    break;
480               
481                sendpacket (ifp, m);
482            }
483          ifp->if_flags &= ~IFF_OACTIVE;
484      }
485}
486
487
488static void
489greth_start (struct ifnet *ifp)
490{
491    struct greth_softc *sc = ifp->if_softc;
492   
493    ifp->if_flags |= IFF_OACTIVE;
494    rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
495   
496}
497
498/*
499 * Initialize and start the device
500 */
501static void
502greth_init (void *arg)
503{
504    struct greth_softc *sc = arg;
505    struct ifnet *ifp = &sc->arpcom.ac_if;
506
507    if (sc->txDaemonTid == 0)
508      {
509
510          /*
511           * Set up GRETH hardware
512           */
513          greth_initialize_hardware (sc);
514
515          /*
516           * Start driver tasks
517           */
518          sc->rxDaemonTid = rtems_bsdnet_newproc ("DCrx", 4096,
519                                                  greth_rxDaemon, sc);
520          sc->txDaemonTid = rtems_bsdnet_newproc ("DCtx", 4096,
521                                                  greth_txDaemon, sc);
522      }
523
524    /*
525     * Tell the world that we're running.
526     */
527    ifp->if_flags |= IFF_RUNNING;
528
529}
530
531/*
532 * Stop the device
533 */
534static void
535greth_stop (struct greth_softc *sc)
536{
537    struct ifnet *ifp = &sc->arpcom.ac_if;
538
539    ifp->if_flags &= ~IFF_RUNNING;
540
541    sc->regs->ctrl = 0;                 /* RX/TX OFF */
542    sc->regs->ctrl = GRETH_CTRL_RST;    /* Reset ON */
543    sc->regs->ctrl = 0;                 /* Reset OFF */
544}
545
546
547/*
548 * Show interface statistics
549 */
550static void
551greth_stats (struct greth_softc *sc)
552{
553  printf ("      Rx Interrupts:%-8lu", sc->rxInterrupts);
554  printf ("      Rx Packets:%-8lu", sc->rxPackets);
555  printf ("          Length:%-8lu", sc->rxLengthError);
556  printf ("       Non-octet:%-8lu\n", sc->rxNonOctet);
557  printf ("            Bad CRC:%-8lu", sc->rxBadCRC);
558  printf ("         Overrun:%-8lu", sc->rxOverrun);
559  printf ("      Tx Interrupts:%-8lu", sc->txInterrupts);
560}
561
562/*
563 * Driver ioctl handler
564 */
565static int
566greth_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data)
567{
568    struct greth_softc *sc = ifp->if_softc;
569    int error = 0;
570
571    switch (command)
572      {
573      case SIOCGIFADDR:
574      case SIOCSIFADDR:
575          ether_ioctl (ifp, command, data);
576          break;
577
578      case SIOCSIFFLAGS:
579          switch (ifp->if_flags & (IFF_UP | IFF_RUNNING))
580            {
581            case IFF_RUNNING:
582                greth_stop (sc);
583                break;
584
585            case IFF_UP:
586                greth_init (sc);
587                break;
588
589            case IFF_UP | IFF_RUNNING:
590                greth_stop (sc);
591                greth_init (sc);
592                break;
593       default:
594                break;
595            }
596          break;
597
598      case SIO_RTEMS_SHOW_STATS:
599          greth_stats (sc);
600          break;
601
602          /*
603           * FIXME: All sorts of multicast commands need to be added here!
604           */
605      default:
606          error = EINVAL;
607          break;
608      }
609
610    return error;
611}
612
613/*
614 * Attach an GRETH driver to the system
615 */
616int
617rtems_greth_driver_attach (struct rtems_bsdnet_ifconfig *config,
618                           greth_configuration_t *chip)
619{
620    struct greth_softc *sc;
621    struct ifnet *ifp;
622    int mtu;
623    int unitNumber;
624    char *unitName;
625
626      /* parse driver name */
627    if ((unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName)) < 0)
628        return 0;
629
630    sc = &greth;
631    ifp = &sc->arpcom.ac_if;
632    memset (sc, 0, sizeof (*sc));
633
634    if (config->hardware_address)
635      {
636          memcpy (sc->arpcom.ac_enaddr, config->hardware_address,
637                  ETHER_ADDR_LEN);
638      }
639    else
640      {
641          memset (sc->arpcom.ac_enaddr, 0x08, ETHER_ADDR_LEN);
642      }
643
644    if (config->mtu)
645        mtu = config->mtu;
646    else
647        mtu = ETHERMTU;
648
649    sc->acceptBroadcast = !config->ignore_broadcast;
650    sc->regs = (void *) chip->base_address;
651    sc->vector = chip->vector;
652    sc->txbufs = chip->txd_count;
653    sc->rxbufs = chip->rxd_count;
654   
655    /*
656     * Set up network interface values
657     */
658    ifp->if_softc = sc;
659    ifp->if_unit = unitNumber;
660    ifp->if_name = unitName;
661    ifp->if_mtu = mtu;
662    ifp->if_init = greth_init;
663    ifp->if_ioctl = greth_ioctl;
664    ifp->if_start = greth_start;
665    ifp->if_output = ether_output;
666    ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
667    if (ifp->if_snd.ifq_maxlen == 0)
668        ifp->if_snd.ifq_maxlen = ifqmaxlen;
669
670    /*
671     * Attach the interface
672     */
673    if_attach (ifp);
674    ether_ifattach (ifp);
675
676#ifdef GRETH_DEBUG
677    printf ("GRETH : driver has been attached\n");
678#endif
679    return 1;
680};
681
Note: See TracBrowser for help on using the repository browser.