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