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
This commit is contained in:
@@ -2257,16 +2257,6 @@ int hdd_bus_bandwidth_init(struct hdd_context *hdd_ctx);
|
|||||||
*/
|
*/
|
||||||
void hdd_bus_bandwidth_deinit(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_CUR_RX_LVL(config) ((config)->cur_rx_level)
|
||||||
#define GET_BW_COMPUTE_INTV(config) ((config)->busBandwidthComputeInterval)
|
#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_CUR_RX_LVL(config) 0
|
||||||
#define GET_BW_COMPUTE_INTV(config) 0
|
#define GET_BW_COMPUTE_INTV(config) 0
|
||||||
|
|
||||||
|
@@ -4996,19 +4996,6 @@ err_free_netdev:
|
|||||||
return NULL;
|
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,
|
QDF_STATUS hdd_close_adapter(struct hdd_context *hdd_ctx, struct hdd_adapter *adapter,
|
||||||
bool rtnl_held)
|
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
|
* work to access a particularly destroyed adapter, leading to
|
||||||
* use-after-free.
|
* use-after-free.
|
||||||
*/
|
*/
|
||||||
hdd_debug("wait for bus bw work to flush");
|
|
||||||
hdd_bus_bw_compute_timer_stop(hdd_ctx);
|
hdd_bus_bw_compute_timer_stop(hdd_ctx);
|
||||||
hdd_bus_bw_cancel_work(hdd_ctx);
|
|
||||||
|
|
||||||
qdf_list_destroy(&adapter->blocked_scan_request_q);
|
qdf_list_destroy(&adapter->blocked_scan_request_q);
|
||||||
qdf_mutex_destroy(&adapter->blocked_scan_request_q_lock);
|
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;
|
bool connected = false;
|
||||||
uint32_t ipa_tx_packets = 0, ipa_rx_packets = 0;
|
uint32_t ipa_tx_packets = 0, ipa_rx_packets = 0;
|
||||||
|
|
||||||
|
hdd_enter();
|
||||||
|
|
||||||
if (wlan_hdd_validate_context(hdd_ctx))
|
if (wlan_hdd_validate_context(hdd_ctx))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -7716,6 +7703,8 @@ restart_timer:
|
|||||||
qdf_timer_mod(&hdd_ctx->bus_bw_timer,
|
qdf_timer_mod(&hdd_ctx->bus_bw_timer,
|
||||||
hdd_ctx->config->busBandwidthComputeInterval);
|
hdd_ctx->config->busBandwidthComputeInterval);
|
||||||
qdf_spinlock_release(&hdd_ctx->bus_bw_timer_lock);
|
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)
|
int hdd_bus_bandwidth_init(struct hdd_context *hdd_ctx)
|
||||||
{
|
{
|
||||||
|
hdd_enter();
|
||||||
|
|
||||||
spin_lock_init(&hdd_ctx->bus_bw_lock);
|
spin_lock_init(&hdd_ctx->bus_bw_lock);
|
||||||
INIT_WORK(&hdd_ctx->bus_bw_work,
|
INIT_WORK(&hdd_ctx->bus_bw_work, hdd_bus_bw_work_handler);
|
||||||
hdd_bus_bw_work_handler);
|
|
||||||
hdd_ctx->bus_bw_timer_running = false;
|
hdd_ctx->bus_bw_timer_running = false;
|
||||||
qdf_spinlock_create(&hdd_ctx->bus_bw_timer_lock);
|
qdf_spinlock_create(&hdd_ctx->bus_bw_timer_lock);
|
||||||
qdf_timer_init(NULL,
|
qdf_timer_init(NULL, &hdd_ctx->bus_bw_timer, hdd_bus_bw_cbk,
|
||||||
&hdd_ctx->bus_bw_timer,
|
(void *)hdd_ctx, QDF_TIMER_TYPE_SW);
|
||||||
hdd_bus_bw_cbk, (void *)hdd_ctx,
|
|
||||||
QDF_TIMER_TYPE_SW);
|
hdd_exit();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void hdd_bus_bandwidth_deinit(struct hdd_context *hdd_ctx)
|
void hdd_bus_bandwidth_deinit(struct hdd_context *hdd_ctx)
|
||||||
{
|
{
|
||||||
if (hdd_ctx->bus_bw_timer_running)
|
hdd_enter();
|
||||||
hdd_reset_tcp_delack(hdd_ctx);
|
|
||||||
|
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);
|
qdf_timer_free(&hdd_ctx->bus_bw_timer);
|
||||||
hdd_ctx->bus_bw_timer_running = false;
|
|
||||||
qdf_spinlock_destroy(&hdd_ctx->bus_bw_timer_lock);
|
qdf_spinlock_destroy(&hdd_ctx->bus_bw_timer_lock);
|
||||||
|
|
||||||
|
hdd_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void hdd_bus_bw_cancel_work(struct hdd_context *hdd_ctx)
|
#endif /* MSM_PLATFORM */
|
||||||
{
|
|
||||||
if (hdd_ctx)
|
|
||||||
cancel_work_sync(&hdd_ctx->bus_bw_work);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* wlan_hdd_init_tx_rx_histogram() - init tx/rx histogram stats
|
* 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);
|
ucfg_ipa_set_perf_level(hdd_ctx->hdd_pdev, 0, 0);
|
||||||
|
|
||||||
qdf_spinlock_acquire(&hdd_ctx->bus_bw_timer_lock);
|
qdf_spinlock_acquire(&hdd_ctx->bus_bw_timer_lock);
|
||||||
qdf_timer_stop(&hdd_ctx->bus_bw_timer);
|
|
||||||
hdd_ctx->bus_bw_timer_running = false;
|
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);
|
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);
|
hdd_reset_tcp_delack(hdd_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user