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/i386/isa/if_wl.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 /* $FreeBSD: src/sys/i386/isa/if_wl.c,v 1.8.2.2 1999/09/05 08:12:59 peter Exp $ */
    2 /* 
    3  * Redistribution and use in source and binary forms, with or without
    4  * modification, are permitted provided that the following conditions
    5  * are met:
    6  * 1. Redistributions of source code must retain all copyright 
    7  *    notices, this list of conditions and the following disclaimer.
    8  * 2. The names of the authors may not be used to endorse or promote products
    9  *    derived from this software withough specific prior written permission
   10  *
   11  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
   12  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   13  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   14  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   15  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   16  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   17  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   18  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   19  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   20  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   21  * 
   22  */
   23 /*
   24  * if_wl.c - original MACH, then BSDI ISA wavelan driver
   25  *      ported to mach by Anders Klemets
   26  *      to BSDI by Robert Morris
   27  *      to FreeBSD by Jim Binkley
   28  *      to FreeBSD 2.2+ by Michael Smith
   29  *
   30  * 2.2 update:
   31  * Changed interface to match 2.1-2.2 differences.
   32  * Implement IRQ selection logic in wlprobe()
   33  * Implement PSA updating.
   34  * Pruned heading comments for relevance.
   35  * Ripped out all the 'interface counters' cruft.
   36  * Cut the missing-interrupt timer back to 100ms.
   37  * 2.2.1 update:
   38  * now supports all multicast mode (mrouted will work),
   39  *      but unfortunately must do that by going into promiscuous mode
   40  * NWID sysctl added so that normally promiscuous mode is NWID-specific
   41  *      but can be made NWID-inspecific
   42  *                      7/14/97 jrb
   43  *
   44  * Work done:
   45  * Ported to FreeBSD, got promiscuous mode working with bpfs,
   46  * and rewired timer routine.  The i82586 will hang occasionally on output 
   47  * and the watchdog timer will kick it if so and log an entry.
   48  * 2 second timeout there.  Apparently the chip loses an interrupt.
   49  * Code borrowed from if_ie.c for watchdog timer.
   50  *
   51  * The wavelan card is a 2mbit radio modem that emulates ethernet;
   52  * i.e., it uses MAC addresses.  This should not be a surprise since
   53  * it uses an ethernet controller as a major hw item.
   54  * It can broadcast, unicast or apparently multicast in a base cell 
   55  * using a omni-directional antennae that is 
   56  * about 800 feet around the base cell barring walls and metal.  
   57  * With directional antennae, it can be used point to point over a mile
   58  * or so apparently (haven't tried that).
   59  *
   60  * There are ISA and pcmcia versions (not supported by this code).
   61  * The ISA card has an Intel 82586 lan controller on it.  It consists
   62  * of 2 pieces of hw, the lan controller (intel) and a radio-modem.
   63  * The latter has an extra set of controller registers that has nothing
   64  * to do with the i82586 and allows setting and monitoring of radio
   65  * signal strength, etc.  There is a nvram area called the PSA that
   66  * contains a number of setup variables including the IRQ and so-called
   67  * NWID or Network ID.  The NWID must be set the same for all radio
   68  * cards to communicate (unless you are using the ATT/NCR roaming feature
   69  * with their access points.  There is no support for that here. Roaming
   70  * involves a link-layer beacon sent out from the access points.  End
   71  * stations monitor the signal strength and only use the strongest
   72  * access point).  This driver assumes that the base ISA port, IRQ, 
   73  * and NWID are first set in nvram via the dos-side "instconf.exe" utility 
   74  * supplied with the card. This driver takes the ISA port from 
   75  * the kernel configuration setup, and then determines the IRQ either 
   76  * from the kernel config (if an explicit IRQ is set) or from the 
   77  * PSA on the card if not.
   78  * The hw also magically just uses the IRQ set in the nvram.
   79  * The NWID is used magically as well by the radio-modem
   80  * to determine which packets to keep or throw out.  
   81  *
   82  * sample config:
   83  *
   84  * device wl0 at isa? port 0x300 net irq ? vector wlintr
   85  *
   86  * Ifdefs:
   87  * 1. WLDEBUG. (off) - if turned on enables IFF_DEBUG set via ifconfig debug
   88  * 2. MULTICAST (on) - turned on and works up to and including mrouted
   89  * 3. WLCACHE (off) -  define to turn on a signal strength 
   90  * (and other metric) cache that is indexed by sender MAC address.  
   91  * Apps can read this out to learn the remote signal strength of a 
   92  * sender.  Note that it has a switch so that it only stores 
   93  * broadcast/multicast senders but it could be set to store unicast 
   94  * too only.  Size is hardwired in if_wl_wavelan.h
   95  *
   96  * one further note: promiscuous mode is a curious thing.  In this driver,
   97  * promiscuous mode apparently CAN catch ALL packets and ignore the NWID
   98  * setting.  This is probably more useful in a sense (for snoopers) if
   99  * you are interested in all traffic as opposed to if you are interested
  100  * in just your own.  There is a driver specific sysctl to turn promiscuous
  101  * from just promiscuous to wildly promiscuous...
  102  *
  103  * This driver also knows how to load the synthesizers in the 2.4 Gz
  104  * ISA Half-card, Product number 847647476 (USA/FCC IEEE Channel set).
  105  * This product consists of a "mothercard" that contains the 82586,
  106  * NVRAM that holds the PSA, and the ISA-buss interface custom ASIC. 
  107  * The radio transceiver is a "daughtercard" called the WaveMODEM which
  108  * connects to the mothercard through two single-inline connectors: a
  109  * 20-pin connector provides DC-power and modem signals, and a 3-pin
  110  * connector which exports the antenna connection. The code herein
  111  * loads the receive and transmit synthesizers and the corresponding
  112  * transmitter output power value from an EEPROM controlled through
  113  * additional registers via the MMC. The EEPROM address selected
  114  * are those whose values are preset by the DOS utility programs
  115  * provided with the product, and this provides compatible operation
  116  * with the DOS Packet Driver software. A future modification will
  117  * add the necessary functionality to this driver and to the wlconfig
  118  * utility to completely replace the DOS Configuration Utilities.
  119  * The 2.4 Gz WaveMODEM is described in document number 407-024692/E,
  120  * and is available through Lucent Technologies OEM supply channels.
  121  * --RAB 1997/06/08.
  122  */
  123 
  124 #define MULTICAST  1
  125 
  126 /* 
  127  *      Olivetti PC586 Mach Ethernet driver v1.0
  128  *      Copyright Ing. C. Olivetti & C. S.p.A. 1988, 1989
  129  *      All rights reserved.
  130  *
  131  */ 
  132 
  133 /*
  134   Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc.,
  135 Cupertino, California.
  136 
  137                 All Rights Reserved
  138 
  139   Permission to use, copy, modify, and distribute this software and
  140 its documentation for any purpose and without fee is hereby
  141 granted, provided that the above copyright notice appears in all
  142 copies and that both the copyright notice and this permission notice
  143 appear in supporting documentation, and that the name of Olivetti
  144 not be used in advertising or publicity pertaining to distribution
  145 of the software without specific, written prior permission.
  146 
  147   OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
  148 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
  149 IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
  150 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  151 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
  152 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
  153 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  154 */
  155 
  156 /*
  157   Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
  158 
  159                 All Rights Reserved
  160 
  161 Permission to use, copy, modify, and distribute this software and
  162 its documentation for any purpose and without fee is hereby
  163 granted, provided that the above copyright notice appears in all
  164 copies and that both the copyright notice and this permission notice
  165 appear in supporting documentation, and that the name of Intel
  166 not be used in advertising or publicity pertaining to distribution
  167 of the software without specific, written prior permission.
  168 
  169 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
  170 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
  171 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
  172 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  173 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
  174 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  175 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  176 */
  177 
  178 /*
  179  * NOTE:
  180  *              by rvb:
  181  *  1.  The best book on the 82586 is:
  182  *              LAN Components User's Manual by Intel
  183  *      The copy I found was dated 1984.  This really tells you
  184  *      what the state machines are doing
  185  *  2.  In the current design, we only do one write at a time,
  186  *      though the hardware is capable of chaining and possibly
  187  *      even batching.  The problem is that we only make one
  188  *      transmit buffer available in sram space.
  189  */
  190 
  191 #include "wl.h"
  192 #include "opt_wavelan.h"
  193 #include "bpfilter.h"
  194 
  195 #include <sys/param.h>
  196 #include <sys/systm.h>
  197 #include <sys/sockio.h>
  198 #include <sys/mbuf.h>
  199 #include <sys/socket.h>
  200 #include <sys/syslog.h>
  201 #include <sys/proc.h>
  202 
  203 #include <sys/kernel.h>
  204 #include <sys/sysctl.h>
  205 
  206 #include <net/if.h>
  207 #include <net/if_dl.h>
  208 
  209 #ifdef INET
  210 #include <netinet/in.h>
  211 #include <netinet/in_systm.h>
  212 #include <netinet/ip.h>
  213 #include <netinet/if_ether.h>
  214 #endif
  215 
  216 #if NBPFILTER > 0
  217 #include <net/bpf.h>
  218 #endif
  219 
  220 #include <machine/clock.h>
  221 
  222 #include <i386/isa/isa_device.h>
  223 
  224 #include <i386/isa/ic/if_wl_i82586.h>   /* Definitions for the Intel chip */
  225 
  226 /* was 1000 in original, fed to DELAY(x) */
  227 #define DELAYCONST      1000
  228 #include <i386/isa/if_wl.h>
  229 #include <machine/if_wl_wavelan.h>
  230 
  231 static char     t_packet[ETHERMTU + sizeof(struct ether_header) + sizeof(long)];
  232 
  233 struct wl_softc{ 
  234     struct      arpcom  wl_ac;                  /* Ethernet common part */
  235 #define wl_if   wl_ac.ac_if                     /* network visible interface */
  236 #define wl_addr wl_ac.ac_enaddr                 /* hardware address */
  237     u_char      psa[0x40];
  238     u_char      nwid[2];        /* current radio modem nwid */
  239     short       base;
  240     short       unit;
  241     int         flags;
  242     int         tbusy;          /* flag to determine if xmit is busy */
  243     u_short     begin_fd;
  244     u_short     end_fd;
  245     u_short     end_rbd;
  246     u_short     hacr;           /* latest host adapter CR command */
  247     short       mode;
  248     u_char      chan24;         /* 2.4 Gz: channel number/EEPROM Area # */
  249     u_short     freq24;         /* 2.4 Gz: resulting frequency  */
  250 #ifdef WLCACHE
  251     int         w_sigitems;     /* number of cached entries */
  252     /*  array of cache entries */
  253     struct w_sigcache w_sigcache[ MAXCACHEITEMS ];            
  254     int w_nextcache;            /* next free cache entry */    
  255     int w_wrapindex;            /* next "free" cache entry */
  256 #endif
  257 };
  258 static struct wl_softc wl_softc[NWL];
  259 
  260 #define WLSOFTC(unit) ((struct wl_softc *)(&wl_softc[unit]))
  261 
  262 static int      wlprobe(struct isa_device *);
  263 static int      wlattach(struct isa_device *);
  264 void            wlintr(int);    /* no, not static */
  265 
  266 struct isa_driver wldriver = {
  267     wlprobe, wlattach, "wl", 0
  268 };
  269 
  270 /*
  271  * XXX  The Wavelan appears to be prone to dropping stuff if you talk to
  272  * it too fast.  This disgusting hack inserts a delay after each packet
  273  * is queued which helps avoid this behaviour on fast systems.
  274  */
  275 static int      wl_xmit_delay = 250;
  276 SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_delay, CTLFLAG_RW, &wl_xmit_delay, 0, "");
  277 
  278 /* 
  279  * not XXX, but ZZZ (bizarre).
  280  * promiscuous mode can be toggled to ignore NWIDs.  By default,
  281  * it does not.  Caution should be exercised about combining
  282  * this mode with IFF_ALLMULTI which puts this driver in
  283  * promiscuous mode.
  284  */
  285 static int      wl_ignore_nwid = 0;
  286 SYSCTL_INT(_machdep, OID_AUTO, wl_ignore_nwid, CTLFLAG_RW, &wl_ignore_nwid, 0, "");
  287 
  288 /*
  289  * Emit diagnostics about transmission problems
  290  */
  291 static int      xmt_watch = 0;
  292 SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_watch, CTLFLAG_RW, &xmt_watch, 0, "");
  293 
  294 /*
  295  * Collect SNR statistics
  296  */
  297 static int      gathersnr = 0;
  298 SYSCTL_INT(_machdep, OID_AUTO, wl_gather_snr, CTLFLAG_RW, &gathersnr, 0, "");
  299 
  300 static void     wlstart(struct ifnet *ifp);
  301 static void     wlinit(void *xsc);
  302 static int      wlioctl(struct ifnet *ifp, int cmd, caddr_t data);
  303 static timeout_t wlwatchdog;
  304 static void     wlxmt(int unt, struct mbuf *m);
  305 static int      wldiag(int unt); 
  306 static int      wlconfig(int unit); 
  307 static int      wlcmd(int unit, char *str);
  308 static void     wlmmcstat(int unit);
  309 static u_short  wlbldru(int unit);
  310 static u_short  wlmmcread(u_int base, u_short reg);
  311 static void     wlinitmmc(int unit);
  312 static void     wlsetirq(int base, int irq);
  313 static int      wlhwrst(int unit);
  314 static void     wlrustrt(int unit);
  315 static void     wlbldcu(int unit);
  316 static int      wlack(int unit);
  317 static int      wlread(int unit, u_short fd_p);
  318 static void     getsnr(int unit);
  319 static void     wlrcv(int unit);
  320 static int      wlrequeue(int unit, u_short fd_p);
  321 static void     wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
  322 static void     wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
  323 static void     wltbd(int unit);
  324 static void     wlgetpsa(int base, u_char *buf);
  325 static void     wlsetpsa(int unit);
  326 static u_short  wlpsacrc(u_char *buf);
  327 static void     wldump(int unit);
  328 #ifdef WLCACHE
  329 static void     wl_cache_store(int, int, struct ether_header *, struct mbuf *);
  330 static void     wl_cache_zero(int unit);
  331 #endif
  332 #ifdef MULTICAST
  333 # if __FreeBSD < 3
  334 static int      check_allmulti(int unit);
  335 # endif
  336 #endif
  337 
  338 /* array for maping irq numbers to values for the irq parameter register */
  339 static int irqvals[16] = { 
  340     0, 0, 0, 0x01, 0x02, 0x04, 0, 0x08, 0, 0, 0x10, 0x20, 0x40, 0, 0, 0x80 
  341 };
  342 /* mask of valid IRQs */
  343 #define WL_IRQS (IRQ3|IRQ4|IRQ5|IRQ7|IRQ10|IRQ11|IRQ12|IRQ15)
  344 
  345 /*
  346  * wlprobe:
  347  *
  348  *      This function "probes" or checks for the WaveLAN board on the bus to
  349  *      see if it is there.  As far as I can tell, the best break between this
  350  *      routine and the attach code is to simply determine whether the board
  351  *      is configured in properly.  Currently my approach to this is to write
  352  *      and read a word from the SRAM on the board being probed.  If the word
  353  *      comes back properly then we assume the board is there.  The config
  354  *      code expects to see a successful return from the probe routine before
  355  *      attach will be called.
  356  *
  357  * input        : address device is mapped to, and unit # being checked
  358  * output       : a '1' is returned if the board exists, and a 0 otherwise
  359  *
  360  */
  361 static int
  362 wlprobe(struct isa_device *id)
  363 {
  364     struct wl_softc     *sc = &wl_softc[id->id_unit];   
  365     register short      base = id->id_iobase;
  366     int                 unit = id->id_unit;
  367     char                *str = "wl%d: board out of range [0..%d]\n";
  368     u_char              inbuf[100];
  369     unsigned long       oldpri;
  370     int                 irq;
  371 
  372     /* TBD. not true.
  373      * regular CMD() will not work, since no softc yet 
  374      */
  375 #define PCMD(base, hacr) outw((base), (hacr))
  376 
  377     oldpri = splimp();
  378     PCMD(base, HACR_RESET);                     /* reset the board */
  379     DELAY(DELAYCONST);                          /* >> 4 clocks at 6MHz */
  380     PCMD(base, HACR_RESET);                     /* reset the board */
  381     DELAY(DELAYCONST);                          /* >> 4 clocks at 6MHz */
  382     splx(oldpri);
  383 
  384     /* clear reset command and set PIO#1 in autoincrement mode */
  385     PCMD(base, HACR_DEFAULT);
  386     PCMD(base, HACR_DEFAULT);
  387     outw(PIOR1(base), 0);                       /* go to beginning of RAM */
  388     outsw(PIOP1(base), str, strlen(str)/2+1);   /* write string */
  389     
  390     outw(PIOR1(base), 0);                       /* rewind */
  391     insw(PIOP1(base), inbuf, strlen(str)/2+1);  /* read result */
  392     
  393     if (bcmp(str, inbuf, strlen(str)))
  394         return(0);
  395 
  396     sc->chan24 = 0;                             /* 2.4 Gz: config channel */
  397     sc->freq24 = 0;                             /* 2.4 Gz: frequency    */
  398 
  399     /* read the PSA from the board into temporary storage */
  400     wlgetpsa(base, inbuf);
  401     
  402     /* We read the IRQ value from the PSA on the board. */
  403     for (irq = 15; irq >= 0; irq--)
  404         if (irqvals[irq] == inbuf[WLPSA_IRQNO])
  405             break;
  406     if ((irq == 0) || (irqvals[irq] == 0)){
  407         printf("wl%d: PSA corrupt (invalid IRQ value)\n", id->id_unit);
  408         id->id_irq = 0;                         /* no interrupt */
  409     } else {
  410         /*
  411          * If the IRQ requested by the PSA is already claimed by another
  412          * device, the board won't work, but the user can still access the
  413          * driver to change the IRQ.
  414          */
  415         id->id_irq = (1<<irq);                  /* use IRQ from PSA */
  416     }
  417     return(16);
  418 }
  419 
  420 
  421 /*
  422  * wlattach:
  423  *
  424  *      This function attaches a WaveLAN board to the "system".  The rest of
  425  *      runtime structures are initialized here (this routine is called after
  426  *      a successful probe of the board).  Once the ethernet address is read
  427  *      and stored, the board's ifnet structure is attached and readied.
  428  *
  429  * input        : isa_dev structure setup in autoconfig
  430  * output       : board structs and ifnet is setup
  431  *
  432  */
  433 static int
  434 wlattach(struct isa_device *id)
  435 {
  436     struct wl_softc     *sc = (struct wl_softc *) &wl_softc[id->id_unit];
  437     register short      base = id->id_iobase;
  438     int                 i,j;
  439     u_char              unit = id->id_unit;
  440     register struct ifnet       *ifp = &sc->wl_if;
  441 
  442 #ifdef WLDEBUG
  443     printf("wlattach: base %x, unit %d\n", base, unit);
  444 #endif
  445     sc->base = base;
  446     sc->unit = unit;
  447     sc->flags = 0;
  448     sc->mode = 0;
  449     sc->hacr = HACR_RESET;
  450     CMD(unit);                          /* reset the board */
  451     DELAY(DELAYCONST);                  /* >> 4 clocks at 6MHz */
  452         
  453     /* clear reset command and set PIO#2 in parameter access mode */
  454     sc->hacr = (HACR_DEFAULT & ~HACR_16BITS);
  455     CMD(unit);
  456 
  457     /* Read the PSA from the board for our later reference */
  458     wlgetpsa(base, sc->psa);
  459 
  460     /* fetch NWID */
  461     sc->nwid[0] = sc->psa[WLPSA_NWID];
  462     sc->nwid[1] = sc->psa[WLPSA_NWID+1];
  463     
  464     /* fetch MAC address - decide which one first */
  465     if (sc->psa[WLPSA_MACSEL] & 1) {
  466         j = WLPSA_LOCALMAC;
  467     } else {
  468         j = WLPSA_UNIMAC;
  469     }
  470     for(i=0; i < WAVELAN_ADDR_SIZE; ++i) {
  471         sc->wl_addr[i] = sc->psa[j + i];
  472     }
  473 
  474     /* enter normal 16 bit mode operation */
  475     sc->hacr = HACR_DEFAULT;
  476     CMD(unit);
  477 
  478     wlinitmmc(unit);
  479     outw(PIOR1(base), OFFSET_SCB + 8);  /* address of scb_crcerrs */
  480     outw(PIOP1(base), 0);                       /* clear scb_crcerrs */
  481     outw(PIOP1(base), 0);                       /* clear scb_alnerrs */
  482     outw(PIOP1(base), 0);                       /* clear scb_rscerrs */
  483     outw(PIOP1(base), 0);                       /* clear scb_ovrnerrs */
  484 
  485     bzero(ifp, sizeof(ifp));
  486     ifp->if_softc = sc;
  487     ifp->if_unit = id->id_unit;
  488     ifp->if_mtu = WAVELAN_MTU;
  489     ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
  490 #ifdef    WLDEBUG
  491     ifp->if_flags |= IFF_DEBUG;
  492 #endif
  493 #if     MULTICAST
  494     ifp->if_flags |= IFF_MULTICAST;
  495 #endif  MULTICAST
  496     ifp->if_name = "wl";
  497     ifp->if_unit = unit;
  498     ifp->if_init = wlinit;
  499     ifp->if_output = ether_output;
  500     ifp->if_start = wlstart;
  501     ifp->if_ioctl = wlioctl;
  502     ifp->if_timer = 0;   /* paranoia */
  503     /* no entries
  504        ifp->if_watchdog
  505        ifp->if_done
  506        ifp->if_reset
  507        */
  508     if_attach(ifp);
  509     ether_ifattach(ifp);
  510 
  511 #if NBPFILTER > 0
  512     bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
  513 #endif
  514 
  515     bcopy(&sc->wl_addr[0], sc->wl_ac.ac_enaddr, WAVELAN_ADDR_SIZE);
  516     printf("%s%d: address %6D, NWID 0x%02x%02x", ifp->if_name, ifp->if_unit,
  517            sc->wl_ac.ac_enaddr, ":", sc->nwid[0], sc->nwid[1]);
  518     if (sc->freq24) 
  519         printf(", Freq %d MHz",sc->freq24);             /* 2.4 Gz       */
  520     printf("\n");                                       /* 2.4 Gz       */
  521 
  522 
  523     if (bootverbose)
  524         wldump(unit);
  525     return(1);
  526 }
  527 
  528 /*
  529  * Print out interesting information about the 82596.
  530  */
  531 static void
  532 wldump(int unit)
  533 {
  534     register struct wl_softc *sp = WLSOFTC(unit);
  535     int         base = sp->base;
  536     int         i;
  537         
  538     printf("hasr %04x\n", inw(HASR(base)));
  539         
  540     printf("scb at %04x:\n ", OFFSET_SCB);
  541     outw(PIOR1(base), OFFSET_SCB);
  542     for(i = 0; i < 8; i++)
  543         printf("%04x ", inw(PIOP1(base)));
  544     printf("\n");
  545         
  546     printf("cu at %04x:\n ", OFFSET_CU);
  547     outw(PIOR1(base), OFFSET_CU);
  548     for(i = 0; i < 8; i++)
  549         printf("%04x ", inw(PIOP1(base)));
  550     printf("\n");
  551         
  552     printf("tbd at %04x:\n ", OFFSET_TBD);
  553     outw(PIOR1(base), OFFSET_TBD);
  554     for(i = 0; i < 4; i++)
  555         printf("%04x ", inw(PIOP1(base)));
  556     printf("\n");
  557 }
  558 
  559 /* Initialize the Modem Management Controller */
  560 static void
  561 wlinitmmc(int unit)
  562 {
  563     register struct wl_softc *sp = WLSOFTC(unit);
  564     int         base = sp->base;
  565     int         configured;
  566     int         mode = sp->mode;
  567     int         i;                              /* 2.4 Gz               */
  568         
  569     /* enter 8 bit operation */
  570     sp->hacr = (HACR_DEFAULT & ~HACR_16BITS);
  571     CMD(unit);
  572 
  573     configured = sp->psa[WLPSA_CONFIGURED] & 1;
  574         
  575     /*
  576      * Set default modem control parameters.  Taken from NCR document
  577      *  407-0024326 Rev. A 
  578      */
  579     MMC_WRITE(MMC_JABBER_ENABLE, 0x01);
  580     MMC_WRITE(MMC_ANTEN_SEL, 0x02);
  581     MMC_WRITE(MMC_IFS, 0x20);
  582     MMC_WRITE(MMC_MOD_DELAY, 0x04);
  583     MMC_WRITE(MMC_JAM_TIME, 0x38);
  584     MMC_WRITE(MMC_DECAY_PRM, 0x00);             /* obsolete ? */
  585     MMC_WRITE(MMC_DECAY_UPDAT_PRM, 0x00);
  586     if (!configured) {
  587         MMC_WRITE(MMC_LOOPT_SEL, 0x00);
  588         if (sp->psa[WLPSA_COMPATNO] & 1) {
  589             MMC_WRITE(MMC_THR_PRE_SET, 0x01);   /* 0x04 for AT and 0x01 for MCA */
  590         } else {
  591             MMC_WRITE(MMC_THR_PRE_SET, 0x04);   /* 0x04 for AT and 0x01 for MCA */
  592         }
  593         MMC_WRITE(MMC_QUALITY_THR, 0x03);
  594     } else {
  595         /* use configuration defaults from parameter storage area */
  596         if (sp->psa[WLPSA_NWIDENABLE] & 1) {
  597             if ((mode & (MOD_PROM | MOD_ENAL)) && wl_ignore_nwid) {
  598                 MMC_WRITE(MMC_LOOPT_SEL, 0x40);
  599             } else {
  600                 MMC_WRITE(MMC_LOOPT_SEL, 0x00);
  601             }
  602         } else {
  603             MMC_WRITE(MMC_LOOPT_SEL, 0x40);     /* disable network id check */
  604         }
  605         MMC_WRITE(MMC_THR_PRE_SET, sp->psa[WLPSA_THRESH]);
  606         MMC_WRITE(MMC_QUALITY_THR, sp->psa[WLPSA_QUALTHRESH]);
  607     }
  608     MMC_WRITE(MMC_FREEZE, 0x00);
  609     MMC_WRITE(MMC_ENCR_ENABLE, 0x00);
  610 
  611     MMC_WRITE(MMC_NETW_ID_L,sp->nwid[1]);       /* set NWID */
  612     MMC_WRITE(MMC_NETW_ID_H,sp->nwid[0]);
  613 
  614     /* enter normal 16 bit mode operation */
  615     sp->hacr = HACR_DEFAULT;
  616     CMD(unit);
  617     CMD(unit);                                  /* virtualpc1 needs this! */
  618 
  619     if (sp->psa[WLPSA_COMPATNO]==               /* 2.4 Gz: half-card ver     */
  620                 WLPSA_COMPATNO_WL24B) {         /* 2.4 Gz                    */
  621         i=sp->chan24<<4;                        /* 2.4 Gz: position ch #     */
  622         MMC_WRITE(MMC_EEADDR,i+0x0f);           /* 2.4 Gz: named ch, wc=16   */
  623         MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+   /* 2.4 Gz: Download Synths   */
  624                         MMC_EECTRL_EEOP_READ);  /* 2.4 Gz: Read EEPROM       */
  625         for (i=0; i<1000; ++i) {                /* 2.4 Gz: wait for download */
  626             DELAY(40);                          /* 2.4 Gz             */
  627             if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and    */
  628                 &(MMC_EECTRLstat_DWLD           /* 2.4 Gz:       EEBUSY      */
  629                  +MMC_EECTRLstat_EEBUSY))==0)   /* 2.4 Gz:                   */
  630                 break;                          /* 2.4 Gz: download finished */
  631         }                                       /* 2.4 Gz                    */
  632         if (i==1000) printf("wl: synth load failed\n"); /* 2.4 Gz       */
  633         MMC_WRITE(MMC_EEADDR,0x61);             /* 2.4 Gz: default pwr, wc=2 */
  634         MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+   /* 2.4 Gz: Download Xmit Pwr */
  635                         MMC_EECTRL_EEOP_READ);  /* 2.4 Gz: Read EEPROM       */
  636         for (i=0; i<1000; ++i) {                /* 2.4 Gz: wait for download */
  637             DELAY(40);                          /* 2.4 Gz             */
  638             if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and    */
  639                 &(MMC_EECTRLstat_DWLD           /* 2.4 Gz:       EEBUSY      */
  640                  +MMC_EECTRLstat_EEBUSY))==0)   /* 2.4 Gz:                   */
  641                 break;                          /* 2.4 Gz: download finished */
  642         }                                       /* 2.4 Gz                    */
  643         if (i==1000) printf("wl: xmit pwr load failed\n"); /* 2.4 Gz         */
  644         MMC_WRITE(MMC_ANALCTRL,                 /* 2.4 Gz: EXT ant+polarity  */
  645                         MMC_ANALCTRL_ANTPOL +   /* 2.4 Gz:                   */
  646                         MMC_ANALCTRL_EXTANT);   /* 2.4 Gz:                   */
  647         i=sp->chan24<<4;                        /* 2.4 Gz: position ch #     */
  648         MMC_WRITE(MMC_EEADDR,i);                /* 2.4 Gz: get frequency     */
  649         MMC_WRITE(MMC_EECTRL,                   /* 2.4 Gz: EEPROM read      */
  650                         MMC_EECTRL_EEOP_READ);  /* 2.4 Gz:                  */
  651         DELAY(40);                              /* 2.4 Gz                    */
  652         i = wlmmcread(base,MMC_EEDATALrv)       /* 2.4 Gz: freq val          */
  653           + (wlmmcread(base,MMC_EEDATAHrv)<<8); /* 2.4 Gz                    */
  654         sp->freq24 = (i>>6)+2400;               /* 2.4 Gz: save real freq    */
  655     }
  656 }
  657 
  658 /*
  659  * wlinit:
  660  *
  661  *      Another routine that interfaces the "if" layer to this driver.  
  662  *      Simply resets the structures that are used by "upper layers".  
  663  *      As well as calling wlhwrst that does reset the WaveLAN board.
  664  *
  665  * input        : softc pointer for this interface
  666  * output       : structures (if structs) and board are reset
  667  *
  668  */     
  669 static void
  670 wlinit(void *xsc)
  671 {
  672     register struct wl_softc *sc = xsc;
  673     struct ifnet        *ifp = &sc->wl_if;
  674     int                 stat;
  675     u_long              oldpri;
  676 
  677 #ifdef WLDEBUG
  678     if (sc->wl_if.if_flags & IFF_DEBUG)
  679         printf("wl%d: entered wlinit()\n",sc->unit);
  680 #endif
  681 #if __FreeBSD__ >= 3
  682     if (ifp->if_addrhead.tqh_first == (struct ifaddr *)0) {
  683 #else
  684     if (ifp->if_addrlist == (struct ifaddr *)0) {
  685 #endif
  686         return;
  687     }
  688     oldpri = splimp();
  689     if ((stat = wlhwrst(sc->unit)) == TRUE) {
  690         sc->wl_if.if_flags |= IFF_RUNNING;   /* same as DSF_RUNNING */
  691         /* 
  692          * OACTIVE is used by upper-level routines
  693          * and must be set
  694          */
  695         sc->wl_if.if_flags &= ~IFF_OACTIVE;  /* same as tbusy below */
  696                 
  697         sc->flags |= DSF_RUNNING;
  698         sc->tbusy = 0;
  699         untimeout(wlwatchdog, sc);
  700                 
  701         wlstart(ifp);
  702     } else {
  703         printf("wl%d init(): trouble resetting board.\n", sc->unit);
  704     }
  705     splx(oldpri);
  706 }
  707 
  708 /*
  709  * wlhwrst:
  710  *
  711  *      This routine resets the WaveLAN board that corresponds to the 
  712  *      board number passed in.
  713  *
  714  * input        : board number to do a hardware reset
  715  * output       : board is reset
  716  *
  717  */
  718 static int
  719 wlhwrst(int unit)
  720 {
  721     register struct wl_softc    *sc = WLSOFTC(unit);
  722     int         i;
  723     short       base = sc->base;
  724 
  725 #ifdef WLDEBUG
  726     if (sc->wl_if.if_flags & IFF_DEBUG)
  727         printf("wl%d: entered wlhwrst()\n",unit);
  728 #endif
  729     sc->hacr = HACR_RESET;
  730     CMD(unit);                  /* reset the board */
  731         
  732     /* clear reset command and set PIO#1 in autoincrement mode */
  733     sc->hacr = HACR_DEFAULT;
  734     CMD(unit);
  735 
  736 #ifdef  WLDEBUG
  737     if (sc->wl_if.if_flags & IFF_DEBUG)
  738         wlmmcstat(unit);        /* Display MMC registers */
  739 #endif  WLDEBUG
  740     wlbldcu(unit);              /* set up command unit structures */
  741     
  742     if (wldiag(unit) == 0)
  743         return(0);
  744     
  745     if (wlconfig(unit) == 0)
  746             return(0);
  747     /* 
  748      * insert code for loopback test here
  749      */
  750     wlrustrt(unit);             /* start receive unit */
  751 
  752     /* enable interrupts */
  753     sc->hacr = (HACR_DEFAULT | HACR_INTRON);
  754     CMD(unit);
  755     
  756     return(1);
  757 }
  758 
  759 /*
  760  * wlbldcu:
  761  *
  762  *      This function builds up the command unit structures.  It inits
  763  *      the scp, iscp, scb, cb, tbd, and tbuf.
  764  *
  765  */
  766 static void
  767 wlbldcu(int unit)
  768 {
  769     register struct wl_softc *sc = WLSOFTC(unit);
  770     short               base = sc->base;
  771     scp_t               scp;
  772     iscp_t              iscp;
  773     scb_t               scb;
  774     ac_t                cb;
  775     tbd_t               tbd;
  776     int         i;
  777 
  778     bzero(&scp, sizeof(scp));
  779     scp.scp_sysbus = 0;
  780     scp.scp_iscp = OFFSET_ISCP;
  781     scp.scp_iscp_base = 0;
  782     outw(PIOR1(base), OFFSET_SCP);
  783     outsw(PIOP1(base), &scp, sizeof(scp_t)/2);
  784 
  785     bzero(&iscp, sizeof(iscp));
  786     iscp.iscp_busy = 1;
  787     iscp.iscp_scb_offset = OFFSET_SCB;
  788     iscp.iscp_scb = 0;
  789     iscp.iscp_scb_base = 0;
  790     outw(PIOR1(base), OFFSET_ISCP);
  791     outsw(PIOP1(base), &iscp, sizeof(iscp_t)/2);
  792 
  793     scb.scb_status = 0;
  794     scb.scb_command = SCB_RESET;
  795     scb.scb_cbl_offset = OFFSET_CU;
  796     scb.scb_rfa_offset = OFFSET_RU;
  797     scb.scb_crcerrs = 0;
  798     scb.scb_alnerrs = 0;
  799     scb.scb_rscerrs = 0;
  800     scb.scb_ovrnerrs = 0;
  801     outw(PIOR1(base), OFFSET_SCB);
  802     outsw(PIOP1(base), &scb, sizeof(scb_t)/2);
  803 
  804     SET_CHAN_ATTN(unit);
  805 
  806     outw(PIOR0(base), OFFSET_ISCP + 0); /* address of iscp_busy */
  807     for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
  808     if (i <= 0) printf("wl%d bldcu(): iscp_busy timeout.\n", unit);
  809     outw(PIOR0(base), OFFSET_SCB + 0);  /* address of scb_status */
  810     for (i = STATUS_TRIES; i-- > 0; ) {
  811         if (inw(PIOP0(base)) == (SCB_SW_CX|SCB_SW_CNA)) 
  812             break;
  813     }
  814     if (i <= 0)
  815         printf("wl%d bldcu(): not ready after reset.\n", unit);
  816     wlack(unit);
  817 
  818     cb.ac_status = 0;
  819     cb.ac_command = AC_CW_EL;           /* NOP */
  820     cb.ac_link_offset = OFFSET_CU;
  821     outw(PIOR1(base), OFFSET_CU);
  822     outsw(PIOP1(base), &cb, 6/2);
  823 
  824     tbd.act_count = 0;
  825     tbd.next_tbd_offset = I82586NULL;
  826     tbd.buffer_addr = 0;
  827     tbd.buffer_base = 0;
  828     outw(PIOR1(base), OFFSET_TBD);
  829     outsw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
  830 }
  831 
  832 /*
  833  * wlstart:
  834  *
  835  *      send a packet
  836  *
  837  * input        : board number
  838  * output       : stuff sent to board if any there
  839  *
  840  */
  841 static void
  842 wlstart(struct ifnet *ifp)
  843 {
  844     int                         unit = ifp->if_unit;
  845     struct mbuf                 *m;
  846     register struct wl_softc    *sc = WLSOFTC(unit);
  847     short                       base = sc->base;
  848     int                         scb_status, cu_status, scb_command;
  849 
  850 #ifdef WLDEBUG
  851     if (sc->wl_if.if_flags & IFF_DEBUG)
  852         printf("wl%d: entered wlstart()\n",unit);
  853 #endif
  854 
  855     outw(PIOR1(base), OFFSET_CU);
  856     cu_status = inw(PIOP1(base));
  857     outw(PIOR0(base),OFFSET_SCB + 0);   /* scb_status */
  858     scb_status = inw(PIOP0(base));
  859     outw(PIOR0(base), OFFSET_SCB + 2);
  860     scb_command = inw(PIOP0(base));
  861 
  862     /*
  863      * don't need OACTIVE check as tbusy here checks to see
  864      * if we are already busy 
  865      */
  866     if (sc->tbusy) {
  867         if((scb_status & 0x0700) == SCB_CUS_IDLE &&
  868            (cu_status & AC_SW_B) == 0){
  869             sc->tbusy = 0;
  870             untimeout(wlwatchdog, sc);
  871             sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
  872             /*
  873              * This is probably just a race.  The xmt'r is just
  874              * became idle but WE have masked interrupts so ...
  875              */
  876 #ifdef WLDEBUG
  877             printf("wl%d: CU idle, scb %04x %04x cu %04x\n",
  878                    unit, scb_status, scb_command, cu_status);
  879 #endif 
  880             if (xmt_watch) printf("!!");
  881         } else {
  882             return;     /* genuinely still busy */
  883         }
  884     } else if((scb_status & 0x0700) == SCB_CUS_ACTV ||
  885               (cu_status & AC_SW_B)){
  886 #ifdef WLDEBUG
  887         printf("wl%d: CU unexpectedly busy; scb %04x cu %04x\n",
  888                unit, scb_status, cu_status);
  889 #endif
  890         if (xmt_watch) printf("wl%d: busy?!",unit);
  891         return;         /* hey, why are we busy? */
  892     }
  893 
  894     /* get ourselves some data */
  895     ifp = &(sc->wl_if);
  896     IF_DEQUEUE(&ifp->if_snd, m);
  897     if (m != (struct mbuf *)0) {
  898 #if NBPFILTER > 0
  899         /* let BPF see it before we commit it */
  900         if (ifp->if_bpf) {
  901             bpf_mtap(ifp, m);
  902         }
  903 #endif
  904         sc->tbusy++;
  905         /* set the watchdog timer so that if the board
  906          * fails to interrupt we will restart
  907          */
  908         /* try 10 ticks, not very long */
  909         timeout(wlwatchdog, sc, 10);
  910         sc->wl_ac.ac_if.if_flags |= IFF_OACTIVE;
  911         sc->wl_if.if_opackets++;
  912         wlxmt(unit, m);
  913     } else {
  914         sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
  915     }
  916     return;
  917 }
  918 
  919 /*
  920  * wlread:
  921  *
  922  *      This routine does the actual copy of data (including ethernet header
  923  *      structure) from the WaveLAN to an mbuf chain that will be passed up
  924  *      to the "if" (network interface) layer.  NOTE:  we currently
  925  *      don't handle trailer protocols, so if that is needed, it will
  926  *      (at least in part) be added here.  For simplicities sake, this
  927  *      routine copies the receive buffers from the board into a local (stack)
  928  *      buffer until the frame has been copied from the board.  Once in
  929  *      the local buffer, the contents are copied to an mbuf chain that
  930  *      is then enqueued onto the appropriate "if" queue.
  931  *
  932  * input        : board number, and an frame descriptor address
  933  * output       : the packet is put into an mbuf chain, and passed up
  934  * assumes      : if any errors occur, packet is "dropped on the floor"
  935  *
  936  */
  937 static int
  938 wlread(int unit, u_short fd_p)
  939 {
  940     register struct wl_softc    *sc = WLSOFTC(unit);
  941     register struct ifnet       *ifp = &sc->wl_if;
  942     short                       base = sc->base;
  943     fd_t                        fd;
  944     struct ether_header         eh;
  945     struct mbuf                 *m, *tm;
  946     rbd_t                       rbd;
  947     u_char                      *mb_p;
  948     u_short                     mlen, len, clen;
  949     u_short                     bytes_in_msg, bytes_in_mbuf, bytes;
  950 
  951 
  952 #ifdef WLDEBUG
  953     if (sc->wl_if.if_flags & IFF_DEBUG)
  954         printf("wl%d: entered wlread()\n",unit);
  955 #endif
  956     if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
  957         printf("wl%d read(): board is not running.\n", ifp->if_unit);
  958         sc->hacr &= ~HACR_INTRON;
  959         CMD(unit);              /* turn off interrupts */
  960     }
  961     /* read ether_header info out of device memory. doesn't
  962      * go into mbuf.  goes directly into eh structure
  963      */
  964     len = sizeof(struct ether_header);  /* 14 bytes */
  965     outw(PIOR1(base), fd_p);
  966     insw(PIOP1(base), &fd, (sizeof(fd_t) - len)/2);
  967     insw(PIOP1(base), &eh, (len-2)/2);
  968     eh.ether_type = ntohs(inw(PIOP1(base)));
  969 #ifdef WLDEBUG
  970     if (sc->wl_if.if_flags & IFF_DEBUG) {
  971         printf("wlread: rcv packet, type is %x\n", eh.ether_type);
  972     }
  973 #endif 
  974     /*
  975      * WARNING.  above is done now in ether_input, above may be
  976      * useful for debug. jrb
  977      */
  978     eh.ether_type = htons(eh.ether_type);
  979 
  980     if (fd.rbd_offset == I82586NULL) {
  981         printf("wl%d read(): Invalid buffer\n", unit);
  982         if (wlhwrst(unit) != TRUE) {
  983             printf("wl%d read(): hwrst trouble.\n", unit);
  984         }
  985         return 0;
  986     }
  987 
  988     outw(PIOR1(base), fd.rbd_offset);
  989     insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
  990     bytes_in_msg = rbd.status & RBD_SW_COUNT;
  991     MGETHDR(m, M_DONTWAIT, MT_DATA);
  992     tm = m;
  993     if (m == (struct mbuf *)0) {
  994         /*
  995          * not only do we want to return, we need to drop the packet on
  996          * the floor to clear the interrupt.
  997          *
  998          */
  999         if (wlhwrst(unit) != TRUE) {
 1000             sc->hacr &= ~HACR_INTRON;
 1001             CMD(unit);          /* turn off interrupts */
 1002             printf("wl%d read(): hwrst trouble.\n", unit);
 1003         }
 1004         return 0;
 1005     }
 1006     m->m_next = (struct mbuf *) 0;
 1007     m->m_pkthdr.rcvif = ifp;
 1008     m->m_pkthdr.len = 0; /* don't know this yet */
 1009     m->m_len = MHLEN;
 1010 
 1011     /* always use a cluster. jrb 
 1012      */
 1013     MCLGET(m, M_DONTWAIT);
 1014     if (m->m_flags & M_EXT) {
 1015         m->m_len = MCLBYTES;
 1016     }
 1017     else {
 1018         m_freem(m);
 1019         if (wlhwrst(unit) != TRUE) {
 1020             sc->hacr &= ~HACR_INTRON;
 1021             CMD(unit);          /* turn off interrupts */
 1022             printf("wl%d read(): hwrst trouble.\n", unit);
 1023         }
 1024         return 0;
 1025     }
 1026 
 1027     mlen = 0;
 1028     clen = mlen;
 1029     bytes_in_mbuf = m->m_len;
 1030     mb_p = mtod(tm, u_char *);
 1031     bytes = min(bytes_in_mbuf, bytes_in_msg);
 1032     for (;;) {
 1033         if (bytes & 1) {
 1034             len = bytes + 1;
 1035         } else {
 1036             len = bytes;
 1037         }
 1038         outw(PIOR1(base), rbd.buffer_addr);
 1039         insw(PIOP1(base), mb_p, len/2);
 1040         clen += bytes;
 1041         mlen += bytes;
 1042 
 1043         if (!(bytes_in_mbuf -= bytes)) {
 1044             MGET(tm->m_next, M_DONTWAIT, MT_DATA);
 1045             tm = tm->m_next;
 1046             if (tm == (struct mbuf *)0) {
 1047                 m_freem(m);
 1048                 printf("wl%d read(): No mbuf nth\n", unit);
 1049                 if (wlhwrst(unit) != TRUE) {
 1050                     sc->hacr &= ~HACR_INTRON;
 1051                     CMD(unit);  /* turn off interrupts */
 1052                     printf("wl%d read(): hwrst trouble.\n", unit);
 1053                 }
 1054                 return 0;
 1055             }
 1056             mlen = 0;
 1057             tm->m_len = MLEN;
 1058             bytes_in_mbuf = MLEN;
 1059             mb_p = mtod(tm, u_char *);
 1060         } else {
 1061             mb_p += bytes;
 1062         }
 1063 
 1064         if (!(bytes_in_msg  -= bytes)) {
 1065             if (rbd.status & RBD_SW_EOF ||
 1066                 rbd.next_rbd_offset == I82586NULL) {
 1067                 tm->m_len = mlen;
 1068                 break;
 1069             } else {
 1070                 outw(PIOR1(base), rbd.next_rbd_offset);
 1071                 insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
 1072                 bytes_in_msg = rbd.status & RBD_SW_COUNT;
 1073             }
 1074         } else {
 1075             rbd.buffer_addr += bytes;
 1076         }
 1077 
 1078         bytes = min(bytes_in_mbuf, bytes_in_msg);
 1079     }
 1080 
 1081     m->m_pkthdr.len = clen;
 1082 
 1083 #if NBPFILTER > 0
 1084     /*
 1085      * Check if there's a BPF listener on this interface. If so, hand off
 1086      * the raw packet to bpf.
 1087      */
 1088     if (ifp->if_bpf) {
 1089         /* bpf assumes header is in mbufs.  It isn't.  We can
 1090          * fool it without allocating memory as follows.
 1091          * Trick borrowed from if_ie.c
 1092          */
 1093         struct mbuf m0;         
 1094         m0.m_len = sizeof eh;
 1095         m0.m_data = (caddr_t) &eh;
 1096         m0.m_next = m;
 1097 
 1098         bpf_mtap(ifp, &m0);
 1099         
 1100     }
 1101 #endif
 1102     /*
 1103      * If hw is in promiscuous mode (note that I said hardware, not if
 1104      * IFF_PROMISC is set in ifnet flags), then if this is a unicast
 1105      * packet and the MAC dst is not us, drop it.  This check was formerly
 1106      * inside the bpf if, above, but IFF_MULTI causes hw promisc without
 1107      * a bpf listener, so this is wrong.
 1108      *          Greg Troxel <gdt@ir.bbn.com>, 1998-08-07
 1109      */
 1110     /*
 1111      * TBD: also discard packets where NWID does not match.
 1112      * However, there does not appear to be a way to read the nwid
 1113      * for a received packet.  -gdt 1998-08-07
 1114      */
 1115     if (
 1116 #ifdef WL_USE_IFNET_PROMISC_CHECK /* not defined */
 1117         (sc->wl_ac.ac_if.if_flags & (IFF_PROMISC|IFF_ALLMULTI))
 1118 #else
 1119         /* hw is in promisc mode if this is true */
 1120         (sc->mode & (MOD_PROM | MOD_ENAL))
 1121 #endif
 1122         &&
 1123         (eh.ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
 1124         bcmp(eh.ether_dhost, sc->wl_ac.ac_enaddr,
 1125              sizeof(eh.ether_dhost)) != 0 ) {
 1126       m_freem(m);
 1127       return 1;
 1128     }
 1129 
 1130 #ifdef WLDEBUG
 1131     if (sc->wl_if.if_flags & IFF_DEBUG)
 1132         printf("wl%d: wlrecv %d bytes\n", unit, clen);
 1133 #endif
 1134 
 1135 #ifdef WLCACHE
 1136     wl_cache_store(unit, base, &eh, m);
 1137 #endif
 1138 
 1139     /*
 1140      * received packet is now in a chain of mbuf's.  next step is
 1141      * to pass the packet upwards.
 1142      *
 1143      */
 1144     ether_input(&sc->wl_if, &eh, m);
 1145     return 1;
 1146 }
 1147 
 1148 /*
 1149  * wlioctl:
 1150  *
 1151  *      This routine processes an ioctl request from the "if" layer
 1152  *      above.
 1153  *
 1154  * input        : pointer the appropriate "if" struct, command, and data
 1155  * output       : based on command appropriate action is taken on the
 1156  *                WaveLAN board(s) or related structures
 1157  * return       : error is returned containing exit conditions
 1158  *
 1159  */
 1160 static int
 1161 wlioctl(struct ifnet *ifp, int cmd, caddr_t data)
 1162 {
 1163     register struct ifaddr      *ifa = (struct ifaddr *)data;
 1164     register struct ifreq       *ifr = (struct ifreq *)data;
 1165     int                         unit = ifp->if_unit;
 1166     register struct wl_softc    *sc = WLSOFTC(unit);
 1167     short               base = sc->base;
 1168     short               mode = 0;
 1169     int                 opri, error = 0;
 1170     u_short             tmp;
 1171     struct proc         *p = curproc;   /* XXX */
 1172     int                 irq, irqval, i, isroot, size;
 1173     caddr_t             up;
 1174     char *              cpt;
 1175         
 1176 
 1177 #ifdef WLDEBUG
 1178     if (sc->wl_if.if_flags & IFF_DEBUG)
 1179         printf("wl%d: entered wlioctl()\n",unit);
 1180 #endif
 1181     opri = splimp();
 1182     switch (cmd) {
 1183     case SIOCSIFADDR:
 1184         /* Set own IP address and enable interface */
 1185         ifp->if_flags |= IFF_UP;
 1186         switch (ifa->ifa_addr->sa_family) {
 1187 #ifdef INET
 1188         case AF_INET:
 1189             wlinit(sc);
 1190             arp_ifinit((struct arpcom *)ifp, ifa);
 1191             break;
 1192 #endif
 1193 #ifdef NS
 1194         case AF_NS:
 1195         {
 1196             register struct ns_addr *ina = 
 1197                 &(IA_SNS(ifa)->sns_addr);
 1198             if (ns_nullhost(*ina))
 1199                 ina->x_host = *(union ns_host *)(ds->wl_addr);
 1200             else
 1201                 wlsetaddr(ina->x_host.c_host, unit);
 1202             wlinit(sc);
 1203             break;
 1204         }
 1205 #endif  
 1206         default:
 1207             wlinit(sc);
 1208             break;
 1209         }
 1210         break;
 1211     case SIOCSIFFLAGS:
 1212         if (ifp->if_flags & IFF_ALLMULTI) {
 1213             mode |= MOD_ENAL;
 1214         }
 1215         if (ifp->if_flags & IFF_PROMISC) {
 1216             mode |= MOD_PROM;
 1217         }
 1218         if(ifp->if_flags & IFF_LINK0) {
 1219             mode |= MOD_PROM;
 1220         }
 1221         /*
 1222          * force a complete reset if the recieve multicast/
 1223          * promiscuous mode changes so that these take 
 1224          * effect immediately.
 1225          *
 1226          */
 1227         if (sc->mode != mode) {
 1228             sc->mode = mode;
 1229             if (sc->flags & DSF_RUNNING) {
 1230                 sc->flags &= ~DSF_RUNNING;
 1231                 wlinit(sc);
 1232             }
 1233         }
 1234         /* if interface is marked DOWN and still running then
 1235          * stop it.
 1236          */
 1237         if ((ifp->if_flags & IFF_UP) == 0 && sc->flags & DSF_RUNNING) {
 1238             printf("wl%d ioctl(): board is not running\n", unit);
 1239             sc->flags &= ~DSF_RUNNING;
 1240             sc->hacr &= ~HACR_INTRON;
 1241             CMD(unit);            /* turn off interrupts */
 1242         } 
 1243         /* else if interface is UP and RUNNING, start it
 1244                 */
 1245         else if (ifp->if_flags & IFF_UP && (sc->flags & DSF_RUNNING) == 0) {
 1246             wlinit(sc);
 1247         }
 1248   
 1249         /* if WLDEBUG set on interface, then printf rf-modem regs
 1250         */
 1251         if(ifp->if_flags & IFF_DEBUG)
 1252             wlmmcstat(unit);
 1253         break;
 1254 #if     MULTICAST
 1255     case SIOCADDMULTI:
 1256     case SIOCDELMULTI:
 1257 
 1258 #if __FreeBSD__ < 3
 1259         if (cmd == SIOCADDMULTI) {
 1260             error = ether_addmulti(ifr, &sc->wl_ac);
 1261         }
 1262         else {
 1263             error = ether_delmulti(ifr, &sc->wl_ac);
 1264         }
 1265 
 1266         /* see if we should be in all multicast mode
 1267          * note that 82586 cannot do that, must simulate with
 1268          * promiscuous mode
 1269          */
 1270         if ( check_allmulti(unit)) {
 1271                 ifp->if_flags |=  IFF_ALLMULTI;
 1272                 sc->mode |= MOD_ENAL;
 1273                 sc->flags &= ~DSF_RUNNING;
 1274                 wlinit(sc);
 1275                 error = 0;
 1276                 break;
 1277         }
 1278 
 1279         if (error == ENETRESET) {
 1280             if(sc->flags & DSF_RUNNING) {
 1281                 sc->flags &= ~DSF_RUNNING;
 1282                 wlinit(sc);
 1283             }
 1284             error = 0;
 1285         }
 1286 #endif
 1287         break;
 1288 #endif  MULTICAST
 1289 
 1290     /* DEVICE SPECIFIC */
 1291 
 1292 
 1293         /* copy the PSA out to the caller */
 1294     case SIOCGWLPSA:
 1295         /* pointer to buffer in user space */
 1296         up = (void *)ifr->ifr_data;
 1297         /* work out if they're root */
 1298         isroot = (suser(p->p_ucred, &p->p_acflag) == 0);
 1299         
 1300         for (i = 0; i < 0x40; i++) {
 1301             /* don't hand the DES key out to non-root users */
 1302             if ((i > WLPSA_DESKEY) && (i < (WLPSA_DESKEY + 8)) && !isroot)
 1303                 continue;
 1304             if (subyte((up + i), sc->psa[i]))
 1305                 return(EFAULT);
 1306         }
 1307         break;
 1308 
 1309 
 1310         /* copy the PSA in from the caller; we only copy _some_ values */
 1311     case SIOCSWLPSA:
 1312         /* root only */
 1313         if ((error = suser(p->p_ucred, &p->p_acflag)))
 1314             break;
 1315         error = EINVAL; /* assume the worst */
 1316         /* pointer to buffer in user space containing data */
 1317         up = (void *)ifr->ifr_data;
 1318         
 1319         /* check validity of input range */
 1320         for (i = 0; i < 0x40; i++)
 1321             if (fubyte(up + i) < 0)
 1322                 return(EFAULT);
 1323 
 1324         /* check IRQ value */
 1325         irqval = fubyte(up+WLPSA_IRQNO);
 1326         for (irq = 15; irq >= 0; irq--)
 1327             if(irqvals[irq] == irqval)
 1328                 break;
 1329         if (irq == 0)                   /* oops */
 1330             break;
 1331         /* new IRQ */
 1332         sc->psa[WLPSA_IRQNO] = irqval;
 1333 
 1334         /* local MAC */
 1335         for (i = 0; i < 6; i++)
 1336             sc->psa[WLPSA_LOCALMAC+i] = fubyte(up+WLPSA_LOCALMAC+i);
 1337                 
 1338         /* MAC select */        
 1339         sc->psa[WLPSA_MACSEL] = fubyte(up+WLPSA_MACSEL);
 1340         
 1341         /* default nwid */
 1342         sc->psa[WLPSA_NWID] = fubyte(up+WLPSA_NWID);
 1343         sc->psa[WLPSA_NWID+1] = fubyte(up+WLPSA_NWID+1);
 1344 
 1345         error = 0;
 1346         wlsetpsa(unit);         /* update the PSA */
 1347         break;
 1348 
 1349 
 1350         /* get the current NWID out of the sc since we stored it there */
 1351     case SIOCGWLCNWID:
 1352         ifr->ifr_data = (caddr_t) (sc->nwid[0] << 8 | sc->nwid[1]);
 1353         break;
 1354 
 1355 
 1356         /*
 1357          * change the nwid dynamically.  This
 1358          * ONLY changes the radio modem and does not
 1359          * change the PSA.
 1360          *
 1361          * 2 steps:
 1362          *      1. save in softc "soft registers"
 1363          *      2. save in radio modem (MMC)
 1364          */
 1365     case SIOCSWLCNWID:
 1366         /* root only */
 1367         if ((error = suser(p->p_ucred, &p->p_acflag)))
 1368             break;
 1369         if (!(ifp->if_flags & IFF_UP)) {
 1370             error = EIO;        /* only allowed while up */
 1371         } else {
 1372             /* 
 1373              * soft c nwid shadows radio modem setting
 1374              */
 1375             sc->nwid[0] = (int)ifr->ifr_data >> 8;
 1376             sc->nwid[1] = (int)ifr->ifr_data & 0xff;
 1377             MMC_WRITE(MMC_NETW_ID_L,sc->nwid[1]);
 1378             MMC_WRITE(MMC_NETW_ID_H,sc->nwid[0]);
 1379         }
 1380         break;
 1381 
 1382         /* copy the EEPROM in 2.4 Gz WaveMODEM  out to the caller */
 1383     case SIOCGWLEEPROM:
 1384         /* root only */
 1385         if ((error = suser(p->p_ucred, &p->p_acflag)))
 1386             break;
 1387         /* pointer to buffer in user space */
 1388         up = (void *)ifr->ifr_data;
 1389         
 1390         for (i=0x00; i<0x80; ++i) {             /* 2.4 Gz: size of EEPROM   */
 1391             MMC_WRITE(MMC_EEADDR,i);            /* 2.4 Gz: get frequency    */
 1392             MMC_WRITE(MMC_EECTRL,               /* 2.4 Gz: EEPROM read      */
 1393                         MMC_EECTRL_EEOP_READ);  /* 2.4 Gz:                  */
 1394             DELAY(40);                          /* 2.4 Gz                   */
 1395             if (subyte(up + 2*i  ,              /* 2.4 Gz: pass low byte of */
 1396                  wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word      */
 1397                ) return(EFAULT);                /* 2.4 Gz:                  */
 1398             if (subyte(up + 2*i+1,              /* 2.4 Gz: pass hi byte of  */
 1399                  wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word      */
 1400                ) return(EFAULT);                /* 2.4 Gz:                  */
 1401         }
 1402         break;
 1403 
 1404 #ifdef WLCACHE
 1405         /* zero (Delete) the wl cache */
 1406     case SIOCDWLCACHE:
 1407         /* root only */
 1408         if ((error = suser(p->p_ucred, &p->p_acflag)))
 1409             break;
 1410         wl_cache_zero(unit);
 1411         break;
 1412 
 1413         /* read out the number of used cache elements */
 1414     case SIOCGWLCITEM:
 1415         ifr->ifr_data = (caddr_t) sc->w_sigitems;
 1416         break;
 1417 
 1418         /* read out the wl cache */
 1419     case SIOCGWLCACHE:
 1420         /* pointer to buffer in user space */
 1421         up = (void *)ifr->ifr_data;
 1422         cpt = (char *) &sc->w_sigcache[0];
 1423         size = sc->w_sigitems * sizeof(struct w_sigcache);
 1424         
 1425         for (i = 0; i < size; i++) {
 1426             if (subyte((up + i), *cpt++))
 1427                 return(EFAULT);
 1428         }
 1429         break;
 1430 #endif
 1431 
 1432     default:
 1433         error = EINVAL;
 1434     }
 1435     splx(opri);
 1436     return (error);
 1437 }
 1438 
 1439 /*
 1440  * wlwatchdog():
 1441  *
 1442  * Called if the timer set in wlstart expires before an interrupt is received
 1443  * from the wavelan.   It seems to lose interrupts sometimes.
 1444  * The watchdog routine gets called if the transmitter failed to interrupt
 1445  *
 1446  * input        : which board is timing out
 1447  * output       : board reset 
 1448  *
 1449  */
 1450 static void
 1451 wlwatchdog(void *vsc)
 1452 {
 1453     struct wl_softc *sc = vsc;
 1454     int unit = sc->unit;
 1455 
 1456     log(LOG_ERR, "wl%d: wavelan device timeout on xmit\n", unit);
 1457     sc->wl_ac.ac_if.if_oerrors++;
 1458     wlinit(sc);
 1459 }
 1460 
 1461 /*
 1462  * wlintr:
 1463  *
 1464  *      This function is the interrupt handler for the WaveLAN
 1465  *      board.  This routine will be called whenever either a packet
 1466  *      is received, or a packet has successfully been transfered and
 1467  *      the unit is ready to transmit another packet.
 1468  *
 1469  * input        : board number that interrupted
 1470  * output       : either a packet is received, or a packet is transfered
 1471  *
 1472  */
 1473 void
 1474 wlintr(unit)
 1475 int unit;
 1476 {
 1477     register struct wl_softc *sc = &wl_softc[unit];
 1478     scb_t               scb;
 1479     ac_t                cb;
 1480     short               base = sc->base;
 1481     int                 next, x, opri;
 1482     int                 i, ac_status;
 1483     u_short             int_type, int_type1;
 1484 
 1485 #ifdef WLDEBUG
 1486     if (sc->wl_if.if_flags & IFF_DEBUG)
 1487         printf("wl%d: wlintr() called\n",unit);
 1488 #endif
 1489 
 1490     if((int_type = inw(HASR(base))) & HASR_MMC_INTR) {
 1491         /* handle interrupt from the modem management controler */
 1492         /* This will clear the interrupt condition */ 
 1493         (void) wlmmcread(base,MMC_DCE_STATUS); /* ignored for now */
 1494     }
 1495 
 1496     if(!(int_type & HASR_INTR)){        /* return if no interrupt from 82586 */
 1497         /* commented out. jrb.  it happens when reinit occurs
 1498            printf("wlintr: int_type %x, dump follows\n", int_type);
 1499            wldump(unit);
 1500            */
 1501         return;
 1502     }
 1503 
 1504     if (gathersnr)
 1505         getsnr(unit);
 1506     for(;;) {
 1507         outw(PIOR0(base), OFFSET_SCB + 0);      /* get scb status */
 1508         int_type = (inw(PIOP0(base)) & SCB_SW_INT);
 1509         if (int_type == 0)                      /* no interrupts left */
 1510             break;
 1511 
 1512         int_type1 = wlack(unit);                /* acknowledge interrupt(s) */
 1513         /* make sure no bits disappeared (others may appear) */
 1514         if ((int_type & int_type1) != int_type)
 1515             printf("wlack() int bits disappeared : %04x != int_type %04x\n",
 1516                    int_type1, int_type);
 1517         int_type = int_type1;                   /* go with the new status */
 1518         /* 
 1519          * incoming packet
 1520          */
 1521         if (int_type & SCB_SW_FR) {
 1522             sc->wl_if.if_ipackets++;
 1523             wlrcv(unit);
 1524         }
 1525         /*
 1526          * receiver not ready
 1527          */
 1528         if (int_type & SCB_SW_RNR) {
 1529             sc->wl_if.if_ierrors++;
 1530 #ifdef  WLDEBUG
 1531             if (sc->wl_if.if_flags & IFF_DEBUG)
 1532                 printf("wl%d intr(): receiver overrun! begin_fd = %x\n",
 1533                        unit, sc->begin_fd);
 1534 #endif
 1535             wlrustrt(unit);
 1536         }
 1537         /*
 1538          * CU not ready
 1539          */
 1540         if (int_type & SCB_SW_CNA) {
 1541             /*
 1542              * At present, we don't care about CNA's.  We
 1543              * believe they are a side effect of XMT.
 1544              */
 1545         }
 1546         if (int_type & SCB_SW_CX) {
 1547             /*
 1548              * At present, we only request Interrupt for
 1549              * XMT.
 1550              */
 1551             outw(PIOR1(base), OFFSET_CU);       /* get command status */
 1552             ac_status = inw(PIOP1(base));
 1553 
 1554             if (xmt_watch) {                    /* report some anomalies */
 1555 
 1556                 if (sc->tbusy == 0) {
 1557                     printf("wl%d: xmt intr but not busy, CU %04x\n",
 1558                            unit, ac_status);
 1559                 }
 1560                 if (ac_status == 0) {
 1561                     printf("wl%d: xmt intr but ac_status == 0\n", unit);
 1562                 }
 1563                 if (ac_status & AC_SW_A) {
 1564                     printf("wl%d: xmt aborted\n",unit);
 1565                 }
 1566 #ifdef  notdef
 1567                 if (ac_status & TC_CARRIER) {
 1568                     printf("wl%d: no carrier\n", unit);
 1569                 }
 1570 #endif  notdef
 1571                 if (ac_status & TC_CLS) {
 1572                     printf("wl%d: no CTS\n", unit);
 1573                 }
 1574                 if (ac_status & TC_DMA) {
 1575                     printf("wl%d: DMA underrun\n", unit);
 1576                 }
 1577                 if (ac_status & TC_DEFER) {
 1578                     printf("wl%d: xmt deferred\n",unit);
 1579                 }
 1580                 if (ac_status & TC_SQE) {
 1581                     printf("wl%d: heart beat\n", unit);
 1582                 }
 1583                 if (ac_status & TC_COLLISION) {
 1584                     printf("wl%d: too many collisions\n", unit);
 1585                 }
 1586             }
 1587             /* if the transmit actually failed, or returned some status */
 1588             if ((!(ac_status & AC_SW_OK)) || (ac_status & 0xfff)) {
 1589                 if (ac_status & (TC_COLLISION | TC_CLS | TC_DMA)) {
 1590                     sc->wl_if.if_oerrors++;
 1591                 }
 1592                 /* count collisions */
 1593                 sc->wl_if.if_collisions += (ac_status & 0xf);
 1594                 /* if TC_COLLISION set and collision count zero, 16 collisions */
 1595                 if ((ac_status & 0x20) == 0x20) {
 1596                     sc->wl_if.if_collisions += 0x10;
 1597                 }
 1598             }
 1599             sc->tbusy = 0;
 1600             untimeout(wlwatchdog, sc);
 1601             sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
 1602             wlstart(&(sc->wl_if));
 1603         }
 1604     }
 1605     return;
 1606 }
 1607 
 1608 /*
 1609  * wlrcv:
 1610  *
 1611  *      This routine is called by the interrupt handler to initiate a
 1612  *      packet transfer from the board to the "if" layer above this
 1613  *      driver.  This routine checks if a buffer has been successfully
 1614  *      received by the WaveLAN.  If so, the routine wlread is called
 1615  *      to do the actual transfer of the board data (including the
 1616  *      ethernet header) into a packet (consisting of an mbuf chain).
 1617  *
 1618  * input        : number of the board to check
 1619  * output       : if a packet is available, it is "sent up"
 1620  *
 1621  */
 1622 static void
 1623 wlrcv(int unit)
 1624 {
 1625     register struct wl_softc *sc = WLSOFTC(unit);
 1626     short       base = sc->base;
 1627     u_short     fd_p, status, offset, link_offset;
 1628 
 1629 #ifdef WLDEBUG
 1630     if (sc->wl_if.if_flags & IFF_DEBUG)
 1631         printf("wl%d: entered wlrcv()\n",unit);
 1632 #endif
 1633     for (fd_p = sc->begin_fd; fd_p != I82586NULL; fd_p = sc->begin_fd) {
 1634 
 1635         outw(PIOR0(base), fd_p + 0);    /* address of status */
 1636         status = inw(PIOP0(base));
 1637         outw(PIOR1(base), fd_p + 4);    /* address of link_offset */
 1638         link_offset = inw(PIOP1(base));
 1639         offset = inw(PIOP1(base));      /* rbd_offset */
 1640         if (status == 0xffff || offset == 0xffff /*I82586NULL*/) {
 1641             if (wlhwrst(unit) != TRUE)
 1642                 printf("wl%d rcv(): hwrst ffff trouble.\n", unit);
 1643             return;
 1644         } else if (status & AC_SW_C) {
 1645             if (status == (RFD_DONE|RFD_RSC)) {
 1646                 /* lost one */
 1647 #ifdef  WLDEBUG
 1648                 if (sc->wl_if.if_flags & IFF_DEBUG)
 1649                     printf("wl%d RCV: RSC %x\n", unit, status);
 1650 #endif
 1651                 sc->wl_if.if_ierrors++;
 1652             } else if (!(status & RFD_OK)) {
 1653                 printf("wl%d RCV: !OK %x\n", unit, status);
 1654                 sc->wl_if.if_ierrors++;
 1655             } else if (status & 0xfff) {        /* can't happen */
 1656                 printf("wl%d RCV: ERRs %x\n", unit, status);
 1657                 sc->wl_if.if_ierrors++;
 1658             } else if (!wlread(unit, fd_p))
 1659                 return;
 1660 
 1661             if (!wlrequeue(unit, fd_p)) {
 1662                 /* abort on chain error */
 1663                 if (wlhwrst(unit) != TRUE)
 1664                     printf("wl%d rcv(): hwrst trouble.\n", unit);
 1665                 return;
 1666             }
 1667             sc->begin_fd = link_offset;
 1668         } else {
 1669             break;
 1670         }
 1671     }
 1672     return;
 1673 }
 1674 
 1675 /*
 1676  * wlrequeue:
 1677  *
 1678  *      This routine puts rbd's used in the last receive back onto the
 1679  *      free list for the next receive.
 1680  *
 1681  */
 1682 static int
 1683 wlrequeue(int unit, u_short fd_p)
 1684 {
 1685     register struct wl_softc *sc = WLSOFTC(unit);
 1686     short               base = sc->base;
 1687     fd_t                fd;
 1688     u_short             l_rbdp, f_rbdp, rbd_offset;
 1689 
 1690     outw(PIOR0(base), fd_p + 6);
 1691     rbd_offset = inw(PIOP0(base));
 1692     if ((f_rbdp = rbd_offset) != I82586NULL) {
 1693         l_rbdp = f_rbdp;
 1694         for(;;) {
 1695             outw(PIOR0(base), l_rbdp + 0);      /* address of status */
 1696             if(inw(PIOP0(base)) & RBD_SW_EOF)
 1697                 break;
 1698             outw(PIOP0(base), 0);
 1699             outw(PIOR0(base), l_rbdp + 2);      /* next_rbd_offset */
 1700             if((l_rbdp = inw(PIOP0(base))) == I82586NULL)
 1701                 break;
 1702         }
 1703         outw(PIOP0(base), 0);
 1704         outw(PIOR0(base), l_rbdp + 2);          /* next_rbd_offset */
 1705         outw(PIOP0(base), I82586NULL);
 1706         outw(PIOR0(base), l_rbdp + 8);          /* address of size */
 1707         outw(PIOP0(base), inw(PIOP0(base)) | AC_CW_EL);
 1708         outw(PIOR0(base), sc->end_rbd + 2);
 1709         outw(PIOP0(base), f_rbdp);              /* end_rbd->next_rbd_offset */
 1710         outw(PIOR0(base), sc->end_rbd + 8);     /* size */
 1711         outw(PIOP0(base), inw(PIOP0(base)) & ~AC_CW_EL);
 1712         sc->end_rbd = l_rbdp;
 1713     }
 1714 
 1715     fd.status = 0;
 1716     fd.command = AC_CW_EL;
 1717     fd.link_offset = I82586NULL;
 1718     fd.rbd_offset = I82586NULL;
 1719     outw(PIOR1(base), fd_p);
 1720     outsw(PIOP1(base), &fd, 8/2);
 1721     
 1722     outw(PIOR1(base), sc->end_fd + 2);  /* addr of command */
 1723     outw(PIOP1(base), 0);               /* command = 0 */
 1724     outw(PIOP1(base), fd_p);            /* end_fd->link_offset = fd_p */
 1725     sc->end_fd = fd_p;
 1726 
 1727     return 1;
 1728 }
 1729 
 1730 #ifdef  WLDEBUG
 1731 static int xmt_debug = 0;
 1732 #endif  WLDEBUG
 1733 
 1734 /*
 1735  * wlxmt:
 1736  *
 1737  *      This routine fills in the appropriate registers and memory
 1738  *      locations on the WaveLAN board and starts the board off on
 1739  *      the transmit.
 1740  *
 1741  * input        : board number of interest, and a pointer to the mbuf
 1742  * output       : board memory and registers are set for xfer and attention
 1743  *
 1744  */
 1745 static void
 1746 wlxmt(int unit, struct mbuf *m)
 1747 {
 1748     register struct wl_softc *sc = WLSOFTC(unit);
 1749     register u_short            xmtdata_p = OFFSET_TBUF;
 1750     register u_short            xmtshort_p;
 1751     struct      mbuf                    *tm_p = m;
 1752     register struct ether_header        *eh_p = mtod(m, struct ether_header *);
 1753     u_char                              *mb_p = mtod(m, u_char *) + sizeof(struct ether_header);
 1754     u_short                             count = m->m_len - sizeof(struct ether_header);
 1755     ac_t                                cb;
 1756     u_short                             tbd_p = OFFSET_TBD;
 1757     u_short                             len, clen = 0;
 1758     short                               base = sc->base;
 1759     int                                 spin;
 1760         
 1761 #ifdef WLDEBUG
 1762     if (sc->wl_if.if_flags & IFF_DEBUG)
 1763         printf("wl%d: entered wlxmt()\n",unit);
 1764 #endif
 1765 
 1766     cb.ac_status = 0;
 1767     cb.ac_command = (AC_CW_EL|AC_TRANSMIT|AC_CW_I);
 1768     cb.ac_link_offset = I82586NULL;
 1769     outw(PIOR1(base), OFFSET_CU);
 1770     outsw(PIOP1(base), &cb, 6/2);
 1771     outw(PIOP1(base), OFFSET_TBD);      /* cb.cmd.transmit.tbd_offset */
 1772     outsw(PIOP1(base), eh_p->ether_dhost, WAVELAN_ADDR_SIZE/2);
 1773     outw(PIOP1(base), eh_p->ether_type);
 1774 
 1775 #ifdef  WLDEBUG
 1776     if (sc->wl_if.if_flags & IFF_DEBUG) {
 1777         if (xmt_debug) {
 1778             printf("XMT    mbuf: L%d @%x ", count, mb_p);
 1779             printf("ether type %x\n", eh_p->ether_type);
 1780         }
 1781     }
 1782 #endif  WLDEBUG
 1783     outw(PIOR0(base), OFFSET_TBD);
 1784     outw(PIOP0(base), 0);               /* act_count */
 1785     outw(PIOR1(base), OFFSET_TBD + 4);
 1786     outw(PIOP1(base), xmtdata_p);       /* buffer_addr */
 1787     outw(PIOP1(base), 0);               /* buffer_base */
 1788     for (;;) {
 1789         if (count) {
 1790             if (clen + count > WAVELAN_MTU)
 1791                 break;
 1792             if (count & 1)
 1793                 len = count + 1;
 1794             else
 1795                 len = count;
 1796             outw(PIOR1(base), xmtdata_p);
 1797             outsw(PIOP1(base), mb_p, len/2);
 1798             clen += count;
 1799             outw(PIOR0(base), tbd_p);  /* address of act_count */
 1800             outw(PIOP0(base), inw(PIOP0(base)) + count);
 1801             xmtdata_p += len;
 1802             if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
 1803                 break;
 1804             if (count & 1) {
 1805                 /* go to the next descriptor */
 1806                 outw(PIOR0(base), tbd_p + 2);
 1807                 tbd_p += sizeof (tbd_t);
 1808                 outw(PIOP0(base), tbd_p); /* next_tbd_offset */
 1809                 outw(PIOR0(base), tbd_p);
 1810                 outw(PIOP0(base), 0);   /* act_count */
 1811                 outw(PIOR1(base), tbd_p + 4);
 1812                 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
 1813                 outw(PIOP1(base), 0);         /* buffer_base */
 1814                 /* at the end -> coallesce remaining mbufs */
 1815                 if (tbd_p == OFFSET_TBD + (N_TBD-1) * sizeof (tbd_t)) {
 1816                     wlsftwsleaze(&count, &mb_p, &tm_p, unit);
 1817                     continue;
 1818                 }
 1819                 /* next mbuf short -> coallesce as needed */
 1820                 if ( (tm_p->m_next == (struct mbuf *) 0) ||
 1821 #define HDW_THRESHOLD 55
 1822                      tm_p->m_len > HDW_THRESHOLD)
 1823                     /* ok */;
 1824                 else {
 1825                     wlhdwsleaze(&count, &mb_p, &tm_p, unit);
 1826                     continue;
 1827                 }
 1828             }
 1829         } else if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
 1830             break;
 1831         count = tm_p->m_len;
 1832         mb_p = mtod(tm_p, u_char *);
 1833 #ifdef  WLDEBUG
 1834         if (sc->wl_if.if_flags & IFF_DEBUG)
 1835             if (xmt_debug)
 1836                 printf("mbuf+ L%d @%x ", count, mb_p);
 1837 #endif  WLDEBUG
 1838     }
 1839 #ifdef  WLDEBUG
 1840     if (sc->wl_if.if_flags & IFF_DEBUG)
 1841         if (xmt_debug)
 1842             printf("CLEN = %d\n", clen);
 1843 #endif  WLDEBUG
 1844     outw(PIOR0(base), tbd_p);
 1845     if (clen < ETHERMIN) {
 1846         outw(PIOP0(base), inw(PIOP0(base)) + ETHERMIN - clen);
 1847         outw(PIOR1(base), xmtdata_p);
 1848         for (xmtshort_p = xmtdata_p; clen < ETHERMIN; clen += 2)
 1849             outw(PIOP1(base), 0);
 1850     }   
 1851     outw(PIOP0(base), inw(PIOP0(base)) | TBD_SW_EOF);
 1852     outw(PIOR0(base), tbd_p + 2);
 1853     outw(PIOP0(base), I82586NULL);
 1854 #ifdef  WLDEBUG
 1855     if (sc->wl_if.if_flags & IFF_DEBUG) {
 1856         if (xmt_debug) {
 1857             wltbd(unit);
 1858             printf("\n");
 1859         }
 1860     }
 1861 #endif  WLDEBUG
 1862 
 1863     outw(PIOR0(base), OFFSET_SCB + 2);  /* address of scb_command */
 1864     /* 
 1865      * wait for 586 to clear previous command, complain if it takes
 1866      * too long
 1867      */
 1868     for (spin = 1;;spin = (spin + 1) % 10000) {
 1869         if (inw(PIOP0(base)) == 0) {            /* it's done, we can go */
 1870             break;
 1871         }
 1872         if ((spin == 0) && xmt_watch) {         /* not waking up, and we care */
 1873                 printf("wl%d: slow accepting xmit\n",unit);
 1874         }
 1875     }
 1876     outw(PIOP0(base), SCB_CU_STRT);             /* new command */
 1877     SET_CHAN_ATTN(unit);
 1878     
 1879     m_freem(m);
 1880 
 1881     /* XXX 
 1882      * Pause to avoid transmit overrun problems.
 1883      * The required delay tends to vary with platform type, and may be
 1884      * related to interrupt loss.
 1885      */
 1886     if (wl_xmit_delay) {
 1887         DELAY(wl_xmit_delay);
 1888     }
 1889     return;
 1890 }
 1891 
 1892 /*
 1893  * wlbldru:
 1894  *
 1895  *      This function builds the linear linked lists of fd's and
 1896  *      rbd's.  Based on page 4-32 of 1986 Intel microcom handbook.
 1897  *
 1898  */
 1899 static u_short
 1900 wlbldru(int unit)
 1901 {
 1902     register struct wl_softc *sc = WLSOFTC(unit);
 1903     short       base = sc->base;
 1904     fd_t        fd;
 1905     rbd_t       rbd;
 1906     u_short     fd_p = OFFSET_RU;
 1907     u_short     rbd_p = OFFSET_RBD;
 1908     int         i;
 1909 
 1910     sc->begin_fd = fd_p;
 1911     for(i = 0; i < N_FD; i++) {
 1912         fd.status = 0;
 1913         fd.command = 0;
 1914         fd.link_offset = fd_p + sizeof(fd_t);
 1915         fd.rbd_offset = I82586NULL;
 1916         outw(PIOR1(base), fd_p);
 1917         outsw(PIOP1(base), &fd, 8/2);
 1918         fd_p = fd.link_offset;
 1919     }
 1920     fd_p -= sizeof(fd_t);
 1921     sc->end_fd = fd_p;
 1922     outw(PIOR1(base), fd_p + 2);
 1923     outw(PIOP1(base), AC_CW_EL);        /* command */
 1924     outw(PIOP1(base), I82586NULL);      /* link_offset */
 1925     fd_p = OFFSET_RU;
 1926     
 1927     outw(PIOR0(base), fd_p + 6);        /* address of rbd_offset */
 1928     outw(PIOP0(base), rbd_p);
 1929     outw(PIOR1(base), rbd_p);
 1930     for(i = 0; i < N_RBD; i++) {
 1931         rbd.status = 0;
 1932         rbd.buffer_addr = rbd_p + sizeof(rbd_t) + 2;
 1933         rbd.buffer_base = 0;
 1934         rbd.size = RCVBUFSIZE;
 1935         if (i != N_RBD-1) {
 1936             rbd_p += sizeof(ru_t);
 1937             rbd.next_rbd_offset = rbd_p;
 1938         } else {
 1939             rbd.next_rbd_offset = I82586NULL;
 1940             rbd.size |= AC_CW_EL;
 1941             sc->end_rbd = rbd_p;
 1942         }
 1943         outsw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
 1944         outw(PIOR1(base), rbd_p);
 1945     }
 1946     return sc->begin_fd;
 1947 }
 1948 
 1949 /*
 1950  * wlrustrt:
 1951  *
 1952  *      This routine starts the receive unit running.  First checks if the
 1953  *      board is actually ready, then the board is instructed to receive
 1954  *      packets again.
 1955  *
 1956  */
 1957 static void
 1958 wlrustrt(int unit)
 1959 {
 1960     register struct wl_softc *sc = WLSOFTC(unit);
 1961     short               base = sc->base;
 1962     u_short             rfa;
 1963 
 1964 #ifdef WLDEBUG
 1965     if (sc->wl_if.if_flags & IFF_DEBUG)
 1966         printf("wl%d: entered wlrustrt()\n",unit);
 1967 #endif
 1968     outw(PIOR0(base), OFFSET_SCB);
 1969     if (inw(PIOP0(base)) & SCB_RUS_READY){
 1970         printf("wlrustrt: RUS_READY\n");
 1971         return;
 1972     }
 1973 
 1974     outw(PIOR0(base), OFFSET_SCB + 2);
 1975     outw(PIOP0(base), SCB_RU_STRT);             /* command */
 1976     rfa = wlbldru(unit);
 1977     outw(PIOR0(base), OFFSET_SCB + 6);  /* address of scb_rfa_offset */
 1978     outw(PIOP0(base), rfa);
 1979 
 1980     SET_CHAN_ATTN(unit);
 1981     return;
 1982 }
 1983 
 1984 /*
 1985  * wldiag:
 1986  *
 1987  *      This routine does a 586 op-code number 7, and obtains the
 1988  *      diagnose status for the WaveLAN.
 1989  *
 1990  */
 1991 static int
 1992 wldiag(int unit)
 1993 {
 1994     register struct wl_softc *sc = WLSOFTC(unit);
 1995     short               base = sc->base;
 1996     short status;
 1997 
 1998 #ifdef WLDEBUG
 1999     if (sc->wl_if.if_flags & IFF_DEBUG)
 2000         printf("wl%d: entered wldiag()\n",unit);
 2001 #endif
 2002     outw(PIOR0(base), OFFSET_SCB);
 2003     status = inw(PIOP0(base));
 2004     if (status & SCB_SW_INT) {
 2005                 /* state is 2000 which seems ok
 2006                    printf("wl%d diag(): unexpected initial state %\n",
 2007                    unit, inw(PIOP0(base)));
 2008                 */
 2009         wlack(unit);
 2010     }
 2011     outw(PIOR1(base), OFFSET_CU);
 2012     outw(PIOP1(base), 0);                       /* ac_status */
 2013     outw(PIOP1(base), AC_DIAGNOSE|AC_CW_EL);/* ac_command */
 2014     if(wlcmd(unit, "diag()") == 0)
 2015         return 0;
 2016     outw(PIOR0(base), OFFSET_CU);
 2017     if (inw(PIOP0(base)) & 0x0800) {
 2018         printf("wl%d: i82586 Self Test failed!\n", unit);
 2019         return 0;
 2020     }
 2021     return TRUE;
 2022 }
 2023 
 2024 /*
 2025  * wlconfig:
 2026  *
 2027  *      This routine does a standard config of the WaveLAN board.
 2028  *
 2029  */
 2030 static int
 2031 wlconfig(int unit)
 2032 {
 2033     configure_t configure;
 2034     register struct wl_softc *sc = WLSOFTC(unit);
 2035     short               base = sc->base;
 2036 
 2037 #if     MULTICAST
 2038 #if __FreeBSD__ >= 3
 2039     struct ifmultiaddr *ifma;
 2040     u_char *addrp;
 2041 #else
 2042     struct ether_multi *enm;
 2043     struct ether_multistep step;
 2044 #endif
 2045     int cnt = 0;
 2046 #endif  MULTICAST
 2047 
 2048 #ifdef WLDEBUG
 2049     if (sc->wl_if.if_flags & IFF_DEBUG)
 2050         printf("wl%d: entered wlconfig()\n",unit);
 2051 #endif
 2052     outw(PIOR0(base), OFFSET_SCB);
 2053     if (inw(PIOP0(base)) & SCB_SW_INT) {
 2054         /*
 2055           printf("wl%d config(): unexpected initial state %x\n",
 2056           unit, inw(PIOP0(base)));
 2057           */
 2058     }
 2059     wlack(unit);
 2060 
 2061     outw(PIOR1(base), OFFSET_CU);
 2062     outw(PIOP1(base), 0);                               /* ac_status */
 2063     outw(PIOP1(base), AC_CONFIGURE|AC_CW_EL);   /* ac_command */
 2064 
 2065 /* jrb hack */
 2066     configure.fifolim_bytecnt   = 0x080c;
 2067     configure.addrlen_mode      = 0x0600;
 2068     configure.linprio_interframe        = 0x2060;
 2069     configure.slot_time         = 0xf200;
 2070     configure.hardware          = 0x0008;       /* tx even w/o CD */
 2071     configure.min_frame_len     = 0x0040;
 2072 #if 0
 2073     /* This is the configuration block suggested by Marc Meertens
 2074      * <mmeerten@obelix.utrecht.NCR.COM> in an e-mail message to John
 2075      * Ioannidis on 10 Nov 92.
 2076      */
 2077     configure.fifolim_bytecnt   = 0x040c;
 2078     configure.addrlen_mode      = 0x0600;
 2079     configure.linprio_interframe        = 0x2060;
 2080     configure.slot_time         = 0xf000;
 2081     configure.hardware          = 0x0008;       /* tx even w/o CD */
 2082     configure.min_frame_len     = 0x0040;
 2083 #else
 2084     /*
 2085      * below is the default board configuration from p2-28 from 586 book
 2086      */
 2087     configure.fifolim_bytecnt   = 0x080c;
 2088     configure.addrlen_mode      = 0x2600;
 2089     configure.linprio_interframe        = 0x7820;       /* IFS=120, ACS=2 */
 2090     configure.slot_time         = 0xf00c;       /* slottime=12    */
 2091     configure.hardware          = 0x0008;       /* tx even w/o CD */
 2092     configure.min_frame_len     = 0x0040;
 2093 #endif
 2094     if(sc->mode & (MOD_PROM | MOD_ENAL)) {
 2095         configure.hardware |= 1;
 2096     }
 2097     outw(PIOR1(base), OFFSET_CU + 6);
 2098     outsw(PIOP1(base), &configure, sizeof(configure_t)/2);
 2099 
 2100     if(wlcmd(unit, "config()-configure") == 0)
 2101         return 0;
 2102 #if     MULTICAST
 2103     outw(PIOR1(base), OFFSET_CU);
 2104     outw(PIOP1(base), 0);                               /* ac_status */
 2105     outw(PIOP1(base), AC_MCSETUP|AC_CW_EL);             /* ac_command */
 2106     outw(PIOR1(base), OFFSET_CU + 8);
 2107 #if __FreeBSD__ >= 3
 2108     for (ifma = sc->wl_if.if_multiaddrs.lh_first; ifma;
 2109          ifma = ifma->ifma_link.le_next) {
 2110         if (ifma->ifma_addr->sa_family != AF_LINK)
 2111             continue;
 2112         
 2113         addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
 2114         outw(PIOP1(base), addrp[0] + (addrp[1] << 8));
 2115         outw(PIOP1(base), addrp[2] + (addrp[3] << 8));
 2116         outw(PIOP1(base), addrp[4] + (addrp[5] << 8));
 2117         ++cnt;
 2118     }
 2119 #else
 2120     ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
 2121     while (enm != NULL) {
 2122         unsigned int lo, hi;
 2123         /* break if setting a multicast range, else we would crash */
 2124         if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
 2125                 break;
 2126         }
 2127         lo = (enm->enm_addrlo[3] << 16) + (enm->enm_addrlo[4] << 8)
 2128             + enm->enm_addrlo[5];
 2129         hi = (enm->enm_addrhi[3] << 16) + (enm->enm_addrhi[4] << 8)
 2130             + enm->enm_addrhi[5];
 2131         while(lo <= hi) {
 2132             outw(PIOP1(base),enm->enm_addrlo[0] +
 2133                  (enm->enm_addrlo[1] << 8));
 2134             outw(PIOP1(base),enm->enm_addrlo[2] +
 2135                  ((lo >> 8) & 0xff00));
 2136             outw(PIOP1(base), ((lo >> 8) & 0xff) +
 2137                  ((lo << 8) & 0xff00));
 2138 /* #define MCASTDEBUG */
 2139 #ifdef MCASTDEBUG
 2140 printf("mcast_addr[%d,%d,%d] %x %x %x %x %x %x\n", lo, hi, cnt,
 2141                 enm->enm_addrlo[0],
 2142                 enm->enm_addrlo[1],
 2143                 enm->enm_addrlo[2],
 2144                 enm->enm_addrlo[3],
 2145                 enm->enm_addrlo[4],
 2146                 enm->enm_addrlo[5]);
 2147 #endif
 2148             ++cnt;
 2149             ++lo;
 2150         }
 2151         ETHER_NEXT_MULTI(step, enm);
 2152     }
 2153 #endif
 2154     outw(PIOR1(base), OFFSET_CU + 6);           /* mc-cnt */
 2155     outw(PIOP1(base), cnt * WAVELAN_ADDR_SIZE);
 2156     if(wlcmd(unit, "config()-mcaddress") == 0)
 2157         return 0;
 2158 #endif  MULTICAST
 2159 
 2160     outw(PIOR1(base), OFFSET_CU);
 2161     outw(PIOP1(base), 0);                               /* ac_status */
 2162     outw(PIOP1(base), AC_IASETUP|AC_CW_EL);             /* ac_command */
 2163     outw(PIOR1(base), OFFSET_CU + 6);
 2164     outsw(PIOP1(base), sc->wl_addr, WAVELAN_ADDR_SIZE/2);
 2165 
 2166     if(wlcmd(unit, "config()-address") == 0)
 2167         return(0);
 2168 
 2169     wlinitmmc(unit);
 2170 
 2171     return(1);
 2172 }
 2173 
 2174 /*
 2175  * wlcmd:
 2176  *
 2177  * Set channel attention bit and busy wait until command has
 2178  * completed. Then acknowledge the command completion.
 2179  */
 2180 static int
 2181 wlcmd(int unit, char *str)
 2182 {
 2183     register struct wl_softc *sc = WLSOFTC(unit);
 2184     short       base = sc->base;
 2185     int i;
 2186         
 2187     outw(PIOR0(base), OFFSET_SCB + 2);  /* address of scb_command */
 2188     outw(PIOP0(base), SCB_CU_STRT);
 2189     
 2190     SET_CHAN_ATTN(unit);
 2191     
 2192     outw(PIOR0(base), OFFSET_CU);
 2193     for(i = 0; i < 0xffff; i++)
 2194         if (inw(PIOP0(base)) & AC_SW_C)
 2195             break;
 2196     if (i == 0xffff || !(inw(PIOP0(base)) & AC_SW_OK)) {
 2197         printf("wl%d: %s failed; status = %d, inw = %x, outw = %x\n",
 2198                unit, str, inw(PIOP0(base)) & AC_SW_OK, inw(PIOP0(base)), inw(PIOR0(base)));
 2199         outw(PIOR0(base), OFFSET_SCB);
 2200         printf("scb_status %x\n", inw(PIOP0(base)));
 2201         outw(PIOR0(base), OFFSET_SCB+2);
 2202         printf("scb_command %x\n", inw(PIOP0(base)));
 2203         outw(PIOR0(base), OFFSET_SCB+4);
 2204         printf("scb_cbl %x\n", inw(PIOP0(base)));
 2205         outw(PIOR0(base), OFFSET_CU+2);
 2206         printf("cu_cmd %x\n", inw(PIOP0(base)));
 2207         return(0);
 2208     }
 2209 
 2210     outw(PIOR0(base), OFFSET_SCB);
 2211     if ((inw(PIOP0(base)) & SCB_SW_INT) && (inw(PIOP0(base)) != SCB_SW_CNA)) {
 2212         /*
 2213           printf("wl%d %s: unexpected final state %x\n",
 2214           unit, str, inw(PIOP0(base)));
 2215           */
 2216     }
 2217     wlack(unit);
 2218     return(TRUE);
 2219 }       
 2220 
 2221 /*
 2222  * wlack: if the 82596 wants attention because it has finished
 2223  * sending or receiving a packet, acknowledge its desire and
 2224  * return bits indicating the kind of attention. wlack() returns
 2225  * these bits so that the caller can service exactly the
 2226  * conditions that wlack() acknowledged.
 2227  */
 2228 static int
 2229 wlack(int unit)
 2230 {
 2231     int i;
 2232     register u_short cmd;
 2233     register struct wl_softc *sc = WLSOFTC(unit);
 2234     short base = sc->base;
 2235 
 2236     outw(PIOR1(base), OFFSET_SCB);
 2237     if(!(cmd = (inw(PIOP1(base)) & SCB_SW_INT)))
 2238         return(0);
 2239 #ifdef WLDEBUG
 2240     if (sc->wl_if.if_flags & IFF_DEBUG)
 2241         printf("wl%d: doing a wlack()\n",unit);
 2242 #endif
 2243     outw(PIOP1(base), cmd);
 2244     SET_CHAN_ATTN(unit);
 2245     outw(PIOR0(base), OFFSET_SCB + 2);  /* address of scb_command */
 2246     for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
 2247     if (i < 1)
 2248         printf("wl%d wlack(): board not accepting command.\n", unit);
 2249     return(cmd);
 2250 }
 2251 
 2252 static void
 2253 wltbd(int unit)
 2254 {
 2255     register struct wl_softc *sc = WLSOFTC(unit);
 2256     short               base = sc->base;
 2257     u_short             tbd_p = OFFSET_TBD;
 2258     tbd_t               tbd;
 2259     int                 i = 0;
 2260     int                 sum = 0;
 2261 
 2262     for (;;) {
 2263         outw(PIOR1(base), tbd_p);
 2264         insw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
 2265         sum += (tbd.act_count & ~TBD_SW_EOF);
 2266         printf("%d: addr %x, count %d (%d), next %x, base %x\n",
 2267                i++, tbd.buffer_addr,
 2268                (tbd.act_count & ~TBD_SW_EOF), sum,
 2269                tbd.next_tbd_offset, tbd.buffer_base);
 2270         if (tbd.act_count & TBD_SW_EOF)
 2271             break;
 2272         tbd_p = tbd.next_tbd_offset;
 2273     }
 2274 }
 2275 
 2276 static void
 2277 wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
 2278 {
 2279     struct mbuf *tm_p = *tm_pp;
 2280     u_char              *mb_p = *mb_pp;
 2281     u_short             count = 0;
 2282     u_char              *cp;
 2283     int         len;
 2284 
 2285     /*
 2286      * can we get a run that will be coallesced or
 2287      * that terminates before breaking
 2288      */
 2289     do {
 2290         count += tm_p->m_len;
 2291         if (tm_p->m_len & 1)
 2292             break;
 2293     } while ((tm_p = tm_p->m_next) != (struct mbuf *)0);
 2294     if ( (tm_p == (struct mbuf *)0) ||
 2295          count > HDW_THRESHOLD) {
 2296         *countp = (*tm_pp)->m_len;
 2297         *mb_pp = mtod((*tm_pp), u_char *);
 2298         return;
 2299     }
 2300 
 2301     /* we need to copy */
 2302     tm_p = *tm_pp;
 2303     mb_p = *mb_pp;
 2304     count = 0;
 2305     cp = (u_char *) t_packet;
 2306     for (;;) {
 2307         bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
 2308         count += len;
 2309         if (count > HDW_THRESHOLD)
 2310                         break;
 2311         cp += len;
 2312         if (tm_p->m_next == (struct mbuf *)0)
 2313             break;
 2314         tm_p = tm_p->m_next;
 2315     }
 2316     *countp = count;
 2317     *mb_pp = (u_char *) t_packet;
 2318     *tm_pp = tm_p;
 2319     return;
 2320 }
 2321 
 2322 
 2323 static void
 2324 wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
 2325 {
 2326     struct mbuf *tm_p = *tm_pp;
 2327     u_char              *mb_p = *mb_pp;
 2328     u_short             count = 0;
 2329     u_char              *cp = (u_char *) t_packet;
 2330     int                 len;
 2331 
 2332     /* we need to copy */
 2333     for (;;) {
 2334         bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
 2335         count += len;
 2336         cp += len;
 2337         if (tm_p->m_next == (struct mbuf *)0)
 2338             break;
 2339         tm_p = tm_p->m_next;
 2340     }
 2341 
 2342     *countp = count;
 2343     *mb_pp = (u_char *) t_packet;
 2344     *tm_pp = tm_p;
 2345     return;
 2346 }
 2347 
 2348 static void
 2349 wlmmcstat(int unit)
 2350 {
 2351     register struct wl_softc *sc = WLSOFTC(unit);
 2352     short       base = sc->base;
 2353     u_short tmp;
 2354 
 2355     printf("wl%d: DCE_STATUS: 0x%x, ", unit,
 2356            wlmmcread(base,MMC_DCE_STATUS) & 0x0f);
 2357     tmp = wlmmcread(base,MMC_CORRECT_NWID_H) << 8;
 2358     tmp |= wlmmcread(base,MMC_CORRECT_NWID_L);
 2359     printf("Correct NWID's: %d, ", tmp);
 2360     tmp = wlmmcread(base,MMC_WRONG_NWID_H) << 8;
 2361     tmp |= wlmmcread(base,MMC_WRONG_NWID_L);
 2362     printf("Wrong NWID's: %d\n", tmp);
 2363     printf("THR_PRE_SET: 0x%x, ", wlmmcread(base,MMC_THR_PRE_SET));
 2364     printf("SIGNAL_LVL: %d, SILENCE_LVL: %d\n", 
 2365            wlmmcread(base,MMC_SIGNAL_LVL),
 2366            wlmmcread(base,MMC_SILENCE_LVL));
 2367     printf("SIGN_QUAL: 0x%x, NETW_ID: %x:%x, DES: %d\n",
 2368            wlmmcread(base,MMC_SIGN_QUAL),
 2369            wlmmcread(base,MMC_NETW_ID_H),
 2370            wlmmcread(base,MMC_NETW_ID_L),
 2371            wlmmcread(base,MMC_DES_AVAIL));
 2372 }
 2373 
 2374 static u_short
 2375 wlmmcread(u_int base, u_short reg)
 2376 {
 2377     while(inw(HASR(base)) & HASR_MMC_BUSY) ;
 2378     outw(MMCR(base),reg << 1);
 2379     while(inw(HASR(base)) & HASR_MMC_BUSY) ;
 2380     return (u_short)inw(MMCR(base)) >> 8;
 2381 }
 2382 
 2383 static void
 2384 getsnr(int unit)
 2385 {
 2386     register struct wl_softc *sc = WLSOFTC(unit);
 2387     short       base = sc->base;
 2388     register int s;
 2389 
 2390     MMC_WRITE(MMC_FREEZE,1);
 2391     /* 
 2392      * SNR retrieval procedure :
 2393      *
 2394      * read signal level : wlmmcread(base, MMC_SIGNAL_LVL);
 2395      * read silence level : wlmmcread(base, MMC_SILENCE_LVL);
 2396      */
 2397     MMC_WRITE(MMC_FREEZE,0);
 2398     /*
 2399      * SNR is signal:silence ratio.
 2400      */
 2401 }
 2402 
 2403 /*
 2404 ** wlgetpsa
 2405 **
 2406 ** Reads the psa for the wavelan at (base) into (buf)
 2407 */
 2408 static void
 2409 wlgetpsa(int base, u_char *buf)
 2410 {
 2411     int i;
 2412 
 2413     PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
 2414     PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
 2415 
 2416     for (i = 0; i < 0x40; i++) {
 2417         outw(PIOR2(base), i);
 2418         buf[i] = inb(PIOP2(base));
 2419     }
 2420     PCMD(base, HACR_DEFAULT);
 2421     PCMD(base, HACR_DEFAULT);
 2422 }
 2423 
 2424 /*
 2425 ** wlsetpsa
 2426 **
 2427 ** Writes the psa for wavelan (unit) from the softc back to the
 2428 ** board.  Updates the CRC and sets the CRC OK flag.
 2429 **
 2430 ** Do not call this when the board is operating, as it doesn't 
 2431 ** preserve the hacr.
 2432 */
 2433 static void
 2434 wlsetpsa(int unit)
 2435 {
 2436     register struct wl_softc *sc = WLSOFTC(unit);
 2437     short       base = sc->base;
 2438     int         i, oldpri;
 2439     u_short     crc;
 2440 
 2441     crc = wlpsacrc(sc->psa);    /* calculate CRC of PSA */
 2442     sc->psa[WLPSA_CRCLOW] = crc & 0xff;
 2443     sc->psa[WLPSA_CRCHIGH] = (crc >> 8) & 0xff;
 2444     sc->psa[WLPSA_CRCOK] = 0x55;        /* default to 'bad' until programming complete */
 2445 
 2446     oldpri = splimp();          /* ick, long pause */
 2447     
 2448     PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
 2449     PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
 2450     
 2451     for (i = 0; i < 0x40; i++) {
 2452         DELAY(DELAYCONST);
 2453         outw(PIOR2(base),i);  /* write param memory */
 2454         DELAY(DELAYCONST);
 2455         outb(PIOP2(base), sc->psa[i]);
 2456     }
 2457     DELAY(DELAYCONST);
 2458     outw(PIOR2(base),WLPSA_CRCOK);  /* update CRC flag*/
 2459     DELAY(DELAYCONST);
 2460     sc->psa[WLPSA_CRCOK] = 0xaa;        /* OK now */
 2461     outb(PIOP2(base), 0xaa);    /* all OK */
 2462     DELAY(DELAYCONST);
 2463     
 2464     PCMD(base, HACR_DEFAULT);
 2465     PCMD(base, HACR_DEFAULT);
 2466     
 2467     splx(oldpri);
 2468 }
 2469 
 2470 /* 
 2471 ** CRC routine provided by Christopher Giordano <cgiordan@gdeb.com>,
 2472 ** from original code by Tomi Mikkonen (tomitm@remedy.fi)
 2473 */
 2474 
 2475 static u_int crc16_table[16] = { 
 2476     0x0000, 0xCC01, 0xD801, 0x1400,
 2477     0xF001, 0x3C00, 0x2800, 0xE401,
 2478     0xA001, 0x6C00, 0x7800, 0xB401,
 2479     0x5000, 0x9C01, 0x8801, 0x4400 
 2480 };
 2481 
 2482 static u_short
 2483 wlpsacrc(u_char *buf)
 2484 {
 2485     u_short     crc = 0;
 2486     int         i, r1;
 2487     
 2488     for (i = 0; i < 0x3d; i++, buf++) {
 2489         /* lower 4 bits */
 2490         r1 = crc16_table[crc & 0xF];
 2491         crc = (crc >> 4) & 0x0FFF;
 2492         crc = crc ^ r1 ^ crc16_table[*buf & 0xF];
 2493         
 2494         /* upper 4 bits */
 2495         r1 = crc16_table[crc & 0xF];
 2496         crc = (crc >> 4) & 0x0FFF;
 2497         crc = crc ^ r1 ^ crc16_table[(*buf >> 4) & 0xF];
 2498     }
 2499     return(crc);
 2500 }
 2501 #ifdef WLCACHE
 2502 
 2503 /*
 2504  * wl_cache_store
 2505  *
 2506  * take input packet and cache various radio hw characteristics
 2507  * indexed by MAC address.
 2508  *
 2509  * Some things to think about:
 2510  *      note that no space is malloced. 
 2511  *      We might hash the mac address if the cache were bigger.
 2512  *      It is not clear that the cache is big enough.
 2513  *              It is also not clear how big it should be.
 2514  *      The cache is IP-specific.  We don't care about that as
 2515  *              we want it to be IP-specific.
 2516  *      The last N recv. packets are saved.  This will tend
 2517  *              to reward agents and mobile hosts that beacon.
 2518  *              That is probably fine for mobile ip.
 2519  */
 2520 
 2521 /* globals for wavelan signal strength cache */
 2522 /* this should go into softc structure above. 
 2523 */
 2524 
 2525 /* set true if you want to limit cache items to broadcast/mcast 
 2526  * only packets (not unicast)
 2527  */
 2528 static int wl_cache_mcastonly = 1;
 2529 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_mcastonly, CTLFLAG_RW, 
 2530         &wl_cache_mcastonly, 0, "");
 2531 
 2532 /* set true if you want to limit cache items to IP packets only
 2533 */
 2534 static int wl_cache_iponly = 1;
 2535 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_iponly, CTLFLAG_RW, 
 2536         &wl_cache_iponly, 0, "");
 2537 
 2538 /* zero out the cache
 2539 */
 2540 static void
 2541 wl_cache_zero(int unit)
 2542 {
 2543         register struct wl_softc        *sc = WLSOFTC(unit);
 2544 
 2545         bzero(&sc->w_sigcache[0], sizeof(struct w_sigcache) * MAXCACHEITEMS);
 2546         sc->w_sigitems = 0;
 2547         sc->w_nextcache = 0;
 2548         sc->w_wrapindex = 0;
 2549 }
 2550 
 2551 /* store hw signal info in cache.
 2552  * index is MAC address, but an ip src gets stored too
 2553  * There are two filters here controllable via sysctl:
 2554  *      throw out unicast (on by default, but can be turned off)
 2555  *      throw out non-ip (on by default, but can be turned off)
 2556  */
 2557 static
 2558 void wl_cache_store (int unit, int base, struct ether_header *eh,
 2559                      struct mbuf *m)
 2560 {
 2561         struct ip *ip; 
 2562         int i;
 2563         int signal, silence;
 2564         int w_insertcache;   /* computed index for cache entry storage */
 2565         register struct wl_softc *sc = WLSOFTC(unit);
 2566         int ipflag = wl_cache_iponly;
 2567 
 2568         /* filters:
 2569          * 1. ip only
 2570          * 2. configurable filter to throw out unicast packets,
 2571          * keep multicast only.
 2572          */
 2573  
 2574         /* reject if not IP packet
 2575         */
 2576         if ( wl_cache_iponly && (ntohs(eh->ether_type) != 0x800)) {
 2577                 return;
 2578         }
 2579 
 2580         /* check if broadcast or multicast packet.  we toss
 2581          * unicast packets
 2582          */
 2583         if (wl_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
 2584                 return;
 2585         }
 2586 
 2587         /* find the ip header.  we want to store the ip_src
 2588          * address.  use the mtod macro(in mbuf.h) 
 2589          * to typecast m to struct ip *
 2590          */
 2591         if (ipflag) {
 2592                 ip = mtod(m, struct ip *);
 2593         }
 2594         
 2595         /* do a linear search for a matching MAC address 
 2596          * in the cache table
 2597          * . MAC address is 6 bytes,
 2598          * . var w_nextcache holds total number of entries already cached
 2599          */
 2600         for(i = 0; i < sc->w_nextcache; i++) {
 2601                 if (! bcmp(eh->ether_shost, sc->w_sigcache[i].macsrc,  6 )) {
 2602                         /* Match!,
 2603                          * so we already have this entry,
 2604                          * update the data, and LRU age
 2605                          */
 2606                         break;  
 2607                 }
 2608         }
 2609 
 2610         /* did we find a matching mac address?
 2611          * if yes, then overwrite a previously existing cache entry
 2612          */
 2613         if (i <  sc->w_nextcache )   {
 2614                 w_insertcache = i; 
 2615         }
 2616         /* else, have a new address entry,so
 2617          * add this new entry,
 2618          * if table full, then we need to replace entry
 2619          */
 2620         else    {                          
 2621 
 2622                 /* check for space in cache table 
 2623                  * note: w_nextcache also holds number of entries
 2624                  * added in the cache table 
 2625                  */
 2626                 if ( sc->w_nextcache < MAXCACHEITEMS ) {
 2627                         w_insertcache = sc->w_nextcache;
 2628                         sc->w_nextcache++;                 
 2629                         sc->w_sigitems = sc->w_nextcache;
 2630                 }
 2631                 /* no space found, so simply wrap with wrap index
 2632                  * and "zap" the next entry
 2633                  */
 2634                 else {
 2635                         if (sc->w_wrapindex == MAXCACHEITEMS) {
 2636                                 sc->w_wrapindex = 0;
 2637                         }
 2638                         w_insertcache = sc->w_wrapindex++;
 2639                 }
 2640         }
 2641 
 2642         /* invariant: w_insertcache now points at some slot
 2643          * in cache.
 2644          */
 2645         if (w_insertcache < 0 || w_insertcache >= MAXCACHEITEMS) {
 2646                 log(LOG_ERR, 
 2647                         "wl_cache_store, bad index: %d of [0..%d], gross cache error\n",
 2648                         w_insertcache, MAXCACHEITEMS);
 2649                 return;
 2650         }
 2651 
 2652         /*  store items in cache
 2653          *  .ipsrc
 2654          *  .macsrc
 2655          *  .signal (0..63) ,silence (0..63) ,quality (0..15)
 2656          */
 2657         if (ipflag) {
 2658                 sc->w_sigcache[w_insertcache].ipsrc = ip->ip_src.s_addr;
 2659         }
 2660         bcopy( eh->ether_shost, sc->w_sigcache[w_insertcache].macsrc,  6);
 2661         signal = sc->w_sigcache[w_insertcache].signal  = wlmmcread(base, MMC_SIGNAL_LVL) & 0x3f;
 2662         silence = sc->w_sigcache[w_insertcache].silence = wlmmcread(base, MMC_SILENCE_LVL) & 0x3f;
 2663         sc->w_sigcache[w_insertcache].quality = wlmmcread(base, MMC_SIGN_QUAL) & 0x0f;
 2664         if (signal > 0)
 2665                 sc->w_sigcache[w_insertcache].snr = 
 2666                         signal - silence;
 2667         else
 2668                 sc->w_sigcache[w_insertcache].snr = 0;
 2669 
 2670 }
 2671 #endif /* WLCACHE */
 2672 
 2673 /*
 2674  * determine if in all multicast mode or not
 2675  * 
 2676  * returns: 1 if IFF_ALLMULTI should be set
 2677  *          else 0
 2678  */
 2679 #ifdef MULTICAST
 2680 
 2681 #if __FreeBSD__ < 3     /* not required */
 2682 static int
 2683 check_allmulti(int unit)
 2684 {
 2685     register struct wl_softc *sc = WLSOFTC(unit);
 2686     short  base = sc->base;
 2687     struct ether_multi *enm;
 2688     struct ether_multistep step;
 2689 
 2690     ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
 2691     while (enm != NULL) {
 2692         unsigned int lo, hi;
 2693 #ifdef MDEBUG
 2694                 printf("enm_addrlo %x:%x:%x:%x:%x:%x\n", enm->enm_addrlo[0], enm->enm_addrlo[1],
 2695                 enm->enm_addrlo[2], enm->enm_addrlo[3], enm->enm_addrlo[4],
 2696                 enm->enm_addrlo[5]);
 2697                 printf("enm_addrhi %x:%x:%x:%x:%x:%x\n", enm->enm_addrhi[0], enm->enm_addrhi[1],
 2698                 enm->enm_addrhi[2], enm->enm_addrhi[3], enm->enm_addrhi[4],
 2699                 enm->enm_addrhi[5]);
 2700 #endif
 2701         if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
 2702                 return(1);
 2703         }
 2704         ETHER_NEXT_MULTI(step, enm);
 2705     }
 2706     return(0);
 2707 }
 2708 #endif
 2709 #endif

Cache object: 8f59ec08893052607c1bf5a8fdcb3464


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