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