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

VxWorks

开发平台:

C/C++

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