Browse Source

qcacmn: Cleanup roc and handle tx ack in schedule thread

To avoid different thread delete the roc context or tx context at same
time, move cleanup roc and handle tx ack in scheduler thread.

Change-Id: Idc2a5394886a2e10c3acfabe139365dd263d6c0a
CRs-Fixed: 2211827
Wu Gao 7 years ago
parent
commit
cd23d9575c

+ 42 - 6
umac/p2p/core/src/wlan_p2p_main.c

@@ -57,6 +57,10 @@ static char *p2p_get_cmd_type_str(enum p2p_cmd_type cmd_type)
 		return "P2P mgmt tx request";
 	case P2P_MGMT_TX_CANCEL:
 		return "P2P cancel mgmt tx request";
+	case P2P_CLEANUP_ROC:
+		return "P2P cleanup roc";
+	case P2P_CLEANUP_TX:
+		return "P2P cleanup tx";
 	default:
 		return "Invalid P2P command";
 	}
@@ -565,8 +569,8 @@ static QDF_STATUS p2p_suspend_handler(struct wlan_objmgr_psoc *psoc, void *arg)
 	}
 
 	/* clean up queue of p2p psoc private object */
-	p2p_cleanup_tx_queue(p2p_soc_obj);
-	p2p_cleanup_roc_queue(p2p_soc_obj);
+	p2p_cleanup_tx_sync(p2p_soc_obj, NULL);
+	p2p_cleanup_roc_sync(p2p_soc_obj, NULL);
 
 	p2p_debug("handle suspend complete");
 
@@ -818,7 +822,19 @@ QDF_STATUS p2p_psoc_object_open(struct wlan_objmgr_psoc *soc)
 	status = qdf_event_create(&p2p_soc_obj->cancel_roc_done);
 	if (status != QDF_STATUS_SUCCESS) {
 		p2p_err("failed to create cancel roc done event");
-		goto fail_event;
+		goto fail_cancel_roc;
+	}
+
+	status = qdf_event_create(&p2p_soc_obj->cleanup_roc_done);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("failed to create cleanup roc done event");
+		goto fail_cleanup_roc;
+	}
+
+	status = qdf_event_create(&p2p_soc_obj->cleanup_tx_done);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("failed to create cleanup roc done event");
+		goto fail_cleanup_tx;
 	}
 
 	qdf_runtime_lock_init(&p2p_soc_obj->roc_runtime_lock);
@@ -830,7 +846,13 @@ QDF_STATUS p2p_psoc_object_open(struct wlan_objmgr_psoc *soc)
 
 	return QDF_STATUS_SUCCESS;
 
-fail_event:
+fail_cleanup_tx:
+	qdf_event_destroy(&p2p_soc_obj->cleanup_roc_done);
+
+fail_cleanup_roc:
+	qdf_event_destroy(&p2p_soc_obj->cancel_roc_done);
+
+fail_cancel_roc:
 	qdf_list_destroy(&p2p_soc_obj->tx_q_ack);
 	qdf_list_destroy(&p2p_soc_obj->tx_q_roc);
 	qdf_list_destroy(&p2p_soc_obj->roc_q);
@@ -857,6 +879,8 @@ QDF_STATUS p2p_psoc_object_close(struct wlan_objmgr_psoc *soc)
 	p2p_unregister_pmo_handler();
 	qdf_idr_destroy(&p2p_soc_obj->p2p_idr);
 	qdf_runtime_lock_deinit(&p2p_soc_obj->roc_runtime_lock);
+	qdf_event_destroy(&p2p_soc_obj->cleanup_tx_done);
+	qdf_event_destroy(&p2p_soc_obj->cleanup_roc_done);
 	qdf_event_destroy(&p2p_soc_obj->cancel_roc_done);
 	qdf_list_destroy(&p2p_soc_obj->tx_q_ack);
 	qdf_list_destroy(&p2p_soc_obj->tx_q_roc);
@@ -948,8 +972,8 @@ QDF_STATUS p2p_psoc_stop(struct wlan_objmgr_psoc *soc)
 	p2p_mgmt_rx_action_ops(soc, false);
 
 	/* clean up queue of p2p psoc private object */
-	p2p_cleanup_tx_queue(p2p_soc_obj);
-	p2p_cleanup_roc_queue(p2p_soc_obj);
+	p2p_cleanup_tx_sync(p2p_soc_obj, NULL);
+	p2p_cleanup_roc_sync(p2p_soc_obj, NULL);
 
 	/* unrgister scan request id*/
 	ucfg_scan_unregister_requester(soc, p2p_soc_obj->scan_req_id);
@@ -1005,6 +1029,18 @@ QDF_STATUS p2p_process_cmd(struct scheduler_msg *msg)
 				msg->bodyptr);
 		qdf_mem_free(msg->bodyptr);
 		break;
