Ignore:
Timestamp:
Oct 15, 2009, 2:05:34 PM (11 years ago)
Author:
Thomas Doerfler <Thomas.Doerfler@…>
Branches:
4.10, 4.11, 5, master
Children:
6504558
Parents:
6229b2a7
Message:

add network support, various corrections

File:
1 edited

Legend:

Unmodified
Added
Removed
  • c/src/lib/libbsp/m68k/genmcf548x/network/network.c

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