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

VxWorks

开发平台:

C/C++

  1. /* if_elt.c - 3Com 3C509 Ethernet network interface driver */
  2. /* Copyright 1993-1998 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01o,24sep98,dat  SPR 21261, discard packets only when complete.
  8. 01n,15jul97,spm  changed ioctl handler: added ARP request to SIOCSIFADDR and 
  9.                  cleaned up SIOCSIFFLAGS
  10. 01m,17mar97,hdn  added codes to load values in EEPROM to the address config
  11.  register and resource config register. 
  12. 01m,07apr97,spm  code cleanup, corrected statistics, and upgraded to BSD 4.4
  13. 01l,06mar96,hdn  supported PCMCIA EtherLink III card.
  14. 01k,14jun95,hdn  removed function declarations defined in sysLib.h.
  15. 01j,01feb95,jdi  doc cleanup.
  16. 01i,12nov94,tmk  removed some IMPORTed function decs and included unixLib.h
  17. 01h,28wed94,hdn  fixed a bug for RX incomplete packet.
  18.  cleaned up, eltFailure(), eltRxDrain(), eltTxCleanup().
  19. 01g,10apr94,hdn  made warm start work by clearing the interrupt latch bit.
  20. 01f,20feb94,bcs  add attachment (connector) type selection in eltattach(),
  21.                  relegate receive-in-net-task to compile-time selection
  22. 01e,07feb94,bcs  fix excessive transmit (and/or receive) net job queuing,
  23.                  add counters (as "ELT_TIMING") for netJobAdd() calls,
  24.                  remove rxInNetTask argument to eltattach(), update comments
  25. 01d,23jan94,bcs  call eltTxCleanup() and eltStatFlush() from interrupt handler,
  26.                  remove receive threshold (not obviously helping), add
  27.                  receive and interrupt timing statistics, fix comments
  28. 01c,16jan94,bcs  eliminated receive task (didn't help enough), consolidated
  29.                  packet receive routine into eltRxDrain, simplified transmit
  30.                  to handle only one packet at a time but 10% slower
  31. 01b,30dec93,bcs  fixed adapter failure int. handling, broke up attach routine
  32.                  added statistics capture
  33. 01a,10dec93,bcs  written
  34. */
  35. /*
  36. DESCRIPTION
  37. This module implements the 3Com 3C509 network adapter driver.
  38. The 3C509 (EtherLink(rg III) is not well-suited for use in real-time systems.
  39. Its meager on-board buffering (4K total; 2K transmit, 2K receive) forces the
  40. host processor to service the board at a high priority.  3Com makes a virtue
  41. of this necessity by adding fancy lookahead support and adding the label
  42. "Parallel Tasking" to the outside of the box.  Using 3Com's drivers, this board
  43. will look good in benchmarks that measure raw link speed.
  44. The board is greatly simplified by using the host CPU as a DMA controller.
  45. BOARD LAYOUT
  46. This device is soft-configured by a DOS-hosted program supplied by the
  47. manufacturer.  No jumpering diagram is required.
  48. EXTERNAL INTERFACE
  49. This driver provides the standard external interface with the following
  50. exceptions.  All initialization is performed within the attach routine and
  51. there is no separate initialization routine.  Thus, in the global interface
  52. structure, the function pointer to the initialization routine is NULL.
  53. There are two user-callable routines:
  54. .iP eltattach() 14
  55. publishes the `elt' interface and initializes the driver and device.
  56. .iP eltShow()
  57. displays statistics that are collected in the interrupt handler.
  58. .LP
  59. See the manual entries for these routines for more detail.
  60. SYSTEM RESOURCE USAGE
  61.     - one mutual exclusion semaphore
  62.     - one interrupt vector
  63.     - 16 bytes in the uninitialized data section (bss)
  64.     - 180 bytes (plus overhead) of malloc'ed memory per unit
  65.     - 1530 bytes (plus overhead) of malloc'ed memory per frame buffer,
  66.         minimum 5 frame buffers.
  67. SHORTCUTS
  68. The EISA and MCA versions of the board are not supported.
  69. Attachment selection assumes the board is in power-on reset state; a warm
  70. restart will not clear the old attachment selection out of the hardware,
  71. and certain new selections may not clear it either.  For example, if RJ45
  72. was selected, the system is warm-booted, and AUI is selected, the RJ45
  73. connector is still functional.
  74. Attachment type selection is not validated against the board's capabilities,
  75. even though there is a register that describes which connectors exist.
  76. The loaned buffer cluster type is MC_EI; no new type is defined yet.
  77. Although it seems possible to put the transmitter into a non-functioning
  78. state, it is not obvious either how to do this or how to detect the resulting
  79. state.  There is therefore no transmit watchdog timer.
  80. No use is made of the tuning features of the board; it is possible that
  81. proper dynamic tuning would reduce or eliminate the receive overruns
  82. that occur when receiving under task control (instead of in the ISR).
  83. TUNING HINTS
  84. More receive buffers (than the default 20) could help by allowing more
  85. loaning in cases of massive reception; four per receiving TCP connection plus
  86. four extras should be considered a minimum.
  87. INTERNAL
  88. A driver implementation for this board faces two conflicting network
  89. interface design goals:  (1) minimizing the time spent at interrupt level,
  90. and (2) servicing the board's input without dropping packets.  This
  91. implementation can be switched at run-time to meet either goal.
  92. Received data is drained from the board's FIFO in the interrupt handler.
  93. Many common TCP/IP occurrences, such as filling a 4K TCP window or
  94. fragmenting a 4K packet, can cause data to arrive faster than it can be
  95. drained at the task level.  This causes receive overruns and if the data
  96. stream continues for very long, the resulting retries may cause the transmitter
  97. to give up completely.
  98. One possible compromise has been tried and discarded: to receive at the
  99. task level in a high-priority task.  It turns out that the worst-case
  100. task-switching latency is too great to prevent the board from overrunning
  101. its receive FIFO often enough to be unacceptable.  Another possible compromise
  102. is to add code to switch between task-level and interrupt-level reception
  103. as necessary depending on the packet arrival rate.  Yet another possibility
  104. is to use the receive threshold feature of the board to receive a packet
  105. in chunks rather than all-or-nothing could make the interrupt-level reception
  106. more palatable in some applications; the threshold would be advanced by perhaps
  107. 200 bytes per interrupt until the whole packet has been read.
  108. The timing measurements represent an attempt to understand why the receiver
  109. performance is what it is, both interrupt-level and task-level.  The most
  110. important statistics are "timer overflows" and "max rx latency", where
  111. overflow is a latency greater than 255 timer ticks.  "Timer invalids" are
  112. not in themselves bad; it means that another interrupt (presumably transmit)
  113. occurred before the receiver was serviced and caused the timer to be reset
  114. (this is a hardware feature).
  115. SEE ALSO: ifLib
  116. */
  117. #define ELT_TIMING                          /* Compiles rx timing measurement */
  118. #include "vxWorks.h"
  119. #include "wdLib.h"
  120. #include "iv.h"
  121. #include "vme.h"
  122. #include "net/mbuf.h"
  123. #include "net/protosw.h"
  124. #include "socket.h"
  125. #include "ioctl.h"
  126. #include "errno.h"
  127. #include "memLib.h"
  128. #include "intLib.h"
  129. #include "net/if.h"
  130. #include "net/unixLib.h"
  131. #include "net/route.h"
  132. #include "iosLib.h"
  133. #include "errnoLib.h"
  134. #include "cacheLib.h"
  135. #include "logLib.h"
  136. #include "netLib.h"
  137. #include "stdio.h"
  138. #include "stdlib.h"
  139. #include "sysLib.h"
  140. #ifdef  INET
  141. #include "netinet/in.h"
  142. #include "netinet/in_systm.h"
  143. #include "netinet/in_var.h"
  144. #include "netinet/ip.h"
  145. #include "netinet/if_ether.h"
  146. #endif  /* INET */
  147. #include "etherLib.h"
  148. #include "net/systm.h"
  149. #include "sys/times.h"
  150. #include "net/if_subr.h"
  151. #include "drv/netif/if_elt.h"
  152. /* defines */
  153. #undef ELT_DEBUG                             /* Compiles debug output */
  154. #define MAX_UNITS 4 /* maximum units to support */
  155. #define DEF_NUM_RX_FRAMES 20 /* default number of rx buffers */
  156. #define MIN_NUM_RX_FRAMES 4 /* number we reserve from loaning */
  157. #define PARTIAL_TRANSFER_MASK   0xfffe  /* when pulling partial frames out */
  158.                                         /* of receive FIFO, transfer even */
  159.                                         /* words only */
  160. /* These should be in a common file but which one? */
  161. /* Ethernet attachment type selections */
  162. #define ATTACHMENT_DEFAULT      0       /* use card as configured */
  163. #define ATTACHMENT_AUI          1       /* AUI  (thick, DIX, DB-15) */
  164. #define ATTACHMENT_BNC          2       /* BNC  (thin, 10BASE-2) */
  165. #define ATTACHMENT_RJ45         3       /* RJ-45 (twisted pair, TPE, 10BASE-T)*/
  166. #define ELT_PRODUCTID_3C589 0x9058 /* product ID for PCMCIA 3C589 */
  167. /* globals */
  168. ELT_CTRL * pEltCtrl [MAX_UNITS];
  169. /* locals */
  170. /* forward function declarations */
  171. LOCAL void eltBoardInit (int unit);
  172. LOCAL STATUS eltMemoryInit (int unit);
  173. LOCAL void eltReset (int unit);
  174. LOCAL int eltIoctl (IDR * pIDR, int cmd, caddr_t data);
  175. #ifdef BSD43_DRIVER
  176. LOCAL int eltOutput (IDR * pIDR, MBUF * pMbuf, SOCK * pDestAddr);
  177. LOCAL void eltTxOutputStart (int unit);
  178. #else
  179. LOCAL void eltTxOutputStart (ELT_CTRL * pDrvCtrl);
  180. #endif
  181. LOCAL void eltInt (ELT_CTRL * pDrvCtrl);
  182. LOCAL void eltTxFlush (ELT_CTRL * pDrvCtrl, BOOL netJob);
  183. LOCAL void eltRxDeliver (ELT_CTRL * pDrvCtrl);
  184. LOCAL void eltLoanFree (ELT_CTRL * pDrvCtrl, ELT_FRAME * pFrame);
  185. LOCAL void eltRxFree (ELT_CTRL * pDrvCtrl, ELT_FRAME * pFrame);
  186. LOCAL void eltStatFlush (ELT_CTRL * pDrvCtrl);
  187. LOCAL void eltIntMaskSet (ELT_CTRL * pDrvCtrl, int maskBits);
  188. LOCAL void eltIntDisable (ELT_CTRL * pDrvCtrl);
  189. LOCAL void eltIntEnable (ELT_CTRL * pDrvCtrl);
  190. LOCAL void eltRxStart (ELT_CTRL * pDrvCtrl);
  191. LOCAL void eltTxStart (ELT_CTRL * pDrvCtrl);
  192. LOCAL STATUS eltActivate (ELT_CTRL * pDrvCtrl);
  193. LOCAL void eltIdCommand (int idPort);
  194. LOCAL UINT16 eltIdEepromRead (int address);
  195. LOCAL int eltEepromRead (int port, int offset);
  196. /*******************************************************************************
  197. *
  198. * eltEepromRead - read one 16-bit adapter EEPROM register.
  199. *
  200. * RETURNS: Value from an offset of the EEPROM.
  201. */
  202. LOCAL int eltEepromRead
  203.     (
  204.     int port,
  205.     int offset
  206.     )
  207.     {
  208.     int ix;
  209.     sysOutWord (port + EEPROM_CONTROL, 0x80 + offset);
  210.     /* wait 162 us minimum */
  211.     for (ix = 0; ix < 300; ix++)
  212. sysDelay ();
  213.     
  214.     return (sysInWord (port + EEPROM_DATA));
  215.     }
  216. /*******************************************************************************
  217. *
  218. * eltattach - publish the `elt' interface and initialize the driver and device
  219. *
  220. * The routine publishes the `elt' interface by filling in a network interface
  221. * record and adding this record to the system list.  This routine also
  222. * initializes the driver and the device to the operational state.
  223. *
  224. * RETURNS: OK or ERROR.
  225. *
  226. * SEE ALSO: ifLib
  227. */
  228. STATUS eltattach
  229.     (
  230.     int         unit,                   /* unit number */
  231.     int         port,                   /* base I/O address */
  232.     int         ivec,                   /* interrupt vector number */
  233.     int         intLevel,               /* interrupt level */
  234.     int         nRxFrames,              /* # of receive frames (0=default) */
  235.     int         attachment,             /* Ethernet connector to use */
  236.     char *ifName /* interface name */
  237.     )
  238.     {
  239.     ELT_CTRL *  pDrvCtrl;
  240.     int productID;
  241.     short *p;
  242.     /* Sanity check the unit number */
  243.     if (unit < 0 || unit >= MAX_UNITS)
  244.         return (ERROR);
  245.     /* allocate this unit's control structure the first time attach is called */
  246.     if (pEltCtrl [unit] == NULL)
  247.         {
  248.         pEltCtrl [unit] = malloc (sizeof (ELT_CTRL));
  249.         if (pEltCtrl [unit] == NULL)
  250.             return (ERROR);
  251.         bzero ( (char *) pEltCtrl [unit], sizeof (ELT_CTRL));
  252.         }
  253.     /* Ensure single invocation per system life */
  254.     pDrvCtrl = pEltCtrl [unit];
  255.     if (pDrvCtrl->attached)
  256.         return (OK);
  257.     /* it would be a good idea to validate these parameters.... */
  258.     pDrvCtrl->intLevel = intLevel; /* PC IRQ number */
  259.     pDrvCtrl->ivec = ivec; /* interrupt vector */
  260.     /* Determine which attachment is desired */
  261.     switch (attachment)
  262.         {
  263.         case ATTACHMENT_DEFAULT:
  264.         case ATTACHMENT_AUI:
  265.         case ATTACHMENT_BNC:
  266.         case ATTACHMENT_RJ45:
  267.             pDrvCtrl->attachment = attachment;
  268.             break;
  269.         default:
  270.             return (ERROR);             /* unknown value */
  271.         }
  272.     /* Find and activate the adapter */
  273.     pDrvCtrl->port = port;
  274.     productID = eltEepromRead (pDrvCtrl->port, EE_A_PRODUCT_ID);
  275.     if (productID == ELT_PRODUCTID_3C589)
  276. {
  277.         p = (short *)pDrvCtrl->idr.ac_enaddr;
  278. *p++ = htons (eltEepromRead (port, EE_A_OEM_NODE_0));
  279. *p++ = htons (eltEepromRead (port, EE_A_OEM_NODE_1));
  280. *p++ = htons (eltEepromRead (port, EE_A_OEM_NODE_2));
  281. sysOutWord (port + ELT_COMMAND, SELECT_WINDOW | WIN_CONFIG);
  282. sysOutWord (port + ADDRESS_CONFIG, eltEepromRead (port, EE_A_ADDRESS));
  283. sysOutWord (port + RESOURCE_CONFIG, eltEepromRead (port,EE_A_RESOURCE));
  284. }
  285.     else
  286.         if (eltActivate (pDrvCtrl) != OK)
  287.             return (ERROR);
  288.     eltBoardInit (unit);
  289.     /* Determine number of Rx descriptors to use */
  290.     pDrvCtrl->nRxFrames = nRxFrames ? nRxFrames : DEF_NUM_RX_FRAMES;
  291.     /* Publish the interface record */
  292.     if (strncmp (ifName, "pcmcia", 6) != 0)
  293. ifName = "elt";
  294. #ifdef BSD43_DRIVER
  295.     ether_attach    ( (IFNET *) & pDrvCtrl->idr, unit, ifName, (FUNCPTR) NULL,
  296.                     (FUNCPTR) eltIoctl, (FUNCPTR) eltOutput, (FUNCPTR) eltReset
  297.                     );
  298. #else
  299.     ether_attach    ( 
  300.                     (IFNET *) & pDrvCtrl->idr, 
  301.                     unit, 
  302.                     ifName, 
  303.                     (FUNCPTR) NULL,
  304.                     (FUNCPTR) eltIoctl, 
  305.                     (FUNCPTR) ether_output, 
  306.                     (FUNCPTR) eltReset
  307.                     );
  308.     pDrvCtrl->idr.ac_if.if_start = (FUNCPTR)eltTxOutputStart;
  309. #endif
  310.     if (eltMemoryInit (unit) != OK)
  311.         return (ERROR);
  312.     /* keep operating registers in window except in critical sections */
  313.     sysOutWord (port + ELT_COMMAND, SELECT_WINDOW | WIN_OPERATING);
  314.     /* Connect the interrupt handler */
  315.     if (intConnect ( (VOIDFUNCPTR *)INUM_TO_IVEC (pDrvCtrl->ivec),
  316.                     eltInt, (int)pDrvCtrl) == ERROR)
  317.         return (ERROR);
  318.     sysIntEnablePIC (intLevel);
  319.     eltIntEnable (pDrvCtrl);
  320.     /* Set our flag */
  321.     pDrvCtrl->attached = TRUE;
  322.     /* Set status flags in IDR */
  323.     pDrvCtrl->idr.ac_if.if_flags |= (IFF_UP | IFF_RUNNING | IFF_NOTRAILERS);
  324.     /* Successful return */
  325.     return (OK);
  326.     }
  327. /*******************************************************************************
  328. *
  329. * eltBoardInit - prepare the board for operation
  330. *
  331. */
  332. static void eltBoardInit
  333.     (
  334.     int unit
  335.     )
  336.     {
  337.     ELT_CTRL * pDrvCtrl;
  338.     int port;
  339.     int index;
  340.     UINT16 transceiver;
  341.     pDrvCtrl = pEltCtrl [unit];
  342.     port = pDrvCtrl->port;
  343.     eltIntDisable (pDrvCtrl);   /* make it OK to change register window */
  344.     sysOutWord (port + ELT_COMMAND, SELECT_WINDOW | WIN_ADDRESS);
  345.     for (index = 0; index < EA_SIZE; index++)
  346.         sysOutByte (port + index, pDrvCtrl->idr.ac_enaddr [index]);
  347.     /* Select the transceiver hardware (attachment) then do whatever is
  348.      * necessary to activate the selected attachment.
  349.      * A truly complete implementation would probably check to see
  350.      * if the selected attachment were present.
  351.      */
  352.     sysOutWord (port + ELT_COMMAND, SELECT_WINDOW | WIN_CONFIG);
  353.     transceiver = sysInWord (port + ADDRESS_CONFIG);
  354.     if (pDrvCtrl->attachment == ATTACHMENT_DEFAULT)
  355.         {
  356.         switch (transceiver & AC_XCVR_MASK)
  357.             {
  358.             case AC_XCVR_TPE:
  359.                 pDrvCtrl->attachment = ATTACHMENT_RJ45;
  360.                 break;
  361.             case AC_XCVR_BNC:
  362.                 pDrvCtrl->attachment = ATTACHMENT_BNC;
  363.                 break;
  364.             case AC_XCVR_AUI:
  365.                 pDrvCtrl->attachment = ATTACHMENT_AUI;
  366.                 break;
  367.             default:    /* there's only one other value; it's "reserved" */
  368.                 pDrvCtrl->attachment = ATTACHMENT_AUI;  /* good enough */
  369.                 break;
  370.             }
  371.         }
  372.     /* Now set the selected attachment type, even if it was already selected */
  373.     transceiver &= ~AC_XCVR_MASK;
  374.     switch (pDrvCtrl->attachment)
  375.         {
  376.         case ATTACHMENT_RJ45:
  377.             sysOutWord (port + ADDRESS_CONFIG, transceiver | AC_XCVR_TPE);
  378.             sysOutWord (port + ELT_COMMAND, SELECT_WINDOW | WIN_DIAGNOSTIC);
  379.             sysOutByte (port + MEDIA_STATUS,
  380.                         sysInByte (port + MEDIA_STATUS) |
  381.                         MT_S_JABBER_ENABLE | MT_S_LINK_BEAT_ENABLE);
  382.             break;
  383.         case ATTACHMENT_BNC:
  384.             sysOutWord (port + ADDRESS_CONFIG, transceiver | AC_XCVR_BNC);
  385.             sysOutWord (port + ELT_COMMAND, START_COAX);
  386.             break;
  387.         case ATTACHMENT_AUI:
  388.         default:
  389.             sysOutWord (port + ADDRESS_CONFIG, transceiver | AC_XCVR_AUI);
  390.             break;
  391.         }
  392.     /* enable normal Ethernet address recognition */
  393.     pDrvCtrl->rxFilter = RX_F_NORMAL;
  394.     /*
  395.      * Define the set of status bits that could cause interrupts.
  396.      * There is no interrupt cause indicator separate from the board status.
  397.      * To keep the ISR from seeing status conditions we didn't want to be
  398.      * interrrupted for, we must mask the STATUS off, not the interrupt.
  399.      * This prevents the condition from interrupting and also prevents
  400.      * the ISR from seeing the condition even if it is true.
  401.      * The interrupt mask is set only once to the set of all conditions
  402.      * we might want to be interrupted by; the status mask is set and
  403.      * cleared according to which conditions we want at any particular
  404.      * time.  The intMask field in the control structure
  405.      * is named for its effect; it is really used in the status mask
  406.      * command (3Com calls it the read zero mask).
  407.      */
  408.     /* enable the status bits we currently want to cause interrupts */
  409.     eltIntMaskSet (pDrvCtrl, ADAPTER_FAILURE | TX_COMPLETE |
  410.                              RX_COMPLETE | RX_EARLY | UPDATE_STATS);
  411.     /* enable the collection of statistics */
  412.     sysOutWord (port + ELT_COMMAND, STATS_ENABLE);
  413.     /* enable the hardware to generate interrupt requests */
  414.     sysOutWord (port + ELT_COMMAND, SELECT_WINDOW | WIN_CONFIG);
  415.     sysOutWord (port + CONFIG_CONTROL, CC_ENABLE);
  416.     sysOutWord (port + ELT_COMMAND, SELECT_WINDOW | WIN_OPERATING);
  417.     eltIntEnable (pDrvCtrl);
  418.     eltRxStart (pDrvCtrl);
  419.     eltTxStart (pDrvCtrl);
  420.     }
  421. /*******************************************************************************
  422. *
  423. * eltMemoryInit - initialize memory structures
  424. *
  425. * The only thing we allocate from system meory besides the driver control
  426. * structure is the frame buffer pool.  Here we malloc it as one big region
  427. * and divide it up into receive and transmit buffers.
  428. */
  429. static STATUS eltMemoryInit
  430.     (
  431.     int unit
  432.     )
  433.     {
  434.     ELT_CTRL * pDrvCtrl;
  435.     ELT_FRAME * pFrame;
  436.     int         index;
  437.     pDrvCtrl = pEltCtrl [unit];
  438.     /* Initialize our data structures */
  439.     pDrvCtrl->pFrameArea = malloc ( (1 + pDrvCtrl->nRxFrames)
  440.                                     * sizeof (ELT_FRAME));
  441.     if (pDrvCtrl->pFrameArea == NULL)
  442.         return (ERROR);
  443.     pFrame = pDrvCtrl->pFrameArea;
  444.     pDrvCtrl->pTxFrame = pFrame++;              /* first allocate tx frame */
  445.     pDrvCtrl->pRxHead = pFrame;                 /* first rx frame */
  446.     for (index = pDrvCtrl->nRxFrames; index > 0; index--)
  447.         {
  448.         pFrame->count = 0;
  449.         pFrame->nextByte = pFrame->header;
  450.         pFrame->length = 0;
  451.         pFrame->lNext = pFrame + 1;
  452.         pFrame++;
  453.         }
  454.     pDrvCtrl->pRxTail = pFrame - 1;             /* last rx frame */
  455.     pDrvCtrl->pRxTail->lNext = NULL;
  456.     pDrvCtrl->pRxCurrent = pDrvCtrl->pRxHead;
  457.     pDrvCtrl->nLoanFrames = pDrvCtrl->nRxFrames - MIN_NUM_RX_FRAMES;
  458.     return (OK);
  459.     }
  460. /*******************************************************************************
  461. *
  462. * eltReset - reset the elt interface
  463. *
  464. * Mark interface as inactive and reset the adapter.
  465. */
  466. static void eltReset
  467.     (
  468.     int unit
  469.     )
  470.     {
  471.     ELT_CTRL * pDrvCtrl;
  472.     pDrvCtrl = pEltCtrl [unit];
  473.     eltIntDisable (pDrvCtrl);           /* prevent device from interrupting */
  474.     sysOutWord (pDrvCtrl->port + ELT_COMMAND, RX_RESET);
  475.     sysOutWord (pDrvCtrl->port + ELT_COMMAND, TX_RESET);
  476.     }
  477. /*******************************************************************************
  478. *
  479. * eltIoctl - interface ioctl procedure
  480. *
  481. * Process an interface ioctl request.
  482. */
  483. static int eltIoctl
  484.     (
  485.     IDR     *pIDR,
  486.     int     cmd,
  487.     caddr_t data
  488.     )
  489.     {
  490.     int unit;
  491.     ELT_CTRL * pDrvCtrl;
  492.     int error;
  493. #ifdef ELT_DEBUG
  494.     printf ("elt: ioctl: pIDR=%x cmd=%x data=%xn", pIDR, cmd, data);
  495. #endif /* ELT_DEBUG */
  496.     unit = pIDR->ac_if.if_unit;
  497.     pDrvCtrl = pEltCtrl [unit];
  498.     error = 0;
  499.     switch (cmd)
  500.         {
  501.         case SIOCSIFADDR:
  502.             ((struct arpcom *)pIDR)->ac_ipaddr = IA_SIN (data)->sin_addr;
  503.             arpwhohas (pIDR, &IA_SIN (data)->sin_addr);
  504.             break;
  505.         case SIOCSIFFLAGS:
  506.             /* Set promiscuous mode according to current interface flags */
  507.             pDrvCtrl->rxFilter = ( (pIDR->ac_if.if_flags & IFF_PROMISC) != 0) ?
  508.                                    RX_F_PROMISCUOUS : RX_F_NORMAL;
  509.             sysOutWord (pDrvCtrl->port + ELT_COMMAND,
  510.                         SET_RX_FILTER | pDrvCtrl->rxFilter);
  511.             break;
  512.         default:
  513.             error = EINVAL;
  514.         }
  515.     return (error);
  516.     }
  517. #ifdef BSD43_DRIVER
  518. /*******************************************************************************
  519. *
  520. * eltOutput - interface output routine.
  521. *
  522. * This is the entry point for packets arriving from protocols above.  This
  523. * routine merely calls our specific output routines that eventually lead
  524. * to a transmit to the network.
  525. *
  526. * RETURNS: 0 or appropriate errno
  527. */
  528. static int eltOutput
  529.     (
  530.     IDR *    pIDR,
  531.     MBUF *     pMbuf,
  532.     SOCK * pDestAddr
  533.     )
  534.     {
  535. #ifdef ELT_DEBUG
  536.     printf ("elt: output: pIDR=%x pMbuf=%x pDestAddr=%xn",
  537.             pIDR, pMbuf, pDestAddr);
  538. #endif /* ELT_DEBUG */
  539.     return (ether_output ( (IFNET *)pIDR, pMbuf, pDestAddr,
  540.             (FUNCPTR) eltTxOutputStart, pIDR));
  541.     }
  542. #endif
  543. /*******************************************************************************
  544. *
  545. * eltTxOutputStart - start output on the board
  546. *
  547. * This routine is called from ether_output() when a new packet is enqueued
  548. * in the interface mbuf queue.
  549. *
  550. * Note that this function is ALWAYS called between an splnet() and an splx().
  551. * This is true because netTask(), and ether_output() take care of
  552. * this when calling this function. Therefore, no calls to these spl functions
  553. * are needed anywhere in this output thread.
  554. */
  555. #ifdef BSD43_DRIVER
  556. static void eltTxOutputStart
  557.     (
  558.     int unit
  559.     )
  560.     {
  561.     ELT_CTRL * pDrvCtrl;
  562.     pDrvCtrl = pEltCtrl [unit];
  563. #else
  564. static void eltTxOutputStart
  565.     (
  566.     ELT_CTRL * pDrvCtrl
  567.     )
  568.     {
  569. #endif
  570.     if (sysInWord (pDrvCtrl->port + TX_FREE_BYTES) >= TX_IDLE_COUNT)
  571.         {
  572. #ifdef ELT_TIMING
  573.         /* pretend we queued eltTxFlush, to keep the counts straight */
  574.         if ( (int)++pDrvCtrl->eltStat.taskQTxOuts >
  575.              (int)pDrvCtrl->eltStat.maxTxTaskQ)
  576.             pDrvCtrl->eltStat.maxTxTaskQ = pDrvCtrl->eltStat.taskQTxOuts;
  577. #endif /* ELT_TIMING */
  578.         eltTxFlush (pDrvCtrl, FALSE);   /* not called via netJobAdd() */
  579.         }
  580.     }
  581. /*******************************************************************************
  582. *
  583. * eltInt - entry point for handling interrupts from the EtherLink III
  584. *
  585. * Most of the board's interrupting conditions must be actually handled to
  586. * clear the interrupting condition; the ACK command does nothing for them.
  587. * Where we defer handling to the task level, we mask the status conditions
  588. * to prevent a repeated interrupt.  This works everywhere except when there
  589. * are received packets waiting to be delivered to the protocols; this is
  590. * synchronized by a flag.
  591. *
  592. * Note that the board manual says to acknowledge the board interrupts before
  593. * acknowledging the processor interrupt, presumably because of level-sensitive
  594. * logic somewhere.
  595. */
  596. static void eltInt
  597.     (
  598.     ELT_CTRL * pDrvCtrl
  599.     )
  600.     {
  601.     UINT16 status;
  602.     UINT16 statusDiag;
  603.     UINT16 statusRx;
  604.     UINT16 statusRxNew;
  605.     UINT8  statusTx;
  606.     UINT16 length;
  607.     int    ix = 0;
  608.     int    port = pDrvCtrl->port;
  609.     BOOL   needTxStart = FALSE;
  610.     volatile ELT_FRAME * pFrame;
  611.     STATUS result;
  612. #ifdef ELT_TIMING
  613.     {
  614.         int time = (int) sysInByte (pDrvCtrl->port + TIMER);
  615.         if (time> pDrvCtrl->eltStat.maxIntLatency)
  616.             pDrvCtrl->eltStat.maxIntLatency = time; 
  617.         if (pDrvCtrl->interruptTime == -1)
  618.             pDrvCtrl->interruptTime = time;
  619.         else if (pDrvCtrl->interruptTime >= 0)
  620.             pDrvCtrl->interruptTime = -1;
  621.     }
  622. #endif /* ELT_TIMING */
  623.     status = sysInByte (pDrvCtrl->port + ELT_STATUS) & 0x00ff;
  624.     if ( (status & INTERRUPT_LATCH) == 0)
  625.         {
  626.         ++pDrvCtrl->eltStat.strayint;
  627.         return;
  628.         }
  629.     else
  630.         ++pDrvCtrl->eltStat.interrupts;
  631.     /* Handle adapter failure first in case other conditions mask it */
  632.     if ( (status & ADAPTER_FAILURE) != 0)
  633.         {
  634.         sysOutWord (port + ELT_COMMAND, SELECT_WINDOW | WIN_DIAGNOSTIC);
  635.         statusDiag = sysInWord (port + FIFO_DIAGNOSTIC);
  636.         sysOutWord (port + ELT_COMMAND, SELECT_WINDOW | WIN_OPERATING);
  637.         if ( (statusDiag & FD_TX_OVERRUN) != 0)
  638.             {
  639.             ++pDrvCtrl->eltStat.txoverruns;
  640.             sysOutWord (port + ELT_COMMAND, TX_RESET);
  641.             eltTxStart (pDrvCtrl);
  642.             }
  643.         if ( (status & FD_RX_UNDERRUN) != 0)
  644.             {
  645.             ++pDrvCtrl->eltStat.rxunderruns;
  646.             sysOutWord (port + ELT_COMMAND, RX_RESET);
  647.             eltRxStart (pDrvCtrl);
  648.             }
  649.         }
  650.     /* Handle receive complete interrupt */
  651.     if ( (status & (RX_COMPLETE | RX_EARLY)) != 0)
  652.         {
  653.         if ( (status & RX_EARLY) != 0)
  654.             ++pDrvCtrl->eltStat.rxearly;
  655.         if (pDrvCtrl->pRxCurrent == NULL)
  656.             ++pDrvCtrl->eltStat.rxnobuffers;
  657. #ifdef ELT_TIMING
  658.         {
  659.         int timeNow;
  660.         int timeDelta;
  661.         if (pDrvCtrl->interruptTime >= 0)
  662.             {
  663.             timeNow = (int)sysInByte (port + TIMER);
  664.             if (timeNow == 0xff)
  665.                 ++pDrvCtrl->eltStat.timerOverflow;
  666.             else
  667.                 {
  668.                 ++pDrvCtrl->eltStat.timerUpdates;
  669.                 timeDelta = timeNow - pDrvCtrl->interruptTime;
  670.                 if (timeDelta > pDrvCtrl->eltStat.maxRxLatency)
  671.                     pDrvCtrl->eltStat.maxRxLatency = timeDelta; 
  672.                 if ( (pDrvCtrl->eltStat.minRxLatency == 0) ||
  673.                     (timeDelta < pDrvCtrl->eltStat.minRxLatency))
  674.                     pDrvCtrl->eltStat.minRxLatency = timeDelta;
  675.                 }
  676.             }
  677.         else if (pDrvCtrl->interruptTime == -1)
  678.             ++pDrvCtrl->eltStat.timerInvalid;
  679.         pDrvCtrl->interruptTime = -2;
  680.         }
  681. #endif /* ELT_TIMING */
  682.         while ( (pFrame = pDrvCtrl->pRxCurrent) != NULL)
  683.             {
  684.             statusRx = sysInWord(port + RX_STATUS);
  685.             if (statusRx & RX_S_INCOMPLETE) /* incomplete */
  686.         {
  687.                 if (statusRx == RX_S_INCOMPLETE) /* no bytes available */
  688.     break;
  689.                 while ((statusRx != (statusRxNew = sysInWord(port + RX_STATUS)))
  690.        && (ix < 10000))
  691.     {
  692.     statusRx = statusRxNew;   
  693.     ix++; /* XXX */
  694.     }
  695.         }
  696. #ifdef ELT_DEBUG
  697.             logMsg ("eltInt: statusRx=%04x ix=%dn", statusRx, ix, 0, 0, 0, 0);
  698. #endif /* ELT_DEBUG */
  699.     
  700.             /* Copy the FIFO data into the buffer */
  701.             length = statusRx & RX_S_CNT_MASK;
  702.             /* Prevent buffer overflow.
  703.              * should we discard the packet? that's hard to do safely here.
  704.      * so truncate packet
  705.      */
  706.             if ( (pFrame->count + length) > MAX_FRAME_SIZE)
  707.                 length = MAX_FRAME_SIZE - pFrame->count;
  708.             /* transfer only an even number of bytes to leave the pointer
  709.              * on an even boundary until we reach the end of the frame
  710.              */
  711.             if ( (statusRx & RX_S_INCOMPLETE) != 0)
  712.                 length &= PARTIAL_TRANSFER_MASK;
  713.             sysInWordString (port + DATA_REGISTER, (short *) pFrame->nextByte,
  714.                              (length + 1) / 2);
  715.             pFrame->count += length;
  716.             pFrame->nextByte += length;
  717.     /* partial packet, wait for complete packet */
  718.             if ( (statusRx & RX_S_INCOMPLETE) != 0)
  719.                 break;
  720.     /*
  721.      * Packet is now complete. Use 'Discard' command to complete the 
  722.      * transfer
  723.      */
  724.             sysOutWord (port + ELT_COMMAND, RX_DISCARD); /* discard packet */
  725.             while ( (sysInWord (port + ELT_STATUS) & COMMAND_IN_PROGRESS) != 0)
  726.                 ;                           /* wait for command to finish */
  727.             /* Check for errors in completed packet */
  728.             if ( (statusRx & RX_S_ERROR) != 0)
  729.                 {
  730.                 switch (statusRx & RX_S_CODE_MASK)
  731.                     {
  732.                     case RX_S_OVERRUN: /* handled by statistics registers */
  733.                         break;
  734.                     case RX_S_RUNT:
  735.                         ++pDrvCtrl->eltStat.shortPacket;
  736.                         break;
  737.                     case RX_S_ALIGN:
  738.                         ++pDrvCtrl->eltStat.aligns;
  739.                         break;
  740.                     case RX_S_CRC:
  741.                         ++pDrvCtrl->eltStat.crcs;
  742.                         break;
  743.                     case RX_S_OVERSIZE:
  744.                         ++pDrvCtrl->eltStat.badPacket;
  745.                         break;
  746.                     default: /* no other codes are defined */
  747.                         break;
  748.                     }
  749.                 ++pDrvCtrl->eltStat.rxerror;
  750.                 ++pDrvCtrl->idr.ac_if.if_ierrors;   /* bump error counter */
  751.                 pFrame->count = 0;
  752.                 pFrame->nextByte = pFrame->header;
  753.                 pFrame->length = 0;
  754.                 continue;
  755.                 }
  756.             /* Got a complete packet, count it. */
  757.             ++pDrvCtrl->idr.ac_if.if_ipackets;
  758.             pFrame->length = statusRx;
  759.             pDrvCtrl->pRxCurrent = pDrvCtrl->pRxCurrent->lNext;
  760.             }
  761. #ifdef ELT_TIMING
  762.         pDrvCtrl->interruptTime = -1;
  763. #endif /* ELT_TIMING */
  764.         /* receive no more for now */
  765.         if (pDrvCtrl->pRxCurrent == NULL)
  766.             pDrvCtrl->intMask &= ~(RX_COMPLETE | RX_EARLY);
  767.         if (!pDrvCtrl->rxHandling && (pDrvCtrl->pRxHead->length != 0))
  768.             {
  769.             result = netJobAdd ( (FUNCPTR) eltRxDeliver, (int) pDrvCtrl,
  770.                                  0, 0, 0, 0);
  771. #ifdef ELT_DEBUG
  772.             if (result == ERROR)
  773.                 logMsg ("elt: netJobAdd (eltRxDeliver) failedn",
  774.                         0, 0, 0, 0, 0, 0);
  775. #endif /* ELT_DEBUG */
  776. #ifdef ELT_TIMING
  777.             if (result != ERROR)
  778.                 if ( (int)++pDrvCtrl->eltStat.taskQRxOuts >
  779.                           (int)pDrvCtrl->eltStat.maxRxTaskQ)
  780.                      pDrvCtrl->eltStat.maxRxTaskQ = 
  781.                               pDrvCtrl->eltStat.taskQRxOuts;
  782. #endif /* ELT_TIMING */
  783.             pDrvCtrl->rxHandling = TRUE;
  784.             }
  785.         }
  786.     /* Handle transmitter interrupts */
  787.     if ( (status & TX_COMPLETE) != 0)
  788.         {
  789.         if ( ( (statusTx = sysInByte (port + TX_STATUS)) & TX_S_COMPLETE) != 0)
  790.             {
  791.             sysOutByte (port + TX_STATUS, 0);       /* clear old status */
  792.             /* other errors are tabulated by reading the statistics registers */
  793.             if ( (statusTx & TX_S_MAX_COLL) != 0)
  794.                 pDrvCtrl->idr.ac_if.if_collisions += 16;
  795.             if ( (statusTx & TX_S_JABBER) != 0)
  796.                 ++pDrvCtrl->eltStat.jabbers;
  797.             
  798.             if ((statusTx & (TX_S_JABBER | TX_S_MAX_COLL | TX_S_UNDERRUN)) != 0)
  799.                 {
  800.                 needTxStart = TRUE;                 /* restart transmitter */
  801.                 /* packet not sent */
  802.                 pDrvCtrl->idr.ac_if.if_oerrors++;   /* incr err count */
  803.                 pDrvCtrl->idr.ac_if.if_opackets--;  /* decr sent count */
  804.                 }
  805.             if ( (statusTx & (TX_S_JABBER | TX_S_UNDERRUN)) != 0)
  806.                 {
  807.                 /* Must reset transmitter; this clears the tx FIFO */
  808.                 sysOutWord (port + ELT_COMMAND, TX_RESET);
  809.                 }
  810.             }
  811.         if (needTxStart)                            /* check flag */
  812.             eltTxStart (pDrvCtrl);
  813.         if (pDrvCtrl->idr.ac_if.if_snd.ifq_head != NULL)
  814.             {
  815.             if (!pDrvCtrl->txHandling)
  816.                 {
  817.                 if (netJobAdd ( (FUNCPTR) eltTxFlush, (int) pDrvCtrl, (int) TRUE,
  818.                                 0, 0, 0) == ERROR)
  819.                     {
  820. #ifdef ELT_DEBUG
  821.                     logMsg ("elt: netJobAdd (eltTxFlush) failedn",
  822.                             0, 0, 0, 0, 0, 0);
  823. #endif /* ELT_DEBUG */
  824.                     }
  825.                 else
  826.                     pDrvCtrl->txHandling = TRUE;
  827. #ifdef ELT_TIMING
  828.                 if ( (int)++pDrvCtrl->eltStat.taskQTxOuts >
  829.                      (int)pDrvCtrl->eltStat.maxTxTaskQ)
  830.                     pDrvCtrl->eltStat.maxTxTaskQ = pDrvCtrl->eltStat.taskQTxOuts;
  831. #endif /* ELT_TIMING */
  832.                 }
  833.             }
  834.         }
  835.     /* Handle update statistics interrupt */
  836.     if ( (status & UPDATE_STATS) != 0)
  837.         eltStatFlush (pDrvCtrl);
  838.     /* mask and ack the events we've just handled or queued handlers for */
  839.     sysOutWord (pDrvCtrl->port + ELT_COMMAND, MASK_STATUS | pDrvCtrl->intMask);
  840.     sysOutWord (pDrvCtrl->port + ELT_COMMAND, ACK_INTERRUPT | status);
  841.     sysBusIntAck (pDrvCtrl->intLevel);
  842.     }
  843. /*******************************************************************************
  844. *
  845. * eltTxFlush - transmit a packet from the output queue
  846. *
  847. * This routine, if the transmitter is currently idle, and if there is a
  848. * packet in the output queue, dequeues a packet and transmits it.  The
  849. * next transmit activity will be a completion interrupt, which will cause
  850. * this routine to be scheduled again if there is a packet in the output
  851. * queue.
  852. */
  853. static void eltTxFlush
  854.     (
  855.     ELT_CTRL *  pDrvCtrl,
  856.     BOOL        netJob
  857.     )
  858.     {
  859.     int port;
  860.     ELT_FRAME * pFrame;
  861.     UINT16 outputCount;
  862.     MBUF * m;
  863.     port = pDrvCtrl->port;
  864.     pFrame = pDrvCtrl->pTxFrame;
  865.     do
  866.         {
  867.         if (netJob)
  868.             pDrvCtrl->txHandling = TRUE;
  869.         /* Don't dequeue if currently sending */
  870.         while ( (sysInWord (pDrvCtrl->port + TX_FREE_BYTES) >= TX_IDLE_COUNT) &&
  871.                 (pDrvCtrl->idr.ac_if.if_snd.ifq_head != NULL))
  872.             {
  873.             IF_DEQUEUE (&pDrvCtrl->idr.ac_if.if_snd, m);
  874.             copy_from_mbufs (pFrame->header, m, outputCount);
  875.             outputCount = max (ETHERSMALL, outputCount);
  876.             if ( (etherOutputHookRtn != NULL) &&
  877.                  (* etherOutputHookRtn)
  878.                  (&pDrvCtrl->idr, pFrame->header, outputCount))
  879.                 continue;
  880.             pFrame->length = outputCount | TX_F_INTERRUPT;
  881.             outputCount = (outputCount + TX_F_PREAMBLE_SIZE + 3) &
  882.                           TX_F_DWORD_MASK;
  883.             sysOutWordString (port + DATA_REGISTER, (short *) & pFrame->length,
  884.                               outputCount / 2);
  885.             /* Bump the statistic counter. */
  886. #ifdef ELT_DEBUG
  887.             printf ("Packet sent.n");
  888.             fflush (stdout);
  889. #endif /* ELT_DEBUG */
  890. #ifndef BSD43_DRIVER
  891.             pDrvCtrl->idr.ac_if.if_opackets++;
  892. #endif
  893.             break;                      /* ISR must call eltTxCleanup() */
  894.             }
  895.         if (netJob)
  896.             pDrvCtrl->txHandling = FALSE;
  897.         }
  898.     while ( (sysInWord (pDrvCtrl->port + TX_FREE_BYTES) >= TX_IDLE_COUNT) &&
  899.             (pDrvCtrl->idr.ac_if.if_snd.ifq_head != NULL));
  900. #ifdef ELT_TIMING
  901.     --pDrvCtrl->eltStat.taskQTxOuts;
  902. #endif /* ELT_TIMING */
  903.     }
  904. /*******************************************************************************
  905. *
  906. * eltRxDeliver - pass received frames to the next layer up
  907. *
  908. * Strips the Ethernet header and passes the packet to the appropriate
  909. * protocol.  If there are enough received frame buffers, the packet may
  910. * be passed to the protocol in the frame buffer.
  911. * In this latter case, the frame buffer will
  912. * eventually be returned by the protocol, via a call to our eltLoanFree().
  913. */
  914. static void eltRxDeliver
  915.     (
  916.     ELT_CTRL * pDrvCtrl
  917.     )
  918.     {
  919.     volatile ELT_FRAME * pFrame;
  920.     UINT16      length;
  921.     struct ether_header *   pEh;
  922.     u_char *    pData;
  923.     UINT16      etherType;
  924.     MBUF *      pMbuf;
  925. #ifdef ELT_DEBUG
  926.     printf ("Elt: Handling received packet.n");
  927.     fflush (stdout);
  928. #endif /* ELT_DEBUG */
  929.     do
  930.         {
  931.         pDrvCtrl->rxHandling = TRUE;
  932.         while ( ( (pFrame = pDrvCtrl->pRxHead) != NULL) &&
  933.                 (pFrame->length != 0))
  934.             {
  935.             pDrvCtrl->pRxHead = pFrame->lNext;
  936.             length = pFrame->count - EH_SIZE;
  937.             pEh = (struct ether_header *)pFrame->header;
  938.             pData = (u_char *) pFrame->data;
  939.             etherType = ntohs (pEh->ether_type);
  940.             /* Service input hook */
  941.             if (etherInputHookRtn != NULL)
  942.                 {
  943.                 if ( (* etherInputHookRtn) (&pDrvCtrl->idr, (char *)pEh,
  944.                                             length) )
  945.                     {
  946.                     eltRxFree (pDrvCtrl, (ELT_FRAME *)pFrame);
  947.                     continue;
  948.                     }
  949.                 }
  950. #ifdef ELT_DEBUG
  951.         printf ("elt: rxDeliver: frame at %08lx, type %04x, length %d, count %dn",
  952.                 (long) pFrame, etherType, pFrame->length, pFrame->count);
  953. #endif /* ELT_DEBUG */
  954.             /* we can loan out receive frames from our pool if:
  955.              *
  956.              * 1) we have enough (nLoanFrames > 0) and
  957.              * 2) size of the input ethernet frame is large enough to be used
  958.              *    with clustering.
  959.              */
  960.             pFrame->refCnt = 0;
  961.             if ( (pDrvCtrl->nLoanFrames > 0) && (USE_CLUSTER (length)) &&
  962.                  ( (pMbuf = build_cluster (pData, length, &pDrvCtrl->idr, MC_EI,
  963.                                      &pFrame->refCnt, eltLoanFree,
  964.                                      (int) pDrvCtrl,
  965.                                      (int) pFrame, NULL)) != NULL))
  966.                 {
  967.                 pDrvCtrl->nLoanFrames -= 1;             /* one less to loan */
  968.                 }
  969.             else
  970.                 {
  971.                 pMbuf = copy_to_mbufs (pData, length, 0, &pDrvCtrl->idr);
  972.                 eltRxFree (pDrvCtrl, (ELT_FRAME *)pFrame);
  973.                 }
  974.             /* deliver mbufs to protocol */
  975. #ifdef BSD43_DRIVER
  976.             if (pMbuf != NULL)
  977.                 do_protocol_with_type (etherType, pMbuf, &pDrvCtrl->idr,length);
  978. #else
  979.             if (pMbuf != NULL)
  980.                 do_protocol (pEh, pMbuf, &pDrvCtrl->idr, length);
  981. #endif
  982.             else
  983.                 ++pDrvCtrl->idr.ac_if.if_ierrors;
  984.             }
  985.         pDrvCtrl->rxHandling = FALSE;   /* allow self to be rescheduled */
  986.         }
  987.     while ( ( (pFrame = pDrvCtrl->pRxHead) != NULL) && (pFrame->length != 0));
  988. #ifdef ELT_TIMING
  989.     --pDrvCtrl->eltStat.taskQRxOuts;
  990. #endif /* ELT_TIMING */
  991.     }
  992. /*******************************************************************************
  993. *
  994. * eltLoanFree - return a loaned receive frame buffer
  995. *
  996. * This routine is called by the protocol code when it has completed use of
  997. * a frame buffer that we loaned to it.
  998. */
  999. static void eltLoanFree
  1000.     (
  1001.     ELT_CTRL * pDrvCtrl,
  1002.     ELT_FRAME * pFrame
  1003.     )
  1004.     {
  1005.     eltRxFree (pDrvCtrl, pFrame);
  1006.     pDrvCtrl->nLoanFrames += 1;         /* one more to loan */
  1007.     }
  1008. /*******************************************************************************
  1009. *
  1010. * eltRxFree - free a received frame buffer
  1011. *
  1012. * Reinitialize necessary fields in the frame structure and link it to the
  1013. * tail of the free frames list.  If there was no current frame (the receive
  1014. * routine had run out of empty buffers), make this the current frame and
  1015. * unmask receive interrupts in case they were waiting for a buffer.
  1016. */
  1017. static void eltRxFree
  1018.     (
  1019.     ELT_CTRL * pDrvCtrl,
  1020.     ELT_FRAME * pFrame
  1021.     )
  1022.     {
  1023.     pFrame->lNext = NULL;
  1024.     pFrame->count = 0;
  1025.     pFrame->nextByte = pFrame->header;
  1026.     pFrame->length = 0;
  1027.     eltIntDisable (pDrvCtrl);
  1028.     if (pDrvCtrl->pRxHead == NULL)
  1029.         pDrvCtrl->pRxHead = pFrame;
  1030.     else
  1031.         pDrvCtrl->pRxTail->lNext = pFrame;
  1032.     pDrvCtrl->pRxTail = pFrame;
  1033.     if (pDrvCtrl->pRxCurrent == NULL)
  1034.         {
  1035.         pDrvCtrl->pRxCurrent = pFrame;
  1036.         eltIntMaskSet (pDrvCtrl, RX_COMPLETE | RX_EARLY);
  1037.         }
  1038.     eltIntEnable (pDrvCtrl);
  1039.     }
  1040. /*******************************************************************************
  1041. *
  1042. * eltStatFlush - flush the board's statistics registers to statistics block
  1043. *
  1044. * Called when the board reports that its statistics registers are getting
  1045. * full, or when someone wants to see the current statistics (to fully update
  1046. * the statistics block).
  1047. *
  1048. * Note that reading a statistics register zeroes it in the hardware.
  1049. * Note also that zeroing all the registers is necessary and sufficient
  1050. * to clear the interrupt condition.
  1051. *
  1052. * Must be called with board or system interrupts disabled.
  1053. */
  1054. static void eltStatFlush
  1055.     (
  1056.     ELT_CTRL * pDrvCtrl
  1057.     )
  1058.     {
  1059.     int         port;
  1060.     port = pDrvCtrl->port;
  1061.     sysOutWord (port + ELT_COMMAND, SELECT_WINDOW | WIN_STATISTICS);
  1062.     sysOutWord (port + ELT_COMMAND, STATS_DISABLE);
  1063.     pDrvCtrl->eltStat.nocarriers +=     sysInByte (port + CARRIER_LOSTS) & 0x0f;
  1064.     pDrvCtrl->eltStat.heartbeats +=     sysInByte (port + SQE_FAILURES) & 0x0f;
  1065.     pDrvCtrl->eltStat.multcollisions += sysInByte (port + MULT_COLLISIONS)
  1066.                                         & 0x3f;
  1067.     pDrvCtrl->eltStat.collisions +=     sysInByte (port + ONE_COLLISIONS)
  1068.                                         & 0x3f;
  1069.     pDrvCtrl->eltStat.latecollisions += sysInByte (port + LATE_COLLISIONS);
  1070.     pDrvCtrl->eltStat.rxoverruns +=     sysInByte (port + RECV_OVERRUNS);
  1071.     pDrvCtrl->eltStat.txnoerror +=      sysInByte (port + GOOD_TRANSMITS);
  1072.     pDrvCtrl->eltStat.rxnoerror +=      sysInByte (port + GOOD_RECEIVES);
  1073.     pDrvCtrl->eltStat.deferring +=      sysInByte (port + TX_DEFERRALS);
  1074.     /* Must read all the registers to be sure to clear the interrupt */
  1075.     (void) sysInWord (port + BYTES_RECEIVED);
  1076.     (void) sysInWord (port + BYTES_TRANSMITTED);
  1077.     sysOutWord (port + ELT_COMMAND, STATS_ENABLE);
  1078.     sysOutWord (port + ELT_COMMAND, SELECT_WINDOW | WIN_OPERATING);
  1079.     }
  1080. /*******************************************************************************
  1081. *
  1082. * eltIntMaskSet - enable specific status conditions to cause interrupts
  1083. *
  1084. * Sets bit(s) in the intMask field of the device control structure and in
  1085. * the board's "read zero mask" where a one bit enables the corresponding
  1086. * status condition to be read and to cause an interrupt.
  1087. */
  1088. static void eltIntMaskSet
  1089.     (
  1090.     ELT_CTRL * pDrvCtrl,
  1091.     int maskBits
  1092.     )
  1093.     {
  1094.     eltIntDisable (pDrvCtrl);
  1095.     pDrvCtrl->intMask |= maskBits;
  1096.     sysOutWord (pDrvCtrl->port + ELT_COMMAND, MASK_STATUS | pDrvCtrl->intMask);
  1097.     eltIntEnable (pDrvCtrl);
  1098.     }
  1099. /*******************************************************************************
  1100. *
  1101. * eltIntEnable - enable board to cause interrupts
  1102. *
  1103. * Because the board has maskable status, this routine can simply set the
  1104. * mask to all ones.  We set all the bits symbolically; the effect is the
  1105. * same.  Note that the interrupt latch is not maskable; if none of the other
  1106. * mask bits are set, no interrupts will occur at all.  Only those interrupts
  1107. * whose status bits are enabled will actually occur.  Note that the "intMask"
  1108. * field in the device control structure is really the status mask.
  1109. */
  1110. static void eltIntEnable
  1111.     (
  1112.     ELT_CTRL * pDrvCtrl
  1113.     )
  1114.     {
  1115.     UINT16  status;
  1116.     status = sysInByte (pDrvCtrl->port + ELT_STATUS) & 0x00ff;
  1117.     sysOutWord (pDrvCtrl->port + ELT_COMMAND, ACK_INTERRUPT | status);
  1118.     sysOutWord (pDrvCtrl->port + ELT_COMMAND, MASK_INTERRUPT |
  1119.                 ADAPTER_FAILURE | TX_COMPLETE | TX_AVAILABLE | RX_COMPLETE |
  1120.                 RX_EARLY | INTERRUPT_REQ | UPDATE_STATS);
  1121.     }
  1122. /*******************************************************************************
  1123. *
  1124. * eltIntDisable - prevent board from causing interrupts
  1125. *
  1126. * This routine simply sets all the interrupt mask bits to zero.
  1127. * It is intended for guarding board-critical sections.
  1128. */
  1129. static void eltIntDisable
  1130.     (
  1131.     ELT_CTRL * pDrvCtrl
  1132.     )
  1133.     {
  1134.     UINT16  status;
  1135.     sysOutWord (pDrvCtrl->port + ELT_COMMAND, MASK_INTERRUPT | 0);
  1136.     status = sysInByte (pDrvCtrl->port + ELT_STATUS) & 0x00ff;
  1137.     sysOutWord (pDrvCtrl->port + ELT_COMMAND, ACK_INTERRUPT | status);
  1138.     }
  1139. /*******************************************************************************
  1140. *
  1141. * eltTxStart - turn on board's transmit function
  1142. */
  1143. static void eltTxStart
  1144.     (
  1145.     ELT_CTRL *  pDrvCtrl
  1146.     )
  1147.     {
  1148.     sysOutWord (pDrvCtrl->port + ELT_COMMAND, TX_ENABLE);
  1149.     }
  1150. /*******************************************************************************
  1151. *
  1152. * eltRxStart - enable board to start receiving
  1153. */
  1154. static void eltRxStart
  1155.     (
  1156.     ELT_CTRL *  pDrvCtrl
  1157.     )
  1158.     {
  1159.     sysOutWord (pDrvCtrl->port + ELT_COMMAND, SET_RX_FILTER |
  1160.                                               pDrvCtrl->rxFilter);
  1161.     sysOutWord (pDrvCtrl->port + ELT_COMMAND, RX_ENABLE);
  1162.     }
  1163. /*******************************************************************************
  1164. *
  1165. * eltActivate - attempt to find and activate the adapter with given address
  1166. *
  1167. * The 3Com 3C509 ISA adapter does not enable itself at power-on.  This is
  1168. * left to the driver, which presumably knows which board it wants.  This
  1169. * we do know, from the port field in the driver control structure.
  1170. *
  1171. * As a helpful side effect, this routine stores the OEM Ethernet address
  1172. * of the selected adapter into the driver control structure.
  1173. *
  1174. * Note that this procedure will activate only one board of the given I/O
  1175. * address; this is presumably designed in by 3Com as a helpful feature.
  1176. */
  1177. static STATUS eltActivate
  1178.     (
  1179.     ELT_CTRL * pDrvCtrl
  1180.     )
  1181.     {
  1182.     int adapterPort;    /* I/O address of adapter we're to look for */
  1183.     int selectedPort;   /* I/O address of adapter we've found */
  1184.     int addressConfig;  /* adapter's address configuration register */
  1185.     int resourceConfig; /* adapter's resource configuration register */
  1186.     char nodeAddress [EA_SIZE];
  1187.     STATUS status = OK; /* presume OK, change if there's a problem */
  1188.     adapterPort = pDrvCtrl->port;
  1189.     eltIdCommand (ID_PORT);             /* wake up all adapters */
  1190.     sysOutByte (ID_PORT, ID_SET_TAG);   /* clear all tags */
  1191.     /* first see if there's a 3Com 3C5xx board out there at all */
  1192.     if (eltIdEepromRead (EE_A_MANUFACTURER) != MANUFACTURER_ID)
  1193.         return (ERROR);
  1194.     /* Identify adapters one by one until we find the right one;
  1195.      * as we eliminate adapters, we tag them so they don't participate
  1196.      * in the next round of contention eliminations.  Along the way,
  1197.      * as part of the adapter contention process, we read out the
  1198.      * station address and resource configuration.
  1199.      */
  1200.     do
  1201.         {
  1202.         eltIdCommand (ID_PORT);         /* prepare for contention */
  1203.         /* Now read all untagged adapters' addresses from EEPROM
  1204.          * a bit at a time.  Tagged adapters ignore the reads therefore
  1205.          * won't be found; we find the next untagged adapter.
  1206.          */
  1207.         * (UINT16 *) &nodeAddress [0] = eltIdEepromRead (EE_A_OEM_NODE_0);
  1208.         * (UINT16 *) &nodeAddress [2] = eltIdEepromRead (EE_A_OEM_NODE_1);
  1209.         * (UINT16 *) &nodeAddress [4] = eltIdEepromRead (EE_A_OEM_NODE_2);
  1210.         resourceConfig = eltIdEepromRead (EE_A_RESOURCE);
  1211.         addressConfig = eltIdEepromRead (EE_A_ADDRESS);
  1212.         if ( (addressConfig & AC_IO_BASE_MASK) == AC_IO_BASE_EISA)
  1213.             {
  1214.             /* the EISA base address is the last possible one; if we hit
  1215.              * this value without finding the adapter we want, we're done.
  1216.              */
  1217.             status = ERROR;
  1218.             break;
  1219.             }
  1220.         selectedPort = (addressConfig & AC_IO_BASE_MASK) * AC_IO_BASE_FACTOR +
  1221.                        AC_IO_BASE_ZERO;
  1222. #ifdef ELT_DEBUG
  1223.         printf ("elt: activate: adapter at 0x%04xn", selectedPort);
  1224. #endif /* ELT_DEBUG */
  1225.         /* tag this adapter so if we don't want it it won't contend again */
  1226.         sysOutByte (ID_PORT, ID_SET_TAG + 1);
  1227.         }
  1228.     while (selectedPort != adapterPort);
  1229.     if (status != ERROR)
  1230.         {
  1231.         sysOutByte (ID_PORT, ID_ACTIVATE);
  1232.         uswab (nodeAddress, (char *)pDrvCtrl->idr.ac_enaddr, EA_SIZE);
  1233.         }
  1234.     return (status);
  1235.     }
  1236. /*******************************************************************************
  1237. *
  1238. * eltIdCommand - put all adapters into ID command state
  1239. *
  1240. * This procedure synchronizes the ID state machines of all installed 3Com
  1241. * adapters in preparation for contending among them.
  1242. */
  1243. static void eltIdCommand
  1244.     (
  1245.     int idPort          /* I/O address to use as ID port (1x0 hex) */
  1246.     )
  1247.     {
  1248.     int idValue;        /* data read or written to ID port */
  1249.     int count;
  1250.     /* We should guard this routine since the ID procedure touches
  1251.      * all unactivated adapters.  In fact the first three writes should
  1252.      * be guarded against any possible intervening write to any port
  1253.      * 0x100, 0x110, 0x120, ... , 0x1f0.
  1254.      */
  1255.     sysOutByte (idPort, ID_RESET);      /* select the ID port */
  1256.     sysOutByte (idPort, ID_RESET);      /* put adapters in ID-WAIT state */
  1257.     idValue = ID_SEQUENCE_INITIAL;
  1258.     for (count = ID_SEQUENCE_LENGTH; count > 0; count--)
  1259.         {
  1260.         sysOutByte (idPort, idValue);
  1261.         idValue <<= 1;
  1262.         if ( (idValue & ID_CARRY_BIT) != 0)
  1263.             idValue ^= ID_POLYNOMIAL;
  1264.         }
  1265.     }
  1266. /*******************************************************************************
  1267. *
  1268. * eltIdEepromRead - read one 16-bit adapter EEPROM register
  1269. *
  1270. * Read an EEPROM register bitwise by way of the ID port.  Used for adapter
  1271. * contention process and to find out what's in the EEPROM.  Addresses are
  1272. * masked to a valid size; invalid addresses are simply truncated.
  1273. */
  1274. static UINT16 eltIdEepromRead
  1275.     (
  1276.     int address                         /* EEPROM register address */
  1277.     )
  1278.     {
  1279.     int bitCount;
  1280.     UINT16 value;
  1281.     sysOutByte (ID_PORT, ID_EEPROM_READ | (address & ID_EEPROM_MASK));
  1282.     taskDelay (2);                      /* must wait for 162 uS read cycle */
  1283.     value = 0;
  1284.     for (bitCount = ID_REGISTER_SIZE; bitCount > 0; bitCount--)
  1285.         {
  1286.         value <<= 1;
  1287.         value |= sysInByte (ID_PORT) & 1;
  1288.         }
  1289.     return (value);
  1290.     }
  1291. /*******************************************************************************
  1292. *
  1293. * eltShow - display statistics for the 3C509 `elt' network interface
  1294. *
  1295. * This routine displays statistics about the `elt' Ethernet network interface.
  1296. * It has two parameters: 
  1297. * .iP <unit>
  1298. * interface unit; should be 0.
  1299. * .iP <zap>
  1300. * if 1, all collected statistics are cleared to zero.
  1301. * .LP
  1302. *
  1303. * RETURNS: N/A
  1304. */
  1305. void eltShow 
  1306.     (
  1307.     int unit,   /* interface unit */
  1308.     BOOL zap    /* 1 = zero totals */
  1309.     )
  1310.     {
  1311.     ELT_CTRL * pDrvCtrl;
  1312.     FAST int ix;
  1313.     static char *e_message [] = {
  1314.         "collisions",
  1315.         "crcs",
  1316.         "aligns",
  1317.         "rx no buffers",
  1318.         "rx over-runs",
  1319.         "disabled",
  1320.         "deferring",
  1321.         "tx under-run",
  1322.         "aborts",
  1323.         "out-of-window",
  1324.         "heart-beats",
  1325.         "bad-packet",
  1326.         "short-packet",
  1327.         "tx-no-error",
  1328.         "rx-no-error",
  1329.         "tx-error",
  1330.         "rx-error",
  1331.         "over-write",
  1332.         "wrapped",
  1333.         "interrupts",
  1334.         "reset",
  1335.         "stray-int",
  1336.         "multiple-collisions",
  1337.         "late-collisions",
  1338.         "no-carriers",
  1339.         "jabbers",
  1340.         "tx over-run",
  1341.         "rx under-run",
  1342. #ifdef ELT_TIMING
  1343.         "rx early",
  1344.         "timer updates",
  1345.         "timer overflows",
  1346.         "timer invalids",
  1347.         "max rx latency",
  1348.         "min rx latency",
  1349.         "max int latency",
  1350.         "current outstanding net rx tasks",
  1351.         "max outstanding rx net tasks",
  1352.         "current outstanding net tx tasks",
  1353.         "max outstanding tx net tasks"
  1354. #else
  1355.         "rx early"
  1356. #endif /* ELT_TIMING */
  1357. };
  1358.     pDrvCtrl = pEltCtrl [unit];
  1359.     /* Disable board interrupts because eltStatFlush() changes reg. window */
  1360.     eltIntDisable (pDrvCtrl);
  1361.     eltStatFlush (pDrvCtrl);            /* get the latest statistics */
  1362.     eltIntEnable (pDrvCtrl);
  1363.     for (ix = 0; ix < NELEMENTS(e_message); ix++)
  1364.         {
  1365.         printf ("    %-30.30s  %4dn", e_message [ix],
  1366.                 pDrvCtrl->eltStat.stat [ix]);
  1367.         if (zap)
  1368.             pDrvCtrl->eltStat.stat [ix] = 0;
  1369.         }
  1370.     }