if_cnw.c revision 1.31
1/* $NetBSD: if_cnw.c,v 1.31 2005/02/27 00:27:43 perry Exp $ */ 2 3/*- 4 * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Michael Eriksson. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39/* 40 * Copyright (c) 1996, 1997 Berkeley Software Design, Inc. 41 * All rights reserved. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that this notice is retained, 45 * the conditions in the following notices are met, and terms applying 46 * to contributors in the following notices also apply to Berkeley 47 * Software Design, Inc. 48 * 49 * 1. Redistributions of source code must retain the above copyright 50 * notice, this list of conditions and the following disclaimer. 51 * 2. Redistributions in binary form must reproduce the above copyright 52 * notice, this list of conditions and the following disclaimer in the 53 * documentation and/or other materials provided with the distribution. 54 * 3. All advertising materials mentioning features or use of this software 55 * must display the following acknowledgement: 56 * This product includes software developed by 57 * Berkeley Software Design, Inc. 58 * 4. Neither the name of the Berkeley Software Design, Inc. nor the names 59 * of its contributors may be used to endorse or promote products derived 60 * from this software without specific prior written permission. 61 * 62 * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``AS IS'' AND 63 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 64 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 65 * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN, INC. BE LIABLE 66 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 67 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 68 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 69 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 70 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 71 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 72 * SUCH DAMAGE. 73 * 74 * Paul Borman, December 1996 75 * 76 * This driver is derived from a generic frame work which is 77 * Copyright(c) 1994,1995,1996 78 * Yoichi Shinoda, Yoshitaka Tokugawa, WIDE Project, Wildboar Project 79 * and Foretune. All rights reserved. 80 * 81 * A linux driver was used as the "hardware reference manual" (i.e., 82 * to determine registers and a general outline of how the card works) 83 * That driver is publically available and copyright 84 * 85 * John Markus Bj�rndalen 86 * Department of Computer Science 87 * University of Troms� 88 * Norway 89 * johnm@staff.cs.uit.no, http://www.cs.uit.no/~johnm/ 90 */ 91 92/* 93 * This is a driver for the Xircom CreditCard Netwave (also known as 94 * the Netwave Airsurfer) wireless LAN PCMCIA adapter. 95 * 96 * When this driver was developed, the Linux Netwave driver was used 97 * as a hardware manual. That driver is Copyright (c) 1997 University 98 * of Troms�, Norway. It is part of the Linux pcmcia-cs package that 99 * can be found at http://pcmcia-cs.sourceforge.net/. The most recent 100 * version of the pcmcia-cs package when this driver was written was 101 * 3.0.6. 102 * 103 * Unfortunately, a lot of explicit numeric constants were used in the 104 * Linux driver. I have tried to use symbolic names whenever possible, 105 * but since I don't have any real hardware documentation, there's 106 * still one or two "magic numbers" :-(. 107 * 108 * Driver limitations: This driver doesn't do multicasting or receiver 109 * promiscuity, because of missing hardware documentation. I couldn't 110 * get receiver promiscuity to work, and I haven't even tried 111 * multicast. Volunteers are welcome, of course :-). 112 */ 113 114#include <sys/cdefs.h> 115__KERNEL_RCSID(0, "$NetBSD: if_cnw.c,v 1.31 2005/02/27 00:27:43 perry Exp $"); 116 117#include "opt_inet.h" 118#include "bpfilter.h" 119 120#include <sys/param.h> 121#include <sys/systm.h> 122#include <sys/device.h> 123#include <sys/socket.h> 124#include <sys/mbuf.h> 125#include <sys/ioctl.h> 126#include <sys/proc.h> 127 128#include <net/if.h> 129 130#include <dev/pcmcia/if_cnwreg.h> 131#include <dev/pcmcia/if_cnwioctl.h> 132 133#include <dev/pcmcia/pcmciareg.h> 134#include <dev/pcmcia/pcmciavar.h> 135#include <dev/pcmcia/pcmciadevs.h> 136 137#include <net/if_dl.h> 138#include <net/if_ether.h> 139 140#ifdef INET 141#include <netinet/in.h> 142#include <netinet/in_systm.h> 143#include <netinet/in_var.h> 144#include <netinet/ip.h> 145#include <netinet/if_inarp.h> 146#endif 147 148#if NBPFILTER > 0 149#include <net/bpf.h> 150#include <net/bpfdesc.h> 151#endif 152 153/* 154 * Let these be patchable variables, initialized from macros that can 155 * be set in the kernel config file. Someone with lots of spare time 156 * could probably write a nice Netwave configuration program to do 157 * this a little bit more elegantly :-). 158 */ 159#ifndef CNW_DOMAIN 160#define CNW_DOMAIN 0x100 161#endif 162int cnw_domain = CNW_DOMAIN; /* Domain */ 163#ifndef CNW_SCRAMBLEKEY 164#define CNW_SCRAMBLEKEY 0 165#endif 166int cnw_skey = CNW_SCRAMBLEKEY; /* Scramble key */ 167 168/* 169 * The card appears to work much better when we only allow one packet 170 * "in the air" at a time. This is done by not allowing another packet 171 * on the card, even if there is room. Turning this off will allow the 172 * driver to stuff packets on the card as soon as a transmit buffer is 173 * available. This does increase the number of collisions, though. 174 * We can que a second packet if there are transmit buffers available, 175 * but we do not actually send the packet until the last packet has 176 * been written. 177 */ 178#define ONE_AT_A_TIME 179 180/* 181 * Netwave cards choke if we try to use io memory address >= 0x400. 182 * Even though, CIS tuple does not talk about this. 183 * Use memory mapped access. 184 */ 185#define MEMORY_MAPPED 186 187int cnw_match(struct device *, struct cfdata *, void *); 188void cnw_attach(struct device *, struct device *, void *); 189int cnw_detach(struct device *, int); 190 191int cnw_activate(struct device *, enum devact); 192 193struct cnw_softc { 194 struct device sc_dev; /* Device glue (must be first) */ 195 struct ethercom sc_ethercom; /* Ethernet common part */ 196 int sc_domain; /* Netwave domain */ 197 int sc_skey; /* Netwave scramble key */ 198 struct cnwstats sc_stats; 199 200 /* PCMCIA-specific stuff */ 201 struct pcmcia_function *sc_pf; /* PCMCIA function */ 202#ifndef MEMORY_MAPPED 203 struct pcmcia_io_handle sc_pcioh; /* PCMCIA I/O space handle */ 204 int sc_iowin; /* ...window */ 205 bus_space_tag_t sc_iot; /* ...bus_space tag */ 206 bus_space_handle_t sc_ioh; /* ...bus_space handle */ 207#endif 208 struct pcmcia_mem_handle sc_pcmemh; /* PCMCIA memory handle */ 209 bus_size_t sc_memoff; /* ...offset */ 210 int sc_memwin; /* ...window */ 211 bus_space_tag_t sc_memt; /* ...bus_space tag */ 212 bus_space_handle_t sc_memh; /* ...bus_space handle */ 213 void *sc_ih; /* Interrupt cookie */ 214 struct timeval sc_txlast; /* When the last xmit was made */ 215 int sc_active; /* Currently xmitting a packet */ 216 217 int sc_resource; /* Resources alloc'ed on attach */ 218#define CNW_RES_PCIC 1 219#define CNW_RES_IO 2 220#define CNW_RES_MEM 4 221#define CNW_RES_NET 8 222}; 223 224CFATTACH_DECL(cnw, sizeof(struct cnw_softc), 225 cnw_match, cnw_attach, cnw_detach, cnw_activate); 226 227void cnw_reset(struct cnw_softc *); 228void cnw_init(struct cnw_softc *); 229int cnw_enable(struct cnw_softc *sc); 230void cnw_disable(struct cnw_softc *sc); 231void cnw_config(struct cnw_softc *sc, u_int8_t *); 232void cnw_start(struct ifnet *); 233void cnw_transmit(struct cnw_softc *, struct mbuf *); 234struct mbuf *cnw_read(struct cnw_softc *); 235void cnw_recv(struct cnw_softc *); 236int cnw_intr(void *arg); 237int cnw_ioctl(struct ifnet *, u_long, caddr_t); 238void cnw_watchdog(struct ifnet *); 239static int cnw_setdomain(struct cnw_softc *, int); 240static int cnw_setkey(struct cnw_softc *, int); 241 242/* ---------------------------------------------------------------- */ 243 244/* Help routines */ 245static int wait_WOC(struct cnw_softc *, int); 246static int read16(struct cnw_softc *, int); 247static int cnw_cmd(struct cnw_softc *, int, int, int, int); 248 249/* 250 * Wait until the WOC (Write Operation Complete) bit in the 251 * ASR (Adapter Status Register) is asserted. 252 */ 253static int 254wait_WOC(sc, line) 255 struct cnw_softc *sc; 256 int line; 257{ 258 int i, asr; 259 260 for (i = 0; i < 5000; i++) { 261#ifndef MEMORY_MAPPED 262 asr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, CNW_REG_ASR); 263#else 264 asr = bus_space_read_1(sc->sc_memt, sc->sc_memh, 265 sc->sc_memoff + CNW_IOM_OFF + CNW_REG_ASR); 266#endif 267 if (asr & CNW_ASR_WOC) 268 return (0); 269 DELAY(100); 270 } 271 if (line > 0) 272 printf("%s: wedged at line %d\n", sc->sc_dev.dv_xname, line); 273 return (1); 274} 275#define WAIT_WOC(sc) wait_WOC(sc, __LINE__) 276 277 278/* 279 * Read a 16 bit value from the card. 280 */ 281static int 282read16(sc, offset) 283 struct cnw_softc *sc; 284 int offset; 285{ 286 int hi, lo; 287 int offs = sc->sc_memoff + offset; 288 289 /* This could presumably be done more efficient with 290 * bus_space_read_2(), but I don't know anything about the 291 * byte sex guarantees... Besides, this is pretty cheap as 292 * well :-) 293 */ 294 lo = bus_space_read_1(sc->sc_memt, sc->sc_memh, offs); 295 hi = bus_space_read_1(sc->sc_memt, sc->sc_memh, offs + 1); 296 return ((hi << 8) | lo); 297} 298 299 300/* 301 * Send a command to the card by writing it to the command buffer. 302 */ 303int 304cnw_cmd(sc, cmd, count, arg1, arg2) 305 struct cnw_softc *sc; 306 int cmd, count, arg1, arg2; 307{ 308 int ptr = sc->sc_memoff + CNW_EREG_CB; 309 310 if (wait_WOC(sc, 0)) { 311 printf("%s: wedged when issuing cmd 0x%x\n", 312 sc->sc_dev.dv_xname, cmd); 313 /* 314 * We'll continue anyway, as that's probably the best 315 * thing we can do; at least the user knows there's a 316 * problem, and can reset the interface with ifconfig 317 * down/up. 318 */ 319 } 320 321 bus_space_write_1(sc->sc_memt, sc->sc_memh, ptr, cmd); 322 if (count > 0) { 323 bus_space_write_1(sc->sc_memt, sc->sc_memh, ptr + 1, arg1); 324 if (count > 1) 325 bus_space_write_1(sc->sc_memt, sc->sc_memh, 326 ptr + 2, arg2); 327 } 328 bus_space_write_1(sc->sc_memt, sc->sc_memh, 329 ptr + count + 1, CNW_CMD_EOC); 330 return (0); 331} 332#define CNW_CMD0(sc, cmd) \ 333 do { cnw_cmd(sc, cmd, 0, 0, 0); } while (0) 334#define CNW_CMD1(sc, cmd, arg1) \ 335 do { cnw_cmd(sc, cmd, 1, arg1 , 0); } while (0) 336#define CNW_CMD2(sc, cmd, arg1, arg2) \ 337 do { cnw_cmd(sc, cmd, 2, arg1, arg2); } while (0) 338 339/* ---------------------------------------------------------------- */ 340 341/* 342 * Reset the hardware. 343 */ 344void 345cnw_reset(sc) 346 struct cnw_softc *sc; 347{ 348#ifdef CNW_DEBUG 349 if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) 350 printf("%s: resetting\n", sc->sc_dev.dv_xname); 351#endif 352 wait_WOC(sc, 0); 353#ifndef MEMORY_MAPPED 354 bus_space_write_1(sc->sc_iot, sc->sc_ioh, CNW_REG_PMR, CNW_PMR_RESET); 355#else 356 bus_space_write_1(sc->sc_memt, sc->sc_memh, 357 sc->sc_memoff + CNW_IOM_OFF + CNW_REG_PMR, CNW_PMR_RESET); 358#endif 359 bus_space_write_1(sc->sc_memt, sc->sc_memh, 360 sc->sc_memoff + CNW_EREG_ASCC, CNW_ASR_WOC); 361#ifndef MEMORY_MAPPED 362 bus_space_write_1(sc->sc_iot, sc->sc_ioh, CNW_REG_PMR, 0); 363#else 364 bus_space_write_1(sc->sc_memt, sc->sc_memh, 365 sc->sc_memoff + CNW_IOM_OFF + CNW_REG_PMR, 0); 366#endif 367} 368 369 370/* 371 * Initialize the card. 372 */ 373void 374cnw_init(sc) 375 struct cnw_softc *sc; 376{ 377 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 378 const u_int8_t rxmode = 379 CNW_RXCONF_RXENA | CNW_RXCONF_BCAST | CNW_RXCONF_AMP; 380 381 /* Reset the card */ 382 cnw_reset(sc); 383 384 /* Issue a NOP to check the card */ 385 CNW_CMD0(sc, CNW_CMD_NOP); 386 387 /* Set up receive configuration */ 388 CNW_CMD1(sc, CNW_CMD_SRC, 389 rxmode | ((ifp->if_flags & IFF_PROMISC) ? CNW_RXCONF_PRO : 0)); 390 391 /* Set up transmit configuration */ 392 CNW_CMD1(sc, CNW_CMD_STC, CNW_TXCONF_TXENA); 393 394 /* Set domain */ 395 CNW_CMD2(sc, CNW_CMD_SMD, sc->sc_domain, sc->sc_domain >> 8); 396 397 /* Set scramble key */ 398 CNW_CMD2(sc, CNW_CMD_SSK, sc->sc_skey, sc->sc_skey >> 8); 399 400 /* Enable interrupts */ 401 WAIT_WOC(sc); 402#ifndef MEMORY_MAPPED 403 bus_space_write_1(sc->sc_iot, sc->sc_ioh, 404 CNW_REG_IMR, CNW_IMR_IENA | CNW_IMR_RFU1); 405#else 406 bus_space_write_1(sc->sc_memt, sc->sc_memh, 407 sc->sc_memoff + CNW_IOM_OFF + CNW_REG_IMR, 408 CNW_IMR_IENA | CNW_IMR_RFU1); 409#endif 410 411 /* Enable receiver */ 412 CNW_CMD0(sc, CNW_CMD_ER); 413 414 /* "Set the IENA bit in COR" */ 415 WAIT_WOC(sc); 416#ifndef MEMORY_MAPPED 417 bus_space_write_1(sc->sc_iot, sc->sc_ioh, CNW_REG_COR, 418 CNW_COR_IENA | CNW_COR_LVLREQ); 419#else 420 bus_space_write_1(sc->sc_memt, sc->sc_memh, 421 sc->sc_memoff + CNW_IOM_OFF + CNW_REG_COR, 422 CNW_COR_IENA | CNW_COR_LVLREQ); 423#endif 424} 425 426 427/* 428 * Enable and initialize the card. 429 */ 430int 431cnw_enable(sc) 432 struct cnw_softc *sc; 433{ 434 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 435 436 if ((ifp->if_flags & IFF_RUNNING) != 0) 437 return (0); 438 439 sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_NET, cnw_intr, sc); 440 if (sc->sc_ih == NULL) { 441 printf("%s: couldn't establish interrupt handler\n", 442 sc->sc_dev.dv_xname); 443 return (EIO); 444 } 445 if (pcmcia_function_enable(sc->sc_pf) != 0) { 446 printf("%s: couldn't enable card\n", sc->sc_dev.dv_xname); 447 return (EIO); 448 } 449 sc->sc_resource |= CNW_RES_PCIC; 450 cnw_init(sc); 451 ifp->if_flags &= ~IFF_OACTIVE; 452 ifp->if_flags |= IFF_RUNNING; 453 return (0); 454} 455 456 457/* 458 * Stop and disable the card. 459 */ 460void 461cnw_disable(sc) 462 struct cnw_softc *sc; 463{ 464 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 465 466 if ((ifp->if_flags & IFF_RUNNING) == 0) 467 return; 468 469 pcmcia_function_disable(sc->sc_pf); 470 sc->sc_resource &= ~CNW_RES_PCIC; 471 pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih); 472 ifp->if_flags &= ~IFF_RUNNING; 473 ifp->if_timer = 0; 474} 475 476 477/* 478 * Match the hardware we handle. 479 */ 480int 481cnw_match(parent, match, aux) 482 struct device *parent; 483 struct cfdata *match; 484 void *aux; 485{ 486 struct pcmcia_attach_args *pa = aux; 487 488 if (pa->manufacturer == PCMCIA_VENDOR_XIRCOM && 489 pa->product == PCMCIA_PRODUCT_XIRCOM_CNW_801) 490 return 1; 491 if (pa->manufacturer == PCMCIA_VENDOR_XIRCOM && 492 pa->product == PCMCIA_PRODUCT_XIRCOM_CNW_802) 493 return 1; 494 return 0; 495} 496 497 498/* 499 * Attach the card. 500 */ 501void 502cnw_attach(parent, self, aux) 503 struct device *parent, *self; 504 void *aux; 505{ 506 struct cnw_softc *sc = (void *) self; 507 struct pcmcia_attach_args *pa = aux; 508 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 509 u_int8_t macaddr[ETHER_ADDR_LEN]; 510 int i; 511 bus_size_t memsize; 512 513 sc->sc_resource = 0; 514 515 /* Enable the card */ 516 sc->sc_pf = pa->pf; 517 pcmcia_function_init(sc->sc_pf, SIMPLEQ_FIRST(&sc->sc_pf->cfe_head)); 518 if (pcmcia_function_enable(sc->sc_pf)) { 519 printf("%s: function enable failed\n", self->dv_xname); 520 return; 521 } 522 sc->sc_resource |= CNW_RES_PCIC; 523 524 /* Map I/O register and "memory" */ 525#ifndef MEMORY_MAPPED 526 if (pcmcia_io_alloc(sc->sc_pf, 0, CNW_IO_SIZE, CNW_IO_SIZE, 527 &sc->sc_pcioh) != 0) { 528 printf("%s: can't allocate i/o space\n", self->dv_xname); 529 goto fail; 530 } 531 if (pcmcia_io_map(sc->sc_pf, PCMCIA_WIDTH_IO16, &sc->sc_pcioh, 532 &sc->sc_iowin) != 0) { 533 printf("%s: can't map i/o space\n", self->dv_xname); 534 pcmcia_io_free(sc->sc_pf, &sc->sc_pcioh); 535 goto fail; 536 } 537 sc->sc_iot = sc->sc_pcioh.iot; 538 sc->sc_ioh = sc->sc_pcioh.ioh; 539 sc->sc_resource |= CNW_RES_IO; 540#endif 541#ifndef MEMORY_MAPPED 542 memsize = CNW_MEM_SIZE; 543#else 544 memsize = CNW_MEM_SIZE + CNW_IOM_SIZE; 545#endif 546 if (pcmcia_mem_alloc(sc->sc_pf, memsize, &sc->sc_pcmemh) != 0) { 547 printf("%s: can't allocate memory\n", self->dv_xname); 548 goto fail; 549 } 550 if (pcmcia_mem_map(sc->sc_pf, PCMCIA_WIDTH_MEM8|PCMCIA_MEM_COMMON, 551 CNW_MEM_ADDR, memsize, &sc->sc_pcmemh, &sc->sc_memoff, 552 &sc->sc_memwin) != 0) { 553 printf("%s: can't map memory\n", self->dv_xname); 554 pcmcia_mem_free(sc->sc_pf, &sc->sc_pcmemh); 555 goto fail; 556 } 557 sc->sc_memt = sc->sc_pcmemh.memt; 558 sc->sc_memh = sc->sc_pcmemh.memh; 559 sc->sc_resource |= CNW_RES_MEM; 560 561 /* Finish setup of softc */ 562 sc->sc_domain = cnw_domain; 563 sc->sc_skey = cnw_skey; 564 565 /* Get MAC address */ 566 cnw_reset(sc); 567 for (i = 0; i < ETHER_ADDR_LEN; i++) 568 macaddr[i] = bus_space_read_1(sc->sc_memt, sc->sc_memh, 569 sc->sc_memoff + CNW_EREG_PA + i); 570 printf("%s: address %s\n", sc->sc_dev.dv_xname, 571 ether_sprintf(macaddr)); 572 573 /* Set up ifnet structure */ 574 strcpy(ifp->if_xname, sc->sc_dev.dv_xname); 575 ifp->if_softc = sc; 576 ifp->if_start = cnw_start; 577 ifp->if_ioctl = cnw_ioctl; 578 ifp->if_watchdog = cnw_watchdog; 579 ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX | 580 IFF_NOTRAILERS; 581 IFQ_SET_READY(&ifp->if_snd); 582 583 /* Attach the interface */ 584 if_attach(ifp); 585 ether_ifattach(ifp, macaddr); 586 587 sc->sc_resource |= CNW_RES_NET; 588 589 ifp->if_baudrate = IF_Mbps(1); 590 591 /* Disable the card now, and turn it on when the interface goes up */ 592 pcmcia_function_disable(sc->sc_pf); 593 sc->sc_resource &= ~CNW_RES_PCIC; 594 return; 595 596fail: 597#ifndef MEMORY_MAPPED 598 if ((sc->sc_resource & CNW_RES_IO) != 0) { 599 pcmcia_io_unmap(sc->sc_pf, sc->sc_iowin); 600 pcmcia_io_free(sc->sc_pf, &sc->sc_pcioh); 601 sc->sc_resource &= ~CNW_RES_IO; 602 } 603#endif 604 if ((sc->sc_resource & CNW_RES_PCIC) != 0) { 605 pcmcia_function_disable(sc->sc_pf); 606 sc->sc_resource &= ~CNW_RES_PCIC; 607 } 608} 609 610/* 611 * Start outputting on the interface. 612 */ 613void 614cnw_start(ifp) 615 struct ifnet *ifp; 616{ 617 struct cnw_softc *sc = ifp->if_softc; 618 struct mbuf *m0; 619 int lif; 620 int asr; 621#ifdef ONE_AT_A_TIME 622 struct timeval now; 623#endif 624 625#ifdef CNW_DEBUG 626 if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) 627 printf("%s: cnw_start\n", ifp->if_xname); 628 if (ifp->if_flags & IFF_OACTIVE) 629 printf("%s: cnw_start reentered\n", ifp->if_xname); 630#endif 631 632 ifp->if_flags |= IFF_OACTIVE; 633 634 for (;;) { 635#ifdef ONE_AT_A_TIME 636 microtime(&now); 637 now.tv_sec -= sc->sc_txlast.tv_sec; 638 now.tv_usec -= sc->sc_txlast.tv_usec; 639 if (now.tv_usec < 0) { 640 now.tv_usec += 1000000; 641 now.tv_sec--; 642 } 643 644 /* 645 * Don't ship this packet out until the last 646 * packet has left the building. 647 * If we have not tried to send a packet for 1/5 648 * a second then we assume we lost an interrupt, 649 * lets go on and send the next packet anyhow. 650 * 651 * I suppose we could check to see if it is okay 652 * to put additional packets on the card (beyond 653 * the one already waiting to be sent) but I don't 654 * think we would get any improvement in speed as 655 * we should have ample time to put the next packet 656 * on while this one is going out. 657 */ 658 if (sc->sc_active && now.tv_sec == 0 && now.tv_usec < 200000) 659 break; 660#endif 661 662 /* Make sure the link integrity field is on */ 663 WAIT_WOC(sc); 664 lif = bus_space_read_1(sc->sc_memt, sc->sc_memh, 665 sc->sc_memoff + CNW_EREG_LIF); 666 if (lif == 0) { 667#ifdef CNW_DEBUG 668 if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) 669 printf("%s: link integrity %d\n", lif); 670#endif 671 break; 672 } 673 674 /* Is there any buffer space available on the card? */ 675 WAIT_WOC(sc); 676#ifndef MEMORY_MAPPED 677 asr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, CNW_REG_ASR); 678#else 679 asr = bus_space_read_1(sc->sc_memt, sc->sc_memh, 680 sc->sc_memoff + CNW_IOM_OFF + CNW_REG_ASR); 681#endif 682 if (!(asr & CNW_ASR_TXBA)) { 683#ifdef CNW_DEBUG 684 if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) 685 printf("%s: no buffer space\n", ifp->if_xname); 686#endif 687 break; 688 } 689 690 sc->sc_stats.nws_tx++; 691 692 IFQ_DEQUEUE(&ifp->if_snd, m0); 693 if (m0 == 0) 694 break; 695 696#if NBPFILTER > 0 697 if (ifp->if_bpf) 698 bpf_mtap(ifp->if_bpf, m0); 699#endif 700 701 cnw_transmit(sc, m0); 702 ++ifp->if_opackets; 703 ifp->if_timer = 3; /* start watchdog timer */ 704 705 microtime(&sc->sc_txlast); 706 sc->sc_active = 1; 707 } 708 709 ifp->if_flags &= ~IFF_OACTIVE; 710} 711 712/* 713 * Transmit a packet. 714 */ 715void 716cnw_transmit(sc, m0) 717 struct cnw_softc *sc; 718 struct mbuf *m0; 719{ 720 int buffer, bufsize, bufoffset, bufptr, bufspace, len, mbytes, n; 721 struct mbuf *m; 722 u_int8_t *mptr; 723 724 /* Get buffer info from card */ 725 buffer = read16(sc, CNW_EREG_TDP); 726 bufsize = read16(sc, CNW_EREG_TDP + 2); 727 bufoffset = read16(sc, CNW_EREG_TDP + 4); 728#ifdef CNW_DEBUG 729 if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) 730 printf("%s: cnw_transmit b=0x%x s=%d o=0x%x\n", 731 sc->sc_dev.dv_xname, buffer, bufsize, bufoffset); 732#endif 733 734 /* Copy data from mbuf chain to card buffers */ 735 bufptr = sc->sc_memoff + buffer + bufoffset; 736 bufspace = bufsize; 737 len = 0; 738 for (m = m0; m; ) { 739 mptr = mtod(m, u_int8_t *); 740 mbytes = m->m_len; 741 len += mbytes; 742 while (mbytes > 0) { 743 if (bufspace == 0) { 744 buffer = read16(sc, buffer); 745 bufptr = sc->sc_memoff + buffer + bufoffset; 746 bufspace = bufsize; 747#ifdef CNW_DEBUG 748 if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) 749 printf("%s: next buffer @0x%x\n", 750 sc->sc_dev.dv_xname, buffer); 751#endif 752 } 753 n = mbytes <= bufspace ? mbytes : bufspace; 754 bus_space_write_region_1(sc->sc_memt, sc->sc_memh, 755 bufptr, mptr, n); 756 bufptr += n; 757 bufspace -= n; 758 mptr += n; 759 mbytes -= n; 760 } 761 MFREE(m, m0); 762 m = m0; 763 } 764 765 /* Issue transmit command */ 766 CNW_CMD2(sc, CNW_CMD_TL, len, len >> 8); 767} 768 769 770/* 771 * Pull a packet from the card into an mbuf chain. 772 */ 773struct mbuf * 774cnw_read(sc) 775 struct cnw_softc *sc; 776{ 777 struct mbuf *m, *top, **mp; 778 int totbytes, buffer, bufbytes, bufptr, mbytes, n; 779 u_int8_t *mptr; 780 781 WAIT_WOC(sc); 782 totbytes = read16(sc, CNW_EREG_RDP); 783#ifdef CNW_DEBUG 784 if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) 785 printf("%s: recv %d bytes\n", sc->sc_dev.dv_xname, totbytes); 786#endif 787 buffer = CNW_EREG_RDP + 2; 788 bufbytes = 0; 789 bufptr = 0; /* XXX make gcc happy */ 790 791 MGETHDR(m, M_DONTWAIT, MT_DATA); 792 if (m == 0) 793 return (0); 794 m->m_pkthdr.rcvif = &sc->sc_ethercom.ec_if; 795 m->m_pkthdr.len = totbytes; 796 mbytes = MHLEN; 797 top = 0; 798 mp = ⊤ 799 800 while (totbytes > 0) { 801 if (top) { 802 MGET(m, M_DONTWAIT, MT_DATA); 803 if (m == 0) { 804 m_freem(top); 805 return (0); 806 } 807 mbytes = MLEN; 808 } 809 if (totbytes >= MINCLSIZE) { 810 MCLGET(m, M_DONTWAIT); 811 if ((m->m_flags & M_EXT) == 0) { 812 m_free(m); 813 m_freem(top); 814 return (0); 815 } 816 mbytes = MCLBYTES; 817 } 818 if (!top) { 819 int pad = ALIGN(sizeof(struct ether_header)) - 820 sizeof(struct ether_header); 821 m->m_data += pad; 822 mbytes -= pad; 823 } 824 mptr = mtod(m, u_int8_t *); 825 mbytes = m->m_len = min(totbytes, mbytes); 826 totbytes -= mbytes; 827 while (mbytes > 0) { 828 if (bufbytes == 0) { 829 buffer = read16(sc, buffer); 830 bufbytes = read16(sc, buffer + 2); 831 bufptr = sc->sc_memoff + buffer + 832 read16(sc, buffer + 4); 833#ifdef CNW_DEBUG 834 if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG) 835 printf("%s: %d bytes @0x%x+0x%x\n", 836 sc->sc_dev.dv_xname, bufbytes, 837 buffer, bufptr - buffer - 838 sc->sc_memoff); 839#endif 840 } 841 n = mbytes <= bufbytes ? mbytes : bufbytes; 842 bus_space_read_region_1(sc->sc_memt, sc->sc_memh, 843 bufptr, mptr, n); 844 bufbytes -= n; 845 bufptr += n; 846 mbytes -= n; 847 mptr += n; 848 } 849 *mp = m; 850 mp = &m->m_next; 851 } 852 853 return (top); 854} 855 856 857/* 858 * Handle received packets. 859 */ 860void 861cnw_recv(sc) 862 struct cnw_softc *sc; 863{ 864 int rser; 865 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 866 struct mbuf *m; 867 868 for (;;) { 869 WAIT_WOC(sc); 870 rser = bus_space_read_1(sc->sc_memt, sc->sc_memh, 871 sc->sc_memoff + CNW_EREG_RSER); 872 if (!(rser & CNW_RSER_RXAVAIL)) 873 return; 874 875 /* Pull packet off card */ 876 m = cnw_read(sc); 877 878 /* Acknowledge packet */ 879 CNW_CMD0(sc, CNW_CMD_SRP); 880 881 /* Did we manage to get the packet from the interface? */ 882 if (m == 0) { 883 ++ifp->if_ierrors; 884 return; 885 } 886 ++ifp->if_ipackets; 887 888#if NBPFILTER > 0 889 if (ifp->if_bpf) 890 bpf_mtap(ifp->if_bpf, m); 891#endif 892 893 /* Pass the packet up. */ 894 (*ifp->if_input)(ifp, m); 895 } 896} 897 898 899/* 900 * Interrupt handler. 901 */ 902int 903cnw_intr(arg) 904 void *arg; 905{ 906 struct cnw_softc *sc = arg; 907 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 908 int ret, status, rser, tser; 909 910 if ((sc->sc_ethercom.ec_if.if_flags & IFF_RUNNING) == 0 || 911 (sc->sc_dev.dv_flags & DVF_ACTIVE) == 0) 912 return (0); 913 ifp->if_timer = 0; /* stop watchdog timer */ 914 915 ret = 0; 916 for (;;) { 917 WAIT_WOC(sc); 918#ifndef MEMORY_MAPPED 919 status = bus_space_read_1(sc->sc_iot, sc->sc_ioh, 920 CNW_REG_CCSR); 921#else 922 status = bus_space_read_1(sc->sc_memt, sc->sc_memh, 923 sc->sc_memoff + CNW_IOM_OFF + CNW_REG_CCSR); 924#endif 925 if (!(status & 0x02)) { 926 if (ret == 0) 927 printf("%s: spurious interrupt\n", 928 sc->sc_dev.dv_xname); 929 return (ret); 930 } 931 ret = 1; 932#ifndef MEMORY_MAPPED 933 status = bus_space_read_1(sc->sc_iot, sc->sc_ioh, CNW_REG_ASR); 934#else 935 status = bus_space_read_1(sc->sc_memt, sc->sc_memh, 936 sc->sc_memoff + CNW_IOM_OFF + CNW_REG_ASR); 937#endif 938 939 /* Anything to receive? */ 940 if (status & CNW_ASR_RXRDY) { 941 sc->sc_stats.nws_rx++; 942 cnw_recv(sc); 943 } 944 945 /* Receive error */ 946 if (status & CNW_ASR_RXERR) { 947 /* 948 * I get a *lot* of spurious receive errors 949 * (many per second), even when the interface 950 * is quiescent, so we don't increment 951 * if_ierrors here. 952 */ 953 rser = bus_space_read_1(sc->sc_memt, sc->sc_memh, 954 sc->sc_memoff + CNW_EREG_RSER); 955 956 /* RX statistics */ 957 sc->sc_stats.nws_rxerr++; 958 if (rser & CNW_RSER_RXBIG) 959 sc->sc_stats.nws_rxframe++; 960 if (rser & CNW_RSER_RXCRC) 961 sc->sc_stats.nws_rxcrcerror++; 962 if (rser & CNW_RSER_RXOVERRUN) 963 sc->sc_stats.nws_rxoverrun++; 964 if (rser & CNW_RSER_RXOVERFLOW) 965 sc->sc_stats.nws_rxoverflow++; 966 if (rser & CNW_RSER_RXERR) 967 sc->sc_stats.nws_rxerrors++; 968 if (rser & CNW_RSER_RXAVAIL) 969 sc->sc_stats.nws_rxavail++; 970 971 /* Clear error bits in RSER */ 972 WAIT_WOC(sc); 973 bus_space_write_1(sc->sc_memt, sc->sc_memh, 974 sc->sc_memoff + CNW_EREG_RSERW, 975 CNW_RSER_RXERR | 976 (rser & (CNW_RSER_RXCRC | CNW_RSER_RXBIG))); 977 /* Clear RXERR in ASR */ 978 WAIT_WOC(sc); 979 bus_space_write_1(sc->sc_memt, sc->sc_memh, 980 sc->sc_memoff + CNW_EREG_ASCC, CNW_ASR_RXERR); 981 } 982 983 /* Transmit done */ 984 if (status & CNW_ASR_TXDN) { 985 tser = bus_space_read_1(sc->sc_memt, sc->sc_memh, 986 CNW_EREG_TSER); 987 988 /* TX statistics */ 989 if (tser & CNW_TSER_TXERR) 990 sc->sc_stats.nws_txerrors++; 991 if (tser & CNW_TSER_TXNOAP) 992 sc->sc_stats.nws_txlostcd++; 993 if (tser & CNW_TSER_TXGU) 994 sc->sc_stats.nws_txabort++; 995 996 if (tser & CNW_TSER_TXOK) { 997 sc->sc_stats.nws_txokay++; 998 sc->sc_stats.nws_txretries[status & 0xf]++; 999 WAIT_WOC(sc); 1000 bus_space_write_1(sc->sc_memt, sc->sc_memh, 1001 sc->sc_memoff + CNW_EREG_TSERW, 1002 CNW_TSER_TXOK | CNW_TSER_RTRY); 1003 } 1004 1005 if (tser & CNW_TSER_ERROR) { 1006 ++ifp->if_oerrors; 1007 WAIT_WOC(sc); 1008 bus_space_write_1(sc->sc_memt, sc->sc_memh, 1009 sc->sc_memoff + CNW_EREG_TSERW, 1010 (tser & CNW_TSER_ERROR) | 1011 CNW_TSER_RTRY); 1012 } 1013 1014 sc->sc_active = 0; 1015 ifp->if_flags &= ~IFF_OACTIVE; 1016 1017 /* Continue to send packets from the queue */ 1018 cnw_start(&sc->sc_ethercom.ec_if); 1019 } 1020 1021 } 1022} 1023 1024 1025/* 1026 * Handle device ioctls. 1027 */ 1028int 1029cnw_ioctl(ifp, cmd, data) 1030 struct ifnet *ifp; 1031 u_long cmd; 1032 caddr_t data; 1033{ 1034 struct cnw_softc *sc = ifp->if_softc; 1035 struct ifaddr *ifa = (struct ifaddr *)data; 1036 struct ifreq *ifr = (struct ifreq *)data; 1037 int s, error = 0; 1038 struct proc *p = curproc; /*XXX*/ 1039 1040 s = splnet(); 1041 1042 switch (cmd) { 1043 1044 case SIOCSIFADDR: 1045 if (!(ifp->if_flags & IFF_RUNNING) && 1046 (error = cnw_enable(sc)) != 0) 1047 break; 1048 ifp->if_flags |= IFF_UP; 1049 switch (ifa->ifa_addr->sa_family) { 1050#ifdef INET 1051 case AF_INET: 1052 cnw_init(sc); 1053 arp_ifinit(&sc->sc_ethercom.ec_if, ifa); 1054 break; 1055#endif 1056 default: 1057 cnw_init(sc); 1058 break; 1059 } 1060 break; 1061 1062 case SIOCSIFFLAGS: 1063 if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == IFF_RUNNING) { 1064 /* 1065 * The interface is marked down and it is running, so 1066 * stop it. 1067 */ 1068 cnw_disable(sc); 1069 } else if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == IFF_UP){ 1070 /* 1071 * The interface is marked up and it is stopped, so 1072 * start it. 1073 */ 1074 error = cnw_enable(sc); 1075 } else { 1076 /* IFF_PROMISC may be changed */ 1077 cnw_init(sc); 1078 } 1079 break; 1080 1081 case SIOCADDMULTI: 1082 case SIOCDELMULTI: 1083 /* Update our multicast list. */ 1084 error = (cmd == SIOCADDMULTI) ? 1085 ether_addmulti(ifr, &sc->sc_ethercom) : 1086 ether_delmulti(ifr, &sc->sc_ethercom); 1087 if (error == ENETRESET) { 1088 if (ifp->if_flags & IFF_RUNNING) 1089 cnw_init(sc); 1090 error = 0; 1091 } 1092 break; 1093 1094 case SIOCGCNWDOMAIN: 1095 ((struct ifreq *)data)->ifr_domain = sc->sc_domain; 1096 break; 1097 1098 case SIOCSCNWDOMAIN: 1099 error = suser(p->p_ucred, &p->p_acflag); 1100 if (error) 1101 break; 1102 error = cnw_setdomain(sc, ifr->ifr_domain); 1103 break; 1104 1105 case SIOCSCNWKEY: 1106 error = suser(p->p_ucred, &p->p_acflag); 1107 if (error) 1108 break; 1109 error = cnw_setkey(sc, ifr->ifr_key); 1110 break; 1111 1112 case SIOCGCNWSTATUS: 1113 error = suser(p->p_ucred, &p->p_acflag); 1114 if (error) 1115 break; 1116 if ((ifp->if_flags & IFF_RUNNING) == 0) 1117 break; 1118 bus_space_read_region_1(sc->sc_memt, sc->sc_memh, 1119 sc->sc_memoff + CNW_EREG_CB, 1120 ((struct cnwstatus *)data)->data, 1121 sizeof(((struct cnwstatus *)data)->data)); 1122 break; 1123 1124 case SIOCGCNWSTATS: 1125 memcpy((void *)&(((struct cnwistats *)data)->stats), 1126 (void *)&sc->sc_stats, sizeof(struct cnwstats)); 1127 break; 1128 1129 default: 1130 error = EINVAL; 1131 break; 1132 } 1133 1134 splx(s); 1135 return (error); 1136} 1137 1138 1139/* 1140 * Device timeout/watchdog routine. Entered if the device neglects to 1141 * generate an interrupt after a transmit has been started on it. 1142 */ 1143void 1144cnw_watchdog(ifp) 1145 struct ifnet *ifp; 1146{ 1147 struct cnw_softc *sc = ifp->if_softc; 1148 1149 printf("%s: device timeout; card reset\n", sc->sc_dev.dv_xname); 1150 ++ifp->if_oerrors; 1151 cnw_init(sc); 1152} 1153 1154int 1155cnw_setdomain(sc, domain) 1156 struct cnw_softc *sc; 1157 int domain; 1158{ 1159 int s; 1160 1161 if (domain & ~0x1ff) 1162 return EINVAL; 1163 1164 s = splnet(); 1165 CNW_CMD2(sc, CNW_CMD_SMD, domain, domain >> 8); 1166 splx(s); 1167 1168 sc->sc_domain = domain; 1169 return 0; 1170} 1171 1172int 1173cnw_setkey(sc, key) 1174 struct cnw_softc *sc; 1175 int key; 1176{ 1177 int s; 1178 1179 if (key & ~0xffff) 1180 return EINVAL; 1181 1182 s = splnet(); 1183 CNW_CMD2(sc, CNW_CMD_SSK, key, key >> 8); 1184 splx(s); 1185 1186 sc->sc_skey = key; 1187 return 0; 1188} 1189 1190int 1191cnw_activate(self, act) 1192 struct device *self; 1193 enum devact act; 1194{ 1195 struct cnw_softc *sc = (struct cnw_softc *)self; 1196 int rv = 0, s; 1197 1198 s = splnet(); 1199 switch (act) { 1200 case DVACT_ACTIVATE: 1201 rv = EOPNOTSUPP; 1202 break; 1203 1204 case DVACT_DEACTIVATE: 1205 if_deactivate(&sc->sc_ethercom.ec_if); 1206 break; 1207 } 1208 splx(s); 1209 return (rv); 1210} 1211 1212int 1213cnw_detach(self, flags) 1214 struct device *self; 1215 int flags; 1216{ 1217 struct cnw_softc *sc = (struct cnw_softc *)self; 1218 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 1219 1220 /* cnw_disable() checks IFF_RUNNING */ 1221 cnw_disable(sc); 1222 1223 if ((sc->sc_resource & CNW_RES_NET) != 0) { 1224 ether_ifdetach(ifp); 1225 if_detach(ifp); 1226 } 1227 1228#ifndef MEMORY_MAPPED 1229 /* unmap and free our i/o windows */ 1230 if ((sc->sc_resource & CNW_RES_IO) != 0) { 1231 pcmcia_io_unmap(sc->sc_pf, sc->sc_iowin); 1232 pcmcia_io_free(sc->sc_pf, &sc->sc_pcioh); 1233 } 1234#endif 1235 1236 /* unmap and free our memory windows */ 1237 if ((sc->sc_resource & CNW_RES_MEM) != 0) { 1238 pcmcia_mem_unmap(sc->sc_pf, sc->sc_memwin); 1239 pcmcia_mem_free(sc->sc_pf, &sc->sc_pcmemh); 1240 } 1241 1242 return (0); 1243} 1244