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: Lu Baolu <baolu.lu@linux.intel.com> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com> Reviewed-by: Kevin Tian <kevin.tian@intel.com> Signed-off-by: Yi Liu <yi.l.liu@intel.com> Link: https://lore.kernel.org/r/20241107122234.7424-12-yi.l.liu@intel.com Signed-off-by: Joerg Roedel <jroedel@suse.de>
This commit is contained in:
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -130,8 +130,58 @@ out:
|
||||
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,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user