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 07/24/13 at 17:49:51

Removed legacy data types from arm

  • Property mode set to 100644
File size: 25.9 KB
RevLine 
[b759b04]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 *
[afcecbf7]8 *
9 *  July 2009: Joel Sherrill merged csb637 PHY differences from
10 *             MicroMonitor 1.17.
[b759b04]11 */
12
13#include <rtems.h>
14#include <rtems/rtems_bsdnet.h>
15#include <at91rm9200.h>
16#include <at91rm9200_emac.h>
[6a184ff]17#include <at91rm9200_gpio.h>
18#include <at91rm9200_pmc.h>
[b759b04]19
20#include <stdio.h>
21#include <string.h>
22
23#include <errno.h>
24#include <rtems/error.h>
[6886a485]25#include <assert.h>
[b759b04]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
[14cd67c]37#include <bsp/irq.h>
[e73f8a17]38#include <bspopts.h>
39
[afcecbf7]40/* enable debugging of the PHY code */
41#define PHY_DBG
42
43/* enable debugging of the EMAC code */
44/* #define EMAC_DBG */
45
[e73f8a17]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
[b759b04]85
[1f4321b]86static void at91rm9200_emac_isr (void *);
[6886a485]87static void at91rm9200_emac_isr_on(void);
[b759b04]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;
[e73f8a17]128
[b759b04]129    /*
130     * Interrupt vector
131     */
132    rtems_vector_number             vector;
[e73f8a17]133
[b759b04]134    /*
135     *  Indicates configuration
136     */
137    int                             acceptBroadcast;
[e73f8a17]138
[b759b04]139    /*
140     * Task waiting for interrupts
141     */
142    rtems_id                        rxDaemonTid;
143    rtems_id                        txDaemonTid;
[e73f8a17]144
[b759b04]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;
[e73f8a17]162
[b759b04]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 */
[e73f8a17]186int rtems_at91rm9200_emac_attach (struct rtems_bsdnet_ifconfig *config,
[b759b04]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);
[e73f8a17]196static int at91rm9200_emac_ioctl (struct ifnet *ifp,
197                                  ioctl_command_t command,
[b759b04]198                                  caddr_t data);
199
[6886a485]200#if csb637
[e73f8a17]201/*
202 * phyread(): Read the PHY
203 */
[6886a485]204static uint32_t phyread(uint8_t reg)
[e73f8a17]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
[afcecbf7]215  #if defined(EMAC_DBG)
[e73f8a17]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}
[6886a485]225#endif
[e73f8a17]226
227/*
228 * phywrite(): Write the PHY
229 */
[6886a485]230static void phywrite(uint8_t reg, uint16_t data)
[e73f8a17]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);
[afcecbf7]238  #if defined(EMAC_DBG)
239    printk("EMAC: Phy 0, Reg %d, Write 0x%04x.\n", reg, data);
[e73f8a17]240  #endif
241
242  /* wait for phy write to complete (was udelay(5000)) */
243  rtems_task_wake_after(1);
244}
245
246
[b759b04]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;
[327e0fcd]256    void *p;
[e73f8a17]257
[327e0fcd]258    /* an array of receive buffer descriptors -- avoid type punned warning */
259    p = (void *)&at91rm9200_emac_rxbuf_hdrs;
260    rxbuf_hdrs = (RXBUF_HDR *)p;
[b759b04]261
262    /* one transmit buffer, 1536 bytes maximum */
[327e0fcd]263    txbuf = (unsigned char *)&at91rm9200_emac_txbuf;
[b759b04]264
265    /* receive buffers starting address */
[327e0fcd]266    rxbuf = (unsigned char *)&at91rm9200_emac_rxbufs;
[b759b04]267    /*
268     * Parse driver name
269     */
270    if ((unitnumber = rtems_bsdnet_parse_driver_name (config, &unitname)) < 0)
271        return 0;
[e73f8a17]272
[b759b04]273    /*
274     * Is driver free?
275     */
276    if (unitnumber != 0) {
[afcecbf7]277        printk ("Bad AT91RM9200 EMAC unit number.\n");
[b759b04]278        return 0;
279    }
280    ifp = &softc.arpcom.ac_if;
281    if (ifp->if_softc != NULL) {
[afcecbf7]282        printk ("Driver already in use.\n");
[b759b04]283        return 0;
284    }
[e73f8a17]285
[b759b04]286    /*
287     *  zero out the control structure
288     */
[e73f8a17]289
[b759b04]290    memset( &softc, 0, sizeof(softc) );
[e73f8a17]291
292
[b759b04]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
[e73f8a17]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
[b759b04]312    if (config->mtu) {
313        mtu = config->mtu;
314    } else {
315        mtu = ETHERMTU;
316    }
317
318    softc.acceptBroadcast = !config->ignore_broadcast;
[e73f8a17]319
[b759b04]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    }
[e73f8a17]335
[b759b04]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{
[e73f8a17]348    at91rm9200_emac_softc_t     *sc = arg;
[b759b04]349    struct ifnet *ifp = &sc->arpcom.ac_if;
[6886a485]350    rtems_status_code status = RTEMS_SUCCESSFUL;
[e73f8a17]351
352    /*
353     *This is for stuff that only gets done once (at91rm9200_emac_init()
354     * gets called multiple times
[b759b04]355     */
356    if (sc->txDaemonTid == 0) {
357        /* Set up EMAC hardware */
358        at91rm9200_emac_init_hw(sc);
[e73f8a17]359
[b759b04]360        /*      Start driver tasks */
[e73f8a17]361        sc->rxDaemonTid = rtems_bsdnet_newproc("ENrx",
362                                               4096,
363                                               at91rm9200_emac_rxDaemon,
[b759b04]364                                               sc);
[e73f8a17]365        sc->txDaemonTid = rtems_bsdnet_newproc("ENtx",
366                                               4096,
367                                               at91rm9200_emac_txDaemon,
[b759b04]368                                               sc);
369    } /* if txDaemonTid */
[e73f8a17]370
[b759b04]371    /* set our priority in the AIC */
372    AIC_SMR_REG(AIC_SMR_EMAC) = AIC_SMR_PRIOR(EMAC_INT_PRIORITY);
[e73f8a17]373
[b759b04]374    /* install the interrupt handler */
[6886a485]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();
[e73f8a17]384
[b759b04]385    /* EMAC doesn't support promiscuous, so ignore requests */
386    if (ifp->if_flags & IFF_PROMISC) {
[afcecbf7]387        printk ("Warning - AT91RM9200 Ethernet driver"
[b759b04]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;
[e73f8a17]395
[b759b04]396    /* Enable TX/RX and clear the statistics counters */
397    EMAC_REG(EMAC_CTL) = (EMAC_CTL_TE | EMAC_CTL_RE | EMAC_CTL_CSR);
[e73f8a17]398
[b759b04]399    /* clear any pending interrupts */
400    EMAC_REG(EMAC_TSR) = 0xffffffff;
401    EMAC_REG(EMAC_RSR) = 0xffffffff;
[e73f8a17]402
[b759b04]403} /* at91rm9200_emac_init() */
404
405void  at91rm9200_emac_init_hw(at91rm9200_emac_softc_t *sc)
406{
407    int i;
[6a184ff]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   */
[e73f8a17]438
[6a184ff]439
440    /* Enable the clock to the EMAC */
441    PMC_REG(PMC_PCER) |= PMC_PCR_PID_EMAC;
442
[b759b04]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  */
[e73f8a17]450    rxbuf_hdrs[i].address = ((unsigned long)(&rxbuf[i * RX_BUFFER_SIZE]) |
[b759b04]451                             RXBUF_ADD_WRAP);
452    rxbuf_hdrs[i].status = 0x00000000;
[e73f8a17]453
[b759b04]454    /* point to our receive buffer queue */
455    EMAC_REG(EMAC_RBQP) = (unsigned long)rxbuf_hdrs;
[e73f8a17]456
[b759b04]457    /* clear any left over status bits */
458    EMAC_REG(EMAC_RSR)  &= ~(EMAC_RSR_OVR | EMAC_RSR_REC | EMAC_RSR_BNA);
[e73f8a17]459
[b759b04]460    /* set the MII clock divder to MCK/64 */
[6a184ff]461    EMAC_REG(EMAC_CFG) &= EMAC_CFG_CLK_MASK;
[b759b04]462    EMAC_REG(EMAC_CFG) = (EMAC_CFG_CLK_64 | EMAC_CFG_BIG | EMAC_CFG_FD);
[e73f8a17]463
[b759b04]464    /* enable the MII interface */
465    EMAC_REG(EMAC_CTL) = EMAC_CTL_MPE;
[e73f8a17]466
467    #if csb637
[afcecbf7]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
[32b8506]522      }
523
[afcecbf7]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
[32b8506]534      }
[afcecbf7]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    }
[e73f8a17]541    #else
542      /* must be csb337 */
[afcecbf7]543      /* Set PHY LED2 to combined Link/Activity and enable pulse stretching */
[e73f8a17]544      phywrite( 18, 0x0d0a );
545    #endif
546
547    #if 0
[b759b04]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) */
[e73f8a17]554   #endif
555
[b759b04]556} /* at91rm9200_emac_init_hw() */
557
558void at91rm9200_emac_start(struct ifnet *ifp)
559{
560    at91rm9200_emac_softc_t *sc = ifp->if_softc;
[e73f8a17]561
[26e90fb1]562    rtems_bsdnet_event_send(sc->txDaemonTid, START_TRANSMIT_EVENT);
[b759b04]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;
[e73f8a17]569
[b759b04]570    ifp->if_flags &= ~IFF_RUNNING;
[e73f8a17]571
[b759b04]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;
[e73f8a17]587
[b759b04]588    for (;;)
589    {
590        /* turn on TX interrupt, then wait for one */
591        EMAC_REG(EMAC_IER) = EMAC_INT_TCOM;     /* Transmit complete */
[e73f8a17]592
[b759b04]593        rtems_bsdnet_event_receive(
594            START_TRANSMIT_EVENT,
595            RTEMS_EVENT_ANY | RTEMS_WAIT,
596            RTEMS_NO_TIMEOUT,
597            &events);
[e73f8a17]598
[b759b04]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;
[afcecbf7]618    /* printk("at91rm9200_emac_sendpacket %p\n", m); */
[e73f8a17]619
[b759b04]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))
[e73f8a17]623
[b759b04]624    {
625        delay_cnt++;
626/*        sleep(0);       make sure we don't hog the cpu */
627        continue;
628    }
[e73f8a17]629
[b759b04]630    /* copy the mbuf chain into the transmit buffer */
[e73f8a17]631    l = m;
[b759b04]632    while (l != NULL) {
[e73f8a17]633        memcpy(((char *)txbuf + pkt_offset),  /* offset into pkt for mbuf */
634               (char *)mtod(l, void *),       /* cast to void */
[b759b04]635               l->m_len);                     /* length of this mbuf */
[e73f8a17]636
[b759b04]637        pkt_offset += l->m_len;               /* update offset */
[e73f8a17]638        l = l->m_next;                        /* get next mbuf, if any */
[b759b04]639    }
[e73f8a17]640
[b759b04]641    /* free the mbuf chain we just copied */
642    m_freem(m);
[e73f8a17]643
[b759b04]644    /* clear any pending status */
645    EMAC_REG(EMAC_TSR) = (EMAC_TSR_OVR | EMAC_TSR_COL | EMAC_TSR_RLE
[e73f8a17]646                          | EMAC_TSR_COMP | EMAC_TSR_UND);
647
[b759b04]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;
[e73f8a17]663
[b759b04]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 */
[e73f8a17]670
[b759b04]671        rtems_bsdnet_event_receive(
672            START_RECEIVE_EVENT,
673            RTEMS_EVENT_ANY | RTEMS_WAIT,
674            RTEMS_NO_TIMEOUT,
675            &events);
[e73f8a17]676
[b759b04]677        if (EMAC_REG(EMAC_RSR) & EMAC_RSR_BNA) {
[afcecbf7]678            printk("1: EMAC_BNA\n");
[b759b04]679        }
680
681        if (EMAC_REG(EMAC_RSR) & EMAC_RSR_OVR) {
[afcecbf7]682            printk("1: EMAC_OVR\n");
[b759b04]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);
[e73f8a17]687
[b759b04]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;
[e73f8a17]691
[b759b04]692            /* get an mbuf this packet */
693            MGETHDR(m, M_WAIT, MT_DATA);
[e73f8a17]694
[b759b04]695            /* now get a cluster pointed to by the mbuf */
696            /* since an mbuf by itself is too small */
697            MCLGET(m, M_WAIT);
[e73f8a17]698
[b759b04]699            /* set the type of mbuf to ifp (ethernet I/F) */
700            m->m_pkthdr.rcvif = ifp;
701            m->m_nextpkt = 0;
[e73f8a17]702
703            /* copy the packet into the cluster pointed to by the mbuf */
[b759b04]704            memcpy((char *)m->m_ext.ext_buf,
705                   (char *)(rxbuf_hdrs[sc->rx_buf_idx].address & 0xfffffffc),
706                   pktlen);
[e73f8a17]707
[b759b04]708            /* Release the buffer ASAP back to the EMAC */
709            rxbuf_hdrs[sc->rx_buf_idx].address &= ~RXBUF_ADD_OWNED;
[e73f8a17]710
[b759b04]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;
[e73f8a17]714
[b759b04]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            }
[e73f8a17]725
[b759b04]726            /* give all this stuff to the stack */
727            ether_input(ifp, eh, m);
[e73f8a17]728
[b759b04]729        } /* while ADD_OWNED = 0 */
730
731        if (EMAC_REG(EMAC_RSR) & EMAC_RSR_BNA) {
[afcecbf7]732            printk("2:EMAC_BNA\n");
[b759b04]733        }
734        if (EMAC_REG(EMAC_RSR) & EMAC_RSR_OVR) {
[afcecbf7]735            printk("2:EMAC_OVR\n");
[b759b04]736        }
737
738
739    } /* for (;;) */
[e73f8a17]740} /* at91rm9200_emac_rxDaemon() */
[b759b04]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);
[e73f8a17]753
[b759b04]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. */
[6886a485]768static void at91rm9200_emac_isr_on(void)
[b759b04]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 */
[e73f8a17]776
[b759b04]777    return;
778}
779
780/*  Driver ioctl handler */
781static int
[7a5265ff]782at91rm9200_emac_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data)
[b759b04]783{
784    at91rm9200_emac_softc_t *sc = ifp->if_softc;
785    int error = 0;
[e73f8a17]786
[b759b04]787    switch (command) {
788    case SIOCGIFADDR:
789    case SIOCSIFADDR:
790        ether_ioctl (ifp, command, data);
791        break;
[e73f8a17]792
[b759b04]793    case SIOCSIFFLAGS:
794        switch (ifp->if_flags & (IFF_UP | IFF_RUNNING))
795        {
796        case IFF_RUNNING:
797            at91rm9200_emac_stop (sc);
798            break;
[e73f8a17]799
[b759b04]800        case IFF_UP:
801            at91rm9200_emac_init (sc);
802            break;
[e73f8a17]803
[b759b04]804        case IFF_UP | IFF_RUNNING:
805            at91rm9200_emac_stop (sc);
806            at91rm9200_emac_init (sc);
807            break;
[e73f8a17]808
[b759b04]809        default:
810            break;
811        } /* switch (if_flags) */
812        break;
[e73f8a17]813
[b759b04]814    case SIO_RTEMS_SHOW_STATS:
815        at91rm9200_emac_stats (sc);
816        break;
[e73f8a17]817
[b759b04]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 */
[1f4321b]829static void at91rm9200_emac_isr (void * unused)
[b759b04]830{
831    unsigned long status32;
[e73f8a17]832
[b759b04]833    /* get the ISR status and determine RX or TX */
834    status32 = EMAC_REG(EMAC_ISR);
[e73f8a17]835
[b759b04]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    }
[e73f8a17]840
[b759b04]841    if (status32 & (EMAC_INT_RCOM |    /* Receive complete */
842                    EMAC_INT_RBNA |    /* Receive buffer not available */
843                    EMAC_INT_ROVR)) {  /* Receive overrun */
[e73f8a17]844
[b759b04]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 */
[e73f8a17]849
[26e90fb1]850        rtems_bsdnet_event_send (softc.rxDaemonTid, START_RECEIVE_EVENT);
[e73f8a17]851    }
[b759b04]852
853    if (status32 & EMAC_INT_TCOM) {      /* Transmit buffer register empty */
[e73f8a17]854
[b759b04]855        /* disable the TX interrupts */
856        EMAC_REG(EMAC_IDR) = EMAC_INT_TCOM;
[e73f8a17]857
[26e90fb1]858        rtems_bsdnet_event_send (softc.txDaemonTid, START_TRANSMIT_EVENT);
[e73f8a17]859    }
[b759b04]860}
861
Note: See TracBrowser for help on using the repository browser.