if_vx.c revision 26640
1/* 2 * Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Herb Peyerl. 16 * 4. The name of Herb Peyerl may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 */ 31 32/* 33 * Created from if_ep.c driver by Fred Gray (fgray@rice.edu) to support 34 * the 3c590 family. 35 */ 36 37/* 38 * Modified from the FreeBSD 1.1.5.1 version by: 39 * Andres Vega Garcia 40 * INRIA - Sophia Antipolis, France 41 * avega@sophia.inria.fr 42 */ 43 44/* 45 * Promiscuous mode added and interrupt logic slightly changed 46 * to reduce the number of adapter failures. Transceiver select 47 * logic changed to use value from EEPROM. Autoconfiguration 48 * features added. 49 * Done by: 50 * Serge Babkin 51 * Chelindbank (Chelyabinsk, Russia) 52 * babkin@hq.icb.chel.su 53 */ 54 55#include "vx.h" 56#if NVX > 0 57 58#if NVX < 4 /* These cost 4 bytes apiece, so give us 4 */ 59#undef NVX 60#define NVX 4 61#endif 62 63#include "bpfilter.h" 64 65#include <sys/param.h> 66#include <sys/systm.h> 67#include <sys/sockio.h> 68#include <sys/malloc.h> 69#include <sys/mbuf.h> 70#include <sys/socket.h> 71 72#include <net/if.h> 73 74#ifdef INET 75#include <netinet/in.h> 76#include <netinet/if_ether.h> 77#endif 78 79#ifdef NS 80#include <netns/ns.h> 81#include <netns/ns_if.h> 82#endif 83 84#if NBPFILTER > 0 85#include <net/bpf.h> 86#endif 87 88#include <machine/clock.h> 89 90#include <dev/vx/if_vxreg.h> 91 92#define ETHER_MAX_LEN 1518 93#define ETHER_ADDR_LEN 6 94 95struct vx_softc *vx_softc[NVX]; 96 97u_long vx_count; /* both PCI and EISA */ 98 99static struct connector_entry { 100 int bit; 101 char *name; 102} conn_tab[VX_CONNECTORS] = { 103#define CONNECTOR_UTP 0 104 { 0x08, "utp"}, 105#define CONNECTOR_AUI 1 106 { 0x20, "aui"}, 107/* dummy */ 108 { 0, "???"}, 109#define CONNECTOR_BNC 3 110 { 0x10, "bnc"}, 111#define CONNECTOR_TX 4 112 { 0x02, "tx"}, 113#define CONNECTOR_FX 5 114 { 0x04, "fx"}, 115#define CONNECTOR_MII 6 116 { 0x40, "mii"}, 117 { 0, "???"} 118}; 119 120/* struct vx_softc *vxalloc __P((int)); */ 121/* void *vxfree __P((struct vx_softc *)); */ 122/* int vxattach __P((struct vx_softc *)); */ 123static void vxtxstat __P((struct vx_softc *)); 124static int vxstatus __P((struct vx_softc *)); 125static void vxinit __P((void *)); 126static int vxioctl __P((struct ifnet *, int, caddr_t)); 127static void vxstart __P((struct ifnet *ifp)); 128static void vxwatchdog __P((struct ifnet *)); 129static void vxreset __P((struct vx_softc *)); 130/* void vxstop __P((struct vx_softc *)); */ 131static void vxread __P((struct vx_softc *)); 132static struct mbuf *vxget __P((struct vx_softc *, u_int)); 133static void vxmbuffill __P((void *)); 134static void vxmbufempty __P((struct vx_softc *)); 135static void vxsetfilter __P((struct vx_softc *)); 136static void vxgetlink __P((struct vx_softc *)); 137static void vxsetlink __P((struct vx_softc *)); 138/* int vxbusyeeprom __P((struct vx_softc *)); */ 139/* void vxintr __P((void *)); */ 140 141struct vx_softc * 142vxalloc(unit) 143 int unit; 144{ 145 struct vx_softc *sc; 146 147 if (unit >= NVX) { 148 printf("vx%d: unit number too high.\n", unit); 149 return NULL; 150 } 151 152 if (vx_softc[unit]) { 153 printf("vx%d: already allocated.\n", unit); 154 return NULL; 155 } 156 157 sc = malloc(sizeof(struct vx_softc), M_DEVBUF, M_NOWAIT); 158 if (sc == NULL) { 159 printf("vx%d: cannot malloc.\n", unit); 160 return NULL; 161 } 162 bzero(sc, sizeof(struct vx_softc)); 163 164 vx_softc[unit] = sc; 165 sc->unit = unit; 166 return (sc); 167} 168 169void 170vxfree(sc) 171 struct vx_softc *sc; 172{ 173 vx_softc[sc->unit] = NULL; 174 free(sc, M_DEVBUF); 175 return; 176} 177 178int 179vxattach(sc) 180 struct vx_softc *sc; 181{ 182 struct ifnet *ifp = &sc->arpcom.ac_if; 183 int i; 184 185 GO_WINDOW(0); 186 outw(VX_COMMAND, GLOBAL_RESET); 187 VX_BUSY_WAIT; 188 189 vxgetlink(sc); 190 191 /* 192 * Read the station address from the eeprom 193 */ 194 GO_WINDOW(0); 195 for (i = 0; i < 3; i++) { 196 int x; 197 if (vxbusyeeprom(sc)) 198 return 0; 199 outw(BASE + VX_W0_EEPROM_COMMAND, EEPROM_CMD_RD 200 | (EEPROM_OEM_ADDR_0 + i)); 201 if (vxbusyeeprom(sc)) 202 return 0; 203 x = inw(BASE + VX_W0_EEPROM_DATA); 204 sc->arpcom.ac_enaddr[(i << 1)] = x >> 8; 205 sc->arpcom.ac_enaddr[(i << 1) + 1] = x; 206 } 207 208 printf(" address %6D\n", sc->arpcom.ac_enaddr, ":"); 209 210 ifp->if_unit = sc->unit; 211 ifp->if_name = "vx"; 212 ifp->if_mtu = ETHERMTU; 213 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 214 ifp->if_output = ether_output; 215 ifp->if_start = vxstart; 216 ifp->if_ioctl = vxioctl; 217 ifp->if_init = vxinit; 218 ifp->if_watchdog = vxwatchdog; 219 ifp->if_softc = sc; 220 221 if_attach(ifp); 222 ether_ifattach(ifp); 223 224#if NBPFILTER > 0 225 bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); 226#endif 227 228 sc->tx_start_thresh = 20; /* probably a good starting point. */ 229 230 vxstop(sc); 231 232 return 1; 233} 234 235 236 237/* 238 * The order in here seems important. Otherwise we may not receive 239 * interrupts. ?! 240 */ 241static void 242vxinit(xsc) 243 void *xsc; 244{ 245 struct vx_softc *sc = (struct vx_softc *) xsc; 246 struct ifnet *ifp = &sc->arpcom.ac_if; 247 int i; 248 249 VX_BUSY_WAIT; 250 251 GO_WINDOW(2); 252 253 for (i = 0; i < 6; i++) /* Reload the ether_addr. */ 254 outb(BASE + VX_W2_ADDR_0 + i, sc->arpcom.ac_enaddr[i]); 255 256 outw(BASE + VX_COMMAND, RX_RESET); 257 VX_BUSY_WAIT; 258 outw(BASE + VX_COMMAND, TX_RESET); 259 VX_BUSY_WAIT; 260 261 GO_WINDOW(1); /* Window 1 is operating window */ 262 for (i = 0; i < 31; i++) 263 inb(BASE + VX_W1_TX_STATUS); 264 265 outw(BASE + VX_COMMAND,SET_RD_0_MASK | S_CARD_FAILURE | 266 S_RX_COMPLETE | S_TX_COMPLETE | S_TX_AVAIL); 267 outw(BASE + VX_COMMAND,SET_INTR_MASK | S_CARD_FAILURE | 268 S_RX_COMPLETE | S_TX_COMPLETE | S_TX_AVAIL); 269 270 /* 271 * Attempt to get rid of any stray interrupts that occured during 272 * configuration. On the i386 this isn't possible because one may 273 * already be queued. However, a single stray interrupt is 274 * unimportant. 275 */ 276 outw(BASE + VX_COMMAND, ACK_INTR | 0xff); 277 278 vxsetfilter(sc); 279 vxsetlink(sc); 280 281 outw(BASE + VX_COMMAND, RX_ENABLE); 282 outw(BASE + VX_COMMAND, TX_ENABLE); 283 284 vxmbuffill((caddr_t) sc); 285 286 /* Interface is now `running', with no output active. */ 287 ifp->if_flags |= IFF_RUNNING; 288 ifp->if_flags &= ~IFF_OACTIVE; 289 290 /* Attempt to start output, if any. */ 291 vxstart(ifp); 292} 293 294static void 295vxsetfilter(sc) 296 struct vx_softc *sc; 297{ 298 register struct ifnet *ifp = &sc->arpcom.ac_if; 299 300 GO_WINDOW(1); /* Window 1 is operating window */ 301 outw(BASE + VX_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL | FIL_BRDCST | 302 FIL_MULTICAST | 303 ((ifp->if_flags & IFF_PROMISC) ? FIL_PROMISC : 0 )); 304} 305 306static void 307vxgetlink(sc) 308 struct vx_softc *sc; 309{ 310 int n, k; 311 312 GO_WINDOW(3); 313 sc->vx_connectors = inw(BASE + VX_W3_RESET_OPT) & 0x7f; 314 for (n = 0, k = 0; k < VX_CONNECTORS; k++) { 315 if (sc->vx_connectors & conn_tab[k].bit) { 316 if (n > 0) { 317 printf("/"); 318 } 319 printf(conn_tab[k].name); 320 n++; 321 } 322 } 323 if (sc->vx_connectors == 0) { 324 printf("no connectors!"); 325 return; 326 } 327 GO_WINDOW(3); 328 sc->vx_connector = (inl(BASE + VX_W3_INTERNAL_CFG) 329 & INTERNAL_CONNECTOR_MASK) 330 >> INTERNAL_CONNECTOR_BITS; 331 if (sc->vx_connector & 0x10) { 332 sc->vx_connector &= 0x0f; 333 printf("[*%s*]", conn_tab[sc->vx_connector].name); 334 printf(": disable 'auto select' with DOS util!", sc->unit); 335 } else { 336 printf("[*%s*]", conn_tab[sc->vx_connector].name); 337 } 338} 339 340static void 341vxsetlink(sc) 342 struct vx_softc *sc; 343{ 344 register struct ifnet *ifp = &sc->arpcom.ac_if; 345 int i, j, k; 346 char *reason, *warning; 347 static short prev_flags; 348 static char prev_conn = -1; 349 350 if (prev_conn == -1) { 351 prev_conn = sc->vx_connector; 352 } 353 354 /* 355 * S.B. 356 * 357 * Now behavior was slightly changed: 358 * 359 * if any of flags link[0-2] is used and its connector is 360 * physically present the following connectors are used: 361 * 362 * link0 - AUI * highest precedence 363 * link1 - BNC 364 * link2 - UTP * lowest precedence 365 * 366 * If none of them is specified then 367 * connector specified in the EEPROM is used 368 * (if present on card or UTP if not). 369 */ 370 371 i = sc->vx_connector; /* default in EEPROM */ 372 reason = "default"; 373 warning = 0; 374 375 if (ifp->if_flags & IFF_LINK0) { 376 if (sc->vx_connectors & conn_tab[CONNECTOR_AUI].bit) { 377 i = CONNECTOR_AUI; 378 reason = "link0"; 379 } else { 380 warning = "aui not present! (link0)"; 381 } 382 } else if (ifp->if_flags & IFF_LINK1) { 383 if (sc->vx_connectors & conn_tab[CONNECTOR_BNC].bit) { 384 i = CONNECTOR_BNC; 385 reason = "link1"; 386 } else { 387 warning = "bnc not present! (link1)"; 388 } 389 } else if (ifp->if_flags & IFF_LINK2) { 390 if (sc->vx_connectors & conn_tab[CONNECTOR_UTP].bit) { 391 i = CONNECTOR_UTP; 392 reason = "link2"; 393 } else { 394 warning = "utp not present! (link2)"; 395 } 396 } else if ((sc->vx_connectors & conn_tab[sc->vx_connector].bit) == 0) { 397 warning = "strange connector type in EEPROM."; 398 reason = "forced"; 399 i = CONNECTOR_UTP; 400 } 401 402 /* Avoid unnecessary message. */ 403 k = (prev_flags ^ ifp->if_flags) & (IFF_LINK0 | IFF_LINK1 | IFF_LINK2); 404 if ((k != 0) || (prev_conn != i)) { 405 if (warning != 0) { 406 printf("vx%d: warning: %s\n", sc->unit); 407 } 408 printf("vx%d: selected %s. (%s)\n", 409 sc->unit, conn_tab[i].name, reason); 410 } 411 412 /* Set the selected connector. */ 413 GO_WINDOW(3); 414 j = inl(BASE + VX_W3_INTERNAL_CFG) & ~INTERNAL_CONNECTOR_MASK; 415 outl(BASE + VX_W3_INTERNAL_CFG, j | (i <<INTERNAL_CONNECTOR_BITS)); 416 417 /* First, disable all. */ 418 outw(BASE + VX_COMMAND, STOP_TRANSCEIVER); 419 DELAY(800); 420 GO_WINDOW(4); 421 outw(BASE + VX_W4_MEDIA_TYPE, 0); 422 423 /* Second, enable the selected one. */ 424 switch(i) { 425 case CONNECTOR_UTP: 426 GO_WINDOW(4); 427 outw(BASE + VX_W4_MEDIA_TYPE, ENABLE_UTP); 428 break; 429 case CONNECTOR_BNC: 430 outw(BASE + VX_COMMAND, START_TRANSCEIVER); 431 DELAY(800); 432 break; 433 case CONNECTOR_TX: 434 case CONNECTOR_FX: 435 GO_WINDOW(4); 436 outw(BASE + VX_W4_MEDIA_TYPE, LINKBEAT_ENABLE); 437 break; 438 default: /* AUI and MII fall here */ 439 break; 440 } 441 GO_WINDOW(1); 442 443 prev_flags = ifp->if_flags; 444 prev_conn = i; 445} 446 447static void 448vxstart(ifp) 449 struct ifnet *ifp; 450{ 451 register struct vx_softc *sc = vx_softc[ifp->if_unit]; 452 register struct mbuf *m, *m0; 453 int sh, len, pad; 454 455 /* Don't transmit if interface is busy or not running */ 456 if ((sc->arpcom.ac_if.if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING) 457 return; 458 459startagain: 460 /* Sneak a peek at the next packet */ 461 m0 = ifp->if_snd.ifq_head; 462 if (m0 == 0) { 463 return; 464 } 465 /* We need to use m->m_pkthdr.len, so require the header */ 466 if ((m0->m_flags & M_PKTHDR) == 0) 467 panic("vxstart: no header mbuf"); 468 len = m0->m_pkthdr.len; 469 470 pad = (4 - len) & 3; 471 472 /* 473 * The 3c509 automatically pads short packets to minimum ethernet length, 474 * but we drop packets that are too large. Perhaps we should truncate 475 * them instead? 476 */ 477 if (len + pad > ETHER_MAX_LEN) { 478 /* packet is obviously too large: toss it */ 479 ++ifp->if_oerrors; 480 IF_DEQUEUE(&ifp->if_snd, m0); 481 m_freem(m0); 482 goto readcheck; 483 } 484 VX_BUSY_WAIT; 485 if (inw(BASE + VX_W1_FREE_TX) < len + pad + 4) { 486 outw(BASE + VX_COMMAND, SET_TX_AVAIL_THRESH | ((len + pad + 4) >> 2)); 487 /* not enough room in FIFO */ 488 if (inw(BASE + VX_W1_FREE_TX) < len + pad + 4) { /* make sure */ 489 ifp->if_flags |= IFF_OACTIVE; 490 ifp->if_timer = 1; 491 return; 492 } 493 } 494 outw(BASE + VX_COMMAND, SET_TX_AVAIL_THRESH | (8188 >> 2)); 495 IF_DEQUEUE(&ifp->if_snd, m0); 496 if (m0 == 0) { /* not really needed */ 497 return; 498 } 499 500 VX_BUSY_WAIT; 501 outw(BASE + VX_COMMAND, SET_TX_START_THRESH | 502 ((len / 4 + sc->tx_start_thresh) >> 2)); 503 504#if NBPFILTER > 0 505 if (sc->arpcom.ac_if.if_bpf) { 506 bpf_mtap(&sc->arpcom.ac_if, m0); 507 } 508#endif 509 510 /* 511 * Do the output at splhigh() so that an interrupt from another device 512 * won't cause a FIFO underrun. 513 */ 514 sh = splhigh(); 515 516 outl(BASE + VX_W1_TX_PIO_WR_1, len | TX_INDICATE); 517 518 for (m = m0; m != 0;) { 519 if (m->m_len > 3) 520 outsl(BASE + VX_W1_TX_PIO_WR_1, mtod(m, caddr_t), m->m_len / 4); 521 if (m->m_len & 3) 522 outsb(BASE + VX_W1_TX_PIO_WR_1, 523 mtod(m, caddr_t) + (m->m_len & ~3) , m->m_len & 3); 524 MFREE(m, m0); 525 m = m0; 526 } 527 while (pad--) 528 outb(BASE + VX_W1_TX_PIO_WR_1, 0); /* Padding */ 529 530 splx(sh); 531 532 ++ifp->if_opackets; 533 ifp->if_timer = 1; 534 535readcheck: 536 if ((inw(BASE + VX_W1_RX_STATUS) & ERR_INCOMPLETE) == 0) { 537 /* We received a complete packet. */ 538 539 if ((inw(BASE + VX_STATUS) & S_INTR_LATCH) == 0) { 540 /* 541 * No interrupt, read the packet and continue 542 * Is this supposed to happen? Is my motherboard 543 * completely busted? 544 */ 545 vxread(sc); 546 } else 547 /* Got an interrupt, return so that it gets serviced. */ 548 return; 549 } else { 550 /* Check if we are stuck and reset [see XXX comment] */ 551 if (vxstatus(sc)) { 552 if (ifp->if_flags & IFF_DEBUG) 553 printf("vx%d: adapter reset\n", ifp->if_unit); 554 vxreset(sc); 555 } 556 } 557 558 goto startagain; 559} 560 561/* 562 * XXX: The 3c509 card can get in a mode where both the fifo status bit 563 * FIFOS_RX_OVERRUN and the status bit ERR_INCOMPLETE are set 564 * We detect this situation and we reset the adapter. 565 * It happens at times when there is a lot of broadcast traffic 566 * on the cable (once in a blue moon). 567 */ 568static int 569vxstatus(sc) 570 struct vx_softc *sc; 571{ 572 int fifost; 573 574 /* 575 * Check the FIFO status and act accordingly 576 */ 577 GO_WINDOW(4); 578 fifost = inw(BASE + VX_W4_FIFO_DIAG); 579 GO_WINDOW(1); 580 581 if (fifost & FIFOS_RX_UNDERRUN) { 582 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) 583 printf("vx%d: RX underrun\n", sc->unit); 584 vxreset(sc); 585 return 0; 586 } 587 588 if (fifost & FIFOS_RX_STATUS_OVERRUN) { 589 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) 590 printf("vx%d: RX Status overrun\n", sc->unit); 591 return 1; 592 } 593 594 if (fifost & FIFOS_RX_OVERRUN) { 595 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) 596 printf("vx%d: RX overrun\n", sc->unit); 597 return 1; 598 } 599 600 if (fifost & FIFOS_TX_OVERRUN) { 601 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) 602 printf("vx%d: TX overrun\n", sc->unit); 603 vxreset(sc); 604 return 0; 605 } 606 607 return 0; 608} 609 610static void 611vxtxstat(sc) 612 struct vx_softc *sc; 613{ 614 int i; 615 616 /* 617 * We need to read+write TX_STATUS until we get a 0 status 618 * in order to turn off the interrupt flag. 619 */ 620 while ((i = inb(BASE + VX_W1_TX_STATUS)) & TXS_COMPLETE) { 621 outb(BASE + VX_W1_TX_STATUS, 0x0); 622 623 if (i & TXS_JABBER) { 624 ++sc->arpcom.ac_if.if_oerrors; 625 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) 626 printf("vx%d: jabber (%x)\n", sc->unit, i); 627 vxreset(sc); 628 } else if (i & TXS_UNDERRUN) { 629 ++sc->arpcom.ac_if.if_oerrors; 630 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) 631 printf("vx%d: fifo underrun (%x) @%d\n", 632 sc->unit, i, sc->tx_start_thresh); 633 if (sc->tx_succ_ok < 100) 634 sc->tx_start_thresh = min(ETHER_MAX_LEN, sc->tx_start_thresh + 20); 635 sc->tx_succ_ok = 0; 636 vxreset(sc); 637 } else if (i & TXS_MAX_COLLISION) { 638 ++sc->arpcom.ac_if.if_collisions; 639 outw(BASE + VX_COMMAND, TX_ENABLE); 640 sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; 641 } else 642 sc->tx_succ_ok = (sc->tx_succ_ok+1) & 127; 643 } 644} 645 646void 647vxintr(sc) 648 struct vx_softc *sc; 649{ 650 register short status; 651 struct ifnet *ifp = &sc->arpcom.ac_if; 652 653 for (;;) { 654 outw(BASE + VX_COMMAND, C_INTR_LATCH); 655 656 status = inw(BASE + VX_STATUS); 657 658 if ((status & (S_TX_COMPLETE | S_TX_AVAIL | 659 S_RX_COMPLETE | S_CARD_FAILURE)) == 0) 660 break; 661 662 /* 663 * Acknowledge any interrupts. It's important that we do this 664 * first, since there would otherwise be a race condition. 665 * Due to the i386 interrupt queueing, we may get spurious 666 * interrupts occasionally. 667 */ 668 outw(BASE + VX_COMMAND, ACK_INTR | status); 669 670 if (status & S_RX_COMPLETE) 671 vxread(sc); 672 if (status & S_TX_AVAIL) { 673 ifp->if_timer = 0; 674 sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; 675 vxstart(&sc->arpcom.ac_if); 676 } 677 if (status & S_CARD_FAILURE) { 678 printf("vx%d: adapter failure (%x)\n", sc->unit, status); 679 ifp->if_timer = 0; 680 vxreset(sc); 681 return; 682 } 683 if (status & S_TX_COMPLETE) { 684 ifp->if_timer = 0; 685 vxtxstat(sc); 686 vxstart(ifp); 687 } 688 } 689 690 /* no more interrupts */ 691 return; 692} 693 694static void 695vxread(sc) 696 struct vx_softc *sc; 697{ 698 struct ifnet *ifp = &sc->arpcom.ac_if; 699 struct mbuf *m; 700 struct ether_header *eh; 701 u_int len; 702 703 len = inw(BASE + VX_W1_RX_STATUS); 704 705again: 706 707 if (ifp->if_flags & IFF_DEBUG) { 708 int err = len & ERR_MASK; 709 char *s = NULL; 710 711 if (len & ERR_INCOMPLETE) 712 s = "incomplete packet"; 713 else if (err == ERR_OVERRUN) 714 s = "packet overrun"; 715 else if (err == ERR_RUNT) 716 s = "runt packet"; 717 else if (err == ERR_ALIGNMENT) 718 s = "bad alignment"; 719 else if (err == ERR_CRC) 720 s = "bad crc"; 721 else if (err == ERR_OVERSIZE) 722 s = "oversized packet"; 723 else if (err == ERR_DRIBBLE) 724 s = "dribble bits"; 725 726 if (s) 727 printf("vx%d: %s\n", sc->unit, s); 728 } 729 730 if (len & ERR_INCOMPLETE) 731 return; 732 733 if (len & ERR_RX) { 734 ++ifp->if_ierrors; 735 goto abort; 736 } 737 738 len &= RX_BYTES_MASK; /* Lower 11 bits = RX bytes. */ 739 740 /* Pull packet off interface. */ 741 m = vxget(sc, len); 742 if (m == 0) { 743 ifp->if_ierrors++; 744 goto abort; 745 } 746 747 ++ifp->if_ipackets; 748 749 /* We assume the header fit entirely in one mbuf. */ 750 eh = mtod(m, struct ether_header *); 751 752#if NBPFILTER > 0 753 /* 754 * Check if there's a BPF listener on this interface. 755 * If so, hand off the raw packet to BPF. 756 */ 757 if (sc->arpcom.ac_if.if_bpf) { 758 bpf_mtap(&sc->arpcom.ac_if, m); 759 } 760#endif 761 762 /* 763 * XXX: Some cards seem to be in promiscous mode all the time. 764 * we need to make sure we only get our own stuff always. 765 * bleah! 766 */ 767 768 if ((eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */ 769 bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, 770 sizeof(eh->ether_dhost)) != 0) { 771 m_freem(m); 772 return; 773 } 774 /* We assume the header fit entirely in one mbuf. */ 775 m_adj(m, sizeof(struct ether_header)); 776 ether_input(ifp, eh, m); 777 778 /* 779 * In periods of high traffic we can actually receive enough 780 * packets so that the fifo overrun bit will be set at this point, 781 * even though we just read a packet. In this case we 782 * are not going to receive any more interrupts. We check for 783 * this condition and read again until the fifo is not full. 784 * We could simplify this test by not using vxstatus(), but 785 * rechecking the RX_STATUS register directly. This test could 786 * result in unnecessary looping in cases where there is a new 787 * packet but the fifo is not full, but it will not fix the 788 * stuck behavior. 789 * 790 * Even with this improvement, we still get packet overrun errors 791 * which are hurting performance. Maybe when I get some more time 792 * I'll modify vxread() so that it can handle RX_EARLY interrupts. 793 */ 794 if (vxstatus(sc)) { 795 len = inw(BASE + VX_W1_RX_STATUS); 796 /* Check if we are stuck and reset [see XXX comment] */ 797 if (len & ERR_INCOMPLETE) { 798 if (ifp->if_flags & IFF_DEBUG) 799 printf("vx%d: adapter reset\n", sc->unit); 800 vxreset(sc); 801 return; 802 } 803 goto again; 804 } 805 806 return; 807 808abort: 809 outw(BASE + VX_COMMAND, RX_DISCARD_TOP_PACK); 810} 811 812static struct mbuf * 813vxget(sc, totlen) 814 struct vx_softc *sc; 815 u_int totlen; 816{ 817 struct ifnet *ifp = &sc->arpcom.ac_if; 818 struct mbuf *top, **mp, *m; 819 int len; 820 int sh; 821 822 m = sc->mb[sc->next_mb]; 823 sc->mb[sc->next_mb] = 0; 824 if (m == 0) { 825 MGETHDR(m, M_DONTWAIT, MT_DATA); 826 if (m == 0) 827 return 0; 828 } else { 829 /* If the queue is no longer full, refill. */ 830 if (sc->last_mb == sc->next_mb) 831 timeout(vxmbuffill, sc, 1); 832 /* Convert one of our saved mbuf's. */ 833 sc->next_mb = (sc->next_mb + 1) % MAX_MBS; 834 m->m_data = m->m_pktdat; 835 m->m_flags = M_PKTHDR; 836 } 837 m->m_pkthdr.rcvif = ifp; 838 m->m_pkthdr.len = totlen; 839 len = MHLEN; 840 top = 0; 841 mp = ⊤ 842 843 /* 844 * We read the packet at splhigh() so that an interrupt from another 845 * device doesn't cause the card's buffer to overflow while we're 846 * reading it. We may still lose packets at other times. 847 */ 848 sh = splhigh(); 849 850 while (totlen > 0) { 851 if (top) { 852 m = sc->mb[sc->next_mb]; 853 sc->mb[sc->next_mb] = 0; 854 if (m == 0) { 855 MGET(m, M_DONTWAIT, MT_DATA); 856 if (m == 0) { 857 splx(sh); 858 m_freem(top); 859 return 0; 860 } 861 } else { 862 sc->next_mb = (sc->next_mb + 1) % MAX_MBS; 863 } 864 len = MLEN; 865 } 866 if (totlen >= MINCLSIZE) { 867 MCLGET(m, M_DONTWAIT); 868 if (m->m_flags & M_EXT) 869 len = MCLBYTES; 870 } 871 len = min(totlen, len); 872 if (len > 3) { 873 len &= ~3; 874 insl(BASE + VX_W1_RX_PIO_RD_1, mtod(m, u_int32_t *), 875 len / 4); 876 } else 877 insb(BASE + VX_W1_RX_PIO_RD_1, mtod(m, u_int8_t *), 878 len); 879 m->m_len = len; 880 totlen -= len; 881 *mp = m; 882 mp = &m->m_next; 883 } 884 885 outw(BASE +VX_COMMAND, RX_DISCARD_TOP_PACK); 886 887 splx(sh); 888 889 return top; 890} 891 892 893static int 894vxioctl(ifp, cmd, data) 895 register struct ifnet *ifp; 896 int cmd; 897 caddr_t data; 898{ 899 struct vx_softc *sc = vx_softc[ifp->if_unit]; 900 struct ifaddr *ifa = (struct ifaddr *) data; 901 struct ifreq *ifr = (struct ifreq *) data; 902 int s, error = 0; 903 904 s = splimp(); 905 906 switch (cmd) { 907 case SIOCSIFADDR: 908 case SIOCGIFADDR: 909 ether_ioctl(ifp, cmd, data); 910 break; 911 912 case SIOCSIFFLAGS: 913 if ((ifp->if_flags & IFF_UP) == 0 && 914 (ifp->if_flags & IFF_RUNNING) != 0) { 915 /* 916 * If interface is marked up and it is stopped, then 917 * start it. 918 */ 919 vxstop(sc); 920 ifp->if_flags &= ~IFF_RUNNING; 921 } else if ((ifp->if_flags & IFF_UP) != 0 && 922 (ifp->if_flags & IFF_RUNNING) == 0) { 923 /* 924 * If interface is marked up and it is stopped, then 925 * start it. 926 */ 927 vxinit(sc); 928 } else { 929 /* 930 * deal with flags changes: 931 * IFF_MULTICAST, IFF_PROMISC, 932 * IFF_LINK0, IFF_LINK1, 933 */ 934 vxsetfilter(sc); 935 vxsetlink(sc); 936 } 937 break; 938 939 case SIOCSIFMTU: 940 /* 941 * Set the interface MTU. 942 */ 943 if (ifr->ifr_mtu > ETHERMTU) { 944 error = EINVAL; 945 } else { 946 ifp->if_mtu = ifr->ifr_mtu; 947 } 948 break; 949 950 case SIOCADDMULTI: 951 case SIOCDELMULTI: 952 /* 953 * Multicast list has changed; set the hardware filter 954 * accordingly. 955 */ 956 vxreset(sc); 957 error = 0; 958 break; 959 960 961 default: 962 error = EINVAL; 963 } 964 965 splx(s); 966 967 return (error); 968} 969 970static void 971vxreset(sc) 972 struct vx_softc *sc; 973{ 974 int s; 975 s = splimp(); 976 977 vxstop(sc); 978 vxinit(sc); 979 splx(s); 980} 981 982static void 983vxwatchdog(ifp) 984 struct ifnet *ifp; 985{ 986 struct vx_softc *sc = vx_softc[ifp->if_unit]; 987 988 if (ifp->if_flags & IFF_DEBUG) 989 printf("vx%d: device timeout\n", ifp->if_unit); 990 ifp->if_flags &= ~IFF_OACTIVE; 991 vxstart(ifp); 992 vxintr(sc); 993} 994 995void 996vxstop(sc) 997 struct vx_softc *sc; 998{ 999 struct ifnet *ifp = &sc->arpcom.ac_if; 1000 1001 ifp->if_timer = 0; 1002 1003 outw(BASE + VX_COMMAND, RX_DISABLE); 1004 outw(BASE + VX_COMMAND, RX_DISCARD_TOP_PACK); 1005 VX_BUSY_WAIT; 1006 outw(BASE + VX_COMMAND, TX_DISABLE); 1007 outw(BASE + VX_COMMAND, STOP_TRANSCEIVER); 1008 DELAY(800); 1009 outw(BASE + VX_COMMAND, RX_RESET); 1010 VX_BUSY_WAIT; 1011 outw(BASE + VX_COMMAND, TX_RESET); 1012 VX_BUSY_WAIT; 1013 outw(BASE + VX_COMMAND, C_INTR_LATCH); 1014 outw(BASE + VX_COMMAND, SET_RD_0_MASK); 1015 outw(BASE + VX_COMMAND, SET_INTR_MASK); 1016 outw(BASE + VX_COMMAND, SET_RX_FILTER); 1017 1018 vxmbufempty(sc); 1019} 1020 1021int 1022vxbusyeeprom(sc) 1023 struct vx_softc *sc; 1024{ 1025 int j, i = 100; 1026 1027 while (i--) { 1028 j = inw(BASE + VX_W0_EEPROM_COMMAND); 1029 if (j & EEPROM_BUSY) 1030 DELAY(100); 1031 else 1032 break; 1033 } 1034 if (!i) { 1035 printf("vx%d: eeprom failed to come ready\n", sc->unit); 1036 return (1); 1037 } 1038 return (0); 1039} 1040 1041static void 1042vxmbuffill(sp) 1043 void *sp; 1044{ 1045 struct vx_softc *sc = (struct vx_softc *) sp; 1046 int s, i; 1047 1048 s = splimp(); 1049 i = sc->last_mb; 1050 do { 1051 if (sc->mb[i] == NULL) 1052 MGET(sc->mb[i], M_DONTWAIT, MT_DATA); 1053 if (sc->mb[i] == NULL) 1054 break; 1055 i = (i + 1) % MAX_MBS; 1056 } while (i != sc->next_mb); 1057 sc->last_mb = i; 1058 /* If the queue was not filled, try again. */ 1059 if (sc->last_mb != sc->next_mb) 1060 timeout(vxmbuffill, sc, 1); 1061 splx(s); 1062} 1063 1064static void 1065vxmbufempty(sc) 1066 struct vx_softc *sc; 1067{ 1068 int s, i; 1069 1070 s = splimp(); 1071 for (i = 0; i < MAX_MBS; i++) { 1072 if (sc->mb[i]) { 1073 m_freem(sc->mb[i]); 1074 sc->mb[i] = NULL; 1075 } 1076 } 1077 sc->last_mb = sc->next_mb = 0; 1078 untimeout(vxmbuffill, sc); 1079 splx(s); 1080} 1081 1082#endif /* NVX > 0 */ 1083