aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLu Baolu <baolu.lu@linux.intel.com>2018-07-14 03:47:01 -0400
committerJoerg Roedel <jroedel@suse.de>2018-07-20 08:44:25 -0400
commit4774cc5245700b8f4414123908c3a7a1c78e5cbb (patch)
treee67765afbb4b2fbc16b3ac253bf637a962a394b9
parenta7fc93fed94b173e2f9815d50f4024161b0a39ae (diff)
iommu/vt-d: Apply per pci device pasid table in SVA
This patch applies the per pci device pasid table in the Shared Virtual Address (SVA) implementation. Cc: Ashok Raj <ashok.raj@intel.com> Cc: Jacob Pan <jacob.jun.pan@linux.intel.com> Cc: Kevin Tian <kevin.tian@intel.com> Cc: Liu Yi L <yi.l.liu@intel.com> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com> Reviewed-by: Liu Yi L <yi.l.liu@intel.com> Signed-off-by: Joerg Roedel <jroedel@suse.de>
-rw-r--r--drivers/iommu/intel-iommu.c29
-rw-r--r--drivers/iommu/intel-svm.c22
2 files changed, 19 insertions, 32 deletions
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 2d68e849a892..f1a3c5e5aff0 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -5178,22 +5178,16 @@ static void intel_iommu_put_resv_regions(struct device *dev,
5178 5178
5179#ifdef CONFIG_INTEL_IOMMU_SVM 5179#ifdef CONFIG_INTEL_IOMMU_SVM
5180#define MAX_NR_PASID_BITS (20) 5180#define MAX_NR_PASID_BITS (20)
5181static inline unsigned long intel_iommu_get_pts(struct intel_iommu *iommu) 5181static inline unsigned long intel_iommu_get_pts(struct device *dev)
5182{ 5182{
5183 /* 5183 int pts, max_pasid;
5184 * Convert ecap_pss to extend context entry pts encoding, also 5184
5185 * respect the soft pasid_max value set by the iommu. 5185 max_pasid = intel_pasid_get_dev_max_id(dev);
5186 * - number of PASID bits = ecap_pss + 1 5186 pts = find_first_bit((unsigned long *)&max_pasid, MAX_NR_PASID_BITS);
5187 * - number of PASID table entries = 2^(pts + 5) 5187 if (pts < 5)
5188 * Therefore, pts = ecap_pss - 4
5189 * e.g. KBL ecap_pss = 0x13, PASID has 20 bits, pts = 15
5190 */
5191 if (ecap_pss(iommu->ecap) < 5)
5192 return 0; 5188 return 0;
5193 5189
5194 /* pasid_max is encoded as actual number of entries not the bits */ 5190 return pts - 5;
5195 return find_first_bit((unsigned long *)&iommu->pasid_max,
5196 MAX_NR_PASID_BITS) - 5;
5197} 5191}
5198 5192
5199int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct intel_svm_dev *sdev) 5193int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct intel_svm_dev *sdev)
@@ -5229,8 +5223,8 @@ int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct intel_svm_dev *sd
5229 if (!(ctx_lo & CONTEXT_PASIDE)) { 5223 if (!(ctx_lo & CONTEXT_PASIDE)) {
5230 if (iommu->pasid_state_table) 5224 if (iommu->pasid_state_table)
5231 context[1].hi = (u64)virt_to_phys(iommu->pasid_state_table); 5225 context[1].hi = (u64)virt_to_phys(iommu->pasid_state_table);
5232 context[1].lo = (u64)virt_to_phys(iommu->pasid_table) | 5226 context[1].lo = (u64)virt_to_phys(info->pasid_table->table) |
5233 intel_iommu_get_pts(iommu); 5227 intel_iommu_get_pts(sdev->dev);
5234 5228
5235 wmb(); 5229 wmb();
5236 /* CONTEXT_TT_MULTI_LEVEL and CONTEXT_TT_DEV_IOTLB are both 5230 /* CONTEXT_TT_MULTI_LEVEL and CONTEXT_TT_DEV_IOTLB are both
@@ -5297,11 +5291,6 @@ struct intel_iommu *intel_svm_device_to_iommu(struct device *dev)
5297 return NULL; 5291 return NULL;
5298 } 5292 }
5299 5293
5300 if (!iommu->pasid_table) {
5301 dev_err(dev, "PASID not enabled on IOMMU; cannot enable SVM\n");
5302 return NULL;
5303 }
5304
5305 return iommu; 5294 return iommu;
5306} 5295}
5307#endif /* CONFIG_INTEL_IOMMU_SVM */ 5296#endif /* CONFIG_INTEL_IOMMU_SVM */
diff --git a/drivers/iommu/intel-svm.c b/drivers/iommu/intel-svm.c
index 9b5dc7262677..a253cdeabd61 100644
--- a/drivers/iommu/intel-svm.c
+++ b/drivers/iommu/intel-svm.c
@@ -274,11 +274,9 @@ static void intel_mm_release(struct mmu_notifier *mn, struct mm_struct *mm)
274 * page) so that we end up taking a fault that the hardware really 274 * page) so that we end up taking a fault that the hardware really
275 * *has* to handle gracefully without affecting other processes. 275 * *has* to handle gracefully without affecting other processes.
276 */ 276 */
277 svm->iommu->pasid_table[svm->pasid].val = 0;
278 wmb();
279
280 rcu_read_lock(); 277 rcu_read_lock();
281 list_for_each_entry_rcu(sdev, &svm->devs, list) { 278 list_for_each_entry_rcu(sdev, &svm->devs, list) {
279 intel_pasid_clear_entry(sdev->dev, svm->pasid);
282 intel_flush_pasid_dev(svm, sdev, svm->pasid); 280 intel_flush_pasid_dev(svm, sdev, svm->pasid);
283 intel_flush_svm_range_dev(svm, sdev, 0, -1, 0, !svm->mm); 281 intel_flush_svm_range_dev(svm, sdev, 0, -1, 0, !svm->mm);
284 } 282 }
@@ -299,6 +297,7 @@ static LIST_HEAD(global_svm_list);
299int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_ops *ops) 297int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_ops *ops)
300{ 298{
301 struct intel_iommu *iommu = intel_svm_device_to_iommu(dev); 299 struct intel_iommu *iommu = intel_svm_device_to_iommu(dev);
300 struct pasid_entry *entry;
302 struct intel_svm_dev *sdev; 301 struct intel_svm_dev *sdev;
303 struct intel_svm *svm = NULL; 302 struct intel_svm *svm = NULL;
304 struct mm_struct *mm = NULL; 303 struct mm_struct *mm = NULL;
@@ -306,7 +305,7 @@ int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_
306 int pasid_max; 305 int pasid_max;
307 int ret; 306 int ret;
308 307
309 if (!iommu || !iommu->pasid_table) 308 if (!iommu)
310 return -EINVAL; 309 return -EINVAL;
311 310
312 if (dev_is_pci(dev)) { 311 if (dev_is_pci(dev)) {
@@ -384,8 +383,8 @@ int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_
384 } 383 }
385 svm->iommu = iommu; 384 svm->iommu = iommu;
386 385
387 if (pasid_max > iommu->pasid_max) 386 if (pasid_max > intel_pasid_max_id)
388 pasid_max = iommu->pasid_max; 387 pasid_max = intel_pasid_max_id;
389 388
390 /* Do not use PASID 0 in caching mode (virtualised IOMMU) */ 389 /* Do not use PASID 0 in caching mode (virtualised IOMMU) */
391 ret = intel_pasid_alloc_id(svm, 390 ret = intel_pasid_alloc_id(svm,
@@ -418,7 +417,8 @@ int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_
418 if (cpu_feature_enabled(X86_FEATURE_LA57)) 417 if (cpu_feature_enabled(X86_FEATURE_LA57))
419 pasid_entry_val |= PASID_ENTRY_FLPM_5LP; 418 pasid_entry_val |= PASID_ENTRY_FLPM_5LP;
420 419
421 iommu->pasid_table[svm->pasid].val = pasid_entry_val; 420 entry = intel_pasid_get_entry(dev, svm->pasid);
421 entry->val = pasid_entry_val;
422 422
423 wmb(); 423 wmb();
424 424
@@ -453,7 +453,7 @@ int intel_svm_unbind_mm(struct device *dev, int pasid)
453 453
454 mutex_lock(&pasid_mutex); 454 mutex_lock(&pasid_mutex);
455 iommu = intel_svm_device_to_iommu(dev); 455 iommu = intel_svm_device_to_iommu(dev);
456 if (!iommu || !iommu->pasid_table) 456 if (!iommu)
457 goto out; 457 goto out;
458 458
459 svm = intel_pasid_lookup_id(pasid); 459 svm = intel_pasid_lookup_id(pasid);
@@ -476,11 +476,9 @@ int intel_svm_unbind_mm(struct device *dev, int pasid)
476 intel_flush_pasid_dev(svm, sdev, svm->pasid); 476 intel_flush_pasid_dev(svm, sdev, svm->pasid);
477 intel_flush_svm_range_dev(svm, sdev, 0, -1, 0, !svm->mm); 477 intel_flush_svm_range_dev(svm, sdev, 0, -1, 0, !svm->mm);
478 kfree_rcu(sdev, rcu); 478 kfree_rcu(sdev, rcu);
479 intel_pasid_clear_entry(dev, svm->pasid);
479 480
480 if (list_empty(&svm->devs)) { 481 if (list_empty(&svm->devs)) {
481 svm->iommu->pasid_table[svm->pasid].val = 0;
482 wmb();
483
484 intel_pasid_free_id(svm->pasid); 482 intel_pasid_free_id(svm->pasid);
485 if (svm->mm) 483 if (svm->mm)
486 mmu_notifier_unregister(&svm->notifier, svm->mm); 484 mmu_notifier_unregister(&svm->notifier, svm->mm);
@@ -513,7 +511,7 @@ int intel_svm_is_pasid_valid(struct device *dev, int pasid)
513 511
514 mutex_lock(&pasid_mutex); 512 mutex_lock(&pasid_mutex);
515 iommu = intel_svm_device_to_iommu(dev); 513 iommu = intel_svm_device_to_iommu(dev);
516 if (!iommu || !iommu->pasid_table) 514 if (!iommu)
517 goto out; 515 goto out;
518 516
519 svm = intel_pasid_lookup_id(pasid); 517 svm = intel_pasid_lookup_id(pasid);