if_vx.c revision 68417
139230Sgibbs/* 239230Sgibbs * Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca> 339230Sgibbs * All rights reserved. 439230Sgibbs * 539230Sgibbs * Redistribution and use in source and binary forms, with or without 639230Sgibbs * modification, are permitted provided that the following conditions 739230Sgibbs * are met: 839230Sgibbs * 1. Redistributions of source code must retain the above copyright 939230Sgibbs * notice, this list of conditions and the following disclaimer. 1039230Sgibbs * 2. Redistributions in binary form must reproduce the above copyright 1139230Sgibbs * notice, this list of conditions and the following disclaimer in the 1239230Sgibbs * documentation and/or other materials provided with the distribution. 1339230Sgibbs * 3. All advertising materials mentioning features or use of this software 1439230Sgibbs * must display the following acknowledgement: 1539230Sgibbs * This product includes software developed by Herb Peyerl. 1639230Sgibbs * 4. The name of Herb Peyerl may not be used to endorse or promote products 1739230Sgibbs * derived from this software without specific prior written permission. 1839230Sgibbs * 1939230Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2039230Sgibbs * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2139230Sgibbs * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2239230Sgibbs * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2339230Sgibbs * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2439230Sgibbs * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2539230Sgibbs * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2639230Sgibbs * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2739230Sgibbs * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2850477Speter * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2939230Sgibbs * 3039230Sgibbs * $FreeBSD: head/sys/dev/vx/if_vx.c 68417 2000-11-07 00:56:14Z wpaul $ 3139230Sgibbs * 3239230Sgibbs */ 3339230Sgibbs 3439230Sgibbs/* 3539230Sgibbs * Created from if_ep.c driver by Fred Gray (fgray@rice.edu) to support 3639230Sgibbs * the 3c590 family. 3739230Sgibbs */ 3839230Sgibbs 3939230Sgibbs/* 4039230Sgibbs * Modified from the FreeBSD 1.1.5.1 version by: 4139230Sgibbs * Andres Vega Garcia 4239230Sgibbs * INRIA - Sophia Antipolis, France 4339230Sgibbs * avega@sophia.inria.fr 4439230Sgibbs */ 4539230Sgibbs 4639230Sgibbs/* 4739230Sgibbs * Promiscuous mode added and interrupt logic slightly changed 4839230Sgibbs * to reduce the number of adapter failures. Transceiver select 4939230Sgibbs * logic changed to use value from EEPROM. Autoconfiguration 5039230Sgibbs * features added. 5139230Sgibbs * Done by: 5239230Sgibbs * Serge Babkin 5339230Sgibbs * Chelindbank (Chelyabinsk, Russia) 5439230Sgibbs * babkin@hq.icb.chel.su 5539230Sgibbs */ 5639230Sgibbs 5739230Sgibbs 5839230Sgibbs#include <sys/param.h> 5939230Sgibbs#include <sys/systm.h> 6039230Sgibbs#include <sys/sockio.h> 6139230Sgibbs#include <sys/malloc.h> 6239230Sgibbs#include <sys/mbuf.h> 6339230Sgibbs#include <sys/socket.h> 6439230Sgibbs 6539230Sgibbs#include <net/if.h> 6639230Sgibbs 6739230Sgibbs#include <net/ethernet.h> 6839230Sgibbs#include <net/if_arp.h> 6939230Sgibbs 7039230Sgibbs#include <machine/bus_pio.h> 7139230Sgibbs#include <machine/bus.h> 7239230Sgibbs 7340060Sobrien#include <net/bpf.h> 7440060Sobrien 7540060Sobrien 7639230Sgibbs#include <dev/vx/if_vxreg.h> 7739230Sgibbs 7840060Sobrien#define ETHER_MAX_LEN 1518 7939230Sgibbs#define ETHER_ADDR_LEN 6 8039230Sgibbs 8139230Sgibbsstatic struct connector_entry { 8239230Sgibbs int bit; 8339230Sgibbs char *name; 8439230Sgibbs} conn_tab[VX_CONNECTORS] = { 8539230Sgibbs#define CONNECTOR_UTP 0 8639230Sgibbs { 0x08, "utp"}, 8739230Sgibbs#define CONNECTOR_AUI 1 8839498Sken { 0x20, "aui"}, 8939498Sken/* dummy */ 9039498Sken { 0, "???"}, 9139498Sken#define CONNECTOR_BNC 3 9239230Sgibbs { 0x10, "bnc"}, 9339230Sgibbs#define CONNECTOR_TX 4 9439230Sgibbs { 0x02, "tx"}, 9539230Sgibbs#define CONNECTOR_FX 5 9639230Sgibbs { 0x04, "fx"}, 9739230Sgibbs#define CONNECTOR_MII 6 9839230Sgibbs { 0x40, "mii"}, 9939230Sgibbs { 0, "???"} 10039230Sgibbs}; 10139230Sgibbs 10239230Sgibbs/* int vxattach __P((struct vx_softc *)); */ 10339230Sgibbsstatic void vxtxstat __P((struct vx_softc *)); 10439230Sgibbsstatic int vxstatus __P((struct vx_softc *)); 10539230Sgibbsstatic void vxinit __P((void *)); 10639230Sgibbsstatic int vxioctl __P((struct ifnet *, u_long, caddr_t)); 10739230Sgibbsstatic void vxstart __P((struct ifnet *ifp)); 10839230Sgibbsstatic void vxwatchdog __P((struct ifnet *)); 10939230Sgibbsstatic void vxreset __P((struct vx_softc *)); 11039230Sgibbs/* void vxstop __P((struct vx_softc *)); */ 11139230Sgibbsstatic void vxread __P((struct vx_softc *)); 11283131Skenstatic struct mbuf *vxget __P((struct vx_softc *, u_int)); 11339230Sgibbsstatic void vxmbuffill __P((void *)); 11439230Sgibbsstatic void vxmbufempty __P((struct vx_softc *)); 11539230Sgibbsstatic void vxsetfilter __P((struct vx_softc *)); 11639230Sgibbsstatic void vxgetlink __P((struct vx_softc *)); 11739230Sgibbsstatic void vxsetlink __P((struct vx_softc *)); 11839230Sgibbs/* int vxbusyeeprom __P((struct vx_softc *)); */ 11939230Sgibbs 12039230Sgibbs 12139230Sgibbsint 12283131Skenvxattach(sc) 12339230Sgibbs struct vx_softc *sc; 12439230Sgibbs{ 12539230Sgibbs struct ifnet *ifp = &sc->arpcom.ac_if; 12639230Sgibbs int i; 12739230Sgibbs 12839230Sgibbs callout_handle_init(&sc->ch); 12939230Sgibbs GO_WINDOW(0); 13039230Sgibbs CSR_WRITE_2(sc, VX_COMMAND, GLOBAL_RESET); 13139230Sgibbs VX_BUSY_WAIT; 13239230Sgibbs 13339230Sgibbs vxgetlink(sc); 13439230Sgibbs 13583131Sken /* 13683131Sken * Read the station address from the eeprom 13783131Sken */ 13839230Sgibbs GO_WINDOW(0); 13939230Sgibbs for (i = 0; i < 3; i++) { 14039230Sgibbs int x; 14139230Sgibbs if (vxbusyeeprom(sc)) 14239230Sgibbs return 0; 14339230Sgibbs CSR_WRITE_2(sc, VX_W0_EEPROM_COMMAND, EEPROM_CMD_RD 14439230Sgibbs | (EEPROM_OEM_ADDR_0 + i)); 14539230Sgibbs if (vxbusyeeprom(sc)) 14639230Sgibbs return 0; 14739230Sgibbs x = CSR_READ_2(sc, VX_W0_EEPROM_DATA); 14839230Sgibbs sc->arpcom.ac_enaddr[(i << 1)] = x >> 8; 14939230Sgibbs sc->arpcom.ac_enaddr[(i << 1) + 1] = x; 15039230Sgibbs } 15139230Sgibbs 15239230Sgibbs printf(" address %6D\n", sc->arpcom.ac_enaddr, ":"); 15339230Sgibbs 15439230Sgibbs ifp->if_unit = sc->unit; 15539230Sgibbs ifp->if_name = "vx"; 15639230Sgibbs ifp->if_mtu = ETHERMTU; 15783131Sken ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 15883131Sken ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 15983131Sken ifp->if_output = ether_output; 16083131Sken ifp->if_start = vxstart; 16183131Sken ifp->if_ioctl = vxioctl; 16283131Sken ifp->if_init = vxinit; 16383131Sken ifp->if_watchdog = vxwatchdog; 16483131Sken ifp->if_softc = sc; 16583131Sken 16639230Sgibbs ether_ifattach(ifp, ETHER_BPF_SUPPORTED); 16739230Sgibbs 16839230Sgibbs sc->tx_start_thresh = 20; /* probably a good starting point. */ 16939230Sgibbs 17039230Sgibbs vxstop(sc); 17139230Sgibbs 17239230Sgibbs return 1; 17339230Sgibbs} 17439230Sgibbs 17539230Sgibbs 17639230Sgibbs 17739230Sgibbs/* 17839230Sgibbs * The order in here seems important. Otherwise we may not receive 17939230Sgibbs * interrupts. ?! 18039230Sgibbs */ 18139230Sgibbsstatic void 18239230Sgibbsvxinit(xsc) 18339230Sgibbs void *xsc; 18439230Sgibbs{ 18539230Sgibbs struct vx_softc *sc = (struct vx_softc *) xsc; 18639230Sgibbs struct ifnet *ifp = &sc->arpcom.ac_if; 18739230Sgibbs int i; 18839230Sgibbs 18939230Sgibbs VX_BUSY_WAIT; 19039230Sgibbs 19139230Sgibbs GO_WINDOW(2); 19239230Sgibbs 19339230Sgibbs for (i = 0; i < 6; i++) /* Reload the ether_addr. */ 19439230Sgibbs CSR_WRITE_1(sc, VX_W2_ADDR_0 + i, sc->arpcom.ac_enaddr[i]); 19539230Sgibbs 19639230Sgibbs CSR_WRITE_2(sc, VX_COMMAND, RX_RESET); 19739230Sgibbs VX_BUSY_WAIT; 19839230Sgibbs CSR_WRITE_2(sc, VX_COMMAND, TX_RESET); 19939230Sgibbs VX_BUSY_WAIT; 20039230Sgibbs 20139230Sgibbs GO_WINDOW(1); /* Window 1 is operating window */ 20239230Sgibbs for (i = 0; i < 31; i++) 20339230Sgibbs CSR_READ_1(sc, VX_W1_TX_STATUS); 20439230Sgibbs 20539230Sgibbs CSR_WRITE_2(sc, VX_COMMAND,SET_RD_0_MASK | S_CARD_FAILURE | 20639230Sgibbs S_RX_COMPLETE | S_TX_COMPLETE | S_TX_AVAIL); 20739230Sgibbs CSR_WRITE_2(sc, VX_COMMAND,SET_INTR_MASK | S_CARD_FAILURE | 20839230Sgibbs S_RX_COMPLETE | S_TX_COMPLETE | S_TX_AVAIL); 20939230Sgibbs 21039230Sgibbs /* 21139230Sgibbs * Attempt to get rid of any stray interrupts that occured during 21239230Sgibbs * configuration. On the i386 this isn't possible because one may 21339230Sgibbs * already be queued. However, a single stray interrupt is 21439230Sgibbs * unimportant. 21539230Sgibbs */ 21639230Sgibbs CSR_WRITE_2(sc, VX_COMMAND, ACK_INTR | 0xff); 21739230Sgibbs 21839230Sgibbs vxsetfilter(sc); 21939230Sgibbs vxsetlink(sc); 22039230Sgibbs 22139230Sgibbs CSR_WRITE_2(sc, VX_COMMAND, RX_ENABLE); 22283131Sken CSR_WRITE_2(sc, VX_COMMAND, TX_ENABLE); 22339230Sgibbs 22439230Sgibbs vxmbuffill((caddr_t) sc); 22539230Sgibbs 22639230Sgibbs /* Interface is now `running', with no output active. */ 22739230Sgibbs ifp->if_flags |= IFF_RUNNING; 22839230Sgibbs ifp->if_flags &= ~IFF_OACTIVE; 22939230Sgibbs 23039230Sgibbs /* Attempt to start output, if any. */ 23183131Sken vxstart(ifp); 23283131Sken} 23383131Sken 23483131Skenstatic void 23539230Sgibbsvxsetfilter(sc) 23639230Sgibbs struct vx_softc *sc; 23739230Sgibbs{ 23839230Sgibbs register struct ifnet *ifp = &sc->arpcom.ac_if; 23939230Sgibbs 24039230Sgibbs GO_WINDOW(1); /* Window 1 is operating window */ 24139230Sgibbs CSR_WRITE_2(sc, VX_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL | FIL_BRDCST | 24239230Sgibbs FIL_MULTICAST | 24339230Sgibbs ((ifp->if_flags & IFF_PROMISC) ? FIL_PROMISC : 0 )); 24439230Sgibbs} 24539230Sgibbs 24639230Sgibbsstatic void 24739230Sgibbsvxgetlink(sc) 24839230Sgibbs struct vx_softc *sc; 24939230Sgibbs{ 25039230Sgibbs int n, k; 25139230Sgibbs 25239230Sgibbs GO_WINDOW(3); 25339230Sgibbs sc->vx_connectors = CSR_READ_2(sc, VX_W3_RESET_OPT) & 0x7f; 25439230Sgibbs for (n = 0, k = 0; k < VX_CONNECTORS; k++) { 25539230Sgibbs if (sc->vx_connectors & conn_tab[k].bit) { 25639230Sgibbs if (n > 0) { 25739230Sgibbs printf("/"); 25839230Sgibbs } 25939230Sgibbs printf(conn_tab[k].name); 26039230Sgibbs n++; 26139230Sgibbs } 26239230Sgibbs } 26339230Sgibbs if (sc->vx_connectors == 0) { 26439230Sgibbs printf("no connectors!"); 26539230Sgibbs return; 26639230Sgibbs } 26739230Sgibbs GO_WINDOW(3); 26839230Sgibbs sc->vx_connector = (CSR_READ_4(sc, VX_W3_INTERNAL_CFG) 26939230Sgibbs & INTERNAL_CONNECTOR_MASK) 27039230Sgibbs >> INTERNAL_CONNECTOR_BITS; 27139230Sgibbs if (sc->vx_connector & 0x10) { 27239230Sgibbs sc->vx_connector &= 0x0f; 27339230Sgibbs printf("[*%s*]", conn_tab[(int)sc->vx_connector].name); 27439230Sgibbs printf(": disable 'auto select' with DOS util!"); 27539230Sgibbs } else { 27639230Sgibbs printf("[*%s*]", conn_tab[(int)sc->vx_connector].name); 27739230Sgibbs } 27839230Sgibbs} 27939230Sgibbs 28039230Sgibbsstatic void 28139230Sgibbsvxsetlink(sc) 28239230Sgibbs struct vx_softc *sc; 28339230Sgibbs{ 28439230Sgibbs register struct ifnet *ifp = &sc->arpcom.ac_if; 28539230Sgibbs int i, j, k; 28639230Sgibbs char *reason, *warning; 28739230Sgibbs static short prev_flags; 28839230Sgibbs static char prev_conn = -1; 28939230Sgibbs 29039230Sgibbs if (prev_conn == -1) { 29139230Sgibbs prev_conn = sc->vx_connector; 29239230Sgibbs } 29339230Sgibbs 29439230Sgibbs /* 29539230Sgibbs * S.B. 29639230Sgibbs * 29739230Sgibbs * Now behavior was slightly changed: 29839230Sgibbs * 29939230Sgibbs * if any of flags link[0-2] is used and its connector is 30039230Sgibbs * physically present the following connectors are used: 30139230Sgibbs * 30239230Sgibbs * link0 - AUI * highest precedence 30339230Sgibbs * link1 - BNC 30439230Sgibbs * link2 - UTP * lowest precedence 30539230Sgibbs * 30639230Sgibbs * If none of them is specified then 30783131Sken * connector specified in the EEPROM is used 30883131Sken * (if present on card or UTP if not). 30983131Sken */ 31083131Sken 31183131Sken i = sc->vx_connector; /* default in EEPROM */ 31239230Sgibbs reason = "default"; 31339230Sgibbs warning = 0; 31439230Sgibbs 31539230Sgibbs if (ifp->if_flags & IFF_LINK0) { 31639230Sgibbs if (sc->vx_connectors & conn_tab[CONNECTOR_AUI].bit) { 31739230Sgibbs i = CONNECTOR_AUI; 31839230Sgibbs reason = "link0"; 319 } else { 320 warning = "aui not present! (link0)"; 321 } 322 } else if (ifp->if_flags & IFF_LINK1) { 323 if (sc->vx_connectors & conn_tab[CONNECTOR_BNC].bit) { 324 i = CONNECTOR_BNC; 325 reason = "link1"; 326 } else { 327 warning = "bnc not present! (link1)"; 328 } 329 } else if (ifp->if_flags & IFF_LINK2) { 330 if (sc->vx_connectors & conn_tab[CONNECTOR_UTP].bit) { 331 i = CONNECTOR_UTP; 332 reason = "link2"; 333 } else { 334 warning = "utp not present! (link2)"; 335 } 336 } else if ((sc->vx_connectors & conn_tab[(int)sc->vx_connector].bit) == 0) { 337 warning = "strange connector type in EEPROM."; 338 reason = "forced"; 339 i = CONNECTOR_UTP; 340 } 341 342 /* Avoid unnecessary message. */ 343 k = (prev_flags ^ ifp->if_flags) & (IFF_LINK0 | IFF_LINK1 | IFF_LINK2); 344 if ((k != 0) || (prev_conn != i)) { 345 if (warning != 0) { 346 printf("vx%d: warning: %s\n", sc->unit, warning); 347 } 348 printf("vx%d: selected %s. (%s)\n", 349 sc->unit, conn_tab[i].name, reason); 350 } 351 352 /* Set the selected connector. */ 353 GO_WINDOW(3); 354 j = CSR_READ_4(sc, VX_W3_INTERNAL_CFG) & ~INTERNAL_CONNECTOR_MASK; 355 CSR_WRITE_4(sc, VX_W3_INTERNAL_CFG, j | (i <<INTERNAL_CONNECTOR_BITS)); 356 357 /* First, disable all. */ 358 CSR_WRITE_2(sc, VX_COMMAND, STOP_TRANSCEIVER); 359 DELAY(800); 360 GO_WINDOW(4); 361 CSR_WRITE_2(sc, VX_W4_MEDIA_TYPE, 0); 362 363 /* Second, enable the selected one. */ 364 switch(i) { 365 case CONNECTOR_UTP: 366 GO_WINDOW(4); 367 CSR_WRITE_2(sc, VX_W4_MEDIA_TYPE, ENABLE_UTP); 368 break; 369 case CONNECTOR_BNC: 370 CSR_WRITE_2(sc, VX_COMMAND, START_TRANSCEIVER); 371 DELAY(800); 372 break; 373 case CONNECTOR_TX: 374 case CONNECTOR_FX: 375 GO_WINDOW(4); 376 CSR_WRITE_2(sc, VX_W4_MEDIA_TYPE, LINKBEAT_ENABLE); 377 break; 378 default: /* AUI and MII fall here */ 379 break; 380 } 381 GO_WINDOW(1); 382 383 prev_flags = ifp->if_flags; 384 prev_conn = i; 385} 386 387static void 388vxstart(ifp) 389 struct ifnet *ifp; 390{ 391 register struct vx_softc *sc = ifp->if_softc; 392 register struct mbuf *m, *m0; 393 int sh, len, pad; 394 395 /* Don't transmit if interface is busy or not running */ 396 if ((sc->arpcom.ac_if.if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING) 397 return; 398 399startagain: 400 /* Sneak a peek at the next packet */ 401 m0 = ifp->if_snd.ifq_head; 402 if (m0 == 0) { 403 return; 404 } 405 /* We need to use m->m_pkthdr.len, so require the header */ 406 if ((m0->m_flags & M_PKTHDR) == 0) 407 panic("vxstart: no header mbuf"); 408 len = m0->m_pkthdr.len; 409 410 pad = (4 - len) & 3; 411 412 /* 413 * The 3c509 automatically pads short packets to minimum ethernet length, 414 * but we drop packets that are too large. Perhaps we should truncate 415 * them instead? 416 */ 417 if (len + pad > ETHER_MAX_LEN) { 418 /* packet is obviously too large: toss it */ 419 ++ifp->if_oerrors; 420 IF_DEQUEUE(&ifp->if_snd, m0); 421 m_freem(m0); 422 goto readcheck; 423 } 424 VX_BUSY_WAIT; 425 if (CSR_READ_2(sc, VX_W1_FREE_TX) < len + pad + 4) { 426 CSR_WRITE_2(sc, VX_COMMAND, SET_TX_AVAIL_THRESH | ((len + pad + 4) >> 2)); 427 /* not enough room in FIFO */ 428 if (CSR_READ_2(sc, VX_W1_FREE_TX) < len + pad + 4) { /* make sure */ 429 ifp->if_flags |= IFF_OACTIVE; 430 ifp->if_timer = 1; 431 return; 432 } 433 } 434 CSR_WRITE_2(sc, VX_COMMAND, SET_TX_AVAIL_THRESH | (8188 >> 2)); 435 IF_DEQUEUE(&ifp->if_snd, m0); 436 if (m0 == 0) { /* not really needed */ 437 return; 438 } 439 440 VX_BUSY_WAIT; 441 CSR_WRITE_2(sc, VX_COMMAND, SET_TX_START_THRESH | 442 ((len / 4 + sc->tx_start_thresh) >> 2)); 443 444 if (sc->arpcom.ac_if.if_bpf) { 445 bpf_mtap(&sc->arpcom.ac_if, m0); 446 } 447 448 /* 449 * Do the output at splhigh() so that an interrupt from another device 450 * won't cause a FIFO underrun. 451 */ 452 sh = splhigh(); 453 454 CSR_WRITE_4(sc, VX_W1_TX_PIO_WR_1, len | TX_INDICATE); 455 456 for (m = m0; m != 0;) { 457 if (m->m_len > 3) 458 bus_space_write_multi_4(sc->vx_btag, sc->vx_bhandle, 459 VX_W1_TX_PIO_WR_1, (u_int32_t *)mtod(m, caddr_t), m->m_len / 4); 460 if (m->m_len & 3) 461 bus_space_write_multi_1(sc->vx_btag, sc->vx_bhandle, 462 VX_W1_TX_PIO_WR_1, 463 mtod(m, caddr_t) + (m->m_len & ~3) , m->m_len & 3); 464 MFREE(m, m0); 465 m = m0; 466 } 467 while (pad--) 468 CSR_WRITE_1(sc, VX_W1_TX_PIO_WR_1, 0); /* Padding */ 469 470 splx(sh); 471 472 ++ifp->if_opackets; 473 ifp->if_timer = 1; 474 475readcheck: 476 if ((CSR_READ_2(sc, VX_W1_RX_STATUS) & ERR_INCOMPLETE) == 0) { 477 /* We received a complete packet. */ 478 479 if ((CSR_READ_2(sc, VX_STATUS) & S_INTR_LATCH) == 0) { 480 /* 481 * No interrupt, read the packet and continue 482 * Is this supposed to happen? Is my motherboard 483 * completely busted? 484 */ 485 vxread(sc); 486 } else 487 /* Got an interrupt, return so that it gets serviced. */ 488 return; 489 } else { 490 /* Check if we are stuck and reset [see XXX comment] */ 491 if (vxstatus(sc)) { 492 if (ifp->if_flags & IFF_DEBUG) 493 printf("vx%d: adapter reset\n", ifp->if_unit); 494 vxreset(sc); 495 } 496 } 497 498 goto startagain; 499} 500 501/* 502 * XXX: The 3c509 card can get in a mode where both the fifo status bit 503 * FIFOS_RX_OVERRUN and the status bit ERR_INCOMPLETE are set 504 * We detect this situation and we reset the adapter. 505 * It happens at times when there is a lot of broadcast traffic 506 * on the cable (once in a blue moon). 507 */ 508static int 509vxstatus(sc) 510 struct vx_softc *sc; 511{ 512 int fifost; 513 514 /* 515 * Check the FIFO status and act accordingly 516 */ 517 GO_WINDOW(4); 518 fifost = CSR_READ_2(sc, VX_W4_FIFO_DIAG); 519 GO_WINDOW(1); 520 521 if (fifost & FIFOS_RX_UNDERRUN) { 522 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) 523 printf("vx%d: RX underrun\n", sc->unit); 524 vxreset(sc); 525 return 0; 526 } 527 528 if (fifost & FIFOS_RX_STATUS_OVERRUN) { 529 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) 530 printf("vx%d: RX Status overrun\n", sc->unit); 531 return 1; 532 } 533 534 if (fifost & FIFOS_RX_OVERRUN) { 535 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) 536 printf("vx%d: RX overrun\n", sc->unit); 537 return 1; 538 } 539 540 if (fifost & FIFOS_TX_OVERRUN) { 541 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) 542 printf("vx%d: TX overrun\n", sc->unit); 543 vxreset(sc); 544 return 0; 545 } 546 547 return 0; 548} 549 550static void 551vxtxstat(sc) 552 struct vx_softc *sc; 553{ 554 int i; 555 556 /* 557 * We need to read+write TX_STATUS until we get a 0 status 558 * in order to turn off the interrupt flag. 559 */ 560 while ((i = CSR_READ_1(sc, VX_W1_TX_STATUS)) & TXS_COMPLETE) { 561 CSR_WRITE_1(sc, VX_W1_TX_STATUS, 0x0); 562 563 if (i & TXS_JABBER) { 564 ++sc->arpcom.ac_if.if_oerrors; 565 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) 566 printf("vx%d: jabber (%x)\n", sc->unit, i); 567 vxreset(sc); 568 } else if (i & TXS_UNDERRUN) { 569 ++sc->arpcom.ac_if.if_oerrors; 570 if (sc->arpcom.ac_if.if_flags & IFF_DEBUG) 571 printf("vx%d: fifo underrun (%x) @%d\n", 572 sc->unit, i, sc->tx_start_thresh); 573 if (sc->tx_succ_ok < 100) 574 sc->tx_start_thresh = min(ETHER_MAX_LEN, sc->tx_start_thresh + 20); 575 sc->tx_succ_ok = 0; 576 vxreset(sc); 577 } else if (i & TXS_MAX_COLLISION) { 578 ++sc->arpcom.ac_if.if_collisions; 579 CSR_WRITE_2(sc, VX_COMMAND, TX_ENABLE); 580 sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; 581 } else 582 sc->tx_succ_ok = (sc->tx_succ_ok+1) & 127; 583 } 584} 585 586void 587vxintr(voidsc) 588 void *voidsc; 589{ 590 register short status; 591 struct vx_softc *sc = voidsc; 592 struct ifnet *ifp = &sc->arpcom.ac_if; 593 594 for (;;) { 595 CSR_WRITE_2(sc, VX_COMMAND, C_INTR_LATCH); 596 597 status = CSR_READ_2(sc, VX_STATUS); 598 599 if ((status & (S_TX_COMPLETE | S_TX_AVAIL | 600 S_RX_COMPLETE | S_CARD_FAILURE)) == 0) 601 break; 602 603 /* 604 * Acknowledge any interrupts. It's important that we do this 605 * first, since there would otherwise be a race condition. 606 * Due to the i386 interrupt queueing, we may get spurious 607 * interrupts occasionally. 608 */ 609 CSR_WRITE_2(sc, VX_COMMAND, ACK_INTR | status); 610 611 if (status & S_RX_COMPLETE) 612 vxread(sc); 613 if (status & S_TX_AVAIL) { 614 ifp->if_timer = 0; 615 sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; 616 vxstart(&sc->arpcom.ac_if); 617 } 618 if (status & S_CARD_FAILURE) { 619 printf("vx%d: adapter failure (%x)\n", sc->unit, status); 620 ifp->if_timer = 0; 621 vxreset(sc); 622 return; 623 } 624 if (status & S_TX_COMPLETE) { 625 ifp->if_timer = 0; 626 vxtxstat(sc); 627 vxstart(ifp); 628 } 629 } 630 631 /* no more interrupts */ 632 return; 633} 634 635static void 636vxread(sc) 637 struct vx_softc *sc; 638{ 639 struct ifnet *ifp = &sc->arpcom.ac_if; 640 struct mbuf *m; 641 struct ether_header *eh; 642 u_int len; 643 644 len = CSR_READ_2(sc, VX_W1_RX_STATUS); 645 646again: 647 648 if (ifp->if_flags & IFF_DEBUG) { 649 int err = len & ERR_MASK; 650 char *s = NULL; 651 652 if (len & ERR_INCOMPLETE) 653 s = "incomplete packet"; 654 else if (err == ERR_OVERRUN) 655 s = "packet overrun"; 656 else if (err == ERR_RUNT) 657 s = "runt packet"; 658 else if (err == ERR_ALIGNMENT) 659 s = "bad alignment"; 660 else if (err == ERR_CRC) 661 s = "bad crc"; 662 else if (err == ERR_OVERSIZE) 663 s = "oversized packet"; 664 else if (err == ERR_DRIBBLE) 665 s = "dribble bits"; 666 667 if (s) 668 printf("vx%d: %s\n", sc->unit, s); 669 } 670 671 if (len & ERR_INCOMPLETE) 672 return; 673 674 if (len & ERR_RX) { 675 ++ifp->if_ierrors; 676 goto abort; 677 } 678 679 len &= RX_BYTES_MASK; /* Lower 11 bits = RX bytes. */ 680 681 /* Pull packet off interface. */ 682 m = vxget(sc, len); 683 if (m == 0) { 684 ifp->if_ierrors++; 685 goto abort; 686 } 687 688 ++ifp->if_ipackets; 689 690 /* We assume the header fit entirely in one mbuf. */ 691 eh = mtod(m, struct ether_header *); 692 693 /* 694 * XXX: Some cards seem to be in promiscous mode all the time. 695 * we need to make sure we only get our own stuff always. 696 * bleah! 697 */ 698 699 if ((eh->ether_dhost[0] & 1) == 0 /* !mcast and !bcast */ 700 && bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, ETHER_ADDR_LEN) != 0) { 701 m_freem(m); 702 return; 703 } 704 705 m_adj(m, sizeof(struct ether_header)); 706 ether_input(ifp, eh, m); 707 708 /* 709 * In periods of high traffic we can actually receive enough 710 * packets so that the fifo overrun bit will be set at this point, 711 * even though we just read a packet. In this case we 712 * are not going to receive any more interrupts. We check for 713 * this condition and read again until the fifo is not full. 714 * We could simplify this test by not using vxstatus(), but 715 * rechecking the RX_STATUS register directly. This test could 716 * result in unnecessary looping in cases where there is a new 717 * packet but the fifo is not full, but it will not fix the 718 * stuck behavior. 719 * 720 * Even with this improvement, we still get packet overrun errors 721 * which are hurting performance. Maybe when I get some more time 722 * I'll modify vxread() so that it can handle RX_EARLY interrupts. 723 */ 724 if (vxstatus(sc)) { 725 len = CSR_READ_2(sc, VX_W1_RX_STATUS); 726 /* Check if we are stuck and reset [see XXX comment] */ 727 if (len & ERR_INCOMPLETE) { 728 if (ifp->if_flags & IFF_DEBUG) 729 printf("vx%d: adapter reset\n", sc->unit); 730 vxreset(sc); 731 return; 732 } 733 goto again; 734 } 735 736 return; 737 738abort: 739 CSR_WRITE_2(sc, VX_COMMAND, RX_DISCARD_TOP_PACK); 740} 741 742static struct mbuf * 743vxget(sc, totlen) 744 struct vx_softc *sc; 745 u_int totlen; 746{ 747 struct ifnet *ifp = &sc->arpcom.ac_if; 748 struct mbuf *top, **mp, *m; 749 int len; 750 int sh; 751 752 m = sc->mb[sc->next_mb]; 753 sc->mb[sc->next_mb] = 0; 754 if (m == 0) { 755 MGETHDR(m, M_DONTWAIT, MT_DATA); 756 if (m == 0) 757 return 0; 758 } else { 759 /* If the queue is no longer full, refill. */ 760 if (sc->last_mb == sc->next_mb && sc->buffill_pending == 0) { 761 sc->ch = timeout(vxmbuffill, sc, 1); 762 sc->buffill_pending = 1; 763 } 764 /* Convert one of our saved mbuf's. */ 765 sc->next_mb = (sc->next_mb + 1) % MAX_MBS; 766 m->m_data = m->m_pktdat; 767 m->m_flags = M_PKTHDR; 768 bzero(&m->m_pkthdr, sizeof(m->m_pkthdr)); 769 } 770 m->m_pkthdr.rcvif = ifp; 771 m->m_pkthdr.len = totlen; 772 len = MHLEN; 773 top = 0; 774 mp = ⊤ 775 776 /* 777 * We read the packet at splhigh() so that an interrupt from another 778 * device doesn't cause the card's buffer to overflow while we're 779 * reading it. We may still lose packets at other times. 780 */ 781 sh = splhigh(); 782 783 /* 784 * Since we don't set allowLargePackets bit in MacControl register, 785 * we can assume that totlen <= 1500bytes. 786 * The while loop will be performed iff we have a packet with 787 * MLEN < m_len < MINCLSIZE. 788 */ 789 while (totlen > 0) { 790 if (top) { 791 m = sc->mb[sc->next_mb]; 792 sc->mb[sc->next_mb] = 0; 793 if (m == 0) { 794 MGET(m, M_DONTWAIT, MT_DATA); 795 if (m == 0) { 796 splx(sh); 797 m_freem(top); 798 return 0; 799 } 800 } else { 801 sc->next_mb = (sc->next_mb + 1) % MAX_MBS; 802 } 803 len = MLEN; 804 } 805 if (totlen >= MINCLSIZE) { 806 MCLGET(m, M_DONTWAIT); 807 if (m->m_flags & M_EXT) 808 len = MCLBYTES; 809 } 810 len = min(totlen, len); 811 if (len > 3) 812 bus_space_read_multi_4(sc->vx_btag, sc->vx_bhandle, 813 VX_W1_RX_PIO_RD_1, mtod(m, u_int32_t *), len / 4); 814 if (len & 3) { 815 bus_space_read_multi_1(sc->vx_btag, sc->vx_bhandle, 816 VX_W1_RX_PIO_RD_1, mtod(m, u_int8_t *) + (len & ~3), 817 len & 3); 818 } 819 m->m_len = len; 820 totlen -= len; 821 *mp = m; 822 mp = &m->m_next; 823 } 824 825 CSR_WRITE_2(sc, VX_COMMAND, RX_DISCARD_TOP_PACK); 826 827 splx(sh); 828 829 return top; 830} 831 832 833static int 834vxioctl(ifp, cmd, data) 835 register struct ifnet *ifp; 836 u_long cmd; 837 caddr_t data; 838{ 839 struct vx_softc *sc = ifp->if_softc; 840 struct ifreq *ifr = (struct ifreq *) data; 841 int s, error = 0; 842 843 s = splimp(); 844 845 switch (cmd) { 846 case SIOCSIFADDR: 847 case SIOCGIFADDR: 848 ether_ioctl(ifp, cmd, data); 849 break; 850 851 case SIOCSIFFLAGS: 852 if ((ifp->if_flags & IFF_UP) == 0 && 853 (ifp->if_flags & IFF_RUNNING) != 0) { 854 /* 855 * If interface is marked up and it is stopped, then 856 * start it. 857 */ 858 vxstop(sc); 859 ifp->if_flags &= ~IFF_RUNNING; 860 } else if ((ifp->if_flags & IFF_UP) != 0 && 861 (ifp->if_flags & IFF_RUNNING) == 0) { 862 /* 863 * If interface is marked up and it is stopped, then 864 * start it. 865 */ 866 vxinit(sc); 867 } else { 868 /* 869 * deal with flags changes: 870 * IFF_MULTICAST, IFF_PROMISC, 871 * IFF_LINK0, IFF_LINK1, 872 */ 873 vxsetfilter(sc); 874 vxsetlink(sc); 875 } 876 break; 877 878 case SIOCSIFMTU: 879 /* 880 * Set the interface MTU. 881 */ 882 if (ifr->ifr_mtu > ETHERMTU) { 883 error = EINVAL; 884 } else { 885 ifp->if_mtu = ifr->ifr_mtu; 886 } 887 break; 888 889 case SIOCADDMULTI: 890 case SIOCDELMULTI: 891 /* 892 * Multicast list has changed; set the hardware filter 893 * accordingly. 894 */ 895 vxreset(sc); 896 error = 0; 897 break; 898 899 900 default: 901 error = EINVAL; 902 } 903 904 splx(s); 905 906 return (error); 907} 908 909static void 910vxreset(sc) 911 struct vx_softc *sc; 912{ 913 int s; 914 s = splimp(); 915 916 vxstop(sc); 917 vxinit(sc); 918 splx(s); 919} 920 921static void 922vxwatchdog(ifp) 923 struct ifnet *ifp; 924{ 925 struct vx_softc *sc = ifp->if_softc; 926 927 if (ifp->if_flags & IFF_DEBUG) 928 printf("vx%d: device timeout\n", ifp->if_unit); 929 ifp->if_flags &= ~IFF_OACTIVE; 930 vxstart(ifp); 931 vxintr(sc); 932} 933 934void 935vxstop(sc) 936 struct vx_softc *sc; 937{ 938 struct ifnet *ifp = &sc->arpcom.ac_if; 939 940 ifp->if_timer = 0; 941 942 CSR_WRITE_2(sc, VX_COMMAND, RX_DISABLE); 943 CSR_WRITE_2(sc, VX_COMMAND, RX_DISCARD_TOP_PACK); 944 VX_BUSY_WAIT; 945 CSR_WRITE_2(sc, VX_COMMAND, TX_DISABLE); 946 CSR_WRITE_2(sc, VX_COMMAND, STOP_TRANSCEIVER); 947 DELAY(800); 948 CSR_WRITE_2(sc, VX_COMMAND, RX_RESET); 949 VX_BUSY_WAIT; 950 CSR_WRITE_2(sc, VX_COMMAND, TX_RESET); 951 VX_BUSY_WAIT; 952 CSR_WRITE_2(sc, VX_COMMAND, C_INTR_LATCH); 953 CSR_WRITE_2(sc, VX_COMMAND, SET_RD_0_MASK); 954 CSR_WRITE_2(sc, VX_COMMAND, SET_INTR_MASK); 955 CSR_WRITE_2(sc, VX_COMMAND, SET_RX_FILTER); 956 957 vxmbufempty(sc); 958} 959 960int 961vxbusyeeprom(sc) 962 struct vx_softc *sc; 963{ 964 int j, i = 100; 965 966 while (i--) { 967 j = CSR_READ_2(sc, VX_W0_EEPROM_COMMAND); 968 if (j & EEPROM_BUSY) 969 DELAY(100); 970 else 971 break; 972 } 973 if (!i) { 974 printf("vx%d: eeprom failed to come ready\n", sc->unit); 975 return (1); 976 } 977 return (0); 978} 979 980static void 981vxmbuffill(sp) 982 void *sp; 983{ 984 struct vx_softc *sc = (struct vx_softc *) sp; 985 int s, i; 986 987 s = splimp(); 988 i = sc->last_mb; 989 do { 990 if (sc->mb[i] == NULL) 991 MGET(sc->mb[i], M_DONTWAIT, MT_DATA); 992 if (sc->mb[i] == NULL) 993 break; 994 i = (i + 1) % MAX_MBS; 995 } while (i != sc->next_mb); 996 sc->last_mb = i; 997 /* If the queue was not filled, try again. */ 998 if (sc->last_mb != sc->next_mb) { 999 sc->ch = timeout(vxmbuffill, sc, 1); 1000 sc->buffill_pending = 1; 1001 } else { 1002 sc->buffill_pending = 0; 1003 } 1004 splx(s); 1005} 1006 1007static void 1008vxmbufempty(sc) 1009 struct vx_softc *sc; 1010{ 1011 int s, i; 1012 1013 s = splimp(); 1014 for (i = 0; i < MAX_MBS; i++) { 1015 if (sc->mb[i]) { 1016 m_freem(sc->mb[i]); 1017 sc->mb[i] = NULL; 1018 } 1019 } 1020 sc->last_mb = sc->next_mb = 0; 1021 if (sc->buffill_pending != 0) 1022 untimeout(vxmbuffill, sc, sc->ch); 1023 splx(s); 1024} 1025