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