📄 c3eth.c
字号:
// disable eth interrupt
IAD_REG_AND(IAD_NP_REG_BASE_ADDR, IAD_NP_REG_INTR_STEERING1,
~IAD_NP_INTR_STATUS_ETH0_MASK);
IAD_REG_AND(IAD_NP_REG_BASE_ADDR, IAD_NP_REG_INTR_STEERING1,
~IAD_NP_INTR_STATUS_ETH1_MASK);
g_bEthPollMode = TRUE;
aos_task_resume(g_ulEthPollTaskId);
aos_printf(MPE_SYS," Ethernet Intr->Poll mode.");
}
else
{
// enable eth interrupt
IAD_REG_OR(IAD_NP_REG_BASE_ADDR, IAD_NP_REG_INTR_STEERING1,
IAD_NP_INTR_STATUS_ETH0_MASK);
IAD_REG_OR(IAD_NP_REG_BASE_ADDR, IAD_NP_REG_INTR_STEERING1,
IAD_NP_INTR_STATUS_ETH1_MASK);
g_bEthPollMode = FALSE;
aos_task_suspend(g_ulEthPollTaskId);
aos_printf(MPE_SYS," Ethernet Poll->Intr mode.");
}
}
void eth_recv_packet(unsigned int ethnum)
{
iad_eth_CfgBlk *p_ethCfgBlk;
iad_pktDesc pktDesc,pktDescCpy;
BOOL_T bUpPacket;
iad_Error ret;
U32 peereth;
U8 *pbuf = NULL;
unsigned int i,count;
L2_MAC_TABLE_S *pL2TableItem;
U8 *pLocalMac,*pBufCopy;
#ifdef ETH_PHP_ENABLE
iad_phpPktDesc phpDesc;
#endif
p_ethCfgBlk = ðCfgBlk[ethnum];
iad_queue_count(p_ethCfgBlk->ethResources.RxQHnd,&count);
for( i=0; i<count; i++ )
{
#ifdef ETH_PHP_ENABLE
ret = iad_php_pktRcv(p_ethCfgBlk->hAutoConnHnd,&phpDesc);
if( ret == IAD_QUEUE_EMPTY )
{
// 正常情况
break;
}
else if( ret != IAD_SUCCESS )
{
AOS_ASSERT(0);
break;
}
pktDesc = phpDesc.pktDesc;
if( IAD_SUCCESS != iad_queue_put(g_hPhpFreeHnd,
&(phpDesc.phpTDPtr),sizeof(void*)) )
{
AOS_ASSERT(0);
break;
}
#else
// 接收完成的以太网报文从RxQueue硬件队列中读出来
ret = iad_eth_pktRcv(p_ethCfgBlk->iadEthHnd,&pktDesc);
if( ret == IAD_QUEUE_EMPTY )
{
// 正常情况
break;
}
else if( ret != IAD_SUCCESS )
{
AOS_ASSERT(0);
break;
}
#endif
/******
if( p_ethCfgBlk->RxBuff[p_ethCfgBlk->RxBDIndex] !=
pktDesc.pBase )
{
aos_printf(0," Rxbuff[%d]=0x%x pBase=0x%x pData=0x%x",
p_ethCfgBlk->RxBDIndex,
p_ethCfgBlk->RxBuff[p_ethCfgBlk->RxBDIndex],
pktDesc.pBase,
pktDesc.pData );
}
******/
// 必须先判断队列空间是否合法
if( AOS_ADDR_INVALID(pktDesc.pBase) )
{
// Rx吊死,复位Rx
aos_printf(0," Reset Eth=%d Rx Queue,pktDesc.pBase=0x%x ",
ethnum,pktDesc.pBase);
break;
}
bUpPacket = TRUE;
/*
aos_printf(0,"eth=%d recv packet status=0x%x Base=0x%x Data=0x%x len=%d",
ethnum,pktDesc.aux_data.eth_data.status,
pktDesc.pBase,
pktDesc.pData,
pktDesc.len);
debug_mem_show(0,(U32)pktDesc.pData,pktDesc.len);
*/
// Table 4-44 Receive Status
// 正常单播报文和广播报文
if( (pktDesc.aux_data.eth_data.status == 0) ||
(pktDesc.aux_data.eth_data.status&0x0100) )
{
p_ethCfgBlk->ethStatSum.ulRxTotalFrames++;
p_ethCfgBlk->ethStatSum.ulRxTotalBytes+=pktDesc.len;
// Bit8 BroadCast Packet
if( pktDesc.aux_data.eth_data.status & 0x0100 )
{
p_ethCfgBlk->ethStatSum.ulPacketBcNum++;
}
if( g_bEthBridgeFlag && g_bSoftBirdgeFlag )
{
//软件桥接处理:
// 1.本机MAC地址交上层协议栈
// 2.广播或多播MAC地址交上层协议栈同时转发
// 3.其余MAC报文转发给对应端口WAN<->LAN, LAN<->WAN
pLocalMac = ethCfgBlk[SERVICE_WAN_PORT].ethResources.szUniMac;
if( 0 == aos_memcmp(pLocalMac,pktDesc.pData,6) )
{
// 1.本机报文,继续...
bUpPacket = TRUE;
}
else if(0 == aos_memcmp( g_szBcastPacket,
pktDesc.pData,6) )
{
// 2.广播MAC地址交上层协议栈同时转发
bUpPacket = TRUE;
//增加内存块引用索引,避免内存释放两次
//mem_buf_inc_ref(mem_obj_head(pktDesc.pBase));
// 另一种方法虽然开销大一点,拷贝一份更安全,luke
pBufCopy = (U8*)eth_get_aligned_buff();
if( pBufCopy )
{
peereth = ((ethnum==SERVICE_WAN_PORT)?SERVICE_LAN_PORT
:SERVICE_WAN_PORT );
//pktDescCpy.pBase = pBufCopy;
pktDescCpy.pData = pBufCopy+ETH_HEADER_RESERV_LEN;
pktDescCpy.len = pktDesc.len;
aos_memcpy(pBufCopy+ETH_HEADER_RESERV_LEN,pktDesc.pData,pktDesc.len);
//eth_forward_packet(peereth, &pktDescCpy);
eth_send_packet(peereth,pktDescCpy.pData,pktDescCpy.len,ETH_FORWARD_SEND);
}
}
else
{
// 3.其余MAC报文转发给对应端口
bUpPacket = FALSE;
peereth = ((ethnum==SERVICE_WAN_PORT)?SERVICE_LAN_PORT
:SERVICE_WAN_PORT );
//eth_forward_packet(peereth, &pktDesc);
eth_send_packet(peereth,pktDesc.pData,pktDesc.len,ETH_FORWARD_SEND);
}
// 4. L2MACTABLE srcMac地址学习,为了提高效率,地址写习限制在UP报文
if( bUpPacket )
{
pL2TableItem = eth_l2mac_hash_find(pktDesc.pData+6);
if( pL2TableItem )
{
// 已经存在此L2表项,刷新时间为缺省最大老化时间
pL2TableItem->port = ethnum; // 更新端口
pL2TableItem->time = L2MAC_AGE_TIME;
}
else
{
// 学习到新的L2表项
//先得到一个空闲的L2MAC表项
pL2TableItem = eth_get_idle_l2mac();
if( pL2TableItem )
{
aos_memcpy(pL2TableItem->mac,pktDesc.pData+6,6);
pL2TableItem->port = ethnum;
pL2TableItem->time = L2MAC_AGE_TIME;
pL2TableItem->flag = TRUE;
eth_l2mac_hash_add(pktDesc.pData+6,pL2TableItem);
/*
aos_printf(0,"L2 MAC Add MAC=%x-%x-%x-%x-%x-%x port=%d ",
pL2TableItem->mac[0], pL2TableItem->mac[1],
pL2TableItem->mac[2], pL2TableItem->mac[3],
pL2TableItem->mac[4], pL2TableItem->mac[5],
pL2TableItem->port );
*/
}
else
{
aos_printf( MPE_ETH,"L2 MAC Table is FULL!");
}
}
}
}
// 为RxFreeQueue补充一个空闲的以太网报文接收缓冲区
pbuf = eth_get_aligned_buff();
if( pbuf )
{
if( IAD_SUCCESS != iad_queue_put(p_ethCfgBlk->ethResources.RxFreeQHnd,
&pbuf,sizeof(void*)) )
{
AOS_ASSERT(0);
}
else
{
if( bUpPacket )
{
eth_stream_up(ethnum,pktDesc.pData,pktDesc.len);
}
else
{
aos_dmem_free((S8*)mem_obj_head(pktDesc.pData));
}
}
///p_ethCfgBlk->RxBuff[p_ethCfgBlk->RxBDIndex] = pbuf;
}
else
{
// 内存不足,将原来的接收缓冲区继续放入RxFreeQueue
iad_queue_put(p_ethCfgBlk->ethResources.RxFreeQHnd,
&(pktDesc.pBase),sizeof(void*));
AOS_ASSERT(0);
}
}
else
{
if( pktDesc.aux_data.eth_data.status & 0x0200 )
{
// Bit9 MultiCast Packet
//目前,设备没有需要接收多播报文,丢弃
p_ethCfgBlk->ethStatSum.ulPacketMcNum++;
}
if( pktDesc.aux_data.eth_data.status & 0x0080 )
{ // Bit7 Length Error,丢弃
p_ethCfgBlk->ethStatSum.ulPacketLenErNum++;
}
if( pktDesc.aux_data.eth_data.status & 0x0040 )
{ // Bit6 CRC Packet,丢弃
p_ethCfgBlk->ethStatSum.ulPacketCrcErNum++;
}
if( pktDesc.aux_data.eth_data.status & 0x0020 )
{ // Bit5 Short Runt Frame ,丢弃
p_ethCfgBlk->ethStatSum.ulPacketShortFrameNum++;
}
if( pktDesc.aux_data.eth_data.status & 0x0010 )
{ // Bit4 Rx FIFO Overrun ,丢弃
p_ethCfgBlk->ethStatSum.ulPacketOvRunNum++;
}
if( pktDesc.aux_data.eth_data.status & 0x0008 )
{ // Bit3 Rx Late Collision ,丢弃
p_ethCfgBlk->ethStatSum.ulPacketColliNum++;
}
if( pktDesc.aux_data.eth_data.status & 0x0004 )
{ // Bit2 Frame Alignment Error,丢弃
p_ethCfgBlk->ethStatSum.ulPacketNoAlignErNum++;
}
// 接收一个无效的以太报文后,
// 将当前接收缓冲区返回到RxFreeQue
iad_queue_put(p_ethCfgBlk->ethResources.RxFreeQHnd,
&(pktDesc.pBase),sizeof(void*));
}
}
/// debug
///p_ethCfgBlk->RxBDIndex++;
///p_ethCfgBlk->RxBDIndex %= FREEQ_ACCESS_MAX_LIMIT;
return;
}
// 以太网接收中断处理,中断模式接收响应速度快,但是当网口流量很大时,
// 由于频繁中断带来过大系统开销,将影响吞吐量,此时应该关闭中断模式
void eth_intr_proc(unsigned int ethnum)
{
U32 intStatus;
if( ethnum > 1 )
{
return;
}
if( ethnum )
{
intStatus = IAD_REG_RD_WORD(IAD_ETH2_REG_BASE_ADDR, IAD_ETH_REG_INTR_CLEAR);
IAD_REG_WR(IAD_ETH2_REG_BASE_ADDR,IAD_ETH_REG_INTR_CLEAR,
intStatus );
}
else
{
intStatus = IAD_REG_RD_WORD(IAD_ETH1_REG_BASE_ADDR, IAD_ETH_REG_INTR_CLEAR);
IAD_REG_WR(IAD_ETH1_REG_BASE_ADDR,IAD_ETH_REG_INTR_CLEAR,
intStatus );
}
if( intStatus&IAD_RX_PACKET_DONE )
{
eth_recv_packet(ethnum);
}
}
// 10ms 以太网接收报文任务,轮询模式下系统开销小,当以太网口流量很大时,关闭
// 中断模式,进入轮询模式
void eth_recv_poll(void )
{
int ethnum;
while( 1 )
{
if( FALSE == g_bEthPollMode )
{
aos_task_suspend(g_ulEthPollTaskId);
}
for( ethnum= SERVICE_WAN_PORT; ethnum >= SERVICE_LAN_PORT ; ethnum-- )
{
// 优先处理WAN口,然后处理LAN口,一次接收完硬件队列中的所有接收完成报文
eth_recv_packet(ethnum);
}
// 10 ms Poll Task interval
aos_task_delay(10);
}
}
// 老化处理每L2_AGING_PERIOD秒被调用一次
void eth_l2mac_aging(U32 ulTimerName, U32 ulPara )
{
U32 i;
if( g_bSoftBirdgeFlag == FALSE )
return;
for(i=0; i< L2MAC_HASH_MAX_NUM; i++ )
{
if( !g_L2MacTable[i].flag )
continue;
g_L2MacTable[i].time -= L2_AGING_PERIOD;
if( g_L2MacTable[i].time < 0)
{
//清除关联的HASH索引表
eth_l2mac_hash_remove(&g_L2MacTable[i]);
//需要清除此项目
/*
aos_printf(0,"L2 MAC Aging MAC=%x-%x-%x-%x-%x-%x port=%d ",
g_L2MacTable[i].mac[0], g_L2MacTable[i].mac[1],
g_L2MacTable[i].mac[2], g_L2MacTable[i].mac[3],
g_L2MacTable[i].mac[4], g_L2MacTable[i].mac[5],
g_L2MacTable[i].port );
*/
aos_memset(&g_L2MacTable[i],0,sizeof(L2_MAC_TABLE_S));
}
}
}
U32 eth_forward_packet(U32 peereth, iad_pktDesc *p_pktDesc )
{
iad_eth_CfgBlk *p_ethCfgBlk;
U32 ret,i,ulLen;
unsigned int count=0;
char *pBuf,*pBufSent;
iad_pktQBlk PktSent;
p_ethCfgBlk = ðCfgBlk[peereth];
pBuf = p_pktDesc->pData;
ulLen = p_pktDesc->len;
// 待发送的报文的地址压入SentQue软件队列,因为C3的硬件入队列非2048对齐的报文
// 入TxFreeQHnd可能出错!! luke
iad_queue_put(p_ethCfgBlk->ethResources.SentQHnd,
(iad_pktQBlk*)&pBuf,
sizeof(iad_pktQBlk));
if( IAD_SUCCESS == iad_eth_pktSend(p_ethCfgBlk->iadEthHnd,p_pktDesc) )
{
ret = iad_queue_count(p_ethCfgBlk->ethResources.TxFreeQHnd,
&count);
if (ret != IAD_SUCCESS )
{
AOS_ASSERT(0);
}
//将已经发送完成的缓冲区释放
for(i=0; i<count; i++)
{
ret= iad_queue_get( p_ethCfgBlk->ethResources.TxFreeQHnd,
&pBuf,sizeof(void*));
if (ret != IAD_SUCCESS )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -