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

4.104.115
Last change on this file since c48572d9 was c48572d9, checked in by Ralf Corsepius <ralf.corsepius@…>, on 05/31/10 at 13:27:07

2010-05-31 Ralf Corsépius <ralf.corsepius@…>

  • libchip/network/greth.c: Misc. hacks to allow compilation on 16bit targets.
  • Property mode set to 100644
File size: 27.7 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 *) (((uintptr_t)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    struct timeval 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_tod_timeval(&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.tv_sec = 0;
321                tstart.tv_usec = 0;
322                rtems_clock_get_tod_timeval(&tstart);
323            }
324            while (!(((phystatus = read_mii(phyaddr, 1)) >> 5) & 1)) {
325                    if ( rtems_clock_get_tod_timeval(&tnow) != RTEMS_SUCCESSFUL )
326                      printk("rtems_clock_get_tod_timeval failed\n\r");
327                    msecs = (tnow.tv_sec-tstart.tv_sec)*1000+(tnow.tv_usec-tstart.tv_usec)/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 = (uintptr_t) sc->txdesc;
420    regs->rxdesc = (uintptr_t) 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
456    uint32_t mac_addr_lsb;
457    mac_addr_lsb = sc->arpcom.ac_enaddr[2];
458    mac_addr_lsb <<= 8;
459    mac_addr_lsb |= sc->arpcom.ac_enaddr[3];
460    mac_addr_lsb <<= 8;
461    mac_addr_lsb |= sc->arpcom.ac_enaddr[4];
462    mac_addr_lsb <<= 8;
463    mac_addr_lsb |= sc->arpcom.ac_enaddr[5];
464    regs->mac_addr_lsb = mac_addr_lsb;
465
466    /* install interrupt vector */
467    set_vector(greth_interrupt_handler, sc->vector, 1);
468
469    /* clear all pending interrupts */
470
471    regs->status = 0xffffffff;
472
473#ifdef GRETH_SUSPEND_NOTXBUF
474    regs->ctrl |= GRETH_CTRL_TXIRQ;
475#endif
476
477    regs->ctrl |= GRETH_CTRL_RXEN | (sc->fd << 4) | GRETH_CTRL_RXIRQ | (sc->sp << 7) | (sc->gb << 8);
478
479    print_init_info(sc);
480}
481
482static void
483greth_rxDaemon (void *arg)
484{
485    struct ether_header *eh;
486    struct greth_softc *dp = (struct greth_softc *) &greth;
487    struct ifnet *ifp = &dp->arpcom.ac_if;
488    struct mbuf *m;
489    unsigned int len, len_status, bad;
490    rtems_event_set events;
491
492    for (;;)
493      {
494        rtems_bsdnet_event_receive (INTERRUPT_EVENT,
495                                    RTEMS_WAIT | RTEMS_EVENT_ANY,
496                                    RTEMS_NO_TIMEOUT, &events);
497
498#ifdef GRETH_ETH_DEBUG
499    printf ("r\n");
500#endif
501    while (!((len_status =
502                    dp->rxdesc[dp->rx_ptr].ctrl) & GRETH_RXD_ENABLE))
503            {
504                    bad = 0;
505                    if (len_status & GRETH_RXD_TOOLONG)
506                    {
507                            dp->rxLengthError++;
508                            bad = 1;
509                    }
510                    if (len_status & GRETH_RXD_DRIBBLE)
511                    {
512                            dp->rxNonOctet++;
513                            bad = 1;
514                    }
515                    if (len_status & GRETH_RXD_CRCERR)
516                    {
517                            dp->rxBadCRC++;
518                            bad = 1;
519                    }
520                    if (len_status & GRETH_RXD_OVERRUN)
521                    {
522                            dp->rxOverrun++;
523                            bad = 1;
524                    }
525                    if (len_status & GRETH_RXD_LENERR)
526                    {
527                            dp->rxLengthError++;
528                            bad = 1;
529                    }
530                    if (!bad)
531                    {
532                            /* pass on the packet in the receive buffer */
533                            len = len_status & 0x7FF;
534                            m = dp->rxmbuf[dp->rx_ptr];
535#ifdef GRETH_DEBUG
536                            int i;
537                            printf("RX: 0x%08x, Len: %d : ", (int) m->m_data, len);
538                            for (i=0; i<len; i++)
539                                    printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
540                            printf("\n");
541#endif
542                            m->m_len = m->m_pkthdr.len =
543                                    len - sizeof (struct ether_header);
544
545                            eh = mtod (m, struct ether_header *);
546                            m->m_data += sizeof (struct ether_header);
547#ifdef CPU_U32_FIX
548                            if(!(dp->gbit_mac))
549                                    ipalign(m); /* Align packet on 32-bit boundary */
550#endif
551
552                            ether_input (ifp, eh, m);
553                            MGETHDR (m, M_WAIT, MT_DATA);
554                            MCLGET (m, M_WAIT);
555                            if (dp->gbit_mac)
556                                    m->m_data += 2;
557                            dp->rxmbuf[dp->rx_ptr] = m;
558                            m->m_pkthdr.rcvif = ifp;
559                            dp->rxdesc[dp->rx_ptr].addr =
560                                    (uint32_t *) mtod (m, uint32_t *);
561                            dp->rxPackets++;
562                    }
563                    if (dp->rx_ptr == dp->rxbufs - 1) {
564                            dp->rxdesc[dp->rx_ptr].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ | GRETH_RXD_WRAP;
565                    } else {
566                            dp->rxdesc[dp->rx_ptr].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ;
567                    }
568                    dp->regs->ctrl |= GRETH_CTRL_RXEN;
569                    dp->rx_ptr = (dp->rx_ptr + 1) % dp->rxbufs;
570            }
571      }
572
573}
574
575static int inside = 0;
576static void
577sendpacket (struct ifnet *ifp, struct mbuf *m)
578{
579    struct greth_softc *dp = ifp->if_softc;
580    unsigned char *temp;
581    struct mbuf *n;
582    unsigned int len;
583
584    /*printf("Send packet entered\n");*/
585    if (inside) printf ("error: sendpacket re-entered!!\n");
586    inside = 1;
587    /*
588     * Waiting for Transmitter ready
589     */
590    n = m;
591
592    while (dp->txdesc[dp->tx_ptr].ctrl & GRETH_TXD_ENABLE)
593      {
594#ifdef GRETH_SUSPEND_NOTXBUF
595        dp->txdesc[dp->tx_ptr].ctrl |= GRETH_TXD_IRQ;
596        rtems_event_set events;
597        rtems_bsdnet_event_receive (GRETH_TX_WAIT_EVENT,
598                                    RTEMS_WAIT | RTEMS_EVENT_ANY,
599                                    TOD_MILLISECONDS_TO_TICKS(500), &events);
600#endif
601      }
602
603    len = 0;
604    temp = (unsigned char *) dp->txdesc[dp->tx_ptr].addr;
605#ifdef GRETH_DEBUG
606    printf("TXD: 0x%08x : BUF: 0x%08x\n", (int) m->m_data, (int) temp);
607#endif
608    for (;;)
609    {
610#ifdef GRETH_DEBUG
611            int i;
612            printf("MBUF: 0x%08x : ", (int) m->m_data);
613            for (i=0;i<m->m_len;i++)
614                    printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
615            printf("\n");
616#endif
617            len += m->m_len;
618            if (len <= RBUF_SIZE)
619                    memcpy ((void *) temp, (char *) m->m_data, m->m_len);
620            temp += m->m_len;
621            if ((m = m->m_next) == NULL)
622                    break;
623    }
624
625    m_freem (n);
626
627    /* don't send long packets */
628
629    if (len <= GRETH_MAXBUF_LEN) {
630            if (dp->tx_ptr < dp->txbufs-1) {
631                    dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_ENABLE | len;
632            } else {
633                    dp->txdesc[dp->tx_ptr].ctrl =
634                            GRETH_TXD_WRAP | GRETH_TXD_ENABLE | len;
635            }
636            dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
637            dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
638    }
639    inside = 0;
640}
641
642
643static void
644sendpacket_gbit (struct ifnet *ifp, struct mbuf *m)
645{
646        struct greth_softc *dp = ifp->if_softc;
647        unsigned int len;
648
649        /*printf("Send packet entered\n");*/
650        if (inside) printf ("error: sendpacket re-entered!!\n");
651        inside = 1;
652        /*
653         * Waiting for Transmitter ready
654         */
655
656        len = 0;
657#ifdef GRETH_DEBUG
658        printf("TXD: 0x%08x\n", (int) m->m_data);
659#endif
660        for (;;)
661        {
662                while (dp->txdesc[dp->tx_ptr].ctrl & GRETH_TXD_ENABLE)
663                {
664#ifdef GRETH_SUSPEND_NOTXBUF
665                        dp->txdesc[dp->tx_ptr].ctrl |= GRETH_TXD_IRQ;
666                        rtems_event_set events;
667                        rtems_bsdnet_event_receive (GRETH_TX_WAIT_EVENT,
668                                                    RTEMS_WAIT | RTEMS_EVENT_ANY,
669                                                    TOD_MILLISECONDS_TO_TICKS(500), &events);
670#endif
671                }
672#ifdef GRETH_DEBUG
673                int i;
674                printf("MBUF: 0x%08x, Len: %d : ", (int) m->m_data, m->m_len);
675                for (i=0; i<m->m_len; i++)
676                        printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
677                printf("\n");
678#endif
679            len += m->m_len;
680            dp->txdesc[dp->tx_ptr].addr = (uint32_t *)m->m_data;
681            if (dp->tx_ptr < dp->txbufs-1) {
682                    if ((m->m_next) == NULL) {
683                            dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_ENABLE | GRETH_TXD_CS | m->m_len;
684                            break;
685                    } else {
686                            dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_ENABLE | GRETH_TXD_MORE | GRETH_TXD_CS | m->m_len;
687                    }
688            } else {
689                    if ((m->m_next) == NULL) {
690                            dp->txdesc[dp->tx_ptr].ctrl =
691                                    GRETH_TXD_WRAP | GRETH_TXD_ENABLE | GRETH_TXD_CS | m->m_len;
692                            break;
693                    } else {
694                            dp->txdesc[dp->tx_ptr].ctrl =
695                                    GRETH_TXD_WRAP | GRETH_TXD_ENABLE | GRETH_TXD_MORE | GRETH_TXD_CS | m->m_len;
696                    }
697            }
698            dp->txmbuf[dp->tx_ptr] = m;
699            dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
700            dp->tx_cnt++;
701            m = m->m_next;
702
703    }
704        dp->txmbuf[dp->tx_ptr] = m;
705        dp->tx_cnt++;
706        dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
707        dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
708        inside = 0;
709}
710
711/*
712 * Driver transmit daemon
713 */
714void
715greth_txDaemon (void *arg)
716{
717    struct greth_softc *sc = (struct greth_softc *) arg;
718    struct ifnet *ifp = &sc->arpcom.ac_if;
719    struct mbuf *m;
720    rtems_event_set events;
721
722    for (;;)
723    {
724            /*
725             * Wait for packet
726             */
727
728            rtems_bsdnet_event_receive (START_TRANSMIT_EVENT,
729                                        RTEMS_EVENT_ANY | RTEMS_WAIT,
730                                        RTEMS_NO_TIMEOUT, &events);
731#ifdef GRETH_DEBUG
732            printf ("t\n");
733#endif
734
735            /*
736             * Send packets till queue is empty
737             */
738
739
740            for (;;)
741            {
742                    /*
743                     * Get the next mbuf chain to transmit.
744                     */
745                    IF_DEQUEUE (&ifp->if_snd, m);
746                    if (!m)
747                            break;
748                    sendpacket(ifp, m);
749            }
750            ifp->if_flags &= ~IFF_OACTIVE;
751    }
752}
753
754/*
755 * Driver transmit daemon
756 */
757void
758greth_txDaemon_gbit (void *arg)
759{
760    struct greth_softc *sc = (struct greth_softc *) arg;
761    struct ifnet *ifp = &sc->arpcom.ac_if;
762    struct mbuf *m;
763    rtems_event_set events;
764
765    for (;;)
766    {
767            /*
768             * Wait for packet
769             */
770
771            rtems_bsdnet_event_receive (START_TRANSMIT_EVENT,
772                                        RTEMS_EVENT_ANY | RTEMS_WAIT,
773                                        RTEMS_NO_TIMEOUT, &events);
774#ifdef GRETH_DEBUG
775            printf ("t\n");
776#endif
777
778            /*
779             * Send packets till queue is empty
780             */
781            for (;;)
782            {
783                    while((sc->tx_cnt > 0) && !(sc->txdesc[sc->tx_dptr].ctrl & GRETH_TXD_ENABLE)) {
784                            m_free(sc->txmbuf[sc->tx_dptr]);
785                            sc->tx_dptr = (sc->tx_dptr + 1) % sc->txbufs;
786                            sc->tx_cnt--;
787                    }
788                    /*
789                     * Get the next mbuf chain to transmit.
790                     */
791                    IF_DEQUEUE (&ifp->if_snd, m);
792                    if (!m)
793                            break;
794                    sendpacket_gbit(ifp, m);
795            }
796            ifp->if_flags &= ~IFF_OACTIVE;
797    }
798}
799
800
801static void
802greth_start (struct ifnet *ifp)
803{
804    struct greth_softc *sc = ifp->if_softc;
805
806    ifp->if_flags |= IFF_OACTIVE;
807    rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
808
809}
810
811/*
812 * Initialize and start the device
813 */
814static void
815greth_init (void *arg)
816{
817    struct greth_softc *sc = arg;
818    struct ifnet *ifp = &sc->arpcom.ac_if;
819
820    if (sc->txDaemonTid == 0)
821      {
822
823          /*
824           * Set up GRETH hardware
825           */
826          greth_initialize_hardware (sc);
827
828          /*
829           * Start driver tasks
830           */
831          sc->rxDaemonTid = rtems_bsdnet_newproc ("DCrx", 4096,
832                                                  greth_rxDaemon, sc);
833          if (sc->gbit_mac) {
834                  sc->txDaemonTid = rtems_bsdnet_newproc ("DCtx", 4096,
835                                                          greth_txDaemon_gbit, sc);
836          } else {
837                  sc->txDaemonTid = rtems_bsdnet_newproc ("DCtx", 4096,
838                                                          greth_txDaemon, sc);
839          }
840
841      }
842
843    /*
844     * Tell the world that we're running.
845     */
846    ifp->if_flags |= IFF_RUNNING;
847
848}
849
850/*
851 * Stop the device
852 */
853static void
854greth_stop (struct greth_softc *sc)
855{
856    struct ifnet *ifp = &sc->arpcom.ac_if;
857
858    ifp->if_flags &= ~IFF_RUNNING;
859
860    sc->regs->ctrl = 0;                 /* RX/TX OFF */
861    sc->regs->ctrl = GRETH_CTRL_RST;    /* Reset ON */
862    sc->regs->ctrl = 0;                 /* Reset OFF */
863}
864
865
866/*
867 * Show interface statistics
868 */
869static void
870greth_stats (struct greth_softc *sc)
871{
872  printf ("      Rx Interrupts:%-8lu", sc->rxInterrupts);
873  printf ("      Rx Packets:%-8lu", sc->rxPackets);
874  printf ("          Length:%-8lu", sc->rxLengthError);
875  printf ("       Non-octet:%-8lu\n", sc->rxNonOctet);
876  printf ("            Bad CRC:%-8lu", sc->rxBadCRC);
877  printf ("         Overrun:%-8lu", sc->rxOverrun);
878  printf ("      Tx Interrupts:%-8lu", sc->txInterrupts);
879}
880
881/*
882 * Driver ioctl handler
883 */
884static int
885greth_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data)
886{
887    struct greth_softc *sc = ifp->if_softc;
888    int error = 0;
889
890    switch (command)
891      {
892      case SIOCGIFADDR:
893      case SIOCSIFADDR:
894          ether_ioctl (ifp, command, data);
895          break;
896
897      case SIOCSIFFLAGS:
898          switch (ifp->if_flags & (IFF_UP | IFF_RUNNING))
899            {
900            case IFF_RUNNING:
901                greth_stop (sc);
902                break;
903
904            case IFF_UP:
905                greth_init (sc);
906                break;
907
908            case IFF_UP | IFF_RUNNING:
909                greth_stop (sc);
910                greth_init (sc);
911                break;
912       default:
913                break;
914            }
915          break;
916
917      case SIO_RTEMS_SHOW_STATS:
918          greth_stats (sc);
919          break;
920
921          /*
922           * FIXME: All sorts of multicast commands need to be added here!
923           */
924      default:
925          error = EINVAL;
926          break;
927      }
928
929    return error;
930}
931
932/*
933 * Attach an GRETH driver to the system
934 */
935int
936rtems_greth_driver_attach (struct rtems_bsdnet_ifconfig *config,
937                           greth_configuration_t *chip)
938{
939    struct greth_softc *sc;
940    struct ifnet *ifp;
941    int mtu;
942    int unitNumber;
943    char *unitName;
944
945      /* parse driver name */
946    if ((unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName)) < 0)
947        return 0;
948
949    sc = &greth;
950    ifp = &sc->arpcom.ac_if;
951    memset (sc, 0, sizeof (*sc));
952
953    if (config->hardware_address)
954      {
955          memcpy (sc->arpcom.ac_enaddr, config->hardware_address,
956                  ETHER_ADDR_LEN);
957      }
958    else
959      {
960          memset (sc->arpcom.ac_enaddr, 0x08, ETHER_ADDR_LEN);
961      }
962
963    if (config->mtu)
964        mtu = config->mtu;
965    else
966        mtu = ETHERMTU;
967
968    sc->acceptBroadcast = !config->ignore_broadcast;
969    sc->regs = (void *) chip->base_address;
970    sc->vector = chip->vector;
971    sc->txbufs = chip->txd_count;
972    sc->rxbufs = chip->rxd_count;
973
974    /*
975     * Set up network interface values
976     */
977    ifp->if_softc = sc;
978    ifp->if_unit = unitNumber;
979    ifp->if_name = unitName;
980    ifp->if_mtu = mtu;
981    ifp->if_init = greth_init;
982    ifp->if_ioctl = greth_ioctl;
983    ifp->if_start = greth_start;
984    ifp->if_output = ether_output;
985    ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
986    if (ifp->if_snd.ifq_maxlen == 0)
987        ifp->if_snd.ifq_maxlen = ifqmaxlen;
988
989    /*
990     * Attach the interface
991     */
992    if_attach (ifp);
993    ether_ifattach (ifp);
994
995#ifdef GRETH_DEBUG
996    printf ("GRETH : driver has been attached\n");
997#endif
998    return 1;
999};
1000
Note: See TracBrowser for help on using the repository browser.