📄 mcf5xxx_fec.c
字号:
* have to trash the received data and reuse the buffer
* hoping that some buffers will free up in the system
* and this frame will be re-transmitted by the host
*/
pRxBD->length = RX_BUF_SZ;
pRxBD->status &= (RX_BD_W | RX_BD_INTERRUPT);
pRxBD->status |= RX_BD_E;
nbuf_add(NBUF_RX_RING, cur_nbuf);
fec_rx_continue();
continue;
}
/*
* Add the new network buffer to the Rx ring queue
*/
nbuf_add(NBUF_RX_RING, new_nbuf);
/*
* Re-initialize the buffer descriptor - pointing it
* to the new data buffer. The previous data buffer
* will be passed up the stack
*/
pRxBD->data = new_nbuf->data;
pRxBD->length = RX_BUF_SZ;
pRxBD->status &= (RX_BD_W | RX_BD_INTERRUPT);
pRxBD->status |= RX_BD_E;
/*
* Let the DMA know that there is a new Rx BD (in case the
* ring was full and the DMA was waiting for an empty one)
*/
fec_rx_continue();
/*
* Get pointer to the frame data inside the network buffer
*/
eth_hdr = (ETH_HDR *)cur_nbuf->data;
/*
* Pass the received packet up the network stack if the
* protocol is supported in our network interface (NIF)
*/
if (nif_protocol_exist(nif,eth_hdr->type))
{
nif_protocol_handler(nif, eth_hdr->type, cur_nbuf);
}
else
nbuf_free(cur_nbuf);
}
else
{
/*
* This frame isn't a keeper
* Reset the status and length, but don't need to get another
* buffer since we are trashing the data in the current one
*/
pRxBD->length = RX_BUF_SZ;
pRxBD->status &= (RX_BD_W | RX_BD_INTERRUPT);
pRxBD->status |= RX_BD_E;
/*
* Move the current buffer from the beginning to the end of the
* Rx ring queue
*/
cur_nbuf = nbuf_remove(NBUF_RX_RING);
nbuf_add(NBUF_RX_RING, cur_nbuf);
/*
* Let the DMA know that there are new Rx BDs (in case
* it is waiting for an empty one)
*/
fec_rx_continue();
}
}
}
/********************************************************************/
/*
* Continue the Tx FEC DMA
*
* This routine is called after the DMA has halted after
* encountering a Tx buffer descriptor that wasn't marked as
* ready. There is no harm in calling the continue DMA routine
* if the DMA was not paused.
*/
void
fec_tx_continue(void)
{
/*
* Continue/restart the FEC DMA
*/
MCF_FEC_TDAR = MCF_FEC_TDAR_X_DES_ACTIVE;
}
/********************************************************************/
/*
* Stop all transmissions on the selected FEC and kill the DMA task
*/
void
fec_tx_stop (void)
{
int i;
uint32 mask;
/* Save off the EIMR value */
mask = MCF_FEC_EIMR;
/* Mask all interrupts */
MCF_FEC_EIMR = 0;
/* Issue the Graceful Transmit Stop */
MCF_FEC_TCR |= MCF_FEC_TCR_GTS;
/* Wait for the Graceful Stop Complete interrupt */
i = 500000;
while(!(MCF_FEC_EIR & MCF_FEC_EIR_GRA))
{
if (--i == 0)
break;
}
/* Clear the Graceful Stop Complete interrupt */
MCF_FEC_EIR = MCF_FEC_EIR_GRA;
/* Restore the interrupt mask register value */
MCF_FEC_EIMR = mask;
}
/********************************************************************/
/*
* Trasmit Frame interrupt handler - this handler is called by the
* FEC/DMA interrupt handler indicating that a packet was successfully
* transferred into the Tx FIFO.
*/
void
fec_tx_handler(void)
{
FECBD *pTxBD;
NBUF *pNbuf;
while ((pTxBD = fecbd_tx_free()) != NULL)
{
/*
* Grab the network buffer associated with this buffer descriptor
*/
pNbuf = nbuf_remove(NBUF_TX_RING);
ASSERT(pNbuf);
ASSERT(pNbuf->data == pTxBD->data);
if (pTxBD->status & TX_BD_L)
fec_log.txf++;
else
fec_log.txb++;
/*
* Free up the network buffer that was just transmitted
*/
nbuf_free(pNbuf);
/*
* Re-initialize the Tx BD
*/
pTxBD->data = NULL;
pTxBD->length = 0;
}
}
/********************************************************************/
/*
* Send a packet
*
* Parameters:
* nif Pointer to Network Interface (NIF) structure
* dst Destination MAC Address
* src Source MAC Address
* type Ethernet Frame Type
* nbuf Pointer to the network buffer
*
* Return Value:
* 1 success
* 0 otherwise
*/
int
fec_send (NIF *nif, uint8 *dst, uint8 *src, uint16 type, NBUF *nbuf)
{
FECBD *pTxBD;
(void) nif;
/* Check the length */
if ((nbuf->length + ETH_HDR_LEN) > ETH_MTU)
return 0;
/*
* Copy the destination address, source address, and Ethernet
* type into the packet
*/
memcpy(&nbuf->data[0], dst, 6);
memcpy(&nbuf->data[6], src, 6);
memcpy(&nbuf->data[12], &type, 2);
/*
* Grab the next available Tx Buffer Descriptor
*/
if ((pTxBD = fecbd_tx_alloc()) == NULL)
return 0;
/*
* Put the network buffer into the Tx waiting queue
*/
nbuf_add(NBUF_TX_RING, nbuf);
/*
* Setup the buffer descriptor for transmission
*/
pTxBD->data = nbuf->data;
pTxBD->length = nbuf->length + ETH_HDR_LEN;
pTxBD->status |= (TX_BD_R | TX_BD_L | TX_BD_TC);
/*
* Continue the Tx DMA task (in case it was waiting for a new
* TxBD to be ready)
*/
fec_tx_continue();
return 1;
}
/********************************************************************/
/*
* Resend the last packet that was already prepared and sent
*/
void
fec_resend (void)
{
FECBD *pTxBD;
NBUF *pNbuf;
/*
* Grab the most recently sent TxBD
*/
pTxBD = fecbd_tx_free();
ASSERT(pTxBD != NULL);
/*
* Grab the network buffer associated with this buffer descriptor
*/
pNbuf = nbuf_remove(NBUF_TX_RING);
ASSERT(pNbuf);
ASSERT(pNbuf->data == pTxBD->data);
/*
* Grab the next available Tx Buffer Descriptor
*/
while ((pTxBD = fecbd_tx_alloc()) == NULL)
;
/*
* Put the network buffer back into the Tx waiting queue
*/
nbuf_add(NBUF_TX_RING, pNbuf);
/*
* Reset the TxBD status flags
*/
pTxBD->data = pNbuf->data;
pTxBD->length = pNbuf->length + ETH_HDR_LEN;
pTxBD->status |= (TX_BD_R | TX_BD_L | TX_BD_TC);
/*
* Continue the Tx DMA task (in case it was waiting for a new
* TxBD to be ready)
*/
fec_tx_continue();
}
/********************************************************************/
/*
* Enable interrupts from the FEC
*/
void
fec_irq_enable(void)
{
/*
* Clear any pending FEC interrupt events
*/
MCF_FEC_EIR = MCF_FEC_EIR_CLEAR_ALL;
/*
* Unmask all FEC interrupts
*/
MCF_FEC_EIMR = MCF_FEC_EIMR_UNMASK_ALL;
}
/********************************************************************/
/*
* Disable interrupts from the FEC
*/
void
fec_irq_disable(void)
{
/*
* Mask all FEC interrupts
*/
MCF_FEC_EIMR = MCF_FEC_EIMR_MASK_ALL;
}
/********************************************************************/
/*
* FEC interrupt handler
*/
int
fec_irq_handler(void* arg1, void* arg2)
{
uint32 event, eir;
(void) arg2;
/*
* Determine which interrupt(s) asserted by AND'ing the
* pending interrupts with those that aren't masked.
*/
eir = MCF_FEC_EIR;
event = eir & MCF_FEC_EIMR;
#ifdef DEBUG
if (event != eir)
printf("Pending but not enabled: 0x%08X\n",(event ^ eir));
#endif
/*
* Clear the event(s) in the EIR immediately
*/
MCF_FEC_EIR = event;
if (event & MCF_FEC_EIR_UN)
{
fec_log.errors++;
fec_log.un++;
#ifdef DEBUG
printf("FEC Tx FIFO Underflow\n");
#endif
}
if (event & MCF_FEC_EIR_RL)
{
fec_log.errors++;
fec_log.rl++;
#ifdef DEBUG
printf("FEC Collision Retry Limit\n");
#endif
fec_resend();
}
if (event & MCF_FEC_EIR_LC)
{
fec_log.errors++;
fec_log.lc++;
#ifdef DEBUG
printf("FEC Late Collision\n");
#endif
fec_resend();
}
if (event & MCF_FEC_EIR_EBERR)
{
fec_log.errors++;
fec_log.eberr++;
#ifdef DEBUG
printf("FEC/DMA fatal bus error!\n");
#endif
fec_eth_stop();
}
if (event & MCF_FEC_EIR_MII)
{
fec_log.mii++;
}
if (event & MCF_FEC_EIR_RXB || event & MCF_FEC_EIR_RXF)
{
fec_rx_handler((NIF *)arg1);
}
if (event & MCF_FEC_EIR_TXB || event & MCF_FEC_EIR_TXF)
{
fec_tx_handler();
}
if (event & MCF_FEC_EIR_GRA)
{
fec_log.gra++;
}
if (event & MCF_FEC_EIR_BABT)
{
fec_log.errors++;
fec_log.babt++;
#ifdef DEBUG
printf("FEC Babbling transmit error\n");
#endif
}
if (event & MCF_FEC_EIR_BABR)
{
fec_log.errors++;
fec_log.babr++;
#ifdef DEBUG
printf("FEC Babbling receive error\n");
#endif
}
if (event & MCF_FEC_EIR_HBERR)
{
fec_log.errors++;
fec_log.hberr++;
#ifdef DEBUG
printf("HBERR\n");
#endif
}
return TRUE;
}
/********************************************************************/
/*
* Configure the selected Ethernet port and enable all operations
*
* Parameters:
* trcvr Transceiver mode (MII, 7-Wire or internal loopback)
* mac Physical (MAC) Address
*/
void
fec_eth_setup(uint8 trcvr, const uint8 *mac)
{
/*
* Disable FEC interrupts
*/
fec_irq_disable();
/*
* Initialize the event log
*/
fec_log_init();
/*
* Initialize the network buffers and fec buffer descriptors
*/
nbuf_init();
fecbd_init();
/*
* Initialize the FEC
*/
fec_reset();
fec_init(trcvr,mac);
if (trcvr == FEC_MODE_MII)
{
/*
* Initialize the MII interface
*/
fec_mii_init(SYSTEM_CLOCK);
}
/*
* Initialize and enable FEC interrupts
*/
fec_irq_enable();
/*
* Enable the FEC channel
*/
MCF_FEC_ECR |= MCF_FEC_ECR_ETHER_EN;
/*
* Start the Rx FEC DMA
*/
fec_rx_continue();
}
/********************************************************************/
/*
* Reset the Ethernet port
*/
void
fec_eth_reset(void)
{
fec_reset();
}
/********************************************************************/
/*
* Stop the Ethernet port
*/
void
fec_eth_stop(void)
{
int level;
/*
* Disable interrupts
*/
level = asm_set_ipl(7);
/*
* Disable FEC interrupts
*/
fec_irq_disable();
/*
* Gracefully disable the transmitter
*/
fec_tx_stop();
/*
* Disable the FEC channel
*/
MCF_FEC_ECR &= ~MCF_FEC_ECR_ETHER_EN;
#ifdef DEBUG
nbuf_debug_dump();
fecbd_dump();
fec_log_dump();
#endif
/*
* Flush the network buffers
*/
nbuf_flush();
/*
* Restore interrupt level
*/
asm_set_ipl(level);
}
/********************************************************************/
#endif /* #ifdef DBUG_NETWORK */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -