public inbox for linux-arm-kernel@lists.infradead.org
 help / color / mirror / Atom feed
* [RFC PATCH 0/5]  Add debugfs support for ARM SMMUv3
@ 2026-03-13 10:43 Qinxin Xia
  2026-03-13 10:43 ` [RFC PATCH 1/5] iommu/arm-smmu-v3: Add basic debugfs framework Qinxin Xia
                   ` (4 more replies)
  0 siblings, 5 replies; 24+ messages in thread
From: Qinxin Xia @ 2026-03-13 10:43 UTC (permalink / raw)
  To: will, robin.murphy, jpb
  Cc: linux-arm-kernel, iommu, xiaqinxin, wangzhou1, prime.zeng,
	fanghao11, jonathan.cameron, linuxarm

This patch series introduces a debugfs interface for the ARM SMMUv3
driver, enabling developers and system administrators to inspect the
internal state of the SMMU for debugging and diagnostic purposes.

The debugfs entries are organized under:

  /sys/kernel/debug/iommu/arm_smmu_v3/

For each SMMU instance, a subdirectory named smmu3.<phys_addr> is
created (e.g. smmu3.0x0000000100100000). Inside, the following files are
available:

  capabilities  - Display SMMU feature capabilities and configuration
                  (stage support, coherency, ATS, PRI, queue depths)
  registers     - Show key control registers (CR0, CR1, CR2) and
                  command/event queue pointers (PROD/CONS)
  stream_table/ - Directory per PCI device or platform device, named
                  as <bus:dev:func>:<stream-id>; contains:
      ste       - Stream Table Entry (STE) details and raw data
      context_descriptors/
          all   - All valid Context Descriptors (CDs) for the device

The interface is designed with scalability in mind; additional
debugging features (e.g., queue dumping, event injection) can be added
later without breaking existing entries. Proper locking and error
handling ensure that the SMMU driver remains stable even when debugfs
accesses fail.
 
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 stream table directory structure to 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     | 516 ++++++++++++++++++
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   |  13 +
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  18 +
 5 files changed, 559 insertions(+)
 create mode 100644 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c

-- 
2.33.0



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

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

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

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/
└── smmu0/
    └── 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     | 132 ++++++++++++++++++
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   |  10 ++
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  14 ++
 5 files changed, 168 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..dfde3779764a 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/arm_smmu_v3/ with
+	  detailed information about SMMU configuration, stream tables,
+	  and context descriptors.
+
+	  Say N unless you are debugging IOMMU 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..81fd2808f12f 100644
--- a/drivers/iommu/arm/arm-smmu-v3/Makefile
+++ b/drivers/iommu/arm/arm-smmu-v3/Makefile
@@ -6,3 +6,4 @@ arm_smmu_v3-$(CONFIG_ARM_SMMU_V3_SVA) += arm-smmu-v3-sva.o
 arm_smmu_v3-$(CONFIG_TEGRA241_CMDQV) += tegra241-cmdqv.o
 
 obj-$(CONFIG_ARM_SMMU_V3_KUNIT_TEST) += arm-smmu-v3-test.o
+obj-$(CONFIG_ARM_SMMU_V3_DEBUGFS) += arm-smmu-v3-debugfs.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..542bd6047f26
--- /dev/null
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-debugfs.c
@@ -0,0 +1,132 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ARM SMMUv3 DebugFS Support
+ *
+ * This file implements the basic debugfs infrastructure for ARM SMMUv3 driver.
+ * It provides the foundation for exposing SMMU internal state through debugfs
+ * for debugging and diagnostic purposes.
+ *
+ * Key Features:
+ * - Global root directory management with proper mutex synchronization
+ * - Per-SMMU instance directory creation with unique naming
+ * - Capability reporting covering all major SMMU features and configuration
+ * - Extensible architecture designed for adding future debug functionality
+ * - Comprehensive error handling and resource cleanup
+ *
+ * Directory Structure:
+ * /sys/kernel/debug/iommu/arm_smmu_v3/
+ * └── smmu0/
+ *     └── capabilities    # SMMU feature capabilities and configuration
+ *
+ * The capabilities file provides detailed information about:
+ * - Architecture version and translation stage support (Stage1/Stage2)
+ * - System coherency, ATS, and PRI feature availability
+ * - Stream table size and command/event queue depths
+ * - All feature bits from the SMMU device structure
+ *
+ * Copyright (C) 2025 HiSilicon Limited.
+ * Author: Qinxin Xia <xiaqinxin@huawei.com>
+ */
+
+#include <linux/debugfs.h>
+#include "arm-smmu-v3.h"
+
+static struct dentry *smmuv3_root_dir;
+static DEFINE_MUTEX(arm_smmu_debugfs_lock);
+
+/**
+ * smmu_debugfs_capabilities_show() - Display SMMU capabilities
+ * @seq: seq_file to write to
+ * @v: private data (SMMU device)
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+static int smmu_debugfs_capabilities_show(struct seq_file *seq, void *v)
+{
+	struct arm_smmu_device *smmu = seq->private;
+
+	if (!smmu)
+		return -ENODEV;
+
+	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;
+}
+DEFINE_SHOW_ATTRIBUTE(smmu_debugfs_capabilities);
+
+/**
+ * arm_smmu_debugfs_setup() - Initialize debugfs for SMMU device
+ * @smmu: SMMU device to setup debugfs for
+ * @ioaddr: Physical base address of the SMMU device registers
+ *
+ * This function creates the basic debugfs directory structure for a SMMU device.
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+int arm_smmu_debugfs_setup(struct arm_smmu_device *smmu, phys_addr_t ioaddr)
+{
+	struct arm_smmu_debugfs *debugfs;
+	struct dentry *smmu_dir;
+	char name[32];
+	int ret;
+
+	/* Create root directory if it doesn't exist */
+	mutex_lock(&arm_smmu_debugfs_lock);
+	if (!smmuv3_root_dir) {
+		smmuv3_root_dir = debugfs_create_dir("arm_smmu_v3",
+						     iommu_debugfs_dir);
+		if (!smmuv3_root_dir) {
+			mutex_unlock(&arm_smmu_debugfs_lock);
+			return -ENOMEM;
+		}
+	}
+	mutex_unlock(&arm_smmu_debugfs_lock);
+
+	/* Allocate debugfs structure */
+	debugfs = kzalloc(sizeof(*debugfs), GFP_KERNEL);
+	if (!debugfs)
+		return -ENOMEM;
+
+	smmu->debugfs = debugfs;
+	debugfs->smmu = smmu;
+
+	/* Create SMMU instance directory */
+	snprintf(name, sizeof(name), "smmu3.%pa", &ioaddr);
+	smmu_dir = debugfs_create_dir(name, smmuv3_root_dir);
+	if (!smmu_dir) {
+		ret = -ENOMEM;
+		goto err_free;
+	}
+
+	debugfs->smmu_dir = smmu_dir;
+
+	/* Create capabilities file */
+	if (!debugfs_create_file("capabilities", 0444, smmu_dir, smmu,
+				 &smmu_debugfs_capabilities_fops))
+		goto err_cleanup;
+
+	pr_info("SMMUv3 debugfs initialized for smmu%pa\n", &ioaddr);
+	return 0;
+
+err_cleanup:
+	debugfs_remove_recursive(smmu_dir);
+err_free:
+	kfree(debugfs);
+	smmu->debugfs = NULL;
+	return ret;
+}
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..211a0c87507a 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -33,6 +33,10 @@
 #include "arm-smmu-v3.h"
 #include "../../dma-iommu.h"
 
+#ifdef CONFIG_ARM_SMMU_V3_DEBUGFS
+static unsigned int arm_smmu_present;
+#endif
+
 static bool disable_msipolling;
 module_param(disable_msipolling, bool, 0444);
 MODULE_PARM_DESC(disable_msipolling,
@@ -4909,6 +4913,12 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
 	if (ret)
 		goto err_disable;
 
+#ifdef CONFIG_ARM_SMMU_V3_DEBUGFS
+	ret = arm_smmu_debugfs_setup(smmu, ioaddr);
+	if (ret)
+		dev_warn(dev, "Failed to create debugfs!\n");
+#endif
+
 	/* And we're up. Go go go! */
 	ret = iommu_device_sysfs_add(&smmu->iommu, dev, NULL,
 				     "smmu3.%pa", &ioaddr);
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..247f27426f6b 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,15 @@ struct arm_smmu_impl_ops {
 			  const struct iommu_user_data *user_data);
 };
 
+#ifdef CONFIG_ARM_SMMU_V3_DEBUGFS
+struct arm_smmu_debugfs {
+	struct dentry *root_dir;
+	struct dentry *smmu_dir;
+	struct arm_smmu_device *smmu;
+};
+int arm_smmu_debugfs_setup(struct arm_smmu_device *smmu, phys_addr_t ioaddr);
+#endif
+
 /* An SMMUv3 instance */
 struct arm_smmu_device {
 	struct device			*dev;
@@ -803,6 +812,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] 24+ messages in thread

* [RFC PATCH 2/5] iommu/arm-smmu-v3: Add register display to debugfs
  2026-03-13 10:43 [RFC PATCH 0/5] Add debugfs support for ARM SMMUv3 Qinxin Xia
  2026-03-13 10:43 ` [RFC PATCH 1/5] iommu/arm-smmu-v3: Add basic debugfs framework Qinxin Xia
@ 2026-03-13 10:43 ` Qinxin Xia
  2026-03-13 20:20   ` Nicolin Chen
  2026-03-16 15:19   ` Robin Murphy
  2026-03-13 10:43 ` [RFC PATCH 3/5] iommu/arm-smmu-v3: Add Stream Table Entry " Qinxin Xia
                   ` (2 subsequent siblings)
  4 siblings, 2 replies; 24+ messages in thread
From: Qinxin Xia @ 2026-03-13 10:43 UTC (permalink / raw)
  To: will, robin.murphy, jpb
  Cc: linux-arm-kernel, iommu, xiaqinxin, wangzhou1, prime.zeng,
	fanghao11, jonathan.cameron, linuxarm

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="y", Size: 4362 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     | 68 ++++++++++++++++++-
 1 file changed, 67 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 542bd6047f26..f9bf955f3351 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
@@ -12,11 +12,20 @@
  * - Capability reporting covering all major SMMU features and configuration
  * - Extensible architecture designed for adding future debug functionality
  * - Comprehensive error handling and resource cleanup
+ * - Display of control registers (CR0, CR1, CR2) with bitfield decoding
+ * - Command and Event queue pointer monitoring (PROD/CONS)
+ *
+ * Register Information Displayed:
+ * - CR0: SMMU global control with enable states and queue enables
+ * - CR1/CR2: Additional control and configuration registers
+ * - CMDQ_PROD/CONS: Command queue producer and consumer pointers
+ * - EVTQ_PROD/CONS: Event queue producer and consumer pointers
  *
  * Directory Structure:
  * /sys/kernel/debug/iommu/arm_smmu_v3/
  * └── smmu0/
- *     └── capabilities    # SMMU feature capabilities and configuration
+ *     ├── capabilities    # SMMU feature capabilities and configuration
+ *     └── registers	   # SMMU Key registers
  *
  * The capabilities file provides detailed information about:
  * - Architecture version and translation stage support (Stage1/Stage2)
@@ -24,6 +33,11 @@
  * - Stream table size and command/event queue depths
  * - All feature bits from the SMMU device structure
  *
+ * The register display provides crucial visibility into:
+ * - SMMU operational state (enabled/disabled)
+ * - Queue operation and potential stalls
+ * - Configuration settings affecting all streams
+ *
  * Copyright (C) 2025 HiSilicon Limited.
  * Author: Qinxin Xia <xiaqinxin@huawei.com>
  */
@@ -69,6 +83,54 @@ static int smmu_debugfs_capabilities_show(struct seq_file *seq, void *v)
 }
 DEFINE_SHOW_ATTRIBUTE(smmu_debugfs_capabilities);
 
+/**
+ * smmu_debugfs_registers_show() - Display SMMU register values
+ * @seq: seq_file to write to
+ * @v: private data (SMMU device)
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+static int smmu_debugfs_registers_show(struct seq_file *seq, void *v)
+{
+	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 [%s%s%s]\n",
+		   readl_relaxed(base + ARM_SMMU_CR0),
+		   readl_relaxed(base + ARM_SMMU_CR0) & CR0_SMMUEN ?
+		   "Enabled " : "Disabled ",
+		   readl_relaxed(base + ARM_SMMU_CR0) & CR0_EVTQEN ?
+		   "EventQ " : "",
+		   readl_relaxed(base + ARM_SMMU_CR0) & CR0_CMDQEN ?
+		   "CmdQ " : "");
+
+	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;
+}
+DEFINE_SHOW_ATTRIBUTE(smmu_debugfs_registers);
+
 /**
  * arm_smmu_debugfs_setup() - Initialize debugfs for SMMU device
  * @smmu: SMMU device to setup debugfs for
@@ -120,6 +182,10 @@ int arm_smmu_debugfs_setup(struct arm_smmu_device *smmu, phys_addr_t ioaddr)
 				 &smmu_debugfs_capabilities_fops))
 		goto err_cleanup;
 
+	if (!debugfs_create_file("registers", 0444, smmu_dir, smmu,
+				 &smmu_debugfs_registers_fops))
+		goto err_cleanup;
+
 	pr_info("SMMUv3 debugfs initialized for smmu%pa\n", &ioaddr);
 	return 0;
 
-- 
2.33.0



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

* [RFC PATCH 3/5] iommu/arm-smmu-v3: Add Stream Table Entry display to debugfs
  2026-03-13 10:43 [RFC PATCH 0/5] Add debugfs support for ARM SMMUv3 Qinxin Xia
  2026-03-13 10:43 ` [RFC PATCH 1/5] iommu/arm-smmu-v3: Add basic debugfs framework Qinxin Xia
  2026-03-13 10:43 ` [RFC PATCH 2/5] iommu/arm-smmu-v3: Add register display to debugfs Qinxin Xia
@ 2026-03-13 10:43 ` Qinxin Xia
  2026-03-13 20:19   ` Nicolin Chen
  2026-03-13 10:43 ` [RFC PATCH 4/5] iommu/arm-smmu-v3: Add stream table directory structure " Qinxin Xia
  2026-03-13 10:43 ` [RFC PATCH 5/5] iommu/arm-smmu-v3: Add Context Descriptor display " Qinxin Xia
  4 siblings, 1 reply; 24+ messages in thread
From: Qinxin Xia @ 2026-03-13 10:43 UTC (permalink / raw)
  To: will, robin.murphy, jpb
  Cc: linux-arm-kernel, iommu, xiaqinxin, wangzhou1, prime.zeng,
	fanghao11, jonathan.cameron, linuxarm

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

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

Signed-off-by: Qinxin Xia <xiaqinxin@huawei.com>
---
 .../arm/arm-smmu-v3/arm-smmu-v3-debugfs.c     | 130 ++++++++++++++++++
 1 file changed, 130 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 f9bf955f3351..d7f3defd94a3 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
@@ -21,6 +21,12 @@
  * - CMDQ_PROD/CONS: Command queue producer and consumer pointers
  * - EVTQ_PROD/CONS: Event queue producer and consumer pointers
  *
+ * STE Information Displayed:
+ * - Validity: Whether the STE is currently active and valid
+ * - Configuration: Translation mode (bypass/abort/S1/S2)
+ * - Context Pointers: Stage 1 and Stage 2 translation context addresses
+ * - Raw Data: Complete 64-bit STE words in hexadecimal
+ *
  * Directory Structure:
  * /sys/kernel/debug/iommu/arm_smmu_v3/
  * └── smmu0/
@@ -43,6 +49,8 @@
  */
 
 #include <linux/debugfs.h>
+#include <linux/pci.h>
+#include <linux/iommu.h>
 #include "arm-smmu-v3.h"
 
 static struct dentry *smmuv3_root_dir;
@@ -196,3 +204,125 @@ int arm_smmu_debugfs_setup(struct arm_smmu_device *smmu, phys_addr_t ioaddr)
 	smmu->debugfs = NULL;
 	return ret;
 }
+
+/**
+ * smmu_get_ste() - Get Stream Table Entry for a given Stream ID
+ * @smmu: SMMU device
+ * @sid: Stream ID
+ *
+ * Return: Pointer to STE if found, NULL otherwise
+ */
+static struct arm_smmu_ste *smmu_get_ste(struct arm_smmu_device *smmu, u32 sid)
+{
+	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
+
+	if (sid >= (1 << smmu->sid_bits))
+		return NULL;
+
+	if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) {
+		u32 l1_idx = arm_smmu_strtab_l1_idx(sid);
+		u32 l2_idx = arm_smmu_strtab_l2_idx(sid);
+
+		if (l1_idx >= cfg->l2.num_l1_ents || !cfg->l2.l2ptrs[l1_idx])
+			return NULL;
+
+		return &cfg->l2.l2ptrs[l1_idx]->stes[l2_idx];
+	}
+
+	return &cfg->linear.table[sid];
+}
+
+/**
+ * smmu_debug_dump_ste() - Dump STE details to seq_file
+ * @seq: seq_file to write to
+ * @dev: device associated with the STE
+ */
+static void smmu_debug_dump_ste(struct seq_file *seq, struct device *dev)
+{
+	struct arm_smmu_master *master = dev_iommu_priv_get(dev);
+	struct arm_smmu_device *smmu;
+	struct arm_smmu_ste *ste;
+	u32 sid, cfg;
+	int i;
+
+	if (!master || !master->smmu) {
+		seq_puts(seq, "No SMMU master data\n");
+		return;
+	}
+
+	smmu = master->smmu;
+
+	/* Use first stream ID for debug */
+	if (master->num_streams == 0) {
+		seq_puts(seq, "No streams configured for device\n");
+		return;
+	}
+	sid = master->streams[0].id;
+
+	if (sid >= (1 << smmu->sid_bits)) {
+		seq_printf(seq, "Invalid Stream ID: %u (max %u)\n",
+			   sid, (1 << smmu->sid_bits) - 1);
+		return;
+	}
+
+	ste = smmu_get_ste(smmu, sid);
+	if (!ste) {
+		seq_printf(seq, "STE not available for SID %u\n", sid);
+		return;
+	}
+
+	seq_printf(seq, "STE for Stream ID %u\n", sid);
+	seq_printf(seq, "  Valid: %s\n",
+		   ste->data[0] & STRTAB_STE_0_V ? "Yes" : "No");
+
+	seq_puts(seq, "  Config: ");
+
+	cfg = FIELD_GET(STRTAB_STE_0_CFG, 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 (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 (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]));
+}
+
+/* STE debugfs file operations */
+static int smmu_debugfs_ste_show(struct seq_file *seq, void *v)
+{
+	struct device *dev = seq->private;
+
+	smmu_debug_dump_ste(seq, dev);
+	return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(smmu_debugfs_ste);
-- 
2.33.0



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

* [RFC PATCH 4/5] iommu/arm-smmu-v3: Add stream table directory structure to debugfs
  2026-03-13 10:43 [RFC PATCH 0/5] Add debugfs support for ARM SMMUv3 Qinxin Xia
                   ` (2 preceding siblings ...)
  2026-03-13 10:43 ` [RFC PATCH 3/5] iommu/arm-smmu-v3: Add Stream Table Entry " Qinxin Xia
@ 2026-03-13 10:43 ` Qinxin Xia
  2026-03-13 20:44   ` Nicolin Chen
  2026-03-16 16:01   ` Robin Murphy
  2026-03-13 10:43 ` [RFC PATCH 5/5] iommu/arm-smmu-v3: Add Context Descriptor display " Qinxin Xia
  4 siblings, 2 replies; 24+ messages in thread
From: Qinxin Xia @ 2026-03-13 10:43 UTC (permalink / raw)
  To: will, robin.murphy, jpb
  Cc: linux-arm-kernel, iommu, xiaqinxin, wangzhou1, prime.zeng,
	fanghao11, jonathan.cameron, linuxarm

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

Add stream table directory structure creation to debugfs
This organizes debugfs entries by device and stream ID:

/sys/kernel/debug/iommu/arm_smmu_v3/smmu0/stream_table/
└── 0000:01:00.0:0/
    └─── ste

Signed-off-by: Qinxin Xia <xiaqinxin@huawei.com>
---
 .../arm/arm-smmu-v3/arm-smmu-v3-debugfs.c     | 80 ++++++++++++++++++-
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   |  3 +
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  4 +
 3 files changed, 85 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 d7f3defd94a3..f62df02847ac 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
@@ -31,7 +31,10 @@
  * /sys/kernel/debug/iommu/arm_smmu_v3/
  * └── smmu0/
  *     ├── capabilities    # SMMU feature capabilities and configuration
- *     └── registers	   # SMMU Key registers
+ *     ├── registers	   # SMMU Key registers
+ *     └── stream_table
+ *	   └── 0000:01:00.0:0/                    # PCI device with Stream ID 0
+ *             ├── ste                           # Stream Table Entry
  *
  * The capabilities file provides detailed information about:
  * - Architecture version and translation stage support (Stage1/Stage2)
@@ -324,5 +327,78 @@ static int smmu_debugfs_ste_show(struct seq_file *seq, void *v)
 	smmu_debug_dump_ste(seq, dev);
 	return 0;
 }
-
 DEFINE_SHOW_ATTRIBUTE(smmu_debugfs_ste);
+
+/**
+ * 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 smmu_debugfs_create_stream_table(struct device *dev,
+				     struct arm_smmu_device *smmu)
+{
+	struct dentry *stream_dir, *cd_dir, *dev_dir;
+	struct dentry *ste_file, *all_cds_file;
+	struct iommu_fwspec *fwspec;
+	char name[64];
+	int i, ret = 0;
+
+	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;
+	}
+
+	fwspec = dev_iommu_fwspec_get(dev);
+	if (!fwspec)
+		return -ENODEV;
+
+	for (i = 0; i < fwspec->num_ids; i++) {
+		u32 sid = fwspec->ids[i];
+
+		if (dev_is_pci(dev)) {
+			struct pci_dev *pdev = to_pci_dev(dev);
+
+			snprintf(name, sizeof(name), "%04x:%02x:%02x.%d:%u",
+				 pci_domain_nr(pdev->bus), pdev->bus->number,
+				 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
+				 sid);
+		} else {
+			snprintf(name, sizeof(name), "%s:%u", dev_name(dev),
+				 sid);
+		}
+
+		dev_dir = debugfs_create_dir(name, stream_dir);
+		if (!dev_dir) {
+			ret = -ENOMEM;
+			goto cleanup;
+		}
+
+		/* Create STE file */
+		ste_file = debugfs_create_file("ste", 0444, dev_dir, dev,
+					       &smmu_debugfs_ste_fops);
+		if (!ste_file) {
+			ret = -ENOMEM;
+			goto cleanup_dev;
+		}
+
+		/* Success for this stream ID, continue to next */
+		continue;
+
+cleanup_dev:
+		debugfs_remove_recursive(dev_dir);
+cleanup:
+		if (ret) {
+			debugfs_remove_recursive(stream_dir);
+			break;
+		}
+	}
+
+	return ret;
+}
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 211a0c87507a..c57897e5f644 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -3133,6 +3133,9 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev,
 
 	arm_smmu_attach_commit(&state);
 	mutex_unlock(&arm_smmu_asid_lock);
+#ifdef CONFIG_ARM_SMMU_V3_DEBUGFS
+	smmu_debugfs_create_stream_table(dev, smmu);
+#endif
 	return 0;
 }
 
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 247f27426f6b..e9cd24c1ab3c 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -737,9 +737,13 @@ struct arm_smmu_impl_ops {
 struct arm_smmu_debugfs {
 	struct dentry *root_dir;
 	struct dentry *smmu_dir;
+	struct dentry *stream_dir;
 	struct arm_smmu_device *smmu;
 };
+
 int arm_smmu_debugfs_setup(struct arm_smmu_device *smmu, phys_addr_t ioaddr);
+int smmu_debugfs_create_stream_table(struct device *dev,
+					struct arm_smmu_device *smmu);
 #endif
 
 /* An SMMUv3 instance */
-- 
2.33.0



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

* [RFC PATCH 5/5] iommu/arm-smmu-v3: Add Context Descriptor display to debugfs
  2026-03-13 10:43 [RFC PATCH 0/5] Add debugfs support for ARM SMMUv3 Qinxin Xia
                   ` (3 preceding siblings ...)
  2026-03-13 10:43 ` [RFC PATCH 4/5] iommu/arm-smmu-v3: Add stream table directory structure " Qinxin Xia
@ 2026-03-13 10:43 ` Qinxin Xia
  2026-03-13 21:04   ` Nicolin Chen
  2026-03-16 15:42   ` Robin Murphy
  4 siblings, 2 replies; 24+ messages in thread
From: Qinxin Xia @ 2026-03-13 10:43 UTC (permalink / raw)
  To: will, robin.murphy, jpb
  Cc: linux-arm-kernel, iommu, xiaqinxin, wangzhou1, prime.zeng,
	fanghao11, jonathan.cameron, linuxarm

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

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/
└── 0000:01:00.0:0/
    ├── ste
    └── context_descriptors/
        └── all

Signed-off-by: Qinxin Xia <xiaqinxin@huawei.com>
---
 .../arm/arm-smmu-v3/arm-smmu-v3-debugfs.c     | 112 ++++++++++++++++++
 1 file changed, 112 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 f62df02847ac..66ae1228c6ad 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
@@ -27,6 +27,13 @@
  * - Context Pointers: Stage 1 and Stage 2 translation context addresses
  * - Raw Data: Complete 64-bit STE words in hexadecimal
  *
+ * CD Information Displayed:
+ * - Validity: Active state of the context descriptor
+ * - 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
+ *
  * Directory Structure:
  * /sys/kernel/debug/iommu/arm_smmu_v3/
  * └── smmu0/
@@ -35,6 +42,8 @@
  *     └── stream_table
  *	   └── 0000:01:00.0:0/                    # PCI device with Stream ID 0
  *             ├── ste                           # Stream Table Entry
+ *             └── context_descriptors/
+ *                 └── all                       # All Context Descriptors
  *
  * The capabilities file provides detailed information about:
  * - Architecture version and translation stage support (Stage1/Stage2)
@@ -59,6 +68,8 @@
 static struct dentry *smmuv3_root_dir;
 static DEFINE_MUTEX(arm_smmu_debugfs_lock);
 
+#define MAX_SSIDS	32	/* Reasonable limit for SSID enumeration */
+
 /**
  * smmu_debugfs_capabilities_show() - Display SMMU capabilities
  * @seq: seq_file to write to
@@ -329,6 +340,90 @@ static int smmu_debugfs_ste_show(struct seq_file *seq, void *v)
 }
 DEFINE_SHOW_ATTRIBUTE(smmu_debugfs_ste);
 
+/**
+ * smmu_debug_dump_cd() - Dump Context Descriptor details to seq_file
+ * @seq: seq_file to write to
+ * @dev: device associated with the CD
+ * @ssid: Substream ID
+ */
+static void smmu_debug_dump_cd(struct seq_file *seq, struct device *dev, u32 ssid)
+{
+	struct arm_smmu_master *master = dev_iommu_priv_get(dev);
+	struct arm_smmu_cd *cd;
+	u64 data;
+	int i;
+
+	if (!master) {
+		seq_puts(seq, "No master data\n");
+		return;
+	}
+
+	cd = arm_smmu_get_cd_ptr(master, ssid);
+	if (!cd) {
+		seq_printf(seq, "CD not available for SSID %u\n", ssid);
+		return;
+	}
+
+	seq_printf(seq, "CD for Substream ID %u:\n", ssid);
+
+	/* CD 0 */
+	data = le64_to_cpu(cd->data[0]);
+	seq_printf(seq, "  Valid: %s\n", data & CTXDESC_CD_0_V ? "Yes" : "No");
+	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]));
+}
+
+/**
+ * smmu_debug_dump_all_cds() - Dump all valid Context Descriptors for a device
+ * @seq: seq_file to write to
+ * @dev: target device
+ */
+static void smmu_debug_dump_all_cds(struct seq_file *seq, struct device *dev)
+{
+	struct arm_smmu_master *master = dev_iommu_priv_get(dev);
+	u32 max_ssids, ssid;
+
+	if (!master) {
+		seq_puts(seq, "No master data\n");
+		return;
+	}
+
+	max_ssids = min_t(u32, 1 << master->ssid_bits, MAX_SSIDS);
+
+	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, dev, ssid);
+		}
+	}
+}
+
+/* All CDs debugfs file operations */
+static int smmu_debugfs_all_cds_show(struct seq_file *seq, void *v)
+{
+	struct device *dev = seq->private;
+
+	smmu_debug_dump_all_cds(seq, dev);
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(smmu_debugfs_all_cds);
+
 /**
  * smmu_debugfs_create_stream_table() - Create debugfs entries for stream table
  * @dev: device to create entries for
@@ -388,9 +483,26 @@ int smmu_debugfs_create_stream_table(struct device *dev,
 			goto cleanup_dev;
 		}
 
+		/* Create CD directory */
+		cd_dir = debugfs_create_dir("context_descriptors", dev_dir);
+		if (!cd_dir) {
+			ret = -ENOMEM;
+			goto cleanup_dev;
+		}
+
+		/* Create "all" file to show all valid CDs */
+		all_cds_file = debugfs_create_file("all", 0444, cd_dir, dev,
+						   &smmu_debugfs_all_cds_fops);
+		if (!all_cds_file) {
+			ret = -ENOMEM;
+			goto cleanup_cd;
+		}
+
 		/* Success for this stream ID, continue to next */
 		continue;
 
+cleanup_cd:
+		debugfs_remove(cd_dir);
 cleanup_dev:
 		debugfs_remove_recursive(dev_dir);
 cleanup:
-- 
2.33.0



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

* Re: [RFC PATCH 1/5] iommu/arm-smmu-v3: Add basic debugfs framework
  2026-03-13 10:43 ` [RFC PATCH 1/5] iommu/arm-smmu-v3: Add basic debugfs framework Qinxin Xia
@ 2026-03-13 19:58   ` Nicolin Chen
  2026-03-16 15:14     ` Qinxin Xia
  0 siblings, 1 reply; 24+ messages in thread
From: Nicolin Chen @ 2026-03-13 19:58 UTC (permalink / raw)
  To: Qinxin Xia
  Cc: will, robin.murphy, jpb, linux-arm-kernel, iommu, wangzhou1,
	prime.zeng, fanghao11, jonathan.cameron, linuxarm

On Fri, Mar 13, 2026 at 06:43:47PM +0800, Qinxin Xia wrote:
> +/**
> + * smmu_debugfs_capabilities_show() - Display SMMU capabilities
> + * @seq: seq_file to write to
> + * @v: private data (SMMU device)

@v is not used

> +
> +/**
> + * arm_smmu_debugfs_setup() - Initialize debugfs for SMMU device
> + * @smmu: SMMU device to setup debugfs for
> + * @ioaddr: Physical base address of the SMMU device registers
> + *
> + * This function creates the basic debugfs directory structure for a SMMU device.

nit: an SMMU

Or maybe simply "@smmu"

> + *
> + * Return: 0 on success, negative error code on failure
> + */
> +int arm_smmu_debugfs_setup(struct arm_smmu_device *smmu, phys_addr_t ioaddr)
> +{
> +	struct arm_smmu_debugfs *debugfs;
> +	struct dentry *smmu_dir;
> +	char name[32];
> +	int ret;
> +
> +	/* Create root directory if it doesn't exist */
> +	mutex_lock(&arm_smmu_debugfs_lock);
> +	if (!smmuv3_root_dir) {
> +		smmuv3_root_dir = debugfs_create_dir("arm_smmu_v3",
> +						     iommu_debugfs_dir);
> +		if (!smmuv3_root_dir) {
> +			mutex_unlock(&arm_smmu_debugfs_lock);
> +			return -ENOMEM;
> +		}
> +	}
> +	mutex_unlock(&arm_smmu_debugfs_lock);
> +
> +	/* Allocate debugfs structure */
> +	debugfs = kzalloc(sizeof(*debugfs), GFP_KERNEL);

kzalloc_obj(*debugfs)

> 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..211a0c87507a 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -33,6 +33,10 @@
>  #include "arm-smmu-v3.h"
>  #include "../../dma-iommu.h"
>  
> +#ifdef CONFIG_ARM_SMMU_V3_DEBUGFS
> +static unsigned int arm_smmu_present;
> +#endif

Unused

> @@ -4909,6 +4913,12 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
>  	if (ret)
>  		goto err_disable;
>  
> +#ifdef CONFIG_ARM_SMMU_V3_DEBUGFS
> +	ret = arm_smmu_debugfs_setup(smmu, ioaddr);
> +	if (ret)
> +		dev_warn(dev, "Failed to create debugfs!\n");
> +#endif
> +
>  	/* And we're up. Go go go! */
>  	ret = iommu_device_sysfs_add(&smmu->iommu, dev, NULL,
>  				     "smmu3.%pa", &ioaddr);

Since name is all we wanted, maybe follow iommu_device_sysfs_add()
by passing in: 
   "const char *name, ..." instead of "phys_addr_t ioaddr"

> 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..247f27426f6b 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,15 @@ struct arm_smmu_impl_ops {
>  			  const struct iommu_user_data *user_data);
>  };
>  
> +#ifdef CONFIG_ARM_SMMU_V3_DEBUGFS
> +struct arm_smmu_debugfs {
> +	struct dentry *root_dir;

Unused

> +	struct dentry *smmu_dir;
> +	struct arm_smmu_device *smmu;

Unused

Nicolin


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

* Re: [RFC PATCH 3/5] iommu/arm-smmu-v3: Add Stream Table Entry display to debugfs
  2026-03-13 10:43 ` [RFC PATCH 3/5] iommu/arm-smmu-v3: Add Stream Table Entry " Qinxin Xia
@ 2026-03-13 20:19   ` Nicolin Chen
  2026-03-16 15:43     ` Qinxin Xia
  0 siblings, 1 reply; 24+ messages in thread
From: Nicolin Chen @ 2026-03-13 20:19 UTC (permalink / raw)
  To: Qinxin Xia
  Cc: will, robin.murphy, jpb, linux-arm-kernel, iommu, wangzhou1,
	prime.zeng, fanghao11, jonathan.cameron, linuxarm

On Fri, Mar 13, 2026 at 06:43:49PM +0800, Qinxin Xia wrote:
> 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
> @@ -43,6 +49,8 @@
>   */
>  
>  #include <linux/debugfs.h>
> +#include <linux/pci.h>

It doesn't seem being used (yet).

> +static struct arm_smmu_ste *smmu_get_ste(struct arm_smmu_device *smmu, u32 sid)
> +{
> +	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
> +
> +	if (sid >= (1 << smmu->sid_bits))
> +		return NULL;
> +
> +	if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) {
> +		u32 l1_idx = arm_smmu_strtab_l1_idx(sid);
> +		u32 l2_idx = arm_smmu_strtab_l2_idx(sid);
> +
> +		if (l1_idx >= cfg->l2.num_l1_ents || !cfg->l2.l2ptrs[l1_idx])
> +			return NULL;
> +
> +		return &cfg->l2.l2ptrs[l1_idx]->stes[l2_idx];
> +	}
> +
> +	return &cfg->linear.table[sid];
> +}

arm_smmu_get_step_for_sid() instead?

> +/**
> + * smmu_debug_dump_ste() - Dump STE details to seq_file
> + * @seq: seq_file to write to
> + * @dev: device associated with the STE
> + */
> +static void smmu_debug_dump_ste(struct seq_file *seq, struct device *dev)
> +{
> +	struct arm_smmu_master *master = dev_iommu_priv_get(dev);
> +	struct arm_smmu_device *smmu;
> +	struct arm_smmu_ste *ste;
> +	u32 sid, cfg;
> +	int i;
> +
> +	if (!master || !master->smmu) {
> +		seq_puts(seq, "No SMMU master data\n");
> +		return;
> +	}
> +
> +	smmu = master->smmu;
> +
> +	/* Use first stream ID for debug */
> +	if (master->num_streams == 0) {
> +		seq_puts(seq, "No streams configured for device\n");
> +		return;
> +	}
> +	sid = master->streams[0].id;

These might race with release_device that would destroy master?

> +
> +	if (sid >= (1 << smmu->sid_bits)) {
> +		seq_printf(seq, "Invalid Stream ID: %u (max %u)\n",
> +			   sid, (1 << smmu->sid_bits) - 1);
> +		return;
> +	}

arm_smmu_sid_in_range() instead?

> +/* STE debugfs file operations */
> +static int smmu_debugfs_ste_show(struct seq_file *seq, void *v)
> +{
> +	struct device *dev = seq->private;
> +
> +	smmu_debug_dump_ste(seq, dev);
> +	return 0;

Could unwrap smmu_debug_dump_ste().

Nicolin


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

* Re: [RFC PATCH 2/5] iommu/arm-smmu-v3: Add register display to debugfs
  2026-03-13 10:43 ` [RFC PATCH 2/5] iommu/arm-smmu-v3: Add register display to debugfs Qinxin Xia
@ 2026-03-13 20:20   ` Nicolin Chen
  2026-03-16 15:22     ` Qinxin Xia
  2026-03-16 15:19   ` Robin Murphy
  1 sibling, 1 reply; 24+ messages in thread
From: Nicolin Chen @ 2026-03-13 20:20 UTC (permalink / raw)
  To: Qinxin Xia
  Cc: will, robin.murphy, jpb, linux-arm-kernel, iommu, wangzhou1,
	prime.zeng, fanghao11, jonathan.cameron, linuxarm

On Fri, Mar 13, 2026 at 06:43:48PM +0800, Qinxin Xia wrote:
> +/**
> + * smmu_debugfs_registers_show() - Display SMMU register values
> + * @seq: seq_file to write to
> + * @v: private data (SMMU device)
> + *
> + * Return: 0 on success, negative error code on failure
> + */
> +static int smmu_debugfs_registers_show(struct seq_file *seq, void *v)

@v seems unused as well.

Nicolin


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

* Re: [RFC PATCH 4/5] iommu/arm-smmu-v3: Add stream table directory structure to debugfs
  2026-03-13 10:43 ` [RFC PATCH 4/5] iommu/arm-smmu-v3: Add stream table directory structure " Qinxin Xia
@ 2026-03-13 20:44   ` Nicolin Chen
  2026-03-16 14:57     ` Qinxin Xia
  2026-03-16 16:01   ` Robin Murphy
  1 sibling, 1 reply; 24+ messages in thread
From: Nicolin Chen @ 2026-03-13 20:44 UTC (permalink / raw)
  To: Qinxin Xia
  Cc: will, robin.murphy, jpb, linux-arm-kernel, iommu, wangzhou1,
	prime.zeng, fanghao11, jonathan.cameron, linuxarm

On Fri, Mar 13, 2026 at 06:43:50PM +0800, Qinxin Xia wrote:
>   * The capabilities file provides detailed information about:
>   * - Architecture version and translation stage support (Stage1/Stage2)
> @@ -324,5 +327,78 @@ static int smmu_debugfs_ste_show(struct seq_file *seq, void *v)
>  	smmu_debug_dump_ste(seq, dev);
>  	return 0;
>  }
> -
>  DEFINE_SHOW_ATTRIBUTE(smmu_debugfs_ste);

nit: let's not add that line in the first place

> +
> +/**
> + * 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 smmu_debugfs_create_stream_table(struct device *dev,
> +				     struct arm_smmu_device *smmu)
> +{
> +	struct dentry *stream_dir, *cd_dir, *dev_dir;
> +	struct dentry *ste_file, *all_cds_file;
> +	struct iommu_fwspec *fwspec;
> +	char name[64];
> +	int i, ret = 0;
> +
> +	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;
> +	}
> +
> +	fwspec = dev_iommu_fwspec_get(dev);
> +	if (!fwspec)
> +		return -ENODEV;
> +
> +	for (i = 0; i < fwspec->num_ids; i++) {
> +		u32 sid = fwspec->ids[i];
> +
> +		if (dev_is_pci(dev)) {
> +			struct pci_dev *pdev = to_pci_dev(dev);
> +
> +			snprintf(name, sizeof(name), "%04x:%02x:%02x.%d:%u",
> +				 pci_domain_nr(pdev->bus), pdev->bus->number,
> +				 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
> +				 sid);

Doesn't dev_name(dev) print the BDF numbers as well?

> +		} else {
> +			snprintf(name, sizeof(name), "%s:%u", dev_name(dev),
> +				 sid);
> +		}
> +
> +		dev_dir = debugfs_create_dir(name, stream_dir);
> +		if (!dev_dir) {
> +			ret = -ENOMEM;
> +			goto cleanup;
> +		}

A device can have multiple streams. So, dev_dir should be the
parent directory?

> +
> +		/* Success for this stream ID, continue to next */
> +		continue;
> +
> +cleanup_dev:
> +		debugfs_remove_recursive(dev_dir);
> +cleanup:
> +		if (ret) {
> +			debugfs_remove_recursive(stream_dir);

One is the other's parent directory. So it should be good enough
with a single debugfs_remove_recursive()?

> 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 211a0c87507a..c57897e5f644 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -3133,6 +3133,9 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev,
>  
>  	arm_smmu_attach_commit(&state);
>  	mutex_unlock(&arm_smmu_asid_lock);
> +#ifdef CONFIG_ARM_SMMU_V3_DEBUGFS
> +	smmu_debugfs_create_stream_table(dev, smmu);
> +#endif

Calling in attach_dev doesn't seem correct to me. And device/master
can be unplugged. So, we would need to unwind those dev/stream_dir.

Maybe probe_device/release_device are the places to go?

Nicolin


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

* Re: [RFC PATCH 5/5] iommu/arm-smmu-v3: Add Context Descriptor display to debugfs
  2026-03-13 10:43 ` [RFC PATCH 5/5] iommu/arm-smmu-v3: Add Context Descriptor display " Qinxin Xia
@ 2026-03-13 21:04   ` Nicolin Chen
  2026-03-16 15:12     ` Qinxin Xia
  2026-03-16 15:42   ` Robin Murphy
  1 sibling, 1 reply; 24+ messages in thread
From: Nicolin Chen @ 2026-03-13 21:04 UTC (permalink / raw)
  To: Qinxin Xia
  Cc: will, robin.murphy, jpb, linux-arm-kernel, iommu, wangzhou1,
	prime.zeng, fanghao11, jonathan.cameron, linuxarm

On Fri, Mar 13, 2026 at 06:43:51PM +0800, Qinxin Xia wrote:
>   * Directory Structure:
>   * /sys/kernel/debug/iommu/arm_smmu_v3/
>   * └── smmu0/
> @@ -35,6 +42,8 @@
>   *     └── stream_table
>   *	   └── 0000:01:00.0:0/                    # PCI device with Stream ID 0
>   *             ├── ste                           # Stream Table Entry
> + *             └── context_descriptors/
> + *                 └── all                       # All Context Descriptors

I wonder if we should do per-RID/PASID v.s. all. Otherwise, cd_dir
seems unnecessary, as it could be a file instead?

> +/**
> + * smmu_debug_dump_cd() - Dump Context Descriptor details to seq_file
> + * @seq: seq_file to write to
> + * @dev: device associated with the CD
> + * @ssid: Substream ID
> + */
> +static void smmu_debug_dump_cd(struct seq_file *seq, struct device *dev, u32 ssid)
> +{
> +	struct arm_smmu_master *master = dev_iommu_priv_get(dev);
> +	struct arm_smmu_cd *cd;
> +	u64 data;
> +	int i;
> +
> +	if (!master) {
> +		seq_puts(seq, "No master data\n");
> +		return;
> +	}
> +
> +	cd = arm_smmu_get_cd_ptr(master, ssid);
> +	if (!cd) {
> +		seq_printf(seq, "CD not available for SSID %u\n", ssid);
> +		return;
> +	}

master->cd_table can be free-ed. We could hit UAF in a race. This
very likely needs arm_smmu_asid_lock.

> +	seq_printf(seq, "CD for Substream ID %u:\n", ssid);
> +
> +	/* CD 0 */
> +	data = le64_to_cpu(cd->data[0]);
> +	seq_printf(seq, "  Valid: %s\n", data & CTXDESC_CD_0_V ? "Yes" : "No");
> +	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");

All these are unnecessary if V=0? Maybe the per-SSID output should
depend on V=1 at all. Same might apply to STE.

> +/* All CDs debugfs file operations */
> +static int smmu_debugfs_all_cds_show(struct seq_file *seq, void *v)
> +{
> +	struct device *dev = seq->private;
> +
> +	smmu_debug_dump_all_cds(seq, dev);
> +	return 0;

Just unwrap the smmu_debug_dump_all_cds().

Nicolin


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

* Re: [RFC PATCH 4/5] iommu/arm-smmu-v3: Add stream table directory structure to debugfs
  2026-03-13 20:44   ` Nicolin Chen
@ 2026-03-16 14:57     ` Qinxin Xia
  0 siblings, 0 replies; 24+ messages in thread
From: Qinxin Xia @ 2026-03-16 14:57 UTC (permalink / raw)
  To: Nicolin Chen
  Cc: will, robin.murphy, jpb, linux-arm-kernel, iommu, wangzhou1,
	prime.zeng, fanghao11, jonathan.cameron, linuxarm



On 2026/3/14 04:44:49, Nicolin Chen <nicolinc@nvidia.com> wrote:
> On Fri, Mar 13, 2026 at 06:43:50PM +0800, Qinxin Xia wrote:
>>    * The capabilities file provides detailed information about:
>>    * - Architecture version and translation stage support (Stage1/Stage2)
>> @@ -324,5 +327,78 @@ static int smmu_debugfs_ste_show(struct seq_file *seq, void *v)
>>   	smmu_debug_dump_ste(seq, dev);
>>   	return 0;
>>   }
>> -
>>   DEFINE_SHOW_ATTRIBUTE(smmu_debugfs_ste);
> 
> nit: let's not add that line in the first place
> 
>> +
>> +/**
>> + * 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 smmu_debugfs_create_stream_table(struct device *dev,
>> +				     struct arm_smmu_device *smmu)
>> +{
>> +	struct dentry *stream_dir, *cd_dir, *dev_dir;
>> +	struct dentry *ste_file, *all_cds_file;
>> +	struct iommu_fwspec *fwspec;
>> +	char name[64];
>> +	int i, ret = 0;
>> +
>> +	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;
>> +	}
>> +
>> +	fwspec = dev_iommu_fwspec_get(dev);
>> +	if (!fwspec)
>> +		return -ENODEV;
>> +
>> +	for (i = 0; i < fwspec->num_ids; i++) {
>> +		u32 sid = fwspec->ids[i];
>> +
>> +		if (dev_is_pci(dev)) {
>> +			struct pci_dev *pdev = to_pci_dev(dev);
>> +
>> +			snprintf(name, sizeof(name), "%04x:%02x:%02x.%d:%u",
>> +				 pci_domain_nr(pdev->bus), pdev->bus->number,
>> +				 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
>> +				 sid);
> 
> Doesn't dev_name(dev) print the BDF numbers as well?
> 
>> +		} else {
>> +			snprintf(name, sizeof(name), "%s:%u", dev_name(dev),
>> +				 sid);
>> +		}
>> +
>> +		dev_dir = debugfs_create_dir(name, stream_dir);
>> +		if (!dev_dir) {
>> +			ret = -ENOMEM;
>> +			goto cleanup;
>> +		}
> 
> A device can have multiple streams. So, dev_dir should be the
> parent directory?
> 
dev_dir is a parent directory and it contains ste info and CD info
for all streams of this device.

[root@localhost stream_table]# ls
0000:34:00.0:13312  0000:34:01.0:13320  0000:35:00.0:13568 
0000:35:00.1:13569  0000:35:00.2:13570  0000:35:00.3:13571
[root@localhost stream_table]# cd 0000\:34\:00.0\:13312/
[root@localhost 0000:34:00.0:13312]# ls
context_descriptors  ste
[root@localhost 0000:34:00.0:13312]#
>> +
>> +		/* Success for this stream ID, continue to next */
>> +		continue;
>> +
>> +cleanup_dev:
>> +		debugfs_remove_recursive(dev_dir);
>> +cleanup:
>> +		if (ret) {
>> +			debugfs_remove_recursive(stream_dir);
> 
> One is the other's parent directory. So it should be good enough
> with a single debugfs_remove_recursive()?
> 
>> 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 211a0c87507a..c57897e5f644 100644
>> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> @@ -3133,6 +3133,9 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev,
>>   
>>   	arm_smmu_attach_commit(&state);
>>   	mutex_unlock(&arm_smmu_asid_lock);
>> +#ifdef CONFIG_ARM_SMMU_V3_DEBUGFS
>> +	smmu_debugfs_create_stream_table(dev, smmu);
>> +#endif
> 
> Calling in attach_dev doesn't seem correct to me. And device/master
> can be unplugged. So, we would need to unwind those dev/stream_dir.
> 
> Maybe probe_device/release_device are the places to go?
> 
> Nicolin
> 
Thanks for your review,
I will fix these bugs in the next RFC version.
-- 
Thanks,
Qinxin



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

* Re: [RFC PATCH 5/5] iommu/arm-smmu-v3: Add Context Descriptor display to debugfs
  2026-03-13 21:04   ` Nicolin Chen
@ 2026-03-16 15:12     ` Qinxin Xia
  0 siblings, 0 replies; 24+ messages in thread
From: Qinxin Xia @ 2026-03-16 15:12 UTC (permalink / raw)
  To: Nicolin Chen
  Cc: will, robin.murphy, jpb, linux-arm-kernel, iommu, wangzhou1,
	prime.zeng, fanghao11, jonathan.cameron, linuxarm



On 2026/3/14 05:04:10, Nicolin Chen <nicolinc@nvidia.com> wrote:
> On Fri, Mar 13, 2026 at 06:43:51PM +0800, Qinxin Xia wrote:
>>    * Directory Structure:
>>    * /sys/kernel/debug/iommu/arm_smmu_v3/
>>    * └── smmu0/
>> @@ -35,6 +42,8 @@
>>    *     └── stream_table
>>    *	   └── 0000:01:00.0:0/                    # PCI device with Stream ID 0
>>    *             ├── ste                           # Stream Table Entry
>> + *             └── context_descriptors/
>> + *                 └── all                       # All Context Descriptors
> 
> I wonder if we should do per-RID/PASID v.s. all. Otherwise, cd_dir
> seems unnecessary, as it could be a file instead?
> 

That's exactly what I'm thinking about.
Per-PASID could be better expanded, but now all maybe is enough.

>> +/**
>> + * smmu_debug_dump_cd() - Dump Context Descriptor details to seq_file
>> + * @seq: seq_file to write to
>> + * @dev: device associated with the CD
>> + * @ssid: Substream ID
>> + */
>> +static void smmu_debug_dump_cd(struct seq_file *seq, struct device *dev, u32 ssid)
>> +{
>> +	struct arm_smmu_master *master = dev_iommu_priv_get(dev);
>> +	struct arm_smmu_cd *cd;
>> +	u64 data;
>> +	int i;
>> +
>> +	if (!master) {
>> +		seq_puts(seq, "No master data\n");
>> +		return;
>> +	}
>> +
>> +	cd = arm_smmu_get_cd_ptr(master, ssid);
>> +	if (!cd) {
>> +		seq_printf(seq, "CD not available for SSID %u\n", ssid);
>> +		return;
>> +	}
> 
> master->cd_table can be free-ed. We could hit UAF in a race. This
> very likely needs arm_smmu_asid_lock.
> 
>> +	seq_printf(seq, "CD for Substream ID %u:\n", ssid);
>> +
>> +	/* CD 0 */
>> +	data = le64_to_cpu(cd->data[0]);
>> +	seq_printf(seq, "  Valid: %s\n", data & CTXDESC_CD_0_V ? "Yes" : "No");
>> +	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");
> 
> All these are unnecessary if V=0? Maybe the per-SSID output should
> depend on V=1 at all. Same might apply to STE.
> 
I made this judgment before dump:

		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, dev, ssid);
		}

So, the CDs dumped here are valid.
You remind me that "Valid" print can be omitted here :-)

>> +/* All CDs debugfs file operations */
>> +static int smmu_debugfs_all_cds_show(struct seq_file *seq, void *v)
>> +{
>> +	struct device *dev = seq->private;
>> +
>> +	smmu_debug_dump_all_cds(seq, dev);
>> +	return 0;
> 
> Just unwrap the smmu_debug_dump_all_cds().
> 
> Nicolin
> 
-- 
Thanks,
Qinxin



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

* Re: [RFC PATCH 1/5] iommu/arm-smmu-v3: Add basic debugfs framework
  2026-03-13 19:58   ` Nicolin Chen
@ 2026-03-16 15:14     ` Qinxin Xia
  0 siblings, 0 replies; 24+ messages in thread
From: Qinxin Xia @ 2026-03-16 15:14 UTC (permalink / raw)
  To: Nicolin Chen
  Cc: will, robin.murphy, jpb, linux-arm-kernel, iommu, wangzhou1,
	prime.zeng, fanghao11, jonathan.cameron, linuxarm



On 2026/3/14 03:58:44, Nicolin Chen <nicolinc@nvidia.com> wrote:
> On Fri, Mar 13, 2026 at 06:43:47PM +0800, Qinxin Xia wrote:
>> +/**
>> + * smmu_debugfs_capabilities_show() - Display SMMU capabilities
>> + * @seq: seq_file to write to
>> + * @v: private data (SMMU device)
> 
> @v is not used
> 
>> +
>> +/**
>> + * arm_smmu_debugfs_setup() - Initialize debugfs for SMMU device
>> + * @smmu: SMMU device to setup debugfs for
>> + * @ioaddr: Physical base address of the SMMU device registers
>> + *
>> + * This function creates the basic debugfs directory structure for a SMMU device.
> 
> nit: an SMMU
> 
> Or maybe simply "@smmu"
> 
>> + *
>> + * Return: 0 on success, negative error code on failure
>> + */
>> +int arm_smmu_debugfs_setup(struct arm_smmu_device *smmu, phys_addr_t ioaddr)
>> +{
>> +	struct arm_smmu_debugfs *debugfs;
>> +	struct dentry *smmu_dir;
>> +	char name[32];
>> +	int ret;
>> +
>> +	/* Create root directory if it doesn't exist */
>> +	mutex_lock(&arm_smmu_debugfs_lock);
>> +	if (!smmuv3_root_dir) {
>> +		smmuv3_root_dir = debugfs_create_dir("arm_smmu_v3",
>> +						     iommu_debugfs_dir);
>> +		if (!smmuv3_root_dir) {
>> +			mutex_unlock(&arm_smmu_debugfs_lock);
>> +			return -ENOMEM;
>> +		}
>> +	}
>> +	mutex_unlock(&arm_smmu_debugfs_lock);
>> +
>> +	/* Allocate debugfs structure */
>> +	debugfs = kzalloc(sizeof(*debugfs), GFP_KERNEL);
> 
> kzalloc_obj(*debugfs)
> 
>> 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..211a0c87507a 100644
>> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> @@ -33,6 +33,10 @@
>>   #include "arm-smmu-v3.h"
>>   #include "../../dma-iommu.h"
>>   
>> +#ifdef CONFIG_ARM_SMMU_V3_DEBUGFS
>> +static unsigned int arm_smmu_present;
>> +#endif
> 
> Unused
> 
>> @@ -4909,6 +4913,12 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
>>   	if (ret)
>>   		goto err_disable;
>>   
>> +#ifdef CONFIG_ARM_SMMU_V3_DEBUGFS
>> +	ret = arm_smmu_debugfs_setup(smmu, ioaddr);
>> +	if (ret)
>> +		dev_warn(dev, "Failed to create debugfs!\n");
>> +#endif
>> +
>>   	/* And we're up. Go go go! */
>>   	ret = iommu_device_sysfs_add(&smmu->iommu, dev, NULL,
>>   				     "smmu3.%pa", &ioaddr);
> 
> Since name is all we wanted, maybe follow iommu_device_sysfs_add()
> by passing in:
>     "const char *name, ..." instead of "phys_addr_t ioaddr"
> 
>> 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..247f27426f6b 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,15 @@ struct arm_smmu_impl_ops {
>>   			  const struct iommu_user_data *user_data);
>>   };
>>   
>> +#ifdef CONFIG_ARM_SMMU_V3_DEBUGFS
>> +struct arm_smmu_debugfs {
>> +	struct dentry *root_dir;
> 
> Unused
> 
>> +	struct dentry *smmu_dir;
>> +	struct arm_smmu_device *smmu;
> 
> Unused
> 
> Nicolin
> 

I'll delete the unuse variable, but I'll keep this struct there for
extensions.
-- 
Thanks,
Qinxin



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

* Re: [RFC PATCH 2/5] iommu/arm-smmu-v3: Add register display to debugfs
  2026-03-13 10:43 ` [RFC PATCH 2/5] iommu/arm-smmu-v3: Add register display to debugfs Qinxin Xia
  2026-03-13 20:20   ` Nicolin Chen
@ 2026-03-16 15:19   ` Robin Murphy
  2026-03-16 15:35     ` Qinxin Xia
  1 sibling, 1 reply; 24+ messages in thread
From: Robin Murphy @ 2026-03-16 15:19 UTC (permalink / raw)
  To: Qinxin Xia, will, jpb
  Cc: linux-arm-kernel, iommu, wangzhou1, prime.zeng, fanghao11,
	jonathan.cameron, linuxarm

On 2026-03-13 10:43 am, Qinxin Xia wrote:
> 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     | 68 ++++++++++++++++++-
>   1 file changed, 67 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 542bd6047f26..f9bf955f3351 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
> @@ -12,11 +12,20 @@
>    * - Capability reporting covering all major SMMU features and configuration
>    * - Extensible architecture designed for adding future debug functionality
>    * - Comprehensive error handling and resource cleanup
> + * - Display of control registers (CR0, CR1, CR2) with bitfield decoding
> + * - Command and Event queue pointer monitoring (PROD/CONS)
> + *
> + * Register Information Displayed:
> + * - CR0: SMMU global control with enable states and queue enables
> + * - CR1/CR2: Additional control and configuration registers
> + * - CMDQ_PROD/CONS: Command queue producer and consumer pointers
> + * - EVTQ_PROD/CONS: Event queue producer and consumer pointers
>    *
>    * Directory Structure:
>    * /sys/kernel/debug/iommu/arm_smmu_v3/
>    * └── smmu0/
> - *     └── capabilities    # SMMU feature capabilities and configuration
> + *     ├── capabilities    # SMMU feature capabilities and configuration
> + *     └── registers	   # SMMU Key registers
>    *
>    * The capabilities file provides detailed information about:
>    * - Architecture version and translation stage support (Stage1/Stage2)
> @@ -24,6 +33,11 @@
>    * - Stream table size and command/event queue depths
>    * - All feature bits from the SMMU device structure
>    *
> + * The register display provides crucial visibility into:
> + * - SMMU operational state (enabled/disabled)
> + * - Queue operation and potential stalls
> + * - Configuration settings affecting all streams
> + *
>    * Copyright (C) 2025 HiSilicon Limited.
>    * Author: Qinxin Xia <xiaqinxin@huawei.com>
>    */
> @@ -69,6 +83,54 @@ static int smmu_debugfs_capabilities_show(struct seq_file *seq, void *v)
>   }
>   DEFINE_SHOW_ATTRIBUTE(smmu_debugfs_capabilities);
>   
> +/**
> + * smmu_debugfs_registers_show() - Display SMMU register values
> + * @seq: seq_file to write to
> + * @v: private data (SMMU device)
> + *
> + * Return: 0 on success, negative error code on failure
> + */
> +static int smmu_debugfs_registers_show(struct seq_file *seq, void *v)
> +{
> +	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 [%s%s%s]\n",
> +		   readl_relaxed(base + ARM_SMMU_CR0),
> +		   readl_relaxed(base + ARM_SMMU_CR0) & CR0_SMMUEN ?
> +		   "Enabled " : "Disabled ",
> +		   readl_relaxed(base + ARM_SMMU_CR0) & CR0_EVTQEN ?
> +		   "EventQ " : "",
> +		   readl_relaxed(base + ARM_SMMU_CR0) & CR0_CMDQEN ?
> +		   "CmdQ " : "");

There's really no point printing these extra strings, since if any of 
those were *not* enabled then we'd have already failed probe and never 
created the debugfs entry. And if anyone ever were to be trying to 
change the driver behaviour at that level, I'd very much expect them to 
be able to be able to read the bottom 4 bits of a CR0 value in hex anyway ;)

Thanks,
Robin.

> +
> +	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;
> +}
> +DEFINE_SHOW_ATTRIBUTE(smmu_debugfs_registers);
> +
>   /**
>    * arm_smmu_debugfs_setup() - Initialize debugfs for SMMU device
>    * @smmu: SMMU device to setup debugfs for
> @@ -120,6 +182,10 @@ int arm_smmu_debugfs_setup(struct arm_smmu_device *smmu, phys_addr_t ioaddr)
>   				 &smmu_debugfs_capabilities_fops))
>   		goto err_cleanup;
>   
> +	if (!debugfs_create_file("registers", 0444, smmu_dir, smmu,
> +				 &smmu_debugfs_registers_fops))
> +		goto err_cleanup;
> +
>   	pr_info("SMMUv3 debugfs initialized for smmu%pa\n", &ioaddr);
>   	return 0;
>   



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

* Re: [RFC PATCH 2/5] iommu/arm-smmu-v3: Add register display to debugfs
  2026-03-13 20:20   ` Nicolin Chen
@ 2026-03-16 15:22     ` Qinxin Xia
  0 siblings, 0 replies; 24+ messages in thread
From: Qinxin Xia @ 2026-03-16 15:22 UTC (permalink / raw)
  To: Nicolin Chen
  Cc: will, robin.murphy, jpb, linux-arm-kernel, iommu, wangzhou1,
	prime.zeng, fanghao11, jonathan.cameron, linuxarm



On 2026/3/14 04:20:23, Nicolin Chen <nicolinc@nvidia.com> wrote:
> On Fri, Mar 13, 2026 at 06:43:48PM +0800, Qinxin Xia wrote:
>> +/**
>> + * smmu_debugfs_registers_show() - Display SMMU register values
>> + * @seq: seq_file to write to
>> + * @v: private data (SMMU device)
>> + *
>> + * Return: 0 on success, negative error code on failure
>> + */
>> +static int smmu_debugfs_registers_show(struct seq_file *seq, void *v)
> 
> @v seems unused as well.
> 
> Nicolin
> 

Thank you for your review. All comments and function encapsulation
problems will be fixed in the next version.
-- 
Thanks,
Qinxin



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

* Re: [RFC PATCH 2/5] iommu/arm-smmu-v3: Add register display to debugfs
  2026-03-16 15:19   ` Robin Murphy
@ 2026-03-16 15:35     ` Qinxin Xia
  2026-03-16 16:26       ` Robin Murphy
  0 siblings, 1 reply; 24+ messages in thread
From: Qinxin Xia @ 2026-03-16 15:35 UTC (permalink / raw)
  To: Robin Murphy, will, jpb
  Cc: linux-arm-kernel, iommu, wangzhou1, prime.zeng, fanghao11,
	jonathan.cameron, linuxarm



On 2026/3/16 23:19:53, Robin Murphy <robin.murphy@arm.com> wrote:
> On 2026-03-13 10:43 am, Qinxin Xia wrote:
>> 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     | 68 ++++++++++++++++++-
>>   1 file changed, 67 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 542bd6047f26..f9bf955f3351 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
>> @@ -12,11 +12,20 @@
>>    * - Capability reporting covering all major SMMU features and 
>> configuration
>>    * - Extensible architecture designed for adding future debug 
>> functionality
>>    * - Comprehensive error handling and resource cleanup
>> + * - Display of control registers (CR0, CR1, CR2) with bitfield decoding
>> + * - Command and Event queue pointer monitoring (PROD/CONS)
>> + *
>> + * Register Information Displayed:
>> + * - CR0: SMMU global control with enable states and queue enables
>> + * - CR1/CR2: Additional control and configuration registers
>> + * - CMDQ_PROD/CONS: Command queue producer and consumer pointers
>> + * - EVTQ_PROD/CONS: Event queue producer and consumer pointers
>>    *
>>    * Directory Structure:
>>    * /sys/kernel/debug/iommu/arm_smmu_v3/
>>    * └── smmu0/
>> - *     └── capabilities    # SMMU feature capabilities and configuration
>> + *     ├── capabilities    # SMMU feature capabilities and configuration
>> + *     └── registers       # SMMU Key registers
>>    *
>>    * The capabilities file provides detailed information about:
>>    * - Architecture version and translation stage support (Stage1/Stage2)
>> @@ -24,6 +33,11 @@
>>    * - Stream table size and command/event queue depths
>>    * - All feature bits from the SMMU device structure
>>    *
>> + * The register display provides crucial visibility into:
>> + * - SMMU operational state (enabled/disabled)
>> + * - Queue operation and potential stalls
>> + * - Configuration settings affecting all streams
>> + *
>>    * Copyright (C) 2025 HiSilicon Limited.
>>    * Author: Qinxin Xia <xiaqinxin@huawei.com>
>>    */
>> @@ -69,6 +83,54 @@ static int smmu_debugfs_capabilities_show(struct 
>> seq_file *seq, void *v)
>>   }
>>   DEFINE_SHOW_ATTRIBUTE(smmu_debugfs_capabilities);
>> +/**
>> + * smmu_debugfs_registers_show() - Display SMMU register values
>> + * @seq: seq_file to write to
>> + * @v: private data (SMMU device)
>> + *
>> + * Return: 0 on success, negative error code on failure
>> + */
>> +static int smmu_debugfs_registers_show(struct seq_file *seq, void *v)
>> +{
>> +    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 [%s%s%s]\n",
>> +           readl_relaxed(base + ARM_SMMU_CR0),
>> +           readl_relaxed(base + ARM_SMMU_CR0) & CR0_SMMUEN ?
>> +           "Enabled " : "Disabled ",
>> +           readl_relaxed(base + ARM_SMMU_CR0) & CR0_EVTQEN ?
>> +           "EventQ " : "",
>> +           readl_relaxed(base + ARM_SMMU_CR0) & CR0_CMDQEN ?
>> +           "CmdQ " : "");
> 
> There's really no point printing these extra strings, since if any of 
> those were *not* enabled then we'd have already failed probe and never 
> created the debugfs entry. And if anyone ever were to be trying to 
> change the driver behaviour at that level, I'd very much expect them to 
> be able to be able to read the bottom 4 bits of a CR0 value in hex 
> anyway ;)
> 
> Thanks,
> Robin.
> 

Since Kunpeng supports ECMDQ(have not been submitted upstream), the
intention was to check whether the SMMU supports ECMDQ, and the logging
for other queues was added incidentally. The prints for the event queue
and command queue indeed seem unnecessary. I will remove them in the
next version.

>> +
>> +    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;
>> +}
>> +DEFINE_SHOW_ATTRIBUTE(smmu_debugfs_registers);
>> +
>>   /**
>>    * arm_smmu_debugfs_setup() - Initialize debugfs for SMMU device
>>    * @smmu: SMMU device to setup debugfs for
>> @@ -120,6 +182,10 @@ int arm_smmu_debugfs_setup(struct arm_smmu_device 
>> *smmu, phys_addr_t ioaddr)
>>                    &smmu_debugfs_capabilities_fops))
>>           goto err_cleanup;
>> +    if (!debugfs_create_file("registers", 0444, smmu_dir, smmu,
>> +                 &smmu_debugfs_registers_fops))
>> +        goto err_cleanup;
>> +
>>       pr_info("SMMUv3 debugfs initialized for smmu%pa\n", &ioaddr);
>>       return 0;
> 
> 

-- 
Thanks,
Qinxin



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

* Re: [RFC PATCH 5/5] iommu/arm-smmu-v3: Add Context Descriptor display to debugfs
  2026-03-13 10:43 ` [RFC PATCH 5/5] iommu/arm-smmu-v3: Add Context Descriptor display " Qinxin Xia
  2026-03-13 21:04   ` Nicolin Chen
@ 2026-03-16 15:42   ` Robin Murphy
  2026-03-17  2:14     ` Qinxin Xia
  1 sibling, 1 reply; 24+ messages in thread
From: Robin Murphy @ 2026-03-16 15:42 UTC (permalink / raw)
  To: Qinxin Xia, will, jpb
  Cc: linux-arm-kernel, iommu, wangzhou1, prime.zeng, fanghao11,
	jonathan.cameron, linuxarm

On 2026-03-13 10:43 am, Qinxin Xia wrote:
> 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/
> └── 0000:01:00.0:0/
>      ├── ste
>      └── context_descriptors/
>          └── all
> 
> Signed-off-by: Qinxin Xia <xiaqinxin@huawei.com>
> ---
>   .../arm/arm-smmu-v3/arm-smmu-v3-debugfs.c     | 112 ++++++++++++++++++
>   1 file changed, 112 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 f62df02847ac..66ae1228c6ad 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
> @@ -27,6 +27,13 @@
>    * - Context Pointers: Stage 1 and Stage 2 translation context addresses
>    * - Raw Data: Complete 64-bit STE words in hexadecimal
>    *
> + * CD Information Displayed:
> + * - Validity: Active state of the context descriptor
> + * - 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
> + *
>    * Directory Structure:
>    * /sys/kernel/debug/iommu/arm_smmu_v3/
>    * └── smmu0/
> @@ -35,6 +42,8 @@
>    *     └── stream_table
>    *	   └── 0000:01:00.0:0/                    # PCI device with Stream ID 0
>    *             ├── ste                           # Stream Table Entry
> + *             └── context_descriptors/
> + *                 └── all                       # All Context Descriptors
>    *
>    * The capabilities file provides detailed information about:
>    * - Architecture version and translation stage support (Stage1/Stage2)
> @@ -59,6 +68,8 @@
>   static struct dentry *smmuv3_root_dir;
>   static DEFINE_MUTEX(arm_smmu_debugfs_lock);
>   
> +#define MAX_SSIDS	32	/* Reasonable limit for SSID enumeration */

Arbitrarily limiting to only 32 out of a potential 2^20 SSIDs seems odd, 
like it's rather more than needed for basic sanity-checking, but far too 
few for debugging specific usage.

FWIW I'd imagine it might be more useful to expose the CDs as individual 
files by index - and if userspace does want an "all" dump then there's 
always `cat`. Whether that would be all of them unconditionally based on 
the current STE.S1CDMAX, or just the "active" ones based on PASID 
allocations and S1DSS, is probably a question of what people think is 
most useful (and/or how fiddly it is to actually implement the latter).

> +
>   /**
>    * smmu_debugfs_capabilities_show() - Display SMMU capabilities
>    * @seq: seq_file to write to
> @@ -329,6 +340,90 @@ static int smmu_debugfs_ste_show(struct seq_file *seq, void *v)
>   }
>   DEFINE_SHOW_ATTRIBUTE(smmu_debugfs_ste);
>   
> +/**
> + * smmu_debug_dump_cd() - Dump Context Descriptor details to seq_file
> + * @seq: seq_file to write to
> + * @dev: device associated with the CD
> + * @ssid: Substream ID
> + */
> +static void smmu_debug_dump_cd(struct seq_file *seq, struct device *dev, u32 ssid)
> +{
> +	struct arm_smmu_master *master = dev_iommu_priv_get(dev);
> +	struct arm_smmu_cd *cd;
> +	u64 data;
> +	int i;
> +
> +	if (!master) {
> +		seq_puts(seq, "No master data\n");
> +		return;
> +	}

If userspace can read these files racily with devices being removed then:

1) we should probably return an actual read error if the device has 
already disappeared such the file is no longer valid.

2) how do we know the device isn't going to disappear, and thus "master" 
become invalid, immediately *after* this check happens to pass?

Thanks,
Robin.

> +
> +	cd = arm_smmu_get_cd_ptr(master, ssid);
> +	if (!cd) {
> +		seq_printf(seq, "CD not available for SSID %u\n", ssid);
> +		return;
> +	}
> +
> +	seq_printf(seq, "CD for Substream ID %u:\n", ssid);
> +
> +	/* CD 0 */
> +	data = le64_to_cpu(cd->data[0]);
> +	seq_printf(seq, "  Valid: %s\n", data & CTXDESC_CD_0_V ? "Yes" : "No");
> +	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]));
> +}
> +
> +/**
> + * smmu_debug_dump_all_cds() - Dump all valid Context Descriptors for a device
> + * @seq: seq_file to write to
> + * @dev: target device
> + */
> +static void smmu_debug_dump_all_cds(struct seq_file *seq, struct device *dev)
> +{
> +	struct arm_smmu_master *master = dev_iommu_priv_get(dev);
> +	u32 max_ssids, ssid;
> +
> +	if (!master) {
> +		seq_puts(seq, "No master data\n");
> +		return;
> +	}
> +
> +	max_ssids = min_t(u32, 1 << master->ssid_bits, MAX_SSIDS);
> +
> +	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, dev, ssid);
> +		}
> +	}
> +}
> +
> +/* All CDs debugfs file operations */
> +static int smmu_debugfs_all_cds_show(struct seq_file *seq, void *v)
> +{
> +	struct device *dev = seq->private;
> +
> +	smmu_debug_dump_all_cds(seq, dev);
> +	return 0;
> +}
> +DEFINE_SHOW_ATTRIBUTE(smmu_debugfs_all_cds);
> +
>   /**
>    * smmu_debugfs_create_stream_table() - Create debugfs entries for stream table
>    * @dev: device to create entries for
> @@ -388,9 +483,26 @@ int smmu_debugfs_create_stream_table(struct device *dev,
>   			goto cleanup_dev;
>   		}
>   
> +		/* Create CD directory */
> +		cd_dir = debugfs_create_dir("context_descriptors", dev_dir);
> +		if (!cd_dir) {
> +			ret = -ENOMEM;
> +			goto cleanup_dev;
> +		}
> +
> +		/* Create "all" file to show all valid CDs */
> +		all_cds_file = debugfs_create_file("all", 0444, cd_dir, dev,
> +						   &smmu_debugfs_all_cds_fops);
> +		if (!all_cds_file) {
> +			ret = -ENOMEM;
> +			goto cleanup_cd;
> +		}
> +
>   		/* Success for this stream ID, continue to next */
>   		continue;
>   
> +cleanup_cd:
> +		debugfs_remove(cd_dir);
>   cleanup_dev:
>   		debugfs_remove_recursive(dev_dir);
>   cleanup:



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

* Re: [RFC PATCH 3/5] iommu/arm-smmu-v3: Add Stream Table Entry display to debugfs
  2026-03-13 20:19   ` Nicolin Chen
@ 2026-03-16 15:43     ` Qinxin Xia
  0 siblings, 0 replies; 24+ messages in thread
From: Qinxin Xia @ 2026-03-16 15:43 UTC (permalink / raw)
  To: Nicolin Chen
  Cc: will, robin.murphy, jpb, linux-arm-kernel, iommu, wangzhou1,
	prime.zeng, fanghao11, jonathan.cameron, linuxarm



On 2026/3/14 04:19:14, Nicolin Chen <nicolinc@nvidia.com> wrote:
> On Fri, Mar 13, 2026 at 06:43:49PM +0800, Qinxin Xia wrote:
>> 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
>> @@ -43,6 +49,8 @@
>>    */
>>   
>>   #include <linux/debugfs.h>
>> +#include <linux/pci.h>
> 
> It doesn't seem being used (yet).
> 
>> +static struct arm_smmu_ste *smmu_get_ste(struct arm_smmu_device *smmu, u32 sid)
>> +{
>> +	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
>> +
>> +	if (sid >= (1 << smmu->sid_bits))
>> +		return NULL;
>> +
>> +	if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) {
>> +		u32 l1_idx = arm_smmu_strtab_l1_idx(sid);
>> +		u32 l2_idx = arm_smmu_strtab_l2_idx(sid);
>> +
>> +		if (l1_idx >= cfg->l2.num_l1_ents || !cfg->l2.l2ptrs[l1_idx])
>> +			return NULL;
>> +
>> +		return &cfg->l2.l2ptrs[l1_idx]->stes[l2_idx];
>> +	}
>> +
>> +	return &cfg->linear.table[sid];
>> +}
> 
> arm_smmu_get_step_for_sid() instead?
> 
>> +/**
>> + * smmu_debug_dump_ste() - Dump STE details to seq_file
>> + * @seq: seq_file to write to
>> + * @dev: device associated with the STE
>> + */
>> +static void smmu_debug_dump_ste(struct seq_file *seq, struct device *dev)
>> +{
>> +	struct arm_smmu_master *master = dev_iommu_priv_get(dev);
>> +	struct arm_smmu_device *smmu;
>> +	struct arm_smmu_ste *ste;
>> +	u32 sid, cfg;
>> +	int i;
>> +
>> +	if (!master || !master->smmu) {
>> +		seq_puts(seq, "No SMMU master data\n");
>> +		return;
>> +	}
>> +
>> +	smmu = master->smmu;
>> +
>> +	/* Use first stream ID for debug */
>> +	if (master->num_streams == 0) {
>> +		seq_puts(seq, "No streams configured for device\n");
>> +		return;
>> +	}
>> +	sid = master->streams[0].id;
> 
> These might race with release_device that would destroy master?
> 
Can we lock streams_mutex here?
>> +
>> +	if (sid >= (1 << smmu->sid_bits)) {
>> +		seq_printf(seq, "Invalid Stream ID: %u (max %u)\n",
>> +			   sid, (1 << smmu->sid_bits) - 1);
>> +		return;
>> +	}
> 
> arm_smmu_sid_in_range() instead?
> 
>> +/* STE debugfs file operations */
>> +static int smmu_debugfs_ste_show(struct seq_file *seq, void *v)
>> +{
>> +	struct device *dev = seq->private;
>> +
>> +	smmu_debug_dump_ste(seq, dev);
>> +	return 0;
> 
> Could unwrap smmu_debug_dump_ste().
> 
> Nicolin
> 
As above, I will do clean code in the next version.
-- 
Thanks,
Qinxin



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

* Re: [RFC PATCH 4/5] iommu/arm-smmu-v3: Add stream table directory structure to debugfs
  2026-03-13 10:43 ` [RFC PATCH 4/5] iommu/arm-smmu-v3: Add stream table directory structure " Qinxin Xia
  2026-03-13 20:44   ` Nicolin Chen
@ 2026-03-16 16:01   ` Robin Murphy
  2026-03-17  2:04     ` Qinxin Xia
  1 sibling, 1 reply; 24+ messages in thread
From: Robin Murphy @ 2026-03-16 16:01 UTC (permalink / raw)
  To: Qinxin Xia, will, jpb
  Cc: linux-arm-kernel, iommu, wangzhou1, prime.zeng, fanghao11,
	jonathan.cameron, linuxarm

On 2026-03-13 10:43 am, Qinxin Xia wrote:
> Add stream table directory structure creation to debugfs
> This organizes debugfs entries by device and stream ID:
> 
> /sys/kernel/debug/iommu/arm_smmu_v3/smmu0/stream_table/
> └── 0000:01:00.0:0/
>      └─── ste

Similar to my previous comment on CDs (sorry I'm reading out of order), 
I wonder if it might not be more useful to expose STEs by index, then 
have the name of the associated device as an attribute/link below that. 
Or perhaps even have whole cross-linked "by StreamID" and "by device" 
hierarchies if you want to get really fancy. From userspace it's not 
always easy to know exactly which StreamIDs are owned by which devices, 
and I can say from experience that if you do have to debug things at the 
STE level, the StreamID is often the thing you're starting from. Plus if 
you wanted to, say, check that STEs are correctly disabled after SR-IOV 
VF teardown, then there may not even be a device any more.

Thanks,
Robin.

> Signed-off-by: Qinxin Xia <xiaqinxin@huawei.com>
> ---
>   .../arm/arm-smmu-v3/arm-smmu-v3-debugfs.c     | 80 ++++++++++++++++++-
>   drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   |  3 +
>   drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  4 +
>   3 files changed, 85 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 d7f3defd94a3..f62df02847ac 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
> @@ -31,7 +31,10 @@
>    * /sys/kernel/debug/iommu/arm_smmu_v3/
>    * └── smmu0/
>    *     ├── capabilities    # SMMU feature capabilities and configuration
> - *     └── registers	   # SMMU Key registers
> + *     ├── registers	   # SMMU Key registers
> + *     └── stream_table
> + *	   └── 0000:01:00.0:0/                    # PCI device with Stream ID 0
> + *             ├── ste                           # Stream Table Entry
>    *
>    * The capabilities file provides detailed information about:
>    * - Architecture version and translation stage support (Stage1/Stage2)
> @@ -324,5 +327,78 @@ static int smmu_debugfs_ste_show(struct seq_file *seq, void *v)
>   	smmu_debug_dump_ste(seq, dev);
>   	return 0;
>   }
> -
>   DEFINE_SHOW_ATTRIBUTE(smmu_debugfs_ste);
> +
> +/**
> + * 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 smmu_debugfs_create_stream_table(struct device *dev,
> +				     struct arm_smmu_device *smmu)
> +{
> +	struct dentry *stream_dir, *cd_dir, *dev_dir;
> +	struct dentry *ste_file, *all_cds_file;
> +	struct iommu_fwspec *fwspec;
> +	char name[64];
> +	int i, ret = 0;
> +
> +	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;
> +	}
> +
> +	fwspec = dev_iommu_fwspec_get(dev);
> +	if (!fwspec)
> +		return -ENODEV;
> +
> +	for (i = 0; i < fwspec->num_ids; i++) {
> +		u32 sid = fwspec->ids[i];
> +
> +		if (dev_is_pci(dev)) {
> +			struct pci_dev *pdev = to_pci_dev(dev);
> +
> +			snprintf(name, sizeof(name), "%04x:%02x:%02x.%d:%u",
> +				 pci_domain_nr(pdev->bus), pdev->bus->number,
> +				 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
> +				 sid);
> +		} else {
> +			snprintf(name, sizeof(name), "%s:%u", dev_name(dev),
> +				 sid);
> +		}
> +
> +		dev_dir = debugfs_create_dir(name, stream_dir);
> +		if (!dev_dir) {
> +			ret = -ENOMEM;
> +			goto cleanup;
> +		}
> +
> +		/* Create STE file */
> +		ste_file = debugfs_create_file("ste", 0444, dev_dir, dev,
> +					       &smmu_debugfs_ste_fops);
> +		if (!ste_file) {
> +			ret = -ENOMEM;
> +			goto cleanup_dev;
> +		}
> +
> +		/* Success for this stream ID, continue to next */
> +		continue;
> +
> +cleanup_dev:
> +		debugfs_remove_recursive(dev_dir);
> +cleanup:
> +		if (ret) {
> +			debugfs_remove_recursive(stream_dir);
> +			break;
> +		}
> +	}
> +
> +	return ret;
> +}
> 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 211a0c87507a..c57897e5f644 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -3133,6 +3133,9 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev,
>   
>   	arm_smmu_attach_commit(&state);
>   	mutex_unlock(&arm_smmu_asid_lock);
> +#ifdef CONFIG_ARM_SMMU_V3_DEBUGFS
> +	smmu_debugfs_create_stream_table(dev, smmu);
> +#endif
>   	return 0;
>   }
>   
> 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 247f27426f6b..e9cd24c1ab3c 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> @@ -737,9 +737,13 @@ struct arm_smmu_impl_ops {
>   struct arm_smmu_debugfs {
>   	struct dentry *root_dir;
>   	struct dentry *smmu_dir;
> +	struct dentry *stream_dir;
>   	struct arm_smmu_device *smmu;
>   };
> +
>   int arm_smmu_debugfs_setup(struct arm_smmu_device *smmu, phys_addr_t ioaddr);
> +int smmu_debugfs_create_stream_table(struct device *dev,
> +					struct arm_smmu_device *smmu);
>   #endif
>   
>   /* An SMMUv3 instance */



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

* Re: [RFC PATCH 2/5] iommu/arm-smmu-v3: Add register display to debugfs
  2026-03-16 15:35     ` Qinxin Xia
@ 2026-03-16 16:26       ` Robin Murphy
  2026-03-17  1:44         ` Qinxin Xia
  0 siblings, 1 reply; 24+ messages in thread
From: Robin Murphy @ 2026-03-16 16:26 UTC (permalink / raw)
  To: Qinxin Xia, will, jpb
  Cc: linux-arm-kernel, iommu, wangzhou1, prime.zeng, fanghao11,
	jonathan.cameron, linuxarm

On 2026-03-16 3:35 pm, Qinxin Xia wrote:
>>> +    /* 32-bit control registers */
>>> +    seq_printf(seq, "CR0: 0x%08x [%s%s%s]\n",
>>> +           readl_relaxed(base + ARM_SMMU_CR0),
>>> +           readl_relaxed(base + ARM_SMMU_CR0) & CR0_SMMUEN ?
>>> +           "Enabled " : "Disabled ",
>>> +           readl_relaxed(base + ARM_SMMU_CR0) & CR0_EVTQEN ?
>>> +           "EventQ " : "",
>>> +           readl_relaxed(base + ARM_SMMU_CR0) & CR0_CMDQEN ?
>>> +           "CmdQ " : "");
>>
>> There's really no point printing these extra strings, since if any of 
>> those were *not* enabled then we'd have already failed probe and never 
>> created the debugfs entry. And if anyone ever were to be trying to 
>> change the driver behaviour at that level, I'd very much expect them 
>> to be able to be able to read the bottom 4 bits of a CR0 value in hex 
>> anyway ;)
>>
>> Thanks,
>> Robin.
>>
> 
> Since Kunpeng supports ECMDQ(have not been submitted upstream), the
> intention was to check whether the SMMU supports ECMDQ, and the logging
> for other queues was added incidentally. The prints for the event queue
> and command queue indeed seem unnecessary. I will remove them in the
> next version.
OK, I would make a similar argument that even then, it wouldn't make 
sense to expose debugfs entries for ECMDQ_PROD registers that don't 
exist or we aren't using. Thus their enabled state should similarly be 
inherent in the files being present at all (but again either way, if a 
developer couldn't tell the significance of 0x80xxxxxx vs. 0x00xxxxxx 
already then I'd have to question their capability to usefully debug any 
more subtle ECMDQ behaviour...)

Thanks,
Robin.


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

* Re: [RFC PATCH 2/5] iommu/arm-smmu-v3: Add register display to debugfs
  2026-03-16 16:26       ` Robin Murphy
@ 2026-03-17  1:44         ` Qinxin Xia
  0 siblings, 0 replies; 24+ messages in thread
From: Qinxin Xia @ 2026-03-17  1:44 UTC (permalink / raw)
  To: Robin Murphy, will, jpb
  Cc: linux-arm-kernel, iommu, wangzhou1, prime.zeng, fanghao11,
	jonathan.cameron, linuxarm



On 2026/3/17 00:26:00, Robin Murphy <robin.murphy@arm.com> wrote:
> On 2026-03-16 3:35 pm, Qinxin Xia wrote:
>>>> +    /* 32-bit control registers */
>>>> +    seq_printf(seq, "CR0: 0x%08x [%s%s%s]\n",
>>>> +           readl_relaxed(base + ARM_SMMU_CR0),
>>>> +           readl_relaxed(base + ARM_SMMU_CR0) & CR0_SMMUEN ?
>>>> +           "Enabled " : "Disabled ",
>>>> +           readl_relaxed(base + ARM_SMMU_CR0) & CR0_EVTQEN ?
>>>> +           "EventQ " : "",
>>>> +           readl_relaxed(base + ARM_SMMU_CR0) & CR0_CMDQEN ?
>>>> +           "CmdQ " : "");
>>>
>>> There's really no point printing these extra strings, since if any of 
>>> those were *not* enabled then we'd have already failed probe and 
>>> never created the debugfs entry. And if anyone ever were to be trying 
>>> to change the driver behaviour at that level, I'd very much expect 
>>> them to be able to be able to read the bottom 4 bits of a CR0 value 
>>> in hex anyway ;)
>>>
>>> Thanks,
>>> Robin.
>>>
>>
>> Since Kunpeng supports ECMDQ(have not been submitted upstream), the
>> intention was to check whether the SMMU supports ECMDQ, and the logging
>> for other queues was added incidentally. The prints for the event queue
>> and command queue indeed seem unnecessary. I will remove them in the
>> next version.
> OK, I would make a similar argument that even then, it wouldn't make 
> sense to expose debugfs entries for ECMDQ_PROD registers that don't 
> exist or we aren't using. Thus their enabled state should similarly be 
> inherent in the files being present at all (but again either way, if a 
> developer couldn't tell the significance of 0x80xxxxxx vs. 0x00xxxxxx 
> already then I'd have to question their capability to usefully debug any 
> more subtle ECMDQ behaviour...)
> 
> Thanks,
> Robin.
> 

You're right.
-- 
Thanks,
Qinxin



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

* Re: [RFC PATCH 4/5] iommu/arm-smmu-v3: Add stream table directory structure to debugfs
  2026-03-16 16:01   ` Robin Murphy
@ 2026-03-17  2:04     ` Qinxin Xia
  0 siblings, 0 replies; 24+ messages in thread
From: Qinxin Xia @ 2026-03-17  2:04 UTC (permalink / raw)
  To: Robin Murphy, will, jpb
  Cc: linux-arm-kernel, iommu, wangzhou1, prime.zeng, fanghao11,
	jonathan.cameron, linuxarm



On 2026/3/17 00:01:50, Robin Murphy <robin.murphy@arm.com> wrote:
> On 2026-03-13 10:43 am, Qinxin Xia wrote:
>> Add stream table directory structure creation to debugfs
>> This organizes debugfs entries by device and stream ID:
>>
>> /sys/kernel/debug/iommu/arm_smmu_v3/smmu0/stream_table/
>> └── 0000:01:00.0:0/
>>      └─── ste
> 
> Similar to my previous comment on CDs (sorry I'm reading out of order), 
> I wonder if it might not be more useful to expose STEs by index, then 
> have the name of the associated device as an attribute/link below that. 
> Or perhaps even have whole cross-linked "by StreamID" and "by device" 
> hierarchies if you want to get really fancy. From userspace it's not 
> always easy to know exactly which StreamIDs are owned by which devices, 
> and I can say from experience that if you do have to debug things at the 
> STE level, the StreamID is often the thing you're starting from. Plus if 
> you wanted to, say, check that STEs are correctly disabled after SR-IOV 
> VF teardown, then there may not even be a device any more.
> 
> Thanks,
> Robin.
> 
To quickly obtain the mapping between SIDs and devices, I named the
directory dev_name+sid. Can we keep this naming mode and add a device
link to the directory?

According to Nicolin's suggestion, I plan to release the corresponding
debugfs in release_device in the next version. After VF teardown, users
cannot view information such as ste and cd anymore.

>> Signed-off-by: Qinxin Xia <xiaqinxin@huawei.com>
>> ---
>>   .../arm/arm-smmu-v3/arm-smmu-v3-debugfs.c     | 80 ++++++++++++++++++-
>>   drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   |  3 +
>>   drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  4 +
>>   3 files changed, 85 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 d7f3defd94a3..f62df02847ac 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
>> @@ -31,7 +31,10 @@
>>    * /sys/kernel/debug/iommu/arm_smmu_v3/
>>    * └── smmu0/
>>    *     ├── capabilities    # SMMU feature capabilities and 
>> configuration
>> - *     └── registers       # SMMU Key registers
>> + *     ├── registers       # SMMU Key registers
>> + *     └── stream_table
>> + *       └── 0000:01:00.0:0/                    # PCI device with 
>> Stream ID 0
>> + *             ├── ste                           # Stream Table Entry
>>    *
>>    * The capabilities file provides detailed information about:
>>    * - Architecture version and translation stage support (Stage1/Stage2)
>> @@ -324,5 +327,78 @@ static int smmu_debugfs_ste_show(struct seq_file 
>> *seq, void *v)
>>       smmu_debug_dump_ste(seq, dev);
>>       return 0;
>>   }
>> -
>>   DEFINE_SHOW_ATTRIBUTE(smmu_debugfs_ste);
>> +
>> +/**
>> + * 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 smmu_debugfs_create_stream_table(struct device *dev,
>> +                     struct arm_smmu_device *smmu)
>> +{
>> +    struct dentry *stream_dir, *cd_dir, *dev_dir;
>> +    struct dentry *ste_file, *all_cds_file;
>> +    struct iommu_fwspec *fwspec;
>> +    char name[64];
>> +    int i, ret = 0;
>> +
>> +    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;
>> +    }
>> +
>> +    fwspec = dev_iommu_fwspec_get(dev);
>> +    if (!fwspec)
>> +        return -ENODEV;
>> +
>> +    for (i = 0; i < fwspec->num_ids; i++) {
>> +        u32 sid = fwspec->ids[i];
>> +
>> +        if (dev_is_pci(dev)) {
>> +            struct pci_dev *pdev = to_pci_dev(dev);
>> +
>> +            snprintf(name, sizeof(name), "%04x:%02x:%02x.%d:%u",
>> +                 pci_domain_nr(pdev->bus), pdev->bus->number,
>> +                 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
>> +                 sid);
>> +        } else {
>> +            snprintf(name, sizeof(name), "%s:%u", dev_name(dev),
>> +                 sid);
>> +        }
>> +
>> +        dev_dir = debugfs_create_dir(name, stream_dir);
>> +        if (!dev_dir) {
>> +            ret = -ENOMEM;
>> +            goto cleanup;
>> +        }
>> +
>> +        /* Create STE file */
>> +        ste_file = debugfs_create_file("ste", 0444, dev_dir, dev,
>> +                           &smmu_debugfs_ste_fops);
>> +        if (!ste_file) {
>> +            ret = -ENOMEM;
>> +            goto cleanup_dev;
>> +        }
>> +
>> +        /* Success for this stream ID, continue to next */
>> +        continue;
>> +
>> +cleanup_dev:
>> +        debugfs_remove_recursive(dev_dir);
>> +cleanup:
>> +        if (ret) {
>> +            debugfs_remove_recursive(stream_dir);
>> +            break;
>> +        }
>> +    }
>> +
>> +    return ret;
>> +}
>> 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 211a0c87507a..c57897e5f644 100644
>> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
>> @@ -3133,6 +3133,9 @@ static int arm_smmu_attach_dev(struct 
>> iommu_domain *domain, struct device *dev,
>>       arm_smmu_attach_commit(&state);
>>       mutex_unlock(&arm_smmu_asid_lock);
>> +#ifdef CONFIG_ARM_SMMU_V3_DEBUGFS
>> +    smmu_debugfs_create_stream_table(dev, smmu);
>> +#endif
>>       return 0;
>>   }
>> 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 247f27426f6b..e9cd24c1ab3c 100644
>> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
>> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
>> @@ -737,9 +737,13 @@ struct arm_smmu_impl_ops {
>>   struct arm_smmu_debugfs {
>>       struct dentry *root_dir;
>>       struct dentry *smmu_dir;
>> +    struct dentry *stream_dir;
>>       struct arm_smmu_device *smmu;
>>   };
>> +
>>   int arm_smmu_debugfs_setup(struct arm_smmu_device *smmu, phys_addr_t 
>> ioaddr);
>> +int smmu_debugfs_create_stream_table(struct device *dev,
>> +                    struct arm_smmu_device *smmu);
>>   #endif
>>   /* An SMMUv3 instance */
> 
> 

-- 
Thanks,
Qinxin



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

* Re: [RFC PATCH 5/5] iommu/arm-smmu-v3: Add Context Descriptor display to debugfs
  2026-03-16 15:42   ` Robin Murphy
@ 2026-03-17  2:14     ` Qinxin Xia
  0 siblings, 0 replies; 24+ messages in thread
From: Qinxin Xia @ 2026-03-17  2:14 UTC (permalink / raw)
  To: Robin Murphy, will, jpb
  Cc: linux-arm-kernel, iommu, wangzhou1, prime.zeng, fanghao11,
	jonathan.cameron, linuxarm



On 2026/3/16 23:42:36, Robin Murphy <robin.murphy@arm.com> wrote:
> On 2026-03-13 10:43 am, Qinxin Xia wrote:
>> 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/
>> └── 0000:01:00.0:0/
>>      ├── ste
>>      └── context_descriptors/
>>          └── all
>>
>> Signed-off-by: Qinxin Xia <xiaqinxin@huawei.com>
>> ---
>>   .../arm/arm-smmu-v3/arm-smmu-v3-debugfs.c     | 112 ++++++++++++++++++
>>   1 file changed, 112 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 f62df02847ac..66ae1228c6ad 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
>> @@ -27,6 +27,13 @@
>>    * - Context Pointers: Stage 1 and Stage 2 translation context 
>> addresses
>>    * - Raw Data: Complete 64-bit STE words in hexadecimal
>>    *
>> + * CD Information Displayed:
>> + * - Validity: Active state of the context descriptor
>> + * - 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
>> + *
>>    * Directory Structure:
>>    * /sys/kernel/debug/iommu/arm_smmu_v3/
>>    * └── smmu0/
>> @@ -35,6 +42,8 @@
>>    *     └── stream_table
>>    *       └── 0000:01:00.0:0/                    # PCI device with 
>> Stream ID 0
>>    *             ├── ste                           # Stream Table Entry
>> + *             └── context_descriptors/
>> + *                 └── all                       # All Context 
>> Descriptors
>>    *
>>    * The capabilities file provides detailed information about:
>>    * - Architecture version and translation stage support (Stage1/Stage2)
>> @@ -59,6 +68,8 @@
>>   static struct dentry *smmuv3_root_dir;
>>   static DEFINE_MUTEX(arm_smmu_debugfs_lock);
>> +#define MAX_SSIDS    32    /* Reasonable limit for SSID enumeration */
> 
> Arbitrarily limiting to only 32 out of a potential 2^20 SSIDs seems odd, 
> like it's rather more than needed for basic sanity-checking, but far too 
> few for debugging specific usage.
> 
> FWIW I'd imagine it might be more useful to expose the CDs as individual 
> files by index - and if userspace does want an "all" dump then there's 
> always `cat`. Whether that would be all of them unconditionally based on 
> the current STE.S1CDMAX, or just the "active" ones based on PASID 
> allocations and S1DSS, is probably a question of what people think is 
> most useful (and/or how fiddly it is to actually implement the latter).
> 

I think 'active' may cover most debug scenarios.In the next version,
I'll remove the limit here.

>> +
>>   /**
>>    * smmu_debugfs_capabilities_show() - Display SMMU capabilities
>>    * @seq: seq_file to write to
>> @@ -329,6 +340,90 @@ static int smmu_debugfs_ste_show(struct seq_file 
>> *seq, void *v)
>>   }
>>   DEFINE_SHOW_ATTRIBUTE(smmu_debugfs_ste);
>> +/**
>> + * smmu_debug_dump_cd() - Dump Context Descriptor details to seq_file
>> + * @seq: seq_file to write to
>> + * @dev: device associated with the CD
>> + * @ssid: Substream ID
>> + */
>> +static void smmu_debug_dump_cd(struct seq_file *seq, struct device 
>> *dev, u32 ssid)
>> +{
>> +    struct arm_smmu_master *master = dev_iommu_priv_get(dev);
>> +    struct arm_smmu_cd *cd;
>> +    u64 data;
>> +    int i;
>> +
>> +    if (!master) {
>> +        seq_puts(seq, "No master data\n");
>> +        return;
>> +    }
> 
> If userspace can read these files racily with devices being removed then:
> 
> 1) we should probably return an actual read error if the device has 
> already disappeared such the file is no longer valid.
> 
> 2) how do we know the device isn't going to disappear, and thus "master" 
> become invalid, immediately *after* this check happens to pass?
> 
> Thanks,
> Robin.
> 
Thank you for your review.
In the next version, I'll use lock protection and check the master again
in the lock.

>> +
>> +    cd = arm_smmu_get_cd_ptr(master, ssid);
>> +    if (!cd) {
>> +        seq_printf(seq, "CD not available for SSID %u\n", ssid);
>> +        return;
>> +    }
>> +
>> +    seq_printf(seq, "CD for Substream ID %u:\n", ssid);
>> +
>> +    /* CD 0 */
>> +    data = le64_to_cpu(cd->data[0]);
>> +    seq_printf(seq, "  Valid: %s\n", data & CTXDESC_CD_0_V ? "Yes" : 
>> "No");
>> +    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]));
>> +}
>> +
>> +/**
>> + * smmu_debug_dump_all_cds() - Dump all valid Context Descriptors for 
>> a device
>> + * @seq: seq_file to write to
>> + * @dev: target device
>> + */
>> +static void smmu_debug_dump_all_cds(struct seq_file *seq, struct 
>> device *dev)
>> +{
>> +    struct arm_smmu_master *master = dev_iommu_priv_get(dev);
>> +    u32 max_ssids, ssid;
>> +
>> +    if (!master) {
>> +        seq_puts(seq, "No master data\n");
>> +        return;
>> +    }
>> +
>> +    max_ssids = min_t(u32, 1 << master->ssid_bits, MAX_SSIDS);
>> +
>> +    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, dev, ssid);
>> +        }
>> +    }
>> +}
>> +
>> +/* All CDs debugfs file operations */
>> +static int smmu_debugfs_all_cds_show(struct seq_file *seq, void *v)
>> +{
>> +    struct device *dev = seq->private;
>> +
>> +    smmu_debug_dump_all_cds(seq, dev);
>> +    return 0;
>> +}
>> +DEFINE_SHOW_ATTRIBUTE(smmu_debugfs_all_cds);
>> +
>>   /**
>>    * smmu_debugfs_create_stream_table() - Create debugfs entries for 
>> stream table
>>    * @dev: device to create entries for
>> @@ -388,9 +483,26 @@ int smmu_debugfs_create_stream_table(struct 
>> device *dev,
>>               goto cleanup_dev;
>>           }
>> +        /* Create CD directory */
>> +        cd_dir = debugfs_create_dir("context_descriptors", dev_dir);
>> +        if (!cd_dir) {
>> +            ret = -ENOMEM;
>> +            goto cleanup_dev;
>> +        }
>> +
>> +        /* Create "all" file to show all valid CDs */
>> +        all_cds_file = debugfs_create_file("all", 0444, cd_dir, dev,
>> +                           &smmu_debugfs_all_cds_fops);
>> +        if (!all_cds_file) {
>> +            ret = -ENOMEM;
>> +            goto cleanup_cd;
>> +        }
>> +
>>           /* Success for this stream ID, continue to next */
>>           continue;
>> +cleanup_cd:
>> +        debugfs_remove(cd_dir);
>>   cleanup_dev:
>>           debugfs_remove_recursive(dev_dir);
>>   cleanup:
> 
> 

-- 
Thanks,
Qinxin



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

end of thread, other threads:[~2026-03-17  2:15 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-13 10:43 [RFC PATCH 0/5] Add debugfs support for ARM SMMUv3 Qinxin Xia
2026-03-13 10:43 ` [RFC PATCH 1/5] iommu/arm-smmu-v3: Add basic debugfs framework Qinxin Xia
2026-03-13 19:58   ` Nicolin Chen
2026-03-16 15:14     ` Qinxin Xia
2026-03-13 10:43 ` [RFC PATCH 2/5] iommu/arm-smmu-v3: Add register display to debugfs Qinxin Xia
2026-03-13 20:20   ` Nicolin Chen
2026-03-16 15:22     ` Qinxin Xia
2026-03-16 15:19   ` Robin Murphy
2026-03-16 15:35     ` Qinxin Xia
2026-03-16 16:26       ` Robin Murphy
2026-03-17  1:44         ` Qinxin Xia
2026-03-13 10:43 ` [RFC PATCH 3/5] iommu/arm-smmu-v3: Add Stream Table Entry " Qinxin Xia
2026-03-13 20:19   ` Nicolin Chen
2026-03-16 15:43     ` Qinxin Xia
2026-03-13 10:43 ` [RFC PATCH 4/5] iommu/arm-smmu-v3: Add stream table directory structure " Qinxin Xia
2026-03-13 20:44   ` Nicolin Chen
2026-03-16 14:57     ` Qinxin Xia
2026-03-16 16:01   ` Robin Murphy
2026-03-17  2:04     ` Qinxin Xia
2026-03-13 10:43 ` [RFC PATCH 5/5] iommu/arm-smmu-v3: Add Context Descriptor display " Qinxin Xia
2026-03-13 21:04   ` Nicolin Chen
2026-03-16 15:12     ` Qinxin Xia
2026-03-16 15:42   ` Robin Murphy
2026-03-17  2:14     ` Qinxin Xia

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