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

4.104.115
Last change on this file since 32b8506 was 32b8506, checked in by Ralf Corsepius <ralf.corsepius@…>, on 11/29/09 at 14:53:02

Whitespace removal.

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