3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions
6 * 1. Redistributions of source code must retain all copyright
7 * notices, this list of conditions and the following disclaimer.
8 * 2. The names of the authors may not be used to endorse or promote products
9 * derived from this software withough specific prior written permission
11 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
12 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
13 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
14 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
15 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
16 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
17 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
18 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
19 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
20 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 * if_wl.c - original MACH, then BSDI ISA wavelan driver
25 * ported to mach by Anders Klemets
26 * to BSDI by Robert Morris
27 * to FreeBSD by Jim Binkley
28 * to FreeBSD 2.2+ by Michael Smith
31 * Changed interface to match 2.1-2.2 differences.
32 * Implement IRQ selection logic in wlprobe()
33 * Implement PSA updating.
34 * Pruned heading comments for relevance.
35 * Ripped out all the 'interface counters' cruft.
36 * Cut the missing-interrupt timer back to 100ms.
38 * now supports all multicast mode (mrouted will work),
39 * but unfortunately must do that by going into promiscuous mode
40 * NWID sysctl added so that normally promiscuous mode is NWID-specific
41 * but can be made NWID-inspecific
45 * Ported to FreeBSD, got promiscuous mode working with bpfs,
46 * and rewired timer routine. The i82586 will hang occasionally on output
47 * and the watchdog timer will kick it if so and log an entry.
48 * 2 second timeout there. Apparently the chip loses an interrupt.
49 * Code borrowed from if_ie.c for watchdog timer.
51 * The wavelan card is a 2mbit radio modem that emulates ethernet;
52 * i.e., it uses MAC addresses. This should not be a surprise since
53 * it uses an ethernet controller as a major hw item.
54 * It can broadcast, unicast or apparently multicast in a base cell
55 * using a omni-directional antennae that is
56 * about 800 feet around the base cell barring walls and metal.
57 * With directional antennae, it can be used point to point over a mile
58 * or so apparently (haven't tried that).
60 * There are ISA and pcmcia versions (not supported by this code).
61 * The ISA card has an Intel 82586 lan controller on it. It consists
62 * of 2 pieces of hw, the lan controller (intel) and a radio-modem.
63 * The latter has an extra set of controller registers that has nothing
64 * to do with the i82586 and allows setting and monitoring of radio
65 * signal strength, etc. There is a nvram area called the PSA that
66 * contains a number of setup variables including the IRQ and so-called
67 * NWID or Network ID. The NWID must be set the same for all radio
68 * cards to communicate (unless you are using the ATT/NCR roaming feature
69 * with their access points. There is no support for that here. Roaming
70 * involves a link-layer beacon sent out from the access points. End
71 * stations monitor the signal strength and only use the strongest
72 * access point). This driver assumes that the base ISA port, IRQ,
73 * and NWID are first set in nvram via the dos-side "instconf.exe" utility
74 * supplied with the card. This driver takes the ISA port from
75 * the kernel configuration setup, and then determines the IRQ either
76 * from the kernel config (if an explicit IRQ is set) or from the
77 * PSA on the card if not.
78 * The hw also magically just uses the IRQ set in the nvram.
79 * The NWID is used magically as well by the radio-modem
80 * to determine which packets to keep or throw out.
84 * device wl0 at isa? port 0x300 net irq ?
87 * 1. WLDEBUG. (off) - if turned on enables IFF_DEBUG set via ifconfig debug
88 * 2. MULTICAST (on) - turned on and works up to and including mrouted
89 * 3. WLCACHE (off) - define to turn on a signal strength
90 * (and other metric) cache that is indexed by sender MAC address.
91 * Apps can read this out to learn the remote signal strength of a
92 * sender. Note that it has a switch so that it only stores
93 * broadcast/multicast senders but it could be set to store unicast
94 * too only. Size is hardwired in if_wl_wavelan.h
96 * one further note: promiscuous mode is a curious thing. In this driver,
97 * promiscuous mode apparently CAN catch ALL packets and ignore the NWID
98 * setting. This is probably more useful in a sense (for snoopers) if
99 * you are interested in all traffic as opposed to if you are interested
100 * in just your own. There is a driver specific sysctl to turn promiscuous
101 * from just promiscuous to wildly promiscuous...
103 * This driver also knows how to load the synthesizers in the 2.4 Gz
104 * ISA Half-card, Product number 847647476 (USA/FCC IEEE Channel set).
105 * This product consists of a "mothercard" that contains the 82586,
106 * NVRAM that holds the PSA, and the ISA-buss interface custom ASIC.
107 * The radio transceiver is a "daughtercard" called the WaveMODEM which
108 * connects to the mothercard through two single-inline connectors: a
109 * 20-pin connector provides DC-power and modem signals, and a 3-pin
110 * connector which exports the antenna connection. The code herein
111 * loads the receive and transmit synthesizers and the corresponding
112 * transmitter output power value from an EEPROM controlled through
113 * additional registers via the MMC. The EEPROM address selected
114 * are those whose values are preset by the DOS utility programs
115 * provided with the product, and this provides compatible operation
116 * with the DOS Packet Driver software. A future modification will
117 * add the necessary functionality to this driver and to the wlconfig
118 * utility to completely replace the DOS Configuration Utilities.
119 * The 2.4 Gz WaveMODEM is described in document number 407-024692/E,
120 * and is available through Lucent Technologies OEM supply channels.
127 * Olivetti PC586 Mach Ethernet driver v1.0
128 * Copyright Ing. C. Olivetti & C. S.p.A. 1988, 1989
129 * All rights reserved.
134 Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc.,
135 Cupertino, California.
139 Permission to use, copy, modify, and distribute this software and
140 its documentation for any purpose and without fee is hereby
141 granted, provided that the above copyright notice appears in all
142 copies and that both the copyright notice and this permission notice
143 appear in supporting documentation, and that the name of Olivetti
144 not be used in advertising or publicity pertaining to distribution
145 of the software without specific, written prior permission.
147 OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
148 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
149 IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
150 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
151 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
152 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
153 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
157 Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
161 Permission to use, copy, modify, and distribute this software and
162 its documentation for any purpose and without fee is hereby
163 granted, provided that the above copyright notice appears in all
164 copies and that both the copyright notice and this permission notice
165 appear in supporting documentation, and that the name of Intel
166 not be used in advertising or publicity pertaining to distribution
167 of the software without specific, written prior permission.
169 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
170 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
171 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
172 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
173 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
174 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
175 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
181 * 1. The best book on the 82586 is:
182 * LAN Components User's Manual by Intel
183 * The copy I found was dated 1984. This really tells you
184 * what the state machines are doing
185 * 2. In the current design, we only do one write at a time,
186 * though the hardware is capable of chaining and possibly
187 * even batching. The problem is that we only make one
188 * transmit buffer available in sram space.
192 #include "opt_wavelan.h"
193 #include "opt_inet.h"
195 #include <sys/param.h>
196 #include <sys/systm.h>
197 #include <sys/kernel.h>
198 #include <sys/sockio.h>
199 #include <sys/mbuf.h>
200 #include <sys/socket.h>
201 #include <sys/syslog.h>
204 #include <sys/sysctl.h>
206 #include <net/ethernet.h>
208 #include <net/if_dl.h>
211 #include <netinet/in.h>
212 #include <netinet/in_systm.h>
213 #include <netinet/ip.h>
214 #include <netinet/if_ether.h>
220 #include <i386/isa/isa_device.h>
222 #include <i386/isa/ic/if_wl_i82586.h> /* Definitions for the Intel chip */
224 /* was 1000 in original, fed to DELAY(x) */
225 #define DELAYCONST 1000
226 #include <i386/isa/if_wl.h>
227 #include <machine/if_wl_wavelan.h>
229 #ifndef COMPAT_OLDISA
230 #error "The wl device requires the old isa compatibility shims"
233 static char t_packet[ETHERMTU + sizeof(struct ether_header) + sizeof(long)];
236 struct arpcom wl_ac; /* Ethernet common part */
237 #define wl_if wl_ac.ac_if /* network visible interface */
238 #define wl_addr wl_ac.ac_enaddr /* hardware address */
240 u_char nwid[2]; /* current radio modem nwid */
244 int tbusy; /* flag to determine if xmit is busy */
248 u_short hacr; /* latest host adapter CR command */
250 u_char chan24; /* 2.4 Gz: channel number/EEPROM Area # */
251 u_short freq24; /* 2.4 Gz: resulting frequency */
252 struct callout_handle watchdog_ch;
254 int w_sigitems; /* number of cached entries */
255 /* array of cache entries */
256 struct w_sigcache w_sigcache[ MAXCACHEITEMS ];
257 int w_nextcache; /* next free cache entry */
258 int w_wrapindex; /* next "free" cache entry */
261 static struct wl_softc wl_softc[NWL];
263 #define WLSOFTC(unit) ((struct wl_softc *)(&wl_softc[unit]))
265 static int wlprobe(struct isa_device *);
266 static int wlattach(struct isa_device *);
268 struct isa_driver wldriver = {
275 COMPAT_ISA_DRIVER(wl, wldriver);
278 * XXX The Wavelan appears to be prone to dropping stuff if you talk to
279 * it too fast. This disgusting hack inserts a delay after each packet
280 * is queued which helps avoid this behaviour on fast systems.
282 static int wl_xmit_delay = 250;
283 SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_delay, CTLFLAG_RW, &wl_xmit_delay, 0, "");
286 * not XXX, but ZZZ (bizarre).
287 * promiscuous mode can be toggled to ignore NWIDs. By default,
288 * it does not. Caution should be exercised about combining
289 * this mode with IFF_ALLMULTI which puts this driver in
292 static int wl_ignore_nwid = 0;
293 SYSCTL_INT(_machdep, OID_AUTO, wl_ignore_nwid, CTLFLAG_RW, &wl_ignore_nwid, 0, "");
296 * Emit diagnostics about transmission problems
298 static int xmt_watch = 0;
299 SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_watch, CTLFLAG_RW, &xmt_watch, 0, "");
302 * Collect SNR statistics
304 static int gathersnr = 0;
305 SYSCTL_INT(_machdep, OID_AUTO, wl_gather_snr, CTLFLAG_RW, &gathersnr, 0, "");
307 static void wlstart(struct ifnet *ifp);
308 static void wlinit(void *xsc);
309 static int wlioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
310 static timeout_t wlwatchdog;
311 static ointhand2_t wlintr;
312 static void wlxmt(int unt, struct mbuf *m);
313 static int wldiag(int unt);
314 static int wlconfig(int unit);
315 static int wlcmd(int unit, char *str);
316 static void wlmmcstat(int unit);
317 static u_short wlbldru(int unit);
318 static u_short wlmmcread(u_int base, u_short reg);
319 static void wlinitmmc(int unit);
320 static int wlhwrst(int unit);
321 static void wlrustrt(int unit);
322 static void wlbldcu(int unit);
323 static int wlack(int unit);
324 static int wlread(int unit, u_short fd_p);
325 static void getsnr(int unit);
326 static void wlrcv(int unit);
327 static int wlrequeue(int unit, u_short fd_p);
328 static void wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
329 static void wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
330 static void wltbd(int unit);
331 static void wlgetpsa(int base, u_char *buf);
332 static void wlsetpsa(int unit);
333 static u_short wlpsacrc(u_char *buf);
334 static void wldump(int unit);
336 static void wl_cache_store(int, int, struct ether_header *, struct mbuf *);
337 static void wl_cache_zero(int unit);
340 # if defined(__FreeBSD__) && __FreeBSD_version < 300000
341 static int check_allmulti(int unit);
345 /* array for maping irq numbers to values for the irq parameter register */
346 static int irqvals[16] = {
347 0, 0, 0, 0x01, 0x02, 0x04, 0, 0x08, 0, 0, 0x10, 0x20, 0x40, 0, 0, 0x80
349 /* mask of valid IRQs */
350 #define WL_IRQS (IRQ3|IRQ4|IRQ5|IRQ7|IRQ10|IRQ11|IRQ12|IRQ15)
355 * This function "probes" or checks for the WaveLAN board on the bus to
356 * see if it is there. As far as I can tell, the best break between this
357 * routine and the attach code is to simply determine whether the board
358 * is configured in properly. Currently my approach to this is to write
359 * and read a word from the SRAM on the board being probed. If the word
360 * comes back properly then we assume the board is there. The config
361 * code expects to see a successful return from the probe routine before
362 * attach will be called.
364 * input : address device is mapped to, and unit # being checked
365 * output : a '1' is returned if the board exists, and a 0 otherwise
369 wlprobe(struct isa_device *id)
371 struct wl_softc *sc = &wl_softc[id->id_unit];
372 register short base = id->id_iobase;
373 char *str = "wl%d: board out of range [0..%d]\n";
375 unsigned long oldpri;
379 * regular CMD() will not work, since no softc yet
381 #define PCMD(base, hacr) outw((base), (hacr))
384 PCMD(base, HACR_RESET); /* reset the board */
385 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
386 PCMD(base, HACR_RESET); /* reset the board */
387 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
390 /* clear reset command and set PIO#1 in autoincrement mode */
391 PCMD(base, HACR_DEFAULT);
392 PCMD(base, HACR_DEFAULT);
393 outw(PIOR1(base), 0); /* go to beginning of RAM */
394 outsw(PIOP1(base), str, strlen(str)/2+1); /* write string */
396 outw(PIOR1(base), 0); /* rewind */
397 insw(PIOP1(base), inbuf, strlen(str)/2+1); /* read result */
399 if (bcmp(str, inbuf, strlen(str)))
402 sc->chan24 = 0; /* 2.4 Gz: config channel */
403 sc->freq24 = 0; /* 2.4 Gz: frequency */
405 /* read the PSA from the board into temporary storage */
406 wlgetpsa(base, inbuf);
408 /* We read the IRQ value from the PSA on the board. */
409 for (irq = 15; irq >= 0; irq--)
410 if (irqvals[irq] == inbuf[WLPSA_IRQNO])
412 if ((irq == 0) || (irqvals[irq] == 0)){
413 printf("wl%d: PSA corrupt (invalid IRQ value)\n", id->id_unit);
414 id->id_irq = 0; /* no interrupt */
417 * If the IRQ requested by the PSA is already claimed by another
418 * device, the board won't work, but the user can still access the
419 * driver to change the IRQ.
421 id->id_irq = (1<<irq); /* use IRQ from PSA */
430 * This function attaches a WaveLAN board to the "system". The rest of
431 * runtime structures are initialized here (this routine is called after
432 * a successful probe of the board). Once the ethernet address is read
433 * and stored, the board's ifnet structure is attached and readied.
435 * input : isa_dev structure setup in autoconfig
436 * output : board structs and ifnet is setup
440 wlattach(struct isa_device *id)
442 struct wl_softc *sc = (struct wl_softc *) &wl_softc[id->id_unit];
443 register short base = id->id_iobase;
445 u_char unit = id->id_unit;
446 register struct ifnet *ifp = &sc->wl_if;
449 printf("wlattach: base %x, unit %d\n", base, unit);
451 id->id_ointr = wlintr;
456 sc->hacr = HACR_RESET;
457 callout_handle_init(&sc->watchdog_ch);
458 CMD(unit); /* reset the board */
459 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
461 /* clear reset command and set PIO#2 in parameter access mode */
462 sc->hacr = (HACR_DEFAULT & ~HACR_16BITS);
465 /* Read the PSA from the board for our later reference */
466 wlgetpsa(base, sc->psa);
469 sc->nwid[0] = sc->psa[WLPSA_NWID];
470 sc->nwid[1] = sc->psa[WLPSA_NWID+1];
472 /* fetch MAC address - decide which one first */
473 if (sc->psa[WLPSA_MACSEL] & 1) {
478 for(i=0; i < WAVELAN_ADDR_SIZE; ++i) {
479 sc->wl_addr[i] = sc->psa[j + i];
482 /* enter normal 16 bit mode operation */
483 sc->hacr = HACR_DEFAULT;
487 outw(PIOR1(base), OFFSET_SCB + 8); /* address of scb_crcerrs */
488 outw(PIOP1(base), 0); /* clear scb_crcerrs */
489 outw(PIOP1(base), 0); /* clear scb_alnerrs */
490 outw(PIOP1(base), 0); /* clear scb_rscerrs */
491 outw(PIOP1(base), 0); /* clear scb_ovrnerrs */
493 bzero(ifp, sizeof(ifp));
495 ifp->if_unit = id->id_unit;
496 ifp->if_mtu = WAVELAN_MTU;
497 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
499 ifp->if_flags |= IFF_DEBUG;
502 ifp->if_flags |= IFF_MULTICAST;
503 #endif /* MULTICAST */
506 ifp->if_init = wlinit;
507 ifp->if_output = ether_output;
508 ifp->if_start = wlstart;
509 ifp->if_ioctl = wlioctl;
510 ifp->if_timer = 0; /* paranoia */
516 ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
518 bcopy(&sc->wl_addr[0], sc->wl_ac.ac_enaddr, WAVELAN_ADDR_SIZE);
519 printf("%s%d: address %6D, NWID 0x%02x%02x", ifp->if_name, ifp->if_unit,
520 sc->wl_ac.ac_enaddr, ":", sc->nwid[0], sc->nwid[1]);
522 printf(", Freq %d MHz",sc->freq24); /* 2.4 Gz */
523 printf("\n"); /* 2.4 Gz */
532 * Print out interesting information about the 82596.
537 register struct wl_softc *sp = WLSOFTC(unit);
541 printf("hasr %04x\n", inw(HASR(base)));
543 printf("scb at %04x:\n ", OFFSET_SCB);
544 outw(PIOR1(base), OFFSET_SCB);
545 for(i = 0; i < 8; i++)
546 printf("%04x ", inw(PIOP1(base)));
549 printf("cu at %04x:\n ", OFFSET_CU);
550 outw(PIOR1(base), OFFSET_CU);
551 for(i = 0; i < 8; i++)
552 printf("%04x ", inw(PIOP1(base)));
555 printf("tbd at %04x:\n ", OFFSET_TBD);
556 outw(PIOR1(base), OFFSET_TBD);
557 for(i = 0; i < 4; i++)
558 printf("%04x ", inw(PIOP1(base)));
562 /* Initialize the Modem Management Controller */
566 register struct wl_softc *sp = WLSOFTC(unit);
572 /* enter 8 bit operation */
573 sp->hacr = (HACR_DEFAULT & ~HACR_16BITS);
576 configured = sp->psa[WLPSA_CONFIGURED] & 1;
579 * Set default modem control parameters. Taken from NCR document
582 MMC_WRITE(MMC_JABBER_ENABLE, 0x01);
583 MMC_WRITE(MMC_ANTEN_SEL, 0x02);
584 MMC_WRITE(MMC_IFS, 0x20);
585 MMC_WRITE(MMC_MOD_DELAY, 0x04);
586 MMC_WRITE(MMC_JAM_TIME, 0x38);
587 MMC_WRITE(MMC_DECAY_PRM, 0x00); /* obsolete ? */
588 MMC_WRITE(MMC_DECAY_UPDAT_PRM, 0x00);
590 MMC_WRITE(MMC_LOOPT_SEL, 0x00);
591 if (sp->psa[WLPSA_COMPATNO] & 1) {
592 MMC_WRITE(MMC_THR_PRE_SET, 0x01); /* 0x04 for AT and 0x01 for MCA */
594 MMC_WRITE(MMC_THR_PRE_SET, 0x04); /* 0x04 for AT and 0x01 for MCA */
596 MMC_WRITE(MMC_QUALITY_THR, 0x03);
598 /* use configuration defaults from parameter storage area */
599 if (sp->psa[WLPSA_NWIDENABLE] & 1) {
600 if ((mode & (MOD_PROM | MOD_ENAL)) && wl_ignore_nwid) {
601 MMC_WRITE(MMC_LOOPT_SEL, 0x40);
603 MMC_WRITE(MMC_LOOPT_SEL, 0x00);
606 MMC_WRITE(MMC_LOOPT_SEL, 0x40); /* disable network id check */
608 MMC_WRITE(MMC_THR_PRE_SET, sp->psa[WLPSA_THRESH]);
609 MMC_WRITE(MMC_QUALITY_THR, sp->psa[WLPSA_QUALTHRESH]);
611 MMC_WRITE(MMC_FREEZE, 0x00);
612 MMC_WRITE(MMC_ENCR_ENABLE, 0x00);
614 MMC_WRITE(MMC_NETW_ID_L,sp->nwid[1]); /* set NWID */
615 MMC_WRITE(MMC_NETW_ID_H,sp->nwid[0]);
617 /* enter normal 16 bit mode operation */
618 sp->hacr = HACR_DEFAULT;
620 CMD(unit); /* virtualpc1 needs this! */
622 if (sp->psa[WLPSA_COMPATNO]== /* 2.4 Gz: half-card ver */
623 WLPSA_COMPATNO_WL24B) { /* 2.4 Gz */
624 i=sp->chan24<<4; /* 2.4 Gz: position ch # */
625 MMC_WRITE(MMC_EEADDR,i+0x0f); /* 2.4 Gz: named ch, wc=16 */
626 MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+ /* 2.4 Gz: Download Synths */
627 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: Read EEPROM */
628 for (i=0; i<1000; ++i) { /* 2.4 Gz: wait for download */
629 DELAY(40); /* 2.4 Gz */
630 if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and */
631 &(MMC_EECTRLstat_DWLD /* 2.4 Gz: EEBUSY */
632 +MMC_EECTRLstat_EEBUSY))==0) /* 2.4 Gz: */
633 break; /* 2.4 Gz: download finished */
635 if (i==1000) printf("wl: synth load failed\n"); /* 2.4 Gz */
636 MMC_WRITE(MMC_EEADDR,0x61); /* 2.4 Gz: default pwr, wc=2 */
637 MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+ /* 2.4 Gz: Download Xmit Pwr */
638 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: Read EEPROM */
639 for (i=0; i<1000; ++i) { /* 2.4 Gz: wait for download */
640 DELAY(40); /* 2.4 Gz */
641 if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and */
642 &(MMC_EECTRLstat_DWLD /* 2.4 Gz: EEBUSY */
643 +MMC_EECTRLstat_EEBUSY))==0) /* 2.4 Gz: */
644 break; /* 2.4 Gz: download finished */
646 if (i==1000) printf("wl: xmit pwr load failed\n"); /* 2.4 Gz */
647 MMC_WRITE(MMC_ANALCTRL, /* 2.4 Gz: EXT ant+polarity */
648 MMC_ANALCTRL_ANTPOL + /* 2.4 Gz: */
649 MMC_ANALCTRL_EXTANT); /* 2.4 Gz: */
650 i=sp->chan24<<4; /* 2.4 Gz: position ch # */
651 MMC_WRITE(MMC_EEADDR,i); /* 2.4 Gz: get frequency */
652 MMC_WRITE(MMC_EECTRL, /* 2.4 Gz: EEPROM read */
653 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: */
654 DELAY(40); /* 2.4 Gz */
655 i = wlmmcread(base,MMC_EEDATALrv) /* 2.4 Gz: freq val */
656 + (wlmmcread(base,MMC_EEDATAHrv)<<8); /* 2.4 Gz */
657 sp->freq24 = (i>>6)+2400; /* 2.4 Gz: save real freq */
664 * Another routine that interfaces the "if" layer to this driver.
665 * Simply resets the structures that are used by "upper layers".
666 * As well as calling wlhwrst that does reset the WaveLAN board.
668 * input : softc pointer for this interface
669 * output : structures (if structs) and board are reset
675 register struct wl_softc *sc = xsc;
676 struct ifnet *ifp = &sc->wl_if;
681 if (sc->wl_if.if_flags & IFF_DEBUG)
682 printf("wl%d: entered wlinit()\n",sc->unit);
684 #if defined(__FreeBSD__) && __FreeBSD_version >= 300000
685 if (TAILQ_FIRST(&ifp->if_addrhead) == (struct ifaddr *)0) {
687 if (ifp->if_addrlist == (struct ifaddr *)0) {
692 if ((stat = wlhwrst(sc->unit)) == TRUE) {
693 sc->wl_if.if_flags |= IFF_RUNNING; /* same as DSF_RUNNING */
695 * OACTIVE is used by upper-level routines
698 sc->wl_if.if_flags &= ~IFF_OACTIVE; /* same as tbusy below */
700 sc->flags |= DSF_RUNNING;
702 untimeout(wlwatchdog, sc, sc->watchdog_ch);
706 printf("wl%d init(): trouble resetting board.\n", sc->unit);
714 * This routine resets the WaveLAN board that corresponds to the
715 * board number passed in.
717 * input : board number to do a hardware reset
718 * output : board is reset
724 register struct wl_softc *sc = WLSOFTC(unit);
727 if (sc->wl_if.if_flags & IFF_DEBUG)
728 printf("wl%d: entered wlhwrst()\n",unit);
730 sc->hacr = HACR_RESET;
731 CMD(unit); /* reset the board */
733 /* clear reset command and set PIO#1 in autoincrement mode */
734 sc->hacr = HACR_DEFAULT;
738 if (sc->wl_if.if_flags & IFF_DEBUG)
739 wlmmcstat(unit); /* Display MMC registers */
741 wlbldcu(unit); /* set up command unit structures */
743 if (wldiag(unit) == 0)
746 if (wlconfig(unit) == 0)
749 * insert code for loopback test here
751 wlrustrt(unit); /* start receive unit */
753 /* enable interrupts */
754 sc->hacr = (HACR_DEFAULT | HACR_INTRON);
763 * This function builds up the command unit structures. It inits
764 * the scp, iscp, scb, cb, tbd, and tbuf.
770 register struct wl_softc *sc = WLSOFTC(unit);
771 short base = sc->base;
779 bzero(&scp, sizeof(scp));
781 scp.scp_iscp = OFFSET_ISCP;
782 scp.scp_iscp_base = 0;
783 outw(PIOR1(base), OFFSET_SCP);
784 outsw(PIOP1(base), &scp, sizeof(scp_t)/2);
786 bzero(&iscp, sizeof(iscp));
788 iscp.iscp_scb_offset = OFFSET_SCB;
790 iscp.iscp_scb_base = 0;
791 outw(PIOR1(base), OFFSET_ISCP);
792 outsw(PIOP1(base), &iscp, sizeof(iscp_t)/2);
795 scb.scb_command = SCB_RESET;
796 scb.scb_cbl_offset = OFFSET_CU;
797 scb.scb_rfa_offset = OFFSET_RU;
801 scb.scb_ovrnerrs = 0;
802 outw(PIOR1(base), OFFSET_SCB);
803 outsw(PIOP1(base), &scb, sizeof(scb_t)/2);
807 outw(PIOR0(base), OFFSET_ISCP + 0); /* address of iscp_busy */
808 for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
809 if (i <= 0) printf("wl%d bldcu(): iscp_busy timeout.\n", unit);
810 outw(PIOR0(base), OFFSET_SCB + 0); /* address of scb_status */
811 for (i = STATUS_TRIES; i-- > 0; ) {
812 if (inw(PIOP0(base)) == (SCB_SW_CX|SCB_SW_CNA))
816 printf("wl%d bldcu(): not ready after reset.\n", unit);
820 cb.ac_command = AC_CW_EL; /* NOP */
821 cb.ac_link_offset = OFFSET_CU;
822 outw(PIOR1(base), OFFSET_CU);
823 outsw(PIOP1(base), &cb, 6/2);
826 tbd.next_tbd_offset = I82586NULL;
829 outw(PIOR1(base), OFFSET_TBD);
830 outsw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
838 * input : board number
839 * output : stuff sent to board if any there
843 wlstart(struct ifnet *ifp)
845 int unit = ifp->if_unit;
847 register struct wl_softc *sc = WLSOFTC(unit);
848 short base = sc->base;
849 int scb_status, cu_status, scb_command;
852 if (sc->wl_if.if_flags & IFF_DEBUG)
853 printf("wl%d: entered wlstart()\n",unit);
856 outw(PIOR1(base), OFFSET_CU);
857 cu_status = inw(PIOP1(base));
858 outw(PIOR0(base),OFFSET_SCB + 0); /* scb_status */
859 scb_status = inw(PIOP0(base));
860 outw(PIOR0(base), OFFSET_SCB + 2);
861 scb_command = inw(PIOP0(base));
864 * don't need OACTIVE check as tbusy here checks to see
865 * if we are already busy
868 if((scb_status & 0x0700) == SCB_CUS_IDLE &&
869 (cu_status & AC_SW_B) == 0){
871 untimeout(wlwatchdog, sc, sc->watchdog_ch);
872 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
874 * This is probably just a race. The xmt'r is just
875 * became idle but WE have masked interrupts so ...
878 printf("wl%d: CU idle, scb %04x %04x cu %04x\n",
879 unit, scb_status, scb_command, cu_status);
881 if (xmt_watch) printf("!!");
883 return; /* genuinely still busy */
885 } else if((scb_status & 0x0700) == SCB_CUS_ACTV ||
886 (cu_status & AC_SW_B)){
888 printf("wl%d: CU unexpectedly busy; scb %04x cu %04x\n",
889 unit, scb_status, cu_status);
891 if (xmt_watch) printf("wl%d: busy?!",unit);
892 return; /* hey, why are we busy? */
895 /* get ourselves some data */
897 IF_DEQUEUE(&ifp->if_snd, m);
898 if (m != (struct mbuf *)0) {
899 /* let BPF see it before we commit it */
904 /* set the watchdog timer so that if the board
905 * fails to interrupt we will restart
907 /* try 10 ticks, not very long */
908 sc->watchdog_ch = timeout(wlwatchdog, sc, 10);
909 sc->wl_ac.ac_if.if_flags |= IFF_OACTIVE;
910 sc->wl_if.if_opackets++;
913 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
921 * This routine does the actual copy of data (including ethernet header
922 * structure) from the WaveLAN to an mbuf chain that will be passed up
923 * to the "if" (network interface) layer. NOTE: we currently
924 * don't handle trailer protocols, so if that is needed, it will
925 * (at least in part) be added here. For simplicities sake, this
926 * routine copies the receive buffers from the board into a local (stack)
927 * buffer until the frame has been copied from the board. Once in
928 * the local buffer, the contents are copied to an mbuf chain that
929 * is then enqueued onto the appropriate "if" queue.
931 * input : board number, and an frame descriptor address
932 * output : the packet is put into an mbuf chain, and passed up
933 * assumes : if any errors occur, packet is "dropped on the floor"
937 wlread(int unit, u_short fd_p)
939 register struct wl_softc *sc = WLSOFTC(unit);
940 register struct ifnet *ifp = &sc->wl_if;
941 short base = sc->base;
943 struct ether_header eh;
947 u_short mlen, len, clen;
948 u_short bytes_in_msg, bytes_in_mbuf, bytes;
952 if (sc->wl_if.if_flags & IFF_DEBUG)
953 printf("wl%d: entered wlread()\n",unit);
955 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
956 printf("wl%d read(): board is not running.\n", ifp->if_unit);
957 sc->hacr &= ~HACR_INTRON;
958 CMD(unit); /* turn off interrupts */
960 /* read ether_header info out of device memory. doesn't
961 * go into mbuf. goes directly into eh structure
963 len = sizeof(struct ether_header); /* 14 bytes */
964 outw(PIOR1(base), fd_p);
965 insw(PIOP1(base), &fd, (sizeof(fd_t) - len)/2);
966 insw(PIOP1(base), &eh, (len-2)/2);
967 eh.ether_type = ntohs(inw(PIOP1(base)));
969 if (sc->wl_if.if_flags & IFF_DEBUG) {
970 printf("wlread: rcv packet, type is %x\n", eh.ether_type);
974 * WARNING. above is done now in ether_input, above may be
975 * useful for debug. jrb
977 eh.ether_type = htons(eh.ether_type);
979 if (fd.rbd_offset == I82586NULL) {
980 printf("wl%d read(): Invalid buffer\n", unit);
981 if (wlhwrst(unit) != TRUE) {
982 printf("wl%d read(): hwrst trouble.\n", unit);
987 outw(PIOR1(base), fd.rbd_offset);
988 insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
989 bytes_in_msg = rbd.status & RBD_SW_COUNT;
990 MGETHDR(m, M_DONTWAIT, MT_DATA);
992 if (m == (struct mbuf *)0) {
994 * not only do we want to return, we need to drop the packet on
995 * the floor to clear the interrupt.
998 if (wlhwrst(unit) != TRUE) {
999 sc->hacr &= ~HACR_INTRON;
1000 CMD(unit); /* turn off interrupts */
1001 printf("wl%d read(): hwrst trouble.\n", unit);
1005 m->m_next = (struct mbuf *) 0;
1006 m->m_pkthdr.rcvif = ifp;
1007 m->m_pkthdr.len = 0; /* don't know this yet */
1010 /* always use a cluster. jrb
1012 MCLGET(m, M_DONTWAIT);
1013 if (m->m_flags & M_EXT) {
1014 m->m_len = MCLBYTES;
1018 if (wlhwrst(unit) != TRUE) {
1019 sc->hacr &= ~HACR_INTRON;
1020 CMD(unit); /* turn off interrupts */
1021 printf("wl%d read(): hwrst trouble.\n", unit);
1028 bytes_in_mbuf = m->m_len;
1029 mb_p = mtod(tm, u_char *);
1030 bytes = min(bytes_in_mbuf, bytes_in_msg);
1037 outw(PIOR1(base), rbd.buffer_addr);
1038 insw(PIOP1(base), mb_p, len/2);
1042 if (!(bytes_in_mbuf -= bytes)) {
1043 MGET(tm->m_next, M_DONTWAIT, MT_DATA);
1045 if (tm == (struct mbuf *)0) {
1047 printf("wl%d read(): No mbuf nth\n", unit);
1048 if (wlhwrst(unit) != TRUE) {
1049 sc->hacr &= ~HACR_INTRON;
1050 CMD(unit); /* turn off interrupts */
1051 printf("wl%d read(): hwrst trouble.\n", unit);
1057 bytes_in_mbuf = MLEN;
1058 mb_p = mtod(tm, u_char *);
1063 if (!(bytes_in_msg -= bytes)) {
1064 if (rbd.status & RBD_SW_EOF ||
1065 rbd.next_rbd_offset == I82586NULL) {
1069 outw(PIOR1(base), rbd.next_rbd_offset);
1070 insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1071 bytes_in_msg = rbd.status & RBD_SW_COUNT;
1074 rbd.buffer_addr += bytes;
1077 bytes = min(bytes_in_mbuf, bytes_in_msg);
1080 m->m_pkthdr.len = clen;
1083 * If hw is in promiscuous mode (note that I said hardware, not if
1084 * IFF_PROMISC is set in ifnet flags), then if this is a unicast
1085 * packet and the MAC dst is not us, drop it. This check in normally
1086 * inside ether_input(), but IFF_MULTI causes hw promisc without
1087 * a bpf listener, so this is wrong.
1088 * Greg Troxel <gdt@ir.bbn.com>, 1998-08-07
1091 * TBD: also discard packets where NWID does not match.
1092 * However, there does not appear to be a way to read the nwid
1093 * for a received packet. -gdt 1998-08-07
1096 #ifdef WL_USE_IFNET_PROMISC_CHECK /* not defined */
1097 (sc->wl_ac.ac_if.if_flags & (IFF_PROMISC|IFF_ALLMULTI))
1099 /* hw is in promisc mode if this is true */
1100 (sc->mode & (MOD_PROM | MOD_ENAL))
1103 (eh.ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
1104 bcmp(eh.ether_dhost, sc->wl_ac.ac_enaddr,
1105 sizeof(eh.ether_dhost)) != 0 ) {
1111 if (sc->wl_if.if_flags & IFF_DEBUG)
1112 printf("wl%d: wlrecv %d bytes\n", unit, clen);
1116 wl_cache_store(unit, base, &eh, m);
1120 * received packet is now in a chain of mbuf's. next step is
1121 * to pass the packet upwards.
1124 ether_input(&sc->wl_if, &eh, m);
1131 * This routine processes an ioctl request from the "if" layer
1134 * input : pointer the appropriate "if" struct, command, and data
1135 * output : based on command appropriate action is taken on the
1136 * WaveLAN board(s) or related structures
1137 * return : error is returned containing exit conditions
1141 wlioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1143 register struct ifreq *ifr = (struct ifreq *)data;
1144 int unit = ifp->if_unit;
1145 register struct wl_softc *sc = WLSOFTC(unit);
1146 short base = sc->base;
1148 int opri, error = 0;
1149 struct proc *p = curproc; /* XXX */
1150 int irq, irqval, i, isroot, size;
1156 if (sc->wl_if.if_flags & IFF_DEBUG)
1157 printf("wl%d: entered wlioctl()\n",unit);
1164 error = ether_ioctl(ifp, cmd, data);
1168 if (ifp->if_flags & IFF_ALLMULTI) {
1171 if (ifp->if_flags & IFF_PROMISC) {
1174 if(ifp->if_flags & IFF_LINK0) {
1178 * force a complete reset if the recieve multicast/
1179 * promiscuous mode changes so that these take
1180 * effect immediately.
1183 if (sc->mode != mode) {
1185 if (sc->flags & DSF_RUNNING) {
1186 sc->flags &= ~DSF_RUNNING;
1190 /* if interface is marked DOWN and still running then
1193 if ((ifp->if_flags & IFF_UP) == 0 && sc->flags & DSF_RUNNING) {
1194 printf("wl%d ioctl(): board is not running\n", unit);
1195 sc->flags &= ~DSF_RUNNING;
1196 sc->hacr &= ~HACR_INTRON;
1197 CMD(unit); /* turn off interrupts */
1199 /* else if interface is UP and RUNNING, start it
1201 else if (ifp->if_flags & IFF_UP && (sc->flags & DSF_RUNNING) == 0) {
1205 /* if WLDEBUG set on interface, then printf rf-modem regs
1207 if(ifp->if_flags & IFF_DEBUG)
1214 #if defined(__FreeBSD__) && __FreeBSD_version < 300000
1215 if (cmd == SIOCADDMULTI) {
1216 error = ether_addmulti(ifr, &sc->wl_ac);
1219 error = ether_delmulti(ifr, &sc->wl_ac);
1222 /* see if we should be in all multicast mode
1223 * note that 82586 cannot do that, must simulate with
1226 if ( check_allmulti(unit)) {
1227 ifp->if_flags |= IFF_ALLMULTI;
1228 sc->mode |= MOD_ENAL;
1229 sc->flags &= ~DSF_RUNNING;
1235 if (error == ENETRESET) {
1236 if(sc->flags & DSF_RUNNING) {
1237 sc->flags &= ~DSF_RUNNING;
1246 #endif /* MULTICAST */
1248 /* DEVICE SPECIFIC */
1251 /* copy the PSA out to the caller */
1253 /* pointer to buffer in user space */
1254 up = (void *)ifr->ifr_data;
1255 /* work out if they're root */
1256 isroot = (suser(p) == 0);
1258 for (i = 0; i < 0x40; i++) {
1259 /* don't hand the DES key out to non-root users */
1260 if ((i > WLPSA_DESKEY) && (i < (WLPSA_DESKEY + 8)) && !isroot)
1262 if (subyte((up + i), sc->psa[i]))
1268 /* copy the PSA in from the caller; we only copy _some_ values */
1271 if ((error = suser(p)))
1273 error = EINVAL; /* assume the worst */
1274 /* pointer to buffer in user space containing data */
1275 up = (void *)ifr->ifr_data;
1277 /* check validity of input range */
1278 for (i = 0; i < 0x40; i++)
1279 if (fubyte(up + i) < 0)
1282 /* check IRQ value */
1283 irqval = fubyte(up+WLPSA_IRQNO);
1284 for (irq = 15; irq >= 0; irq--)
1285 if(irqvals[irq] == irqval)
1287 if (irq == 0) /* oops */
1290 sc->psa[WLPSA_IRQNO] = irqval;
1293 for (i = 0; i < 6; i++)
1294 sc->psa[WLPSA_LOCALMAC+i] = fubyte(up+WLPSA_LOCALMAC+i);
1297 sc->psa[WLPSA_MACSEL] = fubyte(up+WLPSA_MACSEL);
1300 sc->psa[WLPSA_NWID] = fubyte(up+WLPSA_NWID);
1301 sc->psa[WLPSA_NWID+1] = fubyte(up+WLPSA_NWID+1);
1304 wlsetpsa(unit); /* update the PSA */
1308 /* get the current NWID out of the sc since we stored it there */
1310 ifr->ifr_data = (caddr_t) (sc->nwid[0] << 8 | sc->nwid[1]);
1315 * change the nwid dynamically. This
1316 * ONLY changes the radio modem and does not
1320 * 1. save in softc "soft registers"
1321 * 2. save in radio modem (MMC)
1325 if ((error = suser(p)))
1327 if (!(ifp->if_flags & IFF_UP)) {
1328 error = EIO; /* only allowed while up */
1331 * soft c nwid shadows radio modem setting
1333 sc->nwid[0] = (int)ifr->ifr_data >> 8;
1334 sc->nwid[1] = (int)ifr->ifr_data & 0xff;
1335 MMC_WRITE(MMC_NETW_ID_L,sc->nwid[1]);
1336 MMC_WRITE(MMC_NETW_ID_H,sc->nwid[0]);
1340 /* copy the EEPROM in 2.4 Gz WaveMODEM out to the caller */
1343 if ((error = suser(p)))
1345 /* pointer to buffer in user space */
1346 up = (void *)ifr->ifr_data;
1348 for (i=0x00; i<0x80; ++i) { /* 2.4 Gz: size of EEPROM */
1349 MMC_WRITE(MMC_EEADDR,i); /* 2.4 Gz: get frequency */
1350 MMC_WRITE(MMC_EECTRL, /* 2.4 Gz: EEPROM read */
1351 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: */
1352 DELAY(40); /* 2.4 Gz */
1353 if (subyte(up + 2*i , /* 2.4 Gz: pass low byte of */
1354 wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word */
1355 ) return(EFAULT); /* 2.4 Gz: */
1356 if (subyte(up + 2*i+1, /* 2.4 Gz: pass hi byte of */
1357 wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word */
1358 ) return(EFAULT); /* 2.4 Gz: */
1363 /* zero (Delete) the wl cache */
1366 if ((error = suser(p)))
1368 wl_cache_zero(unit);
1371 /* read out the number of used cache elements */
1373 ifr->ifr_data = (caddr_t) sc->w_sigitems;
1376 /* read out the wl cache */
1378 /* pointer to buffer in user space */
1379 up = (void *)ifr->ifr_data;
1380 cpt = (char *) &sc->w_sigcache[0];
1381 size = sc->w_sigitems * sizeof(struct w_sigcache);
1383 for (i = 0; i < size; i++) {
1384 if (subyte((up + i), *cpt++))
1400 * Called if the timer set in wlstart expires before an interrupt is received
1401 * from the wavelan. It seems to lose interrupts sometimes.
1402 * The watchdog routine gets called if the transmitter failed to interrupt
1404 * input : which board is timing out
1405 * output : board reset
1409 wlwatchdog(void *vsc)
1411 struct wl_softc *sc = vsc;
1412 int unit = sc->unit;
1414 log(LOG_ERR, "wl%d: wavelan device timeout on xmit\n", unit);
1415 sc->wl_ac.ac_if.if_oerrors++;
1422 * This function is the interrupt handler for the WaveLAN
1423 * board. This routine will be called whenever either a packet
1424 * is received, or a packet has successfully been transfered and
1425 * the unit is ready to transmit another packet.
1427 * input : board number that interrupted
1428 * output : either a packet is received, or a packet is transfered
1435 register struct wl_softc *sc = &wl_softc[unit];
1436 short base = sc->base;
1438 u_short int_type, int_type1;
1441 if (sc->wl_if.if_flags & IFF_DEBUG)
1442 printf("wl%d: wlintr() called\n",unit);
1445 if((int_type = inw(HASR(base))) & HASR_MMC_INTR) {
1446 /* handle interrupt from the modem management controler */
1447 /* This will clear the interrupt condition */
1448 (void) wlmmcread(base,MMC_DCE_STATUS); /* ignored for now */
1451 if(!(int_type & HASR_INTR)){ /* return if no interrupt from 82586 */
1452 /* commented out. jrb. it happens when reinit occurs
1453 printf("wlintr: int_type %x, dump follows\n", int_type);
1462 outw(PIOR0(base), OFFSET_SCB + 0); /* get scb status */
1463 int_type = (inw(PIOP0(base)) & SCB_SW_INT);
1464 if (int_type == 0) /* no interrupts left */
1467 int_type1 = wlack(unit); /* acknowledge interrupt(s) */
1468 /* make sure no bits disappeared (others may appear) */
1469 if ((int_type & int_type1) != int_type)
1470 printf("wlack() int bits disappeared : %04x != int_type %04x\n",
1471 int_type1, int_type);
1472 int_type = int_type1; /* go with the new status */
1476 if (int_type & SCB_SW_FR) {
1477 sc->wl_if.if_ipackets++;
1481 * receiver not ready
1483 if (int_type & SCB_SW_RNR) {
1484 sc->wl_if.if_ierrors++;
1486 if (sc->wl_if.if_flags & IFF_DEBUG)
1487 printf("wl%d intr(): receiver overrun! begin_fd = %x\n",
1488 unit, sc->begin_fd);
1495 if (int_type & SCB_SW_CNA) {
1497 * At present, we don't care about CNA's. We
1498 * believe they are a side effect of XMT.
1501 if (int_type & SCB_SW_CX) {
1503 * At present, we only request Interrupt for
1506 outw(PIOR1(base), OFFSET_CU); /* get command status */
1507 ac_status = inw(PIOP1(base));
1509 if (xmt_watch) { /* report some anomalies */
1511 if (sc->tbusy == 0) {
1512 printf("wl%d: xmt intr but not busy, CU %04x\n",
1515 if (ac_status == 0) {
1516 printf("wl%d: xmt intr but ac_status == 0\n", unit);
1518 if (ac_status & AC_SW_A) {
1519 printf("wl%d: xmt aborted\n",unit);
1522 if (ac_status & TC_CARRIER) {
1523 printf("wl%d: no carrier\n", unit);
1526 if (ac_status & TC_CLS) {
1527 printf("wl%d: no CTS\n", unit);
1529 if (ac_status & TC_DMA) {
1530 printf("wl%d: DMA underrun\n", unit);
1532 if (ac_status & TC_DEFER) {
1533 printf("wl%d: xmt deferred\n",unit);
1535 if (ac_status & TC_SQE) {
1536 printf("wl%d: heart beat\n", unit);
1538 if (ac_status & TC_COLLISION) {
1539 printf("wl%d: too many collisions\n", unit);
1542 /* if the transmit actually failed, or returned some status */
1543 if ((!(ac_status & AC_SW_OK)) || (ac_status & 0xfff)) {
1544 if (ac_status & (TC_COLLISION | TC_CLS | TC_DMA)) {
1545 sc->wl_if.if_oerrors++;
1547 /* count collisions */
1548 sc->wl_if.if_collisions += (ac_status & 0xf);
1549 /* if TC_COLLISION set and collision count zero, 16 collisions */
1550 if ((ac_status & 0x20) == 0x20) {
1551 sc->wl_if.if_collisions += 0x10;
1555 untimeout(wlwatchdog, sc, sc->watchdog_ch);
1556 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
1557 wlstart(&(sc->wl_if));
1566 * This routine is called by the interrupt handler to initiate a
1567 * packet transfer from the board to the "if" layer above this
1568 * driver. This routine checks if a buffer has been successfully
1569 * received by the WaveLAN. If so, the routine wlread is called
1570 * to do the actual transfer of the board data (including the
1571 * ethernet header) into a packet (consisting of an mbuf chain).
1573 * input : number of the board to check
1574 * output : if a packet is available, it is "sent up"
1580 register struct wl_softc *sc = WLSOFTC(unit);
1581 short base = sc->base;
1582 u_short fd_p, status, offset, link_offset;
1585 if (sc->wl_if.if_flags & IFF_DEBUG)
1586 printf("wl%d: entered wlrcv()\n",unit);
1588 for (fd_p = sc->begin_fd; fd_p != I82586NULL; fd_p = sc->begin_fd) {
1590 outw(PIOR0(base), fd_p + 0); /* address of status */
1591 status = inw(PIOP0(base));
1592 outw(PIOR1(base), fd_p + 4); /* address of link_offset */
1593 link_offset = inw(PIOP1(base));
1594 offset = inw(PIOP1(base)); /* rbd_offset */
1595 if (status == 0xffff || offset == 0xffff /*I82586NULL*/) {
1596 if (wlhwrst(unit) != TRUE)
1597 printf("wl%d rcv(): hwrst ffff trouble.\n", unit);
1599 } else if (status & AC_SW_C) {
1600 if (status == (RFD_DONE|RFD_RSC)) {
1603 if (sc->wl_if.if_flags & IFF_DEBUG)
1604 printf("wl%d RCV: RSC %x\n", unit, status);
1606 sc->wl_if.if_ierrors++;
1607 } else if (!(status & RFD_OK)) {
1608 printf("wl%d RCV: !OK %x\n", unit, status);
1609 sc->wl_if.if_ierrors++;
1610 } else if (status & 0xfff) { /* can't happen */
1611 printf("wl%d RCV: ERRs %x\n", unit, status);
1612 sc->wl_if.if_ierrors++;
1613 } else if (!wlread(unit, fd_p))
1616 if (!wlrequeue(unit, fd_p)) {
1617 /* abort on chain error */
1618 if (wlhwrst(unit) != TRUE)
1619 printf("wl%d rcv(): hwrst trouble.\n", unit);
1622 sc->begin_fd = link_offset;
1633 * This routine puts rbd's used in the last receive back onto the
1634 * free list for the next receive.
1638 wlrequeue(int unit, u_short fd_p)
1640 register struct wl_softc *sc = WLSOFTC(unit);
1641 short base = sc->base;
1643 u_short l_rbdp, f_rbdp, rbd_offset;
1645 outw(PIOR0(base), fd_p + 6);
1646 rbd_offset = inw(PIOP0(base));
1647 if ((f_rbdp = rbd_offset) != I82586NULL) {
1650 outw(PIOR0(base), l_rbdp + 0); /* address of status */
1651 if(inw(PIOP0(base)) & RBD_SW_EOF)
1653 outw(PIOP0(base), 0);
1654 outw(PIOR0(base), l_rbdp + 2); /* next_rbd_offset */
1655 if((l_rbdp = inw(PIOP0(base))) == I82586NULL)
1658 outw(PIOP0(base), 0);
1659 outw(PIOR0(base), l_rbdp + 2); /* next_rbd_offset */
1660 outw(PIOP0(base), I82586NULL);
1661 outw(PIOR0(base), l_rbdp + 8); /* address of size */
1662 outw(PIOP0(base), inw(PIOP0(base)) | AC_CW_EL);
1663 outw(PIOR0(base), sc->end_rbd + 2);
1664 outw(PIOP0(base), f_rbdp); /* end_rbd->next_rbd_offset */
1665 outw(PIOR0(base), sc->end_rbd + 8); /* size */
1666 outw(PIOP0(base), inw(PIOP0(base)) & ~AC_CW_EL);
1667 sc->end_rbd = l_rbdp;
1671 fd.command = AC_CW_EL;
1672 fd.link_offset = I82586NULL;
1673 fd.rbd_offset = I82586NULL;
1674 outw(PIOR1(base), fd_p);
1675 outsw(PIOP1(base), &fd, 8/2);
1677 outw(PIOR1(base), sc->end_fd + 2); /* addr of command */
1678 outw(PIOP1(base), 0); /* command = 0 */
1679 outw(PIOP1(base), fd_p); /* end_fd->link_offset = fd_p */
1686 static int xmt_debug = 0;
1687 #endif /* WLDEBUG */
1692 * This routine fills in the appropriate registers and memory
1693 * locations on the WaveLAN board and starts the board off on
1696 * input : board number of interest, and a pointer to the mbuf
1697 * output : board memory and registers are set for xfer and attention
1701 wlxmt(int unit, struct mbuf *m)
1703 register struct wl_softc *sc = WLSOFTC(unit);
1704 register u_short xmtdata_p = OFFSET_TBUF;
1705 register u_short xmtshort_p;
1706 struct mbuf *tm_p = m;
1707 register struct ether_header *eh_p = mtod(m, struct ether_header *);
1708 u_char *mb_p = mtod(m, u_char *) + sizeof(struct ether_header);
1709 u_short count = m->m_len - sizeof(struct ether_header);
1711 u_short tbd_p = OFFSET_TBD;
1712 u_short len, clen = 0;
1713 short base = sc->base;
1717 if (sc->wl_if.if_flags & IFF_DEBUG)
1718 printf("wl%d: entered wlxmt()\n",unit);
1722 cb.ac_command = (AC_CW_EL|AC_TRANSMIT|AC_CW_I);
1723 cb.ac_link_offset = I82586NULL;
1724 outw(PIOR1(base), OFFSET_CU);
1725 outsw(PIOP1(base), &cb, 6/2);
1726 outw(PIOP1(base), OFFSET_TBD); /* cb.cmd.transmit.tbd_offset */
1727 outsw(PIOP1(base), eh_p->ether_dhost, WAVELAN_ADDR_SIZE/2);
1728 outw(PIOP1(base), eh_p->ether_type);
1731 if (sc->wl_if.if_flags & IFF_DEBUG) {
1733 printf("XMT mbuf: L%d @%p ", count, (void *)mb_p);
1734 printf("ether type %x\n", eh_p->ether_type);
1737 #endif /* WLDEBUG */
1738 outw(PIOR0(base), OFFSET_TBD);
1739 outw(PIOP0(base), 0); /* act_count */
1740 outw(PIOR1(base), OFFSET_TBD + 4);
1741 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1742 outw(PIOP1(base), 0); /* buffer_base */
1745 if (clen + count > WAVELAN_MTU)
1751 outw(PIOR1(base), xmtdata_p);
1752 outsw(PIOP1(base), mb_p, len/2);
1754 outw(PIOR0(base), tbd_p); /* address of act_count */
1755 outw(PIOP0(base), inw(PIOP0(base)) + count);
1757 if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1760 /* go to the next descriptor */
1761 outw(PIOR0(base), tbd_p + 2);
1762 tbd_p += sizeof (tbd_t);
1763 outw(PIOP0(base), tbd_p); /* next_tbd_offset */
1764 outw(PIOR0(base), tbd_p);
1765 outw(PIOP0(base), 0); /* act_count */
1766 outw(PIOR1(base), tbd_p + 4);
1767 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1768 outw(PIOP1(base), 0); /* buffer_base */
1769 /* at the end -> coallesce remaining mbufs */
1770 if (tbd_p == OFFSET_TBD + (N_TBD-1) * sizeof (tbd_t)) {
1771 wlsftwsleaze(&count, &mb_p, &tm_p, unit);
1774 /* next mbuf short -> coallesce as needed */
1775 if ( (tm_p->m_next == (struct mbuf *) 0) ||
1776 #define HDW_THRESHOLD 55
1777 tm_p->m_len > HDW_THRESHOLD)
1780 wlhdwsleaze(&count, &mb_p, &tm_p, unit);
1784 } else if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1786 count = tm_p->m_len;
1787 mb_p = mtod(tm_p, u_char *);
1789 if (sc->wl_if.if_flags & IFF_DEBUG)
1791 printf("mbuf+ L%d @%p ", count, (void *)mb_p);
1792 #endif /* WLDEBUG */
1795 if (sc->wl_if.if_flags & IFF_DEBUG)
1797 printf("CLEN = %d\n", clen);
1798 #endif /* WLDEBUG */
1799 outw(PIOR0(base), tbd_p);
1800 if (clen < ETHERMIN) {
1801 outw(PIOP0(base), inw(PIOP0(base)) + ETHERMIN - clen);
1802 outw(PIOR1(base), xmtdata_p);
1803 for (xmtshort_p = xmtdata_p; clen < ETHERMIN; clen += 2)
1804 outw(PIOP1(base), 0);
1806 outw(PIOP0(base), inw(PIOP0(base)) | TBD_SW_EOF);
1807 outw(PIOR0(base), tbd_p + 2);
1808 outw(PIOP0(base), I82586NULL);
1810 if (sc->wl_if.if_flags & IFF_DEBUG) {
1816 #endif /* WLDEBUG */
1818 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
1820 * wait for 586 to clear previous command, complain if it takes
1823 for (spin = 1;;spin = (spin + 1) % 10000) {
1824 if (inw(PIOP0(base)) == 0) { /* it's done, we can go */
1827 if ((spin == 0) && xmt_watch) { /* not waking up, and we care */
1828 printf("wl%d: slow accepting xmit\n",unit);
1831 outw(PIOP0(base), SCB_CU_STRT); /* new command */
1832 SET_CHAN_ATTN(unit);
1837 * Pause to avoid transmit overrun problems.
1838 * The required delay tends to vary with platform type, and may be
1839 * related to interrupt loss.
1841 if (wl_xmit_delay) {
1842 DELAY(wl_xmit_delay);
1850 * This function builds the linear linked lists of fd's and
1851 * rbd's. Based on page 4-32 of 1986 Intel microcom handbook.
1857 register struct wl_softc *sc = WLSOFTC(unit);
1858 short base = sc->base;
1861 u_short fd_p = OFFSET_RU;
1862 u_short rbd_p = OFFSET_RBD;
1865 sc->begin_fd = fd_p;
1866 for(i = 0; i < N_FD; i++) {
1869 fd.link_offset = fd_p + sizeof(fd_t);
1870 fd.rbd_offset = I82586NULL;
1871 outw(PIOR1(base), fd_p);
1872 outsw(PIOP1(base), &fd, 8/2);
1873 fd_p = fd.link_offset;
1875 fd_p -= sizeof(fd_t);
1877 outw(PIOR1(base), fd_p + 2);
1878 outw(PIOP1(base), AC_CW_EL); /* command */
1879 outw(PIOP1(base), I82586NULL); /* link_offset */
1882 outw(PIOR0(base), fd_p + 6); /* address of rbd_offset */
1883 outw(PIOP0(base), rbd_p);
1884 outw(PIOR1(base), rbd_p);
1885 for(i = 0; i < N_RBD; i++) {
1887 rbd.buffer_addr = rbd_p + sizeof(rbd_t) + 2;
1888 rbd.buffer_base = 0;
1889 rbd.size = RCVBUFSIZE;
1891 rbd_p += sizeof(ru_t);
1892 rbd.next_rbd_offset = rbd_p;
1894 rbd.next_rbd_offset = I82586NULL;
1895 rbd.size |= AC_CW_EL;
1896 sc->end_rbd = rbd_p;
1898 outsw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1899 outw(PIOR1(base), rbd_p);
1901 return sc->begin_fd;
1907 * This routine starts the receive unit running. First checks if the
1908 * board is actually ready, then the board is instructed to receive
1915 register struct wl_softc *sc = WLSOFTC(unit);
1916 short base = sc->base;
1920 if (sc->wl_if.if_flags & IFF_DEBUG)
1921 printf("wl%d: entered wlrustrt()\n",unit);
1923 outw(PIOR0(base), OFFSET_SCB);
1924 if (inw(PIOP0(base)) & SCB_RUS_READY){
1925 printf("wlrustrt: RUS_READY\n");
1929 outw(PIOR0(base), OFFSET_SCB + 2);
1930 outw(PIOP0(base), SCB_RU_STRT); /* command */
1931 rfa = wlbldru(unit);
1932 outw(PIOR0(base), OFFSET_SCB + 6); /* address of scb_rfa_offset */
1933 outw(PIOP0(base), rfa);
1935 SET_CHAN_ATTN(unit);
1942 * This routine does a 586 op-code number 7, and obtains the
1943 * diagnose status for the WaveLAN.
1949 register struct wl_softc *sc = WLSOFTC(unit);
1950 short base = sc->base;
1954 if (sc->wl_if.if_flags & IFF_DEBUG)
1955 printf("wl%d: entered wldiag()\n",unit);
1957 outw(PIOR0(base), OFFSET_SCB);
1958 status = inw(PIOP0(base));
1959 if (status & SCB_SW_INT) {
1960 /* state is 2000 which seems ok
1961 printf("wl%d diag(): unexpected initial state %\n",
1962 unit, inw(PIOP0(base)));
1966 outw(PIOR1(base), OFFSET_CU);
1967 outw(PIOP1(base), 0); /* ac_status */
1968 outw(PIOP1(base), AC_DIAGNOSE|AC_CW_EL);/* ac_command */
1969 if(wlcmd(unit, "diag()") == 0)
1971 outw(PIOR0(base), OFFSET_CU);
1972 if (inw(PIOP0(base)) & 0x0800) {
1973 printf("wl%d: i82586 Self Test failed!\n", unit);
1982 * This routine does a standard config of the WaveLAN board.
1988 configure_t configure;
1989 register struct wl_softc *sc = WLSOFTC(unit);
1990 short base = sc->base;
1993 #if defined(__FreeBSD__) && __FreeBSD_version >= 300000
1994 struct ifmultiaddr *ifma;
1997 struct ether_multi *enm;
1998 struct ether_multistep step;
2001 #endif /* MULTICAST */
2004 if (sc->wl_if.if_flags & IFF_DEBUG)
2005 printf("wl%d: entered wlconfig()\n",unit);
2007 outw(PIOR0(base), OFFSET_SCB);
2008 if (inw(PIOP0(base)) & SCB_SW_INT) {
2010 printf("wl%d config(): unexpected initial state %x\n",
2011 unit, inw(PIOP0(base)));
2016 outw(PIOR1(base), OFFSET_CU);
2017 outw(PIOP1(base), 0); /* ac_status */
2018 outw(PIOP1(base), AC_CONFIGURE|AC_CW_EL); /* ac_command */
2021 configure.fifolim_bytecnt = 0x080c;
2022 configure.addrlen_mode = 0x0600;
2023 configure.linprio_interframe = 0x2060;
2024 configure.slot_time = 0xf200;
2025 configure.hardware = 0x0008; /* tx even w/o CD */
2026 configure.min_frame_len = 0x0040;
2028 /* This is the configuration block suggested by Marc Meertens
2029 * <mmeerten@obelix.utrecht.NCR.COM> in an e-mail message to John
2030 * Ioannidis on 10 Nov 92.
2032 configure.fifolim_bytecnt = 0x040c;
2033 configure.addrlen_mode = 0x0600;
2034 configure.linprio_interframe = 0x2060;
2035 configure.slot_time = 0xf000;
2036 configure.hardware = 0x0008; /* tx even w/o CD */
2037 configure.min_frame_len = 0x0040;
2040 * below is the default board configuration from p2-28 from 586 book
2042 configure.fifolim_bytecnt = 0x080c;
2043 configure.addrlen_mode = 0x2600;
2044 configure.linprio_interframe = 0x7820; /* IFS=120, ACS=2 */
2045 configure.slot_time = 0xf00c; /* slottime=12 */
2046 configure.hardware = 0x0008; /* tx even w/o CD */
2047 configure.min_frame_len = 0x0040;
2049 if(sc->mode & (MOD_PROM | MOD_ENAL)) {
2050 configure.hardware |= 1;
2052 outw(PIOR1(base), OFFSET_CU + 6);
2053 outsw(PIOP1(base), &configure, sizeof(configure_t)/2);
2055 if(wlcmd(unit, "config()-configure") == 0)
2058 outw(PIOR1(base), OFFSET_CU);
2059 outw(PIOP1(base), 0); /* ac_status */
2060 outw(PIOP1(base), AC_MCSETUP|AC_CW_EL); /* ac_command */
2061 outw(PIOR1(base), OFFSET_CU + 8);
2062 #if defined(__FreeBSD__) && __FreeBSD_version >= 300000
2063 TAILQ_FOREACH(ifma, &sc->wl_if.if_multiaddrs, ifma_link) {
2064 if (ifma->ifma_addr->sa_family != AF_LINK)
2067 addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
2068 outw(PIOP1(base), addrp[0] + (addrp[1] << 8));
2069 outw(PIOP1(base), addrp[2] + (addrp[3] << 8));
2070 outw(PIOP1(base), addrp[4] + (addrp[5] << 8));
2074 ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2075 while (enm != NULL) {
2076 unsigned int lo, hi;
2077 /* break if setting a multicast range, else we would crash */
2078 if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2081 lo = (enm->enm_addrlo[3] << 16) + (enm->enm_addrlo[4] << 8)
2082 + enm->enm_addrlo[5];
2083 hi = (enm->enm_addrhi[3] << 16) + (enm->enm_addrhi[4] << 8)
2084 + enm->enm_addrhi[5];
2086 outw(PIOP1(base),enm->enm_addrlo[0] +
2087 (enm->enm_addrlo[1] << 8));
2088 outw(PIOP1(base),enm->enm_addrlo[2] +
2089 ((lo >> 8) & 0xff00));
2090 outw(PIOP1(base), ((lo >> 8) & 0xff) +
2091 ((lo << 8) & 0xff00));
2092 /* #define MCASTDEBUG */
2094 printf("mcast_addr[%d,%d,%d] %x %x %x %x %x %x\n", lo, hi, cnt,
2100 enm->enm_addrlo[5]);
2105 ETHER_NEXT_MULTI(step, enm);
2108 outw(PIOR1(base), OFFSET_CU + 6); /* mc-cnt */
2109 outw(PIOP1(base), cnt * WAVELAN_ADDR_SIZE);
2110 if(wlcmd(unit, "config()-mcaddress") == 0)
2112 #endif /* MULTICAST */
2114 outw(PIOR1(base), OFFSET_CU);
2115 outw(PIOP1(base), 0); /* ac_status */
2116 outw(PIOP1(base), AC_IASETUP|AC_CW_EL); /* ac_command */
2117 outw(PIOR1(base), OFFSET_CU + 6);
2118 outsw(PIOP1(base), sc->wl_addr, WAVELAN_ADDR_SIZE/2);
2120 if(wlcmd(unit, "config()-address") == 0)
2131 * Set channel attention bit and busy wait until command has
2132 * completed. Then acknowledge the command completion.
2135 wlcmd(int unit, char *str)
2137 register struct wl_softc *sc = WLSOFTC(unit);
2138 short base = sc->base;
2141 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
2142 outw(PIOP0(base), SCB_CU_STRT);
2144 SET_CHAN_ATTN(unit);
2146 outw(PIOR0(base), OFFSET_CU);
2147 for(i = 0; i < 0xffff; i++)
2148 if (inw(PIOP0(base)) & AC_SW_C)
2150 if (i == 0xffff || !(inw(PIOP0(base)) & AC_SW_OK)) {
2151 printf("wl%d: %s failed; status = %d, inw = %x, outw = %x\n",
2152 unit, str, inw(PIOP0(base)) & AC_SW_OK, inw(PIOP0(base)), inw(PIOR0(base)));
2153 outw(PIOR0(base), OFFSET_SCB);
2154 printf("scb_status %x\n", inw(PIOP0(base)));
2155 outw(PIOR0(base), OFFSET_SCB+2);
2156 printf("scb_command %x\n", inw(PIOP0(base)));
2157 outw(PIOR0(base), OFFSET_SCB+4);
2158 printf("scb_cbl %x\n", inw(PIOP0(base)));
2159 outw(PIOR0(base), OFFSET_CU+2);
2160 printf("cu_cmd %x\n", inw(PIOP0(base)));
2164 outw(PIOR0(base), OFFSET_SCB);
2165 if ((inw(PIOP0(base)) & SCB_SW_INT) && (inw(PIOP0(base)) != SCB_SW_CNA)) {
2167 printf("wl%d %s: unexpected final state %x\n",
2168 unit, str, inw(PIOP0(base)));
2176 * wlack: if the 82596 wants attention because it has finished
2177 * sending or receiving a packet, acknowledge its desire and
2178 * return bits indicating the kind of attention. wlack() returns
2179 * these bits so that the caller can service exactly the
2180 * conditions that wlack() acknowledged.
2186 register u_short cmd;
2187 register struct wl_softc *sc = WLSOFTC(unit);
2188 short base = sc->base;
2190 outw(PIOR1(base), OFFSET_SCB);
2191 if(!(cmd = (inw(PIOP1(base)) & SCB_SW_INT)))
2194 if (sc->wl_if.if_flags & IFF_DEBUG)
2195 printf("wl%d: doing a wlack()\n",unit);
2197 outw(PIOP1(base), cmd);
2198 SET_CHAN_ATTN(unit);
2199 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
2200 for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
2202 printf("wl%d wlack(): board not accepting command.\n", unit);
2209 register struct wl_softc *sc = WLSOFTC(unit);
2210 short base = sc->base;
2211 u_short tbd_p = OFFSET_TBD;
2217 outw(PIOR1(base), tbd_p);
2218 insw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
2219 sum += (tbd.act_count & ~TBD_SW_EOF);
2220 printf("%d: addr %x, count %d (%d), next %x, base %x\n",
2221 i++, tbd.buffer_addr,
2222 (tbd.act_count & ~TBD_SW_EOF), sum,
2223 tbd.next_tbd_offset, tbd.buffer_base);
2224 if (tbd.act_count & TBD_SW_EOF)
2226 tbd_p = tbd.next_tbd_offset;
2231 wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2233 struct mbuf *tm_p = *tm_pp;
2234 u_char *mb_p = *mb_pp;
2240 * can we get a run that will be coallesced or
2241 * that terminates before breaking
2244 count += tm_p->m_len;
2245 if (tm_p->m_len & 1)
2247 } while ((tm_p = tm_p->m_next) != (struct mbuf *)0);
2248 if ( (tm_p == (struct mbuf *)0) ||
2249 count > HDW_THRESHOLD) {
2250 *countp = (*tm_pp)->m_len;
2251 *mb_pp = mtod((*tm_pp), u_char *);
2255 /* we need to copy */
2259 cp = (u_char *) t_packet;
2261 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2263 if (count > HDW_THRESHOLD)
2266 if (tm_p->m_next == (struct mbuf *)0)
2268 tm_p = tm_p->m_next;
2271 *mb_pp = (u_char *) t_packet;
2278 wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2280 struct mbuf *tm_p = *tm_pp;
2282 u_char *cp = (u_char *) t_packet;
2285 /* we need to copy */
2287 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2290 if (tm_p->m_next == (struct mbuf *)0)
2292 tm_p = tm_p->m_next;
2296 *mb_pp = (u_char *) t_packet;
2304 register struct wl_softc *sc = WLSOFTC(unit);
2305 short base = sc->base;
2308 printf("wl%d: DCE_STATUS: 0x%x, ", unit,
2309 wlmmcread(base,MMC_DCE_STATUS) & 0x0f);
2310 tmp = wlmmcread(base,MMC_CORRECT_NWID_H) << 8;
2311 tmp |= wlmmcread(base,MMC_CORRECT_NWID_L);
2312 printf("Correct NWID's: %d, ", tmp);
2313 tmp = wlmmcread(base,MMC_WRONG_NWID_H) << 8;
2314 tmp |= wlmmcread(base,MMC_WRONG_NWID_L);
2315 printf("Wrong NWID's: %d\n", tmp);
2316 printf("THR_PRE_SET: 0x%x, ", wlmmcread(base,MMC_THR_PRE_SET));
2317 printf("SIGNAL_LVL: %d, SILENCE_LVL: %d\n",
2318 wlmmcread(base,MMC_SIGNAL_LVL),
2319 wlmmcread(base,MMC_SILENCE_LVL));
2320 printf("SIGN_QUAL: 0x%x, NETW_ID: %x:%x, DES: %d\n",
2321 wlmmcread(base,MMC_SIGN_QUAL),
2322 wlmmcread(base,MMC_NETW_ID_H),
2323 wlmmcread(base,MMC_NETW_ID_L),
2324 wlmmcread(base,MMC_DES_AVAIL));
2328 wlmmcread(u_int base, u_short reg)
2330 while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2331 outw(MMCR(base),reg << 1);
2332 while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2333 return (u_short)inw(MMCR(base)) >> 8;
2339 MMC_WRITE(MMC_FREEZE,1);
2341 * SNR retrieval procedure :
2343 * read signal level : wlmmcread(base, MMC_SIGNAL_LVL);
2344 * read silence level : wlmmcread(base, MMC_SILENCE_LVL);
2346 MMC_WRITE(MMC_FREEZE,0);
2348 * SNR is signal:silence ratio.
2355 ** Reads the psa for the wavelan at (base) into (buf)
2358 wlgetpsa(int base, u_char *buf)
2362 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2363 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2365 for (i = 0; i < 0x40; i++) {
2366 outw(PIOR2(base), i);
2367 buf[i] = inb(PIOP2(base));
2369 PCMD(base, HACR_DEFAULT);
2370 PCMD(base, HACR_DEFAULT);
2376 ** Writes the psa for wavelan (unit) from the softc back to the
2377 ** board. Updates the CRC and sets the CRC OK flag.
2379 ** Do not call this when the board is operating, as it doesn't
2380 ** preserve the hacr.
2385 register struct wl_softc *sc = WLSOFTC(unit);
2386 short base = sc->base;
2390 crc = wlpsacrc(sc->psa); /* calculate CRC of PSA */
2391 sc->psa[WLPSA_CRCLOW] = crc & 0xff;
2392 sc->psa[WLPSA_CRCHIGH] = (crc >> 8) & 0xff;
2393 sc->psa[WLPSA_CRCOK] = 0x55; /* default to 'bad' until programming complete */
2395 oldpri = splimp(); /* ick, long pause */
2397 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2398 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2400 for (i = 0; i < 0x40; i++) {
2402 outw(PIOR2(base),i); /* write param memory */
2404 outb(PIOP2(base), sc->psa[i]);
2407 outw(PIOR2(base),WLPSA_CRCOK); /* update CRC flag*/
2409 sc->psa[WLPSA_CRCOK] = 0xaa; /* OK now */
2410 outb(PIOP2(base), 0xaa); /* all OK */
2413 PCMD(base, HACR_DEFAULT);
2414 PCMD(base, HACR_DEFAULT);
2420 ** CRC routine provided by Christopher Giordano <cgiordan@gdeb.com>,
2421 ** from original code by Tomi Mikkonen (tomitm@remedy.fi)
2424 static u_int crc16_table[16] = {
2425 0x0000, 0xCC01, 0xD801, 0x1400,
2426 0xF001, 0x3C00, 0x2800, 0xE401,
2427 0xA001, 0x6C00, 0x7800, 0xB401,
2428 0x5000, 0x9C01, 0x8801, 0x4400
2432 wlpsacrc(u_char *buf)
2437 for (i = 0; i < 0x3d; i++, buf++) {
2439 r1 = crc16_table[crc & 0xF];
2440 crc = (crc >> 4) & 0x0FFF;
2441 crc = crc ^ r1 ^ crc16_table[*buf & 0xF];
2444 r1 = crc16_table[crc & 0xF];
2445 crc = (crc >> 4) & 0x0FFF;
2446 crc = crc ^ r1 ^ crc16_table[(*buf >> 4) & 0xF];
2455 * take input packet and cache various radio hw characteristics
2456 * indexed by MAC address.
2458 * Some things to think about:
2459 * note that no space is malloced.
2460 * We might hash the mac address if the cache were bigger.
2461 * It is not clear that the cache is big enough.
2462 * It is also not clear how big it should be.
2463 * The cache is IP-specific. We don't care about that as
2464 * we want it to be IP-specific.
2465 * The last N recv. packets are saved. This will tend
2466 * to reward agents and mobile hosts that beacon.
2467 * That is probably fine for mobile ip.
2470 /* globals for wavelan signal strength cache */
2471 /* this should go into softc structure above.
2474 /* set true if you want to limit cache items to broadcast/mcast
2475 * only packets (not unicast)
2477 static int wl_cache_mcastonly = 1;
2478 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_mcastonly, CTLFLAG_RW,
2479 &wl_cache_mcastonly, 0, "");
2481 /* set true if you want to limit cache items to IP packets only
2483 static int wl_cache_iponly = 1;
2484 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_iponly, CTLFLAG_RW,
2485 &wl_cache_iponly, 0, "");
2487 /* zero out the cache
2490 wl_cache_zero(int unit)
2492 register struct wl_softc *sc = WLSOFTC(unit);
2494 bzero(&sc->w_sigcache[0], sizeof(struct w_sigcache) * MAXCACHEITEMS);
2496 sc->w_nextcache = 0;
2497 sc->w_wrapindex = 0;
2500 /* store hw signal info in cache.
2501 * index is MAC address, but an ip src gets stored too
2502 * There are two filters here controllable via sysctl:
2503 * throw out unicast (on by default, but can be turned off)
2504 * throw out non-ip (on by default, but can be turned off)
2507 void wl_cache_store (int unit, int base, struct ether_header *eh,
2510 struct ip *ip = NULL; /* Avoid GCC warning */
2512 int signal, silence;
2513 int w_insertcache; /* computed index for cache entry storage */
2514 register struct wl_softc *sc = WLSOFTC(unit);
2515 int ipflag = wl_cache_iponly;
2519 * 2. configurable filter to throw out unicast packets,
2520 * keep multicast only.
2524 /* reject if not IP packet
2526 if ( wl_cache_iponly && (ntohs(eh->ether_type) != 0x800)) {
2530 /* check if broadcast or multicast packet. we toss
2533 if (wl_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
2537 /* find the ip header. we want to store the ip_src
2538 * address. use the mtod macro(in mbuf.h)
2539 * to typecast m to struct ip *
2542 ip = mtod(m, struct ip *);
2545 /* do a linear search for a matching MAC address
2546 * in the cache table
2547 * . MAC address is 6 bytes,
2548 * . var w_nextcache holds total number of entries already cached
2550 for(i = 0; i < sc->w_nextcache; i++) {
2551 if (! bcmp(eh->ether_shost, sc->w_sigcache[i].macsrc, 6 )) {
2553 * so we already have this entry,
2554 * update the data, and LRU age
2560 /* did we find a matching mac address?
2561 * if yes, then overwrite a previously existing cache entry
2563 if (i < sc->w_nextcache ) {
2566 /* else, have a new address entry,so
2567 * add this new entry,
2568 * if table full, then we need to replace entry
2572 /* check for space in cache table
2573 * note: w_nextcache also holds number of entries
2574 * added in the cache table
2576 if ( sc->w_nextcache < MAXCACHEITEMS ) {
2577 w_insertcache = sc->w_nextcache;
2579 sc->w_sigitems = sc->w_nextcache;
2581 /* no space found, so simply wrap with wrap index
2582 * and "zap" the next entry
2585 if (sc->w_wrapindex == MAXCACHEITEMS) {
2586 sc->w_wrapindex = 0;
2588 w_insertcache = sc->w_wrapindex++;
2592 /* invariant: w_insertcache now points at some slot
2595 if (w_insertcache < 0 || w_insertcache >= MAXCACHEITEMS) {
2597 "wl_cache_store, bad index: %d of [0..%d], gross cache error\n",
2598 w_insertcache, MAXCACHEITEMS);
2602 /* store items in cache
2605 * .signal (0..63) ,silence (0..63) ,quality (0..15)
2608 sc->w_sigcache[w_insertcache].ipsrc = ip->ip_src.s_addr;
2610 bcopy( eh->ether_shost, sc->w_sigcache[w_insertcache].macsrc, 6);
2611 signal = sc->w_sigcache[w_insertcache].signal = wlmmcread(base, MMC_SIGNAL_LVL) & 0x3f;
2612 silence = sc->w_sigcache[w_insertcache].silence = wlmmcread(base, MMC_SILENCE_LVL) & 0x3f;
2613 sc->w_sigcache[w_insertcache].quality = wlmmcread(base, MMC_SIGN_QUAL) & 0x0f;
2615 sc->w_sigcache[w_insertcache].snr =
2618 sc->w_sigcache[w_insertcache].snr = 0;
2622 #endif /* WLCACHE */
2625 * determine if in all multicast mode or not
2627 * returns: 1 if IFF_ALLMULTI should be set
2632 #if defined(__FreeBSD__) && __FreeBSD_version < 300000 /* not required */
2634 check_allmulti(int unit)
2636 register struct wl_softc *sc = WLSOFTC(unit);
2637 short base = sc->base;
2638 struct ether_multi *enm;
2639 struct ether_multistep step;
2641 ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2642 while (enm != NULL) {
2643 unsigned int lo, hi;
2645 printf("enm_addrlo %x:%x:%x:%x:%x:%x\n", enm->enm_addrlo[0], enm->enm_addrlo[1],
2646 enm->enm_addrlo[2], enm->enm_addrlo[3], enm->enm_addrlo[4],
2647 enm->enm_addrlo[5]);
2648 printf("enm_addrhi %x:%x:%x:%x:%x:%x\n", enm->enm_addrhi[0], enm->enm_addrhi[1],
2649 enm->enm_addrhi[2], enm->enm_addrhi[3], enm->enm_addrhi[4],
2650 enm->enm_addrhi[5]);
2652 if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2655 ETHER_NEXT_MULTI(step, enm);