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

5
Last change on this file since a97d77c was a97d77c, checked in by Sebastian Huber <sebastian.huber@…>, on 08/25/17 at 09:00:32

Include missing <rtems/bspIo.h>

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