el3c90xEnd.c
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:136k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* el3c90xEnd.c - END  network interface driver for 3COM 3C90xB XL */
  2. /* Copyright 1984 - 2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01o,22jan02,rcs  facilitated common source base with either RFC 1213 or
  8.                  RFC 2233 depending on INCLUDE_RFC_1213 macro.
  9. 01n,28aug01,ann  adding the code that copies the pMib2Tbl contents into
  10.                  mib2Tbl for backward compatibility - SPR 69697 & 69758
  11. 01m,16aug01,ann  fix for SPR 69673 : we now set the RFC2233 flag in the
  12.                  END_OBJ_READY macro call.
  13. 01l,13jul01,ann  eliminating the mibStyle variable and accomodated the
  14.                  END_MIB_2233 flag in the END flags field
  15. 01k,29mar01,spm  merged changes from version 01e of tor2_0.open_stack
  16.                  branch (wpwr VOB, base 01b) for unified code base
  17. 01j,10nov00,mks  passing in correct type of pointer in strtok_r.
  18.                  (SPR 35435 & 62224).
  19. 01i,20sep00,dat  SPR 32058, allow for alternate intConnect rtn
  20. 01h,28aug00,stv  corrected the handling of EIOCSFLAGS ioctl (SPR# 29423).
  21. 01g,08aug00,stv  IFF_UP flag set in the el3c90xStart routine (SPR# 32893,32344,
  22.  32118).
  23. 01f,02aug00,stv  removed netMblkClChainFree() in Pollsend routine (SPR# 32885).
  24. 01e,11jun00,ham  removed reference to etherLib.
  25. 01d,27jan00,dat  fixed use of NULL
  26. 01c,01dec99,stv  freed mBlk chain before returning ERROR (SPR #28492).
  27. 01b,11jan99,mtl  big endian fix to eprm read rtn.
  28. 01a,11jan99,mtl  written by teamF1 Inc.
  29. */
  30. /*
  31. DESCRIPTION  
  32. This module implements the device driver for the 3COM EtherLink Xl and
  33. Fast EtherLink XL PCI network interface cards.
  34. The 3c90x PCI ethernet controller is inherently little endian because
  35. the chip is designed to operate on a PCI bus which is a little endian
  36. bus. The software interface to the driver is divided into three parts.
  37. The first part is the PCI configuration registers and their set up. 
  38. This part is done at the BSP level in the various BSPs which use this
  39. driver. The second and third part are dealt in the driver. The second
  40. part of the interface comprises of the I/O control registers and their
  41. programming. The third part of the interface comprises of the descriptors
  42. and the buffers. 
  43. This driver is designed to be moderately generic, operating unmodified
  44. across the range of architectures and targets supported by VxWorks.  To
  45. achieve this, the driver must be given several target-specific parameters,
  46. and some external support routines must be provided. These target-specific
  47. values and the external support routines are described below.
  48. This driver supports multiple units per CPU.  The driver can be
  49. configured to support big-endian or little-endian architectures.  It
  50. contains error recovery code to handle known device errata related to DMA
  51. activity. 
  52. Big endian processors can be connected to the PCI bus through some controllers
  53. which take care of hardware byte swapping. In such cases all the registers 
  54. which the chip DMA s to have to be swapped and written to, so that when the
  55. hardware swaps the accesses, the chip would see them correctly. The chip still
  56. has to be programmed to operated in little endian mode as it is on the PCI bus.
  57. If the cpu board hardware automatically swaps all the accesses to and from the
  58. PCI bus, then input and output byte stream need not be swapped.
  59. The 3c90x series chips use a bus-master DMA interface for transfering
  60. packets to and from the controller chip. Some of the old 3c59x cards
  61. also supported a bus master mode, however for those chips
  62. you could only DMA packets to and from a contiguous memory buffer. For
  63. transmission this would mean copying the contents of the queued M_BLK
  64. chain into a an M_BLK cluster and then DMAing the cluster. This extra
  65. copy would sort of defeat the purpose of the bus master support for
  66. any packet that doesn't fit into a single M_BLK. By contrast, the 3c90x cards
  67. support a fragment-based bus master mode where M_BLK chains can be
  68. encapsulated using TX descriptors. This is also called the gather technique,
  69. where the fragments in an mBlk chain are directly incorporated into the
  70. download transmit descriptor. This avoids any copying of data from the
  71. mBlk chain. 
  72. NETWORK CARDS SUPPORTED:
  73. - 3Com 3c900-TPO 10Mbps/RJ-45
  74. - 3Com 3c900-COMBO 10Mbps/RJ-45,AUI,BNC
  75.         - 3Com 3c905-TX 10/100Mbps/RJ-45
  76.         - 3Com 3c905-T4 10/100Mbps/RJ-45
  77.         - 3Com 3c900B-TPO 10Mbps/RJ-45
  78.         - 3Com 3c900B-COMBO 10Mbps/RJ-45,AUI,BNC
  79.         - 3Com 3c905B-TX 10/100Mbps/RJ-45
  80.         - 3Com 3c905B-FL/FX 10/100Mbps/Fiber-optic
  81.         - 3Com 3c980-TX 10/100Mbps server adapter
  82.         - Dell Optiplex GX1 on-board 3c918 10/100Mbps/RJ-45
  83.         
  84. BOARD LAYOUT
  85. This device is on-board.  No jumpering diagram is necessary.
  86. EXTERNAL INTERFACE
  87. The only external interface is the el3c90xEndLoad() routine, which expects
  88. the <initString> parameter as input.  This parameter passes in a 
  89. colon-delimited string of the format:
  90. <unit>:<devMemAddr>:<devIoAddr>:<pciMemBase:<vecNum>:<intLvl>:<memAdrs>:
  91. <memSize>:<memWidth>:<flags>:<buffMultiplier>
  92. The el3c90xEndLoad() function uses strtok() to parse the string.
  93. TARGET-SPECIFIC PARAMETERS
  94. .IP <unit>
  95. A convenient holdover from the former model.  This parameter is used only
  96. in the string name for the driver.
  97. .IP <devMemAddr>
  98. This parameter in the memory base address of the device registers in the
  99. memory map of the CPU. It indicates to the driver where to find the
  100. register set. < This parameter should be equal to NONE if the device
  101. does not support memory mapped registers.
  102. .IP <devIoAddr>
  103. This parameter in the IO base address of the device registers in the
  104. IO map of some CPUs. It indicates to the driver where to find the RDP
  105. register. If both <devIoAddr> and <devMemAddr> are given then the device
  106. chooses <devMemAddr> which is a memory mapped register base address.
  107. This parameter should be equal to NONE if the device does not support 
  108. IO mapped registers.
  109. . <pciMemBase>
  110. This parameter is the base address of the CPU memory as seen from the
  111. PCI bus. This parameter is zero for most intel architectures.
  112. .IP <vecNum>
  113. This parameter is the vector associated with the device interrupt.
  114. This driver configures the LANCE device to generate hardware interrupts
  115. for various events within the device; thus it contains
  116. an interrupt handler routine.  The driver calls intConnect() to connect 
  117. its interrupt handler to the interrupt vector generated as a result of 
  118. the LANCE interrupt. The BSP can use a different routine for interrupt
  119. connection by changing the point el3c90xIntConnectRtn to point to a
  120. different routine.
  121. .IP <intLvl>
  122. Some targets use additional interrupt controller devices to help organize
  123. and service the various interrupt sources.  This driver avoids all
  124. board-specific knowledge of such devices.  During the driver's
  125. initialization, the external routine sysEl3c90xIntEnable() is called to
  126. perform any board-specific operations required to allow the servicing of a
  127. NIC interrupt.  For a description of sysEl3c90xIntEnable(), see "External
  128. Support Requirements" below.
  129. .IP <memAdrs>
  130. This parameter gives the driver the memory address to carve out its
  131. buffers and data structures. If this parameter is specified to be
  132. NONE then the driver allocates cache coherent memory for buffers
  133. and descriptors from the system pool.
  134. The 3C90x NIC is a DMA type of device and typically shares access to
  135. some region of memory with the CPU.  This driver is designed for systems
  136. that directly share memory between the CPU and the NIC.  It
  137. assumes that this shared memory is directly available to it
  138. without any arbitration or timing concerns.
  139. .IP <memSize>
  140. This parameter can be used to explicitly limit the amount of shared
  141. memory (bytes) this driver will use.  The constant NONE can be used to
  142. indicate no specific size limitation.  This parameter is used only if
  143. a specific memory region is provided to the driver.
  144. .IP <memWidth>
  145. Some target hardware that restricts the shared memory region to a
  146. specific location also restricts the access width to this region by
  147. the CPU.  On these targets, performing an access of an invalid width
  148. will cause a bus error.
  149. This parameter can be used to specify the number of bytes of access
  150. width to be used by the driver during access to the shared memory.
  151. The constant NONE can be used to indicate no restrictions.
  152. Current internal support for this mechanism is not robust; implementation 
  153. may not work on all targets requiring these restrictions.
  154. .IP <flags>
  155. This is parameter is used for future use, currently its value should be
  156. zero.
  157. .IP <buffMultiplier>
  158. This parameter is used increase the number of buffers allocated in the
  159. driver pool. If this parameter is -1 then a default multiplier of 2 is
  160. choosen. With a multiplier of 2 the total number of clusters allocated
  161. is 64 which is twice the cumulative number of upload and download descriptors.
  162. The device has 16 upload and 16 download descriptors. For example on choosing
  163. the buffer multiplier of 3, the total number of clusters allocated will be
  164. 96 ((16 + 16)*3). There are as many clBlks as the number of clusters.
  165. The number of mBlks allocated are twice the number of clBlks.
  166. By default there are 64 clusters, 64 clBlks and 128 mBlks allocated in the
  167. pool for the device. Depending on the load of the system increase the
  168. number of clusters allocated by incrementing the buffer multiplier.
  169. EXTERNAL SUPPORT REQUIREMENTS
  170. This driver requires several external support functions, defined as macros:
  171. .CS
  172.     SYS_INT_CONNECT(pDrvCtrl, routine, arg)
  173.     SYS_INT_DISCONNECT (pDrvCtrl, routine, arg)
  174.     SYS_INT_ENABLE(pDrvCtrl)
  175.     SYS_INT_DISABLE(pDrvCtrl)
  176.     SYS_OUT_BYTE(pDrvCtrl, reg, data)
  177.     SYS_IN_BYTE(pDrvCtrl, reg, data)
  178.     SYS_OUT_WORD(pDrvCtrl, reg, data)
  179.     SYS_IN_WORD(pDrvCtrl, reg, data)
  180.     SYS_OUT_LONG(pDrvCtrl, reg, data)
  181.     SYS_IN_LONG(pDrvCtrl, reg, data)
  182.     SYS_DELAY (delay)
  183.     sysEl3c90xIntEnable(pDrvCtrl->intLevel) 
  184.     sysEl3c90xIntDisable(pDrvCtrl->intLevel)
  185.     sysDelay (delay)
  186. .CE
  187. There are default values in the source code for these macros.  They presume
  188. memory mapped accesses to the device registers and the normal intConnect(),
  189. and intEnable() BSP functions.  The first argument to each is the device
  190. controller structure. Thus, each has access back to all the device-specific
  191. information.  Having the pointer in the macro facilitates the addition 
  192. of new features to this driver.
  193. The macros SYS_INT_CONNECT, SYS_INT_DISCONNECT, SYS_INT_ENABLE and
  194. SYS_INT_DISABLE allow the driver to be customized for BSPs that use special
  195. versions of these routines.
  196. The macro SYS_INT_CONNECT is used to connect the interrupt handler to
  197. the appropriate vector.  By default it is the routine intConnect().
  198. The macro SYS_INT_DISCONNECT is used to disconnect the interrupt handler prior
  199. to unloading the module.  By default this is a dummy routine that
  200. returns OK.
  201. The macro SYS_INT_ENABLE is used to enable the interrupt level for the
  202. end device.  It is called once during initialization.  It calls an
  203. external board level routine sysEl3c90xIntEnable(). 
  204. The macro SYS_INT_DISABLE is used to disable the interrupt level for the
  205. end device.  It is called during stop.  It calls an
  206. external board level routine sysEl3c90xIntDisable().
  207. The macro SYS_DELAY is used for a delay loop. It calls an external board
  208. level routine sysDelay(delay). The granularity of delay is one microsecond.
  209. SYSTEM RESOURCE USAGE
  210. When implemented, this driver requires the following system resources:
  211.     - one mutual exclusion semaphore
  212.     - one interrupt vector
  213.     - 24072 bytes in text for a I80486 target
  214.     - 112 bytes in the initialized data section (data)
  215.     - 0 bytes in the uninitialized data section (BSS)
  216. The driver allocates clusters of size 1536 bytes for receive frames and
  217. and transmit frames. There are 16 descriptors in the upload ring
  218. and 16 descriptors in the download ring. The buffer multiplier by default
  219. is 2, which means that the total number of clusters allocated by default
  220. are 64 ((upload descriptors + download descriptors)*2). There are as many
  221. clBlks as the number of clusters. The number of mBlks allocated are twice
  222. the number of clBlks. By default there are 64 clusters, 64 clBlks and 128
  223. mBlks allocated in the pool for the device. Depending on the load of the
  224. system increase the number of clusters allocated by incrementing the buffer
  225. multiplier.
  226. INCLUDES:
  227. end.h endLib.h etherMultiLib.h el3c90xEnd.h
  228. SEE ALSO: muxLib, endLib, netBufLib
  229. .pG "Writing and Enhanced Network Driver"
  230. .SH "BIBLIOGRAPHY"
  231. .iB "3COM 3c90x and 3c90xB NICs Technical reference."
  232. */
  233. #include "vxWorks.h"
  234. #include "wdLib.h"
  235. #include "stdlib.h"
  236. #include "taskLib.h"
  237. #include "tickLib.h"
  238. #include "logLib.h"
  239. #include "intLib.h"
  240. #include "netLib.h"
  241. #include "stdio.h"
  242. #include "stdlib.h"
  243. #include "sysLib.h"
  244. #include "iv.h"
  245. #include "memLib.h"
  246. #include "semLib.h"
  247. #include "cacheLib.h"
  248. #include "sys/ioctl.h"
  249. #include "etherMultiLib.h" /* multicast stuff. */
  250. #include "end.h" /* Common END structures. */
  251. #include "endLib.h"
  252. #include "lstLib.h" /* Needed to maintain protocol list. */
  253. #include "netBufLib.h"
  254. #include "muxLib.h"
  255. #include "m2Lib.h"
  256. #include "drv/end/el3c90xEnd.h"
  257. #ifndef EL3C90X_CACHE_INVALIDATE
  258. #define EL3C90X_CACHE_INVALIDATE(address, len) 
  259.         CACHE_DRV_INVALIDATE (&pDrvCtrl->cacheFuncs, (address), (len))
  260. #endif /* EL3C90X_CACHE_INVALIDATE */   
  261.     
  262. #ifndef EL3C90X_CACHE_VIRT_TO_PHYS
  263. #define EL3C90X_CACHE_VIRT_TO_PHYS(address) 
  264.     (MEM_TO_PCI_PHYS((UINT32)(CACHE_DRV_VIRT_TO_PHYS 
  265.                                       (&pDrvCtrl->cacheFuncs,(address)))))
  266. #endif /* EL3C90X_CACHE_VIRT_TO_PHYS */
  267. /* memory to PCI address translation macro */
  268. #ifndef MEM_TO_PCI_PHYS
  269. #define MEM_TO_PCI_PHYS(memAdrs) 
  270.     ((memAdrs) + (pDrvCtrl->pciMemBase))
  271. #endif    
  272.     
  273. /*
  274.  * Default macro definitions for BSP interface.
  275.  * These macros can be redefined in a wrapper file, to generate
  276.  * a new module with an optimized interface.
  277.  */
  278. /* Macro to connect interrupt handler to vector */
  279. #ifndef SYS_INT_CONNECT
  280. #define SYS_INT_CONNECT(pDrvCtrl,rtn,arg,pResult) 
  281.     { 
  282.     *pResult = (*el3c90xIntConnectRtn) ((VOIDFUNCPTR *) 
  283. INUM_TO_IVEC (pDrvCtrl->ivec), 
  284.        rtn, (int)arg); 
  285.     }
  286. #endif
  287. /* Macro to disconnect interrupt handler from vector */
  288. #ifndef SYS_INT_DISCONNECT
  289. #define SYS_INT_DISCONNECT(pDrvCtrl,rtn,arg,pResult) 
  290.     { 
  291.     *pResult = OK;  
  292.     }
  293. #endif
  294. /* Macro to enable the appropriate interrupt level */
  295. #ifndef SYS_INT_ENABLE
  296. #define SYS_INT_ENABLE(pDrvCtrl) 
  297.     { 
  298.     IMPORT STATUS sysEl3c90xIntEnable(); 
  299.     sysEl3c90xIntEnable ((pDrvCtrl)->intLevel); 
  300.     }
  301. #endif /* SYS_INT_ENABLE*/
  302. /* Macro to disable the appropriate interrupt level */
  303. #ifndef SYS_INT_DISABLE
  304. #define SYS_INT_DISABLE(pDrvCtrl) 
  305.     { 
  306.     IMPORT void sysEl3c90xIntDisable (); 
  307.     sysEl3c90xIntDisable ((pDrvCtrl)->intLevel); 
  308.     }
  309. #endif
  310. #ifndef SYS_OUT_LONG
  311. #define SYS_OUT_LONG(pDrvCtrl,addr,value) 
  312.     { 
  313.     *((ULONG *)(addr)) = PCI_SWAP((value)); 
  314.     }
  315. #endif /* SYS_OUT_LONG */
  316. #ifndef SYS_IN_LONG
  317. #define SYS_IN_LONG(pDrvCtrl,addr,data) 
  318.     { 
  319.     ((data) = PCI_SWAP(*((ULONG *)(addr)))); 
  320.     }
  321. #endif /* SYS_IN_LONG */
  322. #ifndef SYS_OUT_SHORT
  323. #define SYS_OUT_SHORT(pDrvCtrl,addr,value) 
  324.     { 
  325.     *((USHORT *)(addr)) = PCI_WORD_SWAP((value)); 
  326.     }
  327. #endif /* SYS_OUT_SHORT*/
  328. #ifndef SYS_IN_SHORT
  329. #define SYS_IN_SHORT(pDrvCtrl,addr,data) 
  330.     { 
  331.     ((data) = PCI_WORD_SWAP(*((USHORT *)(addr)))); 
  332.     }      
  333. #endif /* SYS_IN_SHORT*/
  334. #ifndef SYS_OUT_BYTE
  335. #define SYS_OUT_BYTE(pDrvCtrl,addr,value) 
  336.     { 
  337.     *((UCHAR *)(addr)) = (value); 
  338.     }
  339. #endif /* SYS_OUT_BYTE */
  340. #ifndef SYS_IN_BYTE
  341. #define SYS_IN_BYTE(pDrvCtrl,addr,data) 
  342.     { 
  343.     ((data) = *((UCHAR *)(addr))); 
  344.     }
  345. #endif /* SYS_IN_BYTE */
  346. #ifndef SYS_DELAY    
  347. #define SYS_DELAY(x)           
  348.     {        
  349.     int loop;                  
  350.     loop = (x);                
  351.     loop = ((loop * 3) >> 1);  
  352.     while (loop--)        
  353.         sysDelay();            
  354.     }
  355. #endif /* SYS_DELAY */
  356. /* A shortcut for getting the hardware address from the MIB II stuff. */
  357. #ifdef INCLUDE_RFC_1213
  358. /* Old RFC 1213 mib2 interface */
  359. #define END_HADDR(pEnd) 
  360.                 ((pEnd)->mib2Tbl.ifPhysAddress.phyAddress)
  361. #define END_HADDR_LEN(pEnd) 
  362.                 ((pEnd)->mib2Tbl.ifPhysAddress.addrLength)
  363. #else
  364. /* New RFC 2233 mib2 interface */
  365. #define END_HADDR(pEnd)                                                 
  366.                 ((pEnd)->pMib2Tbl->m2Data.mibIfTbl.ifPhysAddress.phyAddress)
  367. #define END_HADDR_LEN(pEnd)                                             
  368.                 ((pEnd)->pMib2Tbl->m2Data.mibIfTbl.ifPhysAddress.addrLength)
  369. #endif /* INCLUDE_RFC_1213 */
  370. #define END_FLAGS_ISSET(pEnd, setBits) 
  371.             ((pEnd)->flags & (setBits))
  372. #define VOID_TO_DRVCTRL(pVoid,pDrvCtrl) ((pDrvCtrl)=(EL3C90X_DEVICE *)(pVoid))
  373. /* externs */
  374. IMPORT int  endMultiLstCnt (END_OBJ *);
  375. IMPORT void  sysDelay();  /* x86 bSP implements around 720 ns delay */
  376. /* DEBUG MACROS */
  377. #ifdef DRV_DEBUG /* if debugging driver */
  378. int      el3c90xDebug = DRV_DEBUG_LOAD| DRV_DEBUG_INT | DRV_DEBUG_TX;
  379. NET_POOL * pElXlPool;
  380. #define DRV_LOG(FLG, X0, X1, X2, X3, X4, X5, X6) 
  381.         if (el3c90xDebug & FLG) 
  382.             logMsg((char *)X0, (int)X1, (int)X2, (int)X3, (int)X4, 
  383.     (int)X5, (int)X6);
  384. #define ENDLOGMSG(x) 
  385. if (el3c90xDebug) 
  386.     { 
  387.     logMsg x; 
  388.     }
  389. #define DRV_PRINT(FLG,X) 
  390.         if (el3c90xDebug & FLG) printf X;
  391. #else /*DRV_DEBUG*/
  392. #define DRV_LOG(DBG_SW, X0, X1, X2, X3, X4, X5, X6)
  393. #define DRV_PRINT(DBG_SW,X)
  394. #define ENDLOGMSG(x)
  395. #endif /*DRV_DEBUG*/
  396. FUNCPTR el3c90xIntConnectRtn = intConnect;
  397. /*
  398.  * Various supported PHY vendors/types and their names. Note that
  399.  * this driver will work with pretty much any MII-compliant PHY,
  400.  * so failure to positively identify the chip is not a fatal error.
  401.  */
  402. LOCAL EL_DEV_TYPE el3c90xPhyTbl[ ] =
  403.     {
  404.     { TI_PHY_VENDORID, TI_PHY_10BT, "<TI ThunderLAN 10BT (internal)>" },
  405.     { TI_PHY_VENDORID, TI_PHY_100VGPMI, "<TI TNETE211 100VG Any-LAN>" },
  406.     { NS_PHY_VENDORID, NS_PHY_83840A, "<National Semiconductor DP83840A>"},
  407.     { LEVEL1_PHY_VENDORID, LEVEL1_PHY_LXT970, "<Level 1 LXT970>" }, 
  408.     { INTEL_PHY_VENDORID, INTEL_PHY_82555, "<Intel 82555>" },
  409.     { SEEQ_PHY_VENDORID, SEEQ_PHY_80220, "<SEEQ 80220>" },
  410.     { 0, 0, "<MII-compliant physical interface>" }
  411.     };
  412. LOCAL STATUS el3c90xStart (void * pEnd);
  413. LOCAL STATUS el3c90xStop  (void * pEnd);
  414. LOCAL STATUS el3c90xUnload (void * pEnd);
  415. LOCAL int    el3c90xIoctl (void * pEnd, int cmd, caddr_t data);
  416. LOCAL STATUS el3c90xSend (void * pEnd, M_BLK_ID pMblk);
  417. LOCAL STATUS el3c90xMCastAdd (void * pEnd, char * pAddress);
  418. LOCAL STATUS el3c90xMCastDel (void * pEnd, char * pAddress);
  419. LOCAL STATUS el3c90xMCastGet (void * pEnd, MULTI_TABLE * pTable);
  420. LOCAL STATUS el3c90xPollSend (void * pEnd, M_BLK_ID pMblk);
  421. LOCAL STATUS el3c90xPollRcv  (void * pEnd, M_BLK_ID pMblk);
  422. LOCAL void   el3c90xInit (EL3C90X_DEVICE *);
  423. LOCAL STATUS el3c90xMemInit (EL3C90X_DEVICE * pDrvCtrl);
  424. LOCAL void   el3c90xDevStop (EL3C90X_DEVICE *);
  425. LOCAL void   el3c90xReset (EL3C90X_DEVICE *);
  426. LOCAL void   el3c90xIntEnable (EL3C90X_DEVICE * pDrvCtrl);
  427. LOCAL void   el3c90xIntDisable (EL3C90X_DEVICE * pDrvCtrl);
  428. LOCAL STATUS el3c90xPollStart(EL3C90X_DEVICE * pDrvCtrl);
  429. LOCAL STATUS el3c90xPollStop (EL3C90X_DEVICE * pDrvCtrl);
  430. LOCAL int    el3c90xUpdInit (EL3C90X_DEVICE *);
  431. LOCAL int    el3c90xDndInit (EL3C90X_DEVICE *);
  432. LOCAL UINT8  el3c90xHashGet (char *);
  433. LOCAL void   el3c90xFilterSet (EL3C90X_DEVICE *);
  434. LOCAL void   el3c90xHashFilterSet (EL3C90X_DEVICE *);
  435. LOCAL void   el3c90xMcastConfig (EL3C90X_DEVICE * pDrvCtrl);
  436. LOCAL int    el3c90xUpdFill (EL3C90X_DEVICE *, EL_SIMPLE_DESC_CHAIN *);
  437. LOCAL STATUS el3c90xDndMblkPack (EL3C90X_DEVICE *, EL_DESC_CHAIN *, M_BLK_ID);
  438. LOCAL int    el3c90xDndSet (EL3C90X_DEVICE *, EL_DESC_CHAIN *, M_BLK * );
  439. LOCAL STATUS el3c90xDndFree (EL3C90X_DEVICE *, EL_DESC_CHAIN *);
  440. LOCAL STATUS el3c90xDndEnqueue (EL3C90X_DEVICE *, EL_DESC_CHAIN *);
  441. LOCAL EL_DESC_CHAIN * el3c90xDndGet (EL3C90X_DEVICE * pDrvCtrl);
  442. LOCAL EL_DESC_CHAIN * el3c90xTxDequeue (EL3C90X_DEVICE * pDrvCtrl);
  443. LOCAL M_BLK_ID el3c90xNextPktFetch (EL3C90X_DEVICE *, EL_SIMPLE_DESC_CHAIN *);
  444. LOCAL EL_SIMPLE_DESC_CHAIN * el3c90xNextUpdFetch (EL3C90X_DEVICE * pDrvCtrl);
  445. LOCAL STATUS el3c90xRxUnStall (EL3C90X_DEVICE * pDrvCtrl);
  446. LOCAL void   el3c90xRxKick (EL3C90X_DEVICE * pDrvCtrl);
  447. LOCAL void   el3c90xIntrRx (EL3C90X_DEVICE * pDrvCtrl);
  448. LOCAL void   el3c90xIntrTx (EL3C90X_DEVICE * pDrvCtrl);
  449. LOCAL void   el3c90xIntrErr (EL3C90X_DEVICE * pDrvCtrl, UINT8 txstat);
  450. LOCAL void   el3c90xStatUpdate (EL3C90X_DEVICE *);
  451. LOCAL void   el3c90xInt (EL3C90X_DEVICE * pDrvCtrl);
  452. LOCAL void   el3c90xMiiSync (EL3C90X_DEVICE *);
  453. LOCAL void   el3c90xMiiSend (EL3C90X_DEVICE *, UINT32, int);
  454. LOCAL int    el3c90xMiiRegRead (EL3C90X_DEVICE *, EL_MII_FRAME *);
  455. LOCAL int    el3c90xMiiRegWrite (EL3C90X_DEVICE *, EL_MII_FRAME *);
  456. LOCAL UINT16 el3c90xPhyRegRead (EL3C90X_DEVICE *, int);
  457. LOCAL void   el3c90xPhyRegWrite (EL3C90X_DEVICE *, int, int);
  458. LOCAL void   el3c90xAutoNegTx (EL3C90X_DEVICE *);
  459. LOCAL void   el3c90xMiiAutoNeg (EL3C90X_DEVICE *);
  460. LOCAL int    el3c90xMiiModeGet (EL3C90X_DEVICE *);
  461. LOCAL void   el3c90xMediaSet (EL3C90X_DEVICE *, int);
  462. LOCAL void   el3c90xMediaCheck (EL3C90X_DEVICE *);
  463. LOCAL int    el3c90xMediaConfig (EL3C90X_DEVICE * pDrvCtrl);
  464. LOCAL int    el3c90xEprmWait (EL3C90X_DEVICE *);
  465. LOCAL int    el3c90xEprmRead (EL3C90X_DEVICE *, caddr_t, int, int, int);
  466. LOCAL void   el3c90xWait (EL3C90X_DEVICE *);
  467. LOCAL void   el3c90xIntrSet (EL3C90X_DEVICE * pDrvCtrl, UINT16 flag);
  468. LOCAL void   el3c90xIntrClr (EL3C90X_DEVICE * pDrvCtrl, UINT16 flag);
  469. LOCAL UCHAR  el3c90xCsrReadByte (EL3C90X_DEVICE *, USHORT, int);
  470. LOCAL USHORT el3c90xCsrReadWord (EL3C90X_DEVICE *, USHORT, int);
  471. LOCAL ULONG  el3c90xCsrReadLong (EL3C90X_DEVICE *, USHORT, int);
  472. LOCAL void   el3c90xCsrWriteByte (EL3C90X_DEVICE *, USHORT, UCHAR, int);
  473. LOCAL void   el3c90xCsrWriteWord (EL3C90X_DEVICE *, USHORT, USHORT, int);
  474. LOCAL void   el3c90xCsrWriteLong (EL3C90X_DEVICE *, USHORT, ULONG, int);
  475. /*
  476.  * Declare our function table.  This is static across all driver
  477.  * instances.
  478.  */
  479. LOCAL NET_FUNCS el3c90xFuncTable =
  480.     {
  481.     (FUNCPTR) el3c90xStart,     /* Function to start the device. */
  482.     (FUNCPTR) el3c90xStop, /* Function to stop the device. */
  483.     (FUNCPTR) el3c90xUnload, /* Unloading function for the driver. */
  484.     (FUNCPTR) el3c90xIoctl, /* Ioctl function for the driver. */
  485.     (FUNCPTR) el3c90xSend, /* Send function for the driver. */
  486.     (FUNCPTR) el3c90xMCastAdd, /* Multicast address add function for the */
  487. /* driver. */
  488.     (FUNCPTR) el3c90xMCastDel, /* Multicast address delete function for */
  489. /* the driver. */
  490.     (FUNCPTR) el3c90xMCastGet, /* Multicast table retrieve function for */
  491. /* the driver. */
  492.     (FUNCPTR) el3c90xPollSend, /* Polling send function for the driver. */
  493.     (FUNCPTR) el3c90xPollRcv, /* Polling receive function for the driver. */
  494.     endEtherAddressForm,  /* Put address info into a packet.  */
  495.     (FUNCPTR) endEtherPacketDataGet,/* Get a pointer to packet data. */
  496.     (FUNCPTR) endEtherPacketAddrGet /* Get packet addresses. */
  497.     };
  498. /******************************************************************************
  499. *
  500. * el3c90xEndLoad - initialize the driver and device
  501. *
  502. * This routine initializes the driver and the device to the operational state.
  503. * All of the device-specific parameters are passed in <initString>, which
  504. * expects a string of the following format:
  505. *
  506. * <unit>:<devMemAddr>:<devIoAddr>:<pciMemBase:<vecnum>:<intLvl>:<memAdrs>
  507. * :<memSize>:<memWidth>:<flags>:<buffMultiplier>
  508. *
  509. * This routine can be called in two modes. If it is called with an empty but
  510. * allocated string, it places the name of this device (that is, "elPci") into 
  511. * the <initString> and returns 0.
  512. *
  513. * If the string is allocated and not empty, the routine attempts to load
  514. * the driver using the values specified in the string.
  515. *
  516. * RETURNS: An END object pointer, or NULL on error, or 0 and the name of the
  517. * device if the <initString> was NULL.
  518. */
  519. END_OBJ * el3c90xEndLoad
  520.     (
  521.     char * initString /* String to be parsed by the driver. */
  522.     )
  523.     {
  524.     EL3C90X_DEVICE * pDrvCtrl = NULL;
  525.     int speed;
  526.     DRV_LOG (DRV_DEBUG_LOAD, "Loading elPci...n", 1, 2, 3, 4, 5, 6);
  527.     if (initString == NULL)
  528.         return (NULL);
  529.     
  530.     if (initString [0] == 0)
  531.         {
  532.         bcopy ((char *)EL3C90X_DEV_NAME, initString,
  533.                EL3C90X_DEV_NAME_LEN);
  534.         return (0);
  535.         }
  536.     if ((pDrvCtrl = (EL3C90X_DEVICE *)calloc (sizeof (EL3C90X_DEVICE), 1))
  537.         == NULL)
  538.         return (NULL);
  539.         
  540.     /* parse the init string, filling in the device structure */
  541.     if (el3c90xInitParse (pDrvCtrl, initString) == ERROR)
  542.         goto endLoadFail;
  543.     /* initialize the END and MIB2 parts of the structure */
  544.     
  545.     if (END_OBJ_INIT (&pDrvCtrl->endObj, (DEV_OBJ *)pDrvCtrl,
  546.                       EL3C90X_DEV_NAME,
  547.                       pDrvCtrl->unit, &el3c90xFuncTable,
  548.                       "3COM 3c90X Fast Etherlink Endhanced Network Driver.")
  549.         == ERROR)
  550.         {
  551.         goto endLoadFail;
  552.         }
  553.     /* Reset the adapter. */
  554.     el3c90xReset(pDrvCtrl);
  555.     /* get station address from the EEPROM */
  556.     if (el3c90xEprmRead(pDrvCtrl, &pDrvCtrl->enetAddr[0], EL_EE_OEM_ADR0, 3, 1)
  557.         != OK)
  558.         {
  559.         DRV_LOG (DRV_DEBUG_LOAD, "elPci%d: failed to read station addressn",
  560.                  pDrvCtrl->unit, 2, 3, 4, 5, 6);
  561.         goto endLoadFail;
  562. }
  563.     /* Perform memory allocation */
  564.     if (el3c90xMemInit (pDrvCtrl) == ERROR)
  565.         goto endLoadFail;
  566.     DRV_LOG (DRV_DEBUG_LOAD, "Malloc done ...n", 1, 2, 3, 4, 5, 6);
  567.         
  568.     /*
  569.      * Figure out the card type. 3c905B adapters have the
  570.      * 'supportsNoTxLength' bit set in the capabilities
  571.      * word in the EEPROM.
  572.      */
  573.     el3c90xEprmRead(pDrvCtrl, (caddr_t)&pDrvCtrl->devCaps, EL_EE_CAPS, 1, 0);
  574.     if (pDrvCtrl->devCaps & EL_CAPS_NO_TXLENGTH)
  575.         pDrvCtrl->devType = EL_TYPE_905B;
  576.     else
  577.         pDrvCtrl->devType = EL_TYPE_90X;
  578.     speed =  el3c90xMediaConfig (pDrvCtrl);
  579.    
  580. #ifdef INCLUDE_RFC_1213
  581.     /* Old RFC 1213 mib2 interface */
  582.     if (END_MIB_INIT (&pDrvCtrl->endObj, M2_ifType_ethernet_csmacd,
  583.                       &pDrvCtrl->enetAddr[0], 6, ETHERMTU, speed)
  584.         == ERROR)
  585.         goto endLoadFail;
  586.     /* set the flags to indicate readiness */
  587.     END_OBJ_READY (&pDrvCtrl->endObj, IFF_NOTRAILERS | IFF_BROADCAST |
  588.                    IFF_MULTICAST  | IFF_SIMPLEX);
  589. #else
  590.     /* New RFC 2233 mib2 interface */
  591.  
  592.     /* Initialize MIB-II entries (for RFC 2233 ifXTable) */
  593.     pDrvCtrl->endObj.pMib2Tbl = m2IfAlloc(M2_ifType_ethernet_csmacd,
  594.                                           (UINT8*) &pDrvCtrl->enetAddr[0], 6,
  595.                                           ETHERMTU, speed,
  596.                                           EL3C90X_DEV_NAME, pDrvCtrl->unit);
  597.     if (pDrvCtrl->endObj.pMib2Tbl == NULL)
  598.         {
  599.         printf ("%s%d - MIB-II initializations failedn",
  600.                 EL3C90X_DEV_NAME, pDrvCtrl->unit);
  601.         goto endLoadFail;
  602.         }
  603.     /* 
  604.      * Set the RFC2233 flag bit in the END object flags field and
  605.      * install the counter update routines.
  606.      */
  607.     pDrvCtrl->endObj.flags |= END_MIB_2233;
  608.     m2IfPktCountRtnInstall(pDrvCtrl->endObj.pMib2Tbl, m2If8023PacketCount);
  609.     /*
  610.      * Make a copy of the data in mib2Tbl struct as well. We do this
  611.      * mainly for backward compatibility issues. There might be some
  612.      * code that might be referencing the END pointer and might
  613.      * possibly do lookups on the mib2Tbl, which will cause all sorts
  614.      * of problems.
  615.      */
  616.     bcopy ((char *)&pDrvCtrl->endObj.pMib2Tbl->m2Data.mibIfTbl,
  617.                    (char *)&pDrvCtrl->endObj.mib2Tbl, sizeof (M2_INTERFACETBL));
  618.     /* set the flags to indicate readiness */
  619.     END_OBJ_READY (&pDrvCtrl->endObj, IFF_NOTRAILERS | IFF_BROADCAST |
  620.                    IFF_MULTICAST  | IFF_SIMPLEX | END_MIB_2233);
  621. #endif /* INCLUDE_RFC_1213 */
  622.     DRV_LOG (DRV_DEBUG_LOAD, "Done loading elPci...n", 1, 2, 3, 4, 5, 6);
  623.     return (&pDrvCtrl->endObj);
  624.     
  625.     endLoadFail:
  626.         {
  627.         if (pDrvCtrl != NULL)
  628.             free ((char *)pDrvCtrl);
  629.         }
  630.     
  631.     return ((END_OBJ *)NULL);
  632.     }
  633. /*******************************************************************************
  634. *
  635. * el3c90xInitParse - parse the initialization string
  636. *
  637. * Parse the input string. This routine is called from el3c90xEndLoad() which
  638. * intializes some values in the driver control structure with the values
  639. * passed in the intialization string.
  640. *
  641. * The initialization string format is:
  642. * <unit>:<devMemAddr>:<devIoAddr>:<pciMemBase:<vecNum>:<intLvl>:<memAdrs>
  643. * :<memSize>:<memWidth>:<flags>:<buffMultiplier>
  644. *
  645. * .IP <unit>
  646. * Device unit number, a small integer.
  647. * .IP <devMemAddr>
  648. * Device register base memory address
  649. * .IP <devIoAddr>
  650. * Device register base IO address
  651. * .IP <pciMemBase>
  652. * Base address of PCI memory space
  653. * .IP <vecNum>
  654. * Interrupt vector number.
  655. * .IP <intLvl>
  656. * Interrupt level.
  657. * .IP <memAdrs>
  658. * Memory pool address or NONE.
  659. * .IP <memSize>
  660. * Memory pool size or zero.
  661. * .IP <memWidth>
  662. * Memory system size, 1, 2, or 4 bytes (optional).
  663. * .IP <flags>
  664. * Device specific flags, for future use.
  665. * .IP <buffMultiplier>
  666. * Buffer Multiplier or NONE. If NONE is specified, it defaults to 2
  667. *
  668. * RETURNS: OK, or ERROR if any arguments are invalid.
  669. */
  670. STATUS el3c90xInitParse
  671.     (
  672.     EL3C90X_DEVICE * pDrvCtrl, /* pointer to the control structure */
  673.     char *  initString /* initialization string */
  674.     )
  675.     {
  676.     char*       tok;
  677.     char*       pHolder = NULL;
  678.     UINT32      devMemAddr;
  679.     UINT32      devIoAddr;
  680.     DRV_LOG (DRV_DEBUG_LOAD, "Parse starting ...n", 1, 2, 3, 4, 5, 6);
  681.     /* Parse the initString */
  682.     /* Unit number. */
  683.     tok = strtok_r (initString, ":", &pHolder);
  684.     if (tok == NULL)
  685.         return ERROR;
  686.     pDrvCtrl->unit = atoi (tok);
  687.     DRV_LOG (DRV_DEBUG_LOAD, "Unit : %d ...n", pDrvCtrl->unit, 2, 3, 4, 5, 6);
  688.     /* devAdrs address. */
  689.     tok = strtok_r (NULL, ":", &pHolder);
  690.     if (tok == NULL)
  691.         return ERROR;
  692.     devMemAddr = (UINT32) strtoul (tok, NULL, 16);
  693.     DRV_LOG (DRV_DEBUG_LOAD, "devMemAddr : 0x%X ...n", devMemAddr,
  694.              2, 3, 4, 5, 6);
  695.     /* devIoAddrs address */
  696.     tok = strtok_r (NULL, ":", &pHolder);
  697.     if (tok == NULL)
  698.         return ERROR;
  699.     devIoAddr = (UINT32) strtoul (tok, NULL, 16);
  700.     DRV_LOG (DRV_DEBUG_LOAD, "devIoAddr : 0x%X ...n", devIoAddr,
  701.              2, 3, 4, 5, 6);
  702.     /* always use memory mapped IO if provided, else use io map */
  703.     
  704.     if ((devMemAddr == NONE) && (devIoAddr == NONE))
  705.         {
  706.         DRV_LOG (DRV_DEBUG_LOAD, "No memory or IO base specified ...n",
  707.                  1, 2, 3, 4, 5, 6);
  708.         return (ERROR);
  709.         }
  710.     else if (devMemAddr != NONE)
  711.         {
  712.         pDrvCtrl->devAdrs = devMemAddr;
  713.         pDrvCtrl->flags   |= EL_MODE_MEM_IO_MAP;
  714.         }
  715.     else
  716.         {
  717.         pDrvCtrl->devAdrs = devIoAddr;
  718.         }
  719.         
  720.     /* PCI memory base address as seen from the CPU */
  721.     
  722.     tok = strtok_r (NULL, ":", &pHolder);
  723.     if (tok == NULL)
  724.         return ERROR;
  725.     pDrvCtrl->pciMemBase = strtoul (tok, NULL, 16);
  726.     DRV_LOG (DRV_DEBUG_LOAD, "Pci : 0x%X ...n", pDrvCtrl->pciMemBase,
  727.              2, 3, 4, 5, 6);
  728.     /* Interrupt vector. */
  729.     tok = strtok_r (NULL, ":", &pHolder);
  730.     if (tok == NULL)
  731.         return ERROR;
  732.     pDrvCtrl->ivec = atoi (tok);
  733.     DRV_LOG (DRV_DEBUG_LOAD, "ivec : 0x%X ...n", pDrvCtrl->ivec,
  734.              2, 3, 4, 5, 6);
  735.     /* Interrupt level. */
  736.     tok = strtok_r (NULL, ":", &pHolder);
  737.     if (tok == NULL)
  738.         return ERROR;
  739.     pDrvCtrl->intLevel = atoi (tok);
  740.     DRV_LOG (DRV_DEBUG_LOAD, "ilevel : 0x%X ...n", pDrvCtrl->intLevel,
  741.              2, 3, 4, 5, 6);
  742.     /* Caller supplied memory address. */
  743.     tok = strtok_r (NULL, ":", &pHolder);
  744.     if (tok == NULL)
  745.         return ERROR;
  746.     pDrvCtrl->memAdrs = (char *)strtoul (tok, NULL, 16);
  747.     DRV_LOG (DRV_DEBUG_LOAD, "memAdrs : 0x%X ...n", (int)pDrvCtrl->memAdrs,
  748.              2, 3, 4, 5, 6);
  749.     /* Caller supplied memory size. */
  750.     tok = strtok_r (NULL, ":", &pHolder);
  751.     if (tok == NULL)
  752.         return ERROR;
  753.     pDrvCtrl->memSize = strtoul (tok, NULL, 16);
  754.     DRV_LOG (DRV_DEBUG_LOAD, "memSize : 0x%X ...n", pDrvCtrl->memSize,
  755.              2, 3, 4, 5, 6);
  756.     /* Caller supplied memory width. */
  757.     tok = strtok_r (NULL, ":", &pHolder);
  758.     if (tok == NULL)
  759.         return ERROR;
  760.     pDrvCtrl->memWidth = atoi (tok);
  761.     DRV_LOG (DRV_DEBUG_LOAD, "memWidth : 0x%X ...n", pDrvCtrl->memWidth,
  762.              2, 3, 4, 5, 6);
  763.     /* caller supplied flags */
  764.     tok = strtok_r (NULL, ":", &pHolder);
  765.     if (tok == NULL)
  766.         return ERROR;
  767.     pDrvCtrl->flags |= strtoul (tok, NULL, 16);
  768.     DRV_LOG (DRV_DEBUG_LOAD, "flags : 0x%X ...n", pDrvCtrl->flags,
  769.              2, 3, 4, 5, 6);
  770.     /* buffer multiplier */
  771.     tok = strtok_r (NULL, ":", &pHolder);
  772.     if (tok == NULL)
  773.         return ERROR;
  774.     pDrvCtrl->bufMtplr |= strtoul (tok, NULL, 16);
  775.     DRV_LOG (DRV_DEBUG_LOAD, "bufMultiplier : 0x%X ...n", pDrvCtrl->bufMtplr,
  776.              2, 3, 4, 5, 6);
  777.     return OK;
  778.     }
  779. /*******************************************************************************
  780. *
  781. * el3c90xStart - start the device
  782. *
  783. * This function calls BSP functions to connect interrupts and start the
  784. * device running in interrupt mode.
  785. *
  786. * RETURNS: OK or ERROR
  787. *
  788. */
  789. LOCAL STATUS el3c90xStart
  790.     (
  791.     void * pEnd /* device to be started */
  792.     )
  793.     {
  794.     STATUS  result;
  795.     EL3C90X_DEVICE *  pDrvCtrl;
  796.     int flags;
  797.     VOID_TO_DRVCTRL (pEnd, pDrvCtrl);
  798.     
  799.     pDrvCtrl->txBlocked  = FALSE;
  800.     /* perform all initialization memory, ring buffer etc */
  801.     
  802.     el3c90xInit(pDrvCtrl);
  803.     
  804.     flags = END_FLAGS_GET (&pDrvCtrl->endObj);
  805.     flags |= (IFF_UP | IFF_RUNNING);
  806.     END_FLAGS_SET (&pDrvCtrl->endObj, flags);
  807.     
  808.     SYS_INT_CONNECT (pDrvCtrl, el3c90xInt, (int)pDrvCtrl, &result);
  809.     if (result == ERROR)
  810. return ERROR;
  811.     ENDLOGMSG (("Interrupt connected.n", 1, 2, 3, 4, 5, 6));
  812.     SYS_INT_ENABLE (pDrvCtrl);
  813.     ENDLOGMSG (("interrupt enabled.n", 1, 2, 3, 4, 5, 6));
  814.     return (OK);
  815.     }
  816. /*******************************************************************************
  817. *
  818. * el3c90xStop - stop the device
  819. *
  820. * This function calls BSP functions to disconnect interrupts and stop
  821. * the device from operating in interrupt mode.
  822. *
  823. * RETURNS: OK or ERROR.
  824. */
  825. LOCAL STATUS el3c90xStop
  826.     (
  827.     void * pEnd /* device to be stopped */
  828.     )
  829.     {
  830.     STATUS  result = OK;
  831.     EL3C90X_DEVICE *  pDrvCtrl;
  832.     VOID_TO_DRVCTRL (pEnd, pDrvCtrl);
  833.     END_FLAGS_CLR (&pDrvCtrl->endObj, IFF_UP | IFF_RUNNING);
  834.     el3c90xDevStop (pDrvCtrl);
  835.     SYS_INT_DISCONNECT (pDrvCtrl, el3c90xInt, (int)pDrvCtrl, &result);
  836.     if (result == ERROR)
  837. {
  838. ENDLOGMSG (("Could not diconnect interrupt!n", 1, 2, 3, 4, 5, 6));
  839. }
  840.     SYS_INT_DISABLE (pDrvCtrl);
  841.     return (result);
  842.     }
  843. /******************************************************************************
  844. *
  845. * el3c90xUnload - unload a driver from the system
  846. *
  847. * This function first brings down the device, and then frees any
  848. * stuff that was allocated by the driver in the load function.
  849. *
  850. * RETURNS: OK or ERROR.
  851. */
  852. LOCAL STATUS el3c90xUnload
  853.     (
  854.     void * pEnd /* device to be unloaded */
  855.     )
  856.     {
  857.     EL3C90X_DEVICE * pDrvCtrl;
  858.     VOID_TO_DRVCTRL (pEnd, pDrvCtrl);
  859.     
  860.     END_OBJECT_UNLOAD (&pDrvCtrl->endObj);
  861.     /* Free the shared DMA memory. */
  862.     if (pDrvCtrl->flags & EL_MEM_ALLOC_FLAG)
  863.         {
  864.         /* free the memory allocated for descriptors */
  865.         
  866.         if (pDrvCtrl->pDescMem != NULL)
  867.             cacheDmaFree (pDrvCtrl->pDescMem);
  868.         /* free the memory allocated for clusters */
  869.         if (pDrvCtrl->clDesc.memArea != NULL)
  870.             cacheDmaFree (pDrvCtrl->clDesc.memArea);
  871.         /* Free the memory allocated for mBlks and clBlks */
  872.         if (pDrvCtrl->mClCfg.memArea != NULL)
  873.             free (pDrvCtrl->mClCfg.memArea);
  874.         }
  875.     if (pDrvCtrl->endObj.pNetPool != NULL)
  876.         free (pDrvCtrl->endObj.pNetPool);
  877.     
  878.     return (OK);
  879.     }
  880. /*******************************************************************************
  881. *
  882. * el3c90xIoctl - the driver I/O control routine
  883. *
  884. * Process an ioctl request.
  885. *
  886. * RETURNS: A command specific response, OK or ERROR or EINVAL.
  887. */
  888. LOCAL int el3c90xIoctl
  889.     (
  890.     void *  pEnd,           /* device  ptr*/
  891.     int  cmd, /* ioctl command code */
  892.     caddr_t  data /* command argument */
  893.     )
  894.     {
  895.     int  error = 0;
  896.     long  value;
  897.     EL3C90X_DEVICE *  pDrvCtrl;
  898.     VOID_TO_DRVCTRL (pEnd, pDrvCtrl);
  899.     switch (cmd)
  900.         {
  901.         case EIOCSADDR:
  902.     if (data == NULL)
  903. return (EINVAL);
  904.             bcopy ((char *)data, (char *)END_HADDR(&pDrvCtrl->endObj),
  905.    END_HADDR_LEN(&pDrvCtrl->endObj));
  906.             break;
  907.         case EIOCGADDR:
  908.     if (data == NULL)
  909. return (EINVAL);
  910.             bcopy ((char *)END_HADDR(&pDrvCtrl->endObj), (char *)data,
  911.     END_HADDR_LEN(&pDrvCtrl->endObj));
  912.             break;
  913.         case EIOCSFLAGS:
  914.     value = (long)data;
  915.     if (value < 0)
  916. {
  917. value = -value;
  918. value--;
  919. END_FLAGS_CLR (&pDrvCtrl->endObj, value);
  920. }
  921.     else
  922. {
  923. END_FLAGS_SET (&pDrvCtrl->endObj, value);
  924. }
  925.             if (END_FLAGS_GET(&pDrvCtrl->endObj) & IFF_UP)
  926.                 {
  927.                 el3c90xInit (pDrvCtrl);
  928. }
  929.             else
  930.                 {
  931.                 if (END_FLAGS_GET(&pDrvCtrl->endObj) & IFF_RUNNING)
  932.                     el3c90xDevStop (pDrvCtrl);
  933. }
  934.             error = 0;
  935.             break;
  936.         case EIOCGFLAGS:
  937.     *(int *)data = END_FLAGS_GET(&pDrvCtrl->endObj);
  938.             break;
  939. case EIOCPOLLSTART:
  940.     error = el3c90xPollStart(pDrvCtrl);
  941.     break;
  942.  
  943. case EIOCPOLLSTOP:
  944.     error = el3c90xPollStop(pDrvCtrl);
  945.       break;
  946.         case EIOCGMIB2:
  947.             if (data == NULL)
  948.                 return (EINVAL);
  949.             bcopy((char *)&pDrvCtrl->endObj.mib2Tbl, (char *)data,
  950.                   sizeof(pDrvCtrl->endObj.mib2Tbl));
  951.             break;
  952.         case EIOCGFBUF:
  953.             if (data == NULL)
  954.                 return (EINVAL);
  955.             *(int *)data = EL_MIN_FBUF;
  956.             break;
  957.         case EIOCGMWIDTH:
  958.             if (data == NULL)
  959.                 return (EINVAL);
  960.             break;
  961.         case EIOCGHDRLEN:
  962.             if (data == NULL)
  963.                 return (EINVAL);
  964.             *(int *)data = EH_SIZE;
  965.             break;
  966. #ifndef INCLUDE_RFC_1213
  967.         /* New RFC 2233 mib2 interface */
  968.         case EIOCGMIB2233:
  969.             if ((data == NULL) || (pDrvCtrl->endObj.pMib2Tbl == NULL))
  970.                 error = EINVAL;
  971.             else
  972.                 *((M2_ID **)data) = pDrvCtrl->endObj.pMib2Tbl;
  973.             break;
  974. #endif /* INCLUDE_RFC_1213 */
  975.         default:
  976.             error = EINVAL;
  977.         }
  978.     return (error);
  979.     }
  980. /*******************************************************************************
  981. *
  982. * el3c90xSend - the driver send routine
  983. *
  984. * This routine takes a M_BLK_ID sends off the data in the M_BLK_ID.
  985. * The buffer must already have the addressing information properly installed
  986. * in it.  This is done by a higher layer.
  987. *
  988. * RETURNS: OK or END_ERR_BLOCK or ERROR.
  989. */
  990. LOCAL STATUS el3c90xSend
  991.     (
  992.     void  *  pEnd, /* device ptr */
  993.     M_BLK_ID  pMblk /* data to send */
  994.     )
  995.     {
  996.     EL3C90X_DEVICE *  pDrvCtrl;
  997.     EL_DESC_CHAIN * pTxChain = NULL;
  998.     VOID_TO_DRVCTRL (pEnd, pDrvCtrl);
  999.     /* return if in polled mode */
  1000.     
  1001.     if (pDrvCtrl->flags & EL_POLLING)
  1002.         { 
  1003.         netMblkClChainFree (pMblk); /* free the given mBlk chain */
  1004.         errno = EINVAL;
  1005.         return (ERROR);
  1006.         }
  1007.     DRV_LOG (DRV_DEBUG_TX, "Sendn", 1, 2, 3, 4, 5, 6);
  1008.     END_TX_SEM_TAKE (&pDrvCtrl->endObj, WAIT_FOREVER);
  1009.     /* get a free download descriptor */
  1010.     
  1011.     if ((pTxChain = el3c90xDndGet (pDrvCtrl)) == NULL)
  1012.         {
  1013.         DRV_LOG (DRV_DEBUG_TX, "Out of TMDs!n", 1, 2, 3, 4, 5, 6);
  1014.         pDrvCtrl->txBlocked = TRUE;
  1015.         END_TX_SEM_GIVE (&pDrvCtrl->endObj);
  1016.         return (END_ERR_BLOCK);
  1017.         }
  1018.     /* Pack the data into the descriptor. */
  1019.     if (el3c90xDndSet(pDrvCtrl, pTxChain, pMblk) == ERROR)
  1020.         {
  1021.         netMblkClChainFree (pMblk); /* free the given mBlk chain */
  1022.         el3c90xDndFree (pDrvCtrl, pTxChain);
  1023.         END_TX_SEM_GIVE (&pDrvCtrl->endObj);
  1024.         return (ERROR);
  1025.         }
  1026. #ifndef INCLUDE_RFC_1213
  1027.     /* New RFC 2233 mib2 interface */
  1028.     /* RFC 2233 mib2 counter update for outgoing packet */
  1029.     if (pDrvCtrl->endObj.pMib2Tbl != NULL)
  1030.         {
  1031.         pDrvCtrl->endObj.pMib2Tbl->m2PktCountRtn(pDrvCtrl->endObj.pMib2Tbl,
  1032.                                                  M2_PACKET_OUT,
  1033.                                                  pMblk->mBlkHdr.mData,
  1034.                                                  pMblk->mBlkHdr.mLen);
  1035.         }
  1036. #endif /* INCLUDE_RFC_1213 */
  1037.     /* set the interrupt bit for the downloaded packet */
  1038.     pTxChain->pDesc->status |= PCI_SWAP (EL_TXSTAT_DL_INTR);
  1039.     el3c90xDndEnqueue (pDrvCtrl, pTxChain);
  1040.     END_TX_SEM_GIVE (&pDrvCtrl->endObj);
  1041.     /* kick the reciever if blocked, parallel tasking */
  1042.     el3c90xRxKick (pDrvCtrl);
  1043.     return (OK);
  1044.     }
  1045. /*****************************************************************************
  1046. *
  1047. * el3c90xMCastAdd - add a multicast address for the device
  1048. *
  1049. * This routine adds a multicast address to whatever the driver
  1050. * is already listening for.  It then resets the address filter.
  1051. *
  1052. * RETURNS: OK or ERROR.
  1053. */
  1054. LOCAL STATUS el3c90xMCastAdd
  1055.     (
  1056.     void  *  pEnd,         /* device pointer */
  1057.     char *  pAddress /* new address to add */
  1058.     )
  1059.     {
  1060.     int  error;
  1061.     EL3C90X_DEVICE *  pDrvCtrl;
  1062.     VOID_TO_DRVCTRL (pEnd, pDrvCtrl);
  1063.     if ((error = etherMultiAdd (&pDrvCtrl->endObj.multiList,
  1064. pAddress)) == ENETRESET)
  1065. el3c90xMcastConfig (pDrvCtrl);
  1066.     return (OK);
  1067.     }
  1068. /*****************************************************************************
  1069. *
  1070. * el3c90xMCastDel - delete a multicast address for the device
  1071. *
  1072. * This routine removes a multicast address from whatever the driver
  1073. * is listening for.  It then resets the address filter.
  1074. *
  1075. * RETURNS: OK or ERROR.
  1076. */
  1077. LOCAL STATUS el3c90xMCastDel
  1078.     (
  1079.     void  *  pEnd,         /* device pointer */
  1080.     char *  pAddress /* address to be deleted */
  1081.     )
  1082.     {
  1083.     int  error;
  1084.     EL3C90X_DEVICE *  pDrvCtrl;
  1085.     VOID_TO_DRVCTRL (pEnd, pDrvCtrl);
  1086.     if ((error = etherMultiDel (&pDrvCtrl->endObj.multiList,
  1087.      (char *)pAddress)) == ENETRESET)
  1088. el3c90xMcastConfig (pDrvCtrl);
  1089.     return (OK);
  1090.     }
  1091. /*****************************************************************************
  1092. *
  1093. * el3c90xMCastGet - get the multicast address list for the device
  1094. *
  1095. * This routine gets the multicast list of whatever the driver
  1096. * is already listening for.
  1097. *
  1098. * RETURNS: OK or ERROR.
  1099. */
  1100. LOCAL STATUS el3c90xMCastGet
  1101.     (
  1102.     void  *  pEnd,         /* device pointer */
  1103.     MULTI_TABLE *  pTable /* address table to be filled in */
  1104.     )
  1105.     {
  1106.     EL3C90X_DEVICE * pDrvCtrl;
  1107.     VOID_TO_DRVCTRL (pEnd, pDrvCtrl);
  1108.     return (etherMultiGet (&pDrvCtrl->endObj.multiList, pTable));
  1109.     }
  1110. /*******************************************************************************
  1111. *
  1112. * el3c90xPollSend - routine to send a packet in polled mode.
  1113. *
  1114. * This routine is called by a user to try and send a packet on the
  1115. * device.
  1116. *
  1117. * RETURNS: OK upon success.  EAGAIN if device is busy.
  1118. */
  1119. LOCAL STATUS el3c90xPollSend
  1120.     (
  1121.     void  *  pEnd,         /* device pointer */
  1122.     M_BLK_ID  pMblk /* packet to send */
  1123.     )
  1124.     {
  1125.     EL3C90X_DEVICE *  pDrvCtrl;
  1126.     EL_DESC_CHAIN * pTxChain = NULL;
  1127.     VOID_TO_DRVCTRL (pEnd, pDrvCtrl);
  1128.     DRV_LOG (DRV_DEBUG_POLL_TX, "PTX bn", 1, 2, 3, 4, 5, 6);
  1129.     /* check if download engine is still busy */
  1130.     if (el3c90xCsrReadLong (pDrvCtrl, EL_DOWNLIST_PTR, NONE))
  1131.         {
  1132.         DRV_LOG (DRV_DEBUG_POLL_TX, "transmitter busyn", 1, 2, 3, 4, 5, 6);
  1133.         
  1134.         return (EAGAIN);
  1135.         }
  1136.     /* check if a download descriptor is available */
  1137.     if ((pTxChain =  el3c90xDndGet (pDrvCtrl)) == NULL)
  1138.         return (EAGAIN);
  1139.     /* Pack the mBlk into the download descriptor. */
  1140.     if (el3c90xDndMblkPack (pDrvCtrl, pTxChain, pMblk) == ERROR)
  1141.         {
  1142.         el3c90xDndFree (pDrvCtrl, pTxChain);
  1143.         return (EAGAIN);
  1144.         }
  1145. #ifndef INCLUDE_RFC_1213
  1146.     /* New RFC 2233 mib2 interface */
  1147.     /* RFC 2233 mib2 counter update for outgoing packet */
  1148.     if (pDrvCtrl->endObj.pMib2Tbl != NULL)
  1149.         {
  1150.         pDrvCtrl->endObj.pMib2Tbl->m2PktCountRtn(pDrvCtrl->endObj.pMib2Tbl,
  1151.                                                  M2_PACKET_OUT,
  1152.                                                  pMblk->mBlkHdr.mData,
  1153.                                                  pMblk->mBlkHdr.mLen);
  1154.         }
  1155. #endif /* INCLUDE_RFC_1213 */
  1156.     el3c90xCsrWriteLong (pDrvCtrl, EL_DOWNLIST_PTR,
  1157.                          (UINT32)EL3C90X_CACHE_VIRT_TO_PHYS (pTxChain->pDesc),
  1158.                          NONE);
  1159.     /* wait until download has completed */
  1160.     
  1161.     while (el3c90xCsrReadLong (pDrvCtrl, EL_DOWNLIST_PTR, NONE))
  1162.         ;
  1163.     el3c90xDndFree (pDrvCtrl, pTxChain);
  1164.     DRV_LOG (DRV_DEBUG_POLL_TX, "PTX en", 1, 2, 3, 4, 5, 6);
  1165.     return (OK);
  1166.     }
  1167. /*******************************************************************************
  1168. *
  1169. * el3c90xPollRcv - routine to receive a packet in polled mode.
  1170. *
  1171. * This routine is called by a user to try and get a packet from the
  1172. * device.
  1173. *
  1174. * RETURNS: EGAIN or OK
  1175. */
  1176. LOCAL STATUS el3c90xPollRcv
  1177.     (
  1178.     void  *  pEnd, /* device pointer */
  1179.     M_BLK_ID  pMblk /* pointer to the mBlk chain */
  1180.     )
  1181.     {
  1182.     EL_SIMPLE_DESC_CHAIN *  pRxUpd;
  1183.     EL3C90X_DEVICE *  pDrvCtrl;
  1184.     M_BLK_ID  pMblkTemp; /* pointer to the mBlk */
  1185.     int len;
  1186.     DRV_LOG (DRV_DEBUG_POLL_RX, "PRX bn", 1, 2, 3, 4, 5, 6);
  1187.     VOID_TO_DRVCTRL (pEnd, pDrvCtrl);
  1188.     el3c90xRxUnStall (pDrvCtrl);
  1189.     /* get the next upload descriptor */
  1190.     
  1191.     if ((pRxUpd = el3c90xNextUpdFetch (pDrvCtrl)) == NULL)
  1192.         {
  1193.         DRV_LOG (DRV_DEBUG_POLL_RX, "PRX no updn", 1, 2, 3, 4, 5, 6);
  1194.         return (EAGAIN);
  1195.         }
  1196.     /* get the mBlk associated with the upd */
  1197.     
  1198.     if ((pMblkTemp = el3c90xNextPktFetch (pDrvCtrl, pRxUpd)) == NULL)
  1199.         return (EAGAIN);
  1200.     /* copy the data into the given buffer */
  1201.     
  1202.     len = netMblkToBufCopy (pMblkTemp, pMblk->mBlkHdr.mData, NULL);
  1203.     netMblkClChainFree (pMblkTemp);
  1204.     if ((pMblk->mBlkHdr.mLen < len) || (!(pMblk->mBlkHdr.mFlags & M_EXT)))
  1205. {
  1206.         DRV_LOG (DRV_DEBUG_POLL_RX, "PRX bad mblk len:%d flags:%dn",
  1207.                  pMblk->mBlkHdr.mLen, pMblk->mBlkHdr.mFlags, 3, 4, 5, 6);
  1208. return (EAGAIN);
  1209. }
  1210.     pMblk->mBlkHdr.mLen = len;
  1211.     pMblk->mBlkHdr.mFlags |= M_PKTHDR;
  1212.     pMblk->mBlkPktHdr.len = len;
  1213. #ifndef INCLUDE_RFC_1213
  1214.     /* New RFC 2233 mib2 interface */
  1215.     /* RFC 2233 mib2 counter update for incoming packet */
  1216.     if (pDrvCtrl->endObj.pMib2Tbl != NULL)
  1217.         {
  1218.         pDrvCtrl->endObj.pMib2Tbl->m2PktCountRtn(pDrvCtrl->endObj.pMib2Tbl,
  1219.                                                  M2_PACKET_IN,
  1220.                                                  pMblk->mBlkHdr.mData,
  1221.                                                  pMblk->mBlkHdr.mLen);
  1222.         }
  1223. #endif /* INCLUDE_RFC_1213 */
  1224.     DRV_LOG (DRV_DEBUG_POLL_RX, "PRX okn", 1, 2, 3, 4, 5, 6);
  1225.     return (OK);
  1226.     }
  1227. /*******************************************************************************
  1228. *
  1229. * el3c90xInit - initialize the device
  1230. *
  1231. * This routine initializes device and enables the device interrupts. It
  1232. * initializes the descriptor rings
  1233. *
  1234. * RETURNS: N/A
  1235. */
  1236. LOCAL void el3c90xInit
  1237.     (
  1238.     EL3C90X_DEVICE * pDrvCtrl /* pointer to the device control structure */
  1239.     )
  1240.     {
  1241.     int ix;
  1242.     UINT16 rxFilt = 0;
  1243.     UINT16 phyBMCR = 0;
  1244.     int flags;
  1245.     /*
  1246.      * hack for the 3c905B: the built-in autoneg logic's state
  1247.      * gets reset by el3c90xInit() when we don't want it to. Try
  1248.      * to preserve it. (For 3c905 cards with real external PHYs,
  1249.      * the BMCR register doesn't change, but this doesn't hurt.)
  1250.      */
  1251.     if (pDrvCtrl->pPhyDevType != NULL)
  1252.         phyBMCR = el3c90xPhyRegRead(pDrvCtrl, PHY_BMCR);
  1253.     /* cancel pending I/O and free all RX/TX buffers. */
  1254.     el3c90xDevStop(pDrvCtrl);
  1255.     el3c90xWait(pDrvCtrl);
  1256.     /* get the MAC address */
  1257.     for (ix = 0; ix < EA_SIZE; ix++)
  1258.         {
  1259.         el3c90xCsrWriteByte (pDrvCtrl, EL_W2_STATION_ADDR_LO + ix,
  1260.                              pDrvCtrl->enetAddr [ix], EL_WIN_2);
  1261. }
  1262.     /* clear the station mask */
  1263.     for (ix = 0; ix < 3; ix++)
  1264.         el3c90xCsrWriteWord (pDrvCtrl, EL_W2_STATION_MASK_LO + (ix * 2), 0,
  1265.                              EL_WIN_2);
  1266.     /* reset TX and RX */
  1267.     el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_RX_RESET, NONE);
  1268.     el3c90xWait(pDrvCtrl);
  1269.     el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_TX_RESET, NONE);
  1270.     el3c90xWait(pDrvCtrl);
  1271.     /* init circular upload descriptor list */
  1272.     
  1273.     if (el3c90xUpdInit(pDrvCtrl) == ENOBUFS)
  1274.         {
  1275.         DRV_LOG (DRV_DEBUG_LOAD, "elPci%d: initialization failed: no "
  1276.                "memory for rx buffersn", pDrvCtrl->unit, 2, 3, 4, 5, 6);
  1277.         el3c90xDevStop(pDrvCtrl);
  1278.         return;
  1279. }
  1280.     /* init download descriptors list */
  1281.     el3c90xDndInit(pDrvCtrl);
  1282.     /*
  1283.      * set the TX freethresh value.
  1284.      * note that this has no effect on 3c905B "cyclone"
  1285.      * cards but is required for 3c900/3c905 "boomerang"
  1286.      * cards in order to enable the download engine.
  1287.      */
  1288.     el3c90xCsrWriteByte (pDrvCtrl, EL_TX_FREETHRESH, (EL3C90X_BUFSIZ >> 8),
  1289.                          NONE);
  1290.     /*
  1291.      * If this is a 3c905B, also set the tx reclaim threshold.
  1292.      * This helps cut down on the number of tx reclaim errors
  1293.      * that could happen on a busy network. The chip multiplies
  1294.      * the register value by 16 to obtain the actual threshold
  1295.      * in bytes, so we divide by 16 when setting the value here.
  1296.      * The existing threshold value can be examined by reading
  1297.      * the register at offset 9 in window 5.
  1298.      */
  1299.     if (pDrvCtrl->devType == EL_TYPE_905B)
  1300.         {
  1301.         el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND,
  1302.                              (EL_CMD_SET_TX_RECLAIM | (EL3C90X_BUFSIZ >> 4)),
  1303.                              NONE);
  1304.         }
  1305.     /* set RX filter bits. */
  1306.     rxFilt = el3c90xCsrReadByte (pDrvCtrl, EL_W5_RX_FILTER, EL_WIN_5);
  1307.     /* set the individual bit to receive frames for this host only. */
  1308.     rxFilt |= EL_RXFILTER_INDIVIDUAL;
  1309.     flags = END_FLAGS_GET (&pDrvCtrl->endObj);
  1310.     /* if we want promiscuous mode, set the allframes bit. */
  1311.     if (flags & IFF_PROMISC)
  1312.         {
  1313.         rxFilt |= EL_RXFILTER_ALLFRAMES;
  1314.         el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND,
  1315.                              (EL_CMD_RX_SET_FILT | rxFilt), NONE);
  1316. }
  1317.     else
  1318.         {
  1319.         rxFilt &= ~EL_RXFILTER_ALLFRAMES;
  1320.         el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND,
  1321.                              (EL_CMD_RX_SET_FILT | rxFilt), NONE);
  1322. }
  1323.     /* set capture broadcast bit to capture broadcast frames. */
  1324.     if (flags & IFF_BROADCAST)
  1325.         {
  1326.         rxFilt |= EL_RXFILTER_BROADCAST;
  1327.         el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND,
  1328.                              (EL_CMD_RX_SET_FILT | rxFilt), NONE);
  1329. }
  1330.     else
  1331.         {
  1332.         rxFilt &= ~EL_RXFILTER_BROADCAST;
  1333.         el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND,
  1334.                              (EL_CMD_RX_SET_FILT | rxFilt), NONE);
  1335. }
  1336.     /* set the multicast filter etc */
  1337.         
  1338.     el3c90xMcastConfig (pDrvCtrl);
  1339.     /*
  1340.      * load the upload descriptor pointer and start the upload engine
  1341.      * Note that we have to do this after any RX resets have completed
  1342.      * since the uplist register is cleared by a reset.
  1343.      */
  1344.     el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_UP_STALL, NONE);
  1345.     el3c90xWait(pDrvCtrl);
  1346.     el3c90xCsrWriteLong (pDrvCtrl, EL_UPLIST_PTR,
  1347.                          (UINT32) EL3C90X_CACHE_VIRT_TO_PHYS
  1348.                          (&pDrvCtrl->pDescBlk->rxDescs[0]), NONE);
  1349.     el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_UP_UNSTALL, NONE);
  1350.     /*
  1351.      * if the coax transceiver is on, make sure to enable the DC-DC converter.
  1352.      */
  1353.     if (pDrvCtrl->xCvr == EL_XCVR_COAX)
  1354.         el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_COAX_START, NONE);
  1355.     else
  1356.         el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_COAX_STOP, NONE);
  1357.     /* Clear out the stats counters. */
  1358.     el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_STATS_DISABLE, NONE);
  1359.     el3c90xStatUpdate(pDrvCtrl);
  1360.     el3c90xCsrWriteWord (pDrvCtrl, EL_W4_NET_DIAG,
  1361.                          EL_NETDIAG_UPPER_BYTES_ENABLE, EL_WIN_4);
  1362.     el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_STATS_ENABLE, NONE);
  1363.     /* enable device interrupts */
  1364.     el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_INTR_ACK|0xFF, NONE);
  1365.     el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_STAT_ENB|EL_INTRS, NONE);
  1366.     el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_INTR_ENB|EL_INTRS, NONE);
  1367.     /* Set the RX early threshold */
  1368.     el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND,
  1369.                          (EL_CMD_RX_SET_THRESH | (EL3C90X_BUFSIZ >>2)), NONE);
  1370.     el3c90xCsrWriteWord (pDrvCtrl, EL_DMACTL, EL_DMACTL_UP_RX_EARLY, NONE);
  1371.     /* Enable receiver and transmitter. */
  1372.     el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_RX_ENABLE, NONE);
  1373.     el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_TX_ENABLE, NONE);
  1374.     /* Restore state of BMCR */
  1375.     if (pDrvCtrl->pPhyDevType != NULL)
  1376.         el3c90xPhyRegWrite(pDrvCtrl, PHY_BMCR, phyBMCR);
  1377.     return;
  1378.     }
  1379. /*******************************************************************************
  1380. *
  1381. * el3c90xMemInit - initialize memory for the device
  1382. *
  1383. * This function initiailizes memory for the device
  1384. *
  1385. * RETURNS: OK or ERROR
  1386. *
  1387. */
  1388. LOCAL STATUS el3c90xMemInit
  1389.     (
  1390.     EL3C90X_DEVICE *  pDrvCtrl /* device to be initialized */
  1391.     )
  1392.     {
  1393.     int memSize = 0;
  1394.     memSize += (sizeof(EL_DESC_BLK) + 16);
  1395.     if (pDrvCtrl->bufMtplr == NONE)
  1396.         pDrvCtrl->bufMtplr = 2;
  1397.     else if (pDrvCtrl->bufMtplr <= 0)
  1398.             printf ( "elPci: invalid buffer multipliern");
  1399.     
  1400.     pDrvCtrl->clDesc.clNum  = (EL_UPD_CNT + EL_DND_CNT) * pDrvCtrl->bufMtplr;
  1401.     pDrvCtrl->mClCfg.clBlkNum = pDrvCtrl->clDesc.clNum;
  1402.     pDrvCtrl->mClCfg.mBlkNum  = pDrvCtrl->mClCfg.clBlkNum * 2;
  1403.     /* total memory size for mBlks and clBlks */
  1404.     
  1405.     pDrvCtrl->mClCfg.memSize =
  1406.         (pDrvCtrl->mClCfg.mBlkNum  *  (MSIZE + sizeof (long))) +
  1407.         (pDrvCtrl->mClCfg.clBlkNum * (CL_BLK_SZ + sizeof (long)));
  1408.     memSize += pDrvCtrl->mClCfg.memSize;
  1409.     /* total memory size for all clusters */
  1410.     pDrvCtrl->clDesc.clSize  = EL3C90X_BUFSIZ;
  1411.     pDrvCtrl->clDesc.memSize =
  1412.         (pDrvCtrl->clDesc.clNum * (pDrvCtrl->clDesc.clSize + 8)) + sizeof(int);
  1413.     memSize += pDrvCtrl->clDesc.memSize;
  1414.     if ((int)pDrvCtrl->memAdrs != NONE)
  1415.         {
  1416.         /* check if the give memory size if enough */
  1417.         if (pDrvCtrl->memSize < memSize)
  1418.             {
  1419.             printf ( "elPci: memory size too smalln" );
  1420.             return (ERROR);
  1421.             }
  1422.         pDrvCtrl->pDescMem = (char *)pDrvCtrl->memAdrs;
  1423.         pDrvCtrl->mClCfg.memArea = (char *)((UINT32)(pDrvCtrl->pDescMem) +
  1424.                                             sizeof(EL_DESC_BLK) + 16);
  1425.         pDrvCtrl->clDesc.memArea = (pDrvCtrl->mClCfg.memArea +
  1426.                                     pDrvCtrl->mClCfg.memSize);
  1427.         /* assume pool is cache coherent, copy null structure */
  1428.         pDrvCtrl->cacheFuncs = cacheNullFuncs;
  1429.         DRV_LOG (DRV_DEBUG_LOAD, "Memory checks outn", 1, 2, 3, 4, 5, 6);
  1430.         }
  1431.     else /* allocate our own memory */
  1432.         {
  1433.         pDrvCtrl->flags |= EL_MEM_ALLOC_FLAG;
  1434.         if (!CACHE_DMA_IS_WRITE_COHERENT ())
  1435.             {
  1436.             printf ( "elPci: device requires cache coherent memoryn" );
  1437.             return (ERROR);
  1438.             }
  1439.         
  1440.         /* allocate memory for upload and download descriptors */
  1441.         pDrvCtrl->pDescMem =
  1442.             (char *) cacheDmaMalloc (sizeof(EL_DESC_BLK) + 16);
  1443.         if (pDrvCtrl->pDescMem == NULL)
  1444.             {
  1445.             printf ( "elPci: system memory unavailablen" );
  1446.             return (ERROR);
  1447.             }
  1448.         /* allocate memory for mBlks and clBlks */
  1449.         if ((pDrvCtrl->mClCfg.memArea =
  1450.              (char *) memalign (sizeof(long), pDrvCtrl->mClCfg.memSize))
  1451.             == NULL)
  1452.             {
  1453.             printf ( "elPci: system memory unavailablen" );
  1454.             goto elMemInitFail;
  1455.             }
  1456.         /* allocate memory for clusters */
  1457.         pDrvCtrl->clDesc.memArea = cacheDmaMalloc (pDrvCtrl->clDesc.memSize);
  1458.             
  1459.         if (pDrvCtrl->clDesc.memArea == NULL)
  1460.             {
  1461.             printf ( "elPci: system memory unavailablen" );
  1462.             goto elMemInitFail;
  1463.             }
  1464.         /* copy the DMA structure */
  1465.         pDrvCtrl->cacheFuncs = cacheDmaFuncs;
  1466.         }
  1467.     pDrvCtrl->pDescBlk = (EL_DESC_BLK *)(((int)pDrvCtrl->pDescMem
  1468.                                                   + 0x0f) & ~0x0f);
  1469.     bzero ((char*)pDrvCtrl->pDescBlk, sizeof(EL_DESC_BLK));
  1470.     /* allocate memory for net pool */
  1471.     
  1472.     if ((pDrvCtrl->endObj.pNetPool = malloc (sizeof(NET_POOL))) == NULL)
  1473.         {
  1474.         printf ( "elPci: system memory unavailablen" );
  1475.         goto elMemInitFail;
  1476.         }
  1477. #ifdef DRV_DEBUG
  1478.     pElXlPool = pDrvCtrl->endObj.pNetPool;
  1479. #endif
  1480.     
  1481.     /* initialize the device net pool */
  1482.     
  1483.     if (netPoolInit (pDrvCtrl->endObj.pNetPool, &pDrvCtrl->mClCfg,
  1484.                      &pDrvCtrl->clDesc, 1, NULL) == ERROR)
  1485.         {
  1486.         DRV_LOG (DRV_DEBUG_LOAD, "Could not init bufferingn",
  1487.                  1, 2, 3, 4, 5, 6);
  1488.         goto elMemInitFail;
  1489.         }
  1490.     
  1491.     /* Store the cluster pool id as others need it later. */
  1492.     pDrvCtrl->pClPoolId = clPoolIdGet (pDrvCtrl->endObj.pNetPool,
  1493.                                        EL3C90X_BUFSIZ, FALSE);
  1494.     return (OK);
  1495.     elMemInitFail:
  1496.         {
  1497.         if (pDrvCtrl->flags & EL_MEM_ALLOC_FLAG)
  1498.             {
  1499.             /* free the memory allocated for descriptors */
  1500.         
  1501.             if (pDrvCtrl->pDescMem != NULL)
  1502.                 cacheDmaFree (pDrvCtrl->pDescMem);
  1503.             /* Free the memory allocated for mBlks and clBlks */
  1504.             if (pDrvCtrl->mClCfg.memArea != NULL)
  1505.                 free (pDrvCtrl->mClCfg.memArea);
  1506.             /* free the memory allocated for clusters */
  1507.             if (pDrvCtrl->clDesc.memArea != NULL)
  1508.                 cacheDmaFree (pDrvCtrl->clDesc.memArea);
  1509.             }
  1510.         if (pDrvCtrl->endObj.pNetPool != NULL)
  1511.             free (pDrvCtrl->endObj.pNetPool);
  1512.         return (ERROR);
  1513.         }
  1514.     }
  1515. /*******************************************************************************
  1516. *
  1517. * el3c90xDevStop - stop the device
  1518. *
  1519. * This function stops the adapter and frees up any M_BLKS allocated to the
  1520. * upload and download descriptors.
  1521. *
  1522. * RETURNS: N/A
  1523. */
  1524. LOCAL void el3c90xDevStop
  1525.     (
  1526.     EL3C90X_DEVICE *  pDrvCtrl /* pointer to the device control structure */
  1527.     )
  1528.     {
  1529.     register int ix;
  1530.     el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_RX_DISABLE, NONE);
  1531.     el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_STATS_DISABLE, NONE);
  1532.     el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_INTR_ENB, NONE);
  1533.     el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_RX_DISCARD, NONE);
  1534.     el3c90xWait(pDrvCtrl);
  1535.     el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_TX_DISABLE, NONE);
  1536.     el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_COAX_STOP, NONE);
  1537.     el3c90xWait(pDrvCtrl);
  1538.     el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_RX_RESET, NONE);
  1539.     el3c90xWait(pDrvCtrl);
  1540.     el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_TX_RESET, NONE);
  1541.     el3c90xWait(pDrvCtrl);
  1542.     el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND,
  1543.                          (EL_CMD_INTR_ACK | EL_STAT_INTLATCH), NONE);
  1544.     /* free the mblks in the upload descriptor lists */
  1545.     
  1546.     for (ix = 0; ix < EL_UPD_CNT; ix++)
  1547.         {
  1548.         if (pDrvCtrl->rxTxChain.rxChain [ix].pMblk != NULL)
  1549.             {
  1550.             netMblkClChainFree(pDrvCtrl->rxTxChain.rxChain [ix].pMblk);
  1551.             pDrvCtrl->rxTxChain.rxChain [ix].pMblk = NULL;
  1552.             }
  1553. }
  1554.     bzero ((char *)&pDrvCtrl->pDescBlk->rxDescs,
  1555.            sizeof(pDrvCtrl->pDescBlk->rxDescs));
  1556.     /* free the download descriptors */
  1557.     for (ix = 0; ix < EL_DND_CNT; ix++)
  1558.         {
  1559.         if (pDrvCtrl->rxTxChain.txChain [ix].pMblk != NULL)
  1560.             {
  1561.             netMblkClChainFree(pDrvCtrl->rxTxChain.txChain[ix].pMblk);
  1562.             pDrvCtrl->rxTxChain.txChain [ix].pMblk = NULL;
  1563.             }
  1564. }
  1565.     bzero ((char *)&pDrvCtrl->pDescBlk->txDescs,
  1566.            sizeof(pDrvCtrl->pDescBlk->txDescs));
  1567.     return;
  1568.     }
  1569. /*******************************************************************************
  1570. *
  1571. * el3c90xReset - reset  the device
  1572. *
  1573. * This function call resets the device completely
  1574. *
  1575. * RETURNS: N/A
  1576. */
  1577. LOCAL void el3c90xReset
  1578.     (
  1579.     EL3C90X_DEVICE * pDrvCtrl
  1580.     )
  1581.     {
  1582.     /* issue the reset command */
  1583.     
  1584.     el3c90xCsrWriteWord(pDrvCtrl, EL_COMMAND, EL_CMD_RESET, EL_WIN_0);
  1585.     el3c90xWait(pDrvCtrl); /* wait for the command to complete */
  1586.     /* wait for a while */
  1587.     SYS_DELAY(1000);
  1588.     return;
  1589.     }
  1590. /*******************************************************************************
  1591. *
  1592. * el3c90xIntEnable - enable board to cause interrupts
  1593. *
  1594. * Because the board has maskable status, this routine can simply set the
  1595. * mask to all ones.  We set all the bits symbolically; the effect is the
  1596. * same.  Note that the interrupt latch is not maskable; if none of the other
  1597. * mask bits are set, no interrupts will occur at all.  Only those interrupts
  1598. * whose status bits are enabled will actually occur.  Note that the "intMask"
  1599. * field in the device control structure is really the status mask.
  1600. *
  1601. * RETURNS: N/A.
  1602. */
  1603. LOCAL void el3c90xIntEnable
  1604.     (
  1605.     EL3C90X_DEVICE * pDrvCtrl /* device structure */
  1606.     )
  1607.     {
  1608.     UINT16  status;
  1609.     status = el3c90xCsrReadWord (pDrvCtrl, EL_STATUS, NONE);
  1610.     status &= 0x00ff;
  1611.     el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, (EL_CMD_INTR_ACK | status),
  1612.                          NONE);
  1613.     el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, (EL_CMD_INTR_ENB | EL_INTRS),
  1614.                          NONE);
  1615.     }
  1616. /*******************************************************************************
  1617. *
  1618. * el3c90xIntDisable - prevent board from causing interrupts
  1619. *
  1620. * This routine simply sets all the interrupt mask bits to zero.
  1621. * It is intended for guarding board-critical sections.
  1622. *
  1623. * RETURNS: N/A.
  1624. */
  1625. LOCAL void el3c90xIntDisable
  1626.     (
  1627.     EL3C90X_DEVICE * pDrvCtrl /* device structure */
  1628.     )
  1629.     {
  1630.     UINT16  status;
  1631.     el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, EL_CMD_INTR_ENB, NONE);
  1632.     status = el3c90xCsrReadWord (pDrvCtrl, EL_STATUS, NONE);
  1633.     status &= 0x00ff;
  1634.     el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, (EL_CMD_INTR_ACK | status),
  1635.                          NONE);
  1636.     }
  1637. /*******************************************************************************
  1638. *
  1639. * el3c90xPollStart - start polled mode operations
  1640. *
  1641. * This function starts polled mode operation.
  1642. *
  1643. * The device interrupts are disabled, the current mode flag is switched
  1644. * to indicate Polled mode and the device is reconfigured.
  1645. *
  1646. * RETURNS: OK or ERROR.
  1647. */
  1648. LOCAL STATUS el3c90xPollStart
  1649.     (
  1650.     EL3C90X_DEVICE * pDrvCtrl /* device to be polled */
  1651.     )
  1652.     {
  1653.     int         oldLevel;
  1654.     
  1655.     oldLevel = intLock ();          /* disable ints during update */
  1656.     pDrvCtrl->flags |= EL_POLLING;
  1657.     intUnlock (oldLevel);   /* now el3c90xInt won't get confused */
  1658.     el3c90xIntDisable (pDrvCtrl);
  1659.     ENDLOGMSG (("STARTEDn", 1, 2, 3, 4, 5, 6));
  1660.     return (OK);
  1661.     }
  1662. /*******************************************************************************
  1663. *
  1664. * el3c90xPollStop - stop polled mode operations
  1665. *
  1666. * This function terminates polled mode operation.  The device returns to
  1667. * interrupt mode.
  1668. *
  1669. * The device interrupts are enabled, the current mode flag is switched
  1670. * to indicate interrupt mode and the device is then reconfigured for
  1671. * interrupt operation.
  1672. *
  1673. * RETURNS: OK or ERROR.
  1674. */
  1675. LOCAL STATUS el3c90xPollStop
  1676.     (
  1677.     EL3C90X_DEVICE * pDrvCtrl /* device structure */
  1678.     )
  1679.     {
  1680.     int         oldLevel;
  1681.     oldLevel = intLock (); /* disable ints during register updates */
  1682.     pDrvCtrl->flags &= ~EL_POLLING;
  1683.     intUnlock (oldLevel);
  1684.     el3c90xIntEnable (pDrvCtrl);
  1685.     ENDLOGMSG (("STOPPEDn", 1, 2, 3, 4, 5, 6));
  1686.     return (OK);
  1687.     }
  1688. /*******************************************************************************
  1689. *
  1690. * el3c90xUpdInit - initialize the upload descriptor list
  1691. *
  1692. * This function initializes the upload descriptors and allocates M_BLKs for
  1693. * them. Note that we arrange the descriptors in a closed ring, so that the
  1694. * last descriptor points back to the first.
  1695. *
  1696. * RETURNS: OK or ENOBUFS
  1697. */
  1698. LOCAL int el3c90xUpdInit
  1699.     (
  1700.     EL3C90X_DEVICE * pDrvCtrl /* pointer to the device control structure */
  1701.     )
  1702.     {
  1703.     EL_RX_TX_CHAIN * pRxTxChain;
  1704.     EL_DESC_BLK * pDescBlk;
  1705.     int ix;
  1706.     pRxTxChain = &pDrvCtrl->rxTxChain;
  1707.     pDescBlk = pDrvCtrl->pDescBlk;
  1708.     for (ix = 0; ix < EL_UPD_CNT; ix++)
  1709.         {
  1710.         pRxTxChain->rxChain [ix].pDesc =
  1711.             (EL_SIMPLE_DESC *)&pDescBlk->rxDescs [ix];
  1712.         if (el3c90xUpdFill(pDrvCtrl, &pRxTxChain->rxChain [ix]) == ENOBUFS)
  1713.             return(ENOBUFS);
  1714.         
  1715.         if (ix == (EL_UPD_CNT - 1))
  1716.             {
  1717.             pRxTxChain->rxChain [ix].pNextChain = &pRxTxChain->rxChain [0];
  1718.             pDescBlk->rxDescs [ix].nextDesc =
  1719.                 PCI_SWAP
  1720.                 (
  1721.                 (UINT32)EL3C90X_CACHE_VIRT_TO_PHYS (&pDescBlk->rxDescs [0])
  1722.                 );
  1723.             }
  1724.         else
  1725.             {
  1726.             pRxTxChain->rxChain [ix].pNextChain =
  1727.                 &pRxTxChain->rxChain [ix + 1];
  1728.             pDescBlk->rxDescs [ix].nextDesc =
  1729.                 PCI_SWAP((UINT32)EL3C90X_CACHE_VIRT_TO_PHYS
  1730.                          (&pDescBlk->rxDescs [ix + 1]));
  1731.             }
  1732. }
  1733.     pRxTxChain->pRxHead = &pRxTxChain->rxChain [0];
  1734.     return (OK);
  1735.     }
  1736. /*******************************************************************************
  1737. *
  1738. * el3c90xDndInit - initialize the download descriptor list
  1739. *
  1740. * This function initializes the download descriptor list
  1741. *
  1742. * RETURNS: OK
  1743. */
  1744. LOCAL int el3c90xDndInit
  1745.     (
  1746.     EL3C90X_DEVICE * pDrvCtrl /* pointer to the device control structure */
  1747.     )
  1748.     {
  1749.     EL_RX_TX_CHAIN * pRxTxChain;
  1750.     EL_DESC_BLK * pDescBlk;
  1751.     int ix;
  1752.     pRxTxChain = &pDrvCtrl->rxTxChain;
  1753.     pDescBlk = pDrvCtrl->pDescBlk;
  1754.     
  1755.     for (ix = 0; ix < EL_DND_CNT; ix++)
  1756.         {
  1757.         pRxTxChain->txChain [ix].pDesc = &pDescBlk->txDescs [ix];
  1758.         if (ix == (EL_DND_CNT - 1))
  1759.             pRxTxChain->txChain [ix].pNextChain = NULL;
  1760.         else
  1761.             pRxTxChain->txChain[ix].pNextChain = &pRxTxChain->txChain [ix + 1];
  1762. }
  1763.     pRxTxChain->pTxFree = &pRxTxChain->txChain [0];
  1764.     pRxTxChain->pTxTail = pRxTxChain->pTxHead = NULL;
  1765.     return(0);
  1766.     }
  1767. /*******************************************************************************
  1768. *
  1769. * el3c90xHashGet - get a hash filter bit position
  1770. *
  1771. * This routine is taken from the 3Com Etherlink XL manual,
  1772. * chapter 10 pg 156. It calculates a CRC of the supplied multicast
  1773. * group address and returns the lower 8 bits, which are used
  1774. * as the multicast filter position.
  1775. * Note: the 3c905B currently only supports a 64-bit hash table,
  1776. * which means we really only need 6 bits, but the manual indicates
  1777. * that future chip revisions will have a 256-bit hash table,
  1778. * hence the routine is set up to calculate 8 bits of position
  1779. * info in case we need it some day.
  1780. * Note II, The Sequel: _CURRENT_ versions of the 3c905B have a
  1781. * 256 bit hash table. This means we have to use all 8 bits regardless.
  1782. * On older cards, the upper 2 bits will be ignored. Grrrr....
  1783. *
  1784. * RETURNS: filter bit position
  1785. */
  1786. LOCAL UINT8 el3c90xHashGet
  1787.     (
  1788.     char *  addr
  1789.     )
  1790.     {
  1791.     UINT32 crc;
  1792.     UINT32 carry;
  1793.     int ix;
  1794.     int jx;
  1795.     UINT8 ch;
  1796.     /* Compute CRC for the address value. */
  1797.     crc = 0xFFFFFFFF; /* initial value */
  1798.     for (ix = 0; ix < 6; ix++)
  1799.         {
  1800.         ch = *(addr + ix);
  1801.         for (jx = 0; jx < 8; jx++)
  1802.             {
  1803.             carry = ((crc & 0x80000000) ? 1 : 0) ^ (ch & 0x01);
  1804.             crc <<= 1;
  1805.             ch >>= 1;
  1806.             if (carry)
  1807.                 crc = (crc ^ 0x04c11db6) | carry;
  1808.             }
  1809.         }
  1810.     /* return the filter bit position */
  1811.     return (crc & 0x000000FF);
  1812.     }
  1813. /*******************************************************************************
  1814. *
  1815. * el3c90xFilterSet - set the multicast filter
  1816. *
  1817. * NICs older than the 3c905B have only one multicast option, which
  1818. * is to enable reception of all multicast frames.
  1819. *
  1820. * RETURNS: N/A
  1821. */
  1822. LOCAL void el3c90xFilterSet
  1823.     (
  1824.     EL3C90X_DEVICE * pDrvCtrl /* device to be re-configured */
  1825.     )
  1826.     {
  1827.     UINT8 rxFilt;
  1828.     rxFilt = el3c90xCsrReadByte(pDrvCtrl, EL_W5_RX_FILTER, EL_WIN_5);
  1829.     if (END_FLAGS_GET (&pDrvCtrl->endObj) & IFF_ALLMULTI)
  1830.         {
  1831.         rxFilt |= EL_RXFILTER_ALLMULTI;
  1832.         el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND,
  1833.                              (EL_CMD_RX_SET_FILT | rxFilt), NONE);
  1834.         return;
  1835.         }
  1836.     /* Set up address filter for multicasting. 
  1837.      * Multicast bit is set if the address list has one or more entries
  1838.      * Multicasting is disabled if the address list is empty
  1839.      */
  1840.     if (END_MULTI_LST_CNT (&pDrvCtrl->endObj) > 0)
  1841. {
  1842. ENDLOGMSG (("Setting multicast mode on!n", 1, 2, 3, 4, 5, 6));
  1843.         rxFilt |= EL_RXFILTER_ALLMULTI;
  1844. }
  1845.     else
  1846. {
  1847. ENDLOGMSG (("Setting multcast mode off!n", 1, 2, 3, 4, 5, 6));
  1848.         rxFilt &= ~EL_RXFILTER_ALLMULTI;
  1849. }
  1850.     el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND,
  1851.                          (EL_CMD_RX_SET_FILT | rxFilt), NONE);
  1852.     return;
  1853.     }
  1854. /*******************************************************************************
  1855. *
  1856. * el3c90xHashFilterSet - set the hash filter for 3c90xB adapters.
  1857. *
  1858. * This function programs the hash fileter for the 3c905B adapters.
  1859. *
  1860. * RETURNS: N/A
  1861. */
  1862. LOCAL void el3c90xHashFilterSet
  1863.     (
  1864.     EL3C90X_DEVICE * pDrvCtrl /* device to be re-configured */
  1865.     )
  1866.     {
  1867.     ETHER_MULTI *  pCurr;
  1868.     UINT8 rxFilt;
  1869.     int ix;
  1870.     int hash = 0;
  1871.     int mcnt = 0;
  1872.     rxFilt = el3c90xCsrReadByte(pDrvCtrl, EL_W5_RX_FILTER, EL_WIN_5);
  1873.     if (END_FLAGS_GET (&pDrvCtrl->endObj) & IFF_ALLMULTI)
  1874.         {
  1875.         rxFilt |= EL_RXFILTER_ALLMULTI;
  1876.         el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND,
  1877.                              (EL_CMD_RX_SET_FILT | rxFilt), NONE);
  1878.         return;
  1879.         }
  1880.     else
  1881.         rxFilt &= ~EL_RXFILTER_ALLMULTI;
  1882.     /* first, zot all the existing hash bits */
  1883.     for (ix = 0; ix < EL_HASHFILT_SIZE; ix++)
  1884.         el3c90xCsrWriteWord (pDrvCtrl, EL_COMMAND, (EL_CMD_RX_SET_HASH | ix),
  1885.                              NONE);