diff options
-rw-r--r-- | drivers/pci/intel-iommu.c | 54 |
1 files changed, 19 insertions, 35 deletions
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index a490b39ca3d5..bc49b121c667 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c | |||
@@ -1674,17 +1674,6 @@ static int domain_pfn_mapping(struct dmar_domain *domain, unsigned long iov_pfn, | |||
1674 | return 0; | 1674 | return 0; |
1675 | } | 1675 | } |
1676 | 1676 | ||
1677 | static int domain_page_mapping(struct dmar_domain *domain, dma_addr_t iova, | ||
1678 | u64 hpa, size_t size, int prot) | ||
1679 | { | ||
1680 | unsigned long first_pfn = hpa >> VTD_PAGE_SHIFT; | ||
1681 | unsigned long last_pfn = (hpa + size - 1) >> VTD_PAGE_SHIFT; | ||
1682 | |||
1683 | return domain_pfn_mapping(domain, iova >> VTD_PAGE_SHIFT, first_pfn, | ||
1684 | last_pfn - first_pfn + 1, prot); | ||
1685 | |||
1686 | } | ||
1687 | |||
1688 | static void iommu_detach_dev(struct intel_iommu *iommu, u8 bus, u8 devfn) | 1677 | static void iommu_detach_dev(struct intel_iommu *iommu, u8 bus, u8 devfn) |
1689 | { | 1678 | { |
1690 | if (!iommu) | 1679 | if (!iommu) |
@@ -2745,17 +2734,16 @@ static int intel_nontranslate_map_sg(struct device *hddev, | |||
2745 | static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems, | 2734 | static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems, |
2746 | enum dma_data_direction dir, struct dma_attrs *attrs) | 2735 | enum dma_data_direction dir, struct dma_attrs *attrs) |
2747 | { | 2736 | { |
2748 | phys_addr_t addr; | ||
2749 | int i; | 2737 | int i; |
2750 | struct pci_dev *pdev = to_pci_dev(hwdev); | 2738 | struct pci_dev *pdev = to_pci_dev(hwdev); |
2751 | struct dmar_domain *domain; | 2739 | struct dmar_domain *domain; |
2752 | size_t size = 0; | 2740 | size_t size = 0; |
2753 | int prot = 0; | 2741 | int prot = 0; |
2754 | size_t offset = 0; | 2742 | size_t offset_pfn = 0; |
2755 | struct iova *iova = NULL; | 2743 | struct iova *iova = NULL; |
2756 | int ret; | 2744 | int ret; |
2757 | struct scatterlist *sg; | 2745 | struct scatterlist *sg; |
2758 | unsigned long start_addr; | 2746 | unsigned long start_vpfn; |
2759 | struct intel_iommu *iommu; | 2747 | struct intel_iommu *iommu; |
2760 | 2748 | ||
2761 | BUG_ON(dir == DMA_NONE); | 2749 | BUG_ON(dir == DMA_NONE); |
@@ -2768,10 +2756,8 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int ne | |||
2768 | 2756 | ||
2769 | iommu = domain_get_iommu(domain); | 2757 | iommu = domain_get_iommu(domain); |
2770 | 2758 | ||
2771 | for_each_sg(sglist, sg, nelems, i) { | 2759 | for_each_sg(sglist, sg, nelems, i) |
2772 | addr = page_to_phys(sg_page(sg)) + sg->offset; | 2760 | size += aligned_size(sg->offset, sg->length); |
2773 | size += aligned_size((u64)addr, sg->length); | ||
2774 | } | ||
2775 | 2761 | ||
2776 | iova = __intel_alloc_iova(hwdev, domain, size, pdev->dma_mask); | 2762 | iova = __intel_alloc_iova(hwdev, domain, size, pdev->dma_mask); |
2777 | if (!iova) { | 2763 | if (!iova) { |
@@ -2789,36 +2775,34 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int ne | |||
2789 | if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) | 2775 | if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) |
2790 | prot |= DMA_PTE_WRITE; | 2776 | prot |= DMA_PTE_WRITE; |
2791 | 2777 | ||
2792 | start_addr = iova->pfn_lo << PAGE_SHIFT; | 2778 | start_vpfn = mm_to_dma_pfn(iova->pfn_lo); |
2793 | offset = 0; | 2779 | offset_pfn = 0; |
2794 | for_each_sg(sglist, sg, nelems, i) { | 2780 | for_each_sg(sglist, sg, nelems, i) { |
2795 | addr = page_to_phys(sg_page(sg)) + sg->offset; | 2781 | int nr_pages = aligned_size(sg->offset, sg->length) >> VTD_PAGE_SHIFT; |
2796 | size = aligned_size((u64)addr, sg->length); | 2782 | ret = domain_pfn_mapping(domain, start_vpfn + offset_pfn, |
2797 | ret = domain_page_mapping(domain, start_addr + offset, | 2783 | page_to_dma_pfn(sg_page(sg)), |
2798 | ((u64)addr) & PHYSICAL_PAGE_MASK, | 2784 | nr_pages, prot); |
2799 | size, prot); | ||
2800 | if (ret) { | 2785 | if (ret) { |
2801 | /* clear the page */ | 2786 | /* clear the page */ |
2802 | dma_pte_clear_range(domain, | 2787 | dma_pte_clear_range(domain, start_vpfn, |
2803 | start_addr >> VTD_PAGE_SHIFT, | 2788 | start_vpfn + offset_pfn); |
2804 | (start_addr + offset - 1) >> VTD_PAGE_SHIFT); | ||
2805 | /* free page tables */ | 2789 | /* free page tables */ |
2806 | dma_pte_free_pagetable(domain, start_addr >> VTD_PAGE_SHIFT, | 2790 | dma_pte_free_pagetable(domain, start_vpfn, |
2807 | (start_addr + offset - 1) >> VTD_PAGE_SHIFT); | 2791 | start_vpfn + offset_pfn); |
2808 | /* free iova */ | 2792 | /* free iova */ |
2809 | __free_iova(&domain->iovad, iova); | 2793 | __free_iova(&domain->iovad, iova); |
2810 | return 0; | 2794 | return 0; |
2811 | } | 2795 | } |
2812 | sg->dma_address = start_addr + offset + | 2796 | sg->dma_address = ((dma_addr_t)(start_vpfn + offset_pfn) |
2813 | ((u64)addr & (~PAGE_MASK)); | 2797 | << VTD_PAGE_SHIFT) + sg->offset; |
2814 | sg->dma_length = sg->length; | 2798 | sg->dma_length = sg->length; |
2815 | offset += size; | 2799 | offset_pfn += nr_pages; |
2816 | } | 2800 | } |
2817 | 2801 | ||
2818 | /* it's a non-present to present mapping. Only flush if caching mode */ | 2802 | /* it's a non-present to present mapping. Only flush if caching mode */ |
2819 | if (cap_caching_mode(iommu->cap)) | 2803 | if (cap_caching_mode(iommu->cap)) |
2820 | iommu_flush_iotlb_psi(iommu, 0, start_addr, | 2804 | iommu_flush_iotlb_psi(iommu, 0, start_vpfn << VTD_PAGE_SHIFT, |
2821 | offset >> VTD_PAGE_SHIFT); | 2805 | offset_pfn); |
2822 | else | 2806 | else |
2823 | iommu_flush_write_buffer(iommu); | 2807 | iommu_flush_write_buffer(iommu); |
2824 | 2808 | ||