diff mbox series

[v2] ath11k: fix rmmod failure if qmi sequence fails

Message ID 1605076699-21924-1-git-send-email-akolli@codeaurora.org
State New
Headers show
Series [v2] ath11k: fix rmmod failure if qmi sequence fails | expand

Commit Message

Anilkumar Kolli Nov. 11, 2020, 6:38 a.m. UTC
QMI sequence fails if caldata file is not available.
It is observed that 'rmmod ath11k' fails if qmi message fails.
With this patch rmmod/insmod is working.

Logs:
Direct firmware load for IPQ8074/caldata.bin failed with error -2
Falling back to user helper
qmi failed to load CAL: IPQ8074/caldata.bin
qmi failed to load board data file:-11

Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-00009-QCAHKSWPL_SILICONZ-1

Signed-off-by: Anilkumar Kolli <akolli@codeaurora.org>
---
V2:
  - Rebased on latest tree

 drivers/net/wireless/ath/ath11k/ahb.c     |  9 +++++++-
 drivers/net/wireless/ath/ath11k/core.h    |  1 +
 drivers/net/wireless/ath/ath11k/debugfs.c |  1 +
 drivers/net/wireless/ath/ath11k/pci.c     |  8 +++++++
 drivers/net/wireless/ath/ath11k/qmi.c     | 37 ++++++++++++++++++++-----------
 5 files changed, 42 insertions(+), 14 deletions(-)

Comments

Kalle Valo Nov. 25, 2020, 2:03 p.m. UTC | #1
Anilkumar Kolli <akolli@codeaurora.org> writes:

> QMI sequence fails if caldata file is not available.

> It is observed that 'rmmod ath11k' fails if qmi message fails.

> With this patch rmmod/insmod is working.

>

> Logs:

> Direct firmware load for IPQ8074/caldata.bin failed with error -2

> Falling back to user helper

> qmi failed to load CAL: IPQ8074/caldata.bin

> qmi failed to load board data file:-11

>

> Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-00009-QCAHKSWPL_SILICONZ-1

>

> Signed-off-by: Anilkumar Kolli <akolli@codeaurora.org>


With this patch reloading ath11k (which has worked fine before) crashes
the kernel on QCA6390 hw2.0:

Nov 25 16:00:52 nuc1 [  393.188277] BUG: unable to handle page fault for address: ffffffffc05b8e38
Nov 25 16:00:52 nuc1 [  393.188300] #PF: supervisor read access in kernel mode
Nov 25 16:00:52 nuc1 [  393.188312] #PF: error_code(0x0000) - not-present page

-- 
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
Anilkumar Kolli Nov. 30, 2020, 1:55 p.m. UTC | #2
On 2020-11-25 19:33, Kalle Valo wrote:
> Anilkumar Kolli <akolli@codeaurora.org> writes:

> 

>> QMI sequence fails if caldata file is not available.

>> It is observed that 'rmmod ath11k' fails if qmi message fails.

>> With this patch rmmod/insmod is working.

>> 

>> Logs:

>> Direct firmware load for IPQ8074/caldata.bin failed with error -2

>> Falling back to user helper

>> qmi failed to load CAL: IPQ8074/caldata.bin

>> qmi failed to load board data file:-11

>> 

>> Tested-on: IPQ8074 hw2.0 AHB 

>> WLAN.HK.2.4.0.1-00009-QCAHKSWPL_SILICONZ-1

>> 

>> Signed-off-by: Anilkumar Kolli <akolli@codeaurora.org>

> 

> With this patch reloading ath11k (which has worked fine before) crashes

> the kernel on QCA6390 hw2.0:

> 

> Nov 25 16:00:52 nuc1 [  393.188277] BUG: unable to handle page fault

> for address: ffffffffc05b8e38

> Nov 25 16:00:52 nuc1 [  393.188300] #PF: supervisor read access in 

> kernel mode

> Nov 25 16:00:52 nuc1 [  393.188312] #PF: error_code(0x0000) - 

> not-present page


I will test this in QCA6390 and update.
Which branch should I use for testing. master or ath11k-qca6390-bringup 
?

Thanks
Anil
Kalle Valo Nov. 30, 2020, 4:27 p.m. UTC | #3
akolli@codeaurora.org writes:

> On 2020-11-25 19:33, Kalle Valo wrote:

>> Anilkumar Kolli <akolli@codeaurora.org> writes:

>>

>>> QMI sequence fails if caldata file is not available.

>>> It is observed that 'rmmod ath11k' fails if qmi message fails.

>>> With this patch rmmod/insmod is working.

>>>

>>> Logs:

>>> Direct firmware load for IPQ8074/caldata.bin failed with error -2

>>> Falling back to user helper

>>> qmi failed to load CAL: IPQ8074/caldata.bin

>>> qmi failed to load board data file:-11

>>>

>>> Tested-on: IPQ8074 hw2.0 AHB

>>> WLAN.HK.2.4.0.1-00009-QCAHKSWPL_SILICONZ-1

>>>

>>> Signed-off-by: Anilkumar Kolli <akolli@codeaurora.org>

>>

>> With this patch reloading ath11k (which has worked fine before) crashes

>> the kernel on QCA6390 hw2.0:

>>

>> Nov 25 16:00:52 nuc1 [  393.188277] BUG: unable to handle page fault

>> for address: ffffffffc05b8e38

>> Nov 25 16:00:52 nuc1 [  393.188300] #PF: supervisor read access in

>> kernel mode

>> Nov 25 16:00:52 nuc1 [  393.188312] #PF: error_code(0x0000) - 

>> not-present page

>

> I will test this in QCA6390 and update.

> Which branch should I use for testing. master or

> ath11k-qca6390-bringup ?


Please use master branch.

ath11k-qca6390-bringup is just a temporary branch for collecting all
important QCA6390 patches in one place.

-- 
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
diff mbox series

Patch

diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c
index c7843f461dd2..d4ef45cd0685 100644
--- a/drivers/net/wireless/ath/ath11k/ahb.c
+++ b/drivers/net/wireless/ath/ath11k/ahb.c
@@ -747,6 +747,13 @@  static int ath11k_ahb_remove(struct platform_device *pdev)
 	struct ath11k_base *ab = platform_get_drvdata(pdev);
 	unsigned long left;
 
+	if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
+		ath11k_ahb_power_down(ab);
+		ath11k_debugfs_soc_destroy(ab);
+		ath11k_qmi_deinit_service(ab);
+		goto qmi_fail;
+	}
+
 	reinit_completion(&ab->driver_recovery);
 
 	if (test_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags)) {
@@ -760,8 +767,8 @@  static int ath11k_ahb_remove(struct platform_device *pdev)
 	cancel_work_sync(&ab->restart_work);
 
 	ath11k_core_deinit(ab);
+qmi_fail:
 	ath11k_ahb_free_irq(ab);
-
 	ath11k_hal_srng_deinit(ab);
 	ath11k_ce_free_pipes(ab);
 	ath11k_core_free(ab);
diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
index 79224ed703db..b40ce9f3ebac 100644
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -183,6 +183,7 @@  enum ath11k_dev_flags {
 	ATH11K_FLAG_RECOVERY,
 	ATH11K_FLAG_UNREGISTERING,
 	ATH11K_FLAG_REGISTERED,
+	ATH11K_FLAG_QMI_FAIL,
 };
 
 enum ath11k_monitor_flags {
diff --git a/drivers/net/wireless/ath/ath11k/debugfs.c b/drivers/net/wireless/ath/ath11k/debugfs.c
index 1b914e67d314..554feaf1ed5c 100644
--- a/drivers/net/wireless/ath/ath11k/debugfs.c
+++ b/drivers/net/wireless/ath/ath11k/debugfs.c
@@ -867,6 +867,7 @@  void ath11k_debugfs_soc_destroy(struct ath11k_base *ab)
 	debugfs_remove_recursive(ab->debugfs_ath11k);
 	ab->debugfs_ath11k = NULL;
 }
+EXPORT_SYMBOL(ath11k_debugfs_soc_destroy);
 
 void ath11k_debugfs_fw_stats_init(struct ath11k *ar)
 {
diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c
index b75f47dc36de..e535215e53b6 100644
--- a/drivers/net/wireless/ath/ath11k/pci.c
+++ b/drivers/net/wireless/ath/ath11k/pci.c
@@ -1007,10 +1007,18 @@  static void ath11k_pci_remove(struct pci_dev *pdev)
 	struct ath11k_base *ab = pci_get_drvdata(pdev);
 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
 
+	if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
+		ath11k_pci_power_down(ab);
+		ath11k_debugfs_soc_destroy(ab);
+		ath11k_qmi_deinit_service(ab);
+		goto qmi_fail;
+	}
+
 	set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
 
 	ath11k_core_deinit(ab);
 
+qmi_fail:
 	ath11k_mhi_unregister(ab_pci);
 
 	ath11k_pci_free_irq(ab);
diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c
index 8529b3328d24..619b6ec727e3 100644
--- a/drivers/net/wireless/ath/ath11k/qmi.c
+++ b/drivers/net/wireless/ath/ath11k/qmi.c
@@ -2419,7 +2419,7 @@  ath11k_qmi_driver_event_post(struct ath11k_qmi *qmi,
 	return 0;
 }
 
-static void ath11k_qmi_event_server_arrive(struct ath11k_qmi *qmi)
+static int ath11k_qmi_event_server_arrive(struct ath11k_qmi *qmi)
 {
 	struct ath11k_base *ab = qmi->ab;
 	int ret;
@@ -2427,17 +2427,19 @@  static void ath11k_qmi_event_server_arrive(struct ath11k_qmi *qmi)
 	ret = ath11k_qmi_fw_ind_register_send(ab);
 	if (ret < 0) {
 		ath11k_warn(ab, "qmi failed to send FW indication QMI:%d\n", ret);
-		return;
+		return ret;
 	}
 
 	ret = ath11k_qmi_host_cap_send(ab);
 	if (ret < 0) {
 		ath11k_warn(ab, "qmi failed to send host cap QMI:%d\n", ret);
-		return;
+		return ret;
 	}
+
+	return ret;
 }
 
-static void ath11k_qmi_event_mem_request(struct ath11k_qmi *qmi)
+static int ath11k_qmi_event_mem_request(struct ath11k_qmi *qmi)
 {
 	struct ath11k_base *ab = qmi->ab;
 	int ret;
@@ -2445,11 +2447,13 @@  static void ath11k_qmi_event_mem_request(struct ath11k_qmi *qmi)
 	ret = ath11k_qmi_respond_fw_mem_request(ab);
 	if (ret < 0) {
 		ath11k_warn(ab, "qmi failed to respond fw mem req:%d\n", ret);
-		return;
+		return ret;
 	}
+
+	return ret;
 }
 
-static void ath11k_qmi_event_load_bdf(struct ath11k_qmi *qmi)
+static int ath11k_qmi_event_load_bdf(struct ath11k_qmi *qmi)
 {
 	struct ath11k_base *ab = qmi->ab;
 	int ret;
@@ -2457,7 +2461,7 @@  static void ath11k_qmi_event_load_bdf(struct ath11k_qmi *qmi)
 	ret = ath11k_qmi_request_target_cap(ab);
 	if (ret < 0) {
 		ath11k_warn(ab, "qmi failed to req target capabilities:%d\n", ret);
-		return;
+		return ret;
 	}
 
 	if (ab->bus_params.fixed_bdf_addr)
@@ -2466,14 +2470,16 @@  static void ath11k_qmi_event_load_bdf(struct ath11k_qmi *qmi)
 		ret = ath11k_qmi_load_bdf_qmi(ab);
 	if (ret < 0) {
 		ath11k_warn(ab, "qmi failed to load board data file:%d\n", ret);
-		return;
+		return ret;
 	}
 
 	ret = ath11k_qmi_wlanfw_m3_info_send(ab);
 	if (ret < 0) {
 		ath11k_warn(ab, "qmi failed to send m3 info req:%d\n", ret);
-		return;
+		return ret;
 	}
+
+	return ret;
 }
 
 static void ath11k_qmi_msg_mem_request_cb(struct qmi_handle *qmi_hdl,
@@ -2613,7 +2619,7 @@  static int ath11k_qmi_ops_new_server(struct qmi_handle *qmi_hdl,
 	ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi wifi fw qmi service connected\n");
 	ath11k_qmi_driver_event_post(qmi, ATH11K_QMI_EVENT_SERVER_ARRIVE, NULL);
 
-	return 0;
+	return ret;
 }
 
 static void ath11k_qmi_ops_del_server(struct qmi_handle *qmi_hdl,
@@ -2637,6 +2643,7 @@  static void ath11k_qmi_driver_event_work(struct work_struct *work)
 					      event_work);
 	struct ath11k_qmi_driver_event *event;
 	struct ath11k_base *ab = qmi->ab;
+	int ret = 0;
 
 	spin_lock(&qmi->event_lock);
 	while (!list_empty(&qmi->event_list)) {
@@ -2650,17 +2657,17 @@  static void ath11k_qmi_driver_event_work(struct work_struct *work)
 
 		switch (event->type) {
 		case ATH11K_QMI_EVENT_SERVER_ARRIVE:
-			ath11k_qmi_event_server_arrive(qmi);
+			ret = ath11k_qmi_event_server_arrive(qmi);
 			break;
 		case ATH11K_QMI_EVENT_SERVER_EXIT:
 			set_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags);
 			set_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags);
 			break;
 		case ATH11K_QMI_EVENT_REQUEST_MEM:
-			ath11k_qmi_event_mem_request(qmi);
+			ret = ath11k_qmi_event_mem_request(qmi);
 			break;
 		case ATH11K_QMI_EVENT_FW_MEM_READY:
-			ath11k_qmi_event_load_bdf(qmi);
+			ret = ath11k_qmi_event_load_bdf(qmi);
 			break;
 		case ATH11K_QMI_EVENT_FW_READY:
 			if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)) {
@@ -2688,6 +2695,9 @@  static void ath11k_qmi_driver_event_work(struct work_struct *work)
 			break;
 		}
 		kfree(event);
+		if (ret < 0)
+			set_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags);
+
 		spin_lock(&qmi->event_lock);
 	}
 	spin_unlock(&qmi->event_lock);
@@ -2740,4 +2750,5 @@  void ath11k_qmi_deinit_service(struct ath11k_base *ab)
 	ath11k_qmi_m3_free(ab);
 	ath11k_qmi_free_target_mem_chunk(ab);
 }
+EXPORT_SYMBOL(ath11k_qmi_deinit_service);