diff options
Diffstat (limited to 'sys/dev/pci/if_wx.c')
-rw-r--r-- | sys/dev/pci/if_wx.c | 216 |
1 files changed, 141 insertions, 75 deletions
diff --git a/sys/dev/pci/if_wx.c b/sys/dev/pci/if_wx.c index 9aced5fd9e0..cb7338ec132 100644 --- a/sys/dev/pci/if_wx.c +++ b/sys/dev/pci/if_wx.c @@ -1,5 +1,4 @@ -/* $OpenBSD: if_wx.c,v 1.6 2000/08/11 15:11:39 deraadt Exp $ */ - +/* $OpenBSD: if_wx.c,v 1.7 2000/12/06 01:02:14 mjacob Exp $ */ /* * Copyright (c) 1999, Traakan Software * All rights reserved. @@ -26,7 +25,6 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/pci/if_wx.c,v 1.5 2000/01/25 06:09:53 mjacob Exp $ */ /* @@ -182,7 +180,12 @@ wx_match(parent, match, aux) if (PCI_VENDOR(pa->pa_id) != WX_VENDOR_INTEL) { return (0); } - if (PCI_PRODUCT(pa->pa_id) != WX_PRODUCT_82452) { + switch (PCI_PRODUCT(pa->pa_id)) { + case WX_PRODUCT_82452: + case WX_PRODUCT_LIVENGOOD: + case WX_PRODUCT_82452_SC: + break; + default: return (0); } return (1); @@ -212,6 +215,7 @@ wx_attach(parent, self, aux) printf(": can't map registers\n"); return; } + printf(": Intel GigaBit Ethernet\n"); /* * Allocate our interrupt. @@ -229,14 +233,15 @@ wx_attach(parent, self, aux) sc->w.ih = pci_intr_establish(pc, ih, IPL_NET, wx_intr, sc); #endif if (sc->w.ih == NULL) { - printf("couldn't establish interrupt"); + printf("%s: couldn't establish interrupt", sc->wx_name); if (intrstr != NULL) printf(" at %s", intrstr); printf("\n"); return; } - sc->revision = - pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_CLASS_REG) & 0xff; + printf("%s: interrupting at %s\n", sc->wx_name, intrstr); + sc->wx_idnrev = (PCI_PRODUCT(pa->pa_id) << 16) | + (pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_CLASS_REG) & 0xff); data = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG); data &= ~(PCI_CACHELINE_MASK << PCI_CACHELINE_SHIFT); @@ -247,7 +252,8 @@ wx_attach(parent, self, aux) return; } - printf(": %s, address %s\n", intrstr, ether_sprintf(sc->wx_enaddr)); + printf("%s: Ethernet address %s\n", + sc->wx_name, ether_sprintf(sc->wx_enaddr)); ifp = &sc->wx_if; bcopy(sc->wx_name, ifp->if_xname, IFNAMSIZ); @@ -534,12 +540,22 @@ static wx_softc_t *wxlist; static int wx_probe(device_t dev) { - if ((pci_get_vendor(dev) == WX_VENDOR_INTEL) && - (pci_get_device(dev) == WX_PRODUCT_82452)) { - device_set_desc(dev, "Intel GigaBit Ethernet"); - return 0; + if (pci_get_vendor(dev) != WX_VENDOR_INTEL) { + return (ENXIO); + } + switch (pci_get_device(dev)) { + case WX_PRODUCT_82452: + device_set_desc(dev, "Intel GigaBit Ethernet (WISEMAN)"); + break; + case WX_PRODUCT_LIVENGOOD: + device_set_desc(dev, "Intel GigaBit Ethernet (LIVENGOOD)"); + case WX_PRODUCT_82452_SC: + device_set_desc(dev, "Intel GigaBit Ethernet (LIVENGOOD_SC)"); + break; + default: + return (ENXIO); } - return (ENXIO); + return (0); } static int @@ -548,7 +564,6 @@ wx_attach(device_t dev) int error = 0; wx_softc_t *tmp, *sc = device_get_softc(dev); struct ifnet *ifp; - int s; u_long val; int rid; @@ -581,7 +596,16 @@ wx_attach(device_t dev) } } - s = splimp(); +#ifdef SMPNG + mtx_init(&sc->wx_mtx, device_get_nameunit(dev), MTX_DEF); +#endif + + WX_LOCK(sc); + /* + * get revision && id... + */ + sc->wx_idnrev = (pci_get_device(dev) << 16) | (pci_get_revid(dev)); + /* * Enable bus mastering, make sure that the cache line size is right. */ @@ -594,10 +618,6 @@ wx_attach(device_t dev) pci_write_config(dev, PCIR_CACHELNSZ, 0x10, 1); } - /* - * get revision - */ - sc->revision = pci_read_config(dev, PCIR_CLASS, 1); /* * Map control/status registers. @@ -640,6 +660,7 @@ wx_attach(device_t dev) sc->w.arpcom.ac_enaddr[4], sc->w.arpcom.ac_enaddr[5]); (void) snprintf(sc->wx_name, sizeof (sc->wx_name) - 1, "wx%d", device_get_unit(dev)); + ifp = &sc->w.arpcom.ac_if; ifp->if_unit = device_get_unit(dev); ifp->if_name = "wx"; @@ -652,10 +673,8 @@ wx_attach(device_t dev) ifp->if_ioctl = wx_ioctl; ifp->if_start = wx_start; ifp->if_watchdog = wx_txwatchdog; - if_attach(ifp); ifp->if_snd.ifq_maxlen = WX_MAX_TDESC - 1; - ether_ifattach(ifp); - bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); + ether_ifattach(ifp, ETHER_BPF_SUPPORTED); tmp = wxlist; if (tmp) { while (tmp->wx_next) @@ -665,7 +684,7 @@ wx_attach(device_t dev) wxlist = sc; } out: - splx(s); + WX_UNLOCK(sc); return (error); } @@ -673,13 +692,14 @@ static int wx_detach(device_t dev) { wx_softc_t *sc = device_get_softc(dev); - int s = splimp(); - if_detach(&sc->w.arpcom.ac_if); + + WX_LOCK(sc); + ether_ifdetach(&sc->w.arpcom.ac_if, ETHER_BPF_SUPPORTED); wx_stop(sc); bus_teardown_intr(dev, sc->w.irq, sc->w.ih); bus_release_resource(dev, SYS_RES_IRQ, 0, sc->w.irq); bus_release_resource(dev, SYS_RES_MEMORY, WX_MMBA, sc->w.mem); - splx(s); + WX_UNLOCK(sc); return (0); } @@ -721,6 +741,8 @@ wx_dring_setup(sc) return (-1); } if (((u_long)sc->rdescriptors) & 0xfff) { + contigfree(sc->rdescriptors, len, M_DEVBUF); + sc->rdescriptors = NULL; printf("%s: rcv descriptors not 4KB aligned\n", sc->wx_name); return (-1); } @@ -730,10 +752,16 @@ wx_dring_setup(sc) sc->tdescriptors = (wxtd_t *) contigmalloc(len, M_DEVBUF, M_NOWAIT, 0, ~0, 4096, 0); if (sc->tdescriptors == NULL) { + contigfree(sc->rdescriptors, + sizeof (wxrd_t) * WX_MAX_RDESC, M_DEVBUF); + sc->rdescriptors = NULL; printf("%s: could not allocate xmt descriptors\n", sc->wx_name); return (-1); } if (((u_long)sc->tdescriptors) & 0xfff) { + contigfree(sc->rdescriptors, + sizeof (wxrd_t) * WX_MAX_RDESC, M_DEVBUF); + sc->rdescriptors = NULL; printf("%s: xmt descriptors not 4KB aligned\n", sc->wx_name); return (-1); } @@ -746,11 +774,13 @@ wx_dring_teardown(sc) wx_softc_t *sc; { if (sc->rdescriptors) { - WXFREE(sc->rdescriptors); + contigfree(sc->rdescriptors, + sizeof (wxrd_t) * WX_MAX_RDESC, M_DEVBUF); sc->rdescriptors = NULL; } if (sc->tdescriptors) { - WXFREE(sc->tdescriptors); + contigfree(sc->tdescriptors, + sizeof (wxtd_t) * WX_MAX_TDESC, M_DEVBUF); sc->tdescriptors = NULL; } } @@ -787,9 +817,9 @@ wx_attach_common(sc) /* * First, check for revision support. */ - if (sc->revision < 2) { - printf("%s: cannot support revision %d chips\n", - sc->wx_name, sc->revision); + if (sc->wx_idnrev < WX_WISEMAN_2_0) { + printf("%s: cannot support ID 0x%x, revision %d chips\n", + sc->wx_name, sc->wx_idnrev >> 16, sc->wx_idnrev & 0xffff); return (ENXIO); } @@ -1001,6 +1031,7 @@ wx_start(ifp) wx_softc_t *sc = SOFTC_IFP(ifp); u_int16_t cidx, nactv; + WX_LOCK(sc); nactv = sc->tactive; while (nactv < WX_MAX_TDESC) { int ndesc; @@ -1178,6 +1209,7 @@ again: sc->wx_xmitblocked++; ifp->if_flags |= IFF_OACTIVE; } + WX_UNLOCK(sc); } /* @@ -1190,6 +1222,7 @@ wx_intr(arg) wx_softc_t *sc = arg; int claimed = 0; + WX_ILOCK(sc); /* * Read interrupt cause register. Reading it clears bits. */ @@ -1210,6 +1243,7 @@ wx_intr(arg) } WX_ENABLE_INT(sc); } + WX_IUNLK(sc); return (claimed); } @@ -1245,11 +1279,13 @@ wx_handle_link_intr(sc) if (sc->wx_icr & WXISR_LSC) { if (READ_CSR(sc, WXREG_DSR) & WXDSR_LU) { - /* printf("%s: gigabit link now up\n", sc->wx_name); */ + if (sc->wx_debug) + printf("%s: gigabit link up\n", sc->wx_name); sc->linkup = 1; sc->wx_dcr |= (WXDCR_SWDPIO0|WXDCR_SWDPIN0); } else { - /* printf("%s: gigabit link now down\n", sc->wx_name); */ + if (sc->wx_debug) + printf("%s: gigabit link down\n", sc->wx_name); sc->linkup = 0; sc->wx_dcr &= ~(WXDCR_SWDPIO0|WXDCR_SWDPIN0); } @@ -1280,7 +1316,7 @@ wx_check_link(sc) sc->wx_name); } WRITE_CSR(sc, WXREG_XMIT_CFGW, WXTXCW_DEFAULT & ~WXTXCW_ANE); - if (sc->revision == 2) + if (sc->wx_idnrev < WX_WISEMAN_2_1) sc->wx_dcr &= ~WXDCR_TFCE; sc->wx_dcr |= WXDCR_SLU; WRITE_CSR(sc, WXREG_DCR, sc->wx_dcr); @@ -1434,22 +1470,13 @@ wx_handle_rxint(sc) m0->m_pkthdr.len = tlen - WX_CRC_LENGTH; mb->m_len -= WX_CRC_LENGTH; -#ifdef __OpenBSD__ - pending[npkts++] = m0; -#else eh = mtod(m0, struct ether_header *); - if ((ifp->if_flags & IFF_PROMISC) && - (bcmp(eh->ether_dhost, sc->wx_enaddr, ETHER_ADDR_LEN) && - (eh->ether_dhost[0] & 1) == 0)) { - m_freem(m0); - if (sc->rpending) { - m_freem(sc->rpending); - sc->rpending = NULL; - } - } else { - pending[npkts++] = m0; - } -#endif + /* + * No need to check for promiscous mode since + * the decision to keep or drop the packet is + * handled by ether_input() + */ + pending[npkts++] = m0; m0 = NULL; tlen = 0; } @@ -1488,11 +1515,12 @@ wx_gc(sc) wx_softc_t *sc; { struct ifnet *ifp = &sc->wx_if; - txpkt_t *txpkt = sc->tbsyf; - u_int32_t tdh = READ_CSR(sc, WXREG_TDH); - int s; + txpkt_t *txpkt; + u_int32_t tdh; - s = splimp(); + WX_LOCK(sc); + txpkt = sc->tbsyf; + tdh = READ_CSR(sc, WXREG_TDH); while (txpkt != NULL) { u_int32_t end = txpkt->eidx, cidx = tdh; @@ -1541,12 +1569,16 @@ wx_gc(sc) td = &sc->tdescriptors[cidx]; if (td->status & TXSTS_EC) { - /* printf("%s: excess collisions\n", sc->wx_name); */ + if (sc->wx_debug) + printf("%s: excess collisions\n", + sc->wx_name); ifp->if_collisions++; ifp->if_oerrors++; } if (td->status & TXSTS_LC) { - /* printf("%s: lost carrier\n", sc->wx_name); */ + if (sc->wx_debug) + printf("%s: lost carrier\n", + sc->wx_name); ifp->if_oerrors++; } tmp = &sc->tbase[cidx]; @@ -1570,7 +1602,7 @@ wx_gc(sc) ifp->if_timer = 0; ifp->if_flags &= ~IFF_OACTIVE; } - splx(s); + WX_UNLOCK(sc); } /* @@ -1583,17 +1615,16 @@ wx_watchdog(arg) void *arg; { wx_softc_t *sc = arg; - int s; - s = splimp(); + WX_LOCK(sc); wx_gc(sc); wx_check_link(sc); - splx(s); + WX_UNLOCK(sc); /* * Schedule another timeout one second from now. */ - TIMEOUT(sc, wx_watchdog, sc, hz); + VTIMEOUT(sc, wx_watchdog, sc, hz); } /* @@ -1604,14 +1635,14 @@ wx_hw_stop(sc) wx_softc_t *sc; { u_int32_t icr; - if (sc->revision == 2) { + if (sc->wx_idnrev < WX_WISEMAN_2_1) { wx_mwi_whackon(sc); } WRITE_CSR(sc, WXREG_DCR, WXDCR_RST); DELAY(20 * 1000); WRITE_CSR(sc, WXREG_IMASK, ~0); icr = READ_CSR(sc, WXREG_ICR); - if (sc->revision == 2) { + if (sc->wx_idnrev < WX_WISEMAN_2_1) { wx_mwi_unwhack(sc); } WX_DISABLE_INT(sc); @@ -1637,11 +1668,18 @@ wx_hw_initialize(sc) { int i; + if (IS_LIVENGOOD(sc)) { + if ((READ_CSR(sc, WXREG_DSR) & WXDSR_TBIMODE) == 0) { + printf("%s: no fibre mode detected\n", sc->wx_name); + return (-1); + } + } + WRITE_CSR(sc, WXREG_VET, 0); for (i = 0; i < (WX_VLAN_TAB_SIZE << 2); i += 4) { WRITE_CSR(sc, (WXREG_VFTA + i), 0); } - if (sc->revision == 2) { + if (sc->wx_idnrev < WX_WISEMAN_2_1) { wx_mwi_whackon(sc); WRITE_CSR(sc, WXREG_RCTL, WXRCTL_RST); DELAY(5 * 1000); @@ -1666,7 +1704,7 @@ wx_hw_initialize(sc) i++; } - if (sc->revision == 2) { + if (sc->wx_idnrev < WX_WISEMAN_2_1) { WRITE_CSR(sc, WXREG_RCTL, 0); DELAY(1 * 1000); wx_mwi_unwhack(sc); @@ -1685,6 +1723,14 @@ wx_hw_initialize(sc) WRITE_CSR(sc, WXREG_DCR, sc->wx_dcr | WXDCR_LRST); DELAY(50 * 1000); + + if (IS_LIVENGOOD(sc)) { + u_int16_t tew; + wx_read_eeprom(sc, &tew, WX_EEPROM_CTLR2_OFF, 1); + tew = (tew & WX_EEPROM_CTLR2_SWDPIO) << WX_EEPROM_EXT_SHIFT; + WRITE_CSR(sc, WXREG_EXCT, (u_int32_t)tew); + } + if (sc->wx_dcr & (WXDCR_RFCE|WXDCR_TFCE)) { WRITE_CSR(sc, WXREG_FCAL, FC_FRM_CONST_LO); WRITE_CSR(sc, WXREG_FCAH, FC_FRM_CONST_HI); @@ -1695,7 +1741,8 @@ wx_hw_initialize(sc) WRITE_CSR(sc, WXREG_FCT, 0); } WRITE_CSR(sc, WXREG_FLOW_XTIMER, WX_XTIMER_DFLT); - if (sc->revision == 2) { + + if (sc->wx_idnrev < WX_WISEMAN_2_1) { WRITE_CSR(sc, WXREG_FLOW_RCV_HI, 0); WRITE_CSR(sc, WXREG_FLOW_RCV_LO, 0); sc->wx_dcr &= ~(WXDCR_RFCE|WXDCR_TFCE); @@ -1812,9 +1859,9 @@ wx_init(xsc) rxpkt_t *rxpkt; wxrd_t *rd; size_t len; - int s, i, bflags; + int i, bflags; - s = splimp(); + WX_LOCK(sc); /* * Cancel any pending I/O by resetting things. @@ -1828,6 +1875,7 @@ wx_init(xsc) */ if (wx_hw_initialize(sc)) { + WX_UNLOCK(sc); return (EIO); } @@ -1847,6 +1895,7 @@ wx_init(xsc) if (i != WX_MAX_RDESC) { printf("%s: could not set up rbufs\n", sc->wx_name); wx_stop(sc); + WX_UNLOCK(sc); return (ENOMEM); } @@ -1865,7 +1914,11 @@ wx_init(xsc) WRITE_CSR(sc, WXREG_TDT, 0); WRITE_CSR(sc, WXREG_TQSA_HI, 0); WRITE_CSR(sc, WXREG_TQSA_LO, 0); - WRITE_CSR(sc, WXREG_TIPG, WX_TIPG_DFLT); + if (IS_WISEMAN(sc)) { + WRITE_CSR(sc, WXREG_TIPG, WX_WISEMAN_TIPG_DFLT); + } else { + WRITE_CSR(sc, WXREG_TIPG, WX_LIVENGOOD_TIPG_DFLT); + } WRITE_CSR(sc, WXREG_TIDV, sc->wx_txint_delay); WRITE_CSR(sc, WXREG_TCTL, (WXTCTL_CT(WX_COLLISION_THRESHOLD) | WXTCTL_COLD(WX_FDX_COLLISION_DX) | WXTCTL_EN)); @@ -1891,7 +1944,6 @@ wx_init(xsc) WRITE_CSR(sc, WXREG_RDT1, 0); if (ifp->if_mtu > ETHERMTU) { - /* printf("%s: enabling for jumbo packets\n", sc->wx_name); */ bflags = WXRCTL_EN | WXRCTL_LPE | WXRCTL_2KRBUF; } else { bflags = WXRCTL_EN | WXRCTL_2KRBUF; @@ -1918,7 +1970,7 @@ wx_init(xsc) ifm->ifm_media = ifm->ifm_cur->ifm_media; wx_ifmedia_upd(ifp); ifm->ifm_media = i; - splx(s); + WX_UNLOCK(sc); /* * Start stats updater. @@ -1981,9 +2033,9 @@ wx_ioctl(ifp, command, data) { wx_softc_t *sc = SOFTC_IFP(ifp); struct ifreq *ifr = (struct ifreq *) data; - int s, error = 0; + int error = 0; - s = splimp(); + WX_LOCK(sc); switch (command) { case SIOCSIFADDR: #if !defined(__NetBSD__) && !defined(__OpenBSD__) @@ -2050,7 +2102,7 @@ wx_ioctl(ifp, command, data) error = EINVAL; } - (void) splx(s); + WX_UNLOCK(sc); return (error); } @@ -2071,6 +2123,7 @@ wx_ifmedia_sts(ifp, ifmr) struct ifnet *ifp; struct ifmediareq *ifmr; { + u_int32_t dsr; struct wx_softc *sc = SOFTC_IFP(ifp); ifmr->ifm_status = IFM_AVALID; @@ -2079,7 +2132,20 @@ wx_ifmedia_sts(ifp, ifmr) if (sc->linkup == 0) return; - ifmr->ifm_status |= IFM_ACTIVE|IFM_1000_SX; - if (READ_CSR(sc, WXREG_DSR) & WXDSR_FD) + ifmr->ifm_status |= IFM_ACTIVE; + dsr = READ_CSR(sc, WXREG_DSR); + if (IS_LIVENGOOD(sc)) { + if (dsr & WXDSR_1000BT) { + ifmr->ifm_status |= IFM_1000_SX; + } else if (dsr & WXDSR_100BT) { + ifmr->ifm_status |= IFM_100_FX; /* ?? */ + } else { + ifmr->ifm_status |= IFM_10_T; /* ?? */ + } + } else { + ifmr->ifm_status |= IFM_1000_SX; + } + if (dsr & WXDSR_FD) { ifmr->ifm_active |= IFM_FDX; + } } |