diff mbox series

[05/11] RISC-V: drivers/iommu/riscv: Add sysfs interface

Message ID 610abe685f90870be52bc7c2ca45ab5235bd8eb4.1689792825.git.tjeznach@rivosinc.com (mailing list archive)
State Awaiting Upstream, archived
Headers show
Series Linux RISC-V IOMMU Support | expand

Checks

Context Check Description
conchuod/cover_letter success Series has a cover letter
conchuod/tree_selection success Guessed tree name to be for-next at HEAD 471aba2e4760
conchuod/fixes_present success Fixes tag not required for -next series
conchuod/maintainers_pattern success MAINTAINERS pattern errors before the patch: 4 and now 4
conchuod/verify_signedoff success Signed-off-by tag matches author and committer
conchuod/kdoc success Errors and warnings before: 0 this patch: 0
conchuod/build_rv64_clang_allmodconfig success Errors and warnings before: 10 this patch: 10
conchuod/module_param success Was 0 now: 0
conchuod/build_rv64_gcc_allmodconfig fail Errors and warnings before: 11 this patch: 12
conchuod/build_rv32_defconfig fail Build failed
conchuod/dtb_warn_rv64 success Errors and warnings before: 3 this patch: 3
conchuod/header_inline success No static functions without inline keyword in header files
conchuod/checkpatch fail ERROR: Macros with multiple statements should be enclosed in a do - while loop ERROR: open brace '{' following function definitions go on the next line WARNING: Missing a blank line after declarations WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
conchuod/build_rv64_nommu_k210_defconfig success Build OK
conchuod/verify_fixes success No Fixes tag
conchuod/build_rv64_nommu_virt_defconfig success Build OK

Commit Message

Tomasz Jeznach July 19, 2023, 7:33 p.m. UTC
Enable sysfs debug / visibility interface providing restricted
access to hardware registers.

Signed-off-by: Tomasz Jeznach <tjeznach@rivosinc.com>
---
 drivers/iommu/riscv/Makefile      |   2 +-
 drivers/iommu/riscv/iommu-sysfs.c | 183 ++++++++++++++++++++++++++++++
 drivers/iommu/riscv/iommu.c       |   7 ++
 drivers/iommu/riscv/iommu.h       |   2 +
 4 files changed, 193 insertions(+), 1 deletion(-)
 create mode 100644 drivers/iommu/riscv/iommu-sysfs.c

Comments

Krzysztof Kozlowski July 20, 2023, 6:38 a.m. UTC | #1
On 19/07/2023 21:33, Tomasz Jeznach wrote:
> Enable sysfs debug / visibility interface providing restricted
> access to hardware registers.

Please use subject prefixes matching the subsystem. You can get them for
example with `git log --oneline -- DIRECTORY_OR_FILE` on the directory
your patch is touching.

> 
> Signed-off-by: Tomasz Jeznach <tjeznach@rivosinc.com>
> ---
>  drivers/iommu/riscv/Makefile      |   2 +-
>  drivers/iommu/riscv/iommu-sysfs.c | 183 ++++++++++++++++++++++++++++++
>  drivers/iommu/riscv/iommu.c       |   7 ++
>  drivers/iommu/riscv/iommu.h       |   2 +
>  4 files changed, 193 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/iommu/riscv/iommu-sysfs.c
> 
> diff --git a/drivers/iommu/riscv/Makefile b/drivers/iommu/riscv/Makefile
> index 38730c11e4a8..9523eb053cfc 100644
> --- a/drivers/iommu/riscv/Makefile
> +++ b/drivers/iommu/riscv/Makefile
> @@ -1 +1 @@
> -obj-$(CONFIG_RISCV_IOMMU) += iommu.o iommu-pci.o iommu-platform.o
> \ No newline at end of file
> +obj-$(CONFIG_RISCV_IOMMU) += iommu.o iommu-pci.o iommu-platform.o iommu-sysfs.o
> \ No newline at end of file

You have this error in multiple places.

