From 0947b2f31ca1ea1211d3cde2dbd8fcec579ef395 Mon Sep 17 00:00:00 2001 From: "Huang, Ying" Date: Wed, 30 Jan 2008 13:33:44 +0100 Subject: [PATCH] i386 boot: replace boot_ioremap with enhanced bt_ioremap - enhance bt_ioremap This patch makes it possible for bt_ioremap() to be used before paging_init(), via providing an early implementation of set_fixmap() that can be used before paging_init(). This way boot_ioremap() can be replaced by bt_ioremap(). Signed-off-by: Huang Ying Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner --- arch/x86/kernel/setup_32.c | 1 + arch/x86/mm/init_32.c | 2 + arch/x86/mm/ioremap_32.c | 87 +++++++++++++++++++++++++++++++++++++- include/asm-x86/io_32.h | 3 ++ 4 files changed, 91 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/setup_32.c b/arch/x86/kernel/setup_32.c index 83ba3ca5f431..35db426de300 100644 --- a/arch/x86/kernel/setup_32.c +++ b/arch/x86/kernel/setup_32.c @@ -697,6 +697,7 @@ void __init setup_arch(char **cmdline_p) memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data)); pre_setup_arch_hook(); early_cpu_init(); + bt_ioremap_init(); #ifdef CONFIG_EFI if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature, diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c index 206e3f6800b9..f4e1894367a6 100644 --- a/arch/x86/mm/init_32.c +++ b/arch/x86/mm/init_32.c @@ -429,9 +429,11 @@ static void __init pagetable_init (void) * Fixed mappings, only the page table structure has to be * created - mappings will be set by set_fixmap(): */ + bt_ioremap_clear(); vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK; end = (FIXADDR_TOP + PMD_SIZE - 1) & PMD_MASK; page_table_range_init(vaddr, end, pgd_base); + bt_ioremap_reset(); permanent_kmaps_init(pgd_base); diff --git a/arch/x86/mm/ioremap_32.c b/arch/x86/mm/ioremap_32.c index ef0f6a452ee1..fd1f5b6cfa20 100644 --- a/arch/x86/mm/ioremap_32.c +++ b/arch/x86/mm/ioremap_32.c @@ -208,6 +208,89 @@ void iounmap(volatile void __iomem *addr) } EXPORT_SYMBOL(iounmap); +static __initdata int after_paging_init; +static __initdata unsigned long bm_pte[1024] + __attribute__((aligned(PAGE_SIZE))); + +static inline unsigned long * __init bt_ioremap_pgd(unsigned long addr) +{ + return (unsigned long *)swapper_pg_dir + ((addr >> 22) & 1023); +} + +static inline unsigned long * __init bt_ioremap_pte(unsigned long addr) +{ + return bm_pte + ((addr >> PAGE_SHIFT) & 1023); +} + +void __init bt_ioremap_init(void) +{ + unsigned long *pgd; + + pgd = bt_ioremap_pgd(fix_to_virt(FIX_BTMAP_BEGIN)); + *pgd = __pa(bm_pte) | _PAGE_TABLE; + memset(bm_pte, 0, sizeof(bm_pte)); + BUG_ON(pgd != bt_ioremap_pgd(fix_to_virt(FIX_BTMAP_END))); +} + +void __init bt_ioremap_clear(void) +{ + unsigned long *pgd; + + pgd = bt_ioremap_pgd(fix_to_virt(FIX_BTMAP_BEGIN)); + *pgd = 0; + __flush_tlb_all(); +} + +void __init bt_ioremap_reset(void) +{ + enum fixed_addresses idx; + unsigned long *pte, phys, addr; + + after_paging_init = 1; + for (idx = FIX_BTMAP_BEGIN; idx <= FIX_BTMAP_END; idx--) { + addr = fix_to_virt(idx); + pte = bt_ioremap_pte(addr); + if (!*pte & _PAGE_PRESENT) { + phys = *pte & PAGE_MASK; + set_fixmap(idx, phys); + } + } +} + +static void __init __bt_set_fixmap(enum fixed_addresses idx, + unsigned long phys, pgprot_t flags) +{ + unsigned long *pte, addr = __fix_to_virt(idx); + + if (idx >= __end_of_fixed_addresses) { + BUG(); + return; + } + pte = bt_ioremap_pte(addr); + if (pgprot_val(flags)) + *pte = (phys & PAGE_MASK) | pgprot_val(flags); + else + *pte = 0; + __flush_tlb_one(addr); +} + +static inline void __init bt_set_fixmap(enum fixed_addresses idx, + unsigned long phys) +{ + if (after_paging_init) + set_fixmap(idx, phys); + else + __bt_set_fixmap(idx, phys, PAGE_KERNEL); +} + +static inline void __init bt_clear_fixmap(enum fixed_addresses idx) +{ + if (after_paging_init) + clear_fixmap(idx); + else + __bt_set_fixmap(idx, 0, __pgprot(0)); +} + void __init *bt_ioremap(unsigned long phys_addr, unsigned long size) { unsigned long offset, last_addr; @@ -244,7 +327,7 @@ void __init *bt_ioremap(unsigned long phys_addr, unsigned long size) */ idx = FIX_BTMAP_BEGIN; while (nrpages > 0) { - set_fixmap(idx, phys_addr); + bt_set_fixmap(idx, phys_addr); phys_addr += PAGE_SIZE; --idx; --nrpages; @@ -267,7 +350,7 @@ void __init bt_iounmap(void *addr, unsigned long size) idx = FIX_BTMAP_BEGIN; while (nrpages > 0) { - clear_fixmap(idx); + bt_clear_fixmap(idx); --idx; --nrpages; } diff --git a/include/asm-x86/io_32.h b/include/asm-x86/io_32.h index db3978846379..f7b733d9ace9 100644 --- a/include/asm-x86/io_32.h +++ b/include/asm-x86/io_32.h @@ -139,6 +139,9 @@ extern void iounmap(volatile void __iomem *addr); * mappings, before the real ioremap() is functional. * A boot-time mapping is currently limited to at most 16 pages. */ +extern void bt_ioremap_init(void); +extern void bt_ioremap_clear(void); +extern void bt_ioremap_reset(void); extern void *bt_ioremap(unsigned long offset, unsigned long size); extern void bt_iounmap(void *addr, unsigned long size); extern void __iomem *fix_ioremap(unsigned idx, unsigned long phys);