source: rtems/c/src/lib/libbsp/arm/csb337/network/network.c @ e73f8a17

4.104.115
Last change on this file since e73f8a17 was e73f8a17, checked in by Joel Sherrill <joel.sherrill@…>, on 06/11/09 at 20:03:14

2009-06-11 Joel Sherrill <joel.sherrill@…>

  • network/network.c: Attempt to support csb637 PHY.
  • Property mode set to 100644
File size: 24.5 KB
Line 
1/*
2 *  AT91RM9200 ethernet driver
3 *
4 *  Copyright (c) 2003 by Cogent Computer Systems
5 *  Written by Mike Kelly <mike@cogcomp.com>
6 *         and Jay Monkman <jtm@lopingdog.com>
7 *
8 *  $Id$
9 */
10
11#include <rtems.h>
12#include <rtems/rtems_bsdnet.h>
13#include <at91rm9200.h>
14#include <at91rm9200_emac.h>
15#include <at91rm9200_gpio.h>
16#include <at91rm9200_pmc.h>
17
18#include <stdio.h>
19#include <string.h>
20
21#include <errno.h>
22#include <rtems/error.h>
23
24#include <sys/param.h>
25#include <sys/mbuf.h>
26#include <sys/socket.h>
27#include <sys/sockio.h>
28
29#include <net/if.h>
30
31#include <netinet/in.h>
32#include <netinet/if_ether.h>
33
34#include <irq.h>
35#include <bspopts.h>
36
37#if csb637
38  /* Bit defines for the PHY Status Register #1 (phy address 0x01) */
39  /* 1 = PHY able to perform 100BASE-T4 */
40  #define PHY_STAT_100BASE_T4     BIT15
41  /* 1 = PHY able to perform full-duplex 100BASE-X */
42  #define PHY_STAT_100BASE_X_FDX  BIT14
43  /* 1 = PHY able to perform half-duplex 100BASE-X */
44  #define PHY_STAT_100BASE_X_HDX  BIT13
45  /* 1 = PHY able to operate at 10 Mbps in full-duplex mode */
46  #define PHY_STAT_10BASE_FDX     BIT12
47  /* 1 = PHY able to operate at 10 Mbps in half-duplex mode */
48  #define PHY_STAT_10BASE_HDX     BIT11
49  /* 1 = PHY will accept management frames with preamble suppressed */
50  #define PHY_STAT_MF_PREAMBLE    BIT6
51  /* 1 = Auto-negotiation complete */
52  #define PHY_STAT_AUTO_NEG_DONE  BIT5
53  /* 1 = Remote fault condition detected */
54  #define PHY_STAT_REM_FLT        BIT4
55  /* 1 = PHY is able to perform Auto-Negotiation */
56  #define PHY_STAT_AUTO_NEG_ABLE  BIT3
57  /* 1 = Link is up */
58  #define PHY_STAT_LINK_UP        BIT2
59  /* 1 = Jabber condition detected */
60  #define PHY_STAT_JABBER         BIT1
61  /* 1 = Extended register capabilities */
62  #define PHY_STAT_EXT_REG        BIT0
63
64  /* Bit defines for the Auxillary Mode 3 register */
65  #define PHY_AUX_MODE2_TRAFFIC_LED   BIT6
66#endif
67
68  /* interrupt stuff */
69  #define EMAC_INT_PRIORITY       0       /* lowest priority */
70
71  /*  RTEMS event used by interrupt handler to start receive daemon. */
72  #define START_RECEIVE_EVENT  RTEMS_EVENT_1
73
74  /* RTEMS event used to start transmit daemon. */
75  #define START_TRANSMIT_EVENT    RTEMS_EVENT_2
76
77rtems_isr at91rm9200_emac_isr(rtems_vector_number vector);
78static void at91rm9200_emac_isr_on(const rtems_irq_connect_data *unused);
79static void at91rm9200_emac_isr_off(const rtems_irq_connect_data *unused);
80static int at91rm9200_emac_isr_is_on(const rtems_irq_connect_data *irq);
81
82/* Replace the first value with the clock's interrupt name. */
83rtems_irq_connect_data at91rm9200_emac_isr_data = {
84    AT91RM9200_INT_EMAC,
85    (rtems_irq_hdl)at91rm9200_emac_isr,
86    at91rm9200_emac_isr_on,
87    at91rm9200_emac_isr_off,
88    at91rm9200_emac_isr_is_on,
89    3,    /* unused for ARM */
90    0 };  /* unused for ARM */
91
92
93/* use the values defined in linkcmds for our use of SRAM */
94extern void * at91rm9200_emac_rxbuf_hdrs;
95extern void * at91rm9200_emac_txbuf;
96extern void * at91rm9200_emac_rxbufs;
97
98/* Set up EMAC hardware */
99/* Number of Receive and Transmit Buffers and Buffer Descriptors */
100#define NUM_RXBDS 8
101#define NUM_TXBDS 1
102#define RX_BUFFER_SIZE 0x600
103
104/* use internal SRAM for buffers and descriptors
105 * also insure that the receive descriptors
106 * start on a 64byte boundary
107 * Receive Buffer Descriptor Header
108 */
109
110typedef struct
111{
112    unsigned long address;
113    unsigned long status;
114} RXBUF_HDR;
115
116RXBUF_HDR       *rxbuf_hdrs;
117unsigned char   *txbuf;
118unsigned char   *rxbuf;
119
120int delay_cnt;
121
122/*
123 * Hardware-specific storage
124 */
125typedef struct
126{
127    /*
128     * Connection to networking code
129     * This entry *must* be the first in the sonic_softc structure.
130     */
131    struct arpcom                    arpcom;
132
133    /*
134     * Interrupt vector
135     */
136    rtems_vector_number             vector;
137
138    /*
139     *  Indicates configuration
140     */
141    int                             acceptBroadcast;
142
143    /*
144     * Task waiting for interrupts
145     */
146    rtems_id                        rxDaemonTid;
147    rtems_id                        txDaemonTid;
148
149    /*
150     * current receive header
151     */
152    int                rx_buf_idx;
153
154
155
156    /*
157     * Statistics
158     */
159    unsigned long                   Interrupts;
160    unsigned long                   rxInterrupts;
161    unsigned long                   rxMissed;
162    unsigned long                   rxGiant;
163    unsigned long                   rxNonOctet;
164    unsigned long                   rxBadCRC;
165    unsigned long                   rxCollision;
166
167    unsigned long                   txInterrupts;
168    unsigned long                   txSingleCollision;
169    unsigned long                   txMultipleCollision;
170    unsigned long                   txCollision;
171    unsigned long                   txDeferred;
172    unsigned long                   txUnderrun;
173    unsigned long                   txLateCollision;
174    unsigned long                   txExcessiveCollision;
175    unsigned long                   txExcessiveDeferral;
176    unsigned long                   txLostCarrier;
177    unsigned long                   txRawWait;
178} at91rm9200_emac_softc_t;
179
180static at91rm9200_emac_softc_t softc;
181
182
183/* The AT91RM9200 ethernet fifos are very undersized. Therefore
184 * we use the internal SRAM to hold 4 receive packets and one
185 * transmit packet.  Note that the AT91RM9200 can only queue
186 * one transmit packet at a time.
187 */
188
189/* function prototypes */
190int rtems_at91rm9200_emac_attach (struct rtems_bsdnet_ifconfig *config,
191                                  void *chip);
192void at91rm9200_emac_init(void *arg);
193void at91rm9200_emac_init_hw(at91rm9200_emac_softc_t *sc);
194void at91rm9200_emac_start(struct ifnet *ifp);
195void at91rm9200_emac_stop (at91rm9200_emac_softc_t *sc);
196void at91rm9200_emac_txDaemon (void *arg);
197void at91rm9200_emac_sendpacket (struct ifnet *ifp, struct mbuf *m);
198void at91rm9200_emac_rxDaemon(void *arg);
199void at91rm9200_emac_stats (at91rm9200_emac_softc_t *sc);
200static int at91rm9200_emac_ioctl (struct ifnet *ifp,
201                                  ioctl_command_t command,
202                                  caddr_t data);
203
204
205/*
206 * phyread(): Read the PHY
207 */
208uint32_t phyread(uint8_t reg)
209{
210  EMAC_REG(EMAC_MAN) = (0x01 << 30  /* Start of Frame Delimiter */
211            | 0x02 << 28            /* Operation, 0x01 = Write, 0x02 = Read */
212            | 0x00 << 23            /* Phy Number, 0 as we only have one */
213            | reg << 18             /* Phy Register */
214            | 0x02 << 16);          /* must be 0x02 for turn around field */
215
216  /* wait for phy read to complete (was udelay(5000)) */
217  rtems_task_wake_after(1);
218
219  #if EMAC_DBG
220    printk(
221      "EMAC: Phy 0, Reg %d, Read 0x%04lx.\n",
222       reg,
223       (EMAC_REG(EMAC_MAN) & 0xffff)
224    );
225  #endif
226
227  return EMAC_REG(EMAC_MAN) & 0xffff;
228}
229
230/*
231 * phywrite(): Write the PHY
232 */
233void phywrite(uint8_t reg, uint16_t data)
234{
235  EMAC_REG(EMAC_MAN) = (0x01 << 30 /* Start of Frame Delimiter */
236             | 0x01 << 28          /* Operation, 0x01 = Write, 0x02 = Read */
237             | 0x00 << 23          /* Phy Number, BCM5221 is address 0 */
238             | reg << 18           /* Phy Register */
239             | 0x02 << 16          /* must be 0x02 for turn around field */
240             | data);
241  #if EMAC_DBG
242    printf("EMAC: Phy 0, Reg %d, Write 0x%04x.\n", reg, data);
243  #endif
244
245  /* wait for phy write to complete (was udelay(5000)) */
246  rtems_task_wake_after(1);
247}
248
249
250int rtems_at91rm9200_emac_attach (
251    struct rtems_bsdnet_ifconfig *config,
252    void *chip  /* only one ethernet, so no chip number */
253    )
254{
255    struct ifnet *ifp;
256    int mtu;
257    int unitnumber;
258    char *unitname;
259    void *p;
260
261    /* an array of receive buffer descriptors -- avoid type punned warning */
262    p = (void *)&at91rm9200_emac_rxbuf_hdrs;
263    rxbuf_hdrs = (RXBUF_HDR *)p;
264
265    /* one transmit buffer, 1536 bytes maximum */
266    txbuf = (unsigned char *)&at91rm9200_emac_txbuf;
267
268    /* receive buffers starting address */
269    rxbuf = (unsigned char *)&at91rm9200_emac_rxbufs;
270    /*
271     * Parse driver name
272     */
273    if ((unitnumber = rtems_bsdnet_parse_driver_name (config, &unitname)) < 0)
274        return 0;
275
276    /*
277     * Is driver free?
278     */
279    if (unitnumber != 0) {
280        printf ("Bad AT91RM9200 EMAC unit number.\n");
281        return 0;
282    }
283    ifp = &softc.arpcom.ac_if;
284    if (ifp->if_softc != NULL) {
285        printf ("Driver already in use.\n");
286        return 0;
287    }
288
289    /*
290     *  zero out the control structure
291     */
292
293    memset( &softc, 0, sizeof(softc) );
294
295
296    /* get the MAC address from the chip */
297    softc.arpcom.ac_enaddr[0] = (EMAC_REG(EMAC_SA1L) >> 0) & 0xff;
298    softc.arpcom.ac_enaddr[1] = (EMAC_REG(EMAC_SA1L) >> 8) & 0xff;
299    softc.arpcom.ac_enaddr[2] = (EMAC_REG(EMAC_SA1L) >> 16) & 0xff;
300    softc.arpcom.ac_enaddr[3] = (EMAC_REG(EMAC_SA1L) >> 24) & 0xff;
301    softc.arpcom.ac_enaddr[4] = (EMAC_REG(EMAC_SA1H) >> 0) & 0xff;
302    softc.arpcom.ac_enaddr[5] = (EMAC_REG(EMAC_SA1H) >> 8) & 0xff;
303
304    #if 0
305      printk( "MAC=%02x:%02x:%02x:%02x:%02x:%02x\n",
306        softc.arpcom.ac_enaddr[0],
307        softc.arpcom.ac_enaddr[1],
308        softc.arpcom.ac_enaddr[2],
309        softc.arpcom.ac_enaddr[3],
310        softc.arpcom.ac_enaddr[4],
311        softc.arpcom.ac_enaddr[5]
312      );
313    #endif
314
315    if (config->mtu) {
316        mtu = config->mtu;
317    } else {
318        mtu = ETHERMTU;
319    }
320
321    softc.acceptBroadcast = !config->ignore_broadcast;
322
323    /*
324     * Set up network interface values
325     */
326    ifp->if_softc = &softc;
327    ifp->if_unit = unitnumber;
328    ifp->if_name = unitname;
329    ifp->if_mtu = mtu;
330    ifp->if_init = at91rm9200_emac_init;
331    ifp->if_ioctl = at91rm9200_emac_ioctl;
332    ifp->if_start = at91rm9200_emac_start;
333    ifp->if_output = ether_output;
334    ifp->if_flags = IFF_BROADCAST;
335    if (ifp->if_snd.ifq_maxlen == 0) {
336        ifp->if_snd.ifq_maxlen = ifqmaxlen;
337    }
338
339    softc.rx_buf_idx = 0;
340
341    /*
342     * Attach the interface
343     */
344    if_attach (ifp);
345    ether_ifattach (ifp);
346    return 1;
347}
348
349void at91rm9200_emac_init(void *arg)
350{
351    at91rm9200_emac_softc_t     *sc = arg;
352    struct ifnet *ifp = &sc->arpcom.ac_if;
353
354    /*
355     *This is for stuff that only gets done once (at91rm9200_emac_init()
356     * gets called multiple times
357     */
358    if (sc->txDaemonTid == 0) {
359        /* Set up EMAC hardware */
360        at91rm9200_emac_init_hw(sc);
361
362        /*      Start driver tasks */
363        sc->rxDaemonTid = rtems_bsdnet_newproc("ENrx",
364                                               4096,
365                                               at91rm9200_emac_rxDaemon,
366                                               sc);
367        sc->txDaemonTid = rtems_bsdnet_newproc("ENtx",
368                                               4096,
369                                               at91rm9200_emac_txDaemon,
370                                               sc);
371    } /* if txDaemonTid */
372
373    /* set our priority in the AIC */
374    AIC_SMR_REG(AIC_SMR_EMAC) = AIC_SMR_PRIOR(EMAC_INT_PRIORITY);
375
376    /* install the interrupt handler */
377    BSP_install_rtems_irq_handler(&at91rm9200_emac_isr_data);
378
379    /* EMAC doesn't support promiscuous, so ignore requests */
380    if (ifp->if_flags & IFF_PROMISC) {
381        printf ("Warning - AT91RM9200 Ethernet driver"
382                " doesn't support Promiscuous Mode!\n");
383    }
384
385    /*
386     * Tell the world that we're running.
387     */
388    ifp->if_flags |= IFF_RUNNING;
389
390    /* Enable TX/RX and clear the statistics counters */
391    EMAC_REG(EMAC_CTL) = (EMAC_CTL_TE | EMAC_CTL_RE | EMAC_CTL_CSR);
392
393    /* clear any pending interrupts */
394    EMAC_REG(EMAC_TSR) = 0xffffffff;
395    EMAC_REG(EMAC_RSR) = 0xffffffff;
396
397} /* at91rm9200_emac_init() */
398
399void  at91rm9200_emac_init_hw(at91rm9200_emac_softc_t *sc)
400{
401    int i;
402
403    /* Configure shared pins for Ethernet, not GPIO */
404    PIOA_REG(PIO_PDR) = ( BIT7  |   /* tx clock      */
405                          BIT8  |   /* tx enable     */
406                          BIT9  |   /* tx data 0     */
407                          BIT10 |   /* tx data 1     */
408                          BIT11 |   /* carrier sense */
409                          BIT12 |   /* rx data 0     */
410                          BIT13 |   /* rx data 1     */
411                          BIT14 |   /* rx error      */
412                          BIT15 |   /* MII clock     */
413                          BIT16 );  /* MII data      */
414
415    PIOB_REG(PIO_PDR) = ( BIT12 |   /* tx data 2     */
416                          BIT13 |   /* tx data 3     */
417                          BIT14 |   /* tx error      */
418                          BIT15 |   /* rx data 2     */
419                          BIT16 |   /* rx data 3     */
420                          BIT17 |   /* rx data valid */
421                          BIT18 |   /* rx collistion */
422                          BIT19 );  /* rx clock   */
423
424    PIOB_REG(PIO_BSR) = ( BIT12 |   /* tx data 2     */
425                          BIT13 |   /* tx data 3     */
426                          BIT14 |   /* tx error      */
427                          BIT15 |   /* rx data 2     */
428                          BIT16 |   /* rx data 3     */
429                          BIT17 |   /* rx data valid */
430                          BIT18 |   /* rx collistion */
431                          BIT19 );  /* rx clock   */
432
433
434    /* Enable the clock to the EMAC */
435    PMC_REG(PMC_PCER) |= PMC_PCR_PID_EMAC;
436
437    /* initialize our receive buffer descriptors */
438    for (i = 0; i < NUM_RXBDS-1; i++) {
439        rxbuf_hdrs[i].address = (unsigned long)(&rxbuf[i * RX_BUFFER_SIZE]);
440        rxbuf_hdrs[i].status = 0x00000000;
441    }
442
443    /* last one needs the wrapbit set as well  */
444    rxbuf_hdrs[i].address = ((unsigned long)(&rxbuf[i * RX_BUFFER_SIZE]) |
445                             RXBUF_ADD_WRAP);
446    rxbuf_hdrs[i].status = 0x00000000;
447
448    /* point to our receive buffer queue */
449    EMAC_REG(EMAC_RBQP) = (unsigned long)rxbuf_hdrs;
450
451    /* clear any left over status bits */
452    EMAC_REG(EMAC_RSR)  &= ~(EMAC_RSR_OVR | EMAC_RSR_REC | EMAC_RSR_BNA);
453
454    /* set the MII clock divder to MCK/64 */
455    EMAC_REG(EMAC_CFG) &= EMAC_CFG_CLK_MASK;
456    EMAC_REG(EMAC_CFG) = (EMAC_CFG_CLK_64 | EMAC_CFG_BIG | EMAC_CFG_FD);
457
458    /* enable the MII interface */
459    EMAC_REG(EMAC_CTL) = EMAC_CTL_MPE;
460
461    /* Set PHY LED2 to combined Link/Activity and enable pulse stretching */
462    #if csb637
463     /* Set PHY LED modes.  Traffic Meter Mode for ACTLED
464      * Set Bit 6 - Traffic Mode on
465      */
466     phywrite(0x1b, PHY_AUX_MODE2_TRAFFIC_LED);
467    #else
468      /* must be csb337 */
469      phywrite( 18, 0x0d0a );
470    #endif
471
472    #if 0
473    EMAC_REG(EMAC_MAN) = (0x01 << 30 |   /* Start of Frame Delimiter */
474                          0x01 << 28 |   /* Operation, 0x01 = Write */
475                          0x00 << 23 |   /* Phy Number */
476                          0x14 << 18 |   /* Phy Register */
477                          0x02 << 16 |   /* must be 0x02 */
478                          0x0D0A);       /* Write data (0x0000 if read) */
479   #endif
480
481} /* at91rm9200_emac_init_hw() */
482
483void at91rm9200_emac_start(struct ifnet *ifp)
484{
485    at91rm9200_emac_softc_t *sc = ifp->if_softc;
486
487    rtems_event_send(sc->txDaemonTid, START_TRANSMIT_EVENT);
488    ifp->if_flags |= IFF_OACTIVE;
489}
490
491void at91rm9200_emac_stop (at91rm9200_emac_softc_t *sc)
492{
493    struct ifnet *ifp = &sc->arpcom.ac_if;
494
495    ifp->if_flags &= ~IFF_RUNNING;
496
497    /*
498     * Stop the transmitter and receiver.
499     */
500    EMAC_REG(EMAC_CTL) &= ~(EMAC_CTL_TE | EMAC_CTL_RE);
501}
502
503/*
504 * Driver transmit daemon
505 */
506void at91rm9200_emac_txDaemon (void *arg)
507{
508    at91rm9200_emac_softc_t *sc = (at91rm9200_emac_softc_t *)arg;
509    struct ifnet *ifp = &sc->arpcom.ac_if;
510    struct mbuf *m;
511    rtems_event_set events;
512
513    for (;;)
514    {
515        /* turn on TX interrupt, then wait for one */
516        EMAC_REG(EMAC_IER) = EMAC_INT_TCOM;     /* Transmit complete */
517
518        rtems_bsdnet_event_receive(
519            START_TRANSMIT_EVENT,
520            RTEMS_EVENT_ANY | RTEMS_WAIT,
521            RTEMS_NO_TIMEOUT,
522            &events);
523
524        /* Send packets till queue is empty */
525        for (;;)
526        {
527            /* Get the next mbuf chain to transmit. */
528            IF_DEQUEUE(&ifp->if_snd, m);
529            if (!m)
530                break;
531            at91rm9200_emac_sendpacket (ifp, m);
532        }
533        ifp->if_flags &= ~IFF_OACTIVE;
534    }
535}
536
537/* Send packet */
538void at91rm9200_emac_sendpacket (struct ifnet *ifp, struct mbuf *m)
539{
540    struct mbuf *l = NULL;
541    unsigned int pkt_offset = 0;
542    delay_cnt = 0;
543    /* printf("at91rm9200_emac_sendpacket %p\n", m); */
544
545    /* Wait for EMAC Transmit Queue to become available. */
546    while (((EMAC_REG(EMAC_TSR) & EMAC_TSR_COMP) == 0) &&
547           ((EMAC_REG(EMAC_TSR) & EMAC_TSR_TXIDLE) == 0))
548
549    {
550        delay_cnt++;
551/*        sleep(0);       make sure we don't hog the cpu */
552        continue;
553    }
554
555    /* copy the mbuf chain into the transmit buffer */
556    l = m;
557    while (l != NULL) {
558        memcpy(((char *)txbuf + pkt_offset),  /* offset into pkt for mbuf */
559               (char *)mtod(l, void *),       /* cast to void */
560               l->m_len);                     /* length of this mbuf */
561
562        pkt_offset += l->m_len;               /* update offset */
563        l = l->m_next;                        /* get next mbuf, if any */
564    }
565
566    /* free the mbuf chain we just copied */
567    m_freem(m);
568
569    /* clear any pending status */
570    EMAC_REG(EMAC_TSR) = (EMAC_TSR_OVR | EMAC_TSR_COL | EMAC_TSR_RLE
571                          | EMAC_TSR_COMP | EMAC_TSR_UND);
572
573    /* tell the EMAC about our buffer */
574    EMAC_REG(EMAC_TAR) = (unsigned long)txbuf;
575    EMAC_REG(EMAC_TCR) = (unsigned long)pkt_offset;
576} /* at91rm9200_emac_sendpacket () */
577
578
579/* SONIC reader task */
580void at91rm9200_emac_rxDaemon(void *arg)
581{
582    at91rm9200_emac_softc_t *sc = (at91rm9200_emac_softc_t *)arg;
583    struct ifnet *ifp = &sc->arpcom.ac_if;
584    struct mbuf *m;
585    struct ether_header *eh;
586    rtems_event_set events;
587    int pktlen;
588
589    /* Input packet handling loop */
590    for (;;) {
591        /* turn on RX interrupts, then wait for one */
592        EMAC_REG(EMAC_IER) = (EMAC_INT_RCOM |   /* Receive complete */
593                              EMAC_INT_RBNA |   /* Receive buf not available */
594                              EMAC_INT_ROVR);   /* Receive overrun */
595
596        rtems_bsdnet_event_receive(
597            START_RECEIVE_EVENT,
598            RTEMS_EVENT_ANY | RTEMS_WAIT,
599            RTEMS_NO_TIMEOUT,
600            &events);
601
602        if (EMAC_REG(EMAC_RSR) & EMAC_RSR_BNA) {
603            printf("1: EMAC_BNA\n");
604        }
605
606        if (EMAC_REG(EMAC_RSR) & EMAC_RSR_OVR) {
607            printf("1: EMAC_OVR\n");
608        }
609
610        /* clear the receive status as we do not use it anyway */
611        EMAC_REG(EMAC_RSR) = (EMAC_RSR_REC | EMAC_RSR_OVR | EMAC_RSR_BNA);
612
613        /* scan the buffer descriptors looking for any with data in them */
614        while (rxbuf_hdrs[sc->rx_buf_idx].address & RXBUF_ADD_OWNED) {
615            pktlen = rxbuf_hdrs[sc->rx_buf_idx].status & RXBUF_STAT_LEN_MASK;
616
617            /* get an mbuf this packet */
618            MGETHDR(m, M_WAIT, MT_DATA);
619
620            /* now get a cluster pointed to by the mbuf */
621            /* since an mbuf by itself is too small */
622            MCLGET(m, M_WAIT);
623
624            /* set the type of mbuf to ifp (ethernet I/F) */
625            m->m_pkthdr.rcvif = ifp;
626            m->m_nextpkt = 0;
627
628            /* copy the packet into the cluster pointed to by the mbuf */
629            memcpy((char *)m->m_ext.ext_buf,
630                   (char *)(rxbuf_hdrs[sc->rx_buf_idx].address & 0xfffffffc),
631                   pktlen);
632
633            /* Release the buffer ASAP back to the EMAC */
634            rxbuf_hdrs[sc->rx_buf_idx].address &= ~RXBUF_ADD_OWNED;
635
636            /* set the length of the mbuf */
637            m->m_len = pktlen - (sizeof(struct ether_header) + 4);
638            m->m_pkthdr.len = m->m_len;
639
640            /* strip off the ethernet header from the mbuf */
641            /* but save the pointer to it */
642            eh = mtod (m, struct ether_header *);
643            m->m_data += sizeof(struct ether_header);
644
645            /* increment the buffer index */
646            sc->rx_buf_idx++;
647            if (sc->rx_buf_idx >= NUM_RXBDS) {
648                sc->rx_buf_idx = 0;
649            }
650
651            /* give all this stuff to the stack */
652            ether_input(ifp, eh, m);
653
654        } /* while ADD_OWNED = 0 */
655
656        if (EMAC_REG(EMAC_RSR) & EMAC_RSR_BNA) {
657            printf("2:EMAC_BNA\n");
658        }
659        if (EMAC_REG(EMAC_RSR) & EMAC_RSR_OVR) {
660            printf("2:EMAC_OVR\n");
661        }
662
663
664    } /* for (;;) */
665} /* at91rm9200_emac_rxDaemon() */
666
667
668/* Show interface statistics */
669void at91rm9200_emac_stats (at91rm9200_emac_softc_t *sc)
670{
671    printf (" Total Interrupts:%-8lu",          sc->Interrupts);
672    printf ("    Rx Interrupts:%-8lu",          sc->rxInterrupts);
673    printf ("            Giant:%-8lu",          sc->rxGiant);
674    printf ("        Non-octet:%-8lu\n",                sc->rxNonOctet);
675    printf ("          Bad CRC:%-8lu",          sc->rxBadCRC);
676    printf ("        Collision:%-8lu",          sc->rxCollision);
677    printf ("           Missed:%-8lu\n",                sc->rxMissed);
678
679    printf (    "    Tx Interrupts:%-8lu",      sc->txInterrupts);
680    printf (  "           Deferred:%-8lu",      sc->txDeferred);
681    printf ("        Lost Carrier:%-8lu\n",     sc->txLostCarrier);
682    printf (   "Single Collisions:%-8lu",       sc->txSingleCollision);
683    printf ( "Multiple Collisions:%-8lu",       sc->txMultipleCollision);
684    printf ("Excessive Collisions:%-8lu\n",     sc->txExcessiveCollision);
685    printf (   " Total Collisions:%-8lu",       sc->txCollision);
686    printf ( "     Late Collision:%-8lu",       sc->txLateCollision);
687    printf ("            Underrun:%-8lu\n",     sc->txUnderrun);
688    printf (   "  Raw output wait:%-8lu\n",     sc->txRawWait);
689}
690
691
692/* Enables at91rm9200_emac interrupts. */
693static void at91rm9200_emac_isr_on(const rtems_irq_connect_data *unused)
694{
695    /* Enable various TX/RX interrupts */
696    EMAC_REG(EMAC_IER) = (EMAC_INT_RCOM | /* Receive complete */
697                          EMAC_INT_RBNA | /* Receive buffer not available */
698                          EMAC_INT_TCOM | /* Transmit complete */
699                          EMAC_INT_ROVR | /* Receive overrun */
700                          EMAC_INT_ABT);  /* Abort on DMA transfer */
701
702    return;
703}
704
705/* Disables at91rm9200_emac interrupts */
706static void at91rm9200_emac_isr_off(const rtems_irq_connect_data *unused)
707{
708    /* disable all various TX/RX interrupts */
709    EMAC_REG(EMAC_IDR) = 0xffffffff;
710    return;
711}
712
713/* Tests to see if at91rm9200_emac interrupts are enabled, and
714 * returns non-0 if so.
715 * If interrupt is not enabled, returns 0.
716 */
717static int at91rm9200_emac_isr_is_on(const rtems_irq_connect_data *irq)
718{
719    return EMAC_REG(EMAC_IMR); /* any interrupts enabled? */
720}
721
722/*  Driver ioctl handler */
723static int
724at91rm9200_emac_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data)
725{
726    at91rm9200_emac_softc_t *sc = ifp->if_softc;
727    int error = 0;
728
729    switch (command) {
730    case SIOCGIFADDR:
731    case SIOCSIFADDR:
732        ether_ioctl (ifp, command, data);
733        break;
734
735    case SIOCSIFFLAGS:
736        switch (ifp->if_flags & (IFF_UP | IFF_RUNNING))
737        {
738        case IFF_RUNNING:
739            at91rm9200_emac_stop (sc);
740            break;
741
742        case IFF_UP:
743            at91rm9200_emac_init (sc);
744            break;
745
746        case IFF_UP | IFF_RUNNING:
747            at91rm9200_emac_stop (sc);
748            at91rm9200_emac_init (sc);
749            break;
750
751        default:
752            break;
753        } /* switch (if_flags) */
754        break;
755
756    case SIO_RTEMS_SHOW_STATS:
757        at91rm9200_emac_stats (sc);
758        break;
759
760        /*
761         * FIXME: All sorts of multicast commands need to be added here!
762         */
763    default:
764        error = EINVAL;
765        break;
766    } /* switch (command) */
767    return error;
768}
769
770/* interrupt handler */
771rtems_isr at91rm9200_emac_isr (rtems_vector_number v)
772{
773    unsigned long status32;
774
775    /* get the ISR status and determine RX or TX */
776    status32 = EMAC_REG(EMAC_ISR);
777
778    if (status32 & EMAC_INT_ABT) {
779        EMAC_REG(EMAC_IDR) = EMAC_INT_ABT; /* disable it */
780        rtems_panic("AT91RM9200 Ethernet MAC has received an Abort.\n");
781    }
782
783    if (status32 & (EMAC_INT_RCOM |    /* Receive complete */
784                    EMAC_INT_RBNA |    /* Receive buffer not available */
785                    EMAC_INT_ROVR)) {  /* Receive overrun */
786
787        /* disable the RX interrupts */
788        EMAC_REG(EMAC_IDR) = (EMAC_INT_RCOM |  /* Receive complete */
789                              EMAC_INT_RBNA |  /* Receive buf not available */
790                              EMAC_INT_ROVR);  /* Receive overrun */
791
792        rtems_event_send (softc.rxDaemonTid, START_RECEIVE_EVENT);
793    }
794
795    if (status32 & EMAC_INT_TCOM) {      /* Transmit buffer register empty */
796
797        /* disable the TX interrupts */
798        EMAC_REG(EMAC_IDR) = EMAC_INT_TCOM;
799
800        rtems_event_send (softc.txDaemonTid, START_TRANSMIT_EVENT);
801    }
802}
803
Note: See TracBrowser for help on using the repository browser.