aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>2014-10-24 06:18:41 -0400
committerMarek Szyprowski <m.szyprowski@samsung.com>2014-10-27 08:00:54 -0400
commit16195ddd4ebcc10c30b2f232f8e400df8d464380 (patch)
tree7fe365184316ad8211913feeddbf99f457c01318 /mm
parent800a85d3d286604b8c539ca7ee90b992316fd2a7 (diff)
mm: cma: Ensure that reservations never cross the low/high mem boundary
Commit 95b0e655f914 ("ARM: mm: don't limit default CMA region only to low memory") extended CMA memory reservation to allow usage of high memory. It relied on commit f7426b983a6a ("mm: cma: adjust address limit to avoid hitting low/high memory boundary") to ensure that the reserved block never crossed the low/high memory boundary. While the implementation correctly lowered the limit, it failed to consider the case where the base..limit range crossed the low/high memory boundary with enough space on each side to reserve the requested size on either low or high memory. Rework the base and limit adjustment to fix the problem. The function now starts by rejecting the reservation altogether for fixed reservations that cross the boundary, tries to reserve from high memory first and then falls back to low memory. Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Diffstat (limited to 'mm')
-rw-r--r--mm/cma.c49
1 files changed, 33 insertions, 16 deletions
diff --git a/mm/cma.c b/mm/cma.c
index 62a5dccc3fb8..c30a6edee65c 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -253,23 +253,24 @@ int __init cma_declare_contiguous(phys_addr_t base,
253 return -EINVAL; 253 return -EINVAL;
254 254
255 /* 255 /*
256 * adjust limit to avoid crossing low/high memory boundary for 256 * If allocating at a fixed base the request region must not cross the
257 * automatically allocated regions 257 * low/high memory boundary.
258 */ 258 */
259 if (((limit == 0 || limit > memblock_end) && 259 if (fixed && base < highmem_start && base + size > highmem_start) {
260 (memblock_end - size < highmem_start &&
261 memblock_end > highmem_start)) ||
262 (!fixed && limit > highmem_start && limit - size < highmem_start)) {
263 limit = highmem_start;
264 }
265
266 if (fixed && base < highmem_start && base+size > highmem_start) {
267 ret = -EINVAL; 260 ret = -EINVAL;
268 pr_err("Region at %08lx defined on low/high memory boundary (%08lx)\n", 261 pr_err("Region at %08lx defined on low/high memory boundary (%08lx)\n",
269 (unsigned long)base, (unsigned long)highmem_start); 262 (unsigned long)base, (unsigned long)highmem_start);
270 goto err; 263 goto err;
271 } 264 }
272 265
266 /*
267 * If the limit is unspecified or above the memblock end, its effective
268 * value will be the memblock end. Set it explicitly to simplify further
269 * checks.
270 */
271 if (limit == 0 || limit > memblock_end)
272 limit = memblock_end;
273
273 /* Reserve memory */ 274 /* Reserve memory */
274 if (fixed) { 275 if (fixed) {
275 if (memblock_is_region_reserved(base, size) || 276 if (memblock_is_region_reserved(base, size) ||
@@ -278,14 +279,30 @@ int __init cma_declare_contiguous(phys_addr_t base,
278 goto err; 279 goto err;
279 } 280 }
280 } else { 281 } else {
281 phys_addr_t addr = memblock_alloc_range(size, alignment, base, 282 phys_addr_t addr = 0;
282 limit); 283
284 /*
285 * All pages in the reserved area must come from the same zone.
286 * If the requested region crosses the low/high memory boundary,
287 * try allocating from high memory first and fall back to low
288 * memory in case of failure.
289 */
290 if (base < highmem_start && limit > highmem_start) {
291 addr = memblock_alloc_range(size, alignment,
292 highmem_start, limit);
293 limit = highmem_start;
294 }
295
283 if (!addr) { 296 if (!addr) {
284 ret = -ENOMEM; 297 addr = memblock_alloc_range(size, alignment, base,
285 goto err; 298 limit);
286 } else { 299 if (!addr) {
287 base = addr; 300 ret = -ENOMEM;
301 goto err;
302 }
288 } 303 }
304
305 base = addr;
289 } 306 }
290 307
291 ret = cma_init_reserved_mem(base, size, order_per_bit, res_cma); 308 ret = cma_init_reserved_mem(base, size, order_per_bit, res_cma);