This is an experimental (though tested) patch for early ioremap support on mips, before mem_init runs. Something like this is only needed on certain SoCs that have all of their I/O on high addresses such that they can't me ioremapped through kseg1. I think the CONFIG_64 stuff needs to removed since we don't need it. The patch was tested on a MIPS32 CPU only. Some of the significant changes: - trap_init() became early_trap_init() since too much stuff happens there that is needed to support early ioremap. The old trap_init() is now empty. - added plat_setup_late() call. All ports would need to add that call, or at least a placeholder. Early ioremap is possible only at that point. However, most of the code in each plat_setup() can be moved to plat_setup_late() diff -Naur --exclude=CVS linux-2.6-orig/arch/mips/kernel/setup.c linux-2.6-dev/arch/mips/kernel/setup.c --- linux-2.6-orig/arch/mips/kernel/setup.c 2005-08-24 17:12:31.000000000 -0700 +++ linux-2.6-dev/arch/mips/kernel/setup.c 2005-08-25 10:56:40.000000000 -0700 @@ -42,7 +42,10 @@ #include <asm/sections.h> #include <asm/setup.h> #include <asm/system.h> +#include <asm/traps.h> +#include <asm/io.h> +int init_bootmem_done; struct cpuinfo_mips cpu_data[NR_CPUS] __read_mostly; EXPORT_SYMBOL(cpu_data); @@ -417,6 +420,8 @@ /* Reserve the bootmap memory. */ reserve_bootmem(PFN_PHYS(first_usable_pfn), bootmap_size); + + init_bootmem_done = 1; #endif /* CONFIG_SGI_IP27 */ #ifdef CONFIG_BLK_DEV_INITRD @@ -511,7 +516,23 @@ #undef MAXMEM #undef MAXMEM_PFN +void __init early_ioremap_init(void) +{ +#ifdef CONFIG_64BIT + ioremap_base = (VMALLOC_START + PTRS_PER_PGD * PTRS_PER_PMD * PTRS_PER_PTE * PAGE_SIZE); +#else +#ifdef CONFIG_HIGHMEM + ioremap_base = (PKMAP_BASE-2*PAGE_SIZE); +#else + ioremap_base = (FIXADDR_START-2*PAGE_SIZE); +#endif +#endif /* CONFIG_64BIT */ + + ioremap_bot = ioremap_base; +} + extern void plat_setup(void); +extern void plat_setup_late(void); void __init setup_arch(char **cmdline_p) { @@ -540,6 +561,11 @@ sparse_init(); paging_init(); resource_init(); + + early_trap_init(); + early_ioremap_init(); + + plat_setup_late(); /* safe to do early ioremap */ } int __init fpu_disable(char *s) diff -Naur --exclude=CVS linux-2.6-orig/arch/mips/kernel/traps.c linux-2.6-dev/arch/mips/kernel/traps.c --- linux-2.6-orig/arch/mips/kernel/traps.c 2005-08-24 17:12:32.000000000 -0700 +++ linux-2.6-dev/arch/mips/kernel/traps.c 2005-08-25 00:39:39.000000000 -0700 @@ -1239,6 +1238,10 @@ void __init trap_init(void) { +} + +void __init early_trap_init(void) +{ extern char except_vec3_generic, except_vec3_r4000; extern char except_vec4; unsigned long i; diff -Naur --exclude=CVS linux-2.6-orig/arch/mips/mm/init.c linux-2.6-dev/arch/mips/mm/init.c --- linux-2.6-orig/arch/mips/mm/init.c 2005-08-10 18:15:55.000000000 -0700 +++ linux-2.6-dev/arch/mips/mm/init.c 2005-08-25 00:39:40.000000000 -0700 @@ -47,6 +47,8 @@ * don't have to care about aliases on other CPUs. */ unsigned long empty_zero_page, zero_page_mask; +int mem_init_done; +extern int init_bootmem_done; /* * Not static inline because used by IP27 special magic initialization code @@ -200,6 +202,17 @@ return 0; } +void __init *early_get_page(void) +{ + void *p; + if (init_bootmem_done) { + p = alloc_bootmem_pages(PAGE_SIZE); + } else { + p = NULL; + } + return p; +} + void __init mem_init(void) { unsigned long codesize, reservedpages, datasize, initsize; @@ -258,6 +271,8 @@ datasize >> 10, initsize >> 10, (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10))); + + mem_init_done = 1; } #endif /* !CONFIG_NEED_MULTIPLE_NODES */ diff -Naur --exclude=CVS linux-2.6-orig/arch/mips/mm/ioremap.c linux-2.6-dev/arch/mips/mm/ioremap.c --- linux-2.6-orig/arch/mips/mm/ioremap.c 2005-08-10 18:15:55.000000000 -0700 +++ linux-2.6-dev/arch/mips/mm/ioremap.c 2005-08-25 13:35:25.045624752 -0700 @@ -15,6 +15,8 @@ #include <asm/io.h> #include <asm/tlbflush.h> +extern int mem_init_done; + static inline void remap_area_pte(pte_t * pte, unsigned long address, phys_t size, phys_t phys_addr, unsigned long flags) { @@ -141,8 +143,9 @@ /* * Don't allow anybody to remap normal RAM that we're using.. + * mem_init() sets high_memory so only do the check after that. */ - if (phys_addr < virt_to_phys(high_memory)) { + if (mem_init_done && (phys_addr < virt_to_phys(high_memory))) { char *t_addr, *t_end; struct page *page; @@ -164,12 +167,18 @@ /* * Ok, go for it.. */ - area = get_vm_area(size, VM_IOREMAP); - if (!area) - return NULL; - addr = area->addr; + if (mem_init_done) { + area = get_vm_area(size, VM_IOREMAP); + if (!area) + return NULL; + addr = area->addr; + } + else { + addr = (void *)(ioremap_bot -= size); + } if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) { - vunmap(addr); + if (mem_init_done) + vunmap(addr); return NULL; } @@ -185,13 +194,15 @@ if (IS_KSEG1(addr)) return; - p = remove_vm_area((void *) (PAGE_MASK & (unsigned long __force) addr)); - if (!p) { - printk(KERN_ERR "iounmap: bad address %p\n", addr); - return; - } + if ((unsigned long) addr < ioremap_bot) { + p = remove_vm_area((void *) (PAGE_MASK & (unsigned long __force) addr)); + if (!p) { + printk(KERN_ERR "iounmap: bad address %p\n", addr); + return; + } - kfree(p); + kfree(p); + } } EXPORT_SYMBOL(__ioremap); diff -Naur --exclude=CVS linux-2.6-orig/arch/mips/mm/pgtable-32.c linux-2.6-dev/arch/mips/mm/pgtable-32.c --- linux-2.6-orig/arch/mips/mm/pgtable-32.c 2005-08-10 18:15:56.000000000 -0700 +++ linux-2.6-dev/arch/mips/mm/pgtable-32.c 2005-08-23 00:46:14.000000000 -0700 @@ -13,6 +13,9 @@ #include <asm/fixmap.h> #include <asm/pgtable.h> +unsigned long ioremap_base; +unsigned long ioremap_bot; + void pgd_init(unsigned long page) { unsigned long *p = (unsigned long *) page; diff -Naur --exclude=CVS linux-2.6-orig/include/asm-mips/io.h linux-2.6-dev/include/asm-mips/io.h --- linux-2.6-orig/include/asm-mips/io.h 2005-08-10 18:22:04.000000000 -0700 +++ linux-2.6-dev/include/asm-mips/io.h 2005-08-25 13:35:31.000000000 -0700 @@ -637,4 +637,6 @@ */ #define xlate_dev_kmem_ptr(p) p +extern void early_ioremap_init(void); + #endif /* _ASM_IO_H */ diff -Naur --exclude=CVS linux-2.6-orig/include/asm-mips/pgalloc.h linux-2.6-dev/include/asm-mips/pgalloc.h --- linux-2.6-orig/include/asm-mips/pgalloc.h 2005-08-10 18:22:02.000000000 -0700 +++ linux-2.6-dev/include/asm-mips/pgalloc.h 2005-08-25 01:49:04.000000000 -0700 @@ -67,8 +67,17 @@ unsigned long address) { pte_t *pte; + extern int mem_init_done; + extern void *early_get_page(void); - pte = (pte_t *) __get_free_pages(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO, PTE_ORDER); + if (mem_init_done) { + pte = (pte_t *) __get_free_pages(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO, PTE_ORDER); + } else { + pte = (pte_t *)early_get_page(); + if (pte) { + clear_page(pte); + } + } return pte; } diff -Naur --exclude=CVS linux-2.6-orig/include/asm-mips/pgtable-32.h linux-2.6-dev/include/asm-mips/pgtable-32.h --- linux-2.6-orig/include/asm-mips/pgtable-32.h 2005-08-25 13:02:30.000000000 -0700 +++ linux-2.6-dev/include/asm-mips/pgtable-32.h 2005-08-25 01:49:04.000000000 -0700 @@ -19,6 +19,8 @@ #include <asm-generic/pgtable-nopmd.h> +extern unsigned long ioremap_bot, ioremap_base; + /* * - add_wired_entry() add a fixed TLB entry, and move wired register */ @@ -74,13 +76,9 @@ #define USER_PTRS_PER_PGD (0x80000000UL/PGDIR_SIZE) #define FIRST_USER_ADDRESS 0 -#define VMALLOC_START MAP_BASE +#define VMALLOC_START MAP_BASE -#ifdef CONFIG_HIGHMEM -# define VMALLOC_END (PKMAP_BASE-2*PAGE_SIZE) -#else -# define VMALLOC_END (FIXADDR_START-2*PAGE_SIZE) -#endif +#define VMALLOC_END ioremap_bot #ifdef CONFIG_64BIT_PHYS_ADDR #define pte_ERROR(e) \ diff -Naur --exclude=CVS linux-2.6-orig/include/asm-mips/traps.h linux-2.6-dev/include/asm-mips/traps.h --- linux-2.6-orig/include/asm-mips/traps.h 2005-08-10 18:22:04.000000000 -0700 +++ linux-2.6-dev/include/asm-mips/traps.h 2005-08-25 10:56:01.000000000 -0700 @@ -24,4 +24,6 @@ extern void (*board_nmi_handler_setup)(void); extern void (*board_ejtag_handler_setup)(void); +extern void early_trap_init(void); + #endif /* _ASM_TRAPS_H */