Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/pci - Add workaround for I210 Errata 25 and I211 Err...
details: https://anonhg.NetBSD.org/src/rev/727ae0d5a3b2
branches: trunk
changeset: 338731:727ae0d5a3b2
user: msaitoh <msaitoh%NetBSD.org@localhost>
date: Sat Jun 06 04:39:12 2015 +0000
description:
- 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.
diffstat:
sys/dev/pci/if_wm.c | 187 ++++++++++++++++++++++++++++++++++++++++++++++--
sys/dev/pci/if_wmreg.h | 20 ++++-
sys/dev/pci/if_wmvar.h | 4 +-
3 files changed, 197 insertions(+), 14 deletions(-)
diffs (truncated from 366 to 300 lines):
diff -r 18b6b6e0600d -r 727ae0d5a3b2 sys/dev/pci/if_wm.c
--- a/sys/dev/pci/if_wm.c Sat Jun 06 04:38:52 2015 +0000
+++ b/sys/dev/pci/if_wm.c Sat Jun 06 04:39:12 2015 +0000
@@ -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 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_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_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 @@
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_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 @@
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 @@
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 @@
{
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 @@
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");
+}
diff -r 18b6b6e0600d -r 727ae0d5a3b2 sys/dev/pci/if_wmreg.h
--- a/sys/dev/pci/if_wmreg.h Sat Jun 06 04:38:52 2015 +0000
+++ b/sys/dev/pci/if_wmreg.h Sat Jun 06 04:39:12 2015 +0000
@@ -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 @@
#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 @@
#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)
Home |
Main Index |
Thread Index |
Old Index