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