Deleted Added
full compact
if_wl.c (106937) if_wl.c (108470)
1/* $FreeBSD: head/sys/dev/wl/if_wl.c 106937 2002-11-14 23:54:55Z sam $ */
1/* $FreeBSD: head/sys/dev/wl/if_wl.c 108470 2002-12-30 21:18:15Z schweikh $ */
2/*
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions
5 * are met:
6 * 1. Redistributions of source code must retain all copyright
7 * notices, this list of conditions and the following disclaimer.
8 * 2. The names of the authors may not be used to endorse or promote products
9 * derived from this software without specific prior written permission
10 *
11 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
12 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
13 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
14 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
15 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
16 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
17 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
18 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
19 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
20 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21 *
22 */
23/*
24 * if_wl.c - original MACH, then BSDI ISA wavelan driver
25 * ported to mach by Anders Klemets
26 * to BSDI by Robert Morris
27 * to FreeBSD by Jim Binkley
28 * to FreeBSD 2.2+ by Michael Smith
29 *
30 * 2.2 update:
31 * Changed interface to match 2.1-2.2 differences.
32 * Implement IRQ selection logic in wlprobe()
33 * Implement PSA updating.
34 * Pruned heading comments for relevance.
35 * Ripped out all the 'interface counters' cruft.
36 * Cut the missing-interrupt timer back to 100ms.
37 * 2.2.1 update:
38 * now supports all multicast mode (mrouted will work),
39 * but unfortunately must do that by going into promiscuous mode
40 * NWID sysctl added so that normally promiscuous mode is NWID-specific
41 * but can be made NWID-inspecific
42 * 7/14/97 jrb
43 *
44 * Work done:
45 * Ported to FreeBSD, got promiscuous mode working with bpfs,
46 * and rewired timer routine. The i82586 will hang occasionally on output
47 * and the watchdog timer will kick it if so and log an entry.
48 * 2 second timeout there. Apparently the chip loses an interrupt.
49 * Code borrowed from if_ie.c for watchdog timer.
50 *
51 * The wavelan card is a 2mbit radio modem that emulates ethernet;
52 * i.e., it uses MAC addresses. This should not be a surprise since
53 * it uses an ethernet controller as a major hw item.
54 * It can broadcast, unicast or apparently multicast in a base cell
55 * using a omni-directional antennae that is
56 * about 800 feet around the base cell barring walls and metal.
57 * With directional antennae, it can be used point to point over a mile
58 * or so apparently (haven't tried that).
59 *
60 * There are ISA and pcmcia versions (not supported by this code).
61 * The ISA card has an Intel 82586 lan controller on it. It consists
62 * of 2 pieces of hw, the lan controller (intel) and a radio-modem.
63 * The latter has an extra set of controller registers that has nothing
64 * to do with the i82586 and allows setting and monitoring of radio
65 * signal strength, etc. There is a nvram area called the PSA that
66 * contains a number of setup variables including the IRQ and so-called
67 * NWID or Network ID. The NWID must be set the same for all radio
68 * cards to communicate (unless you are using the ATT/NCR roaming feature
69 * with their access points. There is no support for that here. Roaming
70 * involves a link-layer beacon sent out from the access points. End
71 * stations monitor the signal strength and only use the strongest
72 * access point). This driver assumes that the base ISA port, IRQ,
73 * and NWID are first set in nvram via the dos-side "instconf.exe" utility
74 * supplied with the card. This driver takes the ISA port from
75 * the kernel configuration setup, and then determines the IRQ either
76 * from the kernel config (if an explicit IRQ is set) or from the
77 * PSA on the card if not.
78 * The hw also magically just uses the IRQ set in the nvram.
79 * The NWID is used magically as well by the radio-modem
80 * to determine which packets to keep or throw out.
81 *
82 * sample config:
83 *
84 * device wl0 at isa? port 0x300 net irq ?
85 *
86 * Ifdefs:
87 * 1. WLDEBUG. (off) - if turned on enables IFF_DEBUG set via ifconfig debug
88 * 2. MULTICAST (on) - turned on and works up to and including mrouted
89 * 3. WLCACHE (off) - define to turn on a signal strength
90 * (and other metric) cache that is indexed by sender MAC address.
91 * Apps can read this out to learn the remote signal strength of a
92 * sender. Note that it has a switch so that it only stores
93 * broadcast/multicast senders but it could be set to store unicast
94 * too only. Size is hardwired in if_wl_wavelan.h
95 *
96 * one further note: promiscuous mode is a curious thing. In this driver,
97 * promiscuous mode apparently CAN catch ALL packets and ignore the NWID
98 * setting. This is probably more useful in a sense (for snoopers) if
99 * you are interested in all traffic as opposed to if you are interested
100 * in just your own. There is a driver specific sysctl to turn promiscuous
101 * from just promiscuous to wildly promiscuous...
102 *
103 * This driver also knows how to load the synthesizers in the 2.4 Gz
104 * ISA Half-card, Product number 847647476 (USA/FCC IEEE Channel set).
105 * This product consists of a "mothercard" that contains the 82586,
106 * NVRAM that holds the PSA, and the ISA-buss interface custom ASIC.
107 * The radio transceiver is a "daughtercard" called the WaveMODEM which
108 * connects to the mothercard through two single-inline connectors: a
109 * 20-pin connector provides DC-power and modem signals, and a 3-pin
110 * connector which exports the antenna connection. The code herein
111 * loads the receive and transmit synthesizers and the corresponding
112 * transmitter output power value from an EEPROM controlled through
113 * additional registers via the MMC. The EEPROM address selected
114 * are those whose values are preset by the DOS utility programs
115 * provided with the product, and this provides compatible operation
116 * with the DOS Packet Driver software. A future modification will
117 * add the necessary functionality to this driver and to the wlconfig
118 * utility to completely replace the DOS Configuration Utilities.
119 * The 2.4 Gz WaveMODEM is described in document number 407-024692/E,
120 * and is available through Lucent Technologies OEM supply channels.
121 * --RAB 1997/06/08.
122 */
123
124#define MULTICAST 1
125
126/*
127 * Olivetti PC586 Mach Ethernet driver v1.0
128 * Copyright Ing. C. Olivetti & C. S.p.A. 1988, 1989
129 * All rights reserved.
130 *
131 */
132
133/*
134 Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc.,
135Cupertino, California.
136
137 All Rights Reserved
138
139 Permission to use, copy, modify, and distribute this software and
140its documentation for any purpose and without fee is hereby
141granted, provided that the above copyright notice appears in all
142copies and that both the copyright notice and this permission notice
143appear in supporting documentation, and that the name of Olivetti
144not be used in advertising or publicity pertaining to distribution
145of the software without specific, written prior permission.
146
147 OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
148INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
149IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
150CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
151LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
152NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
153WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
154*/
155
156/*
157 Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
158
159 All Rights Reserved
160
161Permission to use, copy, modify, and distribute this software and
162its documentation for any purpose and without fee is hereby
163granted, provided that the above copyright notice appears in all
164copies and that both the copyright notice and this permission notice
165appear in supporting documentation, and that the name of Intel
166not be used in advertising or publicity pertaining to distribution
167of the software without specific, written prior permission.
168
169INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
170INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
171IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
172CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
173LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
174NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
175WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
176*/
177
178/*
179 * NOTE:
180 * by rvb:
181 * 1. The best book on the 82586 is:
182 * LAN Components User's Manual by Intel
183 * The copy I found was dated 1984. This really tells you
184 * what the state machines are doing
185 * 2. In the current design, we only do one write at a time,
186 * though the hardware is capable of chaining and possibly
187 * even batching. The problem is that we only make one
188 * transmit buffer available in sram space.
189 */
190
191#define NWL 4
192#include "opt_wavelan.h"
193#include "opt_inet.h"
194
195#include <sys/param.h>
196#include <sys/systm.h>
197#include <sys/kernel.h>
198#include <sys/sockio.h>
199#include <sys/mbuf.h>
200#include <sys/socket.h>
201#include <sys/syslog.h>
202#include <sys/bus.h>
203
204#include <sys/sysctl.h>
205
206#include <net/ethernet.h>
207#include <net/if.h>
208#include <net/if_dl.h>
209
210#ifdef INET
211#include <netinet/in.h>
212#include <netinet/in_systm.h>
213#include <netinet/ip.h>
214#include <netinet/if_ether.h>
215#endif
216
217#include <net/bpf.h>
218#include <i386/isa/isa_device.h>
219#include <i386/isa/ic/if_wl_i82586.h> /* Definitions for the Intel chip */
220
221/* was 1000 in original, fed to DELAY(x) */
222#define DELAYCONST 1000
223#include <dev/wl/if_wl.h>
224#include <machine/if_wl_wavelan.h>
225
226#ifndef COMPAT_OLDISA
227#error "The wl device requires the old isa compatibility shims"
228#endif
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
265struct isa_driver wldriver = {
266 INTR_TYPE_NET,
267 wlprobe,
268 wlattach,
269 "wl",
270 0
271};
272COMPAT_ISA_DRIVER(wl, wldriver);
273
274/*
275 * XXX The Wavelan appears to be prone to dropping stuff if you talk to
276 * it too fast. This disgusting hack inserts a delay after each packet
277 * is queued which helps avoid this behaviour on fast systems.
278 */
279static int wl_xmit_delay = 250;
280SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_delay, CTLFLAG_RW, &wl_xmit_delay, 0, "");
281
282/*
283 * not XXX, but ZZZ (bizarre).
284 * promiscuous mode can be toggled to ignore NWIDs. By default,
285 * it does not. Caution should be exercised about combining
286 * this mode with IFF_ALLMULTI which puts this driver in
287 * promiscuous mode.
288 */
289static int wl_ignore_nwid = 0;
290SYSCTL_INT(_machdep, OID_AUTO, wl_ignore_nwid, CTLFLAG_RW, &wl_ignore_nwid, 0, "");
291
292/*
293 * Emit diagnostics about transmission problems
294 */
295static int xmt_watch = 0;
296SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_watch, CTLFLAG_RW, &xmt_watch, 0, "");
297
298/*
299 * Collect SNR statistics
300 */
301static int gathersnr = 0;
302SYSCTL_INT(_machdep, OID_AUTO, wl_gather_snr, CTLFLAG_RW, &gathersnr, 0, "");
303
304static void wlstart(struct ifnet *ifp);
305static void wlinit(void *xsc);
306static int wlioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
307static timeout_t wlwatchdog;
308static ointhand2_t wlintr;
309static void wlxmt(int unt, struct mbuf *m);
310static int wldiag(int unt);
311static int wlconfig(int unit);
312static int wlcmd(int unit, char *str);
313static void wlmmcstat(int unit);
314static u_short wlbldru(int unit);
315static u_short wlmmcread(u_int base, u_short reg);
316static void wlinitmmc(int unit);
317static int wlhwrst(int unit);
318static void wlrustrt(int unit);
319static void wlbldcu(int unit);
320static int wlack(int unit);
321static int wlread(int unit, u_short fd_p);
322static void getsnr(int unit);
323static void wlrcv(int unit);
324static int wlrequeue(int unit, u_short fd_p);
325static void wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
326static void wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
327#ifdef WLDEBUG
328static void wltbd(int unit);
329#endif
330static void wlgetpsa(int base, u_char *buf);
331static void wlsetpsa(int unit);
332static u_short wlpsacrc(u_char *buf);
333static void wldump(int unit);
334#ifdef WLCACHE
335static void wl_cache_store(int, int, struct ether_header *, struct mbuf *);
336static void wl_cache_zero(int unit);
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 register 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 register short base = id->id_iobase;
438 int i,j;
439 u_char unit = id->id_unit;
440 register 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 for (i=0; i < WAVELAN_ADDR_SIZE; ++i)
472 sc->wl_addr[i] = sc->psa[j + i];
473
474 /* enter normal 16 bit mode operation */
475 sc->hacr = HACR_DEFAULT;
476 CMD(unit);
477
478 wlinitmmc(unit);
479 outw(PIOR1(base), OFFSET_SCB + 8); /* address of scb_crcerrs */
480 outw(PIOP1(base), 0); /* clear scb_crcerrs */
481 outw(PIOP1(base), 0); /* clear scb_alnerrs */
482 outw(PIOP1(base), 0); /* clear scb_rscerrs */
483 outw(PIOP1(base), 0); /* clear scb_ovrnerrs */
484
485 bzero(ifp, sizeof(ifp));
486 ifp->if_softc = sc;
487 ifp->if_unit = id->id_unit;
488 ifp->if_mtu = WAVELAN_MTU;
489 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
490#ifdef WLDEBUG
491 ifp->if_flags |= IFF_DEBUG;
492#endif
493#if MULTICAST
494 ifp->if_flags |= IFF_MULTICAST;
495#endif /* MULTICAST */
496 ifp->if_name = "wl";
497 ifp->if_unit = unit;
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_addr[0]);
509
510 bcopy(&sc->wl_addr[0], sc->wl_ac.ac_enaddr, WAVELAN_ADDR_SIZE);
511 printf("%s%d: address %6D, NWID 0x%02x%02x", ifp->if_name, ifp->if_unit,
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 register 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 register 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 register 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 (TAILQ_FIRST(&ifp->if_addrhead) == (struct ifaddr *)0)
677 return;
678 oldpri = splimp();
679 if ((stat = wlhwrst(sc->unit)) == TRUE) {
680 sc->wl_if.if_flags |= IFF_RUNNING; /* same as DSF_RUNNING */
681 /*
682 * OACTIVE is used by upper-level routines
683 * and must be set
684 */
685 sc->wl_if.if_flags &= ~IFF_OACTIVE; /* same as tbusy below */
686
687 sc->flags |= DSF_RUNNING;
688 sc->tbusy = 0;
689 untimeout(wlwatchdog, sc, sc->watchdog_ch);
690
691 wlstart(ifp);
692 } else {
693 printf("wl%d init(): trouble resetting board.\n", sc->unit);
694 }
695 splx(oldpri);
696}
697
698/*
699 * wlhwrst:
700 *
701 * This routine resets the WaveLAN board that corresponds to the
702 * board number passed in.
703 *
704 * input : board number to do a hardware reset
705 * output : board is reset
706 *
707 */
708static int
709wlhwrst(int unit)
710{
711 register struct wl_softc *sc = WLSOFTC(unit);
712
713#ifdef WLDEBUG
714 if (sc->wl_if.if_flags & IFF_DEBUG)
715 printf("wl%d: entered wlhwrst()\n",unit);
716#endif
717 sc->hacr = HACR_RESET;
718 CMD(unit); /* reset the board */
719
720 /* clear reset command and set PIO#1 in autoincrement mode */
721 sc->hacr = HACR_DEFAULT;
722 CMD(unit);
723
724#ifdef WLDEBUG
725 if (sc->wl_if.if_flags & IFF_DEBUG)
726 wlmmcstat(unit); /* Display MMC registers */
727#endif /* WLDEBUG */
728 wlbldcu(unit); /* set up command unit structures */
729
730 if (wldiag(unit) == 0)
731 return(0);
732
733 if (wlconfig(unit) == 0)
734 return(0);
735 /*
736 * insert code for loopback test here
737 */
738 wlrustrt(unit); /* start receive unit */
739
740 /* enable interrupts */
741 sc->hacr = (HACR_DEFAULT | HACR_INTRON);
742 CMD(unit);
743
744 return(1);
745}
746
747/*
748 * wlbldcu:
749 *
750 * This function builds up the command unit structures. It inits
751 * the scp, iscp, scb, cb, tbd, and tbuf.
752 *
753 */
754static void
755wlbldcu(int unit)
756{
757 register struct wl_softc *sc = WLSOFTC(unit);
758 short base = sc->base;
759 scp_t scp;
760 iscp_t iscp;
761 scb_t scb;
762 ac_t cb;
763 tbd_t tbd;
764 int i;
765
766 bzero(&scp, sizeof(scp));
767 scp.scp_sysbus = 0;
768 scp.scp_iscp = OFFSET_ISCP;
769 scp.scp_iscp_base = 0;
770 outw(PIOR1(base), OFFSET_SCP);
771 outsw(PIOP1(base), &scp, sizeof(scp_t)/2);
772
773 bzero(&iscp, sizeof(iscp));
774 iscp.iscp_busy = 1;
775 iscp.iscp_scb_offset = OFFSET_SCB;
776 iscp.iscp_scb = 0;
777 iscp.iscp_scb_base = 0;
778 outw(PIOR1(base), OFFSET_ISCP);
779 outsw(PIOP1(base), &iscp, sizeof(iscp_t)/2);
780
781 scb.scb_status = 0;
782 scb.scb_command = SCB_RESET;
783 scb.scb_cbl_offset = OFFSET_CU;
784 scb.scb_rfa_offset = OFFSET_RU;
785 scb.scb_crcerrs = 0;
786 scb.scb_alnerrs = 0;
787 scb.scb_rscerrs = 0;
788 scb.scb_ovrnerrs = 0;
789 outw(PIOR1(base), OFFSET_SCB);
790 outsw(PIOP1(base), &scb, sizeof(scb_t)/2);
791
792 SET_CHAN_ATTN(unit);
793
794 outw(PIOR0(base), OFFSET_ISCP + 0); /* address of iscp_busy */
795 for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); )
796 continue;
797 if (i <= 0)
798 printf("wl%d bldcu(): iscp_busy timeout.\n", unit);
799 outw(PIOR0(base), OFFSET_SCB + 0); /* address of scb_status */
800 for (i = STATUS_TRIES; i-- > 0; ) {
801 if (inw(PIOP0(base)) == (SCB_SW_CX|SCB_SW_CNA))
802 break;
803 }
804 if (i <= 0)
805 printf("wl%d bldcu(): not ready after reset.\n", unit);
806 wlack(unit);
807
808 cb.ac_status = 0;
809 cb.ac_command = AC_CW_EL; /* NOP */
810 cb.ac_link_offset = OFFSET_CU;
811 outw(PIOR1(base), OFFSET_CU);
812 outsw(PIOP1(base), &cb, 6/2);
813
814 tbd.act_count = 0;
815 tbd.next_tbd_offset = I82586NULL;
816 tbd.buffer_addr = 0;
817 tbd.buffer_base = 0;
818 outw(PIOR1(base), OFFSET_TBD);
819 outsw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
820}
821
822/*
823 * wlstart:
824 *
825 * send a packet
826 *
827 * input : board number
828 * output : stuff sent to board if any there
829 *
830 */
831static void
832wlstart(struct ifnet *ifp)
833{
834 int unit = ifp->if_unit;
835 struct mbuf *m;
836 register struct wl_softc *sc = WLSOFTC(unit);
837 short base = sc->base;
838 int scb_status, cu_status, scb_command;
839
840#ifdef WLDEBUG
841 if (sc->wl_if.if_flags & IFF_DEBUG)
842 printf("wl%d: entered wlstart()\n",unit);
843#endif
844
845 outw(PIOR1(base), OFFSET_CU);
846 cu_status = inw(PIOP1(base));
847 outw(PIOR0(base),OFFSET_SCB + 0); /* scb_status */
848 scb_status = inw(PIOP0(base));
849 outw(PIOR0(base), OFFSET_SCB + 2);
850 scb_command = inw(PIOP0(base));
851
852 /*
853 * don't need OACTIVE check as tbusy here checks to see
854 * if we are already busy
855 */
856 if (sc->tbusy) {
857 if ((scb_status & 0x0700) == SCB_CUS_IDLE &&
858 (cu_status & AC_SW_B) == 0){
859 sc->tbusy = 0;
860 untimeout(wlwatchdog, sc, sc->watchdog_ch);
861 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
862 /*
863 * This is probably just a race. The xmt'r is just
864 * became idle but WE have masked interrupts so ...
865 */
866#ifdef WLDEBUG
867 printf("wl%d: CU idle, scb %04x %04x cu %04x\n",
868 unit, scb_status, scb_command, cu_status);
869#endif
870 if (xmt_watch) printf("!!");
871 } else {
872 return; /* genuinely still busy */
873 }
874 } else if ((scb_status & 0x0700) == SCB_CUS_ACTV ||
875 (cu_status & AC_SW_B)){
876#ifdef WLDEBUG
877 printf("wl%d: CU unexpectedly busy; scb %04x cu %04x\n",
878 unit, scb_status, cu_status);
879#endif
880 if (xmt_watch) printf("wl%d: busy?!",unit);
881 return; /* hey, why are we busy? */
882 }
883
884 /* get ourselves some data */
885 ifp = &(sc->wl_if);
886 IF_DEQUEUE(&ifp->if_snd, m);
887 if (m != (struct mbuf *)0) {
888 /* let BPF see it before we commit it */
889 BPF_MTAP(ifp, m);
890 sc->tbusy++;
891 /* set the watchdog timer so that if the board
892 * fails to interrupt we will restart
893 */
894 /* try 10 ticks, not very long */
895 sc->watchdog_ch = timeout(wlwatchdog, sc, 10);
896 sc->wl_ac.ac_if.if_flags |= IFF_OACTIVE;
897 sc->wl_if.if_opackets++;
898 wlxmt(unit, m);
899 } else {
900 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
901 }
902 return;
903}
904
905/*
906 * wlread:
907 *
908 * This routine does the actual copy of data (including ethernet header
909 * structure) from the WaveLAN to an mbuf chain that will be passed up
910 * to the "if" (network interface) layer. NOTE: we currently
911 * don't handle trailer protocols, so if that is needed, it will
912 * (at least in part) be added here. For simplicities sake, this
913 * routine copies the receive buffers from the board into a local (stack)
914 * buffer until the frame has been copied from the board. Once in
915 * the local buffer, the contents are copied to an mbuf chain that
916 * is then enqueued onto the appropriate "if" queue.
917 *
2/*
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions
5 * are met:
6 * 1. Redistributions of source code must retain all copyright
7 * notices, this list of conditions and the following disclaimer.
8 * 2. The names of the authors may not be used to endorse or promote products
9 * derived from this software without specific prior written permission
10 *
11 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
12 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
13 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
14 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
15 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
16 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
17 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
18 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
19 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
20 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21 *
22 */
23/*
24 * if_wl.c - original MACH, then BSDI ISA wavelan driver
25 * ported to mach by Anders Klemets
26 * to BSDI by Robert Morris
27 * to FreeBSD by Jim Binkley
28 * to FreeBSD 2.2+ by Michael Smith
29 *
30 * 2.2 update:
31 * Changed interface to match 2.1-2.2 differences.
32 * Implement IRQ selection logic in wlprobe()
33 * Implement PSA updating.
34 * Pruned heading comments for relevance.
35 * Ripped out all the 'interface counters' cruft.
36 * Cut the missing-interrupt timer back to 100ms.
37 * 2.2.1 update:
38 * now supports all multicast mode (mrouted will work),
39 * but unfortunately must do that by going into promiscuous mode
40 * NWID sysctl added so that normally promiscuous mode is NWID-specific
41 * but can be made NWID-inspecific
42 * 7/14/97 jrb
43 *
44 * Work done:
45 * Ported to FreeBSD, got promiscuous mode working with bpfs,
46 * and rewired timer routine. The i82586 will hang occasionally on output
47 * and the watchdog timer will kick it if so and log an entry.
48 * 2 second timeout there. Apparently the chip loses an interrupt.
49 * Code borrowed from if_ie.c for watchdog timer.
50 *
51 * The wavelan card is a 2mbit radio modem that emulates ethernet;
52 * i.e., it uses MAC addresses. This should not be a surprise since
53 * it uses an ethernet controller as a major hw item.
54 * It can broadcast, unicast or apparently multicast in a base cell
55 * using a omni-directional antennae that is
56 * about 800 feet around the base cell barring walls and metal.
57 * With directional antennae, it can be used point to point over a mile
58 * or so apparently (haven't tried that).
59 *
60 * There are ISA and pcmcia versions (not supported by this code).
61 * The ISA card has an Intel 82586 lan controller on it. It consists
62 * of 2 pieces of hw, the lan controller (intel) and a radio-modem.
63 * The latter has an extra set of controller registers that has nothing
64 * to do with the i82586 and allows setting and monitoring of radio
65 * signal strength, etc. There is a nvram area called the PSA that
66 * contains a number of setup variables including the IRQ and so-called
67 * NWID or Network ID. The NWID must be set the same for all radio
68 * cards to communicate (unless you are using the ATT/NCR roaming feature
69 * with their access points. There is no support for that here. Roaming
70 * involves a link-layer beacon sent out from the access points. End
71 * stations monitor the signal strength and only use the strongest
72 * access point). This driver assumes that the base ISA port, IRQ,
73 * and NWID are first set in nvram via the dos-side "instconf.exe" utility
74 * supplied with the card. This driver takes the ISA port from
75 * the kernel configuration setup, and then determines the IRQ either
76 * from the kernel config (if an explicit IRQ is set) or from the
77 * PSA on the card if not.
78 * The hw also magically just uses the IRQ set in the nvram.
79 * The NWID is used magically as well by the radio-modem
80 * to determine which packets to keep or throw out.
81 *
82 * sample config:
83 *
84 * device wl0 at isa? port 0x300 net irq ?
85 *
86 * Ifdefs:
87 * 1. WLDEBUG. (off) - if turned on enables IFF_DEBUG set via ifconfig debug
88 * 2. MULTICAST (on) - turned on and works up to and including mrouted
89 * 3. WLCACHE (off) - define to turn on a signal strength
90 * (and other metric) cache that is indexed by sender MAC address.
91 * Apps can read this out to learn the remote signal strength of a
92 * sender. Note that it has a switch so that it only stores
93 * broadcast/multicast senders but it could be set to store unicast
94 * too only. Size is hardwired in if_wl_wavelan.h
95 *
96 * one further note: promiscuous mode is a curious thing. In this driver,
97 * promiscuous mode apparently CAN catch ALL packets and ignore the NWID
98 * setting. This is probably more useful in a sense (for snoopers) if
99 * you are interested in all traffic as opposed to if you are interested
100 * in just your own. There is a driver specific sysctl to turn promiscuous
101 * from just promiscuous to wildly promiscuous...
102 *
103 * This driver also knows how to load the synthesizers in the 2.4 Gz
104 * ISA Half-card, Product number 847647476 (USA/FCC IEEE Channel set).
105 * This product consists of a "mothercard" that contains the 82586,
106 * NVRAM that holds the PSA, and the ISA-buss interface custom ASIC.
107 * The radio transceiver is a "daughtercard" called the WaveMODEM which
108 * connects to the mothercard through two single-inline connectors: a
109 * 20-pin connector provides DC-power and modem signals, and a 3-pin
110 * connector which exports the antenna connection. The code herein
111 * loads the receive and transmit synthesizers and the corresponding
112 * transmitter output power value from an EEPROM controlled through
113 * additional registers via the MMC. The EEPROM address selected
114 * are those whose values are preset by the DOS utility programs
115 * provided with the product, and this provides compatible operation
116 * with the DOS Packet Driver software. A future modification will
117 * add the necessary functionality to this driver and to the wlconfig
118 * utility to completely replace the DOS Configuration Utilities.
119 * The 2.4 Gz WaveMODEM is described in document number 407-024692/E,
120 * and is available through Lucent Technologies OEM supply channels.
121 * --RAB 1997/06/08.
122 */
123
124#define MULTICAST 1
125
126/*
127 * Olivetti PC586 Mach Ethernet driver v1.0
128 * Copyright Ing. C. Olivetti & C. S.p.A. 1988, 1989
129 * All rights reserved.
130 *
131 */
132
133/*
134 Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc.,
135Cupertino, California.
136
137 All Rights Reserved
138
139 Permission to use, copy, modify, and distribute this software and
140its documentation for any purpose and without fee is hereby
141granted, provided that the above copyright notice appears in all
142copies and that both the copyright notice and this permission notice
143appear in supporting documentation, and that the name of Olivetti
144not be used in advertising or publicity pertaining to distribution
145of the software without specific, written prior permission.
146
147 OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
148INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
149IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
150CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
151LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
152NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
153WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
154*/
155
156/*
157 Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
158
159 All Rights Reserved
160
161Permission to use, copy, modify, and distribute this software and
162its documentation for any purpose and without fee is hereby
163granted, provided that the above copyright notice appears in all
164copies and that both the copyright notice and this permission notice
165appear in supporting documentation, and that the name of Intel
166not be used in advertising or publicity pertaining to distribution
167of the software without specific, written prior permission.
168
169INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
170INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
171IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
172CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
173LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
174NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
175WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
176*/
177
178/*
179 * NOTE:
180 * by rvb:
181 * 1. The best book on the 82586 is:
182 * LAN Components User's Manual by Intel
183 * The copy I found was dated 1984. This really tells you
184 * what the state machines are doing
185 * 2. In the current design, we only do one write at a time,
186 * though the hardware is capable of chaining and possibly
187 * even batching. The problem is that we only make one
188 * transmit buffer available in sram space.
189 */
190
191#define NWL 4
192#include "opt_wavelan.h"
193#include "opt_inet.h"
194
195#include <sys/param.h>
196#include <sys/systm.h>
197#include <sys/kernel.h>
198#include <sys/sockio.h>
199#include <sys/mbuf.h>
200#include <sys/socket.h>
201#include <sys/syslog.h>
202#include <sys/bus.h>
203
204#include <sys/sysctl.h>
205
206#include <net/ethernet.h>
207#include <net/if.h>
208#include <net/if_dl.h>
209
210#ifdef INET
211#include <netinet/in.h>
212#include <netinet/in_systm.h>
213#include <netinet/ip.h>
214#include <netinet/if_ether.h>
215#endif
216
217#include <net/bpf.h>
218#include <i386/isa/isa_device.h>
219#include <i386/isa/ic/if_wl_i82586.h> /* Definitions for the Intel chip */
220
221/* was 1000 in original, fed to DELAY(x) */
222#define DELAYCONST 1000
223#include <dev/wl/if_wl.h>
224#include <machine/if_wl_wavelan.h>
225
226#ifndef COMPAT_OLDISA
227#error "The wl device requires the old isa compatibility shims"
228#endif
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
265struct isa_driver wldriver = {
266 INTR_TYPE_NET,
267 wlprobe,
268 wlattach,
269 "wl",
270 0
271};
272COMPAT_ISA_DRIVER(wl, wldriver);
273
274/*
275 * XXX The Wavelan appears to be prone to dropping stuff if you talk to
276 * it too fast. This disgusting hack inserts a delay after each packet
277 * is queued which helps avoid this behaviour on fast systems.
278 */
279static int wl_xmit_delay = 250;
280SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_delay, CTLFLAG_RW, &wl_xmit_delay, 0, "");
281
282/*
283 * not XXX, but ZZZ (bizarre).
284 * promiscuous mode can be toggled to ignore NWIDs. By default,
285 * it does not. Caution should be exercised about combining
286 * this mode with IFF_ALLMULTI which puts this driver in
287 * promiscuous mode.
288 */
289static int wl_ignore_nwid = 0;
290SYSCTL_INT(_machdep, OID_AUTO, wl_ignore_nwid, CTLFLAG_RW, &wl_ignore_nwid, 0, "");
291
292/*
293 * Emit diagnostics about transmission problems
294 */
295static int xmt_watch = 0;
296SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_watch, CTLFLAG_RW, &xmt_watch, 0, "");
297
298/*
299 * Collect SNR statistics
300 */
301static int gathersnr = 0;
302SYSCTL_INT(_machdep, OID_AUTO, wl_gather_snr, CTLFLAG_RW, &gathersnr, 0, "");
303
304static void wlstart(struct ifnet *ifp);
305static void wlinit(void *xsc);
306static int wlioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
307static timeout_t wlwatchdog;
308static ointhand2_t wlintr;
309static void wlxmt(int unt, struct mbuf *m);
310static int wldiag(int unt);
311static int wlconfig(int unit);
312static int wlcmd(int unit, char *str);
313static void wlmmcstat(int unit);
314static u_short wlbldru(int unit);
315static u_short wlmmcread(u_int base, u_short reg);
316static void wlinitmmc(int unit);
317static int wlhwrst(int unit);
318static void wlrustrt(int unit);
319static void wlbldcu(int unit);
320static int wlack(int unit);
321static int wlread(int unit, u_short fd_p);
322static void getsnr(int unit);
323static void wlrcv(int unit);
324static int wlrequeue(int unit, u_short fd_p);
325static void wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
326static void wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
327#ifdef WLDEBUG
328static void wltbd(int unit);
329#endif
330static void wlgetpsa(int base, u_char *buf);
331static void wlsetpsa(int unit);
332static u_short wlpsacrc(u_char *buf);
333static void wldump(int unit);
334#ifdef WLCACHE
335static void wl_cache_store(int, int, struct ether_header *, struct mbuf *);
336static void wl_cache_zero(int unit);
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 register 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 register short base = id->id_iobase;
438 int i,j;
439 u_char unit = id->id_unit;
440 register 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 for (i=0; i < WAVELAN_ADDR_SIZE; ++i)
472 sc->wl_addr[i] = sc->psa[j + i];
473
474 /* enter normal 16 bit mode operation */
475 sc->hacr = HACR_DEFAULT;
476 CMD(unit);
477
478 wlinitmmc(unit);
479 outw(PIOR1(base), OFFSET_SCB + 8); /* address of scb_crcerrs */
480 outw(PIOP1(base), 0); /* clear scb_crcerrs */
481 outw(PIOP1(base), 0); /* clear scb_alnerrs */
482 outw(PIOP1(base), 0); /* clear scb_rscerrs */
483 outw(PIOP1(base), 0); /* clear scb_ovrnerrs */
484
485 bzero(ifp, sizeof(ifp));
486 ifp->if_softc = sc;
487 ifp->if_unit = id->id_unit;
488 ifp->if_mtu = WAVELAN_MTU;
489 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
490#ifdef WLDEBUG
491 ifp->if_flags |= IFF_DEBUG;
492#endif
493#if MULTICAST
494 ifp->if_flags |= IFF_MULTICAST;
495#endif /* MULTICAST */
496 ifp->if_name = "wl";
497 ifp->if_unit = unit;
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_addr[0]);
509
510 bcopy(&sc->wl_addr[0], sc->wl_ac.ac_enaddr, WAVELAN_ADDR_SIZE);
511 printf("%s%d: address %6D, NWID 0x%02x%02x", ifp->if_name, ifp->if_unit,
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 register 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 register 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 register 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 (TAILQ_FIRST(&ifp->if_addrhead) == (struct ifaddr *)0)
677 return;
678 oldpri = splimp();
679 if ((stat = wlhwrst(sc->unit)) == TRUE) {
680 sc->wl_if.if_flags |= IFF_RUNNING; /* same as DSF_RUNNING */
681 /*
682 * OACTIVE is used by upper-level routines
683 * and must be set
684 */
685 sc->wl_if.if_flags &= ~IFF_OACTIVE; /* same as tbusy below */
686
687 sc->flags |= DSF_RUNNING;
688 sc->tbusy = 0;
689 untimeout(wlwatchdog, sc, sc->watchdog_ch);
690
691 wlstart(ifp);
692 } else {
693 printf("wl%d init(): trouble resetting board.\n", sc->unit);
694 }
695 splx(oldpri);
696}
697
698/*
699 * wlhwrst:
700 *
701 * This routine resets the WaveLAN board that corresponds to the
702 * board number passed in.
703 *
704 * input : board number to do a hardware reset
705 * output : board is reset
706 *
707 */
708static int
709wlhwrst(int unit)
710{
711 register struct wl_softc *sc = WLSOFTC(unit);
712
713#ifdef WLDEBUG
714 if (sc->wl_if.if_flags & IFF_DEBUG)
715 printf("wl%d: entered wlhwrst()\n",unit);
716#endif
717 sc->hacr = HACR_RESET;
718 CMD(unit); /* reset the board */
719
720 /* clear reset command and set PIO#1 in autoincrement mode */
721 sc->hacr = HACR_DEFAULT;
722 CMD(unit);
723
724#ifdef WLDEBUG
725 if (sc->wl_if.if_flags & IFF_DEBUG)
726 wlmmcstat(unit); /* Display MMC registers */
727#endif /* WLDEBUG */
728 wlbldcu(unit); /* set up command unit structures */
729
730 if (wldiag(unit) == 0)
731 return(0);
732
733 if (wlconfig(unit) == 0)
734 return(0);
735 /*
736 * insert code for loopback test here
737 */
738 wlrustrt(unit); /* start receive unit */
739
740 /* enable interrupts */
741 sc->hacr = (HACR_DEFAULT | HACR_INTRON);
742 CMD(unit);
743
744 return(1);
745}
746
747/*
748 * wlbldcu:
749 *
750 * This function builds up the command unit structures. It inits
751 * the scp, iscp, scb, cb, tbd, and tbuf.
752 *
753 */
754static void
755wlbldcu(int unit)
756{
757 register struct wl_softc *sc = WLSOFTC(unit);
758 short base = sc->base;
759 scp_t scp;
760 iscp_t iscp;
761 scb_t scb;
762 ac_t cb;
763 tbd_t tbd;
764 int i;
765
766 bzero(&scp, sizeof(scp));
767 scp.scp_sysbus = 0;
768 scp.scp_iscp = OFFSET_ISCP;
769 scp.scp_iscp_base = 0;
770 outw(PIOR1(base), OFFSET_SCP);
771 outsw(PIOP1(base), &scp, sizeof(scp_t)/2);
772
773 bzero(&iscp, sizeof(iscp));
774 iscp.iscp_busy = 1;
775 iscp.iscp_scb_offset = OFFSET_SCB;
776 iscp.iscp_scb = 0;
777 iscp.iscp_scb_base = 0;
778 outw(PIOR1(base), OFFSET_ISCP);
779 outsw(PIOP1(base), &iscp, sizeof(iscp_t)/2);
780
781 scb.scb_status = 0;
782 scb.scb_command = SCB_RESET;
783 scb.scb_cbl_offset = OFFSET_CU;
784 scb.scb_rfa_offset = OFFSET_RU;
785 scb.scb_crcerrs = 0;
786 scb.scb_alnerrs = 0;
787 scb.scb_rscerrs = 0;
788 scb.scb_ovrnerrs = 0;
789 outw(PIOR1(base), OFFSET_SCB);
790 outsw(PIOP1(base), &scb, sizeof(scb_t)/2);
791
792 SET_CHAN_ATTN(unit);
793
794 outw(PIOR0(base), OFFSET_ISCP + 0); /* address of iscp_busy */
795 for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); )
796 continue;
797 if (i <= 0)
798 printf("wl%d bldcu(): iscp_busy timeout.\n", unit);
799 outw(PIOR0(base), OFFSET_SCB + 0); /* address of scb_status */
800 for (i = STATUS_TRIES; i-- > 0; ) {
801 if (inw(PIOP0(base)) == (SCB_SW_CX|SCB_SW_CNA))
802 break;
803 }
804 if (i <= 0)
805 printf("wl%d bldcu(): not ready after reset.\n", unit);
806 wlack(unit);
807
808 cb.ac_status = 0;
809 cb.ac_command = AC_CW_EL; /* NOP */
810 cb.ac_link_offset = OFFSET_CU;
811 outw(PIOR1(base), OFFSET_CU);
812 outsw(PIOP1(base), &cb, 6/2);
813
814 tbd.act_count = 0;
815 tbd.next_tbd_offset = I82586NULL;
816 tbd.buffer_addr = 0;
817 tbd.buffer_base = 0;
818 outw(PIOR1(base), OFFSET_TBD);
819 outsw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
820}
821
822/*
823 * wlstart:
824 *
825 * send a packet
826 *
827 * input : board number
828 * output : stuff sent to board if any there
829 *
830 */
831static void
832wlstart(struct ifnet *ifp)
833{
834 int unit = ifp->if_unit;
835 struct mbuf *m;
836 register struct wl_softc *sc = WLSOFTC(unit);
837 short base = sc->base;
838 int scb_status, cu_status, scb_command;
839
840#ifdef WLDEBUG
841 if (sc->wl_if.if_flags & IFF_DEBUG)
842 printf("wl%d: entered wlstart()\n",unit);
843#endif
844
845 outw(PIOR1(base), OFFSET_CU);
846 cu_status = inw(PIOP1(base));
847 outw(PIOR0(base),OFFSET_SCB + 0); /* scb_status */
848 scb_status = inw(PIOP0(base));
849 outw(PIOR0(base), OFFSET_SCB + 2);
850 scb_command = inw(PIOP0(base));
851
852 /*
853 * don't need OACTIVE check as tbusy here checks to see
854 * if we are already busy
855 */
856 if (sc->tbusy) {
857 if ((scb_status & 0x0700) == SCB_CUS_IDLE &&
858 (cu_status & AC_SW_B) == 0){
859 sc->tbusy = 0;
860 untimeout(wlwatchdog, sc, sc->watchdog_ch);
861 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
862 /*
863 * This is probably just a race. The xmt'r is just
864 * became idle but WE have masked interrupts so ...
865 */
866#ifdef WLDEBUG
867 printf("wl%d: CU idle, scb %04x %04x cu %04x\n",
868 unit, scb_status, scb_command, cu_status);
869#endif
870 if (xmt_watch) printf("!!");
871 } else {
872 return; /* genuinely still busy */
873 }
874 } else if ((scb_status & 0x0700) == SCB_CUS_ACTV ||
875 (cu_status & AC_SW_B)){
876#ifdef WLDEBUG
877 printf("wl%d: CU unexpectedly busy; scb %04x cu %04x\n",
878 unit, scb_status, cu_status);
879#endif
880 if (xmt_watch) printf("wl%d: busy?!",unit);
881 return; /* hey, why are we busy? */
882 }
883
884 /* get ourselves some data */
885 ifp = &(sc->wl_if);
886 IF_DEQUEUE(&ifp->if_snd, m);
887 if (m != (struct mbuf *)0) {
888 /* let BPF see it before we commit it */
889 BPF_MTAP(ifp, m);
890 sc->tbusy++;
891 /* set the watchdog timer so that if the board
892 * fails to interrupt we will restart
893 */
894 /* try 10 ticks, not very long */
895 sc->watchdog_ch = timeout(wlwatchdog, sc, 10);
896 sc->wl_ac.ac_if.if_flags |= IFF_OACTIVE;
897 sc->wl_if.if_opackets++;
898 wlxmt(unit, m);
899 } else {
900 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
901 }
902 return;
903}
904
905/*
906 * wlread:
907 *
908 * This routine does the actual copy of data (including ethernet header
909 * structure) from the WaveLAN to an mbuf chain that will be passed up
910 * to the "if" (network interface) layer. NOTE: we currently
911 * don't handle trailer protocols, so if that is needed, it will
912 * (at least in part) be added here. For simplicities sake, this
913 * routine copies the receive buffers from the board into a local (stack)
914 * buffer until the frame has been copied from the board. Once in
915 * the local buffer, the contents are copied to an mbuf chain that
916 * is then enqueued onto the appropriate "if" queue.
917 *
918 * input : board number, and an frame descriptor address
918 * input : board number, and a frame descriptor address
919 * output : the packet is put into an mbuf chain, and passed up
920 * assumes : if any errors occur, packet is "dropped on the floor"
921 *
922 */
923static int
924wlread(int unit, u_short fd_p)
925{
926 register struct wl_softc *sc = WLSOFTC(unit);
927 register struct ifnet *ifp = &sc->wl_if;
928 short base = sc->base;
929 fd_t fd;
930 struct ether_header *eh;
931 struct mbuf *m;
932 rbd_t rbd;
933 u_char *mb_p;
934 u_short mlen, len;
935 u_short bytes_in_msg, bytes_in_mbuf, bytes;
936
937
938#ifdef WLDEBUG
939 if (sc->wl_if.if_flags & IFF_DEBUG)
940 printf("wl%d: entered wlread()\n", unit);
941#endif
942 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
943 printf("wl%d read(): board is not running.\n", unit);
944 sc->hacr &= ~HACR_INTRON;
945 CMD(unit); /* turn off interrupts */
946 }
947
948 /*
949 * Collect message size.
950 */
951 outw(PIOR1(base), fd_p);
952 insw(PIOP1(base), &fd, sizeof(fd_t)/2);
953 if (fd.rbd_offset == I82586NULL) {
954 if (wlhwrst(unit) != TRUE) {
955 sc->hacr &= ~HACR_INTRON;
956 CMD(unit); /* turn off interrupts */
957 printf("wl%d read(): hwrst trouble.\n", unit);
958 }
959 return 0;
960 }
961
962 outw(PIOR1(base), fd.rbd_offset);
963 insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
964 bytes_in_msg = rbd.status & RBD_SW_COUNT;
965
966 /*
967 * Allocate a cluster'd mbuf to receive the packet.
968 */
969 m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
970 if (m == NULL) {
971 if (wlhwrst(unit) != TRUE) {
972 sc->hacr &= ~HACR_INTRON;
973 CMD(unit); /* turn off interrupts */
974 printf("wl%d read(): hwrst trouble.\n", unit);
975 }
976 return 0;
977 }
978 m->m_pkthdr.len = m->m_len = MCLBYTES;
979 m_adj(m, ETHER_ALIGN); /* align IP header */
980
981 /*
982 * Collect the message data.
983 */
984 mlen = 0;
985 mb_p = mtod(m, u_char *);
986 bytes_in_mbuf = MCLBYTES;
987 bytes = min(bytes_in_mbuf, bytes_in_msg);
988 for (;;) {
989 if (bytes & 1) {
990 len = bytes + 1;
991 } else {
992 len = bytes;
993 }
994 outw(PIOR1(base), rbd.buffer_addr);
995 insw(PIOP1(base), mb_p, len/2);
996 mlen += bytes;
997
998 if (bytes > bytes_in_mbuf) {
999 /* XXX something wrong, a packet should fit in 1 cluster */
1000 m_freem(m);
1001 printf("wl%d read(): packet too large (%u > %u)\n",
1002 unit, bytes, bytes_in_mbuf);
1003 if (wlhwrst(unit) != TRUE) {
1004 sc->hacr &= ~HACR_INTRON;
1005 CMD(unit); /* turn off interrupts */
1006 printf("wl%d read(): hwrst trouble.\n", unit);
1007 }
1008 return 0;
1009 }
1010 mb_p += bytes;
1011 bytes_in_msg -= bytes;
1012 if (bytes_in_msg == 0) {
1013 if (rbd.status & RBD_SW_EOF || rbd.next_rbd_offset == I82586NULL) {
1014 break;
1015 }
1016 outw(PIOR1(base), rbd.next_rbd_offset);
1017 insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1018 bytes_in_msg = rbd.status & RBD_SW_COUNT;
1019 } else {
1020 rbd.buffer_addr += bytes;
1021 }
1022
1023 bytes = min(bytes_in_mbuf, bytes_in_msg);
1024 }
1025
1026 m->m_pkthdr.len = m->m_len = mlen;
1027 m->m_pkthdr.rcvif = ifp;
1028
1029 /*
1030 * If hw is in promiscuous mode (note that I said hardware, not if
1031 * IFF_PROMISC is set in ifnet flags), then if this is a unicast
1032 * packet and the MAC dst is not us, drop it. This check in normally
1033 * inside ether_input(), but IFF_MULTI causes hw promisc without
1034 * a bpf listener, so this is wrong.
1035 * Greg Troxel <gdt@ir.bbn.com>, 1998-08-07
1036 */
1037 /*
1038 * TBD: also discard packets where NWID does not match.
1039 * However, there does not appear to be a way to read the nwid
1040 * for a received packet. -gdt 1998-08-07
1041 */
1042 /* XXX verify mbuf length */
1043 eh = mtod(m, struct ether_header *);
1044 if (
1045#ifdef WL_USE_IFNET_PROMISC_CHECK /* not defined */
1046 (sc->wl_ac.ac_if.if_flags & (IFF_PROMISC|IFF_ALLMULTI))
1047#else
1048 /* hw is in promisc mode if this is true */
1049 (sc->mode & (MOD_PROM | MOD_ENAL))
1050#endif
1051 &&
1052 (eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
1053 bcmp(eh->ether_dhost, sc->wl_ac.ac_enaddr,
1054 sizeof(eh->ether_dhost)) != 0 ) {
1055 m_freem(m);
1056 return 1;
1057 }
1058
1059#ifdef WLDEBUG
1060 if (sc->wl_if.if_flags & IFF_DEBUG)
1061 printf("wl%d: wlrecv %u bytes\n", unit, mlen);
1062#endif
1063
1064#ifdef WLCACHE
1065 wl_cache_store(unit, base, eh, m);
1066#endif
1067
1068 /*
1069 * received packet is now in a chain of mbuf's. next step is
1070 * to pass the packet upwards.
1071 */
1072 (*ifp->if_input)(ifp, m);
1073 return 1;
1074}
1075
1076/*
1077 * wlioctl:
1078 *
1079 * This routine processes an ioctl request from the "if" layer
1080 * above.
1081 *
1082 * input : pointer the appropriate "if" struct, command, and data
1083 * output : based on command appropriate action is taken on the
1084 * WaveLAN board(s) or related structures
1085 * return : error is returned containing exit conditions
1086 *
1087 */
1088static int
1089wlioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1090{
1091 register struct ifreq *ifr = (struct ifreq *)data;
1092 int unit = ifp->if_unit;
1093 register struct wl_softc *sc = WLSOFTC(unit);
1094 short base = sc->base;
1095 short mode = 0;
1096 int opri, error = 0;
1097 struct thread *td = curthread; /* XXX */
1098 int irq, irqval, i, isroot;
1099 caddr_t up;
1100#ifdef WLCACHE
1101 int size;
1102 char * cpt;
1103#endif
1104
1105#ifdef WLDEBUG
1106 if (sc->wl_if.if_flags & IFF_DEBUG)
1107 printf("wl%d: entered wlioctl()\n",unit);
1108#endif
1109 opri = splimp();
1110 switch (cmd) {
1111 case SIOCSIFFLAGS:
1112 if (ifp->if_flags & IFF_ALLMULTI) {
1113 mode |= MOD_ENAL;
1114 }
1115 if (ifp->if_flags & IFF_PROMISC) {
1116 mode |= MOD_PROM;
1117 }
1118 if (ifp->if_flags & IFF_LINK0) {
1119 mode |= MOD_PROM;
1120 }
1121 /*
1122 * force a complete reset if the recieve multicast/
1123 * promiscuous mode changes so that these take
1124 * effect immediately.
1125 *
1126 */
1127 if (sc->mode != mode) {
1128 sc->mode = mode;
1129 if (sc->flags & DSF_RUNNING) {
1130 sc->flags &= ~DSF_RUNNING;
1131 wlinit(sc);
1132 }
1133 }
1134 /* if interface is marked DOWN and still running then
1135 * stop it.
1136 */
1137 if ((ifp->if_flags & IFF_UP) == 0 && sc->flags & DSF_RUNNING) {
1138 printf("wl%d ioctl(): board is not running\n", unit);
1139 sc->flags &= ~DSF_RUNNING;
1140 sc->hacr &= ~HACR_INTRON;
1141 CMD(unit); /* turn off interrupts */
1142 }
1143 /* else if interface is UP and RUNNING, start it
1144 */
1145 else if (ifp->if_flags & IFF_UP && (sc->flags & DSF_RUNNING) == 0) {
1146 wlinit(sc);
1147 }
1148
1149 /* if WLDEBUG set on interface, then printf rf-modem regs
1150 */
1151 if (ifp->if_flags & IFF_DEBUG)
1152 wlmmcstat(unit);
1153 break;
1154#if MULTICAST
1155 case SIOCADDMULTI:
1156 case SIOCDELMULTI:
1157
1158 wlinit(sc);
1159 break;
1160#endif /* MULTICAST */
1161
1162 /* DEVICE SPECIFIC */
1163
1164
1165 /* copy the PSA out to the caller */
1166 case SIOCGWLPSA:
1167 /* pointer to buffer in user space */
1168 up = (void *)ifr->ifr_data;
1169 /* work out if they're root */
1170 isroot = (suser(td) == 0);
1171
1172 for (i = 0; i < 0x40; i++) {
1173 /* don't hand the DES key out to non-root users */
1174 if ((i > WLPSA_DESKEY) && (i < (WLPSA_DESKEY + 8)) && !isroot)
1175 continue;
1176 if (subyte((up + i), sc->psa[i]))
1177 return(EFAULT);
1178 }
1179 break;
1180
1181
1182 /* copy the PSA in from the caller; we only copy _some_ values */
1183 case SIOCSWLPSA:
1184 /* root only */
1185 if ((error = suser(td)))
1186 break;
1187 error = EINVAL; /* assume the worst */
1188 /* pointer to buffer in user space containing data */
1189 up = (void *)ifr->ifr_data;
1190
1191 /* check validity of input range */
1192 for (i = 0; i < 0x40; i++)
1193 if (fubyte(up + i) < 0)
1194 return(EFAULT);
1195
1196 /* check IRQ value */
1197 irqval = fubyte(up+WLPSA_IRQNO);
1198 for (irq = 15; irq >= 0; irq--)
1199 if (irqvals[irq] == irqval)
1200 break;
1201 if (irq == 0) /* oops */
1202 break;
1203 /* new IRQ */
1204 sc->psa[WLPSA_IRQNO] = irqval;
1205
1206 /* local MAC */
1207 for (i = 0; i < 6; i++)
1208 sc->psa[WLPSA_LOCALMAC+i] = fubyte(up+WLPSA_LOCALMAC+i);
1209
1210 /* MAC select */
1211 sc->psa[WLPSA_MACSEL] = fubyte(up+WLPSA_MACSEL);
1212
1213 /* default nwid */
1214 sc->psa[WLPSA_NWID] = fubyte(up+WLPSA_NWID);
1215 sc->psa[WLPSA_NWID+1] = fubyte(up+WLPSA_NWID+1);
1216
1217 error = 0;
1218 wlsetpsa(unit); /* update the PSA */
1219 break;
1220
1221
1222 /* get the current NWID out of the sc since we stored it there */
1223 case SIOCGWLCNWID:
1224 ifr->ifr_data = (caddr_t) (sc->nwid[0] << 8 | sc->nwid[1]);
1225 break;
1226
1227
1228 /*
1229 * change the nwid dynamically. This
1230 * ONLY changes the radio modem and does not
1231 * change the PSA.
1232 *
1233 * 2 steps:
1234 * 1. save in softc "soft registers"
1235 * 2. save in radio modem (MMC)
1236 */
1237 case SIOCSWLCNWID:
1238 /* root only */
1239 if ((error = suser(td)))
1240 break;
1241 if (!(ifp->if_flags & IFF_UP)) {
1242 error = EIO; /* only allowed while up */
1243 } else {
1244 /*
1245 * soft c nwid shadows radio modem setting
1246 */
1247 sc->nwid[0] = (int)ifr->ifr_data >> 8;
1248 sc->nwid[1] = (int)ifr->ifr_data & 0xff;
1249 MMC_WRITE(MMC_NETW_ID_L,sc->nwid[1]);
1250 MMC_WRITE(MMC_NETW_ID_H,sc->nwid[0]);
1251 }
1252 break;
1253
1254 /* copy the EEPROM in 2.4 Gz WaveMODEM out to the caller */
1255 case SIOCGWLEEPROM:
1256 /* root only */
1257 if ((error = suser(td)))
1258 break;
1259 /* pointer to buffer in user space */
1260 up = (void *)ifr->ifr_data;
1261
1262 for (i=0x00; i<0x80; ++i) { /* 2.4 Gz: size of EEPROM */
1263 MMC_WRITE(MMC_EEADDR,i); /* 2.4 Gz: get frequency */
1264 MMC_WRITE(MMC_EECTRL, /* 2.4 Gz: EEPROM read */
1265 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: */
1266 DELAY(40); /* 2.4 Gz */
1267 if (subyte(up + 2*i , /* 2.4 Gz: pass low byte of */
1268 wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word */
1269 ) return(EFAULT); /* 2.4 Gz: */
1270 if (subyte(up + 2*i+1, /* 2.4 Gz: pass hi byte of */
1271 wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word */
1272 ) return(EFAULT); /* 2.4 Gz: */
1273 }
1274 break;
1275
1276#ifdef WLCACHE
1277 /* zero (Delete) the wl cache */
1278 case SIOCDWLCACHE:
1279 /* root only */
1280 if ((error = suser(td)))
1281 break;
1282 wl_cache_zero(unit);
1283 break;
1284
1285 /* read out the number of used cache elements */
1286 case SIOCGWLCITEM:
1287 ifr->ifr_data = (caddr_t) sc->w_sigitems;
1288 break;
1289
1290 /* read out the wl cache */
1291 case SIOCGWLCACHE:
1292 /* pointer to buffer in user space */
1293 up = (void *)ifr->ifr_data;
1294 cpt = (char *) &sc->w_sigcache[0];
1295 size = sc->w_sigitems * sizeof(struct w_sigcache);
1296
1297 for (i = 0; i < size; i++) {
1298 if (subyte((up + i), *cpt++))
1299 return(EFAULT);
1300 }
1301 break;
1302#endif
1303
1304 default:
1305 error = ether_ioctl(ifp, cmd, data);
1306 break;
1307 }
1308 splx(opri);
1309 return (error);
1310}
1311
1312/*
1313 * wlwatchdog():
1314 *
1315 * Called if the timer set in wlstart expires before an interrupt is received
1316 * from the wavelan. It seems to lose interrupts sometimes.
1317 * The watchdog routine gets called if the transmitter failed to interrupt
1318 *
1319 * input : which board is timing out
1320 * output : board reset
1321 *
1322 */
1323static void
1324wlwatchdog(void *vsc)
1325{
1326 struct wl_softc *sc = vsc;
1327 int unit = sc->unit;
1328
1329 log(LOG_ERR, "wl%d: wavelan device timeout on xmit\n", unit);
1330 sc->wl_ac.ac_if.if_oerrors++;
1331 wlinit(sc);
1332}
1333
1334/*
1335 * wlintr:
1336 *
1337 * This function is the interrupt handler for the WaveLAN
1338 * board. This routine will be called whenever either a packet
1339 * is received, or a packet has successfully been transfered and
1340 * the unit is ready to transmit another packet.
1341 *
1342 * input : board number that interrupted
1343 * output : either a packet is received, or a packet is transfered
1344 *
1345 */
1346static void
1347wlintr(unit)
1348int unit;
1349{
1350 register struct wl_softc *sc = &wl_softc[unit];
1351 short base = sc->base;
1352 int ac_status;
1353 u_short int_type, int_type1;
1354
1355#ifdef WLDEBUG
1356 if (sc->wl_if.if_flags & IFF_DEBUG)
1357 printf("wl%d: wlintr() called\n",unit);
1358#endif
1359
1360 if ((int_type = inw(HASR(base))) & HASR_MMC_INTR) {
1361 /* handle interrupt from the modem management controler */
1362 /* This will clear the interrupt condition */
1363 (void) wlmmcread(base,MMC_DCE_STATUS); /* ignored for now */
1364 }
1365
1366 if (!(int_type & HASR_INTR)){ /* return if no interrupt from 82586 */
1367 /* commented out. jrb. it happens when reinit occurs
1368 printf("wlintr: int_type %x, dump follows\n", int_type);
1369 wldump(unit);
1370 */
1371 return;
1372 }
1373
1374 if (gathersnr)
1375 getsnr(unit);
1376 for (;;) {
1377 outw(PIOR0(base), OFFSET_SCB + 0); /* get scb status */
1378 int_type = (inw(PIOP0(base)) & SCB_SW_INT);
1379 if (int_type == 0) /* no interrupts left */
1380 break;
1381
1382 int_type1 = wlack(unit); /* acknowledge interrupt(s) */
1383 /* make sure no bits disappeared (others may appear) */
1384 if ((int_type & int_type1) != int_type)
1385 printf("wlack() int bits disappeared : %04x != int_type %04x\n",
1386 int_type1, int_type);
1387 int_type = int_type1; /* go with the new status */
1388 /*
1389 * incoming packet
1390 */
1391 if (int_type & SCB_SW_FR) {
1392 sc->wl_if.if_ipackets++;
1393 wlrcv(unit);
1394 }
1395 /*
1396 * receiver not ready
1397 */
1398 if (int_type & SCB_SW_RNR) {
1399 sc->wl_if.if_ierrors++;
1400#ifdef WLDEBUG
1401 if (sc->wl_if.if_flags & IFF_DEBUG)
1402 printf("wl%d intr(): receiver overrun! begin_fd = %x\n",
1403 unit, sc->begin_fd);
1404#endif
1405 wlrustrt(unit);
1406 }
1407 /*
1408 * CU not ready
1409 */
1410 if (int_type & SCB_SW_CNA) {
1411 /*
1412 * At present, we don't care about CNA's. We
1413 * believe they are a side effect of XMT.
1414 */
1415 }
1416 if (int_type & SCB_SW_CX) {
1417 /*
1418 * At present, we only request Interrupt for
1419 * XMT.
1420 */
1421 outw(PIOR1(base), OFFSET_CU); /* get command status */
1422 ac_status = inw(PIOP1(base));
1423
1424 if (xmt_watch) { /* report some anomalies */
1425
1426 if (sc->tbusy == 0) {
1427 printf("wl%d: xmt intr but not busy, CU %04x\n",
1428 unit, ac_status);
1429 }
1430 if (ac_status == 0) {
1431 printf("wl%d: xmt intr but ac_status == 0\n", unit);
1432 }
1433 if (ac_status & AC_SW_A) {
1434 printf("wl%d: xmt aborted\n",unit);
1435 }
1436#ifdef notdef
1437 if (ac_status & TC_CARRIER) {
1438 printf("wl%d: no carrier\n", unit);
1439 }
1440#endif /* notdef */
1441 if (ac_status & TC_CLS) {
1442 printf("wl%d: no CTS\n", unit);
1443 }
1444 if (ac_status & TC_DMA) {
1445 printf("wl%d: DMA underrun\n", unit);
1446 }
1447 if (ac_status & TC_DEFER) {
1448 printf("wl%d: xmt deferred\n",unit);
1449 }
1450 if (ac_status & TC_SQE) {
1451 printf("wl%d: heart beat\n", unit);
1452 }
1453 if (ac_status & TC_COLLISION) {
1454 printf("wl%d: too many collisions\n", unit);
1455 }
1456 }
1457 /* if the transmit actually failed, or returned some status */
1458 if ((!(ac_status & AC_SW_OK)) || (ac_status & 0xfff)) {
1459 if (ac_status & (TC_COLLISION | TC_CLS | TC_DMA)) {
1460 sc->wl_if.if_oerrors++;
1461 }
1462 /* count collisions */
1463 sc->wl_if.if_collisions += (ac_status & 0xf);
1464 /* if TC_COLLISION set and collision count zero, 16 collisions */
1465 if ((ac_status & 0x20) == 0x20) {
1466 sc->wl_if.if_collisions += 0x10;
1467 }
1468 }
1469 sc->tbusy = 0;
1470 untimeout(wlwatchdog, sc, sc->watchdog_ch);
1471 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
1472 wlstart(&(sc->wl_if));
1473 }
1474 }
1475 return;
1476}
1477
1478/*
1479 * wlrcv:
1480 *
1481 * This routine is called by the interrupt handler to initiate a
1482 * packet transfer from the board to the "if" layer above this
1483 * driver. This routine checks if a buffer has been successfully
1484 * received by the WaveLAN. If so, the routine wlread is called
1485 * to do the actual transfer of the board data (including the
1486 * ethernet header) into a packet (consisting of an mbuf chain).
1487 *
1488 * input : number of the board to check
1489 * output : if a packet is available, it is "sent up"
1490 *
1491 */
1492static void
1493wlrcv(int unit)
1494{
1495 register struct wl_softc *sc = WLSOFTC(unit);
1496 short base = sc->base;
1497 u_short fd_p, status, offset, link_offset;
1498
1499#ifdef WLDEBUG
1500 if (sc->wl_if.if_flags & IFF_DEBUG)
1501 printf("wl%d: entered wlrcv()\n",unit);
1502#endif
1503 for (fd_p = sc->begin_fd; fd_p != I82586NULL; fd_p = sc->begin_fd) {
1504
1505 outw(PIOR0(base), fd_p + 0); /* address of status */
1506 status = inw(PIOP0(base));
1507 outw(PIOR1(base), fd_p + 4); /* address of link_offset */
1508 link_offset = inw(PIOP1(base));
1509 offset = inw(PIOP1(base)); /* rbd_offset */
1510 if (status == 0xffff || offset == 0xffff /*I82586NULL*/) {
1511 if (wlhwrst(unit) != TRUE)
1512 printf("wl%d rcv(): hwrst ffff trouble.\n", unit);
1513 return;
1514 } else if (status & AC_SW_C) {
1515 if (status == (RFD_DONE|RFD_RSC)) {
1516 /* lost one */
1517#ifdef WLDEBUG
1518 if (sc->wl_if.if_flags & IFF_DEBUG)
1519 printf("wl%d RCV: RSC %x\n", unit, status);
1520#endif
1521 sc->wl_if.if_ierrors++;
1522 } else if (!(status & RFD_OK)) {
1523 printf("wl%d RCV: !OK %x\n", unit, status);
1524 sc->wl_if.if_ierrors++;
1525 } else if (status & 0xfff) { /* can't happen */
1526 printf("wl%d RCV: ERRs %x\n", unit, status);
1527 sc->wl_if.if_ierrors++;
1528 } else if (!wlread(unit, fd_p))
1529 return;
1530
1531 if (!wlrequeue(unit, fd_p)) {
1532 /* abort on chain error */
1533 if (wlhwrst(unit) != TRUE)
1534 printf("wl%d rcv(): hwrst trouble.\n", unit);
1535 return;
1536 }
1537 sc->begin_fd = link_offset;
1538 } else {
1539 break;
1540 }
1541 }
1542 return;
1543}
1544
1545/*
1546 * wlrequeue:
1547 *
1548 * This routine puts rbd's used in the last receive back onto the
1549 * free list for the next receive.
1550 *
1551 */
1552static int
1553wlrequeue(int unit, u_short fd_p)
1554{
1555 register struct wl_softc *sc = WLSOFTC(unit);
1556 short base = sc->base;
1557 fd_t fd;
1558 u_short l_rbdp, f_rbdp, rbd_offset;
1559
1560 outw(PIOR0(base), fd_p + 6);
1561 rbd_offset = inw(PIOP0(base));
1562 if ((f_rbdp = rbd_offset) != I82586NULL) {
1563 l_rbdp = f_rbdp;
1564 for (;;) {
1565 outw(PIOR0(base), l_rbdp + 0); /* address of status */
1566 if (inw(PIOP0(base)) & RBD_SW_EOF)
1567 break;
1568 outw(PIOP0(base), 0);
1569 outw(PIOR0(base), l_rbdp + 2); /* next_rbd_offset */
1570 if ((l_rbdp = inw(PIOP0(base))) == I82586NULL)
1571 break;
1572 }
1573 outw(PIOP0(base), 0);
1574 outw(PIOR0(base), l_rbdp + 2); /* next_rbd_offset */
1575 outw(PIOP0(base), I82586NULL);
1576 outw(PIOR0(base), l_rbdp + 8); /* address of size */
1577 outw(PIOP0(base), inw(PIOP0(base)) | AC_CW_EL);
1578 outw(PIOR0(base), sc->end_rbd + 2);
1579 outw(PIOP0(base), f_rbdp); /* end_rbd->next_rbd_offset */
1580 outw(PIOR0(base), sc->end_rbd + 8); /* size */
1581 outw(PIOP0(base), inw(PIOP0(base)) & ~AC_CW_EL);
1582 sc->end_rbd = l_rbdp;
1583 }
1584
1585 fd.status = 0;
1586 fd.command = AC_CW_EL;
1587 fd.link_offset = I82586NULL;
1588 fd.rbd_offset = I82586NULL;
1589 outw(PIOR1(base), fd_p);
1590 outsw(PIOP1(base), &fd, 8/2);
1591
1592 outw(PIOR1(base), sc->end_fd + 2); /* addr of command */
1593 outw(PIOP1(base), 0); /* command = 0 */
1594 outw(PIOP1(base), fd_p); /* end_fd->link_offset = fd_p */
1595 sc->end_fd = fd_p;
1596
1597 return 1;
1598}
1599
1600#ifdef WLDEBUG
1601static int xmt_debug = 0;
1602#endif /* WLDEBUG */
1603
1604/*
1605 * wlxmt:
1606 *
1607 * This routine fills in the appropriate registers and memory
1608 * locations on the WaveLAN board and starts the board off on
1609 * the transmit.
1610 *
1611 * input : board number of interest, and a pointer to the mbuf
1612 * output : board memory and registers are set for xfer and attention
1613 *
1614 */
1615static void
1616wlxmt(int unit, struct mbuf *m)
1617{
1618 register struct wl_softc *sc = WLSOFTC(unit);
1619 register u_short xmtdata_p = OFFSET_TBUF;
1620 register u_short xmtshort_p;
1621 struct mbuf *tm_p = m;
1622 register struct ether_header *eh_p = mtod(m, struct ether_header *);
1623 u_char *mb_p = mtod(m, u_char *) + sizeof(struct ether_header);
1624 u_short count = m->m_len - sizeof(struct ether_header);
1625 ac_t cb;
1626 u_short tbd_p = OFFSET_TBD;
1627 u_short len, clen = 0;
1628 short base = sc->base;
1629 int spin;
1630
1631#ifdef WLDEBUG
1632 if (sc->wl_if.if_flags & IFF_DEBUG)
1633 printf("wl%d: entered wlxmt()\n",unit);
1634#endif
1635
1636 cb.ac_status = 0;
1637 cb.ac_command = (AC_CW_EL|AC_TRANSMIT|AC_CW_I);
1638 cb.ac_link_offset = I82586NULL;
1639 outw(PIOR1(base), OFFSET_CU);
1640 outsw(PIOP1(base), &cb, 6/2);
1641 outw(PIOP1(base), OFFSET_TBD); /* cb.cmd.transmit.tbd_offset */
1642 outsw(PIOP1(base), eh_p->ether_dhost, WAVELAN_ADDR_SIZE/2);
1643 outw(PIOP1(base), eh_p->ether_type);
1644
1645#ifdef WLDEBUG
1646 if (sc->wl_if.if_flags & IFF_DEBUG) {
1647 if (xmt_debug) {
1648 printf("XMT mbuf: L%d @%p ", count, (void *)mb_p);
1649 printf("ether type %x\n", eh_p->ether_type);
1650 }
1651 }
1652#endif /* WLDEBUG */
1653 outw(PIOR0(base), OFFSET_TBD);
1654 outw(PIOP0(base), 0); /* act_count */
1655 outw(PIOR1(base), OFFSET_TBD + 4);
1656 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1657 outw(PIOP1(base), 0); /* buffer_base */
1658 for (;;) {
1659 if (count) {
1660 if (clen + count > WAVELAN_MTU)
1661 break;
1662 if (count & 1)
1663 len = count + 1;
1664 else
1665 len = count;
1666 outw(PIOR1(base), xmtdata_p);
1667 outsw(PIOP1(base), mb_p, len/2);
1668 clen += count;
1669 outw(PIOR0(base), tbd_p); /* address of act_count */
1670 outw(PIOP0(base), inw(PIOP0(base)) + count);
1671 xmtdata_p += len;
1672 if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1673 break;
1674 if (count & 1) {
1675 /* go to the next descriptor */
1676 outw(PIOR0(base), tbd_p + 2);
1677 tbd_p += sizeof (tbd_t);
1678 outw(PIOP0(base), tbd_p); /* next_tbd_offset */
1679 outw(PIOR0(base), tbd_p);
1680 outw(PIOP0(base), 0); /* act_count */
1681 outw(PIOR1(base), tbd_p + 4);
1682 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1683 outw(PIOP1(base), 0); /* buffer_base */
1684 /* at the end -> coallesce remaining mbufs */
1685 if (tbd_p == OFFSET_TBD + (N_TBD-1) * sizeof (tbd_t)) {
1686 wlsftwsleaze(&count, &mb_p, &tm_p, unit);
1687 continue;
1688 }
1689 /* next mbuf short -> coallesce as needed */
1690 if ( (tm_p->m_next == (struct mbuf *) 0) ||
1691#define HDW_THRESHOLD 55
1692 tm_p->m_len > HDW_THRESHOLD)
1693 /* ok */;
1694 else {
1695 wlhdwsleaze(&count, &mb_p, &tm_p, unit);
1696 continue;
1697 }
1698 }
1699 } else if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1700 break;
1701 count = tm_p->m_len;
1702 mb_p = mtod(tm_p, u_char *);
1703#ifdef WLDEBUG
1704 if (sc->wl_if.if_flags & IFF_DEBUG)
1705 if (xmt_debug)
1706 printf("mbuf+ L%d @%p ", count, (void *)mb_p);
1707#endif /* WLDEBUG */
1708 }
1709#ifdef WLDEBUG
1710 if (sc->wl_if.if_flags & IFF_DEBUG)
1711 if (xmt_debug)
1712 printf("CLEN = %d\n", clen);
1713#endif /* WLDEBUG */
1714 outw(PIOR0(base), tbd_p);
1715 if (clen < ETHERMIN) {
1716 outw(PIOP0(base), inw(PIOP0(base)) + ETHERMIN - clen);
1717 outw(PIOR1(base), xmtdata_p);
1718 for (xmtshort_p = xmtdata_p; clen < ETHERMIN; clen += 2)
1719 outw(PIOP1(base), 0);
1720 }
1721 outw(PIOP0(base), inw(PIOP0(base)) | TBD_SW_EOF);
1722 outw(PIOR0(base), tbd_p + 2);
1723 outw(PIOP0(base), I82586NULL);
1724#ifdef WLDEBUG
1725 if (sc->wl_if.if_flags & IFF_DEBUG) {
1726 if (xmt_debug) {
1727 wltbd(unit);
1728 printf("\n");
1729 }
1730 }
1731#endif /* WLDEBUG */
1732
1733 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
1734 /*
1735 * wait for 586 to clear previous command, complain if it takes
1736 * too long
1737 */
1738 for (spin = 1;;spin = (spin + 1) % 10000) {
1739 if (inw(PIOP0(base)) == 0) { /* it's done, we can go */
1740 break;
1741 }
1742 if ((spin == 0) && xmt_watch) { /* not waking up, and we care */
1743 printf("wl%d: slow accepting xmit\n",unit);
1744 }
1745 }
1746 outw(PIOP0(base), SCB_CU_STRT); /* new command */
1747 SET_CHAN_ATTN(unit);
1748
1749 m_freem(m);
1750
1751 /* XXX
1752 * Pause to avoid transmit overrun problems.
1753 * The required delay tends to vary with platform type, and may be
1754 * related to interrupt loss.
1755 */
1756 if (wl_xmit_delay) {
1757 DELAY(wl_xmit_delay);
1758 }
1759 return;
1760}
1761
1762/*
1763 * wlbldru:
1764 *
1765 * This function builds the linear linked lists of fd's and
1766 * rbd's. Based on page 4-32 of 1986 Intel microcom handbook.
1767 *
1768 */
1769static u_short
1770wlbldru(int unit)
1771{
1772 register struct wl_softc *sc = WLSOFTC(unit);
1773 short base = sc->base;
1774 fd_t fd;
1775 rbd_t rbd;
1776 u_short fd_p = OFFSET_RU;
1777 u_short rbd_p = OFFSET_RBD;
1778 int i;
1779
1780 sc->begin_fd = fd_p;
1781 for (i = 0; i < N_FD; i++) {
1782 fd.status = 0;
1783 fd.command = 0;
1784 fd.link_offset = fd_p + sizeof(fd_t);
1785 fd.rbd_offset = I82586NULL;
1786 outw(PIOR1(base), fd_p);
1787 outsw(PIOP1(base), &fd, 8/2);
1788 fd_p = fd.link_offset;
1789 }
1790 fd_p -= sizeof(fd_t);
1791 sc->end_fd = fd_p;
1792 outw(PIOR1(base), fd_p + 2);
1793 outw(PIOP1(base), AC_CW_EL); /* command */
1794 outw(PIOP1(base), I82586NULL); /* link_offset */
1795 fd_p = OFFSET_RU;
1796
1797 outw(PIOR0(base), fd_p + 6); /* address of rbd_offset */
1798 outw(PIOP0(base), rbd_p);
1799 outw(PIOR1(base), rbd_p);
1800 for (i = 0; i < N_RBD; i++) {
1801 rbd.status = 0;
1802 rbd.buffer_addr = rbd_p + sizeof(rbd_t) + 2;
1803 rbd.buffer_base = 0;
1804 rbd.size = RCVBUFSIZE;
1805 if (i != N_RBD-1) {
1806 rbd_p += sizeof(ru_t);
1807 rbd.next_rbd_offset = rbd_p;
1808 } else {
1809 rbd.next_rbd_offset = I82586NULL;
1810 rbd.size |= AC_CW_EL;
1811 sc->end_rbd = rbd_p;
1812 }
1813 outsw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1814 outw(PIOR1(base), rbd_p);
1815 }
1816 return sc->begin_fd;
1817}
1818
1819/*
1820 * wlrustrt:
1821 *
1822 * This routine starts the receive unit running. First checks if the
1823 * board is actually ready, then the board is instructed to receive
1824 * packets again.
1825 *
1826 */
1827static void
1828wlrustrt(int unit)
1829{
1830 register struct wl_softc *sc = WLSOFTC(unit);
1831 short base = sc->base;
1832 u_short rfa;
1833
1834#ifdef WLDEBUG
1835 if (sc->wl_if.if_flags & IFF_DEBUG)
1836 printf("wl%d: entered wlrustrt()\n",unit);
1837#endif
1838 outw(PIOR0(base), OFFSET_SCB);
1839 if (inw(PIOP0(base)) & SCB_RUS_READY){
1840 printf("wlrustrt: RUS_READY\n");
1841 return;
1842 }
1843
1844 outw(PIOR0(base), OFFSET_SCB + 2);
1845 outw(PIOP0(base), SCB_RU_STRT); /* command */
1846 rfa = wlbldru(unit);
1847 outw(PIOR0(base), OFFSET_SCB + 6); /* address of scb_rfa_offset */
1848 outw(PIOP0(base), rfa);
1849
1850 SET_CHAN_ATTN(unit);
1851 return;
1852}
1853
1854/*
1855 * wldiag:
1856 *
1857 * This routine does a 586 op-code number 7, and obtains the
1858 * diagnose status for the WaveLAN.
1859 *
1860 */
1861static int
1862wldiag(int unit)
1863{
1864 register struct wl_softc *sc = WLSOFTC(unit);
1865 short base = sc->base;
1866 short status;
1867
1868#ifdef WLDEBUG
1869 if (sc->wl_if.if_flags & IFF_DEBUG)
1870 printf("wl%d: entered wldiag()\n",unit);
1871#endif
1872 outw(PIOR0(base), OFFSET_SCB);
1873 status = inw(PIOP0(base));
1874 if (status & SCB_SW_INT) {
1875 /* state is 2000 which seems ok
1876 printf("wl%d diag(): unexpected initial state %\n",
1877 unit, inw(PIOP0(base)));
1878 */
1879 wlack(unit);
1880 }
1881 outw(PIOR1(base), OFFSET_CU);
1882 outw(PIOP1(base), 0); /* ac_status */
1883 outw(PIOP1(base), AC_DIAGNOSE|AC_CW_EL);/* ac_command */
1884 if (wlcmd(unit, "diag()") == 0)
1885 return 0;
1886 outw(PIOR0(base), OFFSET_CU);
1887 if (inw(PIOP0(base)) & 0x0800) {
1888 printf("wl%d: i82586 Self Test failed!\n", unit);
1889 return 0;
1890 }
1891 return TRUE;
1892}
1893
1894/*
1895 * wlconfig:
1896 *
1897 * This routine does a standard config of the WaveLAN board.
1898 *
1899 */
1900static int
1901wlconfig(int unit)
1902{
1903 configure_t configure;
1904 register struct wl_softc *sc = WLSOFTC(unit);
1905 short base = sc->base;
1906
1907#if MULTICAST
1908 struct ifmultiaddr *ifma;
1909 u_char *addrp;
1910 int cnt = 0;
1911#endif /* MULTICAST */
1912
1913#ifdef WLDEBUG
1914 if (sc->wl_if.if_flags & IFF_DEBUG)
1915 printf("wl%d: entered wlconfig()\n",unit);
1916#endif
1917 outw(PIOR0(base), OFFSET_SCB);
1918 if (inw(PIOP0(base)) & SCB_SW_INT) {
1919 /*
1920 printf("wl%d config(): unexpected initial state %x\n",
1921 unit, inw(PIOP0(base)));
1922 */
1923 }
1924 wlack(unit);
1925
1926 outw(PIOR1(base), OFFSET_CU);
1927 outw(PIOP1(base), 0); /* ac_status */
1928 outw(PIOP1(base), AC_CONFIGURE|AC_CW_EL); /* ac_command */
1929
1930/* jrb hack */
1931 configure.fifolim_bytecnt = 0x080c;
1932 configure.addrlen_mode = 0x0600;
1933 configure.linprio_interframe = 0x2060;
1934 configure.slot_time = 0xf200;
1935 configure.hardware = 0x0008; /* tx even w/o CD */
1936 configure.min_frame_len = 0x0040;
1937#if 0
1938 /* This is the configuration block suggested by Marc Meertens
1939 * <mmeerten@obelix.utrecht.NCR.COM> in an e-mail message to John
1940 * Ioannidis on 10 Nov 92.
1941 */
1942 configure.fifolim_bytecnt = 0x040c;
1943 configure.addrlen_mode = 0x0600;
1944 configure.linprio_interframe = 0x2060;
1945 configure.slot_time = 0xf000;
1946 configure.hardware = 0x0008; /* tx even w/o CD */
1947 configure.min_frame_len = 0x0040;
1948#else
1949 /*
1950 * below is the default board configuration from p2-28 from 586 book
1951 */
1952 configure.fifolim_bytecnt = 0x080c;
1953 configure.addrlen_mode = 0x2600;
1954 configure.linprio_interframe = 0x7820; /* IFS=120, ACS=2 */
1955 configure.slot_time = 0xf00c; /* slottime=12 */
1956 configure.hardware = 0x0008; /* tx even w/o CD */
1957 configure.min_frame_len = 0x0040;
1958#endif
1959 if (sc->mode & (MOD_PROM | MOD_ENAL))
1960 configure.hardware |= 1;
1961 outw(PIOR1(base), OFFSET_CU + 6);
1962 outsw(PIOP1(base), &configure, sizeof(configure_t)/2);
1963
1964 if (wlcmd(unit, "config()-configure") == 0)
1965 return 0;
1966#if MULTICAST
1967 outw(PIOR1(base), OFFSET_CU);
1968 outw(PIOP1(base), 0); /* ac_status */
1969 outw(PIOP1(base), AC_MCSETUP|AC_CW_EL); /* ac_command */
1970 outw(PIOR1(base), OFFSET_CU + 8);
1971 TAILQ_FOREACH(ifma, &sc->wl_if.if_multiaddrs, ifma_link) {
1972 if (ifma->ifma_addr->sa_family != AF_LINK)
1973 continue;
1974
1975 addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
1976 outw(PIOP1(base), addrp[0] + (addrp[1] << 8));
1977 outw(PIOP1(base), addrp[2] + (addrp[3] << 8));
1978 outw(PIOP1(base), addrp[4] + (addrp[5] << 8));
1979 ++cnt;
1980 }
1981 outw(PIOR1(base), OFFSET_CU + 6); /* mc-cnt */
1982 outw(PIOP1(base), cnt * WAVELAN_ADDR_SIZE);
1983 if (wlcmd(unit, "config()-mcaddress") == 0)
1984 return 0;
1985#endif /* MULTICAST */
1986
1987 outw(PIOR1(base), OFFSET_CU);
1988 outw(PIOP1(base), 0); /* ac_status */
1989 outw(PIOP1(base), AC_IASETUP|AC_CW_EL); /* ac_command */
1990 outw(PIOR1(base), OFFSET_CU + 6);
1991 outsw(PIOP1(base), sc->wl_addr, WAVELAN_ADDR_SIZE/2);
1992
1993 if (wlcmd(unit, "config()-address") == 0)
1994 return(0);
1995
1996 wlinitmmc(unit);
1997
1998 return(1);
1999}
2000
2001/*
2002 * wlcmd:
2003 *
2004 * Set channel attention bit and busy wait until command has
2005 * completed. Then acknowledge the command completion.
2006 */
2007static int
2008wlcmd(int unit, char *str)
2009{
2010 register struct wl_softc *sc = WLSOFTC(unit);
2011 short base = sc->base;
2012 int i;
2013
2014 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
2015 outw(PIOP0(base), SCB_CU_STRT);
2016
2017 SET_CHAN_ATTN(unit);
2018
2019 outw(PIOR0(base), OFFSET_CU);
2020 for (i = 0; i < 0xffff; i++)
2021 if (inw(PIOP0(base)) & AC_SW_C)
2022 break;
2023 if (i == 0xffff || !(inw(PIOP0(base)) & AC_SW_OK)) {
2024 printf("wl%d: %s failed; status = %d, inw = %x, outw = %x\n",
2025 unit, str, inw(PIOP0(base)) & AC_SW_OK, inw(PIOP0(base)), inw(PIOR0(base)));
2026 outw(PIOR0(base), OFFSET_SCB);
2027 printf("scb_status %x\n", inw(PIOP0(base)));
2028 outw(PIOR0(base), OFFSET_SCB+2);
2029 printf("scb_command %x\n", inw(PIOP0(base)));
2030 outw(PIOR0(base), OFFSET_SCB+4);
2031 printf("scb_cbl %x\n", inw(PIOP0(base)));
2032 outw(PIOR0(base), OFFSET_CU+2);
2033 printf("cu_cmd %x\n", inw(PIOP0(base)));
2034 return(0);
2035 }
2036
2037 outw(PIOR0(base), OFFSET_SCB);
2038 if ((inw(PIOP0(base)) & SCB_SW_INT) && (inw(PIOP0(base)) != SCB_SW_CNA)) {
2039 /*
2040 printf("wl%d %s: unexpected final state %x\n",
2041 unit, str, inw(PIOP0(base)));
2042 */
2043 }
2044 wlack(unit);
2045 return(TRUE);
2046}
2047
2048/*
2049 * wlack: if the 82596 wants attention because it has finished
2050 * sending or receiving a packet, acknowledge its desire and
2051 * return bits indicating the kind of attention. wlack() returns
2052 * these bits so that the caller can service exactly the
2053 * conditions that wlack() acknowledged.
2054 */
2055static int
2056wlack(int unit)
2057{
2058 int i;
2059 register u_short cmd;
2060 register struct wl_softc *sc = WLSOFTC(unit);
2061 short base = sc->base;
2062
2063 outw(PIOR1(base), OFFSET_SCB);
2064 if (!(cmd = (inw(PIOP1(base)) & SCB_SW_INT)))
2065 return(0);
2066#ifdef WLDEBUG
2067 if (sc->wl_if.if_flags & IFF_DEBUG)
2068 printf("wl%d: doing a wlack()\n",unit);
2069#endif
2070 outw(PIOP1(base), cmd);
2071 SET_CHAN_ATTN(unit);
2072 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
2073 for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); )
2074 continue;
2075 if (i < 1)
2076 printf("wl%d wlack(): board not accepting command.\n", unit);
2077 return(cmd);
2078}
2079
2080#ifdef WLDEBUG
2081static void
2082wltbd(int unit)
2083{
2084 register struct wl_softc *sc = WLSOFTC(unit);
2085 short base = sc->base;
2086 u_short tbd_p = OFFSET_TBD;
2087 tbd_t tbd;
2088 int i = 0;
2089 int sum = 0;
2090
2091 for (;;) {
2092 outw(PIOR1(base), tbd_p);
2093 insw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
2094 sum += (tbd.act_count & ~TBD_SW_EOF);
2095 printf("%d: addr %x, count %d (%d), next %x, base %x\n",
2096 i++, tbd.buffer_addr,
2097 (tbd.act_count & ~TBD_SW_EOF), sum,
2098 tbd.next_tbd_offset, tbd.buffer_base);
2099 if (tbd.act_count & TBD_SW_EOF)
2100 break;
2101 tbd_p = tbd.next_tbd_offset;
2102 }
2103}
2104#endif
2105
2106static void
2107wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2108{
2109 struct mbuf *tm_p = *tm_pp;
2110 u_char *mb_p = *mb_pp;
2111 u_short count = 0;
2112 u_char *cp;
2113 int len;
2114
2115 /*
2116 * can we get a run that will be coallesced or
2117 * that terminates before breaking
2118 */
2119 do {
2120 count += tm_p->m_len;
2121 if (tm_p->m_len & 1)
2122 break;
2123 } while ((tm_p = tm_p->m_next) != (struct mbuf *)0);
2124 if ( (tm_p == (struct mbuf *)0) ||
2125 count > HDW_THRESHOLD) {
2126 *countp = (*tm_pp)->m_len;
2127 *mb_pp = mtod((*tm_pp), u_char *);
2128 return;
2129 }
2130
2131 /* we need to copy */
2132 tm_p = *tm_pp;
2133 mb_p = *mb_pp;
2134 count = 0;
2135 cp = (u_char *) t_packet;
2136 for (;;) {
2137 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2138 count += len;
2139 if (count > HDW_THRESHOLD)
2140 break;
2141 cp += len;
2142 if (tm_p->m_next == (struct mbuf *)0)
2143 break;
2144 tm_p = tm_p->m_next;
2145 }
2146 *countp = count;
2147 *mb_pp = (u_char *) t_packet;
2148 *tm_pp = tm_p;
2149 return;
2150}
2151
2152
2153static void
2154wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2155{
2156 struct mbuf *tm_p = *tm_pp;
2157 u_short count = 0;
2158 u_char *cp = (u_char *) t_packet;
2159 int len;
2160
2161 /* we need to copy */
2162 for (;;) {
2163 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2164 count += len;
2165 cp += len;
2166 if (tm_p->m_next == (struct mbuf *)0)
2167 break;
2168 tm_p = tm_p->m_next;
2169 }
2170
2171 *countp = count;
2172 *mb_pp = (u_char *) t_packet;
2173 *tm_pp = tm_p;
2174 return;
2175}
2176
2177static void
2178wlmmcstat(int unit)
2179{
2180 register struct wl_softc *sc = WLSOFTC(unit);
2181 short base = sc->base;
2182 u_short tmp;
2183
2184 printf("wl%d: DCE_STATUS: 0x%x, ", unit,
2185 wlmmcread(base,MMC_DCE_STATUS) & 0x0f);
2186 tmp = wlmmcread(base,MMC_CORRECT_NWID_H) << 8;
2187 tmp |= wlmmcread(base,MMC_CORRECT_NWID_L);
2188 printf("Correct NWID's: %d, ", tmp);
2189 tmp = wlmmcread(base,MMC_WRONG_NWID_H) << 8;
2190 tmp |= wlmmcread(base,MMC_WRONG_NWID_L);
2191 printf("Wrong NWID's: %d\n", tmp);
2192 printf("THR_PRE_SET: 0x%x, ", wlmmcread(base,MMC_THR_PRE_SET));
2193 printf("SIGNAL_LVL: %d, SILENCE_LVL: %d\n",
2194 wlmmcread(base,MMC_SIGNAL_LVL),
2195 wlmmcread(base,MMC_SILENCE_LVL));
2196 printf("SIGN_QUAL: 0x%x, NETW_ID: %x:%x, DES: %d\n",
2197 wlmmcread(base,MMC_SIGN_QUAL),
2198 wlmmcread(base,MMC_NETW_ID_H),
2199 wlmmcread(base,MMC_NETW_ID_L),
2200 wlmmcread(base,MMC_DES_AVAIL));
2201}
2202
2203static u_short
2204wlmmcread(u_int base, u_short reg)
2205{
2206 while (inw(HASR(base)) & HASR_MMC_BUSY)
2207 continue;
2208 outw(MMCR(base),reg << 1);
2209 while (inw(HASR(base)) & HASR_MMC_BUSY)
2210 continue;
2211 return (u_short)inw(MMCR(base)) >> 8;
2212}
2213
2214static void
2215getsnr(int unit)
2216{
2217 MMC_WRITE(MMC_FREEZE,1);
2218 /*
2219 * SNR retrieval procedure :
2220 *
2221 * read signal level : wlmmcread(base, MMC_SIGNAL_LVL);
2222 * read silence level : wlmmcread(base, MMC_SILENCE_LVL);
2223 */
2224 MMC_WRITE(MMC_FREEZE,0);
2225 /*
2226 * SNR is signal:silence ratio.
2227 */
2228}
2229
2230/*
2231** wlgetpsa
2232**
2233** Reads the psa for the wavelan at (base) into (buf)
2234*/
2235static void
2236wlgetpsa(int base, u_char *buf)
2237{
2238 int i;
2239
2240 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2241 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2242
2243 for (i = 0; i < 0x40; i++) {
2244 outw(PIOR2(base), i);
2245 buf[i] = inb(PIOP2(base));
2246 }
2247 PCMD(base, HACR_DEFAULT);
2248 PCMD(base, HACR_DEFAULT);
2249}
2250
2251/*
2252** wlsetpsa
2253**
2254** Writes the psa for wavelan (unit) from the softc back to the
2255** board. Updates the CRC and sets the CRC OK flag.
2256**
2257** Do not call this when the board is operating, as it doesn't
2258** preserve the hacr.
2259*/
2260static void
2261wlsetpsa(int unit)
2262{
2263 register struct wl_softc *sc = WLSOFTC(unit);
2264 short base = sc->base;
2265 int i, oldpri;
2266 u_short crc;
2267
2268 crc = wlpsacrc(sc->psa); /* calculate CRC of PSA */
2269 sc->psa[WLPSA_CRCLOW] = crc & 0xff;
2270 sc->psa[WLPSA_CRCHIGH] = (crc >> 8) & 0xff;
2271 sc->psa[WLPSA_CRCOK] = 0x55; /* default to 'bad' until programming complete */
2272
2273 oldpri = splimp(); /* ick, long pause */
2274
2275 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2276 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2277
2278 for (i = 0; i < 0x40; i++) {
2279 DELAY(DELAYCONST);
2280 outw(PIOR2(base),i); /* write param memory */
2281 DELAY(DELAYCONST);
2282 outb(PIOP2(base), sc->psa[i]);
2283 }
2284 DELAY(DELAYCONST);
2285 outw(PIOR2(base),WLPSA_CRCOK); /* update CRC flag*/
2286 DELAY(DELAYCONST);
2287 sc->psa[WLPSA_CRCOK] = 0xaa; /* OK now */
2288 outb(PIOP2(base), 0xaa); /* all OK */
2289 DELAY(DELAYCONST);
2290
2291 PCMD(base, HACR_DEFAULT);
2292 PCMD(base, HACR_DEFAULT);
2293
2294 splx(oldpri);
2295}
2296
2297/*
2298** CRC routine provided by Christopher Giordano <cgiordan@gdeb.com>,
2299** from original code by Tomi Mikkonen (tomitm@remedy.fi)
2300*/
2301
2302static u_int crc16_table[16] = {
2303 0x0000, 0xCC01, 0xD801, 0x1400,
2304 0xF001, 0x3C00, 0x2800, 0xE401,
2305 0xA001, 0x6C00, 0x7800, 0xB401,
2306 0x5000, 0x9C01, 0x8801, 0x4400
2307};
2308
2309static u_short
2310wlpsacrc(u_char *buf)
2311{
2312 u_short crc = 0;
2313 int i, r1;
2314
2315 for (i = 0; i < 0x3d; i++, buf++) {
2316 /* lower 4 bits */
2317 r1 = crc16_table[crc & 0xF];
2318 crc = (crc >> 4) & 0x0FFF;
2319 crc = crc ^ r1 ^ crc16_table[*buf & 0xF];
2320
2321 /* upper 4 bits */
2322 r1 = crc16_table[crc & 0xF];
2323 crc = (crc >> 4) & 0x0FFF;
2324 crc = crc ^ r1 ^ crc16_table[(*buf >> 4) & 0xF];
2325 }
2326 return(crc);
2327}
2328#ifdef WLCACHE
2329
2330/*
2331 * wl_cache_store
2332 *
2333 * take input packet and cache various radio hw characteristics
2334 * indexed by MAC address.
2335 *
2336 * Some things to think about:
2337 * note that no space is malloced.
2338 * We might hash the mac address if the cache were bigger.
2339 * It is not clear that the cache is big enough.
2340 * It is also not clear how big it should be.
2341 * The cache is IP-specific. We don't care about that as
2342 * we want it to be IP-specific.
2343 * The last N recv. packets are saved. This will tend
2344 * to reward agents and mobile hosts that beacon.
2345 * That is probably fine for mobile ip.
2346 */
2347
2348/* globals for wavelan signal strength cache */
2349/* this should go into softc structure above.
2350*/
2351
2352/* set true if you want to limit cache items to broadcast/mcast
2353 * only packets (not unicast)
2354 */
2355static int wl_cache_mcastonly = 1;
2356SYSCTL_INT(_machdep, OID_AUTO, wl_cache_mcastonly, CTLFLAG_RW,
2357 &wl_cache_mcastonly, 0, "");
2358
2359/* set true if you want to limit cache items to IP packets only
2360*/
2361static int wl_cache_iponly = 1;
2362SYSCTL_INT(_machdep, OID_AUTO, wl_cache_iponly, CTLFLAG_RW,
2363 &wl_cache_iponly, 0, "");
2364
2365/* zero out the cache
2366*/
2367static void
2368wl_cache_zero(int unit)
2369{
2370 register struct wl_softc *sc = WLSOFTC(unit);
2371
2372 bzero(&sc->w_sigcache[0], sizeof(struct w_sigcache) * MAXCACHEITEMS);
2373 sc->w_sigitems = 0;
2374 sc->w_nextcache = 0;
2375 sc->w_wrapindex = 0;
2376}
2377
2378/* store hw signal info in cache.
2379 * index is MAC address, but an ip src gets stored too
2380 * There are two filters here controllable via sysctl:
2381 * throw out unicast (on by default, but can be turned off)
2382 * throw out non-ip (on by default, but can be turned off)
2383 */
2384static
2385void wl_cache_store (int unit, int base, struct ether_header *eh,
2386 struct mbuf *m)
2387{
2388 struct ip *ip = NULL; /* Avoid GCC warning */
2389 int i;
2390 int signal, silence;
2391 int w_insertcache; /* computed index for cache entry storage */
2392 register struct wl_softc *sc = WLSOFTC(unit);
2393 int ipflag = wl_cache_iponly;
2394
2395 /* filters:
2396 * 1. ip only
2397 * 2. configurable filter to throw out unicast packets,
2398 * keep multicast only.
2399 */
2400
2401#ifdef INET
2402 /* reject if not IP packet
2403 */
2404 if ( wl_cache_iponly && (ntohs(eh->ether_type) != 0x800)) {
2405 return;
2406 }
2407
2408 /* check if broadcast or multicast packet. we toss
2409 * unicast packets
2410 */
2411 if (wl_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
2412 return;
2413 }
2414
2415 /* find the ip header. we want to store the ip_src
2416 * address. use the mtod macro(in mbuf.h)
2417 * to typecast m to struct ip *
2418 */
2419 if (ipflag) {
2420 ip = mtod(m, struct ip *);
2421 }
2422
2423 /* do a linear search for a matching MAC address
2424 * in the cache table
2425 * . MAC address is 6 bytes,
2426 * . var w_nextcache holds total number of entries already cached
2427 */
2428 for (i = 0; i < sc->w_nextcache; i++) {
2429 if (! bcmp(eh->ether_shost, sc->w_sigcache[i].macsrc, 6 )) {
2430 /* Match!,
2431 * so we already have this entry,
2432 * update the data, and LRU age
2433 */
2434 break;
2435 }
2436 }
2437
2438 /* did we find a matching mac address?
2439 * if yes, then overwrite a previously existing cache entry
2440 */
2441 if (i < sc->w_nextcache ) {
2442 w_insertcache = i;
2443 }
2444 /* else, have a new address entry,so
2445 * add this new entry,
2446 * if table full, then we need to replace entry
2447 */
2448 else {
2449
2450 /* check for space in cache table
2451 * note: w_nextcache also holds number of entries
2452 * added in the cache table
2453 */
2454 if ( sc->w_nextcache < MAXCACHEITEMS ) {
2455 w_insertcache = sc->w_nextcache;
2456 sc->w_nextcache++;
2457 sc->w_sigitems = sc->w_nextcache;
2458 }
2459 /* no space found, so simply wrap with wrap index
2460 * and "zap" the next entry
2461 */
2462 else {
2463 if (sc->w_wrapindex == MAXCACHEITEMS) {
2464 sc->w_wrapindex = 0;
2465 }
2466 w_insertcache = sc->w_wrapindex++;
2467 }
2468 }
2469
2470 /* invariant: w_insertcache now points at some slot
2471 * in cache.
2472 */
2473 if (w_insertcache < 0 || w_insertcache >= MAXCACHEITEMS) {
2474 log(LOG_ERR,
2475 "wl_cache_store, bad index: %d of [0..%d], gross cache error\n",
2476 w_insertcache, MAXCACHEITEMS);
2477 return;
2478 }
2479
2480 /* store items in cache
2481 * .ipsrc
2482 * .macsrc
2483 * .signal (0..63) ,silence (0..63) ,quality (0..15)
2484 */
2485 if (ipflag) {
2486 sc->w_sigcache[w_insertcache].ipsrc = ip->ip_src.s_addr;
2487 }
2488 bcopy( eh->ether_shost, sc->w_sigcache[w_insertcache].macsrc, 6);
2489 signal = sc->w_sigcache[w_insertcache].signal = wlmmcread(base, MMC_SIGNAL_LVL) & 0x3f;
2490 silence = sc->w_sigcache[w_insertcache].silence = wlmmcread(base, MMC_SILENCE_LVL) & 0x3f;
2491 sc->w_sigcache[w_insertcache].quality = wlmmcread(base, MMC_SIGN_QUAL) & 0x0f;
2492 if (signal > 0)
2493 sc->w_sigcache[w_insertcache].snr =
2494 signal - silence;
2495 else
2496 sc->w_sigcache[w_insertcache].snr = 0;
2497#endif /* INET */
2498
2499}
2500#endif /* WLCACHE */
919 * output : the packet is put into an mbuf chain, and passed up
920 * assumes : if any errors occur, packet is "dropped on the floor"
921 *
922 */
923static int
924wlread(int unit, u_short fd_p)
925{
926 register struct wl_softc *sc = WLSOFTC(unit);
927 register struct ifnet *ifp = &sc->wl_if;
928 short base = sc->base;
929 fd_t fd;
930 struct ether_header *eh;
931 struct mbuf *m;
932 rbd_t rbd;
933 u_char *mb_p;
934 u_short mlen, len;
935 u_short bytes_in_msg, bytes_in_mbuf, bytes;
936
937
938#ifdef WLDEBUG
939 if (sc->wl_if.if_flags & IFF_DEBUG)
940 printf("wl%d: entered wlread()\n", unit);
941#endif
942 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
943 printf("wl%d read(): board is not running.\n", unit);
944 sc->hacr &= ~HACR_INTRON;
945 CMD(unit); /* turn off interrupts */
946 }
947
948 /*
949 * Collect message size.
950 */
951 outw(PIOR1(base), fd_p);
952 insw(PIOP1(base), &fd, sizeof(fd_t)/2);
953 if (fd.rbd_offset == I82586NULL) {
954 if (wlhwrst(unit) != TRUE) {
955 sc->hacr &= ~HACR_INTRON;
956 CMD(unit); /* turn off interrupts */
957 printf("wl%d read(): hwrst trouble.\n", unit);
958 }
959 return 0;
960 }
961
962 outw(PIOR1(base), fd.rbd_offset);
963 insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
964 bytes_in_msg = rbd.status & RBD_SW_COUNT;
965
966 /*
967 * Allocate a cluster'd mbuf to receive the packet.
968 */
969 m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
970 if (m == NULL) {
971 if (wlhwrst(unit) != TRUE) {
972 sc->hacr &= ~HACR_INTRON;
973 CMD(unit); /* turn off interrupts */
974 printf("wl%d read(): hwrst trouble.\n", unit);
975 }
976 return 0;
977 }
978 m->m_pkthdr.len = m->m_len = MCLBYTES;
979 m_adj(m, ETHER_ALIGN); /* align IP header */
980
981 /*
982 * Collect the message data.
983 */
984 mlen = 0;
985 mb_p = mtod(m, u_char *);
986 bytes_in_mbuf = MCLBYTES;
987 bytes = min(bytes_in_mbuf, bytes_in_msg);
988 for (;;) {
989 if (bytes & 1) {
990 len = bytes + 1;
991 } else {
992 len = bytes;
993 }
994 outw(PIOR1(base), rbd.buffer_addr);
995 insw(PIOP1(base), mb_p, len/2);
996 mlen += bytes;
997
998 if (bytes > bytes_in_mbuf) {
999 /* XXX something wrong, a packet should fit in 1 cluster */
1000 m_freem(m);
1001 printf("wl%d read(): packet too large (%u > %u)\n",
1002 unit, bytes, bytes_in_mbuf);
1003 if (wlhwrst(unit) != TRUE) {
1004 sc->hacr &= ~HACR_INTRON;
1005 CMD(unit); /* turn off interrupts */
1006 printf("wl%d read(): hwrst trouble.\n", unit);
1007 }
1008 return 0;
1009 }
1010 mb_p += bytes;
1011 bytes_in_msg -= bytes;
1012 if (bytes_in_msg == 0) {
1013 if (rbd.status & RBD_SW_EOF || rbd.next_rbd_offset == I82586NULL) {
1014 break;
1015 }
1016 outw(PIOR1(base), rbd.next_rbd_offset);
1017 insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1018 bytes_in_msg = rbd.status & RBD_SW_COUNT;
1019 } else {
1020 rbd.buffer_addr += bytes;
1021 }
1022
1023 bytes = min(bytes_in_mbuf, bytes_in_msg);
1024 }
1025
1026 m->m_pkthdr.len = m->m_len = mlen;
1027 m->m_pkthdr.rcvif = ifp;
1028
1029 /*
1030 * If hw is in promiscuous mode (note that I said hardware, not if
1031 * IFF_PROMISC is set in ifnet flags), then if this is a unicast
1032 * packet and the MAC dst is not us, drop it. This check in normally
1033 * inside ether_input(), but IFF_MULTI causes hw promisc without
1034 * a bpf listener, so this is wrong.
1035 * Greg Troxel <gdt@ir.bbn.com>, 1998-08-07
1036 */
1037 /*
1038 * TBD: also discard packets where NWID does not match.
1039 * However, there does not appear to be a way to read the nwid
1040 * for a received packet. -gdt 1998-08-07
1041 */
1042 /* XXX verify mbuf length */
1043 eh = mtod(m, struct ether_header *);
1044 if (
1045#ifdef WL_USE_IFNET_PROMISC_CHECK /* not defined */
1046 (sc->wl_ac.ac_if.if_flags & (IFF_PROMISC|IFF_ALLMULTI))
1047#else
1048 /* hw is in promisc mode if this is true */
1049 (sc->mode & (MOD_PROM | MOD_ENAL))
1050#endif
1051 &&
1052 (eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
1053 bcmp(eh->ether_dhost, sc->wl_ac.ac_enaddr,
1054 sizeof(eh->ether_dhost)) != 0 ) {
1055 m_freem(m);
1056 return 1;
1057 }
1058
1059#ifdef WLDEBUG
1060 if (sc->wl_if.if_flags & IFF_DEBUG)
1061 printf("wl%d: wlrecv %u bytes\n", unit, mlen);
1062#endif
1063
1064#ifdef WLCACHE
1065 wl_cache_store(unit, base, eh, m);
1066#endif
1067
1068 /*
1069 * received packet is now in a chain of mbuf's. next step is
1070 * to pass the packet upwards.
1071 */
1072 (*ifp->if_input)(ifp, m);
1073 return 1;
1074}
1075
1076/*
1077 * wlioctl:
1078 *
1079 * This routine processes an ioctl request from the "if" layer
1080 * above.
1081 *
1082 * input : pointer the appropriate "if" struct, command, and data
1083 * output : based on command appropriate action is taken on the
1084 * WaveLAN board(s) or related structures
1085 * return : error is returned containing exit conditions
1086 *
1087 */
1088static int
1089wlioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1090{
1091 register struct ifreq *ifr = (struct ifreq *)data;
1092 int unit = ifp->if_unit;
1093 register struct wl_softc *sc = WLSOFTC(unit);
1094 short base = sc->base;
1095 short mode = 0;
1096 int opri, error = 0;
1097 struct thread *td = curthread; /* XXX */
1098 int irq, irqval, i, isroot;
1099 caddr_t up;
1100#ifdef WLCACHE
1101 int size;
1102 char * cpt;
1103#endif
1104
1105#ifdef WLDEBUG
1106 if (sc->wl_if.if_flags & IFF_DEBUG)
1107 printf("wl%d: entered wlioctl()\n",unit);
1108#endif
1109 opri = splimp();
1110 switch (cmd) {
1111 case SIOCSIFFLAGS:
1112 if (ifp->if_flags & IFF_ALLMULTI) {
1113 mode |= MOD_ENAL;
1114 }
1115 if (ifp->if_flags & IFF_PROMISC) {
1116 mode |= MOD_PROM;
1117 }
1118 if (ifp->if_flags & IFF_LINK0) {
1119 mode |= MOD_PROM;
1120 }
1121 /*
1122 * force a complete reset if the recieve multicast/
1123 * promiscuous mode changes so that these take
1124 * effect immediately.
1125 *
1126 */
1127 if (sc->mode != mode) {
1128 sc->mode = mode;
1129 if (sc->flags & DSF_RUNNING) {
1130 sc->flags &= ~DSF_RUNNING;
1131 wlinit(sc);
1132 }
1133 }
1134 /* if interface is marked DOWN and still running then
1135 * stop it.
1136 */
1137 if ((ifp->if_flags & IFF_UP) == 0 && sc->flags & DSF_RUNNING) {
1138 printf("wl%d ioctl(): board is not running\n", unit);
1139 sc->flags &= ~DSF_RUNNING;
1140 sc->hacr &= ~HACR_INTRON;
1141 CMD(unit); /* turn off interrupts */
1142 }
1143 /* else if interface is UP and RUNNING, start it
1144 */
1145 else if (ifp->if_flags & IFF_UP && (sc->flags & DSF_RUNNING) == 0) {
1146 wlinit(sc);
1147 }
1148
1149 /* if WLDEBUG set on interface, then printf rf-modem regs
1150 */
1151 if (ifp->if_flags & IFF_DEBUG)
1152 wlmmcstat(unit);
1153 break;
1154#if MULTICAST
1155 case SIOCADDMULTI:
1156 case SIOCDELMULTI:
1157
1158 wlinit(sc);
1159 break;
1160#endif /* MULTICAST */
1161
1162 /* DEVICE SPECIFIC */
1163
1164
1165 /* copy the PSA out to the caller */
1166 case SIOCGWLPSA:
1167 /* pointer to buffer in user space */
1168 up = (void *)ifr->ifr_data;
1169 /* work out if they're root */
1170 isroot = (suser(td) == 0);
1171
1172 for (i = 0; i < 0x40; i++) {
1173 /* don't hand the DES key out to non-root users */
1174 if ((i > WLPSA_DESKEY) && (i < (WLPSA_DESKEY + 8)) && !isroot)
1175 continue;
1176 if (subyte((up + i), sc->psa[i]))
1177 return(EFAULT);
1178 }
1179 break;
1180
1181
1182 /* copy the PSA in from the caller; we only copy _some_ values */
1183 case SIOCSWLPSA:
1184 /* root only */
1185 if ((error = suser(td)))
1186 break;
1187 error = EINVAL; /* assume the worst */
1188 /* pointer to buffer in user space containing data */
1189 up = (void *)ifr->ifr_data;
1190
1191 /* check validity of input range */
1192 for (i = 0; i < 0x40; i++)
1193 if (fubyte(up + i) < 0)
1194 return(EFAULT);
1195
1196 /* check IRQ value */
1197 irqval = fubyte(up+WLPSA_IRQNO);
1198 for (irq = 15; irq >= 0; irq--)
1199 if (irqvals[irq] == irqval)
1200 break;
1201 if (irq == 0) /* oops */
1202 break;
1203 /* new IRQ */
1204 sc->psa[WLPSA_IRQNO] = irqval;
1205
1206 /* local MAC */
1207 for (i = 0; i < 6; i++)
1208 sc->psa[WLPSA_LOCALMAC+i] = fubyte(up+WLPSA_LOCALMAC+i);
1209
1210 /* MAC select */
1211 sc->psa[WLPSA_MACSEL] = fubyte(up+WLPSA_MACSEL);
1212
1213 /* default nwid */
1214 sc->psa[WLPSA_NWID] = fubyte(up+WLPSA_NWID);
1215 sc->psa[WLPSA_NWID+1] = fubyte(up+WLPSA_NWID+1);
1216
1217 error = 0;
1218 wlsetpsa(unit); /* update the PSA */
1219 break;
1220
1221
1222 /* get the current NWID out of the sc since we stored it there */
1223 case SIOCGWLCNWID:
1224 ifr->ifr_data = (caddr_t) (sc->nwid[0] << 8 | sc->nwid[1]);
1225 break;
1226
1227
1228 /*
1229 * change the nwid dynamically. This
1230 * ONLY changes the radio modem and does not
1231 * change the PSA.
1232 *
1233 * 2 steps:
1234 * 1. save in softc "soft registers"
1235 * 2. save in radio modem (MMC)
1236 */
1237 case SIOCSWLCNWID:
1238 /* root only */
1239 if ((error = suser(td)))
1240 break;
1241 if (!(ifp->if_flags & IFF_UP)) {
1242 error = EIO; /* only allowed while up */
1243 } else {
1244 /*
1245 * soft c nwid shadows radio modem setting
1246 */
1247 sc->nwid[0] = (int)ifr->ifr_data >> 8;
1248 sc->nwid[1] = (int)ifr->ifr_data & 0xff;
1249 MMC_WRITE(MMC_NETW_ID_L,sc->nwid[1]);
1250 MMC_WRITE(MMC_NETW_ID_H,sc->nwid[0]);
1251 }
1252 break;
1253
1254 /* copy the EEPROM in 2.4 Gz WaveMODEM out to the caller */
1255 case SIOCGWLEEPROM:
1256 /* root only */
1257 if ((error = suser(td)))
1258 break;
1259 /* pointer to buffer in user space */
1260 up = (void *)ifr->ifr_data;
1261
1262 for (i=0x00; i<0x80; ++i) { /* 2.4 Gz: size of EEPROM */
1263 MMC_WRITE(MMC_EEADDR,i); /* 2.4 Gz: get frequency */
1264 MMC_WRITE(MMC_EECTRL, /* 2.4 Gz: EEPROM read */
1265 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: */
1266 DELAY(40); /* 2.4 Gz */
1267 if (subyte(up + 2*i , /* 2.4 Gz: pass low byte of */
1268 wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word */
1269 ) return(EFAULT); /* 2.4 Gz: */
1270 if (subyte(up + 2*i+1, /* 2.4 Gz: pass hi byte of */
1271 wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word */
1272 ) return(EFAULT); /* 2.4 Gz: */
1273 }
1274 break;
1275
1276#ifdef WLCACHE
1277 /* zero (Delete) the wl cache */
1278 case SIOCDWLCACHE:
1279 /* root only */
1280 if ((error = suser(td)))
1281 break;
1282 wl_cache_zero(unit);
1283 break;
1284
1285 /* read out the number of used cache elements */
1286 case SIOCGWLCITEM:
1287 ifr->ifr_data = (caddr_t) sc->w_sigitems;
1288 break;
1289
1290 /* read out the wl cache */
1291 case SIOCGWLCACHE:
1292 /* pointer to buffer in user space */
1293 up = (void *)ifr->ifr_data;
1294 cpt = (char *) &sc->w_sigcache[0];
1295 size = sc->w_sigitems * sizeof(struct w_sigcache);
1296
1297 for (i = 0; i < size; i++) {
1298 if (subyte((up + i), *cpt++))
1299 return(EFAULT);
1300 }
1301 break;
1302#endif
1303
1304 default:
1305 error = ether_ioctl(ifp, cmd, data);
1306 break;
1307 }
1308 splx(opri);
1309 return (error);
1310}
1311
1312/*
1313 * wlwatchdog():
1314 *
1315 * Called if the timer set in wlstart expires before an interrupt is received
1316 * from the wavelan. It seems to lose interrupts sometimes.
1317 * The watchdog routine gets called if the transmitter failed to interrupt
1318 *
1319 * input : which board is timing out
1320 * output : board reset
1321 *
1322 */
1323static void
1324wlwatchdog(void *vsc)
1325{
1326 struct wl_softc *sc = vsc;
1327 int unit = sc->unit;
1328
1329 log(LOG_ERR, "wl%d: wavelan device timeout on xmit\n", unit);
1330 sc->wl_ac.ac_if.if_oerrors++;
1331 wlinit(sc);
1332}
1333
1334/*
1335 * wlintr:
1336 *
1337 * This function is the interrupt handler for the WaveLAN
1338 * board. This routine will be called whenever either a packet
1339 * is received, or a packet has successfully been transfered and
1340 * the unit is ready to transmit another packet.
1341 *
1342 * input : board number that interrupted
1343 * output : either a packet is received, or a packet is transfered
1344 *
1345 */
1346static void
1347wlintr(unit)
1348int unit;
1349{
1350 register struct wl_softc *sc = &wl_softc[unit];
1351 short base = sc->base;
1352 int ac_status;
1353 u_short int_type, int_type1;
1354
1355#ifdef WLDEBUG
1356 if (sc->wl_if.if_flags & IFF_DEBUG)
1357 printf("wl%d: wlintr() called\n",unit);
1358#endif
1359
1360 if ((int_type = inw(HASR(base))) & HASR_MMC_INTR) {
1361 /* handle interrupt from the modem management controler */
1362 /* This will clear the interrupt condition */
1363 (void) wlmmcread(base,MMC_DCE_STATUS); /* ignored for now */
1364 }
1365
1366 if (!(int_type & HASR_INTR)){ /* return if no interrupt from 82586 */
1367 /* commented out. jrb. it happens when reinit occurs
1368 printf("wlintr: int_type %x, dump follows\n", int_type);
1369 wldump(unit);
1370 */
1371 return;
1372 }
1373
1374 if (gathersnr)
1375 getsnr(unit);
1376 for (;;) {
1377 outw(PIOR0(base), OFFSET_SCB + 0); /* get scb status */
1378 int_type = (inw(PIOP0(base)) & SCB_SW_INT);
1379 if (int_type == 0) /* no interrupts left */
1380 break;
1381
1382 int_type1 = wlack(unit); /* acknowledge interrupt(s) */
1383 /* make sure no bits disappeared (others may appear) */
1384 if ((int_type & int_type1) != int_type)
1385 printf("wlack() int bits disappeared : %04x != int_type %04x\n",
1386 int_type1, int_type);
1387 int_type = int_type1; /* go with the new status */
1388 /*
1389 * incoming packet
1390 */
1391 if (int_type & SCB_SW_FR) {
1392 sc->wl_if.if_ipackets++;
1393 wlrcv(unit);
1394 }
1395 /*
1396 * receiver not ready
1397 */
1398 if (int_type & SCB_SW_RNR) {
1399 sc->wl_if.if_ierrors++;
1400#ifdef WLDEBUG
1401 if (sc->wl_if.if_flags & IFF_DEBUG)
1402 printf("wl%d intr(): receiver overrun! begin_fd = %x\n",
1403 unit, sc->begin_fd);
1404#endif
1405 wlrustrt(unit);
1406 }
1407 /*
1408 * CU not ready
1409 */
1410 if (int_type & SCB_SW_CNA) {
1411 /*
1412 * At present, we don't care about CNA's. We
1413 * believe they are a side effect of XMT.
1414 */
1415 }
1416 if (int_type & SCB_SW_CX) {
1417 /*
1418 * At present, we only request Interrupt for
1419 * XMT.
1420 */
1421 outw(PIOR1(base), OFFSET_CU); /* get command status */
1422 ac_status = inw(PIOP1(base));
1423
1424 if (xmt_watch) { /* report some anomalies */
1425
1426 if (sc->tbusy == 0) {
1427 printf("wl%d: xmt intr but not busy, CU %04x\n",
1428 unit, ac_status);
1429 }
1430 if (ac_status == 0) {
1431 printf("wl%d: xmt intr but ac_status == 0\n", unit);
1432 }
1433 if (ac_status & AC_SW_A) {
1434 printf("wl%d: xmt aborted\n",unit);
1435 }
1436#ifdef notdef
1437 if (ac_status & TC_CARRIER) {
1438 printf("wl%d: no carrier\n", unit);
1439 }
1440#endif /* notdef */
1441 if (ac_status & TC_CLS) {
1442 printf("wl%d: no CTS\n", unit);
1443 }
1444 if (ac_status & TC_DMA) {
1445 printf("wl%d: DMA underrun\n", unit);
1446 }
1447 if (ac_status & TC_DEFER) {
1448 printf("wl%d: xmt deferred\n",unit);
1449 }
1450 if (ac_status & TC_SQE) {
1451 printf("wl%d: heart beat\n", unit);
1452 }
1453 if (ac_status & TC_COLLISION) {
1454 printf("wl%d: too many collisions\n", unit);
1455 }
1456 }
1457 /* if the transmit actually failed, or returned some status */
1458 if ((!(ac_status & AC_SW_OK)) || (ac_status & 0xfff)) {
1459 if (ac_status & (TC_COLLISION | TC_CLS | TC_DMA)) {
1460 sc->wl_if.if_oerrors++;
1461 }
1462 /* count collisions */
1463 sc->wl_if.if_collisions += (ac_status & 0xf);
1464 /* if TC_COLLISION set and collision count zero, 16 collisions */
1465 if ((ac_status & 0x20) == 0x20) {
1466 sc->wl_if.if_collisions += 0x10;
1467 }
1468 }
1469 sc->tbusy = 0;
1470 untimeout(wlwatchdog, sc, sc->watchdog_ch);
1471 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
1472 wlstart(&(sc->wl_if));
1473 }
1474 }
1475 return;
1476}
1477
1478/*
1479 * wlrcv:
1480 *
1481 * This routine is called by the interrupt handler to initiate a
1482 * packet transfer from the board to the "if" layer above this
1483 * driver. This routine checks if a buffer has been successfully
1484 * received by the WaveLAN. If so, the routine wlread is called
1485 * to do the actual transfer of the board data (including the
1486 * ethernet header) into a packet (consisting of an mbuf chain).
1487 *
1488 * input : number of the board to check
1489 * output : if a packet is available, it is "sent up"
1490 *
1491 */
1492static void
1493wlrcv(int unit)
1494{
1495 register struct wl_softc *sc = WLSOFTC(unit);
1496 short base = sc->base;
1497 u_short fd_p, status, offset, link_offset;
1498
1499#ifdef WLDEBUG
1500 if (sc->wl_if.if_flags & IFF_DEBUG)
1501 printf("wl%d: entered wlrcv()\n",unit);
1502#endif
1503 for (fd_p = sc->begin_fd; fd_p != I82586NULL; fd_p = sc->begin_fd) {
1504
1505 outw(PIOR0(base), fd_p + 0); /* address of status */
1506 status = inw(PIOP0(base));
1507 outw(PIOR1(base), fd_p + 4); /* address of link_offset */
1508 link_offset = inw(PIOP1(base));
1509 offset = inw(PIOP1(base)); /* rbd_offset */
1510 if (status == 0xffff || offset == 0xffff /*I82586NULL*/) {
1511 if (wlhwrst(unit) != TRUE)
1512 printf("wl%d rcv(): hwrst ffff trouble.\n", unit);
1513 return;
1514 } else if (status & AC_SW_C) {
1515 if (status == (RFD_DONE|RFD_RSC)) {
1516 /* lost one */
1517#ifdef WLDEBUG
1518 if (sc->wl_if.if_flags & IFF_DEBUG)
1519 printf("wl%d RCV: RSC %x\n", unit, status);
1520#endif
1521 sc->wl_if.if_ierrors++;
1522 } else if (!(status & RFD_OK)) {
1523 printf("wl%d RCV: !OK %x\n", unit, status);
1524 sc->wl_if.if_ierrors++;
1525 } else if (status & 0xfff) { /* can't happen */
1526 printf("wl%d RCV: ERRs %x\n", unit, status);
1527 sc->wl_if.if_ierrors++;
1528 } else if (!wlread(unit, fd_p))
1529 return;
1530
1531 if (!wlrequeue(unit, fd_p)) {
1532 /* abort on chain error */
1533 if (wlhwrst(unit) != TRUE)
1534 printf("wl%d rcv(): hwrst trouble.\n", unit);
1535 return;
1536 }
1537 sc->begin_fd = link_offset;
1538 } else {
1539 break;
1540 }
1541 }
1542 return;
1543}
1544
1545/*
1546 * wlrequeue:
1547 *
1548 * This routine puts rbd's used in the last receive back onto the
1549 * free list for the next receive.
1550 *
1551 */
1552static int
1553wlrequeue(int unit, u_short fd_p)
1554{
1555 register struct wl_softc *sc = WLSOFTC(unit);
1556 short base = sc->base;
1557 fd_t fd;
1558 u_short l_rbdp, f_rbdp, rbd_offset;
1559
1560 outw(PIOR0(base), fd_p + 6);
1561 rbd_offset = inw(PIOP0(base));
1562 if ((f_rbdp = rbd_offset) != I82586NULL) {
1563 l_rbdp = f_rbdp;
1564 for (;;) {
1565 outw(PIOR0(base), l_rbdp + 0); /* address of status */
1566 if (inw(PIOP0(base)) & RBD_SW_EOF)
1567 break;
1568 outw(PIOP0(base), 0);
1569 outw(PIOR0(base), l_rbdp + 2); /* next_rbd_offset */
1570 if ((l_rbdp = inw(PIOP0(base))) == I82586NULL)
1571 break;
1572 }
1573 outw(PIOP0(base), 0);
1574 outw(PIOR0(base), l_rbdp + 2); /* next_rbd_offset */
1575 outw(PIOP0(base), I82586NULL);
1576 outw(PIOR0(base), l_rbdp + 8); /* address of size */
1577 outw(PIOP0(base), inw(PIOP0(base)) | AC_CW_EL);
1578 outw(PIOR0(base), sc->end_rbd + 2);
1579 outw(PIOP0(base), f_rbdp); /* end_rbd->next_rbd_offset */
1580 outw(PIOR0(base), sc->end_rbd + 8); /* size */
1581 outw(PIOP0(base), inw(PIOP0(base)) & ~AC_CW_EL);
1582 sc->end_rbd = l_rbdp;
1583 }
1584
1585 fd.status = 0;
1586 fd.command = AC_CW_EL;
1587 fd.link_offset = I82586NULL;
1588 fd.rbd_offset = I82586NULL;
1589 outw(PIOR1(base), fd_p);
1590 outsw(PIOP1(base), &fd, 8/2);
1591
1592 outw(PIOR1(base), sc->end_fd + 2); /* addr of command */
1593 outw(PIOP1(base), 0); /* command = 0 */
1594 outw(PIOP1(base), fd_p); /* end_fd->link_offset = fd_p */
1595 sc->end_fd = fd_p;
1596
1597 return 1;
1598}
1599
1600#ifdef WLDEBUG
1601static int xmt_debug = 0;
1602#endif /* WLDEBUG */
1603
1604/*
1605 * wlxmt:
1606 *
1607 * This routine fills in the appropriate registers and memory
1608 * locations on the WaveLAN board and starts the board off on
1609 * the transmit.
1610 *
1611 * input : board number of interest, and a pointer to the mbuf
1612 * output : board memory and registers are set for xfer and attention
1613 *
1614 */
1615static void
1616wlxmt(int unit, struct mbuf *m)
1617{
1618 register struct wl_softc *sc = WLSOFTC(unit);
1619 register u_short xmtdata_p = OFFSET_TBUF;
1620 register u_short xmtshort_p;
1621 struct mbuf *tm_p = m;
1622 register struct ether_header *eh_p = mtod(m, struct ether_header *);
1623 u_char *mb_p = mtod(m, u_char *) + sizeof(struct ether_header);
1624 u_short count = m->m_len - sizeof(struct ether_header);
1625 ac_t cb;
1626 u_short tbd_p = OFFSET_TBD;
1627 u_short len, clen = 0;
1628 short base = sc->base;
1629 int spin;
1630
1631#ifdef WLDEBUG
1632 if (sc->wl_if.if_flags & IFF_DEBUG)
1633 printf("wl%d: entered wlxmt()\n",unit);
1634#endif
1635
1636 cb.ac_status = 0;
1637 cb.ac_command = (AC_CW_EL|AC_TRANSMIT|AC_CW_I);
1638 cb.ac_link_offset = I82586NULL;
1639 outw(PIOR1(base), OFFSET_CU);
1640 outsw(PIOP1(base), &cb, 6/2);
1641 outw(PIOP1(base), OFFSET_TBD); /* cb.cmd.transmit.tbd_offset */
1642 outsw(PIOP1(base), eh_p->ether_dhost, WAVELAN_ADDR_SIZE/2);
1643 outw(PIOP1(base), eh_p->ether_type);
1644
1645#ifdef WLDEBUG
1646 if (sc->wl_if.if_flags & IFF_DEBUG) {
1647 if (xmt_debug) {
1648 printf("XMT mbuf: L%d @%p ", count, (void *)mb_p);
1649 printf("ether type %x\n", eh_p->ether_type);
1650 }
1651 }
1652#endif /* WLDEBUG */
1653 outw(PIOR0(base), OFFSET_TBD);
1654 outw(PIOP0(base), 0); /* act_count */
1655 outw(PIOR1(base), OFFSET_TBD + 4);
1656 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1657 outw(PIOP1(base), 0); /* buffer_base */
1658 for (;;) {
1659 if (count) {
1660 if (clen + count > WAVELAN_MTU)
1661 break;
1662 if (count & 1)
1663 len = count + 1;
1664 else
1665 len = count;
1666 outw(PIOR1(base), xmtdata_p);
1667 outsw(PIOP1(base), mb_p, len/2);
1668 clen += count;
1669 outw(PIOR0(base), tbd_p); /* address of act_count */
1670 outw(PIOP0(base), inw(PIOP0(base)) + count);
1671 xmtdata_p += len;
1672 if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1673 break;
1674 if (count & 1) {
1675 /* go to the next descriptor */
1676 outw(PIOR0(base), tbd_p + 2);
1677 tbd_p += sizeof (tbd_t);
1678 outw(PIOP0(base), tbd_p); /* next_tbd_offset */
1679 outw(PIOR0(base), tbd_p);
1680 outw(PIOP0(base), 0); /* act_count */
1681 outw(PIOR1(base), tbd_p + 4);
1682 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1683 outw(PIOP1(base), 0); /* buffer_base */
1684 /* at the end -> coallesce remaining mbufs */
1685 if (tbd_p == OFFSET_TBD + (N_TBD-1) * sizeof (tbd_t)) {
1686 wlsftwsleaze(&count, &mb_p, &tm_p, unit);
1687 continue;
1688 }
1689 /* next mbuf short -> coallesce as needed */
1690 if ( (tm_p->m_next == (struct mbuf *) 0) ||
1691#define HDW_THRESHOLD 55
1692 tm_p->m_len > HDW_THRESHOLD)
1693 /* ok */;
1694 else {
1695 wlhdwsleaze(&count, &mb_p, &tm_p, unit);
1696 continue;
1697 }
1698 }
1699 } else if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1700 break;
1701 count = tm_p->m_len;
1702 mb_p = mtod(tm_p, u_char *);
1703#ifdef WLDEBUG
1704 if (sc->wl_if.if_flags & IFF_DEBUG)
1705 if (xmt_debug)
1706 printf("mbuf+ L%d @%p ", count, (void *)mb_p);
1707#endif /* WLDEBUG */
1708 }
1709#ifdef WLDEBUG
1710 if (sc->wl_if.if_flags & IFF_DEBUG)
1711 if (xmt_debug)
1712 printf("CLEN = %d\n", clen);
1713#endif /* WLDEBUG */
1714 outw(PIOR0(base), tbd_p);
1715 if (clen < ETHERMIN) {
1716 outw(PIOP0(base), inw(PIOP0(base)) + ETHERMIN - clen);
1717 outw(PIOR1(base), xmtdata_p);
1718 for (xmtshort_p = xmtdata_p; clen < ETHERMIN; clen += 2)
1719 outw(PIOP1(base), 0);
1720 }
1721 outw(PIOP0(base), inw(PIOP0(base)) | TBD_SW_EOF);
1722 outw(PIOR0(base), tbd_p + 2);
1723 outw(PIOP0(base), I82586NULL);
1724#ifdef WLDEBUG
1725 if (sc->wl_if.if_flags & IFF_DEBUG) {
1726 if (xmt_debug) {
1727 wltbd(unit);
1728 printf("\n");
1729 }
1730 }
1731#endif /* WLDEBUG */
1732
1733 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
1734 /*
1735 * wait for 586 to clear previous command, complain if it takes
1736 * too long
1737 */
1738 for (spin = 1;;spin = (spin + 1) % 10000) {
1739 if (inw(PIOP0(base)) == 0) { /* it's done, we can go */
1740 break;
1741 }
1742 if ((spin == 0) && xmt_watch) { /* not waking up, and we care */
1743 printf("wl%d: slow accepting xmit\n",unit);
1744 }
1745 }
1746 outw(PIOP0(base), SCB_CU_STRT); /* new command */
1747 SET_CHAN_ATTN(unit);
1748
1749 m_freem(m);
1750
1751 /* XXX
1752 * Pause to avoid transmit overrun problems.
1753 * The required delay tends to vary with platform type, and may be
1754 * related to interrupt loss.
1755 */
1756 if (wl_xmit_delay) {
1757 DELAY(wl_xmit_delay);
1758 }
1759 return;
1760}
1761
1762/*
1763 * wlbldru:
1764 *
1765 * This function builds the linear linked lists of fd's and
1766 * rbd's. Based on page 4-32 of 1986 Intel microcom handbook.
1767 *
1768 */
1769static u_short
1770wlbldru(int unit)
1771{
1772 register struct wl_softc *sc = WLSOFTC(unit);
1773 short base = sc->base;
1774 fd_t fd;
1775 rbd_t rbd;
1776 u_short fd_p = OFFSET_RU;
1777 u_short rbd_p = OFFSET_RBD;
1778 int i;
1779
1780 sc->begin_fd = fd_p;
1781 for (i = 0; i < N_FD; i++) {
1782 fd.status = 0;
1783 fd.command = 0;
1784 fd.link_offset = fd_p + sizeof(fd_t);
1785 fd.rbd_offset = I82586NULL;
1786 outw(PIOR1(base), fd_p);
1787 outsw(PIOP1(base), &fd, 8/2);
1788 fd_p = fd.link_offset;
1789 }
1790 fd_p -= sizeof(fd_t);
1791 sc->end_fd = fd_p;
1792 outw(PIOR1(base), fd_p + 2);
1793 outw(PIOP1(base), AC_CW_EL); /* command */
1794 outw(PIOP1(base), I82586NULL); /* link_offset */
1795 fd_p = OFFSET_RU;
1796
1797 outw(PIOR0(base), fd_p + 6); /* address of rbd_offset */
1798 outw(PIOP0(base), rbd_p);
1799 outw(PIOR1(base), rbd_p);
1800 for (i = 0; i < N_RBD; i++) {
1801 rbd.status = 0;
1802 rbd.buffer_addr = rbd_p + sizeof(rbd_t) + 2;
1803 rbd.buffer_base = 0;
1804 rbd.size = RCVBUFSIZE;
1805 if (i != N_RBD-1) {
1806 rbd_p += sizeof(ru_t);
1807 rbd.next_rbd_offset = rbd_p;
1808 } else {
1809 rbd.next_rbd_offset = I82586NULL;
1810 rbd.size |= AC_CW_EL;
1811 sc->end_rbd = rbd_p;
1812 }
1813 outsw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1814 outw(PIOR1(base), rbd_p);
1815 }
1816 return sc->begin_fd;
1817}
1818
1819/*
1820 * wlrustrt:
1821 *
1822 * This routine starts the receive unit running. First checks if the
1823 * board is actually ready, then the board is instructed to receive
1824 * packets again.
1825 *
1826 */
1827static void
1828wlrustrt(int unit)
1829{
1830 register struct wl_softc *sc = WLSOFTC(unit);
1831 short base = sc->base;
1832 u_short rfa;
1833
1834#ifdef WLDEBUG
1835 if (sc->wl_if.if_flags & IFF_DEBUG)
1836 printf("wl%d: entered wlrustrt()\n",unit);
1837#endif
1838 outw(PIOR0(base), OFFSET_SCB);
1839 if (inw(PIOP0(base)) & SCB_RUS_READY){
1840 printf("wlrustrt: RUS_READY\n");
1841 return;
1842 }
1843
1844 outw(PIOR0(base), OFFSET_SCB + 2);
1845 outw(PIOP0(base), SCB_RU_STRT); /* command */
1846 rfa = wlbldru(unit);
1847 outw(PIOR0(base), OFFSET_SCB + 6); /* address of scb_rfa_offset */
1848 outw(PIOP0(base), rfa);
1849
1850 SET_CHAN_ATTN(unit);
1851 return;
1852}
1853
1854/*
1855 * wldiag:
1856 *
1857 * This routine does a 586 op-code number 7, and obtains the
1858 * diagnose status for the WaveLAN.
1859 *
1860 */
1861static int
1862wldiag(int unit)
1863{
1864 register struct wl_softc *sc = WLSOFTC(unit);
1865 short base = sc->base;
1866 short status;
1867
1868#ifdef WLDEBUG
1869 if (sc->wl_if.if_flags & IFF_DEBUG)
1870 printf("wl%d: entered wldiag()\n",unit);
1871#endif
1872 outw(PIOR0(base), OFFSET_SCB);
1873 status = inw(PIOP0(base));
1874 if (status & SCB_SW_INT) {
1875 /* state is 2000 which seems ok
1876 printf("wl%d diag(): unexpected initial state %\n",
1877 unit, inw(PIOP0(base)));
1878 */
1879 wlack(unit);
1880 }
1881 outw(PIOR1(base), OFFSET_CU);
1882 outw(PIOP1(base), 0); /* ac_status */
1883 outw(PIOP1(base), AC_DIAGNOSE|AC_CW_EL);/* ac_command */
1884 if (wlcmd(unit, "diag()") == 0)
1885 return 0;
1886 outw(PIOR0(base), OFFSET_CU);
1887 if (inw(PIOP0(base)) & 0x0800) {
1888 printf("wl%d: i82586 Self Test failed!\n", unit);
1889 return 0;
1890 }
1891 return TRUE;
1892}
1893
1894/*
1895 * wlconfig:
1896 *
1897 * This routine does a standard config of the WaveLAN board.
1898 *
1899 */
1900static int
1901wlconfig(int unit)
1902{
1903 configure_t configure;
1904 register struct wl_softc *sc = WLSOFTC(unit);
1905 short base = sc->base;
1906
1907#if MULTICAST
1908 struct ifmultiaddr *ifma;
1909 u_char *addrp;
1910 int cnt = 0;
1911#endif /* MULTICAST */
1912
1913#ifdef WLDEBUG
1914 if (sc->wl_if.if_flags & IFF_DEBUG)
1915 printf("wl%d: entered wlconfig()\n",unit);
1916#endif
1917 outw(PIOR0(base), OFFSET_SCB);
1918 if (inw(PIOP0(base)) & SCB_SW_INT) {
1919 /*
1920 printf("wl%d config(): unexpected initial state %x\n",
1921 unit, inw(PIOP0(base)));
1922 */
1923 }
1924 wlack(unit);
1925
1926 outw(PIOR1(base), OFFSET_CU);
1927 outw(PIOP1(base), 0); /* ac_status */
1928 outw(PIOP1(base), AC_CONFIGURE|AC_CW_EL); /* ac_command */
1929
1930/* jrb hack */
1931 configure.fifolim_bytecnt = 0x080c;
1932 configure.addrlen_mode = 0x0600;
1933 configure.linprio_interframe = 0x2060;
1934 configure.slot_time = 0xf200;
1935 configure.hardware = 0x0008; /* tx even w/o CD */
1936 configure.min_frame_len = 0x0040;
1937#if 0
1938 /* This is the configuration block suggested by Marc Meertens
1939 * <mmeerten@obelix.utrecht.NCR.COM> in an e-mail message to John
1940 * Ioannidis on 10 Nov 92.
1941 */
1942 configure.fifolim_bytecnt = 0x040c;
1943 configure.addrlen_mode = 0x0600;
1944 configure.linprio_interframe = 0x2060;
1945 configure.slot_time = 0xf000;
1946 configure.hardware = 0x0008; /* tx even w/o CD */
1947 configure.min_frame_len = 0x0040;
1948#else
1949 /*
1950 * below is the default board configuration from p2-28 from 586 book
1951 */
1952 configure.fifolim_bytecnt = 0x080c;
1953 configure.addrlen_mode = 0x2600;
1954 configure.linprio_interframe = 0x7820; /* IFS=120, ACS=2 */
1955 configure.slot_time = 0xf00c; /* slottime=12 */
1956 configure.hardware = 0x0008; /* tx even w/o CD */
1957 configure.min_frame_len = 0x0040;
1958#endif
1959 if (sc->mode & (MOD_PROM | MOD_ENAL))
1960 configure.hardware |= 1;
1961 outw(PIOR1(base), OFFSET_CU + 6);
1962 outsw(PIOP1(base), &configure, sizeof(configure_t)/2);
1963
1964 if (wlcmd(unit, "config()-configure") == 0)
1965 return 0;
1966#if MULTICAST
1967 outw(PIOR1(base), OFFSET_CU);
1968 outw(PIOP1(base), 0); /* ac_status */
1969 outw(PIOP1(base), AC_MCSETUP|AC_CW_EL); /* ac_command */
1970 outw(PIOR1(base), OFFSET_CU + 8);
1971 TAILQ_FOREACH(ifma, &sc->wl_if.if_multiaddrs, ifma_link) {
1972 if (ifma->ifma_addr->sa_family != AF_LINK)
1973 continue;
1974
1975 addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
1976 outw(PIOP1(base), addrp[0] + (addrp[1] << 8));
1977 outw(PIOP1(base), addrp[2] + (addrp[3] << 8));
1978 outw(PIOP1(base), addrp[4] + (addrp[5] << 8));
1979 ++cnt;
1980 }
1981 outw(PIOR1(base), OFFSET_CU + 6); /* mc-cnt */
1982 outw(PIOP1(base), cnt * WAVELAN_ADDR_SIZE);
1983 if (wlcmd(unit, "config()-mcaddress") == 0)
1984 return 0;
1985#endif /* MULTICAST */
1986
1987 outw(PIOR1(base), OFFSET_CU);
1988 outw(PIOP1(base), 0); /* ac_status */
1989 outw(PIOP1(base), AC_IASETUP|AC_CW_EL); /* ac_command */
1990 outw(PIOR1(base), OFFSET_CU + 6);
1991 outsw(PIOP1(base), sc->wl_addr, WAVELAN_ADDR_SIZE/2);
1992
1993 if (wlcmd(unit, "config()-address") == 0)
1994 return(0);
1995
1996 wlinitmmc(unit);
1997
1998 return(1);
1999}
2000
2001/*
2002 * wlcmd:
2003 *
2004 * Set channel attention bit and busy wait until command has
2005 * completed. Then acknowledge the command completion.
2006 */
2007static int
2008wlcmd(int unit, char *str)
2009{
2010 register struct wl_softc *sc = WLSOFTC(unit);
2011 short base = sc->base;
2012 int i;
2013
2014 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
2015 outw(PIOP0(base), SCB_CU_STRT);
2016
2017 SET_CHAN_ATTN(unit);
2018
2019 outw(PIOR0(base), OFFSET_CU);
2020 for (i = 0; i < 0xffff; i++)
2021 if (inw(PIOP0(base)) & AC_SW_C)
2022 break;
2023 if (i == 0xffff || !(inw(PIOP0(base)) & AC_SW_OK)) {
2024 printf("wl%d: %s failed; status = %d, inw = %x, outw = %x\n",
2025 unit, str, inw(PIOP0(base)) & AC_SW_OK, inw(PIOP0(base)), inw(PIOR0(base)));
2026 outw(PIOR0(base), OFFSET_SCB);
2027 printf("scb_status %x\n", inw(PIOP0(base)));
2028 outw(PIOR0(base), OFFSET_SCB+2);
2029 printf("scb_command %x\n", inw(PIOP0(base)));
2030 outw(PIOR0(base), OFFSET_SCB+4);
2031 printf("scb_cbl %x\n", inw(PIOP0(base)));
2032 outw(PIOR0(base), OFFSET_CU+2);
2033 printf("cu_cmd %x\n", inw(PIOP0(base)));
2034 return(0);
2035 }
2036
2037 outw(PIOR0(base), OFFSET_SCB);
2038 if ((inw(PIOP0(base)) & SCB_SW_INT) && (inw(PIOP0(base)) != SCB_SW_CNA)) {
2039 /*
2040 printf("wl%d %s: unexpected final state %x\n",
2041 unit, str, inw(PIOP0(base)));
2042 */
2043 }
2044 wlack(unit);
2045 return(TRUE);
2046}
2047
2048/*
2049 * wlack: if the 82596 wants attention because it has finished
2050 * sending or receiving a packet, acknowledge its desire and
2051 * return bits indicating the kind of attention. wlack() returns
2052 * these bits so that the caller can service exactly the
2053 * conditions that wlack() acknowledged.
2054 */
2055static int
2056wlack(int unit)
2057{
2058 int i;
2059 register u_short cmd;
2060 register struct wl_softc *sc = WLSOFTC(unit);
2061 short base = sc->base;
2062
2063 outw(PIOR1(base), OFFSET_SCB);
2064 if (!(cmd = (inw(PIOP1(base)) & SCB_SW_INT)))
2065 return(0);
2066#ifdef WLDEBUG
2067 if (sc->wl_if.if_flags & IFF_DEBUG)
2068 printf("wl%d: doing a wlack()\n",unit);
2069#endif
2070 outw(PIOP1(base), cmd);
2071 SET_CHAN_ATTN(unit);
2072 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
2073 for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); )
2074 continue;
2075 if (i < 1)
2076 printf("wl%d wlack(): board not accepting command.\n", unit);
2077 return(cmd);
2078}
2079
2080#ifdef WLDEBUG
2081static void
2082wltbd(int unit)
2083{
2084 register struct wl_softc *sc = WLSOFTC(unit);
2085 short base = sc->base;
2086 u_short tbd_p = OFFSET_TBD;
2087 tbd_t tbd;
2088 int i = 0;
2089 int sum = 0;
2090
2091 for (;;) {
2092 outw(PIOR1(base), tbd_p);
2093 insw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
2094 sum += (tbd.act_count & ~TBD_SW_EOF);
2095 printf("%d: addr %x, count %d (%d), next %x, base %x\n",
2096 i++, tbd.buffer_addr,
2097 (tbd.act_count & ~TBD_SW_EOF), sum,
2098 tbd.next_tbd_offset, tbd.buffer_base);
2099 if (tbd.act_count & TBD_SW_EOF)
2100 break;
2101 tbd_p = tbd.next_tbd_offset;
2102 }
2103}
2104#endif
2105
2106static void
2107wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2108{
2109 struct mbuf *tm_p = *tm_pp;
2110 u_char *mb_p = *mb_pp;
2111 u_short count = 0;
2112 u_char *cp;
2113 int len;
2114
2115 /*
2116 * can we get a run that will be coallesced or
2117 * that terminates before breaking
2118 */
2119 do {
2120 count += tm_p->m_len;
2121 if (tm_p->m_len & 1)
2122 break;
2123 } while ((tm_p = tm_p->m_next) != (struct mbuf *)0);
2124 if ( (tm_p == (struct mbuf *)0) ||
2125 count > HDW_THRESHOLD) {
2126 *countp = (*tm_pp)->m_len;
2127 *mb_pp = mtod((*tm_pp), u_char *);
2128 return;
2129 }
2130
2131 /* we need to copy */
2132 tm_p = *tm_pp;
2133 mb_p = *mb_pp;
2134 count = 0;
2135 cp = (u_char *) t_packet;
2136 for (;;) {
2137 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2138 count += len;
2139 if (count > HDW_THRESHOLD)
2140 break;
2141 cp += len;
2142 if (tm_p->m_next == (struct mbuf *)0)
2143 break;
2144 tm_p = tm_p->m_next;
2145 }
2146 *countp = count;
2147 *mb_pp = (u_char *) t_packet;
2148 *tm_pp = tm_p;
2149 return;
2150}
2151
2152
2153static void
2154wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2155{
2156 struct mbuf *tm_p = *tm_pp;
2157 u_short count = 0;
2158 u_char *cp = (u_char *) t_packet;
2159 int len;
2160
2161 /* we need to copy */
2162 for (;;) {
2163 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2164 count += len;
2165 cp += len;
2166 if (tm_p->m_next == (struct mbuf *)0)
2167 break;
2168 tm_p = tm_p->m_next;
2169 }
2170
2171 *countp = count;
2172 *mb_pp = (u_char *) t_packet;
2173 *tm_pp = tm_p;
2174 return;
2175}
2176
2177static void
2178wlmmcstat(int unit)
2179{
2180 register struct wl_softc *sc = WLSOFTC(unit);
2181 short base = sc->base;
2182 u_short tmp;
2183
2184 printf("wl%d: DCE_STATUS: 0x%x, ", unit,
2185 wlmmcread(base,MMC_DCE_STATUS) & 0x0f);
2186 tmp = wlmmcread(base,MMC_CORRECT_NWID_H) << 8;
2187 tmp |= wlmmcread(base,MMC_CORRECT_NWID_L);
2188 printf("Correct NWID's: %d, ", tmp);
2189 tmp = wlmmcread(base,MMC_WRONG_NWID_H) << 8;
2190 tmp |= wlmmcread(base,MMC_WRONG_NWID_L);
2191 printf("Wrong NWID's: %d\n", tmp);
2192 printf("THR_PRE_SET: 0x%x, ", wlmmcread(base,MMC_THR_PRE_SET));
2193 printf("SIGNAL_LVL: %d, SILENCE_LVL: %d\n",
2194 wlmmcread(base,MMC_SIGNAL_LVL),
2195 wlmmcread(base,MMC_SILENCE_LVL));
2196 printf("SIGN_QUAL: 0x%x, NETW_ID: %x:%x, DES: %d\n",
2197 wlmmcread(base,MMC_SIGN_QUAL),
2198 wlmmcread(base,MMC_NETW_ID_H),
2199 wlmmcread(base,MMC_NETW_ID_L),
2200 wlmmcread(base,MMC_DES_AVAIL));
2201}
2202
2203static u_short
2204wlmmcread(u_int base, u_short reg)
2205{
2206 while (inw(HASR(base)) & HASR_MMC_BUSY)
2207 continue;
2208 outw(MMCR(base),reg << 1);
2209 while (inw(HASR(base)) & HASR_MMC_BUSY)
2210 continue;
2211 return (u_short)inw(MMCR(base)) >> 8;
2212}
2213
2214static void
2215getsnr(int unit)
2216{
2217 MMC_WRITE(MMC_FREEZE,1);
2218 /*
2219 * SNR retrieval procedure :
2220 *
2221 * read signal level : wlmmcread(base, MMC_SIGNAL_LVL);
2222 * read silence level : wlmmcread(base, MMC_SILENCE_LVL);
2223 */
2224 MMC_WRITE(MMC_FREEZE,0);
2225 /*
2226 * SNR is signal:silence ratio.
2227 */
2228}
2229
2230/*
2231** wlgetpsa
2232**
2233** Reads the psa for the wavelan at (base) into (buf)
2234*/
2235static void
2236wlgetpsa(int base, u_char *buf)
2237{
2238 int i;
2239
2240 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2241 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2242
2243 for (i = 0; i < 0x40; i++) {
2244 outw(PIOR2(base), i);
2245 buf[i] = inb(PIOP2(base));
2246 }
2247 PCMD(base, HACR_DEFAULT);
2248 PCMD(base, HACR_DEFAULT);
2249}
2250
2251/*
2252** wlsetpsa
2253**
2254** Writes the psa for wavelan (unit) from the softc back to the
2255** board. Updates the CRC and sets the CRC OK flag.
2256**
2257** Do not call this when the board is operating, as it doesn't
2258** preserve the hacr.
2259*/
2260static void
2261wlsetpsa(int unit)
2262{
2263 register struct wl_softc *sc = WLSOFTC(unit);
2264 short base = sc->base;
2265 int i, oldpri;
2266 u_short crc;
2267
2268 crc = wlpsacrc(sc->psa); /* calculate CRC of PSA */
2269 sc->psa[WLPSA_CRCLOW] = crc & 0xff;
2270 sc->psa[WLPSA_CRCHIGH] = (crc >> 8) & 0xff;
2271 sc->psa[WLPSA_CRCOK] = 0x55; /* default to 'bad' until programming complete */
2272
2273 oldpri = splimp(); /* ick, long pause */
2274
2275 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2276 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2277
2278 for (i = 0; i < 0x40; i++) {
2279 DELAY(DELAYCONST);
2280 outw(PIOR2(base),i); /* write param memory */
2281 DELAY(DELAYCONST);
2282 outb(PIOP2(base), sc->psa[i]);
2283 }
2284 DELAY(DELAYCONST);
2285 outw(PIOR2(base),WLPSA_CRCOK); /* update CRC flag*/
2286 DELAY(DELAYCONST);
2287 sc->psa[WLPSA_CRCOK] = 0xaa; /* OK now */
2288 outb(PIOP2(base), 0xaa); /* all OK */
2289 DELAY(DELAYCONST);
2290
2291 PCMD(base, HACR_DEFAULT);
2292 PCMD(base, HACR_DEFAULT);
2293
2294 splx(oldpri);
2295}
2296
2297/*
2298** CRC routine provided by Christopher Giordano <cgiordan@gdeb.com>,
2299** from original code by Tomi Mikkonen (tomitm@remedy.fi)
2300*/
2301
2302static u_int crc16_table[16] = {
2303 0x0000, 0xCC01, 0xD801, 0x1400,
2304 0xF001, 0x3C00, 0x2800, 0xE401,
2305 0xA001, 0x6C00, 0x7800, 0xB401,
2306 0x5000, 0x9C01, 0x8801, 0x4400
2307};
2308
2309static u_short
2310wlpsacrc(u_char *buf)
2311{
2312 u_short crc = 0;
2313 int i, r1;
2314
2315 for (i = 0; i < 0x3d; i++, buf++) {
2316 /* lower 4 bits */
2317 r1 = crc16_table[crc & 0xF];
2318 crc = (crc >> 4) & 0x0FFF;
2319 crc = crc ^ r1 ^ crc16_table[*buf & 0xF];
2320
2321 /* upper 4 bits */
2322 r1 = crc16_table[crc & 0xF];
2323 crc = (crc >> 4) & 0x0FFF;
2324 crc = crc ^ r1 ^ crc16_table[(*buf >> 4) & 0xF];
2325 }
2326 return(crc);
2327}
2328#ifdef WLCACHE
2329
2330/*
2331 * wl_cache_store
2332 *
2333 * take input packet and cache various radio hw characteristics
2334 * indexed by MAC address.
2335 *
2336 * Some things to think about:
2337 * note that no space is malloced.
2338 * We might hash the mac address if the cache were bigger.
2339 * It is not clear that the cache is big enough.
2340 * It is also not clear how big it should be.
2341 * The cache is IP-specific. We don't care about that as
2342 * we want it to be IP-specific.
2343 * The last N recv. packets are saved. This will tend
2344 * to reward agents and mobile hosts that beacon.
2345 * That is probably fine for mobile ip.
2346 */
2347
2348/* globals for wavelan signal strength cache */
2349/* this should go into softc structure above.
2350*/
2351
2352/* set true if you want to limit cache items to broadcast/mcast
2353 * only packets (not unicast)
2354 */
2355static int wl_cache_mcastonly = 1;
2356SYSCTL_INT(_machdep, OID_AUTO, wl_cache_mcastonly, CTLFLAG_RW,
2357 &wl_cache_mcastonly, 0, "");
2358
2359/* set true if you want to limit cache items to IP packets only
2360*/
2361static int wl_cache_iponly = 1;
2362SYSCTL_INT(_machdep, OID_AUTO, wl_cache_iponly, CTLFLAG_RW,
2363 &wl_cache_iponly, 0, "");
2364
2365/* zero out the cache
2366*/
2367static void
2368wl_cache_zero(int unit)
2369{
2370 register struct wl_softc *sc = WLSOFTC(unit);
2371
2372 bzero(&sc->w_sigcache[0], sizeof(struct w_sigcache) * MAXCACHEITEMS);
2373 sc->w_sigitems = 0;
2374 sc->w_nextcache = 0;
2375 sc->w_wrapindex = 0;
2376}
2377
2378/* store hw signal info in cache.
2379 * index is MAC address, but an ip src gets stored too
2380 * There are two filters here controllable via sysctl:
2381 * throw out unicast (on by default, but can be turned off)
2382 * throw out non-ip (on by default, but can be turned off)
2383 */
2384static
2385void wl_cache_store (int unit, int base, struct ether_header *eh,
2386 struct mbuf *m)
2387{
2388 struct ip *ip = NULL; /* Avoid GCC warning */
2389 int i;
2390 int signal, silence;
2391 int w_insertcache; /* computed index for cache entry storage */
2392 register struct wl_softc *sc = WLSOFTC(unit);
2393 int ipflag = wl_cache_iponly;
2394
2395 /* filters:
2396 * 1. ip only
2397 * 2. configurable filter to throw out unicast packets,
2398 * keep multicast only.
2399 */
2400
2401#ifdef INET
2402 /* reject if not IP packet
2403 */
2404 if ( wl_cache_iponly && (ntohs(eh->ether_type) != 0x800)) {
2405 return;
2406 }
2407
2408 /* check if broadcast or multicast packet. we toss
2409 * unicast packets
2410 */
2411 if (wl_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
2412 return;
2413 }
2414
2415 /* find the ip header. we want to store the ip_src
2416 * address. use the mtod macro(in mbuf.h)
2417 * to typecast m to struct ip *
2418 */
2419 if (ipflag) {
2420 ip = mtod(m, struct ip *);
2421 }
2422
2423 /* do a linear search for a matching MAC address
2424 * in the cache table
2425 * . MAC address is 6 bytes,
2426 * . var w_nextcache holds total number of entries already cached
2427 */
2428 for (i = 0; i < sc->w_nextcache; i++) {
2429 if (! bcmp(eh->ether_shost, sc->w_sigcache[i].macsrc, 6 )) {
2430 /* Match!,
2431 * so we already have this entry,
2432 * update the data, and LRU age
2433 */
2434 break;
2435 }
2436 }
2437
2438 /* did we find a matching mac address?
2439 * if yes, then overwrite a previously existing cache entry
2440 */
2441 if (i < sc->w_nextcache ) {
2442 w_insertcache = i;
2443 }
2444 /* else, have a new address entry,so
2445 * add this new entry,
2446 * if table full, then we need to replace entry
2447 */
2448 else {
2449
2450 /* check for space in cache table
2451 * note: w_nextcache also holds number of entries
2452 * added in the cache table
2453 */
2454 if ( sc->w_nextcache < MAXCACHEITEMS ) {
2455 w_insertcache = sc->w_nextcache;
2456 sc->w_nextcache++;
2457 sc->w_sigitems = sc->w_nextcache;
2458 }
2459 /* no space found, so simply wrap with wrap index
2460 * and "zap" the next entry
2461 */
2462 else {
2463 if (sc->w_wrapindex == MAXCACHEITEMS) {
2464 sc->w_wrapindex = 0;
2465 }
2466 w_insertcache = sc->w_wrapindex++;
2467 }
2468 }
2469
2470 /* invariant: w_insertcache now points at some slot
2471 * in cache.
2472 */
2473 if (w_insertcache < 0 || w_insertcache >= MAXCACHEITEMS) {
2474 log(LOG_ERR,
2475 "wl_cache_store, bad index: %d of [0..%d], gross cache error\n",
2476 w_insertcache, MAXCACHEITEMS);
2477 return;
2478 }
2479
2480 /* store items in cache
2481 * .ipsrc
2482 * .macsrc
2483 * .signal (0..63) ,silence (0..63) ,quality (0..15)
2484 */
2485 if (ipflag) {
2486 sc->w_sigcache[w_insertcache].ipsrc = ip->ip_src.s_addr;
2487 }
2488 bcopy( eh->ether_shost, sc->w_sigcache[w_insertcache].macsrc, 6);
2489 signal = sc->w_sigcache[w_insertcache].signal = wlmmcread(base, MMC_SIGNAL_LVL) & 0x3f;
2490 silence = sc->w_sigcache[w_insertcache].silence = wlmmcread(base, MMC_SILENCE_LVL) & 0x3f;
2491 sc->w_sigcache[w_insertcache].quality = wlmmcread(base, MMC_SIGN_QUAL) & 0x0f;
2492 if (signal > 0)
2493 sc->w_sigcache[w_insertcache].snr =
2494 signal - silence;
2495 else
2496 sc->w_sigcache[w_insertcache].snr = 0;
2497#endif /* INET */
2498
2499}
2500#endif /* WLCACHE */