source: rtems/c/src/lib/libbsp/mips/csb350/network/network.c @ 6279149

4.115
Last change on this file since 6279149 was c499856, checked in by Chris Johns <chrisj@…>, on 03/20/14 at 21:10:47

Change all references of rtems.com to rtems.org.

  • Property mode set to 100644
File size: 25.7 KB
Line 
1/**
2 *  @file
3 * 
4 *  Au1x00 ethernet driver
5 */
6
7/*
8 *  Copyright (c) 2005 by Cogent Computer Systems
9 *  Written by Jay Monkman <jtm@lopingdog.com>
10 *
11 *  The license and distribution terms for this file may be
12 *  found in the file LICENSE in this distribution or at
13 *  http://www.rtems.org/license/LICENSE.
14 */
15
16#include <rtems.h>
17#include <rtems/rtems_bsdnet.h>
18#include <bsp.h>
19#include <rtems/bspIo.h>
20#include <libcpu/au1x00.h>
21#include <bsp/irq.h>
22
23#include <stdio.h>
24#include <string.h>
25
26#include <errno.h>
27#include <rtems/error.h>
28
29#include <sys/param.h>
30#include <sys/mbuf.h>
31#include <sys/socket.h>
32#include <sys/sockio.h>
33
34#include <net/if.h>
35
36#include <netinet/in.h>
37#include <netinet/if_ether.h>
38
39#include <assert.h>
40
41#define NUM_IFACES 1
42#define NUM_TX_DMA_BUFS 4
43#define NUM_RX_DMA_BUFS 4
44
45/*  RTEMS event used to start tx daemon. */
46#define START_TX_EVENT  RTEMS_EVENT_1
47/*  RTEMS event used to start rx daemon. */
48#define START_RX_EVENT  RTEMS_EVENT_2
49
50rtems_isr au1x00_emac_isr(rtems_vector_number vector);
51
52#define TX_BUF_SIZE 2048
53
54char tx_buf_base[(4 * TX_BUF_SIZE) + 32];
55
56volatile int wait_count;
57/*
58 * Hardware-specific storage
59 */
60typedef struct
61{
62    /*
63     * Connection to networking code
64     * This entry *must* be the first in the sonic_softc structure.
65     */
66    struct arpcom                    arpcom;
67
68    /*
69     * Interrupt vector
70     */
71    rtems_vector_number             vector;
72
73    /*
74     *  Indicates configuration
75     */
76    int                             acceptBroadcast;
77
78    /*
79     * Tasks waiting for interrupts
80     */
81    rtems_id                        rx_daemon_tid;
82    rtems_id                        tx_daemon_tid;
83
84    /*
85     * Buffers
86     */
87    au1x00_macdma_rx_t             *rx_dma;
88    au1x00_macdma_tx_t             *tx_dma;
89    int                             rx_head;
90    int                             rx_tail;
91    int                             tx_head;
92    int                             tx_tail;
93    struct mbuf                    *rx_mbuf[NUM_RX_DMA_BUFS];
94
95    unsigned char                  *tx_buf[4];
96
97    /*
98     * register addresses
99     */
100    uint32_t                      ctrl_regs;
101    uint32_t                     *en_reg;
102    uint32_t                      int_mask;
103    uint32_t                      int_ctrlr;
104
105    /*
106     * device
107     */
108    int                             unitnumber;
109
110    /*
111     * Statistics
112     */
113    unsigned long                   interrupts;
114    unsigned long                   rx_interrupts;
115    unsigned long                   tx_interrupts;
116    unsigned long                   rx_missed;
117    unsigned long                   rx_bcast;
118    unsigned long                   rx_mcast;
119    unsigned long                   rx_unsupp;
120    unsigned long                   rx_ctrl;
121    unsigned long                   rx_len_err;
122    unsigned long                   rx_crc_err;
123    unsigned long                   rx_dribble;
124    unsigned long                   rx_mii_err;
125    unsigned long                   rx_collision;
126    unsigned long                   rx_too_long;
127    unsigned long                   rx_runt;
128    unsigned long                   rx_watchdog;
129    unsigned long                   rx_pkts;
130    unsigned long                   rx_dropped;
131
132    unsigned long                   tx_deferred;
133    unsigned long                   tx_underrun;
134    unsigned long                   tx_aborted;
135    unsigned long                   tx_pkts;
136} au1x00_emac_softc_t;
137
138static au1x00_emac_softc_t softc[NUM_IFACES];
139
140
141/* function prototypes */
142int rtems_au1x00_emac_attach (struct rtems_bsdnet_ifconfig *config,
143                              int attaching);
144void au1x00_emac_init(void *arg);
145void au1x00_emac_init_hw(au1x00_emac_softc_t *sc);
146void au1x00_emac_start(struct ifnet *ifp);
147void au1x00_emac_stop (au1x00_emac_softc_t *sc);
148void au1x00_emac_tx_daemon (void *arg);
149void au1x00_emac_rx_daemon (void *arg);
150void au1x00_emac_sendpacket (struct ifnet *ifp, struct mbuf *m);
151void au1x00_emac_stats (au1x00_emac_softc_t *sc);
152static int au1x00_emac_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data);
153static void mii_write(au1x00_emac_softc_t *sc, uint8_t reg, uint16_t val);
154static void mii_read(au1x00_emac_softc_t *sc, uint8_t reg, uint16_t *val);
155static void mii_init(au1x00_emac_softc_t *sc);
156
157static void mii_write(au1x00_emac_softc_t *sc, uint8_t reg, uint16_t val)
158{
159    /* wait for the interface to get unbusy */
160    while (AU1X00_MAC_MIICTRL(sc->ctrl_regs) & AU1X00_MAC_MIICTRL_MB) {
161        continue;
162    }
163
164    /* write to address 0 - we only support address 0 */
165    AU1X00_MAC_MIIDATA(sc->ctrl_regs) = val;
166    AU1X00_MAC_MIICTRL(sc->ctrl_regs) = (((reg & 0x1f) << 6) |
167                                         AU1X00_MAC_MIICTRL_MW);
168    au_sync();
169
170    /* wait for it to complete */
171    while (AU1X00_MAC_MIICTRL(sc->ctrl_regs) & AU1X00_MAC_MIICTRL_MB) {
172        continue;
173    }
174}
175
176static void mii_read(au1x00_emac_softc_t *sc, uint8_t reg, uint16_t *val)
177{
178    /* wait for the interface to get unbusy */
179    while (AU1X00_MAC_MIICTRL(sc->ctrl_regs) & AU1X00_MAC_MIICTRL_MB) {
180        continue;
181    }
182
183    /* write to address 0 - we only support address 0 */
184    AU1X00_MAC_MIICTRL(sc->ctrl_regs) = ((reg & 0x1f) << 6);
185    au_sync();
186
187    /* wait for it to complete */
188    while (AU1X00_MAC_MIICTRL(sc->ctrl_regs) & AU1X00_MAC_MIICTRL_MB) {
189        continue;
190    }
191    *val = AU1X00_MAC_MIIDATA(sc->ctrl_regs);
192}
193
194static void mii_init(au1x00_emac_softc_t *sc)
195{
196    uint16_t data;
197
198    mii_write(sc, 0, 0x8000);     /* reset */
199    do {
200        mii_read(sc, 0, &data);
201    } while (data & 0x8000);
202
203    mii_write(sc, 0, 0x3200);     /* reset autonegotiation */
204    mii_write(sc, 17, 0xffc0);    /* setup LEDs */
205
206}
207
208
209
210int rtems_au1x00_emac_attach (
211    struct rtems_bsdnet_ifconfig *config,
212    int attaching
213    )
214{
215    struct ifnet *ifp;
216    int mtu;
217    int unitnumber;
218    char *unitname;
219    static au1x00_emac_softc_t *sc;
220
221    /*
222     * Parse driver name
223     */
224    if ((unitnumber = rtems_bsdnet_parse_driver_name (config, &unitname)) < 0)
225        return 0;
226
227    /*
228     * Is driver free?
229     */
230    if (unitnumber > NUM_IFACES) {
231        printf ("Bad AU1X00 EMAC unit number.\n");
232        return 0;
233    }
234
235    sc = &softc[unitnumber];
236
237    ifp = &sc->arpcom.ac_if;
238    if (ifp->if_softc != NULL) {
239        printf ("Driver already in use.\n");
240        return 0;
241    }
242
243    /*
244     *  zero out the control structure
245     */
246
247    memset((void *)sc, 0, sizeof(*sc));
248
249    sc->unitnumber = unitnumber;
250    sc->int_ctrlr = AU1X00_IC0_ADDR;
251
252    if (unitnumber == 0) {
253        sc->ctrl_regs = AU1100_MAC0_ADDR;
254        sc->en_reg = (void *)(AU1100_MACEN_ADDR + 0);
255
256        sc->tx_dma = (void *)(AU1X00_MACDMA0_ADDR + 0x000);
257        sc->rx_dma = (void *)(AU1X00_MACDMA0_ADDR + 0x100);
258        sc->int_mask = AU1X00_IC_IRQ_MAC0;
259    } else {
260        printk("Unknown network device: %d\n", unitnumber);
261        return 0;
262    }
263
264    /* If the ethernet controller is already set up, read the MAC address */
265    if ((*sc->en_reg & 0x33) == 0x33) {
266        sc->arpcom.ac_enaddr[5] = ((AU1X00_MAC_ADDRHIGH(sc->ctrl_regs) >> 8) &
267                                   0xff);
268        sc->arpcom.ac_enaddr[4] = ((AU1X00_MAC_ADDRHIGH(sc->ctrl_regs) >> 0) &
269                                   0xff);
270        sc->arpcom.ac_enaddr[3] = ((AU1X00_MAC_ADDRLOW(sc->ctrl_regs) >> 24) &
271                                   0xff);
272        sc->arpcom.ac_enaddr[2] = ((AU1X00_MAC_ADDRLOW(sc->ctrl_regs) >> 16) &
273                                   0xff);
274        sc->arpcom.ac_enaddr[1] = ((AU1X00_MAC_ADDRLOW(sc->ctrl_regs) >> 8) &
275                                   0xff);
276        sc->arpcom.ac_enaddr[0] = ((AU1X00_MAC_ADDRLOW(sc->ctrl_regs) >> 0) &
277                                   0xff);
278    } else {
279        /* It's not set up yet, so we set a MAC address */
280        sc->arpcom.ac_enaddr[5] = 0x05;
281        sc->arpcom.ac_enaddr[4] = 0xc0;
282        sc->arpcom.ac_enaddr[3] = 0x50;
283        sc->arpcom.ac_enaddr[2] = 0x31;
284        sc->arpcom.ac_enaddr[1] = 0x23;
285        sc->arpcom.ac_enaddr[0] = 0x00;
286    }
287
288
289    if (config->mtu) {
290        mtu = config->mtu;
291    } else {
292        mtu = ETHERMTU;
293    }
294
295    sc->acceptBroadcast = !config->ignore_broadcast;
296
297    /*
298     * Set up network interface values
299     */
300    ifp->if_softc = sc;
301    ifp->if_unit = unitnumber;
302    ifp->if_name = unitname;
303    ifp->if_mtu = mtu;
304    ifp->if_init = au1x00_emac_init;
305    ifp->if_ioctl = au1x00_emac_ioctl;
306    ifp->if_start = au1x00_emac_start;
307    ifp->if_output = ether_output;
308    ifp->if_flags = IFF_BROADCAST;
309    if (ifp->if_snd.ifq_maxlen == 0) {
310        ifp->if_snd.ifq_maxlen = ifqmaxlen;
311    }
312
313    /*
314     * Attach the interface
315     */
316    if_attach (ifp);
317    ether_ifattach (ifp);
318    return 1;
319}
320
321void au1x00_emac_init(void *arg)
322{
323    au1x00_emac_softc_t     *sc = arg;
324    struct ifnet *ifp = &sc->arpcom.ac_if;
325
326    /*
327     *This is for stuff that only gets done once (au1x00_emac_init()
328     * gets called multiple times
329     */
330    if (sc->tx_daemon_tid == 0)
331    {
332        /* Set up EMAC hardware */
333        au1x00_emac_init_hw(sc);
334
335
336        /* install the interrupt handler */
337        if (sc->unitnumber == 0) {
338            rtems_interrupt_handler_install(
339              AU1X00_IRQ_MAC0,
340              "NIC0",
341              0,
342              (rtems_interrupt_handler)au1x00_emac_isr,
343              NULL
344            );
345        } else {
346            rtems_interrupt_handler_install(
347              AU1X00_IRQ_MAC1,
348              "NIC1",
349              0,
350              (rtems_interrupt_handler)au1x00_emac_isr,
351              NULL
352            );
353        }
354        AU1X00_IC_MASKCLR(sc->int_ctrlr) = sc->int_mask;
355        au_sync();
356
357        /* set src bit */
358        AU1X00_IC_SRCSET(sc->int_ctrlr) = sc->int_mask;
359
360        /* high level */
361        AU1X00_IC_CFG0SET(sc->int_ctrlr) = sc->int_mask;
362        AU1X00_IC_CFG1CLR(sc->int_ctrlr) = sc->int_mask;
363        AU1X00_IC_CFG2SET(sc->int_ctrlr) = sc->int_mask;
364
365        /* assign to request 0 - negative logic */
366        AU1X00_IC_ASSIGNSET(sc->int_ctrlr) = sc->int_mask;
367        au_sync();
368
369        /* Start driver tasks */
370        sc->tx_daemon_tid = rtems_bsdnet_newproc("ENTx",
371                                                 4096,
372                                                 au1x00_emac_tx_daemon,
373                                                 sc);
374
375        sc->rx_daemon_tid = rtems_bsdnet_newproc("ENRx",
376                                                 4096,
377                                                 au1x00_emac_rx_daemon,
378                                                 sc);
379
380
381    }
382    /* EMAC doesn't support promiscuous, so ignore requests */
383    if (ifp->if_flags & IFF_PROMISC)
384        printf ("Warning - AU1X00 EMAC doesn't support Promiscuous Mode!\n");
385
386    /*
387     * Tell the world that we're running.
388     */
389    ifp->if_flags |= IFF_RUNNING;
390
391    /*
392     * start tx, rx
393     */
394    AU1X00_MAC_CONTROL(sc->ctrl_regs) |= (AU1X00_MAC_CTRL_TE |
395                                             AU1X00_MAC_CTRL_RE);
396    au_sync();
397
398
399} /* au1x00_emac_init() */
400
401void  au1x00_emac_init_hw(au1x00_emac_softc_t *sc)
402{
403    int i;
404    struct mbuf *m;
405    struct ifnet *ifp = &sc->arpcom.ac_if;
406
407    /* reset the MAC */
408    *sc->en_reg = 0x40;
409    au_sync();
410    for (i = 0; i < 10000; i++) {
411        continue;
412    }
413
414/*    *sc->en_reg = AU1X00_MAC_EN_CE; */
415    *sc->en_reg = 41;
416    au_sync();
417    for (i = 0; i < 10000; i++) {
418        continue;
419    }
420
421/*
422    *sc->en_reg = (AU1X00_MAC_EN_CE |
423                   AU1X00_MAC_EN_E2 |
424                   AU1X00_MAC_EN_E1 |
425                   AU1X00_MAC_EN_E0);
426*/
427    *sc->en_reg = 0x33;
428    au_sync();
429    mii_init(sc);
430
431    /* set the mac address */
432    AU1X00_MAC_ADDRHIGH(sc->ctrl_regs) = ((sc->arpcom.ac_enaddr[5] << 8) |
433                                          (sc->arpcom.ac_enaddr[4] << 0));
434    AU1X00_MAC_ADDRLOW(sc->ctrl_regs) = ((sc->arpcom.ac_enaddr[3] << 24) |
435                                         (sc->arpcom.ac_enaddr[2] << 16) |
436                                         (sc->arpcom.ac_enaddr[1] << 8) |
437                                         (sc->arpcom.ac_enaddr[0] << 0));
438
439
440    /* get the MAC address from the chip */
441    sc->arpcom.ac_enaddr[5] = (AU1X00_MAC_ADDRHIGH(sc->ctrl_regs) >> 8) & 0xff;
442    sc->arpcom.ac_enaddr[4] = (AU1X00_MAC_ADDRHIGH(sc->ctrl_regs) >> 0) & 0xff;
443    sc->arpcom.ac_enaddr[3] = (AU1X00_MAC_ADDRLOW(sc->ctrl_regs) >> 24) & 0xff;
444    sc->arpcom.ac_enaddr[2] = (AU1X00_MAC_ADDRLOW(sc->ctrl_regs) >> 16) & 0xff;
445    sc->arpcom.ac_enaddr[1] = (AU1X00_MAC_ADDRLOW(sc->ctrl_regs) >> 8) & 0xff;
446    sc->arpcom.ac_enaddr[0] = (AU1X00_MAC_ADDRLOW(sc->ctrl_regs) >> 0) & 0xff;
447
448    printk("Setting mac_control to 0x%x\n",
449           (AU1X00_MAC_CTRL_F |
450            AU1X00_MAC_CTRL_PM |
451            AU1X00_MAC_CTRL_RA |
452            AU1X00_MAC_CTRL_DO |
453            AU1X00_MAC_CTRL_EM));
454
455    AU1X00_MAC_CONTROL(sc->ctrl_regs) = (AU1X00_MAC_CTRL_F |   /* full duplex */
456                                         AU1X00_MAC_CTRL_PM |  /* pass mcast */
457                                         AU1X00_MAC_CTRL_RA |  /* recv all */
458                                         AU1X00_MAC_CTRL_DO |  /* disable own */
459                                         AU1X00_MAC_CTRL_EM);  /* Big endian */
460    au_sync();
461    printk("mac_control was set to 0x%x\n", AU1X00_MAC_CONTROL(sc->ctrl_regs));
462    printk("mac_control addr is 0x%x\n", &AU1X00_MAC_CONTROL(sc->ctrl_regs));
463
464    /* initialize our receive buffer descriptors */
465    for (i = 0; i < NUM_RX_DMA_BUFS; i++) {
466        MGETHDR(m, M_WAIT, MT_DATA);
467        MCLGET(m, M_WAIT);
468
469        m->m_pkthdr.rcvif = ifp;
470        m->m_nextpkt = 0;
471
472        /*
473         * The receive buffer must be aligned with a cache line
474         * boundary.
475         */
476        if (mtod(m, uint32_t) & 0x1f) {
477          uint32_t *p = mtod(m, uint32_t *);
478          *p = (mtod(m, uint32_t) + 0x1f) & 0x1f;
479        }
480        sc->rx_dma[i].addr = (mtod(m, uint32_t) & ~0xe0000000);
481        sc->rx_mbuf[i] = m;
482    }
483
484    /* Initialize transmit buffer descriptors */
485    for (i = 0; i < NUM_TX_DMA_BUFS; i++) {
486        sc->tx_dma[i].addr = 0;
487    }
488
489    /* initialize the transmit buffers */
490    sc->tx_buf[0] = (void *)((((int)&tx_buf_base[0]) + 0x1f) & ~0x1f);
491    sc->tx_buf[1] = (void *)(((int)sc->tx_buf[0]) + TX_BUF_SIZE);
492    sc->tx_buf[2] = (void *)(((int)sc->tx_buf[1]) + TX_BUF_SIZE);
493    sc->tx_buf[3] = (void *)(((int)sc->tx_buf[2]) + TX_BUF_SIZE);
494
495    sc->rx_head = (sc->rx_dma[0].addr >> 2) & 0x3;
496    sc->rx_tail = (sc->rx_dma[0].addr >> 2) & 0x3;
497    sc->tx_head = (sc->tx_dma[0].addr >> 2) & 0x3;
498    sc->tx_tail = (sc->tx_dma[0].addr >> 2) & 0x3;
499
500    for (i = 0; i < NUM_RX_DMA_BUFS; i++) {
501        sc->rx_dma[i].addr |= AU1X00_MAC_DMA_RXADDR_EN;
502    }
503
504} /* au1x00_emac_init_hw() */
505
506void au1x00_emac_start(struct ifnet *ifp)
507{
508    au1x00_emac_softc_t *sc = ifp->if_softc;
509
510    rtems_bsdnet_event_send(sc->tx_daemon_tid, START_TX_EVENT);
511    ifp->if_flags |= IFF_OACTIVE;
512}
513
514void au1x00_emac_stop (au1x00_emac_softc_t *sc)
515{
516    struct ifnet *ifp = &sc->arpcom.ac_if;
517
518    ifp->if_flags &= ~IFF_RUNNING;
519
520    /*
521     * Stop the transmitter and receiver.
522     */
523
524    /* Disable TX/RX  */
525    AU1X00_MAC_CONTROL(sc->ctrl_regs) &= ~(AU1X00_MAC_CTRL_TE |
526                                      AU1X00_MAC_CTRL_RE);
527    au_sync();
528}
529
530/*
531 * Driver tx daemon
532 */
533void au1x00_emac_tx_daemon (void *arg)
534{
535    au1x00_emac_softc_t *sc = (au1x00_emac_softc_t *)arg;
536    struct ifnet *ifp = &sc->arpcom.ac_if;
537    struct mbuf *m;
538    rtems_event_set events;
539    uint32_t ic_base;     /* interrupt controller */
540
541    ic_base = AU1X00_IC0_ADDR;
542
543    /* turn on interrupt, then wait for one */
544    if (sc->unitnumber == 0) {
545        AU1X00_IC_MASKSET(ic_base) = AU1X00_IC_IRQ_MAC0;
546    } else {
547        AU1X00_IC_MASKSET(ic_base) = AU1X00_IC_IRQ_MAC1;
548    }
549    au_sync();
550
551    for (;;)
552    {
553        rtems_bsdnet_event_receive(
554            START_TX_EVENT,
555            RTEMS_EVENT_ANY | RTEMS_WAIT,
556            RTEMS_NO_TIMEOUT,
557            &events);
558
559        /* Send packets till queue is empty */
560        for (;;)
561        {
562            /* Get the next mbuf chain to transmit. */
563            IF_DEQUEUE(&ifp->if_snd, m);
564            if (!m)
565                break;
566
567            sc->tx_pkts++;
568            au1x00_emac_sendpacket (ifp, m);
569        }
570        ifp->if_flags &= ~IFF_OACTIVE;
571    }
572}
573
574/*
575 * Driver rx daemon
576 */
577void au1x00_emac_rx_daemon (void *arg)
578{
579    au1x00_emac_softc_t *sc = (au1x00_emac_softc_t *)arg;
580    struct ifnet *ifp = &sc->arpcom.ac_if;
581    struct mbuf *m;
582    struct ether_header *eh;
583    rtems_event_set events;
584    uint32_t status;
585
586    while (1) {
587        rtems_bsdnet_event_receive(
588            START_RX_EVENT,
589            RTEMS_EVENT_ANY | RTEMS_WAIT,
590            RTEMS_NO_TIMEOUT,
591            &events);
592
593        /* while there are packets to receive */
594
595        while (!(sc->rx_dma[sc->rx_head].addr & (AU1X00_MAC_DMA_RXADDR_DN |
596                                                AU1X00_MAC_DMA_RXADDR_EN))) {
597            status = sc->rx_dma[sc->rx_head].stat;
598            if (status & AU1X00_MAC_DMA_RXSTAT_MI) {
599                sc->rx_missed++;
600            }
601            if (status & AU1X00_MAC_DMA_RXSTAT_BF) {
602                sc->rx_bcast++;
603            }
604            if (status & AU1X00_MAC_DMA_RXSTAT_MF) {
605                sc->rx_mcast++;
606            }
607            if (status & AU1X00_MAC_DMA_RXSTAT_UC) {
608                sc->rx_unsupp++;
609            }
610            if (status & AU1X00_MAC_DMA_RXSTAT_CF) {
611                sc->rx_ctrl++;
612            }
613            if (status & AU1X00_MAC_DMA_RXSTAT_LE) {
614                sc->rx_len_err++;
615            }
616            if (status & AU1X00_MAC_DMA_RXSTAT_CR) {
617                sc->rx_crc_err++;
618            }
619            if (status & AU1X00_MAC_DMA_RXSTAT_DB) {
620                sc->rx_dribble++;
621            }
622            if (status & AU1X00_MAC_DMA_RXSTAT_ME) {
623                sc->rx_mii_err++;
624            }
625            if (status & AU1X00_MAC_DMA_RXSTAT_CS) {
626                sc->rx_collision++;
627            }
628            if (status & AU1X00_MAC_DMA_RXSTAT_FL) {
629                sc->rx_too_long++;
630            }
631            if (status & AU1X00_MAC_DMA_RXSTAT_RF) {
632                sc->rx_runt++;
633            }
634            if (status & AU1X00_MAC_DMA_RXSTAT_WT) {
635                sc->rx_watchdog++;
636            }
637
638            /* If no errrors, accept packet */
639            if ((status & (AU1X00_MAC_DMA_RXSTAT_CR |
640                           AU1X00_MAC_DMA_RXSTAT_DB |
641                           AU1X00_MAC_DMA_RXSTAT_RF)) == 0) {
642
643                sc->rx_pkts++;
644
645                /* find the start of the mbuf */
646                m = sc->rx_mbuf[sc->rx_head];
647
648                /* set the length of the mbuf */
649                m->m_len = AU1X00_MAC_DMA_RXSTAT_LEN(sc->rx_dma[sc->rx_head].stat);
650                m->m_len -= 4; /* remove ethernet CRC */
651
652                m->m_pkthdr.len = m->m_len;
653
654                /* strip off the ethernet header from the mbuf */
655                /* but save the pointer to it */
656                eh = mtod (m, struct ether_header *);
657                m->m_data += sizeof(struct ether_header);
658
659                /* give the received packet to the stack */
660                ether_input(ifp, eh, m);
661                /* get a new buf and make it ready for the MAC */
662                MGETHDR(m, M_WAIT, MT_DATA);
663                MCLGET(m, M_WAIT);
664
665                m->m_pkthdr.rcvif = ifp;
666                m->m_nextpkt = 0;
667
668                /*
669                 * The receive buffer must be aligned with a cache line
670                 * boundary.
671                 */
672                {
673                  uint32_t *p = mtod(m, uint32_t *);
674                  *p = (mtod(m, uint32_t) + 0x1f) & ~0x1f;
675                }
676
677            } else {
678                sc->rx_dropped++;
679
680                /* find the mbuf so we can reuse it*/
681                m = sc->rx_mbuf[sc->rx_head];
682            }
683
684            /* set up the receive dma to use the mbuf's cluster */
685            sc->rx_dma[sc->rx_head].addr = (mtod(m, uint32_t) & ~0xe0000000);
686            au_sync();
687            sc->rx_mbuf[sc->rx_head] = m;
688
689            sc->rx_dma[sc->rx_head].addr |= AU1X00_MAC_DMA_RXADDR_EN;
690            au_sync();
691
692
693            /* increment the buffer index */
694            sc->rx_head++;
695            if (sc->rx_head >= NUM_RX_DMA_BUFS) {
696                sc->rx_head = 0;
697            }
698        }
699    }
700}
701
702/* Send packet */
703void au1x00_emac_sendpacket (struct ifnet *ifp, struct mbuf *m)
704{
705    struct mbuf *l = NULL;
706    unsigned int pkt_offset = 0;
707    au1x00_emac_softc_t *sc = (au1x00_emac_softc_t *)ifp->if_softc;
708    uint32_t txbuf;
709
710    /* Wait for EMAC Transmit Queue to become available. */
711    while((sc->tx_dma[sc->tx_head].addr & (AU1X00_MAC_DMA_TXADDR_EN ||
712                                           AU1X00_MAC_DMA_TXADDR_DN)) != 0) {
713        continue;
714    }
715
716    /* copy the mbuf chain into the transmit buffer */
717    l = m;
718
719    txbuf = (uint32_t)sc->tx_buf[sc->tx_head];
720    while (l != NULL)
721    {
722
723        memcpy(((char *)txbuf + pkt_offset), /* offset into pkt for mbuf */
724               (char *)mtod(l, void *),      /* cast to void */
725               l->m_len);                    /* length of this mbuf */
726
727        pkt_offset += l->m_len;              /* update offset */
728        l = l->m_next;                       /* get next mbuf, if any */
729    }
730
731    /* Pad if necessary */
732    if (pkt_offset < 60) {
733        memset((char *)(txbuf + pkt_offset), 0, (60 - pkt_offset));
734        pkt_offset = 60;
735    }
736
737    /* send it off */
738    sc->tx_dma[sc->tx_head].stat = 0;
739    sc->tx_dma[sc->tx_head].len = pkt_offset;
740    sc->tx_dma[sc->tx_head].addr = ((txbuf & ~0xe0000000) |
741                                    AU1X00_MAC_DMA_TXADDR_EN);
742    au_sync();
743
744
745    /*
746     *Without this delay, some outgoing packets never
747     * make it out the device. Nothing in the documentation
748     * explains this.
749     */
750    for (wait_count = 0; wait_count < 5000; wait_count++){
751        continue;
752    }
753
754    /* free the mbuf chain we just copied */
755    m_freem(m);
756
757    sc->tx_head++;
758    if (sc->tx_head >= NUM_TX_DMA_BUFS) {
759        sc->tx_head = 0;
760    }
761
762} /* au1x00_emac_sendpacket () */
763
764
765
766/* Show interface statistics */
767void au1x00_emac_stats (au1x00_emac_softc_t *sc)
768{
769    printf("Interrupts:%-8lu", sc->interrupts);
770    printf("    RX Interrupts:%-8lu", sc->rx_interrupts);
771    printf(" TX Interrupts:%-8lu\n", sc->tx_interrupts);
772    printf("RX Packets:%-8lu", sc->rx_pkts);
773    printf("    RX Control:%-8lu", sc->rx_ctrl);
774    printf("    RX broadcast:%-8lu\n", sc->rx_bcast);
775    printf("RX Mcast:%-8lu", sc->rx_mcast);
776    printf("      RX missed:%-8lu", sc->rx_missed);
777    printf("     RX Unsupported ctrl:%-8lu\n", sc->rx_unsupp);
778    printf("RX Len err:%-8lu", sc->rx_len_err);
779    printf("    RX CRC err:%-8lu", sc->rx_crc_err);
780    printf("    RX dribble:%-8lu\n", sc->rx_dribble);
781    printf("RX MII err:%-8lu", sc->rx_mii_err);
782    printf("    RX collision:%-8lu", sc->rx_collision);
783    printf("  RX too long:%-8lu\n", sc->rx_too_long);
784    printf("RX runt:%-8lu", sc->rx_runt);
785    printf("       RX watchdog:%-8lu", sc->rx_watchdog);
786    printf("   RX dropped:%-8lu\n", sc->rx_dropped);
787
788    printf("TX Packets:%-8lu", sc->tx_pkts);
789    printf("    TX Deferred:%-8lu", sc->tx_deferred);
790    printf("   TX Underrun:%-8lu\n", sc->tx_underrun);
791    printf("TX Aborted:%-8lu\n", sc->tx_aborted);
792
793}
794
795
796/*  Driver ioctl handler */
797static int
798au1x00_emac_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data)
799{
800    au1x00_emac_softc_t *sc = ifp->if_softc;
801    int error = 0;
802
803    switch (command) {
804    case SIOCGIFADDR:
805    case SIOCSIFADDR:
806        ether_ioctl (ifp, command, data);
807        break;
808
809    case SIOCSIFFLAGS:
810        switch (ifp->if_flags & (IFF_UP | IFF_RUNNING))
811        {
812        case IFF_RUNNING:
813            au1x00_emac_stop (sc);
814            break;
815
816        case IFF_UP:
817            au1x00_emac_init (sc);
818            break;
819
820        case IFF_UP | IFF_RUNNING:
821            au1x00_emac_stop (sc);
822            au1x00_emac_init (sc);
823            break;
824
825        default:
826            break;
827        } /* switch (if_flags) */
828        break;
829
830    case SIO_RTEMS_SHOW_STATS:
831        au1x00_emac_stats (sc);
832        break;
833
834        /*
835         * FIXME: All sorts of multicast commands need to be added here!
836         */
837    default:
838        error = EINVAL;
839        break;
840    } /* switch (command) */
841    return error;
842}
843
844/* interrupt handler */
845rtems_isr au1x00_emac_isr (rtems_vector_number v)
846{
847    volatile au1x00_emac_softc_t *sc;
848    int tx_flag = 0;
849    int rx_flag = 0;
850
851    sc = &softc[0];
852    if (v != AU1X00_IRQ_MAC0) {
853      assert(v == AU1X00_IRQ_MAC0);
854    }
855
856    sc->interrupts++;
857
858    /*
859     * Since there's no easy way to find out the source of the
860     * interrupt, we have to look at the tx and rx dma buffers
861     */
862    /* receive interrupt */
863    while(sc->rx_dma[sc->rx_tail].addr & AU1X00_MAC_DMA_RXADDR_DN) {
864        rx_flag = 1;
865        sc->rx_interrupts++;
866        sc->rx_dma[sc->rx_tail].addr &= ~AU1X00_MAC_DMA_RXADDR_DN;
867        au_sync();
868
869        sc->rx_tail++;
870        if (sc->rx_tail >= NUM_RX_DMA_BUFS) {
871            sc->rx_tail = 0;
872        }
873    }
874    if (rx_flag != 0) {
875        rtems_bsdnet_event_send(sc->rx_daemon_tid, START_RX_EVENT);
876    }
877
878    /* transmit interrupt */
879    while (sc->tx_dma[sc->tx_tail].addr & AU1X00_MAC_DMA_TXADDR_DN) {
880        uint32_t status;
881        tx_flag = 1;
882        sc->tx_interrupts++;
883
884        status = sc->tx_dma[sc->tx_tail].stat;
885        if (status & AU1X00_MAC_DMA_TXSTAT_DF) {
886            sc->tx_deferred++;
887        }
888        if (status & AU1X00_MAC_DMA_TXSTAT_UR) {
889            sc->tx_underrun++;
890        }
891        if (status & AU1X00_MAC_DMA_TXSTAT_FA) {
892            sc->tx_aborted++;
893        }
894
895        sc->tx_dma[sc->tx_tail].addr = 0;
896        au_sync();
897
898        sc->tx_tail++;
899        if (sc->tx_tail >= NUM_TX_DMA_BUFS) {
900            sc->tx_tail = 0;
901        }
902    }
903    if (tx_flag != 0) {
904        rtems_bsdnet_event_send(sc->tx_daemon_tid, START_TX_EVENT);
905    }
906}
907
Note: See TracBrowser for help on using the repository browser.