[PATCH 5/8] iommu/amd: Add support for device id user input
From: Dheeraj Kumar Srivastava
Date: Tue Oct 08 2024 - 06:42:23 EST
Device id user input is needed for dumping IOMMU data structures like
device table, IRT etc in AMD IOMMU debugfs.
eg.
1. # echo 0000:01:00.0 > /sys/kernel/debug/iommu/amd/devid
# cat /sys/kernel/debug/iommu/amd/devid
Output : 0000:01:00.0
2. # echo 01:00.0 > /sys/kernel/debug/iommu/amd/devid
# cat /sys/kernel/debug/iommu/amd/devid
Output : 0000:01:00.0
Signed-off-by: Dheeraj Kumar Srivastava <dheerajkumar.srivastava@xxxxxxx>
---
drivers/iommu/amd/debugfs.c | 86 +++++++++++++++++++++++++++++++++++++
1 file changed, 86 insertions(+)
diff --git a/drivers/iommu/amd/debugfs.c b/drivers/iommu/amd/debugfs.c
index 69d2b01bc0e4..0d11250c1a00 100644
--- a/drivers/iommu/amd/debugfs.c
+++ b/drivers/iommu/amd/debugfs.c
@@ -16,9 +16,11 @@ static struct dentry *amd_iommu_debugfs;
#define MAX_NAME_LEN 20
#define OFS_IN_SZ 8
+#define DEVID_IN_SZ 16
static int mmio_offset = -1;
static int cap_offset = -1;
+static int sbdf = -1;
static ssize_t iommu_mmio_write(struct file *filp, const char __user *ubuf,
size_t cnt, loff_t *ppos)
@@ -184,6 +186,88 @@ static int iommu_cmdbuf_show(struct seq_file *m, void *unused)
}
DEFINE_SHOW_ATTRIBUTE(iommu_cmdbuf);
+static ssize_t devid_write(struct file *filp, const char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ struct amd_iommu_pci_seg *pci_seg;
+ int seg, bus, slot, func;
+ struct amd_iommu *iommu;
+ char *srcid_ptr;
+ int i, ret = cnt;
+ u16 devid;
+
+ if (cnt >= DEVID_IN_SZ) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ srcid_ptr = memdup_user_nul(ubuf, cnt);
+ if (IS_ERR(srcid_ptr)) {
+ ret = PTR_ERR(srcid_ptr);
+ goto err;
+ }
+
+ i = sscanf(srcid_ptr, "%x:%x:%x.%x", &seg, &bus, &slot, &func);
+ if (i != 4) {
+ i = sscanf(srcid_ptr, "%x:%x.%x", &bus, &slot, &func);
+ if (i != 3) {
+ ret = -EINVAL;
+ goto free;
+ }
+ seg = 0;
+ }
+
+ devid = PCI_DEVID(bus, PCI_DEVFN(slot, func));
+
+ /* Check if user device id input is a valid input */
+ for_each_pci_segment(pci_seg) {
+ if (pci_seg->id != seg)
+ continue;
+ if (devid > pci_seg->last_bdf) {
+ ret = -EINVAL;
+ goto free;
+ }
+ iommu = pci_seg->rlookup_table[devid];
+ if (!iommu) {
+ ret = -ENODEV;
+ goto free;
+ }
+ break;
+ }
+
+ if (pci_seg->id != seg) {
+ ret = -EINVAL;
+ goto free;
+ }
+
+ sbdf = PCI_SEG_DEVID_TO_SBDF(seg, devid);
+
+ kfree(srcid_ptr);
+ *ppos += cnt;
+ return ret;
+
+free:
+ kfree(srcid_ptr);
+err:
+ sbdf = -1;
+ return ret;
+}
+
+static int devid_show(struct seq_file *m, void *unused)
+{
+ u16 devid;
+
+ if (sbdf >= 0) {
+ devid = PCI_SBDF_TO_DEVID(sbdf);
+ seq_printf(m, "%04x:%02x:%02x:%x\n", PCI_SBDF_TO_SEGID(sbdf),
+ PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid));
+ } else
+ seq_puts(m, "No or Invalid input provided\n");
+
+ return 0;
+}
+DEFINE_SHOW_STORE_ATTRIBUTE(devid);
+
void amd_iommu_debugfs_setup(void)
{
struct amd_iommu *iommu;
@@ -206,4 +290,6 @@ void amd_iommu_debugfs_setup(void)
debugfs_create_file("cmdbuf", 0444, iommu->debugfs, iommu,
&iommu_cmdbuf_fops);
}
+ debugfs_create_file("devid", 0644, amd_iommu_debugfs, NULL,
+ &devid_fops);
}
--
2.25.1