s390/qeth: integrate RX refill worker with NAPI
authorJulian Wiedmann <jwi@linux.ibm.com>
Thu, 30 Jul 2020 15:01:19 +0000 (17:01 +0200)
committerDavid S. Miller <davem@davemloft.net>
Fri, 31 Jul 2020 23:44:35 +0000 (16:44 -0700)
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>
drivers/s390/net/qeth_core.h
drivers/s390/net/qeth_core_main.c
drivers/s390/net/qeth_l2_main.c
drivers/s390/net/qeth_l3_main.c

index 3d54c8bbfa86eab1d480064c4f77c443b7c972b9..ecfd6d152e8624e24cea153a65561fed8075615e 100644 (file)
@@ -764,6 +764,7 @@ struct qeth_rx {
        u8 buf_element;
        int e_offset;
        int qdio_err;
+       u8 bufs_refill;
 };
 
 struct carrier_info {
@@ -833,7 +834,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;
 };
 
index b356ee5de9f8d02e7732b1b21ab35e97b635238c..c2e44853ac1aff24e2bfb9b847d2b9ae32db549f 100644 (file)
@@ -3492,20 +3492,15 @@ static int qeth_check_qdio_errors(struct qeth_card *card,
        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;
@@ -3533,12 +3528,11 @@ static void qeth_queue_input_buffer(struct qeth_card *card, int index)
                                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;
                }
 
                /*
@@ -3555,7 +3549,10 @@ static void qeth_queue_input_buffer(struct qeth_card *card, int index)
                }
                queue->next_buf_to_init = QDIO_BUFNR(queue->next_buf_to_init +
                                                     count);
+               return count;
        }
+
+       return 0;
 }
 
 static void qeth_buffer_reclaim_work(struct work_struct *work)
@@ -3563,8 +3560,10 @@ static void qeth_buffer_reclaim_work(struct work_struct *work)
        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,
@@ -5743,6 +5742,7 @@ static unsigned int qeth_extract_skbs(struct qeth_card *card, int budget,
 
 static unsigned int qeth_rx_poll(struct qeth_card *card, int budget)
 {
+       struct qeth_rx *ctx = &card->rx;
        unsigned int work_done = 0;
 
        while (budget > 0) {
@@ -5779,8 +5779,10 @@ static unsigned int qeth_rx_poll(struct qeth_card *card, int budget)
                        QETH_CARD_STAT_INC(card, rx_bufs);
                        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);
 
                        /* Step forward to next buffer: */
                        card->rx.b_index = QDIO_BUFNR(card->rx.b_index + 1);
@@ -5820,9 +5822,16 @@ int qeth_poll(struct napi_struct *napi, int budget)
        if (card->options.cq == QETH_CQ_ENABLED)
                qeth_cq_poll(card);
 
-       /* Exhausted the RX budget. Keep IRQ disabled, we get called again. */
-       if (budget && work_done >= budget)
-               return work_done;
+       if (budget) {
+               struct qeth_rx *ctx = &card->rx;
+
+               /* Process any substantial refill backlog: */
+               ctx->bufs_refill -= qeth_rx_refill_queue(card, ctx->bufs_refill);
+
+               /* Exhausted the RX budget. Keep IRQ disabled, we get called again. */
+               if (work_done >= budget)
+                       return work_done;
+       }
 
        if (napi_complete_done(napi, work_done) &&
            qdio_start_irq(CARD_DDEV(card)))
@@ -7009,6 +7018,7 @@ int qeth_stop(struct net_device *dev)
        }
 
        napi_disable(&card->napi);
+       cancel_delayed_work_sync(&card->buffer_reclaim_work);
        qdio_stop_irq(CARD_DDEV(card));
 
        return 0;
index ef7a2db7a7245296bf79b905c6b898b6f709f190..38e97bbde9edcf74f8e29e7b0fd495c24baed4e1 100644 (file)
@@ -285,7 +285,6 @@ static void qeth_l2_stop_card(struct qeth_card *card)
        if (card->state == CARD_STATE_SOFTSETUP) {
                qeth_clear_ipacmd_list(card);
                qeth_drain_output_queues(card);
-               cancel_delayed_work_sync(&card->buffer_reclaim_work);
                card->state = CARD_STATE_DOWN;
        }
 
index 15a12487ff7a3192295bd45d8affe7aaaac11247..fe44b0249e34ad3d8eb8ee0940e132617547974e 100644 (file)
@@ -1169,7 +1169,6 @@ static void qeth_l3_stop_card(struct qeth_card *card)
                qeth_l3_clear_ip_htable(card, 1);
                qeth_clear_ipacmd_list(card);
                qeth_drain_output_queues(card);
-               cancel_delayed_work_sync(&card->buffer_reclaim_work);
                card->state = CARD_STATE_DOWN;
        }