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

VxWorks

开发平台:

C/C++

  1. /* motCpmEnd.c - END style Motorola MC68EN360/MPC800 network interface driver */
  2. /* Copyright 1997-2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 02e,11apr02,rcs  increased clusters, mBlks, clBlks and ring size (SPR# 75471)
  8. 02d,01aug00,stv  allocated END_CTRL structure from heap (SPR# 32775).
  9. 02c,20jun00,stv  fixed the setting of maxd1 & maxd2 registers (SPR# 31197).  
  10. 02b,11jun00,ham  removed reference to etherLib.
  11. 02a,26may00,stv  fixed the packet data length in motCpmEndPollReceive() routine,
  12.  (SPR 31218).
  13. 01z,27jan00,dat  fixed use of NULL
  14. 01y,01dec99,stv  freed mBlk chain before returning ERROR (SPR #28492).
  15. 01x,29mar99,dat  SPR 26119, documentation, usage of .bS/.bE
  16. 01w,26nov98,dbt  removed splimp() and splx() calls in motCmpEndIoctl
  17.  (SPR #23528). Added a missing netMblkClChainFree() call.
  18. 01v,22sep98,dat  added Didier's fix for system-mode transitions. (SPR 22325)
  19.  removed warnings.
  20. 01u,09sep98,n_s  removed promiscous mode filter from motCpmEndPollReceive (). 
  21.                  spr 21143.
  22. 01t,28aug98,dat  chg'd all names from motCmp to motCpm.
  23. 01s,21aug98,n_s  removed promiscous mode filter from motCmpRecv (). spr 21143.
  24. 01r,30jun98,cn   changed include file motCmpEnd.h to motCpmEnd.h
  25. 01q,22jun98,cn   added support for PPC800-series Ethernet Controller.
  26. 01p,11dec97,kbw  making man page edits
  27. 01o,08dec97,gnn  END code review fixes.
  28. 01n,19oct97,vin  moved swapping of loaned buffer before END_RCV_RTN_CALL
  29. 01m,17oct97,vin  removed extra free.
  30. 01l,07oct97,vin  MTU size to ETHER_MTU.
  31. 01k,03oct97,gnn  fixed SPR 8988, memory leak
  32. 01j,25sep97,gnn  SENS beta feedback fixes
  33. 01i,24sep97,vin  added clBlk related calls
  34. 01h,03sep97,gnn  fixed a crashing bug under heavy load
  35. 01g,25aug97,gnn  changes due to new netPool routines.
  36. 01f,22aug97,gnn  changes due to new buffering scheme.
  37. 01e,12aug97,gnn  changes necessitated by MUX/END update.
  38. 01d,15may97,map  fixed intr event ack (scce) handling (SPR# 8580).
  39. 01c,18apr97,gnn  fixed a bug in the receive code.
  40. 01b,09apr97,gnn  updated buffer handling code to follow new MUX level
  41.                  requirements.
  42. 01a,15feb97,dbt  modified if_qu.c to END style.
  43. */
  44. /*
  45. This module implements the Motorola MC68EN360 QUICC as well as the MPC821 and
  46. MPC860 Power-QUICC Ethernet Enhanced network interface driver.
  47. All the above mentioned microprocessors feature a number of Serial 
  48. Communication Controllers (SCC) that support different serial protocols
  49. including IEEE 802.3 and Ethernet CSMA-CD. As a result, when the Ethernet
  50. mode of a SCC is selected, by properly programming its general Mode Register
  51. (GSMR), they can implement the full set of media access control and channel
  52. interface functions those protocol require. However, while the MC68EN360 
  53. QUICC and the MPC860 Power-QUICC support up to four SCCs per unit, the 
  54. MPC821 only includes two on-chip SCCs.
  55. This driver is designed to support the Ethernet mode of a SCC residing on the
  56. CPM processor core, no matter which among the MC68EN360 QUICC or any of the 
  57. PPC800 Series. In fact, the major differences among these processors, as far
  58. as the driver is concerned, are to be found in the mapping of the internal 
  59. Dual-Port RAM. The driver is generic in the sense that it does not care
  60. which SCC is being used. In addition, it poses no constraint on the number 
  61. of individual units that may be used per board. However, this number should
  62. be specified in the bsp through the macro MAX_SCC_CHANNELS. The default value
  63. for this macro in the driver is 4.
  64. To achieve these goals, the driver requires several target-specific values
  65. provided as an input string to the load routine. It also requires some 
  66. external support routines.  These target-specific values and the external 
  67. support routines are described below.
  68. This network interface driver does not include support for trailer protocols
  69. or data chaining.  However, buffer loaning has been implemented in an effort 
  70. to boost performance. 
  71. This driver maintains cache coherency by allocating buffer space using 
  72. the cacheDmaMalloc() routine.  This is provided for boards whose host
  73. processor use data cache space, e.g. the MPC800 Series. Altough the 
  74. MC68EN360 does not have cache memory, it may be used in a particular 
  75. configuration: 'MC68EN360 in 040 companion mode' where that is attached
  76. to processors that may cache memory. However, due to a lack of suitable 
  77. hardware, the multiple unit support and '040 companion mode support have 
  78. not been tested.
  79. BOARD LAYOUT
  80. This device is on-chip.  No jumpering diagram is necessary.
  81. EXTERNAL INTERFACE
  82. This driver provides the standard END external interface.  The only external 
  83. interface is the motCpmEndLoad() routine.  The parameters are passed 
  84. into the motCpmEndLoad() function as a single colon-delimited string.
  85. The motCpmEndLoad() function uses strtok() to parse the string, which it 
  86. expects to be of the following format:
  87. <unit>:<motCpmAddr>:<ivec>:<sccNum>:<txBdNum>:<rxBdNum>:
  88. <txBdBase>: <rxBdBase>:<bufBase> 
  89. TARGET-SPECIFIC PARAMETERS
  90. .IP <unit>
  91. A convenient holdover from the former model.  This parameter is used only
  92. in the string name for the driver.
  93. .IP <motCpmAddr>
  94. Indicates the address at which the host processor presents its internal 
  95. memory (also known as the dual ported RAM base address). With this address, 
  96. and the SCC number (see below), the driver is able to compute the location 
  97. of the SCC parameter RAM and the SCC register map, and, ultimately, to 
  98. program the SCC for proper operations. This parameter should point to the 
  99. internal memory of the processor where the SCC physically resides. This 
  100. location might not necessarily be the Dual-Port RAM of the microprocessor 
  101. configured as master on the target board.
  102. .IP <ivec>
  103. This driver configures the host processor to generate hardware interrupts
  104. for various events within the device. The interrupt-vector offset
  105. parameter is used to connect the driver's ISR to the interrupt through
  106. a call to the VxWorks system function intConnect().
  107. .IP <sccNum>
  108. This driver is written to support multiple individual device units.
  109. Thus, the multiple units supported by this driver can reside on different 
  110. chips or on different SCCs within a single host processor. This parameter 
  111. is used to explicitly state which SCC is being used (SCC1 is most commonly 
  112. used, thus this parameter most often equals "1").
  113. .IP "<txBdNum> and <rxBdNum>"
  114. Specify the number of transmit and receive buffer descriptors (BDs). 
  115. Each buffer descriptor resides in 8 bytes of the processor's dual-ported 
  116. RAM space, and each one points to a 1520 byte buffer in regular RAM.  
  117. There must be a minimum of two transmit and two receive BDs. There is 
  118. no maximum, although more than a certain amount does not speed up the 
  119. driver and wastes valuable dual-ported RAM space. If any of these parameters
  120. is "NULL", a default value of "32" BDs is used.
  121. .IP "<txBdBase> and <rxBdBase>"
  122. Indicate the base location of the transmit and receive buffer descriptors 
  123. (BDs). They are offsets, in bytes, from the base address of the host
  124. processor's internal memory (see above). Each BD takes up 8 bytes of
  125. dual-ported RAM, and it is the user's responsibility to ensure that all
  126. specified BDs fit within dual-ported RAM. This includes any other
  127. BDs the target board might be using, including other SCCs, SMCs, and the
  128. SPI device. There is no default for these parameters.  They must be
  129. provided by the user.
  130. .IP <bufBase> 
  131. Tells the driver that space for the transmit and receive buffers need not 
  132. be allocated but should be taken from a cache-coherent private memory space 
  133. provided by the user at the given address.  The user should be aware that 
  134. memory used for buffers must be 4-byte aligned and non-cacheable.  All the 
  135. buffers must fit in the given memory space.  No checking is performed.  
  136. This includes all transmit and receive buffers (see above).  Each buffer 
  137. is 1520 bytes.  If this parameter is "NONE", space for buffers is obtained 
  138. by calling cacheDmaMalloc() in motCpmEndLoad().
  139. .LP
  140. EXTERNAL SUPPORT REQUIREMENTS
  141. This driver requires three external support functions:
  142. .IP sysXxxEnetEnable()
  143. .LP
  144. This is either sys360EnetEnable() or sysCpmEnetEnable(), based on the 
  145. actual host processor being used. See below for the actual prototypes.
  146. This routine is expected to handle any target-specific functions needed 
  147. to enable the Ethernet controller. These functions typically include 
  148. enabling the Transmit Enable signal (TENA) and connecting the transmit 
  149. and receive clocks to the SCC. This routine is expected to return OK on 
  150. success, or ERROR. The driver calls this routine, once per unit, from the 
  151. motCpmEndLoad() routine.
  152. .IP sysXxxEnetDisable()
  153. .LP
  154. This is either sys360EnetDisable() or sysCpmEnetDisable(), based on the 
  155. actual host processor being used. See below for the actual prototypes.
  156. This routine is expected to handle any target-specific functions required 
  157. to disable the Ethernet controller. This usually involves disabling the 
  158. Transmit Enable (TENA) signal.  This routine is expected to return OK on 
  159. success, or ERROR. The driver calls this routine from the motCpmEndStop() 
  160. routine each time a unit is disabled.
  161. .IP sysXxxEnetAddrGet()
  162. .LP
  163. This is either sys360EnetAddrGet() or sysCpmEnetAddrGet(), based on the 
  164. actual host processor being used. See below for the actual prototypes.
  165. The driver expects this routine to provide the six-byte Ethernet hardware 
  166. address that is used by this unit.  This routine must copy the six-byte 
  167. address to the space provided by <addr>.  This routine is expected to 
  168. return OK on success, or ERROR.  The driver calls this routine, once per 
  169. unit, from the motCpmEndLoad() routine.
  170. .LP
  171. In the case of the CPU32, the prototypes of the above mentioned support
  172. routines are as follows:
  173. .CS
  174.     STATUS sys360EnetEnable (int unit, UINT32 regBase)
  175.     void sys360EnetDisable (int unit, UINT32 regBase)
  176.     STATUS sys360EnetAddrGet (int unit, u_char * addr)
  177. .CE
  178. .LP
  179. In the case of the PPC860, the prototypes of the above mentioned support
  180. routines are as follows:
  181. .CS
  182.     STATUS sysCpmEnetEnable (int unit)
  183.     void sysCpmEnetDisable (int unit)
  184.     STATUS sysCpmEnetAddrGet (int unit, UINT8 * addr)
  185. .CE
  186. .LP
  187. SYSTEM RESOURCE USAGE
  188. When implemented, this driver requires the following system resources:
  189.     - one mutual exclusion semaphore
  190.     - one interrupt vector
  191.     - 0 bytes in the initialized data section (data)
  192.     - 1272 bytes in the uninitialized data section (BSS)
  193.  
  194. The data and BSS sections are quoted for the CPU32 architecture and could
  195. vary for other architectures.  The code size (text) varies greatly between
  196. architectures, and is therefore not quoted here.
  197. If the driver allocates the memory to share with the Ethernet device unit,
  198. it does so by calling the cacheDmaMalloc() routine.  For the default case
  199. of 32 transmit buffers, 32 receive buffers, and 16 loaner buffers (this is not
  200. configurable), the total size requested is 121,600 bytes.  If a non-cacheable 
  201. memory region is provided by the user, the size of this region should be this 
  202. amount, unless the user has specified a different number of transmit or 
  203. receive BDs.
  204. This driver can operate only if this memory region is non-cacheable
  205. or if the hardware implements bus snooping.  The driver cannot maintain
  206. cache coherency for the device because the buffers are asynchronously
  207. modified by both the driver and the device, and these fields might share 
  208. the same cache line.  Additionally, the chip's dual-ported RAM must be
  209. declared as non-cacheable memory where applicable (for example, when attached
  210. to a 68040 processor). For more information, see the
  211. .I "Motorola MC68EN360 User's Manual",
  212. .I "Motorola MPC860 User's Manual",
  213. .I "Motorola MPC821 User's Manual"
  214. INTERNAL
  215. This driver contains conditional compilation switch DEBUG.
  216. If defined, adds debug output routines.  Output is further
  217. selectable at run-time via the motCpmDebug global variable.
  218. */
  219. /* includes */
  220. #include "vxWorks.h"
  221. #include "iv.h"
  222. #include "taskLib.h"
  223. #include "memLib.h"
  224. #include "ioctl.h"
  225. #include "net/mbuf.h"
  226. #include "net/protosw.h"
  227. #include "socket.h"
  228. #include "errno.h"
  229. #include "errnoLib.h"
  230. #include "net/unixLib.h"
  231. #include "net/route.h"
  232. #include "net/if_subr.h"
  233. #include "cacheLib.h"
  234. #include "stdio.h"
  235. #include "intLib.h"
  236. #include "logLib.h"
  237. #include "netLib.h"
  238. #include "iosLib.h"
  239. #include "drv/netif/netifDev.h"
  240. #include "drv/end/motCpmEnd.h"
  241. #include "net/if.h"
  242. #include "netinet/in.h"
  243. #include "netinet/in_systm.h"
  244. #include "netinet/in_var.h"
  245. #include "netinet/ip.h"
  246. #include "netinet/if_ether.h"
  247. #include "etherMultiLib.h"
  248. #include "end.h"
  249. #include "semLib.h"
  250. #undef END_MACROS
  251. #include "endLib.h"
  252. #include "lstLib.h"
  253. #include "netBufLib.h"
  254. /* defines */
  255. #define ENET_ADDR_SIZE 0x6 /* size of Ethernet src/dest addresses */
  256. #define TX_BD_MIN 2 /* minimum number of Tx buffer descriptors */
  257. #define TX_BD_MAX 128 /* maximum number of Tx buffer descriptors */
  258. #define RX_BD_MIN 2 /* minimum number of Rx buffer descriptors */
  259. #define TX_BD_DEFAULT 0x40 /* default number of Tx buffer descriptors */
  260. #define RX_BD_DEFAULT 0x40 /* default number of Rx buffer descriptors */
  261. #define FRAME_MAX 0x05ee /* maximum frame size */
  262. #define FRAME_MAX_AL 0x05f0 /* maximum frame size, 4 byte alligned */
  263. #define FRAME_MIN 0x0040 /* minimum frame size */
  264. #define LENGTH_MIN_FBUF 9 /* min. size of the first buffer in a frame */
  265. #define SPEED 10000000/* ethernet speed */
  266. #define L_POOL 0x80 /* number of Rx loaner buffers in pool */
  267. /* A shortcut for getting the hardware address from the MIB II stuff. */
  268. #define END_HADDR(pEnd) 
  269. ((pEnd)->mib2Tbl.ifPhysAddress.phyAddress)
  270. #define END_HADDR_LEN(pEnd) 
  271. ((pEnd)->mib2Tbl.ifPhysAddress.addrLength)
  272. #ifndef SYS_INT_CONNECT
  273. #define SYS_INT_CONNECT(pFunc, arg, pRet)                              
  274. {                                                                           
  275. *pRet = (intConnect) (INUM_TO_IVEC (pDrvCtrl->ivec),     
  276.       (pFunc), (int) (arg));                              
  277. }
  278. #endif /* SYS_INT_CONNECT */
  279. #define MOT_CPM_DEBUG /* debug support */
  280. int motCpmDebug = 0;
  281. #ifdef MOT_CPM_DEBUG
  282. #define MOTCPMLOGMSG(x) 
  283. if (motCpmDebug) 
  284.     { 
  285.     logMsg x; 
  286.     }
  287. #else
  288. #define MOTCPMLOGMSG(x)
  289. #endif /* MOT_CPM_DEBUG */
  290. /* typedefs */
  291. /* Ethernet header */
  292. typedef struct free_args
  293.     {
  294.     void* arg1;
  295.     void* arg2;
  296.     } FREE_ARGS;
  297. typedef struct end_ctrl /* END_CTRL */
  298.     {
  299.     END_OBJ endObject; /* base class */
  300.     UINT32 regBase; /* register/DPR base address */
  301.     SCC_ETHER_DEV ether; /* ETHERNET SCC device */
  302.     int txBdIndexC; /* current tx buffer descriptor index */
  303.     UINT32 bufBase; /* address of memory pool; */
  304. /* NONE = malloc it */
  305.     int unit; /* unit number */
  306.     int ivec; /* interrupt vector */
  307.     BOOL polling; /* polling mode */
  308.     BOOL txCleaning; /* cleaning queue */
  309.     u_char * txBuf; /* transmit buffer */
  310.     u_char * rxBuf; /* receive buffer */
  311.     u_char *            txPoolBuf;      /* pool send buffer */
  312.     BOOL txStop; /* emergency stop output */
  313.     FUNCPTR freeRtn[TX_BD_MAX]; /* Array of free routines. */
  314.     FREE_ARGS freeData[TX_BD_MAX]; /* Array of free arguments */
  315.     CL_POOL_ID   pClPoolId;      /* for the free routines. */
  316.     BOOL txBlocked; /* flag for implementing flow control */
  317.     } END_CTRL;
  318. typedef struct {
  319.     int unit; /* unit number */
  320.     UINT32  motCpmAddr; /* base address of processor internal mem */
  321.     int ivec; /* interrupt vector */
  322.     int sccNum; /* Serial Communication Controler number */
  323.     int txBdNum; /* number of transmit buffer descriptors */
  324.     int rxBdNum; /* number of receive buffer descriptors */
  325.     UINT32 txBdBase; /* transmit buffer descriptor offset */
  326.     UINT32 rxBdBase; /* receive buffer descriptor offset */
  327.     UINT32 bufBase; /* address of memory pool; NONE = malloc it */
  328.     } END_PARM;
  329. /* globals */
  330. /* locals */
  331. M_CL_CONFIG motMclBlkConfig =  /* network mbuf configuration table */
  332.     {
  333.     /* 
  334.     no. mBlks no. clBlks memArea memSize
  335.     ----------- ---------- ------- -------
  336.     */
  337.     0,  0,  NULL,  0
  338.     };
  339. CL_DESC motClDescTbl [] =  /* network cluster pool configuration table */
  340.     {
  341.     /* 
  342.     clusterSize num memArea memSize
  343.     ----------- ---- ------- -------
  344.     */
  345.     {FRAME_MAX_AL, 0, NULL, 0}
  346.     }; 
  347. int motClDescTblNumEnt = (NELEMENTS(motClDescTbl));
  348. NET_POOL motCpmNetPool;
  349. /* forward declarations */
  350. #ifdef __STDC__
  351. LOCAL STATUS    motCpmInitParse (END_PARM *pEndParm, char *initString);
  352. LOCAL STATUS    motCpmInitMem (END_CTRL *pDrvCtrl);
  353. LOCAL void motCpmRecv (END_CTRL *pDrvCtrl, SCC_BUF * pRxBd);
  354. LOCAL void      motCpmIntr (END_CTRL *pDrvCtrl);
  355. LOCAL void  motCpmReset (END_CTRL * pDrvCtrl);
  356. LOCAL void  motCpmMCastFilterSet (END_CTRL * pDrvCtrl, char * pAddress);
  357. LOCAL void  motCpmMCastConfig (END_CTRL * pDrvCtrl);
  358. LOCAL void  motCpmTxRestart (END_CTRL * pDrvCtrl);
  359. LOCAL void  motCpmHandleInt (END_CTRL * pDrvCtrl);
  360. LOCAL void  motCpmCleanTxBdQueue (END_CTRL * pDrvCtrl);
  361. LOCAL STATUS  motCpmRestart (END_CTRL * pDrvCtrl);
  362. LOCAL void motCpmCleanRxBd (END_CTRL * pDrvCtrl, SCC_BUF * pRxBd);
  363. /* END Specific interfaces. */
  364. END_OBJ *       motCpmEndLoad (char *initString);
  365. LOCAL STATUS    motCpmEndStart(END_CTRL *pDrvCtrl);
  366. LOCAL int       motCpmEndIoctl (END_CTRL *pDrvCtrl, int cmd, caddr_t data);
  367. LOCAL STATUS    motCpmEndSend (END_CTRL *pDrvCtrl, M_BLK_ID pBuf);
  368. LOCAL STATUS    motCpmEndMCastAddrAdd (END_CTRL *pDrvCtrl, char* pAddress);
  369. LOCAL STATUS    motCpmEndMCastAddrDel (END_CTRL *pDrvCtrl, char* pAddress);
  370. LOCAL STATUS    motCpmEndMCastAddrGet (END_CTRL *pDrvCtrl,
  371. MULTI_TABLE *pTable);
  372. LOCAL STATUS    motCpmEndPollSend (END_CTRL *pDrvCtrl, M_BLK_ID pBuf);
  373. LOCAL STATUS    motCpmEndPollReceive (END_CTRL *pDrvCtrl, M_BLK_ID pBuf);
  374. LOCAL STATUS    motCpmEndPollStart (END_CTRL *pDrvCtrl);
  375. LOCAL STATUS    motCpmEndPollStop (END_CTRL *pDrvCtrl);
  376. LOCAL STATUS  motCpmEndUnload (END_CTRL *pDrvCtrl);
  377. LOCAL STATUS  motCpmEndStop (END_CTRL *pDrvCtrl);
  378. #else  /* __STDC__ */
  379. LOCAL STATUS    motCpmInitParse ();
  380. LOCAL STATUS    motCpmInitMem ();
  381. LOCAL void motCpmRecv ();
  382. LOCAL void      motCpmIntr ();
  383. LOCAL void  motCpmReset ();
  384. LOCAL void  motCpmMCastFilterSet ();
  385. LOCAL void  motCpmMCastConfig ();
  386. LOCAL void  motCpmTxRestart ();
  387. LOCAL void  motCpmHandleInt ();
  388. LOCAL void  motCpmCleanTxBdQueue ();
  389. LOCAL STATUS  motCpmRestart ();
  390. LOCAL void motCpmCleanRxBd ();
  391. /* END Specific interfaces. */
  392. END_OBJ *       motCpmEndLoad ();
  393. LOCAL STATUS    motCpmEndStart ();
  394. LOCAL int       motCpmEndIoctl ();
  395. LOCAL STATUS    motCpmEndSend ();
  396. LOCAL STATUS    motCpmEndMCastAddrAdd ();
  397. LOCAL STATUS    motCpmEndMCastAddrDel ();
  398. LOCAL STATUS    motCpmEndMCastAddrGet ();
  399. LOCAL STATUS    motCpmEndPollSend ();
  400. LOCAL STATUS    motCpmEndPollReceive ();
  401. LOCAL STATUS    motCpmEndPollStart ();
  402. LOCAL STATUS    motCpmEndPollStop ();
  403. LOCAL STATUS  motCpmEndUnload ();
  404. LOCAL STATUS  motCpmEndStop ();
  405. #endif  /* __STDC__ */
  406. /*
  407.  * Define the device function table.  This is static across all driver
  408.  * instances.
  409.  */
  410. LOCAL NET_FUNCS netFuncs =
  411.     {
  412.     (FUNCPTR)motCpmEndStart, /* start func. */
  413.     (FUNCPTR)motCpmEndStop, /* stop func. */
  414.     (FUNCPTR)motCpmEndUnload, /* unload func. */
  415.     (FUNCPTR)motCpmEndIoctl, /* ioctl func. */
  416.     (FUNCPTR)motCpmEndSend, /* send func. */
  417.     (FUNCPTR)motCpmEndMCastAddrAdd, /* multicast add func. */
  418.     (FUNCPTR)motCpmEndMCastAddrDel, /* multicast delete func. */
  419.     (FUNCPTR)motCpmEndMCastAddrGet, /* multicast get fun. */
  420.     (FUNCPTR)motCpmEndPollSend, /* polling send func. */
  421.     (FUNCPTR)motCpmEndPollReceive, /* polling receive func.  */
  422.     endEtherAddressForm,           /* Put address info into a packet.  */
  423.     endEtherPacketDataGet,         /* Get a pointer to packet data. */
  424.     endEtherPacketAddrGet          /* Get packet addresses. */
  425.     };
  426. /*******************************************************************************
  427. *
  428. * motCpmEndLoad - initialize the driver and device
  429. *
  430. * This routine initializes the driver and the device to the operational state.
  431. * All of the device specific parameters are passed in the <initString>, which
  432. * is of the following format:
  433. *
  434. * <unit>:<motCpmAddr>:<ivec>:<sccNum>:<txBdNum>:<rxBdNum>:<txBdBase>:<rxBdBase>:<bufBase> 
  435. * The parameters of this string are individually described in the 'motCpmEnd' 
  436. * man page.
  437. *
  438. * The SCC shares a region of memory with the driver.  The caller of 
  439. * this routine can specify the address of a non-cacheable memory region with
  440. * <bufBase>.  Or, if this parameter is "NONE", the driver obtains this
  441. * memory region by making calls to cacheDmaMalloc().  Non-cacheable memory 
  442. * space is important whenever the host processor uses cache memory.
  443. * This is also the case when the MC68EN360 is operating in companion
  444. * mode and is attached to a processor with cache memory.
  445. *
  446. * After non-cacheable memory is obtained, this routine divides up the
  447. * memory between the various buffer descriptors (BDs).  The number
  448. * of BDs can be specified by <txBdNum> and <rxBdNum>, or if "NULL", a
  449. * default value of 32 BDs will be used.  An additional number of buffers are
  450. * reserved as receive loaner buffers.  The number of loaner buffers is
  451. * a default number of 16.
  452. *
  453. * The user must specify the location of the transmit and receive BDs in
  454. * the processor's dual ported RAM.  <txBdBase> and <rxBdBase> give the
  455. * offsets from <motCpmAddr> for the base of the BD rings.  Each BD uses 
  456. * 8 bytes. Care must be taken so that the specified locations for Ethernet 
  457. * BDs do not conflict with other dual ported RAM structures.
  458. *
  459. * Multiple individual device units are supported by this driver.  Device
  460. * units can reside on different chips, or could be on different SCCs
  461. * within a single processor. The <sccNum> parameter is used to explicitly
  462. * state which SCC is being used. SCC1 is most commonly used, thus this
  463. * parameter most often equals "1".
  464. *
  465. * Before this routine returns, it connects up the interrupt vector <ivec>.
  466. *
  467. * RETURNS: An END object pointer or NULL on error.
  468. *
  469. * SEE ALSO:
  470. * .I "Motorola MC68EN360 User's Manual",
  471. * .I "Motorola MPC860 User's Manual",
  472. * .I "Motorola MPC821 User's Manual"
  473. */
  474. END_OBJ *motCpmEndLoad
  475.     (
  476.     char *      initString      /* parameter string */
  477.     )
  478.     {
  479.     END_PARM    endParm;        /* parameters from initString */
  480.     END_CTRL    *pDrvCtrl; /* pointer to END_CTRL structure */
  481.     int         scc;
  482.     UINT32 motCpmAddr;
  483.     u_char enetAddr[ENET_ADDR_SIZE];
  484.     int         retVal;
  485.     MOTCPMLOGMSG(("motCpmEndLoad n", 0, 0, 0, 0, 0, 0));
  486.     if (initString == NULL)
  487.         return (NULL);
  488.     
  489.     if (initString[0] == 0)
  490.         {
  491.         bcopy((char *)MOT_DEV_NAME, initString, MOT_DEV_NAME_LEN);
  492.         return (0);
  493.         }
  494.     /* Parse InitString */
  495.     if (motCpmInitParse (&endParm, initString) == ERROR)
  496. return (NULL);
  497.     /* Sanity check -- unit number */
  498.     if (endParm.unit < 0 || endParm.unit >= MAX_SCC_CHANNELS)
  499. return (NULL);
  500.     /* Sanity check -- scc number */
  501.     if ((endParm.sccNum < 1) || (endParm.sccNum > 4))
  502. return (NULL);
  503.     if (endParm.txBdBase == endParm.rxBdBase)
  504. return (NULL);
  505.     /* allocate the device structure */
  506.     pDrvCtrl = (END_CTRL *)calloc (sizeof(END_CTRL), 1);
  507.     if (pDrvCtrl == NULL)
  508. {
  509. MOTCPMLOGMSG(("motCpmEndLoad : Failed to allocate control structuren", 
  510.        0, 0, 0, 0, 0, 0));
  511. return (NULL);
  512. }
  513.     /* Check if we are already attached */
  514.     if (pDrvCtrl->endObject.attached == TRUE)
  515. return (&pDrvCtrl->endObject);
  516.     /* use default number of buffer descriptors if user did not specify */
  517.     if (endParm.txBdNum == 0)
  518. endParm.txBdNum = TX_BD_DEFAULT;
  519.     if (endParm.rxBdNum == 0)
  520.      endParm.rxBdNum = RX_BD_DEFAULT;
  521.     /* must be at least two transmit and receive buffer descriptors */
  522.     endParm.txBdNum = max (TX_BD_MIN, endParm.txBdNum);
  523.     endParm.rxBdNum = max (RX_BD_MIN, endParm.rxBdNum);
  524.     /* Initialize parameters */
  525.     pDrvCtrl->regBase = endParm.motCpmAddr;
  526.     pDrvCtrl->bufBase = endParm.bufBase;
  527.     pDrvCtrl->unit = endParm.unit;
  528.     pDrvCtrl->ivec = endParm.ivec;
  529.     pDrvCtrl->ether.sccNum = endParm.sccNum;
  530.     pDrvCtrl->ether.txBdNum = endParm.txBdNum;
  531.     pDrvCtrl->ether.rxBdNum = endParm.rxBdNum;
  532.     pDrvCtrl->ether.txBdBase = (SCC_BUF *) (endParm.motCpmAddr + 
  533. (endParm.txBdBase & 0xffff));
  534.     pDrvCtrl->ether.rxBdBase = (SCC_BUF *) (endParm.motCpmAddr + 
  535. (endParm.rxBdBase & 0xffff));
  536.     pDrvCtrl->ether.txBufSize = FRAME_MAX_AL;
  537.     pDrvCtrl->ether.rxBufSize = FRAME_MAX_AL;
  538.     pDrvCtrl->txBdIndexC = 0;
  539.     /* derive SCC dependent variables */
  540.     scc = pDrvCtrl->ether.sccNum - 1;
  541.     motCpmAddr = pDrvCtrl->regBase;
  542.     pDrvCtrl->ether.pScc    = (SCC *) ((UINT32) CPM_DPR_SCC1(motCpmAddr) +
  543.        (scc * 0x100));
  544.     pDrvCtrl->ether.pSccReg = (SCC_REG *) 
  545. ((UINT32) CPM_GSMR_L1(motCpmAddr) + (
  546.  scc * 0x20));
  547.     pDrvCtrl->ether.intMask = CPM_CIMR_SCC4 << (3 - scc);
  548.     /* endObject initializations */
  549.     if (END_OBJ_INIT (&pDrvCtrl->endObject, (void *)pDrvCtrl, MOT_DEV_NAME,
  550.                       pDrvCtrl->unit, &netFuncs,
  551.                       END_OBJ_STRING) == ERROR)
  552. return (NULL);
  553.     /* memory initialization */
  554.     if (motCpmInitMem (pDrvCtrl) == ERROR)
  555. return (NULL);
  556.     /* reset the chip */
  557.     motCpmReset (pDrvCtrl);
  558.     /* connect the interrupt handler motCpmIntr() */
  559.     SYS_INT_CONNECT ((VOIDFUNCPTR) motCpmIntr, 
  560.      (int) pDrvCtrl, &retVal);
  561.     if (retVal == ERROR)
  562.         return (NULL);
  563.  
  564.     /* Get our enet addr */
  565.     SYS_ENET_ADDR_GET (enetAddr);
  566.     MOTCPMLOGMSG(("motCpmEndLoad ADDR: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x n", 
  567. (int) enetAddr[0], (int) enetAddr[1], (int) enetAddr[2], 
  568. (int) enetAddr[3], (int) enetAddr[4], (int) enetAddr[5]));
  569.     /* Initialize MIB2 entries */
  570.     if (END_MIB_INIT (&pDrvCtrl->endObject, M2_ifType_ethernet_csmacd,
  571.                       enetAddr, 6, ETHERMTU,
  572. SPEED) == ERROR)
  573. return (NULL);
  574.     /* Mark the device ready */
  575.     /* IFF_SCAT is not defined by default */
  576.     END_OBJ_READY (&pDrvCtrl->endObject,
  577.  IFF_NOTRAILERS | IFF_BROADCAST | IFF_MULTICAST);
  578.     /* Successful return */
  579.     return (&pDrvCtrl->endObject);
  580.     }
  581. /*******************************************************************************
  582. *
  583. * motCpmInitParse - parse parameter values from initString
  584. *
  585. * Parse the input string.  Fill in values in the driver control structure.
  586. *
  587. * The initialization string format is:
  588. * .CS
  589. *    "unit:motCpmAddr:ivec:sccNum:txBdNum:rxBdNum:txBdBase:rxBdBase:bufBase"
  590. * .CE
  591. *
  592. * .IP <unit>
  593. * Device unit number, a small integer.
  594. * .IP <motCpmAddr>
  595. * base address of processor internal mem 
  596. * .IP <ivec>
  597. * Interrupt vector number
  598. * .IP <sccNum>
  599. * SCC number used.
  600. * .IP <txBdNum>
  601. * number of transmit buffer descriptors; NULL = default
  602. * .IP <rxBdNum>
  603. * number of receive buffer descriptors; NULL = default
  604. * .IP <txBdBase>
  605. * transmit buffer descriptor offset
  606. * .IP <rxBdBase>
  607. * receive buffer descriptor offset
  608. * .IP <bufBase>
  609. * address of memory pool; NONE = malloc it
  610. * .LP
  611. *
  612. * RETURNS: OK or ERROR for invalid arguments.
  613. */
  614. LOCAL STATUS motCpmInitParse
  615.     (
  616.     END_PARM    *pEndParm, /* structure to fill in with parameters */
  617.     char        *initString /* init string */
  618.     )
  619.     {
  620.     char *      tok;            /* an initString token */
  621.     char * holder=NULL;    /* points to initString fragment beyond tok */
  622.     char *  initStringBuff;
  623.     initStringBuff = malloc(strlen(initString) + 1);
  624.     if (initStringBuff == NULL)
  625.         return (ERROR);
  626.     strcpy (initStringBuff, initString);
  627.     tok = strtok_r(initStringBuff, ":", &holder);
  628.     if (tok == NULL)
  629.         {
  630.         free(initStringBuff);
  631. return ERROR;
  632.         }
  633.     pEndParm->unit = atoi(tok);
  634.     tok = strtok_r(NULL, ":", &holder);
  635.     if (tok == NULL)
  636.         {
  637.         free(initStringBuff);
  638. return ERROR;
  639.         }
  640.     pEndParm->motCpmAddr = strtoul (tok, NULL, 16);
  641.     tok = strtok_r(NULL, ":", &holder);
  642.     if (tok == NULL)
  643.         {
  644.         free(initStringBuff);
  645. return ERROR;
  646.         }
  647.     pEndParm->ivec = strtoul (tok, NULL, 16);
  648.     tok = strtok_r(NULL, ":", &holder);
  649.     if (tok == NULL)
  650.         {
  651.         free(initStringBuff);
  652. return ERROR;
  653.         }
  654.     pEndParm->sccNum = atoi (tok);
  655.     tok = strtok_r(NULL, ":", &holder);
  656.     if (tok == NULL)
  657.         {
  658.         free(initStringBuff);
  659. return ERROR;
  660.         }
  661.     pEndParm->txBdNum = strtoul (tok, NULL, 16);
  662.     tok = strtok_r(NULL, ":", &holder);
  663.     if (tok == NULL)
  664.         {
  665.         free(initStringBuff);
  666. return ERROR;
  667.         }
  668.     pEndParm->rxBdNum = strtoul (tok, NULL, 16);
  669.     tok = strtok_r(NULL, ":", &holder);
  670.     if (tok == NULL)
  671.         {
  672.         free(initStringBuff);
  673. return ERROR;
  674.         }
  675.     pEndParm->txBdBase = strtoul (tok, NULL, 16);
  676.     tok = strtok_r(NULL, ":", &holder);
  677.     if (tok == NULL)
  678.         {
  679.         free(initStringBuff);
  680. return ERROR;
  681.         }
  682.     pEndParm->rxBdBase = strtoul (tok, NULL, 16);
  683.     tok = strtok_r(NULL, ":", &holder);
  684.     if (tok == NULL)
  685.         {
  686.         free(initStringBuff);
  687. return ERROR;
  688.         }
  689.     pEndParm->bufBase = strtoul (tok, NULL, 16);
  690.     MOTCPMLOGMSG(("unit = %d, motCpmAddr = 0x%x, ivec = 0x%x, sccNum = 0x%xn",
  691. pEndParm->unit, pEndParm->motCpmAddr, pEndParm->ivec, 
  692. pEndParm->sccNum, 0, 0));
  693.     MOTCPMLOGMSG(("txBdNum = 0x%x, rxBdNum = 0x%x, txBdBase = 0x%xn",
  694. pEndParm->txBdNum, pEndParm->rxBdNum, pEndParm->txBdBase, 
  695. 0, 0, 0));
  696.     MOTCPMLOGMSG(("rxBdBase  = 0x%x, bufBase = %dn", pEndParm->rxBdBase, 
  697. pEndParm->bufBase, 0, 0, 0, 0));
  698.     free(initStringBuff);
  699.     return OK;
  700.     }
  701. /*******************************************************************************
  702. *
  703. * motCpmInitMem - initialize memory 
  704. *
  705. * Using data in the control structure, setup and initialize the memory
  706. * areas needed.  If the memory address is not already specified, then allocate
  707. * cache safe memory.
  708. *
  709. * RETURNS: OK or ERROR.
  710. *
  711. */
  712. LOCAL STATUS motCpmInitMem
  713.     (
  714.     END_CTRL * pDrvCtrl /* pointer to END_CTRL structure */
  715.     )
  716.     {
  717.     int counter;
  718.     FUNCPTR  allocFunc;
  719.     void * pData;
  720.     char* pTmpBuf;
  721.     int numBuf;
  722.     /* Set up the structures to allow us to free data after sending it. */
  723.     for (counter = 0; counter < pDrvCtrl->ether.txBdNum; counter++)
  724. {
  725. pDrvCtrl->freeRtn[counter] = NULL;
  726. pDrvCtrl->freeData[counter].arg1 = NULL;
  727. pDrvCtrl->freeData[counter].arg2 = NULL;
  728. }
  729.     if (pDrvCtrl->bufBase == NONE)
  730. {
  731. /* We must allocate memory for buffer descriptors */
  732. pData = NULL;
  733. allocFunc = (FUNCPTR) cacheDmaMalloc;
  734. }
  735.     else
  736. {
  737. /* Memory for buffer descriptors is already allocated */
  738. pData = (void *) pDrvCtrl->bufBase;
  739. allocFunc = NULL;
  740. }
  741.     /* 
  742.      * calculate the number of buffers we need :
  743.      * receive buffers + transmit buffers + loaner buffers (= L_POOL)
  744.      */
  745.     numBuf = pDrvCtrl->ether.rxBdNum + pDrvCtrl->ether.txBdNum + L_POOL;
  746.     /* Use the MUX's memory manager to get our buffers. */
  747.     pDrvCtrl->endObject.pNetPool = &motCpmNetPool;
  748.     motClDescTbl[0].clNum  = numBuf;
  749.     motClDescTbl[0].memSize  = (numBuf * (FRAME_MAX_AL + sizeof (long)));
  750.     motMclBlkConfig.mBlkNum  = 5 * numBuf;
  751.     motMclBlkConfig.clBlkNum  = 5 * numBuf;
  752.     motMclBlkConfig.memSize  = ((motMclBlkConfig.mBlkNum *
  753.                                     (MSIZE + sizeof (long))) +
  754.                                    (motMclBlkConfig.clBlkNum *
  755.                                     (CL_BLK_SZ + sizeof (long))));
  756.     if ((motMclBlkConfig.memArea = (char *) memalign (sizeof (long),
  757.                                                       motMclBlkConfig.memSize))
  758.         == NULL)
  759.         return (ERROR);
  760.     motClDescTbl[0].memArea = (char *) cacheDmaMalloc(motClDescTbl[0].memSize);
  761.     if (motClDescTbl[0].memArea == NULL)
  762.         {
  763.         MOTCPMLOGMSG (( "system memory unavailablen", 1, 2, 3, 4, 5, 6));
  764.         return (ERROR);
  765.         }
  766.     if (netPoolInit(pDrvCtrl->endObject.pNetPool, &motMclBlkConfig,
  767.                     &motClDescTbl[0], motClDescTblNumEnt, NULL) == ERROR)
  768.                     
  769.         {
  770.         MOTCPMLOGMSG(("Could not init bufferingn", 1, 2, 3, 4, 5, 6));
  771.         return (ERROR);
  772.         }
  773.     /* Store the cluster pool id as others need it later. */
  774.     pDrvCtrl->pClPoolId = clPoolIdGet(pDrvCtrl->endObject.pNetPool,
  775.                                       FRAME_MAX_AL, FALSE);
  776.     for (counter = 0; counter < pDrvCtrl->ether.rxBdNum; counter++)
  777. {
  778.         if ((pTmpBuf = (char *)netClusterGet(pDrvCtrl->endObject.pNetPool,
  779.                                              pDrvCtrl->pClPoolId)) == NULL)
  780.             {
  781.             return (ERROR);
  782.             }
  783.         pDrvCtrl->ether.rxBdBase[counter].dataPointer = (u_char *) pTmpBuf;
  784. }
  785.    
  786.     pDrvCtrl->txPoolBuf = netClusterGet (pDrvCtrl->endObject.pNetPool, 
  787.                                          pDrvCtrl->pClPoolId);
  788.  
  789.     return (OK);
  790.     }
  791. /*******************************************************************************
  792. *
  793. * motCpmEndStart - start the device 
  794. *
  795. * This function initializes the device and calls BSP functions to connect
  796. * interrupts and start the device running in interrupt mode.
  797. *
  798. * The complement of this routine is motCpmEndStop().  Once a unit is reset by
  799. * motCpmEndStop(), it may be re-initialized to a running state by this routine.
  800. * RETURNS: OK if successful, otherwise ERROR.
  801. */
  802. LOCAL STATUS motCpmEndStart
  803.     (
  804.     END_CTRL * pDrvCtrl /* pointer to END_CTRL structure */
  805.     )
  806.     {
  807.     int counter;
  808.     u_char * enetAddr;
  809.     ETHER_MULTI * pCurr;
  810.     MOTCPMLOGMSG(("motCpmEndStart n", 0, 0, 0, 0, 0, 0));
  811.     /* initialize flag(s) */
  812.     pDrvCtrl->polling = FALSE;
  813.     pDrvCtrl->txStop = FALSE;
  814.     pDrvCtrl->txCleaning = FALSE;
  815.     pDrvCtrl->txBlocked = FALSE;
  816.     /* set up transmit buffer descriptors */
  817.     pDrvCtrl->ether.pScc->param.tbase = (UINT16)
  818. ((UINT32) pDrvCtrl->ether.txBdBase & 0xffff);
  819.     pDrvCtrl->ether.pScc->param.tbptr = (UINT16)
  820. ((UINT32) pDrvCtrl->ether.txBdBase & 0xffff);
  821.     pDrvCtrl->ether.txBdNext  = 0;
  822.     /* initialize each transmit buffer descriptor */
  823.      
  824.     for (counter = 0; counter < pDrvCtrl->ether.txBdNum; counter++)
  825.         pDrvCtrl->ether.txBdBase[counter].statusMode = SCC_ETHER_TX_BD_I |
  826.                                                        SCC_ETHER_TX_BD_PAD |
  827.                                                        SCC_ETHER_TX_BD_L |
  828.                                                        SCC_ETHER_TX_BD_TC;
  829.     /* set the last BD to wrap to the first */
  830.     pDrvCtrl->ether.txBdBase[(counter - 1)].statusMode |= SCC_ETHER_TX_BD_W;
  831.     /* set up receive buffer descriptors */
  832.     pDrvCtrl->ether.pScc->param.rbase = (UINT16)
  833. ((UINT32) pDrvCtrl->ether.rxBdBase & 0xffff);
  834.     pDrvCtrl->ether.pScc->param.rbptr = (UINT16)
  835. ((UINT32) pDrvCtrl->ether.rxBdBase & 0xffff);
  836.     pDrvCtrl->ether.rxBdNext  = 0;
  837.     /* initialize each receive buffer descriptor */
  838.     for (counter = 0; counter < pDrvCtrl->ether.rxBdNum; counter++)
  839.         pDrvCtrl->ether.rxBdBase[counter].statusMode = SCC_ETHER_RX_BD_I |
  840.                 SCC_ETHER_RX_BD_E;
  841.     /* set the last BD to wrap to the first */
  842.     pDrvCtrl->ether.rxBdBase[(counter - 1)].statusMode |= SCC_ETHER_RX_BD_W;
  843.     /* set SCC attributes to Ethernet mode */
  844.  
  845.     pDrvCtrl->ether.pSccReg->gsmrl    = SCC_GSMRL_ETHERNET | SCC_GSMRL_TPP_10 |
  846.                                         SCC_GSMRL_TPL_48   | SCC_GSMRL_TCI;
  847.     pDrvCtrl->ether.pSccReg->gsmrh    = 0x0;
  848.     pDrvCtrl->ether.pSccReg->psmr     = SCC_ETHER_PSMR_CRC |
  849. SCC_ETHER_PSMR_NIB_22;
  850.     if (END_FLAGS_GET(&pDrvCtrl->endObject) & IFF_PROMISC)
  851.         pDrvCtrl->ether.pSccReg->psmr |= SCC_ETHER_PSMR_PRO;
  852.  
  853.     pDrvCtrl->ether.pSccReg->dsr      = 0xd555;
  854.     pDrvCtrl->ether.pScc->param.rfcr  = 0x18;      /* supervisor data access */
  855.     pDrvCtrl->ether.pScc->param.tfcr  = 0x18;      /* supervisor data access */
  856.     pDrvCtrl->ether.pScc->param.mrblr = FRAME_MAX_AL;  /* max rx buffer size */
  857.     /* initialize parameter the SCC RAM */
  858.  
  859.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->c_pres = 0xffffffff;
  860.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->c_mask = 0xdebb20e3;
  861.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->crcec = 0x00000000;
  862.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->alec = 0x00000000;
  863.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->disfc = 0x00000000;
  864.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->pads = 0x8888;
  865.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->ret_lim = 0x000f;
  866.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->mflr = FRAME_MAX;
  867.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->minflr = FRAME_MIN;
  868.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->maxd1 = FRAME_MAX_AL;
  869.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->maxd2 = FRAME_MAX_AL;
  870.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->gaddr1 = 0x0000;
  871.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->gaddr2 = 0x0000;
  872.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->gaddr3 = 0x0000;
  873.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->gaddr4 = 0x0000;
  874.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->p_per = 0x0000;
  875.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->iaddr1 = 0x0000;
  876.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->iaddr2 = 0x0000;
  877.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->iaddr3 = 0x0000;
  878.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->iaddr4 = 0x0000;
  879.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->taddr_h = 0x0000;
  880.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->taddr_m = 0x0000;
  881.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->taddr_l = 0x0000;
  882.     /* set the hardware Ethernet address of the board */
  883.     enetAddr = END_HADDR(&pDrvCtrl->endObject);
  884.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->paddr1_h =
  885.         (enetAddr[5] << 8) + enetAddr[4];
  886.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->paddr1_m =
  887.         (enetAddr[3] << 8) + enetAddr[2];
  888.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->paddr1_l =
  889.         (enetAddr[1] << 8) + enetAddr[0];
  890.     /* Set the multicast addresses */
  891.     for (pCurr = END_MULTI_LST_FIRST(&pDrvCtrl->endObject); pCurr != NULL;
  892. pCurr = (ETHER_MULTI *)lstNext(&pCurr->node))
  893. {
  894. /* add multicast address */
  895. motCpmMCastFilterSet (pDrvCtrl, pCurr->addr);
  896. }
  897.     /* enable Ethernet interrupts */
  898.     pDrvCtrl->ether.pSccReg->scce = 0xffff; /* clr events */
  899.     /* allow receive and transmit errors interrupts */
  900.     pDrvCtrl->ether.pSccReg->sccm = SCC_ETHER_SCCX_RXF | SCC_ETHER_SCCX_TXE |
  901.     SCC_ETHER_SCCX_TXB;
  902.     *CPM_CIMR(pDrvCtrl->regBase) |= pDrvCtrl->ether.intMask;
  903.     /* call the BSP to do any other initialization (e.g., connecting clocks) */
  904.     SYS_ENET_ENABLE;
  905.     /* raise the interface flags - mark the device as up */
  906.     END_FLAGS_SET (&pDrvCtrl->endObject, IFF_UP | IFF_RUNNING);
  907.     /* enable the transmitter */
  908.     pDrvCtrl->ether.pSccReg->gsmrl |= SCC_GSMRL_ENT;
  909.     /* issue the restart transmitter command to the CP */
  910.     while (*CPM_CPCR(pDrvCtrl->regBase) & CPM_CR_FLG);
  911.     *CPM_CPCR(pDrvCtrl->regBase) = ((pDrvCtrl->ether.sccNum - 1) << 6) |
  912.                                       CPM_CR_SCC_RESTART | CPM_CR_FLG;
  913.     while (*CPM_CPCR(pDrvCtrl->regBase) & CPM_CR_FLG);
  914.     /* enable the receiver */
  915.     pDrvCtrl->ether.pSccReg->gsmrl |= SCC_GSMRL_ENR;
  916.     return (OK);
  917.     }
  918. /*******************************************************************************
  919. *
  920. * motCpmEndStop - stop the device 
  921. *
  922. * This routine marks the interface as down and resets the device.  This
  923. * includes disabling interrupts, stopping the transmitter and receiver,
  924. * and calling the bsp-specific LAN disable routine to do any target 
  925. * specific disabling.
  926. *
  927. * The complement of this routine is motCpmEndStart().  Once a unit is 
  928. * stop in this routine, it may be re-initialized to a running state by 
  929. * motCpmEndStart().
  930. *
  931. * RETURNS: OK or ERROR.
  932. */
  933. LOCAL STATUS motCpmEndStop
  934.     (
  935.     END_CTRL * pDrvCtrl /* pointer to END_CTRL structure */
  936.     )
  937.     {
  938.     /* mark the driver as down */
  939.     END_FLAGS_CLR (&pDrvCtrl->endObject, IFF_UP | IFF_RUNNING);
  940.     /* Reset the device */
  941.     motCpmReset (pDrvCtrl);
  942.     return (OK);
  943.     }
  944. /******************************************************************************
  945. *
  946. * motCpmEndUnload - unload a driver from the system
  947. *
  948. * This function first brings down the device, and then frees any
  949. * stuff that was allocated by the driver in the load function.
  950. *
  951. * RETURN : OK or ERROR
  952. */
  953. LOCAL STATUS motCpmEndUnload
  954.     (
  955.     END_CTRL *pDrvCtrl /* pointer to END_CTRL structure */
  956.     )
  957.     {
  958.     END_OBJECT_UNLOAD (&pDrvCtrl->endObject);
  959.     return (OK);
  960.     }
  961. /*******************************************************************************
  962. *
  963. * motCpmEndSend - output packet to network interface device
  964. *
  965. * This routine() takes a M_BLK_ID and sends off the data in the M_BLK_ID.
  966. * The buffer must already have the addressing information properly installed
  967. * in it. This is done by a higher layer. The last arguments are a free
  968. * routine to be called when the device is done with the buffer and a pointer
  969. * to the argument to pass to the free routine.
  970. *
  971. * muxSend() calls this routine each time it wants to send a packet.
  972. * Errors are detected at interrupt level.
  973. *
  974. * RETURNS: OK or ERROR.
  975. */
  976. LOCAL STATUS motCpmEndSend
  977.     (
  978.     END_CTRL *pDrvCtrl, /* pointer to END_CTRL structure */
  979.     M_BLK_ID    pMblk /* Data to send */
  980.     )
  981.     {
  982.     int length;
  983.     SCC_BUF * pTxBd;
  984.     u_char * pad;
  985.     char *         pBuf;
  986.     int  oldLevel;
  987.     int                 s;
  988.     
  989.     MOTCPMLOGMSG(("motCpmEndSend n", 0, 0, 0, 0, 0, 0));
  990.     if (pDrvCtrl->txBlocked)
  991.         return (END_ERR_BLOCK);
  992.     
  993.     if (pDrvCtrl->polling)
  994.         netMblkClChainFree (pMblk); /* free the given mBlk chain */
  995.         errno = EINVAL;
  996.         return (ERROR);
  997.         }
  998.     /* gain exclusive access to the transmitter */
  999.     END_TX_SEM_TAKE (&pDrvCtrl->endObject, WAIT_FOREVER);
  1000.     /* get a free transmit frame descriptor */
  1001.     
  1002.     pTxBd = & pDrvCtrl->ether.txBdBase[pDrvCtrl->ether.txBdNext];
  1003.     
  1004.     /* check if a transmit buffer descriptor is available */
  1005.     
  1006.     if ((pTxBd->statusMode & SCC_ETHER_TX_BD_R) || 
  1007.         (((pDrvCtrl->ether.txBdNext + 1) % pDrvCtrl->ether.txBdNum) 
  1008.          == pDrvCtrl->txBdIndexC))
  1009.         {
  1010.         END_TX_SEM_GIVE (&pDrvCtrl->endObject);
  1011.         s = intLock();
  1012.         pDrvCtrl->txBlocked = TRUE;
  1013.         intUnlock(s);
  1014.         return (END_ERR_BLOCK);
  1015.         }
  1016.     
  1017.     /* fill the transmit frame descriptor */
  1018.     
  1019.     pBuf = netClusterGet(pDrvCtrl->endObject.pNetPool, pDrvCtrl->pClPoolId);
  1020.     if (pBuf == NULL)
  1021.         {
  1022.         END_TX_SEM_GIVE (&pDrvCtrl->endObject);
  1023. netMblkClChainFree(pMblk);
  1024.         return (ERROR);
  1025.         }
  1026.     length = netMblkToBufCopy (pMblk, (char *)pBuf, NULL);
  1027.     netMblkClChainFree(pMblk); 
  1028.     pTxBd->dataPointer = (u_char *) pBuf;
  1029.     
  1030.     /* padding mechanism in Rev A is buggy - do in software */
  1031.     
  1032.     if (length < FRAME_MIN)
  1033.         {
  1034.         pad = pTxBd->dataPointer + length;
  1035.         for (; length != FRAME_MIN; length++, pad++)
  1036.             *pad = 0x88;
  1037.         }
  1038.     
  1039.     pTxBd->dataLength = length;
  1040.     
  1041.     oldLevel = intLock (); /* disable ints during update */
  1042.     
  1043.     if (pTxBd->statusMode & SCC_ETHER_TX_BD_W)
  1044.         pTxBd->statusMode = SCC_ETHER_TX_BD_I | SCC_ETHER_TX_BD_PAD |
  1045.             SCC_ETHER_TX_BD_L | SCC_ETHER_TX_BD_TC  |
  1046.             SCC_ETHER_TX_BD_W | SCC_ETHER_TX_BD_R;
  1047.     else
  1048.         pTxBd->statusMode = SCC_ETHER_TX_BD_I | SCC_ETHER_TX_BD_PAD |
  1049.             SCC_ETHER_TX_BD_L | SCC_ETHER_TX_BD_TC  |
  1050.             SCC_ETHER_TX_BD_R;
  1051.     
  1052.     pDrvCtrl->freeRtn[pDrvCtrl->ether.txBdNext] = (FUNCPTR) netClFree;
  1053.     pDrvCtrl->freeData[pDrvCtrl->ether.txBdNext].arg1 =
  1054.         pDrvCtrl->endObject.pNetPool;
  1055.     pDrvCtrl->freeData[pDrvCtrl->ether.txBdNext].arg2 = pBuf;
  1056.     /* incr BD count */
  1057.     
  1058.     pDrvCtrl->ether.txBdNext = (pDrvCtrl->ether.txBdNext + 1) %
  1059.         pDrvCtrl->ether.txBdNum;
  1060.     
  1061.     /* Unlock interrupts */
  1062.     
  1063.     intUnlock (oldLevel);
  1064.     /* release semaphore */
  1065.     END_TX_SEM_GIVE (&pDrvCtrl->endObject);
  1066.     /* Bump the statistic counter. */
  1067.     END_ERR_ADD (&pDrvCtrl->endObject, MIB2_OUT_UCAST, +1);
  1068.     return (OK);
  1069.     }
  1070. /*******************************************************************************
  1071. *
  1072. * motCpmEndIoctl - network interface control routine
  1073. *
  1074. * This routine implements the network interface control functions.
  1075. * It handles EIOCSIFADDR, EIOCGADDR, EIOCSFLAGS, EIOCGFLAGS,
  1076. * EIOCPOLLSTART, EIOCPOLLSTOP, EIOCGMIB2 and EIOCGFBUF commands.
  1077. *
  1078. * RETURNS: OK if successful, otherwise EINVAL.
  1079. */
  1080. LOCAL int motCpmEndIoctl
  1081.     (
  1082.     END_CTRL * pDrvCtrl, /* pointer to END_CTRL structure */
  1083.     int cmd, /* command to process */
  1084.     caddr_t data /* pointer to data */ 
  1085.     )
  1086.     {
  1087.     int         error   = 0;            /* error value */
  1088.     long  value;
  1089.     END_OBJ * pEndObj = &pDrvCtrl->endObject;
  1090.     MOTCPMLOGMSG(("motCpmEndIoctl with command = 0x%x n", cmd, 0, 0, 0, 0, 0));
  1091.     switch (cmd)
  1092.         {
  1093. case EIOCSADDR:
  1094.     if (data == NULL)
  1095.      error = EINVAL;
  1096.     bcopy ((char *)data, (char *)END_HADDR(pEndObj),
  1097. END_HADDR_LEN(pEndObj));
  1098.     break;
  1099.         case EIOCGADDR:
  1100.     if (data == NULL)
  1101.      error = EINVAL;
  1102.      else
  1103.       bcopy ((char *)END_HADDR(pEndObj), (char *)data,
  1104.   END_HADDR_LEN(pEndObj));
  1105.    break;
  1106.    
  1107. case EIOCSFLAGS:
  1108.     value = (long) data;
  1109.     if (value < 0)
  1110. {
  1111. value = -value;
  1112. value--;
  1113. END_FLAGS_CLR (pEndObj, value);
  1114. }
  1115.     else
  1116. END_FLAGS_SET (pEndObj, value);
  1117.     /* set promisc bit off flags */
  1118.     if (END_FLAGS_GET(pEndObj) & IFF_PROMISC)
  1119. pDrvCtrl->ether.pSccReg->psmr |= SCC_ETHER_PSMR_PRO;
  1120.     else
  1121. pDrvCtrl->ether.pSccReg->psmr &= ~SCC_ETHER_PSMR_PRO;
  1122.     break;
  1123. case EIOCGFLAGS:
  1124.     if (data == NULL)
  1125. error = EINVAL;
  1126.     else
  1127.      *(int *)data = END_FLAGS_GET(pEndObj);
  1128.     break;
  1129. case EIOCPOLLSTART:
  1130.     error = motCpmEndPollStart (pDrvCtrl);
  1131.     break;
  1132. case EIOCPOLLSTOP:
  1133.     error = motCpmEndPollStop (pDrvCtrl);
  1134.     break;
  1135. case EIOCGMIB2:
  1136.     if (data == NULL)
  1137.      error = EINVAL;
  1138.     else
  1139. bcopy((char *)&pDrvCtrl->endObject.mib2Tbl, (char *)data,
  1140. sizeof(pDrvCtrl->endObject.mib2Tbl));
  1141.     break;
  1142.         case EIOCGFBUF:
  1143.     if (data == NULL)
  1144. error =  EINVAL;
  1145.     else
  1146. *(int *)data = LENGTH_MIN_FBUF;
  1147.     break;
  1148.         default:
  1149.             error = EINVAL;
  1150.         }
  1151.     return (error);
  1152.     }
  1153. /*******************************************************************************
  1154. *
  1155. * motCpmEndMCastAddrAdd - add a multicast address for the device
  1156. *
  1157. * This routine adds a multicast address to whatever the driver
  1158. * is already listening for. 
  1159. *
  1160. * To add an address in the processor group address hash filter, we use
  1161. * the SET GROUP ADDRESS command. This command can be executed at any 
  1162. * time, regadless of whether the Ethernet channel is enabled.
  1163. *
  1164. * RETURNS : OK or ERROR
  1165. */
  1166. LOCAL STATUS motCpmEndMCastAddrAdd
  1167.     (
  1168.     END_CTRL *  pDrvCtrl, /* pointer to END_CTRL structure */
  1169.     char *      pAddr /* Address to add to the table. */
  1170.     )
  1171.     {
  1172.     STATUS error;
  1173.     MOTCPMLOGMSG(("motCpmEndMCastAddrAdd %x:%x:%x:%x:%x:%x n", 
  1174.  pAddr[5], pAddr[4], pAddr[3], 
  1175.  pAddr[2], pAddr[1], pAddr[0]));
  1176.     error = etherMultiAdd (&pDrvCtrl->endObject.multiList, pAddr);
  1177.     if (error == ENETRESET)
  1178. {
  1179. pDrvCtrl->endObject.nMulti++;
  1180. /* Set the multicast address */
  1181. motCpmMCastFilterSet (pDrvCtrl, pAddr);
  1182. error = OK;
  1183. }
  1184.     return ((error == OK) ? OK : ERROR);
  1185.     }
  1186. /*******************************************************************************
  1187. *
  1188. * motCpmEndMCastAddrDel - delete a multicast address for the device
  1189. *
  1190. * This routine deletes a multicast address from the current list of
  1191. * multicast addresses.
  1192. *
  1193. * RETURNS : OK or ERROR
  1194. */
  1195. LOCAL STATUS motCpmEndMCastAddrDel
  1196.     (
  1197.     END_CTRL *  pDrvCtrl, /* pointer to END_CTRL structure */
  1198.     char *      pAddr /* Address to delete from the table. */
  1199.     )
  1200.     {
  1201.     STATUS error;
  1202.     MOTCPMLOGMSG(("motCpmEndMCastDel %x:%x:%x:%x:%x:%x n", 
  1203.  pAddr[5], pAddr[4], pAddr[3], 
  1204.  pAddr[2], pAddr[1], pAddr[0]));
  1205.     error = etherMultiDel (&pDrvCtrl->endObject.multiList, pAddr);
  1206.     if (error == ENETRESET)
  1207. {
  1208. pDrvCtrl->endObject.nMulti--;
  1209. motCpmMCastConfig (pDrvCtrl);
  1210. error = OK;
  1211. }
  1212.     return ((error == OK) ? OK : ERROR);
  1213.     }
  1214. /*******************************************************************************
  1215. *
  1216. * motCpmEndMCastAddrGet - get the current multicast address list
  1217. *
  1218. * This routine returns the current multicast address list in <pTable>
  1219. *
  1220. */
  1221. LOCAL STATUS motCpmEndMCastAddrGet
  1222.     (
  1223.     END_CTRL *  pDrvCtrl, /* pointer to END_CTRL structure */
  1224.     MULTI_TABLE *pTable /* table to fill in with addresses */
  1225.     )
  1226.     {
  1227.     MOTCPMLOGMSG(("motCpmEndMCastAddrGet n", 0, 0, 0, 0, 0, 0));
  1228.     return (etherMultiGet (&pDrvCtrl->endObject.multiList, pTable));
  1229.     }
  1230. /*******************************************************************************
  1231. *
  1232. * motCpmEndPollStart - start polling mode
  1233. *
  1234. * This routine starts polling mode by disabling ethernet interrupts and
  1235. * setting the polling flag in the END_CTRL stucture.
  1236. *
  1237. * It is necessary to empty transmit queue before entering polling mode
  1238. * because M_BLK_ID free routine used in interrupt mode could be unusable 
  1239. * in this mode (could use kernel calls). 
  1240. *
  1241. * RETURNS: OK or ERROR if already in polling mode.
  1242. */
  1243. LOCAL STATUS motCpmEndPollStart
  1244.     (
  1245.     END_CTRL    *pDrvCtrl /* pointer to END_CTRL structure */
  1246.     )
  1247.     {
  1248.     int  intLevel;
  1249.     int txBdIndex;
  1250.     SCC_BUF * pTxBd;
  1251.     MOTCPMLOGMSG(("motCpmEndPollStart n", 0, 0, 0, 0, 0, 0));
  1252.     /* Lock interrupts */
  1253.     intLevel = intLock();
  1254.     /* clean transmit queue */
  1255.     txBdIndex = pDrvCtrl->txBdIndexC;
  1256.     while (txBdIndex != pDrvCtrl->ether.txBdNext)
  1257. {
  1258. pTxBd = & pDrvCtrl->ether.txBdBase[txBdIndex];
  1259. /* Spin until frame buffer is sent */
  1260. while (pTxBd->statusMode & SCC_ETHER_TX_BD_R)
  1261.     ;
  1262. /* Check for transmit errors */
  1263. if (pTxBd->statusMode & (SCC_ETHER_TX_BD_RL | SCC_ETHER_TX_BD_UN |
  1264.   SCC_ETHER_TX_BD_CSL | SCC_ETHER_TX_BD_LC))
  1265.     {
  1266.     /* An error has occured, restart the transmitter */
  1267.     pDrvCtrl->txStop = TRUE;
  1268.     motCpmTxRestart (pDrvCtrl);
  1269.     }
  1270. /* increment txBdIndex */
  1271. txBdIndex = (txBdIndex + 1) % pDrvCtrl->ether.txBdNum;
  1272. }
  1273.     
  1274.     /* free all transmit buffer and update transmit queue */
  1275.     motCpmCleanTxBdQueue (pDrvCtrl);
  1276.     /* Now, transmit queue is empty. We can enter polling mode. */
  1277.     /* mask off the receive and transmit interrupts */
  1278.     
  1279.     pDrvCtrl->ether.pSccReg->sccm = 0;
  1280.     /* Set the polling flag */
  1281.     pDrvCtrl->polling = TRUE;
  1282.     /* Unlock interrupts */
  1283.     intUnlock (intLevel);
  1284.     return (OK);
  1285.     }
  1286. /*******************************************************************************
  1287. *
  1288. * motCpmEndPollStop - stop polling mode
  1289. *
  1290. * This routine stops polling mode by enabling ethernet interrupts and
  1291. * resetting the polling flag in the END_CTRL structure.
  1292. *
  1293. * RETURNS: OK always
  1294. */
  1295. LOCAL STATUS motCpmEndPollStop
  1296.     (
  1297.     END_CTRL    *pDrvCtrl /* pointer to END_CTRL structure */
  1298.     )
  1299.     {
  1300.     int         intLevel;
  1301.     MOTCPMLOGMSG(("motCpmEndPollStop n", 0, 0, 0, 0, 0, 0));
  1302.     /* lock interrupt  */
  1303.     intLevel = intLock();
  1304.     /* reset the SCC's interrupt status bit */
  1305.     *CPM_CISR(pDrvCtrl->regBase) = pDrvCtrl->ether.intMask;
  1306.     /* enable this SCC's interrupt */
  1307.     *CPM_CIMR(pDrvCtrl->regBase) |= pDrvCtrl->ether.intMask;
  1308.     /* reset the status bits */
  1309.     pDrvCtrl->ether.pSccReg->scce = 0xffff;
  1310.     /* enables the receive and transmit interrupts */
  1311.     pDrvCtrl->ether.pSccReg->sccm = SCC_ETHER_SCCX_RXF | SCC_ETHER_SCCX_TXE |
  1312.     SCC_ETHER_SCCX_TXB;
  1313.     /* reset the polling flag */
  1314.     pDrvCtrl->polling = FALSE;
  1315.     /* unlock interrupt  */
  1316.     intUnlock (intLevel);
  1317.     return (OK);
  1318.     }
  1319. /******************************************************************************
  1320. *
  1321. * motCpmEndPollSend - transmit a packet in polled mode
  1322. *
  1323. * This routine is called by a user to try and send a packet on the
  1324. * device. It sends a packet directly on the network from the caller without
  1325. * going through the normal processes of queuing a pacet on an output queue
  1326. * and the waiting for the device to decide to transmit it.
  1327. *
  1328. * If it detects a transmission error, the restart command is issued.
  1329. *
  1330. * These routine should not call any kernel functions.
  1331. *
  1332. * RETURNS: OK or EAGAIN
  1333. */
  1334. LOCAL STATUS motCpmEndPollSend
  1335.     (
  1336.     END_CTRL    *pDrvCtrl, /* pointer to END_CTRL structure */
  1337.     M_BLK_ID    pMblk /* data to send */
  1338.     )
  1339.     {
  1340.     int length;
  1341.     SCC_BUF * pTxBd;
  1342.     u_char * pad;
  1343.     char * pBuf;
  1344.     MOTCPMLOGMSG(("motCpmEndPollSend n", 0, 0, 0, 0, 0, 0));
  1345.     if (pDrvCtrl->txStop)
  1346. return (ERROR);
  1347.     /* get a free transmit frame descriptor */
  1348.     pTxBd = & pDrvCtrl->ether.txBdBase[pDrvCtrl->ether.txBdNext];
  1349.     /* check if a transmit buffer descriptor is available */
  1350.     if ((pTxBd->statusMode & SCC_ETHER_TX_BD_R) ||
  1351. (((pDrvCtrl->ether.txBdNext + 1) % pDrvCtrl->ether.txBdNum)
  1352. == pDrvCtrl->txBdIndexC))
  1353. {
  1354. return (EAGAIN);
  1355. }
  1356.     /* fill the transmit frame descriptor */
  1357.     
  1358.     pBuf = pDrvCtrl->txPoolBuf;   
  1359.  
  1360.     length = netMblkToBufCopy (pMblk, (char *)pBuf, NULL);
  1361.     pTxBd->dataPointer = (u_char *) pBuf;
  1362.     /* padding mechanism in Rev A is buggy - do in software */
  1363.     if (length < FRAME_MIN)
  1364. {
  1365. pad = pTxBd->dataPointer + length;
  1366. for (; length != FRAME_MIN; length++, pad++)
  1367.     *pad = 0x88;
  1368. }
  1369.     pTxBd->dataLength = length;
  1370.     if (pTxBd->statusMode & SCC_ETHER_TX_BD_W)
  1371. pTxBd->statusMode = SCC_ETHER_TX_BD_I | SCC_ETHER_TX_BD_PAD |
  1372.     SCC_ETHER_TX_BD_L | SCC_ETHER_TX_BD_TC  |
  1373.     SCC_ETHER_TX_BD_W | SCC_ETHER_TX_BD_R;
  1374.     else
  1375. pTxBd->statusMode = SCC_ETHER_TX_BD_I | SCC_ETHER_TX_BD_PAD |
  1376.     SCC_ETHER_TX_BD_L | SCC_ETHER_TX_BD_TC  |
  1377.     SCC_ETHER_TX_BD_R;
  1378.     /* incr BD count */
  1379.     pDrvCtrl->ether.txBdNext = (pDrvCtrl->ether.txBdNext + 1) %
  1380. pDrvCtrl->ether.txBdNum;
  1381.     /* Bump the statistic counter. */
  1382.     END_ERR_ADD (&pDrvCtrl->endObject, MIB2_OUT_UCAST, +1);
  1383.     /*
  1384.      * Spin until we've sent it.
  1385.      */
  1386.     while (pTxBd->statusMode & SCC_ETHER_TX_BD_R)
  1387. ;
  1388.     if (pTxBd->statusMode & (SCC_ETHER_TX_BD_RL | SCC_ETHER_TX_BD_UN |
  1389.     SCC_ETHER_TX_BD_CSL | SCC_ETHER_TX_BD_LC))
  1390. {
  1391. /* An error has occured, restart the transmitter */
  1392. pDrvCtrl->txStop = TRUE;
  1393. motCpmTxRestart (pDrvCtrl);
  1394. }
  1395.     /* 
  1396.      * we are allow to do this because transmit queue is empty when we
  1397.      * start polling mode.
  1398.      */
  1399.     pDrvCtrl->txBdIndexC = pDrvCtrl->ether.txBdNext;
  1400.     return (OK);
  1401.     }
  1402. /*******************************************************************************
  1403. *
  1404. * motCpmEndPollReceive - receive a packet in polled mode
  1405. *
  1406. * This routine is called by a user to try and get a packet from the
  1407. * device. It returns EAGAIN if no packet is available. The caller must
  1408. * supply a M_BLK_ID with enough space to contain the receiving packet. If
  1409. * enough buffer is not available then EAGAIN is returned.
  1410. *
  1411. * These routine should not call any kernel functions.
  1412. *
  1413. * RETURNS: OK or EAGAIN
  1414. */
  1415. LOCAL STATUS motCpmEndPollReceive
  1416.     (
  1417.     END_CTRL    *pDrvCtrl, /* pointer to END_CTRL structure */
  1418.     M_BLK_ID    pMblk
  1419.     )
  1420.     {
  1421.     SCC_BUF * pRxBd = & pDrvCtrl->ether.rxBdBase[pDrvCtrl->ether.rxBdNext];
  1422.     int length;
  1423.     int status = EAGAIN;
  1424.     MOTCPMLOGMSG(("motCpmEndPollReceive n", 0, 0, 0, 0, 0, 0));
  1425.     /* if we have not received packets, leave immediatly */
  1426.     if (pRxBd->statusMode & SCC_ETHER_RX_BD_E)
  1427. return (EAGAIN);
  1428.     /* check packets for errors */
  1429.     if (((pRxBd->statusMode & (SCC_ETHER_RX_BD_F  | SCC_ETHER_RX_BD_L))
  1430.    == (SCC_ETHER_RX_BD_F  | SCC_ETHER_RX_BD_L))
  1431.        && !(pRxBd->statusMode & (SCC_ETHER_RX_BD_CL |
  1432. SCC_ETHER_RX_BD_OV | SCC_ETHER_RX_BD_CR |
  1433. SCC_ETHER_RX_BD_SH | SCC_ETHER_RX_BD_NO |
  1434. SCC_ETHER_RX_BD_LG)))
  1435. {
  1436. /* adjust length to data only */
  1437. length = pRxBd->dataLength - 4;
  1438. if ((length - SIZEOF_ETHERHEADER) <= 0)
  1439.     {
  1440.     /* bump input error packet counter */
  1441.     END_ERR_ADD (&pDrvCtrl->endObject, MIB2_IN_ERRS, +1);
  1442.     goto cleanRxBd;
  1443.     }
  1444. /* 
  1445.  * Upper layer provides the buffer.
  1446.          * If buffer is not large enough, we return.
  1447.  */
  1448. /* copy data */
  1449.         if ((pMblk->mBlkHdr.mLen < length) ||
  1450.             (!(pMblk->mBlkHdr.mFlags & M_EXT)))
  1451.             {
  1452.             goto cleanRxBd;
  1453.             }
  1454.         
  1455. bcopy ((char *) pRxBd->dataPointer, (char *)pMblk->mBlkHdr.mData,
  1456.                length);
  1457. pMblk->mBlkHdr.mLen = length;
  1458. pMblk->mBlkPktHdr.len = length;
  1459. pMblk->mBlkHdr.mFlags |= M_PKTHDR;
  1460. /* bump input packet counter */
  1461. END_ERR_ADD (&pDrvCtrl->endObject, MIB2_IN_UCAST, +1);
  1462. status = OK;
  1463. }
  1464.     else
  1465. {
  1466. /* bump input error packet counter */
  1467. END_ERR_ADD (&pDrvCtrl->endObject, MIB2_IN_ERRS, +1);
  1468. }
  1469. cleanRxBd:
  1470.     motCpmCleanRxBd (pDrvCtrl, pRxBd); /* reset buffer descriptor as empty */
  1471.     return (status);
  1472.     }
  1473. /*******************************************************************************
  1474. *
  1475. * motCpmIntr - network interface interrupt handler
  1476. *
  1477. * This routine gets called at interrupt level. It handles work that 
  1478. * requires minimal processing. Interrupt processing that is more 
  1479. * extensive gets handled at task level. The network task, netTask(), is 
  1480. * provided for this function. Routines get added to the netTask() work 
  1481. * queue via the netJobAdd() command.
  1482. *
  1483. * RETURNS: N/A
  1484. */
  1485. LOCAL void motCpmIntr
  1486.     (
  1487.     END_CTRL * pDrvCtrl /* pointer to END_CTRL structure */
  1488.     )
  1489.     {
  1490.     BOOL rxHandle = FALSE;
  1491.     BOOL txbHandle = FALSE;
  1492.     
  1493.     /* check for spurious interrupt -> initialized ? */
  1494.     if (!pDrvCtrl->endObject.attached)
  1495. {
  1496.         pDrvCtrl->ether.pSccReg->scce = 0xffff;
  1497.         *CPM_CISR(pDrvCtrl->regBase) = pDrvCtrl->ether.intMask;
  1498. return;
  1499. }
  1500.     /* handle receive events */
  1501.     if ((pDrvCtrl->ether.pSccReg->sccm & SCC_ETHER_SCCX_RXF) &&
  1502.         (pDrvCtrl->ether.pSccReg->scce & SCC_ETHER_SCCX_RXF))
  1503. {
  1504.         (void) netJobAdd ((FUNCPTR) motCpmHandleInt, (int) pDrvCtrl, 
  1505.   0, 0, 0, 0); 
  1506. /* turn off receive interrupts for now - motCpmHandleIt turns back on */
  1507.         pDrvCtrl->ether.pSccReg->sccm &= ~SCC_ETHER_SCCX_RXF;
  1508. rxHandle = TRUE;
  1509.         }
  1510.     /* check for output errors */
  1511.     if (pDrvCtrl->ether.pSccReg->scce & SCC_ETHER_SCCX_TXE)
  1512. {
  1513. /* clean the transmit buffer descriptor queue */
  1514. /* NOTE: HBC error not supported -> always RESTART Tx here */
  1515.         (void) netJobAdd ((FUNCPTR) motCpmTxRestart, (int) pDrvCtrl, 
  1516.   0, 0, 0, 0);
  1517. pDrvCtrl->txStop = TRUE;
  1518. }
  1519.     /* handle transmitter events - BD full condition -> ever happen ? */
  1520.     if ((pDrvCtrl->ether.pSccReg->sccm & SCC_ETHER_SCCX_TXB) &&
  1521.         (pDrvCtrl->ether.pSccReg->scce & SCC_ETHER_SCCX_TXB))
  1522. {
  1523. txbHandle = TRUE;
  1524. }
  1525.     /* check for input busy condition */
  1526.     if (pDrvCtrl->ether.pSccReg->scce & SCC_ETHER_SCCX_BSY)
  1527.         pDrvCtrl->ether.pSccReg->scce = SCC_ETHER_SCCX_BSY; 
  1528.     /* acknowledge all other interrupts - ignore events */
  1529.     pDrvCtrl->ether.pSccReg->scce = (pDrvCtrl->ether.pSccReg->scce &
  1530.     ~(SCC_ETHER_SCCX_RXF |
  1531.       SCC_ETHER_SCCX_TXE |
  1532.       SCC_ETHER_SCCX_TXB |
  1533.       SCC_ETHER_SCCX_BSY));
  1534.     /* 
  1535.      * clean the transmit buffer descriptor queue if we have 
  1536.      * received a transmit interrupt and if we are not already
  1537.      * cleaning this transmit queue.
  1538.      */
  1539.     if ((pDrvCtrl->txStop || txbHandle) && !pDrvCtrl->txCleaning)
  1540.         {
  1541.      motCpmCleanTxBdQueue (pDrvCtrl);
  1542.         if (pDrvCtrl->txBlocked)
  1543.             {
  1544.             pDrvCtrl->txBlocked = FALSE;
  1545.             (void) netJobAdd ((FUNCPTR) muxTxRestart,
  1546.                               (int)&pDrvCtrl->endObject,
  1547.                               0, 0, 0, 0);
  1548.             }
  1549.         }
  1550.     /* acknowledge interrupts */
  1551.     if (rxHandle)
  1552.         pDrvCtrl->ether.pSccReg->scce = SCC_ETHER_SCCX_RXF; 
  1553.     if (pDrvCtrl->txStop)
  1554.         pDrvCtrl->ether.pSccReg->scce = SCC_ETHER_SCCX_TXE; 
  1555.     if (txbHandle)
  1556.         pDrvCtrl->ether.pSccReg->scce = SCC_ETHER_SCCX_TXB; 
  1557.     *CPM_CISR(pDrvCtrl->regBase) = pDrvCtrl->ether.intMask;
  1558.     }
  1559. /*******************************************************************************
  1560. *
  1561. * motCpmMCastFilterSet - set the group addres filter for a multicast addresse.
  1562. *
  1563. * To add an address in the processor group address hash filter, we use
  1564. * the SET GROUP ADDRESS command. This command can be executed at any 
  1565. * time, regadless of whether the Ethernet channel is enabled.
  1566. *
  1567. * RETURNS : N/A 
  1568. *
  1569. */
  1570. LOCAL void motCpmMCastFilterSet
  1571.     (
  1572.     END_CTRL *  pDrvCtrl, /* pointer to END_CTRL structure */
  1573.     char *      pAddress        /* Address to delete from the table. */
  1574.     )
  1575.     {
  1576.     MOTCPMLOGMSG(("motCpmMCastFilterSet n", 0, 0, 0, 0, 0, 0));
  1577.     /* add multicast address */
  1578.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->taddr_h =
  1579. (pAddress[5] << 8) + pAddress[4];
  1580.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->taddr_m =
  1581. (pAddress[3] << 8) + pAddress[2];
  1582.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->taddr_l =
  1583. (pAddress[1] << 8) + pAddress[0];
  1584.     /* issue the set group address command to the CP */
  1585.     while (*CPM_CPCR(pDrvCtrl->regBase) & CPM_CR_FLG);
  1586.     *CPM_CPCR(pDrvCtrl->regBase) = ((pDrvCtrl->ether.sccNum - 1) << 6) |
  1587.        CPM_CR_SCC_SET_GROUP |
  1588.        CPM_CR_FLG;
  1589.     while (*CPM_CPCR(pDrvCtrl->regBase) & CPM_CR_FLG);
  1590.     }
  1591. /*******************************************************************************
  1592. *
  1593. * motCpmMCastConfig - reconfigure the interface under us.
  1594. *
  1595. * Reconfigure the interface changing the multicast interface list.
  1596. *
  1597. * In order to delete an address from the hash tabke, the Ethernet channel
  1598. * should be disabled, the hash table registers should be cleared, and 
  1599. * the SET GROUP ADDRESS command must be executed for the remaining 
  1600. * desired addresses. This is required because the hash table may have mapped
  1601. * multiple addresses to the same hash table bit.
  1602. *
  1603. * RETURNS : N/A 
  1604. */
  1605. LOCAL void motCpmMCastConfig
  1606.     (
  1607.     END_CTRL *  pDrvCtrl /* pointer to END_CTRL structure */
  1608.     )
  1609.     {
  1610.     ETHER_MULTI * pCurr;
  1611.     MOTCPMLOGMSG(("motCpmMCastConfig n",0,0,0,0,0,0));
  1612.     /* disable the ethernet channel */
  1613.     motCpmReset (pDrvCtrl);
  1614.     /* clear hash table group registers */
  1615.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->gaddr1     = 0x0000;
  1616.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->gaddr2     = 0x0000;
  1617.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->gaddr3     = 0x0000;
  1618.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->gaddr4     = 0x0000;
  1619.     /* restore remaining addresses */
  1620.     for (pCurr = END_MULTI_LST_FIRST(&pDrvCtrl->endObject); pCurr != NULL;
  1621. pCurr = (ETHER_MULTI *)lstNext(&pCurr->node))
  1622. {
  1623. /* add multicast address */
  1624. motCpmMCastFilterSet (pDrvCtrl, pCurr->addr);
  1625. }
  1626.     /* restart the ethernet channel */
  1627.     motCpmRestart (pDrvCtrl);
  1628.     }
  1629. /*******************************************************************************
  1630. *
  1631. * motCpmRestart - network interface restart routine
  1632. *
  1633. * This routine restarts the device.  This includes enabling interrupts, 
  1634. * starting the transmitter and receiver, and calling the bsp-specific
  1635. * LAN enable routine to do any target specific enabling.
  1636. *
  1637. * This routine follows the instructions in MC68EN360/MPC821 Users's Manual :
  1638. * "Disabling the SCCs on the Fly"
  1639. *
  1640. * The complement of this routine is motCpmReset().  Once a unit is reset by
  1641. * motCpmReset(), it may be re-initialized to a running state by this routine.
  1642. *
  1643. * RETURNS: N/A
  1644. */
  1645. LOCAL STATUS motCpmRestart
  1646.     (
  1647.     END_CTRL *  pDrvCtrl /* pointer to END_CTRL structure */
  1648.     )
  1649.     {
  1650.     /* enable Ethernet interrupts */
  1651.     *CPM_CIMR(pDrvCtrl->regBase) |= pDrvCtrl->ether.intMask;
  1652.     /* call the BSP to do any other initialization (e.g., connecting clocks) */
  1653.     SYS_ENET_ENABLE;
  1654.     /* enable the transmitter */
  1655.     pDrvCtrl->ether.pSccReg->gsmrl |= SCC_GSMRL_ENT;
  1656.     /* issue the restart transmitter command to the CP */
  1657.     while (*CPM_CPCR(pDrvCtrl->regBase) & CPM_CR_FLG);
  1658.     *CPM_CPCR(pDrvCtrl->regBase) = ((pDrvCtrl->ether.sccNum - 1) << 6) |
  1659.       CPM_CR_SCC_RESTART |
  1660.       CPM_CR_FLG;
  1661.     while (*CPM_CPCR(pDrvCtrl->regBase) & CPM_CR_FLG);
  1662.     /* issue the enter hunt mode command to the CP */
  1663.     while (*CPM_CPCR(pDrvCtrl->regBase) & CPM_CR_FLG);
  1664.     *CPM_CPCR(pDrvCtrl->regBase) = ((pDrvCtrl->ether.sccNum - 1) << 6) |
  1665.       CPM_CR_SCC_HUNT |
  1666.       CPM_CR_FLG;
  1667.     while (*CPM_CPCR(pDrvCtrl->regBase) & CPM_CR_FLG);
  1668.     /* enable the receiver */
  1669.     pDrvCtrl->ether.pSccReg->gsmrl |= SCC_GSMRL_ENR;
  1670.     return (OK);
  1671.     }
  1672. /*******************************************************************************
  1673. *
  1674. * motCpmReset - network interface reset routine
  1675. *
  1676. * This routine resets the device.  This includes disabling interrupts, 
  1677. * stopping the transmitter and receiver, and calling the bsp-specific
  1678. * LAN disable routine to do any target specific disabling.
  1679. *
  1680. * This routine follows the instructions in MC68EN360/MPC821 Users's Manual :
  1681. * "Disabling the SCCs on the Fly"
  1682. *
  1683. * The complements of this routine are motCpmEndStart() and motCpmRestart().  
  1684. * Once a unit is reset in this routine, it may be re-started with parameters
  1685. * reinitialized with motCpmEndStart() or re-started with current parameteres 
  1686. * with  motCpmRestart().
  1687. *
  1688. * RETURNS: N/A
  1689. */
  1690. LOCAL void motCpmReset
  1691.     (
  1692.     END_CTRL *  pDrvCtrl /* pointer to END_CTRL structure */
  1693.     )
  1694.     {
  1695.     int counter = 0xffff;
  1696.     /* disable the SCC interrupts */
  1697.     *CPM_CIMR(pDrvCtrl->regBase) &= ~pDrvCtrl->ether.intMask;
  1698.     /* issue the CP graceful stop command to the transmitter if necessary */
  1699.     if (pDrvCtrl->ether.pSccReg->gsmrl & SCC_GSMRL_ENT)
  1700. {
  1701.         while (*CPM_CPCR(pDrvCtrl->regBase) & CPM_CR_FLG);
  1702.         *CPM_CPCR(pDrvCtrl->regBase) = ((pDrvCtrl->ether.sccNum - 1) << 6) |
  1703.                                           CPM_CR_SCC_GRSTOP | CPM_CR_FLG;
  1704.         while (*CPM_CPCR(pDrvCtrl->regBase) & CPM_CR_FLG);
  1705.         /* wait for graceful stop to register */
  1706.         while ((counter--) && (!(pDrvCtrl->ether.pSccReg->scce &
  1707.          SCC_ETHER_SCCX_GRA)));
  1708. }
  1709.     /* disable the SCC receiver and transmitter */
  1710.     pDrvCtrl->ether.pSccReg->gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
  1711.     /* call the BSP to do any other disabling (e.g., *TENA) */
  1712.     SYS_ENET_DISABLE;
  1713.     }
  1714. /*******************************************************************************
  1715. *
  1716. * motCpmTxRestart - issue RESTART Tx command to the CP
  1717. *
  1718. * This routine issues a RESTART transmitter command to the CP.  It is
  1719. * executed by netTask (motCpmIntr() did a netJobAdd).  motCpmIntr() cannot do
  1720. * a RESTART directly because the CPM flag must be taken before a command
  1721. * can be written.  
  1722. *
  1723. * RETURNS: N/A
  1724. */
  1725. LOCAL void motCpmTxRestart
  1726.     (
  1727.     END_CTRL * pDrvCtrl /* pointer to END_CTRL structure */
  1728.     )
  1729.     {
  1730.     MOTCPMLOGMSG(("motCpmTxRestart n", 0, 0, 0, 0, 0, 0));
  1731.     /* update error counter */
  1732.     END_ERR_ADD (&pDrvCtrl->endObject, MIB2_OUT_ERRS, +1);
  1733.     END_ERR_ADD (&pDrvCtrl->endObject, MIB2_OUT_UCAST, -1);
  1734.     /* restart transmitter */
  1735.     while (*CPM_CPCR(pDrvCtrl->regBase) & CPM_CR_FLG);
  1736.     *CPM_CPCR(pDrvCtrl->regBase) = ((pDrvCtrl->ether.sccNum - 1) << 6) |
  1737.                                       CPM_CR_SCC_RESTART | CPM_CR_FLG;
  1738.     while (*CPM_CPCR(pDrvCtrl->regBase) & CPM_CR_FLG);
  1739.     pDrvCtrl->txStop = FALSE;
  1740.     }
  1741. /*******************************************************************************
  1742. *
  1743. * motCpmHandleInt - task-level interrupt handler
  1744. *
  1745. * This is the task-level interrupt handler, which is called from 
  1746. * netTask(). motCpmIntr() gets input frames from the device and then calls 
  1747. * motCpmIntr() to process each frame. motCpmIntr() only gets called if no error
  1748. * stats were reported in the buffer descriptor.  Data chaining is not
  1749. * supported.
  1750. *
  1751. * This routine should be called with SCC receive interrupts masked so that
  1752. * more netJobAdds of this routine are not performed by motCpmIntr().
  1753. * Receive interrupts are turned back on by this routine before exiting.
  1754. *
  1755. * RETURNS: N/A
  1756. */
  1757. LOCAL void motCpmHandleInt
  1758.     (
  1759.     END_CTRL * pDrvCtrl /* pointer to END_CTRL structure */
  1760.     )
  1761.     {
  1762.     SCC_BUF * pRxBd = & pDrvCtrl->ether.rxBdBase[pDrvCtrl->ether.rxBdNext];
  1763.     while (!(pRxBd->statusMode & SCC_ETHER_RX_BD_E))
  1764.         {
  1765.         /* data chaining is not supported  - check all error conditions */
  1766.         if (((pRxBd->statusMode & (SCC_ETHER_RX_BD_F  | SCC_ETHER_RX_BD_L))
  1767.                        == (SCC_ETHER_RX_BD_F  | SCC_ETHER_RX_BD_L))
  1768.                       && !(pRxBd->statusMode & (SCC_ETHER_RX_BD_CL |
  1769.                    SCC_ETHER_RX_BD_OV | SCC_ETHER_RX_BD_CR |
  1770.    SCC_ETHER_RX_BD_SH | SCC_ETHER_RX_BD_NO |
  1771.    SCC_ETHER_RX_BD_LG)))
  1772.             motCpmRecv (pDrvCtrl, pRxBd);
  1773.         else
  1774.     {
  1775.             END_ERR_ADD (&pDrvCtrl->endObject, MIB2_IN_ERRS, +1);
  1776.     /* reset buffer descriptor as empty */
  1777.     motCpmCleanRxBd (pDrvCtrl, pRxBd);
  1778.     }
  1779.         /* update receive buffer descriptor pointer */
  1780.         pRxBd = & pDrvCtrl->ether.rxBdBase[pDrvCtrl->ether.rxBdNext];
  1781.         /* clear Rx events */
  1782.         pDrvCtrl->ether.pSccReg->scce = SCC_ETHER_SCCX_RXF;
  1783.         }
  1784.     /* re-enable Rx interrupts */
  1785.     pDrvCtrl->ether.pSccReg->sccm |= SCC_ETHER_SCCX_RXF;
  1786.     }
  1787. /*******************************************************************************
  1788. *
  1789. * motCpmRecv - process an input frame
  1790. *
  1791. * This routine processes an input frame, then passes it up to the higher 
  1792. * level in a form it expects.  Buffer loaning, promiscuous mode are all 
  1793. * supported.  Trailer protocols is not supported.
  1794. *
  1795. * RETURNS: N/A
  1796. */
  1797. LOCAL void motCpmRecv
  1798.     (
  1799.     END_CTRL * pDrvCtrl, /* pointer to END_CTRL structure */
  1800.     SCC_BUF * pRxBd /* receive buffer descriptor */
  1801.     )
  1802.     { 
  1803.     M_BLK_ID pMblk;
  1804.     CL_BLK_ID pClBlk;
  1805.     char * pNewCluster;
  1806.     if (((pRxBd->dataLength - 4) - SIZEOF_ETHERHEADER) <= 0)
  1807.         END_ERR_ADD (&pDrvCtrl->endObject, MIB2_IN_ERRS, +1);
  1808. motCpmCleanRxBd (pDrvCtrl, pRxBd);/* reset buffer descriptor as empty */
  1809. return;
  1810. }
  1811.     pNewCluster = netClusterGet (pDrvCtrl->endObject.pNetPool,
  1812.                                  pDrvCtrl->pClPoolId);
  1813.     if (pNewCluster == NULL)
  1814.         {
  1815.         END_ERR_ADD (&pDrvCtrl->endObject, MIB2_IN_ERRS, +1);
  1816. motCpmCleanRxBd (pDrvCtrl, pRxBd);/* reset buffer descriptor as empty */
  1817. return;
  1818.         }
  1819.     if ((pMblk = mBlkGet(pDrvCtrl->endObject.pNetPool,
  1820.                          M_DONTWAIT, MT_DATA)) == NULL)
  1821.         {
  1822.         netClFree (pDrvCtrl->endObject.pNetPool, (UCHAR *)pNewCluster);
  1823. END_ERR_ADD (&pDrvCtrl->endObject, MIB2_IN_ERRS, +1);
  1824. motCpmCleanRxBd (pDrvCtrl, pRxBd);/* reset buffer descriptor as empty */
  1825.         return;
  1826.         }
  1827.     if ((pClBlk = clBlkGet (pDrvCtrl->endObject.pNetPool, M_DONTWAIT))
  1828.         == NULL)
  1829.         {
  1830.         netMblkFree (pDrvCtrl->endObject.pNetPool, pMblk); 
  1831.         netClFree (pDrvCtrl->endObject.pNetPool, (UCHAR *)pNewCluster);
  1832. END_ERR_ADD (&pDrvCtrl->endObject, MIB2_IN_ERRS, +1);
  1833. motCpmCleanRxBd (pDrvCtrl, pRxBd);/* reset buffer descriptor as empty */
  1834.         return;
  1835.         }
  1836.     /* join the cluster block to the data buffer */
  1837.     netClBlkJoin (pClBlk, (char *) pRxBd->dataPointer, pRxBd->dataLength - 4,
  1838.                   NULL, 0, 0, 0);
  1839.     /* join the mBlk and cluster Block */
  1840.     netMblkClJoin (pMblk, pClBlk);
  1841.     /* intialize the mBlk */
  1842.     pMblk->mBlkHdr.mLen  = pRxBd->dataLength - 4;
  1843.     pMblk->mBlkHdr.mFlags  |= M_PKTHDR;
  1844.     pMblk->mBlkPktHdr.len  = pMblk->mBlkHdr.mLen;
  1845.     /* update receive buffer descriptor data pointer */
  1846.     pRxBd->dataPointer = (UCHAR *) pNewCluster;
  1847.     /* 
  1848.      * Reset buffer descriptor as empty
  1849.      * It is neccessary to do this before sending up the packet to the
  1850.      * protocol in case we switch to system mode. 
  1851.      */
  1852.     motCpmCleanRxBd (pDrvCtrl, pRxBd);
  1853.     /* send up to protocol */
  1854.     END_RCV_RTN_CALL (&pDrvCtrl->endObject, pMblk);
  1855.     /* bump input packet counter */
  1856.     END_ERR_ADD (&pDrvCtrl->endObject, MIB2_IN_UCAST, +1);
  1857.     }
  1858. /*******************************************************************************
  1859. *
  1860. * motCpmCleanRxBd - reset receive buffer descriptor as empty
  1861. *
  1862. * This routine resets receive buffer descriptor as empty
  1863. *
  1864. * RETURNS: N/A
  1865. */
  1866. LOCAL void motCpmCleanRxBd
  1867.     (
  1868.     END_CTRL * pDrvCtrl, /* pointer to END_CTRL structure */
  1869.     SCC_BUF * pRxBd /* receive buffer descriptor */
  1870.     )
  1871.     {
  1872.     /* reset buffer descriptor as empty */
  1873.     if (pRxBd->statusMode & SCC_ETHER_RX_BD_W)
  1874. pRxBd->statusMode = SCC_ETHER_RX_BD_E | SCC_ETHER_RX_BD_I |
  1875.     SCC_ETHER_RX_BD_W;
  1876.     else
  1877. pRxBd->statusMode = SCC_ETHER_RX_BD_E | SCC_ETHER_RX_BD_I;
  1878.     /* incr BD count */
  1879.     pDrvCtrl->ether.rxBdNext = (pDrvCtrl->ether.rxBdNext + 1) %
  1880. pDrvCtrl->ether.rxBdNum;
  1881.     }
  1882. /*******************************************************************************
  1883. *
  1884. * motCpmCleanTxBdQueue - clean the transmit buffer descriptor queue
  1885. *
  1886. * This routine cleans the transmit buffer queue. It doesn't look for 
  1887. * transmission errors, this is done at interrupt level in motCpmIntr.
  1888. *
  1889. * RETURNS: N/A
  1890. *
  1891. */
  1892. LOCAL void motCpmCleanTxBdQueue
  1893.     (
  1894.     END_CTRL *  pDrvCtrl /* pointer to END_CTRL structure */
  1895.     )
  1896.     {
  1897.     SCC_BUF *  pTxBd;
  1898.     int oldLevel;
  1899.     MOTCPMLOGMSG(("motCpmCleanTxBdQueue n", 0, 0, 0, 0, 0, 0));
  1900.     pDrvCtrl->txCleaning = TRUE;
  1901.     while (pDrvCtrl->txBdIndexC != pDrvCtrl->ether.txBdNext)
  1902. {
  1903. pTxBd = & pDrvCtrl->ether.txBdBase[pDrvCtrl->txBdIndexC];
  1904. /* if the data buffer has not been transmitted, don't touch it */
  1905. if (pTxBd->statusMode & SCC_ETHER_TX_BD_R)
  1906.     break;
  1907. oldLevel = intLock();
  1908. if (pDrvCtrl->freeRtn[pDrvCtrl->txBdIndexC] != NULL)
  1909.     {
  1910.     pDrvCtrl->freeRtn[pDrvCtrl->txBdIndexC]
  1911.     (pDrvCtrl->freeData[pDrvCtrl->txBdIndexC].arg1,
  1912.      pDrvCtrl->freeData[pDrvCtrl->txBdIndexC].arg2);
  1913.     pDrvCtrl->freeRtn[pDrvCtrl->txBdIndexC] = NULL;
  1914.     pDrvCtrl->freeData[pDrvCtrl->txBdIndexC].arg1 = NULL;
  1915.     pDrvCtrl->freeData[pDrvCtrl->txBdIndexC].arg2 = NULL;
  1916.     }
  1917. intUnlock(oldLevel);
  1918. /* incr txBdIndexC */
  1919. pDrvCtrl->txBdIndexC = (pDrvCtrl->txBdIndexC + 1) %
  1920.        pDrvCtrl->ether.txBdNum;
  1921. }
  1922.     pDrvCtrl->txCleaning = FALSE;
  1923.     }
  1924. /* END OF FILE */