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