📄 swpkt.c
字号:
/*
* Copyright (c) 1996, 2003 VIA Networking Technologies, Inc.
* All rights reserved.
*
* This software is copyrighted by and is the sole property of
* VIA Networking Technologies, Inc. This software may only be used
* in accordance with the corresponding license agreement. Any unauthorized
* use, duplication, transmission, distribution, or disclosure of this
* software is expressly forbidden.
*
* This software is provided by VIA Networking Technologies, Inc. "as is"
* and any express or implied warranties, including, but not limited to, the
* implied warranties of merchantability and fitness for a particular purpose
* are disclaimed. In no event shall VIA Networking Technologies, Inc.
* be liable for any direct, indirect, incidental, special, exemplary, or
* consequential damages.
*
*
* File: swpkt.c
*
* Purpose:
*
* Author: Henry Lin
*
* Date: May 05, 2005
*
* Functions:
*
* Revision History:
*
*/
#if !defined(__STR_H__)
#include "str.h"
#endif
#if !defined(__DEVICE_H__)
#include "device.h"
#endif
#if !defined(__PLATFORM_H__)
#include "platform.h"
#endif
#if !defined(__ISR_H__)
#include "isr.h"
#endif
#if !defined(__SWCFG_H__)
#include "swcfg.h"
#endif
#if !defined(__SWITCH_H__)
#include "switch.h"
#endif
#if !defined(__SWREG_H__)
#include "swreg.h"
#endif
#if !defined(__SWSYS_H__)
#include "swsys.h"
#endif
#if !defined(__SWPKT_H__)
#include "swpkt.h"
#endif
#include "armboot.h"
/*--------------------- Static Definitions ------------------------*/
#define DEBUG_PKT 0 /*used to print msg, 1 : yes; 0 : no*/
#define DEBUG_PKT_TX 0
#if DEBUG_PKT
#define DBG_PRN_PKT printf
#else
#define DBG_PRN_PKT(...) FUNC_NULL()
#endif
#if DEBUG_PKT_TX
#define DBG_PRN_PKT_TX printf
#else
#define DBG_PRN_PKT_TX(...) FUNC_NULL()
#endif
#define MAC_ADDR_SIZE 6 // 6 bytes
#define RBUF_RX_BUF_NUM 4
#define RBUF_TX_BUF_NUM 1
#define ETH_PKT_MIN_LEN 60 // w/o CRC, w/o vlan tag
#define ETH_TYPE_OFST 12 // ethernet type offset
#define ETH_PKT_MAX_LEN 1518 // max packet length, with vlan tag, w/o CRC
#define DEF_RP_DMA_WRR_CNT 0x04
#define DEF_WP_DMA_WRR_CNT 0x04
#if __PBUS_DMA_2_CHNNL
#define RP_DMA_CH DMA_CH0
#define WP_DMA_CH DMA_CH1
#else
#define RP_DMA_CH DMA_CH0
#define WP_DMA_CH DMA_CH0
#endif
#define REQ_EN (CPUIF_REQ0_EN | CPUIF_REQ1_EN)
/*--------------------- Static Types ------------------------------*/
struct tagSNetDev {
UINT32 u32RxBufEnque;
UINT32 u32RxBufDeque;
volatile UINT32 u32RxBufQueueNum;
UINT32 u32TxBufEnque;
UINT32 u32TxBufDeque;
volatile UINT32 u32TxBufQueueNum;
PSRBuf apRBufRx[RBUF_RX_BUF_NUM];
PSRBuf apRBufTx[RBUF_TX_BUF_NUM];
};
typedef struct tagSNetDev SNetDev;
/*--------------------- Static Macros -----------------------------*/
#if __SWITCH_CPUIF_PKT8
#define PKTvReadB(pbyData) do { *(pbyData) = *sg_pioCpuPktData; } while (0)
#define PKTvWriteB() do { *sg_pioCpuPktData = *pu8TxBuf; pu8TxBuf++; u16TxIndex++; } while (0)
#define PKTvWriteBlock() do { PKTvWriteB(); PKTvWriteB(); PKTvWriteB(); PKTvWriteB();} while (0)
#else //cpu bus 16 bit
#if defined(__BIG_ENDIAN) && !defined(__CPU_S3C2510A)
// only for Samsung4510b big endian mode
#define PKTvReadW(pwData) do { *((PUINT16)(pwData)) = *sg_pioCpuPktData16; *((PUINT16)(pwData)) = REV_WORD(*((PUINT16)(pwData))); } while (0)
#define PKTvWriteW() do { *((PUINT16)pu8TxBuf) = REV_WORD(*((PUINT16)pu8TxBuf)); *sg_pioCpuPktData16 = *((PUINT16)pu8TxBuf); pu8TxBuf += 2; u16TxIndex += 2; } while (0)
#else
#define PKTvReadW(pwData) do { *((PUINT16)(pwData)) = *sg_pioCpuPktData16; } while (0)
#define PKTvWriteW() do { *sg_pioCpuPktData16 = *((PUINT16)pu8TxBuf); pu8TxBuf += 2; u16TxIndex += 2; } while (0)
#endif
#define PKTvWriteBlock() do { PKTvWriteW(); PKTvWriteW();} while (0)
#endif
#define SWPKT_vSwitchImrEnable(u16IrqBit) do {UINT16 u16IrqMask; SWREG_vReadU16(CPUIF_IRQ_MASK, &u16IrqMask); u16IrqMask |= (u16IrqBit); SWREG_vWriteU16(CPUIF_IRQ_MASK, u16IrqMask);} while (0)
#define SWPKT_vSwitchImrDisable(u16IrqBit) do {UINT16 u16IrqMask;SWREG_vReadU16(CPUIF_IRQ_MASK, &u16IrqMask);u16IrqMask &= ~(u16IrqBit);SWREG_vWriteU16(CPUIF_IRQ_MASK, u16IrqMask);} while (0)
#define ADD_ONE_WITH_WRAP_AROUND(uVar, uModulo) do { if ((uVar) >= ((uModulo) - 1)) (uVar) = 0; else (uVar)++;} while (0)
/*--------------------- Static Classes ----------------------------*/
/*--------------------- Static Variables --------------------------*/
#if __SWITCH_CPUIF_PKT8
volatile UINT8 *sg_pioCpuPktData = (volatile UINT8 *)PLAT_ASIC_CPUIF_BASE_ADDR;
#else
volatile UINT16 *sg_pioCpuPktData16 = (volatile UINT16 *)PLAT_ASIC_CPUIF_BASE_ADDR;
#endif
#if !__PKT_PIO
#if __PBUS_DMA_2_CHNNL || defined(__SWITCH_CPUIF_PCI)
static BOOL sg_bMuxRdPktInDma = FALSE;
static BOOL sg_bMuxWrPktInDma = FALSE;
#else
static BOOL sg_bMuxPktInDma = FALSE;
#define sg_bMuxRdPktInDma sg_bMuxPktInDma
#define sg_bMuxWrPktInDma sg_bMuxPktInDma
#endif
#endif
static PFN_HOOK_PV sg_pfnHookRecv;
static SNetDev sg_NetDev;
static BOOL sg_bFirstTxFail = FALSE;
static SRBuf sg_aRBufRx[RBUF_RX_BUF_NUM];
static SRBuf sg_aRBufTx[RBUF_TX_BUF_NUM];
/*--------------------- Static Functions --------------------------*/
#if !__PKT_PIO
static void s_vDmaStartRecv(SRBuf* pRBuf);
static void s_vDmaStartSend(SRBuf* pRBuf);
#else
static UINT16 s_wRecvPktPIO(PUINT8 pu8RxBuf, PUINT8 pu8SrcPortId, PBOOL pbTagged, PUINT16 pu16VID, PUINT8 pu8Priority);
static void s_vSendPktPIO(SRBuf* pRBuf);
#endif
/*--------------------- Export Variables --------------------------*/
SNetStat g_NetStat;
/*--------------------- Import Functions --------------------------*/
//
// Interrupt Service Routines: Rx Packet
//
void ISR_vRecvPkt (void)
{
//DBG_PRN_PKT("enter ISR_vRecvPkt...\n");
#if !__PKT_PIO
// because we do not clear IRQ status yet, if the interrupt mask open again
// this interrupt service routine will be called again
if (sg_bMuxRdPktInDma)
return;
sg_bMuxRdPktInDma = TRUE;
#endif
DBG_PRN_PKT(" ISR_vRecvPkt: clear IRQ status.");
// clear IRQ status
SWREG_vWriteU16(CPUIF_IRQ_STATUS, IRQ_STATUS_PKT_RX);
DBG_PRN_PKT(" ISR_vRecvPkt: check if packet is ready to receives.");
// check if packet is ready to receive
if (SWREG_bIsBitsOffU8(CPUPORT_OUTPUT_PORT_STATUS, RD_PKT_RDY))
{
#if !__PKT_PIO
sg_bMuxRdPktInDma = FALSE;
#endif
return;
}
// s_vDmaStartRecv(&sg_aRBufRx[0]);
// return;
DBG_PRN_PKT(" ISR_vRecvPkt: rx queue is full.");
// rx queue is full
if (sg_NetDev.u32RxBufQueueNum >= RBUF_RX_BUF_NUM)
{
// drop this rx packet
SWREG_vBitsOnU8(CPUIF_CPU_PKT_CMD, CPU_PKT_CMD_RD_PKT_ABORT);
// Need to Read Clear this CPU_PKT_CMD_RD_PKT_ABORT bit. Otherwise, no packet will be received.
SWREG_bWaitStatus(CPUIF_CPU_PKT_CMD, CPU_PKT_CMD_RD_PKT_ABORT, FALSE);
g_NetStat.u32ErrorRxBufDrop++;
DBG_PRN_PKT(" PKT: no rx buffer, drop packet.");
#if !__PKT_PIO
sg_bMuxRdPktInDma = FALSE;
#endif
return;
}
#if !__PKT_PIO
DBG_PRN_PKT(" ISR_vRecvPkt: s_vDmaStartRecv");
s_vDmaStartRecv(sg_NetDev.apRBufRx[sg_NetDev.u32RxBufEnque]);
#else
DBG_PRN_PKT(" ISR_vRecvPkt: s_wRecvPktPIO");
sg_NetDev.apRBufRx[sg_NetDev.u32RxBufEnque]->pkb_u16BufLen =
s_wRecvPktPIO(sg_NetDev.apRBufRx[sg_NetDev.u32RxBufEnque]->pkb_au8Buffer,
&sg_NetDev.apRBufRx[sg_NetDev.u32RxBufEnque]->pkb_u8SrcPortId,
&sg_NetDev.apRBufRx[sg_NetDev.u32RxBufEnque]->pkb_bTagged,
&sg_NetDev.apRBufRx[sg_NetDev.u32RxBufEnque]->pkb_u16VID,
&sg_NetDev.apRBufRx[sg_NetDev.u32RxBufEnque]->pkb_u8Priority);
ADD_ONE_WITH_WRAP_AROUND(sg_NetDev.u32RxBufEnque, RBUF_RX_BUF_NUM);
sg_NetDev.u32RxBufQueueNum++;
#endif
}
#if 0
//
// Interrupt Service Routines: Tx Packet
//
void ISR_vSendPkt (void)
{
#if !__PKT_PIO
// because we do not clear IRQ status yet, if the interrupt mask open again
// this interrupt service routine will be called again
if (sg_bMuxWrPktInDma)
return;
sg_bMuxWrPktInDma = TRUE;
#endif
// clear IRQ status
SWREG_vWriteU16(CPUIF_IRQ_STATUS, IRQ_STATUS_PKT_TX);
printf("clear IRQ status\n");
// if tx queue is empty
if (sg_NetDev.u32TxBufQueueNum == 0) {
#if !__PKT_PIO
sg_bMuxWrPktInDma = FALSE;
#endif
return;
}
printf(" check if CPUIO ready to write packet into\n");
// check if CPUIO ready to write packet into
if (SWREG_bIsBitsOffU8(CPUPORT_INPUT_PORT_STATUS, WR_PKT_STATUS_RDY)) {
// drop this tx packet
printf(" drop this tx packet\n");
ADD_ONE_WITH_WRAP_AROUND(sg_NetDev.u32TxBufDeque, RBUF_TX_BUF_NUM);
sg_NetDev.u32TxBufQueueNum--;
g_NetStat.u32ErrorTxMacDrop++;
DBG_PRN_PKT_TX(" PKTTX: error, cpuio not ready to write packet.");
#if !__PKT_PIO
sg_bMuxWrPktInDma = FALSE;
#endif
return;
}
#if !__PKT_PIO
printf(" s_vDmaStartSend\n");
s_vDmaStartSend(sg_NetDev.apRBufTx[sg_NetDev.u32TxBufDeque]);
#else
// send next packet
s_vSendPktPIO(sg_NetDev.apRBufTx[sg_NetDev.u32TxBufDeque]);
// packet already sent, deque it
ADD_ONE_WITH_WRAP_AROUND(sg_NetDev.u32TxBufDeque, RBUF_TX_BUF_NUM);
sg_NetDev.u32TxBufQueueNum--;
#endif
}
#endif
#if 0
void Timer_vSendPkt (void)
{
#if !__PKT_PIO
// because we do not clear IRQ status yet, if the interrupt mask open again
// this interrupt service routine will be called again
if (sg_bMuxWrPktInDma) {
sg_bFirstTxFail = TRUE;
return;
}
sg_bMuxWrPktInDma = TRUE;
#endif
printf("Timer_vSendPkt check tx queue is empty\n");
// if tx queue is empty
if (sg_NetDev.u32TxBufQueueNum == 0) {
#if !__PKT_PIO
sg_bMuxWrPktInDma = FALSE;
#endif
return;
}
printf("Timer_vSendPkt check if CPUIO ready to write packet into\n");
// check if CPUIO ready to write packet into
if (SWREG_bIsBitsOffU8(CPUPORT_INPUT_PORT_STATUS, WR_PKT_STATUS_RDY)) {
// drop this tx packet
ADD_ONE_WITH_WRAP_AROUND(sg_NetDev.u32TxBufDeque, RBUF_TX_BUF_NUM);
sg_NetDev.u32TxBufQueueNum--;
g_NetStat.u32ErrorTxMacDrop++;
DBG_PRN_PKT_TX(" PKTTX: error, cpuio not ready to write packet.");
#if !__PKT_PIO
sg_bMuxWrPktInDma = FALSE;
#endif
return;
}
printf("Timer_vSendPkt s_vDmaStartSend\n");
#if !__PKT_PIO
s_vDmaStartSend(sg_NetDev.apRBufTx[sg_NetDev.u32TxBufDeque]);
#else
// send next packet
s_vSendPktPIO(sg_NetDev.apRBufTx[sg_NetDev.u32TxBufDeque]);
// packet already sent, deque it
ADD_ONE_WITH_WRAP_AROUND(sg_NetDev.u32TxBufDeque, RBUF_TX_BUF_NUM);
sg_NetDev.u32TxBufQueueNum--;
#endif
}
#endif
#if !__PKT_PIO
#ifdef __SWITCH_CPUIF_PCI
//
// Interrupt Service Routines: Read/Write Packet DMA Completed
//
void ISR_vRdPktDmaCompleted (void)
{
UINT16 u16PktLen, u16BlkSize;
PUINT8 pu8PktBuf;
if (SWREG_bIsBitsOnU8(CPUIF_RD_PKT_DMA_STATUS, DMA_STATUS_FAIL)) {
// if not OK, it maybe bad packet.
g_NetStat.u32PktRxBad++;
DBG_PRN_PKT(" PKT: error, rx bad packet.");
}
else {
g_NetStat.u32PktRxGood++;
DBG_PRN_PKT(" PKT: rx good packet.");
//
// Copy packet from page
//
u16PktLen = sg_NetDev.apRBufRx[sg_NetDev.u32RxBufEnque]->pkb_u16BufLen;
pu8PktBuf = sg_NetDev.apRBufRx[sg_NetDev.u32RxBufEnque]->pkb_au8Buffer;
// Check if return to page0
if ((g_u32RdPktCurr + u16PktLen) > g_u32RdStopPageAddr ) {
u16BlkSize = g_u32RdStopPageAddr - g_u32RdPktCurr;
STR_pvMemcpy(pu8PktBuf, (void *)g_u32RdPktCurr, u16BlkSize);
STR_pvMemcpy(pu8PktBuf + u16BlkSize, (void *)g_u32RdStrtPageAddr, u16PktLen - u16BlkSize);
}
else
STR_pvMemcpy(pu8PktBuf, (void *)g_u32RdPktCurr, u16PktLen);
// Next free page start address
SWPCICSR_vReadU32(RD_PKT_CURR_ADDR, &g_u32RdPktCurr );
// at this moment, data is really valid on the buffer, so increase rx queue counter here
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -