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