diff --git a/umac/p2p/core/src/wlan_p2p_main.c b/umac/p2p/core/src/wlan_p2p_main.c index e77a16cc6293..3c91293707ef 100644 --- a/umac/p2p/core/src/wlan_p2p_main.c +++ b/umac/p2p/core/src/wlan_p2p_main.c @@ -456,6 +456,7 @@ QDF_STATUS p2p_component_deinit(void) QDF_STATUS p2p_psoc_object_open(struct wlan_objmgr_psoc *soc) { + QDF_STATUS status; struct p2p_soc_priv_obj *p2p_soc_obj; if (!soc) { @@ -473,11 +474,25 @@ QDF_STATUS p2p_psoc_object_open(struct wlan_objmgr_psoc *soc) qdf_list_create(&p2p_soc_obj->roc_q, MAX_QUEUE_LENGTH); qdf_list_create(&p2p_soc_obj->tx_q_roc, MAX_QUEUE_LENGTH); qdf_list_create(&p2p_soc_obj->tx_q_ack, MAX_QUEUE_LENGTH); - qdf_event_create(&p2p_soc_obj->cancel_roc_done); + + 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; + } + p2p_soc_obj->roc_runtime_lock = qdf_runtime_lock_init( + P2P_MODULE_NAME); p2p_debug("p2p psoc object open successful"); return QDF_STATUS_SUCCESS; + +fail_event: + 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); + + return status; } QDF_STATUS p2p_psoc_object_close(struct wlan_objmgr_psoc *soc) @@ -496,6 +511,7 @@ QDF_STATUS p2p_psoc_object_close(struct wlan_objmgr_psoc *soc) return QDF_STATUS_E_FAILURE; } + qdf_runtime_lock_deinit(p2p_soc_obj->roc_runtime_lock); 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); diff --git a/umac/p2p/core/src/wlan_p2p_main.h b/umac/p2p/core/src/wlan_p2p_main.h index c526bbe92788..c13068c805d2 100644 --- a/umac/p2p/core/src/wlan_p2p_main.h +++ b/umac/p2p/core/src/wlan_p2p_main.h @@ -27,6 +27,7 @@ #include #include #include +#include #define MAX_QUEUE_LENGTH 20 #define P2P_NOA_ATTR_IND 0x1090 @@ -138,6 +139,7 @@ struct p2p_noa_event { * @start_param: Start parameters, include callbacks and user * data to HDD * @cancel_roc_done: Cancel roc done event + * @roc_runtime_lock: Runtime lock for roc request */ struct p2p_soc_priv_obj { struct wlan_objmgr_psoc *soc; @@ -147,6 +149,7 @@ struct p2p_soc_priv_obj { uint16_t scan_req_id; struct p2p_start_param *start_param; qdf_event_t cancel_roc_done; + qdf_runtime_lock_t roc_runtime_lock; }; /** diff --git a/umac/p2p/core/src/wlan_p2p_off_chan_tx.c b/umac/p2p/core/src/wlan_p2p_off_chan_tx.c index 81f7021b703e..2fe4b6ba6ae8 100644 --- a/umac/p2p/core/src/wlan_p2p_off_chan_tx.c +++ b/umac/p2p/core/src/wlan_p2p_off_chan_tx.c @@ -855,7 +855,6 @@ static QDF_STATUS p2p_roc_req_for_tx_action( status = p2p_process_roc_req(roc_ctx); if (status != QDF_STATUS_SUCCESS) { p2p_err("request roc for tx action frrame fail"); - qdf_mem_free(roc_ctx); return status; } diff --git a/umac/p2p/core/src/wlan_p2p_roc.c b/umac/p2p/core/src/wlan_p2p_roc.c index e04082353fa1..facf285a7e09 100644 --- a/umac/p2p/core/src/wlan_p2p_roc.c +++ b/umac/p2p/core/src/wlan_p2p_roc.c @@ -246,83 +246,6 @@ static void p2p_roc_timeout(void *pdata) 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 @@ -366,6 +289,135 @@ static QDF_STATUS p2p_send_roc_event( return QDF_STATUS_SUCCESS; } +/** + * p2p_destroy_roc_ctx() - destroy roc ctx + * @roc_ctx: remain on channel request + * @up_layer_event: if send uplayer event + * @in_roc_queue: if roc context in roc queue + * + * This function destroy roc context. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_destroy_roc_ctx(struct p2p_roc_context *roc_ctx, + bool up_layer_event, bool in_roc_queue) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct p2p_soc_priv_obj *p2p_soc_obj = roc_ctx->p2p_soc_obj; + + p2p_debug("p2p_soc_obj:%p, roc_ctx:%p, up_layer_event:%d, in_roc_queue:%d", + p2p_soc_obj, roc_ctx, up_layer_event, in_roc_queue); + + if (up_layer_event) { + p2p_send_roc_event(roc_ctx, ROC_EVENT_READY_ON_CHAN); + p2p_send_roc_event(roc_ctx, ROC_EVENT_COMPLETED); + } + + if (in_roc_queue) { + 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); + + return status; +} + +/** + * 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); + + /* prevent runtime suspend */ + qdf_runtime_pm_prevent_suspend(p2p_soc_obj->roc_runtime_lock); + + status = qdf_mc_timer_init(&roc_ctx->roc_timer, + QDF_TIMER_TYPE_SW, p2p_roc_timeout, + p2p_soc_obj); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("failed to init roc timer, status:%d", status); + goto fail; + } + + 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) { + qdf_mc_timer_destroy(&roc_ctx->roc_timer); + p2p_err("Failed to start scan, status:%d", status); + goto fail; + } + +fail: + if (status != QDF_STATUS_SUCCESS) { + p2p_destroy_roc_ctx(roc_ctx, true, true); + qdf_runtime_pm_allow_suspend( + p2p_soc_obj->roc_runtime_lock); + return 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_process_scan_start_evt() - Process scan start event * @roc_ctx: remain on channel request @@ -450,6 +502,9 @@ static QDF_STATUS p2p_process_scan_complete_evt( roc_ctx->phy_mode, roc_ctx->duration, roc_ctx->roc_type, roc_ctx->roc_state); + /* allow runtime suspend */ + qdf_runtime_pm_allow_suspend(p2p_soc_obj->roc_runtime_lock); + if (QDF_TIMER_STATE_RUNNING == qdf_mc_timer_get_current_state(&roc_ctx->roc_timer)) { status = qdf_mc_timer_stop(&roc_ctx->roc_timer); @@ -469,11 +524,7 @@ static QDF_STATUS p2p_process_scan_complete_evt( 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); + p2p_destroy_roc_ctx(roc_ctx, false, true); qdf_event_set(&p2p_soc_obj->cancel_roc_done); size = qdf_list_size(&p2p_soc_obj->roc_q); @@ -566,7 +617,8 @@ QDF_STATUS p2p_cleanup_roc_queue(struct p2p_soc_priv_obj *p2p_soc_obj) &p2p_soc_obj->roc_q, (qdf_list_node_t *)roc_ctx); if (status == QDF_STATUS_SUCCESS) - qdf_mem_free(roc_ctx); + p2p_destroy_roc_ctx(roc_ctx, + true, false); else p2p_err("Failed to remove roc ctx from queue"); } @@ -617,7 +669,7 @@ QDF_STATUS p2p_process_roc_req(struct p2p_roc_context *roc_ctx) status = qdf_list_insert_back(&p2p_soc_obj->roc_q, &roc_ctx->node); if (QDF_STATUS_SUCCESS != status) { - qdf_mem_free(roc_ctx); + p2p_destroy_roc_ctx(roc_ctx, true, false); p2p_debug("Failed to insert roc req, status %d", status); return status; }