aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/memblock.h20
-rw-r--r--mm/memblock.c76
2 files changed, 96 insertions, 0 deletions
diff --git a/include/linux/memblock.h b/include/linux/memblock.h
index c36a55d3c1c2..31def584cceb 100644
--- a/include/linux/memblock.h
+++ b/include/linux/memblock.h
@@ -61,6 +61,26 @@ extern long memblock_remove(phys_addr_t base, phys_addr_t size);
61extern long memblock_free(phys_addr_t base, phys_addr_t size); 61extern long memblock_free(phys_addr_t base, phys_addr_t size);
62extern long memblock_reserve(phys_addr_t base, phys_addr_t size); 62extern long memblock_reserve(phys_addr_t base, phys_addr_t size);
63 63
64extern void __next_free_mem_range(u64 *idx, int nid, phys_addr_t *out_start,
65 phys_addr_t *out_end, int *out_nid);
66
67/**
68 * for_each_free_mem_range - iterate through free memblock areas
69 * @i: u64 used as loop variable
70 * @nid: node selector, %MAX_NUMNODES for all nodes
71 * @p_start: ptr to phys_addr_t for start address of the range, can be %NULL
72 * @p_end: ptr to phys_addr_t for end address of the range, can be %NULL
73 * @p_nid: ptr to int for nid of the range, can be %NULL
74 *
75 * Walks over free (memory && !reserved) areas of memblock. Available as
76 * soon as memblock is initialized.
77 */
78#define for_each_free_mem_range(i, nid, p_start, p_end, p_nid) \
79 for (i = 0, \
80 __next_free_mem_range(&i, nid, p_start, p_end, p_nid); \
81 i != (u64)ULLONG_MAX; \
82 __next_free_mem_range(&i, nid, p_start, p_end, p_nid))
83
64#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP 84#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
65extern int memblock_set_node(phys_addr_t base, phys_addr_t size, int nid); 85extern int memblock_set_node(phys_addr_t base, phys_addr_t size, int nid);
66 86
diff --git a/mm/memblock.c b/mm/memblock.c
index e815f4b75809..c4a8750406fc 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -461,6 +461,82 @@ long __init_memblock memblock_reserve(phys_addr_t base, phys_addr_t size)
461 return memblock_add_region(_rgn, base, size); 461 return memblock_add_region(_rgn, base, size);
462} 462}
463 463
464/**
465 * __next_free_mem_range - next function for for_each_free_mem_range()
466 * @idx: pointer to u64 loop variable
467 * @nid: nid: node selector, %MAX_NUMNODES for all nodes
468 * @p_start: ptr to phys_addr_t for start address of the range, can be %NULL
469 * @p_end: ptr to phys_addr_t for end address of the range, can be %NULL
470 * @p_nid: ptr to int for nid of the range, can be %NULL
471 *
472 * Find the first free area from *@idx which matches @nid, fill the out
473 * parameters, and update *@idx for the next iteration. The lower 32bit of
474 * *@idx contains index into memory region and the upper 32bit indexes the
475 * areas before each reserved region. For example, if reserved regions
476 * look like the following,
477 *
478 * 0:[0-16), 1:[32-48), 2:[128-130)
479 *
480 * The upper 32bit indexes the following regions.
481 *
482 * 0:[0-0), 1:[16-32), 2:[48-128), 3:[130-MAX)
483 *
484 * As both region arrays are sorted, the function advances the two indices
485 * in lockstep and returns each intersection.
486 */
487void __init_memblock __next_free_mem_range(u64 *idx, int nid,
488 phys_addr_t *out_start,
489 phys_addr_t *out_end, int *out_nid)
490{
491 struct memblock_type *mem = &memblock.memory;
492 struct memblock_type *rsv = &memblock.reserved;
493 int mi = *idx & 0xffffffff;
494 int ri = *idx >> 32;
495
496 for ( ; mi < mem->cnt; mi++) {
497 struct memblock_region *m = &mem->regions[mi];
498 phys_addr_t m_start = m->base;
499 phys_addr_t m_end = m->base + m->size;
500
501 /* only memory regions are associated with nodes, check it */
502 if (nid != MAX_NUMNODES && nid != memblock_get_region_node(m))
503 continue;
504
505 /* scan areas before each reservation for intersection */
506 for ( ; ri < rsv->cnt + 1; ri++) {
507 struct memblock_region *r = &rsv->regions[ri];
508 phys_addr_t r_start = ri ? r[-1].base + r[-1].size : 0;
509 phys_addr_t r_end = ri < rsv->cnt ? r->base : ULLONG_MAX;
510
511 /* if ri advanced past mi, break out to advance mi */
512 if (r_start >= m_end)
513 break;
514 /* if the two regions intersect, we're done */
515 if (m_start < r_end) {
516 if (out_start)
517 *out_start = max(m_start, r_start);
518 if (out_end)
519 *out_end = min(m_end, r_end);
520 if (out_nid)
521 *out_nid = memblock_get_region_node(m);
522 /*
523 * The region which ends first is advanced
524 * for the next iteration.
525 */
526 if (m_end <= r_end)
527 mi++;
528 else
529 ri++;
530 *idx = (u32)mi | (u64)ri << 32;
531 return;
532 }
533 }
534 }
535
536 /* signal end of iteration */
537 *idx = ULLONG_MAX;
538}
539
464#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP 540#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
465/* 541/*
466 * Common iterator interface used to define for_each_mem_range(). 542 * Common iterator interface used to define for_each_mem_range().