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

VxWorks

开发平台:

C/C++

  1. /* if_cpm.c - Motorola CPM core network interface driver */
  2. /* Copyright 1996-1998 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01f,13apr98,map  modified SCC_DEV to SCC_ETHER_DEV.
  8. 01e,15jul97,spm  removed driver initialization from ioctl support (SPR #8831);
  9.                  corrected wait in reset routine; 
  10.                  changed interrupt handler to match if_qu driver
  11. 01d,07apr97,spm  code cleanup, corrected statistics, and upgraded to BSD 4.4
  12. 01c,06nov96,dgp  doc: final formatting
  13. 01b,06aug96,dat  fixed scce register handling, and interrupt service rtn
  14. 01a,09may96,dzb  derived from v01e of src/drv/netif/if_qu.c.
  15. */
  16. /*
  17. DESCRIPTION
  18. This module implements the driver for the Motorola CPM core Ethernet network
  19. interface used in the M68EN360 and PPC800-series communications controllers.
  20. The driver is designed to support the Ethernet mode of an SCC residing on the
  21. CPM processor core.  It is generic in the sense that it does not care
  22. which SCC is being used, and it supports up to four individual units per board.
  23. The driver must be given several target-specific parameters, and some external
  24. support routines must be provided.  These parameters, and the mechanisms used
  25. to communicate them to the driver, are detailed below.
  26. This network interface driver does not include support for trailer protocols
  27. or data chaining.  However, buffer loaning has been implemented in an effort to
  28. boost performance. This driver provides support for four individual device 
  29. units.
  30. This driver maintains cache coherency by allocating buffer space using the
  31. cacheDmaMalloc() routine.  It is assumed that cache-safe memory is returned;
  32. this driver does not perform cache flushing and invalidating.
  33. BOARD LAYOUT
  34. This device is on-chip.  No jumpering diagram is necessary.
  35. EXTERNAL INTERFACE
  36. This driver presents the standard WRS network driver API: the device
  37. unit must be attached and initialized with the cpmattach() routine.
  38. The only user-callable routine is cpmattach(), which publishes the `cpm'
  39. interface and initializes the driver structures.
  40. TARGET-SPECIFIC PARAMETERS
  41. These parameters are passed to the driver via cpmattach().
  42. .iP "address of SCC parameter RAM"
  43. This parameter is the address of the parameter RAM used to control the
  44. SCC.  Through this address, and the address of the SCC
  45. registers (see below), different network interface units are able to use
  46. different SCCs without conflict.  This parameter points to the internal
  47. memory of the chip where the SCC physically resides, which may not necessarily
  48. be the master chip on the target board.
  49. .iP "address of SCC registers"
  50. This parameter is the address of the registers used to control the
  51. SCC.  Through this address, and the address of the SCC
  52. parameter RAM (see above), different network interface units are able to use
  53. different SCCs without conflict.  This parameter points to the internal
  54. memory of the chip where the SCC physically resides, which may not necessarily
  55. be the master chip on the target board.
  56. .iP "interrupt-vector offset"
  57. This driver configures the SCC to generate hardware interrupts
  58. for various events within the device.  The interrupt-vector offset
  59. parameter is used to connect the driver's ISR to the interrupt through
  60. a call to intConnect().
  61. .iP "address of transmit and receive buffer descriptors"
  62. These parameters indicate the base locations of the transmit and receive
  63. buffer descriptor (BD) rings.  Each BD takes up 8 bytes of
  64. dual-ported RAM, and it is the user's responsibility to ensure that all
  65. specified BDs will fit within dual-ported RAM.  This includes any other
  66. BDs the target board may be using, including other SCCs, SMCs, and the
  67. SPI device.  There is no default for these parameters; they must be
  68. provided by the user.
  69. .iP "number of transmit and receive buffer descriptors"
  70. The number of transmit and receive buffer descriptors (BDs) used is
  71. configurable by the user upon attaching the driver.  Each buffer
  72. descriptor resides in 8 bytes of the chip's dual-ported RAM space,
  73. and each one points to a 1520-byte buffer in regular RAM.  There must
  74. be a minimum of two transmit and two receive BDs.  There is no maximum
  75. number of buffers, but there is a limit to how much the driver speed increases
  76. as more buffers are added, and dual-ported RAM space is at a premium.
  77. If this parameter is "NULL", a default value of 32 BDs is used.
  78. .iP "base address of buffer pool"
  79. This parameter is used to notify the driver that space for the transmit
  80. and receive buffers need not be allocated, but should be taken from a
  81. cache-coherent private memory space provided by the user at the given
  82. address.  The user should be aware that memory used for buffers must be
  83. 4-byte aligned and non-cacheable.  All the buffers
  84. must fit in the given memory space; no checking is performed.
  85. This includes all transmit and receive buffers (see above) and an
  86. additional 16 receive loaner buffers.  If the number of receive
  87. BDs is less than 16, that number of loaner buffers is
  88. used.  Each buffer is 1520 bytes.  If this parameter is "NONE," space
  89. for buffers is obtained by calling cacheDmaMalloc() in cpmattach().
  90. .LP
  91. EXTERNAL SUPPORT REQUIREMENTS
  92. This driver requires seven external support functions:
  93. .iP "STATUS sysCpmEnetEnable (int unit)" "" 9 -1
  94. This routine is expected to perform any target-specific functions required
  95. to enable the Ethernet controller.  These functions typically include
  96. enabling the Transmit Enable signal (TENA) and connecting the transmit
  97. and receive clocks to the SCC.
  98. The driver calls this routine, once per unit, from the cpmInit() routine.
  99. .iP "void sysCpmEnetDisable (int unit)"
  100. This routine is expected to perform any target-specific functions required
  101. to disable the Ethernet controller.  This usually involves disabling the
  102. Transmit Enable (TENA) signal.
  103. The driver calls this routine from the cpmReset() routine each time a unit
  104. is disabled.
  105. .iP "STATUS sysCpmEnetCommand (int unit, UINT16 command)"
  106. This routine is expected to issue a command to the Ethernet interface
  107. controller.  The driver calls this routine to perform basic commands,
  108. such as restarting the transmitter and stopping reception.
  109. .iP "void sysCpmEnetIntEnable (int unit)"
  110. This routine is expected to enable the interrupt for the Ethernet interface
  111. specified by <unit>.
  112. .iP "void sysCpmEnetIntDisable (int unit)"
  113. This routine is expected to disable the interrupt for the Ethernet interface
  114. specified by <unit>.
  115. .iP "void sysCpmEnetIntClear (int unit)"
  116. This routine is expected to clear the interrupt for the Ethernet interface
  117. specified by <unit>.
  118. .iP "STATUS sysCpmEnetAddrGet (int unit, UINT8 * addr)"
  119. The driver expects this routine to provide the 6-byte Ethernet
  120. hardware address that will be used by <unit>.  This routine must copy
  121. the 6-byte address to the space provided by <addr>.  This routine is
  122. expected to return OK on success, or ERROR.
  123. The driver calls this routine, once per unit, from the cpmInit() routine.
  124. .LP
  125. SYSTEM RESOURCE USAGE
  126. This driver requires the following system resources:
  127.     - one mutual exclusion semaphore
  128.     - one interrupt vector
  129.     - 0 bytes in the initialized data section (data)
  130.     - 1272 bytes in the uninitialized data section (BSS)
  131.  
  132. The data and BSS sections are quoted for the CPU32 architecture and may vary
  133. for other architectures.  The code size (text) varies greatly between
  134. architectures, and is therefore not quoted here.
  135. If the driver allocates the memory shared with the Ethernet device unit,
  136. it does so by calling the cacheDmaMalloc() routine.  For the default case
  137. of 32 transmit buffers, 32 receive buffers, and 16 loaner buffers, the total
  138. size requested is 121,600 bytes.  If a non-cacheable memory region is provided
  139. by the user, the size of this region should be this amount, unless the
  140. user has specified a different number of transmit or receive BDs.
  141. This driver can operate only if the shared memory region is non-cacheable,
  142. or if the hardware implements bus snooping.  The driver cannot maintain
  143. cache coherency for the device because the buffers are asynchronously
  144. modified by both the driver and the device, and these fields may share the
  145. same cache line.  Additionally, the chip's dual ported RAM must be
  146. declared as non-cacheable memory where applicable.
  147. SEE ALSO: ifLib,
  148. .I "Motorola MC68EN360 User's Manual",
  149. .I "Motorola MPC860 User's Manual",
  150. .I "Motorola MPC821 User's Manual"
  151. INTERNAL
  152. */
  153. /* includes */
  154. #include "vxWorks.h"
  155. #include "iv.h"
  156. #include "taskLib.h"
  157. #include "memLib.h"
  158. #include "ioctl.h"
  159. #include "etherLib.h"
  160. #include "net/mbuf.h"
  161. #include "net/protosw.h"
  162. #include "socket.h"
  163. #include "errno.h"
  164. #include "net/if.h"
  165. #include "net/unixLib.h"
  166. #include "net/route.h"
  167. #include "netinet/in.h"
  168. #include "netinet/in_systm.h"
  169. #include "netinet/in_var.h"
  170. #include "netinet/ip.h"
  171. #include "netinet/if_ether.h"
  172. #include "net/if_subr.h"
  173. #include "cacheLib.h"
  174. #include "stdio.h"
  175. #include "intLib.h"
  176. #include "netLib.h"
  177. #include "drv/netif/netifDev.h"
  178. #include "drv/netif/if_cpm.h"
  179. /* defines */
  180. #define MAX_UNITS 4 /* max cpm units */
  181. #define ENET_ADDR_SIZE 0x6 /* size of Ethernet src/dest addresses */
  182. #define TX_BD_MIN 2 /* minimum number of Tx buffer descriptors */
  183. #define RX_BD_MIN 2 /* minimum number of Rx buffer descriptors */
  184. #define TX_BD_DEFAULT 0x20 /* default number of Tx buffer descriptors */
  185. #define RX_BD_DEFAULT 0x20 /* default number of Rx buffer descriptors */
  186. #define FRAME_MAX 0x05ee /* maximum frame size */
  187. #define FRAME_MAX_AL 0x05f0 /* maximum frame size, 4 byte alligned */
  188. #define FRAME_MIN 0x0040 /* minimum frame size */
  189. #define L_POOL 0x10 /* number of Rx loaner buffers in pool */
  190. /* typedefs */
  191. typedef struct mbuf MBUF;
  192. typedef struct arpcom IDR; /* Interface Data Record */
  193. typedef struct ifnet IFNET;
  194. typedef struct sockaddr SOCK;
  195. typedef struct drv_ctrl /* DRV_CTRL */
  196.     {
  197.     IDR idr; /* Interface Data Record */
  198.     BOOL attached; /* indicates unit is attached */
  199.     BOOL txStop; /* emergency stop output */
  200.     int nLoanRxBd; /* number of receive buffers left to loan */
  201.     UINT8 * lPool[L_POOL]; /* receive BD loaner pool */
  202.     UINT8 * pRefCnt[L_POOL];/* stack of reference count pointers */
  203.     UINT8 refCnt[L_POOL]; /* actual reference count values */
  204.     SCC_ETHER_DEV ether; /* Ethernet SCC device */
  205.     } DRV_CTRL;
  206. /* globals */
  207. IMPORT STATUS sysCpmEnetEnable  (int unit);
  208. IMPORT void   sysCpmEnetDisable (int unit);
  209. IMPORT STATUS sysCpmEnetAddrGet (int unit, UINT8 * addr);
  210. IMPORT STATUS sysCpmEnetCommand (int unit, UINT16 command);
  211. IMPORT void   sysCpmEnetIntEnable (int unit);
  212. IMPORT void   sysCpmEnetIntDisable (int unit);
  213. IMPORT void   sysCpmEnetIntClear (int unit);
  214. /* locals */
  215. LOCAL DRV_CTRL drvCtrl[MAX_UNITS]; /* array of driver control */
  216. /* forward declarations */
  217. #ifdef __STDC__
  218. LOCAL STATUS    cpmInit (int unit);
  219. #ifdef BSD43_DRIVER
  220. LOCAL int       cpmOutput (IFNET * pIfNet, MBUF * pMbuf, SOCK * pSock);
  221. LOCAL void      cpmStartOutput (int unit);
  222. #else
  223. LOCAL void      cpmStartOutput (DRV_CTRL * pDrvCtrl);
  224. #endif
  225. LOCAL int       cpmIoctl (IFNET * pIfNet, int cmd, caddr_t data);
  226. LOCAL STATUS    cpmReset (int unit);
  227. LOCAL void      cpmIntr (int unit);
  228. LOCAL void cpmTxRestart (int unit);
  229. LOCAL void      cpmHandleInt (DRV_CTRL * pDrvCtrl);
  230. LOCAL void      cpmRecv (DRV_CTRL * pDrvCtrl, SCC_BUF * pRxBd);
  231. LOCAL void      cpmLoanFree (DRV_CTRL * pDrvCtrl, UINT8 * pRxBuf, UINT8 * pRef);
  232. #else  /* __STDC__ */
  233. LOCAL STATUS    cpmInit ();
  234. LOCAL int       cpmOutput ();
  235. LOCAL void      cpmStartOutput ();
  236. LOCAL int       cpmIoctl ();
  237. LOCAL STATUS    cpmReset ();
  238. LOCAL void      cpmIntr ();
  239. LOCAL void cpmTxRestart ();
  240. LOCAL void      cpmHandleInt ();
  241. LOCAL void      cpmRecv (); 
  242. LOCAL void      cpmLoanFree (); 
  243. #endif  /* __STDC__ */
  244. /*******************************************************************************
  245. *
  246. * cpmattach - publish the `cpm' network interface and initialize the driver
  247. *
  248. * The routine publishes the `cpm' interface by filling in a network Interface
  249. * Data Record (IDR) and adding this record to the system's interface list.
  250. *
  251. * The SCC shares a region of memory with the driver.  The caller of this
  252. * routine can specify the address of a shared, non-cacheable memory region
  253. * with <bufBase>.  If this parameter is NONE, the driver obtains this
  254. * memory region by calling cacheDmaMalloc().  Non-cacheable memory space
  255. * is important for cases where the SCC is operating with a processor
  256. * that has a data cache.
  257. *
  258. * Once non-cacheable memory is obtained, this routine divides up the
  259. * memory between the various buffer descriptors (BDs).  The number
  260. * of BDs can be specified by <txBdNum> and <rxBdNum>, or if NULL, a
  261. * default value of 32 BDs will be used.  Additional buffers are
  262. * reserved as receive loaner buffers.  The number of loaner buffers is the
  263. * lesser of <rxBdNum> and a default value of 16.
  264. *
  265. * The user must specify the location of the transmit and receive BDs in
  266. * the CPU's dual-ported RAM.  <txBdBase> and <rxBdBase> give the
  267. * base address of the BD rings.  Each BD uses 8 bytes. Care must be taken so
  268. * that the specified locations for Ethernet BDs do not conflict with other
  269. * dual-ported RAM structures. 
  270. *
  271. * Up to four individual device units are supported by this driver.  Device
  272. * units may reside on different processor chips, or may be on different SCCs
  273. * within a single CPU.
  274. * Before this routine returns, it calls cpmReset() and cpmInit() to 
  275. * configure the Ethernet controller, and connects the interrupt vector <ivec>.
  276. *
  277. * RETURNS: OK or ERROR.
  278. *
  279. * SEE ALSO: ifLib,
  280. * .I "Motorola MC68360 User's Manual",
  281. * .I "Motorola MPC821 and MPC860 User's Manual"
  282. */
  283. STATUS cpmattach
  284.     (
  285.     int unit, /* unit number */
  286.     SCC * pScc, /* address of SCC parameter RAM */
  287.     SCC_REG * pSccReg, /* address of SCC registers */
  288.     VOIDFUNCPTR * ivec, /* interrupt vector offset */
  289.     SCC_BUF * txBdBase, /* transmit buffer descriptor base address */
  290.     SCC_BUF * rxBdBase, /* receive buffer descriptor base address */
  291.     int txBdNum, /* number of transmit buffer descriptors */
  292.     int rxBdNum, /* number of receive buffer descriptors */
  293.     UINT8 * bufBase /* address of memory pool; NONE = malloc it */
  294.     )
  295.     {
  296.     DRV_CTRL * pDrvCtrl;
  297.     int counter;
  298.     int loanNum = L_POOL;
  299.     UINT8 * txBuf;
  300.     UINT8 * rxBuf;
  301.     UINT8 * loanBuf;
  302.      
  303.     if (unit < 0 || unit >= MAX_UNITS) /* sanity check the unit number */
  304.  return (ERROR);
  305.   
  306.     pDrvCtrl = & drvCtrl[unit];
  307.     
  308.     /* ensure single invocation */
  309.     if (pDrvCtrl->attached)
  310.         return (ERROR);
  311.     /* do a quick check of input parameters */
  312.     if (txBdBase == rxBdBase)
  313. return (ERROR);
  314.     /* publish the Interface Data Record */
  315. #ifdef BSD43_DRIVER
  316.     ether_attach (& pDrvCtrl->idr.ac_if, unit, "cpm", (FUNCPTR) cpmInit,
  317.                   (FUNCPTR) cpmIoctl, (FUNCPTR) cpmOutput, (FUNCPTR) cpmReset);
  318. #else
  319.     ether_attach (
  320.                  &pDrvCtrl->idr.ac_if, 
  321.                  unit, 
  322.                  "cpm", 
  323.                  (FUNCPTR) cpmInit,
  324.                  (FUNCPTR) cpmIoctl, 
  325.                  (FUNCPTR) ether_output, 
  326.                  (FUNCPTR) cpmReset
  327.                  );
  328.     pDrvCtrl->idr.ac_if.if_start = (FUNCPTR)cpmStartOutput;
  329. #endif
  330.     /* use default number of buffer descriptors if user did not specify */
  331.     if (txBdNum == NULL)
  332. txBdNum = TX_BD_DEFAULT;
  333.     if (rxBdNum == NULL)
  334. rxBdNum = RX_BD_DEFAULT;
  335.     /* must be at least two transmit and receive buffer descriptors */
  336.     txBdNum = max (TX_BD_MIN, txBdNum);
  337.     rxBdNum = max (RX_BD_MIN, rxBdNum);
  338.     loanNum = min (rxBdNum, loanNum); 
  339.     /* fill in driver control structure for <unit> */
  340.     pDrvCtrl->nLoanRxBd       = loanNum;
  341.     pDrvCtrl->ether.txBdNum   = txBdNum;
  342.     pDrvCtrl->ether.rxBdNum   = rxBdNum;
  343.     pDrvCtrl->ether.txBdBase  = txBdBase;
  344.     pDrvCtrl->ether.rxBdBase  = rxBdBase;
  345.     pDrvCtrl->ether.txBufSize = FRAME_MAX_AL;
  346.     pDrvCtrl->ether.rxBufSize = FRAME_MAX_AL;
  347.     pDrvCtrl->ether.pScc      = pScc;
  348.     pDrvCtrl->ether.pSccReg   = pSccReg;
  349.     
  350.     /* set up Rx and Tx buffers */
  351.     if (bufBase == (UINT8 *) NONE)
  352. {
  353.         /* allocate memory pools */
  354. txBuf = cacheDmaMalloc (txBdNum * pDrvCtrl->ether.txBufSize);
  355.         if (txBuf == NULL)
  356.     return (ERROR);
  357. rxBuf = cacheDmaMalloc (rxBdNum * pDrvCtrl->ether.rxBufSize);
  358.         if (rxBuf == NULL)
  359.     {
  360.     free (txBuf);
  361.     return (ERROR);
  362.     }
  363.         loanBuf = cacheDmaMalloc (loanNum * pDrvCtrl->ether.rxBufSize);
  364. if (loanBuf == NULL)
  365.             pDrvCtrl->nLoanRxBd = 0;
  366.         }
  367.     else
  368. {
  369. /* use passed in address as memory pool - assume OK */
  370. txBuf   = bufBase;
  371. rxBuf   = (UINT8 *) (txBuf + (txBdNum * pDrvCtrl->ether.txBufSize));
  372. loanBuf = (UINT8 *) (rxBuf + (rxBdNum * pDrvCtrl->ether.rxBufSize));
  373. }
  374.     /* assign buffer addresses */
  375.     for (counter = 0; counter < txBdNum; counter++)
  376.         pDrvCtrl->ether.txBdBase[counter].dataPointer = (txBuf + (counter *
  377.     pDrvCtrl->ether.txBufSize));
  378.     for (counter = 0; counter < rxBdNum; counter++)
  379.         pDrvCtrl->ether.rxBdBase[counter].dataPointer = (rxBuf + (counter *
  380.     pDrvCtrl->ether.rxBufSize));
  381.     for (counter = 0; counter < pDrvCtrl->nLoanRxBd; counter++)
  382.         {
  383.         pDrvCtrl->lPool[counter] = (loanBuf + (counter *
  384.     pDrvCtrl->ether.rxBufSize));
  385.         pDrvCtrl->refCnt[counter] = 0;
  386. pDrvCtrl->pRefCnt[counter] = & pDrvCtrl->refCnt[counter];
  387.         }
  388.     /* reset the chip */
  389.     if (cpmReset (unit) == ERROR)
  390.         return (ERROR);
  391.     /* connect the interrupt handler cpmIntr() */
  392.     if (intConnect (ivec, (VOIDFUNCPTR) cpmIntr, unit) == ERROR)
  393.         return (ERROR);
  394.     /* Initialize and start controller */
  395.     cpmInit (unit);
  396.     /* mark driver as attached */
  397.     pDrvCtrl->attached = TRUE;
  398.     return (OK);
  399.     }
  400. /*******************************************************************************
  401. *
  402. * cpmInit - network interface initialization routine
  403. *
  404. * This routine marks the interface as down, then configures and initializes
  405. * the chip.  It sets up the transmit and receive buffer descriptor (BD)
  406. * rings, initializes registers, and enables interrupts.  Finally, it marks
  407. * the interface as up and running.  It does not touch the receive loaner
  408. * buffer stack.
  409. *
  410. * The complement of this routine is cpmReset().  Once a unit is reset by
  411. * cpmReset(), it may be re-initialized to a running state by this routine.
  412. *
  413. * RETURNS: OK if successful, otherwise ERROR.
  414. */
  415. LOCAL STATUS cpmInit
  416.     (
  417.     int unit /* unit number */
  418.     )
  419.     {
  420.     DRV_CTRL * pDrvCtrl;
  421.     UINT8 enetAddr[ENET_ADDR_SIZE];
  422.     int counter;
  423.     /* sanity check the unit number */
  424.     if (unit < 0 || unit >= MAX_UNITS)
  425.  return (ERROR);
  426.     pDrvCtrl = & drvCtrl[unit];
  427.     /* mark the device as down */
  428.  
  429.     pDrvCtrl->idr.ac_if.if_flags &= ~(IFF_UP | IFF_RUNNING);
  430.     /* initialize flag(s) */
  431.     pDrvCtrl->txStop = FALSE;
  432.     /* set up transmit buffer descriptors */
  433.     pDrvCtrl->ether.pScc->param.tbase = (UINT16)
  434. ((UINT32) pDrvCtrl->ether.txBdBase & 0xfff);
  435.     pDrvCtrl->ether.pScc->param.tbptr = (UINT16)
  436. ((UINT32) pDrvCtrl->ether.txBdBase & 0xfff);
  437.     pDrvCtrl->ether.txBdNext  = 0;
  438.     /* initialize each transmit buffer descriptor */
  439.      
  440.     for (counter = 0; counter < pDrvCtrl->ether.txBdNum; counter++)
  441.         pDrvCtrl->ether.txBdBase[counter].statusMode = SCC_ETHER_TX_BD_I |
  442.                                                        SCC_ETHER_TX_BD_PAD |
  443.                                                        SCC_ETHER_TX_BD_L |
  444.                                                        SCC_ETHER_TX_BD_TC;
  445.     /* set the last BD to wrap to the first */
  446.     pDrvCtrl->ether.txBdBase[(counter - 1)].statusMode |= SCC_ETHER_TX_BD_W;
  447.     /* set up receive buffer descriptors */
  448.     pDrvCtrl->ether.pScc->param.rbase = (UINT16)
  449. ((UINT32) pDrvCtrl->ether.rxBdBase & 0xfff);
  450.     pDrvCtrl->ether.pScc->param.rbptr = (UINT16)
  451. ((UINT32) pDrvCtrl->ether.rxBdBase & 0xfff);
  452.     pDrvCtrl->ether.rxBdNext  = 0;
  453.     /* initialize each receive buffer descriptor */
  454.     for (counter = 0; counter < pDrvCtrl->ether.rxBdNum; counter++)
  455.         pDrvCtrl->ether.rxBdBase[counter].statusMode = SCC_ETHER_RX_BD_I |
  456.                 SCC_ETHER_RX_BD_E;
  457.     /* set the last BD to wrap to the first */
  458.     pDrvCtrl->ether.rxBdBase[(counter - 1)].statusMode |= SCC_ETHER_RX_BD_W;
  459.     /* set SCC attributes to Ethernet mode */
  460.  
  461.     pDrvCtrl->ether.pSccReg->gsmrl    = SCC_GSMRL_ETHERNET | SCC_GSMRL_TPP_10 |
  462.                                         SCC_GSMRL_TPL_48   | SCC_GSMRL_TCI;
  463.     pDrvCtrl->ether.pSccReg->gsmrh    = 0x0;
  464.     pDrvCtrl->ether.pSccReg->psmr     = SCC_ETHER_PSMR_CRC |
  465. SCC_ETHER_PSMR_NIB_22;
  466.  
  467.     if (pDrvCtrl->idr.ac_if.if_flags & IFF_PROMISC)
  468.         pDrvCtrl->ether.pSccReg->psmr |= SCC_ETHER_PSMR_PRO;
  469.  
  470.     pDrvCtrl->ether.pSccReg->dsr      = 0xd555;
  471.     pDrvCtrl->ether.pScc->param.rfcr  = 0x18;      /* supervisor data access */
  472.     pDrvCtrl->ether.pScc->param.tfcr  = 0x18;      /* supervisor data access */
  473.     pDrvCtrl->ether.pScc->param.mrblr = FRAME_MAX_AL;  /* max rx buffer size */
  474.     /* initialize parameter the SCC RAM */
  475.  
  476.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->c_pres = 0xffffffff;
  477.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->c_mask = 0xdebb20e3;
  478.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->crcec = 0x00000000;
  479.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->alec = 0x00000000;
  480.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->disfc = 0x00000000;
  481.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->pads = 0x8888;
  482.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->ret_lim = 0x000f;
  483.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->mflr = FRAME_MAX;
  484.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->minflr = FRAME_MIN;
  485.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->maxd1 = FRAME_MAX;
  486.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->maxd2 = FRAME_MAX;
  487.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->gaddr1 = 0x0000;
  488.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->gaddr2 = 0x0000;
  489.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->gaddr3 = 0x0000;
  490.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->gaddr4 = 0x0000;
  491.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->p_per = 0x0000;
  492.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->iaddr1 = 0x0000;
  493.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->iaddr2 = 0x0000;
  494.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->iaddr3 = 0x0000;
  495.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->iaddr4 = 0x0000;
  496.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->taddr_h = 0x0000;
  497.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->taddr_m = 0x0000;
  498.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->taddr_l = 0x0000;
  499.     /* set the hardware Ethernet address of the board */
  500.     if (sysCpmEnetAddrGet (unit, (UINT8 *) & enetAddr) == ERROR)
  501. return (ERROR);
  502.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->paddr1_h =
  503.         (enetAddr[5] << 8) + enetAddr[4];
  504.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->paddr1_m =
  505.         (enetAddr[3] << 8) + enetAddr[2];
  506.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->paddr1_l =
  507.         (enetAddr[1] << 8) + enetAddr[0];
  508.     bcopy ((char *) enetAddr, (char *) pDrvCtrl->idr.ac_enaddr, ENET_ADDR_SIZE);
  509.     /* enable Ethernet interrupts */
  510.     pDrvCtrl->ether.pSccReg->scce = 0xffff; /* clr events */
  511.     pDrvCtrl->ether.pSccReg->sccm = SCC_ETHER_SCCX_RXF | SCC_ETHER_SCCX_TXE;
  512.     sysCpmEnetIntEnable (unit); /* unmask interrupts */
  513.     /* call the BSP to do any other initialization (e.g., connecting clocks) */
  514.     if (sysCpmEnetEnable (unit) == ERROR)
  515. return (ERROR);
  516.     /* raise the interface flags - mark the device as up */
  517.  
  518.     pDrvCtrl->idr.ac_if.if_flags |= IFF_UP | IFF_RUNNING | IFF_NOTRAILERS;
  519.     /* enable the transmitter */
  520.     pDrvCtrl->ether.pSccReg->gsmrl |= SCC_GSMRL_ENT;
  521.     /* issue the restart transmitter command to the CP */
  522.     (void) sysCpmEnetCommand (unit, CPM_CR_SCC_RESTART);
  523.     /* enable the receiver */
  524.     pDrvCtrl->ether.pSccReg->gsmrl |= SCC_GSMRL_ENR;
  525.     return (OK);
  526.     }
  527. #ifdef BSD43_DRIVER
  528. /*******************************************************************************
  529. *
  530. * cpmOutput - network interface output routine
  531. *
  532. * This routine simply calls ether_output(). ether_output() resolves 
  533. * the hardware addresses and calls cpmStartOutput() with the unit number
  534. * passed as an argument.
  535. *
  536. * RETURNS: OK if successful, otherwise errno.
  537. */
  538. LOCAL int cpmOutput
  539.     (
  540.     IFNET * pIfNet, /* pointer to IFNET structure */
  541.     MBUF * pMbuf, /* mbuf chain for output */
  542.     SOCK * pSock /* sock ptr for destination */  
  543.     )
  544.     {
  545.     DRV_CTRL * pDrvCtrl = & drvCtrl[pIfNet->if_unit];
  546.     return (ether_output (pIfNet, pMbuf, pSock, (FUNCPTR) cpmStartOutput,
  547.     & pDrvCtrl->idr));
  548.     }
  549. #endif
  550. /*******************************************************************************
  551. *
  552. * cpmStartOutput - output packet to network interface device
  553. *
  554. * cpmStartOutput() takes a packet from the network interface output queue,
  555. * copies the mbuf chain into an interface buffer, and sends the packet over
  556. * the interface.  etherOutputHookRtns are supported.
  557. *
  558. * Collision stats are collected in this routine from previously sent BDs.
  559. * These BDs will not be examined until after the transmitter has cycled the
  560. * ring, coming upon the BD after it has been sent. Thus, collision stat
  561. * collection will be delayed a full cycle through the Tx ring.
  562. *
  563. * This routine is called from several possible threads.  Each one will be
  564. * described below.
  565. *
  566. * The first, and most common thread, is when a user task requests the
  567. * transmission of data. Under BSD 4.3, this will cause cpmOutput() to be
  568. * called, which calls ether_output(), which usually calls this routine. 
  569. * This routine will not be called if ether_output() finds that our interface
  570. * output queue is full. In this very rare case, the outgoing data will be 
  571. * thrown out. BSD 4.4 uses a slightly different model in which the generic
  572. * ether_output() routine is called directly, followed by a call to this
  573. * routine.
  574. *
  575. * The second thread is when a transmitter error occurs that causes a
  576. * TXE event interrupt.  This happens for the following errors: transmitter
  577. * underrun, retry limit reached, late collision, and heartbeat error.
  578. * The ISR sets the txStop flag to stop the transmitter until the errors are
  579. * serviced. These events require a RESTART command of the transmitter, which
  580. * occurs in the cpmTxRestart() routine.  After the transmitter is restarted,
  581. * cpmTxRestart() does a netJobAdd of cpmStartOutput() to send any packets
  582. * left in the interface output queue.  Thus, the second thread executes
  583. * in the context of netTask().
  584. *
  585. * The third, and most unlikely, thread occurs when this routine is executing
  586. * and it runs out of free Tx BDs.  In this case, this routine turns on
  587. * transmit interrupt and exits.  When the next BD is actually sent, an interrupt
  588. * occurs.  The ISR does a netJobAdd of cpmStartOutput() to continue sending
  589. * packets left in the interface output queue.  Once again, we find ourselves
  590. * executing in the context of netTask().
  591. *
  592. * RETURNS: N/A
  593. */
  594. #ifdef BSD43_DRIVER
  595. LOCAL void cpmStartOutput
  596.     (
  597.     int unit /* unit number */
  598.     )
  599.     {
  600.     DRV_CTRL * pDrvCtrl = & drvCtrl[unit];
  601. #else
  602. LOCAL void cpmStartOutput
  603.     (
  604.     DRV_CTRL *  pDrvCtrl /* driver control structure */
  605.     )
  606.     {
  607. #endif
  608.     MBUF * pMbuf; /* mbuf pointer */
  609.     int length;
  610.     SCC_BUF * pTxBd;
  611.     UINT8 * pad;
  612.     /*
  613.      * Loop until:
  614.      *     a) there are no more packets ready to send
  615.      *     b) we have insufficient resources left to send another one
  616.      *     c) a fatal transmitter error occurred, thus txStop was set
  617.      */
  618.     while (!pDrvCtrl->txStop && (pDrvCtrl->idr.ac_if.if_snd.ifq_head != NULL))
  619.         {
  620. pTxBd = & pDrvCtrl->ether.txBdBase[pDrvCtrl->ether.txBdNext];
  621. /* check if a transmit buffer descriptor is available */
  622.         if (pTxBd->statusMode & SCC_ETHER_TX_BD_R)
  623.     {
  624.     /* if no BD available, enable interrupt to see when one is free */
  625.             pDrvCtrl->ether.pSccReg->scce = SCC_ETHER_SCCX_TXB;
  626.             pDrvCtrl->ether.pSccReg->sccm |= SCC_ETHER_SCCX_TXB;
  627.     break;
  628.     }
  629.         IF_DEQUEUE (& pDrvCtrl->idr.ac_if.if_snd, pMbuf); /* dequeue a packet */
  630.         copy_from_mbufs (pTxBd->dataPointer, pMbuf, length);
  631.         /* padding mechanism in Rev A is buggy - do in software */
  632.         if (length < FRAME_MIN)
  633.             {
  634.             pad = pTxBd->dataPointer + length;
  635.             for (; length != FRAME_MIN; length++, pad++)
  636.                 *pad = 0x88;
  637.             }
  638.         /* call hook if one is connected */
  639.         if ((etherOutputHookRtn == NULL) || ((* etherOutputHookRtn)
  640.     (& pDrvCtrl->idr.ac_if, pTxBd->dataPointer, length) == 0))
  641.             {
  642.     /* add in collision stats from previously sent BDs */
  643.             pDrvCtrl->idr.ac_if.if_collisions += ((pTxBd->statusMode &
  644.           SCC_ETHER_TX_BD_RC) >> 2);
  645.     /* if hook did not grab the frame, send packet */
  646.             pTxBd->dataLength = length;
  647.             if (pTxBd->statusMode & SCC_ETHER_TX_BD_W)
  648.                 pTxBd->statusMode = SCC_ETHER_TX_BD_I | SCC_ETHER_TX_BD_PAD |
  649.                                     SCC_ETHER_TX_BD_L | SCC_ETHER_TX_BD_TC  |
  650.                                     SCC_ETHER_TX_BD_W | SCC_ETHER_TX_BD_R;
  651.     else
  652.                 pTxBd->statusMode = SCC_ETHER_TX_BD_I | SCC_ETHER_TX_BD_PAD |
  653.                                     SCC_ETHER_TX_BD_L | SCC_ETHER_TX_BD_TC  |
  654.                                     SCC_ETHER_TX_BD_R;
  655.             /* incr BD count */
  656.     pDrvCtrl->ether.txBdNext = (pDrvCtrl->ether.txBdNext + 1) %
  657.         pDrvCtrl->ether.txBdNum;
  658. #ifndef BSD43_DRIVER    /* BSD 4.4 ether_output() doesn't bump statistic. */
  659.             pDrvCtrl->idr.ac_if.if_opackets++;
  660. #endif
  661.             }
  662.         }
  663.     }
  664. /*******************************************************************************
  665. *
  666. * cpmIoctl - network interface control routine
  667. *
  668. * This routine implements the network interface control functions.
  669. * It handles SIOCSIFADDR and SIOCSIFFLAGS commands.
  670. *
  671. * RETURNS: OK if successful, otherwise EINVAL.
  672. */
  673. LOCAL int cpmIoctl
  674.     (
  675.     IFNET * pIfNet, /* pointer to IFNET structure */
  676.     int cmd, /* command to process */
  677.     caddr_t data /* pointer to data */ 
  678.     )
  679.     {
  680.     DRV_CTRL * pDrvCtrl = & drvCtrl[pIfNet->if_unit];
  681.     int         error   = 0;            /* error value */
  682.     int         s       = splimp ();    /* sem not taken in calling functions */
  683.     switch (cmd)
  684.         {
  685.         case SIOCSIFADDR:       /* set interface address */
  686.             ((struct arpcom *)pIfNet)->ac_ipaddr = IA_SIN (data)->sin_addr;
  687.             arpwhohas (pIfNet, &IA_SIN (data)->sin_addr);
  688.             break;
  689.     
  690.         case SIOCSIFFLAGS:
  691.     /* set promiscuous bit according to flags */
  692.     if (pDrvCtrl->idr.ac_if.if_flags & IFF_PROMISC)
  693.                 pDrvCtrl->ether.pSccReg->psmr |= SCC_ETHER_PSMR_PRO;
  694.             else
  695.                 pDrvCtrl->ether.pSccReg->psmr &= ~SCC_ETHER_PSMR_PRO;
  696.             break;
  697.         default:
  698.             error = EINVAL;
  699.         }
  700.     splx (s);
  701.     return (error);
  702.     }
  703. /*******************************************************************************
  704. *
  705. * cpmReset - network interface reset routine
  706. *
  707. * This routine marks the interface as down and resets the device.  This
  708. * includes disabling interrupts, stopping the transmitter and receiver,
  709. * and calling sysCpmEnetDisable() to do any target specific disabling.
  710. *
  711. * The complement of this rotuine is cpmInit().  Once a unit is reset in this
  712. * routine, it may be re-initialized to a running state by cpmInit().
  713. *
  714. * RETURNS: N/A
  715. */
  716. LOCAL STATUS cpmReset
  717.     (
  718.     int unit /* unit number */
  719.     )
  720.     {
  721.     DRV_CTRL * pDrvCtrl;
  722.     if (unit < 0 || unit >= MAX_UNITS) /* sanity check the unit number */
  723.         return (ERROR);
  724.     pDrvCtrl = & drvCtrl[unit];
  725.     sysCpmEnetIntDisable (unit); /* disable the SCC interrupts */
  726.     /* issue the CP graceful stop command to the transmitter if necessary */
  727.     if (pDrvCtrl->ether.pSccReg->gsmrl & SCC_GSMRL_ENT)
  728. {
  729. (void) sysCpmEnetCommand (unit, CPM_CR_SCC_GRSTOP);
  730.         /* wait for graceful stop to register */
  731.         /* wait for graceful stop to register */
  732.         taskDelay (sysClkRateGet ());
  733.         if (!(pDrvCtrl->ether.pSccReg->scce & SCC_ETHER_SCCX_GRA))
  734.             return (ERROR);     /* Stop not registered. */
  735. }
  736.     /* disable the SCC receiver and transmitter */
  737.     pDrvCtrl->ether.pSccReg->gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
  738.     /* call the BSP to do any other disabling (e.g., *TENA) */
  739.     sysCpmEnetDisable (unit);
  740.     /* mark the driver as down */
  741.     pDrvCtrl->idr.ac_if.if_flags &= ~(IFF_UP | IFF_RUNNING);
  742.     return (OK);
  743.     }
  744. /*******************************************************************************
  745. *
  746. * cpmIntr - network interface interrupt handler
  747. *
  748. * This routine gets called at interrupt level. It handles work that 
  749. * requires minimal processing. Interrupt processing that is more 
  750. * extensive gets handled at task level. The network task, netTask(), is 
  751. * provided for this function. Routines get added to the netTask() work 
  752. * queue via the netJobAdd() command.
  753. *
  754. * RETURNS: N/A
  755. */
  756. LOCAL void cpmIntr
  757.     (
  758.     int unit /* unit number */
  759.     )
  760.     {
  761.     DRV_CTRL * pDrvCtrl = & drvCtrl[unit];
  762.     BOOL rxHandle = FALSE;
  763.     BOOL txHandle = FALSE;
  764.     int events;
  765.     /* identify and acknowledge all interrupt events */
  766.     events = (pDrvCtrl->ether.pSccReg->scce & pDrvCtrl->ether.pSccReg->sccm);
  767.     /* check for spurious interrupt */
  768.     if (!pDrvCtrl->attached)
  769. {
  770.         pDrvCtrl->ether.pSccReg->scce = 0xffff;
  771. sysCpmEnetIntClear (unit);
  772. return;
  773. }
  774.     /* handle receive events */
  775.     if (events & SCC_ETHER_SCCX_RXF)
  776. {
  777.         (void) netJobAdd ((FUNCPTR) cpmHandleInt, (int) pDrvCtrl, 0, 0, 0, 0); 
  778. /* turn off receive interrupts for now - cpmHandleInt turns back on */
  779.         pDrvCtrl->ether.pSccReg->sccm &= ~SCC_ETHER_SCCX_RXF;
  780.         rxHandle = TRUE;
  781.         }
  782.     /* check for output errors */
  783.     if (pDrvCtrl->ether.pSccReg->scce & SCC_ETHER_SCCX_TXE)
  784. {
  785. /* NOTE: HBC error not supported -> always RESTART Tx here */
  786.         (void) netJobAdd ((FUNCPTR) cpmTxRestart, unit, 0, 0, 0, 0);
  787. pDrvCtrl->txStop = TRUE;
  788. }
  789.     /* handle transmitter events - BD full condition -> ever happen ? */
  790.     if (events & SCC_ETHER_SCCX_TXB)
  791. {
  792. #ifdef BSD43_DRIVER
  793.         (void) netJobAdd ((FUNCPTR) cpmStartOutput, unit, 0, 0, 0, 0); 
  794. #else
  795.         (void) netJobAdd ((FUNCPTR) cpmStartOutput, (int)pDrvCtrl, 0, 0, 0, 0); 
  796. #endif
  797.         pDrvCtrl->ether.pSccReg->sccm &= ~SCC_ETHER_SCCX_TXB;
  798. }
  799.     /* check for input busy condition, we don't enable this interrupt
  800.        but we check for it with each interrupt. */
  801.     if (pDrvCtrl->ether.pSccReg->scce & SCC_ETHER_SCCX_BSY)
  802. {
  803.         pDrvCtrl->ether.pSccReg->scce = SCC_ETHER_SCCX_BSY; 
  804.         /* count discarded frames as errors */
  805.         pDrvCtrl->idr.ac_if.if_ierrors +=
  806.     ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->disfc;
  807. ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->disfc = 0;
  808. }
  809.     /* ignore and reset all other events */
  810.     pDrvCtrl->ether.pSccReg->scce = (pDrvCtrl->ether.pSccReg->scce &
  811.                                      ~(SCC_ETHER_SCCX_RXF |
  812.        SCC_ETHER_SCCX_TXE |
  813.        SCC_ETHER_SCCX_TXB |
  814.        SCC_ETHER_SCCX_BSY));
  815.     if (rxHandle)
  816.         pDrvCtrl->ether.pSccReg->scce = SCC_ETHER_SCCX_RXF;
  817.     if (pDrvCtrl->txStop)
  818.         pDrvCtrl->ether.pSccReg->scce = SCC_ETHER_SCCX_TXE;
  819.     if (txHandle)
  820.         pDrvCtrl->ether.pSccReg->scce = SCC_ETHER_SCCX_TXB;
  821.     sysCpmEnetIntClear (unit);
  822.     }
  823. /*******************************************************************************
  824. *
  825. * cpmTxRestart - issue RESTART Tx command to the CP
  826. *
  827. * This routine issues a RESTART transmitter command to the CP.  It is
  828. * executed by netTask (cpmIntr() did a netJobAdd).  cpmIntr() cannot do
  829. * a RESTART directly because the CPM flag must be taken before a command
  830. * can be written.  After a restart, a netJobAdd of cpmStartOutput() is
  831. * performed in order to send any packets remaining in the interface output
  832. * queue.
  833. *
  834. * RETURNS: N/A
  835. */
  836. LOCAL void cpmTxRestart
  837.     (
  838.     int unit /* unit number */
  839.     )
  840.     {
  841.     DRV_CTRL * pDrvCtrl = & drvCtrl[unit];
  842.     /* update error counter */
  843.     pDrvCtrl->idr.ac_if.if_oerrors++;
  844.     /* correct packet counter */
  845.     pDrvCtrl->idr.ac_if.if_opackets--;
  846.     /* restart the transmitter */
  847.     (void) sysCpmEnetCommand (unit, CPM_CR_SCC_RESTART);
  848.     /* restart transmit routine */
  849.     pDrvCtrl->txStop = FALSE;
  850. #ifdef BSD43_DRIVER
  851.     (void) netJobAdd ((FUNCPTR) cpmStartOutput, unit, 0, 0, 0, 0); 
  852. #else
  853.     (void) netJobAdd ((FUNCPTR) cpmStartOutput, (int)pDrvCtrl, 0, 0, 0, 0); 
  854. #endif
  855.     }
  856. /*******************************************************************************
  857. *
  858. * cpmHandleInt - task-level interrupt handler
  859. *
  860. * This is the task-level interrupt handler, which is called from 
  861. * netTask(). cpmHandleInt() gets input frames from the device and then calls 
  862. * cpmRecv() to process each frame.  cpmRecv() only gets called if no error
  863. * stats were reported in the buffer descriptor.  Data chaining is not
  864. * supported.
  865. *
  866. * This routine should be called with SCC receive interrupts masked so that
  867. * more netJobAdds of this routine are not performed by cpmIntr().
  868. * Receive interrupts are turned back on by this routine before exiting.
  869. *
  870. * RETURNS: N/A
  871. */
  872. LOCAL void cpmHandleInt
  873.     (
  874.     DRV_CTRL * pDrvCtrl /* pointer to DRV_CTRL structure */
  875.     )
  876.     {
  877.     SCC_BUF * pRxBd = & pDrvCtrl->ether.rxBdBase[pDrvCtrl->ether.rxBdNext];
  878.     while (!(pRxBd->statusMode & SCC_ETHER_RX_BD_E))
  879.         {
  880.         /* data chaining is not supported - check all error conditions */
  881.         if (((pRxBd->statusMode & (SCC_ETHER_RX_BD_F  | SCC_ETHER_RX_BD_L))
  882.                        == (SCC_ETHER_RX_BD_F  | SCC_ETHER_RX_BD_L))
  883.                       && !(pRxBd->statusMode & (SCC_ETHER_RX_BD_CL |
  884.                    SCC_ETHER_RX_BD_OV | SCC_ETHER_RX_BD_CR |
  885.    SCC_ETHER_RX_BD_SH | SCC_ETHER_RX_BD_NO |
  886.    SCC_ETHER_RX_BD_LG)))
  887.             cpmRecv (pDrvCtrl, pRxBd);
  888.         else
  889.             pDrvCtrl->idr.ac_if.if_ierrors++;
  890.         /* reset buffer descriptor as empty */
  891. if (pRxBd->statusMode & SCC_ETHER_RX_BD_W)
  892.             pRxBd->statusMode = SCC_ETHER_RX_BD_E | SCC_ETHER_RX_BD_I |
  893.                                 SCC_ETHER_RX_BD_W;
  894.         else
  895.             pRxBd->statusMode = SCC_ETHER_RX_BD_E | SCC_ETHER_RX_BD_I;
  896.         /* incr BD count */
  897.         pDrvCtrl->ether.rxBdNext = (pDrvCtrl->ether.rxBdNext + 1) %
  898.     pDrvCtrl->ether.rxBdNum;
  899.         pRxBd = & pDrvCtrl->ether.rxBdBase[pDrvCtrl->ether.rxBdNext];
  900.         /* clear Rx events */
  901.         pDrvCtrl->ether.pSccReg->scce = SCC_ETHER_SCCX_RXF;
  902.         }
  903.     /* re-enable Rx interrupts */
  904.     pDrvCtrl->ether.pSccReg->sccm |= SCC_ETHER_SCCX_RXF;
  905.     }
  906. /*******************************************************************************
  907. *
  908. * cpmRecv - process an input frame
  909. *
  910. * This routine processes an input frame, then passes it up to the higher 
  911. * level in a form it expects.  Buffer loaning, promiscuous mode, and
  912. * etherInputHookRtns are all supported.  Trailer protocols is not supported.
  913. *
  914. * RETURNS: N/A
  915. */
  916. LOCAL void cpmRecv
  917.     (
  918.     DRV_CTRL * pDrvCtrl, /* pointer to DRV_CTRL structure */
  919.     SCC_BUF * pRxBd /* receive buffer descriptor */
  920.     )
  921.     { 
  922.     MBUF * pMbuf = NULL; /* MBUF pointer */
  923.     UINT8 * pData;
  924.     int length;
  925. #ifdef BSD43_DRIVER
  926.     UINT16 type;
  927. #endif
  928.     struct ether_header *  pEh; 
  929.     /* bump input packet counter */
  930.     pDrvCtrl->idr.ac_if.if_ipackets++;
  931.     /* call hook if one is connected */
  932.     if ((etherInputHookRtn != NULL) && ((*etherInputHookRtn)
  933. (& pDrvCtrl->idr.ac_if, pRxBd->dataPointer, pRxBd->dataLength) != 0))
  934.         return; 
  935.     /* get Ethernet header */
  936.     pEh = (struct ether_header *) pRxBd->dataPointer;
  937.     /* filter frame if controller is in promiscuous mode - M bit is buggy */
  938.     if (pDrvCtrl->ether.pSccReg->psmr & SCC_ETHER_PSMR_PRO)
  939. {
  940. if ((bcmp ( (char *) pEh->ether_dhost,
  941.                     (char *) pDrvCtrl->idr.ac_enaddr, ENET_ADDR_SIZE)) &&
  942.     (bcmp ((char *) pEh->ether_dhost,
  943.      (char *) etherbroadcastaddr, ENET_ADDR_SIZE)))
  944.            return;
  945. }
  946.     /* adjust length to data only */
  947.     length = pRxBd->dataLength - SIZEOF_ETHERHEADER;
  948.     if (length <= 0)
  949.         pDrvCtrl->idr.ac_if.if_ierrors++;
  950. return;
  951. }
  952.     /* point to data */
  953.     pData = ((char *)pEh) + SIZEOF_ETHERHEADER;
  954. #ifdef BSD43_DRIVER
  955.     /* save type - build_cluster trashes the type field */
  956.     type = pEh->ether_type;
  957. #endif
  958.     /* OK to loan out buffer ? -> build a mbuf cluster */
  959.     if ((pDrvCtrl->nLoanRxBd > 0) && (USE_CLUSTER (length)))
  960. pMbuf = build_cluster (pData, length, & pDrvCtrl->idr, MC_CPM,
  961.     pDrvCtrl->pRefCnt[(pDrvCtrl->nLoanRxBd - 1)], cpmLoanFree,
  962.     (int) pDrvCtrl, (int) pEh,
  963.             (int) pDrvCtrl->pRefCnt[(pDrvCtrl->nLoanRxBd - 1)]);
  964.     /* if buffer was successfully turned into mbuf cluster */
  965.     if (pMbuf != NULL)
  966. pRxBd->dataPointer = pDrvCtrl->lPool[--pDrvCtrl->nLoanRxBd];
  967.     else
  968.         {
  969. /* else do same ol' copy to mbuf */
  970.         pMbuf = copy_to_mbufs (pData, length, 0, & pDrvCtrl->idr.ac_if);
  971.         if (pMbuf == NULL)
  972.     {
  973.             pDrvCtrl->idr.ac_if.if_ierrors++;
  974.             return;
  975.     }
  976.         }
  977.     /* send up to protocol */
  978. #ifdef BSD43_DRIVER
  979.     do_protocol_with_type (type, pMbuf, & pDrvCtrl->idr, length);
  980. #else
  981.     do_protocol (pEh, pMbuf, & pDrvCtrl->idr, length);
  982. #endif
  983.     }
  984. /*******************************************************************************
  985. *
  986. * cpmLoanFree - return the given buffer to loaner pool
  987. *
  988. * This routine returns <pRxBuf> to the pool of available loaner buffers.
  989. * It also returns <pRef> to the pool of available loaner reference counters,
  990. * then zeroes the reference count.
  991. *
  992. * RETURNS: N/A
  993. */
  994. LOCAL void cpmLoanFree
  995.     (
  996.     DRV_CTRL * pDrvCtrl,
  997.     UINT8 * pRxBuf,
  998.     UINT8 * pRef
  999.     )
  1000.     {
  1001.     /* return loaned buffer to pool */
  1002.     pDrvCtrl->lPool[pDrvCtrl->nLoanRxBd] = pRxBuf;
  1003.     /* return loaned reference count to pool */
  1004.     pDrvCtrl->pRefCnt[pDrvCtrl->nLoanRxBd++] = pRef;
  1005.     /* reset reference count - should have been done from above, but... */
  1006.     *pRef = 0;
  1007.     }