mm: memmap_init: iterate over memblock regions rather that check each PFN
[linux-2.6-microblaze.git] / mm / page_alloc.c
index cbf0301..40587d7 100644 (file)
@@ -335,7 +335,6 @@ static unsigned long nr_kernel_pages __initdata;
 static unsigned long nr_all_pages __initdata;
 static unsigned long dma_reserve __initdata;
 
-#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
 static unsigned long arch_zone_lowest_possible_pfn[MAX_NR_ZONES] __initdata;
 static unsigned long arch_zone_highest_possible_pfn[MAX_NR_ZONES] __initdata;
 static unsigned long required_kernelcore __initdata;
@@ -348,7 +347,6 @@ static bool mirrored_kernelcore __meminitdata;
 /* movable_zone is the "real" zone pages in ZONE_MOVABLE are taken from */
 int movable_zone;
 EXPORT_SYMBOL(movable_zone);
-#endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */
 
 #if MAX_NUMNODES > 1
 unsigned int nr_node_ids __read_mostly = MAX_NUMNODES;
@@ -1499,11 +1497,35 @@ void __free_pages_core(struct page *page, unsigned int order)
        __free_pages(page, order);
 }
 
-#if defined(CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID) || \
-       defined(CONFIG_HAVE_MEMBLOCK_NODE_MAP)
+#ifdef CONFIG_NEED_MULTIPLE_NODES
 
 static struct mminit_pfnnid_cache early_pfnnid_cache __meminitdata;
 
+#ifndef CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID
+
+/*
+ * Required by SPARSEMEM. Given a PFN, return what node the PFN is on.
+ */
+int __meminit __early_pfn_to_nid(unsigned long pfn,
+                                       struct mminit_pfnnid_cache *state)
+{
+       unsigned long start_pfn, end_pfn;
+       int nid;
+
+       if (state->last_start <= pfn && pfn < state->last_end)
+               return state->last_nid;
+
+       nid = memblock_search_pfn_nid(pfn, &start_pfn, &end_pfn);
+       if (nid != NUMA_NO_NODE) {
+               state->last_start = start_pfn;
+               state->last_end = end_pfn;
+               state->last_nid = nid;
+       }
+
+       return nid;
+}
+#endif /* CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID */
+
 int __meminit early_pfn_to_nid(unsigned long pfn)
 {
        static DEFINE_SPINLOCK(early_pfn_lock);
@@ -1517,7 +1539,7 @@ int __meminit early_pfn_to_nid(unsigned long pfn)
 
        return nid;
 }
-#endif
+#endif /* CONFIG_NEED_MULTIPLE_NODES */
 
 #ifdef CONFIG_NODES_SPAN_OTHER_NODES
 /* Only safe to use early in boot when initialisation is single-threaded */
@@ -5319,7 +5341,7 @@ void show_free_areas(unsigned int filter, nodemask_t *nodemask)
 
        printk("active_anon:%lu inactive_anon:%lu isolated_anon:%lu\n"
                " active_file:%lu inactive_file:%lu isolated_file:%lu\n"
-               " unevictable:%lu dirty:%lu writeback:%lu unstable:%lu\n"
+               " unevictable:%lu dirty:%lu writeback:%lu\n"
                " slab_reclaimable:%lu slab_unreclaimable:%lu\n"
                " mapped:%lu shmem:%lu pagetables:%lu bounce:%lu\n"
                " free:%lu free_pcp:%lu free_cma:%lu\n",
@@ -5332,7 +5354,6 @@ void show_free_areas(unsigned int filter, nodemask_t *nodemask)
                global_node_page_state(NR_UNEVICTABLE),
                global_node_page_state(NR_FILE_DIRTY),
                global_node_page_state(NR_WRITEBACK),
-               global_node_page_state(NR_UNSTABLE_NFS),
                global_node_page_state(NR_SLAB_RECLAIMABLE),
                global_node_page_state(NR_SLAB_UNRECLAIMABLE),
                global_node_page_state(NR_FILE_MAPPED),
@@ -5365,7 +5386,6 @@ void show_free_areas(unsigned int filter, nodemask_t *nodemask)
                        " anon_thp: %lukB"
 #endif
                        " writeback_tmp:%lukB"
-                       " unstable:%lukB"
                        " all_unreclaimable? %s"
                        "\n",
                        pgdat->node_id,
@@ -5387,7 +5407,6 @@ void show_free_areas(unsigned int filter, nodemask_t *nodemask)
                        K(node_page_state(pgdat, NR_ANON_THPS) * HPAGE_PMD_NR),
 #endif
                        K(node_page_state(pgdat, NR_WRITEBACK_TEMP)),
-                       K(node_page_state(pgdat, NR_UNSTABLE_NFS)),
                        pgdat->kswapd_failures >= MAX_RECLAIM_RETRIES ?
                                "yes" : "no");
        }
