📄 ks8695end.c
字号:
/* ks8695End.c - ks8695 Enhanced Network Driver (END) for KS8695/X/P BSP */
/*
* Author: LIQUN RUAN (RLQ)
**V1.09:---------------------------------------------------------------------
* 05/13/2004 pcd
* (1).Integrate KS8695/KS8695X to KS8695P. They have different features on following ('x' as support):
* WAN LAN HPNA PCI FlowCntl SDRAM WAN_PHY(0xEA14)
* KS8695 x x x 16M 0xB000
* KS8695X x x 16M 0xB000
* KS8695P x x x x 32M 0x0 (default)
*
* The default is is for KS8695P
* The definition "KS8695" is for KS8695
* The definition "KS8695X" is for KS8695X
* (2).Changed ks8695_dump_packet() from LOCAL routine to public routine.
* (3).Bug fix. when run SmartBit to do throughput test, ks8695p SOHO terminal display "Interrupt:ResetDma, not running"
**V1.08:---------------------------------------------------------------------
* 12/12/2003 pcd
* (1). Fixed the TELNET problem. ks8695EndSend() was not properly handling multi-cluster Tx packets.
* 12/03/2003 pcd
* Changed release revision to 6.
* Changed WAN/LAN mac address to Kendin prefix
* Added DEBUG compiler for ksShowStats and ksClearStats to fix compiler error if DEBUG not defined
* 12/03/2003 pcd
* (1). In ks8695EndSend(), if no available TxBufs, call ks8695TxProcess() to clean up processed tx descriptors
* instead of call ks8695HandleTxIntTask(). Deleted ks8695HandleTxIntTask() routine.
* (2). In ks8695TxProcess(), after clean up processed tx descriptors, if there is block trasnmission,
* notify upper protocols Tx descriptors are available.
* 11/25/2003 pcd
* To maxmize the throughtput, we only need to process Transmit Status and
* Receive Status interrupts.
* 11/14/2003
* Some fixed on defines for KS8695/X.
* 10/22/2003
* Code polishing, and enabled watchdog and modified rx stop ISR, disabled more printout
* and displayed version number at start.
* 10/20/2003
* First release with code polishing, bug fix, LAN driver and D-cache enabled.
* 10/15/2003
* Beta release for customer play with.
* 09/18/2003
* Created based on WindRiver's templateEnd.c for Micrel Semiconductor's KS8695/P SOHO router chip
*
*/
/* Copyright 1984-2001 Wind River Systems, Inc. */
/* includes */
#include "vxWorks.h"
#include "stdlib.h"
#include "cacheLib.h"
#include "intLib.h"
#include "end.h" /* Common END structures. */
#include "endLib.h"
#include "lstLib.h" /* Needed to maintain protocol list. */
#include "iv.h"
#include "semLib.h"
#include "logLib.h"
#include "netLib.h"
#include "stdio.h"
#include "sysLib.h"
#include "errno.h"
#include "errnoLib.h"
#include "memLib.h"
#include "iosLib.h"
#include "tickLib.h"
#undef ETHER_MAP_IP_MULTICAST
#include "etherMultiLib.h" /* multicast stuff. */
#include "net/mbuf.h"
#include "net/unixLib.h"
#include "net/protosw.h"
#include "net/systm.h"
#include "net/if_subr.h"
#include "net/route.h"
#include "netinet/if_ether.h"
#include "sys/socket.h"
#include "sys/ioctl.h"
#include "sys/times.h"
#include "wdLib.h"
#include "ks8695End.h" /* KS8695/X/P specific defines. */
IMPORT int endMultiLstCnt (END_OBJ* pEnd);
/* defines */
#define DEBUG
#undef DEBUG_THIS
#undef PACKET_DUMP
#undef USE_PERF_COUNTER
#define CLEAR_IER_BIT
#define NO_RX_UNAVAIL
#undef USE_TX_UNAVAIL
#undef USE_BOTH_TX_UNAVAIL_AND_TX_BIT
#undef TX_PACKET_IN_RCV_TASK
#define KS8695_DRV_NAME "ks" /* max 8 bytes */
#define KS8695_DRV_NAME_LEN (strlen(KS8695_DRV_NAME) + 1)
#ifdef KS8695
char ks8695_driver_name[] = "KS8695";
#elif KS8695X
char ks8695_driver_name[] = "KS8695X";
#else
char ks8695_driver_name[] = "KS8695P";
#endif
char ks8695_driver_version[] = "1.0.5";
char ks8695_copyright[] = "Copyright (c) 2003 Micrel Semiconductor Corp.";
#define STAT_NET(x) (pDrvCtrl->stats.x)
/*#define NO_TASK_DELAY*/
#ifndef NO_TASK_DELAY
#define SW_WRITE_DELAY() taskDelay(4) /* enough delay for cpu 166/125 MHz */
#else
#define SW_WRITE_DELAY() delayEx(400000)
#endif
/* Configuration items */
#define END_BUFSIZ (ETHERMTU + SIZEOF_ETHERHEADER + 6)
#define END_SPEED_10M 10000000 /* 10Mbs full duplex */
#define END_SPEED_100M 100000000 /* 100Mbs full duplex, default */
#define END_SPEED_10M_H 10000000 /* 10Mbs half duplex */
#define END_SPEED_100M_H 100000000 /* 100Mbs half duplex */
#define END_SPEED END_SPEED_100M
/*
* Default macro definitions for BSP interface.
* These macros can be redefined in a wrapper file, to generate
* a new module with an optimized interface.
*/
/* Macro to connect interrupt handler to vector */
#ifndef KS8695_SYS_INT_CONNECT
FUNCPTR ks8695IntConnectRtn = intConnect;
# define KS8695_SYS_INT_CONNECT(pDrvCtrl,rtn,arg,pResult) \
do { \
*pResult = (*ks8695IntConnectRtn) ((VOIDFUNCPTR *) \
INUM_TO_IVEC (pDrvCtrl->ivec), rtn, (int)arg); \
} while (0)
#endif
/* Macro to disconnect interrupt handler from vector */
#ifndef KS8695_SYS_INT_DISCONNECT
STATUS (*ks8695IntDisconnectRtn) \
(int level, FUNCPTR rtn, int arg) = NULL;
# define KS8695_SYS_INT_DISCONNECT(pDrvCtrl,rtn,arg,pResult) \
do { \
if (ks8695IntDisconnectRtn != NULL) \
*pResult = (*ks8695IntDisconnectRtn)(pDrvCtrl->ivec, \
rtn, (int)arg); \
else \
*pResult = ERROR; \
} while (0)
#endif
/* Macro to enable the appropriate interrupt level */
#undef KS8695_SYS_INT_ENABLE
#ifndef KS8695_SYS_INT_ENABLE
STATUS (*ks8695IntEnableRtn)(int level) = intEnable;
# define KS8695_SYS_INT_ENABLE(pDrvCtrl) \
do { \
if (ks8695IntEnableRtn != NULL) \
(*ks8695IntEnableRtn)(pDrvCtrl->ilevel); \
} while (0)
#endif
#undef KS8695_SYS_INT_DISABLE
#ifndef KS8695_SYS_INT_DISABLE
STATUS (*ks8695IntDisableRtn)(int level) = intDisable;
# define KS8695_SYS_INT_DISABLE(pDrvCtrl) \
do { \
if (ks8695IntDisableRtn != NULL) \
(*ks8695IntDisableRtn) (pDrvCtrl->ilevel); \
} while (0)
#endif
/* Macro to get the ethernet address from the BSP */
#ifndef KS8695_SYS_ENET_ADDR_GET
STATUS (*ks8695EnetAddrGetRtn)(int unit, char * pResult) = NULL;
# define KS8695_SYS_ENET_ADDR_GET(pDevice) \
do { \
if (ks8695EnetAddrGetRtn == NULL) \
bzero ((char *)&pDevice->enetAddr, 6); \
else \
(*ks8695EnetAddrGetRtn)(pDevice->unit, \
(char *)&pDevice->enetAddr); \
} while (0)
#endif
/*
* Macros to do a short (UINT16) access to the chip. Default
* assumes a normal memory mapped device.
*/
#ifndef KS8695_OUT_SHORT
STATUS (*ks8695OutShortRtn)(UINT addr, UINT value) = NULL;
# define KS8695_OUT_SHORT(pDrvCtrl,addr,value) \
do { \
if (ks8695OutShortRtn == NULL) \
(*(USHORT *)addr = value) \
else \
(*ks8695OutShortRtn)((UINT)addr, (UINT)value) \
} while (0)
#endif
#ifndef KS8695_IN_SHORT
STATUS (*ks8695InShortRtn)(UINT addr, USHORT *pData) = NULL;
# define KS8695_IN_SHORT(pDrvCtrl,addr,pData) \
do { \
if (ks8695InShortRtn == NULL) \
(*pData = *addr) \
else \
(*ks8695InShortRtn)((UINT)addr, pData) \
} while (0)
#endif
/* A shortcut for getting the hardware address from the MIB II stuff. */
#define KS8695_END_HADDR(pEnd) \
((pEnd)->mib2Tbl.ifPhysAddress.phyAddress)
#define KS8695_END_HADDR_LEN(pEnd) \
((pEnd)->mib2Tbl.ifPhysAddress.addrLength)
/* Cache and PCI-bus related macros */
#define KS8695_VIRT_TO_PHYS(virtAddr) \
CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheDmaFuncs, (char *)(virtAddr))
#define KS8695_LOCAL_TO_SYS(physAddr) \
LOCAL_TO_SYS_ADDR (pDrvCtrl->unit, (physAddr))
#define KS8695_SYS_TO_VIRT(physAddr) \
(KS8695_SYS_TO_LOCAL (((UINT32) KS8695_PHYS_TO_VIRT (physAddr))))
#define KS8695_PHYS_TO_VIRT(physAddr) \
CACHE_DRV_PHYS_TO_VIRT (&pDrvCtrl->cacheDmaFuncs, (char *)(physAddr))
#define KS8695_SYS_TO_LOCAL(virtAddr) \
SYS_TO_LOCAL_ADDR (pDrvCtrl->unit, (virtAddr))
#define KS8695_CACHE_INVALIDATE(address, len) \
CACHE_DRV_INVALIDATE (&pDrvCtrl->cacheFuncs, (address), (len))
#define KS8695_CACHE_FLUSH(address, len) \
CACHE_DRV_FLUSH (&pDrvCtrl->cacheFuncs, (address), (len))
#define KS8695_CACHE_USER_FLUSH(address, len) \
CACHE_USER_FLUSH((address), (len))
#define KS8695_VIRT_TO_SYS(virtAddr) \
KS8695_LOCAL_TO_SYS(((UINT32)KS8695_VIRT_TOPHYS(virtAddr)))
#define KS8695_CACHE_VIRT_TO_PHYS(address) \
((UINT32)CACHE_DRV_VIRT_TO_PHYS(&pDrvCtrl->cacheFuncs, (address)))
#define KS8695_CACHE_DMA_VIRT_TO_PHYS(address) \
((UINT32)CACHE_DMA_VIRT_TO_PHYS(&pDrvCtrl->cacheFuncs, (address)))
#define KS8695_FLAGS_ISSET(pEnd, bits) ((pEnd)->flags & (bits))
/*** END MACROS ***/ /* Should be in endlib.h in my opinion */
#define KS8695_M2_INUCAST(pEnd) (pEnd)->mib2Tbl.ifInUcastPkts++
#define KS8695_M2_INNUCAST(pEnd) (pEnd)->mib2Tbl.ifInNUcastPkts++
#define KS8695_M2_INERRORS(pEnd) (pEnd)->mib2Tbl.ifInErrors++
#define KS8695_M2_INDISCARDS(pEnd) (pEnd)->mib2Tbl.ifInDiscards++
#define KS8695_M2_INOCTETS(pEnd,bytes) (pEnd)->mib2Tbl.ifInOctets += bytes
#define KS8695_M2_OUTUCAST(pEnd) (pEnd)->mib2Tbl.ifOutUcastPkts++
#define KS8695_M2_OUTNUCAST(pEnd) (pEnd)->mib2Tbl.ifOutNUcastPkts++
#define KS8695_M2_OUTDISCARDS(pEnd) pEnd)->mib2Tbl.ifOutDiscards++
#define KS8695_M2_OUTERRORS(pEnd) (pEnd)->mib2Tbl.ifOutErrors++
#define KS8695_M2_OUTOCTETS(pEnd,bytes) (pEnd)->mib2Tbl.ifOutOctets += bytes
/* The definition of the driver control structure */
typedef struct end_device
{
END_OBJ end; /* The class we inherit from. */
int unit; /* unit number */
int ivec; /* interrupt vector */
int ilevel; /* interrupt level */
char* pShMem; /* real ptr to shared memory */
long flags; /* Our local flags. */
UCHAR enetAddr[6]; /* ethernet address */
CACHE_FUNCS cacheFuncs; /* cache function pointers */
CACHE_FUNCS cacheDmaFuncs; /* cache descriptor */
FUNCPTR freeRtn[128]; /* Array of free routines. */
CL_POOL_ID pClPoolId; /* cluster pool */
BOOL rxHandling; /* rcv task is scheduled */
BOOL txHandling; /* rcv task is scheduled */
BOOL txBlocked; /* doesn't have resources to transmit */
BOOL linkHandling; /* WAN link task is scheduled */
/* added KS8695/P specific member variables here */
volatile KS8695_STAT stats; /* KS8695/P stats */
DMA_INFO stDMAInfo; /* DMA information */
UINT32 rev; /* revision number */
struct ks8695_buffer *pTxMblk;
struct ks8695_buffer *pRxMblk;
INT32 nRxDesc; /* number of Rx descriptors */
INT32 nRxDescNextAvail; /* next available Rx descriptor */
INT32 nRxDescNextToFill; /* next Rx desc to fill new buffer to */
RXDESC *pRxDescriptors;
volatile INT32 RxDescEmpty; /* atomic flag for empty Rx descriptor */
INT32 nRxDescTotal; /* total number fo Rx descriptors */
INT32 nTxDesc; /* number of Tx descriptors */
INT32 nTxDescNextAvail; /* next available Tx descriptor */
INT32 nTxDescUsed; /* used Tx descriptor */
volatile INT32 nTransmitCount; /* number of packets to transmit */
INT32 nTxProcessedCount; /* number of packets to transmitted */
INT32 nTxDescTotal; /* total number fo Tx descriptors */
INT32 nTransmitCoalescing; /* Tx packets coalescing count */
volatile INT32 nTxDescAvail;
int offset; /* packet offset, should be 0 or 2 */
WDOG_ID watchdog; /* watch dog id */
int nWatchdogDelay; /* watch dog delay period */
} END_DEVICE, *PEND_DEVICE;
END_DEVICE *gpDrvCtrl[KS8695_DRV_MAX];
/*
* This will only work if there is only a single unit, for multiple
* unit device drivers these should be integrated into the END_DEVICE
* structure.
*/
M_CL_CONFIG ks8695MclBlkConfig = /* network mbuf configuration table */
{
/*
no. mBlks no. clBlks memArea memSize
----------- ---------- ------- -------
*/
0, 0, NULL, 0
};
CL_DESC ks8695ClDescTbl [] = /* network cluster pool configuration table */
{
/*
clusterSize num memArea memSize
----------- ---- ------- -------
*/
{ETHERMTU + ENET_HEADER_SIZE + 2, 0, NULL, 0}
};
int ks8695ClDescTblNumEnt = (NELEMENTS(ks8695ClDescTbl));
/* Definitions for the flags field */
#define KS8695_PROMISCUOUS 0x1
#define KS8695_POLLING 0x2
#define KS8695_MIN_FBUF (1536) /* min data buffer size */
/* DEBUG MACROS */
#ifdef DEBUG
# define LOGMSG(x,a,b,c,d,e,f) \
if (endDebug) \
{ \
logMsg (x,a,b,c,d,e,f); \
}
#else
# define LOGMSG(x,a,b,c,d,e,f)
#endif /* ENDDEBUG */
#undef DRV_DEBUG
#define DRV_DEBUG
#ifdef DRV_DEBUG
#define DRV_DEBUG_OFF 0x00000000
#define DRV_DEBUG_RX 0x00000001
#define DRV_DEBUG_TX 0x00000002
#define DRV_DEBUG_INT 0x00000004
#define DRV_DEBUG_POLL (DRV_DEBUG_POLL_RX | DRV_DEBUG_POLL_TX)
#define DRV_DEBUG_POLL_RX 0x00000008
#define DRV_DEBUG_POLL_TX 0x00000010
#define DRV_DEBUG_LOAD 0x00000020
#define DRV_DEBUG_IOCTL 0x00000040
#define DRV_DEBUG_POLL_REDIR 0x00010000
#define DRV_DEBUG_LOG_NVRAM 0x00020000
#define DRV_DEBUG_LOG_PHY 0x00040000
#define DRV_DEBUG_LOG_TIMER 0x00080000
#define DRV_DEBUG_LOG_TASK 0x00100000
#define DRV_DEBUG_LOG_EXIT 0x00200000
#define DRV_DEBUG_INT_TXRX 0x00400000
#define DRV_DEBUG_TEMP 0x00800000
#define DRV_DEBUG_ERROR 0x10000000
#define DRV_DEBUG_ALL 0xFFFFFFFF
UINT32 ks8695Debug = ( DRV_DEBUG_ERROR /*| DRV_DEBUG_INT | DRV_DEBUG_POLL_RX | DRV_DEBUG_POLL_TX */);
#define DRV_LOG(FLG, X0, X1, X2, X3, X4, X5, X6) \
if (ks8695Debug & FLG) \
logMsg(X0, X1, X2, X3, X4, X5, X6);
#define DRV_PRINT(FLG,X) \
if (ks8695Debug & FLG) printf X;
#else /*DRV_DEBUG*/
#define DRV_LOG(DBG_SW, X0, X1, X2, X3, X4, X5, X6)
#define DRV_PRINT(DBG_SW,X)
#endif /*DRV_DEBUG*/
/* LOCALS */
LOCAL void swResetSNMPInfo(PEND_DEVICE pDrvCtrl);
LOCAL void macStartRx(PEND_DEVICE pDrvCtrl, BOOLEAN bStart);
LOCAL void macStartTx(PEND_DEVICE pDrvCtrl, BOOLEAN bStart);
LOCAL void macEnableInterrupt(PEND_DEVICE pDrvCtrl, BOOLEAN bEnable);
LOCAL void swCreateLookUpTable(PEND_DEVICE pDrvCtrl);
LOCAL void swAutoNegoStart(PEND_DEVICE pDrvCtrl, UINT uPort);
#ifdef USE_POWER_SAVING
LOCAL void ks8695_power_saving(int bSaving);
#endif
LOCAL void swAutoNegoAdvertisement(PEND_DEVICE pDrvCtrl, UINT uPort);
LOCAL void swAutoNegoAdvertisement(PEND_DEVICE pDrvCtrl, UINT uPort);
LOCAL void ks8695IntLink(PEND_DEVICE pDrvCtrl);
LOCAL void ks8695IntLinkTask(PEND_DEVICE pDrvCtrl);
LOCAL void macConfigureFlow(PEND_DEVICE pDrvCtrl, uint8_t bFlowCtrl);
LOCAL int hook_irqs(PEND_DEVICE pDrvCtrl, int req);
LOCAL int AllocateTxDescriptors(PEND_DEVICE pDrvCtrl);
LOCAL int AllocateRxDescriptors(PEND_DEVICE pDrvCtrl);
LOCAL void FreeTxDescriptors(PEND_DEVICE pDrvCtrl);
LOCAL void FreeRxDescriptors(PEND_DEVICE pDrvCtrl);
LOCAL void CleanTxRing(PEND_DEVICE pDrvCtrl);
LOCAL void CleanRxRing(PEND_DEVICE pDrvCtrl);
LOCAL void InitTxRing(PEND_DEVICE pDrvCtrl);
LOCAL void InitRxRing(PEND_DEVICE pDrvCtrl);
LOCAL M_BLK_ID getBufferBlock(PEND_DEVICE pDrvCtrl, UCHAR **pCluster, M_BLK_ID pSrcMblk);
LOCAL void ReceiveBufferFill(PEND_DEVICE pDrvCtrl);
#ifdef USE_FILLEX
LOCAL void ReceiveBufferFillEx(PEND_DEVICE pDrvCtrl);
#endif
LOCAL void swDetectPhyConnection(PEND_DEVICE pDrvCtrl, UINT uPort);
LOCAL void SetDefaults(PEND_DEVICE pDrvCtrl);
LOCAL void printStr(char *str);
LOCAL void ks8695_relink(PEND_DEVICE pDrvCtrl);
LOCAL void ks8695_set_multi(PEND_DEVICE pDrvCtrl);
LOCAL void macStopAll(PEND_DEVICE pDrvCtrl);
LOCAL STATUS ks8695_ChipInit(PEND_DEVICE pDrvCtrl, UINT8 bResetPhy);
#ifdef USE_DUMP_REG
LOCAL void ks8695_dump_reg(PEND_DEVICE pDrvCtrl, UINT32 offset, UINT32 range);
LOCAL void ks8695_dump_reg_set(PEND_DEVICE pDrvCtrl, UINT32 set);
#endif
#ifdef USE_READSNMPREG
LOCAL UINT32 swReadSNMPReg(PEND_DEVICE pDrvCtrl, UINT uIndex);
#endif
LOCAL void ks8695IntTxComp(END_DEVICE *pDrvCtrl);
LOCAL void ks8695IntRxAvail(END_DEVICE *pDrvCtrl);
LOCAL void ks8695IntTxUnavail(END_DEVICE *pDrvCtrl);
LOCAL void ks8695IntRxUnavail(END_DEVICE *pDrvCtrl);
LOCAL void ks8695IntTxStop(END_DEVICE *pDrvCtrl);
LOCAL void ks8695IntRxStop(END_DEVICE *pDrvCtrl);
LOCAL void ks8695TxProcess(PEND_DEVICE pDrvCtrl);
#ifdef DRV_DEBUG
LOCAL void logValue(char *prompt, UINT32 value, int hex, UINT32 flag);
#endif
LOCAL void ks8695_watchdog(PEND_DEVICE pDrvCtrl);
LOCAL M_BLK_ID ReceiveBufferClone(PEND_DEVICE pDrvCtrl, M_BLK_ID pSrcMblk, int len);
#if !defined(KS8695) && !defined(KS8695X)
void forceFlowControl(PEND_DEVICE pDrvCtrl, UINT uPort, UINT bOn);
void backPressureEnable(PEND_DEVICE pDrvCtrl, UINT uPort, UINT bOn);
#endif
#ifdef USE_POWER_SAVING
LOCAL UINT32 bPowerSaving = FALSE;
LOCAL UINT32 bAllowPowerSaving = FALSE;
#endif
#ifdef NO_TASK_DELAY
/*
* delayEx
* This function is use to delay a little bit without using taskDelay.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -