]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - arch/x86/xen/setup.c
xen: Delay invalidating extra memory
[karo-tx-linux.git] / arch / x86 / xen / setup.c
index e0b6912f9cad732a5d57bf7b5c8c36a80fb3eb81..12cd199e4c9af3079c1d28b92d7cb9efedabc0c6 100644 (file)
@@ -76,7 +76,6 @@ static unsigned long xen_remap_mfn __initdata = INVALID_P2M_ENTRY;
 
 static void __init xen_add_extra_mem(u64 start, u64 size)
 {
-       unsigned long pfn;
        int i;
 
        for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++) {
@@ -96,17 +95,75 @@ static void __init xen_add_extra_mem(u64 start, u64 size)
                printk(KERN_WARNING "Warning: not enough extra memory regions\n");
 
        memblock_reserve(start, size);
+}
 
-       xen_max_p2m_pfn = PFN_DOWN(start + size);
-       for (pfn = PFN_DOWN(start); pfn < xen_max_p2m_pfn; pfn++) {
-               unsigned long mfn = pfn_to_mfn(pfn);
+static void __init xen_del_extra_mem(u64 start, u64 size)
+{
+       int i;
+       u64 start_r, size_r;
 
-               if (WARN_ONCE(mfn == pfn, "Trying to over-write 1-1 mapping (pfn: %lx)\n", pfn))
-                       continue;
-               WARN_ONCE(mfn != INVALID_P2M_ENTRY, "Trying to remove %lx which has %lx mfn!\n",
-                         pfn, mfn);
+       for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++) {
+               start_r = xen_extra_mem[i].start;
+               size_r = xen_extra_mem[i].size;
+
+               /* Start of region. */
+               if (start_r == start) {
+                       BUG_ON(size > size_r);
+                       xen_extra_mem[i].start += size;
+                       xen_extra_mem[i].size -= size;
+                       break;
+               }
+               /* End of region. */
+               if (start_r + size_r == start + size) {
+                       BUG_ON(size > size_r);
+                       xen_extra_mem[i].size -= size;
+                       break;
+               }
+               /* Mid of region. */
+               if (start > start_r && start < start_r + size_r) {
+                       BUG_ON(start + size > start_r + size_r);
+                       xen_extra_mem[i].size = start - start_r;
+                       /* Calling memblock_reserve() again is okay. */
+                       xen_add_extra_mem(start + size, start_r + size_r -
+                                         (start + size));
+                       break;
+               }
+       }
+       memblock_free(start, size);
+}
+
+/*
+ * Called during boot before the p2m list can take entries beyond the
+ * hypervisor supplied p2m list. Entries in extra mem are to be regarded as
+ * invalid.
+ */
+unsigned long __ref xen_chk_extra_mem(unsigned long pfn)
+{
+       int i;
+       unsigned long addr = PFN_PHYS(pfn);
 
-               __set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
+       for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++) {
+               if (addr >= xen_extra_mem[i].start &&
+                   addr < xen_extra_mem[i].start + xen_extra_mem[i].size)
+                       return INVALID_P2M_ENTRY;
+       }
+
+       return IDENTITY_FRAME(pfn);
+}
+
+/*
+ * Mark all pfns of extra mem as invalid in p2m list.
+ */
+void __init xen_inv_extra_mem(void)
+{
+       unsigned long pfn, pfn_s, pfn_e;
+       int i;
+
+       for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++) {
+               pfn_s = PFN_DOWN(xen_extra_mem[i].start);
+               pfn_e = PFN_UP(xen_extra_mem[i].start + xen_extra_mem[i].size);
+               for (pfn = pfn_s; pfn < pfn_e; pfn++)
+                       set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
        }
 }
 
