Commit 67f6f56b authored by Yi Liu's avatar Yi Liu Committed by Joerg Roedel
Browse files

iommu/vt-d: Add set_dev_pasid callback for nested domain



Add intel_nested_set_dev_pasid() to set a nested type domain to a PASID
of a device.

Co-developed-by: default avatarLu Baolu <baolu.lu@linux.intel.com>
Signed-off-by: default avatarLu Baolu <baolu.lu@linux.intel.com>
Reviewed-by: default avatarKevin Tian <kevin.tian@intel.com>
Signed-off-by: default avatarYi Liu <yi.l.liu@intel.com>
Link: https://lore.kernel.org/r/20241107122234.7424-12-yi.l.liu@intel.com


Signed-off-by: default avatarJoerg Roedel <jroedel@suse.de>
parent 9bc18d28
Loading
Loading
Loading
Loading
+0 −6
Original line number Diff line number Diff line
@@ -1812,12 +1812,6 @@ static int domain_setup_first_level(struct intel_iommu *iommu,
					  (pgd_t *)pgd, flags, old);
}

static bool dev_is_real_dma_subdevice(struct device *dev)
{
	return dev && dev_is_pci(dev) &&
	       pci_real_dma_dev(to_pci_dev(dev)) != to_pci_dev(dev);
}

static int dmar_domain_attach_device(struct dmar_domain *domain,
				     struct device *dev)
{
+7 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#include <linux/bitfield.h>
#include <linux/xarray.h>
#include <linux/perf_event.h>
#include <linux/pci.h>

#include <asm/cacheflush.h>
#include <asm/iommu.h>
@@ -832,6 +833,12 @@ iommu_domain_did(struct iommu_domain *domain, struct intel_iommu *iommu)
	return domain_id_iommu(to_dmar_domain(domain), iommu);
}

static inline bool dev_is_real_dma_subdevice(struct device *dev)
{
	return dev && dev_is_pci(dev) &&
	       pci_real_dma_dev(to_pci_dev(dev)) != to_pci_dev(dev);
}

/*
 * 0: readable
 * 1: writable
+50 −0
Original line number Diff line number Diff line
@@ -130,8 +130,58 @@ static int intel_nested_cache_invalidate_user(struct iommu_domain *domain,
	return ret;
}

static int domain_setup_nested(struct intel_iommu *iommu,
			       struct dmar_domain *domain,
			       struct device *dev, ioasid_t pasid,
			       struct iommu_domain *old)
{
	if (!old)
		return intel_pasid_setup_nested(iommu, dev, pasid, domain);
	return intel_pasid_replace_nested(iommu, dev, pasid,
					  iommu_domain_did(old, iommu),
					  domain);
}

static int intel_nested_set_dev_pasid(struct iommu_domain *domain,
				      struct device *dev, ioasid_t pasid,
				      struct iommu_domain *old)
{
	struct device_domain_info *info = dev_iommu_priv_get(dev);
	struct dmar_domain *dmar_domain = to_dmar_domain(domain);
	struct intel_iommu *iommu = info->iommu;
	struct dev_pasid_info *dev_pasid;
	int ret;

	if (!pasid_supported(iommu) || dev_is_real_dma_subdevice(dev))
		return -EOPNOTSUPP;

	if (context_copied(iommu, info->bus, info->devfn))
		return -EBUSY;

	ret = paging_domain_compatible(&dmar_domain->s2_domain->domain, dev);
	if (ret)
		return ret;

	dev_pasid = domain_add_dev_pasid(domain, dev, pasid);
	if (IS_ERR(dev_pasid))
		return PTR_ERR(dev_pasid);

	ret = domain_setup_nested(iommu, dmar_domain, dev, pasid, old);
	if (ret)
		goto out_remove_dev_pasid;

	domain_remove_dev_pasid(old, dev, pasid);

	return 0;

out_remove_dev_pasid:
	domain_remove_dev_pasid(domain, dev, pasid);
	return ret;
}

static const struct iommu_domain_ops intel_nested_domain_ops = {
	.attach_dev		= intel_nested_attach_dev,
	.set_dev_pasid		= intel_nested_set_dev_pasid,
	.free			= intel_nested_domain_free,
	.cache_invalidate_user	= intel_nested_cache_invalidate_user,
};