source: rtems/bsps/sparc/shared/net/greth.c @ 243ddb5

Last change on this file since 243ddb5 was 243ddb5, checked in by Daniel Hellstrom <daniel@…>, on Jun 15, 2018 at 12:28:36 PM

leon,greth: enable MAC filtering (promiscous mode, multicast)

It enabled promiscous mode or sets the multicast filter according
to the configuration and parameters to ioctl(SIOCSIFFLAGS),
ioctl(SIOCADDMULTI) and ioctl(SIOCDELMULTI).
On SIOCADDMULTI/SIOCDELMULTI requests the greth ioctl calls the
Ethernet helper functions ether_addmulti()/ether_delmulti() which
tells the greth driver when its required to update the MAC multicast
filtering.

The interface notifies support for multicast by setting IFF_MULTICAST.

The GRETH has two registers which contains a bit-mask of allowed MAC
addresses. The incomming MAC address is CRC:ed and the CRC is used as
an index into the bit-mask to determine to allow or drop the frame.

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