FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/if_wl.c
1 /* $FreeBSD: src/sys/i386/isa/if_wl.c,v 1.8.2.2 1999/09/05 08:12:59 peter Exp $ */
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 ? vector wlintr
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
195 #include <sys/param.h>
196 #include <sys/systm.h>
197 #include <sys/sockio.h>
198 #include <sys/mbuf.h>
199 #include <sys/socket.h>
200 #include <sys/syslog.h>
201 #include <sys/proc.h>
202
203 #include <sys/kernel.h>
204 #include <sys/sysctl.h>
205
206 #include <net/if.h>
207 #include <net/if_dl.h>
208
209 #ifdef INET
210 #include <netinet/in.h>
211 #include <netinet/in_systm.h>
212 #include <netinet/ip.h>
213 #include <netinet/if_ether.h>
214 #endif
215
216 #if NBPFILTER > 0
217 #include <net/bpf.h>
218 #endif
219
220 #include <machine/clock.h>
221
222 #include <i386/isa/isa_device.h>
223
224 #include <i386/isa/ic/if_wl_i82586.h> /* Definitions for the Intel chip */
225
226 /* was 1000 in original, fed to DELAY(x) */
227 #define DELAYCONST 1000
228 #include <i386/isa/if_wl.h>
229 #include <machine/if_wl_wavelan.h>
230
231 static char t_packet[ETHERMTU + sizeof(struct ether_header) + sizeof(long)];
232
233 struct wl_softc{
234 struct arpcom wl_ac; /* Ethernet common part */
235 #define wl_if wl_ac.ac_if /* network visible interface */
236 #define wl_addr wl_ac.ac_enaddr /* hardware address */
237 u_char psa[0x40];
238 u_char nwid[2]; /* current radio modem nwid */
239 short base;
240 short unit;
241 int flags;
242 int tbusy; /* flag to determine if xmit is busy */
243 u_short begin_fd;
244 u_short end_fd;
245 u_short end_rbd;
246 u_short hacr; /* latest host adapter CR command */
247 short mode;
248 u_char chan24; /* 2.4 Gz: channel number/EEPROM Area # */
249 u_short freq24; /* 2.4 Gz: resulting frequency */
250 #ifdef WLCACHE
251 int w_sigitems; /* number of cached entries */
252 /* array of cache entries */
253 struct w_sigcache w_sigcache[ MAXCACHEITEMS ];
254 int w_nextcache; /* next free cache entry */
255 int w_wrapindex; /* next "free" cache entry */
256 #endif
257 };
258 static struct wl_softc wl_softc[NWL];
259
260 #define WLSOFTC(unit) ((struct wl_softc *)(&wl_softc[unit]))
261
262 static int wlprobe(struct isa_device *);
263 static int wlattach(struct isa_device *);
264 void wlintr(int); /* no, not static */
265
266 struct isa_driver wldriver = {
267 wlprobe, wlattach, "wl", 0
268 };
269
270 /*
271 * XXX The Wavelan appears to be prone to dropping stuff if you talk to
272 * it too fast. This disgusting hack inserts a delay after each packet
273 * is queued which helps avoid this behaviour on fast systems.
274 */
275 static int wl_xmit_delay = 250;
276 SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_delay, CTLFLAG_RW, &wl_xmit_delay, 0, "");
277
278 /*
279 * not XXX, but ZZZ (bizarre).
280 * promiscuous mode can be toggled to ignore NWIDs. By default,
281 * it does not. Caution should be exercised about combining
282 * this mode with IFF_ALLMULTI which puts this driver in
283 * promiscuous mode.
284 */
285 static int wl_ignore_nwid = 0;
286 SYSCTL_INT(_machdep, OID_AUTO, wl_ignore_nwid, CTLFLAG_RW, &wl_ignore_nwid, 0, "");
287
288 /*
289 * Emit diagnostics about transmission problems
290 */
291 static int xmt_watch = 0;
292 SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_watch, CTLFLAG_RW, &xmt_watch, 0, "");
293
294 /*
295 * Collect SNR statistics
296 */
297 static int gathersnr = 0;
298 SYSCTL_INT(_machdep, OID_AUTO, wl_gather_snr, CTLFLAG_RW, &gathersnr, 0, "");
299
300 static void wlstart(struct ifnet *ifp);
301 static void wlinit(void *xsc);
302 static int wlioctl(struct ifnet *ifp, int cmd, caddr_t data);
303 static timeout_t wlwatchdog;
304 static void wlxmt(int unt, struct mbuf *m);
305 static int wldiag(int unt);
306 static int wlconfig(int unit);
307 static int wlcmd(int unit, char *str);
308 static void wlmmcstat(int unit);
309 static u_short wlbldru(int unit);
310 static u_short wlmmcread(u_int base, u_short reg);
311 static void wlinitmmc(int unit);
312 static void wlsetirq(int base, int irq);
313 static int wlhwrst(int unit);
314 static void wlrustrt(int unit);
315 static void wlbldcu(int unit);
316 static int wlack(int unit);
317 static int wlread(int unit, u_short fd_p);
318 static void getsnr(int unit);
319 static void wlrcv(int unit);
320 static int wlrequeue(int unit, u_short fd_p);
321 static void wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
322 static void wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
323 static void wltbd(int unit);
324 static void wlgetpsa(int base, u_char *buf);
325 static void wlsetpsa(int unit);
326 static u_short wlpsacrc(u_char *buf);
327 static void wldump(int unit);
328 #ifdef WLCACHE
329 static void wl_cache_store(int, int, struct ether_header *, struct mbuf *);
330 static void wl_cache_zero(int unit);
331 #endif
332 #ifdef MULTICAST
333 # if __FreeBSD < 3
334 static int check_allmulti(int unit);
335 # endif
336 #endif
337
338 /* array for maping irq numbers to values for the irq parameter register */
339 static int irqvals[16] = {
340 0, 0, 0, 0x01, 0x02, 0x04, 0, 0x08, 0, 0, 0x10, 0x20, 0x40, 0, 0, 0x80
341 };
342 /* mask of valid IRQs */
343 #define WL_IRQS (IRQ3|IRQ4|IRQ5|IRQ7|IRQ10|IRQ11|IRQ12|IRQ15)
344
345 /*
346 * wlprobe:
347 *
348 * This function "probes" or checks for the WaveLAN board on the bus to
349 * see if it is there. As far as I can tell, the best break between this
350 * routine and the attach code is to simply determine whether the board
351 * is configured in properly. Currently my approach to this is to write
352 * and read a word from the SRAM on the board being probed. If the word
353 * comes back properly then we assume the board is there. The config
354 * code expects to see a successful return from the probe routine before
355 * attach will be called.
356 *
357 * input : address device is mapped to, and unit # being checked
358 * output : a '1' is returned if the board exists, and a 0 otherwise
359 *
360 */
361 static int
362 wlprobe(struct isa_device *id)
363 {
364 struct wl_softc *sc = &wl_softc[id->id_unit];
365 register short base = id->id_iobase;
366 int unit = id->id_unit;
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 sc->base = base;
446 sc->unit = unit;
447 sc->flags = 0;
448 sc->mode = 0;
449 sc->hacr = HACR_RESET;
450 CMD(unit); /* reset the board */
451 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
452
453 /* clear reset command and set PIO#2 in parameter access mode */
454 sc->hacr = (HACR_DEFAULT & ~HACR_16BITS);
455 CMD(unit);
456
457 /* Read the PSA from the board for our later reference */
458 wlgetpsa(base, sc->psa);
459
460 /* fetch NWID */
461 sc->nwid[0] = sc->psa[WLPSA_NWID];
462 sc->nwid[1] = sc->psa[WLPSA_NWID+1];
463
464 /* fetch MAC address - decide which one first */
465 if (sc->psa[WLPSA_MACSEL] & 1) {
466 j = WLPSA_LOCALMAC;
467 } else {
468 j = WLPSA_UNIMAC;
469 }
470 for(i=0; i < WAVELAN_ADDR_SIZE; ++i) {
471 sc->wl_addr[i] = sc->psa[j + i];
472 }
473
474 /* enter normal 16 bit mode operation */
475 sc->hacr = HACR_DEFAULT;
476 CMD(unit);
477
478 wlinitmmc(unit);
479 outw(PIOR1(base), OFFSET_SCB + 8); /* address of scb_crcerrs */
480 outw(PIOP1(base), 0); /* clear scb_crcerrs */
481 outw(PIOP1(base), 0); /* clear scb_alnerrs */
482 outw(PIOP1(base), 0); /* clear scb_rscerrs */
483 outw(PIOP1(base), 0); /* clear scb_ovrnerrs */
484
485 bzero(ifp, sizeof(ifp));
486 ifp->if_softc = sc;
487 ifp->if_unit = id->id_unit;
488 ifp->if_mtu = WAVELAN_MTU;
489 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
490 #ifdef WLDEBUG
491 ifp->if_flags |= IFF_DEBUG;
492 #endif
493 #if MULTICAST
494 ifp->if_flags |= IFF_MULTICAST;
495 #endif MULTICAST
496 ifp->if_name = "wl";
497 ifp->if_unit = unit;
498 ifp->if_init = wlinit;
499 ifp->if_output = ether_output;
500 ifp->if_start = wlstart;
501 ifp->if_ioctl = wlioctl;
502 ifp->if_timer = 0; /* paranoia */
503 /* no entries
504 ifp->if_watchdog
505 ifp->if_done
506 ifp->if_reset
507 */
508 if_attach(ifp);
509 ether_ifattach(ifp);
510
511 #if NBPFILTER > 0
512 bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
513 #endif
514
515 bcopy(&sc->wl_addr[0], sc->wl_ac.ac_enaddr, WAVELAN_ADDR_SIZE);
516 printf("%s%d: address %6D, NWID 0x%02x%02x", ifp->if_name, ifp->if_unit,
517 sc->wl_ac.ac_enaddr, ":", sc->nwid[0], sc->nwid[1]);
518 if (sc->freq24)
519 printf(", Freq %d MHz",sc->freq24); /* 2.4 Gz */
520 printf("\n"); /* 2.4 Gz */
521
522
523 if (bootverbose)
524 wldump(unit);
525 return(1);
526 }
527
528 /*
529 * Print out interesting information about the 82596.
530 */
531 static void
532 wldump(int unit)
533 {
534 register struct wl_softc *sp = WLSOFTC(unit);
535 int base = sp->base;
536 int i;
537
538 printf("hasr %04x\n", inw(HASR(base)));
539
540 printf("scb at %04x:\n ", OFFSET_SCB);
541 outw(PIOR1(base), OFFSET_SCB);
542 for(i = 0; i < 8; i++)
543 printf("%04x ", inw(PIOP1(base)));
544 printf("\n");
545
546 printf("cu at %04x:\n ", OFFSET_CU);
547 outw(PIOR1(base), OFFSET_CU);
548 for(i = 0; i < 8; i++)
549 printf("%04x ", inw(PIOP1(base)));
550 printf("\n");
551
552 printf("tbd at %04x:\n ", OFFSET_TBD);
553 outw(PIOR1(base), OFFSET_TBD);
554 for(i = 0; i < 4; i++)
555 printf("%04x ", inw(PIOP1(base)));
556 printf("\n");
557 }
558
559 /* Initialize the Modem Management Controller */
560 static void
561 wlinitmmc(int unit)
562 {
563 register struct wl_softc *sp = WLSOFTC(unit);
564 int base = sp->base;
565 int configured;
566 int mode = sp->mode;
567 int i; /* 2.4 Gz */
568
569 /* enter 8 bit operation */
570 sp->hacr = (HACR_DEFAULT & ~HACR_16BITS);
571 CMD(unit);
572
573 configured = sp->psa[WLPSA_CONFIGURED] & 1;
574
575 /*
576 * Set default modem control parameters. Taken from NCR document
577 * 407-0024326 Rev. A
578 */
579 MMC_WRITE(MMC_JABBER_ENABLE, 0x01);
580 MMC_WRITE(MMC_ANTEN_SEL, 0x02);
581 MMC_WRITE(MMC_IFS, 0x20);
582 MMC_WRITE(MMC_MOD_DELAY, 0x04);
583 MMC_WRITE(MMC_JAM_TIME, 0x38);
584 MMC_WRITE(MMC_DECAY_PRM, 0x00); /* obsolete ? */
585 MMC_WRITE(MMC_DECAY_UPDAT_PRM, 0x00);
586 if (!configured) {
587 MMC_WRITE(MMC_LOOPT_SEL, 0x00);
588 if (sp->psa[WLPSA_COMPATNO] & 1) {
589 MMC_WRITE(MMC_THR_PRE_SET, 0x01); /* 0x04 for AT and 0x01 for MCA */
590 } else {
591 MMC_WRITE(MMC_THR_PRE_SET, 0x04); /* 0x04 for AT and 0x01 for MCA */
592 }
593 MMC_WRITE(MMC_QUALITY_THR, 0x03);
594 } else {
595 /* use configuration defaults from parameter storage area */
596 if (sp->psa[WLPSA_NWIDENABLE] & 1) {
597 if ((mode & (MOD_PROM | MOD_ENAL)) && wl_ignore_nwid) {
598 MMC_WRITE(MMC_LOOPT_SEL, 0x40);
599 } else {
600 MMC_WRITE(MMC_LOOPT_SEL, 0x00);
601 }
602 } else {
603 MMC_WRITE(MMC_LOOPT_SEL, 0x40); /* disable network id check */
604 }
605 MMC_WRITE(MMC_THR_PRE_SET, sp->psa[WLPSA_THRESH]);
606 MMC_WRITE(MMC_QUALITY_THR, sp->psa[WLPSA_QUALTHRESH]);
607 }
608 MMC_WRITE(MMC_FREEZE, 0x00);
609 MMC_WRITE(MMC_ENCR_ENABLE, 0x00);
610
611 MMC_WRITE(MMC_NETW_ID_L,sp->nwid[1]); /* set NWID */
612 MMC_WRITE(MMC_NETW_ID_H,sp->nwid[0]);
613
614 /* enter normal 16 bit mode operation */
615 sp->hacr = HACR_DEFAULT;
616 CMD(unit);
617 CMD(unit); /* virtualpc1 needs this! */
618
619 if (sp->psa[WLPSA_COMPATNO]== /* 2.4 Gz: half-card ver */
620 WLPSA_COMPATNO_WL24B) { /* 2.4 Gz */
621 i=sp->chan24<<4; /* 2.4 Gz: position ch # */
622 MMC_WRITE(MMC_EEADDR,i+0x0f); /* 2.4 Gz: named ch, wc=16 */
623 MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+ /* 2.4 Gz: Download Synths */
624 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: Read EEPROM */
625 for (i=0; i<1000; ++i) { /* 2.4 Gz: wait for download */
626 DELAY(40); /* 2.4 Gz */
627 if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and */
628 &(MMC_EECTRLstat_DWLD /* 2.4 Gz: EEBUSY */
629 +MMC_EECTRLstat_EEBUSY))==0) /* 2.4 Gz: */
630 break; /* 2.4 Gz: download finished */
631 } /* 2.4 Gz */
632 if (i==1000) printf("wl: synth load failed\n"); /* 2.4 Gz */
633 MMC_WRITE(MMC_EEADDR,0x61); /* 2.4 Gz: default pwr, wc=2 */
634 MMC_WRITE(MMC_EECTRL,MMC_EECTRL_DWLD+ /* 2.4 Gz: Download Xmit Pwr */
635 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: Read EEPROM */
636 for (i=0; i<1000; ++i) { /* 2.4 Gz: wait for download */
637 DELAY(40); /* 2.4 Gz */
638 if ((wlmmcread(base,MMC_EECTRLstat) /* 2.4 Gz: check DWLD and */
639 &(MMC_EECTRLstat_DWLD /* 2.4 Gz: EEBUSY */
640 +MMC_EECTRLstat_EEBUSY))==0) /* 2.4 Gz: */
641 break; /* 2.4 Gz: download finished */
642 } /* 2.4 Gz */
643 if (i==1000) printf("wl: xmit pwr load failed\n"); /* 2.4 Gz */
644 MMC_WRITE(MMC_ANALCTRL, /* 2.4 Gz: EXT ant+polarity */
645 MMC_ANALCTRL_ANTPOL + /* 2.4 Gz: */
646 MMC_ANALCTRL_EXTANT); /* 2.4 Gz: */
647 i=sp->chan24<<4; /* 2.4 Gz: position ch # */
648 MMC_WRITE(MMC_EEADDR,i); /* 2.4 Gz: get frequency */
649 MMC_WRITE(MMC_EECTRL, /* 2.4 Gz: EEPROM read */
650 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: */
651 DELAY(40); /* 2.4 Gz */
652 i = wlmmcread(base,MMC_EEDATALrv) /* 2.4 Gz: freq val */
653 + (wlmmcread(base,MMC_EEDATAHrv)<<8); /* 2.4 Gz */
654 sp->freq24 = (i>>6)+2400; /* 2.4 Gz: save real freq */
655 }
656 }
657
658 /*
659 * wlinit:
660 *
661 * Another routine that interfaces the "if" layer to this driver.
662 * Simply resets the structures that are used by "upper layers".
663 * As well as calling wlhwrst that does reset the WaveLAN board.
664 *
665 * input : softc pointer for this interface
666 * output : structures (if structs) and board are reset
667 *
668 */
669 static void
670 wlinit(void *xsc)
671 {
672 register struct wl_softc *sc = xsc;
673 struct ifnet *ifp = &sc->wl_if;
674 int stat;
675 u_long oldpri;
676
677 #ifdef WLDEBUG
678 if (sc->wl_if.if_flags & IFF_DEBUG)
679 printf("wl%d: entered wlinit()\n",sc->unit);
680 #endif
681 #if __FreeBSD__ >= 3
682 if (ifp->if_addrhead.tqh_first == (struct ifaddr *)0) {
683 #else
684 if (ifp->if_addrlist == (struct ifaddr *)0) {
685 #endif
686 return;
687 }
688 oldpri = splimp();
689 if ((stat = wlhwrst(sc->unit)) == TRUE) {
690 sc->wl_if.if_flags |= IFF_RUNNING; /* same as DSF_RUNNING */
691 /*
692 * OACTIVE is used by upper-level routines
693 * and must be set
694 */
695 sc->wl_if.if_flags &= ~IFF_OACTIVE; /* same as tbusy below */
696
697 sc->flags |= DSF_RUNNING;
698 sc->tbusy = 0;
699 untimeout(wlwatchdog, sc);
700
701 wlstart(ifp);
702 } else {
703 printf("wl%d init(): trouble resetting board.\n", sc->unit);
704 }
705 splx(oldpri);
706 }
707
708 /*
709 * wlhwrst:
710 *
711 * This routine resets the WaveLAN board that corresponds to the
712 * board number passed in.
713 *
714 * input : board number to do a hardware reset
715 * output : board is reset
716 *
717 */
718 static int
719 wlhwrst(int unit)
720 {
721 register struct wl_softc *sc = WLSOFTC(unit);
722 int i;
723 short base = sc->base;
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);
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 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, int 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 u_short tmp;
1171 struct proc *p = curproc; /* XXX */
1172 int irq, irqval, i, isroot, size;
1173 caddr_t up;
1174 char * cpt;
1175
1176
1177 #ifdef WLDEBUG
1178 if (sc->wl_if.if_flags & IFF_DEBUG)
1179 printf("wl%d: entered wlioctl()\n",unit);
1180 #endif
1181 opri = splimp();
1182 switch (cmd) {
1183 case SIOCSIFADDR:
1184 /* Set own IP address and enable interface */
1185 ifp->if_flags |= IFF_UP;
1186 switch (ifa->ifa_addr->sa_family) {
1187 #ifdef INET
1188 case AF_INET:
1189 wlinit(sc);
1190 arp_ifinit((struct arpcom *)ifp, ifa);
1191 break;
1192 #endif
1193 #ifdef NS
1194 case AF_NS:
1195 {
1196 register struct ns_addr *ina =
1197 &(IA_SNS(ifa)->sns_addr);
1198 if (ns_nullhost(*ina))
1199 ina->x_host = *(union ns_host *)(ds->wl_addr);
1200 else
1201 wlsetaddr(ina->x_host.c_host, unit);
1202 wlinit(sc);
1203 break;
1204 }
1205 #endif
1206 default:
1207 wlinit(sc);
1208 break;
1209 }
1210 break;
1211 case SIOCSIFFLAGS:
1212 if (ifp->if_flags & IFF_ALLMULTI) {
1213 mode |= MOD_ENAL;
1214 }
1215 if (ifp->if_flags & IFF_PROMISC) {
1216 mode |= MOD_PROM;
1217 }
1218 if(ifp->if_flags & IFF_LINK0) {
1219 mode |= MOD_PROM;
1220 }
1221 /*
1222 * force a complete reset if the recieve multicast/
1223 * promiscuous mode changes so that these take
1224 * effect immediately.
1225 *
1226 */
1227 if (sc->mode != mode) {
1228 sc->mode = mode;
1229 if (sc->flags & DSF_RUNNING) {
1230 sc->flags &= ~DSF_RUNNING;
1231 wlinit(sc);
1232 }
1233 }
1234 /* if interface is marked DOWN and still running then
1235 * stop it.
1236 */
1237 if ((ifp->if_flags & IFF_UP) == 0 && sc->flags & DSF_RUNNING) {
1238 printf("wl%d ioctl(): board is not running\n", unit);
1239 sc->flags &= ~DSF_RUNNING;
1240 sc->hacr &= ~HACR_INTRON;
1241 CMD(unit); /* turn off interrupts */
1242 }
1243 /* else if interface is UP and RUNNING, start it
1244 */
1245 else if (ifp->if_flags & IFF_UP && (sc->flags & DSF_RUNNING) == 0) {
1246 wlinit(sc);
1247 }
1248
1249 /* if WLDEBUG set on interface, then printf rf-modem regs
1250 */
1251 if(ifp->if_flags & IFF_DEBUG)
1252 wlmmcstat(unit);
1253 break;
1254 #if MULTICAST
1255 case SIOCADDMULTI:
1256 case SIOCDELMULTI:
1257
1258 #if __FreeBSD__ < 3
1259 if (cmd == SIOCADDMULTI) {
1260 error = ether_addmulti(ifr, &sc->wl_ac);
1261 }
1262 else {
1263 error = ether_delmulti(ifr, &sc->wl_ac);
1264 }
1265
1266 /* see if we should be in all multicast mode
1267 * note that 82586 cannot do that, must simulate with
1268 * promiscuous mode
1269 */
1270 if ( check_allmulti(unit)) {
1271 ifp->if_flags |= IFF_ALLMULTI;
1272 sc->mode |= MOD_ENAL;
1273 sc->flags &= ~DSF_RUNNING;
1274 wlinit(sc);
1275 error = 0;
1276 break;
1277 }
1278
1279 if (error == ENETRESET) {
1280 if(sc->flags & DSF_RUNNING) {
1281 sc->flags &= ~DSF_RUNNING;
1282 wlinit(sc);
1283 }
1284 error = 0;
1285 }
1286 #endif
1287 break;
1288 #endif MULTICAST
1289
1290 /* DEVICE SPECIFIC */
1291
1292
1293 /* copy the PSA out to the caller */
1294 case SIOCGWLPSA:
1295 /* pointer to buffer in user space */
1296 up = (void *)ifr->ifr_data;
1297 /* work out if they're root */
1298 isroot = (suser(p->p_ucred, &p->p_acflag) == 0);
1299
1300 for (i = 0; i < 0x40; i++) {
1301 /* don't hand the DES key out to non-root users */
1302 if ((i > WLPSA_DESKEY) && (i < (WLPSA_DESKEY + 8)) && !isroot)
1303 continue;
1304 if (subyte((up + i), sc->psa[i]))
1305 return(EFAULT);
1306 }
1307 break;
1308
1309
1310 /* copy the PSA in from the caller; we only copy _some_ values */
1311 case SIOCSWLPSA:
1312 /* root only */
1313 if ((error = suser(p->p_ucred, &p->p_acflag)))
1314 break;
1315 error = EINVAL; /* assume the worst */
1316 /* pointer to buffer in user space containing data */
1317 up = (void *)ifr->ifr_data;
1318
1319 /* check validity of input range */
1320 for (i = 0; i < 0x40; i++)
1321 if (fubyte(up + i) < 0)
1322 return(EFAULT);
1323
1324 /* check IRQ value */
1325 irqval = fubyte(up+WLPSA_IRQNO);
1326 for (irq = 15; irq >= 0; irq--)
1327 if(irqvals[irq] == irqval)
1328 break;
1329 if (irq == 0) /* oops */
1330 break;
1331 /* new IRQ */
1332 sc->psa[WLPSA_IRQNO] = irqval;
1333
1334 /* local MAC */
1335 for (i = 0; i < 6; i++)
1336 sc->psa[WLPSA_LOCALMAC+i] = fubyte(up+WLPSA_LOCALMAC+i);
1337
1338 /* MAC select */
1339 sc->psa[WLPSA_MACSEL] = fubyte(up+WLPSA_MACSEL);
1340
1341 /* default nwid */
1342 sc->psa[WLPSA_NWID] = fubyte(up+WLPSA_NWID);
1343 sc->psa[WLPSA_NWID+1] = fubyte(up+WLPSA_NWID+1);
1344
1345 error = 0;
1346 wlsetpsa(unit); /* update the PSA */
1347 break;
1348
1349
1350 /* get the current NWID out of the sc since we stored it there */
1351 case SIOCGWLCNWID:
1352 ifr->ifr_data = (caddr_t) (sc->nwid[0] << 8 | sc->nwid[1]);
1353 break;
1354
1355
1356 /*
1357 * change the nwid dynamically. This
1358 * ONLY changes the radio modem and does not
1359 * change the PSA.
1360 *
1361 * 2 steps:
1362 * 1. save in softc "soft registers"
1363 * 2. save in radio modem (MMC)
1364 */
1365 case SIOCSWLCNWID:
1366 /* root only */
1367 if ((error = suser(p->p_ucred, &p->p_acflag)))
1368 break;
1369 if (!(ifp->if_flags & IFF_UP)) {
1370 error = EIO; /* only allowed while up */
1371 } else {
1372 /*
1373 * soft c nwid shadows radio modem setting
1374 */
1375 sc->nwid[0] = (int)ifr->ifr_data >> 8;
1376 sc->nwid[1] = (int)ifr->ifr_data & 0xff;
1377 MMC_WRITE(MMC_NETW_ID_L,sc->nwid[1]);
1378 MMC_WRITE(MMC_NETW_ID_H,sc->nwid[0]);
1379 }
1380 break;
1381
1382 /* copy the EEPROM in 2.4 Gz WaveMODEM out to the caller */
1383 case SIOCGWLEEPROM:
1384 /* root only */
1385 if ((error = suser(p->p_ucred, &p->p_acflag)))
1386 break;
1387 /* pointer to buffer in user space */
1388 up = (void *)ifr->ifr_data;
1389
1390 for (i=0x00; i<0x80; ++i) { /* 2.4 Gz: size of EEPROM */
1391 MMC_WRITE(MMC_EEADDR,i); /* 2.4 Gz: get frequency */
1392 MMC_WRITE(MMC_EECTRL, /* 2.4 Gz: EEPROM read */
1393 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: */
1394 DELAY(40); /* 2.4 Gz */
1395 if (subyte(up + 2*i , /* 2.4 Gz: pass low byte of */
1396 wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word */
1397 ) return(EFAULT); /* 2.4 Gz: */
1398 if (subyte(up + 2*i+1, /* 2.4 Gz: pass hi byte of */
1399 wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word */
1400 ) return(EFAULT); /* 2.4 Gz: */
1401 }
1402 break;
1403
1404 #ifdef WLCACHE
1405 /* zero (Delete) the wl cache */
1406 case SIOCDWLCACHE:
1407 /* root only */
1408 if ((error = suser(p->p_ucred, &p->p_acflag)))
1409 break;
1410 wl_cache_zero(unit);
1411 break;
1412
1413 /* read out the number of used cache elements */
1414 case SIOCGWLCITEM:
1415 ifr->ifr_data = (caddr_t) sc->w_sigitems;
1416 break;
1417
1418 /* read out the wl cache */
1419 case SIOCGWLCACHE:
1420 /* pointer to buffer in user space */
1421 up = (void *)ifr->ifr_data;
1422 cpt = (char *) &sc->w_sigcache[0];
1423 size = sc->w_sigitems * sizeof(struct w_sigcache);
1424
1425 for (i = 0; i < size; i++) {
1426 if (subyte((up + i), *cpt++))
1427 return(EFAULT);
1428 }
1429 break;
1430 #endif
1431
1432 default:
1433 error = EINVAL;
1434 }
1435 splx(opri);
1436 return (error);
1437 }
1438
1439 /*
1440 * wlwatchdog():
1441 *
1442 * Called if the timer set in wlstart expires before an interrupt is received
1443 * from the wavelan. It seems to lose interrupts sometimes.
1444 * The watchdog routine gets called if the transmitter failed to interrupt
1445 *
1446 * input : which board is timing out
1447 * output : board reset
1448 *
1449 */
1450 static void
1451 wlwatchdog(void *vsc)
1452 {
1453 struct wl_softc *sc = vsc;
1454 int unit = sc->unit;
1455
1456 log(LOG_ERR, "wl%d: wavelan device timeout on xmit\n", unit);
1457 sc->wl_ac.ac_if.if_oerrors++;
1458 wlinit(sc);
1459 }
1460
1461 /*
1462 * wlintr:
1463 *
1464 * This function is the interrupt handler for the WaveLAN
1465 * board. This routine will be called whenever either a packet
1466 * is received, or a packet has successfully been transfered and
1467 * the unit is ready to transmit another packet.
1468 *
1469 * input : board number that interrupted
1470 * output : either a packet is received, or a packet is transfered
1471 *
1472 */
1473 void
1474 wlintr(unit)
1475 int unit;
1476 {
1477 register struct wl_softc *sc = &wl_softc[unit];
1478 scb_t scb;
1479 ac_t cb;
1480 short base = sc->base;
1481 int next, x, opri;
1482 int i, ac_status;
1483 u_short int_type, int_type1;
1484
1485 #ifdef WLDEBUG
1486 if (sc->wl_if.if_flags & IFF_DEBUG)
1487 printf("wl%d: wlintr() called\n",unit);
1488 #endif
1489
1490 if((int_type = inw(HASR(base))) & HASR_MMC_INTR) {
1491 /* handle interrupt from the modem management controler */
1492 /* This will clear the interrupt condition */
1493 (void) wlmmcread(base,MMC_DCE_STATUS); /* ignored for now */
1494 }
1495
1496 if(!(int_type & HASR_INTR)){ /* return if no interrupt from 82586 */
1497 /* commented out. jrb. it happens when reinit occurs
1498 printf("wlintr: int_type %x, dump follows\n", int_type);
1499 wldump(unit);
1500 */
1501 return;
1502 }
1503
1504 if (gathersnr)
1505 getsnr(unit);
1506 for(;;) {
1507 outw(PIOR0(base), OFFSET_SCB + 0); /* get scb status */
1508 int_type = (inw(PIOP0(base)) & SCB_SW_INT);
1509 if (int_type == 0) /* no interrupts left */
1510 break;
1511
1512 int_type1 = wlack(unit); /* acknowledge interrupt(s) */
1513 /* make sure no bits disappeared (others may appear) */
1514 if ((int_type & int_type1) != int_type)
1515 printf("wlack() int bits disappeared : %04x != int_type %04x\n",
1516 int_type1, int_type);
1517 int_type = int_type1; /* go with the new status */
1518 /*
1519 * incoming packet
1520 */
1521 if (int_type & SCB_SW_FR) {
1522 sc->wl_if.if_ipackets++;
1523 wlrcv(unit);
1524 }
1525 /*
1526 * receiver not ready
1527 */
1528 if (int_type & SCB_SW_RNR) {
1529 sc->wl_if.if_ierrors++;
1530 #ifdef WLDEBUG
1531 if (sc->wl_if.if_flags & IFF_DEBUG)
1532 printf("wl%d intr(): receiver overrun! begin_fd = %x\n",
1533 unit, sc->begin_fd);
1534 #endif
1535 wlrustrt(unit);
1536 }
1537 /*
1538 * CU not ready
1539 */
1540 if (int_type & SCB_SW_CNA) {
1541 /*
1542 * At present, we don't care about CNA's. We
1543 * believe they are a side effect of XMT.
1544 */
1545 }
1546 if (int_type & SCB_SW_CX) {
1547 /*
1548 * At present, we only request Interrupt for
1549 * XMT.
1550 */
1551 outw(PIOR1(base), OFFSET_CU); /* get command status */
1552 ac_status = inw(PIOP1(base));
1553
1554 if (xmt_watch) { /* report some anomalies */
1555
1556 if (sc->tbusy == 0) {
1557 printf("wl%d: xmt intr but not busy, CU %04x\n",
1558 unit, ac_status);
1559 }
1560 if (ac_status == 0) {
1561 printf("wl%d: xmt intr but ac_status == 0\n", unit);
1562 }
1563 if (ac_status & AC_SW_A) {
1564 printf("wl%d: xmt aborted\n",unit);
1565 }
1566 #ifdef notdef
1567 if (ac_status & TC_CARRIER) {
1568 printf("wl%d: no carrier\n", unit);
1569 }
1570 #endif notdef
1571 if (ac_status & TC_CLS) {
1572 printf("wl%d: no CTS\n", unit);
1573 }
1574 if (ac_status & TC_DMA) {
1575 printf("wl%d: DMA underrun\n", unit);
1576 }
1577 if (ac_status & TC_DEFER) {
1578 printf("wl%d: xmt deferred\n",unit);
1579 }
1580 if (ac_status & TC_SQE) {
1581 printf("wl%d: heart beat\n", unit);
1582 }
1583 if (ac_status & TC_COLLISION) {
1584 printf("wl%d: too many collisions\n", unit);
1585 }
1586 }
1587 /* if the transmit actually failed, or returned some status */
1588 if ((!(ac_status & AC_SW_OK)) || (ac_status & 0xfff)) {
1589 if (ac_status & (TC_COLLISION | TC_CLS | TC_DMA)) {
1590 sc->wl_if.if_oerrors++;
1591 }
1592 /* count collisions */
1593 sc->wl_if.if_collisions += (ac_status & 0xf);
1594 /* if TC_COLLISION set and collision count zero, 16 collisions */
1595 if ((ac_status & 0x20) == 0x20) {
1596 sc->wl_if.if_collisions += 0x10;
1597 }
1598 }
1599 sc->tbusy = 0;
1600 untimeout(wlwatchdog, sc);
1601 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
1602 wlstart(&(sc->wl_if));
1603 }
1604 }
1605 return;
1606 }
1607
1608 /*
1609 * wlrcv:
1610 *
1611 * This routine is called by the interrupt handler to initiate a
1612 * packet transfer from the board to the "if" layer above this
1613 * driver. This routine checks if a buffer has been successfully
1614 * received by the WaveLAN. If so, the routine wlread is called
1615 * to do the actual transfer of the board data (including the
1616 * ethernet header) into a packet (consisting of an mbuf chain).
1617 *
1618 * input : number of the board to check
1619 * output : if a packet is available, it is "sent up"
1620 *
1621 */
1622 static void
1623 wlrcv(int unit)
1624 {
1625 register struct wl_softc *sc = WLSOFTC(unit);
1626 short base = sc->base;
1627 u_short fd_p, status, offset, link_offset;
1628
1629 #ifdef WLDEBUG
1630 if (sc->wl_if.if_flags & IFF_DEBUG)
1631 printf("wl%d: entered wlrcv()\n",unit);
1632 #endif
1633 for (fd_p = sc->begin_fd; fd_p != I82586NULL; fd_p = sc->begin_fd) {
1634
1635 outw(PIOR0(base), fd_p + 0); /* address of status */
1636 status = inw(PIOP0(base));
1637 outw(PIOR1(base), fd_p + 4); /* address of link_offset */
1638 link_offset = inw(PIOP1(base));
1639 offset = inw(PIOP1(base)); /* rbd_offset */
1640 if (status == 0xffff || offset == 0xffff /*I82586NULL*/) {
1641 if (wlhwrst(unit) != TRUE)
1642 printf("wl%d rcv(): hwrst ffff trouble.\n", unit);
1643 return;
1644 } else if (status & AC_SW_C) {
1645 if (status == (RFD_DONE|RFD_RSC)) {
1646 /* lost one */
1647 #ifdef WLDEBUG
1648 if (sc->wl_if.if_flags & IFF_DEBUG)
1649 printf("wl%d RCV: RSC %x\n", unit, status);
1650 #endif
1651 sc->wl_if.if_ierrors++;
1652 } else if (!(status & RFD_OK)) {
1653 printf("wl%d RCV: !OK %x\n", unit, status);
1654 sc->wl_if.if_ierrors++;
1655 } else if (status & 0xfff) { /* can't happen */
1656 printf("wl%d RCV: ERRs %x\n", unit, status);
1657 sc->wl_if.if_ierrors++;
1658 } else if (!wlread(unit, fd_p))
1659 return;
1660
1661 if (!wlrequeue(unit, fd_p)) {
1662 /* abort on chain error */
1663 if (wlhwrst(unit) != TRUE)
1664 printf("wl%d rcv(): hwrst trouble.\n", unit);
1665 return;
1666 }
1667 sc->begin_fd = link_offset;
1668 } else {
1669 break;
1670 }
1671 }
1672 return;
1673 }
1674
1675 /*
1676 * wlrequeue:
1677 *
1678 * This routine puts rbd's used in the last receive back onto the
1679 * free list for the next receive.
1680 *
1681 */
1682 static int
1683 wlrequeue(int unit, u_short fd_p)
1684 {
1685 register struct wl_softc *sc = WLSOFTC(unit);
1686 short base = sc->base;
1687 fd_t fd;
1688 u_short l_rbdp, f_rbdp, rbd_offset;
1689
1690 outw(PIOR0(base), fd_p + 6);
1691 rbd_offset = inw(PIOP0(base));
1692 if ((f_rbdp = rbd_offset) != I82586NULL) {
1693 l_rbdp = f_rbdp;
1694 for(;;) {
1695 outw(PIOR0(base), l_rbdp + 0); /* address of status */
1696 if(inw(PIOP0(base)) & RBD_SW_EOF)
1697 break;
1698 outw(PIOP0(base), 0);
1699 outw(PIOR0(base), l_rbdp + 2); /* next_rbd_offset */
1700 if((l_rbdp = inw(PIOP0(base))) == I82586NULL)
1701 break;
1702 }
1703 outw(PIOP0(base), 0);
1704 outw(PIOR0(base), l_rbdp + 2); /* next_rbd_offset */
1705 outw(PIOP0(base), I82586NULL);
1706 outw(PIOR0(base), l_rbdp + 8); /* address of size */
1707 outw(PIOP0(base), inw(PIOP0(base)) | AC_CW_EL);
1708 outw(PIOR0(base), sc->end_rbd + 2);
1709 outw(PIOP0(base), f_rbdp); /* end_rbd->next_rbd_offset */
1710 outw(PIOR0(base), sc->end_rbd + 8); /* size */
1711 outw(PIOP0(base), inw(PIOP0(base)) & ~AC_CW_EL);
1712 sc->end_rbd = l_rbdp;
1713 }
1714
1715 fd.status = 0;
1716 fd.command = AC_CW_EL;
1717 fd.link_offset = I82586NULL;
1718 fd.rbd_offset = I82586NULL;
1719 outw(PIOR1(base), fd_p);
1720 outsw(PIOP1(base), &fd, 8/2);
1721
1722 outw(PIOR1(base), sc->end_fd + 2); /* addr of command */
1723 outw(PIOP1(base), 0); /* command = 0 */
1724 outw(PIOP1(base), fd_p); /* end_fd->link_offset = fd_p */
1725 sc->end_fd = fd_p;
1726
1727 return 1;
1728 }
1729
1730 #ifdef WLDEBUG
1731 static int xmt_debug = 0;
1732 #endif WLDEBUG
1733
1734 /*
1735 * wlxmt:
1736 *
1737 * This routine fills in the appropriate registers and memory
1738 * locations on the WaveLAN board and starts the board off on
1739 * the transmit.
1740 *
1741 * input : board number of interest, and a pointer to the mbuf
1742 * output : board memory and registers are set for xfer and attention
1743 *
1744 */
1745 static void
1746 wlxmt(int unit, struct mbuf *m)
1747 {
1748 register struct wl_softc *sc = WLSOFTC(unit);
1749 register u_short xmtdata_p = OFFSET_TBUF;
1750 register u_short xmtshort_p;
1751 struct mbuf *tm_p = m;
1752 register struct ether_header *eh_p = mtod(m, struct ether_header *);
1753 u_char *mb_p = mtod(m, u_char *) + sizeof(struct ether_header);
1754 u_short count = m->m_len - sizeof(struct ether_header);
1755 ac_t cb;
1756 u_short tbd_p = OFFSET_TBD;
1757 u_short len, clen = 0;
1758 short base = sc->base;
1759 int spin;
1760
1761 #ifdef WLDEBUG
1762 if (sc->wl_if.if_flags & IFF_DEBUG)
1763 printf("wl%d: entered wlxmt()\n",unit);
1764 #endif
1765
1766 cb.ac_status = 0;
1767 cb.ac_command = (AC_CW_EL|AC_TRANSMIT|AC_CW_I);
1768 cb.ac_link_offset = I82586NULL;
1769 outw(PIOR1(base), OFFSET_CU);
1770 outsw(PIOP1(base), &cb, 6/2);
1771 outw(PIOP1(base), OFFSET_TBD); /* cb.cmd.transmit.tbd_offset */
1772 outsw(PIOP1(base), eh_p->ether_dhost, WAVELAN_ADDR_SIZE/2);
1773 outw(PIOP1(base), eh_p->ether_type);
1774
1775 #ifdef WLDEBUG
1776 if (sc->wl_if.if_flags & IFF_DEBUG) {
1777 if (xmt_debug) {
1778 printf("XMT mbuf: L%d @%x ", count, mb_p);
1779 printf("ether type %x\n", eh_p->ether_type);
1780 }
1781 }
1782 #endif WLDEBUG
1783 outw(PIOR0(base), OFFSET_TBD);
1784 outw(PIOP0(base), 0); /* act_count */
1785 outw(PIOR1(base), OFFSET_TBD + 4);
1786 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1787 outw(PIOP1(base), 0); /* buffer_base */
1788 for (;;) {
1789 if (count) {
1790 if (clen + count > WAVELAN_MTU)
1791 break;
1792 if (count & 1)
1793 len = count + 1;
1794 else
1795 len = count;
1796 outw(PIOR1(base), xmtdata_p);
1797 outsw(PIOP1(base), mb_p, len/2);
1798 clen += count;
1799 outw(PIOR0(base), tbd_p); /* address of act_count */
1800 outw(PIOP0(base), inw(PIOP0(base)) + count);
1801 xmtdata_p += len;
1802 if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1803 break;
1804 if (count & 1) {
1805 /* go to the next descriptor */
1806 outw(PIOR0(base), tbd_p + 2);
1807 tbd_p += sizeof (tbd_t);
1808 outw(PIOP0(base), tbd_p); /* next_tbd_offset */
1809 outw(PIOR0(base), tbd_p);
1810 outw(PIOP0(base), 0); /* act_count */
1811 outw(PIOR1(base), tbd_p + 4);
1812 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1813 outw(PIOP1(base), 0); /* buffer_base */
1814 /* at the end -> coallesce remaining mbufs */
1815 if (tbd_p == OFFSET_TBD + (N_TBD-1) * sizeof (tbd_t)) {
1816 wlsftwsleaze(&count, &mb_p, &tm_p, unit);
1817 continue;
1818 }
1819 /* next mbuf short -> coallesce as needed */
1820 if ( (tm_p->m_next == (struct mbuf *) 0) ||
1821 #define HDW_THRESHOLD 55
1822 tm_p->m_len > HDW_THRESHOLD)
1823 /* ok */;
1824 else {
1825 wlhdwsleaze(&count, &mb_p, &tm_p, unit);
1826 continue;
1827 }
1828 }
1829 } else if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1830 break;
1831 count = tm_p->m_len;
1832 mb_p = mtod(tm_p, u_char *);
1833 #ifdef WLDEBUG
1834 if (sc->wl_if.if_flags & IFF_DEBUG)
1835 if (xmt_debug)
1836 printf("mbuf+ L%d @%x ", count, mb_p);
1837 #endif WLDEBUG
1838 }
1839 #ifdef WLDEBUG
1840 if (sc->wl_if.if_flags & IFF_DEBUG)
1841 if (xmt_debug)
1842 printf("CLEN = %d\n", clen);
1843 #endif WLDEBUG
1844 outw(PIOR0(base), tbd_p);
1845 if (clen < ETHERMIN) {
1846 outw(PIOP0(base), inw(PIOP0(base)) + ETHERMIN - clen);
1847 outw(PIOR1(base), xmtdata_p);
1848 for (xmtshort_p = xmtdata_p; clen < ETHERMIN; clen += 2)
1849 outw(PIOP1(base), 0);
1850 }
1851 outw(PIOP0(base), inw(PIOP0(base)) | TBD_SW_EOF);
1852 outw(PIOR0(base), tbd_p + 2);
1853 outw(PIOP0(base), I82586NULL);
1854 #ifdef WLDEBUG
1855 if (sc->wl_if.if_flags & IFF_DEBUG) {
1856 if (xmt_debug) {
1857 wltbd(unit);
1858 printf("\n");
1859 }
1860 }
1861 #endif WLDEBUG
1862
1863 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
1864 /*
1865 * wait for 586 to clear previous command, complain if it takes
1866 * too long
1867 */
1868 for (spin = 1;;spin = (spin + 1) % 10000) {
1869 if (inw(PIOP0(base)) == 0) { /* it's done, we can go */
1870 break;
1871 }
1872 if ((spin == 0) && xmt_watch) { /* not waking up, and we care */
1873 printf("wl%d: slow accepting xmit\n",unit);
1874 }
1875 }
1876 outw(PIOP0(base), SCB_CU_STRT); /* new command */
1877 SET_CHAN_ATTN(unit);
1878
1879 m_freem(m);
1880
1881 /* XXX
1882 * Pause to avoid transmit overrun problems.
1883 * The required delay tends to vary with platform type, and may be
1884 * related to interrupt loss.
1885 */
1886 if (wl_xmit_delay) {
1887 DELAY(wl_xmit_delay);
1888 }
1889 return;
1890 }
1891
1892 /*
1893 * wlbldru:
1894 *
1895 * This function builds the linear linked lists of fd's and
1896 * rbd's. Based on page 4-32 of 1986 Intel microcom handbook.
1897 *
1898 */
1899 static u_short
1900 wlbldru(int unit)
1901 {
1902 register struct wl_softc *sc = WLSOFTC(unit);
1903 short base = sc->base;
1904 fd_t fd;
1905 rbd_t rbd;
1906 u_short fd_p = OFFSET_RU;
1907 u_short rbd_p = OFFSET_RBD;
1908 int i;
1909
1910 sc->begin_fd = fd_p;
1911 for(i = 0; i < N_FD; i++) {
1912 fd.status = 0;
1913 fd.command = 0;
1914 fd.link_offset = fd_p + sizeof(fd_t);
1915 fd.rbd_offset = I82586NULL;
1916 outw(PIOR1(base), fd_p);
1917 outsw(PIOP1(base), &fd, 8/2);
1918 fd_p = fd.link_offset;
1919 }
1920 fd_p -= sizeof(fd_t);
1921 sc->end_fd = fd_p;
1922 outw(PIOR1(base), fd_p + 2);
1923 outw(PIOP1(base), AC_CW_EL); /* command */
1924 outw(PIOP1(base), I82586NULL); /* link_offset */
1925 fd_p = OFFSET_RU;
1926
1927 outw(PIOR0(base), fd_p + 6); /* address of rbd_offset */
1928 outw(PIOP0(base), rbd_p);
1929 outw(PIOR1(base), rbd_p);
1930 for(i = 0; i < N_RBD; i++) {
1931 rbd.status = 0;
1932 rbd.buffer_addr = rbd_p + sizeof(rbd_t) + 2;
1933 rbd.buffer_base = 0;
1934 rbd.size = RCVBUFSIZE;
1935 if (i != N_RBD-1) {
1936 rbd_p += sizeof(ru_t);
1937 rbd.next_rbd_offset = rbd_p;
1938 } else {
1939 rbd.next_rbd_offset = I82586NULL;
1940 rbd.size |= AC_CW_EL;
1941 sc->end_rbd = rbd_p;
1942 }
1943 outsw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1944 outw(PIOR1(base), rbd_p);
1945 }
1946 return sc->begin_fd;
1947 }
1948
1949 /*
1950 * wlrustrt:
1951 *
1952 * This routine starts the receive unit running. First checks if the
1953 * board is actually ready, then the board is instructed to receive
1954 * packets again.
1955 *
1956 */
1957 static void
1958 wlrustrt(int unit)
1959 {
1960 register struct wl_softc *sc = WLSOFTC(unit);
1961 short base = sc->base;
1962 u_short rfa;
1963
1964 #ifdef WLDEBUG
1965 if (sc->wl_if.if_flags & IFF_DEBUG)
1966 printf("wl%d: entered wlrustrt()\n",unit);
1967 #endif
1968 outw(PIOR0(base), OFFSET_SCB);
1969 if (inw(PIOP0(base)) & SCB_RUS_READY){
1970 printf("wlrustrt: RUS_READY\n");
1971 return;
1972 }
1973
1974 outw(PIOR0(base), OFFSET_SCB + 2);
1975 outw(PIOP0(base), SCB_RU_STRT); /* command */
1976 rfa = wlbldru(unit);
1977 outw(PIOR0(base), OFFSET_SCB + 6); /* address of scb_rfa_offset */
1978 outw(PIOP0(base), rfa);
1979
1980 SET_CHAN_ATTN(unit);
1981 return;
1982 }
1983
1984 /*
1985 * wldiag:
1986 *
1987 * This routine does a 586 op-code number 7, and obtains the
1988 * diagnose status for the WaveLAN.
1989 *
1990 */
1991 static int
1992 wldiag(int unit)
1993 {
1994 register struct wl_softc *sc = WLSOFTC(unit);
1995 short base = sc->base;
1996 short status;
1997
1998 #ifdef WLDEBUG
1999 if (sc->wl_if.if_flags & IFF_DEBUG)
2000 printf("wl%d: entered wldiag()\n",unit);
2001 #endif
2002 outw(PIOR0(base), OFFSET_SCB);
2003 status = inw(PIOP0(base));
2004 if (status & SCB_SW_INT) {
2005 /* state is 2000 which seems ok
2006 printf("wl%d diag(): unexpected initial state %\n",
2007 unit, inw(PIOP0(base)));
2008 */
2009 wlack(unit);
2010 }
2011 outw(PIOR1(base), OFFSET_CU);
2012 outw(PIOP1(base), 0); /* ac_status */
2013 outw(PIOP1(base), AC_DIAGNOSE|AC_CW_EL);/* ac_command */
2014 if(wlcmd(unit, "diag()") == 0)
2015 return 0;
2016 outw(PIOR0(base), OFFSET_CU);
2017 if (inw(PIOP0(base)) & 0x0800) {
2018 printf("wl%d: i82586 Self Test failed!\n", unit);
2019 return 0;
2020 }
2021 return TRUE;
2022 }
2023
2024 /*
2025 * wlconfig:
2026 *
2027 * This routine does a standard config of the WaveLAN board.
2028 *
2029 */
2030 static int
2031 wlconfig(int unit)
2032 {
2033 configure_t configure;
2034 register struct wl_softc *sc = WLSOFTC(unit);
2035 short base = sc->base;
2036
2037 #if MULTICAST
2038 #if __FreeBSD__ >= 3
2039 struct ifmultiaddr *ifma;
2040 u_char *addrp;
2041 #else
2042 struct ether_multi *enm;
2043 struct ether_multistep step;
2044 #endif
2045 int cnt = 0;
2046 #endif MULTICAST
2047
2048 #ifdef WLDEBUG
2049 if (sc->wl_if.if_flags & IFF_DEBUG)
2050 printf("wl%d: entered wlconfig()\n",unit);
2051 #endif
2052 outw(PIOR0(base), OFFSET_SCB);
2053 if (inw(PIOP0(base)) & SCB_SW_INT) {
2054 /*
2055 printf("wl%d config(): unexpected initial state %x\n",
2056 unit, inw(PIOP0(base)));
2057 */
2058 }
2059 wlack(unit);
2060
2061 outw(PIOR1(base), OFFSET_CU);
2062 outw(PIOP1(base), 0); /* ac_status */
2063 outw(PIOP1(base), AC_CONFIGURE|AC_CW_EL); /* ac_command */
2064
2065 /* jrb hack */
2066 configure.fifolim_bytecnt = 0x080c;
2067 configure.addrlen_mode = 0x0600;
2068 configure.linprio_interframe = 0x2060;
2069 configure.slot_time = 0xf200;
2070 configure.hardware = 0x0008; /* tx even w/o CD */
2071 configure.min_frame_len = 0x0040;
2072 #if 0
2073 /* This is the configuration block suggested by Marc Meertens
2074 * <mmeerten@obelix.utrecht.NCR.COM> in an e-mail message to John
2075 * Ioannidis on 10 Nov 92.
2076 */
2077 configure.fifolim_bytecnt = 0x040c;
2078 configure.addrlen_mode = 0x0600;
2079 configure.linprio_interframe = 0x2060;
2080 configure.slot_time = 0xf000;
2081 configure.hardware = 0x0008; /* tx even w/o CD */
2082 configure.min_frame_len = 0x0040;
2083 #else
2084 /*
2085 * below is the default board configuration from p2-28 from 586 book
2086 */
2087 configure.fifolim_bytecnt = 0x080c;
2088 configure.addrlen_mode = 0x2600;
2089 configure.linprio_interframe = 0x7820; /* IFS=120, ACS=2 */
2090 configure.slot_time = 0xf00c; /* slottime=12 */
2091 configure.hardware = 0x0008; /* tx even w/o CD */
2092 configure.min_frame_len = 0x0040;
2093 #endif
2094 if(sc->mode & (MOD_PROM | MOD_ENAL)) {
2095 configure.hardware |= 1;
2096 }
2097 outw(PIOR1(base), OFFSET_CU + 6);
2098 outsw(PIOP1(base), &configure, sizeof(configure_t)/2);
2099
2100 if(wlcmd(unit, "config()-configure") == 0)
2101 return 0;
2102 #if MULTICAST
2103 outw(PIOR1(base), OFFSET_CU);
2104 outw(PIOP1(base), 0); /* ac_status */
2105 outw(PIOP1(base), AC_MCSETUP|AC_CW_EL); /* ac_command */
2106 outw(PIOR1(base), OFFSET_CU + 8);
2107 #if __FreeBSD__ >= 3
2108 for (ifma = sc->wl_if.if_multiaddrs.lh_first; ifma;
2109 ifma = ifma->ifma_link.le_next) {
2110 if (ifma->ifma_addr->sa_family != AF_LINK)
2111 continue;
2112
2113 addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
2114 outw(PIOP1(base), addrp[0] + (addrp[1] << 8));
2115 outw(PIOP1(base), addrp[2] + (addrp[3] << 8));
2116 outw(PIOP1(base), addrp[4] + (addrp[5] << 8));
2117 ++cnt;
2118 }
2119 #else
2120 ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2121 while (enm != NULL) {
2122 unsigned int lo, hi;
2123 /* break if setting a multicast range, else we would crash */
2124 if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2125 break;
2126 }
2127 lo = (enm->enm_addrlo[3] << 16) + (enm->enm_addrlo[4] << 8)
2128 + enm->enm_addrlo[5];
2129 hi = (enm->enm_addrhi[3] << 16) + (enm->enm_addrhi[4] << 8)
2130 + enm->enm_addrhi[5];
2131 while(lo <= hi) {
2132 outw(PIOP1(base),enm->enm_addrlo[0] +
2133 (enm->enm_addrlo[1] << 8));
2134 outw(PIOP1(base),enm->enm_addrlo[2] +
2135 ((lo >> 8) & 0xff00));
2136 outw(PIOP1(base), ((lo >> 8) & 0xff) +
2137 ((lo << 8) & 0xff00));
2138 /* #define MCASTDEBUG */
2139 #ifdef MCASTDEBUG
2140 printf("mcast_addr[%d,%d,%d] %x %x %x %x %x %x\n", lo, hi, cnt,
2141 enm->enm_addrlo[0],
2142 enm->enm_addrlo[1],
2143 enm->enm_addrlo[2],
2144 enm->enm_addrlo[3],
2145 enm->enm_addrlo[4],
2146 enm->enm_addrlo[5]);
2147 #endif
2148 ++cnt;
2149 ++lo;
2150 }
2151 ETHER_NEXT_MULTI(step, enm);
2152 }
2153 #endif
2154 outw(PIOR1(base), OFFSET_CU + 6); /* mc-cnt */
2155 outw(PIOP1(base), cnt * WAVELAN_ADDR_SIZE);
2156 if(wlcmd(unit, "config()-mcaddress") == 0)
2157 return 0;
2158 #endif MULTICAST
2159
2160 outw(PIOR1(base), OFFSET_CU);
2161 outw(PIOP1(base), 0); /* ac_status */
2162 outw(PIOP1(base), AC_IASETUP|AC_CW_EL); /* ac_command */
2163 outw(PIOR1(base), OFFSET_CU + 6);
2164 outsw(PIOP1(base), sc->wl_addr, WAVELAN_ADDR_SIZE/2);
2165
2166 if(wlcmd(unit, "config()-address") == 0)
2167 return(0);
2168
2169 wlinitmmc(unit);
2170
2171 return(1);
2172 }
2173
2174 /*
2175 * wlcmd:
2176 *
2177 * Set channel attention bit and busy wait until command has
2178 * completed. Then acknowledge the command completion.
2179 */
2180 static int
2181 wlcmd(int unit, char *str)
2182 {
2183 register struct wl_softc *sc = WLSOFTC(unit);
2184 short base = sc->base;
2185 int i;
2186
2187 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
2188 outw(PIOP0(base), SCB_CU_STRT);
2189
2190 SET_CHAN_ATTN(unit);
2191
2192 outw(PIOR0(base), OFFSET_CU);
2193 for(i = 0; i < 0xffff; i++)
2194 if (inw(PIOP0(base)) & AC_SW_C)
2195 break;
2196 if (i == 0xffff || !(inw(PIOP0(base)) & AC_SW_OK)) {
2197 printf("wl%d: %s failed; status = %d, inw = %x, outw = %x\n",
2198 unit, str, inw(PIOP0(base)) & AC_SW_OK, inw(PIOP0(base)), inw(PIOR0(base)));
2199 outw(PIOR0(base), OFFSET_SCB);
2200 printf("scb_status %x\n", inw(PIOP0(base)));
2201 outw(PIOR0(base), OFFSET_SCB+2);
2202 printf("scb_command %x\n", inw(PIOP0(base)));
2203 outw(PIOR0(base), OFFSET_SCB+4);
2204 printf("scb_cbl %x\n", inw(PIOP0(base)));
2205 outw(PIOR0(base), OFFSET_CU+2);
2206 printf("cu_cmd %x\n", inw(PIOP0(base)));
2207 return(0);
2208 }
2209
2210 outw(PIOR0(base), OFFSET_SCB);
2211 if ((inw(PIOP0(base)) & SCB_SW_INT) && (inw(PIOP0(base)) != SCB_SW_CNA)) {
2212 /*
2213 printf("wl%d %s: unexpected final state %x\n",
2214 unit, str, inw(PIOP0(base)));
2215 */
2216 }
2217 wlack(unit);
2218 return(TRUE);
2219 }
2220
2221 /*
2222 * wlack: if the 82596 wants attention because it has finished
2223 * sending or receiving a packet, acknowledge its desire and
2224 * return bits indicating the kind of attention. wlack() returns
2225 * these bits so that the caller can service exactly the
2226 * conditions that wlack() acknowledged.
2227 */
2228 static int
2229 wlack(int unit)
2230 {
2231 int i;
2232 register u_short cmd;
2233 register struct wl_softc *sc = WLSOFTC(unit);
2234 short base = sc->base;
2235
2236 outw(PIOR1(base), OFFSET_SCB);
2237 if(!(cmd = (inw(PIOP1(base)) & SCB_SW_INT)))
2238 return(0);
2239 #ifdef WLDEBUG
2240 if (sc->wl_if.if_flags & IFF_DEBUG)
2241 printf("wl%d: doing a wlack()\n",unit);
2242 #endif
2243 outw(PIOP1(base), cmd);
2244 SET_CHAN_ATTN(unit);
2245 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
2246 for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
2247 if (i < 1)
2248 printf("wl%d wlack(): board not accepting command.\n", unit);
2249 return(cmd);
2250 }
2251
2252 static void
2253 wltbd(int unit)
2254 {
2255 register struct wl_softc *sc = WLSOFTC(unit);
2256 short base = sc->base;
2257 u_short tbd_p = OFFSET_TBD;
2258 tbd_t tbd;
2259 int i = 0;
2260 int sum = 0;
2261
2262 for (;;) {
2263 outw(PIOR1(base), tbd_p);
2264 insw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
2265 sum += (tbd.act_count & ~TBD_SW_EOF);
2266 printf("%d: addr %x, count %d (%d), next %x, base %x\n",
2267 i++, tbd.buffer_addr,
2268 (tbd.act_count & ~TBD_SW_EOF), sum,
2269 tbd.next_tbd_offset, tbd.buffer_base);
2270 if (tbd.act_count & TBD_SW_EOF)
2271 break;
2272 tbd_p = tbd.next_tbd_offset;
2273 }
2274 }
2275
2276 static void
2277 wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2278 {
2279 struct mbuf *tm_p = *tm_pp;
2280 u_char *mb_p = *mb_pp;
2281 u_short count = 0;
2282 u_char *cp;
2283 int len;
2284
2285 /*
2286 * can we get a run that will be coallesced or
2287 * that terminates before breaking
2288 */
2289 do {
2290 count += tm_p->m_len;
2291 if (tm_p->m_len & 1)
2292 break;
2293 } while ((tm_p = tm_p->m_next) != (struct mbuf *)0);
2294 if ( (tm_p == (struct mbuf *)0) ||
2295 count > HDW_THRESHOLD) {
2296 *countp = (*tm_pp)->m_len;
2297 *mb_pp = mtod((*tm_pp), u_char *);
2298 return;
2299 }
2300
2301 /* we need to copy */
2302 tm_p = *tm_pp;
2303 mb_p = *mb_pp;
2304 count = 0;
2305 cp = (u_char *) t_packet;
2306 for (;;) {
2307 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2308 count += len;
2309 if (count > HDW_THRESHOLD)
2310 break;
2311 cp += len;
2312 if (tm_p->m_next == (struct mbuf *)0)
2313 break;
2314 tm_p = tm_p->m_next;
2315 }
2316 *countp = count;
2317 *mb_pp = (u_char *) t_packet;
2318 *tm_pp = tm_p;
2319 return;
2320 }
2321
2322
2323 static void
2324 wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2325 {
2326 struct mbuf *tm_p = *tm_pp;
2327 u_char *mb_p = *mb_pp;
2328 u_short count = 0;
2329 u_char *cp = (u_char *) t_packet;
2330 int len;
2331
2332 /* we need to copy */
2333 for (;;) {
2334 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2335 count += len;
2336 cp += len;
2337 if (tm_p->m_next == (struct mbuf *)0)
2338 break;
2339 tm_p = tm_p->m_next;
2340 }
2341
2342 *countp = count;
2343 *mb_pp = (u_char *) t_packet;
2344 *tm_pp = tm_p;
2345 return;
2346 }
2347
2348 static void
2349 wlmmcstat(int unit)
2350 {
2351 register struct wl_softc *sc = WLSOFTC(unit);
2352 short base = sc->base;
2353 u_short tmp;
2354
2355 printf("wl%d: DCE_STATUS: 0x%x, ", unit,
2356 wlmmcread(base,MMC_DCE_STATUS) & 0x0f);
2357 tmp = wlmmcread(base,MMC_CORRECT_NWID_H) << 8;
2358 tmp |= wlmmcread(base,MMC_CORRECT_NWID_L);
2359 printf("Correct NWID's: %d, ", tmp);
2360 tmp = wlmmcread(base,MMC_WRONG_NWID_H) << 8;
2361 tmp |= wlmmcread(base,MMC_WRONG_NWID_L);
2362 printf("Wrong NWID's: %d\n", tmp);
2363 printf("THR_PRE_SET: 0x%x, ", wlmmcread(base,MMC_THR_PRE_SET));
2364 printf("SIGNAL_LVL: %d, SILENCE_LVL: %d\n",
2365 wlmmcread(base,MMC_SIGNAL_LVL),
2366 wlmmcread(base,MMC_SILENCE_LVL));
2367 printf("SIGN_QUAL: 0x%x, NETW_ID: %x:%x, DES: %d\n",
2368 wlmmcread(base,MMC_SIGN_QUAL),
2369 wlmmcread(base,MMC_NETW_ID_H),
2370 wlmmcread(base,MMC_NETW_ID_L),
2371 wlmmcread(base,MMC_DES_AVAIL));
2372 }
2373
2374 static u_short
2375 wlmmcread(u_int base, u_short reg)
2376 {
2377 while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2378 outw(MMCR(base),reg << 1);
2379 while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2380 return (u_short)inw(MMCR(base)) >> 8;
2381 }
2382
2383 static void
2384 getsnr(int unit)
2385 {
2386 register struct wl_softc *sc = WLSOFTC(unit);
2387 short base = sc->base;
2388 register int s;
2389
2390 MMC_WRITE(MMC_FREEZE,1);
2391 /*
2392 * SNR retrieval procedure :
2393 *
2394 * read signal level : wlmmcread(base, MMC_SIGNAL_LVL);
2395 * read silence level : wlmmcread(base, MMC_SILENCE_LVL);
2396 */
2397 MMC_WRITE(MMC_FREEZE,0);
2398 /*
2399 * SNR is signal:silence ratio.
2400 */
2401 }
2402
2403 /*
2404 ** wlgetpsa
2405 **
2406 ** Reads the psa for the wavelan at (base) into (buf)
2407 */
2408 static void
2409 wlgetpsa(int base, u_char *buf)
2410 {
2411 int i;
2412
2413 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2414 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2415
2416 for (i = 0; i < 0x40; i++) {
2417 outw(PIOR2(base), i);
2418 buf[i] = inb(PIOP2(base));
2419 }
2420 PCMD(base, HACR_DEFAULT);
2421 PCMD(base, HACR_DEFAULT);
2422 }
2423
2424 /*
2425 ** wlsetpsa
2426 **
2427 ** Writes the psa for wavelan (unit) from the softc back to the
2428 ** board. Updates the CRC and sets the CRC OK flag.
2429 **
2430 ** Do not call this when the board is operating, as it doesn't
2431 ** preserve the hacr.
2432 */
2433 static void
2434 wlsetpsa(int unit)
2435 {
2436 register struct wl_softc *sc = WLSOFTC(unit);
2437 short base = sc->base;
2438 int i, oldpri;
2439 u_short crc;
2440
2441 crc = wlpsacrc(sc->psa); /* calculate CRC of PSA */
2442 sc->psa[WLPSA_CRCLOW] = crc & 0xff;
2443 sc->psa[WLPSA_CRCHIGH] = (crc >> 8) & 0xff;
2444 sc->psa[WLPSA_CRCOK] = 0x55; /* default to 'bad' until programming complete */
2445
2446 oldpri = splimp(); /* ick, long pause */
2447
2448 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2449 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2450
2451 for (i = 0; i < 0x40; i++) {
2452 DELAY(DELAYCONST);
2453 outw(PIOR2(base),i); /* write param memory */
2454 DELAY(DELAYCONST);
2455 outb(PIOP2(base), sc->psa[i]);
2456 }
2457 DELAY(DELAYCONST);
2458 outw(PIOR2(base),WLPSA_CRCOK); /* update CRC flag*/
2459 DELAY(DELAYCONST);
2460 sc->psa[WLPSA_CRCOK] = 0xaa; /* OK now */
2461 outb(PIOP2(base), 0xaa); /* all OK */
2462 DELAY(DELAYCONST);
2463
2464 PCMD(base, HACR_DEFAULT);
2465 PCMD(base, HACR_DEFAULT);
2466
2467 splx(oldpri);
2468 }
2469
2470 /*
2471 ** CRC routine provided by Christopher Giordano <cgiordan@gdeb.com>,
2472 ** from original code by Tomi Mikkonen (tomitm@remedy.fi)
2473 */
2474
2475 static u_int crc16_table[16] = {
2476 0x0000, 0xCC01, 0xD801, 0x1400,
2477 0xF001, 0x3C00, 0x2800, 0xE401,
2478 0xA001, 0x6C00, 0x7800, 0xB401,
2479 0x5000, 0x9C01, 0x8801, 0x4400
2480 };
2481
2482 static u_short
2483 wlpsacrc(u_char *buf)
2484 {
2485 u_short crc = 0;
2486 int i, r1;
2487
2488 for (i = 0; i < 0x3d; i++, buf++) {
2489 /* lower 4 bits */
2490 r1 = crc16_table[crc & 0xF];
2491 crc = (crc >> 4) & 0x0FFF;
2492 crc = crc ^ r1 ^ crc16_table[*buf & 0xF];
2493
2494 /* upper 4 bits */
2495 r1 = crc16_table[crc & 0xF];
2496 crc = (crc >> 4) & 0x0FFF;
2497 crc = crc ^ r1 ^ crc16_table[(*buf >> 4) & 0xF];
2498 }
2499 return(crc);
2500 }
2501 #ifdef WLCACHE
2502
2503 /*
2504 * wl_cache_store
2505 *
2506 * take input packet and cache various radio hw characteristics
2507 * indexed by MAC address.
2508 *
2509 * Some things to think about:
2510 * note that no space is malloced.
2511 * We might hash the mac address if the cache were bigger.
2512 * It is not clear that the cache is big enough.
2513 * It is also not clear how big it should be.
2514 * The cache is IP-specific. We don't care about that as
2515 * we want it to be IP-specific.
2516 * The last N recv. packets are saved. This will tend
2517 * to reward agents and mobile hosts that beacon.
2518 * That is probably fine for mobile ip.
2519 */
2520
2521 /* globals for wavelan signal strength cache */
2522 /* this should go into softc structure above.
2523 */
2524
2525 /* set true if you want to limit cache items to broadcast/mcast
2526 * only packets (not unicast)
2527 */
2528 static int wl_cache_mcastonly = 1;
2529 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_mcastonly, CTLFLAG_RW,
2530 &wl_cache_mcastonly, 0, "");
2531
2532 /* set true if you want to limit cache items to IP packets only
2533 */
2534 static int wl_cache_iponly = 1;
2535 SYSCTL_INT(_machdep, OID_AUTO, wl_cache_iponly, CTLFLAG_RW,
2536 &wl_cache_iponly, 0, "");
2537
2538 /* zero out the cache
2539 */
2540 static void
2541 wl_cache_zero(int unit)
2542 {
2543 register struct wl_softc *sc = WLSOFTC(unit);
2544
2545 bzero(&sc->w_sigcache[0], sizeof(struct w_sigcache) * MAXCACHEITEMS);
2546 sc->w_sigitems = 0;
2547 sc->w_nextcache = 0;
2548 sc->w_wrapindex = 0;
2549 }
2550
2551 /* store hw signal info in cache.
2552 * index is MAC address, but an ip src gets stored too
2553 * There are two filters here controllable via sysctl:
2554 * throw out unicast (on by default, but can be turned off)
2555 * throw out non-ip (on by default, but can be turned off)
2556 */
2557 static
2558 void wl_cache_store (int unit, int base, struct ether_header *eh,
2559 struct mbuf *m)
2560 {
2561 struct ip *ip;
2562 int i;
2563 int signal, silence;
2564 int w_insertcache; /* computed index for cache entry storage */
2565 register struct wl_softc *sc = WLSOFTC(unit);
2566 int ipflag = wl_cache_iponly;
2567
2568 /* filters:
2569 * 1. ip only
2570 * 2. configurable filter to throw out unicast packets,
2571 * keep multicast only.
2572 */
2573
2574 /* reject if not IP packet
2575 */
2576 if ( wl_cache_iponly && (ntohs(eh->ether_type) != 0x800)) {
2577 return;
2578 }
2579
2580 /* check if broadcast or multicast packet. we toss
2581 * unicast packets
2582 */
2583 if (wl_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
2584 return;
2585 }
2586
2587 /* find the ip header. we want to store the ip_src
2588 * address. use the mtod macro(in mbuf.h)
2589 * to typecast m to struct ip *
2590 */
2591 if (ipflag) {
2592 ip = mtod(m, struct ip *);
2593 }
2594
2595 /* do a linear search for a matching MAC address
2596 * in the cache table
2597 * . MAC address is 6 bytes,
2598 * . var w_nextcache holds total number of entries already cached
2599 */
2600 for(i = 0; i < sc->w_nextcache; i++) {
2601 if (! bcmp(eh->ether_shost, sc->w_sigcache[i].macsrc, 6 )) {
2602 /* Match!,
2603 * so we already have this entry,
2604 * update the data, and LRU age
2605 */
2606 break;
2607 }
2608 }
2609
2610 /* did we find a matching mac address?
2611 * if yes, then overwrite a previously existing cache entry
2612 */
2613 if (i < sc->w_nextcache ) {
2614 w_insertcache = i;
2615 }
2616 /* else, have a new address entry,so
2617 * add this new entry,
2618 * if table full, then we need to replace entry
2619 */
2620 else {
2621
2622 /* check for space in cache table
2623 * note: w_nextcache also holds number of entries
2624 * added in the cache table
2625 */
2626 if ( sc->w_nextcache < MAXCACHEITEMS ) {
2627 w_insertcache = sc->w_nextcache;
2628 sc->w_nextcache++;
2629 sc->w_sigitems = sc->w_nextcache;
2630 }
2631 /* no space found, so simply wrap with wrap index
2632 * and "zap" the next entry
2633 */
2634 else {
2635 if (sc->w_wrapindex == MAXCACHEITEMS) {
2636 sc->w_wrapindex = 0;
2637 }
2638 w_insertcache = sc->w_wrapindex++;
2639 }
2640 }
2641
2642 /* invariant: w_insertcache now points at some slot
2643 * in cache.
2644 */
2645 if (w_insertcache < 0 || w_insertcache >= MAXCACHEITEMS) {
2646 log(LOG_ERR,
2647 "wl_cache_store, bad index: %d of [0..%d], gross cache error\n",
2648 w_insertcache, MAXCACHEITEMS);
2649 return;
2650 }
2651
2652 /* store items in cache
2653 * .ipsrc
2654 * .macsrc
2655 * .signal (0..63) ,silence (0..63) ,quality (0..15)
2656 */
2657 if (ipflag) {
2658 sc->w_sigcache[w_insertcache].ipsrc = ip->ip_src.s_addr;
2659 }
2660 bcopy( eh->ether_shost, sc->w_sigcache[w_insertcache].macsrc, 6);
2661 signal = sc->w_sigcache[w_insertcache].signal = wlmmcread(base, MMC_SIGNAL_LVL) & 0x3f;
2662 silence = sc->w_sigcache[w_insertcache].silence = wlmmcread(base, MMC_SILENCE_LVL) & 0x3f;
2663 sc->w_sigcache[w_insertcache].quality = wlmmcread(base, MMC_SIGN_QUAL) & 0x0f;
2664 if (signal > 0)
2665 sc->w_sigcache[w_insertcache].snr =
2666 signal - silence;
2667 else
2668 sc->w_sigcache[w_insertcache].snr = 0;
2669
2670 }
2671 #endif /* WLCACHE */
2672
2673 /*
2674 * determine if in all multicast mode or not
2675 *
2676 * returns: 1 if IFF_ALLMULTI should be set
2677 * else 0
2678 */
2679 #ifdef MULTICAST
2680
2681 #if __FreeBSD__ < 3 /* not required */
2682 static int
2683 check_allmulti(int unit)
2684 {
2685 register struct wl_softc *sc = WLSOFTC(unit);
2686 short base = sc->base;
2687 struct ether_multi *enm;
2688 struct ether_multistep step;
2689
2690 ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2691 while (enm != NULL) {
2692 unsigned int lo, hi;
2693 #ifdef MDEBUG
2694 printf("enm_addrlo %x:%x:%x:%x:%x:%x\n", enm->enm_addrlo[0], enm->enm_addrlo[1],
2695 enm->enm_addrlo[2], enm->enm_addrlo[3], enm->enm_addrlo[4],
2696 enm->enm_addrlo[5]);
2697 printf("enm_addrhi %x:%x:%x:%x:%x:%x\n", enm->enm_addrhi[0], enm->enm_addrhi[1],
2698 enm->enm_addrhi[2], enm->enm_addrhi[3], enm->enm_addrhi[4],
2699 enm->enm_addrhi[5]);
2700 #endif
2701 if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2702 return(1);
2703 }
2704 ETHER_NEXT_MULTI(step, enm);
2705 }
2706 return(0);
2707 }
2708 #endif
2709 #endif
Cache object: 8f59ec08893052607c1bf5a8fdcb3464
|