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