if_vx.c revision 148284
1139826Simp/*- 253541Sshin * Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca> 353541Sshin * All rights reserved. 453541Sshin * 553541Sshin * Redistribution and use in source and binary forms, with or without 653541Sshin * modification, are permitted provided that the following conditions 753541Sshin * are met: 853541Sshin * 1. Redistributions of source code must retain the above copyright 953541Sshin * notice, this list of conditions and the following disclaimer. 1053541Sshin * 2. Redistributions in binary form must reproduce the above copyright 1153541Sshin * notice, this list of conditions and the following disclaimer in the 1253541Sshin * documentation and/or other materials provided with the distribution. 1353541Sshin * 3. All advertising materials mentioning features or use of this software 1453541Sshin * must display the following acknowledgement: 1553541Sshin * This product includes software developed by Herb Peyerl. 1653541Sshin * 4. The name of Herb Peyerl may not be used to endorse or promote products 1753541Sshin * derived from this software without specific prior written permission. 1853541Sshin * 1953541Sshin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2053541Sshin * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2153541Sshin * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2253541Sshin * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2353541Sshin * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2453541Sshin * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2553541Sshin * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2653541Sshin * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2753541Sshin * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28174510Sobrien * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29174510Sobrien * 30174510Sobrien * 3153541Sshin */ 3253541Sshin 3353541Sshin#include <sys/cdefs.h> 3462587Sitojun__FBSDID("$FreeBSD: head/sys/dev/vx/if_vx.c 148284 2005-07-22 11:27:07Z ru $"); 3553541Sshin 3662587Sitojun/* 3762587Sitojun * Created from if_ep.c driver by Fred Gray (fgray@rice.edu) to support 3862587Sitojun * the 3c590 family. 3962587Sitojun */ 4062587Sitojun 4153541Sshin/* 4278064Sume * Modified from the FreeBSD 1.1.5.1 version by: 4353541Sshin * Andres Vega Garcia 44186119Sqingli * INRIA - Sophia Antipolis, France 45151539Ssuz * avega@sophia.inria.fr 4662587Sitojun */ 4778064Sume 4878064Sume/* 4978064Sume * Promiscuous mode added and interrupt logic slightly changed 5078064Sume * to reduce the number of adapter failures. Transceiver select 5178064Sume * logic changed to use value from EEPROM. Autoconfiguration 5278064Sume * features added. 5378064Sume * Done by: 5478064Sume * Serge Babkin 5562587Sitojun * Chelindbank (Chelyabinsk, Russia) 5662587Sitojun * babkin@hq.icb.chel.su 5762587Sitojun */ 5862587Sitojun 5962587Sitojun 6053541Sshin#include <sys/param.h> 6162587Sitojun#include <sys/systm.h> 62186119Sqingli#include <sys/sockio.h> 6362587Sitojun#include <sys/malloc.h> 6453541Sshin#include <sys/mbuf.h> 6562587Sitojun#include <sys/socket.h> 6662587Sitojun 6762587Sitojun#include <net/if.h> 6862587Sitojun 6962587Sitojun#include <net/ethernet.h> 7062587Sitojun#include <net/if_arp.h> 7162587Sitojun#include <net/if_types.h> 7262587Sitojun 73121161Sume#include <machine/bus.h> 7495023Ssuz 7578064Sume#include <sys/bus.h> 7678064Sume 7778064Sume#include <net/bpf.h> 7853541Sshin 7953541Sshin#include <dev/vx/if_vxreg.h> 8062587Sitojun#include <dev/vx/if_vxvar.h> 81118498Sume 82238273Shrs#define ETHER_MAX_LEN 1518 83151474Ssuz#define ETHER_ADDR_LEN 6 84151474Ssuz#define ETHER_ALIGN 2 85151474Ssuz 86151539Ssuzstatic struct connector_entry { 87197138Shrs int bit; 88222728Shrs char *name; 89245230Sume} conn_tab[VX_CONNECTORS] = { 90282805Shrs 9162587Sitojun#define CONNECTOR_UTP 0 92121161Sume { 93121161Sume 0x08, "utp" 94121161Sume }, 95121161Sume#define CONNECTOR_AUI 1 96121161Sume { 97121161Sume 0x20, "aui" 98121161Sume }, 99121161Sume/* dummy */ 100121161Sume { 101121161Sume 0, "???" 10253541Sshin }, 10362587Sitojun#define CONNECTOR_BNC 3 10462587Sitojun { 10553541Sshin 0x10, "bnc" 10653541Sshin }, 10753541Sshin#define CONNECTOR_TX 4 10853541Sshin { 10953541Sshin 0x02, "tx" 11053541Sshin }, 11162587Sitojun#define CONNECTOR_FX 5 11262587Sitojun { 11353541Sshin 0x04, "fx" 11462587Sitojun }, 11553541Sshin#define CONNECTOR_MII 6 11653541Sshin { 11753541Sshin 0x40, "mii" 11853541Sshin }, 11953541Sshin { 12062587Sitojun 0, "???" 12153541Sshin } 12253541Sshin}; 12353541Sshin 12478064Sume/* int vxattach(struct vx_softc *); */ 12578064Sumestatic void vxtxstat(struct vx_softc *); 12678064Sumestatic int vxstatus(struct vx_softc *); 12778064Sumestatic void vxinit(void *); 12878064Sumestatic int vxioctl(struct ifnet *, u_long, caddr_t); 12978064Sumestatic void vxstart(struct ifnet *); 13081369Ssimokawastatic void vxwatchdog(struct ifnet *); 13178064Sumestatic void vxreset(struct vx_softc *); 132121472Sumestatic void vxread(struct vx_softc *); 133121472Sumestatic struct mbuf *vxget(struct vx_softc *, u_int); 134121472Sumestatic void vxmbuffill(void *); 135121472Sumestatic void vxmbufempty(struct vx_softc *); 136121472Sumestatic void vxsetfilter(struct vx_softc *); 137121472Sumestatic void vxgetlink(struct vx_softc *); 138121472Sumestatic void vxsetlink(struct vx_softc *); 139121472Sume 140121472Sumeint 141121472Sumevxattach(device_t dev) 142121472Sume{ 143121472Sume struct vx_softc *sc = device_get_softc(dev); 144121472Sume struct ifnet *ifp; 145121472Sume int i; 146121472Sume u_char eaddr[6]; 147121472Sume 148121472Sume ifp = sc->ifp = if_alloc(IFT_ETHER); 149121472Sume if (ifp == NULL) { 15053541Sshin device_printf(dev, "can not if_alloc()\n"); 15162587Sitojun return 0; 15253541Sshin } 15353541Sshin 15462587Sitojun callout_handle_init(&sc->ch); 15553541Sshin GO_WINDOW(0); 15662587Sitojun CSR_WRITE_2(sc, VX_COMMAND, GLOBAL_RESET); 15795023Ssuz VX_BUSY_WAIT; 15895023Ssuz 15995023Ssuz vxgetlink(sc); 16062587Sitojun 16162587Sitojun /* 16253541Sshin * Read the station address from the eeprom 16353541Sshin */ 16453541Sshin GO_WINDOW(0); 16553541Sshin for (i = 0; i < 3; i++) { 16678064Sume int x; 16778064Sume 16878064Sume if (vxbusyeeprom(sc)) 16978064Sume return 0; 17078064Sume CSR_WRITE_2(sc, VX_W0_EEPROM_COMMAND, EEPROM_CMD_RD 171121472Sume | (EEPROM_OEM_ADDR0 + i)); 172121472Sume if (vxbusyeeprom(sc)) 173121472Sume return 0; 17478064Sume x = CSR_READ_2(sc, VX_W0_EEPROM_DATA); 17578064Sume eaddr[(i << 1)] = x >> 8; 17678064Sume eaddr[(i << 1) + 1] = x; 17778064Sume } 17878064Sume 17981369Ssimokawa if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 18078064Sume ifp->if_mtu = ETHERMTU; 18178064Sume ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 18278064Sume ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST | 18378064Sume IFF_NEEDSGIANT; 18478064Sume ifp->if_start = vxstart; 18578064Sume ifp->if_ioctl = vxioctl; 18678064Sume ifp->if_init = vxinit; 18778064Sume ifp->if_watchdog = vxwatchdog; 18878064Sume ifp->if_softc = sc; 18978064Sume 19078064Sume ether_ifattach(ifp, eaddr); 19178064Sume 19278064Sume sc->tx_start_thresh = 20; /* probably a good starting point. */ 19378064Sume 19478064Sume vxstop(sc); 19578064Sume 19678064Sume return 1; 19778064Sume} 19853541Sshin 19962587Sitojun/* 20062587Sitojun * The order in here seems important. Otherwise we may not receive 20153541Sshin * interrupts. ?! 20253541Sshin */ 20362587Sitojunstatic void 20462587Sitojunvxinit(void *xsc) 20562587Sitojun{ 20662587Sitojun struct vx_softc *sc = (struct vx_softc *)xsc; 20762587Sitojun struct ifnet *ifp = sc->ifp; 20878064Sume int i; 20978064Sume 21078064Sume VX_BUSY_WAIT; 21162587Sitojun 21253541Sshin GO_WINDOW(2); 21395023Ssuz 21495023Ssuz for (i = 0; i < 6; i++) /* Reload the ether_addr. */ 21562587Sitojun CSR_WRITE_1(sc, VX_W2_ADDR_0 + i, IFP2ENADDR(sc->ifp)[i]); 21653541Sshin 21762587Sitojun CSR_WRITE_2(sc, VX_COMMAND, RX_RESET); 21853541Sshin VX_BUSY_WAIT; 21953541Sshin CSR_WRITE_2(sc, VX_COMMAND, TX_RESET); 22053541Sshin VX_BUSY_WAIT; 22162587Sitojun 22262587Sitojun GO_WINDOW(1); /* Window 1 is operating window */ 22362587Sitojun for (i = 0; i < 31; i++) 22462587Sitojun CSR_READ_1(sc, VX_W1_TX_STATUS); 22562587Sitojun 22678064Sume CSR_WRITE_2(sc, VX_COMMAND, SET_RD_0_MASK | S_CARD_FAILURE | 22778064Sume S_RX_COMPLETE | S_TX_COMPLETE | S_TX_AVAIL); 22878064Sume CSR_WRITE_2(sc, VX_COMMAND, SET_INTR_MASK | S_CARD_FAILURE | 22978064Sume S_RX_COMPLETE | S_TX_COMPLETE | S_TX_AVAIL); 23062587Sitojun 231121807Sume /* 23253541Sshin * Attempt to get rid of any stray interrupts that occured during 23353541Sshin * configuration. On the i386 this isn't possible because one may 23462587Sitojun * already be queued. However, a single stray interrupt is 235295583Smarkj * unimportant. 23662587Sitojun */ 237295583Smarkj CSR_WRITE_2(sc, VX_COMMAND, ACK_INTR | 0xff); 238295583Smarkj 23953541Sshin vxsetfilter(sc); 24053541Sshin vxsetlink(sc); 241295583Smarkj 242151539Ssuz CSR_WRITE_2(sc, VX_COMMAND, RX_ENABLE); 243296063Smarkj CSR_WRITE_2(sc, VX_COMMAND, TX_ENABLE); 24453541Sshin 24553541Sshin vxmbuffill((caddr_t) sc); 246151539Ssuz 247151539Ssuz /* Interface is now `running', with no output active. */ 248151539Ssuz ifp->if_flags |= IFF_RUNNING; 249151539Ssuz ifp->if_flags &= ~IFF_OACTIVE; 250151539Ssuz 251151539Ssuz /* Attempt to start output, if any. */ 252151539Ssuz vxstart(ifp); 253151539Ssuz} 254151539Ssuz 255151539Ssuzstatic void 256151539Ssuzvxsetfilter(struct vx_softc *sc) 257151539Ssuz{ 258151539Ssuz register struct ifnet *ifp = sc->ifp; 259151539Ssuz 26053541Sshin GO_WINDOW(1); /* Window 1 is operating window */ 26162587Sitojun CSR_WRITE_2(sc, VX_COMMAND, SET_RX_FILTER | 26260938Sjake FIL_INDIVIDUAL | FIL_BRDCST | FIL_MULTICAST | 26362587Sitojun ((ifp->if_flags & IFF_PROMISC) ? FIL_PROMISC : 0)); 26462587Sitojun} 265151539Ssuz 26662587Sitojunstatic void 26762587Sitojunvxgetlink(struct vx_softc *sc) 268151539Ssuz{ 26962587Sitojun int n, k; 27062587Sitojun 271151539Ssuz GO_WINDOW(3); 272151539Ssuz sc->vx_connectors = CSR_READ_2(sc, VX_W3_RESET_OPT) & 0x7f; 27362587Sitojun for (n = 0, k = 0; k < VX_CONNECTORS; k++) { 27478064Sume if (sc->vx_connectors & conn_tab[k].bit) { 27553541Sshin if (n > 0) 27660938Sjake printf("/"); 27753541Sshin printf("%s", conn_tab[k].name); 27878064Sume n++; 27953541Sshin } 28053541Sshin } 28162587Sitojun if (sc->vx_connectors == 0) { 28262587Sitojun printf("no connectors!"); 28362587Sitojun return; 284151539Ssuz } 28553541Sshin GO_WINDOW(3); 28653541Sshin sc->vx_connector = 28753541Sshin (CSR_READ_4(sc, VX_W3_INTERNAL_CFG) & INTERNAL_CONNECTOR_MASK) 28853541Sshin >> INTERNAL_CONNECTOR_BITS; 28953541Sshin if (sc->vx_connector & 0x10) { 29053541Sshin sc->vx_connector &= 0x0f; 29153541Sshin printf("[*%s*]", conn_tab[(int)sc->vx_connector].name); 29272093Sasmodai printf(": disable 'auto select' with DOS util!"); 29353541Sshin } else { 29462587Sitojun printf("[*%s*]", conn_tab[(int)sc->vx_connector].name); 29553541Sshin } 29653541Sshin} 29753541Sshin 29853541Sshinstatic void 29962587Sitojunvxsetlink(struct vx_softc *sc) 30053541Sshin{ 30153541Sshin register struct ifnet *ifp = sc->ifp; 30253541Sshin int i, j, k; 30353541Sshin char *reason, *warning; 30462587Sitojun static int prev_flags; 30562587Sitojun static signed char prev_conn = -1; 30653541Sshin 30762587Sitojun if (prev_conn == -1) 30853541Sshin prev_conn = sc->vx_connector; 30962587Sitojun 31062587Sitojun /* 31153541Sshin * S.B. 31253541Sshin * 31360938Sjake * Now behavior was slightly changed: 31462587Sitojun * 31553541Sshin * if any of flags link[0-2] is used and its connector is 31653541Sshin * physically present the following connectors are used: 31760938Sjake * 31853541Sshin * link0 - AUI * highest precedence 319300262Smarkj * link1 - BNC 320300262Smarkj * link2 - UTP * lowest precedence 321300262Smarkj * 322300262Smarkj * If none of them is specified then 32353541Sshin * connector specified in the EEPROM is used 324195699Srwatson * (if present on card or UTP if not). 325195699Srwatson */ 326195699Srwatson i = sc->vx_connector; /* default in EEPROM */ 327195699Srwatson reason = "default"; 328195699Srwatson warning = 0; 329195699Srwatson 330195699Srwatson if (ifp->if_flags & IFF_LINK0) { 331195699Srwatson if (sc->vx_connectors & conn_tab[CONNECTOR_AUI].bit) { 332195699Srwatson i = CONNECTOR_AUI; 333195699Srwatson reason = "link0"; 334195699Srwatson } else { 335195727Srwatson warning = "aui not present! (link0)"; 336195727Srwatson } 337195727Srwatson } else if (ifp->if_flags & IFF_LINK1) { 338195727Srwatson if (sc->vx_connectors & conn_tab[CONNECTOR_BNC].bit) { 339195727Srwatson i = CONNECTOR_BNC; 340195727Srwatson reason = "link1"; 341195727Srwatson } else { 342195727Srwatson warning = "bnc not present! (link1)"; 343195727Srwatson } 344195727Srwatson } else if (ifp->if_flags & IFF_LINK2) { 345195727Srwatson if (sc->vx_connectors & conn_tab[CONNECTOR_UTP].bit) { 346207369Sbz i = CONNECTOR_UTP; 347296063Smarkj reason = "link2"; 348296063Smarkj } else { 349296063Smarkj warning = "utp not present! (link2)"; 350296063Smarkj } 351296063Smarkj } else if ((sc->vx_connectors & conn_tab[(int)sc->vx_connector].bit) == 0) { 352296063Smarkj warning = "strange connector type in EEPROM."; 353296063Smarkj reason = "forced"; 354296063Smarkj i = CONNECTOR_UTP; 355296063Smarkj } 356296063Smarkj /* Avoid unnecessary message. */ 357296063Smarkj k = (prev_flags ^ ifp->if_flags) & (IFF_LINK0 | IFF_LINK1 | IFF_LINK2); 358296063Smarkj if ((k != 0) || (prev_conn != i)) { 359296063Smarkj if (warning != 0) { 360207369Sbz printf("vx%d: warning: %s\n", sc->unit, warning); 361207369Sbz } 36262587Sitojun printf("vx%d: selected %s. (%s)\n", 363195699Srwatson sc->unit, conn_tab[i].name, reason); 364195699Srwatson } 365195699Srwatson /* Set the selected connector. */ 366195699Srwatson GO_WINDOW(3); 367195699Srwatson j = CSR_READ_4(sc, VX_W3_INTERNAL_CFG) & ~INTERNAL_CONNECTOR_MASK; 368195727Srwatson CSR_WRITE_4(sc, VX_W3_INTERNAL_CFG, j | (i << INTERNAL_CONNECTOR_BITS)); 369195727Srwatson 370195727Srwatson /* First, disable all. */ 371195727Srwatson CSR_WRITE_2(sc, VX_COMMAND, STOP_TRANSCEIVER); 372195727Srwatson DELAY(800); 373195699Srwatson GO_WINDOW(4); 37453541Sshin CSR_WRITE_2(sc, VX_W4_MEDIA_TYPE, 0); 375279531Shrs 37653541Sshin /* Second, enable the selected one. */ 37762587Sitojun switch (i) { 37862587Sitojun case CONNECTOR_UTP: 37962587Sitojun GO_WINDOW(4); 38095023Ssuz CSR_WRITE_2(sc, VX_W4_MEDIA_TYPE, ENABLE_UTP); 38162587Sitojun break; 38262587Sitojun case CONNECTOR_BNC: 383279531Shrs CSR_WRITE_2(sc, VX_COMMAND, START_TRANSCEIVER); 384279531Shrs DELAY(800); 385279531Shrs break; 386279531Shrs case CONNECTOR_TX: 387279531Shrs case CONNECTOR_FX: 388279531Shrs GO_WINDOW(4); 389279531Shrs CSR_WRITE_2(sc, VX_W4_MEDIA_TYPE, LINKBEAT_ENABLE); 390279531Shrs break; 391279531Shrs default: /* AUI and MII fall here */ 392279531Shrs break; 39362587Sitojun } 39462587Sitojun GO_WINDOW(1); 39562587Sitojun 39662587Sitojun prev_flags = ifp->if_flags; 39753541Sshin prev_conn = i; 39853541Sshin} 39962587Sitojun 40062587Sitojunstatic void 40162587Sitojunvxstart(struct ifnet *ifp) 40262587Sitojun{ 40362587Sitojun register struct vx_softc *sc = ifp->if_softc; 40462587Sitojun register struct mbuf *m; 405279531Shrs int sh, len, pad; 40662587Sitojun 40762587Sitojun /* Don't transmit if interface is busy or not running */ 40862587Sitojun if ((sc->ifp->if_flags & 40953541Sshin (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) 41053541Sshin return; 41153541Sshin 412241916Sdelphijstartagain: 413193731Szec /* Sneak a peek at the next packet */ 414241916Sdelphij m = ifp->if_snd.ifq_head; 415193731Szec if (m == NULL) { 416241916Sdelphij return; 417241916Sdelphij } 418287857Smelifaro /* We need to use m->m_pkthdr.len, so require the header */ 419241916Sdelphij M_ASSERTPKTHDR(m); 420241916Sdelphij len = m->m_pkthdr.len; 421241916Sdelphij 422287857Smelifaro pad = (4 - len) & 3; 423287857Smelifaro 424241916Sdelphij /* 425288062Smelifaro * The 3c509 automatically pads short packets to minimum ethernet 426241916Sdelphij * length, but we drop packets that are too large. Perhaps we should 427241916Sdelphij * truncate them instead? 428292978Smelifaro */ 429292978Smelifaro if (len + pad > ETHER_MAX_LEN) { 430287861Smelifaro /* packet is obviously too large: toss it */ 431301217Sgnn ++ifp->if_oerrors; 432241916Sdelphij IF_DEQUEUE(&ifp->if_snd, m); 433287826Smelifaro m_freem(m); 434241916Sdelphij goto readcheck; 435276844Smelifaro } 436276844Smelifaro VX_BUSY_WAIT; 437276844Smelifaro if (CSR_READ_2(sc, VX_W1_FREE_TX) < len + pad + 4) { 438276844Smelifaro CSR_WRITE_2(sc, VX_COMMAND, 439260882Smelifaro SET_TX_AVAIL_THRESH | ((len + pad + 4) >> 2)); 440287789Smelifaro /* not enough room in FIFO - make sure */ 441287861Smelifaro if (CSR_READ_2(sc, VX_W1_FREE_TX) < len + pad + 4) { 442290867Smelifaro ifp->if_flags |= IFF_OACTIVE; 44353541Sshin ifp->if_timer = 1; 44453541Sshin return; 445241916Sdelphij } 446241916Sdelphij } 447241916Sdelphij CSR_WRITE_2(sc, VX_COMMAND, SET_TX_AVAIL_THRESH | (8188 >> 2)); 448241916Sdelphij IF_DEQUEUE(&ifp->if_snd, m); 449241916Sdelphij if (m == NULL) /* not really needed */ 450287484Smelifaro return; 451241916Sdelphij 452275593Smarkj VX_BUSY_WAIT; 453241916Sdelphij CSR_WRITE_2(sc, VX_COMMAND, SET_TX_START_THRESH | 454241916Sdelphij ((len / 4 + sc->tx_start_thresh) >> 2)); 45553541Sshin 45653541Sshin BPF_MTAP(sc->ifp, m); 457241916Sdelphij 458241916Sdelphij /* 459241916Sdelphij * Do the output at splhigh() so that an interrupt from another device 460241916Sdelphij * won't cause a FIFO underrun. 461296063Smarkj */ 462296063Smarkj sh = splhigh(); 463296991Smarkj 464296063Smarkj CSR_WRITE_4(sc, VX_W1_TX_PIO_WR_1, len | TX_INDICATE); 465296063Smarkj 466241916Sdelphij while (m) { 467241916Sdelphij if (m->m_len > 3) 468241916Sdelphij bus_space_write_multi_4(sc->bst, sc->bsh, 469241916Sdelphij VX_W1_TX_PIO_WR_1, (u_int32_t *)mtod(m, caddr_t), 470241916Sdelphij m->m_len / 4); 471296063Smarkj if (m->m_len & 3) 472241916Sdelphij bus_space_write_multi_1(sc->bst, sc->bsh, 473241916Sdelphij VX_W1_TX_PIO_WR_1, 474241916Sdelphij mtod(m, caddr_t) + (m->m_len & ~3), m->m_len & 3); 475241916Sdelphij m = m_free(m); 47653541Sshin } 47753541Sshin while (pad--) 47853541Sshin CSR_WRITE_1(sc, VX_W1_TX_PIO_WR_1, 0); /* Padding */ 47953541Sshin 480 splx(sh); 481 482 ++ifp->if_opackets; 483 ifp->if_timer = 1; 484 485readcheck: 486 if ((CSR_READ_2(sc, VX_W1_RX_STATUS) & ERR_INCOMPLETE) == 0) { 487 /* We received a complete packet. */ 488 489 if ((CSR_READ_2(sc, VX_STATUS) & S_INTR_LATCH) == 0) { 490 /* 491 * No interrupt, read the packet and continue 492 * Is this supposed to happen? Is my motherboard 493 * completely busted? 494 */ 495 vxread(sc); 496 } else 497 /* 498 * Got an interrupt, return so that it gets 499 * serviced. 500 */ 501 return; 502 } else { 503 /* Check if we are stuck and reset [see XXX comment] */ 504 if (vxstatus(sc)) { 505 if (ifp->if_flags & IFF_DEBUG) 506 if_printf(ifp, "adapter reset\n"); 507 vxreset(sc); 508 } 509 } 510 511 goto startagain; 512} 513 514/* 515 * XXX: The 3c509 card can get in a mode where both the fifo status bit 516 * FIFOS_RX_OVERRUN and the status bit ERR_INCOMPLETE are set 517 * We detect this situation and we reset the adapter. 518 * It happens at times when there is a lot of broadcast traffic 519 * on the cable (once in a blue moon). 520 */ 521static int 522vxstatus(struct vx_softc *sc) 523{ 524 int fifost; 525 526 /* 527 * Check the FIFO status and act accordingly 528 */ 529 GO_WINDOW(4); 530 fifost = CSR_READ_2(sc, VX_W4_FIFO_DIAG); 531 GO_WINDOW(1); 532 533 if (fifost & FIFOS_RX_UNDERRUN) { 534 if (sc->ifp->if_flags & IFF_DEBUG) 535 printf("vx%d: RX underrun\n", sc->unit); 536 vxreset(sc); 537 return 0; 538 } 539 if (fifost & FIFOS_RX_STATUS_OVERRUN) { 540 if (sc->ifp->if_flags & IFF_DEBUG) 541 printf("vx%d: RX Status overrun\n", sc->unit); 542 return 1; 543 } 544 if (fifost & FIFOS_RX_OVERRUN) { 545 if (sc->ifp->if_flags & IFF_DEBUG) 546 printf("vx%d: RX overrun\n", sc->unit); 547 return 1; 548 } 549 if (fifost & FIFOS_TX_OVERRUN) { 550 if (sc->ifp->if_flags & IFF_DEBUG) 551 printf("vx%d: TX overrun\n", sc->unit); 552 vxreset(sc); 553 return 0; 554 } 555 return 0; 556} 557 558static void 559vxtxstat(struct vx_softc *sc) 560{ 561 int i; 562 563 /* 564 * We need to read+write TX_STATUS until we get a 0 status 565 * in order to turn off the interrupt flag. 566 */ 567 while ((i = CSR_READ_1(sc, VX_W1_TX_STATUS)) & TXS_COMPLETE) { 568 CSR_WRITE_1(sc, VX_W1_TX_STATUS, 0x0); 569 570 if (i & TXS_JABBER) { 571 ++sc->ifp->if_oerrors; 572 if (sc->ifp->if_flags & IFF_DEBUG) 573 printf("vx%d: jabber (%x)\n", sc->unit, i); 574 vxreset(sc); 575 } else if (i & TXS_UNDERRUN) { 576 ++sc->ifp->if_oerrors; 577 if (sc->ifp->if_flags & IFF_DEBUG) 578 printf("vx%d: fifo underrun (%x) @%d\n", 579 sc->unit, i, sc->tx_start_thresh); 580 if (sc->tx_succ_ok < 100) 581 sc->tx_start_thresh = 582 min(ETHER_MAX_LEN,sc->tx_start_thresh + 20); 583 sc->tx_succ_ok = 0; 584 vxreset(sc); 585 } else if (i & TXS_MAX_COLLISION) { 586 ++sc->ifp->if_collisions; 587 CSR_WRITE_2(sc, VX_COMMAND, TX_ENABLE); 588 sc->ifp->if_flags &= ~IFF_OACTIVE; 589 } else 590 sc->tx_succ_ok = (sc->tx_succ_ok + 1) & 127; 591 } 592} 593 594void 595vxintr(void *voidsc) 596{ 597 register short status; 598 struct vx_softc *sc = voidsc; 599 struct ifnet *ifp = sc->ifp; 600 601 for (;;) { 602 CSR_WRITE_2(sc, VX_COMMAND, C_INTR_LATCH); 603 604 status = CSR_READ_2(sc, VX_STATUS); 605 606 if ((status & (S_TX_COMPLETE | S_TX_AVAIL | 607 S_RX_COMPLETE | S_CARD_FAILURE)) == 0) 608 break; 609 610 /* 611 * Acknowledge any interrupts. It's important that we do this 612 * first, since there would otherwise be a race condition. 613 * Due to the i386 interrupt queueing, we may get spurious 614 * interrupts occasionally. 615 */ 616 CSR_WRITE_2(sc, VX_COMMAND, ACK_INTR | status); 617 618 if (status & S_RX_COMPLETE) 619 vxread(sc); 620 if (status & S_TX_AVAIL) { 621 ifp->if_timer = 0; 622 sc->ifp->if_flags &= ~IFF_OACTIVE; 623 vxstart(sc->ifp); 624 } 625 if (status & S_CARD_FAILURE) { 626 printf("vx%d: adapter failure (%x)\n", 627 sc->unit, status); 628 ifp->if_timer = 0; 629 vxreset(sc); 630 return; 631 } 632 if (status & S_TX_COMPLETE) { 633 ifp->if_timer = 0; 634 vxtxstat(sc); 635 vxstart(ifp); 636 } 637 } 638 639 /* no more interrupts */ 640 return; 641} 642 643static void 644vxread(struct vx_softc *sc) 645{ 646 struct ifnet *ifp = sc->ifp; 647 struct mbuf *m; 648 struct ether_header *eh; 649 u_int len; 650 651 len = CSR_READ_2(sc, VX_W1_RX_STATUS); 652 653again: 654 655 if (ifp->if_flags & IFF_DEBUG) { 656 int err = len & ERR_MASK; 657 char *s = NULL; 658 659 if (len & ERR_INCOMPLETE) 660 s = "incomplete packet"; 661 else if (err == ERR_OVERRUN) 662 s = "packet overrun"; 663 else if (err == ERR_RUNT) 664 s = "runt packet"; 665 else if (err == ERR_ALIGNMENT) 666 s = "bad alignment"; 667 else if (err == ERR_CRC) 668 s = "bad crc"; 669 else if (err == ERR_OVERSIZE) 670 s = "oversized packet"; 671 else if (err == ERR_DRIBBLE) 672 s = "dribble bits"; 673 674 if (s) 675 printf("vx%d: %s\n", sc->unit, s); 676 } 677 if (len & ERR_INCOMPLETE) 678 return; 679 680 if (len & ERR_RX) { 681 ++ifp->if_ierrors; 682 goto abort; 683 } 684 len &= RX_BYTES_MASK; /* Lower 11 bits = RX bytes. */ 685 686 /* Pull packet off interface. */ 687 m = vxget(sc, len); 688 if (m == 0) { 689 ifp->if_ierrors++; 690 goto abort; 691 } 692 ++ifp->if_ipackets; 693 694 { 695 struct mbuf *m0; 696 697 m0 = m_devget(mtod(m, char *), m->m_pkthdr.len, ETHER_ALIGN, ifp, NULL); 698 if (m0 == NULL) { 699 ifp->if_ierrors++; 700 goto abort; 701 } 702 m_freem(m); 703 m = m0; 704 } 705 706 /* We assume the header fit entirely in one mbuf. */ 707 eh = mtod(m, struct ether_header *); 708 709 /* 710 * XXX: Some cards seem to be in promiscous mode all the time. 711 * we need to make sure we only get our own stuff always. 712 * bleah! 713 */ 714 715 if (!(ifp->if_flags & IFF_PROMISC) 716 && (eh->ether_dhost[0] & 1) == 0 /* !mcast and !bcast */ 717 && bcmp(eh->ether_dhost, IFP2ENADDR(sc->ifp), ETHER_ADDR_LEN)!=0) { 718 m_freem(m); 719 return; 720 } 721 (*ifp->if_input) (ifp, m); 722 723 /* 724 * In periods of high traffic we can actually receive enough 725 * packets so that the fifo overrun bit will be set at this point, 726 * even though we just read a packet. In this case we 727 * are not going to receive any more interrupts. We check for 728 * this condition and read again until the fifo is not full. 729 * We could simplify this test by not using vxstatus(), but 730 * rechecking the RX_STATUS register directly. This test could 731 * result in unnecessary looping in cases where there is a new 732 * packet but the fifo is not full, but it will not fix the 733 * stuck behavior. 734 * 735 * Even with this improvement, we still get packet overrun errors 736 * which are hurting performance. Maybe when I get some more time 737 * I'll modify vxread() so that it can handle RX_EARLY interrupts. 738 */ 739 if (vxstatus(sc)) { 740 len = CSR_READ_2(sc, VX_W1_RX_STATUS); 741 /* Check if we are stuck and reset [see XXX comment] */ 742 if (len & ERR_INCOMPLETE) { 743 if (ifp->if_flags & IFF_DEBUG) 744 printf("vx%d: adapter reset\n", sc->unit); 745 vxreset(sc); 746 return; 747 } 748 goto again; 749 } 750 return; 751 752abort: 753 CSR_WRITE_2(sc, VX_COMMAND, RX_DISCARD_TOP_PACK); 754} 755 756static struct mbuf * 757vxget(struct vx_softc *sc, u_int totlen) 758{ 759 struct ifnet *ifp = sc->ifp; 760 struct mbuf *top, **mp, *m; 761 int len; 762 int sh; 763 764 m = sc->mb[sc->next_mb]; 765 sc->mb[sc->next_mb] = 0; 766 if (m == 0) { 767 MGETHDR(m, M_DONTWAIT, MT_DATA); 768 if (m == 0) 769 return 0; 770 } else { 771 /* If the queue is no longer full, refill. */ 772 if (sc->last_mb == sc->next_mb && sc->buffill_pending == 0) { 773 sc->ch = timeout(vxmbuffill, sc, 1); 774 sc->buffill_pending = 1; 775 } 776 /* Convert one of our saved mbuf's. */ 777 sc->next_mb = (sc->next_mb + 1) % MAX_MBS; 778 m->m_data = m->m_pktdat; 779 m->m_flags = M_PKTHDR; 780 bzero(&m->m_pkthdr, sizeof(m->m_pkthdr)); 781 } 782 m->m_pkthdr.rcvif = ifp; 783 m->m_pkthdr.len = totlen; 784 len = MHLEN; 785 top = 0; 786 mp = ⊤ 787 788 /* 789 * We read the packet at splhigh() so that an interrupt from another 790 * device doesn't cause the card's buffer to overflow while we're 791 * reading it. We may still lose packets at other times. 792 */ 793 sh = splhigh(); 794 795 /* 796 * Since we don't set allowLargePackets bit in MacControl register, 797 * we can assume that totlen <= 1500bytes. 798 * The while loop will be performed iff we have a packet with 799 * MLEN < m_len < MINCLSIZE. 800 */ 801 while (totlen > 0) { 802 if (top) { 803 m = sc->mb[sc->next_mb]; 804 sc->mb[sc->next_mb] = 0; 805 if (m == 0) { 806 MGET(m, M_DONTWAIT, MT_DATA); 807 if (m == 0) { 808 splx(sh); 809 m_freem(top); 810 return 0; 811 } 812 } else { 813 sc->next_mb = (sc->next_mb + 1) % MAX_MBS; 814 } 815 len = MLEN; 816 } 817 if (totlen >= MINCLSIZE) { 818 MCLGET(m, M_DONTWAIT); 819 if (m->m_flags & M_EXT) 820 len = MCLBYTES; 821 } 822 len = min(totlen, len); 823 if (len > 3) 824 bus_space_read_multi_4(sc->bst, sc->bsh, 825 VX_W1_RX_PIO_RD_1, mtod(m, u_int32_t *), len / 4); 826 if (len & 3) { 827 bus_space_read_multi_1(sc->bst, sc->bsh, 828 VX_W1_RX_PIO_RD_1, mtod(m, u_int8_t *) + (len & ~3), 829 len & 3); 830 } 831 m->m_len = len; 832 totlen -= len; 833 *mp = m; 834 mp = &m->m_next; 835 } 836 837 CSR_WRITE_2(sc, VX_COMMAND, RX_DISCARD_TOP_PACK); 838 839 splx(sh); 840 841 return top; 842} 843 844 845static int 846vxioctl(register struct ifnet *ifp, u_long cmd, caddr_t data) 847{ 848 struct vx_softc *sc = ifp->if_softc; 849 struct ifreq *ifr = (struct ifreq *) data; 850 int s, error = 0; 851 852 s = splimp(); 853 854 switch (cmd) { 855 case SIOCSIFFLAGS: 856 if ((ifp->if_flags & IFF_UP) == 0 && 857 (ifp->if_flags & IFF_RUNNING) != 0) { 858 /* 859 * If interface is marked up and it is stopped, then 860 * start it. 861 */ 862 vxstop(sc); 863 ifp->if_flags &= ~IFF_RUNNING; 864 } else if ((ifp->if_flags & IFF_UP) != 0 && 865 (ifp->if_flags & IFF_RUNNING) == 0) { 866 /* 867 * If interface is marked up and it is stopped, then 868 * start it. 869 */ 870 vxinit(sc); 871 } else { 872 /* 873 * deal with flags changes: 874 * IFF_MULTICAST, IFF_PROMISC, 875 * IFF_LINK0, IFF_LINK1, 876 */ 877 vxsetfilter(sc); 878 vxsetlink(sc); 879 } 880 break; 881 882 case SIOCSIFMTU: 883 /* 884 * Set the interface MTU. 885 */ 886 if (ifr->ifr_mtu > ETHERMTU) { 887 error = EINVAL; 888 } else { 889 ifp->if_mtu = ifr->ifr_mtu; 890 } 891 break; 892 893 case SIOCADDMULTI: 894 case SIOCDELMULTI: 895 /* 896 * Multicast list has changed; set the hardware filter 897 * accordingly. 898 */ 899 vxreset(sc); 900 error = 0; 901 break; 902 903 904 default: 905 error = ether_ioctl(ifp, cmd, data); 906 break; 907 } 908 909 splx(s); 910 911 return (error); 912} 913 914static void 915vxreset(struct vx_softc *sc) 916{ 917 int s; 918 919 s = splimp(); 920 921 vxstop(sc); 922 vxinit(sc); 923 splx(s); 924} 925 926static void 927vxwatchdog(struct ifnet *ifp) 928{ 929 struct vx_softc *sc = ifp->if_softc; 930 931 if (ifp->if_flags & IFF_DEBUG) 932 if_printf(ifp, "device timeout\n"); 933 ifp->if_flags &= ~IFF_OACTIVE; 934 vxstart(ifp); 935 vxintr(sc); 936} 937 938void 939vxstop(struct vx_softc *sc) 940{ 941 struct ifnet *ifp = sc->ifp; 942 943 ifp->if_timer = 0; 944 945 CSR_WRITE_2(sc, VX_COMMAND, RX_DISABLE); 946 CSR_WRITE_2(sc, VX_COMMAND, RX_DISCARD_TOP_PACK); 947 VX_BUSY_WAIT; 948 CSR_WRITE_2(sc, VX_COMMAND, TX_DISABLE); 949 CSR_WRITE_2(sc, VX_COMMAND, STOP_TRANSCEIVER); 950 DELAY(800); 951 CSR_WRITE_2(sc, VX_COMMAND, RX_RESET); 952 VX_BUSY_WAIT; 953 CSR_WRITE_2(sc, VX_COMMAND, TX_RESET); 954 VX_BUSY_WAIT; 955 CSR_WRITE_2(sc, VX_COMMAND, C_INTR_LATCH); 956 CSR_WRITE_2(sc, VX_COMMAND, SET_RD_0_MASK); 957 CSR_WRITE_2(sc, VX_COMMAND, SET_INTR_MASK); 958 CSR_WRITE_2(sc, VX_COMMAND, SET_RX_FILTER); 959 960 vxmbufempty(sc); 961} 962 963int 964vxbusyeeprom(struct vx_softc *sc) 965{ 966 int j, i = 100; 967 968 while (i--) { 969 j = CSR_READ_2(sc, VX_W0_EEPROM_COMMAND); 970 if (j & EEPROM_BUSY) 971 DELAY(100); 972 else 973 break; 974 } 975 if (!i) { 976 printf("vx%d: eeprom failed to come ready\n", sc->unit); 977 return (1); 978 } 979 return (0); 980} 981 982static void 983vxmbuffill(void *sp) 984{ 985 struct vx_softc *sc = (struct vx_softc *)sp; 986 int s, i; 987 988 s = splimp(); 989 i = sc->last_mb; 990 do { 991 if (sc->mb[i] == NULL) 992 MGET(sc->mb[i], M_DONTWAIT, MT_DATA); 993 if (sc->mb[i] == NULL) 994 break; 995 i = (i + 1) % MAX_MBS; 996 } while (i != sc->next_mb); 997 sc->last_mb = i; 998 /* If the queue was not filled, try again. */ 999 if (sc->last_mb != sc->next_mb) { 1000 sc->ch = timeout(vxmbuffill, sc, 1); 1001 sc->buffill_pending = 1; 1002 } else { 1003 sc->buffill_pending = 0; 1004 } 1005 splx(s); 1006} 1007 1008static void 1009vxmbufempty(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