Module Name: src Committed By: msaitoh Date: Wed Nov 16 08:56:17 UTC 2016
Modified Files: src/sys/dev/mii: inbmphyreg.h src/sys/dev/pci: if_wm.c if_wmreg.h Log Message: Sync wm_smbustopci() with Linux and FreeBSD. This change effects PCH and newer devices. To generate a diff of this commit: cvs rdiff -u -r1.8 -r1.9 src/sys/dev/mii/inbmphyreg.h cvs rdiff -u -r1.446 -r1.447 src/sys/dev/pci/if_wm.c cvs rdiff -u -r1.92 -r1.93 src/sys/dev/pci/if_wmreg.h 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/mii/inbmphyreg.h diff -u src/sys/dev/mii/inbmphyreg.h:1.8 src/sys/dev/mii/inbmphyreg.h:1.9 --- src/sys/dev/mii/inbmphyreg.h:1.8 Tue Nov 8 10:37:39 2016 +++ src/sys/dev/mii/inbmphyreg.h Wed Nov 16 08:56:17 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: inbmphyreg.h,v 1.8 2016/11/08 10:37:39 msaitoh Exp $ */ +/* $NetBSD: inbmphyreg.h,v 1.9 2016/11/16 08:56:17 msaitoh Exp $ */ /******************************************************************************* Copyright (c) 2001-2005, Intel Corporation All rights reserved. @@ -96,6 +96,12 @@ POSSIBILITY OF SUCH DAMAGE. #define BM_PORT_GEN_CFG BME1000_REG(BM_PORT_CTRL_PAGE, 17) +#define CV_SMB_CTRL BME1000_REG(BM_PORT_CTRL_PAGE, 23) +#define CV_SMB_CTRL_FORCE_SMBUS __BIT(0) + +#define HV_PM_CTRL BME1000_REG(770, 17) +#define HV_PM_CTRL_K1_ENA __BIT(14) + #define IGP3_KMRN_DIAG BME1000_REG(770, 19) #define IGP3_KMRN_DIAG_PCS_LOCK_LOSS (1 << 1) @@ -103,6 +109,17 @@ POSSIBILITY OF SUCH DAMAGE. #define HV_MUX_DATA_CTRL_FORCE_SPEED (1 << 2) #define HV_MUX_DATA_CTRL_GEN_TO_MAC (1 << 10) +#define I218_ULP_CONFIG1 BME1000_REG(779, 16) +#define I218_ULP_CONFIG1_START __BIT(0) +#define I218_ULP_CONFIG1_IND __BIT(2) +#define I218_ULP_CONFIG1_STICKY_ULP __BIT(4) +#define I218_ULP_CONFIG1_INBAND_EXIT __BIT(5) +#define I218_ULP_CONFIG1_WOL_HOST __BIT(6) +#define I218_ULP_CONFIG1_RESET_TO_SMBUS __BIT(8) +#define I218_ULP_CONFIG1_EN_ULP_LANPHYPC __BIT(10) +#define I218_ULP_CONFIG1_DIS_CLR_STICKY_ON_PERST __BIT(11) +#define I218_ULP_CONFIG1_DIS_SMB_PERST __BIT(12) + #define BM_WUC_PAGE 800 #define BM_WUC BME1000_REG(BM_WUC_PAGE, 1) #define BM_WUC_ADDRESS_OPCODE 0x11 Index: src/sys/dev/pci/if_wm.c diff -u src/sys/dev/pci/if_wm.c:1.446 src/sys/dev/pci/if_wm.c:1.447 --- src/sys/dev/pci/if_wm.c:1.446 Wed Nov 16 08:14:39 2016 +++ src/sys/dev/pci/if_wm.c Wed Nov 16 08:56:17 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: if_wm.c,v 1.446 2016/11/16 08:14:39 msaitoh Exp $ */ +/* $NetBSD: if_wm.c,v 1.447 2016/11/16 08:56:17 msaitoh Exp $ */ /* * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc. @@ -84,7 +84,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.446 2016/11/16 08:14:39 msaitoh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.447 2016/11/16 08:56:17 msaitoh Exp $"); #ifdef _KERNEL_OPT #include "opt_net_mpsafe.h" @@ -396,6 +396,7 @@ struct wm_queue { struct wm_phyop { int (*acquire)(struct wm_softc *); void (*release)(struct wm_softc *); + int reset_delay_us; }; /* @@ -637,6 +638,7 @@ static void wm_lan_init_done(struct wm_s static void wm_get_cfg_done(struct wm_softc *); static void wm_initialize_hardware_bits(struct wm_softc *); static uint32_t wm_rxpbs_adjust_82580(uint32_t); +static void wm_reset_phy(struct wm_softc *); static void wm_flush_desc_rings(struct wm_softc *); static void wm_reset(struct wm_softc *); static int wm_add_rxbuf(struct wm_rxqueue *, int); @@ -840,6 +842,7 @@ static void wm_smbustopci(struct wm_soft static void wm_init_manageability(struct wm_softc *); static void wm_release_manageability(struct wm_softc *); static void wm_get_wakeup(struct wm_softc *); +static void wm_ulp_disable(struct wm_softc *); static void wm_enable_phy_wakeup(struct wm_softc *); static void wm_igp3_phy_powerdown_workaround_ich8lan(struct wm_softc *); static void wm_enable_wakeup(struct wm_softc *); @@ -862,6 +865,8 @@ static void wm_set_mdio_slow_mode_hv(str static void wm_configure_k1_ich8lan(struct wm_softc *, int); static void wm_reset_init_script_82575(struct wm_softc *); static void wm_reset_mdicnfg_82580(struct wm_softc *); +static bool wm_phy_is_accessible_pchlan(struct wm_softc *); +static void wm_toggle_lanphypc_pch_lpt(struct wm_softc *); static int wm_platform_pm_pch_lpt(struct wm_softc *, bool); static void wm_pll_workaround_i210(struct wm_softc *); @@ -1630,6 +1635,7 @@ wm_attach(device_t parent, device_t self /* Set default function pointers */ sc->phy.acquire = wm_get_null; sc->phy.release = wm_put_null; + sc->phy.reset_delay_us = (sc->sc_type >= WM_T_82571) ? 100 : 10000; if (sc->sc_type < WM_T_82543) { if (sc->sc_rev < 2) { @@ -3727,6 +3733,40 @@ wm_rxpbs_adjust_82580(uint32_t val) return rv; } +/* + * wm_reset_phy: + * + * generic PHY reset function. + * Same as e1000_phy_hw_reset_generic() + */ +static void +wm_reset_phy(struct wm_softc *sc) +{ + uint32_t reg; + + DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n", + device_xname(sc->sc_dev), __func__)); + if (wm_phy_resetisblocked(sc)) + return; + + sc->phy.acquire(sc); + + reg = CSR_READ(sc, WMREG_CTRL); + CSR_WRITE(sc, WMREG_CTRL, reg | CTRL_PHY_RESET); + CSR_WRITE_FLUSH(sc); + + delay(sc->phy.reset_delay_us); + + CSR_WRITE(sc, WMREG_CTRL, reg); + CSR_WRITE_FLUSH(sc); + + delay(150); + + sc->phy.release(sc); + + wm_get_cfg_done(sc); +} + static void wm_flush_desc_rings(struct wm_softc *sc) { @@ -11902,6 +11942,7 @@ static void wm_smbustopci(struct wm_softc *sc) { uint32_t fwsm, reg; + int rv = 0; DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n", device_xname(sc->sc_dev), __func__)); @@ -11909,46 +11950,82 @@ wm_smbustopci(struct wm_softc *sc) /* Gate automatic PHY configuration by hardware on non-managed 82579 */ wm_gate_hw_phy_config_ich8lan(sc, true); + /* Disable ULP */ + wm_ulp_disable(sc); + /* Acquire PHY semaphore */ sc->phy.acquire(sc); fwsm = CSR_READ(sc, WMREG_FWSM); - if (((fwsm & FWSM_FW_VALID) == 0) - && ((wm_phy_resetisblocked(sc) == false))) { - if (sc->sc_type >= WM_T_PCH_LPT) { - reg = CSR_READ(sc, WMREG_CTRL_EXT); - reg |= CTRL_EXT_FORCE_SMBUS; - CSR_WRITE(sc, WMREG_CTRL_EXT, reg); - CSR_WRITE_FLUSH(sc); - delay(50*1000); - } + switch (sc->sc_type) { + case WM_T_PCH_LPT: + case WM_T_PCH_SPT: + if (wm_phy_is_accessible_pchlan(sc)) + break; - /* Toggle LANPHYPC */ - sc->sc_ctrl |= CTRL_LANPHYPC_OVERRIDE; - sc->sc_ctrl &= ~CTRL_LANPHYPC_VALUE; - CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl); - CSR_WRITE_FLUSH(sc); - delay(1000); - sc->sc_ctrl &= ~CTRL_LANPHYPC_OVERRIDE; - CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl); + reg = CSR_READ(sc, WMREG_CTRL_EXT); + reg |= CTRL_EXT_FORCE_SMBUS; + CSR_WRITE(sc, WMREG_CTRL_EXT, reg); +#if 0 + /* XXX Isn't this required??? */ CSR_WRITE_FLUSH(sc); - delay(50*1000); +#endif + delay(50 * 1000); + /* FALLTHROUGH */ + case WM_T_PCH2: + if (wm_phy_is_accessible_pchlan(sc) == true) + break; + /* FALLTHROUGH */ + case WM_T_PCH: + if ((sc->sc_type == WM_T_PCH)) + if ((fwsm & FWSM_FW_VALID) != 0) + break; + + if (wm_phy_resetisblocked(sc) == true) { + printf("XXX reset is blocked(3)\n"); + break; + } + + wm_toggle_lanphypc_pch_lpt(sc); if (sc->sc_type >= WM_T_PCH_LPT) { + if (wm_phy_is_accessible_pchlan(sc) == true) + break; + reg = CSR_READ(sc, WMREG_CTRL_EXT); reg &= ~CTRL_EXT_FORCE_SMBUS; CSR_WRITE(sc, WMREG_CTRL_EXT, reg); + + if (wm_phy_is_accessible_pchlan(sc) == true) + break; + rv = -1; } + break; + default: + break; } /* Release semaphore */ sc->phy.release(sc); + if (rv == 0) { + if (wm_phy_resetisblocked(sc)) { + printf("XXX reset is blocked(4)\n"); + goto out; + } + wm_reset_phy(sc); + if (wm_phy_resetisblocked(sc)) + printf("XXX reset is blocked(4)\n"); + } + +out: /* * Ungate automatic PHY configuration by hardware on non-managed 82579 */ - if ((sc->sc_type == WM_T_PCH2) && ((fwsm & FWSM_FW_VALID) == 0)) + if ((sc->sc_type == WM_T_PCH2) && ((fwsm & FWSM_FW_VALID) == 0)) { + delay(10*1000); wm_gate_hw_phy_config_ich8lan(sc, false); + } } static void @@ -12051,6 +12128,102 @@ wm_get_wakeup(struct wm_softc *sc) */ } +/* + * Unconfigure Ultra Low Power mode. + * Only for I217 and newer (see below). + */ +static void +wm_ulp_disable(struct wm_softc *sc) +{ + uint32_t reg; + int i = 0; + + DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n", + device_xname(sc->sc_dev), __func__)); + /* Exclude old devices */ + if ((sc->sc_type < WM_T_PCH_LPT) + || (sc->sc_pcidevid == PCI_PRODUCT_INTEL_I217_LM) + || (sc->sc_pcidevid == PCI_PRODUCT_INTEL_I217_V) + || (sc->sc_pcidevid == PCI_PRODUCT_INTEL_I218_LM2) + || (sc->sc_pcidevid == PCI_PRODUCT_INTEL_I218_V2)) + return; + + if ((CSR_READ(sc, WMREG_FWSM) & FWSM_FW_VALID) != 0) { + /* Request ME un-configure ULP mode in the PHY */ + reg = CSR_READ(sc, WMREG_H2ME); + reg &= ~H2ME_ULP; + reg |= H2ME_ENFORCE_SETTINGS; + CSR_WRITE(sc, WMREG_H2ME, reg); + + /* Poll up to 300msec for ME to clear ULP_CFG_DONE. */ + while ((CSR_READ(sc, WMREG_FWSM) & FWSM_ULP_CFG_DONE) != 0) { + if (i++ == 30) { + printf("%s timed out\n", __func__); + return; + } + delay(10 * 1000); + } + reg = CSR_READ(sc, WMREG_H2ME); + reg &= ~H2ME_ENFORCE_SETTINGS; + CSR_WRITE(sc, WMREG_H2ME, reg); + + return; + } + + /* Acquire semaphore */ + sc->phy.acquire(sc); + + /* Toggle LANPHYPC */ + wm_toggle_lanphypc_pch_lpt(sc); + + /* Unforce SMBus mode in PHY */ + reg = wm_gmii_hv_readreg_locked(sc->sc_dev, 2, CV_SMB_CTRL); + if (reg == 0x0000 || reg == 0xffff) { + uint32_t reg2; + + printf("%s: Force SMBus first.\n", __func__); + reg2 = CSR_READ(sc, WMREG_CTRL_EXT); + reg2 |= CTRL_EXT_FORCE_SMBUS; + CSR_WRITE(sc, WMREG_CTRL_EXT, reg2); + delay(50 * 1000); + + reg = wm_gmii_hv_readreg_locked(sc->sc_dev, 2, CV_SMB_CTRL); + } + reg &= ~CV_SMB_CTRL_FORCE_SMBUS; + wm_gmii_hv_writereg_locked(sc->sc_dev, 2, CV_SMB_CTRL, reg); + + /* Unforce SMBus mode in MAC */ + reg = CSR_READ(sc, WMREG_CTRL_EXT); + reg &= ~CTRL_EXT_FORCE_SMBUS; + CSR_WRITE(sc, WMREG_CTRL_EXT, reg); + + reg = wm_gmii_hv_readreg_locked(sc->sc_dev, 2, HV_PM_CTRL); + reg |= HV_PM_CTRL_K1_ENA; + wm_gmii_hv_writereg_locked(sc->sc_dev, 2, HV_PM_CTRL, reg); + + reg = wm_gmii_hv_readreg_locked(sc->sc_dev, 2, I218_ULP_CONFIG1); + reg &= ~(I218_ULP_CONFIG1_IND + | I218_ULP_CONFIG1_STICKY_ULP + | I218_ULP_CONFIG1_RESET_TO_SMBUS + | I218_ULP_CONFIG1_WOL_HOST + | I218_ULP_CONFIG1_INBAND_EXIT + | I218_ULP_CONFIG1_EN_ULP_LANPHYPC + | I218_ULP_CONFIG1_DIS_CLR_STICKY_ON_PERST + | I218_ULP_CONFIG1_DIS_SMB_PERST); + wm_gmii_hv_writereg_locked(sc->sc_dev, 2, I218_ULP_CONFIG1, reg); + reg |= I218_ULP_CONFIG1_START; + wm_gmii_hv_writereg_locked(sc->sc_dev, 2, I218_ULP_CONFIG1, reg); + + reg = CSR_READ(sc, WMREG_FEXTNVM7); + reg &= ~FEXTNVM7_DIS_SMB_PERST; + CSR_WRITE(sc, WMREG_FEXTNVM7, reg); + + /* Release semaphore */ + sc->phy.release(sc); + wm_gmii_reset(sc); + delay(50 * 1000); +} + /* WOL in the newer chipset interfaces (pchlan) */ static void wm_enable_phy_wakeup(struct wm_softc *sc) @@ -12511,6 +12684,99 @@ wm_reset_mdicnfg_82580(struct wm_softc * CSR_WRITE(sc, WMREG_MDICNFG, reg); } +#define MII_INVALIDID(x) (((x) == 0x0000) || ((x) == 0xffff)) + +static bool +wm_phy_is_accessible_pchlan(struct wm_softc *sc) +{ + int i; + uint32_t reg; + uint16_t id1, id2; + + DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n", + device_xname(sc->sc_dev), __func__)); + id1 = id2 = 0xffff; + for (i = 0; i < 2; i++) { + id1 = wm_gmii_hv_readreg_locked(sc->sc_dev, 2, MII_PHYIDR1); + if (MII_INVALIDID(id1)) + continue; + id2 = wm_gmii_hv_readreg_locked(sc->sc_dev, 2, MII_PHYIDR2); + if (MII_INVALIDID(id2)) + continue; + break; + } + if (!MII_INVALIDID(id1) && !MII_INVALIDID(id2)) { + goto out; + } + + if (sc->sc_type < WM_T_PCH_LPT) { + sc->phy.release(sc); + wm_set_mdio_slow_mode_hv(sc); + id1 = wm_gmii_hv_readreg(sc->sc_dev, 2, MII_PHYIDR1); + id2 = wm_gmii_hv_readreg(sc->sc_dev, 2, MII_PHYIDR2); + sc->phy.acquire(sc); + } + if (MII_INVALIDID(id1) || MII_INVALIDID(id2)) { + printf("XXX return with false\n"); + return false; + } +out: + if ((sc->sc_type == WM_T_PCH_LPT) || (sc->sc_type == WM_T_PCH_SPT)) { + /* Only unforce SMBus if ME is not active */ + if ((CSR_READ(sc, WMREG_FWSM) & FWSM_FW_VALID) == 0) { + /* Unforce SMBus mode in PHY */ + reg = wm_gmii_hv_readreg_locked(sc->sc_dev, 2, + CV_SMB_CTRL); + reg &= ~CV_SMB_CTRL_FORCE_SMBUS; + wm_gmii_hv_writereg_locked(sc->sc_dev, 2, + CV_SMB_CTRL, reg); + + /* Unforce SMBus mode in MAC */ + reg = CSR_READ(sc, WMREG_CTRL_EXT); + reg &= ~CTRL_EXT_FORCE_SMBUS; + CSR_WRITE(sc, WMREG_CTRL_EXT, reg); + } + } + return true; +} + +static void +wm_toggle_lanphypc_pch_lpt(struct wm_softc *sc) +{ + uint32_t reg; + int i; + + /* Set PHY Config Counter to 50msec */ + reg = CSR_READ(sc, WMREG_FEXTNVM3); + reg &= ~FEXTNVM3_PHY_CFG_COUNTER_MASK; + reg |= FEXTNVM3_PHY_CFG_COUNTER_50MS; + CSR_WRITE(sc, WMREG_FEXTNVM3, reg); + + /* Toggle LANPHYPC */ + reg = CSR_READ(sc, WMREG_CTRL); + reg |= CTRL_LANPHYPC_OVERRIDE; + reg &= ~CTRL_LANPHYPC_VALUE; + CSR_WRITE(sc, WMREG_CTRL, reg); + CSR_WRITE_FLUSH(sc); + delay(1000); + reg &= ~CTRL_LANPHYPC_OVERRIDE; + CSR_WRITE(sc, WMREG_CTRL, reg); + CSR_WRITE_FLUSH(sc); + + if (sc->sc_type < WM_T_PCH_LPT) + delay(50 * 1000); + else { + i = 20; + + do { + delay(5 * 1000); + } while (((CSR_READ(sc, WMREG_CTRL_EXT) & CTRL_EXT_LPCD) == 0) + && i--); + + delay(30 * 1000); + } +} + static int wm_platform_pm_pch_lpt(struct wm_softc *sc, bool link) { Index: src/sys/dev/pci/if_wmreg.h diff -u src/sys/dev/pci/if_wmreg.h:1.92 src/sys/dev/pci/if_wmreg.h:1.93 --- src/sys/dev/pci/if_wmreg.h:1.92 Wed Nov 16 07:24:52 2016 +++ src/sys/dev/pci/if_wmreg.h Wed Nov 16 08:56:17 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: if_wmreg.h,v 1.92 2016/11/16 07:24:52 msaitoh Exp $ */ +/* $NetBSD: if_wmreg.h,v 1.93 2016/11/16 08:56:17 msaitoh Exp $ */ /* * Copyright (c) 2001 Wasabi Systems, Inc. @@ -317,6 +317,7 @@ struct livengood_tcpip_ctxdesc { #define CTRL_EXT_NSICR __BIT(0) /* Non Interrupt clear on read */ #define CTRL_EXT_GPI_EN(x) (1U << (x)) /* gpin interrupt enable */ #define CTRL_EXT_NVMVS __BITS(0, 1) /* NVM valid sector */ +#define CTRL_EXT_LPCD __BIT(2) /* LCD Power Cycle Done */ #define CTRL_EXT_SWDPINS_SHIFT 4 #define CTRL_EXT_SWDPINS_MASK 0x0d /* The bit order of the SW Definable pin is not 6543 but 3654! */ @@ -423,6 +424,11 @@ struct livengood_tcpip_ctxdesc { #define WMREG_VET 0x0038 /* VLAN Ethertype */ #define WMREG_MDPHYA 0x003C /* PHY address - RW */ + +#define WMREG_FEXTNVM3 0x003c /* Future Extended NVM 3 */ +#define FEXTNVM3_PHY_CFG_COUNTER_MASK __BITS(27, 26) +#define FEXTNVM3_PHY_CFG_COUNTER_50MS __BIT(27) + #define WMREG_RAL_BASE 0x0040 /* Receive Address List */ #define WMREG_CORDOVA_RAL_BASE 0x5400 #define WMREG_RAL_LO(b, x) ((b) + ((x) << 3)) @@ -479,6 +485,11 @@ struct livengood_tcpip_ctxdesc { #define WMREG_EIAC_82574_MSIX_MASK (ICR_RXQ(0) | ICR_RXQ(1) \ | ICR_TXQ(0) | ICR_TXQ(1) | ICR_OTHER) +#define WMREG_FEXTNVM7 0x00e4 /* Future Extended NVM 7 */ +#define FEXTNVM7_SIDE_CLK_UNGATE __BIT(2) +#define FEXTNVM7_DIS_SMB_PERST __BIT(5) +#define FEXTNVM7_DIS_PB_READ __BIT(18) + #define WMREG_IVAR 0x00e4 /* Interrupt Vector Allocation Register */ #define WMREG_IVAR0 0x01700 /* Interrupt Vector Allocation */ #define IVAR_ALLOC_MASK __BITS(0, 6) /* Bit 5 and 6 are reserved */ @@ -1035,6 +1046,10 @@ struct livengood_tcpip_ctxdesc { #define SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */ #define SWSM_WMNG 0x00000004 /* Wake MNG Clock */ #define SWSM_DRV_LOAD 0x00000008 /* Driver Loaded Bit */ +/* Intel driver defines H2ME register at 0x5b50 */ +#define WMREG_H2ME 0x5b50 /* SW Semaphore */ +#define H2ME_ULP __BIT(11) +#define H2ME_ENFORCE_SETTINGS __BIT(12) #define WMREG_FWSM 0x5b54 /* FW Semaphore */ #define FWSM_MODE __BITS(1, 3) @@ -1042,6 +1057,7 @@ struct livengood_tcpip_ctxdesc { #define MNG_IAMT_MODE 0x3 #define FWSM_RSPCIPHY __BIT(6) /* Reset PHY on PCI reset */ #define FWSM_WLOCK_MAC __BITS(7, 9) /* Reset PHY on PCI reset */ +#define FWSM_ULP_CFG_DONE __BIT(10) #define FWSM_FW_VALID __BIT(15) /* FW established a valid mode */ #define WMREG_SWSM2 0x5b58 /* SW Semaphore 2 */