public inbox for linux-arm-kernel@lists.infradead.org
 help / color / mirror / Atom feed
* [RFC PATCH v2 2/5] iommu/arm-smmu-v3: Add register display to debugfs
  2026-03-28 10:09 [RFC PATCH v2 0/5] Add debugfs support for ARM SMMUv3 Qinxin Xia
@ 2026-03-28 10:09 ` Qinxin Xia
  0 siblings, 0 replies; 9+ messages in thread
From: Qinxin Xia @ 2026-03-28 10:09 UTC (permalink / raw)
  To: robin.murphy, nicolinc, will, jpb
  Cc: linux-arm-kernel, iommu, xiaqinxin, wangzhou1, prime.zeng,
	fanghao11, jonathan.cameron, wuyifan50, linuxarm

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="y", Size: 4059 bytes --]

Add register display functionality to debugfs.This allows reading
and displaying key SMMU register values including control registers
and queue pointers.

The registers file shows:
- CR0, CR1, CR2 control registers
- Command and Event queue pointers

Signed-off-by: Qinxin Xia <xiaqinxin@huawei.com>
---
 .../arm/arm-smmu-v3/arm-smmu-v3-debugfs.c     | 78 ++++++++++++++++++-
 1 file changed, 77 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c
index c764b28e5cfb..cfd296aebc9f 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c
@@ -5,13 +5,18 @@
  * Directory Structure:
  * /sys/kernel/debug/iommu/arm_smmu_v3/
  * └── smmu<ioaddr>/
- *     └── capabilities    # SMMU feature capabilities and configuration
+ *     ├── capabilities    # SMMU feature capabilities and configuration
+ *     └── registers	   # SMMU Key registers
  *
  * The capabilities file provides detailed information about:
  * - translation stage support (Stage1/Stage2)
  * - System coherency, ATS, and PRI feature availability
  * - Stream table size and command/event queue depths
  *
+ * The registers display provides crucial visibility into:
+ * - CR0, CR1, CR2 control registers
+ * - Command and Event queue pointers
+ *
  * Copyright (C) 2026 HiSilicon Limited.
  * Author: Qinxin Xia <xiaqinxin@huawei.com>
  */
@@ -89,6 +94,74 @@ static const struct file_operations smmu_debugfs_capabilities_fops = {
 	.release = smmu_debugfs_capabilities_release,
 };
 
+/**
+ * smmu_debugfs_registers_show() - Display SMMU register values
+ * @seq: seq_file to write to
+ *
+ * Errors are reported via seq_puts, the function always returns 0
+ */
+static int smmu_debugfs_registers_show(struct seq_file *seq, void *unused)
+{
+	struct arm_smmu_device *smmu = seq->private;
+	void __iomem *base;
+
+	if (!smmu || !smmu->base) {
+		seq_puts(seq, "SMMU not available\n");
+		return 0;
+	}
+
+	base = smmu->base;
+
+	seq_puts(seq, "SMMUv3 Key Registers:\n");
+
+	/* 32-bit control registers */
+	seq_printf(seq, "CR0: 0x%08x\n", readl_relaxed(base + ARM_SMMU_CR0));
+	seq_printf(seq, "CR1: 0x%08x\n", readl_relaxed(base + ARM_SMMU_CR1));
+	seq_printf(seq, "CR2: 0x%08x\n", readl_relaxed(base + ARM_SMMU_CR2));
+
+	/* 32-bit queue pointer registers */
+	seq_printf(seq, "CMDQ_PROD: 0x%08x\n",
+		   readl_relaxed(base + ARM_SMMU_CMDQ_PROD));
+	seq_printf(seq, "CMDQ_CONS: 0x%08x\n",
+		   readl_relaxed(base + ARM_SMMU_CMDQ_CONS));
+	seq_printf(seq, "EVTQ_PROD: 0x%08x\n",
+		   readl_relaxed(base + ARM_SMMU_EVTQ_PROD));
+	seq_printf(seq, "EVTQ_CONS: 0x%08x\n",
+		   readl_relaxed(base + ARM_SMMU_EVTQ_CONS));
+
+	return 0;
+}
+
+static int smmu_debugfs_registers_open(struct inode *inode, struct file *file)
+{
+	struct arm_smmu_device *smmu = inode->i_private;
+
+	if (!smmu || !get_device(smmu->dev))
+		return -ENODEV;
+
+	return single_open(file, smmu_debugfs_registers_show, smmu);
+}
+
+static int smmu_debugfs_registers_release(struct inode *inode, struct file *file)
+{
+	struct seq_file *seq = file->private_data;
+	struct arm_smmu_device *smmu = seq->private;
+
+	single_release(inode, file);
+	if (smmu)
+		put_device(smmu->dev);
+
+	return 0;
+}
+
+static const struct file_operations smmu_debugfs_registers_fops = {
+	.owner   = THIS_MODULE,
+	.open    = smmu_debugfs_registers_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = smmu_debugfs_registers_release,
+};
+
 /**
  * arm_smmu_debugfs_setup() - Initialize debugfs for SMMU device
  * @smmu: SMMU device to setup debugfs for
@@ -134,6 +207,9 @@ int arm_smmu_debugfs_setup(struct arm_smmu_device *smmu, const char *name)
 	debugfs_create_file("capabilities", 0444, smmu_dir, smmu,
 			    &smmu_debugfs_capabilities_fops);
 
+	debugfs_create_file("registers", 0444, smmu_dir, smmu,
+			    &smmu_debugfs_registers_fops);
+
 	dev_dbg(smmu->dev, "debugfs initialized for %s\n", name);
 	return 0;
 }
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [RFC PATCH v2 0/5] Add debugfs support for ARM SMMUv3
@ 2026-03-28 10:17 Qinxin Xia
  2026-03-28 10:17 ` [RFC PATCH v2 1/5] iommu/arm-smmu-v3: Add basic debugfs framework Qinxin Xia
                   ` (4 more replies)
  0 siblings, 5 replies; 9+ messages in thread
From: Qinxin Xia @ 2026-03-28 10:17 UTC (permalink / raw)
  To: robin.murphy, nicolinc, will, jpb
  Cc: linux-arm-kernel, iommu, xiaqinxin, wangzhou1, prime.zeng,
	fanghao11, jonathan.cameron, wuyifan50, linuxarm

Add a comprehensive debugfs framework to the ARM SMMUv3 driver,                                                                                                                                                                                                                                                       
providing visibility into internal hardware state for debugging
and performance analysis. The debugfs entries are organized under
/sys/kernel/debug/iommu/arm_smmu_v3/, with per-SMMU instance directories
and per-device stream table entries.
                 
Each SMMU instance provides:
- capabilities – static SMMU features and queue sizes.
- registers – SMMU key registers.
- stream_table/ – a directory per device with subdirectories per Stream ID. 
                 
Each Stream ID subdirectory contains:
- ste – the Stream Table Entry in decoded and raw format.
- cd – all valid Context Descriptors (Stage 1 translation tables) associated with the device.
- a symlink named with the device’s BDF/name pointing to its sysfs directory for easy navigation.
                 
/sys/kernel/debug/iommu/arm_smmu_v3/smmu0/stream_table/
└── <sid>/       
    ├─── ste  
    ├─── cd   
    └─── <dev_name>

Changes since V1:
  Address the comments from Nicolin:
  1.Fixed the incorrect comments and replaced 'kzalloc' with 'kzalloc_obj'
  2.'stream_table_create/stream_table_remove' is called in probe_device/release_device
  3.Reused some functions in the driver

  Address the comments from Robin:
  1.Remove unnecessary CR0*EN extra strings
  2.Remove the limit on ssid

  Address the comments from Robin and Nicolin:
  1.The directory structure has been changed
  2.Added lock protection for the ste_show and cd_show

  Others:
  1.'arm_smmu_debugfs_remove' is added to remove the corresponding debugfs when SMMU device is removed
  2.'arm_smmu_debugfs_remove_stream_table' is added to remove the corresponding stream_dir when device is removed
  3.Use scoped_guard for locks that include return
  4.Added 'open' and 'release' operations to prevent the device from being released during dump
  5.Merged 'stream_table_create' and 'ste_show' into one patch
  6.Some other clean code

- Link: https://lore.kernel.org/all/20260313104351.3502293-1-xiaqinxin@huawei.com/

Qinxin Xia (5):
  iommu/arm-smmu-v3: Add basic debugfs framework
  iommu/arm-smmu-v3: Add register display to debugfs
  iommu/arm-smmu-v3: Add Stream Table Entry display to debugfs
  iommu/arm-smmu-v3: Add device symlink in stream table debugfs
  iommu/arm-smmu-v3: Add Context Descriptor display to debugfs

 drivers/iommu/Kconfig                         |  11 +
 drivers/iommu/arm/arm-smmu-v3/Makefile        |   1 +
 .../arm/arm-smmu-v3/arm-smmu-v3-debugfs.c     | 571 ++++++++++++++++++
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   |  33 +-
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  32 +
 5 files changed, 646 insertions(+), 2 deletions(-)
 create mode 100644 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c

-- 
2.33.0



^ permalink raw reply	[flat|nested] 9+ messages in thread

* [RFC PATCH v2 1/5] iommu/arm-smmu-v3: Add basic debugfs framework
  2026-03-28 10:17 [RFC PATCH v2 0/5] Add debugfs support for ARM SMMUv3 Qinxin Xia
@ 2026-03-28 10:17 ` Qinxin Xia
  2026-03-30 10:46   ` Nicolin Chen
  2026-03-28 10:17 ` [RFC PATCH v2 2/5] iommu/arm-smmu-v3: Add register display to debugfs Qinxin Xia
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 9+ messages in thread
From: Qinxin Xia @ 2026-03-28 10:17 UTC (permalink / raw)
  To: robin.murphy, nicolinc, will, jpb
  Cc: linux-arm-kernel, iommu, xiaqinxin, wangzhou1, prime.zeng,
	fanghao11, jonathan.cameron, wuyifan50, linuxarm

Add basic debugfs framework for ARM SMMUv3 driver.This creates the
root directory structure and provides capability display functionality.

The debugfs hierarchy is organized as:
/sys/kernel/debug/iommu/arm_smmu_v3/
└── smmu<ioaddr>/
    └── capabilities

Signed-off-by: Qinxin Xia <xiaqinxin@huawei.com>
---
 drivers/iommu/Kconfig                         |  11 ++
 drivers/iommu/arm/arm-smmu-v3/Makefile        |   1 +
 .../arm/arm-smmu-v3/arm-smmu-v3-debugfs.c     | 163 ++++++++++++++++++
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   |  15 ++
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  15 ++
 5 files changed, 205 insertions(+)
 create mode 100644 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c

diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index f86262b11416..f28f09adba03 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -93,6 +93,17 @@ config IOMMU_DEBUGFS
 	  debug/iommu directory, and then populate a subdirectory with
 	  entries as required.
 
+config ARM_SMMU_V3_DEBUGFS
+	bool "ARM SMMUv3 DebugFS support"
+	depends on ARM_SMMU_V3 && IOMMU_DEBUGFS
+	help
+	  Expose ARM SMMUv3 internal state via debugfs for debugging and
+	  diagnostics. This creates /sys/kernel/debug/iommu/arm_smmu_v3/
+	  with detailed information about SMMU configuration, stream tables,
+	  and context descriptors.
+
+	  Say N unless you are debugging SMMU issues.
+
 choice
 	prompt "IOMMU default domain type"
 	depends on IOMMU_API
diff --git a/drivers/iommu/arm/arm-smmu-v3/Makefile b/drivers/iommu/arm/arm-smmu-v3/Makefile
index 493a659cc66b..787538fb7054 100644
--- a/drivers/iommu/arm/arm-smmu-v3/Makefile
+++ b/drivers/iommu/arm/arm-smmu-v3/Makefile
@@ -4,5 +4,6 @@ arm_smmu_v3-y := arm-smmu-v3.o
 arm_smmu_v3-$(CONFIG_ARM_SMMU_V3_IOMMUFD) += arm-smmu-v3-iommufd.o
 arm_smmu_v3-$(CONFIG_ARM_SMMU_V3_SVA) += arm-smmu-v3-sva.o
 arm_smmu_v3-$(CONFIG_TEGRA241_CMDQV) += tegra241-cmdqv.o
