summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Sperling <stsp@cvs.openbsd.org>2019-10-28 18:11:11 +0000
committerStefan Sperling <stsp@cvs.openbsd.org>2019-10-28 18:11:11 +0000
commitb2796020899590813fae8656955a5e19b0eb85b6 (patch)
tree466c104f36bef59dfd65c243e77f1085f3c3616c
parentcfcd38703794181182b4e68ae055a407c051b110 (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.c48
-rw-r--r--sys/dev/pci/if_iwmreg.h52
-rw-r--r--sys/dev/pci/if_iwmvar.h3
-rw-r--r--sys/dev/pci/pcireg.h4
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
/*