From 830c969fc9fe07f80af094d670e798f57c0cc03d Mon Sep 17 00:00:00 2001 From: Arunk Khandavalli Date: Thu, 22 Mar 2018 12:17:40 +0530 Subject: [PATCH] qcacld-3.0: Dont process driver unload during system reboot During the system reboot when the firmware goes offline before the driver unload there is no way to detect whether the it is because of the reboot or a assert in the firmware. So, the driver waits for the firmware to recover before continuing with unloading the device. Since this is a reboot case the firmware will not respawn the execution and host driver is struck. To mitigate the issue register a reboot notifier with the kernel and if reboot is triggered proceed with a fake unload. Change-Id: I33d14c393930e9ee737d38ffdb26e921fb057f29 CRs-Fixed: 2211776 --- core/hdd/src/wlan_hdd_main.c | 44 ++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 78ac8e2c82a6..c95b054d3d8a 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -78,6 +78,7 @@ #include #include #include +#include #ifdef MSM_PLATFORM #include #endif @@ -167,6 +168,7 @@ #define PANIC_ON_BUG_STR "" #endif +bool g_is_system_reboot_triggered; int wlan_start_ret_val; static DECLARE_COMPLETION(wlan_start_comp); static unsigned int dev_num = 1; @@ -297,8 +299,8 @@ int limit_off_chan_tbl[HDD_MAX_AC][HDD_MAX_OFF_CHAN_ENTRIES] = { { HDD_AC_VO_BIT, HDD_MAX_OFF_CHAN_TIME_FOR_VO }, }; -/* internal function declaration */ struct notifier_block hdd_netdev_notifier; +struct notifier_block system_reboot_notifier; struct sock *cesium_nl_srv_sock; #ifdef FEATURE_WLAN_AUTO_SHUTDOWN @@ -527,6 +529,12 @@ static bool hdd_wait_for_recovery_completion(void) 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"); @@ -545,6 +553,7 @@ static bool hdd_wait_for_recovery_completion(void) return true; } + static int __hdd_netdev_notifier_call(struct notifier_block *nb, unsigned long state, void *data) { @@ -661,6 +670,27 @@ struct notifier_block hdd_netdev_notifier = { .notifier_call = hdd_netdev_notifier_call, }; +static int system_reboot_notifier_call(struct notifier_block *nb, + unsigned long msg_type, void *_unused) +{ + switch (msg_type) { + case SYS_DOWN: + case SYS_HALT: + case SYS_POWER_OFF: + g_is_system_reboot_triggered = true; + hdd_info("reboot, reason: %ld", msg_type); + break; + default: + break; + } + + return NOTIFY_OK; +} + +struct notifier_block system_reboot_notifier = { + .notifier_call = system_reboot_notifier_call, +}; + /* variable to hold the insmod parameters */ static int con_mode; @@ -6577,6 +6607,7 @@ static void hdd_wlan_exit(struct hdd_context *hdd_ctx) hdd_deinit_all_adapters(hdd_ctx, false); } + unregister_reboot_notifier(&system_reboot_notifier); unregister_netdevice_notifier(&hdd_netdev_notifier); hdd_wlan_stop_modules(hdd_ctx, false); @@ -10542,6 +10573,12 @@ int hdd_wlan_startup(struct device *dev) goto err_wiphy_unregister; } + ret = register_reboot_notifier(&system_reboot_notifier); + if (ret) { + hdd_err("Failed to register reboot notifier: %d", ret); + goto err_unregister_netdev; + } + rtnl_held = hdd_hold_rtnl_lock(); ret = hdd_open_interfaces(hdd_ctx, rtnl_held); @@ -10601,9 +10638,11 @@ err_close_adapters: hdd_close_all_adapters(hdd_ctx, rtnl_held); err_release_rtnl_lock: + unregister_reboot_notifier(&system_reboot_notifier); if (rtnl_held) hdd_release_rtnl_lock(); +err_unregister_netdev: unregister_netdevice_notifier(&hdd_netdev_notifier); err_wiphy_unregister: @@ -11924,7 +11963,8 @@ static void __hdd_module_exit(void) return; } - hdd_wait_for_recovery_completion(); + if (!hdd_wait_for_recovery_completion()) + return; qdf_cancel_delayed_work(&hdd_ctx->iface_idle_work);