source: rtems/c/src/lib/libbsp/powerpc/gen5200/network_5200/network.c @ c5feb602

4.104.114.84.95
Last change on this file since c5feb602 was c5feb602, checked in by Joel Sherrill <joel.sherrill@…>, on 09/11/06 at 21:44:06

2006-09-11 Joel Sherrill <joel@…>

  • include/mpc5200.h, network_5200/network.c: Convert C++ style comments to C style.
  • Property mode set to 100644
File size: 43.6 KB
Line 
1/*===============================================================*\
2| Project: RTEMS generic MPC5200 BSP                              |
3+-----------------------------------------------------------------+
4| Partially based on the code references which are named below.   |
5| Adaptions, modifications, enhancements and any recent parts of  |
6| the code are:                                                   |
7|                    Copyright (c) 2005                           |
8|                    Embedded Brains GmbH                         |
9|                    Obere Lagerstr. 30                           |
10|                    D-82178 Puchheim                             |
11|                    Germany                                      |
12|                    rtems@embedded-brains.de                     |
13+-----------------------------------------------------------------+
14| The license and distribution terms for this file may be         |
15| found in the file LICENSE in this distribution or at            |
16|                                                                 |
17| http://www.rtems.com/license/LICENSE.                           |
18|                                                                 |
19+-----------------------------------------------------------------+
20| this file contains the networking driver                        |
21\*===============================================================*/
22/*
23 *  RTEMS/TCPIP driver for MPC5200 FEC Ethernet
24 *
25 *  Modified for Motorola MPC5200 by Thomas Doerfler, <Thomas.Doerfler@imd-systems.de>
26 *  COPYRIGHT (c) 2003, IMD
27 *
28 *  Modified for Motorola IceCube (mgt5100) by Peter Rasmussen <prasmus@ipr-engineering.de>
29 *  COPYRIGHT (c) 2003, IPR Engineering
30 *
31 *  Parts of code are also under property of Driver Information Systems and based
32 *  on Motorola Proprietary Information.
33 *  COPYRIGHT (c) 2002 MOTOROLA INC.
34 *
35 *  Modified for MPC860 by Jay Monkman (jmonkman@frasca.com)
36 *
37 *  This supports Ethernet on either SCC1 or the FEC of the MPC860T.
38 *  Right now, we only do 10 Mbps, even with the FEC. The function
39 *  rtems_enet_driver_attach determines which one to use. Currently,
40 *  only one may be used at a time.
41 *
42 *  Based on the MC68360 network driver by
43 *  W. Eric Norum
44 *  Saskatchewan Accelerator Laboratory
45 *  University of Saskatchewan
46 *  Saskatoon, Saskatchewan, CANADA
47 *  eric@skatter.usask.ca
48 *
49 *  This supports ethernet on SCC1. Right now, we only do 10 Mbps.
50 *
51 *  Modifications by Darlene Stewart <Darlene.Stewart@iit.nrc.ca>
52 *  and Charles-Antoine Gauthier <charles.gauthier@iit.nrc.ca>
53 *  Copyright (c) 1999, National Research Council of Canada
54 *
55 */
56#include <rtems.h>
57#include <rtems/error.h>
58#include <rtems/rtems_bsdnet.h>
59#include <stdio.h>
60#include <sys/param.h>
61#include <sys/mbuf.h>
62#include <sys/socket.h>
63#include <sys/sockio.h>
64#include <net/if.h>
65#include <netinet/in.h>
66#include <netinet/if_ether.h>
67#include <bsp.h>
68#include "../irq/irq.h"
69#include "../include/mpc5200.h"
70#include <net/if_var.h>
71#include <errno.h>
72
73/* motorola-capi-specifics... */
74#include "../bestcomm/include/ppctypes.h"       /* uint32, et. al.                      */
75#include "../bestcomm/dma_image.h"
76#include "../bestcomm/bestcomm_glue.h"
77
78
79#define SDMA_BD_TFD     0x08000000      /*< Transmit Frame Done         */
80#define SDMA_BD_INT     0x04000000      /*< Interrupt on frame done     */
81#define SDMA_BD_RX_NUM  64 /* Number of receive buffer descriptors      */
82#define SDMA_BD_TX_NUM  64 /* Number of transmit buffer descriptors     */
83
84#define SET_BD_STATUS(bd, stat) {               \
85        (bd)->Status &= 0x0000ffff;                     \
86        (bd)->Status |= 0xffff0000 & stat;      \
87}
88#define SET_BD_LENGTH(bd, len) {                \
89        (bd)->Status &= 0xffff0000;                     \
90        (bd)->Status |= 0x0000ffff & len;       \
91}
92#define GET_BD_STATUS(bd)               ((bd)->Status & 0xffff0000)
93#define GET_BD_LENGTH(bd)               ((bd)->Status & 0x0000ffff)
94#define GET_SDMA_PENDINGBIT(Bit)   \
95   (mpc5200.IntPend & (uint32)(1<<Bit))
96
97#include "../bestcomm/bestcomm_api.h"
98#include "../bestcomm/task_api/bestcomm_cntrl.h"
99#include "../bestcomm/task_api/tasksetup_bdtable.h"
100
101extern TaskBDIdxTable_t TaskBDIdxTable[MAX_TASKS];
102
103static TaskId rxTaskId; /* SDMA RX task ID */
104static TaskId txTaskId; /* SDMA TX task ID */
105
106/*#define ETH_DEBUG*/
107
108/*
109 * Number of interfaces supported by this driver
110 */
111#define NIFACES 1
112
113/*
114 * Default number of buffer descriptors set aside for this driver.
115 * The number of transmit buffer descriptors has to be quite large
116 * since a single frame often uses four or more buffer descriptors.
117 */
118#define RX_BUF_COUNT     SDMA_BD_RX_NUM
119#define TX_BUF_COUNT     SDMA_BD_TX_NUM
120#define TX_BD_PER_BUF    1
121
122#define INET_ADDR_MAX_BUF_SIZE (sizeof "255.255.255.255")
123
124
125/*
126 * RTEMS event used by interrupt handler to signal daemons.
127 * This must *not* be the same event used by the TCP/IP task synchronization.
128 */
129#define INTERRUPT_EVENT RTEMS_EVENT_1
130#define FATAL_INT_EVENT RTEMS_EVENT_3
131
132/*
133 * RTEMS event used to start transmit daemon.
134 * This must not be the same as INTERRUPT_EVENT.
135 */
136#define START_TRANSMIT_EVENT RTEMS_EVENT_2
137
138/* Task number assignment */
139#define FEC_RECV_TASK_NO            TASK_FEC_RX
140#define FEC_XMIT_TASK_NO            TASK_FEC_TX
141
142
143/* BD and parameters are stored in SRAM(refer to sdma.h) */
144#define MPC5200_FEC_BD_BASE    ETH_BD_BASE
145
146/* FEC transmit watermark settings */
147#define MPC5200_FEC_X_WMRK_64   0x0     /* or 0x1 */
148#define MPC5200_FEC_X_WMRK_128  0x2
149#define MPC5200_FEC_X_WMRK_192  0x3
150
151/* RBD bits definitions */
152#define MPC5200_FEC_RBD_EMPTY  0x8000   /* Buffer is empty */
153#define MPC5200_FEC_RBD_WRAP   0x2000   /* Last BD in ring */
154#define MPC5200_FEC_RBD_INT    0x1000   /* Interrupt */
155#define MPC5200_FEC_RBD_LAST   0x0800   /* Buffer is last in frame(useless) */
156#define MPC5200_FEC_RBD_MISS   0x0100   /* Miss bit for prom mode */
157#define MPC5200_FEC_RBD_BC     0x0080   /* The received frame is broadcast frame */
158#define MPC5200_FEC_RBD_MC     0x0040   /* The received frame is multicast frame */
159#define MPC5200_FEC_RBD_LG     0x0020   /* Frame length violation */
160#define MPC5200_FEC_RBD_NO     0x0010   /* Nonoctet align frame */
161#define MPC5200_FEC_RBD_SH     0x0008   /* Short frame, FEC does not support SH and this bit is always cleared */
162#define MPC5200_FEC_RBD_CR     0x0004   /* CRC error */
163#define MPC5200_FEC_RBD_OV     0x0002   /* Receive FIFO overrun */
164#define MPC5200_FEC_RBD_TR     0x0001   /* The receive frame is truncated */
165#define MPC5200_FEC_RBD_ERR    (MPC5200_FEC_RBD_LG  | \
166                                MPC5200_FEC_RBD_NO  | \
167                                MPC5200_FEC_RBD_CR  | \
168                                MPC5200_FEC_RBD_OV  | \
169                                MPC5200_FEC_RBD_TR)
170
171/* TBD bits definitions */
172#define MPC5200_FEC_TBD_READY  0x8000   /* Buffer is ready */
173#define MPC5200_FEC_TBD_WRAP   0x2000   /* Last BD in ring */
174#define MPC5200_FEC_TBD_INT    0x1000   /* Interrupt */
175#define MPC5200_FEC_TBD_LAST   0x0800   /* Buffer is last in frame */
176#define MPC5200_FEC_TBD_TC     0x0400   /* Transmit the CRC */
177#define MPC5200_FEC_TBD_ABC    0x0200   /* Append bad CRC */
178
179/* MII-related definitios */
180#define MPC5200_FEC_MII_DATA_ST       0x40000000        /* Start of frame delimiter */
181#define MPC5200_FEC_MII_DATA_OP_RD    0x20000000        /* Perform a read operation */
182#define MPC5200_FEC_MII_DATA_OP_WR    0x10000000        /* Perform a write operation */
183#define MPC5200_FEC_MII_DATA_PA_MSK   0x0f800000        /* PHY Address field mask */
184#define MPC5200_FEC_MII_DATA_RA_MSK   0x007c0000        /* PHY Register field mask */
185#define MPC5200_FEC_MII_DATA_TA       0x00020000        /* Turnaround */
186#define MPC5200_FEC_MII_DATA_DATAMSK  0x0000fff     /* PHY data field */
187
188#define MPC5200_FEC_MII_DATA_RA_SHIFT 0x12      /* MII Register address bits */
189#define MPC5200_FEC_MII_DATA_PA_SHIFT 0x17      /* MII PHY address bits */
190
191
192/* Receive & Transmit Buffer Descriptor definitions */
193typedef struct mpc5200_buffer_desc_
194  {
195  volatile uint16_t status;
196  volatile uint16_t length;
197  volatile void             *buffer;
198  } mpc5200_buffer_desc_t;
199
200
201#define FEC_INTR_MASK_USED \
202(FEC_INTR_LCEN  |FEC_INTR_CRLEN |\
203 FEC_INTR_XFUNEN|FEC_INTR_XFERREN|FEC_INTR_RFERREN)
204
205/*
206 * Device data
207 */
208struct mpc5200_enet_struct {
209#if 0
210  struct ifnet            ac_if;
211#else
212  struct arpcom           arpcom;
213#endif
214  struct mbuf             **rxMbuf;
215  struct mbuf             **txMbuf;
216  int                     acceptBroadcast;
217  int                     rxBdCount;
218  int                     txBdCount;
219  int                     txBdHead;
220  int                     txBdTail;
221  int                     txBdActiveCount;
222
223  rtems_id                rxDaemonTid;
224  rtems_id                txDaemonTid;
225
226  unsigned long           rxInterrupts;
227  unsigned long           rxNotLast;
228  unsigned long           rxGiant;
229  unsigned long           rxNonOctet;
230  unsigned long           rxBadCRC;
231  unsigned long           rxOverrun;
232  unsigned long           rxCollision;
233
234  unsigned long           txInterrupts;
235  unsigned long           txDeferred;
236  unsigned long           txLateCollision;
237  unsigned long           txUnderrun;
238  unsigned long           txMisaligned;
239  unsigned long           rxNotFirst;
240  unsigned long           txRetryLimit;
241  };
242
243static struct mpc5200_enet_struct enet_driver[NIFACES];
244
245extern int taskTable;
246static void mpc5200_fec_restart(struct mpc5200_enet_struct *sc);
247
248
249
250/*
251 * Function:    mpc5200_fec_rx_bd_init
252 *
253 * Description: Initialize the receive buffer descriptor ring.
254 *
255 * Returns:             void
256 *
257 * Notes:       Space for the buffers of rx BDs is allocated by the rx deamon
258 *
259 */
260static void mpc5200_fec_rx_bd_init(struct mpc5200_enet_struct *sc) {
261  int rxBdIndex;
262  struct mbuf *m;
263  struct ifnet *ifp = &sc->arpcom.ac_if;
264  BDIdx bdi;
265
266  /*
267   * Fill RX buffer descriptor ring.
268   */
269  for( rxBdIndex = 0; rxBdIndex < sc->rxBdCount; rxBdIndex++ ) {
270    MGETHDR (m, M_WAIT, MT_DATA);
271    MCLGET (m, M_WAIT);
272
273    m->m_pkthdr.rcvif = ifp;
274    sc->rxMbuf[rxBdIndex] = m;
275    bdi = TaskBDAssign( rxTaskId,
276                        mtod(m, void *),
277                        NULL,
278                        ETHER_MAX_LEN,
279                        0 );
280    if (bdi != rxBdIndex) {
281      rtems_panic("network rx buffer indices out of sync");
282    }
283  }
284}
285
286/*
287 * Function:    mpc5200_fec_rx_bd_cleanup
288 *
289 * Description: put all mbufs pending in rx BDs back to buffer pool
290 *
291 * Returns:             void
292 *
293 */
294static void mpc5200_fec_rx_bd_cleanup(struct mpc5200_enet_struct *sc) {
295  int rxBdIndex;
296  struct mbuf *m,*n;
297
298  /*
299   * Drain RX buffer descriptor ring.
300   */
301  for( rxBdIndex = 0; rxBdIndex < sc->rxBdCount; rxBdIndex++ ) {
302    n = sc->rxMbuf[rxBdIndex];
303    while (n != NULL) {
304      m = n;
305      MFREE(m,n);
306    }
307  }
308}
309
310/*
311 * Function:    MPC5200_eth_addr_filter_set
312 *
313 * Description: Set individual address filter for unicast address and
314 *                              set physical address registers.
315 *
316 * Returns:             void
317 *
318 * Notes:
319 *
320 */
321static void mpc5200_eth_addr_filter_set(struct mpc5200_enet_struct *sc)  {
322  unsigned char *mac;
323  unsigned char currByte;                               /* byte for which to compute the CRC */
324  int           byte;                                   /* loop - counter */
325  int           bit;                                    /* loop - counter */
326  unsigned long crc = 0xffffffff;               /* initial value */
327
328 /*
329  * Get the mac address of ethernet controller
330  */
331  mac = (unsigned char *)(&sc->arpcom.ac_enaddr);
332
333 /*
334  * The algorithm used is the following:
335  * we loop on each of the six bytes of the provided address,
336  * and we compute the CRC by left-shifting the previous
337  * value by one position, so that each bit in the current
338  * byte of the address may contribute the calculation. If
339  * the latter and the MSB in the CRC are different, then
340  * the CRC value so computed is also ex-ored with the
341  * "polynomium generator". The current byte of the address
342  * is also shifted right by one bit at each iteration.
343  * This is because the CRC generatore in hardware is implemented
344  * as a shift-register with as many ex-ores as the radixes
345  * in the polynomium. This suggests that we represent the
346  * polynomiumm itself as a 32-bit constant.
347  */
348  for(byte = 0; byte < 6; byte++)
349    {
350
351    currByte = mac[byte];
352
353    for(bit = 0; bit < 8; bit++)
354      {
355
356      if((currByte & 0x01) ^ (crc & 0x01))
357        {
358
359        crc >>= 1;
360        crc = crc ^ 0xedb88320;
361
362        }
363      else
364        {
365
366        crc >>= 1;
367
368        }
369
370      currByte >>= 1;
371
372      }
373
374    }
375
376    crc = crc >> 26;
377
378   /*
379    * Set individual hash table register
380    */
381    if(crc >= 32)
382      {
383
384      mpc5200.iaddr1 = (1 << (crc - 32));
385      mpc5200.iaddr2 = 0;
386
387      }
388    else
389     {
390
391     mpc5200.iaddr1 = 0;
392     mpc5200.iaddr2 = (1 << crc);
393
394     }
395
396   /*
397    * Set physical address
398    */
399    mpc5200.paddr1 = (mac[0] << 24) + (mac[1] << 16) + (mac[2] << 8) + mac[3];
400    mpc5200.paddr2 = (mac[4] << 24) + (mac[5] << 16) + 0x8808;
401
402   }
403
404
405/*
406 * Function:    mpc5200_eth_mii_read
407 *
408 * Description: Read a media independent interface (MII) register on an
409 *                              18-wire ethernet tranceiver (PHY). Please see your PHY
410 *                              documentation for the register map.
411 *
412 * Returns:             32-bit register value
413 *
414 * Notes:
415 *
416 */
417int mpc5200_eth_mii_read(struct mpc5200_enet_struct *sc, unsigned char phyAddr, unsigned char regAddr, unsigned short * retVal)
418  {
419  unsigned long reg;            /* convenient holder for the PHY register */
420  unsigned long phy;            /* convenient holder for the PHY */
421  int timeout = 0xffff;
422
423 /*
424  * reading from any PHY's register is done by properly
425  * programming the FEC's MII data register.
426  */
427  reg = regAddr << MPC5200_FEC_MII_DATA_RA_SHIFT;
428  phy = phyAddr << MPC5200_FEC_MII_DATA_PA_SHIFT;
429
430  mpc5200.mii_data = (MPC5200_FEC_MII_DATA_ST | MPC5200_FEC_MII_DATA_OP_RD | MPC5200_FEC_MII_DATA_TA | phy | reg);
431
432 /*
433  * wait for the related interrupt
434  */
435  while ((timeout--) && (!(mpc5200.ievent & 0x00800000)));
436
437  if(timeout == 0)
438    {
439
440#ifdef ETH_DEBUG
441    printf ("Read MDIO failed..." "\r\n");
442#endif
443
444        return FALSE;
445
446        }
447
448 /*
449  * clear mii interrupt bit
450  */
451  mpc5200.ievent = 0x00800000;
452
453 /*
454  * it's now safe to read the PHY's register
455  */
456  *retVal = (unsigned short)mpc5200.mii_data;
457
458  return TRUE;
459
460  }
461
462/*
463 * Function:    mpc5200_eth_mii_write
464 *
465 * Description: Write a media independent interface (MII) register on an
466 *                              18-wire ethernet tranceiver (PHY). Please see your PHY
467 *                              documentation for the register map.
468 *
469 * Returns:             Success (boolean)
470 *
471 * Notes:
472 *
473 */
474static int mpc5200_eth_mii_write(struct mpc5200_enet_struct *sc, unsigned char phyAddr, unsigned char regAddr, unsigned short data)
475  {
476  unsigned long reg;                                    /* convenient holder for the PHY register */
477  unsigned long phy;                                    /* convenient holder for the PHY */
478  int timeout = 0xffff;
479
480  reg = regAddr << MPC5200_FEC_MII_DATA_RA_SHIFT;
481  phy = phyAddr << MPC5200_FEC_MII_DATA_PA_SHIFT;
482
483  mpc5200.mii_data = (MPC5200_FEC_MII_DATA_ST | MPC5200_FEC_MII_DATA_OP_WR | MPC5200_FEC_MII_DATA_TA | phy | reg | data);
484
485 /*
486  * wait for the MII interrupt
487  */
488  while ((timeout--) && (!(mpc5200.ievent & 0x00800000)));
489
490  if(timeout == 0)
491    {
492
493#ifdef ETH_DEBUG
494    printf ("Write MDIO failed..." "\r\n");
495#endif
496
497    return FALSE;
498
499    }
500
501 /*
502  * clear MII interrupt bit
503  */
504  mpc5200.ievent = 0x00800000;
505
506  return TRUE;
507
508  }
509
510
511/*
512 * Function:    mpc5200_fec_reset
513 *
514 * Description: Reset a running ethernet driver including the hardware
515 *                              FIFOs and the FEC.
516 *
517 * Returns:             Success (boolean)
518 *
519 * Notes:
520 *
521 */
522static int mpc5200_fec_reset(struct mpc5200_enet_struct *sc) {
523  volatile int delay;
524  /*
525   * Clear FIFO status registers
526   */
527  mpc5200.rfifo_status &= FEC_FIFO_STAT_ERROR;
528  mpc5200.tfifo_status &= FEC_FIFO_STAT_ERROR;
529 
530  /*
531   * reset the FIFOs
532   */
533  mpc5200.reset_cntrl = 0x03000000;
534
535  for (delay = 0;delay < 16*4;delay++) {};
536
537  mpc5200.reset_cntrl = 0x01000000;
538 
539  /*
540   * Issue a reset command to the FEC chip
541   */
542  mpc5200.ecntrl |= FEC_ECNTRL_RESET;
543 
544  /*
545   * wait at least 16 clock cycles
546   */
547  for (delay = 0;delay < 16*4;delay++) {};
548 
549  return TRUE;
550}
551
552
553/*
554 * Function:    mpc5200_fec_off
555 *
556 * Description: Stop the FEC and disable the ethernet SmartComm tasks.
557 *                              This function "turns off" the driver.
558 *
559 * Returns:             void
560 *
561 * Notes:
562 *
563 */
564void mpc5200_fec_off(struct mpc5200_enet_struct *sc)
565  {
566  int            counter = 0xffff;
567
568#if defined(ETH_DEBUG)
569  unsigned short phyStatus, i;
570  unsigned char  phyAddr = 0;
571
572  for(i = 0; i < 9; i++)
573    {
574
575    mpc5200_eth_mii_read(sc, phyAddr, i, &phyStatus);
576    printf ("Mii reg %d: 0x%04x" "\r\n", i, phyStatus);
577
578    }
579
580  for(i = 16; i < 21; i++)
581    {
582
583    mpc5200_eth_mii_read(sc, phyAddr, i, &phyStatus);
584    printf ("Mii reg %d: 0x%04x" "\r\n", i, phyStatus);
585
586    }
587#endif  /* ETH_DEBUG */
588
589 /*
590  * block FEC chip interrupts
591  */
592  mpc5200.imask = 0;
593
594 /*
595  * issue graceful stop command to the FEC transmitter if necessary
596  */
597  mpc5200.x_cntrl |= FEC_XCNTRL_GTS;
598
599 /*
600  * wait for graceful stop to register
601  * FIXME: add rtems_task_wake_after here, if it takes to long
602  */
603  while((counter--) && (!(mpc5200.ievent & FEC_INTR_GRA)));
604
605  /*
606   * Disable the SmartDMA transmit and receive tasks.
607   */
608  TaskStop( rxTaskId );
609  TaskStop( txTaskId );
610 /*
611  * Disable transmit / receive interrupts
612  */
613  bestcomm_glue_irq_disable(FEC_XMIT_TASK_NO);
614  bestcomm_glue_irq_disable(FEC_RECV_TASK_NO);
615
616 /*
617  * Disable the Ethernet Controller
618  */
619  mpc5200.ecntrl &= ~(FEC_ECNTRL_OE | FEC_ECNTRL_EN);
620
621  /*
622   * cleanup all buffers
623   */
624  mpc5200_fec_rx_bd_cleanup(sc);
625
626  }
627
628/*
629 * MPC5200 FEC interrupt handler
630 */
631void mpc5200_fec_irq_handler(rtems_irq_hdl_param handle)
632{
633  struct mpc5200_enet_struct *sc = (struct mpc5200_enet_struct *) handle;
634  volatile uint32_t ievent;
635
636  ievent = mpc5200.ievent;
637
638  mpc5200.ievent = ievent;
639  /*
640   * check errors, update statistics
641   */
642  if (ievent & FEC_INTR_LATE_COL) {
643    sc->txLateCollision++;
644  }
645  if (ievent & FEC_INTR_COL_RETRY) {
646    sc->txRetryLimit++;
647  }
648  if (ievent & FEC_INTR_XFIFO_UN) {
649    sc->txUnderrun++;
650  }
651  if (ievent & FEC_INTR_XFIFO_ERR) {
652    sc->txUnderrun++;
653  }
654  if (ievent & FEC_INTR_RFIFO_ERR) {
655    sc->rxOverrun++;
656  }
657  /*
658   * fatal error ocurred?
659   */
660  if (ievent & (FEC_INTR_XFIFO_ERR | FEC_INTR_RFIFO_ERR)) {
661    mpc5200.imask &= ~(FEC_INTR_XFERREN | FEC_INTR_RFERREN);
662    rtems_event_send(enet_driver[0].rxDaemonTid, FATAL_INT_EVENT);
663  }
664}
665
666/*
667 * MPC5200 SmartComm ethernet interrupt handler
668 */
669void mpc5200_smartcomm_rx_irq_handler(rtems_irq_hdl_param unused)
670  {
671 /* Frame received? */
672  if(GET_SDMA_PENDINGBIT(FEC_RECV_TASK_NO))
673    {
674
675      SDMA_CLEAR_IEVENT(&mpc5200.IntPend,FEC_RECV_TASK_NO);
676
677      bestcomm_glue_irq_disable(FEC_RECV_TASK_NO);/*Disable receive ints*/
678
679      enet_driver[0].rxInterrupts++;            /* Rx int has occurred */
680     
681      rtems_event_send(enet_driver[0].rxDaemonTid, INTERRUPT_EVENT);
682
683    }
684  }
685
686/*
687 * MPC5200 SmartComm ethernet interrupt handler
688 */
689void mpc5200_smartcomm_tx_irq_handler(rtems_irq_hdl_param unused)
690  {
691 /* Buffer transmitted or transmitter error? */
692  if(GET_SDMA_PENDINGBIT(FEC_XMIT_TASK_NO))
693    {
694
695      SDMA_CLEAR_IEVENT(&mpc5200.IntPend,FEC_XMIT_TASK_NO);
696
697      bestcomm_glue_irq_disable(FEC_XMIT_TASK_NO);/*Disable tx ints*/
698
699      enet_driver[0].txInterrupts++; /* Tx int has occurred */
700
701      rtems_event_send(enet_driver[0].txDaemonTid, INTERRUPT_EVENT);
702
703    }
704
705  }
706
707
708
709
710
711 /*
712  * Function:       mpc5200_fec_retire_tbd
713  *
714  * Description:        Soak up buffer descriptors that have been sent.
715  *
716  * Returns:            void
717  *
718  * Notes:
719  *
720  */
721static void mpc5200_fec_retire_tbd(struct mpc5200_enet_struct *sc,
722                                   boolean force)
723{
724  struct mbuf *n;
725  TaskBD1_t   *bdRing = (TaskBD1_t *)TaskGetBDRing( txTaskId );;
726  /*
727   * Clear already transmitted BDs first. Will not work calling same
728   * from fecExceptionHandler(TFINT).
729   */
730 
731  while ((sc->txBdActiveCount > 0) &&
732         (force || (bdRing[sc->txBdTail].Status == 0x0))) {
733    if (sc->txMbuf[sc->txBdTail] != NULL) {
734      /*
735       * NOTE: txMbuf can be NULL, if mbuf has been split into different BDs
736       */
737      MFREE (sc->txMbuf[sc->txBdTail],n);
738      sc->txMbuf[sc->txBdTail] = NULL;
739    }
740    sc->txBdActiveCount--;
741    if(++sc->txBdTail >= sc->txBdCount) {
742      sc->txBdTail = 0;
743    }   
744  }
745}
746
747 /*
748  * Function:        mpc5200_fec_tx_bd_requeue
749  *
750  * Description:        put buffers back to interface output queue
751  *
752  * Returns:            void
753  *
754  * Notes:
755  *
756  */
757static void mpc5200_fec_tx_bd_requeue(struct mpc5200_enet_struct *sc)
758{
759  /*
760   * Clear already transmitted BDs first. Will not work calling same
761   * from fecExceptionHandler(TFINT).
762   */
763 
764  while (sc->txBdActiveCount > 0) {
765    if (sc->txMbuf[sc->txBdHead] != NULL) {
766      /*
767       * NOTE: txMbuf can be NULL, if mbuf has been split into different BDs
768       */
769      IF_PREPEND(&(sc->arpcom.ac_if.if_snd),sc->txMbuf[sc->txBdHead]);
770      sc->txMbuf[sc->txBdHead] = NULL;
771    }
772    sc->txBdActiveCount--;
773    if(--sc->txBdHead < 0) {
774      sc->txBdHead = sc->txBdCount-1;
775    }   
776  }
777}
778
779static void mpc5200_fec_sendpacket(struct ifnet *ifp,struct mbuf *m) {
780  struct mpc5200_enet_struct *sc = ifp->if_softc;
781  struct mbuf *l = NULL;
782  int nAdded;
783  uint32_t status;
784  rtems_event_set events;
785  TaskBD1_t *bdRing = (TaskBD1_t *)TaskGetBDRing( txTaskId );
786  TaskBD1_t *thisBd;
787  TaskBD1_t *firstBd = NULL;
788  void *data_ptr;
789  size_t data_len;
790
791 /*
792  * Free up buffer descriptors
793  */
794  mpc5200_fec_retire_tbd(sc,FALSE);
795
796 /*
797  * Set up the transmit buffer descriptors.
798  * No need to pad out short packets since the
799  * hardware takes care of that automatically.
800  * No need to copy the packet to a contiguous buffer
801  * since the hardware is capable of scatter/gather DMA.
802  */
803  nAdded = 0;
804
805  for(;;) {
806
807   /*
808    * Wait for buffer descriptor to become available.
809    */
810    if((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
811     
812      /*
813       * Clear old events
814       */
815      SDMA_CLEAR_IEVENT(&mpc5200.IntPend,FEC_XMIT_TASK_NO);
816     
817      /*
818       * Wait for buffer descriptor to become available.
819       * Note that the buffer descriptors are checked
820       * *before* * entering the wait loop -- this catches
821       * the possibility that a buffer descriptor became
822       * available between the `if' above, and the clearing
823       * of the event register.
824       * This is to catch the case where the transmitter
825       * stops in the middle of a frame -- and only the
826       * last buffer descriptor in a frame can generate
827       * an interrupt.
828       */
829      mpc5200_fec_retire_tbd(sc,FALSE);
830     
831      while((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
832        bestcomm_glue_irq_enable(FEC_XMIT_TASK_NO);
833        rtems_bsdnet_event_receive(INTERRUPT_EVENT,
834                                   RTEMS_WAIT | RTEMS_EVENT_ANY,
835                                   RTEMS_NO_TIMEOUT, &events);
836        mpc5200_fec_retire_tbd(sc,FALSE);
837      }
838    }
839
840    if(m->m_len == 0) {
841      /*
842       * Just toss empty mbufs
843       */
844      struct mbuf *n;
845      MFREE(m, n);
846      m = n;     
847      if(l != NULL) {
848        l->m_next = m;
849      }
850    }
851    else {
852      /*
853       * Flush the buffer for this descriptor
854       */
855      /*rtems_cache_flush_multiple_data_lines((const void *)mtod(m, void *), m->m_len);*/
856      /*
857       * Fill in the buffer descriptor,
858       * set "end of frame" bit in status,
859       * if last mbuf in chain
860       */
861      thisBd             = bdRing + sc->txBdHead;
862      /*
863       * FIXME: do not send interrupt after every frame
864       * doing this every quarter of BDs is much more efficent
865       */
866      status             = ((m->m_next == NULL)
867                            ? TASK_BD_TFD | TASK_BD_INT
868                            : 0);
869      /*
870       * Don't set the READY flag till the
871       * whole packet has been readied.
872       */
873      if (firstBd != NULL) {
874        status |= (uint32)SDMA_BD_MASK_READY;
875      }
876      else {
877        firstBd = thisBd;
878      }     
879
880      data_ptr = mtod(m, void *);
881      data_len = (uint32)m->m_len;
882      sc->txMbuf[sc->txBdHead] = m;
883      /* go to next part in chain */
884      l = m;
885      m = m->m_next;
886
887      thisBd->DataPtr[0] = (uint32)data_ptr;
888      thisBd->Status     = (status
889                            |((uint32)SDMA_DRD_MASK_LENGTH & data_len));
890
891      nAdded++;
892      if(++(sc->txBdHead) == sc->txBdCount) {
893        sc->txBdHead = 0;
894      }
895    }
896    /*
897     * Set the transmit buffer status.
898     * Break out of the loop if this mbuf is the last in the frame.
899     */
900    if(m == NULL) {
901      if(nAdded) {
902        firstBd->Status     |= SDMA_BD_MASK_READY;
903        SDMA_TASK_ENABLE(SDMA_TCR, txTaskId);
904        sc->txBdActiveCount += nAdded; 
905      }
906      break;
907    }
908  } /* end of for(;;) */
909}
910
911
912/*
913 * Driver transmit daemon
914 */
915void mpc5200_fec_txDaemon(void *arg)
916  {
917  struct mpc5200_enet_struct *sc = (struct mpc5200_enet_struct *)arg;
918  struct ifnet *ifp = &sc->arpcom.ac_if;
919  struct mbuf *m;
920  rtems_event_set events;
921
922  for(;;) {
923   /*
924    * Wait for packet
925    */
926    bestcomm_glue_irq_enable(FEC_XMIT_TASK_NO);
927    rtems_bsdnet_event_receive(START_TRANSMIT_EVENT|INTERRUPT_EVENT,
928                               RTEMS_EVENT_ANY | RTEMS_WAIT,
929                               RTEMS_NO_TIMEOUT,
930                               &events);
931
932    /*
933     * Send packets till queue is empty
934     */
935    for(;;)
936      {
937
938      /*
939       * Get the next mbuf chain to transmit.
940       */
941      IF_DEQUEUE(&ifp->if_snd, m);
942
943      if (!m)
944        break;
945
946      mpc5200_fec_sendpacket(ifp, m);
947
948      }
949
950    ifp->if_flags &= ~IFF_OACTIVE;
951
952    }
953
954  }
955
956
957/*
958 * reader task
959 */
960static void mpc5200_fec_rxDaemon(void *arg){
961  struct mpc5200_enet_struct *sc = (struct mpc5200_enet_struct *)arg;
962  struct ifnet *ifp = &sc->arpcom.ac_if;
963  struct mbuf *m;
964  struct ether_header *eh;
965  int rxBdIndex;
966  uint32_t status;
967  size_t size;
968  rtems_event_set events;
969  uint16    len = 1;
970  TaskBD1_t *bd;
971  void      *dptr;
972  TaskBD1_t   *bdRing = (TaskBD1_t *)TaskGetBDRing( rxTaskId );;
973
974  /*
975   * Input packet handling loop
976   */
977  rxBdIndex = 0;
978 
979  for (;;) {
980    /*
981     * Clear old events
982     */
983    SDMA_CLEAR_IEVENT(&mpc5200.IntPend,FEC_RECV_TASK_NO);
984    /*
985     * Get the first BD pointer and its length.
986     */
987    bd     = bdRing + rxBdIndex;
988    status = bd->Status;
989    len    = (uint16)GET_BD_LENGTH( bd );
990     
991    /*
992     * Loop through BDs until we find an empty one. This indicates that
993     * the SmartDMA is still using it.
994     */
995    while( !(status & SDMA_BD_MASK_READY) ) {
996   
997      /*
998       * Remember the data pointer from this transfer.
999       */
1000      dptr = (void *)bd->DataPtr[0];
1001      m    = sc->rxMbuf[rxBdIndex];
1002      m->m_len = m->m_pkthdr.len = (len
1003                                    - sizeof(uint32_t) 
1004                                    - sizeof(struct ether_header));
1005      eh = mtod(m, struct ether_header *);
1006      m->m_data += sizeof(struct ether_header);
1007      ether_input(ifp, eh, m);
1008       
1009      /*
1010       * Done w/ the BD. Clean it.
1011       */
1012      sc->rxMbuf[rxBdIndex] = NULL;
1013       
1014      /*
1015       * Add a new buffer to the ring.
1016       */
1017      MGETHDR (m, M_WAIT, MT_DATA);
1018      MCLGET (m, M_WAIT);
1019      m->m_pkthdr.rcvif = ifp;
1020      size = ETHER_MAX_LEN;
1021
1022      sc->rxMbuf[rxBdIndex] = m;
1023      bd->DataPtr[0] = (uint32)mtod(m, void *);
1024      bd->Status = ( (  (uint32)SDMA_DRD_MASK_LENGTH & (uint32)size)
1025                     | ((uint32)SDMA_BD_MASK_READY));
1026       
1027      /*
1028       * advance to next BD
1029       */
1030      if (++rxBdIndex >= sc->rxBdCount) {
1031        rxBdIndex = 0;
1032      }
1033      /*
1034       * Get next BD pointer and its length.
1035       */
1036      bd     = bdRing + rxBdIndex;
1037      status = bd->Status;
1038      len    = (uint16)GET_BD_LENGTH( bd );   
1039    }
1040    /*
1041     * Unmask RXF (Full frame received) event
1042     */
1043    bestcomm_glue_irq_enable(FEC_RECV_TASK_NO);
1044     
1045    rtems_bsdnet_event_receive (INTERRUPT_EVENT | FATAL_INT_EVENT,
1046                                RTEMS_WAIT | RTEMS_EVENT_ANY,
1047                                RTEMS_NO_TIMEOUT, &events);
1048    if (events & FATAL_INT_EVENT) {
1049      /*
1050       * fatal interrupt ocurred, so reinit fec and restart bestcomm tasks
1051       */
1052      mpc5200_fec_restart(sc);
1053      rxBdIndex = 0;
1054    }
1055  }
1056}
1057
1058
1059/*
1060 * Function:    mpc5200_fec_initialize_hardware
1061 *
1062 * Description: Configure the MPC5200 FEC registers and enable the
1063 *                              SmartComm tasks. This function "turns on" the driver.
1064 *
1065 * Returns:             void
1066 *
1067 * Notes:
1068 *
1069 */
1070static void mpc5200_fec_initialize_hardware(struct mpc5200_enet_struct *sc)
1071  {
1072
1073 /*
1074  * Reset mpc5200 FEC
1075  */
1076  mpc5200_fec_reset(sc);
1077
1078 /*
1079  * Clear FEC-Lite interrupt event register (IEVENT)
1080  */
1081  mpc5200.ievent = FEC_INTR_CLEAR_ALL;
1082
1083 /*
1084  * Set interrupt mask register
1085  */
1086  mpc5200.imask = FEC_INTR_MASK_USED;
1087  /*
1088   * Set FEC-Lite receive control register (R_CNTRL)
1089   * frame length=1518, MII mode for 18-wire-transceiver
1090   */
1091  mpc5200.r_cntrl = ((ETHER_MAX_LEN << FEC_RCNTRL_MAX_FL_SHIFT)
1092                   | FEC_RCNTRL_FCE
1093                   | FEC_RCNTRL_MII_MODE);
1094 
1095  /*
1096   * Set FEC-Lite transmit control register (X_CNTRL)
1097   * full-duplex, heartbeat disabled
1098   */
1099  mpc5200.x_cntrl = FEC_XCNTRL_FDEN;
1100
1101
1102
1103 /*
1104  * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock(33Mhz)
1105  * and do not drop the Preamble.
1106  */
1107  mpc5200.mii_speed = (7 << 1); /* ipb_clk = 33 MHz */
1108
1109 /*
1110  * Set Opcode/Pause Duration Register
1111  */
1112  mpc5200.op_pause = 0x00010020;
1113
1114  /*
1115   * Set Rx FIFO alarm and granularity value
1116   */
1117  mpc5200.rfifo_cntrl = (FEC_FIFO_CNTRL_FRAME
1118                       | (0x7 << FEC_FIFO_CNTRL_GR_SHIFT));
1119  mpc5200.rfifo_alarm = 0x0000030c;
1120
1121  /*
1122   * Set Tx FIFO granularity value
1123   */
1124  mpc5200.tfifo_cntrl = (FEC_FIFO_CNTRL_FRAME
1125                       | (0x7 << FEC_FIFO_CNTRL_GR_SHIFT));
1126
1127  /*
1128   * Set transmit fifo watermark register (X_WMRK), default = 64
1129   */
1130  mpc5200.tfifo_alarm = 0x00000100;     /* 256 bytes */
1131  mpc5200.x_wmrk = FEC_XWMRK_256;       /* 256 bytes */
1132
1133 /*
1134  * Set individual address filter for unicast address
1135  * and set physical address registers.
1136  */
1137  mpc5200_eth_addr_filter_set(sc);
1138
1139 /*
1140  * Set multicast address filter
1141  */
1142  mpc5200.gaddr1 = 0x00000000;
1143  mpc5200.gaddr2 = 0x00000000;
1144
1145 /*
1146  * enable CRC in finite state machine register
1147  */
1148  mpc5200.xmit_fsm = FEC_FSM_CRC | FEC_FSM_ENFSM;
1149  }
1150
1151 /*
1152  * Initialize PHY(LXT971A):
1153  *
1154  *   Generally, on power up, the LXT971A reads its configuration
1155  *   pins to check for forced operation, If not cofigured for
1156  *   forced operation, it uses auto-negotiation/parallel detection
1157  *   to automatically determine line operating conditions.
1158  *   If the PHY device on the other side of the link supports
1159  *   auto-negotiation, the LXT971A auto-negotiates with it
1160  *   using Fast Link Pulse(FLP) Bursts. If the PHY partner does not
1161  *   support auto-negotiation, the LXT971A automatically detects
1162  *   the presence of either link pulses(10Mbps PHY) or Idle
1163  *   symbols(100Mbps) and sets its operating conditions accordingly.
1164  *
1165  *   When auto-negotiation is controlled by software, the following
1166  *   steps are recommended.
1167  *
1168  * Note:
1169  *   The physical address is dependent on hardware configuration.
1170  *
1171  * Returns:            void
1172  *
1173  * Notes:
1174  *
1175  */
1176static void mpc5200_fec_initialize_phy(struct mpc5200_enet_struct *sc)
1177  {
1178  int            timeout;
1179  unsigned short phyAddr = 0;
1180
1181
1182 /*
1183  * Reset PHY, then delay 300ns
1184  */
1185  mpc5200_eth_mii_write(sc, phyAddr, 0x0, 0x8000);
1186
1187  rtems_task_wake_after(2);
1188
1189 /* MII100 */
1190
1191 /*
1192  * Set the auto-negotiation advertisement register bits
1193  */
1194  mpc5200_eth_mii_write(sc, phyAddr, 0x4, 0x01e1);
1195
1196 /*
1197  * Set MDIO bit 0.12 = 1(&& bit 0.9=1?) to enable auto-negotiation
1198  */
1199  mpc5200_eth_mii_write(sc, phyAddr, 0x0, 0x1200);
1200
1201 /*
1202  * Wait for AN completion
1203  */
1204  timeout = 0x100;
1205#if 0
1206  do
1207    {
1208
1209    rtems_task_wake_after(2);
1210
1211    if((timeout--) == 0)
1212      {
1213
1214#if defined(ETH_DEBUG)
1215    printf ("MPC5200FEC PHY auto neg failed." "\r\n");
1216#endif
1217
1218      }
1219
1220    if(mpc5200_eth_mii_read(sc, phyAddr, 0x1, &phyStatus) != TRUE)
1221      {
1222
1223#if defined(ETH_DEBUG)
1224      printf ("MPC5200FEC PHY auto neg failed: 0x%04x." "\r\n", phyStatus);
1225#endif
1226
1227          return;
1228
1229          }
1230
1231    } while((phyStatus & 0x0020) != 0x0020);
1232
1233#endif
1234#if ETH_PROMISCOUS_MODE
1235  mpc5200.r_cntrl |= 0x00000008;   /* set to promiscous mode */
1236#endif
1237
1238#if ETH_LOOP_MODE
1239  mpc5200.r_cntrl |= 0x00000001;   /* set to loop mode */
1240#endif
1241
1242#if defined(ETH_DEBUG)
1243  int i;
1244 /*
1245  * Print PHY registers after initialization.
1246  */
1247  for(i = 0; i < 9; i++)
1248    {
1249
1250        mpc5200_eth_mii_read(sc, phyAddr, i, &phyStatus);
1251        printf ("Mii reg %d: 0x%04x" "\r\n", i, phyStatus);
1252
1253        }
1254
1255  for(i = 16; i < 21; i++)
1256    {
1257
1258    mpc5200_eth_mii_read(sc, phyAddr, i, &phyStatus);
1259    printf ("Mii reg %d: 0x%04x" "\r\n", i, phyStatus);
1260
1261    }
1262#endif  /* ETH_DEBUG */
1263
1264  }
1265
1266
1267/*
1268 * Send packet (caller provides header).
1269 */
1270static void mpc5200_fec_tx_start(struct ifnet *ifp)
1271  {
1272
1273  struct mpc5200_enet_struct *sc = ifp->if_softc;
1274
1275  ifp->if_flags |= IFF_OACTIVE;
1276
1277  rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
1278
1279  }
1280
1281
1282/*
1283 * set up sdma tasks for ethernet
1284 */
1285static void mpc5200_sdma_task_setup(struct mpc5200_enet_struct *sc) {
1286  TaskSetupParamSet_t   rxParam;        /* RX task setup parameters     */
1287  TaskSetupParamSet_t   txParam;        /* TX task setup parameters     */
1288
1289  /*
1290   * Setup the SDMA RX task.
1291   */
1292  rxParam.NumBD        = sc->rxBdCount;
1293  rxParam.Size.MaxBuf  = ETHER_MAX_LEN;
1294  rxParam.Initiator    = 0;
1295  rxParam.StartAddrSrc = (uint32)&(mpc5200.rfifo_data);
1296  rxParam.IncrSrc      = 0;
1297  rxParam.SzSrc        = sizeof(uint32_t);
1298  rxParam.StartAddrDst = (uint32)NULL;
1299  rxParam.IncrDst      = sizeof(uint32_t);
1300  rxParam.SzDst        = sizeof(uint32_t); 
1301  rxTaskId             = TaskSetup(TASK_FEC_RX,&rxParam );
1302
1303  /*
1304   * Setup the TX task.
1305   */
1306  txParam.NumBD        = sc->txBdCount;
1307  txParam.Size.MaxBuf  = ETHER_MAX_LEN;
1308  txParam.Initiator    = 0;
1309  txParam.StartAddrSrc = (uint32)NULL;
1310  txParam.IncrSrc      = sizeof(uint32_t);
1311  txParam.SzSrc        = sizeof(uint32_t);
1312  txParam.StartAddrDst = (uint32)&(mpc5200.tfifo_data);
1313  txParam.IncrDst      = 0;
1314  txParam.SzDst        = sizeof(uint32_t);
1315 
1316  txTaskId             = TaskSetup( TASK_FEC_TX, &txParam );
1317
1318}
1319
1320void mpc5200_fec_irq_on(const rtems_irq_connect_data* ptr)
1321{
1322  mpc5200.imask = FEC_INTR_MASK_USED;
1323}
1324
1325
1326int mpc5200_fec_irq_isOn(const rtems_irq_connect_data* ptr)
1327{
1328  return mpc5200.imask != 0;
1329}
1330
1331
1332void mpc5200_fec_irq_off(const rtems_irq_connect_data* ptr)
1333{
1334  mpc5200.imask = 0;
1335}
1336
1337
1338/*
1339 * Initialize and start the device
1340 */
1341static void mpc5200_fec_init(void *arg)
1342{
1343  struct mpc5200_enet_struct *sc = (struct mpc5200_enet_struct *)arg;
1344  struct ifnet *ifp = &sc->arpcom.ac_if;
1345  rtems_irq_connect_data fec_irq_data = {
1346    BSP_SIU_IRQ_ETH,
1347    mpc5200_fec_irq_handler, /* rtems_irq_hdl           */
1348    (rtems_irq_hdl_param)sc, /* (rtems_irq_hdl_param)   */
1349    mpc5200_fec_irq_on,      /* (rtems_irq_enable)      */
1350    mpc5200_fec_irq_off,     /* (rtems_irq_disable)     */
1351    mpc5200_fec_irq_isOn     /* (rtems_irq_is_enabled)  */
1352  };
1353
1354
1355  if(sc->txDaemonTid == 0)
1356    {
1357      /*
1358       * Allocate a set of mbuf pointers
1359       */
1360      sc->rxMbuf =
1361        malloc(sc->rxBdCount * sizeof *sc->rxMbuf, M_MBUF, M_NOWAIT);
1362      sc->txMbuf =
1363        malloc(sc->txBdCount * sizeof *sc->txMbuf, M_MBUF, M_NOWAIT);
1364     
1365      if(!sc->rxMbuf || !sc->txMbuf)
1366        rtems_panic ("No memory for mbuf pointers");
1367
1368      bestcomm_glue_init();
1369
1370      mpc5200_sdma_task_setup(sc);
1371   
1372      /*
1373       * Set up interrupts
1374       */
1375      bestcomm_glue_irq_install(FEC_RECV_TASK_NO,
1376                                mpc5200_smartcomm_rx_irq_handler,
1377                                NULL);
1378      bestcomm_glue_irq_install(FEC_XMIT_TASK_NO,
1379                                mpc5200_smartcomm_tx_irq_handler,
1380                                NULL);
1381      if(!BSP_install_rtems_irq_handler (&fec_irq_data)) {
1382        rtems_panic ("Can't attach MPC5x00 FEX interrupt handler\n");
1383      }
1384
1385      /* mpc5200_fec_tx_bd_init(sc); */
1386      mpc5200_fec_rx_bd_init(sc);
1387
1388      /*
1389       * reset and Set up mpc5200 FEC hardware
1390       */
1391      mpc5200_fec_initialize_hardware(sc);
1392      /*
1393       * Set up the phy
1394       */
1395      mpc5200_fec_initialize_phy(sc);
1396      /*
1397       * Set priority of different initiators
1398       */
1399      mpc5200.IPR0 = 7; /* always initiator     */
1400      mpc5200.IPR3 = 6; /* eth rx initiator     */
1401      mpc5200.IPR4 = 5; /* eth tx initiator     */
1402
1403      /*
1404       * Start driver tasks
1405       */
1406      sc->txDaemonTid = rtems_bsdnet_newproc("FEtx", 4096, mpc5200_fec_txDaemon, sc);
1407      sc->rxDaemonTid = rtems_bsdnet_newproc("FErx", 4096, mpc5200_fec_rxDaemon, sc);
1408      /*
1409       * Clear SmartDMA task interrupt pending bits.
1410       */
1411      TaskIntClear( rxTaskId );
1412   
1413      /*
1414       * Enable the SmartDMA receive task.
1415       */
1416      TaskStart( rxTaskId, 1, rxTaskId, 1 );
1417      TaskStart( txTaskId, 1, txTaskId, 1 );
1418      /*
1419       * Enable FEC-Lite controller
1420       */
1421      mpc5200.ecntrl |= (FEC_ECNTRL_OE | FEC_ECNTRL_EN);
1422
1423
1424    }
1425
1426  /*
1427   * Set flags appropriately
1428   */
1429  if(ifp->if_flags & IFF_PROMISC)
1430    mpc5200.r_cntrl |= 0x08;
1431  else
1432    mpc5200.r_cntrl &= ~0x08;
1433
1434  /*
1435   * Tell the world that we're running.
1436   */
1437  ifp->if_flags |= IFF_RUNNING;
1438}
1439
1440
1441static void enet_stats (struct mpc5200_enet_struct *sc)
1442{
1443  printf ("      Rx Interrupts:%-8lu", sc->rxInterrupts);
1444  printf ("       Not First:%-8lu", sc->rxNotFirst);
1445  printf ("        Not Last:%-8lu\n", sc->rxNotLast);
1446  printf ("              Giant:%-8lu", sc->rxGiant);
1447  printf ("       Non-octet:%-8lu\n", sc->rxNonOctet);
1448  printf ("            Bad CRC:%-8lu", sc->rxBadCRC);
1449  printf ("         Overrun:%-8lu", sc->rxOverrun);
1450  printf ("       Collision:%-8lu\n", sc->rxCollision);
1451 
1452  printf ("      Tx Interrupts:%-8lu", sc->txInterrupts);
1453  printf ("        Deferred:%-8lu", sc->txDeferred);
1454  printf ("  Late Collision:%-8lu\n", sc->txLateCollision);
1455  printf ("   Retransmit Limit:%-8lu", sc->txRetryLimit);
1456  printf ("        Underrun:%-8lu", sc->txUnderrun);
1457  printf ("      Misaligned:%-8lu\n", sc->txMisaligned);
1458
1459}
1460
1461/*
1462 * restart the driver, reinit the fec
1463 * this function is responsible to reinitialize the FEC in case a fatal
1464 * error has ocurred. This is needed, wen a RxFIFO Overrun or a TxFIFO underrun
1465 * has ocurred. In these cases, the FEC is automatically disabled, and
1466 * both FIFOs must be reset and the BestComm tasks must be restarted
1467 *
1468 * Note: the daemon tasks will continue to run
1469 * (in fact this function will be called in the context of the rx daemon task)
1470 */
1471#define NEW_SDMA_SETUP
1472
1473static void mpc5200_fec_restart(struct mpc5200_enet_struct *sc)
1474{
1475  /*
1476   * FIXME: bring Tx Daemon into idle state
1477   */
1478#ifdef NEW_SDMA_SETUP
1479  /*
1480   * cleanup remaining receive mbufs
1481   */
1482  mpc5200_fec_rx_bd_cleanup(sc);
1483#endif
1484  /*
1485   * Stop SDMA tasks
1486   */
1487  TaskStop( rxTaskId);
1488  TaskStop( txTaskId);
1489  /*
1490   * FIXME: wait, until Tx Daemon is in idle state
1491   */
1492
1493  /*
1494   * Disable transmit / receive interrupts
1495   */
1496  bestcomm_glue_irq_disable(FEC_XMIT_TASK_NO);
1497  bestcomm_glue_irq_disable(FEC_RECV_TASK_NO);
1498#ifdef NEW_SDMA_SETUP
1499  /*
1500   * recycle pending tx buffers
1501   * FIXME: try to extract pending Tx buffers
1502   */
1503#if 0
1504  mpc5200_fec_tx_bd_requeue(sc);
1505#else
1506  mpc5200_fec_retire_tbd(sc,TRUE);
1507#endif
1508#endif
1509  /*
1510   * re-initialize the FEC hardware
1511   */
1512  mpc5200_fec_initialize_hardware(sc);
1513
1514#ifdef NEW_SDMA_SETUP
1515  /*
1516   * completely reinitialize Bestcomm tasks
1517   */
1518  mpc5200_sdma_task_setup(sc);
1519
1520  /*
1521   * reinit receive mbufs
1522   */
1523  mpc5200_fec_rx_bd_init(sc);
1524#endif
1525  /*
1526   * Clear SmartDMA task interrupt pending bits.
1527   */
1528  TaskIntClear( rxTaskId );
1529 
1530  /*
1531   * Enable the SmartDMA receive/transmit task.
1532   */
1533  TaskStart( rxTaskId, 1, rxTaskId, 1 );
1534  TaskStart( txTaskId, 1, txTaskId, 1 );
1535  /*
1536   * reenable rx/tx interrupts
1537   */
1538  bestcomm_glue_irq_enable(FEC_XMIT_TASK_NO);
1539  bestcomm_glue_irq_enable(FEC_RECV_TASK_NO);
1540  /*
1541   * (re-)init fec hardware
1542   */
1543  mpc5200_fec_initialize_hardware(sc);
1544  /*
1545   * reenable fec FIFO error interrupts
1546   */
1547  mpc5200.imask = FEC_INTR_MASK_USED;
1548  /*
1549   * Enable FEC-Lite controller
1550   */
1551  mpc5200.ecntrl |= (FEC_ECNTRL_OE | FEC_ECNTRL_EN);
1552}
1553
1554
1555/*
1556 * Driver ioctl handler
1557 */
1558static int mpc5200_fec_ioctl (struct ifnet *ifp, u_long command, caddr_t data)
1559  {
1560  struct mpc5200_enet_struct *sc = ifp->if_softc;
1561  int error = 0;
1562
1563  switch(command)
1564    {
1565
1566    case SIOCGIFADDR:
1567    case SIOCSIFADDR:
1568
1569      ether_ioctl(ifp, command, data);
1570
1571      break;
1572
1573    case SIOCSIFFLAGS:
1574
1575      switch(ifp->if_flags & (IFF_UP | IFF_RUNNING))
1576        {
1577
1578        case IFF_RUNNING:
1579
1580          mpc5200_fec_off(sc);
1581
1582          break;
1583
1584        case IFF_UP:
1585
1586          mpc5200_fec_init(sc);
1587
1588          break;
1589
1590        case IFF_UP | IFF_RUNNING:
1591
1592          mpc5200_fec_off(sc);
1593          mpc5200_fec_init(sc);
1594
1595          break;
1596
1597        default:
1598          break;
1599
1600        }
1601
1602      break;
1603
1604    case SIO_RTEMS_SHOW_STATS:
1605
1606      enet_stats(sc);
1607
1608      break;
1609
1610   /*
1611    * FIXME: All sorts of multicast commands need to be added here!
1612    */
1613    default:
1614
1615    error = EINVAL;
1616
1617    break;
1618
1619    }
1620
1621  return error;
1622
1623  }
1624
1625
1626/*
1627 * Attach the MPC5200 fec driver to the system
1628 */
1629int rtems_mpc5200_fec_driver_attach(struct rtems_bsdnet_ifconfig *config)
1630  {
1631  struct mpc5200_enet_struct *sc;
1632  struct ifnet *ifp;
1633  int    mtu;
1634  int    unitNumber;
1635  char   *unitName;
1636
1637 /*
1638  * Parse driver name
1639  */
1640  if((unitNumber = rtems_bsdnet_parse_driver_name(config, &unitName)) < 0)
1641    return 0;
1642
1643 /*
1644  * Is driver free?
1645  */
1646  if ((unitNumber <= 0) || (unitNumber > NIFACES))
1647    {
1648
1649    printf ("Bad FEC unit number.\n");
1650    return 0;
1651
1652    }
1653
1654  sc = &enet_driver[unitNumber - 1];
1655  ifp = &sc->arpcom.ac_if;
1656
1657  if(ifp->if_softc != NULL)
1658    {
1659
1660    printf ("Driver already in use.\n");
1661    return 0;
1662
1663    }
1664
1665  /*
1666   * Process options
1667   */
1668#if NVRAM_CONFIGURE == 1
1669
1670  /* Configure from NVRAM */
1671  if(addr = nvram->ipaddr)
1672    {
1673
1674    /* We have a non-zero entry, copy the value */
1675    if(pAddr = malloc(INET_ADDR_MAX_BUF_SIZE, 0, M_NOWAIT))
1676      config->ip_address = (char *)inet_ntop(AF_INET, &addr, pAddr, INET_ADDR_MAX_BUF_SIZE -1);
1677    else
1678      rtems_panic("Can't allocate ip_address buffer!\n");
1679
1680    }
1681
1682  if(addr = nvram->netmask)
1683    {
1684
1685    /* We have a non-zero entry, copy the value */
1686    if (pAddr = malloc (INET_ADDR_MAX_BUF_SIZE, 0, M_NOWAIT))
1687      config->ip_netmask = (char *)inet_ntop(AF_INET, &addr, pAddr, INET_ADDR_MAX_BUF_SIZE -1);
1688    else
1689      rtems_panic("Can't allocate ip_netmask buffer!\n");
1690
1691    }
1692
1693  /* Ethernet address requires special handling -- it must be copied into
1694   * the arpcom struct. The following if construct serves only to give the
1695   * User Area NVRAM parameter the highest priority.
1696   *
1697   * If the ethernet address is specified in NVRAM, go ahead and copy it.
1698   * (ETHER_ADDR_LEN = 6 bytes).
1699   */
1700  if(nvram->enaddr[0] || nvram->enaddr[1] || nvram->enaddr[2])
1701    {
1702
1703    /* Anything in the first three bytes indicates a non-zero entry, copy value */
1704        memcpy((void *)sc->arpcom.ac_enaddr, &nvram->enaddr, ETHER_ADDR_LEN);
1705
1706    }
1707  else
1708    if(config->hardware_address)
1709      {
1710
1711      /* There is no entry in NVRAM, but there is in the ifconfig struct, so use it. */
1712      memcpy((void *)sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
1713      }
1714    else
1715      {
1716      /* There is no ethernet address provided, so it could be read
1717       * from the Ethernet protocol block of SCC1 in DPRAM.
1718       */
1719      rtems_panic("No Ethernet address specified!\n");
1720      }
1721
1722#else /* NVRAM_CONFIGURE != 1 */
1723
1724  if(config->hardware_address)
1725    {
1726
1727    memcpy(sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
1728
1729    }
1730  else
1731    {
1732
1733    /* There is no ethernet address provided, so it could be read
1734     * from the Ethernet protocol block of SCC1 in DPRAM.
1735     */
1736    rtems_panic("No Ethernet address specified!\n");
1737
1738    }
1739
1740#endif /* NVRAM_CONFIGURE != 1 */
1741#ifdef HAS_UBOOT
1742  if ((sc->arpcom.ac_enaddr[0] == 0) &&
1743      (sc->arpcom.ac_enaddr[1] == 0) &&
1744      (sc->arpcom.ac_enaddr[2] == 0)) {
1745      memcpy((void *)sc->arpcom.ac_enaddr, uboot_bdinfo_ptr->bi_enetaddr, ETHER_ADDR_LEN);   
1746  }
1747#endif
1748  if(config->mtu)
1749    mtu = config->mtu;
1750  else
1751    mtu = ETHERMTU;
1752
1753  if(config->rbuf_count)
1754    sc->rxBdCount = config->rbuf_count;
1755  else
1756    sc->rxBdCount = RX_BUF_COUNT;
1757
1758  if(config->xbuf_count)
1759    sc->txBdCount = config->xbuf_count;
1760  else
1761    sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF;
1762
1763  sc->acceptBroadcast = !config->ignore_broadcast;
1764
1765 /*
1766  * Set up network interface values
1767  */
1768  ifp->if_softc   = sc;
1769  ifp->if_unit    = unitNumber;
1770  ifp->if_name    = unitName;
1771  ifp->if_mtu     = mtu;
1772  ifp->if_init    = mpc5200_fec_init;
1773  ifp->if_ioctl   = mpc5200_fec_ioctl;
1774  ifp->if_start   = mpc5200_fec_tx_start;
1775  ifp->if_output  = ether_output;
1776  ifp->if_flags   = IFF_BROADCAST;
1777  /*ifp->if_flags   = IFF_BROADCAST | IFF_SIMPLEX;*/
1778
1779  if(ifp->if_snd.ifq_maxlen == 0)
1780    ifp->if_snd.ifq_maxlen = ifqmaxlen;
1781
1782  /*
1783   * Attach the interface
1784   */
1785  if_attach(ifp);
1786
1787  ether_ifattach(ifp);
1788
1789  return 1;
1790  }
1791
1792
1793int rtems_mpc5200_fec_driver_attach_detach(struct rtems_bsdnet_ifconfig *config, int attaching)
1794{
1795  if (attaching) {
1796    return rtems_mpc5200_fec_driver_attach(config);
1797  }
1798  else {
1799    return 0;
1800  }
1801}
1802
1803
Note: See TracBrowser for help on using the repository browser.