From a4ef98aab37e4aa2cf75eef5378d477b4493451b Mon Sep 17 00:00:00 2001 From: Dustin Brown Date: Tue, 17 Jan 2017 16:29:38 -0800 Subject: qcacld-3.0: Fix race condition for bandwidth timer start/restart The MC thread uses a timer to measure bandwidth usage in station and soft AP modes. This timer restarts itself periodically, which can race with the MC thread during a stop/start cycle. Fix this race condition by introducing a spinlock that protects the timer during start and restart. Change-Id: I0e86687d28fb07a0a41c9475b89f5f170e72bf77 CRs-Fixed: 1112498 --- core/hdd/inc/wlan_hdd_main.h | 5 +++-- core/hdd/src/wlan_hdd_main.c | 35 +++++++++++++++++++++++++---------- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 356f606cdbf2..420df191d375 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -1447,8 +1447,9 @@ struct hdd_context_s { /* DDR bus bandwidth compute timer */ qdf_timer_t bus_bw_timer; - bool bus_bw_timer_started; - struct work_struct bus_bw_work; + bool bus_bw_timer_running; + qdf_spinlock_t bus_bw_timer_lock; + struct work_struct bus_bw_work; int cur_vote_level; spinlock_t bus_bw_lock; int cur_rx_level; diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index c1fcd9482add..ef340f99eee7 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -5507,8 +5507,14 @@ static void hdd_bus_bw_work_handler(struct work_struct *work) hdd_ipa_set_perf_level(hdd_ctx, tx_packets, rx_packets); hdd_ipa_uc_stat_request(adapter, 2); - qdf_timer_start(&hdd_ctx->bus_bw_timer, - hdd_ctx->config->busBandwidthComputeInterval); + /* restart the periodic timer */ + qdf_spinlock_acquire(&hdd_ctx->bus_bw_timer_lock); + if (!hdd_ctx->bus_bw_timer_running) { + hdd_ctx->bus_bw_timer_running = true; + qdf_timer_start(&hdd_ctx->bus_bw_timer, + hdd_ctx->config->busBandwidthComputeInterval); + } + qdf_spinlock_release(&hdd_ctx->bus_bw_timer_lock); } /** @@ -5547,6 +5553,8 @@ int hdd_bus_bandwidth_init(hdd_context_t *hdd_ctx) spin_lock_init(&hdd_ctx->bus_bw_lock); 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, @@ -5557,12 +5565,14 @@ int hdd_bus_bandwidth_init(hdd_context_t *hdd_ctx) void hdd_bus_bandwidth_destroy(hdd_context_t *hdd_ctx) { - if (hdd_ctx->bus_bw_timer_started) + if (hdd_ctx->bus_bw_timer_running) hdd_reset_tcp_delack(hdd_ctx); hdd_info("wait for bus bw work to flush"); cancel_work_sync(&hdd_ctx->bus_bw_work); qdf_timer_free(&hdd_ctx->bus_bw_timer); + hdd_ctx->bus_bw_timer_running = false; + qdf_spinlock_destroy(&hdd_ctx->bus_bw_timer_lock); } #endif @@ -8926,12 +8936,15 @@ void hdd_start_bus_bw_compute_timer(hdd_adapter_t *adapter) { hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); - if (hdd_ctx->bus_bw_timer_started) - return; + qdf_spinlock_acquire(&hdd_ctx->bus_bw_timer_lock); + if (!hdd_ctx->bus_bw_timer_running) { + hdd_ctx->bus_bw_timer_running = true; + qdf_timer_start(&hdd_ctx->bus_bw_timer, + hdd_ctx->config->busBandwidthComputeInterval); + + } + qdf_spinlock_release(&hdd_ctx->bus_bw_timer_lock); - hdd_ctx->bus_bw_timer_started = true; - qdf_timer_start(&hdd_ctx->bus_bw_timer, - hdd_ctx->config->busBandwidthComputeInterval); } void hdd_stop_bus_bw_compute_timer(hdd_adapter_t *adapter) @@ -8941,7 +8954,7 @@ void hdd_stop_bus_bw_compute_timer(hdd_adapter_t *adapter) bool can_stop = true; hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); - if (!hdd_ctx->bus_bw_timer_started) { + if (!hdd_ctx->bus_bw_timer_running) { /* trying to stop timer, when not running is not good */ hdd_info("bus band width compute timer is not running"); return; @@ -8979,8 +8992,10 @@ void hdd_stop_bus_bw_compute_timer(hdd_adapter_t *adapter) if (can_stop == true) { /* reset the ipa perf level */ hdd_ipa_set_perf_level(hdd_ctx, 0, 0); + qdf_spinlock_acquire(&hdd_ctx->bus_bw_timer_lock); qdf_timer_stop(&hdd_ctx->bus_bw_timer); - hdd_ctx->bus_bw_timer_started = false; + hdd_ctx->bus_bw_timer_running = false; + qdf_spinlock_release(&hdd_ctx->bus_bw_timer_lock); hdd_reset_tcp_delack(hdd_ctx); } } -- cgit v1.2.3