source: rtems/c/src/libchip/network/greth.c @ 26e90fb1

4.115
Last change on this file since 26e90fb1 was 26e90fb1, checked in by Sebastian Huber <sebastian.huber@…>, on 10/30/12 at 16:42:17

libnetworking: Use system events

Add reserved system events RTEMS_EVENT_SYSTEM_NETWORK_SBWAIT and
RTEMS_EVENT_SYSTEM_NETWORK_SOSLEEP.

Add and use rtems_bsdnet_event_send().

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