* [PATCH 0/3] IOVA allocation improvements for iommu-dma @ 2017-03-15 13:33 Robin Murphy [not found] ` <cover.1489581865.git.robin.murphy-5wv7dgnIgG8@public.gmane.org> 2017-03-16 13:18 ` Sunil Kovvuri 0 siblings, 2 replies; 9+ messages in thread From: Robin Murphy @ 2017-03-15 13:33 UTC (permalink / raw) To: joro-zLv9SwRftAIdnm+yROfE0A Cc: will.deacon-5wv7dgnIgG8, damm+renesas-yzvPICuk2ACczHhG9Qg4qA, iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, sunil.kovvuri-Re5JQEeQqe8AvxtiuMwx3w, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r Hi all, Here's the first bit of lock contention removal to chew on - feedback welcome! Note that for the current users of the io-pgtable framework, this is most likely to simply push more contention onto the io-pgtable lock, so may not show a great improvement alone. Will and I both have rough proof-of-concept implementations of lock-free io-pgtable code which we need to sit down and agree on at some point, hopefullt fairly soon. I've taken the opportunity to do a bit of cleanup and refactoring within the series to make the final state of the code nicer, but the diffstat still turns out surprisingly reasonable in the end - it would actually be negative but for the new comments! Magnus, Shimoda-san, the first two patches should be of interest as they constitute the allocation rework I mentioned a while back[1] - if you still need to implement that scary workaround, this should make it simple to hook IPMMU-specific calls into the alloc and free paths, and let the driver take care of the details internally. Robin. [1]:https://lists.linuxfoundation.org/pipermail/iommu/2017-January/020189.html Robin Murphy (3): iommu/dma: Convert to address-based allocation iommu/dma: Clean up MSI IOVA allocation iommu/dma: Plumb in the per-CPU IOVA caches drivers/iommu/dma-iommu.c | 176 ++++++++++++++++++++++++---------------------- 1 file changed, 90 insertions(+), 86 deletions(-) -- 2.11.0.dirty ^ permalink raw reply [flat|nested] 9+ messages in thread
[parent not found: <cover.1489581865.git.robin.murphy-5wv7dgnIgG8@public.gmane.org>]
* [PATCH 1/3] iommu/dma: Convert to address-based allocation [not found] ` <cover.1489581865.git.robin.murphy-5wv7dgnIgG8@public.gmane.org> @ 2017-03-15 13:33 ` Robin Murphy 2017-03-15 13:33 ` [PATCH 2/3] iommu/dma: Clean up MSI IOVA allocation Robin Murphy ` (3 subsequent siblings) 4 siblings, 0 replies; 9+ messages in thread From: Robin Murphy @ 2017-03-15 13:33 UTC (permalink / raw) To: joro-zLv9SwRftAIdnm+yROfE0A Cc: will.deacon-5wv7dgnIgG8, damm+renesas-yzvPICuk2ACczHhG9Qg4qA, iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, sunil.kovvuri-Re5JQEeQqe8AvxtiuMwx3w, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r In preparation for some IOVA allocation improvements, clean up all the explicit struct iova usage such that all our mapping, unmapping and cleanup paths deal exclusively with addresses rather than implementation details. In the process, a few of the things we're touching get renamed for the sake of internal consistency. Signed-off-by: Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org> --- drivers/iommu/dma-iommu.c | 119 ++++++++++++++++++++++++++-------------------- 1 file changed, 67 insertions(+), 52 deletions(-) diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index 48d36ce59efb..9a9dca1073e6 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -286,12 +286,12 @@ int dma_info_to_prot(enum dma_data_direction dir, bool coherent, } } -static struct iova *__alloc_iova(struct iommu_domain *domain, size_t size, - dma_addr_t dma_limit, struct device *dev) +static dma_addr_t iommu_dma_alloc_iova(struct iommu_domain *domain, + size_t size, dma_addr_t dma_limit, struct device *dev) { struct iova_domain *iovad = cookie_iovad(domain); unsigned long shift = iova_shift(iovad); - unsigned long length = iova_align(iovad, size) >> shift; + unsigned long iova_len = size >> shift; struct iova *iova = NULL; if (domain->geometry.force_aperture) @@ -299,35 +299,42 @@ static struct iova *__alloc_iova(struct iommu_domain *domain, size_t size, /* Try to get PCI devices a SAC address */ if (dma_limit > DMA_BIT_MASK(32) && dev_is_pci(dev)) - iova = alloc_iova(iovad, length, DMA_BIT_MASK(32) >> shift, + iova = alloc_iova(iovad, iova_len, DMA_BIT_MASK(32) >> shift, true); /* * Enforce size-alignment to be safe - there could perhaps be an * attribute to control this per-device, or at least per-domain... */ if (!iova) - iova = alloc_iova(iovad, length, dma_limit >> shift, true); + iova = alloc_iova(iovad, iova_len, dma_limit >> shift, true); - return iova; + return (dma_addr_t)iova->pfn_lo << shift; } -/* The IOVA allocator knows what we mapped, so just unmap whatever that was */ -static void __iommu_dma_unmap(struct iommu_domain *domain, dma_addr_t dma_addr) +static void iommu_dma_free_iova(struct iommu_dma_cookie *cookie, + dma_addr_t iova, size_t size) { - struct iova_domain *iovad = cookie_iovad(domain); - unsigned long shift = iova_shift(iovad); - unsigned long pfn = dma_addr >> shift; - struct iova *iova = find_iova(iovad, pfn); - size_t size; + struct iova_domain *iovad = &cookie->iovad; + struct iova *iova_rbnode; - if (WARN_ON(!iova)) + iova_rbnode = find_iova(iovad, iova_pfn(iovad, iova)); + if (WARN_ON(!iova_rbnode)) return; - size = iova_size(iova) << shift; - size -= iommu_unmap(domain, pfn << shift, size); - /* ...and if we can't, then something is horribly, horribly wrong */ - WARN_ON(size > 0); - __free_iova(iovad, iova); + __free_iova(iovad, iova_rbnode); +} + +static void __iommu_dma_unmap(struct iommu_domain *domain, dma_addr_t dma_addr, + size_t size) +{ + struct iova_domain *iovad = cookie_iovad(domain); + size_t iova_off = iova_offset(iovad, dma_addr); + + dma_addr -= iova_off; + size = iova_align(iovad, size + iova_off); + + WARN_ON(iommu_unmap(domain, dma_addr, size) != size); + iommu_dma_free_iova(domain->iova_cookie, dma_addr, size); } static void __iommu_dma_free_pages(struct page **pages, int count) @@ -409,7 +416,7 @@ static struct page **__iommu_dma_alloc_pages(unsigned int count, void iommu_dma_free(struct device *dev, struct page **pages, size_t size, dma_addr_t *handle) { - __iommu_dma_unmap(iommu_get_domain_for_dev(dev), *handle); + __iommu_dma_unmap(iommu_get_domain_for_dev(dev), *handle, size); __iommu_dma_free_pages(pages, PAGE_ALIGN(size) >> PAGE_SHIFT); *handle = DMA_ERROR_CODE; } @@ -437,11 +444,11 @@ struct page **iommu_dma_alloc(struct device *dev, size_t size, gfp_t gfp, void (*flush_page)(struct device *, const void *, phys_addr_t)) { struct iommu_domain *domain = iommu_get_domain_for_dev(dev); - struct iova_domain *iovad = cookie_iovad(domain); - struct iova *iova; + struct iommu_dma_cookie *cookie = domain->iova_cookie; + struct iova_domain *iovad = &cookie->iovad; struct page **pages; struct sg_table sgt; - dma_addr_t dma_addr; + dma_addr_t iova; unsigned int count, min_size, alloc_sizes = domain->pgsize_bitmap; *handle = DMA_ERROR_CODE; @@ -461,11 +468,11 @@ struct page **iommu_dma_alloc(struct device *dev, size_t size, gfp_t gfp, if (!pages) return NULL; - iova = __alloc_iova(domain, size, dev->coherent_dma_mask, dev); + size = iova_align(iovad, size); + iova = iommu_dma_alloc_iova(domain, size, dev->coherent_dma_mask, dev); if (!iova) goto out_free_pages; - size = iova_align(iovad, size); if (sg_alloc_table_from_pages(&sgt, pages, count, 0, size, GFP_KERNEL)) goto out_free_iova; @@ -481,19 +488,18 @@ struct page **iommu_dma_alloc(struct device *dev, size_t size, gfp_t gfp, sg_miter_stop(&miter); } - dma_addr = iova_dma_addr(iovad, iova); - if (iommu_map_sg(domain, dma_addr, sgt.sgl, sgt.orig_nents, prot) + if (iommu_map_sg(domain, iova, sgt.sgl, sgt.orig_nents, prot) < size) goto out_free_sg; - *handle = dma_addr; + *handle = iova; sg_free_table(&sgt); return pages; out_free_sg: sg_free_table(&sgt); out_free_iova: - __free_iova(iovad, iova); + iommu_dma_free_iova(cookie, iova, size); out_free_pages: __iommu_dma_free_pages(pages, count); return NULL; @@ -527,22 +533,22 @@ int iommu_dma_mmap(struct page **pages, size_t size, struct vm_area_struct *vma) static dma_addr_t __iommu_dma_map(struct device *dev, phys_addr_t phys, size_t size, int prot) { - dma_addr_t dma_addr; struct iommu_domain *domain = iommu_get_domain_for_dev(dev); - struct iova_domain *iovad = cookie_iovad(domain); + struct iommu_dma_cookie *cookie = domain->iova_cookie; + struct iova_domain *iovad = &cookie->iovad; size_t iova_off = iova_offset(iovad, phys); - size_t len = iova_align(iovad, size + iova_off); - struct iova *iova = __alloc_iova(domain, len, dma_get_mask(dev), dev); + dma_addr_t iova; + size = iova_align(iovad, size + iova_off); + iova = iommu_dma_alloc_iova(domain, size, dma_get_mask(dev), dev); if (!iova) return DMA_ERROR_CODE; - dma_addr = iova_dma_addr(iovad, iova); - if (iommu_map(domain, dma_addr, phys - iova_off, len, prot)) { - __free_iova(iovad, iova); + if (iommu_map(domain, iova, phys - iova_off, size, prot)) { + iommu_dma_free_iova(cookie, iova, size); return DMA_ERROR_CODE; } - return dma_addr + iova_off; + return iova + iova_off; } dma_addr_t iommu_dma_map_page(struct device *dev, struct page *page, @@ -554,7 +560,7 @@ dma_addr_t iommu_dma_map_page(struct device *dev, struct page *page, void iommu_dma_unmap_page(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir, unsigned long attrs) { - __iommu_dma_unmap(iommu_get_domain_for_dev(dev), handle); + __iommu_dma_unmap(iommu_get_domain_for_dev(dev), handle, size); } /* @@ -643,10 +649,10 @@ int iommu_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, int prot) { struct iommu_domain *domain = iommu_get_domain_for_dev(dev); - struct iova_domain *iovad = cookie_iovad(domain); - struct iova *iova; + struct iommu_dma_cookie *cookie = domain->iova_cookie; + struct iova_domain *iovad = &cookie->iovad; struct scatterlist *s, *prev = NULL; - dma_addr_t dma_addr; + dma_addr_t iova; size_t iova_len = 0; unsigned long mask = dma_get_seg_boundary(dev); int i; @@ -690,7 +696,7 @@ int iommu_dma_map_sg(struct device *dev, struct scatterlist *sg, prev = s; } - iova = __alloc_iova(domain, iova_len, dma_get_mask(dev), dev); + iova = iommu_dma_alloc_iova(domain, iova_len, dma_get_mask(dev), dev); if (!iova) goto out_restore_sg; @@ -698,14 +704,13 @@ int iommu_dma_map_sg(struct device *dev, struct scatterlist *sg, * We'll leave any physical concatenation to the IOMMU driver's * implementation - it knows better than we do. */ - dma_addr = iova_dma_addr(iovad, iova); - if (iommu_map_sg(domain, dma_addr, sg, nents, prot) < iova_len) + if (iommu_map_sg(domain, iova, sg, nents, prot) < iova_len) goto out_free_iova; - return __finalise_sg(dev, sg, nents, dma_addr); + return __finalise_sg(dev, sg, nents, iova); out_free_iova: - __free_iova(iovad, iova); + iommu_dma_free_iova(cookie, iova, iova_len); out_restore_sg: __invalidate_sg(sg, nents); return 0; @@ -714,11 +719,21 @@ int iommu_dma_map_sg(struct device *dev, struct scatterlist *sg, void iommu_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction dir, unsigned long attrs) { + dma_addr_t start, end; + struct scatterlist *tmp; + int i; /* * The scatterlist segments are mapped into a single * contiguous IOVA allocation, so this is incredibly easy. */ - __iommu_dma_unmap(iommu_get_domain_for_dev(dev), sg_dma_address(sg)); + start = sg_dma_address(sg); + for_each_sg(sg_next(sg), tmp, nents - 1, i) { + if (sg_dma_len(tmp) == 0) + break; + sg = tmp; + } + end = sg_dma_address(sg) + sg_dma_len(sg); + __iommu_dma_unmap(iommu_get_domain_for_dev(dev), start, end - start); } dma_addr_t iommu_dma_map_resource(struct device *dev, phys_addr_t phys, @@ -731,7 +746,7 @@ dma_addr_t iommu_dma_map_resource(struct device *dev, phys_addr_t phys, void iommu_dma_unmap_resource(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir, unsigned long attrs) { - __iommu_dma_unmap(iommu_get_domain_for_dev(dev), handle); + __iommu_dma_unmap(iommu_get_domain_for_dev(dev), handle, size); } int iommu_dma_mapping_error(struct device *dev, dma_addr_t dma_addr) @@ -745,7 +760,7 @@ static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev, struct iommu_dma_cookie *cookie = domain->iova_cookie; struct iommu_dma_msi_page *msi_page; struct iova_domain *iovad = cookie_iovad(domain); - struct iova *iova; + dma_addr_t iova; int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO; size_t size = cookie_msi_granule(cookie); @@ -760,10 +775,10 @@ static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev, msi_page->phys = msi_addr; if (iovad) { - iova = __alloc_iova(domain, size, dma_get_mask(dev), dev); + iova = iommu_dma_alloc_iova(domain, size, dma_get_mask(dev), dev); if (!iova) goto out_free_page; - msi_page->iova = iova_dma_addr(iovad, iova); + msi_page->iova = iova; } else { msi_page->iova = cookie->msi_iova; cookie->msi_iova += size; @@ -778,7 +793,7 @@ static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev, out_free_iova: if (iovad) - __free_iova(iovad, iova); + iommu_dma_free_iova(cookie, iova, size); else cookie->msi_iova -= size; out_free_page: -- 2.11.0.dirty ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 2/3] iommu/dma: Clean up MSI IOVA allocation [not found] ` <cover.1489581865.git.robin.murphy-5wv7dgnIgG8@public.gmane.org> 2017-03-15 13:33 ` [PATCH 1/3] iommu/dma: Convert to address-based allocation Robin Murphy @ 2017-03-15 13:33 ` Robin Murphy 2017-03-15 13:33 ` [PATCH 3/3] iommu/dma: Plumb in the per-CPU IOVA caches Robin Murphy ` (2 subsequent siblings) 4 siblings, 0 replies; 9+ messages in thread From: Robin Murphy @ 2017-03-15 13:33 UTC (permalink / raw) To: joro-zLv9SwRftAIdnm+yROfE0A Cc: will.deacon-5wv7dgnIgG8, damm+renesas-yzvPICuk2ACczHhG9Qg4qA, iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, sunil.kovvuri-Re5JQEeQqe8AvxtiuMwx3w, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r Now that allocation is suitably abstracted, our private alloc/free helpers can drive the trivial MSI cookie allocator directly as well, which lets us clean up its exposed guts from iommu_dma_map_msi_msg() and simplify things quite a bit. Signed-off-by: Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org> --- drivers/iommu/dma-iommu.c | 58 ++++++++++++++++++++--------------------------- 1 file changed, 25 insertions(+), 33 deletions(-) diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index 9a9dca1073e6..c03e2eb4ebbb 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -61,15 +61,6 @@ static inline size_t cookie_msi_granule(struct iommu_dma_cookie *cookie) return PAGE_SIZE; } -static inline struct iova_domain *cookie_iovad(struct iommu_domain *domain) -{ - struct iommu_dma_cookie *cookie = domain->iova_cookie; - - if (cookie->type == IOMMU_DMA_IOVA_COOKIE) - return &cookie->iovad; - return NULL; -} - static struct iommu_dma_cookie *cookie_alloc(enum iommu_dma_cookie_type type) { struct iommu_dma_cookie *cookie; @@ -289,11 +280,19 @@ int dma_info_to_prot(enum dma_data_direction dir, bool coherent, static dma_addr_t iommu_dma_alloc_iova(struct iommu_domain *domain, size_t size, dma_addr_t dma_limit, struct device *dev) { - struct iova_domain *iovad = cookie_iovad(domain); - unsigned long shift = iova_shift(iovad); - unsigned long iova_len = size >> shift; + struct iommu_dma_cookie *cookie = domain->iova_cookie; + struct iova_domain *iovad = &cookie->iovad; + unsigned long shift, iova_len; struct iova *iova = NULL; + if (cookie->type == IOMMU_DMA_MSI_COOKIE) { + cookie->msi_iova += size; + return cookie->msi_iova - size; + } + + shift = iova_shift(iovad); + iova_len = size >> shift; + if (domain->geometry.force_aperture) dma_limit = min(dma_limit, domain->geometry.aperture_end); @@ -317,6 +316,12 @@ static void iommu_dma_free_iova(struct iommu_dma_cookie *cookie, struct iova_domain *iovad = &cookie->iovad; struct iova *iova_rbnode; + /* The MSI case is only ever cleaning up its most recent allocation */ + if (cookie->type == IOMMU_DMA_MSI_COOKIE) { + cookie->msi_iova -= size; + return; + } + iova_rbnode = find_iova(iovad, iova_pfn(iovad, iova)); if (WARN_ON(!iova_rbnode)) return; @@ -327,14 +332,15 @@ static void iommu_dma_free_iova(struct iommu_dma_cookie *cookie, static void __iommu_dma_unmap(struct iommu_domain *domain, dma_addr_t dma_addr, size_t size) { - struct iova_domain *iovad = cookie_iovad(domain); + struct iommu_dma_cookie *cookie = domain->iova_cookie; + struct iova_domain *iovad = &cookie->iovad; size_t iova_off = iova_offset(iovad, dma_addr); dma_addr -= iova_off; size = iova_align(iovad, size + iova_off); WARN_ON(iommu_unmap(domain, dma_addr, size) != size); - iommu_dma_free_iova(domain->iova_cookie, dma_addr, size); + iommu_dma_free_iova(cookie, dma_addr, size); } static void __iommu_dma_free_pages(struct page **pages, int count) @@ -759,7 +765,6 @@ static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev, { struct iommu_dma_cookie *cookie = domain->iova_cookie; struct iommu_dma_msi_page *msi_page; - struct iova_domain *iovad = cookie_iovad(domain); dma_addr_t iova; int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO; size_t size = cookie_msi_granule(cookie); @@ -773,29 +778,16 @@ static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev, if (!msi_page) return NULL; - msi_page->phys = msi_addr; - if (iovad) { - iova = iommu_dma_alloc_iova(domain, size, dma_get_mask(dev), dev); - if (!iova) - goto out_free_page; - msi_page->iova = iova; - } else { - msi_page->iova = cookie->msi_iova; - cookie->msi_iova += size; - } - - if (iommu_map(domain, msi_page->iova, msi_addr, size, prot)) - goto out_free_iova; + iova = __iommu_dma_map(dev, msi_addr, size, prot); + if (iommu_dma_mapping_error(dev, iova)) + goto out_free_page; INIT_LIST_HEAD(&msi_page->list); + msi_page->phys = msi_addr; + msi_page->iova = iova; list_add(&msi_page->list, &cookie->msi_page_list); return msi_page; -out_free_iova: - if (iovad) - iommu_dma_free_iova(cookie, iova, size); - else - cookie->msi_iova -= size; out_free_page: kfree(msi_page); return NULL; -- 2.11.0.dirty ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 3/3] iommu/dma: Plumb in the per-CPU IOVA caches [not found] ` <cover.1489581865.git.robin.murphy-5wv7dgnIgG8@public.gmane.org> 2017-03-15 13:33 ` [PATCH 1/3] iommu/dma: Convert to address-based allocation Robin Murphy 2017-03-15 13:33 ` [PATCH 2/3] iommu/dma: Clean up MSI IOVA allocation Robin Murphy @ 2017-03-15 13:33 ` Robin Murphy 2017-03-22 17:43 ` [PATCH 0/3] IOVA allocation improvements for iommu-dma Nate Watterson 2017-03-31 12:40 ` Will Deacon 4 siblings, 0 replies; 9+ messages in thread From: Robin Murphy @ 2017-03-15 13:33 UTC (permalink / raw) To: joro-zLv9SwRftAIdnm+yROfE0A Cc: will.deacon-5wv7dgnIgG8, damm+renesas-yzvPICuk2ACczHhG9Qg4qA, iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, sunil.kovvuri-Re5JQEeQqe8AvxtiuMwx3w, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r With IOVA allocation suitably tidied up, we are finally free to opt in to the per-CPU caching mechanism. The caching alone can provide a modest improvement over walking the rbtree for weedier systems (iperf3 shows ~10% more ethernet throughput on an ARM Juno r1 constrained to a single 650MHz Cortex-A53), but the real gain will be in sidestepping the rbtree lock contention which larger ARM-based systems with lots of parallel I/O are starting to feel the pain of. Signed-off-by: Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org> --- drivers/iommu/dma-iommu.c | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index c03e2eb4ebbb..292008de68f0 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -282,8 +282,7 @@ static dma_addr_t iommu_dma_alloc_iova(struct iommu_domain *domain, { struct iommu_dma_cookie *cookie = domain->iova_cookie; struct iova_domain *iovad = &cookie->iovad; - unsigned long shift, iova_len; - struct iova *iova = NULL; + unsigned long shift, iova_len, iova = 0; if (cookie->type == IOMMU_DMA_MSI_COOKIE) { cookie->msi_iova += size; @@ -292,41 +291,39 @@ static dma_addr_t iommu_dma_alloc_iova(struct iommu_domain *domain, shift = iova_shift(iovad); iova_len = size >> shift; + /* + * Freeing non-power-of-two-sized allocations back into the IOVA caches + * will come back to bite us badly, so we have to waste a bit of space + * rounding up anything cacheable to make sure that can't happen. The + * order of the unadjusted size will still match upon freeing. + */ + if (iova_len < (1 << (IOVA_RANGE_CACHE_MAX_SIZE - 1))) + iova_len = roundup_pow_of_two(iova_len); if (domain->geometry.force_aperture) dma_limit = min(dma_limit, domain->geometry.aperture_end); /* Try to get PCI devices a SAC address */ if (dma_limit > DMA_BIT_MASK(32) && dev_is_pci(dev)) - iova = alloc_iova(iovad, iova_len, DMA_BIT_MASK(32) >> shift, - true); - /* - * Enforce size-alignment to be safe - there could perhaps be an - * attribute to control this per-device, or at least per-domain... - */ - if (!iova) - iova = alloc_iova(iovad, iova_len, dma_limit >> shift, true); + iova = alloc_iova_fast(iovad, iova_len, DMA_BIT_MASK(32) >> shift); - return (dma_addr_t)iova->pfn_lo << shift; + if (!iova) + iova = alloc_iova_fast(iovad, iova_len, dma_limit >> shift); + + return (dma_addr_t)iova << shift; } static void iommu_dma_free_iova(struct iommu_dma_cookie *cookie, dma_addr_t iova, size_t size) { struct iova_domain *iovad = &cookie->iovad; - struct iova *iova_rbnode; + unsigned long shift = iova_shift(iovad); /* The MSI case is only ever cleaning up its most recent allocation */ - if (cookie->type == IOMMU_DMA_MSI_COOKIE) { + if (cookie->type == IOMMU_DMA_MSI_COOKIE) cookie->msi_iova -= size; - return; - } - - iova_rbnode = find_iova(iovad, iova_pfn(iovad, iova)); - if (WARN_ON(!iova_rbnode)) - return; - - __free_iova(iovad, iova_rbnode); + else + free_iova_fast(iovad, iova >> shift, size >> shift); } static void __iommu_dma_unmap(struct iommu_domain *domain, dma_addr_t dma_addr, -- 2.11.0.dirty ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 0/3] IOVA allocation improvements for iommu-dma [not found] ` <cover.1489581865.git.robin.murphy-5wv7dgnIgG8@public.gmane.org> ` (2 preceding siblings ...) 2017-03-15 13:33 ` [PATCH 3/3] iommu/dma: Plumb in the per-CPU IOVA caches Robin Murphy @ 2017-03-22 17:43 ` Nate Watterson 2017-03-31 12:40 ` Will Deacon 4 siblings, 0 replies; 9+ messages in thread From: Nate Watterson @ 2017-03-22 17:43 UTC (permalink / raw) To: Robin Murphy Cc: will.deacon-5wv7dgnIgG8, damm+renesas-yzvPICuk2ACczHhG9Qg4qA, iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, sunil.kovvuri-Re5JQEeQqe8AvxtiuMwx3w, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r On 2017-03-15 09:33, Robin Murphy wrote: > Hi all, Hi Robin, > > Here's the first bit of lock contention removal to chew on - feedback > welcome! Note that for the current users of the io-pgtable framework, > this is most likely to simply push more contention onto the io-pgtable > lock, so may not show a great improvement alone. Will and I both have > rough proof-of-concept implementations of lock-free io-pgtable code > which we need to sit down and agree on at some point, hopefullt fairly > soon. > > I've taken the opportunity to do a bit of cleanup and refactoring > within the series to make the final state of the code nicer, but the > diffstat still turns out surprisingly reasonable in the end - it would > actually be negative but for the new comments! > > Magnus, Shimoda-san, the first two patches should be of interest as > they > constitute the allocation rework I mentioned a while back[1] - if you > still need to implement that scary workaround, this should make it > simple to hook IPMMU-specific calls into the alloc and free paths, and > let the driver take care of the details internally. I've tested your patches on a QDF2400 platform and generally see modest improvements in iperf/fio performance. As you suspected would happen, contention has indeed moved to the io-pgtable lock. I am looking forward to testing with the lock-free io-pgtable implementation, however I suspect that there will still be contention issues acquiring the (SMMUv3) cmdq lock on the unmap path. Reviewed/Tested-by: Nate Watterson <nwatters-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org> > > Robin. > > [1]:https://lists.linuxfoundation.org/pipermail/iommu/2017-January/020189.html > > Robin Murphy (3): > iommu/dma: Convert to address-based allocation > iommu/dma: Clean up MSI IOVA allocation > iommu/dma: Plumb in the per-CPU IOVA caches > > drivers/iommu/dma-iommu.c | 176 > ++++++++++++++++++++++++---------------------- > 1 file changed, 90 insertions(+), 86 deletions(-) -- Qualcomm Datacenter Technologies, Inc. on behalf of Qualcomm Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 0/3] IOVA allocation improvements for iommu-dma [not found] ` <cover.1489581865.git.robin.murphy-5wv7dgnIgG8@public.gmane.org> ` (3 preceding siblings ...) 2017-03-22 17:43 ` [PATCH 0/3] IOVA allocation improvements for iommu-dma Nate Watterson @ 2017-03-31 12:40 ` Will Deacon [not found] ` <20170331124051.GI8967-5wv7dgnIgG8@public.gmane.org> 4 siblings, 1 reply; 9+ messages in thread From: Will Deacon @ 2017-03-31 12:40 UTC (permalink / raw) To: Robin Murphy Cc: damm+renesas-yzvPICuk2ACczHhG9Qg4qA, iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, sunil.kovvuri-Re5JQEeQqe8AvxtiuMwx3w, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r Hi Robin, Joerg, On Wed, Mar 15, 2017 at 01:33:13PM +0000, Robin Murphy wrote: > Here's the first bit of lock contention removal to chew on - feedback > welcome! Note that for the current users of the io-pgtable framework, > this is most likely to simply push more contention onto the io-pgtable > lock, so may not show a great improvement alone. Will and I both have > rough proof-of-concept implementations of lock-free io-pgtable code > which we need to sit down and agree on at some point, hopefullt fairly > soon. > > I've taken the opportunity to do a bit of cleanup and refactoring > within the series to make the final state of the code nicer, but the > diffstat still turns out surprisingly reasonable in the end - it would > actually be negative but for the new comments! > > Magnus, Shimoda-san, the first two patches should be of interest as they > constitute the allocation rework I mentioned a while back[1] - if you > still need to implement that scary workaround, this should make it > simple to hook IPMMU-specific calls into the alloc and free paths, and > let the driver take care of the details internally. What's the plan for merging this? Whilst we still have the iopgtable lock contention to resolve, this is a good incremental step towards improving our scalability and sits nicely alongside the SMMUv2 TLB improvements I just queued. Thanks, Will ^ permalink raw reply [flat|nested] 9+ messages in thread
[parent not found: <20170331124051.GI8967-5wv7dgnIgG8@public.gmane.org>]
* Re: [PATCH 0/3] IOVA allocation improvements for iommu-dma [not found] ` <20170331124051.GI8967-5wv7dgnIgG8@public.gmane.org> @ 2017-03-31 13:13 ` Robin Murphy [not found] ` <10f9621a-41ca-bb3d-0e49-a2827022f608-5wv7dgnIgG8@public.gmane.org> 0 siblings, 1 reply; 9+ messages in thread From: Robin Murphy @ 2017-03-31 13:13 UTC (permalink / raw) To: Will Deacon Cc: damm+renesas-yzvPICuk2ACczHhG9Qg4qA, iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, sunil.kovvuri-Re5JQEeQqe8AvxtiuMwx3w, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r On 31/03/17 13:40, Will Deacon wrote: > Hi Robin, Joerg, > > On Wed, Mar 15, 2017 at 01:33:13PM +0000, Robin Murphy wrote: >> Here's the first bit of lock contention removal to chew on - feedback >> welcome! Note that for the current users of the io-pgtable framework, >> this is most likely to simply push more contention onto the io-pgtable >> lock, so may not show a great improvement alone. Will and I both have >> rough proof-of-concept implementations of lock-free io-pgtable code >> which we need to sit down and agree on at some point, hopefullt fairly >> soon. >> >> I've taken the opportunity to do a bit of cleanup and refactoring >> within the series to make the final state of the code nicer, but the >> diffstat still turns out surprisingly reasonable in the end - it would >> actually be negative but for the new comments! >> >> Magnus, Shimoda-san, the first two patches should be of interest as they >> constitute the allocation rework I mentioned a while back[1] - if you >> still need to implement that scary workaround, this should make it >> simple to hook IPMMU-specific calls into the alloc and free paths, and >> let the driver take care of the details internally. > > What's the plan for merging this? Whilst we still have the iopgtable lock > contention to resolve, this is a good incremental step towards improving > our scalability and sits nicely alongside the SMMUv2 TLB improvements I > just queued. I was assuming this would go through the IOMMU tree if there were no problems and the feedback was good, and that would seem to be the case. I'm pleasantly surprised that this series doesn't even conflict at all with my other iommu-dma changes already queued - I've just checked that it still applies cleanly to the current iommu/next as-is. Robin. > > Thanks, > > Will > ^ permalink raw reply [flat|nested] 9+ messages in thread
[parent not found: <10f9621a-41ca-bb3d-0e49-a2827022f608-5wv7dgnIgG8@public.gmane.org>]
* Re: [PATCH 0/3] IOVA allocation improvements for iommu-dma [not found] ` <10f9621a-41ca-bb3d-0e49-a2827022f608-5wv7dgnIgG8@public.gmane.org> @ 2017-03-31 14:33 ` Joerg Roedel 0 siblings, 0 replies; 9+ messages in thread From: Joerg Roedel @ 2017-03-31 14:33 UTC (permalink / raw) To: Robin Murphy Cc: Will Deacon, damm+renesas-yzvPICuk2ACczHhG9Qg4qA, iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, sunil.kovvuri-Re5JQEeQqe8AvxtiuMwx3w, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r On Fri, Mar 31, 2017 at 02:13:13PM +0100, Robin Murphy wrote: > I was assuming this would go through the IOMMU tree if there were no > problems and the feedback was good, and that would seem to be the case. > I'm pleasantly surprised that this series doesn't even conflict at all > with my other iommu-dma changes already queued - I've just checked that > it still applies cleanly to the current iommu/next as-is. Yes, makes sense. Can you please resend it with the review and tested-tags added? I queue it then. Thanks, Joerg ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 0/3] IOVA allocation improvements for iommu-dma 2017-03-15 13:33 [PATCH 0/3] IOVA allocation improvements for iommu-dma Robin Murphy [not found] ` <cover.1489581865.git.robin.murphy-5wv7dgnIgG8@public.gmane.org> @ 2017-03-16 13:18 ` Sunil Kovvuri 1 sibling, 0 replies; 9+ messages in thread From: Sunil Kovvuri @ 2017-03-16 13:18 UTC (permalink / raw) To: Robin Murphy Cc: Will Deacon, joro, damm+renesas, iommu, nwatters, sgoutham, yoshihiro.shimoda.uh, LAKML On Wed, Mar 15, 2017 at 7:03 PM, Robin Murphy <robin.murphy@arm.com> wrote: > Hi all, > > Here's the first bit of lock contention removal to chew on - feedback > welcome! Note that for the current users of the io-pgtable framework, > this is most likely to simply push more contention onto the io-pgtable > lock, so may not show a great improvement alone. Will and I both have > rough proof-of-concept implementations of lock-free io-pgtable code > which we need to sit down and agree on at some point, hopefullt fairly > soon. Thanks for working on this. As you said, it's indeed pushing lock contention down to pgtable lock from iova rbtree lock but now morethan lock I see issue is with yielding CPU while waiting for tlb_sync. Below are some numbers. I have tweaked '__arm_smmu_tlb_sync' in SMMUv2 driver i.e basically removed cpu_relax() and udelay() to make it a busy loop. Before: 1.1 Gbps With your patches: 1.45Gbps With your patches + busy loop in tlb_sync: 7Gbps If we reduce pgtable contention a bit With your patches + busy loop in tlb_sync + Iperf threads reduced to 8 from 16: ~9Gbps So looks like along with pgtable lock, some optimization can be done to tlb_sync code as well. Thanks, Sunil. ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2017-03-31 14:33 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2017-03-15 13:33 [PATCH 0/3] IOVA allocation improvements for iommu-dma Robin Murphy [not found] ` <cover.1489581865.git.robin.murphy-5wv7dgnIgG8@public.gmane.org> 2017-03-15 13:33 ` [PATCH 1/3] iommu/dma: Convert to address-based allocation Robin Murphy 2017-03-15 13:33 ` [PATCH 2/3] iommu/dma: Clean up MSI IOVA allocation Robin Murphy 2017-03-15 13:33 ` [PATCH 3/3] iommu/dma: Plumb in the per-CPU IOVA caches Robin Murphy 2017-03-22 17:43 ` [PATCH 0/3] IOVA allocation improvements for iommu-dma Nate Watterson 2017-03-31 12:40 ` Will Deacon [not found] ` <20170331124051.GI8967-5wv7dgnIgG8@public.gmane.org> 2017-03-31 13:13 ` Robin Murphy [not found] ` <10f9621a-41ca-bb3d-0e49-a2827022f608-5wv7dgnIgG8@public.gmane.org> 2017-03-31 14:33 ` Joerg Roedel 2017-03-16 13:18 ` Sunil Kovvuri
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).