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

4.104.114.95
Last change on this file since 9797991 was 9797991, checked in by Eric Norum <WENorum@…>, on 04/08/08 at 03:19:53

startup/bspstart.c: Clean up non-FPGA use of EPORT interrupts.
network/network.c: Track half/full-duplex changes from 4.7 branch.

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