aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOmer Peleg <omer@cs.technion.ac.il>2016-04-20 04:33:57 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2016-04-20 15:07:22 -0400
commit2aac630429d986a43ac59525a4cff47a624dc58e (patch)
treeb007758a4aa3cf32fc5388037d3594ac169915ef
parent0824c5920b16fe11034f3b5d2d48456d282d83f9 (diff)
iommu/vt-d: change intel-iommu to use IOVA frame numbers
Make intel-iommu map/unmap/invalidate work with IOVA pfns instead of pointers to "struct iova". This avoids using the iova struct from the IOVA red-black tree and the resulting explicit find_iova() on unmap. This patch will allow us to cache IOVAs in the next patch, in order to avoid rbtree operations for the majority of map/unmap operations. Note: In eliminating the find_iova() operation, we have also eliminated the sanity check previously done in the unmap flow. Arguably, this was overhead that is better avoided in production code, but it could be brought back as a debug option for driver development. Signed-off-by: Omer Peleg <omer@cs.technion.ac.il> [mad@cs.technion.ac.il: rebased, fixed to not break iova api, and reworded the commit message] Signed-off-by: Adam Morrison <mad@cs.technion.ac.il> Reviewed-by: Shaohua Li <shli@fb.com> Reviewed-by: Ben Serebrin <serebrin@google.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
-rw-r--r--drivers/iommu/intel-iommu.c61
1 files changed, 29 insertions, 32 deletions
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index d100583e15e3..a8babc43e6d4 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -459,7 +459,7 @@ static LIST_HEAD(dmar_rmrr_units);
459static void flush_unmaps_timeout(unsigned long data); 459static void flush_unmaps_timeout(unsigned long data);
460 460
461struct deferred_flush_entry { 461struct deferred_flush_entry {
462 struct iova *iova; 462 unsigned long iova_pfn;
463 unsigned long nrpages; 463 unsigned long nrpages;
464 struct dmar_domain *domain; 464 struct dmar_domain *domain;
465 struct page *freelist; 465 struct page *freelist;
@@ -3353,7 +3353,7 @@ error:
3353} 3353}
3354 3354
3355/* This takes a number of _MM_ pages, not VTD pages */ 3355/* This takes a number of _MM_ pages, not VTD pages */
3356static struct iova *intel_alloc_iova(struct device *dev, 3356static unsigned long intel_alloc_iova(struct device *dev,
3357 struct dmar_domain *domain, 3357 struct dmar_domain *domain,
3358 unsigned long nrpages, uint64_t dma_mask) 3358 unsigned long nrpages, uint64_t dma_mask)
3359{ 3359{
@@ -3373,16 +3373,16 @@ static struct iova *intel_alloc_iova(struct device *dev,
3373 iova = alloc_iova(&domain->iovad, nrpages, 3373 iova = alloc_iova(&domain->iovad, nrpages,
3374 IOVA_PFN(DMA_BIT_MASK(32)), 1); 3374 IOVA_PFN(DMA_BIT_MASK(32)), 1);
3375 if (iova) 3375 if (iova)
3376 return iova; 3376 return iova->pfn_lo;
3377 } 3377 }
3378 iova = alloc_iova(&domain->iovad, nrpages, IOVA_PFN(dma_mask), 1); 3378 iova = alloc_iova(&domain->iovad, nrpages, IOVA_PFN(dma_mask), 1);
3379 if (unlikely(!iova)) { 3379 if (unlikely(!iova)) {
3380 pr_err("Allocating %ld-page iova for %s failed", 3380 pr_err("Allocating %ld-page iova for %s failed",
3381 nrpages, dev_name(dev)); 3381 nrpages, dev_name(dev));
3382 return NULL; 3382 return 0;
3383 } 3383 }
3384 3384
3385 return iova; 3385 return iova->pfn_lo;
3386} 3386}
3387 3387
3388static struct dmar_domain *__get_valid_domain_for_dev(struct device *dev) 3388static struct dmar_domain *__get_valid_domain_for_dev(struct device *dev)
@@ -3480,7 +3480,7 @@ static dma_addr_t __intel_map_single(struct device *dev, phys_addr_t paddr,
3480{ 3480{
3481 struct dmar_domain *domain; 3481 struct dmar_domain *domain;
3482 phys_addr_t start_paddr; 3482 phys_addr_t start_paddr;
3483 struct iova *iova; 3483 unsigned long iova_pfn;
3484 int prot = 0; 3484 int prot = 0;
3485 int ret; 3485 int ret;
3486 struct intel_iommu *iommu; 3486 struct intel_iommu *iommu;
@@ -3498,8 +3498,8 @@ static dma_addr_t __intel_map_single(struct device *dev, phys_addr_t paddr,
3498 iommu = domain_get_iommu(domain); 3498 iommu = domain_get_iommu(domain);
3499 size = aligned_nrpages(paddr, size); 3499 size = aligned_nrpages(paddr, size);
3500 3500
3501 iova = intel_alloc_iova(dev, domain, dma_to_mm_pfn(size), dma_mask); 3501 iova_pfn = intel_alloc_iova(dev, domain, dma_to_mm_pfn(size), dma_mask);
3502 if (!iova) 3502 if (!iova_pfn)
3503 goto error; 3503 goto error;
3504 3504
3505 /* 3505 /*
@@ -3517,7 +3517,7 @@ static dma_addr_t __intel_map_single(struct device *dev, phys_addr_t paddr,
3517 * might have two guest_addr mapping to the same host paddr, but this 3517 * might have two guest_addr mapping to the same host paddr, but this
3518 * is not a big problem 3518 * is not a big problem
3519 */ 3519 */
3520 ret = domain_pfn_mapping(domain, mm_to_dma_pfn(iova->pfn_lo), 3520 ret = domain_pfn_mapping(domain, mm_to_dma_pfn(iova_pfn),
3521 mm_to_dma_pfn(paddr_pfn), size, prot); 3521 mm_to_dma_pfn(paddr_pfn), size, prot);
3522 if (ret) 3522 if (ret)
3523 goto error; 3523 goto error;
@@ -3525,18 +3525,18 @@ static dma_addr_t __intel_map_single(struct device *dev, phys_addr_t paddr,
3525 /* it's a non-present to present mapping. Only flush if caching mode */ 3525 /* it's a non-present to present mapping. Only flush if caching mode */
3526 if (cap_caching_mode(iommu->cap)) 3526 if (cap_caching_mode(iommu->cap))
3527 iommu_flush_iotlb_psi(iommu, domain, 3527 iommu_flush_iotlb_psi(iommu, domain,
3528 mm_to_dma_pfn(iova->pfn_lo), 3528 mm_to_dma_pfn(iova_pfn),
3529 size, 0, 1); 3529 size, 0, 1);
3530 else 3530 else
3531 iommu_flush_write_buffer(iommu); 3531 iommu_flush_write_buffer(iommu);
3532 3532
3533 start_paddr = (phys_addr_t)iova->pfn_lo << PAGE_SHIFT; 3533 start_paddr = (phys_addr_t)iova_pfn << PAGE_SHIFT;
3534 start_paddr += paddr & ~PAGE_MASK; 3534 start_paddr += paddr & ~PAGE_MASK;
3535 return start_paddr; 3535 return start_paddr;
3536 3536
3537error: 3537error:
3538 if (iova) 3538 if (iova_pfn)
3539 __free_iova(&domain->iovad, iova); 3539 free_iova(&domain->iovad, iova_pfn);
3540 pr_err("Device %s request: %zx@%llx dir %d --- failed\n", 3540 pr_err("Device %s request: %zx@%llx dir %d --- failed\n",
3541 dev_name(dev), size, (unsigned long long)paddr, dir); 3541 dev_name(dev), size, (unsigned long long)paddr, dir);
3542 return 0; 3542 return 0;
@@ -3576,7 +3576,7 @@ static void flush_unmaps(struct deferred_flush_data *flush_data)
3576 unsigned long mask; 3576 unsigned long mask;
3577 struct deferred_flush_entry *entry = 3577 struct deferred_flush_entry *entry =
3578 &flush_table->entries[j]; 3578 &flush_table->entries[j];
3579 struct iova *iova = entry->iova; 3579 unsigned long iova_pfn = entry->iova_pfn;
3580 unsigned long nrpages = entry->nrpages; 3580 unsigned long nrpages = entry->nrpages;
3581 struct dmar_domain *domain = entry->domain; 3581 struct dmar_domain *domain = entry->domain;
3582 struct page *freelist = entry->freelist; 3582 struct page *freelist = entry->freelist;
@@ -3584,14 +3584,14 @@ static void flush_unmaps(struct deferred_flush_data *flush_data)
3584 /* On real hardware multiple invalidations are expensive */ 3584 /* On real hardware multiple invalidations are expensive */
3585 if (cap_caching_mode(iommu->cap)) 3585 if (cap_caching_mode(iommu->cap))
3586 iommu_flush_iotlb_psi(iommu, domain, 3586 iommu_flush_iotlb_psi(iommu, domain,
3587 mm_to_dma_pfn(iova->pfn_lo), 3587 mm_to_dma_pfn(iova_pfn),
3588 nrpages, !freelist, 0); 3588 nrpages, !freelist, 0);
3589 else { 3589 else {
3590 mask = ilog2(nrpages); 3590 mask = ilog2(nrpages);
3591 iommu_flush_dev_iotlb(domain, 3591 iommu_flush_dev_iotlb(domain,
3592 (uint64_t)iova->pfn_lo << PAGE_SHIFT, mask); 3592 (uint64_t)iova_pfn << PAGE_SHIFT, mask);
3593 } 3593 }
3594 __free_iova(&domain->iovad, iova); 3594 free_iova(&domain->iovad, iova_pfn);
3595 if (freelist) 3595 if (freelist)
3596 dma_free_pagelist(freelist); 3596 dma_free_pagelist(freelist);
3597 } 3597 }
@@ -3611,7 +3611,7 @@ static void flush_unmaps_timeout(unsigned long cpuid)
3611 spin_unlock_irqrestore(&flush_data->lock, flags); 3611 spin_unlock_irqrestore(&flush_data->lock, flags);
3612} 3612}
3613 3613
3614static void add_unmap(struct dmar_domain *dom, struct iova *iova, 3614static void add_unmap(struct dmar_domain *dom, unsigned long iova_pfn,
3615 unsigned long nrpages, struct page *freelist) 3615 unsigned long nrpages, struct page *freelist)
3616{ 3616{
3617 unsigned long flags; 3617 unsigned long flags;
@@ -3645,7 +3645,7 @@ static void add_unmap(struct dmar_domain *dom, struct iova *iova,
3645 3645
3646 entry = &flush_data->tables[iommu_id].entries[entry_id]; 3646 entry = &flush_data->tables[iommu_id].entries[entry_id];
3647 entry->domain = dom; 3647 entry->domain = dom;
3648 entry->iova = iova; 3648 entry->iova_pfn = iova_pfn;
3649 entry->nrpages = nrpages; 3649 entry->nrpages = nrpages;
3650 entry->freelist = freelist; 3650 entry->freelist = freelist;
3651 3651
@@ -3664,7 +3664,7 @@ static void intel_unmap(struct device *dev, dma_addr_t dev_addr, size_t size)
3664 struct dmar_domain *domain; 3664 struct dmar_domain *domain;
3665 unsigned long start_pfn, last_pfn; 3665 unsigned long start_pfn, last_pfn;
3666 unsigned long nrpages; 3666 unsigned long nrpages;
3667 struct iova *iova; 3667 unsigned long iova_pfn;
3668 struct intel_iommu *iommu; 3668 struct intel_iommu *iommu;
3669 struct page *freelist; 3669 struct page *freelist;
3670 3670
@@ -3676,13 +3676,10 @@ static void intel_unmap(struct device *dev, dma_addr_t dev_addr, size_t size)
3676 3676
3677 iommu = domain_get_iommu(domain); 3677 iommu = domain_get_iommu(domain);
3678 3678
3679 iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr)); 3679 iova_pfn = IOVA_PFN(dev_addr);
3680 if (WARN_ONCE(!iova, "Driver unmaps unmatched page at PFN %llx\n",
3681 (unsigned long long)dev_addr))
3682 return;
3683 3680
3684 nrpages = aligned_nrpages(dev_addr, size); 3681 nrpages = aligned_nrpages(dev_addr, size);
3685 start_pfn = mm_to_dma_pfn(iova->pfn_lo); 3682 start_pfn = mm_to_dma_pfn(iova_pfn);
3686 last_pfn = start_pfn + nrpages - 1; 3683 last_pfn = start_pfn + nrpages - 1;
3687 3684
3688 pr_debug("Device %s unmapping: pfn %lx-%lx\n", 3685 pr_debug("Device %s unmapping: pfn %lx-%lx\n",
@@ -3694,10 +3691,10 @@ static void intel_unmap(struct device *dev, dma_addr_t dev_addr, size_t size)
3694 iommu_flush_iotlb_psi(iommu, domain, start_pfn, 3691 iommu_flush_iotlb_psi(iommu, domain, start_pfn,
3695 nrpages, !freelist, 0); 3692 nrpages, !freelist, 0);
3696 /* free iova */ 3693 /* free iova */
3697 __free_iova(&domain->iovad, iova); 3694 free_iova(&domain->iovad, iova_pfn);
3698 dma_free_pagelist(freelist); 3695 dma_free_pagelist(freelist);
3699 } else { 3696 } else {
3700 add_unmap(domain, iova, nrpages, freelist); 3697 add_unmap(domain, iova_pfn, nrpages, freelist);
3701 /* 3698 /*
3702 * queue up the release of the unmap to save the 1/6th of the 3699 * queue up the release of the unmap to save the 1/6th of the
3703 * cpu used up by the iotlb flush operation... 3700 * cpu used up by the iotlb flush operation...
@@ -3810,7 +3807,7 @@ static int intel_map_sg(struct device *dev, struct scatterlist *sglist, int nele
3810 struct dmar_domain *domain; 3807 struct dmar_domain *domain;
3811 size_t size = 0; 3808 size_t size = 0;
3812 int prot = 0; 3809 int prot = 0;
3813 struct iova *iova = NULL; 3810 unsigned long iova_pfn;
3814 int ret; 3811 int ret;
3815 struct scatterlist *sg; 3812 struct scatterlist *sg;
3816 unsigned long start_vpfn; 3813 unsigned long start_vpfn;
@@ -3829,9 +3826,9 @@ static int intel_map_sg(struct device *dev, struct scatterlist *sglist, int nele
3829 for_each_sg(sglist, sg, nelems, i) 3826 for_each_sg(sglist, sg, nelems, i)
3830 size += aligned_nrpages(sg->offset, sg->length); 3827 size += aligned_nrpages(sg->offset, sg->length);
3831 3828
3832 iova = intel_alloc_iova(dev, domain, dma_to_mm_pfn(size), 3829 iova_pfn = intel_alloc_iova(dev, domain, dma_to_mm_pfn(size),
3833 *dev->dma_mask); 3830 *dev->dma_mask);
3834 if (!iova) { 3831 if (!iova_pfn) {
3835 sglist->dma_length = 0; 3832 sglist->dma_length = 0;
3836 return 0; 3833 return 0;
3837 } 3834 }
@@ -3846,13 +3843,13 @@ static int intel_map_sg(struct device *dev, struct scatterlist *sglist, int nele
3846 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) 3843 if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
3847 prot |= DMA_PTE_WRITE; 3844 prot |= DMA_PTE_WRITE;
3848 3845
3849 start_vpfn = mm_to_dma_pfn(iova->pfn_lo); 3846 start_vpfn = mm_to_dma_pfn(iova_pfn);
3850 3847
3851 ret = domain_sg_mapping(domain, start_vpfn, sglist, size, prot); 3848 ret = domain_sg_mapping(domain, start_vpfn, sglist, size, prot);
3852 if (unlikely(ret)) { 3849 if (unlikely(ret)) {
3853 dma_pte_free_pagetable(domain, start_vpfn, 3850 dma_pte_free_pagetable(domain, start_vpfn,
3854 start_vpfn + size - 1); 3851 start_vpfn + size - 1);
3855 __free_iova(&domain->iovad, iova); 3852 free_iova(&domain->iovad, iova_pfn);
3856 return 0; 3853 return 0;
3857 } 3854 }
3858 3855