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 | |
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>
-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 | ||||
-rw-r--r-- | include/asm-x86/xen/page.h | 20 |
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 | |||
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); |
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 | ||
29 | extern unsigned long *phys_to_machine_mapping; | 29 | extern unsigned long get_phys_to_machine(unsigned long pfn); |
30 | extern void set_phys_to_machine(unsigned long pfn, unsigned long mfn); | ||
30 | 31 | ||
31 | static inline unsigned long pfn_to_mfn(unsigned long pfn) | 32 | static 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 | ||
40 | static inline int phys_to_machine_mapping_valid(unsigned long pfn) | 40 | static 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 | ||
48 | static inline unsigned long mfn_to_pfn(unsigned long mfn) | 48 | static 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 | ||
114 | static 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)))) |