Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3feae538 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "iommu/iommu-debug: Only uniquify directory names for dynamic domains"

parents b130da11 09137117
Loading
Loading
Loading
Loading
+62 −0
Original line number Diff line number Diff line
@@ -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) {
@@ -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)
+124 −8
Original line number Diff line number Diff line
@@ -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,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, &reg_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(
@@ -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: