📄 fec.c
字号:
* 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;
/*
* Set Rx FIFO alarm and granularity
*/
MCF_FEC_FECRFCR(ch) = 0
| MCF_FEC_FECRFCR_FRM
| MCF_FEC_FECRFCR_RXW_MSK
| MCF_FEC_FECRFCR_GR(7);
MCF_FEC_FECRFAR(ch) = MCF_FEC_FECRFAR_ALARM(768);
/*
* Set Tx FIFO watermark, alarm and granularity
*/
MCF_FEC_FECTFCR(ch) = 0
| MCF_FEC_FECTFCR_FRM
| MCF_FEC_FECTFCR_TXW_MSK
| MCF_FEC_FECTFCR_GR(7);
MCF_FEC_FECTFAR(ch) = MCF_FEC_FECTFAR_ALARM(256);
MCF_FEC_FECTFWR(ch) = MCF_FEC_FECTFWR_X_WMRK_256;
/*
* Enable the transmitter to append the CRC
*/
MCF_FEC_CTCWR(ch) = 0
| MCF_FEC_CTCWR_TFCW
| MCF_FEC_CTCWR_CRC;
}
/********************************************************************/
/*
* Start the FEC Rx DMA task
*
* Parameters:
* ch FEC channel
* rxbd First Rx buffer descriptor in the chain
*/
void
fec_rx_start(uint8 ch, int8 *rxbd)
{
uint32 initiator;
int channel, result;
ASSERT(ch == 0 || ch == 1);
/*
* Make the initiator assignment
*/
result = dma_set_initiator(DMA_FEC_RX(ch));
ASSERT(result == 0);
/*
* Grab the initiator number
*/
initiator = dma_get_initiator(DMA_FEC_RX(ch));
/*
* Determine the DMA channel running the task for the
* selected FEC
*/
channel = dma_set_channel(DMA_FEC_RX(ch),
(ch == 0) ? fec0_rx_frame : fec1_rx_frame);
ASSERT(channel != -1);
/*
* Start the Rx DMA task
*/
/*
* Start the Rx DMA task
*/
MCD_startDma(channel,
(s8*)rxbd,
0,
(s8*)MCF_FEC_FECRFDR_ADDR(ch),
0,
RX_BUF_SZ,
0,
initiator,
FECRX_DMA_PRI(ch),
0
| MCD_FECRX_DMA
| MCD_INTERRUPT
| MCD_TT_FLAGS_CW
| MCD_TT_FLAGS_RL
| MCD_TT_FLAGS_SP
,
0
| MCD_NO_CSUM
| MCD_NO_BYTE_SWAP
);
}
/********************************************************************/
/*
* Continue the Rx DMA task
*
* This routine is called after the DMA task has halted after
* encountering an Rx buffer descriptor that wasn't marked as
* ready. There is no harm in calling the DMA continue routine
* if the DMA is not halted.
*
* Parameters:
* ch FEC channel
*/
void
fec_rx_continue(uint8 ch)
{
int channel;
ASSERT(ch == 0 || ch == 1);
/*
* Determine the DMA channel running the task for the
* selected FEC
*/
channel = dma_get_channel(DMA_FEC_RX(ch));
ASSERT(channel != -1);
/*
* Continue/restart the DMA task
*/
MCD_continDma(channel);
}
/********************************************************************/
/*
* Stop all frame receptions on the selected FEC
*
* Parameters:
* ch FEC channel
*/
void
fec_rx_stop (uint8 ch)
{
uint32 mask;
int channel;
ASSERT(ch == 0 || ch == 1);
/* Save off the EIMR value */
mask = MCF_FEC_EIMR(ch);
/* Mask all interrupts */
MCF_FEC_EIMR(ch) = 0;
/*
* Determine the DMA channel running the task for the
* selected FEC
*/
channel = dma_get_channel(DMA_FEC_RX(ch));
ASSERT(channel != -1);
/* Kill the FEC Rx DMA task */
MCD_killDma(channel);
/*
* Free up the FEC requestor from the software maintained
* initiator list
*/
dma_free_initiator(DMA_FEC_RX(ch));
/* Free up the DMA channel */
dma_free_channel(DMA_FEC_RX(ch));
/* Restore the interrupt mask register value */
MCF_FEC_EIMR(ch) = mask;
}
/********************************************************************/
/*
* Receive Frame interrupt handler - this handler is called by the
* 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_frame(uint8 ch, NIF *nif)
{
ETH_HDR *eth_hdr;
FECBD *pRxBD;
NBUF *cur_nbuf, *new_nbuf;
int keep;
while ((pRxBD = fecbd_rx_alloc(ch)) != NULL)
{
fec_log[ch].drxf++;
keep = TRUE;
/*
* Check the Receive Frame Status Word for errors
* - The L bit should always be set
* - No undefined bits should be set
* - The upper 5 bits of the length should be cleared
*/
if (!(pRxBD->status & RX_BD_L) || (pRxBD->status & 0x0608)
|| (pRxBD->length & 0xF800))
{
keep = FALSE;
fec_log[ch].rfsw_inv++;
}
else 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_PRINT
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);
}
}
}
void
fec0_rx_frame(void)
{
extern NIF nif1;
fec_rx_frame(0, &nif1);
}
void
fec1_rx_frame(void)
{
extern NIF nif1;
fec_rx_frame(1, &nif1);
}
/********************************************************************/
/*
* Start the FEC Tx DMA task
*
* Parameters:
* ch FEC channel
* txbd First Tx buffer descriptor in the chain
*/
void
fec_tx_start(uint8 ch, int8 *txbd)
{
uint32 initiator;
int channel, result;
void fec0_tx_frame(void);
void fec1_tx_frame(void);
/*
* Make the initiator assignment
*/
result = dma_set_initiator(DMA_FEC_TX(ch));
ASSERT(result == 0);
/*
* Grab the initiator number
*/
initiator = dma_get_initiator(DMA_FEC_TX(ch));
ASSERT(initiator != 0);
/*
* Determine the DMA channel running the task for the
* selected FEC
*/
channel = dma_set_channel(DMA_FEC_TX(ch),
(ch == 0) ? fec0_tx_frame : fec1_tx_frame);
ASSERT(channel != -1);
/*
* Start the Tx DMA task
*/
MCD_startDma(channel,
(s8*)txbd,
0,
(s8*)MCF_FEC_FECTFDR_ADDR(ch),
0,
ETH_MTU,
0,
initiator,
FECTX_DMA_PRI(ch),
0
| MCD_FECTX_DMA
| MCD_INTERRUPT
| MCD_TT_FLAGS_CW
| MCD_TT_FLAGS_RL
| MCD_TT_FLAGS_SP
,
0
| MCD_NO_CSUM
| MCD_NO_BYTE_SWAP
);
}
/********************************************************************/
/*
* Continue the Tx DMA task
*
* This routine is called after the DMA task has halted after
* encountering an 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)
{
int channel;
/*
* Determine the DMA channel running the task for the
* selected FEC
*/
channel = dma_get_channel(DMA_FEC_TX(ch));
ASSERT(channel > 0);
/*
* Continue/restart the DMA task
*/
MCD_continDma((int)channel);
}
/********************************************************************/
/*
* Stop all transmissions on the selected FEC and kill the DMA task
*
* Parameters:
* ch FEC channel
*/
void
fec_tx_stop (uint8 ch)
{
uint32 mask;
int channel;
ASSERT(ch == 0 || ch == 1);
/* Save off the EIMR value */
mask = MCF_FEC_EIMR(ch);
/* Mask all interrupts */
MCF_FEC_EIMR(ch) = 0;
/* If the Ethernet is still enabled... */
if (MCF_FEC_ECR(ch) & MCF_FEC_ECR_ETHER_EN)
{
/* Issue the Graceful Transmit Stop */
MCF_FEC_TCR(ch) |= MCF_FEC_TCR_GTS;
/* Wait for the Graceful Stop Complete interrupt */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -