📄 c3eth.c
字号:
/******************************************************************************
(c) COPYRIGHT 2002- by Shenzhen Allywll Information Co.,Ltd
All rights reserved.
File: c3eth.c
Desc: 2*100M ethernet Port is used by centillium A100
Modification history(no, author, date, desc)
1 luke 04-04-01 create file
2 luke 06-11-10 for centillium A100 eth Mac
******************************************************************************/
#include "syscfg.h"
#ifdef _EIA2000V7
#ifdef __cplusplus
extern "C"{
#endif
#include "aos.h"
#include "ifnet/if_pub.h"
#include "dev/dev_prot.h"
#include "cfm/cfm_pub.h"
#include "drv/eth_pub.h"
#include "iad.h"
#include "iad_packet.h"
#include "iad_chiron_defs.h"
#include "iad_brd_defs.h"
#include "iad_brd_ethphy.h"
#include "iad_queue.h"
#include "iad_ethernet.h"
#include "iad_php.h"
#include "iad_osal.h"
#include "iad_gpio.h"
#include "iad_utils.h"
#include "c3eth.h"
//#define ETH_PHP_ENABLE
ETH_DRV_IF EthIfDrv[CPU_ETH_PORT_NUM];
iad_eth_CfgBlk ethCfgBlk[CPU_ETH_PORT_NUM];
U32 g_ulEthPollTaskId = 0;
volatile U32 g_bEthPollMode = FALSE;
U32 g_ulEthHiRate = 35000; // 200字节的报文在100M以太网的流速为625000
U32 g_ulEthLowRate = 30000; // HiRate,lowRate漏桶流速阈值,避免抖动
U32 g_bMirrorFlag = FALSE;
U32 g_ulWanLinkStatus =FALSE;
U32 g_ulLanLinkStatus =FALSE;
BOOL_T g_bSoftBirdgeFlag = FALSE;
#ifdef ETH_PHP_ENABLE
iad_queueHnd g_hPhpFreeHnd,g_hPhpOverHnd,g_hPhpTaskHnd,g_hResultHnd;
#endif
/*
C3ETH 硬件队列需要ALIGN_SIZE对齐的内存块
2个网口一共8个硬件队列, 多申请一个单位内存块,用于边缘对齐
2个软件队列
*/
#define ALIGN_SIZE 1024
#define HW_QUE_MEM_SIZE (ALIGN_SIZE*10+ALIGN_SIZE)
U8 g_ucHwQueBlk[HW_QUE_MEM_SIZE];
U8 g_szBcastPacket[6]= { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF };
#define L2MAC_HASH_MAX_NUM 96
#define L2MAC_HASH_GET_VAL(Mac) ((Mac[0]+Mac[5])%L2MAC_HASH_MAX_NUM);
#define L2MAC_AGE_TIME 40 // 90s 在公司局域网很容易L2 FULL
#define L2_AGING_PERIOD 5
//这个hash表是为了快速查找L2-MAC-DstPort二层交换表对应的DstPort
HASH_TABLE_S * g_pstL2MacHashTbl;
// L2-MAC-DstPort二层交换表
L2_MAC_TABLE_S g_L2MacTable[L2MAC_HASH_MAX_NUM];
TMR g_L2AgeTmr;
/* external functions reference*/
extern U32 g_bEthBridgeFlag;
extern U32 cli_out_string ( U32 ulIndex,S8 * szString );
void *eth_get_aligned_quebuf(void)
{
void *pBuf;
static U8 ucIndex =0;
pBuf = g_ucHwQueBlk + ucIndex*ALIGN_SIZE;
// 硬件队列要求Queue Size对齐
pBuf += ALIGN_SIZE;
if( (U8*)pBuf > g_ucHwQueBlk + HW_QUE_MEM_SIZE )
{
AOS_ASSERT(0);
return NULL;
}
ucIndex++;
if( (U32)pBuf%ALIGN_SIZE )
{
// not alligned 补齐
(U32)pBuf &=(~(ALIGN_SIZE-1));
}
return pBuf;
}
void *eth_get_aligned_buff(void)
{
U8 *pbuf;
#ifdef ALIGN_2048_BUFF
pbuf = aos_dmem_alloc( MPE_ETH, SID_ETH_RBUF ,4096 );
if( pbuf )
{
pbuf += 2048;
(U32)pbuf &= (~2047);
}
#else
pbuf = aos_dmem_alloc( MPE_ETH, SID_ETH_RBUF , ETH_RECV_BUF_LEN);
#endif
return pbuf;
}
/**** ALIGNED MEM TEST ,luke ************************
U8 g_ucHwEthMem[2*N_FREE_PKTS+1][PKT_BUFFER_SIZE];
void *eth_get_aligned_mem(void)
{
void *pBaseBuf,*pbuf;
static U8 ucIndex =0;
pBaseBuf = (void*)IAD_ENFORCE_ALIGNMENT(g_ucHwEthMem,PKT_BUFFER_SIZE);
pbuf = pBaseBuf + ucIndex*PKT_BUFFER_SIZE;
if( ucIndex > 2*N_FREE_PKTS )
{
AOS_ASSERT(0);
return NULL;
}
ucIndex++;
return pbuf;
}
**************************************/
U32 eth_add_freeq_buff( U32 EthNum )
{
U32 ix;
U8 *pRxBuf;
iad_eth_CfgBlk *p_ethCfgBlk;
p_ethCfgBlk = ðCfgBlk[EthNum];
// 在FreeRxQueue中填满预先分配的以太网接收缓冲区 FREEQ_ACCESS_MAX_LIMIT
p_ethCfgBlk->ethResources.pRxFreeQMem = NULL;
///p_ethCfgBlk->RxBDIndex = 0;
for( ix=0; ix< FREEQ_ACCESS_MAX_LIMIT ; ix++ )
{
pRxBuf = eth_get_aligned_buff();
if( pRxBuf == NULL )
{
AOS_ASSERT(0);
return AOS_FAIL;
}
// rx buff
// p_ethCfgBlk->RxBuff[ix] = pRxBuf;
if( IAD_SUCCESS != iad_queue_put(p_ethCfgBlk->ethResources.RxFreeQHnd,
&pRxBuf,sizeof(void*)) )
{
AOS_ASSERT(0);
return AOS_FAIL;
}
}
return AOS_SUCC;
}
U32 eth_sync_phy( U32 ethnum )
{
iad_Error errCode;
unsigned int eth_phy_link;
unsigned int eth_phy_stat;
unsigned char eth_ctrl_reg;
unsigned short regValue;
iad_ethHnd ethHnd;
iad_eth_CfgBlk *p_ethCfgBlk;
U8 ucHwVer;
U8 phyaddr;
static BOOL_T bInit = FALSE;
p_ethCfgBlk = ðCfgBlk[ethnum];
ethHnd = p_ethCfgBlk->iadEthHnd;
// setup Ethernet MAC to Sync with PHY
drv_get_pcb_ver(&ucHwVer);
if( ucHwVer == EIAV7_EVD )
{
eth_phy_link = IADB_ETH_PHY_KS_STATUS_FULL_DUP;
eth_phy_stat = IADB_ETH_PHY_KS_STATUS_100_MBPS;
eth_ctrl_reg = IADB_ETH_PHY_STATUS_KS_REG;
phyaddr = ( ethnum?IADB_ETH_PHY1_ADDR: IADB_ETH_PHY0_ADDR);
}
else if( ucHwVer == EIAV7_2001 )
{
eth_phy_link = IADB_ETH_PHY_RTL8201BL_DUPLEX_EN;
eth_phy_stat = IADB_ETH_PHY_RTL8201BL_SPEED_100MB;
eth_ctrl_reg = IADB_ETH_PHY_STATUS_REG;
phyaddr = ( ethnum?IADB_ETH_PHY1_ADDR: IADB_ETH_PHY0_ADDR);
}
else
{
if( bInit == FALSE )
{
bInit = TRUE;
// IP175C缺省为175A模式,第一次使用前需要切换为175C模式! luke
if( IAD_SUCCESS != iad_eth_phyWriteCmd(ethHnd, PHY_29_REG, 31,0x175C ))
{
// 5980 == 175C
AOS_ASSERT(0);
}
}
// EIAV7_2002 EIAV7_2004 IP175C switch LAN固定使用100M全双工
// WAN根据PHY来确定
if( ethnum == SERVICE_LAN_PORT )
{
iad_eth_setParam (ethHnd, IAD_ETH_PARAM_TX_HALF_DUP_EN, (iad_ethParamData)FALSE);
iad_eth_setParam (ethHnd, IAD_ETH_PARAM_TX_DFL_BITTIMES1, (iad_ethParamData)IPG_CLK_FOR_100_MB);
iad_eth_setRmiiSpeed(ethHnd, IAD_ETH_RMII_CTRL_USE_100_BASE_T);
return AOS_SUCC;
}
else
{
// WAN口MAC与PHY直接连接
eth_phy_link = IADB_ETH_PHY_IP175C_DUPLEX_EN; // 5.8 6
eth_phy_stat = IADB_ETH_PHY_IP175C_SPEED_100MB; // 5.8 7
eth_ctrl_reg = IADB_ETH_PHY_IP175C_STATUS_REG;
phyaddr = IP175C_PHYAD_WAN;
}
}
// call ethPhy_getStatus(...) to get the PHY chip status
if( IAD_SUCCESS != iad_eth_phyReadCmd(ethHnd,phyaddr,eth_ctrl_reg) )
{
AOS_ASSERT(0);
}
errCode = iad_eth_phyReadVal(ethHnd, ®Value);
if ( errCode != IAD_SUCCESS)
{
AOS_ASSERT(0);
return AOS_FAIL;
}
// set the MAC to proper Duplex Mode by calling Ethernet set param API
if ( regValue & eth_phy_link )
{
p_ethCfgBlk->ethPhyLnkBlk.ethPhyDuplexMode = TRUE;
iad_eth_setParam (ethHnd, IAD_ETH_PARAM_TX_HALF_DUP_EN, (iad_ethParamData)FALSE);
}
else
{
p_ethCfgBlk->ethPhyLnkBlk.ethPhyDuplexMode = FALSE;
iad_eth_setParam(ethHnd, IAD_ETH_PARAM_TX_RANDOM_SEED, (iad_ethParamData)0xAA);
iad_eth_setParam(ethHnd, IAD_ETH_PARAM_TX_RETRY_COL_EN, (iad_ethParamData)TRUE);
iad_eth_setParam(ethHnd, IAD_ETH_PARAM_TX_COL_MAX_RETRY, (iad_ethParamData)15);
iad_eth_setParam(ethHnd, IAD_ETH_PARAM_TX_SLOT_TIME, (iad_ethParamData)0xff);
iad_eth_setParam (ethHnd, IAD_ETH_PARAM_TX_HALF_DUP_EN, (iad_ethParamData)TRUE);
}
aos_printf( MPE_ETH, " eth port[%d] Duplex changed to %s",
ethnum,
(p_ethCfgBlk->ethPhyLnkBlk.ethPhyDuplexMode?"Full":"Half"));
if ( regValue & eth_phy_stat )
{
p_ethCfgBlk->ethPhyLnkBlk.ethPhyLnkSpeed = TRUE;
iad_eth_setParam (ethHnd, IAD_ETH_PARAM_TX_DFL_BITTIMES1, (iad_ethParamData)IPG_CLK_FOR_100_MB);
iad_eth_setRmiiSpeed(ethHnd, IAD_ETH_RMII_CTRL_USE_100_BASE_T);
}
else
{
p_ethCfgBlk->ethPhyLnkBlk.ethPhyLnkSpeed = FALSE;
iad_eth_setParam (ethHnd, IAD_ETH_PARAM_TX_DFL_BITTIMES1, (iad_ethParamData)IPG_CLK_FOR_10_MB);
iad_eth_setRmiiSpeed(ethHnd, IAD_ETH_RMII_CTRL_USE_10_BASE_T);
}
aos_printf( MPE_ETH, " eth port[%d] Speed changed to %s",
ethnum,
(p_ethCfgBlk->ethPhyLnkBlk.ethPhyLnkSpeed?"100Mb":"10Mb"));
return AOS_SUCC;
}
// EIA2000V6 have two 100M RMII ethernet Port
U32 eth_interface_init(DEVLINK_S *pDev,U32 *pIfIndex )
{
ETH_DRV_IF *pDrv;
IFNET_S *pIf;
U32 EthNum;
iad_eth_CfgBlk *p_ethCfgBlk;
iad_ethHnd ethHnd;
if( NULL == pDev || NULL == pIfIndex )
{
AOS_ASSERT(0);
return AOS_FAIL;
}
pIf = (IFNET_S *)if_get_if_by_index(*pIfIndex);
EthNum = pIf->if_ulPortNum;
pIf->if_ulPhyLink = (U32)&EthIfDrv[EthNum];
pDrv = ( ETH_DRV_IF *) pIf->if_ulPhyLink;
pDrv->pIf = pIf;
pDrv->chan_usSlot = pDev->dev_usSlot;
pDrv->chan_usChan = pDev->dev_usChan;
pDrv->chan_usPort = pDev->dev_usPort;
pIf->if_pfPhyTransmit = eth_send;
pIf->if_pfReceived = pIf->if_pfLinkReceived;
pIf->if_pfPhyIOCtl = eth_ioctl;
p_ethCfgBlk = ðCfgBlk[EthNum];
p_ethCfgBlk->initCfgDone = FALSE;
// setup Ethernet hardware
if ( eth_init(EthNum)!= AOS_SUCC )
{
AOS_ASSERT(0);
return AOS_FAIL;
}
ethHnd = p_ethCfgBlk->iadEthHnd;
// 设置以太网参数
// TxFreeQueue 4字节长度对齐 掩码长度为4,2048为11
iad_eth_setParam (ethHnd,IAD_ETH_PARAM_PKT_BUF_SIZE,
(iad_ethParamData)2048);
iad_eth_setParam (ethHnd,IAD_ETH_PARAM_ADDR_MASK,
(iad_ethParamData)0x4);
// 以太网打开短帧自动填充
iad_eth_setParam (ethHnd, IAD_ETH_PARAM_TX_PAD_EN,
(iad_ethParamData)TRUE);
iad_eth_setParam (ethHnd, IAD_ETH_PARAM_RX_PAD_STRIP_EN,
(iad_ethParamData)TRUE);
// 以太网打开16位CRC校验和
iad_eth_setParam (ethHnd, IAD_ETH_PARAM_TX_FCS_EN,
(iad_ethParamData)TRUE);
// 接收报文前面保留96字节,保留用作协议层添加额外字段,ETH_HEADER_RESERV_LEN
iad_eth_setParam (ethHnd, IAD_ETH_PARAM_PKT_BUF_OFFSET,
(iad_ethParamData)ETH_HEADER_RESERV_LEN );
// 802.3X流控开
iad_eth_setParam (ethHnd, IAD_ETH_PARAM_PAUSE_EN,
(iad_ethParamData)TRUE);
iad_eth_setParam (ethHnd, IAD_ETH_PARAM_RX_RUNT_EN,
(iad_ethParamData)TRUE);
// 以太网半双工模式自动重发
iad_eth_setParam (ethHnd, IAD_ETH_PARAM_TX_RETRY_COL_EN,
(iad_ethParamData)TRUE);
iad_eth_setParam (ethHnd, IAD_ETH_REG_TX_DFL_PARAMS_1,
(iad_ethParamData)24);
// 当前网口的广播报文接收允许
iad_eth_setParam( ethHnd,IAD_ETH_PARAM_BCAST_EN,
(iad_ethParamData)TRUE);
// 设置当前网口的单播MAC地址
cfm_get_mac( EthNum, (U8 *)(p_ethCfgBlk->ethResources.szUniMac) );
/********
aos_printf(0,"eth=%d macaddr=%x:%x:%x:%x:%x:%x ",
ulPortNum,
p_ethCfgBlk->ethResources.szUniMac[0],
p_ethCfgBlk->ethResources.szUniMac[1],
p_ethCfgBlk->ethResources.szUniMac[2],
p_ethCfgBlk->ethResources.szUniMac[3],
p_ethCfgBlk->ethResources.szUniMac[4],
p_ethCfgBlk->ethResources.szUniMac[5]);
***************/
iad_eth_setParam(ethHnd, IAD_ETH_PARAM_UCAST_ADDR,
(iad_ethParamData)(p_ethCfgBlk->ethResources.szUniMac));
// 确定EIA工作在桥模式还是在路由器模式
cfm_get_parameter(CMD_EIA_WORK_MODE,(VOID *)&g_bEthBridgeFlag, sizeof(U32) );
//g_bSoftBirdgeFlag = g_bEthBridgeFlag;
// EIA2000V7的处理能力强,Bridge模式下,缺省启动SoftBridge,luke
/*
cfm_get_parameter(CMD_SOFT_BRIDGE_FLAG,
(VOID*)&g_bSoftBirdgeFlag,
sizeof(U32));
*/
// 软件桥接功能,需要将两个网口的MAC设置为混杂模式
// MAC prosmicuous/unicast模式设置
if( g_bEthBridgeFlag )
{
iad_eth_setParam( ethHnd,IAD_ETH_PARAM_ADDR_FLTR_EN,
(iad_ethParamData)FALSE);
}
else
{
iad_eth_setParam( ethHnd,IAD_ETH_PARAM_ADDR_FLTR_EN,
(iad_ethParamData)TRUE);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -