1 /* $Id: if_wl.c,v 1.16 1998/10/22 05:58:39 bde Exp $ */
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 "bpfilter.h"
194 #include "opt_inet.h"
196 #include <sys/param.h>
197 #include <sys/systm.h>
198 #include <sys/sockio.h>
199 #include <sys/mbuf.h>
200 #include <sys/socket.h>
201 #include <sys/syslog.h>
202 #include <sys/proc.h>
204 #include <sys/kernel.h>
205 #include <sys/sysctl.h>
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>
221 #include <machine/clock.h>
223 #include <i386/isa/isa_device.h>
225 #include <i386/isa/ic/if_wl_i82586.h> /* Definitions for the Intel chip */
227 /* was 1000 in original, fed to DELAY(x) */
228 #define DELAYCONST 1000
229 #include <i386/isa/if_wl.h>
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_handle 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 struct isa_driver wldriver = {
268 wlprobe, wlattach, "wl", 0
272 * XXX The Wavelan appears to be prone to dropping stuff if you talk to
273 * it too fast. This disgusting hack inserts a delay after each packet
274 * is queued which helps avoid this behaviour on fast systems.
276 static int wl_xmit_delay = 250;
277 SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_delay, CTLFLAG_RW, &wl_xmit_delay, 0, "");
280 * not XXX, but ZZZ (bizarre).
281 * promiscuous mode can be toggled to ignore NWIDs. By default,
282 * it does not. Caution should be exercised about combining
283 * this mode with IFF_ALLMULTI which puts this driver in
286 static int wl_ignore_nwid = 0;
287 SYSCTL_INT(_machdep, OID_AUTO, wl_ignore_nwid, CTLFLAG_RW, &wl_ignore_nwid, 0, "");
290 * Emit diagnostics about transmission problems
292 static int xmt_watch = 0;
293 SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_watch, CTLFLAG_RW, &xmt_watch, 0, "");
296 * Collect SNR statistics
298 static int gathersnr = 0;
299 SYSCTL_INT(_machdep, OID_AUTO, wl_gather_snr, CTLFLAG_RW, &gathersnr, 0, "");
301 static void wlstart(struct ifnet *ifp);
302 static void wlinit(void *xsc);
303 static int wlioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
304 static timeout_t wlwatchdog;
305 static ointhand2_t wlintr;
306 static void wlxmt(int unt, struct mbuf *m);
307 static int wldiag(int unt);
308 static int wlconfig(int unit);
309 static int wlcmd(int unit, char *str);
310 static void wlmmcstat(int unit);
311 static u_short wlbldru(int unit);
312 static u_short wlmmcread(u_int base, u_short reg);
313 static void wlinitmmc(int unit);
314 static void wlsetirq(int base, int irq);
315 static int wlhwrst(int unit);
316 static void wlrustrt(int unit);
317 static void wlbldcu(int unit);
318 static int wlack(int unit);
319 static int wlread(int unit, u_short fd_p);
320 static void getsnr(int unit);
321 static void wlrcv(int unit);
322 static int wlrequeue(int unit, u_short fd_p);
323 static void wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
324 static void wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
325 static void wltbd(int unit);
326 static void wlgetpsa(int base, u_char *buf);
327 static void wlsetpsa(int unit);
328 static u_short wlpsacrc(u_char *buf);
329 static void wldump(int unit);
331 static void wl_cache_store(int, int, struct ether_header *, struct mbuf *);
332 static void wl_cache_zero(int unit);
335 # if defined(__FreeBSD__) && __FreeBSD_version < 300000
336 static int check_allmulti(int unit);
340 /* array for maping irq numbers to values for the irq parameter register */
341 static int irqvals[16] = {
342 0, 0, 0, 0x01, 0x02, 0x04, 0, 0x08, 0, 0, 0x10, 0x20, 0x40, 0, 0, 0x80
344 /* mask of valid IRQs */
345 #define WL_IRQS (IRQ3|IRQ4|IRQ5|IRQ7|IRQ10|IRQ11|IRQ12|IRQ15)
350 * This function "probes" or checks for the WaveLAN board on the bus to
351 * see if it is there. As far as I can tell, the best break between this
352 * routine and the attach code is to simply determine whether the board
353 * is configured in properly. Currently my approach to this is to write
354 * and read a word from the SRAM on the board being probed. If the word
355 * comes back properly then we assume the board is there. The config
356 * code expects to see a successful return from the probe routine before
357 * attach will be called.
359 * input : address device is mapped to, and unit # being checked
360 * output : a '1' is returned if the board exists, and a 0 otherwise
364 wlprobe(struct isa_device *id)
366 struct wl_softc *sc = &wl_softc[id->id_unit];
367 register short base = id->id_iobase;
368 int unit = id->id_unit;
369 char *str = "wl%d: board out of range [0..%d]\n";
371 unsigned long oldpri;
375 * regular CMD() will not work, since no softc yet
377 #define PCMD(base, hacr) outw((base), (hacr))
380 PCMD(base, HACR_RESET); /* reset the board */
381 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
382 PCMD(base, HACR_RESET); /* reset the board */
383 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
386 /* clear reset command and set PIO#1 in autoincrement mode */
387 PCMD(base, HACR_DEFAULT);
388 PCMD(base, HACR_DEFAULT);
389 outw(PIOR1(base), 0); /* go to beginning of RAM */
390 outsw(PIOP1(base), str, strlen(str)/2+1); /* write string */
392 outw(PIOR1(base), 0); /* rewind */
393 insw(PIOP1(base), inbuf, strlen(str)/2+1); /* read result */
395 if (bcmp(str, inbuf, strlen(str)))
398 sc->chan24 = 0; /* 2.4 Gz: config channel */
399 sc->freq24 = 0; /* 2.4 Gz: frequency */
401 /* read the PSA from the board into temporary storage */
402 wlgetpsa(base, inbuf);
404 /* We read the IRQ value from the PSA on the board. */
405 for (irq = 15; irq >= 0; irq--)
406 if (irqvals[irq] == inbuf[WLPSA_IRQNO])
408 if ((irq == 0) || (irqvals[irq] == 0)){
409 printf("wl%d: PSA corrupt (invalid IRQ value)\n", id->id_unit);
410 id->id_irq = 0; /* no interrupt */
413 * If the IRQ requested by the PSA is already claimed by another
414 * device, the board won't work, but the user can still access the
415 * driver to change the IRQ.
417 id->id_irq = (1<<irq); /* use IRQ from PSA */
426 * This function attaches a WaveLAN board to the "system". The rest of
427 * runtime structures are initialized here (this routine is called after
428 * a successful probe of the board). Once the ethernet address is read
429 * and stored, the board's ifnet structure is attached and readied.
431 * input : isa_dev structure setup in autoconfig
432 * output : board structs and ifnet is setup
436 wlattach(struct isa_device *id)
438 struct wl_softc *sc = (struct wl_softc *) &wl_softc[id->id_unit];
439 register short base = id->id_iobase;
441 u_char unit = id->id_unit;
442 register struct ifnet *ifp = &sc->wl_if;
445 printf("wlattach: base %x, unit %d\n", base, unit);
447 id->id_ointr = wlintr;
452 sc->hacr = HACR_RESET;
453 callout_handle_init(&sc->watchdog_ch);
454 CMD(unit); /* reset the board */
455 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
457 /* clear reset command and set PIO#2 in parameter access mode */
458 sc->hacr = (HACR_DEFAULT & ~HACR_16BITS);
461 /* Read the PSA from the board for our later reference */
462 wlgetpsa(base, sc->psa);
465 sc->nwid[0] = sc->psa[WLPSA_NWID];
466 sc->nwid[1] = sc->psa[WLPSA_NWID+1];
468 /* fetch MAC address - decide which one first */
469 if (sc->psa[WLPSA_MACSEL] & 1) {
474 for(i=0; i < WAVELAN_ADDR_SIZE; ++i) {
475 sc->wl_addr[i] = sc->psa[j + i];
478 /* enter normal 16 bit mode operation */
479 sc->hacr = HACR_DEFAULT;
483 outw(PIOR1(base), OFFSET_SCB + 8); /* address of scb_crcerrs */
484 outw(PIOP1(base), 0); /* clear scb_crcerrs */
485 outw(PIOP1(base), 0); /* clear scb_alnerrs */
486 outw(PIOP1(base), 0); /* clear scb_rscerrs */
487 outw(PIOP1(base), 0); /* clear scb_ovrnerrs */
489 bzero(ifp, sizeof(ifp));
491 ifp->if_unit = id->id_unit;
492 ifp->if_mtu = WAVELAN_MTU;
493 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
495 ifp->if_flags |= IFF_DEBUG;
498 ifp->if_flags |= IFF_MULTICAST;
502 ifp->if_init = wlinit;
503 ifp->if_output = ether_output;
504 ifp->if_start = wlstart;
505 ifp->if_ioctl = wlioctl;
506 ifp->if_timer = 0; /* paranoia */
516 bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
519 bcopy(&sc->wl_addr[0], sc->wl_ac.ac_enaddr, WAVELAN_ADDR_SIZE);
520 printf("%s%d: address %6D, NWID 0x%02x%02x", ifp->if_name, ifp->if_unit,
521 sc->wl_ac.ac_enaddr, ":", sc->nwid[0], sc->nwid[1]);
523 printf(", Freq %d MHz",sc->freq24); /* 2.4 Gz */
524 printf("\n"); /* 2.4 Gz */
533 * Print out interesting information about the 82596.
538 register struct wl_softc *sp = WLSOFTC(unit);
542 printf("hasr %04x\n", inw(HASR(base)));
544 printf("scb at %04x:\n ", OFFSET_SCB);
545 outw(PIOR1(base), OFFSET_SCB);
546 for(i = 0; i < 8; i++)
547 printf("%04x ", inw(PIOP1(base)));
550 printf("cu at %04x:\n ", OFFSET_CU);
551 outw(PIOR1(base), OFFSET_CU);
552 for(i = 0; i < 8; i++)
553 printf("%04x ", inw(PIOP1(base)));
556 printf("tbd at %04x:\n ", OFFSET_TBD);
557 outw(PIOR1(base), OFFSET_TBD);
558 for(i = 0; i < 4; i++)
559 printf("%04x ", inw(PIOP1(base)));
563 /* Initialize the Modem Management Controller */
567 register struct wl_softc *sp = WLSOFTC(unit);
573 /* enter 8 bit operation */
574 sp->hacr = (HACR_DEFAULT & ~HACR_16BITS);
577 configured = sp->psa[WLPSA_CONFIGURED] & 1;
580 * Set default modem control parameters. Taken from NCR document
583 MMC_WRITE(MMC_JABBER_ENABLE, 0x01);
584 MMC_WRITE(MMC_ANTEN_SEL, 0x02);
585 MMC_WRITE(MMC_IFS, 0x20);
586 MMC_WRITE(MMC_MOD_DELAY, 0x04);
587 MMC_WRITE(MMC_JAM_TIME, 0x38);
588 MMC_WRITE(MMC_DECAY_PRM, 0x00); /* obsolete ? */
589 MMC_WRITE(MMC_DECAY_UPDAT_PRM, 0x00);
591 MMC_WRITE(MMC_LOOPT_SEL, 0x00);
592 if (sp->psa[WLPSA_COMPATNO] & 1) {
593 MMC_WRITE(MMC_THR_PRE_SET, 0x01); /* 0x04 for AT and 0x01 for MCA */
595 MMC_WRITE(MMC_THR_PRE_SET, 0x04); /* 0x04 for AT and 0x01 for MCA */
597 MMC_WRITE(MMC_QUALITY_THR, 0x03);
599 /* use configuration defaults from parameter storage area */
600 if (sp->psa[WLPSA_NWIDENABLE] & 1) {
601 if ((mode & (MOD_PROM | MOD_ENAL)) && wl_ignore_nwid) {
602 MMC_WRITE(MMC_LOOPT_SEL, 0x40);
604 MMC_WRITE(MMC_LOOPT_SEL, 0x00);
607 MMC_WRITE(MMC_LOOPT_SEL, 0x40); /* disable network id check */
609 MMC_WRITE(MMC_THR_PRE_SET, sp->psa[WLPSA_THRESH]);
610 MMC_WRITE(MMC_QUALITY_THR, sp->psa[WLPSA_QUALTHRESH]);
612 MMC_WRITE(MMC_FREEZE, 0x00);
613 MMC_WRITE(MMC_ENCR_ENABLE, 0x00);
615 MMC_WRITE(MMC_NETW_ID_L,sp->nwid[1]); /* set NWID */
616 MMC_WRITE(MMC_NETW_ID_H,sp->nwid[0]);
618 /* enter normal 16 bit mode operation */
619 sp->hacr = HACR_DEFAULT;
621 CMD(unit); /* virtualpc1 needs this! */
623 if (sp->psa[WLPSA_COMPATNO]== /* 2.4 Gz: half-card ver */
624 WLPSA_COMPATNO_WL24B) { /* 2.4 Gz */
625 i=sp->chan24<<4; /* 2.4 Gz: position ch # */
626 MMC_WRITE(MMC_EEADDR,i+0x0f); /* 2.4 Gz: named ch, wc=16 */
627 MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+ /* 2.4 Gz: Download Synths */
628 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: Read EEPROM */
629 for (i=0; i<1000; ++i) { /* 2.4 Gz: wait for download */
630 DELAY(40); /* 2.4 Gz */
631 if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and */
632 &(MMC_EECTRLstat_DWLD /* 2.4 Gz: EEBUSY */
633 +MMC_EECTRLstat_EEBUSY))==0) /* 2.4 Gz: */
634 break; /* 2.4 Gz: download finished */
636 if (i==1000) printf("wl: synth load failed\n"); /* 2.4 Gz */
637 MMC_WRITE(MMC_EEADDR,0x61); /* 2.4 Gz: default pwr, wc=2 */
638 MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+ /* 2.4 Gz: Download Xmit Pwr */
639 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: Read EEPROM */
640 for (i=0; i<1000; ++i) { /* 2.4 Gz: wait for download */
641 DELAY(40); /* 2.4 Gz */
642 if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and */
643 &(MMC_EECTRLstat_DWLD /* 2.4 Gz: EEBUSY */
644 +MMC_EECTRLstat_EEBUSY))==0) /* 2.4 Gz: */
645 break; /* 2.4 Gz: download finished */
647 if (i==1000) printf("wl: xmit pwr load failed\n"); /* 2.4 Gz */
648 MMC_WRITE(MMC_ANALCTRL, /* 2.4 Gz: EXT ant+polarity */
649 MMC_ANALCTRL_ANTPOL + /* 2.4 Gz: */
650 MMC_ANALCTRL_EXTANT); /* 2.4 Gz: */
651 i=sp->chan24<<4; /* 2.4 Gz: position ch # */
652 MMC_WRITE(MMC_EEADDR,i); /* 2.4 Gz: get frequency */
653 MMC_WRITE(MMC_EECTRL, /* 2.4 Gz: EEPROM read */
654 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: */
655 DELAY(40); /* 2.4 Gz */
656 i = wlmmcread(base,MMC_EEDATALrv) /* 2.4 Gz: freq val */
657 + (wlmmcread(base,MMC_EEDATAHrv)<<8); /* 2.4 Gz */
658 sp->freq24 = (i>>6)+2400; /* 2.4 Gz: save real freq */
665 * Another routine that interfaces the "if" layer to this driver.
666 * Simply resets the structures that are used by "upper layers".
667 * As well as calling wlhwrst that does reset the WaveLAN board.
669 * input : softc pointer for this interface
670 * output : structures (if structs) and board are reset
676 register struct wl_softc *sc = xsc;
677 struct ifnet *ifp = &sc->wl_if;
682 if (sc->wl_if.if_flags & IFF_DEBUG)
683 printf("wl%d: entered wlinit()\n",sc->unit);
685 #if defined(__FreeBSD__) && __FreeBSD_version >= 300000
686 if (ifp->if_addrhead.tqh_first == (struct ifaddr *)0) {
688 if (ifp->if_addrlist == (struct ifaddr *)0) {
693 if ((stat = wlhwrst(sc->unit)) == TRUE) {
694 sc->wl_if.if_flags |= IFF_RUNNING; /* same as DSF_RUNNING */
696 * OACTIVE is used by upper-level routines
699 sc->wl_if.if_flags &= ~IFF_OACTIVE; /* same as tbusy below */
701 sc->flags |= DSF_RUNNING;
703 untimeout(wlwatchdog, sc, sc->watchdog_ch);
707 printf("wl%d init(): trouble resetting board.\n", sc->unit);
715 * This routine resets the WaveLAN board that corresponds to the
716 * board number passed in.
718 * input : board number to do a hardware reset
719 * output : board is reset
725 register struct wl_softc *sc = WLSOFTC(unit);
727 short base = sc->base;
730 if (sc->wl_if.if_flags & IFF_DEBUG)
731 printf("wl%d: entered wlhwrst()\n",unit);
733 sc->hacr = HACR_RESET;
734 CMD(unit); /* reset the board */
736 /* clear reset command and set PIO#1 in autoincrement mode */
737 sc->hacr = HACR_DEFAULT;
741 if (sc->wl_if.if_flags & IFF_DEBUG)
742 wlmmcstat(unit); /* Display MMC registers */
744 wlbldcu(unit); /* set up command unit structures */
746 if (wldiag(unit) == 0)
749 if (wlconfig(unit) == 0)
752 * insert code for loopback test here
754 wlrustrt(unit); /* start receive unit */
756 /* enable interrupts */
757 sc->hacr = (HACR_DEFAULT | HACR_INTRON);
766 * This function builds up the command unit structures. It inits
767 * the scp, iscp, scb, cb, tbd, and tbuf.
773 register struct wl_softc *sc = WLSOFTC(unit);
774 short base = sc->base;
782 bzero(&scp, sizeof(scp));
784 scp.scp_iscp = OFFSET_ISCP;
785 scp.scp_iscp_base = 0;
786 outw(PIOR1(base), OFFSET_SCP);
787 outsw(PIOP1(base), &scp, sizeof(scp_t)/2);
789 bzero(&iscp, sizeof(iscp));
791 iscp.iscp_scb_offset = OFFSET_SCB;
793 iscp.iscp_scb_base = 0;
794 outw(PIOR1(base), OFFSET_ISCP);
795 outsw(PIOP1(base), &iscp, sizeof(iscp_t)/2);
798 scb.scb_command = SCB_RESET;
799 scb.scb_cbl_offset = OFFSET_CU;
800 scb.scb_rfa_offset = OFFSET_RU;
804 scb.scb_ovrnerrs = 0;
805 outw(PIOR1(base), OFFSET_SCB);
806 outsw(PIOP1(base), &scb, sizeof(scb_t)/2);
810 outw(PIOR0(base), OFFSET_ISCP + 0); /* address of iscp_busy */
811 for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
812 if (i <= 0) printf("wl%d bldcu(): iscp_busy timeout.\n", unit);
813 outw(PIOR0(base), OFFSET_SCB + 0); /* address of scb_status */
814 for (i = STATUS_TRIES; i-- > 0; ) {
815 if (inw(PIOP0(base)) == (SCB_SW_CX|SCB_SW_CNA))
819 printf("wl%d bldcu(): not ready after reset.\n", unit);
823 cb.ac_command = AC_CW_EL; /* NOP */
824 cb.ac_link_offset = OFFSET_CU;
825 outw(PIOR1(base), OFFSET_CU);
826 outsw(PIOP1(base), &cb, 6/2);
829 tbd.next_tbd_offset = I82586NULL;
832 outw(PIOR1(base), OFFSET_TBD);
833 outsw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
841 * input : board number
842 * output : stuff sent to board if any there
846 wlstart(struct ifnet *ifp)
848 int unit = ifp->if_unit;
850 register struct wl_softc *sc = WLSOFTC(unit);
851 short base = sc->base;
852 int scb_status, cu_status, scb_command;
855 if (sc->wl_if.if_flags & IFF_DEBUG)
856 printf("wl%d: entered wlstart()\n",unit);
859 outw(PIOR1(base), OFFSET_CU);
860 cu_status = inw(PIOP1(base));
861 outw(PIOR0(base),OFFSET_SCB + 0); /* scb_status */
862 scb_status = inw(PIOP0(base));
863 outw(PIOR0(base), OFFSET_SCB + 2);
864 scb_command = inw(PIOP0(base));
867 * don't need OACTIVE check as tbusy here checks to see
868 * if we are already busy
871 if((scb_status & 0x0700) == SCB_CUS_IDLE &&
872 (cu_status & AC_SW_B) == 0){
874 untimeout(wlwatchdog, sc, sc->watchdog_ch);
875 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
877 * This is probably just a race. The xmt'r is just
878 * became idle but WE have masked interrupts so ...
881 printf("wl%d: CU idle, scb %04x %04x cu %04x\n",
882 unit, scb_status, scb_command, cu_status);
884 if (xmt_watch) printf("!!");
886 return; /* genuinely still busy */
888 } else if((scb_status & 0x0700) == SCB_CUS_ACTV ||
889 (cu_status & AC_SW_B)){
891 printf("wl%d: CU unexpectedly busy; scb %04x cu %04x\n",
892 unit, scb_status, cu_status);
894 if (xmt_watch) printf("wl%d: busy?!",unit);
895 return; /* hey, why are we busy? */
898 /* get ourselves some data */
900 IF_DEQUEUE(&ifp->if_snd, m);
901 if (m != (struct mbuf *)0) {
903 /* let BPF see it before we commit it */
909 /* set the watchdog timer so that if the board
910 * fails to interrupt we will restart
912 /* try 10 ticks, not very long */
913 sc->watchdog_ch = timeout(wlwatchdog, sc, 10);
914 sc->wl_ac.ac_if.if_flags |= IFF_OACTIVE;
915 sc->wl_if.if_opackets++;
918 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
926 * This routine does the actual copy of data (including ethernet header
927 * structure) from the WaveLAN to an mbuf chain that will be passed up
928 * to the "if" (network interface) layer. NOTE: we currently
929 * don't handle trailer protocols, so if that is needed, it will
930 * (at least in part) be added here. For simplicities sake, this
931 * routine copies the receive buffers from the board into a local (stack)
932 * buffer until the frame has been copied from the board. Once in
933 * the local buffer, the contents are copied to an mbuf chain that
934 * is then enqueued onto the appropriate "if" queue.
936 * input : board number, and an frame descriptor address
937 * output : the packet is put into an mbuf chain, and passed up
938 * assumes : if any errors occur, packet is "dropped on the floor"
942 wlread(int unit, u_short fd_p)
944 register struct wl_softc *sc = WLSOFTC(unit);
945 register struct ifnet *ifp = &sc->wl_if;
946 short base = sc->base;
948 struct ether_header eh;
952 u_short mlen, len, clen;
953 u_short bytes_in_msg, bytes_in_mbuf, bytes;
957 if (sc->wl_if.if_flags & IFF_DEBUG)
958 printf("wl%d: entered wlread()\n",unit);
960 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
961 printf("wl%d read(): board is not running.\n", ifp->if_unit);
962 sc->hacr &= ~HACR_INTRON;
963 CMD(unit); /* turn off interrupts */
965 /* read ether_header info out of device memory. doesn't
966 * go into mbuf. goes directly into eh structure
968 len = sizeof(struct ether_header); /* 14 bytes */
969 outw(PIOR1(base), fd_p);
970 insw(PIOP1(base), &fd, (sizeof(fd_t) - len)/2);
971 insw(PIOP1(base), &eh, (len-2)/2);
972 eh.ether_type = ntohs(inw(PIOP1(base)));
974 if (sc->wl_if.if_flags & IFF_DEBUG) {
975 printf("wlread: rcv packet, type is %x\n", eh.ether_type);
979 * WARNING. above is done now in ether_input, above may be
980 * useful for debug. jrb
982 eh.ether_type = htons(eh.ether_type);
984 if (fd.rbd_offset == I82586NULL) {
985 printf("wl%d read(): Invalid buffer\n", unit);
986 if (wlhwrst(unit) != TRUE) {
987 printf("wl%d read(): hwrst trouble.\n", unit);
992 outw(PIOR1(base), fd.rbd_offset);
993 insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
994 bytes_in_msg = rbd.status & RBD_SW_COUNT;
995 MGETHDR(m, M_DONTWAIT, MT_DATA);
997 if (m == (struct mbuf *)0) {
999 * not only do we want to return, we need to drop the packet on
1000 * the floor to clear the interrupt.
1003 if (wlhwrst(unit) != TRUE) {
1004 sc->hacr &= ~HACR_INTRON;
1005 CMD(unit); /* turn off interrupts */
1006 printf("wl%d read(): hwrst trouble.\n", unit);
1010 m->m_next = (struct mbuf *) 0;
1011 m->m_pkthdr.rcvif = ifp;
1012 m->m_pkthdr.len = 0; /* don't know this yet */
1015 /* always use a cluster. jrb
1017 MCLGET(m, M_DONTWAIT);
1018 if (m->m_flags & M_EXT) {
1019 m->m_len = MCLBYTES;
1023 if (wlhwrst(unit) != TRUE) {
1024 sc->hacr &= ~HACR_INTRON;
1025 CMD(unit); /* turn off interrupts */
1026 printf("wl%d read(): hwrst trouble.\n", unit);
1033 bytes_in_mbuf = m->m_len;
1034 mb_p = mtod(tm, u_char *);
1035 bytes = min(bytes_in_mbuf, bytes_in_msg);
1042 outw(PIOR1(base), rbd.buffer_addr);
1043 insw(PIOP1(base), mb_p, len/2);
1047 if (!(bytes_in_mbuf -= bytes)) {
1048 MGET(tm->m_next, M_DONTWAIT, MT_DATA);
1050 if (tm == (struct mbuf *)0) {
1052 printf("wl%d read(): No mbuf nth\n", unit);
1053 if (wlhwrst(unit) != TRUE) {
1054 sc->hacr &= ~HACR_INTRON;
1055 CMD(unit); /* turn off interrupts */
1056 printf("wl%d read(): hwrst trouble.\n", unit);
1062 bytes_in_mbuf = MLEN;
1063 mb_p = mtod(tm, u_char *);
1068 if (!(bytes_in_msg -= bytes)) {
1069 if (rbd.status & RBD_SW_EOF ||
1070 rbd.next_rbd_offset == I82586NULL) {
1074 outw(PIOR1(base), rbd.next_rbd_offset);
1075 insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1076 bytes_in_msg = rbd.status & RBD_SW_COUNT;
1079 rbd.buffer_addr += bytes;
1082 bytes = min(bytes_in_mbuf, bytes_in_msg);
1085 m->m_pkthdr.len = clen;
1089 * Check if there's a BPF listener on this interface. If so, hand off
1090 * the raw packet to bpf.
1093 /* bpf assumes header is in mbufs. It isn't. We can
1094 * fool it without allocating memory as follows.
1095 * Trick borrowed from if_ie.c
1098 m0.m_len = sizeof eh;
1099 m0.m_data = (caddr_t) &eh;
1107 * If hw is in promiscuous mode (note that I said hardware, not if
1108 * IFF_PROMISC is set in ifnet flags), then if this is a unicast
1109 * packet and the MAC dst is not us, drop it. This check was formerly
1110 * inside the bpf if, above, but IFF_MULTI causes hw promisc without
1111 * a bpf listener, so this is wrong.
1112 * Greg Troxel <gdt@ir.bbn.com>, 1998-08-07
1115 * TBD: also discard packets where NWID does not match.
1116 * However, there does not appear to be a way to read the nwid
1117 * for a received packet. -gdt 1998-08-07
1120 #ifdef WL_USE_IFNET_PROMISC_CHECK /* not defined */
1121 (sc->wl_ac.ac_if.if_flags & (IFF_PROMISC|IFF_ALLMULTI))
1123 /* hw is in promisc mode if this is true */
1124 (sc->mode & (MOD_PROM | MOD_ENAL))
1127 (eh.ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
1128 bcmp(eh.ether_dhost, sc->wl_ac.ac_enaddr,
1129 sizeof(eh.ether_dhost)) != 0 ) {
1135 if (sc->wl_if.if_flags & IFF_DEBUG)
1136 printf("wl%d: wlrecv %d bytes\n", unit, clen);
1140 wl_cache_store(unit, base, &eh, m);
1144 * received packet is now in a chain of mbuf's. next step is
1145 * to pass the packet upwards.
1148 ether_input(&sc->wl_if, &eh, m);
1155 * This routine processes an ioctl request from the "if" layer
1158 * input : pointer the appropriate "if" struct, command, and data
1159 * output : based on command appropriate action is taken on the
1160 * WaveLAN board(s) or related structures
1161 * return : error is returned containing exit conditions
1165 wlioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1167 register struct ifaddr *ifa = (struct ifaddr *)data;
1168 register struct ifreq *ifr = (struct ifreq *)data;
1169 int unit = ifp->if_unit;
1170 register struct wl_softc *sc = WLSOFTC(unit);
1171 short base = sc->base;
1173 int opri, error = 0;
1175 struct proc *p = curproc; /* XXX */
1176 int irq, irqval, i, isroot, size;
1182 if (sc->wl_if.if_flags & IFF_DEBUG)
1183 printf("wl%d: entered wlioctl()\n",unit);
1188 /* Set own IP address and enable interface */
1189 ifp->if_flags |= IFF_UP;
1190 switch (ifa->ifa_addr->sa_family) {
1194 arp_ifinit((struct arpcom *)ifp, ifa);
1200 register struct ns_addr *ina =
1201 &(IA_SNS(ifa)->sns_addr);
1202 if (ns_nullhost(*ina))
1203 ina->x_host = *(union ns_host *)(ds->wl_addr);
1205 wlsetaddr(ina->x_host.c_host, unit);
1216 if (ifp->if_flags & IFF_ALLMULTI) {
1219 if (ifp->if_flags & IFF_PROMISC) {
1222 if(ifp->if_flags & IFF_LINK0) {
1226 * force a complete reset if the recieve multicast/
1227 * promiscuous mode changes so that these take
1228 * effect immediately.
1231 if (sc->mode != mode) {
1233 if (sc->flags & DSF_RUNNING) {
1234 sc->flags &= ~DSF_RUNNING;
1238 /* if interface is marked DOWN and still running then
1241 if ((ifp->if_flags & IFF_UP) == 0 && sc->flags & DSF_RUNNING) {
1242 printf("wl%d ioctl(): board is not running\n", unit);
1243 sc->flags &= ~DSF_RUNNING;
1244 sc->hacr &= ~HACR_INTRON;
1245 CMD(unit); /* turn off interrupts */
1247 /* else if interface is UP and RUNNING, start it
1249 else if (ifp->if_flags & IFF_UP && (sc->flags & DSF_RUNNING) == 0) {
1253 /* if WLDEBUG set on interface, then printf rf-modem regs
1255 if(ifp->if_flags & IFF_DEBUG)
1262 #if defined(__FreeBSD__) && __FreeBSD_version < 300000
1263 if (cmd == SIOCADDMULTI) {
1264 error = ether_addmulti(ifr, &sc->wl_ac);
1267 error = ether_delmulti(ifr, &sc->wl_ac);
1270 /* see if we should be in all multicast mode
1271 * note that 82586 cannot do that, must simulate with
1274 if ( check_allmulti(unit)) {
1275 ifp->if_flags |= IFF_ALLMULTI;
1276 sc->mode |= MOD_ENAL;
1277 sc->flags &= ~DSF_RUNNING;
1283 if (error == ENETRESET) {
1284 if(sc->flags & DSF_RUNNING) {
1285 sc->flags &= ~DSF_RUNNING;
1294 /* DEVICE SPECIFIC */
1297 /* copy the PSA out to the caller */
1299 /* pointer to buffer in user space */
1300 up = (void *)ifr->ifr_data;
1301 /* work out if they're root */
1302 isroot = (suser(p->p_ucred, &p->p_acflag) == 0);
1304 for (i = 0; i < 0x40; i++) {
1305 /* don't hand the DES key out to non-root users */
1306 if ((i > WLPSA_DESKEY) && (i < (WLPSA_DESKEY + 8)) && !isroot)
1308 if (subyte((up + i), sc->psa[i]))
1314 /* copy the PSA in from the caller; we only copy _some_ values */
1317 if ((error = suser(p->p_ucred, &p->p_acflag)))
1319 error = EINVAL; /* assume the worst */
1320 /* pointer to buffer in user space containing data */
1321 up = (void *)ifr->ifr_data;
1323 /* check validity of input range */
1324 for (i = 0; i < 0x40; i++)
1325 if (fubyte(up + i) < 0)
1328 /* check IRQ value */
1329 irqval = fubyte(up+WLPSA_IRQNO);
1330 for (irq = 15; irq >= 0; irq--)
1331 if(irqvals[irq] == irqval)
1333 if (irq == 0) /* oops */
1336 sc->psa[WLPSA_IRQNO] = irqval;
1339 for (i = 0; i < 6; i++)
1340 sc->psa[WLPSA_LOCALMAC+i] = fubyte(up+WLPSA_LOCALMAC+i);
1343 sc->psa[WLPSA_MACSEL] = fubyte(up+WLPSA_MACSEL);
1346 sc->psa[WLPSA_NWID] = fubyte(up+WLPSA_NWID);
1347 sc->psa[WLPSA_NWID+1] = fubyte(up+WLPSA_NWID+1);
1350 wlsetpsa(unit); /* update the PSA */
1354 /* get the current NWID out of the sc since we stored it there */
1356 ifr->ifr_data = (caddr_t) (sc->nwid[0] << 8 | sc->nwid[1]);
1361 * change the nwid dynamically. This
1362 * ONLY changes the radio modem and does not
1366 * 1. save in softc "soft registers"
1367 * 2. save in radio modem (MMC)
1371 if ((error = suser(p->p_ucred, &p->p_acflag)))
1373 if (!(ifp->if_flags & IFF_UP)) {
1374 error = EIO; /* only allowed while up */
1377 * soft c nwid shadows radio modem setting
1379 sc->nwid[0] = (int)ifr->ifr_data >> 8;
1380 sc->nwid[1] = (int)ifr->ifr_data & 0xff;
1381 MMC_WRITE(MMC_NETW_ID_L,sc->nwid[1]);
1382 MMC_WRITE(MMC_NETW_ID_H,sc->nwid[0]);
1386 /* copy the EEPROM in 2.4 Gz WaveMODEM out to the caller */
1389 if ((error = suser(p->p_ucred, &p->p_acflag)))
1391 /* pointer to buffer in user space */
1392 up = (void *)ifr->ifr_data;
1394 for (i=0x00; i<0x80; ++i) { /* 2.4 Gz: size of EEPROM */
1395 MMC_WRITE(MMC_EEADDR,i); /* 2.4 Gz: get frequency */
1396 MMC_WRITE(MMC_EECTRL, /* 2.4 Gz: EEPROM read */
1397 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: */
1398 DELAY(40); /* 2.4 Gz */
1399 if (subyte(up + 2*i , /* 2.4 Gz: pass low byte of */
1400 wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word */
1401 ) return(EFAULT); /* 2.4 Gz: */
1402 if (subyte(up + 2*i+1, /* 2.4 Gz: pass hi byte of */
1403 wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word */
1404 ) return(EFAULT); /* 2.4 Gz: */
1409 /* zero (Delete) the wl cache */
1412 if ((error = suser(p->p_ucred, &p->p_acflag)))
1414 wl_cache_zero(unit);
1417 /* read out the number of used cache elements */
1419 ifr->ifr_data = (caddr_t) sc->w_sigitems;
1422 /* read out the wl cache */
1424 /* pointer to buffer in user space */
1425 up = (void *)ifr->ifr_data;
1426 cpt = (char *) &sc->w_sigcache[0];
1427 size = sc->w_sigitems * sizeof(struct w_sigcache);
1429 for (i = 0; i < size; i++) {
1430 if (subyte((up + i), *cpt++))
1446 * Called if the timer set in wlstart expires before an interrupt is received
1447 * from the wavelan. It seems to lose interrupts sometimes.
1448 * The watchdog routine gets called if the transmitter failed to interrupt
1450 * input : which board is timing out
1451 * output : board reset
1455 wlwatchdog(void *vsc)
1457 struct wl_softc *sc = vsc;
1458 int unit = sc->unit;
1460 log(LOG_ERR, "wl%d: wavelan device timeout on xmit\n", unit);
1461 sc->wl_ac.ac_if.if_oerrors++;
1468 * This function is the interrupt handler for the WaveLAN
1469 * board. This routine will be called whenever either a packet
1470 * is received, or a packet has successfully been transfered and
1471 * the unit is ready to transmit another packet.
1473 * input : board number that interrupted
1474 * output : either a packet is received, or a packet is transfered
1481 register struct wl_softc *sc = &wl_softc[unit];
1484 short base = sc->base;
1487 u_short int_type, int_type1;
1490 if (sc->wl_if.if_flags & IFF_DEBUG)
1491 printf("wl%d: wlintr() called\n",unit);
1494 if((int_type = inw(HASR(base))) & HASR_MMC_INTR) {
1495 /* handle interrupt from the modem management controler */
1496 /* This will clear the interrupt condition */
1497 (void) wlmmcread(base,MMC_DCE_STATUS); /* ignored for now */
1500 if(!(int_type & HASR_INTR)){ /* return if no interrupt from 82586 */
1501 /* commented out. jrb. it happens when reinit occurs
1502 printf("wlintr: int_type %x, dump follows\n", int_type);
1511 outw(PIOR0(base), OFFSET_SCB + 0); /* get scb status */
1512 int_type = (inw(PIOP0(base)) & SCB_SW_INT);
1513 if (int_type == 0) /* no interrupts left */
1516 int_type1 = wlack(unit); /* acknowledge interrupt(s) */
1517 /* make sure no bits disappeared (others may appear) */
1518 if ((int_type & int_type1) != int_type)
1519 printf("wlack() int bits disappeared : %04x != int_type %04x\n",
1520 int_type1, int_type);
1521 int_type = int_type1; /* go with the new status */
1525 if (int_type & SCB_SW_FR) {
1526 sc->wl_if.if_ipackets++;
1530 * receiver not ready
1532 if (int_type & SCB_SW_RNR) {
1533 sc->wl_if.if_ierrors++;
1535 if (sc->wl_if.if_flags & IFF_DEBUG)
1536 printf("wl%d intr(): receiver overrun! begin_fd = %x\n",
1537 unit, sc->begin_fd);
1544 if (int_type & SCB_SW_CNA) {
1546 * At present, we don't care about CNA's. We
1547 * believe they are a side effect of XMT.
1550 if (int_type & SCB_SW_CX) {
1552 * At present, we only request Interrupt for
1555 outw(PIOR1(base), OFFSET_CU); /* get command status */
1556 ac_status = inw(PIOP1(base));
1558 if (xmt_watch) { /* report some anomalies */
1560 if (sc->tbusy == 0) {
1561 printf("wl%d: xmt intr but not busy, CU %04x\n",
1564 if (ac_status == 0) {
1565 printf("wl%d: xmt intr but ac_status == 0\n", unit);
1567 if (ac_status & AC_SW_A) {
1568 printf("wl%d: xmt aborted\n",unit);
1571 if (ac_status & TC_CARRIER) {
1572 printf("wl%d: no carrier\n", unit);
1575 if (ac_status & TC_CLS) {
1576 printf("wl%d: no CTS\n", unit);
1578 if (ac_status & TC_DMA) {
1579 printf("wl%d: DMA underrun\n", unit);
1581 if (ac_status & TC_DEFER) {
1582 printf("wl%d: xmt deferred\n",unit);
1584 if (ac_status & TC_SQE) {
1585 printf("wl%d: heart beat\n", unit);
1587 if (ac_status & TC_COLLISION) {
1588 printf("wl%d: too many collisions\n", unit);
1591 /* if the transmit actually failed, or returned some status */
1592 if ((!(ac_status & AC_SW_OK)) || (ac_status & 0xfff)) {
1593 if (ac_status & (TC_COLLISION | TC_CLS | TC_DMA)) {
1594 sc->wl_if.if_oerrors++;
1596 /* count collisions */
1597 sc->wl_if.if_collisions += (ac_status & 0xf);
1598 /* if TC_COLLISION set and collision count zero, 16 collisions */
1599 if ((ac_status & 0x20) == 0x20) {
1600 sc->wl_if.if_collisions += 0x10;
1604 untimeout(wlwatchdog, sc, sc->watchdog_ch);
1605 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
1606 wlstart(&(sc->wl_if));
1615 * This routine is called by the interrupt handler to initiate a
1616 * packet transfer from the board to the "if" layer above this
1617 * driver. This routine checks if a buffer has been successfully
1618 * received by the WaveLAN. If so, the routine wlread is called
1619 * to do the actual transfer of the board data (including the
1620 * ethernet header) into a packet (consisting of an mbuf chain).
1622 * input : number of the board to check
1623 * output : if a packet is available, it is "sent up"
1629 register struct wl_softc *sc = WLSOFTC(unit);
1630 short base = sc->base;
1631 u_short fd_p, status, offset, link_offset;
1634 if (sc->wl_if.if_flags & IFF_DEBUG)
1635 printf("wl%d: entered wlrcv()\n",unit);
1637 for (fd_p = sc->begin_fd; fd_p != I82586NULL; fd_p = sc->begin_fd) {
1639 outw(PIOR0(base), fd_p + 0); /* address of status */
1640 status = inw(PIOP0(base));
1641 outw(PIOR1(base), fd_p + 4); /* address of link_offset */
1642 link_offset = inw(PIOP1(base));
1643 offset = inw(PIOP1(base)); /* rbd_offset */
1644 if (status == 0xffff || offset == 0xffff /*I82586NULL*/) {
1645 if (wlhwrst(unit) != TRUE)
1646 printf("wl%d rcv(): hwrst ffff trouble.\n", unit);
1648 } else if (status & AC_SW_C) {
1649 if (status == (RFD_DONE|RFD_RSC)) {
1652 if (sc->wl_if.if_flags & IFF_DEBUG)
1653 printf("wl%d RCV: RSC %x\n", unit, status);
1655 sc->wl_if.if_ierrors++;
1656 } else if (!(status & RFD_OK)) {
1657 printf("wl%d RCV: !OK %x\n", unit, status);
1658 sc->wl_if.if_ierrors++;
1659 } else if (status & 0xfff) { /* can't happen */
1660 printf("wl%d RCV: ERRs %x\n", unit, status);
1661 sc->wl_if.if_ierrors++;
1662 } else if (!wlread(unit, fd_p))
1665 if (!wlrequeue(unit, fd_p)) {
1666 /* abort on chain error */
1667 if (wlhwrst(unit) != TRUE)
1668 printf("wl%d rcv(): hwrst trouble.\n", unit);
1671 sc->begin_fd = link_offset;
1682 * This routine puts rbd's used in the last receive back onto the
1683 * free list for the next receive.
1687 wlrequeue(int unit, u_short fd_p)
1689 register struct wl_softc *sc = WLSOFTC(unit);
1690 short base = sc->base;
1692 u_short l_rbdp, f_rbdp, rbd_offset;
1694 outw(PIOR0(base), fd_p + 6);
1695 rbd_offset = inw(PIOP0(base));
1696 if ((f_rbdp = rbd_offset) != I82586NULL) {
1699 outw(PIOR0(base), l_rbdp + 0); /* address of status */
1700 if(inw(PIOP0(base)) & RBD_SW_EOF)
1702 outw(PIOP0(base), 0);
1703 outw(PIOR0(base), l_rbdp + 2); /* next_rbd_offset */
1704 if((l_rbdp = inw(PIOP0(base))) == I82586NULL)
1707 outw(PIOP0(base), 0);
1708 outw(PIOR0(base), l_rbdp + 2); /* next_rbd_offset */
1709 outw(PIOP0(base), I82586NULL);
1710 outw(PIOR0(base), l_rbdp + 8); /* address of size */
1711 outw(PIOP0(base), inw(PIOP0(base)) | AC_CW_EL);
1712 outw(PIOR0(base), sc->end_rbd + 2);
1713 outw(PIOP0(base), f_rbdp); /* end_rbd->next_rbd_offset */
1714 outw(PIOR0(base), sc->end_rbd + 8); /* size */
1715 outw(PIOP0(base), inw(PIOP0(base)) & ~AC_CW_EL);
1716 sc->end_rbd = l_rbdp;
1720 fd.command = AC_CW_EL;
1721 fd.link_offset = I82586NULL;
1722 fd.rbd_offset = I82586NULL;
1723 outw(PIOR1(base), fd_p);
1724 outsw(PIOP1(base), &fd, 8/2);
1726 outw(PIOR1(base), sc->end_fd + 2); /* addr of command */
1727 outw(PIOP1(base), 0); /* command = 0 */
1728 outw(PIOP1(base), fd_p); /* end_fd->link_offset = fd_p */
1735 static int xmt_debug = 0;
1741 * This routine fills in the appropriate registers and memory
1742 * locations on the WaveLAN board and starts the board off on
1745 * input : board number of interest, and a pointer to the mbuf
1746 * output : board memory and registers are set for xfer and attention
1750 wlxmt(int unit, struct mbuf *m)
1752 register struct wl_softc *sc = WLSOFTC(unit);
1753 register u_short xmtdata_p = OFFSET_TBUF;
1754 register u_short xmtshort_p;
1755 struct mbuf *tm_p = m;
1756 register struct ether_header *eh_p = mtod(m, struct ether_header *);
1757 u_char *mb_p = mtod(m, u_char *) + sizeof(struct ether_header);
1758 u_short count = m->m_len - sizeof(struct ether_header);
1760 u_short tbd_p = OFFSET_TBD;
1761 u_short len, clen = 0;
1762 short base = sc->base;
1766 if (sc->wl_if.if_flags & IFF_DEBUG)
1767 printf("wl%d: entered wlxmt()\n",unit);
1771 cb.ac_command = (AC_CW_EL|AC_TRANSMIT|AC_CW_I);
1772 cb.ac_link_offset = I82586NULL;
1773 outw(PIOR1(base), OFFSET_CU);
1774 outsw(PIOP1(base), &cb, 6/2);
1775 outw(PIOP1(base), OFFSET_TBD); /* cb.cmd.transmit.tbd_offset */
1776 outsw(PIOP1(base), eh_p->ether_dhost, WAVELAN_ADDR_SIZE/2);
1777 outw(PIOP1(base), eh_p->ether_type);
1780 if (sc->wl_if.if_flags & IFF_DEBUG) {
1782 printf("XMT mbuf: L%d @%p ", count, (void *)mb_p);
1783 printf("ether type %x\n", eh_p->ether_type);
1787 outw(PIOR0(base), OFFSET_TBD);
1788 outw(PIOP0(base), 0); /* act_count */
1789 outw(PIOR1(base), OFFSET_TBD + 4);
1790 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1791 outw(PIOP1(base), 0); /* buffer_base */
1794 if (clen + count > WAVELAN_MTU)
1800 outw(PIOR1(base), xmtdata_p);
1801 outsw(PIOP1(base), mb_p, len/2);
1803 outw(PIOR0(base), tbd_p); /* address of act_count */
1804 outw(PIOP0(base), inw(PIOP0(base)) + count);
1806 if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1809 /* go to the next descriptor */
1810 outw(PIOR0(base), tbd_p + 2);
1811 tbd_p += sizeof (tbd_t);
1812 outw(PIOP0(base), tbd_p); /* next_tbd_offset */
1813 outw(PIOR0(base), tbd_p);
1814 outw(PIOP0(base), 0); /* act_count */
1815 outw(PIOR1(base), tbd_p + 4);
1816 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1817 outw(PIOP1(base), 0); /* buffer_base */
1818 /* at the end -> coallesce remaining mbufs */
1819 if (tbd_p == OFFSET_TBD + (N_TBD-1) * sizeof (tbd_t)) {
1820 wlsftwsleaze(&count, &mb_p, &tm_p, unit);
1823 /* next mbuf short -> coallesce as needed */
1824 if ( (tm_p->m_next == (struct mbuf *) 0) ||
1825 #define HDW_THRESHOLD 55
1826 tm_p->m_len > HDW_THRESHOLD)
1829 wlhdwsleaze(&count, &mb_p, &tm_p, unit);
1833 } else if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1835 count = tm_p->m_len;
1836 mb_p = mtod(tm_p, u_char *);
1838 if (sc->wl_if.if_flags & IFF_DEBUG)
1840 printf("mbuf+ L%d @%p ", count, (void *)mb_p);
1844 if (sc->wl_if.if_flags & IFF_DEBUG)
1846 printf("CLEN = %d\n", clen);
1848 outw(PIOR0(base), tbd_p);
1849 if (clen < ETHERMIN) {
1850 outw(PIOP0(base), inw(PIOP0(base)) + ETHERMIN - clen);
1851 outw(PIOR1(base), xmtdata_p);
1852 for (xmtshort_p = xmtdata_p; clen < ETHERMIN; clen += 2)
1853 outw(PIOP1(base), 0);
1855 outw(PIOP0(base), inw(PIOP0(base)) | TBD_SW_EOF);
1856 outw(PIOR0(base), tbd_p + 2);
1857 outw(PIOP0(base), I82586NULL);
1859 if (sc->wl_if.if_flags & IFF_DEBUG) {
1867 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
1869 * wait for 586 to clear previous command, complain if it takes
1872 for (spin = 1;;spin = (spin + 1) % 10000) {
1873 if (inw(PIOP0(base)) == 0) { /* it's done, we can go */
1876 if ((spin == 0) && xmt_watch) { /* not waking up, and we care */
1877 printf("wl%d: slow accepting xmit\n",unit);
1880 outw(PIOP0(base), SCB_CU_STRT); /* new command */
1881 SET_CHAN_ATTN(unit);
1886 * Pause to avoid transmit overrun problems.
1887 * The required delay tends to vary with platform type, and may be
1888 * related to interrupt loss.
1890 if (wl_xmit_delay) {
1891 DELAY(wl_xmit_delay);
1899 * This function builds the linear linked lists of fd's and
1900 * rbd's. Based on page 4-32 of 1986 Intel microcom handbook.
1906 register struct wl_softc *sc = WLSOFTC(unit);
1907 short base = sc->base;
1910 u_short fd_p = OFFSET_RU;
1911 u_short rbd_p = OFFSET_RBD;
1914 sc->begin_fd = fd_p;
1915 for(i = 0; i < N_FD; i++) {
1918 fd.link_offset = fd_p + sizeof(fd_t);
1919 fd.rbd_offset = I82586NULL;
1920 outw(PIOR1(base), fd_p);
1921 outsw(PIOP1(base), &fd, 8/2);
1922 fd_p = fd.link_offset;
1924 fd_p -= sizeof(fd_t);
1926 outw(PIOR1(base), fd_p + 2);
1927 outw(PIOP1(base), AC_CW_EL); /* command */
1928 outw(PIOP1(base), I82586NULL); /* link_offset */
1931 outw(PIOR0(base), fd_p + 6); /* address of rbd_offset */
1932 outw(PIOP0(base), rbd_p);
1933 outw(PIOR1(base), rbd_p);
1934 for(i = 0; i < N_RBD; i++) {
1936 rbd.buffer_addr = rbd_p + sizeof(rbd_t) + 2;
1937 rbd.buffer_base = 0;
1938 rbd.size = RCVBUFSIZE;
1940 rbd_p += sizeof(ru_t);
1941 rbd.next_rbd_offset = rbd_p;
1943 rbd.next_rbd_offset = I82586NULL;
1944 rbd.size |= AC_CW_EL;
1945 sc->end_rbd = rbd_p;
1947 outsw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1948 outw(PIOR1(base), rbd_p);
1950 return sc->begin_fd;
1956 * This routine starts the receive unit running. First checks if the
1957 * board is actually ready, then the board is instructed to receive
1964 register struct wl_softc *sc = WLSOFTC(unit);
1965 short base = sc->base;
1969 if (sc->wl_if.if_flags & IFF_DEBUG)
1970 printf("wl%d: entered wlrustrt()\n",unit);
1972 outw(PIOR0(base), OFFSET_SCB);
1973 if (inw(PIOP0(base)) & SCB_RUS_READY){
1974 printf("wlrustrt: RUS_READY\n");
1978 outw(PIOR0(base), OFFSET_SCB + 2);
1979 outw(PIOP0(base), SCB_RU_STRT); /* command */
1980 rfa = wlbldru(unit);
1981 outw(PIOR0(base), OFFSET_SCB + 6); /* address of scb_rfa_offset */
1982 outw(PIOP0(base), rfa);
1984 SET_CHAN_ATTN(unit);
1991 * This routine does a 586 op-code number 7, and obtains the
1992 * diagnose status for the WaveLAN.
1998 register struct wl_softc *sc = WLSOFTC(unit);
1999 short base = sc->base;
2003 if (sc->wl_if.if_flags & IFF_DEBUG)
2004 printf("wl%d: entered wldiag()\n",unit);
2006 outw(PIOR0(base), OFFSET_SCB);
2007 status = inw(PIOP0(base));
2008 if (status & SCB_SW_INT) {
2009 /* state is 2000 which seems ok
2010 printf("wl%d diag(): unexpected initial state %\n",
2011 unit, inw(PIOP0(base)));
2015 outw(PIOR1(base), OFFSET_CU);
2016 outw(PIOP1(base), 0); /* ac_status */
2017 outw(PIOP1(base), AC_DIAGNOSE|AC_CW_EL);/* ac_command */
2018 if(wlcmd(unit, "diag()") == 0)
2020 outw(PIOR0(base), OFFSET_CU);
2021 if (inw(PIOP0(base)) & 0x0800) {
2022 printf("wl%d: i82586 Self Test failed!\n", unit);
2031 * This routine does a standard config of the WaveLAN board.
2037 configure_t configure;
2038 register struct wl_softc *sc = WLSOFTC(unit);
2039 short base = sc->base;
2042 #if defined(__FreeBSD__) && __FreeBSD_version >= 300000
2043 struct ifmultiaddr *ifma;
2046 struct ether_multi *enm;
2047 struct ether_multistep step;
2053 if (sc->wl_if.if_flags & IFF_DEBUG)
2054 printf("wl%d: entered wlconfig()\n",unit);
2056 outw(PIOR0(base), OFFSET_SCB);
2057 if (inw(PIOP0(base)) & SCB_SW_INT) {
2059 printf("wl%d config(): unexpected initial state %x\n",
2060 unit, inw(PIOP0(base)));
2065 outw(PIOR1(base), OFFSET_CU);
2066 outw(PIOP1(base), 0); /* ac_status */
2067 outw(PIOP1(base), AC_CONFIGURE|AC_CW_EL); /* ac_command */
2070 configure.fifolim_bytecnt = 0x080c;
2071 configure.addrlen_mode = 0x0600;
2072 configure.linprio_interframe = 0x2060;
2073 configure.slot_time = 0xf200;
2074 configure.hardware = 0x0008; /* tx even w/o CD */
2075 configure.min_frame_len = 0x0040;
2077 /* This is the configuration block suggested by Marc Meertens
2078 * <mmeerten@obelix.utrecht.NCR.COM> in an e-mail message to John
2079 * Ioannidis on 10 Nov 92.
2081 configure.fifolim_bytecnt = 0x040c;
2082 configure.addrlen_mode = 0x0600;
2083 configure.linprio_interframe = 0x2060;
2084 configure.slot_time = 0xf000;
2085 configure.hardware = 0x0008; /* tx even w/o CD */
2086 configure.min_frame_len = 0x0040;
2089 * below is the default board configuration from p2-28 from 586 book
2091 configure.fifolim_bytecnt = 0x080c;
2092 configure.addrlen_mode = 0x2600;
2093 configure.linprio_interframe = 0x7820; /* IFS=120, ACS=2 */
2094 configure.slot_time = 0xf00c; /* slottime=12 */
2095 configure.hardware = 0x0008; /* tx even w/o CD */
2096 configure.min_frame_len = 0x0040;
2098 if(sc->mode & (MOD_PROM | MOD_ENAL)) {
2099 configure.hardware |= 1;
2101 outw(PIOR1(base), OFFSET_CU + 6);
2102 outsw(PIOP1(base), &configure, sizeof(configure_t)/2);
2104 if(wlcmd(unit, "config()-configure") == 0)
2107 outw(PIOR1(base), OFFSET_CU);
2108 outw(PIOP1(base), 0); /* ac_status */
2109 outw(PIOP1(base), AC_MCSETUP|AC_CW_EL); /* ac_command */
2110 outw(PIOR1(base), OFFSET_CU + 8);
2111 #if defined(__FreeBSD__) && __FreeBSD_version >= 300000
2112 for (ifma = sc->wl_if.if_multiaddrs.lh_first; ifma;
2113 ifma = ifma->ifma_link.le_next) {
2114 if (ifma->ifma_addr->sa_family != AF_LINK)
2117 addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
2118 outw(PIOP1(base), addrp[0] + (addrp[1] << 8));
2119 outw(PIOP1(base), addrp[2] + (addrp[3] << 8));
2120 outw(PIOP1(base), addrp[4] + (addrp[5] << 8));
2124 ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2125 while (enm != NULL) {
2126 unsigned int lo, hi;
2127 /* break if setting a multicast range, else we would crash */
2128 if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2131 lo = (enm->enm_addrlo[3] << 16) + (enm->enm_addrlo[4] << 8)
2132 + enm->enm_addrlo[5];
2133 hi = (enm->enm_addrhi[3] << 16) + (enm->enm_addrhi[4] << 8)
2134 + enm->enm_addrhi[5];
2136 outw(PIOP1(base),enm->enm_addrlo[0] +
2137 (enm->enm_addrlo[1] << 8));
2138 outw(PIOP1(base),enm->enm_addrlo[2] +
2139 ((lo >> 8) & 0xff00));
2140 outw(PIOP1(base), ((lo >> 8) & 0xff) +
2141 ((lo << 8) & 0xff00));
2142 /* #define MCASTDEBUG */
2144 printf("mcast_addr[%d,%d,%d] %x %x %x %x %x %x\n", lo, hi, cnt,
2150 enm->enm_addrlo[5]);
2155 ETHER_NEXT_MULTI(step, enm);
2158 outw(PIOR1(base), OFFSET_CU + 6); /* mc-cnt */
2159 outw(PIOP1(base), cnt * WAVELAN_ADDR_SIZE);
2160 if(wlcmd(unit, "config()-mcaddress") == 0)
2164 outw(PIOR1(base), OFFSET_CU);
2165 outw(PIOP1(base), 0); /* ac_status */
2166 outw(PIOP1(base), AC_IASETUP|AC_CW_EL); /* ac_command */
2167 outw(PIOR1(base), OFFSET_CU + 6);
2168 outsw(PIOP1(base), sc->wl_addr, WAVELAN_ADDR_SIZE/2);
2170 if(wlcmd(unit, "config()-address") == 0)
2181 * Set channel attention bit and busy wait until command has
2182 * completed. Then acknowledge the command completion.
2185 wlcmd(int unit, char *str)
2187 register struct wl_softc *sc = WLSOFTC(unit);
2188 short base = sc->base;
2191 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
2192 outw(PIOP0(base), SCB_CU_STRT);
2194 SET_CHAN_ATTN(unit);
2196 outw(PIOR0(base), OFFSET_CU);
2197 for(i = 0; i < 0xffff; i++)
2198 if (inw(PIOP0(base)) & AC_SW_C)
2200 if (i == 0xffff || !(inw(PIOP0(base)) & AC_SW_OK)) {
2201 printf("wl%d: %s failed; status = %d, inw = %x, outw = %x\n",
2202 unit, str, inw(PIOP0(base)) & AC_SW_OK, inw(PIOP0(base)), inw(PIOR0(base)));
2203 outw(PIOR0(base), OFFSET_SCB);
2204 printf("scb_status %x\n", inw(PIOP0(base)));
2205 outw(PIOR0(base), OFFSET_SCB+2);
2206 printf("scb_command %x\n", inw(PIOP0(base)));
2207 outw(PIOR0(base), OFFSET_SCB+4);
2208 printf("scb_cbl %x\n", inw(PIOP0(base)));
2209 outw(PIOR0(base), OFFSET_CU+2);
2210 printf("cu_cmd %x\n", inw(PIOP0(base)));
2214 outw(PIOR0(base), OFFSET_SCB);
2215 if ((inw(PIOP0(base)) & SCB_SW_INT) && (inw(PIOP0(base)) != SCB_SW_CNA)) {
2217 printf("wl%d %s: unexpected final state %x\n",
2218 unit, str, inw(PIOP0(base)));
2226 * wlack: if the 82596 wants attention because it has finished
2227 * sending or receiving a packet, acknowledge its desire and
2228 * return bits indicating the kind of attention. wlack() returns
2229 * these bits so that the caller can service exactly the
2230 * conditions that wlack() acknowledged.
2236 register u_short cmd;
2237 register struct wl_softc *sc = WLSOFTC(unit);
2238 short base = sc->base;
2240 outw(PIOR1(base), OFFSET_SCB);
2241 if(!(cmd = (inw(PIOP1(base)) & SCB_SW_INT)))
2244 if (sc->wl_if.if_flags & IFF_DEBUG)
2245 printf("wl%d: doing a wlack()\n",unit);
2247 outw(PIOP1(base), cmd);
2248 SET_CHAN_ATTN(unit);
2249 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
2250 for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
2252 printf("wl%d wlack(): board not accepting command.\n", unit);
2259 register struct wl_softc *sc = WLSOFTC(unit);
2260 short base = sc->base;
2261 u_short tbd_p = OFFSET_TBD;
2267 outw(PIOR1(base), tbd_p);
2268 insw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
2269 sum += (tbd.act_count & ~TBD_SW_EOF);
2270 printf("%d: addr %x, count %d (%d), next %x, base %x\n",
2271 i++, tbd.buffer_addr,
2272 (tbd.act_count & ~TBD_SW_EOF), sum,
2273 tbd.next_tbd_offset, tbd.buffer_base);
2274 if (tbd.act_count & TBD_SW_EOF)
2276 tbd_p = tbd.next_tbd_offset;
2281 wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2283 struct mbuf *tm_p = *tm_pp;
2284 u_char *mb_p = *mb_pp;
2290 * can we get a run that will be coallesced or
2291 * that terminates before breaking
2294 count += tm_p->m_len;
2295 if (tm_p->m_len & 1)
2297 } while ((tm_p = tm_p->m_next) != (struct mbuf *)0);
2298 if ( (tm_p == (struct mbuf *)0) ||
2299 count > HDW_THRESHOLD) {
2300 *countp = (*tm_pp)->m_len;
2301 *mb_pp = mtod((*tm_pp), u_char *);
2305 /* we need to copy */
2309 cp = (u_char *) t_packet;
2311 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2313 if (count > HDW_THRESHOLD)
2316 if (tm_p->m_next == (struct mbuf *)0)
2318 tm_p = tm_p->m_next;
2321 *mb_pp = (u_char *) t_packet;
2328 wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2330 struct mbuf *tm_p = *tm_pp;
2331 u_char *mb_p = *mb_pp;
2333 u_char *cp = (u_char *) t_packet;
2336 /* we need to copy */
2338 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2341 if (tm_p->m_next == (struct mbuf *)0)
2343 tm_p = tm_p->m_next;
2347 *mb_pp = (u_char *) t_packet;
2355 register struct wl_softc *sc = WLSOFTC(unit);
2356 short base = sc->base;
2359 printf("wl%d: DCE_STATUS: 0x%x, ", unit,
2360 wlmmcread(base,MMC_DCE_STATUS) & 0x0f);
2361 tmp = wlmmcread(base,MMC_CORRECT_NWID_H) << 8;
2362 tmp |= wlmmcread(base,MMC_CORRECT_NWID_L);
2363 printf("Correct NWID's: %d, ", tmp);
2364 tmp = wlmmcread(base,MMC_WRONG_NWID_H) << 8;
2365 tmp |= wlmmcread(base,MMC_WRONG_NWID_L);
2366 printf("Wrong NWID's: %d\n", tmp);
2367 printf("THR_PRE_SET: 0x%x, ", wlmmcread(base,MMC_THR_PRE_SET));
2368 printf("SIGNAL_LVL: %d, SILENCE_LVL: %d\n",
2369 wlmmcread(base,MMC_SIGNAL_LVL),
2370 wlmmcread(base,MMC_SILENCE_LVL));
2371 printf("SIGN_QUAL: 0x%x, NETW_ID: %x:%x, DES: %d\n",
2372 wlmmcread(base,MMC_SIGN_QUAL),
2373 wlmmcread(base,MMC_NETW_ID_H),
2374 wlmmcread(base,MMC_NETW_ID_L),
2375 wlmmcread(base,MMC_DES_AVAIL));
2379 wlmmcread(u_int base, u_short reg)
2381 while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2382 outw(MMCR(base),reg << 1);
2383 while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2384 return (u_short)inw(MMCR(base)) >> 8;
2390 register struct wl_softc *sc = WLSOFTC(unit);
2391 short base = sc->base;
2394 MMC_WRITE(MMC_FREEZE,1);
2396 * SNR retrieval procedure :
2398 * read signal level : wlmmcread(base, MMC_SIGNAL_LVL);
2399 * read silence level : wlmmcread(base, MMC_SILENCE_LVL);
2401 MMC_WRITE(MMC_FREEZE,0);
2403 * SNR is signal:silence ratio.
2410 ** Reads the psa for the wavelan at (base) into (buf)
2413 wlgetpsa(int base, u_char *buf)
2417 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2418 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2420 for (i = 0; i < 0x40; i++) {
2421 outw(PIOR2(base), i);
2422 buf[i] = inb(PIOP2(base));
2424 PCMD(base, HACR_DEFAULT);
2425 PCMD(base, HACR_DEFAULT);
2431 ** Writes the psa for wavelan (unit) from the softc back to the
2432 ** board. Updates the CRC and sets the CRC OK flag.
2434 ** Do not call this when the board is operating, as it doesn't
2435 ** preserve the hacr.
2440 register struct wl_softc *sc = WLSOFTC(unit);
2441 short base = sc->base;
2445 crc = wlpsacrc(sc->psa); /* calculate CRC of PSA */
2446 sc->psa[WLPSA_CRCLOW] = crc & 0xff;
2447 sc->psa[WLPSA_CRCHIGH] = (crc >> 8) & 0xff;
2448 sc->psa[WLPSA_CRCOK] = 0x55; /* default to 'bad' until programming complete */
2450 oldpri = splimp(); /* ick, long pause */
2452 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2453 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2455 for (i = 0; i < 0x40; i++) {
2457 outw(PIOR2(base),i); /* write param memory */
2459 outb(PIOP2(base), sc->psa[i]);
2462 outw(PIOR2(base),WLPSA_CRCOK); /* update CRC flag*/
2464 sc->psa[WLPSA_CRCOK] = 0xaa; /* OK now */
2465 outb(PIOP2(base), 0xaa); /* all OK */
2468 PCMD(base, HACR_DEFAULT);
2469 PCMD(base, HACR_DEFAULT);
2475 ** CRC routine provided by Christopher Giordano <cgiordan@gdeb.com>,
2476 ** from original code by Tomi Mikkonen (tomitm@remedy.fi)
2479 static u_int crc16_table[16] = {
2480 0x0000, 0xCC01, 0xD801, 0x1400,
2481 0xF001, 0x3C00, 0x2800, 0xE401,
2482 0xA001, 0x6C00, 0x7800, 0xB401,
2483 0x5000, 0x9C01, 0x8801, 0x4400
2487 wlpsacrc(u_char *buf)
2492 for (i = 0; i < 0x3d; i++, buf++) {
2494 r1 = crc16_table[crc & 0xF];
2495 crc = (crc >> 4) & 0x0FFF;
2496 crc = crc ^ r1 ^ crc16_table[*buf & 0xF];
2499 r1 = crc16_table[crc & 0xF];
2500 crc = (crc >> 4) & 0x0FFF;
2501 crc = crc ^ r1 ^ crc16_table[(*buf >> 4) & 0xF];
2510 * take input packet and cache various radio hw characteristics
2511 * indexed by MAC address.
2513 * Some things to think about:
2514 * note that no space is malloced.
2515 * We might hash the mac address if the cache were bigger.
2516 * It is not clear that the cache is big enough.
2517 * It is also not clear how big it should be.
2518 * The cache is IP-specific. We don't care about that as
2519 * we want it to be IP-specific.
2520 * The last N recv. packets are saved. This will tend
2521 * to reward agents and mobile hosts that beacon.
2522 * That is probably fine for mobile ip.
2525 /* globals for wavelan signal strength cache */
2526 /* this should go into softc structure above.
2529 /* set true if you want to limit cache items to broadcast/mcast
2530 * only packets (not unicast)
2532 static int wl_cache_mcastonly = 1;
2533 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_mcastonly, CTLFLAG_RW,
2534 &wl_cache_mcastonly, 0, "");
2536 /* set true if you want to limit cache items to IP packets only
2538 static int wl_cache_iponly = 1;
2539 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_iponly, CTLFLAG_RW,
2540 &wl_cache_iponly, 0, "");
2542 /* zero out the cache
2545 wl_cache_zero(int unit)
2547 register struct wl_softc *sc = WLSOFTC(unit);
2549 bzero(&sc->w_sigcache[0], sizeof(struct w_sigcache) * MAXCACHEITEMS);
2551 sc->w_nextcache = 0;
2552 sc->w_wrapindex = 0;
2555 /* store hw signal info in cache.
2556 * index is MAC address, but an ip src gets stored too
2557 * There are two filters here controllable via sysctl:
2558 * throw out unicast (on by default, but can be turned off)
2559 * throw out non-ip (on by default, but can be turned off)
2562 void wl_cache_store (int unit, int base, struct ether_header *eh,
2567 int signal, silence;
2568 int w_insertcache; /* computed index for cache entry storage */
2569 register struct wl_softc *sc = WLSOFTC(unit);
2570 int ipflag = wl_cache_iponly;
2574 * 2. configurable filter to throw out unicast packets,
2575 * keep multicast only.
2579 /* reject if not IP packet
2581 if ( wl_cache_iponly && (ntohs(eh->ether_type) != 0x800)) {
2585 /* check if broadcast or multicast packet. we toss
2588 if (wl_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
2592 /* find the ip header. we want to store the ip_src
2593 * address. use the mtod macro(in mbuf.h)
2594 * to typecast m to struct ip *
2597 ip = mtod(m, struct ip *);
2600 /* do a linear search for a matching MAC address
2601 * in the cache table
2602 * . MAC address is 6 bytes,
2603 * . var w_nextcache holds total number of entries already cached
2605 for(i = 0; i < sc->w_nextcache; i++) {
2606 if (! bcmp(eh->ether_shost, sc->w_sigcache[i].macsrc, 6 )) {
2608 * so we already have this entry,
2609 * update the data, and LRU age
2615 /* did we find a matching mac address?
2616 * if yes, then overwrite a previously existing cache entry
2618 if (i < sc->w_nextcache ) {
2621 /* else, have a new address entry,so
2622 * add this new entry,
2623 * if table full, then we need to replace entry
2627 /* check for space in cache table
2628 * note: w_nextcache also holds number of entries
2629 * added in the cache table
2631 if ( sc->w_nextcache < MAXCACHEITEMS ) {
2632 w_insertcache = sc->w_nextcache;
2634 sc->w_sigitems = sc->w_nextcache;
2636 /* no space found, so simply wrap with wrap index
2637 * and "zap" the next entry
2640 if (sc->w_wrapindex == MAXCACHEITEMS) {
2641 sc->w_wrapindex = 0;
2643 w_insertcache = sc->w_wrapindex++;
2647 /* invariant: w_insertcache now points at some slot
2650 if (w_insertcache < 0 || w_insertcache >= MAXCACHEITEMS) {
2652 "wl_cache_store, bad index: %d of [0..%d], gross cache error\n",
2653 w_insertcache, MAXCACHEITEMS);
2657 /* store items in cache
2660 * .signal (0..63) ,silence (0..63) ,quality (0..15)
2663 sc->w_sigcache[w_insertcache].ipsrc = ip->ip_src.s_addr;
2665 bcopy( eh->ether_shost, sc->w_sigcache[w_insertcache].macsrc, 6);
2666 signal = sc->w_sigcache[w_insertcache].signal = wlmmcread(base, MMC_SIGNAL_LVL) & 0x3f;
2667 silence = sc->w_sigcache[w_insertcache].silence = wlmmcread(base, MMC_SILENCE_LVL) & 0x3f;
2668 sc->w_sigcache[w_insertcache].quality = wlmmcread(base, MMC_SIGN_QUAL) & 0x0f;
2670 sc->w_sigcache[w_insertcache].snr =
2673 sc->w_sigcache[w_insertcache].snr = 0;
2677 #endif /* WLCACHE */
2680 * determine if in all multicast mode or not
2682 * returns: 1 if IFF_ALLMULTI should be set
2687 #if defined(__FreeBSD__) && __FreeBSD_version < 300000 /* not required */
2689 check_allmulti(int unit)
2691 register struct wl_softc *sc = WLSOFTC(unit);
2692 short base = sc->base;
2693 struct ether_multi *enm;
2694 struct ether_multistep step;
2696 ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2697 while (enm != NULL) {
2698 unsigned int lo, hi;
2700 printf("enm_addrlo %x:%x:%x:%x:%x:%x\n", enm->enm_addrlo[0], enm->enm_addrlo[1],
2701 enm->enm_addrlo[2], enm->enm_addrlo[3], enm->enm_addrlo[4],
2702 enm->enm_addrlo[5]);
2703 printf("enm_addrhi %x:%x:%x:%x:%x:%x\n", enm->enm_addrhi[0], enm->enm_addrhi[1],
2704 enm->enm_addrhi[2], enm->enm_addrhi[3], enm->enm_addrhi[4],
2705 enm->enm_addrhi[5]);
2707 if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2710 ETHER_NEXT_MULTI(step, enm);