> diff --git a/drivers/iommu/riscv/iommu-sysfs.c b/drivers/iommu/riscv/iommu-sysfs.c
> new file mode 100644
> index 000000000000..f038ea8445c5
> --- /dev/null
> +++ b/drivers/iommu/riscv/iommu-sysfs.c
> @@ -0,0 +1,183 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * IOMMU API for RISC-V architected Ziommu implementations.
> + *
> + * Copyright © 2022-2023 Rivos Inc.
> + *
> + * Author: Tomasz Jeznach <tjeznach@rivosinc.com>
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/compiler.h>
> +#include <linux/iommu.h>
> +#include <linux/platform_device.h>
> +#include <asm/page.h>
> +
> +#include "iommu.h"
> +
> +#define sysfs_dev_to_iommu(dev) \
> +	container_of(dev_get_drvdata(dev), struct riscv_iommu_device, iommu)
> +
> +static ssize_t address_show(struct device *dev,
> +			    struct device_attribute *attr, char *buf)


Where is the sysfs ABI documented?


Best regards,
Krzysztof
Baolu Lu July 20, 2023, 12:50 p.m. UTC | #2
On 2023/7/20 3:33, Tomasz Jeznach wrote:
> +#define sysfs_dev_to_iommu(dev) \
> +	container_of(dev_get_drvdata(dev), struct riscv_iommu_device, iommu)
> +
> +static ssize_t address_show(struct device *dev,
> +			    struct device_attribute *attr, char *buf)
> +{
> +	struct riscv_iommu_device *iommu = sysfs_dev_to_iommu(dev);
> +	return sprintf(buf, "%llx\n", iommu->reg_phys);

Use sysfs_emit() please.

> +}
> +
> +static DEVICE_ATTR_RO(address);
> +
> +#define ATTR_RD_REG32(name, offset)					\
> +	ssize_t reg_ ## name ## _show(struct device *dev,		\
> +			struct device_attribute *attr, char *buf)	\
> +{									\
> +	struct riscv_iommu_device *iommu = sysfs_dev_to_iommu(dev);	\
> +	return sprintf(buf, "0x%x\n",					\
> +			riscv_iommu_readl(iommu, offset));		\
> +}
> +
> +#define ATTR_RD_REG64(name, offset)					\
> +	ssize_t reg_ ## name ## _show(struct device *dev,		\
> +			struct device_attribute *attr, char *buf)	\
> +{									\
> +	struct riscv_iommu_device *iommu = sysfs_dev_to_iommu(dev);	\
> +	return sprintf(buf, "0x%llx\n",					\
> +			riscv_iommu_readq(iommu, offset));		\
> +}
> +
> +#define ATTR_WR_REG32(name, offset)					\
> +	ssize_t reg_ ## name ## _store(struct device *dev,		\
> +			struct device_attribute *attr,			\
> +			const char *buf, size_t len)			\
> +{									\
> +	struct riscv_iommu_device *iommu = sysfs_dev_to_iommu(dev);	\
> +	unsigned long val;						\
> +	int ret;							\
> +	ret = kstrtoul(buf, 0, &val);					\
> +	if (ret)							\
> +		return ret;						\
> +	riscv_iommu_writel(iommu, offset, val);				\
> +	return len;							\
> +}
> +
> +#define ATTR_WR_REG64(name, offset)					\
> +	ssize_t reg_ ## name ## _store(struct device *dev,		\
> +			struct device_attribute *attr,			\
> +			const char *buf, size_t len)			\
> +{									\
> +	struct riscv_iommu_device *iommu = sysfs_dev_to_iommu(dev);	\
> +	unsigned long long val;						\
> +	int ret;							\
> +	ret = kstrtoull(buf, 0, &val);					\
> +	if (ret)							\
> +		return ret;						\
> +	riscv_iommu_writeq(iommu, offset, val);				\
> +	return len;							\
> +}

So this allows users to change the registers through sysfs? How does
it synchronize with the iommu driver?

