📄 mcf5xxx_fecx.c
字号:
else
MCF_FEC_IALR(ch) |= (uint32)(1 << crc);
}
/********************************************************************/
/*
* Reset the selected FEC controller
*
* Parameters:
* ch FEC channel
*/
void
fec_reset (uint8 ch)
{
int i;
#if (FEC_NUM_CH == 1)
ch = 0;
#else
ASSERT(ch < FEC_NUM_CH);
#endif
/* Set the Reset bit and clear the Enable bit */
MCF_FEC_ECR(ch) = MCF_FEC_ECR_RESET;
/* Wait at least 8 clock cycles */
for (i=0; i<10; ++i)
nop();
}
/********************************************************************/
/*
* Initialize the selected FEC
*
* Parameters:
* ch FEC channel
* mode External interface mode (MII, 7-wire, or internal loopback)
* pa Physical (Hardware) Address for the selected FEC
*/
void
fec_init (uint8 ch, uint8 mode, const uint8 *pa)
{
#if (FEC_NUM_CH == 1)
ch = 0;
#else
ASSERT(ch < FEC_NUM_CH);
#endif
/*
* Clear the Individual and Group Address Hash registers
*/
MCF_FEC_IALR(ch) = 0;
MCF_FEC_IAUR(ch) = 0;
MCF_FEC_GALR(ch) = 0;
MCF_FEC_GAUR(ch) = 0;
/*
* Set the Physical Address for the selected FEC
*/
fec_set_address(ch, pa);
/*
* Set Rx Buffer Size
*/
MCF_FEC_EMRBR(ch) = (uint16)RX_BUF_SZ;
/*
* Point to the start of the circular Rx buffer descriptor queue
*/
MCF_FEC_ERDSR(ch) = fecbd_get_start(Rx);
/*
* Point to the start of the circular Tx buffer descriptor queue
*/
MCF_FEC_ETDSR(ch) = fecbd_get_start(Tx);
/*
* Mask all FEC interrupts
*/
MCF_FEC_EIMR(ch) = MCF_FEC_EIMR_MASK_ALL;
/*
* Clear all FEC interrupt events
*/
MCF_FEC_EIR(ch) = MCF_FEC_EIR_CLEAR_ALL;
/*
* Initialize the Receive Control Register
*/
MCF_FEC_RCR(ch) = 0
| MCF_FEC_RCR_MAX_FL(ETH_MAX_FRM)
#ifdef FEC_PROMISCUOUS
| MCF_FEC_RCR_PROM
#endif
| MCF_FEC_RCR_FCE;
if (mode == FEC_MODE_MII)
MCF_FEC_RCR(ch) |= MCF_FEC_RCR_MII_MODE;
else if (mode == FEC_MODE_LOOPBACK)
MCF_FEC_RCR(ch) |= MCF_FEC_RCR_LOOP;
/*
* Initialize the Transmit Control Register
*/
MCF_FEC_TCR(ch) = MCF_FEC_TCR_FDEN;
}
/********************************************************************/
/*
* Continue the Rx FEC DMA
*
* This routine is called after the DMA has halted after
* encountering a Rx buffer descriptor that wasn't marked as
* empty. There is no harm in calling the continue DMA routine
* if the DMA was not paused.
*
* Parameters:
* ch FEC channel
*/
void
fec_rx_continue(uint8 ch)
{
/*
* Continue/restart the FEC DMA
*/
MCF_FEC_RDAR(ch) = MCF_FEC_RDAR_R_DES_ACTIVE;
}
/********************************************************************/
/*
* Receive Frame interrupt handler - this handler is called by the
* FEC/DMA interrupt handler indicating that a packet was successfully
* transferred out of the Rx FIFO.
*
* Parameters:
* nif Pointer to Network Interface structure
* ch FEC channel
*/
void
fec_rx_handler(NIF *nif)
{
ETH_HDR *eth_hdr;
FECBD *pRxBD;
NBUF *cur_nbuf, *new_nbuf;
uint8 ch = (uint8)nif->ch;
int keep;
while ((pRxBD = fecbd_rx_alloc()) != NULL)
{
keep = TRUE;
if (pRxBD->status & RX_BD_L)
fec_log[ch].rxf++;
else
fec_log[ch].rxb++;
if (pRxBD->status & RX_BD_ERROR)
{
keep = FALSE;
if (pRxBD->status & RX_BD_NO)
fec_log[ch].rfsw_no++;
if (pRxBD->status & RX_BD_CR)
fec_log[ch].rfsw_cr++;
if (pRxBD->status & RX_BD_OV)
fec_log[ch].rfsw_ov++;
if (pRxBD->status & RX_BD_TR)
fec_log[ch].rfsw_tr++;
}
else
{
if (pRxBD->status & RX_BD_LG)
fec_log[ch].rfsw_lg++;
if (pRxBD->status & RX_BD_M)
fec_log[ch].rfsw_m++;
if (pRxBD->status & RX_BD_BC)
fec_log[ch].rfsw_bc++;
if (pRxBD->status & RX_BD_MC)
fec_log[ch].rfsw_mc++;
}
if (keep)
{
/*
* Pull the network buffer off the Rx ring queue
*/
cur_nbuf = nbuf_remove(NBUF_RX_RING);
ASSERT(cur_nbuf);
ASSERT(cur_nbuf->data == pRxBD->data);
/*
* Copy the buffer descriptor information to the network buffer
*/
cur_nbuf->length = (pRxBD->length - (ETH_HDR_LEN + ETH_CRC_LEN));
cur_nbuf->offset = ETH_HDR_LEN;
/*
* Get a new buffer pointer for this buffer descriptor
*/
new_nbuf = nbuf_alloc();
if (new_nbuf == NULL)
{
#ifdef DEBUG
printf("nbuf_alloc() failed\n");
#endif
/*
* Can't allocate a new network buffer, so we
* 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(ch);
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(ch);
/*
* 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(ch);
}
}
}
/********************************************************************/
/*
* 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.
*
* Parameters:
* ch FEC channel
*/
void
fec_tx_continue(uint8 ch)
{
#if (FEC_NUM_CH == 1)
ch = 0;
#else
ASSERT(ch < FEC_NUM_CH);
#endif
/*
* Continue/restart the FEC DMA
*/
MCF_FEC_TDAR(ch) = MCF_FEC_TDAR_X_DES_ACTIVE;
}
/********************************************************************/
/*
* Stop all transmissions on the selected FEC and kill the DMA task
*
* Parameters:
* ch FEC channel
*/
void
fec_tx_stop (uint8 ch)
{
int i;
uint32 mask;
#if (FEC_NUM_CH == 1)
ch = 0;
#else
ASSERT(ch < FEC_NUM_CH);
#endif
/* Save off the EIMR value */
mask = MCF_FEC_EIMR(ch);
/* Mask all interrupts */
MCF_FEC_EIMR(ch) = 0;
/* Issue the Graceful Transmit Stop */
MCF_FEC_TCR(ch) |= MCF_FEC_TCR_GTS;
/* Wait for the Graceful Stop Complete interrupt */
i = 500000;
while(!(MCF_FEC_EIR(ch) & MCF_FEC_EIR_GRA))
{
if (--i == 0)
break;
}
/* Clear the Graceful Stop Complete interrupt */
MCF_FEC_EIR(ch) = MCF_FEC_EIR_GRA;
/* Restore the interrupt mask register value */
MCF_FEC_EIMR(ch) = 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.
*
* Parameters:
* nif NIF structure
*/
void
fec_tx_handler(NIF *nif)
{
uint32 event, eir;
uint8 ch = (uint8)nif->ch;
FECBD *pTxBD;
NBUF *pNbuf;
ASSERT(ch < FEC_NUM_CH);
/*
* Determine which interrupt(s) asserted by AND'ing the
* pending interrupts with those that aren't masked.
*/
eir = MCF_FEC_EIR(ch);
event = eir & MCF_FEC_EIMR(ch);
#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(ch) = event;
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[ch].txf++;
else
fec_log[ch].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 out the selected FEC
*
* Parameters:
* ch FEC channel
* nif Pointer to Network Interface (NIF) structure
* dst Destination MAC Address
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -