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


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

FreeBSD/Linux Kernel Cross Reference
sys/dev/wl/if_wl.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: c909b6cea3258ad7417609878fabfd12


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