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

4.115
Last change on this file since 25ed11d0 was 25ed11d0, checked in by Sebastian Huber <sebastian.huber@…>, on 06/17/11 at 11:58:41

2011-06-17 Sebastian Huber <sebastian.huber@…>

  • Makefile.am: Added custom memcpy(). Update for network sources.
  • configure.ac: Enable interrupt driven Termios for all BSPs.
  • ide/pcmcia_ide.c: Disable broken DMA support.
  • include/bsp.h: Fixed NEED_LOW_LEVEL_INIT define. Set default console baud to 115200.
  • include/irq.h, irq/irq.c: Fixed interrupt handling to avoid the following problems: 1. multiple invokation of peripheral interrupt handlers, 2. missing synchronization after mask write and enabling of external exceptions, and 3. logic overhead.
  • network_5200/network.c: Added MII interface. Fixed controller restart after FIFO errors. Performance improvements.
  • start/start.S: Fixed ROM startup. Initialize XLB arbiter for all BSPs.
  • startup/bspstart.c: Special intialization for MPC5200B (B variant). Install standard alignment handler.
  • startup/cpuinit.c, startup/linkcmds.brs5l, startup/linkcmds.dp2, startup/linkcmds.icecube, startup/linkcmds.pm520_cr825, startup/linkcmds.pm520_ze30: Avoid accesses outside the RAM area.
  • Property mode set to 100644
File size: 37.1 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
57#define __INSIDE_RTEMS_BSD_TCPIP_STACK__ 1
58#define __BSD_VISIBLE 1
59
60#include <rtems.h>
61#include <rtems/error.h>
62#include <rtems/rtems_bsdnet.h>
63#include <rtems/rtems_mii_ioctl.h>
64#include <stdio.h>
65#include <inttypes.h>
66#include <sys/param.h>
67#include <sys/mbuf.h>
68#include <sys/socket.h>
69#include <sys/sockio.h>
70#include <net/if.h>
71#include <netinet/in.h>
72#include <netinet/if_ether.h>
73#include <bsp.h>
74#include <bsp/irq.h>
75#include <bsp/mpc5200.h>
76#include <net/if_var.h>
77#include <errno.h>
78
79#include <bsp/bestcomm/include/ppctypes.h>
80#include <bsp/bestcomm/dma_image.h>
81#include <bsp/bestcomm/bestcomm_glue.h>
82#include <bsp/bestcomm/bestcomm_api.h>
83#include <bsp/bestcomm/task_api/bestcomm_cntrl.h>
84#include <bsp/bestcomm/task_api/tasksetup_bdtable.h>
85
86/* #define ETH_DEBUG */
87
88#define FEC_BD_LAST TASK_BD_TFD
89#define FEC_BD_INT TASK_BD_INT
90#define FEC_BD_READY SDMA_BD_MASK_READY
91
92/*
93 * Number of interfaces supported by this driver
94 */
95#define NIFACES 1
96
97/*
98 * Default number of buffer descriptors set aside for this driver.
99 * The number of transmit buffer descriptors has to be quite large
100 * since a single frame often uses four or more buffer descriptors.
101 */
102#define RX_BUF_COUNT     64
103#define TX_BUF_COUNT     64
104
105#define INET_ADDR_MAX_BUF_SIZE (sizeof "255.255.255.255")
106
107#define FEC_EVENT RTEMS_EVENT_0
108
109/* Task number assignment */
110#define FEC_RECV_TASK_NO            TASK_FEC_RX
111#define FEC_XMIT_TASK_NO            TASK_FEC_TX
112
113
114/* BD and parameters are stored in SRAM(refer to sdma.h) */
115#define MPC5200_FEC_BD_BASE    ETH_BD_BASE
116
117/* FEC transmit watermark settings */
118#define MPC5200_FEC_X_WMRK_64   0x0     /* or 0x1 */
119#define MPC5200_FEC_X_WMRK_128  0x2
120#define MPC5200_FEC_X_WMRK_192  0x3
121
122/* RBD bits definitions */
123#define MPC5200_FEC_RBD_EMPTY  0x8000   /* Buffer is empty */
124#define MPC5200_FEC_RBD_WRAP   0x2000   /* Last BD in ring */
125#define MPC5200_FEC_RBD_INT    0x1000   /* Interrupt */
126#define MPC5200_FEC_RBD_LAST   0x0800   /* Buffer is last in frame(useless) */
127#define MPC5200_FEC_RBD_MISS   0x0100   /* Miss bit for prom mode */
128#define MPC5200_FEC_RBD_BC     0x0080   /* The received frame is broadcast frame */
129#define MPC5200_FEC_RBD_MC     0x0040   /* The received frame is multicast frame */
130#define MPC5200_FEC_RBD_LG     0x0020   /* Frame length violation */
131#define MPC5200_FEC_RBD_NO     0x0010   /* Nonoctet align frame */
132#define MPC5200_FEC_RBD_SH     0x0008   /* Short frame, FEC does not support SH and this bit is always cleared */
133#define MPC5200_FEC_RBD_CR     0x0004   /* CRC error */
134#define MPC5200_FEC_RBD_OV     0x0002   /* Receive FIFO overrun */
135#define MPC5200_FEC_RBD_TR     0x0001   /* The receive frame is truncated */
136#define MPC5200_FEC_RBD_ERR    (MPC5200_FEC_RBD_LG  | \
137                                MPC5200_FEC_RBD_NO  | \
138                                MPC5200_FEC_RBD_CR  | \
139                                MPC5200_FEC_RBD_OV  | \
140                                MPC5200_FEC_RBD_TR)
141
142/* TBD bits definitions */
143#define MPC5200_FEC_TBD_READY  0x8000   /* Buffer is ready */
144#define MPC5200_FEC_TBD_WRAP   0x2000   /* Last BD in ring */
145#define MPC5200_FEC_TBD_INT    0x1000   /* Interrupt */
146#define MPC5200_FEC_TBD_LAST   0x0800   /* Buffer is last in frame */
147#define MPC5200_FEC_TBD_TC     0x0400   /* Transmit the CRC */
148#define MPC5200_FEC_TBD_ABC    0x0200   /* Append bad CRC */
149
150/* MII-related definitios */
151#define MPC5200_FEC_MII_DATA_ST       0x40000000        /* Start of frame delimiter */
152#define MPC5200_FEC_MII_DATA_OP_RD    0x20000000        /* Perform a read operation */
153#define MPC5200_FEC_MII_DATA_OP_WR    0x10000000        /* Perform a write operation */
154#define MPC5200_FEC_MII_DATA_PA_MSK   0x0f800000        /* PHY Address field mask */
155#define MPC5200_FEC_MII_DATA_RA_MSK   0x007c0000        /* PHY Register field mask */
156#define MPC5200_FEC_MII_DATA_TA       0x00020000        /* Turnaround */
157#define MPC5200_FEC_MII_DATA_DATAMSK  0x0000fff     /* PHY data field */
158
159#define MPC5200_FEC_MII_DATA_RA_SHIFT 0x12      /* MII Register address bits */
160#define MPC5200_FEC_MII_DATA_PA_SHIFT 0x17      /* MII PHY address bits */
161
162#define FEC_INTR_MASK_USED \
163(FEC_INTR_LCEN  |FEC_INTR_CRLEN |\
164 FEC_INTR_XFUNEN|FEC_INTR_XFERREN|FEC_INTR_RFERREN)
165
166typedef enum {
167  FEC_STATE_RESTART_0,
168  FEC_STATE_RESTART_1,
169  FEC_STATE_NORMAL,
170} mpc5200_fec_state;
171
172/*
173 * Device data
174 */
175typedef struct {
176  struct arpcom           arpcom;
177  struct mbuf             **rxMbuf;
178  struct mbuf             **txMbuf;
179  mpc5200_fec_state       state;
180  int                     acceptBroadcast;
181  int                     rxBdCount;
182  int                     txBdCount;
183  int                     txBdHead;
184  int                     txBdTail;
185  int                     txBdActiveCount;
186
187  rtems_id                rxDaemonTid;
188  rtems_id                txDaemonTid;
189
190  unsigned long           rxInterrupts;
191  unsigned long           rxNotLast;
192  unsigned long           rxGiant;
193  unsigned long           rxNonOctet;
194  unsigned long           rxBadCRC;
195  unsigned long           rxFIFOError;
196  unsigned long           rxCollision;
197
198  unsigned long           txInterrupts;
199  unsigned long           txDeferred;
200  unsigned long           txLateCollision;
201  unsigned long           txUnderrun;
202  unsigned long           txFIFOError;
203  unsigned long           txMisaligned;
204  unsigned long           rxNotFirst;
205  unsigned long           txRetryLimit;
206
207  struct rtems_mdio_info  mdio;
208  int                     phyAddr;
209  bool                    phyInitialized;
210} mpc5200_fec_context;
211
212static mpc5200_fec_context enet_driver[NIFACES];
213
214static void mpc5200_fec_send_event(rtems_id task)
215{
216  rtems_event_send(task, FEC_EVENT);
217}
218
219static void mpc5200_fec_wait_for_event(void)
220{
221  rtems_event_set out;
222  rtems_bsdnet_event_receive(
223    FEC_EVENT,
224    RTEMS_EVENT_ANY | RTEMS_WAIT,
225    RTEMS_NO_TIMEOUT,
226    &out
227  );
228}
229
230static void mpc5200_fec_stop_dma(void)
231{
232  TaskStop(FEC_RECV_TASK_NO);
233  TaskStop(FEC_XMIT_TASK_NO);
234}
235
236static void mpc5200_fec_request_restart(mpc5200_fec_context *self)
237{
238  self->state = FEC_STATE_RESTART_0;
239  mpc5200_fec_send_event(self->txDaemonTid);
240  mpc5200_fec_send_event(self->rxDaemonTid);
241}
242
243static void mpc5200_fec_start_dma_and_controller(void)
244{
245  TaskStart(FEC_RECV_TASK_NO, 1, FEC_RECV_TASK_NO, 1);
246  TaskStart(FEC_XMIT_TASK_NO, 1, FEC_XMIT_TASK_NO, 1);
247
248  mpc5200.ecntrl |= FEC_ECNTRL_OE | FEC_ECNTRL_EN;
249}
250
251/*
252 * Function:    MPC5200_eth_addr_filter_set
253 *
254 * Description: Set individual address filter for unicast address and
255 *                              set physical address registers.
256 *
257 * Returns:             void
258 *
259 * Notes:
260 *
261 */
262static void mpc5200_eth_addr_filter_set(mpc5200_fec_context *self)  {
263  unsigned char *mac;
264  unsigned char currByte;                               /* byte for which to compute the CRC */
265  int           byte;                                   /* loop - counter */
266  int           bit;                                    /* loop - counter */
267  unsigned long crc = 0xffffffff;               /* initial value */
268
269 /*
270  * Get the mac address of ethernet controller
271  */
272  mac = (unsigned char *)(&self->arpcom.ac_enaddr);
273
274 /*
275  * The algorithm used is the following:
276  * we loop on each of the six bytes of the provided address,
277  * and we compute the CRC by left-shifting the previous
278  * value by one position, so that each bit in the current
279  * byte of the address may contribute the calculation. If
280  * the latter and the MSB in the CRC are different, then
281  * the CRC value so computed is also ex-ored with the
282  * "polynomium generator". The current byte of the address
283  * is also shifted right by one bit at each iteration.
284  * This is because the CRC generatore in hardware is implemented
285  * as a shift-register with as many ex-ores as the radixes
286  * in the polynomium. This suggests that we represent the
287  * polynomiumm itself as a 32-bit constant.
288  */
289  for(byte = 0; byte < 6; byte++)
290    {
291
292    currByte = mac[byte];
293
294    for(bit = 0; bit < 8; bit++)
295      {
296
297      if((currByte & 0x01) ^ (crc & 0x01))
298        {
299
300        crc >>= 1;
301        crc = crc ^ 0xedb88320;
302
303        }
304      else
305        {
306
307        crc >>= 1;
308
309        }
310
311      currByte >>= 1;
312
313      }
314
315    }
316
317    crc = crc >> 26;
318
319   /*
320    * Set individual hash table register
321    */
322    if(crc >= 32)
323      {
324
325      mpc5200.iaddr1 = (1 << (crc - 32));
326      mpc5200.iaddr2 = 0;
327
328      }
329    else
330     {
331
332     mpc5200.iaddr1 = 0;
333     mpc5200.iaddr2 = (1 << crc);
334
335     }
336
337   /*
338    * Set physical address
339    */
340    mpc5200.paddr1 = (mac[0] << 24) + (mac[1] << 16) + (mac[2] << 8) + mac[3];
341    mpc5200.paddr2 = (mac[4] << 24) + (mac[5] << 16) + 0x8808;
342
343   }
344
345static int mpc5200_eth_mii_transfer(
346  int phyAddr,
347  unsigned regAddr,
348  uint32_t data
349)
350{
351  int timeout = 0xffff;
352
353  mpc5200.ievent = FEC_INTR_MII;
354
355  mpc5200.mii_data = MPC5200_FEC_MII_DATA_ST
356    | MPC5200_FEC_MII_DATA_TA
357    | (phyAddr << MPC5200_FEC_MII_DATA_PA_SHIFT)
358    | (regAddr << MPC5200_FEC_MII_DATA_RA_SHIFT)
359    | data;
360
361  while (timeout > 0 && (mpc5200.ievent & FEC_INTR_MII) == 0) {
362    --timeout;
363  }
364
365  return timeout > 0 ? 0 : -1;
366}
367
368/* FIXME: Make this static, this needs a fix in an application */
369int mpc5200_eth_mii_read(
370  int phyAddr,
371  void *arg,
372  unsigned regAddr,
373  uint32_t *retVal
374)
375{
376  int rv = mpc5200_eth_mii_transfer(
377    phyAddr,
378    regAddr,
379    MPC5200_FEC_MII_DATA_OP_RD
380  );
381
382  *retVal = mpc5200.mii_data & 0xffff;
383
384  return rv;
385}
386
387static int mpc5200_eth_mii_write(
388  int phyAddr,
389  void *arg,
390  unsigned regAddr,
391  uint32_t data
392)
393{
394  return mpc5200_eth_mii_transfer(
395    phyAddr,
396    regAddr,
397    MPC5200_FEC_MII_DATA_OP_WR | data
398  );
399}
400
401
402/*
403 * Reset a running ethernet driver including the hardware FIFOs and the FEC.
404 */
405static void mpc5200_fec_reset(mpc5200_fec_context *self)
406{
407  volatile int delay;
408  /*
409   * Clear FIFO status registers
410   */
411  mpc5200.rfifo_status &= FEC_FIFO_STAT_ERROR;
412  mpc5200.tfifo_status &= FEC_FIFO_STAT_ERROR;
413
414  /*
415   * reset the FIFOs
416   */
417  mpc5200.reset_cntrl = 0x03000000;
418
419  for (delay = 0;delay < 16*4;delay++) {};
420
421  mpc5200.reset_cntrl = 0x01000000;
422
423  /*
424   * Issue a reset command to the FEC chip
425   */
426  mpc5200.ecntrl |= FEC_ECNTRL_RESET;
427
428  /*
429   * wait at least 16 clock cycles
430   */
431  for (delay = 0;delay < 16*4;delay++) {};
432}
433
434
435/*
436 * Function:    mpc5200_fec_off
437 *
438 * Description: Stop the FEC and disable the ethernet SmartComm tasks.
439 *                              This function "turns off" the driver.
440 *
441 * Returns:             void
442 *
443 * Notes:
444 *
445 */
446void mpc5200_fec_off(mpc5200_fec_context *self)
447  {
448  int            counter = 0xffff;
449
450
451#if defined(ETH_DEBUG)
452  uint32_t phyStatus;
453  int i;
454
455  for(i = 0; i < 9; i++)
456    {
457
458    mpc5200_eth_mii_read(self->phyAddr, self, i, &phyStatus);
459    printf ("Mii reg %d: 0x%04" PRIx32 "\r\n", i, phyStatus);
460
461    }
462
463  for(i = 16; i < 21; i++)
464    {
465
466    mpc5200_eth_mii_read(self->phyAddr, self, i, &phyStatus);
467    printf ("Mii reg %d: 0x%04" PRIx32 "\r\n", i, phyStatus);
468
469    }
470#endif  /* ETH_DEBUG */
471
472 /*
473  * block FEC chip interrupts
474  */
475  mpc5200.imask = 0;
476
477 /*
478  * issue graceful stop command to the FEC transmitter if necessary
479  */
480  mpc5200.x_cntrl |= FEC_XCNTRL_GTS;
481
482 /*
483  * wait for graceful stop to register
484  * FIXME: add rtems_task_wake_after here, if it takes to long
485  */
486  while((counter--) && (!(mpc5200.ievent & FEC_INTR_GRA)));
487
488  mpc5200_fec_stop_dma();
489
490 /*
491  * Disable transmit / receive interrupts
492  */
493  bestcomm_glue_irq_disable(FEC_XMIT_TASK_NO);
494  bestcomm_glue_irq_disable(FEC_RECV_TASK_NO);
495
496 /*
497  * Disable the Ethernet Controller
498  */
499  mpc5200.ecntrl &= ~(FEC_ECNTRL_OE | FEC_ECNTRL_EN);
500}
501
502/*
503 * MPC5200 FEC interrupt handler
504 */
505void mpc5200_fec_irq_handler(rtems_irq_hdl_param handle)
506{
507  mpc5200_fec_context *self = (mpc5200_fec_context *) handle;
508  volatile uint32_t ievent;
509
510  ievent = mpc5200.ievent;
511
512  mpc5200.ievent = ievent;
513  /*
514   * check errors, update statistics
515   */
516  if (ievent & FEC_INTR_LATE_COL) {
517    self->txLateCollision++;
518  }
519  if (ievent & FEC_INTR_COL_RETRY) {
520    self->txRetryLimit++;
521  }
522  if (ievent & FEC_INTR_XFIFO_UN) {
523    self->txUnderrun++;
524  }
525  if (ievent & FEC_INTR_XFIFO_ERR) {
526    self->txFIFOError++;
527  }
528  if (ievent & FEC_INTR_RFIFO_ERR) {
529    self->rxFIFOError++;
530  }
531  /*
532   * fatal error ocurred?
533   */
534  if (ievent & (FEC_INTR_XFIFO_ERR | FEC_INTR_RFIFO_ERR)) {
535    mpc5200.imask &= ~(FEC_INTR_XFERREN | FEC_INTR_RFERREN);
536    mpc5200_fec_request_restart(self);
537  }
538}
539
540void mpc5200_smartcomm_rx_irq_handler(void *arg)
541{
542  mpc5200_fec_context *self = arg;
543
544  ++self->rxInterrupts;
545  mpc5200_fec_send_event(self->rxDaemonTid);
546  SDMA_CLEAR_IEVENT(&mpc5200.sdma.IntPend, FEC_RECV_TASK_NO);
547  bestcomm_glue_irq_disable(FEC_RECV_TASK_NO);
548}
549
550void mpc5200_smartcomm_tx_irq_handler(void *arg)
551{
552  mpc5200_fec_context *self = arg;
553
554  ++self->txInterrupts;
555  mpc5200_fec_send_event(self->txDaemonTid);
556  SDMA_CLEAR_IEVENT(&mpc5200.sdma.IntPend, FEC_XMIT_TASK_NO);
557  bestcomm_glue_irq_disable(FEC_XMIT_TASK_NO);
558}
559
560static void mpc5200_fec_init_mib(mpc5200_fec_context *self)
561{
562  memset(&mpc5200.RES [0], 0, 0x2e4);
563  mpc5200.mib_control = 0x40000000;
564}
565
566/*
567 * Function:    mpc5200_fec_initialize_hardware
568 *
569 * Description: Configure the MPC5200 FEC registers and enable the
570 *                              SmartComm tasks. This function "turns on" the driver.
571 *
572 * Returns:             void
573 *
574 * Notes:
575 *
576 */
577static void mpc5200_fec_initialize_hardware(mpc5200_fec_context *self)
578{
579  /* We want at most 2.5MHz */
580  uint32_t div = 2 * 2500000;
581  uint32_t mii_speed = (IPB_CLOCK + div - 1) / div;
582
583 /*
584  * Reset mpc5200 FEC
585  */
586  mpc5200_fec_reset(self);
587  mpc5200_fec_init_mib(self);
588
589 /*
590  * Clear FEC-Lite interrupt event register (IEVENT)
591  */
592  mpc5200.ievent = FEC_INTR_CLEAR_ALL;
593
594 /*
595  * Set interrupt mask register
596  */
597  mpc5200.imask = FEC_INTR_MASK_USED;
598  /*
599   * Set FEC-Lite receive control register (R_CNTRL)
600   * frame length=1518, MII mode for 18-wire-transceiver
601   */
602  mpc5200.r_cntrl = ((ETHER_MAX_LEN << FEC_RCNTRL_MAX_FL_SHIFT)
603                   | FEC_RCNTRL_FCE
604                   | FEC_RCNTRL_MII_MODE);
605
606  /*
607   * Set FEC-Lite transmit control register (X_CNTRL)
608   * full-duplex, heartbeat disabled
609   */
610  mpc5200.x_cntrl = FEC_XCNTRL_FDEN;
611
612
613
614 /*
615  * Set MII_SPEED = IPB clock / (2 * mii_speed))
616  * and do not drop the Preamble.
617  */
618  mpc5200.mii_speed = mii_speed << 1;
619
620 /*
621  * Set Opcode/Pause Duration Register
622  */
623  mpc5200.op_pause = 0x00010020;
624
625  /*
626   * Set Rx FIFO alarm and granularity value
627   */
628  mpc5200.rfifo_cntrl = (FEC_FIFO_CNTRL_FRAME
629                       | (0x7 << FEC_FIFO_CNTRL_GR_SHIFT));
630  mpc5200.rfifo_alarm = 0x0000030c;
631
632  /*
633   * Set Tx FIFO granularity value
634   */
635  mpc5200.tfifo_cntrl = (FEC_FIFO_CNTRL_FRAME
636                       | (0x7 << FEC_FIFO_CNTRL_GR_SHIFT));
637
638  /*
639   * Set transmit fifo watermark register (X_WMRK), default = 64
640   */
641  mpc5200.tfifo_alarm = 0x00000100;     /* 256 bytes */
642  mpc5200.x_wmrk = FEC_XWMRK_256;       /* 256 bytes */
643
644 /*
645  * Set individual address filter for unicast address
646  * and set physical address registers.
647  */
648  mpc5200_eth_addr_filter_set(self);
649
650 /*
651  * Set multicast address filter
652  */
653  mpc5200.gaddr1 = 0x00000000;
654  mpc5200.gaddr2 = 0x00000000;
655
656 /*
657  * enable CRC in finite state machine register
658  */
659  mpc5200.xmit_fsm = FEC_FSM_CRC | FEC_FSM_ENFSM;
660}
661
662 /*
663  * Initialize PHY(LXT971A):
664  *
665  *   Generally, on power up, the LXT971A reads its configuration
666  *   pins to check for forced operation, If not cofigured for
667  *   forced operation, it uses auto-negotiation/parallel detection
668  *   to automatically determine line operating conditions.
669  *   If the PHY device on the other side of the link supports
670  *   auto-negotiation, the LXT971A auto-negotiates with it
671  *   using Fast Link Pulse(FLP) Bursts. If the PHY partner does not
672  *   support auto-negotiation, the LXT971A automatically detects
673  *   the presence of either link pulses(10Mbps PHY) or Idle
674  *   symbols(100Mbps) and sets its operating conditions accordingly.
675  *
676  *   When auto-negotiation is controlled by software, the following
677  *   steps are recommended.
678  *
679  * Note:
680  *   The physical address is dependent on hardware configuration.
681  *
682  * Returns:            void
683  *
684  * Notes:
685  *
686  */
687static void mpc5200_fec_initialize_phy(mpc5200_fec_context *self)
688{
689  if (self->phyInitialized) {
690    return;
691  } else {
692    self->phyInitialized = true;
693  }
694
695 /*
696  * Reset PHY, then delay 300ns
697  */
698  mpc5200_eth_mii_write(self->phyAddr, self, 0x0, 0x8000);
699
700  rtems_task_wake_after(2);
701
702 /* MII100 */
703
704 /*
705  * Set the auto-negotiation advertisement register bits
706  */
707  mpc5200_eth_mii_write(self->phyAddr, self, 0x4, 0x01e1);
708
709 /*
710  * Set MDIO bit 0.12 = 1(&& bit 0.9=1?) to enable auto-negotiation
711  */
712  mpc5200_eth_mii_write(self->phyAddr, self, 0x0, 0x1200);
713
714 /*
715  * Wait for AN completion
716  */
717#if 0
718  int timeout = 0x100;
719  uint32_t phyStatus;
720  do
721    {
722
723    rtems_task_wake_after(2);
724
725    if((timeout--) == 0)
726      {
727
728#if defined(ETH_DEBUG)
729    printf ("MPC5200FEC PHY auto neg failed." "\r\n");
730#endif
731
732      }
733
734    if(mpc5200_eth_mii_read(self->phyAddr, self, 0x1, &phyStatus) != true)
735      {
736
737#if defined(ETH_DEBUG)
738      printf ("MPC5200FEC PHY auto neg failed: 0x%04" PRIx32 ".\r\n", phyStatus);
739#endif
740
741          return;
742
743          }
744
745    } while((phyStatus & 0x0020) != 0x0020);
746
747#endif
748#if ETH_PROMISCOUS_MODE
749  mpc5200.r_cntrl |= 0x00000008;   /* set to promiscous mode */
750#endif
751
752#if ETH_LOOP_MODE
753  mpc5200.r_cntrl |= 0x00000001;   /* set to loop mode */
754#endif
755
756#if defined(ETH_DEBUG)
757  int i;
758  uint32_t phyStatus;
759 /*
760  * Print PHY registers after initialization.
761  */
762  for(i = 0; i < 9; i++)
763    {
764
765        mpc5200_eth_mii_read(self->phyAddr, self, i, &phyStatus);
766        printf ("Mii reg %d: 0x%04" PRIx32 "\r\n", i, phyStatus);
767
768        }
769
770  for(i = 16; i < 21; i++)
771    {
772
773    mpc5200_eth_mii_read(self->phyAddr, self, i, &phyStatus);
774    printf ("Mii reg %d: 0x%04" PRIx32 "\r\n", i, phyStatus);
775
776    }
777#endif  /* ETH_DEBUG */
778
779  }
780
781static void mpc5200_fec_restart(mpc5200_fec_context *self, rtems_id otherDaemon)
782{
783  if (self->state == FEC_STATE_RESTART_1) {
784    mpc5200_fec_initialize_hardware(self);
785    mpc5200_fec_initialize_phy(self);
786    mpc5200_fec_start_dma_and_controller();
787    self->state = FEC_STATE_NORMAL;
788  } else {
789    self->state = FEC_STATE_RESTART_1;
790  }
791
792  mpc5200_fec_send_event(otherDaemon);
793  while (self->state != FEC_STATE_NORMAL) {
794    mpc5200_fec_wait_for_event();
795  }
796}
797
798/*
799 * Send packet (caller provides header).
800 */
801static void mpc5200_fec_tx_start(struct ifnet *ifp)
802  {
803
804  mpc5200_fec_context *self = ifp->if_softc;
805
806  ifp->if_flags |= IFF_OACTIVE;
807
808  mpc5200_fec_send_event(self->txDaemonTid);
809
810  }
811
812static TaskBD1_t *mpc5200_fec_init_tx_dma(int bdCount, struct mbuf **mbufs)
813{
814  TaskSetupParamSet_t param = {
815    .NumBD = bdCount,
816    .Size = {
817      .MaxBuf = ETHER_MAX_LEN
818    },
819    .Initiator = 0,
820    .StartAddrSrc = 0,
821    .IncrSrc = sizeof(uint32_t),
822    .SzSrc = sizeof(uint32_t),
823    .StartAddrDst = (uint32) &mpc5200.tfifo_data,
824    .IncrDst = 0,
825    .SzDst = sizeof(uint32_t)
826  };
827  int bdIndex = 0;
828
829  TaskSetup(FEC_XMIT_TASK_NO, &param);
830
831  for (bdIndex = 0; bdIndex < bdCount; ++bdIndex) {
832    mbufs [bdIndex] = NULL;
833  }
834
835  return (TaskBD1_t *) TaskGetBDRing(FEC_XMIT_TASK_NO);
836}
837
838#if 0
839static void mpc5200_fec_requeue_and_discard_tx_frames(
840  int bdIndex,
841  int bdCount,
842  TaskBD1_t *bdRing,
843  struct mbuf **mbufs
844)
845{
846  int bdStop = bdIndex;
847  struct mbuf *previous = NULL;
848
849  do {
850    struct mbuf *current = NULL;
851    uint32 status = 0;
852    TaskBD1_t *bd = NULL;
853
854    if (bdIndex > 1) {
855      --bdIndex;
856    } else {
857      bdIndex = bdCount - 1;
858    }
859
860    current = mbufs [bdIndex];
861    mbufs [bdIndex] = NULL;
862
863    status = bdRing [bdIndex].Status;
864    bdRing [bdIndex].Status = 0;
865
866    if (current != NULL) {
867      if ((status & FEC_BD_LAST) != 0) {
868        if (previous != NULL) {
869          IF_PREPEND(&ifp->if_snd, previous);
870        }
871      }
872    } else {
873      break;
874    }
875
876    previous = current;
877  } while (bdIndex != bdStop);
878}
879#endif
880
881static void mpc5200_fec_discard_tx_frames(
882  int bdCount,
883  struct mbuf **mbufs
884)
885{
886  int bdIndex = 0;
887
888  for (bdIndex = 0; bdIndex < bdCount; ++bdIndex) {
889    struct mbuf *m = mbufs [bdIndex];
890
891    if (m != NULL) {
892      mbufs [bdIndex] = NULL;
893      m_free(m);
894    }
895  }
896}
897
898static void mpc5200_fec_reset_tx_dma(
899  int bdCount,
900  TaskBD1_t *bdRing,
901  struct mbuf **mbufs,
902  struct mbuf *m
903)
904{
905  TaskStop(FEC_XMIT_TASK_NO);
906  TaskBDReset(FEC_XMIT_TASK_NO);
907  mpc5200_fec_discard_tx_frames(bdCount, mbufs);
908  while (m != NULL) {
909    m = m_free(m);
910  }
911}
912
913static struct mbuf *mpc5200_fec_next_fragment(
914  struct ifnet *ifp,
915  struct mbuf *m,
916  bool *isFirst
917)
918{
919  struct mbuf *n = NULL;
920
921  *isFirst = false;
922
923  while (true) {
924    if (m == NULL) {
925      IF_DEQUEUE(&ifp->if_snd, m);
926
927      if (m != NULL) {
928        *isFirst = true;
929      } else {
930        ifp->if_flags &= ~IFF_OACTIVE;
931
932        return NULL;
933      }
934    }
935
936    if (m->m_len > 0) {
937      break;
938    } else {
939      m = m_free(m);
940    }
941  }
942
943  n = m->m_next;
944  while (n != NULL && n->m_len <= 0) {
945    n = m_free(n);
946  }
947  m->m_next = n;
948
949  return m;
950}
951
952static bool mpc5200_fec_transmit(
953  struct ifnet *ifp,
954  int bdCount,
955  TaskBD1_t *bdRing,
956  struct mbuf **mbufs,
957  int *bdIndexPtr,
958  struct mbuf **mPtr,
959  TaskBD1_t **firstPtr
960)
961{
962  bool bdShortage = false;
963  int bdIndex = *bdIndexPtr;
964  struct mbuf *m = *mPtr;
965  TaskBD1_t *first = *firstPtr;
966
967  while (true) {
968    TaskBD1_t *bd = &bdRing [bdIndex];
969
970    if (bd->Status == 0) {
971      struct mbuf *done = mbufs [bdIndex];
972      bool isFirst = false;
973
974      if (done != NULL) {
975        m_free(done);
976        mbufs [bdIndex] = NULL;
977      }
978
979      m = mpc5200_fec_next_fragment(ifp, m, &isFirst);
980      if (m != NULL) {
981        uint32 status = (uint32) m->m_len;
982
983        mbufs [bdIndex] = m;
984
985        rtems_cache_flush_multiple_data_lines(mtod(m, void *), m->m_len);
986
987        if (isFirst) {
988          first = bd;
989        } else {
990          status |= FEC_BD_READY;
991        }
992
993        bd->DataPtr [0] = mtod(m, uint32);
994
995        if (m->m_next != NULL) {
996          bd->Status = status;
997        } else {
998          bd->Status = status | FEC_BD_INT | FEC_BD_LAST;
999          first->Status |= FEC_BD_READY;
1000          SDMA_TASK_ENABLE(SDMA_TCR, FEC_XMIT_TASK_NO);
1001        }
1002
1003        m = m->m_next;
1004      } else {
1005        break;
1006      }
1007    } else {
1008      bdShortage = true;
1009      break;
1010    }
1011
1012    if (bdIndex < bdCount - 1) {
1013      ++bdIndex;
1014    } else {
1015      bdIndex = 0;
1016    }
1017  }
1018
1019  *bdIndexPtr = bdIndex;
1020  *mPtr = m;
1021  *firstPtr = first;
1022
1023  return bdShortage;
1024}
1025
1026static void mpc5200_fec_tx_daemon(void *arg)
1027{
1028  mpc5200_fec_context *self = arg;
1029  struct ifnet *ifp = &self->arpcom.ac_if;
1030  int bdIndex = 0;
1031  int bdCount = self->txBdCount;
1032  struct mbuf **mbufs = &self->txMbuf [0];
1033  struct mbuf *m = NULL;
1034  TaskBD1_t *bdRing = mpc5200_fec_init_tx_dma(bdCount, mbufs);
1035  TaskBD1_t *first = NULL;
1036  bool bdShortage = false;
1037
1038  while (true) {
1039    if (bdShortage) {
1040      bestcomm_glue_irq_enable(FEC_XMIT_TASK_NO);
1041    }
1042    mpc5200_fec_wait_for_event();
1043
1044    if (self->state != FEC_STATE_NORMAL) {
1045      mpc5200_fec_reset_tx_dma(bdCount, bdRing, mbufs, m);
1046      mpc5200_fec_restart(self, self->rxDaemonTid);
1047      bdIndex = 0;
1048      m = NULL;
1049      first = NULL;
1050    }
1051
1052    bdShortage = mpc5200_fec_transmit(
1053      ifp,
1054      bdCount,
1055      bdRing,
1056      mbufs,
1057      &bdIndex,
1058      &m,
1059      &first
1060    );
1061  }
1062}
1063
1064static struct mbuf *mpc5200_fec_add_mbuf(struct ifnet *ifp, TaskBD1_t *bd)
1065{
1066  struct mbuf *m = NULL;
1067
1068  MGETHDR (m, M_WAIT, MT_DATA);
1069  MCLGET (m, M_WAIT);
1070  m->m_pkthdr.rcvif = ifp;
1071
1072  /* XXX: The dcbi operation does not work properly */
1073  rtems_cache_flush_multiple_data_lines(mtod(m, void *), ETHER_MAX_LEN);
1074
1075  bd->DataPtr [0] = mtod(m, uint32);
1076  bd->Status = ETHER_MAX_LEN | FEC_BD_READY;
1077
1078  return m;
1079}
1080
1081static TaskBD1_t *mpc5200_fec_init_rx_dma(
1082  struct ifnet *ifp,
1083  int bdCount,
1084  struct mbuf **mbufs
1085)
1086{
1087  TaskSetupParamSet_t param = {
1088    .NumBD = bdCount,
1089    .Size = {
1090      .MaxBuf = ETHER_MAX_LEN
1091    },
1092    .Initiator = 0,
1093    .StartAddrSrc = (uint32) &mpc5200.rfifo_data,
1094    .IncrSrc = 0,
1095    .SzSrc = sizeof(uint32_t),
1096    .StartAddrDst = 0,
1097    .IncrDst = sizeof(uint32_t),
1098    .SzDst = sizeof(uint32_t)
1099  };
1100  TaskBD1_t *bdRing = NULL;
1101  int bdIndex = 0;
1102
1103  TaskSetup(FEC_RECV_TASK_NO, &param);
1104  bdRing = (TaskBD1_t *) TaskGetBDRing(FEC_RECV_TASK_NO);
1105
1106  for (bdIndex = 0; bdIndex < bdCount; ++bdIndex) {
1107    mbufs [bdIndex] = mpc5200_fec_add_mbuf(ifp, &bdRing [bdIndex]);
1108  }
1109
1110  return bdRing;
1111}
1112
1113static void mpc5200_fec_reset_rx_dma(int bdCount, TaskBD1_t *bdRing)
1114{
1115  int bdIndex = 0;
1116
1117  TaskStop(FEC_RECV_TASK_NO);
1118  TaskBDReset(FEC_RECV_TASK_NO);
1119
1120  for (bdIndex = 0; bdIndex < bdCount; ++bdIndex) {
1121    bdRing [bdIndex].Status = ETHER_MAX_LEN | FEC_BD_READY;
1122  }
1123}
1124
1125static int mpc5200_fec_ether_input(
1126  struct ifnet *ifp,
1127  int bdIndex,
1128  int bdCount,
1129  TaskBD1_t *bdRing,
1130  struct mbuf **mbufs
1131)
1132{
1133  while (true) {
1134    TaskBD1_t *bd = &bdRing [bdIndex];
1135    struct mbuf *m = mbufs [bdIndex];
1136    uint32 status = 0;
1137    int len = 0;
1138    struct ether_header *eh = NULL;
1139
1140    SDMA_CLEAR_IEVENT(&mpc5200.sdma.IntPend, FEC_RECV_TASK_NO);
1141    status = bd->Status;
1142
1143    if ((status & FEC_BD_READY) != 0) {
1144      break;
1145    }
1146
1147    eh = mtod(m, struct ether_header *);
1148
1149    len = (status & 0xffff) - ETHER_HDR_LEN - ETHER_CRC_LEN;
1150    m->m_len = len;
1151    m->m_pkthdr.len = len;
1152    m->m_data = mtod(m, char *) + ETHER_HDR_LEN;
1153
1154    ether_input(ifp, eh, m);
1155
1156    mbufs [bdIndex] = mpc5200_fec_add_mbuf(ifp, bd);
1157
1158    if (bdIndex < bdCount - 1) {
1159      ++bdIndex;
1160    } else {
1161      bdIndex = 0;
1162    }
1163  }
1164
1165  return bdIndex;
1166}
1167
1168static void mpc5200_fec_rx_daemon(void *arg)
1169{
1170  mpc5200_fec_context *self = arg;
1171  struct ifnet *ifp = &self->arpcom.ac_if;
1172  int bdIndex = 0;
1173  int bdCount = self->rxBdCount;
1174  struct mbuf **mbufs = &self->rxMbuf [0];
1175  TaskBD1_t *bdRing = mpc5200_fec_init_rx_dma(ifp, bdCount, mbufs);
1176
1177  while (true) {
1178    bestcomm_glue_irq_enable(FEC_RECV_TASK_NO);
1179    mpc5200_fec_wait_for_event();
1180
1181    bdIndex = mpc5200_fec_ether_input(ifp, bdIndex, bdCount, bdRing, mbufs);
1182
1183    if (self->state != FEC_STATE_NORMAL) {
1184      mpc5200_fec_reset_rx_dma(bdCount, bdRing);
1185      mpc5200_fec_restart(self, self->txDaemonTid);
1186      bdIndex = 0;
1187    }
1188  }
1189}
1190
1191/*
1192 * Initialize and start the device
1193 */
1194static void mpc5200_fec_init(void *arg)
1195{
1196  rtems_status_code sc = RTEMS_SUCCESSFUL;
1197  mpc5200_fec_context *self = (mpc5200_fec_context *)arg;
1198  struct ifnet *ifp = &self->arpcom.ac_if;
1199
1200  if(self->txDaemonTid == 0)
1201    {
1202      size_t rxMbufTableSize = self->rxBdCount * sizeof(*self->rxMbuf);
1203      size_t txMbufTableSize = self->txBdCount * sizeof(*self->txMbuf);
1204
1205      /*
1206       * Allocate a set of mbuf pointers
1207       */
1208      self->rxMbuf = malloc(rxMbufTableSize, M_MBUF, M_NOWAIT);
1209      self->txMbuf = malloc(txMbufTableSize, M_MBUF, M_NOWAIT);
1210
1211      if(!self->rxMbuf || !self->txMbuf)
1212        rtems_panic ("No memory for mbuf pointers");
1213
1214      /*
1215       * DMA setup
1216       */
1217      bestcomm_glue_init();
1218      mpc5200.sdma.ipr [0] = 4; /* always initiator     */
1219      mpc5200.sdma.ipr [3] = 6; /* eth rx initiator     */
1220      mpc5200.sdma.ipr [4] = 5; /* eth tx initiator     */
1221
1222      /*
1223       * Set up interrupts
1224       */
1225      bestcomm_glue_irq_install(FEC_RECV_TASK_NO,
1226                                mpc5200_smartcomm_rx_irq_handler,
1227                                self);
1228      bestcomm_glue_irq_install(FEC_XMIT_TASK_NO,
1229                                mpc5200_smartcomm_tx_irq_handler,
1230                                self);
1231      sc = rtems_interrupt_handler_install(
1232        BSP_SIU_IRQ_ETH,
1233        "FEC",
1234        RTEMS_INTERRUPT_UNIQUE,
1235        mpc5200_fec_irq_handler,
1236        self
1237      );
1238      if(sc != RTEMS_SUCCESSFUL) {
1239        rtems_panic ("Can't attach MPC5x00 FEX interrupt handler\n");
1240      }
1241
1242      /*
1243       * Start driver tasks
1244       */
1245      self->txDaemonTid = rtems_bsdnet_newproc("FEtx", 4096, mpc5200_fec_tx_daemon, self);
1246      self->rxDaemonTid = rtems_bsdnet_newproc("FErx", 4096, mpc5200_fec_rx_daemon, self);
1247    }
1248
1249  mpc5200_fec_request_restart(self);
1250
1251  /*
1252   * Set flags appropriately
1253   */
1254  if(ifp->if_flags & IFF_PROMISC)
1255    mpc5200.r_cntrl |= 0x08;
1256  else
1257    mpc5200.r_cntrl &= ~0x08;
1258
1259  /*
1260   * Tell the world that we're running.
1261   */
1262  ifp->if_flags |= IFF_RUNNING;
1263}
1264
1265static void enet_stats (mpc5200_fec_context *self)
1266{
1267  if (self->phyAddr >= 0) {
1268    struct ifnet *ifp = &self->arpcom.ac_if;
1269    int media = IFM_MAKEWORD(0, 0, 0, self->phyAddr);
1270    int rv = (*ifp->if_ioctl)(ifp, SIOCGIFMEDIA, (caddr_t) &media);
1271
1272    if (rv == 0) {
1273      rtems_ifmedia2str(media, NULL, 0);
1274      printf ("\n");
1275    } else {
1276      printf ("PHY communication error\n");
1277    }
1278  }
1279  printf ("       Rx Interrupts:%-8lu", self->rxInterrupts);
1280  printf ("        Rx Not First:%-8lu", self->rxNotFirst);
1281  printf ("         Rx Not Last:%-8lu\n", self->rxNotLast);
1282  printf ("            Rx Giant:%-8lu", self->rxGiant);
1283  printf ("        Rx Non-octet:%-8lu", self->rxNonOctet);
1284  printf ("          Rx Bad CRC:%-8lu\n", self->rxBadCRC);
1285  printf ("       Rx FIFO Error:%-8lu", self->rxFIFOError);
1286  printf ("        Rx Collision:%-8lu", self->rxCollision);
1287
1288  printf ("       Tx Interrupts:%-8lu\n", self->txInterrupts);
1289  printf ("         Tx Deferred:%-8lu", self->txDeferred);
1290  printf ("   Tx Late Collision:%-8lu", self->txLateCollision);
1291  printf (" Tx Retransmit Limit:%-8lu\n", self->txRetryLimit);
1292  printf ("         Tx Underrun:%-8lu", self->txUnderrun);
1293  printf ("       Tx FIFO Error:%-8lu", self->txFIFOError);
1294  printf ("       Tx Misaligned:%-8lu\n", self->txMisaligned);
1295}
1296
1297int32_t mpc5200_fec_setMultiFilter(struct ifnet *ifp)
1298{
1299  /*mpc5200_fec_context *self = ifp->if_softc; */
1300  /* XXX anything to do? */
1301  return 0;
1302}
1303
1304
1305/*
1306 * Driver ioctl handler
1307 */
1308static int mpc5200_fec_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data)
1309  {
1310  mpc5200_fec_context *self = ifp->if_softc;
1311  int error = 0;
1312
1313  switch(command)
1314    {
1315
1316    case SIOCGIFADDR:
1317    case SIOCSIFADDR:
1318
1319      ether_ioctl(ifp, command, data);
1320
1321      break;
1322
1323    case SIOCADDMULTI:
1324    case SIOCDELMULTI: {
1325      struct ifreq* ifr = (struct ifreq*) data;
1326      error = (command == SIOCADDMULTI)
1327                  ? ether_addmulti(ifr, &self->arpcom)
1328                  : ether_delmulti(ifr, &self->arpcom);
1329
1330       if (error == ENETRESET) {
1331         if (ifp->if_flags & IFF_RUNNING)
1332           error = mpc5200_fec_setMultiFilter(ifp);
1333         else
1334           error = 0;
1335       }
1336       break;
1337    }
1338
1339    case SIOCSIFFLAGS:
1340
1341      switch(ifp->if_flags & (IFF_UP | IFF_RUNNING))
1342        {
1343
1344        case IFF_RUNNING:
1345
1346          mpc5200_fec_off(self);
1347
1348          break;
1349
1350        case IFF_UP:
1351
1352          mpc5200_fec_init(self);
1353
1354          break;
1355
1356        case IFF_UP | IFF_RUNNING:
1357
1358          mpc5200_fec_off(self);
1359          mpc5200_fec_init(self);
1360
1361          break;
1362
1363        default:
1364          break;
1365
1366        }
1367
1368      break;
1369
1370    case SIOCGIFMEDIA:
1371    case SIOCSIFMEDIA:
1372      error = rtems_mii_ioctl(&self->mdio, self, command, (int *) data);
1373      break;
1374
1375    case SIO_RTEMS_SHOW_STATS:
1376
1377      enet_stats(self);
1378
1379      break;
1380
1381   /*
1382    * FIXME: All sorts of multicast commands need to be added here!
1383    */
1384    default:
1385
1386    error = EINVAL;
1387
1388    break;
1389
1390    }
1391
1392  return error;
1393
1394  }
1395
1396
1397/*
1398 * Attach the MPC5200 fec driver to the system
1399 */
1400int rtems_mpc5200_fec_driver_attach(struct rtems_bsdnet_ifconfig *config)
1401  {
1402  mpc5200_fec_context *self;
1403  struct ifnet *ifp;
1404  int    mtu;
1405  int    unitNumber;
1406  char   *unitName;
1407
1408 /*
1409  * Parse driver name
1410  */
1411  if((unitNumber = rtems_bsdnet_parse_driver_name(config, &unitName)) < 0)
1412    return 0;
1413
1414 /*
1415  * Is driver free?
1416  */
1417  if ((unitNumber <= 0) || (unitNumber > NIFACES))
1418    {
1419
1420    printf ("Bad FEC unit number.\n");
1421    return 0;
1422
1423    }
1424
1425  self = &enet_driver[unitNumber - 1];
1426  ifp = &self->arpcom.ac_if;
1427
1428  if(ifp->if_softc != NULL)
1429    {
1430
1431    printf ("Driver already in use.\n");
1432    return 0;
1433
1434    }
1435
1436  self->mdio.mdio_r = mpc5200_eth_mii_read;
1437  self->mdio.mdio_w = mpc5200_eth_mii_write;
1438
1439  /*
1440   * Process options
1441   */
1442#if NVRAM_CONFIGURE == 1
1443
1444  /* Configure from NVRAM */
1445  if(addr = nvram->ipaddr)
1446    {
1447
1448    /* We have a non-zero entry, copy the value */
1449    if(pAddr = malloc(INET_ADDR_MAX_BUF_SIZE, 0, M_NOWAIT))
1450      config->ip_address = (char *)inet_ntop(AF_INET, &addr, pAddr, INET_ADDR_MAX_BUF_SIZE -1);
1451    else
1452      rtems_panic("Can't allocate ip_address buffer!\n");
1453
1454    }
1455
1456  if(addr = nvram->netmask)
1457    {
1458
1459    /* We have a non-zero entry, copy the value */
1460    if (pAddr = malloc (INET_ADDR_MAX_BUF_SIZE, 0, M_NOWAIT))
1461      config->ip_netmask = (char *)inet_ntop(AF_INET, &addr, pAddr, INET_ADDR_MAX_BUF_SIZE -1);
1462    else
1463      rtems_panic("Can't allocate ip_netmask buffer!\n");
1464
1465    }
1466
1467  /* Ethernet address requires special handling -- it must be copied into
1468   * the arpcom struct. The following if construct serves only to give the
1469   * User Area NVRAM parameter the highest priority.
1470   *
1471   * If the ethernet address is specified in NVRAM, go ahead and copy it.
1472   * (ETHER_ADDR_LEN = 6 bytes).
1473   */
1474  if(nvram->enaddr[0] || nvram->enaddr[1] || nvram->enaddr[2])
1475    {
1476
1477    /* Anything in the first three bytes indicates a non-zero entry, copy value */
1478        memcpy((void *)self->arpcom.ac_enaddr, &nvram->enaddr, ETHER_ADDR_LEN);
1479
1480    }
1481  else
1482    if(config->hardware_address)
1483      {
1484
1485      /* There is no entry in NVRAM, but there is in the ifconfig struct, so use it. */
1486      memcpy((void *)self->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
1487      }
1488    else
1489      {
1490      /* There is no ethernet address provided, so it could be read
1491       * from the Ethernet protocol block of SCC1 in DPRAM.
1492       */
1493      rtems_panic("No Ethernet address specified!\n");
1494      }
1495
1496#else /* NVRAM_CONFIGURE != 1 */
1497
1498  if(config->hardware_address)
1499    {
1500
1501    memcpy(self->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
1502
1503    }
1504  else
1505    {
1506
1507    /* There is no ethernet address provided, so it could be read
1508     * from the Ethernet protocol block of SCC1 in DPRAM.
1509     */
1510    rtems_panic("No Ethernet address specified!\n");
1511
1512    }
1513
1514#endif /* NVRAM_CONFIGURE != 1 */
1515#ifdef HAS_UBOOT
1516  if ((self->arpcom.ac_enaddr[0] == 0) &&
1517      (self->arpcom.ac_enaddr[1] == 0) &&
1518      (self->arpcom.ac_enaddr[2] == 0)) {
1519      memcpy(
1520        (void *)self->arpcom.ac_enaddr,
1521        bsp_uboot_board_info.bi_enetaddr,
1522        ETHER_ADDR_LEN
1523      );
1524  }
1525#endif
1526  if(config->mtu)
1527    mtu = config->mtu;
1528  else
1529    mtu = ETHERMTU;
1530
1531  if(config->rbuf_count)
1532    self->rxBdCount = config->rbuf_count;
1533  else
1534    self->rxBdCount = RX_BUF_COUNT;
1535
1536  if(config->xbuf_count)
1537    self->txBdCount = config->xbuf_count;
1538  else
1539    self->txBdCount = TX_BUF_COUNT;
1540
1541  self->acceptBroadcast = !config->ignore_broadcast;
1542
1543 /*
1544  * Set up network interface values
1545  */
1546  ifp->if_softc   = self;
1547  ifp->if_unit    = unitNumber;
1548  ifp->if_name    = unitName;
1549  ifp->if_mtu     = mtu;
1550  ifp->if_init    = mpc5200_fec_init;
1551  ifp->if_ioctl   = mpc5200_fec_ioctl;
1552  ifp->if_start   = mpc5200_fec_tx_start;
1553  ifp->if_output  = ether_output;
1554  ifp->if_flags   = IFF_BROADCAST | IFF_MULTICAST;
1555  /*ifp->if_flags   = IFF_BROADCAST | IFF_SIMPLEX;*/
1556
1557  if(ifp->if_snd.ifq_maxlen == 0)
1558    ifp->if_snd.ifq_maxlen = ifqmaxlen;
1559
1560  /*
1561   * Attach the interface
1562   */
1563  if_attach(ifp);
1564
1565  ether_ifattach(ifp);
1566
1567  return 1;
1568  }
1569
1570
1571int rtems_mpc5200_fec_driver_attach_detach(struct rtems_bsdnet_ifconfig *config, int attaching)
1572{
1573  if (attaching) {
1574    return rtems_mpc5200_fec_driver_attach(config);
1575  }
1576  else {
1577    return 0;
1578  }
1579}
1580
1581
Note: See TracBrowser for help on using the repository browser.