source: rtems/c/src/libchip/network/greth.c @ 13279f5d

4.104.114.84.95
Last change on this file since 13279f5d was 2697be56, checked in by Joel Sherrill <joel.sherrill@…>, on 03/12/07 at 11:19:21

2007-03-12 Joel Sherrill <joel@…>

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