wifi: ath12k: Reorder and relocate the release of resources in ath12k_core_deinit()
authorYingying Tang <quic_yintang@quicinc.com>
Wed, 23 Apr 2025 05:56:49 +0000 (11:26 +0530)
committerJeff Johnson <jeff.johnson@oss.qualcomm.com>
Mon, 19 May 2025 17:45:39 +0000 (10:45 -0700)
Ath12k panic notifier is registered in driver loading process. But it is not
unregistered if ATH12K_FLAG_QMI_FAIL is set(e.g. load BDF failed) and unload
driver. It causes a dirty node in panic notifier list since ath12k panic
notifier is not unregistered from list but the buffer of this node is freed
in driver unloading process. If load driver again there will be a page fault
error due to this dirty node in panic notifier list.

This issue is caused by asymmetry between ath12k_core_init() and
ath12k_core_deinit(). Reorder and relocate the release of resources in
ath12k_core_deinit() to avoid this asymmetry issue.

Call Trace:
<TASK>
? show_regs+0x67/0x70
? __die_body+0x20/0x70
? __die+0x2b/0x40
? page_fault_oops+0x15d/0x500
? search_bpf_extables+0x63/0x90
? notifier_chain_register+0x21/0xe0
? search_exception_tables+0x5f/0x70
? kernelmode_fixup_or_oops.isra.0+0x61/0x80
? __bad_area_nosemaphore+0x179/0x240
? bad_area_nosemaphore+0x16/0x20
? do_user_addr_fault+0x312/0x7f0
? prb_read_valid+0x1c/0x30
? exc_page_fault+0x78/0x180
? asm_exc_page_fault+0x27/0x30
? notifier_chain_register+0x21/0xe0
? notifier_chain_register+0x55/0xe0
atomic_notifier_chain_register+0x2c/0x50
ath12k_core_init+0x7e/0x110 [ath12k]
ath12k_pci_probe+0xaba/0xba0 [ath12k]

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0-02903-QCAHKSWPL_SILICONZ-1
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3

Fixes: 809055628bce8 ("wifi: ath12k: add panic handler")
Signed-off-by: Yingying Tang <quic_yintang@quicinc.com>
Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
Link: https://patch.msgid.link/20250423055650.16230-2-quic_yintang@quicinc.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
drivers/net/wireless/ath/ath12k/core.c
drivers/net/wireless/ath/ath12k/core.h
drivers/net/wireless/ath/ath12k/pci.c

index c12720a74885c2537fd806dcdd1653fbac3ae526..31d851d8e68838162e7663ad6464b80a7392df12 100644 (file)
@@ -2014,7 +2014,7 @@ static void ath12k_core_hw_group_destroy(struct ath12k_hw_group *ag)
        }
 }
 
-static void ath12k_core_hw_group_cleanup(struct ath12k_hw_group *ag)
+void ath12k_core_hw_group_cleanup(struct ath12k_hw_group *ag)
 {
        struct ath12k_base *ab;
        int i;
@@ -2160,10 +2160,9 @@ err:
 
 void ath12k_core_deinit(struct ath12k_base *ab)
 {
-       ath12k_core_panic_notifier_unregister(ab);
-       ath12k_core_hw_group_cleanup(ab->ag);
        ath12k_core_hw_group_destroy(ab->ag);
        ath12k_core_hw_group_unassign(ab);
+       ath12k_core_panic_notifier_unregister(ab);
 }
 
 void ath12k_core_free(struct ath12k_base *ab)
index f9d7e7d4fce0c286ae97e023381a90e936112807..3344de97238d6597e4fb5562d27ca21e8785098c 100644 (file)
@@ -1282,6 +1282,7 @@ struct ath12k_fw_stats_pdev {
 };
 
 int ath12k_core_qmi_firmware_ready(struct ath12k_base *ab);
+void ath12k_core_hw_group_cleanup(struct ath12k_hw_group *ag);
 int ath12k_core_pre_init(struct ath12k_base *ab);
 int ath12k_core_init(struct ath12k_base *ath12k);
 void ath12k_core_deinit(struct ath12k_base *ath12k);
index 5c012f7fcd975d795792a0a3e5e3385f38e256ce..489d546390fcdab8f615cc9184006a958d9f140a 100644 (file)
@@ -1734,8 +1734,6 @@ static void ath12k_pci_remove(struct pci_dev *pdev)
 
        if (test_bit(ATH12K_FLAG_QMI_FAIL, &ab->dev_flags)) {
                ath12k_pci_power_down(ab, false);
-               ath12k_qmi_deinit_service(ab);
-               ath12k_core_hw_group_unassign(ab);
                goto qmi_fail;
        }
 
@@ -1743,9 +1741,10 @@ static void ath12k_pci_remove(struct pci_dev *pdev)
 
        cancel_work_sync(&ab->reset_work);
        cancel_work_sync(&ab->dump_work);
-       ath12k_core_deinit(ab);
+       ath12k_core_hw_group_cleanup(ab->ag);
 
 qmi_fail:
+       ath12k_core_deinit(ab);
        ath12k_fw_unmap(ab);
        ath12k_mhi_unregister(ab_pci);