diff options
| -rw-r--r-- | drivers/pci/intel-iommu.c | 40 |
1 files changed, 21 insertions, 19 deletions
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index da40f0789739..57be89e6f484 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c | |||
| @@ -3433,19 +3433,6 @@ static void vm_domain_remove_all_dev_info(struct dmar_domain *domain) | |||
| 3433 | /* domain id for virtual machine, it won't be set in context */ | 3433 | /* domain id for virtual machine, it won't be set in context */ |
| 3434 | static unsigned long vm_domid; | 3434 | static unsigned long vm_domid; |
| 3435 | 3435 | ||
| 3436 | static int vm_domain_min_agaw(struct dmar_domain *domain) | ||
| 3437 | { | ||
| 3438 | int i; | ||
| 3439 | int min_agaw = domain->agaw; | ||
| 3440 | |||
| 3441 | for_each_set_bit(i, &domain->iommu_bmp, g_num_of_iommus) { | ||
| 3442 | if (min_agaw > g_iommus[i]->agaw) | ||
| 3443 | min_agaw = g_iommus[i]->agaw; | ||
| 3444 | } | ||
| 3445 | |||
| 3446 | return min_agaw; | ||
| 3447 | } | ||
| 3448 | |||
| 3449 | static struct dmar_domain *iommu_alloc_vm_domain(void) | 3436 | static struct dmar_domain *iommu_alloc_vm_domain(void) |
| 3450 | { | 3437 | { |
| 3451 | struct dmar_domain *domain; | 3438 | struct dmar_domain *domain; |
| @@ -3574,7 +3561,6 @@ static int intel_iommu_attach_device(struct iommu_domain *domain, | |||
| 3574 | struct pci_dev *pdev = to_pci_dev(dev); | 3561 | struct pci_dev *pdev = to_pci_dev(dev); |
| 3575 | struct intel_iommu *iommu; | 3562 | struct intel_iommu *iommu; |
| 3576 | int addr_width; | 3563 | int addr_width; |
| 3577 | u64 end; | ||
| 3578 | 3564 | ||
| 3579 | /* normally pdev is not mapped */ | 3565 | /* normally pdev is not mapped */ |
| 3580 | if (unlikely(domain_context_mapped(pdev))) { | 3566 | if (unlikely(domain_context_mapped(pdev))) { |
| @@ -3597,14 +3583,30 @@ static int intel_iommu_attach_device(struct iommu_domain *domain, | |||
| 3597 | 3583 | ||
| 3598 | /* check if this iommu agaw is sufficient for max mapped address */ | 3584 | /* check if this iommu agaw is sufficient for max mapped address */ |
| 3599 | addr_width = agaw_to_width(iommu->agaw); | 3585 | addr_width = agaw_to_width(iommu->agaw); |
| 3600 | end = DOMAIN_MAX_ADDR(addr_width); | 3586 | if (addr_width > cap_mgaw(iommu->cap)) |
| 3601 | end = end & VTD_PAGE_MASK; | 3587 | addr_width = cap_mgaw(iommu->cap); |
| 3602 | if (end < dmar_domain->max_addr) { | 3588 | |
| 3603 | printk(KERN_ERR "%s: iommu agaw (%d) is not " | 3589 | if (dmar_domain->max_addr > (1LL << addr_width)) { |
| 3590 | printk(KERN_ERR "%s: iommu width (%d) is not " | ||
| 3604 | "sufficient for the mapped address (%llx)\n", | 3591 | "sufficient for the mapped address (%llx)\n", |
| 3605 | __func__, iommu->agaw, dmar_domain->max_addr); | 3592 | __func__, addr_width, dmar_domain->max_addr); |
| 3606 | return -EFAULT; | 3593 | return -EFAULT; |
| 3607 | } | 3594 | } |
| 3595 | dmar_domain->gaw = addr_width; | ||
| 3596 | |||
| 3597 | /* | ||
| 3598 | * Knock out extra levels of page tables if necessary | ||
| 3599 | */ | ||
| 3600 | while (iommu->agaw < dmar_domain->agaw) { | ||
| 3601 | struct dma_pte *pte; | ||
| 3602 | |||
| 3603 | pte = dmar_domain->pgd; | ||
| 3604 | if (dma_pte_present(pte)) { | ||
| 3605 | free_pgtable_page(dmar_domain->pgd); | ||
| 3606 | dmar_domain->pgd = (struct dma_pte *)dma_pte_addr(pte); | ||
| 3607 | } | ||
| 3608 | dmar_domain->agaw--; | ||
| 3609 | } | ||
| 3608 | 3610 | ||
| 3609 | return domain_add_dev_info(dmar_domain, pdev, CONTEXT_TT_MULTI_LEVEL); | 3611 | return domain_add_dev_info(dmar_domain, pdev, CONTEXT_TT_MULTI_LEVEL); |
| 3610 | } | 3612 | } |
