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.14 2004/08/02 13:22:32 joerg Exp $ */
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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
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.
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
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.
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
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.
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).
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.
85 * device wl0 at isa? port 0x300 net irq ?
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
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...
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.
128 * Olivetti PC586 Mach Ethernet driver v1.0
129 * Copyright Ing. C. Olivetti & C. S.p.A. 1988, 1989
130 * All rights reserved.
135 Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc.,
136 Cupertino, California.
140 Permission to use, copy, modify, and distribute this software and
141 its documentation for any purpose and without fee is hereby
142 granted, provided that the above copyright notice appears in all
143 copies and that both the copyright notice and this permission notice
144 appear in supporting documentation, and that the name of Olivetti
145 not be used in advertising or publicity pertaining to distribution
146 of the software without specific, written prior permission.
148 OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
149 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
150 IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
151 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
152 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
153 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
154 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
158 Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
162 Permission to use, copy, modify, and distribute this software and
163 its documentation for any purpose and without fee is hereby
164 granted, provided that the above copyright notice appears in all
165 copies and that both the copyright notice and this permission notice
166 appear in supporting documentation, and that the name of Intel
167 not be used in advertising or publicity pertaining to distribution
168 of the software without specific, written prior permission.
170 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
171 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
172 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
173 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
174 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
175 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
176 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
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.
193 #include "opt_wavelan.h"
194 #include "opt_inet.h"
196 #include <sys/param.h>
197 #include <sys/systm.h>
198 #include <sys/sockio.h>
199 #include <sys/mbuf.h>
200 #include <sys/socket.h>
201 #include <sys/syslog.h>
202 #include <sys/proc.h>
204 #include <sys/kernel.h>
205 #include <sys/sysctl.h>
207 #include <net/ethernet.h>
209 #include <net/if_dl.h>
212 #include <netinet/in.h>
213 #include <netinet/in_systm.h>
214 #include <netinet/ip.h>
215 #include <netinet/if_ether.h>
220 #include <machine/clock.h>
222 #include <bus/isa/i386/isa_device.h>
223 #include "if_wl_i82586.h" /* Definitions for the Intel chip */
225 /* was 1000 in original, fed to DELAY(x) */
226 #define DELAYCONST 1000
228 #include <machine/if_wl_wavelan.h>
230 static char t_packet[ETHERMTU + sizeof(struct ether_header) + sizeof(long)];
233 struct arpcom wl_ac; /* Ethernet common part */
234 #define wl_if wl_ac.ac_if /* network visible interface */
235 #define wl_addr wl_ac.ac_enaddr /* hardware address */
237 u_char nwid[2]; /* current radio modem nwid */
241 int tbusy; /* flag to determine if xmit is busy */
245 u_short hacr; /* latest host adapter CR command */
247 u_char chan24; /* 2.4 Gz: channel number/EEPROM Area # */
248 u_short freq24; /* 2.4 Gz: resulting frequency */
249 struct callout_handle watchdog_ch;
251 int w_sigitems; /* number of cached entries */
252 /* array of cache entries */
253 struct w_sigcache w_sigcache[ MAXCACHEITEMS ];
254 int w_nextcache; /* next free cache entry */
255 int w_wrapindex; /* next "free" cache entry */
258 static struct wl_softc wl_softc[NWL];
260 #define WLSOFTC(unit) ((struct wl_softc *)(&wl_softc[unit]))
262 static int wlprobe(struct isa_device *);
263 static int wlattach(struct isa_device *);
265 DECLARE_DUMMY_MODULE(if_wl);
267 struct isa_driver wldriver = {
268 wlprobe, wlattach, "wl", 0
272 * XXX The Wavelan appears to be prone to dropping stuff if you talk to
273 * it too fast. This disgusting hack inserts a delay after each packet
274 * is queued which helps avoid this behaviour on fast systems.
276 static int wl_xmit_delay = 250;
277 SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_delay, CTLFLAG_RW, &wl_xmit_delay, 0, "");
280 * not XXX, but ZZZ (bizarre).
281 * promiscuous mode can be toggled to ignore NWIDs. By default,
282 * it does not. Caution should be exercised about combining
283 * this mode with IFF_ALLMULTI which puts this driver in
286 static int wl_ignore_nwid = 0;
287 SYSCTL_INT(_machdep, OID_AUTO, wl_ignore_nwid, CTLFLAG_RW, &wl_ignore_nwid, 0, "");
290 * Emit diagnostics about transmission problems
292 static int xmt_watch = 0;
293 SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_watch, CTLFLAG_RW, &xmt_watch, 0, "");
296 * Collect SNR statistics
298 static int gathersnr = 0;
299 SYSCTL_INT(_machdep, OID_AUTO, wl_gather_snr, CTLFLAG_RW, &gathersnr, 0, "");
301 static void wlstart(struct ifnet *ifp);
302 static void wlinit(void *xsc);
303 static int wlioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *);
304 static timeout_t wlwatchdog;
305 static ointhand2_t wlintr;
306 static void wlxmt(int unt, struct mbuf *m);
307 static int wldiag(int unt);
308 static int wlconfig(int unit);
309 static int wlcmd(int unit, char *str);
310 static void wlmmcstat(int unit);
311 static u_short wlbldru(int unit);
312 static u_short wlmmcread(u_int base, u_short reg);
313 static void wlinitmmc(int unit);
314 static int wlhwrst(int unit);
315 static void wlrustrt(int unit);
316 static void wlbldcu(int unit);
317 static int wlack(int unit);
318 static int wlread(int unit, u_short fd_p);
319 static void getsnr(int unit);
320 static void wlrcv(int unit);
321 static int wlrequeue(int unit, u_short fd_p);
322 static void wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
323 static void wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
324 static void wltbd(int unit);
325 static void wlgetpsa(int base, u_char *buf);
326 static void wlsetpsa(int unit);
327 static u_short wlpsacrc(u_char *buf);
328 static void wldump(int unit);
330 static void wl_cache_store(int, int, struct ether_header *, struct mbuf *);
331 static void wl_cache_zero(int unit);
334 # if defined(__FreeBSD__) && __FreeBSD_version < 300000
335 static int check_allmulti(int unit);
339 /* array for maping irq numbers to values for the irq parameter register */
340 static int irqvals[16] = {
341 0, 0, 0, 0x01, 0x02, 0x04, 0, 0x08, 0, 0, 0x10, 0x20, 0x40, 0, 0, 0x80
343 /* mask of valid IRQs */
344 #define WL_IRQS (IRQ3|IRQ4|IRQ5|IRQ7|IRQ10|IRQ11|IRQ12|IRQ15)
349 * This function "probes" or checks for the WaveLAN board on the bus to
350 * see if it is there. As far as I can tell, the best break between this
351 * routine and the attach code is to simply determine whether the board
352 * is configured in properly. Currently my approach to this is to write
353 * and read a word from the SRAM on the board being probed. If the word
354 * comes back properly then we assume the board is there. The config
355 * code expects to see a successful return from the probe routine before
356 * attach will be called.
358 * input : address device is mapped to, and unit # being checked
359 * output : a '1' is returned if the board exists, and a 0 otherwise
363 wlprobe(struct isa_device *id)
365 struct wl_softc *sc = &wl_softc[id->id_unit];
366 short base = id->id_iobase;
367 char *str = "wl%d: board out of range [0..%d]\n";
369 unsigned long oldpri;
373 * regular CMD() will not work, since no softc yet
375 #define PCMD(base, hacr) outw((base), (hacr))
378 PCMD(base, HACR_RESET); /* reset the board */
379 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
380 PCMD(base, HACR_RESET); /* reset the board */
381 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
384 /* clear reset command and set PIO#1 in autoincrement mode */
385 PCMD(base, HACR_DEFAULT);
386 PCMD(base, HACR_DEFAULT);
387 outw(PIOR1(base), 0); /* go to beginning of RAM */
388 outsw(PIOP1(base), str, strlen(str)/2+1); /* write string */
390 outw(PIOR1(base), 0); /* rewind */
391 insw(PIOP1(base), inbuf, strlen(str)/2+1); /* read result */
393 if (bcmp(str, inbuf, strlen(str)))
396 sc->chan24 = 0; /* 2.4 Gz: config channel */
397 sc->freq24 = 0; /* 2.4 Gz: frequency */
399 /* read the PSA from the board into temporary storage */
400 wlgetpsa(base, inbuf);
402 /* We read the IRQ value from the PSA on the board. */
403 for (irq = 15; irq >= 0; irq--)
404 if (irqvals[irq] == inbuf[WLPSA_IRQNO])
406 if ((irq == 0) || (irqvals[irq] == 0)){
407 printf("wl%d: PSA corrupt (invalid IRQ value)\n", id->id_unit);
408 id->id_irq = 0; /* no interrupt */
411 * If the IRQ requested by the PSA is already claimed by another
412 * device, the board won't work, but the user can still access the
413 * driver to change the IRQ.
415 id->id_irq = (1<<irq); /* use IRQ from PSA */
424 * This function attaches a WaveLAN board to the "system". The rest of
425 * runtime structures are initialized here (this routine is called after
426 * a successful probe of the board). Once the ethernet address is read
427 * and stored, the board's ifnet structure is attached and readied.
429 * input : isa_dev structure setup in autoconfig
430 * output : board structs and ifnet is setup
434 wlattach(struct isa_device *id)
436 struct wl_softc *sc = (struct wl_softc *) &wl_softc[id->id_unit];
437 short base = id->id_iobase;
439 u_char unit = id->id_unit;
440 struct ifnet *ifp = &sc->wl_if;
443 printf("wlattach: base %x, unit %d\n", base, unit);
445 id->id_ointr = wlintr;
450 sc->hacr = HACR_RESET;
451 callout_handle_init(&sc->watchdog_ch);
452 CMD(unit); /* reset the board */
453 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
455 /* clear reset command and set PIO#2 in parameter access mode */
456 sc->hacr = (HACR_DEFAULT & ~HACR_16BITS);
459 /* Read the PSA from the board for our later reference */
460 wlgetpsa(base, sc->psa);
463 sc->nwid[0] = sc->psa[WLPSA_NWID];
464 sc->nwid[1] = sc->psa[WLPSA_NWID+1];
466 /* fetch MAC address - decide which one first */
467 if (sc->psa[WLPSA_MACSEL] & 1) {
472 for(i=0; i < WAVELAN_ADDR_SIZE; ++i) {
473 sc->wl_addr[i] = sc->psa[j + i];
476 /* enter normal 16 bit mode operation */
477 sc->hacr = HACR_DEFAULT;
481 outw(PIOR1(base), OFFSET_SCB + 8); /* address of scb_crcerrs */
482 outw(PIOP1(base), 0); /* clear scb_crcerrs */
483 outw(PIOP1(base), 0); /* clear scb_alnerrs */
484 outw(PIOP1(base), 0); /* clear scb_rscerrs */
485 outw(PIOP1(base), 0); /* clear scb_ovrnerrs */
487 bzero(ifp, sizeof(ifp));
489 if_initname(ifp, "wl", id->id_unit);
490 ifp->if_mtu = WAVELAN_MTU;
491 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
493 ifp->if_flags |= IFF_DEBUG;
496 ifp->if_flags |= IFF_MULTICAST;
497 #endif /* MULTICAST */
498 ifp->if_init = wlinit;
499 ifp->if_start = wlstart;
500 ifp->if_ioctl = wlioctl;
501 ifp->if_timer = 0; /* paranoia */
507 ether_ifattach(ifp, sc->wl_ac.ac_enaddr);
509 bcopy(&sc->wl_addr[0], sc->wl_ac.ac_enaddr, WAVELAN_ADDR_SIZE);
510 if_printf(ifp, "NWID 0x%02x%02x", sc->nwid[0], sc->nwid[1]);
512 printf(", Freq %d MHz",sc->freq24); /* 2.4 Gz */
513 printf("\n"); /* 2.4 Gz */
522 * Print out interesting information about the 82596.
527 struct wl_softc *sp = WLSOFTC(unit);
531 printf("hasr %04x\n", inw(HASR(base)));
533 printf("scb at %04x:\n ", OFFSET_SCB);
534 outw(PIOR1(base), OFFSET_SCB);
535 for(i = 0; i < 8; i++)
536 printf("%04x ", inw(PIOP1(base)));
539 printf("cu at %04x:\n ", OFFSET_CU);
540 outw(PIOR1(base), OFFSET_CU);
541 for(i = 0; i < 8; i++)
542 printf("%04x ", inw(PIOP1(base)));
545 printf("tbd at %04x:\n ", OFFSET_TBD);
546 outw(PIOR1(base), OFFSET_TBD);
547 for(i = 0; i < 4; i++)
548 printf("%04x ", inw(PIOP1(base)));
552 /* Initialize the Modem Management Controller */
556 struct wl_softc *sp = WLSOFTC(unit);
562 /* enter 8 bit operation */
563 sp->hacr = (HACR_DEFAULT & ~HACR_16BITS);
566 configured = sp->psa[WLPSA_CONFIGURED] & 1;
569 * Set default modem control parameters. Taken from NCR document
572 MMC_WRITE(MMC_JABBER_ENABLE, 0x01);
573 MMC_WRITE(MMC_ANTEN_SEL, 0x02);
574 MMC_WRITE(MMC_IFS, 0x20);
575 MMC_WRITE(MMC_MOD_DELAY, 0x04);
576 MMC_WRITE(MMC_JAM_TIME, 0x38);
577 MMC_WRITE(MMC_DECAY_PRM, 0x00); /* obsolete ? */
578 MMC_WRITE(MMC_DECAY_UPDAT_PRM, 0x00);
580 MMC_WRITE(MMC_LOOPT_SEL, 0x00);
581 if (sp->psa[WLPSA_COMPATNO] & 1) {
582 MMC_WRITE(MMC_THR_PRE_SET, 0x01); /* 0x04 for AT and 0x01 for MCA */
584 MMC_WRITE(MMC_THR_PRE_SET, 0x04); /* 0x04 for AT and 0x01 for MCA */
586 MMC_WRITE(MMC_QUALITY_THR, 0x03);
588 /* use configuration defaults from parameter storage area */
589 if (sp->psa[WLPSA_NWIDENABLE] & 1) {
590 if ((mode & (MOD_PROM | MOD_ENAL)) && wl_ignore_nwid) {
591 MMC_WRITE(MMC_LOOPT_SEL, 0x40);
593 MMC_WRITE(MMC_LOOPT_SEL, 0x00);
596 MMC_WRITE(MMC_LOOPT_SEL, 0x40); /* disable network id check */
598 MMC_WRITE(MMC_THR_PRE_SET, sp->psa[WLPSA_THRESH]);
599 MMC_WRITE(MMC_QUALITY_THR, sp->psa[WLPSA_QUALTHRESH]);
601 MMC_WRITE(MMC_FREEZE, 0x00);
602 MMC_WRITE(MMC_ENCR_ENABLE, 0x00);
604 MMC_WRITE(MMC_NETW_ID_L,sp->nwid[1]); /* set NWID */
605 MMC_WRITE(MMC_NETW_ID_H,sp->nwid[0]);
607 /* enter normal 16 bit mode operation */
608 sp->hacr = HACR_DEFAULT;
610 CMD(unit); /* virtualpc1 needs this! */
612 if (sp->psa[WLPSA_COMPATNO]== /* 2.4 Gz: half-card ver */
613 WLPSA_COMPATNO_WL24B) { /* 2.4 Gz */
614 i=sp->chan24<<4; /* 2.4 Gz: position ch # */
615 MMC_WRITE(MMC_EEADDR,i+0x0f); /* 2.4 Gz: named ch, wc=16 */
616 MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+ /* 2.4 Gz: Download Synths */
617 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: Read EEPROM */
618 for (i=0; i<1000; ++i) { /* 2.4 Gz: wait for download */
619 DELAY(40); /* 2.4 Gz */
620 if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and */
621 &(MMC_EECTRLstat_DWLD /* 2.4 Gz: EEBUSY */
622 +MMC_EECTRLstat_EEBUSY))==0) /* 2.4 Gz: */
623 break; /* 2.4 Gz: download finished */
625 if (i==1000) printf("wl: synth load failed\n"); /* 2.4 Gz */
626 MMC_WRITE(MMC_EEADDR,0x61); /* 2.4 Gz: default pwr, wc=2 */
627 MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+ /* 2.4 Gz: Download Xmit Pwr */
628 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: Read EEPROM */
629 for (i=0; i<1000; ++i) { /* 2.4 Gz: wait for download */
630 DELAY(40); /* 2.4 Gz */
631 if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and */
632 &(MMC_EECTRLstat_DWLD /* 2.4 Gz: EEBUSY */
633 +MMC_EECTRLstat_EEBUSY))==0) /* 2.4 Gz: */
634 break; /* 2.4 Gz: download finished */
636 if (i==1000) printf("wl: xmit pwr load failed\n"); /* 2.4 Gz */
637 MMC_WRITE(MMC_ANALCTRL, /* 2.4 Gz: EXT ant+polarity */
638 MMC_ANALCTRL_ANTPOL + /* 2.4 Gz: */
639 MMC_ANALCTRL_EXTANT); /* 2.4 Gz: */
640 i=sp->chan24<<4; /* 2.4 Gz: position ch # */
641 MMC_WRITE(MMC_EEADDR,i); /* 2.4 Gz: get frequency */
642 MMC_WRITE(MMC_EECTRL, /* 2.4 Gz: EEPROM read */
643 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: */
644 DELAY(40); /* 2.4 Gz */
645 i = wlmmcread(base,MMC_EEDATALrv) /* 2.4 Gz: freq val */
646 + (wlmmcread(base,MMC_EEDATAHrv)<<8); /* 2.4 Gz */
647 sp->freq24 = (i>>6)+2400; /* 2.4 Gz: save real freq */
654 * Another routine that interfaces the "if" layer to this driver.
655 * Simply resets the structures that are used by "upper layers".
656 * As well as calling wlhwrst that does reset the WaveLAN board.
658 * input : softc pointer for this interface
659 * output : structures (if structs) and board are reset
665 struct wl_softc *sc = xsc;
666 struct ifnet *ifp = &sc->wl_if;
671 if (sc->wl_if.if_flags & IFF_DEBUG)
672 printf("wl%d: entered wlinit()\n",sc->unit);
674 #if defined(__DragonFly__) || (defined(__FreeBSD__) && __FreeBSD_version >= 300000)
675 if (TAILQ_EMPTY(&ifp->if_addrhead)) {
677 if (ifp->if_addrlist == (struct ifaddr *)0) {
682 if ((stat = wlhwrst(sc->unit)) == TRUE) {
683 sc->wl_if.if_flags |= IFF_RUNNING; /* same as DSF_RUNNING */
685 * OACTIVE is used by upper-level routines
688 sc->wl_if.if_flags &= ~IFF_OACTIVE; /* same as tbusy below */
690 sc->flags |= DSF_RUNNING;
692 untimeout(wlwatchdog, sc, sc->watchdog_ch);
696 printf("wl%d init(): trouble resetting board.\n", sc->unit);
704 * This routine resets the WaveLAN board that corresponds to the
705 * board number passed in.
707 * input : board number to do a hardware reset
708 * output : board is reset
714 struct wl_softc *sc = WLSOFTC(unit);
717 if (sc->wl_if.if_flags & IFF_DEBUG)
718 printf("wl%d: entered wlhwrst()\n",unit);
720 sc->hacr = HACR_RESET;
721 CMD(unit); /* reset the board */
723 /* clear reset command and set PIO#1 in autoincrement mode */
724 sc->hacr = HACR_DEFAULT;
728 if (sc->wl_if.if_flags & IFF_DEBUG)
729 wlmmcstat(unit); /* Display MMC registers */
731 wlbldcu(unit); /* set up command unit structures */
733 if (wldiag(unit) == 0)
736 if (wlconfig(unit) == 0)
739 * insert code for loopback test here
741 wlrustrt(unit); /* start receive unit */
743 /* enable interrupts */
744 sc->hacr = (HACR_DEFAULT | HACR_INTRON);
753 * This function builds up the command unit structures. It inits
754 * the scp, iscp, scb, cb, tbd, and tbuf.
760 struct wl_softc *sc = WLSOFTC(unit);
761 short base = sc->base;
769 bzero(&scp, sizeof(scp));
771 scp.scp_iscp = OFFSET_ISCP;
772 scp.scp_iscp_base = 0;
773 outw(PIOR1(base), OFFSET_SCP);
774 outsw(PIOP1(base), &scp, sizeof(scp_t)/2);
776 bzero(&iscp, sizeof(iscp));
778 iscp.iscp_scb_offset = OFFSET_SCB;
780 iscp.iscp_scb_base = 0;
781 outw(PIOR1(base), OFFSET_ISCP);
782 outsw(PIOP1(base), &iscp, sizeof(iscp_t)/2);
785 scb.scb_command = SCB_RESET;
786 scb.scb_cbl_offset = OFFSET_CU;
787 scb.scb_rfa_offset = OFFSET_RU;
791 scb.scb_ovrnerrs = 0;
792 outw(PIOR1(base), OFFSET_SCB);
793 outsw(PIOP1(base), &scb, sizeof(scb_t)/2);
797 outw(PIOR0(base), OFFSET_ISCP + 0); /* address of iscp_busy */
798 for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
799 if (i <= 0) printf("wl%d bldcu(): iscp_busy timeout.\n", unit);
800 outw(PIOR0(base), OFFSET_SCB + 0); /* address of scb_status */
801 for (i = STATUS_TRIES; i-- > 0; ) {
802 if (inw(PIOP0(base)) == (SCB_SW_CX|SCB_SW_CNA))
806 printf("wl%d bldcu(): not ready after reset.\n", unit);
810 cb.ac_command = AC_CW_EL; /* NOP */
811 cb.ac_link_offset = OFFSET_CU;
812 outw(PIOR1(base), OFFSET_CU);
813 outsw(PIOP1(base), &cb, 6/2);
816 tbd.next_tbd_offset = I82586NULL;
819 outw(PIOR1(base), OFFSET_TBD);
820 outsw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
828 * input : board number
829 * output : stuff sent to board if any there
833 wlstart(struct ifnet *ifp)
835 int unit = ifp->if_dunit;
837 struct wl_softc *sc = WLSOFTC(unit);
838 short base = sc->base;
839 int scb_status, cu_status, scb_command;
842 if (sc->wl_if.if_flags & IFF_DEBUG)
843 printf("wl%d: entered wlstart()\n",unit);
846 outw(PIOR1(base), OFFSET_CU);
847 cu_status = inw(PIOP1(base));
848 outw(PIOR0(base),OFFSET_SCB + 0); /* scb_status */
849 scb_status = inw(PIOP0(base));
850 outw(PIOR0(base), OFFSET_SCB + 2);
851 scb_command = inw(PIOP0(base));
854 * don't need OACTIVE check as tbusy here checks to see
855 * if we are already busy
858 if((scb_status & 0x0700) == SCB_CUS_IDLE &&
859 (cu_status & AC_SW_B) == 0){
861 untimeout(wlwatchdog, sc, sc->watchdog_ch);
862 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
864 * This is probably just a race. The xmt'r is just
865 * became idle but WE have masked interrupts so ...
868 printf("wl%d: CU idle, scb %04x %04x cu %04x\n",
869 unit, scb_status, scb_command, cu_status);
871 if (xmt_watch) printf("!!");
873 return; /* genuinely still busy */
875 } else if((scb_status & 0x0700) == SCB_CUS_ACTV ||
876 (cu_status & AC_SW_B)){
878 printf("wl%d: CU unexpectedly busy; scb %04x cu %04x\n",
879 unit, scb_status, cu_status);
881 if (xmt_watch) printf("wl%d: busy?!",unit);
882 return; /* hey, why are we busy? */
885 /* get ourselves some data */
887 IF_DEQUEUE(&ifp->if_snd, m);
888 if (m != (struct mbuf *)0) {
889 /* let BPF see it before we commit it */
894 /* set the watchdog timer so that if the board
895 * fails to interrupt we will restart
897 /* try 10 ticks, not very long */
898 sc->watchdog_ch = timeout(wlwatchdog, sc, 10);
899 sc->wl_ac.ac_if.if_flags |= IFF_OACTIVE;
900 sc->wl_if.if_opackets++;
903 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
911 * This routine does the actual copy of data (including ethernet header
912 * structure) from the WaveLAN to an mbuf chain that will be passed up
913 * to the "if" (network interface) layer. NOTE: we currently
914 * don't handle trailer protocols, so if that is needed, it will
915 * (at least in part) be added here. For simplicities sake, this
916 * routine copies the receive buffers from the board into a local (stack)
917 * buffer until the frame has been copied from the board. Once in
918 * the local buffer, the contents are copied to an mbuf chain that
919 * is then enqueued onto the appropriate "if" queue.
921 * input : board number, and an frame descriptor address
922 * output : the packet is put into an mbuf chain, and passed up
923 * assumes : if any errors occur, packet is "dropped on the floor"
927 wlread(int unit, u_short fd_p)
929 struct wl_softc *sc = WLSOFTC(unit);
930 struct ifnet *ifp = &sc->wl_if;
931 short base = sc->base;
933 struct ether_header eh;
937 u_short mlen, len, clen;
938 u_short bytes_in_msg, bytes_in_mbuf, bytes;
942 if (sc->wl_if.if_flags & IFF_DEBUG)
943 printf("wl%d: entered wlread()\n",unit);
945 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
946 printf("%s read(): board is not running.\n", ifp->if_xname);
947 sc->hacr &= ~HACR_INTRON;
948 CMD(unit); /* turn off interrupts */
950 /* read ether_header info out of device memory. doesn't
951 * go into mbuf. goes directly into eh structure
953 len = sizeof(struct ether_header); /* 14 bytes */
954 outw(PIOR1(base), fd_p);
955 insw(PIOP1(base), &fd, (sizeof(fd_t) - len)/2);
956 insw(PIOP1(base), &eh, (len-2)/2);
957 eh.ether_type = ntohs(inw(PIOP1(base)));
959 if (sc->wl_if.if_flags & IFF_DEBUG) {
960 printf("wlread: rcv packet, type is %x\n", eh.ether_type);
964 * WARNING. above is done now in ether_input, above may be
965 * useful for debug. jrb
967 eh.ether_type = htons(eh.ether_type);
969 if (fd.rbd_offset == I82586NULL) {
970 printf("wl%d read(): Invalid buffer\n", unit);
971 if (wlhwrst(unit) != TRUE) {
972 printf("wl%d read(): hwrst trouble.\n", unit);
977 outw(PIOR1(base), fd.rbd_offset);
978 insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
979 bytes_in_msg = rbd.status & RBD_SW_COUNT;
980 MGETHDR(m, MB_DONTWAIT, MT_DATA);
982 if (m == (struct mbuf *)0) {
984 * not only do we want to return, we need to drop the packet on
985 * the floor to clear the interrupt.
988 if (wlhwrst(unit) != TRUE) {
989 sc->hacr &= ~HACR_INTRON;
990 CMD(unit); /* turn off interrupts */
991 printf("wl%d read(): hwrst trouble.\n", unit);
995 m->m_next = (struct mbuf *) 0;
996 m->m_pkthdr.rcvif = ifp;
997 m->m_pkthdr.len = 0; /* don't know this yet */
1000 /* always use a cluster. jrb
1002 MCLGET(m, MB_DONTWAIT);
1003 if (m->m_flags & M_EXT) {
1004 m->m_len = MCLBYTES;
1008 if (wlhwrst(unit) != TRUE) {
1009 sc->hacr &= ~HACR_INTRON;
1010 CMD(unit); /* turn off interrupts */
1011 printf("wl%d read(): hwrst trouble.\n", unit);
1018 bytes_in_mbuf = m->m_len;
1019 mb_p = mtod(tm, u_char *);
1020 bytes = min(bytes_in_mbuf, bytes_in_msg);
1027 outw(PIOR1(base), rbd.buffer_addr);
1028 insw(PIOP1(base), mb_p, len/2);
1032 if (!(bytes_in_mbuf -= bytes)) {
1033 MGET(tm->m_next, MB_DONTWAIT, MT_DATA);
1035 if (tm == (struct mbuf *)0) {
1037 printf("wl%d read(): No mbuf nth\n", unit);
1038 if (wlhwrst(unit) != TRUE) {
1039 sc->hacr &= ~HACR_INTRON;
1040 CMD(unit); /* turn off interrupts */
1041 printf("wl%d read(): hwrst trouble.\n", unit);
1047 bytes_in_mbuf = MLEN;
1048 mb_p = mtod(tm, u_char *);
1053 if (!(bytes_in_msg -= bytes)) {
1054 if (rbd.status & RBD_SW_EOF ||
1055 rbd.next_rbd_offset == I82586NULL) {
1059 outw(PIOR1(base), rbd.next_rbd_offset);
1060 insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1061 bytes_in_msg = rbd.status & RBD_SW_COUNT;
1064 rbd.buffer_addr += bytes;
1067 bytes = min(bytes_in_mbuf, bytes_in_msg);
1070 m->m_pkthdr.len = clen;
1073 * If hw is in promiscuous mode (note that I said hardware, not if
1074 * IFF_PROMISC is set in ifnet flags), then if this is a unicast
1075 * packet and the MAC dst is not us, drop it. This check in normally
1076 * inside ether_input(), but IFF_MULTI causes hw promisc without
1077 * a bpf listener, so this is wrong.
1078 * Greg Troxel <gdt@ir.bbn.com>, 1998-08-07
1081 * TBD: also discard packets where NWID does not match.
1082 * However, there does not appear to be a way to read the nwid
1083 * for a received packet. -gdt 1998-08-07
1086 #ifdef WL_USE_IFNET_PROMISC_CHECK /* not defined */
1087 (sc->wl_ac.ac_if.if_flags & (IFF_PROMISC|IFF_ALLMULTI))
1089 /* hw is in promisc mode if this is true */
1090 (sc->mode & (MOD_PROM | MOD_ENAL))
1093 (eh.ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
1094 bcmp(eh.ether_dhost, sc->wl_ac.ac_enaddr,
1095 sizeof(eh.ether_dhost)) != 0 ) {
1101 if (sc->wl_if.if_flags & IFF_DEBUG)
1102 printf("wl%d: wlrecv %d bytes\n", unit, clen);
1106 wl_cache_store(unit, base, &eh, m);
1110 * received packet is now in a chain of mbuf's. next step is
1111 * to pass the packet upwards.
1114 ether_input(&sc->wl_if, &eh, m);
1121 * This routine processes an ioctl request from the "if" layer
1124 * input : pointer the appropriate "if" struct, command, and data
1125 * output : based on command appropriate action is taken on the
1126 * WaveLAN board(s) or related structures
1127 * return : error is returned containing exit conditions
1131 wlioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cred)
1133 struct ifreq *ifr = (struct ifreq *)data;
1134 int unit = ifp->if_dunit;
1135 struct wl_softc *sc = WLSOFTC(unit);
1136 short base = sc->base;
1138 int opri, error = 0;
1139 int irq, irqval, i, isroot, size;
1142 struct thread *td = curthread; /* XXX */
1146 if (sc->wl_if.if_flags & IFF_DEBUG)
1147 printf("wl%d: entered wlioctl()\n",unit);
1154 error = ether_ioctl(ifp, cmd, data);
1158 if (ifp->if_flags & IFF_ALLMULTI) {
1161 if (ifp->if_flags & IFF_PROMISC) {
1164 if(ifp->if_flags & IFF_LINK0) {
1168 * force a complete reset if the recieve multicast/
1169 * promiscuous mode changes so that these take
1170 * effect immediately.
1173 if (sc->mode != mode) {
1175 if (sc->flags & DSF_RUNNING) {
1176 sc->flags &= ~DSF_RUNNING;
1180 /* if interface is marked DOWN and still running then
1183 if ((ifp->if_flags & IFF_UP) == 0 && sc->flags & DSF_RUNNING) {
1184 printf("wl%d ioctl(): board is not running\n", unit);
1185 sc->flags &= ~DSF_RUNNING;
1186 sc->hacr &= ~HACR_INTRON;
1187 CMD(unit); /* turn off interrupts */
1189 /* else if interface is UP and RUNNING, start it
1191 else if (ifp->if_flags & IFF_UP && (sc->flags & DSF_RUNNING) == 0) {
1195 /* if WLDEBUG set on interface, then printf rf-modem regs
1197 if(ifp->if_flags & IFF_DEBUG)
1204 #if defined(__FreeBSD__) && __FreeBSD_version < 300000
1205 if (cmd == SIOCADDMULTI) {
1206 error = ether_addmulti(ifr, &sc->wl_ac);
1209 error = ether_delmulti(ifr, &sc->wl_ac);
1212 /* see if we should be in all multicast mode
1213 * note that 82586 cannot do that, must simulate with
1216 if ( check_allmulti(unit)) {
1217 ifp->if_flags |= IFF_ALLMULTI;
1218 sc->mode |= MOD_ENAL;
1219 sc->flags &= ~DSF_RUNNING;
1225 if (error == ENETRESET) {
1226 if(sc->flags & DSF_RUNNING) {
1227 sc->flags &= ~DSF_RUNNING;
1236 #endif /* MULTICAST */
1238 /* DEVICE SPECIFIC */
1241 /* copy the PSA out to the caller */
1243 /* pointer to buffer in user space */
1244 up = (void *)ifr->ifr_data;
1245 /* work out if they're root */
1246 isroot = (suser(td) == 0);
1248 for (i = 0; i < 0x40; i++) {
1249 /* don't hand the DES key out to non-root users */
1250 if ((i > WLPSA_DESKEY) && (i < (WLPSA_DESKEY + 8)) && !isroot)
1252 if (subyte((up + i), sc->psa[i]))
1258 /* copy the PSA in from the caller; we only copy _some_ values */
1261 if ((error = suser(td)))
1263 error = EINVAL; /* assume the worst */
1264 /* pointer to buffer in user space containing data */
1265 up = (void *)ifr->ifr_data;
1267 /* check validity of input range */
1268 for (i = 0; i < 0x40; i++)
1269 if (fubyte(up + i) < 0)
1272 /* check IRQ value */
1273 irqval = fubyte(up+WLPSA_IRQNO);
1274 for (irq = 15; irq >= 0; irq--)
1275 if(irqvals[irq] == irqval)
1277 if (irq == 0) /* oops */
1280 sc->psa[WLPSA_IRQNO] = irqval;
1283 for (i = 0; i < 6; i++)
1284 sc->psa[WLPSA_LOCALMAC+i] = fubyte(up+WLPSA_LOCALMAC+i);
1287 sc->psa[WLPSA_MACSEL] = fubyte(up+WLPSA_MACSEL);
1290 sc->psa[WLPSA_NWID] = fubyte(up+WLPSA_NWID);
1291 sc->psa[WLPSA_NWID+1] = fubyte(up+WLPSA_NWID+1);
1294 wlsetpsa(unit); /* update the PSA */
1298 /* get the current NWID out of the sc since we stored it there */
1300 ifr->ifr_data = (caddr_t) (sc->nwid[0] << 8 | sc->nwid[1]);
1305 * change the nwid dynamically. This
1306 * ONLY changes the radio modem and does not
1310 * 1. save in softc "soft registers"
1311 * 2. save in radio modem (MMC)
1315 if ((error = suser(td)))
1317 if (!(ifp->if_flags & IFF_UP)) {
1318 error = EIO; /* only allowed while up */
1321 * soft c nwid shadows radio modem setting
1323 sc->nwid[0] = (int)ifr->ifr_data >> 8;
1324 sc->nwid[1] = (int)ifr->ifr_data & 0xff;
1325 MMC_WRITE(MMC_NETW_ID_L,sc->nwid[1]);
1326 MMC_WRITE(MMC_NETW_ID_H,sc->nwid[0]);
1330 /* copy the EEPROM in 2.4 Gz WaveMODEM out to the caller */
1333 if ((error = suser(td)))
1335 /* pointer to buffer in user space */
1336 up = (void *)ifr->ifr_data;
1338 for (i=0x00; i<0x80; ++i) { /* 2.4 Gz: size of EEPROM */
1339 MMC_WRITE(MMC_EEADDR,i); /* 2.4 Gz: get frequency */
1340 MMC_WRITE(MMC_EECTRL, /* 2.4 Gz: EEPROM read */
1341 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: */
1342 DELAY(40); /* 2.4 Gz */
1343 if (subyte(up + 2*i , /* 2.4 Gz: pass low byte of */
1344 wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word */
1345 ) return(EFAULT); /* 2.4 Gz: */
1346 if (subyte(up + 2*i+1, /* 2.4 Gz: pass hi byte of */
1347 wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word */
1348 ) return(EFAULT); /* 2.4 Gz: */
1353 /* zero (Delete) the wl cache */
1356 if ((error = suser(td)))
1358 wl_cache_zero(unit);
1361 /* read out the number of used cache elements */
1363 ifr->ifr_data = (caddr_t) sc->w_sigitems;
1366 /* read out the wl cache */
1368 /* pointer to buffer in user space */
1369 up = (void *)ifr->ifr_data;
1370 cpt = (char *) &sc->w_sigcache[0];
1371 size = sc->w_sigitems * sizeof(struct w_sigcache);
1373 for (i = 0; i < size; i++) {
1374 if (subyte((up + i), *cpt++))
1390 * Called if the timer set in wlstart expires before an interrupt is received
1391 * from the wavelan. It seems to lose interrupts sometimes.
1392 * The watchdog routine gets called if the transmitter failed to interrupt
1394 * input : which board is timing out
1395 * output : board reset
1399 wlwatchdog(void *vsc)
1401 struct wl_softc *sc = vsc;
1402 int unit = sc->unit;
1404 log(LOG_ERR, "wl%d: wavelan device timeout on xmit\n", unit);
1405 sc->wl_ac.ac_if.if_oerrors++;
1412 * This function is the interrupt handler for the WaveLAN
1413 * board. This routine will be called whenever either a packet
1414 * is received, or a packet has successfully been transfered and
1415 * the unit is ready to transmit another packet.
1417 * input : board number that interrupted
1418 * output : either a packet is received, or a packet is transfered
1425 struct wl_softc *sc = &wl_softc[unit];
1426 short base = sc->base;
1428 u_short int_type, int_type1;
1431 if (sc->wl_if.if_flags & IFF_DEBUG)
1432 printf("wl%d: wlintr() called\n",unit);
1435 if((int_type = inw(HASR(base))) & HASR_MMC_INTR) {
1436 /* handle interrupt from the modem management controler */
1437 /* This will clear the interrupt condition */
1438 (void) wlmmcread(base,MMC_DCE_STATUS); /* ignored for now */
1441 if(!(int_type & HASR_INTR)){ /* return if no interrupt from 82586 */
1442 /* commented out. jrb. it happens when reinit occurs
1443 printf("wlintr: int_type %x, dump follows\n", int_type);
1452 outw(PIOR0(base), OFFSET_SCB + 0); /* get scb status */
1453 int_type = (inw(PIOP0(base)) & SCB_SW_INT);
1454 if (int_type == 0) /* no interrupts left */
1457 int_type1 = wlack(unit); /* acknowledge interrupt(s) */
1458 /* make sure no bits disappeared (others may appear) */
1459 if ((int_type & int_type1) != int_type)
1460 printf("wlack() int bits disappeared : %04x != int_type %04x\n",
1461 int_type1, int_type);
1462 int_type = int_type1; /* go with the new status */
1466 if (int_type & SCB_SW_FR) {
1467 sc->wl_if.if_ipackets++;
1471 * receiver not ready
1473 if (int_type & SCB_SW_RNR) {
1474 sc->wl_if.if_ierrors++;
1476 if (sc->wl_if.if_flags & IFF_DEBUG)
1477 printf("wl%d intr(): receiver overrun! begin_fd = %x\n",
1478 unit, sc->begin_fd);
1485 if (int_type & SCB_SW_CNA) {
1487 * At present, we don't care about CNA's. We
1488 * believe they are a side effect of XMT.
1491 if (int_type & SCB_SW_CX) {
1493 * At present, we only request Interrupt for
1496 outw(PIOR1(base), OFFSET_CU); /* get command status */
1497 ac_status = inw(PIOP1(base));
1499 if (xmt_watch) { /* report some anomalies */
1501 if (sc->tbusy == 0) {
1502 printf("wl%d: xmt intr but not busy, CU %04x\n",
1505 if (ac_status == 0) {
1506 printf("wl%d: xmt intr but ac_status == 0\n", unit);
1508 if (ac_status & AC_SW_A) {
1509 printf("wl%d: xmt aborted\n",unit);
1512 if (ac_status & TC_CARRIER) {
1513 printf("wl%d: no carrier\n", unit);
1516 if (ac_status & TC_CLS) {
1517 printf("wl%d: no CTS\n", unit);
1519 if (ac_status & TC_DMA) {
1520 printf("wl%d: DMA underrun\n", unit);
1522 if (ac_status & TC_DEFER) {
1523 printf("wl%d: xmt deferred\n",unit);
1525 if (ac_status & TC_SQE) {
1526 printf("wl%d: heart beat\n", unit);
1528 if (ac_status & TC_COLLISION) {
1529 printf("wl%d: too many collisions\n", unit);
1532 /* if the transmit actually failed, or returned some status */
1533 if ((!(ac_status & AC_SW_OK)) || (ac_status & 0xfff)) {
1534 if (ac_status & (TC_COLLISION | TC_CLS | TC_DMA)) {
1535 sc->wl_if.if_oerrors++;
1537 /* count collisions */
1538 sc->wl_if.if_collisions += (ac_status & 0xf);
1539 /* if TC_COLLISION set and collision count zero, 16 collisions */
1540 if ((ac_status & 0x20) == 0x20) {
1541 sc->wl_if.if_collisions += 0x10;
1545 untimeout(wlwatchdog, sc, sc->watchdog_ch);
1546 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
1547 wlstart(&(sc->wl_if));
1556 * This routine is called by the interrupt handler to initiate a
1557 * packet transfer from the board to the "if" layer above this
1558 * driver. This routine checks if a buffer has been successfully
1559 * received by the WaveLAN. If so, the routine wlread is called
1560 * to do the actual transfer of the board data (including the
1561 * ethernet header) into a packet (consisting of an mbuf chain).
1563 * input : number of the board to check
1564 * output : if a packet is available, it is "sent up"
1570 struct wl_softc *sc = WLSOFTC(unit);
1571 short base = sc->base;
1572 u_short fd_p, status, offset, link_offset;
1575 if (sc->wl_if.if_flags & IFF_DEBUG)
1576 printf("wl%d: entered wlrcv()\n",unit);
1578 for (fd_p = sc->begin_fd; fd_p != I82586NULL; fd_p = sc->begin_fd) {
1580 outw(PIOR0(base), fd_p + 0); /* address of status */
1581 status = inw(PIOP0(base));
1582 outw(PIOR1(base), fd_p + 4); /* address of link_offset */
1583 link_offset = inw(PIOP1(base));
1584 offset = inw(PIOP1(base)); /* rbd_offset */
1585 if (status == 0xffff || offset == 0xffff /*I82586NULL*/) {
1586 if (wlhwrst(unit) != TRUE)
1587 printf("wl%d rcv(): hwrst ffff trouble.\n", unit);
1589 } else if (status & AC_SW_C) {
1590 if (status == (RFD_DONE|RFD_RSC)) {
1593 if (sc->wl_if.if_flags & IFF_DEBUG)
1594 printf("wl%d RCV: RSC %x\n", unit, status);
1596 sc->wl_if.if_ierrors++;
1597 } else if (!(status & RFD_OK)) {
1598 printf("wl%d RCV: !OK %x\n", unit, status);
1599 sc->wl_if.if_ierrors++;
1600 } else if (status & 0xfff) { /* can't happen */
1601 printf("wl%d RCV: ERRs %x\n", unit, status);
1602 sc->wl_if.if_ierrors++;
1603 } else if (!wlread(unit, fd_p))
1606 if (!wlrequeue(unit, fd_p)) {
1607 /* abort on chain error */
1608 if (wlhwrst(unit) != TRUE)
1609 printf("wl%d rcv(): hwrst trouble.\n", unit);
1612 sc->begin_fd = link_offset;
1623 * This routine puts rbd's used in the last receive back onto the
1624 * free list for the next receive.
1628 wlrequeue(int unit, u_short fd_p)
1630 struct wl_softc *sc = WLSOFTC(unit);
1631 short base = sc->base;
1633 u_short l_rbdp, f_rbdp, rbd_offset;
1635 outw(PIOR0(base), fd_p + 6);
1636 rbd_offset = inw(PIOP0(base));
1637 if ((f_rbdp = rbd_offset) != I82586NULL) {
1640 outw(PIOR0(base), l_rbdp + 0); /* address of status */
1641 if(inw(PIOP0(base)) & RBD_SW_EOF)
1643 outw(PIOP0(base), 0);
1644 outw(PIOR0(base), l_rbdp + 2); /* next_rbd_offset */
1645 if((l_rbdp = inw(PIOP0(base))) == I82586NULL)
1648 outw(PIOP0(base), 0);
1649 outw(PIOR0(base), l_rbdp + 2); /* next_rbd_offset */
1650 outw(PIOP0(base), I82586NULL);
1651 outw(PIOR0(base), l_rbdp + 8); /* address of size */
1652 outw(PIOP0(base), inw(PIOP0(base)) | AC_CW_EL);
1653 outw(PIOR0(base), sc->end_rbd + 2);
1654 outw(PIOP0(base), f_rbdp); /* end_rbd->next_rbd_offset */
1655 outw(PIOR0(base), sc->end_rbd + 8); /* size */
1656 outw(PIOP0(base), inw(PIOP0(base)) & ~AC_CW_EL);
1657 sc->end_rbd = l_rbdp;
1661 fd.command = AC_CW_EL;
1662 fd.link_offset = I82586NULL;
1663 fd.rbd_offset = I82586NULL;
1664 outw(PIOR1(base), fd_p);
1665 outsw(PIOP1(base), &fd, 8/2);
1667 outw(PIOR1(base), sc->end_fd + 2); /* addr of command */
1668 outw(PIOP1(base), 0); /* command = 0 */
1669 outw(PIOP1(base), fd_p); /* end_fd->link_offset = fd_p */
1676 static int xmt_debug = 0;
1677 #endif /* WLDEBUG */
1682 * This routine fills in the appropriate registers and memory
1683 * locations on the WaveLAN board and starts the board off on
1686 * input : board number of interest, and a pointer to the mbuf
1687 * output : board memory and registers are set for xfer and attention
1691 wlxmt(int unit, struct mbuf *m)
1693 struct wl_softc *sc = WLSOFTC(unit);
1694 u_short xmtdata_p = OFFSET_TBUF;
1696 struct mbuf *tm_p = m;
1697 struct ether_header *eh_p = mtod(m, struct ether_header *);
1698 u_char *mb_p = mtod(m, u_char *) + sizeof(struct ether_header);
1699 u_short count = m->m_len - sizeof(struct ether_header);
1701 u_short tbd_p = OFFSET_TBD;
1702 u_short len, clen = 0;
1703 short base = sc->base;
1707 if (sc->wl_if.if_flags & IFF_DEBUG)
1708 printf("wl%d: entered wlxmt()\n",unit);
1712 cb.ac_command = (AC_CW_EL|AC_TRANSMIT|AC_CW_I);
1713 cb.ac_link_offset = I82586NULL;
1714 outw(PIOR1(base), OFFSET_CU);
1715 outsw(PIOP1(base), &cb, 6/2);
1716 outw(PIOP1(base), OFFSET_TBD); /* cb.cmd.transmit.tbd_offset */
1717 outsw(PIOP1(base), eh_p->ether_dhost, WAVELAN_ADDR_SIZE/2);
1718 outw(PIOP1(base), eh_p->ether_type);
1721 if (sc->wl_if.if_flags & IFF_DEBUG) {
1723 printf("XMT mbuf: L%d @%p ", count, (void *)mb_p);
1724 printf("ether type %x\n", eh_p->ether_type);
1727 #endif /* WLDEBUG */
1728 outw(PIOR0(base), OFFSET_TBD);
1729 outw(PIOP0(base), 0); /* act_count */
1730 outw(PIOR1(base), OFFSET_TBD + 4);
1731 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1732 outw(PIOP1(base), 0); /* buffer_base */
1735 if (clen + count > WAVELAN_MTU)
1741 outw(PIOR1(base), xmtdata_p);
1742 outsw(PIOP1(base), mb_p, len/2);
1744 outw(PIOR0(base), tbd_p); /* address of act_count */
1745 outw(PIOP0(base), inw(PIOP0(base)) + count);
1747 if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1750 /* go to the next descriptor */
1751 outw(PIOR0(base), tbd_p + 2);
1752 tbd_p += sizeof (tbd_t);
1753 outw(PIOP0(base), tbd_p); /* next_tbd_offset */
1754 outw(PIOR0(base), tbd_p);
1755 outw(PIOP0(base), 0); /* act_count */
1756 outw(PIOR1(base), tbd_p + 4);
1757 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1758 outw(PIOP1(base), 0); /* buffer_base */
1759 /* at the end -> coallesce remaining mbufs */
1760 if (tbd_p == OFFSET_TBD + (N_TBD-1) * sizeof (tbd_t)) {
1761 wlsftwsleaze(&count, &mb_p, &tm_p, unit);
1764 /* next mbuf short -> coallesce as needed */
1765 if ( (tm_p->m_next == (struct mbuf *) 0) ||
1766 #define HDW_THRESHOLD 55
1767 tm_p->m_len > HDW_THRESHOLD)
1770 wlhdwsleaze(&count, &mb_p, &tm_p, unit);
1774 } else if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1776 count = tm_p->m_len;
1777 mb_p = mtod(tm_p, u_char *);
1779 if (sc->wl_if.if_flags & IFF_DEBUG)
1781 printf("mbuf+ L%d @%p ", count, (void *)mb_p);
1782 #endif /* WLDEBUG */
1785 if (sc->wl_if.if_flags & IFF_DEBUG)
1787 printf("CLEN = %d\n", clen);
1788 #endif /* WLDEBUG */
1789 outw(PIOR0(base), tbd_p);
1790 if (clen < ETHERMIN) {
1791 outw(PIOP0(base), inw(PIOP0(base)) + ETHERMIN - clen);
1792 outw(PIOR1(base), xmtdata_p);
1793 for (xmtshort_p = xmtdata_p; clen < ETHERMIN; clen += 2)
1794 outw(PIOP1(base), 0);
1796 outw(PIOP0(base), inw(PIOP0(base)) | TBD_SW_EOF);
1797 outw(PIOR0(base), tbd_p + 2);
1798 outw(PIOP0(base), I82586NULL);
1800 if (sc->wl_if.if_flags & IFF_DEBUG) {
1806 #endif /* WLDEBUG */
1808 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
1810 * wait for 586 to clear previous command, complain if it takes
1813 for (spin = 1;;spin = (spin + 1) % 10000) {
1814 if (inw(PIOP0(base)) == 0) { /* it's done, we can go */
1817 if ((spin == 0) && xmt_watch) { /* not waking up, and we care */
1818 printf("wl%d: slow accepting xmit\n",unit);
1821 outw(PIOP0(base), SCB_CU_STRT); /* new command */
1822 SET_CHAN_ATTN(unit);
1827 * Pause to avoid transmit overrun problems.
1828 * The required delay tends to vary with platform type, and may be
1829 * related to interrupt loss.
1831 if (wl_xmit_delay) {
1832 DELAY(wl_xmit_delay);
1840 * This function builds the linear linked lists of fd's and
1841 * rbd's. Based on page 4-32 of 1986 Intel microcom handbook.
1847 struct wl_softc *sc = WLSOFTC(unit);
1848 short base = sc->base;
1851 u_short fd_p = OFFSET_RU;
1852 u_short rbd_p = OFFSET_RBD;
1855 sc->begin_fd = fd_p;
1856 for(i = 0; i < N_FD; i++) {
1859 fd.link_offset = fd_p + sizeof(fd_t);
1860 fd.rbd_offset = I82586NULL;
1861 outw(PIOR1(base), fd_p);
1862 outsw(PIOP1(base), &fd, 8/2);
1863 fd_p = fd.link_offset;
1865 fd_p -= sizeof(fd_t);
1867 outw(PIOR1(base), fd_p + 2);
1868 outw(PIOP1(base), AC_CW_EL); /* command */
1869 outw(PIOP1(base), I82586NULL); /* link_offset */
1872 outw(PIOR0(base), fd_p + 6); /* address of rbd_offset */
1873 outw(PIOP0(base), rbd_p);
1874 outw(PIOR1(base), rbd_p);
1875 for(i = 0; i < N_RBD; i++) {
1877 rbd.buffer_addr = rbd_p + sizeof(rbd_t) + 2;
1878 rbd.buffer_base = 0;
1879 rbd.size = RCVBUFSIZE;
1881 rbd_p += sizeof(ru_t);
1882 rbd.next_rbd_offset = rbd_p;
1884 rbd.next_rbd_offset = I82586NULL;
1885 rbd.size |= AC_CW_EL;
1886 sc->end_rbd = rbd_p;
1888 outsw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1889 outw(PIOR1(base), rbd_p);
1891 return sc->begin_fd;
1897 * This routine starts the receive unit running. First checks if the
1898 * board is actually ready, then the board is instructed to receive
1905 struct wl_softc *sc = WLSOFTC(unit);
1906 short base = sc->base;
1910 if (sc->wl_if.if_flags & IFF_DEBUG)
1911 printf("wl%d: entered wlrustrt()\n",unit);
1913 outw(PIOR0(base), OFFSET_SCB);
1914 if (inw(PIOP0(base)) & SCB_RUS_READY){
1915 printf("wlrustrt: RUS_READY\n");
1919 outw(PIOR0(base), OFFSET_SCB + 2);
1920 outw(PIOP0(base), SCB_RU_STRT); /* command */
1921 rfa = wlbldru(unit);
1922 outw(PIOR0(base), OFFSET_SCB + 6); /* address of scb_rfa_offset */
1923 outw(PIOP0(base), rfa);
1925 SET_CHAN_ATTN(unit);
1932 * This routine does a 586 op-code number 7, and obtains the
1933 * diagnose status for the WaveLAN.
1939 struct wl_softc *sc = WLSOFTC(unit);
1940 short base = sc->base;
1944 if (sc->wl_if.if_flags & IFF_DEBUG)
1945 printf("wl%d: entered wldiag()\n",unit);
1947 outw(PIOR0(base), OFFSET_SCB);
1948 status = inw(PIOP0(base));
1949 if (status & SCB_SW_INT) {
1950 /* state is 2000 which seems ok
1951 printf("wl%d diag(): unexpected initial state %\n",
1952 unit, inw(PIOP0(base)));
1956 outw(PIOR1(base), OFFSET_CU);
1957 outw(PIOP1(base), 0); /* ac_status */
1958 outw(PIOP1(base), AC_DIAGNOSE|AC_CW_EL);/* ac_command */
1959 if(wlcmd(unit, "diag()") == 0)
1961 outw(PIOR0(base), OFFSET_CU);
1962 if (inw(PIOP0(base)) & 0x0800) {
1963 printf("wl%d: i82586 Self Test failed!\n", unit);
1972 * This routine does a standard config of the WaveLAN board.
1978 configure_t configure;
1979 struct wl_softc *sc = WLSOFTC(unit);
1980 short base = sc->base;
1983 #if defined(__DragonFly__) || (defined(__FreeBSD__) && __FreeBSD_version >= 300000)
1984 struct ifmultiaddr *ifma;
1987 struct ether_multi *enm;
1988 struct ether_multistep step;
1991 #endif /* MULTICAST */
1994 if (sc->wl_if.if_flags & IFF_DEBUG)
1995 printf("wl%d: entered wlconfig()\n",unit);
1997 outw(PIOR0(base), OFFSET_SCB);
1998 if (inw(PIOP0(base)) & SCB_SW_INT) {
2000 printf("wl%d config(): unexpected initial state %x\n",
2001 unit, inw(PIOP0(base)));
2006 outw(PIOR1(base), OFFSET_CU);
2007 outw(PIOP1(base), 0); /* ac_status */
2008 outw(PIOP1(base), AC_CONFIGURE|AC_CW_EL); /* ac_command */
2011 configure.fifolim_bytecnt = 0x080c;
2012 configure.addrlen_mode = 0x0600;
2013 configure.linprio_interframe = 0x2060;
2014 configure.slot_time = 0xf200;
2015 configure.hardware = 0x0008; /* tx even w/o CD */
2016 configure.min_frame_len = 0x0040;
2018 /* This is the configuration block suggested by Marc Meertens
2019 * <mmeerten@obelix.utrecht.NCR.COM> in an e-mail message to John
2020 * Ioannidis on 10 Nov 92.
2022 configure.fifolim_bytecnt = 0x040c;
2023 configure.addrlen_mode = 0x0600;
2024 configure.linprio_interframe = 0x2060;
2025 configure.slot_time = 0xf000;
2026 configure.hardware = 0x0008; /* tx even w/o CD */
2027 configure.min_frame_len = 0x0040;
2030 * below is the default board configuration from p2-28 from 586 book
2032 configure.fifolim_bytecnt = 0x080c;
2033 configure.addrlen_mode = 0x2600;
2034 configure.linprio_interframe = 0x7820; /* IFS=120, ACS=2 */
2035 configure.slot_time = 0xf00c; /* slottime=12 */
2036 configure.hardware = 0x0008; /* tx even w/o CD */
2037 configure.min_frame_len = 0x0040;
2039 if(sc->mode & (MOD_PROM | MOD_ENAL)) {
2040 configure.hardware |= 1;
2042 outw(PIOR1(base), OFFSET_CU + 6);
2043 outsw(PIOP1(base), &configure, sizeof(configure_t)/2);
2045 if(wlcmd(unit, "config()-configure") == 0)
2048 outw(PIOR1(base), OFFSET_CU);
2049 outw(PIOP1(base), 0); /* ac_status */
2050 outw(PIOP1(base), AC_MCSETUP|AC_CW_EL); /* ac_command */
2051 outw(PIOR1(base), OFFSET_CU + 8);
2052 #if defined(__DragonFly__) || (defined(__FreeBSD__) && __FreeBSD_version >= 300000)
2053 for (ifma = sc->wl_if.if_multiaddrs.lh_first; ifma;
2054 ifma = ifma->ifma_link.le_next) {
2055 if (ifma->ifma_addr->sa_family != AF_LINK)
2058 addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
2059 outw(PIOP1(base), addrp[0] + (addrp[1] << 8));
2060 outw(PIOP1(base), addrp[2] + (addrp[3] << 8));
2061 outw(PIOP1(base), addrp[4] + (addrp[5] << 8));
2065 ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2066 while (enm != NULL) {
2067 unsigned int lo, hi;
2068 /* break if setting a multicast range, else we would crash */
2069 if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2072 lo = (enm->enm_addrlo[3] << 16) + (enm->enm_addrlo[4] << 8)
2073 + enm->enm_addrlo[5];
2074 hi = (enm->enm_addrhi[3] << 16) + (enm->enm_addrhi[4] << 8)
2075 + enm->enm_addrhi[5];
2077 outw(PIOP1(base),enm->enm_addrlo[0] +
2078 (enm->enm_addrlo[1] << 8));
2079 outw(PIOP1(base),enm->enm_addrlo[2] +
2080 ((lo >> 8) & 0xff00));
2081 outw(PIOP1(base), ((lo >> 8) & 0xff) +
2082 ((lo << 8) & 0xff00));
2083 /* #define MCASTDEBUG */
2085 printf("mcast_addr[%d,%d,%d] %x %x %x %x %x %x\n", lo, hi, cnt,
2091 enm->enm_addrlo[5]);
2096 ETHER_NEXT_MULTI(step, enm);
2099 outw(PIOR1(base), OFFSET_CU + 6); /* mc-cnt */
2100 outw(PIOP1(base), cnt * WAVELAN_ADDR_SIZE);
2101 if(wlcmd(unit, "config()-mcaddress") == 0)
2103 #endif /* MULTICAST */
2105 outw(PIOR1(base), OFFSET_CU);
2106 outw(PIOP1(base), 0); /* ac_status */
2107 outw(PIOP1(base), AC_IASETUP|AC_CW_EL); /* ac_command */
2108 outw(PIOR1(base), OFFSET_CU + 6);
2109 outsw(PIOP1(base), sc->wl_addr, WAVELAN_ADDR_SIZE/2);
2111 if(wlcmd(unit, "config()-address") == 0)
2122 * Set channel attention bit and busy wait until command has
2123 * completed. Then acknowledge the command completion.
2126 wlcmd(int unit, char *str)
2128 struct wl_softc *sc = WLSOFTC(unit);
2129 short base = sc->base;
2132 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
2133 outw(PIOP0(base), SCB_CU_STRT);
2135 SET_CHAN_ATTN(unit);
2137 outw(PIOR0(base), OFFSET_CU);
2138 for(i = 0; i < 0xffff; i++)
2139 if (inw(PIOP0(base)) & AC_SW_C)
2141 if (i == 0xffff || !(inw(PIOP0(base)) & AC_SW_OK)) {
2142 printf("wl%d: %s failed; status = %d, inw = %x, outw = %x\n",
2143 unit, str, inw(PIOP0(base)) & AC_SW_OK, inw(PIOP0(base)), inw(PIOR0(base)));
2144 outw(PIOR0(base), OFFSET_SCB);
2145 printf("scb_status %x\n", inw(PIOP0(base)));
2146 outw(PIOR0(base), OFFSET_SCB+2);
2147 printf("scb_command %x\n", inw(PIOP0(base)));
2148 outw(PIOR0(base), OFFSET_SCB+4);
2149 printf("scb_cbl %x\n", inw(PIOP0(base)));
2150 outw(PIOR0(base), OFFSET_CU+2);
2151 printf("cu_cmd %x\n", inw(PIOP0(base)));
2155 outw(PIOR0(base), OFFSET_SCB);
2156 if ((inw(PIOP0(base)) & SCB_SW_INT) && (inw(PIOP0(base)) != SCB_SW_CNA)) {
2158 printf("wl%d %s: unexpected final state %x\n",
2159 unit, str, inw(PIOP0(base)));
2167 * wlack: if the 82596 wants attention because it has finished
2168 * sending or receiving a packet, acknowledge its desire and
2169 * return bits indicating the kind of attention. wlack() returns
2170 * these bits so that the caller can service exactly the
2171 * conditions that wlack() acknowledged.
2178 struct wl_softc *sc = WLSOFTC(unit);
2179 short base = sc->base;
2181 outw(PIOR1(base), OFFSET_SCB);
2182 if(!(cmd = (inw(PIOP1(base)) & SCB_SW_INT)))
2185 if (sc->wl_if.if_flags & IFF_DEBUG)
2186 printf("wl%d: doing a wlack()\n",unit);
2188 outw(PIOP1(base), cmd);
2189 SET_CHAN_ATTN(unit);
2190 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
2191 for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
2193 printf("wl%d wlack(): board not accepting command.\n", unit);
2200 struct wl_softc *sc = WLSOFTC(unit);
2201 short base = sc->base;
2202 u_short tbd_p = OFFSET_TBD;
2208 outw(PIOR1(base), tbd_p);
2209 insw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
2210 sum += (tbd.act_count & ~TBD_SW_EOF);
2211 printf("%d: addr %x, count %d (%d), next %x, base %x\n",
2212 i++, tbd.buffer_addr,
2213 (tbd.act_count & ~TBD_SW_EOF), sum,
2214 tbd.next_tbd_offset, tbd.buffer_base);
2215 if (tbd.act_count & TBD_SW_EOF)
2217 tbd_p = tbd.next_tbd_offset;
2222 wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2224 struct mbuf *tm_p = *tm_pp;
2225 u_char *mb_p = *mb_pp;
2231 * can we get a run that will be coallesced or
2232 * that terminates before breaking
2235 count += tm_p->m_len;
2236 if (tm_p->m_len & 1)
2238 } while ((tm_p = tm_p->m_next) != (struct mbuf *)0);
2239 if ( (tm_p == (struct mbuf *)0) ||
2240 count > HDW_THRESHOLD) {
2241 *countp = (*tm_pp)->m_len;
2242 *mb_pp = mtod((*tm_pp), u_char *);
2246 /* we need to copy */
2250 cp = (u_char *) t_packet;
2252 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2254 if (count > HDW_THRESHOLD)
2257 if (tm_p->m_next == (struct mbuf *)0)
2259 tm_p = tm_p->m_next;
2262 *mb_pp = (u_char *) t_packet;
2269 wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2271 struct mbuf *tm_p = *tm_pp;
2273 u_char *cp = (u_char *) t_packet;
2276 /* we need to copy */
2278 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2281 if (tm_p->m_next == (struct mbuf *)0)
2283 tm_p = tm_p->m_next;
2287 *mb_pp = (u_char *) t_packet;
2295 struct wl_softc *sc = WLSOFTC(unit);
2296 short base = sc->base;
2299 printf("wl%d: DCE_STATUS: 0x%x, ", unit,
2300 wlmmcread(base,MMC_DCE_STATUS) & 0x0f);
2301 tmp = wlmmcread(base,MMC_CORRECT_NWID_H) << 8;
2302 tmp |= wlmmcread(base,MMC_CORRECT_NWID_L);
2303 printf("Correct NWID's: %d, ", tmp);
2304 tmp = wlmmcread(base,MMC_WRONG_NWID_H) << 8;
2305 tmp |= wlmmcread(base,MMC_WRONG_NWID_L);
2306 printf("Wrong NWID's: %d\n", tmp);
2307 printf("THR_PRE_SET: 0x%x, ", wlmmcread(base,MMC_THR_PRE_SET));
2308 printf("SIGNAL_LVL: %d, SILENCE_LVL: %d\n",
2309 wlmmcread(base,MMC_SIGNAL_LVL),
2310 wlmmcread(base,MMC_SILENCE_LVL));
2311 printf("SIGN_QUAL: 0x%x, NETW_ID: %x:%x, DES: %d\n",
2312 wlmmcread(base,MMC_SIGN_QUAL),
2313 wlmmcread(base,MMC_NETW_ID_H),
2314 wlmmcread(base,MMC_NETW_ID_L),
2315 wlmmcread(base,MMC_DES_AVAIL));
2319 wlmmcread(u_int base, u_short reg)
2321 while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2322 outw(MMCR(base),reg << 1);
2323 while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2324 return (u_short)inw(MMCR(base)) >> 8;
2330 MMC_WRITE(MMC_FREEZE,1);
2332 * SNR retrieval procedure :
2334 * read signal level : wlmmcread(base, MMC_SIGNAL_LVL);
2335 * read silence level : wlmmcread(base, MMC_SILENCE_LVL);
2337 MMC_WRITE(MMC_FREEZE,0);
2339 * SNR is signal:silence ratio.
2346 ** Reads the psa for the wavelan at (base) into (buf)
2349 wlgetpsa(int base, u_char *buf)
2353 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2354 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2356 for (i = 0; i < 0x40; i++) {
2357 outw(PIOR2(base), i);
2358 buf[i] = inb(PIOP2(base));
2360 PCMD(base, HACR_DEFAULT);
2361 PCMD(base, HACR_DEFAULT);
2367 ** Writes the psa for wavelan (unit) from the softc back to the
2368 ** board. Updates the CRC and sets the CRC OK flag.
2370 ** Do not call this when the board is operating, as it doesn't
2371 ** preserve the hacr.
2376 struct wl_softc *sc = WLSOFTC(unit);
2377 short base = sc->base;
2381 crc = wlpsacrc(sc->psa); /* calculate CRC of PSA */
2382 sc->psa[WLPSA_CRCLOW] = crc & 0xff;
2383 sc->psa[WLPSA_CRCHIGH] = (crc >> 8) & 0xff;
2384 sc->psa[WLPSA_CRCOK] = 0x55; /* default to 'bad' until programming complete */
2386 oldpri = splimp(); /* ick, long pause */
2388 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2389 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2391 for (i = 0; i < 0x40; i++) {
2393 outw(PIOR2(base),i); /* write param memory */
2395 outb(PIOP2(base), sc->psa[i]);
2398 outw(PIOR2(base),WLPSA_CRCOK); /* update CRC flag*/
2400 sc->psa[WLPSA_CRCOK] = 0xaa; /* OK now */
2401 outb(PIOP2(base), 0xaa); /* all OK */
2404 PCMD(base, HACR_DEFAULT);
2405 PCMD(base, HACR_DEFAULT);
2411 ** CRC routine provided by Christopher Giordano <cgiordan@gdeb.com>,
2412 ** from original code by Tomi Mikkonen (tomitm@remedy.fi)
2415 static u_int crc16_table[16] = {
2416 0x0000, 0xCC01, 0xD801, 0x1400,
2417 0xF001, 0x3C00, 0x2800, 0xE401,
2418 0xA001, 0x6C00, 0x7800, 0xB401,
2419 0x5000, 0x9C01, 0x8801, 0x4400
2423 wlpsacrc(u_char *buf)
2428 for (i = 0; i < 0x3d; i++, buf++) {
2430 r1 = crc16_table[crc & 0xF];
2431 crc = (crc >> 4) & 0x0FFF;
2432 crc = crc ^ r1 ^ crc16_table[*buf & 0xF];
2435 r1 = crc16_table[crc & 0xF];
2436 crc = (crc >> 4) & 0x0FFF;
2437 crc = crc ^ r1 ^ crc16_table[(*buf >> 4) & 0xF];
2446 * take input packet and cache various radio hw characteristics
2447 * indexed by MAC address.
2449 * Some things to think about:
2450 * note that no space is malloced.
2451 * We might hash the mac address if the cache were bigger.
2452 * It is not clear that the cache is big enough.
2453 * It is also not clear how big it should be.
2454 * The cache is IP-specific. We don't care about that as
2455 * we want it to be IP-specific.
2456 * The last N recv. packets are saved. This will tend
2457 * to reward agents and mobile hosts that beacon.
2458 * That is probably fine for mobile ip.
2461 /* globals for wavelan signal strength cache */
2462 /* this should go into softc structure above.
2465 /* set true if you want to limit cache items to broadcast/mcast
2466 * only packets (not unicast)
2468 static int wl_cache_mcastonly = 1;
2469 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_mcastonly, CTLFLAG_RW,
2470 &wl_cache_mcastonly, 0, "");
2472 /* set true if you want to limit cache items to IP packets only
2474 static int wl_cache_iponly = 1;
2475 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_iponly, CTLFLAG_RW,
2476 &wl_cache_iponly, 0, "");
2478 /* zero out the cache
2481 wl_cache_zero(int unit)
2483 struct wl_softc *sc = WLSOFTC(unit);
2485 bzero(&sc->w_sigcache[0], sizeof(struct w_sigcache) * MAXCACHEITEMS);
2487 sc->w_nextcache = 0;
2488 sc->w_wrapindex = 0;
2491 /* store hw signal info in cache.
2492 * index is MAC address, but an ip src gets stored too
2493 * There are two filters here controllable via sysctl:
2494 * throw out unicast (on by default, but can be turned off)
2495 * throw out non-ip (on by default, but can be turned off)
2498 void wl_cache_store (int unit, int base, struct ether_header *eh,
2501 struct ip *ip = NULL; /* Avoid GCC warning */
2503 int signal, silence;
2504 int w_insertcache; /* computed index for cache entry storage */
2505 struct wl_softc *sc = WLSOFTC(unit);
2506 int ipflag = wl_cache_iponly;
2510 * 2. configurable filter to throw out unicast packets,
2511 * keep multicast only.
2515 /* reject if not IP packet
2517 if ( wl_cache_iponly && (ntohs(eh->ether_type) != 0x800)) {
2521 /* check if broadcast or multicast packet. we toss
2524 if (wl_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
2528 /* find the ip header. we want to store the ip_src
2529 * address. use the mtod macro(in mbuf.h)
2530 * to typecast m to struct ip *
2533 ip = mtod(m, struct ip *);
2536 /* do a linear search for a matching MAC address
2537 * in the cache table
2538 * . MAC address is 6 bytes,
2539 * . var w_nextcache holds total number of entries already cached
2541 for(i = 0; i < sc->w_nextcache; i++) {
2542 if (! bcmp(eh->ether_shost, sc->w_sigcache[i].macsrc, 6 )) {
2544 * so we already have this entry,
2545 * update the data, and LRU age
2551 /* did we find a matching mac address?
2552 * if yes, then overwrite a previously existing cache entry
2554 if (i < sc->w_nextcache ) {
2557 /* else, have a new address entry,so
2558 * add this new entry,
2559 * if table full, then we need to replace entry
2563 /* check for space in cache table
2564 * note: w_nextcache also holds number of entries
2565 * added in the cache table
2567 if ( sc->w_nextcache < MAXCACHEITEMS ) {
2568 w_insertcache = sc->w_nextcache;
2570 sc->w_sigitems = sc->w_nextcache;
2572 /* no space found, so simply wrap with wrap index
2573 * and "zap" the next entry
2576 if (sc->w_wrapindex == MAXCACHEITEMS) {
2577 sc->w_wrapindex = 0;
2579 w_insertcache = sc->w_wrapindex++;
2583 /* invariant: w_insertcache now points at some slot
2586 if (w_insertcache < 0 || w_insertcache >= MAXCACHEITEMS) {
2588 "wl_cache_store, bad index: %d of [0..%d], gross cache error\n",
2589 w_insertcache, MAXCACHEITEMS);
2593 /* store items in cache
2596 * .signal (0..63) ,silence (0..63) ,quality (0..15)
2599 sc->w_sigcache[w_insertcache].ipsrc = ip->ip_src.s_addr;
2601 bcopy( eh->ether_shost, sc->w_sigcache[w_insertcache].macsrc, 6);
2602 signal = sc->w_sigcache[w_insertcache].signal = wlmmcread(base, MMC_SIGNAL_LVL) & 0x3f;
2603 silence = sc->w_sigcache[w_insertcache].silence = wlmmcread(base, MMC_SILENCE_LVL) & 0x3f;
2604 sc->w_sigcache[w_insertcache].quality = wlmmcread(base, MMC_SIGN_QUAL) & 0x0f;
2606 sc->w_sigcache[w_insertcache].snr =
2609 sc->w_sigcache[w_insertcache].snr = 0;
2613 #endif /* WLCACHE */
2616 * determine if in all multicast mode or not
2618 * returns: 1 if IFF_ALLMULTI should be set
2623 #if defined(__FreeBSD__) && __FreeBSD_version < 300000 /* not required */
2625 check_allmulti(int unit)
2627 struct wl_softc *sc = WLSOFTC(unit);
2628 short base = sc->base;
2629 struct ether_multi *enm;
2630 struct ether_multistep step;
2632 ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2633 while (enm != NULL) {
2634 unsigned int lo, hi;
2636 printf("enm_addrlo %x:%x:%x:%x:%x:%x\n", enm->enm_addrlo[0], enm->enm_addrlo[1],
2637 enm->enm_addrlo[2], enm->enm_addrlo[3], enm->enm_addrlo[4],
2638 enm->enm_addrlo[5]);
2639 printf("enm_addrhi %x:%x:%x:%x:%x:%x\n", enm->enm_addrhi[0], enm->enm_addrhi[1],
2640 enm->enm_addrhi[2], enm->enm_addrhi[3], enm->enm_addrhi[4],
2641 enm->enm_addrhi[5]);
2643 if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2646 ETHER_NEXT_MULTI(step, enm);