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

4.104.115
Last change on this file since 20b9e9d9 was 20b9e9d9, checked in by Ralf Corsepius <ralf.corsepius@…>, on 12/11/09 at 07:03:06

2009-12-11 Ralf Corsépius <ralf.corsepius@…>

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