ionic: fix completion descriptor access with 2x desc size

The old ionic_rx_service() and ionic_tx_service() used array
indexing to access completion descriptors:

    comp = &((struct ionic_rxq_comp *)cq->base)[cq->tail_idx];

This assumes the stride is sizeof(struct ionic_rxq_comp) = 16 bytes.
However, when the IONIC_Q_F_2X_CQ_DESC flag is set, the actual
completion descriptor size is 32 bytes (2 * sizeof(comp)), and the
completion itself is located at the end of that 32-byte slot. Array
indexing with a 16-byte stride would access the wrong offset.

Use pointer arithmetic that accounts for the actual descriptor size
from cq->desc_size:

    comp = cq->base +
           cq->desc_size * cq->tail_idx +
           cq->desc_size - sizeof(*comp);

This correctly calculates the completion location regardless of
descriptor size. For the common case where desc_size equals
sizeof(*comp), use array indexing in a likely() fast path to avoid
performance regression.

Fixes: 65e548f6b0 ("ionic: remove the cq_info to save more memory")
Signed-off-by: Prabu Thayalan <prabu.ponrajthayalan@amd.com>
Signed-off-by: Eric Joyner <eric.joyner@amd.com>
Reviewed-by: Brett Creeley <brett.creeley@amd.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20260811195039.1315045-3-eric.joyner@amd.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Prabu Thayalan 2026-08-11 12:50:39 -07:00 committed by Jakub Kicinski
parent 621f44af8c
commit 5da6ec6f06

View File

@ -701,11 +701,7 @@ static void ionic_rx_clean(struct ionic_queue *q,
__le64 *cq_desc_hwstamp;
u64 hwstamp;
cq_desc_hwstamp =
(void *)comp +
qcq->cq.desc_size -
sizeof(struct ionic_rxq_comp) -
IONIC_HWSTAMP_CQ_NEGOFFSET;
cq_desc_hwstamp = (void *)comp - IONIC_HWSTAMP_CQ_NEGOFFSET;
hwstamp = le64_to_cpu(*cq_desc_hwstamp);
@ -729,7 +725,12 @@ static bool __ionic_rx_service(struct ionic_cq *cq, struct bpf_prog *xdp_prog)
struct ionic_queue *q = cq->bound_q;
struct ionic_rxq_comp *comp;
comp = &((struct ionic_rxq_comp *)cq->base)[cq->tail_idx];
if (likely(cq->desc_size == sizeof(*comp)))
comp = &((struct ionic_rxq_comp *)cq->base)[cq->tail_idx];
else
comp = cq->base +
cq->desc_size * cq->tail_idx +
cq->desc_size - sizeof(*comp);
if (!color_match(comp->pkt_type_color, cq->done_color))
return false;
@ -1182,7 +1183,6 @@ static void ionic_tx_clean(struct ionic_queue *q,
bool in_napi)
{
struct ionic_tx_stats *stats = q_to_tx_stats(q);
struct ionic_qcq *qcq = q_to_qcq(q);
struct sk_buff *skb;
if (desc_info->xdpf) {
@ -1207,11 +1207,7 @@ static void ionic_tx_clean(struct ionic_queue *q,
__le64 *cq_desc_hwstamp;
u64 hwstamp;
cq_desc_hwstamp =
(void *)comp +
qcq->cq.desc_size -
sizeof(struct ionic_txq_comp) -
IONIC_HWSTAMP_CQ_NEGOFFSET;
cq_desc_hwstamp = (void *)comp - IONIC_HWSTAMP_CQ_NEGOFFSET;
hwstamp = le64_to_cpu(*cq_desc_hwstamp);
@ -1246,7 +1242,12 @@ static bool ionic_tx_service(struct ionic_cq *cq,
unsigned int pkts = 0;
u16 index;
comp = &((struct ionic_txq_comp *)cq->base)[cq->tail_idx];
if (likely(cq->desc_size == sizeof(*comp)))
comp = &((struct ionic_txq_comp *)cq->base)[cq->tail_idx];
else
comp = cq->base +
cq->desc_size * cq->tail_idx +
cq->desc_size - sizeof(*comp);
if (!color_match(comp->color, cq->done_color))
return false;