summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorstsp <stsp@openbsd.org>2020-08-01 16:14:05 +0000
committerstsp <stsp@openbsd.org>2020-08-01 16:14:05 +0000
commitd4e7b525b6ea4783a069ec35b463bb3cd83b5623 (patch)
tree6ccc40666d49956caa756de778e88fe6d32b88b0
parenttweak previous; ok anton (diff)
downloadwireguard-openbsd-d4e7b525b6ea4783a069ec35b463bb3cd83b5623.tar.xz
wireguard-openbsd-d4e7b525b6ea4783a069ec35b463bb3cd83b5623.zip
Add support for AX201 devices to iwx(4).
Matching firmware can be installed with fw_update(1). Align our device initialization sequence more closely to how Linux does it. We still use a different MSI-X configuration but register values written up to that point are now identical. patrick@ provided help with debugging several issues along way, thanks!
-rw-r--r--sys/dev/pci/if_iwx.c169
-rw-r--r--sys/dev/pci/if_iwxreg.h23
-rw-r--r--sys/dev/pci/if_iwxvar.h3
3 files changed, 156 insertions, 39 deletions
diff --git a/sys/dev/pci/if_iwx.c b/sys/dev/pci/if_iwx.c
index 7b8f086f7d1..0f929a34d66 100644
--- a/sys/dev/pci/if_iwx.c
+++ b/sys/dev/pci/if_iwx.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_iwx.c,v 1.41 2020/07/13 16:23:53 stsp Exp $ */
+/* $OpenBSD: if_iwx.c,v 1.42 2020/08/01 16:14:05 stsp Exp $ */
/*
* Copyright (c) 2014, 2016 genua gmbh <info@genua.de>
@@ -278,6 +278,7 @@ void iwx_disable_interrupts(struct iwx_softc *);
void iwx_ict_reset(struct iwx_softc *);
int iwx_set_hw_ready(struct iwx_softc *);
int iwx_prepare_card_hw(struct iwx_softc *);
+void iwx_force_power_gating(struct iwx_softc *);
void iwx_apm_config(struct iwx_softc *);
int iwx_apm_init(struct iwx_softc *);
void iwx_apm_stop(struct iwx_softc *);
@@ -769,6 +770,7 @@ iwx_ctxt_info_init(struct iwx_softc *sc, const struct iwx_fw_sects *fws)
struct iwx_context_info *ctxt_info;
struct iwx_context_info_rbd_cfg *rx_cfg;
uint32_t control_flags = 0, rb_size;
+ uint64_t paddr;
int err;
ctxt_info = sc->ctxt_info_dma.vaddr;
@@ -819,8 +821,16 @@ iwx_ctxt_info_init(struct iwx_softc *sc, const struct iwx_fw_sects *fws)
}
}
+ /*
+ * Write the context info DMA base address. The device expects a
+ * 64-bit address but a simple bus_space_write_8 to this register
+ * won't work on some devices, such as the AX201.
+ */
+ paddr = sc->ctxt_info_dma.paddr;
+ IWX_WRITE(sc, IWX_CSR_CTXT_INFO_BA, paddr & 0xffffffff);
+ IWX_WRITE(sc, IWX_CSR_CTXT_INFO_BA + 4, paddr >> 32);
+
/* kick FW self load */
- IWX_WRITE_8(sc, IWX_CSR_CTXT_INFO_BA, sc->ctxt_info_dma.paddr);
if (!iwx_nic_lock(sc))
return EBUSY;
iwx_write_prph(sc, IWX_UREG_CPU_INIT_RUN, 1);
@@ -1960,28 +1970,34 @@ iwx_prepare_card_hw(struct iwx_softc *sc)
}
void
+iwx_force_power_gating(struct iwx_softc *sc)
+{
+ iwx_set_bits_prph(sc, IWX_HPM_HIPM_GEN_CFG,
+ IWX_HPM_HIPM_GEN_CFG_CR_FORCE_ACTIVE);
+ DELAY(20);
+ iwx_set_bits_prph(sc, IWX_HPM_HIPM_GEN_CFG,
+ IWX_HPM_HIPM_GEN_CFG_CR_PG_EN |
+ IWX_HPM_HIPM_GEN_CFG_CR_SLP_EN);
+ DELAY(20);
+ iwx_clear_bits_prph(sc, IWX_HPM_HIPM_GEN_CFG,
+ IWX_HPM_HIPM_GEN_CFG_CR_FORCE_ACTIVE);
+}
+
+void
iwx_apm_config(struct iwx_softc *sc)
{
pcireg_t lctl, cap;
/*
- * 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.
+ * L0S states have been found to be unstable with our devices
+ * and in newer hardware they are not officially supported at
+ * all, so we must always set the L0S_DISABLED bit.
*/
+ IWX_SETBITS(sc, IWX_CSR_GIO_REG, IWX_CSR_GIO_REG_VAL_L0S_DISABLED);
+
lctl = pci_conf_read(sc->sc_pct, sc->sc_pcitag,
sc->sc_cap_off + PCI_PCIE_LCSR);
- if (lctl & PCI_PCIE_LCSR_ASPM_L1) {
- IWX_SETBITS(sc, IWX_CSR_GIO_REG,
- IWX_CSR_GIO_REG_VAL_L0S_ENABLED);
- } else {
- IWX_CLRBITS(sc, IWX_CSR_GIO_REG,
- IWX_CSR_GIO_REG_VAL_L0S_ENABLED);
- }
-
+ sc->sc_pm_support = !(lctl & PCI_PCIE_LCSR_ASPM_L0S);
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;
@@ -2179,6 +2195,7 @@ int
iwx_start_hw(struct iwx_softc *sc)
{
int err;
+ int t = 0;
err = iwx_prepare_card_hw(sc);
if (err)
@@ -2188,19 +2205,47 @@ iwx_start_hw(struct iwx_softc *sc)
IWX_SETBITS(sc, IWX_CSR_RESET, IWX_CSR_RESET_REG_FLAG_SW_RESET);
DELAY(5000);
+ if (sc->sc_integrated) {
+ IWX_SETBITS(sc, IWX_CSR_GP_CNTRL,
+ IWX_CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+ DELAY(20);
+ if (!iwx_poll_bit(sc, IWX_CSR_GP_CNTRL,
+ IWX_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+ IWX_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000)) {
+ printf("%s: timeout waiting for clock stabilization\n",
+ DEVNAME(sc));
+ return ETIMEDOUT;
+ }
+
+ iwx_force_power_gating(sc);
+
+ /* Reset the entire device */
+ IWX_SETBITS(sc, IWX_CSR_RESET, IWX_CSR_RESET_REG_FLAG_SW_RESET);
+ DELAY(5000);
+ }
+
err = iwx_apm_init(sc);
if (err)
return err;
iwx_init_msix_hw(sc);
+ while (t < 150000 && !iwx_set_hw_ready(sc)) {
+ DELAY(200);
+ t += 200;
+ if (iwx_set_hw_ready(sc)) {
+ break;
+ }
+ }
+ if (t >= 150000)
+ return ETIMEDOUT;
+
iwx_enable_rfkill_int(sc);
iwx_check_rfkill(sc);
return 0;
}
-
void
iwx_stop_device(struct iwx_softc *sc)
{
@@ -2949,11 +2994,7 @@ iwx_start_fw(struct iwx_softc *sc)
IWX_WRITE(sc, IWX_CSR_INT, ~0);
- err = iwx_nic_init(sc);
- if (err) {
- printf("%s: unable to init nic\n", DEVNAME(sc));
- return err;
- }
+ iwx_disable_interrupts(sc);
/* make sure rfkill handshake bits are cleared */
IWX_WRITE(sc, IWX_CSR_UCODE_DRV_GP1_CLR, IWX_CSR_UCODE_SW_BIT_RFKILL);
@@ -2962,6 +3003,13 @@ iwx_start_fw(struct iwx_softc *sc)
/* clear (again), then enable firwmare load interrupt */
IWX_WRITE(sc, IWX_CSR_INT, ~0);
+
+ err = iwx_nic_init(sc);
+ if (err) {
+ printf("%s: unable to init nic\n", DEVNAME(sc));
+ return err;
+ }
+
iwx_enable_fwload_interrupt(sc);
return iwx_load_firmware(sc);
@@ -7655,13 +7703,67 @@ typedef void *iwx_match_t;
static const struct pci_matchid iwx_devices[] = {
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_22500_1 },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_22500_2 },
+};
+
+static const struct pci_matchid iwx_subsystem_id_ax200[] = {
+ { PCI_VENDOR_INTEL, 0x0080 },
+};
+
+static const struct pci_matchid iwx_subsystem_id_ax201[] = {
+ { PCI_VENDOR_INTEL, 0x0070 },
+ { PCI_VENDOR_INTEL, 0x0074 },
+ { PCI_VENDOR_INTEL, 0x0078 },
+ { PCI_VENDOR_INTEL, 0x007c },
+ { PCI_VENDOR_INTEL, 0x0310 },
+ { PCI_VENDOR_INTEL, 0x2074 },
+ { PCI_VENDOR_INTEL, 0x4070 },
+ /* TODO: There are more ax201 devices with "main" product ID 0x06f0 */
};
int
iwx_match(struct device *parent, iwx_match_t match __unused, void *aux)
{
- return pci_matchbyid((struct pci_attach_args *)aux, iwx_devices,
- nitems(iwx_devices));
+ struct pci_attach_args *pa = aux;
+ pcireg_t subid;
+ pci_vendor_id_t svid;
+ pci_product_id_t spid;
+ int i;
+
+ if (!pci_matchbyid(pa, iwx_devices, nitems(iwx_devices)))
+ return 0;
+
+ /*
+ * Some PCI product IDs are shared among devices which use distinct
+ * chips or firmware. We need to match the subsystem ID as well to
+ * ensure that we have in fact found a supported device.
+ */
+ subid = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
+ svid = PCI_VENDOR(subid);
+ spid = PCI_PRODUCT(subid);
+
+ switch (PCI_PRODUCT(pa->pa_id)) {
+ case PCI_PRODUCT_INTEL_WL_22500_1: /* AX200 */
+ for (i = 0; i < nitems(iwx_subsystem_id_ax200); i++) {
+ if (svid == iwx_subsystem_id_ax200[i].pm_vid &&
+ spid == iwx_subsystem_id_ax200[i].pm_pid)
+ return 1;
+
+ }
+ break;
+ case PCI_PRODUCT_INTEL_WL_22500_2: /* AX201 */
+ for (i = 0; i < nitems(iwx_subsystem_id_ax201); i++) {
+ if (svid == iwx_subsystem_id_ax201[i].pm_vid &&
+ spid == iwx_subsystem_id_ax201[i].pm_pid)
+ return 1;
+
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
}
int
@@ -7807,7 +7909,10 @@ iwx_attach(struct device *parent, struct device *self, void *aux)
}
printf(", %s\n", intrstr);
- iwx_disable_interrupts(sc);
+ /* Clear pending interrupts. */
+ IWX_WRITE(sc, IWX_CSR_INT_MASK, 0);
+ IWX_WRITE(sc, IWX_CSR_INT, ~0);
+ IWX_WRITE(sc, IWX_CSR_FH_INT_STATUS, ~0);
sc->sc_hw_rev = IWX_READ(sc, IWX_CSR_HW_REV);
switch (PCI_PRODUCT(pa->pa_id)) {
@@ -7822,6 +7927,17 @@ iwx_attach(struct device *parent, struct device *self, void *aux)
sc->sc_tx_with_siso_diversity = 0;
sc->sc_uhb_supported = 0;
break;
+ case PCI_PRODUCT_INTEL_WL_22500_2:
+ sc->sc_fwname = "iwx-QuZ-a0-hr-b0-48";
+ sc->sc_device_family = IWX_DEVICE_FAMILY_22000;
+ sc->sc_fwdmasegsz = IWX_FWDMASEGSZ_8000;
+ sc->sc_integrated = 1;
+ sc->sc_ltr_delay = IWX_SOC_FLAGS_LTR_APPLY_DELAY_200;
+ sc->sc_low_latency_xtal = 0;
+ sc->sc_xtal_latency = 5000;
+ sc->sc_tx_with_siso_diversity = 0;
+ sc->sc_uhb_supported = 0;
+ break;
default:
printf("%s: unknown adapter type\n", DEVNAME(sc));
return;
@@ -7931,9 +8047,6 @@ iwx_attach(struct device *parent, struct device *self, void *aux)
if (sc->sc_nswq == NULL)
goto fail4;
- /* Clear pending interrupts. */
- IWX_WRITE(sc, IWX_CSR_INT, 0xffffffff);
-
ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */
ic->ic_state = IEEE80211_S_INIT;
diff --git a/sys/dev/pci/if_iwxreg.h b/sys/dev/pci/if_iwxreg.h
index 419efccd26f..789075c0e54 100644
--- a/sys/dev/pci/if_iwxreg.h
+++ b/sys/dev/pci/if_iwxreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_iwxreg.h,v 1.16 2020/07/13 16:18:52 stsp Exp $ */
+/* $OpenBSD: if_iwxreg.h,v 1.17 2020/08/01 16:14:05 stsp Exp $ */
/*-
* Based on BSD-licensed source modules in the Linux iwlwifi driver,
@@ -427,7 +427,7 @@ struct iwx_context_info {
#define IWX_CSR_HW_REV_TYPE_MSK (0x000FFF0)
/* CSR GIO */
-#define IWX_CSR_GIO_REG_VAL_L0S_ENABLED (0x00000002)
+#define IWX_CSR_GIO_REG_VAL_L0S_DISABLED (0x00000002)
/*
* UCODE-DRIVER GP (general purpose) mailbox register 1
@@ -718,13 +718,22 @@ struct iwx_context_info {
#define IWX_SB_CFG_OVERRIDE_ENABLE 0x8000
#define IWX_SB_CFG_BASE_OVERRIDE 0xa20000
#define IWX_SB_MODIFY_CFG_FLAG 0xa03088
-#define IWX_SB_CPU_1_STATUS 0xa01e30
-#define IWX_SB_CPU_2_STATUS 0Xa01e34
+#define IWX_UMAG_SB_CPU_1_STATUS 0xa038c0
+#define IWX_UMAG_SB_CPU_2_STATUS 0xa038c4
#define IWX_UREG_CHICK 0xa05c00
#define IWX_UREG_CHICK_MSI_ENABLE (1 << 24)
#define IWX_UREG_CHICK_MSIX_ENABLE (1 << 25)
+#define IWX_HPM_DEBUG 0xa03440
+#define IWX_PERSISTENCE_BIT (1 << 12)
+#define IWX_PREG_WFPM_ACCESS (1 << 12)
+
+#define IWX_HPM_HIPM_GEN_CFG 0xa03458
+#define IWX_HPM_HIPM_GEN_CFG_CR_PG_EN (1 << 0)
+#define IWX_HPM_HIPM_GEN_CFG_CR_SLP_EN (1 << 1)
+#define IWX_HPM_HIPM_GEN_CFG_CR_FORCE_ACTIVE (1 << 10)
+
/*
* Per-Tx-queue write pointer (index, really!)
* Indicates index to next TFD that driver will fill (1 past latest filled).
@@ -6583,12 +6592,6 @@ iwx_rx_packet_payload_len(const struct iwx_rx_packet *pkt)
#define IWX_MIN_DBM -100
#define IWX_MAX_DBM -33 /* realistic guess */
-#define IWX_READ_8(sc, reg) \
- bus_space_read_8((sc)->sc_st, (sc)->sc_sh, (reg))
-
-#define IWX_WRITE_8(sc, reg, val) \
- bus_space_write_8((sc)->sc_st, (sc)->sc_sh, (reg), (val))
-
#define IWX_READ(sc, reg) \
bus_space_read_4((sc)->sc_st, (sc)->sc_sh, (reg))
diff --git a/sys/dev/pci/if_iwxvar.h b/sys/dev/pci/if_iwxvar.h
index f437da57cf4..091ae9711d2 100644
--- a/sys/dev/pci/if_iwxvar.h
+++ b/sys/dev/pci/if_iwxvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_iwxvar.h,v 1.10 2020/06/22 16:27:37 stsp Exp $ */
+/* $OpenBSD: if_iwxvar.h,v 1.11 2020/08/01 16:14:05 stsp Exp $ */
/*
* Copyright (c) 2014 genua mbh <info@genua.de>
@@ -476,6 +476,7 @@ struct iwx_softc {
struct iwx_notif_statistics sc_stats;
int sc_noise;
+ int sc_pm_support;
int sc_ltr_enabled;
int sc_integrated;