Make all network interrupt service routines MPSAFE part 1/3.
[dragonfly.git] / sys / dev / netif / wl / if_wl.c
... / ...
CommitLineData
1/* $FreeBSD: src/sys/i386/isa/if_wl.c,v 1.27.2.2 2000/07/17 21:24:32 archie Exp $ */
2/* $DragonFly: src/sys/dev/netif/wl/if_wl.c,v 1.26 2005/11/28 17:13:44 dillon Exp $ */
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
192#include "opt_wavelan.h"
193#include "opt_inet.h"
194
195#include <sys/param.h>
196#include <sys/systm.h>
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>
202#include <sys/serialize.h>
203#include <sys/thread2.h>
204
205#include <sys/kernel.h>
206#include <sys/sysctl.h>
207
208#include <machine/bus.h>
209#include <machine/resource.h>
210#include <sys/bus.h>
211#include <sys/rman.h>
212
213#include <net/ethernet.h>
214#include <net/if.h>
215#include <net/if_arp.h>
216#include <net/ifq_var.h>
217#include <net/if_dl.h>
218
219#ifdef INET
220#include <netinet/in.h>
221#include <netinet/in_systm.h>
222#include <netinet/ip.h>
223#include <netinet/if_ether.h>
224#endif
225
226#include <net/bpf.h>
227
228#include <bus/isa/isavar.h>
229#include <bus/isa/i386/isa_device.h>
230#include "if_wl_i82586.h" /* Definitions for the Intel chip */
231
232/* was 1000 in original, fed to DELAY(x) */
233#define DELAYCONST 1000
234#include "if_wl.h"
235#include <machine/if_wl_wavelan.h>
236
237static char t_packet[ETHERMTU + sizeof(struct ether_header) + sizeof(long)];
238
239struct wl_softc{
240 struct arpcom wl_ac; /* Ethernet common part */
241#define wl_if wl_ac.ac_if /* network visible interface */
242#define wl_addr wl_ac.ac_enaddr /* hardware address */
243 u_char psa[0x40];
244 u_char nwid[2]; /* current radio modem nwid */
245 short base;
246 int flags;
247 int tbusy; /* flag to determine if xmit is busy */
248 u_short begin_fd;
249 u_short end_fd;
250 u_short end_rbd;
251 u_short hacr; /* latest host adapter CR command */
252 short mode;
253 u_char chan24; /* 2.4 Gz: channel number/EEPROM Area # */
254 u_short freq24; /* 2.4 Gz: resulting frequency */
255 int rid_ioport;
256 int rid_irq;
257 struct resource *res_ioport;
258 struct resource *res_irq;
259 void *intr_handle;
260 struct callout watchdog_ch;
261#ifdef WLCACHE
262 int w_sigitems; /* number of cached entries */
263 /* array of cache entries */
264 struct w_sigcache w_sigcache[ MAXCACHEITEMS ];
265 int w_nextcache; /* next free cache entry */
266 int w_wrapindex; /* next "free" cache entry */
267#endif
268};
269
270/*
271 * XXX The Wavelan appears to be prone to dropping stuff if you talk to
272 * it too fast. This disgusting hack inserts a delay after each packet
273 * is queued which helps avoid this behaviour on fast systems.
274 */
275static int wl_xmit_delay = 250;
276SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_delay, CTLFLAG_RW, &wl_xmit_delay, 0, "");
277
278/*
279 * not XXX, but ZZZ (bizarre).
280 * promiscuous mode can be toggled to ignore NWIDs. By default,
281 * it does not. Caution should be exercised about combining
282 * this mode with IFF_ALLMULTI which puts this driver in
283 * promiscuous mode.
284 */
285static int wl_ignore_nwid = 0;
286SYSCTL_INT(_machdep, OID_AUTO, wl_ignore_nwid, CTLFLAG_RW, &wl_ignore_nwid, 0, "");
287
288/*
289 * Emit diagnostics about transmission problems
290 */
291static int xmt_watch = 0;
292SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_watch, CTLFLAG_RW, &xmt_watch, 0, "");
293
294/*
295 * Collect SNR statistics
296 */
297static int gathersnr = 0;
298SYSCTL_INT(_machdep, OID_AUTO, wl_gather_snr, CTLFLAG_RW, &gathersnr, 0, "");
299
300static int wlprobe(device_t);
301static int wlattach(device_t);
302static int wldetach(device_t);
303static int wl_alloc_resources(device_t);
304static void wl_free_resources(device_t);
305static void wlstart(struct ifnet *);
306static void wlinit(void *);
307static int wlioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
308static timeout_t wlwatchdog;
309static void wlintr(void *);
310static void wlxmt(struct wl_softc *, struct mbuf *);
311static int wldiag(struct wl_softc *);
312static int wlconfig(struct wl_softc *);
313static int wlcmd(struct wl_softc *, const char *);
314static void wlmmcstat(struct wl_softc *);
315static u_short wlbldru(struct wl_softc *);
316static u_short wlmmcread(u_int, u_short);
317static void wlinitmmc(struct wl_softc *);
318static int wlhwrst(struct wl_softc *);
319static void wlrustrt(struct wl_softc *);
320static void wlbldcu(struct wl_softc *);
321static int wlack(struct wl_softc *);
322static int wlread(struct wl_softc *, u_short);
323static void getsnr(struct wl_softc *);
324static void wlrcv(struct wl_softc *);
325static int wlrequeue(struct wl_softc *, u_short);
326static void wlsftwsleaze(u_short *, u_char **, struct mbuf **);
327static void wlhdwsleaze(u_short *, u_char **, struct mbuf **);
328static void wltbd(struct wl_softc *);
329static void wlgetpsa(int, u_char *);
330static void wlsetpsa(struct wl_softc *);
331static u_short wlpsacrc(u_char *);
332static void wldump(struct wl_softc *);
333#ifdef WLCACHE
334static void wl_cache_store(struct wl_softc *, int, struct ether_header *,
335 struct mbuf *);
336static void wl_cache_zero(struct wl_softc *);
337#endif
338#ifdef MULTICAST
339# if defined(__FreeBSD__) && __FreeBSD_version < 300000
340static int check_allmulti(struct wl_softc *);
341# endif
342#endif
343
344static device_method_t wl_methods[] = {
345 DEVMETHOD(device_probe, wlprobe),
346 DEVMETHOD(device_attach, wlattach),
347 DEVMETHOD(device_detach, wldetach),
348 { 0, 0 }
349};
350
351static driver_t wl_driver = {
352 "wl",
353 wl_methods,
354 sizeof(struct wl_softc)
355};
356
357devclass_t wl_devclass;
358DECLARE_DUMMY_MODULE(if_wl);
359DRIVER_MODULE(wl, isa, wl_driver, wl_devclass, 0, 0);
360MODULE_DEPEND(wl, isa, 1, 1, 1);
361
362static struct isa_pnp_id wl_ids[] = {
363 { 0, NULL }
364};
365
366/* array for maping irq numbers to values for the irq parameter register */
367static int irqvals[16] = {
368 0, 0, 0, 0x01, 0x02, 0x04, 0, 0x08, 0, 0, 0x10, 0x20, 0x40, 0, 0, 0x80
369};
370
371/*
372 * wlprobe:
373 *
374 * This function "probes" or checks for the WaveLAN board on the bus to
375 * see if it is there. As far as I can tell, the best break between this
376 * routine and the attach code is to simply determine whether the board
377 * is configured in properly. Currently my approach to this is to write
378 * and read a word from the SRAM on the board being probed. If the word
379 * comes back properly then we assume the board is there. The config
380 * code expects to see a successful return from the probe routine before
381 * attach will be called.
382 */
383static int
384wlprobe(device_t dev)
385{
386 struct wl_softc *sc;
387 short base;
388 const char *str = "wl%d: board out of range [0..%d]\n";
389 u_char inbuf[100];
390 int irq, error;
391
392 error = ISA_PNP_PROBE(device_get_parent(dev), dev, wl_ids);
393 if (error == ENXIO || error == 0)
394 return (error);
395
396 sc = device_get_softc(dev);
397 error = wl_alloc_resources(dev);
398 if (error)
399 return error;
400
401 base = rman_get_start(sc->res_ioport);
402
403 /* TBD. not true.
404 * regular CMD() will not work, since no softc yet
405 */
406#define PCMD(base, hacr) outw((base), (hacr))
407
408 PCMD(base, HACR_RESET); /* reset the board */
409 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
410 PCMD(base, HACR_RESET); /* reset the board */
411 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
412
413 /* clear reset command and set PIO#1 in autoincrement mode */
414 PCMD(base, HACR_DEFAULT);
415 PCMD(base, HACR_DEFAULT);
416 outw(PIOR1(base), 0); /* go to beginning of RAM */
417 outsw(PIOP1(base), str, strlen(str)/2+1); /* write string */
418
419 outw(PIOR1(base), 0); /* rewind */
420 insw(PIOP1(base), inbuf, strlen(str)/2+1); /* read result */
421
422 if (bcmp(str, inbuf, strlen(str))) {
423 error = ENXIO;
424 goto fail;
425 }
426
427 sc->chan24 = 0; /* 2.4 Gz: config channel */
428 sc->freq24 = 0; /* 2.4 Gz: frequency */
429
430 /* read the PSA from the board into temporary storage */
431 wlgetpsa(base, inbuf);
432
433 /* We read the IRQ value from the PSA on the board. */
434 for (irq = 15; irq >= 0; irq--)
435 if (irqvals[irq] == inbuf[WLPSA_IRQNO])
436 break;
437 if ((irq == 0) || (irqvals[irq] == 0)){
438 device_printf(dev, "PSA corrupt (invalid IRQ value)\n");
439 } else {
440 u_long sirq, dummy;
441
442 /*
443 * If the IRQ requested by the PSA is already claimed by another
444 * device, the board won't work, but the user can still access the
445 * driver to change the IRQ.
446 */
447 if (bus_get_resource(dev, SYS_RES_IRQ, 0, &sirq, &dummy))
448 goto fail;
449 if (irq != (int)sirq)
450 device_printf(dev, "board is configured for interrupt %d\n", irq);
451 }
452 error = 0;
453
454fail:
455 wl_free_resources(dev);
456 return (error);
457}
458
459/*
460 * wlattach:
461 *
462 * This function attaches a WaveLAN board to the "system". The rest of
463 * runtime structures are initialized here (this routine is called after
464 * a successful probe of the board). Once the ethernet address is read
465 * and stored, the board's ifnet structure is attached and readied.
466 */
467static int
468wlattach(device_t dev)
469{
470 struct wl_softc *sc;
471 short base;
472 int i, j, error;
473 struct ifnet *ifp;
474
475 sc = device_get_softc(dev);
476
477 ifp = &sc->wl_if;
478 if_initname(ifp, device_get_name(dev), device_get_unit(dev));
479
480 error = wl_alloc_resources(dev);
481 if (error)
482 return error;
483
484 base = rman_get_start(sc->res_ioport);
485
486#ifdef WLDEBUG
487 device_printf(dev, "%s: base %x, unit %d\n",
488 __func__, base, device_get_unit(dev));
489#endif
490
491 sc->base = base;
492 sc->flags = 0;
493 sc->mode = 0;
494 sc->hacr = HACR_RESET;
495 callout_init(&sc->watchdog_ch);
496 CMD(sc); /* reset the board */
497 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
498
499 /* clear reset command and set PIO#2 in parameter access mode */
500 sc->hacr = (HACR_DEFAULT & ~HACR_16BITS);
501 CMD(sc);
502
503 /* Read the PSA from the board for our later reference */
504 wlgetpsa(base, sc->psa);
505
506 /* fetch NWID */
507 sc->nwid[0] = sc->psa[WLPSA_NWID];
508 sc->nwid[1] = sc->psa[WLPSA_NWID+1];
509
510 /* fetch MAC address - decide which one first */
511 if (sc->psa[WLPSA_MACSEL] & 1) {
512 j = WLPSA_LOCALMAC;
513 } else {
514 j = WLPSA_UNIMAC;
515 }
516 for(i=0; i < WAVELAN_ADDR_SIZE; ++i) {
517 sc->wl_addr[i] = sc->psa[j + i];
518 }
519
520 /* enter normal 16 bit mode operation */
521 sc->hacr = HACR_DEFAULT;
522 CMD(sc);
523
524 wlinitmmc(sc);
525 outw(PIOR1(base), OFFSET_SCB + 8); /* address of scb_crcerrs */
526 outw(PIOP1(base), 0); /* clear scb_crcerrs */
527 outw(PIOP1(base), 0); /* clear scb_alnerrs */
528 outw(PIOP1(base), 0); /* clear scb_rscerrs */
529 outw(PIOP1(base), 0); /* clear scb_ovrnerrs */
530
531 ifp->if_softc = sc;
532 ifp->if_mtu = WAVELAN_MTU;
533 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
534#ifdef WLDEBUG
535 ifp->if_flags |= IFF_DEBUG;
536#endif
537#if MULTICAST
538 ifp->if_flags |= IFF_MULTICAST;
539#endif /* MULTICAST */
540 ifp->if_init = wlinit;
541 ifp->if_start = wlstart;
542 ifp->if_ioctl = wlioctl;
543 ifp->if_timer = 0; /* paranoia */
544 /* no entries
545 ifp->if_watchdog
546 ifp->if_done
547 ifp->if_reset
548 */
549 ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN);
550 ifq_set_ready(&ifp->if_snd);
551 ether_ifattach(ifp, sc->wl_ac.ac_enaddr, NULL);
552
553 if (sc->freq24)
554 printf(", Freq %d MHz",sc->freq24); /* 2.4 Gz */
555 printf("\n"); /* 2.4 Gz */
556
557 error = bus_setup_intr(dev, sc->res_irq, INTR_NETSAFE,
558 wlintr, sc, &sc->intr_handle,
559 ifp->if_serializer);
560 if (error) {
561 device_printf(dev, "setup irq fail!\n");
562 ether_ifdetach(ifp);
563 wl_free_resources(dev);
564 return error;
565 }
566
567 if (bootverbose)
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
579 lwkt_serialize_enter(ifp->if_serializer);
580 ether_ifdetach(ifp);
581
582 /* reset the board */
583 sc->hacr = HACR_RESET;
584 CMD(sc);
585 sc->hacr = HACR_DEFAULT;
586 CMD(sc);
587
588 if (sc->intr_handle != NULL) {
589 BUS_TEARDOWN_INTR(parent, dev, sc->res_irq, sc->intr_handle);
590 sc->intr_handle = NULL;
591 }
592
593 bus_generic_detach(dev);
594
595 wl_free_resources(dev);
596 lwkt_serialize_exit(ifp->if_serializer);
597 return (0);
598}
599
600static int
601wl_alloc_resources(device_t dev)
602{
603 struct wl_softc *sc = device_get_softc(dev);
604 int ports = 16; /* Number of ports */
605
606 sc->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT,
607 &sc->rid_ioport, 0ul, ~0ul, ports, RF_ACTIVE);
608 if (sc->res_ioport == NULL)
609 goto fail;
610
611 sc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
612 &sc->rid_irq, RF_SHAREABLE | RF_ACTIVE);
613 if (sc->res_irq == NULL)
614 goto fail;
615 return (0);
616
617fail:
618 wl_free_resources(dev);
619 return (ENXIO);
620}
621
622static void
623wl_free_resources(device_t dev)
624{
625 struct wl_softc *sc = device_get_softc(dev);
626
627 if (sc->res_irq != 0) {
628 bus_deactivate_resource(dev, SYS_RES_IRQ, sc->rid_irq, sc->res_irq);
629 bus_release_resource(dev, SYS_RES_IRQ, sc->rid_irq, sc->res_irq);
630 sc->res_irq = 0;
631 }
632 if (sc->res_ioport != 0) {
633 bus_deactivate_resource(dev, SYS_RES_IOPORT,
634 sc->rid_ioport, sc->res_ioport);
635 bus_release_resource(dev, SYS_RES_IOPORT,
636 sc->rid_ioport, sc->res_ioport);
637 sc->res_ioport = 0;
638 }
639}
640
641/*
642 * Print out interesting information about the 82596.
643 */
644static void
645wldump(struct wl_softc *sc)
646{
647 int base = sc->base;
648 int i;
649
650 if_printf(&sc->wl_if, "hasr %04x\n", inw(HASR(base)));
651
652 if_printf(&sc->wl_if, "scb at %04x:\n ", OFFSET_SCB);
653 outw(PIOR1(base), OFFSET_SCB);
654 for(i = 0; i < 8; i++)
655 printf("%04x ", inw(PIOP1(base)));
656 printf("\n");
657
658 if_printf(&sc->wl_if, "cu at %04x:\n ", OFFSET_CU);
659 outw(PIOR1(base), OFFSET_CU);
660 for(i = 0; i < 8; i++)
661 printf("%04x ", inw(PIOP1(base)));
662 printf("\n");
663
664 if_printf(&sc->wl_if, "tbd at %04x:\n ", OFFSET_TBD);
665 outw(PIOR1(base), OFFSET_TBD);
666 for(i = 0; i < 4; i++)
667 printf("%04x ", inw(PIOP1(base)));
668 printf("\n");
669}
670
671/* Initialize the Modem Management Controller */
672static void
673wlinitmmc(struct wl_softc *sc)
674{
675 int base = sc->base;
676 int configured;
677 int mode = sc->mode;
678 int i; /* 2.4 Gz */
679
680 /* enter 8 bit operation */
681 sc->hacr = (HACR_DEFAULT & ~HACR_16BITS);
682 CMD(sc);
683
684 configured = sc->psa[WLPSA_CONFIGURED] & 1;
685
686 /*
687 * Set default modem control parameters. Taken from NCR document
688 * 407-0024326 Rev. A
689 */
690 MMC_WRITE(MMC_JABBER_ENABLE, 0x01);
691 MMC_WRITE(MMC_ANTEN_SEL, 0x02);
692 MMC_WRITE(MMC_IFS, 0x20);
693 MMC_WRITE(MMC_MOD_DELAY, 0x04);
694 MMC_WRITE(MMC_JAM_TIME, 0x38);
695 MMC_WRITE(MMC_DECAY_PRM, 0x00); /* obsolete ? */
696 MMC_WRITE(MMC_DECAY_UPDAT_PRM, 0x00);
697 if (!configured) {
698 MMC_WRITE(MMC_LOOPT_SEL, 0x00);
699 if (sc->psa[WLPSA_COMPATNO] & 1) {
700 MMC_WRITE(MMC_THR_PRE_SET, 0x01); /* 0x04 for AT and 0x01 for MCA */
701 } else {
702 MMC_WRITE(MMC_THR_PRE_SET, 0x04); /* 0x04 for AT and 0x01 for MCA */
703 }
704 MMC_WRITE(MMC_QUALITY_THR, 0x03);
705 } else {
706 /* use configuration defaults from parameter storage area */
707 if (sc->psa[WLPSA_NWIDENABLE] & 1) {
708 if ((mode & (MOD_PROM | MOD_ENAL)) && wl_ignore_nwid) {
709 MMC_WRITE(MMC_LOOPT_SEL, 0x40);
710 } else {
711 MMC_WRITE(MMC_LOOPT_SEL, 0x00);
712 }
713 } else {
714 MMC_WRITE(MMC_LOOPT_SEL, 0x40); /* disable network id check */
715 }
716 MMC_WRITE(MMC_THR_PRE_SET, sc->psa[WLPSA_THRESH]);
717 MMC_WRITE(MMC_QUALITY_THR, sc->psa[WLPSA_QUALTHRESH]);
718 }
719 MMC_WRITE(MMC_FREEZE, 0x00);
720 MMC_WRITE(MMC_ENCR_ENABLE, 0x00);
721
722 MMC_WRITE(MMC_NETW_ID_L,sc->nwid[1]); /* set NWID */
723 MMC_WRITE(MMC_NETW_ID_H,sc->nwid[0]);
724
725 /* enter normal 16 bit mode operation */
726 sc->hacr = HACR_DEFAULT;
727 CMD(sc);
728 CMD(sc); /* virtualpc1 needs this! */
729
730 if (sc->psa[WLPSA_COMPATNO]== /* 2.4 Gz: half-card ver */
731 WLPSA_COMPATNO_WL24B) { /* 2.4 Gz */
732 i=sc->chan24<<4; /* 2.4 Gz: position ch # */
733 MMC_WRITE(MMC_EEADDR,i+0x0f); /* 2.4 Gz: named ch, wc=16 */
734 MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+ /* 2.4 Gz: Download Synths */
735 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: Read EEPROM */
736 for (i=0; i<1000; ++i) { /* 2.4 Gz: wait for download */
737 DELAY(40); /* 2.4 Gz */
738 if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and */
739 &(MMC_EECTRLstat_DWLD /* 2.4 Gz: EEBUSY */
740 +MMC_EECTRLstat_EEBUSY))==0) /* 2.4 Gz: */
741 break; /* 2.4 Gz: download finished */
742 } /* 2.4 Gz */
743 if (i==1000) {
744 if_printf(&sc->wl_if,
745 "synth load failed\n"); /* 2.4 Gz */
746 }
747 MMC_WRITE(MMC_EEADDR,0x61); /* 2.4 Gz: default pwr, wc=2 */
748 MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+ /* 2.4 Gz: Download Xmit Pwr */
749 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: Read EEPROM */
750 for (i=0; i<1000; ++i) { /* 2.4 Gz: wait for download */
751 DELAY(40); /* 2.4 Gz */
752 if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and */
753 &(MMC_EECTRLstat_DWLD /* 2.4 Gz: EEBUSY */
754 +MMC_EECTRLstat_EEBUSY))==0) /* 2.4 Gz: */
755 break; /* 2.4 Gz: download finished */
756 } /* 2.4 Gz */
757 if (i==1000) {
758 if_printf(&sc->wl_if,
759 "xmit pwr load failed\n");/* 2.4 Gz */
760 }
761 MMC_WRITE(MMC_ANALCTRL, /* 2.4 Gz: EXT ant+polarity */
762 MMC_ANALCTRL_ANTPOL + /* 2.4 Gz: */
763 MMC_ANALCTRL_EXTANT); /* 2.4 Gz: */
764 i=sc->chan24<<4; /* 2.4 Gz: position ch # */
765 MMC_WRITE(MMC_EEADDR,i); /* 2.4 Gz: get frequency */
766 MMC_WRITE(MMC_EECTRL, /* 2.4 Gz: EEPROM read */
767 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: */
768 DELAY(40); /* 2.4 Gz */
769 i = wlmmcread(base,MMC_EEDATALrv) /* 2.4 Gz: freq val */
770 + (wlmmcread(base,MMC_EEDATAHrv)<<8); /* 2.4 Gz */
771 sc->freq24 = (i>>6)+2400; /* 2.4 Gz: save real freq */
772 }
773}
774
775/*
776 * wlinit:
777 *
778 * Another routine that interfaces the "if" layer to this driver.
779 * Simply resets the structures that are used by "upper layers".
780 * As well as calling wlhwrst that does reset the WaveLAN board.
781 *
782 * input : softc pointer for this interface
783 * output : structures (if structs) and board are reset
784 *
785 */
786static void
787wlinit(void *xsc)
788{
789 struct wl_softc *sc = xsc;
790 struct ifnet *ifp = &sc->wl_if;
791 int stat;
792
793#ifdef WLDEBUG
794 if (ifp->if_flags & IFF_DEBUG)
795 if_printf(ifp, "entered wlinit()\n");
796#endif
797 if ((stat = wlhwrst(sc)) == TRUE) {
798 ifp->if_flags |= IFF_RUNNING; /* same as DSF_RUNNING */
799 /*
800 * OACTIVE is used by upper-level routines
801 * and must be set
802 */
803 ifp->if_flags &= ~IFF_OACTIVE; /* same as tbusy below */
804
805 sc->flags |= DSF_RUNNING;
806 sc->tbusy = 0;
807 callout_stop(&sc->watchdog_ch);
808
809 wlstart(ifp);
810 } else {
811 if_printf(ifp, "init(): trouble resetting board.\n");
812 }
813}
814
815/*
816 * wlhwrst:
817 *
818 * This routine resets the WaveLAN board that corresponds to the
819 * board number passed in.
820 *
821 * input : softc pointer for this interface
822 * output : board is reset
823 *
824 */
825static int
826wlhwrst(struct wl_softc *sc)
827{
828#ifdef WLDEBUG
829 if (sc->wl_if.if_flags & IFF_DEBUG)
830 if_printf(&sc->wl_if, "entered wlhwrst()\n");
831#endif
832 sc->hacr = HACR_RESET;
833 CMD(sc); /* reset the board */
834
835 /* clear reset command and set PIO#1 in autoincrement mode */
836 sc->hacr = HACR_DEFAULT;
837 CMD(sc);
838
839#ifdef WLDEBUG
840 if (sc->wl_if.if_flags & IFF_DEBUG)
841 wlmmcstat(sc); /* Display MMC registers */
842#endif /* WLDEBUG */
843 wlbldcu(sc); /* set up command unit structures */
844
845 if (wldiag(sc) == 0)
846 return(0);
847
848 if (wlconfig(sc) == 0)
849 return(0);
850 /*
851 * insert code for loopback test here
852 */
853 wlrustrt(sc); /* start receive unit */
854
855 /* enable interrupts */
856 sc->hacr = (HACR_DEFAULT | HACR_INTRON);
857 CMD(sc);
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
870wlbldcu(struct wl_softc *sc)
871{
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
906 SET_CHAN_ATTN(sc);
907
908 outw(PIOR0(base), OFFSET_ISCP + 0); /* address of iscp_busy */
909 for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
910 if (i <= 0) if_printf(&sc->wl_if, "bldcu(): iscp_busy timeout.\n");
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)
917 if_printf(&sc->wl_if, "bldcu(): not ready after reset.\n");
918 wlack(sc);
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 *
939 * input : pointer the appropriate "if" struct
940 * output : stuff sent to board if any there
941 *
942 */
943static void
944wlstart(struct ifnet *ifp)
945{
946 struct mbuf *m;
947 struct wl_softc *sc = ifp->if_softc;
948 short base = sc->base;
949 int scb_status, cu_status, scb_command;
950
951#ifdef WLDEBUG
952 if (ifp->if_flags & IFF_DEBUG)
953 if_printf(ifp, "entered wlstart()\n");
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;
971 callout_stop(&sc->watchdog_ch);
972 ifp->if_flags &= ~IFF_OACTIVE;
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
978 if_printf(ifp, "CU idle, scb %04x %04x cu %04x\n",
979 scb_status, scb_command, cu_status);
980#endif
981 if (xmt_watch) if_printf(ifp, "!!\n");
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
988 if_printf(ifp, "CU unexpectedly busy; scb %04x cu %04x\n",
989 scb_status, cu_status);
990#endif
991 if (xmt_watch) if_printf(ifp, "busy?!");
992 return; /* hey, why are we busy? */
993 }
994
995 /* get ourselves some data */
996 ifp = &(sc->wl_if);
997 m = ifq_dequeue(&ifp->if_snd, NULL);
998 if (m != NULL) {
999 BPF_MTAP(ifp, m);
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 */
1005 callout_reset(&sc->watchdog_ch, 10, wlwatchdog, sc);
1006 ifp->if_flags |= IFF_OACTIVE;
1007 ifp->if_opackets++;
1008 wlxmt(sc, m);
1009 } else {
1010 ifp->if_flags &= ~IFF_OACTIVE;
1011 }
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 *
1027 * input : softc pointer for this interface and
1028 * an frame descriptor address
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
1034wlread(struct wl_softc *sc, u_short fd_p)
1035{
1036 struct ifnet *ifp = &sc->wl_if;
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
1048 if (ifp->if_flags & IFF_DEBUG)
1049 if_printf(ifp, "entered wlread()\n");
1050#endif
1051 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
1052 if_printf(ifp, "read(): board is not running.\n");
1053 sc->hacr &= ~HACR_INTRON;
1054 CMD(sc); /* turn off interrupts */
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
1065 if (ifp->if_flags & IFF_DEBUG)
1066 if_printf(ifp, "wlread: rcv packet, type is %x\n", eh.ether_type);
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) {
1075 if_printf(ifp, "read(): Invalid buffer\n");
1076 if (wlhwrst(sc) != TRUE)
1077 if_printf(ifp, "read(): hwrst trouble.\n");
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;
1084 MGETHDR(m, MB_DONTWAIT, MT_DATA);
1085 tm = m;
1086 if (m == NULL) {
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 */
1092 if (wlhwrst(sc) != TRUE) {
1093 sc->hacr &= ~HACR_INTRON;
1094 CMD(sc); /* turn off interrupts */
1095 if_printf(ifp, "read(): hwrst trouble.\n");
1096 }
1097 return 0;
1098 }
1099 m->m_next = (struct mbuf *) 0;
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 */
1106 MCLGET(m, MB_DONTWAIT);
1107 if (m->m_flags & M_EXT) {
1108 m->m_len = MCLBYTES;
1109 }
1110 else {
1111 m_freem(m);
1112 if (wlhwrst(sc) != TRUE) {
1113 sc->hacr &= ~HACR_INTRON;
1114 CMD(sc); /* turn off interrupts */
1115 if_printf(ifp, "read(): hwrst trouble.\n");
1116 }
1117 return 0;
1118 }
1119
1120 mlen = 0;
1121 clen = mlen;
1122 bytes_in_mbuf = m->m_len - sizeof(eh);
1123 mb_p = mtod(tm, u_char *);
1124 bytes = min(bytes_in_mbuf, bytes_in_msg);
1125 bcopy(&eh, mb_p, sizeof(eh));
1126 mb_p += sizeof(eh);
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)) {
1139 MGET(tm->m_next, MB_DONTWAIT, MT_DATA);
1140 tm = tm->m_next;
1141 if (tm == (struct mbuf *)0) {
1142 m_freem(m);
1143 if_printf(ifp, "read(): No mbuf nth\n");
1144 if (wlhwrst(sc) != TRUE) {
1145 sc->hacr &= ~HACR_INTRON;
1146 CMD(sc); /* turn off interrupts */
1147 if_printf(ifp, "read(): hwrst trouble.\n");
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 */
1193 (ifp->if_flags & (IFF_PROMISC|IFF_ALLMULTI))
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
1207 if (ifp->if_flags & IFF_DEBUG)
1208 if_printf(ifp, "wlrecv %d bytes\n", clen);
1209#endif
1210
1211#ifdef WLCACHE
1212 wl_cache_store(sc, base, &eh, m);
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 */
1220 ifp->if_input(ifp, m);
1221 return 1;
1222}
1223
1224/*
1225 * wlioctl:
1226 *
1227 * This routine processes an ioctl request from the "if" layer
1228 * above.
1229 *
1230 * input : pointer the appropriate "if" struct, command and data
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
1237wlioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cred)
1238{
1239 struct ifreq *ifr = (struct ifreq *)data;
1240 struct wl_softc *sc = ifp->if_softc;
1241 short base = sc->base;
1242 short mode = 0;
1243 int error = 0;
1244 int irq, irqval, i, isroot, size;
1245 caddr_t up;
1246 char * cpt;
1247 struct thread *td = curthread; /* XXX */
1248
1249
1250#ifdef WLDEBUG
1251 if (ifp->if_flags & IFF_DEBUG)
1252 if_printf(ifp, "entered wlioctl()\n");
1253#endif
1254 switch (cmd) {
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) {
1282 if_printf(ifp, "ioctl(): board is not running\n");
1283 sc->flags &= ~DSF_RUNNING;
1284 sc->hacr &= ~HACR_INTRON;
1285 CMD(sc); /* turn off interrupts */
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
1293 /* if WLDEBUG set on interface, then printf rf-modem regs
1294 */
1295 if(ifp->if_flags & IFF_DEBUG)
1296 wlmmcstat(sc);
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 */
1314 if (check_allmulti(sc)) {
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 */
1344 isroot = (suser(td) == 0);
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 */
1359 if ((error = suser(td)))
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;
1392 wlsetpsa(sc); /* update the PSA */
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 */
1413 if ((error = suser(td)))
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 */
1431 if ((error = suser(td)))
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 */
1454 if ((error = suser(td)))
1455 break;
1456 wl_cache_zero(sc);
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:
1479 error = ether_ioctl(ifp, cmd, data);
1480 break;
1481 }
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;
1500 struct ifnet *ifp = &sc->wl_if;
1501
1502 lwkt_serialize_enter(ifp->if_serializer);
1503 log(LOG_ERR, "%s: wavelan device timeout on xmit\n", sc->wl_if.if_xname);
1504 sc->wl_if.if_oerrors++;
1505 wlinit(sc);
1506 lwkt_serialize_exit(ifp->if_serializer);
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 *
1517 * input : softc pointer for this interface
1518 * output : either a packet is received, or a packet is transfered
1519 *
1520 */
1521static void
1522wlintr(void *arg)
1523{
1524 struct wl_softc *sc = arg;
1525 struct ifnet *ifp = &sc->wl_if;
1526 short base = sc->base;
1527 int ac_status;
1528 u_short int_type, int_type1;
1529
1530#ifdef WLDEBUG
1531 if (ifp->if_flags & IFF_DEBUG)
1532 if_printf(ifp, "wlintr() called\n");
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 */
1538 (void) wlmmcread(base,MMC_DCE_STATUS); /* ignored for now */
1539 }
1540
1541 if(!(int_type & HASR_INTR)){ /* return if no interrupt from 82586 */
1542 /* commented out. jrb. it happens when reinit occurs
1543 if_printf(ifp, "%s: int_type %x, dump follows\n",
1544 __func__, int_type);
1545 wldump(sc);
1546 */
1547 return;
1548 }
1549
1550 if (gathersnr)
1551 getsnr(sc);
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
1558 int_type1 = wlack(sc); /* acknowledge interrupt(s) */
1559 /* make sure no bits disappeared (others may appear) */
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 }
1564 int_type = int_type1; /* go with the new status */
1565 /*
1566 * incoming packet
1567 */
1568 if (int_type & SCB_SW_FR) {
1569 ifp->if_ipackets++;
1570 wlrcv(sc);
1571 }
1572 /*
1573 * receiver not ready
1574 */
1575 if (int_type & SCB_SW_RNR) {
1576 ifp->if_ierrors++;
1577#ifdef WLDEBUG
1578 if (ifp->if_flags & IFF_DEBUG) {
1579 if_printf(ifp, "intr(): receiver overrun! begin_fd = %x\n",
1580 sc->begin_fd);
1581 }
1582#endif
1583 wlrustrt(sc);
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) {
1605 if_printf(ifp, "xmt intr but not busy, CU %04x\n",
1606 ac_status);
1607 }
1608 if (ac_status == 0) {
1609 if_printf(ifp, "xmt intr but ac_status == 0\n");
1610 }
1611 if (ac_status & AC_SW_A) {
1612 if_printf(ifp, "xmt aborted\n");
1613 }
1614#ifdef notdef
1615 if (ac_status & TC_CARRIER) {
1616 if_printf(ifp, "no carrier\n");
1617 }
1618#endif /* notdef */
1619 if (ac_status & TC_CLS) {
1620 if_printf(ifp, "no CTS\n");
1621 }
1622 if (ac_status & TC_DMA) {
1623 if_printf(ifp, "DMA underrun\n");
1624 }
1625 if (ac_status & TC_DEFER) {
1626 if_printf(ifp, "xmt deferred\n");
1627 }
1628 if (ac_status & TC_SQE) {
1629 if_printf(ifp, "heart beat\n");
1630 }
1631 if (ac_status & TC_COLLISION) {
1632 if_printf(ifp, "too many collisions\n");
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)) {
1638 ifp->if_oerrors++;
1639 }
1640
1641 /* count collisions */
1642 ifp->if_collisions += (ac_status & 0xf);
1643 /* if TC_COLLISION set and collision count zero, 16 collisions */
1644 if ((ac_status & 0x20) == 0x20) {
1645 ifp->if_collisions += 0x10;
1646 }
1647 }
1648 sc->tbusy = 0;
1649 callout_stop(&sc->watchdog_ch);
1650 ifp->if_flags &= ~IFF_OACTIVE;
1651 wlstart(ifp);
1652 }
1653 }
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 *
1666 * input : softc pointer for this interface
1667 * output : if a packet is available, it is "sent up"
1668 *
1669 */
1670static void
1671wlrcv(struct wl_softc *sc)
1672{
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)
1678 if_printf(&sc->wl_if, "entered wlrcv()\n");
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*/) {
1688 if (wlhwrst(sc) != TRUE)
1689 if_printf(&sc->wl_if, "rcv(): hwrst ffff trouble.\n");
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)
1696 if_printf(&sc->wl_if, "RCV: RSC %x\n", status);
1697#endif
1698 sc->wl_if.if_ierrors++;
1699 } else if (!(status & RFD_OK)) {
1700 if_printf(&sc->wl_if, "RCV: !OK %x\n", status);
1701 sc->wl_if.if_ierrors++;
1702 } else if (status & 0xfff) { /* can't happen */
1703 if_printf(&sc->wl_if, "RCV: ERRs %x\n", status);
1704 sc->wl_if.if_ierrors++;
1705 } else if (!wlread(sc, fd_p))
1706 return;
1707
1708 if (!wlrequeue(sc, fd_p)) {
1709 /* abort on chain error */
1710 if (wlhwrst(sc) != TRUE)
1711 if_printf(&sc->wl_if, "rcv(): hwrst trouble.\n");
1712 return;
1713 }
1714 sc->begin_fd = link_offset;
1715 } else {
1716 break;
1717 }
1718 }
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
1729wlrequeue(struct wl_softc *sc, u_short fd_p)
1730{
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 *
1786 * input : softc pointer for this interface, and a pointer to the mbuf
1787 * output : board memory and registers are set for xfer and attention
1788 *
1789 */
1790static void
1791wlxmt(struct wl_softc *sc, struct mbuf *m)
1792{
1793 u_short xmtdata_p = OFFSET_TBUF;
1794 u_short xmtshort_p;
1795 struct mbuf *tm_p = m;
1796 struct ether_header *eh_p = mtod(m, struct ether_header *);
1797 u_char *mb_p = mtod(m, u_char *) + sizeof(struct ether_header);
1798 u_short count = m->m_len - sizeof(struct ether_header);
1799 ac_t cb;
1800 u_short tbd_p = OFFSET_TBD;
1801 u_short len, clen = 0;
1802 short base = sc->base;
1803 int spin;
1804
1805#ifdef WLDEBUG
1806 if (sc->wl_if.if_flags & IFF_DEBUG)
1807 if_printf(&sc->wl_if, "entered wlxmt()\n");
1808#endif
1809
1810 cb.ac_status = 0;
1811 cb.ac_command = (AC_CW_EL|AC_TRANSMIT|AC_CW_I);
1812 cb.ac_link_offset = I82586NULL;
1813 outw(PIOR1(base), OFFSET_CU);
1814 outsw(PIOP1(base), &cb, 6/2);
1815 outw(PIOP1(base), OFFSET_TBD); /* cb.cmd.transmit.tbd_offset */
1816 outsw(PIOP1(base), eh_p->ether_dhost, WAVELAN_ADDR_SIZE/2);
1817 outw(PIOP1(base), eh_p->ether_type);
1818
1819#ifdef WLDEBUG
1820 if (sc->wl_if.if_flags & IFF_DEBUG) {
1821 if (xmt_debug) {
1822 if_printf(&sc->wl_if, "XMT mbuf: L%d @%p ", count, (void *)mb_p);
1823 printf("ether type %x\n", eh_p->ether_type);
1824 }
1825 }
1826#endif /* WLDEBUG */
1827 outw(PIOR0(base), OFFSET_TBD);
1828 outw(PIOP0(base), 0); /* act_count */
1829 outw(PIOR1(base), OFFSET_TBD + 4);
1830 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1831 outw(PIOP1(base), 0); /* buffer_base */
1832 for (;;) {
1833 if (count) {
1834 if (clen + count > WAVELAN_MTU)
1835 break;
1836 if (count & 1)
1837 len = count + 1;
1838 else
1839 len = count;
1840 outw(PIOR1(base), xmtdata_p);
1841 outsw(PIOP1(base), mb_p, len/2);
1842 clen += count;
1843 outw(PIOR0(base), tbd_p); /* address of act_count */
1844 outw(PIOP0(base), inw(PIOP0(base)) + count);
1845 xmtdata_p += len;
1846 if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1847 break;
1848 if (count & 1) {
1849 /* go to the next descriptor */
1850 outw(PIOR0(base), tbd_p + 2);
1851 tbd_p += sizeof (tbd_t);
1852 outw(PIOP0(base), tbd_p); /* next_tbd_offset */
1853 outw(PIOR0(base), tbd_p);
1854 outw(PIOP0(base), 0); /* act_count */
1855 outw(PIOR1(base), tbd_p + 4);
1856 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1857 outw(PIOP1(base), 0); /* buffer_base */
1858 /* at the end -> coallesce remaining mbufs */
1859 if (tbd_p == OFFSET_TBD + (N_TBD-1) * sizeof (tbd_t)) {
1860 wlsftwsleaze(&count, &mb_p, &tm_p);
1861 continue;
1862 }
1863 /* next mbuf short -> coallesce as needed */
1864 if ( (tm_p->m_next == (struct mbuf *) 0) ||
1865#define HDW_THRESHOLD 55
1866 tm_p->m_len > HDW_THRESHOLD)
1867 /* ok */;
1868 else {
1869 wlhdwsleaze(&count, &mb_p, &tm_p);
1870 continue;
1871 }
1872 }
1873 } else if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1874 break;
1875 count = tm_p->m_len;
1876 mb_p = mtod(tm_p, u_char *);
1877#ifdef WLDEBUG
1878 if (sc->wl_if.if_flags & IFF_DEBUG)
1879 if (xmt_debug)
1880 if_printf(&sc->wl_if, "mbuf+ L%d @%p ", count, (void *)mb_p);
1881#endif /* WLDEBUG */
1882 }
1883#ifdef WLDEBUG
1884 if (sc->wl_if.if_flags & IFF_DEBUG)
1885 if (xmt_debug)
1886 if_printf(&sc->wl_if, "CLEN = %d\n", clen);
1887#endif /* WLDEBUG */
1888 outw(PIOR0(base), tbd_p);
1889 if (clen < ETHERMIN) {
1890 outw(PIOP0(base), inw(PIOP0(base)) + ETHERMIN - clen);
1891 outw(PIOR1(base), xmtdata_p);
1892 for (xmtshort_p = xmtdata_p; clen < ETHERMIN; clen += 2)
1893 outw(PIOP1(base), 0);
1894 }
1895 outw(PIOP0(base), inw(PIOP0(base)) | TBD_SW_EOF);
1896 outw(PIOR0(base), tbd_p + 2);
1897 outw(PIOP0(base), I82586NULL);
1898#ifdef WLDEBUG
1899 if (sc->wl_if.if_flags & IFF_DEBUG) {
1900 if (xmt_debug) {
1901 wltbd(sc);
1902 printf("\n");
1903 }
1904 }
1905#endif /* WLDEBUG */
1906
1907 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
1908 /*
1909 * wait for 586 to clear previous command, complain if it takes
1910 * too long
1911 */
1912 for (spin = 1;;spin = (spin + 1) % 10000) {
1913 if (inw(PIOP0(base)) == 0) { /* it's done, we can go */
1914 break;
1915 }
1916 if ((spin == 0) && xmt_watch) { /* not waking up, and we care */
1917 if_printf(&sc->wl_if, "slow accepting xmit\n");
1918 }
1919 }
1920 outw(PIOP0(base), SCB_CU_STRT); /* new command */
1921 SET_CHAN_ATTN(sc);
1922
1923 m_freem(m);
1924
1925 /* XXX
1926 * Pause to avoid transmit overrun problems.
1927 * The required delay tends to vary with platform type, and may be
1928 * related to interrupt loss.
1929 */
1930 if (wl_xmit_delay) {
1931 DELAY(wl_xmit_delay);
1932 }
1933}
1934
1935/*
1936 * wlbldru:
1937 *
1938 * This function builds the linear linked lists of fd's and
1939 * rbd's. Based on page 4-32 of 1986 Intel microcom handbook.
1940 *
1941 */
1942static u_short
1943wlbldru(struct wl_softc *sc)
1944{
1945 short base = sc->base;
1946 fd_t fd;
1947 rbd_t rbd;
1948 u_short fd_p = OFFSET_RU;
1949 u_short rbd_p = OFFSET_RBD;
1950 int i;
1951
1952 sc->begin_fd = fd_p;
1953 for(i = 0; i < N_FD; i++) {
1954 fd.status = 0;
1955 fd.command = 0;
1956 fd.link_offset = fd_p + sizeof(fd_t);
1957 fd.rbd_offset = I82586NULL;
1958 outw(PIOR1(base), fd_p);
1959 outsw(PIOP1(base), &fd, 8/2);
1960 fd_p = fd.link_offset;
1961 }
1962 fd_p -= sizeof(fd_t);
1963 sc->end_fd = fd_p;
1964 outw(PIOR1(base), fd_p + 2);
1965 outw(PIOP1(base), AC_CW_EL); /* command */
1966 outw(PIOP1(base), I82586NULL); /* link_offset */
1967 fd_p = OFFSET_RU;
1968
1969 outw(PIOR0(base), fd_p + 6); /* address of rbd_offset */
1970 outw(PIOP0(base), rbd_p);
1971 outw(PIOR1(base), rbd_p);
1972 for(i = 0; i < N_RBD; i++) {
1973 rbd.status = 0;
1974 rbd.buffer_addr = rbd_p + sizeof(rbd_t) + 2;
1975 rbd.buffer_base = 0;
1976 rbd.size = RCVBUFSIZE;
1977 if (i != N_RBD-1) {
1978 rbd_p += sizeof(ru_t);
1979 rbd.next_rbd_offset = rbd_p;
1980 } else {
1981 rbd.next_rbd_offset = I82586NULL;
1982 rbd.size |= AC_CW_EL;
1983 sc->end_rbd = rbd_p;
1984 }
1985 outsw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1986 outw(PIOR1(base), rbd_p);
1987 }
1988 return sc->begin_fd;
1989}
1990
1991/*
1992 * wlrustrt:
1993 *
1994 * This routine starts the receive unit running. First checks if the
1995 * board is actually ready, then the board is instructed to receive
1996 * packets again.
1997 *
1998 */
1999static void
2000wlrustrt(struct wl_softc *sc)
2001{
2002 short base = sc->base;
2003 u_short rfa;
2004
2005#ifdef WLDEBUG
2006 if (sc->wl_if.if_flags & IFF_DEBUG)
2007 if_printf(&sc->wl_if, "entered wlrustrt()\n");
2008#endif
2009 outw(PIOR0(base), OFFSET_SCB);
2010 if (inw(PIOP0(base)) & SCB_RUS_READY){
2011 if_printf(&sc->wl_if, "wlrustrt: RUS_READY\n");
2012 return;
2013 }
2014
2015 outw(PIOR0(base), OFFSET_SCB + 2);
2016 outw(PIOP0(base), SCB_RU_STRT); /* command */
2017 rfa = wlbldru(sc);
2018 outw(PIOR0(base), OFFSET_SCB + 6); /* address of scb_rfa_offset */
2019 outw(PIOP0(base), rfa);
2020
2021 SET_CHAN_ATTN(sc);
2022}
2023
2024/*
2025 * wldiag:
2026 *
2027 * This routine does a 586 op-code number 7, and obtains the
2028 * diagnose status for the WaveLAN.
2029 *
2030 */
2031static int
2032wldiag(struct wl_softc *sc)
2033{
2034 short base = sc->base;
2035 short status;
2036
2037#ifdef WLDEBUG
2038 if (sc->wl_if.if_flags & IFF_DEBUG)
2039 if_printf(&sc->wl_if, "entered wldiag()\n");
2040#endif
2041 outw(PIOR0(base), OFFSET_SCB);
2042 status = inw(PIOP0(base));
2043 if (status & SCB_SW_INT) {
2044 /* state is 2000 which seems ok
2045 if_printf(&sc->wl_if, "diag(): unexpected initial state %\n",
2046 inw(PIOP0(base)));
2047 */
2048 wlack(sc);
2049 }
2050 outw(PIOR1(base), OFFSET_CU);
2051 outw(PIOP1(base), 0); /* ac_status */
2052 outw(PIOP1(base), AC_DIAGNOSE|AC_CW_EL);/* ac_command */
2053 if(wlcmd(sc, "diag()") == 0)
2054 return 0;
2055 outw(PIOR0(base), OFFSET_CU);
2056 if (inw(PIOP0(base)) & 0x0800) {
2057 if_printf(&sc->wl_if, "i82586 Self Test failed!\n");
2058 return 0;
2059 }
2060 return TRUE;
2061}
2062
2063/*
2064 * wlconfig:
2065 *
2066 * This routine does a standard config of the WaveLAN board.
2067 *
2068 */
2069static int
2070wlconfig(struct wl_softc *sc)
2071{
2072 configure_t configure;
2073 short base = sc->base;
2074
2075#if MULTICAST
2076#if defined(__DragonFly__) || (defined(__FreeBSD__) && __FreeBSD_version >= 300000)
2077 struct ifmultiaddr *ifma;
2078 u_char *addrp;
2079#else
2080 struct ether_multi *enm;
2081 struct ether_multistep step;
2082#endif
2083 int cnt = 0;
2084#endif /* MULTICAST */
2085
2086#ifdef WLDEBUG
2087 if (sc->wl_if.if_flags & IFF_DEBUG)
2088 if_printf(&sc->wl_if, "entered wlconfig()\n");
2089#endif
2090 outw(PIOR0(base), OFFSET_SCB);
2091 if (inw(PIOP0(base)) & SCB_SW_INT) {
2092 /*
2093 if_printf(&sc->wl_if, "config(): unexpected initial state %x\n",
2094 inw(PIOP0(base)));
2095 */
2096 }
2097 wlack(sc);
2098
2099 outw(PIOR1(base), OFFSET_CU);
2100 outw(PIOP1(base), 0); /* ac_status */
2101 outw(PIOP1(base), AC_CONFIGURE|AC_CW_EL); /* ac_command */
2102
2103/* jrb hack */
2104 configure.fifolim_bytecnt = 0x080c;
2105 configure.addrlen_mode = 0x0600;
2106 configure.linprio_interframe = 0x2060;
2107 configure.slot_time = 0xf200;
2108 configure.hardware = 0x0008; /* tx even w/o CD */
2109 configure.min_frame_len = 0x0040;
2110#if 0
2111 /* This is the configuration block suggested by Marc Meertens
2112 * <mmeerten@obelix.utrecht.NCR.COM> in an e-mail message to John
2113 * Ioannidis on 10 Nov 92.
2114 */
2115 configure.fifolim_bytecnt = 0x040c;
2116 configure.addrlen_mode = 0x0600;
2117 configure.linprio_interframe = 0x2060;
2118 configure.slot_time = 0xf000;
2119 configure.hardware = 0x0008; /* tx even w/o CD */
2120 configure.min_frame_len = 0x0040;
2121#else
2122 /*
2123 * below is the default board configuration from p2-28 from 586 book
2124 */
2125 configure.fifolim_bytecnt = 0x080c;
2126 configure.addrlen_mode = 0x2600;
2127 configure.linprio_interframe = 0x7820; /* IFS=120, ACS=2 */
2128 configure.slot_time = 0xf00c; /* slottime=12 */
2129 configure.hardware = 0x0008; /* tx even w/o CD */
2130 configure.min_frame_len = 0x0040;
2131#endif
2132 if(sc->mode & (MOD_PROM | MOD_ENAL)) {
2133 configure.hardware |= 1;
2134 }
2135 outw(PIOR1(base), OFFSET_CU + 6);
2136 outsw(PIOP1(base), &configure, sizeof(configure_t)/2);
2137
2138 if(wlcmd(sc, "config()-configure") == 0)
2139 return 0;
2140#if MULTICAST
2141 outw(PIOR1(base), OFFSET_CU);
2142 outw(PIOP1(base), 0); /* ac_status */
2143 outw(PIOP1(base), AC_MCSETUP|AC_CW_EL); /* ac_command */
2144 outw(PIOR1(base), OFFSET_CU + 8);
2145#if defined(__DragonFly__) || (defined(__FreeBSD__) && __FreeBSD_version >= 300000)
2146 LIST_FOREACH(ifma, &sc->wl_if.if_multiaddrs, ifma_link) {
2147 if (ifma->ifma_addr->sa_family != AF_LINK)
2148 continue;
2149
2150 addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
2151 outw(PIOP1(base), addrp[0] + (addrp[1] << 8));
2152 outw(PIOP1(base), addrp[2] + (addrp[3] << 8));
2153 outw(PIOP1(base), addrp[4] + (addrp[5] << 8));
2154 ++cnt;
2155 }
2156#else
2157 ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2158 while (enm != NULL) {
2159 unsigned int lo, hi;
2160 /* break if setting a multicast range, else we would crash */
2161 if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2162 break;
2163 }
2164 lo = (enm->enm_addrlo[3] << 16) + (enm->enm_addrlo[4] << 8)
2165 + enm->enm_addrlo[5];
2166 hi = (enm->enm_addrhi[3] << 16) + (enm->enm_addrhi[4] << 8)
2167 + enm->enm_addrhi[5];
2168 while(lo <= hi) {
2169 outw(PIOP1(base),enm->enm_addrlo[0] +
2170 (enm->enm_addrlo[1] << 8));
2171 outw(PIOP1(base),enm->enm_addrlo[2] +
2172 ((lo >> 8) & 0xff00));
2173 outw(PIOP1(base), ((lo >> 8) & 0xff) +
2174 ((lo << 8) & 0xff00));
2175/* #define MCASTDEBUG */
2176#ifdef MCASTDEBUG
2177printf("mcast_addr[%d,%d,%d] %x %x %x %x %x %x\n", lo, hi, cnt,
2178 enm->enm_addrlo[0],
2179 enm->enm_addrlo[1],
2180 enm->enm_addrlo[2],
2181 enm->enm_addrlo[3],
2182 enm->enm_addrlo[4],
2183 enm->enm_addrlo[5]);
2184#endif
2185 ++cnt;
2186 ++lo;
2187 }
2188 ETHER_NEXT_MULTI(step, enm);
2189 }
2190#endif
2191 outw(PIOR1(base), OFFSET_CU + 6); /* mc-cnt */
2192 outw(PIOP1(base), cnt * WAVELAN_ADDR_SIZE);
2193 if(wlcmd(sc, "config()-mcaddress") == 0)
2194 return 0;
2195#endif /* MULTICAST */
2196
2197 outw(PIOR1(base), OFFSET_CU);
2198 outw(PIOP1(base), 0); /* ac_status */
2199 outw(PIOP1(base), AC_IASETUP|AC_CW_EL); /* ac_command */
2200 outw(PIOR1(base), OFFSET_CU + 6);
2201 outsw(PIOP1(base), sc->wl_addr, WAVELAN_ADDR_SIZE/2);
2202
2203 if(wlcmd(sc, "config()-address") == 0)
2204 return(0);
2205
2206 wlinitmmc(sc);
2207
2208 return(1);
2209}
2210
2211/*
2212 * wlcmd:
2213 *
2214 * Set channel attention bit and busy wait until command has
2215 * completed. Then acknowledge the command completion.
2216 */
2217static int
2218wlcmd(struct wl_softc *sc, const char *str)
2219{
2220 short base = sc->base;
2221 int i;
2222
2223 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
2224 outw(PIOP0(base), SCB_CU_STRT);
2225
2226 SET_CHAN_ATTN(sc);
2227
2228 outw(PIOR0(base), OFFSET_CU);
2229 for(i = 0; i < 0xffff; i++)
2230 if (inw(PIOP0(base)) & AC_SW_C)
2231 break;
2232 if (i == 0xffff || !(inw(PIOP0(base)) & AC_SW_OK)) {
2233 if_printf(&sc->wl_if, "%s failed; status = %d, inw = %x, outw = %x\n",
2234 str, inw(PIOP0(base)) & AC_SW_OK, inw(PIOP0(base)),
2235 inw(PIOR0(base)));
2236 outw(PIOR0(base), OFFSET_SCB);
2237 printf("scb_status %x\n", inw(PIOP0(base)));
2238 outw(PIOR0(base), OFFSET_SCB+2);
2239 printf("scb_command %x\n", inw(PIOP0(base)));
2240 outw(PIOR0(base), OFFSET_SCB+4);
2241 printf("scb_cbl %x\n", inw(PIOP0(base)));
2242 outw(PIOR0(base), OFFSET_CU+2);
2243 printf("cu_cmd %x\n", inw(PIOP0(base)));
2244 return(0);
2245 }
2246
2247 outw(PIOR0(base), OFFSET_SCB);
2248 if ((inw(PIOP0(base)) & SCB_SW_INT) && (inw(PIOP0(base)) != SCB_SW_CNA)) {
2249 /*
2250 if_printf(&sc->wl_if, "%s: unexpected final state %x\n",
2251 str, inw(PIOP0(base)));
2252 */
2253 }
2254 wlack(sc);
2255 return(TRUE);
2256}
2257
2258/*
2259 * wlack: if the 82596 wants attention because it has finished
2260 * sending or receiving a packet, acknowledge its desire and
2261 * return bits indicating the kind of attention. wlack() returns
2262 * these bits so that the caller can service exactly the
2263 * conditions that wlack() acknowledged.
2264 */
2265static int
2266wlack(struct wl_softc *sc)
2267{
2268 int i;
2269 u_short cmd;
2270 short base = sc->base;
2271
2272 outw(PIOR1(base), OFFSET_SCB);
2273 if(!(cmd = (inw(PIOP1(base)) & SCB_SW_INT)))
2274 return(0);
2275#ifdef WLDEBUG
2276 if (sc->wl_if.if_flags & IFF_DEBUG)
2277 if_printf(&sc->wl_if, "doing a wlack()\n");
2278#endif
2279 outw(PIOP1(base), cmd);
2280 SET_CHAN_ATTN(sc);
2281 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
2282 for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
2283 if (i < 1)
2284 if_printf(&sc->wl_if, "wlack(): board not accepting command.\n");
2285 return(cmd);
2286}
2287
2288static void
2289wltbd(struct wl_softc *sc)
2290{
2291 short base = sc->base;
2292 u_short tbd_p = OFFSET_TBD;
2293 tbd_t tbd;
2294 int i = 0;
2295 int sum = 0;
2296
2297 for (;;) {
2298 outw(PIOR1(base), tbd_p);
2299 insw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
2300 sum += (tbd.act_count & ~TBD_SW_EOF);
2301 printf("%d: addr %x, count %d (%d), next %x, base %x\n",
2302 i++, tbd.buffer_addr,
2303 (tbd.act_count & ~TBD_SW_EOF), sum,
2304 tbd.next_tbd_offset, tbd.buffer_base);
2305 if (tbd.act_count & TBD_SW_EOF)
2306 break;
2307 tbd_p = tbd.next_tbd_offset;
2308 }
2309}
2310
2311static void
2312wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp)
2313{
2314 struct mbuf *tm_p = *tm_pp;
2315 u_char *mb_p = *mb_pp;
2316 u_short count = 0;
2317 u_char *cp;
2318 int len;
2319
2320 /*
2321 * can we get a run that will be coallesced or
2322 * that terminates before breaking
2323 */
2324 do {
2325 count += tm_p->m_len;
2326 if (tm_p->m_len & 1)
2327 break;
2328 } while ((tm_p = tm_p->m_next) != (struct mbuf *)0);
2329 if ( (tm_p == (struct mbuf *)0) ||
2330 count > HDW_THRESHOLD) {
2331 *countp = (*tm_pp)->m_len;
2332 *mb_pp = mtod((*tm_pp), u_char *);
2333 return;
2334 }
2335
2336 /* we need to copy */
2337 tm_p = *tm_pp;
2338 mb_p = *mb_pp;
2339 count = 0;
2340 cp = (u_char *) t_packet;
2341 for (;;) {
2342 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2343 count += len;
2344 if (count > HDW_THRESHOLD)
2345 break;
2346 cp += len;
2347 if (tm_p->m_next == (struct mbuf *)0)
2348 break;
2349 tm_p = tm_p->m_next;
2350 }
2351 *countp = count;
2352 *mb_pp = (u_char *) t_packet;
2353 *tm_pp = tm_p;
2354}
2355
2356static void
2357wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp)
2358{
2359 struct mbuf *tm_p = *tm_pp;
2360 u_short count = 0;
2361 u_char *cp = (u_char *) t_packet;
2362 int len;
2363
2364 /* we need to copy */
2365 for (;;) {
2366 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2367 count += len;
2368 cp += len;
2369 if (tm_p->m_next == (struct mbuf *)0)
2370 break;
2371 tm_p = tm_p->m_next;
2372 }
2373
2374 *countp = count;
2375 *mb_pp = (u_char *) t_packet;
2376 *tm_pp = tm_p;
2377}
2378
2379static void
2380wlmmcstat(struct wl_softc *sc)
2381{
2382 short base = sc->base;
2383 u_short tmp;
2384
2385 if_printf(&sc->wl_if, "DCE_STATUS: 0x%x, ",
2386 wlmmcread(base,MMC_DCE_STATUS) & 0x0f);
2387 tmp = wlmmcread(base,MMC_CORRECT_NWID_H) << 8;
2388 tmp |= wlmmcread(base,MMC_CORRECT_NWID_L);
2389 printf("Correct NWID's: %d, ", tmp);
2390 tmp = wlmmcread(base,MMC_WRONG_NWID_H) << 8;
2391 tmp |= wlmmcread(base,MMC_WRONG_NWID_L);
2392 printf("Wrong NWID's: %d\n", tmp);
2393 printf("THR_PRE_SET: 0x%x, ", wlmmcread(base,MMC_THR_PRE_SET));
2394 printf("SIGNAL_LVL: %d, SILENCE_LVL: %d\n",
2395 wlmmcread(base,MMC_SIGNAL_LVL),
2396 wlmmcread(base,MMC_SILENCE_LVL));
2397 printf("SIGN_QUAL: 0x%x, NETW_ID: %x:%x, DES: %d\n",
2398 wlmmcread(base,MMC_SIGN_QUAL),
2399 wlmmcread(base,MMC_NETW_ID_H),
2400 wlmmcread(base,MMC_NETW_ID_L),
2401 wlmmcread(base,MMC_DES_AVAIL));
2402}
2403
2404static u_short
2405wlmmcread(u_int base, u_short reg)
2406{
2407 while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2408 outw(MMCR(base),reg << 1);
2409 while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2410 return (u_short)inw(MMCR(base)) >> 8;
2411}
2412
2413static void
2414getsnr(struct wl_softc *sc)
2415{
2416 MMC_WRITE(MMC_FREEZE,1);
2417 /*
2418 * SNR retrieval procedure :
2419 *
2420 * read signal level : wlmmcread(base, MMC_SIGNAL_LVL);
2421 * read silence level : wlmmcread(base, MMC_SILENCE_LVL);
2422 */
2423 MMC_WRITE(MMC_FREEZE,0);
2424 /*
2425 * SNR is signal:silence ratio.
2426 */
2427}
2428
2429/*
2430** wlgetpsa
2431**
2432** Reads the psa for the wavelan at (base) into (buf)
2433*/
2434static void
2435wlgetpsa(int base, u_char *buf)
2436{
2437 int i;
2438
2439 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2440 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2441
2442 for (i = 0; i < 0x40; i++) {
2443 outw(PIOR2(base), i);
2444 buf[i] = inb(PIOP2(base));
2445 }
2446 PCMD(base, HACR_DEFAULT);
2447 PCMD(base, HACR_DEFAULT);
2448}
2449
2450/*
2451** wlsetpsa
2452**
2453** Writes the psa for wavelan (unit) from the softc back to the
2454** board. Updates the CRC and sets the CRC OK flag.
2455**
2456** Do not call this when the board is operating, as it doesn't
2457** preserve the hacr.
2458*/
2459static void
2460wlsetpsa(struct wl_softc *sc)
2461{
2462 short base = sc->base;
2463 int i;
2464 u_short crc;
2465
2466 crc = wlpsacrc(sc->psa); /* calculate CRC of PSA */
2467 sc->psa[WLPSA_CRCLOW] = crc & 0xff;
2468 sc->psa[WLPSA_CRCHIGH] = (crc >> 8) & 0xff;
2469 sc->psa[WLPSA_CRCOK] = 0x55; /* default to 'bad' until programming complete */
2470
2471 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2472 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2473
2474 for (i = 0; i < 0x40; i++) {
2475 DELAY(DELAYCONST);
2476 outw(PIOR2(base),i); /* write param memory */
2477 DELAY(DELAYCONST);
2478 outb(PIOP2(base), sc->psa[i]);
2479 }
2480 DELAY(DELAYCONST);
2481 outw(PIOR2(base),WLPSA_CRCOK); /* update CRC flag*/
2482 DELAY(DELAYCONST);
2483 sc->psa[WLPSA_CRCOK] = 0xaa; /* OK now */
2484 outb(PIOP2(base), 0xaa); /* all OK */
2485 DELAY(DELAYCONST);
2486
2487 PCMD(base, HACR_DEFAULT);
2488 PCMD(base, HACR_DEFAULT);
2489}
2490
2491/*
2492** CRC routine provided by Christopher Giordano <cgiordan@gdeb.com>,
2493** from original code by Tomi Mikkonen (tomitm@remedy.fi)
2494*/
2495
2496static u_int crc16_table[16] = {
2497 0x0000, 0xCC01, 0xD801, 0x1400,
2498 0xF001, 0x3C00, 0x2800, 0xE401,
2499 0xA001, 0x6C00, 0x7800, 0xB401,
2500 0x5000, 0x9C01, 0x8801, 0x4400
2501};
2502
2503static u_short
2504wlpsacrc(u_char *buf)
2505{
2506 u_short crc = 0;
2507 int i, r1;
2508
2509 for (i = 0; i < 0x3d; i++, buf++) {
2510 /* lower 4 bits */
2511 r1 = crc16_table[crc & 0xF];
2512 crc = (crc >> 4) & 0x0FFF;
2513 crc = crc ^ r1 ^ crc16_table[*buf & 0xF];
2514
2515 /* upper 4 bits */
2516 r1 = crc16_table[crc & 0xF];
2517 crc = (crc >> 4) & 0x0FFF;
2518 crc = crc ^ r1 ^ crc16_table[(*buf >> 4) & 0xF];
2519 }
2520 return(crc);
2521}
2522#ifdef WLCACHE
2523
2524/*
2525 * wl_cache_store
2526 *
2527 * take input packet and cache various radio hw characteristics
2528 * indexed by MAC address.
2529 *
2530 * Some things to think about:
2531 * note that no space is malloced.
2532 * We might hash the mac address if the cache were bigger.
2533 * It is not clear that the cache is big enough.
2534 * It is also not clear how big it should be.
2535 * The cache is IP-specific. We don't care about that as
2536 * we want it to be IP-specific.
2537 * The last N recv. packets are saved. This will tend
2538 * to reward agents and mobile hosts that beacon.
2539 * That is probably fine for mobile ip.
2540 */
2541
2542/* globals for wavelan signal strength cache */
2543/* this should go into softc structure above.
2544*/
2545
2546/* set true if you want to limit cache items to broadcast/mcast
2547 * only packets (not unicast)
2548 */
2549static int wl_cache_mcastonly = 1;
2550SYSCTL_INT(_machdep, OID_AUTO, wl_cache_mcastonly, CTLFLAG_RW,
2551 &wl_cache_mcastonly, 0, "");
2552
2553/* set true if you want to limit cache items to IP packets only
2554*/
2555static int wl_cache_iponly = 1;
2556SYSCTL_INT(_machdep, OID_AUTO, wl_cache_iponly, CTLFLAG_RW,
2557 &wl_cache_iponly, 0, "");
2558
2559/* zero out the cache
2560*/
2561static void
2562wl_cache_zero(struct wl_softc *sc)
2563{
2564 bzero(&sc->w_sigcache[0], sizeof(struct w_sigcache) * MAXCACHEITEMS);
2565 sc->w_sigitems = 0;
2566 sc->w_nextcache = 0;
2567 sc->w_wrapindex = 0;
2568}
2569
2570/* store hw signal info in cache.
2571 * index is MAC address, but an ip src gets stored too
2572 * There are two filters here controllable via sysctl:
2573 * throw out unicast (on by default, but can be turned off)
2574 * throw out non-ip (on by default, but can be turned off)
2575 */
2576static
2577void wl_cache_store (struct wl_softc *sc, int base, struct ether_header *eh,
2578 struct mbuf *m)
2579{
2580 struct ip *ip = NULL; /* Avoid GCC warning */
2581 int i;
2582 int signal, silence;
2583 int w_insertcache; /* computed index for cache entry storage */
2584 int ipflag = wl_cache_iponly;
2585
2586 /* filters:
2587 * 1. ip only
2588 * 2. configurable filter to throw out unicast packets,
2589 * keep multicast only.
2590 */
2591
2592#ifdef INET
2593 /* reject if not IP packet
2594 */
2595 if ( wl_cache_iponly && (ntohs(eh->ether_type) != 0x800)) {
2596 return;
2597 }
2598
2599 /* check if broadcast or multicast packet. we toss
2600 * unicast packets
2601 */
2602 if (wl_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
2603 return;
2604 }
2605
2606 /* find the ip header. we want to store the ip_src
2607 * address. use the mtod macro(in mbuf.h)
2608 * to typecast m to struct ip *
2609 */
2610 if (ipflag) {
2611 ip = mtod(m, struct ip *);
2612 }
2613
2614 /* do a linear search for a matching MAC address
2615 * in the cache table
2616 * . MAC address is 6 bytes,
2617 * . var w_nextcache holds total number of entries already cached
2618 */
2619 for(i = 0; i < sc->w_nextcache; i++) {
2620 if (! bcmp(eh->ether_shost, sc->w_sigcache[i].macsrc, 6 )) {
2621 /* Match!,
2622 * so we already have this entry,
2623 * update the data, and LRU age
2624 */
2625 break;
2626 }
2627 }
2628
2629 /* did we find a matching mac address?
2630 * if yes, then overwrite a previously existing cache entry
2631 */
2632 if (i < sc->w_nextcache ) {
2633 w_insertcache = i;
2634 }
2635 /* else, have a new address entry,so
2636 * add this new entry,
2637 * if table full, then we need to replace entry
2638 */
2639 else {
2640
2641 /* check for space in cache table
2642 * note: w_nextcache also holds number of entries
2643 * added in the cache table
2644 */
2645 if ( sc->w_nextcache < MAXCACHEITEMS ) {
2646 w_insertcache = sc->w_nextcache;
2647 sc->w_nextcache++;
2648 sc->w_sigitems = sc->w_nextcache;
2649 }
2650 /* no space found, so simply wrap with wrap index
2651 * and "zap" the next entry
2652 */
2653 else {
2654 if (sc->w_wrapindex == MAXCACHEITEMS) {
2655 sc->w_wrapindex = 0;
2656 }
2657 w_insertcache = sc->w_wrapindex++;
2658 }
2659 }
2660
2661 /* invariant: w_insertcache now points at some slot
2662 * in cache.
2663 */
2664 if (w_insertcache < 0 || w_insertcache >= MAXCACHEITEMS) {
2665 log(LOG_ERR,
2666 "wl_cache_store, bad index: %d of [0..%d], gross cache error\n",
2667 w_insertcache, MAXCACHEITEMS);
2668 return;
2669 }
2670
2671 /* store items in cache
2672 * .ipsrc
2673 * .macsrc
2674 * .signal (0..63) ,silence (0..63) ,quality (0..15)
2675 */
2676 if (ipflag) {
2677 sc->w_sigcache[w_insertcache].ipsrc = ip->ip_src.s_addr;
2678 }
2679 bcopy( eh->ether_shost, sc->w_sigcache[w_insertcache].macsrc, 6);
2680 signal = sc->w_sigcache[w_insertcache].signal = wlmmcread(base, MMC_SIGNAL_LVL) & 0x3f;
2681 silence = sc->w_sigcache[w_insertcache].silence = wlmmcread(base, MMC_SILENCE_LVL) & 0x3f;
2682 sc->w_sigcache[w_insertcache].quality = wlmmcread(base, MMC_SIGN_QUAL) & 0x0f;
2683 if (signal > 0)
2684 sc->w_sigcache[w_insertcache].snr =
2685 signal - silence;
2686 else
2687 sc->w_sigcache[w_insertcache].snr = 0;
2688#endif /* INET */
2689
2690}
2691#endif /* WLCACHE */
2692
2693/*
2694 * determine if in all multicast mode or not
2695 *
2696 * returns: 1 if IFF_ALLMULTI should be set
2697 * else 0
2698 */
2699#ifdef MULTICAST
2700
2701#if defined(__FreeBSD__) && __FreeBSD_version < 300000 /* not required */
2702static int
2703check_allmulti(struct wl_softc *sc)
2704{
2705 short base = sc->base;
2706 struct ether_multi *enm;
2707 struct ether_multistep step;
2708
2709 ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2710 while (enm != NULL) {
2711 unsigned int lo, hi;
2712#ifdef MDEBUG
2713 printf("enm_addrlo %x:%x:%x:%x:%x:%x\n", enm->enm_addrlo[0], enm->enm_addrlo[1],
2714 enm->enm_addrlo[2], enm->enm_addrlo[3], enm->enm_addrlo[4],
2715 enm->enm_addrlo[5]);
2716 printf("enm_addrhi %x:%x:%x:%x:%x:%x\n", enm->enm_addrhi[0], enm->enm_addrhi[1],
2717 enm->enm_addrhi[2], enm->enm_addrhi[3], enm->enm_addrhi[4],
2718 enm->enm_addrhi[5]);
2719#endif
2720 if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2721 return(1);
2722 }
2723 ETHER_NEXT_MULTI(step, enm);
2724 }
2725 return(0);
2726}
2727#endif
2728#endif