diff --git a/drivers/iommu/riscv/Kconfig b/drivers/iommu/riscv/Kconfig index c071816f59a67b..4f54117d38fc8f 100644 --- a/drivers/iommu/riscv/Kconfig +++ b/drivers/iommu/riscv/Kconfig @@ -18,3 +18,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_DEBUGFS + bool "RISC-V IOMMU Debugfs Support" + depends on RISCV_IOMMU + depends on IOMMU_DEBUGFS + help + Expose RISC-V IOMMU internals via debugfs. This includes + register dumps, queue status, and other hardware-specific + information useful for debugging. + + If unsure, say N. diff --git a/drivers/iommu/riscv/Makefile b/drivers/iommu/riscv/Makefile index b5929f9f23e648..9658a10d8b24bb 100644 --- a/drivers/iommu/riscv/Makefile +++ b/drivers/iommu/riscv/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only obj-y += iommu.o iommu-platform.o obj-$(CONFIG_RISCV_IOMMU_PCI) += iommu-pci.o +obj-$(CONFIG_RISCV_IOMMU_DEBUGFS) += debugfs.o diff --git a/drivers/iommu/riscv/debugfs.c b/drivers/iommu/riscv/debugfs.c new file mode 100644 index 00000000000000..52dc50a7fa20a2 --- /dev/null +++ b/drivers/iommu/riscv/debugfs.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include +#include + +#include "iommu.h" + +static const struct debugfs_reg32 riscv_iommu_regs[] = { + /* --- Global Configuration --- */ + { .name = "capabilities", .offset = RISCV_IOMMU_REG_CAPABILITIES }, + { .name = "fctl", .offset = RISCV_IOMMU_REG_FCTL }, + { .name = "ddtp", .offset = RISCV_IOMMU_REG_DDTP }, + /* --- Command Queue --- */ + { .name = "cqb", .offset = RISCV_IOMMU_REG_CQB }, + { .name = "cqh", .offset = RISCV_IOMMU_REG_CQH }, + { .name = "cqt", .offset = RISCV_IOMMU_REG_CQT }, + { .name = "cqcsr", .offset = RISCV_IOMMU_REG_CQCSR }, + /* --- Fault Queue --- */ + { .name = "fqb", .offset = RISCV_IOMMU_REG_FQB }, + { .name = "fqh", .offset = RISCV_IOMMU_REG_FQH }, + { .name = "fqt", .offset = RISCV_IOMMU_REG_FQT }, + { .name = "fqcsr", .offset = RISCV_IOMMU_REG_FQCSR }, + /* --- Interrupts --- */ + { .name = "ipsr", .offset = RISCV_IOMMU_REG_IPSR }, + { .name = "icvec", .offset = RISCV_IOMMU_REG_ICVEC }, +}; + +void riscv_iommu_debugfs_init(struct riscv_iommu_device *iommu) +{ + struct debugfs_regset32 *regset; + + if (!iommu_debugfs_dir) + return; + + iommu->debugfs_dir = debugfs_create_dir(dev_name(iommu->dev), iommu_debugfs_dir); + if (IS_ERR_OR_NULL(iommu->debugfs_dir)) + return; + + regset = devm_kzalloc(iommu->dev, sizeof(*regset), GFP_KERNEL); + if (!regset) + return; + + regset->regs = riscv_iommu_regs; + regset->nregs = ARRAY_SIZE(riscv_iommu_regs); + regset->base = iommu->reg; + + debugfs_create_regset32("registers", 0444, iommu->debugfs_dir, regset); +} + +void riscv_iommu_debugfs_remove(struct riscv_iommu_device *iommu) +{ + debugfs_remove_recursive(iommu->debugfs_dir); +} diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c index 2d8fb0859f30fc..ef1c4010c44274 100644 --- a/drivers/iommu/riscv/iommu.c +++ b/drivers/iommu/riscv/iommu.c @@ -1609,6 +1609,7 @@ void riscv_iommu_remove(struct riscv_iommu_device *iommu) riscv_iommu_iodir_set_mode(iommu, RISCV_IOMMU_DDTP_IOMMU_MODE_OFF); riscv_iommu_queue_disable(&iommu->cmdq); riscv_iommu_queue_disable(&iommu->fltq); + riscv_iommu_debugfs_remove(iommu); } int riscv_iommu_init(struct riscv_iommu_device *iommu) @@ -1669,6 +1670,8 @@ int riscv_iommu_init(struct riscv_iommu_device *iommu) goto err_remove_sysfs; } + riscv_iommu_debugfs_init(iommu); + return 0; err_remove_sysfs: diff --git a/drivers/iommu/riscv/iommu.h b/drivers/iommu/riscv/iommu.h index 46df79dd549570..1084e4e7745524 100644 --- a/drivers/iommu/riscv/iommu.h +++ b/drivers/iommu/riscv/iommu.h @@ -60,6 +60,10 @@ struct riscv_iommu_device { unsigned int ddt_mode; dma_addr_t ddt_phys; u64 *ddt_root; + +#ifdef CONFIG_RISCV_IOMMU_DEBUGFS + struct dentry *debugfs_dir; +#endif }; int riscv_iommu_init(struct riscv_iommu_device *iommu); @@ -86,4 +90,12 @@ void riscv_iommu_disable(struct riscv_iommu_device *iommu); readx_poll_timeout(readl_relaxed, (iommu)->reg + (addr), val, cond, \ delay_us, timeout_us) +#ifdef CONFIG_RISCV_IOMMU_DEBUGFS +void riscv_iommu_debugfs_init(struct riscv_iommu_device *iommu); +void riscv_iommu_debugfs_remove(struct riscv_iommu_device *iommu); +#else +static inline void riscv_iommu_debugfs_init(struct riscv_iommu_device *iommu) { } +static inline void riscv_iommu_debugfs_remove(struct riscv_iommu_device *iommu) { } +#endif + #endif