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