From 26781f65dc7886ee13bb9d987edc4ea29e8a16a9 Mon Sep 17 00:00:00 2001 From: Wu Gao Date: Wed, 15 Mar 2017 17:27:59 +0800 Subject: [PATCH] qcacmn: remain on channel Handles roc request, cancel roc reuqest and scan event in P2P component. Change-Id: I47085ddc3551e76ef042e9d72dc4b29de6c2b118 CRs-Fixed: 2006262 --- umac/p2p/core/src/wlan_p2p_main.c | 20 +- umac/p2p/core/src/wlan_p2p_roc.c | 714 +++++++++++++++++++- umac/p2p/core/src/wlan_p2p_roc.h | 44 ++ umac/p2p/dispatcher/src/wlan_p2p_tgt_api.c | 2 + umac/p2p/dispatcher/src/wlan_p2p_ucfg_api.c | 71 ++ 5 files changed, 845 insertions(+), 6 deletions(-) diff --git a/umac/p2p/core/src/wlan_p2p_main.c b/umac/p2p/core/src/wlan_p2p_main.c index faf753339940..25e53727ab5d 100644 --- a/umac/p2p/core/src/wlan_p2p_main.c +++ b/umac/p2p/core/src/wlan_p2p_main.c @@ -26,6 +26,7 @@ #include #include #include +#include #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; } diff --git a/umac/p2p/core/src/wlan_p2p_roc.c b/umac/p2p/core/src/wlan_p2p_roc.c index 62fcb2f21d90..fd588ebd5787 100644 --- a/umac/p2p/core/src/wlan_p2p_roc.c +++ b/umac/p2p/core/src/wlan_p2p_roc.c @@ -20,20 +20,730 @@ * DOC: This file contains RoC API definitions */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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" + +/** + * 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) { - return QDF_STATUS_SUCCESS; + 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); + } } diff --git a/umac/p2p/core/src/wlan_p2p_roc.h b/umac/p2p/core/src/wlan_p2p_roc.h index af733c0673ff..736742748186 100644 --- a/umac/p2p/core/src/wlan_p2p_roc.h +++ b/umac/p2p/core/src/wlan_p2p_roc.h @@ -27,6 +27,15 @@ #include #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 diff --git a/umac/p2p/dispatcher/src/wlan_p2p_tgt_api.c b/umac/p2p/dispatcher/src/wlan_p2p_tgt_api.c index e2ca5192273b..d07c56c973e8 100644 --- a/umac/p2p/dispatcher/src/wlan_p2p_tgt_api.c +++ b/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, diff --git a/umac/p2p/dispatcher/src/wlan_p2p_ucfg_api.c b/umac/p2p/dispatcher/src/wlan_p2p_ucfg_api.c index 375c0a3f87ac..88b57ce7cc93 100644 --- a/umac/p2p/dispatcher/src/wlan_p2p_ucfg_api.c +++ b/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; }