From 35008baacb01ef584a75708d7c75e949eabab8e6 Mon Sep 17 00:00:00 2001 From: Dustin Brown Date: Thu, 23 Aug 2018 14:34:21 -0700 Subject: [PATCH] qcacld-3.0: Stop bus bandwidth work with timer The bus bandwidth compute timer is a periodic timer which computes bus bandwidth usage of associated adapters over a period of time. When the last adapter disassociates, this timer is stopped. However, the timer starts a work that is not stopped or flushed at this time. When the device is under load from external subsystems, this work can get pushed out past what is safe. When the bus bandwidth timer is stopped, also stop and flush the bus bandwidth work to ensure safe memory access. Change-Id: I32c15b42c9756341d1ecf534c05f87738fd24edb CRs-Fixed: 2300697 --- core/hdd/inc/wlan_hdd_main.h | 15 ---------- core/hdd/src/wlan_hdd_main.c | 54 +++++++++++++----------------------- 2 files changed, 20 insertions(+), 49 deletions(-) diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 4aa3b74d69bd..a36866ce65af 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -2257,16 +2257,6 @@ int hdd_bus_bandwidth_init(struct hdd_context *hdd_ctx); */ void hdd_bus_bandwidth_deinit(struct hdd_context *hdd_ctx); -/** - * hdd_bus_bw_cancel_work() - Cancel the bus_bw_work worker - * @hdd_ctx: HDD context - * - * Cancel the bus_bw_work to stop monitor link state. - * - * Return: None. - */ -void hdd_bus_bw_cancel_work(struct hdd_context *hdd_ctx); - #define GET_CUR_RX_LVL(config) ((config)->cur_rx_level) #define GET_BW_COMPUTE_INTV(config) ((config)->busBandwidthComputeInterval) @@ -2303,11 +2293,6 @@ void hdd_bus_bandwidth_deinit(struct hdd_context *hdd_ctx) { } -static inline -void hdd_bus_bw_cancel_work(struct hdd_context *hdd_ctx) -{ -} - #define GET_CUR_RX_LVL(config) 0 #define GET_BW_COMPUTE_INTV(config) 0 diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 4aa646b30a71..0c8600752b58 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -4996,19 +4996,6 @@ err_free_netdev: return NULL; } -#ifdef MSM_PLATFORM -static inline -void hdd_cancel_bus_bw_work(struct hdd_context *hdd_ctx) -{ - cancel_work_sync(&hdd_ctx->bus_bw_work); -} -#else -static inline -void hdd_cancel_bus_bw_work(struct hdd_context *hdd_ctx) -{ -} -#endif - QDF_STATUS hdd_close_adapter(struct hdd_context *hdd_ctx, struct hdd_adapter *adapter, bool rtnl_held) { @@ -5021,9 +5008,7 @@ QDF_STATUS hdd_close_adapter(struct hdd_context *hdd_ctx, struct hdd_adapter *ad * work to access a particularly destroyed adapter, leading to * use-after-free. */ - hdd_debug("wait for bus bw work to flush"); hdd_bus_bw_compute_timer_stop(hdd_ctx); - hdd_bus_bw_cancel_work(hdd_ctx); qdf_list_destroy(&adapter->blocked_scan_request_q); qdf_mutex_destroy(&adapter->blocked_scan_request_q_lock); @@ -7616,6 +7601,8 @@ static void hdd_bus_bw_work_handler(struct work_struct *work) bool connected = false; uint32_t ipa_tx_packets = 0, ipa_rx_packets = 0; + hdd_enter(); + if (wlan_hdd_validate_context(hdd_ctx)) return; @@ -7716,6 +7703,8 @@ restart_timer: qdf_timer_mod(&hdd_ctx->bus_bw_timer, hdd_ctx->config->busBandwidthComputeInterval); qdf_spinlock_release(&hdd_ctx->bus_bw_timer_lock); + + hdd_exit(); } /** @@ -7751,38 +7740,33 @@ static void hdd_bus_bw_cbk(void *arg) int hdd_bus_bandwidth_init(struct hdd_context *hdd_ctx) { + hdd_enter(); + spin_lock_init(&hdd_ctx->bus_bw_lock); - INIT_WORK(&hdd_ctx->bus_bw_work, - hdd_bus_bw_work_handler); + INIT_WORK(&hdd_ctx->bus_bw_work, hdd_bus_bw_work_handler); hdd_ctx->bus_bw_timer_running = false; qdf_spinlock_create(&hdd_ctx->bus_bw_timer_lock); - qdf_timer_init(NULL, - &hdd_ctx->bus_bw_timer, - hdd_bus_bw_cbk, (void *)hdd_ctx, - QDF_TIMER_TYPE_SW); + qdf_timer_init(NULL, &hdd_ctx->bus_bw_timer, hdd_bus_bw_cbk, + (void *)hdd_ctx, QDF_TIMER_TYPE_SW); + + hdd_exit(); return 0; } void hdd_bus_bandwidth_deinit(struct hdd_context *hdd_ctx) { - if (hdd_ctx->bus_bw_timer_running) - hdd_reset_tcp_delack(hdd_ctx); + hdd_enter(); + + hdd_bus_bw_compute_timer_stop(hdd_ctx); - hdd_debug("wait for bus bw work to flush"); - hdd_cancel_bus_bw_work(hdd_ctx); qdf_timer_free(&hdd_ctx->bus_bw_timer); - hdd_ctx->bus_bw_timer_running = false; qdf_spinlock_destroy(&hdd_ctx->bus_bw_timer_lock); + + hdd_exit(); } -void hdd_bus_bw_cancel_work(struct hdd_context *hdd_ctx) -{ - if (hdd_ctx) - cancel_work_sync(&hdd_ctx->bus_bw_work); -} - -#endif +#endif /* MSM_PLATFORM */ /** * wlan_hdd_init_tx_rx_histogram() - init tx/rx histogram stats @@ -12025,10 +12009,12 @@ static void __hdd_bus_bw_compute_timer_stop(struct hdd_context *hdd_ctx) ucfg_ipa_set_perf_level(hdd_ctx->hdd_pdev, 0, 0); qdf_spinlock_acquire(&hdd_ctx->bus_bw_timer_lock); - qdf_timer_stop(&hdd_ctx->bus_bw_timer); hdd_ctx->bus_bw_timer_running = false; + qdf_timer_sync_cancel(&hdd_ctx->bus_bw_timer); qdf_spinlock_release(&hdd_ctx->bus_bw_timer_lock); + /* work callback is long running; flush outside of lock */ + cancel_work_sync(&hdd_ctx->bus_bw_work); hdd_reset_tcp_delack(hdd_ctx); }