diff mbox series

wifi: ath12k: add panic handler

Message ID 20240529021533.10861-1-quic_bqiang@quicinc.com (mailing list archive)
State Accepted
Commit 809055628bce824b7fe18331abb65e44d02b0ecf
Delegated to: Kalle Valo
Headers show
Series wifi: ath12k: add panic handler | expand

Commit Message

Baochen Qiang May 29, 2024, 2:15 a.m. UTC
Currently for ath12k PCI devices, firmware could be running in one of
several execution environments, e.g., PBL, SBL and mission mode etc. Among
which PBL is the only stage where PCIe link negotiation could happen. So
normally firmware runs in PBL in order to be enumerated during system reboot.

However it might not work in kernel crash scenario: ath12k target is not
found after warm reboot from kernel crash. This is because when kernel crashes,
ath12k host does nothing to firmware. And during warm reboot, WLAN power
is sustained. So firmware is likely to keep running in mission mode throughout
the bootup process. As a result PCIe link is not established and thus target
not enumerated.

So add a handler in panic notification list for ath12k. When kernel crashes,
this handler gets called and tries to reset target to PBL state. Then PCIe
link negotiation could happen and target gets enumerated.

This change applies to all PCI devices including WCN7850 and QCN9274.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Baochen Qiang <quic_bqiang@quicinc.com>
---
 drivers/net/wireless/ath/ath12k/core.c | 29 ++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/core.h |  3 +++
 drivers/net/wireless/ath/ath12k/hif.h  |  9 ++++++++
 drivers/net/wireless/ath/ath12k/pci.c  |  8 +++++++
 4 files changed, 49 insertions(+)


base-commit: 2580be9ee6f5d97d6763b5d4ae4f9c0383fdf130

Comments

Jeff Johnson May 29, 2024, 4:09 p.m. UTC | #1
On 5/28/2024 7:15 PM, Baochen Qiang wrote:
> Currently for ath12k PCI devices, firmware could be running in one of
> several execution environments, e.g., PBL, SBL and mission mode etc. Among
> which PBL is the only stage where PCIe link negotiation could happen. So
> normally firmware runs in PBL in order to be enumerated during system reboot.
> 
> However it might not work in kernel crash scenario: ath12k target is not
> found after warm reboot from kernel crash. This is because when kernel crashes,
> ath12k host does nothing to firmware. And during warm reboot, WLAN power
> is sustained. So firmware is likely to keep running in mission mode throughout
> the bootup process. As a result PCIe link is not established and thus target
> not enumerated.
> 
> So add a handler in panic notification list for ath12k. When kernel crashes,
> this handler gets called and tries to reset target to PBL state. Then PCIe
> link negotiation could happen and target gets enumerated.
> 
> This change applies to all PCI devices including WCN7850 and QCN9274.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Baochen Qiang <quic_bqiang@quicinc.com>
Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com>
Kalle Valo June 3, 2024, 1:14 p.m. UTC | #2
Baochen Qiang <quic_bqiang@quicinc.com> wrote:

> Currently for ath12k PCI devices, firmware could be running in one of
> several execution environments, e.g., PBL, SBL and mission mode etc. Among
> which PBL is the only stage where PCIe link negotiation could happen. So
> normally firmware runs in PBL in order to be enumerated during system reboot.
> 
> However it might not work in kernel crash scenario: ath12k target is not
> found after warm reboot from kernel crash. This is because when kernel crashes,
> ath12k host does nothing to firmware. And during warm reboot, WLAN power
> is sustained. So firmware is likely to keep running in mission mode throughout
> the bootup process. As a result PCIe link is not established and thus target
> not enumerated.
> 
> So add a handler in panic notification list for ath12k. When kernel crashes,
> this handler gets called and tries to reset target to PBL state. Then PCIe
> link negotiation could happen and target gets enumerated.
> 
> This change applies to all PCI devices including WCN7850 and QCN9274.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Baochen Qiang <quic_bqiang@quicinc.com>
> Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com>
> Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>

Patch applied to ath-next branch of ath.git, thanks.

809055628bce wifi: ath12k: add panic handler
diff mbox series

Patch

diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index e7f628e935e4..4c3eab4686c2 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -1188,6 +1188,29 @@  int ath12k_core_pre_init(struct ath12k_base *ab)
 	return 0;
 }
 
