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

4.115
Last change on this file since 6eb1733 was 6eb1733, checked in by Sebastian Huber <sebastian.huber@…>, on 12/06/13 at 07:37:11

bsp/genmcf548x: Use bsp_interrupt_vector_enable()

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