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

4.104.115
Last change on this file since 28b38f3 was 28b38f3, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on 02/25/10 at 11:01:35

combine all checks for missing MAC address
enable FPU, if POSIX init task present
explicitly disable all edge port interrupts

  • Property mode set to 100644
File size: 45.4 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_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_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_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  void      *dptr;
972
973  /*
974   * Input packet handling loop
975   */
976  rxBdIndex = 0;
977
978  for (;;) {
979    /*
980     * Clear old events
981     */
982    MCDMA_CLR_PENDING(sc->rxDmaChan);
983    /*
984     * Get the first BD pointer and its length.
985     */
986    bd     = sc->rxBd + rxBdIndex;
987    status = GET_BD_STATUS( bd );
988    len    = GET_BD_LENGTH( bd );
989
990    /*
991     * Loop through BDs until we find an empty one. This indicates that
992     * the DMA is still using it.
993     */
994    while( !(status & MCF548X_FEC_RBD_EMPTY) ) {
995
996      /*
997       * Remember the data pointer from this transfer.
998       */
999      dptr = GET_BD_BUFFER(bd);
1000      m    = sc->rxMbuf[rxBdIndex];
1001      m->m_len = m->m_pkthdr.len = (len
1002                                    - sizeof(uint32_t)
1003                                    - sizeof(struct ether_header));
1004      eh = mtod(m, struct ether_header *);
1005      m->m_data += sizeof(struct ether_header);
1006      ether_input(ifp, eh, m);
1007
1008      /*
1009       * Done w/ the BD. Clean it.
1010       */
1011      sc->rxMbuf[rxBdIndex] = NULL;
1012
1013      /*
1014       * Add a new buffer to the ring.
1015       */
1016      MGETHDR (m, M_WAIT, MT_DATA);
1017      MCLGET (m, M_WAIT);
1018      m->m_pkthdr.rcvif = ifp;
1019      size = ETHER_MAX_LEN;
1020
1021      sc->rxMbuf[rxBdIndex] = m;
1022      rtems_cache_invalidate_multiple_data_lines(mtod(m,const void *),
1023                                                 size);
1024
1025      SET_BD_BUFFER(bd,mtod(m, void *));
1026      SET_BD_LENGTH(bd,size);
1027      SET_BD_STATUS(bd,
1028                    MCF548X_FEC_RBD_EMPTY
1029                    |MCF548X_FEC_RBD_INT
1030                    |((rxBdIndex == sc->rxBdCount-1)
1031                      ? MCF548X_FEC_RBD_WRAP
1032                      : 0)
1033                    );
1034
1035      /*
1036       * advance to next BD
1037       */
1038      if (++rxBdIndex >= sc->rxBdCount) {
1039        rxBdIndex = 0;
1040      }
1041      /*
1042       * Get next BD pointer and its length.
1043       */
1044      bd     = sc->rxBd + rxBdIndex;
1045      status = GET_BD_STATUS( bd );
1046      len    = GET_BD_LENGTH( bd );
1047    }
1048    /*
1049     * Unmask RXF (Full frame received) event
1050     */
1051    mcdma_glue_irq_enable(sc->rxDmaChan);
1052
1053    rtems_bsdnet_event_receive (INTERRUPT_EVENT | FATAL_INT_EVENT,
1054                                RTEMS_WAIT | RTEMS_EVENT_ANY,
1055                                RTEMS_NO_TIMEOUT, &events);
1056    if (events & FATAL_INT_EVENT) {
1057      /*
1058       * fatal interrupt ocurred, so reinit fec and restart mcdma tasks
1059       */
1060      mcf548x_fec_restart(sc);
1061      rxBdIndex = 0;
1062    }
1063  }
1064}
1065
1066
1067/*
1068 * Function:    mcf548x_fec_initialize_hardware
1069 *
1070 * Description: Configure the MCF548X FEC registers and enable the
1071 *                              SmartComm tasks. This function "turns on" the driver.
1072 *
1073 * Returns:             void
1074 *
1075 * Notes:
1076 *
1077 */
1078static void mcf548x_fec_initialize_hardware(struct mcf548x_enet_struct *sc)
1079  {
1080  int chan = sc->chan;
1081
1082 /*
1083  * Reset mcf548x FEC
1084  */
1085  mcf548x_fec_reset(sc);
1086
1087 /*
1088  * Clear FEC-Lite interrupt event register (IEVENT)
1089  */
1090  MCF548X_FEC_EIR(chan) = MCF548X_FEC_EIR_CLEAR_ALL;
1091
1092 /*
1093  * Set interrupt mask register
1094  */
1095  MCF548X_FEC_EIMR(chan) = FEC_INTR_MASK_USED;
1096  /*
1097   * Set FEC-Lite receive control register (R_CNTRL)
1098   * frame length=1518, MII mode for 18-wire-transceiver
1099   */
1100  MCF548X_FEC_RCR(chan) = (MCF548X_FEC_RCR_MAX_FL(ETHER_MAX_LEN)
1101                           | MCF548X_FEC_RCR_FCE
1102                           | MCF548X_FEC_RCR_MII_MODE);
1103
1104  /*
1105   * Set FEC-Lite transmit control register (X_CNTRL)
1106   * full-duplex, heartbeat disabled
1107   */
1108  MCF548X_FEC_TCR(chan) = MCF548X_FEC_TCR_FDEN;
1109
1110
1111
1112 /*
1113  * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock(33Mhz)
1114  * and do not drop the Preamble.
1115  */
1116  MCF548X_FEC_MSCR(chan) = MCF548X_FEC_MSCR_MII_SPEED(7); /* ipb_clk = 33 MHz */
1117
1118 /*
1119  * Set Opcode/Pause Duration Register
1120  */
1121  MCF548X_FEC_PAUR(chan) = 0x00010020;
1122
1123  /*
1124   * Set Rx FIFO alarm and granularity value
1125   */
1126  MCF548X_FEC_FECRFCR(chan) = (MCF548X_FEC_FECRFCR_FRM
1127                               | MCF548X_FEC_FECRFCR_GR(0x7));
1128  MCF548X_FEC_FECRFAR(chan) = MCF548X_FEC_FECRFAR_ALARM(256);
1129
1130  /*
1131   * Set Tx FIFO granularity value
1132   */
1133  MCF548X_FEC_FECTFCR(chan) = (MCF548X_FEC_FECTFCR_FRM
1134                               | MCF548X_FEC_FECTFCR_GR(7));
1135
1136  /*
1137   * Set transmit fifo watermark register (X_WMRK), default = 64
1138   */
1139  MCF548X_FEC_FECTFAR(chan) = MCF548X_FEC_FECTFAR_ALARM(256);   /* 256 bytes */
1140  MCF548X_FEC_FECTFWR(chan) = MCF548X_FEC_FECTFWR_X_WMRK_64;    /* 64 bytes */
1141
1142 /*
1143  * Set individual address filter for unicast address
1144  * and set physical address registers.
1145  */
1146  mcf548x_eth_addr_filter_set(sc);
1147
1148 /*
1149  * Set multicast address filter
1150  */
1151  MCF548X_FEC_GAUR(chan) = 0x00000000;
1152  MCF548X_FEC_GALR(chan) = 0x00000000;
1153
1154 /*
1155  * enable CRC in finite state machine register
1156  */
1157  MCF548X_FEC_CTCWR(chan) = MCF548X_FEC_CTCWR_TFCW | MCF548X_FEC_CTCWR_CRC;
1158  }
1159
1160
1161/*
1162 * Send packet (caller provides header).
1163 */
1164static void mcf548x_fec_tx_start(struct ifnet *ifp)
1165  {
1166
1167  struct mcf548x_enet_struct *sc = ifp->if_softc;
1168
1169  ifp->if_flags |= IFF_OACTIVE;
1170
1171  rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
1172
1173  }
1174
1175
1176/*
1177 * start the DMA channel
1178 */
1179static void mcf548x_fec_startDMA(struct mcf548x_enet_struct *sc)
1180{
1181  int chan = sc->chan;
1182  int mcdma_rc;
1183      /*
1184       * Enable the SmartDMA receive task.
1185       */
1186      mcdma_rc = MCD_startDma
1187        (sc->rxDmaChan, /* the channel on which to run the DMA */
1188         (void *)sc->rxBd, /* the address to move data from, or buffer-descriptor addr */
1189         0,             /* the amount to increment the source address per transfer */
1190         (void *)&MCF548X_FEC_FECRFDR(chan), /* the address to move data to */
1191         0,             /* the amount to increment the destination address per transfer */
1192         ETHER_MAX_LEN, /* the number of bytes to transfer independent of the transfer size */
1193         0,             /* the number bytes in of each data movement (1, 2, or 4) */
1194         MCF548X_FEC_RX_INITIATOR(chan), /* what device initiates the DMA */
1195         2,  /* priority of the DMA */
1196         0 /* flags describing the DMA */
1197         | MCD_FECRX_DMA
1198         | MCD_INTERRUPT
1199         | MCD_TT_FLAGS_CW
1200         | MCD_TT_FLAGS_RL
1201         | MCD_TT_FLAGS_SP
1202         ,
1203         0 /* a description of byte swapping, bit swapping, and CRC actions */
1204         | MCD_NO_CSUM
1205         | MCD_NO_BYTE_SWAP
1206         );
1207      if (mcdma_rc != MCD_OK) {
1208        rtems_panic("FEC: cannot start rx DMA");
1209      }
1210      mcdma_rc = MCD_startDma
1211        (sc->txDmaChan, /* the channel on which to run the DMA */
1212         (void *)sc->txBd, /* the address to move data from, or buffer-descriptor addr */
1213         0,             /* the amount to increment the source address per transfer */
1214         (void *)&MCF548X_FEC_FECTFDR(chan), /* the address to move data to */
1215         0,             /* the amount to increment the destination address per transfer */
1216         ETHER_MAX_LEN, /* the number of bytes to transfer independent of the transfer size */
1217         0,             /* the number bytes in of each data movement (1, 2, or 4) */
1218         MCF548X_FEC_TX_INITIATOR(chan), /* what device initiates the DMA */
1219         1,  /* priority of the DMA */
1220         0 /* flags describing the DMA */
1221         | MCD_FECTX_DMA
1222         | MCD_INTERRUPT
1223         | MCD_TT_FLAGS_CW
1224         | MCD_TT_FLAGS_RL
1225         | MCD_TT_FLAGS_SP
1226         ,
1227         0 /* a description of byte swapping, bit swapping, and CRC actions */
1228         | MCD_NO_CSUM
1229         | MCD_NO_BYTE_SWAP
1230         );
1231      if (mcdma_rc != MCD_OK) {
1232        rtems_panic("FEC: cannot start tx DMA");
1233      }
1234}
1235/*
1236 * Initialize and start the device
1237 */
1238static void mcf548x_fec_init(void *arg)
1239{
1240  struct mcf548x_enet_struct *sc = (struct mcf548x_enet_struct *)arg;
1241  struct ifnet *ifp = &sc->arpcom.ac_if;
1242  int chan = sc->chan;
1243  rtems_isr_entry old_handler;
1244  char *txTaskName = "FTx0";
1245  char *rxTaskName = "FRx0";
1246  if(sc->txDaemonTid == 0)
1247    {
1248      /*
1249       * Allocate a set of BDs
1250       */
1251      sc->rxBd =  SRAM_RXBD_BASE(_SysSramBase,chan);
1252      sc->txBd =  SRAM_TXBD_BASE(_SysSramBase,chan);
1253
1254      if(!sc->rxBd || !sc->txBd)
1255        rtems_panic ("No memory for BDs");
1256      /*
1257       * clear the BDs
1258       */
1259      memset((void *)sc->rxBd,0,sc->rxBdCount * sizeof *(sc->rxBd));
1260      memset((void *)sc->txBd,0,sc->txBdCount * sizeof *(sc->txBd));
1261      /*
1262       * Allocate a set of mbuf pointers
1263       */
1264      sc->rxMbuf =
1265        malloc(sc->rxBdCount * sizeof *sc->rxMbuf, M_MBUF, M_NOWAIT);
1266      sc->txMbuf =
1267        malloc(sc->txBdCount * sizeof *sc->txMbuf, M_MBUF, M_NOWAIT);
1268
1269      if(!sc->rxMbuf || !sc->txMbuf)
1270        rtems_panic ("No memory for mbuf pointers");
1271
1272      sc->txDmaChan = MCDMA_FEC_TX_CHAN(chan);
1273      sc->rxDmaChan = MCDMA_FEC_RX_CHAN(chan);
1274
1275      mcdma_glue_init(SRAM_DMA_BASE(_SysSramBase));
1276
1277      /*
1278       * Set up interrupts
1279       */
1280      mcdma_glue_irq_install(sc->rxDmaChan,
1281                             mcf548x_mcdma_rx_irq_handler,
1282                             sc);
1283      mcdma_glue_irq_install(sc->txDmaChan,
1284                             mcf548x_mcdma_tx_irq_handler,
1285                             sc);
1286      if(rtems_interrupt_catch(mcf548x_fec_irq_handler,
1287                               MCF548X_FEC_IRQ_VECTOR(chan),
1288                               &old_handler)) {
1289        rtems_panic ("Can't attach MFC54xx FEX interrupt handler\n");
1290      }
1291
1292      MCF548X_INTC_ICRn(MCF548X_FEC_IRQ_VECTOR(chan) % 64) =
1293        MCF548X_INTC_ICRn_IL(FEC_IRQ_LEVEL) |
1294        MCF548X_INTC_ICRn_IP(FEC_IRQ_PRIORITY);
1295
1296      MCF548X_INTC_IMRH &= ~(1 << (MCF548X_FEC_IRQ_VECTOR(chan) % 32));
1297
1298      MCF548X_FEC_EIMR(chan) = FEC_INTR_MASK_USED;
1299      mcf548x_fec_rx_bd_init(sc);
1300
1301      /*
1302       * reset and Set up mcf548x FEC hardware
1303       */
1304      mcf548x_fec_initialize_hardware(sc);
1305
1306      /*
1307       * Start driver tasks
1308       */
1309      txTaskName[3] = '0'+chan;
1310      rxTaskName[3] = '0'+chan;
1311      sc->txDaemonTid = rtems_bsdnet_newproc(txTaskName, 4096,
1312                                             mcf548x_fec_txDaemon, sc);
1313      sc->rxDaemonTid = rtems_bsdnet_newproc(rxTaskName, 4096,
1314                                             mcf548x_fec_rxDaemon, sc);
1315      /*
1316       * Clear SmartDMA task interrupt pending bits.
1317       */
1318      MCDMA_CLR_PENDING(sc->rxDmaChan );
1319      MCDMA_CLR_PENDING(sc->txDmaChan );
1320
1321      /*
1322       * start the DMA channels
1323       */
1324      mcf548x_fec_startDMA(sc);
1325      /*
1326       * Enable FEC-Lite controller
1327       */
1328      MCF548X_FEC_ECR(chan) |= MCF548X_FEC_ECR_ETHER_EN;
1329
1330
1331    }
1332
1333  /*
1334   * Set flags appropriately
1335   */
1336  if(ifp->if_flags & IFF_PROMISC)
1337    MCF548X_FEC_RCR(chan) |=  MCF548X_FEC_RCR_PROM;
1338  else
1339    MCF548X_FEC_RCR(chan) &= ~MCF548X_FEC_RCR_PROM;
1340
1341  /*
1342   * init timer so the "watchdog function gets called periodically
1343   */
1344  ifp->if_timer    = 1;
1345  /*
1346   * Tell the world that we're running.
1347   */
1348  ifp->if_flags |= IFF_RUNNING;
1349}
1350
1351
1352static void enet_stats (struct mcf548x_enet_struct *sc)
1353{
1354  printf ("      Rx Interrupts:%-8lu", sc->rxInterrupts);
1355  printf ("       Not First:%-8lu", sc->rxNotFirst);
1356  printf ("        Not Last:%-8lu\n", sc->rxNotLast);
1357  printf ("              Giant:%-8lu", sc->rxGiant);
1358  printf ("       Non-octet:%-8lu\n", sc->rxNonOctet);
1359  printf ("            Bad CRC:%-8lu", sc->rxBadCRC);
1360  printf ("         Overrun:%-8lu", sc->rxOverrun);
1361  printf ("       Collision:%-8lu\n", sc->rxCollision);
1362
1363  printf ("      Tx Interrupts:%-8lu", sc->txInterrupts);
1364  printf ("        Deferred:%-8lu", sc->txDeferred);
1365  printf ("  Late Collision:%-8lu\n", sc->txLateCollision);
1366  printf ("   Retransmit Limit:%-8lu", sc->txRetryLimit);
1367  printf ("        Underrun:%-8lu", sc->txUnderrun);
1368  printf ("      Misaligned:%-8lu\n", sc->txMisaligned);
1369
1370}
1371
1372/*
1373 * restart the driver, reinit the fec
1374 * this function is responsible to reinitialize the FEC in case a fatal
1375 * error has ocurred. This is needed, wen a RxFIFO Overrun or a TxFIFO underrun
1376 * has ocurred. In these cases, the FEC is automatically disabled, and
1377 * both FIFOs must be reset and the BestComm tasks must be restarted
1378 *
1379 * Note: the daemon tasks will continue to run
1380 * (in fact this function will be called in the context of the rx daemon task)
1381 */
1382#define NEW_DMA_SETUP
1383
1384static void mcf548x_fec_restart(struct mcf548x_enet_struct *sc)
1385{
1386  int chan = sc->chan;
1387  /*
1388   * FIXME: bring Tx Daemon into idle state
1389   */
1390#ifdef NEW_DMA_SETUP
1391  /*
1392   * cleanup remaining receive mbufs
1393   */
1394  mcf548x_fec_rx_bd_cleanup(sc);
1395#endif
1396  /*
1397   * Stop DMA tasks
1398   */
1399  MCD_killDma (sc->rxDmaChan);
1400  MCD_killDma (sc->txDmaChan);
1401  /*
1402   * FIXME: wait, until Tx Daemon is in idle state
1403   */
1404
1405  /*
1406   * Disable transmit / receive interrupts
1407   */
1408  mcdma_glue_irq_disable(sc->txDmaChan);
1409  mcdma_glue_irq_disable(sc->rxDmaChan);
1410#ifdef NEW_DMA_SETUP
1411  /*
1412   * recycle pending tx buffers
1413   * FIXME: try to extract pending Tx buffers
1414   */
1415  mcf548x_fec_retire_tbd(sc,true);
1416#endif
1417  /*
1418   * re-initialize the FEC hardware
1419   */
1420  mcf548x_fec_initialize_hardware(sc);
1421
1422#ifdef NEW_DMA_SETUP
1423
1424  /*
1425   * reinit receive mbufs
1426   */
1427  mcf548x_fec_rx_bd_init(sc);
1428#endif
1429  /*
1430   * Clear SmartDMA task interrupt pending bits.
1431   */
1432  MCDMA_CLR_PENDING( sc->rxDmaChan );
1433
1434  /*
1435   * start the DMA channels again
1436   */
1437  mcf548x_fec_startDMA(sc);
1438  /*
1439   * reenable rx/tx interrupts
1440   */
1441  mcdma_glue_irq_enable(sc->rxDmaChan);
1442  mcdma_glue_irq_enable(sc->txDmaChan);
1443  /*
1444   * (re-)init fec hardware
1445   */
1446  mcf548x_fec_initialize_hardware(sc);
1447  /*
1448   * reenable fec FIFO error interrupts
1449   */
1450  MCF548X_FEC_EIMR(chan) = FEC_INTR_MASK_USED;
1451  /*
1452   * Enable FEC-Lite controller
1453   */
1454  MCF548X_FEC_ECR(chan) |= MCF548X_FEC_ECR_ETHER_EN;
1455}
1456
1457int32_t mcf548x_fec_setMultiFilter(struct ifnet *ifp)
1458{
1459  /*struct mcf548x_enet_struct *sc = ifp->if_softc; */
1460  /* XXX anything to do? */
1461  return 0;
1462}
1463
1464
1465/*
1466 * Driver ioctl handler
1467 */
1468static int mcf548x_fec_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data)
1469  {
1470  struct mcf548x_enet_struct *sc = ifp->if_softc;
1471  int error = 0;
1472
1473  switch(command)
1474    {
1475
1476    case SIOCGIFMEDIA:
1477    case SIOCSIFMEDIA:
1478      rtems_mii_ioctl (&(sc->mdio_info),sc,command,(void *)data);
1479      break;
1480
1481    case SIOCGIFADDR:
1482    case SIOCSIFADDR:
1483
1484      ether_ioctl(ifp, command, data);
1485
1486      break;
1487
1488    case SIOCADDMULTI:
1489    case SIOCDELMULTI: {
1490      struct ifreq* ifr = (struct ifreq*) data;
1491      error = (command == SIOCADDMULTI)
1492                  ? ether_addmulti(ifr, &sc->arpcom)
1493                  : ether_delmulti(ifr, &sc->arpcom);
1494
1495       if (error == ENETRESET) {
1496         if (ifp->if_flags & IFF_RUNNING)
1497           error = mcf548x_fec_setMultiFilter(ifp);
1498         else
1499           error = 0;
1500       }
1501       break;
1502    }
1503
1504    case SIOCSIFFLAGS:
1505
1506      switch(ifp->if_flags & (IFF_UP | IFF_RUNNING))
1507        {
1508
1509        case IFF_RUNNING:
1510
1511          mcf548x_fec_off(sc);
1512
1513          break;
1514
1515        case IFF_UP:
1516
1517          mcf548x_fec_init(sc);
1518
1519          break;
1520
1521        case IFF_UP | IFF_RUNNING:
1522
1523          mcf548x_fec_off(sc);
1524          mcf548x_fec_init(sc);
1525
1526          break;
1527
1528        default:
1529          break;
1530
1531        }
1532
1533      break;
1534
1535    case SIO_RTEMS_SHOW_STATS:
1536
1537      enet_stats(sc);
1538
1539      break;
1540
1541   /*
1542    * FIXME: All sorts of multicast commands need to be added here!
1543    */
1544    default:
1545
1546    error = EINVAL;
1547
1548    break;
1549
1550    }
1551
1552  return error;
1553
1554  }
1555
1556
1557/*
1558 * init the PHY and adapt FEC settings
1559 */
1560int mcf548x_fec_mode_adapt(struct ifnet *ifp)
1561{
1562  int result = 0;
1563  struct mcf548x_enet_struct *sc = ifp->if_softc;
1564  int media = IFM_MAKEWORD( 0, 0, 0, sc->phy_default);
1565  int chan = sc->chan;
1566
1567  /*
1568   * fetch media status
1569   */
1570  result = mcf548x_fec_ioctl(ifp,SIOCGIFMEDIA,(caddr_t)&media);
1571  if (result != 0) {
1572    return result;
1573  }
1574  /*
1575   * status is unchanged? then do nothing
1576   */
1577  if (media == sc->media_state) {
1578    return 0;
1579  }
1580  /*
1581   * otherwise: for the first call, try to negotiate mode
1582   */
1583  if (sc->media_state == 0) {
1584    /*
1585     * set media status: set auto negotiation -> start auto-negotiation
1586     */
1587    media = IFM_MAKEWORD(0,IFM_AUTO,0,sc->phy_default);
1588    result = mcf548x_fec_ioctl(ifp,SIOCSIFMEDIA,(caddr_t)&media);
1589    if (result != 0) {
1590      return result;
1591    }
1592    /*
1593     * wait for auto-negotiation to terminate
1594     */
1595    do {
1596      media = IFM_MAKEWORD(0,0,0,sc->phy_default);
1597      result = mcf548x_fec_ioctl(ifp,SIOCGIFMEDIA,(caddr_t)&media);
1598      if (result != 0) {
1599        return result;
1600      }
1601    } while (IFM_NONE == IFM_SUBTYPE(media));
1602  }
1603
1604  /*
1605   * now set HW according to media results:
1606   */
1607
1608  /*
1609   * if we are half duplex then switch to half duplex
1610   */
1611  if (0 == (IFM_FDX & IFM_OPTIONS(media))) {
1612    MCF548X_FEC_TCR(chan) &= ~MCF548X_FEC_TCR_FDEN;
1613  }
1614  else {
1615    MCF548X_FEC_TCR(chan) |=  MCF548X_FEC_TCR_FDEN;
1616  }
1617  /*
1618   * store current media state for future compares
1619   */
1620  sc->media_state = media;
1621
1622  return 0;
1623}
1624
1625/*
1626 * periodically poll the PHY. if mode has changed,
1627 * then adjust the FEC settings
1628 */
1629static void mcf548x_fec_watchdog( struct ifnet *ifp)
1630{
1631  mcf548x_fec_mode_adapt(ifp);
1632  ifp->if_timer    = FEC_WATCHDOG_TIMEOUT;
1633}
1634
1635/*
1636 * Attach the MCF548X fec driver to the system
1637 */
1638int rtems_mcf548x_fec_driver_attach(struct rtems_bsdnet_ifconfig *config)
1639  {
1640  struct mcf548x_enet_struct *sc;
1641  struct ifnet *ifp;
1642  int    mtu;
1643  int    unitNumber;
1644  char   *unitName;
1645
1646 /*
1647  * Parse driver name
1648  */
1649  if((unitNumber = rtems_bsdnet_parse_driver_name(config, &unitName)) < 0)
1650    return 0;
1651
1652 /*
1653  * Is driver free?
1654  */
1655  if ((unitNumber <= 0) || (unitNumber > NIFACES))
1656    {
1657
1658    printf ("Bad FEC unit number.\n");
1659    return 0;
1660
1661    }
1662
1663  sc = &enet_driver[unitNumber - 1];
1664  sc->chan = unitNumber-1;
1665  ifp = &sc->arpcom.ac_if;
1666
1667  if(ifp->if_softc != NULL)
1668    {
1669
1670    printf ("Driver already in use.\n");
1671    return 0;
1672
1673    }
1674
1675  /*
1676   * Process options
1677   */
1678#if NVRAM_CONFIGURE == 1
1679
1680  /* Configure from NVRAM */
1681  if(addr = nvram->ipaddr)
1682    {
1683
1684    /* We have a non-zero entry, copy the value */
1685    if(pAddr = malloc(INET_ADDR_MAX_BUF_SIZE, 0, M_NOWAIT))
1686      config->ip_address = (char *)inet_ntop(AF_INET, &addr, pAddr, INET_ADDR_MAX_BUF_SIZE -1);
1687    else
1688      rtems_panic("Can't allocate ip_address buffer!\n");
1689
1690    }
1691
1692  if(addr = nvram->netmask)
1693    {
1694
1695    /* We have a non-zero entry, copy the value */
1696    if (pAddr = malloc (INET_ADDR_MAX_BUF_SIZE, 0, M_NOWAIT))
1697      config->ip_netmask = (char *)inet_ntop(AF_INET, &addr, pAddr, INET_ADDR_MAX_BUF_SIZE -1);
1698    else
1699      rtems_panic("Can't allocate ip_netmask buffer!\n");
1700
1701    }
1702
1703  /* Ethernet address requires special handling -- it must be copied into
1704   * the arpcom struct. The following if construct serves only to give the
1705   * User Area NVRAM parameter the highest priority.
1706   *
1707   * If the ethernet address is specified in NVRAM, go ahead and copy it.
1708   * (ETHER_ADDR_LEN = 6 bytes).
1709   */
1710  if(nvram->enaddr[0] || nvram->enaddr[1] || nvram->enaddr[2])
1711    {
1712
1713    /* Anything in the first three bytes indicates a non-zero entry, copy value */
1714        memcpy((void *)sc->arpcom.ac_enaddr, &nvram->enaddr, ETHER_ADDR_LEN);
1715
1716    }
1717  else
1718    if(config->hardware_address)
1719      {
1720
1721      /* There is no entry in NVRAM, but there is in the ifconfig struct, so use it. */
1722      memcpy((void *)sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
1723      }
1724
1725#else /* NVRAM_CONFIGURE != 1 */
1726
1727  if(config->hardware_address)
1728    {
1729
1730    memcpy(sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
1731
1732    }
1733
1734#endif /* NVRAM_CONFIGURE != 1 */
1735#ifdef HAS_UBOOT
1736  if ((sc->arpcom.ac_enaddr[0] == 0) &&
1737      (sc->arpcom.ac_enaddr[1] == 0) &&
1738      (sc->arpcom.ac_enaddr[2] == 0)) {
1739      memcpy(
1740        (void *)sc->arpcom.ac_enaddr,
1741        bsp_uboot_board_info.bi_enetaddr,
1742        ETHER_ADDR_LEN
1743      );
1744  }
1745#endif
1746#ifdef HAS_DBUG
1747  if ((sc->arpcom.ac_enaddr[0] == 0) &&
1748      (sc->arpcom.ac_enaddr[1] == 0) &&
1749      (sc->arpcom.ac_enaddr[2] == 0)) {
1750      memcpy(
1751        (void *)sc->arpcom.ac_enaddr,
1752        DBUG_SETTINGS.macaddr,
1753        ETHER_ADDR_LEN
1754      );
1755  }
1756#endif
1757  if ((sc->arpcom.ac_enaddr[0] == 0) &&
1758      (sc->arpcom.ac_enaddr[1] == 0) &&
1759      (sc->arpcom.ac_enaddr[2] == 0)) {
1760    /* There is no ethernet address provided, so it could be read
1761     * from the Ethernet protocol block of SCC1 in DPRAM.
1762     */
1763    rtems_panic("No Ethernet address specified!\n");
1764  }
1765  if(config->mtu)
1766    mtu = config->mtu;
1767  else
1768    mtu = ETHERMTU;
1769
1770  if(config->rbuf_count)
1771    sc->rxBdCount = config->rbuf_count;
1772  else
1773    sc->rxBdCount = RX_BUF_COUNT;
1774
1775  if(config->xbuf_count)
1776    sc->txBdCount = config->xbuf_count;
1777  else
1778    sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF;
1779
1780  sc->acceptBroadcast = !config->ignore_broadcast;
1781
1782  /*
1783   * setup info about mdio interface
1784   */
1785  sc->mdio_info.mdio_r   = mcf548x_eth_mii_read;
1786  sc->mdio_info.mdio_w   = mcf548x_eth_mii_write;
1787  sc->mdio_info.has_gmii = 0; /* we do not support gigabit IF */
1788
1789  /*
1790   * XXX: Although most hardware builders will assign the PHY addresses
1791   * like this, this should be more configurable
1792   */
1793  sc->phy_default = unitNumber-1;
1794  sc->phy_chan    = 0; /* assume all MII accesses are via FEC0 */
1795
1796 /*
1797  * Set up network interface values
1798  */
1799  ifp->if_softc   = sc;
1800  ifp->if_unit    = unitNumber;
1801  ifp->if_name    = unitName;
1802  ifp->if_mtu     = mtu;
1803  ifp->if_init    = mcf548x_fec_init;
1804  ifp->if_ioctl   = mcf548x_fec_ioctl;
1805  ifp->if_start   = mcf548x_fec_tx_start;
1806  ifp->if_output  = ether_output;
1807  ifp->if_watchdog =  mcf548x_fec_watchdog; /* XXX: timer is set in "init" */
1808  ifp->if_flags   = IFF_BROADCAST | IFF_MULTICAST;
1809  /*ifp->if_flags   = IFF_BROADCAST | IFF_SIMPLEX;*/
1810
1811  if(ifp->if_snd.ifq_maxlen == 0)
1812    ifp->if_snd.ifq_maxlen = ifqmaxlen;
1813
1814  /*
1815   * Attach the interface
1816   */
1817  if_attach(ifp);
1818
1819  ether_ifattach(ifp);
1820
1821  return 1;
1822  }
1823
1824
1825int rtems_mcf548x_fec_driver_attach_detach(struct rtems_bsdnet_ifconfig *config, int attaching)
1826{
1827  if (attaching) {
1828    return rtems_mcf548x_fec_driver_attach(config);
1829  }
1830  else {
1831    return 0;
1832  }
1833}
1834
1835
Note: See TracBrowser for help on using the repository browser.