qcacld-3.0: Acquire wakelock before sending VDEV_STOP
The host driver should not attempt to power collapse while pending
VDEV_STOP commands are in flight. Acquire a wakelock before sending a
VDEV_STOP request to firmware, and release it upon receipt of VDEV_STOP
response.
Change-Id: Iac90fc249e9571090df6948ed931cc07b67e938d
CRs-Fixed: 2014496
diff --git a/core/wma/inc/wma_internal.h b/core/wma/inc/wma_internal.h
index 4692319..3835f95 100644
--- a/core/wma/inc/wma_internal.h
+++ b/core/wma/inc/wma_internal.h
@@ -1239,4 +1239,36 @@
};
#endif /* FEATURE_WLAN_DIAG_SUPPORT */
+/**
+ * wma_acquire_wmi_resp_wakelock() - acquire the WMI response wakelock
+ * @wma: the WMA handle containing the wakelock to acquire
+ * @msec: the wakelock duration in milliseconds
+ *
+ * Return: void
+ */
+void wma_acquire_wmi_resp_wakelock(t_wma_handle *wma, uint32_t msec);
+
+/**
+ * wma_release_wmi_resp_wakelock() - release the WMI response wakelock
+ * @wma: the WMA handle containing the wakelock to release
+ *
+ * Return: void
+ */
+void wma_release_wmi_resp_wakelock(t_wma_handle *wma);
+
+/**
+ * wma_send_vdev_stop_to_fw() - send the vdev stop command to firmware
+ * @wma: the WMA handle containing a reference to the wmi_handle to use
+ * @vdev_id: the VDEV Id of the VDEV to stop
+ *
+ * This is a helper function that acquires the WMI response wakelock before
+ * sending down the VDEV_STOP command to firmware. This wakelock is
+ * automatically released on failure. Consumers should call
+ * wma_release_wmi_resp_wakelock() upon receipt of the VDEV_STOP response from
+ * firmware, to avoid power penalties.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS wma_send_vdev_stop_to_fw(t_wma_handle *wma, uint8_t vdev_id);
+
#endif
diff --git a/core/wma/src/wma_data.c b/core/wma/src/wma_data.c
index 84da522..2bbc736 100644
--- a/core/wma/src/wma_data.c
+++ b/core/wma/src/wma_data.c
@@ -1223,7 +1223,7 @@
wma->interfaces[vdev_id].handle,
OL_TXQ_PAUSE_REASON_VDEV_STOP);
wma->interfaces[vdev_id].pause_bitmap |= (1 << PAUSE_TYPE_HOST);
- if (wmi_unified_vdev_stop_send(wma->wmi_handle, vdev_id)) {
+ if (wma_send_vdev_stop_to_fw(wma, vdev_id)) {
WMA_LOGP("%s: %d Failed to send vdev stop",
__func__, __LINE__);
}
diff --git a/core/wma/src/wma_dev_if.c b/core/wma/src/wma_dev_if.c
index a8196af..5c87025 100644
--- a/core/wma/src/wma_dev_if.c
+++ b/core/wma/src/wma_dev_if.c
@@ -1375,6 +1375,9 @@
struct wma_txrx_node *iface;
int32_t status = 0;
void *soc = cds_get_context(QDF_MODULE_ID_SOC);
+
+ wma_release_wmi_resp_wakelock(wma);
+
#ifdef FEATURE_AP_MCC_CH_AVOIDANCE
tpAniSirGlobal mac_ctx = cds_get_context(QDF_MODULE_ID_PE);
if (NULL == mac_ctx) {
@@ -1435,6 +1438,7 @@
tpDeleteBssParams params =
(tpDeleteBssParams) req_msg->user_data;
struct beacon_info *bcn;
+
if (resp_event->vdev_id > wma->max_bssid) {
WMA_LOGE("%s: Invalid vdev_id %d", __func__,
resp_event->vdev_id);
@@ -4578,7 +4582,7 @@
OL_TXQ_PAUSE_REASON_VDEV_STOP);
iface->pause_bitmap |= (1 << PAUSE_TYPE_HOST);
- if (wmi_unified_vdev_stop_send(wma->wmi_handle, params->smesessionId)) {
+ if (wma_send_vdev_stop_to_fw(wma, params->smesessionId)) {
WMA_LOGP("%s: %d Failed to send vdev stop", __func__, __LINE__);
wma_remove_vdev_req(wma, params->smesessionId,
WMA_TARGET_REQ_TYPE_VDEV_STOP);
diff --git a/core/wma/src/wma_mgmt.c b/core/wma/src/wma_mgmt.c
index 72387eb..1166d98 100644
--- a/core/wma/src/wma_mgmt.c
+++ b/core/wma/src/wma_mgmt.c
@@ -2933,7 +2933,7 @@
OL_TXQ_PAUSE_REASON_VDEV_STOP);
wma_handle->interfaces[pReq->sessionId].pause_bitmap |=
(1 << PAUSE_TYPE_HOST);
- if (wmi_unified_vdev_stop_send(wma_handle->wmi_handle, pReq->sessionId)) {
+ if (wma_send_vdev_stop_to_fw(wma_handle, pReq->sessionId)) {
WMA_LOGE("%s: %d Failed to send vdev stop", __func__, __LINE__);
qdf_atomic_set(&intr[pReq->sessionId].vdev_restart_params.
hidden_ssid_restart_in_progress, 0);
diff --git a/core/wma/src/wma_utils.c b/core/wma/src/wma_utils.c
index de7b851..0e3e400 100644
--- a/core/wma/src/wma_utils.c
+++ b/core/wma/src/wma_utils.c
@@ -3960,3 +3960,30 @@
return (state == WLAN_VDEV_S_RUN) ? true : false;
}
+void wma_acquire_wmi_resp_wakelock(t_wma_handle *wma, uint32_t msec)
+{
+ cds_host_diag_log_work(&wma->wmi_cmd_rsp_wake_lock,
+ msec,
+ WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP);
+ qdf_wake_lock_timeout_acquire(&wma->wmi_cmd_rsp_wake_lock, msec);
+ qdf_runtime_pm_prevent_suspend(wma->wmi_cmd_rsp_runtime_lock);
+}
+
+void wma_release_wmi_resp_wakelock(t_wma_handle *wma)
+{
+ qdf_wake_lock_release(&wma->wmi_cmd_rsp_wake_lock,
+ WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP);
+ qdf_runtime_pm_allow_suspend(wma->wmi_cmd_rsp_runtime_lock);
+}
+
+QDF_STATUS wma_send_vdev_stop_to_fw(t_wma_handle *wma, uint8_t vdev_id)
+{
+ QDF_STATUS status;
+
+ wma_acquire_wmi_resp_wakelock(wma, WMA_VDEV_STOP_REQUEST_TIMEOUT);
+ status = wmi_unified_vdev_stop_send(wma->wmi_handle, vdev_id);
+ if (QDF_IS_STATUS_ERROR(status))
+ wma_release_wmi_resp_wakelock(wma);
+
+ return status;
+}