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