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.20 2005/06/14 11:41:37 joerg Exp $ */
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain all copyright
8 * notices, this list of conditions and the following disclaimer.
9 * 2. The names of the authors may not be used to endorse or promote products
10 * derived from this software withough specific prior written permission
12 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
13 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
14 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
15 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
16 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
17 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
18 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
19 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
21 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 * if_wl.c - original MACH, then BSDI ISA wavelan driver
26 * ported to mach by Anders Klemets
27 * to BSDI by Robert Morris
28 * to FreeBSD by Jim Binkley
29 * to FreeBSD 2.2+ by Michael Smith
32 * Changed interface to match 2.1-2.2 differences.
33 * Implement IRQ selection logic in wlprobe()
34 * Implement PSA updating.
35 * Pruned heading comments for relevance.
36 * Ripped out all the 'interface counters' cruft.
37 * Cut the missing-interrupt timer back to 100ms.
39 * now supports all multicast mode (mrouted will work),
40 * but unfortunately must do that by going into promiscuous mode
41 * NWID sysctl added so that normally promiscuous mode is NWID-specific
42 * but can be made NWID-inspecific
46 * Ported to FreeBSD, got promiscuous mode working with bpfs,
47 * and rewired timer routine. The i82586 will hang occasionally on output
48 * and the watchdog timer will kick it if so and log an entry.
49 * 2 second timeout there. Apparently the chip loses an interrupt.
50 * Code borrowed from if_ie.c for watchdog timer.
52 * The wavelan card is a 2mbit radio modem that emulates ethernet;
53 * i.e., it uses MAC addresses. This should not be a surprise since
54 * it uses an ethernet controller as a major hw item.
55 * It can broadcast, unicast or apparently multicast in a base cell
56 * using a omni-directional antennae that is
57 * about 800 feet around the base cell barring walls and metal.
58 * With directional antennae, it can be used point to point over a mile
59 * or so apparently (haven't tried that).
61 * There are ISA and pcmcia versions (not supported by this code).
62 * The ISA card has an Intel 82586 lan controller on it. It consists
63 * of 2 pieces of hw, the lan controller (intel) and a radio-modem.
64 * The latter has an extra set of controller registers that has nothing
65 * to do with the i82586 and allows setting and monitoring of radio
66 * signal strength, etc. There is a nvram area called the PSA that
67 * contains a number of setup variables including the IRQ and so-called
68 * NWID or Network ID. The NWID must be set the same for all radio
69 * cards to communicate (unless you are using the ATT/NCR roaming feature
70 * with their access points. There is no support for that here. Roaming
71 * involves a link-layer beacon sent out from the access points. End
72 * stations monitor the signal strength and only use the strongest
73 * access point). This driver assumes that the base ISA port, IRQ,
74 * and NWID are first set in nvram via the dos-side "instconf.exe" utility
75 * supplied with the card. This driver takes the ISA port from
76 * the kernel configuration setup, and then determines the IRQ either
77 * from the kernel config (if an explicit IRQ is set) or from the
78 * PSA on the card if not.
79 * The hw also magically just uses the IRQ set in the nvram.
80 * The NWID is used magically as well by the radio-modem
81 * to determine which packets to keep or throw out.
85 * device wl0 at isa? port 0x300 net irq ?
88 * 1. WLDEBUG. (off) - if turned on enables IFF_DEBUG set via ifconfig debug
89 * 2. MULTICAST (on) - turned on and works up to and including mrouted
90 * 3. WLCACHE (off) - define to turn on a signal strength
91 * (and other metric) cache that is indexed by sender MAC address.
92 * Apps can read this out to learn the remote signal strength of a
93 * sender. Note that it has a switch so that it only stores
94 * broadcast/multicast senders but it could be set to store unicast
95 * too only. Size is hardwired in if_wl_wavelan.h
97 * one further note: promiscuous mode is a curious thing. In this driver,
98 * promiscuous mode apparently CAN catch ALL packets and ignore the NWID
99 * setting. This is probably more useful in a sense (for snoopers) if
100 * you are interested in all traffic as opposed to if you are interested
101 * in just your own. There is a driver specific sysctl to turn promiscuous
102 * from just promiscuous to wildly promiscuous...
104 * This driver also knows how to load the synthesizers in the 2.4 Gz
105 * ISA Half-card, Product number 847647476 (USA/FCC IEEE Channel set).
106 * This product consists of a "mothercard" that contains the 82586,
107 * NVRAM that holds the PSA, and the ISA-buss interface custom ASIC.
108 * The radio transceiver is a "daughtercard" called the WaveMODEM which
109 * connects to the mothercard through two single-inline connectors: a
110 * 20-pin connector provides DC-power and modem signals, and a 3-pin
111 * connector which exports the antenna connection. The code herein
112 * loads the receive and transmit synthesizers and the corresponding
113 * transmitter output power value from an EEPROM controlled through
114 * additional registers via the MMC. The EEPROM address selected
115 * are those whose values are preset by the DOS utility programs
116 * provided with the product, and this provides compatible operation
117 * with the DOS Packet Driver software. A future modification will
118 * add the necessary functionality to this driver and to the wlconfig
119 * utility to completely replace the DOS Configuration Utilities.
120 * The 2.4 Gz WaveMODEM is described in document number 407-024692/E,
121 * and is available through Lucent Technologies OEM supply channels.
128 * Olivetti PC586 Mach Ethernet driver v1.0
129 * Copyright Ing. C. Olivetti & C. S.p.A. 1988, 1989
130 * All rights reserved.
135 Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc.,
136 Cupertino, California.
140 Permission to use, copy, modify, and distribute this software and
141 its documentation for any purpose and without fee is hereby
142 granted, provided that the above copyright notice appears in all
143 copies and that both the copyright notice and this permission notice
144 appear in supporting documentation, and that the name of Olivetti
145 not be used in advertising or publicity pertaining to distribution
146 of the software without specific, written prior permission.
148 OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
149 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
150 IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
151 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
152 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
153 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
154 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
158 Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
162 Permission to use, copy, modify, and distribute this software and
163 its documentation for any purpose and without fee is hereby
164 granted, provided that the above copyright notice appears in all
165 copies and that both the copyright notice and this permission notice
166 appear in supporting documentation, and that the name of Intel
167 not be used in advertising or publicity pertaining to distribution
168 of the software without specific, written prior permission.
170 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
171 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
172 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
173 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
174 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
175 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
176 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
182 * 1. The best book on the 82586 is:
183 * LAN Components User's Manual by Intel
184 * The copy I found was dated 1984. This really tells you
185 * what the state machines are doing
186 * 2. In the current design, we only do one write at a time,
187 * though the hardware is capable of chaining and possibly
188 * even batching. The problem is that we only make one
189 * transmit buffer available in sram space.
193 #include "opt_wavelan.h"
194 #include "opt_inet.h"
196 #include <sys/param.h>
197 #include <sys/systm.h>
198 #include <sys/sockio.h>
199 #include <sys/mbuf.h>
200 #include <sys/socket.h>
201 #include <sys/syslog.h>
202 #include <sys/proc.h>
203 #include <sys/thread2.h>
205 #include <sys/kernel.h>
206 #include <sys/sysctl.h>
208 #include <net/ethernet.h>
210 #include <net/ifq_var.h>
211 #include <net/if_dl.h>
214 #include <netinet/in.h>
215 #include <netinet/in_systm.h>
216 #include <netinet/ip.h>
217 #include <netinet/if_ether.h>
222 #include <machine/clock.h>
224 #include <bus/isa/i386/isa_device.h>
225 #include "if_wl_i82586.h" /* Definitions for the Intel chip */
227 /* was 1000 in original, fed to DELAY(x) */
228 #define DELAYCONST 1000
230 #include <machine/if_wl_wavelan.h>
232 static char t_packet[ETHERMTU + sizeof(struct ether_header) + sizeof(long)];
235 struct arpcom wl_ac; /* Ethernet common part */
236 #define wl_if wl_ac.ac_if /* network visible interface */
237 #define wl_addr wl_ac.ac_enaddr /* hardware address */
239 u_char nwid[2]; /* current radio modem nwid */
243 int tbusy; /* flag to determine if xmit is busy */
247 u_short hacr; /* latest host adapter CR command */
249 u_char chan24; /* 2.4 Gz: channel number/EEPROM Area # */
250 u_short freq24; /* 2.4 Gz: resulting frequency */
251 struct callout watchdog_ch;
253 int w_sigitems; /* number of cached entries */
254 /* array of cache entries */
255 struct w_sigcache w_sigcache[ MAXCACHEITEMS ];
256 int w_nextcache; /* next free cache entry */
257 int w_wrapindex; /* next "free" cache entry */
260 static struct wl_softc wl_softc[NWL];
262 #define WLSOFTC(unit) ((struct wl_softc *)(&wl_softc[unit]))
264 static int wlprobe(struct isa_device *);
265 static int wlattach(struct isa_device *);
267 DECLARE_DUMMY_MODULE(if_wl);
269 struct isa_driver wldriver = {
270 wlprobe, wlattach, "wl", 0
274 * XXX The Wavelan appears to be prone to dropping stuff if you talk to
275 * it too fast. This disgusting hack inserts a delay after each packet
276 * is queued which helps avoid this behaviour on fast systems.
278 static int wl_xmit_delay = 250;
279 SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_delay, CTLFLAG_RW, &wl_xmit_delay, 0, "");
282 * not XXX, but ZZZ (bizarre).
283 * promiscuous mode can be toggled to ignore NWIDs. By default,
284 * it does not. Caution should be exercised about combining
285 * this mode with IFF_ALLMULTI which puts this driver in
288 static int wl_ignore_nwid = 0;
289 SYSCTL_INT(_machdep, OID_AUTO, wl_ignore_nwid, CTLFLAG_RW, &wl_ignore_nwid, 0, "");
292 * Emit diagnostics about transmission problems
294 static int xmt_watch = 0;
295 SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_watch, CTLFLAG_RW, &xmt_watch, 0, "");
298 * Collect SNR statistics
300 static int gathersnr = 0;
301 SYSCTL_INT(_machdep, OID_AUTO, wl_gather_snr, CTLFLAG_RW, &gathersnr, 0, "");
303 static void wlstart(struct ifnet *ifp);
304 static void wlinit(void *xsc);
305 static int wlioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *);
306 static timeout_t wlwatchdog;
307 static ointhand2_t wlintr;
308 static void wlxmt(int unt, struct mbuf *m);
309 static int wldiag(int unt);
310 static int wlconfig(int unit);
311 static int wlcmd(int unit, char *str);
312 static void wlmmcstat(int unit);
313 static u_short wlbldru(int unit);
314 static u_short wlmmcread(u_int base, u_short reg);
315 static void wlinitmmc(int unit);
316 static int wlhwrst(int unit);
317 static void wlrustrt(int unit);
318 static void wlbldcu(int unit);
319 static int wlack(int unit);
320 static int wlread(int unit, u_short fd_p);
321 static void getsnr(int unit);
322 static void wlrcv(int unit);
323 static int wlrequeue(int unit, u_short fd_p);
324 static void wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
325 static void wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
326 static void wltbd(int unit);
327 static void wlgetpsa(int base, u_char *buf);
328 static void wlsetpsa(int unit);
329 static u_short wlpsacrc(u_char *buf);
330 static void wldump(int unit);
332 static void wl_cache_store(int, int, struct ether_header *, struct mbuf *);
333 static void wl_cache_zero(int unit);
336 # if defined(__FreeBSD__) && __FreeBSD_version < 300000
337 static int check_allmulti(int unit);
341 /* array for maping irq numbers to values for the irq parameter register */
342 static int irqvals[16] = {
343 0, 0, 0, 0x01, 0x02, 0x04, 0, 0x08, 0, 0, 0x10, 0x20, 0x40, 0, 0, 0x80
345 /* mask of valid IRQs */
346 #define WL_IRQS (IRQ3|IRQ4|IRQ5|IRQ7|IRQ10|IRQ11|IRQ12|IRQ15)
351 * This function "probes" or checks for the WaveLAN board on the bus to
352 * see if it is there. As far as I can tell, the best break between this
353 * routine and the attach code is to simply determine whether the board
354 * is configured in properly. Currently my approach to this is to write
355 * and read a word from the SRAM on the board being probed. If the word
356 * comes back properly then we assume the board is there. The config
357 * code expects to see a successful return from the probe routine before
358 * attach will be called.
360 * input : address device is mapped to, and unit # being checked
361 * output : a '1' is returned if the board exists, and a 0 otherwise
365 wlprobe(struct isa_device *id)
367 struct wl_softc *sc = &wl_softc[id->id_unit];
368 short base = id->id_iobase;
369 char *str = "wl%d: board out of range [0..%d]\n";
374 * regular CMD() will not work, since no softc yet
376 #define PCMD(base, hacr) outw((base), (hacr))
379 PCMD(base, HACR_RESET); /* reset the board */
380 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
381 PCMD(base, HACR_RESET); /* reset the board */
382 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
385 /* clear reset command and set PIO#1 in autoincrement mode */
386 PCMD(base, HACR_DEFAULT);
387 PCMD(base, HACR_DEFAULT);
388 outw(PIOR1(base), 0); /* go to beginning of RAM */
389 outsw(PIOP1(base), str, strlen(str)/2+1); /* write string */
391 outw(PIOR1(base), 0); /* rewind */
392 insw(PIOP1(base), inbuf, strlen(str)/2+1); /* read result */
394 if (bcmp(str, inbuf, strlen(str)))
397 sc->chan24 = 0; /* 2.4 Gz: config channel */
398 sc->freq24 = 0; /* 2.4 Gz: frequency */
400 /* read the PSA from the board into temporary storage */
401 wlgetpsa(base, inbuf);
403 /* We read the IRQ value from the PSA on the board. */
404 for (irq = 15; irq >= 0; irq--)
405 if (irqvals[irq] == inbuf[WLPSA_IRQNO])
407 if ((irq == 0) || (irqvals[irq] == 0)){
408 printf("wl%d: PSA corrupt (invalid IRQ value)\n", id->id_unit);
409 id->id_irq = 0; /* no interrupt */
412 * If the IRQ requested by the PSA is already claimed by another
413 * device, the board won't work, but the user can still access the
414 * driver to change the IRQ.
416 id->id_irq = (1<<irq); /* use IRQ from PSA */
425 * This function attaches a WaveLAN board to the "system". The rest of
426 * runtime structures are initialized here (this routine is called after
427 * a successful probe of the board). Once the ethernet address is read
428 * and stored, the board's ifnet structure is attached and readied.
430 * input : isa_dev structure setup in autoconfig
431 * output : board structs and ifnet is setup
435 wlattach(struct isa_device *id)
437 struct wl_softc *sc = (struct wl_softc *) &wl_softc[id->id_unit];
438 short base = id->id_iobase;
440 u_char unit = id->id_unit;
441 struct ifnet *ifp = &sc->wl_if;
444 printf("wlattach: base %x, unit %d\n", base, unit);
446 id->id_ointr = wlintr;
451 sc->hacr = HACR_RESET;
452 callout_init(&sc->watchdog_ch);
453 CMD(unit); /* reset the board */
454 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
456 /* clear reset command and set PIO#2 in parameter access mode */
457 sc->hacr = (HACR_DEFAULT & ~HACR_16BITS);
460 /* Read the PSA from the board for our later reference */
461 wlgetpsa(base, sc->psa);
464 sc->nwid[0] = sc->psa[WLPSA_NWID];
465 sc->nwid[1] = sc->psa[WLPSA_NWID+1];
467 /* fetch MAC address - decide which one first */
468 if (sc->psa[WLPSA_MACSEL] & 1) {
473 for(i=0; i < WAVELAN_ADDR_SIZE; ++i) {
474 sc->wl_addr[i] = sc->psa[j + i];
477 /* enter normal 16 bit mode operation */
478 sc->hacr = HACR_DEFAULT;
482 outw(PIOR1(base), OFFSET_SCB + 8); /* address of scb_crcerrs */
483 outw(PIOP1(base), 0); /* clear scb_crcerrs */
484 outw(PIOP1(base), 0); /* clear scb_alnerrs */
485 outw(PIOP1(base), 0); /* clear scb_rscerrs */
486 outw(PIOP1(base), 0); /* clear scb_ovrnerrs */
488 bzero(ifp, sizeof(ifp));
490 if_initname(ifp, "wl", id->id_unit);
491 ifp->if_mtu = WAVELAN_MTU;
492 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
494 ifp->if_flags |= IFF_DEBUG;
497 ifp->if_flags |= IFF_MULTICAST;
498 #endif /* MULTICAST */
499 ifp->if_init = wlinit;
500 ifp->if_start = wlstart;
501 ifp->if_ioctl = wlioctl;
502 ifp->if_timer = 0; /* paranoia */
508 ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN);
509 ifq_set_ready(&ifp->if_snd);
510 ether_ifattach(ifp, sc->wl_ac.ac_enaddr);
512 bcopy(&sc->wl_addr[0], sc->wl_ac.ac_enaddr, WAVELAN_ADDR_SIZE);
513 if_printf(ifp, "NWID 0x%02x%02x", 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 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 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 struct wl_softc *sc = xsc;
669 struct ifnet *ifp = &sc->wl_if;
673 if (sc->wl_if.if_flags & IFF_DEBUG)
674 printf("wl%d: entered wlinit()\n",sc->unit);
677 if ((stat = wlhwrst(sc->unit)) == TRUE) {
678 sc->wl_if.if_flags |= IFF_RUNNING; /* same as DSF_RUNNING */
680 * OACTIVE is used by upper-level routines
683 sc->wl_if.if_flags &= ~IFF_OACTIVE; /* same as tbusy below */
685 sc->flags |= DSF_RUNNING;
687 callout_stop(&sc->watchdog_ch);
691 printf("wl%d init(): trouble resetting board.\n", sc->unit);
699 * This routine resets the WaveLAN board that corresponds to the
700 * board number passed in.
702 * input : board number to do a hardware reset
703 * output : board is reset
709 struct wl_softc *sc = WLSOFTC(unit);
712 if (sc->wl_if.if_flags & IFF_DEBUG)
713 printf("wl%d: entered wlhwrst()\n",unit);
715 sc->hacr = HACR_RESET;
716 CMD(unit); /* reset the board */
718 /* clear reset command and set PIO#1 in autoincrement mode */
719 sc->hacr = HACR_DEFAULT;
723 if (sc->wl_if.if_flags & IFF_DEBUG)
724 wlmmcstat(unit); /* Display MMC registers */
726 wlbldcu(unit); /* set up command unit structures */
728 if (wldiag(unit) == 0)
731 if (wlconfig(unit) == 0)
734 * insert code for loopback test here
736 wlrustrt(unit); /* start receive unit */
738 /* enable interrupts */
739 sc->hacr = (HACR_DEFAULT | HACR_INTRON);
748 * This function builds up the command unit structures. It inits
749 * the scp, iscp, scb, cb, tbd, and tbuf.
755 struct wl_softc *sc = WLSOFTC(unit);
756 short base = sc->base;
764 bzero(&scp, sizeof(scp));
766 scp.scp_iscp = OFFSET_ISCP;
767 scp.scp_iscp_base = 0;
768 outw(PIOR1(base), OFFSET_SCP);
769 outsw(PIOP1(base), &scp, sizeof(scp_t)/2);
771 bzero(&iscp, sizeof(iscp));
773 iscp.iscp_scb_offset = OFFSET_SCB;
775 iscp.iscp_scb_base = 0;
776 outw(PIOR1(base), OFFSET_ISCP);
777 outsw(PIOP1(base), &iscp, sizeof(iscp_t)/2);
780 scb.scb_command = SCB_RESET;
781 scb.scb_cbl_offset = OFFSET_CU;
782 scb.scb_rfa_offset = OFFSET_RU;
786 scb.scb_ovrnerrs = 0;
787 outw(PIOR1(base), OFFSET_SCB);
788 outsw(PIOP1(base), &scb, sizeof(scb_t)/2);
792 outw(PIOR0(base), OFFSET_ISCP + 0); /* address of iscp_busy */
793 for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
794 if (i <= 0) printf("wl%d bldcu(): iscp_busy timeout.\n", unit);
795 outw(PIOR0(base), OFFSET_SCB + 0); /* address of scb_status */
796 for (i = STATUS_TRIES; i-- > 0; ) {
797 if (inw(PIOP0(base)) == (SCB_SW_CX|SCB_SW_CNA))
801 printf("wl%d bldcu(): not ready after reset.\n", unit);
805 cb.ac_command = AC_CW_EL; /* NOP */
806 cb.ac_link_offset = OFFSET_CU;
807 outw(PIOR1(base), OFFSET_CU);
808 outsw(PIOP1(base), &cb, 6/2);
811 tbd.next_tbd_offset = I82586NULL;
814 outw(PIOR1(base), OFFSET_TBD);
815 outsw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
823 * input : board number
824 * output : stuff sent to board if any there
828 wlstart(struct ifnet *ifp)
830 int unit = ifp->if_dunit;
832 struct wl_softc *sc = WLSOFTC(unit);
833 short base = sc->base;
834 int scb_status, cu_status, scb_command;
837 if (sc->wl_if.if_flags & IFF_DEBUG)
838 printf("wl%d: entered wlstart()\n",unit);
841 outw(PIOR1(base), OFFSET_CU);
842 cu_status = inw(PIOP1(base));
843 outw(PIOR0(base),OFFSET_SCB + 0); /* scb_status */
844 scb_status = inw(PIOP0(base));
845 outw(PIOR0(base), OFFSET_SCB + 2);
846 scb_command = inw(PIOP0(base));
849 * don't need OACTIVE check as tbusy here checks to see
850 * if we are already busy
853 if((scb_status & 0x0700) == SCB_CUS_IDLE &&
854 (cu_status & AC_SW_B) == 0){
856 callout_stop(&sc->watchdog_ch);
857 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
859 * This is probably just a race. The xmt'r is just
860 * became idle but WE have masked interrupts so ...
863 printf("wl%d: CU idle, scb %04x %04x cu %04x\n",
864 unit, scb_status, scb_command, cu_status);
866 if (xmt_watch) printf("!!");
868 return; /* genuinely still busy */
870 } else if((scb_status & 0x0700) == SCB_CUS_ACTV ||
871 (cu_status & AC_SW_B)){
873 printf("wl%d: CU unexpectedly busy; scb %04x cu %04x\n",
874 unit, scb_status, cu_status);
876 if (xmt_watch) printf("wl%d: busy?!",unit);
877 return; /* hey, why are we busy? */
880 /* get ourselves some data */
882 m = ifq_dequeue(&ifp->if_snd);
886 /* set the watchdog timer so that if the board
887 * fails to interrupt we will restart
889 /* try 10 ticks, not very long */
890 callout_reset(&sc->watchdog_ch, 10, wlwatchdog, sc);
891 sc->wl_ac.ac_if.if_flags |= IFF_OACTIVE;
892 sc->wl_if.if_opackets++;
895 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
903 * This routine does the actual copy of data (including ethernet header
904 * structure) from the WaveLAN to an mbuf chain that will be passed up
905 * to the "if" (network interface) layer. NOTE: we currently
906 * don't handle trailer protocols, so if that is needed, it will
907 * (at least in part) be added here. For simplicities sake, this
908 * routine copies the receive buffers from the board into a local (stack)
909 * buffer until the frame has been copied from the board. Once in
910 * the local buffer, the contents are copied to an mbuf chain that
911 * is then enqueued onto the appropriate "if" queue.
913 * input : board number, and an frame descriptor address
914 * output : the packet is put into an mbuf chain, and passed up
915 * assumes : if any errors occur, packet is "dropped on the floor"
919 wlread(int unit, u_short fd_p)
921 struct wl_softc *sc = WLSOFTC(unit);
922 struct ifnet *ifp = &sc->wl_if;
923 short base = sc->base;
925 struct ether_header eh;
929 u_short mlen, len, clen;
930 u_short bytes_in_msg, bytes_in_mbuf, bytes;
934 if (sc->wl_if.if_flags & IFF_DEBUG)
935 printf("wl%d: entered wlread()\n",unit);
937 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
938 printf("%s read(): board is not running.\n", ifp->if_xname);
939 sc->hacr &= ~HACR_INTRON;
940 CMD(unit); /* turn off interrupts */
942 /* read ether_header info out of device memory. doesn't
943 * go into mbuf. goes directly into eh structure
945 len = sizeof(struct ether_header); /* 14 bytes */
946 outw(PIOR1(base), fd_p);
947 insw(PIOP1(base), &fd, (sizeof(fd_t) - len)/2);
948 insw(PIOP1(base), &eh, (len-2)/2);
949 eh.ether_type = ntohs(inw(PIOP1(base)));
951 if (sc->wl_if.if_flags & IFF_DEBUG) {
952 printf("wlread: rcv packet, type is %x\n", eh.ether_type);
956 * WARNING. above is done now in ether_input, above may be
957 * useful for debug. jrb
959 eh.ether_type = htons(eh.ether_type);
961 if (fd.rbd_offset == I82586NULL) {
962 printf("wl%d read(): Invalid buffer\n", unit);
963 if (wlhwrst(unit) != TRUE) {
964 printf("wl%d read(): hwrst trouble.\n", unit);
969 outw(PIOR1(base), fd.rbd_offset);
970 insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
971 bytes_in_msg = rbd.status & RBD_SW_COUNT;
972 MGETHDR(m, MB_DONTWAIT, MT_DATA);
974 if (m == (struct mbuf *)0) {
976 * not only do we want to return, we need to drop the packet on
977 * the floor to clear the interrupt.
980 if (wlhwrst(unit) != TRUE) {
981 sc->hacr &= ~HACR_INTRON;
982 CMD(unit); /* turn off interrupts */
983 printf("wl%d read(): hwrst trouble.\n", unit);
987 m->m_next = (struct mbuf *) 0;
988 m->m_pkthdr.rcvif = ifp;
989 m->m_pkthdr.len = 0; /* don't know this yet */
992 /* always use a cluster. jrb
994 MCLGET(m, MB_DONTWAIT);
995 if (m->m_flags & M_EXT) {
1000 if (wlhwrst(unit) != TRUE) {
1001 sc->hacr &= ~HACR_INTRON;
1002 CMD(unit); /* turn off interrupts */
1003 printf("wl%d read(): hwrst trouble.\n", unit);
1010 bytes_in_mbuf = m->m_len;
1011 mb_p = mtod(tm, u_char *);
1012 bytes = min(bytes_in_mbuf, bytes_in_msg);
1019 outw(PIOR1(base), rbd.buffer_addr);
1020 insw(PIOP1(base), mb_p, len/2);
1024 if (!(bytes_in_mbuf -= bytes)) {
1025 MGET(tm->m_next, MB_DONTWAIT, MT_DATA);
1027 if (tm == (struct mbuf *)0) {
1029 printf("wl%d read(): No mbuf nth\n", unit);
1030 if (wlhwrst(unit) != TRUE) {
1031 sc->hacr &= ~HACR_INTRON;
1032 CMD(unit); /* turn off interrupts */
1033 printf("wl%d read(): hwrst trouble.\n", unit);
1039 bytes_in_mbuf = MLEN;
1040 mb_p = mtod(tm, u_char *);
1045 if (!(bytes_in_msg -= bytes)) {
1046 if (rbd.status & RBD_SW_EOF ||
1047 rbd.next_rbd_offset == I82586NULL) {
1051 outw(PIOR1(base), rbd.next_rbd_offset);
1052 insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1053 bytes_in_msg = rbd.status & RBD_SW_COUNT;
1056 rbd.buffer_addr += bytes;
1059 bytes = min(bytes_in_mbuf, bytes_in_msg);
1062 m->m_pkthdr.len = clen;
1065 * If hw is in promiscuous mode (note that I said hardware, not if
1066 * IFF_PROMISC is set in ifnet flags), then if this is a unicast
1067 * packet and the MAC dst is not us, drop it. This check in normally
1068 * inside ether_input(), but IFF_MULTI causes hw promisc without
1069 * a bpf listener, so this is wrong.
1070 * Greg Troxel <gdt@ir.bbn.com>, 1998-08-07
1073 * TBD: also discard packets where NWID does not match.
1074 * However, there does not appear to be a way to read the nwid
1075 * for a received packet. -gdt 1998-08-07
1078 #ifdef WL_USE_IFNET_PROMISC_CHECK /* not defined */
1079 (sc->wl_ac.ac_if.if_flags & (IFF_PROMISC|IFF_ALLMULTI))
1081 /* hw is in promisc mode if this is true */
1082 (sc->mode & (MOD_PROM | MOD_ENAL))
1085 (eh.ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
1086 bcmp(eh.ether_dhost, sc->wl_ac.ac_enaddr,
1087 sizeof(eh.ether_dhost)) != 0 ) {
1093 if (sc->wl_if.if_flags & IFF_DEBUG)
1094 printf("wl%d: wlrecv %d bytes\n", unit, clen);
1098 wl_cache_store(unit, base, &eh, m);
1102 * received packet is now in a chain of mbuf's. next step is
1103 * to pass the packet upwards.
1106 ether_input(&sc->wl_if, &eh, m);
1113 * This routine processes an ioctl request from the "if" layer
1116 * input : pointer the appropriate "if" struct, command, and data
1117 * output : based on command appropriate action is taken on the
1118 * WaveLAN board(s) or related structures
1119 * return : error is returned containing exit conditions
1123 wlioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cred)
1125 struct ifreq *ifr = (struct ifreq *)data;
1126 int unit = ifp->if_dunit;
1127 struct wl_softc *sc = WLSOFTC(unit);
1128 short base = sc->base;
1131 int irq, irqval, i, isroot, size;
1134 struct thread *td = curthread; /* XXX */
1138 if (sc->wl_if.if_flags & IFF_DEBUG)
1139 printf("wl%d: entered wlioctl()\n",unit);
1144 if (ifp->if_flags & IFF_ALLMULTI) {
1147 if (ifp->if_flags & IFF_PROMISC) {
1150 if(ifp->if_flags & IFF_LINK0) {
1154 * force a complete reset if the recieve multicast/
1155 * promiscuous mode changes so that these take
1156 * effect immediately.
1159 if (sc->mode != mode) {
1161 if (sc->flags & DSF_RUNNING) {
1162 sc->flags &= ~DSF_RUNNING;
1166 /* if interface is marked DOWN and still running then
1169 if ((ifp->if_flags & IFF_UP) == 0 && sc->flags & DSF_RUNNING) {
1170 printf("wl%d ioctl(): board is not running\n", unit);
1171 sc->flags &= ~DSF_RUNNING;
1172 sc->hacr &= ~HACR_INTRON;
1173 CMD(unit); /* turn off interrupts */
1175 /* else if interface is UP and RUNNING, start it
1177 else if (ifp->if_flags & IFF_UP && (sc->flags & DSF_RUNNING) == 0) {
1181 /* if WLDEBUG set on interface, then printf rf-modem regs
1183 if(ifp->if_flags & IFF_DEBUG)
1190 #if defined(__FreeBSD__) && __FreeBSD_version < 300000
1191 if (cmd == SIOCADDMULTI) {
1192 error = ether_addmulti(ifr, &sc->wl_ac);
1195 error = ether_delmulti(ifr, &sc->wl_ac);
1198 /* see if we should be in all multicast mode
1199 * note that 82586 cannot do that, must simulate with
1202 if ( check_allmulti(unit)) {
1203 ifp->if_flags |= IFF_ALLMULTI;
1204 sc->mode |= MOD_ENAL;
1205 sc->flags &= ~DSF_RUNNING;
1211 if (error == ENETRESET) {
1212 if(sc->flags & DSF_RUNNING) {
1213 sc->flags &= ~DSF_RUNNING;
1222 #endif /* MULTICAST */
1224 /* DEVICE SPECIFIC */
1227 /* copy the PSA out to the caller */
1229 /* pointer to buffer in user space */
1230 up = (void *)ifr->ifr_data;
1231 /* work out if they're root */
1232 isroot = (suser(td) == 0);
1234 for (i = 0; i < 0x40; i++) {
1235 /* don't hand the DES key out to non-root users */
1236 if ((i > WLPSA_DESKEY) && (i < (WLPSA_DESKEY + 8)) && !isroot)
1238 if (subyte((up + i), sc->psa[i]))
1244 /* copy the PSA in from the caller; we only copy _some_ values */
1247 if ((error = suser(td)))
1249 error = EINVAL; /* assume the worst */
1250 /* pointer to buffer in user space containing data */
1251 up = (void *)ifr->ifr_data;
1253 /* check validity of input range */
1254 for (i = 0; i < 0x40; i++)
1255 if (fubyte(up + i) < 0)
1258 /* check IRQ value */
1259 irqval = fubyte(up+WLPSA_IRQNO);
1260 for (irq = 15; irq >= 0; irq--)
1261 if(irqvals[irq] == irqval)
1263 if (irq == 0) /* oops */
1266 sc->psa[WLPSA_IRQNO] = irqval;
1269 for (i = 0; i < 6; i++)
1270 sc->psa[WLPSA_LOCALMAC+i] = fubyte(up+WLPSA_LOCALMAC+i);
1273 sc->psa[WLPSA_MACSEL] = fubyte(up+WLPSA_MACSEL);
1276 sc->psa[WLPSA_NWID] = fubyte(up+WLPSA_NWID);
1277 sc->psa[WLPSA_NWID+1] = fubyte(up+WLPSA_NWID+1);
1280 wlsetpsa(unit); /* update the PSA */
1284 /* get the current NWID out of the sc since we stored it there */
1286 ifr->ifr_data = (caddr_t) (sc->nwid[0] << 8 | sc->nwid[1]);
1291 * change the nwid dynamically. This
1292 * ONLY changes the radio modem and does not
1296 * 1. save in softc "soft registers"
1297 * 2. save in radio modem (MMC)
1301 if ((error = suser(td)))
1303 if (!(ifp->if_flags & IFF_UP)) {
1304 error = EIO; /* only allowed while up */
1307 * soft c nwid shadows radio modem setting
1309 sc->nwid[0] = (int)ifr->ifr_data >> 8;
1310 sc->nwid[1] = (int)ifr->ifr_data & 0xff;
1311 MMC_WRITE(MMC_NETW_ID_L,sc->nwid[1]);
1312 MMC_WRITE(MMC_NETW_ID_H,sc->nwid[0]);
1316 /* copy the EEPROM in 2.4 Gz WaveMODEM out to the caller */
1319 if ((error = suser(td)))
1321 /* pointer to buffer in user space */
1322 up = (void *)ifr->ifr_data;
1324 for (i=0x00; i<0x80; ++i) { /* 2.4 Gz: size of EEPROM */
1325 MMC_WRITE(MMC_EEADDR,i); /* 2.4 Gz: get frequency */
1326 MMC_WRITE(MMC_EECTRL, /* 2.4 Gz: EEPROM read */
1327 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: */
1328 DELAY(40); /* 2.4 Gz */
1329 if (subyte(up + 2*i , /* 2.4 Gz: pass low byte of */
1330 wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word */
1331 ) return(EFAULT); /* 2.4 Gz: */
1332 if (subyte(up + 2*i+1, /* 2.4 Gz: pass hi byte of */
1333 wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word */
1334 ) return(EFAULT); /* 2.4 Gz: */
1339 /* zero (Delete) the wl cache */
1342 if ((error = suser(td)))
1344 wl_cache_zero(unit);
1347 /* read out the number of used cache elements */
1349 ifr->ifr_data = (caddr_t) sc->w_sigitems;
1352 /* read out the wl cache */
1354 /* pointer to buffer in user space */
1355 up = (void *)ifr->ifr_data;
1356 cpt = (char *) &sc->w_sigcache[0];
1357 size = sc->w_sigitems * sizeof(struct w_sigcache);
1359 for (i = 0; i < size; i++) {
1360 if (subyte((up + i), *cpt++))
1367 error = ether_ioctl(ifp, cmd, data);
1377 * Called if the timer set in wlstart expires before an interrupt is received
1378 * from the wavelan. It seems to lose interrupts sometimes.
1379 * The watchdog routine gets called if the transmitter failed to interrupt
1381 * input : which board is timing out
1382 * output : board reset
1386 wlwatchdog(void *vsc)
1388 struct wl_softc *sc = vsc;
1389 int unit = sc->unit;
1391 log(LOG_ERR, "wl%d: wavelan device timeout on xmit\n", unit);
1392 sc->wl_ac.ac_if.if_oerrors++;
1399 * This function is the interrupt handler for the WaveLAN
1400 * board. This routine will be called whenever either a packet
1401 * is received, or a packet has successfully been transfered and
1402 * the unit is ready to transmit another packet.
1404 * input : board number that interrupted
1405 * output : either a packet is received, or a packet is transfered
1412 struct wl_softc *sc = &wl_softc[unit];
1413 short base = sc->base;
1415 u_short int_type, int_type1;
1418 if (sc->wl_if.if_flags & IFF_DEBUG)
1419 printf("wl%d: wlintr() called\n",unit);
1422 if((int_type = inw(HASR(base))) & HASR_MMC_INTR) {
1423 /* handle interrupt from the modem management controler */
1424 /* This will clear the interrupt condition */
1425 (void) wlmmcread(base,MMC_DCE_STATUS); /* ignored for now */
1428 if(!(int_type & HASR_INTR)){ /* return if no interrupt from 82586 */
1429 /* commented out. jrb. it happens when reinit occurs
1430 printf("wlintr: int_type %x, dump follows\n", int_type);
1439 outw(PIOR0(base), OFFSET_SCB + 0); /* get scb status */
1440 int_type = (inw(PIOP0(base)) & SCB_SW_INT);
1441 if (int_type == 0) /* no interrupts left */
1444 int_type1 = wlack(unit); /* acknowledge interrupt(s) */
1445 /* make sure no bits disappeared (others may appear) */
1446 if ((int_type & int_type1) != int_type)
1447 printf("wlack() int bits disappeared : %04x != int_type %04x\n",
1448 int_type1, int_type);
1449 int_type = int_type1; /* go with the new status */
1453 if (int_type & SCB_SW_FR) {
1454 sc->wl_if.if_ipackets++;
1458 * receiver not ready
1460 if (int_type & SCB_SW_RNR) {
1461 sc->wl_if.if_ierrors++;
1463 if (sc->wl_if.if_flags & IFF_DEBUG)
1464 printf("wl%d intr(): receiver overrun! begin_fd = %x\n",
1465 unit, sc->begin_fd);
1472 if (int_type & SCB_SW_CNA) {
1474 * At present, we don't care about CNA's. We
1475 * believe they are a side effect of XMT.
1478 if (int_type & SCB_SW_CX) {
1480 * At present, we only request Interrupt for
1483 outw(PIOR1(base), OFFSET_CU); /* get command status */
1484 ac_status = inw(PIOP1(base));
1486 if (xmt_watch) { /* report some anomalies */
1488 if (sc->tbusy == 0) {
1489 printf("wl%d: xmt intr but not busy, CU %04x\n",
1492 if (ac_status == 0) {
1493 printf("wl%d: xmt intr but ac_status == 0\n", unit);
1495 if (ac_status & AC_SW_A) {
1496 printf("wl%d: xmt aborted\n",unit);
1499 if (ac_status & TC_CARRIER) {
1500 printf("wl%d: no carrier\n", unit);
1503 if (ac_status & TC_CLS) {
1504 printf("wl%d: no CTS\n", unit);
1506 if (ac_status & TC_DMA) {
1507 printf("wl%d: DMA underrun\n", unit);
1509 if (ac_status & TC_DEFER) {
1510 printf("wl%d: xmt deferred\n",unit);
1512 if (ac_status & TC_SQE) {
1513 printf("wl%d: heart beat\n", unit);
1515 if (ac_status & TC_COLLISION) {
1516 printf("wl%d: too many collisions\n", unit);
1519 /* if the transmit actually failed, or returned some status */
1520 if ((!(ac_status & AC_SW_OK)) || (ac_status & 0xfff)) {
1521 if (ac_status & (TC_COLLISION | TC_CLS | TC_DMA)) {
1522 sc->wl_if.if_oerrors++;
1524 /* count collisions */
1525 sc->wl_if.if_collisions += (ac_status & 0xf);
1526 /* if TC_COLLISION set and collision count zero, 16 collisions */
1527 if ((ac_status & 0x20) == 0x20) {
1528 sc->wl_if.if_collisions += 0x10;
1532 callout_stop(&sc->watchdog_ch);
1533 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
1534 wlstart(&(sc->wl_if));
1543 * This routine is called by the interrupt handler to initiate a
1544 * packet transfer from the board to the "if" layer above this
1545 * driver. This routine checks if a buffer has been successfully
1546 * received by the WaveLAN. If so, the routine wlread is called
1547 * to do the actual transfer of the board data (including the
1548 * ethernet header) into a packet (consisting of an mbuf chain).
1550 * input : number of the board to check
1551 * output : if a packet is available, it is "sent up"
1557 struct wl_softc *sc = WLSOFTC(unit);
1558 short base = sc->base;
1559 u_short fd_p, status, offset, link_offset;
1562 if (sc->wl_if.if_flags & IFF_DEBUG)
1563 printf("wl%d: entered wlrcv()\n",unit);
1565 for (fd_p = sc->begin_fd; fd_p != I82586NULL; fd_p = sc->begin_fd) {
1567 outw(PIOR0(base), fd_p + 0); /* address of status */
1568 status = inw(PIOP0(base));
1569 outw(PIOR1(base), fd_p + 4); /* address of link_offset */
1570 link_offset = inw(PIOP1(base));
1571 offset = inw(PIOP1(base)); /* rbd_offset */
1572 if (status == 0xffff || offset == 0xffff /*I82586NULL*/) {
1573 if (wlhwrst(unit) != TRUE)
1574 printf("wl%d rcv(): hwrst ffff trouble.\n", unit);
1576 } else if (status & AC_SW_C) {
1577 if (status == (RFD_DONE|RFD_RSC)) {
1580 if (sc->wl_if.if_flags & IFF_DEBUG)
1581 printf("wl%d RCV: RSC %x\n", unit, status);
1583 sc->wl_if.if_ierrors++;
1584 } else if (!(status & RFD_OK)) {
1585 printf("wl%d RCV: !OK %x\n", unit, status);
1586 sc->wl_if.if_ierrors++;
1587 } else if (status & 0xfff) { /* can't happen */
1588 printf("wl%d RCV: ERRs %x\n", unit, status);
1589 sc->wl_if.if_ierrors++;
1590 } else if (!wlread(unit, fd_p))
1593 if (!wlrequeue(unit, fd_p)) {
1594 /* abort on chain error */
1595 if (wlhwrst(unit) != TRUE)
1596 printf("wl%d rcv(): hwrst trouble.\n", unit);
1599 sc->begin_fd = link_offset;
1610 * This routine puts rbd's used in the last receive back onto the
1611 * free list for the next receive.
1615 wlrequeue(int unit, u_short fd_p)
1617 struct wl_softc *sc = WLSOFTC(unit);
1618 short base = sc->base;
1620 u_short l_rbdp, f_rbdp, rbd_offset;
1622 outw(PIOR0(base), fd_p + 6);
1623 rbd_offset = inw(PIOP0(base));
1624 if ((f_rbdp = rbd_offset) != I82586NULL) {
1627 outw(PIOR0(base), l_rbdp + 0); /* address of status */
1628 if(inw(PIOP0(base)) & RBD_SW_EOF)
1630 outw(PIOP0(base), 0);
1631 outw(PIOR0(base), l_rbdp + 2); /* next_rbd_offset */
1632 if((l_rbdp = inw(PIOP0(base))) == I82586NULL)
1635 outw(PIOP0(base), 0);
1636 outw(PIOR0(base), l_rbdp + 2); /* next_rbd_offset */
1637 outw(PIOP0(base), I82586NULL);
1638 outw(PIOR0(base), l_rbdp + 8); /* address of size */
1639 outw(PIOP0(base), inw(PIOP0(base)) | AC_CW_EL);
1640 outw(PIOR0(base), sc->end_rbd + 2);
1641 outw(PIOP0(base), f_rbdp); /* end_rbd->next_rbd_offset */
1642 outw(PIOR0(base), sc->end_rbd + 8); /* size */
1643 outw(PIOP0(base), inw(PIOP0(base)) & ~AC_CW_EL);
1644 sc->end_rbd = l_rbdp;
1648 fd.command = AC_CW_EL;
1649 fd.link_offset = I82586NULL;
1650 fd.rbd_offset = I82586NULL;
1651 outw(PIOR1(base), fd_p);
1652 outsw(PIOP1(base), &fd, 8/2);
1654 outw(PIOR1(base), sc->end_fd + 2); /* addr of command */
1655 outw(PIOP1(base), 0); /* command = 0 */
1656 outw(PIOP1(base), fd_p); /* end_fd->link_offset = fd_p */
1663 static int xmt_debug = 0;
1664 #endif /* WLDEBUG */
1669 * This routine fills in the appropriate registers and memory
1670 * locations on the WaveLAN board and starts the board off on
1673 * input : board number of interest, and a pointer to the mbuf
1674 * output : board memory and registers are set for xfer and attention
1678 wlxmt(int unit, struct mbuf *m)
1680 struct wl_softc *sc = WLSOFTC(unit);
1681 u_short xmtdata_p = OFFSET_TBUF;
1683 struct mbuf *tm_p = m;
1684 struct ether_header *eh_p = mtod(m, struct ether_header *);
1685 u_char *mb_p = mtod(m, u_char *) + sizeof(struct ether_header);
1686 u_short count = m->m_len - sizeof(struct ether_header);
1688 u_short tbd_p = OFFSET_TBD;
1689 u_short len, clen = 0;
1690 short base = sc->base;
1694 if (sc->wl_if.if_flags & IFF_DEBUG)
1695 printf("wl%d: entered wlxmt()\n",unit);
1699 cb.ac_command = (AC_CW_EL|AC_TRANSMIT|AC_CW_I);
1700 cb.ac_link_offset = I82586NULL;
1701 outw(PIOR1(base), OFFSET_CU);
1702 outsw(PIOP1(base), &cb, 6/2);
1703 outw(PIOP1(base), OFFSET_TBD); /* cb.cmd.transmit.tbd_offset */
1704 outsw(PIOP1(base), eh_p->ether_dhost, WAVELAN_ADDR_SIZE/2);
1705 outw(PIOP1(base), eh_p->ether_type);
1708 if (sc->wl_if.if_flags & IFF_DEBUG) {
1710 printf("XMT mbuf: L%d @%p ", count, (void *)mb_p);
1711 printf("ether type %x\n", eh_p->ether_type);
1714 #endif /* WLDEBUG */
1715 outw(PIOR0(base), OFFSET_TBD);
1716 outw(PIOP0(base), 0); /* act_count */
1717 outw(PIOR1(base), OFFSET_TBD + 4);
1718 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1719 outw(PIOP1(base), 0); /* buffer_base */
1722 if (clen + count > WAVELAN_MTU)
1728 outw(PIOR1(base), xmtdata_p);
1729 outsw(PIOP1(base), mb_p, len/2);
1731 outw(PIOR0(base), tbd_p); /* address of act_count */
1732 outw(PIOP0(base), inw(PIOP0(base)) + count);
1734 if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1737 /* go to the next descriptor */
1738 outw(PIOR0(base), tbd_p + 2);
1739 tbd_p += sizeof (tbd_t);
1740 outw(PIOP0(base), tbd_p); /* next_tbd_offset */
1741 outw(PIOR0(base), tbd_p);
1742 outw(PIOP0(base), 0); /* act_count */
1743 outw(PIOR1(base), tbd_p + 4);
1744 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1745 outw(PIOP1(base), 0); /* buffer_base */
1746 /* at the end -> coallesce remaining mbufs */
1747 if (tbd_p == OFFSET_TBD + (N_TBD-1) * sizeof (tbd_t)) {
1748 wlsftwsleaze(&count, &mb_p, &tm_p, unit);
1751 /* next mbuf short -> coallesce as needed */
1752 if ( (tm_p->m_next == (struct mbuf *) 0) ||
1753 #define HDW_THRESHOLD 55
1754 tm_p->m_len > HDW_THRESHOLD)
1757 wlhdwsleaze(&count, &mb_p, &tm_p, unit);
1761 } else if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1763 count = tm_p->m_len;
1764 mb_p = mtod(tm_p, u_char *);
1766 if (sc->wl_if.if_flags & IFF_DEBUG)
1768 printf("mbuf+ L%d @%p ", count, (void *)mb_p);
1769 #endif /* WLDEBUG */
1772 if (sc->wl_if.if_flags & IFF_DEBUG)
1774 printf("CLEN = %d\n", clen);
1775 #endif /* WLDEBUG */
1776 outw(PIOR0(base), tbd_p);
1777 if (clen < ETHERMIN) {
1778 outw(PIOP0(base), inw(PIOP0(base)) + ETHERMIN - clen);
1779 outw(PIOR1(base), xmtdata_p);
1780 for (xmtshort_p = xmtdata_p; clen < ETHERMIN; clen += 2)
1781 outw(PIOP1(base), 0);
1783 outw(PIOP0(base), inw(PIOP0(base)) | TBD_SW_EOF);
1784 outw(PIOR0(base), tbd_p + 2);
1785 outw(PIOP0(base), I82586NULL);
1787 if (sc->wl_if.if_flags & IFF_DEBUG) {
1793 #endif /* WLDEBUG */
1795 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
1797 * wait for 586 to clear previous command, complain if it takes
1800 for (spin = 1;;spin = (spin + 1) % 10000) {
1801 if (inw(PIOP0(base)) == 0) { /* it's done, we can go */
1804 if ((spin == 0) && xmt_watch) { /* not waking up, and we care */
1805 printf("wl%d: slow accepting xmit\n",unit);
1808 outw(PIOP0(base), SCB_CU_STRT); /* new command */
1809 SET_CHAN_ATTN(unit);
1814 * Pause to avoid transmit overrun problems.
1815 * The required delay tends to vary with platform type, and may be
1816 * related to interrupt loss.
1818 if (wl_xmit_delay) {
1819 DELAY(wl_xmit_delay);
1827 * This function builds the linear linked lists of fd's and
1828 * rbd's. Based on page 4-32 of 1986 Intel microcom handbook.
1834 struct wl_softc *sc = WLSOFTC(unit);
1835 short base = sc->base;
1838 u_short fd_p = OFFSET_RU;
1839 u_short rbd_p = OFFSET_RBD;
1842 sc->begin_fd = fd_p;
1843 for(i = 0; i < N_FD; i++) {
1846 fd.link_offset = fd_p + sizeof(fd_t);
1847 fd.rbd_offset = I82586NULL;
1848 outw(PIOR1(base), fd_p);
1849 outsw(PIOP1(base), &fd, 8/2);
1850 fd_p = fd.link_offset;
1852 fd_p -= sizeof(fd_t);
1854 outw(PIOR1(base), fd_p + 2);
1855 outw(PIOP1(base), AC_CW_EL); /* command */
1856 outw(PIOP1(base), I82586NULL); /* link_offset */
1859 outw(PIOR0(base), fd_p + 6); /* address of rbd_offset */
1860 outw(PIOP0(base), rbd_p);
1861 outw(PIOR1(base), rbd_p);
1862 for(i = 0; i < N_RBD; i++) {
1864 rbd.buffer_addr = rbd_p + sizeof(rbd_t) + 2;
1865 rbd.buffer_base = 0;
1866 rbd.size = RCVBUFSIZE;
1868 rbd_p += sizeof(ru_t);
1869 rbd.next_rbd_offset = rbd_p;
1871 rbd.next_rbd_offset = I82586NULL;
1872 rbd.size |= AC_CW_EL;
1873 sc->end_rbd = rbd_p;
1875 outsw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1876 outw(PIOR1(base), rbd_p);
1878 return sc->begin_fd;
1884 * This routine starts the receive unit running. First checks if the
1885 * board is actually ready, then the board is instructed to receive
1892 struct wl_softc *sc = WLSOFTC(unit);
1893 short base = sc->base;
1897 if (sc->wl_if.if_flags & IFF_DEBUG)
1898 printf("wl%d: entered wlrustrt()\n",unit);
1900 outw(PIOR0(base), OFFSET_SCB);
1901 if (inw(PIOP0(base)) & SCB_RUS_READY){
1902 printf("wlrustrt: RUS_READY\n");
1906 outw(PIOR0(base), OFFSET_SCB + 2);
1907 outw(PIOP0(base), SCB_RU_STRT); /* command */
1908 rfa = wlbldru(unit);
1909 outw(PIOR0(base), OFFSET_SCB + 6); /* address of scb_rfa_offset */
1910 outw(PIOP0(base), rfa);
1912 SET_CHAN_ATTN(unit);
1919 * This routine does a 586 op-code number 7, and obtains the
1920 * diagnose status for the WaveLAN.
1926 struct wl_softc *sc = WLSOFTC(unit);
1927 short base = sc->base;
1931 if (sc->wl_if.if_flags & IFF_DEBUG)
1932 printf("wl%d: entered wldiag()\n",unit);
1934 outw(PIOR0(base), OFFSET_SCB);
1935 status = inw(PIOP0(base));
1936 if (status & SCB_SW_INT) {
1937 /* state is 2000 which seems ok
1938 printf("wl%d diag(): unexpected initial state %\n",
1939 unit, inw(PIOP0(base)));
1943 outw(PIOR1(base), OFFSET_CU);
1944 outw(PIOP1(base), 0); /* ac_status */
1945 outw(PIOP1(base), AC_DIAGNOSE|AC_CW_EL);/* ac_command */
1946 if(wlcmd(unit, "diag()") == 0)
1948 outw(PIOR0(base), OFFSET_CU);
1949 if (inw(PIOP0(base)) & 0x0800) {
1950 printf("wl%d: i82586 Self Test failed!\n", unit);
1959 * This routine does a standard config of the WaveLAN board.
1965 configure_t configure;
1966 struct wl_softc *sc = WLSOFTC(unit);
1967 short base = sc->base;
1970 #if defined(__DragonFly__) || (defined(__FreeBSD__) && __FreeBSD_version >= 300000)
1971 struct ifmultiaddr *ifma;
1974 struct ether_multi *enm;
1975 struct ether_multistep step;
1978 #endif /* MULTICAST */
1981 if (sc->wl_if.if_flags & IFF_DEBUG)
1982 printf("wl%d: entered wlconfig()\n",unit);
1984 outw(PIOR0(base), OFFSET_SCB);
1985 if (inw(PIOP0(base)) & SCB_SW_INT) {
1987 printf("wl%d config(): unexpected initial state %x\n",
1988 unit, inw(PIOP0(base)));
1993 outw(PIOR1(base), OFFSET_CU);
1994 outw(PIOP1(base), 0); /* ac_status */
1995 outw(PIOP1(base), AC_CONFIGURE|AC_CW_EL); /* ac_command */
1998 configure.fifolim_bytecnt = 0x080c;
1999 configure.addrlen_mode = 0x0600;
2000 configure.linprio_interframe = 0x2060;
2001 configure.slot_time = 0xf200;
2002 configure.hardware = 0x0008; /* tx even w/o CD */
2003 configure.min_frame_len = 0x0040;
2005 /* This is the configuration block suggested by Marc Meertens
2006 * <mmeerten@obelix.utrecht.NCR.COM> in an e-mail message to John
2007 * Ioannidis on 10 Nov 92.
2009 configure.fifolim_bytecnt = 0x040c;
2010 configure.addrlen_mode = 0x0600;
2011 configure.linprio_interframe = 0x2060;
2012 configure.slot_time = 0xf000;
2013 configure.hardware = 0x0008; /* tx even w/o CD */
2014 configure.min_frame_len = 0x0040;
2017 * below is the default board configuration from p2-28 from 586 book
2019 configure.fifolim_bytecnt = 0x080c;
2020 configure.addrlen_mode = 0x2600;
2021 configure.linprio_interframe = 0x7820; /* IFS=120, ACS=2 */
2022 configure.slot_time = 0xf00c; /* slottime=12 */
2023 configure.hardware = 0x0008; /* tx even w/o CD */
2024 configure.min_frame_len = 0x0040;
2026 if(sc->mode & (MOD_PROM | MOD_ENAL)) {
2027 configure.hardware |= 1;
2029 outw(PIOR1(base), OFFSET_CU + 6);
2030 outsw(PIOP1(base), &configure, sizeof(configure_t)/2);
2032 if(wlcmd(unit, "config()-configure") == 0)
2035 outw(PIOR1(base), OFFSET_CU);
2036 outw(PIOP1(base), 0); /* ac_status */
2037 outw(PIOP1(base), AC_MCSETUP|AC_CW_EL); /* ac_command */
2038 outw(PIOR1(base), OFFSET_CU + 8);
2039 #if defined(__DragonFly__) || (defined(__FreeBSD__) && __FreeBSD_version >= 300000)
2040 for (ifma = sc->wl_if.if_multiaddrs.lh_first; ifma;
2041 ifma = ifma->ifma_link.le_next) {
2042 if (ifma->ifma_addr->sa_family != AF_LINK)
2045 addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
2046 outw(PIOP1(base), addrp[0] + (addrp[1] << 8));
2047 outw(PIOP1(base), addrp[2] + (addrp[3] << 8));
2048 outw(PIOP1(base), addrp[4] + (addrp[5] << 8));
2052 ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2053 while (enm != NULL) {
2054 unsigned int lo, hi;
2055 /* break if setting a multicast range, else we would crash */
2056 if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2059 lo = (enm->enm_addrlo[3] << 16) + (enm->enm_addrlo[4] << 8)
2060 + enm->enm_addrlo[5];
2061 hi = (enm->enm_addrhi[3] << 16) + (enm->enm_addrhi[4] << 8)
2062 + enm->enm_addrhi[5];
2064 outw(PIOP1(base),enm->enm_addrlo[0] +
2065 (enm->enm_addrlo[1] << 8));
2066 outw(PIOP1(base),enm->enm_addrlo[2] +
2067 ((lo >> 8) & 0xff00));
2068 outw(PIOP1(base), ((lo >> 8) & 0xff) +
2069 ((lo << 8) & 0xff00));
2070 /* #define MCASTDEBUG */
2072 printf("mcast_addr[%d,%d,%d] %x %x %x %x %x %x\n", lo, hi, cnt,
2078 enm->enm_addrlo[5]);
2083 ETHER_NEXT_MULTI(step, enm);
2086 outw(PIOR1(base), OFFSET_CU + 6); /* mc-cnt */
2087 outw(PIOP1(base), cnt * WAVELAN_ADDR_SIZE);
2088 if(wlcmd(unit, "config()-mcaddress") == 0)
2090 #endif /* MULTICAST */
2092 outw(PIOR1(base), OFFSET_CU);
2093 outw(PIOP1(base), 0); /* ac_status */
2094 outw(PIOP1(base), AC_IASETUP|AC_CW_EL); /* ac_command */
2095 outw(PIOR1(base), OFFSET_CU + 6);
2096 outsw(PIOP1(base), sc->wl_addr, WAVELAN_ADDR_SIZE/2);
2098 if(wlcmd(unit, "config()-address") == 0)
2109 * Set channel attention bit and busy wait until command has
2110 * completed. Then acknowledge the command completion.
2113 wlcmd(int unit, char *str)
2115 struct wl_softc *sc = WLSOFTC(unit);
2116 short base = sc->base;
2119 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
2120 outw(PIOP0(base), SCB_CU_STRT);
2122 SET_CHAN_ATTN(unit);
2124 outw(PIOR0(base), OFFSET_CU);
2125 for(i = 0; i < 0xffff; i++)
2126 if (inw(PIOP0(base)) & AC_SW_C)
2128 if (i == 0xffff || !(inw(PIOP0(base)) & AC_SW_OK)) {
2129 printf("wl%d: %s failed; status = %d, inw = %x, outw = %x\n",
2130 unit, str, inw(PIOP0(base)) & AC_SW_OK, inw(PIOP0(base)), inw(PIOR0(base)));
2131 outw(PIOR0(base), OFFSET_SCB);
2132 printf("scb_status %x\n", inw(PIOP0(base)));
2133 outw(PIOR0(base), OFFSET_SCB+2);
2134 printf("scb_command %x\n", inw(PIOP0(base)));
2135 outw(PIOR0(base), OFFSET_SCB+4);
2136 printf("scb_cbl %x\n", inw(PIOP0(base)));
2137 outw(PIOR0(base), OFFSET_CU+2);
2138 printf("cu_cmd %x\n", inw(PIOP0(base)));
2142 outw(PIOR0(base), OFFSET_SCB);
2143 if ((inw(PIOP0(base)) & SCB_SW_INT) && (inw(PIOP0(base)) != SCB_SW_CNA)) {
2145 printf("wl%d %s: unexpected final state %x\n",
2146 unit, str, inw(PIOP0(base)));
2154 * wlack: if the 82596 wants attention because it has finished
2155 * sending or receiving a packet, acknowledge its desire and
2156 * return bits indicating the kind of attention. wlack() returns
2157 * these bits so that the caller can service exactly the
2158 * conditions that wlack() acknowledged.
2165 struct wl_softc *sc = WLSOFTC(unit);
2166 short base = sc->base;
2168 outw(PIOR1(base), OFFSET_SCB);
2169 if(!(cmd = (inw(PIOP1(base)) & SCB_SW_INT)))
2172 if (sc->wl_if.if_flags & IFF_DEBUG)
2173 printf("wl%d: doing a wlack()\n",unit);
2175 outw(PIOP1(base), cmd);
2176 SET_CHAN_ATTN(unit);
2177 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
2178 for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
2180 printf("wl%d wlack(): board not accepting command.\n", unit);
2187 struct wl_softc *sc = WLSOFTC(unit);
2188 short base = sc->base;
2189 u_short tbd_p = OFFSET_TBD;
2195 outw(PIOR1(base), tbd_p);
2196 insw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
2197 sum += (tbd.act_count & ~TBD_SW_EOF);
2198 printf("%d: addr %x, count %d (%d), next %x, base %x\n",
2199 i++, tbd.buffer_addr,
2200 (tbd.act_count & ~TBD_SW_EOF), sum,
2201 tbd.next_tbd_offset, tbd.buffer_base);
2202 if (tbd.act_count & TBD_SW_EOF)
2204 tbd_p = tbd.next_tbd_offset;
2209 wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2211 struct mbuf *tm_p = *tm_pp;
2212 u_char *mb_p = *mb_pp;
2218 * can we get a run that will be coallesced or
2219 * that terminates before breaking
2222 count += tm_p->m_len;
2223 if (tm_p->m_len & 1)
2225 } while ((tm_p = tm_p->m_next) != (struct mbuf *)0);
2226 if ( (tm_p == (struct mbuf *)0) ||
2227 count > HDW_THRESHOLD) {
2228 *countp = (*tm_pp)->m_len;
2229 *mb_pp = mtod((*tm_pp), u_char *);
2233 /* we need to copy */
2237 cp = (u_char *) t_packet;
2239 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2241 if (count > HDW_THRESHOLD)
2244 if (tm_p->m_next == (struct mbuf *)0)
2246 tm_p = tm_p->m_next;
2249 *mb_pp = (u_char *) t_packet;
2256 wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2258 struct mbuf *tm_p = *tm_pp;
2260 u_char *cp = (u_char *) t_packet;
2263 /* we need to copy */
2265 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2268 if (tm_p->m_next == (struct mbuf *)0)
2270 tm_p = tm_p->m_next;
2274 *mb_pp = (u_char *) t_packet;
2282 struct wl_softc *sc = WLSOFTC(unit);
2283 short base = sc->base;
2286 printf("wl%d: DCE_STATUS: 0x%x, ", unit,
2287 wlmmcread(base,MMC_DCE_STATUS) & 0x0f);
2288 tmp = wlmmcread(base,MMC_CORRECT_NWID_H) << 8;
2289 tmp |= wlmmcread(base,MMC_CORRECT_NWID_L);
2290 printf("Correct NWID's: %d, ", tmp);
2291 tmp = wlmmcread(base,MMC_WRONG_NWID_H) << 8;
2292 tmp |= wlmmcread(base,MMC_WRONG_NWID_L);
2293 printf("Wrong NWID's: %d\n", tmp);
2294 printf("THR_PRE_SET: 0x%x, ", wlmmcread(base,MMC_THR_PRE_SET));
2295 printf("SIGNAL_LVL: %d, SILENCE_LVL: %d\n",
2296 wlmmcread(base,MMC_SIGNAL_LVL),
2297 wlmmcread(base,MMC_SILENCE_LVL));
2298 printf("SIGN_QUAL: 0x%x, NETW_ID: %x:%x, DES: %d\n",
2299 wlmmcread(base,MMC_SIGN_QUAL),
2300 wlmmcread(base,MMC_NETW_ID_H),
2301 wlmmcread(base,MMC_NETW_ID_L),
2302 wlmmcread(base,MMC_DES_AVAIL));
2306 wlmmcread(u_int base, u_short reg)
2308 while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2309 outw(MMCR(base),reg << 1);
2310 while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2311 return (u_short)inw(MMCR(base)) >> 8;
2317 MMC_WRITE(MMC_FREEZE,1);
2319 * SNR retrieval procedure :
2321 * read signal level : wlmmcread(base, MMC_SIGNAL_LVL);
2322 * read silence level : wlmmcread(base, MMC_SILENCE_LVL);
2324 MMC_WRITE(MMC_FREEZE,0);
2326 * SNR is signal:silence ratio.
2333 ** Reads the psa for the wavelan at (base) into (buf)
2336 wlgetpsa(int base, u_char *buf)
2340 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2341 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2343 for (i = 0; i < 0x40; i++) {
2344 outw(PIOR2(base), i);
2345 buf[i] = inb(PIOP2(base));
2347 PCMD(base, HACR_DEFAULT);
2348 PCMD(base, HACR_DEFAULT);
2354 ** Writes the psa for wavelan (unit) from the softc back to the
2355 ** board. Updates the CRC and sets the CRC OK flag.
2357 ** Do not call this when the board is operating, as it doesn't
2358 ** preserve the hacr.
2363 struct wl_softc *sc = WLSOFTC(unit);
2364 short base = sc->base;
2368 crc = wlpsacrc(sc->psa); /* calculate CRC of PSA */
2369 sc->psa[WLPSA_CRCLOW] = crc & 0xff;
2370 sc->psa[WLPSA_CRCHIGH] = (crc >> 8) & 0xff;
2371 sc->psa[WLPSA_CRCOK] = 0x55; /* default to 'bad' until programming complete */
2373 crit_enter(); /* ick, long pause */
2375 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2376 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2378 for (i = 0; i < 0x40; i++) {
2380 outw(PIOR2(base),i); /* write param memory */
2382 outb(PIOP2(base), sc->psa[i]);
2385 outw(PIOR2(base),WLPSA_CRCOK); /* update CRC flag*/
2387 sc->psa[WLPSA_CRCOK] = 0xaa; /* OK now */
2388 outb(PIOP2(base), 0xaa); /* all OK */
2391 PCMD(base, HACR_DEFAULT);
2392 PCMD(base, HACR_DEFAULT);
2398 ** CRC routine provided by Christopher Giordano <cgiordan@gdeb.com>,
2399 ** from original code by Tomi Mikkonen (tomitm@remedy.fi)
2402 static u_int crc16_table[16] = {
2403 0x0000, 0xCC01, 0xD801, 0x1400,
2404 0xF001, 0x3C00, 0x2800, 0xE401,
2405 0xA001, 0x6C00, 0x7800, 0xB401,
2406 0x5000, 0x9C01, 0x8801, 0x4400
2410 wlpsacrc(u_char *buf)
2415 for (i = 0; i < 0x3d; i++, buf++) {
2417 r1 = crc16_table[crc & 0xF];
2418 crc = (crc >> 4) & 0x0FFF;
2419 crc = crc ^ r1 ^ crc16_table[*buf & 0xF];
2422 r1 = crc16_table[crc & 0xF];
2423 crc = (crc >> 4) & 0x0FFF;
2424 crc = crc ^ r1 ^ crc16_table[(*buf >> 4) & 0xF];
2433 * take input packet and cache various radio hw characteristics
2434 * indexed by MAC address.
2436 * Some things to think about:
2437 * note that no space is malloced.
2438 * We might hash the mac address if the cache were bigger.
2439 * It is not clear that the cache is big enough.
2440 * It is also not clear how big it should be.
2441 * The cache is IP-specific. We don't care about that as
2442 * we want it to be IP-specific.
2443 * The last N recv. packets are saved. This will tend
2444 * to reward agents and mobile hosts that beacon.
2445 * That is probably fine for mobile ip.
2448 /* globals for wavelan signal strength cache */
2449 /* this should go into softc structure above.
2452 /* set true if you want to limit cache items to broadcast/mcast
2453 * only packets (not unicast)
2455 static int wl_cache_mcastonly = 1;
2456 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_mcastonly, CTLFLAG_RW,
2457 &wl_cache_mcastonly, 0, "");
2459 /* set true if you want to limit cache items to IP packets only
2461 static int wl_cache_iponly = 1;
2462 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_iponly, CTLFLAG_RW,
2463 &wl_cache_iponly, 0, "");
2465 /* zero out the cache
2468 wl_cache_zero(int unit)
2470 struct wl_softc *sc = WLSOFTC(unit);
2472 bzero(&sc->w_sigcache[0], sizeof(struct w_sigcache) * MAXCACHEITEMS);
2474 sc->w_nextcache = 0;
2475 sc->w_wrapindex = 0;
2478 /* store hw signal info in cache.
2479 * index is MAC address, but an ip src gets stored too
2480 * There are two filters here controllable via sysctl:
2481 * throw out unicast (on by default, but can be turned off)
2482 * throw out non-ip (on by default, but can be turned off)
2485 void wl_cache_store (int unit, int base, struct ether_header *eh,
2488 struct ip *ip = NULL; /* Avoid GCC warning */
2490 int signal, silence;
2491 int w_insertcache; /* computed index for cache entry storage */
2492 struct wl_softc *sc = WLSOFTC(unit);
2493 int ipflag = wl_cache_iponly;
2497 * 2. configurable filter to throw out unicast packets,
2498 * keep multicast only.
2502 /* reject if not IP packet
2504 if ( wl_cache_iponly && (ntohs(eh->ether_type) != 0x800)) {
2508 /* check if broadcast or multicast packet. we toss
2511 if (wl_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
2515 /* find the ip header. we want to store the ip_src
2516 * address. use the mtod macro(in mbuf.h)
2517 * to typecast m to struct ip *
2520 ip = mtod(m, struct ip *);
2523 /* do a linear search for a matching MAC address
2524 * in the cache table
2525 * . MAC address is 6 bytes,
2526 * . var w_nextcache holds total number of entries already cached
2528 for(i = 0; i < sc->w_nextcache; i++) {
2529 if (! bcmp(eh->ether_shost, sc->w_sigcache[i].macsrc, 6 )) {
2531 * so we already have this entry,
2532 * update the data, and LRU age
2538 /* did we find a matching mac address?
2539 * if yes, then overwrite a previously existing cache entry
2541 if (i < sc->w_nextcache ) {
2544 /* else, have a new address entry,so
2545 * add this new entry,
2546 * if table full, then we need to replace entry
2550 /* check for space in cache table
2551 * note: w_nextcache also holds number of entries
2552 * added in the cache table
2554 if ( sc->w_nextcache < MAXCACHEITEMS ) {
2555 w_insertcache = sc->w_nextcache;
2557 sc->w_sigitems = sc->w_nextcache;
2559 /* no space found, so simply wrap with wrap index
2560 * and "zap" the next entry
2563 if (sc->w_wrapindex == MAXCACHEITEMS) {
2564 sc->w_wrapindex = 0;
2566 w_insertcache = sc->w_wrapindex++;
2570 /* invariant: w_insertcache now points at some slot
2573 if (w_insertcache < 0 || w_insertcache >= MAXCACHEITEMS) {
2575 "wl_cache_store, bad index: %d of [0..%d], gross cache error\n",
2576 w_insertcache, MAXCACHEITEMS);
2580 /* store items in cache
2583 * .signal (0..63) ,silence (0..63) ,quality (0..15)
2586 sc->w_sigcache[w_insertcache].ipsrc = ip->ip_src.s_addr;
2588 bcopy( eh->ether_shost, sc->w_sigcache[w_insertcache].macsrc, 6);
2589 signal = sc->w_sigcache[w_insertcache].signal = wlmmcread(base, MMC_SIGNAL_LVL) & 0x3f;
2590 silence = sc->w_sigcache[w_insertcache].silence = wlmmcread(base, MMC_SILENCE_LVL) & 0x3f;
2591 sc->w_sigcache[w_insertcache].quality = wlmmcread(base, MMC_SIGN_QUAL) & 0x0f;
2593 sc->w_sigcache[w_insertcache].snr =
2596 sc->w_sigcache[w_insertcache].snr = 0;
2600 #endif /* WLCACHE */
2603 * determine if in all multicast mode or not
2605 * returns: 1 if IFF_ALLMULTI should be set
2610 #if defined(__FreeBSD__) && __FreeBSD_version < 300000 /* not required */
2612 check_allmulti(int unit)
2614 struct wl_softc *sc = WLSOFTC(unit);
2615 short base = sc->base;
2616 struct ether_multi *enm;
2617 struct ether_multistep step;
2619 ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2620 while (enm != NULL) {
2621 unsigned int lo, hi;
2623 printf("enm_addrlo %x:%x:%x:%x:%x:%x\n", enm->enm_addrlo[0], enm->enm_addrlo[1],
2624 enm->enm_addrlo[2], enm->enm_addrlo[3], enm->enm_addrlo[4],
2625 enm->enm_addrlo[5]);
2626 printf("enm_addrhi %x:%x:%x:%x:%x:%x\n", enm->enm_addrhi[0], enm->enm_addrhi[1],
2627 enm->enm_addrhi[2], enm->enm_addrhi[3], enm->enm_addrhi[4],
2628 enm->enm_addrhi[5]);
2630 if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2633 ETHER_NEXT_MULTI(step, enm);