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

5
Last change on this file since d8d6a08 was d8d6a08, checked in by Sebastian Huber <sebastian.huber@…>, on Jan 27, 2018 at 10:12:44 AM

bsps: Move network define to source files

Define INSIDE_RTEMS_BSD_TCPIP_STACK in the network interface driver
source files to avoid some build system magic.

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