diff options
author | Jiang Liu <jiang.liu@linux.intel.com> | 2014-07-11 14:19:29 +0800 |
---|---|---|
committer | Joerg Roedel <jroedel@suse.de> | 2014-07-23 16:04:47 +0200 |
commit | 44bde61428f7719c54a2074443edddf0e827296c (patch) | |
tree | 0182bf0ceebd23310e8b95dba23218d10be63264 /drivers/iommu | |
parent | fb170fb4c548c6d9fe9f71db946e216abb5c6641 (diff) |
iommu/vt-d: Allocate dynamic domain id for virtual domains only
Check the same domain id is allocated for si_domain on each IOMMU,
otherwise the IOTLB flush for si_domain will fail.
Now the rules to allocate and manage domain id are:
1) For normal and static identity domains, domain id is allocated
when creating domain structure. And this id will be written into
context entry.
2) For virtual machine domain, a virtual id is allocated when creating
domain. And when binding virtual machine domain to an iommu, a real
domain id is allocated on demand and this domain id will be written
into context entry. So domain->id for virtual machine domain may be
different from the domain id written into context entry(used by
hardware).
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
Diffstat (limited to 'drivers/iommu')
-rw-r--r-- | drivers/iommu/intel-iommu.c | 47 |
1 files changed, 26 insertions, 21 deletions
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index eae9b0d8bc60..968e3d32e305 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -1549,15 +1549,27 @@ static int iommu_attach_domain(struct dmar_domain *domain, spin_lock_irqsave(&iommu->lock, flags); num = __iommu_attach_domain(domain, iommu); + spin_unlock_irqrestore(&iommu->lock, flags); if (num < 0) pr_err("IOMMU: no free domain ids\n"); - else - domain->id = num; - spin_unlock_irqrestore(&iommu->lock, flags); return num; } +static int iommu_attach_vm_domain(struct dmar_domain *domain, + struct intel_iommu *iommu) +{ + int num; + unsigned long ndomains; + + ndomains = cap_ndoms(iommu->cap); + for_each_set_bit(num, iommu->domain_ids, ndomains) + if (iommu->domains[num] == domain) + return num; + + return __iommu_attach_domain(domain, iommu); +} + static void iommu_detach_domain(struct dmar_domain *domain, struct intel_iommu *iommu) { @@ -1764,8 +1776,6 @@ static int domain_context_mapping_one(struct dmar_domain *domain, struct context_entry *context; unsigned long flags; struct dma_pte *pgd; - unsigned long num; - unsigned long ndomains; int id; int agaw; struct device_domain_info *info = NULL; @@ -1790,20 +1800,8 @@ static int domain_context_mapping_one(struct dmar_domain *domain, pgd = domain->pgd; if (domain_type_is_vm_or_si(domain)) { - int found = 0; - - /* find an available domain id for this device in iommu */ - ndomains = cap_ndoms(iommu->cap); - for_each_set_bit(num, iommu->domain_ids, ndomains) { - if (iommu->domains[num] == domain) { - id = num; - found = 1; - break; - } - } - - if (found == 0) { - id = __iommu_attach_domain(domain, iommu); + if (domain_type_is_vm(domain)) { + id = iommu_attach_vm_domain(domain, iommu); if (id < 0) { spin_unlock_irqrestore(&iommu->lock, flags); pr_err("IOMMU: no free domain ids\n"); @@ -2257,8 +2255,8 @@ static struct dmar_domain *get_domain_for_dev(struct device *dev, int gaw) domain = alloc_domain(0); if (!domain) return NULL; - - if (iommu_attach_domain(domain, iommu) < 0) { + domain->id = iommu_attach_domain(domain, iommu); + if (domain->id < 0) { free_domain_mem(domain); return NULL; } @@ -2428,6 +2426,7 @@ static int __init si_domain_init(int hw) struct dmar_drhd_unit *drhd; struct intel_iommu *iommu; int nid, ret = 0; + bool first = true; si_domain = alloc_domain(DOMAIN_FLAG_STATIC_IDENTITY); if (!si_domain) @@ -2438,6 +2437,12 @@ static int __init si_domain_init(int hw) if (ret < 0) { domain_exit(si_domain); return -EFAULT; + } else if (first) { + si_domain->id = ret; + first = false; + } else if (si_domain->id != ret) { + domain_exit(si_domain); + return -EFAULT; } domain_attach_iommu(si_domain, iommu); } |