source: rtems/c/src/libchip/network/greth.c @ 050249d

4.104.114.84.95
Last change on this file since 050249d was 050249d, checked in by Joel Sherrill <joel.sherrill@…>, on 09/07/07 at 15:01:15

2007-09-07 Daniel Hellstrom <daniel@…>

  • libchip/network/greth.c, libchip/network/greth.h: GRETH_GBIT support and GBIT PHY support for 10/100 MAC, also auto negotiation updated.
  • Property mode set to 100644
File size: 27.9 KB
Line 
1/*
2 * Gaisler Research ethernet MAC driver
3 * adapted from Opencores driver by Marko Isomaki
4 *
5 *  The license and distribution terms for this file may be
6 *  found in found in the file LICENSE in this distribution or at
7 *  http://www.rtems.com/license/LICENSE.
8 *
9 *  $Id$
10 *
11 * 2007-09-07, Ported GBIT support from 4.6.5
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 <rtems/bspIo.h>
22#include <stdlib.h>
23#include <stdio.h>
24#include <stdarg.h>
25#include <rtems/error.h>
26#include <rtems/rtems_bsdnet.h>
27#include "greth.h"
28
29#include <sys/param.h>
30#include <sys/mbuf.h>
31
32#include <sys/socket.h>
33#include <sys/sockio.h>
34#include <net/if.h>
35#include <netinet/in.h>
36#include <netinet/if_ether.h>
37
38#ifdef malloc
39#undef malloc
40#endif
41#ifdef free
42#undef free
43#endif
44
45#if defined(__m68k__)
46extern m68k_isr_entry set_vector( rtems_isr_entry, rtems_vector_number, int );
47#else
48extern rtems_isr_entry set_vector( rtems_isr_entry, rtems_vector_number, int );
49#endif
50
51
52/* #define GRETH_DEBUG */
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/* 4s Autonegotiation Timeout */
95#ifndef GRETH_AUTONEGO_TIMEOUT_MS
96#define GRETH_AUTONEGO_TIMEOUT_MS 4000
97#endif
98
99/* For optimizing the autonegotiation time */
100#define GRETH_AUTONEGO_PRINT_TIME
101
102/* Ethernet buffer descriptor */
103
104typedef struct _greth_rxtxdesc {
105   volatile uint32_t ctrl; /* Length and status */
106   uint32_t *addr;         /* Buffer pointer */
107} greth_rxtxdesc;
108
109
110/*
111 * Per-device data
112 */
113struct greth_softc
114{
115
116   struct arpcom arpcom;
117   
118   greth_regs *regs;
119   
120   int acceptBroadcast;
121   rtems_id rxDaemonTid;
122   rtems_id txDaemonTid;
123   
124   unsigned int tx_ptr;
125   unsigned int tx_dptr;
126   unsigned int tx_cnt;
127   unsigned int rx_ptr;
128   unsigned int txbufs;
129   unsigned int rxbufs;
130   greth_rxtxdesc *txdesc;
131   greth_rxtxdesc *rxdesc;
132   struct mbuf **rxmbuf;
133   struct mbuf **txmbuf;
134   rtems_vector_number vector;
135   
136   /*Status*/
137   struct phy_device_info phydev;
138   int fd;
139   int sp;
140   int gb;
141   int gbit_mac;
142   int auto_neg;
143   unsigned int auto_neg_time;
144   
145   /*
146    * Statistics
147    */
148   unsigned long rxInterrupts;
149   
150   unsigned long rxPackets;
151   unsigned long rxLengthError;
152   unsigned long rxNonOctet;
153   unsigned long rxBadCRC;
154   unsigned long rxOverrun;
155   
156   unsigned long txInterrupts;
157   
158   unsigned long txDeferred;
159   unsigned long txHeartbeat;
160   unsigned long txLateCollision;
161   unsigned long txRetryLimit;
162   unsigned long txUnderrun;
163
164};
165
166static struct greth_softc greth;
167
168static char *almalloc(int sz)
169{
170        char *tmp;
171        tmp = calloc(1,2*sz);
172        tmp = (char *) (((int)tmp+sz) & ~(sz -1));
173        return(tmp);
174}
175
176/* GRETH interrupt handler */
177
178static rtems_isr
179greth_interrupt_handler (rtems_vector_number v)
180{
181        uint32_t status;
182        /* read and clear interrupt cause */
183       
184        status = greth.regs->status;
185        greth.regs->status = status;
186       
187        /* Frame received? */
188        if (status & (GRETH_STATUS_RXERR | GRETH_STATUS_RXIRQ))
189        {
190                greth.rxInterrupts++;
191                rtems_event_send (greth.rxDaemonTid, INTERRUPT_EVENT);
192        }
193#ifdef GRETH_SUSPEND_NOTXBUF
194        if (status & (GRETH_STATUS_TXERR | GRETH_STATUS_TXIRQ))
195        {
196                greth.txInterrupts++;
197                rtems_event_send (greth.txDaemonTid, GRETH_TX_WAIT_EVENT);
198        }
199#endif
200        /*
201          #ifdef __leon__
202          LEON_Clear_interrupt(v-0x10);
203          #endif
204        */
205}
206
207static uint32_t read_mii(uint32_t phy_addr, uint32_t reg_addr)
208{
209    while (greth.regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
210    greth.regs->mdio_ctrl = (phy_addr << 11) | (reg_addr << 6) | GRETH_MDIO_READ;
211    while (greth.regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
212    if (!(greth.regs->mdio_ctrl & GRETH_MDIO_LINKFAIL))
213        return((greth.regs->mdio_ctrl >> 16) & 0xFFFF);
214    else {
215        printf("greth: failed to read mii\n");
216        return (0);
217    }
218}
219
220static void write_mii(uint32_t phy_addr, uint32_t reg_addr, uint32_t data)
221{
222    while (greth.regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
223    greth.regs->mdio_ctrl =
224     ((data & 0xFFFF) << 16) | (phy_addr << 11) | (reg_addr << 6) | GRETH_MDIO_WRITE;
225    while (greth.regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
226}
227
228static void print_init_info(struct greth_softc *sc)
229{
230        printf("greth: driver attached\n");
231        printf("**** PHY ****\n");
232        printf("Vendor: %x   Device: %x   Revision: %d\n",sc->phydev.vendor, sc->phydev.device, sc->phydev.rev);
233        printf("Current Operating Mode: ");
234        if (sc->gb) {
235                printf("1000 Mbit ");
236        } else if (sc->sp) {
237                printf("100 Mbit ");
238        } else {
239                printf("10 Mbit ");
240        }
241        if (sc->fd) {
242                printf("Full Duplex\n");
243        } else {
244                printf("Half Duplex\n");
245        }
246#ifdef GRETH_AUTONEGO_PRINT_TIME
247        if ( sc->auto_neg ){
248          printf("Autonegotiation Time: %dms\n",sc->auto_neg_time);
249        }
250#endif
251}
252
253
254/*
255 * Initialize the ethernet hardware
256 */
257static void
258greth_initialize_hardware (struct greth_softc *sc)
259{
260    struct mbuf *m;
261    int i;
262    int phyaddr;
263    int phyctrl;
264    int phystatus;
265    int tmp1;
266    int tmp2;
267    unsigned int msecs;
268    rtems_clock_time_value tstart, tnow;
269
270    greth_regs *regs;
271
272    regs = sc->regs;
273   
274    /* Reset the controller.  */
275    greth.rxInterrupts = 0;
276    greth.rxPackets = 0;
277
278    regs->ctrl = 0;
279    regs->ctrl = GRETH_CTRL_RST;        /* Reset ON */
280    regs->ctrl = 0;                     /* Reset OFF */
281   
282    /* Check if mac is gbit capable*/
283    sc->gbit_mac = (regs->ctrl >> 27) & 1; 
284   
285    /* Get the phy address which assumed to have been set
286       correctly with the reset value in hardware*/
287    phyaddr = (regs->mdio_ctrl >> 11) & 0x1F;
288
289    /* get phy control register default values */
290    while ((phyctrl = read_mii(phyaddr, 0)) & 0x8000) {}
291   
292    /* reset PHY and wait for completion */
293    write_mii(phyaddr, 0, 0x8000 | phyctrl);
294
295    while ((read_mii(phyaddr, 0)) & 0x8000) {}
296   
297    /* Check if PHY is autoneg capable and then determine operating mode,
298       otherwise force it to 10 Mbit halfduplex */
299    sc->gb = 0;
300    sc->fd = 0;
301    sc->sp = 0;
302    sc->auto_neg = 0;
303    sc->auto_neg_time = 0;
304    if ((phyctrl >> 12) & 1) {
305            /*wait for auto negotiation to complete*/
306            msecs = 0;
307            sc->auto_neg = 1;
308            if ( rtems_clock_get(RTEMS_CLOCK_GET_TIME_VALUE,&tstart) == RTEMS_NOT_DEFINED){
309                /* Not inited, set to epoch */
310                rtems_time_of_day time;
311                time.year   = 1988;
312                time.month  = 1;
313                time.day    = 1;
314                time.hour   = 0;
315                time.minute = 0;
316                time.second = 0;
317                time.ticks  = 0;
318                rtems_clock_set(&time);
319
320                tstart.seconds = 0;
321                tstart.microseconds = 0;
322                rtems_clock_get(RTEMS_CLOCK_GET_TIME_VALUE,&tstart);
323            }
324            while (!(((phystatus = read_mii(phyaddr, 1)) >> 5) & 1)) {
325                    if ( rtems_clock_get(RTEMS_CLOCK_GET_TIME_VALUE,&tnow) != RTEMS_SUCCESSFUL )
326                      printk("rtems_clock_get failed\n\r");
327                    msecs = (tnow.seconds-tstart.seconds)*1000+(tnow.microseconds-tstart.microseconds)/1000;
328                    if ( msecs > GRETH_AUTONEGO_TIMEOUT_MS ){
329                            sc->auto_neg_time = msecs;
330                            printk("Auto negotiation timed out. Selecting default config\n\r");
331                            tmp1 = read_mii(phyaddr, 0);
332                            sc->gb = ((phyctrl >> 6) & 1) && !((phyctrl >> 13) & 1);
333                            sc->sp = !((phyctrl >> 6) & 1) && ((phyctrl >> 13) & 1);
334                            sc->fd = (phyctrl >> 8) & 1;
335                            goto auto_neg_done;
336                    }
337            }
338            sc->auto_neg_time = msecs;
339            sc->phydev.adv = read_mii(phyaddr, 4);
340            sc->phydev.part = read_mii(phyaddr, 5);
341            if ((phystatus >> 8) & 1) {
342                    sc->phydev.extadv = read_mii(phyaddr, 9);
343                    sc->phydev.extpart = read_mii(phyaddr, 10);
344                       if ( (sc->phydev.extadv & GRETH_MII_EXTADV_1000FD) &&
345                            (sc->phydev.extpart & GRETH_MII_EXTPRT_1000FD)) {
346                               sc->gb = 1;
347                               sc->fd = 1;
348                       }
349                       if ( (sc->phydev.extadv & GRETH_MII_EXTADV_1000HD) &&
350                            (sc->phydev.extpart & GRETH_MII_EXTPRT_1000HD)) {
351                               sc->gb = 1;
352                               sc->fd = 0;
353                       }
354            }
355            if ((sc->gb == 0) || ((sc->gb == 1) && (sc->gbit_mac == 0))) {
356                    if ( (sc->phydev.adv & GRETH_MII_100TXFD) &&
357                         (sc->phydev.part & GRETH_MII_100TXFD)) {
358                            sc->sp = 1;
359                            sc->fd = 1;
360                    }
361                    if ( (sc->phydev.adv & GRETH_MII_100TXHD) &&
362                         (sc->phydev.part & GRETH_MII_100TXHD)) {
363                            sc->sp = 1;
364                            sc->fd = 0;
365                    }
366                    if ( (sc->phydev.adv & GRETH_MII_10FD) &&
367                         (sc->phydev.part & GRETH_MII_10FD)) {
368                            sc->fd = 1;
369                    }
370            }
371    }
372auto_neg_done:
373    sc->phydev.vendor = 0;
374    sc->phydev.device = 0;
375    sc->phydev.rev = 0;
376    phystatus = read_mii(phyaddr, 1);
377   
378    /*Read out PHY info if extended registers are available */
379    if (phystatus & 1) { 
380            tmp1 = read_mii(phyaddr, 2);
381            tmp2 = read_mii(phyaddr, 3);
382
383            sc->phydev.vendor = (tmp1 << 6) | ((tmp2 >> 10) & 0x3F);
384            sc->phydev.rev = tmp2 & 0xF;
385            sc->phydev.device = (tmp2 >> 4) & 0x3F;
386    }
387
388    /* Force to 10 mbit half duplex if the 10/100 MAC is used with a 1000 PHY*/
389    /*check if marvell 88EE1111 PHY. Needs special reset handling */
390    if ((phystatus & 1) && (sc->phydev.vendor == 0x005043) && (sc->phydev.device == 0x0C)) {
391            if (((sc->gb) && !(sc->gbit_mac)) || !((phyctrl >> 12) & 1)) {
392                    write_mii(phyaddr, 0, sc->sp << 13);
393                    write_mii(phyaddr, 0, 0x8000);
394                    sc->gb = 0;
395                    sc->sp = 0;
396                    sc->fd = 0;
397            }
398    } else {
399            if (((sc->gb) && !(sc->gbit_mac))  || !((phyctrl >> 12) & 1)) {
400                    write_mii(phyaddr, 0, sc->sp << 13);
401                    sc->gb = 0;
402                    sc->sp = 0;
403                    sc->fd = 0;
404            }
405    }
406    while ((read_mii(phyaddr, 0)) & 0x8000) {}
407
408    regs->ctrl = 0;
409    regs->ctrl = GRETH_CTRL_RST;        /* Reset ON */
410    regs->ctrl = 0;
411
412    /* Initialize rx/tx descriptor pointers */
413    sc->txdesc = (greth_rxtxdesc *) almalloc(1024);
414    sc->rxdesc = (greth_rxtxdesc *) almalloc(1024);
415    sc->tx_ptr = 0;
416    sc->tx_dptr = 0;
417    sc->tx_cnt = 0;
418    sc->rx_ptr = 0;
419    regs->txdesc = (int) sc->txdesc;
420    regs->rxdesc = (int) sc->rxdesc;
421   
422    sc->rxmbuf = calloc(sc->rxbufs, sizeof(*sc->rxmbuf));
423    sc->txmbuf = calloc(sc->txbufs, sizeof(*sc->txmbuf));
424
425    for (i = 0; i < sc->txbufs; i++)
426      {
427              sc->txdesc[i].ctrl = 0;
428              if (!(sc->gbit_mac)) {
429                      sc->txdesc[i].addr = malloc(GRETH_MAXBUF_LEN);
430              }
431#ifdef GRETH_DEBUG
432              /* printf("TXBUF: %08x\n", (int) sc->txdesc[i].addr); */
433#endif
434      }
435    for (i = 0; i < sc->rxbufs; i++)
436      {
437
438          MGETHDR (m, M_WAIT, MT_DATA);
439          MCLGET (m, M_WAIT);
440          if (sc->gbit_mac)
441                  m->m_data += 2;
442          m->m_pkthdr.rcvif = &sc->arpcom.ac_if;
443          sc->rxmbuf[i] = m;
444          sc->rxdesc[i].addr = (uint32_t *) mtod(m, uint32_t *);
445          sc->rxdesc[i].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ;
446#ifdef GRETH_DEBUG
447/*        printf("RXBUF: %08x\n", (int) sc->rxdesc[i].addr); */
448#endif
449      }
450    sc->rxdesc[sc->rxbufs - 1].ctrl |= GRETH_RXD_WRAP;
451
452    /* set ethernet address.  */
453    regs->mac_addr_msb =
454      sc->arpcom.ac_enaddr[0] << 8 | sc->arpcom.ac_enaddr[1];
455    regs->mac_addr_lsb =
456      sc->arpcom.ac_enaddr[2] << 24 | sc->arpcom.ac_enaddr[3] << 16 |
457      sc->arpcom.ac_enaddr[4] << 8 | sc->arpcom.ac_enaddr[5];
458
459    /* install interrupt vector */
460    set_vector(greth_interrupt_handler, sc->vector, 1);
461
462    /* clear all pending interrupts */
463
464    regs->status = 0xffffffff;
465
466#ifdef GRETH_SUSPEND_NOTXBUF
467    regs->ctrl |= GRETH_CTRL_TXIRQ;
468#endif
469
470    regs->ctrl |= GRETH_CTRL_RXEN | (sc->fd << 4) | GRETH_CTRL_RXIRQ | (sc->sp << 7) | (sc->gb << 8);
471
472    print_init_info(sc);
473}
474
475static void
476greth_rxDaemon (void *arg)
477{
478    struct ether_header *eh;
479    struct greth_softc *dp = (struct greth_softc *) &greth;
480    struct ifnet *ifp = &dp->arpcom.ac_if;
481    struct mbuf *m;
482    unsigned int len, len_status, bad;
483    rtems_event_set events;
484   
485    for (;;)
486      {
487        rtems_bsdnet_event_receive (INTERRUPT_EVENT,
488                                    RTEMS_WAIT | RTEMS_EVENT_ANY,
489                                    RTEMS_NO_TIMEOUT, &events);
490       
491#ifdef GRETH_ETH_DEBUG
492    printf ("r\n");
493#endif
494    while (!((len_status =
495                    dp->rxdesc[dp->rx_ptr].ctrl) & GRETH_RXD_ENABLE))
496            {
497                    bad = 0;
498                    if (len_status & GRETH_RXD_TOOLONG)
499                    {
500                            dp->rxLengthError++;
501                            bad = 1;
502                    }
503                    if (len_status & GRETH_RXD_DRIBBLE)
504                    {
505                            dp->rxNonOctet++;
506                            bad = 1;
507                    }
508                    if (len_status & GRETH_RXD_CRCERR)
509                    {
510                            dp->rxBadCRC++;
511                            bad = 1;
512                    }
513                    if (len_status & GRETH_RXD_OVERRUN)
514                    {
515                            dp->rxOverrun++;
516                            bad = 1;
517                    }
518                    if (len_status & GRETH_RXD_LENERR)
519                    {
520                            dp->rxLengthError++;
521                            bad = 1;
522                    }
523                    if (!bad)
524                    {
525                            /* pass on the packet in the receive buffer */
526                            len = len_status & 0x7FF;
527                            m = dp->rxmbuf[dp->rx_ptr];
528#ifdef GRETH_DEBUG
529                            int i;
530                            printf("RX: 0x%08x, Len: %d : ", (int) m->m_data, len);
531                            for (i=0; i<len; i++)
532                                    printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
533                            printf("\n");
534#endif
535                            m->m_len = m->m_pkthdr.len =
536                                    len - sizeof (struct ether_header);
537
538                            eh = mtod (m, struct ether_header *);
539                            m->m_data += sizeof (struct ether_header);
540#ifdef CPU_U32_FIX
541                            if(!(dp->gbit_mac))
542                                    ipalign(m); /* Align packet on 32-bit boundary */
543#endif
544
545                            ether_input (ifp, eh, m);
546                            MGETHDR (m, M_WAIT, MT_DATA);
547                            MCLGET (m, M_WAIT);
548                            if (dp->gbit_mac)
549                                    m->m_data += 2;
550                            dp->rxmbuf[dp->rx_ptr] = m;
551                            m->m_pkthdr.rcvif = ifp;
552                            dp->rxdesc[dp->rx_ptr].addr =
553                                    (uint32_t *) mtod (m, uint32_t *);
554                            dp->rxPackets++;
555                    }
556                    if (dp->rx_ptr == dp->rxbufs - 1) {
557                            dp->rxdesc[dp->rx_ptr].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ | GRETH_RXD_WRAP;
558                    } else {
559                            dp->rxdesc[dp->rx_ptr].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ;
560                    }
561                    dp->regs->ctrl |= GRETH_CTRL_RXEN;
562                    dp->rx_ptr = (dp->rx_ptr + 1) % dp->rxbufs;
563            }
564      }
565   
566}
567
568static int inside = 0;
569static void
570sendpacket (struct ifnet *ifp, struct mbuf *m)
571{
572    struct greth_softc *dp = ifp->if_softc;
573    unsigned char *temp;
574    struct mbuf *n;
575    unsigned int len;
576   
577    /*printf("Send packet entered\n");*/
578    if (inside) printf ("error: sendpacket re-entered!!\n");
579    inside = 1;
580    /*
581     * Waiting for Transmitter ready
582     */
583    n = m;
584
585    while (dp->txdesc[dp->tx_ptr].ctrl & GRETH_TXD_ENABLE)
586      {
587#ifdef GRETH_SUSPEND_NOTXBUF
588        dp->txdesc[dp->tx_ptr].ctrl |= GRETH_TXD_IRQ;
589        rtems_event_set events;
590        rtems_bsdnet_event_receive (GRETH_TX_WAIT_EVENT,
591                                    RTEMS_WAIT | RTEMS_EVENT_ANY,
592                                    TOD_MILLISECONDS_TO_TICKS(500), &events);
593#endif
594      }
595
596    len = 0;
597    temp = (unsigned char *) dp->txdesc[dp->tx_ptr].addr;
598#ifdef GRETH_DEBUG
599    printf("TXD: 0x%08x : BUF: 0x%08x\n", (int) m->m_data, (int) temp);
600#endif
601    for (;;)
602    {
603#ifdef GRETH_DEBUG
604            int i;
605            printf("MBUF: 0x%08x : ", (int) m->m_data);
606            for (i=0;i<m->m_len;i++)
607                    printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
608            printf("\n");
609#endif
610            len += m->m_len;
611            if (len <= RBUF_SIZE)
612                    memcpy ((void *) temp, (char *) m->m_data, m->m_len);
613            temp += m->m_len;
614            if ((m = m->m_next) == NULL)
615                    break;
616    }
617   
618    m_freem (n);
619   
620    /* don't send long packets */
621
622    if (len <= GRETH_MAXBUF_LEN) {
623            if (dp->tx_ptr < dp->txbufs-1) {
624                    dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_ENABLE | len;
625            } else {
626                    dp->txdesc[dp->tx_ptr].ctrl =
627                            GRETH_TXD_WRAP | GRETH_TXD_ENABLE | len;
628            }
629            dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
630            dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
631    }
632    inside = 0;
633}
634
635
636static void
637sendpacket_gbit (struct ifnet *ifp, struct mbuf *m)
638{
639        struct greth_softc *dp = ifp->if_softc;
640        unsigned int len;
641
642        /*printf("Send packet entered\n");*/
643        if (inside) printf ("error: sendpacket re-entered!!\n");
644        inside = 1;
645        /*
646         * Waiting for Transmitter ready
647         */
648       
649        len = 0;
650#ifdef GRETH_DEBUG
651        printf("TXD: 0x%08x\n", (int) m->m_data);
652#endif
653        for (;;)
654        {
655                while (dp->txdesc[dp->tx_ptr].ctrl & GRETH_TXD_ENABLE)
656                {
657#ifdef GRETH_SUSPEND_NOTXBUF
658                        dp->txdesc[dp->tx_ptr].ctrl |= GRETH_TXD_IRQ;
659                        rtems_event_set events;
660                        rtems_bsdnet_event_receive (GRETH_TX_WAIT_EVENT,
661                                                    RTEMS_WAIT | RTEMS_EVENT_ANY,
662                                                    TOD_MILLISECONDS_TO_TICKS(500), &events);
663#endif
664                }
665#ifdef GRETH_DEBUG
666                int i;
667                printf("MBUF: 0x%08x, Len: %d : ", (int) m->m_data, m->m_len);
668                for (i=0; i<m->m_len; i++)
669                        printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
670                printf("\n");
671#endif
672            len += m->m_len;
673            dp->txdesc[dp->tx_ptr].addr = (uint32_t *)m->m_data;
674            if (dp->tx_ptr < dp->txbufs-1) {
675                    if ((m->m_next) == NULL) {
676                            dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_ENABLE | GRETH_TXD_CS | m->m_len;
677                            break;
678                    } else {
679                            dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_ENABLE | GRETH_TXD_MORE | GRETH_TXD_CS | m->m_len;
680                    }
681            } else {
682                    if ((m->m_next) == NULL) {
683                            dp->txdesc[dp->tx_ptr].ctrl =
684                                    GRETH_TXD_WRAP | GRETH_TXD_ENABLE | GRETH_TXD_CS | m->m_len;
685                            break;
686                    } else {
687                            dp->txdesc[dp->tx_ptr].ctrl =
688                                    GRETH_TXD_WRAP | GRETH_TXD_ENABLE | GRETH_TXD_MORE | GRETH_TXD_CS | m->m_len;
689                    }
690            }
691            dp->txmbuf[dp->tx_ptr] = m;
692            dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
693            dp->tx_cnt++;
694            m = m->m_next;
695           
696    }
697        dp->txmbuf[dp->tx_ptr] = m;
698        dp->tx_cnt++;
699        dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
700        dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
701        inside = 0;
702}
703
704/*
705 * Driver transmit daemon
706 */
707void
708greth_txDaemon (void *arg)
709{
710    struct greth_softc *sc = (struct greth_softc *) arg;
711    struct ifnet *ifp = &sc->arpcom.ac_if;
712    struct mbuf *m;
713    rtems_event_set events;
714   
715    for (;;)
716    {
717            /*
718             * Wait for packet
719             */
720           
721            rtems_bsdnet_event_receive (START_TRANSMIT_EVENT,
722                                        RTEMS_EVENT_ANY | RTEMS_WAIT,
723                                        RTEMS_NO_TIMEOUT, &events);
724#ifdef GRETH_DEBUG
725            printf ("t\n");
726#endif
727           
728            /*
729             * Send packets till queue is empty
730             */
731           
732           
733            for (;;)
734            {
735                    /*
736                     * Get the next mbuf chain to transmit.
737                     */
738                    IF_DEQUEUE (&ifp->if_snd, m);
739                    if (!m)
740                            break;
741                    sendpacket(ifp, m);
742            }
743            ifp->if_flags &= ~IFF_OACTIVE;
744    }
745}
746
747/*
748 * Driver transmit daemon
749 */
750void
751greth_txDaemon_gbit (void *arg)
752{
753    struct greth_softc *sc = (struct greth_softc *) arg;
754    struct ifnet *ifp = &sc->arpcom.ac_if;
755    struct mbuf *m;
756    rtems_event_set events;
757   
758    for (;;)
759    {
760            /*
761             * Wait for packet
762             */
763           
764            rtems_bsdnet_event_receive (START_TRANSMIT_EVENT,
765                                        RTEMS_EVENT_ANY | RTEMS_WAIT,
766                                        RTEMS_NO_TIMEOUT, &events);
767#ifdef GRETH_DEBUG
768            printf ("t\n");
769#endif
770           
771            /*
772             * Send packets till queue is empty
773             */
774            for (;;)
775            {
776                    while((sc->tx_cnt > 0) && !(sc->txdesc[sc->tx_dptr].ctrl & GRETH_TXD_ENABLE)) {
777                            m_free(sc->txmbuf[sc->tx_dptr]);
778                            sc->tx_dptr = (sc->tx_dptr + 1) % sc->txbufs;
779                            sc->tx_cnt--;
780                    }
781                    /*
782                     * Get the next mbuf chain to transmit.
783                     */
784                    IF_DEQUEUE (&ifp->if_snd, m);
785                    if (!m)
786                            break;
787                    sendpacket_gbit(ifp, m);
788            }
789            ifp->if_flags &= ~IFF_OACTIVE;
790    }
791}
792
793
794static void
795greth_start (struct ifnet *ifp)
796{
797    struct greth_softc *sc = ifp->if_softc;
798   
799    ifp->if_flags |= IFF_OACTIVE;
800    rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
801   
802}
803
804/*
805 * Initialize and start the device
806 */
807static void
808greth_init (void *arg)
809{
810    struct greth_softc *sc = arg;
811    struct ifnet *ifp = &sc->arpcom.ac_if;
812
813    if (sc->txDaemonTid == 0)
814      {
815
816          /*
817           * Set up GRETH hardware
818           */
819          greth_initialize_hardware (sc);
820
821          /*
822           * Start driver tasks
823           */
824          sc->rxDaemonTid = rtems_bsdnet_newproc ("DCrx", 4096,
825                                                  greth_rxDaemon, sc);
826          if (sc->gbit_mac) {
827                  sc->txDaemonTid = rtems_bsdnet_newproc ("DCtx", 4096,
828                                                          greth_txDaemon_gbit, sc);
829          } else {
830                  sc->txDaemonTid = rtems_bsdnet_newproc ("DCtx", 4096,
831                                                          greth_txDaemon, sc);
832          }
833         
834      }
835
836    /*
837     * Tell the world that we're running.
838     */
839    ifp->if_flags |= IFF_RUNNING;
840
841}
842
843/*
844 * Stop the device
845 */
846static void
847greth_stop (struct greth_softc *sc)
848{
849    struct ifnet *ifp = &sc->arpcom.ac_if;
850
851    ifp->if_flags &= ~IFF_RUNNING;
852
853    sc->regs->ctrl = 0;                 /* RX/TX OFF */
854    sc->regs->ctrl = GRETH_CTRL_RST;    /* Reset ON */
855    sc->regs->ctrl = 0;                 /* Reset OFF */
856}
857
858
859/*
860 * Show interface statistics
861 */
862static void
863greth_stats (struct greth_softc *sc)
864{
865  printf ("      Rx Interrupts:%-8lu", sc->rxInterrupts);
866  printf ("      Rx Packets:%-8lu", sc->rxPackets);
867  printf ("          Length:%-8lu", sc->rxLengthError);
868  printf ("       Non-octet:%-8lu\n", sc->rxNonOctet);
869  printf ("            Bad CRC:%-8lu", sc->rxBadCRC);
870  printf ("         Overrun:%-8lu", sc->rxOverrun);
871  printf ("      Tx Interrupts:%-8lu", sc->txInterrupts);
872}
873
874/*
875 * Driver ioctl handler
876 */
877static int
878greth_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data)
879{
880    struct greth_softc *sc = ifp->if_softc;
881    int error = 0;
882
883    switch (command)
884      {
885      case SIOCGIFADDR:
886      case SIOCSIFADDR:
887          ether_ioctl (ifp, command, data);
888          break;
889
890      case SIOCSIFFLAGS:
891          switch (ifp->if_flags & (IFF_UP | IFF_RUNNING))
892            {
893            case IFF_RUNNING:
894                greth_stop (sc);
895                break;
896
897            case IFF_UP:
898                greth_init (sc);
899                break;
900
901            case IFF_UP | IFF_RUNNING:
902                greth_stop (sc);
903                greth_init (sc);
904                break;
905       default:
906                break;
907            }
908          break;
909
910      case SIO_RTEMS_SHOW_STATS:
911          greth_stats (sc);
912          break;
913
914          /*
915           * FIXME: All sorts of multicast commands need to be added here!
916           */
917      default:
918          error = EINVAL;
919          break;
920      }
921
922    return error;
923}
924
925/*
926 * Attach an GRETH driver to the system
927 */
928int
929rtems_greth_driver_attach (struct rtems_bsdnet_ifconfig *config,
930                           greth_configuration_t *chip)
931{
932    struct greth_softc *sc;
933    struct ifnet *ifp;
934    int mtu;
935    int unitNumber;
936    char *unitName;
937
938      /* parse driver name */
939    if ((unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName)) < 0)
940        return 0;
941
942    sc = &greth;
943    ifp = &sc->arpcom.ac_if;
944    memset (sc, 0, sizeof (*sc));
945
946    if (config->hardware_address)
947      {
948          memcpy (sc->arpcom.ac_enaddr, config->hardware_address,
949                  ETHER_ADDR_LEN);
950      }
951    else
952      {
953          memset (sc->arpcom.ac_enaddr, 0x08, ETHER_ADDR_LEN);
954      }
955
956    if (config->mtu)
957        mtu = config->mtu;
958    else
959        mtu = ETHERMTU;
960
961    sc->acceptBroadcast = !config->ignore_broadcast;
962    sc->regs = (void *) chip->base_address;
963    sc->vector = chip->vector;
964    sc->txbufs = chip->txd_count;
965    sc->rxbufs = chip->rxd_count;
966   
967    /*
968     * Set up network interface values
969     */
970    ifp->if_softc = sc;
971    ifp->if_unit = unitNumber;
972    ifp->if_name = unitName;
973    ifp->if_mtu = mtu;
974    ifp->if_init = greth_init;
975    ifp->if_ioctl = greth_ioctl;
976    ifp->if_start = greth_start;
977    ifp->if_output = ether_output;
978    ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
979    if (ifp->if_snd.ifq_maxlen == 0)
980        ifp->if_snd.ifq_maxlen = ifqmaxlen;
981
982    /*
983     * Attach the interface
984     */
985    if_attach (ifp);
986    ether_ifattach (ifp);
987
988#ifdef GRETH_DEBUG
989    printf ("GRETH : driver has been attached\n");
990#endif
991    return 1;
992};
993
Note: See TracBrowser for help on using the repository browser.