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

Cache object: 353abeefc20baad906f3df06b5246232


[ 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.