Best regards,
baolu
Tomasz Jeznach July 20, 2023, 5:47 p.m. UTC | #3
On Thu, Jul 20, 2023 at 5:51 AM Baolu Lu <baolu.lu@linux.intel.com> wrote:
>
> On 2023/7/20 3:33, Tomasz Jeznach wrote:
> > +#define sysfs_dev_to_iommu(dev) \
> > +     container_of(dev_get_drvdata(dev), struct riscv_iommu_device, iommu)
> > +
> > +static ssize_t address_show(struct device *dev,
> > +                         struct device_attribute *attr, char *buf)
> > +{
> > +     struct riscv_iommu_device *iommu = sysfs_dev_to_iommu(dev);
> > +     return sprintf(buf, "%llx\n", iommu->reg_phys);
>
> Use sysfs_emit() please.
>

ack. Thanks, will update.

> > +}
> > +
> > +static DEVICE_ATTR_RO(address);
> > +
> > +#define ATTR_RD_REG32(name, offset)                                  \
> > +     ssize_t reg_ ## name ## _show(struct device *dev,               \
> > +                     struct device_attribute *attr, char *buf)       \
> > +{                                                                    \
> > +     struct riscv_iommu_device *iommu = sysfs_dev_to_iommu(dev);     \
> > +     return sprintf(buf, "0x%x\n",                                   \
> > +                     riscv_iommu_readl(iommu, offset));              \
> > +}
> > +
> > +#define ATTR_RD_REG64(name, offset)                                  \
> > +     ssize_t reg_ ## name ## _show(struct device *dev,               \
> > +                     struct device_attribute *attr, char *buf)       \
> > +{                                                                    \
> > +     struct riscv_iommu_device *iommu = sysfs_dev_to_iommu(dev);     \
> > +     return sprintf(buf, "0x%llx\n",                                 \
> > +                     riscv_iommu_readq(iommu, offset));              \
> > +}
> > +
> > +#define ATTR_WR_REG32(name, offset)                                  \
> > +     ssize_t reg_ ## name ## _store(struct device *dev,              \
> > +                     struct device_attribute *attr,                  \
> > +                     const char *buf, size_t len)                    \
> > +{                                                                    \
> > +     struct riscv_iommu_device *iommu = sysfs_dev_to_iommu(dev);     \
> > +     unsigned long val;                                              \
> > +     int ret;                                                        \
> > +     ret = kstrtoul(buf, 0, &val);                                   \
> > +     if (ret)                                                        \
> > +             return ret;                                             \
> > +     riscv_iommu_writel(iommu, offset, val);                         \
> > +     return len;                                                     \
> > +}
> > +
> > +#define ATTR_WR_REG64(name, offset)                                  \
> > +     ssize_t reg_ ## name ## _store(struct device *dev,              \
> > +                     struct device_attribute *attr,                  \
> > +                     const char *buf, size_t len)                    \
> > +{                                                                    \
> > +     struct riscv_iommu_device *iommu = sysfs_dev_to_iommu(dev);     \
> > +     unsigned long long val;                                         \
> > +     int ret;                                                        \
> > +     ret = kstrtoull(buf, 0, &val);                                  \
> > +     if (ret)                                                        \
> > +             return ret;                                             \
> > +     riscv_iommu_writeq(iommu, offset, val);                         \
> > +     return len;                                                     \
> > +}
>
> So this allows users to change the registers through sysfs? How does
> it synchronize with the iommu driver?
>

The only writable registers are for debug interface and performance
monitoring counters, without any synchronization requirements between
user / driver.  In follow up patch series performance counters will be
also removed from sysfs, replaced by integration with perfmon
subsystem. The only remaining will be a debug access, providing user
access to address translation, in short it provides an interface to
query SPA based on provided IOVA/RID/PASID. There was a discussion in
RVI IOMMU TG forum if it's acceptable to expose such an interface to
the privileged user, and the conclusion was that it's very likely not
exposing more info than privileged users already are able to acquire
by looking at in-memory data structures.

Read-only registers are to provide debug access to track queue
head/tail pointers and interrupt states.

> Best regards,
> baolu

