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