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

4.115
Last change on this file since 8d292011 was 8d292011, checked in by Sebastian Huber <sebastian.huber@…>, on 12/05/13 at 16:26:41

bsp/genmcf548x: Add initial values for INTC_ICRn

According to the manual the application must use unique and
non-overlapping level and priority definitions for enabled interrupts.

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