Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mlxbf_gige: fix receive packet race condition

Under heavy traffic, the BlueField Gigabit interface can
become unresponsive. This is due to a possible race condition
in the mlxbf_gige_rx_packet function, where the function exits
with producer and consumer indices equal but there are remaining
packet(s) to be processed. In order to prevent this situation,
read receive consumer index *before* the HW replenish so that
the mlxbf_gige_rx_packet function returns an accurate return
value even if a packet is received into just-replenished buffer
prior to exiting this routine. If the just-replenished buffer
is received and occupies the last RX ring entry, the interface
would not recover and instead would encounter RX packet drops
related to internal buffer shortages since the driver RX logic
is not being triggered to drain the RX ring. This patch will
address and prevent this "ring full" condition.

Fixes: f92e1869d74e ("Add Mellanox BlueField Gigabit Ethernet driver")
Reviewed-by: Asmaa Mnebhi <asmaa@nvidia.com>
Signed-off-by: David Thompson <davthompson@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

David Thompson and committed by
David S. Miller
dcea1bd4 97417cd7

+7 -2
+7 -2
drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c
··· 267 267 priv->stats.rx_truncate_errors++; 268 268 } 269 269 270 + /* Read receive consumer index before replenish so that this routine 271 + * returns accurate return value even if packet is received into 272 + * just-replenished buffer prior to exiting this routine. 273 + */ 274 + rx_ci = readq(priv->base + MLXBF_GIGE_RX_CQE_PACKET_CI); 275 + rx_ci_rem = rx_ci % priv->rx_q_entries; 276 + 270 277 /* Let hardware know we've replenished one buffer */ 271 278 rx_pi++; 272 279 ··· 286 279 rx_pi_rem = rx_pi % priv->rx_q_entries; 287 280 if (rx_pi_rem == 0) 288 281 priv->valid_polarity ^= 1; 289 - rx_ci = readq(priv->base + MLXBF_GIGE_RX_CQE_PACKET_CI); 290 - rx_ci_rem = rx_ci % priv->rx_q_entries; 291 282 292 283 if (skb) 293 284 netif_receive_skb(skb);