source: rtems/c/src/lib/libbsp/m68k/genmcf548x/network/network.c @ c499856

4.115
Last change on this file since c499856 was c499856, checked in by Chris Johns <chrisj@…>, on 03/20/14 at 21:10:47

Change all references of rtems.com to rtems.org.

  • Property mode set to 100644
File size: 41.0 KB
Line 
1/*===============================================================*\
2| Project: RTEMS generic MCF548X 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) 2009                           |
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.org/license/LICENSE.                           |
18|                                                                 |
19+-----------------------------------------------------------------+
20| this file contains the networking driver                        |
21\*===============================================================*/
22/*
23 *  RTEMS/TCPIP driver for MCF548X 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 Motorola MCF548X by Thomas Doerfler, <Thomas.Doerfler@imd-systems.de>
36 *  COPYRIGHT (c) 2009, IMD
37 *
38 */
39
40#include <rtems.h>
41#include <rtems/error.h>
42#include <rtems/rtems_bsdnet.h>
43#include <stdio.h>
44#include <sys/param.h>
45#include <sys/mbuf.h>
46#include <sys/socket.h>
47#include <sys/sockio.h>
48#include <net/if.h>
49#include <netinet/in.h>
50#include <netinet/if_ether.h>
51#include <net/if_var.h>
52
53#include <bsp.h>
54#include <bsp/irq-generic.h>
55#include <mcf548x/mcf548x.h>
56#include <rtems/rtems_mii_ioctl.h>
57#include <errno.h>
58
59/* freescale-api-specifics... */
60#include <mcf548x/MCD_dma.h>
61#include <mcf548x/mcdma_glue.h>
62
63/*
64 * Number of interfaces supported by this driver
65 */
66#define NIFACES 2
67
68#define FEC_WATCHDOG_TIMEOUT 5 /* check media every 5 seconds */
69
70#define DMA_BD_RX_NUM   32 /* Number of receive buffer descriptors      */
71#define DMA_BD_TX_NUM   32 /* Number of transmit buffer descriptors     */
72
73#define FEC_EVENT RTEMS_EVENT_0
74
75/*
76 * internal SRAM
77 * Layout:
78 * - RxBD channel 0
79 * - TxBD channel 0
80 * - RxBD channel 1
81 * - TxBD channel 1
82 * - DMA task memory
83 */
84extern char _SysSramBase[];
85#define SRAM_RXBD_BASE(base,chan) (((MCD_bufDescFec*)(base))    \
86  +((chan)                                                      \
87    *(DMA_BD_RX_NUM+DMA_BD_TX_NUM)))
88
89#define SRAM_TXBD_BASE(base,chan) (((MCD_bufDescFec*)(base))            \
90  +((chan)                                                              \
91    *(DMA_BD_RX_NUM+DMA_BD_TX_NUM)                                      \
92    +DMA_BD_RX_NUM))
93
94#define SRAM_DMA_BASE(base) ((void *)SRAM_RXBD_BASE(base,NIFACES+1))
95
96
97#undef ETH_DEBUG
98
99/*
100 * Default number of buffer descriptors set aside for this driver.
101 * The number of transmit buffer descriptors has to be quite large
102 * since a single frame often uses four or more buffer descriptors.
103 */
104#define RX_BUF_COUNT     DMA_BD_RX_NUM
105#define TX_BUF_COUNT     DMA_BD_TX_NUM
106#define TX_BD_PER_BUF    1
107
108#define INET_ADDR_MAX_BUF_SIZE (sizeof "255.255.255.255")
109
110#define MCF548X_FEC0_IRQ_VECTOR    (39+64)
111#define MCF548X_FEC1_IRQ_VECTOR    (38+64)
112
113#define MCF548X_FEC_IRQ_VECTOR(chan) (MCF548X_FEC0_IRQ_VECTOR           \
114                                      +(chan)*(MCF548X_FEC1_IRQ_VECTOR  \
115                                               -MCF548X_FEC0_IRQ_VECTOR))
116
117#define MCF548X_FEC_VECTOR2CHAN(vector) (((int)(vector)-MCF548X_FEC0_IRQ_VECTOR) \
118                                         /(MCF548X_FEC1_IRQ_VECTOR      \
119                                           -MCF548X_FEC0_IRQ_VECTOR))
120
121#define MCDMA_FEC_RX_CHAN(chan) (0 + NIFACES*(chan))
122#define MCDMA_FEC_TX_CHAN(chan) (1 + NIFACES*(chan))
123
124#define MCF548X_FEC0_RX_INITIATOR  (16)
125#define MCF548X_FEC1_RX_INITIATOR  (30)
126#define MCF548X_FEC_RX_INITIATOR(chan) (MCF548X_FEC0_RX_INITIATOR               \
127                                      +(chan)*(MCF548X_FEC1_RX_INITIATOR        \
128                                               -MCF548X_FEC0_RX_INITIATOR))
129#define MCF548X_FEC0_TX_INITIATOR  (17)
130#define MCF548X_FEC1_TX_INITIATOR  (31)
131#define MCF548X_FEC_TX_INITIATOR(chan) (MCF548X_FEC0_TX_INITIATOR               \
132                                      +(chan)*(MCF548X_FEC1_TX_INITIATOR        \
133                                               -MCF548X_FEC0_TX_INITIATOR))
134
135/* BD and parameters are stored in SRAM(refer to sdma.h) */
136#define MCF548X_FEC_BD_BASE    ETH_BD_BASE
137
138/* RBD bits definitions */
139#define MCF548X_FEC_RBD_EMPTY  0x8000   /* Buffer is empty */
140#define MCF548X_FEC_RBD_WRAP   0x2000   /* Last BD in ring */
141#define MCF548X_FEC_RBD_INT    0x1000   /* Interrupt */
142#define MCF548X_FEC_RBD_LAST   0x0800   /* Buffer is last in frame(useless) */
143#define MCF548X_FEC_RBD_MISS   0x0100   /* Miss bit for prom mode */
144#define MCF548X_FEC_RBD_BC     0x0080   /* The received frame is broadcast frame */
145#define MCF548X_FEC_RBD_MC     0x0040   /* The received frame is multicast frame */
146#define MCF548X_FEC_RBD_LG     0x0020   /* Frame length violation */
147#define MCF548X_FEC_RBD_NO     0x0010   /* Nonoctet align frame */
148#define MCF548X_FEC_RBD_SH     0x0008   /* Short frame, FEC does not support SH and this bit is always cleared */
149#define MCF548X_FEC_RBD_CR     0x0004   /* CRC error */
150#define MCF548X_FEC_RBD_OV     0x0002   /* Receive FIFO overrun */
151#define MCF548X_FEC_RBD_TR     0x0001   /* The receive frame is truncated */
152#define MCF548X_FEC_RBD_ERR    (MCF548X_FEC_RBD_LG  | \
153                                MCF548X_FEC_RBD_NO  | \
154                                MCF548X_FEC_RBD_CR  | \
155                                MCF548X_FEC_RBD_OV  | \
156                                MCF548X_FEC_RBD_TR)
157
158/* TBD bits definitions */
159#define MCF548X_FEC_TBD_READY  0x8000   /* Buffer is ready */
160#define MCF548X_FEC_TBD_WRAP   0x2000   /* Last BD in ring */
161#define MCF548X_FEC_TBD_INT    0x1000   /* Interrupt */
162#define MCF548X_FEC_TBD_LAST   0x0800   /* Buffer is last in frame */
163#define MCF548X_FEC_TBD_TC     0x0400   /* Transmit the CRC */
164#define MCF548X_FEC_TBD_ABC    0x0200   /* Append bad CRC */
165
166#define FEC_INTR_MASK_USED \
167(MCF548X_FEC_EIMR_LC   | MCF548X_FEC_EIMR_RL    | \
168 MCF548X_FEC_EIMR_XFUN | MCF548X_FEC_EIMR_XFERR | MCF548X_FEC_EIMR_RFERR)
169
170typedef enum {
171  FEC_STATE_RESTART_0,
172  FEC_STATE_RESTART_1,
173  FEC_STATE_NORMAL,
174} fec_state;
175
176/*
177 * Device data
178 */
179struct mcf548x_enet_struct {
180  struct arpcom           arpcom;
181  struct mbuf             **rxMbuf;
182  struct mbuf             **txMbuf;
183  int                     chan;
184  fec_state               state;
185  int                     acceptBroadcast;
186  int                     rxBdCount;
187  int                     txBdCount;
188  MCD_bufDescFec          *rxBd;
189  MCD_bufDescFec          *txBd;
190  int                     rxDmaChan; /* dma task */
191  int                     txDmaChan; /* dma task */
192  rtems_id                rxDaemonTid;
193  rtems_id                txDaemonTid;
194
195  /*
196   * MDIO/Phy info
197   */
198  struct rtems_mdio_info mdio_info;
199  int phy_default;
200  int phy_chan;    /* which fec channel services this phy access? */
201  int media_state; /* (last detected) state of media */
202
203  unsigned long           rxInterrupts;
204  unsigned long           rxNotLast;
205  unsigned long           rxGiant;
206  unsigned long           rxNonOctet;
207  unsigned long           rxBadCRC;
208  unsigned long           rxFIFOError;
209  unsigned long           rxCollision;
210
211  unsigned long           txInterrupts;
212  unsigned long           txDeferred;
213  unsigned long           txLateCollision;
214  unsigned long           txUnderrun;
215  unsigned long           txFIFOError;
216  unsigned long           txMisaligned;
217  unsigned long           rxNotFirst;
218  unsigned long           txRetryLimit;
219  };
220
221static struct mcf548x_enet_struct enet_driver[NIFACES];
222
223static void mcf548x_fec_restart(struct mcf548x_enet_struct *sc, rtems_id otherDaemon);
224
225static void fec_send_event(rtems_id task)
226{
227  rtems_bsdnet_event_send(task, FEC_EVENT);
228}
229
230static void fec_wait_for_event(void)
231{
232  rtems_event_set out;
233  rtems_bsdnet_event_receive(
234    FEC_EVENT,
235    RTEMS_EVENT_ANY | RTEMS_WAIT,
236    RTEMS_NO_TIMEOUT,
237    &out
238  );
239}
240
241static void mcf548x_fec_request_restart(struct mcf548x_enet_struct *sc)
242{
243  sc->state = FEC_STATE_RESTART_0;
244  fec_send_event(sc->txDaemonTid);
245  fec_send_event(sc->rxDaemonTid);
246}
247
248/*
249 * Function:    MCF548X_eth_addr_filter_set
250 *
251 * Description: Set individual address filter for unicast address and
252 *                              set physical address registers.
253 *
254 * Returns:             void
255 *
256 * Notes:
257 *
258 */
259static void mcf548x_eth_addr_filter_set(struct mcf548x_enet_struct *sc)  {
260  unsigned char *mac;
261  unsigned char currByte;                               /* byte for which to compute the CRC */
262  int           byte;                                   /* loop - counter */
263  int           bit;                                    /* loop - counter */
264  unsigned long crc = 0xffffffff;               /* initial value */
265  int chan     = sc->chan;
266
267 /*
268  * Get the mac address of ethernet controller
269  */
270  mac = (unsigned char *)(&sc->arpcom.ac_enaddr);
271
272 /*
273  * The algorithm used is the following:
274  * we loop on each of the six bytes of the provided address,
275  * and we compute the CRC by left-shifting the previous
276  * value by one position, so that each bit in the current
277  * byte of the address may contribute the calculation. If
278  * the latter and the MSB in the CRC are different, then
279  * the CRC value so computed is also ex-ored with the
280  * "polynomium generator". The current byte of the address
281  * is also shifted right by one bit at each iteration.
282  * This is because the CRC generatore in hardware is implemented
283  * as a shift-register with as many ex-ores as the radixes
284  * in the polynomium. This suggests that we represent the
285  * polynomiumm itsc as a 32-bit constant.
286  */
287  for(byte = 0; byte < 6; byte++)
288    {
289
290    currByte = mac[byte];
291
292    for(bit = 0; bit < 8; bit++)
293      {
294
295      if((currByte & 0x01) ^ (crc & 0x01))
296        {
297
298        crc >>= 1;
299        crc = crc ^ 0xedb88320;
300
301        }
302      else
303        {
304
305        crc >>= 1;
306
307        }
308
309      currByte >>= 1;
310
311      }
312
313    }
314
315    crc = crc >> 26;
316
317   /*
318    * Set individual hash table register
319    */
320    if(crc >= 32)
321      {
322
323        MCF548X_FEC_IAUR(chan) = (1 << (crc - 32));
324        MCF548X_FEC_IALR(chan) = 0;
325
326      }
327    else
328     {
329
330       MCF548X_FEC_IAUR(chan) = 0;
331       MCF548X_FEC_IALR(chan) = (1 << crc);
332
333     }
334
335   /*
336    * Set physical address
337    */
338    MCF548X_FEC_PALR(chan) = ((mac[0] << 24) +
339                              (mac[1] << 16) +
340                              (mac[2] <<  8) +
341                              mac[3]);
342    MCF548X_FEC_PAUR(chan) = ((mac[4] << 24)
343                              + (mac[5] << 16)) + 0x8808;
344
345   }
346
347
348/*
349 * Function:    mcf548x_eth_mii_read
350 *
351 * Description: Read a media independent interface (MII) register on an
352 *                              18-wire ethernet tranceiver (PHY). Please see your PHY
353 *                              documentation for the register map.
354 *
355 * Returns:             0 if ok
356 *
357 * Notes:
358 *
359 */
360int mcf548x_eth_mii_read(
361 int phyAddr,                          /* PHY number to access or -1       */
362 void *uarg,                           /* unit argument                    */
363 unsigned regAddr,                     /* register address                 */
364 uint32_t *retVal)                     /* ptr to read buffer               */
365{
366  struct mcf548x_enet_struct *sc = uarg;
367  int timeout = 0xffff;
368  int chan = sc->phy_chan;
369
370 /*
371  * reading from any PHY's register is done by properly
372  * programming the FEC's MII data register.
373  */
374  MCF548X_FEC_MMFR(chan) = (MCF548X_FEC_MMFR_ST_01    |
375                            MCF548X_FEC_MMFR_OP_READ  |
376                            MCF548X_FEC_MMFR_TA_10    |
377                            MCF548X_FEC_MMFR_PA(phyAddr) |
378                            MCF548X_FEC_MMFR_RA(regAddr));
379
380 /*
381  * wait for the related interrupt
382  */
383  while ((timeout--) && (!(MCF548X_FEC_EIR(chan) & MCF548X_FEC_EIR_MII)));
384
385  if(timeout == 0) {
386
387#ifdef ETH_DEBUG
388    iprintf ("Read MDIO failed..." "\r\n");
389#endif
390
391    return 1;
392
393  }
394
395 /*
396  * clear mii interrupt bit
397  */
398  MCF548X_FEC_EIR(chan) = MCF548X_FEC_EIR_MII;
399
400 /*
401  * it's now safe to read the PHY's register
402  */
403  *retVal = (unsigned short)  MCF548X_FEC_MMFR(chan);
404
405  return 0;
406
407}
408
409/*
410 * Function:    mcf548x_eth_mii_write
411 *
412 * Description: Write a media independent interface (MII) register on an
413 *                              18-wire ethernet tranceiver (PHY). Please see your PHY
414 *                              documentation for the register map.
415 *
416 * Returns:             Success (boolean)
417 *
418 * Notes:
419 *
420 */
421static int mcf548x_eth_mii_write(
422 int phyAddr,                          /* PHY number to access or -1       */
423 void *uarg,                           /* unit argument                    */
424 unsigned regAddr,                     /* register address                 */
425 uint32_t data)                        /* write data                       */
426{
427  struct mcf548x_enet_struct *sc = uarg;
428  int chan     = sc->phy_chan;
429  int timeout  = 0xffff;
430
431  MCF548X_FEC_MMFR(chan) = (MCF548X_FEC_MMFR_ST_01    |
432                            MCF548X_FEC_MMFR_OP_WRITE |
433                            MCF548X_FEC_MMFR_TA_10    |
434                            MCF548X_FEC_MMFR_PA(phyAddr) |
435                            MCF548X_FEC_MMFR_RA(regAddr) |
436                            MCF548X_FEC_MMFR_DATA(data));
437
438 /*
439  * wait for the MII interrupt
440  */
441  while ((timeout--) && (!(MCF548X_FEC_EIR(chan) & MCF548X_FEC_EIR_MII)));
442
443  if(timeout == 0)
444    {
445
446#ifdef ETH_DEBUG
447    iprintf ("Write MDIO failed..." "\r\n");
448#endif
449
450    return 1;
451
452    }
453
454 /*
455  * clear MII interrupt bit
456  */
457  MCF548X_FEC_EIR(chan) = MCF548X_FEC_EIR_MII;
458
459  return 0;
460
461  }
462
463
464/*
465 * Function:    mcf548x_fec_reset
466 *
467 * Description: Reset a running ethernet driver including the hardware
468 *                              FIFOs and the FEC.
469 *
470 * Returns:             Success (boolean)
471 *
472 * Notes:
473 *
474 */
475static void mcf548x_fec_reset(struct mcf548x_enet_struct *sc) {
476  volatile int delay;
477  int chan     = sc->chan;
478  /*
479   * Clear FIFO status registers
480   */
481  MCF548X_FEC_FECRFSR(chan) = ~0;
482  MCF548X_FEC_FECTFSR(chan) = ~0;
483
484  /*
485   * reset the FIFOs
486   */
487  MCF548X_FEC_FRST(chan) = 0x03000000;
488
489  for (delay = 0;delay < 16*4;delay++) {};
490
491  MCF548X_FEC_FRST(chan) = 0x01000000;
492
493  /*
494   * Issue a reset command to the FEC chip
495   */
496  MCF548X_FEC_ECR(chan) |= MCF548X_FEC_ECR_RESET;
497
498  /*
499   * wait at least 16 clock cycles
500   */
501  for (delay = 0;delay < 16*4;delay++) {};
502}
503
504
505/*
506 * Function:    mcf548x_fec_off
507 *
508 * Description: Stop the FEC and disable the ethernet SmartComm tasks.
509 *                              This function "turns off" the driver.
510 *
511 * Returns:             void
512 *
513 * Notes:
514 *
515 */
516void mcf548x_fec_off(struct mcf548x_enet_struct *sc)
517  {
518  int            counter = 0xffff;
519  int chan     = sc->chan;
520
521
522#if defined(ETH_DEBUG)
523  uint32_t phyStatus;
524  int i;
525
526  for(i = 0; i < 9; i++)
527    {
528
529    mcf548x_eth_mii_read(sc->phy_default, sc, i, &phyStatus);
530    iprintf ("Mii reg %d: 0x%04lx" "\r\n", i, phyStatus);
531
532    }
533
534  for(i = 16; i < 21; i++)
535    {
536
537    mcf548x_eth_mii_read(sc->phy_default, sc, i, &phyStatus);
538    iprintf ("Mii reg %d: 0x%04lx" "\r\n", i, phyStatus);
539
540    }
541  for(i = 0; i < 32; i++)
542    {
543
544    mcf548x_eth_mii_read(i, sc, 0, &phyStatus);
545    iprintf ("Mii Phy=%d, reg 0: 0x%04lx" "\r\n", i, phyStatus);
546
547    }
548#endif  /* ETH_DEBUG */
549
550 /*
551  * block FEC chip interrupts
552  */
553  MCF548X_FEC_EIMR(chan) = 0;
554
555 /*
556  * issue graceful stop command to the FEC transmitter if necessary
557  */
558  MCF548X_FEC_TCR(chan) |= MCF548X_FEC_TCR_GTS;
559
560 /*
561  * wait for graceful stop to register
562  * FIXME: add rtems_task_wake_after here, if it takes to long
563  */
564  while((counter--) && (!(  MCF548X_FEC_EIR(chan) & MCF548X_FEC_EIR_GRA)));
565
566  /*
567   * Disable the SmartDMA transmit and receive tasks.
568   */
569  MCD_killDma( sc->rxDmaChan );
570  MCD_killDma( sc->txDmaChan );
571 /*
572  * Disable transmit / receive interrupts
573  */
574  mcdma_glue_irq_disable(sc->txDmaChan);
575  mcdma_glue_irq_disable(sc->rxDmaChan);
576
577 /*
578  * Disable the Ethernet Controller
579  */
580  MCF548X_FEC_ECR(chan) &= ~(MCF548X_FEC_ECR_ETHER_EN);
581}
582
583/*
584 * MCF548X FEC interrupt handler
585 */
586void mcf548x_fec_irq_handler(rtems_vector_number vector)
587{
588  struct mcf548x_enet_struct *sc;
589  volatile uint32_t ievent;
590  int chan;
591
592  sc     = &(enet_driver[MCF548X_FEC_VECTOR2CHAN(vector)]);
593  chan   = sc->chan;
594  ievent = MCF548X_FEC_EIR(chan);
595
596  MCF548X_FEC_EIR(chan) = ievent;
597  /*
598   * check errors, update statistics
599   */
600  if (ievent & MCF548X_FEC_EIR_LC) {
601    sc->txLateCollision++;
602  }
603  if (ievent & MCF548X_FEC_EIR_RL) {
604    sc->txRetryLimit++;
605  }
606  if (ievent & MCF548X_FEC_EIR_XFUN) {
607    sc->txUnderrun++;
608  }
609  if (ievent & MCF548X_FEC_EIR_XFERR) {
610    sc->txFIFOError++;
611  }
612  if (ievent & MCF548X_FEC_EIR_RFERR) {
613    sc->rxFIFOError++;
614  }
615  /*
616   * fatal error ocurred?
617   */
618  if (ievent & (MCF548X_FEC_EIR_RFERR | MCF548X_FEC_EIR_XFERR)) {
619    MCF548X_FEC_EIMR(chan) &=~(MCF548X_FEC_EIMR_RFERR | MCF548X_FEC_EIMR_XFERR);
620    printk("fifo\n");
621    mcf548x_fec_request_restart(sc);
622  }
623}
624
625/*
626 * MCF548X DMA ethernet interrupt handler
627 */
628void mcf548x_mcdma_rx_irq_handler(void * param)
629{
630  struct mcf548x_enet_struct *sc = (struct mcf548x_enet_struct *)param;
631  /* Frame received? */
632  if(MCDMA_GET_PENDING(sc->rxDmaChan)) {
633    MCDMA_CLR_PENDING(sc->rxDmaChan);
634
635    mcdma_glue_irq_disable(sc->rxDmaChan);/*Disable receive ints*/
636    sc->rxInterrupts++;                 /* Rx int has occurred */
637    fec_send_event(sc->rxDaemonTid);
638  }
639}
640
641/*
642 * MCF548X DMA ethernet interrupt handler
643 */
644void mcf548x_mcdma_tx_irq_handler(void * param)
645{
646  struct mcf548x_enet_struct *sc = (struct mcf548x_enet_struct *)param;
647
648 /* Buffer transmitted or transmitter error? */
649  if(MCDMA_GET_PENDING(sc->txDmaChan)) {
650
651    MCDMA_CLR_PENDING(sc->txDmaChan);
652
653    mcdma_glue_irq_disable(sc->txDmaChan);/*Disable tx ints*/
654
655    sc->txInterrupts++; /* Tx int has occurred */
656
657    fec_send_event(sc->txDaemonTid);
658  }
659}
660
661/*
662 * Function:    mcf548x_fec_initialize_hardware
663 *
664 * Description: Configure the MCF548X FEC registers and enable the
665 *                              SmartComm tasks. This function "turns on" the driver.
666 *
667 * Returns:             void
668 *
669 * Notes:
670 *
671 */
672static void mcf548x_fec_initialize_hardware(struct mcf548x_enet_struct *sc)
673  {
674  int chan = sc->chan;
675
676 /*
677  * Reset mcf548x FEC
678  */
679  mcf548x_fec_reset(sc);
680
681 /*
682  * Clear FEC-Lite interrupt event register (IEVENT)
683  */
684  MCF548X_FEC_EIR(chan) = MCF548X_FEC_EIR_CLEAR_ALL;
685
686 /*
687  * Set interrupt mask register
688  */
689  MCF548X_FEC_EIMR(chan) = FEC_INTR_MASK_USED;
690  /*
691   * Set FEC-Lite receive control register (R_CNTRL)
692   * frame length=1518, MII mode for 18-wire-transceiver
693   */
694  MCF548X_FEC_RCR(chan) = (MCF548X_FEC_RCR_MAX_FL(ETHER_MAX_LEN)
695                           | MCF548X_FEC_RCR_FCE
696                           | MCF548X_FEC_RCR_MII_MODE);
697
698  /*
699   * Set FEC-Lite transmit control register (X_CNTRL)
700   * full-duplex, heartbeat disabled
701   */
702  MCF548X_FEC_TCR(chan) = MCF548X_FEC_TCR_FDEN;
703
704
705
706 /*
707  * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock(33Mhz)
708  * and do not drop the Preamble.
709  */
710  MCF548X_FEC_MSCR(chan) = MCF548X_FEC_MSCR_MII_SPEED(7); /* ipb_clk = 33 MHz */
711
712 /*
713  * Set Opcode/Pause Duration Register
714  */
715  MCF548X_FEC_PAUR(chan) = 0x00010020;
716
717  /*
718   * Set Rx FIFO alarm and granularity value
719   */
720  MCF548X_FEC_FECRFCR(chan) = (MCF548X_FEC_FECRFCR_FRM
721                               | MCF548X_FEC_FECRFCR_GR(0x7));
722  MCF548X_FEC_FECRFAR(chan) = MCF548X_FEC_FECRFAR_ALARM(256);
723
724  /*
725   * Set Tx FIFO granularity value
726   */
727  MCF548X_FEC_FECTFCR(chan) = (MCF548X_FEC_FECTFCR_FRM
728                               | MCF548X_FEC_FECTFCR_GR(7));
729
730  /*
731   * Set transmit fifo watermark register (X_WMRK), default = 64
732   */
733  MCF548X_FEC_FECTFAR(chan) = MCF548X_FEC_FECTFAR_ALARM(512);
734  MCF548X_FEC_FECTFWR(chan) = MCF548X_FEC_FECTFWR_X_WMRK_256;
735
736 /*
737  * Set individual address filter for unicast address
738  * and set physical address registers.
739  */
740  mcf548x_eth_addr_filter_set(sc);
741
742 /*
743  * Set multicast address filter
744  */
745  MCF548X_FEC_GAUR(chan) = 0x00000000;
746  MCF548X_FEC_GALR(chan) = 0x00000000;
747
748 /*
749  * enable CRC in finite state machine register
750  */
751  MCF548X_FEC_CTCWR(chan) = MCF548X_FEC_CTCWR_TFCW | MCF548X_FEC_CTCWR_CRC;
752  }
753
754
755/*
756 * Send packet (caller provides header).
757 */
758static void mcf548x_fec_tx_start(struct ifnet *ifp)
759  {
760
761  struct mcf548x_enet_struct *sc = ifp->if_softc;
762
763  ifp->if_flags |= IFF_OACTIVE;
764
765  fec_send_event(sc->txDaemonTid);
766
767  }
768
769static void fec_start_dma_and_controller(struct mcf548x_enet_struct *sc)
770{
771  int chan = sc->chan;
772  int mcdma_rc;
773      /*
774       * Enable the SmartDMA receive task.
775       */
776      mcdma_rc = MCD_startDma
777        (sc->rxDmaChan, /* the channel on which to run the DMA */
778         (void *)sc->rxBd, /* the address to move data from, or buffer-descriptor addr */
779         0,             /* the amount to increment the source address per transfer */
780         (void *)&MCF548X_FEC_FECRFDR(chan), /* the address to move data to */
781         0,             /* the amount to increment the destination address per transfer */
782         ETHER_MAX_LEN, /* the number of bytes to transfer independent of the transfer size */
783         0,             /* the number bytes in of each data movement (1, 2, or 4) */
784         MCF548X_FEC_RX_INITIATOR(chan), /* what device initiates the DMA */
785         2,  /* priority of the DMA */
786         0 /* flags describing the DMA */
787         | MCD_FECRX_DMA
788         | MCD_INTERRUPT
789         | MCD_TT_FLAGS_CW
790         | MCD_TT_FLAGS_RL
791         | MCD_TT_FLAGS_SP
792         ,
793         0 /* a description of byte swapping, bit swapping, and CRC actions */
794         | MCD_NO_CSUM
795         | MCD_NO_BYTE_SWAP
796         );
797      if (mcdma_rc != MCD_OK) {
798        rtems_panic("FEC: cannot start rx DMA");
799      }
800      mcdma_rc = MCD_startDma
801        (sc->txDmaChan, /* the channel on which to run the DMA */
802         (void *)sc->txBd, /* the address to move data from, or buffer-descriptor addr */
803         0,             /* the amount to increment the source address per transfer */
804         (void *)&MCF548X_FEC_FECTFDR(chan), /* the address to move data to */
805         0,             /* the amount to increment the destination address per transfer */
806         ETHER_MAX_LEN, /* the number of bytes to transfer independent of the transfer size */
807         0,             /* the number bytes in of each data movement (1, 2, or 4) */
808         MCF548X_FEC_TX_INITIATOR(chan), /* what device initiates the DMA */
809         1,  /* priority of the DMA */
810         0 /* flags describing the DMA */
811         | MCD_FECTX_DMA
812         | MCD_INTERRUPT
813         | MCD_TT_FLAGS_CW
814         | MCD_TT_FLAGS_RL
815         | MCD_TT_FLAGS_SP
816         ,
817         0 /* a description of byte swapping, bit swapping, and CRC actions */
818         | MCD_NO_CSUM
819         | MCD_NO_BYTE_SWAP
820         );
821      if (mcdma_rc != MCD_OK) {
822        rtems_panic("FEC: cannot start tx DMA");
823      }
824
825  /*
826   * Enable FEC-Lite controller
827   */
828  MCF548X_FEC_ECR(chan) |= MCF548X_FEC_ECR_ETHER_EN;
829}
830
831static void mcf548x_fec_restart(struct mcf548x_enet_struct *sc, rtems_id otherDaemon)
832{
833  if (sc->state == FEC_STATE_RESTART_1) {
834    mcf548x_fec_initialize_hardware(sc);
835    fec_start_dma_and_controller(sc);
836    sc->state = FEC_STATE_NORMAL;
837  } else {
838    sc->state = FEC_STATE_RESTART_1;
839  }
840
841  fec_send_event(otherDaemon);
842  while (sc->state != FEC_STATE_NORMAL) {
843    fec_wait_for_event();
844  }
845}
846
847static void fec_reset_bd_and_discard_tx_frames(
848  int bdCount,
849  MCD_bufDescFec *bdRing,
850  struct mbuf **mbufs
851)
852{
853  int bdIndex = 0;
854
855  for (bdIndex = 0; bdIndex < bdCount; ++bdIndex) {
856    bool bdIsLast = bdIndex == bdCount - 1;
857    struct mbuf *m = mbufs[bdIndex];
858
859    bdRing[bdIndex].statCtrl = bdIsLast ? MCF548X_FEC_TBD_WRAP : 0;
860
861    if (m != NULL) {
862      mbufs[bdIndex] = NULL;
863      m_free(m);
864    }
865  }
866}
867
868static void fec_reset_tx_dma(
869  int dmaChan,
870  int bdCount,
871  MCD_bufDescFec *bdRing,
872  struct mbuf **mbufs,
873  struct mbuf *m
874)
875{
876  if (m != NULL) {
877    m_freem(m);
878  }
879
880  MCD_killDma(dmaChan);
881
882  fec_reset_bd_and_discard_tx_frames(bdCount, bdRing, mbufs);
883}
884
885static struct mbuf *fec_next_fragment(
886  struct ifnet *ifp,
887  struct mbuf *m,
888  bool *isFirst
889)
890{
891  struct mbuf *n = NULL;
892
893  *isFirst = false;
894
895  while (true) {
896    if (m == NULL) {
897      IF_DEQUEUE(&ifp->if_snd, m);
898
899      if (m != NULL) {
900        *isFirst = true;
901      } else {
902        ifp->if_flags &= ~IFF_OACTIVE;
903
904        return NULL;
905      }
906    }
907
908    if (m->m_len > 0) {
909      break;
910    } else {
911      m = m_free(m);
912    }
913  }
914
915  n = m->m_next;
916  while (n != NULL && n->m_len <= 0) {
917    n = m_free(n);
918  }
919  m->m_next = n;
920
921  return m;
922}
923
924static bool fec_transmit(
925  struct ifnet *ifp,
926  int dmaChan,
927  int bdCount,
928  MCD_bufDescFec *bdRing,
929  struct mbuf **mbufs,
930  int *bdIndexPtr,
931  struct mbuf **mPtr,
932  MCD_bufDescFec **firstPtr
933)
934{
935  bool bdShortage = false;
936  int bdIndex = *bdIndexPtr;
937  struct mbuf *m = *mPtr;
938  MCD_bufDescFec *first = *firstPtr;
939
940  while (true) {
941    MCD_bufDescFec *bd = &bdRing[bdIndex];
942
943    MCDMA_CLR_PENDING(dmaChan);
944    if ((bd->statCtrl & MCF548X_FEC_TBD_READY) == 0) {
945      struct mbuf *done = mbufs[bdIndex];
946      bool isFirst = false;
947
948      if (done != NULL) {
949        m_free(done);
950        mbufs[bdIndex] = NULL;
951      }
952
953      m = fec_next_fragment(ifp, m, &isFirst);
954      if (m != NULL) {
955        bool bdIsLast = bdIndex == bdCount - 1;
956        u16 status = bdIsLast ? MCF548X_FEC_TBD_WRAP : 0;
957
958        bd->length = (u16) m->m_len;
959        bd->dataPointer = mtod(m, u32);
960
961        mbufs[bdIndex] = m;
962
963        rtems_cache_flush_multiple_data_lines(mtod(m, void *), m->m_len);
964
965        if (isFirst) {
966          first = bd;
967        } else {
968          status |= MCF548X_FEC_TBD_READY;
969        }
970
971        if (m->m_next != NULL) {
972          bd->statCtrl = status;
973        } else {
974          bd->statCtrl = status | MCF548X_FEC_TBD_INT | MCF548X_FEC_TBD_LAST;
975          first->statCtrl |= MCF548X_FEC_TBD_READY;
976          MCD_continDma(dmaChan);
977        }
978
979        m = m->m_next;
980      } else {
981        break;
982      }
983    } else {
984      bdShortage = true;
985      break;
986    }
987
988    if (bdIndex < bdCount - 1) {
989      ++bdIndex;
990    } else {
991      bdIndex = 0;
992    }
993  }
994
995  *bdIndexPtr = bdIndex;
996  *mPtr = m;
997  *firstPtr = first;
998
999  return bdShortage;
1000}
1001
1002static MCD_bufDescFec *fec_init_tx_dma(
1003  MCD_bufDescFec *bdRing,
1004  int bdCount
1005)
1006{
1007  int bdIndex;
1008
1009  for (bdIndex = 0; bdIndex < bdCount; ++bdIndex) {
1010    bool bdIsLast = bdIndex == bdCount - 1;
1011
1012    bdRing[bdIndex].dataPointer = 0;
1013    bdRing[bdIndex].length = 0;
1014    bdRing[bdIndex].statCtrl = bdIsLast ? MCF548X_FEC_RBD_WRAP : 0;
1015  }
1016
1017  return bdRing;
1018}
1019
1020static void mcf548x_fec_txDaemon(void *arg)
1021{
1022  struct mcf548x_enet_struct *sc = arg;
1023  struct ifnet *ifp = &sc->arpcom.ac_if;
1024  int dmaChan = sc->txDmaChan;
1025  int bdIndex = 0;
1026  int bdCount = sc->txBdCount;
1027  struct mbuf **mbufs = &sc->txMbuf[0];
1028  struct mbuf *m = NULL;
1029  MCD_bufDescFec *bdRing = fec_init_tx_dma(sc->txBd, bdCount);
1030  MCD_bufDescFec *first = NULL;
1031  bool bdShortage = false;
1032
1033  memset(mbufs, 0, bdCount * sizeof(*mbufs));
1034
1035  while (true) {
1036    if (bdShortage) {
1037      mcdma_glue_irq_enable(dmaChan);
1038    }
1039    fec_wait_for_event();
1040
1041    if (sc->state != FEC_STATE_NORMAL) {
1042      fec_reset_tx_dma(dmaChan, bdCount, bdRing, mbufs, m);
1043      mcf548x_fec_restart(sc, sc->rxDaemonTid);
1044      bdIndex = 0;
1045      m = NULL;
1046      first = NULL;
1047    }
1048
1049    bdShortage = fec_transmit(
1050      ifp,
1051      dmaChan,
1052      bdCount,
1053      bdRing,
1054      mbufs,
1055      &bdIndex,
1056      &m,
1057      &first
1058    );
1059  }
1060}
1061
1062static struct mbuf *fec_add_mbuf(
1063  int how,
1064  struct ifnet *ifp,
1065  MCD_bufDescFec *bd,
1066  bool bdIsLast
1067)
1068{
1069  struct mbuf *m;
1070
1071  MGETHDR(m, how, MT_DATA);
1072  if (m != NULL) {
1073    MCLGET(m, how);
1074    if ((m->m_flags & M_EXT) != 0) {
1075      m->m_pkthdr.rcvif = ifp;
1076
1077      rtems_cache_invalidate_multiple_data_lines(mtod(m, void *), ETHER_MAX_LEN);
1078
1079      bd->dataPointer = mtod(m, u32);
1080      bd->length = ETHER_MAX_LEN;
1081      bd->statCtrl = MCF548X_FEC_RBD_EMPTY
1082        | MCF548X_FEC_RBD_INT
1083        | (bdIsLast ? MCF548X_FEC_RBD_WRAP : 0);
1084    } else {
1085      m_free(m);
1086    }
1087  }
1088
1089  return m;
1090}
1091
1092static MCD_bufDescFec *fec_init_rx_dma(
1093  MCD_bufDescFec *bdRing,
1094  struct ifnet *ifp,
1095  int bdCount,
1096  struct mbuf **mbufs
1097)
1098{
1099  int bdIndex;
1100
1101  for (bdIndex = 0; bdIndex < bdCount; ++bdIndex) {
1102    bool bdIsLast = bdIndex == bdCount - 1;
1103
1104    mbufs[bdIndex] = fec_add_mbuf(M_WAIT, ifp, &bdRing[bdIndex], bdIsLast);
1105  }
1106
1107  return bdRing;
1108}
1109
1110static void fec_reset_rx_dma(
1111  int dmaChan,
1112  int bdCount,
1113  MCD_bufDescFec *bdRing
1114)
1115{
1116  int bdIndex;
1117
1118  MCD_killDma(dmaChan);
1119
1120  for (bdIndex = 0; bdIndex < bdCount - 1; ++bdIndex) {
1121    bdRing[bdIndex].length = ETHER_MAX_LEN;
1122    bdRing[bdIndex].statCtrl = MCF548X_FEC_RBD_EMPTY | MCF548X_FEC_RBD_INT;
1123  }
1124
1125  bdRing[bdIndex].length = ETHER_MAX_LEN;
1126  bdRing[bdIndex].statCtrl = MCF548X_FEC_RBD_EMPTY | MCF548X_FEC_RBD_INT | MCF548X_FEC_RBD_WRAP;
1127}
1128
1129static int fec_ether_input(
1130  struct ifnet *ifp,
1131  int dmaChan,
1132  int bdIndex,
1133  int bdCount,
1134  MCD_bufDescFec *bdRing,
1135  struct mbuf **mbufs
1136)
1137{
1138  while (true) {
1139    bool bdIsLast = bdIndex == bdCount - 1;
1140    MCD_bufDescFec *bd = &bdRing[bdIndex];
1141    struct mbuf *m = mbufs[bdIndex];
1142    struct mbuf *n;
1143    u16 status;
1144
1145    MCDMA_CLR_PENDING(dmaChan);
1146    status = bd->statCtrl;
1147
1148    if ((status & MCF548X_FEC_RBD_EMPTY) != 0) {
1149      break;
1150    }
1151
1152    n = fec_add_mbuf(0, ifp, bd, bdIsLast);
1153    if (n != NULL) {
1154      int len = bd->length - ETHER_HDR_LEN - ETHER_CRC_LEN;
1155      struct ether_header *eh = mtod(m, struct ether_header *);
1156
1157      m->m_len = len;
1158      m->m_pkthdr.len = len;
1159      m->m_data = mtod(m, char *) + ETHER_HDR_LEN;
1160
1161      ether_input(ifp, eh, m);
1162    } else {
1163      n = m;
1164    }
1165
1166    mbufs[bdIndex] = n;
1167
1168    if (bdIndex < bdCount - 1) {
1169      ++bdIndex;
1170    } else {
1171      bdIndex = 0;
1172    }
1173  }
1174
1175  return bdIndex;
1176}
1177
1178static void mcf548x_fec_rxDaemon(void *arg)
1179{
1180  struct mcf548x_enet_struct *sc = arg;
1181  struct ifnet *ifp = &sc->arpcom.ac_if;
1182  int dmaChan = sc->rxDmaChan;
1183  int bdIndex = 0;
1184  int bdCount = sc->rxBdCount;
1185  struct mbuf **mbufs = &sc->rxMbuf[0];
1186  MCD_bufDescFec *bdRing = fec_init_rx_dma(sc->rxBd, ifp, bdCount, mbufs);
1187
1188  while (true) {
1189    mcdma_glue_irq_enable(dmaChan);
1190    fec_wait_for_event();
1191
1192    bdIndex = fec_ether_input(ifp, dmaChan, bdIndex, bdCount, bdRing, mbufs);
1193
1194    if (sc->state != FEC_STATE_NORMAL) {
1195      fec_reset_rx_dma(dmaChan, bdCount, bdRing);
1196      mcf548x_fec_restart(sc, sc->txDaemonTid);
1197      bdIndex = 0;
1198    }
1199  }
1200}
1201
1202/*
1203 * Initialize and start the device
1204 */
1205static void mcf548x_fec_init(void *arg)
1206{
1207  struct mcf548x_enet_struct *sc = (struct mcf548x_enet_struct *)arg;
1208  struct ifnet *ifp = &sc->arpcom.ac_if;
1209  int chan = sc->chan;
1210  rtems_isr_entry old_handler;
1211  char *txTaskName = "FTx0";
1212  char *rxTaskName = "FRx0";
1213  if(sc->txDaemonTid == 0)
1214    {
1215      /*
1216       * Allocate a set of BDs
1217       */
1218      sc->rxBd =  SRAM_RXBD_BASE(_SysSramBase,chan);
1219      sc->txBd =  SRAM_TXBD_BASE(_SysSramBase,chan);
1220
1221      if(!sc->rxBd || !sc->txBd)
1222        rtems_panic ("No memory for BDs");
1223      /*
1224       * clear the BDs
1225       */
1226      memset((void *)sc->rxBd,0,sc->rxBdCount * sizeof *(sc->rxBd));
1227      memset((void *)sc->txBd,0,sc->txBdCount * sizeof *(sc->txBd));
1228      /*
1229       * Allocate a set of mbuf pointers
1230       */
1231      sc->rxMbuf =
1232        malloc(sc->rxBdCount * sizeof *sc->rxMbuf, M_MBUF, M_NOWAIT);
1233      sc->txMbuf =
1234        malloc(sc->txBdCount * sizeof *sc->txMbuf, M_MBUF, M_NOWAIT);
1235
1236      if(!sc->rxMbuf || !sc->txMbuf)
1237        rtems_panic ("No memory for mbuf pointers");
1238
1239      sc->txDmaChan = MCDMA_FEC_TX_CHAN(chan);
1240      sc->rxDmaChan = MCDMA_FEC_RX_CHAN(chan);
1241
1242      mcdma_glue_init(SRAM_DMA_BASE(_SysSramBase));
1243
1244      /*
1245       * Set up interrupts
1246       */
1247      mcdma_glue_irq_install(sc->rxDmaChan,
1248                             mcf548x_mcdma_rx_irq_handler,
1249                             sc);
1250      mcdma_glue_irq_install(sc->txDmaChan,
1251                             mcf548x_mcdma_tx_irq_handler,
1252                             sc);
1253      if(rtems_interrupt_catch(mcf548x_fec_irq_handler,
1254                               MCF548X_FEC_IRQ_VECTOR(chan),
1255                               &old_handler)) {
1256        rtems_panic ("Can't attach MFC54xx FEX interrupt handler\n");
1257      }
1258
1259      bsp_interrupt_vector_enable(MCF548X_IRQ_FEC(chan));
1260
1261      MCF548X_FEC_EIMR(chan) = FEC_INTR_MASK_USED;
1262
1263      /*
1264       * Start driver tasks
1265       */
1266      txTaskName[3] = '0'+chan;
1267      rxTaskName[3] = '0'+chan;
1268      sc->txDaemonTid = rtems_bsdnet_newproc(txTaskName, 4096,
1269                                             mcf548x_fec_txDaemon, sc);
1270      sc->rxDaemonTid = rtems_bsdnet_newproc(rxTaskName, 4096,
1271                                             mcf548x_fec_rxDaemon, sc);
1272    }
1273
1274  mcf548x_fec_request_restart(sc);
1275
1276  /*
1277   * Set flags appropriately
1278   */
1279  if(ifp->if_flags & IFF_PROMISC)
1280    MCF548X_FEC_RCR(chan) |=  MCF548X_FEC_RCR_PROM;
1281  else
1282    MCF548X_FEC_RCR(chan) &= ~MCF548X_FEC_RCR_PROM;
1283
1284  /*
1285   * init timer so the "watchdog function gets called periodically
1286   */
1287  ifp->if_timer    = 1;
1288  /*
1289   * Tell the world that we're running.
1290   */
1291  ifp->if_flags |= IFF_RUNNING;
1292}
1293
1294
1295static void enet_stats (struct mcf548x_enet_struct *sc)
1296{
1297  printf ("       Rx Interrupts:%-8lu", sc->rxInterrupts);
1298  printf ("        Rx Not First:%-8lu", sc->rxNotFirst);
1299  printf ("         Rx Not Last:%-8lu\n", sc->rxNotLast);
1300  printf ("            Rx Giant:%-8lu", sc->rxGiant);
1301  printf ("        Rx Non-octet:%-8lu", sc->rxNonOctet);
1302  printf ("          Rx Bad CRC:%-8lu\n", sc->rxBadCRC);
1303  printf ("       Rx FIFO Error:%-8lu", sc->rxFIFOError);
1304  printf ("        Rx Collision:%-8lu", sc->rxCollision);
1305
1306  printf ("       Tx Interrupts:%-8lu\n", sc->txInterrupts);
1307  printf ("         Tx Deferred:%-8lu", sc->txDeferred);
1308  printf ("   Tx Late Collision:%-8lu", sc->txLateCollision);
1309  printf (" Tx Retransmit Limit:%-8lu\n", sc->txRetryLimit);
1310  printf ("         Tx Underrun:%-8lu", sc->txUnderrun);
1311  printf ("       Tx FIFO Error:%-8lu", sc->txFIFOError);
1312  printf ("       Tx Misaligned:%-8lu\n", sc->txMisaligned);
1313
1314}
1315
1316int32_t mcf548x_fec_setMultiFilter(struct ifnet *ifp)
1317{
1318  /*struct mcf548x_enet_struct *sc = ifp->if_softc; */
1319  /* XXX anything to do? */
1320  return 0;
1321}
1322
1323
1324/*
1325 * Driver ioctl handler
1326 */
1327static int mcf548x_fec_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data)
1328  {
1329  struct mcf548x_enet_struct *sc = ifp->if_softc;
1330  int error = 0;
1331
1332  switch(command)
1333    {
1334
1335    case SIOCGIFMEDIA:
1336    case SIOCSIFMEDIA:
1337      rtems_mii_ioctl (&(sc->mdio_info),sc,command,(void *)data);
1338      break;
1339
1340    case SIOCGIFADDR:
1341    case SIOCSIFADDR:
1342
1343      ether_ioctl(ifp, command, data);
1344
1345      break;
1346
1347    case SIOCADDMULTI:
1348    case SIOCDELMULTI: {
1349      struct ifreq* ifr = (struct ifreq*) data;
1350      error = (command == SIOCADDMULTI)
1351                  ? ether_addmulti(ifr, &sc->arpcom)
1352                  : ether_delmulti(ifr, &sc->arpcom);
1353
1354       if (error == ENETRESET) {
1355         if (ifp->if_flags & IFF_RUNNING)
1356           error = mcf548x_fec_setMultiFilter(ifp);
1357         else
1358           error = 0;
1359       }
1360       break;
1361    }
1362
1363    case SIOCSIFFLAGS:
1364
1365      switch(ifp->if_flags & (IFF_UP | IFF_RUNNING))
1366        {
1367
1368        case IFF_RUNNING:
1369
1370          mcf548x_fec_off(sc);
1371
1372          break;
1373
1374        case IFF_UP:
1375
1376          mcf548x_fec_init(sc);
1377
1378          break;
1379
1380        case IFF_UP | IFF_RUNNING:
1381
1382          mcf548x_fec_off(sc);
1383          mcf548x_fec_init(sc);
1384
1385          break;
1386
1387        default:
1388          break;
1389
1390        }
1391
1392      break;
1393
1394    case SIO_RTEMS_SHOW_STATS:
1395
1396      enet_stats(sc);
1397
1398      break;
1399
1400   /*
1401    * FIXME: All sorts of multicast commands need to be added here!
1402    */
1403    default:
1404
1405    error = EINVAL;
1406
1407    break;
1408
1409    }
1410
1411  return error;
1412
1413  }
1414
1415
1416/*
1417 * init the PHY and adapt FEC settings
1418 */
1419int mcf548x_fec_mode_adapt(struct ifnet *ifp)
1420{
1421  int result = 0;
1422  struct mcf548x_enet_struct *sc = ifp->if_softc;
1423  int media = IFM_MAKEWORD( 0, 0, 0, sc->phy_default);
1424  int chan = sc->chan;
1425
1426  /*
1427   * fetch media status
1428   */
1429  result = mcf548x_fec_ioctl(ifp,SIOCGIFMEDIA,(caddr_t)&media);
1430  if (result != 0) {
1431    return result;
1432  }
1433  /*
1434   * status is unchanged? then do nothing
1435   */
1436  if (media == sc->media_state) {
1437    return 0;
1438  }
1439  /*
1440   * otherwise: for the first call, try to negotiate mode
1441   */
1442  if (sc->media_state == 0) {
1443    /*
1444     * set media status: set auto negotiation -> start auto-negotiation
1445     */
1446    media = IFM_MAKEWORD(0,IFM_AUTO,0,sc->phy_default);
1447    result = mcf548x_fec_ioctl(ifp,SIOCSIFMEDIA,(caddr_t)&media);
1448    if (result != 0) {
1449      return result;
1450    }
1451    /*
1452     * wait for auto-negotiation to terminate
1453     */
1454    do {
1455      media = IFM_MAKEWORD(0,0,0,sc->phy_default);
1456      result = mcf548x_fec_ioctl(ifp,SIOCGIFMEDIA,(caddr_t)&media);
1457      if (result != 0) {
1458        return result;
1459      }
1460    } while (IFM_NONE == IFM_SUBTYPE(media));
1461  }
1462
1463  /*
1464   * now set HW according to media results:
1465   */
1466
1467  /*
1468   * if we are half duplex then switch to half duplex
1469   */
1470  if (0 == (IFM_FDX & IFM_OPTIONS(media))) {
1471    MCF548X_FEC_TCR(chan) &= ~MCF548X_FEC_TCR_FDEN;
1472  }
1473  else {
1474    MCF548X_FEC_TCR(chan) |=  MCF548X_FEC_TCR_FDEN;
1475  }
1476  /*
1477   * store current media state for future compares
1478   */
1479  sc->media_state = media;
1480
1481  return 0;
1482}
1483
1484/*
1485 * periodically poll the PHY. if mode has changed,
1486 * then adjust the FEC settings
1487 */
1488static void mcf548x_fec_watchdog( struct ifnet *ifp)
1489{
1490  mcf548x_fec_mode_adapt(ifp);
1491  ifp->if_timer    = FEC_WATCHDOG_TIMEOUT;
1492}
1493
1494/*
1495 * Attach the MCF548X fec driver to the system
1496 */
1497int rtems_mcf548x_fec_driver_attach(struct rtems_bsdnet_ifconfig *config)
1498  {
1499  struct mcf548x_enet_struct *sc;
1500  struct ifnet *ifp;
1501  int    mtu;
1502  int    unitNumber;
1503  char   *unitName;
1504
1505 /*
1506  * Parse driver name
1507  */
1508  if((unitNumber = rtems_bsdnet_parse_driver_name(config, &unitName)) < 0)
1509    return 0;
1510
1511 /*
1512  * Is driver free?
1513  */
1514  if ((unitNumber <= 0) || (unitNumber > NIFACES))
1515    {
1516
1517    printf ("Bad FEC unit number.\n");
1518    return 0;
1519
1520    }
1521
1522  sc = &enet_driver[unitNumber - 1];
1523  sc->chan = unitNumber-1;
1524  ifp = &sc->arpcom.ac_if;
1525
1526  if(ifp->if_softc != NULL)
1527    {
1528
1529    printf ("Driver already in use.\n");
1530    return 0;
1531
1532    }
1533
1534  /*
1535   * Process options
1536   */
1537#if NVRAM_CONFIGURE == 1
1538
1539  /* Configure from NVRAM */
1540  if(addr = nvram->ipaddr)
1541    {
1542
1543    /* We have a non-zero entry, copy the value */
1544    if(pAddr = malloc(INET_ADDR_MAX_BUF_SIZE, 0, M_NOWAIT))
1545      config->ip_address = (char *)inet_ntop(AF_INET, &addr, pAddr, INET_ADDR_MAX_BUF_SIZE -1);
1546    else
1547      rtems_panic("Can't allocate ip_address buffer!\n");
1548
1549    }
1550
1551  if(addr = nvram->netmask)
1552    {
1553
1554    /* We have a non-zero entry, copy the value */
1555    if (pAddr = malloc (INET_ADDR_MAX_BUF_SIZE, 0, M_NOWAIT))
1556      config->ip_netmask = (char *)inet_ntop(AF_INET, &addr, pAddr, INET_ADDR_MAX_BUF_SIZE -1);
1557    else
1558      rtems_panic("Can't allocate ip_netmask buffer!\n");
1559
1560    }
1561
1562  /* Ethernet address requires special handling -- it must be copied into
1563   * the arpcom struct. The following if construct serves only to give the
1564   * User Area NVRAM parameter the highest priority.
1565   *
1566   * If the ethernet address is specified in NVRAM, go ahead and copy it.
1567   * (ETHER_ADDR_LEN = 6 bytes).
1568   */
1569  if(nvram->enaddr[0] || nvram->enaddr[1] || nvram->enaddr[2])
1570    {
1571
1572    /* Anything in the first three bytes indicates a non-zero entry, copy value */
1573        memcpy((void *)sc->arpcom.ac_enaddr, &nvram->enaddr, ETHER_ADDR_LEN);
1574
1575    }
1576  else
1577    if(config->hardware_address)
1578      {
1579
1580      /* There is no entry in NVRAM, but there is in the ifconfig struct, so use it. */
1581      memcpy((void *)sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
1582      }
1583
1584#else /* NVRAM_CONFIGURE != 1 */
1585
1586  if(config->hardware_address)
1587    {
1588
1589    memcpy(sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
1590
1591    }
1592
1593#endif /* NVRAM_CONFIGURE != 1 */
1594#ifdef HAS_UBOOT
1595  if ((sc->arpcom.ac_enaddr[0] == 0) &&
1596      (sc->arpcom.ac_enaddr[1] == 0) &&
1597      (sc->arpcom.ac_enaddr[2] == 0)) {
1598      memcpy(
1599        (void *)sc->arpcom.ac_enaddr,
1600        bsp_uboot_board_info.bi_enetaddr,
1601        ETHER_ADDR_LEN
1602      );
1603  }
1604#endif
1605#ifdef HAS_DBUG
1606  if ((sc->arpcom.ac_enaddr[0] == 0) &&
1607      (sc->arpcom.ac_enaddr[1] == 0) &&
1608      (sc->arpcom.ac_enaddr[2] == 0)) {
1609      memcpy(
1610        (void *)sc->arpcom.ac_enaddr,
1611        DBUG_SETTINGS.macaddr,
1612        ETHER_ADDR_LEN
1613      );
1614  }
1615#endif
1616  if ((sc->arpcom.ac_enaddr[0] == 0) &&
1617      (sc->arpcom.ac_enaddr[1] == 0) &&
1618      (sc->arpcom.ac_enaddr[2] == 0)) {
1619    /* There is no ethernet address provided, so it could be read
1620     * from the Ethernet protocol block of SCC1 in DPRAM.
1621     */
1622    rtems_panic("No Ethernet address specified!\n");
1623  }
1624  if(config->mtu)
1625    mtu = config->mtu;
1626  else
1627    mtu = ETHERMTU;
1628
1629  if(config->rbuf_count)
1630    sc->rxBdCount = config->rbuf_count;
1631  else
1632    sc->rxBdCount = RX_BUF_COUNT;
1633
1634  if(config->xbuf_count)
1635    sc->txBdCount = config->xbuf_count;
1636  else
1637    sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF;
1638
1639  sc->acceptBroadcast = !config->ignore_broadcast;
1640
1641  /*
1642   * setup info about mdio interface
1643   */
1644  sc->mdio_info.mdio_r   = mcf548x_eth_mii_read;
1645  sc->mdio_info.mdio_w   = mcf548x_eth_mii_write;
1646  sc->mdio_info.has_gmii = 0; /* we do not support gigabit IF */
1647
1648  /*
1649   * XXX: Although most hardware builders will assign the PHY addresses
1650   * like this, this should be more configurable
1651   */
1652  sc->phy_default = unitNumber-1;
1653  sc->phy_chan    = 0; /* assume all MII accesses are via FEC0 */
1654
1655 /*
1656  * Set up network interface values
1657  */
1658  ifp->if_softc   = sc;
1659  ifp->if_unit    = unitNumber;
1660  ifp->if_name    = unitName;
1661  ifp->if_mtu     = mtu;
1662  ifp->if_init    = mcf548x_fec_init;
1663  ifp->if_ioctl   = mcf548x_fec_ioctl;
1664  ifp->if_start   = mcf548x_fec_tx_start;
1665  ifp->if_output  = ether_output;
1666  ifp->if_watchdog =  mcf548x_fec_watchdog; /* XXX: timer is set in "init" */
1667  ifp->if_flags   = IFF_BROADCAST | IFF_MULTICAST;
1668  /*ifp->if_flags   = IFF_BROADCAST | IFF_SIMPLEX;*/
1669
1670  if(ifp->if_snd.ifq_maxlen == 0)
1671    ifp->if_snd.ifq_maxlen = ifqmaxlen;
1672
1673  /*
1674   * Attach the interface
1675   */
1676  if_attach(ifp);
1677
1678  ether_ifattach(ifp);
1679
1680  return 1;
1681  }
1682
1683
1684int rtems_mcf548x_fec_driver_attach_detach(struct rtems_bsdnet_ifconfig *config, int attaching)
1685{
1686  if (attaching) {
1687    return rtems_mcf548x_fec_driver_attach(config);
1688  }
1689  else {
1690    return 0;
1691  }
1692}
1693
1694
Note: See TracBrowser for help on using the repository browser.