3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions
6 * 1. Redistributions of source code must retain all copyright
7 * notices, this list of conditions and the following disclaimer.
8 * 2. The names of the authors may not be used to endorse or promote products
9 * derived from this software without specific prior written permission
11 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
12 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
13 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
14 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
15 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
16 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
17 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
18 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
19 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
20 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 * if_wl.c - original MACH, then BSDI ISA wavelan driver
25 * ported to mach by Anders Klemets
26 * to BSDI by Robert Morris
27 * to FreeBSD by Jim Binkley
28 * to FreeBSD 2.2+ by Michael Smith
31 * Changed interface to match 2.1-2.2 differences.
32 * Implement IRQ selection logic in wlprobe()
33 * Implement PSA updating.
34 * Pruned heading comments for relevance.
35 * Ripped out all the 'interface counters' cruft.
36 * Cut the missing-interrupt timer back to 100ms.
38 * now supports all multicast mode (mrouted will work),
39 * but unfortunately must do that by going into promiscuous mode
40 * NWID sysctl added so that normally promiscuous mode is NWID-specific
41 * but can be made NWID-inspecific
45 * Ported to FreeBSD, got promiscuous mode working with bpfs,
46 * and rewired timer routine. The i82586 will hang occasionally on output
47 * and the watchdog timer will kick it if so and log an entry.
48 * 2 second timeout there. Apparently the chip loses an interrupt.
49 * Code borrowed from if_ie.c for watchdog timer.
51 * The wavelan card is a 2mbit radio modem that emulates ethernet;
52 * i.e., it uses MAC addresses. This should not be a surprise since
53 * it uses an ethernet controller as a major hw item.
54 * It can broadcast, unicast or apparently multicast in a base cell
55 * using a omni-directional antennae that is
56 * about 800 feet around the base cell barring walls and metal.
57 * With directional antennae, it can be used point to point over a mile
58 * or so apparently (haven't tried that).
60 * There are ISA and pcmcia versions (not supported by this code).
61 * The ISA card has an Intel 82586 lan controller on it. It consists
62 * of 2 pieces of hw, the lan controller (intel) and a radio-modem.
63 * The latter has an extra set of controller registers that has nothing
64 * to do with the i82586 and allows setting and monitoring of radio
65 * signal strength, etc. There is a nvram area called the PSA that
66 * contains a number of setup variables including the IRQ and so-called
67 * NWID or Network ID. The NWID must be set the same for all radio
68 * cards to communicate (unless you are using the ATT/NCR roaming feature
69 * with their access points. There is no support for that here. Roaming
70 * involves a link-layer beacon sent out from the access points. End
71 * stations monitor the signal strength and only use the strongest
72 * access point). This driver assumes that the base ISA port, IRQ,
73 * and NWID are first set in nvram via the dos-side "instconf.exe" utility
74 * supplied with the card. This driver takes the ISA port from
75 * the kernel configuration setup, and then determines the IRQ either
76 * from the kernel config (if an explicit IRQ is set) or from the
77 * PSA on the card if not.
78 * The hw also magically just uses the IRQ set in the nvram.
79 * The NWID is used magically as well by the radio-modem
80 * to determine which packets to keep or throw out.
84 * device wl0 at isa? port 0x300 net irq ?
87 * 1. WLDEBUG. (off) - if turned on enables IFF_DEBUG set via ifconfig debug
88 * 2. MULTICAST (on) - turned on and works up to and including mrouted
89 * 3. WLCACHE (off) - define to turn on a signal strength
90 * (and other metric) cache that is indexed by sender MAC address.
91 * Apps can read this out to learn the remote signal strength of a
92 * sender. Note that it has a switch so that it only stores
93 * broadcast/multicast senders but it could be set to store unicast
94 * too only. Size is hardwired in if_wl_wavelan.h
96 * one further note: promiscuous mode is a curious thing. In this driver,
97 * promiscuous mode apparently CAN catch ALL packets and ignore the NWID
98 * setting. This is probably more useful in a sense (for snoopers) if
99 * you are interested in all traffic as opposed to if you are interested
100 * in just your own. There is a driver specific sysctl to turn promiscuous
101 * from just promiscuous to wildly promiscuous...
103 * This driver also knows how to load the synthesizers in the 2.4 Gz
104 * ISA Half-card, Product number 847647476 (USA/FCC IEEE Channel set).
105 * This product consists of a "mothercard" that contains the 82586,
106 * NVRAM that holds the PSA, and the ISA-buss interface custom ASIC.
107 * The radio transceiver is a "daughtercard" called the WaveMODEM which
108 * connects to the mothercard through two single-inline connectors: a
109 * 20-pin connector provides DC-power and modem signals, and a 3-pin
110 * connector which exports the antenna connection. The code herein
111 * loads the receive and transmit synthesizers and the corresponding
112 * transmitter output power value from an EEPROM controlled through
113 * additional registers via the MMC. The EEPROM address selected
114 * are those whose values are preset by the DOS utility programs
115 * provided with the product, and this provides compatible operation
116 * with the DOS Packet Driver software. A future modification will
117 * add the necessary functionality to this driver and to the wlconfig
118 * utility to completely replace the DOS Configuration Utilities.
119 * The 2.4 Gz WaveMODEM is described in document number 407-024692/E,
120 * and is available through Lucent Technologies OEM supply channels.
127 * Olivetti PC586 Mach Ethernet driver v1.0
128 * Copyright Ing. C. Olivetti & C. S.p.A. 1988, 1989
129 * All rights reserved.
134 Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc.,
135 Cupertino, California.
139 Permission to use, copy, modify, and distribute this software and
140 its documentation for any purpose and without fee is hereby
141 granted, provided that the above copyright notice appears in all
142 copies and that both the copyright notice and this permission notice
143 appear in supporting documentation, and that the name of Olivetti
144 not be used in advertising or publicity pertaining to distribution
145 of the software without specific, written prior permission.
147 OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
148 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
149 IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
150 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
151 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
152 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
153 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
157 Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
161 Permission to use, copy, modify, and distribute this software and
162 its documentation for any purpose and without fee is hereby
163 granted, provided that the above copyright notice appears in all
164 copies and that both the copyright notice and this permission notice
165 appear in supporting documentation, and that the name of Intel
166 not be used in advertising or publicity pertaining to distribution
167 of the software without specific, written prior permission.
169 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
170 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
171 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
172 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
173 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
174 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
175 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
181 * 1. The best book on the 82586 is:
182 * LAN Components User's Manual by Intel
183 * The copy I found was dated 1984. This really tells you
184 * what the state machines are doing
185 * 2. In the current design, we only do one write at a time,
186 * though the hardware is capable of chaining and possibly
187 * even batching. The problem is that we only make one
188 * transmit buffer available in sram space.
192 #include "opt_wavelan.h"
193 #include "opt_inet.h"
195 #include <sys/param.h>
196 #include <sys/systm.h>
197 #include <sys/kernel.h>
198 #include <sys/sockio.h>
199 #include <sys/mbuf.h>
200 #include <sys/socket.h>
201 #include <sys/syslog.h>
204 #include <sys/sysctl.h>
206 #include <net/ethernet.h>
208 #include <net/if_dl.h>
211 #include <netinet/in.h>
212 #include <netinet/in_systm.h>
213 #include <netinet/ip.h>
214 #include <netinet/if_ether.h>
218 #include <i386/isa/isa_device.h>
219 #include <i386/isa/ic/if_wl_i82586.h> /* Definitions for the Intel chip */
221 /* was 1000 in original, fed to DELAY(x) */
222 #define DELAYCONST 1000
223 #include <dev/wl/if_wl.h>
224 #include <machine/if_wl_wavelan.h>
226 #ifndef COMPAT_OLDISA
227 #error "The wl device requires the old isa compatibility shims"
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 struct isa_driver wldriver = {
272 COMPAT_ISA_DRIVER(wl, wldriver);
275 * XXX The Wavelan appears to be prone to dropping stuff if you talk to
276 * it too fast. This disgusting hack inserts a delay after each packet
277 * is queued which helps avoid this behaviour on fast systems.
279 static int wl_xmit_delay = 250;
280 SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_delay, CTLFLAG_RW, &wl_xmit_delay, 0, "");
283 * not XXX, but ZZZ (bizarre).
284 * promiscuous mode can be toggled to ignore NWIDs. By default,
285 * it does not. Caution should be exercised about combining
286 * this mode with IFF_ALLMULTI which puts this driver in
289 static int wl_ignore_nwid = 0;
290 SYSCTL_INT(_machdep, OID_AUTO, wl_ignore_nwid, CTLFLAG_RW, &wl_ignore_nwid, 0, "");
293 * Emit diagnostics about transmission problems
295 static int xmt_watch = 0;
296 SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_watch, CTLFLAG_RW, &xmt_watch, 0, "");
299 * Collect SNR statistics
301 static int gathersnr = 0;
302 SYSCTL_INT(_machdep, OID_AUTO, wl_gather_snr, CTLFLAG_RW, &gathersnr, 0, "");
304 static void wlstart(struct ifnet *ifp);
305 static void wlinit(void *xsc);
306 static int wlioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
307 static timeout_t wlwatchdog;
308 static ointhand2_t wlintr;
309 static void wlxmt(int unt, struct mbuf *m);
310 static int wldiag(int unt);
311 static int wlconfig(int unit);
312 static int wlcmd(int unit, char *str);
313 static void wlmmcstat(int unit);
314 static u_short wlbldru(int unit);
315 static u_short wlmmcread(u_int base, u_short reg);
316 static void wlinitmmc(int unit);
317 static int wlhwrst(int unit);
318 static void wlrustrt(int unit);
319 static void wlbldcu(int unit);
320 static int wlack(int unit);
321 static int wlread(int unit, u_short fd_p);
322 static void getsnr(int unit);
323 static void wlrcv(int unit);
324 static int wlrequeue(int unit, u_short fd_p);
325 static void wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
326 static void wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
328 static void wltbd(int unit);
330 static void wlgetpsa(int base, u_char *buf);
331 static void wlsetpsa(int unit);
332 static u_short wlpsacrc(u_char *buf);
333 static void wldump(int unit);
335 static void wl_cache_store(int, int, struct ether_header *, struct mbuf *);
336 static void wl_cache_zero(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 register 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 register short base = id->id_iobase;
439 u_char unit = id->id_unit;
440 register 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)
471 for (i=0; i < WAVELAN_ADDR_SIZE; ++i)
472 sc->wl_addr[i] = sc->psa[j + i];
474 /* enter normal 16 bit mode operation */
475 sc->hacr = HACR_DEFAULT;
479 outw(PIOR1(base), OFFSET_SCB + 8); /* address of scb_crcerrs */
480 outw(PIOP1(base), 0); /* clear scb_crcerrs */
481 outw(PIOP1(base), 0); /* clear scb_alnerrs */
482 outw(PIOP1(base), 0); /* clear scb_rscerrs */
483 outw(PIOP1(base), 0); /* clear scb_ovrnerrs */
485 bzero(ifp, sizeof(ifp));
487 ifp->if_unit = id->id_unit;
488 ifp->if_mtu = WAVELAN_MTU;
489 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
491 ifp->if_flags |= IFF_DEBUG;
494 ifp->if_flags |= IFF_MULTICAST;
495 #endif /* MULTICAST */
498 ifp->if_init = wlinit;
499 ifp->if_output = ether_output;
500 ifp->if_start = wlstart;
501 ifp->if_ioctl = wlioctl;
502 ifp->if_timer = 0; /* paranoia */
508 ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
510 bcopy(&sc->wl_addr[0], sc->wl_ac.ac_enaddr, WAVELAN_ADDR_SIZE);
511 printf("%s%d: address %6D, NWID 0x%02x%02x", ifp->if_name, ifp->if_unit,
512 sc->wl_ac.ac_enaddr, ":", sc->nwid[0], sc->nwid[1]);
514 printf(", Freq %d MHz",sc->freq24); /* 2.4 Gz */
515 printf("\n"); /* 2.4 Gz */
524 * Print out interesting information about the 82596.
529 register struct wl_softc *sp = WLSOFTC(unit);
533 printf("hasr %04x\n", inw(HASR(base)));
535 printf("scb at %04x:\n ", OFFSET_SCB);
536 outw(PIOR1(base), OFFSET_SCB);
537 for (i = 0; i < 8; i++)
538 printf("%04x ", inw(PIOP1(base)));
541 printf("cu at %04x:\n ", OFFSET_CU);
542 outw(PIOR1(base), OFFSET_CU);
543 for (i = 0; i < 8; i++)
544 printf("%04x ", inw(PIOP1(base)));
547 printf("tbd at %04x:\n ", OFFSET_TBD);
548 outw(PIOR1(base), OFFSET_TBD);
549 for (i = 0; i < 4; i++)
550 printf("%04x ", inw(PIOP1(base)));
554 /* Initialize the Modem Management Controller */
558 register struct wl_softc *sp = WLSOFTC(unit);
564 /* enter 8 bit operation */
565 sp->hacr = (HACR_DEFAULT & ~HACR_16BITS);
568 configured = sp->psa[WLPSA_CONFIGURED] & 1;
571 * Set default modem control parameters. Taken from NCR document
574 MMC_WRITE(MMC_JABBER_ENABLE, 0x01);
575 MMC_WRITE(MMC_ANTEN_SEL, 0x02);
576 MMC_WRITE(MMC_IFS, 0x20);
577 MMC_WRITE(MMC_MOD_DELAY, 0x04);
578 MMC_WRITE(MMC_JAM_TIME, 0x38);
579 MMC_WRITE(MMC_DECAY_PRM, 0x00); /* obsolete ? */
580 MMC_WRITE(MMC_DECAY_UPDAT_PRM, 0x00);
582 MMC_WRITE(MMC_LOOPT_SEL, 0x00);
583 if (sp->psa[WLPSA_COMPATNO] & 1) {
584 MMC_WRITE(MMC_THR_PRE_SET, 0x01); /* 0x04 for AT and 0x01 for MCA */
586 MMC_WRITE(MMC_THR_PRE_SET, 0x04); /* 0x04 for AT and 0x01 for MCA */
588 MMC_WRITE(MMC_QUALITY_THR, 0x03);
590 /* use configuration defaults from parameter storage area */
591 if (sp->psa[WLPSA_NWIDENABLE] & 1) {
592 if ((mode & (MOD_PROM | MOD_ENAL)) && wl_ignore_nwid) {
593 MMC_WRITE(MMC_LOOPT_SEL, 0x40);
595 MMC_WRITE(MMC_LOOPT_SEL, 0x00);
598 MMC_WRITE(MMC_LOOPT_SEL, 0x40); /* disable network id check */
600 MMC_WRITE(MMC_THR_PRE_SET, sp->psa[WLPSA_THRESH]);
601 MMC_WRITE(MMC_QUALITY_THR, sp->psa[WLPSA_QUALTHRESH]);
603 MMC_WRITE(MMC_FREEZE, 0x00);
604 MMC_WRITE(MMC_ENCR_ENABLE, 0x00);
606 MMC_WRITE(MMC_NETW_ID_L,sp->nwid[1]); /* set NWID */
607 MMC_WRITE(MMC_NETW_ID_H,sp->nwid[0]);
609 /* enter normal 16 bit mode operation */
610 sp->hacr = HACR_DEFAULT;
612 CMD(unit); /* virtualpc1 needs this! */
614 if (sp->psa[WLPSA_COMPATNO]== /* 2.4 Gz: half-card ver */
615 WLPSA_COMPATNO_WL24B) { /* 2.4 Gz */
616 i=sp->chan24<<4; /* 2.4 Gz: position ch # */
617 MMC_WRITE(MMC_EEADDR,i+0x0f); /* 2.4 Gz: named ch, wc=16 */
618 MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+ /* 2.4 Gz: Download Synths */
619 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: Read EEPROM */
620 for (i=0; i<1000; ++i) { /* 2.4 Gz: wait for download */
621 DELAY(40); /* 2.4 Gz */
622 if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and */
623 &(MMC_EECTRLstat_DWLD /* 2.4 Gz: EEBUSY */
624 +MMC_EECTRLstat_EEBUSY))==0) /* 2.4 Gz: */
625 break; /* 2.4 Gz: download finished */
627 if (i==1000) printf("wl: synth load failed\n"); /* 2.4 Gz */
628 MMC_WRITE(MMC_EEADDR,0x61); /* 2.4 Gz: default pwr, wc=2 */
629 MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+ /* 2.4 Gz: Download Xmit Pwr */
630 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: Read EEPROM */
631 for (i=0; i<1000; ++i) { /* 2.4 Gz: wait for download */
632 DELAY(40); /* 2.4 Gz */
633 if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and */
634 &(MMC_EECTRLstat_DWLD /* 2.4 Gz: EEBUSY */
635 +MMC_EECTRLstat_EEBUSY))==0) /* 2.4 Gz: */
636 break; /* 2.4 Gz: download finished */
638 if (i==1000) printf("wl: xmit pwr load failed\n"); /* 2.4 Gz */
639 MMC_WRITE(MMC_ANALCTRL, /* 2.4 Gz: EXT ant+polarity */
640 MMC_ANALCTRL_ANTPOL + /* 2.4 Gz: */
641 MMC_ANALCTRL_EXTANT); /* 2.4 Gz: */
642 i=sp->chan24<<4; /* 2.4 Gz: position ch # */
643 MMC_WRITE(MMC_EEADDR,i); /* 2.4 Gz: get frequency */
644 MMC_WRITE(MMC_EECTRL, /* 2.4 Gz: EEPROM read */
645 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: */
646 DELAY(40); /* 2.4 Gz */
647 i = wlmmcread(base,MMC_EEDATALrv) /* 2.4 Gz: freq val */
648 + (wlmmcread(base,MMC_EEDATAHrv)<<8); /* 2.4 Gz */
649 sp->freq24 = (i>>6)+2400; /* 2.4 Gz: save real freq */
656 * Another routine that interfaces the "if" layer to this driver.
657 * Simply resets the structures that are used by "upper layers".
658 * As well as calling wlhwrst that does reset the WaveLAN board.
660 * input : softc pointer for this interface
661 * output : structures (if structs) and board are reset
667 register struct wl_softc *sc = xsc;
668 struct ifnet *ifp = &sc->wl_if;
673 if (sc->wl_if.if_flags & IFF_DEBUG)
674 printf("wl%d: entered wlinit()\n",sc->unit);
676 if (TAILQ_FIRST(&ifp->if_addrhead) == (struct ifaddr *)0)
679 if ((stat = wlhwrst(sc->unit)) == TRUE) {
680 sc->wl_if.if_flags |= IFF_RUNNING; /* same as DSF_RUNNING */
682 * OACTIVE is used by upper-level routines
685 sc->wl_if.if_flags &= ~IFF_OACTIVE; /* same as tbusy below */
687 sc->flags |= DSF_RUNNING;
689 untimeout(wlwatchdog, sc, sc->watchdog_ch);
693 printf("wl%d init(): trouble resetting board.\n", sc->unit);
701 * This routine resets the WaveLAN board that corresponds to the
702 * board number passed in.
704 * input : board number to do a hardware reset
705 * output : board is reset
711 register struct wl_softc *sc = WLSOFTC(unit);
714 if (sc->wl_if.if_flags & IFF_DEBUG)
715 printf("wl%d: entered wlhwrst()\n",unit);
717 sc->hacr = HACR_RESET;
718 CMD(unit); /* reset the board */
720 /* clear reset command and set PIO#1 in autoincrement mode */
721 sc->hacr = HACR_DEFAULT;
725 if (sc->wl_if.if_flags & IFF_DEBUG)
726 wlmmcstat(unit); /* Display MMC registers */
728 wlbldcu(unit); /* set up command unit structures */
730 if (wldiag(unit) == 0)
733 if (wlconfig(unit) == 0)
736 * insert code for loopback test here
738 wlrustrt(unit); /* start receive unit */
740 /* enable interrupts */
741 sc->hacr = (HACR_DEFAULT | HACR_INTRON);
750 * This function builds up the command unit structures. It inits
751 * the scp, iscp, scb, cb, tbd, and tbuf.
757 register struct wl_softc *sc = WLSOFTC(unit);
758 short base = sc->base;
766 bzero(&scp, sizeof(scp));
768 scp.scp_iscp = OFFSET_ISCP;
769 scp.scp_iscp_base = 0;
770 outw(PIOR1(base), OFFSET_SCP);
771 outsw(PIOP1(base), &scp, sizeof(scp_t)/2);
773 bzero(&iscp, sizeof(iscp));
775 iscp.iscp_scb_offset = OFFSET_SCB;
777 iscp.iscp_scb_base = 0;
778 outw(PIOR1(base), OFFSET_ISCP);
779 outsw(PIOP1(base), &iscp, sizeof(iscp_t)/2);
782 scb.scb_command = SCB_RESET;
783 scb.scb_cbl_offset = OFFSET_CU;
784 scb.scb_rfa_offset = OFFSET_RU;
788 scb.scb_ovrnerrs = 0;
789 outw(PIOR1(base), OFFSET_SCB);
790 outsw(PIOP1(base), &scb, sizeof(scb_t)/2);
794 outw(PIOR0(base), OFFSET_ISCP + 0); /* address of iscp_busy */
795 for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); )
798 printf("wl%d bldcu(): iscp_busy timeout.\n", unit);
799 outw(PIOR0(base), OFFSET_SCB + 0); /* address of scb_status */
800 for (i = STATUS_TRIES; i-- > 0; ) {
801 if (inw(PIOP0(base)) == (SCB_SW_CX|SCB_SW_CNA))
805 printf("wl%d bldcu(): not ready after reset.\n", unit);
809 cb.ac_command = AC_CW_EL; /* NOP */
810 cb.ac_link_offset = OFFSET_CU;
811 outw(PIOR1(base), OFFSET_CU);
812 outsw(PIOP1(base), &cb, 6/2);
815 tbd.next_tbd_offset = I82586NULL;
818 outw(PIOR1(base), OFFSET_TBD);
819 outsw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
827 * input : board number
828 * output : stuff sent to board if any there
832 wlstart(struct ifnet *ifp)
834 int unit = ifp->if_unit;
836 register struct wl_softc *sc = WLSOFTC(unit);
837 short base = sc->base;
838 int scb_status, cu_status, scb_command;
841 if (sc->wl_if.if_flags & IFF_DEBUG)
842 printf("wl%d: entered wlstart()\n",unit);
845 outw(PIOR1(base), OFFSET_CU);
846 cu_status = inw(PIOP1(base));
847 outw(PIOR0(base),OFFSET_SCB + 0); /* scb_status */
848 scb_status = inw(PIOP0(base));
849 outw(PIOR0(base), OFFSET_SCB + 2);
850 scb_command = inw(PIOP0(base));
853 * don't need OACTIVE check as tbusy here checks to see
854 * if we are already busy
857 if ((scb_status & 0x0700) == SCB_CUS_IDLE &&
858 (cu_status & AC_SW_B) == 0){
860 untimeout(wlwatchdog, sc, sc->watchdog_ch);
861 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
863 * This is probably just a race. The xmt'r is just
864 * became idle but WE have masked interrupts so ...
867 printf("wl%d: CU idle, scb %04x %04x cu %04x\n",
868 unit, scb_status, scb_command, cu_status);
870 if (xmt_watch) printf("!!");
872 return; /* genuinely still busy */
874 } else if ((scb_status & 0x0700) == SCB_CUS_ACTV ||
875 (cu_status & AC_SW_B)){
877 printf("wl%d: CU unexpectedly busy; scb %04x cu %04x\n",
878 unit, scb_status, cu_status);
880 if (xmt_watch) printf("wl%d: busy?!",unit);
881 return; /* hey, why are we busy? */
884 /* get ourselves some data */
886 IF_DEQUEUE(&ifp->if_snd, m);
887 if (m != (struct mbuf *)0) {
888 /* let BPF see it before we commit it */
893 /* set the watchdog timer so that if the board
894 * fails to interrupt we will restart
896 /* try 10 ticks, not very long */
897 sc->watchdog_ch = timeout(wlwatchdog, sc, 10);
898 sc->wl_ac.ac_if.if_flags |= IFF_OACTIVE;
899 sc->wl_if.if_opackets++;
902 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
910 * This routine does the actual copy of data (including ethernet header
911 * structure) from the WaveLAN to an mbuf chain that will be passed up
912 * to the "if" (network interface) layer. NOTE: we currently
913 * don't handle trailer protocols, so if that is needed, it will
914 * (at least in part) be added here. For simplicities sake, this
915 * routine copies the receive buffers from the board into a local (stack)
916 * buffer until the frame has been copied from the board. Once in
917 * the local buffer, the contents are copied to an mbuf chain that
918 * is then enqueued onto the appropriate "if" queue.
920 * input : board number, and an frame descriptor address
921 * output : the packet is put into an mbuf chain, and passed up
922 * assumes : if any errors occur, packet is "dropped on the floor"
926 wlread(int unit, u_short fd_p)
928 register struct wl_softc *sc = WLSOFTC(unit);
929 register struct ifnet *ifp = &sc->wl_if;
930 short base = sc->base;
932 struct ether_header eh;
936 u_short mlen, len, clen;
937 u_short bytes_in_msg, bytes_in_mbuf, bytes;
941 if (sc->wl_if.if_flags & IFF_DEBUG)
942 printf("wl%d: entered wlread()\n",unit);
944 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
945 printf("wl%d read(): board is not running.\n", ifp->if_unit);
946 sc->hacr &= ~HACR_INTRON;
947 CMD(unit); /* turn off interrupts */
949 /* read ether_header info out of device memory. doesn't
950 * go into mbuf. goes directly into eh structure
952 len = sizeof(struct ether_header); /* 14 bytes */
953 outw(PIOR1(base), fd_p);
954 insw(PIOP1(base), &fd, (sizeof(fd_t) - len)/2);
955 insw(PIOP1(base), &eh, (len-2)/2);
956 eh.ether_type = ntohs(inw(PIOP1(base)));
958 if (sc->wl_if.if_flags & IFF_DEBUG) {
959 printf("wlread: rcv packet, type is %x\n", eh.ether_type);
963 * WARNING. above is done now in ether_input, above may be
964 * useful for debug. jrb
966 eh.ether_type = htons(eh.ether_type);
968 if (fd.rbd_offset == I82586NULL) {
969 printf("wl%d read(): Invalid buffer\n", unit);
970 if (wlhwrst(unit) != TRUE) {
971 printf("wl%d read(): hwrst trouble.\n", unit);
976 outw(PIOR1(base), fd.rbd_offset);
977 insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
978 bytes_in_msg = rbd.status & RBD_SW_COUNT;
979 MGETHDR(m, M_DONTWAIT, MT_DATA);
981 if (m == (struct mbuf *)0) {
983 * not only do we want to return, we need to drop the packet on
984 * the floor to clear the interrupt.
987 if (wlhwrst(unit) != TRUE) {
988 sc->hacr &= ~HACR_INTRON;
989 CMD(unit); /* turn off interrupts */
990 printf("wl%d read(): hwrst trouble.\n", unit);
994 m->m_next = (struct mbuf *) 0;
995 m->m_pkthdr.rcvif = ifp;
996 m->m_pkthdr.len = 0; /* don't know this yet */
999 /* always use a cluster. jrb
1001 MCLGET(m, M_DONTWAIT);
1002 if (m->m_flags & M_EXT) {
1003 m->m_len = MCLBYTES;
1007 if (wlhwrst(unit) != TRUE) {
1008 sc->hacr &= ~HACR_INTRON;
1009 CMD(unit); /* turn off interrupts */
1010 printf("wl%d read(): hwrst trouble.\n", unit);
1017 bytes_in_mbuf = m->m_len;
1018 mb_p = mtod(tm, u_char *);
1019 bytes = min(bytes_in_mbuf, bytes_in_msg);
1026 outw(PIOR1(base), rbd.buffer_addr);
1027 insw(PIOP1(base), mb_p, len/2);
1031 if (!(bytes_in_mbuf -= bytes)) {
1032 MGET(tm->m_next, M_DONTWAIT, MT_DATA);
1034 if (tm == (struct mbuf *)0) {
1036 printf("wl%d read(): No mbuf nth\n", unit);
1037 if (wlhwrst(unit) != TRUE) {
1038 sc->hacr &= ~HACR_INTRON;
1039 CMD(unit); /* turn off interrupts */
1040 printf("wl%d read(): hwrst trouble.\n", unit);
1046 bytes_in_mbuf = MLEN;
1047 mb_p = mtod(tm, u_char *);
1052 if (!(bytes_in_msg -= bytes)) {
1053 if (rbd.status & RBD_SW_EOF ||
1054 rbd.next_rbd_offset == I82586NULL) {
1058 outw(PIOR1(base), rbd.next_rbd_offset);
1059 insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1060 bytes_in_msg = rbd.status & RBD_SW_COUNT;
1063 rbd.buffer_addr += bytes;
1066 bytes = min(bytes_in_mbuf, bytes_in_msg);
1069 m->m_pkthdr.len = clen;
1072 * If hw is in promiscuous mode (note that I said hardware, not if
1073 * IFF_PROMISC is set in ifnet flags), then if this is a unicast
1074 * packet and the MAC dst is not us, drop it. This check in normally
1075 * inside ether_input(), but IFF_MULTI causes hw promisc without
1076 * a bpf listener, so this is wrong.
1077 * Greg Troxel <gdt@ir.bbn.com>, 1998-08-07
1080 * TBD: also discard packets where NWID does not match.
1081 * However, there does not appear to be a way to read the nwid
1082 * for a received packet. -gdt 1998-08-07
1085 #ifdef WL_USE_IFNET_PROMISC_CHECK /* not defined */
1086 (sc->wl_ac.ac_if.if_flags & (IFF_PROMISC|IFF_ALLMULTI))
1088 /* hw is in promisc mode if this is true */
1089 (sc->mode & (MOD_PROM | MOD_ENAL))
1092 (eh.ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
1093 bcmp(eh.ether_dhost, sc->wl_ac.ac_enaddr,
1094 sizeof(eh.ether_dhost)) != 0 ) {
1100 if (sc->wl_if.if_flags & IFF_DEBUG)
1101 printf("wl%d: wlrecv %d bytes\n", unit, clen);
1105 wl_cache_store(unit, base, &eh, m);
1109 * received packet is now in a chain of mbuf's. next step is
1110 * to pass the packet upwards.
1113 ether_input(&sc->wl_if, &eh, m);
1120 * This routine processes an ioctl request from the "if" layer
1123 * input : pointer the appropriate "if" struct, command, and data
1124 * output : based on command appropriate action is taken on the
1125 * WaveLAN board(s) or related structures
1126 * return : error is returned containing exit conditions
1130 wlioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1132 register struct ifreq *ifr = (struct ifreq *)data;
1133 int unit = ifp->if_unit;
1134 register struct wl_softc *sc = WLSOFTC(unit);
1135 short base = sc->base;
1137 int opri, error = 0;
1138 struct thread *td = curthread; /* XXX */
1139 int irq, irqval, i, isroot;
1147 if (sc->wl_if.if_flags & IFF_DEBUG)
1148 printf("wl%d: entered wlioctl()\n",unit);
1155 error = ether_ioctl(ifp, cmd, data);
1159 if (ifp->if_flags & IFF_ALLMULTI) {
1162 if (ifp->if_flags & IFF_PROMISC) {
1165 if (ifp->if_flags & IFF_LINK0) {
1169 * force a complete reset if the recieve multicast/
1170 * promiscuous mode changes so that these take
1171 * effect immediately.
1174 if (sc->mode != mode) {
1176 if (sc->flags & DSF_RUNNING) {
1177 sc->flags &= ~DSF_RUNNING;
1181 /* if interface is marked DOWN and still running then
1184 if ((ifp->if_flags & IFF_UP) == 0 && sc->flags & DSF_RUNNING) {
1185 printf("wl%d ioctl(): board is not running\n", unit);
1186 sc->flags &= ~DSF_RUNNING;
1187 sc->hacr &= ~HACR_INTRON;
1188 CMD(unit); /* turn off interrupts */
1190 /* else if interface is UP and RUNNING, start it
1192 else if (ifp->if_flags & IFF_UP && (sc->flags & DSF_RUNNING) == 0) {
1196 /* if WLDEBUG set on interface, then printf rf-modem regs
1198 if (ifp->if_flags & IFF_DEBUG)
1207 #endif /* MULTICAST */
1209 /* DEVICE SPECIFIC */
1212 /* copy the PSA out to the caller */
1214 /* pointer to buffer in user space */
1215 up = (void *)ifr->ifr_data;
1216 /* work out if they're root */
1217 isroot = (suser(td) == 0);
1219 for (i = 0; i < 0x40; i++) {
1220 /* don't hand the DES key out to non-root users */
1221 if ((i > WLPSA_DESKEY) && (i < (WLPSA_DESKEY + 8)) && !isroot)
1223 if (subyte((up + i), sc->psa[i]))
1229 /* copy the PSA in from the caller; we only copy _some_ values */
1232 if ((error = suser(td)))
1234 error = EINVAL; /* assume the worst */
1235 /* pointer to buffer in user space containing data */
1236 up = (void *)ifr->ifr_data;
1238 /* check validity of input range */
1239 for (i = 0; i < 0x40; i++)
1240 if (fubyte(up + i) < 0)
1243 /* check IRQ value */
1244 irqval = fubyte(up+WLPSA_IRQNO);
1245 for (irq = 15; irq >= 0; irq--)
1246 if (irqvals[irq] == irqval)
1248 if (irq == 0) /* oops */
1251 sc->psa[WLPSA_IRQNO] = irqval;
1254 for (i = 0; i < 6; i++)
1255 sc->psa[WLPSA_LOCALMAC+i] = fubyte(up+WLPSA_LOCALMAC+i);
1258 sc->psa[WLPSA_MACSEL] = fubyte(up+WLPSA_MACSEL);
1261 sc->psa[WLPSA_NWID] = fubyte(up+WLPSA_NWID);
1262 sc->psa[WLPSA_NWID+1] = fubyte(up+WLPSA_NWID+1);
1265 wlsetpsa(unit); /* update the PSA */
1269 /* get the current NWID out of the sc since we stored it there */
1271 ifr->ifr_data = (caddr_t) (sc->nwid[0] << 8 | sc->nwid[1]);
1276 * change the nwid dynamically. This
1277 * ONLY changes the radio modem and does not
1281 * 1. save in softc "soft registers"
1282 * 2. save in radio modem (MMC)
1286 if ((error = suser(td)))
1288 if (!(ifp->if_flags & IFF_UP)) {
1289 error = EIO; /* only allowed while up */
1292 * soft c nwid shadows radio modem setting
1294 sc->nwid[0] = (int)ifr->ifr_data >> 8;
1295 sc->nwid[1] = (int)ifr->ifr_data & 0xff;
1296 MMC_WRITE(MMC_NETW_ID_L,sc->nwid[1]);
1297 MMC_WRITE(MMC_NETW_ID_H,sc->nwid[0]);
1301 /* copy the EEPROM in 2.4 Gz WaveMODEM out to the caller */
1304 if ((error = suser(td)))
1306 /* pointer to buffer in user space */
1307 up = (void *)ifr->ifr_data;
1309 for (i=0x00; i<0x80; ++i) { /* 2.4 Gz: size of EEPROM */
1310 MMC_WRITE(MMC_EEADDR,i); /* 2.4 Gz: get frequency */
1311 MMC_WRITE(MMC_EECTRL, /* 2.4 Gz: EEPROM read */
1312 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: */
1313 DELAY(40); /* 2.4 Gz */
1314 if (subyte(up + 2*i , /* 2.4 Gz: pass low byte of */
1315 wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word */
1316 ) return(EFAULT); /* 2.4 Gz: */
1317 if (subyte(up + 2*i+1, /* 2.4 Gz: pass hi byte of */
1318 wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word */
1319 ) return(EFAULT); /* 2.4 Gz: */
1324 /* zero (Delete) the wl cache */
1327 if ((error = suser(td)))
1329 wl_cache_zero(unit);
1332 /* read out the number of used cache elements */
1334 ifr->ifr_data = (caddr_t) sc->w_sigitems;
1337 /* read out the wl cache */
1339 /* pointer to buffer in user space */
1340 up = (void *)ifr->ifr_data;
1341 cpt = (char *) &sc->w_sigcache[0];
1342 size = sc->w_sigitems * sizeof(struct w_sigcache);
1344 for (i = 0; i < size; i++) {
1345 if (subyte((up + i), *cpt++))
1361 * Called if the timer set in wlstart expires before an interrupt is received
1362 * from the wavelan. It seems to lose interrupts sometimes.
1363 * The watchdog routine gets called if the transmitter failed to interrupt
1365 * input : which board is timing out
1366 * output : board reset
1370 wlwatchdog(void *vsc)
1372 struct wl_softc *sc = vsc;
1373 int unit = sc->unit;
1375 log(LOG_ERR, "wl%d: wavelan device timeout on xmit\n", unit);
1376 sc->wl_ac.ac_if.if_oerrors++;
1383 * This function is the interrupt handler for the WaveLAN
1384 * board. This routine will be called whenever either a packet
1385 * is received, or a packet has successfully been transfered and
1386 * the unit is ready to transmit another packet.
1388 * input : board number that interrupted
1389 * output : either a packet is received, or a packet is transfered
1396 register struct wl_softc *sc = &wl_softc[unit];
1397 short base = sc->base;
1399 u_short int_type, int_type1;
1402 if (sc->wl_if.if_flags & IFF_DEBUG)
1403 printf("wl%d: wlintr() called\n",unit);
1406 if ((int_type = inw(HASR(base))) & HASR_MMC_INTR) {
1407 /* handle interrupt from the modem management controler */
1408 /* This will clear the interrupt condition */
1409 (void) wlmmcread(base,MMC_DCE_STATUS); /* ignored for now */
1412 if (!(int_type & HASR_INTR)){ /* return if no interrupt from 82586 */
1413 /* commented out. jrb. it happens when reinit occurs
1414 printf("wlintr: int_type %x, dump follows\n", int_type);
1423 outw(PIOR0(base), OFFSET_SCB + 0); /* get scb status */
1424 int_type = (inw(PIOP0(base)) & SCB_SW_INT);
1425 if (int_type == 0) /* no interrupts left */
1428 int_type1 = wlack(unit); /* acknowledge interrupt(s) */
1429 /* make sure no bits disappeared (others may appear) */
1430 if ((int_type & int_type1) != int_type)
1431 printf("wlack() int bits disappeared : %04x != int_type %04x\n",
1432 int_type1, int_type);
1433 int_type = int_type1; /* go with the new status */
1437 if (int_type & SCB_SW_FR) {
1438 sc->wl_if.if_ipackets++;
1442 * receiver not ready
1444 if (int_type & SCB_SW_RNR) {
1445 sc->wl_if.if_ierrors++;
1447 if (sc->wl_if.if_flags & IFF_DEBUG)
1448 printf("wl%d intr(): receiver overrun! begin_fd = %x\n",
1449 unit, sc->begin_fd);
1456 if (int_type & SCB_SW_CNA) {
1458 * At present, we don't care about CNA's. We
1459 * believe they are a side effect of XMT.
1462 if (int_type & SCB_SW_CX) {
1464 * At present, we only request Interrupt for
1467 outw(PIOR1(base), OFFSET_CU); /* get command status */
1468 ac_status = inw(PIOP1(base));
1470 if (xmt_watch) { /* report some anomalies */
1472 if (sc->tbusy == 0) {
1473 printf("wl%d: xmt intr but not busy, CU %04x\n",
1476 if (ac_status == 0) {
1477 printf("wl%d: xmt intr but ac_status == 0\n", unit);
1479 if (ac_status & AC_SW_A) {
1480 printf("wl%d: xmt aborted\n",unit);
1483 if (ac_status & TC_CARRIER) {
1484 printf("wl%d: no carrier\n", unit);
1487 if (ac_status & TC_CLS) {
1488 printf("wl%d: no CTS\n", unit);
1490 if (ac_status & TC_DMA) {
1491 printf("wl%d: DMA underrun\n", unit);
1493 if (ac_status & TC_DEFER) {
1494 printf("wl%d: xmt deferred\n",unit);
1496 if (ac_status & TC_SQE) {
1497 printf("wl%d: heart beat\n", unit);
1499 if (ac_status & TC_COLLISION) {
1500 printf("wl%d: too many collisions\n", unit);
1503 /* if the transmit actually failed, or returned some status */
1504 if ((!(ac_status & AC_SW_OK)) || (ac_status & 0xfff)) {
1505 if (ac_status & (TC_COLLISION | TC_CLS | TC_DMA)) {
1506 sc->wl_if.if_oerrors++;
1508 /* count collisions */
1509 sc->wl_if.if_collisions += (ac_status & 0xf);
1510 /* if TC_COLLISION set and collision count zero, 16 collisions */
1511 if ((ac_status & 0x20) == 0x20) {
1512 sc->wl_if.if_collisions += 0x10;
1516 untimeout(wlwatchdog, sc, sc->watchdog_ch);
1517 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
1518 wlstart(&(sc->wl_if));
1527 * This routine is called by the interrupt handler to initiate a
1528 * packet transfer from the board to the "if" layer above this
1529 * driver. This routine checks if a buffer has been successfully
1530 * received by the WaveLAN. If so, the routine wlread is called
1531 * to do the actual transfer of the board data (including the
1532 * ethernet header) into a packet (consisting of an mbuf chain).
1534 * input : number of the board to check
1535 * output : if a packet is available, it is "sent up"
1541 register struct wl_softc *sc = WLSOFTC(unit);
1542 short base = sc->base;
1543 u_short fd_p, status, offset, link_offset;
1546 if (sc->wl_if.if_flags & IFF_DEBUG)
1547 printf("wl%d: entered wlrcv()\n",unit);
1549 for (fd_p = sc->begin_fd; fd_p != I82586NULL; fd_p = sc->begin_fd) {
1551 outw(PIOR0(base), fd_p + 0); /* address of status */
1552 status = inw(PIOP0(base));
1553 outw(PIOR1(base), fd_p + 4); /* address of link_offset */
1554 link_offset = inw(PIOP1(base));
1555 offset = inw(PIOP1(base)); /* rbd_offset */
1556 if (status == 0xffff || offset == 0xffff /*I82586NULL*/) {
1557 if (wlhwrst(unit) != TRUE)
1558 printf("wl%d rcv(): hwrst ffff trouble.\n", unit);
1560 } else if (status & AC_SW_C) {
1561 if (status == (RFD_DONE|RFD_RSC)) {
1564 if (sc->wl_if.if_flags & IFF_DEBUG)
1565 printf("wl%d RCV: RSC %x\n", unit, status);
1567 sc->wl_if.if_ierrors++;
1568 } else if (!(status & RFD_OK)) {
1569 printf("wl%d RCV: !OK %x\n", unit, status);
1570 sc->wl_if.if_ierrors++;
1571 } else if (status & 0xfff) { /* can't happen */
1572 printf("wl%d RCV: ERRs %x\n", unit, status);
1573 sc->wl_if.if_ierrors++;
1574 } else if (!wlread(unit, fd_p))
1577 if (!wlrequeue(unit, fd_p)) {
1578 /* abort on chain error */
1579 if (wlhwrst(unit) != TRUE)
1580 printf("wl%d rcv(): hwrst trouble.\n", unit);
1583 sc->begin_fd = link_offset;
1594 * This routine puts rbd's used in the last receive back onto the
1595 * free list for the next receive.
1599 wlrequeue(int unit, u_short fd_p)
1601 register struct wl_softc *sc = WLSOFTC(unit);
1602 short base = sc->base;
1604 u_short l_rbdp, f_rbdp, rbd_offset;
1606 outw(PIOR0(base), fd_p + 6);
1607 rbd_offset = inw(PIOP0(base));
1608 if ((f_rbdp = rbd_offset) != I82586NULL) {
1611 outw(PIOR0(base), l_rbdp + 0); /* address of status */
1612 if (inw(PIOP0(base)) & RBD_SW_EOF)
1614 outw(PIOP0(base), 0);
1615 outw(PIOR0(base), l_rbdp + 2); /* next_rbd_offset */
1616 if ((l_rbdp = inw(PIOP0(base))) == I82586NULL)
1619 outw(PIOP0(base), 0);
1620 outw(PIOR0(base), l_rbdp + 2); /* next_rbd_offset */
1621 outw(PIOP0(base), I82586NULL);
1622 outw(PIOR0(base), l_rbdp + 8); /* address of size */
1623 outw(PIOP0(base), inw(PIOP0(base)) | AC_CW_EL);
1624 outw(PIOR0(base), sc->end_rbd + 2);
1625 outw(PIOP0(base), f_rbdp); /* end_rbd->next_rbd_offset */
1626 outw(PIOR0(base), sc->end_rbd + 8); /* size */
1627 outw(PIOP0(base), inw(PIOP0(base)) & ~AC_CW_EL);
1628 sc->end_rbd = l_rbdp;
1632 fd.command = AC_CW_EL;
1633 fd.link_offset = I82586NULL;
1634 fd.rbd_offset = I82586NULL;
1635 outw(PIOR1(base), fd_p);
1636 outsw(PIOP1(base), &fd, 8/2);
1638 outw(PIOR1(base), sc->end_fd + 2); /* addr of command */
1639 outw(PIOP1(base), 0); /* command = 0 */
1640 outw(PIOP1(base), fd_p); /* end_fd->link_offset = fd_p */
1647 static int xmt_debug = 0;
1648 #endif /* WLDEBUG */
1653 * This routine fills in the appropriate registers and memory
1654 * locations on the WaveLAN board and starts the board off on
1657 * input : board number of interest, and a pointer to the mbuf
1658 * output : board memory and registers are set for xfer and attention
1662 wlxmt(int unit, struct mbuf *m)
1664 register struct wl_softc *sc = WLSOFTC(unit);
1665 register u_short xmtdata_p = OFFSET_TBUF;
1666 register u_short xmtshort_p;
1667 struct mbuf *tm_p = m;
1668 register struct ether_header *eh_p = mtod(m, struct ether_header *);
1669 u_char *mb_p = mtod(m, u_char *) + sizeof(struct ether_header);
1670 u_short count = m->m_len - sizeof(struct ether_header);
1672 u_short tbd_p = OFFSET_TBD;
1673 u_short len, clen = 0;
1674 short base = sc->base;
1678 if (sc->wl_if.if_flags & IFF_DEBUG)
1679 printf("wl%d: entered wlxmt()\n",unit);
1683 cb.ac_command = (AC_CW_EL|AC_TRANSMIT|AC_CW_I);
1684 cb.ac_link_offset = I82586NULL;
1685 outw(PIOR1(base), OFFSET_CU);
1686 outsw(PIOP1(base), &cb, 6/2);
1687 outw(PIOP1(base), OFFSET_TBD); /* cb.cmd.transmit.tbd_offset */
1688 outsw(PIOP1(base), eh_p->ether_dhost, WAVELAN_ADDR_SIZE/2);
1689 outw(PIOP1(base), eh_p->ether_type);
1692 if (sc->wl_if.if_flags & IFF_DEBUG) {
1694 printf("XMT mbuf: L%d @%p ", count, (void *)mb_p);
1695 printf("ether type %x\n", eh_p->ether_type);
1698 #endif /* WLDEBUG */
1699 outw(PIOR0(base), OFFSET_TBD);
1700 outw(PIOP0(base), 0); /* act_count */
1701 outw(PIOR1(base), OFFSET_TBD + 4);
1702 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1703 outw(PIOP1(base), 0); /* buffer_base */
1706 if (clen + count > WAVELAN_MTU)
1712 outw(PIOR1(base), xmtdata_p);
1713 outsw(PIOP1(base), mb_p, len/2);
1715 outw(PIOR0(base), tbd_p); /* address of act_count */
1716 outw(PIOP0(base), inw(PIOP0(base)) + count);
1718 if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1721 /* go to the next descriptor */
1722 outw(PIOR0(base), tbd_p + 2);
1723 tbd_p += sizeof (tbd_t);
1724 outw(PIOP0(base), tbd_p); /* next_tbd_offset */
1725 outw(PIOR0(base), tbd_p);
1726 outw(PIOP0(base), 0); /* act_count */
1727 outw(PIOR1(base), tbd_p + 4);
1728 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1729 outw(PIOP1(base), 0); /* buffer_base */
1730 /* at the end -> coallesce remaining mbufs */
1731 if (tbd_p == OFFSET_TBD + (N_TBD-1) * sizeof (tbd_t)) {
1732 wlsftwsleaze(&count, &mb_p, &tm_p, unit);
1735 /* next mbuf short -> coallesce as needed */
1736 if ( (tm_p->m_next == (struct mbuf *) 0) ||
1737 #define HDW_THRESHOLD 55
1738 tm_p->m_len > HDW_THRESHOLD)
1741 wlhdwsleaze(&count, &mb_p, &tm_p, unit);
1745 } else if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1747 count = tm_p->m_len;
1748 mb_p = mtod(tm_p, u_char *);
1750 if (sc->wl_if.if_flags & IFF_DEBUG)
1752 printf("mbuf+ L%d @%p ", count, (void *)mb_p);
1753 #endif /* WLDEBUG */
1756 if (sc->wl_if.if_flags & IFF_DEBUG)
1758 printf("CLEN = %d\n", clen);
1759 #endif /* WLDEBUG */
1760 outw(PIOR0(base), tbd_p);
1761 if (clen < ETHERMIN) {
1762 outw(PIOP0(base), inw(PIOP0(base)) + ETHERMIN - clen);
1763 outw(PIOR1(base), xmtdata_p);
1764 for (xmtshort_p = xmtdata_p; clen < ETHERMIN; clen += 2)
1765 outw(PIOP1(base), 0);
1767 outw(PIOP0(base), inw(PIOP0(base)) | TBD_SW_EOF);
1768 outw(PIOR0(base), tbd_p + 2);
1769 outw(PIOP0(base), I82586NULL);
1771 if (sc->wl_if.if_flags & IFF_DEBUG) {
1777 #endif /* WLDEBUG */
1779 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
1781 * wait for 586 to clear previous command, complain if it takes
1784 for (spin = 1;;spin = (spin + 1) % 10000) {
1785 if (inw(PIOP0(base)) == 0) { /* it's done, we can go */
1788 if ((spin == 0) && xmt_watch) { /* not waking up, and we care */
1789 printf("wl%d: slow accepting xmit\n",unit);
1792 outw(PIOP0(base), SCB_CU_STRT); /* new command */
1793 SET_CHAN_ATTN(unit);
1798 * Pause to avoid transmit overrun problems.
1799 * The required delay tends to vary with platform type, and may be
1800 * related to interrupt loss.
1802 if (wl_xmit_delay) {
1803 DELAY(wl_xmit_delay);
1811 * This function builds the linear linked lists of fd's and
1812 * rbd's. Based on page 4-32 of 1986 Intel microcom handbook.
1818 register struct wl_softc *sc = WLSOFTC(unit);
1819 short base = sc->base;
1822 u_short fd_p = OFFSET_RU;
1823 u_short rbd_p = OFFSET_RBD;
1826 sc->begin_fd = fd_p;
1827 for (i = 0; i < N_FD; i++) {
1830 fd.link_offset = fd_p + sizeof(fd_t);
1831 fd.rbd_offset = I82586NULL;
1832 outw(PIOR1(base), fd_p);
1833 outsw(PIOP1(base), &fd, 8/2);
1834 fd_p = fd.link_offset;
1836 fd_p -= sizeof(fd_t);
1838 outw(PIOR1(base), fd_p + 2);
1839 outw(PIOP1(base), AC_CW_EL); /* command */
1840 outw(PIOP1(base), I82586NULL); /* link_offset */
1843 outw(PIOR0(base), fd_p + 6); /* address of rbd_offset */
1844 outw(PIOP0(base), rbd_p);
1845 outw(PIOR1(base), rbd_p);
1846 for (i = 0; i < N_RBD; i++) {
1848 rbd.buffer_addr = rbd_p + sizeof(rbd_t) + 2;
1849 rbd.buffer_base = 0;
1850 rbd.size = RCVBUFSIZE;
1852 rbd_p += sizeof(ru_t);
1853 rbd.next_rbd_offset = rbd_p;
1855 rbd.next_rbd_offset = I82586NULL;
1856 rbd.size |= AC_CW_EL;
1857 sc->end_rbd = rbd_p;
1859 outsw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1860 outw(PIOR1(base), rbd_p);
1862 return sc->begin_fd;
1868 * This routine starts the receive unit running. First checks if the
1869 * board is actually ready, then the board is instructed to receive
1876 register struct wl_softc *sc = WLSOFTC(unit);
1877 short base = sc->base;
1881 if (sc->wl_if.if_flags & IFF_DEBUG)
1882 printf("wl%d: entered wlrustrt()\n",unit);
1884 outw(PIOR0(base), OFFSET_SCB);
1885 if (inw(PIOP0(base)) & SCB_RUS_READY){
1886 printf("wlrustrt: RUS_READY\n");
1890 outw(PIOR0(base), OFFSET_SCB + 2);
1891 outw(PIOP0(base), SCB_RU_STRT); /* command */
1892 rfa = wlbldru(unit);
1893 outw(PIOR0(base), OFFSET_SCB + 6); /* address of scb_rfa_offset */
1894 outw(PIOP0(base), rfa);
1896 SET_CHAN_ATTN(unit);
1903 * This routine does a 586 op-code number 7, and obtains the
1904 * diagnose status for the WaveLAN.
1910 register struct wl_softc *sc = WLSOFTC(unit);
1911 short base = sc->base;
1915 if (sc->wl_if.if_flags & IFF_DEBUG)
1916 printf("wl%d: entered wldiag()\n",unit);
1918 outw(PIOR0(base), OFFSET_SCB);
1919 status = inw(PIOP0(base));
1920 if (status & SCB_SW_INT) {
1921 /* state is 2000 which seems ok
1922 printf("wl%d diag(): unexpected initial state %\n",
1923 unit, inw(PIOP0(base)));
1927 outw(PIOR1(base), OFFSET_CU);
1928 outw(PIOP1(base), 0); /* ac_status */
1929 outw(PIOP1(base), AC_DIAGNOSE|AC_CW_EL);/* ac_command */
1930 if (wlcmd(unit, "diag()") == 0)
1932 outw(PIOR0(base), OFFSET_CU);
1933 if (inw(PIOP0(base)) & 0x0800) {
1934 printf("wl%d: i82586 Self Test failed!\n", unit);
1943 * This routine does a standard config of the WaveLAN board.
1949 configure_t configure;
1950 register struct wl_softc *sc = WLSOFTC(unit);
1951 short base = sc->base;
1954 struct ifmultiaddr *ifma;
1957 #endif /* MULTICAST */
1960 if (sc->wl_if.if_flags & IFF_DEBUG)
1961 printf("wl%d: entered wlconfig()\n",unit);
1963 outw(PIOR0(base), OFFSET_SCB);
1964 if (inw(PIOP0(base)) & SCB_SW_INT) {
1966 printf("wl%d config(): unexpected initial state %x\n",
1967 unit, inw(PIOP0(base)));
1972 outw(PIOR1(base), OFFSET_CU);
1973 outw(PIOP1(base), 0); /* ac_status */
1974 outw(PIOP1(base), AC_CONFIGURE|AC_CW_EL); /* ac_command */
1977 configure.fifolim_bytecnt = 0x080c;
1978 configure.addrlen_mode = 0x0600;
1979 configure.linprio_interframe = 0x2060;
1980 configure.slot_time = 0xf200;
1981 configure.hardware = 0x0008; /* tx even w/o CD */
1982 configure.min_frame_len = 0x0040;
1984 /* This is the configuration block suggested by Marc Meertens
1985 * <mmeerten@obelix.utrecht.NCR.COM> in an e-mail message to John
1986 * Ioannidis on 10 Nov 92.
1988 configure.fifolim_bytecnt = 0x040c;
1989 configure.addrlen_mode = 0x0600;
1990 configure.linprio_interframe = 0x2060;
1991 configure.slot_time = 0xf000;
1992 configure.hardware = 0x0008; /* tx even w/o CD */
1993 configure.min_frame_len = 0x0040;
1996 * below is the default board configuration from p2-28 from 586 book
1998 configure.fifolim_bytecnt = 0x080c;
1999 configure.addrlen_mode = 0x2600;
2000 configure.linprio_interframe = 0x7820; /* IFS=120, ACS=2 */
2001 configure.slot_time = 0xf00c; /* slottime=12 */
2002 configure.hardware = 0x0008; /* tx even w/o CD */
2003 configure.min_frame_len = 0x0040;
2005 if (sc->mode & (MOD_PROM | MOD_ENAL))
2006 configure.hardware |= 1;
2007 outw(PIOR1(base), OFFSET_CU + 6);
2008 outsw(PIOP1(base), &configure, sizeof(configure_t)/2);
2010 if (wlcmd(unit, "config()-configure") == 0)
2013 outw(PIOR1(base), OFFSET_CU);
2014 outw(PIOP1(base), 0); /* ac_status */
2015 outw(PIOP1(base), AC_MCSETUP|AC_CW_EL); /* ac_command */
2016 outw(PIOR1(base), OFFSET_CU + 8);
2017 TAILQ_FOREACH(ifma, &sc->wl_if.if_multiaddrs, ifma_link) {
2018 if (ifma->ifma_addr->sa_family != AF_LINK)
2021 addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
2022 outw(PIOP1(base), addrp[0] + (addrp[1] << 8));
2023 outw(PIOP1(base), addrp[2] + (addrp[3] << 8));
2024 outw(PIOP1(base), addrp[4] + (addrp[5] << 8));
2027 outw(PIOR1(base), OFFSET_CU + 6); /* mc-cnt */
2028 outw(PIOP1(base), cnt * WAVELAN_ADDR_SIZE);
2029 if (wlcmd(unit, "config()-mcaddress") == 0)
2031 #endif /* MULTICAST */
2033 outw(PIOR1(base), OFFSET_CU);
2034 outw(PIOP1(base), 0); /* ac_status */
2035 outw(PIOP1(base), AC_IASETUP|AC_CW_EL); /* ac_command */
2036 outw(PIOR1(base), OFFSET_CU + 6);
2037 outsw(PIOP1(base), sc->wl_addr, WAVELAN_ADDR_SIZE/2);
2039 if (wlcmd(unit, "config()-address") == 0)
2050 * Set channel attention bit and busy wait until command has
2051 * completed. Then acknowledge the command completion.
2054 wlcmd(int unit, char *str)
2056 register struct wl_softc *sc = WLSOFTC(unit);
2057 short base = sc->base;
2060 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
2061 outw(PIOP0(base), SCB_CU_STRT);
2063 SET_CHAN_ATTN(unit);
2065 outw(PIOR0(base), OFFSET_CU);
2066 for (i = 0; i < 0xffff; i++)
2067 if (inw(PIOP0(base)) & AC_SW_C)
2069 if (i == 0xffff || !(inw(PIOP0(base)) & AC_SW_OK)) {
2070 printf("wl%d: %s failed; status = %d, inw = %x, outw = %x\n",
2071 unit, str, inw(PIOP0(base)) & AC_SW_OK, inw(PIOP0(base)), inw(PIOR0(base)));
2072 outw(PIOR0(base), OFFSET_SCB);
2073 printf("scb_status %x\n", inw(PIOP0(base)));
2074 outw(PIOR0(base), OFFSET_SCB+2);
2075 printf("scb_command %x\n", inw(PIOP0(base)));
2076 outw(PIOR0(base), OFFSET_SCB+4);
2077 printf("scb_cbl %x\n", inw(PIOP0(base)));
2078 outw(PIOR0(base), OFFSET_CU+2);
2079 printf("cu_cmd %x\n", inw(PIOP0(base)));
2083 outw(PIOR0(base), OFFSET_SCB);
2084 if ((inw(PIOP0(base)) & SCB_SW_INT) && (inw(PIOP0(base)) != SCB_SW_CNA)) {
2086 printf("wl%d %s: unexpected final state %x\n",
2087 unit, str, inw(PIOP0(base)));
2095 * wlack: if the 82596 wants attention because it has finished
2096 * sending or receiving a packet, acknowledge its desire and
2097 * return bits indicating the kind of attention. wlack() returns
2098 * these bits so that the caller can service exactly the
2099 * conditions that wlack() acknowledged.
2105 register u_short cmd;
2106 register struct wl_softc *sc = WLSOFTC(unit);
2107 short base = sc->base;
2109 outw(PIOR1(base), OFFSET_SCB);
2110 if (!(cmd = (inw(PIOP1(base)) & SCB_SW_INT)))
2113 if (sc->wl_if.if_flags & IFF_DEBUG)
2114 printf("wl%d: doing a wlack()\n",unit);
2116 outw(PIOP1(base), cmd);
2117 SET_CHAN_ATTN(unit);
2118 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
2119 for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); )
2122 printf("wl%d wlack(): board not accepting command.\n", unit);
2130 register struct wl_softc *sc = WLSOFTC(unit);
2131 short base = sc->base;
2132 u_short tbd_p = OFFSET_TBD;
2138 outw(PIOR1(base), tbd_p);
2139 insw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
2140 sum += (tbd.act_count & ~TBD_SW_EOF);
2141 printf("%d: addr %x, count %d (%d), next %x, base %x\n",
2142 i++, tbd.buffer_addr,
2143 (tbd.act_count & ~TBD_SW_EOF), sum,
2144 tbd.next_tbd_offset, tbd.buffer_base);
2145 if (tbd.act_count & TBD_SW_EOF)
2147 tbd_p = tbd.next_tbd_offset;
2153 wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2155 struct mbuf *tm_p = *tm_pp;
2156 u_char *mb_p = *mb_pp;
2162 * can we get a run that will be coallesced or
2163 * that terminates before breaking
2166 count += tm_p->m_len;
2167 if (tm_p->m_len & 1)
2169 } while ((tm_p = tm_p->m_next) != (struct mbuf *)0);
2170 if ( (tm_p == (struct mbuf *)0) ||
2171 count > HDW_THRESHOLD) {
2172 *countp = (*tm_pp)->m_len;
2173 *mb_pp = mtod((*tm_pp), u_char *);
2177 /* we need to copy */
2181 cp = (u_char *) t_packet;
2183 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2185 if (count > HDW_THRESHOLD)
2188 if (tm_p->m_next == (struct mbuf *)0)
2190 tm_p = tm_p->m_next;
2193 *mb_pp = (u_char *) t_packet;
2200 wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2202 struct mbuf *tm_p = *tm_pp;
2204 u_char *cp = (u_char *) t_packet;
2207 /* we need to copy */
2209 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2212 if (tm_p->m_next == (struct mbuf *)0)
2214 tm_p = tm_p->m_next;
2218 *mb_pp = (u_char *) t_packet;
2226 register struct wl_softc *sc = WLSOFTC(unit);
2227 short base = sc->base;
2230 printf("wl%d: DCE_STATUS: 0x%x, ", unit,
2231 wlmmcread(base,MMC_DCE_STATUS) & 0x0f);
2232 tmp = wlmmcread(base,MMC_CORRECT_NWID_H) << 8;
2233 tmp |= wlmmcread(base,MMC_CORRECT_NWID_L);
2234 printf("Correct NWID's: %d, ", tmp);
2235 tmp = wlmmcread(base,MMC_WRONG_NWID_H) << 8;
2236 tmp |= wlmmcread(base,MMC_WRONG_NWID_L);
2237 printf("Wrong NWID's: %d\n", tmp);
2238 printf("THR_PRE_SET: 0x%x, ", wlmmcread(base,MMC_THR_PRE_SET));
2239 printf("SIGNAL_LVL: %d, SILENCE_LVL: %d\n",
2240 wlmmcread(base,MMC_SIGNAL_LVL),
2241 wlmmcread(base,MMC_SILENCE_LVL));
2242 printf("SIGN_QUAL: 0x%x, NETW_ID: %x:%x, DES: %d\n",
2243 wlmmcread(base,MMC_SIGN_QUAL),
2244 wlmmcread(base,MMC_NETW_ID_H),
2245 wlmmcread(base,MMC_NETW_ID_L),
2246 wlmmcread(base,MMC_DES_AVAIL));
2250 wlmmcread(u_int base, u_short reg)
2252 while (inw(HASR(base)) & HASR_MMC_BUSY)
2254 outw(MMCR(base),reg << 1);
2255 while (inw(HASR(base)) & HASR_MMC_BUSY)
2257 return (u_short)inw(MMCR(base)) >> 8;
2263 MMC_WRITE(MMC_FREEZE,1);
2265 * SNR retrieval procedure :
2267 * read signal level : wlmmcread(base, MMC_SIGNAL_LVL);
2268 * read silence level : wlmmcread(base, MMC_SILENCE_LVL);
2270 MMC_WRITE(MMC_FREEZE,0);
2272 * SNR is signal:silence ratio.
2279 ** Reads the psa for the wavelan at (base) into (buf)
2282 wlgetpsa(int base, u_char *buf)
2286 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2287 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2289 for (i = 0; i < 0x40; i++) {
2290 outw(PIOR2(base), i);
2291 buf[i] = inb(PIOP2(base));
2293 PCMD(base, HACR_DEFAULT);
2294 PCMD(base, HACR_DEFAULT);
2300 ** Writes the psa for wavelan (unit) from the softc back to the
2301 ** board. Updates the CRC and sets the CRC OK flag.
2303 ** Do not call this when the board is operating, as it doesn't
2304 ** preserve the hacr.
2309 register struct wl_softc *sc = WLSOFTC(unit);
2310 short base = sc->base;
2314 crc = wlpsacrc(sc->psa); /* calculate CRC of PSA */
2315 sc->psa[WLPSA_CRCLOW] = crc & 0xff;
2316 sc->psa[WLPSA_CRCHIGH] = (crc >> 8) & 0xff;
2317 sc->psa[WLPSA_CRCOK] = 0x55; /* default to 'bad' until programming complete */
2319 oldpri = splimp(); /* ick, long pause */
2321 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2322 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2324 for (i = 0; i < 0x40; i++) {
2326 outw(PIOR2(base),i); /* write param memory */
2328 outb(PIOP2(base), sc->psa[i]);
2331 outw(PIOR2(base),WLPSA_CRCOK); /* update CRC flag*/
2333 sc->psa[WLPSA_CRCOK] = 0xaa; /* OK now */
2334 outb(PIOP2(base), 0xaa); /* all OK */
2337 PCMD(base, HACR_DEFAULT);
2338 PCMD(base, HACR_DEFAULT);
2344 ** CRC routine provided by Christopher Giordano <cgiordan@gdeb.com>,
2345 ** from original code by Tomi Mikkonen (tomitm@remedy.fi)
2348 static u_int crc16_table[16] = {
2349 0x0000, 0xCC01, 0xD801, 0x1400,
2350 0xF001, 0x3C00, 0x2800, 0xE401,
2351 0xA001, 0x6C00, 0x7800, 0xB401,
2352 0x5000, 0x9C01, 0x8801, 0x4400
2356 wlpsacrc(u_char *buf)
2361 for (i = 0; i < 0x3d; i++, buf++) {
2363 r1 = crc16_table[crc & 0xF];
2364 crc = (crc >> 4) & 0x0FFF;
2365 crc = crc ^ r1 ^ crc16_table[*buf & 0xF];
2368 r1 = crc16_table[crc & 0xF];
2369 crc = (crc >> 4) & 0x0FFF;
2370 crc = crc ^ r1 ^ crc16_table[(*buf >> 4) & 0xF];
2379 * take input packet and cache various radio hw characteristics
2380 * indexed by MAC address.
2382 * Some things to think about:
2383 * note that no space is malloced.
2384 * We might hash the mac address if the cache were bigger.
2385 * It is not clear that the cache is big enough.
2386 * It is also not clear how big it should be.
2387 * The cache is IP-specific. We don't care about that as
2388 * we want it to be IP-specific.
2389 * The last N recv. packets are saved. This will tend
2390 * to reward agents and mobile hosts that beacon.
2391 * That is probably fine for mobile ip.
2394 /* globals for wavelan signal strength cache */
2395 /* this should go into softc structure above.
2398 /* set true if you want to limit cache items to broadcast/mcast
2399 * only packets (not unicast)
2401 static int wl_cache_mcastonly = 1;
2402 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_mcastonly, CTLFLAG_RW,
2403 &wl_cache_mcastonly, 0, "");
2405 /* set true if you want to limit cache items to IP packets only
2407 static int wl_cache_iponly = 1;
2408 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_iponly, CTLFLAG_RW,
2409 &wl_cache_iponly, 0, "");
2411 /* zero out the cache
2414 wl_cache_zero(int unit)
2416 register struct wl_softc *sc = WLSOFTC(unit);
2418 bzero(&sc->w_sigcache[0], sizeof(struct w_sigcache) * MAXCACHEITEMS);
2420 sc->w_nextcache = 0;
2421 sc->w_wrapindex = 0;
2424 /* store hw signal info in cache.
2425 * index is MAC address, but an ip src gets stored too
2426 * There are two filters here controllable via sysctl:
2427 * throw out unicast (on by default, but can be turned off)
2428 * throw out non-ip (on by default, but can be turned off)
2431 void wl_cache_store (int unit, int base, struct ether_header *eh,
2434 struct ip *ip = NULL; /* Avoid GCC warning */
2436 int signal, silence;
2437 int w_insertcache; /* computed index for cache entry storage */
2438 register struct wl_softc *sc = WLSOFTC(unit);
2439 int ipflag = wl_cache_iponly;
2443 * 2. configurable filter to throw out unicast packets,
2444 * keep multicast only.
2448 /* reject if not IP packet
2450 if ( wl_cache_iponly && (ntohs(eh->ether_type) != 0x800)) {
2454 /* check if broadcast or multicast packet. we toss
2457 if (wl_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
2461 /* find the ip header. we want to store the ip_src
2462 * address. use the mtod macro(in mbuf.h)
2463 * to typecast m to struct ip *
2466 ip = mtod(m, struct ip *);
2469 /* do a linear search for a matching MAC address
2470 * in the cache table
2471 * . MAC address is 6 bytes,
2472 * . var w_nextcache holds total number of entries already cached
2474 for (i = 0; i < sc->w_nextcache; i++) {
2475 if (! bcmp(eh->ether_shost, sc->w_sigcache[i].macsrc, 6 )) {
2477 * so we already have this entry,
2478 * update the data, and LRU age
2484 /* did we find a matching mac address?
2485 * if yes, then overwrite a previously existing cache entry
2487 if (i < sc->w_nextcache ) {
2490 /* else, have a new address entry,so
2491 * add this new entry,
2492 * if table full, then we need to replace entry
2496 /* check for space in cache table
2497 * note: w_nextcache also holds number of entries
2498 * added in the cache table
2500 if ( sc->w_nextcache < MAXCACHEITEMS ) {
2501 w_insertcache = sc->w_nextcache;
2503 sc->w_sigitems = sc->w_nextcache;
2505 /* no space found, so simply wrap with wrap index
2506 * and "zap" the next entry
2509 if (sc->w_wrapindex == MAXCACHEITEMS) {
2510 sc->w_wrapindex = 0;
2512 w_insertcache = sc->w_wrapindex++;
2516 /* invariant: w_insertcache now points at some slot
2519 if (w_insertcache < 0 || w_insertcache >= MAXCACHEITEMS) {
2521 "wl_cache_store, bad index: %d of [0..%d], gross cache error\n",
2522 w_insertcache, MAXCACHEITEMS);
2526 /* store items in cache
2529 * .signal (0..63) ,silence (0..63) ,quality (0..15)
2532 sc->w_sigcache[w_insertcache].ipsrc = ip->ip_src.s_addr;
2534 bcopy( eh->ether_shost, sc->w_sigcache[w_insertcache].macsrc, 6);
2535 signal = sc->w_sigcache[w_insertcache].signal = wlmmcread(base, MMC_SIGNAL_LVL) & 0x3f;
2536 silence = sc->w_sigcache[w_insertcache].silence = wlmmcread(base, MMC_SILENCE_LVL) & 0x3f;
2537 sc->w_sigcache[w_insertcache].quality = wlmmcread(base, MMC_SIGN_QUAL) & 0x0f;
2539 sc->w_sigcache[w_insertcache].snr =
2542 sc->w_sigcache[w_insertcache].snr = 0;
2546 #endif /* WLCACHE */