Index: linux-2.6/arch/ia64/Kconfig =================================================================== --- linux-2.6.orig/arch/ia64/Kconfig 2007-03-25 22:15:35.000000000 -0700 +++ linux-2.6/arch/ia64/Kconfig 2007-03-25 22:16:12.000000000 -0700 @@ -350,6 +350,10 @@ def_bool y depends on ARCH_DISCONTIGMEM_ENABLE +config VMEMMAP + def_bool y + depends on ARCH_SPARSEMEM_ENABLE + config ARCH_DISCONTIGMEM_DEFAULT def_bool y if (IA64_SGI_SN2 || IA64_GENERIC || IA64_HP_ZX1 || IA64_HP_ZX1_SWIOTLB) depends on ARCH_DISCONTIGMEM_ENABLE Index: linux-2.6/arch/ia64/kernel/ivt.S =================================================================== --- linux-2.6.orig/arch/ia64/kernel/ivt.S 2007-03-25 22:15:35.000000000 -0700 +++ linux-2.6/arch/ia64/kernel/ivt.S 2007-03-25 22:16:12.000000000 -0700 @@ -374,7 +374,9 @@ movl r19=(((1 << IA64_MAX_PHYS_BITS) - 1) & ~0xfff) mov r21=cr.ipsr mov r31=pr + mov r18=cr.itir ;; + tbit.nz p6,p0=r18,60 // bit marks special vmemmark processing. #ifdef CONFIG_DISABLE_VHPT shr.u r22=r16,61 // get the region number into r21 ;; @@ -386,6 +388,16 @@ (p8) mov r29=b0 // save b0 (p8) br.cond.dptk dtlb_fault #endif + // + // Vmemmap processing. Lookup the relevant pfn in the linear table + // + LOAD_PHYSICAL(p6, r22, vmemmap_table) +(p6) dep.z r23=r18,IA64_VMEM_SHIFT, MAX_PHYSMEM_BITS - IA64_VMEM_SHIFT,3 + ;; +(p6) add r22=r22,r23 // vmemmap_table + addr[IA64_VMEM_SHIFT .. MAX_PHYSMEM_BITS] + ;; +(p6) mov r19=[r22] // load pfn + ;; extr.u r23=r21,IA64_PSR_CPL0_BIT,2 // extract psr.cpl and r22=IA64_ISR_CODE_MASK,r20 // get the isr.code field tbit.nz p6,p7=r20,IA64_ISR_SP_BIT // is speculation bit on? Index: linux-2.6/arch/ia64/mm/discontig.c =================================================================== --- linux-2.6.orig/arch/ia64/mm/discontig.c 2007-03-25 22:15:35.000000000 -0700 +++ linux-2.6/arch/ia64/mm/discontig.c 2007-03-25 22:36:08.000000000 -0700 @@ -44,6 +44,40 @@ unsigned long max_pfn; }; +#ifdef CONFIG_VMEMMAP +#define PAGE_STRUCT_SHIFT 6 + +pte_t vmemmap_table[1UL << (MAX_PHYSMEM_BITS - PAGE_SHIFT + - IA64_GRANULE_SHIFT + PAGE_STRUCT_SHIFT)]; + +#if (sizeof(struct page) > (1 << PAGE_STRUCT_SHIFT)) +#error "Page struct too large. PAGE_STRUCT_SHIFT needs to be increased." +#endif + +void vmemmap_populate(struct page *start, int nr, int node) +{ + unsigned addr = GRANULEROUNDDOWN((unsigned long)start); + unsigned end = (unsigned long)(start + nr); + + for(; addr < end; addr += IA64_GRANULE_SIZE) { + unsigned long vmem_page = addr >> IA64_GRANULE_SHIFT; + + if (!vmemmap_table[vmem_page]) { + block = vmem_alloc_block(IA64_GRANULE_SIZE, node); + pte_t pte = pfn_to_pte(block >> IA64_GRANULE_SHIFT, + PAGE_KERNEL); + + BUG_ON(!block); + BUG_ON(block & (IA64_GRANULE_SIZE - 1)); + pte = pte_mkwrite(pte); + pte = pte_mkdirty(pte); + pte = pte_mkyoung(pte); + vmemmap_table[vmem_page] = pte; + } + } +} +#endif + static struct early_node_data mem_data[MAX_NUMNODES] __initdata; static nodemask_t memory_less_mask __initdata; Index: linux-2.6/include/asm-ia64/page.h =================================================================== --- linux-2.6.orig/include/asm-ia64/page.h 2007-03-25 22:17:02.000000000 -0700 +++ linux-2.6/include/asm-ia64/page.h 2007-03-25 22:20:29.000000000 -0700 @@ -97,6 +97,9 @@ #define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE +#define ARCH_VMEMMAP_POPULATE +#define vmemmap ((struct page *)(RGN_BASE(RGN_KERNEL) + 1UL << 60)) + #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) #ifdef CONFIG_VIRTUAL_MEM_MAP