* [PATCH 0/2] iommu: Add io_ptdump debug interface for iommu @ 2025-08-14 9:30 Qinxin Xia 2025-08-14 9:30 ` [PATCH 1/2] iommu/debug: Add IOMMU page table dump debug facility Qinxin Xia ` (2 more replies) 0 siblings, 3 replies; 14+ messages in thread From: Qinxin Xia @ 2025-08-14 9:30 UTC (permalink / raw) To: will, robin.murphy, linux-kernel Cc: linux-arm-kernel, iommu, xiaqinxin, yangyicong, wangzhou1, prime.zeng, xuwei5, fanghao11, jonathan.cameron, linuxarm This patch supports the iopgtable_dump function (similar to kernel_page_dump). The IOMMU page table dump debugging function is added to the framework layer. Different architectures only need to provide the implemented dump ops. It also provides the implementation of ARM SMMUv3 and io-pgtable-arm. Qinxin Xia (2): iommu/debug: Add IOMMU page table dump debug facility iommu/io-pgtable: Add ARM SMMUv3 page table dump support drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 13 ++ drivers/iommu/dma-iommu.c | 15 ++ drivers/iommu/dma-iommu.h | 4 + drivers/iommu/io-pgtable-arm.c | 169 +++++++++++++++++++ drivers/iommu/iommu.c | 175 ++++++++++++++++++++ include/linux/io-pgtable.h | 4 + include/linux/io_ptdump.h | 16 ++ include/linux/iommu.h | 10 +- mm/Kconfig.debug | 19 +++ mm/Makefile | 2 + mm/io_ptdump.c | 24 +++ mm/io_ptdump_debugfs.c | 17 ++ 12 files changed, 467 insertions(+), 1 deletion(-) create mode 100644 include/linux/io_ptdump.h create mode 100644 mm/io_ptdump.c create mode 100644 mm/io_ptdump_debugfs.c -- 2.33.0 ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 1/2] iommu/debug: Add IOMMU page table dump debug facility 2025-08-14 9:30 [PATCH 0/2] iommu: Add io_ptdump debug interface for iommu Qinxin Xia @ 2025-08-14 9:30 ` Qinxin Xia 2025-08-15 6:47 ` kernel test robot ` (2 more replies) 2025-08-14 9:30 ` [PATCH 2/2] iommu/io-pgtable: Add ARM SMMUv3 page table dump support Qinxin Xia 2025-09-02 16:10 ` [PATCH 0/2] iommu: Add io_ptdump debug interface for iommu Jason Gunthorpe 2 siblings, 3 replies; 14+ messages in thread From: Qinxin Xia @ 2025-08-14 9:30 UTC (permalink / raw) To: will, robin.murphy, linux-kernel Cc: linux-arm-kernel, iommu, xiaqinxin, yangyicong, wangzhou1, prime.zeng, xuwei5, fanghao11, jonathan.cameron, linuxarm This patch introduces a comprehensive debugging mechanism for IOMMU page tables, providing visibility into IOVA mappings and protection information. The feature is particularly valuable for debugging complex DMA mapping issues and validating IOMMU configurations. Key components: 1. New debugfs interface: Creates /sys/kernel/debug/io_page_tables 2. Domain-group hierarchy: Organizes output by domain and group 3. IOVA mapping dump: Shows allocated IOVA ranges and protections 4. Device enumeration: Lists all devices in each IOMMU group Implementation details: - Added dump_iova_prot callback to iommu_domain_ops - Implemented iommu_group_and_iova_dump() to traverse groups - Created iommu_iova_info_dump() to walk IOVA allocations - Added CONFIG_IO_PTDUMP_DEBUGFS for compile-time enablement - Provided iommu_domain_to_iovad() helper for IOVA access The debug output includes: -- domain [address] -- - group [id] - [device1] - [device2] ---[ RANGE START ]--- [IOVA mapping details] ---[ RANGE END ]--- This feature helps diagnose: - IOVA allocation patterns - Protection flag mismatches - Unexpected domain/group mappings - Device-to-domain assignment issues Signed-off-by: Qinxin Xia <xiaqinxin@huawei.com> --- drivers/iommu/dma-iommu.c | 15 ++++ drivers/iommu/dma-iommu.h | 4 + drivers/iommu/iommu.c | 175 ++++++++++++++++++++++++++++++++++++++ include/linux/io_ptdump.h | 16 ++++ include/linux/iommu.h | 10 ++- mm/Kconfig.debug | 19 +++++ mm/Makefile | 2 + mm/io_ptdump.c | 24 ++++++ mm/io_ptdump_debugfs.c | 17 ++++ 9 files changed, 281 insertions(+), 1 deletion(-) create mode 100644 include/linux/io_ptdump.h create mode 100644 mm/io_ptdump.c create mode 100644 mm/io_ptdump_debugfs.c diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index ea2ef53bd4fe..d44cd613ea69 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -448,6 +448,21 @@ void iommu_put_msi_cookie(struct iommu_domain *domain) kfree(cookie); } +#ifdef CONFIG_IO_PTDUMP +/** + * iommu_domain_to_iovad - Retrieve the IOVA domain from an IOMMU domain + * @domain: IOMMU domain with an associated IOVA cookie + * + * This function returns the IOVA domain (iovad) structure associated with + * the given IOMMU domain. The domain must have been initialized with an + * IOVA cookie (typically through iommu_dma_init_domain()). + */ +struct iova_domain *iommu_domain_to_iovad(struct iommu_domain *domain) +{ + return &domain->iova_cookie->iovad; +} +#endif + /** * iommu_dma_get_resv_regions - Reserved region driver helper * @dev: Device from iommu_get_resv_regions() diff --git a/drivers/iommu/dma-iommu.h b/drivers/iommu/dma-iommu.h index eca201c1f963..18b06c62af9d 100644 --- a/drivers/iommu/dma-iommu.h +++ b/drivers/iommu/dma-iommu.h @@ -24,6 +24,10 @@ int iommu_dma_sw_msi(struct iommu_domain *domain, struct msi_desc *desc, extern bool iommu_dma_forcedac; +#ifdef CONFIG_IO_PTDUMP +struct iova_domain *iommu_domain_to_iovad(struct iommu_domain *domain); +#endif + #else /* CONFIG_IOMMU_DMA */ static inline void iommu_setup_dma_ops(struct device *dev) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 060ebe330ee1..8fc89a5b34b8 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -1061,6 +1061,181 @@ struct iommu_group *iommu_group_alloc(void) } EXPORT_SYMBOL_GPL(iommu_group_alloc); +#ifdef CONFIG_IO_PTDUMP +#include <linux/seq_file.h> +#include <linux/iova.h> + +struct dump_domain { + struct iommu_domain *domain; + struct list_head groups; + struct list_head list; +}; + +struct dump_group { + struct iommu_group *group; + struct list_head list; +}; + +/** + * iova_info_dump - dump iova alloced + * @s - file structure used to generate serialized output + * @iovad: - iova domain in question. + */ +static int iommu_iova_info_dump(struct seq_file *s, struct iommu_domain *domain) +{ + struct iova_domain *iovad; + unsigned long long pfn; + unsigned long i_shift; + struct rb_node *node; + unsigned long flags; + size_t prot_size; + + iovad = iommu_domain_to_iovad(domain); + if (!iovad) + return -ENOMEM; + + i_shift = iova_shift(iovad); + + /* Take the lock so that no other thread is manipulating the rbtree */ + spin_lock_irqsave(&iovad->iova_rbtree_lock, flags); + assert_spin_locked(&iovad->iova_rbtree_lock); + + for (node = rb_first(&iovad->rbroot); node; node = rb_next(node)) { + struct iova *iova = rb_entry(node, struct iova, node); + + if (iova->pfn_hi <= iova->pfn_lo) + continue; + + for (pfn = iova->pfn_lo; pfn <= iova->pfn_hi; ) { + prot_size = domain->ops->dump_iova_prot(s, domain, pfn << i_shift); + pfn = ((pfn << i_shift) + prot_size) >> i_shift; + } + } + + spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags); + return 0; +} + +/** + * iommu_group_and_iova_dump - Collect and dump IOMMU group and IOVA mapping information + * @s: seq_file target for output + * + * This function traverses all IOMMU groups in the system and dumps hierarchical information + * about domains, groups, devices, and IOVA mappings. Only groups with default domains using + * DMA_IOVA cookie type are processed. + * + * Key operations: + * 1. Iterates through all registered IOMMU groups + * 2. Filters groups with default domains of type IOMMU_COOKIE_DMA_IOVA + * 3. Organizes groups by domain to avoid duplicate domain output + * 4. Outputs hierarchical information including: + * - Domain address + * - Group IDs and their member devices + * - IOVA mapping ranges via iommu_iova_info_dump() + * + * Data structure hierarchy: + * domain_list (list_head) + * ├── dump_domain + * │ ├── domain: pointer to iommu_domain + * │ └── groups (list_head) + * │ └── dump_group + * │ └── group: pointer to iommu_group + * + */ +int iommu_group_and_iova_dump(struct seq_file *s) +{ + struct dump_domain *domain_entry, *d_tmp; + struct dump_group *group_entry, *g_tmp; + struct list_head domain_list; + struct iommu_group *group; + struct group_device *gdev; + struct kobject *kobj; + int ret = 0; + bool found; + + INIT_LIST_HEAD(&domain_list); + + list_for_each_entry(kobj, &iommu_group_kset->list, entry) { + group = container_of(kobj, struct iommu_group, kobj); + + /* Skip groups that do not meet the criteria */ + if (!group->default_domain || + group->default_domain->cookie_type != IOMMU_COOKIE_DMA_IOVA) + continue; + + /* Check whether the domain already exists. */ + found = false; + list_for_each_entry(domain_entry, &domain_list, list) { + if (domain_entry->domain == group->default_domain) { + found = true; + break; + } + } + + /* New domain, create entry */ + if (!found) { + domain_entry = kzalloc(sizeof(*domain_entry), GFP_KERNEL); + if (!domain_entry) { + ret = -ENOMEM; + goto out; + } + + domain_entry->domain = group->default_domain; + INIT_LIST_HEAD(&domain_entry->groups); + list_add_tail(&domain_entry->list, &domain_list); + } + + /* Create group entries */ + group_entry = kzalloc(sizeof(*group_entry), GFP_KERNEL); + if (!group_entry) { + ret = -ENOMEM; + goto out; + } + + group_entry->group = group; + list_add_tail(&group_entry->list, &domain_entry->groups); + } + + /* Output all domain information */ + list_for_each_entry(domain_entry, &domain_list, list) { + seq_printf(s, "-- domain %p --\n", domain_entry->domain); + + /* Output all groups in the current domain */ + list_for_each_entry(group_entry, &domain_entry->groups, list) { + seq_printf(s, "- group %d\n", group_entry->group->id); + + /* Output all devices in the group */ + for_each_group_device(group_entry->group, gdev) { + seq_printf(s, " - %s\n", dev_name(gdev->dev)); + } + } + + /* Output IOVA range */ + seq_puts(s, "---[ RANGE START ]---\n"); + ret = iommu_iova_info_dump(s, domain_entry->domain); + if (ret) + seq_puts(s, "IOVA INFO DUMP FAIL...\n"); + + seq_puts(s, "---[ RANGE END ]---\n"); + } + +out: + /* Release domain_list and group_list */ + list_for_each_entry_safe(domain_entry, d_tmp, &domain_list, list) { + list_for_each_entry_safe(group_entry, g_tmp, &domain_entry->groups, list) { + list_del(&group_entry->list); + kfree(group_entry); + } + + list_del(&domain_entry->list); + kfree(domain_entry); + } + + return ret; +} +EXPORT_SYMBOL_GPL(iommu_group_and_iova_dump); +#endif + /** * iommu_group_get_iommudata - retrieve iommu_data registered for a group * @group: the group diff --git a/include/linux/io_ptdump.h b/include/linux/io_ptdump.h new file mode 100644 index 000000000000..e087bb7751c2 --- /dev/null +++ b/include/linux/io_ptdump.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * Copyright (C) 2025 HiSilicon Limited + * Author: Qinxin Xia <xiaqinxin@huawei.com> + * + */ + +#ifndef __ASM_IO_PTDUMP_H +#define __ASM_IO_PTDUMP_H + +#ifdef CONFIG_IO_PTDUMP_DEBUGFS +void __init io_ptdump_debugfs_register(const char *name); +#else +void __init io_ptdump_debugfs_register(const char *name) { } +#endif /* CONFIG_IO_PTDUMP_DEBUGFS */ + +#endif diff --git a/include/linux/iommu.h b/include/linux/iommu.h index c30d12e16473..494a4960b8c7 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -772,7 +772,10 @@ struct iommu_domain_ops { phys_addr_t (*iova_to_phys)(struct iommu_domain *domain, dma_addr_t iova); - +#ifdef CONFIG_IO_PTDUMP + size_t (*dump_iova_prot)(struct seq_file *s, struct iommu_domain *domain, + dma_addr_t iova); +#endif bool (*enforce_cache_coherency)(struct iommu_domain *domain); int (*set_pgtable_quirks)(struct iommu_domain *domain, unsigned long quirks); @@ -1698,4 +1701,9 @@ static inline void iopf_group_response(struct iopf_group *group, { } #endif /* CONFIG_IOMMU_IOPF */ + +#ifdef CONFIG_IO_PTDUMP +int iommu_group_and_iova_dump(struct seq_file *s); +#endif /* CONFIG_IO_PTDUMP */ + #endif /* __LINUX_IOMMU_H */ diff --git a/mm/Kconfig.debug b/mm/Kconfig.debug index 32b65073d0cc..e09c9995c496 100644 --- a/mm/Kconfig.debug +++ b/mm/Kconfig.debug @@ -219,6 +219,9 @@ config ARCH_HAS_PTDUMP config PTDUMP bool +config IO_PTDUMP + bool + config PTDUMP_DEBUGFS bool "Export kernel pagetable layout to userspace via debugfs" depends on DEBUG_KERNEL @@ -234,6 +237,22 @@ config PTDUMP_DEBUGFS If in doubt, say N. +config IO_PTDUMP_DEBUGFS + bool "Export io pagetable layout to userspace via debugfs" + depends on DEBUG_KERNEL + depends on DEBUG_FS + depends on IOMMU_IOVA + select IO_PTDUMP + help + Say Y here if you want to show the io pagetable layout in a + debugfs file. This information is only useful for kernel developers + who are working in architecture specific areas of the iommu. + It is probably not a good idea to enable this feature in a production + kernel. + + If in doubt, say N. + + config HAVE_DEBUG_KMEMLEAK bool diff --git a/mm/Makefile b/mm/Makefile index ef54aa615d9d..95759ccf93c1 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -147,3 +147,5 @@ obj-$(CONFIG_SHRINKER_DEBUG) += shrinker_debug.o obj-$(CONFIG_EXECMEM) += execmem.o obj-$(CONFIG_TMPFS_QUOTA) += shmem_quota.o obj-$(CONFIG_PT_RECLAIM) += pt_reclaim.o +obj-$(CONFIG_IO_PTDUMP) += io_ptdump.o +obj-$(CONFIG_IO_PTDUMP_DEBUGFS) += io_ptdump_debugfs.o diff --git a/mm/io_ptdump.c b/mm/io_ptdump.c new file mode 100644 index 000000000000..9aa133de5119 --- /dev/null +++ b/mm/io_ptdump.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025, hisilion limited. + * Debug helper to dump the current IO pagetables of the system + * so that we can see what the various memory ranges are set to. + * + * Author: Qinxin Xia <xiaqinxin@huawei.com> + */ +#include <linux/debugfs.h> +#include <linux/fs.h> +#include <linux/io.h> +#include <linux/iommu.h> +#include <linux/init.h> +#include <linux/io_ptdump.h> +#include <linux/mm.h> +#include <linux/seq_file.h> + +static int __init io_ptdump_init(void) +{ + io_ptdump_debugfs_register("io_page_tables"); + return 0; +} + +device_initcall(io_ptdump_init); diff --git a/mm/io_ptdump_debugfs.c b/mm/io_ptdump_debugfs.c new file mode 100644 index 000000000000..704ca306957e --- /dev/null +++ b/mm/io_ptdump_debugfs.c @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/debugfs.h> +#include <linux/iommu.h> +#include <linux/memory_hotplug.h> +#include <linux/seq_file.h> + +static int io_ptdump_show(struct seq_file *m, void *v) +{ + iommu_group_and_iova_dump(m); + return 0; +} +DEFINE_SHOW_ATTRIBUTE(io_ptdump); + +void __init io_ptdump_debugfs_register(const char *name) +{ + debugfs_create_file(name, 0400, NULL, NULL, &io_ptdump_fops); +} -- 2.33.0 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] iommu/debug: Add IOMMU page table dump debug facility 2025-08-14 9:30 ` [PATCH 1/2] iommu/debug: Add IOMMU page table dump debug facility Qinxin Xia @ 2025-08-15 6:47 ` kernel test robot 2025-08-15 9:57 ` kernel test robot 2025-09-09 13:06 ` Will Deacon 2 siblings, 0 replies; 14+ messages in thread From: kernel test robot @ 2025-08-15 6:47 UTC (permalink / raw) To: Qinxin Xia, will, robin.murphy, linux-kernel Cc: oe-kbuild-all, linux-arm-kernel, iommu, xiaqinxin, yangyicong, wangzhou1, prime.zeng, xuwei5, fanghao11, jonathan.cameron, linuxarm Hi Qinxin, kernel test robot noticed the following build warnings: [auto build test WARNING on akpm-mm/mm-everything] [also build test WARNING on linus/master v6.17-rc1 next-20250814] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Qinxin-Xia/iommu-debug-Add-IOMMU-page-table-dump-debug-facility/20250814-173720 base: https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-everything patch link: https://lore.kernel.org/r/20250814093005.2040511-2-xiaqinxin%40huawei.com patch subject: [PATCH 1/2] iommu/debug: Add IOMMU page table dump debug facility config: sh-allmodconfig (https://download.01.org/0day-ci/archive/20250815/202508151456.FmgCiCK4-lkp@intel.com/config) compiler: sh4-linux-gcc (GCC) 15.1.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250815/202508151456.FmgCiCK4-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202508151456.FmgCiCK4-lkp@intel.com/ All warnings (new ones prefixed by >>): >> mm/io_ptdump_debugfs.c:14:13: warning: no previous prototype for 'io_ptdump_debugfs_register' [-Wmissing-prototypes] 14 | void __init io_ptdump_debugfs_register(const char *name) | ^~~~~~~~~~~~~~~~~~~~~~~~~~ vim +/io_ptdump_debugfs_register +14 mm/io_ptdump_debugfs.c 13 > 14 void __init io_ptdump_debugfs_register(const char *name) -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] iommu/debug: Add IOMMU page table dump debug facility 2025-08-14 9:30 ` [PATCH 1/2] iommu/debug: Add IOMMU page table dump debug facility Qinxin Xia 2025-08-15 6:47 ` kernel test robot @ 2025-08-15 9:57 ` kernel test robot 2025-09-09 13:06 ` Will Deacon 2 siblings, 0 replies; 14+ messages in thread From: kernel test robot @ 2025-08-15 9:57 UTC (permalink / raw) To: Qinxin Xia, will, robin.murphy, linux-kernel Cc: oe-kbuild-all, linux-arm-kernel, iommu, xiaqinxin, yangyicong, wangzhou1, prime.zeng, xuwei5, fanghao11, jonathan.cameron, linuxarm Hi Qinxin, kernel test robot noticed the following build errors: [auto build test ERROR on akpm-mm/mm-everything] [also build test ERROR on linus/master v6.17-rc1 next-20250815] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Qinxin-Xia/iommu-debug-Add-IOMMU-page-table-dump-debug-facility/20250814-173720 base: https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-everything patch link: https://lore.kernel.org/r/20250814093005.2040511-2-xiaqinxin%40huawei.com patch subject: [PATCH 1/2] iommu/debug: Add IOMMU page table dump debug facility config: sh-allmodconfig (https://download.01.org/0day-ci/archive/20250815/202508151711.pZGu9jac-lkp@intel.com/config) compiler: sh4-linux-gcc (GCC) 15.1.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250815/202508151711.pZGu9jac-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202508151711.pZGu9jac-lkp@intel.com/ All errors (new ones prefixed by >>): drivers/iommu/iommu.c: In function 'iommu_iova_info_dump': >> drivers/iommu/iommu.c:1093:17: error: implicit declaration of function 'iommu_domain_to_iovad'; did you mean 'iommu_domain_type_str'? [-Wimplicit-function-declaration] 1093 | iovad = iommu_domain_to_iovad(domain); | ^~~~~~~~~~~~~~~~~~~~~ | iommu_domain_type_str >> drivers/iommu/iommu.c:1093:15: error: assignment to 'struct iova_domain *' from 'int' makes pointer from integer without a cast [-Wint-conversion] 1093 | iovad = iommu_domain_to_iovad(domain); | ^ vim +1093 drivers/iommu/iommu.c 1078 1079 /** 1080 * iova_info_dump - dump iova alloced 1081 * @s - file structure used to generate serialized output 1082 * @iovad: - iova domain in question. 1083 */ 1084 static int iommu_iova_info_dump(struct seq_file *s, struct iommu_domain *domain) 1085 { 1086 struct iova_domain *iovad; 1087 unsigned long long pfn; 1088 unsigned long i_shift; 1089 struct rb_node *node; 1090 unsigned long flags; 1091 size_t prot_size; 1092 > 1093 iovad = iommu_domain_to_iovad(domain); 1094 if (!iovad) 1095 return -ENOMEM; 1096 1097 i_shift = iova_shift(iovad); 1098 1099 /* Take the lock so that no other thread is manipulating the rbtree */ 1100 spin_lock_irqsave(&iovad->iova_rbtree_lock, flags); 1101 assert_spin_locked(&iovad->iova_rbtree_lock); 1102 1103 for (node = rb_first(&iovad->rbroot); node; node = rb_next(node)) { 1104 struct iova *iova = rb_entry(node, struct iova, node); 1105 1106 if (iova->pfn_hi <= iova->pfn_lo) 1107 continue; 1108 1109 for (pfn = iova->pfn_lo; pfn <= iova->pfn_hi; ) { 1110 prot_size = domain->ops->dump_iova_prot(s, domain, pfn << i_shift); 1111 pfn = ((pfn << i_shift) + prot_size) >> i_shift; 1112 } 1113 } 1114 1115 spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags); 1116 return 0; 1117 } 1118 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] iommu/debug: Add IOMMU page table dump debug facility 2025-08-14 9:30 ` [PATCH 1/2] iommu/debug: Add IOMMU page table dump debug facility Qinxin Xia 2025-08-15 6:47 ` kernel test robot 2025-08-15 9:57 ` kernel test robot @ 2025-09-09 13:06 ` Will Deacon 2025-09-10 2:58 ` Qinxin Xia 2 siblings, 1 reply; 14+ messages in thread From: Will Deacon @ 2025-09-09 13:06 UTC (permalink / raw) To: Qinxin Xia Cc: robin.murphy, linux-kernel, linux-arm-kernel, iommu, yangyicong, wangzhou1, prime.zeng, xuwei5, fanghao11, jonathan.cameron, linuxarm On Thu, Aug 14, 2025 at 05:30:04PM +0800, Qinxin Xia wrote: > +/** > + * iova_info_dump - dump iova alloced > + * @s - file structure used to generate serialized output > + * @iovad: - iova domain in question. > + */ > +static int iommu_iova_info_dump(struct seq_file *s, struct iommu_domain *domain) > +{ > + struct iova_domain *iovad; > + unsigned long long pfn; > + unsigned long i_shift; > + struct rb_node *node; > + unsigned long flags; > + size_t prot_size; > + > + iovad = iommu_domain_to_iovad(domain); > + if (!iovad) > + return -ENOMEM; > + > + i_shift = iova_shift(iovad); > + > + /* Take the lock so that no other thread is manipulating the rbtree */ > + spin_lock_irqsave(&iovad->iova_rbtree_lock, flags); > + assert_spin_locked(&iovad->iova_rbtree_lock); > + > + for (node = rb_first(&iovad->rbroot); node; node = rb_next(node)) { > + struct iova *iova = rb_entry(node, struct iova, node); > + > + if (iova->pfn_hi <= iova->pfn_lo) > + continue; > + > + for (pfn = iova->pfn_lo; pfn <= iova->pfn_hi; ) { > + prot_size = domain->ops->dump_iova_prot(s, domain, pfn << i_shift); > + pfn = ((pfn << i_shift) + prot_size) >> i_shift; > + } > + } > + > + spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags); Why is the IOVA rbtree lock sufficient for serialising the page-table accesses made by ->dump_iova_prot()? I don't see anything here that prevents the walker walking into page-table pages that are e.g. being freed or manipulated concurrently. Will ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] iommu/debug: Add IOMMU page table dump debug facility 2025-09-09 13:06 ` Will Deacon @ 2025-09-10 2:58 ` Qinxin Xia 2025-09-11 14:58 ` Will Deacon 0 siblings, 1 reply; 14+ messages in thread From: Qinxin Xia @ 2025-09-10 2:58 UTC (permalink / raw) To: Will Deacon Cc: robin.murphy, linux-kernel, linux-arm-kernel, iommu, yangyicong, wangzhou1, prime.zeng, xuwei5, fanghao11, jonathan.cameron, linuxarm On 2025/9/9 21:06:33, Will Deacon <will@kernel.org> wrote: > On Thu, Aug 14, 2025 at 05:30:04PM +0800, Qinxin Xia wrote: >> +/** >> + * iova_info_dump - dump iova alloced >> + * @s - file structure used to generate serialized output >> + * @iovad: - iova domain in question. >> + */ >> +static int iommu_iova_info_dump(struct seq_file *s, struct iommu_domain *domain) >> +{ >> + struct iova_domain *iovad; >> + unsigned long long pfn; >> + unsigned long i_shift; >> + struct rb_node *node; >> + unsigned long flags; >> + size_t prot_size; >> + >> + iovad = iommu_domain_to_iovad(domain); >> + if (!iovad) >> + return -ENOMEM; >> + >> + i_shift = iova_shift(iovad); >> + >> + /* Take the lock so that no other thread is manipulating the rbtree */ >> + spin_lock_irqsave(&iovad->iova_rbtree_lock, flags); >> + assert_spin_locked(&iovad->iova_rbtree_lock); >> + >> + for (node = rb_first(&iovad->rbroot); node; node = rb_next(node)) { >> + struct iova *iova = rb_entry(node, struct iova, node); >> + >> + if (iova->pfn_hi <= iova->pfn_lo) >> + continue; >> + >> + for (pfn = iova->pfn_lo; pfn <= iova->pfn_hi; ) { >> + prot_size = domain->ops->dump_iova_prot(s, domain, pfn << i_shift); >> + pfn = ((pfn << i_shift) + prot_size) >> i_shift; >> + } >> + } >> + >> + spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags); > > Why is the IOVA rbtree lock sufficient for serialising the page-table > accesses made by ->dump_iova_prot()? I don't see anything here that > prevents the walker walking into page-table pages that are e.g. being > freed or manipulated concurrently. > > Will > Thank you for catching this critical race condition.I will fix this in next version. And,Jason suggests putting io_ptdump on top of iommu pt. What do you think? ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] iommu/debug: Add IOMMU page table dump debug facility 2025-09-10 2:58 ` Qinxin Xia @ 2025-09-11 14:58 ` Will Deacon 0 siblings, 0 replies; 14+ messages in thread From: Will Deacon @ 2025-09-11 14:58 UTC (permalink / raw) To: Qinxin Xia Cc: robin.murphy, linux-kernel, linux-arm-kernel, iommu, yangyicong, wangzhou1, prime.zeng, xuwei5, fanghao11, jonathan.cameron, linuxarm On Wed, Sep 10, 2025 at 10:58:09AM +0800, Qinxin Xia wrote: > > > On 2025/9/9 21:06:33, Will Deacon <will@kernel.org> wrote: > > On Thu, Aug 14, 2025 at 05:30:04PM +0800, Qinxin Xia wrote: > > > +/** > > > + * iova_info_dump - dump iova alloced > > > + * @s - file structure used to generate serialized output > > > + * @iovad: - iova domain in question. > > > + */ > > > +static int iommu_iova_info_dump(struct seq_file *s, struct iommu_domain *domain) > > > +{ > > > + struct iova_domain *iovad; > > > + unsigned long long pfn; > > > + unsigned long i_shift; > > > + struct rb_node *node; > > > + unsigned long flags; > > > + size_t prot_size; > > > + > > > + iovad = iommu_domain_to_iovad(domain); > > > + if (!iovad) > > > + return -ENOMEM; > > > + > > > + i_shift = iova_shift(iovad); > > > + > > > + /* Take the lock so that no other thread is manipulating the rbtree */ > > > + spin_lock_irqsave(&iovad->iova_rbtree_lock, flags); > > > + assert_spin_locked(&iovad->iova_rbtree_lock); > > > + > > > + for (node = rb_first(&iovad->rbroot); node; node = rb_next(node)) { > > > + struct iova *iova = rb_entry(node, struct iova, node); > > > + > > > + if (iova->pfn_hi <= iova->pfn_lo) > > > + continue; > > > + > > > + for (pfn = iova->pfn_lo; pfn <= iova->pfn_hi; ) { > > > + prot_size = domain->ops->dump_iova_prot(s, domain, pfn << i_shift); > > > + pfn = ((pfn << i_shift) + prot_size) >> i_shift; > > > + } > > > + } > > > + > > > + spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags); > > > > Why is the IOVA rbtree lock sufficient for serialising the page-table > > accesses made by ->dump_iova_prot()? I don't see anything here that > > prevents the walker walking into page-table pages that are e.g. being > > freed or manipulated concurrently. > > > Thank you for catching this critical race condition.I will fix this in > next version. And,Jason suggests putting io_ptdump on top of iommu pt. > What do you think? I guess it depends on whether or not you want to tie this debug feature to drivers that support the new page-table stuff. Will ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 2/2] iommu/io-pgtable: Add ARM SMMUv3 page table dump support 2025-08-14 9:30 [PATCH 0/2] iommu: Add io_ptdump debug interface for iommu Qinxin Xia 2025-08-14 9:30 ` [PATCH 1/2] iommu/debug: Add IOMMU page table dump debug facility Qinxin Xia @ 2025-08-14 9:30 ` Qinxin Xia 2025-08-15 9:14 ` kernel test robot 2025-09-02 16:10 ` [PATCH 0/2] iommu: Add io_ptdump debug interface for iommu Jason Gunthorpe 2 siblings, 1 reply; 14+ messages in thread From: Qinxin Xia @ 2025-08-14 9:30 UTC (permalink / raw) To: will, robin.murphy, linux-kernel Cc: linux-arm-kernel, iommu, xiaqinxin, yangyicong, wangzhou1, prime.zeng, xuwei5, fanghao11, jonathan.cameron, linuxarm This patch implements the debug interface for dumping ARM SMMUv3 page table entries and protection information. The functionality enables detailed inspection of IOMMU mappings for debugging and validation purposes. 1. ARM SMMUv3 driver integration: - Implemented arm_smmu_dump_iova_prot() callback - Registered dump_iova_prot in iommu_domain_ops 2. ARM LPAE io-pgtable implementation: - Added arm_lpae_dump_iova_prot() to io_pgtable_ops - Defined protection bit descriptors (prot_bits) - Created io_pgtable_fmt_names for human-readable format strings - Implemented protection flag formatting in dump_prot() 3. Core io-pgtable interface extension: - Added dump_iova_prot callback to io_pgtable_ops The implementation provides detailed output for each IOVA mapping: <start> - <end> lvl <level> stage <format> <protection flags> Example: 0xffff2000 - 0xffff3000 lvl 2 stage ARM_64_LPAE_S1 AF SH_NS Signed-off-by: Qinxin Xia <xiaqinxin@huawei.com> --- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 13 ++ drivers/iommu/io-pgtable-arm.c | 169 ++++++++++++++++++++ include/linux/io-pgtable.h | 4 + 3 files changed, 186 insertions(+) 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 5968043ac802..4128b3307753 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c @@ -3411,6 +3411,16 @@ arm_smmu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova) return ops->iova_to_phys(ops, iova); } +#ifdef CONFIG_IO_PTDUMP +static size_t +arm_smmu_dump_iova_prot(struct seq_file *s, struct iommu_domain *domain, dma_addr_t iova) +{ + struct io_pgtable_ops *ops = to_smmu_domain(domain)->pgtbl_ops; + + return ops->dump_iova_prot(s, ops, iova); +} +#endif + static struct platform_driver arm_smmu_driver; static @@ -3702,6 +3712,9 @@ static const struct iommu_ops arm_smmu_ops = { .flush_iotlb_all = arm_smmu_flush_iotlb_all, .iotlb_sync = arm_smmu_iotlb_sync, .iova_to_phys = arm_smmu_iova_to_phys, +#ifdef CONFIG_IO_PTDUMP + .dump_iova_prot = arm_smmu_dump_iova_prot, +#endif .free = arm_smmu_domain_free_paging, } }; diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index 7e8e2216c294..5deb03a85aa6 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -754,6 +754,172 @@ static phys_addr_t arm_lpae_iova_to_phys(struct io_pgtable_ops *ops, return iopte_to_paddr(d.pte, data) | iova; } +#ifdef CONFIG_IO_PTDUMP +#include <linux/seq_file.h> + +struct io_ptdump_prot_bits { + uint64_t mask; + uint64_t val; + const char *set; + const char *clear; +}; + +static const struct io_ptdump_prot_bits prot_bits[] = { + { + .mask = ARM_LPAE_PTE_VALID, + .val = ARM_LPAE_PTE_VALID, + .set = "V", + .clear = " ", + }, + { + .mask = ARM_LPAE_PTE_XN, + .val = ARM_LPAE_PTE_XN, + .set = "XN", + .clear = " ", + }, + { + .mask = ARM_LPAE_PTE_DBM, + .val = ARM_LPAE_PTE_DBM, + .set = "DBM", + .clear = " ", + }, + { + .mask = ARM_LPAE_PTE_AF, + .val = ARM_LPAE_PTE_AF, + .set = "AF", + .clear = " ", + }, + { + .mask = ARM_LPAE_PTE_SH_NS, + .val = ARM_LPAE_PTE_SH_NS, + .set = "SH_NS", + .clear = " ", + }, + { + .mask = ARM_LPAE_PTE_SH_OS, + .val = ARM_LPAE_PTE_SH_OS, + .set = "SH_OS", + .clear = " ", + }, + { + .mask = ARM_LPAE_PTE_SH_IS, + .val = ARM_LPAE_PTE_SH_IS, + .set = "SH_IS", + .clear = " ", + }, + { + .mask = ARM_LPAE_PTE_NS, + .val = ARM_LPAE_PTE_NS, + .set = "NS", + .clear = " ", + }, + { + .mask = ARM_LPAE_PTE_NSTABLE, + .val = ARM_LPAE_PTE_NSTABLE, + .set = "NST", + .clear = " ", + }, +}; + +const char *io_pgtable_fmt_names[] = { + "ARM_32_LPAE_S1", + "ARM_32_LPAE_S2", + "ARM_64_LPAE_S1", + "ARM_64_LPAE_S2", + "ARM_V7S", + "ARM_MALI_LPAE", + "AMD_IOMMU_V1", + "AMD_IOMMU_V2", + "APPLE_DART", + "APPLE_DART2", +}; + +struct io_ptdump_prot { + int lvl; + int stage; + char *attr; + size_t size; +}; + +static void dump_prot(struct seq_file *s, arm_lpae_iopte pte) +{ + int capacity = 64; + const char *attr; + int length = 0; + + char *prot = kzalloc(capacity * sizeof(char), GFP_KERNEL); + + if (!prot) + return; + + /* Traverse all predefined permission bits */ + for (size_t i = 0; i < ARRAY_SIZE(prot_bits); i++) { + if ((pte & prot_bits[i].mask) == prot_bits[i].val) + attr = prot_bits[i].set; + else + attr = prot_bits[i].clear; + + size_t attr_len = strlen(attr); + + /* Check and extend the buffer */ + while (length + attr_len > capacity) { + capacity *= 2; + + char *temp = krealloc(prot, capacity * sizeof(char), GFP_KERNEL); + + if (!temp) { + kfree(prot); + return; + } + + prot = temp; + } + + length += snprintf(prot + length, capacity - length, "%s ", attr); + + /* Security check: prevents abnormal buffer expansion */ + if (length > PAGE_SIZE) { + pr_err("len = %zu, attr = %s, i =%d\n", length, attr, i); + kfree(prot); + return; + } + } + + seq_printf(s, "%s", prot); + kfree(prot); +} + +static size_t arm_lpae_dump_iova_prot(struct seq_file *s, struct io_pgtable_ops *ops, + unsigned long iova) +{ + struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops); + struct iova_to_phys_data d; + int ret; + + struct io_pgtable_walk_data walk_data = { + .data = &d, + .visit = visit_iova_to_phys, + .addr = iova, + .end = iova + 1, + }; + + /* Only the mapped iova will be output */ + ret = __arm_lpae_iopte_walk(data, &walk_data, data->pgd, data->start_level); + if (ret) + return ARM_LPAE_GRANULE(data); + + seq_printf(s, "%lx - %lx lvl %d stage %s ", + iova, iova + ARM_LPAE_BLOCK_SIZE(d.lvl, data), + d.lvl, io_pgtable_fmt_names[data->iop.fmt]); + + /* TODO: The dump prot is incomplete and will be supplemented later... */ + dump_prot(s, d.pte); + seq_puts(s, "\n"); + + return ARM_LPAE_BLOCK_SIZE(d.lvl, data); +} +#endif + static int visit_pgtable_walk(struct io_pgtable_walk_data *walk_data, int lvl, arm_lpae_iopte *ptep, size_t size) { @@ -950,6 +1116,9 @@ arm_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg) .map_pages = arm_lpae_map_pages, .unmap_pages = arm_lpae_unmap_pages, .iova_to_phys = arm_lpae_iova_to_phys, +#ifdef CONFIG_IO_PTDUMP + .dump_iova_prot = arm_lpae_dump_iova_prot, +#endif .read_and_clear_dirty = arm_lpae_read_and_clear_dirty, .pgtable_walk = arm_lpae_pgtable_walk, }; diff --git a/include/linux/io-pgtable.h b/include/linux/io-pgtable.h index 138fbd89b1e6..307c68f0038c 100644 --- a/include/linux/io-pgtable.h +++ b/include/linux/io-pgtable.h @@ -217,6 +217,10 @@ struct io_pgtable_ops { struct iommu_iotlb_gather *gather); phys_addr_t (*iova_to_phys)(struct io_pgtable_ops *ops, unsigned long iova); +#ifdef CONFIG_IO_PTDUMP + size_t (*dump_iova_prot)(struct seq_file *s, struct io_pgtable_ops *ops, + unsigned long iova); +#endif int (*pgtable_walk)(struct io_pgtable_ops *ops, unsigned long iova, void *wd); int (*read_and_clear_dirty)(struct io_pgtable_ops *ops, unsigned long iova, size_t size, -- 2.33.0 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 2/2] iommu/io-pgtable: Add ARM SMMUv3 page table dump support 2025-08-14 9:30 ` [PATCH 2/2] iommu/io-pgtable: Add ARM SMMUv3 page table dump support Qinxin Xia @ 2025-08-15 9:14 ` kernel test robot 0 siblings, 0 replies; 14+ messages in thread From: kernel test robot @ 2025-08-15 9:14 UTC (permalink / raw) To: Qinxin Xia, will, robin.murphy, linux-kernel Cc: oe-kbuild-all, linux-arm-kernel, iommu, xiaqinxin, yangyicong, wangzhou1, prime.zeng, xuwei5, fanghao11, jonathan.cameron, linuxarm Hi Qinxin, kernel test robot noticed the following build warnings: [auto build test WARNING on akpm-mm/mm-everything] [also build test WARNING on linus/master v6.17-rc1 next-20250815] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Qinxin-Xia/iommu-debug-Add-IOMMU-page-table-dump-debug-facility/20250814-173720 base: https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-everything patch link: https://lore.kernel.org/r/20250814093005.2040511-3-xiaqinxin%40huawei.com patch subject: [PATCH 2/2] iommu/io-pgtable: Add ARM SMMUv3 page table dump support config: s390-allyesconfig (https://download.01.org/0day-ci/archive/20250815/202508151641.JHlhcDRk-lkp@intel.com/config) compiler: s390-linux-gcc (GCC) 15.1.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250815/202508151641.JHlhcDRk-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202508151641.JHlhcDRk-lkp@intel.com/ All warnings (new ones prefixed by >>): In file included from include/asm-generic/bug.h:22, from arch/s390/include/asm/bug.h:69, from include/linux/bug.h:5, from include/linux/mmdebug.h:5, from arch/s390/include/asm/cmpxchg.h:11, from arch/s390/include/asm/atomic.h:16, from include/linux/atomic.h:7, from drivers/iommu/io-pgtable-arm.c:12: drivers/iommu/io-pgtable-arm.c: In function 'dump_prot': >> include/linux/kern_levels.h:5:25: warning: format '%zu' expects argument of type 'size_t', but argument 2 has type 'int' [-Wformat=] 5 | #define KERN_SOH "\001" /* ASCII Start Of Header */ | ^~~~~~ include/linux/printk.h:486:25: note: in definition of macro 'printk_index_wrap' 486 | _p_func(_fmt, ##__VA_ARGS__); \ | ^~~~ include/linux/printk.h:557:9: note: in expansion of macro 'printk' 557 | printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__) | ^~~~~~ include/linux/kern_levels.h:11:25: note: in expansion of macro 'KERN_SOH' 11 | #define KERN_ERR KERN_SOH "3" /* error conditions */ | ^~~~~~~~ include/linux/printk.h:557:16: note: in expansion of macro 'KERN_ERR' 557 | printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__) | ^~~~~~~~ drivers/iommu/io-pgtable-arm.c:882:25: note: in expansion of macro 'pr_err' 882 | pr_err("len = %zu, attr = %s, i =%d\n", length, attr, i); | ^~~~~~ >> include/linux/kern_levels.h:5:25: warning: format '%d' expects argument of type 'int', but argument 4 has type 'size_t' {aka 'long unsigned int'} [-Wformat=] 5 | #define KERN_SOH "\001" /* ASCII Start Of Header */ | ^~~~~~ include/linux/printk.h:486:25: note: in definition of macro 'printk_index_wrap' 486 | _p_func(_fmt, ##__VA_ARGS__); \ | ^~~~ include/linux/printk.h:557:9: note: in expansion of macro 'printk' 557 | printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__) | ^~~~~~ include/linux/kern_levels.h:11:25: note: in expansion of macro 'KERN_SOH' 11 | #define KERN_ERR KERN_SOH "3" /* error conditions */ | ^~~~~~~~ include/linux/printk.h:557:16: note: in expansion of macro 'KERN_ERR' 557 | printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__) | ^~~~~~~~ drivers/iommu/io-pgtable-arm.c:882:25: note: in expansion of macro 'pr_err' 882 | pr_err("len = %zu, attr = %s, i =%d\n", length, attr, i); | ^~~~~~ drivers/iommu/io-pgtable-arm.c: In function 'arm_lpae_dump_iova_prot': >> drivers/iommu/io-pgtable-arm.c:911:32: warning: format '%lx' expects argument of type 'long unsigned int', but argument 4 has type 'long long unsigned int' [-Wformat=] 911 | seq_printf(s, "%lx - %lx lvl %d stage %s ", | ~~^ | | | long unsigned int | %llx vim +911 drivers/iommu/io-pgtable-arm.c 891 892 static size_t arm_lpae_dump_iova_prot(struct seq_file *s, struct io_pgtable_ops *ops, 893 unsigned long iova) 894 { 895 struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops); 896 struct iova_to_phys_data d; 897 int ret; 898 899 struct io_pgtable_walk_data walk_data = { 900 .data = &d, 901 .visit = visit_iova_to_phys, 902 .addr = iova, 903 .end = iova + 1, 904 }; 905 906 /* Only the mapped iova will be output */ 907 ret = __arm_lpae_iopte_walk(data, &walk_data, data->pgd, data->start_level); 908 if (ret) 909 return ARM_LPAE_GRANULE(data); 910 > 911 seq_printf(s, "%lx - %lx lvl %d stage %s ", 912 iova, iova + ARM_LPAE_BLOCK_SIZE(d.lvl, data), 913 d.lvl, io_pgtable_fmt_names[data->iop.fmt]); 914 915 /* TODO: The dump prot is incomplete and will be supplemented later... */ 916 dump_prot(s, d.pte); 917 seq_puts(s, "\n"); 918 919 return ARM_LPAE_BLOCK_SIZE(d.lvl, data); 920 } 921 #endif 922 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 0/2] iommu: Add io_ptdump debug interface for iommu 2025-08-14 9:30 [PATCH 0/2] iommu: Add io_ptdump debug interface for iommu Qinxin Xia 2025-08-14 9:30 ` [PATCH 1/2] iommu/debug: Add IOMMU page table dump debug facility Qinxin Xia 2025-08-14 9:30 ` [PATCH 2/2] iommu/io-pgtable: Add ARM SMMUv3 page table dump support Qinxin Xia @ 2025-09-02 16:10 ` Jason Gunthorpe 2025-09-10 3:20 ` Qinxin Xia 2 siblings, 1 reply; 14+ messages in thread From: Jason Gunthorpe @ 2025-09-02 16:10 UTC (permalink / raw) To: Qinxin Xia Cc: will, robin.murphy, linux-kernel, linux-arm-kernel, iommu, yangyicong, wangzhou1, prime.zeng, xuwei5, fanghao11, jonathan.cameron, linuxarm On Thu, Aug 14, 2025 at 05:30:03PM +0800, Qinxin Xia wrote: > This patch supports the iopgtable_dump function (similar to kernel_page_dump). > The IOMMU page table dump debugging function is added to the framework layer. > Different architectures only need to provide the implemented dump ops. > It also provides the implementation of ARM SMMUv3 and io-pgtable-arm. > > Qinxin Xia (2): > iommu/debug: Add IOMMU page table dump debug facility > iommu/io-pgtable: Add ARM SMMUv3 page table dump support I'd prefer we do this on top of iommu pt please, I don't want to further deeping the hole of changing all the page table code in all drivers for debugfs. Jason ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 0/2] iommu: Add io_ptdump debug interface for iommu 2025-09-02 16:10 ` [PATCH 0/2] iommu: Add io_ptdump debug interface for iommu Jason Gunthorpe @ 2025-09-10 3:20 ` Qinxin Xia 2025-09-10 14:15 ` Jason Gunthorpe 0 siblings, 1 reply; 14+ messages in thread From: Qinxin Xia @ 2025-09-10 3:20 UTC (permalink / raw) To: Jason Gunthorpe Cc: will, robin.murphy, linux-kernel, linux-arm-kernel, iommu, yangyicong, wangzhou1, prime.zeng, xuwei5, fanghao11, jonathan.cameron, linuxarm On 2025/9/3 00:10:28, Jason Gunthorpe <jgg@ziepe.ca> wrote: > On Thu, Aug 14, 2025 at 05:30:03PM +0800, Qinxin Xia wrote: >> This patch supports the iopgtable_dump function (similar to kernel_page_dump). >> The IOMMU page table dump debugging function is added to the framework layer. >> Different architectures only need to provide the implemented dump ops. >> It also provides the implementation of ARM SMMUv3 and io-pgtable-arm. >> >> Qinxin Xia (2): >> iommu/debug: Add IOMMU page table dump debug facility >> iommu/io-pgtable: Add ARM SMMUv3 page table dump support > > I'd prefer we do this on top of iommu pt please, I don't want to > further deeping the hole of changing all the page table code in all > drivers for debugfs. > > Jason Ok, I see, my colleague Wang Zhou also released a version of io_ptdump a long time ago, which is implemented in smmu debugfs. Will recommends that io_ptdump be implemented in a way similar to CPU page table dump. Using debugfs to expose the data and using format-specific callbacks to implement specific data dumps, I'll talk to him about this as well. ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 0/2] iommu: Add io_ptdump debug interface for iommu 2025-09-10 3:20 ` Qinxin Xia @ 2025-09-10 14:15 ` Jason Gunthorpe 2025-09-11 14:08 ` Qinxin Xia 0 siblings, 1 reply; 14+ messages in thread From: Jason Gunthorpe @ 2025-09-10 14:15 UTC (permalink / raw) To: Qinxin Xia Cc: will, robin.murphy, linux-kernel, linux-arm-kernel, iommu, yangyicong, wangzhou1, prime.zeng, xuwei5, fanghao11, jonathan.cameron, linuxarm On Wed, Sep 10, 2025 at 11:20:08AM +0800, Qinxin Xia wrote: > Ok, I see, my colleague Wang Zhou also released a version of io_ptdump > a long time ago, which is implemented in smmu debugfs. Will recommends that > io_ptdump be implemented in a way similar to CPU page table dump. Using > debugfs to expose the data and using format-specific callbacks to implement > specific data dumps, I'll talk to him about this as well. I feel we should have a iommu subsystem debugfs and per-iommu_domain directories to dump the page tables. The smmu debugfs can report what iommu_domains each STE/CD is referencing. This also needs RCU freeing of page table levels as a locking strategy. Jason ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 0/2] iommu: Add io_ptdump debug interface for iommu 2025-09-10 14:15 ` Jason Gunthorpe @ 2025-09-11 14:08 ` Qinxin Xia 2025-09-15 16:28 ` Jason Gunthorpe 0 siblings, 1 reply; 14+ messages in thread From: Qinxin Xia @ 2025-09-11 14:08 UTC (permalink / raw) To: Jason Gunthorpe Cc: will, robin.murphy, linux-kernel, linux-arm-kernel, iommu, yangyicong, wangzhou1, prime.zeng, xuwei5, fanghao11, jonathan.cameron, linuxarm On 2025/9/10 22:15:47, Jason Gunthorpe <jgg@ziepe.ca> wrote: > On Wed, Sep 10, 2025 at 11:20:08AM +0800, Qinxin Xia wrote: >> Ok, I see, my colleague Wang Zhou also released a version of io_ptdump >> a long time ago, which is implemented in smmu debugfs. Will recommends that >> io_ptdump be implemented in a way similar to CPU page table dump. Using >> debugfs to expose the data and using format-specific callbacks to implement >> specific data dumps, I'll talk to him about this as well. > > I feel we should have a iommu subsystem debugfs and per-iommu_domain > directories to dump the page tables. > > The smmu debugfs can report what iommu_domains each STE/CD is > referencing. > > This also needs RCU freeing of page table levels as a locking > strategy. > > Jason > Thanks, I'll add RCU in the next version, but there's some confusion, Do you mean to create a directory for each domain? like: /sys/kernel/debug/io_page_tables/domain_xxxx (xxxx=domain addr) tree domain_xxxx like: domain_xxxx └── group x │ └── device └── io_ptdump And the current design is such: User Space Interface └── DebugFS file: /sys/kernel/debug/io_page_tables └── Operation: Reading this file triggers the entire debug information collection process Kernel Space Components ├── Configuration option (CONFIG_IO_PTDUMP_DEBUGFS) ├── Initialization module (mm/io_ptdump.c) │ └── device_initcall(io_ptdump_init) │ └── io_ptdump_debugfs_register("io_page_tables") ├── DebugFS backend (mm/io_ptdump_debugfs.c) │ └── DEFINE_SHOW_ATTRIBUTE(io_ptdump) │ └── .show = io_ptdump_show │ └── iommu_group_and_iova_dump(m) └── IOMMU core extension (drivers/iommu/iommu.c) └── iommu_group_and_iova_dump() ├── Traverse all IOMMU groups (via iommu_group_kset) ├── Filter groups with default domain using DMA_IOVA cookie ├── Build domain-group hierarchy │ ├── domain_list: list head │ ├── dump_domain: domain entry │ │ ├── domain: pointer to iommu_domain │ │ └── groups: list head of groups │ └── dump_group: group entry │ └── group: pointer to iommu_group ├── Output domain information ├── Output group and device information └── Call iommu_iova_info_dump() to output IOVA mappings └── Traverse IOVA red-black tree └── Call domain->ops->dump_iova_prot() to get protection information └── ARM SMMUv3 implementation (drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c) └── arm_smmu_dump_iova_prot() └── Call io_pgtable_ops->dump_iova_prot() └── ARM LPAE implementation (drivers/iommu/io-pgtable-arm.c) └── arm_lpae_dump_iova_prot() ├── Use __arm_lpae_iopte_walk() to traverse page tables ├── Obtain page table entry and level information ├── Format and output mapping range and information └── Call dump_prot() to output protection flags └── Use prot_bits array to parse permission bits Do you mean that the interface in io-pgtable-arm.c is directly invoked during the process of obtaining page table information without passing through arm-smmu-v3.c? I'll add STE and CD dumps to the next release. Any other suggestions? ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 0/2] iommu: Add io_ptdump debug interface for iommu 2025-09-11 14:08 ` Qinxin Xia @ 2025-09-15 16:28 ` Jason Gunthorpe 0 siblings, 0 replies; 14+ messages in thread From: Jason Gunthorpe @ 2025-09-15 16:28 UTC (permalink / raw) To: Qinxin Xia Cc: will, robin.murphy, linux-kernel, linux-arm-kernel, iommu, yangyicong, wangzhou1, prime.zeng, xuwei5, fanghao11, jonathan.cameron, linuxarm On Thu, Sep 11, 2025 at 10:08:55PM +0800, Qinxin Xia wrote: > > > On 2025/9/10 22:15:47, Jason Gunthorpe <jgg@ziepe.ca> wrote: > > On Wed, Sep 10, 2025 at 11:20:08AM +0800, Qinxin Xia wrote: > > > Ok, I see, my colleague Wang Zhou also released a version of io_ptdump > > > a long time ago, which is implemented in smmu debugfs. Will recommends that > > > io_ptdump be implemented in a way similar to CPU page table dump. Using > > > debugfs to expose the data and using format-specific callbacks to implement > > > specific data dumps, I'll talk to him about this as well. > > > > I feel we should have a iommu subsystem debugfs and per-iommu_domain > > directories to dump the page tables. > > > > The smmu debugfs can report what iommu_domains each STE/CD is > > referencing. > > > > This also needs RCU freeing of page table levels as a locking > > strategy. > > Thanks, I'll add RCU in the next version, but there's some > confusion, Please don't, RCU is quite complicated, I don't really want to see attempts to retrofit it into the existing page table code. This is why I've said debugging like this needs to go along with the new iommu pt work to consolidate the page table code. > Do you > mean to create a directory for each domain? like: > > /sys/kernel/debug/io_page_tables/domain_xxxx (xxxx=domain addr) Something like this could be a reasonable option. > tree domain_xxxx like: > domain_xxxx > └── group x > │ └── device Though I would probably not include this information.. > └── DebugFS file: /sys/kernel/debug/io_page_tables > └── Operation: Reading this file triggers the entire debug information > collection process I don't think we want to dump every page table in the system in one file. > Do you mean that the interface in io-pgtable-arm.c is directly invoked > during the process of obtaining page table information without passing > through arm-smmu-v3.c? Yes, this is what iommu pt brings. Jason ^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2025-09-15 16:28 UTC | newest] Thread overview: 14+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-08-14 9:30 [PATCH 0/2] iommu: Add io_ptdump debug interface for iommu Qinxin Xia 2025-08-14 9:30 ` [PATCH 1/2] iommu/debug: Add IOMMU page table dump debug facility Qinxin Xia 2025-08-15 6:47 ` kernel test robot 2025-08-15 9:57 ` kernel test robot 2025-09-09 13:06 ` Will Deacon 2025-09-10 2:58 ` Qinxin Xia 2025-09-11 14:58 ` Will Deacon 2025-08-14 9:30 ` [PATCH 2/2] iommu/io-pgtable: Add ARM SMMUv3 page table dump support Qinxin Xia 2025-08-15 9:14 ` kernel test robot 2025-09-02 16:10 ` [PATCH 0/2] iommu: Add io_ptdump debug interface for iommu Jason Gunthorpe 2025-09-10 3:20 ` Qinxin Xia 2025-09-10 14:15 ` Jason Gunthorpe 2025-09-11 14:08 ` Qinxin Xia 2025-09-15 16:28 ` Jason Gunthorpe
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).