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