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


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

FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/if_wl.c

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

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

Cache object: 91d1b23eae77792a8eb3a63f740a8b4d


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