📄 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(__PLATFORM_H__)
#include "platform.h"
#endif
#if !defined(__TIMER_H__)
#include "timer.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
#if !defined(__MACRO_H__)
#include "macro.h"
#endif
/*--------------------- Static Definitions ------------------------*/
#define DEBUG_PKT 0
#define DEBUG_PKT_TX 0
#if DEBUG_PKT
#if !defined(__UASSERT_H__)
#include "uassert.h"
#endif
#define DBG_PRN_PKT DBG_PRN
#else
#define DBG_PRN_PKT(...) FUNC_NULL()
#endif
#if DEBUG_PKT_TX
#if !defined(__UASSERT_H__)
#include "uassert.h"
#endif
#define DBG_PRN_PKT_TX DBG_PRN
#else
#define DBG_PRN_PKT_TX(...) FUNC_NULL()
#endif
#define MAC_ADDR_SIZE 6 // 6 bytes
#define RBUF_RX_BUF_NUM 64
#define RBUF_TX_BUF_NUM 64
#define ETH_PKT_MIN_LEN 60 // w/o CRC, w/o vlan tag
#define ETH_TYPE_OFST 12 // ethernet type offset
#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)
{
#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
// clear IRQ status
SWREG_vWriteU16(CPUIF_IRQ_STATUS, IRQ_STATUS_PKT_RX);
// 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;
}
// 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
s_vDmaStartRecv(sg_NetDev.apRBufRx[sg_NetDev.u32RxBufEnque]);
#else
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
}
//
// 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);
// if tx queue is empty
if (sg_NetDev.u32TxBufQueueNum == 0) {
#if !__PKT_PIO
sg_bMuxWrPktInDma = FALSE;
#endif
return;
}
// 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;
}
#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
}
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
// if tx queue is empty
if (sg_NetDev.u32TxBufQueueNum == 0) {
#if !__PKT_PIO
sg_bMuxWrPktInDma = FALSE;
#endif
return;
}
// 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;
}
#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
}
#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.");
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -