The software completion ring masks its producer and consumer counters
when advancing them. When all entries are filled before any completion
is polled, the counters become equal and the ring is treated as empty.
Root-table rule operations generate completions directly into this ring,
so a full batch cannot be dequeued and the queue remains busy.
Keep the counters unmasked and apply the ring mask only when accessing
the completion array. This distinguishes a full ring from an empty one
without reducing the configured queue capacity.
The power-of-two ring capacity divides the 16-bit counter modulus, so
counter wrap preserves masked indices. Capacity also bounds outstanding
completions below that modulus, keeping full distinct from empty.
Fixes: 3eb748869d2d ("net/mlx5/hws: add send layer")
Cc: [email protected]
Signed-off-by: Maxime Peim <[email protected]>
---
drivers/net/mlx5/hws/mlx5dr_send.c | 8 +++++---
drivers/net/mlx5/hws/mlx5dr_send.h | 13 ++++++++++---
2 files changed, 15 insertions(+), 6 deletions(-)
diff --git a/drivers/net/mlx5/hws/mlx5dr_send.c
b/drivers/net/mlx5/hws/mlx5dr_send.c
index 85f613ed39..f94957dd27 100644
--- a/drivers/net/mlx5/hws/mlx5dr_send.c
+++ b/drivers/net/mlx5/hws/mlx5dr_send.c
@@ -646,12 +646,14 @@ static void mlx5dr_send_engine_poll_list(struct
mlx5dr_send_engine *queue,
while (comp->ci != comp->pi) {
if (*polled < res_nb) {
+ uint16_t idx = comp->ci & comp->mask;
+
res[*polled].status =
- comp->entries[comp->ci].status;
+ comp->entries[idx].status;
res[*polled].user_data =
- comp->entries[comp->ci].user_data;
+ comp->entries[idx].user_data;
(*polled)++;
- comp->ci = (comp->ci + 1) & comp->mask;
+ comp->ci++;
mlx5dr_send_engine_dec_rule(queue);
} else {
return;
diff --git a/drivers/net/mlx5/hws/mlx5dr_send.h
b/drivers/net/mlx5/hws/mlx5dr_send.h
index 9209754136..ad2488dca2 100644
--- a/drivers/net/mlx5/hws/mlx5dr_send.h
+++ b/drivers/net/mlx5/hws/mlx5dr_send.h
@@ -138,6 +138,12 @@ struct mlx5dr_completed_poll_entry {
struct mlx5dr_completed_poll {
struct mlx5dr_completed_poll_entry *entries;
+ /*
+ * Keep counters unmasked to distinguish full from empty, and mask
+ * only when indexing entries. The power-of-two capacity divides 2^16,
+ * so uint16_t wrap preserves masked indices. Capacity is less than
+ * 2^16 and bounds outstanding completions, so equal counters mean
empty.
+ */
uint16_t ci;
uint16_t pi;
uint16_t mask;
@@ -279,11 +285,12 @@ static inline void mlx5dr_send_engine_gen_comp(struct
mlx5dr_send_engine *queue,
int comp_status)
{
struct mlx5dr_completed_poll *comp = &queue->completed;
+ uint16_t idx = comp->pi & comp->mask;
- comp->entries[comp->pi].status = comp_status;
- comp->entries[comp->pi].user_data = user_data;
+ comp->entries[idx].status = comp_status;
+ comp->entries[idx].user_data = user_data;
- comp->pi = (comp->pi + 1) & comp->mask;
+ comp->pi++;
}
static inline bool mlx5dr_send_engine_err(struct mlx5dr_send_engine *queue)