Blob Blame History Raw
From: Julian Wiedmann <jwi@linux.ibm.com>
Date: Thu, 30 Jul 2020 17:01:19 +0200
Subject: s390/qeth: integrate RX refill worker with NAPI
Git-commit: 7c94a88295008f66e9a0efc1c15d8511f73a0366
Patch-mainline: v5.9-rc1
References: git-fixes

Running a RX refill outside of NAPI context is inherently racy, even
though the worker is only started for an entirely idle RX ring.
>From the moment that the worker has replenished parts of the RX ring,
the HW can use those RX buffers, raise an IRQ and cause our NAPI code to
run concurrently to the RX refill worker.

Instead let the worker schedule our NAPI instance, and refill the RX
ring from there. Keeping accurate count of how many buffers still need
to be refilled also removes some quirky arithmetic from the low-level
code.

Fixes: b333293058aa ("qeth: add support for af_iucv HiperSockets transport")
Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Acked-by: Petr Tesarik <ptesarik@suse.com>
---
 drivers/s390/net/qeth_core.h      |    2 +-
 drivers/s390/net/qeth_core_main.c |   31 +++++++++++++++++++------------
 drivers/s390/net/qeth_l2_main.c   |    2 +-
 drivers/s390/net/qeth_l3_main.c   |    2 +-
 4 files changed, 22 insertions(+), 15 deletions(-)

--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -759,6 +759,7 @@ struct qeth_rx {
 	struct qdio_buffer_element *b_element;
 	int e_offset;
 	int qdio_err;
+	u8 bufs_refill;
 };
 
 struct carrier_info {
@@ -825,7 +826,6 @@ struct qeth_card {
 	struct napi_struct napi;
 	struct qeth_rx rx;
 	struct delayed_work buffer_reclaim_work;
-	int reclaim_index;
 	struct work_struct close_dev_work;
 };
 
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -3214,20 +3214,15 @@ static int qeth_check_qdio_errors(struct
 	return 0;
 }
 
-static void qeth_queue_input_buffer(struct qeth_card *card, int index)
+static unsigned int qeth_rx_refill_queue(struct qeth_card *card,
+					 unsigned int count)
 {
 	struct qeth_qdio_q *queue = card->qdio.in_q;
 	struct list_head *lh;
-	int count;
 	int i;
 	int rc;
 	int newcount = 0;
 
-	count = (index < queue->next_buf_to_init)?
-		card->qdio.in_buf_pool.buf_count -
-		(queue->next_buf_to_init - index) :
-		card->qdio.in_buf_pool.buf_count -
-		(queue->next_buf_to_init + QDIO_MAX_BUFFERS_PER_Q - index);
 	/* only requeue at a certain threshold to avoid SIGAs */
 	if (count >= QETH_IN_BUF_REQUEUE_THRESHOLD(card)) {
 		for (i = queue->next_buf_to_init;
@@ -3255,12 +3250,11 @@ static void qeth_queue_input_buffer(stru
 				i++;
 			if (i == card->qdio.in_buf_pool.buf_count) {
 				QETH_CARD_TEXT(card, 2, "qsarbw");
-				card->reclaim_index = index;
 				schedule_delayed_work(
 					&card->buffer_reclaim_work,
 					QETH_RECLAIM_WORK_TIME);
 			}
-			return;
+			return 0;
 		}
 
 		/*
@@ -3286,7 +3280,10 @@ static void qeth_queue_input_buffer(stru
 		}
 		queue->next_buf_to_init = (queue->next_buf_to_init + count) %
 					  QDIO_MAX_BUFFERS_PER_Q;
+		return count;
 	}
+
+	return 0;
 }
 
 static void qeth_buffer_reclaim_work(struct work_struct *work)
@@ -3294,8 +3291,10 @@ static void qeth_buffer_reclaim_work(str
 	struct qeth_card *card = container_of(work, struct qeth_card,
 		buffer_reclaim_work.work);
 
-	QETH_CARD_TEXT_(card, 2, "brw:%x", card->reclaim_index);
-	qeth_queue_input_buffer(card, card->reclaim_index);
+	local_bh_disable();
+	napi_schedule(&card->napi);
+	/* kick-start the NAPI softirq: */
+	local_bh_enable();
 }
 
 static void qeth_handle_send_error(struct qeth_card *card,
@@ -5386,6 +5385,7 @@ EXPORT_SYMBOL_GPL(qeth_core_get_next_skb
 int qeth_poll(struct napi_struct *napi, int budget)
 {
 	struct qeth_card *card = container_of(napi, struct qeth_card, napi);
+	struct qeth_rx *ctx = &card->rx;
 	int work_done = 0;
 	struct qeth_qdio_buffer *buffer;
 	int done;
@@ -5429,8 +5429,11 @@ int qeth_poll(struct napi_struct *napi,
 				qeth_put_buffer_pool_entry(card,
 					buffer->pool_entry);
 				buffer->pool_entry = NULL;
-				qeth_queue_input_buffer(card, card->rx.b_index);
 				card->rx.b_count--;
+				ctx->bufs_refill++;
+				ctx->bufs_refill -=
+					qeth_rx_refill_queue(card,
+							     ctx->bufs_refill);
 				if (card->rx.b_count) {
 					card->rx.b_index =
 						(card->rx.b_index + 1) %
@@ -5443,6 +5446,10 @@ int qeth_poll(struct napi_struct *napi,
 				}
 			}
 
+				if (budget)
+					/* Process any substantial refill backlog: */
+					ctx->bufs_refill -= qeth_rx_refill_queue(card, ctx->bufs_refill);
+
 			if (work_done >= budget)
 				goto out;
 			else
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -384,7 +384,6 @@ static void qeth_l2_stop_card(struct qet
 	if (card->state == CARD_STATE_HARDSETUP) {
 		qeth_clear_qdio_buffers(card);
 		qeth_clear_working_pool_list(card);
-		cancel_delayed_work_sync(&card->buffer_reclaim_work);
 		card->state = CARD_STATE_DOWN;
 	}
 	if (card->state == CARD_STATE_DOWN) {
@@ -788,6 +787,7 @@ static int qeth_l2_stop(struct net_devic
 	if (card->state == CARD_STATE_UP) {
 		card->state = CARD_STATE_SOFTSETUP;
 		napi_disable(&card->napi);
+		cancel_delayed_work_sync(&card->buffer_reclaim_work);
 	}
 	return 0;
 }
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -1428,7 +1428,6 @@ static void qeth_l3_stop_card(struct qet
 	if (card->state == CARD_STATE_HARDSETUP) {
 		qeth_clear_qdio_buffers(card);
 		qeth_clear_working_pool_list(card);
-		cancel_delayed_work_sync(&card->buffer_reclaim_work);
 		card->state = CARD_STATE_DOWN;
 	}
 	if (card->state == CARD_STATE_DOWN) {
@@ -2281,6 +2280,7 @@ static int qeth_l3_stop(struct net_devic
 	if (card->state == CARD_STATE_UP) {
 		card->state = CARD_STATE_SOFTSETUP;
 		napi_disable(&card->napi);
+		cancel_delayed_work_sync(&card->buffer_reclaim_work);
 	}
 	return 0;
 }