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

4.104.114.84.95
Last change on this file since 7a5265ff was 7a5265ff, checked in by Ralf Corsepius <ralf.corsepius@…>, on 12/15/06 at 05:48:07

Use ioctl_command_t.

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