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

VxWorks

开发平台:

C/C++

  1. /* if_med.c - Matrix DB-ETH Ethernet network interface driver */
  2. /* "Copyright 1989, Matrix Corporation" */
  3. /* Copyright 1984-1997 Wind River Systems, Inc. */
  4. /*
  5. modification history
  6. --------------------
  7. 02m,15jul97,spm  removed driver initialization from ioctl support (SPR #8831); 
  8.                  cleaned up handling of promiscuous mode
  9. 02l,07apr97,spm  code cleanup, corrected statistics, and upgraded to BSD 4.4
  10. 02k,16dec96,dat  fixed SPR 3026, incorrect test in medNIC_AwaitStop. 
  11.  Removed compiler warnings.
  12. 02j,05may93,caf  tweaked for ansi.
  13. 02i,11aug93,jmm  Changed ioctl.h and socket.h to sys/ioctl.h and sys/socket.h
  14. 02h,09sep92,gae  documentation tweaks.
  15. 02g,26may92,rrr  the tree shuffle
  16.   -changed includes to have absolute path from h/
  17. 02f,04oct91,rrr  passed through the ansification filter
  18.                   -changed functions to ansi style
  19.   -changed includes to have absolute path from h/
  20.   -fixed #else and #endif
  21.   -changed VOID to void
  22.   -changed copyright notice
  23. 02e,20sep90,dab  made medInit() return int.
  24. 02d,10aug90,dnw  added include of if_subr.h.
  25. 02c,11jul90,hjb  changed references to do_protocol() to use
  26.  do_protocol_with_type().  de-linted.
  27. 02b,26jun90,hjb  upgrade to use cluster and if_subr routines;
  28.    +dab  integrated in the new distribution from Matrix.
  29. 02a,05may90,dab  cleanup of Matrix version 01t.
  30. 01a,25sep89,srm  written by modifying if_ln.c.
  31. */
  32. /*
  33. DESCRIPTION
  34. This module implements the
  35. Matrix DB-ETH Ethernet network interface driver.
  36. There is one user-callable routine: medattach().
  37. BOARD LAYOUT
  38. This device is onboard.  No jumpering diagram required.
  39. SEE ALSO: ifLib
  40. */
  41. #include "vxWorks.h"
  42. #include "net/mbuf.h"
  43. #include "net/protosw.h"
  44. #include "sys/ioctl.h"
  45. #include "sys/socket.h"
  46. #include "errno.h"
  47. #include "net/uio.h"
  48. #include "net/if.h"
  49. #include "net/route.h"
  50. #include "netinet/in.h"
  51. #include "netinet/in_systm.h"
  52. #include "netinet/ip.h"
  53. #include "netinet/ip_var.h"
  54. #include "netinet/in_var.h"
  55. #include "netinet/if_ether.h"
  56. #include "net/if_subr.h"
  57. #include "etherLib.h"
  58. #include "vme.h"
  59. #include "iv.h"
  60. #include "iosLib.h"
  61. #include "ioLib.h"
  62. #include "memLib.h"
  63. #include "net/systm.h"
  64. #include "sys/types.h"
  65. #include "drv/netif/if_med.h"
  66. #include "intLib.h"
  67. #include "logLib.h"
  68. #include "stdio.h"
  69. #include "sysLib.h"
  70. #include "netLib.h"
  71. #include "net/if_subr.h"
  72. IMPORT void   sysDbusEtherIntEnable ();
  73. IMPORT ULONG  tickGet ();
  74. #define  NIC_INTERRUPTS_HANDLED   (nic_PKT_RECV_NO_ERRORS 
  75.                                  | nic_PKT_RECV_ERROR     
  76.                                  | nic_PKT_XMIT_NO_ERRORS 
  77.                                  | nic_PKT_XMIT_ERROR     
  78.                                  | nic_RECV_BFR_OVF_WARN  
  79.                                  | nic_NET_STATS_CNTR_OVF)
  80. /* Actual arguments for medSetNIC_IMR() */
  81. #define  MASK_NONE               0
  82. #define  UNMASK_NONE             0
  83. /* DB-ETH addresses as seen from the CPU */
  84. #define  ETH_ADRS_PROM_ADRS    ((u_long)dbeth_ETH_ADDR_ROM           
  85.                                 + ((u_long)es->nicAddr & 0xfff00000))
  86. #define  NIC_XMIT_BFR_ADRS     ((u_long)dbeth_NIC_XMIT_BFR           
  87.                                 + ((u_long)es->nicAddr & 0xfff00000))
  88. #define  NIC_RECV_BFR_ADRS(R)  ((u_long)dbeth_NIC_RECV_BFR           
  89.                                 + ((u_long)es->nicAddr & 0xfff00000)    
  90.                                 + ((u_long)(R) << 8))
  91. #define  END_OF_RECV_BFR       ((u_long)dbeth_NIC_RECV_BFR_END       
  92.                                 + ((u_long)es->nicAddr & 0xfff00000))
  93. /* NIC register initial values */
  94. #define PSTART  (u_char) (dbeth_NIC_RECV_BFR >> 8)
  95. #define PSTOP   (u_char) ((dbeth_NIC_RECV_BFR + dbeth_NIC_RECV_BFR_SIZE) >> 8)
  96. #define BNRY    (u_char) (PSTART)
  97. #define CURR    (u_char) (BNRY + 1)
  98. /* kludge, to force compilation of IP interface code */
  99. #ifndef INET
  100. #define INET
  101. #endif /* INET */
  102. /* globals */
  103. u_int medLogCount = 50;  /* log every medLogCount number of errors */
  104. /* locals */
  105. LOCAL med_Stats_s       med_Stats;
  106. LOCAL struct med_softc *med_softc [NNIC];
  107. /* forward static functions */
  108. static void medRecv (struct med_softc *es, struct ether_header *eh, int len);
  109. static nic_RecvHdr_s *medGetRecvPacket (struct med_softc *es);
  110. static void medRecvIntrHandler (struct med_softc *es);
  111. static int medIoctl (struct ifnet *ifp, int cmd, caddr_t data);
  112. static void medXmitIntrHandler (struct med_softc *es, u_char xmitStatus);
  113. static void medIntr (int unit);
  114. static void medRecordRecvError (struct med_softc *es);
  115. static void medIntEnable (BOOL bEnable);
  116. static void medReset (int unit);
  117. static int medInit (int unit);
  118. static u_char bitReverse (u_char in);
  119. static void medEthAddrGet (int unit);
  120. static void medConfigNIC (int unit);
  121. #ifdef BSD43_DRIVER
  122. static int medOutput (struct ifnet *ifp, struct mbuf *m0, struct sockaddr
  123. *dst);
  124. static void medStartOutput (int unit);
  125. #else
  126. static void medStartOutput (struct med_softc *es);
  127. #endif
  128. static xmitBCB_s *medXmitBfrAlloc (struct med_softc *es);
  129. static STATUS medXmitPacket (struct med_softc *es, char *pPacket, u_short
  130. packetLen);
  131. static void medReadTallyCntrs (struct med_softc *es);
  132. static void medMoveWrappedPacket (struct med_softc *es, nic_RecvHdr_s
  133. *pRecvPacket, u_long pktSize);
  134. static void medSetNIC_IMR (struct med_softc *es, u_char unmaskBits, u_char
  135. maskBits);
  136. static void medNIC_AwaitStop (NIC_DEVICE *pNIC);
  137. static void medXmitBfrDealloc (xmitQCB_s *pXmitQCB);
  138. static STATUS medXmtrLock (lockID_t *pLock);
  139. static void medXmtrUnlock (lockID_t *pLock);
  140. /*******************************************************************************
  141. *
  142. * medattach - publish the interface, and initialize the driver and device
  143. *
  144. * The routine publishes `med' the interface by filling in a network interface
  145. * record and adding this record to the system list.  This routine also
  146. * initializes the driver and the device to the operational state.
  147. *
  148. * RETURNS: OK or ERROR
  149. */
  150. STATUS medattach
  151.     (
  152.     int unit,           /* unit number */
  153.     char *addr,         /* address of Dbus Ethernet board */
  154.     int ivec,           /* interrupt vector to connect to */
  155.     int ilevel          /* interrupt level */
  156.     )
  157.     {
  158.     FAST struct med_softc *es;
  159.     FAST NIC_DEVICE *pNicDev = (NIC_DEVICE *) (addr + (u_long) dbeth_NIC_ADDR);
  160.     /* allocate and initialize med descriptor (med_softc) */
  161.     if ((es = (struct med_softc *) calloc (1, sizeof (struct med_softc)))
  162.         == NULL)
  163.         {
  164.         printErr ("med%d: ERROR - malloc failed.n", es->es_if.if_unit);
  165. return (ERROR);
  166.         }
  167.     med_softc [unit] = es; /* set ptr to med descriptor in array */
  168.     /* allocate and initialize overflow buffer for wrapped receive packets */
  169.     if ((es->pOvfRecvBfr = (nic_RecvHdr_s *)calloc (1, OVERFLOW_BFR_SIZE)) == 0)
  170.         {
  171.         printErr ("med%d: ERROR - malloc failed.n", es->es_if.if_unit);
  172. return (ERROR);
  173.         }
  174.     es->bFirstInit  = TRUE;            /* Unit 'unit' not yet initialized */
  175.     es->nicAddr     = pNicDev;
  176.     es->nicIntLevel = ilevel;
  177.     es->nicIntVec   = ivec;
  178.     (void) intConnect (INUM_TO_IVEC (ivec), medIntr, unit);
  179.     medReset (unit);
  180. #ifdef BSD43_DRIVER
  181.     ether_attach ( (struct ifnet *)&es->es_if, unit, "med",
  182.   medInit, medIoctl, medOutput, (FUNCPTR) medReset);
  183. #else
  184.     ether_attach (
  185.                  &es->es_if,
  186.                  unit, 
  187.                  "med",
  188.  (FUNCPTR) medInit, 
  189.                  (FUNCPTR) medIoctl, 
  190.                  (FUNCPTR) ether_output, 
  191.                  (FUNCPTR) medReset
  192.                  );
  193.     es->es_if.if_start = (FUNCPTR)medStartOutput;
  194. #endif
  195.     medIntEnable (TRUE);      /* enable the DB-ETH interrupt */
  196.     medInit (unit);
  197.     return (OK);
  198.     }
  199. /*******************************************************************************
  200. *
  201. * medRecv - receive packet processing
  202. *
  203. * Process Ethernet receive completion:
  204. * If input error, just drop packet. (This is handled in medRecvIntrHandler.)
  205. * Otherwise purge input buffered data path and examine
  206. * packet to determine type.  If can't determine length
  207. * from type, then have to drop packet.  Otherwise decapsulate
  208. * packet based on type and pass to type-specific higher-level
  209. * input routine.
  210. */
  211. LOCAL void medRecv
  212.     (
  213.     FAST struct med_softc *es,
  214.     FAST struct ether_header *eh,   /* ether header followed by packet data */
  215.     int len
  216.     )
  217.     {
  218.     FAST struct mbuf       *m;
  219.     FAST u_char       *pData;
  220.     int                off;
  221.     es->es_if.if_ipackets++;
  222.     /* call input hook if any */
  223.     if (etherInputHookRtn != NULL &&
  224. (*etherInputHookRtn) (&es->es_if, (char *) eh, len))
  225. {
  226. return; /* input hook has already processed this packet */
  227. }
  228. #ifdef BSD43_DRIVER
  229.     /* This legacy code is not correct for the BSD 4.4 stack. It would
  230.      * also treat multicast addresses like alien packets, and not send
  231.      * them up the stack. The higher-level protocols in the new stack
  232.      * can handle these addresses, and will discard them if they do not
  233.      * match an existing multicast group.
  234.      */
  235.     /* do software filter if controller is in promiscuous mode */
  236.     if (es->bPromisc)
  237. {
  238. if ((bcmp ((char *) eh->ether_dhost, /* not our adrs? */
  239.      (char *) es->es_enaddr,
  240.      sizeof (eh->ether_dhost)) != 0) &&
  241.     (bcmp ((char *) eh->ether_dhost, /* not broadcast? */
  242.      (char *) etherbroadcastaddr,
  243.      sizeof (eh->ether_dhost)) != 0))
  244.     {
  245.     return; /* not for us */
  246.     }
  247. }
  248. #endif
  249.     if (len >= sizeof (struct ether_header))
  250.         len -= sizeof (struct ether_header);
  251.     else
  252.         len = 0;
  253.     pData = ((u_char *) eh) + (sizeof (struct ether_header));
  254. #ifdef BSD43_DRIVER
  255.     /*
  256.      * Deal with trailer protocol: if type is trailer
  257.      * get true type from first 16-bit word past data.
  258.      * Remember that type was trailer by setting off.
  259.      */
  260.     check_trailer (eh, pData, &len, &off, &es->es_if);
  261.     if (len == 0)
  262.         return; /* sanity */
  263. #endif
  264.     m = copy_to_mbufs (pData, len, off, (struct ifnet *) &es->es_if);
  265.     if (m == NULL)
  266.         {
  267.         es->es_if.if_ierrors++;
  268. return;
  269.         }
  270. #ifdef BSD43_DRIVER
  271.     do_protocol_with_type (eh->ether_type, m, &es->es_ac, len);
  272. #else
  273.     do_protocol (eh, m, &es->es_ac, len);
  274. #endif
  275.     return;
  276.     }
  277. /*******************************************************************************
  278. *
  279. * medGetRecvPacket - return the address of the next packet received
  280. *
  281. * If a packet is available in the NIC receive buffer, return its address.
  282. * Otherwise, return NULL.
  283. */
  284. LOCAL nic_RecvHdr_s *medGetRecvPacket
  285.     (
  286.     FAST struct med_softc  *es
  287.     )
  288.     {
  289.     FAST u_char          currNIC_WritePage;
  290.     FAST NIC_DEVICE     *pNIC = es->nicAddr;
  291.     FAST int             oldLevel;
  292.     /*
  293.      * Select NIC register page 1, and retrieve the CURR register,
  294.      * re-select NIC register page 0.
  295.      */
  296.     oldLevel = intLock();
  297.     pNIC->Cr = (u_char) (RPAGE1 | ABORT | STA);
  298.     currNIC_WritePage = pNIC->Curr;
  299.     pNIC->Cr = (u_char) (RPAGE0 | ABORT | STA);
  300.     intUnlock (oldLevel);
  301.     if (es->pktNextToRead == currNIC_WritePage)  /* No new packets. */
  302.         {
  303.         return ((nic_RecvHdr_s *) NULL);
  304.         }
  305.     return ((nic_RecvHdr_s *) NIC_RECV_BFR_ADRS (es->pktNextToRead));
  306.     }
  307. /*******************************************************************************
  308. *
  309. * medRecvIntrHandler - task level interrupt service for input packets
  310. *
  311. * This routine is called at task level indirectly by the interrupt
  312. * service routine to do any message received processing.
  313. */
  314. LOCAL void medRecvIntrHandler
  315.     (
  316.     FAST struct med_softc  *es
  317.     )
  318.     {
  319.     FAST nic_RecvHdr_s  *pRecvPacket;
  320.     FAST u_char          recvStatus;
  321.     FAST u_long          pktSize;
  322.     FAST NIC_DEVICE     *pNIC = es->nicAddr;
  323.     if (es->bRecvBfrOvfl)  /* Ignore packets on receive buffer overflow; */
  324.         return;            /* they all will be dropped.                  */
  325.     while (TRUE)
  326.         {
  327.         while ((pRecvPacket = medGetRecvPacket (es)) != (nic_RecvHdr_s *) NULL)
  328.             {
  329.             if (es->bRecvBfrOvfl)
  330.                 return;
  331.             recvStatus = pRecvPacket->recvStatus;
  332.             if  ((recvStatus & PRX) == nic_RECV_NO_ERROR)
  333.                 {
  334.                 pktSize = (u_long) pRecvPacket->byteCntL
  335.                         | (u_long) (pRecvPacket->byteCntH << 8);
  336.                 /*
  337.                  * If the packet is wrapped around in the receive buffer,
  338.                  * move it to a contiguous buffer.
  339.                  */
  340.                 if (((u_long) pRecvPacket + pktSize) > (u_long) END_OF_RECV_BFR)
  341.                     {
  342.                     medMoveWrappedPacket (es, pRecvPacket, pktSize);
  343.                     medRecv (es, &(es->pOvfRecvBfr->eh), (int) pktSize);
  344.                     }
  345.                 else
  346.                     medRecv (es, &(pRecvPacket->eh), (int) pktSize);
  347.                 es->pktNextToRead = pRecvPacket->nextPkt;
  348.                 /*
  349.                  * Ensure that the "boundry" register is maintained one page
  350.                  * behind the "current"  register.
  351.                  */
  352.                 if (es->pktNextToRead ==
  353.     ((u_char) ((u_short) dbeth_NIC_RECV_BFR) >> 8))
  354.     {
  355.                     pNIC->Bnry = PSTOP - 1;
  356.     }
  357.                 else
  358.                     pNIC->Bnry = es->pktNextToRead - 1;
  359.                 }
  360.             else
  361.                 {
  362.                 if ((recvStatus & DIS) == nic_RCVR_DISABLED)
  363.                    logMsg("med%d: receiver disabledn",
  364. es->es_if.if_unit, 0,0,0,0,0);
  365.                 if ((recvStatus & DFR) == nic_RCVR_DEFERRING)
  366.                    logMsg("med%d: receiver deferringn", 
  367. es->es_if.if_unit, 0,0,0,0,0);
  368.                 }
  369.             }   /* while ((pRecvPacket ... */
  370.         if (pNIC->Isr & PRX)           /* pending recv interrupt ?   */
  371.             {
  372.             pNIC->Isr = PRX;           /* clear interrupt flag       */
  373.             med_Stats.PRX_intrCount++; /* update statistics monitor  */
  374.             }
  375.         else if (pNIC->Isr & RXE)      /* pending recv error interrupt ? */
  376.             {
  377.             pNIC->Isr = RXE;           /* clear interrupt flag       */
  378.             medRecordRecvError (es);
  379.             }
  380.         else
  381.             {                          /* no recv interrupt          */
  382.             /* Re-enable PRX and RXE interrupts. */
  383.             medSetNIC_IMR (es,  nic_PKT_RECV_NO_ERRORS
  384.                               | nic_PKT_RECV_ERROR, MASK_NONE);
  385.             break; /* break from while (TRUE) */
  386.             }
  387.         }       /* while (TRUE)            */
  388.     }
  389. /*******************************************************************************
  390. *
  391. * medIoctl - process an ioctl request.
  392. */
  393. LOCAL int medIoctl
  394.     (
  395.     FAST struct ifnet *ifp,
  396.     int cmd,
  397.     caddr_t data
  398.     )
  399.     {
  400.     int  unit  = ifp->if_unit;
  401.     FAST struct med_softc *  es = med_softc [unit];
  402.     int  s     = splimp ();
  403.     int  error = 0;
  404.     short  flags;
  405.     switch (cmd)
  406. {
  407. case SIOCSIFADDR:
  408.             ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN (data)->sin_addr;
  409.             arpwhohas (ifp, &IA_SIN (data)->sin_addr);
  410.     break;
  411. case SIOCGIFADDR:
  412.     bcopy((caddr_t) es->es_enaddr,
  413.   (caddr_t) ((struct ifreq *) data)->ifr_addr.sa_data, 6);
  414.     break;
  415. case SIOCGIFFLAGS:
  416.     *(short *) data = ifp->if_flags;
  417.     break;
  418. case SIOCSIFFLAGS:
  419.     {
  420.             flags = ifp->if_flags;
  421. #ifdef BSD43_DRIVER
  422.     if (ifp->if_flags & IFF_PROMISC)
  423.         es->bPromisc = TRUE;
  424.     else
  425.         es->bPromisc = FALSE;
  426. #endif
  427.     if (ifp->if_flags & IFF_UP)
  428.         flags |= (IFF_UP | IFF_RUNNING);
  429.     else
  430.         flags &= ~(IFF_UP | IFF_RUNNING);
  431.     ifp->if_flags = flags;
  432.     }
  433.     break;
  434. default:
  435.     error = EINVAL;
  436. }
  437.     splx (s);
  438.     return (error);
  439.     }
  440. /*******************************************************************************
  441. *
  442. * medXmitIntrHandler - handler for transmit interrupts
  443. *
  444. */
  445. LOCAL void medXmitIntrHandler
  446.     (
  447.     FAST struct med_softc *es,
  448.     FAST u_char xmitStatus
  449.     )
  450.     {
  451.     FAST xmitQCB_s  * pXmitQCB = &(es->xmitQCB);
  452.     FAST XBIdx_t      headPkt;
  453.     /*
  454.      * The following flags indicate packet transmission error:
  455.      *
  456.      *   ABT - excess collisions, transmission was aborted
  457.      *   FU  - NIC FIFO underrun, transmission was aborted (should never occur)
  458.      *
  459.      * Retransmit the packet.
  460.      *
  461.      * The following flags indicate a collision occurred but the packet
  462.      * was eventually transmitted.
  463.      *
  464.      *   CRS - carrier lost (lost due to a collision)
  465.      *   OWC - out-of-window-collision
  466.      *
  467.      */
  468.     if (xmitStatus & (ABT | FU))
  469.         {
  470.         es->es_if.if_oerrors++;            /* log transmit error */
  471.         if (xmitStatus & ABT)
  472.             {
  473.             med_Stats.excessColl++;        /* update statistics monitor */
  474.     logMsg("med%d: ERROR - excessive collisions, transmission abortedn"
  475.                    , es->es_if.if_unit, 0,0,0,0,0);
  476.             }
  477.         if (xmitStatus & FU)
  478.             {
  479.             med_Stats.FIFO_UdrRun++;       /* update statistics monitor */
  480.             logMsg("med%d: ERROR - NIC FIFO underrun, transmission abortedn",
  481.                    es->es_if.if_unit, 0,0,0,0,0);
  482.             }
  483.         headPkt = pXmitQCB->head;
  484.         if (medXmitPacket (es,
  485.                            pXmitQCB->xmitBCB [headPkt].pPktBfr,
  486.                            pXmitQCB->xmitBCB [headPkt].pktLen) == ERROR)
  487.             logMsg("med%d: ERROR - NIC transmitter active, should be off.n",
  488.                    es->es_if.if_unit, 0,0,0,0,0);
  489.         }
  490.     else  /* no transmission error */
  491.         {
  492.         if (xmitStatus & CRS)
  493.             med_Stats.carrierLost++;      /* update statistics monitor */
  494.         if (xmitStatus & OWC)
  495.             med_Stats.outOfWndColl++;     /* update statistics monitor */
  496.         es->es_if.if_opackets++;          /* log packet output      */
  497.         pXmitQCB->xmitBCB [pXmitQCB->head].bPktRdy = FALSE;
  498.         medXmitBfrDealloc (pXmitQCB);     /* could be a macro        */
  499.         headPkt = pXmitQCB->head;         /* new head index after buf dealloc */
  500.         if (pXmitQCB->xmitBCB [headPkt].bPktRdy)
  501.             {
  502.             if (medXmitPacket (es,
  503.                                pXmitQCB->xmitBCB [headPkt].pPktBfr,
  504.                                pXmitQCB->xmitBCB [headPkt].pktLen) == ERROR)
  505.                 logMsg("med%d: ERROR - NIC transmitter active, should be off.n"
  506.        , es->es_if.if_unit, 0,0,0,0,0);
  507.             }
  508.         else
  509.             {
  510.             medXmtrUnlock (&(pXmitQCB->lockNIC_Xmtr));
  511.             if (es->es_if.if_snd.ifq_head != NULL) /* if packet(s) on queue   */
  512. #ifdef BSD43_DRIVER
  513.                 netJobAdd ( (FUNCPTR)medStartOutput, es->es_if.if_unit,
  514.                            0, 0, 0, 0);
  515. #else
  516.                 netJobAdd ( (FUNCPTR)medStartOutput, (int)es, 0, 0, 0, 0);
  517. #endif
  518.             }
  519.         }
  520.     }
  521. /*******************************************************************************
  522. *
  523. * medIntr - top level DB-ETH interrupt service routine
  524. */
  525. LOCAL void medIntr
  526.     (
  527.     FAST int unit
  528.     )
  529.     {
  530.     FAST u_char            intrStatus;
  531.     FAST struct med_softc *es   = med_softc [unit];
  532.     FAST NIC_DEVICE       *pNIC = es->nicAddr;
  533.     med_Stats.intrCount++;
  534.     /* retrieve interrupt status */
  535.     intrStatus = pNIC->Isr;
  536.     if (intrStatus & OVW)              /* overflow warning, no recv buffers */
  537.         {
  538.         medSetNIC_IMR (es, UNMASK_NONE,  nic_RECV_BFR_OVF_WARN
  539.                                        | nic_PKT_RECV_NO_ERRORS
  540.                                        | nic_PKT_RECV_ERROR);
  541.         es->bRecvBfrOvfl = TRUE;           /* flag for medRecvIntrHandler() */
  542.         intrStatus &= ~(OVW | PRX | RXE);  /* ignore these interrupts */
  543.         logMsg ("med%d: receive buffer overflow, all buffers cleared.n",
  544. unit, 0,0,0,0,0);
  545.         med_Stats.OVW_intrCount++;         /* update statistics monitor */
  546.         (void) netJobAdd (medInit, unit, 0,0,0,0);
  547.         }
  548.     if (intrStatus & PRX)              /* packet reception, no error */
  549.         {
  550.         /*
  551.          * Handle packet reception interrupts (with and without errors)
  552.          * at task level, until none remaining.
  553.          * Mask further PRX (nic_PKT_RECV_NO_ERRORS) interrupts.
  554.          * Mask further RXE (nic_PKT_RECV_ERROR) interrupts.
  555.          */
  556.         medSetNIC_IMR (es, UNMASK_NONE,  nic_PKT_RECV_NO_ERRORS
  557.                                        | nic_PKT_RECV_ERROR);
  558.         pNIC->Isr = PRX;               /* clear interrupt flag */
  559.         med_Stats.PRX_intrCount++;     /* update statistics monitor */
  560.         (void) netJobAdd ((FUNCPTR)medRecvIntrHandler, (int)es, 0,0,0,0);
  561.         }
  562.     if (intrStatus & PTX)              /* packet transmission, not aborted */
  563.         {
  564.         pNIC->Isr = PTX;               /* clear interrupt flag */
  565.         med_Stats.PTX_intrCount++;     /* update statistics monitor */
  566.         medXmitIntrHandler(es, pNIC->Tsr);
  567.         }
  568.     if (intrStatus & TXE)              /* packet transmission aborted */
  569.         {
  570.         pNIC->Isr = TXE;               /* clear interrupt flag       */
  571.         med_Stats.TXE_intrCount++;     /* update statistics monitor  */
  572.         medXmitIntrHandler(es, pNIC->Tsr);
  573.         }
  574.     if (intrStatus & RXE)              /* packet received with error(s) */
  575.         {
  576.         pNIC->Isr = RXE;               /* clear interrupt flag       */
  577.         medRecordRecvError (es);
  578.         }
  579.     if (intrStatus & CNT)              /* tally counter MSB set      */
  580.         {
  581.         pNIC->Isr = CNT;               /* clear interrupt flag       */
  582.         med_Stats.CNT_intrCount++;     /* update statistics monitor  */
  583.         (void) netJobAdd ((FUNCPTR)medReadTallyCntrs, (int)es,0,0,0,0);
  584.         }
  585.     }
  586. /*******************************************************************************
  587. *
  588. * medRecordRecvError - record packet reception errors
  589. */
  590. LOCAL void medRecordRecvError
  591.     (
  592.     FAST struct med_softc *es
  593.     )
  594.     {
  595.     med_Stats.RXE_intrCount++;     /* update statistics monitor  */
  596.     /*
  597.      * Packets received with errors are not saved. Therefore,
  598.      * es->pktNextToRead is not updated.
  599.      */
  600.     es->es_if.if_ierrors++;
  601.     /* log every medLogCount errors */
  602.     if (medLogCount > 0 && (es->es_if.if_ierrors % medLogCount) == 0)
  603.         logMsg ("med%d: receive errorn",
  604. es->es_if.if_unit,0,0,0,0,0);
  605.     }
  606. /*******************************************************************************
  607. *
  608. * medIntEnable - enables/disables the DB-ETH interrupt
  609. *
  610. */
  611. LOCAL void medIntEnable
  612.     (
  613.     BOOL bEnable
  614.     )
  615.     {
  616.     int oldLevel;
  617.     /*
  618.      * In an attempt to avoid spurious interrupts
  619.      * on Dbus interrupt disable...
  620.      */
  621.     if (!bEnable)
  622.         {
  623.         oldLevel = intLock ();
  624.         sysDbusEtherIntEnable (bEnable);
  625.         intUnlock (oldLevel);
  626.         }
  627.     else
  628.         sysDbusEtherIntEnable (bEnable);
  629.     }
  630. /*******************************************************************************
  631. *
  632. * medReset - reset the interface
  633. *
  634. * Mark interface as inactive and reset the NIC.
  635. */
  636. LOCAL void medReset
  637.     (
  638.     int unit
  639.     )
  640.     {
  641.     struct med_softc  *es   = med_softc [unit];
  642.     NIC_DEVICE        *pNIC = es->nicAddr;
  643.     es->es_if.if_flags &= ~IFF_RUNNING;
  644.     /*
  645.      * The following sequence is required when disabling the NIC from
  646.      * an active network. (This sequence was derived from the DP8390
  647.      * Datasheet Addendum, dated December, 1988, section 2.1.)
  648.      */
  649.     pNIC->Cr = RPAGE0 | STP | ABORT;
  650.     /* clear remote DMA byte count registers */
  651.     pNIC->Rbcr0 = 0;
  652.     pNIC->Rbcr1 = 0;
  653.     /* if the NIC not yet stopped, wait for approximately 2ms */
  654.     if ((pNIC->Isr & RST) != nic_STOP_MODE)
  655.         medNIC_AwaitStop (pNIC);
  656.     }
  657. /*******************************************************************************
  658. *
  659. * medInit - initialize NIC.
  660. *
  661. * Restart the NIC chip and mark the interface as up.
  662. *
  663. */
  664. LOCAL int medInit
  665.     (
  666.     int unit
  667.     )
  668.     {
  669.     struct med_softc *es  = med_softc [unit];
  670.     struct ifnet     *ifp = &es->es_if;
  671.     medIntEnable (FALSE);     /* disable DB-ETH interrupt */
  672.     ifp->if_flags &= ~(IFF_UP | IFF_RUNNING | IFF_PROMISC);
  673.     /* stop all operations, reset the NIC */
  674.     medReset (unit);
  675.     /* Clear all driver statistics on first initialization, but
  676.      * not on subsequent calls of medInit(), e.g. after receive
  677.      * buffer overflow.
  678.      */
  679.     if (es->bFirstInit)
  680.         {
  681.         bzero((char *) &med_Stats, sizeof (med_Stats));
  682.         es->bFirstInit = FALSE;
  683.         }
  684.     /* configure and start NIC operations */
  685.     medConfigNIC (unit);
  686.     /* initialize the NIC IMR shadow register */
  687.     es->currentIMR = NIC_INTERRUPTS_HANDLED;
  688.     /* flag for medRecvIntrHandler(), no receive buffer overflow */
  689.     es->bRecvBfrOvfl = FALSE;
  690.     /*
  691.      * Initialize the "next-packet-to-read" pointer.
  692.      * The NIC's remote DMA capability is not supported by the DB-ETH.
  693.      * Therefore, the BNRY register is not maintained by the NIC, and
  694.      * it must be maintained by software. However, BNRY must never
  695.      * equal CURR.
  696.      *
  697.      * pktNextToRead: This page pointer is required to determine where
  698.      * to retrieve the next received packet.
  699.      */
  700.     es->pktNextToRead = CURR;
  701.     /*
  702.      * Initialize the xmitQCB and xmitBfrCB structures.
  703.      */
  704.     {
  705.     xmitQCB_s *pXmitQCB = &(es->xmitQCB);
  706.     int        idx;
  707.     pXmitQCB->head   = 0;
  708.     pXmitQCB->tail   = 0;
  709.     pXmitQCB->bEmpty = TRUE;
  710.     pXmitQCB->bFull  = FALSE;
  711.     for (idx = 0; idx < NUM_XMIT_BFRS; idx++)
  712.         {
  713.         pXmitQCB->xmitBCB [idx].bPktRdy = FALSE;
  714.         pXmitQCB->xmitBCB [idx].pPktBfr
  715.              = (char *) (NIC_XMIT_BFR_ADRS + XMIT_BFR_SIZE * idx);
  716.         }
  717.     for (idx = 1; idx < NUM_XMIT_BFRS; idx++)
  718.         pXmitQCB->xmitBCB [idx - 1].next = idx;
  719.     /*
  720.      * Close the ring. Assign the next index parameter of the last buffer
  721.      * control block to the index of the first buffer control block in
  722.      * the ring.
  723.      */
  724.     pXmitQCB->xmitBCB [NUM_XMIT_BFRS - 1].next = 0;
  725.     /* allow access to the NIC transmitter */
  726.     medXmtrUnlock (&(pXmitQCB->lockNIC_Xmtr));
  727.     }
  728.     ifp->if_flags |= (IFF_UP | IFF_RUNNING);
  729. #ifdef BSD43_DRIVER
  730.     if (es->bPromisc)
  731. ifp->if_flags |= (IFF_PROMISC);
  732. #endif
  733.     medIntEnable (TRUE);
  734.     return (0);
  735.     }
  736. /*******************************************************************************
  737. *
  738. * bitReverse - reverse the position of the bits in a byte
  739. *
  740. */
  741. LOCAL u_char  bitReverse
  742.     (
  743.    u_char in
  744.     )
  745.     {
  746.     int    bit;
  747.     u_char fromBitMask;
  748.     u_char toBitMask;
  749.     u_char out = 0;
  750.     fromBitMask = 0x01;
  751.     toBitMask   = 0x80;
  752.     for (bit = 0; bit < 8; bit++)
  753. {
  754.         if (in & fromBitMask)
  755.             out |= toBitMask;
  756.         fromBitMask = fromBitMask << 1;
  757.         toBitMask   = toBitMask   >> 1;
  758. }
  759.     return (out);
  760.     }
  761. /*******************************************************************************
  762. *
  763. * medEthAddrGet - Get hardwired ethernet address from DB-ETH.
  764. *
  765. * Read the ethernet address out of the ROM, one byte at a time.
  766. * put it in med_softc
  767. *
  768. * INTERNAL
  769. * The DB-ETH prototype boards have the 8 data lines reversed to the
  770. * Ethernet address PROM. Using the assigned Ethernet address (1st 3
  771. * octets), this function determines if the data lines are reversed on
  772. * the DB-ETH board it is controling and makes the appropriate
  773. * conversion if necessary. Note that this function will fail if each
  774. * of the 3 octets are made-up of nybbles which are mirror images of
  775. * each other. For example, the following bytes (in hex):
  776. * 00, 81, 66, 99, E7, ... The third octet assigned to Matrix Corp.
  777. * is 0x0b. This octet in PROM will be determine whether to reverse
  778. * the data values.
  779. */
  780. LOCAL void medEthAddrGet
  781.     (
  782.     int unit
  783.     )
  784.     {
  785.     u_char             octet;
  786.     u_int              octetSel;
  787.     BOOL               bReversed;
  788.     struct  med_softc *es = med_softc [unit];
  789.     u_char            *pEthOctet = (u_char *) (ETH_ADRS_PROM_ADRS);
  790.     /* XXX optimize by saving result in static variable then just test var. ? */
  791.     bReversed = FALSE;
  792.     if (*(pEthOctet + 2) != 0x0b)
  793.         bReversed = TRUE;
  794.     for (octetSel = 0; octetSel < 6; octetSel++ )
  795.         {
  796.         octet = *pEthOctet;
  797.         if (bReversed)
  798.             octet = bitReverse (octet);
  799.         es->es_enaddr [octetSel] = octet;
  800.         pEthOctet++;
  801.         }
  802.     }
  803. /*******************************************************************************
  804. *
  805. * medConfigNIC - Configure the NIC for operation
  806. *
  807. * INTERNAL
  808. * This NIC initialization/configuration sequence was derived from the
  809. * DP8390 Datasheet Addendum, dated December, 1988, section 2.0. This
  810. * configuration enables the NIC onto an active network.
  811. */
  812. LOCAL void medConfigNIC
  813.     (
  814.     int unit
  815.     )
  816.     {
  817.     struct med_softc  *es   = med_softc [unit];
  818.     NIC_DEVICE        *pNIC = es->nicAddr;
  819.     /* get Ethernet address from ROM */
  820.     medEthAddrGet (unit);
  821.     /* stop/abort all NIC operations */
  822.     pNIC->Cr  = RPAGE0 | STP | ABORT;
  823.     pNIC->Dcr = FT2 | BMS | BOS | WTS;
  824.     /* clear remote DMA byte count registers */
  825.     pNIC->Rbcr0  = 0;
  826.     pNIC->Rbcr1  = 0;
  827.     /* accept broadcast, but not runt and multicast packets */
  828.     pNIC->Rcr = AB;
  829.     /* configure for internal loopback mode */
  830.     pNIC->Tcr = MODE1;
  831.     /* initialize receive buffer pointers */
  832.     pNIC->Bnry   = BNRY;
  833.     pNIC->Pstart = PSTART;
  834.     pNIC->Pstop  = PSTOP;
  835.     /* clear the interrupt status */
  836.     pNIC->Isr = RST | RDC | CNT | OVW | TXE | RXE | PTX | PRX;
  837.     /* enable selected interrupts */
  838.     pNIC->Imr = NIC_INTERRUPTS_HANDLED;
  839.     /* select NIC page 1 registers */
  840.     pNIC->Cr  = RPAGE1 | STP | ABORT;
  841.     /* initialize the physical address, e.g. the Ethernet address */
  842.     pNIC->Par0 = es->es_enaddr [0];
  843.     pNIC->Par1 = es->es_enaddr [1];
  844.     pNIC->Par2 = es->es_enaddr [2];
  845.     pNIC->Par3 = es->es_enaddr [3];
  846.     pNIC->Par4 = es->es_enaddr [4];
  847.     pNIC->Par5 = es->es_enaddr [5];
  848.     /*
  849.      * Initialize the multicast address registers.
  850.      *    CURRENTLY NOT SUPPORTED
  851.      */
  852.     /* initialize the next packet receive buffer pointer */
  853.     pNIC->Curr = CURR;
  854.     /* start NIC */
  855.     pNIC->Cr = RPAGE0 | STA | ABORT;
  856.     /* enable packet transmission */
  857.     pNIC->Tcr = nic_NORMAL_XMIT_CTRL;
  858.     }
  859. #ifdef BSD43_DRIVER
  860. /*******************************************************************************
  861. *
  862. * medOutput -
  863. *
  864. * Ethernet output routine.
  865. * Encapsulate a packet of type family for the local net.
  866. * Use trailer local net encapsulation if enough data in first
  867. * packet leaves a multiple of 512 bytes of data in remainder.
  868. */
  869. LOCAL int medOutput
  870.     (
  871.     FAST struct ifnet   *ifp,
  872.     FAST struct mbuf    *m0,
  873.     struct sockaddr     *dst
  874.     )
  875.     {
  876.     return (ether_output (ifp, m0, dst, (FUNCPTR) medStartOutput,
  877.   &med_softc [ifp->if_unit]->es_ac));
  878.     }
  879. #endif
  880. /*******************************************************************************
  881. *
  882. * medStartOutput - start pending output
  883. *
  884. * Start output to NIC.
  885. * Queue up all pending datagrams for which transmit buffers are available.
  886. * It is very important that this routine be executed with splimp set.
  887. * If this is not done, another task could allocate the same transmit buffer.
  888. */
  889. #ifdef BSD43_DRIVER
  890. LOCAL void medStartOutput
  891.     (
  892.     int unit
  893.     )
  894.     {
  895.     FAST struct med_softc *  es = med_softc [unit];
  896. #else
  897. LOCAL void medStartOutput
  898.     (
  899.     struct med_softc *  es
  900.     )
  901.     {
  902. #endif
  903.     FAST struct mbuf   *m;
  904.     FAST char   *buf;
  905.     int    len;
  906.     FAST xmitBCB_s        *pXmitBCB;
  907.     int    s = splimp ();
  908.     FAST xmitQCB_s  * pXmitQCB = &(es->xmitQCB);
  909.     FAST XBIdx_t      headPkt  = pXmitQCB->head;
  910.     while (es->es_if.if_snd.ifq_head != NULL)
  911.         {
  912. /* there is something to send */
  913.         if ((pXmitBCB = medXmitBfrAlloc (es)) == (xmitBCB_s *) NULL)
  914.             {
  915.             med_Stats.noXmitBfrs++;
  916.             es->es_if.if_oerrors++;
  917.     break; /* no transmit buffers available */
  918.     }
  919.         buf  = pXmitBCB->pPktBfr;
  920. /* get message to send */
  921. IF_DEQUEUE (&es->es_if.if_snd, m); /* get head of next mbuf chain */
  922. copy_from_mbufs (buf, m, len);
  923. len = max (ETHERSMALL, len);
  924.         pXmitBCB->pktLen  = (u_short)len;
  925.         pXmitBCB->bPktRdy = TRUE;
  926. /* call output hook if any */
  927. if (etherOutputHookRtn != NULL &&
  928.      (* etherOutputHookRtn) (&es->es_if, buf, len))
  929.             continue;
  930.         if (medXmtrLock (&(pXmitQCB->lockNIC_Xmtr)) != ERROR)
  931.             {
  932.             /*
  933.              * Start transmission of the next packet on the xmitQ
  934.              * unless the transmit interrupt handler has already
  935.              * transmitted it.
  936.              *
  937.              * Lock mechanism  pXmitQCB->lockNIC_Xmtr is unlocked by
  938.              * the transmit interrupt handler when all packets on
  939.              * the xmitQ have been transmitted.
  940.              */
  941.             if (pXmitQCB->xmitBCB [headPkt].bPktRdy)
  942.                 {
  943.                 if (medXmitPacket (es, pXmitQCB->xmitBCB [headPkt].pPktBfr,
  944.                                    pXmitQCB->xmitBCB [headPkt].pktLen)
  945.                     == ERROR)
  946.                     {
  947.                     logMsg ("med%d: ERROR - NIC transmitter active, should 
  948.                              be off.n", es->es_if.if_unit, 0, 0, 0, 0, 0);
  949.                     }
  950.                 }
  951.             else
  952.                 medXmtrUnlock (&(pXmitQCB->lockNIC_Xmtr));
  953.             }
  954.         /* opackets statistic is incremented elsewhere after interrupt */
  955.         }
  956.     splx (s);
  957.     }
  958. /*******************************************************************************
  959. *
  960. * medXmitBfrAlloc - allocate a NIC transmit buffer
  961. *
  962. * RETURNS: address of the NIC transmit buffer or NULL if none available
  963. */
  964. LOCAL xmitBCB_s   *medXmitBfrAlloc
  965.     (
  966.     struct med_softc  *es
  967.     )
  968.     {
  969.     FAST xmitQCB_s *pXmitQCB = &(es->xmitQCB);
  970.     FAST xmitBCB_s *pTailXBCB;
  971.     int             oldLevel;
  972.     if (pXmitQCB->bFull)
  973.         return (xmitBCB_s *)NULL;
  974.     /* block interrupt service routine access to xmitQCB */
  975.     oldLevel = intLock();
  976.     pXmitQCB->bEmpty = FALSE;
  977.     pTailXBCB        = &(pXmitQCB->xmitBCB [pXmitQCB->tail]);
  978.     pXmitQCB->tail   = pTailXBCB->next;
  979.     if (pXmitQCB->head == pXmitQCB->tail)
  980.         pXmitQCB->bFull = TRUE;
  981.     intUnlock (oldLevel);
  982.     return (pTailXBCB);
  983.     }
  984. /*******************************************************************************
  985. *
  986. * medXmitPacket - NIC packet transmission
  987. *
  988. * RETURNS: ERROR if NIC transmitter busy, otherwise OK
  989. */
  990. LOCAL STATUS   medXmitPacket
  991.     (
  992.     struct med_softc *es,
  993.     char *pPacket,
  994.     u_short packetLen
  995.     )
  996.     {
  997.     NIC_DEVICE *pNIC = es->nicAddr;
  998. #if defined (med_SAVE_XMIT_PKTS)
  999.     static char *pXmitPktSaveBfr = (char *) 0xffd10000;
  1000.     /* check for possible buffer overrun */
  1001.     if (((u_long) pXmitPktSaveBfr + 1600) > 0xffd20000)
  1002. pXmitPktSaveBfr = (char *) 0xffd10000;
  1003.     bcopy (pPacket, pXmitPktSaveBfr, (int) packetLen);
  1004.     pXmitPktSaveBfr = pXmitPktSaveBfr + packetLen;
  1005.     bcopy ("$$$$$$$$$$$$$$$$", pXmitPktSaveBfr, 16);
  1006.     pXmitPktSaveBfr = pXmitPktSaveBfr + 16;
  1007. #endif /* med_SAVE_XMIT_PKTS */
  1008.     if ((pNIC->Cr & TXP) == nic_XMTR_BUSY)
  1009.         return (ERROR);
  1010.     pNIC->Tpsr  = nic_CPU_TO_NIC_ADRS (pPacket);
  1011.     pNIC->Tbcr1 = (u_char) (packetLen >> 8);
  1012.     pNIC->Tbcr0 = (u_char) packetLen;
  1013.     pNIC->Cr    = STA | TXP | ABORT;
  1014.     return (OK);
  1015.     }
  1016. /*******************************************************************************
  1017. *
  1018. * medStatsGet - output to stdout the med statictics
  1019. *
  1020. * NOMANUAL
  1021. */
  1022. void medStatsGet
  1023.     (
  1024.     int unit
  1025.     )
  1026.     {
  1027.     struct med_softc *es = med_softc [unit];
  1028.     medReadTallyCntrs (es);
  1029.     printf("med Statistics:n");
  1030.     printf("   packets received            : %ldn", es->es_if.if_ipackets);
  1031.     printf("   input errors                : %ldn", es->es_if.if_ierrors);
  1032.     printf("   packets transmitted         : %ldn", es->es_if.if_opackets);
  1033.     printf("   output errors               : %ldn", es->es_if.if_oerrors);
  1034.     printf("   packets on send queue       : %dn", es->es_if.if_snd.ifq_len);
  1035.     printf("   packets dropped (not xmit)  : %dn", es->es_if.if_snd.ifq_drops);
  1036.     printf("   xmit bufs full, xmit delayed: %ldn", med_Stats.noXmitBfrs);
  1037.     printf("   NIC total interrupts        : %ldn", med_Stats.intrCount);
  1038.     printf("   NIC PRX interrupts          : %ldn", med_Stats.PRX_intrCount);
  1039.     printf("   NIC PTX interrupts          : %ldn", med_Stats.PTX_intrCount);
  1040.     printf("   NIC RXE interrupts          : %ldn", med_Stats.RXE_intrCount);
  1041.     printf("   NIC TXE interrupts          : %ldn", med_Stats.TXE_intrCount);
  1042.     printf("   NIC OVW interrupts          : %ldn", med_Stats.OVW_intrCount);
  1043.     printf("   NIC CNT interrupts          : %ldn", med_Stats.CNT_intrCount);
  1044.     printf("   carrier lost on xmit        : %ldn", med_Stats.carrierLost);
  1045.     printf("   out of window collision     : %ldn", med_Stats.outOfWndColl);
  1046.     printf("   FIFO underrun               : %ldn", med_Stats.FIFO_UdrRun);
  1047.     printf("   excess collision            : %ldn", med_Stats.excessColl);
  1048.     printf("   frame alignment             : %ldn", med_Stats.frameAlign);
  1049.     printf("   CRC mismatch                : %ldn", med_Stats.misMatchCRC);
  1050.     printf("   missed packet               : %ldn", med_Stats.missedPkt);
  1051.     }
  1052. /*******************************************************************************
  1053. *
  1054. * medReadTallyCntrs - update local counters from NIC tally counters
  1055. *
  1056. */
  1057. LOCAL void medReadTallyCntrs
  1058.     (
  1059.     FAST struct med_softc *es
  1060.     )
  1061.     {
  1062.     NIC_DEVICE *pNIC = es->nicAddr;
  1063.     med_Stats.frameAlign  += pNIC->FaeErr;
  1064.     med_Stats.misMatchCRC += pNIC->CrcErr;
  1065.     med_Stats.missedPkt   += pNIC->MspErr;
  1066.     }
  1067. /*******************************************************************************
  1068. *
  1069. * medMoveWrappedPacket - move a wrapped packet in the NIC receive buffer
  1070. *
  1071. */
  1072. LOCAL void medMoveWrappedPacket
  1073.     (
  1074.     FAST struct med_softc  *es, /* for END_OF_RECV_BFR, NIC_RECV_BFR_ADRS */
  1075.     FAST nic_RecvHdr_s *pRecvPacket,
  1076.     FAST u_long pktSize
  1077.     )
  1078.     {
  1079.     FAST int    byteCount;
  1080.     FAST char  *pOvfRecvBfrMiddle;
  1081.     /* copy from start of packet to end of NIC receive buffer */
  1082.     byteCount = (int) ((u_long) END_OF_RECV_BFR - (u_long) pRecvPacket);
  1083.     bcopy ((char *) pRecvPacket, (char *) (es->pOvfRecvBfr), byteCount);
  1084.     /*
  1085.      * Copy remainder of packet from the base address of the NIC
  1086.      * receive buffer to the current address in the buffer at
  1087.      * es->pOvfRecvBfr.
  1088.      */
  1089.     pOvfRecvBfrMiddle = (char *) ((u_long) (es->pOvfRecvBfr)
  1090. + (u_long) byteCount);
  1091.     byteCount = (int) pktSize - byteCount;
  1092.     bcopy ((char *) NIC_RECV_BFR_ADRS (0), pOvfRecvBfrMiddle, byteCount);
  1093.     }
  1094. /*******************************************************************************
  1095. *
  1096. * medSetNIC_IMR - mask/unmask interrupts in the NIC Interrupt Mask Register
  1097. *
  1098. * INTERNAL
  1099. * This NIC Interrupt Mask Register (IMR) is essentially write-only.
  1100. * The IMR in register page 2 cannot be accessed during normal
  1101. * operation.
  1102. */
  1103. LOCAL void medSetNIC_IMR
  1104.     (
  1105.     FAST struct med_softc *es,
  1106.     FAST u_char unmaskBits,
  1107.     FAST u_char maskBits
  1108.     )
  1109.     {
  1110.     FAST int          oldLevel;
  1111.     FAST NIC_DEVICE  *pNIC       = es->nicAddr;
  1112.     FAST u_char       currentIMR = es->currentIMR;
  1113.     oldLevel = intLock ();
  1114.     /*
  1115.      * This kludge is to ensure that the PRX and RXE interrupts are not
  1116.      * enabled (in task medRecvIntrHandler) after an OVW interrupt.
  1117.      */
  1118.     if (es->bRecvBfrOvfl)
  1119.         unmaskBits &= ~(nic_PKT_RECV_NO_ERRORS | nic_PKT_RECV_ERROR);
  1120.     currentIMR     = (currentIMR | unmaskBits) & (~maskBits);
  1121.     es->currentIMR = currentIMR;
  1122.     pNIC->Imr      = currentIMR;
  1123.     intUnlock (oldLevel);
  1124.     }
  1125. /*******************************************************************************
  1126. *
  1127. * medNIC_AwaitStop - busy-wait 2ms or until the NIC stops
  1128. */
  1129. LOCAL void medNIC_AwaitStop
  1130.     (
  1131.     FAST NIC_DEVICE *pNIC
  1132.     )
  1133.     {
  1134.     FAST int   ticksIn2ms;
  1135.     FAST ULONG tickStartCount = tickGet ();
  1136.     /*
  1137.      * Wait for NIC to complete current operation.
  1138.      * Determine the number of clock ticks in 2ms...
  1139.      * Divide the ticks/second value returned by sysClkRateGet ()
  1140.      * by 512. (Note that 512 is approximately 500. Thus, shifting
  1141.      * by 9 is as if multiplying by approximately 0.002)
  1142.      */
  1143.     ticksIn2ms = sysClkRateGet () >> 9;
  1144.     if (ticksIn2ms == 0)
  1145.         ticksIn2ms = 1;
  1146.     while ((pNIC->Isr & RST) != nic_STOP_MODE)
  1147.         if ((tickStartCount + ticksIn2ms) < tickGet ())
  1148.             break;
  1149.     }
  1150. /*******************************************************************************
  1151. *
  1152. * medXmitBfrDealloc - deallocate emptied transmit buffer(s)
  1153. *
  1154. * This routine must execute at interrupt level only.
  1155. */
  1156. LOCAL void medXmitBfrDealloc
  1157.     (
  1158.     FAST xmitQCB_s  *pXmitQCB
  1159.     )
  1160.     {
  1161.     if (pXmitQCB->bEmpty)
  1162.         {
  1163.         logMsg("med: ERROR - transmit buffer deallocation failed.n",
  1164. 0,0,0,0,0,0);
  1165.         return;
  1166.         }
  1167.     pXmitQCB->bFull = FALSE;
  1168.     pXmitQCB->head  = pXmitQCB->xmitBCB [pXmitQCB->head].next;
  1169.     if (pXmitQCB->head == pXmitQCB->tail)
  1170.         pXmitQCB->bEmpty = TRUE;
  1171.     }
  1172. /*******************************************************************************
  1173. *
  1174. * medXmtrLock - lock access to the NIC transmitter
  1175. *
  1176. * This function must only be invoked by tasks executing with splimp.
  1177. * Otherwise, a race condition is possible during the LOCKED test.
  1178. *
  1179. * RETURNS: ERROR if already locked, OK otherwise
  1180. */
  1181. LOCAL STATUS medXmtrLock
  1182.     (
  1183.     FAST lockID_t *pLock
  1184.     )
  1185.     {
  1186.     FAST int oldLevel;
  1187.     if (*pLock == LOCKED)
  1188.         return ERROR;
  1189.     oldLevel = intLock ();
  1190.     *pLock = LOCKED;
  1191.     intUnlock (oldLevel);
  1192.     return (OK);
  1193.     }
  1194. /*******************************************************************************
  1195. *
  1196. * medXmtrUnlock - unlock access to the NIC transmitter
  1197. *
  1198. */
  1199. LOCAL void medXmtrUnlock
  1200.     (
  1201.     FAST lockID_t *pLock
  1202.     )
  1203.     {
  1204.     *pLock = UNLOCKED;
  1205.     }