source: rtems/c/src/libchip/network/greth.c @ 1fe0257

4.10
Last change on this file since 1fe0257 was 1fe0257, checked in by Joel Sherrill <joel.sherrill@…>, on Feb 2, 2012 at 7:04:49 PM

PR 2011/networking GRETH: Moved print to remove potential deadlock

Deadlock may arise when the EDCL bug link is used to tunnel
console output over Ethernet, when Ethernet is down one should
avoid using console (only during debugging of LEON targets)

Author: Marko Isomaki <marko@…>
Signed-off-by: Daniel Hellstrom <daniel@…>

  • Property mode set to 100644
File size: 28.0 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    int anegtout;
270
271    greth_regs *regs;
272
273    regs = sc->regs;
274
275    /* Reset the controller.  */
276    greth.rxInterrupts = 0;
277    greth.rxPackets = 0;
278
279    regs->ctrl = 0;
280    regs->ctrl = GRETH_CTRL_RST;        /* Reset ON */
281    regs->ctrl = 0;                     /* Reset OFF */
282
283    /* Check if mac is gbit capable*/
284    sc->gbit_mac = (regs->ctrl >> 27) & 1;
285
286    /* Get the phy address which assumed to have been set
287       correctly with the reset value in hardware*/
288    phyaddr = (regs->mdio_ctrl >> 11) & 0x1F;
289
290    /* get phy control register default values */
291    while ((phyctrl = read_mii(phyaddr, 0)) & 0x8000) {}
292
293    /* reset PHY and wait for completion */
294    write_mii(phyaddr, 0, 0x8000 | phyctrl);
295
296    while ((read_mii(phyaddr, 0)) & 0x8000) {}
297
298    /* Check if PHY is autoneg capable and then determine operating mode,
299       otherwise force it to 10 Mbit halfduplex */
300    sc->gb = 0;
301    sc->fd = 0;
302    sc->sp = 0;
303    sc->auto_neg = 0;
304    sc->auto_neg_time = 0;
305    /* the anegtout variable is needed because print cannot be done before mac has
306       been reconfigured due to a possible deadlock situation if rtems
307       is run through the edcl with uart polling (-u)*/
308    anegtout = 0;
309    if ((phyctrl >> 12) & 1) {
310            /*wait for auto negotiation to complete*/
311            msecs = 0;
312            sc->auto_neg = 1;
313            if ( rtems_clock_get_tod_timeval(&tstart) == RTEMS_NOT_DEFINED){
314                /* Not inited, set to epoch */
315                rtems_time_of_day time;
316                time.year   = 1988;
317                time.month  = 1;
318                time.day    = 1;
319                time.hour   = 0;
320                time.minute = 0;
321                time.second = 0;
322                time.ticks  = 0;
323                rtems_clock_set(&time);
324
325                tstart.tv_sec = 0;
326                tstart.tv_usec = 0;
327                rtems_clock_get_tod_timeval(&tstart);
328            }
329            while (!(((phystatus = read_mii(phyaddr, 1)) >> 5) & 1)) {
330                    if ( rtems_clock_get_tod_timeval(&tnow) != RTEMS_SUCCESSFUL )
331                      printk("rtems_clock_get_tod_timeval failed\n\r");
332                    msecs = (tnow.tv_sec-tstart.tv_sec)*1000+(tnow.tv_usec-tstart.tv_usec)/1000;
333                    if ( msecs > GRETH_AUTONEGO_TIMEOUT_MS ){
334                            sc->auto_neg_time = msecs;
335                            anegtout = 1
336                            tmp1 = read_mii(phyaddr, 0);
337                            sc->gb = ((phyctrl >> 6) & 1) && !((phyctrl >> 13) & 1);
338                            sc->sp = !((phyctrl >> 6) & 1) && ((phyctrl >> 13) & 1);
339                            sc->fd = (phyctrl >> 8) & 1;
340                            goto auto_neg_done;
341                    }
342            }
343            sc->auto_neg_time = msecs;
344            sc->phydev.adv = read_mii(phyaddr, 4);
345            sc->phydev.part = read_mii(phyaddr, 5);
346            if ((phystatus >> 8) & 1) {
347                    sc->phydev.extadv = read_mii(phyaddr, 9);
348                    sc->phydev.extpart = read_mii(phyaddr, 10);
349                       if ( (sc->phydev.extadv & GRETH_MII_EXTADV_1000FD) &&
350                            (sc->phydev.extpart & GRETH_MII_EXTPRT_1000FD)) {
351                               sc->gb = 1;
352                               sc->fd = 1;
353                       }
354                       if ( (sc->phydev.extadv & GRETH_MII_EXTADV_1000HD) &&
355                            (sc->phydev.extpart & GRETH_MII_EXTPRT_1000HD)) {
356                               sc->gb = 1;
357                               sc->fd = 0;
358                       }
359            }
360            if ((sc->gb == 0) || ((sc->gb == 1) && (sc->gbit_mac == 0))) {
361                    if ( (sc->phydev.adv & GRETH_MII_100TXFD) &&
362                         (sc->phydev.part & GRETH_MII_100TXFD)) {
363                            sc->sp = 1;
364                            sc->fd = 1;
365                    }
366                    if ( (sc->phydev.adv & GRETH_MII_100TXHD) &&
367                         (sc->phydev.part & GRETH_MII_100TXHD)) {
368                            sc->sp = 1;
369                            sc->fd = 0;
370                    }
371                    if ( (sc->phydev.adv & GRETH_MII_10FD) &&
372                         (sc->phydev.part & GRETH_MII_10FD)) {
373                            sc->fd = 1;
374                    }
375            }
376    }
377auto_neg_done:
378    sc->phydev.vendor = 0;
379    sc->phydev.device = 0;
380    sc->phydev.rev = 0;
381    phystatus = read_mii(phyaddr, 1);
382
383    /*Read out PHY info if extended registers are available */
384    if (phystatus & 1) {
385            tmp1 = read_mii(phyaddr, 2);
386            tmp2 = read_mii(phyaddr, 3);
387
388            sc->phydev.vendor = (tmp1 << 6) | ((tmp2 >> 10) & 0x3F);
389            sc->phydev.rev = tmp2 & 0xF;
390            sc->phydev.device = (tmp2 >> 4) & 0x3F;
391    }
392
393    /* Force to 10 mbit half duplex if the 10/100 MAC is used with a 1000 PHY*/
394    /*check if marvell 88EE1111 PHY. Needs special reset handling */
395    if ((phystatus & 1) && (sc->phydev.vendor == 0x005043) && (sc->phydev.device == 0x0C)) {
396            if (((sc->gb) && !(sc->gbit_mac)) || !((phyctrl >> 12) & 1)) {
397                    write_mii(phyaddr, 0, sc->sp << 13);
398                    write_mii(phyaddr, 0, 0x8000);
399                    sc->gb = 0;
400                    sc->sp = 0;
401                    sc->fd = 0;
402            }
403    } else {
404            if (((sc->gb) && !(sc->gbit_mac))  || !((phyctrl >> 12) & 1)) {
405                    write_mii(phyaddr, 0, sc->sp << 13);
406                    sc->gb = 0;
407                    sc->sp = 0;
408                    sc->fd = 0;
409            }
410    }
411    while ((read_mii(phyaddr, 0)) & 0x8000) {}
412
413    regs->ctrl = 0;
414    regs->ctrl = GRETH_CTRL_RST;        /* Reset ON */
415    regs->ctrl = 0;
416
417    /* Initialize rx/tx descriptor pointers */
418    sc->txdesc = (greth_rxtxdesc *) almalloc(1024);
419    sc->rxdesc = (greth_rxtxdesc *) almalloc(1024);
420    sc->tx_ptr = 0;
421    sc->tx_dptr = 0;
422    sc->tx_cnt = 0;
423    sc->rx_ptr = 0;
424    regs->txdesc = (uintptr_t) sc->txdesc;
425    regs->rxdesc = (uintptr_t) sc->rxdesc;
426
427    sc->rxmbuf = calloc(sc->rxbufs, sizeof(*sc->rxmbuf));
428    sc->txmbuf = calloc(sc->txbufs, sizeof(*sc->txmbuf));
429
430    for (i = 0; i < sc->txbufs; i++)
431      {
432              sc->txdesc[i].ctrl = 0;
433              if (!(sc->gbit_mac)) {
434                      sc->txdesc[i].addr = malloc(GRETH_MAXBUF_LEN);
435              }
436#ifdef GRETH_DEBUG
437              /* printf("TXBUF: %08x\n", (int) sc->txdesc[i].addr); */
438#endif
439      }
440    for (i = 0; i < sc->rxbufs; i++)
441      {
442
443          MGETHDR (m, M_WAIT, MT_DATA);
444          MCLGET (m, M_WAIT);
445          if (sc->gbit_mac)
446                  m->m_data += 2;
447          m->m_pkthdr.rcvif = &sc->arpcom.ac_if;
448          sc->rxmbuf[i] = m;
449          sc->rxdesc[i].addr = (uint32_t *) mtod(m, uint32_t *);
450          sc->rxdesc[i].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ;
451#ifdef GRETH_DEBUG
452/*        printf("RXBUF: %08x\n", (int) sc->rxdesc[i].addr); */
453#endif
454      }
455    sc->rxdesc[sc->rxbufs - 1].ctrl |= GRETH_RXD_WRAP;
456
457    /* set ethernet address.  */
458    regs->mac_addr_msb =
459      sc->arpcom.ac_enaddr[0] << 8 | sc->arpcom.ac_enaddr[1];
460
461    uint32_t mac_addr_lsb;
462    mac_addr_lsb = sc->arpcom.ac_enaddr[2];
463    mac_addr_lsb <<= 8;
464    mac_addr_lsb |= sc->arpcom.ac_enaddr[3];
465    mac_addr_lsb <<= 8;
466    mac_addr_lsb |= sc->arpcom.ac_enaddr[4];
467    mac_addr_lsb <<= 8;
468    mac_addr_lsb |= sc->arpcom.ac_enaddr[5];
469    regs->mac_addr_lsb = mac_addr_lsb;
470
471    /* install interrupt vector */
472    set_vector(greth_interrupt_handler, sc->vector, 1);
473
474    /* clear all pending interrupts */
475
476    regs->status = 0xffffffff;
477
478#ifdef GRETH_SUSPEND_NOTXBUF
479    regs->ctrl |= GRETH_CTRL_TXIRQ;
480#endif
481
482    regs->ctrl |= GRETH_CTRL_RXEN | (sc->fd << 4) | GRETH_CTRL_RXIRQ | (sc->sp << 7) | (sc->gb << 8);
483   
484    if (anegtout) {
485            printk("Auto negotiation timed out. Selecting default config\n\r");
486    }
487   
488    print_init_info(sc);
489}
490
491static void
492greth_rxDaemon (void *arg)
493{
494    struct ether_header *eh;
495    struct greth_softc *dp = (struct greth_softc *) &greth;
496    struct ifnet *ifp = &dp->arpcom.ac_if;
497    struct mbuf *m;
498    unsigned int len, len_status, bad;
499    rtems_event_set events;
500
501    for (;;)
502      {
503        rtems_bsdnet_event_receive (INTERRUPT_EVENT,
504                                    RTEMS_WAIT | RTEMS_EVENT_ANY,
505                                    RTEMS_NO_TIMEOUT, &events);
506
507#ifdef GRETH_ETH_DEBUG
508    printf ("r\n");
509#endif
510    while (!((len_status =
511                    dp->rxdesc[dp->rx_ptr].ctrl) & GRETH_RXD_ENABLE))
512            {
513                    bad = 0;
514                    if (len_status & GRETH_RXD_TOOLONG)
515                    {
516                            dp->rxLengthError++;
517                            bad = 1;
518                    }
519                    if (len_status & GRETH_RXD_DRIBBLE)
520                    {
521                            dp->rxNonOctet++;
522                            bad = 1;
523                    }
524                    if (len_status & GRETH_RXD_CRCERR)
525                    {
526                            dp->rxBadCRC++;
527                            bad = 1;
528                    }
529                    if (len_status & GRETH_RXD_OVERRUN)
530                    {
531                            dp->rxOverrun++;
532                            bad = 1;
533                    }
534                    if (len_status & GRETH_RXD_LENERR)
535                    {
536                            dp->rxLengthError++;
537                            bad = 1;
538                    }
539                    if (!bad)
540                    {
541                            /* pass on the packet in the receive buffer */
542                            len = len_status & 0x7FF;
543                            m = dp->rxmbuf[dp->rx_ptr];
544#ifdef GRETH_DEBUG
545                            int i;
546                            printf("RX: 0x%08x, Len: %d : ", (int) m->m_data, len);
547                            for (i=0; i<len; i++)
548                                    printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
549                            printf("\n");
550#endif
551                            m->m_len = m->m_pkthdr.len =
552                                    len - sizeof (struct ether_header);
553
554                            eh = mtod (m, struct ether_header *);
555                            m->m_data += sizeof (struct ether_header);
556#ifdef CPU_U32_FIX
557                            if(!(dp->gbit_mac))
558                                    ipalign(m); /* Align packet on 32-bit boundary */
559#endif
560
561                            ether_input (ifp, eh, m);
562                            MGETHDR (m, M_WAIT, MT_DATA);
563                            MCLGET (m, M_WAIT);
564                            if (dp->gbit_mac)
565                                    m->m_data += 2;
566                            dp->rxmbuf[dp->rx_ptr] = m;
567                            m->m_pkthdr.rcvif = ifp;
568                            dp->rxdesc[dp->rx_ptr].addr =
569                                    (uint32_t *) mtod (m, uint32_t *);
570                            dp->rxPackets++;
571                    }
572                    if (dp->rx_ptr == dp->rxbufs - 1) {
573                            dp->rxdesc[dp->rx_ptr].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ | GRETH_RXD_WRAP;
574                    } else {
575                            dp->rxdesc[dp->rx_ptr].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ;
576                    }
577                    dp->regs->ctrl |= GRETH_CTRL_RXEN;
578                    dp->rx_ptr = (dp->rx_ptr + 1) % dp->rxbufs;
579            }
580      }
581
582}
583
584static int inside = 0;
585static void
586sendpacket (struct ifnet *ifp, struct mbuf *m)
587{
588    struct greth_softc *dp = ifp->if_softc;
589    unsigned char *temp;
590    struct mbuf *n;
591    unsigned int len;
592
593    /*printf("Send packet entered\n");*/
594    if (inside) printf ("error: sendpacket re-entered!!\n");
595    inside = 1;
596    /*
597     * Waiting for Transmitter ready
598     */
599    n = m;
600
601    while (dp->txdesc[dp->tx_ptr].ctrl & GRETH_TXD_ENABLE)
602      {
603#ifdef GRETH_SUSPEND_NOTXBUF
604        dp->txdesc[dp->tx_ptr].ctrl |= GRETH_TXD_IRQ;
605        rtems_event_set events;
606        rtems_bsdnet_event_receive (GRETH_TX_WAIT_EVENT,
607                                    RTEMS_WAIT | RTEMS_EVENT_ANY,
608                                    TOD_MILLISECONDS_TO_TICKS(500), &events);
609#endif
610      }
611
612    len = 0;
613    temp = (unsigned char *) dp->txdesc[dp->tx_ptr].addr;
614#ifdef GRETH_DEBUG
615    printf("TXD: 0x%08x : BUF: 0x%08x\n", (int) m->m_data, (int) temp);
616#endif
617    for (;;)
618    {
619#ifdef GRETH_DEBUG
620            int i;
621            printf("MBUF: 0x%08x : ", (int) m->m_data);
622            for (i=0;i<m->m_len;i++)
623                    printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
624            printf("\n");
625#endif
626            len += m->m_len;
627            if (len <= RBUF_SIZE)
628                    memcpy ((void *) temp, (char *) m->m_data, m->m_len);
629            temp += m->m_len;
630            if ((m = m->m_next) == NULL)
631                    break;
632    }
633
634    m_freem (n);
635
636    /* don't send long packets */
637
638    if (len <= GRETH_MAXBUF_LEN) {
639            if (dp->tx_ptr < dp->txbufs-1) {
640                    dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_ENABLE | len;
641            } else {
642                    dp->txdesc[dp->tx_ptr].ctrl =
643                            GRETH_TXD_WRAP | GRETH_TXD_ENABLE | len;
644            }
645            dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
646            dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
647    }
648    inside = 0;
649}
650
651
652static void
653sendpacket_gbit (struct ifnet *ifp, struct mbuf *m)
654{
655        struct greth_softc *dp = ifp->if_softc;
656        unsigned int len;
657
658        /*printf("Send packet entered\n");*/
659        if (inside) printf ("error: sendpacket re-entered!!\n");
660        inside = 1;
661        /*
662         * Waiting for Transmitter ready
663         */
664
665        len = 0;
666#ifdef GRETH_DEBUG
667        printf("TXD: 0x%08x\n", (int) m->m_data);
668#endif
669        for (;;)
670        {
671                while (dp->txdesc[dp->tx_ptr].ctrl & GRETH_TXD_ENABLE)
672                {
673#ifdef GRETH_SUSPEND_NOTXBUF
674                        dp->txdesc[dp->tx_ptr].ctrl |= GRETH_TXD_IRQ;
675                        rtems_event_set events;
676                        rtems_bsdnet_event_receive (GRETH_TX_WAIT_EVENT,
677                                                    RTEMS_WAIT | RTEMS_EVENT_ANY,
678                                                    TOD_MILLISECONDS_TO_TICKS(500), &events);
679#endif
680                }
681#ifdef GRETH_DEBUG
682                int i;
683                printf("MBUF: 0x%08x, Len: %d : ", (int) m->m_data, m->m_len);
684                for (i=0; i<m->m_len; i++)
685                        printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
686                printf("\n");
687#endif
688            len += m->m_len;
689            dp->txdesc[dp->tx_ptr].addr = (uint32_t *)m->m_data;
690            if (dp->tx_ptr < dp->txbufs-1) {
691                    if ((m->m_next) == NULL) {
692                            dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_ENABLE | GRETH_TXD_CS | m->m_len;
693                            break;
694                    } else {
695                            dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_ENABLE | GRETH_TXD_MORE | GRETH_TXD_CS | m->m_len;
696                    }
697            } else {
698                    if ((m->m_next) == NULL) {
699                            dp->txdesc[dp->tx_ptr].ctrl =
700                                    GRETH_TXD_WRAP | GRETH_TXD_ENABLE | GRETH_TXD_CS | m->m_len;
701                            break;
702                    } else {
703                            dp->txdesc[dp->tx_ptr].ctrl =
704                                    GRETH_TXD_WRAP | GRETH_TXD_ENABLE | GRETH_TXD_MORE | GRETH_TXD_CS | m->m_len;
705                    }
706            }
707            dp->txmbuf[dp->tx_ptr] = m;
708            dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
709            dp->tx_cnt++;
710            m = m->m_next;
711
712    }
713        dp->txmbuf[dp->tx_ptr] = m;
714        dp->tx_cnt++;
715        dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
716        dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
717        inside = 0;
718}
719
720/*
721 * Driver transmit daemon
722 */
723void
724greth_txDaemon (void *arg)
725{
726    struct greth_softc *sc = (struct greth_softc *) arg;
727    struct ifnet *ifp = &sc->arpcom.ac_if;
728    struct mbuf *m;
729    rtems_event_set events;
730
731    for (;;)
732    {
733            /*
734             * Wait for packet
735             */
736
737            rtems_bsdnet_event_receive (START_TRANSMIT_EVENT,
738                                        RTEMS_EVENT_ANY | RTEMS_WAIT,
739                                        RTEMS_NO_TIMEOUT, &events);
740#ifdef GRETH_DEBUG
741            printf ("t\n");
742#endif
743
744            /*
745             * Send packets till queue is empty
746             */
747
748
749            for (;;)
750            {
751                    /*
752                     * Get the next mbuf chain to transmit.
753                     */
754                    IF_DEQUEUE (&ifp->if_snd, m);
755                    if (!m)
756                            break;
757                    sendpacket(ifp, m);
758            }
759            ifp->if_flags &= ~IFF_OACTIVE;
760    }
761}
762
763/*
764 * Driver transmit daemon
765 */
766void
767greth_txDaemon_gbit (void *arg)
768{
769    struct greth_softc *sc = (struct greth_softc *) arg;
770    struct ifnet *ifp = &sc->arpcom.ac_if;
771    struct mbuf *m;
772    rtems_event_set events;
773
774    for (;;)
775    {
776            /*
777             * Wait for packet
778             */
779
780            rtems_bsdnet_event_receive (START_TRANSMIT_EVENT,
781                                        RTEMS_EVENT_ANY | RTEMS_WAIT,
782                                        RTEMS_NO_TIMEOUT, &events);
783#ifdef GRETH_DEBUG
784            printf ("t\n");
785#endif
786
787            /*
788             * Send packets till queue is empty
789             */
790            for (;;)
791            {
792                    while((sc->tx_cnt > 0) && !(sc->txdesc[sc->tx_dptr].ctrl & GRETH_TXD_ENABLE)) {
793                            m_free(sc->txmbuf[sc->tx_dptr]);
794                            sc->tx_dptr = (sc->tx_dptr + 1) % sc->txbufs;
795                            sc->tx_cnt--;
796                    }
797                    /*
798                     * Get the next mbuf chain to transmit.
799                     */
800                    IF_DEQUEUE (&ifp->if_snd, m);
801                    if (!m)
802                            break;
803                    sendpacket_gbit(ifp, m);
804            }
805            ifp->if_flags &= ~IFF_OACTIVE;
806    }
807}
808
809
810static void
811greth_start (struct ifnet *ifp)
812{
813    struct greth_softc *sc = ifp->if_softc;
814
815    ifp->if_flags |= IFF_OACTIVE;
816    rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
817
818}
819
820/*
821 * Initialize and start the device
822 */
823static void
824greth_init (void *arg)
825{
826    struct greth_softc *sc = arg;
827    struct ifnet *ifp = &sc->arpcom.ac_if;
828
829    if (sc->txDaemonTid == 0)
830      {
831
832          /*
833           * Set up GRETH hardware
834           */
835          greth_initialize_hardware (sc);
836
837          /*
838           * Start driver tasks
839           */
840          sc->rxDaemonTid = rtems_bsdnet_newproc ("DCrx", 4096,
841                                                  greth_rxDaemon, sc);
842          if (sc->gbit_mac) {
843                  sc->txDaemonTid = rtems_bsdnet_newproc ("DCtx", 4096,
844                                                          greth_txDaemon_gbit, sc);
845          } else {
846                  sc->txDaemonTid = rtems_bsdnet_newproc ("DCtx", 4096,
847                                                          greth_txDaemon, sc);
848          }
849
850      }
851
852    /*
853     * Tell the world that we're running.
854     */
855    ifp->if_flags |= IFF_RUNNING;
856
857}
858
859/*
860 * Stop the device
861 */
862static void
863greth_stop (struct greth_softc *sc)
864{
865    struct ifnet *ifp = &sc->arpcom.ac_if;
866
867    ifp->if_flags &= ~IFF_RUNNING;
868
869    sc->regs->ctrl = 0;                 /* RX/TX OFF */
870    sc->regs->ctrl = GRETH_CTRL_RST;    /* Reset ON */
871    sc->regs->ctrl = 0;                 /* Reset OFF */
872}
873
874
875/*
876 * Show interface statistics
877 */
878static void
879greth_stats (struct greth_softc *sc)
880{
881  printf ("      Rx Interrupts:%-8lu", sc->rxInterrupts);
882  printf ("      Rx Packets:%-8lu", sc->rxPackets);
883  printf ("          Length:%-8lu", sc->rxLengthError);
884  printf ("       Non-octet:%-8lu\n", sc->rxNonOctet);
885  printf ("            Bad CRC:%-8lu", sc->rxBadCRC);
886  printf ("         Overrun:%-8lu", sc->rxOverrun);
887  printf ("      Tx Interrupts:%-8lu", sc->txInterrupts);
888}
889
890/*
891 * Driver ioctl handler
892 */
893static int
894greth_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data)
895{
896    struct greth_softc *sc = ifp->if_softc;
897    int error = 0;
898
899    switch (command)
900      {
901      case SIOCGIFADDR:
902      case SIOCSIFADDR:
903          ether_ioctl (ifp, command, data);
904          break;
905
906      case SIOCSIFFLAGS:
907          switch (ifp->if_flags & (IFF_UP | IFF_RUNNING))
908            {
909            case IFF_RUNNING:
910                greth_stop (sc);
911                break;
912
913            case IFF_UP:
914                greth_init (sc);
915                break;
916
917            case IFF_UP | IFF_RUNNING:
918                greth_stop (sc);
919                greth_init (sc);
920                break;
921       default:
922                break;
923            }
924          break;
925
926      case SIO_RTEMS_SHOW_STATS:
927          greth_stats (sc);
928          break;
929
930          /*
931           * FIXME: All sorts of multicast commands need to be added here!
932           */
933      default:
934          error = EINVAL;
935          break;
936      }
937
938    return error;
939}
940
941/*
942 * Attach an GRETH driver to the system
943 */
944int
945rtems_greth_driver_attach (struct rtems_bsdnet_ifconfig *config,
946                           greth_configuration_t *chip)
947{
948    struct greth_softc *sc;
949    struct ifnet *ifp;
950    int mtu;
951    int unitNumber;
952    char *unitName;
953
954      /* parse driver name */
955    if ((unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName)) < 0)
956        return 0;
957
958    sc = &greth;
959    ifp = &sc->arpcom.ac_if;
960    memset (sc, 0, sizeof (*sc));
961
962    if (config->hardware_address)
963      {
964          memcpy (sc->arpcom.ac_enaddr, config->hardware_address,
965                  ETHER_ADDR_LEN);
966      }
967    else
968      {
969          memset (sc->arpcom.ac_enaddr, 0x08, ETHER_ADDR_LEN);
970      }
971
972    if (config->mtu)
973        mtu = config->mtu;
974    else
975        mtu = ETHERMTU;
976
977    sc->acceptBroadcast = !config->ignore_broadcast;
978    sc->regs = (void *) chip->base_address;
979    sc->vector = chip->vector;
980    sc->txbufs = chip->txd_count;
981    sc->rxbufs = chip->rxd_count;
982
983    /*
984     * Set up network interface values
985     */
986    ifp->if_softc = sc;
987    ifp->if_unit = unitNumber;
988    ifp->if_name = unitName;
989    ifp->if_mtu = mtu;
990    ifp->if_init = greth_init;
991    ifp->if_ioctl = greth_ioctl;
992    ifp->if_start = greth_start;
993    ifp->if_output = ether_output;
994    ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
995    if (ifp->if_snd.ifq_maxlen == 0)
996        ifp->if_snd.ifq_maxlen = ifqmaxlen;
997
998    /*
999     * Attach the interface
1000     */
1001    if_attach (ifp);
1002    ether_ifattach (ifp);
1003
1004#ifdef GRETH_DEBUG
1005    printf ("GRETH : driver has been attached\n");
1006#endif
1007    return 1;
1008};
1009
Note: See TracBrowser for help on using the repository browser.