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
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 *  $Id$
13 */
14
15#include <rtems.h>
16#include <rtems/rtems_bsdnet.h>
17#include <at91rm9200.h>
18#include <at91rm9200_emac.h>
19#include <at91rm9200_gpio.h>
20#include <at91rm9200_pmc.h>
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>
39#include <bspopts.h>
40
41/* enable debugging of the PHY code */
42#define PHY_DBG
43
44/* enable debugging of the EMAC code */
45/* #define EMAC_DBG */
46
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
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 = {
94    AT91RM9200_INT_EMAC,
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;
142
143    /*
144     * Interrupt vector
145     */
146    rtems_vector_number             vector;
147
148    /*
149     *  Indicates configuration
150     */
151    int                             acceptBroadcast;
152
153    /*
154     * Task waiting for interrupts
155     */
156    rtems_id                        rxDaemonTid;
157    rtems_id                        txDaemonTid;
158
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;
176
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 */
200int rtems_at91rm9200_emac_attach (struct rtems_bsdnet_ifconfig *config,
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);
210static int at91rm9200_emac_ioctl (struct ifnet *ifp,
211                                  ioctl_command_t command,
212                                  caddr_t data);
213
214
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
229  #if defined(EMAC_DBG)
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);
251  #if defined(EMAC_DBG)
252    printk("EMAC: Phy 0, Reg %d, Write 0x%04x.\n", reg, data);
253  #endif
254
255  /* wait for phy write to complete (was udelay(5000)) */
256  rtems_task_wake_after(1);
257}
258
259
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;
269    void *p;
270
271    /* an array of receive buffer descriptors -- avoid type punned warning */
272    p = (void *)&at91rm9200_emac_rxbuf_hdrs;
273    rxbuf_hdrs = (RXBUF_HDR *)p;
274
275    /* one transmit buffer, 1536 bytes maximum */
276    txbuf = (unsigned char *)&at91rm9200_emac_txbuf;
277
278    /* receive buffers starting address */
279    rxbuf = (unsigned char *)&at91rm9200_emac_rxbufs;
280    /*
281     * Parse driver name
282     */
283    if ((unitnumber = rtems_bsdnet_parse_driver_name (config, &unitname)) < 0)
284        return 0;
285
286    /*
287     * Is driver free?
288     */
289    if (unitnumber != 0) {
290        printk ("Bad AT91RM9200 EMAC unit number.\n");
291        return 0;
292    }
293    ifp = &softc.arpcom.ac_if;
294    if (ifp->if_softc != NULL) {
295        printk ("Driver already in use.\n");
296        return 0;
297    }
298
299    /*
300     *  zero out the control structure
301     */
302
303    memset( &softc, 0, sizeof(softc) );
304
305
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
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
325    if (config->mtu) {
326        mtu = config->mtu;
327    } else {
328        mtu = ETHERMTU;
329    }
330
331    softc.acceptBroadcast = !config->ignore_broadcast;
332
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    }
348
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{
361    at91rm9200_emac_softc_t     *sc = arg;
362    struct ifnet *ifp = &sc->arpcom.ac_if;
363
364    /*
365     *This is for stuff that only gets done once (at91rm9200_emac_init()
366     * gets called multiple times
367     */
368    if (sc->txDaemonTid == 0) {
369        /* Set up EMAC hardware */
370        at91rm9200_emac_init_hw(sc);
371
372        /*      Start driver tasks */
373        sc->rxDaemonTid = rtems_bsdnet_newproc("ENrx",
374                                               4096,
375                                               at91rm9200_emac_rxDaemon,
376                                               sc);
377        sc->txDaemonTid = rtems_bsdnet_newproc("ENtx",
378                                               4096,
379                                               at91rm9200_emac_txDaemon,
380                                               sc);
381    } /* if txDaemonTid */
382
383    /* set our priority in the AIC */
384    AIC_SMR_REG(AIC_SMR_EMAC) = AIC_SMR_PRIOR(EMAC_INT_PRIORITY);
385
386    /* install the interrupt handler */
387    BSP_install_rtems_irq_handler(&at91rm9200_emac_isr_data);
388
389    /* EMAC doesn't support promiscuous, so ignore requests */
390    if (ifp->if_flags & IFF_PROMISC) {
391        printk ("Warning - AT91RM9200 Ethernet driver"
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;
399
400    /* Enable TX/RX and clear the statistics counters */
401    EMAC_REG(EMAC_CTL) = (EMAC_CTL_TE | EMAC_CTL_RE | EMAC_CTL_CSR);
402
403    /* clear any pending interrupts */
404    EMAC_REG(EMAC_TSR) = 0xffffffff;
405    EMAC_REG(EMAC_RSR) = 0xffffffff;
406
407} /* at91rm9200_emac_init() */
408
409void  at91rm9200_emac_init_hw(at91rm9200_emac_softc_t *sc)
410{
411    int i;
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   */
442
443
444    /* Enable the clock to the EMAC */
445    PMC_REG(PMC_PCER) |= PMC_PCR_PID_EMAC;
446
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  */
454    rxbuf_hdrs[i].address = ((unsigned long)(&rxbuf[i * RX_BUFFER_SIZE]) |
455                             RXBUF_ADD_WRAP);
456    rxbuf_hdrs[i].status = 0x00000000;
457
458    /* point to our receive buffer queue */
459    EMAC_REG(EMAC_RBQP) = (unsigned long)rxbuf_hdrs;
460
461    /* clear any left over status bits */
462    EMAC_REG(EMAC_RSR)  &= ~(EMAC_RSR_OVR | EMAC_RSR_REC | EMAC_RSR_BNA);
463
464    /* set the MII clock divder to MCK/64 */
465    EMAC_REG(EMAC_CFG) &= EMAC_CFG_CLK_MASK;
466    EMAC_REG(EMAC_CFG) = (EMAC_CFG_CLK_64 | EMAC_CFG_BIG | EMAC_CFG_FD);
467
468    /* enable the MII interface */
469    EMAC_REG(EMAC_CTL) = EMAC_CTL_MPE;
470
471    #if csb637
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
526      }
527
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
538      }
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    }
545    #else
546      /* must be csb337 */
547      /* Set PHY LED2 to combined Link/Activity and enable pulse stretching */
548      phywrite( 18, 0x0d0a );
549    #endif
550
551    #if 0
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) */
558   #endif
559
560} /* at91rm9200_emac_init_hw() */
561
562void at91rm9200_emac_start(struct ifnet *ifp)
563{
564    at91rm9200_emac_softc_t *sc = ifp->if_softc;
565
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;
573
574    ifp->if_flags &= ~IFF_RUNNING;
575
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;
591
592    for (;;)
593    {
594        /* turn on TX interrupt, then wait for one */
595        EMAC_REG(EMAC_IER) = EMAC_INT_TCOM;     /* Transmit complete */
596
597        rtems_bsdnet_event_receive(
598            START_TRANSMIT_EVENT,
599            RTEMS_EVENT_ANY | RTEMS_WAIT,
600            RTEMS_NO_TIMEOUT,
601            &events);
602
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;
622    /* printk("at91rm9200_emac_sendpacket %p\n", m); */
623
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))
627
628    {
629        delay_cnt++;
630/*        sleep(0);       make sure we don't hog the cpu */
631        continue;
632    }
633
634    /* copy the mbuf chain into the transmit buffer */
635    l = m;
636    while (l != NULL) {
637        memcpy(((char *)txbuf + pkt_offset),  /* offset into pkt for mbuf */
638               (char *)mtod(l, void *),       /* cast to void */
639               l->m_len);                     /* length of this mbuf */
640
641        pkt_offset += l->m_len;               /* update offset */
642        l = l->m_next;                        /* get next mbuf, if any */
643    }
644
645    /* free the mbuf chain we just copied */
646    m_freem(m);
647
648    /* clear any pending status */
649    EMAC_REG(EMAC_TSR) = (EMAC_TSR_OVR | EMAC_TSR_COL | EMAC_TSR_RLE
650                          | EMAC_TSR_COMP | EMAC_TSR_UND);
651
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;
667
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 */
674
675        rtems_bsdnet_event_receive(
676            START_RECEIVE_EVENT,
677            RTEMS_EVENT_ANY | RTEMS_WAIT,
678            RTEMS_NO_TIMEOUT,
679            &events);
680
681        if (EMAC_REG(EMAC_RSR) & EMAC_RSR_BNA) {
682            printk("1: EMAC_BNA\n");
683        }
684
685        if (EMAC_REG(EMAC_RSR) & EMAC_RSR_OVR) {
686            printk("1: EMAC_OVR\n");
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);
691
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;
695
696            /* get an mbuf this packet */
697            MGETHDR(m, M_WAIT, MT_DATA);
698
699            /* now get a cluster pointed to by the mbuf */
700            /* since an mbuf by itself is too small */
701            MCLGET(m, M_WAIT);
702
703            /* set the type of mbuf to ifp (ethernet I/F) */
704            m->m_pkthdr.rcvif = ifp;
705            m->m_nextpkt = 0;
706
707            /* copy the packet into the cluster pointed to by the mbuf */
708            memcpy((char *)m->m_ext.ext_buf,
709                   (char *)(rxbuf_hdrs[sc->rx_buf_idx].address & 0xfffffffc),
710                   pktlen);
711
712            /* Release the buffer ASAP back to the EMAC */
713            rxbuf_hdrs[sc->rx_buf_idx].address &= ~RXBUF_ADD_OWNED;
714
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;
718
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            }
729
730            /* give all this stuff to the stack */
731            ether_input(ifp, eh, m);
732
733        } /* while ADD_OWNED = 0 */
734
735        if (EMAC_REG(EMAC_RSR) & EMAC_RSR_BNA) {
736            printk("2:EMAC_BNA\n");
737        }
738        if (EMAC_REG(EMAC_RSR) & EMAC_RSR_OVR) {
739            printk("2:EMAC_OVR\n");
740        }
741
742
743    } /* for (;;) */
744} /* at91rm9200_emac_rxDaemon() */
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);
757
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 */
780
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
792/* Tests to see if at91rm9200_emac interrupts are enabled, and
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
803at91rm9200_emac_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data)
804{
805    at91rm9200_emac_softc_t *sc = ifp->if_softc;
806    int error = 0;
807
808    switch (command) {
809    case SIOCGIFADDR:
810    case SIOCSIFADDR:
811        ether_ioctl (ifp, command, data);
812        break;
813
814    case SIOCSIFFLAGS:
815        switch (ifp->if_flags & (IFF_UP | IFF_RUNNING))
816        {
817        case IFF_RUNNING:
818            at91rm9200_emac_stop (sc);
819            break;
820
821        case IFF_UP:
822            at91rm9200_emac_init (sc);
823            break;
824
825        case IFF_UP | IFF_RUNNING:
826            at91rm9200_emac_stop (sc);
827            at91rm9200_emac_init (sc);
828            break;
829
830        default:
831            break;
832        } /* switch (if_flags) */
833        break;
834
835    case SIO_RTEMS_SHOW_STATS:
836        at91rm9200_emac_stats (sc);
837        break;
838
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;
853
854    /* get the ISR status and determine RX or TX */
855    status32 = EMAC_REG(EMAC_ISR);
856
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    }
861
862    if (status32 & (EMAC_INT_RCOM |    /* Receive complete */
863                    EMAC_INT_RBNA |    /* Receive buffer not available */
864                    EMAC_INT_ROVR)) {  /* Receive overrun */
865
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 */
870
871        rtems_event_send (softc.rxDaemonTid, START_RECEIVE_EVENT);
872    }
873
874    if (status32 & EMAC_INT_TCOM) {      /* Transmit buffer register empty */
875
876        /* disable the TX interrupts */
877        EMAC_REG(EMAC_IDR) = EMAC_INT_TCOM;
878
879        rtems_event_send (softc.txDaemonTid, START_TRANSMIT_EVENT);
880    }
881}
882
Note: See TracBrowser for help on using the repository browser.