From 0934068545d730e892b00d9f641699a94eea926a Mon Sep 17 00:00:00 2001 From: Mitchel Humpherys Date: Fri, 21 Aug 2015 14:08:40 -0700 Subject: [PATCH] iommu/iommu-debug: Provide debugfs for iommu_reg_{read,write} It can be useful to read and modify SMMU settings interactively. Add a debugfs interface for the recently added iommu_reg_read and iommu_reg_write functions for this purpose. Change-Id: If3c9bf1833dc950c7ca1e2ce1a373bcaa31ebcf0 Signed-off-by: Mitchel Humpherys --- drivers/iommu/iommu-debug.c | 103 ++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/drivers/iommu/iommu-debug.c b/drivers/iommu/iommu-debug.c index 3ce9b7c39291..1f9ba3156c33 100644 --- a/drivers/iommu/iommu-debug.c +++ b/drivers/iommu/iommu-debug.c @@ -35,6 +35,7 @@ struct iommu_debug_attachment { struct device *dev; struct dentry *dentry; struct list_head list; + unsigned long reg_offset; }; static int iommu_debug_attachment_info_show(struct seq_file *s, void *ignored) @@ -112,6 +113,84 @@ iommu_debug_attachment_trigger_fault_fops = { .write = iommu_debug_attachment_trigger_fault_write, }; +static ssize_t iommu_debug_attachment_reg_offset_write( + struct file *file, const char __user *ubuf, size_t count, + loff_t *offset) +{ + struct iommu_debug_attachment *attach = file->private_data; + unsigned long reg_offset; + + if (kstrtoul_from_user(ubuf, count, 0, ®_offset)) { + pr_err("Invalid reg_offset format\n"); + return -EFAULT; + } + + attach->reg_offset = reg_offset; + + return count; +} + +static const struct file_operations iommu_debug_attachment_reg_offset_fops = { + .open = simple_open, + .write = iommu_debug_attachment_reg_offset_write, +}; + +static ssize_t iommu_debug_attachment_reg_read_read( + struct file *file, char __user *ubuf, size_t count, loff_t *offset) +{ + struct iommu_debug_attachment *attach = file->private_data; + unsigned long val; + char *val_str; + ssize_t val_str_len; + + if (*offset) + return 0; + + val = iommu_reg_read(attach->domain, attach->reg_offset); + val_str = kasprintf(GFP_KERNEL, "0x%lx\n", val); + if (!val_str) + return -ENOMEM; + val_str_len = strlen(val_str); + + if (copy_to_user(ubuf, val_str, val_str_len)) { + pr_err("copy_to_user failed\n"); + val_str_len = -EFAULT; + goto out; + } + *offset = 1; /* non-zero means we're done */ + +out: + kfree(val_str); + return val_str_len; +} + +static const struct file_operations iommu_debug_attachment_reg_read_fops = { + .open = simple_open, + .read = iommu_debug_attachment_reg_read_read, +}; + +static ssize_t iommu_debug_attachment_reg_write_write( + struct file *file, const char __user *ubuf, size_t count, + loff_t *offset) +{ + struct iommu_debug_attachment *attach = file->private_data; + unsigned long val; + + if (kstrtoul_from_user(ubuf, count, 0, &val)) { + pr_err("Invalid val format\n"); + return -EFAULT; + } + + iommu_reg_write(attach->domain, attach->reg_offset, val); + + return count; +} + +static const struct file_operations iommu_debug_attachment_reg_write_fops = { + .open = simple_open, + .write = iommu_debug_attachment_reg_write_write, +}; + /* should be called with iommu_debug_attachments_lock locked */ static int iommu_debug_attach_add_debugfs( struct iommu_debug_attachment *attach) @@ -152,6 +231,30 @@ static int iommu_debug_attach_add_debugfs( goto err_rmdir; } + if (!debugfs_create_file( + "reg_offset", S_IRUSR, attach->dentry, attach, + &iommu_debug_attachment_reg_offset_fops)) { + pr_err("Couldn't create iommu/attachments/%s/reg_offset debugfs file for domain 0x%p\n", + dev_name(dev), domain); + goto err_rmdir; + } + + if (!debugfs_create_file( + "reg_read", S_IRUSR, attach->dentry, attach, + &iommu_debug_attachment_reg_read_fops)) { + pr_err("Couldn't create iommu/attachments/%s/reg_read debugfs file for domain 0x%p\n", + dev_name(dev), domain); + goto err_rmdir; + } + + if (!debugfs_create_file( + "reg_write", S_IRUSR, attach->dentry, attach, + &iommu_debug_attachment_reg_write_fops)) { + pr_err("Couldn't create iommu/attachments/%s/reg_write debugfs file for domain 0x%p\n", + dev_name(dev), domain); + goto err_rmdir; + } + return 0; err_rmdir: