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