| From dabffd08545ffa1d7183bc45e387860984025291 Mon Sep 17 00:00:00 2001 |
| From: Long Li <longli@microsoft.com> |
| Date: Thu, 26 Feb 2026 11:28:33 -0800 |
| Subject: net: mana: Ring doorbell at 4 CQ wraparounds |
| |
| From: Long Li <longli@microsoft.com> |
| |
| commit dabffd08545ffa1d7183bc45e387860984025291 upstream. |
| |
| MANA hardware requires at least one doorbell ring every 8 wraparounds |
| of the CQ. The driver rings the doorbell as a form of flow control to |
| inform hardware that CQEs have been consumed. |
| |
| The NAPI poll functions mana_poll_tx_cq() and mana_poll_rx_cq() can |
| poll up to CQE_POLLING_BUFFER (512) completions per call. If the CQ |
| has fewer than 512 entries, a single poll call can process more than |
| 4 wraparounds without ringing the doorbell. The doorbell threshold |
| check also uses ">" instead of ">=", delaying the ring by one extra |
| CQE beyond 4 wraparounds. Combined, these issues can cause the driver |
| to exceed the 8-wraparound hardware limit, leading to missed |
| completions and stalled queues. |
| |
| Fix this by capping the number of CQEs polled per call to 4 wraparounds |
| of the CQ in both TX and RX paths. Also change the doorbell threshold |
| from ">" to ">=" so the doorbell is rung as soon as 4 wraparounds are |
| reached. |
| |
| Cc: stable@vger.kernel.org |
| Fixes: 58a63729c957 ("net: mana: Fix doorbell out of order violation and avoid unnecessary doorbell rings") |
| Signed-off-by: Long Li <longli@microsoft.com> |
| Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com> |
| Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev> |
| Link: https://patch.msgid.link/20260226192833.1050807-1-longli@microsoft.com |
| Signed-off-by: Jakub Kicinski <kuba@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/net/ethernet/microsoft/mana/mana_en.c | 23 ++++++++++++++++++----- |
| 1 file changed, 18 insertions(+), 5 deletions(-) |
| |
| --- a/drivers/net/ethernet/microsoft/mana/mana_en.c |
| +++ b/drivers/net/ethernet/microsoft/mana/mana_en.c |
| @@ -798,8 +798,14 @@ static void mana_poll_tx_cq(struct mana_ |
| ndev = txq->ndev; |
| apc = netdev_priv(ndev); |
| |
| + /* Limit CQEs polled to 4 wraparounds of the CQ to ensure the |
| + * doorbell can be rung in time for the hardware's requirement |
| + * of at least one doorbell ring every 8 wraparounds. |
| + */ |
| comp_read = mana_gd_poll_cq(cq->gdma_cq, completions, |
| - CQE_POLLING_BUFFER); |
| + min((cq->gdma_cq->queue_size / |
| + COMP_ENTRY_SIZE) * 4, |
| + CQE_POLLING_BUFFER)); |
| |
| if (comp_read < 1) |
| return; |
| @@ -1056,7 +1062,14 @@ static void mana_poll_rx_cq(struct mana_ |
| struct gdma_comp *comp = cq->gdma_comp_buf; |
| int comp_read, i; |
| |
| - comp_read = mana_gd_poll_cq(cq->gdma_cq, comp, CQE_POLLING_BUFFER); |
| + /* Limit CQEs polled to 4 wraparounds of the CQ to ensure the |
| + * doorbell can be rung in time for the hardware's requirement |
| + * of at least one doorbell ring every 8 wraparounds. |
| + */ |
| + comp_read = mana_gd_poll_cq(cq->gdma_cq, comp, |
| + min((cq->gdma_cq->queue_size / |
| + COMP_ENTRY_SIZE) * 4, |
| + CQE_POLLING_BUFFER)); |
| WARN_ON_ONCE(comp_read > CQE_POLLING_BUFFER); |
| |
| for (i = 0; i < comp_read; i++) { |
| @@ -1090,11 +1103,11 @@ static int mana_cq_handler(void *context |
| mana_gd_ring_cq(gdma_queue, SET_ARM_BIT); |
| cq->work_done_since_doorbell = 0; |
| napi_complete_done(&cq->napi, w); |
| - } else if (cq->work_done_since_doorbell > |
| - cq->gdma_cq->queue_size / COMP_ENTRY_SIZE * 4) { |
| + } else if (cq->work_done_since_doorbell >= |
| + (cq->gdma_cq->queue_size / COMP_ENTRY_SIZE) * 4) { |
| /* MANA hardware requires at least one doorbell ring every 8 |
| * wraparounds of CQ even if there is no need to arm the CQ. |
| - * This driver rings the doorbell as soon as we have exceeded |
| + * This driver rings the doorbell as soon as it has processed |
| * 4 wraparounds. |
| */ |
| mana_gd_ring_cq(gdma_queue, 0); |