From 29cd9d5f209156f9db5df5c2b5064f6ff84fff32 Mon Sep 17 00:00:00 2001 From: Stephen Tweedie Date: Fri, 7 Dec 2007 11:39:27 +0000 Subject: [PATCH] xen acpi: Enable early access to ACPI tables. Always use the fixmap remapping to remap ACPI tables during boot in __acpi_map_table. Tables which are identity-mapped on baremetal may not be on Xen. Add xen-specific logic to detect when ioremap is being called on local RAM. Use isa_bus_to_virt on ISA regions for consistency with the fixmap code Use is_local_lowmem() to test for local non-highmem pages in a Xen- compatible way. Signed-off-by: Stephen Tweedie --- arch/x86/kernel/acpi/boot.c | 34 +++++++++++++++------------------- arch/x86/mm/ioremap_32.c | 34 ++++++++++++++++++++++++++-------- 2 files changed, 41 insertions(+), 27 deletions(-) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 0ca27c7..e59bda5 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -40,6 +40,8 @@ #include #include +#include + static int __initdata acpi_force = 0; #ifdef CONFIG_ACPI @@ -103,22 +105,6 @@ static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE; */ enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_PIC; -#ifdef CONFIG_X86_64 - -/* rely on all ACPI tables being in the direct mapping */ -char *__acpi_map_table(unsigned long phys_addr, unsigned long size) -{ - if (!phys_addr || !size) - return NULL; - - if (phys_addr+size <= (end_pfn_map << PAGE_SHIFT) + PAGE_SIZE) - return __va(phys_addr); - - return NULL; -} - -#else - /* * Temporarily use the virtual area starting from FIX_IO_APIC_BASE_END, * to map the target physical address. The problem is that set_fixmap() @@ -136,8 +122,19 @@ char *__acpi_map_table(unsigned long phys, unsigned long size) unsigned long base, offset, mapped_size; int idx; - if (phys + size < 8 * 1024 * 1024) - return __va(phys); + if (!phys || !size) + return NULL; + + if (!is_running_on_xen()) { +#ifdef CONFIG_X86_64 + /* rely on all ACPI tables being in the direct mapping */ + if (phys+size <= (end_pfn_map << PAGE_SHIFT) + PAGE_SIZE) + return __va(phys); +#else + if (phys + size < 8 * 1024 * 1024) + return __va(phys); +#endif + } offset = phys & (PAGE_SIZE - 1); mapped_size = PAGE_SIZE - offset; @@ -158,7 +155,6 @@ char *__acpi_map_table(unsigned long phys, unsigned long size) return ((unsigned char *)base + offset); } -#endif #ifdef CONFIG_PCI_MMCONFIG /* The physical address of the MMCONFIG aperture. Set from ACPI tables. */ diff --git a/arch/x86/mm/ioremap_32.c b/arch/x86/mm/ioremap_32.c index 63a301a..b4e71f4 100644 --- a/arch/x86/mm/ioremap_32.c +++ b/arch/x86/mm/ioremap_32.c @@ -18,6 +18,9 @@ #include #include +#include +#include + /* * Generic mapping function (not visible outside): */ @@ -31,6 +34,21 @@ * have to convert them into an offset in a page-aligned mapping, but the * caller shouldn't need to know that small detail. */ +/* + * Does @address reside within a non-highmem page that is local to this virtual + * machine (i.e., not an I/O page, nor a memory page belonging to another VM). + * See the comment that accompanies mfn_to_local_pfn() in page.h to understand + * why this works. + */ +static inline int is_local_lowmem(unsigned long address) +{ + extern unsigned long max_low_pfn; + if (is_running_on_xen()) + return (mfn_to_local_pfn(address >> PAGE_SHIFT) < max_low_pfn); + else + return (address <= virt_to_phys(high_memory - 1)); +} + void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) { void __iomem * addr; @@ -47,12 +65,12 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l * Don't remap the low PCI/ISA area, it's always mapped.. */ if (phys_addr >= ISA_START_ADDRESS && last_addr < ISA_END_ADDRESS) - return (void __iomem *) phys_to_virt(phys_addr); + return (void __iomem *) isa_bus_to_virt(phys_addr); /* * Don't allow anybody to remap normal RAM that we're using.. */ - if (phys_addr <= virt_to_phys(high_memory - 1)) { + if (is_local_lowmem(phys_addr)) { char *t_addr, *t_end; struct page *page; @@ -123,8 +141,8 @@ void __iomem *ioremap_nocache (unsigned long phys_addr, unsigned long size) /* Guaranteed to be > phys_addr, as per __ioremap() */ last_addr = phys_addr + size - 1; - if (last_addr < virt_to_phys(high_memory) - 1) { - struct page *ppage = virt_to_page(__va(phys_addr)); + if (is_local_lowmem(last_addr)) { + struct page *ppage = virt_to_page(bus_to_virt(phys_addr)); unsigned long npages; phys_addr &= PAGE_MASK; @@ -166,8 +184,8 @@ void iounmap(volatile void __iomem *addr) * vm_area and by simply returning an address into the kernel mapping * of ISA space. So handle that here. */ - if (addr >= phys_to_virt(ISA_START_ADDRESS) && - addr < phys_to_virt(ISA_END_ADDRESS)) + if (addr >= isa_bus_to_virt(ISA_START_ADDRESS) && + addr < isa_bus_to_virt(ISA_END_ADDRESS)) return; addr = (volatile void __iomem *)(PAGE_MASK & (unsigned long __force)addr); @@ -191,8 +209,8 @@ void iounmap(volatile void __iomem *addr) } /* Reset the direct mapping. Can block */ - if ((p->flags >> 20) && p->phys_addr < virt_to_phys(high_memory) - 1) { - change_page_attr(virt_to_page(__va(p->phys_addr)), + if ((p->flags >> 20) && is_local_lowmem(p->phys_addr)) { + change_page_attr(virt_to_page(bus_to_virt(p->phys_addr)), get_vm_area_size(p) >> PAGE_SHIFT, PAGE_KERNEL); global_flush_tlb(); -- 1.5.3.4