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

VxWorks

开发平台:

C/C++

  1. /* if_esmc.c - Ampro Ethernet2 SMC-91c9x Ethernet network interface driver */
  2. /* Copyright 1984-1997 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01d,15jul97,spm  removed driver initialization from ioctl support (SPR #8831)
  8. 01c,15may97,spm  reverted to bcopy routines for mbufs in BSD 4.4
  9. 01b,07apr97,spm  code cleanup, corrected statistics, and upgraded to BSD 4.4
  10. 01a,07may96,hdn  written.
  11. */
  12. /*
  13. DESCRIPTION
  14. This module implements the Ampro Ethernet2 SMC-91c9x Ethernet network
  15. interface driver.
  16. CONFIGURATION
  17. The W3 and W4 jumper should be set for IO address and IRQ.
  18. The defined I/O address and IRQ in config.h must match the one stored
  19. in EEROM and the jumper setting. 
  20. BOARD LAYOUT
  21. The diagram below shows the relevant jumpers for VxWorks configuration.
  22. .bS
  23.         ___________________________________
  24.         |             * * * *             |
  25.         |  ______                         |
  26.         |  |    |                         |
  27.         |  | U1 | W1  W3                  |
  28.         |  |PROM| X   "                   |
  29.         |  |    | .   -                   |
  30.         |  |    |     -                   |
  31.         |  |    |     -                   |
  32.         |  |____|                         |
  33.         |                                 |
  34.         |                W4               |
  35.         |                "                |
  36.         |                "                |
  37.         |                -                |
  38.         |                -                |
  39.         |_________________________________|    
  40.       W1:  Boot PROM Size
  41.       W3:  IO-address, IRQ, Media
  42.       W4:  IRQ Group Selection
  43. .bE
  44. EXTERNAL INTERFACE
  45. The only user-callable routines are esmcattach():
  46. .iP esmcattach() 14
  47. publishes the `esmc' interface and initializes the driver and device.
  48. .LP
  49. The last parameter of esmcattach(), <mode>, is a receive mode.
  50. If it is 0, a packet is received in the interrupt level.  If it is 1,
  51. a packet is received in the task level.  Receiving packets in the interrupt
  52. level requires about 10K bytes of memory, but minimize a risk of dropping 
  53. packets.  Receiving packets in the task level doesn't require extra
  54. memory, but might have a risk of dropping packets.
  55. INTERNAL
  56. A driver implementation for this board faces two conflicting network
  57. interface design goals:  (1) minimizing the time spent at interrupt level,
  58. and (2) servicing the board's input without dropping packets.
  59. Receive overrun affects significantly for the performance.  It depends
  60. on CPU power and network traffic of your hardware and software.
  61. And also it depends on the memory size of the chip, 91cxx series.
  62. Importance of performance penalty for dropping packets by the receive
  63. overrun and time spent at the interrupt level is different for each person.  
  64. So there is a configurable flag to decide a receive mode which is the
  65. last parameter of esmcattach() function.
  66. */
  67. #include "vxWorks.h"
  68. #include "net/mbuf.h"
  69. #include "net/protosw.h"
  70. #include "net/unixLib.h"
  71. #include "ioctl.h"
  72. #include "socket.h"
  73. #include "errnoLib.h"
  74. #include "net/uio.h"
  75. #include "net/if.h"
  76. #include "net/route.h"
  77. #include "netinet/in.h"
  78. #include "netinet/in_systm.h"
  79. #include "netinet/ip.h"
  80. #include "netinet/ip_var.h"
  81. #include "netinet/in_var.h"
  82. #include "netinet/if_ether.h"
  83. #include "etherLib.h"
  84. #include "vme.h"
  85. #include "iv.h"
  86. #include "iosLib.h"
  87. #include "ioLib.h"
  88. #include "memLib.h"
  89. #include "net/systm.h"
  90. #include "net/if_subr.h"
  91. #include "sysLib.h"
  92. #include "vxLib.h"
  93. #include "stdio.h"
  94. #include "intLib.h"
  95. #include "logLib.h"
  96. #include "string.h"
  97. #include "netLib.h"
  98. #include "stdlib.h"
  99. #include "semLib.h"
  100. #include "cacheLib.h"
  101. #include "tickLib.h"
  102. #include "drv/netif/if_esmc.h"
  103. #undef ESMC_DEBUG    /* define to include debug messages */
  104. #define NESMC 2 /* max number of ESMC controllers */
  105. #define ESMC_SHOW TRUE /* show routine */
  106. #define ESMC_USE_LONG TRUE /* use long word IO access */
  107. #define ATTACHMENT_DEFAULT      0       /* use card as configured */
  108. #define ATTACHMENT_AUI          1       /* AUI  (thick, DIX, DB-15) */
  109. #define ATTACHMENT_BNC          2       /* BNC  (thin, 10BASE-2) */
  110. #define ATTACHMENT_RJ45         3       /* RJ-45 (twisted pair, TPE, 10BASE-T)*/
  111. #define RX_MODE_INTERRUPT 0 /* receive in interrupt level */
  112. #define RX_MODE_TASK 1 /* receive in task level */
  113. /* globals */
  114. /* locals */
  115. LOCAL ESMC_SOFTC esmc_softc [NESMC];
  116. LOCAL char * pName[12] =
  117.     {
  118.     NULL,       NULL,       NULL, "SMC91C90/91C92",
  119.     "SMC91C94", "SMC91C95", NULL, "SMC91C100", 
  120.     NULL,       NULL,       NULL, NULL
  121.     };  
  122. /* forward static functions */
  123. LOCAL int    esmcInit (int unit);
  124. LOCAL void   esmcReset (int unit);
  125. LOCAL int    esmcIoctl (struct ifnet *ifp, int cmd, caddr_t data);
  126. #ifdef BSD43_DRIVER
  127. LOCAL int    esmcOutput (struct ifnet *ifp, struct mbuf *m0, 
  128.  struct sockaddr *dst);
  129. #endif
  130. LOCAL void   esmcIntr (int unit);
  131. LOCAL void   esmcGet (int unit);
  132. LOCAL void   esmcGetInt (int unit);
  133. LOCAL void   esmcGetTask (int unit);
  134. #ifdef BSD43_DRIVER
  135. LOCAL void   esmcPut (int unit);
  136. #else
  137. LOCAL void   esmcPut (ESMC_SOFTC *sc);
  138. #endif
  139. LOCAL STATUS esmcChipInit (int unit);
  140. LOCAL void   esmcChipReset (int unit);
  141. /*******************************************************************************
  142. *
  143. * esmcattach - publish the `esmc' network interface and initialize the driver.
  144. *
  145. * This routine attaches an `esmc' Ethernet interface to the network if the
  146. * device exists.  It makes the interface available by filling in the network
  147. * interface record.  The system will initialize the interface when it is ready
  148. * to accept packets.
  149. *
  150. * RETURNS: OK or ERROR.
  151. *
  152. * SEE ALSO: ifLib, netShow
  153. */
  154. STATUS esmcattach 
  155.     (
  156.     int unit,           /* unit number */
  157.     int ioAddr,         /* address of esmc's shared memory */
  158.     int intVec,         /* interrupt vector to connect to */
  159.     int intLevel,       /* interrupt level */
  160.     int config, /* 0: Autodetect  1: AUI  2: BNC  3: RJ45 */
  161.     int mode /* 0: rx in interrupt   1: rx in task(netTask) */
  162.     )
  163.     {
  164.     FAST ESMC_SOFTC *sc = &esmc_softc[unit];
  165.     if ((UINT)unit >= NESMC)
  166. {
  167.         errnoSet (S_iosLib_CONTROLLER_NOT_PRESENT);
  168. return (ERROR);
  169. }
  170.     sc->ioAddr = ioAddr;
  171.     sc->intVec = intVec;
  172.     sc->intLevel = intLevel;
  173.     sc->config = config;
  174.     sc->flags = 0;
  175.     sc->mode = mode;
  176.     sc->pBuft = (char *)(((u_int)sc->buft + 3) & ~0x03);
  177.     if (sc->mode == RX_MODE_INTERRUPT) /* RX int */
  178. {
  179.         sc->bufi = malloc (ESMC_BUFSIZE_INT + 8);
  180.         sc->pBufi = (char *)(((u_int)sc->bufi + 3) & ~0x03);
  181.         sc->pStart = sc->pBufi; /* start pointer */
  182.         sc->pEnd = sc->pBufi + ESMC_BUFSIZE_INT; /* end pointer */
  183.         sc->pIn = sc->pBufi; /* input pointer */
  184.         sc->pOut = sc->pBufi; /* output pointer */
  185.         sc->indexIn = 0; /* input index */
  186.         sc->indexOut = 0; /* output index */
  187.         sc->nIndex = ESMC_INDEXES; /* indexes */
  188.         if (sc->bufi == NULL)
  189.     return (ERROR);
  190.         bzero (sc->pBufi, ESMC_BUFSIZE_INT);
  191. }
  192.     semBInit (&sc->esmcSyncSem, SEM_Q_FIFO, SEM_EMPTY);
  193.     (void) intConnect ((VOIDFUNCPTR *)INUM_TO_IVEC (intVec), 
  194.        (VOIDFUNCPTR)esmcIntr, unit);
  195. #ifdef BSD43_DRIVER
  196.     ether_attach (&sc->es_if, unit, "esmc", (FUNCPTR)esmcInit, 
  197.   (FUNCPTR)esmcIoctl, (FUNCPTR)esmcOutput, (FUNCPTR)esmcReset);
  198. #else
  199.     ether_attach (
  200.                  &sc->es_if, 
  201.                  unit, 
  202.                  "esmc", 
  203.                  (FUNCPTR)esmcInit, 
  204.          (FUNCPTR)esmcIoctl, 
  205.                  (FUNCPTR)ether_output, 
  206.                  (FUNCPTR)esmcReset
  207.                  );
  208.     sc->es_if.if_start = (FUNCPTR)esmcPut;
  209. #endif
  210.     esmcInit (unit);
  211.     return (OK);
  212.     }
  213. /*******************************************************************************
  214. *
  215. * esmcReset - reset the interface
  216. *
  217. * RETURNS: N/A
  218. */
  219. LOCAL void esmcReset 
  220.     (
  221.     int unit 
  222.     )
  223.     {
  224.     FAST ESMC_SOFTC *sc   = &esmc_softc [unit];
  225.     int s = splnet ();
  226.     sysIntDisablePIC (sc->intLevel);
  227.     sc->es_if.if_flags = 0;
  228.     splx (s);
  229.     }
  230. /*******************************************************************************
  231. *
  232. * esmcInit - initialize esmc
  233. *
  234. * Restart the link level software on the board and mark the interface up.
  235. *
  236. * RETURNS: 0
  237. */
  238. LOCAL int esmcInit 
  239.     (
  240.     int unit 
  241.     )
  242.     {
  243.     FAST ESMC_SOFTC *sc = &esmc_softc[unit];
  244.     int s = splnet ();
  245.     esmcChipInit (unit);
  246.     sysIntEnablePIC (sc->intLevel);
  247.     sc->es_if.if_flags |= IFF_UP|IFF_RUNNING; /* open for business*/
  248.     splx (s);
  249.     return (0);
  250.     }
  251. #ifdef BSD43_DRIVER
  252. /*******************************************************************************
  253. *
  254. * esmcOutput - ethernet output routine
  255. *
  256. * Encapsulate a packet of type family for the local net.
  257. * Use trailer local net encapsulation if enough data in first
  258. * packet leaves a multiple of 512 bytes of data in remainder.
  259. * If destination is this address or broadcast, send packet to
  260. * loop device to kludge around the fact that 3com interfaces can't
  261. * talk to themselves.
  262. *
  263. * RETURNS:  OK if successful, otherwise errno.
  264. */
  265. LOCAL int esmcOutput 
  266.     (
  267.     struct ifnet *ifp,
  268.     struct mbuf *m0,
  269.     struct sockaddr *dst 
  270.     )
  271.     {
  272.     return (ether_output (ifp, m0, dst, (FUNCPTR)esmcPut,
  273.   &esmc_softc [ifp->if_unit].es_ac));
  274.     }
  275. #endif
  276. /*******************************************************************************
  277. *
  278. * esmcIoctl - ioctl for interface
  279. *
  280. * RETURNS: OK if successful, otherwise errno.
  281. */
  282. LOCAL int esmcIoctl 
  283.     (
  284.     FAST struct ifnet *ifp,
  285.     int cmd,
  286.     caddr_t data 
  287.     )
  288.     {
  289.     FAST ESMC_SOFTC *sc = &esmc_softc[ifp->if_unit];
  290.     int status = OK;
  291.     int s = splimp();
  292.     short flags;
  293.     switch (cmd)
  294. {
  295. case SIOCSIFADDR:
  296.             ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN (data)->sin_addr;
  297.             arpwhohas (ifp, &IA_SIN (data)->sin_addr);
  298.     break;
  299. case SIOCSIFFLAGS:
  300.             flags = ifp->if_flags;
  301.     if (ifp->if_flags & IFF_UP)
  302.                 ifp->if_flags = flags | (IFF_UP|IFF_RUNNING);
  303.             else
  304.                 ifp->if_flags = flags & ~(IFF_UP|IFF_RUNNING);
  305.     break;
  306. default:
  307.     status = EINVAL;
  308. }
  309.     splx (s);
  310.     return (status);
  311.     }
  312. /*******************************************************************************
  313. *
  314. * esmcIntr - Ethernet interface interrupt
  315. *
  316. * Hand off reading of packets from the interface to task level.
  317. *
  318. * RETURNS: N/A
  319. */
  320. LOCAL void esmcIntr 
  321.     (
  322.     int unit 
  323.     )
  324.     {
  325.     FAST ESMC_SOFTC *sc = &esmc_softc[unit];
  326.     FAST int ioaddr     = sc->ioAddr;
  327.     int timeout         = ESMC_INTR_TIMEOUT;
  328.     u_short bank;
  329.     u_short pointerSave;
  330.     u_short statusTx;
  331.     u_short statusCard;
  332.     u_short packetFail;
  333.     u_char packetSave;
  334.     u_char mask;
  335.     u_char status;
  336.     sc->interrupt++;
  337.     bank = sysInWord (ioaddr + ESMC_BANK_SELECT); /* save bank */
  338.     ESMC_SWITCH_BANK (2);
  339.     mask = sysInByte (ioaddr + ESMC_INT_MASK); /* save mask */
  340.     while ((status = sysInByte (ioaddr + ESMC_INT_STAT) & mask) && (timeout--))
  341. {
  342. if (status & ESMC_INT_RCV) /* RX done */
  343.     {
  344.             sc->intRcv++;
  345.     if (sc->mode == RX_MODE_INTERRUPT) /* RX in int */
  346. {
  347. esmcGetInt (unit);
  348.         if ((sc->flags & ESMC_RXING) == 0)
  349.     {
  350.     sc->flags |= ESMC_RXING;
  351.     (void) netJobAdd ((FUNCPTR)esmcGetTask, unit, 0, 0, 0, 0);
  352.     }
  353. }
  354.     else if ((sc->flags & ESMC_RXING) == 0) /* RX in task */
  355. {
  356. sc->flags |= ESMC_RXING;
  357. (void) netJobAdd ((FUNCPTR)esmcGet, unit, 0, 0, 0, 0);
  358. }
  359.     }
  360. if (status & ESMC_INT_TX) /* TX error */
  361.     {
  362.             sc->es_if.if_oerrors++;
  363.             sc->es_if.if_opackets--;
  364.             sc->intTx++;
  365.          pointerSave = sysInWord (ioaddr + ESMC_PTR); /* save pointer */
  366.     packetSave  = sysInByte (ioaddr + ESMC_PNR); /* save packet */
  367.     packetFail  = sysInWord (ioaddr + ESMC_FIFO) & 0x7f;
  368.     sysOutByte (ioaddr + ESMC_PNR, packetFail);
  369.     sysOutWord (ioaddr + ESMC_PTR, ESMC_PTR_AUTOINC | ESMC_PTR_READ);
  370.     statusTx = sysInWord (ioaddr + ESMC_DATA_1);
  371.     if (statusTx & ESMC_TS_LOST_CARR)
  372. sc->lostCarr++;
  373.     if (statusTx & ESMC_TS_LATCOL)
  374. sc->es_if.if_collisions++;
  375.     
  376.     sysOutWord (ioaddr + ESMC_MMU, ESMC_MMU_TX_RELEASE); /* release */
  377.     sysOutByte (ioaddr + ESMC_INT_ACK, ESMC_INT_TX);  /* int ack */
  378.     ESMC_SWITCH_BANK (0);
  379.     sysOutWord (ioaddr + ESMC_TCR, 
  380. sysInWord (ioaddr + ESMC_TCR) | ESMC_TCR_TXEN);
  381.     ESMC_SWITCH_BANK (2);
  382.     sysOutByte (ioaddr + ESMC_PNR, packetSave);  /* restore packet */
  383.             sysOutWord (ioaddr + ESMC_PTR, pointerSave); /* restore pointer */
  384.     }
  385. if (status & ESMC_INT_TX_EMPTY) /* TX done */
  386.     {
  387.             sc->intTxempty++;
  388.     sysOutByte (ioaddr + ESMC_INT_ACK, ESMC_INT_TX_EMPTY); /* int ack */
  389.     ESMC_SWITCH_BANK (0);
  390.     statusCard = sysInWord (ioaddr + ESMC_COUNTER);
  391.          ESMC_SWITCH_BANK (2);
  392.     sc->es_if.if_collisions += statusCard & 0x0f;
  393.     statusCard >>= 4;
  394.     sc->es_if.if_collisions += statusCard & 0x0f;
  395.     mask &= ~ESMC_INT_TX_EMPTY;
  396.     if (sc->es_if.if_snd.ifq_head != NULL)
  397. #ifdef BSD43_DRIVER
  398. (void) netJobAdd ((FUNCPTR)esmcPut, unit, 0, 0, 0, 0);
  399. #else
  400. (void) netJobAdd ((FUNCPTR)esmcPut, (int)sc, 0, 0, 0, 0);
  401. #endif
  402.     }
  403. if (status & ESMC_INT_ALLOC) /* ALLOC done */
  404.     {
  405.             sc->intAlloc++;
  406.     mask &= ~ESMC_INT_ALLOC;
  407.     semGive (&sc->esmcSyncSem);
  408.     }
  409. if (status & ESMC_INT_RX_OVRN) /* RX over run */
  410.     {
  411.             sc->es_if.if_ierrors++;
  412.             sc->intOverrun++;
  413.             sysOutByte (ioaddr + ESMC_INT_ACK, ESMC_INT_RX_OVRN); /* int ack */
  414.     if (sc->mode == RX_MODE_INTERRUPT) /* RX in int */
  415. {
  416. esmcGetInt (unit);
  417.         if ((sc->flags & ESMC_RXING) == 0)
  418.     {
  419.     sc->flags |= ESMC_RXING;
  420.     (void) netJobAdd ((FUNCPTR)esmcGetTask, unit, 0, 0, 0, 0);
  421.     }
  422. }
  423.     else if ((sc->flags & ESMC_RXING) == 0) /* RX in task */
  424. {
  425. sc->flags |= ESMC_RXING;
  426. (void) netJobAdd ((FUNCPTR)esmcGet, unit, 0, 0, 0, 0);
  427. }
  428.     }
  429. if (status & ESMC_INT_EPH) /* EPH */
  430.             sc->intEph++;
  431. if (status & ESMC_INT_ERCV) /* early receive */
  432.             sc->intErcv++;
  433. }
  434.     
  435.     sysOutByte (ioaddr + ESMC_INT_MASK, mask); /* restore the mask */
  436.     ESMC_SWITCH_BANK (bank); /* restore the bank */
  437.     return;
  438.     }
  439. /*******************************************************************************
  440. *
  441. * esmcGet - read a packet off the interface(Task Level: netTask)
  442. *
  443. * Copy packets from a RING into an mbuf and hand it to the next higher layer.
  444. *
  445. * RETURNS: N/A
  446. */
  447. LOCAL void esmcGet 
  448.     (
  449.     int unit
  450.     )
  451.     {
  452.     FAST ESMC_SOFTC *sc = &esmc_softc[unit];
  453.     FAST int ioaddr     = sc->ioAddr;
  454.     FAST struct ether_header *eh;
  455.     FAST struct mbuf *m;
  456.     int off;
  457.     int len;
  458.     u_short packetNo;
  459.     u_short statusRx;
  460.     u_char * pData;
  461.     u_char mask;
  462.     ESMC_SWITCH_BANK (2);
  463.     mask = sysInByte (ioaddr + ESMC_INT_MASK); /* save mask */
  464. unlucky:
  465.     while (((packetNo = sysInWord (ioaddr + ESMC_FIFO)) & ESMC_FP_RXEMPTY) == 0)
  466. {
  467.         sysOutByte (ioaddr + ESMC_INT_MASK, 0); /* lock INT */
  468. sysOutWord (ioaddr + ESMC_PTR, 
  469.     ESMC_PTR_READ | ESMC_PTR_RCV | ESMC_PTR_AUTOINC);
  470. statusRx = sysInWord (ioaddr + ESMC_DATA_1); /* status */
  471. len  = sysInWord (ioaddr + ESMC_DATA_1); /* byte count */
  472. len  = (len & 0x07ff) - 6; /* subtract extra */
  473. if (statusRx & ESMC_RS_ERROR_MASK)
  474.     {
  475.     ++sc->es_if.if_ierrors;
  476.     while (sysInWord (ioaddr + ESMC_MMU) & 0x0001) /* check busy bit */
  477. ;
  478.     sysOutWord (ioaddr + ESMC_MMU, ESMC_MMU_RX_RELEASE); /* release */
  479.             sysOutByte (ioaddr + ESMC_INT_MASK, mask); /* unlock INT */
  480.     }
  481. else
  482.     {
  483. #if ESMC_USE_LONG
  484.     sysInLongString (ioaddr + ESMC_DATA_1, (long *)sc->pBuft, len >> 2);
  485.     if (len & 0x02)
  486.         *(short *)&sc->pBuft[len & ~0x03] = 
  487.                               sysInWord (ioaddr + ESMC_DATA_1);
  488.     *(short *)&sc->pBuft[len & ~0x01] = 
  489.                               sysInWord (ioaddr + ESMC_DATA_1);
  490. #else
  491.     sysInWordString (ioaddr + ESMC_DATA_1, (short *)sc->pBuft,
  492.              (len>>1) + 1);
  493. #endif /* ESMC_USE_LONG */
  494.     if (statusRx & ESMC_RS_ODDFRM)
  495. len++;
  496.     while (sysInWord (ioaddr + ESMC_MMU) & 0x0001) /* check busy bit */
  497. ;
  498.     sysOutWord (ioaddr + ESMC_MMU, ESMC_MMU_RX_RELEASE); /* release */
  499.             sysOutByte (ioaddr + ESMC_INT_MASK, mask); /* unlock INT */
  500. #ifdef ESMC_DEBUG
  501.     {
  502.     int ix;
  503.     int iy;
  504.     printf ("packet=0x%x, status=0x%x, len=%dn", 
  505.     (packetNo >> 8) & 0x1f, statusRx, len);
  506.     for (iy = 0; iy < 8; iy++)
  507.         {
  508.                 for (ix = 0; ix < 16; ix++)
  509.             printf ("%2.2x ", (u_char)sc->pBuft[iy * 16 + ix]);
  510.         printf ("n");
  511.         }
  512.     }
  513. #endif /* ESMC_DEBUG */
  514.             sc->es_if.if_ipackets++;        /* bump statistic */
  515.     eh = (struct ether_header *)(sc->pBuft);
  516.             /* call input hook if any */
  517.             if ((etherInputHookRtn != NULL) &&
  518.         (* etherInputHookRtn) (&sc->es_if, (char *) eh, len))
  519.         {
  520.         continue;
  521.         }
  522.             if (len >= SIZEOF_ETHERHEADER)
  523.                 len -= SIZEOF_ETHERHEADER;
  524.             else
  525.                 {
  526.                 sc->es_if.if_ierrors++;         /* bump error statistic */
  527.         continue;
  528.                 }
  529.             pData = ((unsigned char *) eh) + SIZEOF_ETHERHEADER;
  530. #ifdef BSD43_DRIVER
  531.             check_trailer (eh, pData, &len, &off, &sc->es_if);
  532.             /* copy data from the ring buffer to mbuf a long-word at a time */
  533.             m = bcopy_to_mbufs (pData, len, off, (struct ifnet *)&sc->es_if, 2);
  534.             if (m == NULL)
  535.                 {
  536.                 sc->es_if.if_ierrors++;        /* bump error statistic */
  537.         continue;
  538.                 }
  539.             do_protocol_with_type (eh->ether_type, m, &sc->es_ac, len);
  540. #else
  541.             /* copy data from the ring buffer to mbuf */
  542.             m = bcopy_to_mbufs (pData, len, off, (struct ifnet *)&sc->es_if, 2);
  543.             if (m == NULL)
  544.                 {
  545.                 sc->es_if.if_ierrors++;        /* bump error statistic */
  546.         continue;
  547.                 }
  548.             do_protocol (eh, m, &sc->es_ac, len);
  549. #endif
  550.     }
  551.         }
  552.     sc->flags &= ~ESMC_RXING;
  553.     /* go back if we got an interrupt and a new packet */
  554.     if ((sysInByte (ioaddr + ESMC_INT_STAT) & (ESMC_INT_RCV | ESMC_INT_RX_OVRN))
  555.  || (((sysInWord (ioaddr + ESMC_FIFO)) & ESMC_FP_RXEMPTY) == 0))
  556. goto unlucky;
  557.     }
  558. /*******************************************************************************
  559. *
  560. * esmcGetInt - read a packet off the interface(Interrupt Level)
  561. *
  562. * Copy packets from a RING into an mbuf and hand it to the next higher layer.
  563. *
  564. * RETURNS: N/A
  565. */
  566. LOCAL void esmcGetInt 
  567.     (
  568.     int unit
  569.     )
  570.     {
  571.     FAST ESMC_SOFTC *sc = &esmc_softc[unit];
  572.     FAST int ioaddr     = sc->ioAddr;
  573.     int len;
  574.     int bufLen;
  575.     u_short statusRx;
  576.     u_short packetNo;
  577.     if ((sc->pIn > sc->pOut) && ((sc->pEnd - sc->pIn) < ESMC_BUFSIZE))
  578. sc->pIn = sc->pStart;
  579.     if (((sc->pOut > sc->pIn) && ((sc->pOut - sc->pIn) < ESMC_BUFSIZE)) ||
  580.         (sc->packetLen[sc->indexIn] != 0))
  581. return;
  582.     while (((packetNo = sysInWord (ioaddr + ESMC_FIFO)) & ESMC_FP_RXEMPTY) == 0)
  583. {
  584. sysOutWord (ioaddr + ESMC_PTR, 
  585.     ESMC_PTR_READ | ESMC_PTR_RCV | ESMC_PTR_AUTOINC);
  586. statusRx = sysInWord (ioaddr + ESMC_DATA_1); /* status */
  587. len  = sysInWord (ioaddr + ESMC_DATA_1); /* byte count */
  588. len  = (len & 0x07ff) - 6; /* subtract extra */
  589. if (statusRx & ESMC_RS_ERROR_MASK)
  590.     {
  591.     ++sc->es_if.if_ierrors;
  592.     while (sysInWord (ioaddr + ESMC_MMU) & 0x0001) /* check busy bit */
  593. ;
  594.     sysOutWord (ioaddr + ESMC_MMU, ESMC_MMU_RX_RELEASE); /* release */
  595.     }
  596. else
  597.     {
  598. #if ESMC_USE_LONG
  599.     sysInLongString (ioaddr + ESMC_DATA_1, (long *)sc->pIn, len >> 2);
  600.     if (len & 0x02)
  601.         *(short *)&sc->pIn[len & ~0x03] = 
  602.       sysInWord (ioaddr + ESMC_DATA_1);
  603.     *(short *)&sc->pIn[len & ~0x01] = sysInWord (ioaddr + ESMC_DATA_1);
  604. #else
  605.     sysInWordString (ioaddr + ESMC_DATA_1, (short *)sc->pIn, 
  606.      (len>>1) + 1);
  607. #endif /* ESMC_USE_LONG */
  608.     if (statusRx & ESMC_RS_ODDFRM)
  609. len++;
  610.     while (sysInWord (ioaddr + ESMC_MMU) & 0x0001) /* check busy bit */
  611. ;
  612.     sysOutWord (ioaddr + ESMC_MMU, ESMC_MMU_RX_RELEASE); /* release */
  613.     if (len & 0x01) /* buffer length */
  614. bufLen = len + 1;
  615.     else
  616. bufLen = len + 2;
  617.     sc->packetAddr[sc->indexIn] = sc->pIn; /* packet address */
  618.     sc->packetLen[sc->indexIn] = len; /* packet length */
  619.     sc->pIn += bufLen; /* increment */
  620.     sc->indexIn = (sc->indexIn + 1) % sc->nIndex;
  621.             if ((sc->pIn > sc->pOut) && ((sc->pEnd - sc->pIn) < ESMC_BUFSIZE))
  622.         sc->pIn = sc->pStart; /* wrap around */
  623.             if (((sc->pOut > sc->pIn) && ((sc->pOut - sc->pIn) < ESMC_BUFSIZE))
  624. || (sc->packetLen[sc->indexIn] != 0)) /* no space */
  625.         break;
  626.     }
  627.         }
  628.     }
  629. /*******************************************************************************
  630. *
  631. * esmcGetTask - read a packet off the interface(Task Level)
  632. *
  633. * Copy packets from a RING into an mbuf and hand it to the next higher layer.
  634. *
  635. * RETURNS: N/A
  636. */
  637. LOCAL void esmcGetTask 
  638.     (
  639.     int unit
  640.     )
  641.     {
  642.     FAST ESMC_SOFTC *sc = &esmc_softc[unit];
  643.     FAST struct ether_header *eh;
  644.     FAST struct mbuf *m;
  645.     int off;
  646.     int len;
  647.     int bufLen;
  648.     u_char * pData;
  649.     while ((len = sc->packetLen[sc->indexOut]) != 0)
  650. {
  651. eh = (struct ether_header *)(sc->packetAddr[sc->indexOut]);
  652.         sc->es_if.if_ipackets++;        /* bump statistic */
  653.         /* call input hook if any */
  654.         if ((etherInputHookRtn != NULL) &&
  655.     (* etherInputHookRtn) (&sc->es_if, (char *) eh, len))
  656.     continue;
  657.         if (len >= SIZEOF_ETHERHEADER)
  658.             len -= SIZEOF_ETHERHEADER;
  659.         else
  660.             {
  661.             sc->es_if.if_ierrors++;         /* bump error statistic */
  662.     continue;
  663.             }
  664.         pData = ((unsigned char *) eh) + SIZEOF_ETHERHEADER;
  665. #ifdef BSD43_DRIVER
  666.         check_trailer (eh, pData, &len, &off, &sc->es_if);
  667.         /* copy data from the ring buffer to mbuf a long-word at a time */
  668.         m = bcopy_to_mbufs (pData, len, off, (struct ifnet *)&sc->es_if, 2);
  669.         if (m == NULL)
  670.             {
  671.             sc->es_if.if_ierrors++;         /* bump error statistic */
  672.     continue;
  673.             }
  674.         do_protocol_with_type (eh->ether_type, m, &sc->es_ac, len);
  675. #else
  676.         /* copy data from the ring buffer to mbuf */
  677.         m = bcopy_to_mbufs (pData, len, off, (struct ifnet *)&sc->es_if, 2);
  678.         if (m == NULL)
  679.             {
  680.             sc->es_if.if_ierrors++;         /* bump error statistic */
  681.     continue;
  682.             }
  683.         do_protocol (eh, m, &sc->es_ac, len);
  684. #endif
  685. if (len & 0x01) /* buffer length */
  686.     bufLen = len + 1;
  687. else
  688.     bufLen = len + 2;
  689. sc->pOut = sc->packetAddr[sc->indexOut] + bufLen;
  690. sc->packetLen[sc->indexOut] = 0; /* mark it empty */
  691. sc->indexOut = (sc->indexOut + 1) % sc->nIndex; /* increment */
  692. }
  693.     sc->flags &= ~ESMC_RXING;
  694.     }
  695. /*******************************************************************************
  696. *
  697. * esmcPut - copy a packet to the interface.
  698. *
  699. * Copy from mbuf chain to transmitter buffer in shared memory.
  700. *
  701. * RETURNS: N/A
  702. */
  703. #ifdef BSD43_DRIVER
  704. LOCAL void esmcPut 
  705.     (
  706.     int unit
  707.     )
  708.     {
  709.     FAST ESMC_SOFTC *sc = &esmc_softc [unit];
  710. #else
  711. LOCAL void esmcPut 
  712.     (
  713.     ESMC_SOFTC *sc
  714.     )
  715.     {
  716. #endif
  717.     FAST int ioaddr     = sc->ioAddr;
  718.     FAST struct mbuf *m;
  719.     int timeout         = ESMC_ALLOC_TIMEOUT;
  720.     int len;
  721.     int pages;
  722.     u_char mask;
  723.     u_char packetNo;
  724.     int s = splnet ();
  725.     if (sc->es_if.if_snd.ifq_head != NULL)
  726. {
  727. IF_DEQUEUE (&sc->es_if.if_snd, m);
  728. copy_from_mbufs (sc->pBuft, m, len);
  729. len = max (ETHERSMALL, len);
  730. /* call output hook if any */
  731. if ((etherOutputHookRtn != NULL) &&
  732.     (* etherOutputHookRtn) (&sc->es_if, sc->pBuft, len))
  733.     {
  734.     goto donePut;
  735.     }
  736. #ifndef BSD43_DRIVER
  737.         sc->es_if.if_opackets++;        /* bump statistic. */
  738. #endif
  739. /* allocate transmit memory and transmit */
  740. pages = len / 256;
  741. ESMC_SWITCH_BANK (2);
  742. mask = sysInByte (ioaddr + ESMC_INT_MASK); /* save mask */
  743. sysOutWord (ioaddr + ESMC_MMU, ESMC_MMU_ALLOC | pages); /* alloc mem */
  744. while (((sysInByte (ioaddr + ESMC_INT_STAT) & ESMC_INT_ALLOC) == 0) &&
  745.        (--timeout))
  746.     ;
  747. if (timeout == 0) /* take sem & wait */
  748.     {
  749.     sysOutByte (ioaddr + ESMC_INT_MASK, mask | ESMC_INT_ALLOC);
  750.     if (semTake (&sc->esmcSyncSem, sysClkRateGet () >> 2) == ERROR)
  751. {
  752.         sc->allocTimeout++;
  753.         goto donePut;
  754.         }
  755.     }
  756. if ((packetNo = sysInByte (ioaddr + ESMC_ARR)) & 0x80) /* check it */
  757.     {
  758.     sc->allocFailed++;
  759.     goto donePut;
  760.     }
  761. #ifdef ESMC_DEBUG
  762. {
  763. int ix;
  764. int iy;
  765. printf ("pages=0x%x, packetNo=0x%x, len=%dn", pages, packetNo, len);
  766. for (iy = 0; iy < 8; iy++)
  767.     {
  768.             for (ix = 0; ix < 16; ix++)
  769.         printf ("%2.2x ", (u_char)sc->pBuft[iy * 16 + ix]);
  770.     printf ("n");
  771.     }
  772. }
  773. #endif /* ESMC_DEBUG */
  774. sysOutByte (ioaddr + ESMC_INT_MASK, 0); /* lock INT */
  775. sysOutByte (ioaddr + ESMC_PNR, packetNo); /* set the tx packet */
  776. sysOutWord (ioaddr + ESMC_PTR, ESMC_PTR_AUTOINC); /* set the pointer */
  777. #if ESMC_USE_LONG
  778. sysOutLong (ioaddr + ESMC_DATA_1, (len + 6) << 16); /* status, count */
  779. sysOutLongString (ioaddr + ESMC_DATA_1, (long *)sc->pBuft, len >> 2);
  780. if (len & 0x02)
  781.     sysOutWord (ioaddr + ESMC_DATA_1, *(short *)&sc->pBuft[len & ~0x03]);
  782. #else
  783. sysOutWord (ioaddr + ESMC_DATA_1, 0); /* status */
  784. sysOutWord (ioaddr + ESMC_DATA_1, (len + 6)); /* byte count */
  785. sysOutWordString (ioaddr + ESMC_DATA_1, (short *)sc->pBuft, len >> 1);
  786. #endif /* ESMC_USE_LONG */
  787. if (len & 0x01) /* odd byte count */
  788.     {
  789.     sysOutByte (ioaddr + ESMC_DATA_1, sc->pBuft[len - 1]);
  790.     sysOutByte (ioaddr + ESMC_DATA_1, 0x20);
  791.     }
  792. else /* even byte count */
  793.     sysOutWord (ioaddr + ESMC_DATA_1, 0);
  794. sysOutWord (ioaddr + ESMC_MMU, ESMC_MMU_ENQUEUE); /* send it */
  795. sysOutByte (ioaddr + ESMC_INT_MASK, 
  796.     mask | ESMC_INT_TX | ESMC_INT_TX_EMPTY);
  797. }
  798. donePut:
  799.     splx (s);
  800.     }
  801. /*******************************************************************************
  802. *
  803. * esmcChipInit - initialize SMC91c9x chip
  804. *
  805. * RETURNS: N/A
  806. */
  807. LOCAL STATUS esmcChipInit 
  808.     (
  809.     int unit
  810.     )
  811.     {
  812.     FAST ESMC_SOFTC *sc = &esmc_softc[unit];
  813.     FAST int ioaddr     = sc->ioAddr;
  814.     int memSize;
  815.     int ix;
  816.     u_short bank;
  817.     u_short config;
  818.     u_short addr;
  819.     u_short memInfo;
  820.     u_short memConfig;
  821.     char revision;
  822.     char * pRevision;
  823.     sysOutWord (ioaddr + ESMC_BANK_SELECT, 0x00);
  824.     bank = sysInWord (ioaddr + ESMC_BANK_SELECT);
  825.     if ((bank & 0xff00) != 0x3300)
  826. {
  827. #ifdef ESMC_DEBUG
  828.         printf ("esmc: error - bank select 0x%xn", bank & 0xff00);
  829. #endif
  830. return (ERROR);
  831.         }
  832.     ESMC_SWITCH_BANK (1);
  833.     addr = sysInWord (ioaddr + ESMC_BASE);
  834.     if (ioaddr != ((addr >> 3) & 0x3e0))
  835. {
  836. #ifdef ESMC_DEBUG
  837.         printf ("esmc: error - ioaddr=0x%xn", (addr >> 3) & 0x3e0);
  838. #endif
  839. return (ERROR);
  840.         }
  841.     
  842.     ESMC_SWITCH_BANK (3);
  843.     revision = sysInByte (ioaddr + ESMC_REVISION);
  844.     if ((pRevision = pName[(revision >> 4) & 0x0f]) == NULL)
  845. {
  846. #ifdef ESMC_DEBUG
  847.         printf ("esmc: error - revision=0x%xn", (revision >> 4) & 0x0f);
  848. #endif
  849. return (ERROR);
  850.         }
  851.     
  852.     ESMC_SWITCH_BANK (0);
  853.     memInfo = sysInWord (ioaddr + ESMC_MIR);
  854.     memConfig = sysInWord (ioaddr + ESMC_MCR);
  855.     memSize = (memConfig >> 9) & 0x07;
  856.     memSize *= (memInfo & 0xff) * 256;
  857.     esmcChipReset (unit); /* reset the chip */
  858.     ESMC_SWITCH_BANK (1);
  859.     config = sysInWord (ioaddr + ESMC_CONFIG);
  860.     if (sc->config == ATTACHMENT_DEFAULT) /* EEPROM */
  861. {
  862. if (config & ESMC_CFG_AUI_SELECT) /* EEPROM - AUI */
  863.     sc->config = ATTACHMENT_AUI;
  864. else /* EEPROM - RJ45 */
  865.     {
  866.     sc->config = ATTACHMENT_RJ45;
  867.     sysOutByte (ioaddr + ESMC_CONFIG, config);
  868.     }
  869. }
  870.     else if (sc->config == ATTACHMENT_AUI) /* AUI */
  871. sysOutByte (ioaddr + ESMC_CONFIG, config | ESMC_CFG_AUI_SELECT);
  872.     else if (sc->config == ATTACHMENT_RJ45) /* RJ45 */
  873. sysOutByte (ioaddr + ESMC_CONFIG, config & ~ESMC_CFG_AUI_SELECT);
  874.     
  875.     for (ix = 0; ix < 6; ix++) /* ethernet addres */
  876. sc->es_enaddr[ix] = sysInByte (ioaddr + ESMC_ADDR_0 + ix);
  877.     
  878.     ESMC_SWITCH_BANK (0);
  879.     sysOutWord (ioaddr + ESMC_MCR, 0x0006);   /* 1532 bytes */ 
  880.     sysOutWord (ioaddr + ESMC_TCR, ESMC_TCR_PAD | ESMC_TCR_TXEN); /* TXenable */
  881.     sysOutWord (ioaddr + ESMC_RCR, ESMC_RCR_RXEN); /* RX enable */
  882.     ESMC_SWITCH_BANK (2); /* int enable */
  883.     sysOutByte (ioaddr + ESMC_INT_MASK, ESMC_INT_RX_OVRN | ESMC_INT_RCV); 
  884. #if ESMC_DEBUG
  885.     printf ("ESMC: %s(rev=%d) at %#3x IRQ=%d IF=%s MEM=%d ",
  886.     pRevision, revision & 0x0f, ioaddr, sc->intLevel,
  887.     (sc->config == 1)? "TP" : "AUI", memSize);
  888.     printf ("(");
  889.     for (ix = 0; ix < 5; ix++)
  890. printf ("%2.2x:", (u_char)sc->es_enaddr[ix]);
  891.     printf ("%2.2x)n", (u_char)sc->es_enaddr[ix]);
  892. #endif /* ESMC_DEBUG */
  893.     return (OK);
  894.     }
  895. /*******************************************************************************
  896. *
  897. * esmcChipReset - reset SMC91c9x chip
  898. *
  899. * RETURNS: N/A
  900. */
  901. LOCAL void esmcChipReset 
  902.     (
  903.     int unit
  904.     )
  905.     {
  906.     FAST ESMC_SOFTC *sc = &esmc_softc[unit];
  907.     FAST int ioaddr     = sc->ioAddr;
  908.     ESMC_SWITCH_BANK (2);
  909.     sysOutByte (ioaddr + ESMC_INT_MASK, 0); /* lock INT */
  910.     ESMC_SWITCH_BANK (0);
  911.     sysOutWord (ioaddr + ESMC_RCR, ESMC_RCR_EPH_RST); /* software reset */
  912.     taskDelay (sysClkRateGet () >> 3);
  913.     sysOutWord (ioaddr + ESMC_RCR, 0x0000); /* RX disable */
  914.     sysOutWord (ioaddr + ESMC_TCR, 0x0000); /* TX disable */
  915.     ESMC_SWITCH_BANK (1);
  916.     sysOutWord (ioaddr + ESMC_CONTROL,  /* TX auto release */
  917. sysInWord (ioaddr + ESMC_CONTROL) | ESMC_CTL_AUTO_RELEASE);
  918.     ESMC_SWITCH_BANK (2);
  919.     sysOutWord (ioaddr + ESMC_MMU, ESMC_MMU_RESET); /* MMU reset */
  920.     taskDelay (sysClkRateGet () >> 3);
  921.     }
  922. #if ESMC_SHOW
  923. /*******************************************************************************
  924. *
  925. * esmcShow - display statistics for the `esmc' network interface
  926. *
  927. * This routine displays statistics about the `esmc' Ethernet network interface.
  928. * It has two parameters:
  929. * .iP <unit>
  930. * interface unit; should be 0.
  931. * .iP <zap>
  932. * if 1, all collected statistics are cleared to zero.
  933. * .LP
  934. *
  935. * RETURNS: N/A
  936. */
  937. void esmcShow 
  938.     (
  939.     int unit,   /* interface unit */
  940.     BOOL zap    /* zero totals */
  941.     )
  942.     {
  943.     FAST ESMC_SOFTC *sc = &esmc_softc[unit];
  944.     FAST int ioaddr     = sc->ioAddr;
  945.     FAST u_int * pUint  = &sc->interrupt;
  946.     FAST int ix;
  947.     u_short bank;
  948.     u_char mask;
  949.     static char *pMessage [] =
  950. {
  951. "interrupt",
  952. "interrupt rcv",
  953. "interrupt tx",
  954. "interrupt txempty",
  955. "interrupt alloc",
  956. "interrupt overrun",
  957. "interrupt eph",
  958. "interrupt ercv",
  959. "lost carr",
  960. "alloc timeout",
  961. "alloc failed",
  962. };
  963.     printf ("esmc: ioAddr=0x%x intLevel=0x%xn", sc->ioAddr, sc->intLevel);
  964.     for (ix = 0; ix < NELEMENTS(pMessage); ix++)
  965. {
  966. printf ("    %-30.30s  %4dn", pMessage[ix], pUint[ix]);
  967. if (zap)
  968.     pUint[ix] = 0;
  969. }
  970.     printf ("    %-30.30s  0x%2xn", "flags", sc->flags);
  971.     bank = sysInWord (ioaddr + ESMC_BANK_SELECT);
  972.     ESMC_SWITCH_BANK (2);
  973.     mask = sysInByte (ioaddr + ESMC_INT_MASK);
  974.     sysOutByte (ioaddr + ESMC_INT_MASK, 0); /* lock INT */
  975.     ESMC_SWITCH_BANK (0);
  976.     printf ("bank0-TCR:        0x%xn", sysInWord (ioaddr + ESMC_TCR));
  977.     printf ("bank0-EPH:        0x%xn", sysInWord (ioaddr + ESMC_EPH));
  978.     printf ("bank0-RCR:        0x%xn", sysInWord (ioaddr + ESMC_RCR));
  979.     printf ("bank0-COUNTER:    0x%xn", sysInWord (ioaddr + ESMC_COUNTER));
  980.     printf ("bank0-MIR:        0x%xn", sysInWord (ioaddr + ESMC_MIR));
  981.     printf ("bank0-MCR:        0x%xn", sysInWord (ioaddr + ESMC_MCR));
  982.     ESMC_SWITCH_BANK (1);
  983.     printf ("bank1-CONFIG:     0x%xn", sysInWord (ioaddr + ESMC_CONFIG));
  984.     printf ("bank1-CONTROL:    0x%xn", sysInWord (ioaddr + ESMC_CONTROL));
  985.     ESMC_SWITCH_BANK (2);
  986.     printf ("bank2-MMU:        0x%xn", sysInWord (ioaddr + ESMC_MMU));
  987.     printf ("bank2-PNR:        0x%xn", sysInByte (ioaddr + ESMC_PNR));
  988.     printf ("bank2-ARR:        0x%xn", sysInByte (ioaddr + ESMC_ARR));
  989.     printf ("bank2-FIFO:       0x%xn", sysInWord (ioaddr + ESMC_FIFO));
  990.     printf ("bank2-PTR:        0x%xn", sysInWord (ioaddr + ESMC_PTR));
  991.     printf ("bank2-INT_STAT:   0x%xn", sysInByte (ioaddr + ESMC_INT_STAT));
  992.     printf ("bank2-INT_MASK:   0x%xn", mask);
  993.     ESMC_SWITCH_BANK (3);
  994.     printf ("bank3-MGMT:       0x%xn", sysInWord (ioaddr + ESMC_MGMT));
  995.     printf ("bank3-REVISION:   0x%xn", sysInWord (ioaddr + ESMC_REVISION));
  996.     printf ("bank3-ERCV:       0x%xn", sysInWord (ioaddr + ESMC_ERCV));
  997.     ESMC_SWITCH_BANK (bank);
  998.     sysOutByte (ioaddr + ESMC_INT_MASK, mask); /* unlock INT */
  999.     }
  1000. #endif /* ESMC_SHOW */