+arm_smmu_v3-$(CONFIG_ARM_SMMU_V3_DEBUGFS) += arm-smmu-v3-debugfs.o
 
 obj-$(CONFIG_ARM_SMMU_V3_KUNIT_TEST) += arm-smmu-v3-test.o
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c
new file mode 100644
index 000000000000..c764b28e5cfb
--- /dev/null
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ARM SMMUv3 DebugFS Support
+ *
+ * Directory Structure:
+ * /sys/kernel/debug/iommu/arm_smmu_v3/
+ * └── smmu<ioaddr>/
+ *     └── capabilities    # SMMU feature capabilities and configuration
+ *
+ * The capabilities file provides detailed information about:
+ * - translation stage support (Stage1/Stage2)
+ * - System coherency, ATS, and PRI feature availability
+ * - Stream table size and command/event queue depths
+ *
+ * Copyright (C) 2026 HiSilicon Limited.
+ * Author: Qinxin Xia <xiaqinxin@huawei.com>
+ */
+
+#include <linux/cleanup.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include "arm-smmu-v3.h"
+
+static struct dentry *smmu_debugfs_root;
+static DEFINE_MUTEX(arm_smmu_debugfs_lock);
+
+/**
+ * smmu_debugfs_capabilities_show() - Display SMMU capabilities
+ * @seq: seq_file to write to
+ *
+ * Errors are reported via seq_puts, the function always returns 0
+ */
+static int smmu_debugfs_capabilities_show(struct seq_file *seq, void *unused)
+{
+	struct arm_smmu_device *smmu = seq->private;
+
+	if (!smmu) {
+		seq_puts(seq, "SMMU not available\n");
+		return 0;
+	}
+
+	seq_puts(seq, "SMMUv3 Capabilities:\n");
+	seq_printf(seq, "  Stage1 Translation: %s\n",
+		   smmu->features & ARM_SMMU_FEAT_TRANS_S1 ? "Yes" : "No");
+	seq_printf(seq, "  Stage2 Translation: %s\n",
+		   smmu->features & ARM_SMMU_FEAT_TRANS_S2 ? "Yes" : "No");
+	seq_printf(seq, "  Coherent Walk: %s\n",
+		   smmu->features & ARM_SMMU_FEAT_COHERENCY ? "Yes" : "No");
+	seq_printf(seq, "  ATS Support: %s\n",
+		   smmu->features & ARM_SMMU_FEAT_ATS ? "Yes" : "No");
+	seq_printf(seq, "  PRI Support: %s\n",
+		   smmu->features & ARM_SMMU_FEAT_PRI ? "Yes" : "No");
+	seq_printf(seq, "  Stream Table Size: %d\n", 1 << smmu->sid_bits);
+	seq_printf(seq, "  Command Queue Depth: %d\n",
+		   1 << smmu->cmdq.q.llq.max_n_shift);
+	seq_printf(seq, "  Event Queue Depth: %d\n",
+		   1 << smmu->evtq.q.llq.max_n_shift);
+
+	return 0;
+}
+
+static int smmu_debugfs_capabilities_open(struct inode *inode, struct file *file)
+{
+	struct arm_smmu_device *smmu = inode->i_private;
+
+	if (!smmu || !get_device(smmu->dev))
+		return -ENODEV;
+
+	return single_open(file, smmu_debugfs_capabilities_show, smmu);
+}
+
+static int smmu_debugfs_capabilities_release(struct inode *inode, struct file *file)
+{
+	struct seq_file *seq = file->private_data;
+	struct arm_smmu_device *smmu = seq->private;
+
+	single_release(inode, file);
+	if (smmu)
+		put_device(smmu->dev);
+
+	return 0;
+}
+
+static const struct file_operations smmu_debugfs_capabilities_fops = {
+	.owner   = THIS_MODULE,
+	.open    = smmu_debugfs_capabilities_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = smmu_debugfs_capabilities_release,
+};
+
+/**
+ * arm_smmu_debugfs_setup() - Initialize debugfs for SMMU device
+ * @smmu: SMMU device to setup debugfs for
+ * @name: SMMU device name
+ *
+ * This function creates the basic debugfs directory structure for an SMMU device.
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+int arm_smmu_debugfs_setup(struct arm_smmu_device *smmu, const char *name)
+{
+	struct arm_smmu_debugfs *debugfs;
+	struct dentry *smmu_dir;
+
+	/* Create root directory if it doesn't exist */
+	scoped_guard(mutex, &arm_smmu_debugfs_lock) {
+		if (!smmu_debugfs_root) {
+			/* Once created, it will not be removed */
+			smmu_debugfs_root = debugfs_create_dir("arm_smmu_v3",
+							       iommu_debugfs_dir);
+			if (!smmu_debugfs_root)
+				return -ENOMEM;
+		}
+	}
+
+	/* Allocate debugfs structure */
+	debugfs = kzalloc_obj(*debugfs);
+	if (!debugfs)
+		return -ENOMEM;
+
+	/* Create SMMU instance directory */
+	smmu_dir = debugfs_create_dir(name, smmu_debugfs_root);
+	if (!smmu_dir) {
+		kfree(debugfs);
+		smmu->debugfs = NULL;
+		return -ENOMEM;
+	}
+
+	debugfs->smmu_dir = smmu_dir;
+	smmu->debugfs = debugfs;
+
+	/* Create capabilities file */
+	debugfs_create_file("capabilities", 0444, smmu_dir, smmu,
+			    &smmu_debugfs_capabilities_fops);
+
+	dev_dbg(smmu->dev, "debugfs initialized for %s\n", name);
+	return 0;
+}
+
+/**
+ * arm_smmu_debugfs_remove() - Clean up debugfs entries for an SMMU device
+ * @smmu: SMMU device
+ *
+ * This function removes the debugfs directories created by setup.
+ */
+void arm_smmu_debugfs_remove(struct arm_smmu_device *smmu)
+{
+	struct arm_smmu_debugfs *debugfs;
+
+	scoped_guard(mutex, &arm_smmu_debugfs_lock) {
+		debugfs = smmu->debugfs;
+		if (!debugfs)
+			return;
+
+		/* Remove the entire SMMU instance directory */
+		debugfs_remove_recursive(debugfs->smmu_dir);
+
+		/* Free the debugfs structure */
+		kfree(debugfs);
+		smmu->debugfs = NULL;
+	}
+}
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 4d00d796f078..cbb3fccc501b 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -4904,6 +4904,15 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
 	/* Check for RMRs and install bypass STEs if any */
 	arm_smmu_rmr_install_bypass_ste(smmu);
 
+#ifdef CONFIG_ARM_SMMU_V3_DEBUGFS
+	char name[32];
+
+	snprintf(name, sizeof(name), "smmu3.%pa", &ioaddr);
+	ret = arm_smmu_debugfs_setup(smmu, name);
+	if (ret)
+		dev_warn(dev, "Failed to create debugfs!\n");
+#endif
+
 	/* Reset the device */
 	ret = arm_smmu_device_reset(smmu);
 	if (ret)
@@ -4926,6 +4935,9 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
 err_free_sysfs:
 	iommu_device_sysfs_remove(&smmu->iommu);
 err_disable:
+#ifdef CONFIG_ARM_SMMU_V3_DEBUGFS
+	arm_smmu_debugfs_remove(smmu);
+#endif
 	arm_smmu_device_disable(smmu);
 err_free_iopf:
 	iopf_queue_free(smmu->evtq.iopf);
@@ -4938,6 +4950,9 @@ static void arm_smmu_device_remove(struct platform_device *pdev)
 
 	iommu_device_unregister(&smmu->iommu);
 	iommu_device_sysfs_remove(&smmu->iommu);
+#ifdef CONFIG_ARM_SMMU_V3_DEBUGFS
+	arm_smmu_debugfs_remove(smmu);
+#endif
 	arm_smmu_device_disable(smmu);
 	iopf_queue_free(smmu->evtq.iopf);
 	ida_destroy(&smmu->vmid_map);
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index 3c6d65d36164..a54d72fb9e07 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -733,6 +733,16 @@ struct arm_smmu_impl_ops {
 			  const struct iommu_user_data *user_data);
 };
 
