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

5-freebsd-12
Last change on this file since 457b4fc was 457b4fc, checked in by Sebastian Huber <sebastian.huber@…>, on Sep 12, 2018 at 1:15:12 PM

if_ffec_mpc8xx: Port driver to libbsd

Update #3523.

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