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/8.3/sys/dev/wl/if_wl.c 215342 2010-11-15 17:48:13Z sobomax $");
  177 
  178 /*
  179  * NOTE:
  180  *              by rvb:
  181  *  1.  The best book on the 82586 is:
  182  *              LAN Components User's Manual by Intel
  183  *      The copy I found was dated 1984.  This really tells you
  184  *      what the state machines are doing
  185  *  2.  In the current design, we only do one write at a time,
  186  *      though the hardware is capable of chaining and possibly
  187  *      even batching.  The problem is that we only make one
  188  *      transmit buffer available in sram space.
  189  */
  190 
  191 #include "opt_wavelan.h"
  192 #include "opt_inet.h"
  193 
  194 #include <sys/param.h>
  195 #include <sys/systm.h>
  196 #include <sys/kernel.h>
  197 #include <sys/module.h>
  198 #include <sys/sockio.h>
  199 #include <sys/mbuf.h>
  200 #include <sys/priv.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  * wlattach:
  467  *
  468  *      This function attaches a WaveLAN board to the "system".  The rest of
  469  *      runtime structures are initialized here (this routine is called after
  470  *      a successful probe of the board).  Once the ethernet address is read
  471  *      and stored, the board's ifnet structure is attached and readied.
  472  *
  473  * input        : isa_dev structure setup in autoconfig
  474  * output       : board structs and ifnet is setup
  475  *
  476  */
  477 static int
  478 wlattach(device_t device)
  479 {
  480     struct wl_softc     *sc;
  481     short               base;
  482     int                 error, i, j;
  483     int                 unit;
  484     struct ifnet        *ifp;
  485     u_char              eaddr[6];
  486 
  487     sc = device_get_softc(device);
  488     ifp = sc->ifp = if_alloc(IFT_ETHER);
  489     if (ifp == NULL) {
  490         device_printf(device, "can not if_alloc()\n");
  491         return (ENOSPC);
  492     }
  493 
  494     mtx_init(&sc->wl_mtx, device_get_nameunit(device), MTX_NETWORK_LOCK,
  495         MTX_DEF | MTX_RECURSE);
  496 
  497     error = wl_allocate_resources(device);
  498     if (error) {
  499         wl_deallocate_resources(device);
  500         return (ENXIO);
  501     }
  502 
  503     base = rman_get_start(sc->res_ioport);
  504     unit = device_get_unit(device);
  505 
  506 #ifdef WLDEBUG
  507     printf("wlattach: base %x, unit %d\n", base, unit);
  508 #endif
  509 
  510     sc->base = base;
  511     sc->unit = unit;
  512     sc->flags = 0;
  513     sc->mode = 0;
  514     sc->hacr = HACR_RESET;
  515     callout_handle_init(&sc->watchdog_ch);
  516     CMD(sc);                            /* reset the board */
  517     DELAY(DELAYCONST);                  /* >> 4 clocks at 6MHz */
  518         
  519     /* clear reset command and set PIO#2 in parameter access mode */
  520     sc->hacr = (HACR_DEFAULT & ~HACR_16BITS);
  521     CMD(sc);
  522 
  523     /* Read the PSA from the board for our later reference */
  524     wlgetpsa(base, sc->psa);
  525 
  526     /* fetch NWID */
  527     sc->nwid[0] = sc->psa[WLPSA_NWID];
  528     sc->nwid[1] = sc->psa[WLPSA_NWID+1];
  529     
  530     /* fetch MAC address - decide which one first */
  531     if (sc->psa[WLPSA_MACSEL] & 1)
  532         j = WLPSA_LOCALMAC;
  533     else
  534         j = WLPSA_UNIMAC;
  535     for (i=0; i < WAVELAN_ADDR_SIZE; ++i)
  536         eaddr[i] = sc->psa[j + i];
  537 
  538     /* enter normal 16 bit mode operation */
  539     sc->hacr = HACR_DEFAULT;
  540     CMD(sc);
  541 
  542     wlinitmmc(sc);
  543     outw(PIOR1(base), OFFSET_SCB + 8);  /* address of scb_crcerrs */
  544     outw(PIOP1(base), 0);                       /* clear scb_crcerrs */
  545     outw(PIOP1(base), 0);                       /* clear scb_alnerrs */
  546     outw(PIOP1(base), 0);                       /* clear scb_rscerrs */
  547     outw(PIOP1(base), 0);                       /* clear scb_ovrnerrs */
  548 
  549     ifp->if_softc = sc;
  550     ifp->if_mtu = WAVELAN_MTU;
  551     ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
  552 #ifdef    WLDEBUG
  553     ifp->if_flags |= IFF_DEBUG;
  554 #endif
  555 #if     MULTICAST
  556     ifp->if_flags |= IFF_MULTICAST;
  557 #endif  /* MULTICAST */
  558     if_initname(ifp, device_get_name(device), device_get_unit(device));
  559     ifp->if_init = wlinit;
  560     ifp->if_start = wlstart;
  561     ifp->if_ioctl = wlioctl;
  562     ifp->if_timer = 0;   /* paranoia */
  563     ifp->if_snd.ifq_maxlen = ifqmaxlen;
  564     /* no entries
  565        ifp->if_watchdog
  566        ifp->if_done
  567        ifp->if_reset
  568        */
  569     ether_ifattach(ifp, eaddr);
  570 
  571     if_printf(ifp, "NWID 0x%02x%02x", sc->nwid[0], sc->nwid[1]);
  572     if (sc->freq24) 
  573         printf(", Freq %d MHz",sc->freq24);             /* 2.4 Gz       */
  574     printf("\n");                                       /* 2.4 Gz       */
  575 
  576     bus_setup_intr(device, sc->res_irq, INTR_TYPE_NET, NULL, wlintr, sc, &sc->intr_cookie);
  577 
  578     if (bootverbose)
  579         wldump(sc);
  580     return (0);
  581 }
  582 
  583 static int
  584 wldetach(device_t device)
  585 {
  586     struct wl_softc *sc = device_get_softc(device);
  587     device_t parent = device_get_parent(device);
  588     struct ifnet *ifp;
  589 
  590     ifp = sc->ifp;
  591     ether_ifdetach(ifp);
  592 
  593     WL_LOCK(sc);
  594 
  595     /* reset the board */
  596     sc->hacr = HACR_RESET;
  597     CMD(sc);
  598     sc->hacr = HACR_DEFAULT;
  599     CMD(sc);
  600 
  601     if (sc->intr_cookie != NULL) {
  602         BUS_TEARDOWN_INTR(parent, device, sc->res_irq, sc->intr_cookie);
  603         sc->intr_cookie = NULL;
  604     }
  605 
  606     bus_generic_detach(device);
  607     wl_deallocate_resources(device);
  608     WL_UNLOCK(sc);
  609     if_free(ifp);
  610     mtx_destroy(&sc->wl_mtx);
  611     return (0);
  612 }
  613 
  614 static int
  615 wl_allocate_resources(device_t device)
  616 {
  617     struct wl_softc *sc = device_get_softc(device);
  618     int ports = 16;             /* Number of ports */
  619 
  620     sc->res_ioport = bus_alloc_resource(device, SYS_RES_IOPORT,
  621         &sc->rid_ioport, 0ul, ~0ul, ports, RF_ACTIVE);
  622     if (sc->res_ioport == NULL)
  623         goto errexit;
  624 
  625     sc->res_irq = bus_alloc_resource_any(device, SYS_RES_IRQ,
  626         &sc->rid_irq, RF_SHAREABLE|RF_ACTIVE);
  627     if (sc->res_irq == NULL)
  628         goto errexit;
  629     return (0);
  630 
  631 errexit:
  632     wl_deallocate_resources(device);
  633     return (ENXIO);
  634 }
  635 
  636 static int
  637 wl_deallocate_resources(device_t device)
  638 {
  639     struct wl_softc *sc = device_get_softc(device);
  640 
  641     if (sc->res_irq != 0) {
  642         bus_release_resource(device, SYS_RES_IRQ,
  643             sc->rid_irq, sc->res_irq);
  644         sc->res_irq = 0;
  645     }
  646     if (sc->res_ioport != 0) {
  647         bus_release_resource(device, SYS_RES_IOPORT,
  648             sc->rid_ioport, sc->res_ioport);
  649         sc->res_ioport = 0;
  650     }
  651     return (0);
  652 }
  653 
  654 /*
  655  * Print out interesting information about the 82596.
  656  */
  657 static void
  658 wldump(struct wl_softc *sc)
  659 {
  660     int         base = sc->base;
  661     int         i;
  662         
  663     printf("hasr %04x\n", inw(HASR(base)));
  664         
  665     printf("scb at %04x:\n ", OFFSET_SCB);
  666     outw(PIOR1(base), OFFSET_SCB);
  667     for (i = 0; i < 8; i++)
  668         printf("%04x ", inw(PIOP1(base)));
  669     printf("\n");
  670         
  671     printf("cu at %04x:\n ", OFFSET_CU);
  672     outw(PIOR1(base), OFFSET_CU);
  673     for (i = 0; i < 8; i++)
  674         printf("%04x ", inw(PIOP1(base)));
  675     printf("\n");
  676         
  677     printf("tbd at %04x:\n ", OFFSET_TBD);
  678     outw(PIOR1(base), OFFSET_TBD);
  679     for (i = 0; i < 4; i++)
  680         printf("%04x ", inw(PIOP1(base)));
  681     printf("\n");
  682 }
  683 
  684 /* Initialize the Modem Management Controller */
  685 static void
  686 wlinitmmc(struct wl_softc *sc)
  687 {
  688     int         base = sc->base;
  689     int         configured;
  690     int         mode = sc->mode;
  691     int         i;                              /* 2.4 Gz               */
  692         
  693     /* enter 8 bit operation */
  694     sc->hacr = (HACR_DEFAULT & ~HACR_16BITS);
  695     CMD(sc);
  696 
  697     configured = sc->psa[WLPSA_CONFIGURED] & 1;
  698         
  699     /*
  700      * Set default modem control parameters.  Taken from NCR document
  701      *  407-0024326 Rev. A 
  702      */
  703     MMC_WRITE(MMC_JABBER_ENABLE, 0x01);
  704     MMC_WRITE(MMC_ANTEN_SEL, 0x02);
  705     MMC_WRITE(MMC_IFS, 0x20);
  706     MMC_WRITE(MMC_MOD_DELAY, 0x04);
  707     MMC_WRITE(MMC_JAM_TIME, 0x38);
  708     MMC_WRITE(MMC_DECAY_PRM, 0x00);             /* obsolete ? */
  709     MMC_WRITE(MMC_DECAY_UPDAT_PRM, 0x00);
  710     if (!configured) {
  711         MMC_WRITE(MMC_LOOPT_SEL, 0x00);
  712         if (sc->psa[WLPSA_COMPATNO] & 1) {
  713             MMC_WRITE(MMC_THR_PRE_SET, 0x01);   /* 0x04 for AT and 0x01 for MCA */
  714         } else {
  715             MMC_WRITE(MMC_THR_PRE_SET, 0x04);   /* 0x04 for AT and 0x01 for MCA */
  716         }
  717         MMC_WRITE(MMC_QUALITY_THR, 0x03);
  718     } else {
  719         /* use configuration defaults from parameter storage area */
  720         if (sc->psa[WLPSA_NWIDENABLE] & 1) {
  721             if ((mode & (MOD_PROM | MOD_ENAL)) && wl_ignore_nwid) {
  722                 MMC_WRITE(MMC_LOOPT_SEL, 0x40);
  723             } else {
  724                 MMC_WRITE(MMC_LOOPT_SEL, 0x00);
  725             }
  726         } else {
  727             MMC_WRITE(MMC_LOOPT_SEL, 0x40);     /* disable network id check */
  728         }
  729         MMC_WRITE(MMC_THR_PRE_SET, sc->psa[WLPSA_THRESH]);
  730         MMC_WRITE(MMC_QUALITY_THR, sc->psa[WLPSA_QUALTHRESH]);
  731     }
  732     MMC_WRITE(MMC_FREEZE, 0x00);
  733     MMC_WRITE(MMC_ENCR_ENABLE, 0x00);
  734 
  735     MMC_WRITE(MMC_NETW_ID_L,sc->nwid[1]);       /* set NWID */
  736     MMC_WRITE(MMC_NETW_ID_H,sc->nwid[0]);
  737 
  738     /* enter normal 16 bit mode operation */
  739     sc->hacr = HACR_DEFAULT;
  740     CMD(sc);
  741     CMD(sc);                                    /* virtualpc1 needs this! */
  742 
  743     if (sc->psa[WLPSA_COMPATNO]==               /* 2.4 Gz: half-card ver     */
  744                 WLPSA_COMPATNO_WL24B) {         /* 2.4 Gz                    */
  745         i=sc->chan24<<4;                        /* 2.4 Gz: position ch #     */
  746         MMC_WRITE(MMC_EEADDR,i+0x0f);           /* 2.4 Gz: named ch, wc=16   */
  747         MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+   /* 2.4 Gz: Download Synths   */
  748                         MMC_EECTRL_EEOP_READ);  /* 2.4 Gz: Read EEPROM       */
  749         for (i=0; i<1000; ++i) {                /* 2.4 Gz: wait for download */
  750             DELAY(40);                          /* 2.4 Gz             */
  751             if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and    */
  752                 &(MMC_EECTRLstat_DWLD           /* 2.4 Gz:       EEBUSY      */
  753                  +MMC_EECTRLstat_EEBUSY))==0)   /* 2.4 Gz:                   */
  754                 break;                          /* 2.4 Gz: download finished */
  755         }                                       /* 2.4 Gz                    */
  756         if (i==1000) printf("wl: synth load failed\n"); /* 2.4 Gz       */
  757         MMC_WRITE(MMC_EEADDR,0x61);             /* 2.4 Gz: default pwr, wc=2 */
  758         MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+   /* 2.4 Gz: Download Xmit Pwr */
  759                         MMC_EECTRL_EEOP_READ);  /* 2.4 Gz: Read EEPROM       */
  760         for (i=0; i<1000; ++i) {                /* 2.4 Gz: wait for download */
  761             DELAY(40);                          /* 2.4 Gz             */
  762             if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and    */
  763                 &(MMC_EECTRLstat_DWLD           /* 2.4 Gz:       EEBUSY      */
  764                  +MMC_EECTRLstat_EEBUSY))==0)   /* 2.4 Gz:                   */
  765                 break;                          /* 2.4 Gz: download finished */
  766         }                                       /* 2.4 Gz                    */
  767         if (i==1000) printf("wl: xmit pwr load failed\n"); /* 2.4 Gz         */
  768         MMC_WRITE(MMC_ANALCTRL,                 /* 2.4 Gz: EXT ant+polarity  */
  769                         MMC_ANALCTRL_ANTPOL +   /* 2.4 Gz:                   */
  770                         MMC_ANALCTRL_EXTANT);   /* 2.4 Gz:                   */
  771         i=sc->chan24<<4;                        /* 2.4 Gz: position ch #     */
  772         MMC_WRITE(MMC_EEADDR,i);                /* 2.4 Gz: get frequency     */
  773         MMC_WRITE(MMC_EECTRL,                   /* 2.4 Gz: EEPROM read      */
  774                         MMC_EECTRL_EEOP_READ);  /* 2.4 Gz:                  */
  775         DELAY(40);                              /* 2.4 Gz                    */
  776         i = wlmmcread(base,MMC_EEDATALrv)       /* 2.4 Gz: freq val          */
  777           + (wlmmcread(base,MMC_EEDATAHrv)<<8); /* 2.4 Gz                    */
  778         sc->freq24 = (i>>6)+2400;               /* 2.4 Gz: save real freq    */
  779     }
  780 }
  781 
  782 /*
  783  * wlinit:
  784  *
  785  *      Another routine that interfaces the "if" layer to this driver.  
  786  *      Simply resets the structures that are used by "upper layers".  
  787  *      As well as calling wlhwrst that does reset the WaveLAN board.
  788  *
  789  * input        : softc pointer for this interface
  790  * output       : structures (if structs) and board are reset
  791  *
  792  */     
  793 static void
  794 wlinit(void *xsc)
  795 {
  796     struct wl_softc     *sc = xsc;
  797     struct ifnet        *ifp = sc->ifp;
  798     int                 stat;
  799     u_long              oldpri;
  800 
  801 #ifdef WLDEBUG
  802     if (sc->ifp->if_flags & IFF_DEBUG)
  803         printf("wl%d: entered wlinit()\n",sc->unit);
  804 #endif
  805     WL_LOCK(sc);
  806     oldpri = splimp();
  807     if ((stat = wlhwrst(sc)) == TRUE) {
  808         sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;   /* same as DSF_RUNNING */
  809         /* 
  810          * OACTIVE is used by upper-level routines
  811          * and must be set
  812          */
  813         sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;  /* same as tbusy below */
  814                 
  815         sc->flags |= DSF_RUNNING;
  816         sc->tbusy = 0;
  817         untimeout(wlwatchdog, sc, sc->watchdog_ch);
  818                 
  819         wlstart(ifp);
  820     } else {
  821         printf("wl%d init(): trouble resetting board.\n", sc->unit);
  822     }
  823     splx(oldpri);
  824     WL_UNLOCK(sc);
  825 }
  826 
  827 /*
  828  * wlhwrst:
  829  *
  830  *      This routine resets the WaveLAN board that corresponds to the 
  831  *      board number passed in.
  832  *
  833  * input        : board number to do a hardware reset
  834  * output       : board is reset
  835  *
  836  */
  837 static int
  838 wlhwrst(struct wl_softc *sc)
  839 {
  840 
  841 #ifdef WLDEBUG
  842     if (sc->ifp->if_flags & IFF_DEBUG)
  843         printf("wl%d: entered wlhwrst()\n", sc->unit);
  844 #endif
  845     sc->hacr = HACR_RESET;
  846     CMD(sc);                    /* reset the board */
  847         
  848     /* clear reset command and set PIO#1 in autoincrement mode */
  849     sc->hacr = HACR_DEFAULT;
  850     CMD(sc);
  851 
  852 #ifdef  WLDEBUG
  853     if (sc->ifp->if_flags & IFF_DEBUG)
  854         wlmmcstat(sc);  /* Display MMC registers */
  855 #endif  /* WLDEBUG */
  856     wlbldcu(sc);                /* set up command unit structures */
  857     
  858     if (wldiag(sc) == 0)
  859         return(0);
  860     
  861     if (wlconfig(sc) == 0)
  862             return(0);
  863     /* 
  864      * insert code for loopback test here
  865      */
  866     wlrustrt(sc);               /* start receive unit */
  867 
  868     /* enable interrupts */
  869     sc->hacr = (HACR_DEFAULT | HACR_INTRON);
  870     CMD(sc);
  871     
  872     return(1);
  873 }
  874 
  875 /*
  876  * wlbldcu:
  877  *
  878  *      This function builds up the command unit structures.  It inits
  879  *      the scp, iscp, scb, cb, tbd, and tbuf.
  880  *
  881  */
  882 static void
  883 wlbldcu(struct wl_softc *sc)
  884 {
  885     short               base = sc->base;
  886     scp_t               scp;
  887     iscp_t              iscp;
  888     scb_t               scb;
  889     ac_t                cb;
  890     tbd_t               tbd;
  891     int         i;
  892 
  893     bzero(&scp, sizeof(scp));
  894     scp.scp_sysbus = 0;
  895     scp.scp_iscp = OFFSET_ISCP;
  896     scp.scp_iscp_base = 0;
  897     outw(PIOR1(base), OFFSET_SCP);
  898     outsw(PIOP1(base), &scp, sizeof(scp_t)/2);
  899 
  900     bzero(&iscp, sizeof(iscp));
  901     iscp.iscp_busy = 1;
  902     iscp.iscp_scb_offset = OFFSET_SCB;
  903     iscp.iscp_scb = 0;
  904     iscp.iscp_scb_base = 0;
  905     outw(PIOR1(base), OFFSET_ISCP);
  906     outsw(PIOP1(base), &iscp, sizeof(iscp_t)/2);
  907 
  908     scb.scb_status = 0;
  909     scb.scb_command = SCB_RESET;
  910     scb.scb_cbl_offset = OFFSET_CU;
  911     scb.scb_rfa_offset = OFFSET_RU;
  912     scb.scb_crcerrs = 0;
  913     scb.scb_alnerrs = 0;
  914     scb.scb_rscerrs = 0;
  915     scb.scb_ovrnerrs = 0;
  916     outw(PIOR1(base), OFFSET_SCB);
  917     outsw(PIOP1(base), &scb, sizeof(scb_t)/2);
  918 
  919     SET_CHAN_ATTN(sc);
  920 
  921     outw(PIOR0(base), OFFSET_ISCP + 0); /* address of iscp_busy */
  922     for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); )
  923         continue;
  924     if (i <= 0)
  925         printf("wl%d bldcu(): iscp_busy timeout.\n", sc->unit);
  926     outw(PIOR0(base), OFFSET_SCB + 0);  /* address of scb_status */
  927     for (i = STATUS_TRIES; i-- > 0; ) {
  928         if (inw(PIOP0(base)) == (SCB_SW_CX|SCB_SW_CNA)) 
  929             break;
  930     }
  931     if (i <= 0)
  932         printf("wl%d bldcu(): not ready after reset.\n", sc->unit);
  933     wlack(sc);
  934 
  935     cb.ac_status = 0;
  936     cb.ac_command = AC_CW_EL;           /* NOP */
  937     cb.ac_link_offset = OFFSET_CU;
  938     outw(PIOR1(base), OFFSET_CU);
  939     outsw(PIOP1(base), &cb, 6/2);
  940 
  941     tbd.act_count = 0;
  942     tbd.next_tbd_offset = I82586NULL;
  943     tbd.buffer_addr = 0;
  944     tbd.buffer_base = 0;
  945     outw(PIOR1(base), OFFSET_TBD);
  946     outsw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
  947 }
  948 
  949 /*
  950  * wlstart:
  951  *
  952  *      send a packet
  953  *
  954  * input        : board number
  955  * output       : stuff sent to board if any there
  956  *
  957  */
  958 static void
  959 wlstart(struct ifnet *ifp)
  960 {
  961     struct mbuf         *m;
  962     struct wl_softc     *sc = ifp->if_softc;
  963     short               base = sc->base;
  964     int                 scb_status, cu_status, scb_command;
  965 
  966     WL_LOCK(sc);
  967 #ifdef WLDEBUG
  968     if (sc->ifp->if_flags & IFF_DEBUG)
  969         printf("%s: entered wlstart()\n", ifp->if_xname);
  970 #endif
  971 
  972     outw(PIOR1(base), OFFSET_CU);
  973     cu_status = inw(PIOP1(base));
  974     outw(PIOR0(base),OFFSET_SCB + 0);   /* scb_status */
  975     scb_status = inw(PIOP0(base));
  976     outw(PIOR0(base), OFFSET_SCB + 2);
  977     scb_command = inw(PIOP0(base));
  978 
  979     /*
  980      * don't need OACTIVE check as tbusy here checks to see
  981      * if we are already busy 
  982      */
  983     if (sc->tbusy) {
  984         if ((scb_status & 0x0700) == SCB_CUS_IDLE &&
  985            (cu_status & AC_SW_B) == 0){
  986             sc->tbusy = 0;
  987             untimeout(wlwatchdog, sc, sc->watchdog_ch);
  988             sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
  989             /*
  990              * This is probably just a race.  The xmt'r is just
  991              * became idle but WE have masked interrupts so ...
  992              */
  993 #ifdef WLDEBUG
  994             printf("%s: CU idle, scb %04x %04x cu %04x\n",
  995                    ifp->if_xname, scb_status, scb_command, cu_status);
  996 #endif 
  997             if (xmt_watch) printf("!!");
  998         } else {
  999             WL_UNLOCK(sc);
 1000             return;     /* genuinely still busy */
 1001         }
 1002     } else if ((scb_status & 0x0700) == SCB_CUS_ACTV ||
 1003       (cu_status & AC_SW_B)){
 1004 #ifdef WLDEBUG
 1005         printf("%s: CU unexpectedly busy; scb %04x cu %04x\n",
 1006                ifp->if_xname, scb_status, cu_status);
 1007 #endif
 1008         if (xmt_watch) printf("%s: busy?!",ifp->if_xname);
 1009         WL_UNLOCK(sc);
 1010         return;         /* hey, why are we busy? */
 1011     }
 1012 
 1013     /* get ourselves some data */
 1014     ifp = sc->ifp;
 1015     IF_DEQUEUE(&ifp->if_snd, m);
 1016     if (m != (struct mbuf *)0) {
 1017         /* let BPF see it before we commit it */
 1018         BPF_MTAP(ifp, m);
 1019         sc->tbusy++;
 1020         /* set the watchdog timer so that if the board
 1021          * fails to interrupt we will restart
 1022          */
 1023         /* try 10 ticks, not very long */
 1024         sc->watchdog_ch = timeout(wlwatchdog, sc, 10);
 1025         sc->ifp->if_drv_flags |= IFF_DRV_OACTIVE;
 1026         sc->ifp->if_opackets++;
 1027         wlxmt(sc, m);
 1028     } else {
 1029         sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
 1030     }
 1031     WL_UNLOCK(sc);
 1032     return;
 1033 }
 1034 
 1035 /*
 1036  * wlread:
 1037  *
 1038  *      This routine does the actual copy of data (including ethernet header
 1039  *      structure) from the WaveLAN to an mbuf chain that will be passed up
 1040  *      to the "if" (network interface) layer.  NOTE:  we currently
 1041  *      don't handle trailer protocols, so if that is needed, it will
 1042  *      (at least in part) be added here.  For simplicities sake, this
 1043  *      routine copies the receive buffers from the board into a local (stack)
 1044  *      buffer until the frame has been copied from the board.  Once in
 1045  *      the local buffer, the contents are copied to an mbuf chain that
 1046  *      is then enqueued onto the appropriate "if" queue.
 1047  *
 1048  * input        : board number, and a frame descriptor address
 1049  * output       : the packet is put into an mbuf chain, and passed up
 1050  * assumes      : if any errors occur, packet is "dropped on the floor"
 1051  *
 1052  */
 1053 static int
 1054 wlread(struct wl_softc *sc, u_short fd_p)
 1055 {
 1056     struct ifnet        *ifp = sc->ifp;
 1057     short               base = sc->base;
 1058     fd_t                fd;
 1059     struct ether_header *eh;
 1060     struct mbuf         *m;
 1061     rbd_t               rbd;
 1062     u_char              *mb_p;
 1063     u_short             mlen, len;
 1064     u_short             bytes_in_msg, bytes_in_mbuf, bytes;
 1065 
 1066     WL_LOCK_ASSERT(sc);
 1067 
 1068 #ifdef WLDEBUG
 1069     if (sc->ifp->if_flags & IFF_DEBUG)
 1070         printf("wl%d: entered wlread()\n", sc->unit);
 1071 #endif
 1072     if (!((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING))) {
 1073         printf("%s read(): board is not running.\n", ifp->if_xname);
 1074         sc->hacr &= ~HACR_INTRON;
 1075         CMD(sc);                /* turn off interrupts */
 1076     }
 1077 
 1078     /*
 1079      * Collect message size.
 1080      */
 1081     outw(PIOR1(base), fd_p);
 1082     insw(PIOP1(base), &fd, sizeof(fd_t)/2);
 1083     if (fd.rbd_offset == I82586NULL) {
 1084         if (wlhwrst(sc) != TRUE) {
 1085             sc->hacr &= ~HACR_INTRON;
 1086             CMD(sc);            /* turn off interrupts */
 1087             printf("wl%d read(): hwrst trouble.\n", sc->unit);
 1088         }
 1089         return 0;
 1090     }
 1091 
 1092     outw(PIOR1(base), fd.rbd_offset);
 1093     insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
 1094     bytes_in_msg = rbd.status & RBD_SW_COUNT;
 1095 
 1096     /*
 1097      * Allocate a cluster'd mbuf to receive the packet.
 1098      */
 1099     m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
 1100     if (m == NULL) {
 1101         if (wlhwrst(sc) != TRUE) {
 1102             sc->hacr &= ~HACR_INTRON;
 1103             CMD(sc);            /* turn off interrupts */
 1104             printf("wl%d read(): hwrst trouble.\n", sc->unit);
 1105         }
 1106         return 0;
 1107     }
 1108     m->m_pkthdr.len = m->m_len = MCLBYTES;
 1109     m_adj(m, ETHER_ALIGN);              /* align IP header */
 1110 
 1111     /*
 1112      * Collect the message data.
 1113      */
 1114     mlen = 0;
 1115     mb_p = mtod(m, u_char *);
 1116     bytes_in_mbuf = m->m_len;
 1117 
 1118     /* Put the ethernet header inside the mbuf. */
 1119     bcopy(&fd.destination[0], mb_p, 14);
 1120     mb_p += 14;
 1121     mlen += 14;
 1122     bytes_in_mbuf -= 14;
 1123 
 1124     bytes = min(bytes_in_mbuf, bytes_in_msg);
 1125     for (;;) {
 1126         if (bytes & 1) {
 1127             len = bytes + 1;
 1128         } else {
 1129             len = bytes;
 1130         }
 1131         outw(PIOR1(base), rbd.buffer_addr);
 1132         insw(PIOP1(base), mb_p, len/2);
 1133         mlen += bytes;
 1134 
 1135         if (bytes > bytes_in_mbuf) {
 1136             /* XXX something wrong, a packet should fit in 1 cluster */
 1137             m_freem(m);
 1138             printf("wl%d read(): packet too large (%u > %u)\n",
 1139                    sc->unit, bytes, bytes_in_mbuf);
 1140             if (wlhwrst(sc) != TRUE) {
 1141                 sc->hacr &= ~HACR_INTRON;
 1142                 CMD(sc);  /* turn off interrupts */
 1143                 printf("wl%d read(): hwrst trouble.\n", sc->unit);
 1144             }
 1145             return 0;
 1146         }
 1147         mb_p += bytes;
 1148         bytes_in_mbuf -= bytes;
 1149         bytes_in_msg -= bytes;
 1150         if (bytes_in_msg == 0) {
 1151             if (rbd.status & RBD_SW_EOF || rbd.next_rbd_offset == I82586NULL) {
 1152                 break;
 1153             }
 1154             outw(PIOR1(base), rbd.next_rbd_offset);
 1155             insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
 1156             bytes_in_msg = rbd.status & RBD_SW_COUNT;
 1157         } else {
 1158             rbd.buffer_addr += bytes;
 1159         }
 1160 
 1161         bytes = min(bytes_in_mbuf, bytes_in_msg);
 1162     }
 1163 
 1164     m->m_pkthdr.len = m->m_len = mlen;
 1165     m->m_pkthdr.rcvif = ifp;
 1166 
 1167     /*
 1168      * If hw is in promiscuous mode (note that I said hardware, not if
 1169      * IFF_PROMISC is set in ifnet flags), then if this is a unicast
 1170      * packet and the MAC dst is not us, drop it.  This check in normally
 1171      * inside ether_input(), but IFF_MULTI causes hw promisc without
 1172      * a bpf listener, so this is wrong.
 1173      *          Greg Troxel <gdt@ir.bbn.com>, 1998-08-07
 1174      */
 1175     /*
 1176      * TBD: also discard packets where NWID does not match.
 1177      * However, there does not appear to be a way to read the nwid
 1178      * for a received packet.  -gdt 1998-08-07
 1179      */
 1180     /* XXX verify mbuf length */
 1181     eh = mtod(m, struct ether_header *);
 1182     if (
 1183 #ifdef WL_USE_IFNET_PROMISC_CHECK /* not defined */
 1184         (sc->ifp->if_flags & (IFF_PROMISC|IFF_ALLMULTI))
 1185 #else
 1186         /* hw is in promisc mode if this is true */
 1187         (sc->mode & (MOD_PROM | MOD_ENAL))
 1188 #endif
 1189         &&
 1190         (eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
 1191         bcmp(eh->ether_dhost, IF_LLADDR(sc->ifp),
 1192              sizeof(eh->ether_dhost)) != 0 ) {
 1193       m_freem(m);
 1194       return 1;
 1195     }
 1196 
 1197 #ifdef WLDEBUG
 1198     if (sc->ifp->if_flags & IFF_DEBUG)
 1199         printf("wl%d: wlrecv %u bytes\n", sc->unit, mlen);
 1200 #endif
 1201 
 1202 #ifdef WLCACHE
 1203     wl_cache_store(sc, base, eh, m);
 1204 #endif
 1205 
 1206     /*
 1207      * received packet is now in a chain of mbuf's.  next step is
 1208      * to pass the packet upwards.
 1209      */
 1210     WL_UNLOCK(sc);
 1211     (*ifp->if_input)(ifp, m);
 1212     WL_LOCK(sc);
 1213     return 1;
 1214 }
 1215 
 1216 /*
 1217  * wlioctl:
 1218  *
 1219  *      This routine processes an ioctl request from the "if" layer
 1220  *      above.
 1221  *
 1222  * input        : pointer the appropriate "if" struct, command, and data
 1223  * output       : based on command appropriate action is taken on the
 1224  *                WaveLAN board(s) or related structures
 1225  * return       : error is returned containing exit conditions
 1226  *
 1227  */
 1228 static int
 1229 wlioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
 1230 {
 1231     struct ifreq        *ifr = (struct ifreq *)data;
 1232     struct wl_softc     *sc = ifp->if_softc;
 1233     short               base = sc->base;
 1234     short               mode = 0;
 1235     int                 opri, error = 0;
 1236     struct thread       *td = curthread;        /* XXX */
 1237     int                 irq, irqval, i, isroot;
 1238     caddr_t             up;
 1239 #ifdef WLCACHE
 1240     int                 size;
 1241     char *              cpt;
 1242 #endif
 1243 
 1244     WL_LOCK(sc);
 1245 #ifdef WLDEBUG
 1246     if (sc->ifp->if_flags & IFF_DEBUG)
 1247         printf("%s: entered wlioctl()\n", ifp->if_xname);
 1248 #endif
 1249     opri = splimp();
 1250     switch (cmd) {
 1251     case SIOCSIFFLAGS:
 1252         if (ifp->if_flags & IFF_ALLMULTI) {
 1253             mode |= MOD_ENAL;
 1254         }
 1255         if (ifp->if_flags & IFF_PROMISC) {
 1256             mode |= MOD_PROM;
 1257         }
 1258         if (ifp->if_flags & IFF_LINK0) {
 1259             mode |= MOD_PROM;
 1260         }
 1261         /*
 1262          * force a complete reset if the recieve multicast/
 1263          * promiscuous mode changes so that these take 
 1264          * effect immediately.
 1265          *
 1266          */
 1267         if (sc->mode != mode) {
 1268             sc->mode = mode;
 1269             if (sc->flags & DSF_RUNNING) {
 1270                 sc->flags &= ~DSF_RUNNING;
 1271                 wlinit(sc);
 1272             }
 1273         }
 1274         /* if interface is marked DOWN and still running then
 1275          * stop it.
 1276          */
 1277         if ((ifp->if_flags & IFF_UP) == 0 && sc->flags & DSF_RUNNING) {
 1278             printf("%s ioctl(): board is not running\n", ifp->if_xname);
 1279             sc->flags &= ~DSF_RUNNING;
 1280             sc->hacr &= ~HACR_INTRON;
 1281             CMD(sc);              /* turn off interrupts */
 1282         } 
 1283         /* else if interface is UP and RUNNING, start it
 1284                 */
 1285         else if (ifp->if_flags & IFF_UP && (sc->flags & DSF_RUNNING) == 0) {
 1286             wlinit(sc);
 1287         }
 1288   
 1289         /* if WLDEBUG set on interface, then printf rf-modem regs
 1290         */
 1291         if (ifp->if_flags & IFF_DEBUG)
 1292             wlmmcstat(sc);
 1293         break;
 1294 #if     MULTICAST
 1295     case SIOCADDMULTI:
 1296     case SIOCDELMULTI:
 1297 
 1298         wlinit(sc);
 1299         break;
 1300 #endif  /* MULTICAST */
 1301 
 1302     /* DEVICE SPECIFIC */
 1303 
 1304 
 1305         /* copy the PSA out to the caller */
 1306     case SIOCGWLPSA:
 1307         /* pointer to buffer in user space */
 1308         up = (void *)ifr->ifr_data;
 1309         /* work out if they're root */
 1310         isroot = (priv_check(td, PRIV_NET80211_GETKEY) == 0);
 1311         
 1312         for (i = 0; i < 0x40; i++) {
 1313             /* don't hand the DES key out to non-root users */
 1314             if ((i > WLPSA_DESKEY) && (i < (WLPSA_DESKEY + 8)) && !isroot)
 1315                 continue;
 1316             if (subyte((up + i), sc->psa[i])) {
 1317                 WL_UNLOCK(sc);
 1318                 return(EFAULT);
 1319             }
 1320         }
 1321         break;
 1322 
 1323 
 1324         /* copy the PSA in from the caller; we only copy _some_ values */
 1325     case SIOCSWLPSA:
 1326         /* root only */
 1327         if ((error = priv_check(td, PRIV_DRIVER)))
 1328             break;
 1329         error = EINVAL; /* assume the worst */
 1330         /* pointer to buffer in user space containing data */
 1331         up = (void *)ifr->ifr_data;
 1332         
 1333         /* check validity of input range */
 1334         for (i = 0; i < 0x40; i++)
 1335             if (fubyte(up + i) < 0) {
 1336                 WL_UNLOCK(sc);
 1337                 return(EFAULT);
 1338             }
 1339 
 1340         /* check IRQ value */
 1341         irqval = fubyte(up+WLPSA_IRQNO);
 1342         for (irq = 15; irq >= 0; irq--)
 1343             if (irqvals[irq] == irqval)
 1344                 break;
 1345         if (irq == 0)                   /* oops */
 1346             break;
 1347         /* new IRQ */
 1348         sc->psa[WLPSA_IRQNO] = irqval;
 1349 
 1350         /* local MAC */
 1351         for (i = 0; i < 6; i++)
 1352             sc->psa[WLPSA_LOCALMAC+i] = fubyte(up+WLPSA_LOCALMAC+i);
 1353                 
 1354         /* MAC select */        
 1355         sc->psa[WLPSA_MACSEL] = fubyte(up+WLPSA_MACSEL);
 1356         
 1357         /* default nwid */
 1358         sc->psa[WLPSA_NWID] = fubyte(up+WLPSA_NWID);
 1359         sc->psa[WLPSA_NWID+1] = fubyte(up+WLPSA_NWID+1);
 1360 
 1361         error = 0;
 1362         wlsetpsa(sc);           /* update the PSA */
 1363         break;
 1364 
 1365 
 1366         /* get the current NWID out of the sc since we stored it there */
 1367     case SIOCGWLCNWID:
 1368         ifr->ifr_data = (caddr_t) (sc->nwid[0] << 8 | sc->nwid[1]);
 1369         break;
 1370 
 1371 
 1372         /*
 1373          * change the nwid dynamically.  This
 1374          * ONLY changes the radio modem and does not
 1375          * change the PSA.
 1376          *
 1377          * 2 steps:
 1378          *      1. save in softc "soft registers"
 1379          *      2. save in radio modem (MMC)
 1380          */
 1381     case SIOCSWLCNWID:
 1382         /* root only */
 1383         if ((error = priv_check(td, PRIV_DRIVER)))
 1384             break;
 1385         if (!(ifp->if_flags & IFF_UP)) {
 1386             error = EIO;        /* only allowed while up */
 1387         } else {
 1388             /* 
 1389              * soft c nwid shadows radio modem setting
 1390              */
 1391             sc->nwid[0] = (int)ifr->ifr_data >> 8;
 1392             sc->nwid[1] = (int)ifr->ifr_data & 0xff;
 1393             MMC_WRITE(MMC_NETW_ID_L,sc->nwid[1]);
 1394             MMC_WRITE(MMC_NETW_ID_H,sc->nwid[0]);
 1395         }
 1396         break;
 1397 
 1398         /* copy the EEPROM in 2.4 Gz WaveMODEM  out to the caller */
 1399     case SIOCGWLEEPROM:
 1400         /* root only */
 1401         if ((error = priv_check(td, PRIV_DRIVER)))
 1402             break;
 1403         /* pointer to buffer in user space */
 1404         up = (void *)ifr->ifr_data;
 1405         
 1406         for (i=0x00; i<0x80; ++i) {             /* 2.4 Gz: size of EEPROM   */
 1407             MMC_WRITE(MMC_EEADDR,i);            /* 2.4 Gz: get frequency    */
 1408             MMC_WRITE(MMC_EECTRL,               /* 2.4 Gz: EEPROM read      */
 1409                         MMC_EECTRL_EEOP_READ);  /* 2.4 Gz:                  */
 1410             DELAY(40);                          /* 2.4 Gz                   */
 1411             if (subyte(up + 2*i,                /* 2.4 Gz: pass low byte of */
 1412                 wlmmcread(base,MMC_EEDATALrv))) {/* 2.4 Gz: EEPROM word      */
 1413                 WL_UNLOCK(sc);
 1414                 return(EFAULT);                 /* 2.4 Gz:                  */
 1415             }
 1416             if (subyte(up + 2*i+1,              /* 2.4 Gz: pass hi byte of  */
 1417                 wlmmcread(base,MMC_EEDATALrv))) {/* 2.4 Gz: EEPROM word      */
 1418                 WL_UNLOCK(sc);
 1419                 return(EFAULT);                 /* 2.4 Gz:                  */
 1420             }
 1421         }
 1422         break;
 1423 
 1424 #ifdef WLCACHE
 1425         /* zero (Delete) the wl cache */
 1426     case SIOCDWLCACHE:
 1427         /* root only */
 1428         if ((error = priv_check(td, PRIV_DRIVER)))
 1429             break;
 1430         wl_cache_zero(sc);
 1431         break;
 1432 
 1433         /* read out the number of used cache elements */
 1434     case SIOCGWLCITEM:
 1435         ifr->ifr_data = (caddr_t) sc->w_sigitems;
 1436         break;
 1437 
 1438         /* read out the wl cache */
 1439     case SIOCGWLCACHE:
 1440         /* pointer to buffer in user space */
 1441         up = (void *)ifr->ifr_data;
 1442         cpt = (char *) &sc->w_sigcache[0];
 1443         size = sc->w_sigitems * sizeof(struct w_sigcache);
 1444         
 1445         for (i = 0; i < size; i++) {
 1446             if (subyte((up + i), *cpt++)) {
 1447                 WL_UNLOCK(sc);
 1448                 return(EFAULT);
 1449             }
 1450         }
 1451         break;
 1452 #endif
 1453 
 1454     default:
 1455         error = ether_ioctl(ifp, cmd, data);
 1456         break;
 1457     }
 1458     splx(opri);
 1459     WL_UNLOCK(sc);
 1460     return (error);
 1461 }
 1462 
 1463 /*
 1464  * wlwatchdog():
 1465  *
 1466  * Called if the timer set in wlstart expires before an interrupt is received
 1467  * from the wavelan.   It seems to lose interrupts sometimes.
 1468  * The watchdog routine gets called if the transmitter failed to interrupt
 1469  *
 1470  * input        : which board is timing out
 1471  * output       : board reset 
 1472  *
 1473  */
 1474 static void
 1475 wlwatchdog(void *vsc)
 1476 {
 1477     struct wl_softc *sc = vsc;
 1478     int unit = sc->unit;
 1479 
 1480     log(LOG_ERR, "wl%d: wavelan device timeout on xmit\n", unit);
 1481     WL_LOCK(sc);
 1482     sc->ifp->if_oerrors++;
 1483     wlinit(sc);
 1484     WL_UNLOCK(sc);
 1485 }
 1486 
 1487 /*
 1488  * wlintr:
 1489  *
 1490  *      This function is the interrupt handler for the WaveLAN
 1491  *      board.  This routine will be called whenever either a packet
 1492  *      is received, or a packet has successfully been transfered and
 1493  *      the unit is ready to transmit another packet.
 1494  *
 1495  * input        : board number that interrupted
 1496  * output       : either a packet is received, or a packet is transfered
 1497  *
 1498  */
 1499 static void
 1500 wlintr(void *arg)
 1501 {
 1502     struct wl_softc     *sc = (struct wl_softc *)arg;
 1503     short               base = sc->base;
 1504     int                 ac_status;
 1505     u_short             int_type, int_type1;
 1506 
 1507     WL_LOCK(sc);
 1508 #ifdef WLDEBUG
 1509     if (sc->ifp->if_flags & IFF_DEBUG)
 1510         printf("wl%d: wlintr() called\n", sc->unit);
 1511 #endif
 1512 
 1513     if ((int_type = inw(HASR(base))) & HASR_MMC_INTR) {
 1514         /* handle interrupt from the modem management controler */
 1515         /* This will clear the interrupt condition */ 
 1516         (void) wlmmcread(base,MMC_DCE_STATUS); /* ignored for now */
 1517     }
 1518 
 1519     if (!(int_type & HASR_INTR)){       /* return if no interrupt from 82586 */
 1520         /* commented out. jrb.  it happens when reinit occurs
 1521            printf("wlintr: int_type %x, dump follows\n", int_type);
 1522            wldump(unit);
 1523            */
 1524         WL_UNLOCK(sc);
 1525         return;
 1526     }
 1527 
 1528     if (gathersnr)
 1529         getsnr(sc);
 1530     for (;;) {
 1531         outw(PIOR0(base), OFFSET_SCB + 0);      /* get scb status */
 1532         int_type = (inw(PIOP0(base)) & SCB_SW_INT);
 1533         if (int_type == 0)                      /* no interrupts left */
 1534             break;
 1535 
 1536         int_type1 = wlack(sc);          /* acknowledge interrupt(s) */
 1537         /* make sure no bits disappeared (others may appear) */
 1538         if ((int_type & int_type1) != int_type)
 1539             printf("wlack() int bits disappeared : %04x != int_type %04x\n",
 1540                    int_type1, int_type);
 1541         int_type = int_type1;                   /* go with the new status */
 1542         /* 
 1543          * incoming packet
 1544          */
 1545         if (int_type & SCB_SW_FR) {
 1546             sc->ifp->if_ipackets++;
 1547             wlrcv(sc);
 1548         }
 1549         /*
 1550          * receiver not ready
 1551          */
 1552         if (int_type & SCB_SW_RNR) {
 1553             sc->ifp->if_ierrors++;
 1554 #ifdef  WLDEBUG
 1555             if (sc->ifp->if_flags & IFF_DEBUG)
 1556                 printf("wl%d intr(): receiver overrun! begin_fd = %x\n",
 1557                        sc->unit, sc->begin_fd);
 1558 #endif
 1559             wlrustrt(sc);
 1560         }
 1561         /*
 1562          * CU not ready
 1563          */
 1564         if (int_type & SCB_SW_CNA) {
 1565             /*
 1566              * At present, we don't care about CNA's.  We
 1567              * believe they are a side effect of XMT.
 1568              */
 1569         }
 1570         if (int_type & SCB_SW_CX) {
 1571             /*
 1572              * At present, we only request Interrupt for
 1573              * XMT.
 1574              */
 1575             outw(PIOR1(base), OFFSET_CU);       /* get command status */
 1576             ac_status = inw(PIOP1(base));
 1577 
 1578             if (xmt_watch) {                    /* report some anomalies */
 1579 
 1580                 if (sc->tbusy == 0) {
 1581                     printf("wl%d: xmt intr but not busy, CU %04x\n",
 1582                            sc->unit, ac_status);
 1583                 }
 1584                 if (ac_status == 0) {
 1585                     printf("wl%d: xmt intr but ac_status == 0\n", sc->unit);
 1586                 }
 1587                 if (ac_status & AC_SW_A) {
 1588                     printf("wl%d: xmt aborted\n", sc->unit);
 1589                 }
 1590 #ifdef  notdef
 1591                 if (ac_status & TC_CARRIER) {
 1592                     printf("wl%d: no carrier\n", sc->unit);
 1593                 }
 1594 #endif  /* notdef */
 1595                 if (ac_status & TC_CLS) {
 1596                     printf("wl%d: no CTS\n", sc->unit);
 1597                 }
 1598                 if (ac_status & TC_DMA) {
 1599                     printf("wl%d: DMA underrun\n", sc->unit);
 1600                 }
 1601                 if (ac_status & TC_DEFER) {
 1602                     printf("wl%d: xmt deferred\n", sc->unit);
 1603                 }
 1604                 if (ac_status & TC_SQE) {
 1605                     printf("wl%d: heart beat\n", sc->unit);
 1606                 }
 1607                 if (ac_status & TC_COLLISION) {
 1608                     printf("wl%d: too many collisions\n", sc->unit);
 1609                 }
 1610             }
 1611             /* if the transmit actually failed, or returned some status */
 1612             if ((!(ac_status & AC_SW_OK)) || (ac_status & 0xfff)) {
 1613                 if (ac_status & (TC_COLLISION | TC_CLS | TC_DMA)) {
 1614                     sc->ifp->if_oerrors++;
 1615                 }
 1616                 /* count collisions */
 1617                 sc->ifp->if_collisions += (ac_status & 0xf);
 1618                 /* if TC_COLLISION set and collision count zero, 16 collisions */
 1619                 if ((ac_status & 0x20) == 0x20) {
 1620                     sc->ifp->if_collisions += 0x10;
 1621                 }
 1622             }
 1623             sc->tbusy = 0;
 1624             untimeout(wlwatchdog, sc, sc->watchdog_ch);
 1625             sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
 1626             wlstart(sc->ifp);
 1627         }
 1628     }
 1629     WL_UNLOCK(sc);
 1630     return;
 1631 }
 1632 
 1633 /*
 1634  * wlrcv:
 1635  *
 1636  *      This routine is called by the interrupt handler to initiate a
 1637  *      packet transfer from the board to the "if" layer above this
 1638  *      driver.  This routine checks if a buffer has been successfully
 1639  *      received by the WaveLAN.  If so, the routine wlread is called
 1640  *      to do the actual transfer of the board data (including the
 1641  *      ethernet header) into a packet (consisting of an mbuf chain).
 1642  *
 1643  * input        : number of the board to check
 1644  * output       : if a packet is available, it is "sent up"
 1645  *
 1646  */
 1647 static void
 1648 wlrcv(struct wl_softc *sc)
 1649 {
 1650     short       base = sc->base;
 1651     u_short     fd_p, status, offset, link_offset;
 1652 
 1653 #ifdef WLDEBUG
 1654     if (sc->ifp->if_flags & IFF_DEBUG)
 1655         printf("wl%d: entered wlrcv()\n", sc->unit);
 1656 #endif
 1657     for (fd_p = sc->begin_fd; fd_p != I82586NULL; fd_p = sc->begin_fd) {
 1658 
 1659         outw(PIOR0(base), fd_p + 0);    /* address of status */
 1660         status = inw(PIOP0(base));
 1661         outw(PIOR1(base), fd_p + 4);    /* address of link_offset */
 1662         link_offset = inw(PIOP1(base));
 1663         offset = inw(PIOP1(base));      /* rbd_offset */
 1664         if (status == 0xffff || offset == 0xffff /*I82586NULL*/) {
 1665             if (wlhwrst(sc) != TRUE)
 1666                 printf("wl%d rcv(): hwrst ffff trouble.\n", sc->unit);
 1667             return;
 1668         } else if (status & AC_SW_C) {
 1669             if (status == (RFD_DONE|RFD_RSC)) {
 1670                 /* lost one */
 1671 #ifdef  WLDEBUG
 1672                 if (sc->ifp->if_flags & IFF_DEBUG)
 1673                     printf("wl%d RCV: RSC %x\n", sc->unit, status);
 1674 #endif
 1675                 sc->ifp->if_ierrors++;
 1676             } else if (!(status & RFD_OK)) {
 1677                 printf("wl%d RCV: !OK %x\n", sc->unit, status);
 1678                 sc->ifp->if_ierrors++;
 1679             } else if (status & 0xfff) {        /* can't happen */
 1680                 printf("wl%d RCV: ERRs %x\n", sc->unit, status);
 1681                 sc->ifp->if_ierrors++;
 1682             } else if (!wlread(sc, fd_p))
 1683                 return;
 1684 
 1685             if (!wlrequeue(sc, fd_p)) {
 1686                 /* abort on chain error */
 1687                 if (wlhwrst(sc) != TRUE)
 1688                     printf("wl%d rcv(): hwrst trouble.\n", sc->unit);
 1689                 return;
 1690             }
 1691             sc->begin_fd = link_offset;
 1692         } else {
 1693             break;
 1694         }
 1695     }
 1696     return;
 1697 }
 1698 
 1699 /*
 1700  * wlrequeue:
 1701  *
 1702  *      This routine puts rbd's used in the last receive back onto the
 1703  *      free list for the next receive.
 1704  *
 1705  */
 1706 static int
 1707 wlrequeue(struct wl_softc *sc, u_short fd_p)
 1708 {
 1709     short               base = sc->base;
 1710     fd_t                fd;
 1711     u_short             l_rbdp, f_rbdp, rbd_offset;
 1712 
 1713     outw(PIOR0(base), fd_p + 6);
 1714     rbd_offset = inw(PIOP0(base));
 1715     if ((f_rbdp = rbd_offset) != I82586NULL) {
 1716         l_rbdp = f_rbdp;
 1717         for (;;) {
 1718             outw(PIOR0(base), l_rbdp + 0);      /* address of status */
 1719             if (inw(PIOP0(base)) & RBD_SW_EOF)
 1720                 break;
 1721             outw(PIOP0(base), 0);
 1722             outw(PIOR0(base), l_rbdp + 2);      /* next_rbd_offset */
 1723             if ((l_rbdp = inw(PIOP0(base))) == I82586NULL)
 1724                 break;
 1725         }
 1726         outw(PIOP0(base), 0);
 1727         outw(PIOR0(base), l_rbdp + 2);          /* next_rbd_offset */
 1728         outw(PIOP0(base), I82586NULL);
 1729         outw(PIOR0(base), l_rbdp + 8);          /* address of size */
 1730         outw(PIOP0(base), inw(PIOP0(base)) | AC_CW_EL);
 1731         outw(PIOR0(base), sc->end_rbd + 2);
 1732         outw(PIOP0(base), f_rbdp);              /* end_rbd->next_rbd_offset */
 1733         outw(PIOR0(base), sc->end_rbd + 8);     /* size */
 1734         outw(PIOP0(base), inw(PIOP0(base)) & ~AC_CW_EL);
 1735         sc->end_rbd = l_rbdp;
 1736     }
 1737 
 1738     fd.status = 0;
 1739     fd.command = AC_CW_EL;
 1740     fd.link_offset = I82586NULL;
 1741     fd.rbd_offset = I82586NULL;
 1742     outw(PIOR1(base), fd_p);
 1743     outsw(PIOP1(base), &fd, 8/2);
 1744     
 1745     outw(PIOR1(base), sc->end_fd + 2);  /* addr of command */
 1746     outw(PIOP1(base), 0);               /* command = 0 */
 1747     outw(PIOP1(base), fd_p);            /* end_fd->link_offset = fd_p */
 1748     sc->end_fd = fd_p;
 1749 
 1750     return 1;
 1751 }
 1752 
 1753 #ifdef  WLDEBUG
 1754 static int xmt_debug = 0;
 1755 #endif  /* WLDEBUG */
 1756 
 1757 /*
 1758  * wlxmt:
 1759  *
 1760  *      This routine fills in the appropriate registers and memory
 1761  *      locations on the WaveLAN board and starts the board off on
 1762  *      the transmit.
 1763  *
 1764  * input        : pointers to board of interest's softc and the mbuf
 1765  * output       : board memory and registers are set for xfer and attention
 1766  *
 1767  */
 1768 static void
 1769 wlxmt(struct wl_softc *sc, struct mbuf *m)
 1770 {
 1771     u_short             xmtdata_p = OFFSET_TBUF;
 1772     u_short             xmtshort_p;
 1773     struct mbuf         *tm_p = m;
 1774     struct ether_header *eh_p = mtod(m, struct ether_header *);
 1775     u_char              *mb_p = mtod(m, u_char *) + sizeof(struct ether_header);
 1776     u_short             count = m->m_len - sizeof(struct ether_header);
 1777     ac_t                cb;
 1778     u_short             tbd_p = OFFSET_TBD;
 1779     u_short             len, clen = 0;
 1780     short               base = sc->base;
 1781     int                 spin;
 1782         
 1783 #ifdef WLDEBUG
 1784     if (sc->ifp->if_flags & IFF_DEBUG)
 1785         printf("%s: entered wlxmt()\n", sc->ifp->if_xname);
 1786 #endif
 1787 
 1788     cb.ac_status = 0;
 1789     cb.ac_command = (AC_CW_EL|AC_TRANSMIT|AC_CW_I);
 1790     cb.ac_link_offset = I82586NULL;
 1791     outw(PIOR1(base), OFFSET_CU);
 1792     outsw(PIOP1(base), &cb, 6/2);
 1793     outw(PIOP1(base), OFFSET_TBD);      /* cb.cmd.transmit.tbd_offset */
 1794     outsw(PIOP1(base), eh_p->ether_dhost, WAVELAN_ADDR_SIZE/2);
 1795     outw(PIOP1(base), eh_p->ether_type);
 1796 
 1797 #ifdef  WLDEBUG
 1798     if (sc->ifp->if_flags & IFF_DEBUG) {
 1799         if (xmt_debug) {
 1800             printf("XMT    mbuf: L%d @%p ", count, (void *)mb_p);
 1801             printf("ether type %x\n", eh_p->ether_type);
 1802         }
 1803     }
 1804 #endif  /* WLDEBUG */
 1805     outw(PIOR0(base), OFFSET_TBD);
 1806     outw(PIOP0(base), 0);               /* act_count */
 1807     outw(PIOR1(base), OFFSET_TBD + 4);
 1808     outw(PIOP1(base), xmtdata_p);       /* buffer_addr */
 1809     outw(PIOP1(base), 0);               /* buffer_base */
 1810     for (;;) {
 1811         if (count) {
 1812             if (clen + count > WAVELAN_MTU)
 1813                 break;
 1814             if (count & 1)
 1815                 len = count + 1;
 1816             else
 1817                 len = count;
 1818             outw(PIOR1(base), xmtdata_p);
 1819             outsw(PIOP1(base), mb_p, len/2);
 1820             clen += count;
 1821             outw(PIOR0(base), tbd_p);  /* address of act_count */
 1822             outw(PIOP0(base), inw(PIOP0(base)) + count);
 1823             xmtdata_p += len;
 1824             if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
 1825                 break;
 1826             if (count & 1) {
 1827                 /* go to the next descriptor */
 1828                 outw(PIOR0(base), tbd_p + 2);
 1829                 tbd_p += sizeof (tbd_t);
 1830                 outw(PIOP0(base), tbd_p); /* next_tbd_offset */
 1831                 outw(PIOR0(base), tbd_p);
 1832                 outw(PIOP0(base), 0);   /* act_count */
 1833                 outw(PIOR1(base), tbd_p + 4);
 1834                 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
 1835                 outw(PIOP1(base), 0);         /* buffer_base */
 1836                 /* at the end -> coallesce remaining mbufs */
 1837                 if (tbd_p == OFFSET_TBD + (N_TBD-1) * sizeof (tbd_t)) {
 1838                     wlsftwsleaze(&count, &mb_p, &tm_p, sc);
 1839                     continue;
 1840                 }
 1841                 /* next mbuf short -> coallesce as needed */
 1842                 if ( (tm_p->m_next == (struct mbuf *) 0) ||
 1843 #define HDW_THRESHOLD 55
 1844                      tm_p->m_len > HDW_THRESHOLD)
 1845                     /* ok */;
 1846                 else {
 1847                     wlhdwsleaze(&count, &mb_p, &tm_p, sc);
 1848                     continue;
 1849                 }
 1850             }
 1851         } else if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
 1852             break;
 1853         count = tm_p->m_len;
 1854         mb_p = mtod(tm_p, u_char *);
 1855 #ifdef  WLDEBUG
 1856         if (sc->ifp->if_flags & IFF_DEBUG)
 1857             if (xmt_debug)
 1858                 printf("mbuf+ L%d @%p ", count, (void *)mb_p);
 1859 #endif  /* WLDEBUG */
 1860     }
 1861 #ifdef  WLDEBUG
 1862     if (sc->ifp->if_flags & IFF_DEBUG)
 1863         if (xmt_debug)
 1864             printf("CLEN = %d\n", clen);
 1865 #endif  /* WLDEBUG */
 1866     outw(PIOR0(base), tbd_p);
 1867     if (clen < ETHERMIN) {
 1868         outw(PIOP0(base), inw(PIOP0(base)) + ETHERMIN - clen);
 1869         outw(PIOR1(base), xmtdata_p);
 1870         for (xmtshort_p = xmtdata_p; clen < ETHERMIN; clen += 2)
 1871             outw(PIOP1(base), 0);
 1872     }   
 1873     outw(PIOP0(base), inw(PIOP0(base)) | TBD_SW_EOF);
 1874     outw(PIOR0(base), tbd_p + 2);
 1875     outw(PIOP0(base), I82586NULL);
 1876 #ifdef  WLDEBUG
 1877     if (sc->ifp->if_flags & IFF_DEBUG) {
 1878         if (xmt_debug) {
 1879             wltbd(sc);
 1880             printf("\n");
 1881         }
 1882     }
 1883 #endif  /* WLDEBUG */
 1884 
 1885     outw(PIOR0(base), OFFSET_SCB + 2);  /* address of scb_command */
 1886     /* 
 1887      * wait for 586 to clear previous command, complain if it takes
 1888      * too long
 1889      */
 1890     for (spin = 1;;spin = (spin + 1) % 10000) {
 1891         if (inw(PIOP0(base)) == 0) {            /* it's done, we can go */
 1892             break;
 1893         }
 1894         if ((spin == 0) && xmt_watch) {         /* not waking up, and we care */
 1895                 printf("%s: slow accepting xmit\n", sc->ifp->if_xname);
 1896         }
 1897     }
 1898     outw(PIOP0(base), SCB_CU_STRT);             /* new command */
 1899     SET_CHAN_ATTN(sc);
 1900     
 1901     m_freem(m);
 1902 
 1903     /* XXX 
 1904      * Pause to avoid transmit overrun problems.
 1905      * The required delay tends to vary with platform type, and may be
 1906      * related to interrupt loss.
 1907      */
 1908     if (wl_xmit_delay) {
 1909         DELAY(wl_xmit_delay);
 1910     }
 1911     return;
 1912 }
 1913 
 1914 /*
 1915  * wlbldru:
 1916  *
 1917  *      This function builds the linear linked lists of fd's and
 1918  *      rbd's.  Based on page 4-32 of 1986 Intel microcom handbook.
 1919  *
 1920  */
 1921 static u_short
 1922 wlbldru(struct wl_softc *sc)
 1923 {
 1924     short       base = sc->base;
 1925     fd_t        fd;
 1926     rbd_t       rbd;
 1927     u_short     fd_p = OFFSET_RU;
 1928     u_short     rbd_p = OFFSET_RBD;
 1929     int         i;
 1930 
 1931     sc->begin_fd = fd_p;
 1932     for (i = 0; i < N_FD; i++) {
 1933         fd.status = 0;
 1934         fd.command = 0;
 1935         fd.link_offset = fd_p + sizeof(fd_t);
 1936         fd.rbd_offset = I82586NULL;
 1937         outw(PIOR1(base), fd_p);
 1938         outsw(PIOP1(base), &fd, 8/2);
 1939         fd_p = fd.link_offset;
 1940     }
 1941     fd_p -= sizeof(fd_t);
 1942     sc->end_fd = fd_p;
 1943     outw(PIOR1(base), fd_p + 2);
 1944     outw(PIOP1(base), AC_CW_EL);        /* command */
 1945     outw(PIOP1(base), I82586NULL);      /* link_offset */
 1946     fd_p = OFFSET_RU;
 1947     
 1948     outw(PIOR0(base), fd_p + 6);        /* address of rbd_offset */
 1949     outw(PIOP0(base), rbd_p);
 1950     outw(PIOR1(base), rbd_p);
 1951     for (i = 0; i < N_RBD; i++) {
 1952         rbd.status = 0;
 1953         rbd.buffer_addr = rbd_p + sizeof(rbd_t) + 2;
 1954         rbd.buffer_base = 0;
 1955         rbd.size = RCVBUFSIZE;
 1956         if (i != N_RBD-1) {
 1957             rbd_p += sizeof(ru_t);
 1958             rbd.next_rbd_offset = rbd_p;
 1959         } else {
 1960             rbd.next_rbd_offset = I82586NULL;
 1961             rbd.size |= AC_CW_EL;
 1962             sc->end_rbd = rbd_p;
 1963         }
 1964         outsw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
 1965         outw(PIOR1(base), rbd_p);
 1966     }
 1967     return sc->begin_fd;
 1968 }
 1969 
 1970 /*
 1971  * wlrustrt:
 1972  *
 1973  *      This routine starts the receive unit running.  First checks if the
 1974  *      board is actually ready, then the board is instructed to receive
 1975  *      packets again.
 1976  *
 1977  */
 1978 static void
 1979 wlrustrt(struct wl_softc *sc)
 1980 {
 1981     short               base = sc->base;
 1982     u_short             rfa;
 1983 
 1984 #ifdef WLDEBUG
 1985     if (sc->ifp->if_flags & IFF_DEBUG)
 1986         printf("wl%d: entered wlrustrt()\n", sc->unit);
 1987 #endif
 1988     outw(PIOR0(base), OFFSET_SCB);
 1989     if (inw(PIOP0(base)) & SCB_RUS_READY){
 1990         printf("wlrustrt: RUS_READY\n");
 1991         return;
 1992     }
 1993 
 1994     outw(PIOR0(base), OFFSET_SCB + 2);
 1995     outw(PIOP0(base), SCB_RU_STRT);             /* command */
 1996     rfa = wlbldru(sc);
 1997     outw(PIOR0(base), OFFSET_SCB + 6);  /* address of scb_rfa_offset */
 1998     outw(PIOP0(base), rfa);
 1999 
 2000     SET_CHAN_ATTN(sc);
 2001     return;
 2002 }
 2003 
 2004 /*
 2005  * wldiag:
 2006  *
 2007  *      This routine does a 586 op-code number 7, and obtains the
 2008  *      diagnose status for the WaveLAN.
 2009  *
 2010  */
 2011 static int
 2012 wldiag(struct wl_softc *sc)
 2013 {
 2014     short       base = sc->base;
 2015     short       status;
 2016 
 2017 #ifdef WLDEBUG
 2018     if (sc->ifp->if_flags & IFF_DEBUG)
 2019         printf("wl%d: entered wldiag()\n", sc->unit);
 2020 #endif
 2021     outw(PIOR0(base), OFFSET_SCB);
 2022     status = inw(PIOP0(base));
 2023     if (status & SCB_SW_INT) {
 2024                 /* state is 2000 which seems ok
 2025                    printf("wl%d diag(): unexpected initial state %\n",
 2026                    sc->unit, inw(PIOP0(base)));
 2027                 */
 2028         wlack(sc);
 2029     }
 2030     outw(PIOR1(base), OFFSET_CU);
 2031     outw(PIOP1(base), 0);                       /* ac_status */
 2032     outw(PIOP1(base), AC_DIAGNOSE|AC_CW_EL);/* ac_command */
 2033     if (wlcmd(sc, "diag()") == 0)
 2034         return 0;
 2035     outw(PIOR0(base), OFFSET_CU);
 2036     if (inw(PIOP0(base)) & 0x0800) {
 2037         printf("wl%d: i82586 Self Test failed!\n", sc->unit);
 2038         return 0;
 2039     }
 2040     return TRUE;
 2041 }
 2042 
 2043 /*
 2044  * wlconfig:
 2045  *
 2046  *      This routine does a standard config of the WaveLAN board.
 2047  *
 2048  */
 2049 static int
 2050 wlconfig(struct wl_softc *sc)
 2051 {
 2052     configure_t configure;
 2053     short               base = sc->base;
 2054 
 2055 #if     MULTICAST
 2056     struct ifmultiaddr *ifma;
 2057     u_char *addrp;
 2058     int cnt = 0;
 2059 #endif  /* MULTICAST */
 2060 
 2061 #ifdef WLDEBUG
 2062     if (sc->ifp->if_flags & IFF_DEBUG)
 2063         printf("wl%d: entered wlconfig()\n", sc->unit);
 2064 #endif
 2065     outw(PIOR0(base), OFFSET_SCB);
 2066     if (inw(PIOP0(base)) & SCB_SW_INT) {
 2067         /*
 2068           printf("wl%d config(): unexpected initial state %x\n",
 2069           sc->unit, inw(PIOP0(base)));
 2070           */
 2071     }
 2072     wlack(sc);
 2073 
 2074     outw(PIOR1(base), OFFSET_CU);
 2075     outw(PIOP1(base), 0);                               /* ac_status */
 2076     outw(PIOP1(base), AC_CONFIGURE|AC_CW_EL);   /* ac_command */
 2077 
 2078 /* jrb hack */
 2079     configure.fifolim_bytecnt   = 0x080c;
 2080     configure.addrlen_mode      = 0x0600;
 2081     configure.linprio_interframe        = 0x2060;
 2082     configure.slot_time         = 0xf200;
 2083     configure.hardware          = 0x0008;       /* tx even w/o CD */
 2084     configure.min_frame_len     = 0x0040;
 2085 #if 0
 2086     /* This is the configuration block suggested by Marc Meertens
 2087      * <mmeerten@obelix.utrecht.NCR.COM> in an e-mail message to John
 2088      * Ioannidis on 10 Nov 92.
 2089      */
 2090     configure.fifolim_bytecnt   = 0x040c;
 2091     configure.addrlen_mode      = 0x0600;
 2092     configure.linprio_interframe        = 0x2060;
 2093     configure.slot_time         = 0xf000;
 2094     configure.hardware          = 0x0008;       /* tx even w/o CD */
 2095     configure.min_frame_len     = 0x0040;
 2096 #else
 2097     /*
 2098      * below is the default board configuration from p2-28 from 586 book
 2099      */
 2100     configure.fifolim_bytecnt   = 0x080c;
 2101     configure.addrlen_mode      = 0x2600;
 2102     configure.linprio_interframe        = 0x7820;       /* IFS=120, ACS=2 */
 2103     configure.slot_time         = 0xf00c;       /* slottime=12    */
 2104     configure.hardware          = 0x0008;       /* tx even w/o CD */
 2105     configure.min_frame_len     = 0x0040;
 2106 #endif
 2107     if (sc->mode & (MOD_PROM | MOD_ENAL))
 2108         configure.hardware |= 1;
 2109     outw(PIOR1(base), OFFSET_CU + 6);
 2110     outsw(PIOP1(base), &configure, sizeof(configure_t)/2);
 2111 
 2112     if (wlcmd(sc, "config()-configure") == 0)
 2113         return 0;
 2114 #if     MULTICAST
 2115     outw(PIOR1(base), OFFSET_CU);
 2116     outw(PIOP1(base), 0);                               /* ac_status */
 2117     outw(PIOP1(base), AC_MCSETUP|AC_CW_EL);             /* ac_command */
 2118     outw(PIOR1(base), OFFSET_CU + 8);
 2119     if_maddr_rlock(sc->ifp);
 2120     TAILQ_FOREACH(ifma, &sc->ifp->if_multiaddrs, ifma_link) {
 2121         if (ifma->ifma_addr->sa_family != AF_LINK)
 2122             continue;
 2123         
 2124         addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
 2125         outw(PIOP1(base), addrp[0] + (addrp[1] << 8));
 2126         outw(PIOP1(base), addrp[2] + (addrp[3] << 8));
 2127         outw(PIOP1(base), addrp[4] + (addrp[5] << 8));
 2128         ++cnt;
 2129     }
 2130     if_maddr_runlock(sc->ifp);
 2131     outw(PIOR1(base), OFFSET_CU + 6);           /* mc-cnt */
 2132     outw(PIOP1(base), cnt * WAVELAN_ADDR_SIZE);
 2133     if (wlcmd(sc, "config()-mcaddress") == 0)
 2134         return 0;
 2135 #endif  /* MULTICAST */
 2136 
 2137     outw(PIOR1(base), OFFSET_CU);
 2138     outw(PIOP1(base), 0);                               /* ac_status */
 2139     outw(PIOP1(base), AC_IASETUP|AC_CW_EL);             /* ac_command */
 2140     outw(PIOR1(base), OFFSET_CU + 6);
 2141     outsw(PIOP1(base), IF_LLADDR(sc->ifp), WAVELAN_ADDR_SIZE/2);
 2142 
 2143     if (wlcmd(sc, "config()-address") == 0)
 2144         return(0);
 2145 
 2146     wlinitmmc(sc);
 2147 
 2148     return(1);
 2149 }
 2150 
 2151 /*
 2152  * wlcmd:
 2153  *
 2154  * Set channel attention bit and busy wait until command has
 2155  * completed. Then acknowledge the command completion.
 2156  */
 2157 static int
 2158 wlcmd(struct wl_softc *sc, char *str)
 2159 {
 2160     short       base = sc->base;
 2161     int i;
 2162         
 2163     outw(PIOR0(base), OFFSET_SCB + 2);  /* address of scb_command */
 2164     outw(PIOP0(base), SCB_CU_STRT);
 2165     
 2166     SET_CHAN_ATTN(sc);
 2167     
 2168     outw(PIOR0(base), OFFSET_CU);
 2169     for (i = 0; i < 0xffff; i++)
 2170         if (inw(PIOP0(base)) & AC_SW_C)
 2171             break;
 2172     if (i == 0xffff || !(inw(PIOP0(base)) & AC_SW_OK)) {
 2173         printf("wl%d: %s failed; status = %d, inw = %x, outw = %x\n",
 2174                sc->unit, str, inw(PIOP0(base)) & AC_SW_OK, inw(PIOP0(base)), inw(PIOR0(base)));
 2175         outw(PIOR0(base), OFFSET_SCB);
 2176         printf("scb_status %x\n", inw(PIOP0(base)));
 2177         outw(PIOR0(base), OFFSET_SCB+2);
 2178         printf("scb_command %x\n", inw(PIOP0(base)));
 2179         outw(PIOR0(base), OFFSET_SCB+4);
 2180         printf("scb_cbl %x\n", inw(PIOP0(base)));
 2181         outw(PIOR0(base), OFFSET_CU+2);
 2182         printf("cu_cmd %x\n", inw(PIOP0(base)));
 2183         return(0);
 2184     }
 2185 
 2186     outw(PIOR0(base), OFFSET_SCB);
 2187     if ((inw(PIOP0(base)) & SCB_SW_INT) && (inw(PIOP0(base)) != SCB_SW_CNA)) {
 2188         /*
 2189           printf("wl%d %s: unexpected final state %x\n",
 2190           sc->unit, str, inw(PIOP0(base)));
 2191           */
 2192     }
 2193     wlack(sc);
 2194     return(TRUE);
 2195 }       
 2196 
 2197 /*
 2198  * wlack: if the 82596 wants attention because it has finished
 2199  * sending or receiving a packet, acknowledge its desire and
 2200  * return bits indicating the kind of attention. wlack() returns
 2201  * these bits so that the caller can service exactly the
 2202  * conditions that wlack() acknowledged.
 2203  */
 2204 static int
 2205 wlack(struct wl_softc *sc)
 2206 {
 2207     int i;
 2208     u_short cmd;
 2209     short base = sc->base;
 2210 
 2211     outw(PIOR1(base), OFFSET_SCB);
 2212     if (!(cmd = (inw(PIOP1(base)) & SCB_SW_INT)))
 2213         return(0);
 2214 #ifdef WLDEBUG
 2215     if (sc->ifp->if_flags & IFF_DEBUG)
 2216         printf("wl%d: doing a wlack()\n", sc->unit);
 2217 #endif
 2218     outw(PIOP1(base), cmd);
 2219     SET_CHAN_ATTN(sc);
 2220     outw(PIOR0(base), OFFSET_SCB + 2);  /* address of scb_command */
 2221     for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); )
 2222         continue;
 2223     if (i < 1)
 2224         printf("wl%d wlack(): board not accepting command.\n", sc->unit);
 2225     return(cmd);
 2226 }
 2227 
 2228 #ifdef WLDEBUG
 2229 static void
 2230 wltbd(struct wl_softc *sc)
 2231 {
 2232     short               base = sc->base;
 2233     u_short             tbd_p = OFFSET_TBD;
 2234     tbd_t               tbd;
 2235     int                 i = 0;
 2236     int                 sum = 0;
 2237 
 2238     for (;;) {
 2239         outw(PIOR1(base), tbd_p);
 2240         insw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
 2241         sum += (tbd.act_count & ~TBD_SW_EOF);
 2242         printf("%d: addr %x, count %d (%d), next %x, base %x\n",
 2243                i++, tbd.buffer_addr,
 2244                (tbd.act_count & ~TBD_SW_EOF), sum,
 2245                tbd.next_tbd_offset, tbd.buffer_base);
 2246         if (tbd.act_count & TBD_SW_EOF)
 2247             break;
 2248         tbd_p = tbd.next_tbd_offset;
 2249     }
 2250 }
 2251 #endif
 2252 
 2253 static void
 2254 wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, struct wl_softc *sc)
 2255 {
 2256     struct mbuf *tm_p = *tm_pp;
 2257     u_char              *mb_p = *mb_pp;
 2258     u_short             count = 0;
 2259     u_char              *cp;
 2260     int         len;
 2261 
 2262     /*
 2263      * can we get a run that will be coallesced or
 2264      * that terminates before breaking
 2265      */
 2266     do {
 2267         count += tm_p->m_len;
 2268         if (tm_p->m_len & 1)
 2269             break;
 2270     } while ((tm_p = tm_p->m_next) != (struct mbuf *)0);
 2271     if ( (tm_p == (struct mbuf *)0) ||
 2272          count > HDW_THRESHOLD) {
 2273         *countp = (*tm_pp)->m_len;
 2274         *mb_pp = mtod((*tm_pp), u_char *);
 2275         return;
 2276     }
 2277 
 2278     /* we need to copy */
 2279     tm_p = *tm_pp;
 2280     mb_p = *mb_pp;
 2281     count = 0;
 2282     cp = (u_char *) t_packet;
 2283     for (;;) {
 2284         bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
 2285         count += len;
 2286         if (count > HDW_THRESHOLD)
 2287                         break;
 2288         cp += len;
 2289         if (tm_p->m_next == (struct mbuf *)0)
 2290             break;
 2291         tm_p = tm_p->m_next;
 2292     }
 2293     *countp = count;
 2294     *mb_pp = (u_char *) t_packet;
 2295     *tm_pp = tm_p;
 2296     return;
 2297 }
 2298 
 2299 
 2300 static void
 2301 wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, struct wl_softc *sc)
 2302 {
 2303     struct mbuf *tm_p = *tm_pp;
 2304     u_short             count = 0;
 2305     u_char              *cp = (u_char *) t_packet;
 2306     int                 len;
 2307 
 2308     /* we need to copy */
 2309     for (;;) {
 2310         bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
 2311         count += len;
 2312         cp += len;
 2313         if (tm_p->m_next == (struct mbuf *)0)
 2314             break;
 2315         tm_p = tm_p->m_next;
 2316     }
 2317 
 2318     *countp = count;
 2319     *mb_pp = (u_char *) t_packet;
 2320     *tm_pp = tm_p;
 2321     return;
 2322 }
 2323 
 2324 static void
 2325 wlmmcstat(struct wl_softc *sc)
 2326 {
 2327     short       base = sc->base;
 2328     u_short tmp;
 2329 
 2330     printf("wl%d: DCE_STATUS: 0x%x, ", sc->unit,
 2331            wlmmcread(base,MMC_DCE_STATUS) & 0x0f);
 2332     tmp = wlmmcread(base,MMC_CORRECT_NWID_H) << 8;
 2333     tmp |= wlmmcread(base,MMC_CORRECT_NWID_L);
 2334     printf("Correct NWID's: %d, ", tmp);
 2335     tmp = wlmmcread(base,MMC_WRONG_NWID_H) << 8;
 2336     tmp |= wlmmcread(base,MMC_WRONG_NWID_L);
 2337     printf("Wrong NWID's: %d\n", tmp);
 2338     printf("THR_PRE_SET: 0x%x, ", wlmmcread(base,MMC_THR_PRE_SET));
 2339     printf("SIGNAL_LVL: %d, SILENCE_LVL: %d\n", 
 2340            wlmmcread(base,MMC_SIGNAL_LVL),
 2341            wlmmcread(base,MMC_SILENCE_LVL));
 2342     printf("SIGN_QUAL: 0x%x, NETW_ID: %x:%x, DES: %d\n",
 2343            wlmmcread(base,MMC_SIGN_QUAL),
 2344            wlmmcread(base,MMC_NETW_ID_H),
 2345            wlmmcread(base,MMC_NETW_ID_L),
 2346            wlmmcread(base,MMC_DES_AVAIL));
 2347 }
 2348 
 2349 static u_short
 2350 wlmmcread(u_int base, u_short reg)
 2351 {
 2352     while (inw(HASR(base)) & HASR_MMC_BUSY)
 2353         continue;
 2354     outw(MMCR(base),reg << 1);
 2355     while (inw(HASR(base)) & HASR_MMC_BUSY)
 2356         continue;
 2357     return (u_short)inw(MMCR(base)) >> 8;
 2358 }
 2359 
 2360 static void
 2361 getsnr(struct wl_softc *sc)
 2362 {
 2363     MMC_WRITE(MMC_FREEZE,1);
 2364     /* 
 2365      * SNR retrieval procedure :
 2366      *
 2367      * read signal level : wlmmcread(base, MMC_SIGNAL_LVL);
 2368      * read silence level : wlmmcread(base, MMC_SILENCE_LVL);
 2369      */
 2370     MMC_WRITE(MMC_FREEZE,0);
 2371     /*
 2372      * SNR is signal:silence ratio.
 2373      */
 2374 }
 2375 
 2376 /*
 2377 ** wlgetpsa
 2378 **
 2379 ** Reads the psa for the wavelan at (base) into (buf)
 2380 */
 2381 static void
 2382 wlgetpsa(int base, u_char *buf)
 2383 {
 2384     int i;
 2385 
 2386     PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
 2387     PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
 2388 
 2389     for (i = 0; i < 0x40; i++) {
 2390         outw(PIOR2(base), i);
 2391         buf[i] = inb(PIOP2(base));
 2392     }
 2393     PCMD(base, HACR_DEFAULT);
 2394     PCMD(base, HACR_DEFAULT);
 2395 }
 2396 
 2397 /*
 2398 ** wlsetpsa
 2399 **
 2400 ** Writes the psa for wavelan (unit) from the softc back to the
 2401 ** board.  Updates the CRC and sets the CRC OK flag.
 2402 **
 2403 ** Do not call this when the board is operating, as it doesn't 
 2404 ** preserve the hacr.
 2405 */
 2406 static void
 2407 wlsetpsa(struct wl_softc *sc)
 2408 {
 2409     short       base = sc->base;
 2410     int         i, oldpri;
 2411     u_short     crc;
 2412 
 2413     crc = wlpsacrc(sc->psa);    /* calculate CRC of PSA */
 2414     sc->psa[WLPSA_CRCLOW] = crc & 0xff;
 2415     sc->psa[WLPSA_CRCHIGH] = (crc >> 8) & 0xff;
 2416     sc->psa[WLPSA_CRCOK] = 0x55;        /* default to 'bad' until programming complete */
 2417 
 2418     oldpri = splimp();          /* ick, long pause */
 2419     
 2420     PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
 2421     PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
 2422     
 2423     for (i = 0; i < 0x40; i++) {
 2424         DELAY(DELAYCONST);
 2425         outw(PIOR2(base),i);  /* write param memory */
 2426         DELAY(DELAYCONST);
 2427         outb(PIOP2(base), sc->psa[i]);
 2428     }
 2429     DELAY(DELAYCONST);
 2430     outw(PIOR2(base),WLPSA_CRCOK);  /* update CRC flag*/
 2431     DELAY(DELAYCONST);
 2432     sc->psa[WLPSA_CRCOK] = 0xaa;        /* OK now */
 2433     outb(PIOP2(base), 0xaa);    /* all OK */
 2434     DELAY(DELAYCONST);
 2435     
 2436     PCMD(base, HACR_DEFAULT);
 2437     PCMD(base, HACR_DEFAULT);
 2438     
 2439     splx(oldpri);
 2440 }
 2441 
 2442 /* 
 2443 ** CRC routine provided by Christopher Giordano <cgiordan@gdeb.com>,
 2444 ** from original code by Tomi Mikkonen (tomitm@remedy.fi)
 2445 */
 2446 
 2447 static u_int crc16_table[16] = { 
 2448     0x0000, 0xCC01, 0xD801, 0x1400,
 2449     0xF001, 0x3C00, 0x2800, 0xE401,
 2450     0xA001, 0x6C00, 0x7800, 0xB401,
 2451     0x5000, 0x9C01, 0x8801, 0x4400 
 2452 };
 2453 
 2454 static u_short
 2455 wlpsacrc(u_char *buf)
 2456 {
 2457     u_short     crc = 0;
 2458     int         i, r1;
 2459     
 2460     for (i = 0; i < 0x3d; i++, buf++) {
 2461         /* lower 4 bits */
 2462         r1 = crc16_table[crc & 0xF];
 2463         crc = (crc >> 4) & 0x0FFF;
 2464         crc = crc ^ r1 ^ crc16_table[*buf & 0xF];
 2465         
 2466         /* upper 4 bits */
 2467         r1 = crc16_table[crc & 0xF];
 2468         crc = (crc >> 4) & 0x0FFF;
 2469         crc = crc ^ r1 ^ crc16_table[(*buf >> 4) & 0xF];
 2470     }
 2471     return(crc);
 2472 }
 2473 #ifdef WLCACHE
 2474 
 2475 /*
 2476  * wl_cache_store
 2477  *
 2478  * take input packet and cache various radio hw characteristics
 2479  * indexed by MAC address.
 2480  *
 2481  * Some things to think about:
 2482  *      note that no space is malloced. 
 2483  *      We might hash the mac address if the cache were bigger.
 2484  *      It is not clear that the cache is big enough.
 2485  *              It is also not clear how big it should be.
 2486  *      The cache is IP-specific.  We don't care about that as
 2487  *              we want it to be IP-specific.
 2488  *      The last N recv. packets are saved.  This will tend
 2489  *              to reward agents and mobile hosts that beacon.
 2490  *              That is probably fine for mobile ip.
 2491  */
 2492 
 2493 /* globals for wavelan signal strength cache */
 2494 /* this should go into softc structure above. 
 2495 */
 2496 
 2497 /* set true if you want to limit cache items to broadcast/mcast 
 2498  * only packets (not unicast)
 2499  */
 2500 static int wl_cache_mcastonly = 1;
 2501 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_mcastonly, CTLFLAG_RW, 
 2502         &wl_cache_mcastonly, 0, "");
 2503 
 2504 /* set true if you want to limit cache items to IP packets only
 2505 */
 2506 static int wl_cache_iponly = 1;
 2507 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_iponly, CTLFLAG_RW, 
 2508         &wl_cache_iponly, 0, "");
 2509 
 2510 /* zero out the cache
 2511 */
 2512 static void
 2513 wl_cache_zero(struct wl_softc *sc)
 2514 {
 2515 
 2516         bzero(&sc->w_sigcache[0], sizeof(struct w_sigcache) * MAXCACHEITEMS);
 2517         sc->w_sigitems = 0;
 2518         sc->w_nextcache = 0;
 2519         sc->w_wrapindex = 0;
 2520 }
 2521 
 2522 /* store hw signal info in cache.
 2523  * index is MAC address, but an ip src gets stored too
 2524  * There are two filters here controllable via sysctl:
 2525  *      throw out unicast (on by default, but can be turned off)
 2526  *      throw out non-ip (on by default, but can be turned off)
 2527  */
 2528 static
 2529 void wl_cache_store (struct wl_softc *sc, int base, struct ether_header *eh,
 2530                      struct mbuf *m)
 2531 {
 2532 #ifdef INET
 2533         struct ip *ip = NULL;   /* Avoid GCC warning */
 2534         int i;
 2535         int signal, silence;
 2536         int w_insertcache;   /* computed index for cache entry storage */
 2537         int ipflag = wl_cache_iponly;
 2538 #endif
 2539 
 2540         /* filters:
 2541          * 1. ip only
 2542          * 2. configurable filter to throw out unicast packets,
 2543          * keep multicast only.
 2544          */
 2545  
 2546 #ifdef INET
 2547         /* reject if not IP packet
 2548         */
 2549         if ( wl_cache_iponly && (ntohs(eh->ether_type) != 0x800)) {
 2550                 return;
 2551         }
 2552 
 2553         /* check if broadcast or multicast packet.  we toss
 2554          * unicast packets
 2555          */
 2556         if (wl_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
 2557                 return;
 2558         }
 2559 
 2560         /* find the ip header.  we want to store the ip_src
 2561          * address.  use the mtod macro(in mbuf.h) 
 2562          * to typecast m to struct ip *
 2563          */
 2564         if (ipflag) {
 2565                 ip = mtod(m, struct ip *);
 2566         }
 2567         
 2568         /* do a linear search for a matching MAC address 
 2569          * in the cache table
 2570          * . MAC address is 6 bytes,
 2571          * . var w_nextcache holds total number of entries already cached
 2572          */
 2573         for (i = 0; i < sc->w_nextcache; i++) {
 2574                 if (! bcmp(eh->ether_shost, sc->w_sigcache[i].macsrc,  6 )) {
 2575                         /* Match!,
 2576                          * so we already have this entry,
 2577                          * update the data, and LRU age
 2578                          */
 2579                         break;  
 2580                 }
 2581         }
 2582 
 2583         /* did we find a matching mac address?
 2584          * if yes, then overwrite a previously existing cache entry
 2585          */
 2586         if (i <  sc->w_nextcache )   {
 2587                 w_insertcache = i; 
 2588         }
 2589         /* else, have a new address entry,so
 2590          * add this new entry,
 2591          * if table full, then we need to replace entry
 2592          */
 2593         else    {                          
 2594 
 2595                 /* check for space in cache table 
 2596                  * note: w_nextcache also holds number of entries
 2597                  * added in the cache table 
 2598                  */
 2599                 if ( sc->w_nextcache < MAXCACHEITEMS ) {
 2600                         w_insertcache = sc->w_nextcache;
 2601                         sc->w_nextcache++;                 
 2602                         sc->w_sigitems = sc->w_nextcache;
 2603                 }
 2604                 /* no space found, so simply wrap with wrap index
 2605                  * and "zap" the next entry
 2606                  */
 2607                 else {
 2608                         if (sc->w_wrapindex == MAXCACHEITEMS) {
 2609                                 sc->w_wrapindex = 0;
 2610                         }
 2611                         w_insertcache = sc->w_wrapindex++;
 2612                 }
 2613         }
 2614 
 2615         /* invariant: w_insertcache now points at some slot
 2616          * in cache.
 2617          */
 2618         if (w_insertcache < 0 || w_insertcache >= MAXCACHEITEMS) {
 2619                 log(LOG_ERR, 
 2620                         "wl_cache_store, bad index: %d of [0..%d], gross cache error\n",
 2621                         w_insertcache, MAXCACHEITEMS);
 2622                 return;
 2623         }
 2624 
 2625         /*  store items in cache
 2626          *  .ipsrc
 2627          *  .macsrc
 2628          *  .signal (0..63) ,silence (0..63) ,quality (0..15)
 2629          */
 2630         if (ipflag) {
 2631                 sc->w_sigcache[w_insertcache].ipsrc = ip->ip_src.s_addr;
 2632         }
 2633         bcopy( eh->ether_shost, sc->w_sigcache[w_insertcache].macsrc,  6);
 2634         signal = sc->w_sigcache[w_insertcache].signal  = wlmmcread(base, MMC_SIGNAL_LVL) & 0x3f;
 2635         silence = sc->w_sigcache[w_insertcache].silence = wlmmcread(base, MMC_SILENCE_LVL) & 0x3f;
 2636         sc->w_sigcache[w_insertcache].quality = wlmmcread(base, MMC_SIGN_QUAL) & 0x0f;
 2637         if (signal > 0)
 2638                 sc->w_sigcache[w_insertcache].snr = 
 2639                         signal - silence;
 2640         else
 2641                 sc->w_sigcache[w_insertcache].snr = 0;
 2642 #endif /* INET */
 2643 
 2644 }
 2645 #endif /* WLCACHE */

Cache object: 88759e088a7be7ce95efa1f2419e29cc


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