@@ -268,9 +325,6 @@ static void __init xen_do_set_identity_and_remap_chunk(
 
        BUG_ON(xen_feature(XENFEAT_auto_translated_physmap));
 
-       /* Don't use memory until remapped */
-       memblock_reserve(PFN_PHYS(remap_pfn), PFN_PHYS(size));
-
        mfn_save = virt_to_mfn(buf);
 
        for (ident_pfn_iter = start_pfn, remap_pfn_iter = remap_pfn;
@@ -314,7 +368,7 @@ static void __init xen_do_set_identity_and_remap_chunk(
  * pages. In the case of an error the underlying memory is simply released back
  * to Xen and not remapped.
  */
-static unsigned long __init xen_set_identity_and_remap_chunk(
+static unsigned long xen_set_identity_and_remap_chunk(
         const struct e820entry *list, size_t map_size, unsigned long start_pfn,
        unsigned long end_pfn, unsigned long nr_pages, unsigned long remap_pfn,
        unsigned long *identity, unsigned long *released)
@@ -371,7 +425,7 @@ static unsigned long __init xen_set_identity_and_remap_chunk(
        return remap_pfn;
 }
 
-static unsigned long __init xen_set_identity_and_remap(
+static void __init xen_set_identity_and_remap(
        const struct e820entry *list, size_t map_size, unsigned long nr_pages,
        unsigned long *released)
 {
@@ -415,8 +469,6 @@ static unsigned long __init xen_set_identity_and_remap(
 
        pr_info("Set %ld page(s) to 1-1 mapping\n", identity);
        pr_info("Released %ld page(s)\n", num_released);
-
-       return last_pfn;
 }
 
 /*
@@ -456,7 +508,7 @@ void __init xen_remap_memory(void)
                } else if (pfn_s + len == xen_remap_buf.target_pfn) {
                        len += xen_remap_buf.size;
                } else {
-                       memblock_free(PFN_PHYS(pfn_s), PFN_PHYS(len));
+                       xen_del_extra_mem(PFN_PHYS(pfn_s), PFN_PHYS(len));
                        pfn_s = xen_remap_buf.target_pfn;
                        len = xen_remap_buf.size;
                }
@@ -466,7 +518,7 @@ void __init xen_remap_memory(void)
        }
 
        if (pfn_s != ~0UL && len)
-               memblock_free(PFN_PHYS(pfn_s), PFN_PHYS(len));
+               xen_del_extra_mem(PFN_PHYS(pfn_s), PFN_PHYS(len));
 
        set_pte_mfn(buf, mfn_save, PAGE_KERNEL);
 
@@ -533,7 +585,6 @@ char * __init xen_memory_setup(void)
        int rc;
        struct xen_memory_map memmap;
        unsigned long max_pages;
-       unsigned long last_pfn = 0;
        unsigned long extra_pages = 0;
        int i;
        int op;
@@ -583,15 +634,11 @@ char * __init xen_memory_setup(void)
         * Set identity map on non-RAM pages and prepare remapping the
         * underlying RAM.
         */
-       last_pfn = xen_set_identity_and_remap(map, memmap.nr_entries, max_pfn,
-                                             &xen_released_pages);
+       xen_set_identity_and_remap(map, memmap.nr_entries, max_pfn,
+                                  &xen_released_pages);
 
        extra_pages += xen_released_pages;
 
-       if (last_pfn > max_pfn) {
-               max_pfn = min(MAX_DOMAIN_PAGES, last_pfn);
-               mem_end = PFN_PHYS(max_pfn);
-       }
        /*
         * Clamp the amount of extra memory to a EXTRA_MEM_RATIO
         * factor the base size.  On non-highmem systems, the base
@@ -618,6 +665,7 @@ char * __init xen_memory_setup(void)
                                size = min(size, (u64)extra_pages * PAGE_SIZE);
                                extra_pages -= size / PAGE_SIZE;
                                xen_add_extra_mem(addr, size);
+                               xen_max_p2m_pfn = PFN_DOWN(addr + size);
                        } else
                                type = E820_UNUSABLE;
                }