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