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


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

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

Cache object: 2a2fef12213d970ab36fbc345cc8aaaf


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