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