Forráskód Böngészése

qcacld-3.0: Mitigate Rmmod/SSR deadlock

The platform driver will not allow the WLAN SoC to be removed if a
firmware down indication has been received. However, the firmware down
indication can be received in a hardware interrupt context, and so must
never block. This makes it impossible to add appropriate synchronization
to the firmware down indication handler. This all culminates in a
situation where any check to see if recovery is in progress by the WLAN
driver during rmmod will always be racy and be susceptible to deadlock.

Move remove outside of the protection of the rmmod transition, instead
protecting remove with its own transition. This relies on the platform
driver to do the serialization with recovery itself, removing the
recovery-in-progress check from WLAN.

This fix is _not_ multi-SoC compatible. However, the current platform
driver/wlan driver interface is not multi-SoC compatible either. When
this API is reworked to add multi-SoC support, this issue will need to
be revisited.

Change-Id: Iec28e822182e698427bb40fe1d7e1b39e9ddfc8b
CRs-Fixed: 2388039
Dustin Brown 6 éve
szülő
commit
8c0b5e36ca

+ 0 - 6
core/hdd/inc/wlan_hdd_main.h

@@ -322,12 +322,6 @@ enum hdd_driver_flags {
 #define HDD_SAP_CLIENT_DISCONNECT_WAKE_LOCK_DURATION \
 	WAKELOCK_DURATION_RECOMMENDED
 
-#if defined(CONFIG_HL_SUPPORT)
-#define HDD_MOD_EXIT_SSR_MAX_RETRIES 200
-#else
-#define HDD_MOD_EXIT_SSR_MAX_RETRIES 75
-#endif
-
 #define HDD_CFG_REQUEST_FIRMWARE_RETRIES (3)
 #define HDD_CFG_REQUEST_FIRMWARE_DELAY (20)
 

+ 11 - 5
core/hdd/src/wlan_hdd_driver_ops.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2019 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -601,18 +601,24 @@ static void hdd_soc_remove(struct device *dev)
 {
 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
 	struct hdd_psoc *hdd_psoc;
+	QDF_STATUS status;
 
 	if (!hdd_ctx) {
 		hdd_warn_rl("previous probe was not successful");
 		return;
 	}
-	hdd_psoc = hdd_ctx->hdd_psoc;
 
 	pr_info("%s: Removing driver v%s\n", WLAN_MODULE_NAME,
 		QWLAN_VERSIONSTR);
 
-	/* remove is triggered by rmmod, so assert we are protected by rmmod */
-	dsc_psoc_assert_trans_protected(hdd_psoc->dsc_psoc);
+	hdd_psoc = hdd_ctx->hdd_psoc;
+	status = dsc_psoc_trans_start_wait(hdd_psoc->dsc_psoc, "remove");
+	QDF_BUG(QDF_IS_STATUS_SUCCESS(status));
+	if (QDF_IS_STATUS_ERROR(status)) {
+		hdd_err("Failed to remove WLAN SoC; status:%d", status);
+		return;
+	}
+
 	dsc_psoc_wait_for_ops(hdd_psoc->dsc_psoc);
 
 	cds_set_driver_loaded(false);
@@ -640,7 +646,7 @@ static void hdd_soc_remove(struct device *dev)
 	cds_set_unload_in_progress(false);
 
 	hdd_psoc->state = psoc_state_deinit;
-	dsc_psoc_assert_trans_protected(hdd_psoc->dsc_psoc);
+	dsc_psoc_trans_stop(hdd_psoc->dsc_psoc);
 
 	hdd_psoc_ctx_destroy(&hdd_psoc);
 

+ 11 - 50
core/hdd/src/wlan_hdd_main.c

@@ -701,47 +701,6 @@ int hdd_validate_channel_and_bandwidth(struct hdd_adapter *adapter,
 	return 0;
 }
 
-/**
- * hdd_wait_for_recovery_completion() - Wait for cds recovery completion
- *
- * Block the unloading of the driver (or) interface up until the
- * cds recovery is completed
- *
- * Return: true for recovery completion else false
- */
-static bool hdd_wait_for_recovery_completion(void)
-{
-	int retry = 0;
-
-	/* Wait for recovery to complete */
-	while (cds_is_driver_recovering()) {
-		if (retry == HDD_MOD_EXIT_SSR_MAX_RETRIES/2)
-			hdd_err("Recovery in progress; wait here!!!");
-
-		if (g_is_system_reboot_triggered) {
-			hdd_info("System Reboot happening ignore unload!!");
-			return false;
-		}
-
-		msleep(1000);
-		if (retry++ == HDD_MOD_EXIT_SSR_MAX_RETRIES) {
-			hdd_err("SSR never completed, error");
-			/*
-			 * Trigger the bug_on in the internal builds, in the
-			 * customer builds self-recovery will be enabled
-			 * in those cases just return error.
-			 */
-			if (cds_is_self_recovery_enabled())
-				return false;
-			QDF_BUG(0);
-		}
-	}
-
-	hdd_info("Recovery completed successfully!");
-	return true;
-}
-
-
 static int __hdd_netdev_notifier_call(struct notifier_block *nb,
 				    unsigned long state, void *data)
 {
@@ -13610,6 +13569,17 @@ static void hdd_driver_unload(void)
 	pr_info("%s: Unloading driver v%s\n", WLAN_MODULE_NAME,
 		QWLAN_VERSIONSTR);
 
+	if (g_is_system_reboot_triggered) {
+		hdd_info("System rebooting; Skipping unload");
+		return;
+	}
+
+	if (hdd_ctx)
+		hdd_psoc_idle_timer_stop(hdd_ctx);
+
+	/* trigger SoC remove */
+	wlan_hdd_unregister_driver();
+
 	status = dsc_driver_trans_start_wait(hdd_driver->dsc_driver, "unload");
 	QDF_BUG(QDF_IS_STATUS_SUCCESS(status));
 	if (QDF_IS_STATUS_ERROR(status)) {
@@ -13619,11 +13589,6 @@ static void hdd_driver_unload(void)
 
 	dsc_driver_wait_for_ops(hdd_driver->dsc_driver);
 
-	if (!hdd_wait_for_recovery_completion()) {
-		dsc_driver_trans_stop(hdd_driver->dsc_driver);
-		return;
-	}
-
 	cds_set_driver_loaded(false);
 	cds_set_unload_in_progress(true);
 
@@ -13631,10 +13596,6 @@ static void hdd_driver_unload(void)
 		hdd_warn("External threads are still active attempting "
 			 "driver unload anyway");
 
-	if (hdd_ctx)
-		hdd_psoc_idle_timer_stop(hdd_ctx);
-
-	wlan_hdd_unregister_driver();
 	pld_deinit();
 	wlan_hdd_state_ctrl_param_destroy();
 	hdd_set_conparam(0);