summaryrefslogtreecommitdiff
path: root/drivers/of/of_reserved_mem.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/of/of_reserved_mem.c')
-rw-r--r--drivers/of/of_reserved_mem.c34
1 files changed, 27 insertions, 7 deletions
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
index 9da8835ba5a5..f38f1fa23a86 100644
--- a/drivers/of/of_reserved_mem.c
+++ b/drivers/of/of_reserved_mem.c
@@ -29,11 +29,12 @@
static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS];
static int reserved_mem_count;
-static int __init early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
- phys_addr_t align, phys_addr_t start, phys_addr_t end, bool nomap,
- phys_addr_t *res_base)
+static int __init early_init_dt_alloc_reserved_memory_arch(unsigned long node,
+ phys_addr_t size, phys_addr_t align, phys_addr_t start,
+ phys_addr_t end, bool nomap, phys_addr_t *res_base)
{
phys_addr_t base;
+ phys_addr_t highmem_start = __pa(high_memory - 1) + 1;
int err = 0;
end = !end ? MEMBLOCK_ALLOC_ANYWHERE : end;
@@ -42,6 +43,25 @@ static int __init early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
if (!base)
return -ENOMEM;
+
+ /*
+ * Sanity check for the cma reserved region:If the reserved region
+ * crosses the low/high memory boundary, try to fix it up and then
+ * fall back to allocate the cma region from the low mememory space.
+ */
+
+ if (IS_ENABLED(CONFIG_CMA)
+ && of_flat_dt_is_compatible(node, "shared-dma-pool")
+ && of_get_flat_dt_prop(node, "reusable", NULL) && !nomap) {
+ if (base < highmem_start && (base + size) > highmem_start) {
+ memblock_free(base, size);
+ base = memblock_phys_alloc_range(size, align, start,
+ highmem_start);
+ if (!base)
+ return -ENOMEM;
+ }
+ }
+
*res_base = base;
if (nomap) {
err = memblock_mark_nomap(base, size);
@@ -139,8 +159,8 @@ static int __init __reserved_mem_alloc_size(unsigned long node,
end = start + dt_mem_next_cell(dt_root_size_cells,
&prop);
- ret = early_init_dt_alloc_reserved_memory_arch(size,
- align, start, end, nomap, &base);
+ ret = early_init_dt_alloc_reserved_memory_arch(node,
+ size, align, start, end, nomap, &base);
if (ret == 0) {
pr_debug("allocated memory for '%s' node: base %pa, size %lu MiB\n",
uname, &base,
@@ -151,8 +171,8 @@ static int __init __reserved_mem_alloc_size(unsigned long node,
}
} else {
- ret = early_init_dt_alloc_reserved_memory_arch(size, align,
- 0, 0, nomap, &base);
+ ret = early_init_dt_alloc_reserved_memory_arch(node,
+ size, align, 0, 0, nomap, &base);
if (ret == 0)
pr_debug("allocated memory for '%s' node: base %pa, size %lu MiB\n",
uname, &base, (unsigned long)(size / SZ_1M));