source: rtems/c/src/lib/libbsp/sparc/shared/net/greth.c @ 4d3e70f4

4.115
Last change on this file since 4d3e70f4 was 4d3e70f4, checked in by Daniel Hellstrom <daniel@…>, on 04/13/15 at 09:26:52

DRVMGR: KEY_TYPE now a enum drvmgr_kt

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