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

Cache object: 1be0c4cfa692728518e864f8a06df5f9


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