diff options
author | Jeremy Fitzhardinge <jeremy@goop.org> | 2008-05-26 18:31:18 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2008-05-27 04:11:37 -0400 |
commit | d451bb7aa852627bdf7be7937dc3d9d9f261b235 (patch) | |
tree | 2a92b5e271fb2ae7a869f0f2b4f5bb390cac99cc /arch | |
parent | 955d6f1778da5a9795f2dfb07f760006f194609a (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>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/xen/enlighten.c | 2 | ||||
-rw-r--r-- | arch/x86/xen/mmu.c | 85 | ||||
-rw-r--r-- | arch/x86/xen/setup.c | 2 | ||||
-rw-r--r-- | arch/x86/xen/xen-ops.h | 2 |
4 files changed, 88 insertions, 3 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 | |||
67 | static unsigned long *p2m_top[MAX_GUEST_PAGES / P2M_ENTRIES_PER_PAGE]; | ||
68 | |||
69 | static 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 | |||
75 | static inline unsigned p2m_index(unsigned long pfn) | ||
76 | { | ||
77 | return pfn % P2M_ENTRIES_PER_PAGE; | ||
78 | } | ||
79 | |||
80 | void __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 | |||
96 | unsigned 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 | |||
108 | static 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 | |||
123 | void 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 | |||
59 | xmaddr_t arbitrary_virt_to_machine(unsigned long address) | 144 | xmaddr_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 @@ | |||
27 | extern const char xen_hypervisor_callback[]; | 27 | extern const char xen_hypervisor_callback[]; |
28 | extern const char xen_failsafe_callback[]; | 28 | extern const char xen_failsafe_callback[]; |
29 | 29 | ||
30 | unsigned long *phys_to_machine_mapping; | ||
31 | EXPORT_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); | |||
22 | void __init xen_init_IRQ(void); | 22 | void __init xen_init_IRQ(void); |
23 | void xen_enable_sysenter(void); | 23 | void xen_enable_sysenter(void); |
24 | 24 | ||
25 | void __init xen_build_dynamic_phys_to_machine(void); | ||
26 | |||
25 | void xen_setup_timer(int cpu); | 27 | void xen_setup_timer(int cpu); |
26 | void xen_setup_cpu_clockevents(void); | 28 | void xen_setup_cpu_clockevents(void); |
27 | unsigned long xen_cpu_khz(void); | 29 | unsigned long xen_cpu_khz(void); |