wifi: ath11k: Use RMW accessors for changing LNKCTL
authorIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
Mon, 17 Jul 2023 12:05:00 +0000 (15:05 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 13 Sep 2023 07:42:48 +0000 (09:42 +0200)
[ Upstream commit 6c1b6bdb34aaf8f94f65a9cae1d63490320c11bc ]

Don't assume that only the driver would be accessing LNKCTL. ASPM policy
changes can trigger write to LNKCTL outside of driver's control.

Use RMW capability accessors which do proper locking to avoid losing
concurrent updates to the register value. On restore, clear the ASPMC field
properly.

Suggested-by: Lukas Wunner <lukas@wunner.de>
Fixes: e9603f4bdcc0 ("ath11k: pci: disable ASPM L0sLs before downloading firmware")
Link: https://lore.kernel.org/r/20230717120503.15276-9-ilpo.jarvinen@linux.intel.com
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Acked-by: Kalle Valo <kvalo@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/net/wireless/ath/ath11k/pci.c

index 3c6005a..3953ebd 100644 (file)
@@ -582,8 +582,8 @@ static void ath11k_pci_aspm_disable(struct ath11k_pci *ab_pci)
                   u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L1));
 
        /* disable L0s and L1 */
-       pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL,
-                                  ab_pci->link_ctl & ~PCI_EXP_LNKCTL_ASPMC);
+       pcie_capability_clear_word(ab_pci->pdev, PCI_EXP_LNKCTL,
+                                  PCI_EXP_LNKCTL_ASPMC);
 
        set_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags);
 }
@@ -591,8 +591,10 @@ static void ath11k_pci_aspm_disable(struct ath11k_pci *ab_pci)
 static void ath11k_pci_aspm_restore(struct ath11k_pci *ab_pci)
 {
        if (test_and_clear_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags))
-               pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL,
-                                          ab_pci->link_ctl);
+               pcie_capability_clear_and_set_word(ab_pci->pdev, PCI_EXP_LNKCTL,
+                                                  PCI_EXP_LNKCTL_ASPMC,
+                                                  ab_pci->link_ctl &
+                                                  PCI_EXP_LNKCTL_ASPMC);
 }
 
 static int ath11k_pci_power_up(struct ath11k_base *ab)