]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - arch/x86_64/mm/init.c
[PATCH] x86_64: Account mem_map in VM holes accounting
[karo-tx-linux.git] / arch / x86_64 / mm / init.c
index 72e4b364ed739bd25a4c31800664445801d8cc3b..2b1d6c382396ec17d8d2ac353f6c96b037d138c4 100644 (file)
@@ -47,6 +47,8 @@ extern int swiotlb;
 
 extern char _stext[];
 
+static unsigned long dma_reserve __initdata;
+
 DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 
 /*
@@ -57,31 +59,31 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 
 void show_mem(void)
 {
-       int i, total = 0, reserved = 0;
-       int shared = 0, cached = 0;
+       long i, total = 0, reserved = 0;
+       long shared = 0, cached = 0;
        pg_data_t *pgdat;
        struct page *page;
 
-       printk("Mem-info:\n");
+       printk(KERN_INFO "Mem-info:\n");
        show_free_areas();
-       printk("Free swap:       %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
+       printk(KERN_INFO "Free swap:       %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
 
        for_each_pgdat(pgdat) {
                for (i = 0; i < pgdat->node_spanned_pages; ++i) {
                        page = pfn_to_page(pgdat->node_start_pfn + i);
                        total++;
-                       if (PageReserved(page))
-                       reserved++;
-                       else if (PageSwapCache(page))
-                       cached++;
-                       else if (page_count(page))
-                               shared += page_count(page) - 1;
+                       if (PageReserved(page))
+                               reserved++;
+                       else if (PageSwapCache(page))
+                               cached++;
+                       else if (page_count(page))
+                               shared += page_count(page) - 1;
                }
        }
-       printk("%d pages of RAM\n", total);
-       printk("%d reserved pages\n",reserved);
-       printk("%d pages shared\n",shared);
-       printk("%d pages swap cached\n",cached);
+       printk(KERN_INFO "%lu pages of RAM\n", total);
+       printk(KERN_INFO "%lu reserved pages\n",reserved);
+       printk(KERN_INFO "%lu pages shared\n",shared);
+       printk(KERN_INFO "%lu pages swap cached\n",cached);
 }
 
 /* References to section boundaries */
@@ -318,24 +320,66 @@ void zap_low_mappings(void)
        flush_tlb_all();
 }
 