+static int ath12k_core_panic_handler(struct notifier_block *nb,
+				     unsigned long action, void *data)
+{
+	struct ath12k_base *ab = container_of(nb, struct ath12k_base,
+					      panic_nb);
+
+	return ath12k_hif_panic_handler(ab);
+}
+
+static int ath12k_core_panic_notifier_register(struct ath12k_base *ab)
+{
+	ab->panic_nb.notifier_call = ath12k_core_panic_handler;
+
+	return atomic_notifier_chain_register(&panic_notifier_list,
+					      &ab->panic_nb);
+}
+
+static void ath12k_core_panic_notifier_unregister(struct ath12k_base *ab)
+{
+	atomic_notifier_chain_unregister(&panic_notifier_list,
+					 &ab->panic_nb);
+}
+
 int ath12k_core_init(struct ath12k_base *ab)
 {
 	int ret;
@@ -1198,11 +1221,17 @@  int ath12k_core_init(struct ath12k_base *ab)
 		return ret;
 	}
 
+	ret = ath12k_core_panic_notifier_register(ab);
+	if (ret)
+		ath12k_warn(ab, "failed to register panic handler: %d\n", ret);
+
 	return 0;
 }
 
 void ath12k_core_deinit(struct ath12k_base *ab)
 {
+	ath12k_core_panic_notifier_unregister(ab);
+
 	mutex_lock(&ab->core_lock);
 
 	ath12k_core_pdev_destroy(ab);
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 7d20b09c52e6..44ca30b67fa2 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -14,6 +14,7 @@ 
 #include <linux/dmi.h>
 #include <linux/ctype.h>
 #include <linux/firmware.h>
+#include <linux/panic_notifier.h>
 #include "qmi.h"
 #include "htc.h"
 #include "wmi.h"
@@ -924,6 +925,8 @@  struct ath12k_base {
 
 #endif /* CONFIG_ACPI */
 
+	struct notifier_block panic_nb;
+
 	/* must be last */
 	u8 drv_priv[] __aligned(sizeof(void *));
 };
diff --git a/drivers/net/wireless/ath/ath12k/hif.h b/drivers/net/wireless/ath/ath12k/hif.h
index 7f0926fe751d..0e53ec269fa4 100644
--- a/drivers/net/wireless/ath/ath12k/hif.h
+++ b/drivers/net/wireless/ath/ath12k/hif.h
@@ -30,6 +30,7 @@  struct ath12k_hif_ops {
 	void (*ce_irq_enable)(struct ath12k_base *ab);
 	void (*ce_irq_disable)(struct ath12k_base *ab);
 	void (*get_ce_msi_idx)(struct ath12k_base *ab, u32 ce_id, u32 *msi_idx);
+	int (*panic_handler)(struct ath12k_base *ab);
 };
 
 static inline int ath12k_hif_map_service_to_pipe(struct ath12k_base *ab, u16 service_id,
@@ -147,4 +148,12 @@  static inline void ath12k_hif_power_down(struct ath12k_base *ab, bool is_suspend
 	ab->hif.ops->power_down(ab, is_suspend);
 }
 
+static inline int ath12k_hif_panic_handler(struct ath12k_base *ab)
+{
+	if (!ab->hif.ops->panic_handler)
+		return NOTIFY_DONE;
+
+	return ab->hif.ops->panic_handler(ab);
+}
+
 #endif /* ATH12K_HIF_H */
diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c
index 11b95d037051..876c029f58f6 100644
--- a/drivers/net/wireless/ath/ath12k/pci.c
+++ b/drivers/net/wireless/ath/ath12k/pci.c
@@ -1302,6 +1302,13 @@  void ath12k_pci_power_down(struct ath12k_base *ab, bool is_suspend)
 	ath12k_pci_sw_reset(ab_pci->ab, false);
 }
 
+static int ath12k_pci_panic_handler(struct ath12k_base *ab)
+{
+	ath12k_pci_sw_reset(ab, false);
+
+	return NOTIFY_OK;
+}
+
 static const struct ath12k_hif_ops ath12k_pci_hif_ops = {
 	.start = ath12k_pci_start,
 	.stop = ath12k_pci_stop,
@@ -1319,6 +1326,7 @@  static const struct ath12k_hif_ops ath12k_pci_hif_ops = {
 	.ce_irq_enable = ath12k_pci_hif_ce_irq_enable,
 	.ce_irq_disable = ath12k_pci_hif_ce_irq_disable,
 	.get_ce_msi_idx = ath12k_pci_get_ce_msi_idx,
+	.panic_handler = ath12k_pci_panic_handler,
 };
 
 static