⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ks8695end.c

📁 这是micrel公司宽带路由ARM9芯片的VXWORKS BSP 源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* 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 + -