Jelajahi Sumber

qcacld-3.0: Add wma handler for vdev delete and peer delete responses

- Add handler for the vdev delete and peer delete response at WMA.
- As part of timeout handler, assert if the response is not
  received in 3 seconds.

Change-Id: I7b20254013266414174f686e1f3918822adc65d8
CRs-fixed: 960173
Sandeep Puligilla 9 tahun lalu
induk
melakukan
a7512da088

+ 3 - 1
core/utils/host_diag_log/inc/host_diag_core_event.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -332,6 +332,7 @@ enum wifi_connectivity_events {
  * @WIFI_POWER_EVENT_WAKELOCK_PNO: PNO feature related
  * @WIFI_POWER_EVENT_WAKELOCK_DEL_STA: Deletion of a station
  * @WIFI_POWER_EVENT_WAKELOCK_DFS: DFS related wakelocks
+ * @WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP: Firmware response
  * @WIFI_POWER_EVENT_WAKELOCK_MISC: Miscellaneous wakelocks
  *
  * Indicates the reason for which the wakelock was taken/released
@@ -353,6 +354,7 @@ enum wake_lock_reason {
 	WIFI_POWER_EVENT_WAKELOCK_PNO,
 	WIFI_POWER_EVENT_WAKELOCK_DEL_STA,
 	WIFI_POWER_EVENT_WAKELOCK_DFS,
+	WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP,
 	WIFI_POWER_EVENT_WAKELOCK_MISC,
 };
 

+ 10 - 0
core/wma/inc/wma.h

@@ -243,6 +243,11 @@
 #define WMA_PEER_ASSOC_CNF_START 0x01
 #define WMA_PEER_ASSOC_TIMEOUT (3000) /* 3 seconds */
 
+#define WMA_DELETE_STA_RSP_START 0x02
+#define WMA_DELETE_STA_TIMEOUT (6000) /* 6 seconds */
+
+#define WMA_DEL_P2P_SELF_STA_RSP_START 0x03
+
 #define WMA_VDEV_START_REQUEST_TIMEOUT (3000)   /* 3 seconds */
 #define WMA_VDEV_STOP_REQUEST_TIMEOUT  (3000)   /* 3 seconds */
 
@@ -300,6 +305,7 @@
 #define WMA_AUTO_SHUTDOWN_WAKE_LOCK_DURATION    (5 * 1000)     /* in msec */
 #endif
 #define WMA_BMISS_EVENT_WAKE_LOCK_DURATION      (4 * 1000)     /* in msec */
+#define WMA_FW_RSP_EVENT_WAKE_LOCK_DURATION      (3 * 1000)  /* in msec */
 
 #define WMA_TXMIC_LEN 8
 #define WMA_RXMIC_LEN 8
@@ -1188,6 +1194,8 @@ struct wmi_init_cmd {
  * handle of other modules.
  * @saved_wmi_init_cmd: Saved WMI INIT command
  * @service_ready_ext_evt: Wait event for service ready ext
+ * @wmi_cmd_rsp_wake_lock: wmi command response wake lock
+ * @wmi_cmd_rsp_runtime_lock: wmi command response bus lock
  */
 typedef struct {
 	void *wmi_handle;
@@ -1373,6 +1381,8 @@ typedef struct {
 	CDF_STATUS (*pe_roam_synch_cb)(tpAniSirGlobal mac,
 		roam_offload_synch_ind *roam_synch_data,
 		tpSirBssDescription  bss_desc_ptr);
+	cdf_wake_lock_t wmi_cmd_rsp_wake_lock;
+	cdf_runtime_lock_t wmi_cmd_rsp_runtime_lock;
 } t_wma_handle, *tp_wma_handle;
 
 /**

+ 10 - 0
core/wma/inc/wma_if.h

@@ -1287,6 +1287,16 @@ struct del_sta_self_params {
 	uint32_t status;
 };
 
+/**
+ * struct del_sta_self_rsp_params - Del Sta Self response params
+ * @self_sta_param: sta params
+ * @generate_rsp: generate response to upper layers
+ */
+struct del_sta_self_rsp_params {
+	struct del_sta_self_params *self_sta_param;
+	uint8_t generate_rsp;
+};
+
 /**
  * struct tP2pPsParams - P2P powersave related params
  * @opp_ps: opportunistic power save

+ 6 - 0
core/wma/inc/wma_internal.h

@@ -1169,5 +1169,11 @@ CDF_STATUS wma_process_set_ie_info(tp_wma_handle wma,
 				   struct vdev_ie_info *ie_info);
 int wma_peer_assoc_conf_handler(void *handle, uint8_t *cmd_param_info,
 				uint32_t len);
+int wma_vdev_delete_handler(void *handle, uint8_t *cmd_param_info,
+				uint32_t len);
 
+int wma_peer_delete_handler(void *handle, uint8_t *cmd_param_info,
+				uint32_t len);
+void wma_remove_req(tp_wma_handle wma, uint8_t vdev_id,
+			    uint8_t type);
 #endif

+ 387 - 68
core/wma/src/wma_dev_if.c

@@ -297,6 +297,9 @@ static int wma_unified_vdev_delete_send(wmi_unified_t wmi_handle, uint8_t if_id)
  * @vdev_id: vdev id
  * @type: request type
  *
+ * Find target request for given vdev id & type of request.
+ * Remove that request from active list.
+ *
  * Return: return target request if found or NULL.
  */
 static struct wma_target_req *wma_find_req(tp_wma_handle wma,
@@ -349,6 +352,68 @@ static struct wma_target_req *wma_find_req(tp_wma_handle wma,
 	return req_msg;
 }
 
+/**
+ * wma_find_remove_req_msgtype() - find and remove request for vdev id
+ * @wma: wma handle
+ * @vdev_id: vdev id
+ * @msg_type: message request type
+ *
+ * Find target request for given vdev id & sub type of request.
+ * Remove the same from active list.
+ *
+ * Return: Success if request found, failure other wise
+ */
+static struct wma_target_req *wma_find_remove_req_msgtype(tp_wma_handle wma,
+					   uint8_t vdev_id, uint32_t msg_type)
+{
+	struct wma_target_req *req_msg = NULL;
+	bool found = false;
+	cdf_list_node_t *node1 = NULL, *node2 = NULL;
+	CDF_STATUS status;
+
+	cdf_spin_lock_bh(&wma->wma_hold_req_q_lock);
+	if (CDF_STATUS_SUCCESS != cdf_list_peek_front(&wma->wma_hold_req_queue,
+						      &node2)) {
+		cdf_spin_unlock_bh(&wma->wma_hold_req_q_lock);
+		WMA_LOGE(FL("unable to get msg node from request queue"));
+		return NULL;
+	}
+
+	do {
+		node1 = node2;
+		req_msg = cdf_container_of(node1, struct wma_target_req, node);
+		if (req_msg->vdev_id != vdev_id)
+			continue;
+		if (req_msg->msg_type != msg_type)
+			continue;
+
+		found = true;
+		status = cdf_list_remove_node(&wma->wma_hold_req_queue, node1);
+		if (CDF_STATUS_SUCCESS != status) {
+			cdf_spin_unlock_bh(&wma->wma_hold_req_q_lock);
+			WMA_LOGD(FL("Failed to remove request. vdev_id %d type %d"),
+				 vdev_id, msg_type);
+			return NULL;
+		}
+		break;
+	} while (CDF_STATUS_SUCCESS  ==
+			cdf_list_peek_next(&wma->wma_hold_req_queue, node1,
+					   &node2));
+
+	cdf_spin_unlock_bh(&wma->wma_hold_req_q_lock);
+	if (!found) {
+		WMA_LOGE(FL("target request not found for vdev_id %d type %d"),
+			 vdev_id, msg_type);
+		return NULL;
+	}
+
+	WMA_LOGD(FL("target request found for vdev id: %d type %d"),
+		 vdev_id, msg_type);
+
+	return req_msg;
+}
+
+
 /**
  * wma_find_vdev_req() - find target request for vdev id
  * @wma: wma handle
@@ -428,21 +493,24 @@ void wma_vdev_detach_callback(void *ctx)
 		return;
 	}
 	param = (struct del_sta_self_params *) iface->del_staself_req;
-	WMA_LOGD("%s: sending eWNI_SME_DEL_STA_SELF_RSP for vdev %d",
+	WMA_LOGE("%s: sending eWNI_SME_DEL_STA_SELF_RSP for vdev %d",
 		 __func__, param->session_id);
-
-	req_msg = wma_find_vdev_req(wma, param->session_id,
-				    WMA_TARGET_REQ_TYPE_VDEV_DEL);
-	if (req_msg) {
-		WMA_LOGD("%s: Found vdev request for vdev id %d",
-			 __func__, param->session_id);
-		cdf_mc_timer_stop(&req_msg->event_timeout);
-		cdf_mc_timer_destroy(&req_msg->event_timeout);
-		cdf_mem_free(req_msg);
+	if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
+				    WMI_SERVICE_SYNC_DELETE_CMDS)) {
+		req_msg = wma_find_vdev_req(wma, param->session_id,
+					    WMA_TARGET_REQ_TYPE_VDEV_DEL);
+		if (req_msg) {
+			WMA_LOGD("%s: Found vdev request for vdev id %d",
+				 __func__, param->session_id);
+			cdf_mc_timer_stop(&req_msg->event_timeout);
+			cdf_mc_timer_destroy(&req_msg->event_timeout);
+			cdf_mem_free(req_msg);
+		}
 	}
 	if (iface->addBssStaContext)
 		cdf_mem_free(iface->addBssStaContext);
 
+
 #if defined WLAN_FEATURE_VOWIFI_11R
 	if (iface->staKeyParams)
 		cdf_mem_free(iface->staKeyParams);
@@ -460,93 +528,127 @@ void wma_vdev_detach_callback(void *ctx)
 	}
 }
 
+
 /**
- * wma_vdev_detach() - send vdev delete command to fw
- * @wma_handle: wma handle
- * @pdel_sta_self_req_param: del sta params
- * @generateRsp: generate Response flag
+ * wma_self_peer_remove() - Self peer remove handler
+ * @wma: wma handle
+ * @del_sta_self_req_param: vdev id
+ * @generate_vdev_rsp: request type
  *
- * Return: CDF status
+ * Return: success if peer delete command sent to firmware, else failure.
  */
-CDF_STATUS wma_vdev_detach(tp_wma_handle wma_handle,
-			struct del_sta_self_params *pdel_sta_self_req_param,
-			uint8_t generateRsp)
+
+static CDF_STATUS wma_self_peer_remove(tp_wma_handle wma_handle,
+			struct del_sta_self_params *del_sta_self_req_param,
+			uint8_t generate_vdev_rsp)
 {
-	CDF_STATUS status = CDF_STATUS_SUCCESS;
 	ol_txrx_peer_handle peer;
 	ol_txrx_pdev_handle pdev;
 	uint8_t peer_id;
-	uint8_t vdev_id = pdel_sta_self_req_param->session_id;
-	struct wma_txrx_node *iface = &wma_handle->interfaces[vdev_id];
-	struct wma_target_req *msg;
-	cds_msg_t sme_msg = { 0 };
-
-	if ((iface->type == WMI_VDEV_TYPE_AP) &&
-	    (iface->sub_type == WMI_UNIFIED_VDEV_SUBTYPE_P2P_DEVICE)) {
+	uint8_t vdev_id = del_sta_self_req_param->session_id;
+	struct wma_target_req *msg = NULL;
+	struct del_sta_self_rsp_params *sta_self_wmi_rsp;
 
-		WMA_LOGA("P2P Device: removing self peer %pM",
-			 pdel_sta_self_req_param->self_mac_addr);
+	WMA_LOGE("P2P Device: removing self peer %pM",
+		 del_sta_self_req_param->self_mac_addr);
 
-		pdev = cds_get_context(CDF_MODULE_ID_TXRX);
-
-		if (NULL == pdev) {
-			WMA_LOGE("%s: Failed to get pdev", __func__);
+	pdev = cds_get_context(CDF_MODULE_ID_TXRX);
+	if (NULL == pdev) {
+		WMA_LOGE("%s: Failed to get pdev", __func__);
 			return CDF_STATUS_E_FAULT;
-		}
-
-		peer = ol_txrx_find_peer_by_addr(pdev,
-				 pdel_sta_self_req_param->self_mac_addr,
-				 &peer_id);
-		if (!peer) {
-			WMA_LOGE("%s Failed to find peer %pM", __func__,
-				 pdel_sta_self_req_param->self_mac_addr);
-		}
-		wma_remove_peer(wma_handle,
-				pdel_sta_self_req_param->self_mac_addr,
-				vdev_id, peer, false);
-	}
-	if (cdf_atomic_read(&iface->bss_status) == WMA_BSS_STATUS_STARTED) {
-		WMA_LOGA("BSS is not yet stopped. Defering vdev(vdev id %x) deletion",
-			vdev_id);
-		iface->del_staself_req = pdel_sta_self_req_param;
-		return status;
 	}
 
-	if (!iface->handle) {
-		WMA_LOGE("handle of vdev_id %d is NULL vdev is already freed",
-			 vdev_id);
-		cdf_mem_free(pdel_sta_self_req_param);
-		pdel_sta_self_req_param = NULL;
-		return status;
+	peer = ol_txrx_find_peer_by_addr(pdev,
+			 del_sta_self_req_param->self_mac_addr,
+			 &peer_id);
+	if (!peer) {
+		WMA_LOGE("%s Failed to find peer %pM", __func__,
+			 del_sta_self_req_param->self_mac_addr);
+		return CDF_STATUS_SUCCESS;
 	}
+	wma_remove_peer(wma_handle,
+			del_sta_self_req_param->self_mac_addr,
+			vdev_id, peer, false);
+
+	if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap,
+				WMI_SERVICE_SYNC_DELETE_CMDS)) {
+		sta_self_wmi_rsp =
+			cdf_mem_malloc(sizeof(struct del_sta_self_rsp_params));
+		if (sta_self_wmi_rsp == NULL) {
+			WMA_LOGP(FL("Failed to allocate memory"));
+			return CDF_STATUS_E_NOMEM;
+		}
+		sta_self_wmi_rsp->self_sta_param = del_sta_self_req_param;
+		sta_self_wmi_rsp->generate_rsp = generate_vdev_rsp;
+		msg = wma_fill_hold_req(wma_handle, vdev_id,
+				   WMA_DELETE_STA_REQ,
+				   WMA_DEL_P2P_SELF_STA_RSP_START,
+				   sta_self_wmi_rsp,
+				   WMA_DELETE_STA_TIMEOUT);
+		if (!msg) {
+			WMA_LOGP(FL("Failed to allocate request for vdev_id %d"),
+				 vdev_id);
+			wma_remove_req(wma_handle, vdev_id,
+				WMA_DEL_P2P_SELF_STA_RSP_START);
+			return CDF_STATUS_E_FAILURE;
+		}
+	}
+	return CDF_STATUS_SUCCESS;
+}
 
+static CDF_STATUS wma_handle_vdev_detach(tp_wma_handle wma_handle,
+			struct del_sta_self_params *del_sta_self_req_param,
+			uint8_t generate_rsp)
+{
+	CDF_STATUS status = CDF_STATUS_SUCCESS;
+	uint8_t vdev_id = del_sta_self_req_param->session_id;
+	struct wma_txrx_node *iface = &wma_handle->interfaces[vdev_id];
+	struct wma_target_req *msg = NULL;
+	cds_msg_t sme_msg = { 0 };
 
-	/* remove the interface from ath_dev */
 	if (wma_unified_vdev_delete_send(wma_handle->wmi_handle, vdev_id)) {
-		WMA_LOGE("Unable to remove an interface for ath_dev.");
+		WMA_LOGE("Unable to remove an interface");
 		status = CDF_STATUS_E_FAILURE;
 		goto out;
 	}
 
-	WMA_LOGD("vdev_id:%hu vdev_hdl:%p", vdev_id, iface->handle);
-	if (!generateRsp) {
+	WMA_LOGE("vdev_id:%hu vdev_hdl:%p", vdev_id, iface->handle);
+	if (!generate_rsp) {
 		WMA_LOGE("Call txrx detach w/o callback for vdev %d", vdev_id);
 		ol_txrx_vdev_detach(iface->handle, NULL, NULL);
 		goto out;
 	}
 
-	iface->del_staself_req = pdel_sta_self_req_param;
+	iface->del_staself_req = del_sta_self_req_param;
 	msg = wma_fill_vdev_req(wma_handle, vdev_id, WMA_DEL_STA_SELF_REQ,
-				WMA_TARGET_REQ_TYPE_VDEV_DEL, iface, 2000);
+				WMA_TARGET_REQ_TYPE_VDEV_DEL, iface, 6000);
 	if (!msg) {
 		WMA_LOGE("%s: Failed to fill vdev request for vdev_id %d",
 			 __func__, vdev_id);
 		status = CDF_STATUS_E_NOMEM;
 		goto out;
 	}
+
+	/* Acquire wake lock only when you expect a response from firmware */
+	if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap,
+				    WMI_SERVICE_SYNC_DELETE_CMDS)) {
+		cdf_wake_lock_timeout_acquire(
+					 &wma_handle->wmi_cmd_rsp_wake_lock,
+					 WMA_FW_RSP_EVENT_WAKE_LOCK_DURATION,
+					 WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP);
+		cdf_runtime_pm_prevent_suspend(
+					wma_handle->wmi_cmd_rsp_runtime_lock);
+	}
 	WMA_LOGD("Call txrx detach with callback for vdev %d", vdev_id);
 	ol_txrx_vdev_detach(iface->handle, NULL, NULL);
-	wma_vdev_detach_callback(iface);
+
+	/*
+	 * send the response immediately if WMI_SERVICE_SYNC_DELETE_CMDS
+	 * service is not supported by firmware
+	 */
+	if (!WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap,
+				    WMI_SERVICE_SYNC_DELETE_CMDS))
+		wma_vdev_detach_callback(iface);
 	return status;
 out:
 	if (iface->addBssStaContext)
@@ -556,20 +658,67 @@ out:
 		cdf_mem_free(iface->staKeyParams);
 #endif /* WLAN_FEATURE_VOWIFI_11R */
 	cdf_mem_zero(iface, sizeof(*iface));
-	pdel_sta_self_req_param->status = status;
-	if (generateRsp) {
+	del_sta_self_req_param->status = status;
+	if (generate_rsp) {
 		sme_msg.type = eWNI_SME_DEL_STA_SELF_RSP;
-		sme_msg.bodyptr = pdel_sta_self_req_param;
+		sme_msg.bodyptr = del_sta_self_req_param;
 		sme_msg.bodyval = 0;
 
 		status = cds_mq_post_message(CDF_MODULE_ID_SME, &sme_msg);
 		if (!CDF_IS_STATUS_SUCCESS(status)) {
-			WMA_LOGE("Failed to post eWNI_SME_ADD_STA_SELF_RSP");
-			cdf_mem_free(pdel_sta_self_req_param);
+			WMA_LOGE("Failed to post eWNI_SME_DEL_STA_SELF_RSP");
+			cdf_mem_free(del_sta_self_req_param);
 		}
 	}
 	return status;
 }
+/**
+ * wma_vdev_detach() - send vdev delete command to fw
+ * @wma_handle: wma handle
+ * @pdel_sta_self_req_param: del sta params
+ * @generateRsp: generate Response flag
+ *
+ * Return: CDF status
+ */
+CDF_STATUS wma_vdev_detach(tp_wma_handle wma_handle,
+			struct del_sta_self_params *pdel_sta_self_req_param,
+			uint8_t generateRsp)
+{
+	CDF_STATUS status = CDF_STATUS_SUCCESS;
+	uint8_t vdev_id = pdel_sta_self_req_param->session_id;
+	struct wma_txrx_node *iface = &wma_handle->interfaces[vdev_id];
+
+	if (cdf_atomic_read(&iface->bss_status) == WMA_BSS_STATUS_STARTED) {
+		WMA_LOGA("BSS is not yet stopped. Defering vdev(vdev id %x) deletion",
+			vdev_id);
+		iface->del_staself_req = pdel_sta_self_req_param;
+		return status;
+	}
+
+	if (!iface->handle) {
+		WMA_LOGE("handle of vdev_id %d is NULL vdev is already freed",
+			 vdev_id);
+		cdf_mem_free(pdel_sta_self_req_param);
+		pdel_sta_self_req_param = NULL;
+		return status;
+	}
+
+	/* P2P Device */
+	if ((iface->type == WMI_VDEV_TYPE_AP) &&
+	    (iface->sub_type == WMI_UNIFIED_VDEV_SUBTYPE_P2P_DEVICE)) {
+		wma_self_peer_remove(wma_handle, pdel_sta_self_req_param,
+					generateRsp);
+		if (!WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap,
+				WMI_SERVICE_SYNC_DELETE_CMDS))
+			status = wma_handle_vdev_detach(wma_handle,
+				pdel_sta_self_req_param, generateRsp);
+	} else {  /* other than P2P */
+		status = wma_handle_vdev_detach(wma_handle,
+				pdel_sta_self_req_param, generateRsp);
+	}
+
+	return status;
+}
 
 /**
  * wmi_unified_peer_delete_send() - send PEER delete command to fw
@@ -2275,6 +2424,123 @@ free_req_msg:
 	return status;
 }
 
+/**
+ * wma_vdev_delete_handler() - vdev delete response handler
+ * @handle: wma handle
+ * @cmd_param_info: event buffer
+ * @len: buffer length
+ *
+ * Return: 0 for success or error code
+ */
+int wma_vdev_delete_handler(void *handle, uint8_t *cmd_param_info,
+				uint32_t len)
+{
+	tp_wma_handle wma = (tp_wma_handle) handle;
+	WMI_VDEV_DELETE_RESP_EVENTID_param_tlvs *param_buf;
+	wmi_vdev_delete_cmd_fixed_param *event;
+	struct wma_target_req *req_msg;
+	int status = 0;
+
+	param_buf = (WMI_VDEV_DELETE_RESP_EVENTID_param_tlvs *)cmd_param_info;
+	if (!param_buf) {
+		WMA_LOGE("Invalid vdev delete event buffer");
+		return -EINVAL;
+	}
+
+	event = (wmi_vdev_delete_cmd_fixed_param *)param_buf->fixed_param;
+	if (!event) {
+		WMA_LOGE("Invalid vdev delete event buffer");
+		return -EINVAL;
+	}
+
+	WMA_LOGE("%s Vdev delete resp vdev id %d", __func__, event->vdev_id);
+	req_msg = wma_find_vdev_req(wma, event->vdev_id,
+				WMA_TARGET_REQ_TYPE_VDEV_DEL);
+	if (!req_msg) {
+		WMA_LOGD(FL("Vdev delete resp is not handled! vdev id %d"),
+				event->vdev_id);
+		return -EINVAL;
+	}
+	cdf_wake_lock_release(&wma->wmi_cmd_rsp_wake_lock,
+				WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP);
+	cdf_runtime_pm_allow_suspend(wma->wmi_cmd_rsp_runtime_lock);
+	/* Send response to upper layers */
+	wma_vdev_detach_callback(req_msg->user_data);
+	cdf_mc_timer_stop(&req_msg->event_timeout);
+	cdf_mc_timer_destroy(&req_msg->event_timeout);
+	cdf_mem_free(req_msg);
+
+	return status;
+}
+
+/**
+ * wma_peer_delete_handler() - peer delete response handler
+ * @handle: wma handle
+ * @cmd_param_info: event buffer
+ * @len: buffer length
+ *
+ * Return: 0 for success or error code
+ */
+int wma_peer_delete_handler(void *handle, uint8_t *cmd_param_info,
+				uint32_t len)
+{
+	tp_wma_handle wma = (tp_wma_handle) handle;
+	WMI_PEER_DELETE_RESP_EVENTID_param_tlvs *param_buf;
+	wmi_peer_delete_cmd_fixed_param *event;
+	struct wma_target_req *req_msg;
+	tDeleteStaParams *del_sta;
+	uint8_t macaddr[IEEE80211_ADDR_LEN];
+	int status = 0;
+
+	param_buf = (WMI_PEER_DELETE_RESP_EVENTID_param_tlvs *)cmd_param_info;
+	if (!param_buf) {
+		WMA_LOGE("Invalid vdev delete event buffer");
+		return -EINVAL;
+	}
+
+	event = (wmi_peer_delete_cmd_fixed_param *)param_buf->fixed_param;
+	if (!event) {
+		WMA_LOGE("Invalid vdev delete event buffer");
+		return -EINVAL;
+	}
+
+	WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->peer_macaddr, macaddr);
+	WMA_LOGE(FL("Peer Delete Response, vdev %d Peer %pM"),
+			event->vdev_id, macaddr);
+	req_msg = wma_find_remove_req_msgtype(wma, event->vdev_id,
+					WMA_DELETE_STA_REQ);
+	if (!req_msg) {
+		WMA_LOGD("Peer Delete response is not handled");
+		return -EINVAL;
+	}
+
+	cdf_wake_lock_release(&wma->wmi_cmd_rsp_wake_lock,
+				WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP);
+	cdf_runtime_pm_allow_suspend(wma->wmi_cmd_rsp_runtime_lock);
+		/* Cleanup timeout handler */
+	cdf_mc_timer_stop(&req_msg->event_timeout);
+	cdf_mc_timer_destroy(&req_msg->event_timeout);
+
+	if (req_msg->type == WMA_DELETE_STA_RSP_START) {
+		del_sta = req_msg->user_data;
+		if (del_sta->respReqd) {
+			WMA_LOGD(FL("Sending peer del rsp to umac"));
+			wma_send_msg(wma, WMA_DELETE_STA_RSP,
+				(void *)del_sta, CDF_STATUS_SUCCESS);
+		}
+	} else if (req_msg->type == WMA_DEL_P2P_SELF_STA_RSP_START) {
+		struct del_sta_self_rsp_params *data;
+		data = (struct del_sta_self_rsp_params *)req_msg->user_data;
+		WMA_LOGD(FL("Calling vdev detach handler"));
+		wma_handle_vdev_detach(wma, data->self_sta_param,
+				data->generate_rsp);
+		cdf_mem_free(data);
+	}
+	cdf_mem_free(req_msg);
+	return status;
+}
+
+
 /**
  * wma_hold_req_timer() - wma hold request timeout function
  * @data: target request params
@@ -2310,6 +2576,24 @@ void wma_hold_req_timer(void *data)
 		WMA_LOGD(FL("Sending add sta rsp to umac (mac:%pM, status:%d)"),
 			 params->staMac, params->status);
 		wma_send_msg(wma, WMA_ADD_STA_RSP, (void *)params, 0);
+	} else if ((tgt_req->msg_type == WMA_DELETE_STA_REQ) &&
+		(tgt_req->type == WMA_DELETE_STA_RSP_START)) {
+		tpDeleteStaParams params =
+				(tpDeleteStaParams) tgt_req->user_data;
+		params->status = CDF_STATUS_E_TIMEOUT;
+		WMA_LOGE(FL("WMA_DEL_STA_REQ timed out"));
+		WMA_LOGP(FL("Sending del sta rsp to umac (mac:%pM, status:%d)"),
+			 params->staMac, params->status);
+		/*
+		 * Assert in development build only.
+		 * Send response in production builds.
+		 */
+		CDF_ASSERT(0);
+		wma_send_msg(wma, WMA_DELETE_STA_RSP, (void *)params, 0);
+	} else if ((tgt_req->msg_type == WMA_DELETE_STA_REQ) &&
+		(tgt_req->type == WMA_DEL_P2P_SELF_STA_RSP_START)) {
+		WMA_LOGA(FL("wma delete sta p2p request timed out"));
+		CDF_ASSERT(0);
 	}
 free_tgt_req:
 	cdf_mc_timer_destroy(&tgt_req->event_timeout);
@@ -2342,6 +2626,7 @@ struct wma_target_req *wma_fill_hold_req(tp_wma_handle wma,
 	}
 
 	WMA_LOGE(FL("vdev_id %d msg %d type %d"), vdev_id, msg_type, type);
+
 	req->vdev_id = vdev_id;
 	req->msg_type = msg_type;
 	req->type = type;
@@ -2532,7 +2817,15 @@ void wma_vdev_resp_timer(void *data)
 		struct del_sta_self_params *params =
 			(struct del_sta_self_params *) iface->del_staself_req;
 
+		if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
+			 WMI_SERVICE_SYNC_DELETE_CMDS)) {
+			cdf_wake_lock_release(&wma->wmi_cmd_rsp_wake_lock,
+				WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP);
+			cdf_runtime_pm_allow_suspend(
+				wma->wmi_cmd_rsp_runtime_lock);
+		}
 		params->status = CDF_STATUS_E_TIMEOUT;
+
 		WMA_LOGA("%s: WMA_DEL_STA_SELF_REQ timedout", __func__);
 		sme_msg.type = eWNI_SME_DEL_STA_SELF_RSP;
 		sme_msg.bodyptr = iface->del_staself_req;
@@ -4056,6 +4349,7 @@ static void wma_delete_sta_req_ap_mode(tp_wma_handle wma,
 {
 	ol_txrx_pdev_handle pdev;
 	struct ol_txrx_peer_t *peer;
+	struct wma_target_req *msg;
 
 	pdev = cds_get_context(CDF_MODULE_ID_TXRX);
 
@@ -4077,6 +4371,31 @@ static void wma_delete_sta_req_ap_mode(tp_wma_handle wma,
 			false);
 	del_sta->status = CDF_STATUS_SUCCESS;
 
+	if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap,
+				    WMI_SERVICE_SYNC_DELETE_CMDS)) {
+		msg = wma_fill_hold_req(wma, del_sta->smesessionId,
+				   WMA_DELETE_STA_REQ,
+				   WMA_DELETE_STA_RSP_START, del_sta,
+				   WMA_DELETE_STA_TIMEOUT);
+		if (!msg) {
+			WMA_LOGP(FL("Failed to allocate request. vdev_id %d"),
+				 del_sta->smesessionId);
+			wma_remove_req(wma, del_sta->smesessionId,
+				WMA_DELETE_STA_RSP_START);
+			del_sta->status = CDF_STATUS_E_NOMEM;
+			goto send_del_rsp;
+		}
+		/*
+		 * Acquire wake lock and bus lock till
+		 * firmware sends the response
+		 */
+		cdf_wake_lock_timeout_acquire(&wma->wmi_cmd_rsp_wake_lock,
+				      WMA_FW_RSP_EVENT_WAKE_LOCK_DURATION,
+				      WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP);
+		cdf_runtime_pm_prevent_suspend(wma->wmi_cmd_rsp_runtime_lock);
+		return;
+	}
+
 send_del_rsp:
 	if (del_sta->respReqd) {
 		WMA_LOGD("%s: Sending del rsp to umac (status: %d)",

+ 15 - 1
core/wma/src/wma_main.c

@@ -1937,14 +1937,26 @@ CDF_STATUS wma_open(void *cds_context,
 				WMI_RSSI_BREACH_EVENTID,
 				wma_rssi_breached_event_handler);
 
+	cdf_wake_lock_init(&wma_handle->wmi_cmd_rsp_wake_lock,
+				"wlan_fw_rsp_wakelock");
+	wma_handle->wmi_cmd_rsp_runtime_lock =
+			cdf_runtime_lock_init("wlan_fw_rsp_runtime_lock");
+
 	/* Register peer assoc conf event handler */
 	wmi_unified_register_event_handler(wma_handle->wmi_handle,
 					   WMI_PEER_ASSOC_CONF_EVENTID,
 					   wma_peer_assoc_conf_handler);
-
+	wmi_unified_register_event_handler(wma_handle->wmi_handle,
+					   WMI_VDEV_DELETE_RESP_EVENTID,
+					   wma_vdev_delete_handler);
+	wmi_unified_register_event_handler(wma_handle->wmi_handle,
+					   WMI_PEER_DELETE_RESP_EVENTID,
+					   wma_peer_delete_handler);
 	return CDF_STATUS_SUCCESS;
 
 err_dbglog_init:
+	cdf_wake_lock_destroy(&wma_handle->wmi_cmd_rsp_wake_lock);
+	cdf_runtime_lock_deinit(wma_handle->wmi_cmd_rsp_runtime_lock);
 	cdf_spinlock_destroy(&wma_handle->vdev_respq_lock);
 	cdf_spinlock_destroy(&wma_handle->wma_hold_req_q_lock);
 err_event_init:
@@ -3094,6 +3106,8 @@ CDF_STATUS wma_close(void *cds_ctx)
 	cdf_event_destroy(&wma_handle->recovery_event);
 	wma_cleanup_vdev_resp(wma_handle);
 	wma_cleanup_hold_req(wma_handle);
+	cdf_wake_lock_destroy(&wma_handle->wmi_cmd_rsp_wake_lock);
+	cdf_runtime_lock_deinit(wma_handle->wmi_cmd_rsp_runtime_lock);
 	for (idx = 0; idx < wma_handle->num_mem_chunks; ++idx) {
 		cdf_os_mem_free_consistent(wma_handle->cdf_dev,
 					   wma_handle->mem_chunks[idx].len,