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