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