source: rtems-libbsd/rtemsbsd/sys/dev/ffec/if_ffec_mpc8xx.c @ d101ed8

5-freebsd-12
Last change on this file since d101ed8 was d101ed8, checked in by Sebastian Huber <sebastian.huber@…>, on Sep 14, 2018 at 7:43:12 AM

if_ffec_mpc8xx: New MDIO driver support

Update #3523.

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