From: David Laight <david.laight.linux@gmail.com>
To: Guo Ren <guoren@kernel.org>
Cc: Robin Murphy <robin.murphy@arm.com>,
Zhanpeng Zhang <zhangzhanpeng.jasper@bytedance.com>,
Tomasz Jeznach <tomasz.jeznach@linux.dev>,
Joerg Roedel <joro@8bytes.org>, Will Deacon <will@kernel.org>,
Paul Walmsley <pjw@kernel.org>,
Palmer Dabbelt <palmer@dabbelt.com>,
Albert Ou <aou@eecs.berkeley.edu>,
Alexandre Ghiti <alex@ghiti.fr>,
Vivian Wang <wangruikang@iscas.ac.cn>,
Zong Li <zong.li@sifive.com>,
cuiyunhui@bytedance.com, yuanzhu@bytedance.com,
iommu@lists.linux.dev, linux-riscv@lists.infradead.org,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH v3] iommu/riscv: Use 32-bit MMIO accesses for 64-bit registers
Date: Tue, 14 Jul 2026 22:02:17 +0100 [thread overview]
Message-ID: <20260714220217.65055d98@pumpkin> (raw)
In-Reply-To: <CAJF2gTS2Rw0MYaKMzd0t3ZJ-4ni47wUwLrgkm3pjaxKu7Y1R+A@mail.gmail.com>
On Wed, 15 Jul 2026 00:53:06 +0800
Guo Ren <guoren@kernel.org> wrote:
> On Tue, Jul 14, 2026 at 10:53 PM David Laight
> <david.laight.linux@gmail.com> wrote:
> >
> > On Tue, 14 Jul 2026 21:24:19 +0800
> > Guo Ren <guoren@kernel.org> wrote:
> >
> > > On Tue, Jul 14, 2026 at 8:27 PM Robin Murphy <robin.murphy@arm.com> wrote:
> > > >
> > > > On 13/07/2026 1:29 pm, Zhanpeng Zhang wrote:
> > > > > The RISC-V IOMMU specification [1] permits 64-bit registers to be accessed
> > > > > using two 32-bit transactions, high half first, and leaves the single-copy
> > > > > atomicity of 8-byte IOMMU register accesses unspecified.
> > > > >
> > > > > Use the generic hi_lo_readq_relaxed() and hi_lo_writeq_relaxed() helpers
> > > > > for ordinary 64-bit IOMMU registers. For DDTP, poll BUSY in the low half,
> > > > > then read the high half and compose the register value from the polled low
> > > > > half. HPM counter reads require a rollover-aware sequence and remain
> > > > > outside these accessors.
> > > > >
> > > > > This follows the 32-bit access direction proposed by Guo Ren [2] and uses
> > > > > the generic non-atomic MMIO helpers suggested by David Laight.
> > > > >
> > > > > [1] https://docs.riscv.org/reference/iommu/
> > > > > [2] https://lore.kernel.org/r/20250903144217.837448-1-guoren@kernel.org
> > > > >
> > > > > Suggested-by: Guo Ren <guoren@kernel.org>
> > > > > Suggested-by: David Laight <david.laight.linux@gmail.com>
> > > > > Signed-off-by: Zhanpeng Zhang <zhangzhanpeng.jasper@bytedance.com>
> > > > > ---
> > > > > Changes in v3:
> > > > > - Use the DDTP access sequence from [1]: retain the low half returned by
> > > > > BUSY polling, read only the high half, and compose the DDTP value from
> > > > > those two 32-bit reads.
> > > > >
> > > > > Changes in v2:
> > > > > - Rework the patch based on Guo Ren's earlier proposal [1].
> > > > > - Drop the build-time option and use 32-bit accesses unconditionally.
> > > > > - Drop the global lock and use the generic high-low MMIO helpers, as
> > > > > suggested by David Laight.
> > > > > - Poll DDTP.BUSY through its low half.
> > > > >
> > > > > Link to v1: [2]
> > > > > Specification discussion: [3]
> > > > >
> > > > > [1]: https://lore.kernel.org/r/20250903144217.837448-1-guoren@kernel.org
> > > > > [2]: https://lore.kernel.org/r/20260615064855.90316-1-zhangzhanpeng.jasper@bytedance.com
> > > > > [3]: https://github.com/riscv-non-isa/riscv-iommu/issues/765
> > > > >
> > > > > drivers/iommu/riscv/iommu.c | 9 ++++++---
> > > > > drivers/iommu/riscv/iommu.h | 9 +++------
> > > > > 2 files changed, 9 insertions(+), 9 deletions(-)
> > > > >
> > > > > diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
> > > > > index cec3ddd7ab1..d647b71ebec 100644
> > > > > --- a/drivers/iommu/riscv/iommu.c
> > > > > +++ b/drivers/iommu/riscv/iommu.c
> > > > > @@ -670,9 +670,12 @@ void riscv_iommu_disable(struct riscv_iommu_device *iommu)
> > > > >
> > > > > #define riscv_iommu_read_ddtp(iommu) ({ \
> > > > > u64 ddtp; \
> > > > > - riscv_iommu_readq_timeout((iommu), RISCV_IOMMU_REG_DDTP, ddtp, \
> > > > > - !(ddtp & RISCV_IOMMU_DDTP_BUSY), 10, \
> > > > > + u32 ddtp_lo, ddtp_hi; \
> > > > > + riscv_iommu_readl_timeout((iommu), RISCV_IOMMU_REG_DDTP, ddtp_lo, \
> > > > > + !(ddtp_lo & RISCV_IOMMU_DDTP_BUSY), 10, \
> > > > > RISCV_IOMMU_DDTP_TIMEOUT); \
> > > > > + ddtp_hi = riscv_iommu_readl((iommu), RISCV_IOMMU_REG_DDTP + 4); \
> > > >
> > > > It looks like whenever you read DDTP you're only really looking at the
> > > > BUSY/MODE fields anyway, so does this actually need to read the upper
> > > > bits of PPN at all? (The spec says they don't even need to be written on
> > > > RV32 either)
> > >
> > > The motivation is not RV32 compatibility. It addresses RV64 platforms
> > > where the IOMMU control plane can only be accessed via 32-bit MMIO.
> > >
> > > >
> > > > > + ddtp = ((u64)ddtp_hi << 32) | ddtp_lo; \
> > > > > ddtp; })
> > > > >
> > > > > static int riscv_iommu_iodir_alloc(struct riscv_iommu_device *iommu)
> > > > > @@ -1501,7 +1504,7 @@ static int riscv_iommu_init_check(struct riscv_iommu_device *iommu)
> > > > > * regular boot flow and disable translation when we boot into a kexec
> > > > > * kernel and the previous kernel left them enabled.
> > > > > */
> > > > > - ddtp = riscv_iommu_readq(iommu, RISCV_IOMMU_REG_DDTP);
> > > > > + ddtp = riscv_iommu_read_ddtp(iommu);
> > > > > if (ddtp & RISCV_IOMMU_DDTP_BUSY)
> > > > > return -EBUSY;
> > > > >
> > > > > diff --git a/drivers/iommu/riscv/iommu.h b/drivers/iommu/riscv/iommu.h
> > > > > index 46df79dd549..1b03790fbe1 100644
> > > > > --- a/drivers/iommu/riscv/iommu.h
> > > > > +++ b/drivers/iommu/riscv/iommu.h
> > > > > @@ -11,6 +11,7 @@
> > > > > #ifndef _RISCV_IOMMU_H_
> > > > > #define _RISCV_IOMMU_H_
> > > > >
> > > > > +#include <linux/io-64-nonatomic-hi-lo.h>
> > > > > #include <linux/iommu.h>
> > > > > #include <linux/types.h>
> > > > > #include <linux/iopoll.h>
> > > > > @@ -70,17 +71,13 @@ void riscv_iommu_disable(struct riscv_iommu_device *iommu);
> > > > > readl_relaxed((iommu)->reg + (addr))
> > > > >
> > > > > #define riscv_iommu_readq(iommu, addr) \
> > > > > - readq_relaxed((iommu)->reg + (addr))
> > > > > + hi_lo_readq_relaxed((iommu)->reg + (addr))
> > > >
> > > > This seems unnecessary (similarly for writeq() below) - once you've
> > > > included the header, then it automatically provides readq{_relaxed}()
> > > > for RV32 via the non-atomic implementation, and wherever atomicity
> > > > doesn't matter, then as written there seems to be no reason for RV64 to
> > > > stop using the regular arch readq().
> > > >
> > > > Not that it makes any difference to me either way, but I don't see any
> > > > real issue with the spec - if software *may* make a 64-bit access to any
> > > > 64-bit register unconditionally, then that can only imply that hardware
> > > > *must* be able to accommodate RV64 software choosing to do so, and
> > > > therefore must support *both* 32b and 64b accesses in general, except
> > > > perhaps on RV32-only systems if software could never make 64b accesses
> > > > in the first place. If 64b single-copy atomicity is not
> > > > required/specified then it should be valid to achieve that by just
> > > > sticking a downsizer in the upstream interconnect to split 64b accesses
> > > > into 32bx2 incremental bursts.
> > > >
> > > > If do actually you need this as an erratum workaround to support
> > > > specific hardware which has misinterpreted the spec then I think you
> > > > should be clear about that. Otherwise, adding speculative "workarounds"
> > > > which (slightly) penalise hardware that got it right, while inviting
> > > > future hardware to get it wrong, doesn't seem like the right way to go
> > > > at all...
> > >
> > > The only three 64-bit registers the driver ever touches are DDTP,
> > > CAPABILITIES, and MSI_CFG_TBL_ADDR. None of them is on any
> > > performance-critical or hot path. Even if native 64-bit MMIO accesses
> > > were used, there would be no observable performance benefit.
> > > Therefore, this change does not penalize any hardware.
> > >
> > > Regarding the specification, there remains substantial disagreement
> > > over whether 64-bit accesses are mandatory. The relevant sentence uses
> > > the word “may” (“may be accessed using either a 32-bit or a 64-bit
> > > access”). Per RFC 2119, “may” does not express a requirement. Because
> > > every existing implementation already provides working 32-bit MMIO
> > > access, we believe the safer and less controversial choice is to use
> > > the portable 32-bit path via the generic hi-lo helpers.
> > >
> >
> > There is also this clause:
> > The 8-byte IOMMU registers are defined in such a way that software can
> > perform two individual 4-byte accesses, or hardware can perform two
> > independent 4-byte transactions resulting from an 8-byte access,
> > to the high and low halves of the register, in that order, as long as
> > the register semantics, with regard to side-effects, are respected
> > between the two software accesses, or two hardware transactions,
> > respectively.
> >
> > I'm not sure what the relevance of the high-low order is.
> > It could mean, for example, that a read of the high word can latch the low
> > for the next read - so that you get an atomic 64bit read.
> > That might be ok if hardware splits the 64bit read, but if software does it
> > it isn't going to go well unless the driver locks all (and it might be all)
> > slave accesses.
> > In the worst case there might be a single latch for all odd word reads.
> > Writes could be worse!
> >
> > Hardware can be that broken.
> > I remember a PCI slave that terminated reads requesting 'cycle rerun'
> > and then assumed that the following reads would be repeats of the same
> > read, not reads of a different address by the other cpu.
> > It didn't do writes properly either, I've forgotten the exact details
> > but I think a second (third?) write overwrite some latches.
>
> This is precisely why the specification leaves the single-copy
> atomicity of an 8-byte IOMMU register access UNSPECIFIED. If a 64-bit
> MMIO register were implemented with atomic semantics, 32-bit accesses
> using lw/sw might require implicit mechanisms, such as latching half
> the register for subsequent accesses. Such mechanisms could lead to
> exactly the kind of interleaving problem you described.
Right, but it also says you must do high-low.
The only reason for that would be to allow hardware that requires
that ordering - which means the software better do both accesses
in that order.
The second half of the sentence seems to let the hardware update
half the register from a 32bit access (as you might expect).
The whole thing is misleading/confusing.
And, reading the full page, the system that doesn't support 64bit
accesses is probably non-conformant as well.
David
>
> This is one reason hardware may favor straightforward, latch-free
> 32-bit MMIO transactions. The example you mentioned further
> illustrates the robustness of treating each 32-bit MMIO access as an
> independent transaction without relying on hidden latch semantics.
>
> Using 32-bit MMIO accesses for DDTP, CAPABILITIES, and
> MSI_CFG_TBL_ADDR in this driver introduces no meaningful performance
> overhead and provides broader compatibility without disadvantaging any
> RISC-V IOMMU implementation.
>
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
next prev parent reply other threads:[~2026-07-14 21:02 UTC|newest]
Thread overview: 37+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-15 6:48 [PATCH v1] iommu/riscv: Support 32-bit register accesses Zhanpeng Zhang
2026-06-15 8:21 ` Andreas Schwab
2026-06-15 9:51 ` [External] " Zhanpeng Zhang
2026-06-15 9:59 ` David Laight
2026-06-15 13:21 ` [External] " Zhanpeng Zhang
2026-06-15 12:38 ` Guo Ren
2026-06-15 13:23 ` [External] " Zhanpeng Zhang
2026-06-16 10:36 ` David Laight
2026-06-16 15:47 ` Guo Ren
2026-06-16 19:51 ` David Laight
2026-06-17 16:24 ` Guo Ren
2026-06-17 21:54 ` David Laight
2026-06-18 3:36 ` Guo Ren
2026-06-18 3:20 ` Vivian Wang
2026-06-18 3:45 ` Guo Ren
2026-06-18 7:33 ` Vivian Wang
2026-06-18 9:51 ` Guo Ren
2026-06-18 10:01 ` Vivian Wang
2026-06-18 13:36 ` David Laight
2026-06-18 16:40 ` Guo Ren
2026-06-23 9:20 ` Zong Li
2026-06-28 8:20 ` Guo Ren
2026-06-29 1:15 ` Zong Li
2026-06-26 9:18 ` Zhanpeng Zhang
2026-07-13 6:09 ` [PATCH v2] iommu/riscv: Use 32-bit MMIO accesses for 64-bit registers Zhanpeng Zhang
2026-07-13 7:00 ` Guo Ren
2026-07-13 8:24 ` Zhanpeng Zhang
2026-07-13 12:29 ` [PATCH v3] " Zhanpeng Zhang
2026-07-14 2:02 ` Guo Ren
2026-07-14 7:10 ` Tomasz Jeznach
2026-07-14 12:27 ` Robin Murphy
2026-07-14 13:24 ` Guo Ren
2026-07-14 14:53 ` David Laight
2026-07-14 16:53 ` Guo Ren
2026-07-14 21:02 ` David Laight [this message]
2026-07-15 2:37 ` Guo Ren
2026-07-14 13:55 ` Guo Ren
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=20260714220217.65055d98@pumpkin \
--to=david.laight.linux@gmail.com \
--cc=alex@ghiti.fr \
--cc=aou@eecs.berkeley.edu \
--cc=cuiyunhui@bytedance.com \
--cc=guoren@kernel.org \
--cc=iommu@lists.linux.dev \
--cc=joro@8bytes.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-riscv@lists.infradead.org \
--cc=palmer@dabbelt.com \
--cc=pjw@kernel.org \
--cc=robin.murphy@arm.com \
--cc=tomasz.jeznach@linux.dev \
--cc=wangruikang@iscas.ac.cn \
--cc=will@kernel.org \
--cc=yuanzhu@bytedance.com \
--cc=zhangzhanpeng.jasper@bytedance.com \
--cc=zong.li@sifive.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