@@ -5914,7 +5933,6 @@ void __ref build_all_zonelists(pg_data_t *pgdat)
 static bool __meminit
 overlap_memmap_init(unsigned long zone, unsigned long *pfn)
 {
-#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
        static struct memblock_region *r;
 
        if (mirrored_kernelcore && zone == ZONE_MOVABLE) {
@@ -5930,27 +5948,9 @@ overlap_memmap_init(unsigned long zone, unsigned long *pfn)
                        return true;
                }
        }
-#endif
        return false;
 }
 
-#ifdef CONFIG_SPARSEMEM
-/* Skip PFNs that belong to non-present sections */
-static inline __meminit unsigned long next_pfn(unsigned long pfn)
-{
-       const unsigned long section_nr = pfn_to_section_nr(++pfn);
-
-       if (present_section_nr(section_nr))
-               return pfn;
-       return section_nr_to_pfn(next_present_section_nr(section_nr));
-}
-#else
-static inline __meminit unsigned long next_pfn(unsigned long pfn)
-{
-       return pfn++;
-}
-#endif
-
 /*
  * Initially all pages are reserved - free ones are freed
  * up by memblock_free_all() once the early boot process is
@@ -5990,14 +5990,6 @@ void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone,
                 * function.  They do not exist on hotplugged memory.
                 */
                if (context == MEMMAP_EARLY) {
-                       if (!early_pfn_valid(pfn)) {
-                               pfn = next_pfn(pfn);
-                               continue;
-                       }
-                       if (!early_pfn_in_nid(pfn, nid)) {
-                               pfn++;
-                               continue;
-                       }
                        if (overlap_memmap_init(zone, &pfn))
                                continue;
                        if (defer_init(nid, pfn, end_pfn))
@@ -6113,9 +6105,23 @@ static void __meminit zone_init_free_lists(struct zone *zone)
 }
 
 void __meminit __weak memmap_init(unsigned long size, int nid,
-                                 unsigned long zone, unsigned long start_pfn)
+                                 unsigned long zone,
+                                 unsigned long range_start_pfn)
 {
-       memmap_init_zone(size, nid, zone, start_pfn, MEMMAP_EARLY, NULL);
+       unsigned long start_pfn, end_pfn;
+       unsigned long range_end_pfn = range_start_pfn + size;
+       int i;
+
+       for_each_mem_pfn_range(i, nid, &start_pfn, &end_pfn, NULL) {
+               start_pfn = clamp(start_pfn, range_start_pfn, range_end_pfn);
+               end_pfn = clamp(end_pfn, range_start_pfn, range_end_pfn);
+
+               if (end_pfn > start_pfn) {
+                       size = end_pfn - start_pfn;
+                       memmap_init_zone(size, nid, zone, start_pfn,
+                                        MEMMAP_EARLY, NULL);
+               }
+       }
 }
 
 static int zone_batchsize(struct zone *zone)
@@ -6313,32 +6319,6 @@ void __meminit init_currently_empty_zone(struct zone *zone,
        zone->initialized = 1;
 }
 
-#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
-#ifndef CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID
-
-/*
- * Required by SPARSEMEM. Given a PFN, return what node the PFN is on.
- */
-int __meminit __early_pfn_to_nid(unsigned long pfn,
-                                       struct mminit_pfnnid_cache *state)
-{
-       unsigned long start_pfn, end_pfn;
-       int nid;
-
-       if (state->last_start <= pfn && pfn < state->last_end)
-               return state->last_nid;
-
-       nid = memblock_search_pfn_nid(pfn, &start_pfn, &end_pfn);
-       if (nid != NUMA_NO_NODE) {
-               state->last_start = start_pfn;
-               state->last_end = end_pfn;
-               state->last_nid = nid;
-       }
-
-       return nid;
-}
-#endif /* CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID */
-
 /**
  * free_bootmem_with_active_regions - Call memblock_free_early_nid for each active range
  * @nid: The node to free memory on. If MAX_NUMNODES, all nodes are freed.
@@ -6589,8 +6569,7 @@ static unsigned long __init zone_absent_pages_in_node(int nid,
        return nr_absent;
 }
 
-#else /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */
-static inline unsigned long __init zone_spanned_pages_in_node(int nid,
+static inline unsigned long __init compat_zone_spanned_pages_in_node(int nid,
                                        unsigned long zone_type,
                                        unsigned long node_start_pfn,
                                        unsigned long node_end_pfn,
@@ -6609,7 +6588,7 @@ static inline unsigned long __init zone_spanned_pages_in_node(int nid,
        return zones_size[zone_type];
 }
 
-static inline unsigned long __init zone_absent_pages_in_node(int nid,
+static inline unsigned long __init compat_zone_absent_pages_in_node(int nid,
                                                unsigned long zone_type,
                                                unsigned long node_start_pfn,
                                                unsigned long node_end_pfn,
@@ -6621,13 +6600,12 @@ static inline unsigned long __init zone_absent_pages_in_node(int nid,
        return zholes_size[zone_type];
 }
 
-#endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */
-
 static void __init calculate_node_totalpages(struct pglist_data *pgdat,
                                                unsigned long node_start_pfn,
                                                unsigned long node_end_pfn,
                                                unsigned long *zones_size,
-                                               unsigned long *zholes_size)
+                                               unsigned long *zholes_size,
+                                               bool compat)
 {
        unsigned long realtotalpages = 0, totalpages = 0;
        enum zone_type i;
@@ -6635,17 +6613,38 @@ static void __init calculate_node_totalpages(struct pglist_data *pgdat,
        for (i = 0; i < MAX_NR_ZONES; i++) {
                struct zone *zone = pgdat->node_zones + i;
                unsigned long zone_start_pfn, zone_end_pfn;
+               unsigned long spanned, absent;
                unsigned long size, real_size;
 
-               size = zone_spanned_pages_in_node(pgdat->node_id, i,
-                                                 node_start_pfn,
-                                                 node_end_pfn,
-                                                 &zone_start_pfn,
-                                                 &zone_end_pfn,
-                                                 zones_size);
-               real_size = size - zone_absent_pages_in_node(pgdat->node_id, i,
-                                                 node_start_pfn, node_end_pfn,
-                                                 zholes_size);
+               if (compat) {
+                       spanned = compat_zone_spanned_pages_in_node(
+                                               pgdat->node_id, i,
+                                               node_start_pfn,
+                                               node_end_pfn,
+                                               &zone_start_pfn,
+                                               &zone_end_pfn,
+                                               zones_size);
+                       absent = compat_zone_absent_pages_in_node(
+                                               pgdat->node_id, i,
+                                               node_start_pfn,
+                                               node_end_pfn,
+                                               zholes_size);
+               } else {
+                       spanned = zone_spanned_pages_in_node(pgdat->node_id, i,
+                                               node_start_pfn,
+                                               node_end_pfn,
+                                               &zone_start_pfn,
+                                               &zone_end_pfn,
+                                               zones_size);
+                       absent = zone_absent_pages_in_node(pgdat->node_id, i,
+                                               node_start_pfn,
+                                               node_end_pfn,
+                                               zholes_size);
+               }
+
+               size = spanned;
+               real_size = size - absent;
+
                if (size)
                        zone->zone_start_pfn = zone_start_pfn;
                else
@@ -6945,10 +6944,8 @@ static void __ref alloc_node_mem_map(struct pglist_data *pgdat)
         */
        if (pgdat == NODE_DATA(0)) {
                mem_map = NODE_DATA(0)->node_mem_map;
-#if defined(CONFIG_HAVE_MEMBLOCK_NODE_MAP) || defined(CONFIG_FLATMEM)
                if (page_to_pfn(mem_map) != pgdat->node_start_pfn)
                        mem_map -= offset;
-#endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */
        }
 #endif
 }
@@ -6965,9 +6962,10 @@ static inline void pgdat_set_deferred_range(pg_data_t *pgdat)
 static inline void pgdat_set_deferred_range(pg_data_t *pgdat) {}
 #endif
 
-void __init free_area_init_node(int nid, unsigned long *zones_size,
-                                  unsigned long node_start_pfn,
-                                  unsigned long *zholes_size)
+static void __init __free_area_init_node(int nid, unsigned long *zones_size,
+                                        unsigned long node_start_pfn,
+                                        unsigned long *zholes_size,
+                                        bool compat)
 {
        pg_data_t *pgdat = NODE_DATA(nid);
        unsigned long start_pfn = 0;
@@ -6979,16 +6977,16 @@ void __init free_area_init_node(int nid, unsigned long *zones_size,
        pgdat->node_id = nid;
        pgdat->node_start_pfn = node_start_pfn;
        pgdat->per_cpu_nodestats = NULL;
-#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
-       get_pfn_range_for_nid(nid, &start_pfn, &end_pfn);
-       pr_info("Initmem setup node %d [mem %#018Lx-%#018Lx]\n", nid,
-               (u64)start_pfn << PAGE_SHIFT,
-               end_pfn ? ((u64)end_pfn << PAGE_SHIFT) - 1 : 0);
-#else
-       start_pfn = node_start_pfn;
-#endif
+       if (!compat) {
+               get_pfn_range_for_nid(nid, &start_pfn, &end_pfn);
+               pr_info("Initmem setup node %d [mem %#018Lx-%#018Lx]\n", nid,
+                       (u64)start_pfn << PAGE_SHIFT,
+                       end_pfn ? ((u64)end_pfn << PAGE_SHIFT) - 1 : 0);
+       } else {
+               start_pfn = node_start_pfn;
+       }
        calculate_node_totalpages(pgdat, start_pfn, end_pfn,
-                                 zones_size, zholes_size);
+                                 zones_size, zholes_size, compat);
 
        alloc_node_mem_map(pgdat);
        pgdat_set_deferred_range(pgdat);
@@ -6996,6 +6994,14 @@ void __init free_area_init_node(int nid, unsigned long *zones_size,
        free_area_init_core(pgdat);
 }
 
+void __init free_area_init_node(int nid, unsigned long *zones_size,
+                               unsigned long node_start_pfn,
+                               unsigned long *zholes_size)
+{
+       __free_area_init_node(nid, zones_size, node_start_pfn, zholes_size,
+                             true);
+}
+
 #if !defined(CONFIG_FLAT_NODE_MEM_MAP)
 /*
  * Initialize all valid struct pages in the range [spfn, epfn) and mark them
@@ -7079,8 +7085,6 @@ static inline void __init init_unavailable_mem(void)
 }
 #endif /* !CONFIG_FLAT_NODE_MEM_MAP */
 
-#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
-
 #if MAX_NUMNODES > 1
 /*
  * Figure out the number of possible node ids.
@@ -7223,7 +7227,7 @@ static void __init find_zone_movable_pfns_for_nodes(void)
                        if (!memblock_is_hotpluggable(r))
                                continue;
 
-                       nid = r->nid;
+                       nid = memblock_get_region_node(r);
 
                        usable_startpfn = PFN_DOWN(r->base);
                        zone_movable_pfn[nid] = zone_movable_pfn[nid] ?
@@ -7244,7 +7248,7 @@ static void __init find_zone_movable_pfns_for_nodes(void)
                        if (memblock_is_mirror(r))
                                continue;
 
-                       nid = r->nid;
+                       nid = memblock_get_region_node(r);
 
                        usable_startpfn = memblock_region_memory_base_pfn(r);
 
@@ -7425,7 +7429,7 @@ static void check_for_memory(pg_data_t *pgdat, int nid)
 }
 
 /**
- * free_area_init_nodes - Initialise all pg_data_t and zone data
+ * free_area_init - Initialise all pg_data_t and zone data
  * @max_zone_pfn: an array of max PFNs for each zone
  *
  * This will call free_area_init_node() for each active node in the system.
@@ -7437,7 +7441,7 @@ static void check_for_memory(pg_data_t *pgdat, int nid)
  * starts where the previous one ended. For example, ZONE_DMA32 starts
  * at arch_max_dma_pfn.
  */
-void __init free_area_init_nodes(unsigned long *max_zone_pfn)
+void __init free_area_init(unsigned long *max_zone_pfn)
 {
        unsigned long start_pfn, end_pfn;
        int i, nid;
@@ -7509,8 +7513,8 @@ void __init free_area_init_nodes(unsigned long *max_zone_pfn)
        init_unavailable_mem();
        for_each_online_node(nid) {
                pg_data_t *pgdat = NODE_DATA(nid);
-               free_area_init_node(nid, NULL,
-                               find_min_pfn_for_node(nid), NULL);
+               __free_area_init_node(nid, NULL,
+                                     find_min_pfn_for_node(nid), NULL, false);
 
                /* Any memory on that node */
                if (pgdat->node_present_pages)
@@ -7575,8 +7579,6 @@ static int __init cmdline_parse_movablecore(char *p)
 early_param("kernelcore", cmdline_parse_kernelcore);
 early_param("movablecore", cmdline_parse_movablecore);
 
-#endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */
-
 void adjust_managed_page_count(struct page *page, long count)
 {
        atomic_long_add(count, &page_zone(page)->managed_pages);
@@ -7699,13 +7701,6 @@ void __init set_dma_reserve(unsigned long new_dma_reserve)
        dma_reserve = new_dma_reserve;
 }
 
-void __init free_area_init(unsigned long *zones_size)
-{
-       init_unavailable_mem();
-       free_area_init_node(0, zones_size,
-                       __pa(PAGE_OFFSET) >> PAGE_SHIFT, NULL);
-}
-
 static int page_alloc_cpu_dead(unsigned int cpu)
 {
 
@@ -8253,7 +8248,7 @@ void *__init alloc_large_system_hash(const char *tablename,
                                table = memblock_alloc_raw(size,
                                                           SMP_CACHE_BYTES);
                } else if (get_order(size) >= MAX_ORDER || hashdist) {
-                       table = __vmalloc(size, gfp_flags, PAGE_KERNEL);
+                       table = __vmalloc(size, gfp_flags);
                        virt = true;
                } else {
                        /*