The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/vx/if_vx.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. All advertising materials mentioning features or use of this software
   14  *    must display the following acknowledgement:
   15  *      This product includes software developed by Herb Peyerl.
   16  * 4. The name of Herb Peyerl may not be used to endorse or promote products
   17  *    derived from this software without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   29  *
   30  * $FreeBSD$
   31  *
   32  */
   33 
   34 /*
   35  * Created from if_ep.c driver by Fred Gray (fgray@rice.edu) to support
   36  * the 3c590 family.
   37  */
   38 
   39 /*
   40  *      Modified from the FreeBSD 1.1.5.1 version by:
   41  *                      Andres Vega Garcia
   42  *                      INRIA - Sophia Antipolis, France
   43  *                      avega@sophia.inria.fr
   44  */
   45 
   46 /*
   47  *  Promiscuous mode added and interrupt logic slightly changed
   48  *  to reduce the number of adapter failures. Transceiver select
   49  *  logic changed to use value from EEPROM. Autoconfiguration
   50  *  features added.
   51  *  Done by:
   52  *          Serge Babkin
   53  *          Chelindbank (Chelyabinsk, Russia)
   54  *          babkin@hq.icb.chel.su
   55  */
   56 
   57 #include "vx.h"
   58 #if NVX > 0
   59 
   60 #if NVX < 4     /* These cost 4 bytes apiece, so give us 4 */
   61 #undef NVX
   62 #define NVX 4
   63 #endif
   64 
   65 #include "bpfilter.h"
   66 
   67 #include <sys/param.h>
   68 #include <sys/systm.h>
   69 #include <sys/sockio.h>
   70 #include <sys/malloc.h>
   71 #include <sys/mbuf.h>
   72 #include <sys/socket.h>
   73 
   74 #include <net/if.h>
   75 
   76 #include <net/ethernet.h>
   77 #include <net/if_arp.h>
   78 
   79 #if NBPFILTER > 0
   80 #include <net/bpf.h>
   81 #endif
   82 
   83 #include <machine/clock.h>
   84 
   85 #include <dev/vx/if_vxreg.h>
   86 
   87 #define ETHER_MAX_LEN   1518
   88 #define ETHER_ADDR_LEN  6
   89 
   90 struct vx_softc *vx_softc[NVX];
   91 
   92 u_long vx_count;        /* both PCI and EISA */
   93 
   94 static struct connector_entry {
   95   int bit;
   96   char *name;
   97 } conn_tab[VX_CONNECTORS] = {
   98 #define CONNECTOR_UTP   0
   99   { 0x08, "utp"},
  100 #define CONNECTOR_AUI   1
  101   { 0x20, "aui"},
  102 /* dummy */
  103   { 0, "???"},
  104 #define CONNECTOR_BNC   3
  105   { 0x10, "bnc"},
  106 #define CONNECTOR_TX    4
  107   { 0x02, "tx"},
  108 #define CONNECTOR_FX    5
  109   { 0x04, "fx"},
  110 #define CONNECTOR_MII   6
  111   { 0x40, "mii"},
  112   { 0, "???"}
  113 };
  114 
  115 /* struct vx_softc *vxalloc __P((int)); */
  116 /* void *vxfree __P((struct vx_softc *)); */
  117 /* int vxattach __P((struct vx_softc *)); */
  118 static void vxtxstat __P((struct vx_softc *));
  119 static int vxstatus __P((struct vx_softc *));
  120 static void vxinit __P((void *));
  121 static int vxioctl __P((struct ifnet *, u_long, caddr_t)); 
  122 static void vxstart __P((struct ifnet *ifp));
  123 static void vxwatchdog __P((struct ifnet *));
  124 static void vxreset __P((struct vx_softc *));
  125 /* void vxstop __P((struct vx_softc *)); */
  126 static void vxread __P((struct vx_softc *));
  127 static struct mbuf *vxget __P((struct vx_softc *, u_int));
  128 static void vxmbuffill __P((void *));
  129 static void vxmbufempty __P((struct vx_softc *));
  130 static void vxsetfilter __P((struct vx_softc *));
  131 static void vxgetlink __P((struct vx_softc *));
  132 static void vxsetlink __P((struct vx_softc *));
  133 /* int vxbusyeeprom __P((struct vx_softc *)); */
  134 
  135 struct vx_softc *
  136 vxalloc(unit)
  137     int unit;
  138 {
  139     struct vx_softc *sc;
  140 
  141     if (unit >= NVX) {
  142         printf("vx%d: unit number too high.\n", unit);
  143         return NULL;
  144     }
  145 
  146     if (vx_softc[unit]) {
  147         printf("vx%d: already allocated.\n", unit);
  148         return NULL;
  149     }
  150 
  151     sc = malloc(sizeof(struct vx_softc), M_DEVBUF, M_NOWAIT);
  152     if (sc == NULL) {
  153         printf("vx%d: cannot malloc.\n", unit);
  154         return NULL;
  155     }
  156     bzero(sc, sizeof(struct vx_softc));
  157     callout_handle_init(&sc->ch);
  158 
  159     vx_softc[unit] = sc;
  160     sc->unit = unit;
  161     return (sc);    
  162 }
  163 
  164 void
  165 vxfree(sc)
  166     struct vx_softc *sc;
  167 {
  168     vx_softc[sc->unit] = NULL;
  169     free(sc, M_DEVBUF);
  170     return;
  171 }
  172 
  173 int
  174 vxattach(sc)
  175     struct vx_softc *sc;
  176 {
  177     struct ifnet *ifp = &sc->arpcom.ac_if;
  178     int i;
  179 
  180     GO_WINDOW(0);
  181     outw(VX_COMMAND, GLOBAL_RESET);
  182     VX_BUSY_WAIT;
  183 
  184     vxgetlink(sc);
  185 
  186     /*
  187      * Read the station address from the eeprom
  188      */
  189     GO_WINDOW(0);
  190     for (i = 0; i < 3; i++) {
  191         int x;
  192         if (vxbusyeeprom(sc))
  193             return 0;
  194         outw(BASE + VX_W0_EEPROM_COMMAND, EEPROM_CMD_RD
  195              | (EEPROM_OEM_ADDR_0 + i));
  196         if (vxbusyeeprom(sc))
  197             return 0;
  198         x = inw(BASE + VX_W0_EEPROM_DATA);
  199         sc->arpcom.ac_enaddr[(i << 1)] = x >> 8;
  200         sc->arpcom.ac_enaddr[(i << 1) + 1] = x;
  201     }
  202 
  203     printf(" address %6D\n", sc->arpcom.ac_enaddr, ":");
  204 
  205     ifp->if_unit = sc->unit;
  206     ifp->if_name = "vx";
  207     ifp->if_mtu = ETHERMTU;
  208     ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
  209     ifp->if_output = ether_output;
  210     ifp->if_start = vxstart;
  211     ifp->if_ioctl = vxioctl;
  212     ifp->if_init = vxinit;
  213     ifp->if_watchdog = vxwatchdog;
  214     ifp->if_softc = sc;
  215 
  216     if_attach(ifp);
  217     ether_ifattach(ifp);
  218 
  219 #if NBPFILTER > 0
  220     bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
  221 #endif
  222 
  223     sc->tx_start_thresh = 20;   /* probably a good starting point. */
  224 
  225     vxstop(sc);
  226 
  227     return 1;
  228 }
  229 
  230 
  231 
  232 /*
  233  * The order in here seems important. Otherwise we may not receive
  234  * interrupts. ?!
  235  */
  236 static void
  237 vxinit(xsc)
  238         void *xsc;
  239 {
  240     struct vx_softc *sc = (struct vx_softc *) xsc;
  241     struct ifnet *ifp = &sc->arpcom.ac_if;
  242     int i;
  243 
  244     VX_BUSY_WAIT;
  245 
  246     GO_WINDOW(2);
  247 
  248     for (i = 0; i < 6; i++) /* Reload the ether_addr. */
  249         outb(BASE + VX_W2_ADDR_0 + i, sc->arpcom.ac_enaddr[i]);
  250 
  251     outw(BASE + VX_COMMAND, RX_RESET);
  252     VX_BUSY_WAIT;
  253     outw(BASE + VX_COMMAND, TX_RESET);
  254     VX_BUSY_WAIT;
  255 
  256     GO_WINDOW(1);       /* Window 1 is operating window */
  257     for (i = 0; i < 31; i++)
  258         inb(BASE + VX_W1_TX_STATUS);
  259 
  260     outw(BASE + VX_COMMAND,SET_RD_0_MASK | S_CARD_FAILURE |
  261                         S_RX_COMPLETE | S_TX_COMPLETE | S_TX_AVAIL);
  262     outw(BASE + VX_COMMAND,SET_INTR_MASK | S_CARD_FAILURE |
  263                         S_RX_COMPLETE | S_TX_COMPLETE | S_TX_AVAIL);
  264 
  265     /*
  266      * Attempt to get rid of any stray interrupts that occured during
  267      * configuration.  On the i386 this isn't possible because one may
  268      * already be queued.  However, a single stray interrupt is
  269      * unimportant.
  270      */
  271     outw(BASE + VX_COMMAND, ACK_INTR | 0xff);
  272 
  273     vxsetfilter(sc);
  274     vxsetlink(sc);
  275 
  276     outw(BASE + VX_COMMAND, RX_ENABLE);
  277     outw(BASE + VX_COMMAND, TX_ENABLE);
  278 
  279     vxmbuffill((caddr_t) sc);
  280 
  281     /* Interface is now `running', with no output active. */
  282     ifp->if_flags |= IFF_RUNNING;
  283     ifp->if_flags &= ~IFF_OACTIVE;
  284 
  285     /* Attempt to start output, if any. */
  286     vxstart(ifp);
  287 }
  288 
  289 static void
  290 vxsetfilter(sc)
  291     struct vx_softc *sc;
  292 {
  293     register struct ifnet *ifp = &sc->arpcom.ac_if;  
  294     
  295     GO_WINDOW(1);           /* Window 1 is operating window */
  296     outw(BASE + VX_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL | FIL_BRDCST |
  297          FIL_MULTICAST |
  298          ((ifp->if_flags & IFF_PROMISC) ? FIL_PROMISC : 0 ));
  299 }               
  300 
  301 static void            
  302 vxgetlink(sc)
  303     struct vx_softc *sc;
  304 {
  305     int n, k;
  306 
  307     GO_WINDOW(3);
  308     sc->vx_connectors = inw(BASE + VX_W3_RESET_OPT) & 0x7f;
  309     for (n = 0, k = 0; k < VX_CONNECTORS; k++) {
  310       if (sc->vx_connectors & conn_tab[k].bit) {
  311         if (n > 0) {
  312           printf("/");
  313         }
  314         printf(conn_tab[k].name);
  315         n++;
  316       }
  317     }
  318     if (sc->vx_connectors == 0) {
  319         printf("no connectors!");
  320         return;
  321     }
  322     GO_WINDOW(3);
  323     sc->vx_connector = (inl(BASE + VX_W3_INTERNAL_CFG) 
  324                         & INTERNAL_CONNECTOR_MASK) 
  325                         >> INTERNAL_CONNECTOR_BITS;
  326     if (sc->vx_connector & 0x10) {
  327         sc->vx_connector &= 0x0f;
  328         printf("[*%s*]", conn_tab[sc->vx_connector].name);
  329         printf(": disable 'auto select' with DOS util!");
  330     } else {
  331         printf("[*%s*]", conn_tab[sc->vx_connector].name);
  332     }
  333 }
  334 
  335 static void            
  336 vxsetlink(sc)
  337     struct vx_softc *sc;
  338 {       
  339     register struct ifnet *ifp = &sc->arpcom.ac_if;  
  340     int i, j, k;
  341     char *reason, *warning;
  342     static short prev_flags;
  343     static char prev_conn = -1;
  344 
  345     if (prev_conn == -1) {
  346         prev_conn = sc->vx_connector;
  347     }
  348 
  349     /*
  350      * S.B.
  351      *
  352      * Now behavior was slightly changed:
  353      *
  354      * if any of flags link[0-2] is used and its connector is
  355      * physically present the following connectors are used:
  356      *
  357      *   link0 - AUI * highest precedence
  358      *   link1 - BNC
  359      *   link2 - UTP * lowest precedence
  360      *
  361      * If none of them is specified then
  362      * connector specified in the EEPROM is used
  363      * (if present on card or UTP if not).
  364      */
  365 
  366     i = sc->vx_connector;       /* default in EEPROM */
  367     reason = "default";
  368     warning = 0;
  369 
  370     if (ifp->if_flags & IFF_LINK0) {
  371         if (sc->vx_connectors & conn_tab[CONNECTOR_AUI].bit) {
  372             i = CONNECTOR_AUI;
  373             reason = "link0";
  374         } else {
  375             warning = "aui not present! (link0)";
  376         }
  377     } else if (ifp->if_flags & IFF_LINK1) {
  378         if (sc->vx_connectors & conn_tab[CONNECTOR_BNC].bit) {
  379             i = CONNECTOR_BNC;
  380             reason = "link1";
  381         } else {
  382             warning = "bnc not present! (link1)";
  383         }
  384     } else if (ifp->if_flags & IFF_LINK2) {
  385         if (sc->vx_connectors & conn_tab[CONNECTOR_UTP].bit) {
  386             i = CONNECTOR_UTP;
  387             reason = "link2";
  388         } else {
  389             warning = "utp not present! (link2)";
  390         }
  391     } else if ((sc->vx_connectors & conn_tab[sc->vx_connector].bit) == 0) {
  392         warning = "strange connector type in EEPROM.";
  393         reason = "forced";
  394         i = CONNECTOR_UTP;
  395     }
  396 
  397     /* Avoid unnecessary message. */
  398     k = (prev_flags ^ ifp->if_flags) & (IFF_LINK0 | IFF_LINK1 | IFF_LINK2);
  399     if ((k != 0) || (prev_conn != i)) {
  400         if (warning != 0) {
  401             printf("vx%d: warning: %s\n", sc->unit, warning);
  402         }
  403         printf("vx%d: selected %s. (%s)\n",
  404                sc->unit, conn_tab[i].name, reason);
  405     }
  406 
  407     /* Set the selected connector. */
  408     GO_WINDOW(3);
  409     j = inl(BASE + VX_W3_INTERNAL_CFG) & ~INTERNAL_CONNECTOR_MASK;
  410     outl(BASE + VX_W3_INTERNAL_CFG, j | (i <<INTERNAL_CONNECTOR_BITS));
  411 
  412     /* First, disable all. */
  413     outw(BASE + VX_COMMAND, STOP_TRANSCEIVER);
  414     DELAY(800);
  415     GO_WINDOW(4);
  416     outw(BASE + VX_W4_MEDIA_TYPE, 0);
  417 
  418     /* Second, enable the selected one. */
  419     switch(i) {
  420       case CONNECTOR_UTP:
  421         GO_WINDOW(4);
  422         outw(BASE + VX_W4_MEDIA_TYPE, ENABLE_UTP);
  423         break;
  424       case CONNECTOR_BNC:
  425         outw(BASE + VX_COMMAND, START_TRANSCEIVER);
  426         DELAY(800);
  427         break;
  428       case CONNECTOR_TX:
  429       case CONNECTOR_FX:
  430         GO_WINDOW(4);
  431         outw(BASE + VX_W4_MEDIA_TYPE, LINKBEAT_ENABLE);
  432         break;
  433       default:  /* AUI and MII fall here */
  434         break;
  435     }
  436     GO_WINDOW(1); 
  437 
  438     prev_flags = ifp->if_flags;
  439     prev_conn = i;
  440 }
  441 
  442 static void
  443 vxstart(ifp)
  444     struct ifnet *ifp;
  445 {
  446     register struct vx_softc *sc = vx_softc[ifp->if_unit];
  447     register struct mbuf *m, *m0;
  448     int sh, len, pad;
  449 
  450     /* Don't transmit if interface is busy or not running */
  451     if ((sc->arpcom.ac_if.if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING)
  452         return;
  453 
  454 startagain:
  455     /* Sneak a peek at the next packet */
  456     m0 = ifp->if_snd.ifq_head;
  457     if (m0 == 0) {
  458         return;
  459     }
  460     /* We need to use m->m_pkthdr.len, so require the header */
  461      if ((m0->m_flags & M_PKTHDR) == 0)
  462         panic("vxstart: no header mbuf");
  463      len = m0->m_pkthdr.len;
  464 
  465      pad = (4 - len) & 3;
  466 
  467     /*
  468      * The 3c509 automatically pads short packets to minimum ethernet length,
  469      * but we drop packets that are too large. Perhaps we should truncate
  470      * them instead?
  471      */
  472     if (len + pad > ETHER_MAX_LEN) {
  473         /* packet is obviously too large: toss it */
  474         ++ifp->if_oerrors;
  475         IF_DEQUEUE(&ifp->if_snd, m0);
  476         m_freem(m0);
  477         goto readcheck;
  478     }
  479     VX_BUSY_WAIT;
  480     if (inw(BASE + VX_W1_FREE_TX) < len + pad + 4) {
  481         outw(BASE + VX_COMMAND, SET_TX_AVAIL_THRESH | ((len + pad + 4) >> 2));
  482         /* not enough room in FIFO */
  483         if (inw(BASE + VX_W1_FREE_TX) < len + pad + 4) { /* make sure */
  484             ifp->if_flags |= IFF_OACTIVE;
  485             ifp->if_timer = 1;
  486             return;
  487         }
  488     }
  489     outw(BASE + VX_COMMAND, SET_TX_AVAIL_THRESH | (8188 >> 2));
  490     IF_DEQUEUE(&ifp->if_snd, m0);
  491     if (m0 == 0) {              /* not really needed */
  492         return;
  493     }
  494 
  495     VX_BUSY_WAIT;
  496     outw(BASE + VX_COMMAND, SET_TX_START_THRESH |
  497         ((len / 4 + sc->tx_start_thresh) >> 2));
  498 
  499 #if NBPFILTER > 0
  500     if (sc->arpcom.ac_if.if_bpf) {
  501         bpf_mtap(&sc->arpcom.ac_if, m0);
  502     }
  503 #endif
  504 
  505     /*
  506      * Do the output at splhigh() so that an interrupt from another device
  507      * won't cause a FIFO underrun.
  508      */
  509     sh = splhigh();
  510 
  511     outl(BASE + VX_W1_TX_PIO_WR_1, len | TX_INDICATE);
  512 
  513     for (m = m0; m != 0;) {
  514         if (m->m_len > 3)
  515             outsl(BASE + VX_W1_TX_PIO_WR_1, mtod(m, caddr_t), m->m_len / 4);
  516         if (m->m_len & 3)
  517             outsb(BASE + VX_W1_TX_PIO_WR_1,
  518               mtod(m, caddr_t) + (m->m_len & ~3) , m->m_len & 3);
  519         MFREE(m, m0);
  520         m = m0;
  521     }
  522     while (pad--)
  523         outb(BASE + VX_W1_TX_PIO_WR_1, 0);      /* Padding */
  524 
  525     splx(sh);
  526 
  527     ++ifp->if_opackets;
  528     ifp->if_timer = 1;
  529 
  530 readcheck:
  531     if ((inw(BASE + VX_W1_RX_STATUS) & ERR_INCOMPLETE) == 0) {
  532         /* We received a complete packet. */
  533         
  534         if ((inw(BASE + VX_STATUS) & S_INTR_LATCH) == 0) {
  535             /*
  536              * No interrupt, read the packet and continue
  537              * Is  this supposed to happen? Is my motherboard
  538              * completely busted?
  539              */
  540             vxread(sc);
  541         } else
  542             /* Got an interrupt, return so that it gets serviced. */
  543             return;
  544     } else {
  545         /* Check if we are stuck and reset [see XXX comment] */
  546         if (vxstatus(sc)) {
  547             if (ifp->if_flags & IFF_DEBUG)
  548                printf("vx%d: adapter reset\n", ifp->if_unit);
  549             vxreset(sc);
  550         }
  551     }
  552 
  553     goto startagain;
  554 }
  555 
  556 /*
  557  * XXX: The 3c509 card can get in a mode where both the fifo status bit
  558  *      FIFOS_RX_OVERRUN and the status bit ERR_INCOMPLETE are set
  559  *      We detect this situation and we reset the adapter.
  560  *      It happens at times when there is a lot of broadcast traffic
  561  *      on the cable (once in a blue moon).
  562  */
  563 static int
  564 vxstatus(sc)
  565     struct vx_softc *sc;
  566 {
  567     int fifost;
  568 
  569     /*
  570      * Check the FIFO status and act accordingly
  571      */
  572     GO_WINDOW(4);
  573     fifost = inw(BASE + VX_W4_FIFO_DIAG);
  574     GO_WINDOW(1);
  575 
  576     if (fifost & FIFOS_RX_UNDERRUN) {
  577         if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
  578             printf("vx%d: RX underrun\n", sc->unit);
  579         vxreset(sc);
  580         return 0;
  581     }
  582 
  583     if (fifost & FIFOS_RX_STATUS_OVERRUN) {
  584         if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
  585             printf("vx%d: RX Status overrun\n", sc->unit);
  586         return 1;
  587     }
  588 
  589     if (fifost & FIFOS_RX_OVERRUN) {
  590         if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
  591             printf("vx%d: RX overrun\n", sc->unit);
  592         return 1;
  593     }
  594 
  595     if (fifost & FIFOS_TX_OVERRUN) {
  596         if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
  597             printf("vx%d: TX overrun\n", sc->unit);
  598         vxreset(sc);
  599         return 0;
  600     }
  601 
  602     return 0;
  603 }
  604 
  605 static void     
  606 vxtxstat(sc)
  607     struct vx_softc *sc;
  608 {
  609     int i;
  610 
  611     /*
  612     * We need to read+write TX_STATUS until we get a 0 status
  613     * in order to turn off the interrupt flag.
  614     */
  615     while ((i = inb(BASE + VX_W1_TX_STATUS)) & TXS_COMPLETE) {
  616         outb(BASE + VX_W1_TX_STATUS, 0x0);
  617 
  618     if (i & TXS_JABBER) {
  619         ++sc->arpcom.ac_if.if_oerrors;
  620         if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
  621             printf("vx%d: jabber (%x)\n", sc->unit, i);
  622         vxreset(sc);
  623     } else if (i & TXS_UNDERRUN) {
  624         ++sc->arpcom.ac_if.if_oerrors;
  625         if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
  626             printf("vx%d: fifo underrun (%x) @%d\n",
  627                 sc->unit, i, sc->tx_start_thresh);
  628         if (sc->tx_succ_ok < 100)
  629             sc->tx_start_thresh = min(ETHER_MAX_LEN, sc->tx_start_thresh + 20);
  630         sc->tx_succ_ok = 0;
  631         vxreset(sc);
  632     } else if (i & TXS_MAX_COLLISION) {
  633         ++sc->arpcom.ac_if.if_collisions;
  634         outw(BASE + VX_COMMAND, TX_ENABLE);
  635         sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
  636     } else
  637         sc->tx_succ_ok = (sc->tx_succ_ok+1) & 127;
  638     }
  639 }
  640 
  641 void
  642 vxintr(voidsc)
  643     void *voidsc;
  644 {
  645     register short status;
  646     struct vx_softc *sc = voidsc;
  647     struct ifnet *ifp = &sc->arpcom.ac_if;
  648 
  649     for (;;) {
  650         outw(BASE + VX_COMMAND, C_INTR_LATCH);
  651 
  652         status = inw(BASE + VX_STATUS);
  653 
  654         if ((status & (S_TX_COMPLETE | S_TX_AVAIL |
  655                 S_RX_COMPLETE | S_CARD_FAILURE)) == 0)
  656             break;
  657 
  658         /*
  659          * Acknowledge any interrupts.  It's important that we do this
  660          * first, since there would otherwise be a race condition.
  661          * Due to the i386 interrupt queueing, we may get spurious
  662          * interrupts occasionally.
  663          */
  664         outw(BASE + VX_COMMAND, ACK_INTR | status);
  665 
  666         if (status & S_RX_COMPLETE)
  667             vxread(sc);
  668         if (status & S_TX_AVAIL) {
  669             ifp->if_timer = 0;
  670             sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
  671             vxstart(&sc->arpcom.ac_if);
  672         }
  673         if (status & S_CARD_FAILURE) {
  674             printf("vx%d: adapter failure (%x)\n", sc->unit, status);
  675             ifp->if_timer = 0;
  676             vxreset(sc);
  677             return;
  678         }
  679         if (status & S_TX_COMPLETE) {
  680             ifp->if_timer = 0;
  681             vxtxstat(sc);
  682             vxstart(ifp);
  683         }
  684     }
  685 
  686     /* no more interrupts */
  687     return;
  688 }
  689 
  690 static void
  691 vxread(sc)
  692     struct vx_softc *sc;
  693 {
  694     struct ifnet *ifp = &sc->arpcom.ac_if;
  695     struct mbuf *m;
  696     struct ether_header *eh;
  697     u_int len;
  698 
  699     len = inw(BASE + VX_W1_RX_STATUS);
  700 
  701 again:
  702 
  703     if (ifp->if_flags & IFF_DEBUG) {
  704         int err = len & ERR_MASK;
  705         char *s = NULL;
  706 
  707         if (len & ERR_INCOMPLETE)
  708             s = "incomplete packet";
  709         else if (err == ERR_OVERRUN)
  710             s = "packet overrun";
  711         else if (err == ERR_RUNT)
  712             s = "runt packet";
  713         else if (err == ERR_ALIGNMENT)
  714             s = "bad alignment";
  715         else if (err == ERR_CRC)
  716             s = "bad crc";
  717         else if (err == ERR_OVERSIZE)
  718             s = "oversized packet";
  719         else if (err == ERR_DRIBBLE)
  720             s = "dribble bits";
  721 
  722         if (s)
  723         printf("vx%d: %s\n", sc->unit, s);
  724     }
  725 
  726     if (len & ERR_INCOMPLETE)
  727         return;
  728 
  729     if (len & ERR_RX) {
  730         ++ifp->if_ierrors;
  731         goto abort;
  732     }
  733 
  734     len &= RX_BYTES_MASK;       /* Lower 11 bits = RX bytes. */
  735 
  736     /* Pull packet off interface. */
  737     m = vxget(sc, len);
  738     if (m == 0) {
  739         ifp->if_ierrors++;
  740         goto abort;
  741     }
  742 
  743     ++ifp->if_ipackets;
  744 
  745     /* We assume the header fit entirely in one mbuf. */
  746     eh = mtod(m, struct ether_header *);
  747 
  748 #if NBPFILTER > 0
  749     /*
  750      * Check if there's a BPF listener on this interface.
  751      * If so, hand off the raw packet to BPF.
  752      */
  753     if (sc->arpcom.ac_if.if_bpf) {
  754         bpf_mtap(&sc->arpcom.ac_if, m);
  755     }
  756 #endif
  757 
  758     /*
  759      * XXX: Some cards seem to be in promiscous mode all the time.
  760      * we need to make sure we only get our own stuff always.
  761      * bleah!
  762      */
  763 
  764     if ((eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
  765         bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr,
  766         sizeof(eh->ether_dhost)) != 0) {
  767         m_freem(m);
  768             return;
  769     }
  770     /* We assume the header fit entirely in one mbuf. */
  771     m_adj(m, sizeof(struct ether_header));
  772     ether_input(ifp, eh, m);
  773 
  774     /*
  775     * In periods of high traffic we can actually receive enough
  776     * packets so that the fifo overrun bit will be set at this point,
  777     * even though we just read a packet. In this case we
  778     * are not going to receive any more interrupts. We check for
  779     * this condition and read again until the fifo is not full.
  780     * We could simplify this test by not using vxstatus(), but
  781     * rechecking the RX_STATUS register directly. This test could
  782     * result in unnecessary looping in cases where there is a new
  783     * packet but the fifo is not full, but it will not fix the
  784     * stuck behavior.
  785     *
  786     * Even with this improvement, we still get packet overrun errors
  787     * which are hurting performance. Maybe when I get some more time
  788     * I'll modify vxread() so that it can handle RX_EARLY interrupts.
  789     */
  790     if (vxstatus(sc)) {
  791         len = inw(BASE + VX_W1_RX_STATUS);
  792         /* Check if we are stuck and reset [see XXX comment] */
  793         if (len & ERR_INCOMPLETE) {
  794             if (ifp->if_flags & IFF_DEBUG)
  795                 printf("vx%d: adapter reset\n", sc->unit);
  796             vxreset(sc);
  797             return;
  798         }
  799         goto again;
  800     }
  801 
  802     return;
  803 
  804 abort:
  805     outw(BASE + VX_COMMAND, RX_DISCARD_TOP_PACK);
  806 }
  807 
  808 static struct mbuf *
  809 vxget(sc, totlen)
  810     struct vx_softc *sc;
  811     u_int totlen;
  812 {
  813     struct ifnet *ifp = &sc->arpcom.ac_if;
  814     struct mbuf *top, **mp, *m;
  815     int len;
  816     int sh;
  817 
  818     m = sc->mb[sc->next_mb];
  819     sc->mb[sc->next_mb] = 0;
  820     if (m == 0) {
  821         MGETHDR(m, M_DONTWAIT, MT_DATA);
  822         if (m == 0)
  823             return 0;
  824     } else {
  825         /* If the queue is no longer full, refill. */
  826         if (sc->last_mb == sc->next_mb && sc->buffill_pending == 0) {
  827             sc->ch = timeout(vxmbuffill, sc, 1);
  828             sc->buffill_pending = 1;
  829         }
  830         /* Convert one of our saved mbuf's. */
  831         sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
  832         m->m_data = m->m_pktdat;
  833         m->m_flags = M_PKTHDR;
  834     }
  835     m->m_pkthdr.rcvif = ifp;
  836     m->m_pkthdr.len = totlen;
  837     len = MHLEN;
  838     top = 0;
  839     mp = &top;
  840 
  841     /*
  842      * We read the packet at splhigh() so that an interrupt from another
  843      * device doesn't cause the card's buffer to overflow while we're
  844      * reading it.  We may still lose packets at other times.
  845      */
  846     sh = splhigh();
  847 
  848     /*
  849      * Since we don't set allowLargePackets bit in MacControl register,
  850      * we can assume that totlen <= 1500bytes.
  851      * The while loop will be performed iff we have a packet with
  852      * MLEN < m_len < MINCLSIZE.
  853      */
  854     while (totlen > 0) {
  855         if (top) {
  856             m = sc->mb[sc->next_mb];
  857             sc->mb[sc->next_mb] = 0;
  858             if (m == 0) {
  859                 MGET(m, M_DONTWAIT, MT_DATA);
  860                 if (m == 0) {
  861                     splx(sh);
  862                     m_freem(top);
  863                     return 0;
  864                 }
  865             } else {
  866                 sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
  867             }
  868             len = MLEN;
  869         }
  870         if (totlen >= MINCLSIZE) {
  871             MCLGET(m, M_DONTWAIT);
  872             if (m->m_flags & M_EXT)
  873                 len = MCLBYTES;
  874         }
  875         len = min(totlen, len);
  876         if (len > 3)
  877             insl(BASE + VX_W1_RX_PIO_RD_1, mtod(m, u_int32_t *), len / 4);
  878         if (len & 3) {
  879             insb(BASE + VX_W1_RX_PIO_RD_1, mtod(m, u_int8_t *) + (len & ~3),
  880                 len & 3);
  881         }
  882         m->m_len = len;
  883         totlen -= len;
  884         *mp = m;
  885         mp = &m->m_next;
  886     }
  887 
  888     outw(BASE +VX_COMMAND, RX_DISCARD_TOP_PACK);
  889 
  890     splx(sh);
  891 
  892     return top;
  893 }
  894 
  895 
  896 static int
  897 vxioctl(ifp, cmd, data)
  898     register struct ifnet *ifp;
  899     u_long cmd;
  900     caddr_t data;
  901 {
  902     struct vx_softc *sc = vx_softc[ifp->if_unit];
  903     struct ifreq *ifr = (struct ifreq *) data;
  904     int s, error = 0;
  905 
  906     s = splimp();
  907 
  908     switch (cmd) {
  909     case SIOCSIFADDR:
  910     case SIOCGIFADDR:
  911         ether_ioctl(ifp, cmd, data);
  912         break;
  913 
  914     case SIOCSIFFLAGS:
  915         if ((ifp->if_flags & IFF_UP) == 0 &&
  916             (ifp->if_flags & IFF_RUNNING) != 0) {
  917             /*
  918              * If interface is marked up and it is stopped, then
  919              * start it.
  920              */
  921             vxstop(sc);
  922             ifp->if_flags &= ~IFF_RUNNING;
  923         } else if ((ifp->if_flags & IFF_UP) != 0 &&
  924                    (ifp->if_flags & IFF_RUNNING) == 0) {
  925             /*
  926              * If interface is marked up and it is stopped, then
  927              * start it.
  928              */
  929             vxinit(sc);
  930         } else {
  931             /*
  932              * deal with flags changes:
  933              * IFF_MULTICAST, IFF_PROMISC,
  934              * IFF_LINK0, IFF_LINK1,
  935              */
  936             vxsetfilter(sc);
  937             vxsetlink(sc);
  938         }
  939         break;
  940 
  941     case SIOCSIFMTU:
  942         /*
  943          * Set the interface MTU.
  944          */
  945         if (ifr->ifr_mtu > ETHERMTU) {
  946             error = EINVAL;
  947         } else {
  948             ifp->if_mtu = ifr->ifr_mtu;
  949         }
  950         break;
  951 
  952     case SIOCADDMULTI:
  953     case SIOCDELMULTI:
  954         /*
  955          * Multicast list has changed; set the hardware filter
  956          * accordingly.
  957          */
  958         vxreset(sc);
  959         error = 0;
  960         break;
  961 
  962 
  963     default:
  964         error = EINVAL;
  965     }
  966 
  967     splx(s);
  968 
  969     return (error);
  970 }
  971 
  972 static void
  973 vxreset(sc)
  974     struct vx_softc *sc;
  975 {
  976     int s;
  977     s = splimp();
  978 
  979     vxstop(sc);
  980     vxinit(sc);
  981     splx(s);
  982 }
  983 
  984 static void
  985 vxwatchdog(ifp)
  986     struct ifnet *ifp;
  987 {
  988     struct vx_softc *sc = vx_softc[ifp->if_unit];
  989 
  990     if (ifp->if_flags & IFF_DEBUG)
  991         printf("vx%d: device timeout\n", ifp->if_unit);
  992     ifp->if_flags &= ~IFF_OACTIVE;
  993     vxstart(ifp);
  994     vxintr(sc);
  995 }
  996 
  997 void
  998 vxstop(sc)
  999     struct vx_softc *sc;
 1000 {
 1001     struct ifnet *ifp = &sc->arpcom.ac_if;
 1002 
 1003     ifp->if_timer = 0;
 1004 
 1005     outw(BASE + VX_COMMAND, RX_DISABLE);
 1006     outw(BASE + VX_COMMAND, RX_DISCARD_TOP_PACK);
 1007     VX_BUSY_WAIT;
 1008     outw(BASE + VX_COMMAND, TX_DISABLE);
 1009     outw(BASE + VX_COMMAND, STOP_TRANSCEIVER);
 1010     DELAY(800);
 1011     outw(BASE + VX_COMMAND, RX_RESET);
 1012     VX_BUSY_WAIT;
 1013     outw(BASE + VX_COMMAND, TX_RESET);
 1014     VX_BUSY_WAIT;
 1015     outw(BASE + VX_COMMAND, C_INTR_LATCH);
 1016     outw(BASE + VX_COMMAND, SET_RD_0_MASK);
 1017     outw(BASE + VX_COMMAND, SET_INTR_MASK);
 1018     outw(BASE + VX_COMMAND, SET_RX_FILTER);
 1019 
 1020     vxmbufempty(sc);
 1021 }
 1022 
 1023 int
 1024 vxbusyeeprom(sc)
 1025     struct vx_softc *sc;
 1026 {
 1027     int j, i = 100;
 1028 
 1029     while (i--) {
 1030         j = inw(BASE + VX_W0_EEPROM_COMMAND);
 1031         if (j & EEPROM_BUSY)
 1032             DELAY(100);
 1033         else
 1034             break;
 1035     }
 1036     if (!i) {
 1037         printf("vx%d: eeprom failed to come ready\n", sc->unit);
 1038         return (1);
 1039     }
 1040     return (0);
 1041 }
 1042 
 1043 static void
 1044 vxmbuffill(sp)
 1045     void *sp;
 1046 {
 1047     struct vx_softc *sc = (struct vx_softc *) sp;
 1048     int s, i;
 1049 
 1050     s = splimp();
 1051     i = sc->last_mb;
 1052     do {
 1053         if (sc->mb[i] == NULL)
 1054             MGET(sc->mb[i], M_DONTWAIT, MT_DATA);
 1055         if (sc->mb[i] == NULL)
 1056             break;
 1057         i = (i + 1) % MAX_MBS;
 1058     } while (i != sc->next_mb);
 1059     sc->last_mb = i;
 1060     /* If the queue was not filled, try again. */
 1061     if (sc->last_mb != sc->next_mb) {
 1062         sc->ch = timeout(vxmbuffill, sc, 1);
 1063         sc->buffill_pending = 1;
 1064     } else {
 1065         sc->buffill_pending = 0;
 1066     }
 1067     splx(s);
 1068 }
 1069 
 1070 static void
 1071 vxmbufempty(sc)
 1072     struct vx_softc *sc;
 1073 {
 1074     int s, i;
 1075 
 1076     s = splimp();
 1077     for (i = 0; i < MAX_MBS; i++) {
 1078         if (sc->mb[i]) {
 1079             m_freem(sc->mb[i]);
 1080             sc->mb[i] = NULL;
 1081         }
 1082     }
 1083     sc->last_mb = sc->next_mb = 0;
 1084     if (sc->buffill_pending != 0)
 1085         untimeout(vxmbuffill, sc, sc->ch);
 1086     splx(s);
 1087 }
 1088 
 1089 #endif                          /* NVX > 0 */

Cache object: 32ecb1366328a9cecf6f4291f3407f50


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.