Merge branch 'avoid-compiler-and-iq-oq-reordering'

Vimlesh Kumar says:

====================
avoid compiler and IQ/OQ reordering

Utilize READ_ONCE and WRITE_ONCE APIs to prevent compiler
optimization and reordering. Ensure IO queue OUT/IN_CNT
registers are flushed. Relocate IQ/OQ IN/OUT_CNTS updates
to occur before NAPI completion, and replace napi_complete
with napi_complete_done.
====================

Link: https://patch.msgid.link/20260227091402.1773833-1-vimleshk@marvell.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Paolo Abeni 2026-03-03 11:34:22 +01:00
commit 699f3b2e51
4 changed files with 105 additions and 48 deletions

View file

@ -553,6 +553,36 @@ static void octep_clean_irqs(struct octep_device *oct)
octep_free_ioq_vectors(oct);
}
/**
* octep_update_pkt() - Update IQ/OQ IN/OUT_CNT registers.
*
* @iq: Octeon Tx queue data structure.
* @oq: Octeon Rx queue data structure.
*/
static void octep_update_pkt(struct octep_iq *iq, struct octep_oq *oq)
{
u32 pkts_pend = READ_ONCE(oq->pkts_pending);
u32 last_pkt_count = READ_ONCE(oq->last_pkt_count);
u32 pkts_processed = READ_ONCE(iq->pkts_processed);
u32 pkt_in_done = READ_ONCE(iq->pkt_in_done);
netdev_dbg(iq->netdev, "enabling intr for Q-%u\n", iq->q_no);
if (pkts_processed) {
writel(pkts_processed, iq->inst_cnt_reg);
readl(iq->inst_cnt_reg);
WRITE_ONCE(iq->pkt_in_done, (pkt_in_done - pkts_processed));
WRITE_ONCE(iq->pkts_processed, 0);
}
if (last_pkt_count - pkts_pend) {
writel(last_pkt_count - pkts_pend, oq->pkts_sent_reg);
readl(oq->pkts_sent_reg);
WRITE_ONCE(oq->last_pkt_count, pkts_pend);
}
/* Flush the previous wrties before writing to RESEND bit */
smp_wmb();
}
/**
* octep_enable_ioq_irq() - Enable MSI-x interrupt of a Tx/Rx queue.
*
@ -561,21 +591,6 @@ static void octep_clean_irqs(struct octep_device *oct)
*/
static void octep_enable_ioq_irq(struct octep_iq *iq, struct octep_oq *oq)
{
u32 pkts_pend = oq->pkts_pending;
netdev_dbg(iq->netdev, "enabling intr for Q-%u\n", iq->q_no);
if (iq->pkts_processed) {
writel(iq->pkts_processed, iq->inst_cnt_reg);
iq->pkt_in_done -= iq->pkts_processed;
iq->pkts_processed = 0;
}
if (oq->last_pkt_count - pkts_pend) {
writel(oq->last_pkt_count - pkts_pend, oq->pkts_sent_reg);
oq->last_pkt_count = pkts_pend;
}
/* Flush the previous wrties before writing to RESEND bit */
wmb();
writeq(1UL << OCTEP_OQ_INTR_RESEND_BIT, oq->pkts_sent_reg);
writeq(1UL << OCTEP_IQ_INTR_RESEND_BIT, iq->inst_cnt_reg);
}
@ -601,7 +616,8 @@ static int octep_napi_poll(struct napi_struct *napi, int budget)
if (tx_pending || rx_done >= budget)
return budget;
napi_complete(napi);
octep_update_pkt(ioq_vector->iq, ioq_vector->oq);
napi_complete_done(napi, rx_done);
octep_enable_ioq_irq(ioq_vector->iq, ioq_vector->oq);
return rx_done;
}

View file

@ -324,10 +324,16 @@ static int octep_oq_check_hw_for_pkts(struct octep_device *oct,
struct octep_oq *oq)
{
u32 pkt_count, new_pkts;
u32 last_pkt_count, pkts_pending;
pkt_count = readl(oq->pkts_sent_reg);
new_pkts = pkt_count - oq->last_pkt_count;
last_pkt_count = READ_ONCE(oq->last_pkt_count);
new_pkts = pkt_count - last_pkt_count;
if (pkt_count < last_pkt_count) {
dev_err(oq->dev, "OQ-%u pkt_count(%u) < oq->last_pkt_count(%u)\n",
oq->q_no, pkt_count, last_pkt_count);
}
/* Clear the hardware packets counter register if the rx queue is
* being processed continuously with-in a single interrupt and
* reached half its max value.
@ -338,8 +344,9 @@ static int octep_oq_check_hw_for_pkts(struct octep_device *oct,
pkt_count = readl(oq->pkts_sent_reg);
new_pkts += pkt_count;
}
oq->last_pkt_count = pkt_count;
oq->pkts_pending += new_pkts;
WRITE_ONCE(oq->last_pkt_count, pkt_count);
pkts_pending = READ_ONCE(oq->pkts_pending);
WRITE_ONCE(oq->pkts_pending, (pkts_pending + new_pkts));
return new_pkts;
}
@ -414,7 +421,7 @@ static int __octep_oq_process_rx(struct octep_device *oct,
u16 rx_ol_flags;
u32 read_idx;
read_idx = oq->host_read_idx;
read_idx = READ_ONCE(oq->host_read_idx);
rx_bytes = 0;
desc_used = 0;
for (pkt = 0; pkt < pkts_to_process; pkt++) {
@ -499,7 +506,7 @@ static int __octep_oq_process_rx(struct octep_device *oct,
napi_gro_receive(oq->napi, skb);
}
oq->host_read_idx = read_idx;
WRITE_ONCE(oq->host_read_idx, read_idx);
oq->refill_count += desc_used;
oq->stats->packets += pkt;
oq->stats->bytes += rx_bytes;
@ -522,22 +529,26 @@ int octep_oq_process_rx(struct octep_oq *oq, int budget)
{
u32 pkts_available, pkts_processed, total_pkts_processed;
struct octep_device *oct = oq->octep_dev;
u32 pkts_pending;
pkts_available = 0;
pkts_processed = 0;
total_pkts_processed = 0;
while (total_pkts_processed < budget) {
/* update pending count only when current one exhausted */
if (oq->pkts_pending == 0)
pkts_pending = READ_ONCE(oq->pkts_pending);
if (pkts_pending == 0)
octep_oq_check_hw_for_pkts(oct, oq);
pkts_pending = READ_ONCE(oq->pkts_pending);
pkts_available = min(budget - total_pkts_processed,
oq->pkts_pending);
pkts_pending);
if (!pkts_available)
break;
pkts_processed = __octep_oq_process_rx(oct, oq,
pkts_available);
oq->pkts_pending -= pkts_processed;
pkts_pending = READ_ONCE(oq->pkts_pending);
WRITE_ONCE(oq->pkts_pending, (pkts_pending - pkts_processed));
total_pkts_processed += pkts_processed;
}

View file

@ -285,29 +285,46 @@ static void octep_vf_clean_irqs(struct octep_vf_device *oct)
octep_vf_free_ioq_vectors(oct);
}
/**
* octep_vf_update_pkt() - Update IQ/OQ IN/OUT_CNT registers.
*
* @iq: Octeon Tx queue data structure.
* @oq: Octeon Rx queue data structure.
*/
static void octep_vf_update_pkt(struct octep_vf_iq *iq, struct octep_vf_oq *oq)
{
u32 pkts_pend = READ_ONCE(oq->pkts_pending);
u32 last_pkt_count = READ_ONCE(oq->last_pkt_count);
u32 pkts_processed = READ_ONCE(iq->pkts_processed);
u32 pkt_in_done = READ_ONCE(iq->pkt_in_done);
netdev_dbg(iq->netdev, "enabling intr for Q-%u\n", iq->q_no);
if (pkts_processed) {
writel(pkts_processed, iq->inst_cnt_reg);
readl(iq->inst_cnt_reg);
WRITE_ONCE(iq->pkt_in_done, (pkt_in_done - pkts_processed));
WRITE_ONCE(iq->pkts_processed, 0);
}
if (last_pkt_count - pkts_pend) {
writel(last_pkt_count - pkts_pend, oq->pkts_sent_reg);
readl(oq->pkts_sent_reg);
WRITE_ONCE(oq->last_pkt_count, pkts_pend);
}
/* Flush the previous wrties before writing to RESEND bit */
smp_wmb();
}
/**
* octep_vf_enable_ioq_irq() - Enable MSI-x interrupt of a Tx/Rx queue.
*
* @iq: Octeon Tx queue data structure.
* @oq: Octeon Rx queue data structure.
*/
static void octep_vf_enable_ioq_irq(struct octep_vf_iq *iq, struct octep_vf_oq *oq)
static void octep_vf_enable_ioq_irq(struct octep_vf_iq *iq,
struct octep_vf_oq *oq)
{
u32 pkts_pend = oq->pkts_pending;
netdev_dbg(iq->netdev, "enabling intr for Q-%u\n", iq->q_no);
if (iq->pkts_processed) {
writel(iq->pkts_processed, iq->inst_cnt_reg);
iq->pkt_in_done -= iq->pkts_processed;
iq->pkts_processed = 0;
}
if (oq->last_pkt_count - pkts_pend) {
writel(oq->last_pkt_count - pkts_pend, oq->pkts_sent_reg);
oq->last_pkt_count = pkts_pend;
}
/* Flush the previous wrties before writing to RESEND bit */
smp_wmb();
writeq(1UL << OCTEP_VF_OQ_INTR_RESEND_BIT, oq->pkts_sent_reg);
writeq(1UL << OCTEP_VF_IQ_INTR_RESEND_BIT, iq->inst_cnt_reg);
}
@ -333,6 +350,7 @@ static int octep_vf_napi_poll(struct napi_struct *napi, int budget)
if (tx_pending || rx_done >= budget)
return budget;
octep_vf_update_pkt(ioq_vector->iq, ioq_vector->oq);
if (likely(napi_complete_done(napi, rx_done)))
octep_vf_enable_ioq_irq(ioq_vector->iq, ioq_vector->oq);

View file

@ -325,9 +325,16 @@ static int octep_vf_oq_check_hw_for_pkts(struct octep_vf_device *oct,
struct octep_vf_oq *oq)
{
u32 pkt_count, new_pkts;
u32 last_pkt_count, pkts_pending;
pkt_count = readl(oq->pkts_sent_reg);
new_pkts = pkt_count - oq->last_pkt_count;
last_pkt_count = READ_ONCE(oq->last_pkt_count);
new_pkts = pkt_count - last_pkt_count;
if (pkt_count < last_pkt_count) {
dev_err(oq->dev, "OQ-%u pkt_count(%u) < oq->last_pkt_count(%u)\n",
oq->q_no, pkt_count, last_pkt_count);
}
/* Clear the hardware packets counter register if the rx queue is
* being processed continuously with-in a single interrupt and
@ -339,8 +346,9 @@ static int octep_vf_oq_check_hw_for_pkts(struct octep_vf_device *oct,
pkt_count = readl(oq->pkts_sent_reg);
new_pkts += pkt_count;
}
oq->last_pkt_count = pkt_count;
oq->pkts_pending += new_pkts;
WRITE_ONCE(oq->last_pkt_count, pkt_count);
pkts_pending = READ_ONCE(oq->pkts_pending);
WRITE_ONCE(oq->pkts_pending, (pkts_pending + new_pkts));
return new_pkts;
}
@ -369,7 +377,7 @@ static int __octep_vf_oq_process_rx(struct octep_vf_device *oct,
struct sk_buff *skb;
u32 read_idx;
read_idx = oq->host_read_idx;
read_idx = READ_ONCE(oq->host_read_idx);
rx_bytes = 0;
desc_used = 0;
for (pkt = 0; pkt < pkts_to_process; pkt++) {
@ -463,7 +471,7 @@ static int __octep_vf_oq_process_rx(struct octep_vf_device *oct,
napi_gro_receive(oq->napi, skb);
}
oq->host_read_idx = read_idx;
WRITE_ONCE(oq->host_read_idx, read_idx);
oq->refill_count += desc_used;
oq->stats->packets += pkt;
oq->stats->bytes += rx_bytes;
@ -486,22 +494,26 @@ int octep_vf_oq_process_rx(struct octep_vf_oq *oq, int budget)
{
u32 pkts_available, pkts_processed, total_pkts_processed;
struct octep_vf_device *oct = oq->octep_vf_dev;
u32 pkts_pending;
pkts_available = 0;
pkts_processed = 0;
total_pkts_processed = 0;
while (total_pkts_processed < budget) {
/* update pending count only when current one exhausted */
if (oq->pkts_pending == 0)
pkts_pending = READ_ONCE(oq->pkts_pending);
if (pkts_pending == 0)
octep_vf_oq_check_hw_for_pkts(oct, oq);
pkts_pending = READ_ONCE(oq->pkts_pending);
pkts_available = min(budget - total_pkts_processed,
oq->pkts_pending);
pkts_pending);
if (!pkts_available)
break;
pkts_processed = __octep_vf_oq_process_rx(oct, oq,
pkts_available);
oq->pkts_pending -= pkts_processed;
pkts_pending = READ_ONCE(oq->pkts_pending);
WRITE_ONCE(oq->pkts_pending, (pkts_pending - pkts_processed));
total_pkts_processed += pkts_processed;
}