Module Name: src
Committed By: martin
Date: Tue Dec 4 11:21:33 UTC 2018
Modified Files:
src/sys/dev/mii [netbsd-8]: inbmphyreg.h
src/sys/dev/pci [netbsd-8]: if_wm.c if_wmreg.h
Log Message:
Pull up following revision(s) (requested by msaitoh in ticket #1117):
sys/dev/pci/if_wmreg.h: revision 1.109
sys/dev/pci/if_wm.c: revision 1.597
sys/dev/pci/if_wm.c: revision 1.598
sys/dev/mii/inbmphyreg.h: revision 1.12
sys/dev/pci/if_wm.c: revision 1.600
sys/dev/pci/if_wm.c: revision 1.601
sys/dev/pci/if_wm.c: revision 1.602
- Add new wm_gmii_{hv,i82544}_{read,write}reg_locked() and use them in
wm_gmii_{hv,i82544}_{read,write}reg(). *_locked() functions are not
mii(4) API functions, so it's not required to keep the mii API. Change
the PHY register type from int to uint16_t. It also change the usage of
return value. It returns zero on success and non-zero on error.
- Check the return value of *_locked() function and treat it.
- Use *writereg_locked() function to reduce race condition in
wm_init_lcd_from_nvm().
- Add comment.
- Control TX/RX descriptor snooping control bits on ICH8 and newer.
Only on ICH8, No-snoop bits are opposite polarity. On my Thinkpad X61,
the default value of this bits are all zero, so this commit changes
the snoop function enable on the machine. I tested with some other
PCH machines and those bits are all zero (enable snoop by default),
so this commit won't affect to some machines.
- Disable relax ordering on 82546GB(Device ID 0x1099 and 0x10b5) or >= ICH8.
Same as other OSes.
- Add wm_oem_bits_config_ich8lan() to control LPLU and GbE setting base on
the NVM's info.
- Modify wm_enable_wakeup() to reduce difference against FreeBSD and Linux.
This modification affects to ICH8 and newer devices. I217 Rapid Start
Technology support have not written yet (it's TODO).
- Add wm_k1_workaround_lv() from FreeBSD. It's PCH2 specific:
Workaround to set the K1 beacon duration for 82579 parts in 10Mbps.
Disable K1 for 1000 and 100 speeds.
- Make wm_link_stall_workaround_hv() and move an 82578 specific code into it.
Don't apply the workaround if BMCR_LOOP bit is set. Same as FreeBSD.
- Add comment. Modify comment.
Fix comment. No functional change.
To generate a diff of this commit:
cvs rdiff -u -r1.9.8.2 -r1.9.8.3 src/sys/dev/mii/inbmphyreg.h
cvs rdiff -u -r1.508.4.26 -r1.508.4.27 src/sys/dev/pci/if_wm.c
cvs rdiff -u -r1.98.6.5 -r1.98.6.6 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.9.8.2 src/sys/dev/mii/inbmphyreg.h:1.9.8.3
--- src/sys/dev/mii/inbmphyreg.h:1.9.8.2 Thu Nov 8 12:09:18 2018
+++ src/sys/dev/mii/inbmphyreg.h Tue Dec 4 11:21:32 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: inbmphyreg.h,v 1.9.8.2 2018/11/08 12:09:18 martin Exp $ */
+/* $NetBSD: inbmphyreg.h,v 1.9.8.3 2018/12/04 11:21:32 martin Exp $ */
/*******************************************************************************
Copyright (c) 2001-2005, Intel Corporation
All rights reserved.
@@ -74,6 +74,13 @@ POSSIBILITY OF SUCH DAMAGE.
#define BME1000_PSCR_DOWNSHIFT_COUNTER_MASK 0x7000
#define BME1000_PSCR_DOWNSHIFT_COUNTER_SHIFT 12
+/* BM PHY Copper Specific Status */
+#define BM_CS_STATUS BME1000_REG(0, 17)
+#define BM_CS_STATUS_LINK_UP 0x0400
+#define BM_CS_STATUS_RESOLVED 0x0800
+#define BM_CS_STATUS_SPEED_MASK 0xC000
+#define BM_CS_STATUS_SPEED_1000 0x8000
+
#define BME1000_PHY_PAGE_SELECT BME1000_REG(0, 22) /* Page Select */
#define BME1000_BIAS_SETTING 29
@@ -91,6 +98,14 @@ POSSIBILITY OF SUCH DAMAGE.
#define HV_OEM_BITS_A1KDIS (1 << 6)
#define HV_OEM_BITS_ANEGNOW (1 << 10)
+/* 82577 Mobile Phy Status Register */
+#define HV_M_STATUS BME1000_REG(0, 26)
+#define HV_M_STATUS_AUTONEG_COMPLETE 0x1000
+#define HV_M_STATUS_SPEED_MASK 0x0300
+#define HV_M_STATUS_SPEED_1000 0x0200
+#define HV_M_STATUS_SPEED_100 0x0100
+#define HV_M_STATUS_LINK_UP 0x0040
+
#define HV_LED_CONFIG BME1000_REG(0, 30)
#define HV_KMRN_MODE_CTRL BME1000_REG(BM_PORT_CTRL_PAGE, 16)
Index: src/sys/dev/pci/if_wm.c
diff -u src/sys/dev/pci/if_wm.c:1.508.4.26 src/sys/dev/pci/if_wm.c:1.508.4.27
--- src/sys/dev/pci/if_wm.c:1.508.4.26 Mon Nov 26 17:24:51 2018
+++ src/sys/dev/pci/if_wm.c Tue Dec 4 11:21:32 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: if_wm.c,v 1.508.4.26 2018/11/26 17:24:51 snj Exp $ */
+/* $NetBSD: if_wm.c,v 1.508.4.27 2018/12/04 11:21:32 martin Exp $ */
/*
* Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -83,7 +83,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.508.4.26 2018/11/26 17:24:51 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.508.4.27 2018/12/04 11:21:32 martin Exp $");
#ifdef _KERNEL_OPT
#include "opt_net_mpsafe.h"
@@ -463,6 +463,8 @@ struct wm_queue {
struct wm_phyop {
int (*acquire)(struct wm_softc *);
void (*release)(struct wm_softc *);
+ int (*readreg_locked)(device_t, int, int, uint16_t *);
+ int (*writereg_locked)(device_t, int, int, uint16_t);
int reset_delay_us;
};
@@ -716,8 +718,9 @@ static void wm_get_auto_rd_done(struct w
static void wm_lan_init_done(struct wm_softc *);
static void wm_get_cfg_done(struct wm_softc *);
static void wm_phy_post_reset(struct wm_softc *);
-static void wm_write_smbus_addr(struct wm_softc *);
+static int wm_write_smbus_addr(struct wm_softc *);
static void wm_init_lcd_from_nvm(struct wm_softc *);
+static int wm_oem_bits_config_ich8lan(struct wm_softc *, bool);
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 *);
@@ -819,16 +822,18 @@ static void wm_gmii_i82543_writereg(devi
static int wm_gmii_mdic_readreg(device_t, int, int);
static void wm_gmii_mdic_writereg(device_t, int, int, int);
static int wm_gmii_i82544_readreg(device_t, int, int);
+static int wm_gmii_i82544_readreg_locked(device_t, int, int, uint16_t *);
static void wm_gmii_i82544_writereg(device_t, int, int, int);
+static int wm_gmii_i82544_writereg_locked(device_t, int, int, uint16_t);
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_access_phy_wakeup_reg_bm(device_t, int, int16_t *, int);
static int wm_gmii_hv_readreg(device_t, int, int);
-static int wm_gmii_hv_readreg_locked(device_t, int, int);
+static int wm_gmii_hv_readreg_locked(device_t, int, int, uint16_t *);
static void wm_gmii_hv_writereg(device_t, int, int, int);
-static void wm_gmii_hv_writereg_locked(device_t, int, int, int);
+static int wm_gmii_hv_writereg_locked(device_t, int, int, uint16_t);
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);
@@ -948,9 +953,10 @@ 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 int 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_suspend_workarounds_ich8lan(struct wm_softc *);
static void wm_enable_wakeup(struct wm_softc *);
static void wm_disable_aspm(struct wm_softc *);
/* LPLU (Low Power Link Up) */
@@ -968,6 +974,8 @@ static void wm_hv_phy_workaround_ich8lan
static void wm_lv_phy_workaround_ich8lan(struct wm_softc *);
static int wm_k1_workaround_lpt_lp(struct wm_softc *, bool);
static int wm_k1_gig_workaround_hv(struct wm_softc *, int);
+static int wm_k1_workaround_lv(struct wm_softc *);
+static int wm_link_stall_workaround_hv(struct wm_softc *);
static void wm_set_mdio_slow_mode_hv(struct wm_softc *);
static void wm_configure_k1_ich8lan(struct wm_softc *, int);
static void wm_reset_init_script_82575(struct wm_softc *);
@@ -3826,6 +3834,7 @@ wm_get_cfg_done(struct wm_softc *sc)
else
wm_get_auto_rd_done(sc);
+ /* Clear PHY Reset Asserted bit */
reg = CSR_READ(sc, WMREG_STATUS);
if ((reg & STATUS_PHYRA) != 0)
CSR_WRITE(sc, WMREG_STATUS, reg & ~STATUS_PHYRA);
@@ -3873,7 +3882,8 @@ wm_phy_post_reset(struct wm_softc *sc)
/* Configure the LCD with the extended configuration region in NVM */
wm_init_lcd_from_nvm(sc);
- /* XXX Configure the LCD with the OEM bits in NVM */
+ /* Configure the LCD with the OEM bits in NVM */
+ wm_oem_bits_config_ich8lan(sc, true);
if (sc->sc_type == WM_T_PCH2) {
/* Ungate automatic PHY configuration on non-managed 82579 */
@@ -3886,19 +3896,23 @@ wm_phy_post_reset(struct wm_softc *sc)
}
/* Only for PCH and newer */
-static void
+static int
wm_write_smbus_addr(struct wm_softc *sc)
{
uint32_t strap, freq;
- uint32_t phy_data;
+ uint16_t phy_data;
+ int rv;
DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n",
device_xname(sc->sc_dev), __func__));
+ KASSERT(CSR_READ(sc, WMREG_EXTCNFCTR) & EXTCNFCTR_MDIO_SW_OWNERSHIP);
strap = CSR_READ(sc, WMREG_STRAP);
freq = __SHIFTOUT(strap, STRAP_FREQ);
- phy_data = wm_gmii_hv_readreg_locked(sc->sc_dev, 2, HV_SMB_ADDR);
+ rv = wm_gmii_hv_readreg_locked(sc->sc_dev, 2, HV_SMB_ADDR, &phy_data);
+ if (rv != 0)
+ return -1;
phy_data &= ~HV_SMB_ADDR_ADDR;
phy_data |= __SHIFTOUT(strap, STRAP_SMBUSADDR);
@@ -3920,7 +3934,8 @@ wm_write_smbus_addr(struct wm_softc *sc)
}
}
- wm_gmii_hv_writereg_locked(sc->sc_dev, 2, HV_SMB_ADDR, phy_data);
+ return wm_gmii_hv_writereg_locked(sc->sc_dev, 2, HV_SMB_ADDR,
+ phy_data);
}
void
@@ -4012,9 +4027,8 @@ wm_init_lcd_from_nvm(struct wm_softc *sc
reg_addr &= IGPHY_MAXREGADDR;
reg_addr |= phy_page;
- sc->phy.release(sc); /* XXX */
- sc->sc_mii.mii_writereg(sc->sc_dev, 1, reg_addr, reg_data);
- sc->phy.acquire(sc); /* XXX */
+ KASSERT(sc->phy.writereg_locked != NULL);
+ sc->phy.writereg_locked(sc->sc_dev, 1, reg_addr, reg_data);
}
release:
@@ -4022,6 +4036,72 @@ release:
return;
}
+/*
+ * wm_oem_bits_config_ich8lan - SW-based LCD Configuration
+ * @sc: pointer to the HW structure
+ * @d0_state: boolean if entering d0 or d3 device state
+ *
+ * SW will configure Gbe Disable and LPLU based on the NVM. The four bits are
+ * collectively called OEM bits. The OEM Write Enable bit and SW Config bit
+ * in NVM determines whether HW should configure LPLU and Gbe Disable.
+ */
+int
+wm_oem_bits_config_ich8lan(struct wm_softc *sc, bool d0_state)
+{
+ uint32_t mac_reg;
+ uint16_t oem_reg;
+ int rv;
+
+ if (sc->sc_type < WM_T_PCH)
+ return 0;
+
+ rv = sc->phy.acquire(sc);
+ if (rv != 0)
+ return rv;
+
+ if (sc->sc_type == WM_T_PCH) {
+ mac_reg = CSR_READ(sc, WMREG_EXTCNFCTR);
+ if ((mac_reg & EXTCNFCTR_OEM_WRITE_ENABLE) != 0)
+ goto release;
+ }
+
+ mac_reg = CSR_READ(sc, WMREG_FEXTNVM);
+ if ((mac_reg & FEXTNVM_SW_CONFIG_ICH8M) == 0)
+ goto release;
+
+ mac_reg = CSR_READ(sc, WMREG_PHY_CTRL);
+
+ rv = wm_gmii_hv_readreg_locked(sc->sc_dev, 1, HV_OEM_BITS, &oem_reg);
+ if (rv != 0)
+ goto release;
+ oem_reg &= ~(HV_OEM_BITS_A1KDIS | HV_OEM_BITS_LPLU);
+
+ if (d0_state) {
+ if ((mac_reg & PHY_CTRL_GBE_DIS) != 0)
+ oem_reg |= HV_OEM_BITS_A1KDIS;
+ if ((mac_reg & PHY_CTRL_D0A_LPLU) != 0)
+ oem_reg |= HV_OEM_BITS_LPLU;
+ } else {
+ if ((mac_reg & (PHY_CTRL_GBE_DIS | PHY_CTRL_NOND0A_GBE_DIS))
+ != 0)
+ oem_reg |= HV_OEM_BITS_A1KDIS;
+ if ((mac_reg & (PHY_CTRL_D0A_LPLU | PHY_CTRL_NOND0A_LPLU))
+ != 0)
+ oem_reg |= HV_OEM_BITS_LPLU;
+ }
+
+ /* Set Restart auto-neg to activate the bits */
+ if ((d0_state || (sc->sc_type != WM_T_PCH))
+ && (wm_phy_resetisblocked(sc) == false))
+ oem_reg |= HV_OEM_BITS_ANEGNOW;
+
+ rv = wm_gmii_hv_writereg_locked(sc->sc_dev, 1, HV_OEM_BITS, oem_reg);
+
+release:
+ sc->phy.release(sc);
+
+ return rv;
+}
/* Init hardware bits */
void
@@ -5482,6 +5562,27 @@ wm_init_locked(struct ifnet *ifp)
if (sc->sc_flags & WM_F_HAS_MII)
wm_gmii_reset(sc);
+ if (sc->sc_type >= WM_T_ICH8) {
+ reg = CSR_READ(sc, WMREG_GCR);
+ /*
+ * ICH8 No-snoop bits are opposite polarity. Set to snoop by
+ * default after reset.
+ */
+ if (sc->sc_type == WM_T_ICH8)
+ reg |= GCR_NO_SNOOP_ALL;
+ else
+ reg &= ~GCR_NO_SNOOP_ALL;
+ CSR_WRITE(sc, WMREG_GCR, reg);
+ }
+ if ((sc->sc_type >= WM_T_ICH8)
+ || (sc->sc_pcidevid == PCI_PRODUCT_INTEL_82546GB_QUAD_COPPER)
+ || (sc->sc_pcidevid == PCI_PRODUCT_INTEL_82546GB_QUAD_COPPER_KSP3)) {
+
+ reg = CSR_READ(sc, WMREG_CTRL_EXT);
+ reg |= CTRL_EXT_RO_DIS;
+ CSR_WRITE(sc, WMREG_CTRL_EXT, reg);
+ }
+
/* Calculate (E)ITR value */
if ((sc->sc_flags & WM_F_NEWQUEUE) != 0 && sc->sc_type != WM_T_82575) {
/*
@@ -8751,23 +8852,6 @@ wm_linkintr_gmii(struct wm_softc *sc, ui
((sc->sc_mii.mii_media_status & IFM_ACTIVE) != 0));
}
- if ((sc->sc_phytype == WMPHY_82578)
- && (IFM_SUBTYPE(sc->sc_mii.mii_media_active)
- == IFM_1000_T)) {
-
- if ((sc->sc_mii.mii_media_status & IFM_ACTIVE) != 0) {
- delay(200*1000); /* XXX too big */
-
- /* Link stall fix for link up */
- wm_gmii_hv_writereg(sc->sc_dev, 1,
- HV_MUX_DATA_CTRL,
- HV_MUX_DATA_CTRL_GEN_TO_MAC
- | HV_MUX_DATA_CTRL_FORCE_SPEED);
- wm_gmii_hv_writereg(sc->sc_dev, 1,
- HV_MUX_DATA_CTRL,
- HV_MUX_DATA_CTRL_GEN_TO_MAC);
- }
- }
/*
* I217 Packet Loss issue:
* ensure that FEXTNVM4 Beacon Duration is set correctly
@@ -8807,6 +8891,21 @@ wm_linkintr_gmii(struct wm_softc *sc, ui
reg &= ~FEXTNVM6_K1_OFF_ENABLE;
CSR_WRITE(sc, WMREG_FEXTNVM6, reg);
}
+
+ if (!link)
+ return;
+
+ switch (sc->sc_type) {
+ case WM_T_PCH2:
+ wm_k1_workaround_lv(sc);
+ /* FALLTHROUGH */
+ case WM_T_PCH:
+ if (sc->sc_phytype == WMPHY_82578)
+ wm_link_stall_workaround_hv(sc);
+ break;
+ default:
+ break;
+ }
} else if (icr & ICR_RXSEQ) {
DPRINTF(WM_DEBUG_LINK, ("%s: LINK Receive sequence error\n",
device_xname(sc->sc_dev)));
@@ -9709,6 +9808,13 @@ wm_gmii_setup_phytype(struct wm_softc *s
sc->sc_phytype = new_phytype;
mii->mii_readreg = new_readreg;
mii->mii_writereg = new_writereg;
+ if (new_readreg == wm_gmii_hv_readreg) {
+ sc->phy.readreg_locked = wm_gmii_hv_readreg_locked;
+ sc->phy.writereg_locked = wm_gmii_hv_writereg_locked;
+ } else if (new_readreg == wm_gmii_i82544_readreg) {
+ sc->phy.readreg_locked = wm_gmii_i82544_readreg_locked;
+ sc->phy.writereg_locked = wm_gmii_i82544_writereg_locked;
+ }
}
/*
@@ -10190,13 +10296,25 @@ static int
wm_gmii_i82544_readreg(device_t dev, int phy, int reg)
{
struct wm_softc *sc = device_private(dev);
- int rv;
+ uint16_t val;
if (sc->phy.acquire(sc)) {
device_printf(dev, "%s: failed to get semaphore\n", __func__);
return 0;
}
+ wm_gmii_i82544_readreg_locked(dev, phy, reg, &val);
+
+ sc->phy.release(sc);
+
+ return val;
+}
+
+static int
+wm_gmii_i82544_readreg_locked(device_t dev, int phy, int reg, uint16_t *val)
+{
+ struct wm_softc *sc = device_private(dev);
+
if (reg > BME1000_MAX_MULTI_PAGE_REG) {
switch (sc->sc_phytype) {
case WMPHY_IGP:
@@ -10214,10 +10332,9 @@ wm_gmii_i82544_readreg(device_t dev, int
}
}
- rv = wm_gmii_mdic_readreg(dev, phy, reg & MII_ADDRMASK);
- sc->phy.release(sc);
+ *val = wm_gmii_mdic_readreg(dev, phy, reg & MII_ADDRMASK);
- return rv;
+ return 0;
}
/*
@@ -10235,6 +10352,15 @@ wm_gmii_i82544_writereg(device_t dev, in
return;
}
+ wm_gmii_i82544_writereg_locked(dev, phy, reg & MII_ADDRMASK, val);
+ sc->phy.release(sc);
+}
+
+static int
+wm_gmii_i82544_writereg_locked(device_t dev, int phy, int reg, uint16_t val)
+{
+ struct wm_softc *sc = device_private(dev);
+
if (reg > BME1000_MAX_MULTI_PAGE_REG) {
switch (sc->sc_phytype) {
case WMPHY_IGP:
@@ -10253,7 +10379,8 @@ wm_gmii_i82544_writereg(device_t dev, in
}
wm_gmii_mdic_writereg(dev, phy, reg & MII_ADDRMASK, val);
- sc->phy.release(sc);
+
+ return 0;
}
/*
@@ -10523,7 +10650,7 @@ static int
wm_gmii_hv_readreg(device_t dev, int phy, int reg)
{
struct wm_softc *sc = device_private(dev);
- int rv;
+ uint16_t val;
DPRINTF(WM_DEBUG_GMII, ("%s: %s called\n",
device_xname(dev), __func__));
@@ -10532,25 +10659,23 @@ wm_gmii_hv_readreg(device_t dev, int phy
return 0;
}
- rv = wm_gmii_hv_readreg_locked(dev, phy, reg);
+ wm_gmii_hv_readreg_locked(dev, phy, reg, &val);
sc->phy.release(sc);
- return rv;
+ return val;
}
static int
-wm_gmii_hv_readreg_locked(device_t dev, int phy, int reg)
+wm_gmii_hv_readreg_locked(device_t dev, int phy, int reg, uint16_t *val)
{
uint16_t page = BM_PHY_REG_PAGE(reg);
uint16_t regnum = BM_PHY_REG_NUM(reg);
- uint16_t val;
- int rv;
phy = (page >= HV_INTC_FC_PAGE_START) ? 1 : phy;
/* Page 800 works differently than the rest so it has its own func */
if (page == BM_WUC_PAGE) {
- wm_access_phy_wakeup_reg_bm(dev, reg, &val, 1);
- return val;
+ wm_access_phy_wakeup_reg_bm(dev, reg, val, 1);
+ return 0;
}
/*
@@ -10574,8 +10699,8 @@ wm_gmii_hv_readreg_locked(device_t dev,
page << BME1000_PAGE_SHIFT);
}
- rv = wm_gmii_mdic_readreg(dev, phy, regnum & MII_ADDRMASK);
- return rv;
+ *val = wm_gmii_mdic_readreg(dev, phy, regnum & MII_ADDRMASK);
+ return 0;
}
/*
@@ -10602,8 +10727,8 @@ wm_gmii_hv_writereg(device_t dev, int ph
sc->phy.release(sc);
}
-static void
-wm_gmii_hv_writereg_locked(device_t dev, int phy, int reg, int val)
+static int
+wm_gmii_hv_writereg_locked(device_t dev, int phy, int reg, uint16_t val)
{
struct wm_softc *sc = device_private(dev);
uint16_t page = BM_PHY_REG_PAGE(reg);
@@ -10617,7 +10742,7 @@ wm_gmii_hv_writereg_locked(device_t dev,
tmp = val;
wm_access_phy_wakeup_reg_bm(dev, reg, &tmp, 0);
- return;
+ return 0;
}
/*
@@ -10626,7 +10751,7 @@ wm_gmii_hv_writereg_locked(device_t dev,
*/
if ((page > 0) && (page < HV_INTC_FC_PAGE_START)) {
printf("gmii_hv_writereg!!!\n");
- return;
+ return -1;
}
{
@@ -10660,6 +10785,8 @@ wm_gmii_hv_writereg_locked(device_t dev,
}
wm_gmii_mdic_writereg(dev, phy, regnum & MII_ADDRMASK, val);
+
+ return 0;
}
/*
@@ -13899,11 +14026,12 @@ wm_get_wakeup(struct wm_softc *sc)
* Unconfigure Ultra Low Power mode.
* Only for I217 and newer (see below).
*/
-static void
+static int
wm_ulp_disable(struct wm_softc *sc)
{
uint32_t reg;
- int i = 0;
+ uint16_t phyreg;
+ int i = 0, rv = 0;
DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n",
device_xname(sc->sc_dev), __func__));
@@ -13913,7 +14041,7 @@ wm_ulp_disable(struct wm_softc *sc)
|| (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;
+ return 0;
if ((CSR_READ(sc, WMREG_FWSM) & FWSM_FW_VALID) != 0) {
/* Request ME un-configure ULP mode in the PHY */
@@ -13926,7 +14054,7 @@ wm_ulp_disable(struct wm_softc *sc)
while ((CSR_READ(sc, WMREG_FWSM) & FWSM_ULP_CFG_DONE) != 0) {
if (i++ == 30) {
printf("%s timed out\n", __func__);
- return;
+ return -1;
}
delay(10 * 1000);
}
@@ -13934,7 +14062,7 @@ wm_ulp_disable(struct wm_softc *sc)
reg &= ~H2ME_ENFORCE_SETTINGS;
CSR_WRITE(sc, WMREG_H2ME, reg);
- return;
+ return 0;
}
/* Acquire semaphore */
@@ -13944,8 +14072,8 @@ wm_ulp_disable(struct wm_softc *sc)
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) {
+ rv = wm_gmii_hv_readreg_locked(sc->sc_dev, 2, CV_SMB_CTRL, &phyreg);
+ if (rv != 0) {
uint32_t reg2;
printf("%s: Force SMBus first.\n", __func__);
@@ -13954,22 +14082,30 @@ wm_ulp_disable(struct wm_softc *sc)
CSR_WRITE(sc, WMREG_CTRL_EXT, reg2);
delay(50 * 1000);
- reg = wm_gmii_hv_readreg_locked(sc->sc_dev, 2, CV_SMB_CTRL);
+ rv = wm_gmii_hv_readreg_locked(sc->sc_dev, 2, CV_SMB_CTRL,
+ &phyreg);
+ if (rv != 0)
+ goto release;
}
- reg &= ~CV_SMB_CTRL_FORCE_SMBUS;
- wm_gmii_hv_writereg_locked(sc->sc_dev, 2, CV_SMB_CTRL, reg);
+ phyreg &= ~CV_SMB_CTRL_FORCE_SMBUS;
+ wm_gmii_hv_writereg_locked(sc->sc_dev, 2, CV_SMB_CTRL, phyreg);
/* 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);
+ rv = wm_gmii_hv_readreg_locked(sc->sc_dev, 2, HV_PM_CTRL, &phyreg);
+ if (rv != 0)
+ goto release;
+ phyreg |= HV_PM_CTRL_K1_ENA;
+ wm_gmii_hv_writereg_locked(sc->sc_dev, 2, HV_PM_CTRL, phyreg);
- reg = wm_gmii_hv_readreg_locked(sc->sc_dev, 2, I218_ULP_CONFIG1);
- reg &= ~(I218_ULP_CONFIG1_IND
+ rv = wm_gmii_hv_readreg_locked(sc->sc_dev, 2, I218_ULP_CONFIG1,
+ &phyreg);
+ if (rv != 0)
+ goto release;
+ phyreg &= ~(I218_ULP_CONFIG1_IND
| I218_ULP_CONFIG1_STICKY_ULP
| I218_ULP_CONFIG1_RESET_TO_SMBUS
| I218_ULP_CONFIG1_WOL_HOST
@@ -13977,18 +14113,21 @@ wm_ulp_disable(struct wm_softc *sc)
| 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);
+ wm_gmii_hv_writereg_locked(sc->sc_dev, 2, I218_ULP_CONFIG1, phyreg);
+ phyreg |= I218_ULP_CONFIG1_START;
+ wm_gmii_hv_writereg_locked(sc->sc_dev, 2, I218_ULP_CONFIG1, phyreg);
reg = CSR_READ(sc, WMREG_FEXTNVM7);
reg &= ~FEXTNVM7_DIS_SMB_PERST;
CSR_WRITE(sc, WMREG_FEXTNVM7, reg);
+release:
/* Release semaphore */
sc->phy.release(sc);
wm_gmii_reset(sc);
delay(50 * 1000);
+
+ return rv;
}
/* WOL in the newer chipset interfaces (pchlan) */
@@ -14051,6 +14190,85 @@ wm_igp3_phy_powerdown_workaround_ich8lan
}
}
+/*
+ * e1000_suspend_workarounds_ich8lan - workarounds needed during S0->Sx
+ * @sc: pointer to the HW structure
+ *
+ * During S0 to Sx transition, it is possible the link remains at gig
+ * instead of negotiating to a lower speed. Before going to Sx, set
+ * 'Gig Disable' to force link speed negotiation to a lower speed based on
+ * the LPLU setting in the NVM or custom setting. For PCH and newer parts,
+ * the OEM bits PHY register (LED, GbE disable and LPLU configurations) also
+ * needs to be written.
+ * Parts that support (and are linked to a partner which support) EEE in
+ * 100Mbps should disable LPLU since 100Mbps w/ EEE requires less power
+ * than 10Mbps w/o EEE.
+ */
+static void
+wm_suspend_workarounds_ich8lan(struct wm_softc *sc)
+{
+ uint32_t phy_ctrl;
+
+ phy_ctrl = CSR_READ(sc, WMREG_PHY_CTRL);
+ phy_ctrl |= PHY_CTRL_GBE_DIS;
+
+ if (sc->sc_phytype == WMPHY_I217) {
+ uint16_t devid = sc->sc_pcidevid;
+
+ if ((devid == PCI_PRODUCT_INTEL_I218_LM) ||
+ (devid == PCI_PRODUCT_INTEL_I218_V) ||
+ (devid == PCI_PRODUCT_INTEL_I218_LM3) ||
+ (devid == PCI_PRODUCT_INTEL_I218_V3) ||
+ (sc->sc_type >= WM_T_PCH_SPT))
+ CSR_WRITE(sc, WMREG_FEXTNVM6,
+ CSR_READ(sc, WMREG_FEXTNVM6)
+ & ~FEXTNVM6_REQ_PLL_CLK);
+
+#if 0 /* notyet */
+ if (sc->phy.acquire(sc) != 0)
+ goto out;
+
+ /* XXX Do workaround for EEE */
+
+ /*
+ * For i217 Intel Rapid Start Technology support,
+ * when the system is going into Sx and no manageability engine
+ * is present, the driver must configure proxy to reset only on
+ * power good. LPI (Low Power Idle) state must also reset only
+ * on power good, as well as the MTA (Multicast table array).
+ * The SMBus release must also be disabled on LCD reset.
+ */
+
+ /*
+ * Enable MTA to reset for Intel Rapid Start Technology
+ * Support
+ */
+
+ sc->phy.release(sc);
+#endif
+ }
+#if 0
+out:
+#endif
+ CSR_WRITE(sc, WMREG_PHY_CTRL, phy_ctrl);
+
+ if (sc->sc_type == WM_T_ICH8)
+ wm_gig_downshift_workaround_ich8lan(sc);
+
+ if (sc->sc_type >= WM_T_PCH) {
+ wm_oem_bits_config_ich8lan(sc, false);
+
+ /* Reset PHY to activate OEM bits on 82577/8 */
+ if (sc->sc_type == WM_T_PCH)
+ wm_reset_phy(sc);
+
+ if (sc->phy.acquire(sc) != 0)
+ return;
+ wm_write_smbus_addr(sc);
+ sc->phy.release(sc);
+ }
+}
+
static void
wm_enable_wakeup(struct wm_softc *sc)
{
@@ -14069,38 +14287,6 @@ wm_enable_wakeup(struct wm_softc *sc)
| CTRL_SWDPIN(3));
CSR_WRITE(sc, WMREG_WUC, WUC_APME);
- /* ICH workaround */
- switch (sc->sc_type) {
- case WM_T_ICH8:
- case WM_T_ICH9:
- case WM_T_ICH10:
- case WM_T_PCH:
- case WM_T_PCH2:
- case WM_T_PCH_LPT:
- case WM_T_PCH_SPT:
- case WM_T_PCH_CNP:
- /* Disable gig during WOL */
- reg = CSR_READ(sc, WMREG_PHY_CTRL);
- reg |= PHY_CTRL_D0A_LPLU | PHY_CTRL_GBE_DIS;
- CSR_WRITE(sc, WMREG_PHY_CTRL, reg);
- if (sc->sc_type == WM_T_PCH)
- wm_gmii_reset(sc);
-
- /* Power down workaround */
- if (sc->sc_phytype == WMPHY_82577) {
- struct mii_softc *child;
-
- /* Assume that the PHY is copper */
- child = LIST_FIRST(&sc->sc_mii.mii_phys);
- if ((child != NULL) && (child->mii_mpd_rev <= 2))
- sc->sc_mii.mii_writereg(sc->sc_dev, 1,
- (768 << 5) | 25, 0x0444); /* magic num */
- }
- break;
- default:
- break;
- }
-
/* Keep the laser running on fiber adapters */
if ((sc->sc_mediatype == WM_MEDIATYPE_FIBER)
|| (sc->sc_mediatype == WM_MEDIATYPE_SERDES)) {
@@ -14109,6 +14295,10 @@ wm_enable_wakeup(struct wm_softc *sc)
CSR_WRITE(sc, WMREG_CTRL_EXT, reg);
}
+ if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9) ||
+ (sc->sc_type == WM_T_ICH10) || (sc->sc_type == WM_T_PCH))
+ wm_suspend_workarounds_ich8lan(sc);
+
reg = CSR_READ(sc, WMREG_WUFC) | WUFC_MAG;
#if 0 /* for the multicast packet */
reg |= WUFC_MC;
@@ -14118,6 +14308,7 @@ wm_enable_wakeup(struct wm_softc *sc)
if (sc->sc_type >= WM_T_PCH)
wm_enable_phy_wakeup(sc);
else {
+ /* Enable wakeup by the MAC */
CSR_WRITE(sc, WMREG_WUC, CSR_READ(sc, WMREG_WUC) | WUC_PME_EN);
CSR_WRITE(sc, WMREG_WUFC, reg);
}
@@ -14337,7 +14528,16 @@ out:
return;
}
-/* WOL from S5 stops working */
+/*
+ * wm_gig_downshift_workaround_ich8lan - WoL from S5 stops working
+ * @sc: pointer to the HW structure
+ *
+ * Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC),
+ * LPLU, Gig disable, MDIC PHY reset):
+ * 1) Set Kumeran Near-end loopback
+ * 2) Clear Kumeran Near-end loopback
+ * Should only be called for ICH8[m] devices with any 1G Phy.
+ */
static void
wm_gig_downshift_workaround_ich8lan(struct wm_softc *sc)
{
@@ -14370,7 +14570,7 @@ wm_hv_phy_workaround_ich8lan(struct wm_s
if (sc->sc_phytype == WMPHY_82577)
wm_set_mdio_slow_mode_hv(sc);
- /* (PCH rev.2) && (82577 && (phy rev 2 or 3)) */
+ /* XXX (PCH rev.2) && (82577 && (phy rev 2 or 3)) */
/* (82577 && (phy rev 1 or 2)) || (82578 & phy rev 1)*/
@@ -14403,6 +14603,10 @@ wm_hv_phy_workaround_ich8lan(struct wm_s
wm_k1_gig_workaround_hv(sc, 1);
}
+/*
+ * wm_lv_phy_workarounds_ich8lan - A series of Phy workarounds to be
+ * done after every PHY reset.
+ */
static void
wm_lv_phy_workaround_ich8lan(struct wm_softc *sc)
{
@@ -14411,7 +14615,11 @@ wm_lv_phy_workaround_ich8lan(struct wm_s
device_xname(sc->sc_dev), __func__));
KASSERT(sc->sc_type == WM_T_PCH2);
+ /* Set MDIO slow mode before any other MDIO access */
wm_set_mdio_slow_mode_hv(sc);
+
+ /* XXX set MSE higher to enable link to stay up when noise is high */
+ /* XXX drop link after 5 times MSE threshold was reached */
}
/**
@@ -14485,6 +14693,16 @@ update_fextnvm6:
return 0;
}
+/*
+ * wm_k1_gig_workaround_hv - K1 Si workaround
+ * @sc: pointer to the HW structure
+ * @link: link up bool flag
+ *
+ * If K1 is enabled for 1Gbps, the MAC might stall when transitioning
+ * from a lower speed. This workaround disables K1 whenever link is at 1Gig
+ * If link is down, the function will restore the default K1 setting located
+ * in the NVM.
+ */
static int
wm_k1_gig_workaround_hv(struct wm_softc *sc, int link)
{
@@ -14514,6 +14732,88 @@ wm_k1_gig_workaround_hv(struct wm_softc
return 0;
}
+/*
+ * wm_k1_workaround_lv - K1 Si workaround
+ * @sc: pointer to the HW structure
+ *
+ * Workaround to set the K1 beacon duration for 82579 parts in 10Mbps
+ * Disable K1 for 1000 and 100 speeds
+ */
+static int
+wm_k1_workaround_lv(struct wm_softc *sc)
+{
+ uint32_t reg;
+ int phyreg;
+
+ if (sc->sc_type != WM_T_PCH2)
+ return 0;
+
+ /* Set K1 beacon duration based on 10Mbps speed */
+ phyreg = wm_gmii_hv_readreg(sc->sc_dev, 2, HV_M_STATUS);
+
+ if ((phyreg & (HV_M_STATUS_LINK_UP | HV_M_STATUS_AUTONEG_COMPLETE))
+ == (HV_M_STATUS_LINK_UP | HV_M_STATUS_AUTONEG_COMPLETE)) {
+ if (phyreg &
+ (HV_M_STATUS_SPEED_1000 | HV_M_STATUS_SPEED_100)) {
+ /* LV 1G/100 Packet drop issue wa */
+ phyreg = wm_gmii_hv_readreg(sc->sc_dev, 1, HV_PM_CTRL);
+ phyreg &= ~HV_PM_CTRL_K1_ENA;
+ wm_gmii_hv_writereg(sc->sc_dev, 1, HV_PM_CTRL, phyreg);
+ } else {
+ /* For 10Mbps */
+ reg = CSR_READ(sc, WMREG_FEXTNVM4);
+ reg &= ~FEXTNVM4_BEACON_DURATION;
+ reg |= FEXTNVM4_BEACON_DURATION_16US;
+ CSR_WRITE(sc, WMREG_FEXTNVM4, reg);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * wm_link_stall_workaround_hv - Si workaround
+ * @sc: pointer to the HW structure
+ *
+ * This function works around a Si bug where the link partner can get
+ * a link up indication before the PHY does. If small packets are sent
+ * by the link partner they can be placed in the packet buffer without
+ * being properly accounted for by the PHY and will stall preventing
+ * further packets from being received. The workaround is to clear the
+ * packet buffer after the PHY detects link up.
+ */
+static int
+wm_link_stall_workaround_hv(struct wm_softc *sc)
+{
+ int phyreg;
+
+ if (sc->sc_phytype != WMPHY_82578)
+ return 0;
+
+ /* Do not apply workaround if in PHY loopback bit 14 set */
+ phyreg = wm_gmii_hv_readreg(sc->sc_dev, 2, MII_BMCR);
+ if ((phyreg & BMCR_LOOP) != 0)
+ return 0;
+
+ /* check if link is up and at 1Gbps */
+ phyreg = wm_gmii_hv_readreg(sc->sc_dev, 2, BM_CS_STATUS);
+ phyreg &= BM_CS_STATUS_LINK_UP | BM_CS_STATUS_RESOLVED
+ | BM_CS_STATUS_SPEED_MASK;
+ if (phyreg != (BM_CS_STATUS_LINK_UP | BM_CS_STATUS_RESOLVED
+ | BM_CS_STATUS_SPEED_1000))
+ return 0;
+
+ delay(200 * 1000); /* XXX too big */
+
+ /* flush the packets in the fifo buffer */
+ wm_gmii_hv_writereg(sc->sc_dev, 1, HV_MUX_DATA_CTRL,
+ HV_MUX_DATA_CTRL_GEN_TO_MAC | HV_MUX_DATA_CTRL_FORCE_SPEED);
+ wm_gmii_hv_writereg(sc->sc_dev, 1, HV_MUX_DATA_CTRL,
+ HV_MUX_DATA_CTRL_GEN_TO_MAC);
+
+ return 0;
+}
+
static void
wm_set_mdio_slow_mode_hv(struct wm_softc *sc)
{
@@ -14524,6 +14824,14 @@ wm_set_mdio_slow_mode_hv(struct wm_softc
reg | HV_KMRN_MDIO_SLOW);
}
+/*
+ * wm_configure_k1_ich8lan - Configure K1 power state
+ * @sc: pointer to the HW structure
+ * @enable: K1 state to configure
+ *
+ * Configure the K1 power state based on the provided parameter.
+ * Assumes semaphore already acquired.
+ */
static void
wm_configure_k1_ich8lan(struct wm_softc *sc, int k1_enable)
{
@@ -14531,6 +14839,8 @@ wm_configure_k1_ich8lan(struct wm_softc
uint16_t kmreg;
int rv;
+ KASSERT(CSR_READ(sc, WMREG_EXTCNFCTR) & EXTCNFCTR_MDIO_SW_OWNERSHIP);
+
rv = wm_kmrn_readreg_locked(sc, KUMCTRLSTA_OFFSET_K1_CONFIG, &kmreg);
if (rv != 0)
return;
@@ -14629,25 +14939,33 @@ wm_reset_mdicnfg_82580(struct wm_softc *
static bool
wm_phy_is_accessible_pchlan(struct wm_softc *sc)
{
- int i;
uint32_t reg;
uint16_t id1, id2;
+ int i, rv;
DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n",
device_xname(sc->sc_dev), __func__));
+ KASSERT(CSR_READ(sc, WMREG_EXTCNFCTR) & EXTCNFCTR_MDIO_SW_OWNERSHIP);
+
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))
+ rv = wm_gmii_hv_readreg_locked(sc->sc_dev, 2, MII_PHYIDR1,
+ &id1);
+ if ((rv != 0) || MII_INVALIDID(id1))
continue;
- id2 = wm_gmii_hv_readreg_locked(sc->sc_dev, 2, MII_PHYIDR2);
- if (MII_INVALIDID(id2))
+ rv = wm_gmii_hv_readreg_locked(sc->sc_dev, 2, MII_PHYIDR2,
+ &id2);
+ if ((rv != 0) || MII_INVALIDID(id2))
continue;
break;
}
if (!MII_INVALIDID(id1) && !MII_INVALIDID(id2))
goto out;
+ /*
+ * In case the PHY needs to be in mdio slow mode,
+ * set slow mode and try to get the PHY id again.
+ */
if (sc->sc_type < WM_T_PCH_LPT) {
sc->phy.release(sc);
wm_set_mdio_slow_mode_hv(sc);
@@ -14663,12 +14981,14 @@ out:
if (sc->sc_type >= WM_T_PCH_LPT) {
/* Only unforce SMBus if ME is not active */
if ((CSR_READ(sc, WMREG_FWSM) & FWSM_FW_VALID) == 0) {
+ uint16_t phyreg;
+
/* Unforce SMBus mode in PHY */
- reg = wm_gmii_hv_readreg_locked(sc->sc_dev, 2,
- CV_SMB_CTRL);
- reg &= ~CV_SMB_CTRL_FORCE_SMBUS;
+ rv = wm_gmii_hv_readreg_locked(sc->sc_dev, 2,
+ CV_SMB_CTRL, &phyreg);
+ phyreg &= ~CV_SMB_CTRL_FORCE_SMBUS;
wm_gmii_hv_writereg_locked(sc->sc_dev, 2,
- CV_SMB_CTRL, reg);
+ CV_SMB_CTRL, phyreg);
/* Unforce SMBus mode in MAC */
reg = CSR_READ(sc, WMREG_CTRL_EXT);
Index: src/sys/dev/pci/if_wmreg.h
diff -u src/sys/dev/pci/if_wmreg.h:1.98.6.5 src/sys/dev/pci/if_wmreg.h:1.98.6.6
--- src/sys/dev/pci/if_wmreg.h:1.98.6.5 Thu Nov 8 12:09:18 2018
+++ src/sys/dev/pci/if_wmreg.h Tue Dec 4 11:21:32 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: if_wmreg.h,v 1.98.6.5 2018/11/08 12:09:18 martin Exp $ */
+/* $NetBSD: if_wmreg.h,v 1.98.6.6 2018/12/04 11:21:32 martin Exp $ */
/*
* Copyright (c) 2001 Wasabi Systems, Inc.
@@ -1282,6 +1282,12 @@ struct livengood_tcpip_ctxdesc {
#define GCR_CMPL_TMOUT_RESEND 0x00010000
#define GCR_CAP_VER2 0x00040000
#define GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000
+#define GCR_NO_SNOOP_ALL (GCR_RXD_NO_SNOOP | \
+ GCR_RXDSCW_NO_SNOOP | \
+ GCR_RXDSCR_NO_SNOOP | \
+ GCR_TXD_NO_SNOOP | \
+ GCR_TXDSCW_NO_SNOOP | \
+ GCR_TXDSCR_NO_SNOOP)
#define WMREG_FACTPS 0x5b30 /* Function Active and Power State to MNG */
#define FACTPS_MNGCG 0x20000000