+	case P2P_CLEANUP_ROC:
+		status = p2p_process_cleanup_roc_queue(
+				(struct p2p_cleanup_param *)
+				msg->bodyptr);
+		qdf_mem_free(msg->bodyptr);
+		break;
+	case P2P_CLEANUP_TX:
+		status = p2p_process_cleanup_tx_queue(
+				(struct p2p_cleanup_param *)
+				msg->bodyptr);
+		qdf_mem_free(msg->bodyptr);
+		break;
 	default:
 		p2p_err("drop unexpected message received %d",
 			msg->type);

+ 12 - 4
umac/p2p/core/src/wlan_p2p_main.h

@@ -65,12 +65,16 @@ struct tx_action_context;
  * @P2P_CANCEL_ROC_REQ:     Cancel P2P roc request
  * @P2P_MGMT_TX:            P2P tx action frame request
  * @P2P_MGMT_TX_CANCEL:     Cancel tx action frame request
+ * @P2P_CLEANUP_ROC:        Cleanup roc queue
+ * @P2P_CLEANUP_TX:         Cleanup tx mgmt queue
  */
 enum p2p_cmd_type {
 	P2P_ROC_REQ = 0,
 	P2P_CANCEL_ROC_REQ,
 	P2P_MGMT_TX,
 	P2P_MGMT_TX_CANCEL,
+	P2P_CLEANUP_ROC,
+	P2P_CLEANUP_TX,
 };
 
 /**
@@ -92,13 +96,13 @@ enum p2p_event_type {
 /**
  * struct p2p_tx_conf_event - p2p tx confirm event
  * @p2p_soc_obj:        p2p soc private object
- * @tx_cnf:             p2p tx confirm structure
- * @tx_ctx:             tx context
+ * @buf:                buffer address
+ * @status:             tx status
  */
 struct p2p_tx_conf_event {
 	struct p2p_soc_priv_obj *p2p_soc_obj;
-	struct p2p_tx_cnf *tx_cnf;
-	struct tx_action_context *tx_ctx;
+	qdf_nbuf_t nbuf;
+	uint32_t status;
 };
 
 /**
@@ -167,6 +171,8 @@ enum p2p_connection_status {
  * @start_param:      Start parameters, include callbacks and user
  *                    data to HDD
  * @cancel_roc_done:  Cancel roc done event
+ * @cleanup_roc_done: Cleanup roc done event
+ * @cleanup_tx_done:  Cleanup tx done event
  * @roc_runtime_lock: Runtime lock for roc request
  * @p2p_cb: Callbacks to protocol stack
  * @cur_roc_vdev_id:  Vdev id of current roc
@@ -181,6 +187,8 @@ struct p2p_soc_priv_obj {
 	wlan_scan_requester scan_req_id;
 	struct p2p_start_param *start_param;
 	qdf_event_t cancel_roc_done;
+	qdf_event_t cleanup_roc_done;
+	qdf_event_t cleanup_tx_done;
 	qdf_runtime_lock_t roc_runtime_lock;
 	struct p2p_protocol_callbacks p2p_cb;
 	uint32_t cur_roc_vdev_id;

+ 97 - 18
umac/p2p/core/src/wlan_p2p_off_chan_tx.c

@@ -25,6 +25,7 @@
 #include <wlan_objmgr_psoc_obj.h>
 #include <wlan_objmgr_peer_obj.h>
 #include <wlan_utility.h>
+#include <scheduler_api.h>
 #include "wlan_p2p_public_struct.h"
 #include "wlan_p2p_tgt_api.h"
 #include "wlan_p2p_ucfg_api.h"
@@ -1649,10 +1650,68 @@ QDF_STATUS p2p_ready_to_tx_frame(struct p2p_soc_priv_obj *p2p_soc_obj,
 	return status;
 }
 
-QDF_STATUS p2p_cleanup_tx_queue(struct p2p_soc_priv_obj *p2p_soc_obj)
+QDF_STATUS p2p_cleanup_tx_sync(
+	struct p2p_soc_priv_obj *p2p_soc_obj,
+	struct wlan_objmgr_vdev *vdev)
+{
+	struct scheduler_msg msg = {0};
+	struct p2p_cleanup_param *param;
+	QDF_STATUS status;
+	uint32_t vdev_id;
+
+	if (!p2p_soc_obj) {
+		p2p_err("p2p soc context is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	p2p_debug("p2p_soc_obj:%pK, vdev:%pK", p2p_soc_obj, vdev);
+	param = qdf_mem_malloc(sizeof(*param));
+	if (!param) {
+		p2p_err("failed to allocate cleanup param");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	param->p2p_soc_obj = p2p_soc_obj;
+	if (vdev)
+		vdev_id = (uint32_t)wlan_vdev_get_id(vdev);
+	else
+		vdev_id = P2P_INVALID_VDEV_ID;
+	param->vdev_id = vdev_id;
+	qdf_event_reset(&p2p_soc_obj->cleanup_tx_done);
+	msg.type = P2P_CLEANUP_TX;
+	msg.bodyptr = param;
+	msg.callback = p2p_process_cmd;
+	status = scheduler_post_msg(QDF_MODULE_ID_OS_IF, &msg);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("failed to post message");
+		qdf_mem_free(param);
+		return status;
+	}
+
+	status = qdf_wait_single_event(
+			&p2p_soc_obj->cleanup_tx_done,
+			P2P_WAIT_CLEANUP_ROC);
+
+	if (status != QDF_STATUS_SUCCESS)
+		p2p_err("wait for cleanup tx timeout, %d", status);
+
+	return status;
+}
+
+QDF_STATUS p2p_process_cleanup_tx_queue(struct p2p_cleanup_param *param)
 {
 	struct tx_action_context *curr_tx_ctx;
 	qdf_list_node_t *p_node;
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	uint32_t vdev_id;
+
+	if (!param || !(param->p2p_soc_obj)) {
+		p2p_err("Invalid cleanup param");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	p2p_soc_obj = param->p2p_soc_obj;
+	vdev_id = param->vdev_id;
 
 	p2p_debug("clean up tx queue wait for roc, size:%d",
 		  qdf_list_size(&p2p_soc_obj->tx_q_roc));
@@ -1661,9 +1720,12 @@ QDF_STATUS p2p_cleanup_tx_queue(struct p2p_soc_priv_obj *p2p_soc_obj)
 		QDF_STATUS_SUCCESS) {
 		curr_tx_ctx = qdf_container_of(p_node,
 					struct tx_action_context, node);
-		p2p_send_tx_conf(curr_tx_ctx, false);
-		qdf_mem_free(curr_tx_ctx->buf);
-		qdf_mem_free(curr_tx_ctx);
+		if ((vdev_id == P2P_INVALID_VDEV_ID) ||
+		    (vdev_id == curr_tx_ctx->vdev_id)) {
+			p2p_send_tx_conf(curr_tx_ctx, false);
+			qdf_mem_free(curr_tx_ctx->buf);
+			qdf_mem_free(curr_tx_ctx);
+		}
 	}
 
 	p2p_debug("clean up tx queue wait for ack, size:%d",
@@ -1672,12 +1734,17 @@ QDF_STATUS p2p_cleanup_tx_queue(struct p2p_soc_priv_obj *p2p_soc_obj)
 		QDF_STATUS_SUCCESS) {
 		curr_tx_ctx = qdf_container_of(p_node,
 					struct tx_action_context, node);
-		p2p_disable_tx_timer(curr_tx_ctx);
-		p2p_send_tx_conf(curr_tx_ctx, false);
-		qdf_mem_free(curr_tx_ctx->buf);
-		qdf_mem_free(curr_tx_ctx);
+		if ((vdev_id == P2P_INVALID_VDEV_ID) ||
+		    (vdev_id == curr_tx_ctx->vdev_id)) {
+			p2p_disable_tx_timer(curr_tx_ctx);
+			p2p_send_tx_conf(curr_tx_ctx, false);
+			qdf_mem_free(curr_tx_ctx->buf);
+			qdf_mem_free(curr_tx_ctx);
+		}
 	}
 
+	qdf_event_set(&p2p_soc_obj->cleanup_tx_done);
+
 	return QDF_STATUS_SUCCESS;
 }
 
@@ -1843,36 +1910,48 @@ QDF_STATUS p2p_process_mgmt_tx_cancel(
 QDF_STATUS p2p_process_mgmt_tx_ack_cnf(
 	struct p2p_tx_conf_event *tx_cnf_event)
 {
-	struct p2p_tx_cnf *tx_cnf;
+	struct p2p_tx_cnf tx_cnf;
+	struct tx_action_context *tx_ctx;
 	struct p2p_soc_priv_obj *p2p_soc_obj;
 	struct p2p_start_param *start_param;
 
 	p2p_soc_obj = tx_cnf_event->p2p_soc_obj;
-	tx_cnf = tx_cnf_event->tx_cnf;
 
 	if (!p2p_soc_obj || !(p2p_soc_obj->start_param)) {
+		qdf_nbuf_free(tx_cnf_event->nbuf);
 		p2p_err("Invalid p2p soc object or start parameters");
-		qdf_mem_free(tx_cnf);
 		return QDF_STATUS_E_INVAL;
 	}
 
+	tx_ctx = p2p_find_tx_ctx_by_nbuf(p2p_soc_obj, tx_cnf_event->nbuf);
+	qdf_nbuf_free(tx_cnf_event->nbuf);
+	if (!tx_ctx) {
+		p2p_err("can't find tx_ctx, tx ack comes late");
+		return QDF_STATUS_SUCCESS;
+	}
+
+	tx_cnf.vdev_id = tx_ctx->vdev_id;
+	tx_cnf.action_cookie = (uint64_t)tx_ctx->id;
+	tx_cnf.buf = tx_ctx->buf;
+	tx_cnf.buf_len = tx_ctx->buf_len;
+	tx_cnf.status = tx_cnf_event->status;
+
 	p2p_debug("soc:%pK, vdev_id:%d, action_cookie:%llx, len:%d, status:%d, buf:%pK",
-		p2p_soc_obj->soc, tx_cnf->vdev_id,
-		tx_cnf->action_cookie, tx_cnf->buf_len,
-		tx_cnf->status, tx_cnf->buf);
+		p2p_soc_obj->soc, tx_cnf.vdev_id,
+		tx_cnf.action_cookie, tx_cnf.buf_len,
+		tx_cnf.status, tx_cnf.buf);
 
 	/* disable tx timer */
-	p2p_disable_tx_timer(tx_cnf_event->tx_ctx);
+	p2p_disable_tx_timer(tx_ctx);
 
 	start_param = p2p_soc_obj->start_param;
 	if (start_param->tx_cnf_cb)
 		start_param->tx_cnf_cb(start_param->tx_cnf_cb_data,
-					tx_cnf);
+					&tx_cnf);
 	else
 		p2p_debug("Got tx conf, but no valid up layer callback");
 
-	p2p_remove_tx_context(tx_cnf_event->tx_ctx);
-	qdf_mem_free(tx_cnf);
+	p2p_remove_tx_context(tx_ctx);
 
 	return QDF_STATUS_SUCCESS;
 }

+ 18 - 5
umac/p2p/core/src/wlan_p2p_off_chan_tx.h

@@ -155,7 +155,6 @@ struct p2p_frame_info {
  * @off_chan:       Is this off channel tx
  * @no_cck:         Required cck or not
  * @no_ack:         Required ack or not
- * @is_deleting:    Received tx ack and waiting for deleting
  * @duration:       Duration for the RoC
  * @tx_timer:       RoC timer
  * @frame_info:     Frame type information
@@ -173,7 +172,6 @@ struct tx_action_context {
 	bool off_chan;
 	bool no_cck;
 	bool no_ack;
-	bool is_deleting;
 	uint32_t duration;
 	qdf_mc_timer_t tx_timer;
 	struct p2p_frame_info frame_info;
@@ -205,14 +203,29 @@ QDF_STATUS p2p_ready_to_tx_frame(struct p2p_soc_priv_obj *p2p_soc_obj,
 	uint64_t cookie);
 
 /**
- * p2p_cleanup_tx_queue() - cleanup tx queue
- * @p2p_soc_obj: p2p soc private object
+ * p2p_cleanup_tx_sync() - Cleanup tx queue
+ * @p2p_soc_obj: p2p psoc private object
+ * @vdev:        vdev object
+ *
+ * This function cleanup tx context in queue until cancellation done.
+ * To avoid deadlock, don't call from scheduler thread.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_cleanup_tx_sync(
+	struct p2p_soc_priv_obj *p2p_soc_obj,
+	struct wlan_objmgr_vdev *vdev);
+
+/**
+ * p2p_process_cleanup_tx_queue() - process the message to cleanup tx
+ * @param: pointer to cleanup parameters
  *
  * This function cleanup wait for roc queue and wait for ack queue.
  *
  * Return: QDF_STATUS_SUCCESS - in case of success
  */
-QDF_STATUS p2p_cleanup_tx_queue(struct p2p_soc_priv_obj *p2p_soc_obj);
+QDF_STATUS p2p_process_cleanup_tx_queue(
+	struct p2p_cleanup_param *param);
 
 /**
  * p2p_process_mgmt_tx() - Process mgmt frame tx request

+ 73 - 75
umac/p2p/core/src/wlan_p2p_roc.c

@@ -652,94 +652,89 @@ QDF_STATUS p2p_restart_roc_timer(struct p2p_roc_context *roc_ctx)
 	return status;
 }
 
-QDF_STATUS p2p_cleanup_roc_queue(struct p2p_soc_priv_obj *p2p_soc_obj)
+QDF_STATUS p2p_cleanup_roc_sync(
+	struct p2p_soc_priv_obj *p2p_soc_obj,
+	struct wlan_objmgr_vdev *vdev)
 {
-	struct p2p_roc_context *roc_ctx;
-	qdf_list_node_t *p_node;
-	QDF_STATUS status, ret;
-
-	p2p_debug("clean up idle roc request, roc queue size:%d",
-		  qdf_list_size(&p2p_soc_obj->roc_q));
-
-	status = qdf_list_peek_front(&p2p_soc_obj->roc_q, &p_node);
-	while (QDF_IS_STATUS_SUCCESS(status)) {
-		roc_ctx = qdf_container_of(p_node,
-				struct p2p_roc_context, node);
+	struct scheduler_msg msg = {0};
+	struct p2p_cleanup_param *param;
+	QDF_STATUS status;
+	uint32_t vdev_id;
 
-		p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d, scan_id:%d, tx ctx:%pK, chan:%d, phy_mode:%d, duration:%d, roc_type:%d, roc_state:%d",
-			  roc_ctx->p2p_soc_obj, roc_ctx,
-			  roc_ctx->vdev_id, roc_ctx->scan_id,
-			  roc_ctx->tx_ctx, roc_ctx->chan,
-			  roc_ctx->phy_mode, roc_ctx->duration,
-			  roc_ctx->roc_type, roc_ctx->roc_state);
-		status = qdf_list_peek_next(&p2p_soc_obj->roc_q,
-						p_node, &p_node);
-		if (roc_ctx->roc_state == ROC_STATE_IDLE) {
-			ret = qdf_list_remove_node(
-					&p2p_soc_obj->roc_q,
-					(qdf_list_node_t *)roc_ctx);
-			if (ret == QDF_STATUS_SUCCESS)
-				p2p_destroy_roc_ctx(roc_ctx,
-						true, false);
-			else
-				p2p_err("Failed to remove roc ctx from queue");
-		}
+	if (!p2p_soc_obj) {
+		p2p_err("p2p soc context is NULL");
+		return QDF_STATUS_E_FAILURE;
 	}
 
-	p2p_debug("clean up started roc request, roc queue size:%d",
-		  qdf_list_size(&p2p_soc_obj->roc_q));
-	status = qdf_list_peek_front(&p2p_soc_obj->roc_q, &p_node);
-	while (QDF_IS_STATUS_SUCCESS(status)) {
-		roc_ctx = qdf_container_of(p_node,
-				struct p2p_roc_context, node);
+	p2p_debug("p2p_soc_obj:%pK, vdev:%pK", p2p_soc_obj, vdev);
+	param = qdf_mem_malloc(sizeof(*param));
+	if (!param) {
+		p2p_err("failed to allocate cleanup param");
+		return QDF_STATUS_E_NOMEM;
+	}
 
-	p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d, scan_id:%d, tx_ctx:%pK, chan:%d, phy_mode:%d, duration:%d, roc_type:%d, roc_state:%d",
-		  roc_ctx->p2p_soc_obj, roc_ctx, roc_ctx->vdev_id,
-		  roc_ctx->scan_id, roc_ctx->tx_ctx, roc_ctx->chan,
-		  roc_ctx->phy_mode, roc_ctx->duration,
-		  roc_ctx->roc_type, roc_ctx->roc_state);
+	param->p2p_soc_obj = p2p_soc_obj;
+	if (vdev)
+		vdev_id = (uint32_t)wlan_vdev_get_id(vdev);
+	else
+		vdev_id = P2P_INVALID_VDEV_ID;
+	param->vdev_id = vdev_id;
+	qdf_event_reset(&p2p_soc_obj->cleanup_roc_done);
+	msg.type = P2P_CLEANUP_ROC;
+	msg.bodyptr = param;
+	msg.callback = p2p_process_cmd;
+	status = scheduler_post_msg(QDF_MODULE_ID_OS_IF, &msg);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("failed to post message");
+		qdf_mem_free(param);
+		return status;
+	}
 
-		status = qdf_list_peek_next(&p2p_soc_obj->roc_q,
-						p_node, &p_node);
-		if (roc_ctx->roc_state != ROC_STATE_IDLE) {
-			if (roc_ctx->roc_state !=
-			    ROC_STATE_CANCEL_IN_PROG)
-				p2p_execute_cancel_roc_req(roc_ctx);
+	status = qdf_wait_single_event(
+			&p2p_soc_obj->cleanup_roc_done,
+			P2P_WAIT_CLEANUP_ROC);
 
-			ret = qdf_wait_single_event(
-				&p2p_soc_obj->cancel_roc_done,
-				P2P_WAIT_CANCEL_ROC);
-			p2p_debug("roc cancellation done, return:%d", ret);
-		}
-	}
+	if (status != QDF_STATUS_SUCCESS)
+		p2p_err("wait for cleanup roc timeout, %d", status);
 
-	return QDF_STATUS_SUCCESS;
+	return status;
 }
 
-QDF_STATUS p2p_cleanup_roc_by_vdev(
-	struct p2p_soc_priv_obj *p2p_soc_obj, uint32_t vdev_id)
+QDF_STATUS p2p_process_cleanup_roc_queue(
+	struct p2p_cleanup_param *param)
 {
+	uint32_t vdev_id;
 	QDF_STATUS status, ret;
 	struct p2p_roc_context *roc_ctx;
 	qdf_list_node_t *p_node;
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+
+	if (!param || !(param->p2p_soc_obj)) {
+		p2p_err("Invalid cleanup param");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	p2p_soc_obj = param->p2p_soc_obj;
+	vdev_id = param->vdev_id;
 
-	p2p_info("clean up idle roc request, roc queue size:%d, vdev id:%d",
-		qdf_list_size(&p2p_soc_obj->roc_q), vdev_id);
+	p2p_debug("clean up idle roc request, roc queue size:%d, vdev id:%d",
+		  qdf_list_size(&p2p_soc_obj->roc_q), vdev_id);
 	status = qdf_list_peek_front(&p2p_soc_obj->roc_q, &p_node);
 	while (QDF_IS_STATUS_SUCCESS(status)) {
 		roc_ctx = qdf_container_of(p_node,
 				struct p2p_roc_context, node);
 
-		p2p_info("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d, scan_id:%d, tx ctx:%pK, chan:%d, phy_mode:%d, duration:%d, roc_type:%d, roc_state:%d",
-			roc_ctx->p2p_soc_obj, roc_ctx,
-			roc_ctx->vdev_id, roc_ctx->scan_id,
-			roc_ctx->tx_ctx, roc_ctx->chan,
-			roc_ctx->phy_mode, roc_ctx->duration,
-			roc_ctx->roc_type, roc_ctx->roc_state);
+		p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d, scan_id:%d, tx ctx:%pK, chan:%d, phy_mode:%d, duration:%d, roc_type:%d, roc_state:%d",
+			  roc_ctx->p2p_soc_obj, roc_ctx,
+			  roc_ctx->vdev_id, roc_ctx->scan_id,
+			  roc_ctx->tx_ctx, roc_ctx->chan,
+			  roc_ctx->phy_mode, roc_ctx->duration,
+			  roc_ctx->roc_type, roc_ctx->roc_state);
 		status = qdf_list_peek_next(&p2p_soc_obj->roc_q,
 						p_node, &p_node);
-		if (roc_ctx->roc_state == ROC_STATE_IDLE &&
-			roc_ctx->vdev_id == vdev_id) {
+		if ((roc_ctx->roc_state == ROC_STATE_IDLE) &&
+		    ((vdev_id == P2P_INVALID_VDEV_ID) ||
+		     (vdev_id == roc_ctx->vdev_id))) {
 			ret = qdf_list_remove_node(
 					&p2p_soc_obj->roc_q,
 					(qdf_list_node_t *)roc_ctx);
@@ -750,23 +745,24 @@ QDF_STATUS p2p_cleanup_roc_by_vdev(
 		}
 	}
 
-	p2p_info("clean up started roc request, roc queue size:%d",
-		qdf_list_size(&p2p_soc_obj->roc_q));
+	p2p_debug("clean up started roc request, roc queue size:%d",
+		  qdf_list_size(&p2p_soc_obj->roc_q));
 	status = qdf_list_peek_front(&p2p_soc_obj->roc_q, &p_node);
 	while (QDF_IS_STATUS_SUCCESS(status)) {
 		roc_ctx = qdf_container_of(p_node,
 				struct p2p_roc_context, node);
 
-		p2p_info("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d, scan_id:%d, tx ctx:%pK, chan:%d, phy_mode:%d, duration:%d, roc_type:%d, roc_state:%d",
-		roc_ctx->p2p_soc_obj, roc_ctx, roc_ctx->vdev_id,
-		roc_ctx->scan_id, roc_ctx->tx_ctx, roc_ctx->chan,
-		roc_ctx->phy_mode, roc_ctx->duration,
-		roc_ctx->roc_type, roc_ctx->roc_state);
+		p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d, scan_id:%d, tx ctx:%pK, chan:%d, phy_mode:%d, duration:%d, roc_type:%d, roc_state:%d",
+			  roc_ctx->p2p_soc_obj, roc_ctx, roc_ctx->vdev_id,
+			  roc_ctx->scan_id, roc_ctx->tx_ctx, roc_ctx->chan,
+			  roc_ctx->phy_mode, roc_ctx->duration,
+			  roc_ctx->roc_type, roc_ctx->roc_state);
 
 		status = qdf_list_peek_next(&p2p_soc_obj->roc_q,
 						p_node, &p_node);
-		if (roc_ctx->roc_state != ROC_STATE_IDLE &&
-			roc_ctx->vdev_id == vdev_id) {
+		if ((roc_ctx->roc_state != ROC_STATE_IDLE) &&
+		    ((vdev_id == P2P_INVALID_VDEV_ID) ||
+		     (vdev_id == roc_ctx->vdev_id))) {
 			if (roc_ctx->roc_state !=
 			    ROC_STATE_CANCEL_IN_PROG)
 				p2p_execute_cancel_roc_req(roc_ctx);
@@ -778,6 +774,8 @@ QDF_STATUS p2p_cleanup_roc_by_vdev(
 		}
 	}
 
+	qdf_event_set(&p2p_soc_obj->cleanup_roc_done);
+
 	return QDF_STATUS_SUCCESS;
 }
 

+ 24 - 11
umac/p2p/core/src/wlan_p2p_roc.h

@@ -29,6 +29,7 @@
 
 #define P2P_EVENT_PROPAGATE_TIME 10
 #define P2P_WAIT_CANCEL_ROC      1000
+#define P2P_WAIT_CLEANUP_ROC     2000
 
 #ifdef QCA_WIFI_3_0_EMU
 #define P2P_ROC_DURATION_MULTI_GO_PRESENT   2
@@ -111,6 +112,16 @@ struct cancel_roc_context {
 	uint64_t cookie;
 };
 
+/**
+ * struct p2p_cleanup_param - p2p cleanup parameters
+ * @p2p_soc_obj:      Pointer to SoC global p2p private object
+ * @vdev_id:          vdev id
+ */
+struct p2p_cleanup_param {
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	uint32_t vdev_id;
+};
+
 /**
  * p2p_mgmt_rx_action_ops() - register or unregister rx action callback
  * @psoc: psoc object
@@ -162,29 +173,31 @@ struct p2p_roc_context *p2p_find_roc_by_tx_ctx(
 QDF_STATUS p2p_restart_roc_timer(struct p2p_roc_context *roc_ctx);
 
 /**
- * p2p_cleanup_roc_queue() - Cleanup roc context in queue
+ * p2p_cleanup_roc_sync() - Cleanup roc context in queue
  * @p2p_soc_obj: p2p psoc private object
+ * @vdev:        vdev object
  *
  * This function cleanup roc context in queue, include the roc
- * context in progressing.
+ * context in progressing until cancellation done. To avoid deadlock,
+ * don't call from scheduler thread.
  *
  * Return: QDF_STATUS_SUCCESS - in case of success
  */
-QDF_STATUS p2p_cleanup_roc_queue(
-	struct p2p_soc_priv_obj *p2p_soc_obj);
+QDF_STATUS p2p_cleanup_roc_sync(
+	struct p2p_soc_priv_obj *p2p_soc_obj,
+	struct wlan_objmgr_vdev *vdev);
 
 /**
- * p2p_cleanup_roc_by_vdev() - Cleanup roc context by vdev id
- * @p2p_soc_obj: p2p psoc private object
- * @vdev_id:     vdev id
+ * p2p_process_cleanup_roc_queue() - process the message to cleanup roc
+ * @param: pointer to cleanup parameters
  *
- * This function cleanup roc context by vdev id, include the roc
- * context in progressing.
+ * This function process the message to cleanup roc context in queue,
+ * include the roc context in progressing.
  *
  * Return: QDF_STATUS_SUCCESS - in case of success
  */
-QDF_STATUS p2p_cleanup_roc_by_vdev(
-	struct p2p_soc_priv_obj *p2p_soc_obj, uint32_t vdev_id);
+QDF_STATUS p2p_process_cleanup_roc_queue(
+	struct p2p_cleanup_param *param);
 
 /**
  * p2p_process_roc_req() - Process roc request

+ 11 - 33
umac/p2p/dispatcher/src/wlan_p2p_tgt_api.c

@@ -123,11 +123,9 @@ QDF_STATUS tgt_p2p_mgmt_download_comp_cb(void *context,
 QDF_STATUS tgt_p2p_mgmt_ota_comp_cb(void *context, qdf_nbuf_t buf,
 	uint32_t status, void *tx_compl_params)
 {
-	struct p2p_tx_cnf *tx_cnf;
 	struct p2p_tx_conf_event *tx_conf_event;
-	struct p2p_soc_priv_obj *p2p_soc_obj;
-	struct tx_action_context *tx_ctx;
 	struct scheduler_msg msg = {0};
+	QDF_STATUS ret;
 
 	p2p_debug("context:%pK, buf:%pK, status:%d, tx complete params:%pK",
 		context, buf, status, tx_compl_params);
@@ -137,19 +135,6 @@ QDF_STATUS tgt_p2p_mgmt_ota_comp_cb(void *context, qdf_nbuf_t buf,
 		qdf_nbuf_free(buf);
 		return QDF_STATUS_E_INVAL;
 	}
-	p2p_soc_obj = (struct p2p_soc_priv_obj *)context;
-	tx_ctx = p2p_find_tx_ctx_by_nbuf(p2p_soc_obj, buf);
-	if (!tx_ctx) {
-		p2p_err("can't find tx_ctx, tx ack comes late");
-		qdf_nbuf_free(buf);
-		return QDF_STATUS_E_FAULT;
-	}
-
-	if (tx_ctx->is_deleting) {
-		p2p_info("Received duplicate tx ack");
-		return QDF_STATUS_SUCCESS;
-	}
-	tx_ctx->is_deleting = true;
 
 	tx_conf_event = qdf_mem_malloc(sizeof(*tx_conf_event));
 	if (!tx_conf_event) {
@@ -158,26 +143,19 @@ QDF_STATUS tgt_p2p_mgmt_ota_comp_cb(void *context, qdf_nbuf_t buf,
 		return QDF_STATUS_E_NOMEM;
 	}
 
-	tx_cnf = qdf_mem_malloc(sizeof(*tx_cnf));
-	if (!tx_cnf) {
-		p2p_err("Failed to allocate tx cnf");
-		qdf_nbuf_free(buf);
-		return QDF_STATUS_E_NOMEM;
-	}
-
-	qdf_nbuf_free(buf);
-	tx_cnf->vdev_id = tx_ctx->vdev_id;
-	tx_cnf->action_cookie = (uint64_t)tx_ctx->id;
-	tx_cnf->buf = tx_ctx->buf;
-	tx_cnf->buf_len = tx_ctx->buf_len;
-	tx_cnf->status = status;
-	tx_conf_event->p2p_soc_obj = p2p_soc_obj;
-	tx_conf_event->tx_cnf = tx_cnf;
-	tx_conf_event->tx_ctx = tx_ctx;
+	tx_conf_event->status = status;
+	tx_conf_event->nbuf = buf;
+	tx_conf_event->p2p_soc_obj = (struct p2p_soc_priv_obj *)context;
 	msg.type = P2P_EVENT_MGMT_TX_ACK_CNF;
 	msg.bodyptr = tx_conf_event;
 	msg.callback = p2p_process_evt;
-	scheduler_post_msg(QDF_MODULE_ID_TARGET_IF, &msg);
+	ret = scheduler_post_msg(QDF_MODULE_ID_TARGET_IF, &msg);
+	if (ret != QDF_STATUS_SUCCESS) {
+		qdf_mem_free(tx_conf_event);
+		qdf_mem_free(buf);
+		p2p_err("failed to post message");
+		return status;
+	}
 
 	return QDF_STATUS_SUCCESS;
 }

+ 2 - 5
umac/p2p/dispatcher/src/wlan_p2p_ucfg_api.c

@@ -211,9 +211,8 @@ QDF_STATUS ucfg_p2p_roc_cancel_req(struct wlan_objmgr_psoc *soc,
 
 QDF_STATUS ucfg_p2p_cleanup_roc(struct wlan_objmgr_vdev *vdev)
 {
-	struct wlan_objmgr_psoc *psoc;
 	struct p2p_soc_priv_obj *p2p_soc_obj;
-	uint32_t vdev_id;
+	struct wlan_objmgr_psoc *psoc;
 
 	p2p_debug("vdev:%pK", vdev);
 
@@ -222,7 +221,6 @@ QDF_STATUS ucfg_p2p_cleanup_roc(struct wlan_objmgr_vdev *vdev)
 		return QDF_STATUS_E_INVAL;
 	}
 
-	vdev_id = (uint32_t)wlan_vdev_get_id(vdev);
 	psoc = wlan_vdev_get_psoc(vdev);
 	if (!psoc) {
 		p2p_err("null psoc");
@@ -236,7 +234,7 @@ QDF_STATUS ucfg_p2p_cleanup_roc(struct wlan_objmgr_vdev *vdev)
 		return QDF_STATUS_E_FAILURE;
 	}
 
-	return p2p_cleanup_roc_by_vdev(p2p_soc_obj, vdev_id);
+	return p2p_cleanup_roc_sync(p2p_soc_obj, vdev);
 }
 
 QDF_STATUS ucfg_p2p_mgmt_tx(struct wlan_objmgr_psoc *soc,
@@ -293,7 +291,6 @@ QDF_STATUS ucfg_p2p_mgmt_tx(struct wlan_objmgr_psoc *soc,
 	tx_action->no_cck = mgmt_frm->no_cck;
 	tx_action->no_ack = mgmt_frm->dont_wait_for_ack;
 	tx_action->off_chan = mgmt_frm->off_chan;
-	tx_action->is_deleting = false;
 	tx_action->buf = qdf_mem_malloc(tx_action->buf_len);
 	if (!(tx_action->buf)) {
 		p2p_err("Failed to allocate buffer for action frame");