Merge tag 'stable/for-linus-3.7-x86-tag' of git://git.kernel.org/pub/scm/linux/kernel...
[platform/adaptation/renesas_rcar/renesas_kernel.git] / arch / x86 / xen / p2m.c
index 72213da..95fb2aa 100644 (file)
@@ -22,7 +22,7 @@
  *
  * P2M_PER_PAGE depends on the architecture, as a mfn is always
  * unsigned long (8 bytes on 64-bit, 4 bytes on 32), leading to
- * 512 and 1024 entries respectively. 
+ * 512 and 1024 entries respectively.
  *
  * In short, these structures contain the Machine Frame Number (MFN) of the PFN.
  *
  *      /    | ~0, ~0, ....  |
  *     |     \---------------/
  *     |
- *     p2m_missing             p2m_missing
- * /------------------\     /------------\
- * | [p2m_mid_missing]+---->| ~0, ~0, ~0 |
- * | [p2m_mid_missing]+---->| ..., ~0    |
- * \------------------/     \------------/
+ *   p2m_mid_missing           p2m_missing
+ * /-----------------\     /------------\
+ * | [p2m_missing]   +---->| ~0, ~0, ~0 |
+ * | [p2m_missing]   +---->| ..., ~0    |
+ * \-----------------/     \------------/
  *
  * where ~0 is INVALID_P2M_ENTRY. IDENTITY is (PFN | IDENTITY_BIT)
  */
@@ -396,7 +396,85 @@ void __init xen_build_dynamic_phys_to_machine(void)
 
        m2p_override_init();
 }
+#ifdef CONFIG_X86_64
+#include <linux/bootmem.h>
+unsigned long __init xen_revector_p2m_tree(void)
+{
+       unsigned long va_start;
+       unsigned long va_end;
+       unsigned long pfn;
+       unsigned long pfn_free = 0;
+       unsigned long *mfn_list = NULL;
+       unsigned long size;
+
+       va_start = xen_start_info->mfn_list;
+       /*We copy in increments of P2M_PER_PAGE * sizeof(unsigned long),
+        * so make sure it is rounded up to that */
+       size = PAGE_ALIGN(xen_start_info->nr_pages * sizeof(unsigned long));
+       va_end = va_start + size;
+
+       /* If we were revectored already, don't do it again. */
+       if (va_start <= __START_KERNEL_map && va_start >= __PAGE_OFFSET)
+               return 0;
+
+       mfn_list = alloc_bootmem_align(size, PAGE_SIZE);
+       if (!mfn_list) {
+               pr_warn("Could not allocate space for a new P2M tree!\n");
+               return xen_start_info->mfn_list;
+       }
+       /* Fill it out with INVALID_P2M_ENTRY value */
+       memset(mfn_list, 0xFF, size);
+
+       for (pfn = 0; pfn < ALIGN(MAX_DOMAIN_PAGES, P2M_PER_PAGE); pfn += P2M_PER_PAGE) {
+               unsigned topidx = p2m_top_index(pfn);
+               unsigned mididx;
+               unsigned long *mid_p;
+
+               if (!p2m_top[topidx])
+                       continue;
+
+               if (p2m_top[topidx] == p2m_mid_missing)
+                       continue;
+
+               mididx = p2m_mid_index(pfn);
+               mid_p = p2m_top[topidx][mididx];
+               if (!mid_p)
+                       continue;
+               if ((mid_p == p2m_missing) || (mid_p == p2m_identity))
+                       continue;
+
+               if ((unsigned long)mid_p == INVALID_P2M_ENTRY)
+                       continue;
+
+               /* The old va. Rebase it on mfn_list */
+               if (mid_p >= (unsigned long *)va_start && mid_p <= (unsigned long *)va_end) {
+                       unsigned long *new;
+
+                       if (pfn_free  > (size / sizeof(unsigned long))) {
+                               WARN(1, "Only allocated for %ld pages, but we want %ld!\n",
+                                    size / sizeof(unsigned long), pfn_free);
+                               return 0;
+                       }
+                       new = &mfn_list[pfn_free];
+
+                       copy_page(new, mid_p);
+                       p2m_top[topidx][mididx] = &mfn_list[pfn_free];
+                       p2m_top_mfn_p[topidx][mididx] = virt_to_mfn(&mfn_list[pfn_free]);
+
+                       pfn_free += P2M_PER_PAGE;
 
+               }
+               /* This should be the leafs allocated for identity from _brk. */
+       }
+       return (unsigned long)mfn_list;
+
+}
+#else
+unsigned long __init xen_revector_p2m_tree(void)
+{
+       return 0;
+}
+#endif
 unsigned long get_phys_to_machine(unsigned long pfn)
 {
        unsigned topidx, mididx, idx;
@@ -430,7 +508,7 @@ static void free_p2m_page(void *p)
        free_page((unsigned long)p);
 }
 
-/* 
+/*
  * Fully allocate the p2m structure for a given pfn.  We need to check
  * that both the top and mid levels are allocated, and make sure the
  * parallel mfn tree is kept in sync.  We may race with other cpus, so