diff options
author | Stefan Sperling <stsp@cvs.openbsd.org> | 2019-10-28 18:11:11 +0000 |
---|---|---|
committer | Stefan Sperling <stsp@cvs.openbsd.org> | 2019-10-28 18:11:11 +0000 |
commit | b2796020899590813fae8656955a5e19b0eb85b6 (patch) | |
tree | 466c104f36bef59dfd65c243e77f1085f3c3616c | |
parent | cfcd38703794181182b4e68ae055a407c051b110 (diff) |
Have iwm(4) configure the PCIe LTR.
Patch by Imre Vadasz.
Cross-check and pcireg.h tweak by kettenis@
ok patrick@
-rw-r--r-- | sys/dev/pci/if_iwm.c | 48 | ||||
-rw-r--r-- | sys/dev/pci/if_iwmreg.h | 52 | ||||
-rw-r--r-- | sys/dev/pci/if_iwmvar.h | 3 | ||||
-rw-r--r-- | sys/dev/pci/pcireg.h | 4 |
4 files changed, 98 insertions, 9 deletions
diff --git a/sys/dev/pci/if_iwm.c b/sys/dev/pci/if_iwm.c index 8ae9f01cb02..211f1ca47de 100644 --- a/sys/dev/pci/if_iwm.c +++ b/sys/dev/pci/if_iwm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_iwm.c,v 1.265 2019/10/28 18:08:08 stsp Exp $ */ +/* $OpenBSD: if_iwm.c,v 1.266 2019/10/28 18:11:10 stsp Exp $ */ /* * Copyright (c) 2014, 2016 genua gmbh <info@genua.de> @@ -359,6 +359,7 @@ int iwm_send_phy_cfg_cmd(struct iwm_softc *); int iwm_load_ucode_wait_alive(struct iwm_softc *, enum iwm_ucode_type); int iwm_send_dqa_cmd(struct iwm_softc *); int iwm_run_init_mvm_ucode(struct iwm_softc *, int); +int iwm_config_ltr(struct iwm_softc *); int iwm_rx_addbuf(struct iwm_softc *, int, int); int iwm_get_signal_strength(struct iwm_softc *, struct iwm_rx_phy_info *); void iwm_rx_rx_phy_cmd(struct iwm_softc *, struct iwm_rx_packet *, @@ -1424,19 +1425,33 @@ iwm_prepare_card_hw(struct iwm_softc *sc) void iwm_apm_config(struct iwm_softc *sc) { - pcireg_t reg; + pcireg_t lctl, cap; - reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, + /* + * HW bug W/A for instability in PCIe bus L0S->L1 transition. + * Check if BIOS (or OS) enabled L1-ASPM on this device. + * If so (likely), disable L0S, so device moves directly L0->L1; + * costs negligible amount of power savings. + * If not (unlikely), enable L0S, so there is at least some + * power savings, even without L1. + */ + lctl = pci_conf_read(sc->sc_pct, sc->sc_pcitag, sc->sc_cap_off + PCI_PCIE_LCSR); - if (reg & PCI_PCIE_LCSR_ASPM_L1) { - /* Um the Linux driver prints "Disabling L0S for this one ... */ + if (lctl & PCI_PCIE_LCSR_ASPM_L1) { IWM_SETBITS(sc, IWM_CSR_GIO_REG, IWM_CSR_GIO_REG_VAL_L0S_ENABLED); } else { - /* ... and "Enabling" here */ IWM_CLRBITS(sc, IWM_CSR_GIO_REG, IWM_CSR_GIO_REG_VAL_L0S_ENABLED); } + + cap = pci_conf_read(sc->sc_pct, sc->sc_pcitag, + sc->sc_cap_off + PCI_PCIE_DCSR2); + sc->sc_ltr_enabled = (cap & PCI_PCIE_DCSR2_LTREN) ? 1 : 0; + DPRINTF(("%s: L1 %sabled - LTR %sabled\n", + DEVNAME(sc), + (lctl & PCI_PCIE_LCSR_ASPM_L1) ? "En" : "Dis", + sc->sc_ltr_enabled ? "En" : "Dis")); } /* @@ -3300,6 +3315,19 @@ iwm_run_init_mvm_ucode(struct iwm_softc *sc, int justnvm) } int +iwm_config_ltr(struct iwm_softc *sc) +{ + struct iwm_ltr_config_cmd cmd = { + .flags = htole32(IWM_LTR_CFG_FLAG_FEATURE_ENABLE), + }; + + if (!sc->sc_ltr_enabled) + return 0; + + return iwm_send_cmd_pdu(sc, IWM_LTR_CONFIG, 0, sizeof(cmd), &cmd); +} + +int iwm_rx_addbuf(struct iwm_softc *sc, int size, int idx) { struct iwm_rx_ring *ring = &sc->rxq; @@ -6414,6 +6442,13 @@ iwm_init_hw(struct iwm_softc *sc) if (sc->sc_device_family == IWM_DEVICE_FAMILY_7000) iwm_tt_tx_backoff(sc, 0); + + err = iwm_config_ltr(sc); + if (err) { + printf("%s: PCIe LTR configuration failed (error %d)\n", + DEVNAME(sc), err); + } + err = iwm_power_update_device(sc); if (err) { printf("%s: could not send power command (error %d)\n", @@ -7139,6 +7174,7 @@ iwm_notif_intr(struct iwm_softc *sc) case IWM_MAC_CONTEXT_CMD: case IWM_REPLY_SF_CFG_CMD: case IWM_POWER_TABLE_CMD: + case IWM_LTR_CONFIG: case IWM_PHY_CONTEXT_CMD: case IWM_BINDING_CONTEXT_CMD: case IWM_WIDE_ID(IWM_LONG_GROUP, IWM_SCAN_CFG_CMD): diff --git a/sys/dev/pci/if_iwmreg.h b/sys/dev/pci/if_iwmreg.h index 7b8b38ef54f..f1f1f12bf46 100644 --- a/sys/dev/pci/if_iwmreg.h +++ b/sys/dev/pci/if_iwmreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_iwmreg.h,v 1.36 2019/10/28 18:06:04 stsp Exp $ */ +/* $OpenBSD: if_iwmreg.h,v 1.37 2019/10/28 18:11:10 stsp Exp $ */ /****************************************************************************** * @@ -1755,6 +1755,7 @@ struct iwm_agn_scd_bc_tbl { /* Power - legacy power table command */ #define IWM_POWER_TABLE_CMD 0x77 #define IWM_PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION 0x78 +#define IWM_LTR_CONFIG 0xee /* Thermal Throttling*/ #define IWM_REPLY_THERMAL_MNG_BACKOFF 0x7e @@ -3548,6 +3549,55 @@ struct iwm_nonqos_seq_query_cmd { /* Power Management Commands, Responses, Notifications */ +/** + * masks for LTR config command flags + * @IWM_LTR_CFG_FLAG_FEATURE_ENABLE: Feature operational status + * @IWM_LTR_CFG_FLAG_HW_DIS_ON_SHADOW_REG_ACCESS: allow LTR change on shadow + * memory access + * @IWM_LTR_CFG_FLAG_HW_EN_SHRT_WR_THROUGH: allow LTR msg send on ANY LTR + * reg change + * @IWM_LTR_CFG_FLAG_HW_DIS_ON_D0_2_D3: allow LTR msg send on transition from + * D0 to D3 + * @IWM_LTR_CFG_FLAG_SW_SET_SHORT: fixed static short LTR register + * @IWM_LTR_CFG_FLAG_SW_SET_LONG: fixed static short LONG register + * @IWM_LTR_CFG_FLAG_DENIE_C10_ON_PD: allow going into C10 on PD + */ +#define IWM_LTR_CFG_FLAG_FEATURE_ENABLE 0x00000001 +#define IWM_LTR_CFG_FLAG_HW_DIS_ON_SHADOW_REG_ACCESS 0x00000002 +#define IWM_LTR_CFG_FLAG_HW_EN_SHRT_WR_THROUGH 0x00000004 +#define IWM_LTR_CFG_FLAG_HW_DIS_ON_D0_2_D3 0x00000008 +#define IWM_LTR_CFG_FLAG_SW_SET_SHORT 0x00000010 +#define IWM_LTR_CFG_FLAG_SW_SET_LONG 0x00000020 +#define IWM_LTR_CFG_FLAG_DENIE_C10_ON_PD 0x00000040 + +/** + * struct iwm_ltr_config_cmd_v1 - configures the LTR + * @flags: See %enum iwm_ltr_config_flags + */ +struct iwm_ltr_config_cmd_v1 { + uint32_t flags; + uint32_t static_long; + uint32_t static_short; +} __packed; /* LTR_CAPABLE_API_S_VER_1 */ + +#define IWM_LTR_VALID_STATES_NUM 4 + +/** + * struct iwm_ltr_config_cmd - configures the LTR + * @flags: See %enum iwm_ltr_config_flags + * @static_long: + * @static_short: + * @ltr_cfg_values: + * @ltr_short_idle_timeout: + */ +struct iwm_ltr_config_cmd { + uint32_t flags; + uint32_t static_long; + uint32_t static_short; + uint32_t ltr_cfg_values[IWM_LTR_VALID_STATES_NUM]; + uint32_t ltr_short_idle_timeout; +} __packed; /* LTR_CAPABLE_API_S_VER_2 */ + /* Radio LP RX Energy Threshold measured in dBm */ #define IWM_POWER_LPRX_RSSI_THRESHOLD 75 #define IWM_POWER_LPRX_RSSI_THRESHOLD_MAX 94 diff --git a/sys/dev/pci/if_iwmvar.h b/sys/dev/pci/if_iwmvar.h index 9f593eb62d3..a76797681b1 100644 --- a/sys/dev/pci/if_iwmvar.h +++ b/sys/dev/pci/if_iwmvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_iwmvar.h,v 1.41 2019/10/28 17:32:51 stsp Exp $ */ +/* $OpenBSD: if_iwmvar.h,v 1.42 2019/10/28 18:11:10 stsp Exp $ */ /* * Copyright (c) 2014 genua mbh <info@genua.de> @@ -485,6 +485,7 @@ struct iwm_softc { int sc_noise; int host_interrupt_operation_mode; + int sc_ltr_enabled; #if NBPFILTER > 0 caddr_t sc_drvbpf; diff --git a/sys/dev/pci/pcireg.h b/sys/dev/pci/pcireg.h index 4ef148c1326..580d4849966 100644 --- a/sys/dev/pci/pcireg.h +++ b/sys/dev/pci/pcireg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pcireg.h,v 1.57 2019/05/30 21:44:21 kettenis Exp $ */ +/* $OpenBSD: pcireg.h,v 1.58 2019/10/28 18:11:10 stsp Exp $ */ /* $NetBSD: pcireg.h,v 1.26 2000/05/10 16:58:42 thorpej Exp $ */ /* @@ -602,6 +602,8 @@ typedef u_int8_t pci_revision_t; #define PCI_PCIE_SLCSR_PDS 0x00400000 #define PCI_PCIE_SLCSR_LACS 0x01000000 #define PCI_PCIE_RCSR 0x1c +#define PCI_PCIE_DCSR2 0x28 +#define PCI_PCIE_DCSR2_LTREN 0x00000400 #define PCI_PCIE_LCAP2 0x2c /* |