diff options
author | Jiang Liu <jiang.liu@linux.intel.com> | 2014-07-11 02:19:29 -0400 |
---|---|---|
committer | Joerg Roedel <jroedel@suse.de> | 2014-07-23 10:04:47 -0400 |
commit | 44bde61428f7719c54a2074443edddf0e827296c (patch) | |
tree | 0182bf0ceebd23310e8b95dba23218d10be63264 | |
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>
-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, | |||
1549 | 1549 | ||
1550 | spin_lock_irqsave(&iommu->lock, flags); | 1550 | spin_lock_irqsave(&iommu->lock, flags); |
1551 | num = __iommu_attach_domain(domain, iommu); | 1551 | num = __iommu_attach_domain(domain, iommu); |
1552 | spin_unlock_irqrestore(&iommu->lock, flags); | ||
1552 | if (num < 0) | 1553 | if (num < 0) |
1553 | pr_err("IOMMU: no free domain ids\n"); | 1554 | pr_err("IOMMU: no free domain ids\n"); |
1554 | else | ||
1555 | domain->id = num; | ||
1556 | spin_unlock_irqrestore(&iommu->lock, flags); | ||
1557 | 1555 | ||
1558 | return num; | 1556 | return num; |
1559 | } | 1557 | } |
1560 | 1558 | ||
1559 | static int iommu_attach_vm_domain(struct dmar_domain *domain, | ||
1560 | struct intel_iommu *iommu) | ||
1561 | { | ||
1562 | int num; | ||
1563 | unsigned long ndomains; | ||
1564 | |||
1565 | ndomains = cap_ndoms(iommu->cap); | ||
1566 | for_each_set_bit(num, iommu->domain_ids, ndomains) | ||
1567 | if (iommu->domains[num] == domain) | ||
1568 | return num; | ||
1569 | |||
1570 | return __iommu_attach_domain(domain, iommu); | ||
1571 | } | ||
1572 | |||
1561 | static void iommu_detach_domain(struct dmar_domain *domain, | 1573 | static void iommu_detach_domain(struct dmar_domain *domain, |
1562 | struct intel_iommu *iommu) | 1574 | struct intel_iommu *iommu) |
1563 | { | 1575 | { |
@@ -1764,8 +1776,6 @@ static int domain_context_mapping_one(struct dmar_domain *domain, | |||
1764 | struct context_entry *context; | 1776 | struct context_entry *context; |
1765 | unsigned long flags; | 1777 | unsigned long flags; |
1766 | struct dma_pte *pgd; | 1778 | struct dma_pte *pgd; |
1767 | unsigned long num; | ||
1768 | unsigned long ndomains; | ||
1769 | int id; | 1779 | int id; |
1770 | int agaw; | 1780 | int agaw; |
1771 | struct device_domain_info *info = NULL; | 1781 | struct device_domain_info *info = NULL; |
@@ -1790,20 +1800,8 @@ static int domain_context_mapping_one(struct dmar_domain *domain, | |||
1790 | pgd = domain->pgd; | 1800 | pgd = domain->pgd; |
1791 | 1801 | ||
1792 | if (domain_type_is_vm_or_si(domain)) { | 1802 | if (domain_type_is_vm_or_si(domain)) { |
1793 | int found = 0; | 1803 | if (domain_type_is_vm(domain)) { |
1794 | 1804 | id = iommu_attach_vm_domain(domain, iommu); | |
1795 | /* find an available domain id for this device in iommu */ | ||
1796 | ndomains = cap_ndoms(iommu->cap); | ||
1797 | for_each_set_bit(num, iommu->domain_ids, ndomains) { | ||
1798 | if (iommu->domains[num] == domain) { | ||
1799 | id = num; | ||
1800 | found = 1; | ||
1801 | break; | ||
1802 | } | ||
1803 | } | ||
1804 | |||
1805 | if (found == 0) { | ||
1806 | id = __iommu_attach_domain(domain, iommu); | ||
1807 | if (id < 0) { | 1805 | if (id < 0) { |
1808 | spin_unlock_irqrestore(&iommu->lock, flags); | 1806 | spin_unlock_irqrestore(&iommu->lock, flags); |
1809 | pr_err("IOMMU: no free domain ids\n"); | 1807 | 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) | |||
2257 | domain = alloc_domain(0); | 2255 | domain = alloc_domain(0); |
2258 | if (!domain) | 2256 | if (!domain) |
2259 | return NULL; | 2257 | return NULL; |
2260 | 2258 | domain->id = iommu_attach_domain(domain, iommu); | |
2261 | if (iommu_attach_domain(domain, iommu) < 0) { | 2259 | if (domain->id < 0) { |
2262 | free_domain_mem(domain); | 2260 | free_domain_mem(domain); |
2263 | return NULL; | 2261 | return NULL; |
2264 | } | 2262 | } |
@@ -2428,6 +2426,7 @@ static int __init si_domain_init(int hw) | |||
2428 | struct dmar_drhd_unit *drhd; | 2426 | struct dmar_drhd_unit *drhd; |
2429 | struct intel_iommu *iommu; | 2427 | struct intel_iommu *iommu; |
2430 | int nid, ret = 0; | 2428 | int nid, ret = 0; |
2429 | bool first = true; | ||
2431 | 2430 | ||
2432 | si_domain = alloc_domain(DOMAIN_FLAG_STATIC_IDENTITY); | 2431 | si_domain = alloc_domain(DOMAIN_FLAG_STATIC_IDENTITY); |
2433 | if (!si_domain) | 2432 | if (!si_domain) |
@@ -2438,6 +2437,12 @@ static int __init si_domain_init(int hw) | |||
2438 | if (ret < 0) { | 2437 | if (ret < 0) { |
2439 | domain_exit(si_domain); | 2438 | domain_exit(si_domain); |
2440 | return -EFAULT; | 2439 | return -EFAULT; |
2440 | } else if (first) { | ||
2441 | si_domain->id = ret; | ||
2442 | first = false; | ||
2443 | } else if (si_domain->id != ret) { | ||
2444 | domain_exit(si_domain); | ||
2445 | return -EFAULT; | ||
2441 | } | 2446 | } |
2442 | domain_attach_iommu(si_domain, iommu); | 2447 | domain_attach_iommu(si_domain, iommu); |
2443 | } | 2448 | } |