x86, mm: Move init_memory_mapping calling out of setup.c
[deliverable/linux.git] / arch / x86 / mm / init.c
index ab1f6a93b527c9bd50acc12a52e9ce157f2cc48b..9e17f9e18a21ce821a4356dd36440ae6394792b8 100644 (file)
@@ -35,61 +35,32 @@ struct map_range {
        unsigned page_size_mask;
 };
 
-static void __init find_early_table_space(struct map_range *mr, unsigned long end,
-                                         int use_pse, int use_gbpages)
-{
-       unsigned long puds, pmds, ptes, tables, start = 0, good_end = end;
-       phys_addr_t base;
-
-       puds = (end + PUD_SIZE - 1) >> PUD_SHIFT;
-       tables = roundup(puds * sizeof(pud_t), PAGE_SIZE);
-
-       if (use_gbpages) {
-               unsigned long extra;
-
-               extra = end - ((end>>PUD_SHIFT) << PUD_SHIFT);
-               pmds = (extra + PMD_SIZE - 1) >> PMD_SHIFT;
-       } else
-               pmds = (end + PMD_SIZE - 1) >> PMD_SHIFT;
-
-       tables += roundup(pmds * sizeof(pmd_t), PAGE_SIZE);
-
-       if (use_pse) {
-               unsigned long extra;
+static int page_size_mask;
 
-               extra = end - ((end>>PMD_SHIFT) << PMD_SHIFT);
-#ifdef CONFIG_X86_32
-               extra += PMD_SIZE;
-#endif
-               /* The first 2/4M doesn't use large pages. */
-               if (mr->start < PMD_SIZE)
-                       extra += mr->end - mr->start;
-
-               ptes = (extra + PAGE_SIZE - 1) >> PAGE_SHIFT;
-       } else
-               ptes = (end + PAGE_SIZE - 1) >> PAGE_SHIFT;
-
-       tables += roundup(ptes * sizeof(pte_t), PAGE_SIZE);
-
-#ifdef CONFIG_X86_32
-       /* for fixmap */
-       tables += roundup(__end_of_fixed_addresses * sizeof(pte_t), PAGE_SIZE);
+static void __init probe_page_size_mask(void)
+{
+#if !defined(CONFIG_DEBUG_PAGEALLOC) && !defined(CONFIG_KMEMCHECK)
+       /*
+        * For CONFIG_DEBUG_PAGEALLOC, identity mapping will use small pages.
+        * This will simplify cpa(), which otherwise needs to support splitting
+        * large pages into small in interrupt context, etc.
+        */
+       if (direct_gbpages)
+               page_size_mask |= 1 << PG_LEVEL_1G;
+       if (cpu_has_pse)
+               page_size_mask |= 1 << PG_LEVEL_2M;
 #endif
-       good_end = max_pfn_mapped << PAGE_SHIFT;
-
-       base = memblock_find_in_range(start, good_end, tables, PAGE_SIZE);
-       if (!base)
-               panic("Cannot find space for the kernel page tables");
 
-       pgt_buf_start = base >> PAGE_SHIFT;
-       pgt_buf_end = pgt_buf_start;
-       pgt_buf_top = pgt_buf_start + (tables >> PAGE_SHIFT);
+       /* Enable PSE if available */
+       if (cpu_has_pse)
+               set_in_cr4(X86_CR4_PSE);
 
-       printk(KERN_DEBUG "kernel direct mapping tables up to %#lx @ [mem %#010lx-%#010lx]\n",
-               end - 1, pgt_buf_start << PAGE_SHIFT,
-               (pgt_buf_top << PAGE_SHIFT) - 1);
+       /* Enable PGE if available */
+       if (cpu_has_pge) {
+               set_in_cr4(X86_CR4_PGE);
+               __supported_pte_mask |= _PAGE_GLOBAL;
+       }
 }
-
 void __init native_pagetable_reserve(u64 start, u64 end)
 {
        memblock_reserve(start, end - start);
@@ -117,55 +88,13 @@ static int __meminit save_mr(struct map_range *mr, int nr_range,
        return nr_range;
 }
 
-/*
- * Setup the direct mapping of the physical memory at PAGE_OFFSET.
- * This runs before bootmem is initialized and gets pages directly from
- * the physical memory. To access them they are temporarily mapped.
- */
-unsigned long __init_refok init_memory_mapping(unsigned long start,
-                                              unsigned long end)
+static int __meminit split_mem_range(struct map_range *mr, int nr_range,
+                                    unsigned long start,
+                                    unsigned long end)
 {
-       unsigned long page_size_mask = 0;
        unsigned long start_pfn, end_pfn;
-       unsigned long ret = 0;
        unsigned long pos;
-
-       struct map_range mr[NR_RANGE_MR];
-       int nr_range, i;
-       int use_pse, use_gbpages;
-
-       printk(KERN_INFO "init_memory_mapping: [mem %#010lx-%#010lx]\n",
-              start, end - 1);
-
-#if defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_KMEMCHECK)
-       /*
-        * For CONFIG_DEBUG_PAGEALLOC, identity mapping will use small pages.
-        * This will simplify cpa(), which otherwise needs to support splitting
-        * large pages into small in interrupt context, etc.
-        */
-       use_pse = use_gbpages = 0;
-#else
-       use_pse = cpu_has_pse;
-       use_gbpages = direct_gbpages;
-#endif
-
-       /* Enable PSE if available */
-       if (cpu_has_pse)
-               set_in_cr4(X86_CR4_PSE);
-
-       /* Enable PGE if available */
-       if (cpu_has_pge) {
-               set_in_cr4(X86_CR4_PGE);
-               __supported_pte_mask |= _PAGE_GLOBAL;
-       }
-
-       if (use_gbpages)
-               page_size_mask |= 1 << PG_LEVEL_1G;
-       if (use_pse)
-               page_size_mask |= 1 << PG_LEVEL_2M;
-
-       memset(mr, 0, sizeof(mr));
-       nr_range = 0;
+       int i;
 
        /* head if not big page alignment ? */
        start_pfn = start >> PAGE_SHIFT;
@@ -259,6 +188,86 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
                        (mr[i].page_size_mask & (1<<PG_LEVEL_1G))?"1G":(
                         (mr[i].page_size_mask & (1<<PG_LEVEL_2M))?"2M":"4k"));
 
+       return nr_range;
+}
+
+/*
+ * First calculate space needed for kernel direct mapping page tables to cover
+ * mr[0].start to mr[nr_range - 1].end, while accounting for possible 2M and 1GB
+ * pages. Then find enough contiguous space for those page tables.
+ */
+static void __init find_early_table_space(struct map_range *mr, int nr_range)
+{
+       int i;
+       unsigned long puds = 0, pmds = 0, ptes = 0, tables;
+       unsigned long start = 0, good_end;
+       phys_addr_t base;
+
+       for (i = 0; i < nr_range; i++) {
+               unsigned long range, extra;
+
+               range = mr[i].end - mr[i].start;
+               puds += (range + PUD_SIZE - 1) >> PUD_SHIFT;
+
+               if (mr[i].page_size_mask & (1 << PG_LEVEL_1G)) {
+                       extra = range - ((range >> PUD_SHIFT) << PUD_SHIFT);
+                       pmds += (extra + PMD_SIZE - 1) >> PMD_SHIFT;
+               } else {
+                       pmds += (range + PMD_SIZE - 1) >> PMD_SHIFT;
+               }
+
+               if (mr[i].page_size_mask & (1 << PG_LEVEL_2M)) {
+                       extra = range - ((range >> PMD_SHIFT) << PMD_SHIFT);
+#ifdef CONFIG_X86_32
+                       extra += PMD_SIZE;
+#endif
+                       ptes += (extra + PAGE_SIZE - 1) >> PAGE_SHIFT;
+               } else {
+                       ptes += (range + PAGE_SIZE - 1) >> PAGE_SHIFT;
+               }
+       }
+
+       tables = roundup(puds * sizeof(pud_t), PAGE_SIZE);
+       tables += roundup(pmds * sizeof(pmd_t), PAGE_SIZE);
+       tables += roundup(ptes * sizeof(pte_t), PAGE_SIZE);
+
+#ifdef CONFIG_X86_32
+       /* for fixmap */
+       tables += roundup(__end_of_fixed_addresses * sizeof(pte_t), PAGE_SIZE);
+#endif
+       good_end = max_pfn_mapped << PAGE_SHIFT;
+
+       base = memblock_find_in_range(start, good_end, tables, PAGE_SIZE);
+       if (!base)
+               panic("Cannot find space for the kernel page tables");
+
+       pgt_buf_start = base >> PAGE_SHIFT;
+       pgt_buf_end = pgt_buf_start;
+       pgt_buf_top = pgt_buf_start + (tables >> PAGE_SHIFT);
+
+       printk(KERN_DEBUG "kernel direct mapping tables up to %#lx @ [mem %#010lx-%#010lx]\n",
+               mr[nr_range - 1].end - 1, pgt_buf_start << PAGE_SHIFT,
+               (pgt_buf_top << PAGE_SHIFT) - 1);
+}
+
+/*
+ * Setup the direct mapping of the physical memory at PAGE_OFFSET.
+ * This runs before bootmem is initialized and gets pages directly from
+ * the physical memory. To access them they are temporarily mapped.
+ */
+unsigned long __init_refok init_memory_mapping(unsigned long start,
+                                              unsigned long end)
+{
+       struct map_range mr[NR_RANGE_MR];
+       unsigned long ret = 0;
+       int nr_range, i;
+
+       pr_info("init_memory_mapping: [mem %#010lx-%#010lx]\n",
+              start, end - 1);
+
+       memset(mr, 0, sizeof(mr));
+       nr_range = split_mem_range(mr, 0, start, end);
+
        /*
         * Find space for the kernel direct mapping tables.
         *
@@ -267,7 +276,7 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
         * nodes are discovered.
         */
        if (!after_bootmem)
-               find_early_table_space(&mr[0], end, use_pse, use_gbpages);
+               find_early_table_space(mr, nr_range);
 
        for (i = 0; i < nr_range; i++)
                ret = kernel_physical_mapping_init(mr[i].start, mr[i].end,
@@ -306,6 +315,23 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
        return ret >> PAGE_SHIFT;
 }
 
+void __init init_mem_mapping(void)
+{
+       probe_page_size_mask();
+
+       /* max_pfn_mapped is updated here */
+       max_low_pfn_mapped = init_memory_mapping(0, max_low_pfn<<PAGE_SHIFT);
+       max_pfn_mapped = max_low_pfn_mapped;
+
+#ifdef CONFIG_X86_64
+       if (max_pfn > max_low_pfn) {
+               max_pfn_mapped = init_memory_mapping(1UL<<32,
+                                                    max_pfn<<PAGE_SHIFT);
+               /* can we preseve max_low_pfn ?*/
+               max_low_pfn = max_pfn;
+       }
+#endif
+}
 
 /*
  * devmem_is_allowed() checks to see if /dev/mem access to a certain address
This page took 0.032134 seconds and 5 git commands to generate.