ANDROID: integrate GCMA with CMA using dt-bindings

This patch introduces a new "guarantee" property for shared-dma-pool.
With the property, admin can create specific memory pool as
GCMA-based-CMA if they care about allocation success rate and latency
without reserving a dedicated memory area.

Bug: 236887352
Bug: 270089503
Bug: 391879760
Change-Id: I3a019f889f7ffa4d2255609c19b15078b9c5b6a4
Signed-off-by: Minchan Kim <minchan@google.com>
Signed-off-by: Suren Baghdasaryan <surenb@google.com>
This commit is contained in:
Suren Baghdasaryan
2025-02-28 11:16:51 -08:00
committed by Carlos Llamas
parent 80a603a57a
commit 0dad457899
6 changed files with 49 additions and 11 deletions
+1 -1
View File
@@ -95,7 +95,7 @@ void __init fadump_cma_init(void)
base = fw_dump.reserve_dump_area_start;
size = fw_dump.boot_memory_size;
rc = cma_init_reserved_mem(base, size, 0, "fadump_cma", &fadump_cma);
rc = cma_init_reserved_mem(base, size, 0, "fadump_cma", &fadump_cma, false);
if (rc) {
pr_err("Failed to init cma area for firmware-assisted dump,%d\n", rc);
/*
+2 -1
View File
@@ -43,7 +43,8 @@ static inline int __init cma_declare_contiguous(phys_addr_t base,
extern int cma_init_reserved_mem(phys_addr_t base, phys_addr_t size,
unsigned int order_per_bit,
const char *name,
struct cma **res_cma);
struct cma **res_cma,
bool gcma);
extern struct page *__cma_alloc(struct cma *cma, unsigned long count, unsigned int align,
gfp_t gfp_mask);
extern struct page *cma_alloc(struct cma *cma, unsigned long count, unsigned int align,
+10 -1
View File
@@ -465,6 +465,7 @@ static int __init rmem_cma_setup(struct reserved_mem *rmem)
unsigned long node = rmem->fdt_node;
bool default_cma = of_get_flat_dt_prop(node, "linux,cma-default", NULL);
struct cma *cma;
bool gcma;
int err;
if (size_cmdline != -1 && default_cma) {
@@ -482,7 +483,15 @@ static int __init rmem_cma_setup(struct reserved_mem *rmem)
return -EINVAL;
}
err = cma_init_reserved_mem(rmem->base, rmem->size, 0, rmem->name, &cma);
gcma = !!of_get_flat_dt_prop(node, "guarantee", NULL);
#ifndef CONFIG_GCMA
if (gcma) {
pr_err("Reserved memory: unable to setup GCMA region, GCMA is not enabled\n");
return -EINVAL;
}
#endif
err = cma_init_reserved_mem(rmem->base, rmem->size, 0, rmem->name,
&cma, gcma);
if (err) {
pr_err("Reserved memory: unable to setup CMA region\n");
return err;
+25 -8
View File
@@ -29,6 +29,7 @@
#include <linux/kmemleak.h>
#include <linux/sched.h>
#include <linux/jiffies.h>
#include <linux/gcma.h>
#define CREATE_TRACE_POINTS
#include <trace/events/cma.h>
#undef CREATE_TRACE_POINTS
@@ -126,9 +127,14 @@ static void __init cma_activate_area(struct cma *cma)
goto not_in_zone;
}
for (pfn = base_pfn; pfn < base_pfn + cma->count;
pfn += pageblock_nr_pages)
init_cma_reserved_pageblock(pfn_to_page(pfn));
if (cma->gcma) {
register_gcma_area(cma->name, PFN_PHYS(base_pfn),
cma->count << PAGE_SHIFT);
} else {
for (pfn = base_pfn; pfn < base_pfn + cma->count;
pfn += pageblock_nr_pages)
init_cma_reserved_pageblock(pfn_to_page(pfn));
}
spin_lock_init(&cma->lock);
@@ -186,7 +192,7 @@ void __init cma_reserve_pages_on_error(struct cma *cma)
int __init cma_init_reserved_mem(phys_addr_t base, phys_addr_t size,
unsigned int order_per_bit,
const char *name,
struct cma **res_cma)
struct cma **res_cma, bool gcma)
{
struct cma *cma;
@@ -212,11 +218,13 @@ int __init cma_init_reserved_mem(phys_addr_t base, phys_addr_t size,
if (name)
snprintf(cma->name, CMA_MAX_NAME, name);
else
snprintf(cma->name, CMA_MAX_NAME, "cma%d\n", cma_area_count);
snprintf(cma->name, CMA_MAX_NAME,
gcma ? "gcma%d\n" : "cma%d\n", cma_area_count);
cma->base_pfn = PFN_DOWN(base);
cma->count = size >> PAGE_SHIFT;
cma->order_per_bit = order_per_bit;
cma->gcma = gcma;
*res_cma = cma;
cma_area_count++;
totalcma_pages += cma->count;
@@ -379,7 +387,8 @@ int __init cma_declare_contiguous_nid(phys_addr_t base,
base = addr;
}
ret = cma_init_reserved_mem(base, size, order_per_bit, name, res_cma);
ret = cma_init_reserved_mem(base, size, order_per_bit, name, res_cma,
false);
if (ret)
goto free_mem;
@@ -509,7 +518,12 @@ struct page *__cma_alloc(struct cma *cma, unsigned long count,
pfn = cma->base_pfn + (bitmap_no << cma->order_per_bit);
mutex_lock(&cma_mutex);
ret = alloc_contig_range(pfn, pfn + count, MIGRATE_CMA, gfp);
if (cma->gcma) {
gcma_alloc_range(pfn, pfn + count - 1);
ret = 0;
} else {
ret = alloc_contig_range(pfn, pfn + count, MIGRATE_CMA, gfp);
}
mutex_unlock(&cma_mutex);
if (ret == 0) {
page = pfn_to_page(pfn);
@@ -632,7 +646,10 @@ bool cma_release(struct cma *cma, const struct page *pages,
VM_BUG_ON(pfn + count > cma->base_pfn + cma->count);
free_contig_range(pfn, count);
if (cma->gcma)
gcma_free_range(pfn, pfn + count - 1);
else
free_contig_range(pfn, count);
cma_clear_bitmap(cma, pfn, count);
cma_sysfs_account_release_pages(cma, count);
trace_cma_release(cma->name, pfn, pages, count);
+1
View File
@@ -23,6 +23,7 @@ struct cma {
struct debugfs_u32_array dfs_bitmap;
#endif
char name[CMA_MAX_NAME];
bool gcma;
#ifdef CONFIG_CMA_SYSFS
/* the number of CMA page successful allocations */
atomic64_t nr_pages_succeeded;
+10
View File
@@ -62,6 +62,15 @@ static ssize_t release_pages_success_show(struct kobject *kobj,
}
CMA_ATTR_RO(release_pages_success);
static ssize_t gcma_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct cma *cma = cma_from_kobj(kobj);
return sysfs_emit(buf, "%d\n", cma->gcma);
}
CMA_ATTR_RO(gcma);
static void cma_kobj_release(struct kobject *kobj)
{
struct cma *cma = cma_from_kobj(kobj);
@@ -75,6 +84,7 @@ static struct attribute *cma_attrs[] = {
&alloc_pages_success_attr.attr,
&alloc_pages_fail_attr.attr,
&release_pages_success_attr.attr,
&gcma_attr.attr,
NULL,
};
ATTRIBUTE_GROUPS(cma);