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