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