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