source: rtems/bsps/shared/net/greth2.c @ 20bd667

5
Last change on this file since 20bd667 was 20bd667, checked in by Sebastian Huber <sebastian.huber@…>, on May 27, 2019 at 5:35:07 AM

bsps: Fix warnings in greth

  • Property mode set to 100644
File size: 33.7 KB
Line 
1/*
2 * Gaisler Research ethernet MAC driver
3 * adapted from Opencores driver by Marko Isomaki
4 *
5 *  The license and distribution terms for this file may be
6 *  found in the file LICENSE in this distribution or at
7 *  http://www.rtems.org/license/LICENSE.
8 *
9 * 2007-09-07, Ported GBIT support from 4.6.5
10 */
11
12#include <machine/rtems-bsd-kernel-space.h>
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 <libchip/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 % 1000) *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
183static void 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_bsdnet_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: %lldms\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    phystatus = read_mii(phyaddr, 1);
312
313    /* Disable Gbit auto-neg advertisement if MAC does not support it */
314
315    if ((!sc->gbit_mac) && (phystatus & 0x100)) write_mii(phyaddr, 9, 0);
316
317    /* Restart auto-negotiation if available */
318    if (phystatus & 0x08) {
319        write_mii(phyaddr, 0, phyctrl | 0x1200);
320        phyctrl = read_mii(phyaddr, 0);
321    }
322
323    /* Check if PHY is autoneg capable and then determine operating mode,
324       otherwise force it to 10 Mbit halfduplex */
325    sc->gb = 0;
326    sc->fd = 0;
327    sc->sp = 0;
328    sc->auto_neg = 0;
329    timespecclear(&sc->auto_neg_time);
330    if ((phyctrl >> 12) & 1) {
331            /*wait for auto negotiation to complete*/
332            sc->auto_neg = 1;
333            if (rtems_clock_get_uptime(&tstart) != RTEMS_SUCCESSFUL)
334                    printk("rtems_clock_get_uptime failed\n");
335            while (!(((phystatus = read_mii(phyaddr, 1)) >> 5) & 1)) {
336                    if (rtems_clock_get_uptime(&tnow) != RTEMS_SUCCESSFUL)
337                            printk("rtems_clock_get_uptime failed\n");
338                    timespecsub(&tnow, &tstart, &sc->auto_neg_time);
339                    if (timespeccmp(&sc->auto_neg_time, &greth_tan, >)) {
340                            sc->auto_neg = -1; /* Failed */
341                            tmp1 = read_mii(phyaddr, 0);
342                            sc->gb = ((phyctrl >> 6) & 1) && !((phyctrl >> 13) & 1);
343                            sc->sp = !((phyctrl >> 6) & 1) && ((phyctrl >> 13) & 1);
344                            sc->fd = (phyctrl >> 8) & 1;
345                            goto auto_neg_done;
346                    }
347                    /* Wait about 30ms, time is PHY dependent */
348                    rtems_task_wake_after(rtems_clock_get_ticks_per_second()/32);
349            }
350            sc->phydev.adv = read_mii(phyaddr, 4);
351            sc->phydev.part = read_mii(phyaddr, 5);
352            if ((phystatus >> 8) & 1) {
353                    sc->phydev.extadv = read_mii(phyaddr, 9);
354                    sc->phydev.extpart = read_mii(phyaddr, 10);
355                       if ( (sc->phydev.extadv & GRETH_MII_EXTADV_1000FD) &&
356                            (sc->phydev.extpart & GRETH_MII_EXTPRT_1000FD)) {
357                               sc->gb = 1;
358                               sc->fd = 1;
359                       }
360                       else if ( (sc->phydev.extadv & GRETH_MII_EXTADV_1000HD) &&
361                            (sc->phydev.extpart & GRETH_MII_EXTPRT_1000HD)) {
362                               sc->gb = 1;
363                               sc->fd = 0;
364                       }
365            }
366            if ((sc->gb == 0) || ((sc->gb == 1) && (sc->gbit_mac == 0))) {
367                    if ( (sc->phydev.adv & GRETH_MII_100TXFD) &&
368                         (sc->phydev.part & GRETH_MII_100TXFD)) {
369                            sc->sp = 1;
370                            sc->fd = 1;
371                    }
372                    else if ( (sc->phydev.adv & GRETH_MII_100TXHD) &&
373                         (sc->phydev.part & GRETH_MII_100TXHD)) {
374                            sc->sp = 1;
375                            sc->fd = 0;
376                    }
377                    else if ( (sc->phydev.adv & GRETH_MII_10FD) &&
378                         (sc->phydev.part & GRETH_MII_10FD)) {
379                            sc->fd = 1;
380                    }
381            }
382    }
383auto_neg_done:
384    sc->phydev.vendor = 0;
385    sc->phydev.device = 0;
386    sc->phydev.rev = 0;
387    phystatus = read_mii(phyaddr, 1);
388
389    /*Read out PHY info if extended registers are available */
390    if (phystatus & 1) { 
391            tmp1 = read_mii(phyaddr, 2);
392            tmp2 = read_mii(phyaddr, 3);
393
394            sc->phydev.vendor = (tmp1 << 6) | ((tmp2 >> 10) & 0x3F);
395            sc->phydev.rev = tmp2 & 0xF;
396            sc->phydev.device = (tmp2 >> 4) & 0x3F;
397    }
398
399    /* Force to 10 mbit half duplex if the 10/100 MAC is used with a 1000 PHY*/
400    /*check if marvell 88EE1111 PHY. Needs special reset handling */
401    if ((phystatus & 1) && (sc->phydev.vendor == 0x005043) && (sc->phydev.device == 0x0C)) {
402            if (((sc->gb) && !(sc->gbit_mac)) || !((phyctrl >> 12) & 1)) {
403                    write_mii(phyaddr, 0, sc->sp << 13);
404                    write_mii(phyaddr, 0, 0x8000);
405                    sc->gb = 0;
406                    sc->sp = 0;
407                    sc->fd = 0;
408            }
409    } else {
410            if (((sc->gb) && !(sc->gbit_mac))  || !((phyctrl >> 12) & 1)) {
411                    write_mii(phyaddr, 0, sc->sp << 13);
412                    sc->gb = 0;
413                    sc->sp = 0;
414                    sc->fd = 0;
415            }
416    }
417    while ((read_mii(phyaddr, 0)) & 0x8000) {}
418
419    regs->ctrl = 0;
420    regs->ctrl = GRETH_CTRL_RST;        /* Reset ON */
421    regs->ctrl = 0;
422
423    /* Initialize rx/tx descriptor pointers */
424    sc->txdesc = (greth_rxtxdesc *) almalloc(1024);
425    sc->rxdesc = (greth_rxtxdesc *) almalloc(1024);
426    sc->tx_ptr = 0;
427    sc->tx_dptr = 0;
428    sc->tx_cnt = 0;
429    sc->rx_ptr = 0;
430    regs->txdesc = (uintptr_t) sc->txdesc;
431    regs->rxdesc = (uintptr_t) sc->rxdesc;
432
433    sc->rxmbuf = calloc(sc->rxbufs, sizeof(*sc->rxmbuf));
434    sc->txmbuf = calloc(sc->txbufs, sizeof(*sc->txmbuf));
435
436    for (i = 0; i < sc->txbufs; i++)
437      {
438              sc->txdesc[i].ctrl = 0;
439              if (!(sc->gbit_mac)) {
440                      sc->txdesc[i].addr = malloc(GRETH_MAXBUF_LEN);
441              }
442#ifdef GRETH_DEBUG
443              /* printf("TXBUF: %08x\n", (int) sc->txdesc[i].addr); */
444#endif
445      }
446    for (i = 0; i < sc->rxbufs; i++)
447      {
448
449          MGETHDR (m, M_WAIT, MT_DATA);
450          MCLGET (m, M_WAIT);
451          if (sc->gbit_mac)
452                  m->m_data += 2;
453          m->m_pkthdr.rcvif = &sc->arpcom.ac_if;
454          sc->rxmbuf[i] = m;
455          sc->rxdesc[i].addr = (uint32_t *) mtod(m, uint32_t *);
456          sc->rxdesc[i].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ;
457#ifdef GRETH_DEBUG
458/*        printf("RXBUF: %08x\n", (int) sc->rxdesc[i].addr); */
459#endif
460      }
461    sc->rxdesc[sc->rxbufs - 1].ctrl |= GRETH_RXD_WRAP;
462
463    /* set ethernet address.  */
464    regs->mac_addr_msb =
465      sc->arpcom.ac_enaddr[0] << 8 | sc->arpcom.ac_enaddr[1];
466
467    uint32_t mac_addr_lsb;
468    mac_addr_lsb = sc->arpcom.ac_enaddr[2];
469    mac_addr_lsb <<= 8;
470    mac_addr_lsb |= sc->arpcom.ac_enaddr[3];
471    mac_addr_lsb <<= 8;
472    mac_addr_lsb |= sc->arpcom.ac_enaddr[4];
473    mac_addr_lsb <<= 8;
474    mac_addr_lsb |= sc->arpcom.ac_enaddr[5];
475    regs->mac_addr_lsb = mac_addr_lsb;
476
477    if ( sc->rxbufs < 10 ) {
478        sc->tx_int_gen = sc->tx_int_gen_cur = 1;
479    }else{
480        sc->tx_int_gen = sc->tx_int_gen_cur = sc->txbufs/2;
481    }
482    sc->next_tx_mbuf = NULL;
483   
484    if ( !sc->gbit_mac )
485        sc->max_fragsize = 1;
486
487    /* clear all pending interrupts */
488    regs->status = 0xffffffff;
489   
490    /* install interrupt handler */
491    rtems_interrupt_handler_install(sc->vector, "greth", RTEMS_INTERRUPT_SHARED,
492                                    greth_interrupt_handler, sc);
493
494    regs->ctrl |= GRETH_CTRL_RXEN | (sc->fd << 4) | GRETH_CTRL_RXIRQ | (sc->sp << 7) | (sc->gb << 8);
495
496    print_init_info(sc);
497}
498
499#ifdef CPU_U32_FIX
500
501/*
502 * Routine to align the received packet so that the ip header
503 * is on a 32-bit boundary. Necessary for cpu's that do not
504 * allow unaligned loads and stores and when the 32-bit DMA
505 * mode is used.
506 *
507 * Transfers are done on word basis to avoid possibly slow byte
508 * and half-word writes.
509 */
510
511void ipalign(struct mbuf *m)
512{
513  unsigned int *first, *last, data;
514  unsigned int tmp;
515
516  if ((((int) m->m_data) & 2) && (m->m_len)) {
517    last = (unsigned int *) ((((int) m->m_data) + m->m_len + 8) & ~3);
518    first = (unsigned int *) (((int) m->m_data) & ~3);
519    tmp = GRETH_MEM_LOAD(first);
520    tmp = tmp << 16;
521    first++;
522    do {
523      /* When snooping is not available the LDA instruction must be used
524       * to avoid the cache to return an illegal value.
525       * Load with forced cache miss
526       */
527      data = GRETH_MEM_LOAD(first);
528      *first = tmp | (data >> 16);
529      tmp = data << 16;
530      first++;
531    } while (first <= last);
532
533    m->m_data = (caddr_t)(((int) m->m_data) + 2);
534  }
535}
536#endif
537
538static void
539greth_Daemon (void *arg)
540{
541    struct ether_header *eh;
542    struct greth_softc *dp = (struct greth_softc *) &greth;
543    struct ifnet *ifp = &dp->arpcom.ac_if;
544    struct mbuf *m;
545    unsigned int len, len_status, bad;
546    rtems_event_set events;
547    rtems_interrupt_level level;
548    int first;
549#ifdef CPU_U32_FIX
550    unsigned int tmp;
551#endif
552
553    for (;;)
554      {
555        rtems_bsdnet_event_receive (INTERRUPT_EVENT | GRETH_TX_WAIT_EVENT,
556                                    RTEMS_WAIT | RTEMS_EVENT_ANY,
557                                    RTEMS_NO_TIMEOUT, &events);
558
559        if ( events & GRETH_TX_WAIT_EVENT ){
560            /* TX interrupt.
561             * We only end up here when all TX descriptors has been used,
562             * and
563             */
564            if ( dp->gbit_mac )
565                greth_process_tx_gbit(dp);
566            else
567                greth_process_tx(dp);
568           
569            /* If we didn't get a RX interrupt we don't process it */
570            if ( (events & INTERRUPT_EVENT) == 0 )
571                continue;
572        }
573
574#ifdef GRETH_ETH_DEBUG
575    printf ("r\n");
576#endif
577    first=1;
578    /* Scan for Received packets */
579again:
580    while (!((len_status =
581                    GRETH_MEM_LOAD(&dp->rxdesc[dp->rx_ptr].ctrl)) & GRETH_RXD_ENABLE))
582            {
583                    bad = 0;
584                    if (len_status & GRETH_RXD_TOOLONG)
585                    {
586                            dp->rxLengthError++;
587                            bad = 1;
588                    }
589                    if (len_status & GRETH_RXD_DRIBBLE)
590                    {
591                            dp->rxNonOctet++;
592                            bad = 1;
593                    }
594                    if (len_status & GRETH_RXD_CRCERR)
595                    {
596                            dp->rxBadCRC++;
597                            bad = 1;
598                    }
599                    if (len_status & GRETH_RXD_OVERRUN)
600                    {
601                            dp->rxOverrun++;
602                            bad = 1;
603                    }
604                    if (len_status & GRETH_RXD_LENERR)
605                    {
606                            dp->rxLengthError++;
607                            bad = 1;
608                    }
609                    if (!bad)
610                    {
611                            /* pass on the packet in the receive buffer */
612                            len = len_status & 0x7FF;
613                            m = dp->rxmbuf[dp->rx_ptr];
614#ifdef GRETH_DEBUG
615                            int i;
616                            printf("RX: 0x%08x, Len: %d : ", (int) m->m_data, len);
617                            for (i=0; i<len; i++)
618                                    printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
619                            printf("\n");
620#endif
621                            m->m_len = m->m_pkthdr.len =
622                                    len - sizeof (struct ether_header);
623
624                            eh = mtod (m, struct ether_header *);
625
626                            m->m_data += sizeof (struct ether_header);
627#ifdef CPU_U32_FIX
628                            if(!dp->gbit_mac) {
629                                    /* OVERRIDE CACHED ETHERNET HEADER FOR NON-SNOOPING SYSTEMS */
630                                    tmp = GRETH_MEM_LOAD((uintptr_t)eh);
631                                    tmp = GRETH_MEM_LOAD(4+(uintptr_t)eh);
632                                    tmp = GRETH_MEM_LOAD(8+(uintptr_t)eh);
633                                    tmp = GRETH_MEM_LOAD(12+(uintptr_t)eh);
634                                    (void)tmp;
635                                    ipalign(m); /* Align packet on 32-bit boundary */
636                            }
637#endif
638
639                            ether_input (ifp, eh, m);
640                            MGETHDR (m, M_WAIT, MT_DATA);
641                            MCLGET (m, M_WAIT);
642                            if (dp->gbit_mac)
643                                    m->m_data += 2;
644                            dp->rxmbuf[dp->rx_ptr] = m;
645                            m->m_pkthdr.rcvif = ifp;
646                            dp->rxdesc[dp->rx_ptr].addr =
647                                    (uint32_t *) mtod (m, uint32_t *);
648                            dp->rxPackets++;
649                    }
650                    if (dp->rx_ptr == dp->rxbufs - 1) {
651                            dp->rxdesc[dp->rx_ptr].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ | GRETH_RXD_WRAP;
652                    } else {
653                            dp->rxdesc[dp->rx_ptr].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ;
654                    }
655                    rtems_interrupt_disable(level);
656                    dp->regs->ctrl |= GRETH_CTRL_RXEN;
657                    rtems_interrupt_enable(level);
658                    dp->rx_ptr = (dp->rx_ptr + 1) % dp->rxbufs;
659            }
660
661        /* Always scan twice to avoid deadlock */
662        if ( first ){
663            first=0;
664            rtems_interrupt_disable(level);
665            dp->regs->ctrl |= GRETH_CTRL_RXIRQ;
666            rtems_interrupt_enable(level);
667            goto again;
668        }
669
670      }
671
672}
673
674static int inside = 0;
675static int
676sendpacket (struct ifnet *ifp, struct mbuf *m)
677{
678    struct greth_softc *dp = ifp->if_softc;
679    unsigned char *temp;
680    struct mbuf *n;
681    unsigned int len;
682    rtems_interrupt_level level;
683
684    /*printf("Send packet entered\n");*/
685    if (inside) printf ("error: sendpacket re-entered!!\n");
686    inside = 1;
687
688    /*
689     * Is there a free descriptor available?
690     */
691    if (GRETH_MEM_LOAD(&dp->txdesc[dp->tx_ptr].ctrl) & GRETH_TXD_ENABLE){
692            /* No. */
693            inside = 0;
694            return 1;
695    }
696
697    /* Remember head of chain */
698    n = m;
699
700    len = 0;
701    temp = (unsigned char *) GRETH_MEM_LOAD(&dp->txdesc[dp->tx_ptr].addr);
702#ifdef GRETH_DEBUG
703    printf("TXD: 0x%08x : BUF: 0x%08x\n", (int) m->m_data, (int) temp);
704#endif
705    for (;;)
706    {
707#ifdef GRETH_DEBUG
708            int i;
709            printf("MBUF: 0x%08x : ", (int) m->m_data);
710            for (i=0;i<m->m_len;i++)
711                    printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
712            printf("\n");
713#endif
714            len += m->m_len;
715            if (len <= RBUF_SIZE)
716                    memcpy ((void *) temp, (char *) m->m_data, m->m_len);
717            temp += m->m_len;
718            if ((m = m->m_next) == NULL)
719                    break;
720    }
721
722    m_freem (n);
723
724    /* don't send long packets */
725
726    if (len <= GRETH_MAXBUF_LEN) {
727            if (dp->tx_ptr < dp->txbufs-1) {
728                    dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_ENABLE | len;
729            } else {
730                    dp->txdesc[dp->tx_ptr].ctrl =
731                            GRETH_TXD_WRAP | GRETH_TXD_ENABLE | len;
732            }
733            dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
734            rtems_interrupt_disable(level);
735            dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
736            rtems_interrupt_enable(level);
737           
738    }
739    inside = 0;
740   
741    return 0;
742}
743
744
745static int
746sendpacket_gbit (struct ifnet *ifp, struct mbuf *m)
747{
748        struct greth_softc *dp = ifp->if_softc;
749        unsigned int len;
750       
751        unsigned int ctrl;
752        int frags;
753        struct mbuf *mtmp;
754        int int_en;
755        rtems_interrupt_level level;
756
757        if (inside) printf ("error: sendpacket re-entered!!\n");
758        inside = 1;
759
760        len = 0;
761#ifdef GRETH_DEBUG
762        printf("TXD: 0x%08x\n", (int) m->m_data);
763#endif
764        /* Get number of fragments too see if we have enough
765         * resources.
766         */
767        frags=1;
768        mtmp=m;
769        while(mtmp->m_next){
770            frags++;
771            mtmp = mtmp->m_next;
772        }
773       
774        if ( frags > dp->max_fragsize ) 
775            dp->max_fragsize = frags;
776       
777        if ( frags > dp->txbufs ){
778            inside = 0;
779            printf("GRETH: MBUF-chain cannot be sent. Increase descriptor count.\n");
780            return -1;
781        }
782       
783        if ( frags > (dp->txbufs-dp->tx_cnt) ){
784            inside = 0;
785            /* Return number of fragments */
786            return frags;
787        }
788       
789       
790        /* Enable interrupt from descriptor every tx_int_gen
791         * descriptor. Typically every 16 descriptor. This
792         * is only to reduce the number of interrupts during
793         * heavy load.
794         */
795        dp->tx_int_gen_cur-=frags;
796        if ( dp->tx_int_gen_cur <= 0 ){
797            dp->tx_int_gen_cur = dp->tx_int_gen;
798            int_en = GRETH_TXD_IRQ;
799        }else{
800            int_en = 0;
801        }
802       
803        /* At this stage we know that enough descriptors are available */
804        for (;;)
805        {
806               
807#ifdef GRETH_DEBUG
808            int i;
809            printf("MBUF: 0x%08x, Len: %d : ", (int) m->m_data, m->m_len);
810            for (i=0; i<m->m_len; i++)
811                printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
812            printf("\n");
813#endif
814            len += m->m_len;
815            dp->txdesc[dp->tx_ptr].addr = (uint32_t *)m->m_data;
816
817            /* Wrap around? */
818            if (dp->tx_ptr < dp->txbufs-1) {
819                ctrl = GRETH_TXD_ENABLE;
820            }else{
821                ctrl = GRETH_TXD_ENABLE | GRETH_TXD_WRAP;
822            }
823
824            /* Enable Descriptor */
825            if ((m->m_next) == NULL) {
826                dp->txdesc[dp->tx_ptr].ctrl = ctrl | int_en | m->m_len;
827                break;
828            }else{
829                dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_MORE | ctrl | int_en | m->m_len;
830            }
831
832            /* Next */
833            dp->txmbuf[dp->tx_ptr] = m;
834            dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
835            dp->tx_cnt++;
836            m = m->m_next;
837        }
838        dp->txmbuf[dp->tx_ptr] = m;
839        dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
840        dp->tx_cnt++;
841
842        /* Tell Hardware about newly enabled descriptor */
843        rtems_interrupt_disable(level);
844        dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
845        rtems_interrupt_enable(level);
846
847        inside = 0;
848
849        return 0;
850}
851
852int greth_process_tx_gbit(struct greth_softc *sc)
853{
854    struct ifnet *ifp = &sc->arpcom.ac_if;
855    struct mbuf *m;
856    rtems_interrupt_level level;
857    int first=1;
858
859    /*
860     * Send packets till queue is empty
861     */
862    for (;;){
863        /* Reap Sent packets */
864        while((sc->tx_cnt > 0) && !(GRETH_MEM_LOAD(&sc->txdesc[sc->tx_dptr].ctrl) & GRETH_TXD_ENABLE)) {
865            m_free(sc->txmbuf[sc->tx_dptr]);
866            sc->tx_dptr = (sc->tx_dptr + 1) % sc->txbufs;
867            sc->tx_cnt--;
868        }
869
870        if ( sc->next_tx_mbuf ){
871            /* Get packet we tried but faild to transmit last time */
872            m = sc->next_tx_mbuf;
873            sc->next_tx_mbuf = NULL; /* Mark packet taken */
874        }else{
875            /*
876             * Get the next mbuf chain to transmit from Stack.
877             */
878            IF_DEQUEUE (&ifp->if_snd, m);
879            if (!m){
880                /* Hardware has sent all schedule packets, this
881                 * makes the stack enter at greth_start next time
882                 * a packet is to be sent.
883                 */
884                ifp->if_flags &= ~IFF_OACTIVE;
885                break;
886            }
887        }
888
889        /* Are there free descriptors available? */
890        /* Try to send packet, if it a negative number is returned. */
891        if ( (sc->tx_cnt >= sc->txbufs) || sendpacket_gbit(ifp, m) ){
892            /* Not enough resources */
893
894            /* Since we have taken the mbuf out of the "send chain"
895             * we must remember to use that next time we come back.
896             * or else we have dropped a packet.
897             */
898            sc->next_tx_mbuf = m;
899
900            /* Not enough resources, enable interrupt for transmissions
901             * this way we will be informed when more TX-descriptors are
902             * available.
903             */
904            if ( first ){
905                first = 0;
906                rtems_interrupt_disable(level);
907                ifp->if_flags |= IFF_OACTIVE;
908                sc->regs->ctrl |= GRETH_CTRL_TXIRQ;
909                rtems_interrupt_enable(level);
910
911                /* We must check again to be sure that we didn't
912                 * miss an interrupt (if a packet was sent just before
913                 * enabling interrupts)
914                 */
915                continue;
916            }
917
918            return -1;
919        }else{
920            /* Sent Ok, proceed to process more packets if available */
921        }
922    }
923    return 0;
924}
925
926int greth_process_tx(struct greth_softc *sc)
927{
928    struct ifnet *ifp = &sc->arpcom.ac_if;
929    struct mbuf *m;
930    rtems_interrupt_level level;
931    int first=1;
932
933    /*
934     * Send packets till queue is empty
935     */
936    for (;;){
937        if ( sc->next_tx_mbuf ){
938            /* Get packet we tried but failed to transmit last time */
939            m = sc->next_tx_mbuf;
940            sc->next_tx_mbuf = NULL; /* Mark packet taken */
941        }else{
942            /*
943             * Get the next mbuf chain to transmit from Stack.
944             */
945            IF_DEQUEUE (&ifp->if_snd, m);
946            if (!m){
947                /* Hardware has sent all schedule packets, this
948                 * makes the stack enter at greth_start next time
949                 * a packet is to be sent.
950                 */
951                ifp->if_flags &= ~IFF_OACTIVE;
952                break;
953            }
954        }
955
956        /* Try to send packet, failed if it a non-zero number is returned. */
957        if ( sendpacket(ifp, m) ){
958            /* Not enough resources */
959
960            /* Since we have taken the mbuf out of the "send chain"
961             * we must remember to use that next time we come back.
962             * or else we have dropped a packet.
963             */
964            sc->next_tx_mbuf = m;
965
966            /* Not enough resources, enable interrupt for transmissions
967             * this way we will be informed when more TX-descriptors are
968             * available.
969             */
970            if ( first ){
971                first = 0;
972                rtems_interrupt_disable(level);
973                ifp->if_flags |= IFF_OACTIVE;
974                sc->regs->ctrl |= GRETH_CTRL_TXIRQ;
975                rtems_interrupt_enable(level);
976
977                /* We must check again to be sure that we didn't
978                 * miss an interrupt (if a packet was sent just before
979                 * enabling interrupts)
980                 */
981                continue;
982            }
983
984            return -1;
985        }else{
986            /* Sent Ok, proceed to process more packets if available */
987        }
988    }
989    return 0;
990}
991
992static void
993greth_start (struct ifnet *ifp)
994{
995    struct greth_softc *sc = ifp->if_softc;
996
997    if ( ifp->if_flags & IFF_OACTIVE )
998            return;
999
1000    if ( sc->gbit_mac ){
1001        /* No use trying to handle this if we are waiting on GRETH
1002         * to send the previously scheduled packets.
1003         */
1004
1005        greth_process_tx_gbit(sc);
1006    }else{
1007        greth_process_tx(sc);
1008    }
1009}
1010
1011/*
1012 * Initialize and start the device
1013 */
1014static void
1015greth_init (void *arg)
1016{
1017    struct greth_softc *sc = arg;
1018    struct ifnet *ifp = &sc->arpcom.ac_if;
1019
1020    if (sc->daemonTid == 0) {
1021
1022        /*
1023         * Start driver tasks
1024         */
1025        sc->daemonTid = rtems_bsdnet_newproc ("DCrxtx", 4096,
1026                                              greth_Daemon, sc);
1027
1028        /*
1029         * Set up GRETH hardware
1030         */
1031        greth_initialize_hardware (sc);
1032
1033    }
1034
1035    /*
1036     * Tell the world that we're running.
1037     */
1038    ifp->if_flags |= IFF_RUNNING;
1039}
1040
1041/*
1042 * Stop the device
1043 */
1044static void
1045greth_stop (struct greth_softc *sc)
1046{
1047    struct ifnet *ifp = &sc->arpcom.ac_if;
1048
1049    ifp->if_flags &= ~IFF_RUNNING;
1050
1051    sc->regs->ctrl = 0;                 /* RX/TX OFF */
1052    sc->regs->ctrl = GRETH_CTRL_RST;    /* Reset ON */
1053    sc->regs->ctrl = 0;                 /* Reset OFF */
1054   
1055    sc->next_tx_mbuf = NULL;
1056}
1057
1058
1059/*
1060 * Show interface statistics
1061 */
1062static void
1063greth_stats (struct greth_softc *sc)
1064{
1065  printf ("      Rx Interrupts:%-8lu", sc->rxInterrupts);
1066  printf ("      Rx Packets:%-8lu", sc->rxPackets);
1067  printf ("          Length:%-8lu", sc->rxLengthError);
1068  printf ("       Non-octet:%-8lu\n", sc->rxNonOctet);
1069  printf ("            Bad CRC:%-8lu", sc->rxBadCRC);
1070  printf ("         Overrun:%-8lu", sc->rxOverrun);
1071  printf ("      Tx Interrupts:%-8lu", sc->txInterrupts);
1072  printf ("      Maximal Frags:%-8d", sc->max_fragsize);
1073  printf ("      GBIT MAC:%-8d", sc->gbit_mac);
1074}
1075
1076/*
1077 * Driver ioctl handler
1078 */
1079static int
1080greth_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data)
1081{
1082    struct greth_softc *sc = ifp->if_softc;
1083    int error = 0;
1084
1085    switch (command)
1086      {
1087      case SIOCGIFADDR:
1088      case SIOCSIFADDR:
1089          ether_ioctl (ifp, command, data);
1090          break;
1091
1092      case SIOCSIFFLAGS:
1093          switch (ifp->if_flags & (IFF_UP | IFF_RUNNING))
1094            {
1095            case IFF_RUNNING:
1096                greth_stop (sc);
1097                break;
1098
1099            case IFF_UP:
1100                greth_init (sc);
1101                break;
1102
1103            case IFF_UP | IFF_RUNNING:
1104                greth_stop (sc);
1105                greth_init (sc);
1106                break;
1107       default:
1108                break;
1109            }
1110          break;
1111
1112      case SIO_RTEMS_SHOW_STATS:
1113          greth_stats (sc);
1114          break;
1115
1116          /*
1117           * FIXME: All sorts of multicast commands need to be added here!
1118           */
1119      default:
1120          error = EINVAL;
1121          break;
1122      }
1123
1124    return error;
1125}
1126
1127/*
1128 * Attach an GRETH driver to the system
1129 */
1130int
1131rtems_greth_driver_attach (struct rtems_bsdnet_ifconfig *config,
1132                           greth_configuration_t *chip)
1133{
1134    struct greth_softc *sc;
1135    struct ifnet *ifp;
1136    int mtu;
1137    int unitNumber;
1138    char *unitName;
1139
1140      /* parse driver name */
1141    if ((unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName)) < 0)
1142        return 0;
1143
1144    sc = &greth;
1145    ifp = &sc->arpcom.ac_if;
1146    memset (sc, 0, sizeof (*sc));
1147
1148    if (config->hardware_address)
1149      {
1150          memcpy (sc->arpcom.ac_enaddr, config->hardware_address,
1151                  ETHER_ADDR_LEN);
1152      }
1153    else
1154      {
1155          memset (sc->arpcom.ac_enaddr, 0x08, ETHER_ADDR_LEN);
1156      }
1157
1158    if (config->mtu)
1159        mtu = config->mtu;
1160    else
1161        mtu = ETHERMTU;
1162
1163    sc->acceptBroadcast = !config->ignore_broadcast;
1164    sc->regs = chip->base_address;
1165    sc->vector = chip->vector;
1166    sc->txbufs = chip->txd_count;
1167    sc->rxbufs = chip->rxd_count;
1168
1169    /*
1170     * Set up network interface values
1171     */
1172    ifp->if_softc = sc;
1173    ifp->if_unit = unitNumber;
1174    ifp->if_name = unitName;
1175    ifp->if_mtu = mtu;
1176    ifp->if_init = greth_init;
1177    ifp->if_ioctl = greth_ioctl;
1178    ifp->if_start = greth_start;
1179    ifp->if_output = ether_output;
1180    ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
1181    if (ifp->if_snd.ifq_maxlen == 0)
1182        ifp->if_snd.ifq_maxlen = ifqmaxlen;
1183
1184    /*
1185     * Attach the interface
1186     */
1187    if_attach (ifp);
1188    ether_ifattach (ifp);
1189
1190#ifdef GRETH_DEBUG
1191    printf ("GRETH : driver has been attached\n");
1192#endif
1193    return 1;
1194};
1195
1196#endif
Note: See TracBrowser for help on using the repository browser.