summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/powerpc/gen5200/network_5200/network.c
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/lib/libbsp/powerpc/gen5200/network_5200/network.c')
-rw-r--r--c/src/lib/libbsp/powerpc/gen5200/network_5200/network.c1547
1 files changed, 648 insertions, 899 deletions
diff --git a/c/src/lib/libbsp/powerpc/gen5200/network_5200/network.c b/c/src/lib/libbsp/powerpc/gen5200/network_5200/network.c
index 61dcea40a2..060167adda 100644
--- a/c/src/lib/libbsp/powerpc/gen5200/network_5200/network.c
+++ b/c/src/lib/libbsp/powerpc/gen5200/network_5200/network.c
@@ -53,10 +53,16 @@
* Copyright (c) 1999, National Research Council of Canada
*
*/
+
+#define __INSIDE_RTEMS_BSD_TCPIP_STACK__ 1
+#define __BSD_VISIBLE 1
+
#include <rtems.h>
#include <rtems/error.h>
#include <rtems/rtems_bsdnet.h>
+#include <rtems/rtems_mii_ioctl.h>
#include <stdio.h>
+#include <inttypes.h>
#include <sys/param.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
@@ -66,43 +72,23 @@
#include <netinet/if_ether.h>
#include <bsp.h>
#include <bsp/irq.h>
-#include "../include/mpc5200.h"
+#include <bsp/mpc5200.h>
#include <net/if_var.h>
#include <errno.h>
-/* motorola-capi-specifics... */
-#include "../bestcomm/include/ppctypes.h" /* uint32, et. al. */
-#include "../bestcomm/dma_image.h"
-#include "../bestcomm/bestcomm_glue.h"
-
-
-#define SDMA_BD_TFD 0x08000000 /*< Transmit Frame Done */
-#define SDMA_BD_INT 0x04000000 /*< Interrupt on frame done */
-#define SDMA_BD_RX_NUM 64 /* Number of receive buffer descriptors */
-#define SDMA_BD_TX_NUM 64 /* Number of transmit buffer descriptors */
-
-#define SET_BD_STATUS(bd, stat) { \
- (bd)->Status &= 0x0000ffff; \
- (bd)->Status |= 0xffff0000 & stat; \
-}
-#define SET_BD_LENGTH(bd, len) { \
- (bd)->Status &= 0xffff0000; \
- (bd)->Status |= 0x0000ffff & len; \
-}
-#define GET_BD_STATUS(bd) ((bd)->Status & 0xffff0000)
-#define GET_BD_LENGTH(bd) ((bd)->Status & 0x0000ffff)
-#define GET_SDMA_PENDINGBIT(Bit) \
- (mpc5200.sdma.IntPend & (uint32)(1<<Bit))
-
-#include "../bestcomm/bestcomm_api.h"
-#include "../bestcomm/task_api/bestcomm_cntrl.h"
-#include "../bestcomm/task_api/tasksetup_bdtable.h"
-
-static TaskId rxTaskId; /* SDMA RX task ID */
-static TaskId txTaskId; /* SDMA TX task ID */
+#include <bsp/bestcomm/include/ppctypes.h>
+#include <bsp/bestcomm/dma_image.h>
+#include <bsp/bestcomm/bestcomm_glue.h>
+#include <bsp/bestcomm/bestcomm_api.h>
+#include <bsp/bestcomm/task_api/bestcomm_cntrl.h>
+#include <bsp/bestcomm/task_api/tasksetup_bdtable.h>
/* #define ETH_DEBUG */
+#define FEC_BD_LAST TASK_BD_TFD
+#define FEC_BD_INT TASK_BD_INT
+#define FEC_BD_READY SDMA_BD_MASK_READY
+
/*
* Number of interfaces supported by this driver
*/
@@ -113,25 +99,12 @@ static TaskId txTaskId; /* SDMA TX task ID */
* The number of transmit buffer descriptors has to be quite large
* since a single frame often uses four or more buffer descriptors.
*/
-#define RX_BUF_COUNT SDMA_BD_RX_NUM
-#define TX_BUF_COUNT SDMA_BD_TX_NUM
-#define TX_BD_PER_BUF 1
+#define RX_BUF_COUNT 64
+#define TX_BUF_COUNT 64
#define INET_ADDR_MAX_BUF_SIZE (sizeof "255.255.255.255")
-
-/*
- * RTEMS event used by interrupt handler to signal daemons.
- * This must *not* be the same event used by the TCP/IP task synchronization.
- */
-#define INTERRUPT_EVENT RTEMS_EVENT_1
-#define FATAL_INT_EVENT RTEMS_EVENT_3
-
-/*
- * RTEMS event used to start transmit daemon.
- * This must not be the same as INTERRUPT_EVENT.
- */
-#define START_TRANSMIT_EVENT RTEMS_EVENT_2
+#define FEC_EVENT RTEMS_EVENT_0
/* Task number assignment */
#define FEC_RECV_TASK_NO TASK_FEC_RX
@@ -186,31 +159,24 @@ static TaskId txTaskId; /* SDMA TX task ID */
#define MPC5200_FEC_MII_DATA_RA_SHIFT 0x12 /* MII Register address bits */
#define MPC5200_FEC_MII_DATA_PA_SHIFT 0x17 /* MII PHY address bits */
-
-/* Receive & Transmit Buffer Descriptor definitions */
-typedef struct mpc5200_buffer_desc_
- {
- volatile uint16_t status;
- volatile uint16_t length;
- volatile void *buffer;
- } mpc5200_buffer_desc_t;
-
-
#define FEC_INTR_MASK_USED \
(FEC_INTR_LCEN |FEC_INTR_CRLEN |\
FEC_INTR_XFUNEN|FEC_INTR_XFERREN|FEC_INTR_RFERREN)
+typedef enum {
+ FEC_STATE_RESTART_0,
+ FEC_STATE_RESTART_1,
+ FEC_STATE_NORMAL,
+} mpc5200_fec_state;
+
/*
* Device data
*/
-struct mpc5200_enet_struct {
-#if 0
- struct ifnet ac_if;
-#else
+typedef struct {
struct arpcom arpcom;
-#endif
struct mbuf **rxMbuf;
struct mbuf **txMbuf;
+ mpc5200_fec_state state;
int acceptBroadcast;
int rxBdCount;
int txBdCount;
@@ -226,83 +192,60 @@ struct mpc5200_enet_struct {
unsigned long rxGiant;
unsigned long rxNonOctet;
unsigned long rxBadCRC;
- unsigned long rxOverrun;
+ unsigned long rxFIFOError;
unsigned long rxCollision;
unsigned long txInterrupts;
unsigned long txDeferred;
unsigned long txLateCollision;
unsigned long txUnderrun;
+ unsigned long txFIFOError;
unsigned long txMisaligned;
unsigned long rxNotFirst;
unsigned long txRetryLimit;
- };
-static struct mpc5200_enet_struct enet_driver[NIFACES];
+ struct rtems_mdio_info mdio;
+ int phyAddr;
+ bool phyInitialized;
+} mpc5200_fec_context;
-extern int taskTable;
-static void mpc5200_fec_restart(struct mpc5200_enet_struct *sc);
+static mpc5200_fec_context enet_driver[NIFACES];
+static void mpc5200_fec_send_event(rtems_id task)
+{
+ rtems_event_send(task, FEC_EVENT);
+}
+static void mpc5200_fec_wait_for_event(void)
+{
+ rtems_event_set out;
+ rtems_bsdnet_event_receive(
+ FEC_EVENT,
+ RTEMS_EVENT_ANY | RTEMS_WAIT,
+ RTEMS_NO_TIMEOUT,
+ &out
+ );
+}
-/*
- * Function: mpc5200_fec_rx_bd_init
- *
- * Description: Initialize the receive buffer descriptor ring.
- *
- * Returns: void
- *
- * Notes: Space for the buffers of rx BDs is allocated by the rx deamon
- *
- */
-static void mpc5200_fec_rx_bd_init(struct mpc5200_enet_struct *sc) {
- int rxBdIndex;
- struct mbuf *m;
- struct ifnet *ifp = &sc->arpcom.ac_if;
- BDIdx bdi;
+static void mpc5200_fec_stop_dma(void)
+{
+ TaskStop(FEC_RECV_TASK_NO);
+ TaskStop(FEC_XMIT_TASK_NO);
+}
- /*
- * Fill RX buffer descriptor ring.
- */
- for( rxBdIndex = 0; rxBdIndex < sc->rxBdCount; rxBdIndex++ ) {
- MGETHDR (m, M_WAIT, MT_DATA);
- MCLGET (m, M_WAIT);
-
- m->m_pkthdr.rcvif = ifp;
- sc->rxMbuf[rxBdIndex] = m;
- bdi = TaskBDAssign( rxTaskId,
- mtod(m, void *),
- NULL,
- ETHER_MAX_LEN,
- 0 );
- if (bdi != rxBdIndex) {
- rtems_panic("network rx buffer indices out of sync");
- }
- }
+static void mpc5200_fec_request_restart(mpc5200_fec_context *self)
+{
+ self->state = FEC_STATE_RESTART_0;
+ mpc5200_fec_send_event(self->txDaemonTid);
+ mpc5200_fec_send_event(self->rxDaemonTid);
}
-/*
- * Function: mpc5200_fec_rx_bd_cleanup
- *
- * Description: put all mbufs pending in rx BDs back to buffer pool
- *
- * Returns: void
- *
- */
-static void mpc5200_fec_rx_bd_cleanup(struct mpc5200_enet_struct *sc) {
- int rxBdIndex;
- struct mbuf *m,*n;
+static void mpc5200_fec_start_dma_and_controller(void)
+{
+ TaskStart(FEC_RECV_TASK_NO, 1, FEC_RECV_TASK_NO, 1);
+ TaskStart(FEC_XMIT_TASK_NO, 1, FEC_XMIT_TASK_NO, 1);
- /*
- * Drain RX buffer descriptor ring.
- */
- for( rxBdIndex = 0; rxBdIndex < sc->rxBdCount; rxBdIndex++ ) {
- n = sc->rxMbuf[rxBdIndex];
- while (n != NULL) {
- m = n;
- MFREE(m,n);
- }
- }
+ mpc5200.ecntrl |= FEC_ECNTRL_OE | FEC_ECNTRL_EN;
}
/*
@@ -316,7 +259,7 @@ static void mpc5200_fec_rx_bd_cleanup(struct mpc5200_enet_struct *sc) {
* Notes:
*
*/
-static void mpc5200_eth_addr_filter_set(struct mpc5200_enet_struct *sc) {
+static void mpc5200_eth_addr_filter_set(mpc5200_fec_context *self) {
unsigned char *mac;
unsigned char currByte; /* byte for which to compute the CRC */
int byte; /* loop - counter */
@@ -326,7 +269,7 @@ static void mpc5200_eth_addr_filter_set(struct mpc5200_enet_struct *sc) {
/*
* Get the mac address of ethernet controller
*/
- mac = (unsigned char *)(&sc->arpcom.ac_enaddr);
+ mac = (unsigned char *)(&self->arpcom.ac_enaddr);
/*
* The algorithm used is the following:
@@ -399,125 +342,68 @@ static void mpc5200_eth_addr_filter_set(struct mpc5200_enet_struct *sc) {
}
-
-/*
- * Function: mpc5200_eth_mii_read
- *
- * Description: Read a media independent interface (MII) register on an
- * 18-wire ethernet tranceiver (PHY). Please see your PHY
- * documentation for the register map.
- *
- * Returns: 32-bit register value
- *
- * Notes:
- *
- */
-int mpc5200_eth_mii_read(struct mpc5200_enet_struct *sc, unsigned char phyAddr, unsigned char regAddr, unsigned short * retVal)
- {
- unsigned long reg; /* convenient holder for the PHY register */
- unsigned long phy; /* convenient holder for the PHY */
+static int mpc5200_eth_mii_transfer(
+ int phyAddr,
+ unsigned regAddr,
+ uint32_t data
+)
+{
int timeout = 0xffff;
- /*
- * reading from any PHY's register is done by properly
- * programming the FEC's MII data register.
- */
- reg = regAddr << MPC5200_FEC_MII_DATA_RA_SHIFT;
- phy = phyAddr << MPC5200_FEC_MII_DATA_PA_SHIFT;
-
- mpc5200.mii_data = (MPC5200_FEC_MII_DATA_ST | MPC5200_FEC_MII_DATA_OP_RD | MPC5200_FEC_MII_DATA_TA | phy | reg);
-
- /*
- * wait for the related interrupt
- */
- while ((timeout--) && (!(mpc5200.ievent & 0x00800000)));
-
- if(timeout == 0)
- {
-
-#ifdef ETH_DEBUG
- printf ("Read MDIO failed..." "\r\n");
-#endif
-
- return false;
-
- }
-
- /*
- * clear mii interrupt bit
- */
- mpc5200.ievent = 0x00800000;
-
- /*
- * it's now safe to read the PHY's register
- */
- *retVal = (unsigned short)mpc5200.mii_data;
+ mpc5200.ievent = FEC_INTR_MII;
- return true;
+ mpc5200.mii_data = MPC5200_FEC_MII_DATA_ST
+ | MPC5200_FEC_MII_DATA_TA
+ | (phyAddr << MPC5200_FEC_MII_DATA_PA_SHIFT)
+ | (regAddr << MPC5200_FEC_MII_DATA_RA_SHIFT)
+ | data;
+ while (timeout > 0 && (mpc5200.ievent & FEC_INTR_MII) == 0) {
+ --timeout;
}
-/*
- * Function: mpc5200_eth_mii_write
- *
- * Description: Write a media independent interface (MII) register on an
- * 18-wire ethernet tranceiver (PHY). Please see your PHY
- * documentation for the register map.
- *
- * Returns: Success (boolean)
- *
- * Notes:
- *
- */
-static int mpc5200_eth_mii_write(struct mpc5200_enet_struct *sc, unsigned char phyAddr, unsigned char regAddr, unsigned short data)
- {
- unsigned long reg; /* convenient holder for the PHY register */
- unsigned long phy; /* convenient holder for the PHY */
- int timeout = 0xffff;
-
- reg = regAddr << MPC5200_FEC_MII_DATA_RA_SHIFT;
- phy = phyAddr << MPC5200_FEC_MII_DATA_PA_SHIFT;
-
- mpc5200.mii_data = (MPC5200_FEC_MII_DATA_ST | MPC5200_FEC_MII_DATA_OP_WR | MPC5200_FEC_MII_DATA_TA | phy | reg | data);
-
- /*
- * wait for the MII interrupt
- */
- while ((timeout--) && (!(mpc5200.ievent & 0x00800000)));
-
- if(timeout == 0)
- {
-
-#ifdef ETH_DEBUG
- printf ("Write MDIO failed..." "\r\n");
-#endif
-
- return false;
+ return timeout > 0 ? 0 : -1;
+}
- }
+/* FIXME: Make this static, this needs a fix in an application */
+int mpc5200_eth_mii_read(
+ int phyAddr,
+ void *arg,
+ unsigned regAddr,
+ uint32_t *retVal
+)
+{
+ int rv = mpc5200_eth_mii_transfer(
+ phyAddr,
+ regAddr,
+ MPC5200_FEC_MII_DATA_OP_RD
+ );
- /*
- * clear MII interrupt bit
- */
- mpc5200.ievent = 0x00800000;
+ *retVal = mpc5200.mii_data & 0xffff;
- return true;
+ return rv;
+}
- }
+static int mpc5200_eth_mii_write(
+ int phyAddr,
+ void *arg,
+ unsigned regAddr,
+ uint32_t data
+)
+{
+ return mpc5200_eth_mii_transfer(
+ phyAddr,
+ regAddr,
+ MPC5200_FEC_MII_DATA_OP_WR | data
+ );
+}
/*
- * Function: mpc5200_fec_reset
- *
- * Description: Reset a running ethernet driver including the hardware
- * FIFOs and the FEC.
- *
- * Returns: Success (boolean)
- *
- * Notes:
- *
+ * Reset a running ethernet driver including the hardware FIFOs and the FEC.
*/
-static int mpc5200_fec_reset(struct mpc5200_enet_struct *sc) {
+static void mpc5200_fec_reset(mpc5200_fec_context *self)
+{
volatile int delay;
/*
* Clear FIFO status registers
@@ -543,8 +429,6 @@ static int mpc5200_fec_reset(struct mpc5200_enet_struct *sc) {
* wait at least 16 clock cycles
*/
for (delay = 0;delay < 16*4;delay++) {};
-
- return true;
}
@@ -559,28 +443,28 @@ static int mpc5200_fec_reset(struct mpc5200_enet_struct *sc) {
* Notes:
*
*/
-void mpc5200_fec_off(struct mpc5200_enet_struct *sc)
+void mpc5200_fec_off(mpc5200_fec_context *self)
{
int counter = 0xffff;
#if defined(ETH_DEBUG)
- unsigned short phyStatus, i;
- unsigned char phyAddr = 0;
+ uint32_t phyStatus;
+ int i;
for(i = 0; i < 9; i++)
{
- mpc5200_eth_mii_read(sc, phyAddr, i, &phyStatus);
- printf ("Mii reg %d: 0x%04x" "\r\n", i, phyStatus);
+ mpc5200_eth_mii_read(self->phyAddr, self, i, &phyStatus);
+ printf ("Mii reg %d: 0x%04" PRIx32 "\r\n", i, phyStatus);
}
for(i = 16; i < 21; i++)
{
- mpc5200_eth_mii_read(sc, phyAddr, i, &phyStatus);
- printf ("Mii reg %d: 0x%04x" "\r\n", i, phyStatus);
+ mpc5200_eth_mii_read(self->phyAddr, self, i, &phyStatus);
+ printf ("Mii reg %d: 0x%04" PRIx32 "\r\n", i, phyStatus);
}
#endif /* ETH_DEBUG */
@@ -601,11 +485,8 @@ void mpc5200_fec_off(struct mpc5200_enet_struct *sc)
*/
while((counter--) && (!(mpc5200.ievent & FEC_INTR_GRA)));
- /*
- * Disable the SmartDMA transmit and receive tasks.
- */
- TaskStop( rxTaskId );
- TaskStop( txTaskId );
+ mpc5200_fec_stop_dma();
+
/*
* Disable transmit / receive interrupts
*/
@@ -616,20 +497,14 @@ void mpc5200_fec_off(struct mpc5200_enet_struct *sc)
* Disable the Ethernet Controller
*/
mpc5200.ecntrl &= ~(FEC_ECNTRL_OE | FEC_ECNTRL_EN);
-
- /*
- * cleanup all buffers
- */
- mpc5200_fec_rx_bd_cleanup(sc);
-
- }
+}
/*
* MPC5200 FEC interrupt handler
*/
void mpc5200_fec_irq_handler(rtems_irq_hdl_param handle)
{
- struct mpc5200_enet_struct *sc = (struct mpc5200_enet_struct *) handle;
+ mpc5200_fec_context *self = (mpc5200_fec_context *) handle;
volatile uint32_t ievent;
ievent = mpc5200.ievent;
@@ -639,424 +514,55 @@ void mpc5200_fec_irq_handler(rtems_irq_hdl_param handle)
* check errors, update statistics
*/
if (ievent & FEC_INTR_LATE_COL) {
- sc->txLateCollision++;
+ self->txLateCollision++;
}
if (ievent & FEC_INTR_COL_RETRY) {
- sc->txRetryLimit++;
+ self->txRetryLimit++;
}
if (ievent & FEC_INTR_XFIFO_UN) {
- sc->txUnderrun++;
+ self->txUnderrun++;
}
if (ievent & FEC_INTR_XFIFO_ERR) {
- sc->txUnderrun++;
+ self->txFIFOError++;
}
if (ievent & FEC_INTR_RFIFO_ERR) {
- sc->rxOverrun++;
+ self->rxFIFOError++;
}
/*
* fatal error ocurred?
*/
if (ievent & (FEC_INTR_XFIFO_ERR | FEC_INTR_RFIFO_ERR)) {
mpc5200.imask &= ~(FEC_INTR_XFERREN | FEC_INTR_RFERREN);
- rtems_event_send(enet_driver[0].rxDaemonTid, FATAL_INT_EVENT);
+ mpc5200_fec_request_restart(self);
}
}
-/*
- * MPC5200 SmartComm ethernet interrupt handler
- */
-void mpc5200_smartcomm_rx_irq_handler(rtems_irq_hdl_param unused)
- {
- /* Frame received? */
- if(GET_SDMA_PENDINGBIT(FEC_RECV_TASK_NO))
- {
-
- SDMA_CLEAR_IEVENT(&mpc5200.sdma.IntPend,FEC_RECV_TASK_NO);
-
- bestcomm_glue_irq_disable(FEC_RECV_TASK_NO);/*Disable receive ints*/
-
- enet_driver[0].rxInterrupts++; /* Rx int has occurred */
-
- rtems_event_send(enet_driver[0].rxDaemonTid, INTERRUPT_EVENT);
-
- }
- }
-
-/*
- * MPC5200 SmartComm ethernet interrupt handler
- */
-void mpc5200_smartcomm_tx_irq_handler(rtems_irq_hdl_param unused)
- {
- /* Buffer transmitted or transmitter error? */
- if(GET_SDMA_PENDINGBIT(FEC_XMIT_TASK_NO))
- {
-
- SDMA_CLEAR_IEVENT(&mpc5200.sdma.IntPend,FEC_XMIT_TASK_NO);
-
- bestcomm_glue_irq_disable(FEC_XMIT_TASK_NO);/*Disable tx ints*/
-
- enet_driver[0].txInterrupts++; /* Tx int has occurred */
-
- rtems_event_send(enet_driver[0].txDaemonTid, INTERRUPT_EVENT);
-
- }
-
- }
-
-
-
-
-
- /*
- * Function: mpc5200_fec_retire_tbd
- *
- * Description: Soak up buffer descriptors that have been sent.
- *
- * Returns: void
- *
- * Notes:
- *
- */
-static void mpc5200_fec_retire_tbd(struct mpc5200_enet_struct *sc,
- bool force)
+void mpc5200_smartcomm_rx_irq_handler(void *arg)
{
- struct mbuf *n;
- TaskBD1_t *bdRing = (TaskBD1_t *)TaskGetBDRing( txTaskId );;
- /*
- * Clear already transmitted BDs first. Will not work calling same
- * from fecExceptionHandler(TFINT).
- */
+ mpc5200_fec_context *self = arg;
- while ((sc->txBdActiveCount > 0) &&
- (force || (bdRing[sc->txBdTail].Status == 0x0))) {
- if (sc->txMbuf[sc->txBdTail] != NULL) {
- /*
- * NOTE: txMbuf can be NULL, if mbuf has been split into different BDs
- */
- MFREE (sc->txMbuf[sc->txBdTail],n);
- sc->txMbuf[sc->txBdTail] = NULL;
- }
- sc->txBdActiveCount--;
- if(++sc->txBdTail >= sc->txBdCount) {
- sc->txBdTail = 0;
- }
- }
+ ++self->rxInterrupts;
+ mpc5200_fec_send_event(self->rxDaemonTid);
+ SDMA_CLEAR_IEVENT(&mpc5200.sdma.IntPend, FEC_RECV_TASK_NO);
+ bestcomm_glue_irq_disable(FEC_RECV_TASK_NO);
}
-#if 0
- /*
- * Function: mpc5200_fec_tx_bd_requeue
- *
- * Description: put buffers back to interface output queue
- *
- * Returns: void
- *
- * Notes:
- *
- */
-static void mpc5200_fec_tx_bd_requeue(struct mpc5200_enet_struct *sc)
+void mpc5200_smartcomm_tx_irq_handler(void *arg)
{
- /*
- * Clear already transmitted BDs first. Will not work calling same
- * from fecExceptionHandler(TFINT).
- */
-
- while (sc->txBdActiveCount > 0) {
- if (sc->txMbuf[sc->txBdHead] != NULL) {
- /*
- * NOTE: txMbuf can be NULL, if mbuf has been split into different BDs
- */
- IF_PREPEND(&(sc->arpcom.ac_if.if_snd),sc->txMbuf[sc->txBdHead]);
- sc->txMbuf[sc->txBdHead] = NULL;
- }
- sc->txBdActiveCount--;
- if(--sc->txBdHead < 0) {
- sc->txBdHead = sc->txBdCount-1;
- }
- }
-}
-#endif
-
-static void mpc5200_fec_sendpacket(struct ifnet *ifp,struct mbuf *m) {
- struct mpc5200_enet_struct *sc = ifp->if_softc;
- struct mbuf *l = NULL;
- int nAdded;
- uint32_t status;
- rtems_event_set events;
- TaskBD1_t *bdRing = (TaskBD1_t *)TaskGetBDRing( txTaskId );
- TaskBD1_t *thisBd;
- TaskBD1_t *firstBd = NULL;
- void *data_ptr;
- size_t data_len;
+ mpc5200_fec_context *self = arg;
- /*
- * Free up buffer descriptors
- */
- mpc5200_fec_retire_tbd(sc,false);
-
- /*
- * Set up the transmit buffer descriptors.
- * No need to pad out short packets since the
- * hardware takes care of that automatically.
- * No need to copy the packet to a contiguous buffer
- * since the hardware is capable of scatter/gather DMA.
- */
- nAdded = 0;
-
- for(;;) {
-
- /*
- * Wait for buffer descriptor to become available.
- */
- if((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
-
- /*
- * Clear old events
- */
- SDMA_CLEAR_IEVENT(&mpc5200.sdma.IntPend,FEC_XMIT_TASK_NO);
-
- /*
- * Wait for buffer descriptor to become available.
- * Note that the buffer descriptors are checked
- * *before* * entering the wait loop -- this catches
- * the possibility that a buffer descriptor became
- * available between the `if' above, and the clearing
- * of the event register.
- * This is to catch the case where the transmitter
- * stops in the middle of a frame -- and only the
- * last buffer descriptor in a frame can generate
- * an interrupt.
- */
- mpc5200_fec_retire_tbd(sc,false);
-
- while((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
- bestcomm_glue_irq_enable(FEC_XMIT_TASK_NO);
- rtems_bsdnet_event_receive(INTERRUPT_EVENT,
- RTEMS_WAIT | RTEMS_EVENT_ANY,
- RTEMS_NO_TIMEOUT, &events);
- mpc5200_fec_retire_tbd(sc,false);
- }
- }
-
- if(m->m_len == 0) {
- /*
- * Just toss empty mbufs
- */
- struct mbuf *n;
- MFREE(m, n);
- m = n;
- if(l != NULL) {
- l->m_next = m;
- }
- }
- else {
- /*
- * Flush the buffer for this descriptor
- */
- /*rtems_cache_flush_multiple_data_lines((const void *)mtod(m, void *), m->m_len);*/
- /*
- * Fill in the buffer descriptor,
- * set "end of frame" bit in status,
- * if last mbuf in chain
- */
- thisBd = bdRing + sc->txBdHead;
- /*
- * FIXME: do not send interrupt after every frame
- * doing this every quarter of BDs is much more efficent
- */
- status = ((m->m_next == NULL)
- ? TASK_BD_TFD | TASK_BD_INT
- : 0);
- /*
- * Don't set the READY flag till the
- * whole packet has been readied.
- */
- if (firstBd != NULL) {
- status |= (uint32)SDMA_BD_MASK_READY;
- }
- else {
- firstBd = thisBd;
- }
-
- data_ptr = mtod(m, void *);
- data_len = (uint32)m->m_len;
- sc->txMbuf[sc->txBdHead] = m;
- /* go to next part in chain */
- l = m;
- m = m->m_next;
-
- thisBd->DataPtr[0] = (uint32)data_ptr;
- thisBd->Status = (status
- |((uint32)SDMA_DRD_MASK_LENGTH & data_len));
-
- nAdded++;
- if(++(sc->txBdHead) == sc->txBdCount) {
- sc->txBdHead = 0;
- }
- }
- /*
- * Set the transmit buffer status.
- * Break out of the loop if this mbuf is the last in the frame.
- */
- if(m == NULL) {
- if(nAdded) {
- firstBd->Status |= SDMA_BD_MASK_READY;
- SDMA_TASK_ENABLE(SDMA_TCR, txTaskId);
- sc->txBdActiveCount += nAdded;
- }
- break;
- }
- } /* end of for(;;) */
+ ++self->txInterrupts;
+ mpc5200_fec_send_event(self->txDaemonTid);
+ SDMA_CLEAR_IEVENT(&mpc5200.sdma.IntPend, FEC_XMIT_TASK_NO);
+ bestcomm_glue_irq_disable(FEC_XMIT_TASK_NO);
}
-
-/*
- * Driver transmit daemon
- */
-void mpc5200_fec_txDaemon(void *arg)
- {
- struct mpc5200_enet_struct *sc = (struct mpc5200_enet_struct *)arg;
- struct ifnet *ifp = &sc->arpcom.ac_if;
- struct mbuf *m;
- rtems_event_set events;
-
- for(;;) {
- /*
- * Wait for packet
- */
- bestcomm_glue_irq_enable(FEC_XMIT_TASK_NO);
- rtems_bsdnet_event_receive(START_TRANSMIT_EVENT|INTERRUPT_EVENT,
- RTEMS_EVENT_ANY | RTEMS_WAIT,
- RTEMS_NO_TIMEOUT,
- &events);
-
- /*
- * Send packets till queue is empty
- */
- for(;;)
- {
-
- /*
- * Get the next mbuf chain to transmit.
- */
- IF_DEQUEUE(&ifp->if_snd, m);
-
- if (!m)
- break;
-
- mpc5200_fec_sendpacket(ifp, m);
-
- }
-
- ifp->if_flags &= ~IFF_OACTIVE;
-
- }
-
- }
-
-
-/*
- * reader task
- */
-static void mpc5200_fec_rxDaemon(void *arg){
- struct mpc5200_enet_struct *sc = (struct mpc5200_enet_struct *)arg;
- struct ifnet *ifp = &sc->arpcom.ac_if;
- struct mbuf *m;
- struct ether_header *eh;
- int rxBdIndex;
- uint32_t status;
- size_t size;
- rtems_event_set events;
- uint16 len = 1;
- TaskBD1_t *bd;
- void *dptr;
- TaskBD1_t *bdRing = (TaskBD1_t *)TaskGetBDRing( rxTaskId );;
-
- /*
- * Input packet handling loop
- */
- rxBdIndex = 0;
-
- for (;;) {
- /*
- * Clear old events
- */
- SDMA_CLEAR_IEVENT(&mpc5200.sdma.IntPend,FEC_RECV_TASK_NO);
- /*
- * Get the first BD pointer and its length.
- */
- bd = bdRing + rxBdIndex;
- status = bd->Status;
- len = (uint16)GET_BD_LENGTH( bd );
-
- /*
- * Loop through BDs until we find an empty one. This indicates that
- * the SmartDMA is still using it.
- */
- while( !(status & SDMA_BD_MASK_READY) ) {
-
- /*
- * Remember the data pointer from this transfer.
- */
- dptr = (void *)bd->DataPtr[0];
- m = sc->rxMbuf[rxBdIndex];
- m->m_len = m->m_pkthdr.len = (len
- - sizeof(uint32_t)
- - sizeof(struct ether_header));
- eh = mtod(m, struct ether_header *);
- m->m_data += sizeof(struct ether_header);
- ether_input(ifp, eh, m);
-
- /*
- * Done w/ the BD. Clean it.
- */
- sc->rxMbuf[rxBdIndex] = NULL;
-
- /*
- * Add a new buffer to the ring.
- */
- MGETHDR (m, M_WAIT, MT_DATA);
- MCLGET (m, M_WAIT);
- m->m_pkthdr.rcvif = ifp;
- size = ETHER_MAX_LEN;
-
- sc->rxMbuf[rxBdIndex] = m;
- bd->DataPtr[0] = (uint32)mtod(m, void *);
- bd->Status = ( ( (uint32)SDMA_DRD_MASK_LENGTH & (uint32)size)
- | ((uint32)SDMA_BD_MASK_READY));
-
- /*
- * advance to next BD
- */
- if (++rxBdIndex >= sc->rxBdCount) {
- rxBdIndex = 0;
- }
- /*
- * Get next BD pointer and its length.
- */
- bd = bdRing + rxBdIndex;
- status = bd->Status;
- len = (uint16)GET_BD_LENGTH( bd );
- }
- /*
- * Unmask RXF (Full frame received) event
- */
- bestcomm_glue_irq_enable(FEC_RECV_TASK_NO);
-
- rtems_bsdnet_event_receive (INTERRUPT_EVENT | FATAL_INT_EVENT,
- RTEMS_WAIT | RTEMS_EVENT_ANY,
- RTEMS_NO_TIMEOUT, &events);
- if (events & FATAL_INT_EVENT) {
- /*
- * fatal interrupt ocurred, so reinit fec and restart bestcomm tasks
- */
- mpc5200_fec_restart(sc);
- rxBdIndex = 0;
- }
- }
+static void mpc5200_fec_init_mib(mpc5200_fec_context *self)
+{
+ memset(&mpc5200.RES [0], 0, 0x2e4);
+ mpc5200.mib_control = 0x40000000;
}
-
/*
* Function: mpc5200_fec_initialize_hardware
*
@@ -1068,13 +574,17 @@ static void mpc5200_fec_rxDaemon(void *arg){
* Notes:
*
*/
-static void mpc5200_fec_initialize_hardware(struct mpc5200_enet_struct *sc)
- {
+static void mpc5200_fec_initialize_hardware(mpc5200_fec_context *self)
+{
+ /* We want at most 2.5MHz */
+ uint32_t div = 2 * 2500000;
+ uint32_t mii_speed = (IPB_CLOCK + div - 1) / div;
/*
* Reset mpc5200 FEC
*/
- mpc5200_fec_reset(sc);
+ mpc5200_fec_reset(self);
+ mpc5200_fec_init_mib(self);
/*
* Clear FEC-Lite interrupt event register (IEVENT)
@@ -1102,10 +612,10 @@ static void mpc5200_fec_initialize_hardware(struct mpc5200_enet_struct *sc)
/*
- * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock(33Mhz)
+ * Set MII_SPEED = IPB clock / (2 * mii_speed))
* and do not drop the Preamble.
*/
- mpc5200.mii_speed = (7 << 1); /* ipb_clk = 33 MHz */
+ mpc5200.mii_speed = mii_speed << 1;
/*
* Set Opcode/Pause Duration Register
@@ -1135,7 +645,7 @@ static void mpc5200_fec_initialize_hardware(struct mpc5200_enet_struct *sc)
* Set individual address filter for unicast address
* and set physical address registers.
*/
- mpc5200_eth_addr_filter_set(sc);
+ mpc5200_eth_addr_filter_set(self);
/*
* Set multicast address filter
@@ -1147,7 +657,7 @@ static void mpc5200_fec_initialize_hardware(struct mpc5200_enet_struct *sc)
* enable CRC in finite state machine register
*/
mpc5200.xmit_fsm = FEC_FSM_CRC | FEC_FSM_ENFSM;
- }
+}
/*
* Initialize PHY(LXT971A):
@@ -1174,16 +684,18 @@ static void mpc5200_fec_initialize_hardware(struct mpc5200_enet_struct *sc)
* Notes:
*
*/
-static void mpc5200_fec_initialize_phy(struct mpc5200_enet_struct *sc)
- {
- int timeout;
- unsigned short phyAddr = 0;
-
+static void mpc5200_fec_initialize_phy(mpc5200_fec_context *self)
+{
+ if (self->phyInitialized) {
+ return;
+ } else {
+ self->phyInitialized = true;
+ }
/*
* Reset PHY, then delay 300ns
*/
- mpc5200_eth_mii_write(sc, phyAddr, 0x0, 0x8000);
+ mpc5200_eth_mii_write(self->phyAddr, self, 0x0, 0x8000);
rtems_task_wake_after(2);
@@ -1192,18 +704,19 @@ static void mpc5200_fec_initialize_phy(struct mpc5200_enet_struct *sc)
/*
* Set the auto-negotiation advertisement register bits
*/
- mpc5200_eth_mii_write(sc, phyAddr, 0x4, 0x01e1);
+ mpc5200_eth_mii_write(self->phyAddr, self, 0x4, 0x01e1);
/*
* Set MDIO bit 0.12 = 1(&& bit 0.9=1?) to enable auto-negotiation
*/
- mpc5200_eth_mii_write(sc, phyAddr, 0x0, 0x1200);
+ mpc5200_eth_mii_write(self->phyAddr, self, 0x0, 0x1200);
/*
* Wait for AN completion
*/
- timeout = 0x100;
#if 0
+ int timeout = 0x100;
+ uint32_t phyStatus;
do
{
@@ -1218,11 +731,11 @@ static void mpc5200_fec_initialize_phy(struct mpc5200_enet_struct *sc)
}
- if(mpc5200_eth_mii_read(sc, phyAddr, 0x1, &phyStatus) != true)
+ if(mpc5200_eth_mii_read(self->phyAddr, self, 0x1, &phyStatus) != true)
{
#if defined(ETH_DEBUG)
- printf ("MPC5200FEC PHY auto neg failed: 0x%04x." "\r\n", phyStatus);
+ printf ("MPC5200FEC PHY auto neg failed: 0x%04" PRIx32 ".\r\n", phyStatus);
#endif
return;
@@ -1242,29 +755,45 @@ static void mpc5200_fec_initialize_phy(struct mpc5200_enet_struct *sc)
#if defined(ETH_DEBUG)
int i;
- unsigned short phyStatus;
+ uint32_t phyStatus;
/*
* Print PHY registers after initialization.
*/
for(i = 0; i < 9; i++)
{
- mpc5200_eth_mii_read(sc, phyAddr, i, &phyStatus);
- printf ("Mii reg %d: 0x%04x" "\r\n", i, phyStatus);
+ mpc5200_eth_mii_read(self->phyAddr, self, i, &phyStatus);
+ printf ("Mii reg %d: 0x%04" PRIx32 "\r\n", i, phyStatus);
}
for(i = 16; i < 21; i++)
{
- mpc5200_eth_mii_read(sc, phyAddr, i, &phyStatus);
- printf ("Mii reg %d: 0x%04x" "\r\n", i, phyStatus);
+ mpc5200_eth_mii_read(self->phyAddr, self, i, &phyStatus);
+ printf ("Mii reg %d: 0x%04" PRIx32 "\r\n", i, phyStatus);
}
#endif /* ETH_DEBUG */
}
+static void mpc5200_fec_restart(mpc5200_fec_context *self, rtems_id otherDaemon)
+{
+ if (self->state == FEC_STATE_RESTART_1) {
+ mpc5200_fec_initialize_hardware(self);
+ mpc5200_fec_initialize_phy(self);
+ mpc5200_fec_start_dma_and_controller();
+ self->state = FEC_STATE_NORMAL;
+ } else {
+ self->state = FEC_STATE_RESTART_1;
+ }
+
+ mpc5200_fec_send_event(otherDaemon);
+ while (self->state != FEC_STATE_NORMAL) {
+ mpc5200_fec_wait_for_event();
+ }
+}
/*
* Send packet (caller provides header).
@@ -1272,159 +801,453 @@ static void mpc5200_fec_initialize_phy(struct mpc5200_enet_struct *sc)
static void mpc5200_fec_tx_start(struct ifnet *ifp)
{
- struct mpc5200_enet_struct *sc = ifp->if_softc;
+ mpc5200_fec_context *self = ifp->if_softc;
ifp->if_flags |= IFF_OACTIVE;
- rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
+ mpc5200_fec_send_event(self->txDaemonTid);
}
+static TaskBD1_t *mpc5200_fec_init_tx_dma(int bdCount, struct mbuf **mbufs)
+{
+ TaskSetupParamSet_t param = {
+ .NumBD = bdCount,
+ .Size = {
+ .MaxBuf = ETHER_MAX_LEN
+ },
+ .Initiator = 0,
+ .StartAddrSrc = 0,
+ .IncrSrc = sizeof(uint32_t),
+ .SzSrc = sizeof(uint32_t),
+ .StartAddrDst = (uint32) &mpc5200.tfifo_data,
+ .IncrDst = 0,
+ .SzDst = sizeof(uint32_t)
+ };
+ int bdIndex = 0;
-/*
- * set up sdma tasks for ethernet
- */
-static void mpc5200_sdma_task_setup(struct mpc5200_enet_struct *sc) {
- TaskSetupParamSet_t rxParam; /* RX task setup parameters */
- TaskSetupParamSet_t txParam; /* TX task setup parameters */
+ TaskSetup(FEC_XMIT_TASK_NO, &param);
- /*
- * Setup the SDMA RX task.
- */
- rxParam.NumBD = sc->rxBdCount;
- rxParam.Size.MaxBuf = ETHER_MAX_LEN;
- rxParam.Initiator = 0;
- rxParam.StartAddrSrc = (uint32)&(mpc5200.rfifo_data);
- rxParam.IncrSrc = 0;
- rxParam.SzSrc = sizeof(uint32_t);
- rxParam.StartAddrDst = (uint32)NULL;
- rxParam.IncrDst = sizeof(uint32_t);
- rxParam.SzDst = sizeof(uint32_t);
- rxTaskId = TaskSetup(TASK_FEC_RX,&rxParam );
+ for (bdIndex = 0; bdIndex < bdCount; ++bdIndex) {
+ mbufs [bdIndex] = NULL;
+ }
- /*
- * Setup the TX task.
- */
- txParam.NumBD = sc->txBdCount;
- txParam.Size.MaxBuf = ETHER_MAX_LEN;
- txParam.Initiator = 0;
- txParam.StartAddrSrc = (uint32)NULL;
- txParam.IncrSrc = sizeof(uint32_t);
- txParam.SzSrc = sizeof(uint32_t);
- txParam.StartAddrDst = (uint32)&(mpc5200.tfifo_data);
- txParam.IncrDst = 0;
- txParam.SzDst = sizeof(uint32_t);
-
- txTaskId = TaskSetup( TASK_FEC_TX, &txParam );
+ return (TaskBD1_t *) TaskGetBDRing(FEC_XMIT_TASK_NO);
+}
+#if 0
+static void mpc5200_fec_requeue_and_discard_tx_frames(
+ int bdIndex,
+ int bdCount,
+ TaskBD1_t *bdRing,
+ struct mbuf **mbufs
+)
+{
+ int bdStop = bdIndex;
+ struct mbuf *previous = NULL;
+
+ do {
+ struct mbuf *current = NULL;
+ uint32 status = 0;
+ TaskBD1_t *bd = NULL;
+
+ if (bdIndex > 1) {
+ --bdIndex;
+ } else {
+ bdIndex = bdCount - 1;
+ }
+
+ current = mbufs [bdIndex];
+ mbufs [bdIndex] = NULL;
+
+ status = bdRing [bdIndex].Status;
+ bdRing [bdIndex].Status = 0;
+
+ if (current != NULL) {
+ if ((status & FEC_BD_LAST) != 0) {
+ if (previous != NULL) {
+ IF_PREPEND(&ifp->if_snd, previous);
+ }
+ }
+ } else {
+ break;
+ }
+
+ previous = current;
+ } while (bdIndex != bdStop);
}
+#endif
-void mpc5200_fec_irq_on(const rtems_irq_connect_data* ptr)
+static void mpc5200_fec_discard_tx_frames(
+ int bdCount,
+ struct mbuf **mbufs
+)
{
- mpc5200.imask = FEC_INTR_MASK_USED;
+ int bdIndex = 0;
+
+ for (bdIndex = 0; bdIndex < bdCount; ++bdIndex) {
+ struct mbuf *m = mbufs [bdIndex];
+
+ if (m != NULL) {
+ mbufs [bdIndex] = NULL;
+ m_free(m);
+ }
+ }
}
+static void mpc5200_fec_reset_tx_dma(
+ int bdCount,
+ TaskBD1_t *bdRing,
+ struct mbuf **mbufs,
+ struct mbuf *m
+)
+{
+ TaskStop(FEC_XMIT_TASK_NO);
+ TaskBDReset(FEC_XMIT_TASK_NO);
+ mpc5200_fec_discard_tx_frames(bdCount, mbufs);
+ while (m != NULL) {
+ m = m_free(m);
+ }
+}
-int mpc5200_fec_irq_isOn(const rtems_irq_connect_data* ptr)
+static struct mbuf *mpc5200_fec_next_fragment(
+ struct ifnet *ifp,
+ struct mbuf *m,
+ bool *isFirst
+)
{
- return mpc5200.imask != 0;
+ struct mbuf *n = NULL;
+
+ *isFirst = false;
+
+ while (true) {
+ if (m == NULL) {
+ IF_DEQUEUE(&ifp->if_snd, m);
+
+ if (m != NULL) {
+ *isFirst = true;
+ } else {
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ return NULL;
+ }
+ }
+
+ if (m->m_len > 0) {
+ break;
+ } else {
+ m = m_free(m);
+ }
+ }
+
+ n = m->m_next;
+ while (n != NULL && n->m_len <= 0) {
+ n = m_free(n);
+ }
+ m->m_next = n;
+
+ return m;
}
+static bool mpc5200_fec_transmit(
+ struct ifnet *ifp,
+ int bdCount,
+ TaskBD1_t *bdRing,
+ struct mbuf **mbufs,
+ int *bdIndexPtr,
+ struct mbuf **mPtr,
+ TaskBD1_t **firstPtr
+)
+{
+ bool bdShortage = false;
+ int bdIndex = *bdIndexPtr;
+ struct mbuf *m = *mPtr;
+ TaskBD1_t *first = *firstPtr;
+
+ while (true) {
+ TaskBD1_t *bd = &bdRing [bdIndex];
+
+ if (bd->Status == 0) {
+ struct mbuf *done = mbufs [bdIndex];
+ bool isFirst = false;
+
+ if (done != NULL) {
+ m_free(done);
+ mbufs [bdIndex] = NULL;
+ }
+
+ m = mpc5200_fec_next_fragment(ifp, m, &isFirst);
+ if (m != NULL) {
+ uint32 status = (uint32) m->m_len;
+
+ mbufs [bdIndex] = m;
+
+ rtems_cache_flush_multiple_data_lines(mtod(m, void *), m->m_len);
+
+ if (isFirst) {
+ first = bd;
+ } else {
+ status |= FEC_BD_READY;
+ }
+
+ bd->DataPtr [0] = mtod(m, uint32);
+
+ if (m->m_next != NULL) {
+ bd->Status = status;
+ } else {
+ bd->Status = status | FEC_BD_INT | FEC_BD_LAST;
+ first->Status |= FEC_BD_READY;
+ SDMA_TASK_ENABLE(SDMA_TCR, FEC_XMIT_TASK_NO);
+ }
+
+ m = m->m_next;
+ } else {
+ break;
+ }
+ } else {
+ bdShortage = true;
+ break;
+ }
+
+ if (bdIndex < bdCount - 1) {
+ ++bdIndex;
+ } else {
+ bdIndex = 0;
+ }
+ }
+
+ *bdIndexPtr = bdIndex;
+ *mPtr = m;
+ *firstPtr = first;
-void mpc5200_fec_irq_off(const rtems_irq_connect_data* ptr)
+ return bdShortage;
+}
+
+static void mpc5200_fec_tx_daemon(void *arg)
{
- mpc5200.imask = 0;
+ mpc5200_fec_context *self = arg;
+ struct ifnet *ifp = &self->arpcom.ac_if;
+ int bdIndex = 0;
+ int bdCount = self->txBdCount;
+ struct mbuf **mbufs = &self->txMbuf [0];
+ struct mbuf *m = NULL;
+ TaskBD1_t *bdRing = mpc5200_fec_init_tx_dma(bdCount, mbufs);
+ TaskBD1_t *first = NULL;
+ bool bdShortage = false;
+
+ while (true) {
+ if (bdShortage) {
+ bestcomm_glue_irq_enable(FEC_XMIT_TASK_NO);
+ }
+ mpc5200_fec_wait_for_event();
+
+ if (self->state != FEC_STATE_NORMAL) {
+ mpc5200_fec_reset_tx_dma(bdCount, bdRing, mbufs, m);
+ mpc5200_fec_restart(self, self->rxDaemonTid);
+ bdIndex = 0;
+ m = NULL;
+ first = NULL;
+ }
+
+ bdShortage = mpc5200_fec_transmit(
+ ifp,
+ bdCount,
+ bdRing,
+ mbufs,
+ &bdIndex,
+ &m,
+ &first
+ );
+ }
}
+static struct mbuf *mpc5200_fec_add_mbuf(struct ifnet *ifp, TaskBD1_t *bd)
+{
+ struct mbuf *m = NULL;
+
+ MGETHDR (m, M_WAIT, MT_DATA);
+ MCLGET (m, M_WAIT);
+ m->m_pkthdr.rcvif = ifp;
+
+ /* XXX: The dcbi operation does not work properly */
+ rtems_cache_flush_multiple_data_lines(mtod(m, void *), ETHER_MAX_LEN);
+
+ bd->DataPtr [0] = mtod(m, uint32);
+ bd->Status = ETHER_MAX_LEN | FEC_BD_READY;
+
+ return m;
+}
+
+static TaskBD1_t *mpc5200_fec_init_rx_dma(
+ struct ifnet *ifp,
+ int bdCount,
+ struct mbuf **mbufs
+)
+{
+ TaskSetupParamSet_t param = {
+ .NumBD = bdCount,
+ .Size = {
+ .MaxBuf = ETHER_MAX_LEN
+ },
+ .Initiator = 0,
+ .StartAddrSrc = (uint32) &mpc5200.rfifo_data,
+ .IncrSrc = 0,
+ .SzSrc = sizeof(uint32_t),
+ .StartAddrDst = 0,
+ .IncrDst = sizeof(uint32_t),
+ .SzDst = sizeof(uint32_t)
+ };
+ TaskBD1_t *bdRing = NULL;
+ int bdIndex = 0;
+
+ TaskSetup(FEC_RECV_TASK_NO, &param);
+ bdRing = (TaskBD1_t *) TaskGetBDRing(FEC_RECV_TASK_NO);
+
+ for (bdIndex = 0; bdIndex < bdCount; ++bdIndex) {
+ mbufs [bdIndex] = mpc5200_fec_add_mbuf(ifp, &bdRing [bdIndex]);
+ }
+
+ return bdRing;
+}
+
+static void mpc5200_fec_reset_rx_dma(int bdCount, TaskBD1_t *bdRing)
+{
+ int bdIndex = 0;
+
+ TaskStop(FEC_RECV_TASK_NO);
+ TaskBDReset(FEC_RECV_TASK_NO);
+
+ for (bdIndex = 0; bdIndex < bdCount; ++bdIndex) {
+ bdRing [bdIndex].Status = ETHER_MAX_LEN | FEC_BD_READY;
+ }
+}
+
+static int mpc5200_fec_ether_input(
+ struct ifnet *ifp,
+ int bdIndex,
+ int bdCount,
+ TaskBD1_t *bdRing,
+ struct mbuf **mbufs
+)
+{
+ while (true) {
+ TaskBD1_t *bd = &bdRing [bdIndex];
+ struct mbuf *m = mbufs [bdIndex];
+ uint32 status = 0;
+ int len = 0;
+ struct ether_header *eh = NULL;
+
+ SDMA_CLEAR_IEVENT(&mpc5200.sdma.IntPend, FEC_RECV_TASK_NO);
+ status = bd->Status;
+
+ if ((status & FEC_BD_READY) != 0) {
+ break;
+ }
+
+ eh = mtod(m, struct ether_header *);
+
+ len = (status & 0xffff) - ETHER_HDR_LEN - ETHER_CRC_LEN;
+ m->m_len = len;
+ m->m_pkthdr.len = len;
+ m->m_data = mtod(m, char *) + ETHER_HDR_LEN;
+
+ ether_input(ifp, eh, m);
+
+ mbufs [bdIndex] = mpc5200_fec_add_mbuf(ifp, bd);
+
+ if (bdIndex < bdCount - 1) {
+ ++bdIndex;
+ } else {
+ bdIndex = 0;
+ }
+ }
+
+ return bdIndex;
+}
+
+static void mpc5200_fec_rx_daemon(void *arg)
+{
+ mpc5200_fec_context *self = arg;
+ struct ifnet *ifp = &self->arpcom.ac_if;
+ int bdIndex = 0;
+ int bdCount = self->rxBdCount;
+ struct mbuf **mbufs = &self->rxMbuf [0];
+ TaskBD1_t *bdRing = mpc5200_fec_init_rx_dma(ifp, bdCount, mbufs);
+
+ while (true) {
+ bestcomm_glue_irq_enable(FEC_RECV_TASK_NO);
+ mpc5200_fec_wait_for_event();
+
+ bdIndex = mpc5200_fec_ether_input(ifp, bdIndex, bdCount, bdRing, mbufs);
+
+ if (self->state != FEC_STATE_NORMAL) {
+ mpc5200_fec_reset_rx_dma(bdCount, bdRing);
+ mpc5200_fec_restart(self, self->txDaemonTid);
+ bdIndex = 0;
+ }
+ }
+}
/*
* Initialize and start the device
*/
static void mpc5200_fec_init(void *arg)
{
- struct mpc5200_enet_struct *sc = (struct mpc5200_enet_struct *)arg;
- struct ifnet *ifp = &sc->arpcom.ac_if;
- rtems_irq_connect_data fec_irq_data = {
- BSP_SIU_IRQ_ETH,
- mpc5200_fec_irq_handler, /* rtems_irq_hdl */
- (rtems_irq_hdl_param)sc, /* (rtems_irq_hdl_param) */
- mpc5200_fec_irq_on, /* (rtems_irq_enable) */
- mpc5200_fec_irq_off, /* (rtems_irq_disable) */
- mpc5200_fec_irq_isOn /* (rtems_irq_is_enabled) */
- };
-
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ mpc5200_fec_context *self = (mpc5200_fec_context *)arg;
+ struct ifnet *ifp = &self->arpcom.ac_if;
- if(sc->txDaemonTid == 0)
+ if(self->txDaemonTid == 0)
{
+ size_t rxMbufTableSize = self->rxBdCount * sizeof(*self->rxMbuf);
+ size_t txMbufTableSize = self->txBdCount * sizeof(*self->txMbuf);
+
/*
* Allocate a set of mbuf pointers
*/
- sc->rxMbuf =
- malloc(sc->rxBdCount * sizeof *sc->rxMbuf, M_MBUF, M_NOWAIT);
- sc->txMbuf =
- malloc(sc->txBdCount * sizeof *sc->txMbuf, M_MBUF, M_NOWAIT);
+ self->rxMbuf = malloc(rxMbufTableSize, M_MBUF, M_NOWAIT);
+ self->txMbuf = malloc(txMbufTableSize, M_MBUF, M_NOWAIT);
- if(!sc->rxMbuf || !sc->txMbuf)
+ if(!self->rxMbuf || !self->txMbuf)
rtems_panic ("No memory for mbuf pointers");
+ /*
+ * DMA setup
+ */
bestcomm_glue_init();
-
- mpc5200_sdma_task_setup(sc);
+ mpc5200.sdma.ipr [0] = 4; /* always initiator */
+ mpc5200.sdma.ipr [3] = 6; /* eth rx initiator */
+ mpc5200.sdma.ipr [4] = 5; /* eth tx initiator */
/*
* Set up interrupts
*/
bestcomm_glue_irq_install(FEC_RECV_TASK_NO,
mpc5200_smartcomm_rx_irq_handler,
- NULL);
+ self);
bestcomm_glue_irq_install(FEC_XMIT_TASK_NO,
mpc5200_smartcomm_tx_irq_handler,
- NULL);
- if(!BSP_install_rtems_irq_handler (&fec_irq_data)) {
+ self);
+ sc = rtems_interrupt_handler_install(
+ BSP_SIU_IRQ_ETH,
+ "FEC",
+ RTEMS_INTERRUPT_UNIQUE,
+ mpc5200_fec_irq_handler,
+ self
+ );
+ if(sc != RTEMS_SUCCESSFUL) {
rtems_panic ("Can't attach MPC5x00 FEX interrupt handler\n");
}
- /* mpc5200_fec_tx_bd_init(sc); */
- mpc5200_fec_rx_bd_init(sc);
-
- /*
- * reset and Set up mpc5200 FEC hardware
- */
- mpc5200_fec_initialize_hardware(sc);
- /*
- * Set up the phy
- */
- mpc5200_fec_initialize_phy(sc);
- /*
- * Set priority of different initiators
- */
- mpc5200.sdma.ipr [0] = 7; /* always initiator */
- mpc5200.sdma.ipr [3] = 6; /* eth rx initiator */
- mpc5200.sdma.ipr [4] = 5; /* eth tx initiator */
-
/*
* Start driver tasks
*/
- sc->txDaemonTid = rtems_bsdnet_newproc("FEtx", 4096, mpc5200_fec_txDaemon, sc);
- sc->rxDaemonTid = rtems_bsdnet_newproc("FErx", 4096, mpc5200_fec_rxDaemon, sc);
- /*
- * Clear SmartDMA task interrupt pending bits.
- */
- TaskIntClear( rxTaskId );
-
- /*
- * Enable the SmartDMA receive task.
- */
- TaskStart( rxTaskId, 1, rxTaskId, 1 );
- TaskStart( txTaskId, 1, txTaskId, 1 );
- /*
- * Enable FEC-Lite controller
- */
- mpc5200.ecntrl |= (FEC_ECNTRL_OE | FEC_ECNTRL_EN);
-
-
+ self->txDaemonTid = rtems_bsdnet_newproc("FEtx", 4096, mpc5200_fec_tx_daemon, self);
+ self->rxDaemonTid = rtems_bsdnet_newproc("FErx", 4096, mpc5200_fec_rx_daemon, self);
}
+ mpc5200_fec_request_restart(self);
+
/*
* Set flags appropriately
*/
@@ -1439,123 +1262,41 @@ static void mpc5200_fec_init(void *arg)
ifp->if_flags |= IFF_RUNNING;
}
-
-static void enet_stats (struct mpc5200_enet_struct *sc)
-{
- printf (" Rx Interrupts:%-8lu", sc->rxInterrupts);
- printf (" Not First:%-8lu", sc->rxNotFirst);
- printf (" Not Last:%-8lu\n", sc->rxNotLast);
- printf (" Giant:%-8lu", sc->rxGiant);
- printf (" Non-octet:%-8lu\n", sc->rxNonOctet);
- printf (" Bad CRC:%-8lu", sc->rxBadCRC);
- printf (" Overrun:%-8lu", sc->rxOverrun);
- printf (" Collision:%-8lu\n", sc->rxCollision);
-
- printf (" Tx Interrupts:%-8lu", sc->txInterrupts);
- printf (" Deferred:%-8lu", sc->txDeferred);
- printf (" Late Collision:%-8lu\n", sc->txLateCollision);
- printf (" Retransmit Limit:%-8lu", sc->txRetryLimit);
- printf (" Underrun:%-8lu", sc->txUnderrun);
- printf (" Misaligned:%-8lu\n", sc->txMisaligned);
-
-}
-
-/*
- * restart the driver, reinit the fec
- * this function is responsible to reinitialize the FEC in case a fatal
- * error has ocurred. This is needed, wen a RxFIFO Overrun or a TxFIFO underrun
- * has ocurred. In these cases, the FEC is automatically disabled, and
- * both FIFOs must be reset and the BestComm tasks must be restarted
- *
- * Note: the daemon tasks will continue to run
- * (in fact this function will be called in the context of the rx daemon task)
- */
-#define NEW_SDMA_SETUP
-
-static void mpc5200_fec_restart(struct mpc5200_enet_struct *sc)
+static void enet_stats (mpc5200_fec_context *self)
{
- /*
- * FIXME: bring Tx Daemon into idle state
- */
-#ifdef NEW_SDMA_SETUP
- /*
- * cleanup remaining receive mbufs
- */
- mpc5200_fec_rx_bd_cleanup(sc);
-#endif
- /*
- * Stop SDMA tasks
- */
- TaskStop( rxTaskId);
- TaskStop( txTaskId);
- /*
- * FIXME: wait, until Tx Daemon is in idle state
- */
-
- /*
- * Disable transmit / receive interrupts
- */
- bestcomm_glue_irq_disable(FEC_XMIT_TASK_NO);
- bestcomm_glue_irq_disable(FEC_RECV_TASK_NO);
-#ifdef NEW_SDMA_SETUP
- /*
- * recycle pending tx buffers
- * FIXME: try to extract pending Tx buffers
- */
-#if 0
- mpc5200_fec_tx_bd_requeue(sc);
-#else
- mpc5200_fec_retire_tbd(sc,true);
-#endif
-#endif
- /*
- * re-initialize the FEC hardware
- */
- mpc5200_fec_initialize_hardware(sc);
-
-#ifdef NEW_SDMA_SETUP
- /*
- * completely reinitialize Bestcomm tasks
- */
- mpc5200_sdma_task_setup(sc);
-
- /*
- * reinit receive mbufs
- */
- mpc5200_fec_rx_bd_init(sc);
-#endif
- /*
- * Clear SmartDMA task interrupt pending bits.
- */
- TaskIntClear( rxTaskId );
-
- /*
- * Enable the SmartDMA receive/transmit task.
- */
- TaskStart( rxTaskId, 1, rxTaskId, 1 );
- TaskStart( txTaskId, 1, txTaskId, 1 );
- /*
- * reenable rx/tx interrupts
- */
- bestcomm_glue_irq_enable(FEC_XMIT_TASK_NO);
- bestcomm_glue_irq_enable(FEC_RECV_TASK_NO);
- /*
- * (re-)init fec hardware
- */
- mpc5200_fec_initialize_hardware(sc);
- /*
- * reenable fec FIFO error interrupts
- */
- mpc5200.imask = FEC_INTR_MASK_USED;
- /*
- * Enable FEC-Lite controller
- */
- mpc5200.ecntrl |= (FEC_ECNTRL_OE | FEC_ECNTRL_EN);
+ if (self->phyAddr >= 0) {
+ struct ifnet *ifp = &self->arpcom.ac_if;
+ int media = IFM_MAKEWORD(0, 0, 0, self->phyAddr);
+ int rv = (*ifp->if_ioctl)(ifp, SIOCGIFMEDIA, (caddr_t) &media);
+
+ if (rv == 0) {
+ rtems_ifmedia2str(media, NULL, 0);
+ printf ("\n");
+ } else {
+ printf ("PHY communication error\n");
+ }
+ }
+ printf (" Rx Interrupts:%-8lu", self->rxInterrupts);
+ printf (" Rx Not First:%-8lu", self->rxNotFirst);
+ printf (" Rx Not Last:%-8lu\n", self->rxNotLast);
+ printf (" Rx Giant:%-8lu", self->rxGiant);
+ printf (" Rx Non-octet:%-8lu", self->rxNonOctet);
+ printf (" Rx Bad CRC:%-8lu\n", self->rxBadCRC);
+ printf (" Rx FIFO Error:%-8lu", self->rxFIFOError);
+ printf (" Rx Collision:%-8lu", self->rxCollision);
+
+ printf (" Tx Interrupts:%-8lu\n", self->txInterrupts);
+ printf (" Tx Deferred:%-8lu", self->txDeferred);
+ printf (" Tx Late Collision:%-8lu", self->txLateCollision);
+ printf (" Tx Retransmit Limit:%-8lu\n", self->txRetryLimit);
+ printf (" Tx Underrun:%-8lu", self->txUnderrun);
+ printf (" Tx FIFO Error:%-8lu", self->txFIFOError);
+ printf (" Tx Misaligned:%-8lu\n", self->txMisaligned);
}
int32_t mpc5200_fec_setMultiFilter(struct ifnet *ifp)
{
- /*struct mpc5200_enet_struct *sc = ifp->if_softc; */
+ /*mpc5200_fec_context *self = ifp->if_softc; */
/* XXX anything to do? */
return 0;
}
@@ -1566,7 +1307,7 @@ int32_t mpc5200_fec_setMultiFilter(struct ifnet *ifp)
*/
static int mpc5200_fec_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data)
{
- struct mpc5200_enet_struct *sc = ifp->if_softc;
+ mpc5200_fec_context *self = ifp->if_softc;
int error = 0;
switch(command)
@@ -1583,8 +1324,8 @@ static int mpc5200_fec_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_
case SIOCDELMULTI: {
struct ifreq* ifr = (struct ifreq*) data;
error = (command == SIOCADDMULTI)
- ? ether_addmulti(ifr, &sc->arpcom)
- : ether_delmulti(ifr, &sc->arpcom);
+ ? ether_addmulti(ifr, &self->arpcom)
+ : ether_delmulti(ifr, &self->arpcom);
if (error == ENETRESET) {
if (ifp->if_flags & IFF_RUNNING)
@@ -1602,20 +1343,20 @@ static int mpc5200_fec_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_
case IFF_RUNNING:
- mpc5200_fec_off(sc);
+ mpc5200_fec_off(self);
break;
case IFF_UP:
- mpc5200_fec_init(sc);
+ mpc5200_fec_init(self);
break;
case IFF_UP | IFF_RUNNING:
- mpc5200_fec_off(sc);
- mpc5200_fec_init(sc);
+ mpc5200_fec_off(self);
+ mpc5200_fec_init(self);
break;
@@ -1626,9 +1367,14 @@ static int mpc5200_fec_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_
break;
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ error = rtems_mii_ioctl(&self->mdio, self, command, (int *) data);
+ break;
+
case SIO_RTEMS_SHOW_STATS:
- enet_stats(sc);
+ enet_stats(self);
break;
@@ -1653,7 +1399,7 @@ static int mpc5200_fec_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_
*/
int rtems_mpc5200_fec_driver_attach(struct rtems_bsdnet_ifconfig *config)
{
- struct mpc5200_enet_struct *sc;
+ mpc5200_fec_context *self;
struct ifnet *ifp;
int mtu;
int unitNumber;
@@ -1676,8 +1422,8 @@ int rtems_mpc5200_fec_driver_attach(struct rtems_bsdnet_ifconfig *config)
}
- sc = &enet_driver[unitNumber - 1];
- ifp = &sc->arpcom.ac_if;
+ self = &enet_driver[unitNumber - 1];
+ ifp = &self->arpcom.ac_if;
if(ifp->if_softc != NULL)
{
@@ -1687,6 +1433,9 @@ int rtems_mpc5200_fec_driver_attach(struct rtems_bsdnet_ifconfig *config)
}
+ self->mdio.mdio_r = mpc5200_eth_mii_read;
+ self->mdio.mdio_w = mpc5200_eth_mii_write;
+
/*
* Process options
*/
@@ -1726,7 +1475,7 @@ int rtems_mpc5200_fec_driver_attach(struct rtems_bsdnet_ifconfig *config)
{
/* Anything in the first three bytes indicates a non-zero entry, copy value */
- memcpy((void *)sc->arpcom.ac_enaddr, &nvram->enaddr, ETHER_ADDR_LEN);
+ memcpy((void *)self->arpcom.ac_enaddr, &nvram->enaddr, ETHER_ADDR_LEN);
}
else
@@ -1734,7 +1483,7 @@ int rtems_mpc5200_fec_driver_attach(struct rtems_bsdnet_ifconfig *config)
{
/* There is no entry in NVRAM, but there is in the ifconfig struct, so use it. */
- memcpy((void *)sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
+ memcpy((void *)self->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
}
else
{
@@ -1749,7 +1498,7 @@ int rtems_mpc5200_fec_driver_attach(struct rtems_bsdnet_ifconfig *config)
if(config->hardware_address)
{
- memcpy(sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
+ memcpy(self->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
}
else
@@ -1764,11 +1513,11 @@ int rtems_mpc5200_fec_driver_attach(struct rtems_bsdnet_ifconfig *config)
#endif /* NVRAM_CONFIGURE != 1 */
#ifdef HAS_UBOOT
- if ((sc->arpcom.ac_enaddr[0] == 0) &&
- (sc->arpcom.ac_enaddr[1] == 0) &&
- (sc->arpcom.ac_enaddr[2] == 0)) {
+ if ((self->arpcom.ac_enaddr[0] == 0) &&
+ (self->arpcom.ac_enaddr[1] == 0) &&
+ (self->arpcom.ac_enaddr[2] == 0)) {
memcpy(
- (void *)sc->arpcom.ac_enaddr,
+ (void *)self->arpcom.ac_enaddr,
bsp_uboot_board_info.bi_enetaddr,
ETHER_ADDR_LEN
);
@@ -1780,21 +1529,21 @@ int rtems_mpc5200_fec_driver_attach(struct rtems_bsdnet_ifconfig *config)
mtu = ETHERMTU;
if(config->rbuf_count)
- sc->rxBdCount = config->rbuf_count;
+ self->rxBdCount = config->rbuf_count;
else
- sc->rxBdCount = RX_BUF_COUNT;
+ self->rxBdCount = RX_BUF_COUNT;
if(config->xbuf_count)
- sc->txBdCount = config->xbuf_count;
+ self->txBdCount = config->xbuf_count;
else
- sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF;
+ self->txBdCount = TX_BUF_COUNT;
- sc->acceptBroadcast = !config->ignore_broadcast;
+ self->acceptBroadcast = !config->ignore_broadcast;
/*
* Set up network interface values
*/
- ifp->if_softc = sc;
+ ifp->if_softc = self;
ifp->if_unit = unitNumber;
ifp->if_name = unitName;
ifp->if_mtu = mtu;