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 withough 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/sockio.h>
198 #include <sys/mbuf.h>
199 #include <sys/socket.h>
200 #include <sys/syslog.h>
201 #include <sys/proc.h>
203 #include <sys/kernel.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>
219 #include <machine/clock.h>
221 #include <i386/isa/isa_device.h>
223 #include <i386/isa/ic/if_wl_i82586.h> /* Definitions for the Intel chip */
225 /* was 1000 in original, fed to DELAY(x) */
226 #define DELAYCONST 1000
227 #include <i386/isa/if_wl.h>
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 struct isa_driver wldriver = {
266 wlprobe, wlattach, "wl", 0
270 * XXX The Wavelan appears to be prone to dropping stuff if you talk to
271 * it too fast. This disgusting hack inserts a delay after each packet
272 * is queued which helps avoid this behaviour on fast systems.
274 static int wl_xmit_delay = 250;
275 SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_delay, CTLFLAG_RW, &wl_xmit_delay, 0, "");
278 * not XXX, but ZZZ (bizarre).
279 * promiscuous mode can be toggled to ignore NWIDs. By default,
280 * it does not. Caution should be exercised about combining
281 * this mode with IFF_ALLMULTI which puts this driver in
284 static int wl_ignore_nwid = 0;
285 SYSCTL_INT(_machdep, OID_AUTO, wl_ignore_nwid, CTLFLAG_RW, &wl_ignore_nwid, 0, "");
288 * Emit diagnostics about transmission problems
290 static int xmt_watch = 0;
291 SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_watch, CTLFLAG_RW, &xmt_watch, 0, "");
294 * Collect SNR statistics
296 static int gathersnr = 0;
297 SYSCTL_INT(_machdep, OID_AUTO, wl_gather_snr, CTLFLAG_RW, &gathersnr, 0, "");
299 static void wlstart(struct ifnet *ifp);
300 static void wlinit(void *xsc);
301 static int wlioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
302 static timeout_t wlwatchdog;
303 static ointhand2_t wlintr;
304 static void wlxmt(int unt, struct mbuf *m);
305 static int wldiag(int unt);
306 static int wlconfig(int unit);
307 static int wlcmd(int unit, char *str);
308 static void wlmmcstat(int unit);
309 static u_short wlbldru(int unit);
310 static u_short wlmmcread(u_int base, u_short reg);
311 static void wlinitmmc(int unit);
312 static int wlhwrst(int unit);
313 static void wlrustrt(int unit);
314 static void wlbldcu(int unit);
315 static int wlack(int unit);
316 static int wlread(int unit, u_short fd_p);
317 static void getsnr(int unit);
318 static void wlrcv(int unit);
319 static int wlrequeue(int unit, u_short fd_p);
320 static void wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
321 static void wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
322 static void wltbd(int unit);
323 static void wlgetpsa(int base, u_char *buf);
324 static void wlsetpsa(int unit);
325 static u_short wlpsacrc(u_char *buf);
326 static void wldump(int unit);
328 static void wl_cache_store(int, int, struct ether_header *, struct mbuf *);
329 static void wl_cache_zero(int unit);
332 # if defined(__FreeBSD__) && __FreeBSD_version < 300000
333 static int check_allmulti(int unit);
337 /* array for maping irq numbers to values for the irq parameter register */
338 static int irqvals[16] = {
339 0, 0, 0, 0x01, 0x02, 0x04, 0, 0x08, 0, 0, 0x10, 0x20, 0x40, 0, 0, 0x80
341 /* mask of valid IRQs */
342 #define WL_IRQS (IRQ3|IRQ4|IRQ5|IRQ7|IRQ10|IRQ11|IRQ12|IRQ15)
347 * This function "probes" or checks for the WaveLAN board on the bus to
348 * see if it is there. As far as I can tell, the best break between this
349 * routine and the attach code is to simply determine whether the board
350 * is configured in properly. Currently my approach to this is to write
351 * and read a word from the SRAM on the board being probed. If the word
352 * comes back properly then we assume the board is there. The config
353 * code expects to see a successful return from the probe routine before
354 * attach will be called.
356 * input : address device is mapped to, and unit # being checked
357 * output : a '1' is returned if the board exists, and a 0 otherwise
361 wlprobe(struct isa_device *id)
363 struct wl_softc *sc = &wl_softc[id->id_unit];
364 register short base = id->id_iobase;
365 char *str = "wl%d: board out of range [0..%d]\n";
367 unsigned long oldpri;
371 * regular CMD() will not work, since no softc yet
373 #define PCMD(base, hacr) outw((base), (hacr))
376 PCMD(base, HACR_RESET); /* reset the board */
377 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
378 PCMD(base, HACR_RESET); /* reset the board */
379 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
382 /* clear reset command and set PIO#1 in autoincrement mode */
383 PCMD(base, HACR_DEFAULT);
384 PCMD(base, HACR_DEFAULT);
385 outw(PIOR1(base), 0); /* go to beginning of RAM */
386 outsw(PIOP1(base), str, strlen(str)/2+1); /* write string */
388 outw(PIOR1(base), 0); /* rewind */
389 insw(PIOP1(base), inbuf, strlen(str)/2+1); /* read result */
391 if (bcmp(str, inbuf, strlen(str)))
394 sc->chan24 = 0; /* 2.4 Gz: config channel */
395 sc->freq24 = 0; /* 2.4 Gz: frequency */
397 /* read the PSA from the board into temporary storage */
398 wlgetpsa(base, inbuf);
400 /* We read the IRQ value from the PSA on the board. */
401 for (irq = 15; irq >= 0; irq--)
402 if (irqvals[irq] == inbuf[WLPSA_IRQNO])
404 if ((irq == 0) || (irqvals[irq] == 0)){
405 printf("wl%d: PSA corrupt (invalid IRQ value)\n", id->id_unit);
406 id->id_irq = 0; /* no interrupt */
409 * If the IRQ requested by the PSA is already claimed by another
410 * device, the board won't work, but the user can still access the
411 * driver to change the IRQ.
413 id->id_irq = (1<<irq); /* use IRQ from PSA */
422 * This function attaches a WaveLAN board to the "system". The rest of
423 * runtime structures are initialized here (this routine is called after
424 * a successful probe of the board). Once the ethernet address is read
425 * and stored, the board's ifnet structure is attached and readied.
427 * input : isa_dev structure setup in autoconfig
428 * output : board structs and ifnet is setup
432 wlattach(struct isa_device *id)
434 struct wl_softc *sc = (struct wl_softc *) &wl_softc[id->id_unit];
435 register short base = id->id_iobase;
437 u_char unit = id->id_unit;
438 register struct ifnet *ifp = &sc->wl_if;
441 printf("wlattach: base %x, unit %d\n", base, unit);
443 id->id_ointr = wlintr;
448 sc->hacr = HACR_RESET;
449 callout_handle_init(&sc->watchdog_ch);
450 CMD(unit); /* reset the board */
451 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
453 /* clear reset command and set PIO#2 in parameter access mode */
454 sc->hacr = (HACR_DEFAULT & ~HACR_16BITS);
457 /* Read the PSA from the board for our later reference */
458 wlgetpsa(base, sc->psa);
461 sc->nwid[0] = sc->psa[WLPSA_NWID];
462 sc->nwid[1] = sc->psa[WLPSA_NWID+1];
464 /* fetch MAC address - decide which one first */
465 if (sc->psa[WLPSA_MACSEL] & 1) {
470 for(i=0; i < WAVELAN_ADDR_SIZE; ++i) {
471 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 */
511 bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
513 bcopy(&sc->wl_addr[0], sc->wl_ac.ac_enaddr, WAVELAN_ADDR_SIZE);
514 printf("%s%d: address %6D, NWID 0x%02x%02x", ifp->if_name, ifp->if_unit,
515 sc->wl_ac.ac_enaddr, ":", sc->nwid[0], sc->nwid[1]);
517 printf(", Freq %d MHz",sc->freq24); /* 2.4 Gz */
518 printf("\n"); /* 2.4 Gz */
527 * Print out interesting information about the 82596.
532 register struct wl_softc *sp = WLSOFTC(unit);
536 printf("hasr %04x\n", inw(HASR(base)));
538 printf("scb at %04x:\n ", OFFSET_SCB);
539 outw(PIOR1(base), OFFSET_SCB);
540 for(i = 0; i < 8; i++)
541 printf("%04x ", inw(PIOP1(base)));
544 printf("cu at %04x:\n ", OFFSET_CU);
545 outw(PIOR1(base), OFFSET_CU);
546 for(i = 0; i < 8; i++)
547 printf("%04x ", inw(PIOP1(base)));
550 printf("tbd at %04x:\n ", OFFSET_TBD);
551 outw(PIOR1(base), OFFSET_TBD);
552 for(i = 0; i < 4; i++)
553 printf("%04x ", inw(PIOP1(base)));
557 /* Initialize the Modem Management Controller */
561 register struct wl_softc *sp = WLSOFTC(unit);
567 /* enter 8 bit operation */
568 sp->hacr = (HACR_DEFAULT & ~HACR_16BITS);
571 configured = sp->psa[WLPSA_CONFIGURED] & 1;
574 * Set default modem control parameters. Taken from NCR document
577 MMC_WRITE(MMC_JABBER_ENABLE, 0x01);
578 MMC_WRITE(MMC_ANTEN_SEL, 0x02);
579 MMC_WRITE(MMC_IFS, 0x20);
580 MMC_WRITE(MMC_MOD_DELAY, 0x04);
581 MMC_WRITE(MMC_JAM_TIME, 0x38);
582 MMC_WRITE(MMC_DECAY_PRM, 0x00); /* obsolete ? */
583 MMC_WRITE(MMC_DECAY_UPDAT_PRM, 0x00);
585 MMC_WRITE(MMC_LOOPT_SEL, 0x00);
586 if (sp->psa[WLPSA_COMPATNO] & 1) {
587 MMC_WRITE(MMC_THR_PRE_SET, 0x01); /* 0x04 for AT and 0x01 for MCA */
589 MMC_WRITE(MMC_THR_PRE_SET, 0x04); /* 0x04 for AT and 0x01 for MCA */
591 MMC_WRITE(MMC_QUALITY_THR, 0x03);
593 /* use configuration defaults from parameter storage area */
594 if (sp->psa[WLPSA_NWIDENABLE] & 1) {
595 if ((mode & (MOD_PROM | MOD_ENAL)) && wl_ignore_nwid) {
596 MMC_WRITE(MMC_LOOPT_SEL, 0x40);
598 MMC_WRITE(MMC_LOOPT_SEL, 0x00);
601 MMC_WRITE(MMC_LOOPT_SEL, 0x40); /* disable network id check */
603 MMC_WRITE(MMC_THR_PRE_SET, sp->psa[WLPSA_THRESH]);
604 MMC_WRITE(MMC_QUALITY_THR, sp->psa[WLPSA_QUALTHRESH]);
606 MMC_WRITE(MMC_FREEZE, 0x00);
607 MMC_WRITE(MMC_ENCR_ENABLE, 0x00);
609 MMC_WRITE(MMC_NETW_ID_L,sp->nwid[1]); /* set NWID */
610 MMC_WRITE(MMC_NETW_ID_H,sp->nwid[0]);
612 /* enter normal 16 bit mode operation */
613 sp->hacr = HACR_DEFAULT;
615 CMD(unit); /* virtualpc1 needs this! */
617 if (sp->psa[WLPSA_COMPATNO]== /* 2.4 Gz: half-card ver */
618 WLPSA_COMPATNO_WL24B) { /* 2.4 Gz */
619 i=sp->chan24<<4; /* 2.4 Gz: position ch # */
620 MMC_WRITE(MMC_EEADDR,i+0x0f); /* 2.4 Gz: named ch, wc=16 */
621 MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+ /* 2.4 Gz: Download Synths */
622 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: Read EEPROM */
623 for (i=0; i<1000; ++i) { /* 2.4 Gz: wait for download */
624 DELAY(40); /* 2.4 Gz */
625 if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and */
626 &(MMC_EECTRLstat_DWLD /* 2.4 Gz: EEBUSY */
627 +MMC_EECTRLstat_EEBUSY))==0) /* 2.4 Gz: */
628 break; /* 2.4 Gz: download finished */
630 if (i==1000) printf("wl: synth load failed\n"); /* 2.4 Gz */
631 MMC_WRITE(MMC_EEADDR,0x61); /* 2.4 Gz: default pwr, wc=2 */
632 MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+ /* 2.4 Gz: Download Xmit Pwr */
633 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: Read EEPROM */
634 for (i=0; i<1000; ++i) { /* 2.4 Gz: wait for download */
635 DELAY(40); /* 2.4 Gz */
636 if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and */
637 &(MMC_EECTRLstat_DWLD /* 2.4 Gz: EEBUSY */
638 +MMC_EECTRLstat_EEBUSY))==0) /* 2.4 Gz: */
639 break; /* 2.4 Gz: download finished */
641 if (i==1000) printf("wl: xmit pwr load failed\n"); /* 2.4 Gz */
642 MMC_WRITE(MMC_ANALCTRL, /* 2.4 Gz: EXT ant+polarity */
643 MMC_ANALCTRL_ANTPOL + /* 2.4 Gz: */
644 MMC_ANALCTRL_EXTANT); /* 2.4 Gz: */
645 i=sp->chan24<<4; /* 2.4 Gz: position ch # */
646 MMC_WRITE(MMC_EEADDR,i); /* 2.4 Gz: get frequency */
647 MMC_WRITE(MMC_EECTRL, /* 2.4 Gz: EEPROM read */
648 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: */
649 DELAY(40); /* 2.4 Gz */
650 i = wlmmcread(base,MMC_EEDATALrv) /* 2.4 Gz: freq val */
651 + (wlmmcread(base,MMC_EEDATAHrv)<<8); /* 2.4 Gz */
652 sp->freq24 = (i>>6)+2400; /* 2.4 Gz: save real freq */
659 * Another routine that interfaces the "if" layer to this driver.
660 * Simply resets the structures that are used by "upper layers".
661 * As well as calling wlhwrst that does reset the WaveLAN board.
663 * input : softc pointer for this interface
664 * output : structures (if structs) and board are reset
670 register struct wl_softc *sc = xsc;
671 struct ifnet *ifp = &sc->wl_if;
676 if (sc->wl_if.if_flags & IFF_DEBUG)
677 printf("wl%d: entered wlinit()\n",sc->unit);
679 #if defined(__FreeBSD__) && __FreeBSD_version >= 300000
680 if (ifp->if_addrhead.tqh_first == (struct ifaddr *)0) {
682 if (ifp->if_addrlist == (struct ifaddr *)0) {
687 if ((stat = wlhwrst(sc->unit)) == TRUE) {
688 sc->wl_if.if_flags |= IFF_RUNNING; /* same as DSF_RUNNING */
690 * OACTIVE is used by upper-level routines
693 sc->wl_if.if_flags &= ~IFF_OACTIVE; /* same as tbusy below */
695 sc->flags |= DSF_RUNNING;
697 untimeout(wlwatchdog, sc, sc->watchdog_ch);
701 printf("wl%d init(): trouble resetting board.\n", sc->unit);
709 * This routine resets the WaveLAN board that corresponds to the
710 * board number passed in.
712 * input : board number to do a hardware reset
713 * output : board is reset
719 register struct wl_softc *sc = WLSOFTC(unit);
722 if (sc->wl_if.if_flags & IFF_DEBUG)
723 printf("wl%d: entered wlhwrst()\n",unit);
725 sc->hacr = HACR_RESET;
726 CMD(unit); /* reset the board */
728 /* clear reset command and set PIO#1 in autoincrement mode */
729 sc->hacr = HACR_DEFAULT;
733 if (sc->wl_if.if_flags & IFF_DEBUG)
734 wlmmcstat(unit); /* Display MMC registers */
736 wlbldcu(unit); /* set up command unit structures */
738 if (wldiag(unit) == 0)
741 if (wlconfig(unit) == 0)
744 * insert code for loopback test here
746 wlrustrt(unit); /* start receive unit */
748 /* enable interrupts */
749 sc->hacr = (HACR_DEFAULT | HACR_INTRON);
758 * This function builds up the command unit structures. It inits
759 * the scp, iscp, scb, cb, tbd, and tbuf.
765 register struct wl_softc *sc = WLSOFTC(unit);
766 short base = sc->base;
774 bzero(&scp, sizeof(scp));
776 scp.scp_iscp = OFFSET_ISCP;
777 scp.scp_iscp_base = 0;
778 outw(PIOR1(base), OFFSET_SCP);
779 outsw(PIOP1(base), &scp, sizeof(scp_t)/2);
781 bzero(&iscp, sizeof(iscp));
783 iscp.iscp_scb_offset = OFFSET_SCB;
785 iscp.iscp_scb_base = 0;
786 outw(PIOR1(base), OFFSET_ISCP);
787 outsw(PIOP1(base), &iscp, sizeof(iscp_t)/2);
790 scb.scb_command = SCB_RESET;
791 scb.scb_cbl_offset = OFFSET_CU;
792 scb.scb_rfa_offset = OFFSET_RU;
796 scb.scb_ovrnerrs = 0;
797 outw(PIOR1(base), OFFSET_SCB);
798 outsw(PIOP1(base), &scb, sizeof(scb_t)/2);
802 outw(PIOR0(base), OFFSET_ISCP + 0); /* address of iscp_busy */
803 for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
804 if (i <= 0) printf("wl%d bldcu(): iscp_busy timeout.\n", unit);
805 outw(PIOR0(base), OFFSET_SCB + 0); /* address of scb_status */
806 for (i = STATUS_TRIES; i-- > 0; ) {
807 if (inw(PIOP0(base)) == (SCB_SW_CX|SCB_SW_CNA))
811 printf("wl%d bldcu(): not ready after reset.\n", unit);
815 cb.ac_command = AC_CW_EL; /* NOP */
816 cb.ac_link_offset = OFFSET_CU;
817 outw(PIOR1(base), OFFSET_CU);
818 outsw(PIOP1(base), &cb, 6/2);
821 tbd.next_tbd_offset = I82586NULL;
824 outw(PIOR1(base), OFFSET_TBD);
825 outsw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
833 * input : board number
834 * output : stuff sent to board if any there
838 wlstart(struct ifnet *ifp)
840 int unit = ifp->if_unit;
842 register struct wl_softc *sc = WLSOFTC(unit);
843 short base = sc->base;
844 int scb_status, cu_status, scb_command;
847 if (sc->wl_if.if_flags & IFF_DEBUG)
848 printf("wl%d: entered wlstart()\n",unit);
851 outw(PIOR1(base), OFFSET_CU);
852 cu_status = inw(PIOP1(base));
853 outw(PIOR0(base),OFFSET_SCB + 0); /* scb_status */
854 scb_status = inw(PIOP0(base));
855 outw(PIOR0(base), OFFSET_SCB + 2);
856 scb_command = inw(PIOP0(base));
859 * don't need OACTIVE check as tbusy here checks to see
860 * if we are already busy
863 if((scb_status & 0x0700) == SCB_CUS_IDLE &&
864 (cu_status & AC_SW_B) == 0){
866 untimeout(wlwatchdog, sc, sc->watchdog_ch);
867 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
869 * This is probably just a race. The xmt'r is just
870 * became idle but WE have masked interrupts so ...
873 printf("wl%d: CU idle, scb %04x %04x cu %04x\n",
874 unit, scb_status, scb_command, cu_status);
876 if (xmt_watch) printf("!!");
878 return; /* genuinely still busy */
880 } else if((scb_status & 0x0700) == SCB_CUS_ACTV ||
881 (cu_status & AC_SW_B)){
883 printf("wl%d: CU unexpectedly busy; scb %04x cu %04x\n",
884 unit, scb_status, cu_status);
886 if (xmt_watch) printf("wl%d: busy?!",unit);
887 return; /* hey, why are we busy? */
890 /* get ourselves some data */
892 IF_DEQUEUE(&ifp->if_snd, m);
893 if (m != (struct mbuf *)0) {
894 /* let BPF see it before we commit it */
899 /* set the watchdog timer so that if the board
900 * fails to interrupt we will restart
902 /* try 10 ticks, not very long */
903 sc->watchdog_ch = timeout(wlwatchdog, sc, 10);
904 sc->wl_ac.ac_if.if_flags |= IFF_OACTIVE;
905 sc->wl_if.if_opackets++;
908 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
916 * This routine does the actual copy of data (including ethernet header
917 * structure) from the WaveLAN to an mbuf chain that will be passed up
918 * to the "if" (network interface) layer. NOTE: we currently
919 * don't handle trailer protocols, so if that is needed, it will
920 * (at least in part) be added here. For simplicities sake, this
921 * routine copies the receive buffers from the board into a local (stack)
922 * buffer until the frame has been copied from the board. Once in
923 * the local buffer, the contents are copied to an mbuf chain that
924 * is then enqueued onto the appropriate "if" queue.
926 * input : board number, and an frame descriptor address
927 * output : the packet is put into an mbuf chain, and passed up
928 * assumes : if any errors occur, packet is "dropped on the floor"
932 wlread(int unit, u_short fd_p)
934 register struct wl_softc *sc = WLSOFTC(unit);
935 register struct ifnet *ifp = &sc->wl_if;
936 short base = sc->base;
938 struct ether_header eh;
942 u_short mlen, len, clen;
943 u_short bytes_in_msg, bytes_in_mbuf, bytes;
947 if (sc->wl_if.if_flags & IFF_DEBUG)
948 printf("wl%d: entered wlread()\n",unit);
950 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
951 printf("wl%d read(): board is not running.\n", ifp->if_unit);
952 sc->hacr &= ~HACR_INTRON;
953 CMD(unit); /* turn off interrupts */
955 /* read ether_header info out of device memory. doesn't
956 * go into mbuf. goes directly into eh structure
958 len = sizeof(struct ether_header); /* 14 bytes */
959 outw(PIOR1(base), fd_p);
960 insw(PIOP1(base), &fd, (sizeof(fd_t) - len)/2);
961 insw(PIOP1(base), &eh, (len-2)/2);
962 eh.ether_type = ntohs(inw(PIOP1(base)));
964 if (sc->wl_if.if_flags & IFF_DEBUG) {
965 printf("wlread: rcv packet, type is %x\n", eh.ether_type);
969 * WARNING. above is done now in ether_input, above may be
970 * useful for debug. jrb
972 eh.ether_type = htons(eh.ether_type);
974 if (fd.rbd_offset == I82586NULL) {
975 printf("wl%d read(): Invalid buffer\n", unit);
976 if (wlhwrst(unit) != TRUE) {
977 printf("wl%d read(): hwrst trouble.\n", unit);
982 outw(PIOR1(base), fd.rbd_offset);
983 insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
984 bytes_in_msg = rbd.status & RBD_SW_COUNT;
985 MGETHDR(m, M_DONTWAIT, MT_DATA);
987 if (m == (struct mbuf *)0) {
989 * not only do we want to return, we need to drop the packet on
990 * the floor to clear the interrupt.
993 if (wlhwrst(unit) != TRUE) {
994 sc->hacr &= ~HACR_INTRON;
995 CMD(unit); /* turn off interrupts */
996 printf("wl%d read(): hwrst trouble.\n", unit);
1000 m->m_next = (struct mbuf *) 0;
1001 m->m_pkthdr.rcvif = ifp;
1002 m->m_pkthdr.len = 0; /* don't know this yet */
1005 /* always use a cluster. jrb
1007 MCLGET(m, M_DONTWAIT);
1008 if (m->m_flags & M_EXT) {
1009 m->m_len = MCLBYTES;
1013 if (wlhwrst(unit) != TRUE) {
1014 sc->hacr &= ~HACR_INTRON;
1015 CMD(unit); /* turn off interrupts */
1016 printf("wl%d read(): hwrst trouble.\n", unit);
1023 bytes_in_mbuf = m->m_len;
1024 mb_p = mtod(tm, u_char *);
1025 bytes = min(bytes_in_mbuf, bytes_in_msg);
1032 outw(PIOR1(base), rbd.buffer_addr);
1033 insw(PIOP1(base), mb_p, len/2);
1037 if (!(bytes_in_mbuf -= bytes)) {
1038 MGET(tm->m_next, M_DONTWAIT, MT_DATA);
1040 if (tm == (struct mbuf *)0) {
1042 printf("wl%d read(): No mbuf nth\n", unit);
1043 if (wlhwrst(unit) != TRUE) {
1044 sc->hacr &= ~HACR_INTRON;
1045 CMD(unit); /* turn off interrupts */
1046 printf("wl%d read(): hwrst trouble.\n", unit);
1052 bytes_in_mbuf = MLEN;
1053 mb_p = mtod(tm, u_char *);
1058 if (!(bytes_in_msg -= bytes)) {
1059 if (rbd.status & RBD_SW_EOF ||
1060 rbd.next_rbd_offset == I82586NULL) {
1064 outw(PIOR1(base), rbd.next_rbd_offset);
1065 insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1066 bytes_in_msg = rbd.status & RBD_SW_COUNT;
1069 rbd.buffer_addr += bytes;
1072 bytes = min(bytes_in_mbuf, bytes_in_msg);
1075 m->m_pkthdr.len = clen;
1078 * Check if there's a BPF listener on this interface. If so, hand off
1079 * the raw packet to bpf.
1082 /* bpf assumes header is in mbufs. It isn't. We can
1083 * fool it without allocating memory as follows.
1084 * Trick borrowed from if_ie.c
1087 m0.m_len = sizeof eh;
1088 m0.m_data = (caddr_t) &eh;
1095 * If hw is in promiscuous mode (note that I said hardware, not if
1096 * IFF_PROMISC is set in ifnet flags), then if this is a unicast
1097 * packet and the MAC dst is not us, drop it. This check was formerly
1098 * inside the bpf if, above, but IFF_MULTI causes hw promisc without
1099 * a bpf listener, so this is wrong.
1100 * Greg Troxel <gdt@ir.bbn.com>, 1998-08-07
1103 * TBD: also discard packets where NWID does not match.
1104 * However, there does not appear to be a way to read the nwid
1105 * for a received packet. -gdt 1998-08-07
1108 #ifdef WL_USE_IFNET_PROMISC_CHECK /* not defined */
1109 (sc->wl_ac.ac_if.if_flags & (IFF_PROMISC|IFF_ALLMULTI))
1111 /* hw is in promisc mode if this is true */
1112 (sc->mode & (MOD_PROM | MOD_ENAL))
1115 (eh.ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
1116 bcmp(eh.ether_dhost, sc->wl_ac.ac_enaddr,
1117 sizeof(eh.ether_dhost)) != 0 ) {
1123 if (sc->wl_if.if_flags & IFF_DEBUG)
1124 printf("wl%d: wlrecv %d bytes\n", unit, clen);
1128 wl_cache_store(unit, base, &eh, m);
1132 * received packet is now in a chain of mbuf's. next step is
1133 * to pass the packet upwards.
1136 ether_input(&sc->wl_if, &eh, m);
1143 * This routine processes an ioctl request from the "if" layer
1146 * input : pointer the appropriate "if" struct, command, and data
1147 * output : based on command appropriate action is taken on the
1148 * WaveLAN board(s) or related structures
1149 * return : error is returned containing exit conditions
1153 wlioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1155 register struct ifreq *ifr = (struct ifreq *)data;
1156 int unit = ifp->if_unit;
1157 register struct wl_softc *sc = WLSOFTC(unit);
1158 short base = sc->base;
1160 int opri, error = 0;
1161 struct proc *p = curproc; /* XXX */
1162 int irq, irqval, i, isroot, size;
1168 if (sc->wl_if.if_flags & IFF_DEBUG)
1169 printf("wl%d: entered wlioctl()\n",unit);
1176 error = ether_ioctl(ifp, cmd, data);
1180 if (ifp->if_flags & IFF_ALLMULTI) {
1183 if (ifp->if_flags & IFF_PROMISC) {
1186 if(ifp->if_flags & IFF_LINK0) {
1190 * force a complete reset if the recieve multicast/
1191 * promiscuous mode changes so that these take
1192 * effect immediately.
1195 if (sc->mode != mode) {
1197 if (sc->flags & DSF_RUNNING) {
1198 sc->flags &= ~DSF_RUNNING;
1202 /* if interface is marked DOWN and still running then
1205 if ((ifp->if_flags & IFF_UP) == 0 && sc->flags & DSF_RUNNING) {
1206 printf("wl%d ioctl(): board is not running\n", unit);
1207 sc->flags &= ~DSF_RUNNING;
1208 sc->hacr &= ~HACR_INTRON;
1209 CMD(unit); /* turn off interrupts */
1211 /* else if interface is UP and RUNNING, start it
1213 else if (ifp->if_flags & IFF_UP && (sc->flags & DSF_RUNNING) == 0) {
1217 /* if WLDEBUG set on interface, then printf rf-modem regs
1219 if(ifp->if_flags & IFF_DEBUG)
1226 #if defined(__FreeBSD__) && __FreeBSD_version < 300000
1227 if (cmd == SIOCADDMULTI) {
1228 error = ether_addmulti(ifr, &sc->wl_ac);
1231 error = ether_delmulti(ifr, &sc->wl_ac);
1234 /* see if we should be in all multicast mode
1235 * note that 82586 cannot do that, must simulate with
1238 if ( check_allmulti(unit)) {
1239 ifp->if_flags |= IFF_ALLMULTI;
1240 sc->mode |= MOD_ENAL;
1241 sc->flags &= ~DSF_RUNNING;
1247 if (error == ENETRESET) {
1248 if(sc->flags & DSF_RUNNING) {
1249 sc->flags &= ~DSF_RUNNING;
1258 #endif /* MULTICAST */
1260 /* DEVICE SPECIFIC */
1263 /* copy the PSA out to the caller */
1265 /* pointer to buffer in user space */
1266 up = (void *)ifr->ifr_data;
1267 /* work out if they're root */
1268 isroot = (suser(p) == 0);
1270 for (i = 0; i < 0x40; i++) {
1271 /* don't hand the DES key out to non-root users */
1272 if ((i > WLPSA_DESKEY) && (i < (WLPSA_DESKEY + 8)) && !isroot)
1274 if (subyte((up + i), sc->psa[i]))
1280 /* copy the PSA in from the caller; we only copy _some_ values */
1283 if ((error = suser(p)))
1285 error = EINVAL; /* assume the worst */
1286 /* pointer to buffer in user space containing data */
1287 up = (void *)ifr->ifr_data;
1289 /* check validity of input range */
1290 for (i = 0; i < 0x40; i++)
1291 if (fubyte(up + i) < 0)
1294 /* check IRQ value */
1295 irqval = fubyte(up+WLPSA_IRQNO);
1296 for (irq = 15; irq >= 0; irq--)
1297 if(irqvals[irq] == irqval)
1299 if (irq == 0) /* oops */
1302 sc->psa[WLPSA_IRQNO] = irqval;
1305 for (i = 0; i < 6; i++)
1306 sc->psa[WLPSA_LOCALMAC+i] = fubyte(up+WLPSA_LOCALMAC+i);
1309 sc->psa[WLPSA_MACSEL] = fubyte(up+WLPSA_MACSEL);
1312 sc->psa[WLPSA_NWID] = fubyte(up+WLPSA_NWID);
1313 sc->psa[WLPSA_NWID+1] = fubyte(up+WLPSA_NWID+1);
1316 wlsetpsa(unit); /* update the PSA */
1320 /* get the current NWID out of the sc since we stored it there */
1322 ifr->ifr_data = (caddr_t) (sc->nwid[0] << 8 | sc->nwid[1]);
1327 * change the nwid dynamically. This
1328 * ONLY changes the radio modem and does not
1332 * 1. save in softc "soft registers"
1333 * 2. save in radio modem (MMC)
1337 if ((error = suser(p)))
1339 if (!(ifp->if_flags & IFF_UP)) {
1340 error = EIO; /* only allowed while up */
1343 * soft c nwid shadows radio modem setting
1345 sc->nwid[0] = (int)ifr->ifr_data >> 8;
1346 sc->nwid[1] = (int)ifr->ifr_data & 0xff;
1347 MMC_WRITE(MMC_NETW_ID_L,sc->nwid[1]);
1348 MMC_WRITE(MMC_NETW_ID_H,sc->nwid[0]);
1352 /* copy the EEPROM in 2.4 Gz WaveMODEM out to the caller */
1355 if ((error = suser(p)))
1357 /* pointer to buffer in user space */
1358 up = (void *)ifr->ifr_data;
1360 for (i=0x00; i<0x80; ++i) { /* 2.4 Gz: size of EEPROM */
1361 MMC_WRITE(MMC_EEADDR,i); /* 2.4 Gz: get frequency */
1362 MMC_WRITE(MMC_EECTRL, /* 2.4 Gz: EEPROM read */
1363 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: */
1364 DELAY(40); /* 2.4 Gz */
1365 if (subyte(up + 2*i , /* 2.4 Gz: pass low byte of */
1366 wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word */
1367 ) return(EFAULT); /* 2.4 Gz: */
1368 if (subyte(up + 2*i+1, /* 2.4 Gz: pass hi byte of */
1369 wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word */
1370 ) return(EFAULT); /* 2.4 Gz: */
1375 /* zero (Delete) the wl cache */
1378 if ((error = suser(p)))
1380 wl_cache_zero(unit);
1383 /* read out the number of used cache elements */
1385 ifr->ifr_data = (caddr_t) sc->w_sigitems;
1388 /* read out the wl cache */
1390 /* pointer to buffer in user space */
1391 up = (void *)ifr->ifr_data;
1392 cpt = (char *) &sc->w_sigcache[0];
1393 size = sc->w_sigitems * sizeof(struct w_sigcache);
1395 for (i = 0; i < size; i++) {
1396 if (subyte((up + i), *cpt++))
1412 * Called if the timer set in wlstart expires before an interrupt is received
1413 * from the wavelan. It seems to lose interrupts sometimes.
1414 * The watchdog routine gets called if the transmitter failed to interrupt
1416 * input : which board is timing out
1417 * output : board reset
1421 wlwatchdog(void *vsc)
1423 struct wl_softc *sc = vsc;
1424 int unit = sc->unit;
1426 log(LOG_ERR, "wl%d: wavelan device timeout on xmit\n", unit);
1427 sc->wl_ac.ac_if.if_oerrors++;
1434 * This function is the interrupt handler for the WaveLAN
1435 * board. This routine will be called whenever either a packet
1436 * is received, or a packet has successfully been transfered and
1437 * the unit is ready to transmit another packet.
1439 * input : board number that interrupted
1440 * output : either a packet is received, or a packet is transfered
1447 register struct wl_softc *sc = &wl_softc[unit];
1448 short base = sc->base;
1450 u_short int_type, int_type1;
1453 if (sc->wl_if.if_flags & IFF_DEBUG)
1454 printf("wl%d: wlintr() called\n",unit);
1457 if((int_type = inw(HASR(base))) & HASR_MMC_INTR) {
1458 /* handle interrupt from the modem management controler */
1459 /* This will clear the interrupt condition */
1460 (void) wlmmcread(base,MMC_DCE_STATUS); /* ignored for now */
1463 if(!(int_type & HASR_INTR)){ /* return if no interrupt from 82586 */
1464 /* commented out. jrb. it happens when reinit occurs
1465 printf("wlintr: int_type %x, dump follows\n", int_type);
1474 outw(PIOR0(base), OFFSET_SCB + 0); /* get scb status */
1475 int_type = (inw(PIOP0(base)) & SCB_SW_INT);
1476 if (int_type == 0) /* no interrupts left */
1479 int_type1 = wlack(unit); /* acknowledge interrupt(s) */
1480 /* make sure no bits disappeared (others may appear) */
1481 if ((int_type & int_type1) != int_type)
1482 printf("wlack() int bits disappeared : %04x != int_type %04x\n",
1483 int_type1, int_type);
1484 int_type = int_type1; /* go with the new status */
1488 if (int_type & SCB_SW_FR) {
1489 sc->wl_if.if_ipackets++;
1493 * receiver not ready
1495 if (int_type & SCB_SW_RNR) {
1496 sc->wl_if.if_ierrors++;
1498 if (sc->wl_if.if_flags & IFF_DEBUG)
1499 printf("wl%d intr(): receiver overrun! begin_fd = %x\n",
1500 unit, sc->begin_fd);
1507 if (int_type & SCB_SW_CNA) {
1509 * At present, we don't care about CNA's. We
1510 * believe they are a side effect of XMT.
1513 if (int_type & SCB_SW_CX) {
1515 * At present, we only request Interrupt for
1518 outw(PIOR1(base), OFFSET_CU); /* get command status */
1519 ac_status = inw(PIOP1(base));
1521 if (xmt_watch) { /* report some anomalies */
1523 if (sc->tbusy == 0) {
1524 printf("wl%d: xmt intr but not busy, CU %04x\n",
1527 if (ac_status == 0) {
1528 printf("wl%d: xmt intr but ac_status == 0\n", unit);
1530 if (ac_status & AC_SW_A) {
1531 printf("wl%d: xmt aborted\n",unit);
1534 if (ac_status & TC_CARRIER) {
1535 printf("wl%d: no carrier\n", unit);
1538 if (ac_status & TC_CLS) {
1539 printf("wl%d: no CTS\n", unit);
1541 if (ac_status & TC_DMA) {
1542 printf("wl%d: DMA underrun\n", unit);
1544 if (ac_status & TC_DEFER) {
1545 printf("wl%d: xmt deferred\n",unit);
1547 if (ac_status & TC_SQE) {
1548 printf("wl%d: heart beat\n", unit);
1550 if (ac_status & TC_COLLISION) {
1551 printf("wl%d: too many collisions\n", unit);
1554 /* if the transmit actually failed, or returned some status */
1555 if ((!(ac_status & AC_SW_OK)) || (ac_status & 0xfff)) {
1556 if (ac_status & (TC_COLLISION | TC_CLS | TC_DMA)) {
1557 sc->wl_if.if_oerrors++;
1559 /* count collisions */
1560 sc->wl_if.if_collisions += (ac_status & 0xf);
1561 /* if TC_COLLISION set and collision count zero, 16 collisions */
1562 if ((ac_status & 0x20) == 0x20) {
1563 sc->wl_if.if_collisions += 0x10;
1567 untimeout(wlwatchdog, sc, sc->watchdog_ch);
1568 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
1569 wlstart(&(sc->wl_if));
1578 * This routine is called by the interrupt handler to initiate a
1579 * packet transfer from the board to the "if" layer above this
1580 * driver. This routine checks if a buffer has been successfully
1581 * received by the WaveLAN. If so, the routine wlread is called
1582 * to do the actual transfer of the board data (including the
1583 * ethernet header) into a packet (consisting of an mbuf chain).
1585 * input : number of the board to check
1586 * output : if a packet is available, it is "sent up"
1592 register struct wl_softc *sc = WLSOFTC(unit);
1593 short base = sc->base;
1594 u_short fd_p, status, offset, link_offset;
1597 if (sc->wl_if.if_flags & IFF_DEBUG)
1598 printf("wl%d: entered wlrcv()\n",unit);
1600 for (fd_p = sc->begin_fd; fd_p != I82586NULL; fd_p = sc->begin_fd) {
1602 outw(PIOR0(base), fd_p + 0); /* address of status */
1603 status = inw(PIOP0(base));
1604 outw(PIOR1(base), fd_p + 4); /* address of link_offset */
1605 link_offset = inw(PIOP1(base));
1606 offset = inw(PIOP1(base)); /* rbd_offset */
1607 if (status == 0xffff || offset == 0xffff /*I82586NULL*/) {
1608 if (wlhwrst(unit) != TRUE)
1609 printf("wl%d rcv(): hwrst ffff trouble.\n", unit);
1611 } else if (status & AC_SW_C) {
1612 if (status == (RFD_DONE|RFD_RSC)) {
1615 if (sc->wl_if.if_flags & IFF_DEBUG)
1616 printf("wl%d RCV: RSC %x\n", unit, status);
1618 sc->wl_if.if_ierrors++;
1619 } else if (!(status & RFD_OK)) {
1620 printf("wl%d RCV: !OK %x\n", unit, status);
1621 sc->wl_if.if_ierrors++;
1622 } else if (status & 0xfff) { /* can't happen */
1623 printf("wl%d RCV: ERRs %x\n", unit, status);
1624 sc->wl_if.if_ierrors++;
1625 } else if (!wlread(unit, fd_p))
1628 if (!wlrequeue(unit, fd_p)) {
1629 /* abort on chain error */
1630 if (wlhwrst(unit) != TRUE)
1631 printf("wl%d rcv(): hwrst trouble.\n", unit);
1634 sc->begin_fd = link_offset;
1645 * This routine puts rbd's used in the last receive back onto the
1646 * free list for the next receive.
1650 wlrequeue(int unit, u_short fd_p)
1652 register struct wl_softc *sc = WLSOFTC(unit);
1653 short base = sc->base;
1655 u_short l_rbdp, f_rbdp, rbd_offset;
1657 outw(PIOR0(base), fd_p + 6);
1658 rbd_offset = inw(PIOP0(base));
1659 if ((f_rbdp = rbd_offset) != I82586NULL) {
1662 outw(PIOR0(base), l_rbdp + 0); /* address of status */
1663 if(inw(PIOP0(base)) & RBD_SW_EOF)
1665 outw(PIOP0(base), 0);
1666 outw(PIOR0(base), l_rbdp + 2); /* next_rbd_offset */
1667 if((l_rbdp = inw(PIOP0(base))) == I82586NULL)
1670 outw(PIOP0(base), 0);
1671 outw(PIOR0(base), l_rbdp + 2); /* next_rbd_offset */
1672 outw(PIOP0(base), I82586NULL);
1673 outw(PIOR0(base), l_rbdp + 8); /* address of size */
1674 outw(PIOP0(base), inw(PIOP0(base)) | AC_CW_EL);
1675 outw(PIOR0(base), sc->end_rbd + 2);
1676 outw(PIOP0(base), f_rbdp); /* end_rbd->next_rbd_offset */
1677 outw(PIOR0(base), sc->end_rbd + 8); /* size */
1678 outw(PIOP0(base), inw(PIOP0(base)) & ~AC_CW_EL);
1679 sc->end_rbd = l_rbdp;
1683 fd.command = AC_CW_EL;
1684 fd.link_offset = I82586NULL;
1685 fd.rbd_offset = I82586NULL;
1686 outw(PIOR1(base), fd_p);
1687 outsw(PIOP1(base), &fd, 8/2);
1689 outw(PIOR1(base), sc->end_fd + 2); /* addr of command */
1690 outw(PIOP1(base), 0); /* command = 0 */
1691 outw(PIOP1(base), fd_p); /* end_fd->link_offset = fd_p */
1698 static int xmt_debug = 0;
1699 #endif /* WLDEBUG */
1704 * This routine fills in the appropriate registers and memory
1705 * locations on the WaveLAN board and starts the board off on
1708 * input : board number of interest, and a pointer to the mbuf
1709 * output : board memory and registers are set for xfer and attention
1713 wlxmt(int unit, struct mbuf *m)
1715 register struct wl_softc *sc = WLSOFTC(unit);
1716 register u_short xmtdata_p = OFFSET_TBUF;
1717 register u_short xmtshort_p;
1718 struct mbuf *tm_p = m;
1719 register struct ether_header *eh_p = mtod(m, struct ether_header *);
1720 u_char *mb_p = mtod(m, u_char *) + sizeof(struct ether_header);
1721 u_short count = m->m_len - sizeof(struct ether_header);
1723 u_short tbd_p = OFFSET_TBD;
1724 u_short len, clen = 0;
1725 short base = sc->base;
1729 if (sc->wl_if.if_flags & IFF_DEBUG)
1730 printf("wl%d: entered wlxmt()\n",unit);
1734 cb.ac_command = (AC_CW_EL|AC_TRANSMIT|AC_CW_I);
1735 cb.ac_link_offset = I82586NULL;
1736 outw(PIOR1(base), OFFSET_CU);
1737 outsw(PIOP1(base), &cb, 6/2);
1738 outw(PIOP1(base), OFFSET_TBD); /* cb.cmd.transmit.tbd_offset */
1739 outsw(PIOP1(base), eh_p->ether_dhost, WAVELAN_ADDR_SIZE/2);
1740 outw(PIOP1(base), eh_p->ether_type);
1743 if (sc->wl_if.if_flags & IFF_DEBUG) {
1745 printf("XMT mbuf: L%d @%p ", count, (void *)mb_p);
1746 printf("ether type %x\n", eh_p->ether_type);
1749 #endif /* WLDEBUG */
1750 outw(PIOR0(base), OFFSET_TBD);
1751 outw(PIOP0(base), 0); /* act_count */
1752 outw(PIOR1(base), OFFSET_TBD + 4);
1753 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1754 outw(PIOP1(base), 0); /* buffer_base */
1757 if (clen + count > WAVELAN_MTU)
1763 outw(PIOR1(base), xmtdata_p);
1764 outsw(PIOP1(base), mb_p, len/2);
1766 outw(PIOR0(base), tbd_p); /* address of act_count */
1767 outw(PIOP0(base), inw(PIOP0(base)) + count);
1769 if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1772 /* go to the next descriptor */
1773 outw(PIOR0(base), tbd_p + 2);
1774 tbd_p += sizeof (tbd_t);
1775 outw(PIOP0(base), tbd_p); /* next_tbd_offset */
1776 outw(PIOR0(base), tbd_p);
1777 outw(PIOP0(base), 0); /* act_count */
1778 outw(PIOR1(base), tbd_p + 4);
1779 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1780 outw(PIOP1(base), 0); /* buffer_base */
1781 /* at the end -> coallesce remaining mbufs */
1782 if (tbd_p == OFFSET_TBD + (N_TBD-1) * sizeof (tbd_t)) {
1783 wlsftwsleaze(&count, &mb_p, &tm_p, unit);
1786 /* next mbuf short -> coallesce as needed */
1787 if ( (tm_p->m_next == (struct mbuf *) 0) ||
1788 #define HDW_THRESHOLD 55
1789 tm_p->m_len > HDW_THRESHOLD)
1792 wlhdwsleaze(&count, &mb_p, &tm_p, unit);
1796 } else if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1798 count = tm_p->m_len;
1799 mb_p = mtod(tm_p, u_char *);
1801 if (sc->wl_if.if_flags & IFF_DEBUG)
1803 printf("mbuf+ L%d @%p ", count, (void *)mb_p);
1804 #endif /* WLDEBUG */
1807 if (sc->wl_if.if_flags & IFF_DEBUG)
1809 printf("CLEN = %d\n", clen);
1810 #endif /* WLDEBUG */
1811 outw(PIOR0(base), tbd_p);
1812 if (clen < ETHERMIN) {
1813 outw(PIOP0(base), inw(PIOP0(base)) + ETHERMIN - clen);
1814 outw(PIOR1(base), xmtdata_p);
1815 for (xmtshort_p = xmtdata_p; clen < ETHERMIN; clen += 2)
1816 outw(PIOP1(base), 0);
1818 outw(PIOP0(base), inw(PIOP0(base)) | TBD_SW_EOF);
1819 outw(PIOR0(base), tbd_p + 2);
1820 outw(PIOP0(base), I82586NULL);
1822 if (sc->wl_if.if_flags & IFF_DEBUG) {
1828 #endif /* WLDEBUG */
1830 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
1832 * wait for 586 to clear previous command, complain if it takes
1835 for (spin = 1;;spin = (spin + 1) % 10000) {
1836 if (inw(PIOP0(base)) == 0) { /* it's done, we can go */
1839 if ((spin == 0) && xmt_watch) { /* not waking up, and we care */
1840 printf("wl%d: slow accepting xmit\n",unit);
1843 outw(PIOP0(base), SCB_CU_STRT); /* new command */
1844 SET_CHAN_ATTN(unit);
1849 * Pause to avoid transmit overrun problems.
1850 * The required delay tends to vary with platform type, and may be
1851 * related to interrupt loss.
1853 if (wl_xmit_delay) {
1854 DELAY(wl_xmit_delay);
1862 * This function builds the linear linked lists of fd's and
1863 * rbd's. Based on page 4-32 of 1986 Intel microcom handbook.
1869 register struct wl_softc *sc = WLSOFTC(unit);
1870 short base = sc->base;
1873 u_short fd_p = OFFSET_RU;
1874 u_short rbd_p = OFFSET_RBD;
1877 sc->begin_fd = fd_p;
1878 for(i = 0; i < N_FD; i++) {
1881 fd.link_offset = fd_p + sizeof(fd_t);
1882 fd.rbd_offset = I82586NULL;
1883 outw(PIOR1(base), fd_p);
1884 outsw(PIOP1(base), &fd, 8/2);
1885 fd_p = fd.link_offset;
1887 fd_p -= sizeof(fd_t);
1889 outw(PIOR1(base), fd_p + 2);
1890 outw(PIOP1(base), AC_CW_EL); /* command */
1891 outw(PIOP1(base), I82586NULL); /* link_offset */
1894 outw(PIOR0(base), fd_p + 6); /* address of rbd_offset */
1895 outw(PIOP0(base), rbd_p);
1896 outw(PIOR1(base), rbd_p);
1897 for(i = 0; i < N_RBD; i++) {
1899 rbd.buffer_addr = rbd_p + sizeof(rbd_t) + 2;
1900 rbd.buffer_base = 0;
1901 rbd.size = RCVBUFSIZE;
1903 rbd_p += sizeof(ru_t);
1904 rbd.next_rbd_offset = rbd_p;
1906 rbd.next_rbd_offset = I82586NULL;
1907 rbd.size |= AC_CW_EL;
1908 sc->end_rbd = rbd_p;
1910 outsw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1911 outw(PIOR1(base), rbd_p);
1913 return sc->begin_fd;
1919 * This routine starts the receive unit running. First checks if the
1920 * board is actually ready, then the board is instructed to receive
1927 register struct wl_softc *sc = WLSOFTC(unit);
1928 short base = sc->base;
1932 if (sc->wl_if.if_flags & IFF_DEBUG)
1933 printf("wl%d: entered wlrustrt()\n",unit);
1935 outw(PIOR0(base), OFFSET_SCB);
1936 if (inw(PIOP0(base)) & SCB_RUS_READY){
1937 printf("wlrustrt: RUS_READY\n");
1941 outw(PIOR0(base), OFFSET_SCB + 2);
1942 outw(PIOP0(base), SCB_RU_STRT); /* command */
1943 rfa = wlbldru(unit);
1944 outw(PIOR0(base), OFFSET_SCB + 6); /* address of scb_rfa_offset */
1945 outw(PIOP0(base), rfa);
1947 SET_CHAN_ATTN(unit);
1954 * This routine does a 586 op-code number 7, and obtains the
1955 * diagnose status for the WaveLAN.
1961 register struct wl_softc *sc = WLSOFTC(unit);
1962 short base = sc->base;
1966 if (sc->wl_if.if_flags & IFF_DEBUG)
1967 printf("wl%d: entered wldiag()\n",unit);
1969 outw(PIOR0(base), OFFSET_SCB);
1970 status = inw(PIOP0(base));
1971 if (status & SCB_SW_INT) {
1972 /* state is 2000 which seems ok
1973 printf("wl%d diag(): unexpected initial state %\n",
1974 unit, inw(PIOP0(base)));
1978 outw(PIOR1(base), OFFSET_CU);
1979 outw(PIOP1(base), 0); /* ac_status */
1980 outw(PIOP1(base), AC_DIAGNOSE|AC_CW_EL);/* ac_command */
1981 if(wlcmd(unit, "diag()") == 0)
1983 outw(PIOR0(base), OFFSET_CU);
1984 if (inw(PIOP0(base)) & 0x0800) {
1985 printf("wl%d: i82586 Self Test failed!\n", unit);
1994 * This routine does a standard config of the WaveLAN board.
2000 configure_t configure;
2001 register struct wl_softc *sc = WLSOFTC(unit);
2002 short base = sc->base;
2005 #if defined(__FreeBSD__) && __FreeBSD_version >= 300000
2006 struct ifmultiaddr *ifma;
2009 struct ether_multi *enm;
2010 struct ether_multistep step;
2013 #endif /* MULTICAST */
2016 if (sc->wl_if.if_flags & IFF_DEBUG)
2017 printf("wl%d: entered wlconfig()\n",unit);
2019 outw(PIOR0(base), OFFSET_SCB);
2020 if (inw(PIOP0(base)) & SCB_SW_INT) {
2022 printf("wl%d config(): unexpected initial state %x\n",
2023 unit, inw(PIOP0(base)));
2028 outw(PIOR1(base), OFFSET_CU);
2029 outw(PIOP1(base), 0); /* ac_status */
2030 outw(PIOP1(base), AC_CONFIGURE|AC_CW_EL); /* ac_command */
2033 configure.fifolim_bytecnt = 0x080c;
2034 configure.addrlen_mode = 0x0600;
2035 configure.linprio_interframe = 0x2060;
2036 configure.slot_time = 0xf200;
2037 configure.hardware = 0x0008; /* tx even w/o CD */
2038 configure.min_frame_len = 0x0040;
2040 /* This is the configuration block suggested by Marc Meertens
2041 * <mmeerten@obelix.utrecht.NCR.COM> in an e-mail message to John
2042 * Ioannidis on 10 Nov 92.
2044 configure.fifolim_bytecnt = 0x040c;
2045 configure.addrlen_mode = 0x0600;
2046 configure.linprio_interframe = 0x2060;
2047 configure.slot_time = 0xf000;
2048 configure.hardware = 0x0008; /* tx even w/o CD */
2049 configure.min_frame_len = 0x0040;
2052 * below is the default board configuration from p2-28 from 586 book
2054 configure.fifolim_bytecnt = 0x080c;
2055 configure.addrlen_mode = 0x2600;
2056 configure.linprio_interframe = 0x7820; /* IFS=120, ACS=2 */
2057 configure.slot_time = 0xf00c; /* slottime=12 */
2058 configure.hardware = 0x0008; /* tx even w/o CD */
2059 configure.min_frame_len = 0x0040;
2061 if(sc->mode & (MOD_PROM | MOD_ENAL)) {
2062 configure.hardware |= 1;
2064 outw(PIOR1(base), OFFSET_CU + 6);
2065 outsw(PIOP1(base), &configure, sizeof(configure_t)/2);
2067 if(wlcmd(unit, "config()-configure") == 0)
2070 outw(PIOR1(base), OFFSET_CU);
2071 outw(PIOP1(base), 0); /* ac_status */
2072 outw(PIOP1(base), AC_MCSETUP|AC_CW_EL); /* ac_command */
2073 outw(PIOR1(base), OFFSET_CU + 8);
2074 #if defined(__FreeBSD__) && __FreeBSD_version >= 300000
2075 for (ifma = sc->wl_if.if_multiaddrs.lh_first; ifma;
2076 ifma = ifma->ifma_link.le_next) {
2077 if (ifma->ifma_addr->sa_family != AF_LINK)
2080 addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
2081 outw(PIOP1(base), addrp[0] + (addrp[1] << 8));
2082 outw(PIOP1(base), addrp[2] + (addrp[3] << 8));
2083 outw(PIOP1(base), addrp[4] + (addrp[5] << 8));
2087 ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2088 while (enm != NULL) {
2089 unsigned int lo, hi;
2090 /* break if setting a multicast range, else we would crash */
2091 if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2094 lo = (enm->enm_addrlo[3] << 16) + (enm->enm_addrlo[4] << 8)
2095 + enm->enm_addrlo[5];
2096 hi = (enm->enm_addrhi[3] << 16) + (enm->enm_addrhi[4] << 8)
2097 + enm->enm_addrhi[5];
2099 outw(PIOP1(base),enm->enm_addrlo[0] +
2100 (enm->enm_addrlo[1] << 8));
2101 outw(PIOP1(base),enm->enm_addrlo[2] +
2102 ((lo >> 8) & 0xff00));
2103 outw(PIOP1(base), ((lo >> 8) & 0xff) +
2104 ((lo << 8) & 0xff00));
2105 /* #define MCASTDEBUG */
2107 printf("mcast_addr[%d,%d,%d] %x %x %x %x %x %x\n", lo, hi, cnt,
2113 enm->enm_addrlo[5]);
2118 ETHER_NEXT_MULTI(step, enm);
2121 outw(PIOR1(base), OFFSET_CU + 6); /* mc-cnt */
2122 outw(PIOP1(base), cnt * WAVELAN_ADDR_SIZE);
2123 if(wlcmd(unit, "config()-mcaddress") == 0)
2125 #endif /* MULTICAST */
2127 outw(PIOR1(base), OFFSET_CU);
2128 outw(PIOP1(base), 0); /* ac_status */
2129 outw(PIOP1(base), AC_IASETUP|AC_CW_EL); /* ac_command */
2130 outw(PIOR1(base), OFFSET_CU + 6);
2131 outsw(PIOP1(base), sc->wl_addr, WAVELAN_ADDR_SIZE/2);
2133 if(wlcmd(unit, "config()-address") == 0)
2144 * Set channel attention bit and busy wait until command has
2145 * completed. Then acknowledge the command completion.
2148 wlcmd(int unit, char *str)
2150 register struct wl_softc *sc = WLSOFTC(unit);
2151 short base = sc->base;
2154 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
2155 outw(PIOP0(base), SCB_CU_STRT);
2157 SET_CHAN_ATTN(unit);
2159 outw(PIOR0(base), OFFSET_CU);
2160 for(i = 0; i < 0xffff; i++)
2161 if (inw(PIOP0(base)) & AC_SW_C)
2163 if (i == 0xffff || !(inw(PIOP0(base)) & AC_SW_OK)) {
2164 printf("wl%d: %s failed; status = %d, inw = %x, outw = %x\n",
2165 unit, str, inw(PIOP0(base)) & AC_SW_OK, inw(PIOP0(base)), inw(PIOR0(base)));
2166 outw(PIOR0(base), OFFSET_SCB);
2167 printf("scb_status %x\n", inw(PIOP0(base)));
2168 outw(PIOR0(base), OFFSET_SCB+2);
2169 printf("scb_command %x\n", inw(PIOP0(base)));
2170 outw(PIOR0(base), OFFSET_SCB+4);
2171 printf("scb_cbl %x\n", inw(PIOP0(base)));
2172 outw(PIOR0(base), OFFSET_CU+2);
2173 printf("cu_cmd %x\n", inw(PIOP0(base)));
2177 outw(PIOR0(base), OFFSET_SCB);
2178 if ((inw(PIOP0(base)) & SCB_SW_INT) && (inw(PIOP0(base)) != SCB_SW_CNA)) {
2180 printf("wl%d %s: unexpected final state %x\n",
2181 unit, str, inw(PIOP0(base)));
2189 * wlack: if the 82596 wants attention because it has finished
2190 * sending or receiving a packet, acknowledge its desire and
2191 * return bits indicating the kind of attention. wlack() returns
2192 * these bits so that the caller can service exactly the
2193 * conditions that wlack() acknowledged.
2199 register u_short cmd;
2200 register struct wl_softc *sc = WLSOFTC(unit);
2201 short base = sc->base;
2203 outw(PIOR1(base), OFFSET_SCB);
2204 if(!(cmd = (inw(PIOP1(base)) & SCB_SW_INT)))
2207 if (sc->wl_if.if_flags & IFF_DEBUG)
2208 printf("wl%d: doing a wlack()\n",unit);
2210 outw(PIOP1(base), cmd);
2211 SET_CHAN_ATTN(unit);
2212 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
2213 for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
2215 printf("wl%d wlack(): board not accepting command.\n", unit);
2222 register struct wl_softc *sc = WLSOFTC(unit);
2223 short base = sc->base;
2224 u_short tbd_p = OFFSET_TBD;
2230 outw(PIOR1(base), tbd_p);
2231 insw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
2232 sum += (tbd.act_count & ~TBD_SW_EOF);
2233 printf("%d: addr %x, count %d (%d), next %x, base %x\n",
2234 i++, tbd.buffer_addr,
2235 (tbd.act_count & ~TBD_SW_EOF), sum,
2236 tbd.next_tbd_offset, tbd.buffer_base);
2237 if (tbd.act_count & TBD_SW_EOF)
2239 tbd_p = tbd.next_tbd_offset;
2244 wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2246 struct mbuf *tm_p = *tm_pp;
2247 u_char *mb_p = *mb_pp;
2253 * can we get a run that will be coallesced or
2254 * that terminates before breaking
2257 count += tm_p->m_len;
2258 if (tm_p->m_len & 1)
2260 } while ((tm_p = tm_p->m_next) != (struct mbuf *)0);
2261 if ( (tm_p == (struct mbuf *)0) ||
2262 count > HDW_THRESHOLD) {
2263 *countp = (*tm_pp)->m_len;
2264 *mb_pp = mtod((*tm_pp), u_char *);
2268 /* we need to copy */
2272 cp = (u_char *) t_packet;
2274 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2276 if (count > HDW_THRESHOLD)
2279 if (tm_p->m_next == (struct mbuf *)0)
2281 tm_p = tm_p->m_next;
2284 *mb_pp = (u_char *) t_packet;
2291 wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2293 struct mbuf *tm_p = *tm_pp;
2295 u_char *cp = (u_char *) t_packet;
2298 /* we need to copy */
2300 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2303 if (tm_p->m_next == (struct mbuf *)0)
2305 tm_p = tm_p->m_next;
2309 *mb_pp = (u_char *) t_packet;
2317 register struct wl_softc *sc = WLSOFTC(unit);
2318 short base = sc->base;
2321 printf("wl%d: DCE_STATUS: 0x%x, ", unit,
2322 wlmmcread(base,MMC_DCE_STATUS) & 0x0f);
2323 tmp = wlmmcread(base,MMC_CORRECT_NWID_H) << 8;
2324 tmp |= wlmmcread(base,MMC_CORRECT_NWID_L);
2325 printf("Correct NWID's: %d, ", tmp);
2326 tmp = wlmmcread(base,MMC_WRONG_NWID_H) << 8;
2327 tmp |= wlmmcread(base,MMC_WRONG_NWID_L);
2328 printf("Wrong NWID's: %d\n", tmp);
2329 printf("THR_PRE_SET: 0x%x, ", wlmmcread(base,MMC_THR_PRE_SET));
2330 printf("SIGNAL_LVL: %d, SILENCE_LVL: %d\n",
2331 wlmmcread(base,MMC_SIGNAL_LVL),
2332 wlmmcread(base,MMC_SILENCE_LVL));
2333 printf("SIGN_QUAL: 0x%x, NETW_ID: %x:%x, DES: %d\n",
2334 wlmmcread(base,MMC_SIGN_QUAL),
2335 wlmmcread(base,MMC_NETW_ID_H),
2336 wlmmcread(base,MMC_NETW_ID_L),
2337 wlmmcread(base,MMC_DES_AVAIL));
2341 wlmmcread(u_int base, u_short reg)
2343 while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2344 outw(MMCR(base),reg << 1);
2345 while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2346 return (u_short)inw(MMCR(base)) >> 8;
2352 MMC_WRITE(MMC_FREEZE,1);
2354 * SNR retrieval procedure :
2356 * read signal level : wlmmcread(base, MMC_SIGNAL_LVL);
2357 * read silence level : wlmmcread(base, MMC_SILENCE_LVL);
2359 MMC_WRITE(MMC_FREEZE,0);
2361 * SNR is signal:silence ratio.
2368 ** Reads the psa for the wavelan at (base) into (buf)
2371 wlgetpsa(int base, u_char *buf)
2375 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2376 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2378 for (i = 0; i < 0x40; i++) {
2379 outw(PIOR2(base), i);
2380 buf[i] = inb(PIOP2(base));
2382 PCMD(base, HACR_DEFAULT);
2383 PCMD(base, HACR_DEFAULT);
2389 ** Writes the psa for wavelan (unit) from the softc back to the
2390 ** board. Updates the CRC and sets the CRC OK flag.
2392 ** Do not call this when the board is operating, as it doesn't
2393 ** preserve the hacr.
2398 register struct wl_softc *sc = WLSOFTC(unit);
2399 short base = sc->base;
2403 crc = wlpsacrc(sc->psa); /* calculate CRC of PSA */
2404 sc->psa[WLPSA_CRCLOW] = crc & 0xff;
2405 sc->psa[WLPSA_CRCHIGH] = (crc >> 8) & 0xff;
2406 sc->psa[WLPSA_CRCOK] = 0x55; /* default to 'bad' until programming complete */
2408 oldpri = splimp(); /* ick, long pause */
2410 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2411 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2413 for (i = 0; i < 0x40; i++) {
2415 outw(PIOR2(base),i); /* write param memory */
2417 outb(PIOP2(base), sc->psa[i]);
2420 outw(PIOR2(base),WLPSA_CRCOK); /* update CRC flag*/
2422 sc->psa[WLPSA_CRCOK] = 0xaa; /* OK now */
2423 outb(PIOP2(base), 0xaa); /* all OK */
2426 PCMD(base, HACR_DEFAULT);
2427 PCMD(base, HACR_DEFAULT);
2433 ** CRC routine provided by Christopher Giordano <cgiordan@gdeb.com>,
2434 ** from original code by Tomi Mikkonen (tomitm@remedy.fi)
2437 static u_int crc16_table[16] = {
2438 0x0000, 0xCC01, 0xD801, 0x1400,
2439 0xF001, 0x3C00, 0x2800, 0xE401,
2440 0xA001, 0x6C00, 0x7800, 0xB401,
2441 0x5000, 0x9C01, 0x8801, 0x4400
2445 wlpsacrc(u_char *buf)
2450 for (i = 0; i < 0x3d; i++, buf++) {
2452 r1 = crc16_table[crc & 0xF];
2453 crc = (crc >> 4) & 0x0FFF;
2454 crc = crc ^ r1 ^ crc16_table[*buf & 0xF];
2457 r1 = crc16_table[crc & 0xF];
2458 crc = (crc >> 4) & 0x0FFF;
2459 crc = crc ^ r1 ^ crc16_table[(*buf >> 4) & 0xF];
2468 * take input packet and cache various radio hw characteristics
2469 * indexed by MAC address.
2471 * Some things to think about:
2472 * note that no space is malloced.
2473 * We might hash the mac address if the cache were bigger.
2474 * It is not clear that the cache is big enough.
2475 * It is also not clear how big it should be.
2476 * The cache is IP-specific. We don't care about that as
2477 * we want it to be IP-specific.
2478 * The last N recv. packets are saved. This will tend
2479 * to reward agents and mobile hosts that beacon.
2480 * That is probably fine for mobile ip.
2483 /* globals for wavelan signal strength cache */
2484 /* this should go into softc structure above.
2487 /* set true if you want to limit cache items to broadcast/mcast
2488 * only packets (not unicast)
2490 static int wl_cache_mcastonly = 1;
2491 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_mcastonly, CTLFLAG_RW,
2492 &wl_cache_mcastonly, 0, "");
2494 /* set true if you want to limit cache items to IP packets only
2496 static int wl_cache_iponly = 1;
2497 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_iponly, CTLFLAG_RW,
2498 &wl_cache_iponly, 0, "");
2500 /* zero out the cache
2503 wl_cache_zero(int unit)
2505 register struct wl_softc *sc = WLSOFTC(unit);
2507 bzero(&sc->w_sigcache[0], sizeof(struct w_sigcache) * MAXCACHEITEMS);
2509 sc->w_nextcache = 0;
2510 sc->w_wrapindex = 0;
2513 /* store hw signal info in cache.
2514 * index is MAC address, but an ip src gets stored too
2515 * There are two filters here controllable via sysctl:
2516 * throw out unicast (on by default, but can be turned off)
2517 * throw out non-ip (on by default, but can be turned off)
2520 void wl_cache_store (int unit, int base, struct ether_header *eh,
2523 struct ip *ip = NULL; /* Avoid GCC warning */
2525 int signal, silence;
2526 int w_insertcache; /* computed index for cache entry storage */
2527 register struct wl_softc *sc = WLSOFTC(unit);
2528 int ipflag = wl_cache_iponly;
2532 * 2. configurable filter to throw out unicast packets,
2533 * keep multicast only.
2537 /* reject if not IP packet
2539 if ( wl_cache_iponly && (ntohs(eh->ether_type) != 0x800)) {
2543 /* check if broadcast or multicast packet. we toss
2546 if (wl_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
2550 /* find the ip header. we want to store the ip_src
2551 * address. use the mtod macro(in mbuf.h)
2552 * to typecast m to struct ip *
2555 ip = mtod(m, struct ip *);
2558 /* do a linear search for a matching MAC address
2559 * in the cache table
2560 * . MAC address is 6 bytes,
2561 * . var w_nextcache holds total number of entries already cached
2563 for(i = 0; i < sc->w_nextcache; i++) {
2564 if (! bcmp(eh->ether_shost, sc->w_sigcache[i].macsrc, 6 )) {
2566 * so we already have this entry,
2567 * update the data, and LRU age
2573 /* did we find a matching mac address?
2574 * if yes, then overwrite a previously existing cache entry
2576 if (i < sc->w_nextcache ) {
2579 /* else, have a new address entry,so
2580 * add this new entry,
2581 * if table full, then we need to replace entry
2585 /* check for space in cache table
2586 * note: w_nextcache also holds number of entries
2587 * added in the cache table
2589 if ( sc->w_nextcache < MAXCACHEITEMS ) {
2590 w_insertcache = sc->w_nextcache;
2592 sc->w_sigitems = sc->w_nextcache;
2594 /* no space found, so simply wrap with wrap index
2595 * and "zap" the next entry
2598 if (sc->w_wrapindex == MAXCACHEITEMS) {
2599 sc->w_wrapindex = 0;
2601 w_insertcache = sc->w_wrapindex++;
2605 /* invariant: w_insertcache now points at some slot
2608 if (w_insertcache < 0 || w_insertcache >= MAXCACHEITEMS) {
2610 "wl_cache_store, bad index: %d of [0..%d], gross cache error\n",
2611 w_insertcache, MAXCACHEITEMS);
2615 /* store items in cache
2618 * .signal (0..63) ,silence (0..63) ,quality (0..15)
2621 sc->w_sigcache[w_insertcache].ipsrc = ip->ip_src.s_addr;
2623 bcopy( eh->ether_shost, sc->w_sigcache[w_insertcache].macsrc, 6);
2624 signal = sc->w_sigcache[w_insertcache].signal = wlmmcread(base, MMC_SIGNAL_LVL) & 0x3f;
2625 silence = sc->w_sigcache[w_insertcache].silence = wlmmcread(base, MMC_SILENCE_LVL) & 0x3f;
2626 sc->w_sigcache[w_insertcache].quality = wlmmcread(base, MMC_SIGN_QUAL) & 0x0f;
2628 sc->w_sigcache[w_insertcache].snr =
2631 sc->w_sigcache[w_insertcache].snr = 0;
2635 #endif /* WLCACHE */
2638 * determine if in all multicast mode or not
2640 * returns: 1 if IFF_ALLMULTI should be set
2645 #if defined(__FreeBSD__) && __FreeBSD_version < 300000 /* not required */
2647 check_allmulti(int unit)
2649 register struct wl_softc *sc = WLSOFTC(unit);
2650 short base = sc->base;
2651 struct ether_multi *enm;
2652 struct ether_multistep step;
2654 ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2655 while (enm != NULL) {
2656 unsigned int lo, hi;
2658 printf("enm_addrlo %x:%x:%x:%x:%x:%x\n", enm->enm_addrlo[0], enm->enm_addrlo[1],
2659 enm->enm_addrlo[2], enm->enm_addrlo[3], enm->enm_addrlo[4],
2660 enm->enm_addrlo[5]);
2661 printf("enm_addrhi %x:%x:%x:%x:%x:%x\n", enm->enm_addrhi[0], enm->enm_addrhi[1],
2662 enm->enm_addrhi[2], enm->enm_addrhi[3], enm->enm_addrhi[4],
2663 enm->enm_addrhi[5]);
2665 if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2668 ETHER_NEXT_MULTI(step, enm);