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

VxWorks

开发平台:

C/C++

  1. /* if_eitp.c - Intel 82596 Ethernet network interface driver for the TP41V */
  2. /* Copyright 1989-1997 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 03f,03jul97,spm  added ARP request to SIOCSIFADDR ioctl handler
  8. 03e,07apr97,spm  code cleanup, corrected statistics, and upgraded to BSD 4.4
  9. 03d,11aug93,jmm  Changed ioctl.h and socket.h to sys/ioctl.h and sys/socket.h
  10. 03c,24mar93,jdi  documentation cleanup for 5.1.
  11. 03b,30nov92,rfs  Branched off custom version for TP41.
  12.                  Removed calls to sys596Init(), sys596IntAck().
  13.                  Replaced calls to sys596IntDisable() with intLock().
  14.                  Replaced calls to sys596IntEnable() with intUnlock().
  15.                  Removed dummy function eiChipReset().
  16. 03a,05oct92,rfs  Added documentation.
  17. 02z,02oct92,rfs  Made multiple attach calls per unit return OK, not ERROR.
  18. 02y,01oct92,rfs  Added 16 byte page alignment for SCP.
  19. 02x,28sep92,rfs  Modified the eiAction() routine to clear all events.  This
  20.                  makes the diagnostics pass, for some undocumented reason.
  21. 02w,09sep92,gae  documentation tweaks.
  22. 02v,11aug92,rfs  Slight change to memory carving.  Also fixed receive bug
  23.                  that was due to device manual incorrectly describing bit 7
  24.                  of config byte 10 and added error checks to RFDs.  Changed
  25.                  the device startup routine.
  26. 02u,26aug92,kdl  moved internal notes to file header (were just #ifdef'd out).
  27. 02t,19aug92,smb  changed systime.h to sys/times.h
  28. 02s,31jul92,dave Changed to new cacheLib.
  29. 02r,28jul92,rfs  Adapted to latest cache coherency model.
  30.                  Renamed driver control structure and moved it to bss.
  31.                  Combined the init() routine with the attach() routine and
  32.                  made attach() reject multiple invocations.  Rewrote the
  33.                  ioctl() routine to do the right stuff.  Reworked the action
  34.                  command routine and the primary command routine.  Other misc.
  35. 02q,16jul92,rfs  Moved driver specific items from header file to here,
  36.                  where they belong.
  37. 02p,16jul92,rfs  Moved internal comments to end of file, where they belong.
  38. 02o,03jul92,jwt  converted cacheClearEntry() calls to cacheClear() for 5.1.
  39. 02n,26jun92,rrr  make eiBusSnoop global again (needed by bsps)
  40. 02m,25jun92,rfs  backed out last mod; the manual is incorrect about the
  41.                  state of the bit that configures CRC inclusion
  42. 02l,25jun92,rfs  bug fix, changed a receive config parm that selects whether
  43.                  the CRC is included in the buffer
  44. 02k,23jun92,ajm  made eiChipReset global for tp41 BSP
  45. 02j,08jun92,ajm  modified so eiattach is only external function
  46.                  got rid of MEM_ROUND_UP macro now pulled in with vxWorks.h
  47.                  got rid of many ansi complaints
  48. 02i,26may92,rrr  the tree shuffle
  49.                  -changed includes to have absolute path from h/
  50. 02h,22feb92,wmd  added conditional compiles for 040, ansi fixes.
  51. 02g,07jan92,shl  made driver cache safe. added eiBusSnoop(). eliminated some
  52.                  ANSI warnings.
  53. 02f,12nov91,wmd  Added fix, courtesy of jrb-Intel, which added a watchdog to
  54.                  timeout any stalls due to hardware lockup and resets the
  55.                  82596.
  56. 02e,25oct91,rfs  Changed eiChipReset() to not depend on valid *es, and
  57.                  made it global for TP41 usage. Also eliminated ANSI
  58.                  warnings.
  59. 02d,04oct91,rrr  passed through the ansification filter
  60.                  -changed functions to ansi style
  61.                  -changed includes to have absolute path from h/
  62.                  -changed VOID to void
  63.                  -changed copyright notice
  64. 02c,15sep91,rfs  Bug fix. Eliminated lock condition when output queue full
  65.                  and out of TFDs. Added major comment to eiTxStartup. Also,
  66.                  major changes to eiChipReset() to make more robust. All
  67.                  instances of intLock()/intUnlock() changed to
  68.                  sys596IntDisable()/sys596IntEnable respectively. Statistic
  69.                  counters now being used, which required moderate changes to
  70.                  the transmit side design. More comments added.
  71. 02b,21aug91,rfs  changed method of obtaining Ethernet address.
  72. 02a,22jul91,jcf  completely rewritten to utilize simplified mode,
  73.             rfs  added big endian support, reworked buffer loaning.
  74. 01h,01may91,elh  fixed ethernet addressing problem, upgraded to 5.0,
  75.                  added buffer loanouts, fixed ifAddrSet bug by disabling
  76.                  interrupts in eiHardReset.
  77. 01g,28apr91,del  added #define of ETHER_HEADER_SIZE as workaround for
  78.                  gnu960 pading of struct ether_header.
  79. 01f,05jan91,gae  added global eiSCPSysConfig for board specific SCP parameters.
  80.                  moved CDELAY here from if_ei.h and renamed eichkcca.
  81. 01e,03jan91,gae  more cleanup and merged with Intel's fixes.
  82.                  Ethernet address (eiEnetAddr) is set in sysHwInit.
  83.                  cleaned up error printing & no carrier message always printed.
  84.                  changed printf's to printErr's (logMsg if at int level).
  85.                  made most routines local -- not available outside this module.
  86. 01d,31dec90,gae  removed 68K stuff.
  87. 01c,14dec90,elh  more cleanup.
  88. 01b,12dec90,elh  fixed buffer problems, cleaned up, added etherhooks.
  89. 01a,06feb90,djk  written
  90. */
  91. /*
  92. This module implements the Intel 82596 Ethernet network interface driver.
  93. This driver is a custom version of the generic `ei' driver, to support the
  94. Tadpole TP41V.   Use the information from manual page for if_ei, except for
  95. the following differences:
  96. .iP "" 4
  97. The name of the attach routine is eitpattach().  The arguments are the same.
  98. .iP
  99. The following external support routines are not required:  sys596Init(),
  100. sys596IntEnable(), sys596IntDisable(), and sys596IntAck().
  101. SEE ALSO: if_ei, ifLib,
  102. .I "Intel 82596 User's Manual"
  103. */
  104. #include "vxWorks.h"
  105. #include "wdLib.h"
  106. #include "iv.h"
  107. #include "vme.h"
  108. #include "net/mbuf.h"
  109. #include "net/protosw.h"
  110. #include "sys/socket.h"
  111. #include "sys/ioctl.h"
  112. #include "errno.h"
  113. #include "memLib.h"
  114. #include "intLib.h"
  115. #include "net/if.h"
  116. #include "net/route.h"
  117. #include "cacheLib.h"
  118. #include "logLib.h"
  119. #include "netLib.h"
  120. #include "stdio.h"
  121. #include "stdlib.h"
  122. #include "sysLib.h"
  123. #ifdef  INET
  124. #include "netinet/in.h"
  125. #include "netinet/in_systm.h"
  126. #include "netinet/in_var.h"
  127. #include "netinet/ip.h"
  128. #include "netinet/if_ether.h"
  129. #endif  /* INET */
  130. #include "etherLib.h"
  131. #include "net/systm.h"
  132. #include "sys/times.h"
  133. #include "drv/netif/if_ei.h"
  134. #include "net/if_subr.h"
  135. /***** LOCAL DEFINITIONS *****/
  136. #undef EI_DEBUG                             /* Compiles debug output */
  137. #define MAX_UNITS       4                   /* maximum units to support */
  138. #define DEF_NUM_TFDS    32                  /* default number of TFDs */
  139. #define DEF_NUM_RFDS    32                  /* default number of RFDs */
  140. #define MAX_RFDS_LOANED 8                   /* max RFDs that can be loaned */
  141. /* Typedefs for external structures that are not typedef'd in their .h files */
  142. typedef struct mbuf MBUF;
  143. typedef struct arpcom IDR;                  /* Interface Data Record wrapper */
  144. typedef struct ifnet IFNET;                 /* real Interface Data Record */
  145. typedef struct sockaddr SOCK;
  146. typedef struct ether_header ETH_HDR;
  147. /* The definition of our linked list management structure */
  148. typedef struct ei_list                       /* EI_LIST - 82596 queue head */
  149.     {
  150.     volatile EI_NODE *  head;       /* header of list */
  151.     volatile EI_NODE *  tail;       /* tail of list */
  152.     } EI_LIST;
  153. /* The definition of the driver control structure */
  154. typedef struct drv_ctrl
  155.     {
  156.     IDR                 idr;        /* interface data record */
  157.     BOOL                attached;   /* indicates attach() called */
  158.     char                *memBase;   /* 82596 memory pool base */
  159.     SCP                 *pScp;      /* SCP ptr */
  160.     ISCP                *pIscp;     /* ISCP ptr */
  161.     SCB                 *pScb;      /* SCB ptr */
  162.     CFD                 *pCfd;      /* synchronous command frame */
  163.     RFD                 *rfdPool;   /* RFD pool */
  164.     TFD                 *tfdPool;   /* TFD pool */
  165.     RFD                 *pFreeRfd;  /* first empty RFD in rxQueue */
  166.     volatile EI_LIST    rxQueue;    /* receive queue */
  167.     volatile EI_LIST    txQueue;    /* to be sent queue */
  168.     volatile EI_LIST    tfdQueue;   /* free transmit frame descriptors */
  169.     volatile EI_LIST    cblQueue;   /* actual chip transmit queue */
  170.     volatile EI_LIST    cleanQueue; /* queue of TFDs to cleanup */
  171.     volatile BOOL       rcvHandling;/* flag, indicates netTask active */
  172.     volatile BOOL       txCleaning; /* flag, indicates netTask active */
  173.     volatile BOOL       txIdle;     /* flag, indicates idle transmitter */
  174.     int                 nTFDs;      /* how many TFDs to create */
  175.     int                 nRFDs;      /* how many RFDs to create */
  176.     int                 nLoanRfds;  /* number of loanable RFDs left */
  177.     UINT8               sysbus;     /* SCP sysbus value */
  178.     int                 ivec;       /* interrupt vector */
  179.     CACHE_FUNCS         cacheFuncs; /* cache descriptor */
  180.     WDOG_ID             wid;        /* watchdog timer for transmit */
  181.     long                transLocks; /* count for transmit lockup failures */
  182.     } DRV_CTRL;
  183. #define DRV_CTRL_SIZ  sizeof(DRV_CTRL)
  184. /***** GLOBALS *****/
  185. /* Function declarations not in any header files */
  186. IMPORT STATUS sysEnetAddrGet (int unit, char addr[]);
  187. IMPORT void   sys596Port (int unit, int cmd, UINT32 addr);
  188. IMPORT void   sys596ChanAtn (int unit);
  189. /***** LOCALS *****/
  190. /* The array of driver control structs */
  191. LOCAL DRV_CTRL drvCtrl [MAX_UNITS];
  192. /* forward function declarations */
  193. static void eiReset (int unit);
  194. static int eiIoctl (IDR *pIDR, int cmd, caddr_t data);
  195. #ifdef BSD43_DRIVER
  196. static int eiOutput (IDR *pIDR, MBUF *pMbuf, SOCK *pDestAddr);
  197. static void eiTxStartup (int unit);
  198. #else
  199. static void eiTxStartup (DRV_CTRL *pDrvCtrl);
  200. #endif
  201. static void eiInt (DRV_CTRL *pDrvCtrl);
  202. static void eiTxCleanQ (DRV_CTRL *pDrvCtrl);
  203. static void eiHandleRecvInt (DRV_CTRL *pDrvCtrl);
  204. static STATUS eiReceive (DRV_CTRL *pDrvCtrl, RFD *pRfd);
  205. static void eiLoanFree (DRV_CTRL *pDrvCtrl, RFD *pRfd);
  206. static STATUS eiDiag (int unit);
  207. static void eiConfig (int unit);
  208. static void eiIASetup (int unit);
  209. static void eiRxStartup (DRV_CTRL *pDrvCtrl);
  210. static void eiAction (int unit, UINT16 action);
  211. static STATUS eiCommand (DRV_CTRL *pDrvCtrl, UINT16 cmd);
  212. static void eiTxQPut (DRV_CTRL *pDrvCtrl, TFD *pTfd);
  213. static void eiTxQFlush (DRV_CTRL *pDrvCtrl);
  214. static void eiRxQPut (DRV_CTRL *pDrvCtrl, RFD *pRfd);
  215. static RFD *eiRxQGet (DRV_CTRL *pDrvCtrl);
  216. static BOOL eiRxQFull (DRV_CTRL *pDrvCtrl);
  217. static void eiQInit (EI_LIST *pHead);
  218. static EI_NODE *eiQGet (EI_LIST *pQueue);
  219. static void eiQPut (int unit, EI_LIST *pQueue, EI_NODE *pNode);
  220. static STATUS eiDeviceStart (int unit);
  221. static void eiWatchDog(int unit);
  222. /*******************************************************************************
  223. *
  224. * eitpattach - publish the `ei' network interface for the TP41V and initialize the driver and device
  225. *
  226. * The routine publishes the `ei' interface by filling in a network interface
  227. * record and adding this record to the system list.  This routine also
  228. * initializes the driver and the device to the operational state.
  229. *
  230. * The 82596 shares a region of memory with the driver.  The caller of this
  231. * routine can specify the address of this memory region, or can specify that
  232. * the driver must obtain this memory region from the system resources.
  233. *
  234. * The <sysbus> parameter accepts values as described in the Intel manual
  235. * for the 82596.  A default number of transmit/receive frames of 32 can be
  236. * selected by passing zero in the parameters <nTfds> and <nRfds>.
  237. * In other cases, the number of frames selected should be greater than two.
  238. *
  239. * The <memBase> parameter is used to inform the driver about the shared
  240. * memory region.  If this parameter is set to the constant "NONE", then
  241. * eitpattach() will attempt to allocate the shared memory from the system.
  242. * Any other value for this parameter is interpreted as the address of the
  243. * shared memory region to be used.
  244. *
  245. * If the caller provides the shared memory region, then the driver assumes
  246. * that this region does not require cache coherency operations, nor does it
  247. * require conversions between virtual and physical addresses.
  248. *
  249. * If the caller indicates that this routine must allocate the shared memory
  250. * region, then this routine will use the routine cacheDmaMalloc() to obtain
  251. * some  non-cacheable memory.  The attributes of this memory will be checked,
  252. * and if the memory is not both read and write coherent, this routine will
  253. * abort and return ERROR.
  254. *
  255. * RETURNS: OK or ERROR.
  256. *
  257. * SEE ALSO: if_ei, ifLib,
  258. * .I "Intel 82596 User's Manual"
  259. */
  260. STATUS eitpattach
  261.     (
  262.     int         unit,              /* unit number */
  263.     int         ivec,              /* interrupt vector number */
  264.     UINT8       sysbus,            /* sysbus field of SCP */
  265.     char *      memBase,           /* address of memory pool or NONE */
  266.     int         nTfds,             /* no. of transmit frames (0 = default) */
  267.     int         nRfds              /* no. of receive frames (0 = default) */
  268.     )
  269.     {
  270.     DRV_CTRL    *pDrvCtrl;
  271.     UINT        size;                           /* temporary size holder */
  272.     UINT        sizeScp;
  273.     UINT        sizeIscp;
  274.     UINT        sizeScb;
  275.     UINT        sizeCfd;
  276. int intLevel;
  277.     static char *errMsg1 = "neiattach: could not obtain memoryn";
  278.     static char *errMsg2 = "neiattach: shared memory not cache coherentn";
  279.     sizeScp  = MEM_ROUND_UP (sizeof (SCP));
  280.     sizeIscp = MEM_ROUND_UP (sizeof (ISCP));
  281.     sizeScb  = MEM_ROUND_UP (sizeof (SCB));
  282.     sizeCfd  = MEM_ROUND_UP (sizeof (CFD));
  283.     /* Sanity check the unit number */
  284.     if (unit < 0 || unit >= MAX_UNITS)
  285.         return (ERROR);
  286.     /* Ensure single invocation per system life */
  287.     pDrvCtrl = & drvCtrl [unit];
  288.     if (pDrvCtrl->attached)
  289.         return (OK);
  290.     /* Determine number of Tx and Rx descriptors to use */
  291.     pDrvCtrl->nTFDs = nTfds ? nTfds : DEF_NUM_TFDS;
  292.     pDrvCtrl->nRFDs = nRfds ? nRfds : DEF_NUM_RFDS;
  293.     /* Publish the interface record */
  294. #ifdef BSD43_DRIVER
  295.     ether_attach ( (IFNET *)&pDrvCtrl->idr, unit, "eitp", (FUNCPTR)NULL,
  296.                    (FUNCPTR) eiIoctl, (FUNCPTR) eiOutput, (FUNCPTR) eiReset);
  297. #else
  298.     ether_attach    (
  299.                     &pDrvCtrl->idr.ac_if,
  300.                     unit,
  301.                     "eitp",
  302.                     (FUNCPTR) NULL,
  303.                     (FUNCPTR) eiIoctl,
  304.                     (FUNCPTR) ether_output,
  305.                     (FUNCPTR) eiReset
  306.                     );
  307.     pDrvCtrl->idr.ac_if.if_start = (FUNCPTR)eiTxStartup;
  308. #endif
  309.     /* calculate the total size of 82596 memory pool */
  310.     size =
  311.             16 +                                /* allow for alignment */
  312.             sizeScp +
  313.             sizeIscp +
  314.             sizeScb +
  315.             sizeCfd +                           /* synch'ed command frame */
  316.             (sizeof (RFD) * pDrvCtrl->nRFDs) +  /* pool of receive frames */
  317.             (sizeof (TFD) * pDrvCtrl->nTFDs);   /* pool of transmit frames */
  318.     /* Establish the memory area that we will share with the device.  If
  319.      * the caller has provided an area, then we assume it is non-cacheable
  320.      * and will not require the use of the special cache routines.
  321.      * If the caller did not provide an area, then we must obtain it from
  322.      * the system, using the cache savvy allocation routine.
  323.      */
  324.     switch ((int) memBase)
  325.         {
  326.         case NONE :                            /* we must obtain it */
  327.             /* this driver can't handle incoherent caches */
  328.             if (!CACHE_DMA_IS_WRITE_COHERENT () ||
  329.                 !CACHE_DMA_IS_READ_COHERENT ())
  330.                 {
  331.                 printf (errMsg2);
  332.                 goto error;
  333.                 }
  334.             pDrvCtrl->memBase = cacheDmaMalloc (size);
  335.             if (pDrvCtrl->memBase == NULL)    /* no memory available */
  336.                 {
  337.                 printf (errMsg1);
  338.                 goto error;
  339.                 }
  340.             pDrvCtrl->cacheFuncs = cacheDmaFuncs;
  341.             break;
  342.         default :                               /* the user provided an area */
  343.             pDrvCtrl->memBase = memBase;        /* use the provided address */
  344.             pDrvCtrl->cacheFuncs = cacheNullFuncs;
  345.             break;
  346.         }
  347.     /* Save other passed-in parameters */
  348.     pDrvCtrl->sysbus = sysbus;                  /* remember sysbus value */
  349.     pDrvCtrl->ivec = ivec;                      /* interrupt vector */
  350.     /* Carve up the shared memory region into the specific sections */
  351.     bzero ((char *) pDrvCtrl->memBase, size);
  352.     pDrvCtrl->pScp  = (SCP *)                /* align to first 16 byte page */
  353.                       ( ((u_long) pDrvCtrl->memBase + 0xf) & ~0xf );
  354.     pDrvCtrl->pIscp = (ISCP *)((int)pDrvCtrl->pScp   + sizeScp);
  355.     pDrvCtrl->pScb  = (SCB *) ((int)pDrvCtrl->pIscp  + sizeIscp);
  356.     pDrvCtrl->pCfd  = (CFD *) ((int)pDrvCtrl->pScb   + sizeScb);
  357.     pDrvCtrl->rfdPool   = (RFD *) ((int)pDrvCtrl->pCfd   + sizeCfd);
  358.     pDrvCtrl->tfdPool = (TFD *)
  359.             ((int)pDrvCtrl->rfdPool+ (sizeof (RFD) * pDrvCtrl->nRFDs));
  360.     /* Init the watchdog that will patrol for device lockups */
  361.     pDrvCtrl->transLocks = 0;
  362.     pDrvCtrl->wid = wdCreate ();                      /* create watchdog */
  363.     if (pDrvCtrl->wid == NULL)                        /* no resource */
  364.         goto error;
  365.     /* get our enet addr */
  366.     if (sysEnetAddrGet (unit, (char *)pDrvCtrl->idr.ac_enaddr) == ERROR)
  367.         goto error;
  368.     pDrvCtrl->rcvHandling   = FALSE;  /* netTask not running our receive job */
  369.     pDrvCtrl->txCleaning    = FALSE;  /* netTask not running our clean job */
  370.     pDrvCtrl->txIdle        = TRUE;         /* transmitter idle */
  371.     eiQInit ((EI_LIST *)&pDrvCtrl->rxQueue);    /* to be received queue */
  372.     eiQInit ((EI_LIST *)&pDrvCtrl->txQueue);    /* to be sent queue */
  373.     eiQInit ((EI_LIST *)&pDrvCtrl->tfdQueue);   /* free tfds to add to send q */
  374.     eiQInit ((EI_LIST *)&pDrvCtrl->cblQueue);   /* actively sending queue */
  375.     eiQInit ((EI_LIST *)&pDrvCtrl->cleanQueue); /* queue of TFDs to clean */
  376.     { /***** Perform device initialization *****/
  377.     /* Block local variables */
  378.     int ix;
  379.     /* Connect the interrupt handler */
  380.     if (intConnect ((VOIDFUNCPTR *)INUM_TO_IVEC (ivec), eiInt, (int)pDrvCtrl)
  381.         == ERROR)
  382.         goto error;
  383. /* Disable system interrupts (NOTE #1) */
  384. intLevel = intLock ();
  385.     /* Start the device */
  386.     if ( eiDeviceStart (unit) == ERROR )
  387.         goto error;
  388.     if ( eiDiag (unit) == ERROR )              /* run diagnostics */
  389. goto error;
  390.     eiConfig (unit);                           /* configure chip */
  391.     eiIASetup (unit);                          /* setup address */
  392.     for (ix = 0; ix < pDrvCtrl->nTFDs; ix ++)  /* tank up the free tfd queue */
  393.         {
  394.         eiQPut  (
  395.                 unit,
  396.                 (EI_LIST *) & pDrvCtrl->tfdQueue,
  397.                 (EI_NODE *) & pDrvCtrl->tfdPool [ix]
  398.                 );
  399.         }
  400.     pDrvCtrl->pFreeRfd  = NULL;                  /* first free RFD */
  401.     pDrvCtrl->nLoanRfds = MAX_RFDS_LOANED;       /* number of loanable RFD's */
  402.     for (ix = 0; ix < pDrvCtrl->nRFDs; ix ++)   /* tank up the receive queue */
  403.         eiRxQPut (pDrvCtrl, & pDrvCtrl->rfdPool [ix]);
  404. /* Re-enable system interrupts */
  405.     intUnlock (intLevel);
  406.     } /* End block */
  407.     /* Set our flag */
  408.     pDrvCtrl->attached = TRUE;
  409.     /* Set status flags in IDR */
  410.     pDrvCtrl->idr.ac_if.if_flags |= (IFF_UP | IFF_RUNNING | IFF_NOTRAILERS);
  411.     /* Successful return */
  412.     return (OK);
  413.     /***** Handle error cases *****/
  414.     error:
  415.         {
  416. /* Re-enable system interrupts */
  417.      intUnlock (intLevel);
  418.         /* Release system memory */
  419.         if (((int) memBase == NONE) && ((int) pDrvCtrl->memBase != NULL))
  420.             cacheDmaFree (pDrvCtrl->memBase);
  421.         /* Release watchdog */
  422.         if (pDrvCtrl->wid != NULL)
  423.             wdDelete (pDrvCtrl->wid);
  424.         return (ERROR);
  425.         }
  426.     }
  427. /*******************************************************************************
  428. *
  429. * eiReset - reset the ei interface
  430. *
  431. * Mark interface as inactive and reset the chip.
  432. */
  433. static void eiReset
  434.     (
  435.     int unit
  436.     )
  437.     {
  438.     int intLevel;
  439.     DRV_CTRL *pDrvCtrl;
  440.     pDrvCtrl = & drvCtrl [unit];
  441.     if (pDrvCtrl->idr.ac_if.if_flags & IFF_RUNNING)
  442.         {
  443.         /* issue command to disable CU and RU */
  444.         intLevel = intLock ();
  445.         eiCommand (pDrvCtrl, SCB_C_CUABORT | SCB_C_RUABORT);
  446.         intUnlock (intLevel);
  447.         }
  448.     pDrvCtrl->idr.ac_if.if_flags = 0;
  449.     }
  450. /*******************************************************************************
  451. *
  452. * eiIoctl - interface ioctl procedure
  453. *
  454. * Process an interface ioctl request.
  455. */
  456. static int eiIoctl
  457.     (
  458.     IDR     *pIDR,
  459.     int     cmd,
  460.     caddr_t data
  461.     )
  462.     {
  463.     int error;
  464. #ifdef EI_DEBUG
  465.     printf ("ei: ioctl: pIDR=%x cmd=%x data=%xn", pIDR, cmd, data);
  466. #endif /* EI_DEBUG */
  467.     error = 0;
  468.     switch (cmd)
  469.         {
  470.         case SIOCSIFADDR:
  471.             ((struct arpcom *)pIDR)->ac_ipaddr = IA_SIN (data)->sin_addr;
  472.             arpwhohas (pIDR, &IA_SIN (data)->sin_addr);
  473.             break;
  474.         case SIOCSIFFLAGS:
  475.             /* Flags are set outside this module. No additional work to do. */
  476.             break;
  477.         default:
  478.             error = EINVAL;
  479.         }
  480.     return (error);
  481.     }
  482. #ifdef BSD43_DRIVER
  483. /*******************************************************************************
  484. *
  485. * eiOutput - interface output routine.
  486. *
  487. * This is the entry point for packets arriving from protocols above.  This
  488. * routine merely calls our specific output routines that eventually lead
  489. * to a transmit to the network.
  490. *
  491. * RETURNS: 0 or appropriate errno
  492. */
  493. static int eiOutput
  494.     (
  495.     IDR *    pIDR,
  496.     MBUF *     pMbuf,
  497.     SOCK * pDestAddr
  498.     )
  499.     {
  500. #ifdef EI_DEBUG
  501.     printf ("ei: output: pIDR=%x pMbuf=%x pDestAddr=%xn",
  502.             pIDR, pMbuf, pDestAddr);
  503. #endif /* EI_DEBUG */
  504.     return (ether_output ((IFNET *)pIDR, pMbuf, pDestAddr,
  505.             (FUNCPTR) eiTxStartup, pIDR));
  506.     }
  507. #endif
  508. /*******************************************************************************
  509. *
  510. * eiTxStartup - start output on the chip
  511. *
  512. * Looks for any action on the queue, and begins output if there is anything
  513. * there. This routine is called from several possible threads. Each will be
  514. * described below.
  515. *
  516. * The first, and most common thread, is when a user task requests the
  517. * transmission of data. Under BSD 4.3, this will cause eiOutput() to be 
  518. * called, which calls ether_output(), which will usually call this routine.
  519. * This routine will not be called if ether_output() finds that our interface 
  520. * output queue is full. In this case, the outgoing data will be thrown out.
  521. * BSD 4.4 uses a slightly different model in which the generic ether_output()
  522. * routine is called directly, followed by a call to this routine.
  523. *
  524. * The second, and most obscure thread, is when the reception of certain
  525. * packets causes an immediate (attempted) response. For example, ICMP echo
  526. * packets (ping), and ICMP "no listener on that port" notifications. All
  527. * functions in this driver that handle the reception side are executed in the
  528. * context of netTask(). Always. So, in the case being discussed, netTask() will
  529. * receive these certain packets, cause IP to be stimulated, and cause the
  530. * generation of a response to be sent. We then find ourselves following the
  531. * thread explained in the second example, with the important distinction that
  532. * the context is that of netTask().
  533. *
  534. * The third thread occurs when this routine runs out of TFDs and returns. If
  535. * this occurs when our output queue is not empty, this routine would typically
  536. * not get called again until new output was requested. Even worse, if the
  537. * output queue was also full, this routine would never get called again and
  538. * we would have a lock state. It DOES happen. To guard against this, the
  539. * transmit clean-up handler detects the out-of-TFDs state and calls this
  540. * function. The clean-up handler also runs from netTask.
  541. *
  542. * Note that this function is ALWAYS called between an splnet() and an splx().
  543. * This is true because netTask(), and ether_output() take care of
  544. * this when calling this function. Therefore, no calls to these spl functions
  545. * are needed anywhere in this output thread.
  546. */
  547. #ifdef BSD43_DRIVER
  548. static void eiTxStartup
  549.     (
  550.     int unit
  551.     )
  552.     {
  553.     DRV_CTRL * pDrvCtrl = & drvCtrl [unit];
  554. #else
  555. static void eiTxStartup
  556.     (
  557.     DRV_CTRL *  pDrvCtrl  /* driver control structure */
  558.     )
  559.     {
  560. #endif
  561.     MBUF * pMbuf;
  562.     int length;
  563.     TFD * pTfd;
  564.     /*
  565.      * Loop until there are no more packets ready to send or we
  566.      * have insufficient resources left to send another one.
  567.      */
  568.     while (pDrvCtrl->idr.ac_if.if_snd.ifq_head)
  569.         {
  570.         /* get free tfd */
  571.         pTfd = (TFD *) eiQGet ((EI_LIST *)&pDrvCtrl->tfdQueue);
  572.         if (pTfd == NULL)
  573.             break;                              /* out of TFD's */
  574.         IF_DEQUEUE (&pDrvCtrl->idr.ac_if.if_snd, pMbuf);  /* dequeue a packet */
  575.         copy_from_mbufs ((ETH_HDR *)pTfd->enetHdr, pMbuf, length);
  576.         length = max (ETHERSMALL, length);
  577.         if ((etherOutputHookRtn != NULL) &&
  578.             (* etherOutputHookRtn)
  579.             (&pDrvCtrl->idr, (ETH_HDR *)pTfd->enetHdr, length))
  580.             continue;
  581.         pTfd->count = length & ~0xc000;     /* fill in length */
  582.         eiTxQPut (pDrvCtrl, pTfd);
  583. #ifndef BSD43_DRIVER    /* BSD 4.4 ether_output() doesn't bump statistic. */
  584.         pDrvCtrl->idr.ac_if.if_opackets++;
  585. #endif
  586.         }
  587.     }
  588. /*******************************************************************************
  589. *
  590. * eiInt - entry point for handling interrupts from the 82596
  591. *
  592. * The interrupting events are acknowledged to the device, so that the device
  593. * will deassert its interrupt signal. The amount of work done here is kept
  594. * to a minimum; the bulk of the work is defered to the netTask. Several flags
  595. * are used here to synchronize with task level code and eliminate races.
  596. */
  597. static void eiInt
  598.     (
  599.     DRV_CTRL *pDrvCtrl
  600.     )
  601.     {
  602.     UINT16  event;
  603.     SCB *pScb;
  604.     int unit;
  605.     pScb = pDrvCtrl->pScb;
  606.     unit = pDrvCtrl->idr.ac_if.if_unit;
  607.     event = pScb->scbStatus & (SCB_S_CX | SCB_S_FR | SCB_S_CNA | SCB_S_RNR);
  608. #ifdef EI_DEBUG
  609.     logMsg ("ei: interrupt: event=%xn", event, 0, 0, 0, 0, 0);
  610. #endif /* EI_DEBUG */
  611.     eiCommand (pDrvCtrl, event);                        /* ack the events */
  612.     /* Handle transmitter interrupt */
  613.     if (event & SCB_S_CNA)                              /* reclaim tx tfds */
  614.         {
  615.         wdCancel(pDrvCtrl->wid);
  616.         if (pDrvCtrl->cleanQueue.head == NULL)      /* clean queue empty */
  617.             {
  618.             pDrvCtrl->cleanQueue.head = pDrvCtrl->cblQueue.head; /* new head */
  619.             pDrvCtrl->cleanQueue.tail = pDrvCtrl->cblQueue.tail; /* new tail */
  620.             }
  621.         else                                            /* concatenate queues */
  622.             {
  623.             pDrvCtrl->cleanQueue.tail->pNext =
  624.                         (EI_NODE*) pDrvCtrl->cblQueue.head;
  625.             pDrvCtrl->cleanQueue.tail = pDrvCtrl->cblQueue.tail;
  626.             }
  627.         if (!pDrvCtrl->txCleaning)                          /* not cleaning? */
  628.             {
  629.             pDrvCtrl->txCleaning = TRUE;                    /* set flag */
  630.             netJobAdd ((FUNCPTR) eiTxCleanQ, (int) pDrvCtrl, 0, 0, 0, 0);
  631.                             /* defer cleanup */
  632.             }
  633.         if (pDrvCtrl->txQueue.head != NULL)             /* anything to flush? */
  634.             eiTxQFlush (pDrvCtrl);                      /* flush the tx q */
  635.         else
  636.             pDrvCtrl->txIdle = TRUE;                    /* transmitter idle */
  637.         }
  638.     /* Handle receiver interrupt */
  639.     if ((event & SCB_S_FR) && !(pDrvCtrl->rcvHandling))
  640.         {
  641.         pDrvCtrl->rcvHandling = TRUE;
  642.         (void) netJobAdd ((FUNCPTR) eiHandleRecvInt, (int) pDrvCtrl,0, 0, 0, 0);         /* netTask processes */
  643.         }
  644.     }
  645. /*******************************************************************************
  646. *
  647. * eiTxCleanQ - checks errors in completed TFDs and moves TFDs to free queue
  648. *
  649. * This routine is executed by netTask. It "cleans" the TFDs on the clean-up
  650. * queue by checking each one for errors and then returning the TFD to the
  651. * "free TFD" queue. The startup routine is sometimes called here to eliminate
  652. * the lock-out case where the driver input queue is full but there are no
  653. * TFDs available.
  654. */
  655. static void eiTxCleanQ
  656.     (
  657.     DRV_CTRL *pDrvCtrl
  658.     )
  659.     {
  660.     TFD *pTfd;
  661.     BOOL needTxStart;
  662.     int unit;
  663. int intLevel;
  664.     unit = pDrvCtrl->idr.ac_if.if_unit;
  665.     do
  666.         {
  667.         pDrvCtrl->txCleaning = TRUE;
  668.         if (pDrvCtrl->tfdQueue.head == NULL)              /* tfd queue empty */
  669.             needTxStart = TRUE;                           /* set flag */
  670.         else
  671.             needTxStart = FALSE;
  672.         /* process transmitted frames */
  673.         while (1)
  674.             {
  675.             /* Get TFD. No ints allowed while manipulating this queue. */
  676. /* Disable system interrupts (NOTE #1) */
  677. intLevel = intLock ();
  678.             pTfd = (TFD*) eiQGet ((EI_LIST *)&pDrvCtrl->cleanQueue);
  679. /* Re-enable system interrupts */
  680.      intUnlock (intLevel);
  681.             if (pTfd == NULL)
  682.                 break;
  683.             pDrvCtrl->idr.ac_if.if_collisions +=         /* add any colls */
  684.                 (pTfd->status & CFD_S_RETRY) ? 16 :  /* excessive colls */
  685.                 (pTfd->status & CFD_S_COLL_MASK);    /* some colls */
  686.             if (!(pTfd->status & CFD_S_OK))          /* packet not sent */
  687.                 {
  688.                 pDrvCtrl->idr.ac_if.if_oerrors++;        /* incr err count */
  689.                 pDrvCtrl->idr.ac_if.if_opackets--;       /* decr sent count */
  690.                 }
  691.             /* return to tfdQ */
  692.             eiQPut (unit,(EI_LIST *)&pDrvCtrl->tfdQueue, (EI_NODE*)pTfd);
  693.             }
  694.         if (needTxStart)                                  /* check flag */
  695. #ifdef BSD43_DRIVER
  696.             eiTxStartup (unit);
  697. #else
  698.             eiTxStartup (pDrvCtrl);
  699. #endif
  700.         pDrvCtrl->txCleaning = FALSE;
  701.         }
  702.     while (pDrvCtrl->cleanQueue.head != NULL);            /* check again */
  703.     }
  704. /*******************************************************************************
  705. *
  706. * eiHandleRecvInt - task level interrupt service for input packets
  707. *
  708. * This routine is called at task level indirectly by the interrupt
  709. * service routine to do any message received processing.
  710. */
  711. static void eiHandleRecvInt
  712.     (
  713.     DRV_CTRL *pDrvCtrl
  714.     )
  715.     {
  716.     RFD *pRfd;
  717.     do
  718.         {
  719.         pDrvCtrl->rcvHandling = TRUE;             /* interlock with eiInt() */
  720.         while ((pRfd = eiRxQGet (pDrvCtrl)) != NULL)
  721.             if (eiReceive (pDrvCtrl, pRfd) == OK)
  722.                 eiRxQPut (pDrvCtrl, pRfd);
  723.         pDrvCtrl->rcvHandling = FALSE;            /* interlock with eiInt() */
  724.         }
  725.     while (eiRxQFull (pDrvCtrl));              /* make sure rx q still empty */
  726.     }
  727. /*******************************************************************************
  728. *
  729. * eiReceive - pass a received frame to the next layer up
  730. *
  731. * Strips the Ethernet header and passes the packet to the appropriate
  732. * protocol. The return value indicates if buffer loaning was used to hold
  733. * the data. A return value of OK means that loaning was not done, and it
  734. * is therefore 'ok' to return the RFD to the Rx queue. A return value of ERROR
  735. * means that buffer loaning was employed, and so the RFD is still in use and
  736. * should not be returned to the Rx queue. In this latter case, the RFD will
  737. * eventually be returned by the protocol, via a call to our eiLoanFree().
  738. */
  739. static STATUS eiReceive
  740.     (
  741.     DRV_CTRL *pDrvCtrl,
  742.     RFD *pRfd
  743.     )
  744.     {
  745.     ETH_HDR     *pEh;
  746.     u_char      *pData;
  747.     int         len;
  748. #ifdef BSD43_DRIVER
  749.     UINT16      etherType;
  750. #endif
  751.     MBUF        *m = NULL;
  752.     BOOL        rfdLoaned = FALSE;
  753.     /* Check packet for errors.  This should be completely unnecessary,
  754.      * but since Intel does not seem capable of explaining the exact
  755.      * functioning of the 'save bad frames' config bit, we will look for
  756.      * errors.
  757.      */
  758.     if  (
  759.         ( pRfd->status & ( RFD_S_OK | RFD_S_COMPLETE ) ) !=
  760.         ( RFD_S_OK | RFD_S_COMPLETE )
  761.         )
  762.         {
  763.         ++pDrvCtrl->idr.ac_if.if_ierrors;            /* bump error counter */
  764.         eiRxQPut (pDrvCtrl, pRfd);                   /* free the RFD */
  765.         return (ERROR);
  766.         }
  767.     /* Bump input packet counter. */
  768.     ++pDrvCtrl->idr.ac_if.if_ipackets;
  769.     len = pRfd->actualCnt & ~0xc000;        /* get frame length */
  770.     pEh = (ETH_HDR *)pRfd->enetHdr;         /* get ptr to ethernet header */
  771.     /* Service input hook */
  772.     if ( (etherInputHookRtn != NULL) )
  773.         {
  774.         if  ( (* etherInputHookRtn) (&pDrvCtrl->idr, (char *)pEh, len) )
  775.             {
  776.             eiRxQPut (pDrvCtrl, pRfd);                  /* free the RFD */
  777.             return (OK);
  778.             }
  779.         }
  780.     len -= EH_SIZE;
  781.     pData = (u_char *) pRfd->enetData;
  782. #ifdef BSD43_DRIVER
  783.     etherType = ntohs (pEh->ether_type);
  784. #endif
  785.     /* we can loan out receive frames from 82596 receive queue if:
  786.      *
  787.      * 1) the threshold of loanable frames has not been exceeded
  788.      * 2) size of the input ethernet frame is large enough to be used with
  789.      *    clustering.
  790.      */
  791.     if ((pDrvCtrl->nLoanRfds > 0) && (USE_CLUSTER (len)) &&
  792.         ((m = build_cluster (pData, len, &pDrvCtrl->idr, MC_EI, &pRfd->refCnt,
  793.                  eiLoanFree, (int) pDrvCtrl, (int) pRfd, NULL)) != NULL))
  794.         {
  795.         pDrvCtrl->nLoanRfds --;             /* one less to loan */
  796.         rfdLoaned = TRUE;               /* we loaned a frame */
  797.         }
  798.     else
  799.         m = copy_to_mbufs (pData, len, 0, &pDrvCtrl->idr);
  800.     if (m != NULL)
  801. #ifdef BSD43_DRIVER
  802.         do_protocol_with_type (etherType, m, &pDrvCtrl->idr, len);
  803. #else
  804.         do_protocol (pEh, m, &pDrvCtrl->idr, len);
  805. #endif
  806.     else
  807.         pDrvCtrl->idr.ac_if.if_ierrors++;       /* bump error counter */
  808.     return ((rfdLoaned) ? ERROR : OK);
  809.     }
  810. /*******************************************************************************
  811. *
  812. * eiLoanFree - return a loaned receive frame descriptor
  813. *
  814. * This routine is called by the protocol code when it has completed use of
  815. * an RFD that we loaned to it.
  816. */
  817. static void eiLoanFree
  818.     (
  819.     DRV_CTRL *pDrvCtrl,
  820.     RFD *pRfd
  821.     )
  822.     {
  823.     eiRxQPut (pDrvCtrl, pRfd);
  824.     pDrvCtrl->nLoanRfds ++;
  825.     }
  826. /*******************************************************************************
  827. *
  828. * eiDeviceStart - reset and start the device
  829. *
  830. * This routine assumes interrupts from the device have been disabled, and
  831. * that the driver control structure has been initialized.
  832. */
  833. static STATUS eiDeviceStart
  834.     (
  835.     int unit                              /* physical unit number */
  836.     )
  837.     {
  838.     void     *pTemp;
  839.     DRV_CTRL *pDrvCtrl;
  840.     SCP      *pScp;                       /* system config ptr */
  841.     ISCP     *pIscp;                      /* intermediate system config ptr */
  842.     SCB      *pScb;                       /* system control block ptr */
  843. unsigned long loopy;
  844.     /* Get pointers */
  845.     pDrvCtrl = & drvCtrl [unit];
  846.     pScp = pDrvCtrl->pScp;
  847.     pIscp = pDrvCtrl->pIscp;
  848.     pScb = pDrvCtrl->pScb;
  849.     /* Issue the reset operation to the device */
  850.     sys596Port (unit, PORT_RESET, NULL);
  851.     /* Initialize the SCP */
  852.     pScp->scpRsv1 =
  853.     pScp->scpRsv2 =
  854.     pScp->scpRsv3 = 0;
  855.     pScp->scpSysbus = pDrvCtrl->sysbus;
  856.     pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, pIscp);
  857.     LINK_WR (&pScp->pIscp, pTemp);              /* point SCP to ISCP */
  858.     /* Initialize the ISCP */
  859.     pIscp->iscpBusy = 1;
  860.     pIscp->iscpRsv1 = 0;
  861.     pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, pScb);
  862.     LINK_WR (&pIscp->pScb, pTemp);              /* point ISCP to SCB */
  863.     /* Initialize the SCB */
  864.     bzero ((char *)pScb, sizeof (SCB));
  865.     /* Tell the device where the SCP is located */
  866.     pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, pScp);
  867.     sys596Port (unit, PORT_NEWSCP, (UINT32) pTemp);
  868.     sys596ChanAtn (unit);
  869.     /*
  870.      * The device will now read our SCP and ISCP. It will clear the busy
  871.      * flag in the ISCP.
  872.      */
  873. /* Delay here for ample time.  Can not use taskDelay() because all
  874.  * interrupts have been enabled, and thus no clock ticks.
  875.  */
  876. for ( loopy = 0x00100000; loopy--; )
  877. ;
  878.     if ( pIscp->iscpBusy == 1 )
  879.         return (ERROR);
  880.     return (OK);
  881.     }
  882. /*******************************************************************************
  883. *
  884. * eiDiag - format and issue a diagnostic command
  885. */
  886. static STATUS eiDiag
  887.     (
  888.     int unit
  889.     )
  890.     {
  891.     DRV_CTRL *pDrvCtrl;
  892.     pDrvCtrl = & drvCtrl [unit];
  893.     bzero ((char *)pDrvCtrl->pCfd, sizeof (CFD));       /* zero command frame */
  894.     eiAction (unit, CFD_C_DIAG);                /* run diagnostics */
  895.     if (!(pDrvCtrl->pCfd->cfdStatus & CFD_S_OK))
  896.         return (ERROR);
  897. return (OK);
  898.     }
  899. /*******************************************************************************
  900. *
  901. * eiConfig - format and issue a config command
  902. */
  903. static void eiConfig
  904.     (
  905.     int unit
  906.     )
  907.     {
  908.     DRV_CTRL *pDrvCtrl;
  909.     pDrvCtrl = & drvCtrl [unit];
  910.     bzero ((char *)pDrvCtrl->pCfd, sizeof (CFD));       /* zero command frame */
  911.     /* Recommeded i82596 User's Manual configuration values.  Note that
  912.      * the original manual, #296443-001, was full of errors.  Errors in the
  913.      * description of the config bytes that I am aware of are noted below.
  914.      * It is possible there are further errors.  Intel has replaced the
  915.      * manual with #296853-001, which does correct some errors, but not all.
  916.      */
  917.     pDrvCtrl->pCfd->cfdConfig.ccByte8  = 0x8e;
  918.     pDrvCtrl->pCfd->cfdConfig.ccByte9  = 0xc8;
  919.     /* The manual is wrong about bit 7 in byte 10.
  920.      * A '0' allows reception of bad packets.
  921.      * A '1' causes rejection of bad packets.
  922.      */
  923.     pDrvCtrl->pCfd->cfdConfig.ccByte10 = 0xc0;
  924.     pDrvCtrl->pCfd->cfdConfig.ccByte11 = 0x2e;      /* loopback, NSAI */
  925.     pDrvCtrl->pCfd->cfdConfig.ccByte12 = 0x00;
  926.     pDrvCtrl->pCfd->cfdConfig.ccByte13 = 0x60;
  927.     pDrvCtrl->pCfd->cfdConfig.ccByte14 = 0x00;
  928.     pDrvCtrl->pCfd->cfdConfig.ccByte15 = 0xf2;
  929.     pDrvCtrl->pCfd->cfdConfig.ccByte16 = 0x00;      /* promiscuous off */
  930.     pDrvCtrl->pCfd->cfdConfig.ccByte17 = 0x00;
  931.     pDrvCtrl->pCfd->cfdConfig.ccByte18 = 0x40;
  932.     /* The manual is wrong about 2 bits in byte 19.
  933.      * Bit 5, multicast, a '1' disables.
  934.      * Bit 2, include CRC, a '1' disables.
  935.      */
  936.     pDrvCtrl->pCfd->cfdConfig.ccByte19 = 0xff;
  937.     pDrvCtrl->pCfd->cfdConfig.ccByte20 = 0x00;
  938.     pDrvCtrl->pCfd->cfdConfig.ccByte21 = 0x3f;
  939.     eiAction (unit, CFD_C_CONFIG);          /* configure the chip */
  940.     }
  941. /*******************************************************************************
  942. *
  943. * eiIASetup - format and issue an interface address command
  944. */
  945. static void eiIASetup
  946.     (
  947.     int unit
  948.     )
  949.     {
  950.     DRV_CTRL *pDrvCtrl;
  951.     pDrvCtrl = & drvCtrl [unit];
  952.     bzero ((char *)pDrvCtrl->pCfd, sizeof (CFD));       /* zero command frame */
  953.     bcopy   (
  954.             (char *)pDrvCtrl->idr.ac_enaddr,
  955.             (char *)pDrvCtrl->pCfd->cfdIASetup.ciAddress,
  956.             6
  957.             );
  958.     eiAction (unit, CFD_C_IASETUP);         /* setup the address */
  959.     }
  960. /*******************************************************************************
  961. *
  962. * eiRxStartup - start up the Receive Unit
  963. *
  964. * Starts up the Receive Unit.  Assumes that the receive structures are set up.
  965. */
  966. static void eiRxStartup
  967.     (
  968.     DRV_CTRL *pDrvCtrl
  969.     )
  970.     {
  971.     SCB *pScb = pDrvCtrl->pScb;
  972.     void * pTemp;
  973. int intLevel;
  974.     if (pScb->scbStatus & SCB_S_RUREADY)        /* already running */
  975.         return;
  976.     pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, pDrvCtrl->pFreeRfd);
  977.     LINK_WR (&pScb->pRF, pTemp);            /* point to free Rfd */
  978. /* Disable system interrupts (NOTE #1) */
  979. intLevel = intLock ();
  980.     if ((pScb->scbStatus & SCB_S_RUMASK) != SCB_S_RUIDLE)
  981.         eiCommand (pDrvCtrl, SCB_C_RUABORT);            /* abort if not idle */
  982.     eiCommand (pDrvCtrl, SCB_C_RUSTART);              /* start receive unit */
  983. /* Re-enable system interrupts */
  984.     intUnlock (intLevel);
  985.     }
  986. /*******************************************************************************
  987. *
  988. * eiAction - execute the specified action with the CFD pointed to in pDrvCtrl
  989. *
  990. * Do the command contained in the CFD synchronously, so that we know
  991. * it's complete upon return.  This routine assumes that interrupts from the
  992. * device have been disabled.
  993. */
  994. static void eiAction
  995.     (
  996.     int    unit,
  997.     UINT16 action
  998.     )
  999.     {
  1000.     void     *pTemp;
  1001.     CFD      *pCfd;
  1002.     SCB      *pScb;
  1003.     DRV_CTRL *pDrvCtrl;
  1004.     pDrvCtrl = & drvCtrl [unit];
  1005.     pCfd = pDrvCtrl->pCfd;
  1006.     pScb = pDrvCtrl->pScb;
  1007.     while (1)                   /* wait for idle command unit */
  1008.         {
  1009.         if ((pScb->scbStatus & SCB_S_CUMASK) == SCB_S_CUIDLE)
  1010.             break;
  1011.         }
  1012.     { /* Prepare and issue the command to the device */
  1013.     /* fill in CFD */
  1014.     pCfd->cfdStatus  = 0;                       /* clear status */
  1015.     pCfd->cfdCommand = CFD_C_EL | action;       /* fill in action */
  1016.     LINK_WR (&pCfd->link, NULL);                /* terminate link */
  1017.     /* and the SCB */
  1018.     pScb->scbCommand =
  1019.                         SCB_S_CX |              /* ack any events */
  1020.                         SCB_S_FR |
  1021.                         SCB_S_CNA |
  1022.                         SCB_S_RNR |
  1023.                         SCB_C_CUSTART;          /* start command unit */
  1024.     pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, pCfd);
  1025.     LINK_WR (&pScb->pCB, pTemp);                /* point chip at CFD */
  1026.     sys596ChanAtn (unit);               /* notify device of new command */
  1027.     }
  1028.     while (1)               /* wait for command acceptance and interrupt */
  1029.         {
  1030.         if ((pScb->scbCommand == 0) && (pScb->scbStatus & SCB_S_CNA))
  1031.             break;
  1032.         }
  1033.     /* Acknowledge the event to the device */
  1034.     pScb->scbCommand = (SCB_S_CX | SCB_S_CNA);
  1035.     sys596ChanAtn (unit);
  1036.     while (1)               /* wait for acknowledge acceptance */
  1037.         {
  1038.         if (pScb->scbCommand == 0)
  1039.             break;
  1040.         }
  1041.     }
  1042. /*******************************************************************************
  1043. *
  1044. * eiCommand - deliver a command to the 82596 via SCB
  1045. *
  1046. * This function causes the device to execute a command. It should be called
  1047. * with interrupts from the device disabled. An error status is returned if
  1048. * the command field does not return to zero, from a previous command, in a
  1049. * reasonable amount of time.
  1050. */
  1051. static STATUS eiCommand
  1052.     (
  1053.     DRV_CTRL *pDrvCtrl,
  1054.     UINT16    cmd
  1055.     )
  1056.     {
  1057.     SCB * pScb;
  1058.     pScb = pDrvCtrl->pScb;
  1059.     while (1)
  1060.         {
  1061.         if (pScb->scbCommand == 0)                  /* wait for cmd zero */
  1062.             break;
  1063.         }
  1064.     pScb->scbCommand = cmd;                     /* fill in command */
  1065.     sys596ChanAtn (pDrvCtrl->idr.ac_if.if_unit);    /* channel attention */
  1066.     return (OK);
  1067.     }
  1068. /*******************************************************************************
  1069. *
  1070. * eiTxQPut - place a transmit frame on the transmit queue
  1071. *
  1072. * The TFD has been filled in with the network pertinent data. This
  1073. * routine will enqueue the TFD for transmission and attempt to feed
  1074. * the queue to the device.
  1075. */
  1076. static void eiTxQPut
  1077.     (
  1078.     DRV_CTRL *pDrvCtrl,
  1079.     TFD *pTfd
  1080.     )
  1081.     {
  1082.     int unit;
  1083. int intLevel;
  1084.     unit = pDrvCtrl->idr.ac_if.if_unit;
  1085.     pTfd->status    = 0;                    /* fill in TFD fields */
  1086.     pTfd->command   = CFD_C_XMIT;           /* EL set later */
  1087.     pTfd->count     |= TFD_CNT_EOF;         /* data kept in frame */
  1088.     pTfd->reserved  = 0;                    /* must be zero */
  1089.     LINK_WR (& pTfd->lBufDesc, NULL);                /* TBDs not used */
  1090. /* Disable system interrupts (NOTE #1) */
  1091. intLevel = intLock ();
  1092.     /* enqueue the TFD */
  1093.     eiQPut (unit,(EI_LIST *)&pDrvCtrl->txQueue, (EI_NODE*)pTfd);
  1094.     if (pDrvCtrl->txIdle)                             /* transmitter idle */
  1095.         eiTxQFlush (pDrvCtrl);                        /* flush txQueue */
  1096. /* Re-enable system interrupts */
  1097.     intUnlock (intLevel);
  1098.     }
  1099. /*******************************************************************************
  1100. *
  1101. * eiTxQFlush - make cmd unit of device start processing cmds
  1102. *
  1103. * This routine flushes the contents of the txQ to the cblQ and starts the
  1104. * device transmitting the cblQ. Called only if transmit queue is not empty.
  1105. * Sometimes called from interrupt handler.
  1106. */
  1107. static void eiTxQFlush
  1108.     (
  1109.     DRV_CTRL *pDrvCtrl
  1110.     )
  1111.     {
  1112.     void * pTemp;
  1113.     extern int sysClkRateGet();     /* we call this */
  1114.     ((TFD*)pDrvCtrl->txQueue.tail)->command |= CFD_C_EL;  /* EL terminate q */
  1115.     pDrvCtrl->cblQueue.head = pDrvCtrl->txQueue.head;   /* remember cbl head */
  1116.     pDrvCtrl->cblQueue.tail = pDrvCtrl->txQueue.tail;   /* remember cbl tail */
  1117.     eiQInit ((EI_LIST *)&pDrvCtrl->txQueue);            /* tx queue now empty */
  1118.     pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs,
  1119.                                     pDrvCtrl->cblQueue.head);
  1120.     LINK_WR (&pDrvCtrl->pScb->pCB, pTemp);          /* point CU to head */
  1121.     pDrvCtrl->txIdle = FALSE;                   /* transmitter busy */
  1122.     /* start watchdog */
  1123.     wdStart (
  1124.             pDrvCtrl->wid,
  1125.             (int) (sysClkRateGet() >> 1),
  1126.             (FUNCPTR) eiWatchDog,
  1127.             pDrvCtrl->idr.ac_if.if_unit
  1128.             );
  1129.     /* start command unit */
  1130.     eiCommand (pDrvCtrl, SCB_C_CUSTART);
  1131.     }
  1132. /*******************************************************************************
  1133. *
  1134. * eiRxQPut - return a RFD to the receive queue for use by the device
  1135. */
  1136. static void eiRxQPut
  1137.     (
  1138.     DRV_CTRL *pDrvCtrl,
  1139.     RFD *pRfd
  1140.     )
  1141.     {
  1142.     int unit;
  1143.     RFD *pTail;
  1144.     unit = pDrvCtrl->idr.ac_if.if_unit;
  1145.     pRfd->status    = 0;                    /* clear status */
  1146.     pRfd->command   = CFD_C_EL;             /* new end of list */
  1147.     pRfd->actualCnt  = 0;                   /* clear actual count */
  1148.     pRfd->bufSize   = ETHERMTU + EH_SIZE;   /* fill in size */
  1149.     pRfd->refCnt    = 0;                    /* initialize ref cnt */
  1150.     LINK_WR (& pRfd->lBufDesc, 0xffffffff);         /* no RBD used */
  1151.     pTail = (RFD *) pDrvCtrl->rxQueue.tail;         /* remember tail */
  1152.     /* Put the RFD on the list */
  1153.     eiQPut (unit, (EI_LIST *) & pDrvCtrl->rxQueue, (EI_NODE *) pRfd);
  1154.     if (pTail != NULL)
  1155.         {
  1156.         pTail->command &= ~CFD_C_EL;        /* clear old tail EL */
  1157.         if (pTail->status & (CFD_S_COMPLETE | CFD_S_BUSY))
  1158.             {
  1159.             pDrvCtrl->pFreeRfd = pRfd;          /* link questionable */
  1160.             }
  1161.         else if (!(pDrvCtrl->pScb->scbStatus & SCB_S_RUREADY))
  1162.             /* receiver dormant */
  1163.             {
  1164.             eiRxStartup (pDrvCtrl);             /* start receive unit */
  1165.             }
  1166.         }
  1167.     else
  1168.         {
  1169.         pDrvCtrl->pFreeRfd = pRfd;              /* first free RFD */
  1170.         }
  1171.     }
  1172. /*******************************************************************************
  1173. *
  1174. * eiRxQGet - get a successfully received frame from the receive queue
  1175. *
  1176. * RETURNS: ptr to valid RFD, or NULL if none available
  1177. */
  1178. static RFD *eiRxQGet
  1179.     (
  1180.     DRV_CTRL *pDrvCtrl
  1181.     )
  1182.     {
  1183.     RFD *pRfd = NULL;
  1184.     if (eiRxQFull (pDrvCtrl))
  1185.         pRfd = (RFD *) eiQGet ((EI_LIST *)&pDrvCtrl->rxQueue);
  1186.     return (pRfd);
  1187.     }
  1188. /*******************************************************************************
  1189. *
  1190. * eiRxQFull - boolean function to determine fullness of receive queue
  1191. *
  1192. * RETURNS: TRUE if completely received frame is available, FALSE otherwise.
  1193. */
  1194. static BOOL eiRxQFull
  1195.     (
  1196.     DRV_CTRL *pDrvCtrl
  1197.     )
  1198.     {
  1199.     return ((pDrvCtrl->rxQueue.head != NULL) &&
  1200.         (((RFD*)pDrvCtrl->rxQueue.head)->status & CFD_S_COMPLETE));
  1201.     }
  1202. /*******************************************************************************
  1203. *
  1204. * eiQInit - initialize a singly linked node queue
  1205. */
  1206. static void eiQInit
  1207.     (
  1208.     EI_LIST *pQueue
  1209.     )
  1210.     {
  1211.     pQueue->head = pQueue->tail = NULL;         /* init head & tail */
  1212.     }
  1213. /*******************************************************************************
  1214. *
  1215. * eiQGet - get a node from the head of a node queue
  1216. *
  1217. * RETURNS: ptr to useable node, or NULL ptr if none available
  1218. */
  1219. static EI_NODE *eiQGet
  1220.     (
  1221.     EI_LIST *pQueue
  1222.     )
  1223.     {
  1224.     EI_NODE *pNode;
  1225.     if ((pNode = (EI_NODE *) pQueue->head) != NULL)     /* if list not empty */
  1226.         pQueue->head = pNode->pNext;                    /* advance ptr */
  1227.     return (pNode);
  1228.     }
  1229. /*******************************************************************************
  1230. *
  1231. * eiQPut - put a node on the tail of a node queue
  1232. */
  1233. static void eiQPut
  1234.     (
  1235.     int unit,
  1236.     EI_LIST *pQueue,
  1237.     EI_NODE *pNode
  1238.     )
  1239.     {
  1240.     void * pTemp;
  1241.     DRV_CTRL *pDrvCtrl;
  1242.     pDrvCtrl = & drvCtrl [unit];
  1243.     LINK_WR (&pNode->lNext, NULL);                    /* mark "end of list" */
  1244.     pNode->pNext = NULL;
  1245.     if (pQueue->head == NULL)                        /* if list empty */
  1246.         pQueue->tail = pQueue->head = pNode;         /* set both ptrs */
  1247.     else
  1248.         {
  1249.         pTemp = CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, pNode);
  1250.         LINK_WR (&pQueue->tail->lNext, pTemp);       /* link node on tail */
  1251.         pQueue->tail->pNext = pNode;
  1252.         pQueue->tail = pNode;                        /* update tail ptr */
  1253.         }
  1254.     }
  1255. /*******************************************************************************
  1256. *
  1257. * eiWatchDog - if the watchdog timer fired off, we've hung during a transmit
  1258. *
  1259. * Check the scb command to verify and if so, reinit.
  1260. */
  1261. static void eiWatchDog
  1262.     (
  1263.     int unit        /* unit number */
  1264.     )
  1265.     {
  1266.     DRV_CTRL *pDrvCtrl;
  1267.     SCB *pScb;
  1268.     pScb = pDrvCtrl->pScb;
  1269.     pDrvCtrl = & drvCtrl [unit];
  1270.     /* sanity check.
  1271.      * If the scb status indicates that CU (transmit) is active
  1272.      * It might make sense to loop through the cfd's to look for
  1273.      * a complete bit as a sanity check , but given that we are
  1274.      * here and that transmit was active, we will go ahead and do
  1275.      * a reset.
  1276.      */
  1277.     if (pScb->scbStatus & SCB_S_CUACTIVE)
  1278.         {
  1279.         pDrvCtrl->transLocks++;                     /* local failure count */
  1280.         pDrvCtrl->idr.ac_if.if_oerrors++;           /* incr err count */
  1281.         pDrvCtrl->idr.ac_if.if_opackets--;          /* decr sent count */
  1282.         }
  1283.     }
  1284. /* NOTES
  1285.  *
  1286.  * NOTE #1:
  1287.  * The TP41 has a major design oversite.  The interrupt pin from the
  1288.  * 82596 connects directly to the CPU.  Since the 82596 provides no way
  1289.  * to disable the device from generating interrupts, there is no way to
  1290.  * selectively disable the 82596 interrupt.  The only option is to disable
  1291.  * all interrupts in the system during critical code regions.
  1292.  */
  1293. /* END OF FILE */