+#ifdef CONFIG_ARM_SMMU_V3_DEBUGFS
+struct arm_smmu_debugfs {
+	struct dentry			*smmu_dir;
+	/* Reserved for future extensions */
+};
+
+int arm_smmu_debugfs_setup(struct arm_smmu_device *smmu, const char *name);
+void arm_smmu_debugfs_remove(struct arm_smmu_device *smmu);
+#endif
+
 /* An SMMUv3 instance */
 struct arm_smmu_device {
 	struct device			*dev;
@@ -803,6 +813,11 @@ struct arm_smmu_device {
 
 	struct rb_root			streams;
 	struct mutex			streams_mutex;
+
+#ifdef CONFIG_ARM_SMMU_V3_DEBUGFS
+	/* DebugFS Info */
+	struct arm_smmu_debugfs		*debugfs;
+#endif
 };
 
 struct arm_smmu_stream {
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [RFC PATCH v2 2/5] iommu/arm-smmu-v3: Add register display to debugfs
  2026-03-28 10:17 [RFC PATCH v2 0/5] Add debugfs support for ARM SMMUv3 Qinxin Xia
  2026-03-28 10:17 ` [RFC PATCH v2 1/5] iommu/arm-smmu-v3: Add basic debugfs framework Qinxin Xia
@ 2026-03-28 10:17 ` Qinxin Xia
  2026-03-30 11:25   ` Nicolin Chen
  2026-03-28 10:17 ` [RFC PATCH v2 3/5] iommu/arm-smmu-v3: Add Stream Table Entry " Qinxin Xia
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 9+ messages in thread
From: Qinxin Xia @ 2026-03-28 10:17 UTC (permalink / raw)
  To: robin.murphy, nicolinc, will, jpb
  Cc: linux-arm-kernel, iommu, xiaqinxin, wangzhou1, prime.zeng,
	fanghao11, jonathan.cameron, wuyifan50, linuxarm

Add register display functionality to debugfs.This allows reading
and displaying key SMMU register values including control registers
and queue pointers.

The registers file shows:
- CR0, CR1, CR2 control registers
- Command and Event queue pointers

Signed-off-by: Qinxin Xia <xiaqinxin@huawei.com>
---
 .../arm/arm-smmu-v3/arm-smmu-v3-debugfs.c     | 78 ++++++++++++++++++-
 1 file changed, 77 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c
index c764b28e5cfb..cfd296aebc9f 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c
@@ -5,13 +5,18 @@
  * Directory Structure:
  * /sys/kernel/debug/iommu/arm_smmu_v3/
  * └── smmu<ioaddr>/
- *     └── capabilities    # SMMU feature capabilities and configuration
+ *     ├── capabilities    # SMMU feature capabilities and configuration
+ *     └── registers	   # SMMU Key registers
  *
  * The capabilities file provides detailed information about:
  * - translation stage support (Stage1/Stage2)
  * - System coherency, ATS, and PRI feature availability
  * - Stream table size and command/event queue depths
  *
+ * The registers display provides crucial visibility into:
+ * - CR0, CR1, CR2 control registers
+ * - Command and Event queue pointers
+ *
  * Copyright (C) 2026 HiSilicon Limited.
  * Author: Qinxin Xia <xiaqinxin@huawei.com>
  */
@@ -89,6 +94,74 @@ static const struct file_operations smmu_debugfs_capabilities_fops = {
 	.release = smmu_debugfs_capabilities_release,
 };
 
+/**
+ * smmu_debugfs_registers_show() - Display SMMU register values
+ * @seq: seq_file to write to
+ *
+ * Errors are reported via seq_puts, the function always returns 0
+ */
+static int smmu_debugfs_registers_show(struct seq_file *seq, void *unused)
+{
+	struct arm_smmu_device *smmu = seq->private;
+	void __iomem *base;
+
+	if (!smmu || !smmu->base) {
+		seq_puts(seq, "SMMU not available\n");
+		return 0;
+	}
+
+	base = smmu->base;
+
+	seq_puts(seq, "SMMUv3 Key Registers:\n");
+
+	/* 32-bit control registers */
+	seq_printf(seq, "CR0: 0x%08x\n", readl_relaxed(base + ARM_SMMU_CR0));
+	seq_printf(seq, "CR1: 0x%08x\n", readl_relaxed(base + ARM_SMMU_CR1));
+	seq_printf(seq, "CR2: 0x%08x\n", readl_relaxed(base + ARM_SMMU_CR2));
+
+	/* 32-bit queue pointer registers */
+	seq_printf(seq, "CMDQ_PROD: 0x%08x\n",
+		   readl_relaxed(base + ARM_SMMU_CMDQ_PROD));
+	seq_printf(seq, "CMDQ_CONS: 0x%08x\n",
+		   readl_relaxed(base + ARM_SMMU_CMDQ_CONS));
+	seq_printf(seq, "EVTQ_PROD: 0x%08x\n",
+		   readl_relaxed(base + ARM_SMMU_EVTQ_PROD));
+	seq_printf(seq, "EVTQ_CONS: 0x%08x\n",
+		   readl_relaxed(base + ARM_SMMU_EVTQ_CONS));
+
+	return 0;
+}
+
+static int smmu_debugfs_registers_open(struct inode *inode, struct file *file)
+{
+	struct arm_smmu_device *smmu = inode->i_private;
+
+	if (!smmu || !get_device(smmu->dev))
+		return -ENODEV;
+
+	return single_open(file, smmu_debugfs_registers_show, smmu);
+}
+
+static int smmu_debugfs_registers_release(struct inode *inode, struct file *file)
+{
+	struct seq_file *seq = file->private_data;
+	struct arm_smmu_device *smmu = seq->private;
+
+	single_release(inode, file);
+	if (smmu)
+		put_device(smmu->dev);
+
+	return 0;
+}
+
+static const struct file_operations smmu_debugfs_registers_fops = {
+	.owner   = THIS_MODULE,
+	.open    = smmu_debugfs_registers_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = smmu_debugfs_registers_release,
+};
+
 /**
  * arm_smmu_debugfs_setup() - Initialize debugfs for SMMU device
  * @smmu: SMMU device to setup debugfs for
@@ -134,6 +207,9 @@ int arm_smmu_debugfs_setup(struct arm_smmu_device *smmu, const char *name)
 	debugfs_create_file("capabilities", 0444, smmu_dir, smmu,
 			    &smmu_debugfs_capabilities_fops);
 
+	debugfs_create_file("registers", 0444, smmu_dir, smmu,
+			    &smmu_debugfs_registers_fops);
+
 	dev_dbg(smmu->dev, "debugfs initialized for %s\n", name);
 	return 0;
 }
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [RFC PATCH v2 3/5] iommu/arm-smmu-v3: Add Stream Table Entry display to debugfs
  2026-03-28 10:17 [RFC PATCH v2 0/5] Add debugfs support for ARM SMMUv3 Qinxin Xia
  2026-03-28 10:17 ` [RFC PATCH v2 1/5] iommu/arm-smmu-v3: Add basic debugfs framework Qinxin Xia
  2026-03-28 10:17 ` [RFC PATCH v2 2/5] iommu/arm-smmu-v3: Add register display to debugfs Qinxin Xia
@ 2026-03-28 10:17 ` Qinxin Xia
  2026-03-28 10:17 ` [RFC PATCH v2 4/5] iommu/arm-smmu-v3: Add device symlink in stream table debugfs Qinxin Xia
  2026-03-28 10:17 ` [RFC PATCH v2 5/5] iommu/arm-smmu-v3: Add Context Descriptor display to debugfs Qinxin Xia
  4 siblings, 0 replies; 9+ messages in thread
From: Qinxin Xia @ 2026-03-28 10:17 UTC (permalink / raw)
  To: robin.murphy, nicolinc, will, jpb
  Cc: linux-arm-kernel, iommu, xiaqinxin, wangzhou1, prime.zeng,
	fanghao11, jonathan.cameron, wuyifan50, linuxarm

Add Stream Table Entry (STE) display functionality to debugfs.
This allow inspecting STE contents for each device stream including:
- STE validity and configuration
- Stage 1 and Stage 2 context pointers
- Raw STE data

/sys/kernel/debug/iommu/arm_smmu_v3/smmu0/stream_table/
└── <sid>/
    └─── ste

Signed-off-by: Qinxin Xia <xiaqinxin@huawei.com>
---
 .../arm/arm-smmu-v3/arm-smmu-v3-debugfs.c     | 224 +++++++++++++++++-
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   |  18 +-
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  17 ++
 3 files changed, 256 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c
index cfd296aebc9f..70623b480d64 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c
@@ -6,7 +6,10 @@
  * /sys/kernel/debug/iommu/arm_smmu_v3/
  * └── smmu<ioaddr>/
  *     ├── capabilities    # SMMU feature capabilities and configuration
- *     └── registers	   # SMMU Key registers
+ *     ├── registers	   # SMMU Key registers
+ *     └── stream_table
+ *	   └─── <sid>/                                # Stream ID 0
+ *	       └── ste                                # Stream Table Entry
  *
  * The capabilities file provides detailed information about:
  * - translation stage support (Stage1/Stage2)
@@ -17,6 +20,11 @@
  * - CR0, CR1, CR2 control registers
  * - Command and Event queue pointers
  *
+ * The STE Information Displayed:
+ * - STE validity and configuration
+ * - Stage 1 and Stage 2 context pointers
+ * - Raw STE data
+ *
  * Copyright (C) 2026 HiSilicon Limited.
  * Author: Qinxin Xia <xiaqinxin@huawei.com>
  */
@@ -162,6 +170,218 @@ static const struct file_operations smmu_debugfs_registers_fops = {
 	.release = smmu_debugfs_registers_release,
 };
 
+/**
+ * smmu_debugfs_ste_show() - Dump STE details to seq_file
+ * @seq: seq_file to write to
+ *
+ * Errors are reported via seq_puts, the function always returns 0
+ */
+static int smmu_debugfs_ste_show(struct seq_file *seq, void *unused)
+{
+	struct ste_context *ctx = seq->private;
+	struct arm_smmu_master *master = ctx->master;
+	struct arm_smmu_device *smmu;
+	struct arm_smmu_ste *ste;
+	u32 sid, cfg;
+	int i;
+
+	if (!master) {
+		seq_puts(seq, "No SMMU master data\n");
+		return 0;
+	}
+
+	smmu = master->smmu;
+	scoped_guard(mutex, &smmu->streams_mutex) {
+		sid = ctx->sid;
+
+		if (!arm_smmu_sid_in_range(smmu, sid)) {
+			seq_printf(seq, "Invalid Stream ID: %u (max %u)\n",
+				   sid, (1 << smmu->sid_bits) - 1);
+			return 0;
+		}
+
+		ste = arm_smmu_get_step_for_sid(smmu, sid);
+		if (!ste) {
+			seq_printf(seq, "STE not available for SID %u\n", sid);
+			return 0;
+		}
+
+		seq_printf(seq, "STE for Stream ID %u\n", sid);
+		seq_printf(seq, "  Valid: %s\n",
+			   le64_to_cpu(ste->data[0]) & STRTAB_STE_0_V ? "Yes" : "No");
+
+		seq_puts(seq, "  Config: ");
+
+		cfg = FIELD_GET(STRTAB_STE_0_CFG, le64_to_cpu(ste->data[0]));
+
+		switch (cfg) {
+		case STRTAB_STE_0_CFG_BYPASS:
+			seq_puts(seq, "BYPASS\n");
+			break;
+		case STRTAB_STE_0_CFG_S1_TRANS:
+			seq_puts(seq, "only S1_TRANS\n");
+			break;
+		case STRTAB_STE_0_CFG_S2_TRANS:
+			seq_puts(seq, "only S2_TRANS\n");
+			break;
+		case STRTAB_STE_0_CFG_NESTED:
+			seq_puts(seq, "S1+S2_TRANS\n");
+			break;
+		case STRTAB_STE_0_CFG_ABORT:
+			seq_puts(seq, "ABORT\n");
+			break;
+		default:
+			seq_puts(seq, "UNKNOWN\n");
+		}
+
+		if (le64_to_cpu(ste->data[0]) & STRTAB_STE_0_CFG_S1_TRANS) {
+			seq_printf(seq, "  S1ContextPtr: 0x%016llx\n",
+				   le64_to_cpu(ste->data[1]) & STRTAB_STE_0_S1CTXPTR_MASK);
+		}
+
+		if (le64_to_cpu(ste->data[0]) & STRTAB_STE_0_CFG_S2_TRANS) {
+			seq_printf(seq, "  S2ContextPtr: 0x%016llx\n",
+				   le64_to_cpu(ste->data[3]) & STRTAB_STE_3_S2TTB_MASK);
+		}
+
+		/* Display raw STE data */
+		seq_puts(seq, "  Raw Data:\n");
+		for (i = 0; i < STRTAB_STE_DWORDS; i++)
+			seq_printf(seq, "    STE[%d]: 0x%016llx\n", i,
+				   le64_to_cpu(ste->data[i]));
+	}
+		return 0;
+}
+
+static int smmu_debugfs_ste_open(struct inode *inode, struct file *file)
+{
+	struct ste_context *ctx = inode->i_private;
+
+	if (!ctx || !get_device(ctx->master->dev))
+		return -ENODEV;
+
+	return single_open(file, smmu_debugfs_ste_show, ctx);
+}
+
+static int smmu_debugfs_ste_release(struct inode *inode, struct file *file)
+{
+	struct seq_file *seq = file->private_data;
+	struct ste_context *ctx = seq->private;
+
+	single_release(inode, file);
+	if (ctx)
+		put_device(ctx->master->dev);
+	return 0;
+}
+
+static const struct file_operations smmu_debugfs_ste_fops = {
+	.owner   = THIS_MODULE,
+	.open    = smmu_debugfs_ste_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = smmu_debugfs_ste_release,
+};
+
+/**
+ * arm_smmu_debugfs_create_stream_table() - Create debugfs entries for stream table
+ * @dev: device to create entries for
+ * @smmu: SMMU device
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+int arm_smmu_debugfs_create_stream_table(struct device *dev,
+					 struct arm_smmu_device *smmu)
+{
+	struct dentry *stream_dir, *dev_dir;
+	struct arm_smmu_master *master;
+	struct ste_context *ctx;
+	char name[64];
+	u32 sid;
+	int i;
+
+	scoped_guard(mutex, &arm_smmu_debugfs_lock) {
+		if (!smmu->debugfs->stream_dir) {
+			stream_dir = debugfs_create_dir("stream_table",
+							smmu->debugfs->smmu_dir);
+			if (!stream_dir)
+				return -ENOMEM;
+
+			smmu->debugfs->stream_dir = stream_dir;
+		} else {
+			stream_dir = smmu->debugfs->stream_dir;
+		}
+	}
+
+	master = dev_iommu_priv_get(dev);
+	if (!master || !master->num_streams)
+		return -ENODEV;
+
+	for (i = 0; i < master->num_streams; i++) {
+		sid = master->streams[i].id;
+		snprintf(name, sizeof(name), "%u", sid);
+		dev_dir = debugfs_create_dir(name, stream_dir);
+		if (!dev_dir)
+			continue;
+
+		/* Create STE file */
+		ctx = kzalloc_obj(*ctx);
+		ctx->master = master;
+		ctx->sid = sid;
+		spin_lock(&smmu->debugfs->stream_lock);
+		list_add_tail(&ctx->node, &smmu->debugfs->stream_list);
+		spin_unlock(&smmu->debugfs->stream_lock);
+		debugfs_create_file("ste", 0444, dev_dir, ctx,
+				    &smmu_debugfs_ste_fops);
+
+	}
+
+	return 0;
+}
+
+/**
+ * arm_smmu_debugfs_remove_stream_table() - Remove debugfs entries for stream table
+ * @dev: device to remove entries for
+ * @smmu: SMMU device
+ *
+ * This function removes the debugfs directories created by
+ * arm_smmu_debugfs_create_stream_table().
+ */
+void arm_smmu_debugfs_remove_stream_table(struct device *dev,
+				      struct arm_smmu_device *smmu)
+{
+	struct dentry *stream_dir, *dev_dir;
+	struct arm_smmu_master *master;
+	struct ste_context *ctx, *tmp;
+	char name[64];
+	int i;
+
+	/* Check if stream_table directory exists */
+	if (!smmu->debugfs || !smmu->debugfs->stream_dir)
+		return;
+
+	stream_dir = smmu->debugfs->stream_dir;
+	master = dev_iommu_priv_get(dev);
+	if (!master)
+		return;
+
+	/* Remove directories for each stream ID */
+	for (i = 0; i < master->num_streams; i++) {
+		snprintf(name, sizeof(name), "%u", master->streams[i].id);
+		dev_dir = debugfs_lookup(name, stream_dir);
+		debugfs_remove_recursive(dev_dir);
+	}
+
+	/* Free stream context */
+	spin_lock(&smmu->debugfs->stream_lock);
+	list_for_each_entry_safe(ctx, tmp, &smmu->debugfs->stream_list, node) {
+		if (ctx->master->dev == dev) {
+			list_del(&ctx->node);
+			kfree(ctx);
+		}
+	}
+	spin_unlock(&smmu->debugfs->stream_lock);
+}
+
 /**
  * arm_smmu_debugfs_setup() - Initialize debugfs for SMMU device
  * @smmu: SMMU device to setup debugfs for
@@ -201,6 +421,8 @@ int arm_smmu_debugfs_setup(struct arm_smmu_device *smmu, const char *name)
 	}
 
 	debugfs->smmu_dir = smmu_dir;
+	INIT_LIST_HEAD(&debugfs->stream_list);
+	spin_lock_init(&debugfs->stream_lock);
 	smmu->debugfs = debugfs;
 
 	/* Create capabilities file */
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index cbb3fccc501b..6be132b2f3f0 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2654,7 +2654,10 @@ static int arm_smmu_domain_finalise(struct arm_smmu_domain *smmu_domain,
 	return 0;
 }
 
-static struct arm_smmu_ste *
+#ifndef CONFIG_ARM_SMMU_V3_DEBUGFS
+static
+#endif
+struct arm_smmu_ste *
 arm_smmu_get_step_for_sid(struct arm_smmu_device *smmu, u32 sid)
 {
 	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
@@ -3489,7 +3492,10 @@ struct arm_smmu_device *arm_smmu_get_by_fwnode(struct fwnode_handle *fwnode)
 	return dev ? dev_get_drvdata(dev) : NULL;
 }
 
-static bool arm_smmu_sid_in_range(struct arm_smmu_device *smmu, u32 sid)
+#ifndef CONFIG_ARM_SMMU_V3_DEBUGFS
+static
+#endif
+bool arm_smmu_sid_in_range(struct arm_smmu_device *smmu, u32 sid)
 {
 	if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB)
 		return arm_smmu_strtab_l1_idx(sid) < smmu->strtab_cfg.l2.num_l1_ents;
@@ -3635,6 +3641,10 @@ static struct iommu_device *arm_smmu_probe_device(struct device *dev)
 		pci_prepare_ats(to_pci_dev(dev), stu);
 	}
 
+#ifdef CONFIG_ARM_SMMU_V3_DEBUGFS
+	arm_smmu_debugfs_create_stream_table(dev, smmu);
+#endif
+
 	return &smmu->iommu;
 
 err_free_master:
@@ -3648,10 +3658,14 @@ static void arm_smmu_release_device(struct device *dev)
 
 	WARN_ON(master->iopf_refcount);
 
+#ifdef CONFIG_ARM_SMMU_V3_DEBUGFS
+	arm_smmu_debugfs_remove_stream_table(dev, master->smmu);
+#endif
 	arm_smmu_disable_pasid(master);
 	arm_smmu_remove_master(master);
 	if (arm_smmu_cdtab_allocated(&master->cd_table))
 		arm_smmu_free_cd_tables(master);
+
 	kfree(master);
 }
 
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index a54d72fb9e07..d9ea803a2e4e 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -734,13 +734,30 @@ struct arm_smmu_impl_ops {
 };
 
 #ifdef CONFIG_ARM_SMMU_V3_DEBUGFS
+struct ste_context {
+	struct arm_smmu_master		*master;
+	u32				sid;
+	struct list_head		node;
+};
+
 struct arm_smmu_debugfs {
+	struct list_head		stream_list;
+	spinlock_t			stream_lock;
 	struct dentry			*smmu_dir;
+	struct dentry			*stream_dir;
 	/* Reserved for future extensions */
 };
 
 int arm_smmu_debugfs_setup(struct arm_smmu_device *smmu, const char *name);
 void arm_smmu_debugfs_remove(struct arm_smmu_device *smmu);
+int arm_smmu_debugfs_create_stream_table(struct device *dev,
+					 struct arm_smmu_device *smmu);
+void arm_smmu_debugfs_remove_stream_table(struct device *dev,
+					  struct arm_smmu_device *smmu);
+
+struct arm_smmu_ste *
+arm_smmu_get_step_for_sid(struct arm_smmu_device *smmu, u32 sid);
+bool arm_smmu_sid_in_range(struct arm_smmu_device *smmu, u32 sid);
 #endif
 
 /* An SMMUv3 instance */
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [RFC PATCH v2 4/5] iommu/arm-smmu-v3: Add device symlink in stream table debugfs
  2026-03-28 10:17 [RFC PATCH v2 0/5] Add debugfs support for ARM SMMUv3 Qinxin Xia
                   ` (2 preceding siblings ...)
  2026-03-28 10:17 ` [RFC PATCH v2 3/5] iommu/arm-smmu-v3: Add Stream Table Entry " Qinxin Xia
@ 2026-03-28 10:17 ` Qinxin Xia
  2026-03-28 10:17 ` [RFC PATCH v2 5/5] iommu/arm-smmu-v3: Add Context Descriptor display to debugfs Qinxin Xia
  4 siblings, 0 replies; 9+ messages in thread
From: Qinxin Xia @ 2026-03-28 10:17 UTC (permalink / raw)
  To: robin.murphy, nicolinc, will, jpb
  Cc: linux-arm-kernel, iommu, xiaqinxin, wangzhou1, prime.zeng,
	fanghao11, jonathan.cameron, wuyifan50, linuxarm

Add a symlink named  under each stream table entry directory pointing to
the sysfs directory of the actual device. This aids debugging
by providing direct access to device attributes.

/sys/kernel/debug/iommu/arm_smmu_v3/smmu0/stream_table/
└── <sid>/
    ├─── ste
    └─── <dev_name>

Signed-off-by: Qinxin Xia <xiaqinxin@huawei.com>
---
 .../arm/arm-smmu-v3/arm-smmu-v3-debugfs.c     | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c
index 70623b480d64..dbcc8fce6d8e 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c
@@ -8,8 +8,9 @@
  *     ├── capabilities    # SMMU feature capabilities and configuration
  *     ├── registers	   # SMMU Key registers
  *     └── stream_table
- *	   └─── <sid>/                                # Stream ID 0
- *	       └── ste                                # Stream Table Entry
+ *	   └─── <sid>/                                # Stream ID
+ *	       ├─── ste                               # Stream Table Entry
+ *	       └── <dev_name>                         # Symlink to device sysfs directory
  *
  * The capabilities file provides detailed information about:
  * - translation stage support (Stage1/Stage2)
@@ -31,6 +32,7 @@
 
 #include <linux/cleanup.h>
 #include <linux/debugfs.h>
+#include <linux/kobject.h>
 #include <linux/slab.h>
 #include "arm-smmu-v3.h"
 
@@ -295,6 +297,7 @@ int arm_smmu_debugfs_create_stream_table(struct device *dev,
 	struct dentry *stream_dir, *dev_dir;
 	struct arm_smmu_master *master;
 	struct ste_context *ctx;
+	char *path, *full_path;
 	char name[64];
 	u32 sid;
 	int i;
@@ -333,6 +336,18 @@ int arm_smmu_debugfs_create_stream_table(struct device *dev,
 		debugfs_create_file("ste", 0444, dev_dir, ctx,
 				    &smmu_debugfs_ste_fops);
 
+		/* Create a symlink to the device's sysfs directory */
+		path = kobject_get_path(&dev->kobj, GFP_KERNEL);
+		if (!path)
+			continue;
+
+		full_path = kasprintf(GFP_KERNEL, "/sys%s", path);
+		if (full_path) {
+			debugfs_create_symlink(dev_name(dev), dev_dir, full_path);
+			kfree(full_path);
+		}
+
+		kfree(path);
 	}
 
 	return 0;
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [RFC PATCH v2 5/5] iommu/arm-smmu-v3: Add Context Descriptor display to debugfs
  2026-03-28 10:17 [RFC PATCH v2 0/5] Add debugfs support for ARM SMMUv3 Qinxin Xia
                   ` (3 preceding siblings ...)
  2026-03-28 10:17 ` [RFC PATCH v2 4/5] iommu/arm-smmu-v3: Add device symlink in stream table debugfs Qinxin Xia
@ 2026-03-28 10:17 ` Qinxin Xia
  4 siblings, 0 replies; 9+ messages in thread
From: Qinxin Xia @ 2026-03-28 10:17 UTC (permalink / raw)
  To: robin.murphy, nicolinc, will, jpb
  Cc: linux-arm-kernel, iommu, xiaqinxin, wangzhou1, prime.zeng,
	fanghao11, jonathan.cameron, wuyifan50, linuxarm

Add Context Descriptor (CD) display functionality to debugfs.
This allow inspecting CD contents for all Substream IDs including:
- CD validity and translation parameters
- TTBR0 and TCR configurations
- Raw CD data

/sys/kernel/debug/iommu/arm_smmu_v3/smmu0/stream_table/
└── <sid>/
    ├─── ste
    ├─── cd
    └─── <dev_name>

Signed-off-by: Qinxin Xia <xiaqinxin@huawei.com>
---
 .../arm/arm-smmu-v3/arm-smmu-v3-debugfs.c     | 94 +++++++++++++++++++
 1 file changed, 94 insertions(+)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c
index dbcc8fce6d8e..501437432809 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c
@@ -10,6 +10,7 @@
  *     └── stream_table
  *	   └─── <sid>/                                # Stream ID
  *	       ├─── ste                               # Stream Table Entry
+ *	       ├── cd                                 # Context Descriptor
  *	       └── <dev_name>                         # Symlink to device sysfs directory
  *
  * The capabilities file provides detailed information about:
@@ -26,6 +27,12 @@
  * - Stage 1 and Stage 2 context pointers
  * - Raw STE data
  *
+ * CD Information Displayed:
+ * - T0SZ: Input address space size configuration
+ * - EPD0/EPD1: Stage 1 translation enable flags
+ * - TTBR0: Stage 1 translation table base address
+ * - Raw Data: Complete CD structure in hexadecimal format
+
  * Copyright (C) 2026 HiSilicon Limited.
  * Author: Qinxin Xia <xiaqinxin@huawei.com>
  */
@@ -284,6 +291,91 @@ static const struct file_operations smmu_debugfs_ste_fops = {
 	.release = smmu_debugfs_ste_release,
 };
 
+/**
+ * smmu_debug_dump_cd() - Dump a single Context Descriptor
+ * @seq: seq_file to write to
+ * @cd: pointer to the Context Descriptor to dump
+ */
+static void smmu_debug_dump_cd(struct seq_file *seq, struct arm_smmu_cd *cd)
+{
+	u64 data;
+	int i;
+
+	/* CD 0 */
+	data = le64_to_cpu(cd->data[0]);
+	seq_printf(seq, "  T0SZ: 0x%llx\n", data & CTXDESC_CD_0_TCR_T0SZ);
+	seq_printf(seq, "  EPD0: %s\n", data & CTXDESC_CD_0_TCR_EPD0 ? "Yes" : "No");
+	seq_printf(seq, "  EPD1: %s\n", data & CTXDESC_CD_0_TCR_EPD1 ? "Yes" : "No");
+
+	/* CD 1 */
+	data = le64_to_cpu(cd->data[1]);
+	seq_printf(seq, "  TTBR0: 0x%016llx\n", data & CTXDESC_CD_1_TTB0_MASK);
+
+	/* Display raw CD data */
+	seq_puts(seq, "  Raw Data:\n");
+	for (i = 0; i < CTXDESC_CD_DWORDS; i++)
+		seq_printf(seq, "    CD[%d]: 0x%016llx\n", i,
+			   le64_to_cpu(cd->data[i]));
+}
+
+static int smmu_debugfs_cd_show(struct seq_file *seq, void *unused)
+{
+	struct device *dev = seq->private;
+	struct arm_smmu_master *master = dev_iommu_priv_get(dev);
+	u32 max_ssids, ssid;
+
+	if (!master) {
+		seq_puts(seq, "No master data\n");
+		return 0;
+	}
+
+	mutex_lock(&arm_smmu_asid_lock);
+	max_ssids = 1 << master->ssid_bits;
+	seq_printf(seq, "Context Descriptors for device (max SSIDs: %u):\n",
+		   max_ssids);
+
+	for (ssid = 0; ssid < max_ssids; ssid++) {
+		struct arm_smmu_cd *cd = arm_smmu_get_cd_ptr(master, ssid);
+
+		if (cd && (le64_to_cpu(cd->data[0]) & CTXDESC_CD_0_V)) {
+			seq_printf(seq, "\n--- SSID %u ---\n", ssid);
+			smmu_debug_dump_cd(seq, cd);
+		}
+	}
+
+	mutex_unlock(&arm_smmu_asid_lock);
+	return 0;
+}
+
+static int smmu_debugfs_cd_open(struct inode *inode, struct file *file)
+{
+	struct device *dev = inode->i_private;
+
+	if (!dev || !get_device(dev))
+		return -ENODEV;
+
+	return single_open(file, smmu_debugfs_cd_show, dev);
+}
+
+static int smmu_debugfs_cd_release(struct inode *inode, struct file *file)
+{
+	struct seq_file *seq = file->private_data;
+	struct device *dev = seq->private;
+
+	single_release(inode, file);
+	if (dev)
+		put_device(dev);
+	return 0;
+}
+
+static const struct file_operations smmu_debugfs_cd_fops = {
+	.owner   = THIS_MODULE,
+	.open    = smmu_debugfs_cd_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = smmu_debugfs_cd_release,
+};
+
 /**
  * arm_smmu_debugfs_create_stream_table() - Create debugfs entries for stream table
  * @dev: device to create entries for
@@ -348,6 +440,8 @@ int arm_smmu_debugfs_create_stream_table(struct device *dev,
 		}
 
 		kfree(path);
+		/* Create CD file to dump all valid Context Descriptors */
+		debugfs_create_file("cd", 0444, dev_dir, dev, &smmu_debugfs_cd_fops);
 	}
 
 	return 0;
-- 
2.33.0



^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [RFC PATCH v2 1/5] iommu/arm-smmu-v3: Add basic debugfs framework
  2026-03-28 10:17 ` [RFC PATCH v2 1/5] iommu/arm-smmu-v3: Add basic debugfs framework Qinxin Xia
@ 2026-03-30 10:46   ` Nicolin Chen
  0 siblings, 0 replies; 9+ messages in thread
From: Nicolin Chen @ 2026-03-30 10:46 UTC (permalink / raw)
  To: Qinxin Xia
  Cc: robin.murphy, will, jpb, linux-arm-kernel, iommu, wangzhou1,
	prime.zeng, fanghao11, jonathan.cameron, wuyifan50, linuxarm

On Sat, Mar 28, 2026 at 06:17:02PM +0800, Qinxin Xia wrote:
> Add basic debugfs framework for ARM SMMUv3 driver.This creates the

Needs a space after "."

> +static int smmu_debugfs_capabilities_show(struct seq_file *seq, void *unused)
> +{
> +	struct arm_smmu_device *smmu = seq->private;
> +
> +	if (!smmu) {
> +		seq_puts(seq, "SMMU not available\n");
> +		return 0;
> +	}
> +
> +	seq_puts(seq, "SMMUv3 Capabilities:\n");
> +	seq_printf(seq, "  Stage1 Translation: %s\n",
> +		   smmu->features & ARM_SMMU_FEAT_TRANS_S1 ? "Yes" : "No");
> +	seq_printf(seq, "  Stage2 Translation: %s\n",
> +		   smmu->features & ARM_SMMU_FEAT_TRANS_S2 ? "Yes" : "No");
> +	seq_printf(seq, "  Coherent Walk: %s\n",
> +		   smmu->features & ARM_SMMU_FEAT_COHERENCY ? "Yes" : "No");
> +	seq_printf(seq, "  ATS Support: %s\n",
> +		   smmu->features & ARM_SMMU_FEAT_ATS ? "Yes" : "No");
> +	seq_printf(seq, "  PRI Support: %s\n",
> +		   smmu->features & ARM_SMMU_FEAT_PRI ? "Yes" : "No");
> +	seq_printf(seq, "  Stream Table Size: %d\n", 1 << smmu->sid_bits);
> +	seq_printf(seq, "  Command Queue Depth: %d\n",
> +		   1 << smmu->cmdq.q.llq.max_n_shift);
> +	seq_printf(seq, "  Event Queue Depth: %d\n",
> +		   1 << smmu->evtq.q.llq.max_n_shift);

Nit: should we do all sizes or all depths? Any good reason to mix
them here?

> +/**
> + * arm_smmu_debugfs_remove() - Clean up debugfs entries for an SMMU device
> + * @smmu: SMMU device
> + *
> + * This function removes the debugfs directories created by setup.
> + */
> +void arm_smmu_debugfs_remove(struct arm_smmu_device *smmu)
> +{
> +	struct arm_smmu_debugfs *debugfs;
> +
> +	scoped_guard(mutex, &arm_smmu_debugfs_lock) {

It could be just normal guard().

> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> index 4d00d796f078..cbb3fccc501b 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -4904,6 +4904,15 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
>  	/* Check for RMRs and install bypass STEs if any */
>  	arm_smmu_rmr_install_bypass_ste(smmu);
>  
> +#ifdef CONFIG_ARM_SMMU_V3_DEBUGFS
> +	char name[32];

This could be moved to the top, as iommu_device_sysfs_add() can use
it, whether CONFIG_ARM_SMMU_V3_DEBUGFS=y or =n.

> +	snprintf(name, sizeof(name), "smmu3.%pa", &ioaddr);

And this could be moved after ioaddr gets a copy from res->start.

>  
> +#ifdef CONFIG_ARM_SMMU_V3_DEBUGFS
> +struct arm_smmu_debugfs {
> +	struct dentry			*smmu_dir;

A personal preference: for new structures, maybe drop those tabs?

>  /* An SMMUv3 instance */
>  struct arm_smmu_device {
>  	struct device			*dev;
> @@ -803,6 +813,11 @@ struct arm_smmu_device {
>  
>  	struct rb_root			streams;
>  	struct mutex			streams_mutex;
> +
> +#ifdef CONFIG_ARM_SMMU_V3_DEBUGFS
> +	/* DebugFS Info */

Doesn't seem very useful. I'd drop it.

> +	struct arm_smmu_debugfs		*debugfs;
> +#endif
 
Nicolin


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [RFC PATCH v2 2/5] iommu/arm-smmu-v3: Add register display to debugfs
  2026-03-28 10:17 ` [RFC PATCH v2 2/5] iommu/arm-smmu-v3: Add register display to debugfs Qinxin Xia
@ 2026-03-30 11:25   ` Nicolin Chen
  0 siblings, 0 replies; 9+ messages in thread
From: Nicolin Chen @ 2026-03-30 11:25 UTC (permalink / raw)
  To: Qinxin Xia
  Cc: robin.murphy, will, jpb, linux-arm-kernel, iommu, wangzhou1,
	prime.zeng, fanghao11, jonathan.cameron, wuyifan50, linuxarm

On Sat, Mar 28, 2026 at 06:17:03PM +0800, Qinxin Xia wrote:
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c
> @@ -5,13 +5,18 @@
>   * Directory Structure:
>   * /sys/kernel/debug/iommu/arm_smmu_v3/
>   * └── smmu<ioaddr>/
> - *     └── capabilities    # SMMU feature capabilities and configuration

Nit: perhaps the last line in every patch could start with '|-',
so we wouldn't need to update it every time.

> + *     ├── capabilities    # SMMU feature capabilities and configuration
> + *     └── registers	   # SMMU Key registers

Maybe replace '\t' with whitespaces? The final file doesn't seem
to have this line properly aligned with others also.

Nicolin


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2026-03-30 11:26 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-28 10:17 [RFC PATCH v2 0/5] Add debugfs support for ARM SMMUv3 Qinxin Xia
2026-03-28 10:17 ` [RFC PATCH v2 1/5] iommu/arm-smmu-v3: Add basic debugfs framework Qinxin Xia
2026-03-30 10:46   ` Nicolin Chen
2026-03-28 10:17 ` [RFC PATCH v2 2/5] iommu/arm-smmu-v3: Add register display to debugfs Qinxin Xia
2026-03-30 11:25   ` Nicolin Chen
2026-03-28 10:17 ` [RFC PATCH v2 3/5] iommu/arm-smmu-v3: Add Stream Table Entry " Qinxin Xia
2026-03-28 10:17 ` [RFC PATCH v2 4/5] iommu/arm-smmu-v3: Add device symlink in stream table debugfs Qinxin Xia
2026-03-28 10:17 ` [RFC PATCH v2 5/5] iommu/arm-smmu-v3: Add Context Descriptor display to debugfs Qinxin Xia
  -- strict thread matches above, loose matches on Subject: below --
2026-03-28 10:09 [RFC PATCH v2 0/5] Add debugfs support for ARM SMMUv3 Qinxin Xia
2026-03-28 10:09 ` [RFC PATCH v2 2/5] iommu/arm-smmu-v3: Add register display to debugfs Qinxin Xia

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox