summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Sperling <stsp@cvs.openbsd.org>2021-07-18 12:39:17 +0000
committerStefan Sperling <stsp@cvs.openbsd.org>2021-07-18 12:39:17 +0000
commit14cf0d6e82bd6205d5b3b8fe550c3d6ab898e2ac (patch)
tree8be9cff39e6d6c31e54aefa9f9e3bab89eaea480
parentbf4ae9cd47e44644a7b9b18ca3e8621701f978df (diff)
Clear the "persistence bit" on iwx(4) devices during hardware init.
According to iwlwifi commit messages this fixes an edge case where devices fail to resume after system suspend. See Linux commit 8954e1eb2270fa2effffd031b4839253952c76f2 Same fix was made for iwm(4) in CVS commit x0XTNdEmudy5oBR4
-rw-r--r--sys/dev/pci/if_iwx.c49
1 files changed, 44 insertions, 5 deletions
diff --git a/sys/dev/pci/if_iwx.c b/sys/dev/pci/if_iwx.c
index 332d49f38ce..b8aa25290bf 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.67 2021/07/18 12:21:49 stsp Exp $ */
+/* $OpenBSD: if_iwx.c,v 1.68 2021/07/18 12:39:16 stsp Exp $ */
/*
* Copyright (c) 2014, 2016 genua gmbh <info@genua.de>
@@ -248,7 +248,9 @@ int iwx_firmware_store_section(struct iwx_softc *, enum iwx_ucode_type,
int iwx_set_default_calib(struct iwx_softc *, const void *);
void iwx_fw_info_free(struct iwx_fw_info *);
int iwx_read_firmware(struct iwx_softc *);
+uint32_t iwx_read_prph_unlocked(struct iwx_softc *, uint32_t);
uint32_t iwx_read_prph(struct iwx_softc *, uint32_t);
+void iwx_write_prph_unlocked(struct iwx_softc *, uint32_t, uint32_t);
void iwx_write_prph(struct iwx_softc *, uint32_t, uint32_t);
int iwx_read_mem(struct iwx_softc *, uint32_t, void *, int);
int iwx_write_mem(struct iwx_softc *, uint32_t, const void *, int);
@@ -287,6 +289,7 @@ void iwx_apm_stop(struct iwx_softc *);
int iwx_allow_mcast(struct iwx_softc *);
void iwx_init_msix_hw(struct iwx_softc *);
void iwx_conf_msix_hw(struct iwx_softc *, int);
+int iwx_clear_persistence_bit(struct iwx_softc *);
int iwx_start_hw(struct iwx_softc *);
void iwx_stop_device(struct iwx_softc *);
void iwx_nic_config(struct iwx_softc *);
@@ -1344,19 +1347,24 @@ iwx_read_firmware(struct iwx_softc *sc)
}
uint32_t
-iwx_read_prph(struct iwx_softc *sc, uint32_t addr)
+iwx_read_prph_unlocked(struct iwx_softc *sc, uint32_t addr)
{
- iwx_nic_assert_locked(sc);
IWX_WRITE(sc,
IWX_HBUS_TARG_PRPH_RADDR, ((addr & 0x000fffff) | (3 << 24)));
IWX_BARRIER_READ_WRITE(sc);
return IWX_READ(sc, IWX_HBUS_TARG_PRPH_RDAT);
}
-void
-iwx_write_prph(struct iwx_softc *sc, uint32_t addr, uint32_t val)
+uint32_t
+iwx_read_prph(struct iwx_softc *sc, uint32_t addr)
{
iwx_nic_assert_locked(sc);
+ return iwx_read_prph_unlocked(sc, addr);
+}
+
+void
+iwx_write_prph_unlocked(struct iwx_softc *sc, uint32_t addr, uint32_t val)
+{
IWX_WRITE(sc,
IWX_HBUS_TARG_PRPH_WADDR, ((addr & 0x000fffff) | (3 << 24)));
IWX_BARRIER_WRITE(sc);
@@ -1364,6 +1372,13 @@ iwx_write_prph(struct iwx_softc *sc, uint32_t addr, uint32_t val)
}
void
+iwx_write_prph(struct iwx_softc *sc, uint32_t addr, uint32_t val)
+{
+ iwx_nic_assert_locked(sc);
+ iwx_write_prph_unlocked(sc, addr, val);
+}
+
+void
iwx_write_prph64(struct iwx_softc *sc, uint64_t addr, uint64_t val)
{
iwx_write_prph(sc, (uint32_t)addr, val & 0xffffffff);
@@ -2216,6 +2231,26 @@ iwx_conf_msix_hw(struct iwx_softc *sc, int stopped)
}
int
+iwx_clear_persistence_bit(struct iwx_softc *sc)
+{
+ uint32_t hpm, wprot;
+
+ hpm = iwx_read_prph_unlocked(sc, IWX_HPM_DEBUG);
+ if (hpm != 0xa5a5a5a0 && (hpm & IWX_PERSISTENCE_BIT)) {
+ wprot = iwx_read_prph_unlocked(sc, IWX_PREG_PRPH_WPROT_22000);
+ if (wprot & IWX_PREG_WFPM_ACCESS) {
+ printf("%s: cannot clear persistence bit\n",
+ DEVNAME(sc));
+ return EPERM;
+ }
+ iwx_write_prph_unlocked(sc, IWX_HPM_DEBUG,
+ hpm & ~IWX_PERSISTENCE_BIT);
+ }
+
+ return 0;
+}
+
+int
iwx_start_hw(struct iwx_softc *sc)
{
int err;
@@ -2225,6 +2260,10 @@ iwx_start_hw(struct iwx_softc *sc)
if (err)
return err;
+ err = iwx_clear_persistence_bit(sc);
+ if (err)
+ return err;
+
/* Reset the entire device */
IWX_SETBITS(sc, IWX_CSR_RESET, IWX_CSR_RESET_REG_FLAG_SW_RESET);
DELAY(5000);