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

Last change on this file since c167b56 was c167b56, checked in by Daniel Hellstrom <daniel@…>, on 04/05/12 at 15:23:17

GRETH: use shared-irq service instead of BSP specific set_vec()

The ISR code is updated to use argument instead of global greth
structure, now that the greth private is available in the ISR.

The shared-irq routines will unmask the IRQ, so the forced LEON3
BSP unmask/clear IRQ is removed.

Signed-off-by: Daniel Hellstrom <daniel@…>

  • Property mode set to 100644
File size: 33.3 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 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#include <bsp.h>
16
17#ifdef GRETH_SUPPORTED
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/* #define GRETH_DEBUG */
46
47#ifdef CPU_U32_FIX
48extern void ipalign(struct mbuf *m);
49#endif
50
51/* Used when reading from memory written by GRETH DMA unit */
52#ifndef GRETH_MEM_LOAD
53#define GRETH_MEM_LOAD(addr) (*(volatile unsigned int *)(addr))
54#endif
55
56/*
57 * Number of OCs supported by this driver
58 */
59#define NOCDRIVER       1
60
61/*
62 * Receive buffer size -- Allow for a full ethernet packet including CRC
63 */
64#define RBUF_SIZE 1518
65
66#define ET_MINLEN 64            /* minimum message length */
67
68/*
69 * RTEMS event used by interrupt handler to signal driver tasks.
70 * This must not be any of the events used by the network task synchronization.
71 */
72#define INTERRUPT_EVENT RTEMS_EVENT_1
73
74/*
75 * RTEMS event used to start transmit daemon.
76 * This must not be the same as INTERRUPT_EVENT.
77 */
78#define START_TRANSMIT_EVENT    RTEMS_EVENT_2
79
80 /* event to send when tx buffers become available */
81#define GRETH_TX_WAIT_EVENT  RTEMS_EVENT_3
82
83#if (MCLBYTES < RBUF_SIZE)
84# error "Driver must have MCLBYTES > RBUF_SIZE"
85#endif
86
87/* 4s Autonegotiation Timeout */
88#ifndef GRETH_AUTONEGO_TIMEOUT_MS
89#define GRETH_AUTONEGO_TIMEOUT_MS 4000
90#endif
91const struct timespec greth_tan = {
92   GRETH_AUTONEGO_TIMEOUT_MS/1000,
93   GRETH_AUTONEGO_TIMEOUT_MS*1000000
94};
95
96/* For optimizing the autonegotiation time */
97#define GRETH_AUTONEGO_PRINT_TIME
98
99/* Ethernet buffer descriptor */
100
101typedef struct _greth_rxtxdesc {
102   volatile uint32_t ctrl; /* Length and status */
103   uint32_t *addr;         /* Buffer pointer */
104} greth_rxtxdesc;
105
106
107/*
108 * Per-device data
109 */
110struct greth_softc
111{
112
113   struct arpcom arpcom;
114
115   greth_regs *regs;
116
117   int acceptBroadcast;
118   rtems_id daemonTid;
119
120   unsigned int tx_ptr;
121   unsigned int tx_dptr;
122   unsigned int tx_cnt;
123   unsigned int rx_ptr;
124   unsigned int txbufs;
125   unsigned int rxbufs;
126   greth_rxtxdesc *txdesc;
127   greth_rxtxdesc *rxdesc;
128   struct mbuf **rxmbuf;
129   struct mbuf **txmbuf;
130   rtems_vector_number vector;
131
132   /* TX descriptor interrupt generation */
133   int tx_int_gen;
134   int tx_int_gen_cur;
135   struct mbuf *next_tx_mbuf;
136   int max_fragsize;
137
138   /*Status*/
139   struct phy_device_info phydev;
140   int fd;
141   int sp;
142   int gb;
143   int gbit_mac;
144   int auto_neg;
145   struct timespec auto_neg_time;
146
147   /*
148    * Statistics
149    */
150   unsigned long rxInterrupts;
151
152   unsigned long rxPackets;
153   unsigned long rxLengthError;
154   unsigned long rxNonOctet;
155   unsigned long rxBadCRC;
156   unsigned long rxOverrun;
157
158   unsigned long txInterrupts;
159
160   unsigned long txDeferred;
161   unsigned long txHeartbeat;
162   unsigned long txLateCollision;
163   unsigned long txRetryLimit;
164   unsigned long txUnderrun;
165
166};
167
168static struct greth_softc greth;
169
170int greth_process_tx_gbit(struct greth_softc *sc);
171int greth_process_tx(struct greth_softc *sc);
172
173static char *almalloc(int sz)
174{
175        char *tmp;
176        tmp = calloc(1,2*sz);
177        tmp = (char *) (((uintptr_t)tmp+sz) & ~(sz -1));
178        return(tmp);
179}
180
181/* GRETH interrupt handler */
182
183void greth_interrupt_handler (void *arg)
184{
185        uint32_t status;
186        uint32_t ctrl;
187        rtems_event_set events = 0;
188        struct greth_softc *greth = arg;
189
190        /* read and clear interrupt cause */
191        status = greth->regs->status;
192        greth->regs->status = status;
193        ctrl = greth->regs->ctrl;
194
195        /* Frame received? */
196        if ((ctrl & GRETH_CTRL_RXIRQ) && (status & (GRETH_STATUS_RXERR | GRETH_STATUS_RXIRQ)))
197        {
198                greth->rxInterrupts++;
199                /* Stop RX-Error and RX-Packet interrupts */
200                ctrl &= ~GRETH_CTRL_RXIRQ;
201                events |= INTERRUPT_EVENT;
202        }
203       
204        if ( (ctrl & GRETH_CTRL_TXIRQ) && (status & (GRETH_STATUS_TXERR | GRETH_STATUS_TXIRQ)) )
205        {
206                greth->txInterrupts++;
207                ctrl &= ~GRETH_CTRL_TXIRQ;
208                events |= GRETH_TX_WAIT_EVENT;
209        }
210
211        /* Clear interrupt sources */
212        greth->regs->ctrl = ctrl;
213
214        /* Send the event(s) */
215        if ( events )
216                rtems_event_send (greth->daemonTid, events);
217}
218
219static uint32_t read_mii(uint32_t phy_addr, uint32_t reg_addr)
220{
221    while (greth.regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
222    greth.regs->mdio_ctrl = (phy_addr << 11) | (reg_addr << 6) | GRETH_MDIO_READ;
223    while (greth.regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
224    if (!(greth.regs->mdio_ctrl & GRETH_MDIO_LINKFAIL))
225        return((greth.regs->mdio_ctrl >> 16) & 0xFFFF);
226    else {
227        printf("greth: failed to read mii\n");
228        return (0);
229    }
230}
231
232static void write_mii(uint32_t phy_addr, uint32_t reg_addr, uint32_t data)
233{
234    while (greth.regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
235    greth.regs->mdio_ctrl =
236     ((data & 0xFFFF) << 16) | (phy_addr << 11) | (reg_addr << 6) | GRETH_MDIO_WRITE;
237    while (greth.regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
238}
239
240static void print_init_info(struct greth_softc *sc)
241{
242        printf("greth: driver attached\n");
243                if ( sc->auto_neg == -1 ){
244                        printf("Auto negotiation timed out. Selecting default config\n");
245                }
246        printf("**** PHY ****\n");
247        printf("Vendor: %x   Device: %x   Revision: %d\n",sc->phydev.vendor, sc->phydev.device, sc->phydev.rev);
248        printf("Current Operating Mode: ");
249        if (sc->gb) {
250                printf("1000 Mbit ");
251        } else if (sc->sp) {
252                printf("100 Mbit ");
253        } else {
254                printf("10 Mbit ");
255        }
256        if (sc->fd) {
257                printf("Full Duplex\n");
258        } else {
259                printf("Half Duplex\n");
260        }
261#ifdef GRETH_AUTONEGO_PRINT_TIME
262        if ( sc->auto_neg ) {
263          printf("Autonegotiation Time: %dms\n", sc->auto_neg_time.tv_sec*1000 +
264                 sc->auto_neg_time.tv_nsec/1000000);
265        }
266#endif
267}
268
269
270/*
271 * Initialize the ethernet hardware
272 */
273static void
274greth_initialize_hardware (struct greth_softc *sc)
275{
276    struct mbuf *m;
277    int i;
278    int phyaddr;
279    int phyctrl;
280    int phystatus;
281    int tmp1;
282    int tmp2;
283    struct timespec tstart, tnow;
284
285    greth_regs *regs;
286
287    regs = sc->regs;
288
289    /* Reset the controller.  */
290    greth.rxInterrupts = 0;
291    greth.rxPackets = 0;
292
293    regs->ctrl = 0;
294    regs->ctrl = GRETH_CTRL_RST;        /* Reset ON */
295    regs->ctrl = 0;                     /* Reset OFF */
296
297    /* Check if mac is gbit capable*/
298    sc->gbit_mac = (regs->ctrl >> 27) & 1;
299
300    /* Get the phy address which assumed to have been set
301       correctly with the reset value in hardware*/
302    phyaddr = (regs->mdio_ctrl >> 11) & 0x1F;
303
304    /* get phy control register default values */
305    while ((phyctrl = read_mii(phyaddr, 0)) & 0x8000) {}
306
307    /* reset PHY and wait for completion */
308    write_mii(phyaddr, 0, 0x8000 | phyctrl);
309
310    while ((read_mii(phyaddr, 0)) & 0x8000) {}
311
312    /* Check if PHY is autoneg capable and then determine operating mode,
313       otherwise force it to 10 Mbit halfduplex */
314    sc->gb = 0;
315    sc->fd = 0;
316    sc->sp = 0;
317    sc->auto_neg = 0;
318    _Timespec_Set_to_zero(&sc->auto_neg_time);
319    if ((phyctrl >> 12) & 1) {
320            /*wait for auto negotiation to complete*/
321            sc->auto_neg = 1;
322            if (rtems_clock_get_uptime(&tstart) != RTEMS_SUCCESSFUL)
323                    printk("rtems_clock_get_uptime failed\n");
324            while (!(((phystatus = read_mii(phyaddr, 1)) >> 5) & 1)) {
325                    if (rtems_clock_get_uptime(&tnow) != RTEMS_SUCCESSFUL)
326                            printk("rtems_clock_get_uptime failed\n");
327                    _Timespec_Subtract(&tstart, &tnow, &sc->auto_neg_time);
328                    if (_Timespec_Greater_than(&sc->auto_neg_time, &greth_tan)) {
329                            sc->auto_neg = -1; /* Failed */
330                            tmp1 = read_mii(phyaddr, 0);
331                            sc->gb = ((phyctrl >> 6) & 1) && !((phyctrl >> 13) & 1);
332                            sc->sp = !((phyctrl >> 6) & 1) && ((phyctrl >> 13) & 1);
333                            sc->fd = (phyctrl >> 8) & 1;
334                            goto auto_neg_done;
335                    }
336                    /* Wait about 30ms, time is PHY dependent */
337                    rtems_task_wake_after(rtems_clock_get_ticks_per_second()/32);
338            }
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    if ( sc->rxbufs < 10 ) {
467        sc->tx_int_gen = sc->tx_int_gen_cur = 1;
468    }else{
469        sc->tx_int_gen = sc->tx_int_gen_cur = sc->txbufs/2;
470    }
471    sc->next_tx_mbuf = NULL;
472   
473    if ( !sc->gbit_mac )
474        sc->max_fragsize = 1;
475
476    /* clear all pending interrupts */
477    regs->status = 0xffffffff;
478   
479    /* install interrupt handler */
480    rtems_interrupt_handler_install(sc->vector, "greth", RTEMS_INTERRUPT_SHARED,
481                                    greth_interrupt_handler, sc);
482
483    regs->ctrl |= GRETH_CTRL_RXEN | (sc->fd << 4) | GRETH_CTRL_RXIRQ | (sc->sp << 7) | (sc->gb << 8);
484
485    print_init_info(sc);
486}
487
488#ifdef CPU_U32_FIX
489
490/*
491 * Routine to align the received packet so that the ip header
492 * is on a 32-bit boundary. Necessary for cpu's that do not
493 * allow unaligned loads and stores and when the 32-bit DMA
494 * mode is used.
495 *
496 * Transfers are done on word basis to avoid possibly slow byte
497 * and half-word writes.
498 */
499
500void ipalign(struct mbuf *m)
501{
502  unsigned int *first, *last, data;
503  unsigned int tmp;
504
505  if ((((int) m->m_data) & 2) && (m->m_len)) {
506    last = (unsigned int *) ((((int) m->m_data) + m->m_len + 8) & ~3);
507    first = (unsigned int *) (((int) m->m_data) & ~3);
508    tmp = GRETH_MEM_LOAD(first);
509    tmp = tmp << 16;
510    first++;
511    do {
512      /* When snooping is not available the LDA instruction must be used
513       * to avoid the cache to return an illegal value.
514       * Load with forced cache miss
515       */
516      data = GRETH_MEM_LOAD(first);
517      *first = tmp | (data >> 16);
518      tmp = data << 16;
519      first++;
520    } while (first <= last);
521
522    m->m_data = (caddr_t)(((int) m->m_data) + 2);
523  }
524}
525#endif
526
527void
528greth_Daemon (void *arg)
529{
530    struct ether_header *eh;
531    struct greth_softc *dp = (struct greth_softc *) &greth;
532    struct ifnet *ifp = &dp->arpcom.ac_if;
533    struct mbuf *m;
534    unsigned int len, len_status, bad;
535    rtems_event_set events;
536    rtems_interrupt_level level;
537    int first;
538    unsigned int tmp;
539
540    for (;;)
541      {
542        rtems_bsdnet_event_receive (INTERRUPT_EVENT | GRETH_TX_WAIT_EVENT,
543                                    RTEMS_WAIT | RTEMS_EVENT_ANY,
544                                    RTEMS_NO_TIMEOUT, &events);
545
546        if ( events & GRETH_TX_WAIT_EVENT ){
547            /* TX interrupt.
548             * We only end up here when all TX descriptors has been used,
549             * and
550             */
551            if ( dp->gbit_mac )
552                greth_process_tx_gbit(dp);
553            else
554                greth_process_tx(dp);
555           
556            /* If we didn't get a RX interrupt we don't process it */
557            if ( (events & INTERRUPT_EVENT) == 0 )
558                continue;
559        }
560
561#ifdef GRETH_ETH_DEBUG
562    printf ("r\n");
563#endif
564    first=1;
565    /* Scan for Received packets */
566again:
567    while (!((len_status =
568                    GRETH_MEM_LOAD(&dp->rxdesc[dp->rx_ptr].ctrl)) & GRETH_RXD_ENABLE))
569            {
570                    bad = 0;
571                    if (len_status & GRETH_RXD_TOOLONG)
572                    {
573                            dp->rxLengthError++;
574                            bad = 1;
575                    }
576                    if (len_status & GRETH_RXD_DRIBBLE)
577                    {
578                            dp->rxNonOctet++;
579                            bad = 1;
580                    }
581                    if (len_status & GRETH_RXD_CRCERR)
582                    {
583                            dp->rxBadCRC++;
584                            bad = 1;
585                    }
586                    if (len_status & GRETH_RXD_OVERRUN)
587                    {
588                            dp->rxOverrun++;
589                            bad = 1;
590                    }
591                    if (len_status & GRETH_RXD_LENERR)
592                    {
593                            dp->rxLengthError++;
594                            bad = 1;
595                    }
596                    if (!bad)
597                    {
598                            /* pass on the packet in the receive buffer */
599                            len = len_status & 0x7FF;
600                            m = dp->rxmbuf[dp->rx_ptr];
601#ifdef GRETH_DEBUG
602                            int i;
603                            printf("RX: 0x%08x, Len: %d : ", (int) m->m_data, len);
604                            for (i=0; i<len; i++)
605                                    printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
606                            printf("\n");
607#endif
608                            m->m_len = m->m_pkthdr.len =
609                                    len - sizeof (struct ether_header);
610
611                            eh = mtod (m, struct ether_header *);
612
613                            m->m_data += sizeof (struct ether_header);
614#ifdef CPU_U32_FIX
615                            if(!dp->gbit_mac) {
616                                    /* OVERRIDE CACHED ETHERNET HEADER FOR NON-SNOOPING SYSTEMS */
617                                    tmp = GRETH_MEM_LOAD((uintptr_t)eh);
618                                    tmp = GRETH_MEM_LOAD(4+(uintptr_t)eh);
619                                    tmp = GRETH_MEM_LOAD(8+(uintptr_t)eh);
620                                    tmp = GRETH_MEM_LOAD(12+(uintptr_t)eh);
621
622                                    ipalign(m); /* Align packet on 32-bit boundary */
623                            }
624#endif
625
626                            ether_input (ifp, eh, m);
627                            MGETHDR (m, M_WAIT, MT_DATA);
628                            MCLGET (m, M_WAIT);
629                            if (dp->gbit_mac)
630                                    m->m_data += 2;
631                            dp->rxmbuf[dp->rx_ptr] = m;
632                            m->m_pkthdr.rcvif = ifp;
633                            dp->rxdesc[dp->rx_ptr].addr =
634                                    (uint32_t *) mtod (m, uint32_t *);
635                            dp->rxPackets++;
636                    }
637                    if (dp->rx_ptr == dp->rxbufs - 1) {
638                            dp->rxdesc[dp->rx_ptr].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ | GRETH_RXD_WRAP;
639                    } else {
640                            dp->rxdesc[dp->rx_ptr].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ;
641                    }
642                    rtems_interrupt_disable(level);
643                    dp->regs->ctrl |= GRETH_CTRL_RXEN;
644                    rtems_interrupt_enable(level);
645                    dp->rx_ptr = (dp->rx_ptr + 1) % dp->rxbufs;
646            }
647
648        /* Always scan twice to avoid deadlock */
649        if ( first ){
650            first=0;
651            rtems_interrupt_disable(level);
652            dp->regs->ctrl |= GRETH_CTRL_RXIRQ;
653            rtems_interrupt_enable(level);
654            goto again;
655        }
656
657      }
658
659}
660
661static int inside = 0;
662static int
663sendpacket (struct ifnet *ifp, struct mbuf *m)
664{
665    struct greth_softc *dp = ifp->if_softc;
666    unsigned char *temp;
667    struct mbuf *n;
668    unsigned int len;
669    rtems_interrupt_level level;
670
671    /*printf("Send packet entered\n");*/
672    if (inside) printf ("error: sendpacket re-entered!!\n");
673    inside = 1;
674
675    /*
676     * Is there a free descriptor available?
677     */
678    if (GRETH_MEM_LOAD(&dp->txdesc[dp->tx_ptr].ctrl) & GRETH_TXD_ENABLE){
679            /* No. */
680            inside = 0;
681            return 1;
682    }
683
684    /* Remember head of chain */
685    n = m;
686
687    len = 0;
688    temp = (unsigned char *) GRETH_MEM_LOAD(&dp->txdesc[dp->tx_ptr].addr);
689#ifdef GRETH_DEBUG
690    printf("TXD: 0x%08x : BUF: 0x%08x\n", (int) m->m_data, (int) temp);
691#endif
692    for (;;)
693    {
694#ifdef GRETH_DEBUG
695            int i;
696            printf("MBUF: 0x%08x : ", (int) m->m_data);
697            for (i=0;i<m->m_len;i++)
698                    printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
699            printf("\n");
700#endif
701            len += m->m_len;
702            if (len <= RBUF_SIZE)
703                    memcpy ((void *) temp, (char *) m->m_data, m->m_len);
704            temp += m->m_len;
705            if ((m = m->m_next) == NULL)
706                    break;
707    }
708
709    m_freem (n);
710
711    /* don't send long packets */
712
713    if (len <= GRETH_MAXBUF_LEN) {
714            if (dp->tx_ptr < dp->txbufs-1) {
715                    dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_ENABLE | len;
716            } else {
717                    dp->txdesc[dp->tx_ptr].ctrl =
718                            GRETH_TXD_WRAP | GRETH_TXD_ENABLE | len;
719            }
720            dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
721            rtems_interrupt_disable(level);
722            dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
723            rtems_interrupt_enable(level);
724           
725    }
726    inside = 0;
727   
728    return 0;
729}
730
731
732int
733sendpacket_gbit (struct ifnet *ifp, struct mbuf *m)
734{
735        struct greth_softc *dp = ifp->if_softc;
736        unsigned int len;
737       
738        unsigned int ctrl;
739        int frags;
740        struct mbuf *mtmp;
741        int int_en;
742        rtems_interrupt_level level;
743
744        if (inside) printf ("error: sendpacket re-entered!!\n");
745        inside = 1;
746
747        len = 0;
748#ifdef GRETH_DEBUG
749        printf("TXD: 0x%08x\n", (int) m->m_data);
750#endif
751        /* Get number of fragments too see if we have enough
752         * resources.
753         */
754        frags=1;
755        mtmp=m;
756        while(mtmp->m_next){
757            frags++;
758            mtmp = mtmp->m_next;
759        }
760       
761        if ( frags > dp->max_fragsize )
762            dp->max_fragsize = frags;
763       
764        if ( frags > dp->txbufs ){
765            inside = 0;
766            printf("GRETH: MBUF-chain cannot be sent. Increase descriptor count.\n");
767            return -1;
768        }
769       
770        if ( frags > (dp->txbufs-dp->tx_cnt) ){
771            inside = 0;
772            /* Return number of fragments */
773            return frags;
774        }
775       
776       
777        /* Enable interrupt from descriptor every tx_int_gen
778         * descriptor. Typically every 16 descriptor. This
779         * is only to reduce the number of interrupts during
780         * heavy load.
781         */
782        dp->tx_int_gen_cur-=frags;
783        if ( dp->tx_int_gen_cur <= 0 ){
784            dp->tx_int_gen_cur = dp->tx_int_gen;
785            int_en = GRETH_TXD_IRQ;
786        }else{
787            int_en = 0;
788        }
789       
790        /* At this stage we know that enough descriptors are available */
791        for (;;)
792        {
793               
794#ifdef GRETH_DEBUG
795            int i;
796            printf("MBUF: 0x%08x, Len: %d : ", (int) m->m_data, m->m_len);
797            for (i=0; i<m->m_len; i++)
798                printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
799            printf("\n");
800#endif
801            len += m->m_len;
802            dp->txdesc[dp->tx_ptr].addr = (uint32_t *)m->m_data;
803
804            /* Wrap around? */
805            if (dp->tx_ptr < dp->txbufs-1) {
806                ctrl = GRETH_TXD_ENABLE | GRETH_TXD_CS;
807            }else{
808                ctrl = GRETH_TXD_ENABLE | GRETH_TXD_CS | GRETH_TXD_WRAP;
809            }
810
811            /* Enable Descriptor */
812            if ((m->m_next) == NULL) {
813                dp->txdesc[dp->tx_ptr].ctrl = ctrl | int_en | m->m_len;
814                break;
815            }else{
816                dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_MORE | ctrl | int_en | m->m_len;
817            }
818
819            /* Next */
820            dp->txmbuf[dp->tx_ptr] = m;
821            dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
822            dp->tx_cnt++;
823            m = m->m_next;
824        }
825        dp->txmbuf[dp->tx_ptr] = m;
826        dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
827        dp->tx_cnt++;
828
829        /* Tell Hardware about newly enabled descriptor */
830        rtems_interrupt_disable(level);
831        dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
832        rtems_interrupt_enable(level);
833
834        inside = 0;
835
836        return 0;
837}
838
839int greth_process_tx_gbit(struct greth_softc *sc)
840{
841    struct ifnet *ifp = &sc->arpcom.ac_if;
842    struct mbuf *m;
843    rtems_interrupt_level level;
844    int first=1;
845
846    /*
847     * Send packets till queue is empty
848     */
849    for (;;){
850        /* Reap Sent packets */
851        while((sc->tx_cnt > 0) && !(GRETH_MEM_LOAD(&sc->txdesc[sc->tx_dptr].ctrl) & GRETH_TXD_ENABLE)) {
852            m_free(sc->txmbuf[sc->tx_dptr]);
853            sc->tx_dptr = (sc->tx_dptr + 1) % sc->txbufs;
854            sc->tx_cnt--;
855        }
856
857        if ( sc->next_tx_mbuf ){
858            /* Get packet we tried but faild to transmit last time */
859            m = sc->next_tx_mbuf;
860            sc->next_tx_mbuf = NULL; /* Mark packet taken */
861        }else{
862            /*
863             * Get the next mbuf chain to transmit from Stack.
864             */
865            IF_DEQUEUE (&ifp->if_snd, m);
866            if (!m){
867                /* Hardware has sent all schedule packets, this
868                 * makes the stack enter at greth_start next time
869                 * a packet is to be sent.
870                 */
871                ifp->if_flags &= ~IFF_OACTIVE;
872                break;
873            }
874        }
875
876        /* Are there free descriptors available? */
877        /* Try to send packet, if it a negative number is returned. */
878        if ( (sc->tx_cnt >= sc->txbufs) || sendpacket_gbit(ifp, m) ){
879            /* Not enough resources */
880
881            /* Since we have taken the mbuf out of the "send chain"
882             * we must remember to use that next time we come back.
883             * or else we have dropped a packet.
884             */
885            sc->next_tx_mbuf = m;
886
887            /* Not enough resources, enable interrupt for transmissions
888             * this way we will be informed when more TX-descriptors are
889             * available.
890             */
891            if ( first ){
892                first = 0;
893                rtems_interrupt_disable(level);
894                ifp->if_flags |= IFF_OACTIVE;
895                sc->regs->ctrl |= GRETH_CTRL_TXIRQ;
896                rtems_interrupt_enable(level);
897
898                /* We must check again to be sure that we didn't
899                 * miss an interrupt (if a packet was sent just before
900                 * enabling interrupts)
901                 */
902                continue;
903            }
904
905            return -1;
906        }else{
907            /* Sent Ok, proceed to process more packets if available */
908        }
909    }
910    return 0;
911}
912
913int greth_process_tx(struct greth_softc *sc)
914{
915    struct ifnet *ifp = &sc->arpcom.ac_if;
916    struct mbuf *m;
917    rtems_interrupt_level level;
918    int first=1;
919
920    /*
921     * Send packets till queue is empty
922     */
923    for (;;){
924        if ( sc->next_tx_mbuf ){
925            /* Get packet we tried but failed to transmit last time */
926            m = sc->next_tx_mbuf;
927            sc->next_tx_mbuf = NULL; /* Mark packet taken */
928        }else{
929            /*
930             * Get the next mbuf chain to transmit from Stack.
931             */
932            IF_DEQUEUE (&ifp->if_snd, m);
933            if (!m){
934                /* Hardware has sent all schedule packets, this
935                 * makes the stack enter at greth_start next time
936                 * a packet is to be sent.
937                 */
938                ifp->if_flags &= ~IFF_OACTIVE;
939                break;
940            }
941        }
942
943        /* Try to send packet, failed if it a non-zero number is returned. */
944        if ( sendpacket(ifp, m) ){
945            /* Not enough resources */
946
947            /* Since we have taken the mbuf out of the "send chain"
948             * we must remember to use that next time we come back.
949             * or else we have dropped a packet.
950             */
951            sc->next_tx_mbuf = m;
952
953            /* Not enough resources, enable interrupt for transmissions
954             * this way we will be informed when more TX-descriptors are
955             * available.
956             */
957            if ( first ){
958                first = 0;
959                rtems_interrupt_disable(level);
960                ifp->if_flags |= IFF_OACTIVE;
961                sc->regs->ctrl |= GRETH_CTRL_TXIRQ;
962                rtems_interrupt_enable(level);
963
964                /* We must check again to be sure that we didn't
965                 * miss an interrupt (if a packet was sent just before
966                 * enabling interrupts)
967                 */
968                continue;
969            }
970
971            return -1;
972        }else{
973            /* Sent Ok, proceed to process more packets if available */
974        }
975    }
976    return 0;
977}
978
979static void
980greth_start (struct ifnet *ifp)
981{
982    struct greth_softc *sc = ifp->if_softc;
983
984    if ( ifp->if_flags & IFF_OACTIVE )
985            return;
986
987    if ( sc->gbit_mac ){
988        /* No use trying to handle this if we are waiting on GRETH
989         * to send the previously scheduled packets.
990         */
991
992        greth_process_tx_gbit(sc);
993    }else{
994        greth_process_tx(sc);
995    }
996}
997
998/*
999 * Initialize and start the device
1000 */
1001static void
1002greth_init (void *arg)
1003{
1004    struct greth_softc *sc = arg;
1005    struct ifnet *ifp = &sc->arpcom.ac_if;
1006
1007    if (sc->daemonTid == 0) {
1008
1009        /*
1010         * Start driver tasks
1011         */
1012        sc->daemonTid = rtems_bsdnet_newproc ("DCrxtx", 4096,
1013                                              greth_Daemon, sc);
1014
1015        /*
1016         * Set up GRETH hardware
1017         */
1018        greth_initialize_hardware (sc);
1019
1020    }
1021
1022    /*
1023     * Tell the world that we're running.
1024     */
1025    ifp->if_flags |= IFF_RUNNING;
1026}
1027
1028/*
1029 * Stop the device
1030 */
1031static void
1032greth_stop (struct greth_softc *sc)
1033{
1034    struct ifnet *ifp = &sc->arpcom.ac_if;
1035
1036    ifp->if_flags &= ~IFF_RUNNING;
1037
1038    sc->regs->ctrl = 0;                 /* RX/TX OFF */
1039    sc->regs->ctrl = GRETH_CTRL_RST;    /* Reset ON */
1040    sc->regs->ctrl = 0;                 /* Reset OFF */
1041   
1042    sc->next_tx_mbuf = NULL;
1043}
1044
1045
1046/*
1047 * Show interface statistics
1048 */
1049static void
1050greth_stats (struct greth_softc *sc)
1051{
1052  printf ("      Rx Interrupts:%-8lu", sc->rxInterrupts);
1053  printf ("      Rx Packets:%-8lu", sc->rxPackets);
1054  printf ("          Length:%-8lu", sc->rxLengthError);
1055  printf ("       Non-octet:%-8lu\n", sc->rxNonOctet);
1056  printf ("            Bad CRC:%-8lu", sc->rxBadCRC);
1057  printf ("         Overrun:%-8lu", sc->rxOverrun);
1058  printf ("      Tx Interrupts:%-8lu", sc->txInterrupts);
1059  printf ("      Maximal Frags:%-8d", sc->max_fragsize);
1060  printf ("      GBIT MAC:%-8d", sc->gbit_mac);
1061}
1062
1063/*
1064 * Driver ioctl handler
1065 */
1066static int
1067greth_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data)
1068{
1069    struct greth_softc *sc = ifp->if_softc;
1070    int error = 0;
1071
1072    switch (command)
1073      {
1074      case SIOCGIFADDR:
1075      case SIOCSIFADDR:
1076          ether_ioctl (ifp, command, data);
1077          break;
1078
1079      case SIOCSIFFLAGS:
1080          switch (ifp->if_flags & (IFF_UP | IFF_RUNNING))
1081            {
1082            case IFF_RUNNING:
1083                greth_stop (sc);
1084                break;
1085
1086            case IFF_UP:
1087                greth_init (sc);
1088                break;
1089
1090            case IFF_UP | IFF_RUNNING:
1091                greth_stop (sc);
1092                greth_init (sc);
1093                break;
1094       default:
1095                break;
1096            }
1097          break;
1098
1099      case SIO_RTEMS_SHOW_STATS:
1100          greth_stats (sc);
1101          break;
1102
1103          /*
1104           * FIXME: All sorts of multicast commands need to be added here!
1105           */
1106      default:
1107          error = EINVAL;
1108          break;
1109      }
1110
1111    return error;
1112}
1113
1114/*
1115 * Attach an GRETH driver to the system
1116 */
1117int
1118rtems_greth_driver_attach (struct rtems_bsdnet_ifconfig *config,
1119                           greth_configuration_t *chip)
1120{
1121    struct greth_softc *sc;
1122    struct ifnet *ifp;
1123    int mtu;
1124    int unitNumber;
1125    char *unitName;
1126
1127      /* parse driver name */
1128    if ((unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName)) < 0)
1129        return 0;
1130
1131    sc = &greth;
1132    ifp = &sc->arpcom.ac_if;
1133    memset (sc, 0, sizeof (*sc));
1134
1135    if (config->hardware_address)
1136      {
1137          memcpy (sc->arpcom.ac_enaddr, config->hardware_address,
1138                  ETHER_ADDR_LEN);
1139      }
1140    else
1141      {
1142          memset (sc->arpcom.ac_enaddr, 0x08, ETHER_ADDR_LEN);
1143      }
1144
1145    if (config->mtu)
1146        mtu = config->mtu;
1147    else
1148        mtu = ETHERMTU;
1149
1150    sc->acceptBroadcast = !config->ignore_broadcast;
1151    sc->regs = chip->base_address;
1152    sc->vector = chip->vector;
1153    sc->txbufs = chip->txd_count;
1154    sc->rxbufs = chip->rxd_count;
1155
1156    /*
1157     * Set up network interface values
1158     */
1159    ifp->if_softc = sc;
1160    ifp->if_unit = unitNumber;
1161    ifp->if_name = unitName;
1162    ifp->if_mtu = mtu;
1163    ifp->if_init = greth_init;
1164    ifp->if_ioctl = greth_ioctl;
1165    ifp->if_start = greth_start;
1166    ifp->if_output = ether_output;
1167    ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
1168    if (ifp->if_snd.ifq_maxlen == 0)
1169        ifp->if_snd.ifq_maxlen = ifqmaxlen;
1170
1171    /*
1172     * Attach the interface
1173     */
1174    if_attach (ifp);
1175    ether_ifattach (ifp);
1176
1177#ifdef GRETH_DEBUG
1178    printf ("GRETH : driver has been attached\n");
1179#endif
1180    return 1;
1181};
1182
1183#endif
Note: See TracBrowser for help on using the repository browser.