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

4.104.115
Last change on this file since 045821e was 045821e, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on Oct 15, 2009 at 2:05:34 PM

add network support, various corrections

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