regards,
- Tomasz
Tomasz Jeznach July 20, 2023, 6:30 p.m. UTC | #4
On Wed, Jul 19, 2023 at 11:38 PM Krzysztof Kozlowski <krzk@kernel.org> wrote:
>
> On 19/07/2023 21:33, Tomasz Jeznach wrote:
> > Enable sysfs debug / visibility interface providing restricted
> > access to hardware registers.
>
> Please use subject prefixes matching the subsystem. You can get them for
> example with `git log --oneline -- DIRECTORY_OR_FILE` on the directory
> your patch is touching.
>

ack.

> >
> > Signed-off-by: Tomasz Jeznach <tjeznach@rivosinc.com>
> > ---
> >  drivers/iommu/riscv/Makefile      |   2 +-
> >  drivers/iommu/riscv/iommu-sysfs.c | 183 ++++++++++++++++++++++++++++++
> >  drivers/iommu/riscv/iommu.c       |   7 ++
> >  drivers/iommu/riscv/iommu.h       |   2 +
> >  4 files changed, 193 insertions(+), 1 deletion(-)
> >  create mode 100644 drivers/iommu/riscv/iommu-sysfs.c
> >
> > diff --git a/drivers/iommu/riscv/Makefile b/drivers/iommu/riscv/Makefile
> > index 38730c11e4a8..9523eb053cfc 100644
> > --- a/drivers/iommu/riscv/Makefile
> > +++ b/drivers/iommu/riscv/Makefile
> > @@ -1 +1 @@
> > -obj-$(CONFIG_RISCV_IOMMU) += iommu.o iommu-pci.o iommu-platform.o
> > \ No newline at end of file
> > +obj-$(CONFIG_RISCV_IOMMU) += iommu.o iommu-pci.o iommu-platform.o iommu-sysfs.o
> > \ No newline at end of file
>
> You have this error in multiple places.
>

ack. next version will run through checkpatch.pl, should spot such problems.

> > diff --git a/drivers/iommu/riscv/iommu-sysfs.c b/drivers/iommu/riscv/iommu-sysfs.c
> > new file mode 100644
> > index 000000000000..f038ea8445c5
> > --- /dev/null
> > +++ b/drivers/iommu/riscv/iommu-sysfs.c
> > @@ -0,0 +1,183 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * IOMMU API for RISC-V architected Ziommu implementations.
> > + *
> > + * Copyright © 2022-2023 Rivos Inc.
> > + *
> > + * Author: Tomasz Jeznach <tjeznach@rivosinc.com>
> > + */
> > +
> > +#include <linux/module.h>
> > +#include <linux/kernel.h>
> > +#include <linux/compiler.h>
> > +#include <linux/iommu.h>
> > +#include <linux/platform_device.h>
> > +#include <asm/page.h>
> > +
> > +#include "iommu.h"
> > +
> > +#define sysfs_dev_to_iommu(dev) \
> > +     container_of(dev_get_drvdata(dev), struct riscv_iommu_device, iommu)
> > +
> > +static ssize_t address_show(struct device *dev,
> > +                         struct device_attribute *attr, char *buf)
>
>
> Where is the sysfs ABI documented?
>

Sysfs for now is used only to expose selected IOMMU memory mapped
registers, with complete documentation in the RISC-V IOMMU Arch Spec
[1], and some comments in iommu-bits.h file.
LMK If it would be better to put a dedicated file documenting those
with the patch itself.


[1] https://github.com/riscv-non-isa/riscv-iommu/releases/download/v1.0/riscv-iommu.pdf

>
> Best regards,
> Krzysztof
>

regards,
- Tomasz
Krzysztof Kozlowski July 20, 2023, 9:37 p.m. UTC | #5
On 20/07/2023 20:30, Tomasz Jeznach wrote:
u.h"
>>> +
>>> +#define sysfs_dev_to_iommu(dev) \
>>> +     container_of(dev_get_drvdata(dev), struct riscv_iommu_device, iommu)
>>> +
>>> +static ssize_t address_show(struct device *dev,
>>> +                         struct device_attribute *attr, char *buf)
>>
>>
>> Where is the sysfs ABI documented?
>>
> 
> Sysfs for now is used only to expose selected IOMMU memory mapped
> registers, with complete documentation in the RISC-V IOMMU Arch Spec
> [1], and some comments in iommu-bits.h file.
> LMK If it would be better to put a dedicated file documenting those
> with the patch itself.

