--- arch/x86/mm/init_64.c | 36 ++++++++++++++++++++++++++++++++++++ include/asm-x86/pgtable_64.h | 1 + include/linux/cpu_alloc.h | 25 +++++++++++++------------ 3 files changed, 50 insertions(+), 12 deletions(-) Index: linux-2.6/arch/x86/mm/init_64.c =================================================================== --- linux-2.6.orig/arch/x86/mm/init_64.c 2007-11-03 00:31:17.304239275 -0700 +++ linux-2.6/arch/x86/mm/init_64.c 2007-11-03 00:36:48.603694964 -0700 @@ -781,3 +781,39 @@ int __meminit vmemmap_populate(struct pa return 0; } #endif + +int __meminit cpu_area_populate(void *start, unsigned long size, + gfp_t flags, int node) +{ + unsigned long addr = (unsigned long)start; + unsigned long end = addr + size; + unsigned long next; + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + + for (; addr < end; addr = next) { + next = pmd_addr_end(addr, end); + + pgd = cpu_area_pgd_populate(addr, flags, node); + if (!pgd) + return -ENOMEM; + pud = cpu_area_pud_populate(pgd, addr, flags, node); + if (!pud) + return -ENOMEM; + + pmd = pmd_offset(pud, addr); + if (pmd_none(*pmd)) { + pte_t entry; + void *p = cpu_area_alloc_block(PMD_SIZE, flags, node); + if (!p) + return -ENOMEM; + + entry = pfn_pte(__pa(p) >> PAGE_SHIFT, PAGE_KERNEL); + mk_pte_huge(entry); + set_pmd(pmd, __pmd(pte_val(entry))); + } + } + + return 0; +} Index: linux-2.6/include/asm-x86/pgtable_64.h =================================================================== --- linux-2.6.orig/include/asm-x86/pgtable_64.h 2007-11-03 00:35:27.715694746 -0700 +++ linux-2.6/include/asm-x86/pgtable_64.h 2007-11-03 00:42:24.556444993 -0700 @@ -140,6 +140,7 @@ static inline pte_t ptep_get_and_clear_f #define VMEMMAP_START _AC(0xffffe20000000000, UL) #define CPU_AREA_BASE _AC(0xfffff20000000000, UL) #define CPU_AREA_BITS 43 +#define CPU_AREA_BLOCK_SHIFT PMD_SHIFT #define MODULES_VADDR _AC(0xffffffff88000000, UL) #define MODULES_END _AC(0xfffffffffff00000, UL) #define MODULES_LEN (MODULES_END - MODULES_VADDR) Index: linux-2.6/include/linux/cpu_alloc.h =================================================================== --- linux-2.6.orig/include/linux/cpu_alloc.h 2007-11-03 00:25:28.484694831 -0700 +++ linux-2.6/include/linux/cpu_alloc.h 2007-11-03 10:28:08.438303025 -0700 @@ -75,20 +75,21 @@ extern u8 cpu_area[]; #define CPU_AREA_SHIFT (CPU_AREA_BITS - ilog2(NR_CPUS)) -/* - * Special variable used to calculate the address of an object on the - * currently executing processor. The arch may provide their own - * THIS_CPU_OFFSET constant that may work more efficiently than this one. - * (Although this definition is typically very effective). - */ -#define THIS_CPU_OFFSET ((unsigned long)smp_processor_id() \ - << CPU_AREA_SHIFT) - #define CPU_PTR(__p, __cpu) ((__typeof__(__p))((void *)(__p) + \ ((unsigned long)(__cpu) << CPU_AREA_SHIFT))) - -#define THIS_CPU_PTR(__p) \ - ((__typeof__(__p))((void *)(__p) + THIS_CPU_OFFSET)) +/* Functions for populating the per cpu areas mappings */ +pgd_t *cpu_area_pgd_populate(unsigned long addr, gfp_t flags, int node); +pud_t *cpu_area_pud_populate(pgd_t *pgd, unsigned long addr, + gfp_t flags, int node); +pmd_t *cpu_area_pmd_populate(pud_t *pud, unsigned long addr, + gfp_t flags, int node); +pte_t *cpu_area_pte_populate(pmd_t *pmd, unsigned long addr, + gfp_t flags, int node); +void *cpu_area_alloc_block(unsigned long size, gfp_t flags, int node); +int cpu_area_populate_basepages(void *start, unsigned long size, + gfp_t flags, int node); +int cpu_area_populate(void *start, unsigned long size, + gfp_t flags, int node); #endif /* _LINUX_CPU_ALLOC_H_ */