[PATCH 363/379][SRU][OEM-5.6] UBUNTU: SAUCE: ath11k: put target to suspend when system enters suspend state
You-Sheng Yang
vicamo.yang at canonical.com
Wed Dec 23 08:51:36 UTC 2020
From: Carl Huang <cjhuang at codeaurora.org>
BugLink: https://bugs.launchpad.net/bugs/1879633
This change is to put target to suspend state when OS enters
suspend state and resume the target when OS resumes.
Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1
Signed-off-by: Carl Huang <cjhuang at codeaurora.org>
Signed-off-by: Kalle Valo <kvalo at codeaurora.org>
(cherry picked from commit 68023bee4d61ea2b02af49bba00adabba51d8b6b
https://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git)
Signed-off-by: You-Sheng Yang <vicamo.yang at canonical.com>
---
drivers/net/wireless/ath/ath11k/core.c | 38 ++++++++++++++++++++++++
drivers/net/wireless/ath/ath11k/core.h | 2 ++
drivers/net/wireless/ath/ath11k/hw.h | 1 +
drivers/net/wireless/ath/ath11k/pci.c | 41 ++++++++++++++++++++++++--
4 files changed, 79 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
index ebd6886a8c18..6e126e2ffffe 100644
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -65,6 +65,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.supports_monitor = true,
.supports_shadow_regs = false,
.idle_ps = false,
+ .support_suspend = false,
},
{
.hw_rev = ATH11K_HW_IPQ6018_HW10,
@@ -102,6 +103,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.supports_monitor = true,
.supports_shadow_regs = false,
.idle_ps = false,
+ .support_suspend = false,
},
{
.name = "qca6390 hw2.0",
@@ -138,6 +140,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.supports_monitor = false,
.supports_shadow_regs = true,
.idle_ps = true,
+ .support_suspend = true,
},
};
@@ -937,5 +940,40 @@ struct ath11k_base *ath11k_core_alloc(struct device *dev, size_t priv_size,
}
EXPORT_SYMBOL(ath11k_core_alloc);
+int ath11k_core_suspend(struct ath11k_base *ab)
+{
+ struct ath11k *ar = ab->pdevs[0].ar;
+ int ret = 0;
+
+ if (ab->hw_params.support_suspend) {
+ reinit_completion(&ar->target_suspend);
+ ath11k_wmi_pdev_suspend(ar, 1, 0);
+ ret = wait_for_completion_timeout(&ar->target_suspend, 3 * HZ);
+ if (ret == 0) {
+ ath11k_warn(ab,
+ "timed out while waiting for suspend completion\n");
+ return -ETIMEDOUT;
+ } else if (!ar->target_suspend_ack) {
+ ath11k_warn(ab, "suspend failed\n");
+ return -EAGAIN;
+ }
+
+ return ath11k_hif_suspend(ab);
+ }
+ return 0;
+}
+EXPORT_SYMBOL(ath11k_core_suspend);
+
+int ath11k_core_resume(struct ath11k_base *ab)
+{
+ if (ab->hw_params.support_suspend) {
+ ath11k_hif_resume(ab);
+ ath11k_wmi_pdev_resume(ab->pdevs[0].ar, 0);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(ath11k_core_resume);
+
MODULE_DESCRIPTION("Core module for Qualcomm Atheros 802.11ax wireless LAN cards.");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
index a51bb6f918a0..a0ff7579b310 100644
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -888,6 +888,8 @@ int ath11k_core_fetch_bdf(struct ath11k_base *ath11k,
void ath11k_core_free_bdf(struct ath11k_base *ab, struct ath11k_board_data *bd);
void ath11k_core_halt(struct ath11k *ar);
+int ath11k_core_resume(struct ath11k_base *ab);
+int ath11k_core_suspend(struct ath11k_base *ab);
const struct firmware *ath11k_core_firmware_request(struct ath11k_base *ab,
const char *filename);
diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h
index 1dda4257e6d7..0df9c901aa3a 100644
--- a/drivers/net/wireless/ath/ath11k/hw.h
+++ b/drivers/net/wireless/ath/ath11k/hw.h
@@ -161,6 +161,7 @@ struct ath11k_hw_params {
bool supports_monitor;
bool supports_shadow_regs;
bool idle_ps;
+ bool support_suspend;
};
struct ath11k_hw_ops {
diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c
index 0a59a7ccd7dc..4f058ceaa0f1 100644
--- a/drivers/net/wireless/ath/ath11k/pci.c
+++ b/drivers/net/wireless/ath/ath11k/pci.c
@@ -243,13 +243,17 @@ static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab)
static void ath11k_pci_force_wake(struct ath11k_base *ab)
{
+ int val;
+
+ ath11k_pci_write32(ab, PCIE_SCRATCH_0_SOC_PCIE_REG, 0);
ath11k_pci_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1);
- mdelay(5);
+ mdelay(10);
+ val = ath11k_pci_read32(ab, PCIE_SCRATCH_0_SOC_PCIE_REG);
+ ath11k_dbg(ab, ATH11K_DBG_PCI, "forcw_wake scratch 0: 0x%x\n", val);
}
static void ath11k_pci_sw_reset(struct ath11k_base *ab)
{
- ath11k_pci_soc_global_reset(ab);
ath11k_mhi_clear_vector(ab);
ath11k_pci_soc_global_reset(ab);
ath11k_mhi_set_mhictrl_reset(ab);
@@ -885,9 +889,9 @@ static void ath11k_pci_power_down(struct ath11k_base *ab)
{
struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
+ ath11k_pci_force_wake(ab_pci->ab);
ath11k_mhi_stop(ab_pci);
clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
- ath11k_pci_force_wake(ab_pci->ab);
ath11k_pci_sw_reset(ab_pci->ab);
}
@@ -1180,12 +1184,43 @@ static void ath11k_pci_shutdown(struct pci_dev *pdev)
ath11k_pci_power_down(ab);
}
+static __maybe_unused int ath11k_pci_pm_suspend(struct device *dev)
+{
+ struct ath11k_base *ab = dev_get_drvdata(dev);
+ int ret;
+
+ ret = ath11k_core_suspend(ab);
+ if (ret)
+ ath11k_warn(ab, "failed to suspend hif: %d\n", ret);
+
+ return ret;
+}
+
+static __maybe_unused int ath11k_pci_pm_resume(struct device *dev)
+{
+ struct ath11k_base *ab = dev_get_drvdata(dev);
+ int ret;
+
+ ret = ath11k_core_resume(ab);
+ if (ret)
+ ath11k_warn(ab, "failed to resume hif: %d\n", ret);
+
+ return ret;
+}
+
+static SIMPLE_DEV_PM_OPS(ath11k_pci_pm_ops,
+ ath11k_pci_pm_suspend,
+ ath11k_pci_pm_resume);
+
static struct pci_driver ath11k_pci_driver = {
.name = "ath11k_pci",
.id_table = ath11k_pci_id_table,
.probe = ath11k_pci_probe,
.remove = ath11k_pci_remove,
.shutdown = ath11k_pci_shutdown,
+#ifdef CONFIG_PM
+ .driver.pm = &ath11k_pci_pm_ops,
+#endif
};
static int ath11k_pci_init(void)
--
2.29.2
More information about the kernel-team
mailing list