|
@@ -253,23 +253,24 @@ int __init cma_declare_contiguous(phys_addr_t base,
|
|
|
return -EINVAL;
|
|
|
|
|
|
/*
|
|
|
- * adjust limit to avoid crossing low/high memory boundary for
|
|
|
- * automatically allocated regions
|
|
|
+ * If allocating at a fixed base the request region must not cross the
|
|
|
+ * low/high memory boundary.
|
|
|
*/
|
|
|
- if (((limit == 0 || limit > memblock_end) &&
|
|
|
- (memblock_end - size < highmem_start &&
|
|
|
- memblock_end > highmem_start)) ||
|
|
|
- (!fixed && limit > highmem_start && limit - size < highmem_start)) {
|
|
|
- limit = highmem_start;
|
|
|
- }
|
|
|
-
|
|
|
- if (fixed && base < highmem_start && base+size > highmem_start) {
|
|
|
+ if (fixed && base < highmem_start && base + size > highmem_start) {
|
|
|
ret = -EINVAL;
|
|
|
pr_err("Region at %08lx defined on low/high memory boundary (%08lx)\n",
|
|
|
(unsigned long)base, (unsigned long)highmem_start);
|
|
|
goto err;
|
|
|
}
|
|
|
|
|
|
+ /*
|
|
|
+ * If the limit is unspecified or above the memblock end, its effective
|
|
|
+ * value will be the memblock end. Set it explicitly to simplify further
|
|
|
+ * checks.
|
|
|
+ */
|
|
|
+ if (limit == 0 || limit > memblock_end)
|
|
|
+ limit = memblock_end;
|
|
|
+
|
|
|
/* Reserve memory */
|
|
|
if (fixed) {
|
|
|
if (memblock_is_region_reserved(base, size) ||
|
|
@@ -278,14 +279,30 @@ int __init cma_declare_contiguous(phys_addr_t base,
|
|
|
goto err;
|
|
|
}
|
|
|
} else {
|
|
|
- phys_addr_t addr = memblock_alloc_range(size, alignment, base,
|
|
|
- limit);
|
|
|
+ phys_addr_t addr = 0;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * All pages in the reserved area must come from the same zone.
|
|
|
+ * If the requested region crosses the low/high memory boundary,
|
|
|
+ * try allocating from high memory first and fall back to low
|
|
|
+ * memory in case of failure.
|
|
|
+ */
|
|
|
+ if (base < highmem_start && limit > highmem_start) {
|
|
|
+ addr = memblock_alloc_range(size, alignment,
|
|
|
+ highmem_start, limit);
|
|
|
+ limit = highmem_start;
|
|
|
+ }
|
|
|
+
|
|
|
if (!addr) {
|
|
|
- ret = -ENOMEM;
|
|
|
- goto err;
|
|
|
- } else {
|
|
|
- base = addr;
|
|
|
+ addr = memblock_alloc_range(size, alignment, base,
|
|
|
+ limit);
|
|
|
+ if (!addr) {
|
|
|
+ ret = -ENOMEM;
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
+ base = addr;
|
|
|
}
|
|
|
|
|
|
ret = cma_init_reserved_mem(base, size, order_per_bit, res_cma);
|