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