Module Name: src Committed By: snj Date: Thu May 21 01:13:49 UTC 2009
Modified Files: src/sys/dev/pci [netbsd-5]: if_wm.c if_wmreg.h pcidevs Log Message: Pull up following revision(s) (requested by bouyer in ticket #711): sys/dev/pci/pcidevs: revisions 1.975, 1.981, 1.982 via patch sys/dev/pci/if_wm.c: revisions 1.164, 1.167, 1.173, 1.174 via patch sys/dev/pci/if_wmreg.h: revisions 1.25, 1.27 via patch Add Intel 82567LM_3 ethernet -- Add i82567LM-3 -- add i82567LF-3 LAN Controller -- add an entry for 82567LF-3. fix the register access for ICH10DO. -- Fix about TBI mode. This fix doesn't influence MII mode. -- - Fix panic in mediachange. - Fix SWDPIN(1)'s polarity on some chips. - Fix flow control stuff (includes PR#32009). - Stop RXCFG storm. It ocours easily. - And more fix about autonego. -- add 82801J_D_BM_LF (ICH10) -- Reload sc_ctrl in wm_reset(). Add an ICH10 entry. Remove some obsolete comments. To generate a diff of this commit: cvs rdiff -u -r1.162.4.8 -r1.162.4.9 src/sys/dev/pci/if_wm.c cvs rdiff -u -r1.24.20.1 -r1.24.20.2 src/sys/dev/pci/if_wmreg.h cvs rdiff -u -r1.962.4.3 -r1.962.4.4 src/sys/dev/pci/pcidevs Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/pci/if_wm.c diff -u src/sys/dev/pci/if_wm.c:1.162.4.8 src/sys/dev/pci/if_wm.c:1.162.4.9 --- src/sys/dev/pci/if_wm.c:1.162.4.8 Mon May 11 20:11:34 2009 +++ src/sys/dev/pci/if_wm.c Thu May 21 01:13:49 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: if_wm.c,v 1.162.4.8 2009/05/11 20:11:34 bouyer Exp $ */ +/* $NetBSD: if_wm.c,v 1.162.4.9 2009/05/21 01:13:49 snj Exp $ */ /* * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc. @@ -73,13 +73,10 @@ * TODO (in order of importance): * * - Rework how parameters are loaded from the EEPROM. - * - Figure out what to do with the i82545GM and i82546GB - * SERDES controllers. - * - Fix hw VLAN assist. */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.162.4.8 2009/05/11 20:11:34 bouyer Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.162.4.9 2009/05/21 01:13:49 snj Exp $"); #include "bpfilter.h" #include "rnd.h" @@ -254,8 +251,11 @@ WM_T_80003, /* i80003 */ WM_T_ICH8, /* ICH8 LAN */ WM_T_ICH9, /* ICH9 LAN */ + WM_T_ICH10, /* ICH10 LAN */ } wm_chip_type; +#define WM_LINKUP_TIMEOUT 50 + /* * Software state per device. */ @@ -376,7 +376,10 @@ uint32_t sc_pba; /* prototype PBA register */ int sc_tbi_linkup; /* TBI link status */ - int sc_tbi_anstate; /* autonegotiation state */ + int sc_tbi_anegticks; /* autonegotiation ticks */ + int sc_tbi_ticks; /* tbi ticks */ + int sc_tbi_nrxcfg; /* count of ICR_RXCFG */ + int sc_tbi_lastnrxcfg; /* count of ICR_RXCFG (on last tick) */ int sc_mchash_type; /* multicast filter offset */ @@ -554,6 +557,9 @@ static int wm_gmii_i80003_readreg(device_t, int, int); static void wm_gmii_i80003_writereg(device_t, int, int, int); +static int wm_gmii_bm_readreg(device_t, int, int); +static void wm_gmii_bm_writereg(device_t, int, int, int); + static void wm_gmii_statchg(device_t); static void wm_gmii_mediainit(struct wm_softc *); @@ -580,13 +586,17 @@ static int32_t wm_ich8_flash_cycle(struct wm_softc *, uint32_t); static int32_t wm_read_ich8_data(struct wm_softc *, uint32_t, uint32_t, uint16_t *); +static int32_t wm_read_ich8_byte(struct wm_softc *sc, uint32_t, uint8_t *); static int32_t wm_read_ich8_word(struct wm_softc *sc, uint32_t, uint16_t *); static void wm_82547_txfifo_stall(void *); static int wm_check_mng_mode(struct wm_softc *); static int wm_check_mng_mode_ich8lan(struct wm_softc *); +#if 0 static int wm_check_mng_mode_82574(struct wm_softc *); +#endif static int wm_check_mng_mode_generic(struct wm_softc *); static void wm_get_hw_control(struct wm_softc *); +static int wm_check_for_link(struct wm_softc *); CFATTACH_DECL_NEW(wm, sizeof(struct wm_softc), wm_match, wm_attach, NULL, NULL); @@ -867,6 +877,15 @@ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801I_IGP_M_AMT, "82801I mobile (AMT) LAN Controller", WM_T_ICH9, WMP_F_1000T }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82567LM_3, + "82567LM-3 LAN Controller", + WM_T_ICH10, WMP_F_1000T }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82567LF_3, + "82567LF-3 LAN Controller", + WM_T_ICH10, WMP_F_1000T }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801J_D_BM_LF, + "i82801J (LF) LAN Controller", + WM_T_ICH10, WMP_F_1000T }, { 0, 0, NULL, 0, 0 }, @@ -1102,7 +1121,8 @@ } } else if (sc->sc_type >= WM_T_82571) { sc->sc_flags |= WM_F_PCIE; - if ((sc->sc_type != WM_T_ICH8) && (sc->sc_type != WM_T_ICH9)) + if ((sc->sc_type != WM_T_ICH8) && (sc->sc_type != WM_T_ICH9) + && (sc->sc_type != WM_T_ICH10)) sc->sc_flags |= WM_F_EEPROM_SEMAPHORE; aprint_verbose_dev(sc->sc_dev, "PCI-Express bus\n"); } else { @@ -1272,9 +1292,14 @@ wm_reset(sc); switch (sc->sc_type) { + case WM_T_82571: + case WM_T_82572: case WM_T_82573: + case WM_T_82574: + case WM_T_80003: case WM_T_ICH8: case WM_T_ICH9: + case WM_T_ICH10: if (wm_check_mng_mode(sc) != 0) wm_get_hw_control(sc); break; @@ -1285,7 +1310,8 @@ /* * Get some information about the EEPROM. */ - if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)) { + if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9) + || (sc->sc_type == WM_T_ICH10)) { uint32_t flash_size; sc->sc_flags |= WM_F_SWFWHW_SYNC | WM_F_EEPROM_FLASH; memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, WM_ICH8_FLASH); @@ -1508,7 +1534,8 @@ * media structures accordingly. */ if (sc->sc_type == WM_T_ICH8 || sc->sc_type == WM_T_ICH9 - || sc->sc_type == WM_T_82573 || sc->sc_type == WM_T_82574) { + || sc->sc_type == WM_T_ICH10 || sc->sc_type == WM_T_82573 + || sc->sc_type == WM_T_82574) { /* STATUS_TBIMODE reserved/reused, can't rely on it */ wm_gmii_mediainit(sc); } else if (sc->sc_type < WM_T_82543 || @@ -2759,6 +2786,8 @@ { uint32_t status; + DPRINTF(WM_DEBUG_LINK, ("%s: %s:\n", device_xname(sc->sc_dev), + __func__)); /* * If we get a link status interrupt on a 1000BASE-T * device, just fall into the normal MII tick path. @@ -2815,22 +2844,18 @@ return; } - /* - * If we are now receiving /C/, check for link again in - * a couple of link clock ticks. - */ - if (icr & ICR_RXCFG) { - DPRINTF(WM_DEBUG_LINK, ("%s: LINK: receiving /C/\n", - device_xname(sc->sc_dev))); - sc->sc_tbi_anstate = 2; - } - + status = CSR_READ(sc, WMREG_STATUS); if (icr & ICR_LSC) { - status = CSR_READ(sc, WMREG_STATUS); if (status & STATUS_LU) { DPRINTF(WM_DEBUG_LINK, ("%s: LINK: LSC -> up %s\n", device_xname(sc->sc_dev), (status & STATUS_FD) ? "FDX" : "HDX")); + /* + * NOTE: CTRL will update TFCE and RFCE automatically, + * so we should update sc->sc_ctrl + */ + + sc->sc_ctrl = CSR_READ(sc, WMREG_CTRL); sc->sc_tctl &= ~TCTL_COLD(0x3ff); sc->sc_fcrtl &= ~FCRTL_XONE; if (status & STATUS_FD) @@ -2839,7 +2864,7 @@ else sc->sc_tctl |= TCTL_COLD(TX_COLLISION_DISTANCE_HDX); - if (CSR_READ(sc, WMREG_CTRL) & CTRL_TFCE) + if (sc->sc_ctrl & CTRL_TFCE) sc->sc_fcrtl |= FCRTL_XONE; CSR_WRITE(sc, WMREG_TCTL, sc->sc_tctl); CSR_WRITE(sc, (sc->sc_type < WM_T_82543) ? @@ -2851,8 +2876,12 @@ device_xname(sc->sc_dev))); sc->sc_tbi_linkup = 0; } - sc->sc_tbi_anstate = 2; wm_tbi_set_linkled(sc); + } else if (icr & ICR_RXCFG) { + DPRINTF(WM_DEBUG_LINK, ("%s: LINK: receiving /C/\n", + device_xname(sc->sc_dev))); + sc->sc_tbi_nrxcfg++; + wm_check_for_link(sc); } else if (icr & ICR_RXSEQ) { DPRINTF(WM_DEBUG_LINK, ("%s: LINK: Receive sequence error\n", @@ -2937,6 +2966,7 @@ CSR_WRITE(sc, WMREG_PBS, PBA_16K); break; case WM_T_ICH9: + case WM_T_ICH10: sc->sc_pba = PBA_10K; break; default: @@ -3005,6 +3035,7 @@ case WM_T_ICH8: case WM_T_ICH9: + case WM_T_ICH10: wm_get_swfwhw_semaphore(sc); CSR_WRITE(sc, WMREG_CTRL, CTRL_RST | CTRL_PHY_RESET); delay(10000); @@ -3046,6 +3077,9 @@ wm_get_auto_rd_done(sc); } + /* reload sc_ctrl */ + sc->sc_ctrl = CSR_READ(sc, WMREG_CTRL); + #if 0 for (i = 0; i < 1000; i++) { if ((CSR_READ(sc, WMREG_CTRL) & CTRL_RST) == 0) { @@ -3104,9 +3138,14 @@ wm_reset(sc); switch (sc->sc_type) { + case WM_T_82571: + case WM_T_82572: case WM_T_82573: + case WM_T_82574: + case WM_T_80003: case WM_T_ICH8: case WM_T_ICH9: + case WM_T_ICH10: if (wm_check_mng_mode(sc) != 0) wm_get_hw_control(sc); break; @@ -3277,6 +3316,9 @@ reg |= RXCSUM_IPV6OFL | RXCSUM_TUOFL; CSR_WRITE(sc, WMREG_RXCSUM, reg); + /* Reset TBI's RXCFG count */ + sc->sc_tbi_nrxcfg = sc->sc_tbi_lastnrxcfg = 0; + /* * Set up the interrupt registers. */ @@ -3433,6 +3475,11 @@ if (sc->sc_flags & WM_F_HAS_MII) { /* Down the MII. */ mii_down(&sc->sc_mii); + } else { +#if 0 + /* Should we clear PHY's status properly? */ + wm_reset(sc); +#endif } /* Stop the transmit and receive processes. */ @@ -3480,6 +3527,7 @@ case WM_T_80003: case WM_T_ICH8: case WM_T_ICH9: + case WM_T_ICH10: for (i = 10; i > 0; i--) { if (CSR_READ(sc, WMREG_EECD) & EECD_EE_AUTORD) break; @@ -3798,7 +3846,8 @@ if (wm_acquire_eeprom(sc)) return 1; - if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)) + if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9) + || (sc->sc_type == WM_T_ICH10)) rv = wm_read_eeprom_ich8(sc, word, wordcnt, data); else if (sc->sc_flags & WM_F_EEPROM_EERDEEWR) rv = wm_read_eeprom_eerd(sc, word, wordcnt, data); @@ -3944,7 +3993,8 @@ static const int ich8_hi_shift[4] = { 2, 3, 4, 6 }; uint32_t hash; - if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)) { + if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9) + || (sc->sc_type == WM_T_ICH10)) { hash = (enaddr[4] >> ich8_lo_shift[sc->sc_mchash_type]) | (((uint16_t) enaddr[5]) << ich8_hi_shift[sc->sc_mchash_type]); return (hash & 0x3ff); @@ -3989,7 +4039,8 @@ * Set the station address in the first RAL slot, and * clear the remaining slots. */ - if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)) + if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9) + || (sc->sc_type == WM_T_ICH10)) size = WM_ICH8_RAL_TABSIZE; else size = WM_RAL_TABSIZE; @@ -3997,7 +4048,8 @@ for (i = 1; i < size; i++) wm_set_ral(sc, NULL, i); - if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)) + if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9) + || (sc->sc_type == WM_T_ICH10)) size = WM_ICH8_MC_TABSIZE; else size = WM_MC_TABSIZE; @@ -4022,7 +4074,8 @@ hash = wm_mchash(sc, enm->enm_addrlo); reg = (hash >> 5); - if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)) + if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9) + || (sc->sc_type == WM_T_ICH10)) reg &= 0x1f; else reg &= 0x7f; @@ -4061,6 +4114,7 @@ static void wm_tbi_mediainit(struct wm_softc *sc) { + struct ifnet *ifp = &sc->sc_ethercom.ec_if; const char *sep = ""; if (sc->sc_type < WM_T_82543) @@ -4068,6 +4122,12 @@ else sc->sc_tipg = TIPG_LG_DFLT; + sc->sc_tbi_anegticks = 5; + + /* Initialize our media structures */ + sc->sc_mii.mii_ifp = ifp; + + sc->sc_ethercom.ec_mii = &sc->sc_mii; ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK, wm_tbi_mediachange, wm_tbi_mediastatus); @@ -4109,12 +4169,13 @@ wm_tbi_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) { struct wm_softc *sc = ifp->if_softc; - uint32_t ctrl; + uint32_t ctrl, status; ifmr->ifm_status = IFM_AVALID; ifmr->ifm_active = IFM_ETHER; - if (sc->sc_tbi_linkup == 0) { + status = CSR_READ(sc, WMREG_STATUS); + if ((status & STATUS_LU) == 0) { ifmr->ifm_active |= IFM_NONE; return; } @@ -4143,18 +4204,20 @@ uint32_t status; int i; - sc->sc_txcw = ife->ifm_data; - DPRINTF(WM_DEBUG_LINK,("%s: sc_txcw = 0x%x on entry\n", - device_xname(sc->sc_dev),sc->sc_txcw)); + sc->sc_txcw = 0; if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO || (sc->sc_mii.mii_media.ifm_media & IFM_FLOW) != 0) - sc->sc_txcw |= ANAR_X_PAUSE_SYM | ANAR_X_PAUSE_ASYM; + sc->sc_txcw |= TXCW_SYM_PAUSE | TXCW_ASYM_PAUSE; if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) { - sc->sc_txcw |= TXCW_ANE; + sc->sc_txcw |= TXCW_ANE; } else { - /*If autonegotiation is turned off, force link up and turn on full duplex*/ + /* + * If autonegotiation is turned off, force link up and turn on + * full duplex + */ sc->sc_txcw &= ~TXCW_ANE; sc->sc_ctrl |= CTRL_SLU | CTRL_FD; + sc->sc_ctrl &= ~(CTRL_TFCE | CTRL_RFCE); CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl); delay(1000); } @@ -4164,10 +4227,6 @@ CSR_WRITE(sc, WMREG_TXCW, sc->sc_txcw); delay(10000); - /* NOTE: CTRL will update TFCE and RFCE automatically. */ - - sc->sc_tbi_anstate = 0; - i = CSR_READ(sc, WMREG_CTRL) & CTRL_SWDPIN(1); DPRINTF(WM_DEBUG_LINK,("%s: i = 0x%x\n", device_xname(sc->sc_dev),i)); @@ -4175,7 +4234,7 @@ * On 82544 chips and later, the CTRL_SWDPIN(1) bit will be set if the * optics detect a signal, 0 if they don't. */ - if (((i != 0) && (sc->sc_type >= WM_T_82544)) || (i == 0)) { + if (((i != 0) && (sc->sc_type > WM_T_82544)) || (i == 0)) { /* Have signal; wait for the link to come up. */ if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) { @@ -4190,7 +4249,7 @@ delay(1000); } - for (i = 0; i < 50; i++) { + for (i = 0; i < WM_LINKUP_TIMEOUT; i++) { delay(10000); if (CSR_READ(sc, WMREG_STATUS) & STATUS_LU) break; @@ -4209,6 +4268,12 @@ ("%s: LINK: set media -> link up %s\n", device_xname(sc->sc_dev), (status & STATUS_FD) ? "FDX" : "HDX")); + + /* + * NOTE: CTRL will update TFCE and RFCE automatically, + * so we should update sc->sc_ctrl + */ + sc->sc_ctrl = CSR_READ(sc, WMREG_CTRL); sc->sc_tctl &= ~TCTL_COLD(0x3ff); sc->sc_fcrtl &= ~FCRTL_XONE; if (status & STATUS_FD) @@ -4225,6 +4290,8 @@ sc->sc_fcrtl); sc->sc_tbi_linkup = 1; } else { + if (i == WM_LINKUP_TIMEOUT) + wm_check_for_link(sc); /* Link is down. */ DPRINTF(WM_DEBUG_LINK, ("%s: LINK: set media -> link down\n", @@ -4256,6 +4323,9 @@ else sc->sc_ctrl &= ~CTRL_SWDPIN(0); + /* 82540 or newer devices are active low */ + sc->sc_ctrl ^= (sc->sc_type >= WM_T_82540) ? CTRL_SWDPIN(0) : 0; + CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl); } @@ -4267,49 +4337,58 @@ static void wm_tbi_check_link(struct wm_softc *sc) { + struct ifnet *ifp = &sc->sc_ethercom.ec_if; + struct ifmedia_entry *ife = sc->sc_mii.mii_media.ifm_cur; uint32_t rxcw, ctrl, status; - if (sc->sc_tbi_anstate == 0) - return; - else if (sc->sc_tbi_anstate > 1) { - DPRINTF(WM_DEBUG_LINK, - ("%s: LINK: anstate %d\n", device_xname(sc->sc_dev), - sc->sc_tbi_anstate)); - sc->sc_tbi_anstate--; - return; - } - - sc->sc_tbi_anstate = 0; + status = CSR_READ(sc, WMREG_STATUS); rxcw = CSR_READ(sc, WMREG_RXCW); ctrl = CSR_READ(sc, WMREG_CTRL); - status = CSR_READ(sc, WMREG_STATUS); + /* set link status */ if ((status & STATUS_LU) == 0) { DPRINTF(WM_DEBUG_LINK, ("%s: LINK: checklink -> down\n", device_xname(sc->sc_dev))); sc->sc_tbi_linkup = 0; - } else { + } else if (sc->sc_tbi_linkup == 0) { DPRINTF(WM_DEBUG_LINK, ("%s: LINK: checklink -> up %s\n", device_xname(sc->sc_dev), (status & STATUS_FD) ? "FDX" : "HDX")); - sc->sc_tctl &= ~TCTL_COLD(0x3ff); - sc->sc_fcrtl &= ~FCRTL_XONE; - if (status & STATUS_FD) - sc->sc_tctl |= - TCTL_COLD(TX_COLLISION_DISTANCE_FDX); - else - sc->sc_tctl |= - TCTL_COLD(TX_COLLISION_DISTANCE_HDX); - if (ctrl & CTRL_TFCE) - sc->sc_fcrtl |= FCRTL_XONE; - CSR_WRITE(sc, WMREG_TCTL, sc->sc_tctl); - CSR_WRITE(sc, (sc->sc_type < WM_T_82543) ? - WMREG_OLD_FCRTL : WMREG_FCRTL, - sc->sc_fcrtl); sc->sc_tbi_linkup = 1; } + if ((sc->sc_ethercom.ec_if.if_flags & IFF_UP) + && ((status & STATUS_LU) == 0)) { + sc->sc_tbi_linkup = 0; + if (sc->sc_tbi_nrxcfg - sc->sc_tbi_lastnrxcfg > 100) { + /* RXCFG storm! */ + DPRINTF(WM_DEBUG_LINK, ("RXCFG storm! (%d)\n", + sc->sc_tbi_nrxcfg - sc->sc_tbi_lastnrxcfg)); + wm_init(ifp); + wm_start(ifp); + } else if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) { + /* If the timer expired, retry autonegotiation */ + if (++sc->sc_tbi_ticks >= sc->sc_tbi_anegticks) { + DPRINTF(WM_DEBUG_LINK, ("EXPIRE\n")); + sc->sc_tbi_ticks = 0; + /* + * Reset the link, and let autonegotiation do + * its thing + */ + sc->sc_ctrl |= CTRL_LRST; + CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl); + delay(1000); + sc->sc_ctrl &= ~CTRL_LRST; + CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl); + delay(1000); + CSR_WRITE(sc, WMREG_TXCW, + sc->sc_txcw & ~TXCW_ANE); + CSR_WRITE(sc, WMREG_TXCW, sc->sc_txcw); + } + } + } + wm_tbi_set_linkled(sc); } @@ -4324,7 +4403,8 @@ uint32_t reg; int func = 0; /* XXX gcc */ - if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)) { + if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9) + || (sc->sc_type == WM_T_ICH10)) { if (wm_get_swfwhw_semaphore(sc)) { aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", __func__); @@ -4374,7 +4454,8 @@ sc->sc_ctrl_ext = reg | CTRL_EXT_SWDPIN(4); #endif } - if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9)) + if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9) + || (sc->sc_type == WM_T_ICH10)) wm_put_swfwhw_semaphore(sc); if (sc->sc_type == WM_T_80003) wm_put_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM); @@ -4410,7 +4491,10 @@ /* Initialize our media structures and probe the GMII. */ sc->sc_mii.mii_ifp = ifp; - if (sc->sc_type >= WM_T_80003) { + if (sc->sc_type == WM_T_ICH10) { + sc->sc_mii.mii_readreg = wm_gmii_bm_readreg; + sc->sc_mii.mii_writereg = wm_gmii_bm_writereg; + } else if (sc->sc_type >= WM_T_80003) { sc->sc_mii.mii_readreg = wm_gmii_i80003_readreg; sc->sc_mii.mii_writereg = wm_gmii_i80003_writereg; } else if (sc->sc_type >= WM_T_82544) { @@ -4706,12 +4790,11 @@ wm_gmii_i82544_writereg(self, phy, GG82563_PHY_PAGE_SELECT_ALT, reg >> GG82563_PAGE_SHIFT); } - /* Wait more 200us for a bug of the ready bit in the MDIC register */ delay(200); - rv = wm_gmii_i82544_readreg(self, phy, reg & GG82563_MAX_REG_ADDRESS); delay(200); + wm_put_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM); return (rv); } @@ -4745,12 +4828,79 @@ wm_gmii_i82544_writereg(self, phy, GG82563_PHY_PAGE_SELECT_ALT, reg >> GG82563_PAGE_SHIFT); } - /* Wait more 200us for a bug of the ready bit in the MDIC register */ delay(200); - wm_gmii_i82544_writereg(self, phy, reg & GG82563_MAX_REG_ADDRESS, val); delay(200); + + wm_put_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM); +} + +/* + * wm_gmii_bm_readreg: [mii interface function] + * + * Read a PHY register on the kumeran + * This could be handled by the PHY layer if we didn't have to lock the + * ressource ... + */ +static int +wm_gmii_bm_readreg(device_t self, int phy, int reg) +{ + struct wm_softc *sc = device_private(self); + int func = ((CSR_READ(sc, WMREG_STATUS) >> STATUS_FUNCID_SHIFT) & 1); + int rv; + + if (wm_get_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM)) { + aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", + __func__); + return 0; + } + + if (reg > GG82563_MAX_REG_ADDRESS) { + if (phy == 1) + wm_gmii_i82544_writereg(self, phy, 0x1f, + reg); + else + wm_gmii_i82544_writereg(self, phy, GG82563_PHY_PAGE_SELECT, + reg >> GG82563_PAGE_SHIFT); + + } + + rv = wm_gmii_i82544_readreg(self, phy, reg & GG82563_MAX_REG_ADDRESS); + wm_put_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM); + return (rv); +} + +/* + * wm_gmii_bm_writereg: [mii interface function] + * + * Write a PHY register on the kumeran. + * This could be handled by the PHY layer if we didn't have to lock the + * ressource ... + */ +static void +wm_gmii_bm_writereg(device_t self, int phy, int reg, int val) +{ + struct wm_softc *sc = device_private(self); + int func = ((CSR_READ(sc, WMREG_STATUS) >> STATUS_FUNCID_SHIFT) & 1); + + if (wm_get_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM)) { + aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", + __func__); + return; + } + + if (reg > GG82563_MAX_REG_ADDRESS) { + if (phy == 1) + wm_gmii_i82544_writereg(self, phy, 0x1f, + reg); + else + wm_gmii_i82544_writereg(self, phy, GG82563_PHY_PAGE_SELECT, + reg >> GG82563_PAGE_SHIFT); + + } + + wm_gmii_i82544_writereg(self, phy, reg & GG82563_MAX_REG_ADDRESS, val); wm_put_swfw_semaphore(sc, func ? SWFW_PHY1_SM : SWFW_PHY0_SM); } @@ -5006,6 +5156,36 @@ CSR_WRITE(sc, WMREG_EXTCNFCTR, ext_ctrl); } +static int +wm_valid_nvm_bank_detect_ich8lan(struct wm_softc *sc, unsigned int *bank) +{ + uint32_t act_offset = ICH_NVM_SIG_WORD * 2 + 1; + uint8_t bank_high_byte; + uint32_t bank1_offset = sc->sc_ich8_flash_bank_size * sizeof(uint16_t); + + if (sc->sc_type != WM_T_ICH10) { + /* Value of bit 22 corresponds to the flash bank we're on. */ + *bank = (CSR_READ(sc, WMREG_EECD) & EECD_SEC1VAL) ? 1 : 0; + } else { + wm_read_ich8_byte(sc, act_offset, &bank_high_byte); + if ((bank_high_byte & 0xc0) == 0x80) + *bank = 0; + else { + wm_read_ich8_byte(sc, act_offset + bank1_offset, + &bank_high_byte); + if ((bank_high_byte & 0xc0) == 0x80) + *bank = 1; + else { + aprint_error_dev(sc->sc_dev, + "EEPROM not present\n"); + return -1; + } + } + } + + return 0; +} + /****************************************************************************** * Reads a 16 bit word or words from the EEPROM using the ICH8's flash access * register. @@ -5030,8 +5210,12 @@ * managing flash_bank. So it cannot be trusted and needs * to be updated with each read. */ - /* Value of bit 22 corresponds to the flash bank we're on. */ - flash_bank = (CSR_READ(sc, WMREG_EECD) & EECD_SEC1VAL) ? 1 : 0; + error = wm_valid_nvm_bank_detect_ich8lan(sc, &flash_bank); + if (error) { + aprint_error_dev(sc->sc_dev, "%s: failed to detect NVM bank\n", + __func__); + return error; + } /* Adjust offset appropriately if we're on bank 1 - adjust for word size */ bank_offset = flash_bank * (sc->sc_ich8_flash_bank_size * 2); @@ -5229,7 +5413,6 @@ return error; } -#if 0 /****************************************************************************** * Reads a single byte from the NVM using the ICH8 flash access registers. * @@ -5250,7 +5433,6 @@ return status; } -#endif /****************************************************************************** * Reads a word from the NVM using the ICH8 flash access registers. @@ -5276,14 +5458,28 @@ switch (sc->sc_type) { case WM_T_ICH8: case WM_T_ICH9: + case WM_T_ICH10: rv = wm_check_mng_mode_ich8lan(sc); break; +#if 0 case WM_T_82574: + /* + * The function is provided in em driver, but it's not + * used. Why? + */ rv = wm_check_mng_mode_82574(sc); break; - default: +#endif + case WM_T_82571: + case WM_T_82572: + case WM_T_82573: + case WM_T_80003: rv = wm_check_mng_mode_generic(sc); break; + default: + /* noting to do */ + rv = 0; + break; } return rv; @@ -5302,6 +5498,7 @@ return 0; } +#if 0 static int wm_check_mng_mode_82574(struct wm_softc *sc) { @@ -5314,6 +5511,7 @@ return 0; } +#endif static int wm_check_mng_mode_generic(struct wm_softc *sc) @@ -5335,6 +5533,13 @@ switch (sc->sc_type) { case WM_T_82573: +#if 0 + case WM_T_82574: + /* + * FreeBSD's em driver has the function for 82574 to checks + * the management mode, but it's not used. Why? + */ +#endif reg = CSR_READ(sc, WMREG_SWSM); CSR_WRITE(sc, WMREG_SWSM, reg | SWSM_DRV_LOAD); break; @@ -5343,6 +5548,7 @@ case WM_T_80003: case WM_T_ICH8: case WM_T_ICH9: + case WM_T_ICH10: reg = CSR_READ(sc, WMREG_CTRL_EXT); CSR_WRITE(sc, WMREG_CTRL_EXT, reg | CTRL_EXT_DRV_LOAD); break; @@ -5350,3 +5556,74 @@ break; } } + +/* XXX Currently TBI only */ +static int +wm_check_for_link(struct wm_softc *sc) +{ + struct ifmedia_entry *ife = sc->sc_mii.mii_media.ifm_cur; + uint32_t rxcw; + uint32_t ctrl; + uint32_t status; + uint32_t sig; + + rxcw = CSR_READ(sc, WMREG_RXCW); + ctrl = CSR_READ(sc, WMREG_CTRL); + status = CSR_READ(sc, WMREG_STATUS); + + sig = (sc->sc_type > WM_T_82544) ? CTRL_SWDPIN(1) : 0; + + DPRINTF(WM_DEBUG_LINK, ("%s: %s: sig = %d, status_lu = %d, rxcw_c = %d\n", + device_xname(sc->sc_dev), __func__, + ((ctrl & CTRL_SWDPIN(1)) == sig), + ((status & STATUS_LU) != 0), + ((rxcw & RXCW_C) != 0) + )); + + /* + * SWDPIN LU RXCW + * 0 0 0 + * 0 0 1 (should not happen) + * 0 1 0 (should not happen) + * 0 1 1 (should not happen) + * 1 0 0 Disable autonego and force linkup + * 1 0 1 got /C/ but not linkup yet + * 1 1 0 (linkup) + * 1 1 1 If IFM_AUTO, back to autonego + * + */ + if (((ctrl & CTRL_SWDPIN(1)) == sig) + && ((status & STATUS_LU) == 0) + && ((rxcw & RXCW_C) == 0)) { + DPRINTF(WM_DEBUG_LINK, ("%s: force linkup and fullduplex\n", + __func__)); + sc->sc_tbi_linkup = 0; + /* Disable auto-negotiation in the TXCW register */ + CSR_WRITE(sc, WMREG_TXCW, (sc->sc_txcw & ~TXCW_ANE)); + + /* + * Force link-up and also force full-duplex. + * + * NOTE: CTRL was updated TFCE and RFCE automatically, + * so we should update sc->sc_ctrl + */ + sc->sc_ctrl = ctrl | CTRL_SLU | CTRL_FD; + CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl); + } else if(((status & STATUS_LU) != 0) + && ((rxcw & RXCW_C) != 0) + && (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO)) { + sc->sc_tbi_linkup = 1; + DPRINTF(WM_DEBUG_LINK, ("%s: go back to autonego\n", + __func__)); + CSR_WRITE(sc, WMREG_TXCW, sc->sc_txcw); + CSR_WRITE(sc, WMREG_CTRL, (ctrl & ~CTRL_SLU)); + } else if (((ctrl & CTRL_SWDPIN(1)) == sig) + && ((rxcw & RXCW_C) != 0)) { + DPRINTF(WM_DEBUG_LINK, ("/C/")); + } else { + DPRINTF(WM_DEBUG_LINK, ("%s: %x,%x,%x\n", __func__, rxcw, ctrl, + status)); + } + + return 0; +} Index: src/sys/dev/pci/if_wmreg.h diff -u src/sys/dev/pci/if_wmreg.h:1.24.20.1 src/sys/dev/pci/if_wmreg.h:1.24.20.2 --- src/sys/dev/pci/if_wmreg.h:1.24.20.1 Sun May 3 17:51:02 2009 +++ src/sys/dev/pci/if_wmreg.h Thu May 21 01:13:49 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: if_wmreg.h,v 1.24.20.1 2009/05/03 17:51:02 snj Exp $ */ +/* $NetBSD: if_wmreg.h,v 1.24.20.2 2009/05/21 01:13:49 snj Exp $ */ /* * Copyright (c) 2001 Wasabi Systems, Inc. @@ -482,6 +482,8 @@ #define WMREG_TXCW 0x0178 /* Transmit Configuration Word (TBI mode) */ /* See MII ANAR_X bits. */ +#define TXCW_SYM_PAUSE (1U << 7) /* sym pause request */ +#define TXCW_ASYM_PAUSE (1U << 8) /* asym pause request */ #define TXCW_TxConfig (1U << 30) /* Tx Config */ #define TXCW_ANE (1U << 31) /* Autonegotiate */ @@ -739,5 +741,8 @@ #define ICH_GFPREG_BASE_MASK 0x1FFF #define ICH_FLASH_LINEAR_ADDR_MASK 0x00FFFFFF +#define ICH_NVM_SIG_WORD 0x13 +#define ICH_NVM_SIG_MASK 0xc000 + #define NVM_INIT_CONTROL2_REG 0x000f #define NVM_INIT_CTRL2_MNGM 0x6000 Index: src/sys/dev/pci/pcidevs diff -u src/sys/dev/pci/pcidevs:1.962.4.3 src/sys/dev/pci/pcidevs:1.962.4.4 --- src/sys/dev/pci/pcidevs:1.962.4.3 Tue May 5 18:17:57 2009 +++ src/sys/dev/pci/pcidevs Thu May 21 01:13:49 2009 @@ -1,4 +1,4 @@ -$NetBSD: pcidevs,v 1.962.4.3 2009/05/05 18:17:57 bouyer Exp $ +$NetBSD: pcidevs,v 1.962.4.4 2009/05/21 01:13:49 snj Exp $ /* * Copyright (c) 1995, 1996 Christopher G. Demetriou @@ -2210,9 +2210,12 @@ product INTEL 82801H_IFE_GT 0x10c4 i82801H IFE (GT) LAN Controller product INTEL 82801H_IFE_G 0x10c5 i82801H IFE (G) LAN Controller product INTEL 82801H_IGP_M_V 0x10cb i82801H IGP (MV) LAN Controller -product INTEL 82567V 0x10ce i82567V LAN controller +product INTEL 82801J_D_BM_LF 0x10cd i82801J (LF) LAN Controller +product INTEL 82567V 0x10ce i82567V LAN Controller product INTEL 82574L 0x10d3 i82574L 1000baseT Ethernet -product INTEL 82801I_IGP_M_AMT 0x10f5 82801I mobile (AMT) LAN controller +product INTEL 82567LM_3 0x10de i82567LM-3 LAN Controller +product INTEL 82567LF_3 0x10df i82567LF-3 LAN Controller +product INTEL 82801I_IGP_M_AMT 0x10f5 82801I Mobile (AMT) LAN Controller product INTEL 82815_DC100_HUB 0x1100 82815 Hub product INTEL 82815_DC100_AGP 0x1101 82815 AGP product INTEL 82815_DC100_GRAPH 0x1102 82815 Graphics