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...@linux.intel.com>
---
 drivers/iommu/intel/svm.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
index b16a4791acfb..18a9f05df407 100644
--- a/drivers/iommu/intel/svm.c
+++ b/drivers/iommu/intel/svm.c
@@ -299,6 +299,7 @@ int intel_svm_bind_gpasid(struct iommu_domain *domain, 
struct device *dev,
        struct dmar_domain *dmar_domain;
        struct device_domain_info *info;
        struct intel_svm *svm = NULL;
+       unsigned long iflags;
        int ret = 0;
 
        if (WARN_ON(!iommu) || !data)
@@ -400,12 +401,12 @@ int intel_svm_bind_gpasid(struct iommu_domain *domain, 
struct device *dev,
         * each bind of a new device even with an existing PASID, we need to
         * call the nested mode setup function here.
         */
-       spin_lock(&iommu->lock);
+       spin_lock_irqsave(&iommu->lock, iflags);
        ret = intel_pasid_setup_nested(iommu, dev,
                                       (pgd_t *)(uintptr_t)data->gpgd,
                                       data->hpasid, &data->vendor.vtd, 
dmar_domain,
                                       data->addr_width);
-       spin_unlock(&iommu->lock);
+       spin_unlock_irqrestore(&iommu->lock, iflags);
        if (ret) {
                dev_err_ratelimited(dev, "Failed to set up PASID %llu in nested 
mode, Err %d\n",
                                    data->hpasid, ret);
@@ -505,6 +506,7 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags,
        struct device_domain_info *info;
        struct intel_svm_dev *sdev;
        struct intel_svm *svm = NULL;
+       unsigned long iflags;
        int pasid_max;
        int ret;
 
@@ -624,14 +626,14 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags,
                        }
                }
 
-               spin_lock(&iommu->lock);
+               spin_lock_irqsave(&iommu->lock, iflags);
                ret = intel_pasid_setup_first_level(iommu, dev,
                                mm ? mm->pgd : init_mm.pgd,
                                svm->pasid, FLPT_DEFAULT_DID,
                                (mm ? 0 : PASID_FLAG_SUPERVISOR_MODE) |
                                (cpu_feature_enabled(X86_FEATURE_LA57) ?
                                 PASID_FLAG_FL5LP : 0));
-               spin_unlock(&iommu->lock);
+               spin_unlock_irqrestore(&iommu->lock, iflags);
                if (ret) {
                        if (mm)
                                mmu_notifier_unregister(&svm->notifier, mm);
@@ -651,14 +653,14 @@ intel_svm_bind_mm(struct device *dev, unsigned int flags,
                 * Binding a new device with existing PASID, need to setup
                 * the PASID entry.
                 */
-               spin_lock(&iommu->lock);
+               spin_lock_irqsave(&iommu->lock, iflags);
                ret = intel_pasid_setup_first_level(iommu, dev,
                                                mm ? mm->pgd : init_mm.pgd,
                                                svm->pasid, FLPT_DEFAULT_DID,
                                                (mm ? 0 : 
PASID_FLAG_SUPERVISOR_MODE) |
                                                
(cpu_feature_enabled(X86_FEATURE_LA57) ?
                                                PASID_FLAG_FL5LP : 0));
-               spin_unlock(&iommu->lock);
+               spin_unlock_irqrestore(&iommu->lock, iflags);
                if (ret) {
                        kfree(sdev);
                        goto out;
-- 
2.25.1

Reply via email to