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

4.11
Last change on this file since 26e90fb1 was 26e90fb1, checked in by Sebastian Huber <sebastian.huber@…>, on Oct 30, 2012 at 4:42:17 PM

libnetworking: Use system events

Add reserved system events RTEMS_EVENT_SYSTEM_NETWORK_SBWAIT and
RTEMS_EVENT_SYSTEM_NETWORK_SOSLEEP.

Add and use rtems_bsdnet_event_send().

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