Merge from vendor branch BSDTAR:
[dragonfly.git] / sys / dev / netif / wl / if_wl.c
... / ...
CommitLineData
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.15 2004/09/15 16:54:21 joerg Exp $ */
3/*
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
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
11 *
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.
22 *
23 */
24/*
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
30 *
31 * 2.2 update:
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.
38 * 2.2.1 update:
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
43 * 7/14/97 jrb
44 *
45 * Work done:
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.
51 *
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).
60 *
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.
82 *
83 * sample config:
84 *
85 * device wl0 at isa? port 0x300 net irq ?
86 *
87 * Ifdefs:
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
96 *
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...
103 *
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.
122 * --RAB 1997/06/08.
123 */
124
125#define MULTICAST 1
126
127/*
128 * Olivetti PC586 Mach Ethernet driver v1.0
129 * Copyright Ing. C. Olivetti & C. S.p.A. 1988, 1989
130 * All rights reserved.
131 *
132 */
133
134/*
135 Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc.,
136Cupertino, California.
137
138 All Rights Reserved
139
140 Permission to use, copy, modify, and distribute this software and
141its documentation for any purpose and without fee is hereby
142granted, provided that the above copyright notice appears in all
143copies and that both the copyright notice and this permission notice
144appear in supporting documentation, and that the name of Olivetti
145not be used in advertising or publicity pertaining to distribution
146of the software without specific, written prior permission.
147
148 OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
149INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
150IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
151CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
152LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
153NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
154WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
155*/
156
157/*
158 Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
159
160 All Rights Reserved
161
162Permission to use, copy, modify, and distribute this software and
163its documentation for any purpose and without fee is hereby
164granted, provided that the above copyright notice appears in all
165copies and that both the copyright notice and this permission notice
166appear in supporting documentation, and that the name of Intel
167not be used in advertising or publicity pertaining to distribution
168of the software without specific, written prior permission.
169
170INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
171INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
172IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
173CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
174LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
175NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
176WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
177*/
178
179/*
180 * NOTE:
181 * by rvb:
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.
190 */
191
192#include "use_wl.h"
193#include "opt_wavelan.h"
194#include "opt_inet.h"
195
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
204#include <sys/kernel.h>
205#include <sys/sysctl.h>
206
207#include <net/ethernet.h>
208#include <net/if.h>
209#include <net/if_dl.h>
210
211#ifdef INET
212#include <netinet/in.h>
213#include <netinet/in_systm.h>
214#include <netinet/ip.h>
215#include <netinet/if_ether.h>
216#endif
217
218#include <net/bpf.h>
219
220#include <machine/clock.h>
221
222#include <bus/isa/i386/isa_device.h>
223#include "if_wl_i82586.h" /* Definitions for the Intel chip */
224
225/* was 1000 in original, fed to DELAY(x) */
226#define DELAYCONST 1000
227#include "if_wl.h"
228#include <machine/if_wl_wavelan.h>
229
230static char t_packet[ETHERMTU + sizeof(struct ether_header) + sizeof(long)];
231
232struct wl_softc{
233 struct arpcom wl_ac; /* Ethernet common part */
234#define wl_if wl_ac.ac_if /* network visible interface */
235#define wl_addr wl_ac.ac_enaddr /* hardware address */
236 u_char psa[0x40];
237 u_char nwid[2]; /* current radio modem nwid */
238 short base;
239 short unit;
240 int flags;
241 int tbusy; /* flag to determine if xmit is busy */
242 u_short begin_fd;
243 u_short end_fd;
244 u_short end_rbd;
245 u_short hacr; /* latest host adapter CR command */
246 short mode;
247 u_char chan24; /* 2.4 Gz: channel number/EEPROM Area # */
248 u_short freq24; /* 2.4 Gz: resulting frequency */
249 struct callout watchdog_ch;
250#ifdef WLCACHE
251 int w_sigitems; /* number of cached entries */
252 /* array of cache entries */
253 struct w_sigcache w_sigcache[ MAXCACHEITEMS ];
254 int w_nextcache; /* next free cache entry */
255 int w_wrapindex; /* next "free" cache entry */
256#endif
257};
258static struct wl_softc wl_softc[NWL];
259
260#define WLSOFTC(unit) ((struct wl_softc *)(&wl_softc[unit]))
261
262static int wlprobe(struct isa_device *);
263static int wlattach(struct isa_device *);
264
265DECLARE_DUMMY_MODULE(if_wl);
266
267struct isa_driver wldriver = {
268 wlprobe, wlattach, "wl", 0
269};
270
271/*
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.
275 */
276static int wl_xmit_delay = 250;
277SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_delay, CTLFLAG_RW, &wl_xmit_delay, 0, "");
278
279/*
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
284 * promiscuous mode.
285 */
286static int wl_ignore_nwid = 0;
287SYSCTL_INT(_machdep, OID_AUTO, wl_ignore_nwid, CTLFLAG_RW, &wl_ignore_nwid, 0, "");
288
289/*
290 * Emit diagnostics about transmission problems
291 */
292static int xmt_watch = 0;
293SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_watch, CTLFLAG_RW, &xmt_watch, 0, "");
294
295/*
296 * Collect SNR statistics
297 */
298static int gathersnr = 0;
299SYSCTL_INT(_machdep, OID_AUTO, wl_gather_snr, CTLFLAG_RW, &gathersnr, 0, "");
300
301static void wlstart(struct ifnet *ifp);
302static void wlinit(void *xsc);
303static int wlioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *);
304static timeout_t wlwatchdog;
305static ointhand2_t wlintr;
306static void wlxmt(int unt, struct mbuf *m);
307static int wldiag(int unt);
308static int wlconfig(int unit);
309static int wlcmd(int unit, char *str);
310static void wlmmcstat(int unit);
311static u_short wlbldru(int unit);
312static u_short wlmmcread(u_int base, u_short reg);
313static void wlinitmmc(int unit);
314static int wlhwrst(int unit);
315static void wlrustrt(int unit);
316static void wlbldcu(int unit);
317static int wlack(int unit);
318static int wlread(int unit, u_short fd_p);
319static void getsnr(int unit);
320static void wlrcv(int unit);
321static int wlrequeue(int unit, u_short fd_p);
322static void wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
323static void wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
324static void wltbd(int unit);
325static void wlgetpsa(int base, u_char *buf);
326static void wlsetpsa(int unit);
327static u_short wlpsacrc(u_char *buf);
328static void wldump(int unit);
329#ifdef WLCACHE
330static void wl_cache_store(int, int, struct ether_header *, struct mbuf *);
331static void wl_cache_zero(int unit);
332#endif
333#ifdef MULTICAST
334# if defined(__FreeBSD__) && __FreeBSD_version < 300000
335static int check_allmulti(int unit);
336# endif
337#endif
338
339/* array for maping irq numbers to values for the irq parameter register */
340static int irqvals[16] = {
341 0, 0, 0, 0x01, 0x02, 0x04, 0, 0x08, 0, 0, 0x10, 0x20, 0x40, 0, 0, 0x80
342};
343/* mask of valid IRQs */
344#define WL_IRQS (IRQ3|IRQ4|IRQ5|IRQ7|IRQ10|IRQ11|IRQ12|IRQ15)
345
346/*
347 * wlprobe:
348 *
349 * This function "probes" or checks for the WaveLAN board on the bus to
350 * see if it is there. As far as I can tell, the best break between this
351 * routine and the attach code is to simply determine whether the board
352 * is configured in properly. Currently my approach to this is to write
353 * and read a word from the SRAM on the board being probed. If the word
354 * comes back properly then we assume the board is there. The config
355 * code expects to see a successful return from the probe routine before
356 * attach will be called.
357 *
358 * input : address device is mapped to, and unit # being checked
359 * output : a '1' is returned if the board exists, and a 0 otherwise
360 *
361 */
362static int
363wlprobe(struct isa_device *id)
364{
365 struct wl_softc *sc = &wl_softc[id->id_unit];
366 short base = id->id_iobase;
367 char *str = "wl%d: board out of range [0..%d]\n";
368 u_char inbuf[100];
369 unsigned long oldpri;
370 int irq;
371
372 /* TBD. not true.
373 * regular CMD() will not work, since no softc yet
374 */
375#define PCMD(base, hacr) outw((base), (hacr))
376
377 oldpri = splimp();
378 PCMD(base, HACR_RESET); /* reset the board */
379 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
380 PCMD(base, HACR_RESET); /* reset the board */
381 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
382 splx(oldpri);
383
384 /* clear reset command and set PIO#1 in autoincrement mode */
385 PCMD(base, HACR_DEFAULT);
386 PCMD(base, HACR_DEFAULT);
387 outw(PIOR1(base), 0); /* go to beginning of RAM */
388 outsw(PIOP1(base), str, strlen(str)/2+1); /* write string */
389
390 outw(PIOR1(base), 0); /* rewind */
391 insw(PIOP1(base), inbuf, strlen(str)/2+1); /* read result */
392
393 if (bcmp(str, inbuf, strlen(str)))
394 return(0);
395
396 sc->chan24 = 0; /* 2.4 Gz: config channel */
397 sc->freq24 = 0; /* 2.4 Gz: frequency */
398
399 /* read the PSA from the board into temporary storage */
400 wlgetpsa(base, inbuf);
401
402 /* We read the IRQ value from the PSA on the board. */
403 for (irq = 15; irq >= 0; irq--)
404 if (irqvals[irq] == inbuf[WLPSA_IRQNO])
405 break;
406 if ((irq == 0) || (irqvals[irq] == 0)){
407 printf("wl%d: PSA corrupt (invalid IRQ value)\n", id->id_unit);
408 id->id_irq = 0; /* no interrupt */
409 } else {
410 /*
411 * If the IRQ requested by the PSA is already claimed by another
412 * device, the board won't work, but the user can still access the
413 * driver to change the IRQ.
414 */
415 id->id_irq = (1<<irq); /* use IRQ from PSA */
416 }
417 return(16);
418}
419
420
421/*
422 * wlattach:
423 *
424 * This function attaches a WaveLAN board to the "system". The rest of
425 * runtime structures are initialized here (this routine is called after
426 * a successful probe of the board). Once the ethernet address is read
427 * and stored, the board's ifnet structure is attached and readied.
428 *
429 * input : isa_dev structure setup in autoconfig
430 * output : board structs and ifnet is setup
431 *
432 */
433static int
434wlattach(struct isa_device *id)
435{
436 struct wl_softc *sc = (struct wl_softc *) &wl_softc[id->id_unit];
437 short base = id->id_iobase;
438 int i,j;
439 u_char unit = id->id_unit;
440 struct ifnet *ifp = &sc->wl_if;
441
442#ifdef WLDEBUG
443 printf("wlattach: base %x, unit %d\n", base, unit);
444#endif
445 id->id_ointr = wlintr;
446 sc->base = base;
447 sc->unit = unit;
448 sc->flags = 0;
449 sc->mode = 0;
450 sc->hacr = HACR_RESET;
451 callout_init(&sc->watchdog_ch);
452 CMD(unit); /* reset the board */
453 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
454
455 /* clear reset command and set PIO#2 in parameter access mode */
456 sc->hacr = (HACR_DEFAULT & ~HACR_16BITS);
457 CMD(unit);
458
459 /* Read the PSA from the board for our later reference */
460 wlgetpsa(base, sc->psa);
461
462 /* fetch NWID */
463 sc->nwid[0] = sc->psa[WLPSA_NWID];
464 sc->nwid[1] = sc->psa[WLPSA_NWID+1];
465
466 /* fetch MAC address - decide which one first */
467 if (sc->psa[WLPSA_MACSEL] & 1) {
468 j = WLPSA_LOCALMAC;
469 } else {
470 j = WLPSA_UNIMAC;
471 }
472 for(i=0; i < WAVELAN_ADDR_SIZE; ++i) {
473 sc->wl_addr[i] = sc->psa[j + i];
474 }
475
476 /* enter normal 16 bit mode operation */
477 sc->hacr = HACR_DEFAULT;
478 CMD(unit);
479
480 wlinitmmc(unit);
481 outw(PIOR1(base), OFFSET_SCB + 8); /* address of scb_crcerrs */
482 outw(PIOP1(base), 0); /* clear scb_crcerrs */
483 outw(PIOP1(base), 0); /* clear scb_alnerrs */
484 outw(PIOP1(base), 0); /* clear scb_rscerrs */
485 outw(PIOP1(base), 0); /* clear scb_ovrnerrs */
486
487 bzero(ifp, sizeof(ifp));
488 ifp->if_softc = sc;
489 if_initname(ifp, "wl", id->id_unit);
490 ifp->if_mtu = WAVELAN_MTU;
491 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
492#ifdef WLDEBUG
493 ifp->if_flags |= IFF_DEBUG;
494#endif
495#if MULTICAST
496 ifp->if_flags |= IFF_MULTICAST;
497#endif /* MULTICAST */
498 ifp->if_init = wlinit;
499 ifp->if_start = wlstart;
500 ifp->if_ioctl = wlioctl;
501 ifp->if_timer = 0; /* paranoia */
502 /* no entries
503 ifp->if_watchdog
504 ifp->if_done
505 ifp->if_reset
506 */
507 ether_ifattach(ifp, sc->wl_ac.ac_enaddr);
508
509 bcopy(&sc->wl_addr[0], sc->wl_ac.ac_enaddr, WAVELAN_ADDR_SIZE);
510 if_printf(ifp, "NWID 0x%02x%02x", sc->nwid[0], sc->nwid[1]);
511 if (sc->freq24)
512 printf(", Freq %d MHz",sc->freq24); /* 2.4 Gz */
513 printf("\n"); /* 2.4 Gz */
514
515
516 if (bootverbose)
517 wldump(unit);
518 return(1);
519}
520
521/*
522 * Print out interesting information about the 82596.
523 */
524static void
525wldump(int unit)
526{
527 struct wl_softc *sp = WLSOFTC(unit);
528 int base = sp->base;
529 int i;
530
531 printf("hasr %04x\n", inw(HASR(base)));
532
533 printf("scb at %04x:\n ", OFFSET_SCB);
534 outw(PIOR1(base), OFFSET_SCB);
535 for(i = 0; i < 8; i++)
536 printf("%04x ", inw(PIOP1(base)));
537 printf("\n");
538
539 printf("cu at %04x:\n ", OFFSET_CU);
540 outw(PIOR1(base), OFFSET_CU);
541 for(i = 0; i < 8; i++)
542 printf("%04x ", inw(PIOP1(base)));
543 printf("\n");
544
545 printf("tbd at %04x:\n ", OFFSET_TBD);
546 outw(PIOR1(base), OFFSET_TBD);
547 for(i = 0; i < 4; i++)
548 printf("%04x ", inw(PIOP1(base)));
549 printf("\n");
550}
551
552/* Initialize the Modem Management Controller */
553static void
554wlinitmmc(int unit)
555{
556 struct wl_softc *sp = WLSOFTC(unit);
557 int base = sp->base;
558 int configured;
559 int mode = sp->mode;
560 int i; /* 2.4 Gz */
561
562 /* enter 8 bit operation */
563 sp->hacr = (HACR_DEFAULT & ~HACR_16BITS);
564 CMD(unit);
565
566 configured = sp->psa[WLPSA_CONFIGURED] & 1;
567
568 /*
569 * Set default modem control parameters. Taken from NCR document
570 * 407-0024326 Rev. A
571 */
572 MMC_WRITE(MMC_JABBER_ENABLE, 0x01);
573 MMC_WRITE(MMC_ANTEN_SEL, 0x02);
574 MMC_WRITE(MMC_IFS, 0x20);
575 MMC_WRITE(MMC_MOD_DELAY, 0x04);
576 MMC_WRITE(MMC_JAM_TIME, 0x38);
577 MMC_WRITE(MMC_DECAY_PRM, 0x00); /* obsolete ? */
578 MMC_WRITE(MMC_DECAY_UPDAT_PRM, 0x00);
579 if (!configured) {
580 MMC_WRITE(MMC_LOOPT_SEL, 0x00);
581 if (sp->psa[WLPSA_COMPATNO] & 1) {
582 MMC_WRITE(MMC_THR_PRE_SET, 0x01); /* 0x04 for AT and 0x01 for MCA */
583 } else {
584 MMC_WRITE(MMC_THR_PRE_SET, 0x04); /* 0x04 for AT and 0x01 for MCA */
585 }
586 MMC_WRITE(MMC_QUALITY_THR, 0x03);
587 } else {
588 /* use configuration defaults from parameter storage area */
589 if (sp->psa[WLPSA_NWIDENABLE] & 1) {
590 if ((mode & (MOD_PROM | MOD_ENAL)) && wl_ignore_nwid) {
591 MMC_WRITE(MMC_LOOPT_SEL, 0x40);
592 } else {
593 MMC_WRITE(MMC_LOOPT_SEL, 0x00);
594 }
595 } else {
596 MMC_WRITE(MMC_LOOPT_SEL, 0x40); /* disable network id check */
597 }
598 MMC_WRITE(MMC_THR_PRE_SET, sp->psa[WLPSA_THRESH]);
599 MMC_WRITE(MMC_QUALITY_THR, sp->psa[WLPSA_QUALTHRESH]);
600 }
601 MMC_WRITE(MMC_FREEZE, 0x00);
602 MMC_WRITE(MMC_ENCR_ENABLE, 0x00);
603
604 MMC_WRITE(MMC_NETW_ID_L,sp->nwid[1]); /* set NWID */
605 MMC_WRITE(MMC_NETW_ID_H,sp->nwid[0]);
606
607 /* enter normal 16 bit mode operation */
608 sp->hacr = HACR_DEFAULT;
609 CMD(unit);
610 CMD(unit); /* virtualpc1 needs this! */
611
612 if (sp->psa[WLPSA_COMPATNO]== /* 2.4 Gz: half-card ver */
613 WLPSA_COMPATNO_WL24B) { /* 2.4 Gz */
614 i=sp->chan24<<4; /* 2.4 Gz: position ch # */
615 MMC_WRITE(MMC_EEADDR,i+0x0f); /* 2.4 Gz: named ch, wc=16 */
616 MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+ /* 2.4 Gz: Download Synths */
617 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: Read EEPROM */
618 for (i=0; i<1000; ++i) { /* 2.4 Gz: wait for download */
619 DELAY(40); /* 2.4 Gz */
620 if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and */
621 &(MMC_EECTRLstat_DWLD /* 2.4 Gz: EEBUSY */
622 +MMC_EECTRLstat_EEBUSY))==0) /* 2.4 Gz: */
623 break; /* 2.4 Gz: download finished */
624 } /* 2.4 Gz */
625 if (i==1000) printf("wl: synth load failed\n"); /* 2.4 Gz */
626 MMC_WRITE(MMC_EEADDR,0x61); /* 2.4 Gz: default pwr, wc=2 */
627 MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+ /* 2.4 Gz: Download Xmit Pwr */
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 */
635 } /* 2.4 Gz */
636 if (i==1000) printf("wl: xmit pwr load failed\n"); /* 2.4 Gz */
637 MMC_WRITE(MMC_ANALCTRL, /* 2.4 Gz: EXT ant+polarity */
638 MMC_ANALCTRL_ANTPOL + /* 2.4 Gz: */
639 MMC_ANALCTRL_EXTANT); /* 2.4 Gz: */
640 i=sp->chan24<<4; /* 2.4 Gz: position ch # */
641 MMC_WRITE(MMC_EEADDR,i); /* 2.4 Gz: get frequency */
642 MMC_WRITE(MMC_EECTRL, /* 2.4 Gz: EEPROM read */
643 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: */
644 DELAY(40); /* 2.4 Gz */
645 i = wlmmcread(base,MMC_EEDATALrv) /* 2.4 Gz: freq val */
646 + (wlmmcread(base,MMC_EEDATAHrv)<<8); /* 2.4 Gz */
647 sp->freq24 = (i>>6)+2400; /* 2.4 Gz: save real freq */
648 }
649}
650
651/*
652 * wlinit:
653 *
654 * Another routine that interfaces the "if" layer to this driver.
655 * Simply resets the structures that are used by "upper layers".
656 * As well as calling wlhwrst that does reset the WaveLAN board.
657 *
658 * input : softc pointer for this interface
659 * output : structures (if structs) and board are reset
660 *
661 */
662static void
663wlinit(void *xsc)
664{
665 struct wl_softc *sc = xsc;
666 struct ifnet *ifp = &sc->wl_if;
667 int stat;
668 u_long oldpri;
669
670#ifdef WLDEBUG
671 if (sc->wl_if.if_flags & IFF_DEBUG)
672 printf("wl%d: entered wlinit()\n",sc->unit);
673#endif
674#if defined(__DragonFly__) || (defined(__FreeBSD__) && __FreeBSD_version >= 300000)
675 if (TAILQ_EMPTY(&ifp->if_addrhead)) {
676#else
677 if (ifp->if_addrlist == (struct ifaddr *)0) {
678#endif
679 return;
680 }
681 oldpri = splimp();
682 if ((stat = wlhwrst(sc->unit)) == TRUE) {
683 sc->wl_if.if_flags |= IFF_RUNNING; /* same as DSF_RUNNING */
684 /*
685 * OACTIVE is used by upper-level routines
686 * and must be set
687 */
688 sc->wl_if.if_flags &= ~IFF_OACTIVE; /* same as tbusy below */
689
690 sc->flags |= DSF_RUNNING;
691 sc->tbusy = 0;
692 callout_stop(&sc->watchdog_ch);
693
694 wlstart(ifp);
695 } else {
696 printf("wl%d init(): trouble resetting board.\n", sc->unit);
697 }
698 splx(oldpri);
699}
700
701/*
702 * wlhwrst:
703 *
704 * This routine resets the WaveLAN board that corresponds to the
705 * board number passed in.
706 *
707 * input : board number to do a hardware reset
708 * output : board is reset
709 *
710 */
711static int
712wlhwrst(int unit)
713{
714 struct wl_softc *sc = WLSOFTC(unit);
715
716#ifdef WLDEBUG
717 if (sc->wl_if.if_flags & IFF_DEBUG)
718 printf("wl%d: entered wlhwrst()\n",unit);
719#endif
720 sc->hacr = HACR_RESET;
721 CMD(unit); /* reset the board */
722
723 /* clear reset command and set PIO#1 in autoincrement mode */
724 sc->hacr = HACR_DEFAULT;
725 CMD(unit);
726
727#ifdef WLDEBUG
728 if (sc->wl_if.if_flags & IFF_DEBUG)
729 wlmmcstat(unit); /* Display MMC registers */
730#endif /* WLDEBUG */
731 wlbldcu(unit); /* set up command unit structures */
732
733 if (wldiag(unit) == 0)
734 return(0);
735
736 if (wlconfig(unit) == 0)
737 return(0);
738 /*
739 * insert code for loopback test here
740 */
741 wlrustrt(unit); /* start receive unit */
742
743 /* enable interrupts */
744 sc->hacr = (HACR_DEFAULT | HACR_INTRON);
745 CMD(unit);
746
747 return(1);
748}
749
750/*
751 * wlbldcu:
752 *
753 * This function builds up the command unit structures. It inits
754 * the scp, iscp, scb, cb, tbd, and tbuf.
755 *
756 */
757static void
758wlbldcu(int unit)
759{
760 struct wl_softc *sc = WLSOFTC(unit);
761 short base = sc->base;
762 scp_t scp;
763 iscp_t iscp;
764 scb_t scb;
765 ac_t cb;
766 tbd_t tbd;
767 int i;
768
769 bzero(&scp, sizeof(scp));
770 scp.scp_sysbus = 0;
771 scp.scp_iscp = OFFSET_ISCP;
772 scp.scp_iscp_base = 0;
773 outw(PIOR1(base), OFFSET_SCP);
774 outsw(PIOP1(base), &scp, sizeof(scp_t)/2);
775
776 bzero(&iscp, sizeof(iscp));
777 iscp.iscp_busy = 1;
778 iscp.iscp_scb_offset = OFFSET_SCB;
779 iscp.iscp_scb = 0;
780 iscp.iscp_scb_base = 0;
781 outw(PIOR1(base), OFFSET_ISCP);
782 outsw(PIOP1(base), &iscp, sizeof(iscp_t)/2);
783
784 scb.scb_status = 0;
785 scb.scb_command = SCB_RESET;
786 scb.scb_cbl_offset = OFFSET_CU;
787 scb.scb_rfa_offset = OFFSET_RU;
788 scb.scb_crcerrs = 0;
789 scb.scb_alnerrs = 0;
790 scb.scb_rscerrs = 0;
791 scb.scb_ovrnerrs = 0;
792 outw(PIOR1(base), OFFSET_SCB);
793 outsw(PIOP1(base), &scb, sizeof(scb_t)/2);
794
795 SET_CHAN_ATTN(unit);
796
797 outw(PIOR0(base), OFFSET_ISCP + 0); /* address of iscp_busy */
798 for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
799 if (i <= 0) printf("wl%d bldcu(): iscp_busy timeout.\n", unit);
800 outw(PIOR0(base), OFFSET_SCB + 0); /* address of scb_status */
801 for (i = STATUS_TRIES; i-- > 0; ) {
802 if (inw(PIOP0(base)) == (SCB_SW_CX|SCB_SW_CNA))
803 break;
804 }
805 if (i <= 0)
806 printf("wl%d bldcu(): not ready after reset.\n", unit);
807 wlack(unit);
808
809 cb.ac_status = 0;
810 cb.ac_command = AC_CW_EL; /* NOP */
811 cb.ac_link_offset = OFFSET_CU;
812 outw(PIOR1(base), OFFSET_CU);
813 outsw(PIOP1(base), &cb, 6/2);
814
815 tbd.act_count = 0;
816 tbd.next_tbd_offset = I82586NULL;
817 tbd.buffer_addr = 0;
818 tbd.buffer_base = 0;
819 outw(PIOR1(base), OFFSET_TBD);
820 outsw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
821}
822
823/*
824 * wlstart:
825 *
826 * send a packet
827 *
828 * input : board number
829 * output : stuff sent to board if any there
830 *
831 */
832static void
833wlstart(struct ifnet *ifp)
834{
835 int unit = ifp->if_dunit;
836 struct mbuf *m;
837 struct wl_softc *sc = WLSOFTC(unit);
838 short base = sc->base;
839 int scb_status, cu_status, scb_command;
840
841#ifdef WLDEBUG
842 if (sc->wl_if.if_flags & IFF_DEBUG)
843 printf("wl%d: entered wlstart()\n",unit);
844#endif
845
846 outw(PIOR1(base), OFFSET_CU);
847 cu_status = inw(PIOP1(base));
848 outw(PIOR0(base),OFFSET_SCB + 0); /* scb_status */
849 scb_status = inw(PIOP0(base));
850 outw(PIOR0(base), OFFSET_SCB + 2);
851 scb_command = inw(PIOP0(base));
852
853 /*
854 * don't need OACTIVE check as tbusy here checks to see
855 * if we are already busy
856 */
857 if (sc->tbusy) {
858 if((scb_status & 0x0700) == SCB_CUS_IDLE &&
859 (cu_status & AC_SW_B) == 0){
860 sc->tbusy = 0;
861 callout_stop(&sc->watchdog_ch);
862 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
863 /*
864 * This is probably just a race. The xmt'r is just
865 * became idle but WE have masked interrupts so ...
866 */
867#ifdef WLDEBUG
868 printf("wl%d: CU idle, scb %04x %04x cu %04x\n",
869 unit, scb_status, scb_command, cu_status);
870#endif
871 if (xmt_watch) printf("!!");
872 } else {
873 return; /* genuinely still busy */
874 }
875 } else if((scb_status & 0x0700) == SCB_CUS_ACTV ||
876 (cu_status & AC_SW_B)){
877#ifdef WLDEBUG
878 printf("wl%d: CU unexpectedly busy; scb %04x cu %04x\n",
879 unit, scb_status, cu_status);
880#endif
881 if (xmt_watch) printf("wl%d: busy?!",unit);
882 return; /* hey, why are we busy? */
883 }
884
885 /* get ourselves some data */
886 ifp = &(sc->wl_if);
887 IF_DEQUEUE(&ifp->if_snd, m);
888 if (m != (struct mbuf *)0) {
889 /* let BPF see it before we commit it */
890 if (ifp->if_bpf) {
891 bpf_mtap(ifp, m);
892 }
893 sc->tbusy++;
894 /* set the watchdog timer so that if the board
895 * fails to interrupt we will restart
896 */
897 /* try 10 ticks, not very long */
898 callout_reset(&sc->watchdog_ch, 10, wlwatchdog, sc);
899 sc->wl_ac.ac_if.if_flags |= IFF_OACTIVE;
900 sc->wl_if.if_opackets++;
901 wlxmt(unit, m);
902 } else {
903 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
904 }
905 return;
906}
907
908/*
909 * wlread:
910 *
911 * This routine does the actual copy of data (including ethernet header
912 * structure) from the WaveLAN to an mbuf chain that will be passed up
913 * to the "if" (network interface) layer. NOTE: we currently
914 * don't handle trailer protocols, so if that is needed, it will
915 * (at least in part) be added here. For simplicities sake, this
916 * routine copies the receive buffers from the board into a local (stack)
917 * buffer until the frame has been copied from the board. Once in
918 * the local buffer, the contents are copied to an mbuf chain that
919 * is then enqueued onto the appropriate "if" queue.
920 *
921 * input : board number, and an frame descriptor address
922 * output : the packet is put into an mbuf chain, and passed up
923 * assumes : if any errors occur, packet is "dropped on the floor"
924 *
925 */
926static int
927wlread(int unit, u_short fd_p)
928{
929 struct wl_softc *sc = WLSOFTC(unit);
930 struct ifnet *ifp = &sc->wl_if;
931 short base = sc->base;
932 fd_t fd;
933 struct ether_header eh;
934 struct mbuf *m, *tm;
935 rbd_t rbd;
936 u_char *mb_p;
937 u_short mlen, len, clen;
938 u_short bytes_in_msg, bytes_in_mbuf, bytes;
939
940
941#ifdef WLDEBUG
942 if (sc->wl_if.if_flags & IFF_DEBUG)
943 printf("wl%d: entered wlread()\n",unit);
944#endif
945 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
946 printf("%s read(): board is not running.\n", ifp->if_xname);
947 sc->hacr &= ~HACR_INTRON;
948 CMD(unit); /* turn off interrupts */
949 }
950 /* read ether_header info out of device memory. doesn't
951 * go into mbuf. goes directly into eh structure
952 */
953 len = sizeof(struct ether_header); /* 14 bytes */
954 outw(PIOR1(base), fd_p);
955 insw(PIOP1(base), &fd, (sizeof(fd_t) - len)/2);
956 insw(PIOP1(base), &eh, (len-2)/2);
957 eh.ether_type = ntohs(inw(PIOP1(base)));
958#ifdef WLDEBUG
959 if (sc->wl_if.if_flags & IFF_DEBUG) {
960 printf("wlread: rcv packet, type is %x\n", eh.ether_type);
961 }
962#endif
963 /*
964 * WARNING. above is done now in ether_input, above may be
965 * useful for debug. jrb
966 */
967 eh.ether_type = htons(eh.ether_type);
968
969 if (fd.rbd_offset == I82586NULL) {
970 printf("wl%d read(): Invalid buffer\n", unit);
971 if (wlhwrst(unit) != TRUE) {
972 printf("wl%d read(): hwrst trouble.\n", unit);
973 }
974 return 0;
975 }
976
977 outw(PIOR1(base), fd.rbd_offset);
978 insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
979 bytes_in_msg = rbd.status & RBD_SW_COUNT;
980 MGETHDR(m, MB_DONTWAIT, MT_DATA);
981 tm = m;
982 if (m == (struct mbuf *)0) {
983 /*
984 * not only do we want to return, we need to drop the packet on
985 * the floor to clear the interrupt.
986 *
987 */
988 if (wlhwrst(unit) != TRUE) {
989 sc->hacr &= ~HACR_INTRON;
990 CMD(unit); /* turn off interrupts */
991 printf("wl%d read(): hwrst trouble.\n", unit);
992 }
993 return 0;
994 }
995 m->m_next = (struct mbuf *) 0;
996 m->m_pkthdr.rcvif = ifp;
997 m->m_pkthdr.len = 0; /* don't know this yet */
998 m->m_len = MHLEN;
999
1000 /* always use a cluster. jrb
1001 */
1002 MCLGET(m, MB_DONTWAIT);
1003 if (m->m_flags & M_EXT) {
1004 m->m_len = MCLBYTES;
1005 }
1006 else {
1007 m_freem(m);
1008 if (wlhwrst(unit) != TRUE) {
1009 sc->hacr &= ~HACR_INTRON;
1010 CMD(unit); /* turn off interrupts */
1011 printf("wl%d read(): hwrst trouble.\n", unit);
1012 }
1013 return 0;
1014 }
1015
1016 mlen = 0;
1017 clen = mlen;
1018 bytes_in_mbuf = m->m_len;
1019 mb_p = mtod(tm, u_char *);
1020 bytes = min(bytes_in_mbuf, bytes_in_msg);
1021 for (;;) {
1022 if (bytes & 1) {
1023 len = bytes + 1;
1024 } else {
1025 len = bytes;
1026 }
1027 outw(PIOR1(base), rbd.buffer_addr);
1028 insw(PIOP1(base), mb_p, len/2);
1029 clen += bytes;
1030 mlen += bytes;
1031
1032 if (!(bytes_in_mbuf -= bytes)) {
1033 MGET(tm->m_next, MB_DONTWAIT, MT_DATA);
1034 tm = tm->m_next;
1035 if (tm == (struct mbuf *)0) {
1036 m_freem(m);
1037 printf("wl%d read(): No mbuf nth\n", unit);
1038 if (wlhwrst(unit) != TRUE) {
1039 sc->hacr &= ~HACR_INTRON;
1040 CMD(unit); /* turn off interrupts */
1041 printf("wl%d read(): hwrst trouble.\n", unit);
1042 }
1043 return 0;
1044 }
1045 mlen = 0;
1046 tm->m_len = MLEN;
1047 bytes_in_mbuf = MLEN;
1048 mb_p = mtod(tm, u_char *);
1049 } else {
1050 mb_p += bytes;
1051 }
1052
1053 if (!(bytes_in_msg -= bytes)) {
1054 if (rbd.status & RBD_SW_EOF ||
1055 rbd.next_rbd_offset == I82586NULL) {
1056 tm->m_len = mlen;
1057 break;
1058 } else {
1059 outw(PIOR1(base), rbd.next_rbd_offset);
1060 insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1061 bytes_in_msg = rbd.status & RBD_SW_COUNT;
1062 }
1063 } else {
1064 rbd.buffer_addr += bytes;
1065 }
1066
1067 bytes = min(bytes_in_mbuf, bytes_in_msg);
1068 }
1069
1070 m->m_pkthdr.len = clen;
1071
1072 /*
1073 * If hw is in promiscuous mode (note that I said hardware, not if
1074 * IFF_PROMISC is set in ifnet flags), then if this is a unicast
1075 * packet and the MAC dst is not us, drop it. This check in normally
1076 * inside ether_input(), but IFF_MULTI causes hw promisc without
1077 * a bpf listener, so this is wrong.
1078 * Greg Troxel <gdt@ir.bbn.com>, 1998-08-07
1079 */
1080 /*
1081 * TBD: also discard packets where NWID does not match.
1082 * However, there does not appear to be a way to read the nwid
1083 * for a received packet. -gdt 1998-08-07
1084 */
1085 if (
1086#ifdef WL_USE_IFNET_PROMISC_CHECK /* not defined */
1087 (sc->wl_ac.ac_if.if_flags & (IFF_PROMISC|IFF_ALLMULTI))
1088#else
1089 /* hw is in promisc mode if this is true */
1090 (sc->mode & (MOD_PROM | MOD_ENAL))
1091#endif
1092 &&
1093 (eh.ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
1094 bcmp(eh.ether_dhost, sc->wl_ac.ac_enaddr,
1095 sizeof(eh.ether_dhost)) != 0 ) {
1096 m_freem(m);
1097 return 1;
1098 }
1099
1100#ifdef WLDEBUG
1101 if (sc->wl_if.if_flags & IFF_DEBUG)
1102 printf("wl%d: wlrecv %d bytes\n", unit, clen);
1103#endif
1104
1105#ifdef WLCACHE
1106 wl_cache_store(unit, base, &eh, m);
1107#endif
1108
1109 /*
1110 * received packet is now in a chain of mbuf's. next step is
1111 * to pass the packet upwards.
1112 *
1113 */
1114 ether_input(&sc->wl_if, &eh, m);
1115 return 1;
1116}
1117
1118/*
1119 * wlioctl:
1120 *
1121 * This routine processes an ioctl request from the "if" layer
1122 * above.
1123 *
1124 * input : pointer the appropriate "if" struct, command, and data
1125 * output : based on command appropriate action is taken on the
1126 * WaveLAN board(s) or related structures
1127 * return : error is returned containing exit conditions
1128 *
1129 */
1130static int
1131wlioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cred)
1132{
1133 struct ifreq *ifr = (struct ifreq *)data;
1134 int unit = ifp->if_dunit;
1135 struct wl_softc *sc = WLSOFTC(unit);
1136 short base = sc->base;
1137 short mode = 0;
1138 int opri, error = 0;
1139 int irq, irqval, i, isroot, size;
1140 caddr_t up;
1141 char * cpt;
1142 struct thread *td = curthread; /* XXX */
1143
1144
1145#ifdef WLDEBUG
1146 if (sc->wl_if.if_flags & IFF_DEBUG)
1147 printf("wl%d: entered wlioctl()\n",unit);
1148#endif
1149 opri = splimp();
1150 switch (cmd) {
1151 case SIOCSIFADDR:
1152 case SIOCGIFADDR:
1153 case SIOCSIFMTU:
1154 error = ether_ioctl(ifp, cmd, data);
1155 break;
1156
1157 case SIOCSIFFLAGS:
1158 if (ifp->if_flags & IFF_ALLMULTI) {
1159 mode |= MOD_ENAL;
1160 }
1161 if (ifp->if_flags & IFF_PROMISC) {
1162 mode |= MOD_PROM;
1163 }
1164 if(ifp->if_flags & IFF_LINK0) {
1165 mode |= MOD_PROM;
1166 }
1167 /*
1168 * force a complete reset if the recieve multicast/
1169 * promiscuous mode changes so that these take
1170 * effect immediately.
1171 *
1172 */
1173 if (sc->mode != mode) {
1174 sc->mode = mode;
1175 if (sc->flags & DSF_RUNNING) {
1176 sc->flags &= ~DSF_RUNNING;
1177 wlinit(sc);
1178 }
1179 }
1180 /* if interface is marked DOWN and still running then
1181 * stop it.
1182 */
1183 if ((ifp->if_flags & IFF_UP) == 0 && sc->flags & DSF_RUNNING) {
1184 printf("wl%d ioctl(): board is not running\n", unit);
1185 sc->flags &= ~DSF_RUNNING;
1186 sc->hacr &= ~HACR_INTRON;
1187 CMD(unit); /* turn off interrupts */
1188 }
1189 /* else if interface is UP and RUNNING, start it
1190 */
1191 else if (ifp->if_flags & IFF_UP && (sc->flags & DSF_RUNNING) == 0) {
1192 wlinit(sc);
1193 }
1194
1195 /* if WLDEBUG set on interface, then printf rf-modem regs
1196 */
1197 if(ifp->if_flags & IFF_DEBUG)
1198 wlmmcstat(unit);
1199 break;
1200#if MULTICAST
1201 case SIOCADDMULTI:
1202 case SIOCDELMULTI:
1203
1204#if defined(__FreeBSD__) && __FreeBSD_version < 300000
1205 if (cmd == SIOCADDMULTI) {
1206 error = ether_addmulti(ifr, &sc->wl_ac);
1207 }
1208 else {
1209 error = ether_delmulti(ifr, &sc->wl_ac);
1210 }
1211
1212 /* see if we should be in all multicast mode
1213 * note that 82586 cannot do that, must simulate with
1214 * promiscuous mode
1215 */
1216 if ( check_allmulti(unit)) {
1217 ifp->if_flags |= IFF_ALLMULTI;
1218 sc->mode |= MOD_ENAL;
1219 sc->flags &= ~DSF_RUNNING;
1220 wlinit(sc);
1221 error = 0;
1222 break;
1223 }
1224
1225 if (error == ENETRESET) {
1226 if(sc->flags & DSF_RUNNING) {
1227 sc->flags &= ~DSF_RUNNING;
1228 wlinit(sc);
1229 }
1230 error = 0;
1231 }
1232#else
1233 wlinit(sc);
1234#endif
1235 break;
1236#endif /* MULTICAST */
1237
1238 /* DEVICE SPECIFIC */
1239
1240
1241 /* copy the PSA out to the caller */
1242 case SIOCGWLPSA:
1243 /* pointer to buffer in user space */
1244 up = (void *)ifr->ifr_data;
1245 /* work out if they're root */
1246 isroot = (suser(td) == 0);
1247
1248 for (i = 0; i < 0x40; i++) {
1249 /* don't hand the DES key out to non-root users */
1250 if ((i > WLPSA_DESKEY) && (i < (WLPSA_DESKEY + 8)) && !isroot)
1251 continue;
1252 if (subyte((up + i), sc->psa[i]))
1253 return(EFAULT);
1254 }
1255 break;
1256
1257
1258 /* copy the PSA in from the caller; we only copy _some_ values */
1259 case SIOCSWLPSA:
1260 /* root only */
1261 if ((error = suser(td)))
1262 break;
1263 error = EINVAL; /* assume the worst */
1264 /* pointer to buffer in user space containing data */
1265 up = (void *)ifr->ifr_data;
1266
1267 /* check validity of input range */
1268 for (i = 0; i < 0x40; i++)
1269 if (fubyte(up + i) < 0)
1270 return(EFAULT);
1271
1272 /* check IRQ value */
1273 irqval = fubyte(up+WLPSA_IRQNO);
1274 for (irq = 15; irq >= 0; irq--)
1275 if(irqvals[irq] == irqval)
1276 break;
1277 if (irq == 0) /* oops */
1278 break;
1279 /* new IRQ */
1280 sc->psa[WLPSA_IRQNO] = irqval;
1281
1282 /* local MAC */
1283 for (i = 0; i < 6; i++)
1284 sc->psa[WLPSA_LOCALMAC+i] = fubyte(up+WLPSA_LOCALMAC+i);
1285
1286 /* MAC select */
1287 sc->psa[WLPSA_MACSEL] = fubyte(up+WLPSA_MACSEL);
1288
1289 /* default nwid */
1290 sc->psa[WLPSA_NWID] = fubyte(up+WLPSA_NWID);
1291 sc->psa[WLPSA_NWID+1] = fubyte(up+WLPSA_NWID+1);
1292
1293 error = 0;
1294 wlsetpsa(unit); /* update the PSA */
1295 break;
1296
1297
1298 /* get the current NWID out of the sc since we stored it there */
1299 case SIOCGWLCNWID:
1300 ifr->ifr_data = (caddr_t) (sc->nwid[0] << 8 | sc->nwid[1]);
1301 break;
1302
1303
1304 /*
1305 * change the nwid dynamically. This
1306 * ONLY changes the radio modem and does not
1307 * change the PSA.
1308 *
1309 * 2 steps:
1310 * 1. save in softc "soft registers"
1311 * 2. save in radio modem (MMC)
1312 */
1313 case SIOCSWLCNWID:
1314 /* root only */
1315 if ((error = suser(td)))
1316 break;
1317 if (!(ifp->if_flags & IFF_UP)) {
1318 error = EIO; /* only allowed while up */
1319 } else {
1320 /*
1321 * soft c nwid shadows radio modem setting
1322 */
1323 sc->nwid[0] = (int)ifr->ifr_data >> 8;
1324 sc->nwid[1] = (int)ifr->ifr_data & 0xff;
1325 MMC_WRITE(MMC_NETW_ID_L,sc->nwid[1]);
1326 MMC_WRITE(MMC_NETW_ID_H,sc->nwid[0]);
1327 }
1328 break;
1329
1330 /* copy the EEPROM in 2.4 Gz WaveMODEM out to the caller */
1331 case SIOCGWLEEPROM:
1332 /* root only */
1333 if ((error = suser(td)))
1334 break;
1335 /* pointer to buffer in user space */
1336 up = (void *)ifr->ifr_data;
1337
1338 for (i=0x00; i<0x80; ++i) { /* 2.4 Gz: size of EEPROM */
1339 MMC_WRITE(MMC_EEADDR,i); /* 2.4 Gz: get frequency */
1340 MMC_WRITE(MMC_EECTRL, /* 2.4 Gz: EEPROM read */
1341 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: */
1342 DELAY(40); /* 2.4 Gz */
1343 if (subyte(up + 2*i , /* 2.4 Gz: pass low byte of */
1344 wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word */
1345 ) return(EFAULT); /* 2.4 Gz: */
1346 if (subyte(up + 2*i+1, /* 2.4 Gz: pass hi byte of */
1347 wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word */
1348 ) return(EFAULT); /* 2.4 Gz: */
1349 }
1350 break;
1351
1352#ifdef WLCACHE
1353 /* zero (Delete) the wl cache */
1354 case SIOCDWLCACHE:
1355 /* root only */
1356 if ((error = suser(td)))
1357 break;
1358 wl_cache_zero(unit);
1359 break;
1360
1361 /* read out the number of used cache elements */
1362 case SIOCGWLCITEM:
1363 ifr->ifr_data = (caddr_t) sc->w_sigitems;
1364 break;
1365
1366 /* read out the wl cache */
1367 case SIOCGWLCACHE:
1368 /* pointer to buffer in user space */
1369 up = (void *)ifr->ifr_data;
1370 cpt = (char *) &sc->w_sigcache[0];
1371 size = sc->w_sigitems * sizeof(struct w_sigcache);
1372
1373 for (i = 0; i < size; i++) {
1374 if (subyte((up + i), *cpt++))
1375 return(EFAULT);
1376 }
1377 break;
1378#endif
1379
1380 default:
1381 error = EINVAL;
1382 }
1383 splx(opri);
1384 return (error);
1385}
1386
1387/*
1388 * wlwatchdog():
1389 *
1390 * Called if the timer set in wlstart expires before an interrupt is received
1391 * from the wavelan. It seems to lose interrupts sometimes.
1392 * The watchdog routine gets called if the transmitter failed to interrupt
1393 *
1394 * input : which board is timing out
1395 * output : board reset
1396 *
1397 */
1398static void
1399wlwatchdog(void *vsc)
1400{
1401 struct wl_softc *sc = vsc;
1402 int unit = sc->unit;
1403
1404 log(LOG_ERR, "wl%d: wavelan device timeout on xmit\n", unit);
1405 sc->wl_ac.ac_if.if_oerrors++;
1406 wlinit(sc);
1407}
1408
1409/*
1410 * wlintr:
1411 *
1412 * This function is the interrupt handler for the WaveLAN
1413 * board. This routine will be called whenever either a packet
1414 * is received, or a packet has successfully been transfered and
1415 * the unit is ready to transmit another packet.
1416 *
1417 * input : board number that interrupted
1418 * output : either a packet is received, or a packet is transfered
1419 *
1420 */
1421static void
1422wlintr(unit)
1423int unit;
1424{
1425 struct wl_softc *sc = &wl_softc[unit];
1426 short base = sc->base;
1427 int ac_status;
1428 u_short int_type, int_type1;
1429
1430#ifdef WLDEBUG
1431 if (sc->wl_if.if_flags & IFF_DEBUG)
1432 printf("wl%d: wlintr() called\n",unit);
1433#endif
1434
1435 if((int_type = inw(HASR(base))) & HASR_MMC_INTR) {
1436 /* handle interrupt from the modem management controler */
1437 /* This will clear the interrupt condition */
1438 (void) wlmmcread(base,MMC_DCE_STATUS); /* ignored for now */
1439 }
1440
1441 if(!(int_type & HASR_INTR)){ /* return if no interrupt from 82586 */
1442 /* commented out. jrb. it happens when reinit occurs
1443 printf("wlintr: int_type %x, dump follows\n", int_type);
1444 wldump(unit);
1445 */
1446 return;
1447 }
1448
1449 if (gathersnr)
1450 getsnr(unit);
1451 for(;;) {
1452 outw(PIOR0(base), OFFSET_SCB + 0); /* get scb status */
1453 int_type = (inw(PIOP0(base)) & SCB_SW_INT);
1454 if (int_type == 0) /* no interrupts left */
1455 break;
1456
1457 int_type1 = wlack(unit); /* acknowledge interrupt(s) */
1458 /* make sure no bits disappeared (others may appear) */
1459 if ((int_type & int_type1) != int_type)
1460 printf("wlack() int bits disappeared : %04x != int_type %04x\n",
1461 int_type1, int_type);
1462 int_type = int_type1; /* go with the new status */
1463 /*
1464 * incoming packet
1465 */
1466 if (int_type & SCB_SW_FR) {
1467 sc->wl_if.if_ipackets++;
1468 wlrcv(unit);
1469 }
1470 /*
1471 * receiver not ready
1472 */
1473 if (int_type & SCB_SW_RNR) {
1474 sc->wl_if.if_ierrors++;
1475#ifdef WLDEBUG
1476 if (sc->wl_if.if_flags & IFF_DEBUG)
1477 printf("wl%d intr(): receiver overrun! begin_fd = %x\n",
1478 unit, sc->begin_fd);
1479#endif
1480 wlrustrt(unit);
1481 }
1482 /*
1483 * CU not ready
1484 */
1485 if (int_type & SCB_SW_CNA) {
1486 /*
1487 * At present, we don't care about CNA's. We
1488 * believe they are a side effect of XMT.
1489 */
1490 }
1491 if (int_type & SCB_SW_CX) {
1492 /*
1493 * At present, we only request Interrupt for
1494 * XMT.
1495 */
1496 outw(PIOR1(base), OFFSET_CU); /* get command status */
1497 ac_status = inw(PIOP1(base));
1498
1499 if (xmt_watch) { /* report some anomalies */
1500
1501 if (sc->tbusy == 0) {
1502 printf("wl%d: xmt intr but not busy, CU %04x\n",
1503 unit, ac_status);
1504 }
1505 if (ac_status == 0) {
1506 printf("wl%d: xmt intr but ac_status == 0\n", unit);
1507 }
1508 if (ac_status & AC_SW_A) {
1509 printf("wl%d: xmt aborted\n",unit);
1510 }
1511#ifdef notdef
1512 if (ac_status & TC_CARRIER) {
1513 printf("wl%d: no carrier\n", unit);
1514 }
1515#endif /* notdef */
1516 if (ac_status & TC_CLS) {
1517 printf("wl%d: no CTS\n", unit);
1518 }
1519 if (ac_status & TC_DMA) {
1520 printf("wl%d: DMA underrun\n", unit);
1521 }
1522 if (ac_status & TC_DEFER) {
1523 printf("wl%d: xmt deferred\n",unit);
1524 }
1525 if (ac_status & TC_SQE) {
1526 printf("wl%d: heart beat\n", unit);
1527 }
1528 if (ac_status & TC_COLLISION) {
1529 printf("wl%d: too many collisions\n", unit);
1530 }
1531 }
1532 /* if the transmit actually failed, or returned some status */
1533 if ((!(ac_status & AC_SW_OK)) || (ac_status & 0xfff)) {
1534 if (ac_status & (TC_COLLISION | TC_CLS | TC_DMA)) {
1535 sc->wl_if.if_oerrors++;
1536 }
1537 /* count collisions */
1538 sc->wl_if.if_collisions += (ac_status & 0xf);
1539 /* if TC_COLLISION set and collision count zero, 16 collisions */
1540 if ((ac_status & 0x20) == 0x20) {
1541 sc->wl_if.if_collisions += 0x10;
1542 }
1543 }
1544 sc->tbusy = 0;
1545 callout_stop(&sc->watchdog_ch);
1546 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
1547 wlstart(&(sc->wl_if));
1548 }
1549 }
1550 return;
1551}
1552
1553/*
1554 * wlrcv:
1555 *
1556 * This routine is called by the interrupt handler to initiate a
1557 * packet transfer from the board to the "if" layer above this
1558 * driver. This routine checks if a buffer has been successfully
1559 * received by the WaveLAN. If so, the routine wlread is called
1560 * to do the actual transfer of the board data (including the
1561 * ethernet header) into a packet (consisting of an mbuf chain).
1562 *
1563 * input : number of the board to check
1564 * output : if a packet is available, it is "sent up"
1565 *
1566 */
1567static void
1568wlrcv(int unit)
1569{
1570 struct wl_softc *sc = WLSOFTC(unit);
1571 short base = sc->base;
1572 u_short fd_p, status, offset, link_offset;
1573
1574#ifdef WLDEBUG
1575 if (sc->wl_if.if_flags & IFF_DEBUG)
1576 printf("wl%d: entered wlrcv()\n",unit);
1577#endif
1578 for (fd_p = sc->begin_fd; fd_p != I82586NULL; fd_p = sc->begin_fd) {
1579
1580 outw(PIOR0(base), fd_p + 0); /* address of status */
1581 status = inw(PIOP0(base));
1582 outw(PIOR1(base), fd_p + 4); /* address of link_offset */
1583 link_offset = inw(PIOP1(base));
1584 offset = inw(PIOP1(base)); /* rbd_offset */
1585 if (status == 0xffff || offset == 0xffff /*I82586NULL*/) {
1586 if (wlhwrst(unit) != TRUE)
1587 printf("wl%d rcv(): hwrst ffff trouble.\n", unit);
1588 return;
1589 } else if (status & AC_SW_C) {
1590 if (status == (RFD_DONE|RFD_RSC)) {
1591 /* lost one */
1592#ifdef WLDEBUG
1593 if (sc->wl_if.if_flags & IFF_DEBUG)
1594 printf("wl%d RCV: RSC %x\n", unit, status);
1595#endif
1596 sc->wl_if.if_ierrors++;
1597 } else if (!(status & RFD_OK)) {
1598 printf("wl%d RCV: !OK %x\n", unit, status);
1599 sc->wl_if.if_ierrors++;
1600 } else if (status & 0xfff) { /* can't happen */
1601 printf("wl%d RCV: ERRs %x\n", unit, status);
1602 sc->wl_if.if_ierrors++;
1603 } else if (!wlread(unit, fd_p))
1604 return;
1605
1606 if (!wlrequeue(unit, fd_p)) {
1607 /* abort on chain error */
1608 if (wlhwrst(unit) != TRUE)
1609 printf("wl%d rcv(): hwrst trouble.\n", unit);
1610 return;
1611 }
1612 sc->begin_fd = link_offset;
1613 } else {
1614 break;
1615 }
1616 }
1617 return;
1618}
1619
1620/*
1621 * wlrequeue:
1622 *
1623 * This routine puts rbd's used in the last receive back onto the
1624 * free list for the next receive.
1625 *
1626 */
1627static int
1628wlrequeue(int unit, u_short fd_p)
1629{
1630 struct wl_softc *sc = WLSOFTC(unit);
1631 short base = sc->base;
1632 fd_t fd;
1633 u_short l_rbdp, f_rbdp, rbd_offset;
1634
1635 outw(PIOR0(base), fd_p + 6);
1636 rbd_offset = inw(PIOP0(base));
1637 if ((f_rbdp = rbd_offset) != I82586NULL) {
1638 l_rbdp = f_rbdp;
1639 for(;;) {
1640 outw(PIOR0(base), l_rbdp + 0); /* address of status */
1641 if(inw(PIOP0(base)) & RBD_SW_EOF)
1642 break;
1643 outw(PIOP0(base), 0);
1644 outw(PIOR0(base), l_rbdp + 2); /* next_rbd_offset */
1645 if((l_rbdp = inw(PIOP0(base))) == I82586NULL)
1646 break;
1647 }
1648 outw(PIOP0(base), 0);
1649 outw(PIOR0(base), l_rbdp + 2); /* next_rbd_offset */
1650 outw(PIOP0(base), I82586NULL);
1651 outw(PIOR0(base), l_rbdp + 8); /* address of size */
1652 outw(PIOP0(base), inw(PIOP0(base)) | AC_CW_EL);
1653 outw(PIOR0(base), sc->end_rbd + 2);
1654 outw(PIOP0(base), f_rbdp); /* end_rbd->next_rbd_offset */
1655 outw(PIOR0(base), sc->end_rbd + 8); /* size */
1656 outw(PIOP0(base), inw(PIOP0(base)) & ~AC_CW_EL);
1657 sc->end_rbd = l_rbdp;
1658 }
1659
1660 fd.status = 0;
1661 fd.command = AC_CW_EL;
1662 fd.link_offset = I82586NULL;
1663 fd.rbd_offset = I82586NULL;
1664 outw(PIOR1(base), fd_p);
1665 outsw(PIOP1(base), &fd, 8/2);
1666
1667 outw(PIOR1(base), sc->end_fd + 2); /* addr of command */
1668 outw(PIOP1(base), 0); /* command = 0 */
1669 outw(PIOP1(base), fd_p); /* end_fd->link_offset = fd_p */
1670 sc->end_fd = fd_p;
1671
1672 return 1;
1673}
1674
1675#ifdef WLDEBUG
1676static int xmt_debug = 0;
1677#endif /* WLDEBUG */
1678
1679/*
1680 * wlxmt:
1681 *
1682 * This routine fills in the appropriate registers and memory
1683 * locations on the WaveLAN board and starts the board off on
1684 * the transmit.
1685 *
1686 * input : board number of interest, and a pointer to the mbuf
1687 * output : board memory and registers are set for xfer and attention
1688 *
1689 */
1690static void
1691wlxmt(int unit, struct mbuf *m)
1692{
1693 struct wl_softc *sc = WLSOFTC(unit);
1694 u_short xmtdata_p = OFFSET_TBUF;
1695 u_short xmtshort_p;
1696 struct mbuf *tm_p = m;
1697 struct ether_header *eh_p = mtod(m, struct ether_header *);
1698 u_char *mb_p = mtod(m, u_char *) + sizeof(struct ether_header);
1699 u_short count = m->m_len - sizeof(struct ether_header);
1700 ac_t cb;
1701 u_short tbd_p = OFFSET_TBD;
1702 u_short len, clen = 0;
1703 short base = sc->base;
1704 int spin;
1705
1706#ifdef WLDEBUG
1707 if (sc->wl_if.if_flags & IFF_DEBUG)
1708 printf("wl%d: entered wlxmt()\n",unit);
1709#endif
1710
1711 cb.ac_status = 0;
1712 cb.ac_command = (AC_CW_EL|AC_TRANSMIT|AC_CW_I);
1713 cb.ac_link_offset = I82586NULL;
1714 outw(PIOR1(base), OFFSET_CU);
1715 outsw(PIOP1(base), &cb, 6/2);
1716 outw(PIOP1(base), OFFSET_TBD); /* cb.cmd.transmit.tbd_offset */
1717 outsw(PIOP1(base), eh_p->ether_dhost, WAVELAN_ADDR_SIZE/2);
1718 outw(PIOP1(base), eh_p->ether_type);
1719
1720#ifdef WLDEBUG
1721 if (sc->wl_if.if_flags & IFF_DEBUG) {
1722 if (xmt_debug) {
1723 printf("XMT mbuf: L%d @%p ", count, (void *)mb_p);
1724 printf("ether type %x\n", eh_p->ether_type);
1725 }
1726 }
1727#endif /* WLDEBUG */
1728 outw(PIOR0(base), OFFSET_TBD);
1729 outw(PIOP0(base), 0); /* act_count */
1730 outw(PIOR1(base), OFFSET_TBD + 4);
1731 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1732 outw(PIOP1(base), 0); /* buffer_base */
1733 for (;;) {
1734 if (count) {
1735 if (clen + count > WAVELAN_MTU)
1736 break;
1737 if (count & 1)
1738 len = count + 1;
1739 else
1740 len = count;
1741 outw(PIOR1(base), xmtdata_p);
1742 outsw(PIOP1(base), mb_p, len/2);
1743 clen += count;
1744 outw(PIOR0(base), tbd_p); /* address of act_count */
1745 outw(PIOP0(base), inw(PIOP0(base)) + count);
1746 xmtdata_p += len;
1747 if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1748 break;
1749 if (count & 1) {
1750 /* go to the next descriptor */
1751 outw(PIOR0(base), tbd_p + 2);
1752 tbd_p += sizeof (tbd_t);
1753 outw(PIOP0(base), tbd_p); /* next_tbd_offset */
1754 outw(PIOR0(base), tbd_p);
1755 outw(PIOP0(base), 0); /* act_count */
1756 outw(PIOR1(base), tbd_p + 4);
1757 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1758 outw(PIOP1(base), 0); /* buffer_base */
1759 /* at the end -> coallesce remaining mbufs */
1760 if (tbd_p == OFFSET_TBD + (N_TBD-1) * sizeof (tbd_t)) {
1761 wlsftwsleaze(&count, &mb_p, &tm_p, unit);
1762 continue;
1763 }
1764 /* next mbuf short -> coallesce as needed */
1765 if ( (tm_p->m_next == (struct mbuf *) 0) ||
1766#define HDW_THRESHOLD 55
1767 tm_p->m_len > HDW_THRESHOLD)
1768 /* ok */;
1769 else {
1770 wlhdwsleaze(&count, &mb_p, &tm_p, unit);
1771 continue;
1772 }
1773 }
1774 } else if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1775 break;
1776 count = tm_p->m_len;
1777 mb_p = mtod(tm_p, u_char *);
1778#ifdef WLDEBUG
1779 if (sc->wl_if.if_flags & IFF_DEBUG)
1780 if (xmt_debug)
1781 printf("mbuf+ L%d @%p ", count, (void *)mb_p);
1782#endif /* WLDEBUG */
1783 }
1784#ifdef WLDEBUG
1785 if (sc->wl_if.if_flags & IFF_DEBUG)
1786 if (xmt_debug)
1787 printf("CLEN = %d\n", clen);
1788#endif /* WLDEBUG */
1789 outw(PIOR0(base), tbd_p);
1790 if (clen < ETHERMIN) {
1791 outw(PIOP0(base), inw(PIOP0(base)) + ETHERMIN - clen);
1792 outw(PIOR1(base), xmtdata_p);
1793 for (xmtshort_p = xmtdata_p; clen < ETHERMIN; clen += 2)
1794 outw(PIOP1(base), 0);
1795 }
1796 outw(PIOP0(base), inw(PIOP0(base)) | TBD_SW_EOF);
1797 outw(PIOR0(base), tbd_p + 2);
1798 outw(PIOP0(base), I82586NULL);
1799#ifdef WLDEBUG
1800 if (sc->wl_if.if_flags & IFF_DEBUG) {
1801 if (xmt_debug) {
1802 wltbd(unit);
1803 printf("\n");
1804 }
1805 }
1806#endif /* WLDEBUG */
1807
1808 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
1809 /*
1810 * wait for 586 to clear previous command, complain if it takes
1811 * too long
1812 */
1813 for (spin = 1;;spin = (spin + 1) % 10000) {
1814 if (inw(PIOP0(base)) == 0) { /* it's done, we can go */
1815 break;
1816 }
1817 if ((spin == 0) && xmt_watch) { /* not waking up, and we care */
1818 printf("wl%d: slow accepting xmit\n",unit);
1819 }
1820 }
1821 outw(PIOP0(base), SCB_CU_STRT); /* new command */
1822 SET_CHAN_ATTN(unit);
1823
1824 m_freem(m);
1825
1826 /* XXX
1827 * Pause to avoid transmit overrun problems.
1828 * The required delay tends to vary with platform type, and may be
1829 * related to interrupt loss.
1830 */
1831 if (wl_xmit_delay) {
1832 DELAY(wl_xmit_delay);
1833 }
1834 return;
1835}
1836
1837/*
1838 * wlbldru:
1839 *
1840 * This function builds the linear linked lists of fd's and
1841 * rbd's. Based on page 4-32 of 1986 Intel microcom handbook.
1842 *
1843 */
1844static u_short
1845wlbldru(int unit)
1846{
1847 struct wl_softc *sc = WLSOFTC(unit);
1848 short base = sc->base;
1849 fd_t fd;
1850 rbd_t rbd;
1851 u_short fd_p = OFFSET_RU;
1852 u_short rbd_p = OFFSET_RBD;
1853 int i;
1854
1855 sc->begin_fd = fd_p;
1856 for(i = 0; i < N_FD; i++) {
1857 fd.status = 0;
1858 fd.command = 0;
1859 fd.link_offset = fd_p + sizeof(fd_t);
1860 fd.rbd_offset = I82586NULL;
1861 outw(PIOR1(base), fd_p);
1862 outsw(PIOP1(base), &fd, 8/2);
1863 fd_p = fd.link_offset;
1864 }
1865 fd_p -= sizeof(fd_t);
1866 sc->end_fd = fd_p;
1867 outw(PIOR1(base), fd_p + 2);
1868 outw(PIOP1(base), AC_CW_EL); /* command */
1869 outw(PIOP1(base), I82586NULL); /* link_offset */
1870 fd_p = OFFSET_RU;
1871
1872 outw(PIOR0(base), fd_p + 6); /* address of rbd_offset */
1873 outw(PIOP0(base), rbd_p);
1874 outw(PIOR1(base), rbd_p);
1875 for(i = 0; i < N_RBD; i++) {
1876 rbd.status = 0;
1877 rbd.buffer_addr = rbd_p + sizeof(rbd_t) + 2;
1878 rbd.buffer_base = 0;
1879 rbd.size = RCVBUFSIZE;
1880 if (i != N_RBD-1) {
1881 rbd_p += sizeof(ru_t);
1882 rbd.next_rbd_offset = rbd_p;
1883 } else {
1884 rbd.next_rbd_offset = I82586NULL;
1885 rbd.size |= AC_CW_EL;
1886 sc->end_rbd = rbd_p;
1887 }
1888 outsw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1889 outw(PIOR1(base), rbd_p);
1890 }
1891 return sc->begin_fd;
1892}
1893
1894/*
1895 * wlrustrt:
1896 *
1897 * This routine starts the receive unit running. First checks if the
1898 * board is actually ready, then the board is instructed to receive
1899 * packets again.
1900 *
1901 */
1902static void
1903wlrustrt(int unit)
1904{
1905 struct wl_softc *sc = WLSOFTC(unit);
1906 short base = sc->base;
1907 u_short rfa;
1908
1909#ifdef WLDEBUG
1910 if (sc->wl_if.if_flags & IFF_DEBUG)
1911 printf("wl%d: entered wlrustrt()\n",unit);
1912#endif
1913 outw(PIOR0(base), OFFSET_SCB);
1914 if (inw(PIOP0(base)) & SCB_RUS_READY){
1915 printf("wlrustrt: RUS_READY\n");
1916 return;
1917 }
1918
1919 outw(PIOR0(base), OFFSET_SCB + 2);
1920 outw(PIOP0(base), SCB_RU_STRT); /* command */
1921 rfa = wlbldru(unit);
1922 outw(PIOR0(base), OFFSET_SCB + 6); /* address of scb_rfa_offset */
1923 outw(PIOP0(base), rfa);
1924
1925 SET_CHAN_ATTN(unit);
1926 return;
1927}
1928
1929/*
1930 * wldiag:
1931 *
1932 * This routine does a 586 op-code number 7, and obtains the
1933 * diagnose status for the WaveLAN.
1934 *
1935 */
1936static int
1937wldiag(int unit)
1938{
1939 struct wl_softc *sc = WLSOFTC(unit);
1940 short base = sc->base;
1941 short status;
1942
1943#ifdef WLDEBUG
1944 if (sc->wl_if.if_flags & IFF_DEBUG)
1945 printf("wl%d: entered wldiag()\n",unit);
1946#endif
1947 outw(PIOR0(base), OFFSET_SCB);
1948 status = inw(PIOP0(base));
1949 if (status & SCB_SW_INT) {
1950 /* state is 2000 which seems ok
1951 printf("wl%d diag(): unexpected initial state %\n",
1952 unit, inw(PIOP0(base)));
1953 */
1954 wlack(unit);
1955 }
1956 outw(PIOR1(base), OFFSET_CU);
1957 outw(PIOP1(base), 0); /* ac_status */
1958 outw(PIOP1(base), AC_DIAGNOSE|AC_CW_EL);/* ac_command */
1959 if(wlcmd(unit, "diag()") == 0)
1960 return 0;
1961 outw(PIOR0(base), OFFSET_CU);
1962 if (inw(PIOP0(base)) & 0x0800) {
1963 printf("wl%d: i82586 Self Test failed!\n", unit);
1964 return 0;
1965 }
1966 return TRUE;
1967}
1968
1969/*
1970 * wlconfig:
1971 *
1972 * This routine does a standard config of the WaveLAN board.
1973 *
1974 */
1975static int
1976wlconfig(int unit)
1977{
1978 configure_t configure;
1979 struct wl_softc *sc = WLSOFTC(unit);
1980 short base = sc->base;
1981
1982#if MULTICAST
1983#if defined(__DragonFly__) || (defined(__FreeBSD__) && __FreeBSD_version >= 300000)
1984 struct ifmultiaddr *ifma;
1985 u_char *addrp;
1986#else
1987 struct ether_multi *enm;
1988 struct ether_multistep step;
1989#endif
1990 int cnt = 0;
1991#endif /* MULTICAST */
1992
1993#ifdef WLDEBUG
1994 if (sc->wl_if.if_flags & IFF_DEBUG)
1995 printf("wl%d: entered wlconfig()\n",unit);
1996#endif
1997 outw(PIOR0(base), OFFSET_SCB);
1998 if (inw(PIOP0(base)) & SCB_SW_INT) {
1999 /*
2000 printf("wl%d config(): unexpected initial state %x\n",
2001 unit, inw(PIOP0(base)));
2002 */
2003 }
2004 wlack(unit);
2005
2006 outw(PIOR1(base), OFFSET_CU);
2007 outw(PIOP1(base), 0); /* ac_status */
2008 outw(PIOP1(base), AC_CONFIGURE|AC_CW_EL); /* ac_command */
2009
2010/* jrb hack */
2011 configure.fifolim_bytecnt = 0x080c;
2012 configure.addrlen_mode = 0x0600;
2013 configure.linprio_interframe = 0x2060;
2014 configure.slot_time = 0xf200;
2015 configure.hardware = 0x0008; /* tx even w/o CD */
2016 configure.min_frame_len = 0x0040;
2017#if 0
2018 /* This is the configuration block suggested by Marc Meertens
2019 * <mmeerten@obelix.utrecht.NCR.COM> in an e-mail message to John
2020 * Ioannidis on 10 Nov 92.
2021 */
2022 configure.fifolim_bytecnt = 0x040c;
2023 configure.addrlen_mode = 0x0600;
2024 configure.linprio_interframe = 0x2060;
2025 configure.slot_time = 0xf000;
2026 configure.hardware = 0x0008; /* tx even w/o CD */
2027 configure.min_frame_len = 0x0040;
2028#else
2029 /*
2030 * below is the default board configuration from p2-28 from 586 book
2031 */
2032 configure.fifolim_bytecnt = 0x080c;
2033 configure.addrlen_mode = 0x2600;
2034 configure.linprio_interframe = 0x7820; /* IFS=120, ACS=2 */
2035 configure.slot_time = 0xf00c; /* slottime=12 */
2036 configure.hardware = 0x0008; /* tx even w/o CD */
2037 configure.min_frame_len = 0x0040;
2038#endif
2039 if(sc->mode & (MOD_PROM | MOD_ENAL)) {
2040 configure.hardware |= 1;
2041 }
2042 outw(PIOR1(base), OFFSET_CU + 6);
2043 outsw(PIOP1(base), &configure, sizeof(configure_t)/2);
2044
2045 if(wlcmd(unit, "config()-configure") == 0)
2046 return 0;
2047#if MULTICAST
2048 outw(PIOR1(base), OFFSET_CU);
2049 outw(PIOP1(base), 0); /* ac_status */
2050 outw(PIOP1(base), AC_MCSETUP|AC_CW_EL); /* ac_command */
2051 outw(PIOR1(base), OFFSET_CU + 8);
2052#if defined(__DragonFly__) || (defined(__FreeBSD__) && __FreeBSD_version >= 300000)
2053 for (ifma = sc->wl_if.if_multiaddrs.lh_first; ifma;
2054 ifma = ifma->ifma_link.le_next) {
2055 if (ifma->ifma_addr->sa_family != AF_LINK)
2056 continue;
2057
2058 addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
2059 outw(PIOP1(base), addrp[0] + (addrp[1] << 8));
2060 outw(PIOP1(base), addrp[2] + (addrp[3] << 8));
2061 outw(PIOP1(base), addrp[4] + (addrp[5] << 8));
2062 ++cnt;
2063 }
2064#else
2065 ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2066 while (enm != NULL) {
2067 unsigned int lo, hi;
2068 /* break if setting a multicast range, else we would crash */
2069 if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2070 break;
2071 }
2072 lo = (enm->enm_addrlo[3] << 16) + (enm->enm_addrlo[4] << 8)
2073 + enm->enm_addrlo[5];
2074 hi = (enm->enm_addrhi[3] << 16) + (enm->enm_addrhi[4] << 8)
2075 + enm->enm_addrhi[5];
2076 while(lo <= hi) {
2077 outw(PIOP1(base),enm->enm_addrlo[0] +
2078 (enm->enm_addrlo[1] << 8));
2079 outw(PIOP1(base),enm->enm_addrlo[2] +
2080 ((lo >> 8) & 0xff00));
2081 outw(PIOP1(base), ((lo >> 8) & 0xff) +
2082 ((lo << 8) & 0xff00));
2083/* #define MCASTDEBUG */
2084#ifdef MCASTDEBUG
2085printf("mcast_addr[%d,%d,%d] %x %x %x %x %x %x\n", lo, hi, cnt,
2086 enm->enm_addrlo[0],
2087 enm->enm_addrlo[1],
2088 enm->enm_addrlo[2],
2089 enm->enm_addrlo[3],
2090 enm->enm_addrlo[4],
2091 enm->enm_addrlo[5]);
2092#endif
2093 ++cnt;
2094 ++lo;
2095 }
2096 ETHER_NEXT_MULTI(step, enm);
2097 }
2098#endif
2099 outw(PIOR1(base), OFFSET_CU + 6); /* mc-cnt */
2100 outw(PIOP1(base), cnt * WAVELAN_ADDR_SIZE);
2101 if(wlcmd(unit, "config()-mcaddress") == 0)
2102 return 0;
2103#endif /* MULTICAST */
2104
2105 outw(PIOR1(base), OFFSET_CU);
2106 outw(PIOP1(base), 0); /* ac_status */
2107 outw(PIOP1(base), AC_IASETUP|AC_CW_EL); /* ac_command */
2108 outw(PIOR1(base), OFFSET_CU + 6);
2109 outsw(PIOP1(base), sc->wl_addr, WAVELAN_ADDR_SIZE/2);
2110
2111 if(wlcmd(unit, "config()-address") == 0)
2112 return(0);
2113
2114 wlinitmmc(unit);
2115
2116 return(1);
2117}
2118
2119/*
2120 * wlcmd:
2121 *
2122 * Set channel attention bit and busy wait until command has
2123 * completed. Then acknowledge the command completion.
2124 */
2125static int
2126wlcmd(int unit, char *str)
2127{
2128 struct wl_softc *sc = WLSOFTC(unit);
2129 short base = sc->base;
2130 int i;
2131
2132 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
2133 outw(PIOP0(base), SCB_CU_STRT);
2134
2135 SET_CHAN_ATTN(unit);
2136
2137 outw(PIOR0(base), OFFSET_CU);
2138 for(i = 0; i < 0xffff; i++)
2139 if (inw(PIOP0(base)) & AC_SW_C)
2140 break;
2141 if (i == 0xffff || !(inw(PIOP0(base)) & AC_SW_OK)) {
2142 printf("wl%d: %s failed; status = %d, inw = %x, outw = %x\n",
2143 unit, str, inw(PIOP0(base)) & AC_SW_OK, inw(PIOP0(base)), inw(PIOR0(base)));
2144 outw(PIOR0(base), OFFSET_SCB);
2145 printf("scb_status %x\n", inw(PIOP0(base)));
2146 outw(PIOR0(base), OFFSET_SCB+2);
2147 printf("scb_command %x\n", inw(PIOP0(base)));
2148 outw(PIOR0(base), OFFSET_SCB+4);
2149 printf("scb_cbl %x\n", inw(PIOP0(base)));
2150 outw(PIOR0(base), OFFSET_CU+2);
2151 printf("cu_cmd %x\n", inw(PIOP0(base)));
2152 return(0);
2153 }
2154
2155 outw(PIOR0(base), OFFSET_SCB);
2156 if ((inw(PIOP0(base)) & SCB_SW_INT) && (inw(PIOP0(base)) != SCB_SW_CNA)) {
2157 /*
2158 printf("wl%d %s: unexpected final state %x\n",
2159 unit, str, inw(PIOP0(base)));
2160 */
2161 }
2162 wlack(unit);
2163 return(TRUE);
2164}
2165
2166/*
2167 * wlack: if the 82596 wants attention because it has finished
2168 * sending or receiving a packet, acknowledge its desire and
2169 * return bits indicating the kind of attention. wlack() returns
2170 * these bits so that the caller can service exactly the
2171 * conditions that wlack() acknowledged.
2172 */
2173static int
2174wlack(int unit)
2175{
2176 int i;
2177 u_short cmd;
2178 struct wl_softc *sc = WLSOFTC(unit);
2179 short base = sc->base;
2180
2181 outw(PIOR1(base), OFFSET_SCB);
2182 if(!(cmd = (inw(PIOP1(base)) & SCB_SW_INT)))
2183 return(0);
2184#ifdef WLDEBUG
2185 if (sc->wl_if.if_flags & IFF_DEBUG)
2186 printf("wl%d: doing a wlack()\n",unit);
2187#endif
2188 outw(PIOP1(base), cmd);
2189 SET_CHAN_ATTN(unit);
2190 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
2191 for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
2192 if (i < 1)
2193 printf("wl%d wlack(): board not accepting command.\n", unit);
2194 return(cmd);
2195}
2196
2197static void
2198wltbd(int unit)
2199{
2200 struct wl_softc *sc = WLSOFTC(unit);
2201 short base = sc->base;
2202 u_short tbd_p = OFFSET_TBD;
2203 tbd_t tbd;
2204 int i = 0;
2205 int sum = 0;
2206
2207 for (;;) {
2208 outw(PIOR1(base), tbd_p);
2209 insw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
2210 sum += (tbd.act_count & ~TBD_SW_EOF);
2211 printf("%d: addr %x, count %d (%d), next %x, base %x\n",
2212 i++, tbd.buffer_addr,
2213 (tbd.act_count & ~TBD_SW_EOF), sum,
2214 tbd.next_tbd_offset, tbd.buffer_base);
2215 if (tbd.act_count & TBD_SW_EOF)
2216 break;
2217 tbd_p = tbd.next_tbd_offset;
2218 }
2219}
2220
2221static void
2222wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2223{
2224 struct mbuf *tm_p = *tm_pp;
2225 u_char *mb_p = *mb_pp;
2226 u_short count = 0;
2227 u_char *cp;
2228 int len;
2229
2230 /*
2231 * can we get a run that will be coallesced or
2232 * that terminates before breaking
2233 */
2234 do {
2235 count += tm_p->m_len;
2236 if (tm_p->m_len & 1)
2237 break;
2238 } while ((tm_p = tm_p->m_next) != (struct mbuf *)0);
2239 if ( (tm_p == (struct mbuf *)0) ||
2240 count > HDW_THRESHOLD) {
2241 *countp = (*tm_pp)->m_len;
2242 *mb_pp = mtod((*tm_pp), u_char *);
2243 return;
2244 }
2245
2246 /* we need to copy */
2247 tm_p = *tm_pp;
2248 mb_p = *mb_pp;
2249 count = 0;
2250 cp = (u_char *) t_packet;
2251 for (;;) {
2252 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2253 count += len;
2254 if (count > HDW_THRESHOLD)
2255 break;
2256 cp += len;
2257 if (tm_p->m_next == (struct mbuf *)0)
2258 break;
2259 tm_p = tm_p->m_next;
2260 }
2261 *countp = count;
2262 *mb_pp = (u_char *) t_packet;
2263 *tm_pp = tm_p;
2264 return;
2265}
2266
2267
2268static void
2269wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2270{
2271 struct mbuf *tm_p = *tm_pp;
2272 u_short count = 0;
2273 u_char *cp = (u_char *) t_packet;
2274 int len;
2275
2276 /* we need to copy */
2277 for (;;) {
2278 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2279 count += len;
2280 cp += len;
2281 if (tm_p->m_next == (struct mbuf *)0)
2282 break;
2283 tm_p = tm_p->m_next;
2284 }
2285
2286 *countp = count;
2287 *mb_pp = (u_char *) t_packet;
2288 *tm_pp = tm_p;
2289 return;
2290}
2291
2292static void
2293wlmmcstat(int unit)
2294{
2295 struct wl_softc *sc = WLSOFTC(unit);
2296 short base = sc->base;
2297 u_short tmp;
2298
2299 printf("wl%d: DCE_STATUS: 0x%x, ", unit,
2300 wlmmcread(base,MMC_DCE_STATUS) & 0x0f);
2301 tmp = wlmmcread(base,MMC_CORRECT_NWID_H) << 8;
2302 tmp |= wlmmcread(base,MMC_CORRECT_NWID_L);
2303 printf("Correct NWID's: %d, ", tmp);
2304 tmp = wlmmcread(base,MMC_WRONG_NWID_H) << 8;
2305 tmp |= wlmmcread(base,MMC_WRONG_NWID_L);
2306 printf("Wrong NWID's: %d\n", tmp);
2307 printf("THR_PRE_SET: 0x%x, ", wlmmcread(base,MMC_THR_PRE_SET));
2308 printf("SIGNAL_LVL: %d, SILENCE_LVL: %d\n",
2309 wlmmcread(base,MMC_SIGNAL_LVL),
2310 wlmmcread(base,MMC_SILENCE_LVL));
2311 printf("SIGN_QUAL: 0x%x, NETW_ID: %x:%x, DES: %d\n",
2312 wlmmcread(base,MMC_SIGN_QUAL),
2313 wlmmcread(base,MMC_NETW_ID_H),
2314 wlmmcread(base,MMC_NETW_ID_L),
2315 wlmmcread(base,MMC_DES_AVAIL));
2316}
2317
2318static u_short
2319wlmmcread(u_int base, u_short reg)
2320{
2321 while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2322 outw(MMCR(base),reg << 1);
2323 while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2324 return (u_short)inw(MMCR(base)) >> 8;
2325}
2326
2327static void
2328getsnr(int unit)
2329{
2330 MMC_WRITE(MMC_FREEZE,1);
2331 /*
2332 * SNR retrieval procedure :
2333 *
2334 * read signal level : wlmmcread(base, MMC_SIGNAL_LVL);
2335 * read silence level : wlmmcread(base, MMC_SILENCE_LVL);
2336 */
2337 MMC_WRITE(MMC_FREEZE,0);
2338 /*
2339 * SNR is signal:silence ratio.
2340 */
2341}
2342
2343/*
2344** wlgetpsa
2345**
2346** Reads the psa for the wavelan at (base) into (buf)
2347*/
2348static void
2349wlgetpsa(int base, u_char *buf)
2350{
2351 int i;
2352
2353 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2354 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2355
2356 for (i = 0; i < 0x40; i++) {
2357 outw(PIOR2(base), i);
2358 buf[i] = inb(PIOP2(base));
2359 }
2360 PCMD(base, HACR_DEFAULT);
2361 PCMD(base, HACR_DEFAULT);
2362}
2363
2364/*
2365** wlsetpsa
2366**
2367** Writes the psa for wavelan (unit) from the softc back to the
2368** board. Updates the CRC and sets the CRC OK flag.
2369**
2370** Do not call this when the board is operating, as it doesn't
2371** preserve the hacr.
2372*/
2373static void
2374wlsetpsa(int unit)
2375{
2376 struct wl_softc *sc = WLSOFTC(unit);
2377 short base = sc->base;
2378 int i, oldpri;
2379 u_short crc;
2380
2381 crc = wlpsacrc(sc->psa); /* calculate CRC of PSA */
2382 sc->psa[WLPSA_CRCLOW] = crc & 0xff;
2383 sc->psa[WLPSA_CRCHIGH] = (crc >> 8) & 0xff;
2384 sc->psa[WLPSA_CRCOK] = 0x55; /* default to 'bad' until programming complete */
2385
2386 oldpri = splimp(); /* ick, long pause */
2387
2388 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2389 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2390
2391 for (i = 0; i < 0x40; i++) {
2392 DELAY(DELAYCONST);
2393 outw(PIOR2(base),i); /* write param memory */
2394 DELAY(DELAYCONST);
2395 outb(PIOP2(base), sc->psa[i]);
2396 }
2397 DELAY(DELAYCONST);
2398 outw(PIOR2(base),WLPSA_CRCOK); /* update CRC flag*/
2399 DELAY(DELAYCONST);
2400 sc->psa[WLPSA_CRCOK] = 0xaa; /* OK now */
2401 outb(PIOP2(base), 0xaa); /* all OK */
2402 DELAY(DELAYCONST);
2403
2404 PCMD(base, HACR_DEFAULT);
2405 PCMD(base, HACR_DEFAULT);
2406
2407 splx(oldpri);
2408}
2409
2410/*
2411** CRC routine provided by Christopher Giordano <cgiordan@gdeb.com>,
2412** from original code by Tomi Mikkonen (tomitm@remedy.fi)
2413*/
2414
2415static u_int crc16_table[16] = {
2416 0x0000, 0xCC01, 0xD801, 0x1400,
2417 0xF001, 0x3C00, 0x2800, 0xE401,
2418 0xA001, 0x6C00, 0x7800, 0xB401,
2419 0x5000, 0x9C01, 0x8801, 0x4400
2420};
2421
2422static u_short
2423wlpsacrc(u_char *buf)
2424{
2425 u_short crc = 0;
2426 int i, r1;
2427
2428 for (i = 0; i < 0x3d; i++, buf++) {
2429 /* lower 4 bits */
2430 r1 = crc16_table[crc & 0xF];
2431 crc = (crc >> 4) & 0x0FFF;
2432 crc = crc ^ r1 ^ crc16_table[*buf & 0xF];
2433
2434 /* upper 4 bits */
2435 r1 = crc16_table[crc & 0xF];
2436 crc = (crc >> 4) & 0x0FFF;
2437 crc = crc ^ r1 ^ crc16_table[(*buf >> 4) & 0xF];
2438 }
2439 return(crc);
2440}
2441#ifdef WLCACHE
2442
2443/*
2444 * wl_cache_store
2445 *
2446 * take input packet and cache various radio hw characteristics
2447 * indexed by MAC address.
2448 *
2449 * Some things to think about:
2450 * note that no space is malloced.
2451 * We might hash the mac address if the cache were bigger.
2452 * It is not clear that the cache is big enough.
2453 * It is also not clear how big it should be.
2454 * The cache is IP-specific. We don't care about that as
2455 * we want it to be IP-specific.
2456 * The last N recv. packets are saved. This will tend
2457 * to reward agents and mobile hosts that beacon.
2458 * That is probably fine for mobile ip.
2459 */
2460
2461/* globals for wavelan signal strength cache */
2462/* this should go into softc structure above.
2463*/
2464
2465/* set true if you want to limit cache items to broadcast/mcast
2466 * only packets (not unicast)
2467 */
2468static int wl_cache_mcastonly = 1;
2469SYSCTL_INT(_machdep, OID_AUTO, wl_cache_mcastonly, CTLFLAG_RW,
2470 &wl_cache_mcastonly, 0, "");
2471
2472/* set true if you want to limit cache items to IP packets only
2473*/
2474static int wl_cache_iponly = 1;
2475SYSCTL_INT(_machdep, OID_AUTO, wl_cache_iponly, CTLFLAG_RW,
2476 &wl_cache_iponly, 0, "");
2477
2478/* zero out the cache
2479*/
2480static void
2481wl_cache_zero(int unit)
2482{
2483 struct wl_softc *sc = WLSOFTC(unit);
2484
2485 bzero(&sc->w_sigcache[0], sizeof(struct w_sigcache) * MAXCACHEITEMS);
2486 sc->w_sigitems = 0;
2487 sc->w_nextcache = 0;
2488 sc->w_wrapindex = 0;
2489}
2490
2491/* store hw signal info in cache.
2492 * index is MAC address, but an ip src gets stored too
2493 * There are two filters here controllable via sysctl:
2494 * throw out unicast (on by default, but can be turned off)
2495 * throw out non-ip (on by default, but can be turned off)
2496 */
2497static
2498void wl_cache_store (int unit, int base, struct ether_header *eh,
2499 struct mbuf *m)
2500{
2501 struct ip *ip = NULL; /* Avoid GCC warning */
2502 int i;
2503 int signal, silence;
2504 int w_insertcache; /* computed index for cache entry storage */
2505 struct wl_softc *sc = WLSOFTC(unit);
2506 int ipflag = wl_cache_iponly;
2507
2508 /* filters:
2509 * 1. ip only
2510 * 2. configurable filter to throw out unicast packets,
2511 * keep multicast only.
2512 */
2513
2514#ifdef INET
2515 /* reject if not IP packet
2516 */
2517 if ( wl_cache_iponly && (ntohs(eh->ether_type) != 0x800)) {
2518 return;
2519 }
2520
2521 /* check if broadcast or multicast packet. we toss
2522 * unicast packets
2523 */
2524 if (wl_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
2525 return;
2526 }
2527
2528 /* find the ip header. we want to store the ip_src
2529 * address. use the mtod macro(in mbuf.h)
2530 * to typecast m to struct ip *
2531 */
2532 if (ipflag) {
2533 ip = mtod(m, struct ip *);
2534 }
2535
2536 /* do a linear search for a matching MAC address
2537 * in the cache table
2538 * . MAC address is 6 bytes,
2539 * . var w_nextcache holds total number of entries already cached
2540 */
2541 for(i = 0; i < sc->w_nextcache; i++) {
2542 if (! bcmp(eh->ether_shost, sc->w_sigcache[i].macsrc, 6 )) {
2543 /* Match!,
2544 * so we already have this entry,
2545 * update the data, and LRU age
2546 */
2547 break;
2548 }
2549 }
2550
2551 /* did we find a matching mac address?
2552 * if yes, then overwrite a previously existing cache entry
2553 */
2554 if (i < sc->w_nextcache ) {
2555 w_insertcache = i;
2556 }
2557 /* else, have a new address entry,so
2558 * add this new entry,
2559 * if table full, then we need to replace entry
2560 */
2561 else {
2562
2563 /* check for space in cache table
2564 * note: w_nextcache also holds number of entries
2565 * added in the cache table
2566 */
2567 if ( sc->w_nextcache < MAXCACHEITEMS ) {
2568 w_insertcache = sc->w_nextcache;
2569 sc->w_nextcache++;
2570 sc->w_sigitems = sc->w_nextcache;
2571 }
2572 /* no space found, so simply wrap with wrap index
2573 * and "zap" the next entry
2574 */
2575 else {
2576 if (sc->w_wrapindex == MAXCACHEITEMS) {
2577 sc->w_wrapindex = 0;
2578 }
2579 w_insertcache = sc->w_wrapindex++;
2580 }
2581 }
2582
2583 /* invariant: w_insertcache now points at some slot
2584 * in cache.
2585 */
2586 if (w_insertcache < 0 || w_insertcache >= MAXCACHEITEMS) {
2587 log(LOG_ERR,
2588 "wl_cache_store, bad index: %d of [0..%d], gross cache error\n",
2589 w_insertcache, MAXCACHEITEMS);
2590 return;
2591 }
2592
2593 /* store items in cache
2594 * .ipsrc
2595 * .macsrc
2596 * .signal (0..63) ,silence (0..63) ,quality (0..15)
2597 */
2598 if (ipflag) {
2599 sc->w_sigcache[w_insertcache].ipsrc = ip->ip_src.s_addr;
2600 }
2601 bcopy( eh->ether_shost, sc->w_sigcache[w_insertcache].macsrc, 6);
2602 signal = sc->w_sigcache[w_insertcache].signal = wlmmcread(base, MMC_SIGNAL_LVL) & 0x3f;
2603 silence = sc->w_sigcache[w_insertcache].silence = wlmmcread(base, MMC_SILENCE_LVL) & 0x3f;
2604 sc->w_sigcache[w_insertcache].quality = wlmmcread(base, MMC_SIGN_QUAL) & 0x0f;
2605 if (signal > 0)
2606 sc->w_sigcache[w_insertcache].snr =
2607 signal - silence;
2608 else
2609 sc->w_sigcache[w_insertcache].snr = 0;
2610#endif /* INET */
2611
2612}
2613#endif /* WLCACHE */
2614
2615/*
2616 * determine if in all multicast mode or not
2617 *
2618 * returns: 1 if IFF_ALLMULTI should be set
2619 * else 0
2620 */
2621#ifdef MULTICAST
2622
2623#if defined(__FreeBSD__) && __FreeBSD_version < 300000 /* not required */
2624static int
2625check_allmulti(int unit)
2626{
2627 struct wl_softc *sc = WLSOFTC(unit);
2628 short base = sc->base;
2629 struct ether_multi *enm;
2630 struct ether_multistep step;
2631
2632 ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2633 while (enm != NULL) {
2634 unsigned int lo, hi;
2635#ifdef MDEBUG
2636 printf("enm_addrlo %x:%x:%x:%x:%x:%x\n", enm->enm_addrlo[0], enm->enm_addrlo[1],
2637 enm->enm_addrlo[2], enm->enm_addrlo[3], enm->enm_addrlo[4],
2638 enm->enm_addrlo[5]);
2639 printf("enm_addrhi %x:%x:%x:%x:%x:%x\n", enm->enm_addrhi[0], enm->enm_addrhi[1],
2640 enm->enm_addrhi[2], enm->enm_addrhi[3], enm->enm_addrhi[4],
2641 enm->enm_addrhi[5]);
2642#endif
2643 if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2644 return(1);
2645 }
2646 ETHER_NEXT_MULTI(step, enm);
2647 }
2648 return(0);
2649}
2650#endif
2651#endif