Linux s390 Architecture development
 help / color / mirror / Atom feed
From: Thierry Reding <thierry.reding@kernel.org>
To: "Rob Herring" <robh@kernel.org>,
	"Krzysztof Kozlowski" <krzk+dt@kernel.org>,
	"Conor Dooley" <conor+dt@kernel.org>,
	"Thierry Reding" <thierry.reding@kernel.org>,
	"Jonathan Hunter" <jonathanh@nvidia.com>,
	"David Airlie" <airlied@gmail.com>,
	"Simona Vetter" <simona@ffwll.ch>,
	"Maarten Lankhorst" <maarten.lankhorst@linux.intel.com>,
	"Maxime Ripard" <mripard@kernel.org>,
	"Thomas Zimmermann" <tzimmermann@suse.de>,
	"Sowjanya Komatineni" <skomatineni@nvidia.com>,
	"Luca Ceresoli" <luca.ceresoli@bootlin.com>,
	"Mikko Perttunen" <mperttunen@nvidia.com>,
	"Yury Norov" <yury.norov@gmail.com>,
	"Rasmus Villemoes" <linux@rasmusvillemoes.dk>,
	"Russell King" <linux@armlinux.org.uk>,
	"Alexander Gordeev" <agordeev@linux.ibm.com>,
	"Gerald Schaefer" <gerald.schaefer@linux.ibm.com>,
	"Heiko Carstens" <hca@linux.ibm.com>,
	"Vasily Gorbik" <gor@linux.ibm.com>,
	"Christian Borntraeger" <borntraeger@linux.ibm.com>,
	"Sven Schnelle" <svens@linux.ibm.com>,
	"Andrew Morton" <akpm@linux-foundation.org>,
	"David Hildenbrand" <david@kernel.org>,
	"Lorenzo Stoakes" <ljs@kernel.org>,
	"Liam R. Howlett" <liam@infradead.org>,
	"Vlastimil Babka" <vbabka@kernel.org>,
	"Mike Rapoport" <rppt@kernel.org>,
	"Suren Baghdasaryan" <surenb@google.com>,
	"Michal Hocko" <mhocko@suse.com>,
	"Marek Szyprowski" <m.szyprowski@samsung.com>,
	"Robin Murphy" <robin.murphy@arm.com>,
	"Sumit Semwal" <sumit.semwal@linaro.org>,
	"Benjamin Gaignard" <benjamin.gaignard@collabora.com>,
	"Brian Starkey" <Brian.Starkey@arm.com>,
	"John Stultz" <jstultz@google.com>,
	"T.J. Mercier" <tjmercier@google.com>,
	"Christian König" <christian.koenig@amd.com>,
	"Steven Rostedt" <rostedt@goodmis.org>,
	"Masami Hiramatsu" <mhiramat@kernel.org>,
	"Mathieu Desnoyers" <mathieu.desnoyers@efficios.com>,
	"Catalin Marinas" <catalin.marinas@arm.com>,
	"Will Deacon" <will@kernel.org>, "Chun Ng" <chunn@nvidia.com>,
	"Mark Rutland" <mark.rutland@arm.com>,
	"Saravana Kannan" <saravanak@kernel.org>
Cc: Thierry Reding <thierry.reding@gmail.com>,
	devicetree@vger.kernel.org,  linux-tegra@vger.kernel.org,
	linux-kernel@vger.kernel.org,  dri-devel@lists.freedesktop.org,
	linux-media@vger.kernel.org,
	 linux-arm-kernel@lists.infradead.org,
	linux-s390@vger.kernel.org,  linux-mm@kvack.org,
	iommu@lists.linux.dev, linaro-mm-sig@lists.linaro.org,
	 linux-trace-kernel@vger.kernel.org,
	Thierry Reding <treding@nvidia.com>
Subject: [PATCH v6 07/12] mm/cma: Introduce cma_alloc_at() API
Date: Fri, 04 Sep 2026 12:44:58 +0200	[thread overview]
Message-ID: <20260904-tegra-vpr-v6-7-79042cfa8de5@nvidia.com> (raw)
In-Reply-To: <20260904-tegra-vpr-v6-0-79042cfa8de5@nvidia.com>

From: Thierry Reding <treding@nvidia.com>

This API can be used to allocate a number of CMA pages starting at a
fixed offset. This is useful, for example, if the CMA area is used as
backing storage for a nested allocator that has stricter requirements
than CMA itself.

In order to reuse most of the existing code, the cma_range_alloc()
function is enhanced to take as inputs a range of pages to look for a
free region. If this range encompasses the entire CMA range, the
behavior is as before, but the range can also be specified to match
the offset and size passed in from cma_alloc_at(), in which case that
is the range that will be allocated (or allocation will fail if the
range is not available).

Suggested-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
---
Changes in v6:
- refactor cma_range_alloc() so it can be reused for _at() code paths
---
 include/linux/cma.h        |  4 +++
 include/trace/events/cma.h | 77 ++++++++++++++++++++++++++++++++++++++--
 mm/cma.c                   | 88 +++++++++++++++++++++++++++++++++++-----------
 3 files changed, 146 insertions(+), 23 deletions(-)

diff --git a/include/linux/cma.h b/include/linux/cma.h
index 8555d38a97b1..844404459a42 100644
--- a/include/linux/cma.h
+++ b/include/linux/cma.h
@@ -49,11 +49,15 @@ extern int cma_init_reserved_mem(phys_addr_t base, phys_addr_t size,
 					struct cma **res_cma);
 extern struct page *cma_alloc(struct cma *cma, unsigned long count, unsigned int align,
 			      bool no_warn);
+extern struct page *cma_alloc_at(struct cma *cma, unsigned long offset,
+				 unsigned long count, bool no_warn);
 extern bool cma_release(struct cma *cma, const struct page *pages, unsigned long count);
 
 struct page *cma_alloc_frozen(struct cma *cma, unsigned long count,
 		unsigned int align, bool no_warn);
 struct page *cma_alloc_frozen_compound(struct cma *cma, unsigned int order);
+struct page *cma_alloc_at_frozen(struct cma *cma, unsigned long offset,
+				 unsigned long count, bool no_warn);
 bool cma_release_frozen(struct cma *cma, const struct page *pages,
 		unsigned long count);
 
diff --git a/include/trace/events/cma.h b/include/trace/events/cma.h
index 37195edf2498..4e0ab63e303f 100644
--- a/include/trace/events/cma.h
+++ b/include/trace/events/cma.h
@@ -38,13 +38,17 @@ TRACE_EVENT(cma_release,
 
 TRACE_EVENT(cma_alloc_start,
 
-	TP_PROTO(const char *name, unsigned long request_count, unsigned long available_count,
+	TP_PROTO(const char *name, unsigned long start, unsigned long end,
+		unsigned long request_count, unsigned long available_count,
 		unsigned long total_count, unsigned int align),
 
-	TP_ARGS(name, request_count, available_count, total_count, align),
+	TP_ARGS(name, start, end, request_count, available_count, total_count,
+		align),
 
 	TP_STRUCT__entry(
 		__string(name, name)
+		__field(unsigned long, start)
+		__field(unsigned long, end)
 		__field(unsigned long, request_count)
 		__field(unsigned long, available_count)
 		__field(unsigned long, total_count)
@@ -53,14 +57,18 @@ TRACE_EVENT(cma_alloc_start,
 
 	TP_fast_assign(
 		__assign_str(name);
+		__entry->start = start;
+		__entry->end = end;
 		__entry->request_count = request_count;
 		__entry->available_count = available_count;
 		__entry->total_count = total_count;
 		__entry->align = align;
 	),
 
-	TP_printk("name=%s request_count=%lu available_count=%lu total_count=%lu align=%u",
+	TP_printk("name=%s start=%lu end=%lu request_count=%lu available_count=%lu total_count=%lu align=%u",
 		  __get_str(name),
+		  __entry->start,
+		  __entry->end,
 		  __entry->request_count,
 		  __entry->available_count,
 		  __entry->total_count,
@@ -132,6 +140,69 @@ TRACE_EVENT(cma_alloc_busy_retry,
 		  __entry->align)
 );
 
+TRACE_EVENT(cma_alloc_at_start,
+
+	TP_PROTO(const char *name, unsigned long pfn,
+		 unsigned long request_count, unsigned long available_count,
+		 unsigned long total_count),
+
+	TP_ARGS(name, pfn, request_count, available_count, total_count),
+
+	TP_STRUCT__entry(
+		__string(name, name)
+		__field(unsigned long, pfn)
+		__field(unsigned long, request_count)
+		__field(unsigned long, available_count)
+		__field(unsigned long, total_count)
+	),
+
+	TP_fast_assign(
+		__assign_str(name);
+		__entry->pfn = pfn;
+		__entry->request_count = request_count;
+		__entry->available_count = available_count;
+		__entry->total_count = total_count;
+	),
+
+	TP_printk("name=%s pfn=%lx, request_count=%lu available_count=%lu total_count=%lu",
+		  __get_str(name),
+		  __entry->pfn,
+		  __entry->request_count,
+		  __entry->available_count,
+		  __entry->total_count)
+);
+
+TRACE_EVENT(cma_alloc_at_finish,
+
+	TP_PROTO(const char *name, unsigned long pfn, const struct page *page,
+		 unsigned long count, int errorno),
+
+	TP_ARGS(name, pfn, page, count, errorno),
+
+	TP_STRUCT__entry(
+		__string(name, name)
+		__field(unsigned long, pfn)
+		__field(const struct page *, page)
+		__field(unsigned long, count)
+		__field(int, errorno)
+	),
+
+	TP_fast_assign(
+		__assign_str(name);
+		__entry->pfn = pfn;
+		__entry->page = page;
+		__entry->count = count;
+		__entry->errorno = errorno;
+	),
+
+	TP_printk("name=%s pfn=0x%lx page=%p count=%lu errorno=%d",
+		  __get_str(name),
+		  __entry->pfn,
+		  __entry->page,
+		  __entry->count,
+		  __entry->errorno)
+);
+
 #endif /* _TRACE_CMA_H */
 
 /* This part must be outside protection */
diff --git a/mm/cma.c b/mm/cma.c
index a10ea37a261d..f92d3a188209 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -783,25 +783,32 @@ static void cma_debug_show_areas(struct cma *cma)
 	spin_unlock_irq(&cma->lock);
 }
 
+/*
+ * Searches the CMA memrange, from @start to @end, for a free region of
+ * @count bits. If @end is less or equal to @start, will search the entire
+ * memrange.
+ */
 static int cma_range_alloc(struct cma *cma, struct cma_memrange *cmr,
-				unsigned long count, unsigned int align,
-				struct page **pagep, gfp_t gfp)
+			   unsigned long start, unsigned long end,
+			   unsigned long count, unsigned int align,
+			   struct page **pagep, gfp_t gfp)
 {
 	unsigned long bitmap_maxno, bitmap_no, bitmap_count;
-	unsigned long start, pfn, mask, offset;
-	int ret = -EBUSY;
+	unsigned long pfn, mask, offset;
 	struct page *page = NULL;
+	int ret = -EBUSY;
 
 	mask = cma_bitmap_aligned_mask(cma, align);
 	offset = cma_bitmap_aligned_offset(cma, cmr, align);
-	bitmap_maxno = cma_bitmap_maxno(cma, cmr);
+	bitmap_maxno = (end > start) ? end : cma_bitmap_maxno(cma, cmr);
 	bitmap_count = cma_bitmap_pages_to_bits(cma, count);
 
 	if (bitmap_count > bitmap_maxno)
 		goto out;
 
-	for (start = 0; ; start = bitmap_no + mask + 1) {
+	while (true) {
 		spin_lock_irq(&cma->lock);
+
 		/*
 		 * If the request is larger than the available number
 		 * of pages, stop right away.
@@ -810,6 +817,7 @@ static int cma_range_alloc(struct cma *cma, struct cma_memrange *cmr,
 			spin_unlock_irq(&cma->lock);
 			break;
 		}
+
 		bitmap_no = bitmap_find_next_zero_area_off(cmr->bitmap,
 				bitmap_maxno, start, bitmap_count, mask,
 				offset);
@@ -835,10 +843,11 @@ static int cma_range_alloc(struct cma *cma, struct cma_memrange *cmr,
 
 		bitmap_set(cmr->bitmap, bitmap_no, bitmap_count);
 		cma->available_count -= count;
+
 		/*
-		 * It's safe to drop the lock here. We've marked this region for
-		 * our exclusive use. If the migration fails we will take the
-		 * lock again and unmark it.
+		 * It's safe to drop the lock here. We've marked this region
+		 * for our exclusive use. If the migration fails we will take
+		 * the lock again and unmark it.
 		 */
 		spin_unlock_irq(&cma->lock);
 
@@ -856,37 +865,45 @@ static int cma_range_alloc(struct cma *cma, struct cma_memrange *cmr,
 			 __func__, pfn, page);
 
 		trace_cma_alloc_busy_retry(cma->name, pfn, page, count, align);
+		start = bitmap_no + mask + 1;
 	}
+
 out:
 	if (!ret)
 		*pagep = page;
+
 	return ret;
 }
 
-static struct page *__cma_alloc_frozen(struct cma *cma,
-		unsigned long count, unsigned int align, gfp_t gfp)
+static struct page *__cma_alloc_frozen(struct cma *cma, unsigned long start,
+				       unsigned long end, unsigned long count,
+				       unsigned int align, gfp_t gfp)
 {
 	struct page *page = NULL;
 	int ret = -ENOMEM, r;
 	unsigned long i;
-	const char *name = cma ? cma->name : NULL;
+
+	/* cma_alloc_at() and friends will only work with single-range CMA */
+	if (WARN_ON_ONCE(start > 0 && cma->nranges != 1))
+		return page;
 
 	if (!cma || !cma->count)
 		return page;
 
-	pr_debug("%s(cma %p, name: %s, count %lu, align %d)\n", __func__,
-		(void *)cma, cma->name, count, align);
+	pr_debug("%s(cma %p, name: %s, start %lu, end %lu, count %lu, align %d)\n",
+		 __func__, (void *)cma, cma->name, start, end, count, align);
 
 	if (!count)
 		return page;
 
-	trace_cma_alloc_start(name, count, cma->available_count, cma->count, align);
+	trace_cma_alloc_start(cma->name, start, end, count,
+			      cma->available_count, cma->count, align);
 
 	for (r = 0; r < cma->nranges; r++) {
 		page = NULL;
 
-		ret = cma_range_alloc(cma, &cma->ranges[r], count, align,
-				       &page, gfp);
+		ret = cma_range_alloc(cma, &cma->ranges[r], start, end,
+				      count, align, &page, gfp);
 		if (ret != -EBUSY || page)
 			break;
 	}
@@ -908,7 +925,7 @@ static struct page *__cma_alloc_frozen(struct cma *cma,
 	}
 
 	pr_debug("%s(): returned %p\n", __func__, page);
-	trace_cma_alloc_finish(name, page ? page_to_pfn(page) : 0,
+	trace_cma_alloc_finish(cma->name, page ? page_to_pfn(page) : 0,
 			       page, count, align, ret);
 	if (page) {
 		count_vm_event(CMA_ALLOC_SUCCESS);
@@ -926,14 +943,22 @@ struct page *cma_alloc_frozen(struct cma *cma, unsigned long count,
 {
 	gfp_t gfp = GFP_KERNEL | (no_warn ? __GFP_NOWARN : 0);
 
-	return __cma_alloc_frozen(cma, count, align, gfp);
+	return __cma_alloc_frozen(cma, 0, 0, count, align, gfp);
 }
 
 struct page *cma_alloc_frozen_compound(struct cma *cma, unsigned int order)
 {
 	gfp_t gfp = GFP_KERNEL | __GFP_COMP | __GFP_NOWARN;
 
-	return __cma_alloc_frozen(cma, 1 << order, order, gfp);
+	return __cma_alloc_frozen(cma, 0, 0, 1 << order, order, gfp);
+}
+
+struct page *cma_alloc_at_frozen(struct cma *cma, unsigned long offset,
+				 unsigned long count, bool no_warn)
+{
+	gfp_t gfp = GFP_KERNEL | (no_warn ? __GFP_NOWARN : 0);
+
+	return __cma_alloc_frozen(cma, offset, offset + count, count, 0, gfp);
 }
 
 /**
@@ -959,6 +984,29 @@ struct page *cma_alloc(struct cma *cma, unsigned long count,
 }
 EXPORT_SYMBOL_GPL(cma_alloc);
 
+/**
+ * cma_alloc_at() - allocate pages from contiguous area at fixed offset
+ * @cma:     Contiguous memory region for which the allocation is performed.
+ * @offset:  Index of the first page to allocate.
+ * @count:   Requested number of pages (in PAGE_SIZE order).
+ * @no_warn: Avoid printing message about failed allocation.
+ *
+ * This function allocates a part of the contiguous memory on a specific
+ * contiguous memory area.
+ */
+struct page *cma_alloc_at(struct cma *cma, unsigned long offset,
+			  unsigned long count, bool no_warn)
+{
+	struct page *page;
+
+	page = cma_alloc_at_frozen(cma, offset, count, no_warn);
+	if (page)
+		set_pages_refcounted(page, count);
+
+	return page;
+}
+EXPORT_SYMBOL_GPL(cma_alloc_at);
+
 static struct cma_memrange *find_cma_memrange(struct cma *cma,
 		const struct page *pages, unsigned long count)
 {

-- 
2.55.0


  parent reply	other threads:[~2026-09-04 10:45 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-04 10:44 [PATCH v6 00/12] dma-buf: heaps: Add support for Tegra VPR Thierry Reding
2026-09-04 10:44 ` [PATCH v6 01/12] dt-bindings: reserved-memory: Document " Thierry Reding
2026-09-04 10:59   ` sashiko-bot
2026-09-04 10:44 ` [PATCH v6 02/12] dt-bindings: display: tegra: Document memory regions Thierry Reding
2026-09-04 10:56   ` sashiko-bot
2026-09-04 10:44 ` [PATCH v6 03/12] dt-bindings: gpu: host1x: Document memory-regions for NVDEC Thierry Reding
2026-09-04 11:03   ` sashiko-bot
2026-09-04 10:44 ` [PATCH v6 04/12] arm64/mm: Export set_direct_map_*_noflush() APIs Thierry Reding
2026-09-04 11:13   ` sashiko-bot
2026-09-04 10:44 ` [PATCH v6 05/12] bitmap: Add bitmap_allocate() function Thierry Reding
2026-09-04 11:13   ` sashiko-bot
2026-09-04 10:44 ` [PATCH v6 06/12] of: Export of_node_to_nid() Thierry Reding
2026-09-04 11:21   ` sashiko-bot
2026-09-04 10:44 ` Thierry Reding [this message]
2026-09-04 11:22   ` [PATCH v6 07/12] mm/cma: Introduce cma_alloc_at() API sashiko-bot
2026-09-04 10:44 ` [PATCH v6 08/12] dma-buf: heaps: Add debugfs support Thierry Reding
2026-09-04 11:34   ` sashiko-bot
2026-09-04 10:45 ` [PATCH v6 09/12] dma-buf: heaps: Add support for Tegra VPR Thierry Reding
2026-09-04 11:38   ` sashiko-bot
2026-09-04 10:45 ` [PATCH v6 10/12] arm64: tegra: Add VPR placeholder node on Tegra234 Thierry Reding
2026-09-04 11:54   ` sashiko-bot
2026-09-04 10:45 ` [PATCH v6 11/12] arm64: tegra: Hook up VPR to host1x Thierry Reding
2026-09-04 11:49   ` sashiko-bot
2026-09-04 10:45 ` [PATCH v6 12/12] arm64: tegra: Add VPR placeholder node on Tegra264 Thierry Reding
2026-09-04 11:53   ` sashiko-bot
2026-09-04 11:41 ` [PATCH v6 00/12] dma-buf: heaps: Add support for Tegra VPR Will Deacon

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260904-tegra-vpr-v6-7-79042cfa8de5@nvidia.com \
    --to=thierry.reding@kernel.org \
    --cc=Brian.Starkey@arm.com \
    --cc=agordeev@linux.ibm.com \
    --cc=airlied@gmail.com \
    --cc=akpm@linux-foundation.org \
    --cc=benjamin.gaignard@collabora.com \
    --cc=borntraeger@linux.ibm.com \
    --cc=catalin.marinas@arm.com \
    --cc=christian.koenig@amd.com \
    --cc=chunn@nvidia.com \
    --cc=conor+dt@kernel.org \
    --cc=david@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=gerald.schaefer@linux.ibm.com \
    --cc=gor@linux.ibm.com \
    --cc=hca@linux.ibm.com \
    --cc=iommu@lists.linux.dev \
    --cc=jonathanh@nvidia.com \
    --cc=jstultz@google.com \
    --cc=krzk+dt@kernel.org \
    --cc=liam@infradead.org \
    --cc=linaro-mm-sig@lists.linaro.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=linux-s390@vger.kernel.org \
    --cc=linux-tegra@vger.kernel.org \
    --cc=linux-trace-kernel@vger.kernel.org \
    --cc=linux@armlinux.org.uk \
    --cc=linux@rasmusvillemoes.dk \
    --cc=ljs@kernel.org \
    --cc=luca.ceresoli@bootlin.com \
    --cc=m.szyprowski@samsung.com \
    --cc=maarten.lankhorst@linux.intel.com \
    --cc=mark.rutland@arm.com \
    --cc=mathieu.desnoyers@efficios.com \
    --cc=mhiramat@kernel.org \
    --cc=mhocko@suse.com \
    --cc=mperttunen@nvidia.com \
    --cc=mripard@kernel.org \
    --cc=robh@kernel.org \
    --cc=robin.murphy@arm.com \
    --cc=rostedt@goodmis.org \
    --cc=rppt@kernel.org \
    --cc=saravanak@kernel.org \
    --cc=simona@ffwll.ch \
    --cc=skomatineni@nvidia.com \
    --cc=sumit.semwal@linaro.org \
    --cc=surenb@google.com \
    --cc=svens@linux.ibm.com \
    --cc=thierry.reding@gmail.com \
    --cc=tjmercier@google.com \
    --cc=treding@nvidia.com \
    --cc=tzimmermann@suse.de \
    --cc=vbabka@kernel.org \
    --cc=will@kernel.org \
    --cc=yury.norov@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox