Deleted Added
sdiff udiff text old ( 29677 ) new ( 32350 )
full compact
1/* $Id: if_wl.c,v 1.8 1997/08/25 22:34:25 bde 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.,
135Cupertino, California.
136
137 All Rights Reserved
138
139 Permission to use, copy, modify, and distribute this software and
140its documentation for any purpose and without fee is hereby
141granted, provided that the above copyright notice appears in all
142copies and that both the copyright notice and this permission notice
143appear in supporting documentation, and that the name of Olivetti
144not be used in advertising or publicity pertaining to distribution
145of the software without specific, written prior permission.
146
147 OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
148INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
149IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
150CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
151LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
152NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
153WITH 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
161Permission to use, copy, modify, and distribute this software and
162its documentation for any purpose and without fee is hereby
163granted, provided that the above copyright notice appears in all
164copies and that both the copyright notice and this permission notice
165appear in supporting documentation, and that the name of Intel
166not be used in advertising or publicity pertaining to distribution
167of the software without specific, written prior permission.
168
169INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
170INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
171IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
172CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
173LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
174NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
175WITH 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
231static char t_packet[ETHERMTU + sizeof(struct ether_header) + sizeof(long)];
232
233struct 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 struct callout_handle watchdog_ch;
251#ifdef WLCACHE
252 int w_sigitems; /* number of cached entries */
253 /* array of cache entries */
254 struct w_sigcache w_sigcache[ MAXCACHEITEMS ];
255 int w_nextcache; /* next free cache entry */
256 int w_wrapindex; /* next "free" cache entry */
257#endif
258};
259static struct wl_softc wl_softc[NWL];
260
261#define WLSOFTC(unit) ((struct wl_softc *)(&wl_softc[unit]))
262
263static int wlprobe(struct isa_device *);
264static int wlattach(struct isa_device *);
265void wlintr(int); /* no, not static */
266
267struct 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 */
276static int wl_xmit_delay = 250;
277SYSCTL_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 */
286static int wl_ignore_nwid = 0;
287SYSCTL_INT(_machdep, OID_AUTO, wl_ignore_nwid, CTLFLAG_RW, &wl_ignore_nwid, 0, "");
288
289/*
290 * Emit diagnostics about transmission problems
291 */
292static int xmt_watch = 0;
293SYSCTL_INT(_machdep, OID_AUTO, wl_xmit_watch, CTLFLAG_RW, &xmt_watch, 0, "");
294
295/*
296 * Collect SNR statistics
297 */
298static int gathersnr = 0;
299SYSCTL_INT(_machdep, OID_AUTO, wl_gather_snr, CTLFLAG_RW, &gathersnr, 0, "");
300
301static void wlstart(struct ifnet *ifp);
302static void wlinit(void *xsc);
303static int wlioctl(struct ifnet *ifp, int cmd, caddr_t data);
304static timeout_t wlwatchdog;
305static void wlxmt(int unt, struct mbuf *m);
306static int wldiag(int unt);
307static int wlconfig(int unit);
308static int wlcmd(int unit, char *str);
309static void wlmmcstat(int unit);
310static u_short wlbldru(int unit);
311static u_short wlmmcread(u_int base, u_short reg);
312static void wlinitmmc(int unit);
313static void wlsetirq(int base, int irq);
314static int wlhwrst(int unit);
315static void wlrustrt(int unit);
316static void wlbldcu(int unit);
317static int wlack(int unit);
318static int wlread(int unit, u_short fd_p);
319static void getsnr(int unit);
320static void wlrcv(int unit);
321static int wlrequeue(int unit, u_short fd_p);
322static void wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
323static void wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit);
324static void wltbd(int unit);
325static void wlgetpsa(int base, u_char *buf);
326static void wlsetpsa(int unit);
327static u_short wlpsacrc(u_char *buf);
328static void wldump(int unit);
329#ifdef WLCACHE
330static void wl_cache_store(int, int, struct ether_header *, struct mbuf *);
331static void wl_cache_zero(int unit);
332#endif
333#ifdef MULTICAST
334# if __FreeBSD < 3
335static int check_allmulti(int unit);
336# endif
337#endif
338
339/* array for maping irq numbers to values for the irq parameter register */
340static 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 */
362static int
363wlprobe(struct isa_device *id)
364{
365 struct wl_softc *sc = &wl_softc[id->id_unit];
366 register short base = id->id_iobase;
367 int unit = id->id_unit;
368 char *str = "wl%d: board out of range [0..%d]\n";
369 u_char inbuf[100];
370 unsigned long oldpri;
371 int irq;
372
373 /* TBD. not true.
374 * regular CMD() will not work, since no softc yet
375 */
376#define PCMD(base, hacr) outw((base), (hacr))
377
378 oldpri = splimp();
379 PCMD(base, HACR_RESET); /* reset the board */
380 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
381 PCMD(base, HACR_RESET); /* reset the board */
382 DELAY(DELAYCONST); /* >> 4 clocks at 6MHz */
383 splx(oldpri);
384
385 /* clear reset command and set PIO#1 in autoincrement mode */
386 PCMD(base, HACR_DEFAULT);
387 PCMD(base, HACR_DEFAULT);
388 outw(PIOR1(base), 0); /* go to beginning of RAM */
389 outsw(PIOP1(base), str, strlen(str)/2+1); /* write string */
390
391 outw(PIOR1(base), 0); /* rewind */
392 insw(PIOP1(base), inbuf, strlen(str)/2+1); /* read result */
393
394 if (bcmp(str, inbuf, strlen(str)))
395 return(0);
396
397 sc->chan24 = 0; /* 2.4 Gz: config channel */
398 sc->freq24 = 0; /* 2.4 Gz: frequency */
399
400 /* read the PSA from the board into temporary storage */
401 wlgetpsa(base, inbuf);
402
403 /* We read the IRQ value from the PSA on the board. */
404 for (irq = 15; irq >= 0; irq--)
405 if (irqvals[irq] == inbuf[WLPSA_IRQNO])
406 break;
407 if ((irq == 0) || (irqvals[irq] == 0)){
408 printf("wl%d: PSA corrupt (invalid IRQ value)\n", id->id_unit);
409 id->id_irq = 0; /* no interrupt */
410 } else {
411 /*
412 * If the IRQ requested by the PSA is already claimed by another
413 * device, the board won't work, but the user can still access the
414 * driver to change the IRQ.
415 */
416 id->id_irq = (1<<irq); /* use IRQ from PSA */
417 }
418 return(16);
419}
420
421
422/*
423 * wlattach:
424 *
425 * This function attaches a WaveLAN board to the "system". The rest of
426 * runtime structures are initialized here (this routine is called after
427 * a successful probe of the board). Once the ethernet address is read
428 * and stored, the board's ifnet structure is attached and readied.
429 *
430 * input : isa_dev structure setup in autoconfig
431 * output : board structs and ifnet is setup
432 *
433 */
434static int
435wlattach(struct isa_device *id)
436{
437 struct wl_softc *sc = (struct wl_softc *) &wl_softc[id->id_unit];
438 register short base = id->id_iobase;
439 int i,j;
440 u_char unit = id->id_unit;
441 register struct ifnet *ifp = &sc->wl_if;
442
443#ifdef WLDEBUG
444 printf("wlattach: base %x, unit %d\n", base, unit);
445#endif
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 */
533static void
534wldump(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 */
562static void
563wlinitmmc(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 */
671static void
672wlinit(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 __FreeBSD__ >= 3
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 */
720static int
721wlhwrst(int unit)
722{
723 register struct wl_softc *sc = WLSOFTC(unit);
724 int i;
725 short base = sc->base;
726
727#ifdef WLDEBUG
728 if (sc->wl_if.if_flags & IFF_DEBUG)
729 printf("wl%d: entered wlhwrst()\n",unit);
730#endif
731 sc->hacr = HACR_RESET;
732 CMD(unit); /* reset the board */
733
734 /* clear reset command and set PIO#1 in autoincrement mode */
735 sc->hacr = HACR_DEFAULT;
736 CMD(unit);
737
738#ifdef WLDEBUG
739 if (sc->wl_if.if_flags & IFF_DEBUG)
740 wlmmcstat(unit); /* Display MMC registers */
741#endif WLDEBUG
742 wlbldcu(unit); /* set up command unit structures */
743
744 if (wldiag(unit) == 0)
745 return(0);
746
747 if (wlconfig(unit) == 0)
748 return(0);
749 /*
750 * insert code for loopback test here
751 */
752 wlrustrt(unit); /* start receive unit */
753
754 /* enable interrupts */
755 sc->hacr = (HACR_DEFAULT | HACR_INTRON);
756 CMD(unit);
757
758 return(1);
759}
760
761/*
762 * wlbldcu:
763 *
764 * This function builds up the command unit structures. It inits
765 * the scp, iscp, scb, cb, tbd, and tbuf.
766 *
767 */
768static void
769wlbldcu(int unit)
770{
771 register struct wl_softc *sc = WLSOFTC(unit);
772 short base = sc->base;
773 scp_t scp;
774 iscp_t iscp;
775 scb_t scb;
776 ac_t cb;
777 tbd_t tbd;
778 int i;
779
780 bzero(&scp, sizeof(scp));
781 scp.scp_sysbus = 0;
782 scp.scp_iscp = OFFSET_ISCP;
783 scp.scp_iscp_base = 0;
784 outw(PIOR1(base), OFFSET_SCP);
785 outsw(PIOP1(base), &scp, sizeof(scp_t)/2);
786
787 bzero(&iscp, sizeof(iscp));
788 iscp.iscp_busy = 1;
789 iscp.iscp_scb_offset = OFFSET_SCB;
790 iscp.iscp_scb = 0;
791 iscp.iscp_scb_base = 0;
792 outw(PIOR1(base), OFFSET_ISCP);
793 outsw(PIOP1(base), &iscp, sizeof(iscp_t)/2);
794
795 scb.scb_status = 0;
796 scb.scb_command = SCB_RESET;
797 scb.scb_cbl_offset = OFFSET_CU;
798 scb.scb_rfa_offset = OFFSET_RU;
799 scb.scb_crcerrs = 0;
800 scb.scb_alnerrs = 0;
801 scb.scb_rscerrs = 0;
802 scb.scb_ovrnerrs = 0;
803 outw(PIOR1(base), OFFSET_SCB);
804 outsw(PIOP1(base), &scb, sizeof(scb_t)/2);
805
806 SET_CHAN_ATTN(unit);
807
808 outw(PIOR0(base), OFFSET_ISCP + 0); /* address of iscp_busy */
809 for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
810 if (i <= 0) printf("wl%d bldcu(): iscp_busy timeout.\n", unit);
811 outw(PIOR0(base), OFFSET_SCB + 0); /* address of scb_status */
812 for (i = STATUS_TRIES; i-- > 0; ) {
813 if (inw(PIOP0(base)) == (SCB_SW_CX|SCB_SW_CNA))
814 break;
815 }
816 if (i <= 0)
817 printf("wl%d bldcu(): not ready after reset.\n", unit);
818 wlack(unit);
819
820 cb.ac_status = 0;
821 cb.ac_command = AC_CW_EL; /* NOP */
822 cb.ac_link_offset = OFFSET_CU;
823 outw(PIOR1(base), OFFSET_CU);
824 outsw(PIOP1(base), &cb, 6/2);
825
826 tbd.act_count = 0;
827 tbd.next_tbd_offset = I82586NULL;
828 tbd.buffer_addr = 0;
829 tbd.buffer_base = 0;
830 outw(PIOR1(base), OFFSET_TBD);
831 outsw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
832}
833
834/*
835 * wlstart:
836 *
837 * send a packet
838 *
839 * input : board number
840 * output : stuff sent to board if any there
841 *
842 */
843static void
844wlstart(struct ifnet *ifp)
845{
846 int unit = ifp->if_unit;
847 struct mbuf *m;
848 register struct wl_softc *sc = WLSOFTC(unit);
849 short base = sc->base;
850 int scb_status, cu_status, scb_command;
851
852#ifdef WLDEBUG
853 if (sc->wl_if.if_flags & IFF_DEBUG)
854 printf("wl%d: entered wlstart()\n",unit);
855#endif
856
857 outw(PIOR1(base), OFFSET_CU);
858 cu_status = inw(PIOP1(base));
859 outw(PIOR0(base),OFFSET_SCB + 0); /* scb_status */
860 scb_status = inw(PIOP0(base));
861 outw(PIOR0(base), OFFSET_SCB + 2);
862 scb_command = inw(PIOP0(base));
863
864 /*
865 * don't need OACTIVE check as tbusy here checks to see
866 * if we are already busy
867 */
868 if (sc->tbusy) {
869 if((scb_status & 0x0700) == SCB_CUS_IDLE &&
870 (cu_status & AC_SW_B) == 0){
871 sc->tbusy = 0;
872 untimeout(wlwatchdog, sc, sc->watchdog_ch);
873 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
874 /*
875 * This is probably just a race. The xmt'r is just
876 * became idle but WE have masked interrupts so ...
877 */
878#ifdef WLDEBUG
879 printf("wl%d: CU idle, scb %04x %04x cu %04x\n",
880 unit, scb_status, scb_command, cu_status);
881#endif
882 if (xmt_watch) printf("!!");
883 } else {
884 return; /* genuinely still busy */
885 }
886 } else if((scb_status & 0x0700) == SCB_CUS_ACTV ||
887 (cu_status & AC_SW_B)){
888#ifdef WLDEBUG
889 printf("wl%d: CU unexpectedly busy; scb %04x cu %04x\n",
890 unit, scb_status, cu_status);
891#endif
892 if (xmt_watch) printf("wl%d: busy?!",unit);
893 return; /* hey, why are we busy? */
894 }
895
896 /* get ourselves some data */
897 ifp = &(sc->wl_if);
898 IF_DEQUEUE(&ifp->if_snd, m);
899 if (m != (struct mbuf *)0) {
900#if NBPFILTER > 0
901 /* let BPF see it before we commit it */
902 if (ifp->if_bpf) {
903 bpf_mtap(ifp, m);
904 }
905#endif
906 sc->tbusy++;
907 /* set the watchdog timer so that if the board
908 * fails to interrupt we will restart
909 */
910 /* try 10 ticks, not very long */
911 sc->watchdog_ch = timeout(wlwatchdog, sc, 10);
912 sc->wl_ac.ac_if.if_flags |= IFF_OACTIVE;
913 sc->wl_if.if_opackets++;
914 wlxmt(unit, m);
915 } else {
916 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
917 }
918 return;
919}
920
921/*
922 * wlread:
923 *
924 * This routine does the actual copy of data (including ethernet header
925 * structure) from the WaveLAN to an mbuf chain that will be passed up
926 * to the "if" (network interface) layer. NOTE: we currently
927 * don't handle trailer protocols, so if that is needed, it will
928 * (at least in part) be added here. For simplicities sake, this
929 * routine copies the receive buffers from the board into a local (stack)
930 * buffer until the frame has been copied from the board. Once in
931 * the local buffer, the contents are copied to an mbuf chain that
932 * is then enqueued onto the appropriate "if" queue.
933 *
934 * input : board number, and an frame descriptor address
935 * output : the packet is put into an mbuf chain, and passed up
936 * assumes : if any errors occur, packet is "dropped on the floor"
937 *
938 */
939static int
940wlread(int unit, u_short fd_p)
941{
942 register struct wl_softc *sc = WLSOFTC(unit);
943 register struct ifnet *ifp = &sc->wl_if;
944 short base = sc->base;
945 fd_t fd;
946 struct ether_header eh;
947 struct mbuf *m, *tm;
948 rbd_t rbd;
949 u_char *mb_p;
950 u_short mlen, len, clen;
951 u_short bytes_in_msg, bytes_in_mbuf, bytes;
952
953
954#ifdef WLDEBUG
955 if (sc->wl_if.if_flags & IFF_DEBUG)
956 printf("wl%d: entered wlread()\n",unit);
957#endif
958 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
959 printf("wl%d read(): board is not running.\n", ifp->if_unit);
960 sc->hacr &= ~HACR_INTRON;
961 CMD(unit); /* turn off interrupts */
962 }
963 /* read ether_header info out of device memory. doesn't
964 * go into mbuf. goes directly into eh structure
965 */
966 len = sizeof(struct ether_header); /* 14 bytes */
967 outw(PIOR1(base), fd_p);
968 insw(PIOP1(base), &fd, (sizeof(fd_t) - len)/2);
969 insw(PIOP1(base), &eh, (len-2)/2);
970 eh.ether_type = ntohs(inw(PIOP1(base)));
971#ifdef WLDEBUG
972 if (sc->wl_if.if_flags & IFF_DEBUG) {
973 printf("wlread: rcv packet, type is %x\n", eh.ether_type);
974 }
975#endif
976 /*
977 * WARNING. above is done now in ether_input, above may be
978 * useful for debug. jrb
979 */
980 eh.ether_type = htons(eh.ether_type);
981
982 if (fd.rbd_offset == I82586NULL) {
983 printf("wl%d read(): Invalid buffer\n", unit);
984 if (wlhwrst(unit) != TRUE) {
985 printf("wl%d read(): hwrst trouble.\n", unit);
986 }
987 return 0;
988 }
989
990 outw(PIOR1(base), fd.rbd_offset);
991 insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
992 bytes_in_msg = rbd.status & RBD_SW_COUNT;
993 MGETHDR(m, M_DONTWAIT, MT_DATA);
994 tm = m;
995 if (m == (struct mbuf *)0) {
996 /*
997 * not only do we want to return, we need to drop the packet on
998 * the floor to clear the interrupt.
999 *
1000 */
1001 if (wlhwrst(unit) != TRUE) {
1002 sc->hacr &= ~HACR_INTRON;
1003 CMD(unit); /* turn off interrupts */
1004 printf("wl%d read(): hwrst trouble.\n", unit);
1005 }
1006 return 0;
1007 }
1008 m->m_next = (struct mbuf *) 0;
1009 m->m_pkthdr.rcvif = ifp;
1010 m->m_pkthdr.len = 0; /* don't know this yet */
1011 m->m_len = MHLEN;
1012
1013 /* always use a cluster. jrb
1014 */
1015 MCLGET(m, M_DONTWAIT);
1016 if (m->m_flags & M_EXT) {
1017 m->m_len = MCLBYTES;
1018 }
1019 else {
1020 m_freem(m);
1021 if (wlhwrst(unit) != TRUE) {
1022 sc->hacr &= ~HACR_INTRON;
1023 CMD(unit); /* turn off interrupts */
1024 printf("wl%d read(): hwrst trouble.\n", unit);
1025 }
1026 return 0;
1027 }
1028
1029 mlen = 0;
1030 clen = mlen;
1031 bytes_in_mbuf = m->m_len;
1032 mb_p = mtod(tm, u_char *);
1033 bytes = min(bytes_in_mbuf, bytes_in_msg);
1034 for (;;) {
1035 if (bytes & 1) {
1036 len = bytes + 1;
1037 } else {
1038 len = bytes;
1039 }
1040 outw(PIOR1(base), rbd.buffer_addr);
1041 insw(PIOP1(base), mb_p, len/2);
1042 clen += bytes;
1043 mlen += bytes;
1044
1045 if (!(bytes_in_mbuf -= bytes)) {
1046 MGET(tm->m_next, M_DONTWAIT, MT_DATA);
1047 tm = tm->m_next;
1048 if (tm == (struct mbuf *)0) {
1049 m_freem(m);
1050 printf("wl%d read(): No mbuf nth\n", unit);
1051 if (wlhwrst(unit) != TRUE) {
1052 sc->hacr &= ~HACR_INTRON;
1053 CMD(unit); /* turn off interrupts */
1054 printf("wl%d read(): hwrst trouble.\n", unit);
1055 }
1056 return 0;
1057 }
1058 mlen = 0;
1059 tm->m_len = MLEN;
1060 bytes_in_mbuf = MLEN;
1061 mb_p = mtod(tm, u_char *);
1062 } else {
1063 mb_p += bytes;
1064 }
1065
1066 if (!(bytes_in_msg -= bytes)) {
1067 if (rbd.status & RBD_SW_EOF ||
1068 rbd.next_rbd_offset == I82586NULL) {
1069 tm->m_len = mlen;
1070 break;
1071 } else {
1072 outw(PIOR1(base), rbd.next_rbd_offset);
1073 insw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1074 bytes_in_msg = rbd.status & RBD_SW_COUNT;
1075 }
1076 } else {
1077 rbd.buffer_addr += bytes;
1078 }
1079
1080 bytes = min(bytes_in_mbuf, bytes_in_msg);
1081 }
1082
1083 m->m_pkthdr.len = clen;
1084
1085#ifdef NOTYET
1086 /* due to fact that controller does not support
1087 * all multicast mode, we must filter out unicast packets
1088 * that are not for us.
1089 *
1090 * if we are in all multicast mode and not promiscuous mode
1091 * and packet is unicast and not for us,
1092 * toss the packet
1093 *
1094 * TBD: also discard packets where NWID does not match.
1095 */
1096 if ( (sc->mode & MOD_ENAL) && ((sc->mode & MOD_PROM) != 0) &&
1097 ((eh.ether_dhost[0] & 1) == 0) /* !mcast and !bcast */ &&
1098 (bcmp(eh.ether_dhost, sc->wl_ac.ac_enaddr,
1099 sizeof(eh.ether_dhost)) != 0) ) {
1100 m_freem(m);
1101 return 1;
1102 }
1103#endif
1104#if NBPFILTER > 0
1105 /*
1106 * Check if there's a BPF listener on this interface. If so, hand off
1107 * the raw packet to bpf.
1108 */
1109 if (ifp->if_bpf) {
1110 /* bpf assumes header is in mbufs. It isn't. We can
1111 * fool it without allocating memory as follows.
1112 * Trick borrowed from if_ie.c
1113 */
1114 struct mbuf m0;
1115 m0.m_len = sizeof eh;
1116 m0.m_data = (caddr_t) &eh;
1117 m0.m_next = m;
1118
1119 bpf_mtap(ifp, &m0);
1120
1121 /*
1122 * point of this code is that even though we are in promiscuous
1123 * mode, and due to fact that bpf got packet already, we
1124 * do toss unicast packet not to us so that stacks upstairs
1125 * do not need to weed it out
1126 *
1127 * logic: if promiscuous mode AND not multicast/bcast AND
1128 * not to us, throw away
1129 */
1130 if ((sc->wl_ac.ac_if.if_flags & IFF_PROMISC) &&
1131 (eh.ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
1132 bcmp(eh.ether_dhost, sc->wl_ac.ac_enaddr,
1133 sizeof(eh.ether_dhost)) != 0 ) {
1134 m_freem(m);
1135 return 1;
1136 }
1137 }
1138#endif
1139
1140#ifdef WLDEBUG
1141 if (sc->wl_if.if_flags & IFF_DEBUG)
1142 printf("wl%d: wlrecv %d bytes\n", unit, clen);
1143#endif
1144
1145#ifdef WLCACHE
1146 wl_cache_store(unit, base, &eh, m);
1147#endif
1148
1149 /*
1150 * received packet is now in a chain of mbuf's. next step is
1151 * to pass the packet upwards.
1152 *
1153 */
1154 ether_input(&sc->wl_if, &eh, m);
1155 return 1;
1156}
1157
1158/*
1159 * wlioctl:
1160 *
1161 * This routine processes an ioctl request from the "if" layer
1162 * above.
1163 *
1164 * input : pointer the appropriate "if" struct, command, and data
1165 * output : based on command appropriate action is taken on the
1166 * WaveLAN board(s) or related structures
1167 * return : error is returned containing exit conditions
1168 *
1169 */
1170static int
1171wlioctl(struct ifnet *ifp, int cmd, caddr_t data)
1172{
1173 register struct ifaddr *ifa = (struct ifaddr *)data;
1174 register struct ifreq *ifr = (struct ifreq *)data;
1175 int unit = ifp->if_unit;
1176 register struct wl_softc *sc = WLSOFTC(unit);
1177 short base = sc->base;
1178 short mode = 0;
1179 int opri, error = 0;
1180 u_short tmp;
1181 struct proc *p = curproc; /* XXX */
1182 int irq, irqval, i, isroot, size;
1183 caddr_t up;
1184 char * cpt;
1185
1186
1187#ifdef WLDEBUG
1188 if (sc->wl_if.if_flags & IFF_DEBUG)
1189 printf("wl%d: entered wlioctl()\n",unit);
1190#endif
1191 opri = splimp();
1192 switch (cmd) {
1193 case SIOCSIFADDR:
1194 /* Set own IP address and enable interface */
1195 ifp->if_flags |= IFF_UP;
1196 switch (ifa->ifa_addr->sa_family) {
1197#ifdef INET
1198 case AF_INET:
1199 wlinit(sc);
1200 arp_ifinit((struct arpcom *)ifp, ifa);
1201 break;
1202#endif
1203#ifdef NS
1204 case AF_NS:
1205 {
1206 register struct ns_addr *ina =
1207 &(IA_SNS(ifa)->sns_addr);
1208 if (ns_nullhost(*ina))
1209 ina->x_host = *(union ns_host *)(ds->wl_addr);
1210 else
1211 wlsetaddr(ina->x_host.c_host, unit);
1212 wlinit(sc);
1213 break;
1214 }
1215#endif
1216 default:
1217 wlinit(sc);
1218 break;
1219 }
1220 break;
1221 case SIOCSIFFLAGS:
1222 if (ifp->if_flags & IFF_ALLMULTI) {
1223 mode |= MOD_ENAL;
1224 }
1225 if (ifp->if_flags & IFF_PROMISC) {
1226 mode |= MOD_PROM;
1227 }
1228 if(ifp->if_flags & IFF_LINK0) {
1229 mode |= MOD_PROM;
1230 }
1231 /*
1232 * force a complete reset if the recieve multicast/
1233 * promiscuous mode changes so that these take
1234 * effect immediately.
1235 *
1236 */
1237 if (sc->mode != mode) {
1238 sc->mode = mode;
1239 if (sc->flags & DSF_RUNNING) {
1240 sc->flags &= ~DSF_RUNNING;
1241 wlinit(sc);
1242 }
1243 }
1244 /* if interface is marked DOWN and still running then
1245 * stop it.
1246 */
1247 if ((ifp->if_flags & IFF_UP) == 0 && sc->flags & DSF_RUNNING) {
1248 printf("wl%d ioctl(): board is not running\n", unit);
1249 sc->flags &= ~DSF_RUNNING;
1250 sc->hacr &= ~HACR_INTRON;
1251 CMD(unit); /* turn off interrupts */
1252 }
1253 /* else if interface is UP and RUNNING, start it
1254 */
1255 else if (ifp->if_flags & IFF_UP && (sc->flags & DSF_RUNNING) == 0) {
1256 wlinit(sc);
1257 }
1258
1259 /* if WLDEBUG set on interface, then printf rf-modem regs
1260 */
1261 if(ifp->if_flags & IFF_DEBUG)
1262 wlmmcstat(unit);
1263 break;
1264#if MULTICAST
1265 case SIOCADDMULTI:
1266 case SIOCDELMULTI:
1267
1268#if __FreeBSD__ < 3
1269 if (cmd == SIOCADDMULTI) {
1270 error = ether_addmulti(ifr, &sc->wl_ac);
1271 }
1272 else {
1273 error = ether_delmulti(ifr, &sc->wl_ac);
1274 }
1275
1276 /* see if we should be in all multicast mode
1277 * note that 82586 cannot do that, must simulate with
1278 * promiscuous mode
1279 */
1280 if ( check_allmulti(unit)) {
1281 ifp->if_flags |= IFF_ALLMULTI;
1282 sc->mode |= MOD_ENAL;
1283 sc->flags &= ~DSF_RUNNING;
1284 wlinit(sc);
1285 error = 0;
1286 break;
1287 }
1288
1289 if (error == ENETRESET) {
1290 if(sc->flags & DSF_RUNNING) {
1291 sc->flags &= ~DSF_RUNNING;
1292 wlinit(sc);
1293 }
1294 error = 0;
1295 }
1296#endif
1297 break;
1298#endif MULTICAST
1299
1300 /* DEVICE SPECIFIC */
1301
1302
1303 /* copy the PSA out to the caller */
1304 case SIOCGWLPSA:
1305 /* pointer to buffer in user space */
1306 up = (void *)ifr->ifr_data;
1307 /* work out if they're root */
1308 isroot = (suser(p->p_ucred, &p->p_acflag) == 0);
1309
1310 for (i = 0; i < 0x40; i++) {
1311 /* don't hand the DES key out to non-root users */
1312 if ((i > WLPSA_DESKEY) && (i < (WLPSA_DESKEY + 8)) && !isroot)
1313 continue;
1314 if (subyte((up + i), sc->psa[i]))
1315 return(EFAULT);
1316 }
1317 break;
1318
1319
1320 /* copy the PSA in from the caller; we only copy _some_ values */
1321 case SIOCSWLPSA:
1322 /* root only */
1323 if ((error = suser(p->p_ucred, &p->p_acflag)))
1324 break;
1325 error = EINVAL; /* assume the worst */
1326 /* pointer to buffer in user space containing data */
1327 up = (void *)ifr->ifr_data;
1328
1329 /* check validity of input range */
1330 for (i = 0; i < 0x40; i++)
1331 if (fubyte(up + i) < 0)
1332 return(EFAULT);
1333
1334 /* check IRQ value */
1335 irqval = fubyte(up+WLPSA_IRQNO);
1336 for (irq = 15; irq >= 0; irq--)
1337 if(irqvals[irq] == irqval)
1338 break;
1339 if (irq == 0) /* oops */
1340 break;
1341 /* new IRQ */
1342 sc->psa[WLPSA_IRQNO] = irqval;
1343
1344 /* local MAC */
1345 for (i = 0; i < 6; i++)
1346 sc->psa[WLPSA_LOCALMAC+i] = fubyte(up+WLPSA_LOCALMAC+i);
1347
1348 /* MAC select */
1349 sc->psa[WLPSA_MACSEL] = fubyte(up+WLPSA_MACSEL);
1350
1351 /* default nwid */
1352 sc->psa[WLPSA_NWID] = fubyte(up+WLPSA_NWID);
1353 sc->psa[WLPSA_NWID+1] = fubyte(up+WLPSA_NWID+1);
1354
1355 error = 0;
1356 wlsetpsa(unit); /* update the PSA */
1357 break;
1358
1359
1360 /* get the current NWID out of the sc since we stored it there */
1361 case SIOCGWLCNWID:
1362 ifr->ifr_data = (caddr_t) (sc->nwid[0] << 8 | sc->nwid[1]);
1363 break;
1364
1365
1366 /*
1367 * change the nwid dynamically. This
1368 * ONLY changes the radio modem and does not
1369 * change the PSA.
1370 *
1371 * 2 steps:
1372 * 1. save in softc "soft registers"
1373 * 2. save in radio modem (MMC)
1374 */
1375 case SIOCSWLCNWID:
1376 /* root only */
1377 if ((error = suser(p->p_ucred, &p->p_acflag)))
1378 break;
1379 if (!(ifp->if_flags & IFF_UP)) {
1380 error = EIO; /* only allowed while up */
1381 } else {
1382 /*
1383 * soft c nwid shadows radio modem setting
1384 */
1385 sc->nwid[0] = (int)ifr->ifr_data >> 8;
1386 sc->nwid[1] = (int)ifr->ifr_data & 0xff;
1387 MMC_WRITE(MMC_NETW_ID_L,sc->nwid[1]);
1388 MMC_WRITE(MMC_NETW_ID_H,sc->nwid[0]);
1389 }
1390 break;
1391
1392 /* copy the EEPROM in 2.4 Gz WaveMODEM out to the caller */
1393 case SIOCGWLEEPROM:
1394 /* root only */
1395 if ((error = suser(p->p_ucred, &p->p_acflag)))
1396 break;
1397 /* pointer to buffer in user space */
1398 up = (void *)ifr->ifr_data;
1399
1400 for (i=0x00; i<0x80; ++i) { /* 2.4 Gz: size of EEPROM */
1401 MMC_WRITE(MMC_EEADDR,i); /* 2.4 Gz: get frequency */
1402 MMC_WRITE(MMC_EECTRL, /* 2.4 Gz: EEPROM read */
1403 MMC_EECTRL_EEOP_READ); /* 2.4 Gz: */
1404 DELAY(40); /* 2.4 Gz */
1405 if (subyte(up + 2*i , /* 2.4 Gz: pass low byte of */
1406 wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word */
1407 ) return(EFAULT); /* 2.4 Gz: */
1408 if (subyte(up + 2*i+1, /* 2.4 Gz: pass hi byte of */
1409 wlmmcread(base,MMC_EEDATALrv)) /* 2.4 Gz: EEPROM word */
1410 ) return(EFAULT); /* 2.4 Gz: */
1411 }
1412 break;
1413
1414#ifdef WLCACHE
1415 /* zero (Delete) the wl cache */
1416 case SIOCDWLCACHE:
1417 /* root only */
1418 if ((error = suser(p->p_ucred, &p->p_acflag)))
1419 break;
1420 wl_cache_zero(unit);
1421 break;
1422
1423 /* read out the number of used cache elements */
1424 case SIOCGWLCITEM:
1425 ifr->ifr_data = (caddr_t) sc->w_sigitems;
1426 break;
1427
1428 /* read out the wl cache */
1429 case SIOCGWLCACHE:
1430 /* pointer to buffer in user space */
1431 up = (void *)ifr->ifr_data;
1432 cpt = (char *) &sc->w_sigcache[0];
1433 size = sc->w_sigitems * sizeof(struct w_sigcache);
1434
1435 for (i = 0; i < size; i++) {
1436 if (subyte((up + i), *cpt++))
1437 return(EFAULT);
1438 }
1439 break;
1440#endif
1441
1442 default:
1443 error = EINVAL;
1444 }
1445 splx(opri);
1446 return (error);
1447}
1448
1449/*
1450 * wlwatchdog():
1451 *
1452 * Called if the timer set in wlstart expires before an interrupt is received
1453 * from the wavelan. It seems to lose interrupts sometimes.
1454 * The watchdog routine gets called if the transmitter failed to interrupt
1455 *
1456 * input : which board is timing out
1457 * output : board reset
1458 *
1459 */
1460static void
1461wlwatchdog(void *vsc)
1462{
1463 struct wl_softc *sc = vsc;
1464 int unit = sc->unit;
1465
1466 log(LOG_ERR, "wl%d: wavelan device timeout on xmit\n", unit);
1467 sc->wl_ac.ac_if.if_oerrors++;
1468 wlinit(sc);
1469}
1470
1471/*
1472 * wlintr:
1473 *
1474 * This function is the interrupt handler for the WaveLAN
1475 * board. This routine will be called whenever either a packet
1476 * is received, or a packet has successfully been transfered and
1477 * the unit is ready to transmit another packet.
1478 *
1479 * input : board number that interrupted
1480 * output : either a packet is received, or a packet is transfered
1481 *
1482 */
1483void
1484wlintr(unit)
1485int unit;
1486{
1487 register struct wl_softc *sc = &wl_softc[unit];
1488 scb_t scb;
1489 ac_t cb;
1490 short base = sc->base;
1491 int next, x, opri;
1492 int i, ac_status;
1493 u_short int_type, int_type1;
1494
1495#ifdef WLDEBUG
1496 if (sc->wl_if.if_flags & IFF_DEBUG)
1497 printf("wl%d: wlintr() called\n",unit);
1498#endif
1499
1500 if((int_type = inw(HASR(base))) & HASR_MMC_INTR) {
1501 /* handle interrupt from the modem management controler */
1502 /* This will clear the interrupt condition */
1503 (void) wlmmcread(base,MMC_DCE_STATUS); /* ignored for now */
1504 }
1505
1506 if(!(int_type & HASR_INTR)){ /* return if no interrupt from 82586 */
1507 /* commented out. jrb. it happens when reinit occurs
1508 printf("wlintr: int_type %x, dump follows\n", int_type);
1509 wldump(unit);
1510 */
1511 return;
1512 }
1513
1514 if (gathersnr)
1515 getsnr(unit);
1516 for(;;) {
1517 outw(PIOR0(base), OFFSET_SCB + 0); /* get scb status */
1518 int_type = (inw(PIOP0(base)) & SCB_SW_INT);
1519 if (int_type == 0) /* no interrupts left */
1520 break;
1521
1522 int_type1 = wlack(unit); /* acknowledge interrupt(s) */
1523 /* make sure no bits disappeared (others may appear) */
1524 if ((int_type & int_type1) != int_type)
1525 printf("wlack() int bits disappeared : %04x != int_type %04x\n",
1526 int_type1, int_type);
1527 int_type = int_type1; /* go with the new status */
1528 /*
1529 * incoming packet
1530 */
1531 if (int_type & SCB_SW_FR) {
1532 sc->wl_if.if_ipackets++;
1533 wlrcv(unit);
1534 }
1535 /*
1536 * receiver not ready
1537 */
1538 if (int_type & SCB_SW_RNR) {
1539 sc->wl_if.if_ierrors++;
1540#ifdef WLDEBUG
1541 if (sc->wl_if.if_flags & IFF_DEBUG)
1542 printf("wl%d intr(): receiver overrun! begin_fd = %x\n",
1543 unit, sc->begin_fd);
1544#endif
1545 wlrustrt(unit);
1546 }
1547 /*
1548 * CU not ready
1549 */
1550 if (int_type & SCB_SW_CNA) {
1551 /*
1552 * At present, we don't care about CNA's. We
1553 * believe they are a side effect of XMT.
1554 */
1555 }
1556 if (int_type & SCB_SW_CX) {
1557 /*
1558 * At present, we only request Interrupt for
1559 * XMT.
1560 */
1561 outw(PIOR1(base), OFFSET_CU); /* get command status */
1562 ac_status = inw(PIOP1(base));
1563
1564 if (xmt_watch) { /* report some anomalies */
1565
1566 if (sc->tbusy == 0) {
1567 printf("wl%d: xmt intr but not busy, CU %04x\n",
1568 unit, ac_status);
1569 }
1570 if (ac_status == 0) {
1571 printf("wl%d: xmt intr but ac_status == 0\n", unit);
1572 }
1573 if (ac_status & AC_SW_A) {
1574 printf("wl%d: xmt aborted\n",unit);
1575 }
1576#ifdef notdef
1577 if (ac_status & TC_CARRIER) {
1578 printf("wl%d: no carrier\n", unit);
1579 }
1580#endif notdef
1581 if (ac_status & TC_CLS) {
1582 printf("wl%d: no CTS\n", unit);
1583 }
1584 if (ac_status & TC_DMA) {
1585 printf("wl%d: DMA underrun\n", unit);
1586 }
1587 if (ac_status & TC_DEFER) {
1588 printf("wl%d: xmt deferred\n",unit);
1589 }
1590 if (ac_status & TC_SQE) {
1591 printf("wl%d: heart beat\n", unit);
1592 }
1593 if (ac_status & TC_COLLISION) {
1594 printf("wl%d: too many collisions\n", unit);
1595 }
1596 }
1597 /* if the transmit actually failed, or returned some status */
1598 if ((!(ac_status & AC_SW_OK)) || (ac_status & 0xfff)) {
1599 if (ac_status & (TC_COLLISION | TC_CLS | TC_DMA)) {
1600 sc->wl_if.if_oerrors++;
1601 }
1602 /* count collisions */
1603 sc->wl_if.if_collisions += (ac_status & 0xf);
1604 /* if TC_COLLISION set and collision count zero, 16 collisions */
1605 if ((ac_status & 0x20) == 0x20) {
1606 sc->wl_if.if_collisions += 0x10;
1607 }
1608 }
1609 sc->tbusy = 0;
1610 untimeout(wlwatchdog, sc, sc->watchdog_ch);
1611 sc->wl_ac.ac_if.if_flags &= ~IFF_OACTIVE;
1612 wlstart(&(sc->wl_if));
1613 }
1614 }
1615 return;
1616}
1617
1618/*
1619 * wlrcv:
1620 *
1621 * This routine is called by the interrupt handler to initiate a
1622 * packet transfer from the board to the "if" layer above this
1623 * driver. This routine checks if a buffer has been successfully
1624 * received by the WaveLAN. If so, the routine wlread is called
1625 * to do the actual transfer of the board data (including the
1626 * ethernet header) into a packet (consisting of an mbuf chain).
1627 *
1628 * input : number of the board to check
1629 * output : if a packet is available, it is "sent up"
1630 *
1631 */
1632static void
1633wlrcv(int unit)
1634{
1635 register struct wl_softc *sc = WLSOFTC(unit);
1636 short base = sc->base;
1637 u_short fd_p, status, offset, link_offset;
1638
1639#ifdef WLDEBUG
1640 if (sc->wl_if.if_flags & IFF_DEBUG)
1641 printf("wl%d: entered wlrcv()\n",unit);
1642#endif
1643 for (fd_p = sc->begin_fd; fd_p != I82586NULL; fd_p = sc->begin_fd) {
1644
1645 outw(PIOR0(base), fd_p + 0); /* address of status */
1646 status = inw(PIOP0(base));
1647 outw(PIOR1(base), fd_p + 4); /* address of link_offset */
1648 link_offset = inw(PIOP1(base));
1649 offset = inw(PIOP1(base)); /* rbd_offset */
1650 if (status == 0xffff || offset == 0xffff /*I82586NULL*/) {
1651 if (wlhwrst(unit) != TRUE)
1652 printf("wl%d rcv(): hwrst ffff trouble.\n", unit);
1653 return;
1654 } else if (status & AC_SW_C) {
1655 if (status == (RFD_DONE|RFD_RSC)) {
1656 /* lost one */
1657#ifdef WLDEBUG
1658 if (sc->wl_if.if_flags & IFF_DEBUG)
1659 printf("wl%d RCV: RSC %x\n", unit, status);
1660#endif
1661 sc->wl_if.if_ierrors++;
1662 } else if (!(status & RFD_OK)) {
1663 printf("wl%d RCV: !OK %x\n", unit, status);
1664 sc->wl_if.if_ierrors++;
1665 } else if (status & 0xfff) { /* can't happen */
1666 printf("wl%d RCV: ERRs %x\n", unit, status);
1667 sc->wl_if.if_ierrors++;
1668 } else if (!wlread(unit, fd_p))
1669 return;
1670
1671 if (!wlrequeue(unit, fd_p)) {
1672 /* abort on chain error */
1673 if (wlhwrst(unit) != TRUE)
1674 printf("wl%d rcv(): hwrst trouble.\n", unit);
1675 return;
1676 }
1677 sc->begin_fd = link_offset;
1678 } else {
1679 break;
1680 }
1681 }
1682 return;
1683}
1684
1685/*
1686 * wlrequeue:
1687 *
1688 * This routine puts rbd's used in the last receive back onto the
1689 * free list for the next receive.
1690 *
1691 */
1692static int
1693wlrequeue(int unit, u_short fd_p)
1694{
1695 register struct wl_softc *sc = WLSOFTC(unit);
1696 short base = sc->base;
1697 fd_t fd;
1698 u_short l_rbdp, f_rbdp, rbd_offset;
1699
1700 outw(PIOR0(base), fd_p + 6);
1701 rbd_offset = inw(PIOP0(base));
1702 if ((f_rbdp = rbd_offset) != I82586NULL) {
1703 l_rbdp = f_rbdp;
1704 for(;;) {
1705 outw(PIOR0(base), l_rbdp + 0); /* address of status */
1706 if(inw(PIOP0(base)) & RBD_SW_EOF)
1707 break;
1708 outw(PIOP0(base), 0);
1709 outw(PIOR0(base), l_rbdp + 2); /* next_rbd_offset */
1710 if((l_rbdp = inw(PIOP0(base))) == I82586NULL)
1711 break;
1712 }
1713 outw(PIOP0(base), 0);
1714 outw(PIOR0(base), l_rbdp + 2); /* next_rbd_offset */
1715 outw(PIOP0(base), I82586NULL);
1716 outw(PIOR0(base), l_rbdp + 8); /* address of size */
1717 outw(PIOP0(base), inw(PIOP0(base)) | AC_CW_EL);
1718 outw(PIOR0(base), sc->end_rbd + 2);
1719 outw(PIOP0(base), f_rbdp); /* end_rbd->next_rbd_offset */
1720 outw(PIOR0(base), sc->end_rbd + 8); /* size */
1721 outw(PIOP0(base), inw(PIOP0(base)) & ~AC_CW_EL);
1722 sc->end_rbd = l_rbdp;
1723 }
1724
1725 fd.status = 0;
1726 fd.command = AC_CW_EL;
1727 fd.link_offset = I82586NULL;
1728 fd.rbd_offset = I82586NULL;
1729 outw(PIOR1(base), fd_p);
1730 outsw(PIOP1(base), &fd, 8/2);
1731
1732 outw(PIOR1(base), sc->end_fd + 2); /* addr of command */
1733 outw(PIOP1(base), 0); /* command = 0 */
1734 outw(PIOP1(base), fd_p); /* end_fd->link_offset = fd_p */
1735 sc->end_fd = fd_p;
1736
1737 return 1;
1738}
1739
1740#ifdef WLDEBUG
1741static int xmt_debug = 0;
1742#endif WLDEBUG
1743
1744/*
1745 * wlxmt:
1746 *
1747 * This routine fills in the appropriate registers and memory
1748 * locations on the WaveLAN board and starts the board off on
1749 * the transmit.
1750 *
1751 * input : board number of interest, and a pointer to the mbuf
1752 * output : board memory and registers are set for xfer and attention
1753 *
1754 */
1755static void
1756wlxmt(int unit, struct mbuf *m)
1757{
1758 register struct wl_softc *sc = WLSOFTC(unit);
1759 register u_short xmtdata_p = OFFSET_TBUF;
1760 register u_short xmtshort_p;
1761 struct mbuf *tm_p = m;
1762 register struct ether_header *eh_p = mtod(m, struct ether_header *);
1763 u_char *mb_p = mtod(m, u_char *) + sizeof(struct ether_header);
1764 u_short count = m->m_len - sizeof(struct ether_header);
1765 ac_t cb;
1766 u_short tbd_p = OFFSET_TBD;
1767 u_short len, clen = 0;
1768 short base = sc->base;
1769 int spin;
1770
1771#ifdef WLDEBUG
1772 if (sc->wl_if.if_flags & IFF_DEBUG)
1773 printf("wl%d: entered wlxmt()\n",unit);
1774#endif
1775
1776 cb.ac_status = 0;
1777 cb.ac_command = (AC_CW_EL|AC_TRANSMIT|AC_CW_I);
1778 cb.ac_link_offset = I82586NULL;
1779 outw(PIOR1(base), OFFSET_CU);
1780 outsw(PIOP1(base), &cb, 6/2);
1781 outw(PIOP1(base), OFFSET_TBD); /* cb.cmd.transmit.tbd_offset */
1782 outsw(PIOP1(base), eh_p->ether_dhost, WAVELAN_ADDR_SIZE/2);
1783 outw(PIOP1(base), eh_p->ether_type);
1784
1785#ifdef WLDEBUG
1786 if (sc->wl_if.if_flags & IFF_DEBUG) {
1787 if (xmt_debug) {
1788 printf("XMT mbuf: L%d @%x ", count, mb_p);
1789 printf("ether type %x\n", eh_p->ether_type);
1790 }
1791 }
1792#endif WLDEBUG
1793 outw(PIOR0(base), OFFSET_TBD);
1794 outw(PIOP0(base), 0); /* act_count */
1795 outw(PIOR1(base), OFFSET_TBD + 4);
1796 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1797 outw(PIOP1(base), 0); /* buffer_base */
1798 for (;;) {
1799 if (count) {
1800 if (clen + count > WAVELAN_MTU)
1801 break;
1802 if (count & 1)
1803 len = count + 1;
1804 else
1805 len = count;
1806 outw(PIOR1(base), xmtdata_p);
1807 outsw(PIOP1(base), mb_p, len/2);
1808 clen += count;
1809 outw(PIOR0(base), tbd_p); /* address of act_count */
1810 outw(PIOP0(base), inw(PIOP0(base)) + count);
1811 xmtdata_p += len;
1812 if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1813 break;
1814 if (count & 1) {
1815 /* go to the next descriptor */
1816 outw(PIOR0(base), tbd_p + 2);
1817 tbd_p += sizeof (tbd_t);
1818 outw(PIOP0(base), tbd_p); /* next_tbd_offset */
1819 outw(PIOR0(base), tbd_p);
1820 outw(PIOP0(base), 0); /* act_count */
1821 outw(PIOR1(base), tbd_p + 4);
1822 outw(PIOP1(base), xmtdata_p); /* buffer_addr */
1823 outw(PIOP1(base), 0); /* buffer_base */
1824 /* at the end -> coallesce remaining mbufs */
1825 if (tbd_p == OFFSET_TBD + (N_TBD-1) * sizeof (tbd_t)) {
1826 wlsftwsleaze(&count, &mb_p, &tm_p, unit);
1827 continue;
1828 }
1829 /* next mbuf short -> coallesce as needed */
1830 if ( (tm_p->m_next == (struct mbuf *) 0) ||
1831#define HDW_THRESHOLD 55
1832 tm_p->m_len > HDW_THRESHOLD)
1833 /* ok */;
1834 else {
1835 wlhdwsleaze(&count, &mb_p, &tm_p, unit);
1836 continue;
1837 }
1838 }
1839 } else if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1840 break;
1841 count = tm_p->m_len;
1842 mb_p = mtod(tm_p, u_char *);
1843#ifdef WLDEBUG
1844 if (sc->wl_if.if_flags & IFF_DEBUG)
1845 if (xmt_debug)
1846 printf("mbuf+ L%d @%x ", count, mb_p);
1847#endif WLDEBUG
1848 }
1849#ifdef WLDEBUG
1850 if (sc->wl_if.if_flags & IFF_DEBUG)
1851 if (xmt_debug)
1852 printf("CLEN = %d\n", clen);
1853#endif WLDEBUG
1854 outw(PIOR0(base), tbd_p);
1855 if (clen < ETHERMIN) {
1856 outw(PIOP0(base), inw(PIOP0(base)) + ETHERMIN - clen);
1857 outw(PIOR1(base), xmtdata_p);
1858 for (xmtshort_p = xmtdata_p; clen < ETHERMIN; clen += 2)
1859 outw(PIOP1(base), 0);
1860 }
1861 outw(PIOP0(base), inw(PIOP0(base)) | TBD_SW_EOF);
1862 outw(PIOR0(base), tbd_p + 2);
1863 outw(PIOP0(base), I82586NULL);
1864#ifdef WLDEBUG
1865 if (sc->wl_if.if_flags & IFF_DEBUG) {
1866 if (xmt_debug) {
1867 wltbd(unit);
1868 printf("\n");
1869 }
1870 }
1871#endif WLDEBUG
1872
1873 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
1874 /*
1875 * wait for 586 to clear previous command, complain if it takes
1876 * too long
1877 */
1878 for (spin = 1;;spin = (spin + 1) % 10000) {
1879 if (inw(PIOP0(base)) == 0) { /* it's done, we can go */
1880 break;
1881 }
1882 if ((spin == 0) && xmt_watch) { /* not waking up, and we care */
1883 printf("wl%d: slow accepting xmit\n",unit);
1884 }
1885 }
1886 outw(PIOP0(base), SCB_CU_STRT); /* new command */
1887 SET_CHAN_ATTN(unit);
1888
1889 m_freem(m);
1890
1891 /* XXX
1892 * Pause to avoid transmit overrun problems.
1893 * The required delay tends to vary with platform type, and may be
1894 * related to interrupt loss.
1895 */
1896 if (wl_xmit_delay) {
1897 DELAY(wl_xmit_delay);
1898 }
1899 return;
1900}
1901
1902/*
1903 * wlbldru:
1904 *
1905 * This function builds the linear linked lists of fd's and
1906 * rbd's. Based on page 4-32 of 1986 Intel microcom handbook.
1907 *
1908 */
1909static u_short
1910wlbldru(int unit)
1911{
1912 register struct wl_softc *sc = WLSOFTC(unit);
1913 short base = sc->base;
1914 fd_t fd;
1915 rbd_t rbd;
1916 u_short fd_p = OFFSET_RU;
1917 u_short rbd_p = OFFSET_RBD;
1918 int i;
1919
1920 sc->begin_fd = fd_p;
1921 for(i = 0; i < N_FD; i++) {
1922 fd.status = 0;
1923 fd.command = 0;
1924 fd.link_offset = fd_p + sizeof(fd_t);
1925 fd.rbd_offset = I82586NULL;
1926 outw(PIOR1(base), fd_p);
1927 outsw(PIOP1(base), &fd, 8/2);
1928 fd_p = fd.link_offset;
1929 }
1930 fd_p -= sizeof(fd_t);
1931 sc->end_fd = fd_p;
1932 outw(PIOR1(base), fd_p + 2);
1933 outw(PIOP1(base), AC_CW_EL); /* command */
1934 outw(PIOP1(base), I82586NULL); /* link_offset */
1935 fd_p = OFFSET_RU;
1936
1937 outw(PIOR0(base), fd_p + 6); /* address of rbd_offset */
1938 outw(PIOP0(base), rbd_p);
1939 outw(PIOR1(base), rbd_p);
1940 for(i = 0; i < N_RBD; i++) {
1941 rbd.status = 0;
1942 rbd.buffer_addr = rbd_p + sizeof(rbd_t) + 2;
1943 rbd.buffer_base = 0;
1944 rbd.size = RCVBUFSIZE;
1945 if (i != N_RBD-1) {
1946 rbd_p += sizeof(ru_t);
1947 rbd.next_rbd_offset = rbd_p;
1948 } else {
1949 rbd.next_rbd_offset = I82586NULL;
1950 rbd.size |= AC_CW_EL;
1951 sc->end_rbd = rbd_p;
1952 }
1953 outsw(PIOP1(base), &rbd, sizeof(rbd_t)/2);
1954 outw(PIOR1(base), rbd_p);
1955 }
1956 return sc->begin_fd;
1957}
1958
1959/*
1960 * wlrustrt:
1961 *
1962 * This routine starts the receive unit running. First checks if the
1963 * board is actually ready, then the board is instructed to receive
1964 * packets again.
1965 *
1966 */
1967static void
1968wlrustrt(int unit)
1969{
1970 register struct wl_softc *sc = WLSOFTC(unit);
1971 short base = sc->base;
1972 u_short rfa;
1973
1974#ifdef WLDEBUG
1975 if (sc->wl_if.if_flags & IFF_DEBUG)
1976 printf("wl%d: entered wlrustrt()\n",unit);
1977#endif
1978 outw(PIOR0(base), OFFSET_SCB);
1979 if (inw(PIOP0(base)) & SCB_RUS_READY){
1980 printf("wlrustrt: RUS_READY\n");
1981 return;
1982 }
1983
1984 outw(PIOR0(base), OFFSET_SCB + 2);
1985 outw(PIOP0(base), SCB_RU_STRT); /* command */
1986 rfa = wlbldru(unit);
1987 outw(PIOR0(base), OFFSET_SCB + 6); /* address of scb_rfa_offset */
1988 outw(PIOP0(base), rfa);
1989
1990 SET_CHAN_ATTN(unit);
1991 return;
1992}
1993
1994/*
1995 * wldiag:
1996 *
1997 * This routine does a 586 op-code number 7, and obtains the
1998 * diagnose status for the WaveLAN.
1999 *
2000 */
2001static int
2002wldiag(int unit)
2003{
2004 register struct wl_softc *sc = WLSOFTC(unit);
2005 short base = sc->base;
2006 short status;
2007
2008#ifdef WLDEBUG
2009 if (sc->wl_if.if_flags & IFF_DEBUG)
2010 printf("wl%d: entered wldiag()\n",unit);
2011#endif
2012 outw(PIOR0(base), OFFSET_SCB);
2013 status = inw(PIOP0(base));
2014 if (status & SCB_SW_INT) {
2015 /* state is 2000 which seems ok
2016 printf("wl%d diag(): unexpected initial state %\n",
2017 unit, inw(PIOP0(base)));
2018 */
2019 wlack(unit);
2020 }
2021 outw(PIOR1(base), OFFSET_CU);
2022 outw(PIOP1(base), 0); /* ac_status */
2023 outw(PIOP1(base), AC_DIAGNOSE|AC_CW_EL);/* ac_command */
2024 if(wlcmd(unit, "diag()") == 0)
2025 return 0;
2026 outw(PIOR0(base), OFFSET_CU);
2027 if (inw(PIOP0(base)) & 0x0800) {
2028 printf("wl%d: i82586 Self Test failed!\n", unit);
2029 return 0;
2030 }
2031 return TRUE;
2032}
2033
2034/*
2035 * wlconfig:
2036 *
2037 * This routine does a standard config of the WaveLAN board.
2038 *
2039 */
2040static int
2041wlconfig(int unit)
2042{
2043 configure_t configure;
2044 register struct wl_softc *sc = WLSOFTC(unit);
2045 short base = sc->base;
2046
2047#if MULTICAST
2048#if __FreeBSD__ >= 3
2049 struct ifmultiaddr *ifma;
2050 u_char *addrp;
2051#else
2052 struct ether_multi *enm;
2053 struct ether_multistep step;
2054#endif
2055 int cnt = 0;
2056#endif MULTICAST
2057
2058#ifdef WLDEBUG
2059 if (sc->wl_if.if_flags & IFF_DEBUG)
2060 printf("wl%d: entered wlconfig()\n",unit);
2061#endif
2062 outw(PIOR0(base), OFFSET_SCB);
2063 if (inw(PIOP0(base)) & SCB_SW_INT) {
2064 /*
2065 printf("wl%d config(): unexpected initial state %x\n",
2066 unit, inw(PIOP0(base)));
2067 */
2068 }
2069 wlack(unit);
2070
2071 outw(PIOR1(base), OFFSET_CU);
2072 outw(PIOP1(base), 0); /* ac_status */
2073 outw(PIOP1(base), AC_CONFIGURE|AC_CW_EL); /* ac_command */
2074
2075/* jrb hack */
2076 configure.fifolim_bytecnt = 0x080c;
2077 configure.addrlen_mode = 0x0600;
2078 configure.linprio_interframe = 0x2060;
2079 configure.slot_time = 0xf200;
2080 configure.hardware = 0x0008; /* tx even w/o CD */
2081 configure.min_frame_len = 0x0040;
2082#if 0
2083 /* This is the configuration block suggested by Marc Meertens
2084 * <mmeerten@obelix.utrecht.NCR.COM> in an e-mail message to John
2085 * Ioannidis on 10 Nov 92.
2086 */
2087 configure.fifolim_bytecnt = 0x040c;
2088 configure.addrlen_mode = 0x0600;
2089 configure.linprio_interframe = 0x2060;
2090 configure.slot_time = 0xf000;
2091 configure.hardware = 0x0008; /* tx even w/o CD */
2092 configure.min_frame_len = 0x0040;
2093#else
2094 /*
2095 * below is the default board configuration from p2-28 from 586 book
2096 */
2097 configure.fifolim_bytecnt = 0x080c;
2098 configure.addrlen_mode = 0x2600;
2099 configure.linprio_interframe = 0x7820; /* IFS=120, ACS=2 */
2100 configure.slot_time = 0xf00c; /* slottime=12 */
2101 configure.hardware = 0x0008; /* tx even w/o CD */
2102 configure.min_frame_len = 0x0040;
2103#endif
2104 if(sc->mode & (MOD_PROM | MOD_ENAL)) {
2105 configure.hardware |= 1;
2106 }
2107 outw(PIOR1(base), OFFSET_CU + 6);
2108 outsw(PIOP1(base), &configure, sizeof(configure_t)/2);
2109
2110 if(wlcmd(unit, "config()-configure") == 0)
2111 return 0;
2112#if MULTICAST
2113 outw(PIOR1(base), OFFSET_CU);
2114 outw(PIOP1(base), 0); /* ac_status */
2115 outw(PIOP1(base), AC_MCSETUP|AC_CW_EL); /* ac_command */
2116 outw(PIOR1(base), OFFSET_CU + 8);
2117#if __FreeBSD__ >= 3
2118 for (ifma = sc->wl_if.if_multiaddrs.lh_first; ifma;
2119 ifma = ifma->ifma_link.le_next) {
2120 if (ifma->ifma_addr->sa_family != AF_LINK)
2121 continue;
2122
2123 addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
2124 outw(PIOP1(base), addrp[0] + (addrp[1] << 8));
2125 outw(PIOP1(base), addrp[2] + (addrp[3] << 8));
2126 outw(PIOP1(base), addrp[4] + (addrp[5] << 8));
2127 ++cnt;
2128 }
2129#else
2130 ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2131 while (enm != NULL) {
2132 unsigned int lo, hi;
2133 /* break if setting a multicast range, else we would crash */
2134 if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2135 break;
2136 }
2137 lo = (enm->enm_addrlo[3] << 16) + (enm->enm_addrlo[4] << 8)
2138 + enm->enm_addrlo[5];
2139 hi = (enm->enm_addrhi[3] << 16) + (enm->enm_addrhi[4] << 8)
2140 + enm->enm_addrhi[5];
2141 while(lo <= hi) {
2142 outw(PIOP1(base),enm->enm_addrlo[0] +
2143 (enm->enm_addrlo[1] << 8));
2144 outw(PIOP1(base),enm->enm_addrlo[2] +
2145 ((lo >> 8) & 0xff00));
2146 outw(PIOP1(base), ((lo >> 8) & 0xff) +
2147 ((lo << 8) & 0xff00));
2148/* #define MCASTDEBUG */
2149#ifdef MCASTDEBUG
2150printf("mcast_addr[%d,%d,%d] %x %x %x %x %x %x\n", lo, hi, cnt,
2151 enm->enm_addrlo[0],
2152 enm->enm_addrlo[1],
2153 enm->enm_addrlo[2],
2154 enm->enm_addrlo[3],
2155 enm->enm_addrlo[4],
2156 enm->enm_addrlo[5]);
2157#endif
2158 ++cnt;
2159 ++lo;
2160 }
2161 ETHER_NEXT_MULTI(step, enm);
2162 }
2163#endif
2164 outw(PIOR1(base), OFFSET_CU + 6); /* mc-cnt */
2165 outw(PIOP1(base), cnt * WAVELAN_ADDR_SIZE);
2166 if(wlcmd(unit, "config()-mcaddress") == 0)
2167 return 0;
2168#endif MULTICAST
2169
2170 outw(PIOR1(base), OFFSET_CU);
2171 outw(PIOP1(base), 0); /* ac_status */
2172 outw(PIOP1(base), AC_IASETUP|AC_CW_EL); /* ac_command */
2173 outw(PIOR1(base), OFFSET_CU + 6);
2174 outsw(PIOP1(base), sc->wl_addr, WAVELAN_ADDR_SIZE/2);
2175
2176 if(wlcmd(unit, "config()-address") == 0)
2177 return(0);
2178
2179 wlinitmmc(unit);
2180
2181 return(1);
2182}
2183
2184/*
2185 * wlcmd:
2186 *
2187 * Set channel attention bit and busy wait until command has
2188 * completed. Then acknowledge the command completion.
2189 */
2190static int
2191wlcmd(int unit, char *str)
2192{
2193 register struct wl_softc *sc = WLSOFTC(unit);
2194 short base = sc->base;
2195 int i;
2196
2197 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
2198 outw(PIOP0(base), SCB_CU_STRT);
2199
2200 SET_CHAN_ATTN(unit);
2201
2202 outw(PIOR0(base), OFFSET_CU);
2203 for(i = 0; i < 0xffff; i++)
2204 if (inw(PIOP0(base)) & AC_SW_C)
2205 break;
2206 if (i == 0xffff || !(inw(PIOP0(base)) & AC_SW_OK)) {
2207 printf("wl%d: %s failed; status = %d, inw = %x, outw = %x\n",
2208 unit, str, inw(PIOP0(base)) & AC_SW_OK, inw(PIOP0(base)), inw(PIOR0(base)));
2209 outw(PIOR0(base), OFFSET_SCB);
2210 printf("scb_status %x\n", inw(PIOP0(base)));
2211 outw(PIOR0(base), OFFSET_SCB+2);
2212 printf("scb_command %x\n", inw(PIOP0(base)));
2213 outw(PIOR0(base), OFFSET_SCB+4);
2214 printf("scb_cbl %x\n", inw(PIOP0(base)));
2215 outw(PIOR0(base), OFFSET_CU+2);
2216 printf("cu_cmd %x\n", inw(PIOP0(base)));
2217 return(0);
2218 }
2219
2220 outw(PIOR0(base), OFFSET_SCB);
2221 if ((inw(PIOP0(base)) & SCB_SW_INT) && (inw(PIOP0(base)) != SCB_SW_CNA)) {
2222 /*
2223 printf("wl%d %s: unexpected final state %x\n",
2224 unit, str, inw(PIOP0(base)));
2225 */
2226 }
2227 wlack(unit);
2228 return(TRUE);
2229}
2230
2231/*
2232 * wlack: if the 82596 wants attention because it has finished
2233 * sending or receiving a packet, acknowledge its desire and
2234 * return bits indicating the kind of attention. wlack() returns
2235 * these bits so that the caller can service exactly the
2236 * conditions that wlack() acknowledged.
2237 */
2238static int
2239wlack(int unit)
2240{
2241 int i;
2242 register u_short cmd;
2243 register struct wl_softc *sc = WLSOFTC(unit);
2244 short base = sc->base;
2245
2246 outw(PIOR1(base), OFFSET_SCB);
2247 if(!(cmd = (inw(PIOP1(base)) & SCB_SW_INT)))
2248 return(0);
2249#ifdef WLDEBUG
2250 if (sc->wl_if.if_flags & IFF_DEBUG)
2251 printf("wl%d: doing a wlack()\n",unit);
2252#endif
2253 outw(PIOP1(base), cmd);
2254 SET_CHAN_ATTN(unit);
2255 outw(PIOR0(base), OFFSET_SCB + 2); /* address of scb_command */
2256 for (i = 1000000; inw(PIOP0(base)) && (i-- > 0); );
2257 if (i < 1)
2258 printf("wl%d wlack(): board not accepting command.\n", unit);
2259 return(cmd);
2260}
2261
2262static void
2263wltbd(int unit)
2264{
2265 register struct wl_softc *sc = WLSOFTC(unit);
2266 short base = sc->base;
2267 u_short tbd_p = OFFSET_TBD;
2268 tbd_t tbd;
2269 int i = 0;
2270 int sum = 0;
2271
2272 for (;;) {
2273 outw(PIOR1(base), tbd_p);
2274 insw(PIOP1(base), &tbd, sizeof(tbd_t)/2);
2275 sum += (tbd.act_count & ~TBD_SW_EOF);
2276 printf("%d: addr %x, count %d (%d), next %x, base %x\n",
2277 i++, tbd.buffer_addr,
2278 (tbd.act_count & ~TBD_SW_EOF), sum,
2279 tbd.next_tbd_offset, tbd.buffer_base);
2280 if (tbd.act_count & TBD_SW_EOF)
2281 break;
2282 tbd_p = tbd.next_tbd_offset;
2283 }
2284}
2285
2286static void
2287wlhdwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2288{
2289 struct mbuf *tm_p = *tm_pp;
2290 u_char *mb_p = *mb_pp;
2291 u_short count = 0;
2292 u_char *cp;
2293 int len;
2294
2295 /*
2296 * can we get a run that will be coallesced or
2297 * that terminates before breaking
2298 */
2299 do {
2300 count += tm_p->m_len;
2301 if (tm_p->m_len & 1)
2302 break;
2303 } while ((tm_p = tm_p->m_next) != (struct mbuf *)0);
2304 if ( (tm_p == (struct mbuf *)0) ||
2305 count > HDW_THRESHOLD) {
2306 *countp = (*tm_pp)->m_len;
2307 *mb_pp = mtod((*tm_pp), u_char *);
2308 return;
2309 }
2310
2311 /* we need to copy */
2312 tm_p = *tm_pp;
2313 mb_p = *mb_pp;
2314 count = 0;
2315 cp = (u_char *) t_packet;
2316 for (;;) {
2317 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2318 count += len;
2319 if (count > HDW_THRESHOLD)
2320 break;
2321 cp += len;
2322 if (tm_p->m_next == (struct mbuf *)0)
2323 break;
2324 tm_p = tm_p->m_next;
2325 }
2326 *countp = count;
2327 *mb_pp = (u_char *) t_packet;
2328 *tm_pp = tm_p;
2329 return;
2330}
2331
2332
2333static void
2334wlsftwsleaze(u_short *countp, u_char **mb_pp, struct mbuf **tm_pp, int unit)
2335{
2336 struct mbuf *tm_p = *tm_pp;
2337 u_char *mb_p = *mb_pp;
2338 u_short count = 0;
2339 u_char *cp = (u_char *) t_packet;
2340 int len;
2341
2342 /* we need to copy */
2343 for (;;) {
2344 bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2345 count += len;
2346 cp += len;
2347 if (tm_p->m_next == (struct mbuf *)0)
2348 break;
2349 tm_p = tm_p->m_next;
2350 }
2351
2352 *countp = count;
2353 *mb_pp = (u_char *) t_packet;
2354 *tm_pp = tm_p;
2355 return;
2356}
2357
2358static void
2359wlmmcstat(int unit)
2360{
2361 register struct wl_softc *sc = WLSOFTC(unit);
2362 short base = sc->base;
2363 u_short tmp;
2364
2365 printf("wl%d: DCE_STATUS: 0x%x, ", unit,
2366 wlmmcread(base,MMC_DCE_STATUS) & 0x0f);
2367 tmp = wlmmcread(base,MMC_CORRECT_NWID_H) << 8;
2368 tmp |= wlmmcread(base,MMC_CORRECT_NWID_L);
2369 printf("Correct NWID's: %d, ", tmp);
2370 tmp = wlmmcread(base,MMC_WRONG_NWID_H) << 8;
2371 tmp |= wlmmcread(base,MMC_WRONG_NWID_L);
2372 printf("Wrong NWID's: %d\n", tmp);
2373 printf("THR_PRE_SET: 0x%x, ", wlmmcread(base,MMC_THR_PRE_SET));
2374 printf("SIGNAL_LVL: %d, SILENCE_LVL: %d\n",
2375 wlmmcread(base,MMC_SIGNAL_LVL),
2376 wlmmcread(base,MMC_SILENCE_LVL));
2377 printf("SIGN_QUAL: 0x%x, NETW_ID: %x:%x, DES: %d\n",
2378 wlmmcread(base,MMC_SIGN_QUAL),
2379 wlmmcread(base,MMC_NETW_ID_H),
2380 wlmmcread(base,MMC_NETW_ID_L),
2381 wlmmcread(base,MMC_DES_AVAIL));
2382}
2383
2384static u_short
2385wlmmcread(u_int base, u_short reg)
2386{
2387 while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2388 outw(MMCR(base),reg << 1);
2389 while(inw(HASR(base)) & HASR_MMC_BUSY) ;
2390 return (u_short)inw(MMCR(base)) >> 8;
2391}
2392
2393static void
2394getsnr(int unit)
2395{
2396 register struct wl_softc *sc = WLSOFTC(unit);
2397 short base = sc->base;
2398 register int s;
2399
2400 MMC_WRITE(MMC_FREEZE,1);
2401 /*
2402 * SNR retrieval procedure :
2403 *
2404 * read signal level : wlmmcread(base, MMC_SIGNAL_LVL);
2405 * read silence level : wlmmcread(base, MMC_SILENCE_LVL);
2406 */
2407 MMC_WRITE(MMC_FREEZE,0);
2408 /*
2409 * SNR is signal:silence ratio.
2410 */
2411}
2412
2413/*
2414** wlgetpsa
2415**
2416** Reads the psa for the wavelan at (base) into (buf)
2417*/
2418static void
2419wlgetpsa(int base, u_char *buf)
2420{
2421 int i;
2422
2423 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2424 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2425
2426 for (i = 0; i < 0x40; i++) {
2427 outw(PIOR2(base), i);
2428 buf[i] = inb(PIOP2(base));
2429 }
2430 PCMD(base, HACR_DEFAULT);
2431 PCMD(base, HACR_DEFAULT);
2432}
2433
2434/*
2435** wlsetpsa
2436**
2437** Writes the psa for wavelan (unit) from the softc back to the
2438** board. Updates the CRC and sets the CRC OK flag.
2439**
2440** Do not call this when the board is operating, as it doesn't
2441** preserve the hacr.
2442*/
2443static void
2444wlsetpsa(int unit)
2445{
2446 register struct wl_softc *sc = WLSOFTC(unit);
2447 short base = sc->base;
2448 int i, oldpri;
2449 u_short crc;
2450
2451 crc = wlpsacrc(sc->psa); /* calculate CRC of PSA */
2452 sc->psa[WLPSA_CRCLOW] = crc & 0xff;
2453 sc->psa[WLPSA_CRCHIGH] = (crc >> 8) & 0xff;
2454 sc->psa[WLPSA_CRCOK] = 0x55; /* default to 'bad' until programming complete */
2455
2456 oldpri = splimp(); /* ick, long pause */
2457
2458 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2459 PCMD(base, HACR_DEFAULT & ~HACR_16BITS);
2460
2461 for (i = 0; i < 0x40; i++) {
2462 DELAY(DELAYCONST);
2463 outw(PIOR2(base),i); /* write param memory */
2464 DELAY(DELAYCONST);
2465 outb(PIOP2(base), sc->psa[i]);
2466 }
2467 DELAY(DELAYCONST);
2468 outw(PIOR2(base),WLPSA_CRCOK); /* update CRC flag*/
2469 DELAY(DELAYCONST);
2470 sc->psa[WLPSA_CRCOK] = 0xaa; /* OK now */
2471 outb(PIOP2(base), 0xaa); /* all OK */
2472 DELAY(DELAYCONST);
2473
2474 PCMD(base, HACR_DEFAULT);
2475 PCMD(base, HACR_DEFAULT);
2476
2477 splx(oldpri);
2478}
2479
2480/*
2481** CRC routine provided by Christopher Giordano <cgiordan@gdeb.com>,
2482** from original code by Tomi Mikkonen (tomitm@remedy.fi)
2483*/
2484
2485static u_int crc16_table[16] = {
2486 0x0000, 0xCC01, 0xD801, 0x1400,
2487 0xF001, 0x3C00, 0x2800, 0xE401,
2488 0xA001, 0x6C00, 0x7800, 0xB401,
2489 0x5000, 0x9C01, 0x8801, 0x4400
2490};
2491
2492static u_short
2493wlpsacrc(u_char *buf)
2494{
2495 u_short crc = 0;
2496 int i, r1;
2497
2498 for (i = 0; i < 0x3d; i++, buf++) {
2499 /* lower 4 bits */
2500 r1 = crc16_table[crc & 0xF];
2501 crc = (crc >> 4) & 0x0FFF;
2502 crc = crc ^ r1 ^ crc16_table[*buf & 0xF];
2503
2504 /* upper 4 bits */
2505 r1 = crc16_table[crc & 0xF];
2506 crc = (crc >> 4) & 0x0FFF;
2507 crc = crc ^ r1 ^ crc16_table[(*buf >> 4) & 0xF];
2508 }
2509 return(crc);
2510}
2511#ifdef WLCACHE
2512
2513/*
2514 * wl_cache_store
2515 *
2516 * take input packet and cache various radio hw characteristics
2517 * indexed by MAC address.
2518 *
2519 * Some things to think about:
2520 * note that no space is malloced.
2521 * We might hash the mac address if the cache were bigger.
2522 * It is not clear that the cache is big enough.
2523 * It is also not clear how big it should be.
2524 * The cache is IP-specific. We don't care about that as
2525 * we want it to be IP-specific.
2526 * The last N recv. packets are saved. This will tend
2527 * to reward agents and mobile hosts that beacon.
2528 * That is probably fine for mobile ip.
2529 */
2530
2531/* globals for wavelan signal strength cache */
2532/* this should go into softc structure above.
2533*/
2534
2535/* set true if you want to limit cache items to broadcast/mcast
2536 * only packets (not unicast)
2537 */
2538static int wl_cache_mcastonly = 1;
2539SYSCTL_INT(_machdep, OID_AUTO, wl_cache_mcastonly, CTLFLAG_RW,
2540 &wl_cache_mcastonly, 0, "");
2541
2542/* set true if you want to limit cache items to IP packets only
2543*/
2544static int wl_cache_iponly = 1;
2545SYSCTL_INT(_machdep, OID_AUTO, wl_cache_iponly, CTLFLAG_RW,
2546 &wl_cache_iponly, 0, "");
2547
2548/* zero out the cache
2549*/
2550static void
2551wl_cache_zero(int unit)
2552{
2553 register struct wl_softc *sc = WLSOFTC(unit);
2554
2555 bzero(&sc->w_sigcache[0], sizeof(struct w_sigcache) * MAXCACHEITEMS);
2556 sc->w_sigitems = 0;
2557 sc->w_nextcache = 0;
2558 sc->w_wrapindex = 0;
2559}
2560
2561/* store hw signal info in cache.
2562 * index is MAC address, but an ip src gets stored too
2563 * There are two filters here controllable via sysctl:
2564 * throw out unicast (on by default, but can be turned off)
2565 * throw out non-ip (on by default, but can be turned off)
2566 */
2567static
2568void wl_cache_store (int unit, int base, struct ether_header *eh,
2569 struct mbuf *m)
2570{
2571 struct ip *ip;
2572 int i;
2573 int signal, silence;
2574 int w_insertcache; /* computed index for cache entry storage */
2575 register struct wl_softc *sc = WLSOFTC(unit);
2576 int ipflag = wl_cache_iponly;
2577
2578 /* filters:
2579 * 1. ip only
2580 * 2. configurable filter to throw out unicast packets,
2581 * keep multicast only.
2582 */
2583
2584 /* reject if not IP packet
2585 */
2586 if ( wl_cache_iponly && (ntohs(eh->ether_type) != 0x800)) {
2587 return;
2588 }
2589
2590 /* check if broadcast or multicast packet. we toss
2591 * unicast packets
2592 */
2593 if (wl_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
2594 return;
2595 }
2596
2597 /* find the ip header. we want to store the ip_src
2598 * address. use the mtod macro(in mbuf.h)
2599 * to typecast m to struct ip *
2600 */
2601 if (ipflag) {
2602 ip = mtod(m, struct ip *);
2603 }
2604
2605 /* do a linear search for a matching MAC address
2606 * in the cache table
2607 * . MAC address is 6 bytes,
2608 * . var w_nextcache holds total number of entries already cached
2609 */
2610 for(i = 0; i < sc->w_nextcache; i++) {
2611 if (! bcmp(eh->ether_shost, sc->w_sigcache[i].macsrc, 6 )) {
2612 /* Match!,
2613 * so we already have this entry,
2614 * update the data, and LRU age
2615 */
2616 break;
2617 }
2618 }
2619
2620 /* did we find a matching mac address?
2621 * if yes, then overwrite a previously existing cache entry
2622 */
2623 if (i < sc->w_nextcache ) {
2624 w_insertcache = i;
2625 }
2626 /* else, have a new address entry,so
2627 * add this new entry,
2628 * if table full, then we need to replace entry
2629 */
2630 else {
2631
2632 /* check for space in cache table
2633 * note: w_nextcache also holds number of entries
2634 * added in the cache table
2635 */
2636 if ( sc->w_nextcache < MAXCACHEITEMS ) {
2637 w_insertcache = sc->w_nextcache;
2638 sc->w_nextcache++;
2639 sc->w_sigitems = sc->w_nextcache;
2640 }
2641 /* no space found, so simply wrap with wrap index
2642 * and "zap" the next entry
2643 */
2644 else {
2645 if (sc->w_wrapindex == MAXCACHEITEMS) {
2646 sc->w_wrapindex = 0;
2647 }
2648 w_insertcache = sc->w_wrapindex++;
2649 }
2650 }
2651
2652 /* invariant: w_insertcache now points at some slot
2653 * in cache.
2654 */
2655 if (w_insertcache < 0 || w_insertcache >= MAXCACHEITEMS) {
2656 log(LOG_ERR,
2657 "wl_cache_store, bad index: %d of [0..%d], gross cache error\n",
2658 w_insertcache, MAXCACHEITEMS);
2659 return;
2660 }
2661
2662 /* store items in cache
2663 * .ipsrc
2664 * .macsrc
2665 * .signal (0..63) ,silence (0..63) ,quality (0..15)
2666 */
2667 if (ipflag) {
2668 sc->w_sigcache[w_insertcache].ipsrc = ip->ip_src.s_addr;
2669 }
2670 bcopy( eh->ether_shost, sc->w_sigcache[w_insertcache].macsrc, 6);
2671 signal = sc->w_sigcache[w_insertcache].signal = wlmmcread(base, MMC_SIGNAL_LVL) & 0x3f;
2672 silence = sc->w_sigcache[w_insertcache].silence = wlmmcread(base, MMC_SILENCE_LVL) & 0x3f;
2673 sc->w_sigcache[w_insertcache].quality = wlmmcread(base, MMC_SIGN_QUAL) & 0x0f;
2674 if (signal > 0)
2675 sc->w_sigcache[w_insertcache].snr =
2676 signal - silence;
2677 else
2678 sc->w_sigcache[w_insertcache].snr = 0;
2679
2680}
2681#endif /* WLCACHE */
2682
2683/*
2684 * determine if in all multicast mode or not
2685 *
2686 * returns: 1 if IFF_ALLMULTI should be set
2687 * else 0
2688 */
2689#ifdef MULTICAST
2690
2691#if __FreeBSD__ < 3 /* not required */
2692static int
2693check_allmulti(int unit)
2694{
2695 register struct wl_softc *sc = WLSOFTC(unit);
2696 short base = sc->base;
2697 struct ether_multi *enm;
2698 struct ether_multistep step;
2699
2700 ETHER_FIRST_MULTI(step, &sc->wl_ac, enm);
2701 while (enm != NULL) {
2702 unsigned int lo, hi;
2703#ifdef MDEBUG
2704 printf("enm_addrlo %x:%x:%x:%x:%x:%x\n", enm->enm_addrlo[0], enm->enm_addrlo[1],
2705 enm->enm_addrlo[2], enm->enm_addrlo[3], enm->enm_addrlo[4],
2706 enm->enm_addrlo[5]);
2707 printf("enm_addrhi %x:%x:%x:%x:%x:%x\n", enm->enm_addrhi[0], enm->enm_addrhi[1],
2708 enm->enm_addrhi[2], enm->enm_addrhi[3], enm->enm_addrhi[4],
2709 enm->enm_addrhi[5]);
2710#endif
2711 if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2712 return(1);
2713 }
2714 ETHER_NEXT_MULTI(step, enm);
2715 }
2716 return(0);
2717}
2718#endif
2719#endif