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$ */
    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 ?
   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 #include "opt_inet.h"
  195 
  196 #include <sys/param.h>
  197 #include <sys/systm.h>
  198 #include <sys/sockio.h>
  199 #include <sys/mbuf.h>
  200 #include <sys/socket.h>
  201 #include <sys/syslog.h>
  202 #include <sys/proc.h>
  203 
  204 #include <sys/kernel.h>
  205 #include <sys/sysctl.h>
  206 
  207 #include <net/if.h>
  208 #include <net/if_dl.h>
  209 
  210 #ifdef INET
  211 #include <netinet/in.h>
  212 #include <netinet/in_systm.h>
  213 #include <netinet/ip.h>
  214 #include <netinet/if_ether.h>
  215 #endif
  216 
  217 #if NBPFILTER > 0
  218 #include <net/bpf.h>
  219 #endif
  220 
  221 #include <machine/clock.h>
  222 
  223 #include <i386/isa/isa_device.h>
  224 
  225 #include <i386/isa/ic/if_wl_i82586.h>   /* Definitions for the Intel chip */
  226 
  227 /* was 1000 in original, fed to DELAY(x) */
  228 #define DELAYCONST      1000
  229 #include <i386/isa/if_wl.h>
  230 #include <machine/if_wl_wavelan.h>
  231 
  232 static char     t_packet[ETHERMTU + sizeof(struct ether_header) + sizeof(long)];
  233 
  234 struct wl_softc{ 
  235     struct      arpcom  wl_ac;                  /* Ethernet common part */
  236 #define wl_if   wl_ac.ac_if                     /* network visible interface */
  237 #define wl_addr wl_ac.ac_enaddr                 /* hardware address */
  238     u_char      psa[0x40];
  239     u_char      nwid[2];        /* current radio modem nwid */
  240     short       base;
  241     short       unit;
  242     int         flags;
  243     int         tbusy;          /* flag to determine if xmit is busy */
  244     u_short     begin_fd;
  245     u_short     end_fd;
  246     u_short     end_rbd;
  247     u_short     hacr;           /* latest host adapter CR command */
  248     short       mode;
  249     u_char      chan24;         /* 2.4 Gz: channel number/EEPROM Area # */
  250     u_short     freq24;         /* 2.4 Gz: resulting frequency  */
  251     struct      callout_handle watchdog_ch;
  252 #ifdef WLCACHE
  253     int         w_sigitems;     /* number of cached entries */
  254     /*  array of cache entries */
  255     struct w_sigcache w_sigcache[ MAXCACHEITEMS ];            
  256     int w_nextcache;            /* next free cache entry */    
  257     int w_wrapindex;            /* next "free" cache entry */
  258 #endif
  259 };
  260 static struct wl_softc wl_softc[NWL];
  261 
  262 #define WLSOFTC(unit) ((struct wl_softc *)(&wl_softc[unit]))
  263 
  264 static int      wlprobe(struct isa_device *);
  265 static int      wlattach(struct isa_device *);
  266 
  267 struct isa_driver wldriver = {
  268     wlprobe, wlattach, "wl", 0
  269 };
  270 
  271 /*
  272  * XXX  The Wavelan appears to be prone to dropping stuff if you talk to
  273  * it too fast.  This disgusting hack inserts a delay after each packet
  274  * is queued which helps avoid this behaviour on fast systems.
  275  */
  276 static int      wl_xmit_delay = 250;
  277 SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_delay, CTLFLAG_RW, &wl_xmit_delay, 0, "");
  278 
  279 /* 
  280  * not XXX, but ZZZ (bizarre).
  281  * promiscuous mode can be toggled to ignore NWIDs.  By default,
  282  * it does not.  Caution should be exercised about combining
  283  * this mode with IFF_ALLMULTI which puts this driver in
  284  * promiscuous mode.
  285  */
  286 static int      wl_ignore_nwid = 0;
  287 SYSCTL_INT(_machdep, OID_AUTO, wl_ignore_nwid, CTLFLAG_RW, &wl_ignore_nwid, 0, "");
  288 
  289 /*
  290  * Emit diagnostics about transmission problems
  291  */
  292 static int      xmt_watch = 0;
  293 SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_watch, CTLFLAG_RW, &xmt_watch, 0, "");
  294 
  295 /*
  296  * Collect SNR statistics
  297  */
  298 static int      gathersnr = 0;
  299 SYSCTL_INT(_machdep, OID_AUTO, wl_gather_snr, CTLFLAG_RW, &gathersnr, 0, "");
  300 
  301 static void     wlstart(struct ifnet *ifp);
  302 static void     wlinit(void *xsc);
  303 static int      wlioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
  304 static timeout_t wlwatchdog;
  305 static ointhand2_t wlintr;
  306 static void     wlxmt(int unt, struct mbuf *m);
  307 static int      wldiag(int unt); 
  308 static int      wlconfig(int unit); 
  309 static int      wlcmd(int unit, char *str);
  310 static void     wlmmcstat(int unit);
  311 static u_short  wlbldru(int unit);
  312 static u_short  wlmmcread(u_int base, u_short reg);
  313 static void     wlinitmmc(int unit);
  314 static int      wlhwrst(int unit);
  315 static void     wlrustrt(int unit);
  316 static void     wlbldcu(int unit);
  317 static int      wlack(int unit);
  318 static int      wlread(int unit, u_short fd_p);
  319 static void     getsnr(int unit);
  320 static void     wlrcv(int unit);
  321 static int      wlrequeue(int unit, u_short fd_p);
  322 static void     wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
  323 static void     wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
  324 static void     wltbd(int unit);
  325 static void     wlgetpsa(int base, u_char *buf);
  326 static void     wlsetpsa(int unit);
  327 static u_short  wlpsacrc(u_char *buf);
  328 static void     wldump(int unit);
  329 #ifdef WLCACHE
  330 static void     wl_cache_store(int, int, struct ether_header *, struct mbuf *);
  331 static void     wl_cache_zero(int unit);
  332 #endif
  333 #ifdef MULTICAST
  334 # if defined(__FreeBSD__) && __FreeBSD_version < 300000
  335 static int      check_allmulti(int unit);
  336 # endif
  337 #endif
  338 
  339 /* array for maping irq numbers to values for the irq parameter register */
  340 static int irqvals[16] = { 
  341     0, 0, 0, 0x01, 0x02, 0x04, 0, 0x08, 0, 0, 0x10, 0x20, 0x40, 0, 0, 0x80 
  342 };
  343 /* mask of valid IRQs */
  344 #define WL_IRQS (IRQ3|IRQ4|IRQ5|IRQ7|IRQ10|IRQ11|IRQ12|IRQ15)
  345 
  346 /*
  347  * wlprobe:
  348  *
  349  *      This function "probes" or checks for the WaveLAN board on the bus to
  350  *      see if it is there.  As far as I can tell, the best break between this
  351  *      routine and the attach code is to simply determine whether the board
  352  *      is configured in properly.  Currently my approach to this is to write
  353  *      and read a word from the SRAM on the board being probed.  If the word
  354  *      comes back properly then we assume the board is there.  The config
  355  *      code expects to see a successful return from the probe routine before
  356  *      attach will be called.
  357  *
  358  * input        : address device is mapped to, and unit # being checked
  359  * output       : a '1' is returned if the board exists, and a 0 otherwise
  360  *
  361  */
  362 static int
  363 wlprobe(struct isa_device *id)
  364 {
  365     struct wl_softc     *sc = &wl_softc[id->id_unit];   
  366     register short      base = id->id_iobase;
  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     id->id_ointr = wlintr;
  446     sc->base = base;
  447     sc->unit = unit;
  448     sc->flags = 0;
  449     sc->mode = 0;
  450     sc->hacr = HACR_RESET;
  451     callout_handle_init(&sc->watchdog_ch);
  452     CMD(unit);                          /* reset the board */
  453     DELAY(DELAYCONST);                  /* >> 4 clocks at 6MHz */
  454         
  455     /* clear reset command and set PIO#2 in parameter access mode */
  456     sc->hacr = (HACR_DEFAULT & ~HACR_16BITS);
  457     CMD(unit);
  458 
  459     /* Read the PSA from the board for our later reference */
  460     wlgetpsa(base, sc->psa);
  461 
  462     /* fetch NWID */
  463     sc->nwid[0] = sc->psa[WLPSA_NWID];
  464     sc->nwid[1] = sc->psa[WLPSA_NWID+1];
  465     
  466     /* fetch MAC address - decide which one first */
  467     if (sc->psa[WLPSA_MACSEL] & 1) {
  468         j = WLPSA_LOCALMAC;
  469     } else {
  470         j = WLPSA_UNIMAC;
  471     }
  472     for(i=0; i < WAVELAN_ADDR_SIZE; ++i) {
  473         sc->wl_addr[i] = sc->psa[j + i];
  474     }
  475 
  476     /* enter normal 16 bit mode operation */
  477     sc->hacr = HACR_DEFAULT;
  478     CMD(unit);
  479 
  480     wlinitmmc(unit);
  481     outw(PIOR1(base), OFFSET_SCB + 8);  /* address of scb_crcerrs */
  482     outw(PIOP1(base), 0);                       /* clear scb_crcerrs */
  483     outw(PIOP1(base), 0);                       /* clear scb_alnerrs */
  484     outw(PIOP1(base), 0);                       /* clear scb_rscerrs */
  485     outw(PIOP1(base), 0);                       /* clear scb_ovrnerrs */
  486 
  487     bzero(ifp, sizeof(ifp));
  488     ifp->if_softc = sc;
  489     ifp->if_unit = id->id_unit;
  490     ifp->if_mtu = WAVELAN_MTU;
  491     ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
  492 #ifdef    WLDEBUG
  493     ifp->if_flags |= IFF_DEBUG;
  494 #endif
  495 #if     MULTICAST
  496     ifp->if_flags |= IFF_MULTICAST;
  497 #endif  /* MULTICAST */
  498     ifp->if_name = "wl";
  499     ifp->if_unit = unit;
  500     ifp->if_init = wlinit;
  501     ifp->if_output = ether_output;
  502     ifp->if_start = wlstart;
  503     ifp->if_ioctl = wlioctl;
  504     ifp->if_timer = 0;   /* paranoia */
  505     /* no entries
  506        ifp->if_watchdog
  507        ifp->if_done
  508        ifp->if_reset
  509        */
  510     if_attach(ifp);
  511     ether_ifattach(ifp);
  512 
  513 #if NBPFILTER > 0
  514     bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
  515 #endif
  516 
  517     bcopy(&sc->wl_addr[0], sc->wl_ac.ac_enaddr, WAVELAN_ADDR_SIZE);
  518     printf("%s%d: address %6D, NWID 0x%02x%02x", ifp->if_name, ifp->if_unit,
  519            sc->wl_ac.ac_enaddr, ":", sc->nwid[0], sc->nwid[1]);
  520     if (sc->freq24) 
  521         printf(", Freq %d MHz",sc->freq24);             /* 2.4 Gz       */
  522     printf("\n");                                       /* 2.4 Gz       */
  523 
  524 
  525     if (bootverbose)
  526         wldump(unit);
  527     return(1);
  528 }
  529 
  530 /*
  531  * Print out interesting information about the 82596.
  532  */
  533 static void
  534 wldump(int unit)
  535 {
  536     register struct wl_softc *sp = WLSOFTC(unit);
  537     int         base = sp->base;
  538     int         i;
  539         
  540     printf("hasr %04x\n", inw(HASR(base)));
  541         
  542     printf("scb at %04x:\n ", OFFSET_SCB);
  543     outw(PIOR1(base), OFFSET_SCB);
  544     for(i = 0; i < 8; i++)
  545         printf("%04x ", inw(PIOP1(base)));
  546     printf("\n");
  547         
  548     printf("cu at %04x:\n ", OFFSET_CU);
  549     outw(PIOR1(base), OFFSET_CU);
  550     for(i = 0; i < 8; i++)
  551         printf("%04x ", inw(PIOP1(base)));
  552     printf("\n");
  553         
  554     printf("tbd at %04x:\n ", OFFSET_TBD);
  555     outw(PIOR1(base), OFFSET_TBD);
  556     for(i = 0; i < 4; i++)
  557         printf("%04x ", inw(PIOP1(base)));
  558     printf("\n");
  559 }
  560 
  561 /* Initialize the Modem Management Controller */
  562 static void
  563 wlinitmmc(int unit)
  564 {
  565     register struct wl_softc *sp = WLSOFTC(unit);
  566     int         base = sp->base;
  567     int         configured;
  568     int         mode = sp->mode;
  569     int         i;                              /* 2.4 Gz               */
  570         
  571     /* enter 8 bit operation */
  572     sp->hacr = (HACR_DEFAULT & ~HACR_16BITS);
  573     CMD(unit);
  574 
  575     configured = sp->psa[WLPSA_CONFIGURED] & 1;
  576         
  577     /*
  578      * Set default modem control parameters.  Taken from NCR document
  579      *  407-0024326 Rev. A 
  580      */
  581     MMC_WRITE(MMC_JABBER_ENABLE, 0x01);
  582     MMC_WRITE(MMC_ANTEN_SEL, 0x02);
  583     MMC_WRITE(MMC_IFS, 0x20);
  584     MMC_WRITE(MMC_MOD_DELAY, 0x04);
  585     MMC_WRITE(MMC_JAM_TIME, 0x38);
  586     MMC_WRITE(MMC_DECAY_PRM, 0x00);             /* obsolete ? */
  587     MMC_WRITE(MMC_DECAY_UPDAT_PRM, 0x00);
  588     if (!configured) {
  589         MMC_WRITE(MMC_LOOPT_SEL, 0x00);
  590         if (sp->psa[WLPSA_COMPATNO] & 1) {
  591             MMC_WRITE(MMC_THR_PRE_SET, 0x01);   /* 0x04 for AT and 0x01 for MCA */
  592         } else {
  593             MMC_WRITE(MMC_THR_PRE_SET, 0x04);   /* 0x04 for AT and 0x01 for MCA */
  594         }
  595         MMC_WRITE(MMC_QUALITY_THR, 0x03);
  596     } else {
  597         /* use configuration defaults from parameter storage area */
  598         if (sp->psa[WLPSA_NWIDENABLE] & 1) {
  599             if ((mode & (MOD_PROM | MOD_ENAL)) && wl_ignore_nwid) {
  600                 MMC_WRITE(MMC_LOOPT_SEL, 0x40);
  601             } else {
  602                 MMC_WRITE(MMC_LOOPT_SEL, 0x00);
  603             }
  604         } else {
  605             MMC_WRITE(MMC_LOOPT_SEL, 0x40);     /* disable network id check */
  606         }
  607         MMC_WRITE(MMC_THR_PRE_SET, sp->psa[WLPSA_THRESH]);
  608         MMC_WRITE(MMC_QUALITY_THR, sp->psa[WLPSA_QUALTHRESH]);
  609     }
  610     MMC_WRITE(MMC_FREEZE, 0x00);
  611     MMC_WRITE(MMC_ENCR_ENABLE, 0x00);
  612 
  613     MMC_WRITE(MMC_NETW_ID_L,sp->nwid[1]);       /* set NWID */
  614     MMC_WRITE(MMC_NETW_ID_H,sp->nwid[0]);
  615 
  616     /* enter normal 16 bit mode operation */
  617     sp->hacr = HACR_DEFAULT;
  618     CMD(unit);
  619     CMD(unit);                                  /* virtualpc1 needs this! */
  620 
  621     if (sp->psa[WLPSA_COMPATNO]==               /* 2.4 Gz: half-card ver     */
  622                 WLPSA_COMPATNO_WL24B) {         /* 2.4 Gz                    */
  623         i=sp->chan24<<4;                        /* 2.4 Gz: position ch #     */
  624         MMC_WRITE(MMC_EEADDR,i+0x0f);           /* 2.4 Gz: named ch, wc=16   */
  625         MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+   /* 2.4 Gz: Download Synths   */
  626                         MMC_EECTRL_EEOP_READ);  /* 2.4 Gz: Read EEPROM       */
  627         for (i=0; i<1000; ++i) {                /* 2.4 Gz: wait for download */
  628             DELAY(40);                          /* 2.4 Gz             */
  629             if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and    */
  630                 &(MMC_EECTRLstat_DWLD           /* 2.4 Gz:       EEBUSY      */
  631                  +MMC_EECTRLstat_EEBUSY))==0)   /* 2.4 Gz:                   */
  632                 break;                          /* 2.4 Gz: download finished */
  633         }                                       /* 2.4 Gz                    */
  634         if (i==1000) printf("wl: synth load failed\n"); /* 2.4 Gz       */
  635         MMC_WRITE(MMC_EEADDR,0x61);             /* 2.4 Gz: default pwr, wc=2 */
  636         MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+   /* 2.4 Gz: Download Xmit Pwr */
  637                         MMC_EECTRL_EEOP_READ);  /* 2.4 Gz: Read EEPROM       */
  638         for (i=0; i<1000; ++i) {                /* 2.4 Gz: wait for download */
  639             DELAY(40);                          /* 2.4 Gz             */
  640             if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and    */
  641                 &(MMC_EECTRLstat_DWLD           /* 2.4 Gz:       EEBUSY      */
  642                  +MMC_EECTRLstat_EEBUSY))==0)   /* 2.4 Gz:                   */
  643                 break;                          /* 2.4 Gz: download finished */
  644         }                                       /* 2.4 Gz                    */
  645         if (i==1000) printf("wl: xmit pwr load failed\n"); /* 2.4 Gz         */
  646         MMC_WRITE(MMC_ANALCTRL,                 /* 2.4 Gz: EXT ant+polarity  */
  647                         MMC_ANALCTRL_ANTPOL +   /* 2.4 Gz:                   */
  648                         MMC_ANALCTRL_EXTANT);   /* 2.4 Gz:                   */
  649         i=sp->chan24<<4;                        /* 2.4 Gz: position ch #     */
  650         MMC_WRITE(MMC_EEADDR,i);                /* 2.4 Gz: get frequency     */
  651         MMC_WRITE(MMC_EECTRL,                   /* 2.4 Gz: EEPROM read      */
  652                         MMC_EECTRL_EEOP_READ);  /* 2.4 Gz:                  */
  653         DELAY(40);                              /* 2.4 Gz                    */
  654         i = wlmmcread(base,MMC_EEDATALrv)       /* 2.4 Gz: freq val          */
  655           + (wlmmcread(base,MMC_EEDATAHrv)<<8); /* 2.4 Gz                    */
  656         sp->freq24 = (i>>6)+2400;               /* 2.4 Gz: save real freq    */
  657     }
  658 }
  659 
  660 /*
  661  * wlinit:
  662  *
  663  *      Another routine that interfaces the "if" layer to this driver.  
  664  *      Simply resets the structures that are used by "upper layers".  
  665  *      As well as calling wlhwrst that does reset the WaveLAN board.
  666  *
  667  * input        : softc pointer for this interface
  668  * output       : structures (if structs) and board are reset
  669  *
  670  */     
  671 static void
  672 wlinit(void *xsc)
  673 {
  674     register struct wl_softc *sc = xsc;
  675     struct ifnet        *ifp = &sc->wl_if;
  676     int                 stat;
  677     u_long              oldpri;
  678 
  679 #ifdef WLDEBUG
  680     if (sc->wl_if.if_flags & IFF_DEBUG)
  681         printf("wl%d: entered wlinit()\n",sc->unit);
  682 #endif
  683 #if defined(__FreeBSD__) && __FreeBSD_version >= 300000
  684     if (ifp->if_addrhead.tqh_first == (struct ifaddr *)0) {
  685 #else
  686     if (ifp->if_addrlist == (struct ifaddr *)0) {
  687 #endif
  688         return;
  689     }
  690     oldpri = splimp();
  691     if ((stat = wlhwrst(sc->unit)) == TRUE) {
  692         sc->wl_if.if_flags |= IFF_RUNNING;   /* same as DSF_RUNNING */
  693         /* 
  694          * OACTIVE is used by upper-level routines
  695          * and must be set
  696          */
  697         sc->wl_if.if_flags &= ~IFF_OACTIVE;  /* same as tbusy below */
  698                 
  699         sc->flags |= DSF_RUNNING;
  700         sc->tbusy = 0;
  701         untimeout(wlwatchdog, sc, sc->watchdog_ch);
  702                 
  703         wlstart(ifp);
  704     } else {
  705         printf("wl%d init(): trouble resetting board.\n", sc->unit);
  706     }
  707     splx(oldpri);
  708 }
  709 
  710 /*
  711  * wlhwrst:
  712  *
  713  *      This routine resets the WaveLAN board that corresponds to the 
  714  *      board number passed in.
  715  *
  716  * input        : board number to do a hardware reset
  717  * output       : board is reset
  718  *
  719  */
  720 static int
  721 wlhwrst(int unit)
  722 {
  723     register struct wl_softc    *sc = WLSOFTC(unit);
  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, sc->watchdog_ch);
  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         sc->watchdog_ch = 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, u_long 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     struct proc         *p = curproc;   /* XXX */
 1171     int                 irq, irqval, i, isroot, size;
 1172     caddr_t             up;
 1173     char *              cpt;
 1174         
 1175 
 1176 #ifdef WLDEBUG
 1177     if (sc->wl_if.if_flags & IFF_DEBUG)
 1178         printf("wl%d: entered wlioctl()\n",unit);
 1179 #endif
 1180     opri = splimp();
 1181     switch (cmd) {
 1182     case SIOCSIFADDR:
 1183         /* Set own IP address and enable interface */
 1184         ifp->if_flags |= IFF_UP;
 1185         switch (ifa->ifa_addr->sa_family) {
 1186 #ifdef INET
 1187         case AF_INET:
 1188             wlinit(sc);
 1189             arp_ifinit((struct arpcom *)ifp, ifa);
 1190             break;
 1191 #endif
 1192 #ifdef NS
 1193         case AF_NS:
 1194         {
 1195             register struct ns_addr *ina = 
 1196                 &(IA_SNS(ifa)->sns_addr);
 1197             if (ns_nullhost(*ina))
 1198                 ina->x_host = *(union ns_host *)(ds->wl_addr);
 1199             else
 1200                 wlsetaddr(ina->x_host.c_host, unit);
 1201             wlinit(sc);
 1202             break;
 1203         }
 1204 #endif  
 1205         default:
 1206             wlinit(sc);
 1207             break;
 1208         }
 1209         break;
 1210     case SIOCSIFFLAGS:
 1211         if (ifp->if_flags & IFF_ALLMULTI) {
 1212             mode |= MOD_ENAL;
 1213         }
 1214         if (ifp->if_flags & IFF_PROMISC) {
 1215             mode |= MOD_PROM;
 1216         }
 1217         if(ifp->if_flags & IFF_LINK0) {
 1218             mode |= MOD_PROM;
 1219         }
 1220         /*
 1221          * force a complete reset if the recieve multicast/
 1222          * promiscuous mode changes so that these take 
 1223          * effect immediately.
 1224          *
 1225          */
 1226         if (sc->mode != mode) {
 1227             sc->mode = mode;
 1228             if (sc->flags & DSF_RUNNING) {
 1229                 sc->flags &= ~DSF_RUNNING;
 1230                 wlinit(sc);
 1231             }
 1232         }
 1233         /* if interface is marked DOWN and still running then
 1234          * stop it.
 1235          */
 1236         if ((ifp->if_flags & IFF_UP) == 0 && sc->flags & DSF_RUNNING) {
 1237             printf("wl%d ioctl(): board is not running\n", unit);
 1238             sc->flags &= ~DSF_RUNNING;
 1239             sc->hacr &= ~HACR_INTRON;
 1240             CMD(unit);            /* turn off interrupts */
 1241         } 
 1242         /* else if interface is UP and RUNNING, start it
 1243                 */
 1244         else if (ifp->if_flags & IFF_UP && (sc->flags & DSF_RUNNING) == 0) {
 1245             wlinit(sc);
 1246         }
 1247   
 1248         /* if WLDEBUG set on interface, then printf rf-modem regs
 1249         */
 1250         if(ifp->if_flags & IFF_DEBUG)
 1251             wlmmcstat(unit);
 1252         break;
 1253 #if     MULTICAST
 1254     case SIOCADDMULTI:
 1255     case SIOCDELMULTI:
 1256 
 1257 #if defined(__FreeBSD__) && __FreeBSD_version < 300000
 1258         if (cmd == SIOCADDMULTI) {
 1259             error = ether_addmulti(ifr, &sc->wl_ac);
 1260         }
 1261         else {
 1262             error = ether_delmulti(ifr, &sc->wl_ac);
 1263         }
 1264 
 1265         /* see if we should be in all multicast mode
 1266          * note that 82586 cannot do that, must simulate with
 1267          * promiscuous mode
 1268          */
 1269         if ( check_allmulti(unit)) {
 1270                 ifp->if_flags |=  IFF_ALLMULTI;
 1271                 sc->mode |= MOD_ENAL;
 1272                 sc->flags &= ~DSF_RUNNING;
 1273                 wlinit(sc);
 1274                 error = 0;
 1275                 break;
 1276         }
 1277 
 1278         if (error == ENETRESET) {
 1279             if(sc->flags & DSF_RUNNING) {
 1280                 sc->flags &= ~DSF_RUNNING;
 1281                 wlinit(sc);
 1282             }
 1283             error = 0;
 1284         }
 1285 #else
 1286         wlinit(sc);
 1287 #endif
 1288         break;
 1289 #endif  /* MULTICAST */
 1290 
 1291     /* DEVICE SPECIFIC */
 1292 
 1293 
 1294         /* copy the PSA out to the caller */
 1295     case SIOCGWLPSA:
 1296         /* pointer to buffer in user space */
 1297         up = (void *)ifr->ifr_data;
 1298         /* work out if they're root */
 1299         isroot = (suser(p->p_ucred, &p->p_acflag) == 0);
 1300         
 1301         for (i = 0; i < 0x40; i++) {
 1302             /* don't hand the DES key out to non-root users */
 1303             if ((i > WLPSA_DESKEY) && (i < (WLPSA_DESKEY + 8)) && !isroot)
 1304                 continue;
 1305             if (subyte((up + i), sc->psa[i]))
 1306                 return(EFAULT);
 1307         }
 1308         break;
 1309 
 1310 
 1311         /* copy the PSA in from the caller; we only copy _some_ values */
 1312     case SIOCSWLPSA:
 1313         /* root only */
 1314         if ((error = suser(p->p_ucred, &p->p_acflag)))
 1315             break;
 1316         error = EINVAL; /* assume the worst */
 1317         /* pointer to buffer in user space containing data */
 1318         up = (void *)ifr->ifr_data;
 1319         
 1320         /* check validity of input range */
 1321         for (i = 0; i < 0x40; i++)
 1322             if (fubyte(up + i) < 0)
 1323                 return(EFAULT);
 1324 
 1325         /* check IRQ value */
 1326         irqval = fubyte(up+WLPSA_IRQNO);
 1327         for (irq = 15; irq >= 0; irq--)
 1328             if(irqvals[irq] == irqval)
 1329                 break;
 1330         if (irq == 0)                   /* oops */
 1331             break;
 1332         /* new IRQ */
 1333         sc->psa[WLPSA_IRQNO] = irqval;
 1334 
 1335         /* local MAC */
 1336         for (i = 0; i < 6; i++)
 1337             sc->psa[WLPSA_LOCALMAC+i] = fubyte(up+WLPSA_LOCALMAC+i);
 1338                 
 1339         /* MAC select */        
 1340         sc->psa[WLPSA_MACSEL] = fubyte(up+WLPSA_MACSEL);
 1341         
 1342         /* default nwid */
 1343         sc->psa[WLPSA_NWID] = fubyte(up+WLPSA_NWID);
 1344         sc->psa[WLPSA_NWID+1] = fubyte(up+WLPSA_NWID+1);
 1345 
 1346         error = 0;
 1347         wlsetpsa(unit);         /* update the PSA */
 1348         break;
 1349 
 1350 
 1351         /* get the current NWID out of the sc since we stored it there */
 1352     case SIOCGWLCNWID:
 1353         ifr->ifr_data = (caddr_t) (sc->nwid[0] << 8 | sc->nwid[1]);
 1354         break;
 1355 
 1356 
 1357         /*
 1358          * change the nwid dynamically.  This
 1359          * ONLY changes the radio modem and does not
 1360          * change the PSA.
 1361          *
 1362          * 2 steps:
 1363          *      1. save in softc "soft registers"
 1364          *      2. save in radio modem (MMC)
 1365          */
 1366     case SIOCSWLCNWID:
 1367         /* root only */
 1368         if ((error = suser(p->p_ucred, &p->p_acflag)))
 1369             break;
 1370         if (!(ifp->if_flags & IFF_UP)) {
 1371             error = EIO;        /* only allowed while up */
 1372         } else {
 1373             /* 
 1374              * soft c nwid shadows radio modem setting
 1375              */
 1376             sc->nwid[0] = (int)ifr->ifr_data >> 8;
 1377             sc->nwid[1] = (int)ifr->ifr_data & 0xff;
 1378             MMC_WRITE(MMC_NETW_ID_L,sc->nwid[1]);
 1379             MMC_WRITE(MMC_NETW_ID_H,sc->nwid[0]);
 1380         }
 1381         break;
 1382 
 1383         /* copy the EEPROM in 2.4 Gz WaveMODEM  out to the caller */
 1384     case SIOCGWLEEPROM:
 1385         /* root only */
 1386         if ((error = suser(p->p_ucred, &p->p_acflag)))
 1387             break;
 1388         /* pointer to buffer in user space */
 1389         up = (void *)ifr->ifr_data;
 1390         
 1391         for (i=0x00; i<0x80; ++i) {             /* 2.4 Gz: size of EEPROM   */
 1392             MMC_WRITE(MMC_EEADDR,i);            /* 2.4 Gz: get frequency    */
 1393             MMC_WRITE(MMC_EECTRL,               /* 2.4 Gz: EEPROM read      */
 1394                         MMC_EECTRL_EEOP_READ);  /* 2.4 Gz:                  */
 1395             DELAY(40);                          /* 2.4 Gz                   */
 1396             if (subyte(up + 2*i  ,              /* 2.4 Gz: pass low byte of */
 1397                  wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word      */
 1398                ) return(EFAULT);                /* 2.4 Gz:                  */
 1399             if (subyte(up + 2*i+1,              /* 2.4 Gz: pass hi byte of  */
 1400                  wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word      */
 1401                ) return(EFAULT);                /* 2.4 Gz:                  */
 1402         }
 1403         break;
 1404 
 1405 #ifdef WLCACHE
 1406         /* zero (Delete) the wl cache */
 1407     case SIOCDWLCACHE:
 1408         /* root only */
 1409         if ((error = suser(p->p_ucred, &p->p_acflag)))
 1410             break;
 1411         wl_cache_zero(unit);
 1412         break;
 1413 
 1414         /* read out the number of used cache elements */
 1415     case SIOCGWLCITEM:
 1416         ifr->ifr_data = (caddr_t) sc->w_sigitems;
 1417         break;
 1418 
 1419         /* read out the wl cache */
 1420     case SIOCGWLCACHE:
 1421         /* pointer to buffer in user space */
 1422         up = (void *)ifr->ifr_data;
 1423         cpt = (char *) &sc->w_sigcache[0];
 1424         size = sc->w_sigitems * sizeof(struct w_sigcache);
 1425         
 1426         for (i = 0; i < size; i++) {
 1427             if (subyte((up + i), *cpt++))
 1428                 return(EFAULT);
 1429         }
 1430         break;
 1431 #endif
 1432 
 1433     default:
 1434         error = EINVAL;
 1435     }
 1436     splx(opri);
 1437     return (error);
 1438 }
 1439 
 1440 /*
 1441  * wlwatchdog():
 1442  *
 1443  * Called if the timer set in wlstart expires before an interrupt is received
 1444  * from the wavelan.   It seems to lose interrupts sometimes.
 1445  * The watchdog routine gets called if the transmitter failed to interrupt
 1446  *
 1447  * input        : which board is timing out
 1448  * output       : board reset 
 1449  *
 1450  */
 1451 static void
 1452 wlwatchdog(void *vsc)
 1453 {
 1454     struct wl_softc *sc = vsc;
 1455     int unit = sc->unit;
 1456 
 1457     log(LOG_ERR, "wl%d: wavelan device timeout on xmit\n", unit);
 1458     sc->wl_ac.ac_if.if_oerrors++;
 1459     wlinit(sc);
 1460 }
 1461 
 1462 /*
 1463  * wlintr:
 1464  *
 1465  *      This function is the interrupt handler for the WaveLAN
 1466  *      board.  This routine will be called whenever either a packet
 1467  *      is received, or a packet has successfully been transfered and
 1468  *      the unit is ready to transmit another packet.
 1469  *
 1470  * input        : board number that interrupted
 1471  * output       : either a packet is received, or a packet is transfered
 1472  *
 1473  */
 1474 static void
 1475 wlintr(unit)
 1476 int unit;
 1477 {
 1478     register struct wl_softc *sc = &wl_softc[unit];
 1479     short               base = sc->base;
 1480     int                 ac_status;
 1481     u_short             int_type, int_type1;
 1482 
 1483 #ifdef WLDEBUG
 1484     if (sc->wl_if.if_flags & IFF_DEBUG)
 1485         printf("wl%d: wlintr() called\n",unit);
 1486 #endif
 1487 
 1488     if((int_type = inw(HASR(base))) & HASR_MMC_INTR) {
 1489         /* handle interrupt from the modem management controler */
 1490         /* This will clear the interrupt condition */ 
 1491         (void) wlmmcread(base,MMC_DCE_STATUS); /* ignored for now */
 1492     }
 1493 
 1494     if(!(int_type & HASR_INTR)){        /* return if no interrupt from 82586 */
 1495         /* commented out. jrb.  it happens when reinit occurs
 1496            printf("wlintr: int_type %x, dump follows\n", int_type);
 1497            wldump(unit);
 1498            */
 1499         return;
 1500     }
 1501 
 1502     if (gathersnr)
 1503         getsnr(unit);
 1504     for(;;) {
 1505         outw(PIOR0(base), OFFSET_SCB + 0);      /* get scb status */
 1506         int_type = (inw(PIOP0(base)) & SCB_SW_INT);
 1507         if (int_type == 0)                      /* no interrupts left */
 1508             break;
 1509 
 1510         int_type1 = wlack(unit);                /* acknowledge interrupt(s) */
 1511         /* make sure no bits disappeared (others may appear) */
 1512         if ((int_type & int_type1) != int_type)
 1513             printf("wlack() int bits disappeared : %04x != int_type %04x\n",
 1514                    int_type1, int_type);
 1515         int_type = int_type1;                   /* go with the new status */
 1516         /* 
 1517          * incoming packet
 1518          */
 1519         if (int_type & SCB_SW_FR) {
 1520             sc->wl_if.if_ipackets++;
 1521             wlrcv(unit);
 1522         }
 1523         /*
 1524          * receiver not ready
 1525          */
 1526         if (int_type & SCB_SW_RNR) {
 1527             sc->wl_if.if_ierrors++;
 1528 #ifdef  WLDEBUG
 1529             if (sc->wl_if.if_flags & IFF_DEBUG)
 1530                 printf("wl%d intr(): receiver overrun! begin_fd = %x\n",
 1531                        unit, sc->begin_fd);
 1532 #endif
 1533             wlrustrt(unit);
 1534         }
 1535         /*
 1536          * CU not ready
 1537          */
 1538         if (int_type & SCB_SW_CNA) {
 1539             /*
 1540              * At present, we don't care about CNA's.  We
 1541              * believe they are a side effect of XMT.
 1542              */
 1543         }
 1544         if (int_type & SCB_SW_CX) {
 1545             /*
 1546              * At present, we only request Interrupt for
 1547              * XMT.
 1548              */
 1549             outw(PIOR1(base), OFFSET_CU);       /* get command status */
 1550             ac_status = inw(PIOP1(base));
 1551 
 1552             if (xmt_watch) {                    /* report some anomalies */
 1553 
 1554                 if (sc->tbusy == 0) {
 1555                     printf("wl%d: xmt intr but not busy, CU %04x\n",
 1556                            unit, ac_status);
 1557                 }
 1558                 if (ac_status == 0) {
 1559                     printf("wl%d: xmt intr but ac_status == 0\n", unit);
 1560                 }
 1561                 if (ac_status & AC_SW_A) {
 1562                     printf("wl%d: xmt aborted\n",unit);
 1563                 }
 1564 #ifdef  notdef
 1565                 if (ac_status & TC_CARRIER) {
 1566                     printf("wl%d: no carrier\n", unit);
 1567                 }
 1568 #endif  /* notdef */
 1569                 if (ac_status & TC_CLS) {
 1570                     printf("wl%d: no CTS\n", unit);
 1571                 }
 1572                 if (ac_status & TC_DMA) {
 1573                     printf("wl%d: DMA underrun\n", unit);
 1574                 }
 1575                 if (ac_status & TC_DEFER) {
 1576                     printf("wl%d: xmt deferred\n",unit);
 1577                 }
 1578                 if (ac_status & TC_SQE) {
 1579                     printf("wl%d: heart beat\n", unit);
 1580                 }
 1581                 if (ac_status & TC_COLLISION) {
 1582                     printf("wl%d: too many collisions\n", unit);
 1583                 }
 1584             }
 1585             /* if the transmit actually failed, or returned some status */
 1586             if ((!(ac_status & AC_SW_OK)) || (ac_status & 0xfff)) {
 1587                 if (ac_status & (TC_COLLISION | TC_CLS | TC_DMA)) {
 1588                     sc->wl_if.if_oerrors++;
 1589                 }
 1590                 /* count collisions */
 1591                 sc->wl_if.if_collisions += (ac_status & 0xf);
 1592                 /* if TC_COLLISION set and collision count zero, 16 collisions */
 1593                 if ((ac_status & 0x20) == 0x20) {
 1594                     sc->wl_if.if_collisions += 0x10;
 1595                 }
 1596             }
 1597             sc->tbusy = 0;
 1598             untimeout(wlwatchdog, sc, sc->watchdog_ch);
 1599             sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
 1600             wlstart(&(sc->wl_if));
 1601         }
 1602     }
 1603     return;
 1604 }
 1605 
 1606 /*
 1607  * wlrcv:
 1608  *
 1609  *      This routine is called by the interrupt handler to initiate a
 1610  *      packet transfer from the board to the "if" layer above this
 1611  *      driver.  This routine checks if a buffer has been successfully
 1612  *      received by the WaveLAN.  If so, the routine wlread is called
 1613  *      to do the actual transfer of the board data (including the
 1614  *      ethernet header) into a packet (consisting of an mbuf chain).
 1615  *
 1616  * input        : number of the board to check
 1617  * output       : if a packet is available, it is "sent up"
 1618  *
 1619  */
 1620 static void
 1621 wlrcv(int unit)
 1622 {
 1623     register struct wl_softc *sc = WLSOFTC(unit);
 1624     short       base = sc->base;
 1625     u_short     fd_p, status, offset, link_offset;
 1626 
 1627 #ifdef WLDEBUG
 1628     if (sc->wl_if.if_flags & IFF_DEBUG)
 1629         printf("wl%d: entered wlrcv()\n",unit);
 1630 #endif
 1631     for (fd_p = sc->begin_fd; fd_p != I82586NULL; fd_p = sc->begin_fd) {
 1632 
 1633         outw(PIOR0(base), fd_p + 0);    /* address of status */
 1634         status = inw(PIOP0(base));
 1635         outw(PIOR1(base), fd_p + 4);    /* address of link_offset */
 1636         link_offset = inw(PIOP1(base));
 1637         offset = inw(PIOP1(base));      /* rbd_offset */
 1638         if (status == 0xffff || offset == 0xffff /*I82586NULL*/) {
 1639             if (wlhwrst(unit) != TRUE)
 1640                 printf("wl%d rcv(): hwrst ffff trouble.\n", unit);
 1641             return;
 1642         } else if (status & AC_SW_C) {
 1643             if (status == (RFD_DONE|RFD_RSC)) {
 1644                 /* lost one */
 1645 #ifdef  WLDEBUG
 1646                 if (sc->wl_if.if_flags & IFF_DEBUG)
 1647                     printf("wl%d RCV: RSC %x\n", unit, status);
 1648 #endif
 1649                 sc->wl_if.if_ierrors++;
 1650             } else if (!(status & RFD_OK)) {
 1651                 printf("wl%d RCV: !OK %x\n", unit, status);
 1652                 sc->wl_if.if_ierrors++;
 1653             } else if (status & 0xfff) {        /* can't happen */
 1654                 printf("wl%d RCV: ERRs %x\n", unit, status);
 1655                 sc->wl_if.if_ierrors++;
 1656             } else if (!wlread(unit, fd_p))
 1657                 return;
 1658 
 1659             if (!wlrequeue(unit, fd_p)) {
 1660                 /* abort on chain error */
 1661                 if (wlhwrst(unit) != TRUE)
 1662                     printf("wl%d rcv(): hwrst trouble.\n", unit);
 1663                 return;
 1664             }
 1665             sc->begin_fd = link_offset;
 1666         } else {
 1667             break;
 1668         }
 1669     }
 1670     return;
 1671 }
 1672 
 1673 /*
 1674  * wlrequeue:
 1675  *
 1676  *      This routine puts rbd's used in the last receive back onto the
 1677  *      free list for the next receive.
 1678  *
 1679  */
 1680 static int
 1681 wlrequeue(int unit, u_short fd_p)
 1682 {
 1683     register struct wl_softc *sc = WLSOFTC(unit);
 1684     short               base = sc->base;
 1685     fd_t                fd;
 1686     u_short             l_rbdp, f_rbdp, rbd_offset;
 1687 
 1688     outw(PIOR0(base), fd_p + 6);
 1689     rbd_offset = inw(PIOP0(base));
 1690     if ((f_rbdp = rbd_offset) != I82586NULL) {
 1691         l_rbdp = f_rbdp;
 1692         for(;;) {
 1693             outw(PIOR0(base), l_rbdp + 0);      /* address of status */
 1694             if(inw(PIOP0(base)) & RBD_SW_EOF)
 1695                 break;
 1696             outw(PIOP0(base), 0);
 1697             outw(PIOR0(base), l_rbdp + 2);      /* next_rbd_offset */
 1698             if((l_rbdp = inw(PIOP0(base))) == I82586NULL)
 1699                 break;
 1700         }
 1701         outw(PIOP0(base), 0);
 1702         outw(PIOR0(base), l_rbdp + 2);          /* next_rbd_offset */
 1703         outw(PIOP0(base), I82586NULL);
 1704         outw(PIOR0(base), l_rbdp + 8);          /* address of size */
 1705         outw(PIOP0(base), inw(PIOP0(base)) | AC_CW_EL);
 1706         outw(PIOR0(base), sc->end_rbd + 2);
 1707         outw(PIOP0(base), f_rbdp);              /* end_rbd->next_rbd_offset */
 1708         outw(PIOR0(base), sc->end_rbd + 8);     /* size */
 1709         outw(PIOP0(base), inw(PIOP0(base)) & ~AC_CW_EL);
 1710         sc->end_rbd = l_rbdp;
 1711     }
 1712 
 1713     fd.status = 0;
 1714     fd.command = AC_CW_EL;
 1715     fd.link_offset = I82586NULL;
 1716     fd.rbd_offset = I82586NULL;
 1717     outw(PIOR1(base), fd_p);
 1718     outsw(PIOP1(base), &fd, 8/2);
 1719     
 1720     outw(PIOR1(base), sc->end_fd + 2);  /* addr of command */
 1721     outw(PIOP1(base), 0);               /* command = 0 */
 1722     outw(PIOP1(base), fd_p);            /* end_fd->link_offset = fd_p */
 1723     sc->end_fd = fd_p;
 1724 
 1725     return 1;
 1726 }
 1727 
 1728 #ifdef  WLDEBUG
 1729 static int xmt_debug = 0;
 1730 #endif  /* WLDEBUG */
 1731 
 1732 /*
 1733  * wlxmt:
 1734  *
 1735  *      This routine fills in the appropriate registers and memory
 1736  *      locations on the WaveLAN board and starts the board off on
 1737  *      the transmit.
 1738  *
 1739  * input        : board number of interest, and a pointer to the mbuf
 1740  * output       : board memory and registers are set for xfer and attention
 1741  *
 1742  */
 1743 static void
 1744 wlxmt(int unit, struct mbuf *m)
 1745 {
 1746     register struct wl_softc *sc = WLSOFTC(unit);
 1747     register u_short            xmtdata_p = OFFSET_TBUF;
 1748     register u_short            xmtshort_p;
 1749     struct      mbuf                    *tm_p = m;
 1750     register struct ether_header        *eh_p = mtod(m, struct ether_header *);
 1751     u_char                              *mb_p = mtod(m, u_char *) + sizeof(struct ether_header);
 1752     u_short                             count = m->m_len - sizeof(struct ether_header);
 1753     ac_t                                cb;
 1754     u_short                             tbd_p = OFFSET_TBD;
 1755     u_short                             len, clen = 0;
 1756     short                               base = sc->base;
 1757     int                                 spin;
 1758         
 1759 #ifdef WLDEBUG
 1760     if (sc->wl_if.if_flags & IFF_DEBUG)
 1761         printf("wl%d: entered wlxmt()\n",unit);
 1762 #endif
 1763 
 1764     cb.ac_status = 0;
 1765     cb.ac_command = (AC_CW_EL|AC_TRANSMIT|AC_CW_I);
 1766     cb.ac_link_offset = I82586NULL;
 1767     outw(PIOR1(base), OFFSET_CU);
 1768     outsw(PIOP1(base), &cb, 6/2);
 1769     outw(PIOP1(base), OFFSET_TBD);      /* cb.cmd.transmit.tbd_offset */
 1770     outsw(PIOP1(base), eh_p->ether_dhost, WAVELAN_ADDR_SIZE/2);
 1771     outw(PIOP1(base), eh_p->ether_type);
 1772 
 1773 #ifdef  WLDEBUG
 1774     if (sc->wl_if.if_flags & IFF_DEBUG) {
 1775         if (xmt_debug) {
 1776             printf("XMT    mbuf: L%d @%p ", count, (void *)mb_p);
 1777             printf("ether type %x\n", eh_p->ether_type);
 1778         }
 1779     }
 1780 #endif  /* WLDEBUG */
 1781     outw(PIOR0(base), OFFSET_TBD);
 1782     outw(PIOP0(base), 0);               /* act_count */
 1783     outw(PIOR1(base), OFFSET_TBD + 4);
 1784     outw(PIOP1(base), xmtdata_p);       /* buffer_addr */
 1785     outw(PIOP1(base), 0);               /* buffer_base */
 1786     for (;;) {
 1787         if (count) {
 1788             if (clen + count > WAVELAN_MTU)
 1789                 break;
 1790             if (count & 1)
 1791                 len = count + 1;
 1792             else
 1793                 len = count;
 1794             outw(PIOR1(base), xmtdata_p);
 1795             outsw(PIOP1(base), mb_p, len/2);
 1796             clen += count;
 1797             outw(PIOR0(base), tbd_p);  /* address of act_count */
 1798             outw(PIOP0(base), inw(PIOP0(base)) + count);
 1799             xmtdata_p += len;
 1800             if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
 1801                 break;
 1802             if (count & 1) {
 1803                 /* go to the next descriptor */
 1804                 outw(PIOR0(base), tbd_p + 2);
 1805                 tbd_p += sizeof (tbd_t);
 1806                 outw(PIOP0(base), tbd_p); /* next_tbd_offset */
 1807                 outw(PIOR0(base), tbd_p);
 1808                 outw(PIOP0(base), 0);   /* act_count */
 1809                 outw(PIOR1(base), tbd_p + 4);
 1810                 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
 1811                 outw(PIOP1(base), 0);         /* buffer_base */
 1812                 /* at the end -> coallesce remaining mbufs */
 1813                 if (tbd_p == OFFSET_TBD + (N_TBD-1) * sizeof (tbd_t)) {
 1814                     wlsftwsleaze(&count, &mb_p, &tm_p, unit);
 1815                     continue;
 1816                 }
 1817                 /* next mbuf short -> coallesce as needed */
 1818                 if ( (tm_p->m_next == (struct mbuf *) 0) ||
 1819 #define HDW_THRESHOLD 55
 1820                      tm_p->m_len > HDW_THRESHOLD)
 1821                     /* ok */;
 1822                 else {
 1823                     wlhdwsleaze(&count, &mb_p, &tm_p, unit);
 1824                     continue;
 1825                 }
 1826             }
 1827         } else if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
 1828             break;
 1829         count = tm_p->m_len;
 1830         mb_p = mtod(tm_p, u_char *);
 1831 #ifdef  WLDEBUG
 1832         if (sc->wl_if.if_flags & IFF_DEBUG)
 1833             if (xmt_debug)
 1834                 printf("mbuf+ L%d @%p ", count, (void *)mb_p);
 1835 #endif  /* WLDEBUG */
 1836     }
 1837 #ifdef  WLDEBUG
 1838     if (sc->wl_if.if_flags & IFF_DEBUG)
 1839         if (xmt_debug)
 1840             printf("CLEN = %d\n", clen);
 1841 #endif  /* WLDEBUG */
 1842     outw(PIOR0(base), tbd_p);
 1843     if (clen < ETHERMIN) {
 1844         outw(PIOP0(base), inw(PIOP0(base)) + ETHERMIN - clen);
 1845         outw(PIOR1(base), xmtdata_p);
 1846         for (xmtshort_p = xmtdata_p; clen < ETHERMIN; clen += 2)
 1847             outw(PIOP1(base), 0);
 1848     }   
 1849     outw(PIOP0(base), inw(PIOP0(base)) | TBD_SW_EOF);
 1850     outw(PIOR0(base), tbd_p + 2);
 1851     outw(PIOP0(base), I82586NULL);
 1852 #ifdef  WLDEBUG
 1853     if (sc->wl_if.if_flags & IFF_DEBUG) {
 1854         if (xmt_debug) {
 1855             wltbd(unit);
 1856             printf("\n");
 1857         }
 1858     }
 1859 #endif  /* WLDEBUG */
 1860 
 1861     outw(PIOR0(base), OFFSET_SCB + 2);  /* address of scb_command */
 1862     /* 
 1863      * wait for 586 to clear previous command, complain if it takes
 1864      * too long
 1865      */
 1866     for (spin = 1;;spin = (spin + 1) % 10000) {
 1867         if (inw(PIOP0(base)) == 0) {            /* it's done, we can go */
 1868             break;
 1869         }
 1870         if ((spin == 0) && xmt_watch) {         /* not waking up, and we care */
 1871                 printf("wl%d: slow accepting xmit\n",unit);
 1872         }
 1873     }
 1874     outw(PIOP0(base), SCB_CU_STRT);             /* new command */
 1875     SET_CHAN_ATTN(unit);
 1876     
 1877     m_freem(m);
 1878 
 1879     /* XXX 
 1880      * Pause to avoid transmit overrun problems.
 1881      * The required delay tends to vary with platform type, and may be
 1882      * related to interrupt loss.
 1883      */
 1884     if (wl_xmit_delay) {
 1885         DELAY(wl_xmit_delay);
 1886     }
 1887     return;
 1888 }
 1889 
 1890 /*
 1891  * wlbldru:
 1892  *
 1893  *      This function builds the linear linked lists of fd's and
 1894  *      rbd's.  Based on page 4-32 of 1986 Intel microcom handbook.
 1895  *
 1896  */
 1897 static u_short
 1898 wlbldru(int unit)
 1899 {
 1900     register struct wl_softc *sc = WLSOFTC(unit);
 1901     short       base = sc->base;
 1902     fd_t        fd;
 1903     rbd_t       rbd;
 1904     u_short     fd_p = OFFSET_RU;
 1905     u_short     rbd_p = OFFSET_RBD;
 1906     int         i;
 1907 
 1908     sc->begin_fd = fd_p;
 1909     for(i = 0; i < N_FD; i++) {
 1910         fd.status = 0;
 1911         fd.command = 0;
 1912         fd.link_offset = fd_p + sizeof(fd_t);
 1913         fd.rbd_offset = I82586NULL;
 1914         outw(PIOR1(base), fd_p);
 1915         outsw(PIOP1(base), &fd, 8/2);
 1916         fd_p = fd.link_offset;
 1917     }
 1918     fd_p -= sizeof(fd_t);
 1919     sc->end_fd = fd_p;
 1920     outw(PIOR1(base), fd_p + 2);
 1921     outw(PIOP1(base), AC_CW_EL);        /* command */
 1922     outw(PIOP1(base), I82586NULL);      /* link_offset */
 1923     fd_p = OFFSET_RU;
 1924     
 1925     outw(PIOR0(base), fd_p + 6);        /* address of rbd_offset */
 1926     outw(PIOP0(base), rbd_p);
 1927     outw(PIOR1(base), rbd_p);
 1928     for(i = 0; i < N_RBD; i++) {
 1929         rbd.status = 0;
 1930         rbd.buffer_addr = rbd_p + sizeof(rbd_t) + 2;
 1931         rbd.buffer_base = 0;
 1932         rbd.size = RCVBUFSIZE;
 1933         if (i != N_RBD-1) {
 1934             rbd_p += sizeof(ru_t);
 1935             rbd.next_rbd_offset = rbd_p;
 1936         } else {
 1937             rbd.next_rbd_offset = I82586NULL;
 1938             rbd.size |= AC_CW_EL;
 1939             sc->end_rbd = rbd_p;
 1940         }
 1941         outsw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
 1942         outw(PIOR1(base), rbd_p);
 1943     }
 1944     return sc->begin_fd;
 1945 }
 1946 
 1947 /*
 1948  * wlrustrt:
 1949  *
 1950  *      This routine starts the receive unit running.  First checks if the
 1951  *      board is actually ready, then the board is instructed to receive
 1952  *      packets again.
 1953  *
 1954  */
 1955 static void
 1956 wlrustrt(int unit)
 1957 {
 1958     register struct wl_softc *sc = WLSOFTC(unit);
 1959     short               base = sc->base;
 1960     u_short             rfa;
 1961 
 1962 #ifdef WLDEBUG
 1963     if (sc->wl_if.if_flags & IFF_DEBUG)
 1964         printf("wl%d: entered wlrustrt()\n",unit);
 1965 #endif
 1966     outw(PIOR0(base), OFFSET_SCB);
 1967     if (inw(PIOP0(base)) & SCB_RUS_READY){
 1968         printf("wlrustrt: RUS_READY\n");
 1969         return;
 1970     }
 1971 
 1972     outw(PIOR0(base), OFFSET_SCB + 2);
 1973     outw(PIOP0(base), SCB_RU_STRT);             /* command */
 1974     rfa = wlbldru(unit);
 1975     outw(PIOR0(base), OFFSET_SCB + 6);  /* address of scb_rfa_offset */
 1976     outw(PIOP0(base), rfa);
 1977 
 1978     SET_CHAN_ATTN(unit);
 1979     return;
 1980 }
 1981 
 1982 /*
 1983  * wldiag:
 1984  *
 1985  *      This routine does a 586 op-code number 7, and obtains the
 1986  *      diagnose status for the WaveLAN.
 1987  *
 1988  */
 1989 static int
 1990 wldiag(int unit)
 1991 {
 1992     register struct wl_softc *sc = WLSOFTC(unit);
 1993     short               base = sc->base;
 1994     short status;
 1995 
 1996 #ifdef WLDEBUG
 1997     if (sc->wl_if.if_flags & IFF_DEBUG)
 1998         printf("wl%d: entered wldiag()\n",unit);
 1999 #endif
 2000     outw(PIOR0(base), OFFSET_SCB);
 2001     status = inw(PIOP0(base));
 2002     if (status & SCB_SW_INT) {
 2003                 /* state is 2000 which seems ok
 2004                    printf("wl%d diag(): unexpected initial state %\n",
 2005                    unit, inw(PIOP0(base)));
 2006                 */
 2007         wlack(unit);
 2008     }
 2009     outw(PIOR1(base), OFFSET_CU);
 2010     outw(PIOP1(base), 0);                       /* ac_status */
 2011     outw(PIOP1(base), AC_DIAGNOSE|AC_CW_EL);/* ac_command */
 2012     if(wlcmd(unit, "diag()") == 0)
 2013         return 0;
 2014     outw(PIOR0(base), OFFSET_CU);
 2015     if (inw(PIOP0(base)) & 0x0800) {
 2016         printf("wl%d: i82586 Self Test failed!\n", unit);
 2017         return 0;
 2018     }
 2019     return TRUE;
 2020 }
 2021 
 2022 /*
 2023  * wlconfig:
 2024  *
 2025  *      This routine does a standard config of the WaveLAN board.
 2026  *
 2027  */
 2028 static int
 2029 wlconfig(int unit)
 2030 {
 2031     configure_t configure;
 2032     register struct wl_softc *sc = WLSOFTC(unit);
 2033     short               base = sc->base;
 2034 
 2035 #if     MULTICAST
 2036 #if defined(__FreeBSD__) && __FreeBSD_version >= 300000
 2037     struct ifmultiaddr *ifma;
 2038     u_char *addrp;
 2039 #else
 2040     struct ether_multi *enm;
 2041     struct ether_multistep step;
 2042 #endif
 2043     int cnt = 0;
 2044 #endif  /* MULTICAST */
 2045 
 2046 #ifdef WLDEBUG
 2047     if (sc->wl_if.if_flags & IFF_DEBUG)
 2048         printf("wl%d: entered wlconfig()\n",unit);
 2049 #endif
 2050     outw(PIOR0(base), OFFSET_SCB);
 2051     if (inw(PIOP0(base)) & SCB_SW_INT) {
 2052         /*
 2053           printf("wl%d config(): unexpected initial state %x\n",
 2054           unit, inw(PIOP0(base)));
 2055           */
 2056     }
 2057     wlack(unit);
 2058 
 2059     outw(PIOR1(base), OFFSET_CU);
 2060     outw(PIOP1(base), 0);                               /* ac_status */
 2061     outw(PIOP1(base), AC_CONFIGURE|AC_CW_EL);   /* ac_command */
 2062 
 2063 /* jrb hack */
 2064     configure.fifolim_bytecnt   = 0x080c;
 2065     configure.addrlen_mode      = 0x0600;
 2066     configure.linprio_interframe        = 0x2060;
 2067     configure.slot_time         = 0xf200;
 2068     configure.hardware          = 0x0008;       /* tx even w/o CD */
 2069     configure.min_frame_len     = 0x0040;
 2070 #if 0
 2071     /* This is the configuration block suggested by Marc Meertens
 2072      * <mmeerten@obelix.utrecht.NCR.COM> in an e-mail message to John
 2073      * Ioannidis on 10 Nov 92.
 2074      */
 2075     configure.fifolim_bytecnt   = 0x040c;
 2076     configure.addrlen_mode      = 0x0600;
 2077     configure.linprio_interframe        = 0x2060;
 2078     configure.slot_time         = 0xf000;
 2079     configure.hardware          = 0x0008;       /* tx even w/o CD */
 2080     configure.min_frame_len     = 0x0040;
 2081 #else
 2082     /*
 2083      * below is the default board configuration from p2-28 from 586 book
 2084      */
 2085     configure.fifolim_bytecnt   = 0x080c;
 2086     configure.addrlen_mode      = 0x2600;
 2087     configure.linprio_interframe        = 0x7820;       /* IFS=120, ACS=2 */
 2088     configure.slot_time         = 0xf00c;       /* slottime=12    */
 2089     configure.hardware          = 0x0008;       /* tx even w/o CD */
 2090     configure.min_frame_len     = 0x0040;
 2091 #endif
 2092     if(sc->mode & (MOD_PROM | MOD_ENAL)) {
 2093         configure.hardware |= 1;
 2094     }
 2095     outw(PIOR1(base), OFFSET_CU + 6);
 2096     outsw(PIOP1(base), &configure, sizeof(configure_t)/2);
 2097 
 2098     if(wlcmd(unit, "config()-configure") == 0)
 2099         return 0;
 2100 #if     MULTICAST
 2101     outw(PIOR1(base), OFFSET_CU);
 2102     outw(PIOP1(base), 0);                               /* ac_status */
 2103     outw(PIOP1(base), AC_MCSETUP|AC_CW_EL);             /* ac_command */
 2104     outw(PIOR1(base), OFFSET_CU + 8);
 2105 #if defined(__FreeBSD__) && __FreeBSD_version >= 300000
 2106     for (ifma = sc->wl_if.if_multiaddrs.lh_first; ifma;
 2107          ifma = ifma->ifma_link.le_next) {
 2108         if (ifma->ifma_addr->sa_family != AF_LINK)
 2109             continue;
 2110         
 2111         addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
 2112         outw(PIOP1(base), addrp[0] + (addrp[1] << 8));
 2113         outw(PIOP1(base), addrp[2] + (addrp[3] << 8));
 2114         outw(PIOP1(base), addrp[4] + (addrp[5] << 8));
 2115         ++cnt;
 2116     }
 2117 #else
 2118     ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
 2119     while (enm != NULL) {
 2120         unsigned int lo, hi;
 2121         /* break if setting a multicast range, else we would crash */
 2122         if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
 2123                 break;
 2124         }
 2125         lo = (enm->enm_addrlo[3] << 16) + (enm->enm_addrlo[4] << 8)
 2126             + enm->enm_addrlo[5];
 2127         hi = (enm->enm_addrhi[3] << 16) + (enm->enm_addrhi[4] << 8)
 2128             + enm->enm_addrhi[5];
 2129         while(lo <= hi) {
 2130             outw(PIOP1(base),enm->enm_addrlo[0] +
 2131                  (enm->enm_addrlo[1] << 8));
 2132             outw(PIOP1(base),enm->enm_addrlo[2] +
 2133                  ((lo >> 8) & 0xff00));
 2134             outw(PIOP1(base), ((lo >> 8) & 0xff) +
 2135                  ((lo << 8) & 0xff00));
 2136 /* #define MCASTDEBUG */
 2137 #ifdef MCASTDEBUG
 2138 printf("mcast_addr[%d,%d,%d] %x %x %x %x %x %x\n", lo, hi, cnt,
 2139                 enm->enm_addrlo[0],
 2140                 enm->enm_addrlo[1],
 2141                 enm->enm_addrlo[2],
 2142                 enm->enm_addrlo[3],
 2143                 enm->enm_addrlo[4],
 2144                 enm->enm_addrlo[5]);
 2145 #endif
 2146             ++cnt;
 2147             ++lo;
 2148         }
 2149         ETHER_NEXT_MULTI(step, enm);
 2150     }
 2151 #endif
 2152     outw(PIOR1(base), OFFSET_CU + 6);           /* mc-cnt */
 2153     outw(PIOP1(base), cnt * WAVELAN_ADDR_SIZE);
 2154     if(wlcmd(unit, "config()-mcaddress") == 0)
 2155         return 0;
 2156 #endif  /* MULTICAST */
 2157 
 2158     outw(PIOR1(base), OFFSET_CU);
 2159     outw(PIOP1(base), 0);                               /* ac_status */
 2160     outw(PIOP1(base), AC_IASETUP|AC_CW_EL);             /* ac_command */
 2161     outw(PIOR1(base), OFFSET_CU + 6);
 2162     outsw(PIOP1(base), sc->wl_addr, WAVELAN_ADDR_SIZE/2);
 2163 
 2164     if(wlcmd(unit, "config()-address") == 0)
 2165         return(0);
 2166 
 2167     wlinitmmc(unit);
 2168 
 2169     return(1);
 2170 }
 2171 
 2172 /*
 2173  * wlcmd:
 2174  *
 2175  * Set channel attention bit and busy wait until command has
 2176  * completed. Then acknowledge the command completion.
 2177  */
 2178 static int
 2179 wlcmd(int unit, char *str)
 2180 {
 2181     register struct wl_softc *sc = WLSOFTC(unit);
 2182     short       base = sc->base;
 2183     int i;
 2184         
 2185     outw(PIOR0(base), OFFSET_SCB + 2);  /* address of scb_command */
 2186     outw(PIOP0(base), SCB_CU_STRT);
 2187     
 2188     SET_CHAN_ATTN(unit);
 2189     
 2190     outw(PIOR0(base), OFFSET_CU);
 2191     for(i = 0; i < 0xffff; i++)
 2192         if (inw(PIOP0(base)) & AC_SW_C)
 2193             break;
 2194     if (i == 0xffff || !(inw(PIOP0(base)) & AC_SW_OK)) {
 2195         printf("wl%d: %s failed; status = %d, inw = %x, outw = %x\n",
 2196                unit, str, inw(PIOP0(base)) & AC_SW_OK, inw(PIOP0(base)), inw(PIOR0(base)));
 2197         outw(PIOR0(base), OFFSET_SCB);
 2198         printf("scb_status %x\n", inw(PIOP0(base)));
 2199         outw(PIOR0(base), OFFSET_SCB+2);
 2200         printf("scb_command %x\n", inw(PIOP0(base)));
 2201         outw(PIOR0(base), OFFSET_SCB+4);
 2202         printf("scb_cbl %x\n", inw(PIOP0(base)));
 2203         outw(PIOR0(base), OFFSET_CU+2);
 2204         printf("cu_cmd %x\n", inw(PIOP0(base)));
 2205         return(0);
 2206     }
 2207 
 2208     outw(PIOR0(base), OFFSET_SCB);
 2209     if ((inw(PIOP0(base)) & SCB_SW_INT) && (inw(PIOP0(base)) != SCB_SW_CNA)) {
 2210         /*
 2211           printf("wl%d %s: unexpected final state %x\n",
 2212           unit, str, inw(PIOP0(base)));
 2213           */
 2214     }
 2215     wlack(unit);
 2216     return(TRUE);
 2217 }       
 2218 
 2219 /*
 2220  * wlack: if the 82596 wants attention because it has finished
 2221  * sending or receiving a packet, acknowledge its desire and
 2222  * return bits indicating the kind of attention. wlack() returns
 2223  * these bits so that the caller can service exactly the
 2224  * conditions that wlack() acknowledged.
 2225  */
 2226 static int
 2227 wlack(int unit)
 2228 {
 2229     int i;
 2230     register u_short cmd;
 2231     register struct wl_softc *sc = WLSOFTC(unit);
 2232     short base = sc->base;
 2233 
 2234     outw(PIOR1(base), OFFSET_SCB);
 2235     if(!(cmd = (inw(PIOP1(base)) & SCB_SW_INT)))
 2236         return(0);
 2237 #ifdef WLDEBUG
 2238     if (sc->wl_if.if_flags & IFF_DEBUG)
 2239         printf("wl%d: doing a wlack()\n",unit);
 2240 #endif
 2241     outw(PIOP1(base), cmd);
 2242     SET_CHAN_ATTN(unit);
 2243     outw(PIOR0(base), OFFSET_SCB + 2);  /* address of scb_command */
 2244     for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
 2245     if (i < 1)
 2246         printf("wl%d wlack(): board not accepting command.\n", unit);
 2247     return(cmd);
 2248 }
 2249 
 2250 static void
 2251 wltbd(int unit)
 2252 {
 2253     register struct wl_softc *sc = WLSOFTC(unit);
 2254     short               base = sc->base;
 2255     u_short             tbd_p = OFFSET_TBD;
 2256     tbd_t               tbd;
 2257     int                 i = 0;
 2258     int                 sum = 0;
 2259 
 2260     for (;;) {
 2261         outw(PIOR1(base), tbd_p);
 2262         insw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
 2263         sum += (tbd.act_count & ~TBD_SW_EOF);
 2264         printf("%d: addr %x, count %d (%d), next %x, base %x\n",
 2265                i++, tbd.buffer_addr,
 2266                (tbd.act_count & ~TBD_SW_EOF), sum,
 2267                tbd.next_tbd_offset, tbd.buffer_base);
 2268         if (tbd.act_count & TBD_SW_EOF)
 2269             break;
 2270         tbd_p = tbd.next_tbd_offset;
 2271     }
 2272 }
 2273 
 2274 static void
 2275 wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
 2276 {
 2277     struct mbuf *tm_p = *tm_pp;
 2278     u_char              *mb_p = *mb_pp;
 2279     u_short             count = 0;
 2280     u_char              *cp;
 2281     int         len;
 2282 
 2283     /*
 2284      * can we get a run that will be coallesced or
 2285      * that terminates before breaking
 2286      */
 2287     do {
 2288         count += tm_p->m_len;
 2289         if (tm_p->m_len & 1)
 2290             break;
 2291     } while ((tm_p = tm_p->m_next) != (struct mbuf *)0);
 2292     if ( (tm_p == (struct mbuf *)0) ||
 2293          count > HDW_THRESHOLD) {
 2294         *countp = (*tm_pp)->m_len;
 2295         *mb_pp = mtod((*tm_pp), u_char *);
 2296         return;
 2297     }
 2298 
 2299     /* we need to copy */
 2300     tm_p = *tm_pp;
 2301     mb_p = *mb_pp;
 2302     count = 0;
 2303     cp = (u_char *) t_packet;
 2304     for (;;) {
 2305         bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
 2306         count += len;
 2307         if (count > HDW_THRESHOLD)
 2308                         break;
 2309         cp += len;
 2310         if (tm_p->m_next == (struct mbuf *)0)
 2311             break;
 2312         tm_p = tm_p->m_next;
 2313     }
 2314     *countp = count;
 2315     *mb_pp = (u_char *) t_packet;
 2316     *tm_pp = tm_p;
 2317     return;
 2318 }
 2319 
 2320 
 2321 static void
 2322 wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
 2323 {
 2324     struct mbuf *tm_p = *tm_pp;
 2325     u_short             count = 0;
 2326     u_char              *cp = (u_char *) t_packet;
 2327     int                 len;
 2328 
 2329     /* we need to copy */
 2330     for (;;) {
 2331         bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
 2332         count += len;
 2333         cp += len;
 2334         if (tm_p->m_next == (struct mbuf *)0)
 2335             break;
 2336         tm_p = tm_p->m_next;
 2337     }
 2338 
 2339     *countp = count;
 2340     *mb_pp = (u_char *) t_packet;
 2341     *tm_pp = tm_p;
 2342     return;
 2343 }
 2344 
 2345 static void
 2346 wlmmcstat(int unit)
 2347 {
 2348     register struct wl_softc *sc = WLSOFTC(unit);
 2349     short       base = sc->base;
 2350     u_short tmp;
 2351 
 2352     printf("wl%d: DCE_STATUS: 0x%x, ", unit,
 2353            wlmmcread(base,MMC_DCE_STATUS) & 0x0f);
 2354     tmp = wlmmcread(base,MMC_CORRECT_NWID_H) << 8;
 2355     tmp |= wlmmcread(base,MMC_CORRECT_NWID_L);
 2356     printf("Correct NWID's: %d, ", tmp);
 2357     tmp = wlmmcread(base,MMC_WRONG_NWID_H) << 8;
 2358     tmp |= wlmmcread(base,MMC_WRONG_NWID_L);
 2359     printf("Wrong NWID's: %d\n", tmp);
 2360     printf("THR_PRE_SET: 0x%x, ", wlmmcread(base,MMC_THR_PRE_SET));
 2361     printf("SIGNAL_LVL: %d, SILENCE_LVL: %d\n", 
 2362            wlmmcread(base,MMC_SIGNAL_LVL),
 2363            wlmmcread(base,MMC_SILENCE_LVL));
 2364     printf("SIGN_QUAL: 0x%x, NETW_ID: %x:%x, DES: %d\n",
 2365            wlmmcread(base,MMC_SIGN_QUAL),
 2366            wlmmcread(base,MMC_NETW_ID_H),
 2367            wlmmcread(base,MMC_NETW_ID_L),
 2368            wlmmcread(base,MMC_DES_AVAIL));
 2369 }
 2370 
 2371 static u_short
 2372 wlmmcread(u_int base, u_short reg)
 2373 {
 2374     while(inw(HASR(base)) & HASR_MMC_BUSY) ;
 2375     outw(MMCR(base),reg << 1);
 2376     while(inw(HASR(base)) & HASR_MMC_BUSY) ;
 2377     return (u_short)inw(MMCR(base)) >> 8;
 2378 }
 2379 
 2380 static void
 2381 getsnr(int unit)
 2382 {
 2383     MMC_WRITE(MMC_FREEZE,1);
 2384     /* 
 2385      * SNR retrieval procedure :
 2386      *
 2387      * read signal level : wlmmcread(base, MMC_SIGNAL_LVL);
 2388      * read silence level : wlmmcread(base, MMC_SILENCE_LVL);
 2389      */
 2390     MMC_WRITE(MMC_FREEZE,0);
 2391     /*
 2392      * SNR is signal:silence ratio.
 2393      */
 2394 }
 2395 
 2396 /*
 2397 ** wlgetpsa
 2398 **
 2399 ** Reads the psa for the wavelan at (base) into (buf)
 2400 */
 2401 static void
 2402 wlgetpsa(int base, u_char *buf)
 2403 {
 2404     int i;
 2405 
 2406     PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
 2407     PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
 2408 
 2409     for (i = 0; i < 0x40; i++) {
 2410         outw(PIOR2(base), i);
 2411         buf[i] = inb(PIOP2(base));
 2412     }
 2413     PCMD(base, HACR_DEFAULT);
 2414     PCMD(base, HACR_DEFAULT);
 2415 }
 2416 
 2417 /*
 2418 ** wlsetpsa
 2419 **
 2420 ** Writes the psa for wavelan (unit) from the softc back to the
 2421 ** board.  Updates the CRC and sets the CRC OK flag.
 2422 **
 2423 ** Do not call this when the board is operating, as it doesn't 
 2424 ** preserve the hacr.
 2425 */
 2426 static void
 2427 wlsetpsa(int unit)
 2428 {
 2429     register struct wl_softc *sc = WLSOFTC(unit);
 2430     short       base = sc->base;
 2431     int         i, oldpri;
 2432     u_short     crc;
 2433 
 2434     crc = wlpsacrc(sc->psa);    /* calculate CRC of PSA */
 2435     sc->psa[WLPSA_CRCLOW] = crc & 0xff;
 2436     sc->psa[WLPSA_CRCHIGH] = (crc >> 8) & 0xff;
 2437     sc->psa[WLPSA_CRCOK] = 0x55;        /* default to 'bad' until programming complete */
 2438 
 2439     oldpri = splimp();          /* ick, long pause */
 2440     
 2441     PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
 2442     PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
 2443     
 2444     for (i = 0; i < 0x40; i++) {
 2445         DELAY(DELAYCONST);
 2446         outw(PIOR2(base),i);  /* write param memory */
 2447         DELAY(DELAYCONST);
 2448         outb(PIOP2(base), sc->psa[i]);
 2449     }
 2450     DELAY(DELAYCONST);
 2451     outw(PIOR2(base),WLPSA_CRCOK);  /* update CRC flag*/
 2452     DELAY(DELAYCONST);
 2453     sc->psa[WLPSA_CRCOK] = 0xaa;        /* OK now */
 2454     outb(PIOP2(base), 0xaa);    /* all OK */
 2455     DELAY(DELAYCONST);
 2456     
 2457     PCMD(base, HACR_DEFAULT);
 2458     PCMD(base, HACR_DEFAULT);
 2459     
 2460     splx(oldpri);
 2461 }
 2462 
 2463 /* 
 2464 ** CRC routine provided by Christopher Giordano <cgiordan@gdeb.com>,
 2465 ** from original code by Tomi Mikkonen (tomitm@remedy.fi)
 2466 */
 2467 
 2468 static u_int crc16_table[16] = { 
 2469     0x0000, 0xCC01, 0xD801, 0x1400,
 2470     0xF001, 0x3C00, 0x2800, 0xE401,
 2471     0xA001, 0x6C00, 0x7800, 0xB401,
 2472     0x5000, 0x9C01, 0x8801, 0x4400 
 2473 };
 2474 
 2475 static u_short
 2476 wlpsacrc(u_char *buf)
 2477 {
 2478     u_short     crc = 0;
 2479     int         i, r1;
 2480     
 2481     for (i = 0; i < 0x3d; i++, buf++) {
 2482         /* lower 4 bits */
 2483         r1 = crc16_table[crc & 0xF];
 2484         crc = (crc >> 4) & 0x0FFF;
 2485         crc = crc ^ r1 ^ crc16_table[*buf & 0xF];
 2486         
 2487         /* upper 4 bits */
 2488         r1 = crc16_table[crc & 0xF];
 2489         crc = (crc >> 4) & 0x0FFF;
 2490         crc = crc ^ r1 ^ crc16_table[(*buf >> 4) & 0xF];
 2491     }
 2492     return(crc);
 2493 }
 2494 #ifdef WLCACHE
 2495 
 2496 /*
 2497  * wl_cache_store
 2498  *
 2499  * take input packet and cache various radio hw characteristics
 2500  * indexed by MAC address.
 2501  *
 2502  * Some things to think about:
 2503  *      note that no space is malloced. 
 2504  *      We might hash the mac address if the cache were bigger.
 2505  *      It is not clear that the cache is big enough.
 2506  *              It is also not clear how big it should be.
 2507  *      The cache is IP-specific.  We don't care about that as
 2508  *              we want it to be IP-specific.
 2509  *      The last N recv. packets are saved.  This will tend
 2510  *              to reward agents and mobile hosts that beacon.
 2511  *              That is probably fine for mobile ip.
 2512  */
 2513 
 2514 /* globals for wavelan signal strength cache */
 2515 /* this should go into softc structure above. 
 2516 */
 2517 
 2518 /* set true if you want to limit cache items to broadcast/mcast 
 2519  * only packets (not unicast)
 2520  */
 2521 static int wl_cache_mcastonly = 1;
 2522 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_mcastonly, CTLFLAG_RW, 
 2523         &wl_cache_mcastonly, 0, "");
 2524 
 2525 /* set true if you want to limit cache items to IP packets only
 2526 */
 2527 static int wl_cache_iponly = 1;
 2528 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_iponly, CTLFLAG_RW, 
 2529         &wl_cache_iponly, 0, "");
 2530 
 2531 /* zero out the cache
 2532 */
 2533 static void
 2534 wl_cache_zero(int unit)
 2535 {
 2536         register struct wl_softc        *sc = WLSOFTC(unit);
 2537 
 2538         bzero(&sc->w_sigcache[0], sizeof(struct w_sigcache) * MAXCACHEITEMS);
 2539         sc->w_sigitems = 0;
 2540         sc->w_nextcache = 0;
 2541         sc->w_wrapindex = 0;
 2542 }
 2543 
 2544 /* store hw signal info in cache.
 2545  * index is MAC address, but an ip src gets stored too
 2546  * There are two filters here controllable via sysctl:
 2547  *      throw out unicast (on by default, but can be turned off)
 2548  *      throw out non-ip (on by default, but can be turned off)
 2549  */
 2550 static
 2551 void wl_cache_store (int unit, int base, struct ether_header *eh,
 2552                      struct mbuf *m)
 2553 {
 2554         struct ip *ip = NULL;   /* Avoid GCC warning */
 2555         int i;
 2556         int signal, silence;
 2557         int w_insertcache;   /* computed index for cache entry storage */
 2558         register struct wl_softc *sc = WLSOFTC(unit);
 2559         int ipflag = wl_cache_iponly;
 2560 
 2561         /* filters:
 2562          * 1. ip only
 2563          * 2. configurable filter to throw out unicast packets,
 2564          * keep multicast only.
 2565          */
 2566  
 2567 #ifdef INET
 2568         /* reject if not IP packet
 2569         */
 2570         if ( wl_cache_iponly && (ntohs(eh->ether_type) != 0x800)) {
 2571                 return;
 2572         }
 2573 
 2574         /* check if broadcast or multicast packet.  we toss
 2575          * unicast packets
 2576          */
 2577         if (wl_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
 2578                 return;
 2579         }
 2580 
 2581         /* find the ip header.  we want to store the ip_src
 2582          * address.  use the mtod macro(in mbuf.h) 
 2583          * to typecast m to struct ip *
 2584          */
 2585         if (ipflag) {
 2586                 ip = mtod(m, struct ip *);
 2587         }
 2588         
 2589         /* do a linear search for a matching MAC address 
 2590          * in the cache table
 2591          * . MAC address is 6 bytes,
 2592          * . var w_nextcache holds total number of entries already cached
 2593          */
 2594         for(i = 0; i < sc->w_nextcache; i++) {
 2595                 if (! bcmp(eh->ether_shost, sc->w_sigcache[i].macsrc,  6 )) {
 2596                         /* Match!,
 2597                          * so we already have this entry,
 2598                          * update the data, and LRU age
 2599                          */
 2600                         break;  
 2601                 }
 2602         }
 2603 
 2604         /* did we find a matching mac address?
 2605          * if yes, then overwrite a previously existing cache entry
 2606          */
 2607         if (i <  sc->w_nextcache )   {
 2608                 w_insertcache = i; 
 2609         }
 2610         /* else, have a new address entry,so
 2611          * add this new entry,
 2612          * if table full, then we need to replace entry
 2613          */
 2614         else    {                          
 2615 
 2616                 /* check for space in cache table 
 2617                  * note: w_nextcache also holds number of entries
 2618                  * added in the cache table 
 2619                  */
 2620                 if ( sc->w_nextcache < MAXCACHEITEMS ) {
 2621                         w_insertcache = sc->w_nextcache;
 2622                         sc->w_nextcache++;                 
 2623                         sc->w_sigitems = sc->w_nextcache;
 2624                 }
 2625                 /* no space found, so simply wrap with wrap index
 2626                  * and "zap" the next entry
 2627                  */
 2628                 else {
 2629                         if (sc->w_wrapindex == MAXCACHEITEMS) {
 2630                                 sc->w_wrapindex = 0;
 2631                         }
 2632                         w_insertcache = sc->w_wrapindex++;
 2633                 }
 2634         }
 2635 
 2636         /* invariant: w_insertcache now points at some slot
 2637          * in cache.
 2638          */
 2639         if (w_insertcache < 0 || w_insertcache >= MAXCACHEITEMS) {
 2640                 log(LOG_ERR, 
 2641                         "wl_cache_store, bad index: %d of [0..%d], gross cache error\n",
 2642                         w_insertcache, MAXCACHEITEMS);
 2643                 return;
 2644         }
 2645 
 2646         /*  store items in cache
 2647          *  .ipsrc
 2648          *  .macsrc
 2649          *  .signal (0..63) ,silence (0..63) ,quality (0..15)
 2650          */
 2651         if (ipflag) {
 2652                 sc->w_sigcache[w_insertcache].ipsrc = ip->ip_src.s_addr;
 2653         }
 2654         bcopy( eh->ether_shost, sc->w_sigcache[w_insertcache].macsrc,  6);
 2655         signal = sc->w_sigcache[w_insertcache].signal  = wlmmcread(base, MMC_SIGNAL_LVL) & 0x3f;
 2656         silence = sc->w_sigcache[w_insertcache].silence = wlmmcread(base, MMC_SILENCE_LVL) & 0x3f;
 2657         sc->w_sigcache[w_insertcache].quality = wlmmcread(base, MMC_SIGN_QUAL) & 0x0f;
 2658         if (signal > 0)
 2659                 sc->w_sigcache[w_insertcache].snr = 
 2660                         signal - silence;
 2661         else
 2662                 sc->w_sigcache[w_insertcache].snr = 0;
 2663 #endif /* INET */
 2664 
 2665 }
 2666 #endif /* WLCACHE */
 2667 
 2668 /*
 2669  * determine if in all multicast mode or not
 2670  * 
 2671  * returns: 1 if IFF_ALLMULTI should be set
 2672  *          else 0
 2673  */
 2674 #ifdef MULTICAST
 2675 
 2676 #if defined(__FreeBSD__) && __FreeBSD_version < 300000  /* not required */
 2677 static int
 2678 check_allmulti(int unit)
 2679 {
 2680     register struct wl_softc *sc = WLSOFTC(unit);
 2681     short  base = sc->base;
 2682     struct ether_multi *enm;
 2683     struct ether_multistep step;
 2684 
 2685     ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
 2686     while (enm != NULL) {
 2687         unsigned int lo, hi;
 2688 #ifdef MDEBUG
 2689                 printf("enm_addrlo %x:%x:%x:%x:%x:%x\n", enm->enm_addrlo[0], enm->enm_addrlo[1],
 2690                 enm->enm_addrlo[2], enm->enm_addrlo[3], enm->enm_addrlo[4],
 2691                 enm->enm_addrlo[5]);
 2692                 printf("enm_addrhi %x:%x:%x:%x:%x:%x\n", enm->enm_addrhi[0], enm->enm_addrhi[1],
 2693                 enm->enm_addrhi[2], enm->enm_addrhi[3], enm->enm_addrhi[4],
 2694                 enm->enm_addrhi[5]);
 2695 #endif
 2696         if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
 2697                 return(1);
 2698         }
 2699         ETHER_NEXT_MULTI(step, enm);
 2700     }
 2701     return(0);
 2702 }
 2703 #endif
 2704 #endif

Cache object: 7c9cf78de79caa6994b7c6554bddf8fb


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