aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremy Fitzhardinge <jeremy@goop.org>2008-05-26 18:31:18 -0400
committerThomas Gleixner <tglx@linutronix.de>2008-05-27 04:11:37 -0400
commitd451bb7aa852627bdf7be7937dc3d9d9f261b235 (patch)
tree2a92b5e271fb2ae7a869f0f2b4f5bb390cac99cc
parent955d6f1778da5a9795f2dfb07f760006f194609a (diff)
xen: make phys_to_machine structure dynamic
We now support the use of memory hotplug, so the physical to machine page mapping structure must be dynamic. This is implemented as a two-level radix tree structure, which allows us to efficiently incrementally allocate memory for the p2m table as new pages are added. Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--arch/x86/xen/enlighten.c2
-rw-r--r--arch/x86/xen/mmu.c85
-rw-r--r--arch/x86/xen/setup.c2
-rw-r--r--arch/x86/xen/xen-ops.h2
-rw-r--r--include/asm-x86/xen/page.h20
5 files changed, 94 insertions, 17 deletions
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index 5c0635a8bffd..73d3c84a3495 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -1221,7 +1221,7 @@ asmlinkage void __init xen_start_kernel(void)
1221 1221
1222 /* Get mfn list */ 1222 /* Get mfn list */
1223 if (!xen_feature(XENFEAT_auto_translated_physmap)) 1223 if (!xen_feature(XENFEAT_auto_translated_physmap))
1224 phys_to_machine_mapping = (unsigned long *)xen_start_info->mfn_list; 1224 xen_build_dynamic_phys_to_machine();
1225 1225
1226 pgd = (pgd_t *)xen_start_info->pt_base; 1226 pgd = (pgd_t *)xen_start_info->pt_base;
1227 1227
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index 07c2653ec335..c3b27dec6f03 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -56,6 +56,91 @@
56#include "multicalls.h" 56#include "multicalls.h"
57#include "mmu.h" 57#include "mmu.h"
58 58
59/*
60 * This should probably be a config option. On 32-bit, it costs 1
61 * page/gig of memory; on 64-bit its 2 pages/gig. If we want it to be
62 * completely unbounded we can add another level to the p2m structure.
63 */
64#define MAX_GUEST_PAGES (16ull * 1024*1024*1024 / PAGE_SIZE)
65#define P2M_ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(unsigned long))
66
67static unsigned long *p2m_top[MAX_GUEST_PAGES / P2M_ENTRIES_PER_PAGE];
68
69static inline unsigned p2m_top_index(unsigned long pfn)
70{
71 BUG_ON(pfn >= MAX_GUEST_PAGES);
72 return pfn / P2M_ENTRIES_PER_PAGE;
73}
74
75static inline unsigned p2m_index(unsigned long pfn)
76{
77 return pfn % P2M_ENTRIES_PER_PAGE;
78}
79
80void __init xen_build_dynamic_phys_to_machine(void)
81{
82 unsigned pfn;
83 unsigned long *mfn_list = (unsigned long *)xen_start_info->mfn_list;
84
85 BUG_ON(xen_start_info->nr_pages >= MAX_GUEST_PAGES);
86
87 for(pfn = 0;
88 pfn < xen_start_info->nr_pages;
89 pfn += P2M_ENTRIES_PER_PAGE) {
90 unsigned topidx = p2m_top_index(pfn);
91
92 p2m_top[topidx] = &mfn_list[pfn];
93 }
94}
95
96unsigned long get_phys_to_machine(unsigned long pfn)
97{
98 unsigned topidx, idx;
99
100 topidx = p2m_top_index(pfn);
101 if (p2m_top[topidx] == NULL)
102 return INVALID_P2M_ENTRY;
103
104 idx = p2m_index(pfn);
105 return p2m_top[topidx][idx];
106}
107
108static void alloc_p2m(unsigned long **pp)
109{
110 unsigned long *p;
111 unsigned i;
112
113 p = (void *)__get_free_page(GFP_KERNEL | __GFP_NOFAIL);
114 BUG_ON(p == NULL);
115
116 for(i = 0; i < P2M_ENTRIES_PER_PAGE; i++)
117 p[i] = INVALID_P2M_ENTRY;
118
119 if (cmpxchg(pp, NULL, p) != NULL)
120 free_page((unsigned long)p);
121}
122
123void set_phys_to_machine(unsigned long pfn, unsigned long mfn)
124{
125 unsigned topidx, idx;
126
127 if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) {
128 BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
129 return;
130 }
131
132 topidx = p2m_top_index(pfn);
133 if (p2m_top[topidx] == NULL) {
134 /* no need to allocate a page to store an invalid entry */
135 if (mfn == INVALID_P2M_ENTRY)
136 return;
137 alloc_p2m(&p2m_top[topidx]);
138 }
139
140 idx = p2m_index(pfn);
141 p2m_top[topidx][idx] = mfn;
142}
143
59xmaddr_t arbitrary_virt_to_machine(unsigned long address) 144xmaddr_t arbitrary_virt_to_machine(unsigned long address)
60{ 145{
61 unsigned int level; 146 unsigned int level;
diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c
index 82517e4a752a..37f8f0b8f743 100644
--- a/arch/x86/xen/setup.c
+++ b/arch/x86/xen/setup.c
@@ -27,8 +27,6 @@
27extern const char xen_hypervisor_callback[]; 27extern const char xen_hypervisor_callback[];
28extern const char xen_failsafe_callback[]; 28extern const char xen_failsafe_callback[];
29 29
30unsigned long *phys_to_machine_mapping;
31EXPORT_SYMBOL(phys_to_machine_mapping);
32 30
33/** 31/**
34 * machine_specific_memory_setup - Hook for machine specific memory setup. 32 * machine_specific_memory_setup - Hook for machine specific memory setup.
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h
index f1063ae08037..7bdc8c5c9244 100644
--- a/arch/x86/xen/xen-ops.h
+++ b/arch/x86/xen/xen-ops.h
@@ -22,6 +22,8 @@ void __init xen_arch_setup(void);
22void __init xen_init_IRQ(void); 22void __init xen_init_IRQ(void);
23void xen_enable_sysenter(void); 23void xen_enable_sysenter(void);
24 24
25void __init xen_build_dynamic_phys_to_machine(void);
26
25void xen_setup_timer(int cpu); 27void xen_setup_timer(int cpu);
26void xen_setup_cpu_clockevents(void); 28void xen_setup_cpu_clockevents(void);
27unsigned long xen_cpu_khz(void); 29unsigned long xen_cpu_khz(void);
diff --git a/include/asm-x86/xen/page.h b/include/asm-x86/xen/page.h
index e11f24038b1d..293344f8102e 100644
--- a/include/asm-x86/xen/page.h
+++ b/include/asm-x86/xen/page.h
@@ -26,15 +26,15 @@ typedef struct xpaddr {
26#define FOREIGN_FRAME_BIT (1UL<<31) 26#define FOREIGN_FRAME_BIT (1UL<<31)
27#define FOREIGN_FRAME(m) ((m) | FOREIGN_FRAME_BIT) 27#define FOREIGN_FRAME(m) ((m) | FOREIGN_FRAME_BIT)
28 28
29extern unsigned long *phys_to_machine_mapping; 29extern unsigned long get_phys_to_machine(unsigned long pfn);
30extern void set_phys_to_machine(unsigned long pfn, unsigned long mfn);
30 31
31static inline unsigned long pfn_to_mfn(unsigned long pfn) 32static inline unsigned long pfn_to_mfn(unsigned long pfn)
32{ 33{
33 if (xen_feature(XENFEAT_auto_translated_physmap)) 34 if (xen_feature(XENFEAT_auto_translated_physmap))
34 return pfn; 35 return pfn;
35 36
36 return phys_to_machine_mapping[(unsigned int)(pfn)] & 37 return get_phys_to_machine(pfn) & ~FOREIGN_FRAME_BIT;
37 ~FOREIGN_FRAME_BIT;
38} 38}
39 39
40static inline int phys_to_machine_mapping_valid(unsigned long pfn) 40static inline int phys_to_machine_mapping_valid(unsigned long pfn)
@@ -42,7 +42,7 @@ static inline int phys_to_machine_mapping_valid(unsigned long pfn)
42 if (xen_feature(XENFEAT_auto_translated_physmap)) 42 if (xen_feature(XENFEAT_auto_translated_physmap))
43 return 1; 43 return 1;
44 44
45 return (phys_to_machine_mapping[pfn] != INVALID_P2M_ENTRY); 45 return get_phys_to_machine(pfn) != INVALID_P2M_ENTRY;
46} 46}
47 47
48static inline unsigned long mfn_to_pfn(unsigned long mfn) 48static inline unsigned long mfn_to_pfn(unsigned long mfn)
@@ -106,20 +106,12 @@ static inline unsigned long mfn_to_local_pfn(unsigned long mfn)
106 unsigned long pfn = mfn_to_pfn(mfn); 106 unsigned long pfn = mfn_to_pfn(mfn);
107 if ((pfn < max_mapnr) 107 if ((pfn < max_mapnr)
108 && !xen_feature(XENFEAT_auto_translated_physmap) 108 && !xen_feature(XENFEAT_auto_translated_physmap)
109 && (phys_to_machine_mapping[pfn] != mfn)) 109 && (get_phys_to_machine(pfn) != mfn))
110 return max_mapnr; /* force !pfn_valid() */ 110 return max_mapnr; /* force !pfn_valid() */
111 /* XXX fixme; not true with sparsemem */
111 return pfn; 112 return pfn;
112} 113}
113 114
114static inline void set_phys_to_machine(unsigned long pfn, unsigned long mfn)
115{
116 if (xen_feature(XENFEAT_auto_translated_physmap)) {
117 BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
118 return;
119 }
120 phys_to_machine_mapping[pfn] = mfn;
121}
122
123/* VIRT <-> MACHINE conversion */ 115/* VIRT <-> MACHINE conversion */
124#define virt_to_machine(v) (phys_to_machine(XPADDR(__pa(v)))) 116#define virt_to_machine(v) (phys_to_machine(XPADDR(__pa(v))))
125#define virt_to_mfn(v) (pfn_to_mfn(PFN_DOWN(__pa(v)))) 117#define virt_to_mfn(v) (pfn_to_mfn(PFN_DOWN(__pa(v))))