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.2 2003/06/17 04:28:37 dillon 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 <i386/isa/isa_device.h>
224 #include <i386/isa/ic/if_wl_i82586.h> /* Definitions for the Intel chip */
226 /* was 1000 in original, fed to DELAY(x) */
227 #define DELAYCONST 1000
228 #include <i386/isa/if_wl.h>
229 #include <machine/if_wl_wavelan.h>
231 static char t_packet[ETHERMTU + sizeof(struct ether_header) + sizeof(long)];
234 struct arpcom wl_ac; /* Ethernet common part */
235 #define wl_if wl_ac.ac_if /* network visible interface */
236 #define wl_addr wl_ac.ac_enaddr /* hardware address */
238 u_char nwid[2]; /* current radio modem nwid */
242 int tbusy; /* flag to determine if xmit is busy */
246 u_short hacr; /* latest host adapter CR command */
248 u_char chan24; /* 2.4 Gz: channel number/EEPROM Area # */
249 u_short freq24; /* 2.4 Gz: resulting frequency */
250 struct callout_handle watchdog_ch;
252 int w_sigitems; /* number of cached entries */
253 /* array of cache entries */
254 struct w_sigcache w_sigcache[ MAXCACHEITEMS ];
255 int w_nextcache; /* next free cache entry */
256 int w_wrapindex; /* next "free" cache entry */
259 static struct wl_softc wl_softc[NWL];
261 #define WLSOFTC(unit) ((struct wl_softc *)(&wl_softc[unit]))
263 static int wlprobe(struct isa_device *);
264 static int wlattach(struct isa_device *);
266 struct isa_driver wldriver = {
267 wlprobe, wlattach, "wl", 0
271 * XXX The Wavelan appears to be prone to dropping stuff if you talk to
272 * it too fast. This disgusting hack inserts a delay after each packet
273 * is queued which helps avoid this behaviour on fast systems.
275 static int wl_xmit_delay = 250;
276 SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_delay, CTLFLAG_RW, &wl_xmit_delay, 0, "");
279 * not XXX, but ZZZ (bizarre).
280 * promiscuous mode can be toggled to ignore NWIDs. By default,
281 * it does not. Caution should be exercised about combining
282 * this mode with IFF_ALLMULTI which puts this driver in
285 static int wl_ignore_nwid = 0;
286 SYSCTL_INT(_machdep, OID_AUTO, wl_ignore_nwid, CTLFLAG_RW, &wl_ignore_nwid, 0, "");
289 * Emit diagnostics about transmission problems
291 static int xmt_watch = 0;
292 SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_watch, CTLFLAG_RW, &xmt_watch, 0, "");
295 * Collect SNR statistics
297 static int gathersnr = 0;
298 SYSCTL_INT(_machdep, OID_AUTO, wl_gather_snr, CTLFLAG_RW, &gathersnr, 0, "");
300 static void wlstart(struct ifnet *ifp);
301 static void wlinit(void *xsc);
302 static int wlioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
303 static timeout_t wlwatchdog;
304 static ointhand2_t wlintr;
305 static void wlxmt(int unt, struct mbuf *m);
306 static int wldiag(int unt);
307 static int wlconfig(int unit);
308 static int wlcmd(int unit, char *str);
309 static void wlmmcstat(int unit);
310 static u_short wlbldru(int unit);
311 static u_short wlmmcread(u_int base, u_short reg);
312 static void wlinitmmc(int unit);
313 static int wlhwrst(int unit);
314 static void wlrustrt(int unit);
315 static void wlbldcu(int unit);
316 static int wlack(int unit);
317 static int wlread(int unit, u_short fd_p);
318 static void getsnr(int unit);
319 static void wlrcv(int unit);
320 static int wlrequeue(int unit, u_short fd_p);
321 static void wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
322 static void wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
323 static void wltbd(int unit);
324 static void wlgetpsa(int base, u_char *buf);
325 static void wlsetpsa(int unit);
326 static u_short wlpsacrc(u_char *buf);
327 static void wldump(int unit);
329 static void wl_cache_store(int, int, struct ether_header *, struct mbuf *);
330 static void wl_cache_zero(int unit);
333 # if defined(__FreeBSD__) && __FreeBSD_version < 300000
334 static int check_allmulti(int unit);
338 /* array for maping irq numbers to values for the irq parameter register */
339 static int irqvals[16] = {
340 0, 0, 0, 0x01, 0x02, 0x04, 0, 0x08, 0, 0, 0x10, 0x20, 0x40, 0, 0, 0x80
342 /* mask of valid IRQs */
343 #define WL_IRQS (IRQ3|IRQ4|IRQ5|IRQ7|IRQ10|IRQ11|IRQ12|IRQ15)
348 * This function "probes" or checks for the WaveLAN board on the bus to
349 * see if it is there. As far as I can tell, the best break between this
350 * routine and the attach code is to simply determine whether the board
351 * is configured in properly. Currently my approach to this is to write
352 * and read a word from the SRAM on the board being probed. If the word
353 * comes back properly then we assume the board is there. The config
354 * code expects to see a successful return from the probe routine before
355 * attach will be called.
357 * input : address device is mapped to, and unit # being checked
358 * output : a '1' is returned if the board exists, and a 0 otherwise
362 wlprobe(struct isa_device *id)
364 struct wl_softc *sc = &wl_softc[id->id_unit];
365 register short base = id->id_iobase;
366 char *str = "wl%d: board out of range [0..%d]\n";
368 unsigned long oldpri;
372 * regular CMD() will not work, since no softc yet
374 #define PCMD(base, hacr) outw((base), (hacr))
377 PCMD(base, HACR_RESET); /* reset the board */
378 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
379 PCMD(base, HACR_RESET); /* reset the board */
380 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
383 /* clear reset command and set PIO#1 in autoincrement mode */
384 PCMD(base, HACR_DEFAULT);
385 PCMD(base, HACR_DEFAULT);
386 outw(PIOR1(base), 0); /* go to beginning of RAM */
387 outsw(PIOP1(base), str, strlen(str)/2+1); /* write string */
389 outw(PIOR1(base), 0); /* rewind */
390 insw(PIOP1(base), inbuf, strlen(str)/2+1); /* read result */
392 if (bcmp(str, inbuf, strlen(str)))
395 sc->chan24 = 0; /* 2.4 Gz: config channel */
396 sc->freq24 = 0; /* 2.4 Gz: frequency */
398 /* read the PSA from the board into temporary storage */
399 wlgetpsa(base, inbuf);
401 /* We read the IRQ value from the PSA on the board. */
402 for (irq = 15; irq >= 0; irq--)
403 if (irqvals[irq] == inbuf[WLPSA_IRQNO])
405 if ((irq == 0) || (irqvals[irq] == 0)){
406 printf("wl%d: PSA corrupt (invalid IRQ value)\n", id->id_unit);
407 id->id_irq = 0; /* no interrupt */
410 * If the IRQ requested by the PSA is already claimed by another
411 * device, the board won't work, but the user can still access the
412 * driver to change the IRQ.
414 id->id_irq = (1<<irq); /* use IRQ from PSA */
423 * This function attaches a WaveLAN board to the "system". The rest of
424 * runtime structures are initialized here (this routine is called after
425 * a successful probe of the board). Once the ethernet address is read
426 * and stored, the board's ifnet structure is attached and readied.
428 * input : isa_dev structure setup in autoconfig
429 * output : board structs and ifnet is setup
433 wlattach(struct isa_device *id)
435 struct wl_softc *sc = (struct wl_softc *) &wl_softc[id->id_unit];
436 register short base = id->id_iobase;
438 u_char unit = id->id_unit;
439 register struct ifnet *ifp = &sc->wl_if;
442 printf("wlattach: base %x, unit %d\n", base, unit);
444 id->id_ointr = wlintr;
449 sc->hacr = HACR_RESET;
450 callout_handle_init(&sc->watchdog_ch);
451 CMD(unit); /* reset the board */
452 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
454 /* clear reset command and set PIO#2 in parameter access mode */
455 sc->hacr = (HACR_DEFAULT & ~HACR_16BITS);
458 /* Read the PSA from the board for our later reference */
459 wlgetpsa(base, sc->psa);
462 sc->nwid[0] = sc->psa[WLPSA_NWID];
463 sc->nwid[1] = sc->psa[WLPSA_NWID+1];
465 /* fetch MAC address - decide which one first */
466 if (sc->psa[WLPSA_MACSEL] & 1) {
471 for(i=0; i < WAVELAN_ADDR_SIZE; ++i) {
472 sc->wl_addr[i] = sc->psa[j + i];
475 /* enter normal 16 bit mode operation */
476 sc->hacr = HACR_DEFAULT;
480 outw(PIOR1(base), OFFSET_SCB + 8); /* address of scb_crcerrs */
481 outw(PIOP1(base), 0); /* clear scb_crcerrs */
482 outw(PIOP1(base), 0); /* clear scb_alnerrs */
483 outw(PIOP1(base), 0); /* clear scb_rscerrs */
484 outw(PIOP1(base), 0); /* clear scb_ovrnerrs */
486 bzero(ifp, sizeof(ifp));
488 ifp->if_unit = id->id_unit;
489 ifp->if_mtu = WAVELAN_MTU;
490 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
492 ifp->if_flags |= IFF_DEBUG;
495 ifp->if_flags |= IFF_MULTICAST;
496 #endif /* MULTICAST */
499 ifp->if_init = wlinit;
500 ifp->if_output = ether_output;
501 ifp->if_start = wlstart;
502 ifp->if_ioctl = wlioctl;
503 ifp->if_timer = 0; /* paranoia */
509 ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
511 bcopy(&sc->wl_addr[0], sc->wl_ac.ac_enaddr, WAVELAN_ADDR_SIZE);
512 printf("%s%d: address %6D, NWID 0x%02x%02x", ifp->if_name, ifp->if_unit,
513 sc->wl_ac.ac_enaddr, ":", sc->nwid[0], sc->nwid[1]);
515 printf(", Freq %d MHz",sc->freq24); /* 2.4 Gz */
516 printf("\n"); /* 2.4 Gz */
525 * Print out interesting information about the 82596.
530 register struct wl_softc *sp = WLSOFTC(unit);
534 printf("hasr %04x\n", inw(HASR(base)));
536 printf("scb at %04x:\n ", OFFSET_SCB);
537 outw(PIOR1(base), OFFSET_SCB);
538 for(i = 0; i < 8; i++)
539 printf("%04x ", inw(PIOP1(base)));
542 printf("cu at %04x:\n ", OFFSET_CU);
543 outw(PIOR1(base), OFFSET_CU);
544 for(i = 0; i < 8; i++)
545 printf("%04x ", inw(PIOP1(base)));
548 printf("tbd at %04x:\n ", OFFSET_TBD);
549 outw(PIOR1(base), OFFSET_TBD);
550 for(i = 0; i < 4; i++)
551 printf("%04x ", inw(PIOP1(base)));
555 /* Initialize the Modem Management Controller */
559 register struct wl_softc *sp = WLSOFTC(unit);
565 /* enter 8 bit operation */
566 sp->hacr = (HACR_DEFAULT & ~HACR_16BITS);
569 configured = sp->psa[WLPSA_CONFIGURED] & 1;
572 * Set default modem control parameters. Taken from NCR document
575 MMC_WRITE(MMC_JABBER_ENABLE, 0x01);
576 MMC_WRITE(MMC_ANTEN_SEL, 0x02);
577 MMC_WRITE(MMC_IFS, 0x20);
578 MMC_WRITE(MMC_MOD_DELAY, 0x04);
579 MMC_WRITE(MMC_JAM_TIME, 0x38);
580 MMC_WRITE(MMC_DECAY_PRM, 0x00); /* obsolete ? */
581 MMC_WRITE(MMC_DECAY_UPDAT_PRM, 0x00);
583 MMC_WRITE(MMC_LOOPT_SEL, 0x00);
584 if (sp->psa[WLPSA_COMPATNO] & 1) {
585 MMC_WRITE(MMC_THR_PRE_SET, 0x01); /* 0x04 for AT and 0x01 for MCA */
587 MMC_WRITE(MMC_THR_PRE_SET, 0x04); /* 0x04 for AT and 0x01 for MCA */
589 MMC_WRITE(MMC_QUALITY_THR, 0x03);
591 /* use configuration defaults from parameter storage area */
592 if (sp->psa[WLPSA_NWIDENABLE] & 1) {
593 if ((mode & (MOD_PROM | MOD_ENAL)) && wl_ignore_nwid) {
594 MMC_WRITE(MMC_LOOPT_SEL, 0x40);
596 MMC_WRITE(MMC_LOOPT_SEL, 0x00);
599 MMC_WRITE(MMC_LOOPT_SEL, 0x40); /* disable network id check */
601 MMC_WRITE(MMC_THR_PRE_SET, sp->psa[WLPSA_THRESH]);
602 MMC_WRITE(MMC_QUALITY_THR, sp->psa[WLPSA_QUALTHRESH]);
604 MMC_WRITE(MMC_FREEZE, 0x00);
605 MMC_WRITE(MMC_ENCR_ENABLE, 0x00);
607 MMC_WRITE(MMC_NETW_ID_L,sp->nwid[1]); /* set NWID */
608 MMC_WRITE(MMC_NETW_ID_H,sp->nwid[0]);
610 /* enter normal 16 bit mode operation */
611 sp->hacr = HACR_DEFAULT;
613 CMD(unit); /* virtualpc1 needs this! */
615 if (sp->psa[WLPSA_COMPATNO]== /* 2.4 Gz: half-card ver */
616 WLPSA_COMPATNO_WL24B) { /* 2.4 Gz */
617 i=sp->chan24<<4; /* 2.4 Gz: position ch # */
618 MMC_WRITE(MMC_EEADDR,i+0x0f); /* 2.4 Gz: named ch, wc=16 */
619 MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+ /* 2.4 Gz: Download Synths */
620 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: Read EEPROM */
621 for (i=0; i<1000; ++i) { /* 2.4 Gz: wait for download */
622 DELAY(40); /* 2.4 Gz */
623 if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and */
624 &(MMC_EECTRLstat_DWLD /* 2.4 Gz: EEBUSY */
625 +MMC_EECTRLstat_EEBUSY))==0) /* 2.4 Gz: */
626 break; /* 2.4 Gz: download finished */
628 if (i==1000) printf("wl: synth load failed\n"); /* 2.4 Gz */
629 MMC_WRITE(MMC_EEADDR,0x61); /* 2.4 Gz: default pwr, wc=2 */
630 MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+ /* 2.4 Gz: Download Xmit Pwr */
631 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: Read EEPROM */
632 for (i=0; i<1000; ++i) { /* 2.4 Gz: wait for download */
633 DELAY(40); /* 2.4 Gz */
634 if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and */
635 &(MMC_EECTRLstat_DWLD /* 2.4 Gz: EEBUSY */
636 +MMC_EECTRLstat_EEBUSY))==0) /* 2.4 Gz: */
637 break; /* 2.4 Gz: download finished */
639 if (i==1000) printf("wl: xmit pwr load failed\n"); /* 2.4 Gz */
640 MMC_WRITE(MMC_ANALCTRL, /* 2.4 Gz: EXT ant+polarity */
641 MMC_ANALCTRL_ANTPOL + /* 2.4 Gz: */
642 MMC_ANALCTRL_EXTANT); /* 2.4 Gz: */
643 i=sp->chan24<<4; /* 2.4 Gz: position ch # */
644 MMC_WRITE(MMC_EEADDR,i); /* 2.4 Gz: get frequency */
645 MMC_WRITE(MMC_EECTRL, /* 2.4 Gz: EEPROM read */
646 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: */
647 DELAY(40); /* 2.4 Gz */
648 i = wlmmcread(base,MMC_EEDATALrv) /* 2.4 Gz: freq val */
649 + (wlmmcread(base,MMC_EEDATAHrv)<<8); /* 2.4 Gz */
650 sp->freq24 = (i>>6)+2400; /* 2.4 Gz: save real freq */
657 * Another routine that interfaces the "if" layer to this driver.
658 * Simply resets the structures that are used by "upper layers".
659 * As well as calling wlhwrst that does reset the WaveLAN board.
661 * input : softc pointer for this interface
662 * output : structures (if structs) and board are reset
668 register struct wl_softc *sc = xsc;
669 struct ifnet *ifp = &sc->wl_if;
674 if (sc->wl_if.if_flags & IFF_DEBUG)
675 printf("wl%d: entered wlinit()\n",sc->unit);
677 #if defined(__FreeBSD__) && __FreeBSD_version >= 300000
678 if (ifp->if_addrhead.tqh_first == (struct ifaddr *)0) {
680 if (ifp->if_addrlist == (struct ifaddr *)0) {
685 if ((stat = wlhwrst(sc->unit)) == TRUE) {
686 sc->wl_if.if_flags |= IFF_RUNNING; /* same as DSF_RUNNING */
688 * OACTIVE is used by upper-level routines
691 sc->wl_if.if_flags &= ~IFF_OACTIVE; /* same as tbusy below */
693 sc->flags |= DSF_RUNNING;
695 untimeout(wlwatchdog, sc, sc->watchdog_ch);
699 printf("wl%d init(): trouble resetting board.\n", sc->unit);
707 * This routine resets the WaveLAN board that corresponds to the
708 * board number passed in.
710 * input : board number to do a hardware reset
711 * output : board is reset
717 register struct wl_softc *sc = WLSOFTC(unit);
720 if (sc->wl_if.if_flags & IFF_DEBUG)
721 printf("wl%d: entered wlhwrst()\n",unit);
723 sc->hacr = HACR_RESET;
724 CMD(unit); /* reset the board */
726 /* clear reset command and set PIO#1 in autoincrement mode */
727 sc->hacr = HACR_DEFAULT;
731 if (sc->wl_if.if_flags & IFF_DEBUG)
732 wlmmcstat(unit); /* Display MMC registers */
734 wlbldcu(unit); /* set up command unit structures */
736 if (wldiag(unit) == 0)
739 if (wlconfig(unit) == 0)
742 * insert code for loopback test here
744 wlrustrt(unit); /* start receive unit */
746 /* enable interrupts */
747 sc->hacr = (HACR_DEFAULT | HACR_INTRON);
756 * This function builds up the command unit structures. It inits
757 * the scp, iscp, scb, cb, tbd, and tbuf.
763 register struct wl_softc *sc = WLSOFTC(unit);
764 short base = sc->base;
772 bzero(&scp, sizeof(scp));
774 scp.scp_iscp = OFFSET_ISCP;
775 scp.scp_iscp_base = 0;
776 outw(PIOR1(base), OFFSET_SCP);
777 outsw(PIOP1(base), &scp, sizeof(scp_t)/2);
779 bzero(&iscp, sizeof(iscp));
781 iscp.iscp_scb_offset = OFFSET_SCB;
783 iscp.iscp_scb_base = 0;
784 outw(PIOR1(base), OFFSET_ISCP);
785 outsw(PIOP1(base), &iscp, sizeof(iscp_t)/2);
788 scb.scb_command = SCB_RESET;
789 scb.scb_cbl_offset = OFFSET_CU;
790 scb.scb_rfa_offset = OFFSET_RU;
794 scb.scb_ovrnerrs = 0;
795 outw(PIOR1(base), OFFSET_SCB);
796 outsw(PIOP1(base), &scb, sizeof(scb_t)/2);
800 outw(PIOR0(base), OFFSET_ISCP + 0); /* address of iscp_busy */
801 for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
802 if (i <= 0) printf("wl%d bldcu(): iscp_busy timeout.\n", unit);
803 outw(PIOR0(base), OFFSET_SCB + 0); /* address of scb_status */
804 for (i = STATUS_TRIES; i-- > 0; ) {
805 if (inw(PIOP0(base)) == (SCB_SW_CX|SCB_SW_CNA))
809 printf("wl%d bldcu(): not ready after reset.\n", unit);
813 cb.ac_command = AC_CW_EL; /* NOP */
814 cb.ac_link_offset = OFFSET_CU;
815 outw(PIOR1(base), OFFSET_CU);
816 outsw(PIOP1(base), &cb, 6/2);
819 tbd.next_tbd_offset = I82586NULL;
822 outw(PIOR1(base), OFFSET_TBD);
823 outsw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
831 * input : board number
832 * output : stuff sent to board if any there
836 wlstart(struct ifnet *ifp)
838 int unit = ifp->if_unit;
840 register struct wl_softc *sc = WLSOFTC(unit);
841 short base = sc->base;
842 int scb_status, cu_status, scb_command;
845 if (sc->wl_if.if_flags & IFF_DEBUG)
846 printf("wl%d: entered wlstart()\n",unit);
849 outw(PIOR1(base), OFFSET_CU);
850 cu_status = inw(PIOP1(base));
851 outw(PIOR0(base),OFFSET_SCB + 0); /* scb_status */
852 scb_status = inw(PIOP0(base));
853 outw(PIOR0(base), OFFSET_SCB + 2);
854 scb_command = inw(PIOP0(base));
857 * don't need OACTIVE check as tbusy here checks to see
858 * if we are already busy
861 if((scb_status & 0x0700) == SCB_CUS_IDLE &&
862 (cu_status & AC_SW_B) == 0){
864 untimeout(wlwatchdog, sc, sc->watchdog_ch);
865 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
867 * This is probably just a race. The xmt'r is just
868 * became idle but WE have masked interrupts so ...
871 printf("wl%d: CU idle, scb %04x %04x cu %04x\n",
872 unit, scb_status, scb_command, cu_status);
874 if (xmt_watch) printf("!!");
876 return; /* genuinely still busy */
878 } else if((scb_status & 0x0700) == SCB_CUS_ACTV ||
879 (cu_status & AC_SW_B)){
881 printf("wl%d: CU unexpectedly busy; scb %04x cu %04x\n",
882 unit, scb_status, cu_status);
884 if (xmt_watch) printf("wl%d: busy?!",unit);
885 return; /* hey, why are we busy? */
888 /* get ourselves some data */
890 IF_DEQUEUE(&ifp->if_snd, m);
891 if (m != (struct mbuf *)0) {
892 /* let BPF see it before we commit it */
897 /* set the watchdog timer so that if the board
898 * fails to interrupt we will restart
900 /* try 10 ticks, not very long */
901 sc->watchdog_ch = timeout(wlwatchdog, sc, 10);
902 sc->wl_ac.ac_if.if_flags |= IFF_OACTIVE;
903 sc->wl_if.if_opackets++;
906 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
914 * This routine does the actual copy of data (including ethernet header
915 * structure) from the WaveLAN to an mbuf chain that will be passed up
916 * to the "if" (network interface) layer. NOTE: we currently
917 * don't handle trailer protocols, so if that is needed, it will
918 * (at least in part) be added here. For simplicities sake, this
919 * routine copies the receive buffers from the board into a local (stack)
920 * buffer until the frame has been copied from the board. Once in
921 * the local buffer, the contents are copied to an mbuf chain that
922 * is then enqueued onto the appropriate "if" queue.
924 * input : board number, and an frame descriptor address
925 * output : the packet is put into an mbuf chain, and passed up
926 * assumes : if any errors occur, packet is "dropped on the floor"
930 wlread(int unit, u_short fd_p)
932 register struct wl_softc *sc = WLSOFTC(unit);
933 register struct ifnet *ifp = &sc->wl_if;
934 short base = sc->base;
936 struct ether_header eh;
940 u_short mlen, len, clen;
941 u_short bytes_in_msg, bytes_in_mbuf, bytes;
945 if (sc->wl_if.if_flags & IFF_DEBUG)
946 printf("wl%d: entered wlread()\n",unit);
948 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
949 printf("wl%d read(): board is not running.\n", ifp->if_unit);
950 sc->hacr &= ~HACR_INTRON;
951 CMD(unit); /* turn off interrupts */
953 /* read ether_header info out of device memory. doesn't
954 * go into mbuf. goes directly into eh structure
956 len = sizeof(struct ether_header); /* 14 bytes */
957 outw(PIOR1(base), fd_p);
958 insw(PIOP1(base), &fd, (sizeof(fd_t) - len)/2);
959 insw(PIOP1(base), &eh, (len-2)/2);
960 eh.ether_type = ntohs(inw(PIOP1(base)));
962 if (sc->wl_if.if_flags & IFF_DEBUG) {
963 printf("wlread: rcv packet, type is %x\n", eh.ether_type);
967 * WARNING. above is done now in ether_input, above may be
968 * useful for debug. jrb
970 eh.ether_type = htons(eh.ether_type);
972 if (fd.rbd_offset == I82586NULL) {
973 printf("wl%d read(): Invalid buffer\n", unit);
974 if (wlhwrst(unit) != TRUE) {
975 printf("wl%d read(): hwrst trouble.\n", unit);
980 outw(PIOR1(base), fd.rbd_offset);
981 insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
982 bytes_in_msg = rbd.status & RBD_SW_COUNT;
983 MGETHDR(m, M_DONTWAIT, MT_DATA);
985 if (m == (struct mbuf *)0) {
987 * not only do we want to return, we need to drop the packet on
988 * the floor to clear the interrupt.
991 if (wlhwrst(unit) != TRUE) {
992 sc->hacr &= ~HACR_INTRON;
993 CMD(unit); /* turn off interrupts */
994 printf("wl%d read(): hwrst trouble.\n", unit);
998 m->m_next = (struct mbuf *) 0;
999 m->m_pkthdr.rcvif = ifp;
1000 m->m_pkthdr.len = 0; /* don't know this yet */
1003 /* always use a cluster. jrb
1005 MCLGET(m, M_DONTWAIT);
1006 if (m->m_flags & M_EXT) {
1007 m->m_len = MCLBYTES;
1011 if (wlhwrst(unit) != TRUE) {
1012 sc->hacr &= ~HACR_INTRON;
1013 CMD(unit); /* turn off interrupts */
1014 printf("wl%d read(): hwrst trouble.\n", unit);
1021 bytes_in_mbuf = m->m_len;
1022 mb_p = mtod(tm, u_char *);
1023 bytes = min(bytes_in_mbuf, bytes_in_msg);
1030 outw(PIOR1(base), rbd.buffer_addr);
1031 insw(PIOP1(base), mb_p, len/2);
1035 if (!(bytes_in_mbuf -= bytes)) {
1036 MGET(tm->m_next, M_DONTWAIT, MT_DATA);
1038 if (tm == (struct mbuf *)0) {
1040 printf("wl%d read(): No mbuf nth\n", unit);
1041 if (wlhwrst(unit) != TRUE) {
1042 sc->hacr &= ~HACR_INTRON;
1043 CMD(unit); /* turn off interrupts */
1044 printf("wl%d read(): hwrst trouble.\n", unit);
1050 bytes_in_mbuf = MLEN;
1051 mb_p = mtod(tm, u_char *);
1056 if (!(bytes_in_msg -= bytes)) {
1057 if (rbd.status & RBD_SW_EOF ||
1058 rbd.next_rbd_offset == I82586NULL) {
1062 outw(PIOR1(base), rbd.next_rbd_offset);
1063 insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1064 bytes_in_msg = rbd.status & RBD_SW_COUNT;
1067 rbd.buffer_addr += bytes;
1070 bytes = min(bytes_in_mbuf, bytes_in_msg);
1073 m->m_pkthdr.len = clen;
1076 * If hw is in promiscuous mode (note that I said hardware, not if
1077 * IFF_PROMISC is set in ifnet flags), then if this is a unicast
1078 * packet and the MAC dst is not us, drop it. This check in normally
1079 * inside ether_input(), but IFF_MULTI causes hw promisc without
1080 * a bpf listener, so this is wrong.
1081 * Greg Troxel <gdt@ir.bbn.com>, 1998-08-07
1084 * TBD: also discard packets where NWID does not match.
1085 * However, there does not appear to be a way to read the nwid
1086 * for a received packet. -gdt 1998-08-07
1089 #ifdef WL_USE_IFNET_PROMISC_CHECK /* not defined */
1090 (sc->wl_ac.ac_if.if_flags & (IFF_PROMISC|IFF_ALLMULTI))
1092 /* hw is in promisc mode if this is true */
1093 (sc->mode & (MOD_PROM | MOD_ENAL))
1096 (eh.ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
1097 bcmp(eh.ether_dhost, sc->wl_ac.ac_enaddr,
1098 sizeof(eh.ether_dhost)) != 0 ) {
1104 if (sc->wl_if.if_flags & IFF_DEBUG)
1105 printf("wl%d: wlrecv %d bytes\n", unit, clen);
1109 wl_cache_store(unit, base, &eh, m);
1113 * received packet is now in a chain of mbuf's. next step is
1114 * to pass the packet upwards.
1117 ether_input(&sc->wl_if, &eh, m);
1124 * This routine processes an ioctl request from the "if" layer
1127 * input : pointer the appropriate "if" struct, command, and data
1128 * output : based on command appropriate action is taken on the
1129 * WaveLAN board(s) or related structures
1130 * return : error is returned containing exit conditions
1134 wlioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1136 register struct ifreq *ifr = (struct ifreq *)data;
1137 int unit = ifp->if_unit;
1138 register struct wl_softc *sc = WLSOFTC(unit);
1139 short base = sc->base;
1141 int opri, error = 0;
1142 struct proc *p = curproc; /* XXX */
1143 int irq, irqval, i, isroot, size;
1149 if (sc->wl_if.if_flags & IFF_DEBUG)
1150 printf("wl%d: entered wlioctl()\n",unit);
1157 error = ether_ioctl(ifp, cmd, data);
1161 if (ifp->if_flags & IFF_ALLMULTI) {
1164 if (ifp->if_flags & IFF_PROMISC) {
1167 if(ifp->if_flags & IFF_LINK0) {
1171 * force a complete reset if the recieve multicast/
1172 * promiscuous mode changes so that these take
1173 * effect immediately.
1176 if (sc->mode != mode) {
1178 if (sc->flags & DSF_RUNNING) {
1179 sc->flags &= ~DSF_RUNNING;
1183 /* if interface is marked DOWN and still running then
1186 if ((ifp->if_flags & IFF_UP) == 0 && sc->flags & DSF_RUNNING) {
1187 printf("wl%d ioctl(): board is not running\n", unit);
1188 sc->flags &= ~DSF_RUNNING;
1189 sc->hacr &= ~HACR_INTRON;
1190 CMD(unit); /* turn off interrupts */
1192 /* else if interface is UP and RUNNING, start it
1194 else if (ifp->if_flags & IFF_UP && (sc->flags & DSF_RUNNING) == 0) {
1198 /* if WLDEBUG set on interface, then printf rf-modem regs
1200 if(ifp->if_flags & IFF_DEBUG)
1207 #if defined(__FreeBSD__) && __FreeBSD_version < 300000
1208 if (cmd == SIOCADDMULTI) {
1209 error = ether_addmulti(ifr, &sc->wl_ac);
1212 error = ether_delmulti(ifr, &sc->wl_ac);
1215 /* see if we should be in all multicast mode
1216 * note that 82586 cannot do that, must simulate with
1219 if ( check_allmulti(unit)) {
1220 ifp->if_flags |= IFF_ALLMULTI;
1221 sc->mode |= MOD_ENAL;
1222 sc->flags &= ~DSF_RUNNING;
1228 if (error == ENETRESET) {
1229 if(sc->flags & DSF_RUNNING) {
1230 sc->flags &= ~DSF_RUNNING;
1239 #endif /* MULTICAST */
1241 /* DEVICE SPECIFIC */
1244 /* copy the PSA out to the caller */
1246 /* pointer to buffer in user space */
1247 up = (void *)ifr->ifr_data;
1248 /* work out if they're root */
1249 isroot = (suser(p) == 0);
1251 for (i = 0; i < 0x40; i++) {
1252 /* don't hand the DES key out to non-root users */
1253 if ((i > WLPSA_DESKEY) && (i < (WLPSA_DESKEY + 8)) && !isroot)
1255 if (subyte((up + i), sc->psa[i]))
1261 /* copy the PSA in from the caller; we only copy _some_ values */
1264 if ((error = suser(p)))
1266 error = EINVAL; /* assume the worst */
1267 /* pointer to buffer in user space containing data */
1268 up = (void *)ifr->ifr_data;
1270 /* check validity of input range */
1271 for (i = 0; i < 0x40; i++)
1272 if (fubyte(up + i) < 0)
1275 /* check IRQ value */
1276 irqval = fubyte(up+WLPSA_IRQNO);
1277 for (irq = 15; irq >= 0; irq--)
1278 if(irqvals[irq] == irqval)
1280 if (irq == 0) /* oops */
1283 sc->psa[WLPSA_IRQNO] = irqval;
1286 for (i = 0; i < 6; i++)
1287 sc->psa[WLPSA_LOCALMAC+i] = fubyte(up+WLPSA_LOCALMAC+i);
1290 sc->psa[WLPSA_MACSEL] = fubyte(up+WLPSA_MACSEL);
1293 sc->psa[WLPSA_NWID] = fubyte(up+WLPSA_NWID);
1294 sc->psa[WLPSA_NWID+1] = fubyte(up+WLPSA_NWID+1);
1297 wlsetpsa(unit); /* update the PSA */
1301 /* get the current NWID out of the sc since we stored it there */
1303 ifr->ifr_data = (caddr_t) (sc->nwid[0] << 8 | sc->nwid[1]);
1308 * change the nwid dynamically. This
1309 * ONLY changes the radio modem and does not
1313 * 1. save in softc "soft registers"
1314 * 2. save in radio modem (MMC)
1318 if ((error = suser(p)))
1320 if (!(ifp->if_flags & IFF_UP)) {
1321 error = EIO; /* only allowed while up */
1324 * soft c nwid shadows radio modem setting
1326 sc->nwid[0] = (int)ifr->ifr_data >> 8;
1327 sc->nwid[1] = (int)ifr->ifr_data & 0xff;
1328 MMC_WRITE(MMC_NETW_ID_L,sc->nwid[1]);
1329 MMC_WRITE(MMC_NETW_ID_H,sc->nwid[0]);
1333 /* copy the EEPROM in 2.4 Gz WaveMODEM out to the caller */
1336 if ((error = suser(p)))
1338 /* pointer to buffer in user space */
1339 up = (void *)ifr->ifr_data;
1341 for (i=0x00; i<0x80; ++i) { /* 2.4 Gz: size of EEPROM */
1342 MMC_WRITE(MMC_EEADDR,i); /* 2.4 Gz: get frequency */
1343 MMC_WRITE(MMC_EECTRL, /* 2.4 Gz: EEPROM read */
1344 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: */
1345 DELAY(40); /* 2.4 Gz */
1346 if (subyte(up + 2*i , /* 2.4 Gz: pass low byte of */
1347 wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word */
1348 ) return(EFAULT); /* 2.4 Gz: */
1349 if (subyte(up + 2*i+1, /* 2.4 Gz: pass hi byte of */
1350 wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word */
1351 ) return(EFAULT); /* 2.4 Gz: */
1356 /* zero (Delete) the wl cache */
1359 if ((error = suser(p)))
1361 wl_cache_zero(unit);
1364 /* read out the number of used cache elements */
1366 ifr->ifr_data = (caddr_t) sc->w_sigitems;
1369 /* read out the wl cache */
1371 /* pointer to buffer in user space */
1372 up = (void *)ifr->ifr_data;
1373 cpt = (char *) &sc->w_sigcache[0];
1374 size = sc->w_sigitems * sizeof(struct w_sigcache);
1376 for (i = 0; i < size; i++) {
1377 if (subyte((up + i), *cpt++))
1393 * Called if the timer set in wlstart expires before an interrupt is received
1394 * from the wavelan. It seems to lose interrupts sometimes.
1395 * The watchdog routine gets called if the transmitter failed to interrupt
1397 * input : which board is timing out
1398 * output : board reset
1402 wlwatchdog(void *vsc)
1404 struct wl_softc *sc = vsc;
1405 int unit = sc->unit;
1407 log(LOG_ERR, "wl%d: wavelan device timeout on xmit\n", unit);
1408 sc->wl_ac.ac_if.if_oerrors++;
1415 * This function is the interrupt handler for the WaveLAN
1416 * board. This routine will be called whenever either a packet
1417 * is received, or a packet has successfully been transfered and
1418 * the unit is ready to transmit another packet.
1420 * input : board number that interrupted
1421 * output : either a packet is received, or a packet is transfered
1428 register struct wl_softc *sc = &wl_softc[unit];
1429 short base = sc->base;
1431 u_short int_type, int_type1;
1434 if (sc->wl_if.if_flags & IFF_DEBUG)
1435 printf("wl%d: wlintr() called\n",unit);
1438 if((int_type = inw(HASR(base))) & HASR_MMC_INTR) {
1439 /* handle interrupt from the modem management controler */
1440 /* This will clear the interrupt condition */
1441 (void) wlmmcread(base,MMC_DCE_STATUS); /* ignored for now */
1444 if(!(int_type & HASR_INTR)){ /* return if no interrupt from 82586 */
1445 /* commented out. jrb. it happens when reinit occurs
1446 printf("wlintr: int_type %x, dump follows\n", int_type);
1455 outw(PIOR0(base), OFFSET_SCB + 0); /* get scb status */
1456 int_type = (inw(PIOP0(base)) & SCB_SW_INT);
1457 if (int_type == 0) /* no interrupts left */
1460 int_type1 = wlack(unit); /* acknowledge interrupt(s) */
1461 /* make sure no bits disappeared (others may appear) */
1462 if ((int_type & int_type1) != int_type)
1463 printf("wlack() int bits disappeared : %04x != int_type %04x\n",
1464 int_type1, int_type);
1465 int_type = int_type1; /* go with the new status */
1469 if (int_type & SCB_SW_FR) {
1470 sc->wl_if.if_ipackets++;
1474 * receiver not ready
1476 if (int_type & SCB_SW_RNR) {
1477 sc->wl_if.if_ierrors++;
1479 if (sc->wl_if.if_flags & IFF_DEBUG)
1480 printf("wl%d intr(): receiver overrun! begin_fd = %x\n",
1481 unit, sc->begin_fd);
1488 if (int_type & SCB_SW_CNA) {
1490 * At present, we don't care about CNA's. We
1491 * believe they are a side effect of XMT.
1494 if (int_type & SCB_SW_CX) {
1496 * At present, we only request Interrupt for
1499 outw(PIOR1(base), OFFSET_CU); /* get command status */
1500 ac_status = inw(PIOP1(base));
1502 if (xmt_watch) { /* report some anomalies */
1504 if (sc->tbusy == 0) {
1505 printf("wl%d: xmt intr but not busy, CU %04x\n",
1508 if (ac_status == 0) {
1509 printf("wl%d: xmt intr but ac_status == 0\n", unit);
1511 if (ac_status & AC_SW_A) {
1512 printf("wl%d: xmt aborted\n",unit);
1515 if (ac_status & TC_CARRIER) {
1516 printf("wl%d: no carrier\n", unit);
1519 if (ac_status & TC_CLS) {
1520 printf("wl%d: no CTS\n", unit);
1522 if (ac_status & TC_DMA) {
1523 printf("wl%d: DMA underrun\n", unit);
1525 if (ac_status & TC_DEFER) {
1526 printf("wl%d: xmt deferred\n",unit);
1528 if (ac_status & TC_SQE) {
1529 printf("wl%d: heart beat\n", unit);
1531 if (ac_status & TC_COLLISION) {
1532 printf("wl%d: too many collisions\n", unit);
1535 /* if the transmit actually failed, or returned some status */
1536 if ((!(ac_status & AC_SW_OK)) || (ac_status & 0xfff)) {
1537 if (ac_status & (TC_COLLISION | TC_CLS | TC_DMA)) {
1538 sc->wl_if.if_oerrors++;
1540 /* count collisions */
1541 sc->wl_if.if_collisions += (ac_status & 0xf);
1542 /* if TC_COLLISION set and collision count zero, 16 collisions */
1543 if ((ac_status & 0x20) == 0x20) {
1544 sc->wl_if.if_collisions += 0x10;
1548 untimeout(wlwatchdog, sc, sc->watchdog_ch);
1549 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
1550 wlstart(&(sc->wl_if));
1559 * This routine is called by the interrupt handler to initiate a
1560 * packet transfer from the board to the "if" layer above this
1561 * driver. This routine checks if a buffer has been successfully
1562 * received by the WaveLAN. If so, the routine wlread is called
1563 * to do the actual transfer of the board data (including the
1564 * ethernet header) into a packet (consisting of an mbuf chain).
1566 * input : number of the board to check
1567 * output : if a packet is available, it is "sent up"
1573 register struct wl_softc *sc = WLSOFTC(unit);
1574 short base = sc->base;
1575 u_short fd_p, status, offset, link_offset;
1578 if (sc->wl_if.if_flags & IFF_DEBUG)
1579 printf("wl%d: entered wlrcv()\n",unit);
1581 for (fd_p = sc->begin_fd; fd_p != I82586NULL; fd_p = sc->begin_fd) {
1583 outw(PIOR0(base), fd_p + 0); /* address of status */
1584 status = inw(PIOP0(base));
1585 outw(PIOR1(base), fd_p + 4); /* address of link_offset */
1586 link_offset = inw(PIOP1(base));
1587 offset = inw(PIOP1(base)); /* rbd_offset */
1588 if (status == 0xffff || offset == 0xffff /*I82586NULL*/) {
1589 if (wlhwrst(unit) != TRUE)
1590 printf("wl%d rcv(): hwrst ffff trouble.\n", unit);
1592 } else if (status & AC_SW_C) {
1593 if (status == (RFD_DONE|RFD_RSC)) {
1596 if (sc->wl_if.if_flags & IFF_DEBUG)
1597 printf("wl%d RCV: RSC %x\n", unit, status);
1599 sc->wl_if.if_ierrors++;
1600 } else if (!(status & RFD_OK)) {
1601 printf("wl%d RCV: !OK %x\n", unit, status);
1602 sc->wl_if.if_ierrors++;
1603 } else if (status & 0xfff) { /* can't happen */
1604 printf("wl%d RCV: ERRs %x\n", unit, status);
1605 sc->wl_if.if_ierrors++;
1606 } else if (!wlread(unit, fd_p))
1609 if (!wlrequeue(unit, fd_p)) {
1610 /* abort on chain error */
1611 if (wlhwrst(unit) != TRUE)
1612 printf("wl%d rcv(): hwrst trouble.\n", unit);
1615 sc->begin_fd = link_offset;
1626 * This routine puts rbd's used in the last receive back onto the
1627 * free list for the next receive.
1631 wlrequeue(int unit, u_short fd_p)
1633 register struct wl_softc *sc = WLSOFTC(unit);
1634 short base = sc->base;
1636 u_short l_rbdp, f_rbdp, rbd_offset;
1638 outw(PIOR0(base), fd_p + 6);
1639 rbd_offset = inw(PIOP0(base));
1640 if ((f_rbdp = rbd_offset) != I82586NULL) {
1643 outw(PIOR0(base), l_rbdp + 0); /* address of status */
1644 if(inw(PIOP0(base)) & RBD_SW_EOF)
1646 outw(PIOP0(base), 0);
1647 outw(PIOR0(base), l_rbdp + 2); /* next_rbd_offset */
1648 if((l_rbdp = inw(PIOP0(base))) == I82586NULL)
1651 outw(PIOP0(base), 0);
1652 outw(PIOR0(base), l_rbdp + 2); /* next_rbd_offset */
1653 outw(PIOP0(base), I82586NULL);
1654 outw(PIOR0(base), l_rbdp + 8); /* address of size */
1655 outw(PIOP0(base), inw(PIOP0(base)) | AC_CW_EL);
1656 outw(PIOR0(base), sc->end_rbd + 2);
1657 outw(PIOP0(base), f_rbdp); /* end_rbd->next_rbd_offset */
1658 outw(PIOR0(base), sc->end_rbd + 8); /* size */
1659 outw(PIOP0(base), inw(PIOP0(base)) & ~AC_CW_EL);
1660 sc->end_rbd = l_rbdp;
1664 fd.command = AC_CW_EL;
1665 fd.link_offset = I82586NULL;
1666 fd.rbd_offset = I82586NULL;
1667 outw(PIOR1(base), fd_p);
1668 outsw(PIOP1(base), &fd, 8/2);
1670 outw(PIOR1(base), sc->end_fd + 2); /* addr of command */
1671 outw(PIOP1(base), 0); /* command = 0 */
1672 outw(PIOP1(base), fd_p); /* end_fd->link_offset = fd_p */
1679 static int xmt_debug = 0;
1680 #endif /* WLDEBUG */
1685 * This routine fills in the appropriate registers and memory
1686 * locations on the WaveLAN board and starts the board off on
1689 * input : board number of interest, and a pointer to the mbuf
1690 * output : board memory and registers are set for xfer and attention
1694 wlxmt(int unit, struct mbuf *m)
1696 register struct wl_softc *sc = WLSOFTC(unit);
1697 register u_short xmtdata_p = OFFSET_TBUF;
1698 register u_short xmtshort_p;
1699 struct mbuf *tm_p = m;
1700 register struct ether_header *eh_p = mtod(m, struct ether_header *);
1701 u_char *mb_p = mtod(m, u_char *) + sizeof(struct ether_header);
1702 u_short count = m->m_len - sizeof(struct ether_header);
1704 u_short tbd_p = OFFSET_TBD;
1705 u_short len, clen = 0;
1706 short base = sc->base;
1710 if (sc->wl_if.if_flags & IFF_DEBUG)
1711 printf("wl%d: entered wlxmt()\n",unit);
1715 cb.ac_command = (AC_CW_EL|AC_TRANSMIT|AC_CW_I);
1716 cb.ac_link_offset = I82586NULL;
1717 outw(PIOR1(base), OFFSET_CU);
1718 outsw(PIOP1(base), &cb, 6/2);
1719 outw(PIOP1(base), OFFSET_TBD); /* cb.cmd.transmit.tbd_offset */
1720 outsw(PIOP1(base), eh_p->ether_dhost, WAVELAN_ADDR_SIZE/2);
1721 outw(PIOP1(base), eh_p->ether_type);
1724 if (sc->wl_if.if_flags & IFF_DEBUG) {
1726 printf("XMT mbuf: L%d @%p ", count, (void *)mb_p);
1727 printf("ether type %x\n", eh_p->ether_type);
1730 #endif /* WLDEBUG */
1731 outw(PIOR0(base), OFFSET_TBD);
1732 outw(PIOP0(base), 0); /* act_count */
1733 outw(PIOR1(base), OFFSET_TBD + 4);
1734 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1735 outw(PIOP1(base), 0); /* buffer_base */
1738 if (clen + count > WAVELAN_MTU)
1744 outw(PIOR1(base), xmtdata_p);
1745 outsw(PIOP1(base), mb_p, len/2);
1747 outw(PIOR0(base), tbd_p); /* address of act_count */
1748 outw(PIOP0(base), inw(PIOP0(base)) + count);
1750 if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1753 /* go to the next descriptor */
1754 outw(PIOR0(base), tbd_p + 2);
1755 tbd_p += sizeof (tbd_t);
1756 outw(PIOP0(base), tbd_p); /* next_tbd_offset */
1757 outw(PIOR0(base), tbd_p);
1758 outw(PIOP0(base), 0); /* act_count */
1759 outw(PIOR1(base), tbd_p + 4);
1760 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1761 outw(PIOP1(base), 0); /* buffer_base */
1762 /* at the end -> coallesce remaining mbufs */
1763 if (tbd_p == OFFSET_TBD + (N_TBD-1) * sizeof (tbd_t)) {
1764 wlsftwsleaze(&count, &mb_p, &tm_p, unit);
1767 /* next mbuf short -> coallesce as needed */
1768 if ( (tm_p->m_next == (struct mbuf *) 0) ||
1769 #define HDW_THRESHOLD 55
1770 tm_p->m_len > HDW_THRESHOLD)
1773 wlhdwsleaze(&count, &mb_p, &tm_p, unit);
1777 } else if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1779 count = tm_p->m_len;
1780 mb_p = mtod(tm_p, u_char *);
1782 if (sc->wl_if.if_flags & IFF_DEBUG)
1784 printf("mbuf+ L%d @%p ", count, (void *)mb_p);
1785 #endif /* WLDEBUG */
1788 if (sc->wl_if.if_flags & IFF_DEBUG)
1790 printf("CLEN = %d\n", clen);
1791 #endif /* WLDEBUG */
1792 outw(PIOR0(base), tbd_p);
1793 if (clen < ETHERMIN) {
1794 outw(PIOP0(base), inw(PIOP0(base)) + ETHERMIN - clen);
1795 outw(PIOR1(base), xmtdata_p);
1796 for (xmtshort_p = xmtdata_p; clen < ETHERMIN; clen += 2)
1797 outw(PIOP1(base), 0);
1799 outw(PIOP0(base), inw(PIOP0(base)) | TBD_SW_EOF);
1800 outw(PIOR0(base), tbd_p + 2);
1801 outw(PIOP0(base), I82586NULL);
1803 if (sc->wl_if.if_flags & IFF_DEBUG) {
1809 #endif /* WLDEBUG */
1811 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
1813 * wait for 586 to clear previous command, complain if it takes
1816 for (spin = 1;;spin = (spin + 1) % 10000) {
1817 if (inw(PIOP0(base)) == 0) { /* it's done, we can go */
1820 if ((spin == 0) && xmt_watch) { /* not waking up, and we care */
1821 printf("wl%d: slow accepting xmit\n",unit);
1824 outw(PIOP0(base), SCB_CU_STRT); /* new command */
1825 SET_CHAN_ATTN(unit);
1830 * Pause to avoid transmit overrun problems.
1831 * The required delay tends to vary with platform type, and may be
1832 * related to interrupt loss.
1834 if (wl_xmit_delay) {
1835 DELAY(wl_xmit_delay);
1843 * This function builds the linear linked lists of fd's and
1844 * rbd's. Based on page 4-32 of 1986 Intel microcom handbook.
1850 register struct wl_softc *sc = WLSOFTC(unit);
1851 short base = sc->base;
1854 u_short fd_p = OFFSET_RU;
1855 u_short rbd_p = OFFSET_RBD;
1858 sc->begin_fd = fd_p;
1859 for(i = 0; i < N_FD; i++) {
1862 fd.link_offset = fd_p + sizeof(fd_t);
1863 fd.rbd_offset = I82586NULL;
1864 outw(PIOR1(base), fd_p);
1865 outsw(PIOP1(base), &fd, 8/2);
1866 fd_p = fd.link_offset;
1868 fd_p -= sizeof(fd_t);
1870 outw(PIOR1(base), fd_p + 2);
1871 outw(PIOP1(base), AC_CW_EL); /* command */
1872 outw(PIOP1(base), I82586NULL); /* link_offset */
1875 outw(PIOR0(base), fd_p + 6); /* address of rbd_offset */
1876 outw(PIOP0(base), rbd_p);
1877 outw(PIOR1(base), rbd_p);
1878 for(i = 0; i < N_RBD; i++) {
1880 rbd.buffer_addr = rbd_p + sizeof(rbd_t) + 2;
1881 rbd.buffer_base = 0;
1882 rbd.size = RCVBUFSIZE;
1884 rbd_p += sizeof(ru_t);
1885 rbd.next_rbd_offset = rbd_p;
1887 rbd.next_rbd_offset = I82586NULL;
1888 rbd.size |= AC_CW_EL;
1889 sc->end_rbd = rbd_p;
1891 outsw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1892 outw(PIOR1(base), rbd_p);
1894 return sc->begin_fd;
1900 * This routine starts the receive unit running. First checks if the
1901 * board is actually ready, then the board is instructed to receive
1908 register struct wl_softc *sc = WLSOFTC(unit);
1909 short base = sc->base;
1913 if (sc->wl_if.if_flags & IFF_DEBUG)
1914 printf("wl%d: entered wlrustrt()\n",unit);
1916 outw(PIOR0(base), OFFSET_SCB);
1917 if (inw(PIOP0(base)) & SCB_RUS_READY){
1918 printf("wlrustrt: RUS_READY\n");
1922 outw(PIOR0(base), OFFSET_SCB + 2);
1923 outw(PIOP0(base), SCB_RU_STRT); /* command */
1924 rfa = wlbldru(unit);
1925 outw(PIOR0(base), OFFSET_SCB + 6); /* address of scb_rfa_offset */
1926 outw(PIOP0(base), rfa);
1928 SET_CHAN_ATTN(unit);
1935 * This routine does a 586 op-code number 7, and obtains the
1936 * diagnose status for the WaveLAN.
1942 register struct wl_softc *sc = WLSOFTC(unit);
1943 short base = sc->base;
1947 if (sc->wl_if.if_flags & IFF_DEBUG)
1948 printf("wl%d: entered wldiag()\n",unit);
1950 outw(PIOR0(base), OFFSET_SCB);
1951 status = inw(PIOP0(base));
1952 if (status & SCB_SW_INT) {
1953 /* state is 2000 which seems ok
1954 printf("wl%d diag(): unexpected initial state %\n",
1955 unit, inw(PIOP0(base)));
1959 outw(PIOR1(base), OFFSET_CU);
1960 outw(PIOP1(base), 0); /* ac_status */
1961 outw(PIOP1(base), AC_DIAGNOSE|AC_CW_EL);/* ac_command */
1962 if(wlcmd(unit, "diag()") == 0)
1964 outw(PIOR0(base), OFFSET_CU);
1965 if (inw(PIOP0(base)) & 0x0800) {
1966 printf("wl%d: i82586 Self Test failed!\n", unit);
1975 * This routine does a standard config of the WaveLAN board.
1981 configure_t configure;
1982 register struct wl_softc *sc = WLSOFTC(unit);
1983 short base = sc->base;
1986 #if defined(__FreeBSD__) && __FreeBSD_version >= 300000
1987 struct ifmultiaddr *ifma;
1990 struct ether_multi *enm;
1991 struct ether_multistep step;
1994 #endif /* MULTICAST */
1997 if (sc->wl_if.if_flags & IFF_DEBUG)
1998 printf("wl%d: entered wlconfig()\n",unit);
2000 outw(PIOR0(base), OFFSET_SCB);
2001 if (inw(PIOP0(base)) & SCB_SW_INT) {
2003 printf("wl%d config(): unexpected initial state %x\n",
2004 unit, inw(PIOP0(base)));
2009 outw(PIOR1(base), OFFSET_CU);
2010 outw(PIOP1(base), 0); /* ac_status */
2011 outw(PIOP1(base), AC_CONFIGURE|AC_CW_EL); /* ac_command */
2014 configure.fifolim_bytecnt = 0x080c;
2015 configure.addrlen_mode = 0x0600;
2016 configure.linprio_interframe = 0x2060;
2017 configure.slot_time = 0xf200;
2018 configure.hardware = 0x0008; /* tx even w/o CD */
2019 configure.min_frame_len = 0x0040;
2021 /* This is the configuration block suggested by Marc Meertens
2022 * <mmeerten@obelix.utrecht.NCR.COM> in an e-mail message to John
2023 * Ioannidis on 10 Nov 92.
2025 configure.fifolim_bytecnt = 0x040c;
2026 configure.addrlen_mode = 0x0600;
2027 configure.linprio_interframe = 0x2060;
2028 configure.slot_time = 0xf000;
2029 configure.hardware = 0x0008; /* tx even w/o CD */
2030 configure.min_frame_len = 0x0040;
2033 * below is the default board configuration from p2-28 from 586 book
2035 configure.fifolim_bytecnt = 0x080c;
2036 configure.addrlen_mode = 0x2600;
2037 configure.linprio_interframe = 0x7820; /* IFS=120, ACS=2 */
2038 configure.slot_time = 0xf00c; /* slottime=12 */
2039 configure.hardware = 0x0008; /* tx even w/o CD */
2040 configure.min_frame_len = 0x0040;
2042 if(sc->mode & (MOD_PROM | MOD_ENAL)) {
2043 configure.hardware |= 1;
2045 outw(PIOR1(base), OFFSET_CU + 6);
2046 outsw(PIOP1(base), &configure, sizeof(configure_t)/2);
2048 if(wlcmd(unit, "config()-configure") == 0)
2051 outw(PIOR1(base), OFFSET_CU);
2052 outw(PIOP1(base), 0); /* ac_status */
2053 outw(PIOP1(base), AC_MCSETUP|AC_CW_EL); /* ac_command */
2054 outw(PIOR1(base), OFFSET_CU + 8);
2055 #if defined(__FreeBSD__) && __FreeBSD_version >= 300000
2056 for (ifma = sc->wl_if.if_multiaddrs.lh_first; ifma;
2057 ifma = ifma->ifma_link.le_next) {
2058 if (ifma->ifma_addr->sa_family != AF_LINK)
2061 addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
2062 outw(PIOP1(base), addrp[0] + (addrp[1] << 8));
2063 outw(PIOP1(base), addrp[2] + (addrp[3] << 8));
2064 outw(PIOP1(base), addrp[4] + (addrp[5] << 8));
2068 ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2069 while (enm != NULL) {
2070 unsigned int lo, hi;
2071 /* break if setting a multicast range, else we would crash */
2072 if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2075 lo = (enm->enm_addrlo[3] << 16) + (enm->enm_addrlo[4] << 8)
2076 + enm->enm_addrlo[5];
2077 hi = (enm->enm_addrhi[3] << 16) + (enm->enm_addrhi[4] << 8)
2078 + enm->enm_addrhi[5];
2080 outw(PIOP1(base),enm->enm_addrlo[0] +
2081 (enm->enm_addrlo[1] << 8));
2082 outw(PIOP1(base),enm->enm_addrlo[2] +
2083 ((lo >> 8) & 0xff00));
2084 outw(PIOP1(base), ((lo >> 8) & 0xff) +
2085 ((lo << 8) & 0xff00));
2086 /* #define MCASTDEBUG */
2088 printf("mcast_addr[%d,%d,%d] %x %x %x %x %x %x\n", lo, hi, cnt,
2094 enm->enm_addrlo[5]);
2099 ETHER_NEXT_MULTI(step, enm);
2102 outw(PIOR1(base), OFFSET_CU + 6); /* mc-cnt */
2103 outw(PIOP1(base), cnt * WAVELAN_ADDR_SIZE);
2104 if(wlcmd(unit, "config()-mcaddress") == 0)
2106 #endif /* MULTICAST */
2108 outw(PIOR1(base), OFFSET_CU);
2109 outw(PIOP1(base), 0); /* ac_status */
2110 outw(PIOP1(base), AC_IASETUP|AC_CW_EL); /* ac_command */
2111 outw(PIOR1(base), OFFSET_CU + 6);
2112 outsw(PIOP1(base), sc->wl_addr, WAVELAN_ADDR_SIZE/2);
2114 if(wlcmd(unit, "config()-address") == 0)
2125 * Set channel attention bit and busy wait until command has
2126 * completed. Then acknowledge the command completion.
2129 wlcmd(int unit, char *str)
2131 register struct wl_softc *sc = WLSOFTC(unit);
2132 short base = sc->base;
2135 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
2136 outw(PIOP0(base), SCB_CU_STRT);
2138 SET_CHAN_ATTN(unit);
2140 outw(PIOR0(base), OFFSET_CU);
2141 for(i = 0; i < 0xffff; i++)
2142 if (inw(PIOP0(base)) & AC_SW_C)
2144 if (i == 0xffff || !(inw(PIOP0(base)) & AC_SW_OK)) {
2145 printf("wl%d: %s failed; status = %d, inw = %x, outw = %x\n",
2146 unit, str, inw(PIOP0(base)) & AC_SW_OK, inw(PIOP0(base)), inw(PIOR0(base)));
2147 outw(PIOR0(base), OFFSET_SCB);
2148 printf("scb_status %x\n", inw(PIOP0(base)));
2149 outw(PIOR0(base), OFFSET_SCB+2);
2150 printf("scb_command %x\n", inw(PIOP0(base)));
2151 outw(PIOR0(base), OFFSET_SCB+4);
2152 printf("scb_cbl %x\n", inw(PIOP0(base)));
2153 outw(PIOR0(base), OFFSET_CU+2);
2154 printf("cu_cmd %x\n", inw(PIOP0(base)));
2158 outw(PIOR0(base), OFFSET_SCB);
2159 if ((inw(PIOP0(base)) & SCB_SW_INT) && (inw(PIOP0(base)) != SCB_SW_CNA)) {
2161 printf("wl%d %s: unexpected final state %x\n",
2162 unit, str, inw(PIOP0(base)));
2170 * wlack: if the 82596 wants attention because it has finished
2171 * sending or receiving a packet, acknowledge its desire and
2172 * return bits indicating the kind of attention. wlack() returns
2173 * these bits so that the caller can service exactly the
2174 * conditions that wlack() acknowledged.
2180 register u_short cmd;
2181 register struct wl_softc *sc = WLSOFTC(unit);
2182 short base = sc->base;
2184 outw(PIOR1(base), OFFSET_SCB);
2185 if(!(cmd = (inw(PIOP1(base)) & SCB_SW_INT)))
2188 if (sc->wl_if.if_flags & IFF_DEBUG)
2189 printf("wl%d: doing a wlack()\n",unit);
2191 outw(PIOP1(base), cmd);
2192 SET_CHAN_ATTN(unit);
2193 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
2194 for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
2196 printf("wl%d wlack(): board not accepting command.\n", unit);
2203 register struct wl_softc *sc = WLSOFTC(unit);
2204 short base = sc->base;
2205 u_short tbd_p = OFFSET_TBD;
2211 outw(PIOR1(base), tbd_p);
2212 insw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
2213 sum += (tbd.act_count & ~TBD_SW_EOF);
2214 printf("%d: addr %x, count %d (%d), next %x, base %x\n",
2215 i++, tbd.buffer_addr,
2216 (tbd.act_count & ~TBD_SW_EOF), sum,
2217 tbd.next_tbd_offset, tbd.buffer_base);
2218 if (tbd.act_count & TBD_SW_EOF)
2220 tbd_p = tbd.next_tbd_offset;
2225 wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2227 struct mbuf *tm_p = *tm_pp;
2228 u_char *mb_p = *mb_pp;
2234 * can we get a run that will be coallesced or
2235 * that terminates before breaking
2238 count += tm_p->m_len;
2239 if (tm_p->m_len & 1)
2241 } while ((tm_p = tm_p->m_next) != (struct mbuf *)0);
2242 if ( (tm_p == (struct mbuf *)0) ||
2243 count > HDW_THRESHOLD) {
2244 *countp = (*tm_pp)->m_len;
2245 *mb_pp = mtod((*tm_pp), u_char *);
2249 /* we need to copy */
2253 cp = (u_char *) t_packet;
2255 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2257 if (count > HDW_THRESHOLD)
2260 if (tm_p->m_next == (struct mbuf *)0)
2262 tm_p = tm_p->m_next;
2265 *mb_pp = (u_char *) t_packet;
2272 wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2274 struct mbuf *tm_p = *tm_pp;
2276 u_char *cp = (u_char *) t_packet;
2279 /* we need to copy */
2281 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2284 if (tm_p->m_next == (struct mbuf *)0)
2286 tm_p = tm_p->m_next;
2290 *mb_pp = (u_char *) t_packet;
2298 register struct wl_softc *sc = WLSOFTC(unit);
2299 short base = sc->base;
2302 printf("wl%d: DCE_STATUS: 0x%x, ", unit,
2303 wlmmcread(base,MMC_DCE_STATUS) & 0x0f);
2304 tmp = wlmmcread(base,MMC_CORRECT_NWID_H) << 8;
2305 tmp |= wlmmcread(base,MMC_CORRECT_NWID_L);
2306 printf("Correct NWID's: %d, ", tmp);
2307 tmp = wlmmcread(base,MMC_WRONG_NWID_H) << 8;
2308 tmp |= wlmmcread(base,MMC_WRONG_NWID_L);
2309 printf("Wrong NWID's: %d\n", tmp);
2310 printf("THR_PRE_SET: 0x%x, ", wlmmcread(base,MMC_THR_PRE_SET));
2311 printf("SIGNAL_LVL: %d, SILENCE_LVL: %d\n",
2312 wlmmcread(base,MMC_SIGNAL_LVL),
2313 wlmmcread(base,MMC_SILENCE_LVL));
2314 printf("SIGN_QUAL: 0x%x, NETW_ID: %x:%x, DES: %d\n",
2315 wlmmcread(base,MMC_SIGN_QUAL),
2316 wlmmcread(base,MMC_NETW_ID_H),
2317 wlmmcread(base,MMC_NETW_ID_L),
2318 wlmmcread(base,MMC_DES_AVAIL));
2322 wlmmcread(u_int base, u_short reg)
2324 while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2325 outw(MMCR(base),reg << 1);
2326 while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2327 return (u_short)inw(MMCR(base)) >> 8;
2333 MMC_WRITE(MMC_FREEZE,1);
2335 * SNR retrieval procedure :
2337 * read signal level : wlmmcread(base, MMC_SIGNAL_LVL);
2338 * read silence level : wlmmcread(base, MMC_SILENCE_LVL);
2340 MMC_WRITE(MMC_FREEZE,0);
2342 * SNR is signal:silence ratio.
2349 ** Reads the psa for the wavelan at (base) into (buf)
2352 wlgetpsa(int base, u_char *buf)
2356 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2357 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2359 for (i = 0; i < 0x40; i++) {
2360 outw(PIOR2(base), i);
2361 buf[i] = inb(PIOP2(base));
2363 PCMD(base, HACR_DEFAULT);
2364 PCMD(base, HACR_DEFAULT);
2370 ** Writes the psa for wavelan (unit) from the softc back to the
2371 ** board. Updates the CRC and sets the CRC OK flag.
2373 ** Do not call this when the board is operating, as it doesn't
2374 ** preserve the hacr.
2379 register struct wl_softc *sc = WLSOFTC(unit);
2380 short base = sc->base;
2384 crc = wlpsacrc(sc->psa); /* calculate CRC of PSA */
2385 sc->psa[WLPSA_CRCLOW] = crc & 0xff;
2386 sc->psa[WLPSA_CRCHIGH] = (crc >> 8) & 0xff;
2387 sc->psa[WLPSA_CRCOK] = 0x55; /* default to 'bad' until programming complete */
2389 oldpri = splimp(); /* ick, long pause */
2391 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2392 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2394 for (i = 0; i < 0x40; i++) {
2396 outw(PIOR2(base),i); /* write param memory */
2398 outb(PIOP2(base), sc->psa[i]);
2401 outw(PIOR2(base),WLPSA_CRCOK); /* update CRC flag*/
2403 sc->psa[WLPSA_CRCOK] = 0xaa; /* OK now */
2404 outb(PIOP2(base), 0xaa); /* all OK */
2407 PCMD(base, HACR_DEFAULT);
2408 PCMD(base, HACR_DEFAULT);
2414 ** CRC routine provided by Christopher Giordano <cgiordan@gdeb.com>,
2415 ** from original code by Tomi Mikkonen (tomitm@remedy.fi)
2418 static u_int crc16_table[16] = {
2419 0x0000, 0xCC01, 0xD801, 0x1400,
2420 0xF001, 0x3C00, 0x2800, 0xE401,
2421 0xA001, 0x6C00, 0x7800, 0xB401,
2422 0x5000, 0x9C01, 0x8801, 0x4400
2426 wlpsacrc(u_char *buf)
2431 for (i = 0; i < 0x3d; i++, buf++) {
2433 r1 = crc16_table[crc & 0xF];
2434 crc = (crc >> 4) & 0x0FFF;
2435 crc = crc ^ r1 ^ crc16_table[*buf & 0xF];
2438 r1 = crc16_table[crc & 0xF];
2439 crc = (crc >> 4) & 0x0FFF;
2440 crc = crc ^ r1 ^ crc16_table[(*buf >> 4) & 0xF];
2449 * take input packet and cache various radio hw characteristics
2450 * indexed by MAC address.
2452 * Some things to think about:
2453 * note that no space is malloced.
2454 * We might hash the mac address if the cache were bigger.
2455 * It is not clear that the cache is big enough.
2456 * It is also not clear how big it should be.
2457 * The cache is IP-specific. We don't care about that as
2458 * we want it to be IP-specific.
2459 * The last N recv. packets are saved. This will tend
2460 * to reward agents and mobile hosts that beacon.
2461 * That is probably fine for mobile ip.
2464 /* globals for wavelan signal strength cache */
2465 /* this should go into softc structure above.
2468 /* set true if you want to limit cache items to broadcast/mcast
2469 * only packets (not unicast)
2471 static int wl_cache_mcastonly = 1;
2472 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_mcastonly, CTLFLAG_RW,
2473 &wl_cache_mcastonly, 0, "");
2475 /* set true if you want to limit cache items to IP packets only
2477 static int wl_cache_iponly = 1;
2478 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_iponly, CTLFLAG_RW,
2479 &wl_cache_iponly, 0, "");
2481 /* zero out the cache
2484 wl_cache_zero(int unit)
2486 register struct wl_softc *sc = WLSOFTC(unit);
2488 bzero(&sc->w_sigcache[0], sizeof(struct w_sigcache) * MAXCACHEITEMS);
2490 sc->w_nextcache = 0;
2491 sc->w_wrapindex = 0;
2494 /* store hw signal info in cache.
2495 * index is MAC address, but an ip src gets stored too
2496 * There are two filters here controllable via sysctl:
2497 * throw out unicast (on by default, but can be turned off)
2498 * throw out non-ip (on by default, but can be turned off)
2501 void wl_cache_store (int unit, int base, struct ether_header *eh,
2504 struct ip *ip = NULL; /* Avoid GCC warning */
2506 int signal, silence;
2507 int w_insertcache; /* computed index for cache entry storage */
2508 register struct wl_softc *sc = WLSOFTC(unit);
2509 int ipflag = wl_cache_iponly;
2513 * 2. configurable filter to throw out unicast packets,
2514 * keep multicast only.
2518 /* reject if not IP packet
2520 if ( wl_cache_iponly && (ntohs(eh->ether_type) != 0x800)) {
2524 /* check if broadcast or multicast packet. we toss
2527 if (wl_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
2531 /* find the ip header. we want to store the ip_src
2532 * address. use the mtod macro(in mbuf.h)
2533 * to typecast m to struct ip *
2536 ip = mtod(m, struct ip *);
2539 /* do a linear search for a matching MAC address
2540 * in the cache table
2541 * . MAC address is 6 bytes,
2542 * . var w_nextcache holds total number of entries already cached
2544 for(i = 0; i < sc->w_nextcache; i++) {
2545 if (! bcmp(eh->ether_shost, sc->w_sigcache[i].macsrc, 6 )) {
2547 * so we already have this entry,
2548 * update the data, and LRU age
2554 /* did we find a matching mac address?
2555 * if yes, then overwrite a previously existing cache entry
2557 if (i < sc->w_nextcache ) {
2560 /* else, have a new address entry,so
2561 * add this new entry,
2562 * if table full, then we need to replace entry
2566 /* check for space in cache table
2567 * note: w_nextcache also holds number of entries
2568 * added in the cache table
2570 if ( sc->w_nextcache < MAXCACHEITEMS ) {
2571 w_insertcache = sc->w_nextcache;
2573 sc->w_sigitems = sc->w_nextcache;
2575 /* no space found, so simply wrap with wrap index
2576 * and "zap" the next entry
2579 if (sc->w_wrapindex == MAXCACHEITEMS) {
2580 sc->w_wrapindex = 0;
2582 w_insertcache = sc->w_wrapindex++;
2586 /* invariant: w_insertcache now points at some slot
2589 if (w_insertcache < 0 || w_insertcache >= MAXCACHEITEMS) {
2591 "wl_cache_store, bad index: %d of [0..%d], gross cache error\n",
2592 w_insertcache, MAXCACHEITEMS);
2596 /* store items in cache
2599 * .signal (0..63) ,silence (0..63) ,quality (0..15)
2602 sc->w_sigcache[w_insertcache].ipsrc = ip->ip_src.s_addr;
2604 bcopy( eh->ether_shost, sc->w_sigcache[w_insertcache].macsrc, 6);
2605 signal = sc->w_sigcache[w_insertcache].signal = wlmmcread(base, MMC_SIGNAL_LVL) & 0x3f;
2606 silence = sc->w_sigcache[w_insertcache].silence = wlmmcread(base, MMC_SILENCE_LVL) & 0x3f;
2607 sc->w_sigcache[w_insertcache].quality = wlmmcread(base, MMC_SIGN_QUAL) & 0x0f;
2609 sc->w_sigcache[w_insertcache].snr =
2612 sc->w_sigcache[w_insertcache].snr = 0;
2616 #endif /* WLCACHE */
2619 * determine if in all multicast mode or not
2621 * returns: 1 if IFF_ALLMULTI should be set
2626 #if defined(__FreeBSD__) && __FreeBSD_version < 300000 /* not required */
2628 check_allmulti(int unit)
2630 register struct wl_softc *sc = WLSOFTC(unit);
2631 short base = sc->base;
2632 struct ether_multi *enm;
2633 struct ether_multistep step;
2635 ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2636 while (enm != NULL) {
2637 unsigned int lo, hi;
2639 printf("enm_addrlo %x:%x:%x:%x:%x:%x\n", enm->enm_addrlo[0], enm->enm_addrlo[1],
2640 enm->enm_addrlo[2], enm->enm_addrlo[3], enm->enm_addrlo[4],
2641 enm->enm_addrlo[5]);
2642 printf("enm_addrhi %x:%x:%x:%x:%x:%x\n", enm->enm_addrhi[0], enm->enm_addrhi[1],
2643 enm->enm_addrhi[2], enm->enm_addrhi[3], enm->enm_addrhi[4],
2644 enm->enm_addrhi[5]);
2646 if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2649 ETHER_NEXT_MULTI(step, enm);