From 14cf0d6e82bd6205d5b3b8fe550c3d6ab898e2ac Mon Sep 17 00:00:00 2001 From: Stefan Sperling Date: Sun, 18 Jul 2021 12:39:17 +0000 Subject: 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 --- sys/dev/pci/if_iwx.c | 49 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file 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 @@ -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,25 +1347,37 @@ 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); IWX_WRITE(sc, IWX_HBUS_TARG_PRPH_WDAT, 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) { @@ -2215,6 +2230,26 @@ iwx_conf_msix_hw(struct iwx_softc *sc, int stopped) IWX_MSIX_HW_INT_CAUSES_REG_HAP); } +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) { @@ -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); -- cgit v1.2.3