]> 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 e60a1a848de8f622ce87bd7616b7c32b0dea6e0e..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);
 
 /*
@@ -318,32 +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];
-               unsigned long holes[MAX_NR_ZONES];
-               unsigned int max_dma;
-
-               memset(zones_size, 0, sizeof(zones_size));
-               memset(holes, 0, sizeof(holes));
-
-               max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
-
-               if (end_pfn < max_dma) {
-                       zones_size[ZONE_DMA] = end_pfn;
-                       holes[ZONE_DMA] = e820_hole_size(0, end_pfn);
-               } else {
-                       zones_size[ZONE_DMA] = max_dma;
-                       holes[ZONE_DMA] = e820_hole_size(0, max_dma);
-                       zones_size[ZONE_NORMAL] = end_pfn - max_dma;
-                       holes[ZONE_NORMAL] = e820_hole_size(max_dma, end_pfn);
+       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];
+       }
+
+       /* 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);
+       }
+
+       /* 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_node(0, NODE_DATA(0), zones_size,
-                        __pa(PAGE_OFFSET) >> PAGE_SHIFT, holes);
        }
-       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
 
@@ -491,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)