Loading drivers/iommu/arm-smmu.c +62 −0 Original line number Diff line number Diff line Loading @@ -2338,6 +2338,66 @@ static phys_addr_t arm_smmu_iova_to_phys_hard_no_halt( return __arm_smmu_iova_to_phys_hard(domain, iova, false); } static unsigned long arm_smmu_reg_read(struct iommu_domain *domain, unsigned long offset) { struct arm_smmu_domain *smmu_domain = domain->priv; struct arm_smmu_device *smmu; struct arm_smmu_cfg *cfg = &smmu_domain->cfg; void __iomem *cb_base; unsigned long val; if (offset >= SZ_4K) { pr_err("Invalid offset: 0x%lx\n", offset); return 0; } mutex_lock(&smmu_domain->init_mutex); smmu = smmu_domain->smmu; if (!smmu) { WARN(1, "Can't read registers of a detached domain\n"); val = 0; goto unlock; } cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx); arm_smmu_enable_clocks(smmu); val = readl_relaxed(cb_base + offset); arm_smmu_disable_clocks(smmu); unlock: mutex_unlock(&smmu_domain->init_mutex); return val; } static void arm_smmu_reg_write(struct iommu_domain *domain, unsigned long offset, unsigned long val) { struct arm_smmu_domain *smmu_domain = domain->priv; struct arm_smmu_device *smmu; struct arm_smmu_cfg *cfg = &smmu_domain->cfg; void __iomem *cb_base; if (offset >= SZ_4K) { pr_err("Invalid offset: 0x%lx\n", offset); return; } mutex_lock(&smmu_domain->init_mutex); smmu = smmu_domain->smmu; if (!smmu) { WARN(1, "Can't read registers of a detached domain\n"); goto unlock; } cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx); arm_smmu_enable_clocks(smmu); writel_relaxed(val, cb_base + offset); arm_smmu_disable_clocks(smmu); unlock: mutex_unlock(&smmu_domain->init_mutex); } static bool arm_smmu_capable(enum iommu_cap cap) { switch (cap) { Loading Loading @@ -2643,6 +2703,8 @@ static struct iommu_ops arm_smmu_ops = { .pgsize_bitmap = -1UL, /* Restricted during device attach */ .dma_supported = arm_smmu_dma_supported, .trigger_fault = arm_smmu_trigger_fault, .reg_read = arm_smmu_reg_read, .reg_write = arm_smmu_reg_write, }; static void arm_smmu_device_reset(struct arm_smmu_device *smmu) Loading drivers/iommu/iommu-debug.c +124 −8 Original line number Diff line number Diff line Loading @@ -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) Loading Loading @@ -112,28 +113,119 @@ 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) { uuid_le uuid; char *attach_name; const char *attach_name; struct device *dev = attach->dev; struct iommu_domain *domain = attach->domain; int is_dynamic; if (iommu_domain_get_attr(domain, DOMAIN_ATTR_DYNAMIC, &is_dynamic)) is_dynamic = 0; if (is_dynamic) { uuid_le uuid; uuid_le_gen(&uuid); attach_name = kasprintf(GFP_KERNEL, "%s-%pUl", dev_name(dev), uuid.b); attach_name = kasprintf(GFP_KERNEL, "%s-%pUl", dev_name(dev), uuid.b); if (!attach_name) return -ENOMEM; } else { attach_name = dev_name(dev); } attach->dentry = debugfs_create_dir(attach_name, debugfs_attachments_dir); if (!attach->dentry) { pr_err("Couldn't create iommu/attachments/%s debugfs directory for domain 0x%p\n", attach_name, domain); if (is_dynamic) kfree(attach_name); return -EIO; } if (is_dynamic) kfree(attach_name); if (!debugfs_create_file( Loading @@ -152,6 +244,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: Loading Loading
drivers/iommu/arm-smmu.c +62 −0 Original line number Diff line number Diff line Loading @@ -2338,6 +2338,66 @@ static phys_addr_t arm_smmu_iova_to_phys_hard_no_halt( return __arm_smmu_iova_to_phys_hard(domain, iova, false); } static unsigned long arm_smmu_reg_read(struct iommu_domain *domain, unsigned long offset) { struct arm_smmu_domain *smmu_domain = domain->priv; struct arm_smmu_device *smmu; struct arm_smmu_cfg *cfg = &smmu_domain->cfg; void __iomem *cb_base; unsigned long val; if (offset >= SZ_4K) { pr_err("Invalid offset: 0x%lx\n", offset); return 0; } mutex_lock(&smmu_domain->init_mutex); smmu = smmu_domain->smmu; if (!smmu) { WARN(1, "Can't read registers of a detached domain\n"); val = 0; goto unlock; } cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx); arm_smmu_enable_clocks(smmu); val = readl_relaxed(cb_base + offset); arm_smmu_disable_clocks(smmu); unlock: mutex_unlock(&smmu_domain->init_mutex); return val; } static void arm_smmu_reg_write(struct iommu_domain *domain, unsigned long offset, unsigned long val) { struct arm_smmu_domain *smmu_domain = domain->priv; struct arm_smmu_device *smmu; struct arm_smmu_cfg *cfg = &smmu_domain->cfg; void __iomem *cb_base; if (offset >= SZ_4K) { pr_err("Invalid offset: 0x%lx\n", offset); return; } mutex_lock(&smmu_domain->init_mutex); smmu = smmu_domain->smmu; if (!smmu) { WARN(1, "Can't read registers of a detached domain\n"); goto unlock; } cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx); arm_smmu_enable_clocks(smmu); writel_relaxed(val, cb_base + offset); arm_smmu_disable_clocks(smmu); unlock: mutex_unlock(&smmu_domain->init_mutex); } static bool arm_smmu_capable(enum iommu_cap cap) { switch (cap) { Loading Loading @@ -2643,6 +2703,8 @@ static struct iommu_ops arm_smmu_ops = { .pgsize_bitmap = -1UL, /* Restricted during device attach */ .dma_supported = arm_smmu_dma_supported, .trigger_fault = arm_smmu_trigger_fault, .reg_read = arm_smmu_reg_read, .reg_write = arm_smmu_reg_write, }; static void arm_smmu_device_reset(struct arm_smmu_device *smmu) Loading
drivers/iommu/iommu-debug.c +124 −8 Original line number Diff line number Diff line Loading @@ -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) Loading Loading @@ -112,28 +113,119 @@ 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) { uuid_le uuid; char *attach_name; const char *attach_name; struct device *dev = attach->dev; struct iommu_domain *domain = attach->domain; int is_dynamic; if (iommu_domain_get_attr(domain, DOMAIN_ATTR_DYNAMIC, &is_dynamic)) is_dynamic = 0; if (is_dynamic) { uuid_le uuid; uuid_le_gen(&uuid); attach_name = kasprintf(GFP_KERNEL, "%s-%pUl", dev_name(dev), uuid.b); attach_name = kasprintf(GFP_KERNEL, "%s-%pUl", dev_name(dev), uuid.b); if (!attach_name) return -ENOMEM; } else { attach_name = dev_name(dev); } attach->dentry = debugfs_create_dir(attach_name, debugfs_attachments_dir); if (!attach->dentry) { pr_err("Couldn't create iommu/attachments/%s debugfs directory for domain 0x%p\n", attach_name, domain); if (is_dynamic) kfree(attach_name); return -EIO; } if (is_dynamic) kfree(attach_name); if (!debugfs_create_file( Loading @@ -152,6 +244,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: Loading