Module Name: src Committed By: msaitoh Date: Sat Jun 6 04:39:12 UTC 2015
Modified Files: src/sys/dev/pci: if_wm.c if_wmreg.h if_wmvar.h Log Message: - Add workaround for I210 Errata 25 and I211 Errata 10. - Add wm_gmii_gs40g_{read|write}reg() and use it to access non-standatrd page. - Add wm_pll_workaround_i210() and call it when chip is i211 chip is i210 and it use INVM chip is i210 and NVM image version < 3.25 - Add comment - Rename macros. To generate a diff of this commit: cvs rdiff -u -r1.328 -r1.329 src/sys/dev/pci/if_wm.c cvs rdiff -u -r1.76 -r1.77 src/sys/dev/pci/if_wmreg.h cvs rdiff -u -r1.28 -r1.29 src/sys/dev/pci/if_wmvar.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/pci/if_wm.c diff -u src/sys/dev/pci/if_wm.c:1.328 src/sys/dev/pci/if_wm.c:1.329 --- src/sys/dev/pci/if_wm.c:1.328 Sat Jun 6 03:38:40 2015 +++ src/sys/dev/pci/if_wm.c Sat Jun 6 04:39:12 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: if_wm.c,v 1.328 2015/06/06 03:38:40 msaitoh Exp $ */ +/* $NetBSD: if_wm.c,v 1.329 2015/06/06 04:39:12 msaitoh Exp $ */ /* * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc. @@ -81,7 +81,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.328 2015/06/06 03:38:40 msaitoh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.329 2015/06/06 04:39:12 msaitoh Exp $"); #ifdef _KERNEL_OPT #include "opt_net_mpsafe.h" @@ -628,6 +628,8 @@ static int wm_gmii_hv_readreg(device_t, static void wm_gmii_hv_writereg(device_t, int, int, int); static int wm_gmii_82580_readreg(device_t, int, int); static void wm_gmii_82580_writereg(device_t, int, int, int); +static int wm_gmii_gs40g_readreg(device_t, int, int); +static void wm_gmii_gs40g_writereg(device_t, int, int, int); static void wm_gmii_statchg(struct ifnet *); static int wm_kmrn_readreg(struct wm_softc *, int); static void wm_kmrn_writereg(struct wm_softc *, int, int); @@ -739,6 +741,7 @@ 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 void wm_pll_workaround_i210(struct wm_softc *); CFATTACH_DECL3_NEW(wm, sizeof(struct wm_softc), wm_match, wm_attach, wm_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN); @@ -1942,6 +1945,25 @@ wm_attach(device_t parent, device_t self wm_nvm_version(sc); aprint_verbose("\n"); + /* Check for I21[01] PLL workaround */ + if (sc->sc_type == WM_T_I210) + sc->sc_flags |= WM_F_PLL_WA_I210; + if ((sc->sc_type == WM_T_I210) && wm_nvm_get_flash_presence_i210(sc)) { + /* NVM image release 3.25 has a workaround */ + if ((sc->sc_nvm_ver_major > 3) + || ((sc->sc_nvm_ver_major == 3) + && (sc->sc_nvm_ver_minor >= 25))) + return; + else { + aprint_verbose_dev(sc->sc_dev, + "ROM image version %d.%d is older than 3.25\n", + sc->sc_nvm_ver_major, sc->sc_nvm_ver_minor); + sc->sc_flags |= WM_F_PLL_WA_I210; + } + } + if ((sc->sc_flags & WM_F_PLL_WA_I210) != 0) + wm_pll_workaround_i210(sc); + switch (sc->sc_type) { case WM_T_82571: case WM_T_82572: @@ -6636,19 +6658,24 @@ wm_gmii_mediainit(struct wm_softc *sc, p default: if (((sc->sc_flags & WM_F_SGMII) != 0) && !wm_sgmii_uses_mdio(sc)){ + /* SGMII */ mii->mii_readreg = wm_sgmii_readreg; mii->mii_writereg = wm_sgmii_writereg; } else if (sc->sc_type >= WM_T_80003) { + /* 80003 */ mii->mii_readreg = wm_gmii_i80003_readreg; mii->mii_writereg = wm_gmii_i80003_writereg; } else if (sc->sc_type >= WM_T_I210) { - mii->mii_readreg = wm_gmii_i82544_readreg; - mii->mii_writereg = wm_gmii_i82544_writereg; + /* I210 and I211 */ + mii->mii_readreg = wm_gmii_gs40g_readreg; + mii->mii_writereg = wm_gmii_gs40g_writereg; } else if (sc->sc_type >= WM_T_82580) { + /* 82580, I350 and I354 */ sc->sc_phytype = WMPHY_82580; mii->mii_readreg = wm_gmii_82580_readreg; mii->mii_writereg = wm_gmii_82580_writereg; } else if (sc->sc_type >= WM_T_82544) { + /* 82544, 0, [56], [17], 8257[1234] and 82583 */ mii->mii_readreg = wm_gmii_i82544_readreg; mii->mii_writereg = wm_gmii_i82544_writereg; } else { @@ -7358,6 +7385,75 @@ wm_gmii_82580_writereg(device_t self, in } /* + * wm_gmii_gs40g_readreg: [mii interface function] + * + * Read a PHY register on the I2100 and I211. + * This could be handled by the PHY layer if we didn't have to lock the + * ressource ... + */ +static int +wm_gmii_gs40g_readreg(device_t self, int phy, int reg) +{ + struct wm_softc *sc = device_private(self); + int sem; + int page, offset; + int rv; + + /* Acquire semaphore */ + sem = swfwphysem[sc->sc_funcid]; + if (wm_get_swfw_semaphore(sc, sem)) { + aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", + __func__); + return 0; + } + + /* Page select */ + page = reg >> GS40G_PAGE_SHIFT; + wm_gmii_i82544_writereg(self, phy, GS40G_PAGE_SELECT, page); + + /* Read reg */ + offset = reg & GS40G_OFFSET_MASK; + rv = wm_gmii_i82544_readreg(self, phy, offset); + + wm_put_swfw_semaphore(sc, sem); + return rv; +} + +/* + * wm_gmii_gs40g_writereg: [mii interface function] + * + * Write a PHY register on the I210 and I211. + * This could be handled by the PHY layer if we didn't have to lock the + * ressource ... + */ +static void +wm_gmii_gs40g_writereg(device_t self, int phy, int reg, int val) +{ + struct wm_softc *sc = device_private(self); + int sem; + int page, offset; + + /* Acquire semaphore */ + sem = swfwphysem[sc->sc_funcid]; + if (wm_get_swfw_semaphore(sc, sem)) { + aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", + __func__); + return; + } + + /* Page select */ + page = reg >> GS40G_PAGE_SHIFT; + wm_gmii_i82544_writereg(self, phy, GS40G_PAGE_SELECT, page); + + /* Write reg */ + offset = reg & GS40G_OFFSET_MASK; + wm_gmii_i82544_writereg(self, phy, offset, val); + + /* Release semaphore */ + wm_put_swfw_semaphore(sc, sem); +} + +/* * wm_gmii_statchg: [mii interface function] * * Callback from MII layer when media changes. @@ -8904,7 +9000,7 @@ wm_nvm_read_word_invm(struct wm_softc *s uint8_t record_type, word_address; for (i = 0; i < INVM_SIZE; i++) { - invm_dword = CSR_READ(sc, E1000_INVM_DATA_REG(i)); + invm_dword = CSR_READ(sc, WM_INVM_DATA_REG(i)); /* Get record type */ record_type = INVM_DWORD_TO_RECORD_TYPE(invm_dword); if (record_type == INVM_UNINITIALIZED_STRUCTURE) @@ -9415,11 +9511,11 @@ wm_get_swfwhw_semaphore(struct wm_softc for (timeout = 0; timeout < 200; timeout++) { ext_ctrl = CSR_READ(sc, WMREG_EXTCNFCTR); - ext_ctrl |= E1000_EXTCNF_CTRL_SWFLAG; + ext_ctrl |= EXTCNFCTR_MDIO_SW_OWNERSHIP; CSR_WRITE(sc, WMREG_EXTCNFCTR, ext_ctrl); ext_ctrl = CSR_READ(sc, WMREG_EXTCNFCTR); - if (ext_ctrl & E1000_EXTCNF_CTRL_SWFLAG) + if (ext_ctrl & EXTCNFCTR_MDIO_SW_OWNERSHIP) return 0; delay(5000); } @@ -9433,7 +9529,7 @@ wm_put_swfwhw_semaphore(struct wm_softc { uint32_t ext_ctrl; ext_ctrl = CSR_READ(sc, WMREG_EXTCNFCTR); - ext_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; + ext_ctrl &= ~EXTCNFCTR_MDIO_SW_OWNERSHIP; CSR_WRITE(sc, WMREG_EXTCNFCTR, ext_ctrl); } @@ -10226,3 +10322,78 @@ wm_reset_mdicnfg_82580(struct wm_softc * reg |= MDICNFG_COM_MDIO; CSR_WRITE(sc, WMREG_MDICNFG, reg); } + +/* + * I210 Errata 25 and I211 Errata 10 + * Slow System Clock. + */ +static void +wm_pll_workaround_i210(struct wm_softc *sc) +{ + uint32_t mdicnfg, wuc; + uint32_t reg; + pcireg_t pcireg; + uint32_t pmreg; + uint16_t nvmword, tmp_nvmword; + int phyval; + bool wa_done = false; + int i; + + /* Save WUC and MDICNFG registers */ + wuc = CSR_READ(sc, WMREG_WUC); + mdicnfg = CSR_READ(sc, WMREG_MDICNFG); + + reg = mdicnfg & ~MDICNFG_DEST; + CSR_WRITE(sc, WMREG_MDICNFG, reg); + + if (wm_nvm_read(sc, INVM_AUTOLOAD, 1, &nvmword) != 0) + nvmword = INVM_DEFAULT_AL; + tmp_nvmword = nvmword | INVM_PLL_WO_VAL; + + /* Get Power Management cap offset */ + if (pci_get_capability(sc->sc_pc, sc->sc_pcitag, PCI_CAP_PWRMGMT, + &pmreg, NULL) == 0) + return; + for (i = 0; i < WM_MAX_PLL_TRIES; i++) { + phyval = wm_gmii_gs40g_readreg(sc->sc_dev, 1, + GS40G_PHY_PLL_FREQ_PAGE | GS40G_PHY_PLL_FREQ_REG); + + if ((phyval & GS40G_PHY_PLL_UNCONF) != GS40G_PHY_PLL_UNCONF) { + break; /* OK */ + } + + wa_done = true; + /* Directly reset the internal PHY */ + reg = CSR_READ(sc, WMREG_CTRL); + CSR_WRITE(sc, WMREG_CTRL, reg | CTRL_PHY_RESET); + + reg = CSR_READ(sc, WMREG_CTRL_EXT); + reg |= CTRL_EXT_PHYPDEN | CTRL_EXT_SDLPE; + CSR_WRITE(sc, WMREG_CTRL_EXT, reg); + + CSR_WRITE(sc, WMREG_WUC, 0); + reg = (INVM_AUTOLOAD << 4) | (tmp_nvmword << 16); + CSR_WRITE(sc, WMREG_EEARBC_I210, reg); + + pcireg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, + pmreg + PCI_PMCSR); + pcireg |= PCI_PMCSR_STATE_D3; + pci_conf_write(sc->sc_pc, sc->sc_pcitag, + pmreg + PCI_PMCSR, pcireg); + delay(1000); + pcireg &= ~PCI_PMCSR_STATE_D3; + pci_conf_write(sc->sc_pc, sc->sc_pcitag, + pmreg + PCI_PMCSR, pcireg); + + reg = (INVM_AUTOLOAD << 4) | (nvmword << 16); + CSR_WRITE(sc, WMREG_EEARBC_I210, reg); + + /* Restore WUC register */ + CSR_WRITE(sc, WMREG_WUC, wuc); + } + + /* Restore MDICNFG setting */ + CSR_WRITE(sc, WMREG_MDICNFG, mdicnfg); + if (wa_done) + aprint_verbose_dev(sc->sc_dev, "I210 workaround done\n"); +} Index: src/sys/dev/pci/if_wmreg.h diff -u src/sys/dev/pci/if_wmreg.h:1.76 src/sys/dev/pci/if_wmreg.h:1.77 --- src/sys/dev/pci/if_wmreg.h:1.76 Sat Jun 6 03:38:40 2015 +++ src/sys/dev/pci/if_wmreg.h Sat Jun 6 04:39:12 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: if_wmreg.h,v 1.76 2015/06/06 03:38:40 msaitoh Exp $ */ +/* $NetBSD: if_wmreg.h,v 1.77 2015/06/06 04:39:12 msaitoh Exp $ */ /* * Copyright (c) 2001 Wasabi Systems, Inc. @@ -315,6 +315,7 @@ struct livengood_tcpip_ctxdesc { #define CTRL_EXT_SPD_BYPS (1U << 15) /* speed select bypass */ #define CTRL_EXT_IPS1 (1U << 16) /* invert power state bit 1 */ #define CTRL_EXT_RO_DIS (1U << 17) /* relaxed ordering disabled */ +#define CTRL_EXT_SDLPE (1U << 18) /* SerDes Low Power Enable */ #define CTRL_EXT_DMA_DYN_CLK (1U << 19) /* DMA Dynamic Gating Enable */ #define CTRL_EXT_LINK_MODE_MASK 0x00C00000 #define CTRL_EXT_LINK_MODE_GMII 0x00000000 @@ -653,7 +654,6 @@ struct livengood_tcpip_ctxdesc { #define EXTCNFCTR_MDIO_HW_OWNERSHIP 0x00000040 #define EXTCNFCTR_GATE_PHY_CFG 0x00000080 #define EXTCNFCTR_EXT_CNF_POINTER 0x0FFF0000 -#define E1000_EXTCNF_CTRL_SWFLAG EXTCNFCTR_MDIO_SW_OWNERSHIP #define WMREG_PHY_CTRL 0x0f10 /* PHY control */ #define PHY_CTRL_SPD_EN (1 << 0) @@ -918,6 +918,7 @@ struct livengood_tcpip_ctxdesc { #define EEC_FLASH_DETECTED (1U << 19) /* FLASH */ #define EEC_FLUPD (1U << 23) /* Update FLASH */ +#define WMREG_EEARBC_I210 0x12024 /* * NVM related values. @@ -1041,7 +1042,7 @@ struct livengood_tcpip_ctxdesc { #define NVM_UID_VALID 0x8000 /* iNVM Registers for i21[01] */ -#define E1000_INVM_DATA_REG(reg) (0x12120 + 4*(reg)) +#define WM_INVM_DATA_REG(reg) (0x12120 + 4*(reg)) #define INVM_SIZE 64 /* Number of INVM Data Registers */ /* iNVM default vaule */ @@ -1060,11 +1061,15 @@ struct livengood_tcpip_ctxdesc { #define INVM_CSR_AUTOLOAD_STRUCTURE 0x2 #define INVM_PHY_REGISTER_AUTOLOAD_STRUCTURE 0x3 #define INVM_RSA_KEY_SHA256_STRUCTURE 0x4 -#define INVM_INVALIDATED_STRUCTURE 0x5 +#define INVM_INVALIDATED_STRUCTURE 0xf #define INVM_RSA_KEY_SHA256_DATA_SIZE_IN_DWORDS 8 #define INVM_CSR_AUTOLOAD_DATA_SIZE_IN_DWORDS 1 +#define INVM_DEFAULT_AL 0x202f +#define INVM_AUTOLOAD 0x0a +#define INVM_PLL_WO_VAL 0x0010 + /* Word definitions for ID LED Settings */ #define ID_LED_RESERVED_FFFF 0xFFFF @@ -1138,6 +1143,13 @@ struct livengood_tcpip_ctxdesc { #define SFF_SFP_ETH_FLAGS_1000T 0x08 #define SFF_SFP_ETH_FLAGS_100FX 0x10 +/* I21[01] PHY related definitions */ +#define GS40G_PAGE_SELECT 0x16 +#define GS40G_PAGE_SHIFT 16 +#define GS40G_OFFSET_MASK 0xffff +#define GS40G_PHY_PLL_FREQ_PAGE 0xfc0000 +#define GS40G_PHY_PLL_FREQ_REG 0x000e +#define GS40G_PHY_PLL_UNCONF 0xff /* advanced TX descriptor for 82575 and newer */ typedef union nq_txdesc { Index: src/sys/dev/pci/if_wmvar.h diff -u src/sys/dev/pci/if_wmvar.h:1.28 src/sys/dev/pci/if_wmvar.h:1.29 --- src/sys/dev/pci/if_wmvar.h:1.28 Sat Jun 6 03:38:40 2015 +++ src/sys/dev/pci/if_wmvar.h Sat Jun 6 04:39:12 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: if_wmvar.h,v 1.28 2015/06/06 03:38:40 msaitoh Exp $ */ +/* $NetBSD: if_wmvar.h,v 1.29 2015/06/06 04:39:12 msaitoh Exp $ */ /* * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc. @@ -98,7 +98,7 @@ #define WM_F_ATTACHED 0x00800000 /* attach() finished successfully */ #define WM_F_EEPROM_INVM 0x01000000 /* NVM is iNVM */ #define WM_F_PCS_DIS_AUTONEGO 0x02000000 /* PCS Disable Autonego */ - +#define WM_F_PLL_WA_I210 0x04000000 /* I21[01] PLL workaround */ /* * Variations of Intel gigabit Ethernet controller: