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