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.9 2004/03/14 15:36:53 joerg Exp $ */
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain all copyright
8 * notices, this list of conditions and the following disclaimer.
9 * 2. The names of the authors may not be used to endorse or promote products
10 * derived from this software withough specific prior written permission
12 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
13 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
14 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
15 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
16 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
17 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
18 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
19 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
21 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 * if_wl.c - original MACH, then BSDI ISA wavelan driver
26 * ported to mach by Anders Klemets
27 * to BSDI by Robert Morris
28 * to FreeBSD by Jim Binkley
29 * to FreeBSD 2.2+ by Michael Smith
32 * Changed interface to match 2.1-2.2 differences.
33 * Implement IRQ selection logic in wlprobe()
34 * Implement PSA updating.
35 * Pruned heading comments for relevance.
36 * Ripped out all the 'interface counters' cruft.
37 * Cut the missing-interrupt timer back to 100ms.
39 * now supports all multicast mode (mrouted will work),
40 * but unfortunately must do that by going into promiscuous mode
41 * NWID sysctl added so that normally promiscuous mode is NWID-specific
42 * but can be made NWID-inspecific
46 * Ported to FreeBSD, got promiscuous mode working with bpfs,
47 * and rewired timer routine. The i82586 will hang occasionally on output
48 * and the watchdog timer will kick it if so and log an entry.
49 * 2 second timeout there. Apparently the chip loses an interrupt.
50 * Code borrowed from if_ie.c for watchdog timer.
52 * The wavelan card is a 2mbit radio modem that emulates ethernet;
53 * i.e., it uses MAC addresses. This should not be a surprise since
54 * it uses an ethernet controller as a major hw item.
55 * It can broadcast, unicast or apparently multicast in a base cell
56 * using a omni-directional antennae that is
57 * about 800 feet around the base cell barring walls and metal.
58 * With directional antennae, it can be used point to point over a mile
59 * or so apparently (haven't tried that).
61 * There are ISA and pcmcia versions (not supported by this code).
62 * The ISA card has an Intel 82586 lan controller on it. It consists
63 * of 2 pieces of hw, the lan controller (intel) and a radio-modem.
64 * The latter has an extra set of controller registers that has nothing
65 * to do with the i82586 and allows setting and monitoring of radio
66 * signal strength, etc. There is a nvram area called the PSA that
67 * contains a number of setup variables including the IRQ and so-called
68 * NWID or Network ID. The NWID must be set the same for all radio
69 * cards to communicate (unless you are using the ATT/NCR roaming feature
70 * with their access points. There is no support for that here. Roaming
71 * involves a link-layer beacon sent out from the access points. End
72 * stations monitor the signal strength and only use the strongest
73 * access point). This driver assumes that the base ISA port, IRQ,
74 * and NWID are first set in nvram via the dos-side "instconf.exe" utility
75 * supplied with the card. This driver takes the ISA port from
76 * the kernel configuration setup, and then determines the IRQ either
77 * from the kernel config (if an explicit IRQ is set) or from the
78 * PSA on the card if not.
79 * The hw also magically just uses the IRQ set in the nvram.
80 * The NWID is used magically as well by the radio-modem
81 * to determine which packets to keep or throw out.
85 * device wl0 at isa? port 0x300 net irq ?
88 * 1. WLDEBUG. (off) - if turned on enables IFF_DEBUG set via ifconfig debug
89 * 2. MULTICAST (on) - turned on and works up to and including mrouted
90 * 3. WLCACHE (off) - define to turn on a signal strength
91 * (and other metric) cache that is indexed by sender MAC address.
92 * Apps can read this out to learn the remote signal strength of a
93 * sender. Note that it has a switch so that it only stores
94 * broadcast/multicast senders but it could be set to store unicast
95 * too only. Size is hardwired in if_wl_wavelan.h
97 * one further note: promiscuous mode is a curious thing. In this driver,
98 * promiscuous mode apparently CAN catch ALL packets and ignore the NWID
99 * setting. This is probably more useful in a sense (for snoopers) if
100 * you are interested in all traffic as opposed to if you are interested
101 * in just your own. There is a driver specific sysctl to turn promiscuous
102 * from just promiscuous to wildly promiscuous...
104 * This driver also knows how to load the synthesizers in the 2.4 Gz
105 * ISA Half-card, Product number 847647476 (USA/FCC IEEE Channel set).
106 * This product consists of a "mothercard" that contains the 82586,
107 * NVRAM that holds the PSA, and the ISA-buss interface custom ASIC.
108 * The radio transceiver is a "daughtercard" called the WaveMODEM which
109 * connects to the mothercard through two single-inline connectors: a
110 * 20-pin connector provides DC-power and modem signals, and a 3-pin
111 * connector which exports the antenna connection. The code herein
112 * loads the receive and transmit synthesizers and the corresponding
113 * transmitter output power value from an EEPROM controlled through
114 * additional registers via the MMC. The EEPROM address selected
115 * are those whose values are preset by the DOS utility programs
116 * provided with the product, and this provides compatible operation
117 * with the DOS Packet Driver software. A future modification will
118 * add the necessary functionality to this driver and to the wlconfig
119 * utility to completely replace the DOS Configuration Utilities.
120 * The 2.4 Gz WaveMODEM is described in document number 407-024692/E,
121 * and is available through Lucent Technologies OEM supply channels.
128 * Olivetti PC586 Mach Ethernet driver v1.0
129 * Copyright Ing. C. Olivetti & C. S.p.A. 1988, 1989
130 * All rights reserved.
135 Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc.,
136 Cupertino, California.
140 Permission to use, copy, modify, and distribute this software and
141 its documentation for any purpose and without fee is hereby
142 granted, provided that the above copyright notice appears in all
143 copies and that both the copyright notice and this permission notice
144 appear in supporting documentation, and that the name of Olivetti
145 not be used in advertising or publicity pertaining to distribution
146 of the software without specific, written prior permission.
148 OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
149 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
150 IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
151 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
152 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
153 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
154 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
158 Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
162 Permission to use, copy, modify, and distribute this software and
163 its documentation for any purpose and without fee is hereby
164 granted, provided that the above copyright notice appears in all
165 copies and that both the copyright notice and this permission notice
166 appear in supporting documentation, and that the name of Intel
167 not be used in advertising or publicity pertaining to distribution
168 of the software without specific, written prior permission.
170 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
171 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
172 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
173 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
174 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
175 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
176 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
182 * 1. The best book on the 82586 is:
183 * LAN Components User's Manual by Intel
184 * The copy I found was dated 1984. This really tells you
185 * what the state machines are doing
186 * 2. In the current design, we only do one write at a time,
187 * though the hardware is capable of chaining and possibly
188 * even batching. The problem is that we only make one
189 * transmit buffer available in sram space.
193 #include "opt_wavelan.h"
194 #include "opt_inet.h"
196 #include <sys/param.h>
197 #include <sys/systm.h>
198 #include <sys/sockio.h>
199 #include <sys/mbuf.h>
200 #include <sys/socket.h>
201 #include <sys/syslog.h>
202 #include <sys/proc.h>
204 #include <sys/kernel.h>
205 #include <sys/sysctl.h>
207 #include <net/ethernet.h>
209 #include <net/if_dl.h>
212 #include <netinet/in.h>
213 #include <netinet/in_systm.h>
214 #include <netinet/ip.h>
215 #include <netinet/if_ether.h>
220 #include <machine/clock.h>
222 #include <bus/isa/i386/isa_device.h>
223 #include "if_wl_i82586.h" /* Definitions for the Intel chip */
225 /* was 1000 in original, fed to DELAY(x) */
226 #define DELAYCONST 1000
228 #include <machine/if_wl_wavelan.h>
230 static char t_packet[ETHERMTU + sizeof(struct ether_header) + sizeof(long)];
233 struct arpcom wl_ac; /* Ethernet common part */
234 #define wl_if wl_ac.ac_if /* network visible interface */
235 #define wl_addr wl_ac.ac_enaddr /* hardware address */
237 u_char nwid[2]; /* current radio modem nwid */
241 int tbusy; /* flag to determine if xmit is busy */
245 u_short hacr; /* latest host adapter CR command */
247 u_char chan24; /* 2.4 Gz: channel number/EEPROM Area # */
248 u_short freq24; /* 2.4 Gz: resulting frequency */
249 struct callout_handle watchdog_ch;
251 int w_sigitems; /* number of cached entries */
252 /* array of cache entries */
253 struct w_sigcache w_sigcache[ MAXCACHEITEMS ];
254 int w_nextcache; /* next free cache entry */
255 int w_wrapindex; /* next "free" cache entry */
258 static struct wl_softc wl_softc[NWL];
260 #define WLSOFTC(unit) ((struct wl_softc *)(&wl_softc[unit]))
262 static int wlprobe(struct isa_device *);
263 static int wlattach(struct isa_device *);
265 DECLARE_DUMMY_MODULE(if_wl);
267 struct isa_driver wldriver = {
268 wlprobe, wlattach, "wl", 0
272 * XXX The Wavelan appears to be prone to dropping stuff if you talk to
273 * it too fast. This disgusting hack inserts a delay after each packet
274 * is queued which helps avoid this behaviour on fast systems.
276 static int wl_xmit_delay = 250;
277 SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_delay, CTLFLAG_RW, &wl_xmit_delay, 0, "");
280 * not XXX, but ZZZ (bizarre).
281 * promiscuous mode can be toggled to ignore NWIDs. By default,
282 * it does not. Caution should be exercised about combining
283 * this mode with IFF_ALLMULTI which puts this driver in
286 static int wl_ignore_nwid = 0;
287 SYSCTL_INT(_machdep, OID_AUTO, wl_ignore_nwid, CTLFLAG_RW, &wl_ignore_nwid, 0, "");
290 * Emit diagnostics about transmission problems
292 static int xmt_watch = 0;
293 SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_watch, CTLFLAG_RW, &xmt_watch, 0, "");
296 * Collect SNR statistics
298 static int gathersnr = 0;
299 SYSCTL_INT(_machdep, OID_AUTO, wl_gather_snr, CTLFLAG_RW, &gathersnr, 0, "");
301 static void wlstart(struct ifnet *ifp);
302 static void wlinit(void *xsc);
303 static int wlioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
304 static timeout_t wlwatchdog;
305 static ointhand2_t wlintr;
306 static void wlxmt(int unt, struct mbuf *m);
307 static int wldiag(int unt);
308 static int wlconfig(int unit);
309 static int wlcmd(int unit, char *str);
310 static void wlmmcstat(int unit);
311 static u_short wlbldru(int unit);
312 static u_short wlmmcread(u_int base, u_short reg);
313 static void wlinitmmc(int unit);
314 static int wlhwrst(int unit);
315 static void wlrustrt(int unit);
316 static void wlbldcu(int unit);
317 static int wlack(int unit);
318 static int wlread(int unit, u_short fd_p);
319 static void getsnr(int unit);
320 static void wlrcv(int unit);
321 static int wlrequeue(int unit, u_short fd_p);
322 static void wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
323 static void wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
324 static void wltbd(int unit);
325 static void wlgetpsa(int base, u_char *buf);
326 static void wlsetpsa(int unit);
327 static u_short wlpsacrc(u_char *buf);
328 static void wldump(int unit);
330 static void wl_cache_store(int, int, struct ether_header *, struct mbuf *);
331 static void wl_cache_zero(int unit);
334 # if defined(__FreeBSD__) && __FreeBSD_version < 300000
335 static int check_allmulti(int unit);
339 /* array for maping irq numbers to values for the irq parameter register */
340 static int irqvals[16] = {
341 0, 0, 0, 0x01, 0x02, 0x04, 0, 0x08, 0, 0, 0x10, 0x20, 0x40, 0, 0, 0x80
343 /* mask of valid IRQs */
344 #define WL_IRQS (IRQ3|IRQ4|IRQ5|IRQ7|IRQ10|IRQ11|IRQ12|IRQ15)
349 * This function "probes" or checks for the WaveLAN board on the bus to
350 * see if it is there. As far as I can tell, the best break between this
351 * routine and the attach code is to simply determine whether the board
352 * is configured in properly. Currently my approach to this is to write
353 * and read a word from the SRAM on the board being probed. If the word
354 * comes back properly then we assume the board is there. The config
355 * code expects to see a successful return from the probe routine before
356 * attach will be called.
358 * input : address device is mapped to, and unit # being checked
359 * output : a '1' is returned if the board exists, and a 0 otherwise
363 wlprobe(struct isa_device *id)
365 struct wl_softc *sc = &wl_softc[id->id_unit];
366 short base = id->id_iobase;
367 char *str = "wl%d: board out of range [0..%d]\n";
369 unsigned long oldpri;
373 * regular CMD() will not work, since no softc yet
375 #define PCMD(base, hacr) outw((base), (hacr))
378 PCMD(base, HACR_RESET); /* reset the board */
379 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
380 PCMD(base, HACR_RESET); /* reset the board */
381 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
384 /* clear reset command and set PIO#1 in autoincrement mode */
385 PCMD(base, HACR_DEFAULT);
386 PCMD(base, HACR_DEFAULT);
387 outw(PIOR1(base), 0); /* go to beginning of RAM */
388 outsw(PIOP1(base), str, strlen(str)/2+1); /* write string */
390 outw(PIOR1(base), 0); /* rewind */
391 insw(PIOP1(base), inbuf, strlen(str)/2+1); /* read result */
393 if (bcmp(str, inbuf, strlen(str)))
396 sc->chan24 = 0; /* 2.4 Gz: config channel */
397 sc->freq24 = 0; /* 2.4 Gz: frequency */
399 /* read the PSA from the board into temporary storage */
400 wlgetpsa(base, inbuf);
402 /* We read the IRQ value from the PSA on the board. */
403 for (irq = 15; irq >= 0; irq--)
404 if (irqvals[irq] == inbuf[WLPSA_IRQNO])
406 if ((irq == 0) || (irqvals[irq] == 0)){
407 printf("wl%d: PSA corrupt (invalid IRQ value)\n", id->id_unit);
408 id->id_irq = 0; /* no interrupt */
411 * If the IRQ requested by the PSA is already claimed by another
412 * device, the board won't work, but the user can still access the
413 * driver to change the IRQ.
415 id->id_irq = (1<<irq); /* use IRQ from PSA */
424 * This function attaches a WaveLAN board to the "system". The rest of
425 * runtime structures are initialized here (this routine is called after
426 * a successful probe of the board). Once the ethernet address is read
427 * and stored, the board's ifnet structure is attached and readied.
429 * input : isa_dev structure setup in autoconfig
430 * output : board structs and ifnet is setup
434 wlattach(struct isa_device *id)
436 struct wl_softc *sc = (struct wl_softc *) &wl_softc[id->id_unit];
437 short base = id->id_iobase;
439 u_char unit = id->id_unit;
440 struct ifnet *ifp = &sc->wl_if;
443 printf("wlattach: base %x, unit %d\n", base, unit);
445 id->id_ointr = wlintr;
450 sc->hacr = HACR_RESET;
451 callout_handle_init(&sc->watchdog_ch);
452 CMD(unit); /* reset the board */
453 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
455 /* clear reset command and set PIO#2 in parameter access mode */
456 sc->hacr = (HACR_DEFAULT & ~HACR_16BITS);
459 /* Read the PSA from the board for our later reference */
460 wlgetpsa(base, sc->psa);
463 sc->nwid[0] = sc->psa[WLPSA_NWID];
464 sc->nwid[1] = sc->psa[WLPSA_NWID+1];
466 /* fetch MAC address - decide which one first */
467 if (sc->psa[WLPSA_MACSEL] & 1) {
472 for(i=0; i < WAVELAN_ADDR_SIZE; ++i) {
473 sc->wl_addr[i] = sc->psa[j + i];
476 /* enter normal 16 bit mode operation */
477 sc->hacr = HACR_DEFAULT;
481 outw(PIOR1(base), OFFSET_SCB + 8); /* address of scb_crcerrs */
482 outw(PIOP1(base), 0); /* clear scb_crcerrs */
483 outw(PIOP1(base), 0); /* clear scb_alnerrs */
484 outw(PIOP1(base), 0); /* clear scb_rscerrs */
485 outw(PIOP1(base), 0); /* clear scb_ovrnerrs */
487 bzero(ifp, sizeof(ifp));
489 if_initname(ifp, "wl", id->id_unit);
490 ifp->if_mtu = WAVELAN_MTU;
491 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
493 ifp->if_flags |= IFF_DEBUG;
496 ifp->if_flags |= IFF_MULTICAST;
497 #endif /* MULTICAST */
498 ifp->if_init = wlinit;
499 ifp->if_output = ether_output;
500 ifp->if_start = wlstart;
501 ifp->if_ioctl = wlioctl;
502 ifp->if_timer = 0; /* paranoia */
508 ether_ifattach(ifp, sc->wl_ac.ac_enaddr);
510 bcopy(&sc->wl_addr[0], sc->wl_ac.ac_enaddr, WAVELAN_ADDR_SIZE);
511 printf("%s: address %6D, NWID 0x%02x%02x", ifp->if_xname,
512 sc->wl_ac.ac_enaddr, ":", sc->nwid[0], sc->nwid[1]);
514 printf(", Freq %d MHz",sc->freq24); /* 2.4 Gz */
515 printf("\n"); /* 2.4 Gz */
524 * Print out interesting information about the 82596.
529 struct wl_softc *sp = WLSOFTC(unit);
533 printf("hasr %04x\n", inw(HASR(base)));
535 printf("scb at %04x:\n ", OFFSET_SCB);
536 outw(PIOR1(base), OFFSET_SCB);
537 for(i = 0; i < 8; i++)
538 printf("%04x ", inw(PIOP1(base)));
541 printf("cu at %04x:\n ", OFFSET_CU);
542 outw(PIOR1(base), OFFSET_CU);
543 for(i = 0; i < 8; i++)
544 printf("%04x ", inw(PIOP1(base)));
547 printf("tbd at %04x:\n ", OFFSET_TBD);
548 outw(PIOR1(base), OFFSET_TBD);
549 for(i = 0; i < 4; i++)
550 printf("%04x ", inw(PIOP1(base)));
554 /* Initialize the Modem Management Controller */
558 struct wl_softc *sp = WLSOFTC(unit);
564 /* enter 8 bit operation */
565 sp->hacr = (HACR_DEFAULT & ~HACR_16BITS);
568 configured = sp->psa[WLPSA_CONFIGURED] & 1;
571 * Set default modem control parameters. Taken from NCR document
574 MMC_WRITE(MMC_JABBER_ENABLE, 0x01);
575 MMC_WRITE(MMC_ANTEN_SEL, 0x02);
576 MMC_WRITE(MMC_IFS, 0x20);
577 MMC_WRITE(MMC_MOD_DELAY, 0x04);
578 MMC_WRITE(MMC_JAM_TIME, 0x38);
579 MMC_WRITE(MMC_DECAY_PRM, 0x00); /* obsolete ? */
580 MMC_WRITE(MMC_DECAY_UPDAT_PRM, 0x00);
582 MMC_WRITE(MMC_LOOPT_SEL, 0x00);
583 if (sp->psa[WLPSA_COMPATNO] & 1) {
584 MMC_WRITE(MMC_THR_PRE_SET, 0x01); /* 0x04 for AT and 0x01 for MCA */
586 MMC_WRITE(MMC_THR_PRE_SET, 0x04); /* 0x04 for AT and 0x01 for MCA */
588 MMC_WRITE(MMC_QUALITY_THR, 0x03);
590 /* use configuration defaults from parameter storage area */
591 if (sp->psa[WLPSA_NWIDENABLE] & 1) {
592 if ((mode & (MOD_PROM | MOD_ENAL)) && wl_ignore_nwid) {
593 MMC_WRITE(MMC_LOOPT_SEL, 0x40);
595 MMC_WRITE(MMC_LOOPT_SEL, 0x00);
598 MMC_WRITE(MMC_LOOPT_SEL, 0x40); /* disable network id check */
600 MMC_WRITE(MMC_THR_PRE_SET, sp->psa[WLPSA_THRESH]);
601 MMC_WRITE(MMC_QUALITY_THR, sp->psa[WLPSA_QUALTHRESH]);
603 MMC_WRITE(MMC_FREEZE, 0x00);
604 MMC_WRITE(MMC_ENCR_ENABLE, 0x00);
606 MMC_WRITE(MMC_NETW_ID_L,sp->nwid[1]); /* set NWID */
607 MMC_WRITE(MMC_NETW_ID_H,sp->nwid[0]);
609 /* enter normal 16 bit mode operation */
610 sp->hacr = HACR_DEFAULT;
612 CMD(unit); /* virtualpc1 needs this! */
614 if (sp->psa[WLPSA_COMPATNO]== /* 2.4 Gz: half-card ver */
615 WLPSA_COMPATNO_WL24B) { /* 2.4 Gz */
616 i=sp->chan24<<4; /* 2.4 Gz: position ch # */
617 MMC_WRITE(MMC_EEADDR,i+0x0f); /* 2.4 Gz: named ch, wc=16 */
618 MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+ /* 2.4 Gz: Download Synths */
619 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: Read EEPROM */
620 for (i=0; i<1000; ++i) { /* 2.4 Gz: wait for download */
621 DELAY(40); /* 2.4 Gz */
622 if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and */
623 &(MMC_EECTRLstat_DWLD /* 2.4 Gz: EEBUSY */
624 +MMC_EECTRLstat_EEBUSY))==0) /* 2.4 Gz: */
625 break; /* 2.4 Gz: download finished */
627 if (i==1000) printf("wl: synth load failed\n"); /* 2.4 Gz */
628 MMC_WRITE(MMC_EEADDR,0x61); /* 2.4 Gz: default pwr, wc=2 */
629 MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+ /* 2.4 Gz: Download Xmit Pwr */
630 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: Read EEPROM */
631 for (i=0; i<1000; ++i) { /* 2.4 Gz: wait for download */
632 DELAY(40); /* 2.4 Gz */
633 if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and */
634 &(MMC_EECTRLstat_DWLD /* 2.4 Gz: EEBUSY */
635 +MMC_EECTRLstat_EEBUSY))==0) /* 2.4 Gz: */
636 break; /* 2.4 Gz: download finished */
638 if (i==1000) printf("wl: xmit pwr load failed\n"); /* 2.4 Gz */
639 MMC_WRITE(MMC_ANALCTRL, /* 2.4 Gz: EXT ant+polarity */
640 MMC_ANALCTRL_ANTPOL + /* 2.4 Gz: */
641 MMC_ANALCTRL_EXTANT); /* 2.4 Gz: */
642 i=sp->chan24<<4; /* 2.4 Gz: position ch # */
643 MMC_WRITE(MMC_EEADDR,i); /* 2.4 Gz: get frequency */
644 MMC_WRITE(MMC_EECTRL, /* 2.4 Gz: EEPROM read */
645 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: */
646 DELAY(40); /* 2.4 Gz */
647 i = wlmmcread(base,MMC_EEDATALrv) /* 2.4 Gz: freq val */
648 + (wlmmcread(base,MMC_EEDATAHrv)<<8); /* 2.4 Gz */
649 sp->freq24 = (i>>6)+2400; /* 2.4 Gz: save real freq */
656 * Another routine that interfaces the "if" layer to this driver.
657 * Simply resets the structures that are used by "upper layers".
658 * As well as calling wlhwrst that does reset the WaveLAN board.
660 * input : softc pointer for this interface
661 * output : structures (if structs) and board are reset
667 struct wl_softc *sc = xsc;
668 struct ifnet *ifp = &sc->wl_if;
673 if (sc->wl_if.if_flags & IFF_DEBUG)
674 printf("wl%d: entered wlinit()\n",sc->unit);
676 #if defined(__DragonFly__) || (defined(__FreeBSD__) && __FreeBSD_version >= 300000)
677 if (ifp->if_addrhead.tqh_first == (struct ifaddr *)0) {
679 if (ifp->if_addrlist == (struct ifaddr *)0) {
684 if ((stat = wlhwrst(sc->unit)) == TRUE) {
685 sc->wl_if.if_flags |= IFF_RUNNING; /* same as DSF_RUNNING */
687 * OACTIVE is used by upper-level routines
690 sc->wl_if.if_flags &= ~IFF_OACTIVE; /* same as tbusy below */
692 sc->flags |= DSF_RUNNING;
694 untimeout(wlwatchdog, sc, sc->watchdog_ch);
698 printf("wl%d init(): trouble resetting board.\n", sc->unit);
706 * This routine resets the WaveLAN board that corresponds to the
707 * board number passed in.
709 * input : board number to do a hardware reset
710 * output : board is reset
716 struct wl_softc *sc = WLSOFTC(unit);
719 if (sc->wl_if.if_flags & IFF_DEBUG)
720 printf("wl%d: entered wlhwrst()\n",unit);
722 sc->hacr = HACR_RESET;
723 CMD(unit); /* reset the board */
725 /* clear reset command and set PIO#1 in autoincrement mode */
726 sc->hacr = HACR_DEFAULT;
730 if (sc->wl_if.if_flags & IFF_DEBUG)
731 wlmmcstat(unit); /* Display MMC registers */
733 wlbldcu(unit); /* set up command unit structures */
735 if (wldiag(unit) == 0)
738 if (wlconfig(unit) == 0)
741 * insert code for loopback test here
743 wlrustrt(unit); /* start receive unit */
745 /* enable interrupts */
746 sc->hacr = (HACR_DEFAULT | HACR_INTRON);
755 * This function builds up the command unit structures. It inits
756 * the scp, iscp, scb, cb, tbd, and tbuf.
762 struct wl_softc *sc = WLSOFTC(unit);
763 short base = sc->base;
771 bzero(&scp, sizeof(scp));
773 scp.scp_iscp = OFFSET_ISCP;
774 scp.scp_iscp_base = 0;
775 outw(PIOR1(base), OFFSET_SCP);
776 outsw(PIOP1(base), &scp, sizeof(scp_t)/2);
778 bzero(&iscp, sizeof(iscp));
780 iscp.iscp_scb_offset = OFFSET_SCB;
782 iscp.iscp_scb_base = 0;
783 outw(PIOR1(base), OFFSET_ISCP);
784 outsw(PIOP1(base), &iscp, sizeof(iscp_t)/2);
787 scb.scb_command = SCB_RESET;
788 scb.scb_cbl_offset = OFFSET_CU;
789 scb.scb_rfa_offset = OFFSET_RU;
793 scb.scb_ovrnerrs = 0;
794 outw(PIOR1(base), OFFSET_SCB);
795 outsw(PIOP1(base), &scb, sizeof(scb_t)/2);
799 outw(PIOR0(base), OFFSET_ISCP + 0); /* address of iscp_busy */
800 for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
801 if (i <= 0) printf("wl%d bldcu(): iscp_busy timeout.\n", unit);
802 outw(PIOR0(base), OFFSET_SCB + 0); /* address of scb_status */
803 for (i = STATUS_TRIES; i-- > 0; ) {
804 if (inw(PIOP0(base)) == (SCB_SW_CX|SCB_SW_CNA))
808 printf("wl%d bldcu(): not ready after reset.\n", unit);
812 cb.ac_command = AC_CW_EL; /* NOP */
813 cb.ac_link_offset = OFFSET_CU;
814 outw(PIOR1(base), OFFSET_CU);
815 outsw(PIOP1(base), &cb, 6/2);
818 tbd.next_tbd_offset = I82586NULL;
821 outw(PIOR1(base), OFFSET_TBD);
822 outsw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
830 * input : board number
831 * output : stuff sent to board if any there
835 wlstart(struct ifnet *ifp)
837 int unit = ifp->if_dunit;
839 struct wl_softc *sc = WLSOFTC(unit);
840 short base = sc->base;
841 int scb_status, cu_status, scb_command;
844 if (sc->wl_if.if_flags & IFF_DEBUG)
845 printf("wl%d: entered wlstart()\n",unit);
848 outw(PIOR1(base), OFFSET_CU);
849 cu_status = inw(PIOP1(base));
850 outw(PIOR0(base),OFFSET_SCB + 0); /* scb_status */
851 scb_status = inw(PIOP0(base));
852 outw(PIOR0(base), OFFSET_SCB + 2);
853 scb_command = inw(PIOP0(base));
856 * don't need OACTIVE check as tbusy here checks to see
857 * if we are already busy
860 if((scb_status & 0x0700) == SCB_CUS_IDLE &&
861 (cu_status & AC_SW_B) == 0){
863 untimeout(wlwatchdog, sc, sc->watchdog_ch);
864 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
866 * This is probably just a race. The xmt'r is just
867 * became idle but WE have masked interrupts so ...
870 printf("wl%d: CU idle, scb %04x %04x cu %04x\n",
871 unit, scb_status, scb_command, cu_status);
873 if (xmt_watch) printf("!!");
875 return; /* genuinely still busy */
877 } else if((scb_status & 0x0700) == SCB_CUS_ACTV ||
878 (cu_status & AC_SW_B)){
880 printf("wl%d: CU unexpectedly busy; scb %04x cu %04x\n",
881 unit, scb_status, cu_status);
883 if (xmt_watch) printf("wl%d: busy?!",unit);
884 return; /* hey, why are we busy? */
887 /* get ourselves some data */
889 IF_DEQUEUE(&ifp->if_snd, m);
890 if (m != (struct mbuf *)0) {
891 /* let BPF see it before we commit it */
896 /* set the watchdog timer so that if the board
897 * fails to interrupt we will restart
899 /* try 10 ticks, not very long */
900 sc->watchdog_ch = timeout(wlwatchdog, sc, 10);
901 sc->wl_ac.ac_if.if_flags |= IFF_OACTIVE;
902 sc->wl_if.if_opackets++;
905 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
913 * This routine does the actual copy of data (including ethernet header
914 * structure) from the WaveLAN to an mbuf chain that will be passed up
915 * to the "if" (network interface) layer. NOTE: we currently
916 * don't handle trailer protocols, so if that is needed, it will
917 * (at least in part) be added here. For simplicities sake, this
918 * routine copies the receive buffers from the board into a local (stack)
919 * buffer until the frame has been copied from the board. Once in
920 * the local buffer, the contents are copied to an mbuf chain that
921 * is then enqueued onto the appropriate "if" queue.
923 * input : board number, and an frame descriptor address
924 * output : the packet is put into an mbuf chain, and passed up
925 * assumes : if any errors occur, packet is "dropped on the floor"
929 wlread(int unit, u_short fd_p)
931 struct wl_softc *sc = WLSOFTC(unit);
932 struct ifnet *ifp = &sc->wl_if;
933 short base = sc->base;
935 struct ether_header eh;
939 u_short mlen, len, clen;
940 u_short bytes_in_msg, bytes_in_mbuf, bytes;
944 if (sc->wl_if.if_flags & IFF_DEBUG)
945 printf("wl%d: entered wlread()\n",unit);
947 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
948 printf("%s read(): board is not running.\n", ifp->if_xname);
949 sc->hacr &= ~HACR_INTRON;
950 CMD(unit); /* turn off interrupts */
952 /* read ether_header info out of device memory. doesn't
953 * go into mbuf. goes directly into eh structure
955 len = sizeof(struct ether_header); /* 14 bytes */
956 outw(PIOR1(base), fd_p);
957 insw(PIOP1(base), &fd, (sizeof(fd_t) - len)/2);
958 insw(PIOP1(base), &eh, (len-2)/2);
959 eh.ether_type = ntohs(inw(PIOP1(base)));
961 if (sc->wl_if.if_flags & IFF_DEBUG) {
962 printf("wlread: rcv packet, type is %x\n", eh.ether_type);
966 * WARNING. above is done now in ether_input, above may be
967 * useful for debug. jrb
969 eh.ether_type = htons(eh.ether_type);
971 if (fd.rbd_offset == I82586NULL) {
972 printf("wl%d read(): Invalid buffer\n", unit);
973 if (wlhwrst(unit) != TRUE) {
974 printf("wl%d read(): hwrst trouble.\n", unit);
979 outw(PIOR1(base), fd.rbd_offset);
980 insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
981 bytes_in_msg = rbd.status & RBD_SW_COUNT;
982 MGETHDR(m, M_DONTWAIT, MT_DATA);
984 if (m == (struct mbuf *)0) {
986 * not only do we want to return, we need to drop the packet on
987 * the floor to clear the interrupt.
990 if (wlhwrst(unit) != TRUE) {
991 sc->hacr &= ~HACR_INTRON;
992 CMD(unit); /* turn off interrupts */
993 printf("wl%d read(): hwrst trouble.\n", unit);
997 m->m_next = (struct mbuf *) 0;
998 m->m_pkthdr.rcvif = ifp;
999 m->m_pkthdr.len = 0; /* don't know this yet */
1002 /* always use a cluster. jrb
1004 MCLGET(m, M_DONTWAIT);
1005 if (m->m_flags & M_EXT) {
1006 m->m_len = MCLBYTES;
1010 if (wlhwrst(unit) != TRUE) {
1011 sc->hacr &= ~HACR_INTRON;
1012 CMD(unit); /* turn off interrupts */
1013 printf("wl%d read(): hwrst trouble.\n", unit);
1020 bytes_in_mbuf = m->m_len;
1021 mb_p = mtod(tm, u_char *);
1022 bytes = min(bytes_in_mbuf, bytes_in_msg);
1029 outw(PIOR1(base), rbd.buffer_addr);
1030 insw(PIOP1(base), mb_p, len/2);
1034 if (!(bytes_in_mbuf -= bytes)) {
1035 MGET(tm->m_next, M_DONTWAIT, MT_DATA);
1037 if (tm == (struct mbuf *)0) {
1039 printf("wl%d read(): No mbuf nth\n", unit);
1040 if (wlhwrst(unit) != TRUE) {
1041 sc->hacr &= ~HACR_INTRON;
1042 CMD(unit); /* turn off interrupts */
1043 printf("wl%d read(): hwrst trouble.\n", unit);
1049 bytes_in_mbuf = MLEN;
1050 mb_p = mtod(tm, u_char *);
1055 if (!(bytes_in_msg -= bytes)) {
1056 if (rbd.status & RBD_SW_EOF ||
1057 rbd.next_rbd_offset == I82586NULL) {
1061 outw(PIOR1(base), rbd.next_rbd_offset);
1062 insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1063 bytes_in_msg = rbd.status & RBD_SW_COUNT;
1066 rbd.buffer_addr += bytes;
1069 bytes = min(bytes_in_mbuf, bytes_in_msg);
1072 m->m_pkthdr.len = clen;
1075 * If hw is in promiscuous mode (note that I said hardware, not if
1076 * IFF_PROMISC is set in ifnet flags), then if this is a unicast
1077 * packet and the MAC dst is not us, drop it. This check in normally
1078 * inside ether_input(), but IFF_MULTI causes hw promisc without
1079 * a bpf listener, so this is wrong.
1080 * Greg Troxel <gdt@ir.bbn.com>, 1998-08-07
1083 * TBD: also discard packets where NWID does not match.
1084 * However, there does not appear to be a way to read the nwid
1085 * for a received packet. -gdt 1998-08-07
1088 #ifdef WL_USE_IFNET_PROMISC_CHECK /* not defined */
1089 (sc->wl_ac.ac_if.if_flags & (IFF_PROMISC|IFF_ALLMULTI))
1091 /* hw is in promisc mode if this is true */
1092 (sc->mode & (MOD_PROM | MOD_ENAL))
1095 (eh.ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
1096 bcmp(eh.ether_dhost, sc->wl_ac.ac_enaddr,
1097 sizeof(eh.ether_dhost)) != 0 ) {
1103 if (sc->wl_if.if_flags & IFF_DEBUG)
1104 printf("wl%d: wlrecv %d bytes\n", unit, clen);
1108 wl_cache_store(unit, base, &eh, m);
1112 * received packet is now in a chain of mbuf's. next step is
1113 * to pass the packet upwards.
1116 ether_input(&sc->wl_if, &eh, m);
1123 * This routine processes an ioctl request from the "if" layer
1126 * input : pointer the appropriate "if" struct, command, and data
1127 * output : based on command appropriate action is taken on the
1128 * WaveLAN board(s) or related structures
1129 * return : error is returned containing exit conditions
1133 wlioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1135 struct ifreq *ifr = (struct ifreq *)data;
1136 int unit = ifp->if_dunit;
1137 struct wl_softc *sc = WLSOFTC(unit);
1138 short base = sc->base;
1140 int opri, error = 0;
1141 int irq, irqval, i, isroot, size;
1144 struct thread *td = curthread; /* XXX */
1148 if (sc->wl_if.if_flags & IFF_DEBUG)
1149 printf("wl%d: entered wlioctl()\n",unit);
1156 error = ether_ioctl(ifp, cmd, data);
1160 if (ifp->if_flags & IFF_ALLMULTI) {
1163 if (ifp->if_flags & IFF_PROMISC) {
1166 if(ifp->if_flags & IFF_LINK0) {
1170 * force a complete reset if the recieve multicast/
1171 * promiscuous mode changes so that these take
1172 * effect immediately.
1175 if (sc->mode != mode) {
1177 if (sc->flags & DSF_RUNNING) {
1178 sc->flags &= ~DSF_RUNNING;
1182 /* if interface is marked DOWN and still running then
1185 if ((ifp->if_flags & IFF_UP) == 0 && sc->flags & DSF_RUNNING) {
1186 printf("wl%d ioctl(): board is not running\n", unit);
1187 sc->flags &= ~DSF_RUNNING;
1188 sc->hacr &= ~HACR_INTRON;
1189 CMD(unit); /* turn off interrupts */
1191 /* else if interface is UP and RUNNING, start it
1193 else if (ifp->if_flags & IFF_UP && (sc->flags & DSF_RUNNING) == 0) {
1197 /* if WLDEBUG set on interface, then printf rf-modem regs
1199 if(ifp->if_flags & IFF_DEBUG)
1206 #if defined(__FreeBSD__) && __FreeBSD_version < 300000
1207 if (cmd == SIOCADDMULTI) {
1208 error = ether_addmulti(ifr, &sc->wl_ac);
1211 error = ether_delmulti(ifr, &sc->wl_ac);
1214 /* see if we should be in all multicast mode
1215 * note that 82586 cannot do that, must simulate with
1218 if ( check_allmulti(unit)) {
1219 ifp->if_flags |= IFF_ALLMULTI;
1220 sc->mode |= MOD_ENAL;
1221 sc->flags &= ~DSF_RUNNING;
1227 if (error == ENETRESET) {
1228 if(sc->flags & DSF_RUNNING) {
1229 sc->flags &= ~DSF_RUNNING;
1238 #endif /* MULTICAST */
1240 /* DEVICE SPECIFIC */
1243 /* copy the PSA out to the caller */
1245 /* pointer to buffer in user space */
1246 up = (void *)ifr->ifr_data;
1247 /* work out if they're root */
1248 isroot = (suser(td) == 0);
1250 for (i = 0; i < 0x40; i++) {
1251 /* don't hand the DES key out to non-root users */
1252 if ((i > WLPSA_DESKEY) && (i < (WLPSA_DESKEY + 8)) && !isroot)
1254 if (subyte((up + i), sc->psa[i]))
1260 /* copy the PSA in from the caller; we only copy _some_ values */
1263 if ((error = suser(td)))
1265 error = EINVAL; /* assume the worst */
1266 /* pointer to buffer in user space containing data */
1267 up = (void *)ifr->ifr_data;
1269 /* check validity of input range */
1270 for (i = 0; i < 0x40; i++)
1271 if (fubyte(up + i) < 0)
1274 /* check IRQ value */
1275 irqval = fubyte(up+WLPSA_IRQNO);
1276 for (irq = 15; irq >= 0; irq--)
1277 if(irqvals[irq] == irqval)
1279 if (irq == 0) /* oops */
1282 sc->psa[WLPSA_IRQNO] = irqval;
1285 for (i = 0; i < 6; i++)
1286 sc->psa[WLPSA_LOCALMAC+i] = fubyte(up+WLPSA_LOCALMAC+i);
1289 sc->psa[WLPSA_MACSEL] = fubyte(up+WLPSA_MACSEL);
1292 sc->psa[WLPSA_NWID] = fubyte(up+WLPSA_NWID);
1293 sc->psa[WLPSA_NWID+1] = fubyte(up+WLPSA_NWID+1);
1296 wlsetpsa(unit); /* update the PSA */
1300 /* get the current NWID out of the sc since we stored it there */
1302 ifr->ifr_data = (caddr_t) (sc->nwid[0] << 8 | sc->nwid[1]);
1307 * change the nwid dynamically. This
1308 * ONLY changes the radio modem and does not
1312 * 1. save in softc "soft registers"
1313 * 2. save in radio modem (MMC)
1317 if ((error = suser(td)))
1319 if (!(ifp->if_flags & IFF_UP)) {
1320 error = EIO; /* only allowed while up */
1323 * soft c nwid shadows radio modem setting
1325 sc->nwid[0] = (int)ifr->ifr_data >> 8;
1326 sc->nwid[1] = (int)ifr->ifr_data & 0xff;
1327 MMC_WRITE(MMC_NETW_ID_L,sc->nwid[1]);
1328 MMC_WRITE(MMC_NETW_ID_H,sc->nwid[0]);
1332 /* copy the EEPROM in 2.4 Gz WaveMODEM out to the caller */
1335 if ((error = suser(td)))
1337 /* pointer to buffer in user space */
1338 up = (void *)ifr->ifr_data;
1340 for (i=0x00; i<0x80; ++i) { /* 2.4 Gz: size of EEPROM */
1341 MMC_WRITE(MMC_EEADDR,i); /* 2.4 Gz: get frequency */
1342 MMC_WRITE(MMC_EECTRL, /* 2.4 Gz: EEPROM read */
1343 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: */
1344 DELAY(40); /* 2.4 Gz */
1345 if (subyte(up + 2*i , /* 2.4 Gz: pass low byte of */
1346 wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word */
1347 ) return(EFAULT); /* 2.4 Gz: */
1348 if (subyte(up + 2*i+1, /* 2.4 Gz: pass hi byte of */
1349 wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word */
1350 ) return(EFAULT); /* 2.4 Gz: */
1355 /* zero (Delete) the wl cache */
1358 if ((error = suser(td)))
1360 wl_cache_zero(unit);
1363 /* read out the number of used cache elements */
1365 ifr->ifr_data = (caddr_t) sc->w_sigitems;
1368 /* read out the wl cache */
1370 /* pointer to buffer in user space */
1371 up = (void *)ifr->ifr_data;
1372 cpt = (char *) &sc->w_sigcache[0];
1373 size = sc->w_sigitems * sizeof(struct w_sigcache);
1375 for (i = 0; i < size; i++) {
1376 if (subyte((up + i), *cpt++))
1392 * Called if the timer set in wlstart expires before an interrupt is received
1393 * from the wavelan. It seems to lose interrupts sometimes.
1394 * The watchdog routine gets called if the transmitter failed to interrupt
1396 * input : which board is timing out
1397 * output : board reset
1401 wlwatchdog(void *vsc)
1403 struct wl_softc *sc = vsc;
1404 int unit = sc->unit;
1406 log(LOG_ERR, "wl%d: wavelan device timeout on xmit\n", unit);
1407 sc->wl_ac.ac_if.if_oerrors++;
1414 * This function is the interrupt handler for the WaveLAN
1415 * board. This routine will be called whenever either a packet
1416 * is received, or a packet has successfully been transfered and
1417 * the unit is ready to transmit another packet.
1419 * input : board number that interrupted
1420 * output : either a packet is received, or a packet is transfered
1427 struct wl_softc *sc = &wl_softc[unit];
1428 short base = sc->base;
1430 u_short int_type, int_type1;
1433 if (sc->wl_if.if_flags & IFF_DEBUG)
1434 printf("wl%d: wlintr() called\n",unit);
1437 if((int_type = inw(HASR(base))) & HASR_MMC_INTR) {
1438 /* handle interrupt from the modem management controler */
1439 /* This will clear the interrupt condition */
1440 (void) wlmmcread(base,MMC_DCE_STATUS); /* ignored for now */
1443 if(!(int_type & HASR_INTR)){ /* return if no interrupt from 82586 */
1444 /* commented out. jrb. it happens when reinit occurs
1445 printf("wlintr: int_type %x, dump follows\n", int_type);
1454 outw(PIOR0(base), OFFSET_SCB + 0); /* get scb status */
1455 int_type = (inw(PIOP0(base)) & SCB_SW_INT);
1456 if (int_type == 0) /* no interrupts left */
1459 int_type1 = wlack(unit); /* acknowledge interrupt(s) */
1460 /* make sure no bits disappeared (others may appear) */
1461 if ((int_type & int_type1) != int_type)
1462 printf("wlack() int bits disappeared : %04x != int_type %04x\n",
1463 int_type1, int_type);
1464 int_type = int_type1; /* go with the new status */
1468 if (int_type & SCB_SW_FR) {
1469 sc->wl_if.if_ipackets++;
1473 * receiver not ready
1475 if (int_type & SCB_SW_RNR) {
1476 sc->wl_if.if_ierrors++;
1478 if (sc->wl_if.if_flags & IFF_DEBUG)
1479 printf("wl%d intr(): receiver overrun! begin_fd = %x\n",
1480 unit, sc->begin_fd);
1487 if (int_type & SCB_SW_CNA) {
1489 * At present, we don't care about CNA's. We
1490 * believe they are a side effect of XMT.
1493 if (int_type & SCB_SW_CX) {
1495 * At present, we only request Interrupt for
1498 outw(PIOR1(base), OFFSET_CU); /* get command status */
1499 ac_status = inw(PIOP1(base));
1501 if (xmt_watch) { /* report some anomalies */
1503 if (sc->tbusy == 0) {
1504 printf("wl%d: xmt intr but not busy, CU %04x\n",
1507 if (ac_status == 0) {
1508 printf("wl%d: xmt intr but ac_status == 0\n", unit);
1510 if (ac_status & AC_SW_A) {
1511 printf("wl%d: xmt aborted\n",unit);
1514 if (ac_status & TC_CARRIER) {
1515 printf("wl%d: no carrier\n", unit);
1518 if (ac_status & TC_CLS) {
1519 printf("wl%d: no CTS\n", unit);
1521 if (ac_status & TC_DMA) {
1522 printf("wl%d: DMA underrun\n", unit);
1524 if (ac_status & TC_DEFER) {
1525 printf("wl%d: xmt deferred\n",unit);
1527 if (ac_status & TC_SQE) {
1528 printf("wl%d: heart beat\n", unit);
1530 if (ac_status & TC_COLLISION) {
1531 printf("wl%d: too many collisions\n", unit);
1534 /* if the transmit actually failed, or returned some status */
1535 if ((!(ac_status & AC_SW_OK)) || (ac_status & 0xfff)) {
1536 if (ac_status & (TC_COLLISION | TC_CLS | TC_DMA)) {
1537 sc->wl_if.if_oerrors++;
1539 /* count collisions */
1540 sc->wl_if.if_collisions += (ac_status & 0xf);
1541 /* if TC_COLLISION set and collision count zero, 16 collisions */
1542 if ((ac_status & 0x20) == 0x20) {
1543 sc->wl_if.if_collisions += 0x10;
1547 untimeout(wlwatchdog, sc, sc->watchdog_ch);
1548 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
1549 wlstart(&(sc->wl_if));
1558 * This routine is called by the interrupt handler to initiate a
1559 * packet transfer from the board to the "if" layer above this
1560 * driver. This routine checks if a buffer has been successfully
1561 * received by the WaveLAN. If so, the routine wlread is called
1562 * to do the actual transfer of the board data (including the
1563 * ethernet header) into a packet (consisting of an mbuf chain).
1565 * input : number of the board to check
1566 * output : if a packet is available, it is "sent up"
1572 struct wl_softc *sc = WLSOFTC(unit);
1573 short base = sc->base;
1574 u_short fd_p, status, offset, link_offset;
1577 if (sc->wl_if.if_flags & IFF_DEBUG)
1578 printf("wl%d: entered wlrcv()\n",unit);
1580 for (fd_p = sc->begin_fd; fd_p != I82586NULL; fd_p = sc->begin_fd) {
1582 outw(PIOR0(base), fd_p + 0); /* address of status */
1583 status = inw(PIOP0(base));
1584 outw(PIOR1(base), fd_p + 4); /* address of link_offset */
1585 link_offset = inw(PIOP1(base));
1586 offset = inw(PIOP1(base)); /* rbd_offset */
1587 if (status == 0xffff || offset == 0xffff /*I82586NULL*/) {
1588 if (wlhwrst(unit) != TRUE)
1589 printf("wl%d rcv(): hwrst ffff trouble.\n", unit);
1591 } else if (status & AC_SW_C) {
1592 if (status == (RFD_DONE|RFD_RSC)) {
1595 if (sc->wl_if.if_flags & IFF_DEBUG)
1596 printf("wl%d RCV: RSC %x\n", unit, status);
1598 sc->wl_if.if_ierrors++;
1599 } else if (!(status & RFD_OK)) {
1600 printf("wl%d RCV: !OK %x\n", unit, status);
1601 sc->wl_if.if_ierrors++;
1602 } else if (status & 0xfff) { /* can't happen */
1603 printf("wl%d RCV: ERRs %x\n", unit, status);
1604 sc->wl_if.if_ierrors++;
1605 } else if (!wlread(unit, fd_p))
1608 if (!wlrequeue(unit, fd_p)) {
1609 /* abort on chain error */
1610 if (wlhwrst(unit) != TRUE)
1611 printf("wl%d rcv(): hwrst trouble.\n", unit);
1614 sc->begin_fd = link_offset;
1625 * This routine puts rbd's used in the last receive back onto the
1626 * free list for the next receive.
1630 wlrequeue(int unit, u_short fd_p)
1632 struct wl_softc *sc = WLSOFTC(unit);
1633 short base = sc->base;
1635 u_short l_rbdp, f_rbdp, rbd_offset;
1637 outw(PIOR0(base), fd_p + 6);
1638 rbd_offset = inw(PIOP0(base));
1639 if ((f_rbdp = rbd_offset) != I82586NULL) {
1642 outw(PIOR0(base), l_rbdp + 0); /* address of status */
1643 if(inw(PIOP0(base)) & RBD_SW_EOF)
1645 outw(PIOP0(base), 0);
1646 outw(PIOR0(base), l_rbdp + 2); /* next_rbd_offset */
1647 if((l_rbdp = inw(PIOP0(base))) == I82586NULL)
1650 outw(PIOP0(base), 0);
1651 outw(PIOR0(base), l_rbdp + 2); /* next_rbd_offset */
1652 outw(PIOP0(base), I82586NULL);
1653 outw(PIOR0(base), l_rbdp + 8); /* address of size */
1654 outw(PIOP0(base), inw(PIOP0(base)) | AC_CW_EL);
1655 outw(PIOR0(base), sc->end_rbd + 2);
1656 outw(PIOP0(base), f_rbdp); /* end_rbd->next_rbd_offset */
1657 outw(PIOR0(base), sc->end_rbd + 8); /* size */
1658 outw(PIOP0(base), inw(PIOP0(base)) & ~AC_CW_EL);
1659 sc->end_rbd = l_rbdp;
1663 fd.command = AC_CW_EL;
1664 fd.link_offset = I82586NULL;
1665 fd.rbd_offset = I82586NULL;
1666 outw(PIOR1(base), fd_p);
1667 outsw(PIOP1(base), &fd, 8/2);
1669 outw(PIOR1(base), sc->end_fd + 2); /* addr of command */
1670 outw(PIOP1(base), 0); /* command = 0 */
1671 outw(PIOP1(base), fd_p); /* end_fd->link_offset = fd_p */
1678 static int xmt_debug = 0;
1679 #endif /* WLDEBUG */
1684 * This routine fills in the appropriate registers and memory
1685 * locations on the WaveLAN board and starts the board off on
1688 * input : board number of interest, and a pointer to the mbuf
1689 * output : board memory and registers are set for xfer and attention
1693 wlxmt(int unit, struct mbuf *m)
1695 struct wl_softc *sc = WLSOFTC(unit);
1696 u_short xmtdata_p = OFFSET_TBUF;
1698 struct mbuf *tm_p = m;
1699 struct ether_header *eh_p = mtod(m, struct ether_header *);
1700 u_char *mb_p = mtod(m, u_char *) + sizeof(struct ether_header);
1701 u_short count = m->m_len - sizeof(struct ether_header);
1703 u_short tbd_p = OFFSET_TBD;
1704 u_short len, clen = 0;
1705 short base = sc->base;
1709 if (sc->wl_if.if_flags & IFF_DEBUG)
1710 printf("wl%d: entered wlxmt()\n",unit);
1714 cb.ac_command = (AC_CW_EL|AC_TRANSMIT|AC_CW_I);
1715 cb.ac_link_offset = I82586NULL;
1716 outw(PIOR1(base), OFFSET_CU);
1717 outsw(PIOP1(base), &cb, 6/2);
1718 outw(PIOP1(base), OFFSET_TBD); /* cb.cmd.transmit.tbd_offset */
1719 outsw(PIOP1(base), eh_p->ether_dhost, WAVELAN_ADDR_SIZE/2);
1720 outw(PIOP1(base), eh_p->ether_type);
1723 if (sc->wl_if.if_flags & IFF_DEBUG) {
1725 printf("XMT mbuf: L%d @%p ", count, (void *)mb_p);
1726 printf("ether type %x\n", eh_p->ether_type);
1729 #endif /* WLDEBUG */
1730 outw(PIOR0(base), OFFSET_TBD);
1731 outw(PIOP0(base), 0); /* act_count */
1732 outw(PIOR1(base), OFFSET_TBD + 4);
1733 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1734 outw(PIOP1(base), 0); /* buffer_base */
1737 if (clen + count > WAVELAN_MTU)
1743 outw(PIOR1(base), xmtdata_p);
1744 outsw(PIOP1(base), mb_p, len/2);
1746 outw(PIOR0(base), tbd_p); /* address of act_count */
1747 outw(PIOP0(base), inw(PIOP0(base)) + count);
1749 if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1752 /* go to the next descriptor */
1753 outw(PIOR0(base), tbd_p + 2);
1754 tbd_p += sizeof (tbd_t);
1755 outw(PIOP0(base), tbd_p); /* next_tbd_offset */
1756 outw(PIOR0(base), tbd_p);
1757 outw(PIOP0(base), 0); /* act_count */
1758 outw(PIOR1(base), tbd_p + 4);
1759 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1760 outw(PIOP1(base), 0); /* buffer_base */
1761 /* at the end -> coallesce remaining mbufs */
1762 if (tbd_p == OFFSET_TBD + (N_TBD-1) * sizeof (tbd_t)) {
1763 wlsftwsleaze(&count, &mb_p, &tm_p, unit);
1766 /* next mbuf short -> coallesce as needed */
1767 if ( (tm_p->m_next == (struct mbuf *) 0) ||
1768 #define HDW_THRESHOLD 55
1769 tm_p->m_len > HDW_THRESHOLD)
1772 wlhdwsleaze(&count, &mb_p, &tm_p, unit);
1776 } else if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1778 count = tm_p->m_len;
1779 mb_p = mtod(tm_p, u_char *);
1781 if (sc->wl_if.if_flags & IFF_DEBUG)
1783 printf("mbuf+ L%d @%p ", count, (void *)mb_p);
1784 #endif /* WLDEBUG */
1787 if (sc->wl_if.if_flags & IFF_DEBUG)
1789 printf("CLEN = %d\n", clen);
1790 #endif /* WLDEBUG */
1791 outw(PIOR0(base), tbd_p);
1792 if (clen < ETHERMIN) {
1793 outw(PIOP0(base), inw(PIOP0(base)) + ETHERMIN - clen);
1794 outw(PIOR1(base), xmtdata_p);
1795 for (xmtshort_p = xmtdata_p; clen < ETHERMIN; clen += 2)
1796 outw(PIOP1(base), 0);
1798 outw(PIOP0(base), inw(PIOP0(base)) | TBD_SW_EOF);
1799 outw(PIOR0(base), tbd_p + 2);
1800 outw(PIOP0(base), I82586NULL);
1802 if (sc->wl_if.if_flags & IFF_DEBUG) {
1808 #endif /* WLDEBUG */
1810 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
1812 * wait for 586 to clear previous command, complain if it takes
1815 for (spin = 1;;spin = (spin + 1) % 10000) {
1816 if (inw(PIOP0(base)) == 0) { /* it's done, we can go */
1819 if ((spin == 0) && xmt_watch) { /* not waking up, and we care */
1820 printf("wl%d: slow accepting xmit\n",unit);
1823 outw(PIOP0(base), SCB_CU_STRT); /* new command */
1824 SET_CHAN_ATTN(unit);
1829 * Pause to avoid transmit overrun problems.
1830 * The required delay tends to vary with platform type, and may be
1831 * related to interrupt loss.
1833 if (wl_xmit_delay) {
1834 DELAY(wl_xmit_delay);
1842 * This function builds the linear linked lists of fd's and
1843 * rbd's. Based on page 4-32 of 1986 Intel microcom handbook.
1849 struct wl_softc *sc = WLSOFTC(unit);
1850 short base = sc->base;
1853 u_short fd_p = OFFSET_RU;
1854 u_short rbd_p = OFFSET_RBD;
1857 sc->begin_fd = fd_p;
1858 for(i = 0; i < N_FD; i++) {
1861 fd.link_offset = fd_p + sizeof(fd_t);
1862 fd.rbd_offset = I82586NULL;
1863 outw(PIOR1(base), fd_p);
1864 outsw(PIOP1(base), &fd, 8/2);
1865 fd_p = fd.link_offset;
1867 fd_p -= sizeof(fd_t);
1869 outw(PIOR1(base), fd_p + 2);
1870 outw(PIOP1(base), AC_CW_EL); /* command */
1871 outw(PIOP1(base), I82586NULL); /* link_offset */
1874 outw(PIOR0(base), fd_p + 6); /* address of rbd_offset */
1875 outw(PIOP0(base), rbd_p);
1876 outw(PIOR1(base), rbd_p);
1877 for(i = 0; i < N_RBD; i++) {
1879 rbd.buffer_addr = rbd_p + sizeof(rbd_t) + 2;
1880 rbd.buffer_base = 0;
1881 rbd.size = RCVBUFSIZE;
1883 rbd_p += sizeof(ru_t);
1884 rbd.next_rbd_offset = rbd_p;
1886 rbd.next_rbd_offset = I82586NULL;
1887 rbd.size |= AC_CW_EL;
1888 sc->end_rbd = rbd_p;
1890 outsw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1891 outw(PIOR1(base), rbd_p);
1893 return sc->begin_fd;
1899 * This routine starts the receive unit running. First checks if the
1900 * board is actually ready, then the board is instructed to receive
1907 struct wl_softc *sc = WLSOFTC(unit);
1908 short base = sc->base;
1912 if (sc->wl_if.if_flags & IFF_DEBUG)
1913 printf("wl%d: entered wlrustrt()\n",unit);
1915 outw(PIOR0(base), OFFSET_SCB);
1916 if (inw(PIOP0(base)) & SCB_RUS_READY){
1917 printf("wlrustrt: RUS_READY\n");
1921 outw(PIOR0(base), OFFSET_SCB + 2);
1922 outw(PIOP0(base), SCB_RU_STRT); /* command */
1923 rfa = wlbldru(unit);
1924 outw(PIOR0(base), OFFSET_SCB + 6); /* address of scb_rfa_offset */
1925 outw(PIOP0(base), rfa);
1927 SET_CHAN_ATTN(unit);
1934 * This routine does a 586 op-code number 7, and obtains the
1935 * diagnose status for the WaveLAN.
1941 struct wl_softc *sc = WLSOFTC(unit);
1942 short base = sc->base;
1946 if (sc->wl_if.if_flags & IFF_DEBUG)
1947 printf("wl%d: entered wldiag()\n",unit);
1949 outw(PIOR0(base), OFFSET_SCB);
1950 status = inw(PIOP0(base));
1951 if (status & SCB_SW_INT) {
1952 /* state is 2000 which seems ok
1953 printf("wl%d diag(): unexpected initial state %\n",
1954 unit, inw(PIOP0(base)));
1958 outw(PIOR1(base), OFFSET_CU);
1959 outw(PIOP1(base), 0); /* ac_status */
1960 outw(PIOP1(base), AC_DIAGNOSE|AC_CW_EL);/* ac_command */
1961 if(wlcmd(unit, "diag()") == 0)
1963 outw(PIOR0(base), OFFSET_CU);
1964 if (inw(PIOP0(base)) & 0x0800) {
1965 printf("wl%d: i82586 Self Test failed!\n", unit);
1974 * This routine does a standard config of the WaveLAN board.
1980 configure_t configure;
1981 struct wl_softc *sc = WLSOFTC(unit);
1982 short base = sc->base;
1985 #if defined(__DragonFly__) || (defined(__FreeBSD__) && __FreeBSD_version >= 300000)
1986 struct ifmultiaddr *ifma;
1989 struct ether_multi *enm;
1990 struct ether_multistep step;
1993 #endif /* MULTICAST */
1996 if (sc->wl_if.if_flags & IFF_DEBUG)
1997 printf("wl%d: entered wlconfig()\n",unit);
1999 outw(PIOR0(base), OFFSET_SCB);
2000 if (inw(PIOP0(base)) & SCB_SW_INT) {
2002 printf("wl%d config(): unexpected initial state %x\n",
2003 unit, inw(PIOP0(base)));
2008 outw(PIOR1(base), OFFSET_CU);
2009 outw(PIOP1(base), 0); /* ac_status */
2010 outw(PIOP1(base), AC_CONFIGURE|AC_CW_EL); /* ac_command */
2013 configure.fifolim_bytecnt = 0x080c;
2014 configure.addrlen_mode = 0x0600;
2015 configure.linprio_interframe = 0x2060;
2016 configure.slot_time = 0xf200;
2017 configure.hardware = 0x0008; /* tx even w/o CD */
2018 configure.min_frame_len = 0x0040;
2020 /* This is the configuration block suggested by Marc Meertens
2021 * <mmeerten@obelix.utrecht.NCR.COM> in an e-mail message to John
2022 * Ioannidis on 10 Nov 92.
2024 configure.fifolim_bytecnt = 0x040c;
2025 configure.addrlen_mode = 0x0600;
2026 configure.linprio_interframe = 0x2060;
2027 configure.slot_time = 0xf000;
2028 configure.hardware = 0x0008; /* tx even w/o CD */
2029 configure.min_frame_len = 0x0040;
2032 * below is the default board configuration from p2-28 from 586 book
2034 configure.fifolim_bytecnt = 0x080c;
2035 configure.addrlen_mode = 0x2600;
2036 configure.linprio_interframe = 0x7820; /* IFS=120, ACS=2 */
2037 configure.slot_time = 0xf00c; /* slottime=12 */
2038 configure.hardware = 0x0008; /* tx even w/o CD */
2039 configure.min_frame_len = 0x0040;
2041 if(sc->mode & (MOD_PROM | MOD_ENAL)) {
2042 configure.hardware |= 1;
2044 outw(PIOR1(base), OFFSET_CU + 6);
2045 outsw(PIOP1(base), &configure, sizeof(configure_t)/2);
2047 if(wlcmd(unit, "config()-configure") == 0)
2050 outw(PIOR1(base), OFFSET_CU);
2051 outw(PIOP1(base), 0); /* ac_status */
2052 outw(PIOP1(base), AC_MCSETUP|AC_CW_EL); /* ac_command */
2053 outw(PIOR1(base), OFFSET_CU + 8);
2054 #if defined(__DragonFly__) || (defined(__FreeBSD__) && __FreeBSD_version >= 300000)
2055 for (ifma = sc->wl_if.if_multiaddrs.lh_first; ifma;
2056 ifma = ifma->ifma_link.le_next) {
2057 if (ifma->ifma_addr->sa_family != AF_LINK)
2060 addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
2061 outw(PIOP1(base), addrp[0] + (addrp[1] << 8));
2062 outw(PIOP1(base), addrp[2] + (addrp[3] << 8));
2063 outw(PIOP1(base), addrp[4] + (addrp[5] << 8));
2067 ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2068 while (enm != NULL) {
2069 unsigned int lo, hi;
2070 /* break if setting a multicast range, else we would crash */
2071 if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2074 lo = (enm->enm_addrlo[3] << 16) + (enm->enm_addrlo[4] << 8)
2075 + enm->enm_addrlo[5];
2076 hi = (enm->enm_addrhi[3] << 16) + (enm->enm_addrhi[4] << 8)
2077 + enm->enm_addrhi[5];
2079 outw(PIOP1(base),enm->enm_addrlo[0] +
2080 (enm->enm_addrlo[1] << 8));
2081 outw(PIOP1(base),enm->enm_addrlo[2] +
2082 ((lo >> 8) & 0xff00));
2083 outw(PIOP1(base), ((lo >> 8) & 0xff) +
2084 ((lo << 8) & 0xff00));
2085 /* #define MCASTDEBUG */
2087 printf("mcast_addr[%d,%d,%d] %x %x %x %x %x %x\n", lo, hi, cnt,
2093 enm->enm_addrlo[5]);
2098 ETHER_NEXT_MULTI(step, enm);
2101 outw(PIOR1(base), OFFSET_CU + 6); /* mc-cnt */
2102 outw(PIOP1(base), cnt * WAVELAN_ADDR_SIZE);
2103 if(wlcmd(unit, "config()-mcaddress") == 0)
2105 #endif /* MULTICAST */
2107 outw(PIOR1(base), OFFSET_CU);
2108 outw(PIOP1(base), 0); /* ac_status */
2109 outw(PIOP1(base), AC_IASETUP|AC_CW_EL); /* ac_command */
2110 outw(PIOR1(base), OFFSET_CU + 6);
2111 outsw(PIOP1(base), sc->wl_addr, WAVELAN_ADDR_SIZE/2);
2113 if(wlcmd(unit, "config()-address") == 0)
2124 * Set channel attention bit and busy wait until command has
2125 * completed. Then acknowledge the command completion.
2128 wlcmd(int unit, char *str)
2130 struct wl_softc *sc = WLSOFTC(unit);
2131 short base = sc->base;
2134 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
2135 outw(PIOP0(base), SCB_CU_STRT);
2137 SET_CHAN_ATTN(unit);
2139 outw(PIOR0(base), OFFSET_CU);
2140 for(i = 0; i < 0xffff; i++)
2141 if (inw(PIOP0(base)) & AC_SW_C)
2143 if (i == 0xffff || !(inw(PIOP0(base)) & AC_SW_OK)) {
2144 printf("wl%d: %s failed; status = %d, inw = %x, outw = %x\n",
2145 unit, str, inw(PIOP0(base)) & AC_SW_OK, inw(PIOP0(base)), inw(PIOR0(base)));
2146 outw(PIOR0(base), OFFSET_SCB);
2147 printf("scb_status %x\n", inw(PIOP0(base)));
2148 outw(PIOR0(base), OFFSET_SCB+2);
2149 printf("scb_command %x\n", inw(PIOP0(base)));
2150 outw(PIOR0(base), OFFSET_SCB+4);
2151 printf("scb_cbl %x\n", inw(PIOP0(base)));
2152 outw(PIOR0(base), OFFSET_CU+2);
2153 printf("cu_cmd %x\n", inw(PIOP0(base)));
2157 outw(PIOR0(base), OFFSET_SCB);
2158 if ((inw(PIOP0(base)) & SCB_SW_INT) && (inw(PIOP0(base)) != SCB_SW_CNA)) {
2160 printf("wl%d %s: unexpected final state %x\n",
2161 unit, str, inw(PIOP0(base)));
2169 * wlack: if the 82596 wants attention because it has finished
2170 * sending or receiving a packet, acknowledge its desire and
2171 * return bits indicating the kind of attention. wlack() returns
2172 * these bits so that the caller can service exactly the
2173 * conditions that wlack() acknowledged.
2180 struct wl_softc *sc = WLSOFTC(unit);
2181 short base = sc->base;
2183 outw(PIOR1(base), OFFSET_SCB);
2184 if(!(cmd = (inw(PIOP1(base)) & SCB_SW_INT)))
2187 if (sc->wl_if.if_flags & IFF_DEBUG)
2188 printf("wl%d: doing a wlack()\n",unit);
2190 outw(PIOP1(base), cmd);
2191 SET_CHAN_ATTN(unit);
2192 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
2193 for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
2195 printf("wl%d wlack(): board not accepting command.\n", unit);
2202 struct wl_softc *sc = WLSOFTC(unit);
2203 short base = sc->base;
2204 u_short tbd_p = OFFSET_TBD;
2210 outw(PIOR1(base), tbd_p);
2211 insw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
2212 sum += (tbd.act_count & ~TBD_SW_EOF);
2213 printf("%d: addr %x, count %d (%d), next %x, base %x\n",
2214 i++, tbd.buffer_addr,
2215 (tbd.act_count & ~TBD_SW_EOF), sum,
2216 tbd.next_tbd_offset, tbd.buffer_base);
2217 if (tbd.act_count & TBD_SW_EOF)
2219 tbd_p = tbd.next_tbd_offset;
2224 wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2226 struct mbuf *tm_p = *tm_pp;
2227 u_char *mb_p = *mb_pp;
2233 * can we get a run that will be coallesced or
2234 * that terminates before breaking
2237 count += tm_p->m_len;
2238 if (tm_p->m_len & 1)
2240 } while ((tm_p = tm_p->m_next) != (struct mbuf *)0);
2241 if ( (tm_p == (struct mbuf *)0) ||
2242 count > HDW_THRESHOLD) {
2243 *countp = (*tm_pp)->m_len;
2244 *mb_pp = mtod((*tm_pp), u_char *);
2248 /* we need to copy */
2252 cp = (u_char *) t_packet;
2254 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2256 if (count > HDW_THRESHOLD)
2259 if (tm_p->m_next == (struct mbuf *)0)
2261 tm_p = tm_p->m_next;
2264 *mb_pp = (u_char *) t_packet;
2271 wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2273 struct mbuf *tm_p = *tm_pp;
2275 u_char *cp = (u_char *) t_packet;
2278 /* we need to copy */
2280 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2283 if (tm_p->m_next == (struct mbuf *)0)
2285 tm_p = tm_p->m_next;
2289 *mb_pp = (u_char *) t_packet;
2297 struct wl_softc *sc = WLSOFTC(unit);
2298 short base = sc->base;
2301 printf("wl%d: DCE_STATUS: 0x%x, ", unit,
2302 wlmmcread(base,MMC_DCE_STATUS) & 0x0f);
2303 tmp = wlmmcread(base,MMC_CORRECT_NWID_H) << 8;
2304 tmp |= wlmmcread(base,MMC_CORRECT_NWID_L);
2305 printf("Correct NWID's: %d, ", tmp);
2306 tmp = wlmmcread(base,MMC_WRONG_NWID_H) << 8;
2307 tmp |= wlmmcread(base,MMC_WRONG_NWID_L);
2308 printf("Wrong NWID's: %d\n", tmp);
2309 printf("THR_PRE_SET: 0x%x, ", wlmmcread(base,MMC_THR_PRE_SET));
2310 printf("SIGNAL_LVL: %d, SILENCE_LVL: %d\n",
2311 wlmmcread(base,MMC_SIGNAL_LVL),
2312 wlmmcread(base,MMC_SILENCE_LVL));
2313 printf("SIGN_QUAL: 0x%x, NETW_ID: %x:%x, DES: %d\n",
2314 wlmmcread(base,MMC_SIGN_QUAL),
2315 wlmmcread(base,MMC_NETW_ID_H),
2316 wlmmcread(base,MMC_NETW_ID_L),
2317 wlmmcread(base,MMC_DES_AVAIL));
2321 wlmmcread(u_int base, u_short reg)
2323 while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2324 outw(MMCR(base),reg << 1);
2325 while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2326 return (u_short)inw(MMCR(base)) >> 8;
2332 MMC_WRITE(MMC_FREEZE,1);
2334 * SNR retrieval procedure :
2336 * read signal level : wlmmcread(base, MMC_SIGNAL_LVL);
2337 * read silence level : wlmmcread(base, MMC_SILENCE_LVL);
2339 MMC_WRITE(MMC_FREEZE,0);
2341 * SNR is signal:silence ratio.
2348 ** Reads the psa for the wavelan at (base) into (buf)
2351 wlgetpsa(int base, u_char *buf)
2355 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2356 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2358 for (i = 0; i < 0x40; i++) {
2359 outw(PIOR2(base), i);
2360 buf[i] = inb(PIOP2(base));
2362 PCMD(base, HACR_DEFAULT);
2363 PCMD(base, HACR_DEFAULT);
2369 ** Writes the psa for wavelan (unit) from the softc back to the
2370 ** board. Updates the CRC and sets the CRC OK flag.
2372 ** Do not call this when the board is operating, as it doesn't
2373 ** preserve the hacr.
2378 struct wl_softc *sc = WLSOFTC(unit);
2379 short base = sc->base;
2383 crc = wlpsacrc(sc->psa); /* calculate CRC of PSA */
2384 sc->psa[WLPSA_CRCLOW] = crc & 0xff;
2385 sc->psa[WLPSA_CRCHIGH] = (crc >> 8) & 0xff;
2386 sc->psa[WLPSA_CRCOK] = 0x55; /* default to 'bad' until programming complete */
2388 oldpri = splimp(); /* ick, long pause */
2390 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2391 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2393 for (i = 0; i < 0x40; i++) {
2395 outw(PIOR2(base),i); /* write param memory */
2397 outb(PIOP2(base), sc->psa[i]);
2400 outw(PIOR2(base),WLPSA_CRCOK); /* update CRC flag*/
2402 sc->psa[WLPSA_CRCOK] = 0xaa; /* OK now */
2403 outb(PIOP2(base), 0xaa); /* all OK */
2406 PCMD(base, HACR_DEFAULT);
2407 PCMD(base, HACR_DEFAULT);
2413 ** CRC routine provided by Christopher Giordano <cgiordan@gdeb.com>,
2414 ** from original code by Tomi Mikkonen (tomitm@remedy.fi)
2417 static u_int crc16_table[16] = {
2418 0x0000, 0xCC01, 0xD801, 0x1400,
2419 0xF001, 0x3C00, 0x2800, 0xE401,
2420 0xA001, 0x6C00, 0x7800, 0xB401,
2421 0x5000, 0x9C01, 0x8801, 0x4400
2425 wlpsacrc(u_char *buf)
2430 for (i = 0; i < 0x3d; i++, buf++) {
2432 r1 = crc16_table[crc & 0xF];
2433 crc = (crc >> 4) & 0x0FFF;
2434 crc = crc ^ r1 ^ crc16_table[*buf & 0xF];
2437 r1 = crc16_table[crc & 0xF];
2438 crc = (crc >> 4) & 0x0FFF;
2439 crc = crc ^ r1 ^ crc16_table[(*buf >> 4) & 0xF];
2448 * take input packet and cache various radio hw characteristics
2449 * indexed by MAC address.
2451 * Some things to think about:
2452 * note that no space is malloced.
2453 * We might hash the mac address if the cache were bigger.
2454 * It is not clear that the cache is big enough.
2455 * It is also not clear how big it should be.
2456 * The cache is IP-specific. We don't care about that as
2457 * we want it to be IP-specific.
2458 * The last N recv. packets are saved. This will tend
2459 * to reward agents and mobile hosts that beacon.
2460 * That is probably fine for mobile ip.
2463 /* globals for wavelan signal strength cache */
2464 /* this should go into softc structure above.
2467 /* set true if you want to limit cache items to broadcast/mcast
2468 * only packets (not unicast)
2470 static int wl_cache_mcastonly = 1;
2471 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_mcastonly, CTLFLAG_RW,
2472 &wl_cache_mcastonly, 0, "");
2474 /* set true if you want to limit cache items to IP packets only
2476 static int wl_cache_iponly = 1;
2477 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_iponly, CTLFLAG_RW,
2478 &wl_cache_iponly, 0, "");
2480 /* zero out the cache
2483 wl_cache_zero(int unit)
2485 struct wl_softc *sc = WLSOFTC(unit);
2487 bzero(&sc->w_sigcache[0], sizeof(struct w_sigcache) * MAXCACHEITEMS);
2489 sc->w_nextcache = 0;
2490 sc->w_wrapindex = 0;
2493 /* store hw signal info in cache.
2494 * index is MAC address, but an ip src gets stored too
2495 * There are two filters here controllable via sysctl:
2496 * throw out unicast (on by default, but can be turned off)
2497 * throw out non-ip (on by default, but can be turned off)
2500 void wl_cache_store (int unit, int base, struct ether_header *eh,
2503 struct ip *ip = NULL; /* Avoid GCC warning */
2505 int signal, silence;
2506 int w_insertcache; /* computed index for cache entry storage */
2507 struct wl_softc *sc = WLSOFTC(unit);
2508 int ipflag = wl_cache_iponly;
2512 * 2. configurable filter to throw out unicast packets,
2513 * keep multicast only.
2517 /* reject if not IP packet
2519 if ( wl_cache_iponly && (ntohs(eh->ether_type) != 0x800)) {
2523 /* check if broadcast or multicast packet. we toss
2526 if (wl_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
2530 /* find the ip header. we want to store the ip_src
2531 * address. use the mtod macro(in mbuf.h)
2532 * to typecast m to struct ip *
2535 ip = mtod(m, struct ip *);
2538 /* do a linear search for a matching MAC address
2539 * in the cache table
2540 * . MAC address is 6 bytes,
2541 * . var w_nextcache holds total number of entries already cached
2543 for(i = 0; i < sc->w_nextcache; i++) {
2544 if (! bcmp(eh->ether_shost, sc->w_sigcache[i].macsrc, 6 )) {
2546 * so we already have this entry,
2547 * update the data, and LRU age
2553 /* did we find a matching mac address?
2554 * if yes, then overwrite a previously existing cache entry
2556 if (i < sc->w_nextcache ) {
2559 /* else, have a new address entry,so
2560 * add this new entry,
2561 * if table full, then we need to replace entry
2565 /* check for space in cache table
2566 * note: w_nextcache also holds number of entries
2567 * added in the cache table
2569 if ( sc->w_nextcache < MAXCACHEITEMS ) {
2570 w_insertcache = sc->w_nextcache;
2572 sc->w_sigitems = sc->w_nextcache;
2574 /* no space found, so simply wrap with wrap index
2575 * and "zap" the next entry
2578 if (sc->w_wrapindex == MAXCACHEITEMS) {
2579 sc->w_wrapindex = 0;
2581 w_insertcache = sc->w_wrapindex++;
2585 /* invariant: w_insertcache now points at some slot
2588 if (w_insertcache < 0 || w_insertcache >= MAXCACHEITEMS) {
2590 "wl_cache_store, bad index: %d of [0..%d], gross cache error\n",
2591 w_insertcache, MAXCACHEITEMS);
2595 /* store items in cache
2598 * .signal (0..63) ,silence (0..63) ,quality (0..15)
2601 sc->w_sigcache[w_insertcache].ipsrc = ip->ip_src.s_addr;
2603 bcopy( eh->ether_shost, sc->w_sigcache[w_insertcache].macsrc, 6);
2604 signal = sc->w_sigcache[w_insertcache].signal = wlmmcread(base, MMC_SIGNAL_LVL) & 0x3f;
2605 silence = sc->w_sigcache[w_insertcache].silence = wlmmcread(base, MMC_SILENCE_LVL) & 0x3f;
2606 sc->w_sigcache[w_insertcache].quality = wlmmcread(base, MMC_SIGN_QUAL) & 0x0f;
2608 sc->w_sigcache[w_insertcache].snr =
2611 sc->w_sigcache[w_insertcache].snr = 0;
2615 #endif /* WLCACHE */
2618 * determine if in all multicast mode or not
2620 * returns: 1 if IFF_ALLMULTI should be set
2625 #if defined(__FreeBSD__) && __FreeBSD_version < 300000 /* not required */
2627 check_allmulti(int unit)
2629 struct wl_softc *sc = WLSOFTC(unit);
2630 short base = sc->base;
2631 struct ether_multi *enm;
2632 struct ether_multistep step;
2634 ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2635 while (enm != NULL) {
2636 unsigned int lo, hi;
2638 printf("enm_addrlo %x:%x:%x:%x:%x:%x\n", enm->enm_addrlo[0], enm->enm_addrlo[1],
2639 enm->enm_addrlo[2], enm->enm_addrlo[3], enm->enm_addrlo[4],
2640 enm->enm_addrlo[5]);
2641 printf("enm_addrhi %x:%x:%x:%x:%x:%x\n", enm->enm_addrhi[0], enm->enm_addrhi[1],
2642 enm->enm_addrhi[2], enm->enm_addrhi[3], enm->enm_addrhi[4],
2643 enm->enm_addrhi[5]);
2645 if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2648 ETHER_NEXT_MULTI(step, enm);