Commit 5dfaeb00 authored by Jean-Philippe Brucker's avatar Jean-Philippe Brucker Committed by Zheng Zengkai
Browse files

iommu: Add group variant for SVA bind/unbind

maillist inclusion
category: feature
bugzilla: 51855
CVE: NA

Reference: https://jpbrucker.net/git/linux/commit/?h=sva/2021-03-01&id=7984f27d63b2f56dcdc106be9484061b3a13df0b



---------------------------------------------

VFIO works directly with IOMMU groups rather than devices. Even if groups
ar still required to only contain one device in order to use SVA, add a
set of helpers for VFIO.

Signed-off-by: default avatarJean-Philippe Brucker <jean-philippe@linaro.org>
Signed-off-by: default avatarLijun Fang <fanglijun3@huawei.com>
Reviewed-by: default avatarWeilong Chen <chenweilong@huawei.com>
Signed-off-by: default avatarZheng Zengkai <zhengzengkai@huawei.com>
parent a3bc5676
Loading
Loading
Loading
Loading
+51 −21
Original line number Diff line number Diff line
@@ -3067,6 +3067,55 @@ int iommu_aux_get_pasid(struct iommu_domain *domain, struct device *dev)
}
EXPORT_SYMBOL_GPL(iommu_aux_get_pasid);

struct iommu_sva_bind_group_data {
	struct mm_struct *mm;
	struct iommu_sva *handle;
	void *drvdata;
};

static int iommu_group_do_bind_dev(struct device *dev, void *data)
{
	struct iommu_sva_bind_group_data *bind = data;
	const struct iommu_ops *ops = dev->bus->iommu_ops;

	if (!ops || !ops->sva_bind)
		return -ENODEV;

	bind->handle = ops->sva_bind(dev, bind->mm, bind->drvdata);
	return PTR_ERR_OR_ZERO(bind->handle);
}

struct iommu_sva *
iommu_sva_bind_group(struct iommu_group *group, struct mm_struct *mm,
		     void *drvdata)
{
	int ret = -EINVAL;
	struct iommu_sva_bind_group_data data = {
		.mm = mm,
		.drvdata = drvdata,
	};

	/* Ensure device count and domain don't change while we're binding */
	mutex_lock(&group->mutex);

	/*
	 * To keep things simple, SVA currently doesn't support IOMMU groups
	 * with more than one device. Existing SVA-capable systems are not
	 * affected by the problems that required IOMMU groups (lack of ACS
	 * isolation, device ID aliasing and other hardware issues).
	 */
	if (iommu_group_device_count(group) != 1)
		goto out_unlock;

	ret = __iommu_group_for_each_dev(group, &data,
					 iommu_group_do_bind_dev);
out_unlock:
	mutex_unlock(&group->mutex);

	return ret ? ERR_PTR(ret) : data.handle;
}
EXPORT_SYMBOL_GPL(iommu_sva_bind_group);

/**
 * iommu_sva_bind_device() - Bind a process address space to a device
 * @dev: the device
@@ -3085,33 +3134,14 @@ EXPORT_SYMBOL_GPL(iommu_aux_get_pasid);
struct iommu_sva *
iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void *drvdata)
{
	struct iommu_sva *handle;
	struct iommu_group *group;
	struct iommu_sva *handle = ERR_PTR(-EINVAL);
	const struct iommu_ops *ops = dev->bus->iommu_ops;

	if (!ops || !ops->sva_bind)
		return ERR_PTR(-ENODEV);

	group = iommu_group_get(dev);
	if (!group)
		return ERR_PTR(-ENODEV);

	/* Ensure device count and domain don't change while we're binding */
	mutex_lock(&group->mutex);

	/*
	 * To keep things simple, SVA currently doesn't support IOMMU groups
	 * with more than one device. Existing SVA-capable systems are not
	 * affected by the problems that required IOMMU groups (lack of ACS
	 * isolation, device ID aliasing and other hardware issues).
	 */
	if (iommu_group_device_count(group) != 1)
		goto out_unlock;

	handle = ops->sva_bind(dev, mm, drvdata);

out_unlock:
	mutex_unlock(&group->mutex);
	handle = iommu_sva_bind_group(group, mm, drvdata);
	iommu_group_put(group);

	return handle;
+10 −0
Original line number Diff line number Diff line
@@ -666,6 +666,9 @@ int iommu_aux_get_pasid(struct iommu_domain *domain, struct device *dev);
struct iommu_sva *iommu_sva_bind_device(struct device *dev,
					struct mm_struct *mm,
					void *drvdata);
extern struct iommu_sva *
iommu_sva_bind_group(struct iommu_group *group, struct mm_struct *mm,
		     void *drvdata);
void iommu_sva_unbind_device(struct iommu_sva *handle);
u32 iommu_sva_get_pasid(struct iommu_sva *handle);

@@ -1107,6 +1110,13 @@ int iommu_attach_pasid_table(struct iommu_domain *domain,
static inline
void iommu_detach_pasid_table(struct iommu_domain *domain) {}

static inline struct iommu_sva *
iommu_sva_bind_group(struct iommu_group *group, struct mm_struct *mm,
		     void *drvdata)
{
	return -ENODEV;
}

#endif /* CONFIG_IOMMU_API */

/**