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

Cache object: c0f15b74f262017874fca6b8b4f966a6


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