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

4.115
Last change on this file since 991fdb33 was 1f4321b, checked in by Vipul Nayyar <nayyar_vipul@…>, on Jul 24, 2013 at 5:49:51 PM

Removed legacy data types from arm

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