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