Browse Source

qcacmn: remain on channel

Handles roc request, cancel roc reuqest and scan event in P2P
component.

Change-Id: I47085ddc3551e76ef042e9d72dc4b29de6c2b118
CRs-Fixed: 2006262
Wu Gao 8 years ago
parent
commit
26781f65dc

+ 16 - 4
umac/p2p/core/src/wlan_p2p_main.c

@@ -26,6 +26,7 @@
 #include <wlan_objmgr_pdev_obj.h>
 #include <wlan_objmgr_vdev_obj.h>
 #include <wlan_objmgr_peer_obj.h>
+#include <wlan_scan_ucfg_api.h>
 #include "wlan_p2p_public_struct.h"
 #include "wlan_p2p_ucfg_api.h"
 #include "wlan_p2p_tgt_api.h"
@@ -542,7 +543,13 @@ QDF_STATUS p2p_psoc_start(struct wlan_objmgr_psoc *soc,
 	tgt_p2p_register_lo_ev_handler(soc);
 	tgt_p2p_register_noa_ev_handler(soc);
 
-	p2p_debug("p2p psoc start successful");
+	/* register scan request id */
+	p2p_soc_obj->scan_req_id = ucfg_scan_register_requester(
+		soc, P2P_MODULE_NAME, tgt_p2p_scan_event_cb,
+		p2p_soc_obj);
+
+	p2p_debug("p2p psoc start successful, scan request id:%d",
+		p2p_soc_obj->scan_req_id);
 
 	return QDF_STATUS_SUCCESS;
 }
@@ -571,6 +578,12 @@ QDF_STATUS p2p_psoc_stop(struct wlan_objmgr_psoc *soc)
 		return QDF_STATUS_E_FAILURE;
 	}
 
+	/* clean up queue of p2p psoc private object */
+	p2p_cleanup_roc_queue(p2p_soc_obj);
+
+	/* unrgister scan request id*/
+	ucfg_scan_unregister_requester(soc, p2p_soc_obj->scan_req_id);
+
 	/* unregister p2p lo stop and noa event */
 	tgt_p2p_unregister_lo_ev_handler(soc);
 	tgt_p2p_unregister_noa_ev_handler(soc);
@@ -609,6 +622,7 @@ QDF_STATUS p2p_process_cmd(struct scheduler_msg *msg)
 		status = p2p_process_cancel_roc_req(
 				(struct cancel_roc_context *)
 				msg->bodyptr);
+		qdf_mem_free(msg->bodyptr);
 		break;
 	case P2P_MGMT_TX:
 		status = p2p_process_mgmt_tx(
@@ -619,6 +633,7 @@ QDF_STATUS p2p_process_cmd(struct scheduler_msg *msg)
 		status = p2p_process_mgmt_tx_cancel(
 				(struct cancel_roc_context *)
 				msg->bodyptr);
+		qdf_mem_free(msg->bodyptr);
 		break;
 	default:
 		p2p_err("drop unexpected message received %d",
@@ -627,9 +642,6 @@ QDF_STATUS p2p_process_cmd(struct scheduler_msg *msg)
 		break;
 	}
 
-	qdf_mem_free(msg->bodyptr);
-	msg->bodyptr = NULL;
-
 	return status;
 }
 

+ 712 - 2
umac/p2p/core/src/wlan_p2p_roc.c

@@ -20,20 +20,730 @@
  * DOC: This file contains RoC API definitions
  */
 
+#include <wlan_mgmt_txrx_utils_api.h>
+#include <wlan_scan_public_structs.h>
+#include <wlan_scan_ucfg_api.h>
+#include <wlan_objmgr_psoc_obj.h>
+#include <wlan_objmgr_global_obj.h>
+#include <wlan_objmgr_pdev_obj.h>
+#include <wlan_objmgr_vdev_obj.h>
+#include <wlan_policy_mgr_api.h>
+#include <wlan_utility.h>
+#include "wlan_p2p_public_struct.h"
+#include "wlan_p2p_tgt_api.h"
+#include "wlan_p2p_ucfg_api.h"
 #include "wlan_p2p_roc.h"
+#include "wlan_p2p_main.h"
+#include "wlan_p2p_off_chan_tx.h"
 
-QDF_STATUS p2p_process_roc_req(struct p2p_roc_context *roc_ctx)
+/**
+ * p2p_mgmt_rx_ops() - register or unregister rx callback
+ * @psoc: psoc object
+ * @isregister: register if true, unregister if false
+ *
+ * This function registers or unregisters rx callback to mgmt txrx
+ * component.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_mgmt_rx_ops(struct wlan_objmgr_psoc *psoc,
+	bool isregister)
+{
+	struct mgmt_txrx_mgmt_frame_cb_info frm_cb_info;
+	QDF_STATUS status;
+
+	p2p_debug("psoc:%p, is register rx:%d", psoc, isregister);
+
+	frm_cb_info.frm_type = MGMT_PROBE_REQ;
+	frm_cb_info.mgmt_rx_cb = (mgmt_frame_rx_callback)
+				tgt_p2p_mgmt_frame_rx_cb;
+
+	if (isregister)
+		status = wlan_mgmt_txrx_register_rx_cb(psoc,
+				WLAN_UMAC_COMP_P2P, &frm_cb_info, 1);
+	else
+		status = wlan_mgmt_txrx_deregister_rx_cb(psoc,
+				WLAN_UMAC_COMP_P2P, &frm_cb_info, 1);
+
+	return status;
+}
+
+/**
+ * p2p_scan_start() - Start scan
+ * @roc_ctx: remain on channel request
+ *
+ * This function trigger a start scan request to scan component.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_scan_start(struct p2p_roc_context *roc_ctx)
+{
+	QDF_STATUS status;
+	struct scan_start_request *req;
+	struct wlan_objmgr_vdev *vdev;
+	struct p2p_soc_priv_obj *p2p_soc_obj = roc_ctx->p2p_soc_obj;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(
+			p2p_soc_obj->soc, roc_ctx->vdev_id,
+			WLAN_P2P_ID);
+	if (!vdev) {
+		p2p_err("vdev is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	req = qdf_mem_malloc(sizeof(*req));
+	if (!req) {
+		p2p_err("failed to alloc scan start request");
+		status = QDF_STATUS_E_NOMEM;
+		goto fail;
+	}
+
+	ucfg_scan_init_default_params(vdev, req);
+	roc_ctx->scan_id = ucfg_scan_get_scan_id(p2p_soc_obj->soc);
+	req->vdev = vdev;
+	req->scan_req.scan_id = roc_ctx->scan_id;
+	req->scan_req.scan_req_id = p2p_soc_obj->scan_req_id;
+	req->scan_req.num_chan = 1;
+	req->scan_req.chan_list[0] = wlan_chan_to_freq(roc_ctx->chan);
+	req->scan_req.dwell_time_passive = roc_ctx->duration;
+	req->scan_req.dwell_time_active = 0;
+	qdf_set_macaddr_broadcast(&req->scan_req.bssid_list[0]);
+
+	status = ucfg_scan_start(req);
+
+	p2p_debug("start scan, scan req id:%d, scan id:%d, status:%d",
+		p2p_soc_obj->scan_req_id, roc_ctx->scan_id, status);
+fail:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
+
+	return status;
+}
+
+/**
+ * p2p_scan_abort() - Abort scan
+ * @roc_ctx: remain on channel request
+ *
+ * This function trigger an abort scan request to scan component.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_scan_abort(struct p2p_roc_context *roc_ctx)
 {
+	QDF_STATUS status;
+	struct scan_cancel_request *req;
+	struct wlan_objmgr_vdev *vdev;
+	struct p2p_soc_priv_obj *p2p_soc_obj = roc_ctx->p2p_soc_obj;
+
+	p2p_debug("abort scan, scan req id:%d, scan id:%d",
+		p2p_soc_obj->scan_req_id, roc_ctx->scan_id);
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(
+			p2p_soc_obj->soc, roc_ctx->vdev_id,
+			WLAN_P2P_ID);
+	if (!vdev) {
+		p2p_err("vdev is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	req = qdf_mem_malloc(sizeof(*req));
+	if (!req) {
+		p2p_err("failed to alloc scan cancel request");
+		status = QDF_STATUS_E_NOMEM;
+		goto fail;
+	}
+
+	req->vdev = vdev;
+	req->cancel_req.requester = p2p_soc_obj->scan_req_id;
+	req->cancel_req.scan_id = roc_ctx->scan_id;
+	req->cancel_req.vdev_id = roc_ctx->vdev_id;
+	req->cancel_req.req_type = WLAN_SCAN_CANCEL_SINGLE;
+
+	status = ucfg_scan_cancel(req);
+
+	p2p_debug("abort scan, scan req id:%d, scan id:%d, status:%d",
+		p2p_soc_obj->scan_req_id, roc_ctx->scan_id, status);
+fail:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
+
+	return status;
+}
+
+/**
+ * p2p_execute_cancel_roc_req() - Execute cancel roc request
+ * @roc_ctx: remain on channel request
+ *
+ * This function stop roc timer, abort scan and unregister mgmt rx
+ * callbak.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_execute_cancel_roc_req(
+	struct p2p_roc_context *roc_ctx)
+{
+	QDF_STATUS status;
+	struct p2p_soc_priv_obj *p2p_soc_obj = roc_ctx->p2p_soc_obj;
+
+	p2p_debug("p2p soc obj:%p, roc ctx:%p, vdev_id:%d, scan_id:%d, cookie:%llx, chan:%d, phy_mode:%d, duration:%d, roc_type:%d, roc_state:%d",
+		p2p_soc_obj, roc_ctx, roc_ctx->vdev_id,
+		roc_ctx->scan_id, roc_ctx->cookie, roc_ctx->chan,
+		roc_ctx->phy_mode, roc_ctx->duration,
+		roc_ctx->roc_type, roc_ctx->roc_state);
+
+	roc_ctx->roc_state = ROC_STATE_CANCEL_IN_PROG;
+	qdf_event_reset(&p2p_soc_obj->cancel_roc_done);
+	status = qdf_mc_timer_stop(&roc_ctx->roc_timer);
+	if (status != QDF_STATUS_SUCCESS)
+		p2p_err("Failed to stop roc timer, roc %p", roc_ctx);
+
+	status = p2p_scan_abort(roc_ctx);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("Failed to abort scan, status:%d", status);
+	}
+
 	return QDF_STATUS_SUCCESS;
 }
 
+/**
+ * p2p_roc_timeout() - Callback for roc timeout
+ * @pdata: pointer to p2p soc private object
+ *
+ * This function is callback for roc time out.
+ *
+ * Return: None
+ */
+static void p2p_roc_timeout(void *pdata)
+{
+	struct p2p_roc_context *roc_ctx;
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+
+	p2p_debug("p2p soc obj:%p", pdata);
+
+	p2p_soc_obj = pdata;
+	if (!p2p_soc_obj) {
+		p2p_err("Invalid p2p soc object");
+		return;
+	}
+
+	roc_ctx = p2p_find_current_roc_ctx(p2p_soc_obj);
+	if (!roc_ctx) {
+		p2p_debug("No P2P roc is pending");
+		return;
+	}
+
+	p2p_debug("p2p soc obj:%p, roc ctx:%p, vdev_id:%d, scan_id:%d, cookie:%llx, 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->cookie, roc_ctx->chan,
+		roc_ctx->phy_mode, roc_ctx->duration,
+		roc_ctx->roc_type, roc_ctx->roc_state);
+
+	if (roc_ctx->roc_state == ROC_STATE_CANCEL_IN_PROG) {
+		p2p_err("Cancellation already in progress");
+		return;
+	}
+	p2p_execute_cancel_roc_req(roc_ctx);
+}
+
+/**
+ * p2p_execute_roc_req() - Execute roc request
+ * @roc_ctx: remain on channel request
+ *
+ * This function init roc timer, start scan and register mgmt rx
+ * callbak.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_execute_roc_req(struct p2p_roc_context *roc_ctx)
+{
+	QDF_STATUS status;
+	uint32_t go_num;
+	struct p2p_soc_priv_obj *p2p_soc_obj = roc_ctx->p2p_soc_obj;
+
+	p2p_debug("p2p soc obj:%p, roc ctx:%p, vdev_id:%d, scan_id:%d, cookie:%llx, chan:%d, phy_mode:%d, duration:%d, roc_type:%d, roc_state:%d",
+		p2p_soc_obj, roc_ctx, roc_ctx->vdev_id,
+		roc_ctx->scan_id, roc_ctx->cookie, roc_ctx->chan,
+		roc_ctx->phy_mode, roc_ctx->duration,
+		roc_ctx->roc_type, roc_ctx->roc_state);
+
+	status = qdf_mc_timer_init(&roc_ctx->roc_timer,
+			QDF_TIMER_TYPE_SW, p2p_roc_timeout,
+			p2p_soc_obj);
+	if (status != QDF_STATUS_SUCCESS)
+		return status;
+
+	roc_ctx->roc_state = ROC_STATE_REQUESTED;
+	go_num = policy_mgr_mode_specific_connection_count(
+			p2p_soc_obj->soc, PM_P2P_GO_MODE, NULL);
+	p2p_debug("present go number:%d", go_num);
+	if (go_num)
+		roc_ctx->duration *= P2P_ROC_DURATION_MULTI_GO_PRESENT;
+	else
+		roc_ctx->duration *= P2P_ROC_DURATION_MULTI_GO_ABSENT;
+
+	status = p2p_scan_start(roc_ctx);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("Failed to start scan, status:%d", status);
+	}
+	status = p2p_mgmt_rx_ops(roc_ctx->p2p_soc_obj->soc, true);
+	if (status != QDF_STATUS_SUCCESS)
+		p2p_err("Failed to register mgmt rx callback, status:%d",
+			status);
+
+	return status;
+}
+
+/**
+ * p2p_find_roc_ctx() - Find out roc context by cookie
+ * @p2p_soc_obj: p2p psoc private object
+ * @cookie: cookie is the key to find out roc context
+ *
+ * This function find out roc context by cookie from p2p psoc private
+ * object
+ *
+ * Return: Pointer to roc context - success
+ *         NULL                   - failure
+ */
+static struct p2p_roc_context *p2p_find_roc_ctx(
+	struct p2p_soc_priv_obj *p2p_soc_obj, uint64_t cookie)
+{
+	struct p2p_roc_context *curr_roc_ctx;
+	qdf_list_node_t *tmp, *pos;
+
+	p2p_debug("p2p soc obj:%p, cookie:%llx", p2p_soc_obj, cookie);
+
+	list_for_each_safe(pos, tmp, &p2p_soc_obj->roc_q.anchor) {
+		curr_roc_ctx = list_entry(pos, struct p2p_roc_context,
+					node);
+		if ((uintptr_t) curr_roc_ctx == cookie)
+			return curr_roc_ctx;
+	}
+
+	return NULL;
+}
+
+/**
+ * p2p_send_roc_event() - Send roc event
+ * @roc_ctx: remain on channel request
+ * @evt: roc event information
+ *
+ * This function send out roc event to up layer.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_send_roc_event(
+	struct p2p_roc_context *roc_ctx, enum p2p_roc_event evt)
+{
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	struct p2p_event p2p_evt;
+	struct p2p_start_param *start_param;
+
+	p2p_soc_obj = roc_ctx->p2p_soc_obj;
+	if (!p2p_soc_obj || !(p2p_soc_obj->start_param)) {
+		p2p_err("Invalid p2p soc object or start parameters");
+		return QDF_STATUS_E_INVAL;
+	}
+	start_param = p2p_soc_obj->start_param;
+	if (!(start_param->event_cb)) {
+		p2p_err("Invalid p2p event callback to up layer");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_evt.vdev_id = roc_ctx->vdev_id;
+	p2p_evt.roc_event = evt;
+	p2p_evt.cookie = (uintptr_t)roc_ctx;
+	p2p_evt.chan = roc_ctx->chan;
+	p2p_evt.duration = roc_ctx->duration;
+
+	p2p_debug("p2p soc_obj:%p, roc_ctx:%p, vdev_id:%d, roc_event:"
+		"%d, cookie:%llx, chan:%d, duration:%d", p2p_soc_obj,
+		roc_ctx, p2p_evt.vdev_id, p2p_evt.roc_event,
+		p2p_evt.cookie, p2p_evt.chan, p2p_evt.duration);
+
+	start_param->event_cb(start_param->event_cb_data, &p2p_evt);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * p2p_process_scan_start_evt() - Process scan start event
+ * @roc_ctx: remain on channel request
+ *
+ * This function process scan start event.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_process_scan_start_evt(
+	struct p2p_roc_context *roc_ctx)
+{
+	roc_ctx->roc_state = ROC_STATE_STARTED;
+	p2p_debug("scan started, roc ctx:%p, scan id:%d",
+		roc_ctx, roc_ctx->scan_id);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * p2p_process_ready_on_channel_evt() - Process ready on channel event
+ * @roc_ctx: remain on channel request
+ *
+ * This function process ready on channel event. Starts roc timer.
+ * Indicates this event to up layer if this is user request roc. Sends
+ * mgmt frame if this is off channel rx roc.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_process_ready_on_channel_evt(
+	struct p2p_roc_context *roc_ctx)
+{
+	uint64_t cookie;
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	QDF_STATUS status;
+
+	p2p_soc_obj = roc_ctx->p2p_soc_obj;
+	roc_ctx->roc_state = ROC_STATE_ON_CHAN;
+
+	p2p_debug("p2p soc obj:%p, roc ctx:%p, vdev_id:%d, scan_id:%d, cookie:%llx, chan:%d, phy_mode:%d, duration:%d, roc_type:%d, roc_state:%d",
+		p2p_soc_obj, roc_ctx, roc_ctx->vdev_id,
+		roc_ctx->scan_id, roc_ctx->cookie, roc_ctx->chan,
+		roc_ctx->phy_mode, roc_ctx->duration,
+		roc_ctx->roc_type, roc_ctx->roc_state);
+
+	status = qdf_mc_timer_start(&roc_ctx->roc_timer,
+		(roc_ctx->duration + P2P_EVENT_PROPOGATE_TIME));
+	if (status != QDF_STATUS_SUCCESS)
+		p2p_err("Remain on Channel timer start failed");
+	if (roc_ctx->roc_type == USER_REQUESTED) {
+		p2p_debug("user required roc, send roc event");
+		status = p2p_send_roc_event(roc_ctx,
+				ROC_EVENT_READY_ON_CHAN);
+	} else {
+		p2p_debug("roc for off chan tx, ready to send frame");
+		cookie = (uintptr_t)roc_ctx;
+		/* ready to tx frame */
+	}
+
+	return status;
+}
+
+/**
+ * p2p_process_scan_complete_evt() - Process scan complete event
+ * @roc_ctx: remain on channel request
+ *
+ * This function process scan complete event.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_process_scan_complete_evt(
+	struct p2p_roc_context *roc_ctx)
+{
+	QDF_STATUS status;
+	qdf_list_node_t *next_node;
+	uint32_t size;
+	struct p2p_soc_priv_obj *p2p_soc_obj = roc_ctx->p2p_soc_obj;
+
+	p2p_debug("p2p soc obj:%p, roc ctx:%p, vdev_id:%d, scan_id:%d, cookie:%llx, chan:%d, phy_mode:%d, duration:%d, roc_type:%d, roc_state:%d",
+		p2p_soc_obj, roc_ctx, roc_ctx->vdev_id,
+		roc_ctx->scan_id, roc_ctx->cookie, roc_ctx->chan,
+		roc_ctx->phy_mode, roc_ctx->duration,
+		roc_ctx->roc_type, roc_ctx->roc_state);
+
+	status = qdf_mc_timer_stop(&roc_ctx->roc_timer);
+	if (status != QDF_STATUS_SUCCESS)
+		p2p_err("Failed to stop roc timer");
+	status = qdf_mc_timer_destroy(&roc_ctx->roc_timer);
+	if (status != QDF_STATUS_SUCCESS)
+		p2p_err("Failed to destroy roc timer");
+
+	status = p2p_mgmt_rx_ops(p2p_soc_obj->soc, false);
+	if (status != QDF_STATUS_SUCCESS)
+		p2p_err("Failed to deregister mgmt rx callback");
+
+	if (roc_ctx->roc_type == USER_REQUESTED)
+		status = p2p_send_roc_event(roc_ctx,
+				ROC_EVENT_COMPLETED);
+
+	status = qdf_list_remove_node(&p2p_soc_obj->roc_q,
+			(qdf_list_node_t *)roc_ctx);
+	if (QDF_STATUS_SUCCESS != status)
+		p2p_err("Failed to remove roc req, status %d", status);
+	qdf_mem_free(roc_ctx);
+	qdf_event_set(&p2p_soc_obj->cancel_roc_done);
+
+	size = qdf_list_size(&p2p_soc_obj->roc_q);
+	p2p_debug("P2P roc queue size is %d", status);
+	if (size > 0) {
+		status = qdf_list_peek_front(&p2p_soc_obj->roc_q,
+				&next_node);
+		if (QDF_STATUS_SUCCESS != status) {
+			p2p_err("Failed to peek roc req from front, status %d",
+				status);
+			return status;
+		}
+		roc_ctx = qdf_container_of(next_node,
+				struct p2p_roc_context, node);
+		status = p2p_execute_roc_req(roc_ctx);
+	}
+	return status;
+}
+
+/**
+ * p2p_process_scan_dequeue() - Process scan dequeue
+ * @roc_ctx: remain on channel request
+ *
+ * This function process scan dequeued event.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_process_scan_dequeue(
+	struct p2p_roc_context *roc_ctx)
+{
+	QDF_STATUS status;
+	struct p2p_soc_priv_obj *p2p_soc_obj = roc_ctx->p2p_soc_obj;
+
+	if (roc_ctx->roc_state != ROC_STATE_CANCEL_IN_PROG) {
+		p2p_debug("invalid roc state, %d", roc_ctx->roc_state);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (QDF_TIMER_STATE_RUNNING !=
+		qdf_mc_timer_get_current_state(&roc_ctx->roc_timer)) {
+		qdf_mc_timer_stop(&roc_ctx->roc_timer);
+	}
+
+	status = qdf_mc_timer_destroy(&roc_ctx->roc_timer);
+	if (status != QDF_STATUS_SUCCESS)
+		p2p_err("failed to destroy roc timer, roc ctx:%p, status:%d",
+			roc_ctx, status);
+
+	status = qdf_list_remove_node(&p2p_soc_obj->roc_q,
+				(qdf_list_node_t *)roc_ctx);
+	if (status != QDF_STATUS_SUCCESS)
+		p2p_err("failed to remove roc context, roc ctx:%p, status:%d",
+			roc_ctx, status);
+	qdf_mem_free(roc_ctx);
+
+	return status;
+}
+
+struct p2p_roc_context *p2p_find_current_roc_ctx(
+	struct p2p_soc_priv_obj *p2p_soc_obj)
+{
+	struct p2p_roc_context *roc_ctx;
+	qdf_list_node_t *tmp, *pos;
+
+	list_for_each_safe(pos, tmp, &p2p_soc_obj->roc_q.anchor) {
+		roc_ctx = list_entry(pos, struct p2p_roc_context,
+					node);
+		if (roc_ctx->roc_state != ROC_STATE_IDLE) {
+			p2p_debug("p2p soc obj:%p, roc ctx:%p, vdev_id"
+				":%d, scan_id:%d, cookie:%llx, 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->cookie, roc_ctx->chan,
+				roc_ctx->phy_mode, roc_ctx->duration,
+				roc_ctx->roc_type, roc_ctx->roc_state);
+
+			return roc_ctx;
+		}
+	}
+
+	return NULL;
+}
+
+QDF_STATUS p2p_restart_roc_timer(struct p2p_roc_context *roc_ctx)
+{
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+
+	if (QDF_TIMER_STATE_RUNNING ==
+		qdf_mc_timer_get_current_state(&roc_ctx->roc_timer)) {
+		p2p_debug("roc timer is running");
+		status = qdf_mc_timer_stop(&roc_ctx->roc_timer);
+		if (status != QDF_STATUS_SUCCESS) {
+			p2p_err("Failed to stop roc timer");
+			return status;
+		}
+
+		status = qdf_mc_timer_start(&roc_ctx->roc_timer,
+						roc_ctx->duration);
+		if (status != QDF_STATUS_SUCCESS)
+			p2p_err("Remain on Channel timer start failed");
+	}
+
+	return status;
+}
+
+QDF_STATUS p2p_cleanup_roc_queue(struct p2p_soc_priv_obj *p2p_soc_obj)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct p2p_roc_context *roc_ctx;
+	qdf_list_node_t *tmp, *pos;
+	unsigned long rc = 0;
+
+	p2p_debug("clean up idle roc request, roc queue size:%d",
+		qdf_list_size(&p2p_soc_obj->roc_q));
+	list_for_each_safe(pos, tmp, &p2p_soc_obj->roc_q.anchor) {
+		roc_ctx = list_entry(pos, struct p2p_roc_context,
+					node);
+
+		p2p_debug("p2p soc obj:%p, roc ctx:%p, vdev_id:%d, scan_id:%d, cookie:%llx, 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->cookie, roc_ctx->chan,
+			roc_ctx->phy_mode, roc_ctx->duration,
+			roc_ctx->roc_type, roc_ctx->roc_state);
+
+		if (roc_ctx->roc_state == ROC_STATE_IDLE) {
+			status = qdf_list_remove_node(
+					&p2p_soc_obj->roc_q,
+					(qdf_list_node_t *)roc_ctx);
+			if (status == QDF_STATUS_SUCCESS)
+				qdf_mem_free(roc_ctx);
+			else
+				p2p_err("Failed to remove roc ctx from queue");
+		}
+	}
+
+	p2p_debug("clean up started roc request, roc queue size:%d",
+		qdf_list_size(&p2p_soc_obj->roc_q));
+	list_for_each_safe(pos, tmp, &p2p_soc_obj->roc_q.anchor) {
+		roc_ctx = list_entry(pos, struct p2p_roc_context,
+					node);
+
+	p2p_debug("p2p soc obj:%p, roc ctx:%p, vdev_id:%d, scan_id:%d, cookie:%llx, 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->cookie, roc_ctx->chan,
+		roc_ctx->phy_mode, roc_ctx->duration,
+		roc_ctx->roc_type, roc_ctx->roc_state);
+
+		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);
+
+			rc = qdf_wait_single_event(
+				&p2p_soc_obj->cancel_roc_done,
+				msecs_to_jiffies(P2P_WAIT_CANCEL_ROC));
+			if (!rc)
+				p2p_err("Timeout occurred while waiting for RoC cancellation");
+		}
+	}
+
+	if (status != QDF_STATUS_SUCCESS || rc) {
+		p2p_err("failed to cleanup roc queue, status:%d, rc:%ld",
+			status, rc);
+		status = QDF_STATUS_E_FAILURE;
+	}
+
+	return status;
+}
+
+QDF_STATUS p2p_process_roc_req(struct p2p_roc_context *roc_ctx)
+{
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	struct p2p_roc_context *curr_roc_ctx;
+	QDF_STATUS status;
+	uint32_t size;
+
+	p2p_soc_obj = roc_ctx->p2p_soc_obj;
+
+	p2p_debug("p2p soc obj:%p, roc ctx:%p, vdev_id:%d, scan_id:%d, cookie:%llx, chan:%d, phy_mode:%d, duration:%d, roc_type:%d, roc_state:%d",
+		p2p_soc_obj, roc_ctx, roc_ctx->vdev_id,
+		roc_ctx->scan_id, roc_ctx->cookie, roc_ctx->chan,
+		roc_ctx->phy_mode, roc_ctx->duration,
+		roc_ctx->roc_type, roc_ctx->roc_state);
+
+	status = qdf_list_insert_back(&p2p_soc_obj->roc_q,
+			&roc_ctx->node);
+	if (QDF_STATUS_SUCCESS != status) {
+		qdf_mem_free(roc_ctx);
+		p2p_err("Failed to insert roc req, status %d", status);
+		return status;
+	}
+
+	size = qdf_list_size(&p2p_soc_obj->roc_q);
+	if (size == 1) {
+		status = p2p_execute_roc_req(roc_ctx);
+	} else if (size > 1) {
+		curr_roc_ctx = p2p_find_current_roc_ctx(p2p_soc_obj);
+		/*TODO, to handle extend roc */
+	}
+
+	return status;
+}
+
 QDF_STATUS p2p_process_cancel_roc_req(
 	struct cancel_roc_context *cancel_roc_ctx)
 {
-	return QDF_STATUS_SUCCESS;
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	struct p2p_roc_context *curr_roc_ctx;
+	QDF_STATUS status;
+
+	p2p_soc_obj = cancel_roc_ctx->p2p_soc_obj;
+	curr_roc_ctx = p2p_find_roc_ctx(p2p_soc_obj,
+				cancel_roc_ctx->cookie);
+
+	p2p_debug("p2p soc obj:%p, cookie:%llx, roc ctx:%p",
+		p2p_soc_obj, cancel_roc_ctx->cookie, curr_roc_ctx);
+
+	if (!curr_roc_ctx) {
+		p2p_err("Failed to find roc req by cookie, cookie %llx",
+				cancel_roc_ctx->cookie);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (curr_roc_ctx->roc_state == ROC_STATE_IDLE) {
+		status = qdf_list_remove_node(&p2p_soc_obj->roc_q,
+				(qdf_list_node_t *)curr_roc_ctx);
+		if (status == QDF_STATUS_SUCCESS)
+			qdf_mem_free(curr_roc_ctx);
+		else
+			p2p_err("Failed to remove roc req, status %d", status);
+	} else if (curr_roc_ctx->roc_state ==
+				ROC_STATE_CANCEL_IN_PROG) {
+		p2p_debug("Receive cancel roc req when roc req is canceling, cookie %llx",
+			cancel_roc_ctx->cookie);
+		status = QDF_STATUS_SUCCESS;
+	} else {
+		status = p2p_execute_cancel_roc_req(curr_roc_ctx);
+	}
+
+	return status;
 }
 
 void p2p_scan_event_cb(struct wlan_objmgr_vdev *vdev,
 	struct scan_event *event, void *arg)
 {
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	struct p2p_roc_context *curr_roc_ctx;
+
+	p2p_debug("soc:%p, scan event:%d", arg, event->type);
+
+	p2p_soc_obj = (struct p2p_soc_priv_obj *)arg;
+	if (!p2p_soc_obj) {
+		p2p_err("Invalid P2P context");
+		return;
+	}
+
+	curr_roc_ctx = p2p_find_current_roc_ctx(p2p_soc_obj);
+	if (!curr_roc_ctx) {
+		p2p_err("Failed to find valid P2P roc context");
+		return;
+	}
+	switch (event->type) {
+	case SCAN_EVENT_TYPE_STARTED:
+		p2p_process_scan_start_evt(curr_roc_ctx);
+		break;
+	case SCAN_EVENT_TYPE_FOREIGN_CHANNEL:
+		p2p_process_ready_on_channel_evt(curr_roc_ctx);
+		break;
+	case SCAN_EVENT_TYPE_COMPLETED:
+		p2p_process_scan_complete_evt(curr_roc_ctx);
+		break;
+	case SCAN_EVENT_TYPE_DEQUEUED:
+		p2p_process_scan_dequeue(curr_roc_ctx);
+		break;
+	default:
+		p2p_err("invalid scan event, %d", event->type);
+	}
 }

+ 44 - 0
umac/p2p/core/src/wlan_p2p_roc.h

@@ -27,6 +27,15 @@
 #include <qdf_mc_timer.h>
 
 #define P2P_EVENT_PROPOGATE_TIME 10
+#define P2P_WAIT_CANCEL_ROC      1000
+
+#ifdef QCA_WIFI_3_0_EMU
+#define P2P_ROC_DURATION_MULTI_GO_PRESENT   2
+#define P2P_ROC_DURATION_MULTI_GO_ABSENT    3
+#else
+#define P2P_ROC_DURATION_MULTI_GO_PRESENT   2
+#define P2P_ROC_DURATION_MULTI_GO_ABSENT    5
+#endif
 
 struct wlan_objmgr_vdev;
 struct scan_event;
@@ -97,6 +106,41 @@ struct cancel_roc_context {
 	uint64_t cookie;
 };
 
+/**
+ * p2p_find_current_roc_ctx() - Find out roc context in progressing
+ * @p2p_soc_obj: p2p psoc private object
+ *
+ * This function find out roc context in progressing from p2p psoc
+ * private object
+ *
+ * Return: Pointer to roc context - success
+ *         NULL                   - failure
+ */
+struct p2p_roc_context *p2p_find_current_roc_ctx(
+	struct p2p_soc_priv_obj *p2p_soc_obj);
+
+/**
+ * p2p_restart_roc_timer() - Restarts roc timer
+ * @roc_ctx: remain on channel context
+ *
+ * This function restarts roc timer with updated duration.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_restart_roc_timer(struct p2p_roc_context *roc_ctx);
+
+/**
+ * p2p_cleanup_roc_queue() - Cleanup roc context in queue
+ * @p2p_soc_obj: p2p psoc private object
+ *
+ * This function cleanup roc context in queue, include the roc
+ * context in progressing.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_cleanup_roc_queue(
+	struct p2p_soc_priv_obj *p2p_soc_obj);
+
 /**
  * p2p_process_roc_req() - Process roc request
  * @roc_ctx: roc request context

+ 2 - 0
umac/p2p/dispatcher/src/wlan_p2p_tgt_api.c

@@ -26,6 +26,7 @@
 #include "wlan_p2p_tgt_api.h"
 #include "wlan_p2p_public_struct.h"
 #include "../../core/src/wlan_p2p_main.h"
+#include "../../core/src/wlan_p2p_roc.h"
 
 static inline struct wlan_lmac_if_p2p_tx_ops *
 wlan_psoc_get_p2p_tx_ops(struct wlan_objmgr_psoc *psoc)
@@ -96,6 +97,7 @@ QDF_STATUS tgt_p2p_unregister_noa_ev_handler(
 void tgt_p2p_scan_event_cb(struct wlan_objmgr_vdev *vdev,
 	struct scan_event *event, void *arg)
 {
+	p2p_scan_event_cb(vdev, event, arg);
 }
 
 QDF_STATUS tgt_p2p_mgmt_download_comp_cb(void *context,

+ 71 - 0
umac/p2p/dispatcher/src/wlan_p2p_ucfg_api.c

@@ -26,6 +26,7 @@
 #include "wlan_p2p_ucfg_api.h"
 #include "wlan_p2p_public_struct.h"
 #include "../../core/src/wlan_p2p_main.h"
+#include "../../core/src/wlan_p2p_roc.h"
 
 static inline struct wlan_lmac_if_p2p_tx_ops *
 ucfg_p2p_psoc_get_tx_ops(struct wlan_objmgr_psoc *psoc)
@@ -67,12 +68,82 @@ QDF_STATUS ucfg_p2p_psoc_stop(struct wlan_objmgr_psoc *soc)
 QDF_STATUS ucfg_p2p_roc_req(struct wlan_objmgr_psoc *soc,
 	struct p2p_roc_req *roc_req, uint64_t *cookie)
 {
+	struct scheduler_msg msg;
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	struct p2p_roc_context *roc_ctx;
+
+	p2p_debug("soc:%p, vdev_id:%d, chan:%d, phy_mode:%d, duration:%d",
+		soc, roc_req->vdev_id, roc_req->chan,
+		roc_req->phy_mode, roc_req->duration);
+
+	if (!soc) {
+		p2p_err("psoc context passed is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(soc,
+			WLAN_UMAC_COMP_P2P);
+	if (!p2p_soc_obj) {
+		p2p_err("P2P soc object is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	roc_ctx = qdf_mem_malloc(sizeof(*roc_ctx));
+	if (!roc_ctx) {
+		p2p_err("failed to allocate p2p roc context");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	*cookie = (uintptr_t)roc_ctx;
+	roc_ctx->p2p_soc_obj = p2p_soc_obj;
+	roc_ctx->vdev_id = roc_req->vdev_id;
+	roc_ctx->chan = roc_req->chan;
+	roc_ctx->phy_mode = roc_req->phy_mode;
+	roc_ctx->duration = roc_req->duration;
+	roc_ctx->roc_state = ROC_STATE_IDLE;
+	roc_ctx->roc_type = USER_REQUESTED;
+	msg.type = P2P_ROC_REQ;
+	msg.bodyptr = roc_ctx;
+	msg.callback = p2p_process_cmd;
+	scheduler_post_msg(QDF_MODULE_ID_OS_IF, &msg);
+
 	return QDF_STATUS_SUCCESS;
 }
 
 QDF_STATUS ucfg_p2p_roc_cancel_req(struct wlan_objmgr_psoc *soc,
 	uint64_t cookie)
 {
+	struct scheduler_msg msg;
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	struct cancel_roc_context *cancel_roc;
+
+	p2p_debug("soc:%p, cookie:0x%llx", soc, cookie);
+
+	if (!soc) {
+		p2p_err("psoc context passed is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(soc,
+			WLAN_UMAC_COMP_P2P);
+	if (!p2p_soc_obj) {
+		p2p_err("p2p soc context is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	cancel_roc = qdf_mem_malloc(sizeof(*cancel_roc));
+	if (!cancel_roc) {
+		p2p_err("failed to allocate cancel p2p roc");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	cancel_roc->p2p_soc_obj = p2p_soc_obj;
+	cancel_roc->cookie = cookie;
+	msg.type = P2P_CANCEL_ROC_REQ;
+	msg.bodyptr = cancel_roc;
+	msg.callback = p2p_process_cmd;
+	scheduler_post_msg(QDF_MODULE_ID_OS_IF, &msg);
+
 	return QDF_STATUS_SUCCESS;
 }