source: rtems/c/src/lib/libbsp/m68k/uC5282/network/network.c @ 721fe34

4.11
Last change on this file since 721fe34 was 721fe34, checked in by Joel Sherrill <joel.sherrill@…>, on May 31, 2012 at 8:34:36 PM

Fix C files which had two semi-colons at EOL

  • Property mode set to 100644
File size: 31.1 KB
Line 
1/*
2 * RTEMS driver for MCF5282 Fast Ethernet Controller
3 *
4 *  Author: W. Eric Norum <norume@aps.anl.gov>
5 *
6 *  COPYRIGHT (c) 2005.
7 *  On-Line Applications Research Corporation (OAR).
8 *
9 *  The license and distribution terms for this file may be
10 *  found in the file LICENSE in this distribution or at
11 *  http://www.rtems.com/license/LICENSE.
12 */
13
14#include <bsp.h>
15#include <stdio.h>
16#include <errno.h>
17#include <stdarg.h>
18#include <string.h>
19#include <rtems.h>
20#include <rtems/error.h>
21#include <rtems/rtems_bsdnet.h>
22
23#include <sys/param.h>
24#include <sys/mbuf.h>
25#include <sys/socket.h>
26#include <sys/sockio.h>
27
28#include <net/ethernet.h>
29#include <net/if.h>
30
31#include <netinet/in.h>
32#include <netinet/if_ether.h>
33
34
35/*
36 * Number of interfaces supported by this driver
37 */
38#define NIFACES 1
39
40#define FEC_INTC0_TX_VECTOR (64+23)
41#define FEC_INTC0_RX_VECTOR (64+27)
42#define MII_VECTOR (64+7)  /* IRQ7* pin connected to external transceiver */
43#define MII_EPPAR  MCF5282_EPORT_EPPAR_EPPA7_LEVEL
44#define MII_EPDDR  MCF5282_EPORT_EPDDR_EPDD7
45#define MII_EPIER  MCF5282_EPORT_EPIER_EPIE7
46#define MII_EPPDR  MCF5282_EPORT_EPPDR_EPPD7
47
48/*
49 * Default number of buffer descriptors set aside for this driver.
50 * The number of transmit buffer descriptors has to be quite large
51 * since a single frame often uses three or more buffer descriptors.
52 */
53#define RX_BUF_COUNT     32
54#define TX_BUF_COUNT     20
55#define TX_BD_PER_BUF    3
56
57#define INET_ADDR_MAX_BUF_SIZE (sizeof "255.255.255.255")
58
59/*
60 * RTEMS event used by interrupt handler to signal daemons.
61 * This must *not* be the same event used by the TCP/IP task synchronization.
62 */
63#define TX_INTERRUPT_EVENT RTEMS_EVENT_1
64#define RX_INTERRUPT_EVENT RTEMS_EVENT_1
65
66/*
67 * RTEMS event used to start transmit daemon.
68 * This must not be the same as INTERRUPT_EVENT.
69 */
70#define START_TRANSMIT_EVENT RTEMS_EVENT_2
71
72/*
73 * Receive buffer size -- Allow for a full ethernet packet plus CRC (1518).
74 * Round off to nearest multiple of RBUF_ALIGN.
75 */
76#define MAX_MTU_SIZE    1518
77#define RBUF_ALIGN      4
78#define RBUF_SIZE       ((MAX_MTU_SIZE + RBUF_ALIGN) & ~RBUF_ALIGN)
79
80#if (MCLBYTES < RBUF_SIZE)
81    #error "Driver must have MCLBYTES > RBUF_SIZE"
82#endif
83
84/*
85 * Per-device data
86 */
87struct mcf5282_enet_struct {
88    struct arpcom               arpcom;
89    struct mbuf                 **rxMbuf;
90    struct mbuf                 **txMbuf;
91    int                         acceptBroadcast;
92    int                         rxBdCount;
93    int                         txBdCount;
94    int                         txBdHead;
95    int                         txBdTail;
96    int                         txBdActiveCount;
97    mcf5282BufferDescriptor_t  *rxBdBase;
98    mcf5282BufferDescriptor_t  *txBdBase;
99    rtems_id                    rxDaemonTid;
100    rtems_id                    txDaemonTid;
101
102    /*
103     * Statistics
104     */
105    unsigned long   rxInterrupts;
106    unsigned long   txInterrupts;
107    unsigned long   miiInterrupts;
108    unsigned long   txRawWait;
109    unsigned long   txRealign;
110    unsigned long   txRealignDrop;
111
112    /*
113     * Link parameters
114     */
115    enum            { link_auto, link_100Full, link_10Half } link;
116    uint16_t        mii_cr;
117    uint16_t        mii_sr2;
118};
119static struct mcf5282_enet_struct enet_driver[NIFACES];
120
121/*
122 * Read MII register
123 * Busy-waits, but transfer time should be short!
124 */
125static int
126getMII(int phyNumber, int regNumber)
127{
128    MCF5282_FEC_MMFR = (0x1 << 30)       |
129                       (0x2 << 28)       |
130                       (phyNumber << 23) |
131                       (regNumber << 18) |
132                       (0x2 << 16);
133    while ((MCF5282_FEC_EIR & MCF5282_FEC_EIR_MII) == 0);
134    MCF5282_FEC_EIR = MCF5282_FEC_EIR_MII;
135    return MCF5282_FEC_MMFR & 0xFFFF;
136}
137
138/*
139 * Write MII register
140 * Busy-waits, but transfer time should be short!
141 */
142static void
143setMII(int phyNumber, int regNumber, int value)
144{
145    MCF5282_FEC_MMFR = (0x1 << 30)       |
146                       (0x1 << 28)       |
147                       (phyNumber << 23) |
148                       (regNumber << 18) |
149                       (0x2 << 16)       |
150                       (value & 0xFFFF);
151    while ((MCF5282_FEC_EIR & MCF5282_FEC_EIR_MII) == 0);
152    MCF5282_FEC_EIR = MCF5282_FEC_EIR_MII;
153}
154
155static rtems_isr
156mcf5282_fec_rx_interrupt_handler( rtems_vector_number v )
157{
158    MCF5282_FEC_EIR = MCF5282_FEC_EIR_RXF;
159    MCF5282_FEC_EIMR &= ~MCF5282_FEC_EIMR_RXF;
160    enet_driver[0].rxInterrupts++;
161    rtems_event_send(enet_driver[0].rxDaemonTid, RX_INTERRUPT_EVENT);
162}
163
164static rtems_isr
165mcf5282_fec_tx_interrupt_handler( rtems_vector_number v )
166{
167    MCF5282_FEC_EIR = MCF5282_FEC_EIR_TXF;
168    MCF5282_FEC_EIMR &= ~MCF5282_FEC_EIMR_TXF;
169    enet_driver[0].txInterrupts++;
170    rtems_event_send(enet_driver[0].txDaemonTid, TX_INTERRUPT_EVENT);
171}
172
173static rtems_isr
174mcf5282_mii_interrupt_handler( rtems_vector_number v )
175{
176    uint16 sr2;
177
178    enet_driver[0].miiInterrupts++;
179    getMII(1, 19); /* Read and clear interrupt status bits */
180    enet_driver[0].mii_sr2 = sr2 = getMII(1, 17);
181    if (((sr2 & 0x200) != 0)
182     && ((MCF5282_FEC_TCR & MCF5282_FEC_TCR_FDEN) == 0))
183        MCF5282_FEC_TCR |= MCF5282_FEC_TCR_FDEN;
184    else if (((sr2 & 0x200) == 0)
185          && ((MCF5282_FEC_TCR & MCF5282_FEC_TCR_FDEN) != 0))
186        MCF5282_FEC_TCR &= ~MCF5282_FEC_TCR_FDEN;
187}
188
189/*
190 * Allocate buffer descriptors from (non-cached) on-chip static RAM
191 * Ensure 128-bit (16-byte) alignment
192 * Allow some space at the beginning for other diagnostic counters
193 */
194static mcf5282BufferDescriptor_t *
195mcf5282_bd_allocate(unsigned int count)
196{
197    static mcf5282BufferDescriptor_t *bdp = __SRAMBASE.fec_descriptors;
198    mcf5282BufferDescriptor_t *p = bdp;
199
200    bdp += count;
201    if ((int)bdp & 0xF)
202        bdp = (mcf5282BufferDescriptor_t *)((char *)bdp + (16 - ((int)bdp & 0xF)));
203    return p;
204}
205
206static void
207mcf5282_fec_initialize_hardware(struct mcf5282_enet_struct *sc)
208{
209    int i;
210    const unsigned char *hwaddr;
211    rtems_status_code status;
212    rtems_isr_entry old_handler;
213        uint32_t clock_speed = bsp_get_CPU_clock_speed();
214
215    /*
216     * Issue reset to FEC
217     */
218    MCF5282_FEC_ECR = MCF5282_FEC_ECR_RESET;
219    rtems_task_wake_after(2);
220    MCF5282_FEC_ECR = 0;
221
222    /*
223     * Configuration of I/O ports is done outside of this function
224     */
225#if 0
226    imm->gpio.pbcnt |= MCF5282_GPIO_PBCNT_SET_FEC;        /* Set up port b FEC pins */
227#endif
228
229    /*
230     * Set our physical address
231     */
232    hwaddr = sc->arpcom.ac_enaddr;
233    MCF5282_FEC_PALR = (hwaddr[0] << 24) | (hwaddr[1] << 16) |
234                       (hwaddr[2] << 8)  | (hwaddr[3] << 0);
235    MCF5282_FEC_PAUR = (hwaddr[4] << 24) | (hwaddr[5] << 16);
236
237
238    /*
239     * Clear the hash table
240     */
241    MCF5282_FEC_GAUR = 0;
242    MCF5282_FEC_GALR = 0;
243
244    /*
245     * Set up receive buffer size
246     */
247    MCF5282_FEC_EMRBR = 1520; /* Standard Ethernet */
248
249    /*
250     * Allocate mbuf pointers
251     */
252    sc->rxMbuf = malloc(sc->rxBdCount * sizeof *sc->rxMbuf, M_MBUF, M_NOWAIT);
253    sc->txMbuf = malloc(sc->txBdCount * sizeof *sc->txMbuf, M_MBUF, M_NOWAIT);
254    if (!sc->rxMbuf || !sc->txMbuf)
255        rtems_panic("No memory for mbuf pointers");
256
257    /*
258     * Set receiver and transmitter buffer descriptor bases
259     */
260    sc->rxBdBase = mcf5282_bd_allocate(sc->rxBdCount);
261    sc->txBdBase = mcf5282_bd_allocate(sc->txBdCount);
262    MCF5282_FEC_ERDSR = (int)sc->rxBdBase;
263    MCF5282_FEC_ETDSR = (int)sc->txBdBase;
264
265    /*
266     * Set up Receive Control Register:
267     *   Not promiscuous
268     *   MII mode
269     *   Full duplex
270     *   No loopback
271     */
272    MCF5282_FEC_RCR = MCF5282_FEC_RCR_MAX_FL(MAX_MTU_SIZE) |
273                      MCF5282_FEC_RCR_MII_MODE;
274
275    /*
276     * Set up Transmit Control Register:
277     *   Full or half duplex
278     *   No heartbeat
279     */
280    if (sc->link == link_10Half)
281        MCF5282_FEC_TCR = 0;
282    else
283    MCF5282_FEC_TCR = MCF5282_FEC_TCR_FDEN;
284
285    /*
286     * Initialize statistic counters
287     */
288    MCF5282_FEC_MIBC = MCF5282_FEC_MIBC_MIB_DISABLE;
289    {
290    vuint32 *vuip = &MCF5282_FEC_RMON_T_DROP;
291    while (vuip <= &MCF5282_FEC_IEEE_R_OCTETS_OK)
292        *vuip++ = 0;
293    }
294    MCF5282_FEC_MIBC = 0;
295
296    /*
297     * Set MII speed to <= 2.5 MHz
298     */
299    i = (clock_speed + 5000000 - 1) / 5000000;
300    MCF5282_FEC_MSCR = MCF5282_FEC_MSCR_MII_SPEED(i);
301
302    /*
303     * Set PHYS
304     *  LED1 receive status, LED2 link status, LEDs stretched
305     *  Advertise 100 Mb/s, full-duplex, IEEE-802.3
306     *  Turn off auto-negotiate
307     *  Clear status
308     */
309    setMII(1, 20, 0x24F2);
310    setMII(1,  4, 0x0181);
311    setMII(1,  0, 0x0);
312    rtems_task_wake_after(2);
313    sc->mii_sr2 = getMII(1, 17);
314    switch (sc->link) {
315    case link_auto:
316        /*
317         * Enable speed-change, duplex-change and link-status-change interrupts
318         * Enable auto-negotiate (start at 100/FULL)
319         */
320    setMII(1, 18, 0x0072);
321        setMII(1, 0, 0x3100);
322        break;
323
324    case link_10Half:
325        /*
326         * Force 10/HALF
327         */
328        setMII(1, 0, 0x0);
329        break;
330
331    case link_100Full:
332        /*
333         * Force 100/FULL
334         */
335        setMII(1, 0, 0x2100);
336        break;
337    }
338    sc->mii_cr = getMII(1, 0);
339
340    /*
341     * Set up receive buffer descriptors
342     */
343    for (i = 0 ; i < sc->rxBdCount ; i++)
344        (sc->rxBdBase + i)->status = 0;
345
346    /*
347     * Set up transmit buffer descriptors
348     */
349    for (i = 0 ; i < sc->txBdCount ; i++) {
350        sc->txBdBase[i].status = 0;
351        sc->txMbuf[i] = NULL;
352    }
353    sc->txBdHead = sc->txBdTail = 0;
354    sc->txBdActiveCount = 0;
355
356    /*
357     * Set up interrupts
358     */
359    status = rtems_interrupt_catch( mcf5282_fec_tx_interrupt_handler, FEC_INTC0_TX_VECTOR, &old_handler );
360    if (status != RTEMS_SUCCESSFUL)
361        rtems_panic ("Can't attach MCF5282 FEC TX interrupt handler: %s\n",
362                                                 rtems_status_text(status));
363    bsp_allocate_interrupt(FEC_IRQ_LEVEL, FEC_IRQ_TX_PRIORITY);
364    MCF5282_INTC0_ICR23 = MCF5282_INTC_ICR_IL(FEC_IRQ_LEVEL) |
365                          MCF5282_INTC_ICR_IP(FEC_IRQ_TX_PRIORITY);
366    MCF5282_INTC0_IMRL &= ~(MCF5282_INTC_IMRL_INT23 | MCF5282_INTC_IMRL_MASKALL);
367
368    status = rtems_interrupt_catch(mcf5282_fec_rx_interrupt_handler, FEC_INTC0_RX_VECTOR, &old_handler);
369    if (status != RTEMS_SUCCESSFUL)
370        rtems_panic ("Can't attach MCF5282 FEC RX interrupt handler: %s\n",
371                                                 rtems_status_text(status));
372    bsp_allocate_interrupt(FEC_IRQ_LEVEL, FEC_IRQ_RX_PRIORITY);
373    MCF5282_INTC0_ICR27 = MCF5282_INTC_ICR_IL(FEC_IRQ_LEVEL) |
374                          MCF5282_INTC_ICR_IP(FEC_IRQ_RX_PRIORITY);
375    MCF5282_INTC0_IMRL &= ~(MCF5282_INTC_IMRL_INT27 | MCF5282_INTC_IMRL_MASKALL);
376
377    status = rtems_interrupt_catch(mcf5282_mii_interrupt_handler, MII_VECTOR, &old_handler);
378    if (status != RTEMS_SUCCESSFUL)
379        rtems_panic ("Can't attach MCF5282 FEC MII interrupt handler: %s\n",
380                                                 rtems_status_text(status));
381    MCF5282_EPORT_EPPAR &= ~MII_EPPAR;
382    MCF5282_EPORT_EPDDR &= ~MII_EPDDR;
383    MCF5282_EPORT_EPIER |=  MII_EPIER;
384    MCF5282_INTC0_IMRL &= ~(MCF5282_INTC_IMRL_INT7 | MCF5282_INTC_IMRL_MASKALL);
385}
386
387/*
388 * Soak up buffer descriptors that have been sent.
389 */
390static void
391fec_retire_tx_bd(volatile struct mcf5282_enet_struct *sc )
392{
393    struct mbuf *m, *n;
394    uint16_t status;
395
396    while ((sc->txBdActiveCount != 0)
397        && (((status = sc->txBdBase[sc->txBdTail].status) & MCF5282_FEC_TxBD_R) == 0)) {
398        if ((status & MCF5282_FEC_TxBD_TO1) == 0) {
399            m = sc->txMbuf[sc->txBdTail];
400            MFREE(m, n);
401        }
402        if (++sc->txBdTail == sc->txBdCount)
403            sc->txBdTail = 0;
404        sc->txBdActiveCount--;
405    }
406}
407
408static void
409fec_rxDaemon (void *arg)
410{
411    volatile struct mcf5282_enet_struct *sc = (volatile struct mcf5282_enet_struct *)arg;
412    struct ifnet *ifp = (struct ifnet* )&sc->arpcom.ac_if;
413    struct mbuf *m;
414    uint16_t status;
415    volatile mcf5282BufferDescriptor_t *rxBd;
416    int rxBdIndex;
417
418    /*
419     * Allocate space for incoming packets and start reception
420     */
421    for (rxBdIndex = 0 ; ;) {
422        rxBd = sc->rxBdBase + rxBdIndex;
423        MGETHDR(m, M_WAIT, MT_DATA);
424        MCLGET(m, M_WAIT);
425        m->m_pkthdr.rcvif = ifp;
426        sc->rxMbuf[rxBdIndex] = m;
427        rxBd->buffer = mtod(m, void *);
428        rxBd->status = MCF5282_FEC_RxBD_E;
429        if (++rxBdIndex == sc->rxBdCount) {
430            rxBd->status |= MCF5282_FEC_RxBD_W;
431            break;
432        }
433    }
434
435    /*
436     * Input packet handling loop
437     */
438    MCF5282_FEC_RDAR = 0;
439
440    rxBdIndex = 0;
441    for (;;) {
442        rxBd = sc->rxBdBase + rxBdIndex;
443
444        /*
445         * Wait for packet if there's not one ready
446         */
447        if ((status = rxBd->status) & MCF5282_FEC_RxBD_E) {
448            /*
449             * Clear old events.
450             */
451            MCF5282_FEC_EIR = MCF5282_FEC_EIR_RXF;
452
453            /*
454             * Wait for packet to arrive.
455             * Check the buffer descriptor before waiting for the event.
456             * This catches the case when a packet arrives between the
457             * `if' above, and the clearing of the RXF bit in the EIR.
458             */
459            while ((status = rxBd->status) & MCF5282_FEC_RxBD_E) {
460                rtems_event_set events;
461                int level;
462
463                rtems_interrupt_disable(level);
464                MCF5282_FEC_EIMR |= MCF5282_FEC_EIMR_RXF;
465                rtems_interrupt_enable(level);
466                rtems_bsdnet_event_receive (RX_INTERRUPT_EVENT,
467                                            RTEMS_WAIT|RTEMS_EVENT_ANY,
468                                            RTEMS_NO_TIMEOUT,
469                                            &events);
470            }
471        }
472
473        /*
474         * Check that packet is valid
475         */
476        if (status & MCF5282_FEC_RxBD_L) {
477            /*
478             * Pass the packet up the chain.
479             * FIXME: Packet filtering hook could be done here.
480             */
481            struct ether_header *eh;
482            int len = rxBd->length - sizeof(uint32_t);
483
484            m = sc->rxMbuf[rxBdIndex];
485#ifdef RTEMS_MCF5282_BSP_ENABLE_DATA_CACHE
486            /*
487             * Invalidate the cache.  The cache is so small that it's
488             * reasonable to simply invalidate the whole thing.
489             */
490            rtems_cache_invalidate_entire_data();
491#endif
492            m->m_len = m->m_pkthdr.len = len - sizeof(struct ether_header);
493            eh = mtod(m, struct ether_header *);
494            m->m_data += sizeof(struct ether_header);
495            ether_input(ifp, eh, m);
496
497            /*
498             * Allocate a new mbuf
499             */
500            MGETHDR(m, M_WAIT, MT_DATA);
501            MCLGET(m, M_WAIT);
502            m->m_pkthdr.rcvif = ifp;
503            sc->rxMbuf[rxBdIndex] = m;
504            rxBd->buffer = mtod(m, void *);
505        }
506
507        /*
508         * Reenable the buffer descriptor
509         */
510        rxBd->status = (status & MCF5282_FEC_RxBD_W) | MCF5282_FEC_RxBD_E;
511        MCF5282_FEC_RDAR = 0;
512
513        /*
514         * Move to next buffer descriptor
515         */
516        if (++rxBdIndex == sc->rxBdCount)
517            rxBdIndex = 0;
518    }
519}
520
521static void
522fec_sendpacket(struct ifnet *ifp, struct mbuf *m)
523{
524    struct mcf5282_enet_struct *sc = ifp->if_softc;
525    volatile mcf5282BufferDescriptor_t *firstTxBd, *txBd;
526    uint16_t status;
527    int nAdded;
528
529   /*
530     * Free up buffer descriptors
531     */
532    fec_retire_tx_bd(sc);
533
534    /*
535     * Set up the transmit buffer descriptors.
536     * No need to pad out short packets since the
537     * hardware takes care of that automatically.
538     * No need to copy the packet to a contiguous buffer
539     * since the hardware is capable of scatter/gather DMA.
540     */
541    nAdded = 0;
542    firstTxBd = sc->txBdBase + sc->txBdHead;
543
544    while (m != NULL) {
545        /*
546         * Wait for buffer descriptor to become available
547         */
548        if ((sc->txBdActiveCount + nAdded)  == sc->txBdCount) {
549            /*
550             * Clear old events.
551             */
552            MCF5282_FEC_EIR = MCF5282_FEC_EIR_TXF;
553
554            /*
555             * Wait for buffer descriptor to become available.
556             * Check for buffer descriptors before waiting for the event.
557             * This catches the case when a buffer became available between
558             * the `if' above, and the clearing of the TXF bit in the EIR.
559             */
560            fec_retire_tx_bd(sc);
561            while ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
562                rtems_event_set events;
563                int level;
564
565                rtems_interrupt_disable(level);
566                MCF5282_FEC_EIMR |= MCF5282_FEC_EIMR_TXF;
567                rtems_interrupt_enable(level);
568                sc->txRawWait++;
569                rtems_bsdnet_event_receive(TX_INTERRUPT_EVENT,
570                                           RTEMS_WAIT|RTEMS_EVENT_ANY,
571                                           RTEMS_NO_TIMEOUT,
572                                           &events);
573                fec_retire_tx_bd(sc);
574            }
575        }
576
577        /*
578         * Don't set the READY flag on the first fragment
579         * until the whole packet has been readied.
580         */
581        status = nAdded ? MCF5282_FEC_TxBD_R : 0;
582
583        /*
584         * The IP fragmentation routine in ip_output
585         * can produce fragments with zero length.
586         */
587        txBd = sc->txBdBase + sc->txBdHead;
588        if (m->m_len) {
589            char *p = mtod(m, char *);
590            int offset = (int)p & 0x3;
591            if (offset == 0) {
592                txBd->buffer = p;
593                txBd->length = m->m_len;
594                sc->txMbuf[sc->txBdHead] = m;
595                m = m->m_next;
596            }
597            else {
598                /*
599                 * Stupid FEC can't handle misaligned data!
600                 * Move offending bytes to a local buffer.
601                 * Use buffer descriptor TO1 bit to indicate this.
602                 */
603                int nmove = 4 - offset;
604                char *d = (char *)&sc->txMbuf[sc->txBdHead];
605                status |= MCF5282_FEC_TxBD_TO1;
606                sc->txRealign++;
607                if (nmove > m->m_len)
608                    nmove = m->m_len;
609                m->m_data += nmove;
610                m->m_len -= nmove;
611                txBd->buffer = d;
612                txBd->length = nmove;
613                while (nmove--)
614                    *d++ = *p++;
615                if (m->m_len == 0) {
616                    struct mbuf *n;
617                    sc->txRealignDrop++;
618                    MFREE(m, n);
619                    m = n;
620                }
621            }
622            nAdded++;
623            if (++sc->txBdHead == sc->txBdCount) {
624                status |= MCF5282_FEC_TxBD_W;
625                sc->txBdHead = 0;
626            }
627            txBd->status = status;
628        }
629        else {
630            /*
631             * Toss empty mbufs.
632             */
633            struct mbuf *n;
634            MFREE(m, n);
635            m = n;
636        }
637    }
638    if (nAdded) {
639        txBd->status = status | MCF5282_FEC_TxBD_R
640                              | MCF5282_FEC_TxBD_L
641                              | MCF5282_FEC_TxBD_TC;
642        if (nAdded > 1)
643            firstTxBd->status |= MCF5282_FEC_TxBD_R;
644        MCF5282_FEC_TDAR = 0;
645        sc->txBdActiveCount += nAdded;
646      }
647}
648
649void
650fec_txDaemon(void *arg)
651{
652    struct mcf5282_enet_struct *sc = (struct mcf5282_enet_struct *)arg;
653    struct ifnet *ifp = &sc->arpcom.ac_if;
654    struct mbuf *m;
655    rtems_event_set events;
656
657    for (;;) {
658        /*
659         * Wait for packet
660         */
661        rtems_bsdnet_event_receive(START_TRANSMIT_EVENT,
662                                    RTEMS_EVENT_ANY | RTEMS_WAIT,
663                                    RTEMS_NO_TIMEOUT,
664                                    &events);
665
666        /*
667         * Send packets till queue is empty
668         */
669        for (;;) {
670            /*
671             * Get the next mbuf chain to transmit.
672             */
673            IF_DEQUEUE(&ifp->if_snd, m);
674            if (!m)
675                break;
676            fec_sendpacket(ifp, m);
677        }
678        ifp->if_flags &= ~IFF_OACTIVE;
679    }
680}
681
682
683/*
684 * Send packet (caller provides header).
685 */
686static void
687mcf5282_enet_start(struct ifnet *ifp)
688{
689    struct mcf5282_enet_struct *sc = ifp->if_softc;
690
691    rtems_event_send(sc->txDaemonTid, START_TRANSMIT_EVENT);
692    ifp->if_flags |= IFF_OACTIVE;
693}
694
695static void
696fec_init(void *arg)
697{
698    struct mcf5282_enet_struct *sc = arg;
699    struct ifnet *ifp = &sc->arpcom.ac_if;
700
701    if (sc->txDaemonTid == 0) {
702        /*
703         * Set up hardware
704         */
705        mcf5282_fec_initialize_hardware(sc);
706
707        /*
708         * Start driver tasks
709         */
710        sc->txDaemonTid = rtems_bsdnet_newproc("FECtx", 4096, fec_txDaemon, sc);
711        sc->rxDaemonTid = rtems_bsdnet_newproc("FECrx", 4096, fec_rxDaemon, sc);
712    }
713
714    /*
715     * Set flags appropriately
716     */
717    if (ifp->if_flags & IFF_PROMISC)
718        MCF5282_FEC_RCR |= MCF5282_FEC_RCR_PROM;
719    else
720        MCF5282_FEC_RCR &= ~MCF5282_FEC_RCR_PROM;
721
722    /*
723     * Tell the world that we're running.
724     */
725    ifp->if_flags |= IFF_RUNNING;
726
727    /*
728     * Enable receiver and transmitter
729     */
730    MCF5282_FEC_ECR = MCF5282_FEC_ECR_ETHER_EN;
731}
732
733
734static void
735fec_stop(struct mcf5282_enet_struct *sc)
736{
737    struct ifnet *ifp = &sc->arpcom.ac_if;
738
739    ifp->if_flags &= ~IFF_RUNNING;
740
741    /*
742     * Shut down receiver and transmitter
743     */
744    MCF5282_FEC_ECR = 0x0;
745}
746
747/*
748 * Show interface statistics
749 */
750static void
751enet_stats(struct mcf5282_enet_struct *sc)
752{
753  printf("  Rx Interrupts:%-10lu",   sc->rxInterrupts);
754  printf("Rx Packet Count:%-10lu",   (uint32_t) MCF5282_FEC_RMON_R_PACKETS);
755  printf("   Rx Broadcast:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_R_BC_PKT);
756  printf("   Rx Multicast:%-10lu",   (uint32_t) MCF5282_FEC_RMON_R_MC_PKT);
757  printf("CRC/Align error:%-10lu",   (uint32_t) MCF5282_FEC_RMON_R_CRC_ALIGN);
758  printf("   Rx Undersize:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_R_UNDERSIZE);
759  printf("    Rx Oversize:%-10lu",   (uint32_t) MCF5282_FEC_RMON_R_OVERSIZE);
760  printf("    Rx Fragment:%-10lu",   (uint32_t) MCF5282_FEC_RMON_R_FRAG);
761  printf("      Rx Jabber:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_R_JAB);
762  printf("          Rx 64:%-10lu",   (uint32_t) MCF5282_FEC_RMON_R_P64);
763  printf("      Rx 65-127:%-10lu",   (uint32_t) MCF5282_FEC_RMON_R_P65T0127);
764  printf("     Rx 128-255:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_R_P128TO255);
765  printf("     Rx 256-511:%-10lu",   (uint32_t) MCF5282_FEC_RMON_R_P256TO511);
766  printf("    Rx 511-1023:%-10lu",   (uint32_t) MCF5282_FEC_RMON_R_P512TO1023);
767  printf("   Rx 1024-2047:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_R_P1024TO2047);
768  printf("      Rx >=2048:%-10lu",   (uint32_t) MCF5282_FEC_RMON_R_GTE2048);
769  printf("      Rx Octets:%-10lu",   (uint32_t) MCF5282_FEC_RMON_R_OCTETS);
770  printf("     Rx Dropped:%-10lu\n", (uint32_t) MCF5282_FEC_IEEE_R_DROP);
771  printf("    Rx frame OK:%-10lu",   (uint32_t) MCF5282_FEC_IEEE_R_FRAME_OK);
772  printf("   Rx CRC error:%-10lu",   (uint32_t) MCF5282_FEC_IEEE_R_CRC);
773  printf(" Rx Align error:%-10lu\n", (uint32_t) MCF5282_FEC_IEEE_R_ALIGN);
774  printf("  FIFO Overflow:%-10lu",   (uint32_t) MCF5282_FEC_IEEE_R_MACERR);
775  printf("Rx Pause Frames:%-10lu",   (uint32_t) MCF5282_FEC_IEEE_R_FDXFC);
776  printf("   Rx Octets OK:%-10lu\n", (uint32_t) MCF5282_FEC_IEEE_R_OCTETS_OK);
777  printf("  Tx Interrupts:%-10lu",   sc->txInterrupts);
778  printf("Tx Output Waits:%-10lu",   sc->txRawWait);
779  printf("Tx mbuf realign:%-10lu\n", sc->txRealign);
780  printf("Tx realign drop:%-10lu",   sc->txRealignDrop);
781  printf(" Tx Unaccounted:%-10lu",   (uint32_t) MCF5282_FEC_RMON_T_DROP);
782  printf("Tx Packet Count:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_T_PACKETS);
783  printf("   Tx Broadcast:%-10lu",   (uint32_t) MCF5282_FEC_RMON_T_BC_PKT);
784  printf("   Tx Multicast:%-10lu",   (uint32_t) MCF5282_FEC_RMON_T_MC_PKT);
785  printf("CRC/Align error:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_T_CRC_ALIGN);
786  printf("   Tx Undersize:%-10lu",   (uint32_t) MCF5282_FEC_RMON_T_UNDERSIZE);
787  printf("    Tx Oversize:%-10lu",   (uint32_t) MCF5282_FEC_RMON_T_OVERSIZE);
788  printf("    Tx Fragment:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_T_FRAG);
789  printf("      Tx Jabber:%-10lu",   (uint32_t) MCF5282_FEC_RMON_T_JAB);
790  printf("  Tx Collisions:%-10lu",   (uint32_t) MCF5282_FEC_RMON_T_COL);
791  printf("          Tx 64:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_T_P64);
792  printf("      Tx 65-127:%-10lu",   (uint32_t) MCF5282_FEC_RMON_T_P65TO127);
793  printf("     Tx 128-255:%-10lu",   (uint32_t) MCF5282_FEC_RMON_T_P128TO255);
794  printf("     Tx 256-511:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_T_P256TO511);
795  printf("    Tx 511-1023:%-10lu",   (uint32_t) MCF5282_FEC_RMON_T_P512TO1023);
796  printf("   Tx 1024-2047:%-10lu",   (uint32_t) MCF5282_FEC_RMON_T_P1024TO2047);
797  printf("      Tx >=2048:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_T_P_GTE2048);
798  printf("      Tx Octets:%-10lu",   (uint32_t) MCF5282_FEC_RMON_T_OCTETS);
799  printf("     Tx Dropped:%-10lu",   (uint32_t) MCF5282_FEC_IEEE_T_DROP);
800  printf("    Tx Frame OK:%-10lu\n", (uint32_t) MCF5282_FEC_IEEE_T_FRAME_OK);
801  printf(" Tx 1 Collision:%-10lu",   (uint32_t) MCF5282_FEC_IEEE_T_1COL);
802  printf("Tx >1 Collision:%-10lu",   (uint32_t) MCF5282_FEC_IEEE_T_MCOL);
803  printf("    Tx Deferred:%-10lu\n", (uint32_t) MCF5282_FEC_IEEE_T_DEF);
804  printf(" Late Collision:%-10lu",   (uint32_t) MCF5282_FEC_IEEE_T_LCOL);
805  printf(" Excessive Coll:%-10lu",   (uint32_t) MCF5282_FEC_IEEE_T_EXCOL);
806  printf("  FIFO Underrun:%-10lu\n", (uint32_t) MCF5282_FEC_IEEE_T_MACERR);
807  printf("  Carrier Error:%-10lu",   (uint32_t) MCF5282_FEC_IEEE_T_CSERR);
808  printf("   Tx SQE Error:%-10lu",   (uint32_t) MCF5282_FEC_IEEE_T_SQE);
809  printf("Tx Pause Frames:%-10lu\n", (uint32_t) MCF5282_FEC_IEEE_T_FDXFC);
810  printf("   Tx Octets OK:%-10lu",   (uint32_t) MCF5282_FEC_IEEE_T_OCTETS_OK);
811  printf(" MII interrupts:%-10lu\n", sc->miiInterrupts);
812  if ((sc->mii_sr2 & 0x400) == 0) {
813      printf("LINK DOWN!\n");
814  }
815  else {
816      int speed;
817      int full;
818      int fixed;
819      if (sc->mii_cr & 0x1000) {
820          fixed = 0;
821          speed = sc->mii_sr2 & 0x4000 ? 100 : 10;
822          full = sc->mii_sr2 & 0x200 ? 1 : 0;
823      }
824      else {
825          fixed = 1;
826          speed = sc->mii_cr & 0x2000 ? 100 : 10;
827          full = sc->mii_cr & 0x100 ? 1 : 0;
828      }
829      printf("Link %s %d Mb/s, %s-duplex.\n",
830                                          fixed ? "fixed" : "auto-negotiate",
831                                          speed,
832                                          full ? "full" : "half");
833  }
834  printf(" EIR:%8.8lx  ",  (uint32_t) MCF5282_FEC_EIR);
835  printf("EIMR:%8.8lx  ",  (uint32_t) MCF5282_FEC_EIMR);
836  printf("RDAR:%8.8lx  ",  (uint32_t) MCF5282_FEC_RDAR);
837  printf("TDAR:%8.8lx\n",  (uint32_t) MCF5282_FEC_TDAR);
838  printf(" ECR:%8.8lx  ",  (uint32_t) MCF5282_FEC_ECR);
839  printf(" RCR:%8.8lx  ",  (uint32_t) MCF5282_FEC_RCR);
840  printf(" TCR:%8.8lx\n",  (uint32_t) MCF5282_FEC_TCR);
841  printf("FRBR:%8.8lx  ",  (uint32_t) MCF5282_FEC_FRBR);
842  printf("FRSR:%8.8lx\n",  (uint32_t) MCF5282_FEC_FRSR);
843  if (sc->txBdActiveCount != 0) {
844      int i, n;
845      /*
846       * Yes, there are races here with adding and retiring descriptors,
847       * but this diagnostic is more for when things have backed up.
848       */
849      printf("Transmit Buffer Descriptors (Tail %d, Head %d, Unretired %d):\n",
850                                                  sc->txBdTail,
851                                                  sc->txBdHead,
852                                                  sc->txBdActiveCount);
853      i = sc->txBdTail;
854      for (n = 0 ; n < sc->txBdCount ; n++) {
855          if ((sc->txBdBase[i].status & MCF5282_FEC_TxBD_R) != 0)
856              printf("  %3d: status:%4.4x  length:%-4d  buffer:%p\n",
857                                                  i,
858                                                  sc->txBdBase[i].status,
859                                                  sc->txBdBase[i].length,
860                                                  sc->txBdBase[i].buffer);
861          if (++i == sc->txBdCount)
862              i = 0;
863      }
864  }
865}
866
867static int
868fec_ioctl(struct ifnet *ifp, ioctl_command_t command, caddr_t data)
869{
870    struct mcf5282_enet_struct *sc = ifp->if_softc;
871    int error = 0;
872
873    switch (command) {
874        case SIOCGIFADDR:
875        case SIOCSIFADDR:
876            ether_ioctl(ifp, command, data);
877            break;
878
879        case SIOCSIFFLAGS:
880            switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
881                case IFF_RUNNING:
882                    fec_stop(sc);
883                    break;
884
885                case IFF_UP:
886                    fec_init(sc);
887                    break;
888
889                case IFF_UP | IFF_RUNNING:
890                    fec_stop(sc);
891                    fec_init(sc);
892                    break;
893
894                default:
895                    break;
896            }
897            break;
898
899        case SIO_RTEMS_SHOW_STATS:
900            enet_stats(sc);
901            break;
902
903            /*
904             * FIXME: All sorts of multicast commands need to be added here!
905             */
906        default:
907            error = EINVAL;
908            break;
909    }
910    return error;
911}
912
913int
914rtems_fec_driver_attach(struct rtems_bsdnet_ifconfig *config, int attaching )
915{
916    struct mcf5282_enet_struct *sc;
917    struct ifnet *ifp;
918    int mtu;
919    int unitNumber;
920    char *unitName;
921    const unsigned char *hwaddr;
922    const char *env;
923
924    /*
925     * Parse driver name
926     */
927    if ((unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName)) < 0)
928        return 0;
929
930    /*
931     * Is driver free?
932     */
933    if ((unitNumber <= 0) || (unitNumber > NIFACES)) {
934        printf("Bad FEC unit number.\n");
935        return 0;
936    }
937    sc = &enet_driver[unitNumber - 1];
938    ifp = &sc->arpcom.ac_if;
939    if (ifp->if_softc != NULL) {
940        printf("Driver already in use.\n");
941        return 0;
942    }
943
944    /*
945     * Process options
946     */
947    if (config->hardware_address) {
948        hwaddr = config->hardware_address;
949    } else if ((hwaddr = bsp_gethwaddr(unitNumber - 1)) == NULL) {
950        /* Locally-administered address */
951        static const unsigned char defaultAddress[ETHER_ADDR_LEN] = {
952                                        0x06, 'R', 'T', 'E', 'M', 'S'};
953        printf ("WARNING -- No %s%d Ethernet address specified "
954                "-- Using default address.\n", unitName, unitNumber);
955        hwaddr = defaultAddress;
956    }
957    printf("%s%d: Ethernet address: %02x:%02x:%02x:%02x:%02x:%02x\n",
958                                            unitName, unitNumber,
959                                            hwaddr[0], hwaddr[1], hwaddr[2],
960                                            hwaddr[3], hwaddr[4], hwaddr[5]);
961    memcpy(sc->arpcom.ac_enaddr, hwaddr, ETHER_ADDR_LEN);
962
963    if (config->mtu)
964        mtu = config->mtu;
965    else
966        mtu = ETHERMTU;
967    if (config->rbuf_count)
968        sc->rxBdCount = config->rbuf_count;
969    else
970        sc->rxBdCount = RX_BUF_COUNT;
971    if (config->xbuf_count)
972        sc->txBdCount = config->xbuf_count;
973    else
974        sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF;
975
976    sc->acceptBroadcast = !config->ignore_broadcast;
977
978    /*
979     * Set up network interface values
980     */
981    ifp->if_softc = sc;
982    ifp->if_unit = unitNumber;
983    ifp->if_name = unitName;
984    ifp->if_mtu = mtu;
985    ifp->if_init = fec_init;
986    ifp->if_ioctl = fec_ioctl;
987    ifp->if_start = mcf5282_enet_start;
988    ifp->if_output = ether_output;
989    ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
990    if (ifp->if_snd.ifq_maxlen == 0)
991        ifp->if_snd.ifq_maxlen = ifqmaxlen;
992
993    /*
994     * Check for environment overrides
995     */
996    if (((env = bsp_getbenv("IPADDR0_100FULL")) != NULL)
997     && ((*env == 'y') || (*env == 'Y')))
998        sc->link = link_100Full;
999    else if (((env = bsp_getbenv("IPADDR0_10HALF")) != NULL)
1000     && ((*env == 'y') || (*env == 'Y')))
1001        sc->link = link_10Half;
1002    else
1003        sc->link = link_auto;
1004
1005    /*
1006     * Attach the interface
1007     */
1008    if_attach(ifp);
1009    ether_ifattach(ifp);
1010    return 1;
1011};
Note: See TracBrowser for help on using the repository browser.