From: Vimlesh Kumar <vimleshk@marvell.com>
To: <netdev@vger.kernel.org>, <linux-kernel@vger.kernel.org>
Cc: <sedara@marvell.com>, <srasheed@marvell.com>, <hgani@marvell.com>,
"Vimlesh Kumar" <vimleshk@marvell.com>,
Veerasenareddy Burru <vburru@marvell.com>,
Satananda Burla <sburla@marvell.com>,
Andrew Lunn <andrew+netdev@lunn.ch>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>
Subject: [PATCH net v2 4/4] octeon_ep_vf: avoid compiler and IQ/OQ reordering
Date: Fri, 27 Feb 2026 09:14:00 +0000 [thread overview]
Message-ID: <20260227091402.1773833-5-vimleshk@marvell.com> (raw)
In-Reply-To: <20260227091402.1773833-1-vimleshk@marvell.com>
Utilize READ_ONCE and WRITE_ONCE APIs for IO queue Tx/Rx
variable access to prevent compiler optimization and reordering.
Additionally, ensure IO queue OUT/IN_CNT registers are flushed
by performing a read-back after writing.
The compiler could reorder reads/writes to pkts_pending, last_pkt_count,
etc., causing stale values to be used when calculating packets to process
or register updates to send to hardware. The Octeon hardware requires a
read-back after writing to OUT_CNT/IN_CNT registers to ensure the write
has been flushed through any posted write buffers before the interrupt
resend bit is set. Without this, we have observed cases where the hardware
didn't properly update its internal state.
wmb/rmb only provides ordering guarantees but doesn't prevent the compiler
from performing optimizations like caching in registers, load tearing etc.
Fixes: 1cd3b407977c3 ("octeon_ep_vf: add Tx/Rx processing and interrupt support")
Signed-off-by: Sathesh Edara <sedara@marvell.com>
Signed-off-by: Shinas Rasheed <srasheed@marvell.com>
Signed-off-by: Vimlesh Kumar <vimleshk@marvell.com>
---
V1: https://lore.kernel.org/all/20260212121634.360252-3-vimleshk@marvell.com/
.../marvell/octeon_ep_vf/octep_vf_main.c | 21 ++++++++------
.../marvell/octeon_ep_vf/octep_vf_rx.c | 28 +++++++++++++------
2 files changed, 33 insertions(+), 16 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c
index e113c846f9d1..27a5fc38bccb 100644
--- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c
+++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c
@@ -294,17 +294,22 @@ static void octep_vf_clean_irqs(struct octep_vf_device *oct)
static void octep_vf_update_pkt(struct octep_vf_iq *iq, struct octep_vf_oq *oq)
{
- u32 pkts_pend = oq->pkts_pending;
+ 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 (iq->pkts_processed) {
- writel(iq->pkts_processed, iq->inst_cnt_reg);
- iq->pkt_in_done -= iq->pkts_processed;
- iq->pkts_processed = 0;
+ 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 (oq->last_pkt_count - pkts_pend) {
- writel(oq->last_pkt_count - pkts_pend, oq->pkts_sent_reg);
- oq->last_pkt_count = pkts_pend;
+ 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 */
diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c
index d70c8be3cfc4..31380962c212 100644
--- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c
+++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c
@@ -319,9 +319,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
@@ -333,8 +340,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;
}
@@ -363,7 +371,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++) {
@@ -457,7 +465,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;
@@ -480,22 +488,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;
}
--
2.47.3
next prev parent reply other threads:[~2026-02-27 9:14 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-27 9:13 [PATCH net v2 0/4] avoid compiler and IQ/OQ reordering Vimlesh Kumar
2026-02-27 9:13 ` [PATCH net v2 1/4] octeon_ep: Relocate counter updates before NAPI Vimlesh Kumar
2026-02-27 9:13 ` [PATCH net v2 2/4] octeon_ep: avoid compiler and IQ/OQ reordering Vimlesh Kumar
2026-02-27 9:13 ` [PATCH net v2 3/4] octeon_ep_vf: Relocate counter updates before NAPI Vimlesh Kumar
2026-02-27 9:14 ` Vimlesh Kumar [this message]
2026-03-03 10:40 ` [PATCH net v2 0/4] avoid compiler and IQ/OQ reordering patchwork-bot+netdevbpf
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260227091402.1773833-5-vimleshk@marvell.com \
--to=vimleshk@marvell.com \
--cc=andrew+netdev@lunn.ch \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=hgani@marvell.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=sburla@marvell.com \
--cc=sedara@marvell.com \
--cc=srasheed@marvell.com \
--cc=vburru@marvell.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox