aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/intel-iommu.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/intel-iommu.c')
-rw-r--r--drivers/pci/intel-iommu.c40
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 */
3434static unsigned long vm_domid; 3434static unsigned long vm_domid;
3435 3435
3436static 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
3449static struct dmar_domain *iommu_alloc_vm_domain(void) 3436static 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}