mirror of
https://github.com/edk2-porting/linux-next.git
synced 2025-01-25 07:06:40 +08:00
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>
This commit is contained in:
parent
955d6f1778
commit
d451bb7aa8
@ -1221,7 +1221,7 @@ asmlinkage void __init xen_start_kernel(void)
|
||||
|
||||
/* Get mfn list */
|
||||
if (!xen_feature(XENFEAT_auto_translated_physmap))
|
||||
phys_to_machine_mapping = (unsigned long *)xen_start_info->mfn_list;
|
||||
xen_build_dynamic_phys_to_machine();
|
||||
|
||||
pgd = (pgd_t *)xen_start_info->pt_base;
|
||||
|
||||
|
@ -56,6 +56,91 @@
|
||||
#include "multicalls.h"
|
||||
#include "mmu.h"
|
||||
|
||||
/*
|
||||
* This should probably be a config option. On 32-bit, it costs 1
|
||||
* page/gig of memory; on 64-bit its 2 pages/gig. If we want it to be
|
||||
* completely unbounded we can add another level to the p2m structure.
|
||||
*/
|
||||
#define MAX_GUEST_PAGES (16ull * 1024*1024*1024 / PAGE_SIZE)
|
||||
#define P2M_ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(unsigned long))
|
||||
|
||||
static unsigned long *p2m_top[MAX_GUEST_PAGES / P2M_ENTRIES_PER_PAGE];
|
||||
|
||||
static inline unsigned p2m_top_index(unsigned long pfn)
|
||||
{
|
||||
BUG_ON(pfn >= MAX_GUEST_PAGES);
|
||||
return pfn / P2M_ENTRIES_PER_PAGE;
|
||||
}
|
||||
|
||||
static inline unsigned p2m_index(unsigned long pfn)
|
||||
{
|
||||
return pfn % P2M_ENTRIES_PER_PAGE;
|
||||
}
|
||||
|
||||
void __init xen_build_dynamic_phys_to_machine(void)
|
||||
{
|
||||
unsigned pfn;
|
||||
unsigned long *mfn_list = (unsigned long *)xen_start_info->mfn_list;
|
||||
|
||||
BUG_ON(xen_start_info->nr_pages >= MAX_GUEST_PAGES);
|
||||
|
||||
for(pfn = 0;
|
||||
pfn < xen_start_info->nr_pages;
|
||||
pfn += P2M_ENTRIES_PER_PAGE) {
|
||||
unsigned topidx = p2m_top_index(pfn);
|
||||
|
||||
p2m_top[topidx] = &mfn_list[pfn];
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long get_phys_to_machine(unsigned long pfn)
|
||||
{
|
||||
unsigned topidx, idx;
|
||||
|
||||
topidx = p2m_top_index(pfn);
|
||||
if (p2m_top[topidx] == NULL)
|
||||
return INVALID_P2M_ENTRY;
|
||||
|
||||
idx = p2m_index(pfn);
|
||||
return p2m_top[topidx][idx];
|
||||
}
|
||||
|
||||
static void alloc_p2m(unsigned long **pp)
|
||||
{
|
||||
unsigned long *p;
|
||||
unsigned i;
|
||||
|
||||
p = (void *)__get_free_page(GFP_KERNEL | __GFP_NOFAIL);
|
||||
BUG_ON(p == NULL);
|
||||
|
||||
for(i = 0; i < P2M_ENTRIES_PER_PAGE; i++)
|
||||
p[i] = INVALID_P2M_ENTRY;
|
||||
|
||||
if (cmpxchg(pp, NULL, p) != NULL)
|
||||
free_page((unsigned long)p);
|
||||
}
|
||||
|
||||
void set_phys_to_machine(unsigned long pfn, unsigned long mfn)
|
||||
{
|
||||
unsigned topidx, idx;
|
||||
|
||||
if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) {
|
||||
BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
|
||||
return;
|
||||
}
|
||||
|
||||
topidx = p2m_top_index(pfn);
|
||||
if (p2m_top[topidx] == NULL) {
|
||||
/* no need to allocate a page to store an invalid entry */
|
||||
if (mfn == INVALID_P2M_ENTRY)
|
||||
return;
|
||||
alloc_p2m(&p2m_top[topidx]);
|
||||
}
|
||||
|
||||
idx = p2m_index(pfn);
|
||||
p2m_top[topidx][idx] = mfn;
|
||||
}
|
||||
|
||||
xmaddr_t arbitrary_virt_to_machine(unsigned long address)
|
||||
{
|
||||
unsigned int level;
|
||||
|
@ -27,8 +27,6 @@
|
||||
extern const char xen_hypervisor_callback[];
|
||||
extern const char xen_failsafe_callback[];
|
||||
|
||||
unsigned long *phys_to_machine_mapping;
|
||||
EXPORT_SYMBOL(phys_to_machine_mapping);
|
||||
|
||||
/**
|
||||
* machine_specific_memory_setup - Hook for machine specific memory setup.
|
||||
|
@ -22,6 +22,8 @@ void __init xen_arch_setup(void);
|
||||
void __init xen_init_IRQ(void);
|
||||
void xen_enable_sysenter(void);
|
||||
|
||||
void __init xen_build_dynamic_phys_to_machine(void);
|
||||
|
||||
void xen_setup_timer(int cpu);
|
||||
void xen_setup_cpu_clockevents(void);
|
||||
unsigned long xen_cpu_khz(void);
|
||||
|
@ -26,15 +26,15 @@ typedef struct xpaddr {
|
||||
#define FOREIGN_FRAME_BIT (1UL<<31)
|
||||
#define FOREIGN_FRAME(m) ((m) | FOREIGN_FRAME_BIT)
|
||||
|
||||
extern unsigned long *phys_to_machine_mapping;
|
||||
extern unsigned long get_phys_to_machine(unsigned long pfn);
|
||||
extern void set_phys_to_machine(unsigned long pfn, unsigned long mfn);
|
||||
|
||||
static inline unsigned long pfn_to_mfn(unsigned long pfn)
|
||||
{
|
||||
if (xen_feature(XENFEAT_auto_translated_physmap))
|
||||
return pfn;
|
||||
|
||||
return phys_to_machine_mapping[(unsigned int)(pfn)] &
|
||||
~FOREIGN_FRAME_BIT;
|
||||
return get_phys_to_machine(pfn) & ~FOREIGN_FRAME_BIT;
|
||||
}
|
||||
|
||||
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)
|
||||
if (xen_feature(XENFEAT_auto_translated_physmap))
|
||||
return 1;
|
||||
|
||||
return (phys_to_machine_mapping[pfn] != INVALID_P2M_ENTRY);
|
||||
return get_phys_to_machine(pfn) != INVALID_P2M_ENTRY;
|
||||
}
|
||||
|
||||
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)
|
||||
unsigned long pfn = mfn_to_pfn(mfn);
|
||||
if ((pfn < max_mapnr)
|
||||
&& !xen_feature(XENFEAT_auto_translated_physmap)
|
||||
&& (phys_to_machine_mapping[pfn] != mfn))
|
||||
&& (get_phys_to_machine(pfn) != mfn))
|
||||
return max_mapnr; /* force !pfn_valid() */
|
||||
/* XXX fixme; not true with sparsemem */
|
||||
return pfn;
|
||||
}
|
||||
|
||||
static inline void set_phys_to_machine(unsigned long pfn, unsigned long mfn)
|
||||
{
|
||||
if (xen_feature(XENFEAT_auto_translated_physmap)) {
|
||||
BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
|
||||
return;
|
||||
}
|
||||
phys_to_machine_mapping[pfn] = mfn;
|
||||
}
|
||||
|
||||
/* VIRT <-> MACHINE conversion */
|
||||
#define virt_to_machine(v) (phys_to_machine(XPADDR(__pa(v))))
|
||||
#define virt_to_mfn(v) (pfn_to_mfn(PFN_DOWN(__pa(v))))
|
||||
|
Loading…
Reference in New Issue
Block a user