-#ifndef CONFIG_NUMA
-void __init paging_init(void)
+/* Compute zone sizes for the DMA and DMA32 zones in a node. */
+__init void
+size_zones(unsigned long *z, unsigned long *h,
+          unsigned long start_pfn, unsigned long end_pfn)
 {
-       {
-               unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
-               unsigned int max_dma;
+       int i;
+       unsigned long w;
+
+       for (i = 0; i < MAX_NR_ZONES; i++)
+               z[i] = 0;
+
+       if (start_pfn < MAX_DMA_PFN)
+               z[ZONE_DMA] = MAX_DMA_PFN - start_pfn;
+       if (start_pfn < MAX_DMA32_PFN) {
+               unsigned long dma32_pfn = MAX_DMA32_PFN;
+               if (dma32_pfn > end_pfn)
+                       dma32_pfn = end_pfn;
+               z[ZONE_DMA32] = dma32_pfn - start_pfn;
+       }
+       z[ZONE_NORMAL] = end_pfn - start_pfn;
+
+       /* Remove lower zones from higher ones. */
+       w = 0;
+       for (i = 0; i < MAX_NR_ZONES; i++) {
+               if (z[i])
+                       z[i] -= w;
+               w += z[i];
+       }
 
-               max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
+       /* Compute holes */
+       w = 0;
+       for (i = 0; i < MAX_NR_ZONES; i++) {
+               unsigned long s = w;
+               w += z[i];
+               h[i] = e820_hole_size(s, w);
+       }
 
-               if (end_pfn < max_dma)
-                       zones_size[ZONE_DMA] = end_pfn;
-               else {
-                       zones_size[ZONE_DMA] = max_dma;
-                       zones_size[ZONE_NORMAL] = end_pfn - max_dma;
+       /* Add the space pace needed for mem_map to the holes too. */
+       for (i = 0; i < MAX_NR_ZONES; i++)
+               h[i] += (z[i] * sizeof(struct page)) / PAGE_SIZE;
+
+       /* The 16MB DMA zone has the kernel and other misc mappings.
+          Account them too */
+       if (h[ZONE_DMA]) {
+               h[ZONE_DMA] += dma_reserve;
+               if (h[ZONE_DMA] >= z[ZONE_DMA]) {
+                       printk(KERN_WARNING
+                               "Kernel too large and filling up ZONE_DMA?\n");
+                       h[ZONE_DMA] = z[ZONE_DMA];
                }
-               free_area_init(zones_size);
        }
-       return;
+}
+
+#ifndef CONFIG_NUMA
+void __init paging_init(void)
+{
+       unsigned long zones[MAX_NR_ZONES], holes[MAX_NR_ZONES];
+       size_zones(zones, holes, 0, end_pfn);
+       free_area_init_node(0, NODE_DATA(0), zones,
+                           __pa(PAGE_OFFSET) >> PAGE_SHIFT, holes);
 }
 #endif
 
@@ -373,41 +417,14 @@ void __init clear_kernel_mapping(unsigned long address, unsigned long size)
        __flush_tlb_all();
 } 
 
-static inline int page_is_ram (unsigned long pagenr)
-{
-       int i;
-
-       for (i = 0; i < e820.nr_map; i++) {
-               unsigned long addr, end;
-
-               if (e820.map[i].type != E820_RAM)       /* not usable memory */
-                       continue;
-               /*
-                *      !!!FIXME!!! Some BIOSen report areas as RAM that
-                *      are not. Notably the 640->1Mb area. We need a sanity
-                *      check here.
-                */
-               addr = (e820.map[i].addr+PAGE_SIZE-1) >> PAGE_SHIFT;
-               end = (e820.map[i].addr+e820.map[i].size) >> PAGE_SHIFT;
-               if  ((pagenr >= addr) && (pagenr < end))
-                       return 1;
-       }
-       return 0;
-}
-
-extern int swiotlb_force;
-
 static struct kcore_list kcore_mem, kcore_vmalloc, kcore_kernel, kcore_modules,
                         kcore_vsyscall;
 
 void __init mem_init(void)
 {
-       int codesize, reservedpages, datasize, initsize;
-       int tmp;
+       long codesize, reservedpages, datasize, initsize;
 
 #ifdef CONFIG_SWIOTLB
-       if (swiotlb_force)
-               swiotlb = 1;
        if (!iommu_aperture &&
            (end_pfn >= 0xffffffff>>PAGE_SHIFT || force_iommu))
               swiotlb = 1;
@@ -428,25 +445,11 @@ void __init mem_init(void)
 
        /* this will put all low memory onto the freelists */
 #ifdef CONFIG_NUMA
-       totalram_pages += numa_free_all_bootmem();
-       tmp = 0;
-       /* should count reserved pages here for all nodes */ 
+       totalram_pages = numa_free_all_bootmem();
 #else
-
-#ifdef CONFIG_FLATMEM
-       max_mapnr = end_pfn;
-       if (!mem_map) BUG();
-#endif
-
-       totalram_pages += free_all_bootmem();
-
-       for (tmp = 0; tmp < end_pfn; tmp++)
-               /*
-                * Only count reserved RAM pages
-                */
-               if (page_is_ram(tmp) && PageReserved(pfn_to_page(tmp)))
-                       reservedpages++;
+       totalram_pages = free_all_bootmem();
 #endif
+       reservedpages = end_pfn - totalram_pages - e820_hole_size(0, end_pfn);
 
        after_bootmem = 1;
 
@@ -463,7 +466,7 @@ void __init mem_init(void)
        kclist_add(&kcore_vsyscall, (void *)VSYSCALL_START, 
                                 VSYSCALL_END - VSYSCALL_START);
 
-       printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init)\n",
+       printk("Memory: %luk/%luk available (%ldk kernel code, %ldk reserved, %ldk data, %ldk init)\n",
                (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
                end_pfn << (PAGE_SHIFT-10),
                codesize >> 10,
@@ -524,6 +527,8 @@ void __init reserve_bootmem_generic(unsigned long phys, unsigned len)
 #else                  
        reserve_bootmem(phys, len);    
 #endif
+       if (phys+len <= MAX_DMA_PFN*PAGE_SIZE)
+               dma_reserve += len / PAGE_SIZE;
 }
 
 int kern_addr_valid(unsigned long addr)