I meant, you created new sysfs interface. Maybe I missed something in
the patchset, but each new sysfs interface required documenting in
Documentation/ABI/.

Best regards,
Krzysztof
Conor Dooley July 20, 2023, 10:08 p.m. UTC | #6
On Thu, Jul 20, 2023 at 11:37:50PM +0200, Krzysztof Kozlowski wrote:
> On 20/07/2023 20:30, Tomasz Jeznach wrote:

> >>> +#define sysfs_dev_to_iommu(dev) \
> >>> +     container_of(dev_get_drvdata(dev), struct riscv_iommu_device, iommu)
> >>> +
> >>> +static ssize_t address_show(struct device *dev,
> >>> +                         struct device_attribute *attr, char *buf)
> >>
> >>
> >> Where is the sysfs ABI documented?
> >>
> > 
> > Sysfs for now is used only to expose selected IOMMU memory mapped
> > registers, with complete documentation in the RISC-V IOMMU Arch Spec
> > [1], and some comments in iommu-bits.h file.
> > LMK If it would be better to put a dedicated file documenting those
> > with the patch itself.
> 
> I meant, you created new sysfs interface. Maybe I missed something in
> the patchset, but each new sysfs interface required documenting in
> Documentation/ABI/.

| expose selected IOMMU memory mapped registers

| Enable sysfs debug / visibility interface providing restricted
| access to hardware registers.

Documentation requirements of sysfs stuff aside, I'm not sure that we
even want a sysfs interface for this in the first place? Seems like, if
at all, this should be debugfs instead? Seems like the only use case for
it is debugging/development...
Tomasz Jeznach July 21, 2023, 3:49 a.m. UTC | #7
On Thu, Jul 20, 2023 at 3:08 PM Conor Dooley <conor@kernel.org> wrote:
>
> On Thu, Jul 20, 2023 at 11:37:50PM +0200, Krzysztof Kozlowski wrote:
> > On 20/07/2023 20:30, Tomasz Jeznach wrote:
>
> > >>> +#define sysfs_dev_to_iommu(dev) \
> > >>> +     container_of(dev_get_drvdata(dev), struct riscv_iommu_device, iommu)
> > >>> +
> > >>> +static ssize_t address_show(struct device *dev,
> > >>> +                         struct device_attribute *attr, char *buf)
> > >>
> > >>
> > >> Where is the sysfs ABI documented?
> > >>
> > >
> > > Sysfs for now is used only to expose selected IOMMU memory mapped
> > > registers, with complete documentation in the RISC-V IOMMU Arch Spec
> > > [1], and some comments in iommu-bits.h file.
> > > LMK If it would be better to put a dedicated file documenting those
> > > with the patch itself.
> >
> > I meant, you created new sysfs interface. Maybe I missed something in
> > the patchset, but each new sysfs interface required documenting in
> > Documentation/ABI/.
>
> | expose selected IOMMU memory mapped registers
>
> | Enable sysfs debug / visibility interface providing restricted
> | access to hardware registers.
>
> Documentation requirements of sysfs stuff aside, I'm not sure that we
> even want a sysfs interface for this in the first place? Seems like, if
> at all, this should be debugfs instead? Seems like the only use case for
> it is debugging/development...

Thanks Conor, will switch to debugfs. This will be a more suitable interface.

regards,
- Tomasz
diff mbox series

Patch

