fix discontig & virtual memmap combination
PATCH 1/1 fix discontig & virtual memmap combination
This patch fixes the combination of CONFIG_DISCONTIGMEM and CONFIG_VIRTUAL_MEM_MAP so that generic kernels will work on all ia64 platforms, including sn2, and also makes sn2 specific kernels work (which I think is a first).
I've cleaned this patch up heavily based on feedback from yourself, Christoph and others. I've tested sn2, zx1, and dig (thanks Xavier!) specific configurations, as well as a generic configuration that allows the same binary to boot on zx1, dig, and sn2.
arch/ia64/Kconfig | 30 -- arch/ia64/kernel/acpi.c | 30 -- arch/ia64/kernel/setup.c | 35 -- arch/ia64/mm/contig.c | 43 +++ arch/ia64/mm/discontig.c | 618 +++++++++++++++++++++++++++----------------- arch/ia64/mm/init.c | 9 include/asm-ia64/meminit.h | 15 - include/asm-ia64/mmzone.h | 159 +---------- include/asm-ia64/nodedata.h | 36 -- include/asm-ia64/numa.h | 13 include/asm-ia64/page.h | 18 - include/asm-ia64/percpu.h | 2 include/asm-ia64/pgtable.h | 4
Thanks,
Jesse
arch/ia64/Kconfig +5 -25
@@ -220,24 +220,8 @@ Access). This option is for configuring high-end multiprocessor server systems. If in doubt, say N. -choice - prompt "Maximum Memory per NUMA Node" if NUMA && IA64_DIG - depends on NUMA && IA64_DIG - default IA64_NODESIZE_16GB - -config IA64_NODESIZE_16GB - bool "16GB" - -config IA64_NODESIZE_64GB - bool "64GB" - -config IA64_NODESIZE_256GB - bool "256GB" - -endchoice - config DISCONTIGMEM - bool "Discontiguous memory support" if (IA64_DIG || IA64_SGI_SN2 || IA64_GENERIC) && NUMA + bool "Discontiguous memory support" if (IA64_DIG || IA64_SGI_SN2 || IA64_GENERIC) && NUMA && VIRTUAL_MEM_MAP default y if (IA64_SGI_SN2 || IA64_GENERIC) && NUMA help Say Y to support efficient handling of discontiguous physical memory,
@@ -250,14 +234,10 @@ default y if !IA64_HP_SIM help Say Y to compile the kernel with support for a virtual mem map. - This is an alternate method of supporting large holes in the - physical address space on non NUMA machines. Since the DISCONTIGMEM - option is not supported on machines with the ZX1 chipset, this is - the only way of supporting more than 1 Gb of memory on those - machines. This code also only takes effect if a memory hole of - greater than 1 Gb is found during boot, so it is safe to enable - unless you require the DISCONTIGMEM option for your machine. If you - are unsure, say Y. + This code also only takes effect if a memory hole of greater than + 1 Gb is found during boot. You must turn this option on if you + require the DISCONTIGMEM option for your machine. If you are + unsure, say Y. config IA64_MCA bool "Enable IA-64 Machine Check Abort"
arch/ia64/kernel/acpi.c +1 -29
@@ -379,7 +379,7 @@void __init acpi_numa_memory_affinity_init (struct acpi_table_memory_affinity *ma) { -unsigned long paddr, size, hole_size, min_hole_size; +unsigned long paddr, size;u8 pxm;struct node_memblk_s *p, *q, *pend;
@@ -400,34 +400,6 @@/* Ignore disabled entries */ if (!ma->flags.enabled)return ; - -/* -* When the chunk is not the first one in the node, check distance -* from the other chunks. When the hole is too huge ignore the chunk. -* This restriction should be removed when multiple chunks per node -* is supported. -*/ - pend = &node_memblk[num_memblks]; - min_hole_size =0 ; -for (p = &node_memblk[0 ]; p < pend; p++) { -if (p->nid != pxm) -continue ; -if (p->start_paddr < paddr) - hole_size = paddr - (p->start_paddr + p->size); -else - hole_size = p->start_paddr - (paddr + size); - -if (!min_hole_size || hole_size < min_hole_size) - min_hole_size = hole_size; - } - -if (min_hole_size) { -if (min_hole_size > size) { -printk (KERN_ERR "Too huge memory hole. Ignoring %ld MBytes at %lx\n" , - size/(1024 *1024 ), paddr); -return ; - } - }/* record this node in proximity bitmap */ pxm_bit_set (pxm);
arch/ia64/kernel/setup.c +4 -31
@@ -101,7 +101,7 @@ filter_rsvd_memory (unsigned long start, unsigned long end, void *arg) {unsigned long range_start, range_end, prev_start; -void (*func)(unsigned long ,unsigned long ); +void (*func)(unsigned long ,unsigned long ,int );int i;#if IGNORE_PFN0
@@ -122,11 +122,8 @@ range_end =min (end, rsvd_region[i].start);if (range_start < range_end) -#ifdef CONFIG_DISCONTIGMEM -call_pernode_memory (__pa (range_start),__pa (range_end), func); -#else - (*func)(__pa (range_start), range_end - range_start); -#endif +call_pernode_memory (__pa (range_start), + range_end - range_start, func);/* nothing more available in this segment */ if (range_end = end)return 0 ;
@@ -545,28 +542,7 @@struct cpuinfo_ia64 *cpu_info;void *cpu_data; -#ifdef CONFIG_SMP -int cpu; - -/* -* get_free_pages() cannot be used before cpu_init() done. BSP allocates -* "NR_CPUS" pages for all CPUs to avoid that AP calls get_zeroed_page(). -*/ -if (smp_processor_id () =0 ) { - cpu_data =__alloc_bootmem (PERCPU_PAGE_SIZE *NR_CPUS ,PERCPU_PAGE_SIZE , -__pa (MAX_DMA_ADDRESS )); -for (cpu =0 ; cpu <NR_CPUS ; cpu++) { -memcpy (cpu_data, __phys_per_cpu_start, __per_cpu_end - __per_cpu_start); - __per_cpu_offset[cpu] = (char *) cpu_data - __per_cpu_start; - cpu_data +=PERCPU_PAGE_SIZE ; - -per_cpu (local_per_cpu_offset, cpu) = __per_cpu_offset[cpu]; - } - } - cpu_data = __per_cpu_start + __per_cpu_offset[smp_processor_id ()]; -#else /* !CONFIG_SMP */ - cpu_data = __phys_per_cpu_start; -#endif /* !CONFIG_SMP */ + cpu_data =per_cpu_init ();get_max_cacheline_size ();
@@ -577,9 +553,6 @@* accessing cpu_data() through the canonical per-CPU address. */ cpu_info = cpu_data + ((char *) &__ia64_per_cpu_var (cpu_info) - __per_cpu_start); -#ifdef CONFIG_NUMA - cpu_info->node_data =get_node_data_ptr (); -#endif identify_cpu (cpu_info);#ifdef CONFIG_MCKINLEY
arch/ia64/mm/contig.c +42 -0
48 lines not on this page · raw message
arch/ia64/mm/discontig.c +387 -227
712 lines not on this page · raw message
arch/ia64/mm/init.c +0 -9
@@ -450,15 +450,6 @@ }#endif /* CONFIG_VIRTUAL_MEM_MAP */ -int -count_pages (u64 start,u64 end,void *arg) -{ -unsigned long *count = arg; - - *count += (end - start) >>PAGE_SHIFT ; -return 0 ; -} -static int count_reserved_pages (u64 start,u64 end,void *arg) {
include/asm-ia64/meminit.h +12 -3
@@ -8,7 +8,6 @@*/ #include <linux/config.h> -#include <linux/mm.h> /* * Entries defined so far:
@@ -34,16 +33,26 @@extern void reserve_memory (void );extern void find_initrd (void );extern int filter_rsvd_memory (unsigned long start,unsigned long end,void *arg); -extern int count_pages (u64 start,u64 end,void *arg); + +/* +* For rounding an address to the next IA64_GRANULE_SIZE or order +*/ +#define GRANULEROUNDDOWN (n) ((n) & ~(IA64_GRANULE_SIZE-1)) +#define GRANULEROUNDUP (n) (((n)+IA64_GRANULE_SIZE-1) & ~(IA64_GRANULE_SIZE-1)) +#define ORDERROUNDDOWN (n) ((n) & ~((PAGE_SIZE<<MAX_ORDER)-1))#ifdef CONFIG_DISCONTIGMEM -extern void call_pernode_memory (unsigned long start,unsigned long end,void *arg); +extern void call_pernode_memory (unsigned long start,unsigned long len, +void *func); +#else +#define call_pernode_memory (start, len, func) (*func)(start, len, 0)#endif #define IGNORE_PFN0 1/* XXX fix me: ignore pfn 0 until TLB miss handler is updated... */ #ifdef CONFIG_VIRTUAL_MEM_MAP #define LARGE_GAP 0x40000000/* Use virtual mem map if hole is > than this */ +extern unsigned long vmalloc_end;extern struct page *vmem_map;extern int find_largest_hole (u64 start,u64 end,void *arg);extern int create_mem_map_page_table (u64 start,u64 end,void *arg);
include/asm-ia64/mmzone.h +17 -142
176 lines not on this page · raw message
include/asm-ia64/nodedata.h +6 -30
@@ -13,9 +13,12 @@#ifndef _ASM_IA64_NODEDATA_H#define _ASM_IA64_NODEDATA_H - +#include <linux/config.h> +#include <asm/percpu.h> #include <asm/mmzone.h> +#ifdef CONFIG_DISCONTIGMEM +/* * Node Data. One of these structures is located on each node of a NUMA system. */
@@ -24,10 +27,7 @@struct ia64_node_data {short active_cpu_count;short node; -struct pglist_data *pg_data_ptrs[NR_NODES ]; -struct page *bank_mem_map_base[NR_BANKS ]; -struct ia64_node_data *node_data_ptrs[NR_NODES ]; -short node_id_map[NR_BANKS ]; +struct pglist_data *pg_data_ptrs[NR_NODES ]; };
@@ -36,41 +36,17 @@*/ #define local_node_data (local_cpu_data->node_data) - -/* -* Return a pointer to the node_data structure for the specified node. -*/ -#define node_data (node) (local_node_data->node_data_ptrs[node]) - -/* -* Get a pointer to the node_id/node_data for the current cpu. -* (boot time only) -*/ -extern int boot_get_local_nodeid (void ); -extern struct ia64_node_data *get_node_data_ptr (void ); -/* * Given a node id, return a pointer to the pg_data_t for the node. -* The following 2 macros are similar. * * NODE_DATA - should be used in all code not related to system * initialization. It uses pernode data structures to minimize * offnode memory references. However, these structure are not * present during boot. This macro can be used once cpu_init * completes. -* -* BOOT_NODE_DATA -* - should be used during system initialization -* prior to freeing __initdata. It does not depend on the percpu -* area being present. -* -* NOTE: The names of these macros are misleading but are difficult to change -* since they are used in generic linux & on other architecures. */ #define NODE_DATA (nid) (local_node_data->pg_data_ptrs[nid]) -#define BOOT_NODE_DATA (nid) boot_get_pg_data_ptr((long)(nid)) -struct pglist_data ; -extern struct pglist_data *__init boot_get_pg_data_ptr (long ); +#endif /* CONFIG_DISCONTIGMEM */ #endif /* _ASM_IA64_NODEDATA_H */
include/asm-ia64/numa.h +4 -9
@@ -13,18 +13,13 @@#include <linux/config.h> #include <linux/cpumask.h> +#include <linux/cache.h> +#include <linux/threads.h> +#include <linux/smp.h> +#include <asm/mmzone.h> #ifdef CONFIG_NUMA -#ifdef CONFIG_DISCONTIGMEM -# include <asm/mmzone.h> -# define NR_MEMBLKS (NR_BANKS) -#else -# define NR_NODES (8) -# define NR_MEMBLKS (NR_NODES * 8) -#endif - -#include <linux/cache.h> extern volatile char cpu_to_node_map[NR_CPUS] __cacheline_aligned; extern volatile cpumask_t node_to_cpu_mask[NR_NODES] __cacheline_aligned;
include/asm-ia64/page.h +10 -8
@@ -94,18 +94,20 @@#define virt_addr_valid (kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) +#ifdef CONFIG_VIRTUAL_MEM_MAP +extern int ia64_pfn_valid (unsigned long pfn); +#else +#define ia64_pfn_valid (pfn) 1 +#endif +#ifndef CONFIG_DISCONTIGMEM -# ifdef CONFIG_VIRTUAL_MEM_MAP -extern int ia64_pfn_valid (unsigned long pfn); -# define pfn_valid (pfn) (((pfn) < max_mapnr) && ia64_pfn_valid(pfn)) -# else -# define pfn_valid (pfn) ((pfn) < max_mapnr) -# endif -#define virt_to_page (kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) +#define pfn_valid (pfn) (((pfn) < max_mapnr) && ia64_pfn_valid(pfn))#define page_to_pfn (page) ((unsigned long) (page - mem_map))#define pfn_to_page (pfn) (mem_map + (pfn)) +#endif /* CONFIG_DISCONTIGMEM */ +#define page_to_phys (page) (page_to_pfn(page) << PAGE_SHIFT) -#endif +#define virt_to_page (kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) typedef union ia64_va { struct {
include/asm-ia64/percpu.h +2 -0
@@ -46,11 +46,13 @@extern void percpu_modcopy (void *pcpudst,const void *src,unsigned long size);extern void setup_per_cpu_areas (void ); +extern void *per_cpu_init (void );#else /* ! SMP */ #define per_cpu (var, cpu) ((void)cpu, per_cpu__##var)#define __get_cpu_var (var) per_cpu__##var +#define per_cpu_init () (__phys_per_cpu_start)#endif /* SMP */
include/asm-ia64/pgtable.h +0 -1
@@ -174,7 +174,6 @@return (addr & (local_cpu_data->unimpl_pa_mask)) =0 ; } -#ifndef CONFIG_DISCONTIGMEM /* * kern_addr_valid(ADDR) tests if ADDR is pointing to valid kernel * memory. For the return value to be meaningful, ADDR must be >@@ -190,7 +189,6 @@
*/
#define kern_addr_valid(addr) (1)
-#endif
/*
* Now come the defines and routines to manage and access the three-level
@@ -241,10 +239,8 @@
#define pte_none(pte) (!pte_val(pte))
#define pte_present(pte) (pte_val(pte) & (_PAGE_P | _PAGE_PROTNONE))
#define pte_clear(pte) (pte_val(*(pte)) = 0UL)
-#ifndef CONFIG_DISCONTIGMEM
/* pte_page() returns the "struct page *" corresponding to the PTE: */
#define pte_page(pte) virt_to_page(((pte_val(pte) & _PFN_MASK) + PAGE_OFFSET))
-#endif
#define pmd_none(pmd) (!pmd_val(pmd))
#define pmd_bad(pmd) (!ia64_phys_addr_valid(pmd_val(pmd)))