📄 mcf5xxx_fecx.c
字号:
/*
* File: fecx.c
* Purpose: Driver for the Fast Ethernet Controller (FEC)
*
* Notes: For use with processors featuring multiple
* ethernet controllers
*/
//#include "src/include/dbug.h"
#include "..\..\..\control.h"
#include "..\m5271evb.h"
#include "..\mcf5xxx.h"
#include "..\mcf5271.h"
#include "..\..\..\uif\net\Nbuf.h"
#include "..\..\..\uif\net\eth.h"
#include "..\..\..\uif\net\nif.h"
#include "mcf5xxx_fecx.h"
#include "mcf5xxx_fecbd.h"
#include "..\mcf5271\mcf5271_fec.h"
#ifdef DBUG_NETWORK
/*
* Number of FEC channels supported
*/
#ifndef FEC_NUM_CH
#define FEC_NUM_CH 1
#endif
/********************************************************************/
FEC_EVENT_LOG fec_log[FEC_NUM_CH];
/********************************************************************/
/*
* Write a value to a PHY's MII register.
*
* Parameters:
* ch FEC channel
* phy_addr Address of the PHY.
* reg_addr Address of the register in the PHY.
* data Data to be written to the PHY register.
*
* Return Values:
* 1 on failure
* 0 on success.
*
* Please refer to your PHY manual for registers and their meanings.
* mii_write() polls for the FEC's MII interrupt event (which should
* be masked from the interrupt handler) and clears it. If after a
* suitable amount of time the event isn't triggered, a value of 0
* is returned.
*/
int
fec_mii_write(uint8 ch, uint8 phy_addr, uint8 reg_addr, uint16 data)
{
int timeout;
uint32 eimr;
#if (FEC_NUM_CH == 1)
ch = 0;
#else
ASSERT(ch < FEC_NUM_CH);
#endif
/*
* Clear the MII interrupt bit
*/
// MCF_FEC_EIR = MCF_FEC_EIR_MII;
MCF_FEC_EIR(ch) = MCF_FEC_EIR_MII;
/*
* Write to the MII Management Frame Register to kick-off
* the MII write
*/
MCF_FEC_MMFR(ch) = 0
| MCF_FEC_MMFR_ST_01
| MCF_FEC_MMFR_OP_WRITE
| MCF_FEC_MMFR_PA(phy_addr)
| MCF_FEC_MMFR_RA(reg_addr)
| MCF_FEC_MMFR_TA_10
| MCF_FEC_MMFR_DATA(data);
/*
* Mask the MII interrupt
*/
eimr = MCF_FEC_EIMR(ch);
MCF_FEC_EIMR(ch) &= ~MCF_FEC_EIMR_MII;
/*
* Poll for the MII interrupt (interrupt should be masked)
*/
for (timeout = 0; timeout < FEC_MII_TIMEOUT; timeout++)
{
if (MCF_FEC_EIR(ch) & MCF_FEC_EIR_MII)
break;
}
if(timeout == FEC_MII_TIMEOUT)
return 1;
/*
* Clear the MII interrupt bit
*/
MCF_FEC_EIR(ch) = MCF_FEC_EIR_MII;
/*
* Restore the EIMR
*/
MCF_FEC_EIMR(ch) = eimr;
return 0;
}
/********************************************************************/
/*
* Read a value from a PHY's MII register.
*
* Parameters:
* ch FEC channel
* phy_addr Address of the PHY.
* reg_addr Address of the register in the PHY.
* data Pointer to storage for the Data to be read
* from the PHY register (passed by reference)
*
* Return Values:
* 1 on failure
* 0 on success.
*
* Please refer to your PHY manual for registers and their meanings.
* mii_read() polls for the FEC's MII interrupt event (which should
* be masked from the interrupt handler) and clears it. If after a
* suitable amount of time the event isn't triggered, a value of 0
* is returned.
*/
int
fec_mii_read(uint8 ch, uint8 phy_addr, uint8 reg_addr, uint16 *data)
{
int timeout;
#if (FEC_NUM_CH == 1)
ch = 0;
#else
ASSERT(ch < FEC_NUM_CH);
#endif
/*
* Clear the MII interrupt bit
*/
MCF_FEC_EIR(ch) = MCF_FEC_EIR_MII;
/*
* Write to the MII Management Frame Register to kick-off
* the MII read
*/
MCF_FEC_MMFR(ch) = 0
| MCF_FEC_MMFR_ST_01
| MCF_FEC_MMFR_OP_READ
| MCF_FEC_MMFR_PA(phy_addr)
| MCF_FEC_MMFR_RA(reg_addr)
| MCF_FEC_MMFR_TA_10;
/*
* Poll for the MII interrupt (interrupt should be masked)
*/
for (timeout = 0; timeout < FEC_MII_TIMEOUT; timeout++)
{
if (MCF_FEC_EIR(ch) & MCF_FEC_EIR_MII)
break;
}
if(timeout == FEC_MII_TIMEOUT)
return 1;
/*
* Clear the MII interrupt bit
*/
MCF_FEC_EIR(ch) = MCF_FEC_EIR_MII;
*data = (uint16)(MCF_FEC_MMFR(ch) & 0x0000FFFF);
return 0;
}
/********************************************************************/
/*
* Initialize the MII interface controller
*
* Parameters:
* ch FEC channel
* sys_clk System Clock Frequency (in MHz)
*/
void
fec_mii_init(uint8 ch, uint32 sys_clk)
{
#if (FEC_NUM_CH == 1)
ch = 0;
#else
ASSERT(ch < FEC_NUM_CH);
#endif
/*
* Initialize the MII clock (EMDC) frequency
*
* Desired MII clock is 2.5MHz
* MII Speed Setting = System_Clock / (2.5MHz * 2)
* (plus 1 to make sure we round up)
*/
MCF_FEC_MSCR(ch) = MCF_FEC_MSCR_MII_SPEED((sys_clk/5)+1);
}
/********************************************************************/
/* Initialize the MIB counters
*
* Parameters:
* ch FEC channel
*/
void
fec_mib_init(uint8 ch)
{
#if (FEC_NUM_CH == 1)
ch = 0;
#else
ASSERT(ch < FEC_NUM_CH);
#endif
//To do
}
/********************************************************************/
/* Display the MIB counters
*
* Parameters:
* ch FEC channel
*/
void
fec_mib_dump(uint8 ch)
{
#if (FEC_NUM_CH == 1)
ch = 0;
#else
ASSERT(ch < FEC_NUM_CH);
#endif
//To do
}
/********************************************************************/
/* Initialize the FEC log
*
* Parameters:
* ch FEC channel
*/
void
fec_log_init(uint8 ch)
{
#if (FEC_NUM_CH == 1)
ch = 0;
#else
ASSERT(ch < FEC_NUM_CH);
#endif
memset(&fec_log[ch],0,sizeof(FEC_EVENT_LOG));
}
/********************************************************************/
/* Display the FEC log
*
* Parameters:
* ch FEC channel
*/
void
fec_log_dump(uint8 ch)
{
#if (FEC_NUM_CH == 1)
ch = 0;
#else
ASSERT(ch < FEC_NUM_CH);
#endif
#if 0
ASSERT(ch < FEC_NUM_CH);
printf("\n FEC%d Log\n---------------\n",ch);
printf("Total: %4d\n",fec_log[ch].errors);
printf("hberr: %4d\n",fec_log[ch].hberr);
printf("babr: %4d\n",fec_log[ch].babr);
printf("babt: %4d\n",fec_log[ch].babt);
printf("gra: %4d\n",fec_log[ch].gra);
printf("txf: %4d\n",fec_log[ch].txf);
printf("txb: %4d\n",fec_log[ch].txb);
printf("rxf: %4d\n",fec_log[ch].rxf);
printf("rxb: %4d\n",fec_log[ch].rxb);
printf("mii: %4d\n",fec_log[ch].mii);
printf("eberr: %4d\n",fec_log[ch].eberr);
printf("lc: %4d\n",fec_log[ch].lc);
printf("rl: %4d\n",fec_log[ch].rl);
printf("un: %4d\n",fec_log[ch].un);
printf("\nRFSW:\n");
printf("inv: %4d\n",fec_log[ch].rfsw_inv);
printf("l: %4d\n",fec_log[ch].rfsw_l);
printf("m: %4d\n",fec_log[ch].rfsw_m);
printf("bc: %4d\n",fec_log[ch].rfsw_bc);
printf("mc: %4d\n",fec_log[ch].rfsw_mc);
printf("lg: %4d\n",fec_log[ch].rfsw_lg);
printf("no: %4d\n",fec_log[ch].rfsw_no);
printf("cr: %4d\n",fec_log[ch].rfsw_cr);
printf("ov: %4d\n",fec_log[ch].rfsw_ov);
printf("tr: %4d\n",fec_log[ch].rfsw_tr);
printf("---------------\n\n");
#endif
}
/********************************************************************/
/*
* Display some of the registers for debugging
*
* Parameters:
* ch FEC channel
*/
void
fec_debug_dump(uint8 ch)
{
#ifdef DEBUG
#if (FEC_NUM_CH == 1)
ch = 0;
#else
ASSERT(ch < FEC_NUM_CH);
#endif
#if 0
printf("\n------------- FEC%d -------------\n");
printf("EIR %08x \n",MCF_FEC_EIR(ch));
printf("EIMR %08x \n",MCF_FEC_EIMR(ch));
printf("ECR %08x \n",MCF_FEC_ECR(ch));
printf("RCR %08x \n",MCF_FEC_RCR(ch));
printf("TCR %08x \n",MCF_FEC_TCR(ch));
printf("--------------------------------\n\n");
#endif
#endif
}
/********************************************************************/
/*
* Set the duplex on the selected FEC controller
*
* Parameters:
* ch FEC channel
* duplex FEC_MII_FULL_DUPLEX or FEC_MII_HALF_DUPLEX
*/
void
fec_duplex (uint8 ch, uint8 duplex)
{
#if (FEC_NUM_CH == 1)
ch = 0;
#else
ASSERT(ch < FEC_NUM_CH);
#endif
switch (duplex)
{
case FEC_MII_HALF_DUPLEX:
MCF_FEC_RCR(ch) |= MCF_FEC_RCR_DRT;
MCF_FEC_TCR(ch) &= (uint32)~MCF_FEC_TCR_FDEN;
break;
case FEC_MII_FULL_DUPLEX:
default:
MCF_FEC_RCR(ch) &= (uint32)~MCF_FEC_RCR_DRT;
MCF_FEC_TCR(ch) |= MCF_FEC_TCR_FDEN;
break;
}
}
/********************************************************************/
/*
* Generate the hash table settings for the given address
*
* Parameters:
* addr 48-bit (6 byte) Address to generate the hash for
*
* Return Value:
* The 6 most significant bits of the 32-bit CRC result
*/
uint8
fec_hash_address(const uint8 *addr)
{
uint32 crc;
uint8 byte;
int i, j;
crc = 0xFFFFFFFF;
for(i=0; i<6; ++i)
{
byte = addr[i];
for(j=0; j<8; ++j)
{
if((byte & 0x01)^(crc & 0x01))
{
crc >>= 1;
crc = crc ^ 0xEDB88320;
}
else
crc >>= 1;
byte >>= 1;
}
}
return (uint8)(crc >> 26);
}
/********************************************************************/
/*
* Set the Physical (Hardware) Address and the Individual Address
* Hash in the selected FEC
*
* Parameters:
* ch FEC channel
* pa Physical (Hardware) Address for the selected FEC
*/
void
fec_set_address (uint8 ch, const uint8 *pa)
{
uint8 crc;
#if (FEC_NUM_CH == 1)
ch = 0;
#else
ASSERT(ch < FEC_NUM_CH);
#endif
/*
* Set the Physical Address
*/
MCF_FEC_PALR(ch) = (uint32)((pa[0]<<24)|(pa[1]<<16)|(pa[2]<<8)|pa[3]);
MCF_FEC_PAUR(ch) = (uint32)((pa[4]<<24)|(pa[5]<<16));
/*
* Calculate and set the hash for given Physical Address
* in the Individual Address Hash registers
*/
crc = fec_hash_address(pa);
if(crc >= 32)
MCF_FEC_IAUR(ch) |= (uint32)(1 << (crc - 32));
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -