if_vx.c revision 33707
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 * $Id$ 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 "bpfilter.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 NBPFILTER > 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 *, int, 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/* void vxintr __P((void *)); */ 135 136struct vx_softc * 137vxalloc(unit) 138 int unit; 139{ 140 struct vx_softc *sc; 141 142 if (unit >= NVX) { 143 printf("vx%d: unit number too high.\n", unit); 144 return NULL; 145 } 146 147 if (vx_softc[unit]) { 148 printf("vx%d: already allocated.\n", unit); 149 return NULL; 150 } 151 152 sc = malloc(sizeof(struct vx_softc), M_DEVBUF, M_NOWAIT); 153 if (sc == NULL) { 154 printf("vx%d: cannot malloc.\n", unit); 155 return NULL; 156 } 157 bzero(sc, sizeof(struct vx_softc)); 158 callout_handle_init(&sc->ch); 159 160 vx_softc[unit] = sc; 161 sc->unit = unit; 162 return (sc); 163} 164 165void 166vxfree(sc) 167 struct vx_softc *sc; 168{ 169 vx_softc[sc->unit] = NULL; 170 free(sc, M_DEVBUF); 171 return; 172} 173 174int 175vxattach(sc) 176 struct vx_softc *sc; 177{ 178 struct ifnet *ifp = &sc->arpcom.ac_if; 179 int i; 180 181 GO_WINDOW(0); 182 outw(VX_COMMAND, GLOBAL_RESET); 183 VX_BUSY_WAIT; 184 185 vxgetlink(sc); 186 187 /* 188 * Read the station address from the eeprom 189 */ 190 GO_WINDOW(0); 191 for (i = 0; i < 3; i++) { 192 int x; 193 if (vxbusyeeprom(sc)) 194 return 0; 195 outw(BASE + VX_W0_EEPROM_COMMAND, EEPROM_CMD_RD 196 | (EEPROM_OEM_ADDR_0 + i)); 197 if (vxbusyeeprom(sc)) 198 return 0; 199 x = inw(BASE + VX_W0_EEPROM_DATA); 200 sc->arpcom.ac_enaddr[(i << 1)] = x >> 8; 201 sc->arpcom.ac_enaddr[(i << 1) + 1] = x; 202 } 203 204 printf(" address %6D\n", sc->arpcom.ac_enaddr, ":"); 205 206 ifp->if_unit = sc->unit; 207 ifp->if_name = "vx"; 208 ifp->if_mtu = ETHERMTU; 209 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 210 ifp->if_output = ether_output; 211 ifp->if_start = vxstart; 212 ifp->if_ioctl = vxioctl; 213 ifp->if_init = vxinit; 214 ifp->if_watchdog = vxwatchdog; 215 ifp->if_softc = sc; 216 217 if_attach(ifp); 218 ether_ifattach(ifp); 219 220#if NBPFILTER > 0 221 bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); 222#endif 223 224 sc->tx_start_thresh = 20; /* probably a good starting point. */ 225 226 vxstop(sc); 227 228 return 1; 229} 230 231 232 233/* 234 * The order in here seems important. Otherwise we may not receive 235 * interrupts. ?! 236 */ 237static void 238vxinit(xsc) 239 void *xsc; 240{ 241 struct vx_softc *sc = (struct vx_softc *) xsc; 242 struct ifnet *ifp = &sc->arpcom.ac_if; 243 int i; 244 245 VX_BUSY_WAIT; 246 247 GO_WINDOW(2); 248 249 for (i = 0; i < 6; i++) /* Reload the ether_addr. */ 250 outb(BASE + VX_W2_ADDR_0 + i, sc->arpcom.ac_enaddr[i]); 251 252 outw(BASE + VX_COMMAND, RX_RESET); 253 VX_BUSY_WAIT; 254 outw(BASE + VX_COMMAND, TX_RESET); 255 VX_BUSY_WAIT; 256 257 GO_WINDOW(1); /* Window 1 is operating window */ 258 for (i = 0; i < 31; i++) 259 inb(BASE + VX_W1_TX_STATUS); 260 261 outw(BASE + VX_COMMAND,SET_RD_0_MASK | S_CARD_FAILURE | 262 S_RX_COMPLETE | S_TX_COMPLETE | S_TX_AVAIL); 263 outw(BASE + VX_COMMAND,SET_INTR_MASK | S_CARD_FAILURE | 264 S_RX_COMPLETE | S_TX_COMPLETE | S_TX_AVAIL); 265 266 /* 267 * Attempt to get rid of any stray interrupts that occured during 268 * configuration. On the i386 this isn't possible because one may 269 * already be queued. However, a single stray interrupt is 270 * unimportant. 271 */ 272 outw(BASE + VX_COMMAND, ACK_INTR | 0xff); 273 274 vxsetfilter(sc); 275 vxsetlink(sc); 276 277 outw(BASE + VX_COMMAND, RX_ENABLE); 278 outw(BASE + VX_COMMAND, TX_ENABLE); 279 280 vxmbuffill((caddr_t) sc); 281 282 /* Interface is now `running', with no output active. */ 283 ifp->if_flags |= IFF_RUNNING; 284 ifp->if_flags &= ~IFF_OACTIVE; 285 286 /* Attempt to start output, if any. */ 287 vxstart(ifp); 288} 289 290static void 291vxsetfilter(sc) 292 struct vx_softc *sc; 293{ 294 register struct ifnet *ifp = &sc->arpcom.ac_if; 295 296 GO_WINDOW(1); /* Window 1 is operating window */ 297 outw(BASE + VX_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL | FIL_BRDCST | 298 FIL_MULTICAST | 299 ((ifp->if_flags & IFF_PROMISC) ? FIL_PROMISC : 0 )); 300} 301 302static void 303vxgetlink(sc) 304 struct vx_softc *sc; 305{ 306 int n, k; 307 308 GO_WINDOW(3); 309 sc->vx_connectors = inw(BASE + VX_W3_RESET_OPT) & 0x7f; 310 for (n = 0, k = 0; k < VX_CONNECTORS; k++) { 311 if (sc->vx_connectors & conn_tab[k].bit) { 312 if (n > 0) { 313 printf("/"); 314 } 315 printf(conn_tab[k].name); 316 n++; 317 } 318 } 319 if (sc->vx_connectors == 0) { 320 printf("no connectors!"); 321 return; 322 } 323 GO_WINDOW(3); 324 sc->vx_connector = (inl(BASE + VX_W3_INTERNAL_CFG) 325 & INTERNAL_CONNECTOR_MASK) 326 >> INTERNAL_CONNECTOR_BITS; 327 if (sc->vx_connector & 0x10) { 328 sc->vx_connector &= 0x0f; 329 printf("[*%s*]", conn_tab[sc->vx_connector].name); 330 printf(": disable 'auto select' with DOS util!", sc->unit); 331 } else { 332 printf("[*%s*]", conn_tab[sc->vx_connector].name); 333 } 334} 335 336static void 337vxsetlink(sc) 338 struct vx_softc *sc; 339{ 340 register struct ifnet *ifp = &sc->arpcom.ac_if; 341 int i, j, k; 342 char *reason, *warning; 343 static short prev_flags; 344 static char prev_conn = -1; 345 346 if (prev_conn == -1) { 347 prev_conn = sc->vx_connector; 348 } 349 350 /* 351 * S.B. 352 * 353 * Now behavior was slightly changed: 354 * 355 * if any of flags link[0-2] is used and its connector is 356 * physically present the following connectors are used: 357 * 358 * link0 - AUI * highest precedence 359 * link1 - BNC 360 * link2 - UTP * lowest precedence 361 * 362 * If none of them is specified then 363 * connector specified in the EEPROM is used 364 * (if present on card or UTP if not). 365 */ 366 367 i = sc->vx_connector; /* default in EEPROM */ 368 reason = "default"; 369 warning = 0; 370 371 if (ifp->if_flags & IFF_LINK0) { 372 if (sc->vx_connectors & conn_tab[CONNECTOR_AUI].bit) { 373 i = CONNECTOR_AUI; 374 reason = "link0"; 375 } else { 376 warning = "aui not present! (link0)"; 377 } 378 } else if (ifp->if_flags & IFF_LINK1) { 379 if (sc->vx_connectors & conn_tab[CONNECTOR_BNC].bit) { 380 i = CONNECTOR_BNC; 381 reason = "link1"; 382 } else { 383 warning = "bnc not present! (link1)"; 384 } 385 } else if (ifp->if_flags & IFF_LINK2) { 386 if (sc->vx_connectors & conn_tab[CONNECTOR_UTP].bit) { 387 i = CONNECTOR_UTP; 388 reason = "link2"; 389 } else { 390 warning = "utp not present! (link2)"; 391 } 392 } else if ((sc->vx_connectors & conn_tab[sc->vx_connector].bit) == 0) { 393 warning = "strange connector type in EEPROM."; 394 reason = "forced"; 395 i = CONNECTOR_UTP; 396 } 397 398 /* Avoid unnecessary message. */ 399 k = (prev_flags ^ ifp->if_flags) & (IFF_LINK0 | IFF_LINK1 | IFF_LINK2); 400 if ((k != 0) || (prev_conn != i)) { 401 if (warning != 0) { 402 printf("vx%d: warning: %s\n", sc->unit, warning); 403 } 404 printf("vx%d: selected %s. (%s)\n", 405 sc->unit, conn_tab[i].name, reason); 406 } 407 408 /* Set the selected connector. */ 409 GO_WINDOW(3); 410 j = inl(BASE + VX_W3_INTERNAL_CFG) & ~INTERNAL_CONNECTOR_MASK; 411 outl(BASE + VX_W3_INTERNAL_CFG, j | (i <<INTERNAL_CONNECTOR_BITS)); 412 413 /* First, disable all. */ 414 outw(BASE + VX_COMMAND, STOP_TRANSCEIVER); 415 DELAY(800); 416 GO_WINDOW(4); 417 outw(BASE + VX_W4_MEDIA_TYPE, 0); 418 419 /* Second, enable the selected one. */ 420 switch(i) { 421 case CONNECTOR_UTP: 422 GO_WINDOW(4); 423 outw(BASE + VX_W4_MEDIA_TYPE, ENABLE_UTP); 424 break; 425 case CONNECTOR_BNC: 426 outw(BASE + VX_COMMAND, START_TRANSCEIVER); 427 DELAY(800); 428 break; 429 case CONNECTOR_TX: 430 case CONNECTOR_FX: 431 GO_WINDOW(4); 432 outw(BASE + VX_W4_MEDIA_TYPE, LINKBEAT_ENABLE); 433 break; 434 default: /* AUI and MII fall here */ 435 break; 436 } 437 GO_WINDOW(1); 438 439 prev_flags = ifp->if_flags; 440 prev_conn = i; 441} 442 443static void 444vxstart(ifp) 445 struct ifnet *ifp; 446{ 447 register struct vx_softc *sc = vx_softc[ifp->if_unit]; 448 register struct mbuf *m, *m0; 449 int sh, len, pad; 450 451 /* Don't transmit if interface is busy or not running */ 452 if ((sc->arpcom.ac_if.if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING) 453 return; 454 455startagain: 456 /* Sneak a peek at the next packet */ 457 m0 = ifp->if_snd.ifq_head; 458 if (m0 == 0) { 459 return; 460 } 461 /* We need to use m->m_pkthdr.len, so require the header */ 462 if ((m0->m_flags & M_PKTHDR) == 0) 463 panic("vxstart: no header mbuf"); 464 len = m0->m_pkthdr.len; 465 466 pad = (4 - len) & 3; 467 468 /* 469 * The 3c509 automatically pads short packets to minimum ethernet length, 470 * but we drop packets that are too large. Perhaps we should truncate 471 * them instead? 472 */ 473 if (len + pad > ETHER_MAX_LEN) { 474 /* packet is obviously too large: toss it */ 475 ++ifp->if_oerrors; 476 IF_DEQUEUE(&ifp->if_snd, m0); 477 m_freem(m0); 478 goto readcheck; 479 } 480 VX_BUSY_WAIT; 481 if (inw(BASE + VX_W1_FREE_TX) < len + pad + 4) { 482 outw(BASE + VX_COMMAND, SET_TX_AVAIL_THRESH | ((len + pad + 4) >> 2)); 483 /* not enough room in FIFO */ 484 if (inw(BASE + VX_W1_FREE_TX) < len + pad + 4) { /* make sure */ 485 ifp->if_flags |= IFF_OACTIVE; 486 ifp->if_timer = 1; 487 return; 488 } 489 } 490 outw(BASE + VX_COMMAND, SET_TX_AVAIL_THRESH | (8188 >> 2)); 491 IF_DEQUEUE(&ifp->if_snd, m0); 492 if (m0 == 0) { /* not really needed */ 493 return; 494 } 495 496 VX_BUSY_WAIT; 497 outw(BASE + VX_COMMAND, SET_TX_START_THRESH | 498 ((len / 4 + sc->tx_start_thresh) >> 2)); 499 500#if NBPFILTER > 0 501 if (sc->arpcom.ac_if.if_bpf) { 502 bpf_mtap(&sc->arpcom.ac_if, m0); 503 } 504#endif 505 506 /* 507 * Do the output at splhigh() so that an interrupt from another device 508 * won't cause a FIFO underrun. 509 */ 510 sh = splhigh(); 511 512 outl(BASE + VX_W1_TX_PIO_WR_1, len | TX_INDICATE); 513 514 for (m = m0; m != 0;) { 515 if (m->m_len > 3) 516 outsl(BASE + VX_W1_TX_PIO_WR_1, mtod(m, caddr_t), m->m_len / 4); 517 if (m->m_len & 3) 518 outsb(BASE + VX_W1_TX_PIO_WR_1, 519 mtod(m, caddr_t) + (m->m_len & ~3) , m->m_len & 3); 520 MFREE(m, m0); 521 m = m0; 522 } 523 while (pad--) 524 outb(BASE + VX_W1_TX_PIO_WR_1, 0); /* Padding */ 525 526 splx(sh); 527 528 ++ifp->if_opackets; 529 ifp->if_timer = 1; 530 531readcheck: 532 if ((inw(BASE + VX_W1_RX_STATUS) & ERR_INCOMPLETE) == 0) { 533 /* We received a complete packet. */ 534 535 if ((inw(BASE + VX_STATUS) & S_INTR_LATCH) == 0) { 536 /* 537 * No interrupt, read the packet and continue 538 * Is this supposed to happen? Is my motherboard 539 * completely busted? 540 */ 541 vxread(sc); 542 } else 543 /* Got an interrupt, return so that it gets serviced. */ 544 return; 545 } else { 546 /* Check if we are stuck and reset [see XXX comment] */ 547 if (vxstatus(sc)) { 548 if (ifp->if_flags & IFF_DEBUG) 549 printf("vx%d: adapter reset\n", ifp->if_unit); 550 vxreset(sc); 551 } 552 } 553 554 goto startagain; 555} 556 557/* 558 * XXX: The 3c509 card can get in a mode where both the fifo status bit 559 * FIFOS_RX_OVERRUN and the status bit ERR_INCOMPLETE are set 560 * We detect this situation and we reset the adapter. 561 * It happens at times when there is a lot of broadcast traffic 562 * on the cable (once in a blue moon). 563 */ 564static int 565vxstatus(sc) 566 struct vx_softc *sc; 567{ 568 int fifost; 569 570 /* 571 * Check the FIFO status and act accordingly 572 */ 573 GO_WINDOW(4); 574 fifost = inw(BASE + VX_W4_FIFO_DIAG); 575 GO_WINDOW(1); 576 577 if (fifost & FIFOS_RX_UNDERRUN) { 578 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) 579 printf("vx%d: RX underrun\n", sc->unit); 580 vxreset(sc); 581 return 0; 582 } 583 584 if (fifost & FIFOS_RX_STATUS_OVERRUN) { 585 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) 586 printf("vx%d: RX Status overrun\n", sc->unit); 587 return 1; 588 } 589 590 if (fifost & FIFOS_RX_OVERRUN) { 591 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) 592 printf("vx%d: RX overrun\n", sc->unit); 593 return 1; 594 } 595 596 if (fifost & FIFOS_TX_OVERRUN) { 597 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) 598 printf("vx%d: TX overrun\n", sc->unit); 599 vxreset(sc); 600 return 0; 601 } 602 603 return 0; 604} 605 606static void 607vxtxstat(sc) 608 struct vx_softc *sc; 609{ 610 int i; 611 612 /* 613 * We need to read+write TX_STATUS until we get a 0 status 614 * in order to turn off the interrupt flag. 615 */ 616 while ((i = inb(BASE + VX_W1_TX_STATUS)) & TXS_COMPLETE) { 617 outb(BASE + VX_W1_TX_STATUS, 0x0); 618 619 if (i & TXS_JABBER) { 620 ++sc->arpcom.ac_if.if_oerrors; 621 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) 622 printf("vx%d: jabber (%x)\n", sc->unit, i); 623 vxreset(sc); 624 } else if (i & TXS_UNDERRUN) { 625 ++sc->arpcom.ac_if.if_oerrors; 626 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) 627 printf("vx%d: fifo underrun (%x) @%d\n", 628 sc->unit, i, sc->tx_start_thresh); 629 if (sc->tx_succ_ok < 100) 630 sc->tx_start_thresh = min(ETHER_MAX_LEN, sc->tx_start_thresh + 20); 631 sc->tx_succ_ok = 0; 632 vxreset(sc); 633 } else if (i & TXS_MAX_COLLISION) { 634 ++sc->arpcom.ac_if.if_collisions; 635 outw(BASE + VX_COMMAND, TX_ENABLE); 636 sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; 637 } else 638 sc->tx_succ_ok = (sc->tx_succ_ok+1) & 127; 639 } 640} 641 642void 643vxintr(sc) 644 struct vx_softc *sc; 645{ 646 register short status; 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 NBPFILTER > 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 int 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