1 /* $FreeBSD: src/sys/i386/isa/if_wl.c,v 1.27.2.2 2000/07/17 21:24:32 archie Exp $ */
2 /* $DragonFly: src/sys/dev/netif/wl/if_wl.c,v 1.16 2005/01/23 20:23:22 joerg Exp $ */
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain all copyright
8 * notices, this list of conditions and the following disclaimer.
9 * 2. The names of the authors may not be used to endorse or promote products
10 * derived from this software withough specific prior written permission
12 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
13 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
14 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
15 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
16 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
17 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
18 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
19 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
21 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 * if_wl.c - original MACH, then BSDI ISA wavelan driver
26 * ported to mach by Anders Klemets
27 * to BSDI by Robert Morris
28 * to FreeBSD by Jim Binkley
29 * to FreeBSD 2.2+ by Michael Smith
32 * Changed interface to match 2.1-2.2 differences.
33 * Implement IRQ selection logic in wlprobe()
34 * Implement PSA updating.
35 * Pruned heading comments for relevance.
36 * Ripped out all the 'interface counters' cruft.
37 * Cut the missing-interrupt timer back to 100ms.
39 * now supports all multicast mode (mrouted will work),
40 * but unfortunately must do that by going into promiscuous mode
41 * NWID sysctl added so that normally promiscuous mode is NWID-specific
42 * but can be made NWID-inspecific
46 * Ported to FreeBSD, got promiscuous mode working with bpfs,
47 * and rewired timer routine. The i82586 will hang occasionally on output
48 * and the watchdog timer will kick it if so and log an entry.
49 * 2 second timeout there. Apparently the chip loses an interrupt.
50 * Code borrowed from if_ie.c for watchdog timer.
52 * The wavelan card is a 2mbit radio modem that emulates ethernet;
53 * i.e., it uses MAC addresses. This should not be a surprise since
54 * it uses an ethernet controller as a major hw item.
55 * It can broadcast, unicast or apparently multicast in a base cell
56 * using a omni-directional antennae that is
57 * about 800 feet around the base cell barring walls and metal.
58 * With directional antennae, it can be used point to point over a mile
59 * or so apparently (haven't tried that).
61 * There are ISA and pcmcia versions (not supported by this code).
62 * The ISA card has an Intel 82586 lan controller on it. It consists
63 * of 2 pieces of hw, the lan controller (intel) and a radio-modem.
64 * The latter has an extra set of controller registers that has nothing
65 * to do with the i82586 and allows setting and monitoring of radio
66 * signal strength, etc. There is a nvram area called the PSA that
67 * contains a number of setup variables including the IRQ and so-called
68 * NWID or Network ID. The NWID must be set the same for all radio
69 * cards to communicate (unless you are using the ATT/NCR roaming feature
70 * with their access points. There is no support for that here. Roaming
71 * involves a link-layer beacon sent out from the access points. End
72 * stations monitor the signal strength and only use the strongest
73 * access point). This driver assumes that the base ISA port, IRQ,
74 * and NWID are first set in nvram via the dos-side "instconf.exe" utility
75 * supplied with the card. This driver takes the ISA port from
76 * the kernel configuration setup, and then determines the IRQ either
77 * from the kernel config (if an explicit IRQ is set) or from the
78 * PSA on the card if not.
79 * The hw also magically just uses the IRQ set in the nvram.
80 * The NWID is used magically as well by the radio-modem
81 * to determine which packets to keep or throw out.
85 * device wl0 at isa? port 0x300 net irq ?
88 * 1. WLDEBUG. (off) - if turned on enables IFF_DEBUG set via ifconfig debug
89 * 2. MULTICAST (on) - turned on and works up to and including mrouted
90 * 3. WLCACHE (off) - define to turn on a signal strength
91 * (and other metric) cache that is indexed by sender MAC address.
92 * Apps can read this out to learn the remote signal strength of a
93 * sender. Note that it has a switch so that it only stores
94 * broadcast/multicast senders but it could be set to store unicast
95 * too only. Size is hardwired in if_wl_wavelan.h
97 * one further note: promiscuous mode is a curious thing. In this driver,
98 * promiscuous mode apparently CAN catch ALL packets and ignore the NWID
99 * setting. This is probably more useful in a sense (for snoopers) if
100 * you are interested in all traffic as opposed to if you are interested
101 * in just your own. There is a driver specific sysctl to turn promiscuous
102 * from just promiscuous to wildly promiscuous...
104 * This driver also knows how to load the synthesizers in the 2.4 Gz
105 * ISA Half-card, Product number 847647476 (USA/FCC IEEE Channel set).
106 * This product consists of a "mothercard" that contains the 82586,
107 * NVRAM that holds the PSA, and the ISA-buss interface custom ASIC.
108 * The radio transceiver is a "daughtercard" called the WaveMODEM which
109 * connects to the mothercard through two single-inline connectors: a
110 * 20-pin connector provides DC-power and modem signals, and a 3-pin
111 * connector which exports the antenna connection. The code herein
112 * loads the receive and transmit synthesizers and the corresponding
113 * transmitter output power value from an EEPROM controlled through
114 * additional registers via the MMC. The EEPROM address selected
115 * are those whose values are preset by the DOS utility programs
116 * provided with the product, and this provides compatible operation
117 * with the DOS Packet Driver software. A future modification will
118 * add the necessary functionality to this driver and to the wlconfig
119 * utility to completely replace the DOS Configuration Utilities.
120 * The 2.4 Gz WaveMODEM is described in document number 407-024692/E,
121 * and is available through Lucent Technologies OEM supply channels.
128 * Olivetti PC586 Mach Ethernet driver v1.0
129 * Copyright Ing. C. Olivetti & C. S.p.A. 1988, 1989
130 * All rights reserved.
135 Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc.,
136 Cupertino, California.
140 Permission to use, copy, modify, and distribute this software and
141 its documentation for any purpose and without fee is hereby
142 granted, provided that the above copyright notice appears in all
143 copies and that both the copyright notice and this permission notice
144 appear in supporting documentation, and that the name of Olivetti
145 not be used in advertising or publicity pertaining to distribution
146 of the software without specific, written prior permission.
148 OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
149 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
150 IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
151 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
152 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
153 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
154 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
158 Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
162 Permission to use, copy, modify, and distribute this software and
163 its documentation for any purpose and without fee is hereby
164 granted, provided that the above copyright notice appears in all
165 copies and that both the copyright notice and this permission notice
166 appear in supporting documentation, and that the name of Intel
167 not be used in advertising or publicity pertaining to distribution
168 of the software without specific, written prior permission.
170 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
171 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
172 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
173 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
174 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
175 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
176 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
182 * 1. The best book on the 82586 is:
183 * LAN Components User's Manual by Intel
184 * The copy I found was dated 1984. This really tells you
185 * what the state machines are doing
186 * 2. In the current design, we only do one write at a time,
187 * though the hardware is capable of chaining and possibly
188 * even batching. The problem is that we only make one
189 * transmit buffer available in sram space.
193 #include "opt_wavelan.h"
194 #include "opt_inet.h"
196 #include <sys/param.h>
197 #include <sys/systm.h>
198 #include <sys/sockio.h>
199 #include <sys/mbuf.h>
200 #include <sys/socket.h>
201 #include <sys/syslog.h>
202 #include <sys/proc.h>
204 #include <sys/kernel.h>
205 #include <sys/sysctl.h>
207 #include <net/ethernet.h>
209 #include <net/if_dl.h>
212 #include <netinet/in.h>
213 #include <netinet/in_systm.h>
214 #include <netinet/ip.h>
215 #include <netinet/if_ether.h>
220 #include <machine/clock.h>
222 #include <bus/isa/i386/isa_device.h>
223 #include "if_wl_i82586.h" /* Definitions for the Intel chip */
225 /* was 1000 in original, fed to DELAY(x) */
226 #define DELAYCONST 1000
228 #include <machine/if_wl_wavelan.h>
230 static char t_packet[ETHERMTU + sizeof(struct ether_header) + sizeof(long)];
233 struct arpcom wl_ac; /* Ethernet common part */
234 #define wl_if wl_ac.ac_if /* network visible interface */
235 #define wl_addr wl_ac.ac_enaddr /* hardware address */
237 u_char nwid[2]; /* current radio modem nwid */
241 int tbusy; /* flag to determine if xmit is busy */
245 u_short hacr; /* latest host adapter CR command */
247 u_char chan24; /* 2.4 Gz: channel number/EEPROM Area # */
248 u_short freq24; /* 2.4 Gz: resulting frequency */
249 struct callout watchdog_ch;
251 int w_sigitems; /* number of cached entries */
252 /* array of cache entries */
253 struct w_sigcache w_sigcache[ MAXCACHEITEMS ];
254 int w_nextcache; /* next free cache entry */
255 int w_wrapindex; /* next "free" cache entry */
258 static struct wl_softc wl_softc[NWL];
260 #define WLSOFTC(unit) ((struct wl_softc *)(&wl_softc[unit]))
262 static int wlprobe(struct isa_device *);
263 static int wlattach(struct isa_device *);
265 DECLARE_DUMMY_MODULE(if_wl);
267 struct isa_driver wldriver = {
268 wlprobe, wlattach, "wl", 0
272 * XXX The Wavelan appears to be prone to dropping stuff if you talk to
273 * it too fast. This disgusting hack inserts a delay after each packet
274 * is queued which helps avoid this behaviour on fast systems.
276 static int wl_xmit_delay = 250;
277 SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_delay, CTLFLAG_RW, &wl_xmit_delay, 0, "");
280 * not XXX, but ZZZ (bizarre).
281 * promiscuous mode can be toggled to ignore NWIDs. By default,
282 * it does not. Caution should be exercised about combining
283 * this mode with IFF_ALLMULTI which puts this driver in
286 static int wl_ignore_nwid = 0;
287 SYSCTL_INT(_machdep, OID_AUTO, wl_ignore_nwid, CTLFLAG_RW, &wl_ignore_nwid, 0, "");
290 * Emit diagnostics about transmission problems
292 static int xmt_watch = 0;
293 SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_watch, CTLFLAG_RW, &xmt_watch, 0, "");
296 * Collect SNR statistics
298 static int gathersnr = 0;
299 SYSCTL_INT(_machdep, OID_AUTO, wl_gather_snr, CTLFLAG_RW, &gathersnr, 0, "");
301 static void wlstart(struct ifnet *ifp);
302 static void wlinit(void *xsc);
303 static int wlioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *);
304 static timeout_t wlwatchdog;
305 static ointhand2_t wlintr;
306 static void wlxmt(int unt, struct mbuf *m);
307 static int wldiag(int unt);
308 static int wlconfig(int unit);
309 static int wlcmd(int unit, char *str);
310 static void wlmmcstat(int unit);
311 static u_short wlbldru(int unit);
312 static u_short wlmmcread(u_int base, u_short reg);
313 static void wlinitmmc(int unit);
314 static int wlhwrst(int unit);
315 static void wlrustrt(int unit);
316 static void wlbldcu(int unit);
317 static int wlack(int unit);
318 static int wlread(int unit, u_short fd_p);
319 static void getsnr(int unit);
320 static void wlrcv(int unit);
321 static int wlrequeue(int unit, u_short fd_p);
322 static void wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
323 static void wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
324 static void wltbd(int unit);
325 static void wlgetpsa(int base, u_char *buf);
326 static void wlsetpsa(int unit);
327 static u_short wlpsacrc(u_char *buf);
328 static void wldump(int unit);
330 static void wl_cache_store(int, int, struct ether_header *, struct mbuf *);
331 static void wl_cache_zero(int unit);
334 # if defined(__FreeBSD__) && __FreeBSD_version < 300000
335 static int check_allmulti(int unit);
339 /* array for maping irq numbers to values for the irq parameter register */
340 static int irqvals[16] = {
341 0, 0, 0, 0x01, 0x02, 0x04, 0, 0x08, 0, 0, 0x10, 0x20, 0x40, 0, 0, 0x80
343 /* mask of valid IRQs */
344 #define WL_IRQS (IRQ3|IRQ4|IRQ5|IRQ7|IRQ10|IRQ11|IRQ12|IRQ15)
349 * This function "probes" or checks for the WaveLAN board on the bus to
350 * see if it is there. As far as I can tell, the best break between this
351 * routine and the attach code is to simply determine whether the board
352 * is configured in properly. Currently my approach to this is to write
353 * and read a word from the SRAM on the board being probed. If the word
354 * comes back properly then we assume the board is there. The config
355 * code expects to see a successful return from the probe routine before
356 * attach will be called.
358 * input : address device is mapped to, and unit # being checked
359 * output : a '1' is returned if the board exists, and a 0 otherwise
363 wlprobe(struct isa_device *id)
365 struct wl_softc *sc = &wl_softc[id->id_unit];
366 short base = id->id_iobase;
367 char *str = "wl%d: board out of range [0..%d]\n";
369 unsigned long oldpri;
373 * regular CMD() will not work, since no softc yet
375 #define PCMD(base, hacr) outw((base), (hacr))
378 PCMD(base, HACR_RESET); /* reset the board */
379 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
380 PCMD(base, HACR_RESET); /* reset the board */
381 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
384 /* clear reset command and set PIO#1 in autoincrement mode */
385 PCMD(base, HACR_DEFAULT);
386 PCMD(base, HACR_DEFAULT);
387 outw(PIOR1(base), 0); /* go to beginning of RAM */
388 outsw(PIOP1(base), str, strlen(str)/2+1); /* write string */
390 outw(PIOR1(base), 0); /* rewind */
391 insw(PIOP1(base), inbuf, strlen(str)/2+1); /* read result */
393 if (bcmp(str, inbuf, strlen(str)))
396 sc->chan24 = 0; /* 2.4 Gz: config channel */
397 sc->freq24 = 0; /* 2.4 Gz: frequency */
399 /* read the PSA from the board into temporary storage */
400 wlgetpsa(base, inbuf);
402 /* We read the IRQ value from the PSA on the board. */
403 for (irq = 15; irq >= 0; irq--)
404 if (irqvals[irq] == inbuf[WLPSA_IRQNO])
406 if ((irq == 0) || (irqvals[irq] == 0)){
407 printf("wl%d: PSA corrupt (invalid IRQ value)\n", id->id_unit);
408 id->id_irq = 0; /* no interrupt */
411 * If the IRQ requested by the PSA is already claimed by another
412 * device, the board won't work, but the user can still access the
413 * driver to change the IRQ.
415 id->id_irq = (1<<irq); /* use IRQ from PSA */
424 * This function attaches a WaveLAN board to the "system". The rest of
425 * runtime structures are initialized here (this routine is called after
426 * a successful probe of the board). Once the ethernet address is read
427 * and stored, the board's ifnet structure is attached and readied.
429 * input : isa_dev structure setup in autoconfig
430 * output : board structs and ifnet is setup
434 wlattach(struct isa_device *id)
436 struct wl_softc *sc = (struct wl_softc *) &wl_softc[id->id_unit];
437 short base = id->id_iobase;
439 u_char unit = id->id_unit;
440 struct ifnet *ifp = &sc->wl_if;
443 printf("wlattach: base %x, unit %d\n", base, unit);
445 id->id_ointr = wlintr;
450 sc->hacr = HACR_RESET;
451 callout_init(&sc->watchdog_ch);
452 CMD(unit); /* reset the board */
453 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
455 /* clear reset command and set PIO#2 in parameter access mode */
456 sc->hacr = (HACR_DEFAULT & ~HACR_16BITS);
459 /* Read the PSA from the board for our later reference */
460 wlgetpsa(base, sc->psa);
463 sc->nwid[0] = sc->psa[WLPSA_NWID];
464 sc->nwid[1] = sc->psa[WLPSA_NWID+1];
466 /* fetch MAC address - decide which one first */
467 if (sc->psa[WLPSA_MACSEL] & 1) {
472 for(i=0; i < WAVELAN_ADDR_SIZE; ++i) {
473 sc->wl_addr[i] = sc->psa[j + i];
476 /* enter normal 16 bit mode operation */
477 sc->hacr = HACR_DEFAULT;
481 outw(PIOR1(base), OFFSET_SCB + 8); /* address of scb_crcerrs */
482 outw(PIOP1(base), 0); /* clear scb_crcerrs */
483 outw(PIOP1(base), 0); /* clear scb_alnerrs */
484 outw(PIOP1(base), 0); /* clear scb_rscerrs */
485 outw(PIOP1(base), 0); /* clear scb_ovrnerrs */
487 bzero(ifp, sizeof(ifp));
489 if_initname(ifp, "wl", id->id_unit);
490 ifp->if_mtu = WAVELAN_MTU;
491 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
493 ifp->if_flags |= IFF_DEBUG;
496 ifp->if_flags |= IFF_MULTICAST;
497 #endif /* MULTICAST */
498 ifp->if_init = wlinit;
499 ifp->if_start = wlstart;
500 ifp->if_ioctl = wlioctl;
501 ifp->if_timer = 0; /* paranoia */
507 ether_ifattach(ifp, sc->wl_ac.ac_enaddr);
509 bcopy(&sc->wl_addr[0], sc->wl_ac.ac_enaddr, WAVELAN_ADDR_SIZE);
510 if_printf(ifp, "NWID 0x%02x%02x", sc->nwid[0], sc->nwid[1]);
512 printf(", Freq %d MHz",sc->freq24); /* 2.4 Gz */
513 printf("\n"); /* 2.4 Gz */
522 * Print out interesting information about the 82596.
527 struct wl_softc *sp = WLSOFTC(unit);
531 printf("hasr %04x\n", inw(HASR(base)));
533 printf("scb at %04x:\n ", OFFSET_SCB);
534 outw(PIOR1(base), OFFSET_SCB);
535 for(i = 0; i < 8; i++)
536 printf("%04x ", inw(PIOP1(base)));
539 printf("cu at %04x:\n ", OFFSET_CU);
540 outw(PIOR1(base), OFFSET_CU);
541 for(i = 0; i < 8; i++)
542 printf("%04x ", inw(PIOP1(base)));
545 printf("tbd at %04x:\n ", OFFSET_TBD);
546 outw(PIOR1(base), OFFSET_TBD);
547 for(i = 0; i < 4; i++)
548 printf("%04x ", inw(PIOP1(base)));
552 /* Initialize the Modem Management Controller */
556 struct wl_softc *sp = WLSOFTC(unit);
562 /* enter 8 bit operation */
563 sp->hacr = (HACR_DEFAULT & ~HACR_16BITS);
566 configured = sp->psa[WLPSA_CONFIGURED] & 1;
569 * Set default modem control parameters. Taken from NCR document
572 MMC_WRITE(MMC_JABBER_ENABLE, 0x01);
573 MMC_WRITE(MMC_ANTEN_SEL, 0x02);
574 MMC_WRITE(MMC_IFS, 0x20);
575 MMC_WRITE(MMC_MOD_DELAY, 0x04);
576 MMC_WRITE(MMC_JAM_TIME, 0x38);
577 MMC_WRITE(MMC_DECAY_PRM, 0x00); /* obsolete ? */
578 MMC_WRITE(MMC_DECAY_UPDAT_PRM, 0x00);
580 MMC_WRITE(MMC_LOOPT_SEL, 0x00);
581 if (sp->psa[WLPSA_COMPATNO] & 1) {
582 MMC_WRITE(MMC_THR_PRE_SET, 0x01); /* 0x04 for AT and 0x01 for MCA */
584 MMC_WRITE(MMC_THR_PRE_SET, 0x04); /* 0x04 for AT and 0x01 for MCA */
586 MMC_WRITE(MMC_QUALITY_THR, 0x03);
588 /* use configuration defaults from parameter storage area */
589 if (sp->psa[WLPSA_NWIDENABLE] & 1) {
590 if ((mode & (MOD_PROM | MOD_ENAL)) && wl_ignore_nwid) {
591 MMC_WRITE(MMC_LOOPT_SEL, 0x40);
593 MMC_WRITE(MMC_LOOPT_SEL, 0x00);
596 MMC_WRITE(MMC_LOOPT_SEL, 0x40); /* disable network id check */
598 MMC_WRITE(MMC_THR_PRE_SET, sp->psa[WLPSA_THRESH]);
599 MMC_WRITE(MMC_QUALITY_THR, sp->psa[WLPSA_QUALTHRESH]);
601 MMC_WRITE(MMC_FREEZE, 0x00);
602 MMC_WRITE(MMC_ENCR_ENABLE, 0x00);
604 MMC_WRITE(MMC_NETW_ID_L,sp->nwid[1]); /* set NWID */
605 MMC_WRITE(MMC_NETW_ID_H,sp->nwid[0]);
607 /* enter normal 16 bit mode operation */
608 sp->hacr = HACR_DEFAULT;
610 CMD(unit); /* virtualpc1 needs this! */
612 if (sp->psa[WLPSA_COMPATNO]== /* 2.4 Gz: half-card ver */
613 WLPSA_COMPATNO_WL24B) { /* 2.4 Gz */
614 i=sp->chan24<<4; /* 2.4 Gz: position ch # */
615 MMC_WRITE(MMC_EEADDR,i+0x0f); /* 2.4 Gz: named ch, wc=16 */
616 MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+ /* 2.4 Gz: Download Synths */
617 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: Read EEPROM */
618 for (i=0; i<1000; ++i) { /* 2.4 Gz: wait for download */
619 DELAY(40); /* 2.4 Gz */
620 if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and */
621 &(MMC_EECTRLstat_DWLD /* 2.4 Gz: EEBUSY */
622 +MMC_EECTRLstat_EEBUSY))==0) /* 2.4 Gz: */
623 break; /* 2.4 Gz: download finished */
625 if (i==1000) printf("wl: synth load failed\n"); /* 2.4 Gz */
626 MMC_WRITE(MMC_EEADDR,0x61); /* 2.4 Gz: default pwr, wc=2 */
627 MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+ /* 2.4 Gz: Download Xmit Pwr */
628 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: Read EEPROM */
629 for (i=0; i<1000; ++i) { /* 2.4 Gz: wait for download */
630 DELAY(40); /* 2.4 Gz */
631 if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and */
632 &(MMC_EECTRLstat_DWLD /* 2.4 Gz: EEBUSY */
633 +MMC_EECTRLstat_EEBUSY))==0) /* 2.4 Gz: */
634 break; /* 2.4 Gz: download finished */
636 if (i==1000) printf("wl: xmit pwr load failed\n"); /* 2.4 Gz */
637 MMC_WRITE(MMC_ANALCTRL, /* 2.4 Gz: EXT ant+polarity */
638 MMC_ANALCTRL_ANTPOL + /* 2.4 Gz: */
639 MMC_ANALCTRL_EXTANT); /* 2.4 Gz: */
640 i=sp->chan24<<4; /* 2.4 Gz: position ch # */
641 MMC_WRITE(MMC_EEADDR,i); /* 2.4 Gz: get frequency */
642 MMC_WRITE(MMC_EECTRL, /* 2.4 Gz: EEPROM read */
643 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: */
644 DELAY(40); /* 2.4 Gz */
645 i = wlmmcread(base,MMC_EEDATALrv) /* 2.4 Gz: freq val */
646 + (wlmmcread(base,MMC_EEDATAHrv)<<8); /* 2.4 Gz */
647 sp->freq24 = (i>>6)+2400; /* 2.4 Gz: save real freq */
654 * Another routine that interfaces the "if" layer to this driver.
655 * Simply resets the structures that are used by "upper layers".
656 * As well as calling wlhwrst that does reset the WaveLAN board.
658 * input : softc pointer for this interface
659 * output : structures (if structs) and board are reset
665 struct wl_softc *sc = xsc;
666 struct ifnet *ifp = &sc->wl_if;
671 if (sc->wl_if.if_flags & IFF_DEBUG)
672 printf("wl%d: entered wlinit()\n",sc->unit);
674 #if defined(__DragonFly__) || (defined(__FreeBSD__) && __FreeBSD_version >= 300000)
675 if (TAILQ_EMPTY(&ifp->if_addrhead)) {
677 if (ifp->if_addrlist == (struct ifaddr *)0) {
682 if ((stat = wlhwrst(sc->unit)) == TRUE) {
683 sc->wl_if.if_flags |= IFF_RUNNING; /* same as DSF_RUNNING */
685 * OACTIVE is used by upper-level routines
688 sc->wl_if.if_flags &= ~IFF_OACTIVE; /* same as tbusy below */
690 sc->flags |= DSF_RUNNING;
692 callout_stop(&sc->watchdog_ch);
696 printf("wl%d init(): trouble resetting board.\n", sc->unit);
704 * This routine resets the WaveLAN board that corresponds to the
705 * board number passed in.
707 * input : board number to do a hardware reset
708 * output : board is reset
714 struct wl_softc *sc = WLSOFTC(unit);
717 if (sc->wl_if.if_flags & IFF_DEBUG)
718 printf("wl%d: entered wlhwrst()\n",unit);
720 sc->hacr = HACR_RESET;
721 CMD(unit); /* reset the board */
723 /* clear reset command and set PIO#1 in autoincrement mode */
724 sc->hacr = HACR_DEFAULT;
728 if (sc->wl_if.if_flags & IFF_DEBUG)
729 wlmmcstat(unit); /* Display MMC registers */
731 wlbldcu(unit); /* set up command unit structures */
733 if (wldiag(unit) == 0)
736 if (wlconfig(unit) == 0)
739 * insert code for loopback test here
741 wlrustrt(unit); /* start receive unit */
743 /* enable interrupts */
744 sc->hacr = (HACR_DEFAULT | HACR_INTRON);
753 * This function builds up the command unit structures. It inits
754 * the scp, iscp, scb, cb, tbd, and tbuf.
760 struct wl_softc *sc = WLSOFTC(unit);
761 short base = sc->base;
769 bzero(&scp, sizeof(scp));
771 scp.scp_iscp = OFFSET_ISCP;
772 scp.scp_iscp_base = 0;
773 outw(PIOR1(base), OFFSET_SCP);
774 outsw(PIOP1(base), &scp, sizeof(scp_t)/2);
776 bzero(&iscp, sizeof(iscp));
778 iscp.iscp_scb_offset = OFFSET_SCB;
780 iscp.iscp_scb_base = 0;
781 outw(PIOR1(base), OFFSET_ISCP);
782 outsw(PIOP1(base), &iscp, sizeof(iscp_t)/2);
785 scb.scb_command = SCB_RESET;
786 scb.scb_cbl_offset = OFFSET_CU;
787 scb.scb_rfa_offset = OFFSET_RU;
791 scb.scb_ovrnerrs = 0;
792 outw(PIOR1(base), OFFSET_SCB);
793 outsw(PIOP1(base), &scb, sizeof(scb_t)/2);
797 outw(PIOR0(base), OFFSET_ISCP + 0); /* address of iscp_busy */
798 for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
799 if (i <= 0) printf("wl%d bldcu(): iscp_busy timeout.\n", unit);
800 outw(PIOR0(base), OFFSET_SCB + 0); /* address of scb_status */
801 for (i = STATUS_TRIES; i-- > 0; ) {
802 if (inw(PIOP0(base)) == (SCB_SW_CX|SCB_SW_CNA))
806 printf("wl%d bldcu(): not ready after reset.\n", unit);
810 cb.ac_command = AC_CW_EL; /* NOP */
811 cb.ac_link_offset = OFFSET_CU;
812 outw(PIOR1(base), OFFSET_CU);
813 outsw(PIOP1(base), &cb, 6/2);
816 tbd.next_tbd_offset = I82586NULL;
819 outw(PIOR1(base), OFFSET_TBD);
820 outsw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
828 * input : board number
829 * output : stuff sent to board if any there
833 wlstart(struct ifnet *ifp)
835 int unit = ifp->if_dunit;
837 struct wl_softc *sc = WLSOFTC(unit);
838 short base = sc->base;
839 int scb_status, cu_status, scb_command;
842 if (sc->wl_if.if_flags & IFF_DEBUG)
843 printf("wl%d: entered wlstart()\n",unit);
846 outw(PIOR1(base), OFFSET_CU);
847 cu_status = inw(PIOP1(base));
848 outw(PIOR0(base),OFFSET_SCB + 0); /* scb_status */
849 scb_status = inw(PIOP0(base));
850 outw(PIOR0(base), OFFSET_SCB + 2);
851 scb_command = inw(PIOP0(base));
854 * don't need OACTIVE check as tbusy here checks to see
855 * if we are already busy
858 if((scb_status & 0x0700) == SCB_CUS_IDLE &&
859 (cu_status & AC_SW_B) == 0){
861 callout_stop(&sc->watchdog_ch);
862 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
864 * This is probably just a race. The xmt'r is just
865 * became idle but WE have masked interrupts so ...
868 printf("wl%d: CU idle, scb %04x %04x cu %04x\n",
869 unit, scb_status, scb_command, cu_status);
871 if (xmt_watch) printf("!!");
873 return; /* genuinely still busy */
875 } else if((scb_status & 0x0700) == SCB_CUS_ACTV ||
876 (cu_status & AC_SW_B)){
878 printf("wl%d: CU unexpectedly busy; scb %04x cu %04x\n",
879 unit, scb_status, cu_status);
881 if (xmt_watch) printf("wl%d: busy?!",unit);
882 return; /* hey, why are we busy? */
885 /* get ourselves some data */
887 IF_DEQUEUE(&ifp->if_snd, m);
888 if (m != (struct mbuf *)0) {
891 /* set the watchdog timer so that if the board
892 * fails to interrupt we will restart
894 /* try 10 ticks, not very long */
895 callout_reset(&sc->watchdog_ch, 10, wlwatchdog, sc);
896 sc->wl_ac.ac_if.if_flags |= IFF_OACTIVE;
897 sc->wl_if.if_opackets++;
900 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
908 * This routine does the actual copy of data (including ethernet header
909 * structure) from the WaveLAN to an mbuf chain that will be passed up
910 * to the "if" (network interface) layer. NOTE: we currently
911 * don't handle trailer protocols, so if that is needed, it will
912 * (at least in part) be added here. For simplicities sake, this
913 * routine copies the receive buffers from the board into a local (stack)
914 * buffer until the frame has been copied from the board. Once in
915 * the local buffer, the contents are copied to an mbuf chain that
916 * is then enqueued onto the appropriate "if" queue.
918 * input : board number, and an frame descriptor address
919 * output : the packet is put into an mbuf chain, and passed up
920 * assumes : if any errors occur, packet is "dropped on the floor"
924 wlread(int unit, u_short fd_p)
926 struct wl_softc *sc = WLSOFTC(unit);
927 struct ifnet *ifp = &sc->wl_if;
928 short base = sc->base;
930 struct ether_header eh;
934 u_short mlen, len, clen;
935 u_short bytes_in_msg, bytes_in_mbuf, bytes;
939 if (sc->wl_if.if_flags & IFF_DEBUG)
940 printf("wl%d: entered wlread()\n",unit);
942 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
943 printf("%s read(): board is not running.\n", ifp->if_xname);
944 sc->hacr &= ~HACR_INTRON;
945 CMD(unit); /* turn off interrupts */
947 /* read ether_header info out of device memory. doesn't
948 * go into mbuf. goes directly into eh structure
950 len = sizeof(struct ether_header); /* 14 bytes */
951 outw(PIOR1(base), fd_p);
952 insw(PIOP1(base), &fd, (sizeof(fd_t) - len)/2);
953 insw(PIOP1(base), &eh, (len-2)/2);
954 eh.ether_type = ntohs(inw(PIOP1(base)));
956 if (sc->wl_if.if_flags & IFF_DEBUG) {
957 printf("wlread: rcv packet, type is %x\n", eh.ether_type);
961 * WARNING. above is done now in ether_input, above may be
962 * useful for debug. jrb
964 eh.ether_type = htons(eh.ether_type);
966 if (fd.rbd_offset == I82586NULL) {
967 printf("wl%d read(): Invalid buffer\n", unit);
968 if (wlhwrst(unit) != TRUE) {
969 printf("wl%d read(): hwrst trouble.\n", unit);
974 outw(PIOR1(base), fd.rbd_offset);
975 insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
976 bytes_in_msg = rbd.status & RBD_SW_COUNT;
977 MGETHDR(m, MB_DONTWAIT, MT_DATA);
979 if (m == (struct mbuf *)0) {
981 * not only do we want to return, we need to drop the packet on
982 * the floor to clear the interrupt.
985 if (wlhwrst(unit) != TRUE) {
986 sc->hacr &= ~HACR_INTRON;
987 CMD(unit); /* turn off interrupts */
988 printf("wl%d read(): hwrst trouble.\n", unit);
992 m->m_next = (struct mbuf *) 0;
993 m->m_pkthdr.rcvif = ifp;
994 m->m_pkthdr.len = 0; /* don't know this yet */
997 /* always use a cluster. jrb
999 MCLGET(m, MB_DONTWAIT);
1000 if (m->m_flags & M_EXT) {
1001 m->m_len = MCLBYTES;
1005 if (wlhwrst(unit) != TRUE) {
1006 sc->hacr &= ~HACR_INTRON;
1007 CMD(unit); /* turn off interrupts */
1008 printf("wl%d read(): hwrst trouble.\n", unit);
1015 bytes_in_mbuf = m->m_len;
1016 mb_p = mtod(tm, u_char *);
1017 bytes = min(bytes_in_mbuf, bytes_in_msg);
1024 outw(PIOR1(base), rbd.buffer_addr);
1025 insw(PIOP1(base), mb_p, len/2);
1029 if (!(bytes_in_mbuf -= bytes)) {
1030 MGET(tm->m_next, MB_DONTWAIT, MT_DATA);
1032 if (tm == (struct mbuf *)0) {
1034 printf("wl%d read(): No mbuf nth\n", unit);
1035 if (wlhwrst(unit) != TRUE) {
1036 sc->hacr &= ~HACR_INTRON;
1037 CMD(unit); /* turn off interrupts */
1038 printf("wl%d read(): hwrst trouble.\n", unit);
1044 bytes_in_mbuf = MLEN;
1045 mb_p = mtod(tm, u_char *);
1050 if (!(bytes_in_msg -= bytes)) {
1051 if (rbd.status & RBD_SW_EOF ||
1052 rbd.next_rbd_offset == I82586NULL) {
1056 outw(PIOR1(base), rbd.next_rbd_offset);
1057 insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1058 bytes_in_msg = rbd.status & RBD_SW_COUNT;
1061 rbd.buffer_addr += bytes;
1064 bytes = min(bytes_in_mbuf, bytes_in_msg);
1067 m->m_pkthdr.len = clen;
1070 * If hw is in promiscuous mode (note that I said hardware, not if
1071 * IFF_PROMISC is set in ifnet flags), then if this is a unicast
1072 * packet and the MAC dst is not us, drop it. This check in normally
1073 * inside ether_input(), but IFF_MULTI causes hw promisc without
1074 * a bpf listener, so this is wrong.
1075 * Greg Troxel <gdt@ir.bbn.com>, 1998-08-07
1078 * TBD: also discard packets where NWID does not match.
1079 * However, there does not appear to be a way to read the nwid
1080 * for a received packet. -gdt 1998-08-07
1083 #ifdef WL_USE_IFNET_PROMISC_CHECK /* not defined */
1084 (sc->wl_ac.ac_if.if_flags & (IFF_PROMISC|IFF_ALLMULTI))
1086 /* hw is in promisc mode if this is true */
1087 (sc->mode & (MOD_PROM | MOD_ENAL))
1090 (eh.ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
1091 bcmp(eh.ether_dhost, sc->wl_ac.ac_enaddr,
1092 sizeof(eh.ether_dhost)) != 0 ) {
1098 if (sc->wl_if.if_flags & IFF_DEBUG)
1099 printf("wl%d: wlrecv %d bytes\n", unit, clen);
1103 wl_cache_store(unit, base, &eh, m);
1107 * received packet is now in a chain of mbuf's. next step is
1108 * to pass the packet upwards.
1111 ether_input(&sc->wl_if, &eh, m);
1118 * This routine processes an ioctl request from the "if" layer
1121 * input : pointer the appropriate "if" struct, command, and data
1122 * output : based on command appropriate action is taken on the
1123 * WaveLAN board(s) or related structures
1124 * return : error is returned containing exit conditions
1128 wlioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cred)
1130 struct ifreq *ifr = (struct ifreq *)data;
1131 int unit = ifp->if_dunit;
1132 struct wl_softc *sc = WLSOFTC(unit);
1133 short base = sc->base;
1135 int opri, error = 0;
1136 int irq, irqval, i, isroot, size;
1139 struct thread *td = curthread; /* XXX */
1143 if (sc->wl_if.if_flags & IFF_DEBUG)
1144 printf("wl%d: entered wlioctl()\n",unit);
1151 error = ether_ioctl(ifp, cmd, data);
1155 if (ifp->if_flags & IFF_ALLMULTI) {
1158 if (ifp->if_flags & IFF_PROMISC) {
1161 if(ifp->if_flags & IFF_LINK0) {
1165 * force a complete reset if the recieve multicast/
1166 * promiscuous mode changes so that these take
1167 * effect immediately.
1170 if (sc->mode != mode) {
1172 if (sc->flags & DSF_RUNNING) {
1173 sc->flags &= ~DSF_RUNNING;
1177 /* if interface is marked DOWN and still running then
1180 if ((ifp->if_flags & IFF_UP) == 0 && sc->flags & DSF_RUNNING) {
1181 printf("wl%d ioctl(): board is not running\n", unit);
1182 sc->flags &= ~DSF_RUNNING;
1183 sc->hacr &= ~HACR_INTRON;
1184 CMD(unit); /* turn off interrupts */
1186 /* else if interface is UP and RUNNING, start it
1188 else if (ifp->if_flags & IFF_UP && (sc->flags & DSF_RUNNING) == 0) {
1192 /* if WLDEBUG set on interface, then printf rf-modem regs
1194 if(ifp->if_flags & IFF_DEBUG)
1201 #if defined(__FreeBSD__) && __FreeBSD_version < 300000
1202 if (cmd == SIOCADDMULTI) {
1203 error = ether_addmulti(ifr, &sc->wl_ac);
1206 error = ether_delmulti(ifr, &sc->wl_ac);
1209 /* see if we should be in all multicast mode
1210 * note that 82586 cannot do that, must simulate with
1213 if ( check_allmulti(unit)) {
1214 ifp->if_flags |= IFF_ALLMULTI;
1215 sc->mode |= MOD_ENAL;
1216 sc->flags &= ~DSF_RUNNING;
1222 if (error == ENETRESET) {
1223 if(sc->flags & DSF_RUNNING) {
1224 sc->flags &= ~DSF_RUNNING;
1233 #endif /* MULTICAST */
1235 /* DEVICE SPECIFIC */
1238 /* copy the PSA out to the caller */
1240 /* pointer to buffer in user space */
1241 up = (void *)ifr->ifr_data;
1242 /* work out if they're root */
1243 isroot = (suser(td) == 0);
1245 for (i = 0; i < 0x40; i++) {
1246 /* don't hand the DES key out to non-root users */
1247 if ((i > WLPSA_DESKEY) && (i < (WLPSA_DESKEY + 8)) && !isroot)
1249 if (subyte((up + i), sc->psa[i]))
1255 /* copy the PSA in from the caller; we only copy _some_ values */
1258 if ((error = suser(td)))
1260 error = EINVAL; /* assume the worst */
1261 /* pointer to buffer in user space containing data */
1262 up = (void *)ifr->ifr_data;
1264 /* check validity of input range */
1265 for (i = 0; i < 0x40; i++)
1266 if (fubyte(up + i) < 0)
1269 /* check IRQ value */
1270 irqval = fubyte(up+WLPSA_IRQNO);
1271 for (irq = 15; irq >= 0; irq--)
1272 if(irqvals[irq] == irqval)
1274 if (irq == 0) /* oops */
1277 sc->psa[WLPSA_IRQNO] = irqval;
1280 for (i = 0; i < 6; i++)
1281 sc->psa[WLPSA_LOCALMAC+i] = fubyte(up+WLPSA_LOCALMAC+i);
1284 sc->psa[WLPSA_MACSEL] = fubyte(up+WLPSA_MACSEL);
1287 sc->psa[WLPSA_NWID] = fubyte(up+WLPSA_NWID);
1288 sc->psa[WLPSA_NWID+1] = fubyte(up+WLPSA_NWID+1);
1291 wlsetpsa(unit); /* update the PSA */
1295 /* get the current NWID out of the sc since we stored it there */
1297 ifr->ifr_data = (caddr_t) (sc->nwid[0] << 8 | sc->nwid[1]);
1302 * change the nwid dynamically. This
1303 * ONLY changes the radio modem and does not
1307 * 1. save in softc "soft registers"
1308 * 2. save in radio modem (MMC)
1312 if ((error = suser(td)))
1314 if (!(ifp->if_flags & IFF_UP)) {
1315 error = EIO; /* only allowed while up */
1318 * soft c nwid shadows radio modem setting
1320 sc->nwid[0] = (int)ifr->ifr_data >> 8;
1321 sc->nwid[1] = (int)ifr->ifr_data & 0xff;
1322 MMC_WRITE(MMC_NETW_ID_L,sc->nwid[1]);
1323 MMC_WRITE(MMC_NETW_ID_H,sc->nwid[0]);
1327 /* copy the EEPROM in 2.4 Gz WaveMODEM out to the caller */
1330 if ((error = suser(td)))
1332 /* pointer to buffer in user space */
1333 up = (void *)ifr->ifr_data;
1335 for (i=0x00; i<0x80; ++i) { /* 2.4 Gz: size of EEPROM */
1336 MMC_WRITE(MMC_EEADDR,i); /* 2.4 Gz: get frequency */
1337 MMC_WRITE(MMC_EECTRL, /* 2.4 Gz: EEPROM read */
1338 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: */
1339 DELAY(40); /* 2.4 Gz */
1340 if (subyte(up + 2*i , /* 2.4 Gz: pass low byte of */
1341 wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word */
1342 ) return(EFAULT); /* 2.4 Gz: */
1343 if (subyte(up + 2*i+1, /* 2.4 Gz: pass hi byte of */
1344 wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word */
1345 ) return(EFAULT); /* 2.4 Gz: */
1350 /* zero (Delete) the wl cache */
1353 if ((error = suser(td)))
1355 wl_cache_zero(unit);
1358 /* read out the number of used cache elements */
1360 ifr->ifr_data = (caddr_t) sc->w_sigitems;
1363 /* read out the wl cache */
1365 /* pointer to buffer in user space */
1366 up = (void *)ifr->ifr_data;
1367 cpt = (char *) &sc->w_sigcache[0];
1368 size = sc->w_sigitems * sizeof(struct w_sigcache);
1370 for (i = 0; i < size; i++) {
1371 if (subyte((up + i), *cpt++))
1387 * Called if the timer set in wlstart expires before an interrupt is received
1388 * from the wavelan. It seems to lose interrupts sometimes.
1389 * The watchdog routine gets called if the transmitter failed to interrupt
1391 * input : which board is timing out
1392 * output : board reset
1396 wlwatchdog(void *vsc)
1398 struct wl_softc *sc = vsc;
1399 int unit = sc->unit;
1401 log(LOG_ERR, "wl%d: wavelan device timeout on xmit\n", unit);
1402 sc->wl_ac.ac_if.if_oerrors++;
1409 * This function is the interrupt handler for the WaveLAN
1410 * board. This routine will be called whenever either a packet
1411 * is received, or a packet has successfully been transfered and
1412 * the unit is ready to transmit another packet.
1414 * input : board number that interrupted
1415 * output : either a packet is received, or a packet is transfered
1422 struct wl_softc *sc = &wl_softc[unit];
1423 short base = sc->base;
1425 u_short int_type, int_type1;
1428 if (sc->wl_if.if_flags & IFF_DEBUG)
1429 printf("wl%d: wlintr() called\n",unit);
1432 if((int_type = inw(HASR(base))) & HASR_MMC_INTR) {
1433 /* handle interrupt from the modem management controler */
1434 /* This will clear the interrupt condition */
1435 (void) wlmmcread(base,MMC_DCE_STATUS); /* ignored for now */
1438 if(!(int_type & HASR_INTR)){ /* return if no interrupt from 82586 */
1439 /* commented out. jrb. it happens when reinit occurs
1440 printf("wlintr: int_type %x, dump follows\n", int_type);
1449 outw(PIOR0(base), OFFSET_SCB + 0); /* get scb status */
1450 int_type = (inw(PIOP0(base)) & SCB_SW_INT);
1451 if (int_type == 0) /* no interrupts left */
1454 int_type1 = wlack(unit); /* acknowledge interrupt(s) */
1455 /* make sure no bits disappeared (others may appear) */
1456 if ((int_type & int_type1) != int_type)
1457 printf("wlack() int bits disappeared : %04x != int_type %04x\n",
1458 int_type1, int_type);
1459 int_type = int_type1; /* go with the new status */
1463 if (int_type & SCB_SW_FR) {
1464 sc->wl_if.if_ipackets++;
1468 * receiver not ready
1470 if (int_type & SCB_SW_RNR) {
1471 sc->wl_if.if_ierrors++;
1473 if (sc->wl_if.if_flags & IFF_DEBUG)
1474 printf("wl%d intr(): receiver overrun! begin_fd = %x\n",
1475 unit, sc->begin_fd);
1482 if (int_type & SCB_SW_CNA) {
1484 * At present, we don't care about CNA's. We
1485 * believe they are a side effect of XMT.
1488 if (int_type & SCB_SW_CX) {
1490 * At present, we only request Interrupt for
1493 outw(PIOR1(base), OFFSET_CU); /* get command status */
1494 ac_status = inw(PIOP1(base));
1496 if (xmt_watch) { /* report some anomalies */
1498 if (sc->tbusy == 0) {
1499 printf("wl%d: xmt intr but not busy, CU %04x\n",
1502 if (ac_status == 0) {
1503 printf("wl%d: xmt intr but ac_status == 0\n", unit);
1505 if (ac_status & AC_SW_A) {
1506 printf("wl%d: xmt aborted\n",unit);
1509 if (ac_status & TC_CARRIER) {
1510 printf("wl%d: no carrier\n", unit);
1513 if (ac_status & TC_CLS) {
1514 printf("wl%d: no CTS\n", unit);
1516 if (ac_status & TC_DMA) {
1517 printf("wl%d: DMA underrun\n", unit);
1519 if (ac_status & TC_DEFER) {
1520 printf("wl%d: xmt deferred\n",unit);
1522 if (ac_status & TC_SQE) {
1523 printf("wl%d: heart beat\n", unit);
1525 if (ac_status & TC_COLLISION) {
1526 printf("wl%d: too many collisions\n", unit);
1529 /* if the transmit actually failed, or returned some status */
1530 if ((!(ac_status & AC_SW_OK)) || (ac_status & 0xfff)) {
1531 if (ac_status & (TC_COLLISION | TC_CLS | TC_DMA)) {
1532 sc->wl_if.if_oerrors++;
1534 /* count collisions */
1535 sc->wl_if.if_collisions += (ac_status & 0xf);
1536 /* if TC_COLLISION set and collision count zero, 16 collisions */
1537 if ((ac_status & 0x20) == 0x20) {
1538 sc->wl_if.if_collisions += 0x10;
1542 callout_stop(&sc->watchdog_ch);
1543 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
1544 wlstart(&(sc->wl_if));
1553 * This routine is called by the interrupt handler to initiate a
1554 * packet transfer from the board to the "if" layer above this
1555 * driver. This routine checks if a buffer has been successfully
1556 * received by the WaveLAN. If so, the routine wlread is called
1557 * to do the actual transfer of the board data (including the
1558 * ethernet header) into a packet (consisting of an mbuf chain).
1560 * input : number of the board to check
1561 * output : if a packet is available, it is "sent up"
1567 struct wl_softc *sc = WLSOFTC(unit);
1568 short base = sc->base;
1569 u_short fd_p, status, offset, link_offset;
1572 if (sc->wl_if.if_flags & IFF_DEBUG)
1573 printf("wl%d: entered wlrcv()\n",unit);
1575 for (fd_p = sc->begin_fd; fd_p != I82586NULL; fd_p = sc->begin_fd) {
1577 outw(PIOR0(base), fd_p + 0); /* address of status */
1578 status = inw(PIOP0(base));
1579 outw(PIOR1(base), fd_p + 4); /* address of link_offset */
1580 link_offset = inw(PIOP1(base));
1581 offset = inw(PIOP1(base)); /* rbd_offset */
1582 if (status == 0xffff || offset == 0xffff /*I82586NULL*/) {
1583 if (wlhwrst(unit) != TRUE)
1584 printf("wl%d rcv(): hwrst ffff trouble.\n", unit);
1586 } else if (status & AC_SW_C) {
1587 if (status == (RFD_DONE|RFD_RSC)) {
1590 if (sc->wl_if.if_flags & IFF_DEBUG)
1591 printf("wl%d RCV: RSC %x\n", unit, status);
1593 sc->wl_if.if_ierrors++;
1594 } else if (!(status & RFD_OK)) {
1595 printf("wl%d RCV: !OK %x\n", unit, status);
1596 sc->wl_if.if_ierrors++;
1597 } else if (status & 0xfff) { /* can't happen */
1598 printf("wl%d RCV: ERRs %x\n", unit, status);
1599 sc->wl_if.if_ierrors++;
1600 } else if (!wlread(unit, fd_p))
1603 if (!wlrequeue(unit, fd_p)) {
1604 /* abort on chain error */
1605 if (wlhwrst(unit) != TRUE)
1606 printf("wl%d rcv(): hwrst trouble.\n", unit);
1609 sc->begin_fd = link_offset;
1620 * This routine puts rbd's used in the last receive back onto the
1621 * free list for the next receive.
1625 wlrequeue(int unit, u_short fd_p)
1627 struct wl_softc *sc = WLSOFTC(unit);
1628 short base = sc->base;
1630 u_short l_rbdp, f_rbdp, rbd_offset;
1632 outw(PIOR0(base), fd_p + 6);
1633 rbd_offset = inw(PIOP0(base));
1634 if ((f_rbdp = rbd_offset) != I82586NULL) {
1637 outw(PIOR0(base), l_rbdp + 0); /* address of status */
1638 if(inw(PIOP0(base)) & RBD_SW_EOF)
1640 outw(PIOP0(base), 0);
1641 outw(PIOR0(base), l_rbdp + 2); /* next_rbd_offset */
1642 if((l_rbdp = inw(PIOP0(base))) == I82586NULL)
1645 outw(PIOP0(base), 0);
1646 outw(PIOR0(base), l_rbdp + 2); /* next_rbd_offset */
1647 outw(PIOP0(base), I82586NULL);
1648 outw(PIOR0(base), l_rbdp + 8); /* address of size */
1649 outw(PIOP0(base), inw(PIOP0(base)) | AC_CW_EL);
1650 outw(PIOR0(base), sc->end_rbd + 2);
1651 outw(PIOP0(base), f_rbdp); /* end_rbd->next_rbd_offset */
1652 outw(PIOR0(base), sc->end_rbd + 8); /* size */
1653 outw(PIOP0(base), inw(PIOP0(base)) & ~AC_CW_EL);
1654 sc->end_rbd = l_rbdp;
1658 fd.command = AC_CW_EL;
1659 fd.link_offset = I82586NULL;
1660 fd.rbd_offset = I82586NULL;
1661 outw(PIOR1(base), fd_p);
1662 outsw(PIOP1(base), &fd, 8/2);
1664 outw(PIOR1(base), sc->end_fd + 2); /* addr of command */
1665 outw(PIOP1(base), 0); /* command = 0 */
1666 outw(PIOP1(base), fd_p); /* end_fd->link_offset = fd_p */
1673 static int xmt_debug = 0;
1674 #endif /* WLDEBUG */
1679 * This routine fills in the appropriate registers and memory
1680 * locations on the WaveLAN board and starts the board off on
1683 * input : board number of interest, and a pointer to the mbuf
1684 * output : board memory and registers are set for xfer and attention
1688 wlxmt(int unit, struct mbuf *m)
1690 struct wl_softc *sc = WLSOFTC(unit);
1691 u_short xmtdata_p = OFFSET_TBUF;
1693 struct mbuf *tm_p = m;
1694 struct ether_header *eh_p = mtod(m, struct ether_header *);
1695 u_char *mb_p = mtod(m, u_char *) + sizeof(struct ether_header);
1696 u_short count = m->m_len - sizeof(struct ether_header);
1698 u_short tbd_p = OFFSET_TBD;
1699 u_short len, clen = 0;
1700 short base = sc->base;
1704 if (sc->wl_if.if_flags & IFF_DEBUG)
1705 printf("wl%d: entered wlxmt()\n",unit);
1709 cb.ac_command = (AC_CW_EL|AC_TRANSMIT|AC_CW_I);
1710 cb.ac_link_offset = I82586NULL;
1711 outw(PIOR1(base), OFFSET_CU);
1712 outsw(PIOP1(base), &cb, 6/2);
1713 outw(PIOP1(base), OFFSET_TBD); /* cb.cmd.transmit.tbd_offset */
1714 outsw(PIOP1(base), eh_p->ether_dhost, WAVELAN_ADDR_SIZE/2);
1715 outw(PIOP1(base), eh_p->ether_type);
1718 if (sc->wl_if.if_flags & IFF_DEBUG) {
1720 printf("XMT mbuf: L%d @%p ", count, (void *)mb_p);
1721 printf("ether type %x\n", eh_p->ether_type);
1724 #endif /* WLDEBUG */
1725 outw(PIOR0(base), OFFSET_TBD);
1726 outw(PIOP0(base), 0); /* act_count */
1727 outw(PIOR1(base), OFFSET_TBD + 4);
1728 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1729 outw(PIOP1(base), 0); /* buffer_base */
1732 if (clen + count > WAVELAN_MTU)
1738 outw(PIOR1(base), xmtdata_p);
1739 outsw(PIOP1(base), mb_p, len/2);
1741 outw(PIOR0(base), tbd_p); /* address of act_count */
1742 outw(PIOP0(base), inw(PIOP0(base)) + count);
1744 if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1747 /* go to the next descriptor */
1748 outw(PIOR0(base), tbd_p + 2);
1749 tbd_p += sizeof (tbd_t);
1750 outw(PIOP0(base), tbd_p); /* next_tbd_offset */
1751 outw(PIOR0(base), tbd_p);
1752 outw(PIOP0(base), 0); /* act_count */
1753 outw(PIOR1(base), tbd_p + 4);
1754 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1755 outw(PIOP1(base), 0); /* buffer_base */
1756 /* at the end -> coallesce remaining mbufs */
1757 if (tbd_p == OFFSET_TBD + (N_TBD-1) * sizeof (tbd_t)) {
1758 wlsftwsleaze(&count, &mb_p, &tm_p, unit);
1761 /* next mbuf short -> coallesce as needed */
1762 if ( (tm_p->m_next == (struct mbuf *) 0) ||
1763 #define HDW_THRESHOLD 55
1764 tm_p->m_len > HDW_THRESHOLD)
1767 wlhdwsleaze(&count, &mb_p, &tm_p, unit);
1771 } else if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1773 count = tm_p->m_len;
1774 mb_p = mtod(tm_p, u_char *);
1776 if (sc->wl_if.if_flags & IFF_DEBUG)
1778 printf("mbuf+ L%d @%p ", count, (void *)mb_p);
1779 #endif /* WLDEBUG */
1782 if (sc->wl_if.if_flags & IFF_DEBUG)
1784 printf("CLEN = %d\n", clen);
1785 #endif /* WLDEBUG */
1786 outw(PIOR0(base), tbd_p);
1787 if (clen < ETHERMIN) {
1788 outw(PIOP0(base), inw(PIOP0(base)) + ETHERMIN - clen);
1789 outw(PIOR1(base), xmtdata_p);
1790 for (xmtshort_p = xmtdata_p; clen < ETHERMIN; clen += 2)
1791 outw(PIOP1(base), 0);
1793 outw(PIOP0(base), inw(PIOP0(base)) | TBD_SW_EOF);
1794 outw(PIOR0(base), tbd_p + 2);
1795 outw(PIOP0(base), I82586NULL);
1797 if (sc->wl_if.if_flags & IFF_DEBUG) {
1803 #endif /* WLDEBUG */
1805 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
1807 * wait for 586 to clear previous command, complain if it takes
1810 for (spin = 1;;spin = (spin + 1) % 10000) {
1811 if (inw(PIOP0(base)) == 0) { /* it's done, we can go */
1814 if ((spin == 0) && xmt_watch) { /* not waking up, and we care */
1815 printf("wl%d: slow accepting xmit\n",unit);
1818 outw(PIOP0(base), SCB_CU_STRT); /* new command */
1819 SET_CHAN_ATTN(unit);
1824 * Pause to avoid transmit overrun problems.
1825 * The required delay tends to vary with platform type, and may be
1826 * related to interrupt loss.
1828 if (wl_xmit_delay) {
1829 DELAY(wl_xmit_delay);
1837 * This function builds the linear linked lists of fd's and
1838 * rbd's. Based on page 4-32 of 1986 Intel microcom handbook.
1844 struct wl_softc *sc = WLSOFTC(unit);
1845 short base = sc->base;
1848 u_short fd_p = OFFSET_RU;
1849 u_short rbd_p = OFFSET_RBD;
1852 sc->begin_fd = fd_p;
1853 for(i = 0; i < N_FD; i++) {
1856 fd.link_offset = fd_p + sizeof(fd_t);
1857 fd.rbd_offset = I82586NULL;
1858 outw(PIOR1(base), fd_p);
1859 outsw(PIOP1(base), &fd, 8/2);
1860 fd_p = fd.link_offset;
1862 fd_p -= sizeof(fd_t);
1864 outw(PIOR1(base), fd_p + 2);
1865 outw(PIOP1(base), AC_CW_EL); /* command */
1866 outw(PIOP1(base), I82586NULL); /* link_offset */
1869 outw(PIOR0(base), fd_p + 6); /* address of rbd_offset */
1870 outw(PIOP0(base), rbd_p);
1871 outw(PIOR1(base), rbd_p);
1872 for(i = 0; i < N_RBD; i++) {
1874 rbd.buffer_addr = rbd_p + sizeof(rbd_t) + 2;
1875 rbd.buffer_base = 0;
1876 rbd.size = RCVBUFSIZE;
1878 rbd_p += sizeof(ru_t);
1879 rbd.next_rbd_offset = rbd_p;
1881 rbd.next_rbd_offset = I82586NULL;
1882 rbd.size |= AC_CW_EL;
1883 sc->end_rbd = rbd_p;
1885 outsw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1886 outw(PIOR1(base), rbd_p);
1888 return sc->begin_fd;
1894 * This routine starts the receive unit running. First checks if the
1895 * board is actually ready, then the board is instructed to receive
1902 struct wl_softc *sc = WLSOFTC(unit);
1903 short base = sc->base;
1907 if (sc->wl_if.if_flags & IFF_DEBUG)
1908 printf("wl%d: entered wlrustrt()\n",unit);
1910 outw(PIOR0(base), OFFSET_SCB);
1911 if (inw(PIOP0(base)) & SCB_RUS_READY){
1912 printf("wlrustrt: RUS_READY\n");
1916 outw(PIOR0(base), OFFSET_SCB + 2);
1917 outw(PIOP0(base), SCB_RU_STRT); /* command */
1918 rfa = wlbldru(unit);
1919 outw(PIOR0(base), OFFSET_SCB + 6); /* address of scb_rfa_offset */
1920 outw(PIOP0(base), rfa);
1922 SET_CHAN_ATTN(unit);
1929 * This routine does a 586 op-code number 7, and obtains the
1930 * diagnose status for the WaveLAN.
1936 struct wl_softc *sc = WLSOFTC(unit);
1937 short base = sc->base;
1941 if (sc->wl_if.if_flags & IFF_DEBUG)
1942 printf("wl%d: entered wldiag()\n",unit);
1944 outw(PIOR0(base), OFFSET_SCB);
1945 status = inw(PIOP0(base));
1946 if (status & SCB_SW_INT) {
1947 /* state is 2000 which seems ok
1948 printf("wl%d diag(): unexpected initial state %\n",
1949 unit, inw(PIOP0(base)));
1953 outw(PIOR1(base), OFFSET_CU);
1954 outw(PIOP1(base), 0); /* ac_status */
1955 outw(PIOP1(base), AC_DIAGNOSE|AC_CW_EL);/* ac_command */
1956 if(wlcmd(unit, "diag()") == 0)
1958 outw(PIOR0(base), OFFSET_CU);
1959 if (inw(PIOP0(base)) & 0x0800) {
1960 printf("wl%d: i82586 Self Test failed!\n", unit);
1969 * This routine does a standard config of the WaveLAN board.
1975 configure_t configure;
1976 struct wl_softc *sc = WLSOFTC(unit);
1977 short base = sc->base;
1980 #if defined(__DragonFly__) || (defined(__FreeBSD__) && __FreeBSD_version >= 300000)
1981 struct ifmultiaddr *ifma;
1984 struct ether_multi *enm;
1985 struct ether_multistep step;
1988 #endif /* MULTICAST */
1991 if (sc->wl_if.if_flags & IFF_DEBUG)
1992 printf("wl%d: entered wlconfig()\n",unit);
1994 outw(PIOR0(base), OFFSET_SCB);
1995 if (inw(PIOP0(base)) & SCB_SW_INT) {
1997 printf("wl%d config(): unexpected initial state %x\n",
1998 unit, inw(PIOP0(base)));
2003 outw(PIOR1(base), OFFSET_CU);
2004 outw(PIOP1(base), 0); /* ac_status */
2005 outw(PIOP1(base), AC_CONFIGURE|AC_CW_EL); /* ac_command */
2008 configure.fifolim_bytecnt = 0x080c;
2009 configure.addrlen_mode = 0x0600;
2010 configure.linprio_interframe = 0x2060;
2011 configure.slot_time = 0xf200;
2012 configure.hardware = 0x0008; /* tx even w/o CD */
2013 configure.min_frame_len = 0x0040;
2015 /* This is the configuration block suggested by Marc Meertens
2016 * <mmeerten@obelix.utrecht.NCR.COM> in an e-mail message to John
2017 * Ioannidis on 10 Nov 92.
2019 configure.fifolim_bytecnt = 0x040c;
2020 configure.addrlen_mode = 0x0600;
2021 configure.linprio_interframe = 0x2060;
2022 configure.slot_time = 0xf000;
2023 configure.hardware = 0x0008; /* tx even w/o CD */
2024 configure.min_frame_len = 0x0040;
2027 * below is the default board configuration from p2-28 from 586 book
2029 configure.fifolim_bytecnt = 0x080c;
2030 configure.addrlen_mode = 0x2600;
2031 configure.linprio_interframe = 0x7820; /* IFS=120, ACS=2 */
2032 configure.slot_time = 0xf00c; /* slottime=12 */
2033 configure.hardware = 0x0008; /* tx even w/o CD */
2034 configure.min_frame_len = 0x0040;
2036 if(sc->mode & (MOD_PROM | MOD_ENAL)) {
2037 configure.hardware |= 1;
2039 outw(PIOR1(base), OFFSET_CU + 6);
2040 outsw(PIOP1(base), &configure, sizeof(configure_t)/2);
2042 if(wlcmd(unit, "config()-configure") == 0)
2045 outw(PIOR1(base), OFFSET_CU);
2046 outw(PIOP1(base), 0); /* ac_status */
2047 outw(PIOP1(base), AC_MCSETUP|AC_CW_EL); /* ac_command */
2048 outw(PIOR1(base), OFFSET_CU + 8);
2049 #if defined(__DragonFly__) || (defined(__FreeBSD__) && __FreeBSD_version >= 300000)
2050 for (ifma = sc->wl_if.if_multiaddrs.lh_first; ifma;
2051 ifma = ifma->ifma_link.le_next) {
2052 if (ifma->ifma_addr->sa_family != AF_LINK)
2055 addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
2056 outw(PIOP1(base), addrp[0] + (addrp[1] << 8));
2057 outw(PIOP1(base), addrp[2] + (addrp[3] << 8));
2058 outw(PIOP1(base), addrp[4] + (addrp[5] << 8));
2062 ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2063 while (enm != NULL) {
2064 unsigned int lo, hi;
2065 /* break if setting a multicast range, else we would crash */
2066 if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2069 lo = (enm->enm_addrlo[3] << 16) + (enm->enm_addrlo[4] << 8)
2070 + enm->enm_addrlo[5];
2071 hi = (enm->enm_addrhi[3] << 16) + (enm->enm_addrhi[4] << 8)
2072 + enm->enm_addrhi[5];
2074 outw(PIOP1(base),enm->enm_addrlo[0] +
2075 (enm->enm_addrlo[1] << 8));
2076 outw(PIOP1(base),enm->enm_addrlo[2] +
2077 ((lo >> 8) & 0xff00));
2078 outw(PIOP1(base), ((lo >> 8) & 0xff) +
2079 ((lo << 8) & 0xff00));
2080 /* #define MCASTDEBUG */
2082 printf("mcast_addr[%d,%d,%d] %x %x %x %x %x %x\n", lo, hi, cnt,
2088 enm->enm_addrlo[5]);
2093 ETHER_NEXT_MULTI(step, enm);
2096 outw(PIOR1(base), OFFSET_CU + 6); /* mc-cnt */
2097 outw(PIOP1(base), cnt * WAVELAN_ADDR_SIZE);
2098 if(wlcmd(unit, "config()-mcaddress") == 0)
2100 #endif /* MULTICAST */
2102 outw(PIOR1(base), OFFSET_CU);
2103 outw(PIOP1(base), 0); /* ac_status */
2104 outw(PIOP1(base), AC_IASETUP|AC_CW_EL); /* ac_command */
2105 outw(PIOR1(base), OFFSET_CU + 6);
2106 outsw(PIOP1(base), sc->wl_addr, WAVELAN_ADDR_SIZE/2);
2108 if(wlcmd(unit, "config()-address") == 0)
2119 * Set channel attention bit and busy wait until command has
2120 * completed. Then acknowledge the command completion.
2123 wlcmd(int unit, char *str)
2125 struct wl_softc *sc = WLSOFTC(unit);
2126 short base = sc->base;
2129 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
2130 outw(PIOP0(base), SCB_CU_STRT);
2132 SET_CHAN_ATTN(unit);
2134 outw(PIOR0(base), OFFSET_CU);
2135 for(i = 0; i < 0xffff; i++)
2136 if (inw(PIOP0(base)) & AC_SW_C)
2138 if (i == 0xffff || !(inw(PIOP0(base)) & AC_SW_OK)) {
2139 printf("wl%d: %s failed; status = %d, inw = %x, outw = %x\n",
2140 unit, str, inw(PIOP0(base)) & AC_SW_OK, inw(PIOP0(base)), inw(PIOR0(base)));
2141 outw(PIOR0(base), OFFSET_SCB);
2142 printf("scb_status %x\n", inw(PIOP0(base)));
2143 outw(PIOR0(base), OFFSET_SCB+2);
2144 printf("scb_command %x\n", inw(PIOP0(base)));
2145 outw(PIOR0(base), OFFSET_SCB+4);
2146 printf("scb_cbl %x\n", inw(PIOP0(base)));
2147 outw(PIOR0(base), OFFSET_CU+2);
2148 printf("cu_cmd %x\n", inw(PIOP0(base)));
2152 outw(PIOR0(base), OFFSET_SCB);
2153 if ((inw(PIOP0(base)) & SCB_SW_INT) && (inw(PIOP0(base)) != SCB_SW_CNA)) {
2155 printf("wl%d %s: unexpected final state %x\n",
2156 unit, str, inw(PIOP0(base)));
2164 * wlack: if the 82596 wants attention because it has finished
2165 * sending or receiving a packet, acknowledge its desire and
2166 * return bits indicating the kind of attention. wlack() returns
2167 * these bits so that the caller can service exactly the
2168 * conditions that wlack() acknowledged.
2175 struct wl_softc *sc = WLSOFTC(unit);
2176 short base = sc->base;
2178 outw(PIOR1(base), OFFSET_SCB);
2179 if(!(cmd = (inw(PIOP1(base)) & SCB_SW_INT)))
2182 if (sc->wl_if.if_flags & IFF_DEBUG)
2183 printf("wl%d: doing a wlack()\n",unit);
2185 outw(PIOP1(base), cmd);
2186 SET_CHAN_ATTN(unit);
2187 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
2188 for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
2190 printf("wl%d wlack(): board not accepting command.\n", unit);
2197 struct wl_softc *sc = WLSOFTC(unit);
2198 short base = sc->base;
2199 u_short tbd_p = OFFSET_TBD;
2205 outw(PIOR1(base), tbd_p);
2206 insw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
2207 sum += (tbd.act_count & ~TBD_SW_EOF);
2208 printf("%d: addr %x, count %d (%d), next %x, base %x\n",
2209 i++, tbd.buffer_addr,
2210 (tbd.act_count & ~TBD_SW_EOF), sum,
2211 tbd.next_tbd_offset, tbd.buffer_base);
2212 if (tbd.act_count & TBD_SW_EOF)
2214 tbd_p = tbd.next_tbd_offset;
2219 wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2221 struct mbuf *tm_p = *tm_pp;
2222 u_char *mb_p = *mb_pp;
2228 * can we get a run that will be coallesced or
2229 * that terminates before breaking
2232 count += tm_p->m_len;
2233 if (tm_p->m_len & 1)
2235 } while ((tm_p = tm_p->m_next) != (struct mbuf *)0);
2236 if ( (tm_p == (struct mbuf *)0) ||
2237 count > HDW_THRESHOLD) {
2238 *countp = (*tm_pp)->m_len;
2239 *mb_pp = mtod((*tm_pp), u_char *);
2243 /* we need to copy */
2247 cp = (u_char *) t_packet;
2249 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2251 if (count > HDW_THRESHOLD)
2254 if (tm_p->m_next == (struct mbuf *)0)
2256 tm_p = tm_p->m_next;
2259 *mb_pp = (u_char *) t_packet;
2266 wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2268 struct mbuf *tm_p = *tm_pp;
2270 u_char *cp = (u_char *) t_packet;
2273 /* we need to copy */
2275 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2278 if (tm_p->m_next == (struct mbuf *)0)
2280 tm_p = tm_p->m_next;
2284 *mb_pp = (u_char *) t_packet;
2292 struct wl_softc *sc = WLSOFTC(unit);
2293 short base = sc->base;
2296 printf("wl%d: DCE_STATUS: 0x%x, ", unit,
2297 wlmmcread(base,MMC_DCE_STATUS) & 0x0f);
2298 tmp = wlmmcread(base,MMC_CORRECT_NWID_H) << 8;
2299 tmp |= wlmmcread(base,MMC_CORRECT_NWID_L);
2300 printf("Correct NWID's: %d, ", tmp);
2301 tmp = wlmmcread(base,MMC_WRONG_NWID_H) << 8;
2302 tmp |= wlmmcread(base,MMC_WRONG_NWID_L);
2303 printf("Wrong NWID's: %d\n", tmp);
2304 printf("THR_PRE_SET: 0x%x, ", wlmmcread(base,MMC_THR_PRE_SET));
2305 printf("SIGNAL_LVL: %d, SILENCE_LVL: %d\n",
2306 wlmmcread(base,MMC_SIGNAL_LVL),
2307 wlmmcread(base,MMC_SILENCE_LVL));
2308 printf("SIGN_QUAL: 0x%x, NETW_ID: %x:%x, DES: %d\n",
2309 wlmmcread(base,MMC_SIGN_QUAL),
2310 wlmmcread(base,MMC_NETW_ID_H),
2311 wlmmcread(base,MMC_NETW_ID_L),
2312 wlmmcread(base,MMC_DES_AVAIL));
2316 wlmmcread(u_int base, u_short reg)
2318 while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2319 outw(MMCR(base),reg << 1);
2320 while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2321 return (u_short)inw(MMCR(base)) >> 8;
2327 MMC_WRITE(MMC_FREEZE,1);
2329 * SNR retrieval procedure :
2331 * read signal level : wlmmcread(base, MMC_SIGNAL_LVL);
2332 * read silence level : wlmmcread(base, MMC_SILENCE_LVL);
2334 MMC_WRITE(MMC_FREEZE,0);
2336 * SNR is signal:silence ratio.
2343 ** Reads the psa for the wavelan at (base) into (buf)
2346 wlgetpsa(int base, u_char *buf)
2350 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2351 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2353 for (i = 0; i < 0x40; i++) {
2354 outw(PIOR2(base), i);
2355 buf[i] = inb(PIOP2(base));
2357 PCMD(base, HACR_DEFAULT);
2358 PCMD(base, HACR_DEFAULT);
2364 ** Writes the psa for wavelan (unit) from the softc back to the
2365 ** board. Updates the CRC and sets the CRC OK flag.
2367 ** Do not call this when the board is operating, as it doesn't
2368 ** preserve the hacr.
2373 struct wl_softc *sc = WLSOFTC(unit);
2374 short base = sc->base;
2378 crc = wlpsacrc(sc->psa); /* calculate CRC of PSA */
2379 sc->psa[WLPSA_CRCLOW] = crc & 0xff;
2380 sc->psa[WLPSA_CRCHIGH] = (crc >> 8) & 0xff;
2381 sc->psa[WLPSA_CRCOK] = 0x55; /* default to 'bad' until programming complete */
2383 oldpri = splimp(); /* ick, long pause */
2385 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2386 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2388 for (i = 0; i < 0x40; i++) {
2390 outw(PIOR2(base),i); /* write param memory */
2392 outb(PIOP2(base), sc->psa[i]);
2395 outw(PIOR2(base),WLPSA_CRCOK); /* update CRC flag*/
2397 sc->psa[WLPSA_CRCOK] = 0xaa; /* OK now */
2398 outb(PIOP2(base), 0xaa); /* all OK */
2401 PCMD(base, HACR_DEFAULT);
2402 PCMD(base, HACR_DEFAULT);
2408 ** CRC routine provided by Christopher Giordano <cgiordan@gdeb.com>,
2409 ** from original code by Tomi Mikkonen (tomitm@remedy.fi)
2412 static u_int crc16_table[16] = {
2413 0x0000, 0xCC01, 0xD801, 0x1400,
2414 0xF001, 0x3C00, 0x2800, 0xE401,
2415 0xA001, 0x6C00, 0x7800, 0xB401,
2416 0x5000, 0x9C01, 0x8801, 0x4400
2420 wlpsacrc(u_char *buf)
2425 for (i = 0; i < 0x3d; i++, buf++) {
2427 r1 = crc16_table[crc & 0xF];
2428 crc = (crc >> 4) & 0x0FFF;
2429 crc = crc ^ r1 ^ crc16_table[*buf & 0xF];
2432 r1 = crc16_table[crc & 0xF];
2433 crc = (crc >> 4) & 0x0FFF;
2434 crc = crc ^ r1 ^ crc16_table[(*buf >> 4) & 0xF];
2443 * take input packet and cache various radio hw characteristics
2444 * indexed by MAC address.
2446 * Some things to think about:
2447 * note that no space is malloced.
2448 * We might hash the mac address if the cache were bigger.
2449 * It is not clear that the cache is big enough.
2450 * It is also not clear how big it should be.
2451 * The cache is IP-specific. We don't care about that as
2452 * we want it to be IP-specific.
2453 * The last N recv. packets are saved. This will tend
2454 * to reward agents and mobile hosts that beacon.
2455 * That is probably fine for mobile ip.
2458 /* globals for wavelan signal strength cache */
2459 /* this should go into softc structure above.
2462 /* set true if you want to limit cache items to broadcast/mcast
2463 * only packets (not unicast)
2465 static int wl_cache_mcastonly = 1;
2466 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_mcastonly, CTLFLAG_RW,
2467 &wl_cache_mcastonly, 0, "");
2469 /* set true if you want to limit cache items to IP packets only
2471 static int wl_cache_iponly = 1;
2472 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_iponly, CTLFLAG_RW,
2473 &wl_cache_iponly, 0, "");
2475 /* zero out the cache
2478 wl_cache_zero(int unit)
2480 struct wl_softc *sc = WLSOFTC(unit);
2482 bzero(&sc->w_sigcache[0], sizeof(struct w_sigcache) * MAXCACHEITEMS);
2484 sc->w_nextcache = 0;
2485 sc->w_wrapindex = 0;
2488 /* store hw signal info in cache.
2489 * index is MAC address, but an ip src gets stored too
2490 * There are two filters here controllable via sysctl:
2491 * throw out unicast (on by default, but can be turned off)
2492 * throw out non-ip (on by default, but can be turned off)
2495 void wl_cache_store (int unit, int base, struct ether_header *eh,
2498 struct ip *ip = NULL; /* Avoid GCC warning */
2500 int signal, silence;
2501 int w_insertcache; /* computed index for cache entry storage */
2502 struct wl_softc *sc = WLSOFTC(unit);
2503 int ipflag = wl_cache_iponly;
2507 * 2. configurable filter to throw out unicast packets,
2508 * keep multicast only.
2512 /* reject if not IP packet
2514 if ( wl_cache_iponly && (ntohs(eh->ether_type) != 0x800)) {
2518 /* check if broadcast or multicast packet. we toss
2521 if (wl_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
2525 /* find the ip header. we want to store the ip_src
2526 * address. use the mtod macro(in mbuf.h)
2527 * to typecast m to struct ip *
2530 ip = mtod(m, struct ip *);
2533 /* do a linear search for a matching MAC address
2534 * in the cache table
2535 * . MAC address is 6 bytes,
2536 * . var w_nextcache holds total number of entries already cached
2538 for(i = 0; i < sc->w_nextcache; i++) {
2539 if (! bcmp(eh->ether_shost, sc->w_sigcache[i].macsrc, 6 )) {
2541 * so we already have this entry,
2542 * update the data, and LRU age
2548 /* did we find a matching mac address?
2549 * if yes, then overwrite a previously existing cache entry
2551 if (i < sc->w_nextcache ) {
2554 /* else, have a new address entry,so
2555 * add this new entry,
2556 * if table full, then we need to replace entry
2560 /* check for space in cache table
2561 * note: w_nextcache also holds number of entries
2562 * added in the cache table
2564 if ( sc->w_nextcache < MAXCACHEITEMS ) {
2565 w_insertcache = sc->w_nextcache;
2567 sc->w_sigitems = sc->w_nextcache;
2569 /* no space found, so simply wrap with wrap index
2570 * and "zap" the next entry
2573 if (sc->w_wrapindex == MAXCACHEITEMS) {
2574 sc->w_wrapindex = 0;
2576 w_insertcache = sc->w_wrapindex++;
2580 /* invariant: w_insertcache now points at some slot
2583 if (w_insertcache < 0 || w_insertcache >= MAXCACHEITEMS) {
2585 "wl_cache_store, bad index: %d of [0..%d], gross cache error\n",
2586 w_insertcache, MAXCACHEITEMS);
2590 /* store items in cache
2593 * .signal (0..63) ,silence (0..63) ,quality (0..15)
2596 sc->w_sigcache[w_insertcache].ipsrc = ip->ip_src.s_addr;
2598 bcopy( eh->ether_shost, sc->w_sigcache[w_insertcache].macsrc, 6);
2599 signal = sc->w_sigcache[w_insertcache].signal = wlmmcread(base, MMC_SIGNAL_LVL) & 0x3f;
2600 silence = sc->w_sigcache[w_insertcache].silence = wlmmcread(base, MMC_SILENCE_LVL) & 0x3f;
2601 sc->w_sigcache[w_insertcache].quality = wlmmcread(base, MMC_SIGN_QUAL) & 0x0f;
2603 sc->w_sigcache[w_insertcache].snr =
2606 sc->w_sigcache[w_insertcache].snr = 0;
2610 #endif /* WLCACHE */
2613 * determine if in all multicast mode or not
2615 * returns: 1 if IFF_ALLMULTI should be set
2620 #if defined(__FreeBSD__) && __FreeBSD_version < 300000 /* not required */
2622 check_allmulti(int unit)
2624 struct wl_softc *sc = WLSOFTC(unit);
2625 short base = sc->base;
2626 struct ether_multi *enm;
2627 struct ether_multistep step;
2629 ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2630 while (enm != NULL) {
2631 unsigned int lo, hi;
2633 printf("enm_addrlo %x:%x:%x:%x:%x:%x\n", enm->enm_addrlo[0], enm->enm_addrlo[1],
2634 enm->enm_addrlo[2], enm->enm_addrlo[3], enm->enm_addrlo[4],
2635 enm->enm_addrlo[5]);
2636 printf("enm_addrhi %x:%x:%x:%x:%x:%x\n", enm->enm_addrhi[0], enm->enm_addrhi[1],
2637 enm->enm_addrhi[2], enm->enm_addrhi[3], enm->enm_addrhi[4],
2638 enm->enm_addrhi[5]);
2640 if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2643 ETHER_NEXT_MULTI(step, enm);