Ver código fonte

qcacld-3.0: Add RX refill thread infra to replenish RX buffers

Add Rx refill thread infrastructure to replenish RX buffer pool

Change-Id: I2553e0e35d251cf72e741321a2389f741f1bb485
CRs-Fixed: 2869355
Karthik Kantamneni 4 anos atrás
pai
commit
7983966ef5

+ 5 - 1
core/cds/inc/cds_sched.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -48,6 +48,10 @@
 #define RX_VDEV_DEL_EVENT           0x004
 #define RX_SHUTDOWN_EVENT           0x010
 
+#define RX_REFILL_POST_EVENT           0x001
+#define RX_REFILL_SUSPEND_EVENT        0x002
+#define RX_REFILL_SHUTDOWN_EVENT       0x004
+
 #ifdef QCA_CONFIG_SMP
 /*
 ** Maximum number of cds messages to be allocated for

+ 209 - 1
core/dp/txrx3.0/dp_rx_thread.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -19,6 +19,7 @@
 #include <dp_txrx.h>
 #include "dp_peer.h"
 #include "dp_internal.h"
+#include "dp_types.h"
 #include <cdp_txrx_cmn_struct.h>
 #include <cdp_txrx_peer_ops.h>
 #include <cds_sched.h>
@@ -599,6 +600,86 @@ static int dp_rx_thread_loop(void *arg)
 	return 0;
 }
 
+static int dp_rx_refill_thread_sub_loop(struct dp_rx_refill_thread *rx_thread,
+					bool *shutdown)
+{
+	while (true) {
+		if (qdf_atomic_test_and_clear_bit(RX_REFILL_SHUTDOWN_EVENT,
+						  &rx_thread->event_flag)) {
+			if (qdf_atomic_test_and_clear_bit(RX_REFILL_SUSPEND_EVENT,
+							  &rx_thread->event_flag)) {
+				qdf_event_set(&rx_thread->suspend_event);
+			}
+			dp_debug("shutting down (%s) pid %d",
+				 qdf_get_current_comm(), qdf_get_current_pid());
+			*shutdown = true;
+			break;
+		}
+
+		dp_rx_refill_buff_pool_enqueue((struct dp_soc *)rx_thread->soc);
+
+		if (qdf_atomic_test_and_clear_bit(RX_REFILL_SUSPEND_EVENT,
+						  &rx_thread->event_flag)) {
+			dp_debug("refill thread received suspend ind (%s) pid %d",
+				 qdf_get_current_comm(),
+				 qdf_get_current_pid());
+			qdf_event_set(&rx_thread->suspend_event);
+			dp_debug("refill thread waiting for resume (%s) pid %d",
+				 qdf_get_current_comm(),
+				 qdf_get_current_pid());
+			qdf_wait_single_event(&rx_thread->resume_event, 0);
+		}
+		break;
+	}
+	return 0;
+}
+
+static int dp_rx_refill_thread_loop(void *arg)
+{
+	struct dp_rx_refill_thread *rx_thread = arg;
+	bool shutdown = false;
+	int status;
+
+	if (!arg) {
+		dp_err("bad Args passed");
+		return 0;
+	}
+
+	qdf_set_user_nice(qdf_get_current_task(), -1);
+	qdf_set_wake_up_idle(true);
+
+	qdf_event_set(&rx_thread->start_event);
+	dp_info("starting rx_refill_thread (%s) pid %d", qdf_get_current_comm(),
+		qdf_get_current_pid());
+	while (!shutdown) {
+		/* This implements the execution model algorithm */
+		dp_debug("refill thread sleeping");
+		status =
+		    qdf_wait_queue_interruptible
+				(rx_thread->wait_q,
+				 qdf_atomic_test_bit(RX_REFILL_POST_EVENT,
+						     &rx_thread->event_flag) ||
+				 qdf_atomic_test_bit(RX_REFILL_SUSPEND_EVENT,
+						     &rx_thread->event_flag));
+		dp_debug("refill thread woken up");
+
+		if (status == -ERESTARTSYS) {
+			QDF_DEBUG_PANIC("wait_event_interruptible returned -ERESTARTSYS");
+			break;
+		}
+		dp_rx_refill_thread_sub_loop(rx_thread, &shutdown);
+		qdf_atomic_clear_bit(RX_REFILL_POST_EVENT, &rx_thread->event_flag);
+	}
+
+	/* If we get here the scheduler thread must exit */
+	dp_info("exiting (%s) pid %d", qdf_get_current_comm(),
+		qdf_get_current_pid());
+	qdf_event_set(&rx_thread->shutdown_event);
+	qdf_exit_thread(QDF_STATUS_SUCCESS);
+
+	return 0;
+}
+
 /**
  * dp_rx_tm_thread_napi_poll() - dummy napi poll for rx_thread NAPI
  * @napi: pointer to DP rx_thread NAPI
@@ -715,6 +796,60 @@ static QDF_STATUS dp_rx_tm_thread_deinit(struct dp_rx_thread *rx_thread)
 	return QDF_STATUS_SUCCESS;
 }
 
+QDF_STATUS dp_rx_refill_thread_init(struct dp_rx_refill_thread *refill_thread)
+{
+	char refill_thread_name[20] = {0};
+	QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
+
+	qdf_scnprintf(refill_thread_name, sizeof(refill_thread_name),
+		      "dp_refill_thread");
+	dp_info("Initializing %s", refill_thread_name);
+
+	refill_thread->state = DP_RX_REFILL_THREAD_INVALID;
+	refill_thread->event_flag = 0;
+	qdf_event_create(&refill_thread->start_event);
+	qdf_event_create(&refill_thread->suspend_event);
+	qdf_event_create(&refill_thread->resume_event);
+	qdf_event_create(&refill_thread->shutdown_event);
+	qdf_init_waitqueue_head(&refill_thread->wait_q);
+	refill_thread->task = qdf_create_thread(dp_rx_refill_thread_loop,
+						refill_thread,
+						refill_thread_name);
+	if (!refill_thread->task) {
+		dp_err("could not create dp_rx_refill_thread");
+		return QDF_STATUS_E_FAILURE;
+	}
+	qdf_wake_up_process(refill_thread->task);
+	qdf_status = qdf_wait_single_event(&refill_thread->start_event,
+					   0);
+	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
+		dp_err("failed waiting for refill thread creation status: %d",
+		       qdf_status);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	refill_thread->state = DP_RX_REFILL_THREAD_RUNNING;
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS dp_rx_refill_thread_deinit(struct dp_rx_refill_thread *refill_thread)
+{
+	qdf_set_bit(RX_REFILL_SHUTDOWN_EVENT,
+		    &refill_thread->event_flag);
+	qdf_set_bit(RX_REFILL_POST_EVENT,
+		    &refill_thread->event_flag);
+	qdf_wake_up_interruptible(&refill_thread->wait_q);
+	qdf_wait_single_event(&refill_thread->shutdown_event, 0);
+
+	qdf_event_destroy(&refill_thread->start_event);
+	qdf_event_destroy(&refill_thread->suspend_event);
+	qdf_event_destroy(&refill_thread->resume_event);
+	qdf_event_destroy(&refill_thread->shutdown_event);
+
+	refill_thread->state = DP_RX_REFILL_THREAD_INVALID;
+	return QDF_STATUS_SUCCESS;
+}
+
 QDF_STATUS dp_rx_tm_init(struct dp_rx_tm_handle *rx_tm_hdl,
 			 uint8_t num_dp_rx_threads)
 {
@@ -823,6 +958,50 @@ suspend_fail:
 	return qdf_status;
 }
 
+/**
+ * dp_rx_refill_thread_suspend() - Suspend DP RX refill threads
+ * @refill_thread: containing the overall refill thread infrastructure
+ *
+ * Return: Success/Failure
+ */
+QDF_STATUS
+dp_rx_refill_thread_suspend(struct dp_rx_refill_thread *refill_thread)
+{
+	QDF_STATUS qdf_status;
+
+	if (refill_thread->state == DP_RX_REFILL_THREAD_SUSPENDED) {
+		dp_info("already in suspend state! Ignoring.");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	refill_thread->state = DP_RX_REFILL_THREAD_SUSPENDING;
+
+	qdf_event_reset(&refill_thread->resume_event);
+	qdf_event_reset(&refill_thread->suspend_event);
+	qdf_set_bit(RX_REFILL_SUSPEND_EVENT,
+		    &refill_thread->event_flag);
+	qdf_wake_up_interruptible(&refill_thread->wait_q);
+
+	qdf_status = qdf_wait_single_event(&refill_thread->suspend_event,
+					   DP_RX_THREAD_WAIT_TIMEOUT);
+	if (QDF_IS_STATUS_SUCCESS(qdf_status))
+		dp_debug("Refill thread  suspended");
+	else
+		goto suspend_fail;
+
+	refill_thread->state = DP_RX_REFILL_THREAD_SUSPENDED;
+	return QDF_STATUS_SUCCESS;
+
+suspend_fail:
+	dp_err("Refill thread %s(%d) while waiting for suspend",
+	       qdf_status == QDF_STATUS_E_TIMEOUT ? "timeout out" : "failed",
+	       qdf_status);
+
+	dp_rx_refill_thread_resume(refill_thread);
+
+	return qdf_status;
+}
+
 /**
  * dp_rx_thread_flush_by_vdev_id() - flush rx packets by vdev_id in
 				     a particular rx thread queue
@@ -938,6 +1117,35 @@ QDF_STATUS dp_rx_tm_resume(struct dp_rx_tm_handle *rx_tm_hdl)
 	return QDF_STATUS_SUCCESS;
 }
 
+/**
+ * dp_rx_refill_thread_resume() - Resume DP RX refill threads
+ * @refill_thread: refill_thread containing the overall thread infrastructure
+ *
+ * Return: QDF_STATUS_SUCCESS on resume success. QDF error otherwise.
+ */
+QDF_STATUS dp_rx_refill_thread_resume(struct dp_rx_refill_thread *refill_thread)
+{
+	dp_debug("calling refill thread to resume");
+
+	if (refill_thread->state != DP_RX_REFILL_THREAD_SUSPENDED &&
+	    refill_thread->state != DP_RX_REFILL_THREAD_SUSPENDING) {
+		dp_info("resume callback received in %d state ! Ignoring.",
+			refill_thread->state);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	/* postively reset event_flag for DP_RX_REFILL_THREAD_SUSPENDING
+	 * state
+	 */
+	qdf_clear_bit(RX_REFILL_SUSPEND_EVENT,
+		      &refill_thread->event_flag);
+	qdf_event_set(&refill_thread->resume_event);
+
+	refill_thread->state = DP_RX_REFILL_THREAD_RUNNING;
+
+	return QDF_STATUS_SUCCESS;
+}
+
 /**
  * dp_rx_tm_shutdown() - shutdown all DP RX threads
  * @rx_tm_hdl: dp_rx_tm_handle containing the overall thread infrastructure

+ 76 - 1
core/dp/txrx3.0/dp_rx_thread.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -70,6 +70,21 @@ struct dp_rx_thread_stats {
 	unsigned int dropped_enq_fail;
 };
 
+/**
+ * enum dp_rx_refill_thread_state - enum to keep track of rx refill thread state
+ * @DP_RX_REFILL_THREAD_INVALID: initial invalid state
+ * @DP_RX_REFILL_THREAD_RUNNING: rx refill thread functional(NOT suspended,
+ *                      processing packets or waiting on a wait_queue)
+ * @DP_RX_REFILL_THREAD_SUSPENDING: rx refill thread is suspending
+ * @DP_RX_REFILL_THREAD_SUSPENDED: rx refill_thread suspended
+ */
+enum dp_rx_refill_thread_state {
+	DP_RX_REFILL_THREAD_INVALID,
+	DP_RX_REFILL_THREAD_RUNNING,
+	DP_RX_REFILL_THREAD_SUSPENDING,
+	DP_RX_REFILL_THREAD_SUSPENDED
+};
+
 /**
  * struct dp_rx_thread - structure holding variables for a single DP RX thread
  * @id: id of the dp_rx_thread (0 or 1 or 2..DP_MAX_RX_THREADS - 1)
@@ -109,6 +124,32 @@ struct dp_rx_thread {
 	struct net_device netdev;
 };
 
+/**
+ * struct dp_rx_refill_thread - structure holding info of DP Rx refill thread
+ * @task: task structure corresponding to the thread
+ * @start_event: handle of Event for DP Rx refill thread to signal startup
+ * @suspend_event: handle of Event for DP Rx refill thread to signal suspend
+ * @resume_event: handle of Event for DP Rx refill thread to signal resume
+ * @shutdown_event: handle of Event for DP Rx refill thread to signal shutdown
+ * @event_flag: event flag to post events to DP Rx refill thread
+ * @wait_q: wait queue to conditionally wait on events for DP Rx refill thread
+ * @enabled: flag to check whether DP Rx refill thread is enabled
+ * @soc: abstract DP soc reference used in internal API's
+ * @state: state of DP Rx refill thread
+ */
+struct dp_rx_refill_thread {
+	qdf_thread_t *task;
+	qdf_event_t start_event;
+	qdf_event_t suspend_event;
+	qdf_event_t resume_event;
+	qdf_event_t shutdown_event;
+	unsigned long event_flag;
+	qdf_wait_queue_head_t wait_q;
+	bool enabled;
+	void *soc;
+	enum dp_rx_refill_thread_state state;
+};
+
 /**
  * enum dp_rx_thread_state - enum to keep track of the state of the rx threads
  * @DP_RX_THREADS_INVALID: initial invalid state
@@ -152,6 +193,23 @@ enum dp_rx_gro_flush_code {
 	DP_RX_GRO_LOW_TPUT_FLUSH
 };
 
+/**
+ * dp_rx_refill_thread_init() - Initialize DP Rx refill threads
+ * @refill_thread: Contains over all rx refill thread info
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS dp_rx_refill_thread_init(struct dp_rx_refill_thread *refill_thread);
+
+/**
+ * dp_rx_refill_thread_deinit() - De-initialize DP Rx refill threads
+ * @refill_thread: Contains over all rx refill thread info
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+dp_rx_refill_thread_deinit(struct dp_rx_refill_thread *refill_thread);
+
 /**
  * dp_rx_tm_init() - initialize DP Rx thread infrastructure
  * @rx_tm_hdl: dp_rx_tm_handle containing the overall thread infrastructure
@@ -191,6 +249,14 @@ QDF_STATUS dp_rx_tm_enqueue_pkt(struct dp_rx_tm_handle *rx_tm_hdl,
 QDF_STATUS dp_rx_tm_gro_flush_ind(struct dp_rx_tm_handle *rx_tm_handle,
 				  int rx_ctx_id,
 				  enum dp_rx_gro_flush_code flush_code);
+/**
+ * dp_rx_refill_thread_suspend() - Suspend RX refill thread
+ * @refill_thread: pointer to dp_rx_refill_thread object
+ *
+ * Return: QDF_STATUS_SUCCESS on success, error qdf status on failure
+ */
+QDF_STATUS
+dp_rx_refill_thread_suspend(struct dp_rx_refill_thread *refill_thread);
 
 /**
  * dp_rx_tm_suspend() - suspend all threads in RXTI
@@ -212,6 +278,15 @@ QDF_STATUS dp_rx_tm_suspend(struct dp_rx_tm_handle *rx_tm_handle);
 QDF_STATUS dp_rx_tm_flush_by_vdev_id(struct dp_rx_tm_handle *rx_tm_hdl,
 				     uint8_t vdev_id);
 
+/**
+ * dp_rx_refill_thread_resume() - Resume RX refill thread
+ * @refill_thread: pointer to dp_rx_refill_thread
+ *
+ * Return: QDF_STATUS_SUCCESS on success, error qdf status on failure
+ */
+QDF_STATUS
+dp_rx_refill_thread_resume(struct dp_rx_refill_thread *refill_thread);
+
 /**
  * dp_rx_tm_resume() - resume all threads in RXTI
  * @rx_tm_handle: pointer to dp_rx_tm_handle object

+ 53 - 0
core/dp/txrx3.0/dp_txrx.c

@@ -26,6 +26,35 @@
 #include <dp_rx.h>
 #include <ce_api.h>
 #include <ce_internal.h>
+#include <wlan_cfg.h>
+
+/**
+ * dp_rx_refill_thread_schedule() - Schedule rx refill thread
+ * @soc: ol_txrx_soc_handle object
+ *
+ */
+#ifdef WLAN_FEATURE_RX_PREALLOC_BUFFER_POOL
+static void dp_rx_refill_thread_schedule(ol_txrx_soc_handle soc)
+{
+	struct dp_rx_refill_thread *rx_thread;
+	struct dp_txrx_handle *dp_ext_hdl;
+
+	if (!soc)
+		return;
+
+	dp_ext_hdl = cdp_soc_get_dp_txrx_handle(soc);
+	if (!dp_ext_hdl)
+		return;
+
+	rx_thread = &dp_ext_hdl->refill_thread;
+	qdf_set_bit(RX_REFILL_POST_EVENT, &rx_thread->event_flag);
+	qdf_wake_up_interruptible(&rx_thread->wait_q);
+}
+#else
+static void dp_rx_refill_thread_schedule(ol_txrx_soc_handle soc)
+{
+}
+#endif
 
 QDF_STATUS dp_txrx_init(ol_txrx_soc_handle soc, uint8_t pdev_id,
 			struct dp_txrx_config *config)
@@ -34,6 +63,7 @@ QDF_STATUS dp_txrx_init(ol_txrx_soc_handle soc, uint8_t pdev_id,
 	QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
 	uint8_t num_dp_rx_threads;
 	struct dp_pdev *pdev;
+	struct dp_soc *dp_soc;
 
 	if (qdf_unlikely(!soc)) {
 		dp_err("soc is NULL");
@@ -61,6 +91,21 @@ QDF_STATUS dp_txrx_init(ol_txrx_soc_handle soc, uint8_t pdev_id,
 	dp_ext_hdl->rx_tm_hdl.txrx_handle_cmn =
 				dp_txrx_get_cmn_hdl_frm_ext_hdl(dp_ext_hdl);
 
+	dp_soc = cdp_soc_t_to_dp_soc(soc);
+	if (wlan_cfg_is_rx_refill_buffer_pool_enabled(dp_soc->wlan_cfg_ctx)) {
+		dp_ext_hdl->refill_thread.soc = soc;
+		dp_ext_hdl->refill_thread.enabled = true;
+		qdf_status =
+			dp_rx_refill_thread_init(&dp_ext_hdl->refill_thread);
+		if (qdf_status != QDF_STATUS_SUCCESS) {
+			dp_err("Failed to initialize RX refill thread status:%d",
+			       qdf_status);
+			return qdf_status;
+		}
+		cdp_register_rx_refill_thread_sched_handler(soc,
+						dp_rx_refill_thread_schedule);
+	}
+
 	num_dp_rx_threads = cdp_get_num_rx_contexts(soc);
 
 	if (dp_ext_hdl->config.enable_rx_threads) {
@@ -74,6 +119,7 @@ QDF_STATUS dp_txrx_init(ol_txrx_soc_handle soc, uint8_t pdev_id,
 QDF_STATUS dp_txrx_deinit(ol_txrx_soc_handle soc)
 {
 	struct dp_txrx_handle *dp_ext_hdl;
+	struct dp_soc *dp_soc;
 
 	if (!soc)
 		return QDF_STATUS_E_INVAL;
@@ -82,6 +128,13 @@ QDF_STATUS dp_txrx_deinit(ol_txrx_soc_handle soc)
 	if (!dp_ext_hdl)
 		return QDF_STATUS_E_FAULT;
 
+	dp_soc = cdp_soc_t_to_dp_soc(soc);
+	if (wlan_cfg_is_rx_refill_buffer_pool_enabled(dp_soc->wlan_cfg_ctx)) {
+		dp_rx_refill_thread_deinit(&dp_ext_hdl->refill_thread);
+		dp_ext_hdl->refill_thread.soc = NULL;
+		dp_ext_hdl->refill_thread.enabled = false;
+	}
+
 	if (dp_ext_hdl->config.enable_rx_threads)
 		dp_rx_tm_deinit(&dp_ext_hdl->rx_tm_hdl);
 

+ 19 - 1
core/dp/txrx3.0/dp_txrx.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -37,12 +37,14 @@ struct dp_txrx_handle_cmn;
 /**
  * struct dp_txrx_handle - main dp txrx container handle
  * @soc: ol_txrx_soc_handle soc handle
+ * @refill_thread: rx refill thread infra handle
  * @rx_tm_hdl: rx thread infrastructure handle
  */
 struct dp_txrx_handle {
 	ol_txrx_soc_handle soc;
 	struct cdp_pdev *pdev;
 	struct dp_rx_tm_handle rx_tm_hdl;
+	struct dp_rx_refill_thread refill_thread;
 	struct dp_txrx_config config;
 };
 
@@ -187,6 +189,7 @@ static inline QDF_STATUS dp_txrx_resume(ol_txrx_soc_handle soc)
 {
 	struct dp_txrx_handle *dp_ext_hdl;
 	QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
+	struct dp_rx_refill_thread *refill_thread;
 
 	if (!soc) {
 		qdf_status = QDF_STATUS_E_INVAL;
@@ -199,6 +202,13 @@ static inline QDF_STATUS dp_txrx_resume(ol_txrx_soc_handle soc)
 		goto ret;
 	}
 
+	refill_thread = &dp_ext_hdl->refill_thread;
+	if (refill_thread->enabled) {
+		qdf_status = dp_rx_refill_thread_resume(refill_thread);
+		if (qdf_status != QDF_STATUS_SUCCESS)
+			return qdf_status;
+	}
+
 	qdf_status = dp_rx_tm_resume(&dp_ext_hdl->rx_tm_hdl);
 ret:
 	return qdf_status;
@@ -214,6 +224,7 @@ static inline QDF_STATUS dp_txrx_suspend(ol_txrx_soc_handle soc)
 {
 	struct dp_txrx_handle *dp_ext_hdl;
 	QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
+	struct dp_rx_refill_thread *refill_thread;
 
 	if (!soc) {
 		qdf_status = QDF_STATUS_E_INVAL;
@@ -226,6 +237,13 @@ static inline QDF_STATUS dp_txrx_suspend(ol_txrx_soc_handle soc)
 		goto ret;
 	}
 
+	refill_thread = &dp_ext_hdl->refill_thread;
+	if (refill_thread->enabled) {
+		qdf_status = dp_rx_refill_thread_suspend(refill_thread);
+		if (qdf_status != QDF_STATUS_SUCCESS)
+			return qdf_status;
+	}
+
 	qdf_status = dp_rx_tm_suspend(&dp_ext_hdl->rx_tm_hdl);
 
 ret: