Prechádzať zdrojové kódy

qcacmn: Add runtime pm lock for P2P

Add runtime pm lock for remain on channel request in P2P component.

Change-Id: Ic29c5edf9e9325d1f9b65d766385327b91b0d14a
CRs-Fixed: 2036085
Wu Gao 8 rokov pred
rodič
commit
0b3198cbc0

+ 17 - 1
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);

+ 3 - 0
core/src/wlan_p2p_main.h

@@ -27,6 +27,7 @@
 #include <qdf_types.h>
 #include <qdf_event.h>
 #include <qdf_list.h>
+#include <qdf_lock.h>
 
 #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;
 };
 
 /**

+ 0 - 1
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;
 	}
 

+ 104 - 52
core/src/wlan_p2p_roc.c

@@ -246,6 +246,85 @@ static void p2p_roc_timeout(void *pdata)
 	p2p_execute_cancel_roc_req(roc_ctx);
 }
 
+/**
+ * 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_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
@@ -267,11 +346,16 @@ static QDF_STATUS p2p_execute_roc_req(struct p2p_roc_context *roc_ctx)
 		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)
-		return status;
+	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(
@@ -284,8 +368,19 @@ static QDF_STATUS p2p_execute_roc_req(struct p2p_roc_context *roc_ctx)
 
 	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",
@@ -323,49 +418,6 @@ static struct p2p_roc_context *p2p_find_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
@@ -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;
 	}