source: rtems/c/src/lib/libbsp/powerpc/tqm8xx/network/network_fec.c @ 63de714c

4.104.114.95
Last change on this file since 63de714c was 63de714c, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on 09/08/08 at 09:55:39

added new BSP for TQM8xx boards

  • Property mode set to 100644
File size: 24.0 KB
Line 
1/*===============================================================*\
2| Project: RTEMS TQM8xx BSP                                       |
3+-----------------------------------------------------------------+
4| This file has been adapted to MPC8xx by                         |
5|    Thomas Doerfler <Thomas.Doerfler@embedded-brains.de>         |
6|                    Copyright (c) 2008                           |
7|                    Embedded Brains GmbH                         |
8|                    Obere Lagerstr. 30                           |
9|                    D-82178 Puchheim                             |
10|                    Germany                                      |
11|                    rtems@embedded-brains.de                     |
12|                                                                 |
13| See the other copyright notice below for the original parts.    |
14+-----------------------------------------------------------------+
15| The license and distribution terms for this file may be         |
16| found in the file LICENSE in this distribution or at            |
17|                                                                 |
18| http://www.rtems.com/license/LICENSE.                           |
19|                                                                 |
20+-----------------------------------------------------------------+
21| this file contains the console driver                           |
22\*===============================================================*/
23/* derived from: */
24/*
25 * RTEMS/TCPIP driver for MPC8xx Ethernet
26 *
27 * split into separate driver files for SCC and FEC by
28 * Thomas Doerfler <Thomas.Doerfler@embedded-brains.de>
29 *
30 *  Modified for MPC860 by Jay Monkman (jmonkman@frasca.com)
31 *
32 *  This supports Ethernet on either SCC1 or the FEC of the MPC860T.
33 *  Right now, we only do 10 Mbps, even with the FEC. The function
34 *  rtems_enet_driver_attach determines which one to use. Currently,
35 *  only one may be used at a time.
36 *
37 *  Based on the MC68360 network driver by
38 *  W. Eric Norum
39 *  Saskatchewan Accelerator Laboratory
40 *  University of Saskatchewan
41 *  Saskatoon, Saskatchewan, CANADA
42 *  eric@skatter.usask.ca
43 *
44 *  This supports ethernet on SCC1. Right now, we only do 10 Mbps.
45 *
46 *  Modifications by Darlene Stewart <Darlene.Stewart@iit.nrc.ca>
47 *  and Charles-Antoine Gauthier <charles.gauthier@iit.nrc.ca>
48 *  Copyright (c) 1999, National Research Council of Canada
49 *
50 *  $Id$
51 */
52#include <bsp.h>
53#include <stdio.h>
54#include <errno.h>
55#include <rtems/error.h>
56#include <rtems/rtems_bsdnet.h>
57
58#include <sys/param.h>
59#include <sys/mbuf.h>
60#include <sys/socket.h>
61#include <sys/sockio.h>
62
63#include <net/if.h>
64
65#include <netinet/in.h>
66#include <netinet/if_ether.h>
67#include <bsp/irq.h>
68
69#include <sys/types.h>
70#include <sys/socket.h>
71#include <arpa/inet.h>
72
73/*
74 * Number of interfaces supported by this driver
75 */
76#define NIFACES 1
77
78/*
79 * Default number of buffer descriptors set aside for this driver.
80 * The number of transmit buffer descriptors has to be quite large
81 * since a single frame often uses four or more buffer descriptors.
82 */
83#define RX_BUF_COUNT     32
84#define TX_BUF_COUNT     8
85#define TX_BD_PER_BUF    4
86
87#define INET_ADDR_MAX_BUF_SIZE (sizeof "255.255.255.255")
88
89/*
90 * RTEMS event used by interrupt handler to signal daemons.
91 * This must *not* be the same event used by the TCP/IP task synchronization.
92 */
93#define INTERRUPT_EVENT RTEMS_EVENT_1
94
95/*
96 * RTEMS event used to start transmit daemon.
97 * This must not be the same as INTERRUPT_EVENT.
98 */
99#define START_TRANSMIT_EVENT RTEMS_EVENT_2
100
101/*
102 * Receive buffer size -- Allow for a full ethernet packet plus CRC (1518).
103 * Round off to nearest multiple of RBUF_ALIGN.
104 */
105#define MAX_MTU_SIZE    1518
106#define RBUF_ALIGN              4
107#define RBUF_SIZE       ((MAX_MTU_SIZE + RBUF_ALIGN) & ~RBUF_ALIGN)
108
109#if (MCLBYTES < RBUF_SIZE)
110# error "Driver must have MCLBYTES > RBUF_SIZE"
111#endif
112
113/*
114 * Per-device data
115 */
116struct m8xx_fec_enet_struct {
117  struct arpcom           arpcom;
118  struct mbuf             **rxMbuf;
119  struct mbuf             **txMbuf;
120  int                     acceptBroadcast;
121  int                     rxBdCount;
122  int                     txBdCount;
123  int                     txBdHead;
124  int                     txBdTail;
125  int                     txBdActiveCount;
126  m8xxBufferDescriptor_t  *rxBdBase;
127  m8xxBufferDescriptor_t  *txBdBase;
128  rtems_id                rxDaemonTid;
129  rtems_id                txDaemonTid;
130
131  /*
132   * Statistics
133   */
134  unsigned long   rxInterrupts;
135  unsigned long   rxNotFirst;
136  unsigned long   rxNotLast;
137  unsigned long   rxGiant;
138  unsigned long   rxNonOctet;
139  unsigned long   rxRunt;
140  unsigned long   rxBadCRC;
141  unsigned long   rxOverrun;
142  unsigned long   rxCollision;
143
144  unsigned long   txInterrupts;
145  unsigned long   txDeferred;
146  unsigned long   txHeartbeat;
147  unsigned long   txLateCollision;
148  unsigned long   txRetryLimit;
149  unsigned long   txUnderrun;
150  unsigned long   txLostCarrier;
151  unsigned long   txRawWait;
152};
153static struct m8xx_fec_enet_struct enet_driver[NIFACES];
154
155/*
156 * FEC interrupt handler
157 */
158static void m8xx_fec_interrupt_handler ()
159{
160  /*
161   * Frame received?
162   */
163  if (m8xx.fec.ievent & M8xx_FEC_IEVENT_RFINT) {
164    m8xx.fec.ievent = M8xx_FEC_IEVENT_RFINT;
165    enet_driver[0].rxInterrupts++;
166    rtems_event_send (enet_driver[0].rxDaemonTid, INTERRUPT_EVENT);
167  }
168
169  /*
170   * Buffer transmitted or transmitter error?
171   */
172  if (m8xx.fec.ievent & M8xx_FEC_IEVENT_TFINT) {
173    m8xx.fec.ievent = M8xx_FEC_IEVENT_TFINT;
174    enet_driver[0].txInterrupts++;
175    rtems_event_send (enet_driver[0].txDaemonTid, INTERRUPT_EVENT);
176  }
177}
178
179/*
180 * Please organize FEC controller code better by moving code from
181 * m860_fec_initialize_hardware to m8xx_fec_ethernet_on
182 */
183static void m8xx_fec_ethernet_on(){};
184static void m8xx_fec_ethernet_off(){};
185static int m8xx_fec_ethernet_isOn (const rtems_irq_connect_data* ptr)
186{
187  return BSP_irq_enabled_at_siu (ptr->name);
188}
189
190static rtems_irq_connect_data ethernetFECIrqData = {
191  BSP_FAST_ETHERNET_CTRL,
192  (rtems_irq_hdl) m8xx_fec_interrupt_handler,
193  (rtems_irq_enable) m8xx_fec_ethernet_on,
194  (rtems_irq_disable) m8xx_fec_ethernet_off,
195  (rtems_irq_is_enabled)m8xx_fec_ethernet_isOn
196};
197
198static void
199m8xx_fec_initialize_hardware (struct m8xx_fec_enet_struct *sc)
200{
201  int i;
202  unsigned char *hwaddr;
203
204  /*
205   * Issue reset to FEC
206   */
207  m8xx.fec.ecntrl=0x1;
208
209  /*
210   * Put ethernet transciever in reset
211   */
212  m8xx.pgcra |= 0x80;
213
214  /*
215   * Configure I/O ports
216   */
217  m8xx.pdpar = 0x1fff;
218  m8xx.pddir = 0x1c58;
219
220  /*
221   * Take ethernet transciever out of reset
222   */
223  m8xx.pgcra &= ~0x80;
224
225  /*
226   * Set SIU interrupt level to LVL2
227   *
228   */
229  m8xx.fec.ivec = ((((unsigned) BSP_FAST_ETHERNET_CTRL)/2) << 29);
230
231  /*
232   * Set the TX and RX fifo sizes. For now, we'll split it evenly
233   */
234  /* If you uncomment these, the FEC will not work right.
235     m8xx.fec.r_fstart = ((m8xx.fec.r_bound & 0x3ff) >> 2) & 0x3ff;
236     m8xx.fec.x_fstart = 0;
237  */
238
239  /*
240   * Set our physical address
241   */
242  hwaddr = sc->arpcom.ac_enaddr;
243
244  m8xx.fec.addr_low = (hwaddr[0] << 24) | (hwaddr[1] << 16) |
245    (hwaddr[2] << 8)  | (hwaddr[3] << 0);
246  m8xx.fec.addr_high = (hwaddr[4] << 24) | (hwaddr[5] << 16);
247
248  /*
249   * Clear the hash table
250   */
251  m8xx.fec.hash_table_high = 0;
252  m8xx.fec.hash_table_low  = 0;
253
254  /*
255   * Set up receive buffer size
256   */
257  m8xx.fec.r_buf_size = 0x5f0; /* set to 1520 */
258
259  /*
260   * Allocate mbuf pointers
261   */
262  sc->rxMbuf = malloc (sc->rxBdCount * sizeof *sc->rxMbuf,
263                       M_MBUF, M_NOWAIT);
264  sc->txMbuf = malloc (sc->txBdCount * sizeof *sc->txMbuf,
265                       M_MBUF, M_NOWAIT);
266  if (!sc->rxMbuf || !sc->txMbuf)
267    rtems_panic ("No memory for mbuf pointers");
268
269  /*
270   * Set receiver and transmitter buffer descriptor bases
271   */
272  sc->rxBdBase = m8xx_bd_allocate(sc->rxBdCount);
273  sc->txBdBase = m8xx_bd_allocate(sc->txBdCount);
274  m8xx.fec.r_des_start = (int)sc->rxBdBase;
275  m8xx.fec.x_des_start = (int)sc->txBdBase;
276
277  /*
278   * Set up Receive Control Register:
279   *   Not promiscuous mode
280   *   MII mode
281   *   Half duplex
282   *   No loopback
283   */
284  m8xx.fec.r_cntrl = 0x00000006;
285
286  /*
287   * Set up Transmit Control Register:
288   *   Half duplex
289   *   No heartbeat
290   */
291  m8xx.fec.x_cntrl = 0x00000000;
292
293  /*
294   * Set up DMA function code:
295   *   Big-endian
296   *   DMA functino code = 0
297   */
298  m8xx.fec.fun_code = 0x78000000;
299
300  /*
301   * Initialize SDMA configuration register
302   *   SDMA ignores FRZ
303   *   FEC not aggressive
304   *   FEC arbitration ID = 0 => U-bus arbitration = 6
305   *   RISC arbitration ID = 1 => U-bus arbitration = 5
306   */
307  m8xx.sdcr = 1;
308
309  /*
310   * Set MII speed to 2.5 MHz for 25 Mhz system clock
311   */
312  m8xx.fec.mii_speed = 0x0a;
313  m8xx.fec.mii_data = 0x58021000;
314
315  /*
316   * Set up receive buffer descriptors
317   */
318  for (i = 0 ; i < sc->rxBdCount ; i++)
319    (sc->rxBdBase + i)->status = 0;
320
321  /*
322   * Set up transmit buffer descriptors
323   */
324  for (i = 0 ; i < sc->txBdCount ; i++) {
325    (sc->txBdBase + i)->status = 0;
326    sc->txMbuf[i] = NULL;
327  }
328  sc->txBdHead = sc->txBdTail = 0;
329  sc->txBdActiveCount = 0;
330
331  /*
332   * Mask all FEC interrupts and clear events
333   */
334  m8xx.fec.imask = M8xx_FEC_IEVENT_TFINT |
335    M8xx_FEC_IEVENT_RFINT;
336  m8xx.fec.ievent = ~0;
337
338  /*
339   * Set up interrupts
340   */
341  if (!BSP_install_rtems_irq_handler (&ethernetFECIrqData))
342    rtems_panic ("Can't attach M860 FEC interrupt handler\n");
343
344}
345static void fec_rxDaemon (void *arg)
346{
347  struct m8xx_fec_enet_struct *sc = (struct m8xx_fec_enet_struct *)arg;
348  struct ifnet *ifp = &sc->arpcom.ac_if;
349  struct mbuf *m;
350  uint16_t   status;
351  m8xxBufferDescriptor_t *rxBd;
352  int rxBdIndex;
353
354  /*
355   * Allocate space for incoming packets and start reception
356   */
357  for (rxBdIndex = 0 ; ;) {
358    rxBd = sc->rxBdBase + rxBdIndex;
359    MGETHDR (m, M_WAIT, MT_DATA);
360    MCLGET (m, M_WAIT);
361    m->m_pkthdr.rcvif = ifp;
362    sc->rxMbuf[rxBdIndex] = m;
363    rxBd->buffer = mtod (m, void *);
364    rxBd->status = M8xx_BD_EMPTY;
365    m8xx.fec.r_des_active = 0x1000000;
366    if (++rxBdIndex == sc->rxBdCount) {
367      rxBd->status |= M8xx_BD_WRAP;
368      break;
369    }
370  }
371
372  /*
373   * Input packet handling loop
374   */
375  rxBdIndex = 0;
376  for (;;) {
377    rxBd = sc->rxBdBase + rxBdIndex;
378
379    /*
380     * Wait for packet if there's not one ready
381     */
382    if ((status = rxBd->status) & M8xx_BD_EMPTY) {
383      /*
384       * Clear old events
385       */
386      m8xx.fec.ievent = M8xx_FEC_IEVENT_RFINT;
387
388      /*
389       * Wait for packet
390       * Note that the buffer descriptor is checked
391       * *before* the event wait -- this catches the
392       * possibility that a packet arrived between the
393       * `if' above, and the clearing of the event register.
394       */
395      while ((status = rxBd->status) & M8xx_BD_EMPTY) {
396        rtems_event_set events;
397
398        /*
399         * Unmask RXF (Full frame received) event
400         */
401        m8xx.fec.ievent |= M8xx_FEC_IEVENT_RFINT;
402
403        rtems_bsdnet_event_receive (INTERRUPT_EVENT,
404                                    RTEMS_WAIT|RTEMS_EVENT_ANY,
405                                    RTEMS_NO_TIMEOUT,
406                                    &events);
407      }
408    }
409
410    /*
411     * Check that packet is valid
412     */
413    if (status & M8xx_BD_LAST) {
414      /*
415       * Pass the packet up the chain.
416       * FIXME: Packet filtering hook could be done here.
417       */
418      struct ether_header *eh;
419
420      /*
421       * Invalidate the buffer for this descriptor
422       */
423      rtems_cache_invalidate_multiple_data_lines((const void *)rxBd->buffer, rxBd->length);
424
425      m = sc->rxMbuf[rxBdIndex];
426      m->m_len = m->m_pkthdr.len = rxBd->length -
427        sizeof(uint32_t) -
428        sizeof(struct ether_header);
429      eh = mtod (m, struct ether_header *);
430      m->m_data += sizeof(struct ether_header);
431      ether_input (ifp, eh, m);
432
433      /*
434       * Allocate a new mbuf
435       */
436      MGETHDR (m, M_WAIT, MT_DATA);
437      MCLGET (m, M_WAIT);
438      m->m_pkthdr.rcvif = ifp;
439      sc->rxMbuf[rxBdIndex] = m;
440      rxBd->buffer = mtod (m, void *);
441    }
442    else {
443      /*
444       * Something went wrong with the reception
445       */
446      if (!(status & M8xx_BD_LAST))
447        sc->rxNotLast++;
448      if (status & M8xx_BD_LONG)
449        sc->rxGiant++;
450      if (status & M8xx_BD_NONALIGNED)
451        sc->rxNonOctet++;
452      if (status & M8xx_BD_SHORT)
453        sc->rxRunt++;
454      if (status & M8xx_BD_CRC_ERROR)
455        sc->rxBadCRC++;
456      if (status & M8xx_BD_OVERRUN)
457        sc->rxOverrun++;
458      if (status & M8xx_BD_COLLISION)
459        sc->rxCollision++;
460    }
461    /*
462     * Reenable the buffer descriptor
463     */
464    rxBd->status = (status & M8xx_BD_WRAP) |
465      M8xx_BD_EMPTY;
466    m8xx.fec.r_des_active = 0x1000000;
467    /*
468     * Move to next buffer descriptor
469     */
470    if (++rxBdIndex == sc->rxBdCount)
471      rxBdIndex = 0;
472  }
473}
474
475/*
476 * Soak up buffer descriptors that have been sent.
477 * Note that a buffer descriptor can't be retired as soon as it becomes
478 * ready. The MPC860 manual (MPC860UM/AD 07/98 Rev.1) and the MPC821
479 * manual state that, "If an Ethernet frame is made up of multiple
480 * buffers, the user should not reuse the first buffer descriptor until
481 * the last buffer descriptor of the frame has had its ready bit cleared
482 * by the CPM".
483 */
484static void
485m8xx_fec_Enet_retire_tx_bd (struct m8xx_fec_enet_struct *sc)
486{
487  uint16_t   status;
488  int i;
489  int nRetired;
490  struct mbuf *m, *n;
491
492  i = sc->txBdTail;
493  nRetired = 0;
494  while ((sc->txBdActiveCount != 0)
495         &&  (((status = (sc->txBdBase + i)->status) & M8xx_BD_READY) == 0)) {
496    /*
497     * See if anything went wrong
498     */
499    if (status & (M8xx_BD_DEFER |
500                  M8xx_BD_HEARTBEAT |
501                  M8xx_BD_LATE_COLLISION |
502                  M8xx_BD_RETRY_LIMIT |
503                  M8xx_BD_UNDERRUN |
504                  M8xx_BD_CARRIER_LOST)) {
505      /*
506       * Check for errors which stop the transmitter.
507       */
508      if (status & (M8xx_BD_LATE_COLLISION |
509                    M8xx_BD_RETRY_LIMIT |
510                    M8xx_BD_UNDERRUN)) {
511        if (status & M8xx_BD_LATE_COLLISION)
512          enet_driver[0].txLateCollision++;
513        if (status & M8xx_BD_RETRY_LIMIT)
514          enet_driver[0].txRetryLimit++;
515        if (status & M8xx_BD_UNDERRUN)
516          enet_driver[0].txUnderrun++;
517
518        /*
519         * Restart the transmitter
520         */
521        /* FIXME: this should get executed only if using the SCC */
522        m8xx_cp_execute_cmd (M8xx_CR_OP_RESTART_TX | M8xx_CR_CHAN_SCC1);
523      }
524      if (status & M8xx_BD_DEFER)
525        enet_driver[0].txDeferred++;
526      if (status & M8xx_BD_HEARTBEAT)
527        enet_driver[0].txHeartbeat++;
528      if (status & M8xx_BD_CARRIER_LOST)
529        enet_driver[0].txLostCarrier++;
530    }
531    nRetired++;
532    if (status & M8xx_BD_LAST) {
533      /*
534       * A full frame has been transmitted.
535       * Free all the associated buffer descriptors.
536       */
537      sc->txBdActiveCount -= nRetired;
538      while (nRetired) {
539        nRetired--;
540        m = sc->txMbuf[sc->txBdTail];
541        MFREE (m, n);
542        if (++sc->txBdTail == sc->txBdCount)
543          sc->txBdTail = 0;
544      }
545    }
546    if (++i == sc->txBdCount)
547      i = 0;
548  }
549}
550
551static void fec_sendpacket (struct ifnet *ifp, struct mbuf *m)
552{
553  struct m8xx_fec_enet_struct *sc = ifp->if_softc;
554  volatile m8xxBufferDescriptor_t *firstTxBd, *txBd;
555  /*  struct mbuf *l = NULL; */
556  uint16_t   status;
557  int nAdded;
558
559  /*
560   * Free up buffer descriptors
561   */
562  m8xx_fec_Enet_retire_tx_bd (sc);
563
564  /*
565   * Set up the transmit buffer descriptors.
566   * No need to pad out short packets since the
567   * hardware takes care of that automatically.
568   * No need to copy the packet to a contiguous buffer
569   * since the hardware is capable of scatter/gather DMA.
570   */
571  nAdded = 0;
572  txBd = firstTxBd = sc->txBdBase + sc->txBdHead;
573  for (;;) {
574    /*
575     * Wait for buffer descriptor to become available.
576     */
577    if ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
578      /*
579       * Clear old events
580       */
581      m8xx.fec.ievent = M8xx_FEC_IEVENT_TFINT;
582
583      /*
584       * Wait for buffer descriptor to become available.
585       * Note that the buffer descriptors are checked
586       * *before* * entering the wait loop -- this catches
587       * the possibility that a buffer descriptor became
588       * available between the `if' above, and the clearing
589       * of the event register.
590       * This is to catch the case where the transmitter
591       * stops in the middle of a frame -- and only the
592       * last buffer descriptor in a frame can generate
593       * an interrupt.
594       */
595      m8xx_fec_Enet_retire_tx_bd (sc);
596      while ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
597        rtems_event_set events;
598
599        /*
600         * Unmask TXB (buffer transmitted) and
601         * TXE (transmitter error) events.
602         */
603        m8xx.fec.ievent |= M8xx_FEC_IEVENT_TFINT;
604        rtems_bsdnet_event_receive (INTERRUPT_EVENT,
605                                    RTEMS_WAIT|RTEMS_EVENT_ANY,
606                                    RTEMS_NO_TIMEOUT,
607                                    &events);
608        m8xx_fec_Enet_retire_tx_bd (sc);
609      }
610    }
611
612    /*
613     * Don't set the READY flag till the
614     * whole packet has been readied.
615     */
616    status = nAdded ? M8xx_BD_READY : 0;
617
618    /*
619     *  FIXME: Why not deal with empty mbufs at at higher level?
620     * The IP fragmentation routine in ip_output
621     * can produce packet fragments with zero length.
622     * I think that ip_output should be changed to get
623     * rid of these zero-length mbufs, but for now,
624     * I'll deal with them here.
625     */
626    if (m->m_len) {
627      /*
628       * Fill in the buffer descriptor
629       */
630      txBd->buffer = mtod (m, void *);
631      txBd->length = m->m_len;
632
633      /*
634       * Flush the buffer for this descriptor
635       */
636      rtems_cache_flush_multiple_data_lines(txBd->buffer, txBd->length);
637
638      sc->txMbuf[sc->txBdHead] = m;
639      nAdded++;
640      if (++sc->txBdHead == sc->txBdCount) {
641        status |= M8xx_BD_WRAP;
642        sc->txBdHead = 0;
643      }
644      /*      l = m;*/
645      m = m->m_next;
646    }
647    else {
648      /*
649       * Just toss empty mbufs
650       */
651      struct mbuf *n;
652      MFREE (m, n);
653      m = n;
654      /*
655        if (l != NULL)
656        l->m_next = m;
657      */
658    }
659
660    /*
661     * Set the transmit buffer status.
662     * Break out of the loop if this mbuf is the last in the frame.
663     */
664    if (m == NULL) {
665      if (nAdded) {
666        status |= M8xx_BD_LAST | M8xx_BD_TX_CRC;
667        txBd->status = status;
668        firstTxBd->status |= M8xx_BD_READY;
669        m8xx.fec.x_des_active = 0x1000000;
670        sc->txBdActiveCount += nAdded;
671      }
672      break;
673    }
674    txBd->status = status;
675    txBd = sc->txBdBase + sc->txBdHead;
676  }
677}
678void fec_txDaemon (void *arg)
679{
680  struct m8xx_fec_enet_struct *sc = (struct m8xx_fec_enet_struct *)arg;
681  struct ifnet *ifp = &sc->arpcom.ac_if;
682  struct mbuf *m;
683  rtems_event_set events;
684
685  for (;;) {
686    /*
687     * Wait for packet
688     */
689    rtems_bsdnet_event_receive (START_TRANSMIT_EVENT,
690                                RTEMS_EVENT_ANY | RTEMS_WAIT,
691                                RTEMS_NO_TIMEOUT,
692                                &events);
693
694    /*
695     * Send packets till queue is empty
696     */
697    for (;;) {
698      /*
699       * Get the next mbuf chain to transmit.
700       */
701      IF_DEQUEUE(&ifp->if_snd, m);
702      if (!m)
703        break;
704      fec_sendpacket (ifp, m);
705    }
706    ifp->if_flags &= ~IFF_OACTIVE;
707  }
708}
709static void fec_init (void *arg)
710{
711  struct m8xx_fec_enet_struct *sc = arg;
712  struct ifnet *ifp = &sc->arpcom.ac_if;
713
714  if (sc->txDaemonTid == 0) {
715
716    /*
717     * Set up SCC hardware
718     */
719    m8xx_fec_initialize_hardware (sc);
720
721    /*
722     * Start driver tasks
723     */
724    sc->txDaemonTid = rtems_bsdnet_newproc ("SCtx", 4096, fec_txDaemon, sc);
725    sc->rxDaemonTid = rtems_bsdnet_newproc ("SCrx", 4096, fec_rxDaemon, sc);
726
727  }
728
729  /*
730   * Set flags appropriately
731   */
732  if (ifp->if_flags & IFF_PROMISC)
733    m8xx.fec.r_cntrl |= 0x8;
734  else
735    m8xx.fec.r_cntrl &= ~0x8;
736
737  /*
738   * Tell the world that we're running.
739   */
740  ifp->if_flags |= IFF_RUNNING;
741
742  /*
743   * Enable receiver and transmitter
744   */
745  m8xx.fec.ecntrl = 0x2;
746}
747
748/*
749 * Send packet (caller provides header).
750 */
751static void
752m8xx_fec_enet_start (struct ifnet *ifp)
753{
754  struct m8xx_fec_enet_struct *sc = ifp->if_softc;
755
756  rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
757  ifp->if_flags |= IFF_OACTIVE;
758}
759
760static void fec_stop (struct m8xx_fec_enet_struct *sc)
761{
762  struct ifnet *ifp = &sc->arpcom.ac_if;
763
764  ifp->if_flags &= ~IFF_RUNNING;
765
766  /*
767   * Shut down receiver and transmitter
768   */
769  m8xx.fec.ecntrl = 0x0;
770}
771
772/*
773 * Show interface statistics
774 */
775static void fec_enet_stats (struct m8xx_fec_enet_struct *sc)
776{
777  printf ("      Rx Interrupts:%-8lu", sc->rxInterrupts);
778  printf ("       Not First:%-8lu", sc->rxNotFirst);
779  printf ("        Not Last:%-8lu\n", sc->rxNotLast);
780  printf ("              Giant:%-8lu", sc->rxGiant);
781  printf ("            Runt:%-8lu", sc->rxRunt);
782  printf ("       Non-octet:%-8lu\n", sc->rxNonOctet);
783  printf ("            Bad CRC:%-8lu", sc->rxBadCRC);
784  printf ("         Overrun:%-8lu", sc->rxOverrun);
785  printf ("       Collision:%-8lu\n", sc->rxCollision);
786  printf ("          Discarded:%-8lu\n", (unsigned long)m8xx.scc1p.un.ethernet.disfc);
787
788  printf ("      Tx Interrupts:%-8lu", sc->txInterrupts);
789  printf ("        Deferred:%-8lu", sc->txDeferred);
790  printf (" Missed Hearbeat:%-8lu\n", sc->txHeartbeat);
791  printf ("         No Carrier:%-8lu", sc->txLostCarrier);
792  printf ("Retransmit Limit:%-8lu", sc->txRetryLimit);
793  printf ("  Late Collision:%-8lu\n", sc->txLateCollision);
794  printf ("           Underrun:%-8lu", sc->txUnderrun);
795  printf (" Raw output wait:%-8lu\n", sc->txRawWait);
796}
797
798static int fec_ioctl (struct ifnet *ifp, int command, caddr_t data)
799{
800  struct m8xx_fec_enet_struct *sc = ifp->if_softc;
801  int error = 0;
802
803  switch (command) {
804  case SIOCGIFADDR:
805  case SIOCSIFADDR:
806    ether_ioctl (ifp, command, data);
807    break;
808
809  case SIOCSIFFLAGS:
810    switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
811    case IFF_RUNNING:
812      fec_stop (sc);
813      break;
814
815    case IFF_UP:
816      fec_init (sc);
817      break;
818
819    case IFF_UP | IFF_RUNNING:
820      fec_stop (sc);
821      fec_init (sc);
822      break;
823
824    default:
825      break;
826    }
827    break;
828
829  case SIO_RTEMS_SHOW_STATS:
830    fec_enet_stats (sc);
831    break;
832
833    /*
834     * FIXME: All sorts of multicast commands need to be added here!
835     */
836  default:
837    error = EINVAL;
838    break;
839  }
840  return error;
841}
842int rtems_fec_driver_attach (struct rtems_bsdnet_ifconfig *config)
843{
844  struct m8xx_fec_enet_struct *sc;
845  struct ifnet *ifp;
846  int mtu;
847  int unitNumber;
848  char *unitName;
849  static const uint8_t maczero[] ={0,0,0,0,0,0};
850
851  /*
852   * Parse driver name
853   */
854  if ((unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName)) < 0)
855    return 0;
856
857  /*
858   * Is driver free?
859   */
860  if ((unitNumber <= 0) || (unitNumber > NIFACES)) {
861    printf ("Bad SCC unit number.\n");
862    return 0;
863  }
864  sc = &enet_driver[unitNumber - 1];
865  ifp = &sc->arpcom.ac_if;
866  if (ifp->if_softc != NULL) {
867    printf ("Driver already in use.\n");
868    return 0;
869  }
870
871  /*
872   * Process options
873   */
874  if (config->hardware_address) {
875    memcpy (sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
876  }
877#ifdef BSP_HAS_TQMMON
878  else if(0 != memcmp(maczero,TQM_BD_INFO.eth_addr,ETHER_ADDR_LEN)) {
879    memcpy (sc->arpcom.ac_enaddr, TQM_BD_INFO.eth_addr, ETHER_ADDR_LEN);
880  }
881#endif
882  else {
883    /* FIXME to read the enaddr from NVRAM */
884  }
885  if (config->mtu)
886    mtu = config->mtu;
887  else
888    mtu = ETHERMTU;
889  if (config->rbuf_count)
890    sc->rxBdCount = config->rbuf_count;
891  else
892    sc->rxBdCount = RX_BUF_COUNT;
893  if (config->xbuf_count)
894    sc->txBdCount = config->xbuf_count;
895  else
896    sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF;
897  sc->acceptBroadcast = !config->ignore_broadcast;
898
899  /*
900   * Set up network interface values
901   */
902  ifp->if_softc = sc;
903  ifp->if_unit = unitNumber;
904  ifp->if_name = unitName;
905  ifp->if_mtu = mtu;
906  ifp->if_init = fec_init;
907  ifp->if_ioctl = fec_ioctl;
908  ifp->if_start = m8xx_fec_enet_start;
909  ifp->if_output = ether_output;
910  ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
911  if (ifp->if_snd.ifq_maxlen == 0)
912    ifp->if_snd.ifq_maxlen = ifqmaxlen;
913
914  /*
915   * Attach the interface
916   */
917  if_attach (ifp);
918  ether_ifattach (ifp);
919  return 1;
920};
921
922int rtems_fec_enet_driver_attach(struct rtems_bsdnet_ifconfig *config,
923                                 int attaching)
924{
925  return rtems_fec_driver_attach(config);
926}
Note: See TracBrowser for help on using the repository browser.