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