From 932a9e161a3624ab737e162a1f978e308451e65e Mon Sep 17 00:00:00 2001 From: Arunk Khandavalli Date: Wed, 4 Oct 2017 12:41:27 +0530 Subject: [PATCH] qcacld-3.0: synchronize interface change timer with driver shutdown As part of the last interface down, driver starts the interface change timer to close the modules of 15seconds, if there is no request to use the interfaces from upper layer during this time the timer expiers and closes modules. There can be SSR/PDR triggered in the different context which during shutdown tries to call the respective module notifiers which can be purged/freed in the timer context. Synchronize the interface change timer callback with the shutdown using the interface change timer lock. Following steps are taken to make sure one thread is completed before other thread starts execution: * Set the respective flag of recovery inprogress or fw_down so that access to firmware is blocked. * Take the interface change lock, so if the timer callback is running it will complete the closing the modulkes, or if the uevent gets the lock it completes the calling notifiers and purges the same. * Release the interface change lock. Change-Id: I1d7f62cd0ce7268cc9a5bda2a72dae384b70a6e2 CRs-Fixed: 2100846 --- core/cds/inc/cds_sched.h | 7 +++++++ core/cds/src/cds_sched.c | 4 +--- core/hdd/src/wlan_hdd_driver_ops.c | 25 +++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/core/cds/inc/cds_sched.h b/core/cds/inc/cds_sched.h index e45639a1d6e8..e6ee6fabebd2 100644 --- a/core/cds/inc/cds_sched.h +++ b/core/cds/inc/cds_sched.h @@ -484,4 +484,11 @@ QDF_STATUS cds_shutdown_notifier_register(void (*cb)(void *priv), void *priv); */ void cds_shutdown_notifier_purge(void); +/** + * cds_shutdown_notifier_call() - Call shutdown notifier call back + * + * Call registered shutdown notifier call back to indicate about remove or + * shutdown. + */ +void cds_shutdown_notifier_call(void); #endif /* #if !defined __CDS_SCHED_H */ diff --git a/core/cds/src/cds_sched.c b/core/cds/src/cds_sched.c index 1df5a233107c..e92f9069c013 100644 --- a/core/cds/src/cds_sched.c +++ b/core/cds/src/cds_sched.c @@ -1120,7 +1120,7 @@ void cds_shutdown_notifier_purge(void) * Call registered shutdown notifier call back to indicate about remove or * shutdown. */ -static void cds_shutdown_notifier_call(void) +void cds_shutdown_notifier_call(void) { struct shutdown_notifier *notifier; unsigned long irq_flags; @@ -1153,8 +1153,6 @@ bool cds_wait_for_external_threads_completion(const char *caller_func) int count = MAX_SSR_WAIT_ITERATIONS; int r; - cds_shutdown_notifier_call(); - while (count) { r = atomic_read(&ssr_protect_entry_count); diff --git a/core/hdd/src/wlan_hdd_driver_ops.c b/core/hdd/src/wlan_hdd_driver_ops.c index 1d08f1c83999..55d6ced4ee15 100644 --- a/core/hdd/src/wlan_hdd_driver_ops.c +++ b/core/hdd/src/wlan_hdd_driver_ops.c @@ -1363,6 +1363,29 @@ static void wlan_hdd_pld_notify_handler(struct device *dev, wlan_hdd_notify_handler(state); } +static void wlan_hdd_purge_notifier(void) +{ + struct hdd_context *hdd_ctx; + + ENTER(); + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("hdd context is NULL return!!"); + return; + } + + mutex_lock(&hdd_ctx->iface_change_lock); + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(&hdd_ctx->iface_change_timer)) + qdf_mc_timer_stop(&hdd_ctx->iface_change_timer); + + cds_shutdown_notifier_call(); + cds_shutdown_notifier_purge(); + mutex_unlock(&hdd_ctx->iface_change_lock); + EXIT(); +} + /** * wlan_hdd_pld_uevent() - update driver status * @dev: device @@ -1379,6 +1402,8 @@ static void wlan_hdd_pld_uevent(struct device *dev, } else if (uevent->uevent == PLD_FW_DOWN) { cds_set_fw_state(CDS_FW_STATE_DOWN); } + + wlan_hdd_purge_notifier(); } #ifdef FEATURE_RUNTIME_PM