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

5
Last change on this file since f3b29236 was 4c02385, checked in by Christian Mauderer <Christian.Mauderer@…>, on 06/24/16 at 06:52:48

libnetworking: Import current <arpa/inet.h>

Import the <arpa/inet.h> from current FreeBSD. Necessary due to changes
in <netinet/in.h>. Remove BSD hack from <arpa/inet.h>.

Clean up problems with htonl(). These functions are defined in
<arpa/inet.h>. This lead to some problems because they are defined in
<rtems/endian.h> too. Add NTOHL, ... to
<rtems/rtems_bsdnet_internal.h>.

  • Property mode set to 100644
File size: 34.6 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.org/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#include <bsp.h>
51#include <stdio.h>
52#include <errno.h>
53#include <rtems/error.h>
54#include <rtems/rtems_bsdnet.h>
55#include <rtems/rtems_mii_ioctl.h>
56
57#include <sys/param.h>
58#include <sys/mbuf.h>
59#include <sys/socket.h>
60#include <sys/sockio.h>
61
62#include <net/if.h>
63
64#include <netinet/in.h>
65#include <netinet/if_ether.h>
66#include <bsp/irq.h>
67
68#include <sys/types.h>
69#include <sys/socket.h>
70
71/*
72 * Number of interfaces supported by this driver
73 */
74#define NIFACES 1
75
76/*
77 * Default number of buffer descriptors set aside for this driver.
78 * The number of transmit buffer descriptors has to be quite large
79 * since a single frame often uses four or more buffer descriptors.
80 */
81#define RX_BUF_COUNT     32
82#define TX_BUF_COUNT     8
83#define TX_BD_PER_BUF    4
84
85#define INET_ADDR_MAX_BUF_SIZE (sizeof "255.255.255.255")
86
87/*
88 * RTEMS event used by interrupt handler to signal daemons.
89 * This must *not* be the same event used by the TCP/IP task synchronization.
90 */
91#define INTERRUPT_EVENT RTEMS_EVENT_1
92
93/*
94 * RTEMS event used to start transmit daemon.
95 * This must not be the same as INTERRUPT_EVENT.
96 */
97#define START_TRANSMIT_EVENT RTEMS_EVENT_2
98
99/*
100 * Receive buffer size -- Allow for a full ethernet packet plus CRC (1518).
101 * Round off to nearest multiple of RBUF_ALIGN.
102 */
103#define MAX_MTU_SIZE    1518
104#define RBUF_ALIGN              4
105#define RBUF_SIZE       ((MAX_MTU_SIZE + RBUF_ALIGN) & ~RBUF_ALIGN)
106
107#if (MCLBYTES < RBUF_SIZE)
108# error "Driver must have MCLBYTES > RBUF_SIZE"
109#endif
110
111#define FEC_WATCHDOG_TIMEOUT 5 /* check media every 5 seconds */
112/*
113 * Per-device data
114 */
115struct m8xx_fec_enet_struct {
116  struct arpcom           arpcom;
117  struct mbuf             **rxMbuf;
118  struct mbuf             **txMbuf;
119  int                     acceptBroadcast;
120  int                     rxBdCount;
121  int                     txBdCount;
122  int                     txBdHead;
123  int                     txBdTail;
124  int                     txBdActiveCount;
125  m8xxBufferDescriptor_t  *rxBdBase;
126  m8xxBufferDescriptor_t  *txBdBase;
127  rtems_id                rxDaemonTid;
128  rtems_id                txDaemonTid;
129
130  /*
131   * MDIO/Phy info
132   */
133  struct rtems_mdio_info mdio_info;
134  int phy_default;
135  int media_state; /* (last detected) state of media */
136  /*
137   * Statistics
138   */
139  unsigned long   rxInterrupts;
140  unsigned long   rxNotFirst;
141  unsigned long   rxNotLast;
142  unsigned long   rxGiant;
143  unsigned long   rxNonOctet;
144  unsigned long   rxRunt;
145  unsigned long   rxBadCRC;
146  unsigned long   rxOverrun;
147  unsigned long   rxCollision;
148
149  unsigned long   txInterrupts;
150  unsigned long   txDeferred;
151  unsigned long   txHeartbeat;
152  unsigned long   txLateCollision;
153  unsigned long   txRetryLimit;
154  unsigned long   txUnderrun;
155  unsigned long   txLostCarrier;
156  unsigned long   txRawWait;
157};
158static struct m8xx_fec_enet_struct enet_driver[NIFACES];
159
160/* declare ioctl function for internal use */
161static int fec_ioctl (struct ifnet *ifp,
162                      ioctl_command_t command, caddr_t data);
163/***************************************************************************\
164|  MII Management access functions                                          |
165\***************************************************************************/
166
167/*=========================================================================*\
168| Function:                                                                 |
169\*-------------------------------------------------------------------------*/
170static void fec_mdio_init
171(
172/*-------------------------------------------------------------------------*\
173| Purpose:                                                                  |
174|   initialize the MII interface                                            |
175+---------------------------------------------------------------------------+
176| Input Parameters:                                                         |
177\*-------------------------------------------------------------------------*/
178 struct m8xx_fec_enet_struct *sc     /* control structure                */
179)
180/*-------------------------------------------------------------------------*\
181| Return Value:                                                             |
182|    <none>                                                                 |
183\*=========================================================================*/
184{
185
186  /* Set FEC registers for MDIO communication */
187  /*
188   * set clock divider
189   */
190  m8xx.fec.mii_speed = BSP_bus_frequency / 25000000 / 2 + 1;
191}
192
193/*=========================================================================*\
194| Function:                                                                 |
195\*-------------------------------------------------------------------------*/
196int fec_mdio_read
197(
198/*-------------------------------------------------------------------------*\
199| Purpose:                                                                  |
200|   read register of a phy                                                  |
201+---------------------------------------------------------------------------+
202| Input Parameters:                                                         |
203\*-------------------------------------------------------------------------*/
204 int phy,                              /* PHY number to access or -1       */
205 void *uarg,                           /* unit argument                    */
206 unsigned reg,                         /* register address                 */
207 uint32_t *pval                        /* ptr to read buffer               */
208 )
209/*-------------------------------------------------------------------------*\
210| Return Value:                                                             |
211|    0, if ok, else error                                                   |
212\*=========================================================================*/
213{
214  struct m8xx_fec_enet_struct *sc = uarg;/* control structure            */
215
216  /*
217   * make sure we work with a valid phy
218   */
219  if (phy == -1) {
220    /*
221     * set default phy number: 0
222     */
223    phy = sc->phy_default;
224  }
225  if ( (phy < 0) || (phy > 31)) {
226    /*
227     * invalid phy number
228     */
229    return EINVAL;
230  }
231  /*
232   * clear MII transfer event bit
233   */
234  m8xx.fec.ievent = M8xx_FEC_IEVENT_MII;
235  /*
236   * set access command, data, start transfer
237   */
238  m8xx.fec.mii_data = (M8xx_FEC_MII_DATA_ST    |
239                       M8xx_FEC_MII_DATA_OP_RD |
240                       M8xx_FEC_MII_DATA_PHYAD(phy) |
241                       M8xx_FEC_MII_DATA_PHYRA(reg) |
242                       M8xx_FEC_MII_DATA_WDATA(0));
243
244  /*
245   * wait for cycle to terminate
246   */
247  do {
248    rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
249  }  while (0 == (m8xx.fec.ievent & M8xx_FEC_IEVENT_MII));
250
251  /*
252   * fetch read data, if available
253   */
254  if (pval != NULL) {
255    *pval = M8xx_FEC_MII_DATA_RDATA(m8xx.fec.mii_data);
256  }
257  return 0;
258}
259
260/*=========================================================================*\
261| Function:                                                                 |
262\*-------------------------------------------------------------------------*/
263int fec_mdio_write
264(
265/*-------------------------------------------------------------------------*\
266| Purpose:                                                                  |
267|   write register of a phy                                                 |
268+---------------------------------------------------------------------------+
269| Input Parameters:                                                         |
270\*-------------------------------------------------------------------------*/
271 int phy,                              /* PHY number to access or -1       */
272 void *uarg,                           /* unit argument                    */
273 unsigned reg,                         /* register address                 */
274 uint32_t val                          /* write value                      */
275 )
276/*-------------------------------------------------------------------------*\
277| Return Value:                                                             |
278|    0, if ok, else error                                                   |
279\*=========================================================================*/
280{
281  struct m8xx_fec_enet_struct *sc = uarg;/* control structure            */
282
283  /*
284   * make sure we work with a valid phy
285   */
286  if (phy == -1) {
287    /*
288     * set default phy number: 0
289     */
290    phy = sc->phy_default;
291  }
292  if ( (phy < 0) || (phy > 31)) {
293    /*
294     * invalid phy number
295     */
296    return EINVAL;
297  }
298  /*
299   * clear MII transfer event bit
300   */
301  m8xx.fec.ievent = M8xx_FEC_IEVENT_MII;
302  /*
303   * set access command, data, start transfer
304   */
305  m8xx.fec.mii_data = (M8xx_FEC_MII_DATA_ST    |
306                       M8xx_FEC_MII_DATA_OP_WR |
307                       M8xx_FEC_MII_DATA_PHYAD(phy) |
308                       M8xx_FEC_MII_DATA_PHYRA(reg) |
309                       M8xx_FEC_MII_DATA_WDATA(val));
310
311  /*
312   * wait for cycle to terminate
313   */
314  do {
315    rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
316  }  while (0 == (m8xx.fec.ievent & M8xx_FEC_IEVENT_MII));
317
318  return 0;
319}
320
321/*
322 * FEC interrupt handler
323 */
324static void m8xx_fec_interrupt_handler (void *unused)
325{
326  /*
327   * Frame received?
328   */
329  if (m8xx.fec.ievent & M8xx_FEC_IEVENT_RFINT) {
330    m8xx.fec.ievent = M8xx_FEC_IEVENT_RFINT;
331    enet_driver[0].rxInterrupts++;
332    rtems_bsdnet_event_send (enet_driver[0].rxDaemonTid, INTERRUPT_EVENT);
333  }
334
335  /*
336   * Buffer transmitted or transmitter error?
337   */
338  if (m8xx.fec.ievent & M8xx_FEC_IEVENT_TFINT) {
339    m8xx.fec.ievent = M8xx_FEC_IEVENT_TFINT;
340    enet_driver[0].txInterrupts++;
341    rtems_bsdnet_event_send (enet_driver[0].txDaemonTid, INTERRUPT_EVENT);
342  }
343}
344
345/*
346 * Please organize FEC controller code better by moving code from
347 * m860_fec_initialize_hardware to m8xx_fec_ethernet_on
348 */
349static void m8xx_fec_ethernet_on(const rtems_irq_connect_data* ptr){};
350static void m8xx_fec_ethernet_off(const rtems_irq_connect_data* ptr){};
351static int m8xx_fec_ethernet_isOn (const rtems_irq_connect_data* ptr)
352{
353  return 1;
354}
355
356static rtems_irq_connect_data ethernetFECIrqData = {
357  BSP_FAST_ETHERNET_CTRL,
358  m8xx_fec_interrupt_handler,
359  NULL,
360  m8xx_fec_ethernet_on,
361  m8xx_fec_ethernet_off,
362  m8xx_fec_ethernet_isOn
363};
364
365static void
366m8xx_fec_initialize_hardware (struct m8xx_fec_enet_struct *sc)
367{
368  int i;
369  unsigned char *hwaddr;
370
371  /*
372   * Issue reset to FEC
373   */
374  m8xx.fec.ecntrl=0x1;
375
376  /*
377   * Put ethernet transciever in reset
378   */
379  m8xx.pgcra |= 0x80;
380
381  /*
382   * Configure I/O ports
383   */
384  m8xx.pdpar = 0x1fff;
385  m8xx.pddir = 0x1c58;
386
387  /*
388   * Take ethernet transciever out of reset
389   */
390  m8xx.pgcra &= ~0x80;
391
392  /*
393   * Set SIU interrupt level to LVL2
394   *
395   */
396  m8xx.fec.ivec = ((((unsigned) BSP_FAST_ETHERNET_CTRL)/2) << 29);
397
398  /*
399   * Set the TX and RX fifo sizes. For now, we'll split it evenly
400   */
401  /* If you uncomment these, the FEC will not work right.
402     m8xx.fec.r_fstart = ((m8xx.fec.r_bound & 0x3ff) >> 2) & 0x3ff;
403     m8xx.fec.x_fstart = 0;
404  */
405
406  /*
407   * Set our physical address
408   */
409  hwaddr = sc->arpcom.ac_enaddr;
410
411  m8xx.fec.addr_low = (hwaddr[0] << 24) | (hwaddr[1] << 16) |
412    (hwaddr[2] << 8)  | (hwaddr[3] << 0);
413  m8xx.fec.addr_high = (hwaddr[4] << 24) | (hwaddr[5] << 16);
414
415  /*
416   * Clear the hash table
417   */
418  m8xx.fec.hash_table_high = 0;
419  m8xx.fec.hash_table_low  = 0;
420
421  /*
422   * Set up receive buffer size
423   */
424  m8xx.fec.r_buf_size = 0x5f0; /* set to 1520 */
425
426  /*
427   * Allocate mbuf pointers
428   */
429  sc->rxMbuf = malloc (sc->rxBdCount * sizeof *sc->rxMbuf,
430                       M_MBUF, M_NOWAIT);
431  sc->txMbuf = malloc (sc->txBdCount * sizeof *sc->txMbuf,
432                       M_MBUF, M_NOWAIT);
433  if (!sc->rxMbuf || !sc->txMbuf)
434    rtems_panic ("No memory for mbuf pointers");
435
436  /*
437   * Set receiver and transmitter buffer descriptor bases
438   */
439  sc->rxBdBase = m8xx_bd_allocate(sc->rxBdCount);
440  sc->txBdBase = m8xx_bd_allocate(sc->txBdCount);
441  m8xx.fec.r_des_start = (int)sc->rxBdBase;
442  m8xx.fec.x_des_start = (int)sc->txBdBase;
443
444  /*
445   * Set up Receive Control Register:
446   *   Not promiscuous mode
447   *   MII mode
448   *   Half duplex
449   *   No loopback
450   */
451  m8xx.fec.r_cntrl = 0x00000006;
452
453  /*
454   * Set up Transmit Control Register:
455   *   Full duplex
456   *   No heartbeat
457   */
458  m8xx.fec.x_cntrl = M8xx_FEC_X_CNTRL_FDEN;
459
460  /*
461   * Set up DMA function code:
462   *   Big-endian
463   *   DMA functino code = 0
464   */
465  m8xx.fec.fun_code = 0x78000000;
466
467  /*
468   * Initialize SDMA configuration register
469   *   SDMA ignores FRZ
470   *   FEC not aggressive
471   *   FEC arbitration ID = 0 => U-bus arbitration = 6
472   *   RISC arbitration ID = 1 => U-bus arbitration = 5
473   */
474  m8xx.sdcr = 1;
475
476  /*
477   * Set up receive buffer descriptors
478   */
479  for (i = 0 ; i < sc->rxBdCount ; i++)
480    (sc->rxBdBase + i)->status = 0;
481
482  /*
483   * Set up transmit buffer descriptors
484   */
485  for (i = 0 ; i < sc->txBdCount ; i++) {
486    (sc->txBdBase + i)->status = 0;
487    sc->txMbuf[i] = NULL;
488  }
489  sc->txBdHead = sc->txBdTail = 0;
490  sc->txBdActiveCount = 0;
491
492  /*
493   * Mask all FEC interrupts and clear events
494   */
495  m8xx.fec.imask = M8xx_FEC_IEVENT_TFINT |
496    M8xx_FEC_IEVENT_RFINT;
497  m8xx.fec.ievent = ~0;
498
499  /*
500   * Set up interrupts
501   */
502  if (!BSP_install_rtems_irq_handler (&ethernetFECIrqData))
503    rtems_panic ("Can't attach M860 FEC interrupt handler\n");
504
505}
506static void fec_rxDaemon (void *arg)
507{
508  struct m8xx_fec_enet_struct *sc = (struct m8xx_fec_enet_struct *)arg;
509  struct ifnet *ifp = &sc->arpcom.ac_if;
510  struct mbuf *m;
511  uint16_t   status;
512  m8xxBufferDescriptor_t *rxBd;
513  int rxBdIndex;
514
515  /*
516   * Allocate space for incoming packets and start reception
517   */
518  for (rxBdIndex = 0 ; ;) {
519    rxBd = sc->rxBdBase + rxBdIndex;
520    MGETHDR (m, M_WAIT, MT_DATA);
521    MCLGET (m, M_WAIT);
522    m->m_pkthdr.rcvif = ifp;
523    sc->rxMbuf[rxBdIndex] = m;
524    rxBd->buffer = mtod (m, void *);
525    rxBd->status = M8xx_BD_EMPTY;
526    m8xx.fec.r_des_active = 0x1000000;
527    if (++rxBdIndex == sc->rxBdCount) {
528      rxBd->status |= M8xx_BD_WRAP;
529      break;
530    }
531  }
532
533  /*
534   * Input packet handling loop
535   */
536  rxBdIndex = 0;
537  for (;;) {
538    rxBd = sc->rxBdBase + rxBdIndex;
539
540    /*
541     * Wait for packet if there's not one ready
542     */
543    if ((status = rxBd->status) & M8xx_BD_EMPTY) {
544      /*
545       * Clear old events
546       */
547      m8xx.fec.ievent = M8xx_FEC_IEVENT_RFINT;
548
549      /*
550       * Wait for packet
551       * Note that the buffer descriptor is checked
552       * *before* the event wait -- this catches the
553       * possibility that a packet arrived between the
554       * `if' above, and the clearing of the event register.
555       */
556      while ((status = rxBd->status) & M8xx_BD_EMPTY) {
557        rtems_event_set events;
558
559        /*
560         * Unmask RXF (Full frame received) event
561         */
562        m8xx.fec.ievent |= M8xx_FEC_IEVENT_RFINT;
563
564        rtems_bsdnet_event_receive (INTERRUPT_EVENT,
565                                    RTEMS_WAIT|RTEMS_EVENT_ANY,
566                                    RTEMS_NO_TIMEOUT,
567                                    &events);
568      }
569    }
570
571    /*
572     * Check that packet is valid
573     */
574    if (status & M8xx_BD_LAST) {
575      /*
576       * Pass the packet up the chain.
577       * FIXME: Packet filtering hook could be done here.
578       */
579      struct ether_header *eh;
580
581      /*
582       * Invalidate the buffer for this descriptor
583       */
584      rtems_cache_invalidate_multiple_data_lines((const void *)rxBd->buffer, rxBd->length);
585
586      m = sc->rxMbuf[rxBdIndex];
587      m->m_len = m->m_pkthdr.len = rxBd->length -
588        sizeof(uint32_t) -
589        sizeof(struct ether_header);
590      eh = mtod (m, struct ether_header *);
591      m->m_data += sizeof(struct ether_header);
592      ether_input (ifp, eh, m);
593
594      /*
595       * Allocate a new mbuf
596       */
597      MGETHDR (m, M_WAIT, MT_DATA);
598      MCLGET (m, M_WAIT);
599      m->m_pkthdr.rcvif = ifp;
600      sc->rxMbuf[rxBdIndex] = m;
601      rxBd->buffer = mtod (m, void *);
602    }
603    else {
604      /*
605       * Something went wrong with the reception
606       */
607      if (!(status & M8xx_BD_LAST))
608        sc->rxNotLast++;
609      if (status & M8xx_BD_LONG)
610        sc->rxGiant++;
611      if (status & M8xx_BD_NONALIGNED)
612        sc->rxNonOctet++;
613      if (status & M8xx_BD_SHORT)
614        sc->rxRunt++;
615      if (status & M8xx_BD_CRC_ERROR)
616        sc->rxBadCRC++;
617      if (status & M8xx_BD_OVERRUN)
618        sc->rxOverrun++;
619      if (status & M8xx_BD_COLLISION)
620        sc->rxCollision++;
621    }
622    /*
623     * Reenable the buffer descriptor
624     */
625    rxBd->status = (status & M8xx_BD_WRAP) |
626      M8xx_BD_EMPTY;
627    m8xx.fec.r_des_active = 0x1000000;
628    /*
629     * Move to next buffer descriptor
630     */
631    if (++rxBdIndex == sc->rxBdCount)
632      rxBdIndex = 0;
633  }
634}
635
636/*
637 * Soak up buffer descriptors that have been sent.
638 * Note that a buffer descriptor can't be retired as soon as it becomes
639 * ready. The MPC860 manual (MPC860UM/AD 07/98 Rev.1) and the MPC821
640 * manual state that, "If an Ethernet frame is made up of multiple
641 * buffers, the user should not reuse the first buffer descriptor until
642 * the last buffer descriptor of the frame has had its ready bit cleared
643 * by the CPM".
644 */
645static void
646m8xx_fec_Enet_retire_tx_bd (struct m8xx_fec_enet_struct *sc)
647{
648  uint16_t   status;
649  int i;
650  int nRetired;
651  struct mbuf *m, *n;
652
653  i = sc->txBdTail;
654  nRetired = 0;
655  while ((sc->txBdActiveCount != 0)
656         &&  (((status = (sc->txBdBase + i)->status) & M8xx_BD_READY) == 0)) {
657    /*
658     * See if anything went wrong
659     */
660    if (status & (M8xx_BD_DEFER |
661                  M8xx_BD_HEARTBEAT |
662                  M8xx_BD_LATE_COLLISION |
663                  M8xx_BD_RETRY_LIMIT |
664                  M8xx_BD_UNDERRUN |
665                  M8xx_BD_CARRIER_LOST)) {
666      /*
667       * Check for errors which stop the transmitter.
668       */
669      if (status & (M8xx_BD_LATE_COLLISION |
670                    M8xx_BD_RETRY_LIMIT |
671                    M8xx_BD_UNDERRUN)) {
672        if (status & M8xx_BD_LATE_COLLISION)
673          enet_driver[0].txLateCollision++;
674        if (status & M8xx_BD_RETRY_LIMIT)
675          enet_driver[0].txRetryLimit++;
676        if (status & M8xx_BD_UNDERRUN)
677          enet_driver[0].txUnderrun++;
678
679      }
680      if (status & M8xx_BD_DEFER)
681        enet_driver[0].txDeferred++;
682      if (status & M8xx_BD_HEARTBEAT)
683        enet_driver[0].txHeartbeat++;
684      if (status & M8xx_BD_CARRIER_LOST)
685        enet_driver[0].txLostCarrier++;
686    }
687    nRetired++;
688    if (status & M8xx_BD_LAST) {
689      /*
690       * A full frame has been transmitted.
691       * Free all the associated buffer descriptors.
692       */
693      sc->txBdActiveCount -= nRetired;
694      while (nRetired) {
695        nRetired--;
696        m = sc->txMbuf[sc->txBdTail];
697        MFREE (m, n);
698        if (++sc->txBdTail == sc->txBdCount)
699          sc->txBdTail = 0;
700      }
701    }
702    if (++i == sc->txBdCount)
703      i = 0;
704  }
705}
706
707static void fec_sendpacket (struct ifnet *ifp, struct mbuf *m)
708{
709  struct m8xx_fec_enet_struct *sc = ifp->if_softc;
710  volatile m8xxBufferDescriptor_t *firstTxBd, *txBd;
711  /*  struct mbuf *l = NULL; */
712  uint16_t   status;
713  int nAdded;
714
715  /*
716   * Free up buffer descriptors
717   */
718  m8xx_fec_Enet_retire_tx_bd (sc);
719
720  /*
721   * Set up the transmit buffer descriptors.
722   * No need to pad out short packets since the
723   * hardware takes care of that automatically.
724   * No need to copy the packet to a contiguous buffer
725   * since the hardware is capable of scatter/gather DMA.
726   */
727  nAdded = 0;
728  txBd = firstTxBd = sc->txBdBase + sc->txBdHead;
729  for (;;) {
730    /*
731     * Wait for buffer descriptor to become available.
732     */
733    if ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
734      /*
735       * Clear old events
736       */
737      m8xx.fec.ievent = M8xx_FEC_IEVENT_TFINT;
738
739      /*
740       * Wait for buffer descriptor to become available.
741       * Note that the buffer descriptors are checked
742       * *before* * entering the wait loop -- this catches
743       * the possibility that a buffer descriptor became
744       * available between the `if' above, and the clearing
745       * of the event register.
746       * This is to catch the case where the transmitter
747       * stops in the middle of a frame -- and only the
748       * last buffer descriptor in a frame can generate
749       * an interrupt.
750       */
751      m8xx_fec_Enet_retire_tx_bd (sc);
752      while ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
753        rtems_event_set events;
754
755        /*
756         * Unmask TXB (buffer transmitted) and
757         * TXE (transmitter error) events.
758         */
759        m8xx.fec.ievent |= M8xx_FEC_IEVENT_TFINT;
760        rtems_bsdnet_event_receive (INTERRUPT_EVENT,
761                                    RTEMS_WAIT|RTEMS_EVENT_ANY,
762                                    RTEMS_NO_TIMEOUT,
763                                    &events);
764        m8xx_fec_Enet_retire_tx_bd (sc);
765      }
766    }
767
768    /*
769     * Don't set the READY flag till the
770     * whole packet has been readied.
771     */
772    status = nAdded ? M8xx_BD_READY : 0;
773
774    /*
775     *  FIXME: Why not deal with empty mbufs at at higher level?
776     * The IP fragmentation routine in ip_output
777     * can produce packet fragments with zero length.
778     * I think that ip_output should be changed to get
779     * rid of these zero-length mbufs, but for now,
780     * I'll deal with them here.
781     */
782    if (m->m_len) {
783      /*
784       * Fill in the buffer descriptor
785       */
786      txBd->buffer = mtod (m, void *);
787      txBd->length = m->m_len;
788
789      /*
790       * Flush the buffer for this descriptor
791       */
792      rtems_cache_flush_multiple_data_lines((void *)txBd->buffer, txBd->length);
793
794      sc->txMbuf[sc->txBdHead] = m;
795      nAdded++;
796      if (++sc->txBdHead == sc->txBdCount) {
797        status |= M8xx_BD_WRAP;
798        sc->txBdHead = 0;
799      }
800      /*      l = m;*/
801      m = m->m_next;
802    }
803    else {
804      /*
805       * Just toss empty mbufs
806       */
807      struct mbuf *n;
808      MFREE (m, n);
809      m = n;
810      /*
811        if (l != NULL)
812        l->m_next = m;
813      */
814    }
815
816    /*
817     * Set the transmit buffer status.
818     * Break out of the loop if this mbuf is the last in the frame.
819     */
820    if (m == NULL) {
821      if (nAdded) {
822        status |= M8xx_BD_LAST | M8xx_BD_TX_CRC;
823        txBd->status = status;
824        firstTxBd->status |= M8xx_BD_READY;
825        m8xx.fec.x_des_active = 0x1000000;
826        sc->txBdActiveCount += nAdded;
827      }
828      break;
829    }
830    txBd->status = status;
831    txBd = sc->txBdBase + sc->txBdHead;
832  }
833}
834void fec_txDaemon (void *arg)
835{
836  struct m8xx_fec_enet_struct *sc = (struct m8xx_fec_enet_struct *)arg;
837  struct ifnet *ifp = &sc->arpcom.ac_if;
838  struct mbuf *m;
839  rtems_event_set events;
840
841  for (;;) {
842    /*
843     * Wait for packet
844     */
845    rtems_bsdnet_event_receive (START_TRANSMIT_EVENT,
846                                RTEMS_EVENT_ANY | RTEMS_WAIT,
847                                RTEMS_NO_TIMEOUT,
848                                &events);
849
850    /*
851     * Send packets till queue is empty
852     */
853    for (;;) {
854      /*
855       * Get the next mbuf chain to transmit.
856       */
857      IF_DEQUEUE(&ifp->if_snd, m);
858      if (!m)
859        break;
860      fec_sendpacket (ifp, m);
861    }
862    ifp->if_flags &= ~IFF_OACTIVE;
863  }
864}
865static void fec_init (void *arg)
866{
867  struct m8xx_fec_enet_struct *sc = arg;
868  struct ifnet *ifp = &sc->arpcom.ac_if;
869
870  if (sc->txDaemonTid == 0) {
871
872    /*
873     * Set up FEC hardware
874     */
875    m8xx_fec_initialize_hardware (sc);
876
877    /*
878     * init access to phy
879     */
880    fec_mdio_init(sc);
881
882    /*
883     * Start driver tasks
884     */
885    sc->txDaemonTid = rtems_bsdnet_newproc ("SCtx", 4096, fec_txDaemon, sc);
886    sc->rxDaemonTid = rtems_bsdnet_newproc ("SCrx", 4096, fec_rxDaemon, sc);
887
888  }
889
890  /*
891   * Set flags appropriately
892   */
893  if (ifp->if_flags & IFF_PROMISC)
894    m8xx.fec.r_cntrl |= 0x8;
895  else
896    m8xx.fec.r_cntrl &= ~0x8;
897
898  /*
899   * init timer so the "watchdog function gets called periodically
900   */
901  ifp->if_timer    = 1;
902
903  /*
904   * Tell the world that we're running.
905   */
906  ifp->if_flags |= IFF_RUNNING;
907
908  /*
909   * Enable receiver and transmitter
910   */
911  m8xx.fec.ecntrl = 0x2;
912}
913
914/*
915 * Send packet (caller provides header).
916 */
917static void
918m8xx_fec_enet_start (struct ifnet *ifp)
919{
920  struct m8xx_fec_enet_struct *sc = ifp->if_softc;
921
922  rtems_bsdnet_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
923  ifp->if_flags |= IFF_OACTIVE;
924}
925
926static void fec_stop (struct m8xx_fec_enet_struct *sc)
927{
928  struct ifnet *ifp = &sc->arpcom.ac_if;
929
930  ifp->if_flags &= ~IFF_RUNNING;
931
932  /*
933   * Shut down receiver and transmitter
934   */
935  m8xx.fec.ecntrl = 0x0;
936}
937
938/*
939 * Show interface statistics
940 */
941static void fec_enet_stats (struct m8xx_fec_enet_struct *sc)
942{
943  int media;
944  int result;
945  /*
946   * fetch/print media info
947   */
948  media = IFM_MAKEWORD(0,0,0,sc->phy_default); /* fetch from default phy */
949
950  result = fec_ioctl(&(sc->arpcom.ac_if),
951                     SIOCGIFMEDIA,
952                     (caddr_t)&media);
953  if (result == 0) {
954    rtems_ifmedia2str(media,NULL,0);
955    printf ("\n");
956  }
957
958  printf ("      Rx Interrupts:%-8lu", sc->rxInterrupts);
959  printf ("       Not First:%-8lu", sc->rxNotFirst);
960  printf ("        Not Last:%-8lu\n", sc->rxNotLast);
961  printf ("              Giant:%-8lu", sc->rxGiant);
962  printf ("            Runt:%-8lu", sc->rxRunt);
963  printf ("       Non-octet:%-8lu\n", sc->rxNonOctet);
964  printf ("            Bad CRC:%-8lu", sc->rxBadCRC);
965  printf ("         Overrun:%-8lu", sc->rxOverrun);
966  printf ("       Collision:%-8lu\n", sc->rxCollision);
967
968  printf ("      Tx Interrupts:%-8lu", sc->txInterrupts);
969  printf ("        Deferred:%-8lu", sc->txDeferred);
970  printf (" Missed Hearbeat:%-8lu\n", sc->txHeartbeat);
971  printf ("         No Carrier:%-8lu", sc->txLostCarrier);
972  printf ("Retransmit Limit:%-8lu", sc->txRetryLimit);
973  printf ("  Late Collision:%-8lu\n", sc->txLateCollision);
974  printf ("           Underrun:%-8lu", sc->txUnderrun);
975  printf (" Raw output wait:%-8lu\n", sc->txRawWait);
976}
977
978static int fec_ioctl (struct ifnet *ifp,
979                      ioctl_command_t command, caddr_t data)
980{
981  struct m8xx_fec_enet_struct *sc = ifp->if_softc;
982  int error = 0;
983
984  switch (command) {
985    /*
986     * access PHY via MII
987     */
988  case SIOCGIFMEDIA:
989  case SIOCSIFMEDIA:
990    rtems_mii_ioctl (&(sc->mdio_info),sc,command,(void *)data);
991    break;
992  case SIOCGIFADDR:
993  case SIOCSIFADDR:
994    ether_ioctl (ifp, command, data);
995    break;
996
997  case SIOCSIFFLAGS:
998    switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
999    case IFF_RUNNING:
1000      fec_stop (sc);
1001      break;
1002
1003    case IFF_UP:
1004      fec_init (sc);
1005      break;
1006
1007    case IFF_UP | IFF_RUNNING:
1008      fec_stop (sc);
1009      fec_init (sc);
1010      break;
1011
1012    default:
1013      break;
1014    }
1015    break;
1016
1017  case SIO_RTEMS_SHOW_STATS:
1018    fec_enet_stats (sc);
1019    break;
1020
1021    /*
1022     * FIXME: All sorts of multicast commands need to be added here!
1023     */
1024  default:
1025    error = EINVAL;
1026    break;
1027  }
1028  return error;
1029}
1030
1031/*=========================================================================*\
1032| Function:                                                                 |
1033\*-------------------------------------------------------------------------*/
1034int fec_mode_adapt
1035(
1036/*-------------------------------------------------------------------------*\
1037| Purpose:                                                                  |
1038|   init the PHY and adapt FEC settings                                     |
1039+---------------------------------------------------------------------------+
1040| Input Parameters:                                                         |
1041\*-------------------------------------------------------------------------*/
1042 struct ifnet *ifp
1043)
1044/*-------------------------------------------------------------------------*\
1045| Return Value:                                                             |
1046|    0, if success                                                          |
1047\*=========================================================================*/
1048{
1049  int result = 0;
1050  struct m8xx_fec_enet_struct *sc = ifp->if_softc;
1051  int media = IFM_MAKEWORD( 0, 0, 0, sc->phy_default);
1052
1053#ifdef DEBUG
1054  printf("c");
1055#endif
1056  /*
1057   * fetch media status
1058   */
1059  result = fec_ioctl(ifp,SIOCGIFMEDIA,(caddr_t)&media);
1060  if (result != 0) {
1061    return result;
1062  }
1063#ifdef DEBUG
1064  printf("C");
1065#endif
1066  /*
1067   * status is unchanged? then do nothing
1068   */
1069  if (media == sc->media_state) {
1070    return 0;
1071  }
1072  /*
1073   * otherwise: for the first call, try to negotiate mode
1074   */
1075  if (sc->media_state == 0) {
1076    /*
1077     * set media status: set auto negotiation -> start auto-negotiation
1078     */
1079    media = IFM_MAKEWORD(0,IFM_AUTO,0,sc->phy_default);
1080    result = fec_ioctl(ifp,SIOCSIFMEDIA,(caddr_t)&media);
1081    if (result != 0) {
1082      return result;
1083    }
1084    /*
1085     * wait for auto-negotiation to terminate
1086     */
1087    do {
1088      media = IFM_MAKEWORD(0,0,0,sc->phy_default);
1089      result = fec_ioctl(ifp,SIOCGIFMEDIA,(caddr_t)&media);
1090      if (result != 0) {
1091        return result;
1092      }
1093    } while (IFM_NONE == IFM_SUBTYPE(media));
1094  }
1095
1096  /*
1097   * now set HW according to media results:
1098   */
1099  /*
1100   * if we are half duplex then switch to half duplex
1101   */
1102  if (0 == (IFM_FDX & IFM_OPTIONS(media))) {
1103    m8xx.fec.x_cntrl &= ~M8xx_FEC_X_CNTRL_FDEN;
1104  }
1105  else {
1106    m8xx.fec.x_cntrl |=  M8xx_FEC_X_CNTRL_FDEN;
1107  }
1108  /*
1109   * store current media state for future compares
1110   */
1111  sc->media_state = media;
1112
1113  return 0;
1114}
1115
1116/*=========================================================================*\
1117| Function:                                                                 |
1118\*-------------------------------------------------------------------------*/
1119static void fec_watchdog
1120(
1121/*-------------------------------------------------------------------------*\
1122| Purpose:                                                                  |
1123|   periodically poll the PHY. if mode has changed,                         |
1124|  then adjust the FEC settings                                             |
1125+---------------------------------------------------------------------------+
1126| Input Parameters:                                                         |
1127\*-------------------------------------------------------------------------*/
1128 struct ifnet *ifp
1129)
1130/*-------------------------------------------------------------------------*\
1131| Return Value:                                                             |
1132|    1, if success                                                          |
1133\*=========================================================================*/
1134{
1135  fec_mode_adapt(ifp);
1136  ifp->if_timer    = FEC_WATCHDOG_TIMEOUT;
1137}
1138
1139int rtems_fec_driver_attach (struct rtems_bsdnet_ifconfig *config)
1140{
1141  struct m8xx_fec_enet_struct *sc;
1142  struct ifnet *ifp;
1143  int mtu;
1144  int unitNumber;
1145  char *unitName;
1146  static const uint8_t maczero[] ={0,0,0,0,0,0};
1147
1148  /*
1149   * Parse driver name
1150   */
1151  if ((unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName)) < 0)
1152    return 0;
1153
1154  /*
1155   * Is driver free?
1156   */
1157  if ((unitNumber <= 0) || (unitNumber > NIFACES)) {
1158    printk ("Bad FEC unit number.\n");
1159    return 0;
1160  }
1161  sc = &enet_driver[unitNumber - 1];
1162  ifp = &sc->arpcom.ac_if;
1163  if (ifp->if_softc != NULL) {
1164    printk ("Driver already in use.\n");
1165    return 0;
1166  }
1167
1168  /*
1169   * Process options
1170   */
1171  if (config->hardware_address) {
1172    memcpy (sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
1173  }
1174#ifdef BSP_HAS_TQMMON
1175  else if(0 != memcmp(maczero,TQM_BD_INFO.eth_addr,ETHER_ADDR_LEN)) {
1176    memcpy (sc->arpcom.ac_enaddr, TQM_BD_INFO.eth_addr, ETHER_ADDR_LEN);
1177  }
1178#endif
1179  else {
1180    /* FIXME to read the enaddr from NVRAM */
1181  }
1182  if (config->mtu)
1183    mtu = config->mtu;
1184  else
1185    mtu = ETHERMTU;
1186  if (config->rbuf_count)
1187    sc->rxBdCount = config->rbuf_count;
1188  else
1189    sc->rxBdCount = RX_BUF_COUNT;
1190  if (config->xbuf_count)
1191    sc->txBdCount = config->xbuf_count;
1192  else
1193    sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF;
1194  sc->acceptBroadcast = !config->ignore_broadcast;
1195
1196  /*
1197   * setup info about mdio interface
1198   */
1199  sc->mdio_info.mdio_r   = fec_mdio_read;
1200  sc->mdio_info.mdio_w   = fec_mdio_write;
1201  sc->mdio_info.has_gmii = 0; /* we do not support gigabit IF */
1202  /*
1203   * assume: IF 1 -> PHY 0
1204   */
1205  sc->phy_default = unitNumber-1;
1206
1207  /*
1208   * Set up network interface values
1209   */
1210  ifp->if_softc = sc;
1211  ifp->if_unit = unitNumber;
1212  ifp->if_name = unitName;
1213  ifp->if_mtu = mtu;
1214  ifp->if_init = fec_init;
1215  ifp->if_ioctl = fec_ioctl;
1216  ifp->if_start = m8xx_fec_enet_start;
1217  ifp->if_output = ether_output;
1218  ifp->if_watchdog =  fec_watchdog; /* XXX: timer is set in "init" */
1219  ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
1220  if (ifp->if_snd.ifq_maxlen == 0)
1221    ifp->if_snd.ifq_maxlen = ifqmaxlen;
1222
1223  /*
1224   * Attach the interface
1225   */
1226  if_attach (ifp);
1227  ether_ifattach (ifp);
1228  return 1;
1229};
1230
1231int rtems_fec_enet_driver_attach(struct rtems_bsdnet_ifconfig *config,
1232                                 int attaching)
1233{
1234  /*
1235   * enable FEC functionality at hardware pins*
1236   * PD[3-15] are FEC pins
1237   */
1238  if (attaching) {
1239    m8xx.pdpar |= 0x1fff;
1240    m8xx.pddir |= 0x1fff;
1241  }
1242  return rtems_fec_driver_attach(config);
1243}
Note: See TracBrowser for help on using the repository browser.