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