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