source: rtems/bsps/arm/csb337/net/network.c @ cb68253

5
Last change on this file since cb68253 was cb68253, checked in by Sebastian Huber <sebastian.huber@…>, on 09/07/18 at 04:19:02

network: Use kernel/user space header files

Add and use <machine/rtems-bsd-kernel-space.h> and
<machine/rtems-bsd-user-space.h> similar to the libbsd to avoid command
line defines and defines scattered throught the code base.

Simplify cpukit/libnetworking/Makefile.am.

Update #3375.

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