Skip to content

Commit 58a6372

Browse files
longlimsftPaolo Abeni
authored andcommitted
net: mana: Fix doorbell out of order violation and avoid unnecessary doorbell rings
After napi_complete_done() is called when NAPI is polling in the current process context, another NAPI may be scheduled and start running in softirq on another CPU and may ring the doorbell before the current CPU does. When combined with unnecessary rings when there is no need to arm the CQ, it triggers error paths in the hardware. This patch fixes this by calling napi_complete_done() after doorbell rings. It limits the number of unnecessary rings when there is no need to arm. MANA hardware specifies that there must be one doorbell ring every 8 CQ wraparounds. This driver guarantees one doorbell ring as soon as the number of consumed CQEs exceeds 4 CQ wraparounds. In practical workloads, the 4 CQ wraparounds proves to be big enough that it rarely exceeds this limit before all the napi weight is consumed. To implement this, add a per-CQ counter cq->work_done_since_doorbell, and make sure the CQ is armed as soon as passing 4 wraparounds of the CQ. Cc: stable@vger.kernel.org Fixes: e1b5683 ("net: mana: Move NAPI from EQ to CQ") Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com> Signed-off-by: Long Li <longli@microsoft.com> Link: https://patch.msgid.link/1723219138-29887-1-git-send-email-longli@linuxonhyperv.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
1 parent 6e1918f commit 58a6372

2 files changed

Lines changed: 16 additions & 9 deletions

File tree

drivers/net/ethernet/microsoft/mana/mana_en.c

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1792,7 +1792,6 @@ static void mana_poll_rx_cq(struct mana_cq *cq)
17921792
static int mana_cq_handler(void *context, struct gdma_queue *gdma_queue)
17931793
{
17941794
struct mana_cq *cq = context;
1795-
u8 arm_bit;
17961795
int w;
17971796

17981797
WARN_ON_ONCE(cq->gdma_cq != gdma_queue);
@@ -1803,16 +1802,23 @@ static int mana_cq_handler(void *context, struct gdma_queue *gdma_queue)
18031802
mana_poll_tx_cq(cq);
18041803

18051804
w = cq->work_done;
1806-
1807-
if (w < cq->budget &&
1808-
napi_complete_done(&cq->napi, w)) {
1809-
arm_bit = SET_ARM_BIT;
1810-
} else {
1811-
arm_bit = 0;
1805+
cq->work_done_since_doorbell += w;
1806+
1807+
if (w < cq->budget) {
1808+
mana_gd_ring_cq(gdma_queue, SET_ARM_BIT);
1809+
cq->work_done_since_doorbell = 0;
1810+
napi_complete_done(&cq->napi, w);
1811+
} else if (cq->work_done_since_doorbell >
1812+
cq->gdma_cq->queue_size / COMP_ENTRY_SIZE * 4) {
1813+
/* MANA hardware requires at least one doorbell ring every 8
1814+
* wraparounds of CQ even if there is no need to arm the CQ.
1815+
* This driver rings the doorbell as soon as we have exceeded
1816+
* 4 wraparounds.
1817+
*/
1818+
mana_gd_ring_cq(gdma_queue, 0);
1819+
cq->work_done_since_doorbell = 0;
18121820
}
18131821

1814-
mana_gd_ring_cq(gdma_queue, arm_bit);
1815-
18161822
return w;
18171823
}
18181824

include/net/mana/mana.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ struct mana_cq {
275275
/* NAPI data */
276276
struct napi_struct napi;
277277
int work_done;
278+
int work_done_since_doorbell;
278279
int budget;
279280
};
280281

0 commit comments

Comments
 (0)