diff --git a/drivers/iommu/riscv/Makefile b/drivers/iommu/riscv/Makefile
index 38730c11e4a8..9523eb053cfc 100644
--- a/drivers/iommu/riscv/Makefile
+++ b/drivers/iommu/riscv/Makefile
@@ -1 +1 @@ 
-obj-$(CONFIG_RISCV_IOMMU) += iommu.o iommu-pci.o iommu-platform.o
\ No newline at end of file
+obj-$(CONFIG_RISCV_IOMMU) += iommu.o iommu-pci.o iommu-platform.o iommu-sysfs.o
\ No newline at end of file
diff --git a/drivers/iommu/riscv/iommu-sysfs.c b/drivers/iommu/riscv/iommu-sysfs.c
new file mode 100644
index 000000000000..f038ea8445c5
--- /dev/null
+++ b/drivers/iommu/riscv/iommu-sysfs.c
@@ -0,0 +1,183 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * IOMMU API for RISC-V architected Ziommu implementations.
+ *
+ * Copyright © 2022-2023 Rivos Inc.
+ *
+ * Author: Tomasz Jeznach <tjeznach@rivosinc.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/compiler.h>
+#include <linux/iommu.h>
+#include <linux/platform_device.h>
+#include <asm/page.h>
+
+#include "iommu.h"
+
+#define sysfs_dev_to_iommu(dev) \
+	container_of(dev_get_drvdata(dev), struct riscv_iommu_device, iommu)
+
+static ssize_t address_show(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	struct riscv_iommu_device *iommu = sysfs_dev_to_iommu(dev);
+	return sprintf(buf, "%llx\n", iommu->reg_phys);
+}
+
+static DEVICE_ATTR_RO(address);
+
+#define ATTR_RD_REG32(name, offset)					\
+	ssize_t reg_ ## name ## _show(struct device *dev,		\
+			struct device_attribute *attr, char *buf)	\
+{									\
+	struct riscv_iommu_device *iommu = sysfs_dev_to_iommu(dev);	\
+	return sprintf(buf, "0x%x\n",					\
+			riscv_iommu_readl(iommu, offset));		\
+}
+
+#define ATTR_RD_REG64(name, offset)					\
+	ssize_t reg_ ## name ## _show(struct device *dev,		\
+			struct device_attribute *attr, char *buf)	\
+{									\
+	struct riscv_iommu_device *iommu = sysfs_dev_to_iommu(dev);	\
+	return sprintf(buf, "0x%llx\n",					\
+			riscv_iommu_readq(iommu, offset));		\
+}
+
+#define ATTR_WR_REG32(name, offset)					\
+	ssize_t reg_ ## name ## _store(struct device *dev,		\
+			struct device_attribute *attr,			\
+			const char *buf, size_t len)			\
+{									\
+	struct riscv_iommu_device *iommu = sysfs_dev_to_iommu(dev);	\
+	unsigned long val;						\
+	int ret;							\
+	ret = kstrtoul(buf, 0, &val);					\
+	if (ret)							\
+		return ret;						\
+	riscv_iommu_writel(iommu, offset, val);				\
+	return len;							\
+}
+
+#define ATTR_WR_REG64(name, offset)					\
+	ssize_t reg_ ## name ## _store(struct device *dev,		\
+			struct device_attribute *attr,			\
+			const char *buf, size_t len)			\
+{									\
+	struct riscv_iommu_device *iommu = sysfs_dev_to_iommu(dev);	\
+	unsigned long long val;						\
+	int ret;							\
+	ret = kstrtoull(buf, 0, &val);					\
+	if (ret)							\
+		return ret;						\
+	riscv_iommu_writeq(iommu, offset, val);				\
+	return len;							\
+}
+
+#define ATTR_RO_REG32(name, offset)					\
+static ATTR_RD_REG32(name, offset);					\
+static DEVICE_ATTR_RO(reg_ ## name)
+
+#define ATTR_RW_REG32(name, offset)					\
+static ATTR_RD_REG32(name, offset);					\
+static ATTR_WR_REG32(name, offset);					\
+static DEVICE_ATTR_RW(reg_ ## name)
+
+#define ATTR_RO_REG64(name, offset)					\
+static ATTR_RD_REG64(name, offset);					\
+static DEVICE_ATTR_RO(reg_ ## name)
+
+#define ATTR_RW_REG64(name, offset)					\
+static ATTR_RD_REG64(name, offset);					\
+static ATTR_WR_REG64(name, offset);					\
+static DEVICE_ATTR_RW(reg_ ## name)
+
+ATTR_RO_REG64(cap, RISCV_IOMMU_REG_CAP);
+ATTR_RO_REG64(fctl, RISCV_IOMMU_REG_FCTL);
+ATTR_RO_REG32(cqh, RISCV_IOMMU_REG_CQH);
+ATTR_RO_REG32(cqt, RISCV_IOMMU_REG_CQT);
+ATTR_RO_REG32(cqcsr, RISCV_IOMMU_REG_CQCSR);
+ATTR_RO_REG32(fqh, RISCV_IOMMU_REG_FQH);
+ATTR_RO_REG32(fqt, RISCV_IOMMU_REG_FQT);
+ATTR_RO_REG32(fqcsr, RISCV_IOMMU_REG_FQCSR);
+ATTR_RO_REG32(pqh, RISCV_IOMMU_REG_PQH);
+ATTR_RO_REG32(pqt, RISCV_IOMMU_REG_PQT);
+ATTR_RO_REG32(pqcsr, RISCV_IOMMU_REG_PQCSR);
+ATTR_RO_REG32(ipsr, RISCV_IOMMU_REG_IPSR);
+ATTR_RO_REG32(ivec, RISCV_IOMMU_REG_IVEC);
+ATTR_RW_REG64(tr_iova, RISCV_IOMMU_REG_TR_REQ_IOVA);
+ATTR_RW_REG64(tr_ctrl, RISCV_IOMMU_REG_TR_REQ_CTL);
+ATTR_RW_REG64(tr_response, RISCV_IOMMU_REG_TR_RESPONSE);
+ATTR_RW_REG32(iocntovf, RISCV_IOMMU_REG_IOCOUNTOVF);
+ATTR_RW_REG32(iocntinh, RISCV_IOMMU_REG_IOCOUNTINH);
+ATTR_RW_REG64(iohpmcycles, RISCV_IOMMU_REG_IOHPMCYCLES);
+ATTR_RW_REG64(iohpmevt_1, RISCV_IOMMU_REG_IOHPMEVT(0));
+ATTR_RW_REG64(iohpmevt_2, RISCV_IOMMU_REG_IOHPMEVT(1));
+ATTR_RW_REG64(iohpmevt_3, RISCV_IOMMU_REG_IOHPMEVT(2));
+ATTR_RW_REG64(iohpmevt_4, RISCV_IOMMU_REG_IOHPMEVT(3));
+ATTR_RW_REG64(iohpmevt_5, RISCV_IOMMU_REG_IOHPMEVT(4));
+ATTR_RW_REG64(iohpmevt_6, RISCV_IOMMU_REG_IOHPMEVT(5));
+ATTR_RW_REG64(iohpmevt_7, RISCV_IOMMU_REG_IOHPMEVT(6));
+ATTR_RW_REG64(iohpmctr_1, RISCV_IOMMU_REG_IOHPMCTR(0));
+ATTR_RW_REG64(iohpmctr_2, RISCV_IOMMU_REG_IOHPMCTR(1));
+ATTR_RW_REG64(iohpmctr_3, RISCV_IOMMU_REG_IOHPMCTR(2));
+ATTR_RW_REG64(iohpmctr_4, RISCV_IOMMU_REG_IOHPMCTR(3));
+ATTR_RW_REG64(iohpmctr_5, RISCV_IOMMU_REG_IOHPMCTR(4));
+ATTR_RW_REG64(iohpmctr_6, RISCV_IOMMU_REG_IOHPMCTR(5));
+ATTR_RW_REG64(iohpmctr_7, RISCV_IOMMU_REG_IOHPMCTR(6));
+
+static struct attribute *riscv_iommu_attrs[] = {
+	&dev_attr_address.attr,
+	&dev_attr_reg_cap.attr,
+	&dev_attr_reg_fctl.attr,
+	&dev_attr_reg_cqh.attr,
+	&dev_attr_reg_cqt.attr,
+	&dev_attr_reg_cqcsr.attr,
+	&dev_attr_reg_fqh.attr,
+	&dev_attr_reg_fqt.attr,
+	&dev_attr_reg_fqcsr.attr,
+	&dev_attr_reg_pqh.attr,
+	&dev_attr_reg_pqt.attr,
+	&dev_attr_reg_pqcsr.attr,
+	&dev_attr_reg_ipsr.attr,
+	&dev_attr_reg_ivec.attr,
+	&dev_attr_reg_tr_iova.attr,
+	&dev_attr_reg_tr_ctrl.attr,
+	&dev_attr_reg_tr_response.attr,
+	&dev_attr_reg_iocntovf.attr,
+	&dev_attr_reg_iocntinh.attr,
+	&dev_attr_reg_iohpmcycles.attr,
+	&dev_attr_reg_iohpmctr_1.attr,
+	&dev_attr_reg_iohpmevt_1.attr,
+	&dev_attr_reg_iohpmctr_2.attr,
+	&dev_attr_reg_iohpmevt_2.attr,
+	&dev_attr_reg_iohpmctr_3.attr,
+	&dev_attr_reg_iohpmevt_3.attr,
+	&dev_attr_reg_iohpmctr_4.attr,
+	&dev_attr_reg_iohpmevt_4.attr,
+	&dev_attr_reg_iohpmctr_5.attr,
+	&dev_attr_reg_iohpmevt_5.attr,
+	&dev_attr_reg_iohpmctr_6.attr,
+	&dev_attr_reg_iohpmevt_6.attr,
+	&dev_attr_reg_iohpmctr_7.attr,
+	&dev_attr_reg_iohpmevt_7.attr,
+	NULL,
+};
+
+static struct attribute_group riscv_iommu_group = {
+	.name = "riscv-iommu",
+	.attrs = riscv_iommu_attrs,
+};
+
+const struct attribute_group *riscv_iommu_groups[] = {
+	&riscv_iommu_group,
+	NULL,
+};
+
+int riscv_iommu_sysfs_add(struct riscv_iommu_device *iommu) {
+	return iommu_device_sysfs_add(&iommu->iommu, NULL,
+		riscv_iommu_groups, "riscv-iommu@%llx", iommu->reg_phys);
+}
+
diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index 8c236242e2cc..31dc3c458e13 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -608,6 +608,7 @@  static const struct iommu_ops riscv_iommu_ops = {
 void riscv_iommu_remove(struct riscv_iommu_device *iommu)
 {
 	iommu_device_unregister(&iommu->iommu);
+	iommu_device_sysfs_remove(&iommu->iommu);
 	riscv_iommu_enable(iommu, RISCV_IOMMU_DDTP_MODE_OFF);
 }
 
@@ -646,6 +647,12 @@  int riscv_iommu_init(struct riscv_iommu_device *iommu)
 		goto fail;
 	}
 
+	ret = riscv_iommu_sysfs_add(iommu);
+	if (ret) {
+		dev_err(dev, "cannot register sysfs interface (%d)\n", ret);
+		goto fail;
+	}
+
 	ret = iommu_device_register(&iommu->iommu, &riscv_iommu_ops, dev);
 	if (ret) {
 		dev_err(dev, "cannot register iommu interface (%d)\n", ret);
diff --git a/drivers/iommu/riscv/iommu.h b/drivers/iommu/riscv/iommu.h
index 7baefd3630b3..7dc9baa59a50 100644
--- a/drivers/iommu/riscv/iommu.h
+++ b/drivers/iommu/riscv/iommu.h
@@ -112,4 +112,6 @@  static inline void riscv_iommu_writeq(struct riscv_iommu_device *iommu,
 int riscv_iommu_init(struct riscv_iommu_device *iommu);
 void riscv_iommu_remove(struct riscv_iommu_device *iommu);
 
+int riscv_iommu_sysfs_add(struct riscv_iommu_device *iommu);
+
 #endif