diff options
Diffstat (limited to 'drivers/iommu/intel/svm.c')
| -rw-r--r-- | drivers/iommu/intel/svm.c | 145 | 
1 files changed, 57 insertions, 88 deletions
diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c index 03b25358946c..c76b66263467 100644 --- a/drivers/iommu/intel/svm.c +++ b/drivers/iommu/intel/svm.c @@ -24,7 +24,7 @@  #include "iommu.h"  #include "pasid.h"  #include "perf.h" -#include "../iommu-sva-lib.h" +#include "../iommu-sva.h"  #include "trace.h"  static irqreturn_t prq_event_thread(int irq, void *d); @@ -299,19 +299,9 @@ out:  	return 0;  } -static int intel_svm_alloc_pasid(struct device *dev, struct mm_struct *mm, -				 unsigned int flags) -{ -	ioasid_t max_pasid = dev_is_pci(dev) ? -			pci_max_pasids(to_pci_dev(dev)) : intel_pasid_max_id; - -	return iommu_sva_alloc_pasid(mm, PASID_MIN, max_pasid - 1); -} -  static struct iommu_sva *intel_svm_bind_mm(struct intel_iommu *iommu,  					   struct device *dev, -					   struct mm_struct *mm, -					   unsigned int flags) +					   struct mm_struct *mm)  {  	struct device_domain_info *info = dev_iommu_priv_get(dev);  	struct intel_svm_dev *sdev; @@ -327,22 +317,18 @@ static struct iommu_sva *intel_svm_bind_mm(struct intel_iommu *iommu,  		svm->pasid = mm->pasid;  		svm->mm = mm; -		svm->flags = flags;  		INIT_LIST_HEAD_RCU(&svm->devs); -		if (!(flags & SVM_FLAG_SUPERVISOR_MODE)) { -			svm->notifier.ops = &intel_mmuops; -			ret = mmu_notifier_register(&svm->notifier, mm); -			if (ret) { -				kfree(svm); -				return ERR_PTR(ret); -			} +		svm->notifier.ops = &intel_mmuops; +		ret = mmu_notifier_register(&svm->notifier, mm); +		if (ret) { +			kfree(svm); +			return ERR_PTR(ret);  		}  		ret = pasid_private_add(svm->pasid, svm);  		if (ret) { -			if (svm->notifier.ops) -				mmu_notifier_unregister(&svm->notifier, mm); +			mmu_notifier_unregister(&svm->notifier, mm);  			kfree(svm);  			return ERR_PTR(ret);  		} @@ -377,9 +363,7 @@ static struct iommu_sva *intel_svm_bind_mm(struct intel_iommu *iommu,  	}  	/* Setup the pasid table: */ -	sflags = (flags & SVM_FLAG_SUPERVISOR_MODE) ? -			PASID_FLAG_SUPERVISOR_MODE : 0; -	sflags |= cpu_feature_enabled(X86_FEATURE_LA57) ? PASID_FLAG_FL5LP : 0; +	sflags = cpu_feature_enabled(X86_FEATURE_LA57) ? PASID_FLAG_FL5LP : 0;  	ret = intel_pasid_setup_first_level(iommu, dev, mm->pgd, mm->pasid,  					    FLPT_DEFAULT_DID, sflags);  	if (ret) @@ -393,8 +377,7 @@ free_sdev:  	kfree(sdev);  free_svm:  	if (list_empty(&svm->devs)) { -		if (svm->notifier.ops) -			mmu_notifier_unregister(&svm->notifier, mm); +		mmu_notifier_unregister(&svm->notifier, mm);  		pasid_private_remove(mm->pasid);  		kfree(svm);  	} @@ -787,67 +770,6 @@ prq_advance:  	return IRQ_RETVAL(handled);  } -struct iommu_sva *intel_svm_bind(struct device *dev, struct mm_struct *mm, void *drvdata) -{ -	struct intel_iommu *iommu = device_to_iommu(dev, NULL, NULL); -	unsigned int flags = 0; -	struct iommu_sva *sva; -	int ret; - -	if (drvdata) -		flags = *(unsigned int *)drvdata; - -	if (flags & SVM_FLAG_SUPERVISOR_MODE) { -		if (!ecap_srs(iommu->ecap)) { -			dev_err(dev, "%s: Supervisor PASID not supported\n", -				iommu->name); -			return ERR_PTR(-EOPNOTSUPP); -		} - -		if (mm) { -			dev_err(dev, "%s: Supervisor PASID with user provided mm\n", -				iommu->name); -			return ERR_PTR(-EINVAL); -		} - -		mm = &init_mm; -	} - -	mutex_lock(&pasid_mutex); -	ret = intel_svm_alloc_pasid(dev, mm, flags); -	if (ret) { -		mutex_unlock(&pasid_mutex); -		return ERR_PTR(ret); -	} - -	sva = intel_svm_bind_mm(iommu, dev, mm, flags); -	mutex_unlock(&pasid_mutex); - -	return sva; -} - -void intel_svm_unbind(struct iommu_sva *sva) -{ -	struct intel_svm_dev *sdev = to_intel_svm_dev(sva); - -	mutex_lock(&pasid_mutex); -	intel_svm_unbind_mm(sdev->dev, sdev->pasid); -	mutex_unlock(&pasid_mutex); -} - -u32 intel_svm_get_pasid(struct iommu_sva *sva) -{ -	struct intel_svm_dev *sdev; -	u32 pasid; - -	mutex_lock(&pasid_mutex); -	sdev = to_intel_svm_dev(sva); -	pasid = sdev->pasid; -	mutex_unlock(&pasid_mutex); - -	return pasid; -} -  int intel_svm_page_response(struct device *dev,  			    struct iommu_fault_event *evt,  			    struct iommu_page_response *msg) @@ -918,3 +840,50 @@ int intel_svm_page_response(struct device *dev,  out:  	return ret;  } + +void intel_svm_remove_dev_pasid(struct device *dev, ioasid_t pasid) +{ +	mutex_lock(&pasid_mutex); +	intel_svm_unbind_mm(dev, pasid); +	mutex_unlock(&pasid_mutex); +} + +static int intel_svm_set_dev_pasid(struct iommu_domain *domain, +				   struct device *dev, ioasid_t pasid) +{ +	struct device_domain_info *info = dev_iommu_priv_get(dev); +	struct intel_iommu *iommu = info->iommu; +	struct mm_struct *mm = domain->mm; +	struct iommu_sva *sva; +	int ret = 0; + +	mutex_lock(&pasid_mutex); +	sva = intel_svm_bind_mm(iommu, dev, mm); +	if (IS_ERR(sva)) +		ret = PTR_ERR(sva); +	mutex_unlock(&pasid_mutex); + +	return ret; +} + +static void intel_svm_domain_free(struct iommu_domain *domain) +{ +	kfree(to_dmar_domain(domain)); +} + +static const struct iommu_domain_ops intel_svm_domain_ops = { +	.set_dev_pasid		= intel_svm_set_dev_pasid, +	.free			= intel_svm_domain_free +}; + +struct iommu_domain *intel_svm_domain_alloc(void) +{ +	struct dmar_domain *domain; + +	domain = kzalloc(sizeof(*domain), GFP_KERNEL); +	if (!domain) +		return NULL; +	domain->domain.ops = &intel_svm_domain_ops; + +	return &domain->domain; +}  | 
