Module Name: src Committed By: msaitoh Date: Thu Nov 22 15:09:46 UTC 2018
Modified Files: src/sys/dev/mii: inbmphyreg.h src/sys/dev/pci: if_wm.c Log Message: - Add wm_k1_workaround_lv() from FreeBSD. It's PCH2 specifc: 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. To generate a diff of this commit: cvs rdiff -u -r1.11 -r1.12 src/sys/dev/mii/inbmphyreg.h cvs rdiff -u -r1.600 -r1.601 src/sys/dev/pci/if_wm.c 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.11 src/sys/dev/mii/inbmphyreg.h:1.12 --- src/sys/dev/mii/inbmphyreg.h:1.11 Fri Nov 2 03:22:19 2018 +++ src/sys/dev/mii/inbmphyreg.h Thu Nov 22 15:09:45 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: inbmphyreg.h,v 1.11 2018/11/02 03:22:19 msaitoh Exp $ */ +/* $NetBSD: inbmphyreg.h,v 1.12 2018/11/22 15:09:45 msaitoh 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.600 src/sys/dev/pci/if_wm.c:1.601 --- src/sys/dev/pci/if_wm.c:1.600 Tue Nov 20 04:04:42 2018 +++ src/sys/dev/pci/if_wm.c Thu Nov 22 15:09:46 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: if_wm.c,v 1.600 2018/11/20 04:04:42 msaitoh Exp $ */ +/* $NetBSD: if_wm.c,v 1.601 2018/11/22 15:09:46 msaitoh 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.600 2018/11/20 04:04:42 msaitoh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.601 2018/11/22 15:09:46 msaitoh Exp $"); #ifdef _KERNEL_OPT #include "opt_net_mpsafe.h" @@ -974,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 *); @@ -8850,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 @@ -8906,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))); @@ -14528,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) { @@ -14561,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)*/ @@ -14594,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) { @@ -14602,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 */ } /** @@ -14676,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) { @@ -14705,6 +14732,88 @@ wm_k1_gig_workaround_hv(struct wm_softc return 0; } +/* + * wm_k1_gig_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) { @@ -14715,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) {