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