qcacld-3.0: Refine RX GRO flush when detach the vdev device

There might be race condition when doing RX GRO flush between dp_rx_thread
and vdev detach thread.

Only doing RX GRO flush in the dp_rx_thread context, and use the events to
sync with dp_rx_thread and vdev detach thread.

Change-Id: I2dbf92c2c11e950ca790dd7429c8bb235c239d0c
CRs-Fixed: 2601826
This commit is contained in:
Tiger Yu 2020-01-10 12:31:36 +08:00 • committed by nshrivas
commit 0da98c48ee
3 changed files with 41 additions and 7 deletions

View file

@ -45,6 +45,7 @@
#define MC_SUSPEND_EVENT 0x002
#define RX_POST_EVENT 0x001
#define RX_SUSPEND_EVENT 0x002
#define RX_VDEV_DEL_EVENT 0x004
#define RX_SHUTDOWN_EVENT 0x010
#ifdef QCA_CONFIG_SMP

View file

@ -104,7 +104,7 @@ static void dp_rx_tm_thread_dump_stats(struct dp_rx_thread *rx_thread)
if (!total_queued)
return;
dp_info("thread:%u - qlen:%u queued:(total:%u %s) dequeued:%u stack:%u gro_flushes: %u rx_flushes: %u max_len:%u invalid(peer:%u vdev:%u rx-handle:%u others:%u)",
dp_info("thread:%u - qlen:%u queued:(total:%u %s) dequeued:%u stack:%u gro_flushes: %u gro_flushes_by_vdev_del: %u rx_flushes: %u max_len:%u invalid(peer:%u vdev:%u rx-handle:%u others:%u)",
rx_thread->id,
qdf_nbuf_queue_head_qlen(&rx_thread->nbuf_queue),
total_queued,
@ -112,6 +112,7 @@ static void dp_rx_tm_thread_dump_stats(struct dp_rx_thread *rx_thread)
rx_thread->stats.nbuf_dequeued,
rx_thread->stats.nbuf_sent_to_stack,
rx_thread->stats.gro_flushes,
rx_thread->stats.gro_flushes_by_vdev_del,
rx_thread->stats.rx_flushed,
rx_thread->stats.nbufq_max_len,
rx_thread->stats.dropped_invalid_peer,
@ -384,11 +385,19 @@ static int dp_rx_thread_sub_loop(struct dp_rx_thread *rx_thread, bool *shutdown)
dp_rx_thread_process_nbufq(rx_thread);
if (qdf_atomic_read(&rx_thread->gro_flush_ind)) {
if (qdf_atomic_read(&rx_thread->gro_flush_ind) |
qdf_atomic_test_bit(RX_VDEV_DEL_EVENT,
&rx_thread->event_flag)) {
dp_rx_thread_gro_flush(rx_thread);
qdf_atomic_set(&rx_thread->gro_flush_ind, 0);
}
if (qdf_atomic_test_and_clear_bit(RX_VDEV_DEL_EVENT,
&rx_thread->event_flag)) {
rx_thread->stats.gro_flushes_by_vdev_del++;
qdf_event_set(&rx_thread->vdev_del_event);
}
if (qdf_atomic_test_and_clear_bit(RX_SUSPEND_EVENT,
&rx_thread->event_flag)) {
dp_debug("received suspend ind (%s) id %d pid %d",
@ -441,6 +450,8 @@ static int dp_rx_thread_loop(void *arg)
qdf_atomic_test_bit(RX_POST_EVENT,
&rx_thread->event_flag) ||
qdf_atomic_test_bit(RX_SUSPEND_EVENT,
&rx_thread->event_flag) ||
qdf_atomic_test_bit(RX_VDEV_DEL_EVENT,
&rx_thread->event_flag));
dp_debug("woken up");
@ -528,6 +539,7 @@ static QDF_STATUS dp_rx_tm_thread_init(struct dp_rx_thread *rx_thread,
qdf_event_create(&rx_thread->suspend_event);
qdf_event_create(&rx_thread->resume_event);
qdf_event_create(&rx_thread->shutdown_event);
qdf_event_create(&rx_thread->vdev_del_event);
qdf_atomic_init(&rx_thread->gro_flush_ind);
qdf_init_waitqueue_head(&rx_thread->wait_q);
qdf_scnprintf(thread_name, sizeof(thread_name), "dp_rx_thread_%u", id);
@ -567,6 +579,7 @@ static QDF_STATUS dp_rx_tm_thread_deinit(struct dp_rx_thread *rx_thread)
qdf_event_destroy(&rx_thread->suspend_event);
qdf_event_destroy(&rx_thread->resume_event);
qdf_event_destroy(&rx_thread->shutdown_event);
qdf_event_destroy(&rx_thread->vdev_del_event);
if (cdp_cfg_get(dp_rx_tm_get_soc_handle(rx_thread->rtm_handle_cmn),
cfg_dp_gro_enable))
@ -680,6 +693,10 @@ QDF_STATUS dp_rx_tm_suspend(struct dp_rx_tm_handle *rx_tm_hdl)
* to be flushed out
* @vdev_id: vdev id for which packets are to be flushed
*
* The function will flush the RX packets by vdev_id in a particular
* RX thead queue. And will notify and wait the TX thread to flush the
* packets in the NAPI RX GRO hash list
*
* Return: void
*/
static inline
@ -688,6 +705,7 @@ void dp_rx_thread_flush_by_vdev_id(struct dp_rx_thread *rx_thread,
{
qdf_nbuf_t nbuf_list, tmp_nbuf_list;
uint32_t num_list_elements = 0;
QDF_STATUS qdf_status;
qdf_nbuf_queue_head_lock(&rx_thread->nbuf_queue);
QDF_NBUF_QUEUE_WALK_SAFE(&rx_thread->nbuf_queue, nbuf_list,
@ -704,10 +722,20 @@ void dp_rx_thread_flush_by_vdev_id(struct dp_rx_thread *rx_thread,
}
qdf_nbuf_queue_head_unlock(&rx_thread->nbuf_queue);
if (qdf_atomic_read(&rx_thread->gro_flush_ind))
qdf_atomic_set(&rx_thread->gro_flush_ind, 0);
qdf_set_bit(RX_VDEV_DEL_EVENT, &rx_thread->event_flag);
qdf_wake_up_interruptible(&rx_thread->wait_q);
dp_rx_thread_gro_flush(rx_thread);
qdf_status = qdf_wait_single_event(&rx_thread->vdev_del_event,
DP_RX_THREAD_WAIT_TIMEOUT);
if (QDF_IS_STATUS_SUCCESS(qdf_status))
dp_debug("thread:%d napi gro flush successfully",
rx_thread->id);
else if (qdf_status == QDF_STATUS_E_TIMEOUT)
dp_err("thread:%d timed out waiting for napi gro flush",
rx_thread->id);
else
dp_err("thread:%d failed while waiting for napi gro flush",
rx_thread->id);
}
/**

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014-2019 The Linux Foundation. All rights reserved.
* Copyright (c) 2014-2020 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
@ -44,6 +44,7 @@ struct dp_rx_tm_handle_cmn;
* @nbuf_sent_to_stack: packets sent to the stack. some dequeued packets may be
* dropped due to no peer or vdev, hence this stat.
* @gro_flushes: number of GRO flushes
* @gro_flushes_by_vdev_del: number of GRO flushes triggered by vdev del.
* @nbufq_max_len: maximum number of nbuf_lists queued for the thread
* @dropped_invalid_vdev: packets(nbuf_list) dropped due to no vdev
* @rx_flushed: packets flushed after vdev delete
@ -56,6 +57,7 @@ struct dp_rx_thread_stats {
unsigned int nbuf_dequeued;
unsigned int nbuf_sent_to_stack;
unsigned int gro_flushes;
unsigned int gro_flushes_by_vdev_del;
unsigned int nbufq_max_len;
unsigned int dropped_invalid_vdev;
unsigned int rx_flushed;
@ -72,6 +74,8 @@ struct dp_rx_thread_stats {
* @suspend_event: handle of Event for DP Rx thread to signal suspend
* @resume_event: handle of Event for DP Rx thread to signal resume
* @shutdown_event: handle of Event for DP Rx thread to signal shutdown
* @vdev_del_event: handle of Event for vdev del thread to signal completion
* for gro flush
* @event_flag: event flag to post events to DP Rx thread
* @nbuf_queue:nbuf queue used to store RX packets
* @nbufq_len: length of the nbuf queue
@ -89,6 +93,7 @@ struct dp_rx_thread {
qdf_event_t suspend_event;
qdf_event_t resume_event;
qdf_event_t shutdown_event;
qdf_event_t vdev_del_event;
qdf_atomic_t gro_flush_ind;
unsigned long event_flag;
qdf_nbuf_queue_head_t nbuf_queue;