Skip to content

Commit 420d42f

Browse files
LuBaoluwilldeacon
authored andcommitted
iommu/vt-d: Fix lockdep splat in sva bind()/unbind()
Lock(&iommu->lock) without disabling irq causes lockdep warnings. ======================================================== WARNING: possible irq lock inversion dependency detected 5.11.0-rc1+ #828 Not tainted -------------------------------------------------------- kworker/0:1H/120 just changed the state of lock: ffffffffad9ea1b8 (device_domain_lock){..-.}-{2:2}, at: iommu_flush_dev_iotlb.part.0+0x32/0x120 but this lock took another, SOFTIRQ-unsafe lock in the past: (&iommu->lock){+.+.}-{2:2} and interrupts could create inverse lock ordering between them. other info that might help us debug this: Possible interrupt unsafe locking scenario: CPU0 CPU1 ---- ---- lock(&iommu->lock); local_irq_disable(); lock(device_domain_lock); lock(&iommu->lock); <Interrupt> lock(device_domain_lock); *** DEADLOCK *** Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com> Link: https://lore.kernel.org/r/20201231005323.2178523-5-baolu.lu@linux.intel.com Signed-off-by: Will Deacon <will@kernel.org>
1 parent 4df7b22 commit 420d42f

1 file changed

Lines changed: 8 additions & 6 deletions

File tree

drivers/iommu/intel/svm.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ int intel_svm_bind_gpasid(struct iommu_domain *domain, struct device *dev,
281281
struct dmar_domain *dmar_domain;
282282
struct device_domain_info *info;
283283
struct intel_svm *svm = NULL;
284+
unsigned long iflags;
284285
int ret = 0;
285286

286287
if (WARN_ON(!iommu) || !data)
@@ -381,12 +382,12 @@ int intel_svm_bind_gpasid(struct iommu_domain *domain, struct device *dev,
381382
* each bind of a new device even with an existing PASID, we need to
382383
* call the nested mode setup function here.
383384
*/
384-
spin_lock(&iommu->lock);
385+
spin_lock_irqsave(&iommu->lock, iflags);
385386
ret = intel_pasid_setup_nested(iommu, dev,
386387
(pgd_t *)(uintptr_t)data->gpgd,
387388
data->hpasid, &data->vendor.vtd, dmar_domain,
388389
data->addr_width);
389-
spin_unlock(&iommu->lock);
390+
spin_unlock_irqrestore(&iommu->lock, iflags);
390391
if (ret) {
391392
dev_err_ratelimited(dev, "Failed to set up PASID %llu in nested mode, Err %d\n",
392393
data->hpasid, ret);
@@ -486,6 +487,7 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags,
486487
struct device_domain_info *info;
487488
struct intel_svm_dev *sdev;
488489
struct intel_svm *svm = NULL;
490+
unsigned long iflags;
489491
int pasid_max;
490492
int ret;
491493

@@ -605,14 +607,14 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags,
605607
}
606608
}
607609

608-
spin_lock(&iommu->lock);
610+
spin_lock_irqsave(&iommu->lock, iflags);
609611
ret = intel_pasid_setup_first_level(iommu, dev,
610612
mm ? mm->pgd : init_mm.pgd,
611613
svm->pasid, FLPT_DEFAULT_DID,
612614
(mm ? 0 : PASID_FLAG_SUPERVISOR_MODE) |
613615
(cpu_feature_enabled(X86_FEATURE_LA57) ?
614616
PASID_FLAG_FL5LP : 0));
615-
spin_unlock(&iommu->lock);
617+
spin_unlock_irqrestore(&iommu->lock, iflags);
616618
if (ret) {
617619
if (mm)
618620
mmu_notifier_unregister(&svm->notifier, mm);
@@ -632,14 +634,14 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags,
632634
* Binding a new device with existing PASID, need to setup
633635
* the PASID entry.
634636
*/
635-
spin_lock(&iommu->lock);
637+
spin_lock_irqsave(&iommu->lock, iflags);
636638
ret = intel_pasid_setup_first_level(iommu, dev,
637639
mm ? mm->pgd : init_mm.pgd,
638640
svm->pasid, FLPT_DEFAULT_DID,
639641
(mm ? 0 : PASID_FLAG_SUPERVISOR_MODE) |
640642
(cpu_feature_enabled(X86_FEATURE_LA57) ?
641643
PASID_FLAG_FL5LP : 0));
642-
spin_unlock(&iommu->lock);
644+
spin_unlock_irqrestore(&iommu->lock, iflags);
643645
if (ret) {
644646
kfree(sdev);
645647
goto out;

0 commit comments

Comments
 (0)