diff options
| author | Daniel Zahka <daniel.zahka@gmail.com> | 2026-10-01 09:39:01 -0700 |
|---|---|---|
| committer | Jakub Kicinski <kuba@kernel.org> | 2026-10-05 16:51:17 -0700 |
| commit | 56f2178ff7f6c1f458eeb5f79ab2385028ae8a02 (patch) | |
| tree | 89e9d6fbcab431adc1ff0cd39d5fd1aa45e9f19f | |
| parent | 9e072eda51cadc944c7c0d6b64d9c7169d43a5ad (diff) | |
eth: mpnic: add a NAPI depletion check
The Rx path can wedge if page pool allocations fail in
__mpnic_fill_bdq(). The problematic sequence is: page pool allocations
fail, bdq rings are empty, device receives packet from the network, but
drops it for lack of buffer space and does not raise interrupt,
mpnic_poll() does not run, so page pool allocations are not retried.
To break out of this cycle, we can add a depletion check to our service
task. The depletion check checks if posted buffers are under a low
watermark, and raises a completion queue interrupt, so that mpnic_poll
will run on the corresponding napi vector.
A note about the lock free reads: We don't bother synchronizing the ring
head and tail reads with mpnic_poll(), because a false positive signal
would simply raise a spurious interrupt scheduling mpnic_poll(), and a
false negative signal will result in a retry, where if mpnic_poll() has
truly not been running, should then report accurately whether or not
posted Rx buffers are low.
Signed-off-by: Daniel Zahka <daniel.zahka@gmail.com>
Reviewed-by: Harshitha Ramamurthy <hramamurthy@google.com>
Link: https://patch.msgid.link/20261001-linux-mpnic-v1-4-6422ee74233a@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
| -rw-r--r-- | drivers/net/ethernet/meta/mpnic/mpnic_pci.c | 4 | ||||
| -rw-r--r-- | drivers/net/ethernet/meta/mpnic/mpnic_txrx.c | 31 | ||||
| -rw-r--r-- | drivers/net/ethernet/meta/mpnic/mpnic_txrx.h | 1 |
3 files changed, 36 insertions, 0 deletions
diff --git a/drivers/net/ethernet/meta/mpnic/mpnic_pci.c b/drivers/net/ethernet/meta/mpnic/mpnic_pci.c index 17eae5a9ba16..125fb26edf93 100644 --- a/drivers/net/ethernet/meta/mpnic/mpnic_pci.c +++ b/drivers/net/ethernet/meta/mpnic/mpnic_pci.c @@ -11,6 +11,7 @@ #include "mpnic.h" #include "mpnic_netdev.h" +#include "mpnic_txrx.h" #define PCI_DEVICE_ID_META_MPNIC 0x0014 @@ -61,6 +62,9 @@ static void mpnic_service_task(struct work_struct *work) netdev_lock(netdev); + if (netif_carrier_ok(netdev)) + mpnic_napi_depletion_check(netdev_priv(netdev)); + if (netif_running(netdev)) schedule_delayed_work(&mpd->service_task, HZ); diff --git a/drivers/net/ethernet/meta/mpnic/mpnic_txrx.c b/drivers/net/ethernet/meta/mpnic/mpnic_txrx.c index 49061c7316d5..5495e9a9aa65 100644 --- a/drivers/net/ethernet/meta/mpnic/mpnic_txrx.c +++ b/drivers/net/ethernet/meta/mpnic/mpnic_txrx.c @@ -55,6 +55,12 @@ static unsigned int mpnic_desc_unused(struct mpnic_ring *ring) return (ring->head - ring->tail - 1) & ring->size_mask; } +static unsigned int mpnic_desc_used(struct mpnic_ring *ring) +{ + return (READ_ONCE(ring->tail) - READ_ONCE(ring->head)) & + ring->size_mask; +} + static struct netdev_queue *mpnic_txring_txq(const struct net_device *dev, const struct mpnic_ring *ring) { @@ -1393,3 +1399,28 @@ void mpnic_napi_enable(struct mpnic_net *mpn) mpnic_wrfl(mpn->mpd); } + +void mpnic_napi_depletion_check(struct mpnic_net *mpn) +{ + int i, j, t; + + for (i = 0; i < mpn->num_napi; i++) { + struct mpnic_napi_vector *nv = mpn->napi[i]; + + for (t = nv->txt_count, j = 0; j < nv->rxt_count; j++, t++) { + /* Check if BDs posted covers a max sized frame + * + 1 BD held by RDE as a spare + * + 1 BD of extra safety margin + */ + if (mpnic_desc_used(&nv->qt[t].sub0) < + MPNIC_RX_HPQ_DROP_THRS + 2 || + mpnic_desc_used(&nv->qt[t].sub1) < + MPNIC_RX_PPQ_DROP_THRS + 2) { + mpnic_nv_irq_trigger(nv); + break; + } + } + } + + mpnic_wrfl(mpn->mpd); +} diff --git a/drivers/net/ethernet/meta/mpnic/mpnic_txrx.h b/drivers/net/ethernet/meta/mpnic/mpnic_txrx.h index 9397010557eb..767d87a36c35 100644 --- a/drivers/net/ethernet/meta/mpnic/mpnic_txrx.h +++ b/drivers/net/ethernet/meta/mpnic/mpnic_txrx.h @@ -148,6 +148,7 @@ int mpnic_set_netif_queues(struct mpnic_net *mpn); void mpnic_reset_netif_queues(struct mpnic_net *mpn); void mpnic_napi_enable(struct mpnic_net *mpn); void mpnic_napi_disable(struct mpnic_net *mpn); +void mpnic_napi_depletion_check(struct mpnic_net *mpn); void mpnic_enable(struct mpnic_net *mpn); void mpnic_disable(struct mpnic_net *mpn); void mpnic_wait_all_queues_idle(struct mpnic_dev *mpd); |
