- Make new wm_phy_post_reset() and use this function at all location after

reseting phy.
- Move the location of calling wm_get_hw_control. Same as Linux.
- Add I219 specific wokaround for legacy interrupt. From OpenBSD.
- Move the location of calling wm_lplu_d0_disable().
- Fix latency calculation in wm_platform_pm_pch_lpt().
- Set OBFF water mark and enable OBFF on PCH_LPT and newer.
This commit is contained in:
msaitoh 2017-06-26 04:22:46 +00:00
parent f99b415579
commit 14a58cc1cc
2 changed files with 144 additions and 67 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_wm.c,v 1.516 2017/06/26 04:18:14 msaitoh Exp $ */
/* $NetBSD: if_wm.c,v 1.517 2017/06/26 04:22:46 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.516 2017/06/26 04:18:14 msaitoh Exp $");
__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.517 2017/06/26 04:22:46 msaitoh Exp $");
#ifdef _KERNEL_OPT
#include "opt_net_mpsafe.h"
@ -679,6 +679,7 @@ static void wm_set_pcie_completion_timeout(struct wm_softc *);
static void wm_get_auto_rd_done(struct wm_softc *);
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_initialize_hardware_bits(struct wm_softc *);
static uint32_t wm_rxpbs_adjust_82580(uint32_t);
static void wm_reset_phy(struct wm_softc *);
@ -930,6 +931,7 @@ 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 *);
static void wm_legacy_irq_quirk_spt(struct wm_softc *);
CFATTACH_DECL3_NEW(wm, sizeof(struct wm_softc),
wm_match, wm_attach, wm_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN);
@ -3659,6 +3661,47 @@ wm_get_cfg_done(struct wm_softc *sc)
}
}
void
wm_phy_post_reset(struct wm_softc *sc)
{
uint32_t reg;
/* This function is only for ICH8 and newer. */
if (sc->sc_type < WM_T_ICH8)
return;
if (wm_phy_resetisblocked(sc)) {
/* XXX */
device_printf(sc->sc_dev, " PHY is blocked\n");
return;
}
/* Allow time for h/w to get to quiescent state after reset */
delay(10*1000);
/* Perform any necessary post-reset workarounds */
if (sc->sc_type == WM_T_PCH)
wm_hv_phy_workaround_ich8lan(sc);
if (sc->sc_type == WM_T_PCH2)
wm_lv_phy_workaround_ich8lan(sc);
/* Clear the host wakeup bit after lcd reset */
if (sc->sc_type >= WM_T_PCH) {
reg = wm_gmii_hv_readreg(sc->sc_dev, 2,
BM_PORT_GEN_CFG);
reg &= ~BM_WUC_HOST_WU_BIT;
wm_gmii_hv_writereg(sc->sc_dev, 2,
BM_PORT_GEN_CFG, reg);
}
/*
* XXX Configure the LCD with th extended configuration region
* in NVM
*/
/* Configure the LCD with the OEM bits in NVM */
}
/* Init hardware bits */
void
wm_initialize_hardware_bits(struct wm_softc *sc)
@ -3938,6 +3981,7 @@ wm_reset_phy(struct wm_softc *sc)
sc->phy.release(sc);
wm_get_cfg_done(sc);
wm_phy_post_reset(sc);
}
static void
@ -4371,6 +4415,9 @@ wm_reset(struct wm_softc *sc)
break;
}
if (phy_reset != 0)
wm_phy_post_reset(sc);
if ((sc->sc_type == WM_T_82580)
|| (sc->sc_type == WM_T_I350) || (sc->sc_type == WM_T_I354)) {
/* clear global device reset status bit */
@ -4403,15 +4450,6 @@ wm_reset(struct wm_softc *sc)
if ((sc->sc_type >= WM_T_I350) && (sc->sc_type <= WM_T_I211))
wm_set_eee_i350(sc);
/* Clear the host wakeup bit after lcd reset */
if (sc->sc_type >= WM_T_PCH) {
reg = wm_gmii_hv_readreg(sc->sc_dev, 2,
BM_PORT_GEN_CFG);
reg &= ~BM_WUC_HOST_WU_BIT;
wm_gmii_hv_writereg(sc->sc_dev, 2,
BM_PORT_GEN_CFG, reg);
}
/*
* For PCH, this write will make sure that any noise will be detected
* as a CRC error and be dropped rather than show up as a bad packet
@ -5091,6 +5129,10 @@ wm_init_locked(struct ifnet *ifp)
ifp->if_collisions += CSR_READ(sc, WMREG_COLC);
ifp->if_ierrors += CSR_READ(sc, WMREG_RXERRC);
/* AMT based hardware can now take control from firmware */
if ((sc->sc_flags & WM_F_HAS_AMT) != 0)
wm_get_hw_control(sc);
/* PCH_SPT hardware workaround */
if (sc->sc_type == WM_T_PCH_SPT)
wm_flush_desc_rings(sc);
@ -5098,9 +5140,9 @@ wm_init_locked(struct ifnet *ifp)
/* Reset the chip to a known state. */
wm_reset(sc);
/* AMT based hardware can now take control from firmware */
if ((sc->sc_flags & WM_F_HAS_AMT) != 0)
wm_get_hw_control(sc);
if ((sc->sc_type == WM_T_PCH_SPT) &&
pci_intr_type(sc->sc_pc, sc->sc_intrs[0]) == PCI_INTR_TYPE_INTX)
wm_legacy_irq_quirk_spt(sc);
/* Init hardware bits */
wm_initialize_hardware_bits(sc);
@ -8528,7 +8570,7 @@ wm_intr_legacy(void *arg)
break;
if (handled == 0) {
DPRINTF(WM_DEBUG_TX,
("%s: INTx: got intr\n", device_xname(sc->sc_dev)));
("%s: INTx: got intr\n",device_xname(sc->sc_dev)));
}
if (rndval == 0)
rndval = icr;
@ -8934,34 +8976,7 @@ wm_gmii_reset(struct wm_softc *sc)
case WM_T_PCH2:
case WM_T_PCH_LPT:
case WM_T_PCH_SPT:
/* Allow time for h/w to get to a quiescent state afer reset */
delay(10*1000);
if (sc->sc_type == WM_T_PCH)
wm_hv_phy_workaround_ich8lan(sc);
if (sc->sc_type == WM_T_PCH2)
wm_lv_phy_workaround_ich8lan(sc);
/* Clear the host wakeup bit after lcd reset */
if (sc->sc_type >= WM_T_PCH) {
reg = wm_gmii_hv_readreg(sc->sc_dev, 2,
BM_PORT_GEN_CFG);
reg &= ~BM_WUC_HOST_WU_BIT;
wm_gmii_hv_writereg(sc->sc_dev, 2,
BM_PORT_GEN_CFG, reg);
}
/*
* XXX Configure the LCD with th extended configuration region
* in NVM
*/
/* Disable D0 LPLU. */
if (sc->sc_type >= WM_T_PCH) /* PCH* */
wm_lplu_d0_disable_pch(sc);
else
wm_lplu_d0_disable(sc); /* ICH* */
wm_phy_post_reset(sc);
break;
default:
panic("%s: unknown type\n", __func__);
@ -9422,6 +9437,12 @@ wm_gmii_mediachange(struct ifnet *ifp)
if ((ifp->if_flags & IFF_UP) == 0)
return 0;
/* Disable D0 LPLU. */
if (sc->sc_type >= WM_T_PCH) /* PCH* */
wm_lplu_d0_disable_pch(sc);
else
wm_lplu_d0_disable(sc); /* ICH* */
sc->sc_ctrl &= ~(CTRL_SPEED_MASK | CTRL_FD);
sc->sc_ctrl |= CTRL_SLU;
if ((IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO)
@ -13764,33 +13785,17 @@ wm_platform_pm_pch_lpt(struct wm_softc *sc, bool link)
| __SHIFTIN(link, LTRV_SNOOP_REQ) | LTRV_SEND;
uint32_t rxa;
uint16_t scale = 0, lat_enc = 0;
int32_t obff_hwm = 0;
int64_t lat_ns, value;
DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n",
device_xname(sc->sc_dev), __func__));
if (link) {
pcireg_t preg;
uint16_t max_snoop, max_nosnoop, max_ltr_enc;
rxa = CSR_READ(sc, WMREG_PBA) & PBA_RXA_MASK;
/*
* Determine the maximum latency tolerated by the device.
*
* Per the PCIe spec, the tolerated latencies are encoded as
* a 3-bit encoded scale (only 0-5 are valid) multiplied by
* a 10-bit value (0-1023) to provide a range from 1 ns to
* 2^25*(2^10-1) ns. The scale is encoded as 0=2^0ns,
* 1=2^5ns, 2=2^10ns,...5=2^25ns.
*/
lat_ns = ((int64_t)rxa * 1024 -
(2 * (int64_t)sc->sc_ethercom.ec_if.if_mtu)) * 8 * 1000;
if (lat_ns < 0)
lat_ns = 0;
else {
uint32_t status;
uint16_t speed;
pcireg_t preg;
status = CSR_READ(sc, WMREG_STATUS);
switch (__SHIFTOUT(status, STATUS_SPEED)) {
@ -13804,12 +13809,30 @@ wm_platform_pm_pch_lpt(struct wm_softc *sc, bool link)
speed = 1000;
break;
default:
printf("%s: Unknown speed (status = %08x)\n",
device_xname(sc->sc_dev), status);
device_printf(sc->sc_dev, "Unknown speed "
"(status = %08x)\n", status);
return -1;
}
/* Rx Packet Buffer Allocation size (KB) */
rxa = CSR_READ(sc, WMREG_PBA) & PBA_RXA_MASK;
/*
* Determine the maximum latency tolerated by the device.
*
* Per the PCIe spec, the tolerated latencies are encoded as
* a 3-bit encoded scale (only 0-5 are valid) multiplied by
* a 10-bit value (0-1023) to provide a range from 1 ns to
* 2^25*(2^10-1) ns. The scale is encoded as 0=2^0ns,
* 1=2^5ns, 2=2^10ns,...5=2^25ns.
*/
lat_ns = ((int64_t)rxa * 1024 -
(2 * ((int64_t)sc->sc_ethercom.ec_if.if_mtu
+ ETHER_HDR_LEN))) * 8 * 1000;
if (lat_ns < 0)
lat_ns = 0;
else
lat_ns /= speed;
}
value = lat_ns;
while (value > LTRV_VALUE) {
@ -13833,12 +13856,39 @@ wm_platform_pm_pch_lpt(struct wm_softc *sc, bool link)
if (lat_enc > max_ltr_enc) {
lat_enc = max_ltr_enc;
lat_ns = __SHIFTOUT(lat_enc, PCI_LTR_MAXSNOOPLAT_VAL)
* PCI_LTR_SCALETONS(
__SHIFTOUT(lat_enc,
PCI_LTR_MAXSNOOPLAT_SCALE));
}
if (lat_ns) {
lat_ns *= speed * 1000;
lat_ns /= 8;
lat_ns /= 1000000000;
obff_hwm = (int32_t)(rxa - lat_ns);
}
if ((obff_hwm < 0) || (obff_hwm > SVT_OFF_HWM)) {
device_printf(sc->sc_dev, "Invalid high water mark %d"
"(rxa = %d, lat_ns = %d)\n",
obff_hwm, (int32_t)rxa, (int32_t)lat_ns);
return -1;
}
}
/* Snoop and No-Snoop latencies the same */
reg |= lat_enc | __SHIFTIN(lat_enc, LTRV_NONSNOOP);
CSR_WRITE(sc, WMREG_LTRV, reg);
/* Set OBFF high water mark */
reg = CSR_READ(sc, WMREG_SVT) & ~SVT_OFF_HWM;
reg |= obff_hwm;
CSR_WRITE(sc, WMREG_SVT, reg);
/* Enable OBFF */
reg = CSR_READ(sc, WMREG_SVCR);
reg |= SVCR_OFF_EN | SVCR_OFF_MASKINT;
CSR_WRITE(sc, WMREG_SVCR, reg);
return 0;
}
@ -13916,3 +13966,21 @@ wm_pll_workaround_i210(struct wm_softc *sc)
if (wa_done)
aprint_verbose_dev(sc->sc_dev, "I210 workaround done\n");
}
static void
wm_legacy_irq_quirk_spt(struct wm_softc *sc)
{
uint32_t reg;
DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n",
device_xname(sc->sc_dev), __func__));
KASSERT(sc->sc_type == WM_T_PCH_SPT);
reg = CSR_READ(sc, WMREG_FEXTNVM7);
reg |= FEXTNVM7_SIDE_CLK_UNGATE;
CSR_WRITE(sc, WMREG_FEXTNVM7, reg);
reg = CSR_READ(sc, WMREG_FEXTNVM9);
reg |= FEXTNVM9_IOSFSB_CLKGATE_DIS | FEXTNVM9_IOSFSB_CLKREQ_DIS;
CSR_WRITE(sc, WMREG_FEXTNVM9, reg);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_wmreg.h,v 1.99 2017/06/26 04:09:02 msaitoh Exp $ */
/* $NetBSD: if_wmreg.h,v 1.100 2017/06/26 04:22:46 msaitoh Exp $ */
/*
* Copyright (c) 2001 Wasabi Systems, Inc.
@ -728,6 +728,13 @@ struct livengood_tcpip_ctxdesc {
#define IVAR_MISC_TCPTIMER __BITS(0, 7)
#define IVAR_MISC_OTHER __BITS(8, 15)
#define WMREG_SVCR 0x00f0
#define SVCR_OFF_EN __BIT(0)
#define SVCR_OFF_MASKINT __BIT(12)
#define WMREG_SVT 0x00f4
#define SVT_OFF_HWM __BITS(4, 0)
#define WMREG_LTRV 0x00f8 /* Latency Tolerance Reporting */
#define LTRV_VALUE __BITS(9, 0)
#define LTRV_SCALE __BITS(12, 10)
@ -1302,6 +1309,8 @@ struct livengood_tcpip_ctxdesc {
#define WMREG_GCR2 0x5b64 /* 3GPIO Control Register 2 */
#define WMREG_FEXTNVM9 0x5bb4 /* Future Extended NVM 9 */
#define FEXTNVM9_IOSFSB_CLKGATE_DIS __BIT(11)
#define FEXTNVM9_IOSFSB_CLKREQ_DIS __BIT(12)
#define WMREG_FEXTNVM11 0x5bbc /* Future Extended NVM 11 */
#define FEXTNVM11_DIS_MULRFIX __BIT(13) /* Disable MULR fix */