source: rtems/c/src/lib/libbsp/sparc/shared/net/greth.c @ 9b8e04e2

4.115
Last change on this file since 9b8e04e2 was 9b8e04e2, checked in by Daniel Hellstrom <daniel@…>, on 10/22/13 at 10:03:41

GRETH: avoid hw generated UDP/TCP cksum generation

Hardware generated checksum UDP packets does not work for
IP fragmented UDP packets. It seems as if the BSD stack never
signals to the GRETH driver to generate or not to generate
TCP/UDP checksum for different cases. The GRETH driver never
tells the BSD stack about it capabilities either so there is
no point generating the cksums in HW when its done in SW any
way.

This patch disables hardware generated UDP and TCP checksums.

  • Property mode set to 100644
File size: 41.9 KB
Line 
1/*
2 * Gaisler Research ethernet MAC driver
3 * adapted from Opencores driver by Marko Isomaki
4 *
5 *  The license and distribution terms for this file may be
6 *  found in found in the file LICENSE in this distribution or at
7 *  http://www.rtems.com/license/LICENSE.
8 *
9 *
10 *  2008-12-10, Converted to driver manager and added support for
11 *              multiple GRETH cores. <daniel@gaisler.com>
12 *  2007-09-07, Ported GBIT support from 4.6.5
13 */
14#include <rtems.h>
15#define _KERNEL
16#define CPU_U32_FIX
17#include <bsp.h>
18
19#ifdef GRETH_SUPPORTED
20
21#include <inttypes.h>
22#include <errno.h>
23#include <rtems/bspIo.h>
24#include <stdlib.h>
25#include <stdio.h>
26#include <stdarg.h>
27#include <rtems/error.h>
28#include <rtems/rtems_bsdnet.h>
29
30#include <greth.h>
31#include <drvmgr/drvmgr.h>
32#include <drvmgr/ambapp_bus.h>
33#include <ambapp.h>
34
35#include <sys/param.h>
36#include <sys/mbuf.h>
37
38#include <sys/socket.h>
39#include <sys/sockio.h>
40#include <net/if.h>
41#include <netinet/in.h>
42#include <netinet/if_ether.h>
43
44#ifdef malloc
45#undef malloc
46#endif
47#ifdef free
48#undef free
49#endif
50
51#if defined(__m68k__)
52extern m68k_isr_entry set_vector( rtems_isr_entry, rtems_vector_number, int );
53#else
54extern rtems_isr_entry set_vector( rtems_isr_entry, rtems_vector_number, int );
55#endif
56
57
58/* #define GRETH_DEBUG */
59
60#ifdef GRETH_DEBUG
61#define DBG(args...) printk(args)
62#else
63#define DBG(args...)
64#endif
65
66/* #define GRETH_DEBUG_MII */
67
68#ifdef GRETH_DEBUG_MII
69#define MIIDBG(args...) printk(args)
70#else
71#define MIIDBG(args...)
72#endif
73
74#ifdef CPU_U32_FIX
75extern void ipalign(struct mbuf *m);
76#endif
77
78/* Used when reading from memory written by GRETH DMA unit */
79#ifndef GRETH_MEM_LOAD
80#define GRETH_MEM_LOAD(addr) (*(volatile unsigned int *)(addr))
81#endif
82
83/*
84 * Number of OCs supported by this driver
85 */
86#define NOCDRIVER       1
87
88/*
89 * Receive buffer size -- Allow for a full ethernet packet including CRC
90 */
91#define RBUF_SIZE 1518
92
93#define ET_MINLEN 64            /* minimum message length */
94
95/*
96 * RTEMS event used by interrupt handler to signal driver tasks.
97 * This must not be any of the events used by the network task synchronization.
98 */
99#define INTERRUPT_EVENT RTEMS_EVENT_1
100
101/*
102 * RTEMS event used to start transmit daemon.
103 * This must not be the same as INTERRUPT_EVENT.
104 */
105#define START_TRANSMIT_EVENT    RTEMS_EVENT_2
106
107 /* event to send when tx buffers become available */
108#define GRETH_TX_WAIT_EVENT  RTEMS_EVENT_3
109
110#if (MCLBYTES < RBUF_SIZE)
111# error "Driver must have MCLBYTES > RBUF_SIZE"
112#endif
113
114/* 4s Autonegotiation Timeout */
115#ifndef GRETH_AUTONEGO_TIMEOUT_MS
116#define GRETH_AUTONEGO_TIMEOUT_MS 4000
117#endif
118const struct timespec greth_tan = {
119   GRETH_AUTONEGO_TIMEOUT_MS/1000,
120   GRETH_AUTONEGO_TIMEOUT_MS*1000000
121};
122
123/* For optimizing the autonegotiation time */
124#define GRETH_AUTONEGO_PRINT_TIME
125
126/* Ethernet buffer descriptor */
127
128typedef struct _greth_rxtxdesc {
129   volatile uint32_t ctrl; /* Length and status */
130   uint32_t *addr;         /* Buffer pointer */
131} greth_rxtxdesc;
132
133
134/*
135 * Per-device data
136 */
137struct greth_softc
138{
139
140   struct arpcom arpcom;
141   struct drvmgr_dev *dev;              /* Driver manager device */
142   char devName[32];
143
144   greth_regs *regs;
145   int minor;
146   int phyaddr;  /* PHY Address configured by user (or -1 to autodetect) */
147
148   int acceptBroadcast;
149   rtems_id daemonTid;
150   
151   unsigned int tx_ptr;
152   unsigned int tx_dptr;
153   unsigned int tx_cnt;
154   unsigned int rx_ptr;
155   unsigned int txbufs;
156   unsigned int rxbufs;
157   greth_rxtxdesc *txdesc;
158   greth_rxtxdesc *rxdesc;
159   unsigned int txdesc_remote;
160   unsigned int rxdesc_remote;
161   struct mbuf **rxmbuf;
162   struct mbuf **txmbuf;
163   rtems_vector_number vector;
164   
165   /* TX descriptor interrupt generation */
166   int tx_int_gen;
167   int tx_int_gen_cur;
168   struct mbuf *next_tx_mbuf;
169   int max_fragsize;
170   
171   /*Status*/
172   struct phy_device_info phydev;
173   int phy_read_access;
174   int phy_write_access;
175   int fd;
176   int sp;
177   int gb;
178   int gbit_mac;
179   int auto_neg;
180   struct timespec auto_neg_time;
181
182   /*
183    * Statistics
184    */
185   unsigned long rxInterrupts;
186   
187   unsigned long rxPackets;
188   unsigned long rxLengthError;
189   unsigned long rxNonOctet;
190   unsigned long rxBadCRC;
191   unsigned long rxOverrun;
192   
193   unsigned long txInterrupts;
194   
195   unsigned long txDeferred;
196   unsigned long txHeartbeat;
197   unsigned long txLateCollision;
198   unsigned long txRetryLimit;
199   unsigned long txUnderrun;
200
201};
202
203int greth_process_tx_gbit(struct greth_softc *sc);
204int greth_process_tx(struct greth_softc *sc);
205
206static char *almalloc(int sz, int alignment)
207{
208        char *tmp;
209        tmp = calloc(1, sz + (alignment-1));
210        tmp = (char *) (((int)tmp+alignment) & ~(alignment -1));
211        return(tmp);
212}
213
214/* GRETH interrupt handler */
215
216void greth_interrupt (void *arg)
217{
218        uint32_t status;
219        uint32_t ctrl;
220        rtems_event_set events = 0;
221        struct greth_softc *greth = arg;
222       
223        /* read and clear interrupt cause */
224        status = greth->regs->status;
225        greth->regs->status = status;
226        ctrl = greth->regs->ctrl;
227       
228        /* Frame received? */
229        if ((ctrl & GRETH_CTRL_RXIRQ) && (status & (GRETH_STATUS_RXERR | GRETH_STATUS_RXIRQ)))
230        {
231                greth->rxInterrupts++;
232                /* Stop RX-Error and RX-Packet interrupts */
233                ctrl &= ~GRETH_CTRL_RXIRQ;
234                events |= INTERRUPT_EVENT;
235        }
236       
237        if ( (ctrl & GRETH_CTRL_TXIRQ) && (status & (GRETH_STATUS_TXERR | GRETH_STATUS_TXIRQ)) )
238        {
239                greth->txInterrupts++;
240                ctrl &= ~GRETH_CTRL_TXIRQ;
241                events |= GRETH_TX_WAIT_EVENT;
242        }
243       
244        /* Clear interrupt sources */
245        greth->regs->ctrl = ctrl;
246       
247        /* Send the event(s) */
248        if ( events )
249            rtems_event_send (greth->daemonTid, events);
250}
251
252static uint32_t read_mii(struct greth_softc *sc, uint32_t phy_addr, uint32_t reg_addr)
253{
254    sc->phy_read_access++;
255    while (sc->regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
256    sc->regs->mdio_ctrl = (phy_addr << 11) | (reg_addr << 6) | GRETH_MDIO_READ;
257    while (sc->regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
258    if (!(sc->regs->mdio_ctrl & GRETH_MDIO_LINKFAIL)) {
259        MIIDBG("greth%d: mii read[%d] OK to %x.%x (0x%08x,0x%08x)\n",
260                sc->minor, sc->phy_read_access, phy_addr, reg_addr,
261                sc->regs->ctrl, sc->regs->mdio_ctrl);
262
263        return((sc->regs->mdio_ctrl >> 16) & 0xFFFF);
264    } else {
265        printf("greth%d: mii read[%d] failed to %x.%x (0x%08x,0x%08x)\n",
266                sc->minor, sc->phy_read_access, phy_addr, reg_addr,
267                sc->regs->ctrl, sc->regs->mdio_ctrl);
268        return (0xffff);
269    }
270}
271
272static void write_mii(struct greth_softc *sc, uint32_t phy_addr, uint32_t reg_addr, uint32_t data)
273{
274    sc->phy_write_access++;
275    while (sc->regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
276    sc->regs->mdio_ctrl =
277     ((data & 0xFFFF) << 16) | (phy_addr << 11) | (reg_addr << 6) | GRETH_MDIO_WRITE;
278    while (sc->regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
279    if (!(sc->regs->mdio_ctrl & GRETH_MDIO_LINKFAIL)) {
280        MIIDBG("greth%d: mii write[%d] OK to %x.%x (0x%08x,0x%08x)\n",
281                sc->minor, sc->phy_write_access, phy_addr, reg_addr,
282                sc->regs->ctrl, sc->regs->mdio_ctrl);
283    } else {
284        printf("greth%d: mii write[%d] failed to %x.%x (0x%08x,0x%08x)\n",
285                sc->minor, sc->phy_write_access, phy_addr, reg_addr,
286                sc->regs->ctrl, sc->regs->mdio_ctrl);
287    }
288}
289
290static void print_init_info(struct greth_softc *sc)
291{
292    printf("greth: driver attached\n");
293    if ( sc->auto_neg == -1 ){
294        printf("Auto negotiation timed out. Selecting default config\n");
295    }
296    printf("**** PHY ****\n");
297    printf("Vendor: %x   Device: %x   Revision: %d\n",sc->phydev.vendor, sc->phydev.device, sc->phydev.rev);
298    printf("Current Operating Mode: ");
299    if (sc->gb) {
300        printf("1000 Mbit ");
301    } else if (sc->sp) {
302        printf("100 Mbit ");
303    } else {
304        printf("10 Mbit ");
305    }
306    if (sc->fd) {
307        printf("Full Duplex\n");
308    } else {
309        printf("Half Duplex\n");
310    }
311#ifdef GRETH_AUTONEGO_PRINT_TIME
312    if ( sc->auto_neg ) {
313        printf("Autonegotiation Time: %dms\n", sc->auto_neg_time.tv_sec * 1000 +
314               sc->auto_neg_time.tv_nsec / 1000000);
315    }
316#endif
317}
318
319
320/*
321 * Initialize the ethernet hardware
322 */
323static void
324greth_initialize_hardware (struct greth_softc *sc)
325{
326    struct mbuf *m;
327    int i;
328    int phyaddr;
329    int phyctrl;
330    int phystatus;
331    int tmp1;
332    int tmp2;
333    struct timespec tstart, tnow;
334
335    greth_regs *regs;
336
337    regs = sc->regs;
338   
339    /* Reset the controller.  */
340    sc->rxInterrupts = 0;
341    sc->rxPackets = 0;
342
343    regs->ctrl = GRETH_CTRL_RST;        /* Reset ON */
344    for (i = 0; i<100 && (regs->ctrl & GRETH_CTRL_RST); i++)
345        ;
346    regs->ctrl = GRETH_CTRL_DD;         /* Reset OFF. SW do PHY Init */
347
348    /* Check if mac is gbit capable*/
349    sc->gbit_mac = (regs->ctrl >> 27) & 1;
350
351    /* Get the phy address which assumed to have been set
352       correctly with the reset value in hardware*/
353    if ( sc->phyaddr == -1 ) {
354        phyaddr = (regs->mdio_ctrl >> 11) & 0x1F;
355    } else {
356        phyaddr = sc->phyaddr;
357    }
358    sc->phy_read_access = 0;
359    sc->phy_write_access = 0;
360
361    /* As I understand the PHY comes back to a good default state after
362     * Power-down or Reset, so we do both just in case. Power-down bit should
363     * be cleared.
364     * Wait for old reset (if asserted by boot loader) to complete, otherwise
365     * power-down instruction might not have any effect.
366     */
367    while (read_mii(sc, phyaddr, 0) & 0x8000) {}
368    write_mii(sc, phyaddr, 0, 0x0800); /* Power-down */
369    write_mii(sc, phyaddr, 0, 0x0000); /* Power-Up */
370    write_mii(sc, phyaddr, 0, 0x8000); /* Reset */
371
372    /* We wait about 30ms */
373    rtems_task_wake_after(rtems_clock_get_ticks_per_second()/32);
374
375    /* Wait for reset to complete and get default values */
376    while ((phyctrl = read_mii(sc, phyaddr, 0)) & 0x8000) {}
377
378    /* Enable/Disable GBit auto-neg advetisement so that the link partner
379     * know that we have/haven't GBit capability. The MAC may not support
380     * Gbit even though PHY does...
381     */
382    phystatus = read_mii(sc, phyaddr, 1);
383    if (phystatus & 0x0100) {
384        tmp1 = read_mii(sc, phyaddr, 9);
385        if (sc->gbit_mac)
386            write_mii(sc, phyaddr, 9, tmp1 | 0x300);
387        else
388            write_mii(sc, phyaddr, 9, tmp1 & ~(0x300));
389    }
390
391    /* If autonegotiation implemented we start it */
392    if (phystatus & 0x0008) {
393        write_mii(sc, phyaddr, 0, phyctrl | 0x1200);
394        phyctrl = read_mii(sc, phyaddr, 0);
395    }
396
397    /* Check if PHY is autoneg capable and then determine operating mode,
398       otherwise force it to 10 Mbit halfduplex */
399    sc->gb = 0;
400    sc->fd = 0;
401    sc->sp = 0;
402    sc->auto_neg = 0;
403    _Timespec_Set_to_zero(&sc->auto_neg_time);
404    if ((phyctrl >> 12) & 1) {
405            /*wait for auto negotiation to complete*/
406            sc->auto_neg = 1;
407            if (rtems_clock_get_uptime(&tstart) != RTEMS_SUCCESSFUL)
408                    printk("rtems_clock_get_uptime failed\n");
409            while (!(((phystatus = read_mii(sc, phyaddr, 1)) >> 5) & 1)) {
410                    if (rtems_clock_get_uptime(&tnow) != RTEMS_SUCCESSFUL)
411                            printk("rtems_clock_get_uptime failed\n");
412                    _Timespec_Subtract(&tstart, &tnow, &sc->auto_neg_time);
413                    if (_Timespec_Greater_than(&sc->auto_neg_time, &greth_tan)) {
414                            sc->auto_neg = -1; /* Failed */
415                            tmp1 = read_mii(sc, phyaddr, 0);
416                            sc->gb = ((phyctrl >> 6) & 1) && !((phyctrl >> 13) & 1);
417                            sc->sp = !((phyctrl >> 6) & 1) && ((phyctrl >> 13) & 1);
418                            sc->fd = (phyctrl >> 8) & 1;
419                            goto auto_neg_done;
420                    }
421                    /* Wait about 30ms, time is PHY dependent */
422                    rtems_task_wake_after(rtems_clock_get_ticks_per_second()/32);
423            }
424            sc->phydev.adv = read_mii(sc, phyaddr, 4);
425            sc->phydev.part = read_mii(sc, phyaddr, 5);
426            if ((phystatus >> 8) & 1) {
427                    sc->phydev.extadv = read_mii(sc, phyaddr, 9);
428                    sc->phydev.extpart = read_mii(sc, phyaddr, 10);
429                       if ( (sc->phydev.extadv & GRETH_MII_EXTADV_1000FD) &&
430                            (sc->phydev.extpart & GRETH_MII_EXTPRT_1000FD)) {
431                               sc->gb = 1;
432                               sc->fd = 1;
433                       }
434                       if ( (sc->phydev.extadv & GRETH_MII_EXTADV_1000HD) &&
435                            (sc->phydev.extpart & GRETH_MII_EXTPRT_1000HD)) {
436                               sc->gb = 1;
437                               sc->fd = 0;
438                       }
439            }
440            if ((sc->gb == 0) || ((sc->gb == 1) && (sc->gbit_mac == 0))) {
441                    if ( (sc->phydev.adv & GRETH_MII_100TXFD) &&
442                         (sc->phydev.part & GRETH_MII_100TXFD)) {
443                            sc->sp = 1;
444                            sc->fd = 1;
445                    }
446                    if ( (sc->phydev.adv & GRETH_MII_100TXHD) &&
447                         (sc->phydev.part & GRETH_MII_100TXHD)) {
448                            sc->sp = 1;
449                            sc->fd = 0;
450                    }
451                    if ( (sc->phydev.adv & GRETH_MII_10FD) &&
452                         (sc->phydev.part & GRETH_MII_10FD)) {
453                            sc->fd = 1;
454                    }
455            }
456    }
457auto_neg_done:
458    sc->phydev.vendor = 0;
459    sc->phydev.device = 0;
460    sc->phydev.rev = 0;
461    phystatus = read_mii(sc, phyaddr, 1);
462
463    /* Read out PHY info if extended registers are available */
464    if (phystatus & 1) { 
465            tmp1 = read_mii(sc, phyaddr, 2);
466            tmp2 = read_mii(sc, phyaddr, 3);
467
468            sc->phydev.vendor = (tmp1 << 6) | ((tmp2 >> 10) & 0x3F);
469            sc->phydev.rev = tmp2 & 0xF;
470            sc->phydev.device = (tmp2 >> 4) & 0x3F;
471    }
472
473    /* Force to 10 mbit half duplex if the 10/100 MAC is used with a 1000 PHY */
474    if (((sc->gb) && !(sc->gbit_mac)) || !((phyctrl >> 12) & 1)) {
475        write_mii(sc, phyaddr, 0, sc->sp << 13);
476
477        /* check if marvell 88EE1111 PHY. Needs special reset handling */
478        if ((phystatus & 1) && (sc->phydev.vendor == 0x005043) &&
479            (sc->phydev.device == 0x0C))
480            write_mii(sc, phyaddr, 0, 0x8000);
481
482        sc->gb = 0;
483        sc->sp = 0;
484        sc->fd = 0;
485    }
486    while ((read_mii(sc, phyaddr, 0)) & 0x8000) {}
487
488    regs->ctrl = GRETH_CTRL_RST;        /* Reset ON */
489    for (i = 0; i < 100 && (regs->ctrl & GRETH_CTRL_RST); i++)
490        ;
491    regs->ctrl = GRETH_CTRL_DD;
492
493    /* Initialize rx/tx descriptor table pointers. Due to alignment we
494     * always allocate maximum table size.
495     */
496    sc->txdesc = (greth_rxtxdesc *) almalloc(0x800, 0x400);
497    sc->rxdesc = (greth_rxtxdesc *) &sc->txdesc[128];
498    sc->tx_ptr = 0;
499    sc->tx_dptr = 0;
500    sc->tx_cnt = 0;
501    sc->rx_ptr = 0;
502
503    /* Translate the Descriptor DMA table base address into an address that
504     * the GRETH core can understand
505     */
506    drvmgr_translate_check(
507        sc->dev,
508        CPUMEM_TO_DMA,
509        (void *)sc->txdesc,
510        (void **)&sc->txdesc_remote,
511        0x800);
512    sc->rxdesc_remote = sc->txdesc_remote + 0x400;
513    regs->txdesc = (int) sc->txdesc_remote;
514    regs->rxdesc = (int) sc->rxdesc_remote;
515
516    sc->rxmbuf = calloc(sc->rxbufs, sizeof(*sc->rxmbuf));
517    sc->txmbuf = calloc(sc->txbufs, sizeof(*sc->txmbuf));
518
519    for (i = 0; i < sc->txbufs; i++)
520      {
521        sc->txdesc[i].ctrl = 0;
522        if (!(sc->gbit_mac)) {
523            drvmgr_translate_check(
524                sc->dev,
525                CPUMEM_TO_DMA,
526                (void *)malloc(GRETH_MAXBUF_LEN),
527                (void **)&sc->txdesc[i].addr,
528                GRETH_MAXBUF_LEN);
529        }
530#ifdef GRETH_DEBUG
531              /* printf("TXBUF: %08x\n", (int) sc->txdesc[i].addr); */
532#endif
533      }
534    for (i = 0; i < sc->rxbufs; i++)
535      {
536         MGETHDR (m, M_WAIT, MT_DATA);
537          MCLGET (m, M_WAIT);
538          if (sc->gbit_mac)
539                  m->m_data += 2;
540          m->m_pkthdr.rcvif = &sc->arpcom.ac_if;
541          sc->rxmbuf[i] = m;
542          drvmgr_translate_check(
543            sc->dev,
544            CPUMEM_TO_DMA,
545            (void *)mtod(m, uint32_t *),
546            (void **)&sc->rxdesc[i].addr,
547            GRETH_MAXBUF_LEN);
548          sc->rxdesc[i].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ;
549#ifdef GRETH_DEBUG
550/*        printf("RXBUF: %08x\n", (int) sc->rxdesc[i].addr); */
551#endif
552      }
553    sc->rxdesc[sc->rxbufs - 1].ctrl |= GRETH_RXD_WRAP;
554
555    /* set ethernet address.  */
556    regs->mac_addr_msb =
557      sc->arpcom.ac_enaddr[0] << 8 | sc->arpcom.ac_enaddr[1];
558    regs->mac_addr_lsb =
559      sc->arpcom.ac_enaddr[2] << 24 | sc->arpcom.ac_enaddr[3] << 16 |
560      sc->arpcom.ac_enaddr[4] << 8 | sc->arpcom.ac_enaddr[5];
561
562    if ( sc->rxbufs < 10 ) {
563        sc->tx_int_gen = sc->tx_int_gen_cur = 1;
564    }else{
565        sc->tx_int_gen = sc->tx_int_gen_cur = sc->txbufs/2;
566    }
567    sc->next_tx_mbuf = NULL;
568   
569    if ( !sc->gbit_mac )
570        sc->max_fragsize = 1;
571
572    /* clear all pending interrupts */
573    regs->status = 0xffffffff;
574
575    /* install interrupt handler */
576    drvmgr_interrupt_register(sc->dev, 0, "greth", greth_interrupt, sc);
577
578    regs->ctrl |= GRETH_CTRL_RXEN | (sc->fd << 4) | GRETH_CTRL_RXIRQ | (sc->sp << 7) | (sc->gb << 8);
579
580    print_init_info(sc);
581}
582
583#ifdef CPU_U32_FIX
584
585/*
586 * Routine to align the received packet so that the ip header
587 * is on a 32-bit boundary. Necessary for cpu's that do not
588 * allow unaligned loads and stores and when the 32-bit DMA
589 * mode is used.
590 *
591 * Transfers are done on word basis to avoid possibly slow byte
592 * and half-word writes.
593 */
594
595void ipalign(struct mbuf *m)
596{
597  unsigned int *first, *last, data;
598  unsigned int tmp = 0;
599
600  if ((((int) m->m_data) & 2) && (m->m_len)) {
601    last = (unsigned int *) ((((int) m->m_data) + m->m_len + 8) & ~3);
602    first = (unsigned int *) (((int) m->m_data) & ~3);
603                /* tmp = *first << 16; */
604                asm volatile (" lda [%1] 1, %0\n" : "=r"(tmp) : "r"(first) );
605                tmp = tmp << 16;
606    first++;
607    do {
608                        /* When snooping is not available the LDA instruction must be used
609                         * to avoid the cache to return an illegal value.
610                         ** Load with forced cache miss
611                         * data = *first;
612                         */
613      asm volatile (" lda [%1] 1, %0\n" : "=r"(data) : "r"(first) );
614      *first = tmp | (data >> 16);
615      tmp = data << 16;
616      first++;
617    } while (first <= last);
618
619    m->m_data = (caddr_t)(((int) m->m_data) + 2);
620  }
621}
622#endif
623
624void
625greth_Daemon (void *arg)
626{
627    struct ether_header *eh;
628    struct greth_softc *dp = (struct greth_softc *) arg;
629    struct ifnet *ifp = &dp->arpcom.ac_if;
630    struct mbuf *m;
631    unsigned int len, len_status, bad;
632    rtems_event_set events;
633    rtems_interrupt_level level;
634    int first;
635                int tmp;
636                unsigned int addr;
637   
638    for (;;)
639      {
640        rtems_bsdnet_event_receive (INTERRUPT_EVENT | GRETH_TX_WAIT_EVENT,
641                                    RTEMS_WAIT | RTEMS_EVENT_ANY,
642                                    RTEMS_NO_TIMEOUT, &events);
643       
644        if ( events & GRETH_TX_WAIT_EVENT ){
645            /* TX interrupt.
646             * We only end up here when all TX descriptors has been used,
647             * and
648             */
649            if ( dp->gbit_mac )
650                greth_process_tx_gbit(dp);
651            else
652                greth_process_tx(dp);
653           
654            /* If we didn't get a RX interrupt we don't process it */
655            if ( (events & INTERRUPT_EVENT) == 0 )
656                continue;
657        }
658       
659       
660#ifdef GRETH_ETH_DEBUG
661    printf ("r\n");
662#endif
663    first=1;
664    /* Scan for Received packets */
665again:
666    while (!((len_status =
667                    GRETH_MEM_LOAD(&dp->rxdesc[dp->rx_ptr].ctrl)) & GRETH_RXD_ENABLE))
668            {
669                    bad = 0;
670                    if (len_status & GRETH_RXD_TOOLONG)
671                    {
672                            dp->rxLengthError++;
673                            bad = 1;
674                    }
675                    if (len_status & GRETH_RXD_DRIBBLE)
676                    {
677                            dp->rxNonOctet++;
678                            bad = 1;
679                    }
680                    if (len_status & GRETH_RXD_CRCERR)
681                    {
682                            dp->rxBadCRC++;
683                            bad = 1;
684                    }
685                    if (len_status & GRETH_RXD_OVERRUN)
686                    {
687                            dp->rxOverrun++;
688                            bad = 1;
689                    }
690                    if (len_status & GRETH_RXD_LENERR)
691                    {
692                            dp->rxLengthError++;
693                            bad = 1;
694                    }
695                    if (!bad)
696                    {
697                            /* pass on the packet in the receive buffer */
698                            len = len_status & 0x7FF;
699                            m = dp->rxmbuf[dp->rx_ptr];
700#ifdef GRETH_DEBUG
701                            int i;
702                            printf("RX: 0x%08x, Len: %d : ", (int) m->m_data, len);
703                            for (i=0; i<len; i++)
704                                    printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
705                            printf("\n");
706#endif
707                            m->m_len = m->m_pkthdr.len =
708                                    len - sizeof (struct ether_header);
709
710                            eh = mtod (m, struct ether_header *);
711
712                            m->m_data += sizeof (struct ether_header);
713#ifdef CPU_U32_FIX
714                            if(!dp->gbit_mac) {
715                                    /* OVERRIDE CACHED ETHERNET HEADER FOR NON-SNOOPING SYSTEMS */
716                                    addr = (unsigned int)eh;
717                                    asm volatile (" lda [%1] 1, %0\n" : "=r"(tmp) : "r"(addr) );
718                                    addr+=4;
719                                    asm volatile (" lda [%1] 1, %0\n" : "=r"(tmp) : "r"(addr) );
720                                    addr+=4;
721                                    asm volatile (" lda [%1] 1, %0\n" : "=r"(tmp) : "r"(addr) );
722                                    addr+=4;
723                                    asm volatile (" lda [%1] 1, %0\n" : "=r"(tmp) : "r"(addr) );
724
725                                    ipalign(m); /* Align packet on 32-bit boundary */
726                            }
727#endif
728/*
729                            if(!(dp->gbit_mac) && !CPU_SPARC_HAS_SNOOPING) {
730                                    rtems_cache_invalidate_entire_data();
731                            }
732*/
733                            ether_input (ifp, eh, m);
734                            MGETHDR (m, M_WAIT, MT_DATA);
735                            MCLGET (m, M_WAIT);
736                            if (dp->gbit_mac)
737                                    m->m_data += 2;
738                            dp->rxmbuf[dp->rx_ptr] = m;
739                            m->m_pkthdr.rcvif = ifp;
740                            drvmgr_translate_check(
741                                dp->dev,
742                                CPUMEM_TO_DMA,
743                                (void *)mtod (m, uint32_t *),
744                                (void **)&dp->rxdesc[dp->rx_ptr].addr,
745                                GRETH_MAXBUF_LEN);
746                            dp->rxPackets++;
747                    }
748                    if (dp->rx_ptr == dp->rxbufs - 1) {
749                            dp->rxdesc[dp->rx_ptr].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ | GRETH_RXD_WRAP;
750                    } else {
751                            dp->rxdesc[dp->rx_ptr].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ;
752                    }
753                    rtems_interrupt_disable(level);
754                    dp->regs->ctrl |= GRETH_CTRL_RXEN;
755                    rtems_interrupt_enable(level);
756                    dp->rx_ptr = (dp->rx_ptr + 1) % dp->rxbufs;
757            }
758       
759        /* Always scan twice to avoid deadlock */
760        if ( first ){
761            first=0;
762            rtems_interrupt_disable(level);
763            dp->regs->ctrl |= GRETH_CTRL_RXIRQ;
764            rtems_interrupt_enable(level);
765            goto again;
766        }
767
768      }
769   
770}
771
772static int inside = 0;
773static int
774sendpacket (struct ifnet *ifp, struct mbuf *m)
775{
776    struct greth_softc *dp = ifp->if_softc;
777    unsigned char *temp;
778    struct mbuf *n;
779    unsigned int len;
780    rtems_interrupt_level level;
781       
782    /*printf("Send packet entered\n");*/
783    if (inside) printf ("error: sendpacket re-entered!!\n");
784    inside = 1;
785   
786    /*
787     * Is there a free descriptor available?
788     */
789    if (GRETH_MEM_LOAD(&dp->txdesc[dp->tx_ptr].ctrl) & GRETH_TXD_ENABLE){
790            /* No. */
791            inside = 0;
792            return 1;
793    }
794   
795    /* Remember head of chain */
796    n = m;
797
798    len = 0;
799    temp = (unsigned char *) GRETH_MEM_LOAD(&dp->txdesc[dp->tx_ptr].addr);
800    drvmgr_translate(dp->dev, CPUMEM_FROM_DMA, (void *)temp, (void **)&temp);
801#ifdef GRETH_DEBUG
802    printf("TXD: 0x%08x : BUF: 0x%08x\n", (int) m->m_data, (int) temp);
803#endif
804    for (;;)
805    {
806#ifdef GRETH_DEBUG
807            int i;
808            printf("MBUF: 0x%08x : ", (int) m->m_data);
809            for (i=0;i<m->m_len;i++)
810                    printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
811            printf("\n");
812#endif
813            len += m->m_len;
814            if (len <= RBUF_SIZE)
815                    memcpy ((void *) temp, (char *) m->m_data, m->m_len);
816            temp += m->m_len;
817            if ((m = m->m_next) == NULL)
818                    break;
819    }
820   
821    m_freem (n);
822   
823    /* don't send long packets */
824
825    if (len <= GRETH_MAXBUF_LEN) {
826            if (dp->tx_ptr < dp->txbufs-1) {
827                    dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_ENABLE | len;
828            } else {
829                    dp->txdesc[dp->tx_ptr].ctrl =
830                            GRETH_TXD_WRAP | GRETH_TXD_ENABLE | len;
831            }
832            dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
833            rtems_interrupt_disable(level);
834            dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
835            rtems_interrupt_enable(level);
836           
837    }
838    inside = 0;
839   
840    return 0;
841}
842
843
844int
845sendpacket_gbit (struct ifnet *ifp, struct mbuf *m)
846{
847        struct greth_softc *dp = ifp->if_softc;
848        unsigned int len;
849       
850        unsigned int ctrl;
851        int frags;
852        struct mbuf *mtmp;
853        int int_en;
854        rtems_interrupt_level level;
855
856        if (inside) printf ("error: sendpacket re-entered!!\n");
857        inside = 1;
858       
859        len = 0;
860#ifdef GRETH_DEBUG
861        printf("TXD: 0x%08x\n", (int) m->m_data);
862#endif
863        /* Get number of fragments too see if we have enough
864         * resources.
865         */
866        frags=1;
867        mtmp=m;
868        while(mtmp->m_next){
869            frags++;
870            mtmp = mtmp->m_next;
871        }
872
873        if ( frags > dp->max_fragsize )
874            dp->max_fragsize = frags;
875       
876        if ( frags > dp->txbufs ){
877            inside = 0;
878            printf("GRETH: MBUF-chain cannot be sent. Increase descriptor count.\n");
879            return -1;
880        }
881       
882        if ( frags > (dp->txbufs-dp->tx_cnt) ){
883            inside = 0;
884            /* Return number of fragments */
885            return frags;
886        }
887       
888       
889        /* Enable interrupt from descriptor every tx_int_gen
890         * descriptor. Typically every 16 descriptor. This
891         * is only to reduce the number of interrupts during
892         * heavy load.
893         */
894        dp->tx_int_gen_cur-=frags;
895        if ( dp->tx_int_gen_cur <= 0 ){
896            dp->tx_int_gen_cur = dp->tx_int_gen;
897            int_en = GRETH_TXD_IRQ;
898        }else{
899            int_en = 0;
900        }
901       
902        /* At this stage we know that enough descriptors are available */
903        for (;;)
904        {
905               
906#ifdef GRETH_DEBUG
907            int i;
908            printf("MBUF: 0x%08x, Len: %d : ", (int) m->m_data, m->m_len);
909            for (i=0; i<m->m_len; i++)
910                printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
911            printf("\n");
912#endif
913            len += m->m_len;
914            drvmgr_translate_check(
915                dp->dev,
916                CPUMEM_TO_DMA,
917                (void *)(uint32_t *)m->m_data,
918                (void **)&dp->txdesc[dp->tx_ptr].addr,
919                m->m_len);
920
921            /* Wrap around? */
922            if (dp->tx_ptr < dp->txbufs-1) {
923                ctrl = GRETH_TXD_ENABLE;
924            }else{
925                ctrl = GRETH_TXD_ENABLE | GRETH_TXD_WRAP;
926            }
927
928            /* Enable Descriptor */ 
929            if ((m->m_next) == NULL) {
930                dp->txdesc[dp->tx_ptr].ctrl = ctrl | int_en | m->m_len;
931                break;
932            }else{
933                dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_MORE | ctrl | int_en | m->m_len;
934            }
935
936            /* Next */
937            dp->txmbuf[dp->tx_ptr] = m;
938            dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
939            dp->tx_cnt++;
940            m = m->m_next;
941        }
942        dp->txmbuf[dp->tx_ptr] = m;
943        dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
944        dp->tx_cnt++;
945     
946        /* Tell Hardware about newly enabled descriptor */
947        rtems_interrupt_disable(level);
948        dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
949        rtems_interrupt_enable(level);
950
951        inside = 0;
952               
953        return 0;
954}
955
956int greth_process_tx_gbit(struct greth_softc *sc)
957{
958    struct ifnet *ifp = &sc->arpcom.ac_if;
959    struct mbuf *m;
960    rtems_interrupt_level level;
961    int first=1;
962   
963    /*
964     * Send packets till queue is empty
965     */
966    for (;;){
967        /* Reap Sent packets */
968        while((sc->tx_cnt > 0) && !(GRETH_MEM_LOAD(&sc->txdesc[sc->tx_dptr].ctrl) & GRETH_TXD_ENABLE)) {
969            m_free(sc->txmbuf[sc->tx_dptr]);
970            sc->tx_dptr = (sc->tx_dptr + 1) % sc->txbufs;
971            sc->tx_cnt--;
972        }
973       
974        if ( sc->next_tx_mbuf ){
975            /* Get packet we tried but faild to transmit last time */
976            m = sc->next_tx_mbuf;
977            sc->next_tx_mbuf = NULL; /* Mark packet taken */
978        }else{
979            /*
980             * Get the next mbuf chain to transmit from Stack.
981             */
982            IF_DEQUEUE (&ifp->if_snd, m);
983            if (!m){
984                /* Hardware has sent all schedule packets, this
985                 * makes the stack enter at greth_start next time
986                 * a packet is to be sent.
987                 */
988                ifp->if_flags &= ~IFF_OACTIVE;
989                break;
990            }
991        }
992
993        /* Are there free descriptors available? */
994        /* Try to send packet, if it a negative number is returned. */
995        if ( (sc->tx_cnt >= sc->txbufs) || sendpacket_gbit(ifp, m) ){
996            /* Not enough resources */
997             
998            /* Since we have taken the mbuf out of the "send chain"
999             * we must remember to use that next time we come back.
1000             * or else we have dropped a packet.
1001             */
1002            sc->next_tx_mbuf = m;
1003           
1004            /* Not enough resources, enable interrupt for transmissions
1005             * this way we will be informed when more TX-descriptors are
1006             * available.
1007             */
1008            if ( first ){
1009                first = 0;
1010                rtems_interrupt_disable(level);
1011                ifp->if_flags |= IFF_OACTIVE;
1012                sc->regs->ctrl |= GRETH_CTRL_TXIRQ;
1013                rtems_interrupt_enable(level);
1014               
1015                /* We must check again to be sure that we didn't
1016                 * miss an interrupt (if a packet was sent just before
1017                 * enabling interrupts)
1018                 */
1019                continue;
1020            }
1021           
1022            return -1;
1023        }else{
1024            /* Sent Ok, proceed to process more packets if available */
1025        }
1026    }
1027    return 0;
1028}
1029
1030int greth_process_tx(struct greth_softc *sc)
1031{
1032    struct ifnet *ifp = &sc->arpcom.ac_if;
1033    struct mbuf *m;
1034    rtems_interrupt_level level;
1035    int first=1;
1036   
1037    /*
1038     * Send packets till queue is empty
1039     */
1040    for (;;){
1041        if ( sc->next_tx_mbuf ){
1042            /* Get packet we tried but failed to transmit last time */
1043            m = sc->next_tx_mbuf;
1044            sc->next_tx_mbuf = NULL; /* Mark packet taken */
1045        }else{
1046            /*
1047             * Get the next mbuf chain to transmit from Stack.
1048             */
1049            IF_DEQUEUE (&ifp->if_snd, m);
1050            if (!m){
1051                /* Hardware has sent all schedule packets, this
1052                 * makes the stack enter at greth_start next time
1053                 * a packet is to be sent.
1054                 */
1055                ifp->if_flags &= ~IFF_OACTIVE;
1056                break;
1057            }
1058        }
1059
1060        /* Try to send packet, failed if it a non-zero number is returned. */
1061        if ( sendpacket(ifp, m) ){
1062            /* Not enough resources */
1063             
1064            /* Since we have taken the mbuf out of the "send chain"
1065             * we must remember to use that next time we come back.
1066             * or else we have dropped a packet.
1067             */
1068            sc->next_tx_mbuf = m;
1069           
1070            /* Not enough resources, enable interrupt for transmissions
1071             * this way we will be informed when more TX-descriptors are
1072             * available.
1073             */
1074            if ( first ){
1075                first = 0;
1076                rtems_interrupt_disable(level);
1077                ifp->if_flags |= IFF_OACTIVE;
1078                sc->regs->ctrl |= GRETH_CTRL_TXIRQ;
1079                rtems_interrupt_enable(level);
1080               
1081                /* We must check again to be sure that we didn't
1082                 * miss an interrupt (if a packet was sent just before
1083                 * enabling interrupts)
1084                 */
1085                continue;
1086            }
1087           
1088            return -1;
1089        }else{
1090            /* Sent Ok, proceed to process more packets if available */
1091        }
1092    }
1093    return 0;
1094}
1095
1096static void
1097greth_start (struct ifnet *ifp)
1098{
1099    struct greth_softc *sc = ifp->if_softc;
1100   
1101    if ( ifp->if_flags & IFF_OACTIVE )
1102            return;
1103   
1104    if ( sc->gbit_mac ){
1105        /* No use trying to handle this if we are waiting on GRETH
1106         * to send the previously scheduled packets.
1107         */
1108       
1109        greth_process_tx_gbit(sc);
1110    }else{
1111        greth_process_tx(sc);
1112    }
1113   
1114}
1115
1116/*
1117 * Initialize and start the device
1118 */
1119static void
1120greth_init (void *arg)
1121{
1122    struct greth_softc *sc = arg;
1123    struct ifnet *ifp = &sc->arpcom.ac_if;
1124    char name[4] = {'E', 'T', 'H', '0'};
1125
1126    if (sc->daemonTid == 0)
1127      {
1128
1129          /*
1130           * Start driver tasks
1131           */
1132          name[3] += sc->minor;
1133          sc->daemonTid = rtems_bsdnet_newproc (name, 4096,
1134                                                  greth_Daemon, sc);
1135
1136          /*
1137           * Set up GRETH hardware
1138           */
1139      greth_initialize_hardware (sc);
1140         
1141      }
1142
1143    /*
1144     * Tell the world that we're running.
1145     */
1146    ifp->if_flags |= IFF_RUNNING;
1147
1148}
1149
1150/*
1151 * Stop the device
1152 */
1153static void
1154greth_stop (struct greth_softc *sc)
1155{
1156    struct ifnet *ifp = &sc->arpcom.ac_if;
1157
1158    ifp->if_flags &= ~IFF_RUNNING;
1159
1160    sc->regs->ctrl = 0;                 /* RX/TX OFF */
1161    sc->regs->ctrl = GRETH_CTRL_RST;    /* Reset ON */
1162    sc->regs->ctrl = 0;                 /* Reset OFF */
1163   
1164    sc->next_tx_mbuf = NULL;
1165}
1166
1167
1168/*
1169 * Show interface statistics
1170 */
1171static void
1172greth_stats (struct greth_softc *sc)
1173{
1174  printf ("      Rx Interrupts:%-8lu", sc->rxInterrupts);
1175  printf ("      Rx Packets:%-8lu", sc->rxPackets);
1176  printf ("          Length:%-8lu", sc->rxLengthError);
1177  printf ("       Non-octet:%-8lu\n", sc->rxNonOctet);
1178  printf ("            Bad CRC:%-8lu", sc->rxBadCRC);
1179  printf ("         Overrun:%-8lu", sc->rxOverrun);
1180  printf ("      Tx Interrupts:%-8lu", sc->txInterrupts);
1181  printf ("      Maximal Frags:%-8d", sc->max_fragsize);
1182  printf ("      GBIT MAC:%-8d", sc->gbit_mac);
1183}
1184
1185/*
1186 * Driver ioctl handler
1187 */
1188static int
1189greth_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data)
1190{
1191    struct greth_softc *sc = ifp->if_softc;
1192    int error = 0;
1193
1194    switch (command)
1195      {
1196      case SIOCGIFADDR:
1197      case SIOCSIFADDR:
1198          ether_ioctl (ifp, command, data);
1199          break;
1200
1201      case SIOCSIFFLAGS:
1202          switch (ifp->if_flags & (IFF_UP | IFF_RUNNING))
1203            {
1204            case IFF_RUNNING:
1205                greth_stop (sc);
1206                break;
1207
1208            case IFF_UP:
1209                greth_init (sc);
1210                break;
1211
1212            case IFF_UP | IFF_RUNNING:
1213                greth_stop (sc);
1214                greth_init (sc);
1215                break;
1216       default:
1217                break;
1218            }
1219          break;
1220
1221      case SIO_RTEMS_SHOW_STATS:
1222          greth_stats (sc);
1223          break;
1224
1225          /*
1226           * FIXME: All sorts of multicast commands need to be added here!
1227           */
1228      default:
1229          error = EINVAL;
1230          break;
1231      }
1232
1233    return error;
1234}
1235
1236/*
1237 * Attach an GRETH driver to the system
1238 */
1239int
1240greth_interface_driver_attach (
1241    struct rtems_bsdnet_ifconfig *config,
1242    int attach
1243    )
1244{
1245    struct greth_softc *sc;
1246    struct ifnet *ifp;
1247    int mtu;
1248    int unitNumber;
1249    char *unitName;
1250   
1251      /* parse driver name */
1252    if ((unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName)) < 0)
1253        return 0;
1254
1255    sc = config->drv_ctrl;
1256    ifp = &sc->arpcom.ac_if;
1257#ifdef GRETH_DEBUG
1258    printf("GRETH[%d]: %s, sc %p, dev %p on %s\n", unitNumber, config->ip_address, sc, sc->dev, sc->dev->parent->dev->name);
1259#endif
1260    if (config->hardware_address)
1261      {
1262          memcpy (sc->arpcom.ac_enaddr, config->hardware_address,
1263                  ETHER_ADDR_LEN);
1264      }
1265    else
1266      {
1267          memset (sc->arpcom.ac_enaddr, 0x08, ETHER_ADDR_LEN);
1268      }
1269
1270    if (config->mtu)
1271        mtu = config->mtu;
1272    else
1273        mtu = ETHERMTU;
1274
1275    sc->acceptBroadcast = !config->ignore_broadcast;
1276
1277    /*
1278     * Set up network interface values
1279     */
1280    ifp->if_softc = sc;
1281    ifp->if_unit = unitNumber;
1282    ifp->if_name = unitName;
1283    ifp->if_mtu = mtu;
1284    ifp->if_init = greth_init;
1285    ifp->if_ioctl = greth_ioctl;
1286    ifp->if_start = greth_start;
1287    ifp->if_output = ether_output;
1288    ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
1289    if (ifp->if_snd.ifq_maxlen == 0)
1290        ifp->if_snd.ifq_maxlen = ifqmaxlen;
1291
1292    /*
1293     * Attach the interface
1294     */
1295    if_attach (ifp);
1296    ether_ifattach (ifp);
1297
1298#ifdef GRETH_DEBUG
1299    printf ("GRETH : driver has been attached\n");
1300#endif
1301    return 1;
1302}
1303
1304/******************* Driver manager interface ***********************/
1305
1306/* Driver prototypes */
1307int greth_register_io(rtems_device_major_number *m);
1308int greth_device_init(struct greth_softc *sc);
1309int network_interface_add(struct rtems_bsdnet_ifconfig *interface);
1310
1311#ifdef GRETH_INFO_AVAIL
1312static int greth_info(
1313        struct drvmgr_dev *dev,
1314        void (*print_line)(void *p, char *str),
1315        void *p, int argc, char *argv[]);
1316#define GRETH_INFO_FUNC greth_info
1317#else
1318#define GRETH_INFO_FUNC NULL
1319#endif
1320
1321int greth_init2(struct drvmgr_dev *dev);
1322int greth_init3(struct drvmgr_dev *dev);
1323
1324struct drvmgr_drv_ops greth_ops =
1325{
1326        .init   =
1327                {
1328                        NULL,
1329                        greth_init2,
1330                        greth_init3,
1331                        NULL
1332                },
1333        .remove = NULL,
1334        .info = GRETH_INFO_FUNC,
1335};
1336
1337struct amba_dev_id greth_ids[] =
1338{
1339        {VENDOR_GAISLER, GAISLER_ETHMAC},
1340        {0, 0}          /* Mark end of table */
1341};
1342
1343struct amba_drv_info greth_drv_info =
1344{
1345        {
1346                DRVMGR_OBJ_DRV,                 /* Driver */
1347                NULL,                           /* Next driver */
1348                NULL,                           /* Device list */
1349                DRIVER_AMBAPP_GAISLER_GRETH_ID, /* Driver ID */
1350                "GRETH_DRV",                    /* Driver Name */
1351                DRVMGR_BUS_TYPE_AMBAPP,         /* Bus Type */
1352                &greth_ops,
1353                NULL,                           /* Funcs */
1354                0,                              /* No devices yet */
1355                0,
1356        },
1357        &greth_ids[0]
1358};
1359
1360void greth_register_drv (void)
1361{
1362        DBG("Registering GRETH driver\n");
1363        drvmgr_drv_register(&greth_drv_info.general);
1364}
1365
1366int greth_init2(struct drvmgr_dev *dev)
1367{
1368        struct greth_softc *priv;
1369
1370        DBG("GRETH[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
1371        priv = dev->priv = malloc(sizeof(struct greth_softc));
1372        if ( !priv )
1373                return DRVMGR_NOMEM;
1374        memset(priv, 0, sizeof(*priv));
1375        priv->dev = dev;
1376
1377        /* This core will not find other cores, so we wait for init3() */
1378
1379        return DRVMGR_OK;
1380}
1381
1382int greth_init3(struct drvmgr_dev *dev)
1383{
1384    struct greth_softc *sc;
1385    struct rtems_bsdnet_ifconfig *ifp;
1386    rtems_status_code status;
1387
1388    sc = dev->priv;
1389    sprintf(sc->devName, "gr_eth%d", (dev->minor_drv+1));
1390
1391    /* Init GRETH device */
1392    if ( greth_device_init(sc) ) {
1393        printk("GRETH: Failed to init device\n");
1394        return DRVMGR_FAIL;
1395    }
1396
1397    /* Register GRETH device as an Network interface */
1398    ifp = malloc(sizeof(struct rtems_bsdnet_ifconfig));
1399    memset(ifp, 0, sizeof(*ifp));
1400
1401    ifp->name = sc->devName;
1402    ifp->drv_ctrl = sc;
1403    ifp->attach = greth_interface_driver_attach;
1404
1405    status = network_interface_add(ifp);
1406    if (status != 0) {
1407        return DRVMGR_FAIL;
1408    }
1409
1410    return DRVMGR_OK;
1411}
1412
1413int greth_device_init(struct greth_softc *sc)
1414{
1415    struct amba_dev_info *ambadev;
1416    struct ambapp_core *pnpinfo;
1417    union drvmgr_key_value *value;
1418
1419    /* Get device information from AMBA PnP information */
1420    ambadev = (struct amba_dev_info *)sc->dev->businfo;
1421    if ( ambadev == NULL ) {
1422        return -1;
1423    }
1424    pnpinfo = &ambadev->info;
1425    sc->regs = (greth_regs *)pnpinfo->apb_slv->start;
1426    sc->minor = sc->dev->minor_drv;
1427
1428    /* clear control register and reset NIC
1429     * This should be done as quick as possible during startup, this is to
1430     * stop DMA transfers after a reboot.
1431     */
1432    sc->regs->ctrl = 0;
1433    sc->regs->ctrl = GRETH_CTRL_RST;
1434    sc->regs->ctrl = 0;
1435
1436    /* Configure driver by overriding default config with the bus resources
1437     * configured by the user
1438     */
1439    sc->txbufs = 32;
1440    sc->rxbufs = 32;
1441    sc->phyaddr = -1;
1442
1443    value = drvmgr_dev_key_get(sc->dev, "txDescs", KEY_TYPE_INT);
1444    if ( value && (value->i <= 128) )
1445        sc->txbufs = value->i;
1446
1447    value = drvmgr_dev_key_get(sc->dev, "rxDescs", KEY_TYPE_INT);
1448    if ( value && (value->i <= 128) )
1449        sc->rxbufs = value->i;
1450
1451    value = drvmgr_dev_key_get(sc->dev, "phyAdr", KEY_TYPE_INT);
1452    if ( value && (value->i < 32) )
1453        sc->phyaddr = value->i;
1454
1455    return 0;
1456}
1457
1458#ifdef GRETH_INFO_AVAIL
1459static int greth_info(
1460        struct drvmgr_dev *dev,
1461        void (*print_line)(void *p, char *str),
1462        void *p, int argc, char *argv[])
1463{
1464        struct greth_softc *sc;
1465        char buf[64];
1466
1467        if (dev->priv == NULL)
1468                return -DRVMGR_EINVAL;
1469        sc = dev->priv;
1470
1471        sprintf(buf, "IFACE NAME:  %s", sc->devName);
1472        print_line(p, buf);
1473        sprintf(buf, "GBIT MAC:    %s", sc->gbit_mac ? "YES" : "NO");
1474        print_line(p, buf);
1475
1476        return DRVMGR_OK;
1477}
1478#endif
1479
1480#endif
Note: See TracBrowser for help on using the repository browser.