Loading drivers/iommu/intel-iommu.c +49 −76 Original line number Diff line number Diff line Loading @@ -1678,90 +1678,64 @@ static struct dmar_domain *alloc_domain(int flags) return domain; } static int __iommu_attach_domain(struct dmar_domain *domain, /* Must be called with iommu->lock */ static int domain_attach_iommu(struct dmar_domain *domain, struct intel_iommu *iommu) { int num; unsigned long ndomains; unsigned long flags; int ret, num; num = domain->iommu_did[iommu->seq_id]; if (num) return num; assert_spin_locked(&iommu->lock); spin_lock_irqsave(&domain->iommu_lock, flags); domain->iommu_refcnt[iommu->seq_id] += 1; domain->iommu_count += 1; if (domain->iommu_refcnt[iommu->seq_id] == 1) { ndomains = cap_ndoms(iommu->cap); num = find_first_zero_bit(iommu->domain_ids, ndomains); if (num < ndomains) { set_bit(num, iommu->domain_ids); set_iommu_domain(iommu, num, domain); domain->iommu_did[iommu->seq_id] = num; } else { num = -ENOSPC; } if (num < 0) if (num >= ndomains) { pr_err("%s: No free domain ids\n", iommu->name); return num; } static int iommu_attach_domain(struct dmar_domain *domain, struct intel_iommu *iommu) { int num; unsigned long flags; spin_lock_irqsave(&iommu->lock, flags); num = __iommu_attach_domain(domain, iommu); spin_unlock_irqrestore(&iommu->lock, flags); return num; } static void iommu_detach_domain(struct dmar_domain *domain, struct intel_iommu *iommu) { unsigned long flags; int num; spin_lock_irqsave(&iommu->lock, flags); num = domain->iommu_did[iommu->seq_id]; if (num == 0) return; clear_bit(num, iommu->domain_ids); set_iommu_domain(iommu, num, NULL); spin_unlock_irqrestore(&iommu->lock, flags); domain->iommu_refcnt[iommu->seq_id] -= 1; domain->iommu_count -= 1; ret = -ENOSPC; goto out_unlock; } static void domain_attach_iommu(struct dmar_domain *domain, struct intel_iommu *iommu) { unsigned long flags; set_bit(num, iommu->domain_ids); set_iommu_domain(iommu, num, domain); spin_lock_irqsave(&domain->iommu_lock, flags); domain->iommu_refcnt[iommu->seq_id] += 1; domain->iommu_count += 1; if (domain->iommu_refcnt[iommu->seq_id] == 1) { domain->iommu_did[iommu->seq_id] = num; domain->nid = iommu->node; domain_update_iommu_cap(domain); } ret = 0; out_unlock: spin_unlock_irqrestore(&domain->iommu_lock, flags); return ret; } static int domain_detach_iommu(struct dmar_domain *domain, struct intel_iommu *iommu) { int num, count = INT_MAX; unsigned long flags; int count = INT_MAX; assert_spin_locked(&iommu->lock); spin_lock_irqsave(&domain->iommu_lock, flags); domain->iommu_refcnt[iommu->seq_id] -= 1; count = --domain->iommu_count; if (domain->iommu_refcnt[iommu->seq_id] == 0) { num = domain->iommu_did[iommu->seq_id]; clear_bit(num, iommu->domain_ids); set_iommu_domain(iommu, num, NULL); domain_update_iommu_cap(domain); domain->iommu_did[iommu->seq_id] = 0; } Loading Loading @@ -1886,7 +1860,6 @@ static int domain_init(struct dmar_domain *domain, struct intel_iommu *iommu, static void domain_exit(struct dmar_domain *domain) { struct page *freelist = NULL; int i; /* Domain 0 is reserved, so dont process it */ if (!domain) Loading @@ -1896,20 +1869,16 @@ static void domain_exit(struct dmar_domain *domain) if (!intel_iommu_strict) flush_unmaps_timeout(0); /* remove associated devices */ /* Remove associated devices and clear attached or cached domains */ rcu_read_lock(); domain_remove_dev_info(domain); rcu_read_unlock(); /* destroy iovas */ put_iova_domain(&domain->iovad); freelist = domain_unmap(domain, 0, DOMAIN_MAX_PFN(domain->gaw)); /* clear attached or cached domains */ rcu_read_lock(); for_each_domain_iommu(i, domain) iommu_detach_domain(domain, g_iommus[i]); rcu_read_unlock(); dma_free_pagelist(freelist); free_domain_mem(domain); Loading Loading @@ -2286,6 +2255,7 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu, struct dmar_domain *found = NULL; struct device_domain_info *info; unsigned long flags; int ret; info = alloc_devinfo_mem(); if (!info) Loading Loading @@ -2313,11 +2283,14 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu, return found; } if (iommu_attach_domain(domain, iommu) < 0) { spin_lock(&iommu->lock); ret = domain_attach_iommu(domain, iommu); spin_unlock(&iommu->lock); if (ret) { spin_unlock_irqrestore(&device_domain_lock, flags); return NULL; } domain_attach_iommu(domain, iommu); list_add(&info->link, &domain->devices); list_add(&info->global, &device_domain_list); Loading Loading @@ -4590,12 +4563,10 @@ static void dmar_remove_one_dev_info(struct dmar_domain *domain, iommu_disable_dev_iotlb(info); domain_context_clear(iommu, dev); free_devinfo_mem(info); domain_detach_iommu(domain, iommu); spin_lock_irqsave(&domain->iommu_lock, flags); if (!domain->iommu_refcnt[iommu->seq_id]) iommu_detach_domain(domain, iommu); spin_unlock_irqrestore(&domain->iommu_lock, flags); spin_lock_irqsave(&iommu->lock, flags); domain_detach_iommu(domain, iommu); spin_unlock_irqrestore(&iommu->lock, flags); } static int md_domain_init(struct dmar_domain *domain, int guest_width) Loading Loading @@ -4676,10 +4647,12 @@ static int intel_iommu_attach_device(struct iommu_domain *domain, old_domain = find_domain(dev); if (old_domain) { rcu_read_lock(); if (domain_type_is_vm_or_si(dmar_domain)) dmar_remove_one_dev_info(old_domain, dev); else domain_remove_dev_info(old_domain); rcu_read_unlock(); if (!domain_type_is_vm_or_si(old_domain) && list_empty(&old_domain->devices)) Loading Loading
drivers/iommu/intel-iommu.c +49 −76 Original line number Diff line number Diff line Loading @@ -1678,90 +1678,64 @@ static struct dmar_domain *alloc_domain(int flags) return domain; } static int __iommu_attach_domain(struct dmar_domain *domain, /* Must be called with iommu->lock */ static int domain_attach_iommu(struct dmar_domain *domain, struct intel_iommu *iommu) { int num; unsigned long ndomains; unsigned long flags; int ret, num; num = domain->iommu_did[iommu->seq_id]; if (num) return num; assert_spin_locked(&iommu->lock); spin_lock_irqsave(&domain->iommu_lock, flags); domain->iommu_refcnt[iommu->seq_id] += 1; domain->iommu_count += 1; if (domain->iommu_refcnt[iommu->seq_id] == 1) { ndomains = cap_ndoms(iommu->cap); num = find_first_zero_bit(iommu->domain_ids, ndomains); if (num < ndomains) { set_bit(num, iommu->domain_ids); set_iommu_domain(iommu, num, domain); domain->iommu_did[iommu->seq_id] = num; } else { num = -ENOSPC; } if (num < 0) if (num >= ndomains) { pr_err("%s: No free domain ids\n", iommu->name); return num; } static int iommu_attach_domain(struct dmar_domain *domain, struct intel_iommu *iommu) { int num; unsigned long flags; spin_lock_irqsave(&iommu->lock, flags); num = __iommu_attach_domain(domain, iommu); spin_unlock_irqrestore(&iommu->lock, flags); return num; } static void iommu_detach_domain(struct dmar_domain *domain, struct intel_iommu *iommu) { unsigned long flags; int num; spin_lock_irqsave(&iommu->lock, flags); num = domain->iommu_did[iommu->seq_id]; if (num == 0) return; clear_bit(num, iommu->domain_ids); set_iommu_domain(iommu, num, NULL); spin_unlock_irqrestore(&iommu->lock, flags); domain->iommu_refcnt[iommu->seq_id] -= 1; domain->iommu_count -= 1; ret = -ENOSPC; goto out_unlock; } static void domain_attach_iommu(struct dmar_domain *domain, struct intel_iommu *iommu) { unsigned long flags; set_bit(num, iommu->domain_ids); set_iommu_domain(iommu, num, domain); spin_lock_irqsave(&domain->iommu_lock, flags); domain->iommu_refcnt[iommu->seq_id] += 1; domain->iommu_count += 1; if (domain->iommu_refcnt[iommu->seq_id] == 1) { domain->iommu_did[iommu->seq_id] = num; domain->nid = iommu->node; domain_update_iommu_cap(domain); } ret = 0; out_unlock: spin_unlock_irqrestore(&domain->iommu_lock, flags); return ret; } static int domain_detach_iommu(struct dmar_domain *domain, struct intel_iommu *iommu) { int num, count = INT_MAX; unsigned long flags; int count = INT_MAX; assert_spin_locked(&iommu->lock); spin_lock_irqsave(&domain->iommu_lock, flags); domain->iommu_refcnt[iommu->seq_id] -= 1; count = --domain->iommu_count; if (domain->iommu_refcnt[iommu->seq_id] == 0) { num = domain->iommu_did[iommu->seq_id]; clear_bit(num, iommu->domain_ids); set_iommu_domain(iommu, num, NULL); domain_update_iommu_cap(domain); domain->iommu_did[iommu->seq_id] = 0; } Loading Loading @@ -1886,7 +1860,6 @@ static int domain_init(struct dmar_domain *domain, struct intel_iommu *iommu, static void domain_exit(struct dmar_domain *domain) { struct page *freelist = NULL; int i; /* Domain 0 is reserved, so dont process it */ if (!domain) Loading @@ -1896,20 +1869,16 @@ static void domain_exit(struct dmar_domain *domain) if (!intel_iommu_strict) flush_unmaps_timeout(0); /* remove associated devices */ /* Remove associated devices and clear attached or cached domains */ rcu_read_lock(); domain_remove_dev_info(domain); rcu_read_unlock(); /* destroy iovas */ put_iova_domain(&domain->iovad); freelist = domain_unmap(domain, 0, DOMAIN_MAX_PFN(domain->gaw)); /* clear attached or cached domains */ rcu_read_lock(); for_each_domain_iommu(i, domain) iommu_detach_domain(domain, g_iommus[i]); rcu_read_unlock(); dma_free_pagelist(freelist); free_domain_mem(domain); Loading Loading @@ -2286,6 +2255,7 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu, struct dmar_domain *found = NULL; struct device_domain_info *info; unsigned long flags; int ret; info = alloc_devinfo_mem(); if (!info) Loading Loading @@ -2313,11 +2283,14 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu, return found; } if (iommu_attach_domain(domain, iommu) < 0) { spin_lock(&iommu->lock); ret = domain_attach_iommu(domain, iommu); spin_unlock(&iommu->lock); if (ret) { spin_unlock_irqrestore(&device_domain_lock, flags); return NULL; } domain_attach_iommu(domain, iommu); list_add(&info->link, &domain->devices); list_add(&info->global, &device_domain_list); Loading Loading @@ -4590,12 +4563,10 @@ static void dmar_remove_one_dev_info(struct dmar_domain *domain, iommu_disable_dev_iotlb(info); domain_context_clear(iommu, dev); free_devinfo_mem(info); domain_detach_iommu(domain, iommu); spin_lock_irqsave(&domain->iommu_lock, flags); if (!domain->iommu_refcnt[iommu->seq_id]) iommu_detach_domain(domain, iommu); spin_unlock_irqrestore(&domain->iommu_lock, flags); spin_lock_irqsave(&iommu->lock, flags); domain_detach_iommu(domain, iommu); spin_unlock_irqrestore(&iommu->lock, flags); } static int md_domain_init(struct dmar_domain *domain, int guest_width) Loading Loading @@ -4676,10 +4647,12 @@ static int intel_iommu_attach_device(struct iommu_domain *domain, old_domain = find_domain(dev); if (old_domain) { rcu_read_lock(); if (domain_type_is_vm_or_si(dmar_domain)) dmar_remove_one_dev_info(old_domain, dev); else domain_remove_dev_info(old_domain); rcu_read_unlock(); if (!domain_type_is_vm_or_si(old_domain) && list_empty(&old_domain->devices)) Loading