📄 fec.c
字号:
while(!(MCF_FEC_EIR(ch) & MCF_FEC_EIR_GRA))
{
if (!(MCF_FEC_ECR(ch) & MCF_FEC_ECR_ETHER_EN))
break;
}
/* Clear the Graceful Stop Complete interrupt */
MCF_FEC_EIR(ch) = MCF_FEC_EIR_GRA;
}
/*
* Determine the DMA channel running the task for the
* selected FEC
*/
channel = dma_get_channel(DMA_FEC_TX(ch));
ASSERT(channel > 0);
/* Kill the FEC Tx DMA task */
MCD_killDma(channel);
/*
* Free up the FEC requestor from the software maintained
* initiator list
*/
dma_free_initiator(DMA_FEC_TX(ch));
/* Free up the DMA channel */
dma_free_channel(DMA_FEC_TX(ch));
/* Restore the interrupt mask register value */
MCF_FEC_EIMR(ch) = mask;
}
/********************************************************************/
/*
* Trasmit Frame interrupt handler - this handler is called by the
* DMA interrupt handler indicating that a packet was successfully
* transferred to the Tx FIFO.
*
* Parameters:
* ch FEC channel
*/
void
fec_tx_frame(uint8 ch)
{
FECBD *pTxBD;
NBUF *pNbuf;
while ((pTxBD = fecbd_tx_free(ch)) != NULL)
{
fec_log[ch].dtxf++;
/*
* Grab the network buffer associated with this buffer descriptor
*/
pNbuf = nbuf_remove(NBUF_TX_RING);
ASSERT(pNbuf);
ASSERT(pNbuf->data == pTxBD->data);
/*
* Free up the network buffer that was just transmitted
*/
nbuf_free(pNbuf);
/*
* Re-initialize the Tx BD
*/
pTxBD->data = NULL;
pTxBD->length = 0;
}
}
void
fec0_tx_frame(void)
{
fec_tx_frame(0);
}
void
fec1_tx_frame(void)
{
fec_tx_frame(1);
}
/********************************************************************/
/*
* Send a packet out the selected FEC
*
* Parameters:
* ch FEC channel
* nif Pointer to Network Interface (NIF) structure
* dst Destination MAC Address
* src Source MAC Address
* type Ethernet Frame Type
* length Number of bytes to be transmitted (doesn't include type,
* src, or dest byte count)
* pkt Pointer packet network buffer
*
* Return Value:
* 1 success
* 0 otherwise
*/
int
fec_send (uint8 ch, NIF *nif, uint8 *dst, uint8 *src, uint16 type, NBUF *nbuf)
{
FECBD *pTxBD;
ASSERT(ch == 0 || ch == 1);
/* 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
*/
while ((pTxBD = fecbd_tx_alloc(ch)) == NULL) {};
/*
* 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);
/*
* Continue the Tx DMA task (in case it was waiting for a new
* TxBD to be ready
*/
fec_tx_continue(ch);
return 1;
}
int
fec0_send(NIF *nif, uint8 *dst, uint8 *src, uint16 type, NBUF *nbuf)
{
return fec_send(0, nif, dst, src, type, nbuf);
}
int
fec1_send(NIF *nif, uint8 *dst, uint8 *src, uint16 type, NBUF *nbuf)
{
return fec_send(1, nif, dst, src, type, nbuf);
}
/********************************************************************/
/*
* Enable interrupts on the selected FEC
*
* Parameters:
* ch FEC channel
* pri Interrupt Priority
* lvl Interrupt Level
*/
void
fec_irq_enable(uint8 ch, uint8 lvl, uint8 pri)
{
ASSERT(ch == 0 || ch == 1);
ASSERT(lvl > 0 && lvl < 8);
ASSERT(pri < 8);
/*
* Setup the appropriate ICR
*/
MCF_INTC_ICRn((ch == 0) ? 39 : 38) = (uint8)(0
| MCF_INTC_ICRn_IP(pri)
| MCF_INTC_ICRn_IL(lvl));
/*
* Clear any pending FEC interrupt events
*/
MCF_FEC_EIR(ch) = MCF_FEC_EIR_CLEAR_ALL;
/*
* Unmask all FEC interrupts
*/
MCF_FEC_EIMR(ch) = MCF_FEC_EIMR_UNMASK_ALL;
/*
* Unmask the FEC interrupt in the interrupt controller
*/
if (ch == 0)
MCF_INTC_IMRH &= ~MCF_INTC_IMRH_INT_MASK39;
else
MCF_INTC_IMRH &= ~MCF_INTC_IMRH_INT_MASK38;
}
/********************************************************************/
/*
* Disable interrupts on the selected FEC
*
* Parameters:
* ch FEC channel
*/
void
fec_irq_disable(uint8 ch)
{
ASSERT(ch == 0 || ch == 1);
/*
* Mask all FEC interrupts
*/
MCF_FEC_EIMR(ch) = MCF_FEC_EIMR_MASK_ALL;
/*
* Mask the FEC interrupt in the interrupt controller
*/
if (ch == 0)
MCF_INTC_IMRH |= MCF_INTC_IMRH_INT_MASK39;
else
MCF_INTC_IMRH |= MCF_INTC_IMRH_INT_MASK38;
}
/********************************************************************/
/*
* FEC interrupt handler
* All interrupts are multiplexed into a single vector for each
* FEC module. The lower level interrupt handler passes in the
* channel to this handler. Note that the receive interrupt is
* generated by the Multi-channel DMA FEC Rx task.
*
* Parameters:
* ch FEC channel
*/
static void
fec_irq_handler(uint8 ch)
{
uint32 event, eir;
/*
* 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;
if (event & MCF_FEC_EIR_RFERR)
{
fec_log[ch].total++;
fec_log[ch].rferr++;
#ifdef DEBUG
printf("RFERR\n");
printf("FECRFSR%d = 0x%08x\n",ch,MCF_FEC_FECRFSR(ch));
fec_eth_stop(ch);
#endif
}
if (event & MCF_FEC_EIR_XFERR)
{
fec_log[ch].total++;
fec_log[ch].xferr++;
#ifdef DEBUG
printf("XFERR\n");
#endif
}
if (event & MCF_FEC_EIR_XFUN)
{
fec_log[ch].total++;
fec_log[ch].xfun++;
#ifdef DEBUG
printf("XFUN\n");
fec_eth_stop(ch);
#endif
}
if (event & MCF_FEC_EIR_RL)
{
fec_log[ch].total++;
fec_log[ch].rl++;
#ifdef DEBUG
printf("RL\n");
#endif
}
if (event & MCF_FEC_EIR_LC)
{
fec_log[ch].total++;
fec_log[ch].lc++;
#ifdef DEBUG
printf("LC\n");
#endif
}
if (event & MCF_FEC_EIR_MII)
{
fec_log[ch].mii++;
}
if (event & MCF_FEC_EIR_TXF)
{
fec_log[ch].txf++;
}
if (event & MCF_FEC_EIR_GRA)
{
fec_log[ch].gra++;
}
if (event & MCF_FEC_EIR_BABT)
{
fec_log[ch].total++;
fec_log[ch].babt++;
#ifdef DEBUG
printf("BABT\n");
#endif
}
if (event & MCF_FEC_EIR_BABR)
{
fec_log[ch].total++;
fec_log[ch].babr++;
#ifdef DEBUG
printf("BABR\n");
#endif
}
if (event & MCF_FEC_EIR_HBERR)
{
fec_log[ch].total++;
fec_log[ch].hberr++;
#ifdef DEBUG
printf("HBERR\n");
#endif
}
}
int
fec0_interrupt_handler(void* arg1, void* arg2)
{
(void) arg1;
(void) arg2;
fec_irq_handler(0);
return 1;
}
int
fec1_interrupt_handler(void* arg1, void* arg2)
{
(void) arg1;
(void) arg2;
fec_irq_handler(1);
return 1;
}
/********************************************************************/
/*
* Configure the selected Ethernet port and enable all operations
*
* Parameters:
* ch FEC channel
* trcvr Transceiver mode (MII, 7-Wire or internal loopback)
* speed Maximum operating speed (MII only)
* duplex Full or Half-duplex (MII only)
* mac Physical (MAC) Address
*/
void
fec_eth_setup(uint8 ch, uint8 trcvr, uint8 speed, uint8 duplex, const uint8 *mac)
{
ASSERT(ch == 0 || ch == 1);
/*
* Disable FEC interrupts
*/
fec_irq_disable(ch);
/*
* Initialize the event log
*/
fec_log_init(ch);
/*
* Initialize the network buffers and fec buffer descriptors
*/
nbuf_init();
fecbd_init(ch);
/*
* Initialize the FEC
*/
fec_reset(ch);
fec_init(ch,trcvr,mac);
if (trcvr == FEC_MODE_MII)
{
/*
* Initialize the MII interface
*/
fec_mii_init(ch, SYSTEM_CLOCK);
}
/*
* Initialize and enable FEC interrupts
*/
fec_irq_enable(ch, FEC_INTC_LVL(ch), FEC_INTC_PRI(ch));
/*
* Enable the multi-channel DMA tasks
*/
fec_rx_start(ch, (int8*)fecbd_get_start(ch,Rx));
fec_tx_start(ch, (int8*)fecbd_get_start(ch,Tx));
/*
* Enable the FEC channel
*/
MCF_FEC_ECR(ch) |= MCF_FEC_ECR_ETHER_EN;
}
/********************************************************************/
/*
* Reset the selected Ethernet port
*
* Parameters:
* ch FEC channel
*/
void
fec_eth_reset(uint8 ch)
{
// To do
}
/********************************************************************/
/*
* Stop the selected Ethernet port
*
* Parameters:
* ch FEC channel
*/
void
fec_eth_stop(uint8 ch)
{
int level;
/*
* Disable interrupts
*/
level = asm_set_ipl(7);
/*
* Gracefully disable the receiver and transmitter
*/
fec_tx_stop(ch);
fec_rx_stop(ch);
/*
* Disable FEC interrupts
*/
fec_irq_disable(ch);
/*
* Disable the FEC channel
*/
MCF_FEC_ECR(ch) &= ~MCF_FEC_ECR_ETHER_EN;
#ifdef DEBUG_PRINT
nbuf_debug_dump();
fec_log_dump(ch);
#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 + -