el3c90xEnd.c
资源名称:ixp425BSP.rar [点击查看]
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:136k
源码类别:
VxWorks
开发平台:
C/C++
- /* el3c90xEnd.c - END network interface driver for 3COM 3C90xB XL */
- /* Copyright 1984 - 2002 Wind River Systems, Inc. */
- #include "copyright_wrs.h"
- /*
- modification history
- --------------------
- 01o,22jan02,rcs facilitated common source base with either RFC 1213 or
- RFC 2233 depending on INCLUDE_RFC_1213 macro.
- 01n,28aug01,ann adding the code that copies the pMib2Tbl contents into
- mib2Tbl for backward compatibility - SPR 69697 & 69758
- 01m,16aug01,ann fix for SPR 69673 : we now set the RFC2233 flag in the
- END_OBJ_READY macro call.
- 01l,13jul01,ann eliminating the mibStyle variable and accomodated the
- END_MIB_2233 flag in the END flags field
- 01k,29mar01,spm merged changes from version 01e of tor2_0.open_stack
- branch (wpwr VOB, base 01b) for unified code base
- 01j,10nov00,mks passing in correct type of pointer in strtok_r.
- (SPR 35435 & 62224).
- 01i,20sep00,dat SPR 32058, allow for alternate intConnect rtn
- 01h,28aug00,stv corrected the handling of EIOCSFLAGS ioctl (SPR# 29423).
- 01g,08aug00,stv IFF_UP flag set in the el3c90xStart routine (SPR# 32893,32344,
- 32118).
- 01f,02aug00,stv removed netMblkClChainFree() in Pollsend routine (SPR# 32885).
- 01e,11jun00,ham removed reference to etherLib.
- 01d,27jan00,dat fixed use of NULL
- 01c,01dec99,stv freed mBlk chain before returning ERROR (SPR #28492).
- 01b,11jan99,mtl big endian fix to eprm read rtn.
- 01a,11jan99,mtl written by teamF1 Inc.
- */
- /*
- DESCRIPTION
- This module implements the device driver for the 3COM EtherLink Xl and
- Fast EtherLink XL PCI network interface cards.
- The 3c90x PCI ethernet controller is inherently little endian because
- the chip is designed to operate on a PCI bus which is a little endian
- bus. The software interface to the driver is divided into three parts.
- The first part is the PCI configuration registers and their set up.
- This part is done at the BSP level in the various BSPs which use this
- driver. The second and third part are dealt in the driver. The second
- part of the interface comprises of the I/O control registers and their
- programming. The third part of the interface comprises of the descriptors
- and the buffers.
- This driver is designed to be moderately generic, operating unmodified
- across the range of architectures and targets supported by VxWorks. To
- achieve this, the driver must be given several target-specific parameters,
- and some external support routines must be provided. These target-specific
- values and the external support routines are described below.
- This driver supports multiple units per CPU. The driver can be
- configured to support big-endian or little-endian architectures. It
- contains error recovery code to handle known device errata related to DMA
- activity.
- Big endian processors can be connected to the PCI bus through some controllers
- which take care of hardware byte swapping. In such cases all the registers
- which the chip DMA s to have to be swapped and written to, so that when the
- hardware swaps the accesses, the chip would see them correctly. The chip still
- has to be programmed to operated in little endian mode as it is on the PCI bus.
- If the cpu board hardware automatically swaps all the accesses to and from the
- PCI bus, then input and output byte stream need not be swapped.
- The 3c90x series chips use a bus-master DMA interface for transfering
- packets to and from the controller chip. Some of the old 3c59x cards
- also supported a bus master mode, however for those chips
- you could only DMA packets to and from a contiguous memory buffer. For
- transmission this would mean copying the contents of the queued M_BLK
- chain into a an M_BLK cluster and then DMAing the cluster. This extra
- copy would sort of defeat the purpose of the bus master support for
- any packet that doesn't fit into a single M_BLK. By contrast, the 3c90x cards
- support a fragment-based bus master mode where M_BLK chains can be
- encapsulated using TX descriptors. This is also called the gather technique,
- where the fragments in an mBlk chain are directly incorporated into the
- download transmit descriptor. This avoids any copying of data from the
- mBlk chain.
- NETWORK CARDS SUPPORTED:
- - 3Com 3c900-TPO 10Mbps/RJ-45
- - 3Com 3c900-COMBO 10Mbps/RJ-45,AUI,BNC
- - 3Com 3c905-TX 10/100Mbps/RJ-45
- - 3Com 3c905-T4 10/100Mbps/RJ-45
- - 3Com 3c900B-TPO 10Mbps/RJ-45
- - 3Com 3c900B-COMBO 10Mbps/RJ-45,AUI,BNC
- - 3Com 3c905B-TX 10/100Mbps/RJ-45
- - 3Com 3c905B-FL/FX 10/100Mbps/Fiber-optic
- - 3Com 3c980-TX 10/100Mbps server adapter
- - Dell Optiplex GX1 on-board 3c918 10/100Mbps/RJ-45
- BOARD LAYOUT
- This device is on-board. No jumpering diagram is necessary.
- EXTERNAL INTERFACE
- The only external interface is the el3c90xEndLoad() routine, which expects
- the <initString> parameter as input. This parameter passes in a
- colon-delimited string of the format:
- <unit>:<devMemAddr>:<devIoAddr>:<pciMemBase:<vecNum>:<intLvl>:<memAdrs>:
- <memSize>:<memWidth>:<flags>:<buffMultiplier>
- The el3c90xEndLoad() function uses strtok() to parse the string.
- TARGET-SPECIFIC PARAMETERS
- .IP <unit>
- A convenient holdover from the former model. This parameter is used only
- in the string name for the driver.
- .IP <devMemAddr>
- This parameter in the memory base address of the device registers in the
- memory map of the CPU. It indicates to the driver where to find the
- register set. < This parameter should be equal to NONE if the device
- does not support memory mapped registers.
- .IP <devIoAddr>
- This parameter in the IO base address of the device registers in the
- IO map of some CPUs. It indicates to the driver where to find the RDP
- register. If both <devIoAddr> and <devMemAddr> are given then the device
- chooses <devMemAddr> which is a memory mapped register base address.
- This parameter should be equal to NONE if the device does not support
- IO mapped registers.
- . <pciMemBase>
- This parameter is the base address of the CPU memory as seen from the
- PCI bus. This parameter is zero for most intel architectures.
- .IP <vecNum>
- This parameter is the vector associated with the device interrupt.
- This driver configures the LANCE device to generate hardware interrupts
- for various events within the device; thus it contains
- an interrupt handler routine. The driver calls intConnect() to connect
- its interrupt handler to the interrupt vector generated as a result of
- the LANCE interrupt. The BSP can use a different routine for interrupt
- connection by changing the point el3c90xIntConnectRtn to point to a
- different routine.
- .IP <intLvl>
- Some targets use additional interrupt controller devices to help organize
- and service the various interrupt sources. This driver avoids all
- board-specific knowledge of such devices. During the driver's
- initialization, the external routine sysEl3c90xIntEnable() is called to
- perform any board-specific operations required to allow the servicing of a
- NIC interrupt. For a description of sysEl3c90xIntEnable(), see "External
- Support Requirements" below.
- .IP <memAdrs>
- This parameter gives the driver the memory address to carve out its
- buffers and data structures. If this parameter is specified to be
- NONE then the driver allocates cache coherent memory for buffers
- and descriptors from the system pool.
- The 3C90x NIC is a DMA type of device and typically shares access to
- some region of memory with the CPU. This driver is designed for systems
- that directly share memory between the CPU and the NIC. It
- assumes that this shared memory is directly available to it
- without any arbitration or timing concerns.
- .IP <memSize>
- This parameter can be used to explicitly limit the amount of shared
- memory (bytes) this driver will use. The constant NONE can be used to
- indicate no specific size limitation. This parameter is used only if
- a specific memory region is provided to the driver.
- .IP <memWidth>
- Some target hardware that restricts the shared memory region to a
- specific location also restricts the access width to this region by
- the CPU. On these targets, performing an access of an invalid width
- will cause a bus error.
- This parameter can be used to specify the number of bytes of access
- width to be used by the driver during access to the shared memory.
- The constant NONE can be used to indicate no restrictions.
- Current internal support for this mechanism is not robust; implementation
- may not work on all targets requiring these restrictions.
- .IP <flags>
- This is parameter is used for future use, currently its value should be
- zero.
- .IP <buffMultiplier>
- This parameter is used increase the number of buffers allocated in the
- driver pool. If this parameter is -1 then a default multiplier of 2 is
- choosen. With a multiplier of 2 the total number of clusters allocated
- is 64 which is twice the cumulative number of upload and download descriptors.
- The device has 16 upload and 16 download descriptors. For example on choosing
- the buffer multiplier of 3, the total number of clusters allocated will be
- 96 ((16 + 16)*3). There are as many clBlks as the number of clusters.
- The number of mBlks allocated are twice the number of clBlks.
- By default there are 64 clusters, 64 clBlks and 128 mBlks allocated in the
- pool for the device. Depending on the load of the system increase the
- number of clusters allocated by incrementing the buffer multiplier.
- EXTERNAL SUPPORT REQUIREMENTS
- This driver requires several external support functions, defined as macros:
- .CS
- SYS_INT_CONNECT(pDrvCtrl, routine, arg)
- SYS_INT_DISCONNECT (pDrvCtrl, routine, arg)
- SYS_INT_ENABLE(pDrvCtrl)
- SYS_INT_DISABLE(pDrvCtrl)
- SYS_OUT_BYTE(pDrvCtrl, reg, data)
- SYS_IN_BYTE(pDrvCtrl, reg, data)
- SYS_OUT_WORD(pDrvCtrl, reg, data)
- SYS_IN_WORD(pDrvCtrl, reg, data)
- SYS_OUT_LONG(pDrvCtrl, reg, data)
- SYS_IN_LONG(pDrvCtrl, reg, data)
- SYS_DELAY (delay)
- sysEl3c90xIntEnable(pDrvCtrl->intLevel)
- sysEl3c90xIntDisable(pDrvCtrl->intLevel)
- sysDelay (delay)
- .CE
- There are default values in the source code for these macros. They presume
- memory mapped accesses to the device registers and the normal intConnect(),
- and intEnable() BSP functions. The first argument to each is the device
- controller structure. Thus, each has access back to all the device-specific
- information. Having the pointer in the macro facilitates the addition
- of new features to this driver.
- The macros SYS_INT_CONNECT, SYS_INT_DISCONNECT, SYS_INT_ENABLE and
- SYS_INT_DISABLE allow the driver to be customized for BSPs that use special
- versions of these routines.
- The macro SYS_INT_CONNECT is used to connect the interrupt handler to
- the appropriate vector. By default it is the routine intConnect().
- The macro SYS_INT_DISCONNECT is used to disconnect the interrupt handler prior
- to unloading the module. By default this is a dummy routine that
- returns OK.
- The macro SYS_INT_ENABLE is used to enable the interrupt level for the
- end device. It is called once during initialization. It calls an
- external board level routine sysEl3c90xIntEnable().
- The macro SYS_INT_DISABLE is used to disable the interrupt level for the
- end device. It is called during stop. It calls an
- external board level routine sysEl3c90xIntDisable().
- The macro SYS_DELAY is used for a delay loop. It calls an external board
- level routine sysDelay(delay). The granularity of delay is one microsecond.
- SYSTEM RESOURCE USAGE
- When implemented, this driver requires the following system resources:
- - one mutual exclusion semaphore
- - one interrupt vector
- - 24072 bytes in text for a I80486 target
- - 112 bytes in the initialized data section (data)
- - 0 bytes in the uninitialized data section (BSS)
- The driver allocates clusters of size 1536 bytes for receive frames and
- and transmit frames. There are 16 descriptors in the upload ring
- and 16 descriptors in the download ring. The buffer multiplier by default
- is 2, which means that the total number of clusters allocated by default
- are 64 ((upload descriptors + download descriptors)*2). There are as many
- clBlks as the number of clusters. The number of mBlks allocated are twice
- the number of clBlks. By default there are 64 clusters, 64 clBlks and 128
- mBlks allocated in the pool for the device. Depending on the load of the
- system increase the number of clusters allocated by incrementing the buffer
- multiplier.
- INCLUDES:
- end.h endLib.h etherMultiLib.h el3c90xEnd.h
- SEE ALSO: muxLib, endLib, netBufLib
- .pG "Writing and Enhanced Network Driver"
- .SH "BIBLIOGRAPHY"
- .iB "3COM 3c90x and 3c90xB NICs Technical reference."
- */
- #include "vxWorks.h"
- #include "wdLib.h"
- #include "stdlib.h"
- #include "taskLib.h"
- #include "tickLib.h"
- #include "logLib.h"
- #include "intLib.h"
- #include "netLib.h"
- #include "stdio.h"
- #include "stdlib.h"
- #include "sysLib.h"
- #include "iv.h"
- #include "memLib.h"
- #include "semLib.h"
- #include "cacheLib.h"
- #include "sys/ioctl.h"
- #include "etherMultiLib.h" /* multicast stuff. */
- #include "end.h" /* Common END structures. */
- #include "endLib.h"
- #include "lstLib.h" /* Needed to maintain protocol list. */
- #include "netBufLib.h"
- #include "muxLib.h"
- #include "m2Lib.h"
- #include "drv/end/el3c90xEnd.h"
- #ifndef EL3C90X_CACHE_INVALIDATE
- #define EL3C90X_CACHE_INVALIDATE(address, len)
- CACHE_DRV_INVALIDATE (&pDrvCtrl->cacheFuncs, (address), (len))
- #endif /* EL3C90X_CACHE_INVALIDATE */
- #ifndef EL3C90X_CACHE_VIRT_TO_PHYS
- #define EL3C90X_CACHE_VIRT_TO_PHYS(address)
- (MEM_TO_PCI_PHYS((UINT32)(CACHE_DRV_VIRT_TO_PHYS
- (&pDrvCtrl->cacheFuncs,(address)))))
- #endif /* EL3C90X_CACHE_VIRT_TO_PHYS */
- /* memory to PCI address translation macro */
- #ifndef MEM_TO_PCI_PHYS
- #define MEM_TO_PCI_PHYS(memAdrs)
- ((memAdrs) + (pDrvCtrl->pciMemBase))
- #endif
- /*
- * 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 SYS_INT_CONNECT
- #define SYS_INT_CONNECT(pDrvCtrl,rtn,arg,pResult)
- {
- *pResult = (*el3c90xIntConnectRtn) ((VOIDFUNCPTR *)
- INUM_TO_IVEC (pDrvCtrl->ivec),
- rtn, (int)arg);
- }
- #endif
- /* Macro to disconnect interrupt handler from vector */
- #ifndef SYS_INT_DISCONNECT
- #define SYS_INT_DISCONNECT(pDrvCtrl,rtn,arg,pResult)
- {
- *pResult = OK;
- }
- #endif
- /* Macro to enable the appropriate interrupt level */
- #ifndef SYS_INT_ENABLE
- #define SYS_INT_ENABLE(pDrvCtrl)
- {
- IMPORT STATUS sysEl3c90xIntEnable();
- sysEl3c90xIntEnable ((pDrvCtrl)->intLevel);
- }
- #endif /* SYS_INT_ENABLE*/
- /* Macro to disable the appropriate interrupt level */
- #ifndef SYS_INT_DISABLE
- #define SYS_INT_DISABLE(pDrvCtrl)
- {
- IMPORT void sysEl3c90xIntDisable ();
- sysEl3c90xIntDisable ((pDrvCtrl)->intLevel);
- }
- #endif
- #ifndef SYS_OUT_LONG
- #define SYS_OUT_LONG(pDrvCtrl,addr,value)
- {
- *((ULONG *)(addr)) = PCI_SWAP((value));
- }
- #endif /* SYS_OUT_LONG */
- #ifndef SYS_IN_LONG
- #define SYS_IN_LONG(pDrvCtrl,addr,data)
- {
- ((data) = PCI_SWAP(*((ULONG *)(addr))));
- }
- #endif /* SYS_IN_LONG */
- #ifndef SYS_OUT_SHORT
- #define SYS_OUT_SHORT(pDrvCtrl,addr,value)
- {
- *((USHORT *)(addr)) = PCI_WORD_SWAP((value));
- }
- #endif /* SYS_OUT_SHORT*/
- #ifndef SYS_IN_SHORT
- #define SYS_IN_SHORT(pDrvCtrl,addr,data)
- {
- ((data) = PCI_WORD_SWAP(*((USHORT *)(addr))));
- }
- #endif /* SYS_IN_SHORT*/
- #ifndef SYS_OUT_BYTE
- #define SYS_OUT_BYTE(pDrvCtrl,addr,value)
- {
- *((UCHAR *)(addr)) = (value);
- }
- #endif /* SYS_OUT_BYTE */
- #ifndef SYS_IN_BYTE
- #define SYS_IN_BYTE(pDrvCtrl,addr,data)
- {
- ((data) = *((UCHAR *)(addr)));
- }
- #endif /* SYS_IN_BYTE */
- #ifndef SYS_DELAY
- #define SYS_DELAY(x)
- {
- int loop;
- loop = (x);
- loop = ((loop * 3) >> 1);
- while (loop--)
- sysDelay();
- }
- #endif /* SYS_DELAY */
- /* A shortcut for getting the hardware address from the MIB II stuff. */
- #ifdef INCLUDE_RFC_1213
- /* Old RFC 1213 mib2 interface */
- #define END_HADDR(pEnd)
- ((pEnd)->mib2Tbl.ifPhysAddress.phyAddress)
- #define END_HADDR_LEN(pEnd)
- ((pEnd)->mib2Tbl.ifPhysAddress.addrLength)
- #else
- /* New RFC 2233 mib2 interface */
- #define END_HADDR(pEnd)
- ((pEnd)->pMib2Tbl->m2Data.mibIfTbl.ifPhysAddress.phyAddress)
- #define END_HADDR_LEN(pEnd)
- ((pEnd)->pMib2Tbl->m2Data.mibIfTbl.ifPhysAddress.addrLength)
- #endif /* INCLUDE_RFC_1213 */
- #define END_FLAGS_ISSET(pEnd, setBits)
- ((pEnd)->flags & (setBits))
- #define VOID_TO_DRVCTRL(pVoid,pDrvCtrl) ((pDrvCtrl)=(EL3C90X_DEVICE *)(pVoid))
- /* externs */
- IMPORT int endMultiLstCnt (END_OBJ *);
- IMPORT void sysDelay(); /* x86 bSP implements around 720 ns delay */
- /* DEBUG MACROS */
- #ifdef DRV_DEBUG /* if debugging driver */
- int el3c90xDebug = DRV_DEBUG_LOAD| DRV_DEBUG_INT | DRV_DEBUG_TX;
- NET_POOL * pElXlPool;
- #define DRV_LOG(FLG, X0, X1, X2, X3, X4, X5, X6)
- if (el3c90xDebug & FLG)
- logMsg((char *)X0, (int)X1, (int)X2, (int)X3, (int)X4,
- (int)X5, (int)X6);
- #define ENDLOGMSG(x)
- if (el3c90xDebug)
- {
- logMsg x;
- }
- #define DRV_PRINT(FLG,X)
- if (el3c90xDebug & FLG) printf X;
- #else /*DRV_DEBUG*/
- #define DRV_LOG(DBG_SW, X0, X1, X2, X3, X4, X5, X6)
- #define DRV_PRINT(DBG_SW,X)
- #define ENDLOGMSG(x)
- #endif /*DRV_DEBUG*/
- FUNCPTR el3c90xIntConnectRtn = intConnect;
- /*
- * Various supported PHY vendors/types and their names. Note that
- * this driver will work with pretty much any MII-compliant PHY,
- * so failure to positively identify the chip is not a fatal error.
- */
- LOCAL EL_DEV_TYPE el3c90xPhyTbl[ ] =
- {
- { TI_PHY_VENDORID, TI_PHY_10BT, "<TI ThunderLAN 10BT (internal)>" },
- { TI_PHY_VENDORID, TI_PHY_100VGPMI, "<TI TNETE211 100VG Any-LAN>" },
- { NS_PHY_VENDORID, NS_PHY_83840A, "<National Semiconductor DP83840A>"},
- { LEVEL1_PHY_VENDORID, LEVEL1_PHY_LXT970, "<Level 1 LXT970>" },
- { INTEL_PHY_VENDORID, INTEL_PHY_82555, "<Intel 82555>" },
- { SEEQ_PHY_VENDORID, SEEQ_PHY_80220, "<SEEQ 80220>" },
- { 0, 0, "<MII-compliant physical interface>" }
- };
- LOCAL STATUS el3c90xStart (void * pEnd);
- LOCAL STATUS el3c90xStop (void * pEnd);
- LOCAL STATUS el3c90xUnload (void * pEnd);
- LOCAL int el3c90xIoctl (void * pEnd, int cmd, caddr_t data);
- LOCAL STATUS el3c90xSend (void * pEnd, M_BLK_ID pMblk);
- LOCAL STATUS el3c90xMCastAdd (void * pEnd, char * pAddress);
- LOCAL STATUS el3c90xMCastDel (void * pEnd, char * pAddress);
- LOCAL STATUS el3c90xMCastGet (void * pEnd, MULTI_TABLE * pTable);
- LOCAL STATUS el3c90xPollSend (void * pEnd, M_BLK_ID pMblk);
- LOCAL STATUS el3c90xPollRcv (void * pEnd, M_BLK_ID pMblk);
- LOCAL void el3c90xInit (EL3C90X_DEVICE *);
- LOCAL STATUS el3c90xMemInit (EL3C90X_DEVICE * pDrvCtrl);
- LOCAL void el3c90xDevStop (EL3C90X_DEVICE *);
- LOCAL void el3c90xReset (EL3C90X_DEVICE *);
- LOCAL void el3c90xIntEnable (EL3C90X_DEVICE * pDrvCtrl);
- LOCAL void el3c90xIntDisable (EL3C90X_DEVICE * pDrvCtrl);
- LOCAL STATUS el3c90xPollStart(EL3C90X_DEVICE * pDrvCtrl);
- LOCAL STATUS el3c90xPollStop (EL3C90X_DEVICE * pDrvCtrl);
- LOCAL int el3c90xUpdInit (EL3C90X_DEVICE *);
- LOCAL int el3c90xDndInit (EL3C90X_DEVICE *);
- LOCAL UINT8 el3c90xHashGet (char *);
- LOCAL void el3c90xFilterSet (EL3C90X_DEVICE *);
- LOCAL void el3c90xHashFilterSet (EL3C90X_DEVICE *);
- LOCAL void el3c90xMcastConfig (EL3C90X_DEVICE * pDrvCtrl);
- LOCAL int el3c90xUpdFill (EL3C90X_DEVICE *, EL_SIMPLE_DESC_CHAIN *);
- LOCAL STATUS el3c90xDndMblkPack (EL3C90X_DEVICE *, EL_DESC_CHAIN *, M_BLK_ID);
- LOCAL int el3c90xDndSet (EL3C90X_DEVICE *, EL_DESC_CHAIN *, M_BLK * );
- LOCAL STATUS el3c90xDndFree (EL3C90X_DEVICE *, EL_DESC_CHAIN *);
- LOCAL STATUS el3c90xDndEnqueue (EL3C90X_DEVICE *, EL_DESC_CHAIN *);
- LOCAL EL_DESC_CHAIN * el3c90xDndGet (EL3C90X_DEVICE * pDrvCtrl);
- LOCAL EL_DESC_CHAIN * el3c90xTxDequeue (EL3C90X_DEVICE * pDrvCtrl);
- LOCAL M_BLK_ID el3c90xNextPktFetch (EL3C90X_DEVICE *, EL_SIMPLE_DESC_CHAIN *);
- LOCAL EL_SIMPLE_DESC_CHAIN * el3c90xNextUpdFetch (EL3C90X_DEVICE * pDrvCtrl);
- LOCAL STATUS el3c90xRxUnStall (EL3C90X_DEVICE * pDrvCtrl);
- LOCAL void el3c90xRxKick (EL3C90X_DEVICE * pDrvCtrl);
- LOCAL void el3c90xIntrRx (EL3C90X_DEVICE * pDrvCtrl);
- LOCAL void el3c90xIntrTx (EL3C90X_DEVICE * pDrvCtrl);
- LOCAL void el3c90xIntrErr (EL3C90X_DEVICE * pDrvCtrl, UINT8 txstat);
- LOCAL void el3c90xStatUpdate (EL3C90X_DEVICE *);
- LOCAL void el3c90xInt (EL3C90X_DEVICE * pDrvCtrl);
- LOCAL void el3c90xMiiSync (EL3C90X_DEVICE *);
- LOCAL void el3c90xMiiSend (EL3C90X_DEVICE *, UINT32, int);
- LOCAL int el3c90xMiiRegRead (EL3C90X_DEVICE *, EL_MII_FRAME *);
- LOCAL int el3c90xMiiRegWrite (EL3C90X_DEVICE *, EL_MII_FRAME *);
- LOCAL UINT16 el3c90xPhyRegRead (EL3C90X_DEVICE *, int);
- LOCAL void el3c90xPhyRegWrite (EL3C90X_DEVICE *, int, int);
- LOCAL void el3c90xAutoNegTx (EL3C90X_DEVICE *);
- LOCAL void el3c90xMiiAutoNeg (EL3C90X_DEVICE *);
- LOCAL int el3c90xMiiModeGet (EL3C90X_DEVICE *);
- LOCAL void el3c90xMediaSet (EL3C90X_DEVICE *, int);
- LOCAL void el3c90xMediaCheck (EL3C90X_DEVICE *);
- LOCAL int el3c90xMediaConfig (EL3C90X_DEVICE * pDrvCtrl);
- LOCAL int el3c90xEprmWait (EL3C90X_DEVICE *);
- LOCAL int el3c90xEprmRead (EL3C90X_DEVICE *, caddr_t, int, int, int);
- LOCAL void el3c90xWait (EL3C90X_DEVICE *);
- LOCAL void el3c90xIntrSet (EL3C90X_DEVICE * pDrvCtrl, UINT16 flag);
- LOCAL void el3c90xIntrClr (EL3C90X_DEVICE * pDrvCtrl, UINT16 flag);
- LOCAL UCHAR el3c90xCsrReadByte (EL3C90X_DEVICE *, USHORT, int);
- LOCAL USHORT el3c90xCsrReadWord (EL3C90X_DEVICE *, USHORT, int);
- LOCAL ULONG el3c90xCsrReadLong (EL3C90X_DEVICE *, USHORT, int);
- LOCAL void el3c90xCsrWriteByte (EL3C90X_DEVICE *, USHORT, UCHAR, int);
- LOCAL void el3c90xCsrWriteWord (EL3C90X_DEVICE *, USHORT, USHORT, int);
- LOCAL void el3c90xCsrWriteLong (EL3C90X_DEVICE *, USHORT, ULONG, int);
- /*
- * Declare our function table. This is static across all driver
- * instances.
- */
- LOCAL NET_FUNCS el3c90xFuncTable =
- {
- (FUNCPTR) el3c90xStart, /* Function to start the device. */
- (FUNCPTR) el3c90xStop, /* Function to stop the device. */
- (FUNCPTR) el3c90xUnload, /* Unloading function for the driver. */
- (FUNCPTR) el3c90xIoctl, /* Ioctl function for the driver. */
- (FUNCPTR) el3c90xSend, /* Send function for the driver. */
- (FUNCPTR) el3c90xMCastAdd, /* Multicast address add function for the */
- /* driver. */
- (FUNCPTR) el3c90xMCastDel, /* Multicast address delete function for */
- /* the driver. */
- (FUNCPTR) el3c90xMCastGet, /* Multicast table retrieve function for */
- /* the driver. */
- (FUNCPTR) el3c90xPollSend, /* Polling send function for the driver. */
- (FUNCPTR) el3c90xPollRcv, /* Polling receive function for the driver. */
- endEtherAddressForm, /* Put address info into a packet. */
- (FUNCPTR) endEtherPacketDataGet,/* Get a pointer to packet data. */
- (FUNCPTR) endEtherPacketAddrGet /* Get packet addresses. */
- };
- /******************************************************************************
- *
- * el3c90xEndLoad - initialize the driver and device
- *
- * This routine initializes the driver and the device to the operational state.
- * All of the device-specific parameters are passed in <initString>, which
- * expects a string of the following format:
- *
- * <unit>:<devMemAddr>:<devIoAddr>:<pciMemBase:<vecnum>:<intLvl>:<memAdrs>
- * :<memSize>:<memWidth>:<flags>:<buffMultiplier>
- *
- * This routine can be called in two modes. If it is called with an empty but
- * allocated string, it places the name of this device (that is, "elPci") into
- * the <initString> and returns 0.
- *
- * If the string is allocated and not empty, the routine attempts to load
- * the driver using the values specified in the string.
- *
- * RETURNS: An END object pointer, or NULL on error, or 0 and the name of the
- * device if the <initString> was NULL.
- */
- END_OBJ * el3c90xEndLoad
- (
- char * initString /* String to be parsed by the driver. */
- )
- {
- EL3C90X_DEVICE * pDrvCtrl = NULL;
- int speed;
- DRV_LOG (DRV_DEBUG_LOAD, "Loading elPci...n", 1, 2, 3, 4, 5, 6);
- if (initString == NULL)
- return (NULL);
- if (initString [0] == 0)
- {
- bcopy ((char *)EL3C90X_DEV_NAME, initString,
- EL3C90X_DEV_NAME_LEN);
- return (0);
- }
- if ((pDrvCtrl = (EL3C90X_DEVICE *)calloc (sizeof (EL3C90X_DEVICE), 1))
- == NULL)
- return (NULL);
- /* parse the init string, filling in the device structure */
- if (el3c90xInitParse (pDrvCtrl, initString) == ERROR)
- goto endLoadFail;
- /* initialize the END and MIB2 parts of the structure */
- if (END_OBJ_INIT (&pDrvCtrl->endObj, (DEV_OBJ *)pDrvCtrl,
- EL3C90X_DEV_NAME,
- pDrvCtrl->unit, &el3c90xFuncTable,
- "3COM 3c90X Fast Etherlink Endhanced Network Driver.")
- == ERROR)
- {
- goto endLoadFail;
- }
- /* Reset the adapter. */
- el3c90xReset(pDrvCtrl);
- /* get station address from the EEPROM */
- if (el3c90xEprmRead(pDrvCtrl, &pDrvCtrl->enetAddr[0], EL_EE_OEM_ADR0, 3, 1)
- != OK)
- {
- DRV_LOG (DRV_DEBUG_LOAD, "elPci%d: failed to read station addressn",
- pDrvCtrl->unit, 2, 3, 4, 5, 6);
- goto endLoadFail;
- }
- /* Perform memory allocation */
- if (el3c90xMemInit (pDrvCtrl) == ERROR)
- goto endLoadFail;
- DRV_LOG (DRV_DEBUG_LOAD, "Malloc done ...n", 1, 2, 3, 4, 5, 6);
- /*
- * Figure out the card type. 3c905B adapters have the
- * 'supportsNoTxLength' bit set in the capabilities
- * word in the EEPROM.
- */
- el3c90xEprmRead(pDrvCtrl, (caddr_t)&pDrvCtrl->devCaps, EL_EE_CAPS, 1, 0);
- if (pDrvCtrl->devCaps & EL_CAPS_NO_TXLENGTH)
- pDrvCtrl->devType = EL_TYPE_905B;
- else
- pDrvCtrl->devType = EL_TYPE_90X;
- speed = el3c90xMediaConfig (pDrvCtrl);
- #ifdef INCLUDE_RFC_1213
- /* Old RFC 1213 mib2 interface */
- if (END_MIB_INIT (&pDrvCtrl->endObj, M2_ifType_ethernet_csmacd,
- &pDrvCtrl->enetAddr[0], 6, ETHERMTU, speed)
- == ERROR)
- goto endLoadFail;
- /* set the flags to indicate readiness */
- END_OBJ_READY (&pDrvCtrl->endObj, IFF_NOTRAILERS | IFF_BROADCAST |
- IFF_MULTICAST | IFF_SIMPLEX);
- #else
- /* New RFC 2233 mib2 interface */
- /* Initialize MIB-II entries (for RFC 2233 ifXTable) */
- pDrvCtrl->endObj.pMib2Tbl = m2IfAlloc(M2_ifType_ethernet_csmacd,
- (UINT8*) &pDrvCtrl->enetAddr[0], 6,
- ETHERMTU, speed,
- EL3C90X_DEV_NAME, pDrvCtrl->unit);
- if (pDrvCtrl->endObj.pMib2Tbl == NULL)
- {
- printf ("%s%d - MIB-II initializations failedn",
- EL3C90X_DEV_NAME, pDrvCtrl->unit);
- goto endLoadFail;
- }
- /*
- * Set the RFC2233 flag bit in the END object flags field and
- * install the counter update routines.
- */
- pDrvCtrl->endObj.flags |= END_MIB_2233;
- m2IfPktCountRtnInstall(pDrvCtrl->endObj.pMib2Tbl, m2If8023PacketCount);
- /*
- * Make a copy of the data in mib2Tbl struct as well. We do this
- * mainly for backward compatibility issues. There might be some
- * code that might be referencing the END pointer and might
- * possibly do lookups on the mib2Tbl, which will cause all sorts
- * of problems.
- */
- bcopy ((char *)&pDrvCtrl->endObj.pMib2Tbl->m2Data.mibIfTbl,
- (char *)&pDrvCtrl->endObj.mib2Tbl, sizeof (M2_INTERFACETBL));
- /* set the flags to indicate readiness */
- END_OBJ_READY (&pDrvCtrl->endObj, IFF_NOTRAILERS | IFF_BROADCAST |
- IFF_MULTICAST | IFF_SIMPLEX | END_MIB_2233);
- #endif /* INCLUDE_RFC_1213 */
- DRV_LOG (DRV_DEBUG_LOAD, "Done loading elPci...n", 1, 2, 3, 4, 5, 6);
- return (&pDrvCtrl->endObj);
- endLoadFail:
- {
- if (pDrvCtrl != NULL)
- free ((char *)pDrvCtrl);
- }
- return ((END_OBJ *)NULL);
- }
- /*******************************************************************************
- *
- * el3c90xInitParse - parse the initialization string
- *
- * Parse the input string. This routine is called from el3c90xEndLoad() which
- * intializes some values in the driver control structure with the values
- * passed in the intialization string.
- *
- * The initialization string format is:
- * <unit>:<devMemAddr>:<devIoAddr>:<pciMemBase:<vecNum>:<intLvl>:<memAdrs>
- * :<memSize>:<memWidth>:<flags>:<buffMultiplier>
- *
- * .IP <unit>
- * Device unit number, a small integer.
- * .IP <devMemAddr>
- * Device register base memory address
- * .IP <devIoAddr>
- * Device register base IO address
- * .IP <pciMemBase>
- * Base address of PCI memory space
- * .IP <vecNum>
- * Interrupt vector number.
- * .IP <intLvl>
- * Interrupt level.
- * .IP <memAdrs>
- * Memory pool address or NONE.
- * .IP <memSize>
- * Memory pool size or zero.
- * .IP <memWidth>
- * Memory system size, 1, 2, or 4 bytes (optional).
- * .IP <flags>
- * Device specific flags, for future use.
- * .IP <buffMultiplier>
- * Buffer Multiplier or NONE. If NONE is specified, it defaults to 2
- *
- * RETURNS: OK, or ERROR if any arguments are invalid.
- */
- STATUS el3c90xInitParse
- (
- EL3C90X_DEVICE * pDrvCtrl, /* pointer to the control structure */
- char * initString /* initialization string */
- )
- {
- char* tok;
- char* pHolder = NULL;
- UINT32 devMemAddr;
- UINT32 devIoAddr;
- DRV_LOG (DRV_DEBUG_LOAD, "Parse starting ...n", 1, 2, 3, 4, 5, 6);
- /* Parse the initString */
- /* Unit number. */
- tok = strtok_r (initString, ":", &pHolder);
- if (tok == NULL)
- return ERROR;
- pDrvCtrl->unit = atoi (tok);
- DRV_LOG (DRV_DEBUG_LOAD, "Unit : %d ...n", pDrvCtrl->unit, 2, 3, 4, 5, 6);
- /* devAdrs address. */
- tok = strtok_r (NULL, ":", &pHolder);
- if (tok == NULL)
- return ERROR;
- devMemAddr = (UINT32) strtoul (tok, NULL, 16);
- DRV_LOG (DRV_DEBUG_LOAD, "devMemAddr : 0x%X ...n", devMemAddr,
- 2, 3, 4, 5, 6);
- /* devIoAddrs address */
- tok = strtok_r (NULL, ":", &pHolder);
- if (tok == NULL)
- return ERROR;
- devIoAddr = (UINT32) strtoul (tok, NULL, 16);
- DRV_LOG (DRV_DEBUG_LOAD, "devIoAddr : 0x%X ...n", devIoAddr,
- 2, 3, 4, 5, 6);
- /* always use memory mapped IO if provided, else use io map */
- if ((devMemAddr == NONE) && (devIoAddr == NONE))
- {
- DRV_LOG (DRV_DEBUG_LOAD, "No memory or IO base specified ...n",
- 1, 2, 3, 4, 5, 6);
- return (ERROR);
- }
- else if (devMemAddr != NONE)
- {
- pDrvCtrl->devAdrs = devMemAddr;
- pDrvCtrl->flags |= EL_MODE_MEM_IO_MAP;
- }
- else
- {
- pDrvCtrl->devAdrs = devIoAddr;
- }
- /* PCI memory base address as seen from the CPU */
- tok = strtok_r (NULL, ":", &pHolder);
- if (tok == NULL)
- return ERROR;
- pDrvCtrl->pciMemBase = strtoul (tok, NULL, 16);
- DRV_LOG (DRV_DEBUG_LOAD, "Pci : 0x%X ...n", pDrvCtrl->pciMemBase,
- 2, 3, 4, 5, 6);
- /* Interrupt vector. */
- tok = strtok_r (NULL, ":", &pHolder);
- if (tok == NULL)
- return ERROR;
- pDrvCtrl->ivec = atoi (tok);
- DRV_LOG (DRV_DEBUG_LOAD, "ivec : 0x%X ...n", pDrvCtrl->ivec,
- 2, 3, 4, 5, 6);
- /* Interrupt level. */
- tok = strtok_r (NULL, ":", &pHolder);
- if (tok == NULL)
- return ERROR;
- pDrvCtrl->intLevel = atoi (tok);
- DRV_LOG (DRV_DEBUG_LOAD, "ilevel : 0x%X ...n", pDrvCtrl->intLevel,
- 2, 3, 4, 5, 6);
- /* Caller supplied memory address. */
- tok = strtok_r (NULL, ":", &pHolder);
- if (tok == NULL)
- return ERROR;
- pDrvCtrl->memAdrs = (char *)strtoul (tok, NULL, 16);
- DRV_LOG (DRV_DEBUG_LOAD, "memAdrs : 0x%X ...n", (int)pDrvCtrl->memAdrs,
- 2, 3, 4, 5, 6);
- /* Caller supplied memory size. */
- tok = strtok_r (NULL, ":", &pHolder);
- if (tok == NULL)
- return ERROR;
- pDrvCtrl->memSize = strtoul (tok, NULL, 16);
- DRV_LOG (DRV_DEBUG_LOAD, "memSize : 0x%X ...n", pDrvCtrl->memSize,
- 2, 3, 4, 5, 6);
- /* Caller supplied memory width. */
- tok = strtok_r (NULL, ":", &pHolder);
- if (tok == NULL)
- return ERROR;
- pDrvCtrl->memWidth = atoi (tok);
- DRV_LOG (DRV_DEBUG_LOAD, "memWidth : 0x%X ...n", pDrvCtrl->memWidth,
- 2, 3, 4, 5, 6);
- /* caller supplied flags */
- tok = strtok_r (NULL, ":", &pHolder);
- if (tok == NULL)
- return ERROR;
- pDrvCtrl->flags |= strtoul (tok, NULL, 16);
- DRV_LOG (DRV_DEBUG_LOAD, "flags : 0x%X ...n", pDrvCtrl->flags,
- 2, 3, 4, 5, 6);
- /* buffer multiplier */
- tok = strtok_r (NULL, ":", &pHolder);
- if (tok == NULL)
- return ERROR;
- pDrvCtrl->bufMtplr |= strtoul (tok, NULL, 16);
- DRV_LOG (DRV_DEBUG_LOAD, "bufMultiplier : 0x%X ...n", pDrvCtrl->bufMtplr,
- 2, 3, 4, 5, 6);
- return OK;
- }
- /*******************************************************************************
- *
- * el3c90xStart - start the device
- *
- * This function calls BSP functions to connect interrupts and start the
- * device running in interrupt mode.
- *
- * RETURNS: OK or ERROR
- *
- */
- LOCAL STATUS el3c90xStart
- (
- void * pEnd /* device to be started */
- )
- {
- STATUS result;
- EL3C90X_DEVICE * pDrvCtrl;
- int flags;
- VOID_TO_DRVCTRL (pEnd, pDrvCtrl);
- pDrvCtrl->txBlocked = FALSE;
- /* perform all initialization memory, ring buffer etc */
- el3c90xInit(pDrvCtrl);
- flags = END_FLAGS_GET (&pDrvCtrl->endObj);
- flags |= (IFF_UP | IFF_RUNNING);
- END_FLAGS_SET (&pDrvCtrl->endObj, flags);
- SYS_INT_CONNECT (pDrvCtrl, el3c90xInt, (int)pDrvCtrl, &result);
- if (result == ERROR)
- return ERROR;
- ENDLOGMSG (("Interrupt connected.n", 1, 2, 3, 4, 5, 6));
- SYS_INT_ENABLE (pDrvCtrl);
- ENDLOGMSG (("interrupt enabled.n", 1, 2, 3, 4, 5, 6));
- return (OK);
- }
- /*******************************************************************************
- *
- * el3c90xStop - stop the device
- *
- * This function calls BSP functions to disconnect interrupts and stop
- * the device from operating in interrupt mode.
- *
- * RETURNS: OK or ERROR.
- */
- LOCAL STATUS el3c90xStop
- (
- void * pEnd /* device to be stopped */
- )
- {
- STATUS result = OK;
- EL3C90X_DEVICE * pDrvCtrl;
- VOID_TO_DRVCTRL (pEnd, pDrvCtrl);
- END_FLAGS_CLR (&pDrvCtrl->endObj, IFF_UP | IFF_RUNNING);
- el3c90xDevStop (pDrvCtrl);
- SYS_INT_DISCONNECT (pDrvCtrl, el3c90xInt, (int)pDrvCtrl, &result);
- if (result == ERROR)
- {
- ENDLOGMSG (("Could not diconnect interrupt!n", 1, 2, 3, 4, 5, 6));
- }
- SYS_INT_DISABLE (pDrvCtrl);
- return (result);
- }
- /******************************************************************************
- *
- * el3c90xUnload - unload a driver from the system
- *
- * This function first brings down the device, and then frees any
- * stuff that was allocated by the driver in the load function.
- *
- * RETURNS: OK or ERROR.
- */
- LOCAL STATUS el3c90xUnload
- (
- void * pEnd /* device to be unloaded */
- )
- {
- EL3C90X_DEVICE * pDrvCtrl;
- VOID_TO_DRVCTRL (pEnd, pDrvCtrl);
- END_OBJECT_UNLOAD (&pDrvCtrl->endObj);
- /* Free the shared DMA memory. */
- if (pDrvCtrl->flags & EL_MEM_ALLOC_FLAG)
- {
- /* free the memory allocated for descriptors */
- if (pDrvCtrl->pDescMem != NULL)
- cacheDmaFree (pDrvCtrl->pDescMem);
- /* free the memory allocated for clusters */
- if (pDrvCtrl->clDesc.memArea != NULL)
- cacheDmaFree (pDrvCtrl->clDesc.memArea);
- /* Free the memory allocated for mBlks and clBlks */
- if (pDrvCtrl->mClCfg.memArea != NULL)
- free (pDrvCtrl->mClCfg.memArea);
- }
- if (pDrvCtrl->endObj.pNetPool != NULL)
- free (pDrvCtrl->endObj.pNetPool);
- return (OK);
- }
- /*******************************************************************************
- *
- * el3c90xIoctl - the driver I/O control routine
- *
- * Process an ioctl request.
- *
- * RETURNS: A command specific response, OK or ERROR or EINVAL.
- */
- LOCAL int el3c90xIoctl
- (
- void * pEnd, /* device ptr*/
- int cmd, /* ioctl command code */
- caddr_t data /* command argument */
- )
- {
- int error = 0;
- long value;
- EL3C90X_DEVICE * pDrvCtrl;
- VOID_TO_DRVCTRL (pEnd, pDrvCtrl);
- switch (cmd)
- {
- case EIOCSADDR:
- if (data == NULL)
- return (EINVAL);
- bcopy ((char *)data, (char *)END_HADDR(&pDrvCtrl->endObj),
- END_HADDR_LEN(&pDrvCtrl->endObj));
- break;
- case EIOCGADDR:
- if (data == NULL)
- return (EINVAL);
- bcopy ((char *)END_HADDR(&pDrvCtrl->endObj), (char *)data,
- END_HADDR_LEN(&pDrvCtrl->endObj));
- break;
- case EIOCSFLAGS:
- value = (long)data;
- if (value < 0)
- {
- value = -value;
- value--;
- END_FLAGS_CLR (&pDrvCtrl->endObj, value);
- }
- else
- {
- END_FLAGS_SET (&pDrvCtrl->endObj, value);
- }
- if (END_FLAGS_GET(&pDrvCtrl->endObj) & IFF_UP)
- {
- el3c90xInit (pDrvCtrl);
- }
- else
- {
- if (END_FLAGS_GET(&pDrvCtrl->endObj) & IFF_RUNNING)
- el3c90xDevStop (pDrvCtrl);
- }
- error = 0;
- break;
- case EIOCGFLAGS:
- *(int *)data = END_FLAGS_GET(&pDrvCtrl->endObj);
- break;
- case EIOCPOLLSTART:
- error = el3c90xPollStart(pDrvCtrl);
- break;
- case EIOCPOLLSTOP:
- error = el3c90xPollStop(pDrvCtrl);
- break;
- case EIOCGMIB2:
- if (data == NULL)
- return (EINVAL);
- bcopy((char *)&pDrvCtrl->endObj.mib2Tbl, (char *)data,
- sizeof(pDrvCtrl->endObj.mib2Tbl));
- break;
- case EIOCGFBUF:
- if (data == NULL)
- return (EINVAL);
- *(int *)data = EL_MIN_FBUF;
- break;
- case EIOCGMWIDTH:
- if (data == NULL)
- return (EINVAL);
- break;
- case EIOCGHDRLEN:
- if (data == NULL)
- return (EINVAL);
- *(int *)data = EH_SIZE;
- break;
- #ifndef INCLUDE_RFC_1213
- /* New RFC 2233 mib2 interface */
- case EIOCGMIB2233:
- if ((data == NULL) || (pDrvCtrl->endObj.pMib2Tbl == NULL))
- error = EINVAL;
- else
- *((M2_ID **)data) = pDrvCtrl->endObj.pMib2Tbl;
- break;
- #endif /* INCLUDE_RFC_1213 */
- default:
- error = EINVAL;
- }
- return (error);
- }
- /*******************************************************************************
- *
- * el3c90xSend - the driver send routine
- *
- * This routine takes a M_BLK_ID sends off the data in the M_BLK_ID.
- * The buffer must already have the addressing information properly installed
- * in it. This is done by a higher layer.
- *
- * RETURNS: OK or END_ERR_BLOCK or ERROR.
- */
- LOCAL STATUS el3c90xSend
- (
- void * pEnd, /* device ptr */
- M_BLK_ID pMblk /* data to send */
- )
- {
- EL3C90X_DEVICE * pDrvCtrl;
- EL_DESC_CHAIN * pTxChain = NULL;
- VOID_TO_DRVCTRL (pEnd, pDrvCtrl);
- /* return if in polled mode */
- if (pDrvCtrl->flags & EL_POLLING)
- {
- netMblkClChainFree (pMblk); /* free the given mBlk chain */
- errno = EINVAL;
- return (ERROR);
- }
- DRV_LOG (DRV_DEBUG_TX, "Sendn", 1, 2, 3, 4, 5, 6);
- END_TX_SEM_TAKE (&pDrvCtrl->endObj, WAIT_FOREVER);
- /* get a free download descriptor */
- if ((pTxChain = el3c90xDndGet (pDrvCtrl)) == NULL)
- {
- DRV_LOG (DRV_DEBUG_TX, "Out of TMDs!n", 1, 2, 3, 4, 5, 6);
- pDrvCtrl->txBlocked = TRUE;
- END_TX_SEM_GIVE (&pDrvCtrl->endObj);
- return (END_ERR_BLOCK);
- }
- /* Pack the data into the descriptor. */
- if (el3c90xDndSet(pDrvCtrl, pTxChain, pMblk) == ERROR)
- {
- netMblkClChainFree (pMblk); /* free the given mBlk chain */
- el3c90xDndFree (pDrvCtrl, pTxChain);
- END_TX_SEM_GIVE (&pDrvCtrl->endObj);
- return (ERROR);
- }
- #ifndef INCLUDE_RFC_1213
- /* New RFC 2233 mib2 interface */
- /* RFC 2233 mib2 counter update for outgoing packet */
- if (pDrvCtrl->endObj.pMib2Tbl != NULL)
- {
- pDrvCtrl->endObj.pMib2Tbl->m2PktCountRtn(pDrvCtrl->endObj.pMib2Tbl,
- M2_PACKET_OUT,
- pMblk->mBlkHdr.mData,
- pMblk->mBlkHdr.mLen);
- }
- #endif /* INCLUDE_RFC_1213 */
- /* set the interrupt bit for the downloaded packet */
- pTxChain->pDesc->status |= PCI_SWAP (EL_TXSTAT_DL_INTR);
- el3c90xDndEnqueue (pDrvCtrl, pTxChain);
- END_TX_SEM_GIVE (&pDrvCtrl->endObj);
- /* kick the reciever if blocked, parallel tasking */
- el3c90xRxKick (pDrvCtrl);
- return (OK);
- }
- /*****************************************************************************
- *
- * el3c90xMCastAdd - add a multicast address for the device
- *
- * This routine adds a multicast address to whatever the driver
- * is already listening for. It then resets the address filter.
- *
- * RETURNS: OK or ERROR.
- */
- LOCAL STATUS el3c90xMCastAdd
- (
- void * pEnd, /* device pointer */
- char * pAddress /* new address to add */
- )
- {
- int error;
- EL3C90X_DEVICE * pDrvCtrl;
- VOID_TO_DRVCTRL (pEnd, pDrvCtrl);
- if ((error = etherMultiAdd (&pDrvCtrl->endObj.multiList,
- pAddress)) == ENETRESET)
- el3c90xMcastConfig (pDrvCtrl);
- return (OK);
- }
- /*****************************************************************************
- *
- * el3c90xMCastDel - delete a multicast address for the device
- *
- * This routine removes a multicast address from whatever the driver
- * is listening for. It then resets the address filter.
- *
- * RETURNS: OK or ERROR.
- */
- LOCAL STATUS el3c90xMCastDel
- (
- void * pEnd, /* device pointer */
- char * pAddress /* address to be deleted */
- )
- {
- int error;
- EL3C90X_DEVICE * pDrvCtrl;
- VOID_TO_DRVCTRL (pEnd, pDrvCtrl);
- if ((error = etherMultiDel (&pDrvCtrl->endObj.multiList,
- (char *)pAddress)) == ENETRESET)
- el3c90xMcastConfig (pDrvCtrl);
- return (OK);
- }
- /*****************************************************************************
- *
- * el3c90xMCastGet - get the multicast address list for the device
- *
- * This routine gets the multicast list of whatever the driver
- * is already listening for.
- *
- * RETURNS: OK or ERROR.
- */
- LOCAL STATUS el3c90xMCastGet
- (
- void * pEnd, /* device pointer */
- MULTI_TABLE * pTable /* address table to be filled in */
- )
- {
- EL3C90X_DEVICE * pDrvCtrl;
- VOID_TO_DRVCTRL (pEnd, pDrvCtrl);
- return (etherMultiGet (&pDrvCtrl->endObj.multiList, pTable));
- }
- /*******************************************************************************
- *
- * el3c90xPollSend - routine to send a packet in polled mode.
- *
- * This routine is called by a user to try and send a packet on the
- * device.
- *
- * RETURNS: OK upon success. EAGAIN if device is busy.
- */
- LOCAL STATUS el3c90xPollSend
- (
- void * pEnd, /* device pointer */
- M_BLK_ID pMblk /* packet to send */
- )
- {
- EL3C90X_DEVICE * pDrvCtrl;
- EL_DESC_CHAIN * pTxChain = NULL;
- VOID_TO_DRVCTRL (pEnd, pDrvCtrl);
- DRV_LOG (DRV_DEBUG_POLL_TX, "PTX bn", 1, 2, 3, 4, 5, 6);
- /* check if download engine is still busy */
- if (el3c90xCsrReadLong (pDrvCtrl, EL_DOWNLIST_PTR, NONE))
- {
- DRV_LOG (DRV_DEBUG_POLL_TX, "transmitter busyn", 1, 2, 3, 4, 5, 6);
- return (EAGAIN);
- }
- /* check if a download descriptor is available */
- if ((pTxChain = el3c90xDndGet (pDrvCtrl)) == NULL)
- return (EAGAIN);
- /* Pack the mBlk into the download descriptor. */
- if (el3c90xDndMblkPack (pDrvCtrl, pTxChain, pMblk) == ERROR)
- {
- el3c90xDndFree (pDrvCtrl, pTxChain);
- return (EAGAIN);
- }
- #ifndef INCLUDE_RFC_1213
- /* New RFC 2233 mib2 interface */
- /* RFC 2233 mib2 counter update for outgoing packet */
- if (pDrvCtrl->endObj.pMib2Tbl != NULL)
- {
- pDrvCtrl->endObj.pMib2Tbl->m2PktCountRtn(pDrvCtrl->endObj.pMib2Tbl,
- M2_PACKET_OUT,
- pMblk->mBlkHdr.mData,
- pMblk->mBlkHdr.mLen);
- }
- #endif /* INCLUDE_RFC_1213 */
- el3c90xCsrWriteLong (pDrvCtrl, EL_DOWNLIST_PTR,
- (UINT32)EL3C90X_CACHE_VIRT_TO_PHYS (pTxChain->pDesc),
- NONE);
- /* wait until download has completed */
- while (el3c90xCsrReadLong (pDrvCtrl, EL_DOWNLIST_PTR, NONE))
- ;
- el3c90xDndFree (pDrvCtrl, pTxChain);
- DRV_LOG (DRV_DEBUG_POLL_TX, "PTX en", 1, 2, 3, 4, 5, 6);
- return (OK);
- }
- /*******************************************************************************
- *
- * el3c90xPollRcv - routine to receive a packet in polled mode.
- *
- * This routine is called by a user to try and get a packet from the
- * device.
- *
- * RETURNS: EGAIN or OK
- */
- LOCAL STATUS el3c90xPollRcv
- (
- void * pEnd, /* device pointer */
- M_BLK_ID pMblk /* pointer to the mBlk chain */
- )
- {
- EL_SIMPLE_DESC_CHAIN * pRxUpd;
- EL3C90X_DEVICE * pDrvCtrl;
- M_BLK_ID pMblkTemp; /* pointer to the mBlk */
- int len;
- DRV_LOG (DRV_DEBUG_POLL_RX, "PRX bn", 1, 2, 3, 4, 5, 6);
- VOID_TO_DRVCTRL (pEnd, pDrvCtrl);
- el3c90xRxUnStall (pDrvCtrl);
- /* get the next upload descriptor */
- if ((pRxUpd = el3c90xNextUpdFetch (pDrvCtrl)) == NULL)
- {
- DRV_LOG (DRV_DEBUG_POLL_RX, "PRX no updn", 1, 2, 3, 4, 5, 6);
- return (EAGAIN);
- }
- /* get the mBlk associated with the upd */
- if ((pMblkTemp = el3c90xNextPktFetch (pDrvCtrl, pRxUpd)) == NULL)
- return (EAGAIN);
- /* copy the data into the given buffer */
- len = netMblkToBufCopy (pMblkTemp, pMblk->mBlkHdr.mData, NULL);
- netMblkClChainFree (pMblkTemp);
- if ((pMblk->mBlkHdr.mLen < len) || (!(pMblk->mBlkHdr.mFlags & M_EXT)))
- {
- DRV_LOG (DRV_DEBUG_POLL_RX, "PRX bad mblk len:%d flags:%dn",
- pMblk->mBlkHdr.mLen, pMblk->mBlkHdr.mFlags, 3, 4, 5, 6);
- return (EAGAIN);
- }
- pMblk->mBlkHdr.mLen = len;
- pMblk->mBlkHdr.mFlags |= M_PKTHDR;
- pMblk->mBlkPktHdr.len = len;
- #ifndef INCLUDE_RFC_1213
- /* New RFC 2233 mib2 interface */
- /* RFC 2233 mib2 counter update for incoming packet */
- if (pDrvCtrl->endObj.pMib2Tbl != NULL)
- {
- pDrvCtrl->endObj.pMib2Tbl->m2PktCountRtn(pDrvCtrl->endObj.pMib2Tbl,
- M2_PACKET_IN,
- pMblk->mBlkHdr.mData,
- pMblk->mBlkHdr.mLen);
- }
- #endif /* INCLUDE_RFC_1213 */
- DRV_LOG (DRV_DEBUG_POLL_RX, "PRX okn", 1, 2, 3, 4, 5, 6);
- return (OK);
- }
- /*******************************************************************************
- *
- * el3c90xInit - initialize the device
- *
- * This routine initializes device and enables the device interrupts. It
- * initializes the descriptor rings
- *
- * RETURNS: N/A
- */
- LOCAL void el3c90xInit
- (
- EL3C90X_DEVICE * pDrvCtrl /* pointer to the device control structure */
- )
- {
- int ix;
- UINT16 rxFilt = 0;
- UINT16 phyBMCR = 0;
- int flags;
- /*
- * hack for the 3c905B: the built-in autoneg logic's state
- * gets reset by el3c90xInit() when we don't want it to. Try
- * to preserve it. (For 3c905 cards with real external PHYs,
- * the BMCR register doesn't change, but this doesn't hurt.)
- */
- if (pDrvCtrl->pPhyDevType != NULL)
- phyBMCR = el3c90xPhyRegRead(pDrvCtrl, PHY_BMCR);
- /* cancel pending I/O and free all RX/TX buffers. */
- el3c90xDevStop(pDrvCtrl);
- el3c90xWait(pDrvCtrl);
- /* get the MAC address */
- for (ix = 0; ix < EA_SIZE; ix++)
- {
- el3c90xCsrWriteByte (pDrvCtrl, EL_W2_STATION_ADDR_LO + ix,
- pDrvCtrl->enetAddr [ix], EL_WIN_2);
- }
- /* clear the station mask */
- for (ix = 0; ix < 3; ix++)
- el3c90xCsrWriteWord (pDrvCtrl, EL_W2_STATION_MASK_LO + (ix * 2), 0,
- EL_WIN_2);
- /* reset TX and RX */
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_RX_RESET, NONE);
- el3c90xWait(pDrvCtrl);
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_TX_RESET, NONE);
- el3c90xWait(pDrvCtrl);
- /* init circular upload descriptor list */
- if (el3c90xUpdInit(pDrvCtrl) == ENOBUFS)
- {
- DRV_LOG (DRV_DEBUG_LOAD, "elPci%d: initialization failed: no "
- "memory for rx buffersn", pDrvCtrl->unit, 2, 3, 4, 5, 6);
- el3c90xDevStop(pDrvCtrl);
- return;
- }
- /* init download descriptors list */
- el3c90xDndInit(pDrvCtrl);
- /*
- * set the TX freethresh value.
- * note that this has no effect on 3c905B "cyclone"
- * cards but is required for 3c900/3c905 "boomerang"
- * cards in order to enable the download engine.
- */
- el3c90xCsrWriteByte (pDrvCtrl, EL_TX_FREETHRESH, (EL3C90X_BUFSIZ >> 8),
- NONE);
- /*
- * If this is a 3c905B, also set the tx reclaim threshold.
- * This helps cut down on the number of tx reclaim errors
- * that could happen on a busy network. The chip multiplies
- * the register value by 16 to obtain the actual threshold
- * in bytes, so we divide by 16 when setting the value here.
- * The existing threshold value can be examined by reading
- * the register at offset 9 in window 5.
- */
- if (pDrvCtrl->devType == EL_TYPE_905B)
- {
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND,
- (EL_CMD_SET_TX_RECLAIM | (EL3C90X_BUFSIZ >> 4)),
- NONE);
- }
- /* set RX filter bits. */
- rxFilt = el3c90xCsrReadByte (pDrvCtrl, EL_W5_RX_FILTER, EL_WIN_5);
- /* set the individual bit to receive frames for this host only. */
- rxFilt |= EL_RXFILTER_INDIVIDUAL;
- flags = END_FLAGS_GET (&pDrvCtrl->endObj);
- /* if we want promiscuous mode, set the allframes bit. */
- if (flags & IFF_PROMISC)
- {
- rxFilt |= EL_RXFILTER_ALLFRAMES;
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND,
- (EL_CMD_RX_SET_FILT | rxFilt), NONE);
- }
- else
- {
- rxFilt &= ~EL_RXFILTER_ALLFRAMES;
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND,
- (EL_CMD_RX_SET_FILT | rxFilt), NONE);
- }
- /* set capture broadcast bit to capture broadcast frames. */
- if (flags & IFF_BROADCAST)
- {
- rxFilt |= EL_RXFILTER_BROADCAST;
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND,
- (EL_CMD_RX_SET_FILT | rxFilt), NONE);
- }
- else
- {
- rxFilt &= ~EL_RXFILTER_BROADCAST;
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND,
- (EL_CMD_RX_SET_FILT | rxFilt), NONE);
- }
- /* set the multicast filter etc */
- el3c90xMcastConfig (pDrvCtrl);
- /*
- * load the upload descriptor pointer and start the upload engine
- * Note that we have to do this after any RX resets have completed
- * since the uplist register is cleared by a reset.
- */
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_UP_STALL, NONE);
- el3c90xWait(pDrvCtrl);
- el3c90xCsrWriteLong (pDrvCtrl, EL_UPLIST_PTR,
- (UINT32) EL3C90X_CACHE_VIRT_TO_PHYS
- (&pDrvCtrl->pDescBlk->rxDescs[0]), NONE);
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_UP_UNSTALL, NONE);
- /*
- * if the coax transceiver is on, make sure to enable the DC-DC converter.
- */
- if (pDrvCtrl->xCvr == EL_XCVR_COAX)
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_COAX_START, NONE);
- else
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_COAX_STOP, NONE);
- /* Clear out the stats counters. */
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_STATS_DISABLE, NONE);
- el3c90xStatUpdate(pDrvCtrl);
- el3c90xCsrWriteWord (pDrvCtrl, EL_W4_NET_DIAG,
- EL_NETDIAG_UPPER_BYTES_ENABLE, EL_WIN_4);
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_STATS_ENABLE, NONE);
- /* enable device interrupts */
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_INTR_ACK|0xFF, NONE);
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_STAT_ENB|EL_INTRS, NONE);
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_INTR_ENB|EL_INTRS, NONE);
- /* Set the RX early threshold */
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND,
- (EL_CMD_RX_SET_THRESH | (EL3C90X_BUFSIZ >>2)), NONE);
- el3c90xCsrWriteWord (pDrvCtrl, EL_DMACTL, EL_DMACTL_UP_RX_EARLY, NONE);
- /* Enable receiver and transmitter. */
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_RX_ENABLE, NONE);
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_TX_ENABLE, NONE);
- /* Restore state of BMCR */
- if (pDrvCtrl->pPhyDevType != NULL)
- el3c90xPhyRegWrite(pDrvCtrl, PHY_BMCR, phyBMCR);
- return;
- }
- /*******************************************************************************
- *
- * el3c90xMemInit - initialize memory for the device
- *
- * This function initiailizes memory for the device
- *
- * RETURNS: OK or ERROR
- *
- */
- LOCAL STATUS el3c90xMemInit
- (
- EL3C90X_DEVICE * pDrvCtrl /* device to be initialized */
- )
- {
- int memSize = 0;
- memSize += (sizeof(EL_DESC_BLK) + 16);
- if (pDrvCtrl->bufMtplr == NONE)
- pDrvCtrl->bufMtplr = 2;
- else if (pDrvCtrl->bufMtplr <= 0)
- printf ( "elPci: invalid buffer multipliern");
- pDrvCtrl->clDesc.clNum = (EL_UPD_CNT + EL_DND_CNT) * pDrvCtrl->bufMtplr;
- pDrvCtrl->mClCfg.clBlkNum = pDrvCtrl->clDesc.clNum;
- pDrvCtrl->mClCfg.mBlkNum = pDrvCtrl->mClCfg.clBlkNum * 2;
- /* total memory size for mBlks and clBlks */
- pDrvCtrl->mClCfg.memSize =
- (pDrvCtrl->mClCfg.mBlkNum * (MSIZE + sizeof (long))) +
- (pDrvCtrl->mClCfg.clBlkNum * (CL_BLK_SZ + sizeof (long)));
- memSize += pDrvCtrl->mClCfg.memSize;
- /* total memory size for all clusters */
- pDrvCtrl->clDesc.clSize = EL3C90X_BUFSIZ;
- pDrvCtrl->clDesc.memSize =
- (pDrvCtrl->clDesc.clNum * (pDrvCtrl->clDesc.clSize + 8)) + sizeof(int);
- memSize += pDrvCtrl->clDesc.memSize;
- if ((int)pDrvCtrl->memAdrs != NONE)
- {
- /* check if the give memory size if enough */
- if (pDrvCtrl->memSize < memSize)
- {
- printf ( "elPci: memory size too smalln" );
- return (ERROR);
- }
- pDrvCtrl->pDescMem = (char *)pDrvCtrl->memAdrs;
- pDrvCtrl->mClCfg.memArea = (char *)((UINT32)(pDrvCtrl->pDescMem) +
- sizeof(EL_DESC_BLK) + 16);
- pDrvCtrl->clDesc.memArea = (pDrvCtrl->mClCfg.memArea +
- pDrvCtrl->mClCfg.memSize);
- /* assume pool is cache coherent, copy null structure */
- pDrvCtrl->cacheFuncs = cacheNullFuncs;
- DRV_LOG (DRV_DEBUG_LOAD, "Memory checks outn", 1, 2, 3, 4, 5, 6);
- }
- else /* allocate our own memory */
- {
- pDrvCtrl->flags |= EL_MEM_ALLOC_FLAG;
- if (!CACHE_DMA_IS_WRITE_COHERENT ())
- {
- printf ( "elPci: device requires cache coherent memoryn" );
- return (ERROR);
- }
- /* allocate memory for upload and download descriptors */
- pDrvCtrl->pDescMem =
- (char *) cacheDmaMalloc (sizeof(EL_DESC_BLK) + 16);
- if (pDrvCtrl->pDescMem == NULL)
- {
- printf ( "elPci: system memory unavailablen" );
- return (ERROR);
- }
- /* allocate memory for mBlks and clBlks */
- if ((pDrvCtrl->mClCfg.memArea =
- (char *) memalign (sizeof(long), pDrvCtrl->mClCfg.memSize))
- == NULL)
- {
- printf ( "elPci: system memory unavailablen" );
- goto elMemInitFail;
- }
- /* allocate memory for clusters */
- pDrvCtrl->clDesc.memArea = cacheDmaMalloc (pDrvCtrl->clDesc.memSize);
- if (pDrvCtrl->clDesc.memArea == NULL)
- {
- printf ( "elPci: system memory unavailablen" );
- goto elMemInitFail;
- }
- /* copy the DMA structure */
- pDrvCtrl->cacheFuncs = cacheDmaFuncs;
- }
- pDrvCtrl->pDescBlk = (EL_DESC_BLK *)(((int)pDrvCtrl->pDescMem
- + 0x0f) & ~0x0f);
- bzero ((char*)pDrvCtrl->pDescBlk, sizeof(EL_DESC_BLK));
- /* allocate memory for net pool */
- if ((pDrvCtrl->endObj.pNetPool = malloc (sizeof(NET_POOL))) == NULL)
- {
- printf ( "elPci: system memory unavailablen" );
- goto elMemInitFail;
- }
- #ifdef DRV_DEBUG
- pElXlPool = pDrvCtrl->endObj.pNetPool;
- #endif
- /* initialize the device net pool */
- if (netPoolInit (pDrvCtrl->endObj.pNetPool, &pDrvCtrl->mClCfg,
- &pDrvCtrl->clDesc, 1, NULL) == ERROR)
- {
- DRV_LOG (DRV_DEBUG_LOAD, "Could not init bufferingn",
- 1, 2, 3, 4, 5, 6);
- goto elMemInitFail;
- }
- /* Store the cluster pool id as others need it later. */
- pDrvCtrl->pClPoolId = clPoolIdGet (pDrvCtrl->endObj.pNetPool,
- EL3C90X_BUFSIZ, FALSE);
- return (OK);
- elMemInitFail:
- {
- if (pDrvCtrl->flags & EL_MEM_ALLOC_FLAG)
- {
- /* free the memory allocated for descriptors */
- if (pDrvCtrl->pDescMem != NULL)
- cacheDmaFree (pDrvCtrl->pDescMem);
- /* Free the memory allocated for mBlks and clBlks */
- if (pDrvCtrl->mClCfg.memArea != NULL)
- free (pDrvCtrl->mClCfg.memArea);
- /* free the memory allocated for clusters */
- if (pDrvCtrl->clDesc.memArea != NULL)
- cacheDmaFree (pDrvCtrl->clDesc.memArea);
- }
- if (pDrvCtrl->endObj.pNetPool != NULL)
- free (pDrvCtrl->endObj.pNetPool);
- return (ERROR);
- }
- }
- /*******************************************************************************
- *
- * el3c90xDevStop - stop the device
- *
- * This function stops the adapter and frees up any M_BLKS allocated to the
- * upload and download descriptors.
- *
- * RETURNS: N/A
- */
- LOCAL void el3c90xDevStop
- (
- EL3C90X_DEVICE * pDrvCtrl /* pointer to the device control structure */
- )
- {
- register int ix;
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_RX_DISABLE, NONE);
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_STATS_DISABLE, NONE);
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_INTR_ENB, NONE);
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_RX_DISCARD, NONE);
- el3c90xWait(pDrvCtrl);
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_TX_DISABLE, NONE);
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_COAX_STOP, NONE);
- el3c90xWait(pDrvCtrl);
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_RX_RESET, NONE);
- el3c90xWait(pDrvCtrl);
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_TX_RESET, NONE);
- el3c90xWait(pDrvCtrl);
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND,
- (EL_CMD_INTR_ACK | EL_STAT_INTLATCH), NONE);
- /* free the mblks in the upload descriptor lists */
- for (ix = 0; ix < EL_UPD_CNT; ix++)
- {
- if (pDrvCtrl->rxTxChain.rxChain [ix].pMblk != NULL)
- {
- netMblkClChainFree(pDrvCtrl->rxTxChain.rxChain [ix].pMblk);
- pDrvCtrl->rxTxChain.rxChain [ix].pMblk = NULL;
- }
- }
- bzero ((char *)&pDrvCtrl->pDescBlk->rxDescs,
- sizeof(pDrvCtrl->pDescBlk->rxDescs));
- /* free the download descriptors */
- for (ix = 0; ix < EL_DND_CNT; ix++)
- {
- if (pDrvCtrl->rxTxChain.txChain [ix].pMblk != NULL)
- {
- netMblkClChainFree(pDrvCtrl->rxTxChain.txChain[ix].pMblk);
- pDrvCtrl->rxTxChain.txChain [ix].pMblk = NULL;
- }
- }
- bzero ((char *)&pDrvCtrl->pDescBlk->txDescs,
- sizeof(pDrvCtrl->pDescBlk->txDescs));
- return;
- }
- /*******************************************************************************
- *
- * el3c90xReset - reset the device
- *
- * This function call resets the device completely
- *
- * RETURNS: N/A
- */
- LOCAL void el3c90xReset
- (
- EL3C90X_DEVICE * pDrvCtrl
- )
- {
- /* issue the reset command */
- el3c90xCsrWriteWord(pDrvCtrl, EL_COMMAND, EL_CMD_RESET, EL_WIN_0);
- el3c90xWait(pDrvCtrl); /* wait for the command to complete */
- /* wait for a while */
- SYS_DELAY(1000);
- return;
- }
- /*******************************************************************************
- *
- * el3c90xIntEnable - enable board to cause interrupts
- *
- * Because the board has maskable status, this routine can simply set the
- * mask to all ones. We set all the bits symbolically; the effect is the
- * same. Note that the interrupt latch is not maskable; if none of the other
- * mask bits are set, no interrupts will occur at all. Only those interrupts
- * whose status bits are enabled will actually occur. Note that the "intMask"
- * field in the device control structure is really the status mask.
- *
- * RETURNS: N/A.
- */
- LOCAL void el3c90xIntEnable
- (
- EL3C90X_DEVICE * pDrvCtrl /* device structure */
- )
- {
- UINT16 status;
- status = el3c90xCsrReadWord (pDrvCtrl, EL_STATUS, NONE);
- status &= 0x00ff;
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, (EL_CMD_INTR_ACK | status),
- NONE);
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, (EL_CMD_INTR_ENB | EL_INTRS),
- NONE);
- }
- /*******************************************************************************
- *
- * el3c90xIntDisable - prevent board from causing interrupts
- *
- * This routine simply sets all the interrupt mask bits to zero.
- * It is intended for guarding board-critical sections.
- *
- * RETURNS: N/A.
- */
- LOCAL void el3c90xIntDisable
- (
- EL3C90X_DEVICE * pDrvCtrl /* device structure */
- )
- {
- UINT16 status;
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_INTR_ENB, NONE);
- status = el3c90xCsrReadWord (pDrvCtrl, EL_STATUS, NONE);
- status &= 0x00ff;
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, (EL_CMD_INTR_ACK | status),
- NONE);
- }
- /*******************************************************************************
- *
- * el3c90xPollStart - start polled mode operations
- *
- * This function starts polled mode operation.
- *
- * The device interrupts are disabled, the current mode flag is switched
- * to indicate Polled mode and the device is reconfigured.
- *
- * RETURNS: OK or ERROR.
- */
- LOCAL STATUS el3c90xPollStart
- (
- EL3C90X_DEVICE * pDrvCtrl /* device to be polled */
- )
- {
- int oldLevel;
- oldLevel = intLock (); /* disable ints during update */
- pDrvCtrl->flags |= EL_POLLING;
- intUnlock (oldLevel); /* now el3c90xInt won't get confused */
- el3c90xIntDisable (pDrvCtrl);
- ENDLOGMSG (("STARTEDn", 1, 2, 3, 4, 5, 6));
- return (OK);
- }
- /*******************************************************************************
- *
- * el3c90xPollStop - stop polled mode operations
- *
- * This function terminates polled mode operation. The device returns to
- * interrupt mode.
- *
- * The device interrupts are enabled, the current mode flag is switched
- * to indicate interrupt mode and the device is then reconfigured for
- * interrupt operation.
- *
- * RETURNS: OK or ERROR.
- */
- LOCAL STATUS el3c90xPollStop
- (
- EL3C90X_DEVICE * pDrvCtrl /* device structure */
- )
- {
- int oldLevel;
- oldLevel = intLock (); /* disable ints during register updates */
- pDrvCtrl->flags &= ~EL_POLLING;
- intUnlock (oldLevel);
- el3c90xIntEnable (pDrvCtrl);
- ENDLOGMSG (("STOPPEDn", 1, 2, 3, 4, 5, 6));
- return (OK);
- }
- /*******************************************************************************
- *
- * el3c90xUpdInit - initialize the upload descriptor list
- *
- * This function initializes the upload descriptors and allocates M_BLKs for
- * them. Note that we arrange the descriptors in a closed ring, so that the
- * last descriptor points back to the first.
- *
- * RETURNS: OK or ENOBUFS
- */
- LOCAL int el3c90xUpdInit
- (
- EL3C90X_DEVICE * pDrvCtrl /* pointer to the device control structure */
- )
- {
- EL_RX_TX_CHAIN * pRxTxChain;
- EL_DESC_BLK * pDescBlk;
- int ix;
- pRxTxChain = &pDrvCtrl->rxTxChain;
- pDescBlk = pDrvCtrl->pDescBlk;
- for (ix = 0; ix < EL_UPD_CNT; ix++)
- {
- pRxTxChain->rxChain [ix].pDesc =
- (EL_SIMPLE_DESC *)&pDescBlk->rxDescs [ix];
- if (el3c90xUpdFill(pDrvCtrl, &pRxTxChain->rxChain [ix]) == ENOBUFS)
- return(ENOBUFS);
- if (ix == (EL_UPD_CNT - 1))
- {
- pRxTxChain->rxChain [ix].pNextChain = &pRxTxChain->rxChain [0];
- pDescBlk->rxDescs [ix].nextDesc =
- PCI_SWAP
- (
- (UINT32)EL3C90X_CACHE_VIRT_TO_PHYS (&pDescBlk->rxDescs [0])
- );
- }
- else
- {
- pRxTxChain->rxChain [ix].pNextChain =
- &pRxTxChain->rxChain [ix + 1];
- pDescBlk->rxDescs [ix].nextDesc =
- PCI_SWAP((UINT32)EL3C90X_CACHE_VIRT_TO_PHYS
- (&pDescBlk->rxDescs [ix + 1]));
- }
- }
- pRxTxChain->pRxHead = &pRxTxChain->rxChain [0];
- return (OK);
- }
- /*******************************************************************************
- *
- * el3c90xDndInit - initialize the download descriptor list
- *
- * This function initializes the download descriptor list
- *
- * RETURNS: OK
- */
- LOCAL int el3c90xDndInit
- (
- EL3C90X_DEVICE * pDrvCtrl /* pointer to the device control structure */
- )
- {
- EL_RX_TX_CHAIN * pRxTxChain;
- EL_DESC_BLK * pDescBlk;
- int ix;
- pRxTxChain = &pDrvCtrl->rxTxChain;
- pDescBlk = pDrvCtrl->pDescBlk;
- for (ix = 0; ix < EL_DND_CNT; ix++)
- {
- pRxTxChain->txChain [ix].pDesc = &pDescBlk->txDescs [ix];
- if (ix == (EL_DND_CNT - 1))
- pRxTxChain->txChain [ix].pNextChain = NULL;
- else
- pRxTxChain->txChain[ix].pNextChain = &pRxTxChain->txChain [ix + 1];
- }
- pRxTxChain->pTxFree = &pRxTxChain->txChain [0];
- pRxTxChain->pTxTail = pRxTxChain->pTxHead = NULL;
- return(0);
- }
- /*******************************************************************************
- *
- * el3c90xHashGet - get a hash filter bit position
- *
- * This routine is taken from the 3Com Etherlink XL manual,
- * chapter 10 pg 156. It calculates a CRC of the supplied multicast
- * group address and returns the lower 8 bits, which are used
- * as the multicast filter position.
- * Note: the 3c905B currently only supports a 64-bit hash table,
- * which means we really only need 6 bits, but the manual indicates
- * that future chip revisions will have a 256-bit hash table,
- * hence the routine is set up to calculate 8 bits of position
- * info in case we need it some day.
- * Note II, The Sequel: _CURRENT_ versions of the 3c905B have a
- * 256 bit hash table. This means we have to use all 8 bits regardless.
- * On older cards, the upper 2 bits will be ignored. Grrrr....
- *
- * RETURNS: filter bit position
- */
- LOCAL UINT8 el3c90xHashGet
- (
- char * addr
- )
- {
- UINT32 crc;
- UINT32 carry;
- int ix;
- int jx;
- UINT8 ch;
- /* Compute CRC for the address value. */
- crc = 0xFFFFFFFF; /* initial value */
- for (ix = 0; ix < 6; ix++)
- {
- ch = *(addr + ix);
- for (jx = 0; jx < 8; jx++)
- {
- carry = ((crc & 0x80000000) ? 1 : 0) ^ (ch & 0x01);
- crc <<= 1;
- ch >>= 1;
- if (carry)
- crc = (crc ^ 0x04c11db6) | carry;
- }
- }
- /* return the filter bit position */
- return (crc & 0x000000FF);
- }
- /*******************************************************************************
- *
- * el3c90xFilterSet - set the multicast filter
- *
- * NICs older than the 3c905B have only one multicast option, which
- * is to enable reception of all multicast frames.
- *
- * RETURNS: N/A
- */
- LOCAL void el3c90xFilterSet
- (
- EL3C90X_DEVICE * pDrvCtrl /* device to be re-configured */
- )
- {
- UINT8 rxFilt;
- rxFilt = el3c90xCsrReadByte(pDrvCtrl, EL_W5_RX_FILTER, EL_WIN_5);
- if (END_FLAGS_GET (&pDrvCtrl->endObj) & IFF_ALLMULTI)
- {
- rxFilt |= EL_RXFILTER_ALLMULTI;
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND,
- (EL_CMD_RX_SET_FILT | rxFilt), NONE);
- return;
- }
- /* Set up address filter for multicasting.
- * Multicast bit is set if the address list has one or more entries
- * Multicasting is disabled if the address list is empty
- */
- if (END_MULTI_LST_CNT (&pDrvCtrl->endObj) > 0)
- {
- ENDLOGMSG (("Setting multicast mode on!n", 1, 2, 3, 4, 5, 6));
- rxFilt |= EL_RXFILTER_ALLMULTI;
- }
- else
- {
- ENDLOGMSG (("Setting multcast mode off!n", 1, 2, 3, 4, 5, 6));
- rxFilt &= ~EL_RXFILTER_ALLMULTI;
- }
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND,
- (EL_CMD_RX_SET_FILT | rxFilt), NONE);
- return;
- }
- /*******************************************************************************
- *
- * el3c90xHashFilterSet - set the hash filter for 3c90xB adapters.
- *
- * This function programs the hash fileter for the 3c905B adapters.
- *
- * RETURNS: N/A
- */
- LOCAL void el3c90xHashFilterSet
- (
- EL3C90X_DEVICE * pDrvCtrl /* device to be re-configured */
- )
- {
- ETHER_MULTI * pCurr;
- UINT8 rxFilt;
- int ix;
- int hash = 0;
- int mcnt = 0;
- rxFilt = el3c90xCsrReadByte(pDrvCtrl, EL_W5_RX_FILTER, EL_WIN_5);
- if (END_FLAGS_GET (&pDrvCtrl->endObj) & IFF_ALLMULTI)
- {
- rxFilt |= EL_RXFILTER_ALLMULTI;
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND,
- (EL_CMD_RX_SET_FILT | rxFilt), NONE);
- return;
- }
- else
- rxFilt &= ~EL_RXFILTER_ALLMULTI;
- /* first, zot all the existing hash bits */
- for (ix = 0; ix < EL_HASHFILT_SIZE; ix++)
- el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, (EL_CMD_RX_SET_HASH | ix),
- NONE);