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