* [PATCH v1] iommu/riscv: Support 32-bit register accesses
@ 2026-06-15 6:48 Zhanpeng Zhang
2026-06-15 8:21 ` Andreas Schwab
` (4 more replies)
0 siblings, 5 replies; 30+ messages in thread
From: Zhanpeng Zhang @ 2026-06-15 6:48 UTC (permalink / raw)
To: Tomasz Jeznach, Joerg Roedel, Will Deacon
Cc: Robin Murphy, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, iommu, linux-riscv, linux-kernel, Xu Lu,
cuiyunhui, yuanzhu, Zhanpeng Zhang
Some RISC-V IOMMU implementations cannot perform 64-bit MMIO accesses
to the IOMMU register file. The RISC-V IOMMU architecture allows 64-bit
registers to be accessed using 32-bit accesses, provided the accesses are
properly aligned and do not span multiple registers.
Add a config option for such implementations and access 64-bit IOMMU
registers as paired 32-bit MMIO operations when it is enabled. Serialize
the paired accesses so the high and low halves cannot interleave with
another CPU. Full 64-bit register programming writes the high half before
the low half.
This option describes the register access width. It is not an RV32 kernel
mode and does not describe a 32-bit IOMMU architecture.
Co-developed-by: Xu Lu <luxu.kernel@bytedance.com>
Signed-off-by: Xu Lu <luxu.kernel@bytedance.com>
Signed-off-by: Zhanpeng Zhang <zhangzhanpeng.jasper@bytedance.com>
---
This is needed for platforms whose RISC-V IOMMU register window does not
support naturally aligned 64-bit MMIO accesses.
drivers/iommu/riscv/Kconfig | 11 ++++++++
drivers/iommu/riscv/iommu.c | 4 +++
drivers/iommu/riscv/iommu.h | 55 +++++++++++++++++++++++++++++++++----
3 files changed, 64 insertions(+), 6 deletions(-)
diff --git a/drivers/iommu/riscv/Kconfig b/drivers/iommu/riscv/Kconfig
index b86e5ab94183..54d624b9b2ef 100644
--- a/drivers/iommu/riscv/Kconfig
+++ b/drivers/iommu/riscv/Kconfig
@@ -22,3 +22,14 @@ config RISCV_IOMMU_PCI
def_bool y if RISCV_IOMMU && PCI_MSI
help
Support for the PCIe implementation of RISC-V IOMMU architecture.
+
+config RISCV_IOMMU_32BIT_ACCESS
+ bool "Use 32-bit accesses for RISC-V IOMMU registers"
+ depends on RISCV_IOMMU
+ help
+ Say Y when the RISC-V IOMMU MMIO window cannot be accessed
+ using naturally aligned 64-bit loads and stores.
+
+ When enabled, 64-bit IOMMU registers are accessed as paired
+ 32-bit MMIO operations. This option does not describe an RV32
+ kernel or a 32-bit IOMMU architecture.
diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index a31f50bbad35..7fa1721b5728 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -53,6 +53,10 @@ struct riscv_iommu_devres {
void *addr;
};
+#ifdef CONFIG_RISCV_IOMMU_32BIT_ACCESS
+DEFINE_RAW_SPINLOCK(riscv_iommu_32bit_access_lock);
+#endif
+
static void riscv_iommu_devres_pages_release(struct device *dev, void *res)
{
struct riscv_iommu_devres *devres = res;
diff --git a/drivers/iommu/riscv/iommu.h b/drivers/iommu/riscv/iommu.h
index 46df79dd5495..ba78ef1858c5 100644
--- a/drivers/iommu/riscv/iommu.h
+++ b/drivers/iommu/riscv/iommu.h
@@ -14,6 +14,9 @@
#include <linux/iommu.h>
#include <linux/types.h>
#include <linux/iopoll.h>
+#ifdef CONFIG_RISCV_IOMMU_32BIT_ACCESS
+#include <linux/spinlock.h>
+#endif
#include "iommu-bits.h"
@@ -69,21 +72,61 @@ void riscv_iommu_disable(struct riscv_iommu_device *iommu);
#define riscv_iommu_readl(iommu, addr) \
readl_relaxed((iommu)->reg + (addr))
-#define riscv_iommu_readq(iommu, addr) \
- readq_relaxed((iommu)->reg + (addr))
-
#define riscv_iommu_writel(iommu, addr, val) \
writel_relaxed((val), (iommu)->reg + (addr))
+#define riscv_iommu_readl_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
+ readx_poll_timeout(readl_relaxed, (iommu)->reg + (addr), val, cond, \
+ delay_us, timeout_us)
+
+#ifndef CONFIG_RISCV_IOMMU_32BIT_ACCESS
+#define riscv_iommu_readq(iommu, addr) \
+ readq_relaxed((iommu)->reg + (addr))
+
#define riscv_iommu_writeq(iommu, addr, val) \
writeq_relaxed((val), (iommu)->reg + (addr))
#define riscv_iommu_readq_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
readx_poll_timeout(readq_relaxed, (iommu)->reg + (addr), val, cond, \
delay_us, timeout_us)
+#else /* CONFIG_RISCV_IOMMU_32BIT_ACCESS */
-#define riscv_iommu_readl_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
- readx_poll_timeout(readl_relaxed, (iommu)->reg + (addr), val, cond, \
- delay_us, timeout_us)
+extern raw_spinlock_t riscv_iommu_32bit_access_lock;
+
+static inline u64 __riscv_iommu_readq_relaxed(void __iomem *addr)
+{
+ u32 lo, hi;
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&riscv_iommu_32bit_access_lock, flags);
+ do {
+ hi = readl_relaxed(addr + sizeof(u32));
+ lo = readl_relaxed(addr);
+ } while (hi != readl_relaxed(addr + sizeof(u32)));
+ raw_spin_unlock_irqrestore(&riscv_iommu_32bit_access_lock, flags);
+
+ return ((u64)hi << 32) | (u64)lo;
+}
+
+static inline void __riscv_iommu_writeq_relaxed(u64 value, void __iomem *addr)
+{
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&riscv_iommu_32bit_access_lock, flags);
+ writel_relaxed((u32)(value >> 32), addr + sizeof(u32));
+ writel_relaxed((u32)value, addr);
+ raw_spin_unlock_irqrestore(&riscv_iommu_32bit_access_lock, flags);
+}
+
+#define riscv_iommu_readq(iommu, addr) \
+ __riscv_iommu_readq_relaxed((iommu)->reg + (addr))
+
+#define riscv_iommu_writeq(iommu, addr, val) \
+ __riscv_iommu_writeq_relaxed((val), (iommu)->reg + (addr))
+
+#define riscv_iommu_readq_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
+ readx_poll_timeout(__riscv_iommu_readq_relaxed, (iommu)->reg + (addr), \
+ val, cond, delay_us, timeout_us)
+#endif /* CONFIG_RISCV_IOMMU_32BIT_ACCESS */
#endif
--
2.50.1 (Apple Git-155)
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 30+ messages in thread
* Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
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
` (3 subsequent siblings)
4 siblings, 1 reply; 30+ messages in thread
From: Andreas Schwab @ 2026-06-15 8:21 UTC (permalink / raw)
To: Zhanpeng Zhang
Cc: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, iommu,
linux-riscv, linux-kernel, Xu Lu, cuiyunhui, yuanzhu
On Jun 15 2026, Zhanpeng Zhang wrote:
> +config RISCV_IOMMU_32BIT_ACCESS
> + bool "Use 32-bit accesses for RISC-V IOMMU registers"
> + depends on RISCV_IOMMU
> + help
> + Say Y when the RISC-V IOMMU MMIO window cannot be accessed
> + using naturally aligned 64-bit loads and stores.
> +
> + When enabled, 64-bit IOMMU registers are accessed as paired
> + 32-bit MMIO operations. This option does not describe an RV32
> + kernel or a 32-bit IOMMU architecture.
What is the expected setting in a generic kernel?
--
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE 1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [External] Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
2026-06-15 8:21 ` Andreas Schwab
@ 2026-06-15 9:51 ` Zhanpeng Zhang
0 siblings, 0 replies; 30+ messages in thread
From: Zhanpeng Zhang @ 2026-06-15 9:51 UTC (permalink / raw)
To: Andreas Schwab
Cc: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, iommu,
linux-riscv, linux-kernel, Xu Lu, cuiyunhui, yuanzhu
Hi Andreas,
For a generic kernel, the expected setting is to leave
RISCV_IOMMU_32BIT_ACCESS disabled.
If supporting such platforms from a single generic kernel is preferred, I can
look into replacing this build-time option with a runtime indication.
Regards,
Zhanpeng
> From: "Andreas Schwab"<schwab@suse.de>
> Date: Mon, Jun 15, 2026, 16:22
> Subject: [External] Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
> To: "Zhanpeng Zhang"<zhangzhanpeng.jasper@bytedance.com>
> Cc: "Tomasz Jeznach"<tjeznach@rivosinc.com>, "Joerg Roedel"<joro@8bytes.org>, "Will Deacon"<will@kernel.org>, "Robin Murphy"<robin.murphy@arm.com>, "Paul Walmsley"<pjw@kernel.org>, "Palmer Dabbelt"<palmer@dabbelt.com>, "Albert Ou"<aou@eecs.berkeley.edu>, "Alexandre Ghiti"<alex@ghiti.fr>, <iommu@lists.linux.dev>, <linux-riscv@lists.infradead.org>, <linux-kernel@vger.kernel.org>, "Xu Lu"<luxu.kernel@bytedance.com>, <cuiyunhui@bytedance.com>, <yuanzhu@bytedance.com>
> On Jun 15 2026, Zhanpeng Zhang wrote:
>
> > +config RISCV_IOMMU_32BIT_ACCESS
> > + bool "Use 32-bit accesses for RISC-V IOMMU registers"
> > + depends on RISCV_IOMMU
> > + help
> > + Say Y when the RISC-V IOMMU MMIO window cannot be accessed
> > + using naturally aligned 64-bit loads and stores.
> > +
> > + When enabled, 64-bit IOMMU registers are accessed as paired
> > + 32-bit MMIO operations. This option does not describe an RV32
> > + kernel or a 32-bit IOMMU architecture.
>
> What is the expected setting in a generic kernel?
>
> --
> Andreas Schwab, SUSE Labs, schwab@suse.de
> GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE 1748 E4D4 88E3 0EEA B9D7
> "And now for something completely different."
>
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
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:59 ` David Laight
2026-06-15 13:21 ` [External] " Zhanpeng Zhang
2026-06-15 12:38 ` Guo Ren
` (2 subsequent siblings)
4 siblings, 1 reply; 30+ messages in thread
From: David Laight @ 2026-06-15 9:59 UTC (permalink / raw)
To: Zhanpeng Zhang
Cc: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, iommu,
linux-riscv, linux-kernel, Xu Lu, cuiyunhui, yuanzhu
On Mon, 15 Jun 2026 14:48:55 +0800
Zhanpeng Zhang <zhangzhanpeng.jasper@bytedance.com> wrote:
> Some RISC-V IOMMU implementations cannot perform 64-bit MMIO accesses
> to the IOMMU register file. The RISC-V IOMMU architecture allows 64-bit
> registers to be accessed using 32-bit accesses, provided the accesses are
> properly aligned and do not span multiple registers.
>
> Add a config option for such implementations and access 64-bit IOMMU
> registers as paired 32-bit MMIO operations when it is enabled. Serialize
> the paired accesses so the high and low halves cannot interleave with
> another CPU. Full 64-bit register programming writes the high half before
> the low half.
>
> This option describes the register access width. It is not an RV32 kernel
> mode and does not describe a 32-bit IOMMU architecture.
>
> Co-developed-by: Xu Lu <luxu.kernel@bytedance.com>
> Signed-off-by: Xu Lu <luxu.kernel@bytedance.com>
> Signed-off-by: Zhanpeng Zhang <zhangzhanpeng.jasper@bytedance.com>
> ---
> This is needed for platforms whose RISC-V IOMMU register window does not
> support naturally aligned 64-bit MMIO accesses.
>
> drivers/iommu/riscv/Kconfig | 11 ++++++++
> drivers/iommu/riscv/iommu.c | 4 +++
> drivers/iommu/riscv/iommu.h | 55 +++++++++++++++++++++++++++++++++----
> 3 files changed, 64 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/iommu/riscv/Kconfig b/drivers/iommu/riscv/Kconfig
> index b86e5ab94183..54d624b9b2ef 100644
> --- a/drivers/iommu/riscv/Kconfig
> +++ b/drivers/iommu/riscv/Kconfig
> @@ -22,3 +22,14 @@ config RISCV_IOMMU_PCI
> def_bool y if RISCV_IOMMU && PCI_MSI
> help
> Support for the PCIe implementation of RISC-V IOMMU architecture.
> +
> +config RISCV_IOMMU_32BIT_ACCESS
> + bool "Use 32-bit accesses for RISC-V IOMMU registers"
> + depends on RISCV_IOMMU
> + help
> + Say Y when the RISC-V IOMMU MMIO window cannot be accessed
> + using naturally aligned 64-bit loads and stores.
> +
> + When enabled, 64-bit IOMMU registers are accessed as paired
> + 32-bit MMIO operations. This option does not describe an RV32
> + kernel or a 32-bit IOMMU architecture.
> diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
> index a31f50bbad35..7fa1721b5728 100644
> --- a/drivers/iommu/riscv/iommu.c
> +++ b/drivers/iommu/riscv/iommu.c
> @@ -53,6 +53,10 @@ struct riscv_iommu_devres {
> void *addr;
> };
>
> +#ifdef CONFIG_RISCV_IOMMU_32BIT_ACCESS
> +DEFINE_RAW_SPINLOCK(riscv_iommu_32bit_access_lock);
> +#endif
> +
> static void riscv_iommu_devres_pages_release(struct device *dev, void *res)
> {
> struct riscv_iommu_devres *devres = res;
> diff --git a/drivers/iommu/riscv/iommu.h b/drivers/iommu/riscv/iommu.h
> index 46df79dd5495..ba78ef1858c5 100644
> --- a/drivers/iommu/riscv/iommu.h
> +++ b/drivers/iommu/riscv/iommu.h
> @@ -14,6 +14,9 @@
> #include <linux/iommu.h>
> #include <linux/types.h>
> #include <linux/iopoll.h>
> +#ifdef CONFIG_RISCV_IOMMU_32BIT_ACCESS
> +#include <linux/spinlock.h>
> +#endif
>
> #include "iommu-bits.h"
>
> @@ -69,21 +72,61 @@ void riscv_iommu_disable(struct riscv_iommu_device *iommu);
> #define riscv_iommu_readl(iommu, addr) \
> readl_relaxed((iommu)->reg + (addr))
>
> -#define riscv_iommu_readq(iommu, addr) \
> - readq_relaxed((iommu)->reg + (addr))
> -
> #define riscv_iommu_writel(iommu, addr, val) \
> writel_relaxed((val), (iommu)->reg + (addr))
>
> +#define riscv_iommu_readl_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> + readx_poll_timeout(readl_relaxed, (iommu)->reg + (addr), val, cond, \
> + delay_us, timeout_us)
> +
> +#ifndef CONFIG_RISCV_IOMMU_32BIT_ACCESS
> +#define riscv_iommu_readq(iommu, addr) \
> + readq_relaxed((iommu)->reg + (addr))
> +
> #define riscv_iommu_writeq(iommu, addr, val) \
> writeq_relaxed((val), (iommu)->reg + (addr))
>
> #define riscv_iommu_readq_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> readx_poll_timeout(readq_relaxed, (iommu)->reg + (addr), val, cond, \
> delay_us, timeout_us)
> +#else /* CONFIG_RISCV_IOMMU_32BIT_ACCESS */
>
> -#define riscv_iommu_readl_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> - readx_poll_timeout(readl_relaxed, (iommu)->reg + (addr), val, cond, \
> - delay_us, timeout_us)
> +extern raw_spinlock_t riscv_iommu_32bit_access_lock;
> +
> +static inline u64 __riscv_iommu_readq_relaxed(void __iomem *addr)
> +{
> + u32 lo, hi;
> + unsigned long flags;
> +
> + raw_spin_lock_irqsave(&riscv_iommu_32bit_access_lock, flags);
> + do {
> + hi = readl_relaxed(addr + sizeof(u32));
> + lo = readl_relaxed(addr);
> + } while (hi != readl_relaxed(addr + sizeof(u32)));
> + raw_spin_unlock_irqrestore(&riscv_iommu_32bit_access_lock, flags);
Why the lock and the loop?
If you need the loop (for places where the hardware might be changing
both words?) then there is no need to read 'hi' twice when you loop.
But does it make any sense to be reading the value either while the hardware
is updating it (does that happen?) or concurrently with a write.
> +
> + return ((u64)hi << 32) | (u64)lo;
> +}
> +
> +static inline void __riscv_iommu_writeq_relaxed(u64 value, void __iomem *addr)
> +{
> + unsigned long flags;
> +
> + raw_spin_lock_irqsave(&riscv_iommu_32bit_access_lock, flags);
> + writel_relaxed((u32)(value >> 32), addr + sizeof(u32));
> + writel_relaxed((u32)value, addr);
> + raw_spin_unlock_irqrestore(&riscv_iommu_32bit_access_lock, flags);
What are you actually locking against?
I'm pretty sure it doesn't make any sense for two cpu to be writing to the
same entry at the same time.
Can't the writel_relaxed() be re-ordered, so you aren't guaranteeing they'll
be done high-low.
Same with the reads.
David
> +}
> +
> +#define riscv_iommu_readq(iommu, addr) \
> + __riscv_iommu_readq_relaxed((iommu)->reg + (addr))
> +
> +#define riscv_iommu_writeq(iommu, addr, val) \
> + __riscv_iommu_writeq_relaxed((val), (iommu)->reg + (addr))
> +
> +#define riscv_iommu_readq_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> + readx_poll_timeout(__riscv_iommu_readq_relaxed, (iommu)->reg + (addr), \
> + val, cond, delay_us, timeout_us)
> +#endif /* CONFIG_RISCV_IOMMU_32BIT_ACCESS */
>
> #endif
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
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:59 ` David Laight
@ 2026-06-15 12:38 ` Guo Ren
2026-06-15 13:23 ` [External] " Zhanpeng Zhang
` (2 more replies)
2026-07-13 6:09 ` [PATCH v2] iommu/riscv: Use 32-bit MMIO accesses for 64-bit registers Zhanpeng Zhang
2026-07-13 12:29 ` [PATCH v3] " Zhanpeng Zhang
4 siblings, 3 replies; 30+ messages in thread
From: Guo Ren @ 2026-06-15 12:38 UTC (permalink / raw)
To: zhangzhanpeng.jasper
Cc: alex, aou, cuiyunhui, iommu, joro, linux-kernel, linux-riscv,
luxu.kernel, palmer, pjw, robin.murphy, tjeznach, will, yuanzhu
Hi Zhanpeng Zhang,
I noticed you posted a similar fix recently. However, I had already
submitted a similar solution back in September 2025 [1]. It would be
great if you could review it. A few concerns with the current patch:
1. Using spin_lock_irqsave in such a small semantic structure is
unnecessary. IRQ protection should be provided by the higher-level
IOMMU driver interfaces. Many existing call sites already handle IRQ
disabling, so adding it here feels redundant and adds avoidable
overhead.
2. More critically, the RISCV_IOMMU_32BIT_ACCESS Kconfig option is
problematic. According to the RISC-V IOMMU specification (Software
Guidelines, “Reading and writing IOMMU registers”):
> Registers that are 64-bit wide may be accessed using either a 32-bit
> or a 64-bit access.
This clearly requires that any hardware supporting 64-bit MMIO access
must also support 32-bit MMIO access. Therefore, the IOMMU driver should
be built on a 32-bit access base for maximum hardware compatibility.
3. Only performance-monitoring counters require 64-bit IO access or the
high-low-high do-while retry strategy. For ordinary status and control
MMIO registers, a single read is sufficient.
4. Introducing a compile-time Kconfig that forces 32-bit splitting (or
64-bit access) across the entire driver is unnecessary for the vast
majority of registers and would prevent a single kernel Image (or .ko)
from working across all compliant platforms.
I believe the correct approach is to keep the driver on a 32-bit access
foundation (as required by the spec) and apply special 64-bit or
high-low-high handling only to performance-monitoring counters when
justified by data. This preserves broad hardware support without
unnecessary complexity.
What do you think? I’m happy to discuss or collaborate on a cleaner
solution based on the earlier patch [1].
[1]: https://lore.kernel.org/linux-riscv/20250903144217.837448-1-guoren@kernel.org/
Best Regards
GUO Ren
> Some RISC-V IOMMU implementations cannot perform 64-bit MMIO accesses
> to the IOMMU register file. The RISC-V IOMMU architecture allows 64-bit
> registers to be accessed using 32-bit accesses, provided the accesses are
> properly aligned and do not span multiple registers.
>
> Add a config option for such implementations and access 64-bit IOMMU
> registers as paired 32-bit MMIO operations when it is enabled. Serialize
> the paired accesses so the high and low halves cannot interleave with
> another CPU. Full 64-bit register programming writes the high half before
> the low half.
>
> This option describes the register access width. It is not an RV32 kernel
> mode and does not describe a 32-bit IOMMU architecture.
>
> Co-developed-by: Xu Lu <luxu.kernel@bytedance.com>
> Signed-off-by: Xu Lu <luxu.kernel@bytedance.com>
> Signed-off-by: Zhanpeng Zhang <zhangzhanpeng.jasper@bytedance.com>
> ---
> This is needed for platforms whose RISC-V IOMMU register window does not
> support naturally aligned 64-bit MMIO accesses.
>
> drivers/iommu/riscv/Kconfig | 11 ++++++++
> drivers/iommu/riscv/iommu.c | 4 +++
> drivers/iommu/riscv/iommu.h | 55 +++++++++++++++++++++++++++++++++----
> 3 files changed, 64 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/iommu/riscv/Kconfig b/drivers/iommu/riscv/Kconfig
> index b86e5ab94183..54d624b9b2ef 100644
> --- a/drivers/iommu/riscv/Kconfig
> +++ b/drivers/iommu/riscv/Kconfig
> @@ -22,3 +22,14 @@ config RISCV_IOMMU_PCI
> def_bool y if RISCV_IOMMU && PCI_MSI
> help
> Support for the PCIe implementation of RISC-V IOMMU architecture.
> +
> +config RISCV_IOMMU_32BIT_ACCESS
> + bool "Use 32-bit accesses for RISC-V IOMMU registers"
> + depends on RISCV_IOMMU
> + help
> + Say Y when the RISC-V IOMMU MMIO window cannot be accessed
> + using naturally aligned 64-bit loads and stores.
> +
> + When enabled, 64-bit IOMMU registers are accessed as paired
> + 32-bit MMIO operations. This option does not describe an RV32
> + kernel or a 32-bit IOMMU architecture.
> diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
> index a31f50bbad35..7fa1721b5728 100644
> --- a/drivers/iommu/riscv/iommu.c
> +++ b/drivers/iommu/riscv/iommu.c
> @@ -53,6 +53,10 @@ struct riscv_iommu_devres {
> void *addr;
> };
>
> +#ifdef CONFIG_RISCV_IOMMU_32BIT_ACCESS
> +DEFINE_RAW_SPINLOCK(riscv_iommu_32bit_access_lock);
> +#endif
> +
> static void riscv_iommu_devres_pages_release(struct device *dev, void *res)
> {
> struct riscv_iommu_devres *devres = res;
> diff --git a/drivers/iommu/riscv/iommu.h b/drivers/iommu/riscv/iommu.h
> index 46df79dd5495..ba78ef1858c5 100644
> --- a/drivers/iommu/riscv/iommu.h
> +++ b/drivers/iommu/riscv/iommu.h
> @@ -14,6 +14,9 @@
> #include <linux/iommu.h>
> #include <linux/types.h>
> #include <linux/iopoll.h>
> +#ifdef CONFIG_RISCV_IOMMU_32BIT_ACCESS
> +#include <linux/spinlock.h>
> +#endif
>
> #include "iommu-bits.h"
>
> @@ -69,21 +72,61 @@ void riscv_iommu_disable(struct riscv_iommu_device *iommu);
> #define riscv_iommu_readl(iommu, addr) \
> readl_relaxed((iommu)->reg + (addr))
>
> -#define riscv_iommu_readq(iommu, addr) \
> - readq_relaxed((iommu)->reg + (addr))
> -
> #define riscv_iommu_writel(iommu, addr, val) \
> writel_relaxed((val), (iommu)->reg + (addr))
>
> +#define riscv_iommu_readl_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> + readx_poll_timeout(readl_relaxed, (iommu)->reg + (addr), val, cond, \
> + delay_us, timeout_us)
> +
> +#ifndef CONFIG_RISCV_IOMMU_32BIT_ACCESS
> +#define riscv_iommu_readq(iommu, addr) \
> + readq_relaxed((iommu)->reg + (addr))
> +
> #define riscv_iommu_writeq(iommu, addr, val) \
> writeq_relaxed((val), (iommu)->reg + (addr))
>
> #define riscv_iommu_readq_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> readx_poll_timeout(readq_relaxed, (iommu)->reg + (addr), val, cond, \
> delay_us, timeout_us)
> +#else /* CONFIG_RISCV_IOMMU_32BIT_ACCESS */
>
> -#define riscv_iommu_readl_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> - readx_poll_timeout(readl_relaxed, (iommu)->reg + (addr), val, cond, \
> - delay_us, timeout_us)
> +extern raw_spinlock_t riscv_iommu_32bit_access_lock;
> +
> +static inline u64 __riscv_iommu_readq_relaxed(void __iomem *addr)
> +{
> + u32 lo, hi;
> + unsigned long flags;
> +
> + raw_spin_lock_irqsave(&riscv_iommu_32bit_access_lock, flags);
> + do {
> + hi = readl_relaxed(addr + sizeof(u32));
> + lo = readl_relaxed(addr);
> + } while (hi != readl_relaxed(addr + sizeof(u32)));
> + raw_spin_unlock_irqrestore(&riscv_iommu_32bit_access_lock, flags);
> +
> + return ((u64)hi << 32) | (u64)lo;
> +}
> +
> +static inline void __riscv_iommu_writeq_relaxed(u64 value, void __iomem *addr)
> +{
> + unsigned long flags;
> +
> + raw_spin_lock_irqsave(&riscv_iommu_32bit_access_lock, flags);
> + writel_relaxed((u32)(value >> 32), addr + sizeof(u32));
> + writel_relaxed((u32)value, addr);
> + raw_spin_unlock_irqrestore(&riscv_iommu_32bit_access_lock, flags);
> +}
> +
> +#define riscv_iommu_readq(iommu, addr) \
> + __riscv_iommu_readq_relaxed((iommu)->reg + (addr))
> +
> +#define riscv_iommu_writeq(iommu, addr, val) \
> + __riscv_iommu_writeq_relaxed((val), (iommu)->reg + (addr))
> +
> +#define riscv_iommu_readq_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> + readx_poll_timeout(__riscv_iommu_readq_relaxed, (iommu)->reg + (addr), \
> + val, cond, delay_us, timeout_us)
> +#endif /* CONFIG_RISCV_IOMMU_32BIT_ACCESS */
>
> #endif
> --
> 2.50.1 (Apple Git-155)
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [External] Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
2026-06-15 9:59 ` David Laight
@ 2026-06-15 13:21 ` Zhanpeng Zhang
0 siblings, 0 replies; 30+ messages in thread
From: Zhanpeng Zhang @ 2026-06-15 13:21 UTC (permalink / raw)
To: David Laight
Cc: tjeznach, joro, will, robin.murphy, pjw, palmer, aou, alex, iommu,
linux-riscv, linux-kernel, Xu Lu, cuiyunhui, yuanzhu,
guoren@kernel.org
Hi David,
Thanks, I agree with your point about the lock and the relaxed accessors.
Guo Ren also pointed me to the earlier discussion on this topic, and I think the
right next step is to align with that thread rather than continue this separate
Kconfig-based patch.
So I will drop this patch.
Thanks,
Zhanpeng
> From: "David Laight"<david.laight.linux@gmail.com>
> Date: Mon, Jun 15, 2026, 18:00
> Subject: [External] Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
> To: "Zhanpeng Zhang"<zhangzhanpeng.jasper@bytedance.com>
> Cc: "Tomasz Jeznach"<tjeznach@rivosinc.com>, "Joerg Roedel"<joro@8bytes.org>, "Will Deacon"<will@kernel.org>, "Robin Murphy"<robin.murphy@arm.com>, "Paul Walmsley"<pjw@kernel.org>, "Palmer Dabbelt"<palmer@dabbelt.com>, "Albert Ou"<aou@eecs.berkeley.edu>, "Alexandre Ghiti"<alex@ghiti.fr>, <iommu@lists.linux.dev>, <linux-riscv@lists.infradead.org>, <linux-kernel@vger.kernel.org>, "Xu Lu"<luxu.kernel@bytedance.com>, <cuiyunhui@bytedance.com>, <yuanzhu@bytedance.com>
> On Mon, 15 Jun 2026 14:48:55 +0800
> Zhanpeng Zhang <zhangzhanpeng.jasper@bytedance.com> wrote:
>
> > Some RISC-V IOMMU implementations cannot perform 64-bit MMIO accesses
> > to the IOMMU register file. The RISC-V IOMMU architecture allows 64-bit
> > registers to be accessed using 32-bit accesses, provided the accesses are
> > properly aligned and do not span multiple registers.
> >
> > Add a config option for such implementations and access 64-bit IOMMU
> > registers as paired 32-bit MMIO operations when it is enabled. Serialize
> > the paired accesses so the high and low halves cannot interleave with
> > another CPU. Full 64-bit register programming writes the high half before
> > the low half.
> >
> > This option describes the register access width. It is not an RV32 kernel
> > mode and does not describe a 32-bit IOMMU architecture.
> >
> > Co-developed-by: Xu Lu <luxu.kernel@bytedance.com>
> > Signed-off-by: Xu Lu <luxu.kernel@bytedance.com>
> > Signed-off-by: Zhanpeng Zhang <zhangzhanpeng.jasper@bytedance.com>
> > ---
> > This is needed for platforms whose RISC-V IOMMU register window does not
> > support naturally aligned 64-bit MMIO accesses.
> >
> > drivers/iommu/riscv/Kconfig | 11 ++++++++
> > drivers/iommu/riscv/iommu.c | 4 +++
> > drivers/iommu/riscv/iommu.h | 55 +++++++++++++++++++++++++++++++++----
> > 3 files changed, 64 insertions(+), 6 deletions(-)
> >
> > diff --git a/drivers/iommu/riscv/Kconfig b/drivers/iommu/riscv/Kconfig
> > index b86e5ab94183..54d624b9b2ef 100644
> > --- a/drivers/iommu/riscv/Kconfig
> > +++ b/drivers/iommu/riscv/Kconfig
> > @@ -22,3 +22,14 @@ config RISCV_IOMMU_PCI
> > def_bool y if RISCV_IOMMU && PCI_MSI
> > help
> > Support for the PCIe implementation of RISC-V IOMMU architecture.
> > +
> > +config RISCV_IOMMU_32BIT_ACCESS
> > + bool "Use 32-bit accesses for RISC-V IOMMU registers"
> > + depends on RISCV_IOMMU
> > + help
> > + Say Y when the RISC-V IOMMU MMIO window cannot be accessed
> > + using naturally aligned 64-bit loads and stores.
> > +
> > + When enabled, 64-bit IOMMU registers are accessed as paired
> > + 32-bit MMIO operations. This option does not describe an RV32
> > + kernel or a 32-bit IOMMU architecture.
> > diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
> > index a31f50bbad35..7fa1721b5728 100644
> > --- a/drivers/iommu/riscv/iommu.c
> > +++ b/drivers/iommu/riscv/iommu.c
> > @@ -53,6 +53,10 @@ struct riscv_iommu_devres {
> > void *addr;
> > };
> >
> > +#ifdef CONFIG_RISCV_IOMMU_32BIT_ACCESS
> > +DEFINE_RAW_SPINLOCK(riscv_iommu_32bit_access_lock);
> > +#endif
> > +
> > static void riscv_iommu_devres_pages_release(struct device *dev, void *res)
> > {
> > struct riscv_iommu_devres *devres = res;
> > diff --git a/drivers/iommu/riscv/iommu.h b/drivers/iommu/riscv/iommu.h
> > index 46df79dd5495..ba78ef1858c5 100644
> > --- a/drivers/iommu/riscv/iommu.h
> > +++ b/drivers/iommu/riscv/iommu.h
> > @@ -14,6 +14,9 @@
> > #include <linux/iommu.h>
> > #include <linux/types.h>
> > #include <linux/iopoll.h>
> > +#ifdef CONFIG_RISCV_IOMMU_32BIT_ACCESS
> > +#include <linux/spinlock.h>
> > +#endif
> >
> > #include "iommu-bits.h"
> >
> > @@ -69,21 +72,61 @@ void riscv_iommu_disable(struct riscv_iommu_device *iommu);
> > #define riscv_iommu_readl(iommu, addr) \
> > readl_relaxed((iommu)->reg + (addr))
> >
> > -#define riscv_iommu_readq(iommu, addr) \
> > - readq_relaxed((iommu)->reg + (addr))
> > -
> > #define riscv_iommu_writel(iommu, addr, val) \
> > writel_relaxed((val), (iommu)->reg + (addr))
> >
> > +#define riscv_iommu_readl_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> > + readx_poll_timeout(readl_relaxed, (iommu)->reg + (addr), val, cond, \
> > + delay_us, timeout_us)
> > +
> > +#ifndef CONFIG_RISCV_IOMMU_32BIT_ACCESS
> > +#define riscv_iommu_readq(iommu, addr) \
> > + readq_relaxed((iommu)->reg + (addr))
> > +
> > #define riscv_iommu_writeq(iommu, addr, val) \
> > writeq_relaxed((val), (iommu)->reg + (addr))
> >
> > #define riscv_iommu_readq_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> > readx_poll_timeout(readq_relaxed, (iommu)->reg + (addr), val, cond, \
> > delay_us, timeout_us)
> > +#else /* CONFIG_RISCV_IOMMU_32BIT_ACCESS */
> >
> > -#define riscv_iommu_readl_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> > - readx_poll_timeout(readl_relaxed, (iommu)->reg + (addr), val, cond, \
> > - delay_us, timeout_us)
> > +extern raw_spinlock_t riscv_iommu_32bit_access_lock;
> > +
> > +static inline u64 __riscv_iommu_readq_relaxed(void __iomem *addr)
> > +{
> > + u32 lo, hi;
> > + unsigned long flags;
> > +
> > + raw_spin_lock_irqsave(&riscv_iommu_32bit_access_lock, flags);
> > + do {
> > + hi = readl_relaxed(addr + sizeof(u32));
> > + lo = readl_relaxed(addr);
> > + } while (hi != readl_relaxed(addr + sizeof(u32)));
> > + raw_spin_unlock_irqrestore(&riscv_iommu_32bit_access_lock, flags);
>
> Why the lock and the loop?
> If you need the loop (for places where the hardware might be changing
> both words?) then there is no need to read 'hi' twice when you loop.
>
> But does it make any sense to be reading the value either while the hardware
> is updating it (does that happen?) or concurrently with a write.
>
>
> > +
> > + return ((u64)hi << 32) | (u64)lo;
> > +}
> > +
> > +static inline void __riscv_iommu_writeq_relaxed(u64 value, void __iomem *addr)
> > +{
> > + unsigned long flags;
> > +
> > + raw_spin_lock_irqsave(&riscv_iommu_32bit_access_lock, flags);
> > + writel_relaxed((u32)(value >> 32), addr + sizeof(u32));
> > + writel_relaxed((u32)value, addr);
> > + raw_spin_unlock_irqrestore(&riscv_iommu_32bit_access_lock, flags);
>
> What are you actually locking against?
> I'm pretty sure it doesn't make any sense for two cpu to be writing to the
> same entry at the same time.
>
> Can't the writel_relaxed() be re-ordered, so you aren't guaranteeing they'll
> be done high-low.
> Same with the reads.
>
> David
>
> > +}
> > +
> > +#define riscv_iommu_readq(iommu, addr) \
> > + __riscv_iommu_readq_relaxed((iommu)->reg + (addr))
> > +
> > +#define riscv_iommu_writeq(iommu, addr, val) \
> > + __riscv_iommu_writeq_relaxed((val), (iommu)->reg + (addr))
> > +
> > +#define riscv_iommu_readq_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> > + readx_poll_timeout(__riscv_iommu_readq_relaxed, (iommu)->reg + (addr), \
> > + val, cond, delay_us, timeout_us)
> > +#endif /* CONFIG_RISCV_IOMMU_32BIT_ACCESS */
> >
> > #endif
>
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [External] Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
2026-06-15 12:38 ` Guo Ren
@ 2026-06-15 13:23 ` Zhanpeng Zhang
2026-06-16 10:36 ` David Laight
2026-06-18 3:20 ` Vivian Wang
2 siblings, 0 replies; 30+ messages in thread
From: Zhanpeng Zhang @ 2026-06-15 13:23 UTC (permalink / raw)
To: Guo Ren
Cc: alex, aou, cuiyunhui, iommu, joro, linux-kernel, linux-riscv,
luxu.kernel, palmer, pjw, robin.murphy, tjeznach, will, yuanzhu
Hi Guo Ren,
Thanks for the pointer, and sorry that I missed the earlier discussion.
I agree with your concerns. The lock in my v1 is not the right approach, and
David also pointed out the same issue. More importantly, after reading your
comments, I agree that this should not be handled as a separate Kconfig-selected
path.
If the RISC-V IOMMU specification allows 64-bit registers to be accessed with
32-bit MMIO operations, then a generic kernel should be able to support that
without requiring a platform-specific build-time option. So I will drop my v1
and will not continue this separate patch.
I will take a closer look at your earlier proposal and the previous discussion.
If the preferred direction is to make 32-bit register accesses part of the
driver's common register access model, I am happy to help test, review, or
rework patches in that direction.
Best Regards,
Zhanpeng
> From: "Guo Ren"<guoren@kernel.org>
> Date: Mon, Jun 15, 2026, 20:38
> Subject: [External] Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
> To: <zhangzhanpeng.jasper@bytedance.com>
> Cc: <alex@ghiti.fr>, <aou@eecs.berkeley.edu>, <cuiyunhui@bytedance.com>, <iommu@lists.linux.dev>, <joro@8bytes.org>, <linux-kernel@vger.kernel.org>, <linux-riscv@lists.infradead.org>, <luxu.kernel@bytedance.com>, <palmer@dabbelt.com>, <pjw@kernel.org>, <robin.murphy@arm.com>, <tjeznach@rivosinc.com>, <will@kernel.org>, <yuanzhu@bytedance.com>
> Hi Zhanpeng Zhang,
>
> I noticed you posted a similar fix recently. However, I had already
> submitted a similar solution back in September 2025 [1]. It would be
> great if you could review it. A few concerns with the current patch:
>
> 1. Using spin_lock_irqsave in such a small semantic structure is
> unnecessary. IRQ protection should be provided by the higher-level
> IOMMU driver interfaces. Many existing call sites already handle IRQ
> disabling, so adding it here feels redundant and adds avoidable
> overhead.
>
> 2. More critically, the RISCV_IOMMU_32BIT_ACCESS Kconfig option is
> problematic. According to the RISC-V IOMMU specification (Software
> Guidelines, “Reading and writing IOMMU registers”):
>
> > Registers that are 64-bit wide may be accessed using either a 32-bit
> > or a 64-bit access.
>
> This clearly requires that any hardware supporting 64-bit MMIO access
> must also support 32-bit MMIO access. Therefore, the IOMMU driver should
> be built on a 32-bit access base for maximum hardware compatibility.
>
> 3. Only performance-monitoring counters require 64-bit IO access or the
> high-low-high do-while retry strategy. For ordinary status and control
> MMIO registers, a single read is sufficient.
>
> 4. Introducing a compile-time Kconfig that forces 32-bit splitting (or
> 64-bit access) across the entire driver is unnecessary for the vast
> majority of registers and would prevent a single kernel Image (or .ko)
> from working across all compliant platforms.
>
> I believe the correct approach is to keep the driver on a 32-bit access
> foundation (as required by the spec) and apply special 64-bit or
> high-low-high handling only to performance-monitoring counters when
> justified by data. This preserves broad hardware support without
> unnecessary complexity.
>
> What do you think? I’m happy to discuss or collaborate on a cleaner
> solution based on the earlier patch [1].
>
> [1]: https://lore.kernel.org/linux-riscv/20250903144217.837448-1-guoren@kernel.org/
>
> Best Regards
> GUO Ren
>
> > Some RISC-V IOMMU implementations cannot perform 64-bit MMIO accesses
> > to the IOMMU register file. The RISC-V IOMMU architecture allows 64-bit
> > registers to be accessed using 32-bit accesses, provided the accesses are
> > properly aligned and do not span multiple registers.
> >
> > Add a config option for such implementations and access 64-bit IOMMU
> > registers as paired 32-bit MMIO operations when it is enabled. Serialize
> > the paired accesses so the high and low halves cannot interleave with
> > another CPU. Full 64-bit register programming writes the high half before
> > the low half.
> >
> > This option describes the register access width. It is not an RV32 kernel
> > mode and does not describe a 32-bit IOMMU architecture.
> >
> > Co-developed-by: Xu Lu <luxu.kernel@bytedance.com>
> > Signed-off-by: Xu Lu <luxu.kernel@bytedance.com>
> > Signed-off-by: Zhanpeng Zhang <zhangzhanpeng.jasper@bytedance.com>
> > ---
> > This is needed for platforms whose RISC-V IOMMU register window does not
> > support naturally aligned 64-bit MMIO accesses.
> >
> > drivers/iommu/riscv/Kconfig | 11 ++++++++
> > drivers/iommu/riscv/iommu.c | 4 +++
> > drivers/iommu/riscv/iommu.h | 55 +++++++++++++++++++++++++++++++++----
> > 3 files changed, 64 insertions(+), 6 deletions(-)
> >
> > diff --git a/drivers/iommu/riscv/Kconfig b/drivers/iommu/riscv/Kconfig
> > index b86e5ab94183..54d624b9b2ef 100644
> > --- a/drivers/iommu/riscv/Kconfig
> > +++ b/drivers/iommu/riscv/Kconfig
> > @@ -22,3 +22,14 @@ config RISCV_IOMMU_PCI
> > def_bool y if RISCV_IOMMU && PCI_MSI
> > help
> > Support for the PCIe implementation of RISC-V IOMMU architecture.
> > +
> > +config RISCV_IOMMU_32BIT_ACCESS
> > + bool "Use 32-bit accesses for RISC-V IOMMU registers"
> > + depends on RISCV_IOMMU
> > + help
> > + Say Y when the RISC-V IOMMU MMIO window cannot be accessed
> > + using naturally aligned 64-bit loads and stores.
> > +
> > + When enabled, 64-bit IOMMU registers are accessed as paired
> > + 32-bit MMIO operations. This option does not describe an RV32
> > + kernel or a 32-bit IOMMU architecture.
> > diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
> > index a31f50bbad35..7fa1721b5728 100644
> > --- a/drivers/iommu/riscv/iommu.c
> > +++ b/drivers/iommu/riscv/iommu.c
> > @@ -53,6 +53,10 @@ struct riscv_iommu_devres {
> > void *addr;
> > };
> >
> > +#ifdef CONFIG_RISCV_IOMMU_32BIT_ACCESS
> > +DEFINE_RAW_SPINLOCK(riscv_iommu_32bit_access_lock);
> > +#endif
> > +
> > static void riscv_iommu_devres_pages_release(struct device *dev, void *res)
> > {
> > struct riscv_iommu_devres *devres = res;
> > diff --git a/drivers/iommu/riscv/iommu.h b/drivers/iommu/riscv/iommu.h
> > index 46df79dd5495..ba78ef1858c5 100644
> > --- a/drivers/iommu/riscv/iommu.h
> > +++ b/drivers/iommu/riscv/iommu.h
> > @@ -14,6 +14,9 @@
> > #include <linux/iommu.h>
> > #include <linux/types.h>
> > #include <linux/iopoll.h>
> > +#ifdef CONFIG_RISCV_IOMMU_32BIT_ACCESS
> > +#include <linux/spinlock.h>
> > +#endif
> >
> > #include "iommu-bits.h"
> >
> > @@ -69,21 +72,61 @@ void riscv_iommu_disable(struct riscv_iommu_device *iommu);
> > #define riscv_iommu_readl(iommu, addr) \
> > readl_relaxed((iommu)->reg + (addr))
> >
> > -#define riscv_iommu_readq(iommu, addr) \
> > - readq_relaxed((iommu)->reg + (addr))
> > -
> > #define riscv_iommu_writel(iommu, addr, val) \
> > writel_relaxed((val), (iommu)->reg + (addr))
> >
> > +#define riscv_iommu_readl_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> > + readx_poll_timeout(readl_relaxed, (iommu)->reg + (addr), val, cond, \
> > + delay_us, timeout_us)
> > +
> > +#ifndef CONFIG_RISCV_IOMMU_32BIT_ACCESS
> > +#define riscv_iommu_readq(iommu, addr) \
> > + readq_relaxed((iommu)->reg + (addr))
> > +
> > #define riscv_iommu_writeq(iommu, addr, val) \
> > writeq_relaxed((val), (iommu)->reg + (addr))
> >
> > #define riscv_iommu_readq_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> > readx_poll_timeout(readq_relaxed, (iommu)->reg + (addr), val, cond, \
> > delay_us, timeout_us)
> > +#else /* CONFIG_RISCV_IOMMU_32BIT_ACCESS */
> >
> > -#define riscv_iommu_readl_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> > - readx_poll_timeout(readl_relaxed, (iommu)->reg + (addr), val, cond, \
> > - delay_us, timeout_us)
> > +extern raw_spinlock_t riscv_iommu_32bit_access_lock;
> > +
> > +static inline u64 __riscv_iommu_readq_relaxed(void __iomem *addr)
> > +{
> > + u32 lo, hi;
> > + unsigned long flags;
> > +
> > + raw_spin_lock_irqsave(&riscv_iommu_32bit_access_lock, flags);
> > + do {
> > + hi = readl_relaxed(addr + sizeof(u32));
> > + lo = readl_relaxed(addr);
> > + } while (hi != readl_relaxed(addr + sizeof(u32)));
> > + raw_spin_unlock_irqrestore(&riscv_iommu_32bit_access_lock, flags);
> > +
> > + return ((u64)hi << 32) | (u64)lo;
> > +}
> > +
> > +static inline void __riscv_iommu_writeq_relaxed(u64 value, void __iomem *addr)
> > +{
> > + unsigned long flags;
> > +
> > + raw_spin_lock_irqsave(&riscv_iommu_32bit_access_lock, flags);
> > + writel_relaxed((u32)(value >> 32), addr + sizeof(u32));
> > + writel_relaxed((u32)value, addr);
> > + raw_spin_unlock_irqrestore(&riscv_iommu_32bit_access_lock, flags);
> > +}
> > +
> > +#define riscv_iommu_readq(iommu, addr) \
> > + __riscv_iommu_readq_relaxed((iommu)->reg + (addr))
> > +
> > +#define riscv_iommu_writeq(iommu, addr, val) \
> > + __riscv_iommu_writeq_relaxed((val), (iommu)->reg + (addr))
> > +
> > +#define riscv_iommu_readq_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> > + readx_poll_timeout(__riscv_iommu_readq_relaxed, (iommu)->reg + (addr), \
> > + val, cond, delay_us, timeout_us)
> > +#endif /* CONFIG_RISCV_IOMMU_32BIT_ACCESS */
> >
> > #endif
> > --
> > 2.50.1 (Apple Git-155)
>
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
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-18 3:20 ` Vivian Wang
2 siblings, 1 reply; 30+ messages in thread
From: David Laight @ 2026-06-16 10:36 UTC (permalink / raw)
To: Guo Ren
Cc: zhangzhanpeng.jasper, alex, aou, cuiyunhui, iommu, joro,
linux-kernel, linux-riscv, luxu.kernel, palmer, pjw, robin.murphy,
tjeznach, will, yuanzhu
On Mon, 15 Jun 2026 12:38:17 +0000
Guo Ren <guoren@kernel.org> wrote:
> Hi Zhanpeng Zhang,
..
> 3. Only performance-monitoring counters require 64-bit IO access or the
> high-low-high do-while retry strategy. For ordinary status and control
> MMIO registers, a single read is sufficient.
Actually this sequence should be enough for a counter:
hi = read_hi();
lo = read_lo();
if (hi != read_hi()) {
// Pick a value that happened while doing the reads.
hi++;
lo = 0;
}
-- David
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
2026-06-16 10:36 ` David Laight
@ 2026-06-16 15:47 ` Guo Ren
2026-06-16 19:51 ` David Laight
0 siblings, 1 reply; 30+ messages in thread
From: Guo Ren @ 2026-06-16 15:47 UTC (permalink / raw)
To: David Laight
Cc: zhangzhanpeng.jasper, alex, aou, cuiyunhui, iommu, joro,
linux-kernel, linux-riscv, luxu.kernel, palmer, pjw, robin.murphy,
tjeznach, will, yuanzhu
On Tue, Jun 16, 2026 at 6:36 PM David Laight
<david.laight.linux@gmail.com> wrote:
>
> On Mon, 15 Jun 2026 12:38:17 +0000
> Guo Ren <guoren@kernel.org> wrote:
>
> > Hi Zhanpeng Zhang,
> ..
> > 3. Only performance-monitoring counters require 64-bit IO access or the
> > high-low-high do-while retry strategy. For ordinary status and control
> > MMIO registers, a single read is sufficient.
>
> Actually this sequence should be enough for a counter:
> hi = read_hi();
> lo = read_lo();
> if (hi != read_hi()) {
> // Pick a value that happened while doing the reads.
> hi++;
> lo = 0;
> }
This is not a free optimization — it does not preserve the same
semantics as an atomic 64-bit read. There are at least two correctness
issues:
1. Loss of precision: If hi changed during the read, setting lo = 0
discards the actual lo value. The correct approach is to re-read lo
after detecting the change, not fabricate a value.
2. Multiple overflows: This assumes at most one overflow occurs
between reads. If two overflows happen (e.g., due to interrupt
injection), hi++ will produce an incorrect result, silently corrupting
the counter value.
Negligible benefit: hi changing between reads is an extremely rare
event. Optimizing away the retry loop for such a rare case provides no
meaningful performance gain. And if hi never stabilizes, that
indicates a hardware failure — in which case hanging in the retry loop
is actually the more appropriate behavior, as it makes the failure
visible rather than silently producing garbage values.
The high-low-high do-while retry strategy exists precisely to handle
these cases correctly. I don't think this proposed sequence is a valid
replacement.
--
Best Regards
Guo Ren
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
2026-06-16 15:47 ` Guo Ren
@ 2026-06-16 19:51 ` David Laight
2026-06-17 16:24 ` Guo Ren
0 siblings, 1 reply; 30+ messages in thread
From: David Laight @ 2026-06-16 19:51 UTC (permalink / raw)
To: Guo Ren
Cc: zhangzhanpeng.jasper, alex, aou, cuiyunhui, iommu, joro,
linux-kernel, linux-riscv, luxu.kernel, palmer, pjw, robin.murphy,
tjeznach, will, yuanzhu
On Tue, 16 Jun 2026 23:47:05 +0800
Guo Ren <guoren@kernel.org> wrote:
> On Tue, Jun 16, 2026 at 6:36 PM David Laight
> <david.laight.linux@gmail.com> wrote:
> >
> > On Mon, 15 Jun 2026 12:38:17 +0000
> > Guo Ren <guoren@kernel.org> wrote:
> >
> > > Hi Zhanpeng Zhang,
> > ..
> > > 3. Only performance-monitoring counters require 64-bit IO access or the
> > > high-low-high do-while retry strategy. For ordinary status and control
> > > MMIO registers, a single read is sufficient.
> >
> > Actually this sequence should be enough for a counter:
> > hi = read_hi();
> > lo = read_lo();
> > if (hi != read_hi()) {
> > // Pick a value that happened while doing the reads.
> > hi++;
> > lo = 0;
> > }
> This is not a free optimization — it does not preserve the same
> semantics as an atomic 64-bit read. There are at least two correctness
> issues:
>
> 1. Loss of precision: If hi changed during the read, setting lo = 0
> discards the actual lo value. The correct approach is to re-read lo
> after detecting the change, not fabricate a value.
>
> 2. Multiple overflows: This assumes at most one overflow occurs
> between reads. If two overflows happen (e.g., due to interrupt
> injection), hi++ will produce an incorrect result, silently corrupting
> the counter value.
>
> Negligible benefit: hi changing between reads is an extremely rare
> event. Optimizing away the retry loop for such a rare case provides no
> meaningful performance gain. And if hi never stabilizes, that
> indicates a hardware failure — in which case hanging in the retry loop
> is actually the more appropriate behavior, as it makes the failure
> visible rather than silently producing garbage values.
>
> The high-low-high do-while retry strategy exists precisely to handle
> these cases correctly. I don't think this proposed sequence is a valid
> replacement.
>
The point is that if the value is an incrementing counter (of some form)
then the value is stale by the time the reading sequence completes.
So all the code can be assumed to do is return a value the counter had
sometime between when the code started and when it finished.
If hi changes then hi+1:0 must have happened while the code was running
so it is a safe return value.
It is likely that the reads are also much slower than memory reads.
If hi changes relatively infrequently (compared to the number of reads)
it may be worth saving the previously read value and avoiding the second
read of hi if it is the same as the previous read hi and lo has got larger.
David
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
2026-06-16 19:51 ` David Laight
@ 2026-06-17 16:24 ` Guo Ren
2026-06-17 21:54 ` David Laight
0 siblings, 1 reply; 30+ messages in thread
From: Guo Ren @ 2026-06-17 16:24 UTC (permalink / raw)
To: David Laight
Cc: zhangzhanpeng.jasper, alex, aou, cuiyunhui, iommu, joro,
linux-kernel, linux-riscv, luxu.kernel, palmer, pjw, robin.murphy,
tjeznach, will, yuanzhu
On Wed, Jun 17, 2026 at 3:51 AM David Laight
<david.laight.linux@gmail.com> wrote:
>
> On Tue, 16 Jun 2026 23:47:05 +0800
> Guo Ren <guoren@kernel.org> wrote:
>
> > On Tue, Jun 16, 2026 at 6:36 PM David Laight
> > <david.laight.linux@gmail.com> wrote:
> > >
> > > On Mon, 15 Jun 2026 12:38:17 +0000
> > > Guo Ren <guoren@kernel.org> wrote:
> > >
> > > > Hi Zhanpeng Zhang,
> > > ..
> > > > 3. Only performance-monitoring counters require 64-bit IO access or the
> > > > high-low-high do-while retry strategy. For ordinary status and control
> > > > MMIO registers, a single read is sufficient.
> > >
> > > Actually this sequence should be enough for a counter:
> > > hi = read_hi();
> > > lo = read_lo();
> > > if (hi != read_hi()) {
> > > // Pick a value that happened while doing the reads.
> > > hi++;
> > > lo = 0;
> > > }
> > This is not a free optimization — it does not preserve the same
> > semantics as an atomic 64-bit read. There are at least two correctness
> > issues:
> >
> > 1. Loss of precision: If hi changed during the read, setting lo = 0
> > discards the actual lo value. The correct approach is to re-read lo
> > after detecting the change, not fabricate a value.
> >
> > 2. Multiple overflows: This assumes at most one overflow occurs
> > between reads. If two overflows happen (e.g., due to interrupt
> > injection), hi++ will produce an incorrect result, silently corrupting
> > the counter value.
> >
> > Negligible benefit: hi changing between reads is an extremely rare
> > event. Optimizing away the retry loop for such a rare case provides no
> > meaningful performance gain. And if hi never stabilizes, that
> > indicates a hardware failure — in which case hanging in the retry loop
> > is actually the more appropriate behavior, as it makes the failure
> > visible rather than silently producing garbage values.
> >
> > The high-low-high do-while retry strategy exists precisely to handle
> > these cases correctly. I don't think this proposed sequence is a valid
> > replacement.
> >
>
> The point is that if the value is an incrementing counter (of some form)
> then the value is stale by the time the reading sequence completes.
> So all the code can be assumed to do is return a value the counter had
> sometime between when the code started and when it finished.
> If hi changes then hi+1:0 must have happened while the code was running
> so it is a safe return value.
You're right — (hi + 1):0 is enough for hi-lo-hi. Thank you for
sticking to your point; it helped me think more carefully and
understand the subtlety.
>
> It is likely that the reads are also much slower than memory reads.
> If hi changes relatively infrequently (compared to the number of reads)
> it may be worth saving the previously read value and avoiding the second
> read of hi if it is the same as the previous read hi and lo has got larger.
--
Best Regards
Guo Ren
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
2026-06-17 16:24 ` Guo Ren
@ 2026-06-17 21:54 ` David Laight
2026-06-18 3:36 ` Guo Ren
0 siblings, 1 reply; 30+ messages in thread
From: David Laight @ 2026-06-17 21:54 UTC (permalink / raw)
To: Guo Ren
Cc: zhangzhanpeng.jasper, alex, aou, cuiyunhui, iommu, joro,
linux-kernel, linux-riscv, luxu.kernel, palmer, pjw, robin.murphy,
tjeznach, will, yuanzhu
On Thu, 18 Jun 2026 00:24:12 +0800
Guo Ren <guoren@kernel.org> wrote:
> On Wed, Jun 17, 2026 at 3:51 AM David Laight
> <david.laight.linux@gmail.com> wrote:
> >
> > On Tue, 16 Jun 2026 23:47:05 +0800
> > Guo Ren <guoren@kernel.org> wrote:
> >
> > > On Tue, Jun 16, 2026 at 6:36 PM David Laight
> > > <david.laight.linux@gmail.com> wrote:
> > > >
> > > > On Mon, 15 Jun 2026 12:38:17 +0000
> > > > Guo Ren <guoren@kernel.org> wrote:
> > > >
> > > > > Hi Zhanpeng Zhang,
> > > > ..
> > > > > 3. Only performance-monitoring counters require 64-bit IO access or the
> > > > > high-low-high do-while retry strategy. For ordinary status and control
> > > > > MMIO registers, a single read is sufficient.
> > > >
> > > > Actually this sequence should be enough for a counter:
> > > > hi = read_hi();
> > > > lo = read_lo();
> > > > if (hi != read_hi()) {
> > > > // Pick a value that happened while doing the reads.
> > > > hi++;
> > > > lo = 0;
> > > > }
> > > This is not a free optimization — it does not preserve the same
> > > semantics as an atomic 64-bit read. There are at least two correctness
> > > issues:
> > >
> > > 1. Loss of precision: If hi changed during the read, setting lo = 0
> > > discards the actual lo value. The correct approach is to re-read lo
> > > after detecting the change, not fabricate a value.
> > >
> > > 2. Multiple overflows: This assumes at most one overflow occurs
> > > between reads. If two overflows happen (e.g., due to interrupt
> > > injection), hi++ will produce an incorrect result, silently corrupting
> > > the counter value.
> > >
> > > Negligible benefit: hi changing between reads is an extremely rare
> > > event. Optimizing away the retry loop for such a rare case provides no
> > > meaningful performance gain. And if hi never stabilizes, that
> > > indicates a hardware failure — in which case hanging in the retry loop
> > > is actually the more appropriate behavior, as it makes the failure
> > > visible rather than silently producing garbage values.
> > >
> > > The high-low-high do-while retry strategy exists precisely to handle
> > > these cases correctly. I don't think this proposed sequence is a valid
> > > replacement.
> > >
> >
> > The point is that if the value is an incrementing counter (of some form)
> > then the value is stale by the time the reading sequence completes.
> > So all the code can be assumed to do is return a value the counter had
> > sometime between when the code started and when it finished.
> > If hi changes then hi+1:0 must have happened while the code was running
> > so it is a safe return value.
> You're right — (hi + 1):0 is enough for hi-lo-hi. Thank you for
> sticking to your point; it helped me think more carefully and
> understand the subtlety.
Don't worry, I'll have written the loop in the past.
Probably best is read old_hi-lo-hi then if (hi != old_hi) lo = 0
David
>
> >
> > It is likely that the reads are also much slower than memory reads.
> > If hi changes relatively infrequently (compared to the number of reads)
> > it may be worth saving the previously read value and avoiding the second
> > read of hi if it is the same as the previous read hi and lo has got larger.
>
>
> --
> Best Regards
> Guo Ren
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
2026-06-15 12:38 ` Guo Ren
2026-06-15 13:23 ` [External] " Zhanpeng Zhang
2026-06-16 10:36 ` David Laight
@ 2026-06-18 3:20 ` Vivian Wang
2026-06-18 3:45 ` Guo Ren
2 siblings, 1 reply; 30+ messages in thread
From: Vivian Wang @ 2026-06-18 3:20 UTC (permalink / raw)
To: Guo Ren, zhangzhanpeng.jasper
Cc: alex, aou, cuiyunhui, iommu, joro, linux-kernel, linux-riscv,
luxu.kernel, palmer, pjw, robin.murphy, tjeznach, will, yuanzhu
On 6/15/26 20:38, Guo Ren wrote:
> Hi Zhanpeng Zhang,
>
> I noticed you posted a similar fix recently. However, I had already
> submitted a similar solution back in September 2025 [1]. It would be
> great if you could review it. A few concerns with the current patch:
>
> 1. Using spin_lock_irqsave in such a small semantic structure is
> unnecessary. IRQ protection should be provided by the higher-level
> IOMMU driver interfaces. Many existing call sites already handle IRQ
> disabling, so adding it here feels redundant and adds avoidable
> overhead.
>
> 2. More critically, the RISCV_IOMMU_32BIT_ACCESS Kconfig option is
> problematic. According to the RISC-V IOMMU specification (Software
> Guidelines, “Reading and writing IOMMU registers”):
>
>> Registers that are 64-bit wide may be accessed using either a 32-bit
>> or a 64-bit access.
> This clearly requires that any hardware supporting 64-bit MMIO access
> must also support 32-bit MMIO access. Therefore, the IOMMU driver should
> be built on a 32-bit access base for maximum hardware compatibility.
I agree that the driver should be build with 32-bit accesses to support
these hardware. However there's one minor thing that I want to propose
regarding this, for the sake of clarity:
RISC-V IOMMU implementations that do not support 64-bit accesses are not
fully compliant with the RISC-V IOMMU specification and should not use
the standard RISC-V identifiers, namely:
- Devicetree compatible riscv,iommu
- ACPI HID RSCV0004
This, in my opinion, is not only the right thing to do (not claiming to
be standard hardware without actually being standard hardware), but also
saves a lot of trouble for operating system developers (yes, there are
RISC-V operating systems other than Linux out there), since invalid IO
accesses usually manifest as mysterious access faults (that would
usually suggest an incorrect IOMMU address), or worse, system hangs.
I would appreciate if the hardware vendors shipping 32-bit-access-only
IOMMUs would consider this.
Vivian "dramforever" Wang
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
2026-06-17 21:54 ` David Laight
@ 2026-06-18 3:36 ` Guo Ren
0 siblings, 0 replies; 30+ messages in thread
From: Guo Ren @ 2026-06-18 3:36 UTC (permalink / raw)
To: David Laight
Cc: zhangzhanpeng.jasper, alex, aou, cuiyunhui, iommu, joro,
linux-kernel, linux-riscv, luxu.kernel, palmer, pjw, robin.murphy,
tjeznach, will, yuanzhu
On Thu, Jun 18, 2026 at 5:54 AM David Laight
<david.laight.linux@gmail.com> wrote:
>
> On Thu, 18 Jun 2026 00:24:12 +0800
> Guo Ren <guoren@kernel.org> wrote:
>
> > On Wed, Jun 17, 2026 at 3:51 AM David Laight
> > <david.laight.linux@gmail.com> wrote:
> > >
> > > On Tue, 16 Jun 2026 23:47:05 +0800
> > > Guo Ren <guoren@kernel.org> wrote:
> > >
> > > > On Tue, Jun 16, 2026 at 6:36 PM David Laight
> > > > <david.laight.linux@gmail.com> wrote:
> > > > >
> > > > > On Mon, 15 Jun 2026 12:38:17 +0000
> > > > > Guo Ren <guoren@kernel.org> wrote:
> > > > >
> > > > > > Hi Zhanpeng Zhang,
> > > > > ..
> > > > > > 3. Only performance-monitoring counters require 64-bit IO access or the
> > > > > > high-low-high do-while retry strategy. For ordinary status and control
> > > > > > MMIO registers, a single read is sufficient.
> > > > >
> > > > > Actually this sequence should be enough for a counter:
> > > > > hi = read_hi();
> > > > > lo = read_lo();
> > > > > if (hi != read_hi()) {
> > > > > // Pick a value that happened while doing the reads.
> > > > > hi++;
> > > > > lo = 0;
> > > > > }
> > > > This is not a free optimization — it does not preserve the same
> > > > semantics as an atomic 64-bit read. There are at least two correctness
> > > > issues:
> > > >
> > > > 1. Loss of precision: If hi changed during the read, setting lo = 0
> > > > discards the actual lo value. The correct approach is to re-read lo
> > > > after detecting the change, not fabricate a value.
> > > >
> > > > 2. Multiple overflows: This assumes at most one overflow occurs
> > > > between reads. If two overflows happen (e.g., due to interrupt
> > > > injection), hi++ will produce an incorrect result, silently corrupting
> > > > the counter value.
> > > >
> > > > Negligible benefit: hi changing between reads is an extremely rare
> > > > event. Optimizing away the retry loop for such a rare case provides no
> > > > meaningful performance gain. And if hi never stabilizes, that
> > > > indicates a hardware failure — in which case hanging in the retry loop
> > > > is actually the more appropriate behavior, as it makes the failure
> > > > visible rather than silently producing garbage values.
> > > >
> > > > The high-low-high do-while retry strategy exists precisely to handle
> > > > these cases correctly. I don't think this proposed sequence is a valid
> > > > replacement.
> > > >
> > >
> > > The point is that if the value is an incrementing counter (of some form)
> > > then the value is stale by the time the reading sequence completes.
> > > So all the code can be assumed to do is return a value the counter had
> > > sometime between when the code started and when it finished.
> > > If hi changes then hi+1:0 must have happened while the code was running
> > > so it is a safe return value.
> > You're right — (hi + 1):0 is enough for hi-lo-hi. Thank you for
> > sticking to your point; it helped me think more carefully and
> > understand the subtlety.
>
> Don't worry, I'll have written the loop in the past.
> Probably best is read old_hi-lo-hi then if (hi != old_hi) lo = 0
This is more conservative than (hi + 1):0.
--
Best Regards
Guo Ren
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
2026-06-18 3:20 ` Vivian Wang
@ 2026-06-18 3:45 ` Guo Ren
2026-06-18 7:33 ` Vivian Wang
0 siblings, 1 reply; 30+ messages in thread
From: Guo Ren @ 2026-06-18 3:45 UTC (permalink / raw)
To: Vivian Wang
Cc: zhangzhanpeng.jasper, alex, aou, cuiyunhui, iommu, joro,
linux-kernel, linux-riscv, luxu.kernel, palmer, pjw, robin.murphy,
tjeznach, will, yuanzhu
On Thu, Jun 18, 2026 at 11:20 AM Vivian Wang <wangruikang@iscas.ac.cn> wrote:
>
> On 6/15/26 20:38, Guo Ren wrote:
> > Hi Zhanpeng Zhang,
> >
> > I noticed you posted a similar fix recently. However, I had already
> > submitted a similar solution back in September 2025 [1]. It would be
> > great if you could review it. A few concerns with the current patch:
> >
> > 1. Using spin_lock_irqsave in such a small semantic structure is
> > unnecessary. IRQ protection should be provided by the higher-level
> > IOMMU driver interfaces. Many existing call sites already handle IRQ
> > disabling, so adding it here feels redundant and adds avoidable
> > overhead.
> >
> > 2. More critically, the RISCV_IOMMU_32BIT_ACCESS Kconfig option is
> > problematic. According to the RISC-V IOMMU specification (Software
> > Guidelines, “Reading and writing IOMMU registers”):
> >
> >> Registers that are 64-bit wide may be accessed using either a 32-bit
> >> or a 64-bit access.
> > This clearly requires that any hardware supporting 64-bit MMIO access
> > must also support 32-bit MMIO access. Therefore, the IOMMU driver should
> > be built on a 32-bit access base for maximum hardware compatibility.
>
> I agree that the driver should be build with 32-bit accesses to support
> these hardware. However there's one minor thing that I want to propose
> regarding this, for the sake of clarity:
>
> RISC-V IOMMU implementations that do not support 64-bit accesses are not
> fully compliant with the RISC-V IOMMU specification and should not use
> the standard RISC-V identifiers, namely:
>
> - Devicetree compatible riscv,iommu
> - ACPI HID RSCV0004
>
> This, in my opinion, is not only the right thing to do (not claiming to
> be standard hardware without actually being standard hardware), but also
> saves a lot of trouble for operating system developers (yes, there are
> RISC-V operating systems other than Linux out there), since invalid IO
> accesses usually manifest as mysterious access faults (that would
> usually suggest an incorrect IOMMU address), or worse, system hangs.
>
> I would appreciate if the hardware vendors shipping 32-bit-access-only
> IOMMUs would consider this.
>
> Vivian "dramforever" Wang
>
32-bit MMIO access is explicitly supported by the RISC-V IOMMU
specification and is a valid choice (64-bit MMIO access is optional).
64-bit MMIO access is not "free" — it consumes additional interconnect
hardware resources.
Could you elaborate on the concrete benefit of using 64-bit MMIO
access in this driver, for these non-PMU registers? A clear
justification would help evaluate whether the trade-off is worthwhile.
--
Best Regards
Guo Ren
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
2026-06-18 3:45 ` Guo Ren
@ 2026-06-18 7:33 ` Vivian Wang
2026-06-18 9:51 ` Guo Ren
0 siblings, 1 reply; 30+ messages in thread
From: Vivian Wang @ 2026-06-18 7:33 UTC (permalink / raw)
To: Guo Ren
Cc: zhangzhanpeng.jasper, alex, aou, cuiyunhui, iommu, joro,
linux-kernel, linux-riscv, luxu.kernel, palmer, pjw, robin.murphy,
tjeznach, will, yuanzhu
On 6/18/26 11:45, Guo Ren wrote:
> On Thu, Jun 18, 2026 at 11:20 AM Vivian Wang <wangruikang@iscas.ac.cn> wrote:
>> On 6/15/26 20:38, Guo Ren wrote:
>>> Hi Zhanpeng Zhang,
>>>
>>> I noticed you posted a similar fix recently. However, I had already
>>> submitted a similar solution back in September 2025 [1]. It would be
>>> great if you could review it. A few concerns with the current patch:
>>>
>>> 1. Using spin_lock_irqsave in such a small semantic structure is
>>> unnecessary. IRQ protection should be provided by the higher-level
>>> IOMMU driver interfaces. Many existing call sites already handle IRQ
>>> disabling, so adding it here feels redundant and adds avoidable
>>> overhead.
>>>
>>> 2. More critically, the RISCV_IOMMU_32BIT_ACCESS Kconfig option is
>>> problematic. According to the RISC-V IOMMU specification (Software
>>> Guidelines, “Reading and writing IOMMU registers”):
>>>
>>>> Registers that are 64-bit wide may be accessed using either a 32-bit
>>>> or a 64-bit access.
>>> This clearly requires that any hardware supporting 64-bit MMIO access
>>> must also support 32-bit MMIO access. Therefore, the IOMMU driver should
>>> be built on a 32-bit access base for maximum hardware compatibility.
>> I agree that the driver should be build with 32-bit accesses to support
>> these hardware. However there's one minor thing that I want to propose
>> regarding this, for the sake of clarity:
>>
>> RISC-V IOMMU implementations that do not support 64-bit accesses are not
>> fully compliant with the RISC-V IOMMU specification and should not use
>> the standard RISC-V identifiers, namely:
>>
>> - Devicetree compatible riscv,iommu
>> - ACPI HID RSCV0004
>>
>> This, in my opinion, is not only the right thing to do (not claiming to
>> be standard hardware without actually being standard hardware), but also
>> saves a lot of trouble for operating system developers (yes, there are
>> RISC-V operating systems other than Linux out there), since invalid IO
>> accesses usually manifest as mysterious access faults (that would
>> usually suggest an incorrect IOMMU address), or worse, system hangs.
>>
>> I would appreciate if the hardware vendors shipping 32-bit-access-only
>> IOMMUs would consider this.
>>
>> Vivian "dramforever" Wang
>>
> 32-bit MMIO access is explicitly supported by the RISC-V IOMMU
> specification and is a valid choice (64-bit MMIO access is optional).
Hmm... I think it's optional in software but not optional in hardware,
but the specs are not super clear on this. I've opened a GitHub issue to
ask:
https://github.com/riscv-non-isa/riscv-iommu/issues/765
> 64-bit MMIO access is not "free" — it consumes additional interconnect
> hardware resources.
>
> Could you elaborate on the concrete benefit of using 64-bit MMIO
> access in this driver, for these non-PMU registers? A clear
> justification would help evaluate whether the trade-off is worthwhile.
>
>
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
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
0 siblings, 2 replies; 30+ messages in thread
From: Guo Ren @ 2026-06-18 9:51 UTC (permalink / raw)
To: Vivian Wang, zhangzhanpeng.jasper
Cc: alex, aou, cuiyunhui, iommu, joro, linux-kernel, linux-riscv,
luxu.kernel, palmer, pjw, robin.murphy, tjeznach, will, yuanzhu
Hi Vivian,
As noted in the RISC-V IOMMU Specification, Chapter 6:
> Whether an 8-byte access to an IOMMU register is single-copy atomic is UNSPECIFIED, and such an access may appear, internally to the IOMMU, as if two separate 4-byte accesses — first to the high half and second to the low half — were performed.
Therefore, the atomicity of 64-bit MMIO accesses is UNSPECIFIED and
not clearly defined in the current ratified RISC-V IOMMU
specification. To handle this correctly, the Linux RISC-V IOMMU driver
should fall back to 32-bit MMIO accesses when reading 64-bit registers
(e.g., performance counters). The behavior of 32-bit MMIO accesses is
more precisely defined in the RISC-V IOMMU specification.
Thus, many hardware vendors implement 32-bit MMIO (rather than 64-bit
MMIO) based on the current ratified RISC-V IOMMU specification, and
this driver does not appear to benefit from 64-bit MMIO access either.
Performance is fundamentally constrained by bus latency; assuming that
simply reducing the number of accesses will improve performance is an
oversimplification that ignores the underlying hardware
characteristics.
Hi Zhang,
The hardware targeted by the 32-bit MMIO access in your patch is
precisely the kind that deserves the official ACPI HID RSCV0004 and
Devicetree compatible string (riscv,iommu). It is rather the hardware
that supports only 64-bit MMIO access — whose atomicity is explicitly
left as UNSPECIFIED by the RISC-V IOMMU specification — that should be
relegated to a non-standard ACPI ID. That is what truly constitutes
poor hardware design.
I will consistently support your position of adopting 32-bit MMIO
access in this patch, and will advocate for making it the default
behavior in the Linux RISC-V IOMMU driver, as it better aligns with
the intent of the RISC-V IOMMU specification.
--
Best Regards
Guo Ren
On Thu, Jun 18, 2026 at 3:33 PM Vivian Wang <wangruikang@iscas.ac.cn> wrote:
>
> On 6/18/26 11:45, Guo Ren wrote:
> > On Thu, Jun 18, 2026 at 11:20 AM Vivian Wang <wangruikang@iscas.ac.cn> wrote:
> >> On 6/15/26 20:38, Guo Ren wrote:
> >>> Hi Zhanpeng Zhang,
> >>>
> >>> I noticed you posted a similar fix recently. However, I had already
> >>> submitted a similar solution back in September 2025 [1]. It would be
> >>> great if you could review it. A few concerns with the current patch:
> >>>
> >>> 1. Using spin_lock_irqsave in such a small semantic structure is
> >>> unnecessary. IRQ protection should be provided by the higher-level
> >>> IOMMU driver interfaces. Many existing call sites already handle IRQ
> >>> disabling, so adding it here feels redundant and adds avoidable
> >>> overhead.
> >>>
> >>> 2. More critically, the RISCV_IOMMU_32BIT_ACCESS Kconfig option is
> >>> problematic. According to the RISC-V IOMMU specification (Software
> >>> Guidelines, “Reading and writing IOMMU registers”):
> >>>
> >>>> Registers that are 64-bit wide may be accessed using either a 32-bit
> >>>> or a 64-bit access.
> >>> This clearly requires that any hardware supporting 64-bit MMIO access
> >>> must also support 32-bit MMIO access. Therefore, the IOMMU driver should
> >>> be built on a 32-bit access base for maximum hardware compatibility.
> >> I agree that the driver should be build with 32-bit accesses to support
> >> these hardware. However there's one minor thing that I want to propose
> >> regarding this, for the sake of clarity:
> >>
> >> RISC-V IOMMU implementations that do not support 64-bit accesses are not
> >> fully compliant with the RISC-V IOMMU specification and should not use
> >> the standard RISC-V identifiers, namely:
> >>
> >> - Devicetree compatible riscv,iommu
> >> - ACPI HID RSCV0004
> >>
> >> This, in my opinion, is not only the right thing to do (not claiming to
> >> be standard hardware without actually being standard hardware), but also
> >> saves a lot of trouble for operating system developers (yes, there are
> >> RISC-V operating systems other than Linux out there), since invalid IO
> >> accesses usually manifest as mysterious access faults (that would
> >> usually suggest an incorrect IOMMU address), or worse, system hangs.
> >>
> >> I would appreciate if the hardware vendors shipping 32-bit-access-only
> >> IOMMUs would consider this.
> >>
> >> Vivian "dramforever" Wang
> >>
> > 32-bit MMIO access is explicitly supported by the RISC-V IOMMU
> > specification and is a valid choice (64-bit MMIO access is optional).
>
> Hmm... I think it's optional in software but not optional in hardware,
> but the specs are not super clear on this. I've opened a GitHub issue to
> ask:
>
> https://github.com/riscv-non-isa/riscv-iommu/issues/765
>
> > 64-bit MMIO access is not "free" — it consumes additional interconnect
> > hardware resources.
> >
> > Could you elaborate on the concrete benefit of using 64-bit MMIO
> > access in this driver, for these non-PMU registers? A clear
> > justification would help evaluate whether the trade-off is worthwhile.
> >
> >
>
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
2026-06-18 9:51 ` Guo Ren
@ 2026-06-18 10:01 ` Vivian Wang
2026-06-18 13:36 ` David Laight
1 sibling, 0 replies; 30+ messages in thread
From: Vivian Wang @ 2026-06-18 10:01 UTC (permalink / raw)
To: Guo Ren, zhangzhanpeng.jasper
Cc: alex, aou, cuiyunhui, iommu, joro, linux-kernel, linux-riscv,
luxu.kernel, palmer, pjw, robin.murphy, tjeznach, will, yuanzhu
On 6/18/26 17:51, Guo Ren wrote:
> Hi Vivian,
>
> As noted in the RISC-V IOMMU Specification, Chapter 6:
>> Whether an 8-byte access to an IOMMU register is single-copy atomic is UNSPECIFIED, and such an access may appear, internally to the IOMMU, as if two separate 4-byte accesses — first to the high half and second to the low half — were performed.
> Therefore, the atomicity of 64-bit MMIO accesses is UNSPECIFIED and
> not clearly defined in the current ratified RISC-V IOMMU
> specification. To handle this correctly, the Linux RISC-V IOMMU driver
> should fall back to 32-bit MMIO accesses when reading 64-bit registers
> (e.g., performance counters). The behavior of 32-bit MMIO accesses is
> more precisely defined in the RISC-V IOMMU specification.
>
> Thus, many hardware vendors implement 32-bit MMIO (rather than 64-bit
> MMIO) based on the current ratified RISC-V IOMMU specification, and
> this driver does not appear to benefit from 64-bit MMIO access either.
> Performance is fundamentally constrained by bus latency; assuming that
> simply reducing the number of accesses will improve performance is an
> oversimplification that ignores the underlying hardware
> characteristics.
Just as a clarification, I had never said that the driver *should* use
64-bit accesses. In fact, I said:
I agree that the driver should be build with 32-bit accesses to support
these hardware.
Perhaps I wasn't clear enough. I meant that I agree that the RISC-V
IOMMU driver should use 32-bit accesses. At *no* point had I claimed
that 64-bit accesses are better.
> Hi Zhang,
>
> The hardware targeted by the 32-bit MMIO access in your patch is
> precisely the kind that deserves the official ACPI HID RSCV0004 and
> Devicetree compatible string (riscv,iommu). It is rather the hardware
> that supports only 64-bit MMIO access — whose atomicity is explicitly
> [...]
IOMMU Hardware that supports only 64-bit MMIO access for 8-byte
registers has never come up in this discussion. If they ever show up
we'll talk about them then.
Vivian "dramforever" Wang
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
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
1 sibling, 1 reply; 30+ messages in thread
From: David Laight @ 2026-06-18 13:36 UTC (permalink / raw)
To: Guo Ren
Cc: Vivian Wang, zhangzhanpeng.jasper, alex, aou, cuiyunhui, iommu,
joro, linux-kernel, linux-riscv, luxu.kernel, palmer, pjw,
robin.murphy, tjeznach, will, yuanzhu
On Thu, 18 Jun 2026 17:51:34 +0800
Guo Ren <guoren@kernel.org> wrote:
> Hi Vivian,
>
> As noted in the RISC-V IOMMU Specification, Chapter 6:
> > Whether an 8-byte access to an IOMMU register is single-copy atomic is UNSPECIFIED, and such an access may appear, internally to the IOMMU, as if two separate 4-byte accesses — first to the high half and second to the low half — were performed.
>
> Therefore, the atomicity of 64-bit MMIO accesses is UNSPECIFIED and
> not clearly defined in the current ratified RISC-V IOMMU
> specification. To handle this correctly, the Linux RISC-V IOMMU driver
> should fall back to 32-bit MMIO accesses when reading 64-bit registers
> (e.g., performance counters). The behavior of 32-bit MMIO accesses is
> more precisely defined in the RISC-V IOMMU specification.
>
> Thus, many hardware vendors implement 32-bit MMIO (rather than 64-bit
> MMIO) based on the current ratified RISC-V IOMMU specification, and
> this driver does not appear to benefit from 64-bit MMIO access either.
> Performance is fundamentally constrained by bus latency; assuming that
> simply reducing the number of accesses will improve performance is an
> oversimplification that ignores the underlying hardware
> characteristics.
If the bus latency is significant it is almost certainly worth using
memory accesses to avoid re-reading the hi register.
Something like this might work:
static volatile u32 hi_prev, lo_prev;
u32 hi = read_reg_hi();
u32 lo = read_reg_lo();
if (lo <= lo_prev || hi != hi_prev) {
u32 hi_tmp = read_reg_hi;
if (hi_tmp != hi) {
hi = hi_tmp;
lo = 0;
}
lo_prev = ~0u;
hi_prev = hi;
}
lo_prev = lo;
return (u64)hi << 32 | lo;
It shouldn't need any locking but the accesses do need to be ordered.
David
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
2026-06-18 13:36 ` David Laight
@ 2026-06-18 16:40 ` Guo Ren
2026-06-23 9:20 ` Zong Li
2026-06-26 9:18 ` Zhanpeng Zhang
0 siblings, 2 replies; 30+ messages in thread
From: Guo Ren @ 2026-06-18 16:40 UTC (permalink / raw)
To: David Laight
Cc: Vivian Wang, zhangzhanpeng.jasper, alex, aou, cuiyunhui, iommu,
joro, linux-kernel, linux-riscv, luxu.kernel, palmer, pjw,
robin.murphy, tjeznach, will, yuanzhu
On Thu, Jun 18, 2026 at 9:36 PM David Laight
<david.laight.linux@gmail.com> wrote:
>
> On Thu, 18 Jun 2026 17:51:34 +0800
> Guo Ren <guoren@kernel.org> wrote:
>
> > Hi Vivian,
> >
> > As noted in the RISC-V IOMMU Specification, Chapter 6:
> > > Whether an 8-byte access to an IOMMU register is single-copy atomic is UNSPECIFIED, and such an access may appear, internally to the IOMMU, as if two separate 4-byte accesses — first to the high half and second to the low half — were performed.
> >
> > Therefore, the atomicity of 64-bit MMIO accesses is UNSPECIFIED and
> > not clearly defined in the current ratified RISC-V IOMMU
> > specification. To handle this correctly, the Linux RISC-V IOMMU driver
> > should fall back to 32-bit MMIO accesses when reading 64-bit registers
> > (e.g., performance counters). The behavior of 32-bit MMIO accesses is
> > more precisely defined in the RISC-V IOMMU specification.
> >
> > Thus, many hardware vendors implement 32-bit MMIO (rather than 64-bit
> > MMIO) based on the current ratified RISC-V IOMMU specification, and
> > this driver does not appear to benefit from 64-bit MMIO access either.
> > Performance is fundamentally constrained by bus latency; assuming that
> > simply reducing the number of accesses will improve performance is an
> > oversimplification that ignores the underlying hardware
> > characteristics.
>
> If the bus latency is significant it is almost certainly worth using
> memory accesses to avoid re-reading the hi register.
>
> Something like this might work:
>
> static volatile u32 hi_prev, lo_prev;
>
> u32 hi = read_reg_hi();
> u32 lo = read_reg_lo();
>
> if (lo <= lo_prev || hi != hi_prev) {
> u32 hi_tmp = read_reg_hi;
> if (hi_tmp != hi) {
> hi = hi_tmp;
> lo = 0;
> }
> lo_prev = ~0u;
> hi_prev = hi;
> }
> lo_prev = lo;
> return (u64)hi << 32 | lo;
>
> It shouldn't need any locking but the accesses do need to be ordered.
Thank you for the suggestion. However, I believe this feedback is more
relevant to the RISC-V IOMMU HPM patchset [1], as no counter registers
are involved in the current patchset. That said, the idea of improving
the hi-lo-hi slow-path mechanism to better handle high-latency
hardware scenarios is well taken and worth discussing in the
appropriate thread.
[1]: https://lore.kernel.org/linux-riscv/20260208063848.3547817-2-zong.li@sifive.com/
P.S. The hardware I have at hand exhibits very low interconnect
latency. And I have never observed the slow path where hi_tmp != hi
being triggered — my approach was to remove the retry mechanism
directly in 32-bit mmio mode and run stress tests to check whether
perf stat produced incorrect results. That said, I may have simply
been lucky instead of hw guarantee.
--
Best Regards
Guo Ren
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
2026-06-18 16:40 ` Guo Ren
@ 2026-06-23 9:20 ` Zong Li
2026-06-28 8:20 ` Guo Ren
2026-06-26 9:18 ` Zhanpeng Zhang
1 sibling, 1 reply; 30+ messages in thread
From: Zong Li @ 2026-06-23 9:20 UTC (permalink / raw)
To: Guo Ren
Cc: David Laight, Vivian Wang, zhangzhanpeng.jasper, alex, aou,
cuiyunhui, iommu, joro, linux-kernel, linux-riscv, luxu.kernel,
palmer, pjw, robin.murphy, tjeznach, will, yuanzhu
On Fri, Jun 19, 2026 at 1:14 AM Guo Ren <guoren@kernel.org> wrote:
>
> On Thu, Jun 18, 2026 at 9:36 PM David Laight
> <david.laight.linux@gmail.com> wrote:
> >
> > On Thu, 18 Jun 2026 17:51:34 +0800
> > Guo Ren <guoren@kernel.org> wrote:
> >
> > > Hi Vivian,
> > >
> > > As noted in the RISC-V IOMMU Specification, Chapter 6:
> > > > Whether an 8-byte access to an IOMMU register is single-copy atomic is UNSPECIFIED, and such an access may appear, internally to the IOMMU, as if two separate 4-byte accesses — first to the high half and second to the low half — were performed.
> > >
> > > Therefore, the atomicity of 64-bit MMIO accesses is UNSPECIFIED and
> > > not clearly defined in the current ratified RISC-V IOMMU
> > > specification. To handle this correctly, the Linux RISC-V IOMMU driver
> > > should fall back to 32-bit MMIO accesses when reading 64-bit registers
> > > (e.g., performance counters). The behavior of 32-bit MMIO accesses is
> > > more precisely defined in the RISC-V IOMMU specification.
> > >
> > > Thus, many hardware vendors implement 32-bit MMIO (rather than 64-bit
> > > MMIO) based on the current ratified RISC-V IOMMU specification, and
> > > this driver does not appear to benefit from 64-bit MMIO access either.
> > > Performance is fundamentally constrained by bus latency; assuming that
> > > simply reducing the number of accesses will improve performance is an
> > > oversimplification that ignores the underlying hardware
> > > characteristics.
> >
> > If the bus latency is significant it is almost certainly worth using
> > memory accesses to avoid re-reading the hi register.
> >
> > Something like this might work:
> >
> > static volatile u32 hi_prev, lo_prev;
> >
> > u32 hi = read_reg_hi();
> > u32 lo = read_reg_lo();
> >
> > if (lo <= lo_prev || hi != hi_prev) {
> > u32 hi_tmp = read_reg_hi;
> > if (hi_tmp != hi) {
> > hi = hi_tmp;
> > lo = 0;
> > }
> > lo_prev = ~0u;
> > hi_prev = hi;
> > }
> > lo_prev = lo;
> > return (u64)hi << 32 | lo;
> >
> > It shouldn't need any locking but the accesses do need to be ordered.
> Thank you for the suggestion. However, I believe this feedback is more
> relevant to the RISC-V IOMMU HPM patchset [1], as no counter registers
> are involved in the current patchset. That said, the idea of improving
> the hi-lo-hi slow-path mechanism to better handle high-latency
> hardware scenarios is well taken and worth discussing in the
> appropriate thread.
> [1]: https://lore.kernel.org/linux-riscv/20260208063848.3547817-2-zong.li@sifive.com/
>
> P.S. The hardware I have at hand exhibits very low interconnect
> latency. And I have never observed the slow path where hi_tmp != hi
> being triggered — my approach was to remove the retry mechanism
> directly in 32-bit mmio mode and run stress tests to check whether
> perf stat produced incorrect results. That said, I may have simply
> been lucky instead of hw guarantee.
>
Hi everyone,
Thank you for adding me to this discussion. I took some time to read
the previous messages.
Regarding the GitHub issue mentioned by Vivian, I noticed someone
pointed out that the hardware must support 64-bit access.
https://github.com/riscv-non-isa/riscv-iommu/issues/765#issuecomment-4742941894
I would like to confirm if that is correct. If so, should we update
the spec? And does this mean we do not need to modify the driver?
Thanks
> --
> Best Regards
> Guo Ren
>
> _______________________________________________
> linux-riscv mailing list
> linux-riscv@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-riscv
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
2026-06-18 16:40 ` Guo Ren
2026-06-23 9:20 ` Zong Li
@ 2026-06-26 9:18 ` Zhanpeng Zhang
1 sibling, 0 replies; 30+ messages in thread
From: Zhanpeng Zhang @ 2026-06-26 9:18 UTC (permalink / raw)
To: Guo Ren, Vivian Wang
Cc: David Laight, alex, aou, cuiyunhui, iommu, joro, linux-kernel,
linux-riscv, luxu.kernel, palmer, pjw, robin.murphy, tjeznach,
will, yuanzhu, zong.li@sifive.com
Hi Vivian, Guo Ren,
Thanks for the discussion. I just caught up with the thread and the
GitHub issue [1].
I think we probably do not need to spend too much time discussing the exact
meaning of RSCV0004 around 32-bit vs 64-bit MMIO access. At least from my
side, I do not see much practical benefit in splitting the standard HID for
this distinction.
The original problem I want to solve is simple: Linux should have a compatible
and maintainable way to support IOMMUs that need 32-bit MMIO accesses for
64-bit registers, instead of taking an access fault that leads to panic.
Ideally, one generic kernel should support both access sequences without a
build-time option.
Would it be reasonable to keep RSCV0004 / riscv,iommu as the common device
identifier, and describe the required register access width as a runtime
firmware property instead? For ACPI, this might be an _DSD property on the
IOMMU device; for devicetree, it could be a matching DT property. The driver
could then check it during enumeration and select the appropriate register
accessors.
This avoids redefining the ACPI HID or compatible string, keeps one generic
kernel image, and makes the 32-bit MMIO fallback explicit in firmware. My goal
is just to implement the spec wording that "Registers that are 64-bit wide may
be accessed using either a 32-bit or a 64-bit access." in a lightweight way
that is acceptable for the Linux driver.
[1] https://github.com/riscv-non-isa/riscv-iommu/issues/765#issuecomment-4742941894
Best regards,
Zhanpeng
> From: "Guo Ren"<guoren@kernel.org>
> Date: Fri, Jun 19, 2026, 00:41
> Subject: [External] Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
> To: "David Laight"<david.laight.linux@gmail.com>
> Cc: "Vivian Wang"<wangruikang@iscas.ac.cn>, <zhangzhanpeng.jasper@bytedance.com>, <alex@ghiti.fr>, <aou@eecs.berkeley.edu>, <cuiyunhui@bytedance.com>, <iommu@lists.linux.dev>, <joro@8bytes.org>, <linux-kernel@vger.kernel.org>, <linux-riscv@lists.infradead.org>, <luxu.kernel@bytedance.com>, <palmer@dabbelt.com>, <pjw@kernel.org>, <robin.murphy@arm.com>, <tjeznach@rivosinc.com>, <will@kernel.org>, <yuanzhu@bytedance.com>
> On Thu, Jun 18, 2026 at 9:36 PM David Laight
> <david.laight.linux@gmail.com> wrote:
> >
> > On Thu, 18 Jun 2026 17:51:34 +0800
> > Guo Ren <guoren@kernel.org> wrote:
> >
> > > Hi Vivian,
> > >
> > > As noted in the RISC-V IOMMU Specification, Chapter 6:
> > > > Whether an 8-byte access to an IOMMU register is single-copy atomic is UNSPECIFIED, and such an access may appear, internally to the IOMMU, as if two separate 4-byte accesses — first to the high half and second to the low half — were performed.
> > >
> > > Therefore, the atomicity of 64-bit MMIO accesses is UNSPECIFIED and
> > > not clearly defined in the current ratified RISC-V IOMMU
> > > specification. To handle this correctly, the Linux RISC-V IOMMU driver
> > > should fall back to 32-bit MMIO accesses when reading 64-bit registers
> > > (e.g., performance counters). The behavior of 32-bit MMIO accesses is
> > > more precisely defined in the RISC-V IOMMU specification.
> > >
> > > Thus, many hardware vendors implement 32-bit MMIO (rather than 64-bit
> > > MMIO) based on the current ratified RISC-V IOMMU specification, and
> > > this driver does not appear to benefit from 64-bit MMIO access either.
> > > Performance is fundamentally constrained by bus latency; assuming that
> > > simply reducing the number of accesses will improve performance is an
> > > oversimplification that ignores the underlying hardware
> > > characteristics.
> >
> > If the bus latency is significant it is almost certainly worth using
> > memory accesses to avoid re-reading the hi register.
> >
> > Something like this might work:
> >
> > static volatile u32 hi_prev, lo_prev;
> >
> > u32 hi = read_reg_hi();
> > u32 lo = read_reg_lo();
> >
> > if (lo <= lo_prev || hi != hi_prev) {
> > u32 hi_tmp = read_reg_hi;
> > if (hi_tmp != hi) {
> > hi = hi_tmp;
> > lo = 0;
> > }
> > lo_prev = ~0u;
> > hi_prev = hi;
> > }
> > lo_prev = lo;
> > return (u64)hi << 32 | lo;
> >
> > It shouldn't need any locking but the accesses do need to be ordered.
> Thank you for the suggestion. However, I believe this feedback is more
> relevant to the RISC-V IOMMU HPM patchset [1], as no counter registers
> are involved in the current patchset. That said, the idea of improving
> the hi-lo-hi slow-path mechanism to better handle high-latency
> hardware scenarios is well taken and worth discussing in the
> appropriate thread.
> [1]: https://lore.kernel.org/linux-riscv/20260208063848.3547817-2-zong.li@sifive.com/
>
> P.S. The hardware I have at hand exhibits very low interconnect
> latency. And I have never observed the slow path where hi_tmp != hi
> being triggered — my approach was to remove the retry mechanism
> directly in 32-bit mmio mode and run stress tests to check whether
> perf stat produced incorrect results. That said, I may have simply
> been lucky instead of hw guarantee.
>
> --
> Best Regards
> Guo Ren
>
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
2026-06-23 9:20 ` Zong Li
@ 2026-06-28 8:20 ` Guo Ren
2026-06-29 1:15 ` Zong Li
0 siblings, 1 reply; 30+ messages in thread
From: Guo Ren @ 2026-06-28 8:20 UTC (permalink / raw)
To: Zong Li
Cc: David Laight, Vivian Wang, zhangzhanpeng.jasper, alex, aou,
cuiyunhui, iommu, joro, linux-kernel, linux-riscv, luxu.kernel,
palmer, pjw, robin.murphy, tjeznach, will, yuanzhu
Hi Zong Li,
On Tue, Jun 23, 2026 at 5:21 PM Zong Li <zong.li@sifive.com> wrote:
>
> On Fri, Jun 19, 2026 at 1:14 AM Guo Ren <guoren@kernel.org> wrote:
> >
> > On Thu, Jun 18, 2026 at 9:36 PM David Laight
> > <david.laight.linux@gmail.com> wrote:
> > >
> > > On Thu, 18 Jun 2026 17:51:34 +0800
> > > Guo Ren <guoren@kernel.org> wrote:
> > >
> > > > Hi Vivian,
> > > >
> > > > As noted in the RISC-V IOMMU Specification, Chapter 6:
> > > > > Whether an 8-byte access to an IOMMU register is single-copy atomic is UNSPECIFIED, and such an access may appear, internally to the IOMMU, as if two separate 4-byte accesses — first to the high half and second to the low half — were performed.
> > > >
> > > > Therefore, the atomicity of 64-bit MMIO accesses is UNSPECIFIED and
> > > > not clearly defined in the current ratified RISC-V IOMMU
> > > > specification. To handle this correctly, the Linux RISC-V IOMMU driver
> > > > should fall back to 32-bit MMIO accesses when reading 64-bit registers
> > > > (e.g., performance counters). The behavior of 32-bit MMIO accesses is
> > > > more precisely defined in the RISC-V IOMMU specification.
> > > >
> > > > Thus, many hardware vendors implement 32-bit MMIO (rather than 64-bit
> > > > MMIO) based on the current ratified RISC-V IOMMU specification, and
> > > > this driver does not appear to benefit from 64-bit MMIO access either.
> > > > Performance is fundamentally constrained by bus latency; assuming that
> > > > simply reducing the number of accesses will improve performance is an
> > > > oversimplification that ignores the underlying hardware
> > > > characteristics.
> > >
> > > If the bus latency is significant it is almost certainly worth using
> > > memory accesses to avoid re-reading the hi register.
> > >
> > > Something like this might work:
> > >
> > > static volatile u32 hi_prev, lo_prev;
> > >
> > > u32 hi = read_reg_hi();
> > > u32 lo = read_reg_lo();
> > >
> > > if (lo <= lo_prev || hi != hi_prev) {
> > > u32 hi_tmp = read_reg_hi;
> > > if (hi_tmp != hi) {
> > > hi = hi_tmp;
> > > lo = 0;
> > > }
> > > lo_prev = ~0u;
> > > hi_prev = hi;
> > > }
> > > lo_prev = lo;
> > > return (u64)hi << 32 | lo;
> > >
> > > It shouldn't need any locking but the accesses do need to be ordered.
> > Thank you for the suggestion. However, I believe this feedback is more
> > relevant to the RISC-V IOMMU HPM patchset [1], as no counter registers
> > are involved in the current patchset. That said, the idea of improving
> > the hi-lo-hi slow-path mechanism to better handle high-latency
> > hardware scenarios is well taken and worth discussing in the
> > appropriate thread.
> > [1]: https://lore.kernel.org/linux-riscv/20260208063848.3547817-2-zong.li@sifive.com/
> >
> > P.S. The hardware I have at hand exhibits very low interconnect
> > latency. And I have never observed the slow path where hi_tmp != hi
> > being triggered — my approach was to remove the retry mechanism
> > directly in 32-bit mmio mode and run stress tests to check whether
> > perf stat produced incorrect results. That said, I may have simply
> > been lucky instead of hw guarantee.
> >
>
>
> Hi everyone,
>
> Thank you for adding me to this discussion. I took some time to read
> the previous messages.
> Regarding the GitHub issue mentioned by Vivian, I noticed someone
> pointed out that the hardware must support 64-bit access.
>
> https://github.com/riscv-non-isa/riscv-iommu/issues/765#issuecomment-4742941894
>
> I would like to confirm if that is correct. If so, should we update
> the spec? And does this mean we do not need to modify the driver?
Currently, no one has proposed updating the SPEC. Discussions are
still focused on clarifying the meaning of the existing specification.
There are two main points under discussion: the first has been
clarified, while the second remains controversial.
The first point — "Whether an 8-byte access to an IOMMU register is
single-copy atomic is UNSPECIFIED" — is uncontroversial. Ved further
explained that such an access may appear internally to the IOMMU as
two separate 4-byte accesses. Therefore, for hpm COUNTER counters,
32-bit MMIO access must be used to guarantee the correct hi-lo-hi
ordering. Using 64-bit MMIO access can result in a lo-hi-hi-lo
sequence, because the specification does not define the order in which
the access may be split and explicitly marks this behavior as
UNSPECIFIED. At present, there is unanimous agreement on this point,
that is, "Whether an 8-byte access to an IOMMU register is single-copy
atomic is UNSPECIFIED".
The second point — "Registers that are 64-bit wide may be accessed
using either a 32-bit or a 64-bit access." — is controversial.
According to the clear definition in RFC 2119: MAY This word, or the
adjective "OPTIONAL", mean that an item is truly optional. One vendor
may choose to include the item because a particular marketplace
requires it or because the vendor feels that it enhances the product
while another vendor may omit the same item. An implementation which
does not include a particular option MUST be prepared to interoperate
with another implementation which does include the option, though
perhaps with reduced functionality. In the same vein an implementation
which does include a particular option MUST be prepared to
interoperate with another implementation which does not include the
option (except, of course, for the feature the option provides).
Consequently, any claim that this wording imposes a requirement for
hardware to support 64-bit MMIO access has generated significant
controversy.
The current explicit consensus on the specification is therefore as follows:
1. All hardware must support access to 64-bit registers using 32-bit
MMIO accesses.
2. Only 32-bit MMIO accesses are guaranteed to be single-copy atomic.
From both a single-copy atomicity perspective and a hardware
requirements standpoint, Linux kernel drivers should currently follow
the consensus described above and avoid the controversial 64-bit MMIO
access. Furthermore, I see no performance benefit to using 64-bit MMIO
accesses in this driver, as the only 64-bit registers involved — such
as RISCV_IOMMU_REG_DDTP, RISCV_IOMMU_REG_ICVEC, and queue->qbr — are
not frequently accessed.
--
Best Regards
Guo Ren
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
2026-06-28 8:20 ` Guo Ren
@ 2026-06-29 1:15 ` Zong Li
0 siblings, 0 replies; 30+ messages in thread
From: Zong Li @ 2026-06-29 1:15 UTC (permalink / raw)
To: Guo Ren
Cc: David Laight, Vivian Wang, zhangzhanpeng.jasper, alex, aou,
cuiyunhui, iommu, joro, linux-kernel, linux-riscv, luxu.kernel,
palmer, pjw, robin.murphy, tjeznach, will, yuanzhu
On Sun, Jun 28, 2026 at 4:20 PM Guo Ren <guoren@kernel.org> wrote:
>
> Hi Zong Li,
>
> On Tue, Jun 23, 2026 at 5:21 PM Zong Li <zong.li@sifive.com> wrote:
> >
> > On Fri, Jun 19, 2026 at 1:14 AM Guo Ren <guoren@kernel.org> wrote:
> > >
> > > On Thu, Jun 18, 2026 at 9:36 PM David Laight
> > > <david.laight.linux@gmail.com> wrote:
> > > >
> > > > On Thu, 18 Jun 2026 17:51:34 +0800
> > > > Guo Ren <guoren@kernel.org> wrote:
> > > >
> > > > > Hi Vivian,
> > > > >
> > > > > As noted in the RISC-V IOMMU Specification, Chapter 6:
> > > > > > Whether an 8-byte access to an IOMMU register is single-copy atomic is UNSPECIFIED, and such an access may appear, internally to the IOMMU, as if two separate 4-byte accesses — first to the high half and second to the low half — were performed.
> > > > >
> > > > > Therefore, the atomicity of 64-bit MMIO accesses is UNSPECIFIED and
> > > > > not clearly defined in the current ratified RISC-V IOMMU
> > > > > specification. To handle this correctly, the Linux RISC-V IOMMU driver
> > > > > should fall back to 32-bit MMIO accesses when reading 64-bit registers
> > > > > (e.g., performance counters). The behavior of 32-bit MMIO accesses is
> > > > > more precisely defined in the RISC-V IOMMU specification.
> > > > >
> > > > > Thus, many hardware vendors implement 32-bit MMIO (rather than 64-bit
> > > > > MMIO) based on the current ratified RISC-V IOMMU specification, and
> > > > > this driver does not appear to benefit from 64-bit MMIO access either.
> > > > > Performance is fundamentally constrained by bus latency; assuming that
> > > > > simply reducing the number of accesses will improve performance is an
> > > > > oversimplification that ignores the underlying hardware
> > > > > characteristics.
> > > >
> > > > If the bus latency is significant it is almost certainly worth using
> > > > memory accesses to avoid re-reading the hi register.
> > > >
> > > > Something like this might work:
> > > >
> > > > static volatile u32 hi_prev, lo_prev;
> > > >
> > > > u32 hi = read_reg_hi();
> > > > u32 lo = read_reg_lo();
> > > >
> > > > if (lo <= lo_prev || hi != hi_prev) {
> > > > u32 hi_tmp = read_reg_hi;
> > > > if (hi_tmp != hi) {
> > > > hi = hi_tmp;
> > > > lo = 0;
> > > > }
> > > > lo_prev = ~0u;
> > > > hi_prev = hi;
> > > > }
> > > > lo_prev = lo;
> > > > return (u64)hi << 32 | lo;
> > > >
> > > > It shouldn't need any locking but the accesses do need to be ordered.
> > > Thank you for the suggestion. However, I believe this feedback is more
> > > relevant to the RISC-V IOMMU HPM patchset [1], as no counter registers
> > > are involved in the current patchset. That said, the idea of improving
> > > the hi-lo-hi slow-path mechanism to better handle high-latency
> > > hardware scenarios is well taken and worth discussing in the
> > > appropriate thread.
> > > [1]: https://lore.kernel.org/linux-riscv/20260208063848.3547817-2-zong.li@sifive.com/
> > >
> > > P.S. The hardware I have at hand exhibits very low interconnect
> > > latency. And I have never observed the slow path where hi_tmp != hi
> > > being triggered — my approach was to remove the retry mechanism
> > > directly in 32-bit mmio mode and run stress tests to check whether
> > > perf stat produced incorrect results. That said, I may have simply
> > > been lucky instead of hw guarantee.
> > >
> >
> >
> > Hi everyone,
> >
> > Thank you for adding me to this discussion. I took some time to read
> > the previous messages.
> > Regarding the GitHub issue mentioned by Vivian, I noticed someone
> > pointed out that the hardware must support 64-bit access.
> >
> > https://github.com/riscv-non-isa/riscv-iommu/issues/765#issuecomment-4742941894
> >
> > I would like to confirm if that is correct. If so, should we update
> > the spec? And does this mean we do not need to modify the driver?
>
> Currently, no one has proposed updating the SPEC. Discussions are
> still focused on clarifying the meaning of the existing specification.
> There are two main points under discussion: the first has been
> clarified, while the second remains controversial.
>
> The first point — "Whether an 8-byte access to an IOMMU register is
> single-copy atomic is UNSPECIFIED" — is uncontroversial. Ved further
> explained that such an access may appear internally to the IOMMU as
> two separate 4-byte accesses. Therefore, for hpm COUNTER counters,
> 32-bit MMIO access must be used to guarantee the correct hi-lo-hi
> ordering. Using 64-bit MMIO access can result in a lo-hi-hi-lo
> sequence, because the specification does not define the order in which
> the access may be split and explicitly marks this behavior as
> UNSPECIFIED. At present, there is unanimous agreement on this point,
> that is, "Whether an 8-byte access to an IOMMU register is single-copy
> atomic is UNSPECIFIED".
>
> The second point — "Registers that are 64-bit wide may be accessed
> using either a 32-bit or a 64-bit access." — is controversial.
> According to the clear definition in RFC 2119: MAY This word, or the
> adjective "OPTIONAL", mean that an item is truly optional. One vendor
> may choose to include the item because a particular marketplace
> requires it or because the vendor feels that it enhances the product
> while another vendor may omit the same item. An implementation which
> does not include a particular option MUST be prepared to interoperate
> with another implementation which does include the option, though
> perhaps with reduced functionality. In the same vein an implementation
> which does include a particular option MUST be prepared to
> interoperate with another implementation which does not include the
> option (except, of course, for the feature the option provides).
> Consequently, any claim that this wording imposes a requirement for
> hardware to support 64-bit MMIO access has generated significant
> controversy.
>
> The current explicit consensus on the specification is therefore as follows:
> 1. All hardware must support access to 64-bit registers using 32-bit
> MMIO accesses.
> 2. Only 32-bit MMIO accesses are guaranteed to be single-copy atomic.
>
> From both a single-copy atomicity perspective and a hardware
> requirements standpoint, Linux kernel drivers should currently follow
> the consensus described above and avoid the controversial 64-bit MMIO
> access. Furthermore, I see no performance benefit to using 64-bit MMIO
> accesses in this driver, as the only 64-bit registers involved — such
> as RISCV_IOMMU_REG_DDTP, RISCV_IOMMU_REG_ICVEC, and queue->qbr — are
> not frequently accessed.
>
Thanks for your clarification, I will address this topic in PMU driver
in the next version.
> --
> Best Regards
> Guo Ren
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH v2] iommu/riscv: Use 32-bit MMIO accesses for 64-bit registers
2026-06-15 6:48 [PATCH v1] iommu/riscv: Support 32-bit register accesses Zhanpeng Zhang
` (2 preceding siblings ...)
2026-06-15 12:38 ` Guo Ren
@ 2026-07-13 6:09 ` Zhanpeng Zhang
2026-07-13 7:00 ` Guo Ren
2026-07-13 12:29 ` [PATCH v3] " Zhanpeng Zhang
4 siblings, 1 reply; 30+ messages in thread
From: Zhanpeng Zhang @ 2026-07-13 6:09 UTC (permalink / raw)
To: Tomasz Jeznach, Joerg Roedel, Will Deacon
Cc: Robin Murphy, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Guo Ren, David Laight, Vivian Wang, Zong Li,
cuiyunhui, yuanzhu, iommu, linux-riscv, linux-kernel,
Zhanpeng Zhang
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. Poll DDTP.BUSY in the low half before
reading the full register from high to low. 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 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 before reading the full register.
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 | 18 +++++++++++-------
drivers/iommu/riscv/iommu.h | 9 +++------
2 files changed, 14 insertions(+), 13 deletions(-)
diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index cec3ddd7ab1..14b572058ed 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -668,12 +668,16 @@ void riscv_iommu_disable(struct riscv_iommu_device *iommu)
riscv_iommu_writel(iommu, RISCV_IOMMU_REG_PQCSR, 0);
}
-#define riscv_iommu_read_ddtp(iommu) ({ \
- u64 ddtp; \
- riscv_iommu_readq_timeout((iommu), RISCV_IOMMU_REG_DDTP, ddtp, \
- !(ddtp & RISCV_IOMMU_DDTP_BUSY), 10, \
- RISCV_IOMMU_DDTP_TIMEOUT); \
- ddtp; })
+static u64 riscv_iommu_read_ddtp(struct riscv_iommu_device *iommu)
+{
+ u32 ddtp_lo;
+
+ riscv_iommu_readl_timeout(iommu, RISCV_IOMMU_REG_DDTP, ddtp_lo,
+ !(ddtp_lo & RISCV_IOMMU_DDTP_BUSY), 10,
+ RISCV_IOMMU_DDTP_TIMEOUT);
+
+ return riscv_iommu_readq(iommu, RISCV_IOMMU_REG_DDTP);
+}
static int riscv_iommu_iodir_alloc(struct riscv_iommu_device *iommu)
{
@@ -1501,7 +1505,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))
#define riscv_iommu_writel(iommu, addr, val) \
writel_relaxed((val), (iommu)->reg + (addr))
#define riscv_iommu_writeq(iommu, addr, val) \
- writeq_relaxed((val), (iommu)->reg + (addr))
-
-#define riscv_iommu_readq_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
- readx_poll_timeout(readq_relaxed, (iommu)->reg + (addr), val, cond, \
- delay_us, timeout_us)
+ hi_lo_writeq_relaxed((val), (iommu)->reg + (addr))
#define riscv_iommu_readl_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
readx_poll_timeout(readl_relaxed, (iommu)->reg + (addr), val, cond, \
--
2.50.1 (Apple Git-155)
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 30+ messages in thread
* Re: [PATCH v2] iommu/riscv: Use 32-bit MMIO accesses for 64-bit registers
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
0 siblings, 1 reply; 30+ messages in thread
From: Guo Ren @ 2026-07-13 7:00 UTC (permalink / raw)
To: Zhanpeng Zhang
Cc: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
David Laight, Vivian Wang, Zong Li, cuiyunhui, yuanzhu, iommu,
linux-riscv, linux-kernel
On Mon, Jul 13, 2026 at 2:09 PM Zhanpeng Zhang
<zhangzhanpeng.jasper@bytedance.com> 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. Poll DDTP.BUSY in the low half before
> reading the full register from high to low. 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 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 before reading the full register.
>
> 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 | 18 +++++++++++-------
> drivers/iommu/riscv/iommu.h | 9 +++------
> 2 files changed, 14 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
> index cec3ddd7ab1..14b572058ed 100644
> --- a/drivers/iommu/riscv/iommu.c
> +++ b/drivers/iommu/riscv/iommu.c
> @@ -668,12 +668,16 @@ void riscv_iommu_disable(struct riscv_iommu_device *iommu)
> riscv_iommu_writel(iommu, RISCV_IOMMU_REG_PQCSR, 0);
> }
>
> -#define riscv_iommu_read_ddtp(iommu) ({ \
> - u64 ddtp; \
> - riscv_iommu_readq_timeout((iommu), RISCV_IOMMU_REG_DDTP, ddtp, \
> - !(ddtp & RISCV_IOMMU_DDTP_BUSY), 10, \
> - RISCV_IOMMU_DDTP_TIMEOUT); \
> - ddtp; })
> +static u64 riscv_iommu_read_ddtp(struct riscv_iommu_device *iommu)
> +{
> + u32 ddtp_lo;
> +
> + riscv_iommu_readl_timeout(iommu, RISCV_IOMMU_REG_DDTP, ddtp_lo,
> + !(ddtp_lo & RISCV_IOMMU_DDTP_BUSY), 10,
> + RISCV_IOMMU_DDTP_TIMEOUT);
> +
> + return riscv_iommu_readq(iommu, RISCV_IOMMU_REG_DDTP);
readq? Please ref [1]:
#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); \
+ ddtp = ((u64)ddtp_hi << 32) | ddtp_lo; \
ddtp; })
> +}
>
> static int riscv_iommu_iodir_alloc(struct riscv_iommu_device *iommu)
> {
> @@ -1501,7 +1505,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))
>
> #define riscv_iommu_writel(iommu, addr, val) \
> writel_relaxed((val), (iommu)->reg + (addr))
>
> #define riscv_iommu_writeq(iommu, addr, val) \
> - writeq_relaxed((val), (iommu)->reg + (addr))
> -
> -#define riscv_iommu_readq_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> - readx_poll_timeout(readq_relaxed, (iommu)->reg + (addr), val, cond, \
> - delay_us, timeout_us)
> + hi_lo_writeq_relaxed((val), (iommu)->reg + (addr))
>
> #define riscv_iommu_readl_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> readx_poll_timeout(readl_relaxed, (iommu)->reg + (addr), val, cond, \
> --
> 2.50.1 (Apple Git-155)
--
Best Regards
Guo Ren
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: Re: [PATCH v2] iommu/riscv: Use 32-bit MMIO accesses for 64-bit registers
2026-07-13 7:00 ` Guo Ren
@ 2026-07-13 8:24 ` Zhanpeng Zhang
0 siblings, 0 replies; 30+ messages in thread
From: Zhanpeng Zhang @ 2026-07-13 8:24 UTC (permalink / raw)
To: Guo Ren
Cc: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
David Laight, Vivian Wang, Zong Li, cuiyunhui, yuanzhu, iommu,
linux-riscv, linux-kernel
Hi Guo,
On 7/13/26 3:00 PM, Guo Ren wrote:
> On Mon, Jul 13, 2026 at 2:09 PM Zhanpeng Zhang
> <zhangzhanpeng.jasper@bytedance.com> 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. Poll DDTP.BUSY in the low half before
>> reading the full register from high to low. 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 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 before reading the full register.
>>
>> 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 | 18 +++++++++++-------
>> drivers/iommu/riscv/iommu.h | 9 +++------
>> 2 files changed, 14 insertions(+), 13 deletions(-)
>>
>> diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
>> index cec3ddd7ab1..14b572058ed 100644
>> --- a/drivers/iommu/riscv/iommu.c
>> +++ b/drivers/iommu/riscv/iommu.c
>> @@ -668,12 +668,16 @@ void riscv_iommu_disable(struct riscv_iommu_device *iommu)
>> riscv_iommu_writel(iommu, RISCV_IOMMU_REG_PQCSR, 0);
>> }
>>
>> -#define riscv_iommu_read_ddtp(iommu) ({ \
>> - u64 ddtp; \
>> - riscv_iommu_readq_timeout((iommu), RISCV_IOMMU_REG_DDTP, ddtp, \
>> - !(ddtp & RISCV_IOMMU_DDTP_BUSY), 10, \
>> - RISCV_IOMMU_DDTP_TIMEOUT); \
>> - ddtp; })
>> +static u64 riscv_iommu_read_ddtp(struct riscv_iommu_device *iommu)
>> +{
>> + u32 ddtp_lo;
>> +
>> + riscv_iommu_readl_timeout(iommu, RISCV_IOMMU_REG_DDTP, ddtp_lo,
>> + !(ddtp_lo & RISCV_IOMMU_DDTP_BUSY), 10,
>> + RISCV_IOMMU_DDTP_TIMEOUT);
>> +
>> + return riscv_iommu_readq(iommu, RISCV_IOMMU_REG_DDTP);
> readq? Please ref [1]:
>
> #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); \
> + ddtp = ((u64)ddtp_hi << 32) | ddtp_lo; \
> ddtp; })
>
Oops, thanks for catching that, it will re-read the low 32 bits. DDTP
must retain that polled low-half value, read only the high half, and
then compose the result.
The macro one [1] is correct, I've fixed it in v3.
>
>> +}
>>
>> static int riscv_iommu_iodir_alloc(struct riscv_iommu_device *iommu)
>> {
>> @@ -1501,7 +1505,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))
>>
>> #define riscv_iommu_writel(iommu, addr, val) \
>> writel_relaxed((val), (iommu)->reg + (addr))
>>
>> #define riscv_iommu_writeq(iommu, addr, val) \
>> - writeq_relaxed((val), (iommu)->reg + (addr))
>> -
>> -#define riscv_iommu_readq_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
>> - readx_poll_timeout(readq_relaxed, (iommu)->reg + (addr), val, cond, \
>> - delay_us, timeout_us)
>> + hi_lo_writeq_relaxed((val), (iommu)->reg + (addr))
>>
>> #define riscv_iommu_readl_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
>> readx_poll_timeout(readl_relaxed, (iommu)->reg + (addr), val, cond, \
>> --
>> 2.50.1 (Apple Git-155)
>
>
>
Thanks,
Zhanpeng
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH v3] iommu/riscv: Use 32-bit MMIO accesses for 64-bit registers
2026-06-15 6:48 [PATCH v1] iommu/riscv: Support 32-bit register accesses Zhanpeng Zhang
` (3 preceding siblings ...)
2026-07-13 6:09 ` [PATCH v2] iommu/riscv: Use 32-bit MMIO accesses for 64-bit registers Zhanpeng Zhang
@ 2026-07-13 12:29 ` Zhanpeng Zhang
2026-07-14 2:02 ` Guo Ren
4 siblings, 1 reply; 30+ messages in thread
From: Zhanpeng Zhang @ 2026-07-13 12:29 UTC (permalink / raw)
To: Tomasz Jeznach, Joerg Roedel, Will Deacon
Cc: Robin Murphy, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Guo Ren, David Laight, Vivian Wang, Zong Li,
cuiyunhui, yuanzhu, iommu, linux-riscv, linux-kernel
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); \
+ 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))
#define riscv_iommu_writel(iommu, addr, val) \
writel_relaxed((val), (iommu)->reg + (addr))
#define riscv_iommu_writeq(iommu, addr, val) \
- writeq_relaxed((val), (iommu)->reg + (addr))
-
-#define riscv_iommu_readq_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
- readx_poll_timeout(readq_relaxed, (iommu)->reg + (addr), val, cond, \
- delay_us, timeout_us)
+ hi_lo_writeq_relaxed((val), (iommu)->reg + (addr))
#define riscv_iommu_readl_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
readx_poll_timeout(readl_relaxed, (iommu)->reg + (addr), val, cond, \
--
2.50.1 (Apple Git-155)
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 30+ messages in thread
* Re: [PATCH v3] iommu/riscv: Use 32-bit MMIO accesses for 64-bit registers
2026-07-13 12:29 ` [PATCH v3] " Zhanpeng Zhang
@ 2026-07-14 2:02 ` Guo Ren
2026-07-14 7:10 ` Tomasz Jeznach
0 siblings, 1 reply; 30+ messages in thread
From: Guo Ren @ 2026-07-14 2:02 UTC (permalink / raw)
To: Zhanpeng Zhang
Cc: Tomasz Jeznach, Joerg Roedel, Will Deacon, Robin Murphy,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
David Laight, Vivian Wang, Zong Li, cuiyunhui, yuanzhu, iommu,
linux-riscv, linux-kernel
LGTM!
Reviewed-by: Guo Ren (Alibaba DAMO Academy) <guoren@kernel.org>
Co-developed-by: Guo Ren (Alibaba DAMO Academy) <guoren@kernel.org>
Signed-off-by: Guo Ren (Alibaba DAMO Academy) <guoren@kernel.org>
On Mon, Jul 13, 2026 at 8:29 PM Zhanpeng Zhang
<zhangzhanpeng.jasper@bytedance.com> 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); \
> + 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))
>
> #define riscv_iommu_writel(iommu, addr, val) \
> writel_relaxed((val), (iommu)->reg + (addr))
>
> #define riscv_iommu_writeq(iommu, addr, val) \
> - writeq_relaxed((val), (iommu)->reg + (addr))
> -
> -#define riscv_iommu_readq_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> - readx_poll_timeout(readq_relaxed, (iommu)->reg + (addr), val, cond, \
> - delay_us, timeout_us)
> + hi_lo_writeq_relaxed((val), (iommu)->reg + (addr))
>
> #define riscv_iommu_readl_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> readx_poll_timeout(readl_relaxed, (iommu)->reg + (addr), val, cond, \
> --
> 2.50.1 (Apple Git-155)
--
Best Regards
Guo Ren
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v3] iommu/riscv: Use 32-bit MMIO accesses for 64-bit registers
2026-07-14 2:02 ` Guo Ren
@ 2026-07-14 7:10 ` Tomasz Jeznach
0 siblings, 0 replies; 30+ messages in thread
From: Tomasz Jeznach @ 2026-07-14 7:10 UTC (permalink / raw)
To: Guo Ren, Zhanpeng Zhang
Cc: Joerg Roedel, Will Deacon, Robin Murphy, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, David Laight,
Vivian Wang, Zong Li, cuiyunhui, yuanzhu, iommu, linux-riscv,
linux-kernel
On 7/13/26 7:02 PM, Guo Ren wrote:
> LGTM!
>
> Reviewed-by: Guo Ren (Alibaba DAMO Academy) <guoren@kernel.org>
> Co-developed-by: Guo Ren (Alibaba DAMO Academy) <guoren@kernel.org>
> Signed-off-by: Guo Ren (Alibaba DAMO Academy) <guoren@kernel.org>
>
> On Mon, Jul 13, 2026 at 8:29 PM Zhanpeng Zhang
> <zhangzhanpeng.jasper@bytedance.com> 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); \
>> + 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))
>>
>> #define riscv_iommu_writel(iommu, addr, val) \
>> writel_relaxed((val), (iommu)->reg + (addr))
>>
>> #define riscv_iommu_writeq(iommu, addr, val) \
>> - writeq_relaxed((val), (iommu)->reg + (addr))
>> -
>> -#define riscv_iommu_readq_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
>> - readx_poll_timeout(readq_relaxed, (iommu)->reg + (addr), val, cond, \
>> - delay_us, timeout_us)
>> + hi_lo_writeq_relaxed((val), (iommu)->reg + (addr))
>>
>> #define riscv_iommu_readl_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
>> readx_poll_timeout(readl_relaxed, (iommu)->reg + (addr), val, cond, \
>> --
>> 2.50.1 (Apple Git-155)
Thank you for this change. Sorry for being late on the discussion. LGTM
Reviewed-by: Tomasz Jeznach <tomasz.jeznach@linux.dev>
Best,
- Tomasz
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 30+ messages in thread
end of thread, other threads:[~2026-07-14 7:11 UTC | newest]
Thread overview: 30+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox