return sizeof(struct mem_section_usage) + usemap_size();
}
-#ifdef CONFIG_MEMORY_HOTREMOVE
-static inline phys_addr_t pgdat_to_phys(struct pglist_data *pgdat)
-{
-#ifndef CONFIG_NUMA
- VM_BUG_ON(pgdat != &contig_page_data);
- return __pa_symbol(&contig_page_data);
-#else
- return __pa(pgdat);
-#endif
-}
-
-static struct mem_section_usage * __init
-sparse_early_usemaps_alloc_pgdat_section(struct pglist_data *pgdat,
- unsigned long size)
-{
- struct mem_section_usage *usage;
- unsigned long goal, limit;
- int nid;
- /*
- * A page may contain usemaps for other sections preventing the
- * page being freed and making a section unremovable while
- * other sections referencing the usemap remain active. Similarly,
- * a pgdat can prevent a section being removed. If section A
- * contains a pgdat and section B contains the usemap, both
- * sections become inter-dependent. This allocates usemaps
- * from the same section as the pgdat where possible to avoid
- * this problem.
- */
- goal = pgdat_to_phys(pgdat) & (PAGE_SECTION_MASK << PAGE_SHIFT);
- limit = goal + (1UL << PA_SECTION_SHIFT);
- nid = early_pfn_to_nid(goal >> PAGE_SHIFT);
-again:
- usage = memblock_alloc_try_nid(size, SMP_CACHE_BYTES, goal, limit, nid);
- if (!usage && limit) {
- limit = MEMBLOCK_ALLOC_ACCESSIBLE;
- goto again;
- }
- return usage;
-}
-
-static void __init check_usemap_section_nr(int nid,
- struct mem_section_usage *usage)
-{
- unsigned long usemap_snr, pgdat_snr;
- static unsigned long old_usemap_snr;
- static unsigned long old_pgdat_snr;
- struct pglist_data *pgdat = NODE_DATA(nid);
- int usemap_nid;
-
- /* First call */
- if (!old_usemap_snr) {
- old_usemap_snr = NR_MEM_SECTIONS;
- old_pgdat_snr = NR_MEM_SECTIONS;
- }
-
- usemap_snr = pfn_to_section_nr(__pa(usage) >> PAGE_SHIFT);
- pgdat_snr = pfn_to_section_nr(pgdat_to_phys(pgdat) >> PAGE_SHIFT);
- if (usemap_snr == pgdat_snr)
- return;
-
- if (old_usemap_snr == usemap_snr && old_pgdat_snr == pgdat_snr)
- /* skip redundant message */
- return;
-
- old_usemap_snr = usemap_snr;
- old_pgdat_snr = pgdat_snr;
-
- usemap_nid = sparse_early_nid(__nr_to_section(usemap_snr));
- if (usemap_nid != nid) {
- pr_info("node %d must be removed before remove section %ld\n",
- nid, usemap_snr);
- return;
- }
- /*
- * There is a circular dependency.
- * Some platforms allow un-removable section because they will just
- * gather other removable sections for dynamic partitioning.
- * Just notify un-removable section's number here.
- */
- pr_info("Section %ld and %ld (node %d) have a circular dependency on usemap and pgdat allocations\n",
- usemap_snr, pgdat_snr, nid);
-}
-#else
-static struct mem_section_usage * __init
-sparse_early_usemaps_alloc_pgdat_section(struct pglist_data *pgdat,
- unsigned long size)
-{
- return memblock_alloc_node(size, SMP_CACHE_BYTES, pgdat->node_id);
-}
-
-static void __init check_usemap_section_nr(int nid,
- struct mem_section_usage *usage)
-{
-}
-#endif /* CONFIG_MEMORY_HOTREMOVE */
-
#ifdef CONFIG_SPARSEMEM_VMEMMAP
unsigned long __init section_map_size(void)
{
unsigned long pnum, unsigned long flags)
{
BUG_ON(!sparse_usagebuf || sparse_usagebuf >= sparse_usagebuf_end);
- check_usemap_section_nr(nid, sparse_usagebuf);
sparse_init_one_section(__nr_to_section(pnum), pnum, map,
sparse_usagebuf, SECTION_IS_EARLY | flags);
sparse_usagebuf = (void *)sparse_usagebuf + mem_section_usage_size();
unsigned long size;
size = mem_section_usage_size() * map_count;
- sparse_usagebuf = sparse_early_usemaps_alloc_pgdat_section(
- NODE_DATA(nid), size);
+ sparse_usagebuf = memblock_alloc_node(size, SMP_CACHE_BYTES, nid);
if (!sparse_usagebuf) {
sparse_usagebuf_end = NULL;
return -ENOMEM;