linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH RFC/RFT 0/5] Save single pages from CMA area
@ 2019-03-26 22:49 Nicolin Chen
  2019-03-26 22:49 ` [PATCH RFC/RFT 1/5] ARM: dma-mapping: Add fallback normal page allocations Nicolin Chen
                   ` (4 more replies)
  0 siblings, 5 replies; 7+ messages in thread
From: Nicolin Chen @ 2019-03-26 22:49 UTC (permalink / raw)
  To: hch, robin.murphy
  Cc: vdumpa, linux, catalin.marinas, will.deacon, joro, m.szyprowski,
	linux-arm-kernel, linux-kernel, iommu, tony

This series of patches try to save single pages from CMA area bypassing
all CMA single page alloctions and allocating normal pages instead, as
all addresses within one single page are contiguous.

We had once applied the PATCH-5 but reverted it as actually not all the
callers handled the fallback allocations. Per Robin's suggestion, let's
stuff alloc_pages()/free_page() fallbacks to those callers before having
PATCH-5.

Nicolin Chen (5):
  ARM: dma-mapping: Add fallback normal page allocations
  dma-remap: Run alloc_pages() on failure
  iommu: amd_iommu: Add fallback normal page allocations
  arm64: dma-mapping: Add fallback normal page allocations
  dma-contiguous: Do not allocate a single page from CMA area

 arch/arm/mm/dma-mapping.c   | 13 ++++++++++---
 arch/arm64/mm/dma-mapping.c | 19 ++++++++++++-------
 drivers/iommu/amd_iommu.c   |  3 +++
 kernel/dma/contiguous.c     | 22 +++++++++++++++++++---
 kernel/dma/remap.c          |  2 +-
 5 files changed, 45 insertions(+), 14 deletions(-)

-- 
2.17.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH RFC/RFT 1/5] ARM: dma-mapping: Add fallback normal page allocations
  2019-03-26 22:49 [PATCH RFC/RFT 0/5] Save single pages from CMA area Nicolin Chen
@ 2019-03-26 22:49 ` Nicolin Chen
  2019-03-26 22:49 ` [PATCH RFC/RFT 2/5] dma-remap: Run alloc_pages() on failure Nicolin Chen
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Nicolin Chen @ 2019-03-26 22:49 UTC (permalink / raw)
  To: hch, robin.murphy
  Cc: vdumpa, linux, catalin.marinas, will.deacon, joro, m.szyprowski,
	linux-arm-kernel, linux-kernel, iommu, tony

The CMA allocation will skip allocations of single pages to save CMA
resource. This requires its callers to rebound those page allocations
from normal area. So this patch adds fallback routines.

Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
 arch/arm/mm/dma-mapping.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 8a90f298af96..febaf637a25b 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -589,6 +589,8 @@ static void *__alloc_from_contiguous(struct device *dev, size_t size,
 	void *ptr = NULL;
 
 	page = dma_alloc_from_contiguous(dev, count, order, gfp & __GFP_NOWARN);
+	if (!page)
+		page = alloc_pages(gfp, order);
 	if (!page)
 		return NULL;
 
@@ -600,7 +602,8 @@ static void *__alloc_from_contiguous(struct device *dev, size_t size,
 	if (PageHighMem(page)) {
 		ptr = __dma_alloc_remap(page, size, GFP_KERNEL, prot, caller);
 		if (!ptr) {
-			dma_release_from_contiguous(dev, page, count);
+			if (!dma_release_from_contiguous(dev, page, count))
+				__free_pages(page, get_order(size));
 			return NULL;
 		}
 	} else {
@@ -622,7 +625,8 @@ static void __free_from_contiguous(struct device *dev, struct page *page,
 		else
 			__dma_remap(page, size, PAGE_KERNEL);
 	}
-	dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT);
+	if (!dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT))
+		__free_pages(page, get_order(size));
 }
 
 static inline pgprot_t __get_dma_pgprot(unsigned long attrs, pgprot_t prot)
@@ -1295,6 +1299,8 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size,
 
 		page = dma_alloc_from_contiguous(dev, count, order,
 						 gfp & __GFP_NOWARN);
+		if (!page)
+			page = alloc_pages(gfp, order);
 		if (!page)
 			goto error;
 
