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

4.104.114.84.95
Last change on this file since b16f38a was b16f38a, checked in by Joel Sherrill <joel.sherrill@…>, on 06/22/07 at 19:15:44

2007-06-22 Joel Sherrill <joel.sherrill@…>

  • clock/clock.c, network_5200/network.c: Convert to using clock driver template.
  • Property mode set to 100644
File size: 43.7 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
569#if defined(ETH_DEBUG)
570  unsigned short phyStatus, i;
571  unsigned char  phyAddr = 0;
572
573  for(i = 0; i < 9; i++)
574    {
575
576    mpc5200_eth_mii_read(sc, phyAddr, i, &phyStatus);
577    printf ("Mii reg %d: 0x%04x" "\r\n", i, phyStatus);
578
579    }
580
581  for(i = 16; i < 21; i++)
582    {
583
584    mpc5200_eth_mii_read(sc, phyAddr, i, &phyStatus);
585    printf ("Mii reg %d: 0x%04x" "\r\n", i, phyStatus);
586
587    }
588#endif  /* ETH_DEBUG */
589
590 /*
591  * block FEC chip interrupts
592  */
593  mpc5200.imask = 0;
594
595 /*
596  * issue graceful stop command to the FEC transmitter if necessary
597  */
598  mpc5200.x_cntrl |= FEC_XCNTRL_GTS;
599
600 /*
601  * wait for graceful stop to register
602  * FIXME: add rtems_task_wake_after here, if it takes to long
603  */
604  while((counter--) && (!(mpc5200.ievent & FEC_INTR_GRA)));
605
606  /*
607   * Disable the SmartDMA transmit and receive tasks.
608   */
609  TaskStop( rxTaskId );
610  TaskStop( txTaskId );
611 /*
612  * Disable transmit / receive interrupts
613  */
614  bestcomm_glue_irq_disable(FEC_XMIT_TASK_NO);
615  bestcomm_glue_irq_disable(FEC_RECV_TASK_NO);
616
617 /*
618  * Disable the Ethernet Controller
619  */
620  mpc5200.ecntrl &= ~(FEC_ECNTRL_OE | FEC_ECNTRL_EN);
621
622  /*
623   * cleanup all buffers
624   */
625  mpc5200_fec_rx_bd_cleanup(sc);
626
627  }
628
629/*
630 * MPC5200 FEC interrupt handler
631 */
632void mpc5200_fec_irq_handler(rtems_irq_hdl_param handle)
633{
634  struct mpc5200_enet_struct *sc = (struct mpc5200_enet_struct *) handle;
635  volatile uint32_t ievent;
636
637  ievent = mpc5200.ievent;
638
639  mpc5200.ievent = ievent;
640  /*
641   * check errors, update statistics
642   */
643  if (ievent & FEC_INTR_LATE_COL) {
644    sc->txLateCollision++;
645  }
646  if (ievent & FEC_INTR_COL_RETRY) {
647    sc->txRetryLimit++;
648  }
649  if (ievent & FEC_INTR_XFIFO_UN) {
650    sc->txUnderrun++;
651  }
652  if (ievent & FEC_INTR_XFIFO_ERR) {
653    sc->txUnderrun++;
654  }
655  if (ievent & FEC_INTR_RFIFO_ERR) {
656    sc->rxOverrun++;
657  }
658  /*
659   * fatal error ocurred?
660   */
661  if (ievent & (FEC_INTR_XFIFO_ERR | FEC_INTR_RFIFO_ERR)) {
662    mpc5200.imask &= ~(FEC_INTR_XFERREN | FEC_INTR_RFERREN);
663    rtems_event_send(enet_driver[0].rxDaemonTid, FATAL_INT_EVENT);
664  }
665}
666
667/*
668 * MPC5200 SmartComm ethernet interrupt handler
669 */
670void mpc5200_smartcomm_rx_irq_handler(rtems_irq_hdl_param unused)
671  {
672 /* Frame received? */
673  if(GET_SDMA_PENDINGBIT(FEC_RECV_TASK_NO))
674    {
675
676      SDMA_CLEAR_IEVENT(&mpc5200.IntPend,FEC_RECV_TASK_NO);
677
678      bestcomm_glue_irq_disable(FEC_RECV_TASK_NO);/*Disable receive ints*/
679
680      enet_driver[0].rxInterrupts++;            /* Rx int has occurred */
681     
682      rtems_event_send(enet_driver[0].rxDaemonTid, INTERRUPT_EVENT);
683
684    }
685  }
686
687/*
688 * MPC5200 SmartComm ethernet interrupt handler
689 */
690void mpc5200_smartcomm_tx_irq_handler(rtems_irq_hdl_param unused)
691  {
692 /* Buffer transmitted or transmitter error? */
693  if(GET_SDMA_PENDINGBIT(FEC_XMIT_TASK_NO))
694    {
695
696      SDMA_CLEAR_IEVENT(&mpc5200.IntPend,FEC_XMIT_TASK_NO);
697
698      bestcomm_glue_irq_disable(FEC_XMIT_TASK_NO);/*Disable tx ints*/
699
700      enet_driver[0].txInterrupts++; /* Tx int has occurred */
701
702      rtems_event_send(enet_driver[0].txDaemonTid, INTERRUPT_EVENT);
703
704    }
705
706  }
707
708
709
710
711
712 /*
713  * Function:       mpc5200_fec_retire_tbd
714  *
715  * Description:        Soak up buffer descriptors that have been sent.
716  *
717  * Returns:            void
718  *
719  * Notes:
720  *
721  */
722static void mpc5200_fec_retire_tbd(struct mpc5200_enet_struct *sc,
723                                   boolean force)
724{
725  struct mbuf *n;
726  TaskBD1_t   *bdRing = (TaskBD1_t *)TaskGetBDRing( txTaskId );;
727  /*
728   * Clear already transmitted BDs first. Will not work calling same
729   * from fecExceptionHandler(TFINT).
730   */
731 
732  while ((sc->txBdActiveCount > 0) &&
733         (force || (bdRing[sc->txBdTail].Status == 0x0))) {
734    if (sc->txMbuf[sc->txBdTail] != NULL) {
735      /*
736       * NOTE: txMbuf can be NULL, if mbuf has been split into different BDs
737       */
738      MFREE (sc->txMbuf[sc->txBdTail],n);
739      sc->txMbuf[sc->txBdTail] = NULL;
740    }
741    sc->txBdActiveCount--;
742    if(++sc->txBdTail >= sc->txBdCount) {
743      sc->txBdTail = 0;
744    }   
745  }
746}
747
748 /*
749  * Function:        mpc5200_fec_tx_bd_requeue
750  *
751  * Description:        put buffers back to interface output queue
752  *
753  * Returns:            void
754  *
755  * Notes:
756  *
757  */
758static void mpc5200_fec_tx_bd_requeue(struct mpc5200_enet_struct *sc)
759{
760  /*
761   * Clear already transmitted BDs first. Will not work calling same
762   * from fecExceptionHandler(TFINT).
763   */
764 
765  while (sc->txBdActiveCount > 0) {
766    if (sc->txMbuf[sc->txBdHead] != NULL) {
767      /*
768       * NOTE: txMbuf can be NULL, if mbuf has been split into different BDs
769       */
770      IF_PREPEND(&(sc->arpcom.ac_if.if_snd),sc->txMbuf[sc->txBdHead]);
771      sc->txMbuf[sc->txBdHead] = NULL;
772    }
773    sc->txBdActiveCount--;
774    if(--sc->txBdHead < 0) {
775      sc->txBdHead = sc->txBdCount-1;
776    }   
777  }
778}
779
780static void mpc5200_fec_sendpacket(struct ifnet *ifp,struct mbuf *m) {
781  struct mpc5200_enet_struct *sc = ifp->if_softc;
782  struct mbuf *l = NULL;
783  int nAdded;
784  uint32_t status;
785  rtems_event_set events;
786  TaskBD1_t *bdRing = (TaskBD1_t *)TaskGetBDRing( txTaskId );
787  TaskBD1_t *thisBd;
788  TaskBD1_t *firstBd = NULL;
789  void *data_ptr;
790  size_t data_len;
791
792 /*
793  * Free up buffer descriptors
794  */
795  mpc5200_fec_retire_tbd(sc,FALSE);
796
797 /*
798  * Set up the transmit buffer descriptors.
799  * No need to pad out short packets since the
800  * hardware takes care of that automatically.
801  * No need to copy the packet to a contiguous buffer
802  * since the hardware is capable of scatter/gather DMA.
803  */
804  nAdded = 0;
805
806  for(;;) {
807
808   /*
809    * Wait for buffer descriptor to become available.
810    */
811    if((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
812     
813      /*
814       * Clear old events
815       */
816      SDMA_CLEAR_IEVENT(&mpc5200.IntPend,FEC_XMIT_TASK_NO);
817     
818      /*
819       * Wait for buffer descriptor to become available.
820       * Note that the buffer descriptors are checked
821       * *before* * entering the wait loop -- this catches
822       * the possibility that a buffer descriptor became
823       * available between the `if' above, and the clearing
824       * of the event register.
825       * This is to catch the case where the transmitter
826       * stops in the middle of a frame -- and only the
827       * last buffer descriptor in a frame can generate
828       * an interrupt.
829       */
830      mpc5200_fec_retire_tbd(sc,FALSE);
831     
832      while((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
833        bestcomm_glue_irq_enable(FEC_XMIT_TASK_NO);
834        rtems_bsdnet_event_receive(INTERRUPT_EVENT,
835                                   RTEMS_WAIT | RTEMS_EVENT_ANY,
836                                   RTEMS_NO_TIMEOUT, &events);
837        mpc5200_fec_retire_tbd(sc,FALSE);
838      }
839    }
840
841    if(m->m_len == 0) {
842      /*
843       * Just toss empty mbufs
844       */
845      struct mbuf *n;
846      MFREE(m, n);
847      m = n;     
848      if(l != NULL) {
849        l->m_next = m;
850      }
851    }
852    else {
853      /*
854       * Flush the buffer for this descriptor
855       */
856      /*rtems_cache_flush_multiple_data_lines((const void *)mtod(m, void *), m->m_len);*/
857      /*
858       * Fill in the buffer descriptor,
859       * set "end of frame" bit in status,
860       * if last mbuf in chain
861       */
862      thisBd             = bdRing + sc->txBdHead;
863      /*
864       * FIXME: do not send interrupt after every frame
865       * doing this every quarter of BDs is much more efficent
866       */
867      status             = ((m->m_next == NULL)
868                            ? TASK_BD_TFD | TASK_BD_INT
869                            : 0);
870      /*
871       * Don't set the READY flag till the
872       * whole packet has been readied.
873       */
874      if (firstBd != NULL) {
875        status |= (uint32)SDMA_BD_MASK_READY;
876      }
877      else {
878        firstBd = thisBd;
879      }     
880
881      data_ptr = mtod(m, void *);
882      data_len = (uint32)m->m_len;
883      sc->txMbuf[sc->txBdHead] = m;
884      /* go to next part in chain */
885      l = m;
886      m = m->m_next;
887
888      thisBd->DataPtr[0] = (uint32)data_ptr;
889      thisBd->Status     = (status
890                            |((uint32)SDMA_DRD_MASK_LENGTH & data_len));
891
892      nAdded++;
893      if(++(sc->txBdHead) == sc->txBdCount) {
894        sc->txBdHead = 0;
895      }
896    }
897    /*
898     * Set the transmit buffer status.
899     * Break out of the loop if this mbuf is the last in the frame.
900     */
901    if(m == NULL) {
902      if(nAdded) {
903        firstBd->Status     |= SDMA_BD_MASK_READY;
904        SDMA_TASK_ENABLE(SDMA_TCR, txTaskId);
905        sc->txBdActiveCount += nAdded; 
906      }
907      break;
908    }
909  } /* end of for(;;) */
910}
911
912
913/*
914 * Driver transmit daemon
915 */
916void mpc5200_fec_txDaemon(void *arg)
917  {
918  struct mpc5200_enet_struct *sc = (struct mpc5200_enet_struct *)arg;
919  struct ifnet *ifp = &sc->arpcom.ac_if;
920  struct mbuf *m;
921  rtems_event_set events;
922
923  for(;;) {
924   /*
925    * Wait for packet
926    */
927    bestcomm_glue_irq_enable(FEC_XMIT_TASK_NO);
928    rtems_bsdnet_event_receive(START_TRANSMIT_EVENT|INTERRUPT_EVENT,
929                               RTEMS_EVENT_ANY | RTEMS_WAIT,
930                               RTEMS_NO_TIMEOUT,
931                               &events);
932
933    /*
934     * Send packets till queue is empty
935     */
936    for(;;)
937      {
938
939      /*
940       * Get the next mbuf chain to transmit.
941       */
942      IF_DEQUEUE(&ifp->if_snd, m);
943
944      if (!m)
945        break;
946
947      mpc5200_fec_sendpacket(ifp, m);
948
949      }
950
951    ifp->if_flags &= ~IFF_OACTIVE;
952
953    }
954
955  }
956
957
958/*
959 * reader task
960 */
961static void mpc5200_fec_rxDaemon(void *arg){
962  struct mpc5200_enet_struct *sc = (struct mpc5200_enet_struct *)arg;
963  struct ifnet *ifp = &sc->arpcom.ac_if;
964  struct mbuf *m;
965  struct ether_header *eh;
966  int rxBdIndex;
967  uint32_t status;
968  size_t size;
969  rtems_event_set events;
970  uint16    len = 1;
971  TaskBD1_t *bd;
972  void      *dptr;
973  TaskBD1_t   *bdRing = (TaskBD1_t *)TaskGetBDRing( rxTaskId );;
974
975  /*
976   * Input packet handling loop
977   */
978  rxBdIndex = 0;
979 
980  for (;;) {
981    /*
982     * Clear old events
983     */
984    SDMA_CLEAR_IEVENT(&mpc5200.IntPend,FEC_RECV_TASK_NO);
985    /*
986     * Get the first BD pointer and its length.
987     */
988    bd     = bdRing + rxBdIndex;
989    status = bd->Status;
990    len    = (uint16)GET_BD_LENGTH( bd );
991     
992    /*
993     * Loop through BDs until we find an empty one. This indicates that
994     * the SmartDMA is still using it.
995     */
996    while( !(status & SDMA_BD_MASK_READY) ) {
997   
998      /*
999       * Remember the data pointer from this transfer.
1000       */
1001      dptr = (void *)bd->DataPtr[0];
1002      m    = sc->rxMbuf[rxBdIndex];
1003      m->m_len = m->m_pkthdr.len = (len
1004                                    - sizeof(uint32_t) 
1005                                    - sizeof(struct ether_header));
1006      eh = mtod(m, struct ether_header *);
1007      m->m_data += sizeof(struct ether_header);
1008      ether_input(ifp, eh, m);
1009       
1010      /*
1011       * Done w/ the BD. Clean it.
1012       */
1013      sc->rxMbuf[rxBdIndex] = NULL;
1014       
1015      /*
1016       * Add a new buffer to the ring.
1017       */
1018      MGETHDR (m, M_WAIT, MT_DATA);
1019      MCLGET (m, M_WAIT);
1020      m->m_pkthdr.rcvif = ifp;
1021      size = ETHER_MAX_LEN;
1022
1023      sc->rxMbuf[rxBdIndex] = m;
1024      bd->DataPtr[0] = (uint32)mtod(m, void *);
1025      bd->Status = ( (  (uint32)SDMA_DRD_MASK_LENGTH & (uint32)size)
1026                     | ((uint32)SDMA_BD_MASK_READY));
1027       
1028      /*
1029       * advance to next BD
1030       */
1031      if (++rxBdIndex >= sc->rxBdCount) {
1032        rxBdIndex = 0;
1033      }
1034      /*
1035       * Get next BD pointer and its length.
1036       */
1037      bd     = bdRing + rxBdIndex;
1038      status = bd->Status;
1039      len    = (uint16)GET_BD_LENGTH( bd );   
1040    }
1041    /*
1042     * Unmask RXF (Full frame received) event
1043     */
1044    bestcomm_glue_irq_enable(FEC_RECV_TASK_NO);
1045     
1046    rtems_bsdnet_event_receive (INTERRUPT_EVENT | FATAL_INT_EVENT,
1047                                RTEMS_WAIT | RTEMS_EVENT_ANY,
1048                                RTEMS_NO_TIMEOUT, &events);
1049    if (events & FATAL_INT_EVENT) {
1050      /*
1051       * fatal interrupt ocurred, so reinit fec and restart bestcomm tasks
1052       */
1053      mpc5200_fec_restart(sc);
1054      rxBdIndex = 0;
1055    }
1056  }
1057}
1058
1059
1060/*
1061 * Function:    mpc5200_fec_initialize_hardware
1062 *
1063 * Description: Configure the MPC5200 FEC registers and enable the
1064 *                              SmartComm tasks. This function "turns on" the driver.
1065 *
1066 * Returns:             void
1067 *
1068 * Notes:
1069 *
1070 */
1071static void mpc5200_fec_initialize_hardware(struct mpc5200_enet_struct *sc)
1072  {
1073
1074 /*
1075  * Reset mpc5200 FEC
1076  */
1077  mpc5200_fec_reset(sc);
1078
1079 /*
1080  * Clear FEC-Lite interrupt event register (IEVENT)
1081  */
1082  mpc5200.ievent = FEC_INTR_CLEAR_ALL;
1083
1084 /*
1085  * Set interrupt mask register
1086  */
1087  mpc5200.imask = FEC_INTR_MASK_USED;
1088  /*
1089   * Set FEC-Lite receive control register (R_CNTRL)
1090   * frame length=1518, MII mode for 18-wire-transceiver
1091   */
1092  mpc5200.r_cntrl = ((ETHER_MAX_LEN << FEC_RCNTRL_MAX_FL_SHIFT)
1093                   | FEC_RCNTRL_FCE
1094                   | FEC_RCNTRL_MII_MODE);
1095 
1096  /*
1097   * Set FEC-Lite transmit control register (X_CNTRL)
1098   * full-duplex, heartbeat disabled
1099   */
1100  mpc5200.x_cntrl = FEC_XCNTRL_FDEN;
1101
1102
1103
1104 /*
1105  * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock(33Mhz)
1106  * and do not drop the Preamble.
1107  */
1108  mpc5200.mii_speed = (7 << 1); /* ipb_clk = 33 MHz */
1109
1110 /*
1111  * Set Opcode/Pause Duration Register
1112  */
1113  mpc5200.op_pause = 0x00010020;
1114
1115  /*
1116   * Set Rx FIFO alarm and granularity value
1117   */
1118  mpc5200.rfifo_cntrl = (FEC_FIFO_CNTRL_FRAME
1119                       | (0x7 << FEC_FIFO_CNTRL_GR_SHIFT));
1120  mpc5200.rfifo_alarm = 0x0000030c;
1121
1122  /*
1123   * Set Tx FIFO granularity value
1124   */
1125  mpc5200.tfifo_cntrl = (FEC_FIFO_CNTRL_FRAME
1126                       | (0x7 << FEC_FIFO_CNTRL_GR_SHIFT));
1127
1128  /*
1129   * Set transmit fifo watermark register (X_WMRK), default = 64
1130   */
1131  mpc5200.tfifo_alarm = 0x00000100;     /* 256 bytes */
1132  mpc5200.x_wmrk = FEC_XWMRK_256;       /* 256 bytes */
1133
1134 /*
1135  * Set individual address filter for unicast address
1136  * and set physical address registers.
1137  */
1138  mpc5200_eth_addr_filter_set(sc);
1139
1140 /*
1141  * Set multicast address filter
1142  */
1143  mpc5200.gaddr1 = 0x00000000;
1144  mpc5200.gaddr2 = 0x00000000;
1145
1146 /*
1147  * enable CRC in finite state machine register
1148  */
1149  mpc5200.xmit_fsm = FEC_FSM_CRC | FEC_FSM_ENFSM;
1150  }
1151
1152 /*
1153  * Initialize PHY(LXT971A):
1154  *
1155  *   Generally, on power up, the LXT971A reads its configuration
1156  *   pins to check for forced operation, If not cofigured for
1157  *   forced operation, it uses auto-negotiation/parallel detection
1158  *   to automatically determine line operating conditions.
1159  *   If the PHY device on the other side of the link supports
1160  *   auto-negotiation, the LXT971A auto-negotiates with it
1161  *   using Fast Link Pulse(FLP) Bursts. If the PHY partner does not
1162  *   support auto-negotiation, the LXT971A automatically detects
1163  *   the presence of either link pulses(10Mbps PHY) or Idle
1164  *   symbols(100Mbps) and sets its operating conditions accordingly.
1165  *
1166  *   When auto-negotiation is controlled by software, the following
1167  *   steps are recommended.
1168  *
1169  * Note:
1170  *   The physical address is dependent on hardware configuration.
1171  *
1172  * Returns:            void
1173  *
1174  * Notes:
1175  *
1176  */
1177static void mpc5200_fec_initialize_phy(struct mpc5200_enet_struct *sc)
1178  {
1179  int            timeout;
1180  unsigned short phyAddr = 0;
1181
1182
1183 /*
1184  * Reset PHY, then delay 300ns
1185  */
1186  mpc5200_eth_mii_write(sc, phyAddr, 0x0, 0x8000);
1187
1188  rtems_task_wake_after(2);
1189
1190 /* MII100 */
1191
1192 /*
1193  * Set the auto-negotiation advertisement register bits
1194  */
1195  mpc5200_eth_mii_write(sc, phyAddr, 0x4, 0x01e1);
1196
1197 /*
1198  * Set MDIO bit 0.12 = 1(&& bit 0.9=1?) to enable auto-negotiation
1199  */
1200  mpc5200_eth_mii_write(sc, phyAddr, 0x0, 0x1200);
1201
1202 /*
1203  * Wait for AN completion
1204  */
1205  timeout = 0x100;
1206#if 0
1207  do
1208    {
1209
1210    rtems_task_wake_after(2);
1211
1212    if((timeout--) == 0)
1213      {
1214
1215#if defined(ETH_DEBUG)
1216    printf ("MPC5200FEC PHY auto neg failed." "\r\n");
1217#endif
1218
1219      }
1220
1221    if(mpc5200_eth_mii_read(sc, phyAddr, 0x1, &phyStatus) != TRUE)
1222      {
1223
1224#if defined(ETH_DEBUG)
1225      printf ("MPC5200FEC PHY auto neg failed: 0x%04x." "\r\n", phyStatus);
1226#endif
1227
1228          return;
1229
1230          }
1231
1232    } while((phyStatus & 0x0020) != 0x0020);
1233
1234#endif
1235#if ETH_PROMISCOUS_MODE
1236  mpc5200.r_cntrl |= 0x00000008;   /* set to promiscous mode */
1237#endif
1238
1239#if ETH_LOOP_MODE
1240  mpc5200.r_cntrl |= 0x00000001;   /* set to loop mode */
1241#endif
1242
1243#if defined(ETH_DEBUG)
1244  int i;
1245  unsigned short phyStatus;
1246 /*
1247  * Print PHY registers after initialization.
1248  */
1249  for(i = 0; i < 9; i++)
1250    {
1251
1252        mpc5200_eth_mii_read(sc, phyAddr, i, &phyStatus);
1253        printf ("Mii reg %d: 0x%04x" "\r\n", i, phyStatus);
1254
1255        }
1256
1257  for(i = 16; i < 21; i++)
1258    {
1259
1260    mpc5200_eth_mii_read(sc, phyAddr, i, &phyStatus);
1261    printf ("Mii reg %d: 0x%04x" "\r\n", i, phyStatus);
1262
1263    }
1264#endif  /* ETH_DEBUG */
1265
1266  }
1267
1268
1269/*
1270 * Send packet (caller provides header).
1271 */
1272static void mpc5200_fec_tx_start(struct ifnet *ifp)
1273  {
1274
1275  struct mpc5200_enet_struct *sc = ifp->if_softc;
1276
1277  ifp->if_flags |= IFF_OACTIVE;
1278
1279  rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
1280
1281  }
1282
1283
1284/*
1285 * set up sdma tasks for ethernet
1286 */
1287static void mpc5200_sdma_task_setup(struct mpc5200_enet_struct *sc) {
1288  TaskSetupParamSet_t   rxParam;        /* RX task setup parameters     */
1289  TaskSetupParamSet_t   txParam;        /* TX task setup parameters     */
1290
1291  /*
1292   * Setup the SDMA RX task.
1293   */
1294  rxParam.NumBD        = sc->rxBdCount;
1295  rxParam.Size.MaxBuf  = ETHER_MAX_LEN;
1296  rxParam.Initiator    = 0;
1297  rxParam.StartAddrSrc = (uint32)&(mpc5200.rfifo_data);
1298  rxParam.IncrSrc      = 0;
1299  rxParam.SzSrc        = sizeof(uint32_t);
1300  rxParam.StartAddrDst = (uint32)NULL;
1301  rxParam.IncrDst      = sizeof(uint32_t);
1302  rxParam.SzDst        = sizeof(uint32_t); 
1303  rxTaskId             = TaskSetup(TASK_FEC_RX,&rxParam );
1304
1305  /*
1306   * Setup the TX task.
1307   */
1308  txParam.NumBD        = sc->txBdCount;
1309  txParam.Size.MaxBuf  = ETHER_MAX_LEN;
1310  txParam.Initiator    = 0;
1311  txParam.StartAddrSrc = (uint32)NULL;
1312  txParam.IncrSrc      = sizeof(uint32_t);
1313  txParam.SzSrc        = sizeof(uint32_t);
1314  txParam.StartAddrDst = (uint32)&(mpc5200.tfifo_data);
1315  txParam.IncrDst      = 0;
1316  txParam.SzDst        = sizeof(uint32_t);
1317 
1318  txTaskId             = TaskSetup( TASK_FEC_TX, &txParam );
1319
1320}
1321
1322void mpc5200_fec_irq_on(const rtems_irq_connect_data* ptr)
1323{
1324  mpc5200.imask = FEC_INTR_MASK_USED;
1325}
1326
1327
1328int mpc5200_fec_irq_isOn(const rtems_irq_connect_data* ptr)
1329{
1330  return mpc5200.imask != 0;
1331}
1332
1333
1334void mpc5200_fec_irq_off(const rtems_irq_connect_data* ptr)
1335{
1336  mpc5200.imask = 0;
1337}
1338
1339
1340/*
1341 * Initialize and start the device
1342 */
1343static void mpc5200_fec_init(void *arg)
1344{
1345  struct mpc5200_enet_struct *sc = (struct mpc5200_enet_struct *)arg;
1346  struct ifnet *ifp = &sc->arpcom.ac_if;
1347  rtems_irq_connect_data fec_irq_data = {
1348    BSP_SIU_IRQ_ETH,
1349    mpc5200_fec_irq_handler, /* rtems_irq_hdl           */
1350    (rtems_irq_hdl_param)sc, /* (rtems_irq_hdl_param)   */
1351    mpc5200_fec_irq_on,      /* (rtems_irq_enable)      */
1352    mpc5200_fec_irq_off,     /* (rtems_irq_disable)     */
1353    mpc5200_fec_irq_isOn     /* (rtems_irq_is_enabled)  */
1354  };
1355
1356
1357  if(sc->txDaemonTid == 0)
1358    {
1359      /*
1360       * Allocate a set of mbuf pointers
1361       */
1362      sc->rxMbuf =
1363        malloc(sc->rxBdCount * sizeof *sc->rxMbuf, M_MBUF, M_NOWAIT);
1364      sc->txMbuf =
1365        malloc(sc->txBdCount * sizeof *sc->txMbuf, M_MBUF, M_NOWAIT);
1366     
1367      if(!sc->rxMbuf || !sc->txMbuf)
1368        rtems_panic ("No memory for mbuf pointers");
1369
1370      bestcomm_glue_init();
1371
1372      mpc5200_sdma_task_setup(sc);
1373   
1374      /*
1375       * Set up interrupts
1376       */
1377      bestcomm_glue_irq_install(FEC_RECV_TASK_NO,
1378                                mpc5200_smartcomm_rx_irq_handler,
1379                                NULL);
1380      bestcomm_glue_irq_install(FEC_XMIT_TASK_NO,
1381                                mpc5200_smartcomm_tx_irq_handler,
1382                                NULL);
1383      if(!BSP_install_rtems_irq_handler (&fec_irq_data)) {
1384        rtems_panic ("Can't attach MPC5x00 FEX interrupt handler\n");
1385      }
1386
1387      /* mpc5200_fec_tx_bd_init(sc); */
1388      mpc5200_fec_rx_bd_init(sc);
1389
1390      /*
1391       * reset and Set up mpc5200 FEC hardware
1392       */
1393      mpc5200_fec_initialize_hardware(sc);
1394      /*
1395       * Set up the phy
1396       */
1397      mpc5200_fec_initialize_phy(sc);
1398      /*
1399       * Set priority of different initiators
1400       */
1401      mpc5200.IPR0 = 7; /* always initiator     */
1402      mpc5200.IPR3 = 6; /* eth rx initiator     */
1403      mpc5200.IPR4 = 5; /* eth tx initiator     */
1404
1405      /*
1406       * Start driver tasks
1407       */
1408      sc->txDaemonTid = rtems_bsdnet_newproc("FEtx", 4096, mpc5200_fec_txDaemon, sc);
1409      sc->rxDaemonTid = rtems_bsdnet_newproc("FErx", 4096, mpc5200_fec_rxDaemon, sc);
1410      /*
1411       * Clear SmartDMA task interrupt pending bits.
1412       */
1413      TaskIntClear( rxTaskId );
1414   
1415      /*
1416       * Enable the SmartDMA receive task.
1417       */
1418      TaskStart( rxTaskId, 1, rxTaskId, 1 );
1419      TaskStart( txTaskId, 1, txTaskId, 1 );
1420      /*
1421       * Enable FEC-Lite controller
1422       */
1423      mpc5200.ecntrl |= (FEC_ECNTRL_OE | FEC_ECNTRL_EN);
1424
1425
1426    }
1427
1428  /*
1429   * Set flags appropriately
1430   */
1431  if(ifp->if_flags & IFF_PROMISC)
1432    mpc5200.r_cntrl |= 0x08;
1433  else
1434    mpc5200.r_cntrl &= ~0x08;
1435
1436  /*
1437   * Tell the world that we're running.
1438   */
1439  ifp->if_flags |= IFF_RUNNING;
1440}
1441
1442
1443static void enet_stats (struct mpc5200_enet_struct *sc)
1444{
1445  printf ("      Rx Interrupts:%-8lu", sc->rxInterrupts);
1446  printf ("       Not First:%-8lu", sc->rxNotFirst);
1447  printf ("        Not Last:%-8lu\n", sc->rxNotLast);
1448  printf ("              Giant:%-8lu", sc->rxGiant);
1449  printf ("       Non-octet:%-8lu\n", sc->rxNonOctet);
1450  printf ("            Bad CRC:%-8lu", sc->rxBadCRC);
1451  printf ("         Overrun:%-8lu", sc->rxOverrun);
1452  printf ("       Collision:%-8lu\n", sc->rxCollision);
1453 
1454  printf ("      Tx Interrupts:%-8lu", sc->txInterrupts);
1455  printf ("        Deferred:%-8lu", sc->txDeferred);
1456  printf ("  Late Collision:%-8lu\n", sc->txLateCollision);
1457  printf ("   Retransmit Limit:%-8lu", sc->txRetryLimit);
1458  printf ("        Underrun:%-8lu", sc->txUnderrun);
1459  printf ("      Misaligned:%-8lu\n", sc->txMisaligned);
1460
1461}
1462
1463/*
1464 * restart the driver, reinit the fec
1465 * this function is responsible to reinitialize the FEC in case a fatal
1466 * error has ocurred. This is needed, wen a RxFIFO Overrun or a TxFIFO underrun
1467 * has ocurred. In these cases, the FEC is automatically disabled, and
1468 * both FIFOs must be reset and the BestComm tasks must be restarted
1469 *
1470 * Note: the daemon tasks will continue to run
1471 * (in fact this function will be called in the context of the rx daemon task)
1472 */
1473#define NEW_SDMA_SETUP
1474
1475static void mpc5200_fec_restart(struct mpc5200_enet_struct *sc)
1476{
1477  /*
1478   * FIXME: bring Tx Daemon into idle state
1479   */
1480#ifdef NEW_SDMA_SETUP
1481  /*
1482   * cleanup remaining receive mbufs
1483   */
1484  mpc5200_fec_rx_bd_cleanup(sc);
1485#endif
1486  /*
1487   * Stop SDMA tasks
1488   */
1489  TaskStop( rxTaskId);
1490  TaskStop( txTaskId);
1491  /*
1492   * FIXME: wait, until Tx Daemon is in idle state
1493   */
1494
1495  /*
1496   * Disable transmit / receive interrupts
1497   */
1498  bestcomm_glue_irq_disable(FEC_XMIT_TASK_NO);
1499  bestcomm_glue_irq_disable(FEC_RECV_TASK_NO);
1500#ifdef NEW_SDMA_SETUP
1501  /*
1502   * recycle pending tx buffers
1503   * FIXME: try to extract pending Tx buffers
1504   */
1505#if 0
1506  mpc5200_fec_tx_bd_requeue(sc);
1507#else
1508  mpc5200_fec_retire_tbd(sc,TRUE);
1509#endif
1510#endif
1511  /*
1512   * re-initialize the FEC hardware
1513   */
1514  mpc5200_fec_initialize_hardware(sc);
1515
1516#ifdef NEW_SDMA_SETUP
1517  /*
1518   * completely reinitialize Bestcomm tasks
1519   */
1520  mpc5200_sdma_task_setup(sc);
1521
1522  /*
1523   * reinit receive mbufs
1524   */
1525  mpc5200_fec_rx_bd_init(sc);
1526#endif
1527  /*
1528   * Clear SmartDMA task interrupt pending bits.
1529   */
1530  TaskIntClear( rxTaskId );
1531 
1532  /*
1533   * Enable the SmartDMA receive/transmit task.
1534   */
1535  TaskStart( rxTaskId, 1, rxTaskId, 1 );
1536  TaskStart( txTaskId, 1, txTaskId, 1 );
1537  /*
1538   * reenable rx/tx interrupts
1539   */
1540  bestcomm_glue_irq_enable(FEC_XMIT_TASK_NO);
1541  bestcomm_glue_irq_enable(FEC_RECV_TASK_NO);
1542  /*
1543   * (re-)init fec hardware
1544   */
1545  mpc5200_fec_initialize_hardware(sc);
1546  /*
1547   * reenable fec FIFO error interrupts
1548   */
1549  mpc5200.imask = FEC_INTR_MASK_USED;
1550  /*
1551   * Enable FEC-Lite controller
1552   */
1553  mpc5200.ecntrl |= (FEC_ECNTRL_OE | FEC_ECNTRL_EN);
1554}
1555
1556
1557/*
1558 * Driver ioctl handler
1559 */
1560static int mpc5200_fec_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data)
1561  {
1562  struct mpc5200_enet_struct *sc = ifp->if_softc;
1563  int error = 0;
1564
1565  switch(command)
1566    {
1567
1568    case SIOCGIFADDR:
1569    case SIOCSIFADDR:
1570
1571      ether_ioctl(ifp, command, data);
1572
1573      break;
1574
1575    case SIOCSIFFLAGS:
1576
1577      switch(ifp->if_flags & (IFF_UP | IFF_RUNNING))
1578        {
1579
1580        case IFF_RUNNING:
1581
1582          mpc5200_fec_off(sc);
1583
1584          break;
1585
1586        case IFF_UP:
1587
1588          mpc5200_fec_init(sc);
1589
1590          break;
1591
1592        case IFF_UP | IFF_RUNNING:
1593
1594          mpc5200_fec_off(sc);
1595          mpc5200_fec_init(sc);
1596
1597          break;
1598
1599        default:
1600          break;
1601
1602        }
1603
1604      break;
1605
1606    case SIO_RTEMS_SHOW_STATS:
1607
1608      enet_stats(sc);
1609
1610      break;
1611
1612   /*
1613    * FIXME: All sorts of multicast commands need to be added here!
1614    */
1615    default:
1616
1617    error = EINVAL;
1618
1619    break;
1620
1621    }
1622
1623  return error;
1624
1625  }
1626
1627
1628/*
1629 * Attach the MPC5200 fec driver to the system
1630 */
1631int rtems_mpc5200_fec_driver_attach(struct rtems_bsdnet_ifconfig *config)
1632  {
1633  struct mpc5200_enet_struct *sc;
1634  struct ifnet *ifp;
1635  int    mtu;
1636  int    unitNumber;
1637  char   *unitName;
1638
1639 /*
1640  * Parse driver name
1641  */
1642  if((unitNumber = rtems_bsdnet_parse_driver_name(config, &unitName)) < 0)
1643    return 0;
1644
1645 /*
1646  * Is driver free?
1647  */
1648  if ((unitNumber <= 0) || (unitNumber > NIFACES))
1649    {
1650
1651    printf ("Bad FEC unit number.\n");
1652    return 0;
1653
1654    }
1655
1656  sc = &enet_driver[unitNumber - 1];
1657  ifp = &sc->arpcom.ac_if;
1658
1659  if(ifp->if_softc != NULL)
1660    {
1661
1662    printf ("Driver already in use.\n");
1663    return 0;
1664
1665    }
1666
1667  /*
1668   * Process options
1669   */
1670#if NVRAM_CONFIGURE == 1
1671
1672  /* Configure from NVRAM */
1673  if(addr = nvram->ipaddr)
1674    {
1675
1676    /* We have a non-zero entry, copy the value */
1677    if(pAddr = malloc(INET_ADDR_MAX_BUF_SIZE, 0, M_NOWAIT))
1678      config->ip_address = (char *)inet_ntop(AF_INET, &addr, pAddr, INET_ADDR_MAX_BUF_SIZE -1);
1679    else
1680      rtems_panic("Can't allocate ip_address buffer!\n");
1681
1682    }
1683
1684  if(addr = nvram->netmask)
1685    {
1686
1687    /* We have a non-zero entry, copy the value */
1688    if (pAddr = malloc (INET_ADDR_MAX_BUF_SIZE, 0, M_NOWAIT))
1689      config->ip_netmask = (char *)inet_ntop(AF_INET, &addr, pAddr, INET_ADDR_MAX_BUF_SIZE -1);
1690    else
1691      rtems_panic("Can't allocate ip_netmask buffer!\n");
1692
1693    }
1694
1695  /* Ethernet address requires special handling -- it must be copied into
1696   * the arpcom struct. The following if construct serves only to give the
1697   * User Area NVRAM parameter the highest priority.
1698   *
1699   * If the ethernet address is specified in NVRAM, go ahead and copy it.
1700   * (ETHER_ADDR_LEN = 6 bytes).
1701   */
1702  if(nvram->enaddr[0] || nvram->enaddr[1] || nvram->enaddr[2])
1703    {
1704
1705    /* Anything in the first three bytes indicates a non-zero entry, copy value */
1706        memcpy((void *)sc->arpcom.ac_enaddr, &nvram->enaddr, ETHER_ADDR_LEN);
1707
1708    }
1709  else
1710    if(config->hardware_address)
1711      {
1712
1713      /* There is no entry in NVRAM, but there is in the ifconfig struct, so use it. */
1714      memcpy((void *)sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
1715      }
1716    else
1717      {
1718      /* There is no ethernet address provided, so it could be read
1719       * from the Ethernet protocol block of SCC1 in DPRAM.
1720       */
1721      rtems_panic("No Ethernet address specified!\n");
1722      }
1723
1724#else /* NVRAM_CONFIGURE != 1 */
1725
1726  if(config->hardware_address)
1727    {
1728
1729    memcpy(sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
1730
1731    }
1732  else
1733    {
1734
1735    /* There is no ethernet address provided, so it could be read
1736     * from the Ethernet protocol block of SCC1 in DPRAM.
1737     */
1738    rtems_panic("No Ethernet address specified!\n");
1739
1740    }
1741
1742#endif /* NVRAM_CONFIGURE != 1 */
1743#ifdef HAS_UBOOT
1744  if ((sc->arpcom.ac_enaddr[0] == 0) &&
1745      (sc->arpcom.ac_enaddr[1] == 0) &&
1746      (sc->arpcom.ac_enaddr[2] == 0)) {
1747      memcpy((void *)sc->arpcom.ac_enaddr, uboot_bdinfo_ptr->bi_enetaddr, ETHER_ADDR_LEN);   
1748  }
1749#endif
1750  if(config->mtu)
1751    mtu = config->mtu;
1752  else
1753    mtu = ETHERMTU;
1754
1755  if(config->rbuf_count)
1756    sc->rxBdCount = config->rbuf_count;
1757  else
1758    sc->rxBdCount = RX_BUF_COUNT;
1759
1760  if(config->xbuf_count)
1761    sc->txBdCount = config->xbuf_count;
1762  else
1763    sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF;
1764
1765  sc->acceptBroadcast = !config->ignore_broadcast;
1766
1767 /*
1768  * Set up network interface values
1769  */
1770  ifp->if_softc   = sc;
1771  ifp->if_unit    = unitNumber;
1772  ifp->if_name    = unitName;
1773  ifp->if_mtu     = mtu;
1774  ifp->if_init    = mpc5200_fec_init;
1775  ifp->if_ioctl   = mpc5200_fec_ioctl;
1776  ifp->if_start   = mpc5200_fec_tx_start;
1777  ifp->if_output  = ether_output;
1778  ifp->if_flags   = IFF_BROADCAST;
1779  /*ifp->if_flags   = IFF_BROADCAST | IFF_SIMPLEX;*/
1780
1781  if(ifp->if_snd.ifq_maxlen == 0)
1782    ifp->if_snd.ifq_maxlen = ifqmaxlen;
1783
1784  /*
1785   * Attach the interface
1786   */
1787  if_attach(ifp);
1788
1789  ether_ifattach(ifp);
1790
1791  return 1;
1792  }
1793
1794
1795int rtems_mpc5200_fec_driver_attach_detach(struct rtems_bsdnet_ifconfig *config, int attaching)
1796{
1797  if (attaching) {
1798    return rtems_mpc5200_fec_driver_attach(config);
1799  }
1800  else {
1801    return 0;
1802  }
1803}
1804
1805
Note: See TracBrowser for help on using the repository browser.