From: Don Dutile <ddutile@redhat.com> Date: Fri, 15 May 2009 10:21:22 -0400 Subject: [pci] IOMMU phys_addr cleanup Message-id: 4A0D7A62.7090201@redhat.com O-Subject: [RHEL5.4 PATCH 3/3] IOMMU phys_addr cleanup Bugzilla: 500901 RH-Acked-by: Rik van Riel <riel@redhat.com> RH-Acked-by: Justin M. Forbes <jforbes@redhat.com> RH-Acked-by: Chris Wright <chrisw@redhat.com> BZ 500901 Chris Wright's review of the VTd support for RHEL5.4 had feedback that the phys_addr implementation was less than ideal. The VT-d support was included in 5.4 build before a refresh of the patch could be done to implement the recommended cleanup. Since the phys_addr cleanup affect the IOMMU API, the AMD IOMMU support had to be (minimally) tweaked as well. arch/x86_64/kernel/amd_iommu.c | 9 +++---- drivers/base/iommu.c | 4 +- drivers/pci/dmar.c | 2 +- drivers/pci/intel-iommu.c | 51 +++++++++++++++++++-------------------- include/asm-x86_64/types.h | 1 + include/linux/intel-iommu.h | 7 ----- include/linux/iommu.h | 12 ++++---- 7 files changed, 39 insertions(+), 47 deletions(-) Please review & ack. Note: this bz is a beta blocker for 5.4. - Don diff --git a/arch/x86_64/kernel/amd_iommu.c b/arch/x86_64/kernel/amd_iommu.c index bccdb78..dab0ff5 100644 --- a/arch/x86_64/kernel/amd_iommu.c +++ b/arch/x86_64/kernel/amd_iommu.c @@ -1851,11 +1851,10 @@ static int amd_iommu_attach_device(struct iommu_domain *dom, } static int amd_iommu_map_range(struct iommu_domain *dom, - unsigned long iova, void *addr, + unsigned long iova, phys_addr_t paddr, size_t size, int iommu_prot) { struct protection_domain *domain = dom->priv; - unsigned long paddr = (unsigned long)addr; unsigned long i, npages = iommu_num_pages(paddr, size, PAGE_SIZE); int prot = 0; int ret; @@ -1897,13 +1896,13 @@ static void amd_iommu_unmap_range(struct iommu_domain *dom, iommu_flush_domain(domain->id); } -static void * +static phys_addr_t amd_iommu_iova_to_phys(struct iommu_domain *dom, unsigned long iova) { struct protection_domain *domain = dom->priv; unsigned long offset = iova & ~PAGE_MASK; - unsigned long paddr; + phys_addr_t paddr; u64 *pte; pte = &domain->pt_root[IOMMU_PTE_L2_INDEX(iova)]; @@ -1926,7 +1925,7 @@ amd_iommu_iova_to_phys(struct iommu_domain *dom, paddr = *pte & IOMMU_PAGE_MASK; paddr |= offset; - return (void *)paddr; + return paddr; } static struct iommu_ops amd_iommu_ops = { diff --git a/drivers/base/iommu.c b/drivers/base/iommu.c index d4ce2de..b60ecbe 100644 --- a/drivers/base/iommu.c +++ b/drivers/base/iommu.c @@ -80,7 +80,7 @@ void iommu_detach_device(struct iommu_domain *domain, struct device *dev) EXPORT_SYMBOL_GPL(iommu_detach_device); int iommu_map_range(struct iommu_domain *domain, unsigned long iova, - void *paddr, size_t size, int prot) + phys_addr_t paddr, size_t size, int prot) { return iommu_ops->map(domain, iova, paddr, size, prot); } @@ -93,7 +93,7 @@ void iommu_unmap_range(struct iommu_domain *domain, unsigned long iova, } EXPORT_SYMBOL_GPL(iommu_unmap_range); -void *iommu_iova_to_phys(struct iommu_domain *domain, +phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain, unsigned long iova) { return iommu_ops->iova_to_phys(domain, iova); diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index 51a587e..e87ebbd 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c @@ -974,7 +974,7 @@ static int dmar_fault_do_one(struct intel_iommu *iommu, int type, #define PRIMARY_FAULT_REG_LEN (16) irqreturn_t dmar_fault(int irq, void *dev_id, struct pt_regs *regs) { - struct intel_iommu *iommu = (struct intel_iommu *)dev_id; + struct intel_iommu *iommu = dev_id; int reg, fault_index; u32 fault_status; unsigned long flag; diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index ae1f4d2..b6fbb16 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -2149,7 +2149,7 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr, BUG_ON(dir == DMA_NONE); if (pdev->iommu == DUMMY_DEVICE_DOMAIN_INFO) - return (dma_addr_t)paddr; + return paddr; domain = get_valid_domain_for_dev(pdev); if (!domain) @@ -2162,7 +2162,7 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr, if (!iova) goto error; - start_paddr = (phys_addr_t)((unsigned long)iova->pfn_lo << PAGE_SHIFT); + start_paddr = (phys_addr_t)iova->pfn_lo << PAGE_SHIFT; /* * Check if DMAR supports zero-length reads on write only @@ -2179,31 +2179,31 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr, * might have two guest_addr mapping to the same host paddr, but this * is not a big problem */ - ret = domain_page_mapping(domain, (dma_addr_t)start_paddr, + ret = domain_page_mapping(domain, start_paddr, ((u64)paddr) & PAGE_MASK, size, prot); if (ret) goto error; /* it's a non-present to present mapping */ ret = iommu_flush_iotlb_psi(iommu, domain->id, - (u64)start_paddr, size >> VTD_PAGE_SHIFT, 1); + start_paddr, size >> VTD_PAGE_SHIFT, 1); if (ret) iommu_flush_write_buffer(iommu); - return (dma_addr_t)start_paddr + ((u64)paddr & (~PAGE_MASK)); + return start_paddr + ((u64)paddr & (~PAGE_MASK)); error: if (iova) __free_iova(&domain->iovad, iova); - printk(KERN_ERR"Device %s request: %lx@%llx dir %d --- failed\n", + printk(KERN_ERR"Device %s request: %zx@%llx dir %d --- failed\n", pci_name(pdev), size, (unsigned long long)paddr, dir); return 0; } -dma_addr_t intel_map_single(struct device *hwdev, void *vaddr, +static dma_addr_t intel_map_single(struct device *hwdev, void *vaddr, size_t size, int dir) { - return __intel_map_single(hwdev, (phys_addr_t)(virt_to_phys(vaddr)), + return __intel_map_single(hwdev, virt_to_phys(vaddr), size, dir, to_pci_dev(hwdev)->dma_mask); } @@ -2268,7 +2268,7 @@ static void add_unmap(struct dmar_domain *dom, struct iova *iova) spin_unlock_irqrestore(&async_umap_flush_lock, flags); } -void intel_unmap_single(struct device *dev, dma_addr_t dev_addr, size_t size, +static void intel_unmap_single(struct device *dev, dma_addr_t dev_addr, size_t size, int dir) { struct pci_dev *pdev = to_pci_dev(dev); @@ -2313,7 +2313,7 @@ void intel_unmap_single(struct device *dev, dma_addr_t dev_addr, size_t size, } } -void *intel_alloc_coherent(struct device *hwdev, size_t size, +static void *intel_alloc_coherent(struct device *hwdev, size_t size, dma_addr_t *dma_handle, gfp_t flags) { void *vaddr; @@ -2328,9 +2328,7 @@ void *intel_alloc_coherent(struct device *hwdev, size_t size, return NULL; memset(vaddr, 0, size); - *dma_handle = __intel_map_single(hwdev, - (phys_addr_t)(virt_to_phys(vaddr)), - size, + *dma_handle = __intel_map_single(hwdev, virt_to_phys(vaddr), size, DMA_BIDIRECTIONAL, hwdev->coherent_dma_mask); if (*dma_handle) @@ -2351,10 +2349,13 @@ static void intel_free_coherent(struct device *hwdev, size_t size, void *vaddr, free_pages((unsigned long)vaddr, order); } -#define SG_ENT_VIRT_ADDRESS(sg) (page_address((sg)->page) + (sg)->offset) +static inline struct page *sg_page(struct scatterlist *sg) +{ + return sg->page; +} static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist, - int nelems, int dir) + int nelems, int dir) { int i; struct pci_dev *pdev = to_pci_dev(hwdev); @@ -2362,7 +2363,7 @@ static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist, unsigned long start_addr; struct iova *iova; size_t size = 0; - void *addr; + phys_addr_t addr; struct scatterlist *sg; struct intel_iommu *iommu; @@ -2378,7 +2379,7 @@ static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist, if (!iova) return; for_each_sg(sglist, sg, nelems, i) { - addr = SG_ENT_VIRT_ADDRESS(sg); + addr = page_to_phys(sg_page(sg)) + sg->offset; size += aligned_size((u64)addr, sg->length); } @@ -2404,8 +2405,8 @@ static int intel_nontranslate_map_sg(struct device *hddev, struct scatterlist *sg; for_each_sg(sglist, sg, nelems, i) { - BUG_ON(!sg->page); - sg->dma_address = virt_to_bus(SG_ENT_VIRT_ADDRESS(sg)); + BUG_ON(!sg_page(sg)); + sg->dma_address = page_to_phys(sg_page(sg)) + sg->offset; sg->dma_length = sg->length; } return nelems; @@ -2414,7 +2415,7 @@ static int intel_nontranslate_map_sg(struct device *hddev, static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems, int dir) { - void *addr; + phys_addr_t addr; int i; struct pci_dev *pdev = to_pci_dev(hwdev); struct dmar_domain *domain; @@ -2438,8 +2439,7 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int ne iommu = domain_get_iommu(domain); for_each_sg(sglist, sg, nelems, i) { - addr = SG_ENT_VIRT_ADDRESS(sg); - addr = (void *)virt_to_phys(addr); + addr = page_to_phys(sg_page(sg)) + sg->offset; size += aligned_size((u64)addr, sg->length); } @@ -2462,8 +2462,7 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int ne start_addr = iova->pfn_lo << PAGE_SHIFT; offset = 0; for_each_sg(sglist, sg, nelems, i) { - addr = SG_ENT_VIRT_ADDRESS(sg); - addr = (void *)virt_to_phys(addr); + addr = page_to_phys(sg_page(sg)) + sg->offset; size = aligned_size((u64)addr, sg->length); ret = domain_page_mapping(domain, start_addr + offset, ((u64)addr) & PAGE_MASK, @@ -3195,7 +3194,7 @@ static int intel_iommu_map_range(struct iommu_domain *domain, dmar_domain->max_addr = max_addr; } - ret = domain_page_mapping(dmar_domain, iova, (u64)hpa, size, prot); + ret = domain_page_mapping(dmar_domain, iova, hpa, size, prot); return ret; } @@ -3225,7 +3224,7 @@ static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain, if (pte) phys = dma_pte_addr(pte); - return (phys_addr_t)phys; + return phys; } static int intel_iommu_domain_has_cap(struct iommu_domain *domain, diff --git a/include/asm-x86_64/types.h b/include/asm-x86_64/types.h index c86c2e6..f8cdbe9 100644 --- a/include/asm-x86_64/types.h +++ b/include/asm-x86_64/types.h @@ -47,6 +47,7 @@ typedef unsigned long long u64; typedef u64 dma64_addr_t; typedef u64 dma_addr_t; +typedef u64 phys_addr_t; typedef u64 sector_t; #define HAVE_SECTOR_T diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h index 37e9f76..ac578e9 100644 --- a/include/linux/intel-iommu.h +++ b/include/linux/intel-iommu.h @@ -29,13 +29,6 @@ #include <asm/cacheflush.h> #include <asm/proto.h> -/* - * in linux/types.h upstream - */ -#ifndef CONFIG_PHYS_ADDR_T_64BIT -typedef void* phys_addr_t; -#endif - /* in linux/scatterlist.h upstream */ /* * Loop over each sg element, following the pointer to a new list if necessary diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 1e2ebbc..3af4ffd 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -37,10 +37,10 @@ struct iommu_ops { int (*attach_dev)(struct iommu_domain *domain, struct device *dev); void (*detach_dev)(struct iommu_domain *domain, struct device *dev); int (*map)(struct iommu_domain *domain, unsigned long iova, - void *paddr, size_t size, int prot); + phys_addr_t paddr, size_t size, int prot); void (*unmap)(struct iommu_domain *domain, unsigned long iova, size_t size); - void *(*iova_to_phys)(struct iommu_domain *domain, + phys_addr_t (*iova_to_phys)(struct iommu_domain *domain, unsigned long iova); int (*domain_has_cap)(struct iommu_domain *domain, unsigned long cap); @@ -57,10 +57,10 @@ extern int iommu_attach_device(struct iommu_domain *domain, extern void iommu_detach_device(struct iommu_domain *domain, struct device *dev); extern int iommu_map_range(struct iommu_domain *domain, unsigned long iova, - void *paddr, size_t size, int prot); + phys_addr_t paddr, size_t size, int prot); extern void iommu_unmap_range(struct iommu_domain *domain, unsigned long iova, size_t size); -extern void *iommu_iova_to_phys(struct iommu_domain *domain, +extern phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain, unsigned long iova); extern int iommu_domain_has_cap(struct iommu_domain *domain, unsigned long cap); @@ -97,7 +97,7 @@ static inline void iommu_detach_device(struct iommu_domain *domain, } static inline int iommu_map_range(struct iommu_domain *domain, - unsigned long iova, void *paddr, + unsigned long iova, phys_addr_t paddr, size_t size, int prot) { return -ENODEV; @@ -108,7 +108,7 @@ static inline void iommu_unmap_range(struct iommu_domain *domain, { } -static inline void *iommu_iova_to_phys(struct iommu_domain *domain, +static inline phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain, unsigned long iova) { return 0;