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

4.8
Last change on this file since b9f17f8 was b9f17f8, checked in by Joel Sherrill <joel.sherrill@…>, on Sep 21, 2007 at 3:45:11 PM

2007-09-21 Joel Sherrill <joel.sherrill@…>

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