Skip to content

Commit eaca888

Browse files
LuBaolujoergroedel
authored andcommitted
iommu/vt-d: Add SVA domain support
Add support for SVA domain allocation and provide an SVA-specific iommu_domain_ops. This implementation is based on the existing SVA code. Possible cleanup and refactoring are left for incremental changes later. The VT-d driver will also need to support setting a DMA domain to a PASID of device. Current SVA implementation uses different data structures to track the domain and device PASID relationship. That's the reason why we need to check the domain type in remove_dev_pasid callback. Eventually we'll consolidate the data structures and remove the need of domain type check. Signed-off-by: Lu Baolu <[email protected]> Reviewed-by: Kevin Tian <[email protected]> Reviewed-by: Jason Gunthorpe <[email protected]> Reviewed-by: Yi Liu <[email protected]> Tested-by: Tony Zhu <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Joerg Roedel <[email protected]>
1 parent 1364679 commit eaca888

File tree

3 files changed

+82
-0
lines changed

3 files changed

+82
-0
lines changed

drivers/iommu/intel/iommu.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4169,6 +4169,8 @@ static struct iommu_domain *intel_iommu_domain_alloc(unsigned type)
41694169
return domain;
41704170
case IOMMU_DOMAIN_IDENTITY:
41714171
return &si_domain->domain;
4172+
case IOMMU_DOMAIN_SVA:
4173+
return intel_svm_domain_alloc();
41724174
default:
41734175
return NULL;
41744176
}
@@ -4712,6 +4714,28 @@ static void intel_iommu_iotlb_sync_map(struct iommu_domain *domain,
47124714
__mapping_notify_one(info->iommu, dmar_domain, pfn, pages);
47134715
}
47144716

4717+
static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid)
4718+
{
4719+
struct intel_iommu *iommu = device_to_iommu(dev, NULL, NULL);
4720+
struct iommu_domain *domain;
4721+
4722+
/* Domain type specific cleanup: */
4723+
domain = iommu_get_domain_for_dev_pasid(dev, pasid, 0);
4724+
if (domain) {
4725+
switch (domain->type) {
4726+
case IOMMU_DOMAIN_SVA:
4727+
intel_svm_remove_dev_pasid(dev, pasid);
4728+
break;
4729+
default:
4730+
/* should never reach here */
4731+
WARN_ON(1);
4732+
break;
4733+
}
4734+
}
4735+
4736+
intel_pasid_tear_down_entry(iommu, dev, pasid, false);
4737+
}
4738+
47154739
const struct iommu_ops intel_iommu_ops = {
47164740
.capable = intel_iommu_capable,
47174741
.domain_alloc = intel_iommu_domain_alloc,
@@ -4724,6 +4748,7 @@ const struct iommu_ops intel_iommu_ops = {
47244748
.dev_disable_feat = intel_iommu_dev_disable_feat,
47254749
.is_attach_deferred = intel_iommu_is_attach_deferred,
47264750
.def_domain_type = device_def_domain_type,
4751+
.remove_dev_pasid = intel_iommu_remove_dev_pasid,
47274752
.pgsize_bitmap = SZ_4K,
47284753
#ifdef CONFIG_INTEL_IOMMU_SVM
47294754
.sva_bind = intel_svm_bind,

drivers/iommu/intel/iommu.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,8 @@ void intel_svm_unbind(struct iommu_sva *handle);
753753
u32 intel_svm_get_pasid(struct iommu_sva *handle);
754754
int intel_svm_page_response(struct device *dev, struct iommu_fault_event *evt,
755755
struct iommu_page_response *msg);
756+
struct iommu_domain *intel_svm_domain_alloc(void);
757+
void intel_svm_remove_dev_pasid(struct device *dev, ioasid_t pasid);
756758

757759
struct intel_svm_dev {
758760
struct list_head list;
@@ -777,6 +779,14 @@ struct intel_svm {
777779
};
778780
#else
779781
static inline void intel_svm_check(struct intel_iommu *iommu) {}
782+
static inline struct iommu_domain *intel_svm_domain_alloc(void)
783+
{
784+
return NULL;
785+
}
786+
787+
static inline void intel_svm_remove_dev_pasid(struct device *dev, ioasid_t pasid)
788+
{
789+
}
780790
#endif
781791

782792
#ifdef CONFIG_INTEL_IOMMU_DEBUGFS

drivers/iommu/intel/svm.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -882,3 +882,50 @@ int intel_svm_page_response(struct device *dev,
882882
out:
883883
return ret;
884884
}
885+
886+
void intel_svm_remove_dev_pasid(struct device *dev, ioasid_t pasid)
887+
{
888+
mutex_lock(&pasid_mutex);
889+
intel_svm_unbind_mm(dev, pasid);
890+
mutex_unlock(&pasid_mutex);
891+
}
892+
893+
static int intel_svm_set_dev_pasid(struct iommu_domain *domain,
894+
struct device *dev, ioasid_t pasid)
895+
{
896+
struct device_domain_info *info = dev_iommu_priv_get(dev);
897+
struct intel_iommu *iommu = info->iommu;
898+
struct mm_struct *mm = domain->mm;
899+
struct iommu_sva *sva;
900+
int ret = 0;
901+
902+
mutex_lock(&pasid_mutex);
903+
sva = intel_svm_bind_mm(iommu, dev, mm);
904+
if (IS_ERR(sva))
905+
ret = PTR_ERR(sva);
906+
mutex_unlock(&pasid_mutex);
907+
908+
return ret;
909+
}
910+
911+
static void intel_svm_domain_free(struct iommu_domain *domain)
912+
{
913+
kfree(to_dmar_domain(domain));
914+
}
915+
916+
static const struct iommu_domain_ops intel_svm_domain_ops = {
917+
.set_dev_pasid = intel_svm_set_dev_pasid,
918+
.free = intel_svm_domain_free
919+
};
920+
921+
struct iommu_domain *intel_svm_domain_alloc(void)
922+
{
923+
struct dmar_domain *domain;
924+
925+
domain = kzalloc(sizeof(*domain), GFP_KERNEL);
926+
if (!domain)
927+
return NULL;
928+
domain->domain.ops = &intel_svm_domain_ops;
929+
930+
return &domain->domain;
931+
}

0 commit comments

Comments
 (0)