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
This commit is contained in:
Karthik Kantamneni 2021-01-27 19:41:01 +05:30 committed by Gerrit - the friendly Code Review server
parent 488ff19efc
commit 0c7c251f6e
5 changed files with 362 additions and 4 deletions

View File

@ -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

View File

@ -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>
@ -581,6 +582,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
@ -697,6 +778,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)
{
@ -805,6 +940,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
@ -920,6 +1099,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

View File

@ -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

View File

@ -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);

View File

@ -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: