iommu/vt-d: debugfs: Create/remove debugfs file per {device, pasid}
authorJingqi Liu <Jingqi.liu@intel.com>
Mon, 16 Oct 2023 03:28:29 +0000 (11:28 +0800)
committerJoerg Roedel <jroedel@suse.de>
Mon, 16 Oct 2023 07:34:51 +0000 (09:34 +0200)
Add a debugfs directory per pair of {device, pasid} if the mappings of
its page table are created and destroyed by the iommu_map/unmap()
interfaces. i.e. /sys/kernel/debug/iommu/intel/<device source id>/<pasid>.
Create a debugfs file in the directory for users to dump the page
table corresponding to {device, pasid}. e.g.
/sys/kernel/debug/iommu/intel/0000:00:02.0/1/domain_translation_struct.
For the default domain without pasid, it creates a debugfs file in the
debugfs device directory for users to dump its page table. e.g.
/sys/kernel/debug/iommu/intel/0000:00:02.0/domain_translation_struct.

When setting a domain to a PASID of device, create a debugfs file in
the pasid debugfs directory for users to dump the page table of the
specified pasid. Remove the debugfs device directory of the device
when releasing a device. e.g.
/sys/kernel/debug/iommu/intel/0000:00:01.0

Signed-off-by: Jingqi Liu <Jingqi.liu@intel.com>
Link: https://lore.kernel.org/r/20231013135811.73953-3-Jingqi.liu@intel.com
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/intel/debugfs.c
drivers/iommu/intel/iommu.c
drivers/iommu/intel/iommu.h

index 497c1561d3d21aefa291d67041a48b846b415581..8a18a7be52152d83b5a91894c2348e83f22d132a 100644 (file)
@@ -111,6 +111,8 @@ static const struct iommu_regset iommu_regs_64[] = {
        IOMMU_REGSET_ENTRY(VCRSP),
 };
 
+static struct dentry *intel_iommu_debug;
+
 static int iommu_regset_show(struct seq_file *m, void *unused)
 {
        struct dmar_drhd_unit *drhd;
@@ -671,16 +673,12 @@ static const struct file_operations dmar_perf_latency_fops = {
 
 void __init intel_iommu_debugfs_init(void)
 {
-       struct dentry *intel_iommu_debug = debugfs_create_dir("intel",
-                                               iommu_debugfs_dir);
+       intel_iommu_debug = debugfs_create_dir("intel", iommu_debugfs_dir);
 
        debugfs_create_file("iommu_regset", 0444, intel_iommu_debug, NULL,
                            &iommu_regset_fops);
        debugfs_create_file("dmar_translation_struct", 0444, intel_iommu_debug,
                            NULL, &dmar_translation_struct_fops);
-       debugfs_create_file("domain_translation_struct", 0444,
-                           intel_iommu_debug, NULL,
-                           &domain_translation_struct_fops);
        debugfs_create_file("invalidation_queue", 0444, intel_iommu_debug,
                            NULL, &invalidation_queue_fops);
 #ifdef CONFIG_IRQ_REMAP
@@ -690,3 +688,48 @@ void __init intel_iommu_debugfs_init(void)
        debugfs_create_file("dmar_perf_latency", 0644, intel_iommu_debug,
                            NULL, &dmar_perf_latency_fops);
 }
+
+/*
+ * Create a debugfs directory for each device, and then create a
+ * debugfs file in this directory for users to dump the page table
+ * of the default domain. e.g.
+ * /sys/kernel/debug/iommu/intel/0000:00:01.0/domain_translation_struct
+ */
+void intel_iommu_debugfs_create_dev(struct device_domain_info *info)
+{
+       info->debugfs_dentry = debugfs_create_dir(dev_name(info->dev), intel_iommu_debug);
+
+       debugfs_create_file("domain_translation_struct", 0444, info->debugfs_dentry,
+                           NULL, &domain_translation_struct_fops);
+}
+
+/* Remove the device debugfs directory. */
+void intel_iommu_debugfs_remove_dev(struct device_domain_info *info)
+{
+       debugfs_remove_recursive(info->debugfs_dentry);
+}
+
+/*
+ * Create a debugfs directory per pair of {device, pasid}, then create the
+ * corresponding debugfs file in this directory for users to dump its page
+ * table. e.g.
+ * /sys/kernel/debug/iommu/intel/0000:00:01.0/1/domain_translation_struct
+ *
+ * The debugfs only dumps the page tables whose mappings are created and
+ * destroyed by the iommu_map/unmap() interfaces. Check the mapping type
+ * of the domain before creating debugfs directory.
+ */
+void intel_iommu_debugfs_create_dev_pasid(struct dev_pasid_info *dev_pasid)
+{
+       struct device_domain_info *info = dev_iommu_priv_get(dev_pasid->dev);
+       char dir_name[10];
+
+       sprintf(dir_name, "%x", dev_pasid->pasid);
+       dev_pasid->debugfs_dentry = debugfs_create_dir(dir_name, info->debugfs_dentry);
+}
+
+/* Remove the device pasid debugfs directory. */
+void intel_iommu_debugfs_remove_dev_pasid(struct dev_pasid_info *dev_pasid)
+{
+       debugfs_remove_recursive(dev_pasid->debugfs_dentry);
+}
index 5db283c17e0dc5cd7ffd0147efec316595df53c8..a42916354ed4c2d4dc4e7b240831dd51f66a334c 100644 (file)
@@ -4425,6 +4425,8 @@ static struct iommu_device *intel_iommu_probe_device(struct device *dev)
                }
        }
 
+       intel_iommu_debugfs_create_dev(info);
+
        return &iommu->iommu;
 }
 
@@ -4434,6 +4436,7 @@ static void intel_iommu_release_device(struct device *dev)
 
        dmar_remove_one_dev_info(dev);
        intel_pasid_free_table(dev);
+       intel_iommu_debugfs_remove_dev(info);
        dev_iommu_priv_set(dev, NULL);
        kfree(info);
        set_dma_ops(dev, NULL);
@@ -4726,6 +4729,7 @@ static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid)
        spin_unlock_irqrestore(&dmar_domain->lock, flags);
 
        domain_detach_iommu(dmar_domain, iommu);
+       intel_iommu_debugfs_remove_dev_pasid(dev_pasid);
        kfree(dev_pasid);
 out_tear_down:
        intel_pasid_tear_down_entry(iommu, dev, pasid, false);
@@ -4778,6 +4782,9 @@ static int intel_iommu_set_dev_pasid(struct iommu_domain *domain,
        list_add(&dev_pasid->link_domain, &dmar_domain->dev_pasids);
        spin_unlock_irqrestore(&dmar_domain->lock, flags);
 
+       if (domain->type & __IOMMU_DOMAIN_PAGING)
+               intel_iommu_debugfs_create_dev_pasid(dev_pasid);
+
        return 0;
 out_detach_iommu:
        domain_detach_iommu(dmar_domain, iommu);
index c18fb699c87ac5faabf40c84eafba8fb28f8ad9d..43ecda2ac11db3d5e645fdf697709b7755d6ca6a 100644 (file)
@@ -716,12 +716,18 @@ struct device_domain_info {
        struct intel_iommu *iommu; /* IOMMU used by this device */
        struct dmar_domain *domain; /* pointer to domain */
        struct pasid_table *pasid_table; /* pasid table */
+#ifdef CONFIG_INTEL_IOMMU_DEBUGFS
+       struct dentry *debugfs_dentry; /* pointer to device directory dentry */
+#endif
 };
 
 struct dev_pasid_info {
        struct list_head link_domain;   /* link to domain siblings */
        struct device *dev;
        ioasid_t pasid;
+#ifdef CONFIG_INTEL_IOMMU_DEBUGFS
+       struct dentry *debugfs_dentry; /* pointer to pasid directory dentry */
+#endif
 };
 
 static inline void __iommu_flush_cache(
@@ -883,8 +889,16 @@ static inline void intel_svm_remove_dev_pasid(struct device *dev, ioasid_t pasid
 
 #ifdef CONFIG_INTEL_IOMMU_DEBUGFS
 void intel_iommu_debugfs_init(void);
+void intel_iommu_debugfs_create_dev(struct device_domain_info *info);
+void intel_iommu_debugfs_remove_dev(struct device_domain_info *info);
+void intel_iommu_debugfs_create_dev_pasid(struct dev_pasid_info *dev_pasid);
+void intel_iommu_debugfs_remove_dev_pasid(struct dev_pasid_info *dev_pasid);
 #else
 static inline void intel_iommu_debugfs_init(void) {}
+static inline void intel_iommu_debugfs_create_dev(struct device_domain_info *info) {}
+static inline void intel_iommu_debugfs_remove_dev(struct device_domain_info *info) {}
+static inline void intel_iommu_debugfs_create_dev_pasid(struct dev_pasid_info *dev_pasid) {}
+static inline void intel_iommu_debugfs_remove_dev_pasid(struct dev_pasid_info *dev_pasid) {}
 #endif /* CONFIG_INTEL_IOMMU_DEBUGFS */
 
 extern const struct attribute_group *intel_iommu_groups[];