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