@@ -1369,7 +1375,8 @@ static int __iommu_free_buffer(struct device *dev, struct page **pages,
 	int i;
 
 	if (attrs & DMA_ATTR_FORCE_CONTIGUOUS) {
-		dma_release_from_contiguous(dev, pages[0], count);
+		if (!dma_release_from_contiguous(dev, pages[0], count))
+			__free_pages(page[0], get_order(size));
 	} else {
 		for (i = 0; i < count; i++)
 			if (pages[i])
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH RFC/RFT 2/5] dma-remap: Run alloc_pages() on failure
  2019-03-26 22:49 [PATCH RFC/RFT 0/5] Save single pages from CMA area Nicolin Chen
  2019-03-26 22:49 ` [PATCH RFC/RFT 1/5] ARM: dma-mapping: Add fallback normal page allocations Nicolin Chen
@ 2019-03-26 22:49 ` Nicolin Chen
  2019-03-26 22:53   ` Nicolin Chen
  2019-03-26 22:49 ` [PATCH RFC/RFT 3/5] iommu: amd_iommu: Add fallback normal page allocations Nicolin Chen
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 7+ messages in thread
From: Nicolin Chen @ 2019-03-26 22:49 UTC (permalink / raw)
  To: hch, robin.murphy
  Cc: vdumpa, linux, catalin.marinas, will.deacon, joro, m.szyprowski,
	linux-arm-kernel, linux-kernel, iommu, tony

The CMA allocation will skip allocations of single pages to save CMA
resource. This requires its callers to rebound those page allocations
from normal area.

So this patch moves the alloc_pages() call to the fallback routines.

Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
 kernel/dma/remap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel/dma/remap.c b/kernel/dma/remap.c
index 2b750f13bc8f..daab2f3186a2 100644
--- a/kernel/dma/remap.c
+++ b/kernel/dma/remap.c
@@ -116,7 +116,7 @@ int __init dma_atomic_pool_init(gfp_t gfp, pgprot_t prot)
 	if (dev_get_cma_area(NULL))
 		page = dma_alloc_from_contiguous(NULL, nr_pages,
 						 pool_size_order, false);
-	else
+	if (!page)
 		page = alloc_pages(gfp, pool_size_order);
 	if (!page)
 		goto out;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH RFC/RFT 3/5] iommu: amd_iommu: Add fallback normal page allocations
  2019-03-26 22:49 [PATCH RFC/RFT 0/5] Save single pages from CMA area Nicolin Chen
  2019-03-26 22:49 ` [PATCH RFC/RFT 1/5] ARM: dma-mapping: Add fallback normal page allocations Nicolin Chen
  2019-03-26 22:49 ` [PATCH RFC/RFT 2/5] dma-remap: Run alloc_pages() on failure Nicolin Chen
@ 2019-03-26 22:49 ` Nicolin Chen
  2019-03-26 22:49 ` [PATCH RFC/RFT 4/5] arm64: dma-mapping: " Nicolin Chen
  2019-03-26 22:49 ` [PATCH RFC/RFT 5/5] dma-contiguous: Do not allocate a single page from CMA area Nicolin Chen
  4 siblings, 0 replies; 7+ messages in thread
From: Nicolin Chen @ 2019-03-26 22:49 UTC (permalink / raw)
  To: hch, robin.murphy
  Cc: vdumpa, linux, catalin.marinas, will.deacon, joro, m.szyprowski,
	linux-arm-kernel, linux-kernel, iommu, tony

The CMA allocation will skip allocations of single pages to save CMA
resource. This requires its callers to rebound those page allocations
from normal area. So this patch adds fallback routines.

Note: amd_iommu driver uses dma_alloc_from_contiguous() as a fallback
      allocation and uses alloc_pages() as its first round allocation.
      This's in reverse order than other callers. So the alloc_pages()
      added by this change becomes a second fallback, though it likely
      won't succeed since the alloc_pages() has failed once.

Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
 drivers/iommu/amd_iommu.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 21cb088d6687..2aa4818f5249 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -2701,6 +2701,9 @@ static void *alloc_coherent(struct device *dev, size_t size,
 
 		page = dma_alloc_from_contiguous(dev, size >> PAGE_SHIFT,
 					get_order(size), flag & __GFP_NOWARN);
+		if (!page)
+			page = alloc_pages(flag | __GFP_NOWARN,
+					   get_order(size));
 		if (!page)
 			return NULL;
 	}
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH RFC/RFT 4/5] arm64: dma-mapping: Add fallback normal page allocations
  2019-03-26 22:49 [PATCH RFC/RFT 0/5] Save single pages from CMA area Nicolin Chen
                   ` (2 preceding siblings ...)
  2019-03-26 22:49 ` [PATCH RFC/RFT 3/5] iommu: amd_iommu: Add fallback normal page allocations Nicolin Chen
@ 2019-03-26 22:49 ` Nicolin Chen
  2019-03-26 22:49 ` [PATCH RFC/RFT 5/5] dma-contiguous: Do not allocate a single page from CMA area Nicolin Chen
  4 siblings, 0 replies; 7+ messages in thread
From: Nicolin Chen @ 2019-03-26 22:49 UTC (permalink / raw)
  To: hch, robin.murphy
  Cc: vdumpa, linux, catalin.marinas, will.deacon, joro, m.szyprowski,
	linux-arm-kernel, linux-kernel, iommu, tony

The cma allocation will skip allocations of single pages to save CMA
resource. This requires its callers to rebound those page allocations
from normal area. So this patch adds fallback routines.

Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
 arch/arm64/mm/dma-mapping.c | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index 78c0a72f822c..be2302533334 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -156,17 +156,20 @@ static void *__iommu_alloc_attrs(struct device *dev, size_t size,
 		}
 	} else if (attrs & DMA_ATTR_FORCE_CONTIGUOUS) {
 		pgprot_t prot = arch_dma_mmap_pgprot(dev, PAGE_KERNEL, attrs);
+		unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
 		struct page *page;
 
-		page = dma_alloc_from_contiguous(dev, size >> PAGE_SHIFT,
-					get_order(size), gfp & __GFP_NOWARN);
+		page = dma_alloc_from_contiguous(dev, count, get_order(size),
+						 gfp & __GFP_NOWARN);
+		if (!page)
+			page = alloc_pages(gfp, get_order(size));
 		if (!page)
 			return NULL;
 
 		*handle = iommu_dma_map_page(dev, page, 0, iosize, ioprot);
 		if (*handle == DMA_MAPPING_ERROR) {
-			dma_release_from_contiguous(dev, page,
-						    size >> PAGE_SHIFT);
+			if (!dma_release_from_contiguous(dev, page, count))
+				__free_pages(page, get_order(size));
 			return NULL;
 		}
 		addr = dma_common_contiguous_remap(page, size, VM_USERMAP,
@@ -178,8 +181,8 @@ static void *__iommu_alloc_attrs(struct device *dev, size_t size,
 			memset(addr, 0, size);
 		} else {
 			iommu_dma_unmap_page(dev, *handle, iosize, 0, attrs);
-			dma_release_from_contiguous(dev, page,
-						    size >> PAGE_SHIFT);
+			if (!dma_release_from_contiguous(dev, page, count))
+				__free_pages(page, get_order(size));
 		}
 	} else {
 		pgprot_t prot = arch_dma_mmap_pgprot(dev, PAGE_KERNEL, attrs);
@@ -201,6 +204,7 @@ static void *__iommu_alloc_attrs(struct device *dev, size_t size,
 static void __iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
 			       dma_addr_t handle, unsigned long attrs)
 {
+	unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
 	size_t iosize = size;
 
 	size = PAGE_ALIGN(size);
@@ -222,7 +226,8 @@ static void __iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
 		struct page *page = vmalloc_to_page(cpu_addr);
 
 		iommu_dma_unmap_page(dev, handle, iosize, 0, attrs);
-		dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT);
+		if (!dma_release_from_contiguous(dev, page, count))
+			__free_pages(page, get_order(size));
 		dma_common_free_remap(cpu_addr, size, VM_USERMAP);
 	} else if (is_vmalloc_addr(cpu_addr)){
 		struct vm_struct *area = find_vm_area(cpu_addr);
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH RFC/RFT 5/5] dma-contiguous: Do not allocate a single page from CMA area
  2019-03-26 22:49 [PATCH RFC/RFT 0/5] Save single pages from CMA area Nicolin Chen
                   ` (3 preceding siblings ...)
  2019-03-26 22:49 ` [PATCH RFC/RFT 4/5] arm64: dma-mapping: " Nicolin Chen
@ 2019-03-26 22:49 ` Nicolin Chen
  4 siblings, 0 replies; 7+ messages in thread
From: Nicolin Chen @ 2019-03-26 22:49 UTC (permalink / raw)
  To: hch, robin.murphy
  Cc: vdumpa, linux, catalin.marinas, will.deacon, joro, m.szyprowski,
	linux-arm-kernel, linux-kernel, iommu, tony

The addresses within a single page are always contiguous, so it's
not so necessary to always allocate one single page from CMA area.
Since the CMA area has a limited predefined size of space, it may
run out of space in heavy use cases, where there might be quite a
lot CMA pages being allocated for single pages.

However, there is also a concern that a device might care where a
page comes from -- it might expect the page from CMA area and act
differently if the page doesn't.

This patch tries to skip of one-page size allocations and returns
NULL so as to let callers allocate normal pages unless the device
has its own CMA area. This would save resources from the CMA area
for more CMA allocations. And it'd also reduce CMA fragmentations
resulted from trivial allocations.

Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
 kernel/dma/contiguous.c | 22 +++++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/kernel/dma/contiguous.c b/kernel/dma/contiguous.c
index b2a87905846d..09074bd04793 100644
--- a/kernel/dma/contiguous.c
+++ b/kernel/dma/contiguous.c
@@ -186,16 +186,32 @@ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base,
  *
  * This function allocates memory buffer for specified device. It uses
  * device specific contiguous memory area if available or the default
- * global one. Requires architecture specific dev_get_cma_area() helper
- * function.
+ * global one.
+ *
+ * However, it skips one-page size of allocations from the global area.
+ * As the addresses within one page are always contiguous, so there is
+ * no need to waste CMA pages for that kind; it also helps reduce the
+ * fragmentations in the CMA area. So a caller should be the rebounder
+ * in such case to allocate a normal page upon NULL return value.
+ *
+ * Requires architecture specific dev_get_cma_area() helper function.
  */
 struct page *dma_alloc_from_contiguous(struct device *dev, size_t count,
 				       unsigned int align, bool no_warn)
 {
+	struct cma *cma;
+
 	if (align > CONFIG_CMA_ALIGNMENT)
 		align = CONFIG_CMA_ALIGNMENT;
 
-	return cma_alloc(dev_get_cma_area(dev), count, align, no_warn);
+	if (dev && dev->cma_area)
+		cma = dev->cma_area;
+	else if (count > 1)
+		cma = dma_contiguous_default_area;
+	else
+		return NULL;
+
+	return cma_alloc(cma, count, align, no_warn);
 }
 
 /**
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH RFC/RFT 2/5] dma-remap: Run alloc_pages() on failure
  2019-03-26 22:49 ` [PATCH RFC/RFT 2/5] dma-remap: Run alloc_pages() on failure Nicolin Chen
@ 2019-03-26 22:53   ` Nicolin Chen
  0 siblings, 0 replies; 7+ messages in thread
From: Nicolin Chen @ 2019-03-26 22:53 UTC (permalink / raw)
  To: hch, robin.murphy
  Cc: vdumpa, linux, catalin.marinas, will.deacon, joro, m.szyprowski,
	linux-arm-kernel, linux-kernel, iommu, tony

On Tue, Mar 26, 2019 at 03:49:56PM -0700, Nicolin Chen wrote:
> @@ -116,7 +116,7 @@ int __init dma_atomic_pool_init(gfp_t gfp, pgprot_t prot)
>  	if (dev_get_cma_area(NULL))
>  		page = dma_alloc_from_contiguous(NULL, nr_pages,
>  						 pool_size_order, false);
> -	else
> +	if (!page)
>  		page = alloc_pages(gfp, pool_size_order);

Just realized a missing change in this patch, will send v2.
Please ignore this version.

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2019-03-26 22:53 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-03-26 22:49 [PATCH RFC/RFT 0/5] Save single pages from CMA area Nicolin Chen
2019-03-26 22:49 ` [PATCH RFC/RFT 1/5] ARM: dma-mapping: Add fallback normal page allocations Nicolin Chen
2019-03-26 22:49 ` [PATCH RFC/RFT 2/5] dma-remap: Run alloc_pages() on failure Nicolin Chen
2019-03-26 22:53   ` Nicolin Chen
2019-03-26 22:49 ` [PATCH RFC/RFT 3/5] iommu: amd_iommu: Add fallback normal page allocations Nicolin Chen
2019-03-26 22:49 ` [PATCH RFC/RFT 4/5] arm64: dma-mapping: " Nicolin Chen
2019-03-26 22:49 ` [PATCH RFC/RFT 5/5] dma-contiguous: Do not allocate a single page from CMA area Nicolin Chen

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).