From 7347aefbccb47ce2d076d8ac7dff2cdd1435974c Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 23 Apr 2008 23:30:59 -0700 Subject: [LMB]: Fix lmb allocation regression. Changeset d9024df02ffe74d723d97d552f86de3b34beb8cc ("[LMB] Restructure allocation loops to avoid unsigned underflow") removed the alignment of the 'size' argument to call lmb_add_region() done by __lmb_alloc_base(). In doing so it reintroduced the bug fixed by changeset eea89e13a9c61d3928223d2f9bf2295e22e0efb6 ("[LMB]: Fix bug in __lmb_alloc_base()."). This puts it back. Signed-off-by: David S. Miller --- lib/lmb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/lmb.c b/lib/lmb.c index 896e2832099..207147ab25e 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -346,7 +346,7 @@ u64 __init __lmb_alloc_base(u64 size, u64 align, u64 max_addr) if (j < 0) { /* this area isn't reserved, take it */ if (lmb_add_region(&lmb.reserved, base, - size) < 0) + lmb_align_up(size, align)) < 0) return 0; return base; } -- cgit v1.2.3-18-g5258 From 4e82c9a606da2b1c1c7ea7dfd8052626a4c6d5d6 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 13 Feb 2008 18:00:03 -0800 Subject: [SPARC64]: Move ramdisk discovery code out to seperate function. And add some comments explaining all of the quirks involved in the way the bootloader provides this information. Signed-off-by: David S. Miller --- arch/sparc64/mm/init.c | 57 +++++++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index f37078d9640..21e9267608c 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -883,6 +883,37 @@ static void __init trim_pavail(unsigned long *cur_size_p, } } +static void __init find_ramdisk(unsigned long phys_base) +{ +#ifdef CONFIG_BLK_DEV_INITRD + if (sparc_ramdisk_image || sparc_ramdisk_image64) { + unsigned long ramdisk_image; + + /* Older versions of the bootloader only supported a + * 32-bit physical address for the ramdisk image + * location, stored at sparc_ramdisk_image. Newer + * SILO versions set sparc_ramdisk_image to zero and + * provide a full 64-bit physical address at + * sparc_ramdisk_image64. + */ + ramdisk_image = sparc_ramdisk_image; + if (!ramdisk_image) + ramdisk_image = sparc_ramdisk_image64; + + /* Another bootloader quirk. The bootloader normalizes + * the physical address to KERNBASE, so we have to + * factor that back out and add in the lowest valid + * physical page address to get the true physical address. + */ + ramdisk_image -= KERNBASE; + ramdisk_image += phys_base; + + initrd_start = ramdisk_image; + initrd_end = ramdisk_image + sparc_ramdisk_size; + } +#endif +} + /* About pages_avail, this is the value we will use to calculate * the zholes_size[] argument given to free_area_init_node(). The * page allocator uses this to calculate nr_kernel_pages, @@ -912,30 +943,6 @@ static unsigned long __init bootmem_init(unsigned long *pages_avail, bytes_avail += pavail[i].reg_size; } - /* Determine the location of the initial ramdisk before trying - * to honor the "mem=xxx" command line argument. We must know - * where the kernel image and the ramdisk image are so that we - * do not trim those two areas from the physical memory map. - */ - -#ifdef CONFIG_BLK_DEV_INITRD - /* Now have to check initial ramdisk, so that bootmap does not overwrite it */ - if (sparc_ramdisk_image || sparc_ramdisk_image64) { - unsigned long ramdisk_image = sparc_ramdisk_image ? - sparc_ramdisk_image : sparc_ramdisk_image64; - ramdisk_image -= KERNBASE; - initrd_start = ramdisk_image + phys_base; - initrd_end = initrd_start + sparc_ramdisk_size; - if (initrd_end > end_of_phys_memory) { - printk(KERN_CRIT "initrd extends beyond end of memory " - "(0x%016lx > 0x%016lx)\ndisabling initrd\n", - initrd_end, end_of_phys_memory); - initrd_start = 0; - initrd_end = 0; - } - } -#endif - if (cmdline_memory_size && bytes_avail > cmdline_memory_size) trim_pavail(&bytes_avail, @@ -1337,6 +1344,8 @@ void __init paging_init(void) for (i = 0; i < pavail_ents; i++) phys_base = min(phys_base, pavail[i].phys_addr); + find_ramdisk(phys_base); + set_bit(0, mmu_context_bmap); shift = kern_base + PAGE_OFFSET - ((unsigned long)KERNBASE); -- cgit v1.2.3-18-g5258 From 3b2a7e23a9808e349bc5fb32327bacc5e81be79c Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 13 Feb 2008 18:13:20 -0800 Subject: [SPARC64]: Initialize LMB tables. Call lmb_add() on available regions, and call lmb_reserve() on the main kernel image and the ramdisk (if any). Signed-off-by: David S. Miller --- arch/sparc64/mm/init.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 21e9267608c..6eb76243fa9 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -910,6 +911,8 @@ static void __init find_ramdisk(unsigned long phys_base) initrd_start = ramdisk_image; initrd_end = ramdisk_image + sparc_ramdisk_size; + + lmb_reserve(initrd_start, initrd_end); } #endif } @@ -1337,15 +1340,24 @@ void __init paging_init(void) sun4v_ktsb_init(); } + lmb_init(); + /* Find available physical memory... */ read_obp_memory("available", &pavail[0], &pavail_ents); phys_base = 0xffffffffffffffffUL; - for (i = 0; i < pavail_ents; i++) + for (i = 0; i < pavail_ents; i++) { phys_base = min(phys_base, pavail[i].phys_addr); + lmb_add(pavail[i].phys_addr, pavail[i].reg_size); + } + + lmb_reserve(kern_base, kern_size); find_ramdisk(phys_base); + lmb_analyze(); + lmb_dump_all(); + set_bit(0, mmu_context_bmap); shift = kern_base + PAGE_OFFSET - ((unsigned long)KERNBASE); -- cgit v1.2.3-18-g5258 From 25b0c659dfb94f1ddaeda7a8c88ef7043f57f419 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 13 Feb 2008 18:20:14 -0800 Subject: [SPARC64]: Start using LMB information in bootmem_init(). This allows us to kill the incredibly complicated and stupid function trim_pavail(). Signed-off-by: David S. Miller --- arch/sparc64/mm/init.c | 132 +++---------------------------------------------- 1 file changed, 6 insertions(+), 126 deletions(-) diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 6eb76243fa9..3e6c4ecb8fe 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -775,115 +775,6 @@ static unsigned long __init choose_bootmap_pfn(unsigned long start_pfn, prom_halt(); } -static void __init trim_pavail(unsigned long *cur_size_p, - unsigned long *end_of_phys_p) -{ - unsigned long to_trim = *cur_size_p - cmdline_memory_size; - unsigned long avoid_start, avoid_end; - int i; - - to_trim = PAGE_ALIGN(to_trim); - - avoid_start = avoid_end = 0; -#ifdef CONFIG_BLK_DEV_INITRD - avoid_start = initrd_start; - avoid_end = PAGE_ALIGN(initrd_end); -#endif - - /* Trim some pavail[] entries in order to satisfy the - * requested "mem=xxx" kernel command line specification. - * - * We must not trim off the kernel image area nor the - * initial ramdisk range (if any). Also, we must not trim - * any pavail[] entry down to zero in order to preserve - * the invariant that all pavail[] entries have a non-zero - * size which is assumed by all of the code in here. - */ - for (i = 0; i < pavail_ents; i++) { - unsigned long start, end, kern_end; - unsigned long trim_low, trim_high, n; - - kern_end = PAGE_ALIGN(kern_base + kern_size); - - trim_low = start = pavail[i].phys_addr; - trim_high = end = start + pavail[i].reg_size; - - if (kern_base >= start && - kern_base < end) { - trim_low = kern_base; - if (kern_end >= end) - continue; - } - if (kern_end >= start && - kern_end < end) { - trim_high = kern_end; - } - if (avoid_start && - avoid_start >= start && - avoid_start < end) { - if (trim_low > avoid_start) - trim_low = avoid_start; - if (avoid_end >= end) - continue; - } - if (avoid_end && - avoid_end >= start && - avoid_end < end) { - if (trim_high < avoid_end) - trim_high = avoid_end; - } - - if (trim_high <= trim_low) - continue; - - if (trim_low == start && trim_high == end) { - /* Whole chunk is available for trimming. - * Trim all except one page, in order to keep - * entry non-empty. - */ - n = (end - start) - PAGE_SIZE; - if (n > to_trim) - n = to_trim; - - if (n) { - pavail[i].phys_addr += n; - pavail[i].reg_size -= n; - to_trim -= n; - } - } else { - n = (trim_low - start); - if (n > to_trim) - n = to_trim; - - if (n) { - pavail[i].phys_addr += n; - pavail[i].reg_size -= n; - to_trim -= n; - } - if (to_trim) { - n = end - trim_high; - if (n > to_trim) - n = to_trim; - if (n) { - pavail[i].reg_size -= n; - to_trim -= n; - } - } - } - - if (!to_trim) - break; - } - - /* Recalculate. */ - *cur_size_p = 0UL; - for (i = 0; i < pavail_ents; i++) { - *end_of_phys_p = pavail[i].phys_addr + - pavail[i].reg_size; - *cur_size_p += pavail[i].reg_size; - } -} - static void __init find_ramdisk(unsigned long phys_base) { #ifdef CONFIG_BLK_DEV_INITRD @@ -935,25 +826,11 @@ static unsigned long __init bootmem_init(unsigned long *pages_avail, unsigned long phys_base) { unsigned long bootmap_size, end_pfn; - unsigned long end_of_phys_memory = 0UL; - unsigned long bootmap_pfn, bytes_avail, size; + unsigned long bootmap_pfn, size; int i; - bytes_avail = 0UL; - for (i = 0; i < pavail_ents; i++) { - end_of_phys_memory = pavail[i].phys_addr + - pavail[i].reg_size; - bytes_avail += pavail[i].reg_size; - } - - if (cmdline_memory_size && - bytes_avail > cmdline_memory_size) - trim_pavail(&bytes_avail, - &end_of_phys_memory); - - *pages_avail = bytes_avail >> PAGE_SHIFT; - - end_pfn = end_of_phys_memory >> PAGE_SHIFT; + *pages_avail = lmb_phys_mem_size() >> PAGE_SHIFT; + end_pfn = lmb_end_of_DRAM() >> PAGE_SHIFT; /* Initialize the boot-time allocator. */ max_pfn = max_low_pfn = end_pfn; @@ -1355,6 +1232,9 @@ void __init paging_init(void) find_ramdisk(phys_base); + if (cmdline_memory_size) + lmb_enforce_memory_limit(phys_base + cmdline_memory_size); + lmb_analyze(); lmb_dump_all(); -- cgit v1.2.3-18-g5258 From 9422273ba7d139537720c8c47514925d9a621e0d Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 13 Feb 2008 18:31:41 -0800 Subject: [SPARC64]: Fully use LMB information in bootmem_init(). Signed-off-by: David S. Miller --- arch/sparc64/mm/init.c | 100 +++++++++---------------------------------------- 1 file changed, 18 insertions(+), 82 deletions(-) diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 3e6c4ecb8fe..90e644a0e93 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -722,57 +722,12 @@ out: static unsigned long __init choose_bootmap_pfn(unsigned long start_pfn, unsigned long end_pfn) { - unsigned long avoid_start, avoid_end, bootmap_size; - int i; + unsigned long bootmap_size; bootmap_size = bootmem_bootmap_pages(end_pfn - start_pfn); bootmap_size <<= PAGE_SHIFT; - avoid_start = avoid_end = 0; -#ifdef CONFIG_BLK_DEV_INITRD - avoid_start = initrd_start; - avoid_end = PAGE_ALIGN(initrd_end); -#endif - - for (i = 0; i < pavail_ents; i++) { - unsigned long start, end; - - start = pavail[i].phys_addr; - end = start + pavail[i].reg_size; - - while (start < end) { - if (start >= kern_base && - start < PAGE_ALIGN(kern_base + kern_size)) { - start = PAGE_ALIGN(kern_base + kern_size); - continue; - } - if (start >= avoid_start && start < avoid_end) { - start = avoid_end; - continue; - } - - if ((end - start) < bootmap_size) - break; - - if (start < kern_base && - (start + bootmap_size) > kern_base) { - start = PAGE_ALIGN(kern_base + kern_size); - continue; - } - - if (start < avoid_start && - (start + bootmap_size) > avoid_start) { - start = avoid_end; - continue; - } - - /* OK, it doesn't overlap anything, use it. */ - return start >> PAGE_SHIFT; - } - } - - prom_printf("Cannot find free area for bootmap, aborting.\n"); - prom_halt(); + return lmb_alloc(bootmap_size, PAGE_SIZE) >> PAGE_SHIFT; } static void __init find_ramdisk(unsigned long phys_base) @@ -825,8 +780,7 @@ static void __init find_ramdisk(unsigned long phys_base) static unsigned long __init bootmem_init(unsigned long *pages_avail, unsigned long phys_base) { - unsigned long bootmap_size, end_pfn; - unsigned long bootmap_pfn, size; + unsigned long end_pfn; int i; *pages_avail = lmb_phys_mem_size() >> PAGE_SHIFT; @@ -836,49 +790,31 @@ static unsigned long __init bootmem_init(unsigned long *pages_avail, max_pfn = max_low_pfn = end_pfn; min_low_pfn = (phys_base >> PAGE_SHIFT); - bootmap_pfn = choose_bootmap_pfn(min_low_pfn, end_pfn); - - bootmap_size = init_bootmem_node(NODE_DATA(0), bootmap_pfn, - min_low_pfn, end_pfn); + init_bootmem_node(NODE_DATA(0), + choose_bootmap_pfn(min_low_pfn, end_pfn), + min_low_pfn, end_pfn); /* Now register the available physical memory with the * allocator. */ - for (i = 0; i < pavail_ents; i++) - free_bootmem(pavail[i].phys_addr, pavail[i].reg_size); + for (i = 0; i < lmb.memory.cnt; i++) + free_bootmem(lmb.memory.region[i].base, + lmb_size_bytes(&lmb.memory, i)); -#ifdef CONFIG_BLK_DEV_INITRD - if (initrd_start) { - size = initrd_end - initrd_start; - - /* Reserve the initrd image area. */ - reserve_bootmem(initrd_start, size, BOOTMEM_DEFAULT); + for (i = 0; i < lmb.reserved.cnt; i++) + reserve_bootmem(lmb.reserved.region[i].base, + lmb_size_bytes(&lmb.reserved, i), + BOOTMEM_DEFAULT); - initrd_start += PAGE_OFFSET; - initrd_end += PAGE_OFFSET; - } -#endif - /* Reserve the kernel text/data/bss. */ - reserve_bootmem(kern_base, kern_size, BOOTMEM_DEFAULT); *pages_avail -= PAGE_ALIGN(kern_size) >> PAGE_SHIFT; - /* Add back in the initmem pages. */ - size = ((unsigned long)(__init_end) & PAGE_MASK) - - PAGE_ALIGN((unsigned long)__init_begin); - *pages_avail += size >> PAGE_SHIFT; + for (i = 0; i < lmb.memory.cnt; ++i) { + unsigned long start_pfn, end_pfn, pages; - /* Reserve the bootmem map. We do not account for it - * in pages_avail because we will release that memory - * in free_all_bootmem. - */ - size = bootmap_size; - reserve_bootmem((bootmap_pfn << PAGE_SHIFT), size, BOOTMEM_DEFAULT); - - for (i = 0; i < pavail_ents; i++) { - unsigned long start_pfn, end_pfn; + pages = lmb_size_pages(&lmb.memory, i); + start_pfn = lmb.memory.region[i].base >> PAGE_SHIFT; + end_pfn = start_pfn + pages; - start_pfn = pavail[i].phys_addr >> PAGE_SHIFT; - end_pfn = (start_pfn + (pavail[i].reg_size >> PAGE_SHIFT)); memory_present(0, start_pfn, end_pfn); } -- cgit v1.2.3-18-g5258 From b97094560b991af5c62391014e72bfa4c3a3701f Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 13 Feb 2008 19:20:45 -0800 Subject: [SPARC64]: Call real_setup_per_cpu_areas() earlier and use lmb_alloc(). We have to do it like this before we can move the PROM and MDESC device tree code over to using lmb_alloc(). Signed-off-by: David S. Miller --- arch/sparc64/kernel/smp.c | 11 ++++++++--- arch/sparc64/mm/init.c | 8 ++++++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index 59f020d69d4..524b8892094 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include @@ -1431,7 +1431,7 @@ EXPORT_SYMBOL(__per_cpu_shift); void __init real_setup_per_cpu_areas(void) { - unsigned long goal, size, i; + unsigned long paddr, goal, size, i; char *ptr; /* Copy section for each CPU (we discard the original) */ @@ -1441,8 +1441,13 @@ void __init real_setup_per_cpu_areas(void) for (size = PAGE_SIZE; size < goal; size <<= 1UL) __per_cpu_shift++; - ptr = alloc_bootmem_pages(size * NR_CPUS); + paddr = lmb_alloc(size * NR_CPUS, PAGE_SIZE); + if (!paddr) { + prom_printf("Cannot allocate per-cpu memory.\n"); + prom_halt(); + } + ptr = __va(paddr); __per_cpu_base = ptr - __per_cpu_start; for (i = 0; i < NR_CPUS; i++, ptr += size) diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 90e644a0e93..658ec462ed4 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -1208,6 +1208,12 @@ void __init paging_init(void) if (tlb_type == hypervisor) sun4v_ktsb_register(); + /* We must setup the per-cpu areas before we pull in the + * PROM and the MDESC. The code there fills in cpu and + * other information into per-cpu data structures. + */ + real_setup_per_cpu_areas(); + /* Setup bootmem... */ pages_avail = 0; last_valid_pfn = end_pfn = bootmem_init(&pages_avail, phys_base); @@ -1216,8 +1222,6 @@ void __init paging_init(void) kernel_physical_mapping_init(); - real_setup_per_cpu_areas(); - prom_build_devicetree(); if (tlb_type == hypervisor) -- cgit v1.2.3-18-g5258 From ad072004ca35a9918964ca7aee2bf00d79c8657f Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 13 Feb 2008 19:21:51 -0800 Subject: [SPARC64]: Use lmb_alloc() for PROM device tree. Signed-off-by: David S. Miller --- arch/sparc64/kernel/prom.c | 14 +++++++++----- arch/sparc64/mm/init.c | 4 ++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index 68964ddcde1..ed03a18d3b3 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c @@ -19,8 +19,8 @@ #include #include #include -#include #include +#include #include #include @@ -122,16 +122,20 @@ int of_find_in_proplist(const char *list, const char *match, int len) } EXPORT_SYMBOL(of_find_in_proplist); -static unsigned int prom_early_allocated; +static unsigned int prom_early_allocated __initdata; static void * __init prom_early_alloc(unsigned long size) { + unsigned long paddr = lmb_alloc(size, SMP_CACHE_BYTES); void *ret; - ret = __alloc_bootmem(size, SMP_CACHE_BYTES, 0UL); - if (ret != NULL) - memset(ret, 0, size); + if (!paddr) { + prom_printf("prom_early_alloc(%lu) failed\n"); + prom_halt(); + } + ret = __va(paddr); + memset(ret, 0, size); prom_early_allocated += size; return ret; diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 658ec462ed4..0abefc8ca40 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -1214,6 +1214,8 @@ void __init paging_init(void) */ real_setup_per_cpu_areas(); + prom_build_devicetree(); + /* Setup bootmem... */ pages_avail = 0; last_valid_pfn = end_pfn = bootmem_init(&pages_avail, phys_base); @@ -1222,8 +1224,6 @@ void __init paging_init(void) kernel_physical_mapping_init(); - prom_build_devicetree(); - if (tlb_type == hypervisor) sun4v_mdesc_init(); -- cgit v1.2.3-18-g5258 From 4a28333984be123d9c063df23175c48749c4b4a0 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 13 Feb 2008 19:22:23 -0800 Subject: [SPARC64]: Initialize MDESC earlier and use lmb_alloc() Signed-off-by: David S. Miller --- arch/sparc64/kernel/mdesc.c | 28 ++++++++++++++++------------ arch/sparc64/mm/init.c | 6 +++--- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/arch/sparc64/kernel/mdesc.c b/arch/sparc64/kernel/mdesc.c index 91008358956..dde52bcf5c6 100644 --- a/arch/sparc64/kernel/mdesc.c +++ b/arch/sparc64/kernel/mdesc.c @@ -1,10 +1,10 @@ /* mdesc.c: Sun4V machine description handling. * - * Copyright (C) 2007 David S. Miller + * Copyright (C) 2007, 2008 David S. Miller */ #include #include -#include +#include #include #include #include @@ -84,24 +84,28 @@ static void mdesc_handle_init(struct mdesc_handle *hp, hp->handle_size = handle_size; } -static struct mdesc_handle * __init mdesc_bootmem_alloc(unsigned int mdesc_size) +static struct mdesc_handle * __init mdesc_lmb_alloc(unsigned int mdesc_size) { - struct mdesc_handle *hp; unsigned int handle_size, alloc_size; + struct mdesc_handle *hp; + unsigned long paddr; handle_size = (sizeof(struct mdesc_handle) - sizeof(struct mdesc_hdr) + mdesc_size); alloc_size = PAGE_ALIGN(handle_size); - hp = __alloc_bootmem(alloc_size, PAGE_SIZE, 0UL); - if (hp) - mdesc_handle_init(hp, handle_size, hp); + paddr = lmb_alloc(alloc_size, PAGE_SIZE); + hp = NULL; + if (paddr) { + hp = __va(paddr); + mdesc_handle_init(hp, handle_size, hp); + } return hp; } -static void mdesc_bootmem_free(struct mdesc_handle *hp) +static void mdesc_lmb_free(struct mdesc_handle *hp) { unsigned int alloc_size, handle_size = hp->handle_size; unsigned long start, end; @@ -124,9 +128,9 @@ static void mdesc_bootmem_free(struct mdesc_handle *hp) } } -static struct mdesc_mem_ops bootmem_mdesc_ops = { - .alloc = mdesc_bootmem_alloc, - .free = mdesc_bootmem_free, +static struct mdesc_mem_ops lmb_mdesc_ops = { + .alloc = mdesc_lmb_alloc, + .free = mdesc_lmb_free, }; static struct mdesc_handle *mdesc_kmalloc(unsigned int mdesc_size) @@ -888,7 +892,7 @@ void __init sun4v_mdesc_init(void) printk("MDESC: Size is %lu bytes.\n", len); - hp = mdesc_alloc(len, &bootmem_mdesc_ops); + hp = mdesc_alloc(len, &lmb_mdesc_ops); if (hp == NULL) { prom_printf("MDESC: alloc of %lu bytes failed.\n", len); prom_halt(); diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 0abefc8ca40..8e0e8678712 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -1216,6 +1216,9 @@ void __init paging_init(void) prom_build_devicetree(); + if (tlb_type == hypervisor) + sun4v_mdesc_init(); + /* Setup bootmem... */ pages_avail = 0; last_valid_pfn = end_pfn = bootmem_init(&pages_avail, phys_base); @@ -1224,9 +1227,6 @@ void __init paging_init(void) kernel_physical_mapping_init(); - if (tlb_type == hypervisor) - sun4v_mdesc_init(); - { unsigned long zones_size[MAX_NR_ZONES]; unsigned long zholes_size[MAX_NR_ZONES]; -- cgit v1.2.3-18-g5258 From 86cfc751cb4d5da20904ae26c67fb6fd2a68a9c4 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 13 Feb 2008 22:01:57 -0800 Subject: [SPARC64]: Decrease SECTION_SIZE_BITS to 30. We'll need this to handle NUMA properly on some systems. Signed-off-by: David S. Miller --- include/asm-sparc64/sparsemem.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asm-sparc64/sparsemem.h b/include/asm-sparc64/sparsemem.h index 77bcd2bfa53..b99d4e4b6d2 100644 --- a/include/asm-sparc64/sparsemem.h +++ b/include/asm-sparc64/sparsemem.h @@ -3,7 +3,7 @@ #ifdef __KERNEL__ -#define SECTION_SIZE_BITS 31 +#define SECTION_SIZE_BITS 30 #define MAX_PHYSADDR_BITS 42 #define MAX_PHYSMEM_BITS 42 -- cgit v1.2.3-18-g5258 From 30957a86c2442fb6d73aaa9a3153f023fe0a682b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 13 Feb 2008 22:07:34 -0800 Subject: [SPARC64]: Remove unused asm-sparc64/numnodes.h This is handled with config options now. Signed-off-by: David S. Miller --- include/asm-sparc64/numnodes.h | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 include/asm-sparc64/numnodes.h diff --git a/include/asm-sparc64/numnodes.h b/include/asm-sparc64/numnodes.h deleted file mode 100644 index 017e7e74f5e..00000000000 --- a/include/asm-sparc64/numnodes.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _SPARC64_NUMNODES_H -#define _SPARC64_NUMNODES_H - -#define NODES_SHIFT 0 - -#endif /* !(_SPARC64_NUMNODES_H) */ -- cgit v1.2.3-18-g5258 From ce3b1d47a8605905b666649ea309b6471a75b4ed Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 19 Mar 2008 03:54:09 -0700 Subject: [SPARC64]: Once we have the boot cmdline, call parse_early_param() Signed-off-by: David S. Miller --- arch/sparc64/kernel/setup.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c index 6acb4c51cfe..46bcf41097a 100644 --- a/arch/sparc64/kernel/setup.c +++ b/arch/sparc64/kernel/setup.c @@ -281,6 +281,7 @@ void __init setup_arch(char **cmdline_p) /* Initialize PROM console and command line. */ *cmdline_p = prom_getbootargs(); strcpy(boot_command_line, *cmdline_p); + parse_early_param(); boot_flags_init(*cmdline_p); register_console(&prom_early_console); -- cgit v1.2.3-18-g5258 From 0c49a573ea93f777fd27f26b7853e7bf5a20e1a3 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 13 Feb 2008 22:15:46 -0800 Subject: [SPARC64]: Kill pci_iommu_table_init() declaration. No longer exists. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci_impl.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h index 4a50da13ce4..f79c923fdd8 100644 --- a/arch/sparc64/kernel/pci_impl.h +++ b/arch/sparc64/kernel/pci_impl.h @@ -161,8 +161,6 @@ extern struct pci_pbm_info *pci_pbm_root; extern int pci_num_pbms; /* PCI bus scanning and fixup support. */ -extern void pci_iommu_table_init(struct iommu *iommu, int tsbsize, - u32 dma_offset, u32 dma_addr_mask); extern void pci_get_pbm_props(struct pci_pbm_info *pbm); extern struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm); extern void pci_determine_mem_io_space(struct pci_pbm_info *pbm); -- cgit v1.2.3-18-g5258 From c1b1a5f1f1b2612b69b67381b223bce9f8ec4da5 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 19 Mar 2008 04:52:48 -0700 Subject: [SPARC64]: NUMA device infrastructure. Record and propagate NUMA information for devices. Signed-off-by: David S. Miller --- arch/sparc64/kernel/ebus.c | 1 + arch/sparc64/kernel/iommu.c | 33 +++++++++++++++++++++------------ arch/sparc64/kernel/isa.c | 1 + arch/sparc64/kernel/of_device.c | 12 +++++++++++- arch/sparc64/kernel/pci.c | 12 ++++++++++++ arch/sparc64/kernel/pci_fire.c | 5 ++++- arch/sparc64/kernel/pci_impl.h | 2 ++ arch/sparc64/kernel/pci_msi.c | 8 +++++++- arch/sparc64/kernel/pci_psycho.c | 5 ++++- arch/sparc64/kernel/pci_sabre.c | 4 +++- arch/sparc64/kernel/pci_schizo.c | 5 ++++- arch/sparc64/kernel/pci_sun4v.c | 13 ++++++++++--- arch/sparc64/kernel/sbus.c | 3 ++- include/asm-sparc/device.h | 2 ++ include/asm-sparc/prom.h | 5 +++++ include/asm-sparc64/iommu.h | 3 ++- 16 files changed, 91 insertions(+), 23 deletions(-) diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c index 04ab81cb4f4..bc263227484 100644 --- a/arch/sparc64/kernel/ebus.c +++ b/arch/sparc64/kernel/ebus.c @@ -396,6 +396,7 @@ static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_de sd->op = &dev->ofdev; sd->iommu = dev->bus->ofdev.dev.parent->archdata.iommu; sd->stc = dev->bus->ofdev.dev.parent->archdata.stc; + sd->numa_node = dev->bus->ofdev.dev.parent->archdata.numa_node; dev->ofdev.node = dp; dev->ofdev.dev.parent = &dev->bus->ofdev.dev; diff --git a/arch/sparc64/kernel/iommu.c b/arch/sparc64/kernel/iommu.c index 756fa24eeef..2a37a6ca2a1 100644 --- a/arch/sparc64/kernel/iommu.c +++ b/arch/sparc64/kernel/iommu.c @@ -173,9 +173,11 @@ void iommu_range_free(struct iommu *iommu, dma_addr_t dma_addr, unsigned long np } int iommu_table_init(struct iommu *iommu, int tsbsize, - u32 dma_offset, u32 dma_addr_mask) + u32 dma_offset, u32 dma_addr_mask, + int numa_node) { - unsigned long i, tsbbase, order, sz, num_tsb_entries; + unsigned long i, order, sz, num_tsb_entries; + struct page *page; num_tsb_entries = tsbsize / sizeof(iopte_t); @@ -188,11 +190,12 @@ int iommu_table_init(struct iommu *iommu, int tsbsize, /* Allocate and initialize the free area map. */ sz = num_tsb_entries / 8; sz = (sz + 7UL) & ~7UL; - iommu->arena.map = kzalloc(sz, GFP_KERNEL); + iommu->arena.map = kmalloc_node(sz, GFP_KERNEL, numa_node); if (!iommu->arena.map) { printk(KERN_ERR "IOMMU: Error, kmalloc(arena.map) failed.\n"); return -ENOMEM; } + memset(iommu->arena.map, 0, sz); iommu->arena.limit = num_tsb_entries; if (tlb_type != hypervisor) @@ -201,21 +204,23 @@ int iommu_table_init(struct iommu *iommu, int tsbsize, /* Allocate and initialize the dummy page which we * set inactive IO PTEs to point to. */ - iommu->dummy_page = get_zeroed_page(GFP_KERNEL); - if (!iommu->dummy_page) { + page = alloc_pages_node(numa_node, GFP_KERNEL, 0); + if (!page) { printk(KERN_ERR "IOMMU: Error, gfp(dummy_page) failed.\n"); goto out_free_map; } + iommu->dummy_page = (unsigned long) page_address(page); + memset((void *)iommu->dummy_page, 0, PAGE_SIZE); iommu->dummy_page_pa = (unsigned long) __pa(iommu->dummy_page); /* Now allocate and setup the IOMMU page table itself. */ order = get_order(tsbsize); - tsbbase = __get_free_pages(GFP_KERNEL, order); - if (!tsbbase) { + page = alloc_pages_node(numa_node, GFP_KERNEL, order); + if (!page) { printk(KERN_ERR "IOMMU: Error, gfp(tsb) failed.\n"); goto out_free_dummy_page; } - iommu->page_table = (iopte_t *)tsbbase; + iommu->page_table = (iopte_t *)page_address(page); for (i = 0; i < num_tsb_entries; i++) iopte_make_dummy(iommu, &iommu->page_table[i]); @@ -276,20 +281,24 @@ static inline void iommu_free_ctx(struct iommu *iommu, int ctx) static void *dma_4u_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addrp, gfp_t gfp) { + unsigned long flags, order, first_page; struct iommu *iommu; + struct page *page; + int npages, nid; iopte_t *iopte; - unsigned long flags, order, first_page; void *ret; - int npages; size = IO_PAGE_ALIGN(size); order = get_order(size); if (order >= 10) return NULL; - first_page = __get_free_pages(gfp, order); - if (first_page == 0UL) + nid = dev->archdata.numa_node; + page = alloc_pages_node(nid, gfp, order); + if (unlikely(!page)) return NULL; + + first_page = (unsigned long) page_address(page); memset((char *)first_page, 0, PAGE_SIZE << order); iommu = dev->archdata.iommu; diff --git a/arch/sparc64/kernel/isa.c b/arch/sparc64/kernel/isa.c index b5f7b354084..a2af5ed784c 100644 --- a/arch/sparc64/kernel/isa.c +++ b/arch/sparc64/kernel/isa.c @@ -92,6 +92,7 @@ static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br) sd->op = &isa_dev->ofdev; sd->iommu = isa_br->ofdev.dev.parent->archdata.iommu; sd->stc = isa_br->ofdev.dev.parent->archdata.stc; + sd->numa_node = isa_br->ofdev.dev.parent->archdata.numa_node; isa_dev->ofdev.node = dp; isa_dev->ofdev.dev.parent = &isa_br->ofdev.dev; diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c index 0fd9db95b89..9e58e8cba1c 100644 --- a/arch/sparc64/kernel/of_device.c +++ b/arch/sparc64/kernel/of_device.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -660,6 +661,7 @@ static unsigned int __init build_one_device_irq(struct of_device *op, struct device_node *dp = op->node; struct device_node *pp, *ip; unsigned int orig_irq = irq; + int nid; if (irq == 0xffffffff) return irq; @@ -672,7 +674,7 @@ static unsigned int __init build_one_device_irq(struct of_device *op, printk("%s: direct translate %x --> %x\n", dp->full_name, orig_irq, irq); - return irq; + goto out; } /* Something more complicated. Walk up to the root, applying @@ -744,6 +746,14 @@ static unsigned int __init build_one_device_irq(struct of_device *op, printk("%s: Apply IRQ trans [%s] %x --> %x\n", op->node->full_name, ip->full_name, orig_irq, irq); +out: + nid = of_node_to_nid(dp); + if (nid != -1) { + cpumask_t numa_mask = node_to_cpumask(nid); + + irq_set_affinity(irq, numa_mask); + } + return irq; } diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index 545356b00e2..49f91276651 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -369,10 +369,12 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, sd->host_controller = pbm; sd->prom_node = node; sd->op = of_find_device_by_node(node); + sd->numa_node = pbm->numa_node; sd = &sd->op->dev.archdata; sd->iommu = pbm->iommu; sd->stc = &pbm->stc; + sd->numa_node = pbm->numa_node; type = of_get_property(node, "device_type", NULL); if (type == NULL) @@ -1159,6 +1161,16 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, return 0; } +#ifdef CONFIG_NUMA +int pcibus_to_node(struct pci_bus *pbus) +{ + struct pci_pbm_info *pbm = pbus->sysdata; + + return pbm->numa_node; +} +EXPORT_SYMBOL(pcibus_to_node); +#endif + /* Return the domain nuber for this pci bus */ int pci_domain_nr(struct pci_bus *pbus) diff --git a/arch/sparc64/kernel/pci_fire.c b/arch/sparc64/kernel/pci_fire.c index 7571ed56314..d23bb6f53cd 100644 --- a/arch/sparc64/kernel/pci_fire.c +++ b/arch/sparc64/kernel/pci_fire.c @@ -71,7 +71,8 @@ static int pci_fire_pbm_iommu_init(struct pci_pbm_info *pbm) */ fire_write(iommu->iommu_flushinv, ~(u64)0); - err = iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask); + err = iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask, + pbm->numa_node); if (err) return err; @@ -449,6 +450,8 @@ static int __init pci_fire_pbm_init(struct pci_controller_info *p, pbm->next = pci_pbm_root; pci_pbm_root = pbm; + pbm->numa_node = -1; + pbm->scan_bus = pci_fire_scan_bus; pbm->pci_ops = &sun4u_pci_ops; pbm->config_space_reg_bits = 12; diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h index f79c923fdd8..218bac4ff79 100644 --- a/arch/sparc64/kernel/pci_impl.h +++ b/arch/sparc64/kernel/pci_impl.h @@ -148,6 +148,8 @@ struct pci_pbm_info { struct pci_bus *pci_bus; void (*scan_bus)(struct pci_pbm_info *); struct pci_ops *pci_ops; + + int numa_node; }; struct pci_controller_info { diff --git a/arch/sparc64/kernel/pci_msi.c b/arch/sparc64/kernel/pci_msi.c index d6d64b44af6..db5e8fd8f67 100644 --- a/arch/sparc64/kernel/pci_msi.c +++ b/arch/sparc64/kernel/pci_msi.c @@ -279,11 +279,17 @@ static int bringup_one_msi_queue(struct pci_pbm_info *pbm, unsigned long devino) { int irq = ops->msiq_build_irq(pbm, msiqid, devino); - int err; + int err, nid; if (irq < 0) return irq; + nid = pbm->numa_node; + if (nid != -1) { + cpumask_t numa_mask = node_to_cpumask(nid); + + irq_set_affinity(irq, numa_mask); + } err = request_irq(irq, sparc64_msiq_interrupt, 0, "MSIQ", &pbm->msiq_irq_cookies[msiqid - pbm->msiq_first]); diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index 0bad96e5d18..994dbe0603d 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -848,7 +848,8 @@ static int psycho_iommu_init(struct pci_pbm_info *pbm) /* Leave diag mode enabled for full-flushing done * in pci_iommu.c */ - err = iommu_table_init(iommu, IO_TSB_SIZE, 0xc0000000, 0xffffffff); + err = iommu_table_init(iommu, IO_TSB_SIZE, 0xc0000000, 0xffffffff, + pbm->numa_node); if (err) return err; @@ -979,6 +980,8 @@ static void __init psycho_pbm_init(struct pci_controller_info *p, pbm->next = pci_pbm_root; pci_pbm_root = pbm; + pbm->numa_node = -1; + pbm->scan_bus = psycho_scan_bus; pbm->pci_ops = &sun4u_pci_ops; pbm->config_space_reg_bits = 8; diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index 1c5f5fa2339..4c34195baf3 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -704,7 +704,7 @@ static int sabre_iommu_init(struct pci_pbm_info *pbm, * in pci_iommu.c */ err = iommu_table_init(iommu, tsbsize * 1024 * 8, - dvma_offset, dma_mask); + dvma_offset, dma_mask, pbm->numa_node); if (err) return err; @@ -737,6 +737,8 @@ static void __init sabre_pbm_init(struct pci_controller_info *p, pbm->name = dp->full_name; printk("%s: SABRE PCI Bus Module\n", pbm->name); + pbm->numa_node = -1; + pbm->scan_bus = sabre_scan_bus; pbm->pci_ops = &sun4u_pci_ops; pbm->config_space_reg_bits = 8; diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index e3060936232..615edd9c8e2 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -1220,7 +1220,8 @@ static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm) /* Leave diag mode enabled for full-flushing done * in pci_iommu.c */ - err = iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask); + err = iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask, + pbm->numa_node); if (err) return err; @@ -1379,6 +1380,8 @@ static int __init schizo_pbm_init(struct pci_controller_info *p, pbm->next = pci_pbm_root; pci_pbm_root = pbm; + pbm->numa_node = -1; + pbm->scan_bus = schizo_scan_bus; pbm->pci_ops = &sun4u_pci_ops; pbm->config_space_reg_bits = 8; diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index 01839706bd5..e2bb9790039 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -127,10 +127,12 @@ static inline long iommu_batch_end(void) static void *dma_4v_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addrp, gfp_t gfp) { - struct iommu *iommu; unsigned long flags, order, first_page, npages, n; + struct iommu *iommu; + struct page *page; void *ret; long entry; + int nid; size = IO_PAGE_ALIGN(size); order = get_order(size); @@ -139,10 +141,12 @@ static void *dma_4v_alloc_coherent(struct device *dev, size_t size, npages = size >> IO_PAGE_SHIFT; - first_page = __get_free_pages(gfp, order); - if (unlikely(first_page == 0UL)) + nid = dev->archdata.numa_node; + page = alloc_pages_node(nid, gfp, order); + if (unlikely(!page)) return NULL; + first_page = (unsigned long) page_address(page); memset((char *)first_page, 0, PAGE_SIZE << order); iommu = dev->archdata.iommu; @@ -899,6 +903,8 @@ static void __init pci_sun4v_pbm_init(struct pci_controller_info *p, pbm->next = pci_pbm_root; pci_pbm_root = pbm; + pbm->numa_node = of_node_to_nid(dp); + pbm->scan_bus = pci_sun4v_scan_bus; pbm->pci_ops = &sun4v_pci_ops; pbm->config_space_reg_bits = 12; @@ -913,6 +919,7 @@ static void __init pci_sun4v_pbm_init(struct pci_controller_info *p, pbm->name = dp->full_name; printk("%s: SUN4V PCI Bus Module\n", pbm->name); + printk("%s: On NUMA node %d\n", pbm->name, pbm->numa_node); pci_determine_mem_io_space(pbm); diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c index d1fb13ba02b..fa2827c4a3a 100644 --- a/arch/sparc64/kernel/sbus.c +++ b/arch/sparc64/kernel/sbus.c @@ -544,6 +544,7 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus) sbus->ofdev.dev.archdata.iommu = iommu; sbus->ofdev.dev.archdata.stc = strbuf; + sbus->ofdev.dev.archdata.numa_node = -1; reg_base = regs + SYSIO_IOMMUREG_BASE; iommu->iommu_control = reg_base + IOMMU_CONTROL; @@ -575,7 +576,7 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus) sbus->portid, regs); /* Setup for TSB_SIZE=7, TBW_SIZE=0, MMU_DE=1, MMU_EN=1 */ - if (iommu_table_init(iommu, IO_TSB_SIZE, MAP_BASE, 0xffffffff)) + if (iommu_table_init(iommu, IO_TSB_SIZE, MAP_BASE, 0xffffffff, -1)) goto fatal_memory_error; control = upa_readq(iommu->iommu_control); diff --git a/include/asm-sparc/device.h b/include/asm-sparc/device.h index 680e51d8737..19790eb99cc 100644 --- a/include/asm-sparc/device.h +++ b/include/asm-sparc/device.h @@ -16,6 +16,8 @@ struct dev_archdata { struct device_node *prom_node; struct of_device *op; + + int numa_node; }; #endif /* _ASM_SPARC_DEVICE_H */ diff --git a/include/asm-sparc/prom.h b/include/asm-sparc/prom.h index df5dc442248..fd55522481c 100644 --- a/include/asm-sparc/prom.h +++ b/include/asm-sparc/prom.h @@ -77,6 +77,11 @@ extern int of_getintprop_default(struct device_node *np, const char *name, int def); extern int of_find_in_proplist(const char *list, const char *match, int len); +#ifdef CONFIG_NUMA +extern int of_node_to_nid(struct device_node *dp); +#else +#define of_node_to_nid(dp) (-1) +#endif extern void prom_build_devicetree(void); diff --git a/include/asm-sparc64/iommu.h b/include/asm-sparc64/iommu.h index 46325ddee23..d7b9afcba08 100644 --- a/include/asm-sparc64/iommu.h +++ b/include/asm-sparc64/iommu.h @@ -56,6 +56,7 @@ struct strbuf { }; extern int iommu_table_init(struct iommu *iommu, int tsbsize, - u32 dma_offset, u32 dma_addr_mask); + u32 dma_offset, u32 dma_addr_mask, + int numa_node); #endif /* !(_SPARC64_IOMMU_H) */ -- cgit v1.2.3-18-g5258 From 1f261ef53ba06658dfeb5a9c3007d0ad1b85cadf Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 19 Mar 2008 04:53:58 -0700 Subject: [SPARC64]: Allocate TSB node-local. Signed-off-by: David S. Miller --- arch/sparc64/mm/tsb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/sparc64/mm/tsb.c b/arch/sparc64/mm/tsb.c index a3e6e4b635b..fe70c8a557b 100644 --- a/arch/sparc64/mm/tsb.c +++ b/arch/sparc64/mm/tsb.c @@ -321,7 +321,8 @@ retry_tsb_alloc: if (new_size > (PAGE_SIZE * 2)) gfp_flags = __GFP_NOWARN | __GFP_NORETRY; - new_tsb = kmem_cache_alloc(tsb_caches[new_cache_index], gfp_flags); + new_tsb = kmem_cache_alloc_node(tsb_caches[new_cache_index], + gfp_flags, numa_node_id()); if (unlikely(!new_tsb)) { /* Not being able to fork due to a high-order TSB * allocation failure is very bad behavior. Just back -- cgit v1.2.3-18-g5258 From 919ee677b656c52c5f86d3d916786891220d5452 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 23 Apr 2008 05:40:25 -0700 Subject: [SPARC64]: Add NUMA support. Currently there is only code to parse NUMA attributes on sun4v/niagara systems, but later on we will add such parsing for older systems. Signed-off-by: David S. Miller --- Makefile | 2 +- arch/sparc64/Kconfig | 20 ++ arch/sparc64/defconfig | 99 +++-- arch/sparc64/kernel/sysfs.c | 12 + arch/sparc64/mm/init.c | 796 +++++++++++++++++++++++++++++++++++------ include/asm-sparc64/mmzone.h | 17 + include/asm-sparc64/topology.h | 73 +++- 7 files changed, 881 insertions(+), 138 deletions(-) create mode 100644 include/asm-sparc64/mmzone.h diff --git a/Makefile b/Makefile index 3dbc826bb8e..d35c5246fce 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 25 -EXTRAVERSION = +EXTRAVERSION = -numa NAME = Funky Weasel is Jiggy wit it # *DOCUMENTATION* diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index df3eacb5ca1..8acc5cc3862 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig @@ -250,6 +250,26 @@ endchoice endmenu +config NUMA + bool "NUMA support" + +config NODES_SHIFT + int + default "4" + depends on NEED_MULTIPLE_NODES + +# Some NUMA nodes have memory ranges that span +# other nodes. Even though a pfn is valid and +# between a node's start and end pfns, it may not +# reside on that node. See memmap_init_zone() +# for details. +config NODES_SPAN_OTHER_NODES + def_bool y + depends on NEED_MULTIPLE_NODES + +config ARCH_POPULATES_NODE_MAP + def_bool y + config ARCH_SELECT_MEMORY_MODEL def_bool y diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index e1835868ad3..92f79680f70 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.25 -# Sun Apr 20 01:33:21 2008 +# Linux kernel version: 2.6.25-numa +# Wed Apr 23 04:49:08 2008 # CONFIG_SPARC=y CONFIG_SPARC64=y @@ -152,6 +152,8 @@ CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_HUGETLB_PAGE_SIZE_4MB=y # CONFIG_HUGETLB_PAGE_SIZE_512K is not set # CONFIG_HUGETLB_PAGE_SIZE_64K is not set +# CONFIG_NUMA is not set +CONFIG_ARCH_POPULATES_NODE_MAP=y CONFIG_ARCH_SELECT_MEMORY_MODEL=y CONFIG_ARCH_SPARSEMEM_ENABLE=y CONFIG_ARCH_SPARSEMEM_DEFAULT=y @@ -787,7 +789,6 @@ CONFIG_I2C_ALGOBIT=y # CONFIG_SENSORS_PCF8574 is not set # CONFIG_PCF8575 is not set # CONFIG_SENSORS_PCF8591 is not set -# CONFIG_TPS65010 is not set # CONFIG_SENSORS_MAX6875 is not set # CONFIG_SENSORS_TSL2550 is not set # CONFIG_I2C_DEBUG_CORE is not set @@ -869,6 +870,7 @@ CONFIG_SSB_POSSIBLE=y # Multifunction device drivers # # CONFIG_MFD_SM501 is not set +# CONFIG_HTC_PASIC3 is not set # # Multimedia devices @@ -1219,10 +1221,6 @@ CONFIG_USB_STORAGE=m # CONFIG_NEW_LEDS is not set # CONFIG_INFINIBAND is not set # CONFIG_RTC_CLASS is not set - -# -# Userspace I/O -# # CONFIG_UIO is not set # @@ -1399,6 +1397,7 @@ CONFIG_SCHEDSTATS=y CONFIG_DEBUG_BUGVERBOSE=y # CONFIG_DEBUG_INFO is not set # CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set # CONFIG_DEBUG_LIST is not set # CONFIG_DEBUG_SG is not set # CONFIG_BOOT_PRINTK_DELAY is not set @@ -1425,53 +1424,82 @@ CONFIG_ASYNC_CORE=m CONFIG_ASYNC_MEMCPY=m CONFIG_ASYNC_XOR=m CONFIG_CRYPTO=y + +# +# Crypto core or helper +# CONFIG_CRYPTO_ALGAPI=y CONFIG_CRYPTO_AEAD=y CONFIG_CRYPTO_BLKCIPHER=y -# CONFIG_CRYPTO_SEQIV is not set CONFIG_CRYPTO_HASH=y CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_GF128MUL=m +CONFIG_CRYPTO_NULL=m +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_AUTHENC=y +CONFIG_CRYPTO_TEST=m + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_LRW=m +CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_XTS=m + +# +# Hash modes +# CONFIG_CRYPTO_HMAC=y CONFIG_CRYPTO_XCBC=y -CONFIG_CRYPTO_NULL=m + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=m CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_SHA1=y CONFIG_CRYPTO_SHA256=m CONFIG_CRYPTO_SHA512=m -CONFIG_CRYPTO_WP512=m CONFIG_CRYPTO_TGR192=m -CONFIG_CRYPTO_GF128MUL=m -CONFIG_CRYPTO_ECB=m -CONFIG_CRYPTO_CBC=y -CONFIG_CRYPTO_PCBC=m -CONFIG_CRYPTO_LRW=m -CONFIG_CRYPTO_XTS=m -# CONFIG_CRYPTO_CTR is not set -# CONFIG_CRYPTO_GCM is not set -# CONFIG_CRYPTO_CCM is not set -# CONFIG_CRYPTO_CRYPTD is not set -CONFIG_CRYPTO_DES=y -CONFIG_CRYPTO_FCRYPT=m -CONFIG_CRYPTO_BLOWFISH=m -CONFIG_CRYPTO_TWOFISH=m -CONFIG_CRYPTO_TWOFISH_COMMON=m -CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_WP512=m + +# +# Ciphers +# CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_CAMELLIA=m CONFIG_CRYPTO_CAST5=m CONFIG_CRYPTO_CAST6=m -CONFIG_CRYPTO_TEA=m -CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_DES=y +CONFIG_CRYPTO_FCRYPT=m CONFIG_CRYPTO_KHAZAD=m -CONFIG_CRYPTO_ANUBIS=m -CONFIG_CRYPTO_SEED=m # CONFIG_CRYPTO_SALSA20 is not set +CONFIG_CRYPTO_SEED=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_TEA=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_TWOFISH_COMMON=m + +# +# Compression +# CONFIG_CRYPTO_DEFLATE=y -CONFIG_CRYPTO_MICHAEL_MIC=m -CONFIG_CRYPTO_CRC32C=m -CONFIG_CRYPTO_CAMELLIA=m -CONFIG_CRYPTO_TEST=m -CONFIG_CRYPTO_AUTHENC=y # CONFIG_CRYPTO_LZO is not set CONFIG_CRYPTO_HW=y # CONFIG_CRYPTO_DEV_HIFN_795X is not set @@ -1492,3 +1520,4 @@ CONFIG_PLIST=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y CONFIG_HAS_DMA=y +CONFIG_HAVE_LMB=y diff --git a/arch/sparc64/kernel/sysfs.c b/arch/sparc64/kernel/sysfs.c index 52816c7be0b..e885034a6b7 100644 --- a/arch/sparc64/kernel/sysfs.c +++ b/arch/sparc64/kernel/sysfs.c @@ -273,10 +273,22 @@ static void __init check_mmu_stats(void) mmu_stats_supported = 1; } +static void register_nodes(void) +{ +#ifdef CONFIG_NUMA + int i; + + for (i = 0; i < MAX_NUMNODES; i++) + register_one_node(i); +#endif +} + static int __init topology_init(void) { int cpu; + register_nodes(); + check_mmu_stats(); register_cpu_notifier(&sysfs_cpu_nb); diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 8e0e8678712..177d8aaeec4 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -73,9 +74,7 @@ extern struct tsb swapper_4m_tsb[KERNEL_TSB4M_NENTRIES]; #define MAX_BANKS 32 static struct linux_prom64_registers pavail[MAX_BANKS] __initdata; -static struct linux_prom64_registers pavail_rescan[MAX_BANKS] __initdata; static int pavail_ents __initdata; -static int pavail_rescan_ents __initdata; static int cmp_p64(const void *a, const void *b) { @@ -716,19 +715,28 @@ out: smp_new_mmu_context_version(); } -/* Find a free area for the bootmem map, avoiding the kernel image - * and the initial ramdisk. - */ -static unsigned long __init choose_bootmap_pfn(unsigned long start_pfn, - unsigned long end_pfn) +static int numa_enabled = 1; +static int numa_debug; + +static int __init early_numa(char *p) { - unsigned long bootmap_size; + if (!p) + return 0; + + if (strstr(p, "off")) + numa_enabled = 0; - bootmap_size = bootmem_bootmap_pages(end_pfn - start_pfn); - bootmap_size <<= PAGE_SHIFT; + if (strstr(p, "debug")) + numa_debug = 1; - return lmb_alloc(bootmap_size, PAGE_SIZE) >> PAGE_SHIFT; + return 0; } +early_param("numa", early_numa); + +#define numadbg(f, a...) \ +do { if (numa_debug) \ + printk(KERN_INFO f, ## a); \ +} while (0) static void __init find_ramdisk(unsigned long phys_base) { @@ -755,6 +763,9 @@ static void __init find_ramdisk(unsigned long phys_base) ramdisk_image -= KERNBASE; ramdisk_image += phys_base; + numadbg("Found ramdisk at physical address 0x%lx, size %u\n", + ramdisk_image, sparc_ramdisk_size); + initrd_start = ramdisk_image; initrd_end = ramdisk_image + sparc_ramdisk_size; @@ -763,60 +774,625 @@ static void __init find_ramdisk(unsigned long phys_base) #endif } -/* About pages_avail, this is the value we will use to calculate - * the zholes_size[] argument given to free_area_init_node(). The - * page allocator uses this to calculate nr_kernel_pages, - * nr_all_pages and zone->present_pages. On NUMA it is used - * to calculate zone->min_unmapped_pages and zone->min_slab_pages. - * - * So this number should really be set to what the page allocator - * actually ends up with. This means: - * 1) It should include bootmem map pages, we'll release those. - * 2) It should not include the kernel image, except for the - * __init sections which we will also release. - * 3) It should include the initrd image, since we'll release - * that too. +struct node_mem_mask { + unsigned long mask; + unsigned long val; + unsigned long bootmem_paddr; +}; +static struct node_mem_mask node_masks[MAX_NUMNODES]; +static int num_node_masks; + +int numa_cpu_lookup_table[NR_CPUS]; +cpumask_t numa_cpumask_lookup_table[MAX_NUMNODES]; + +#ifdef CONFIG_NEED_MULTIPLE_NODES +static bootmem_data_t plat_node_bdata[MAX_NUMNODES]; + +struct mdesc_mblock { + u64 base; + u64 size; + u64 offset; /* RA-to-PA */ +}; +static struct mdesc_mblock *mblocks; +static int num_mblocks; + +static unsigned long ra_to_pa(unsigned long addr) +{ + int i; + + for (i = 0; i < num_mblocks; i++) { + struct mdesc_mblock *m = &mblocks[i]; + + if (addr >= m->base && + addr < (m->base + m->size)) { + addr += m->offset; + break; + } + } + return addr; +} + +static int find_node(unsigned long addr) +{ + int i; + + addr = ra_to_pa(addr); + for (i = 0; i < num_node_masks; i++) { + struct node_mem_mask *p = &node_masks[i]; + + if ((addr & p->mask) == p->val) + return i; + } + return -1; +} + +static unsigned long nid_range(unsigned long start, unsigned long end, + int *nid) +{ + *nid = find_node(start); + start += PAGE_SIZE; + while (start < end) { + int n = find_node(start); + + if (n != *nid) + break; + start += PAGE_SIZE; + } + + return start; +} +#else +static unsigned long nid_range(unsigned long start, unsigned long end, + int *nid) +{ + *nid = 0; + return end; +} +#endif + +/* This must be invoked after performing all of the necessary + * add_active_range() calls for 'nid'. We need to be able to get + * correct data from get_pfn_range_for_nid(). */ -static unsigned long __init bootmem_init(unsigned long *pages_avail, - unsigned long phys_base) +static void __init allocate_node_data(int nid) +{ + unsigned long paddr, num_pages, start_pfn, end_pfn; + struct pglist_data *p; + +#ifdef CONFIG_NEED_MULTIPLE_NODES + paddr = lmb_alloc_nid(sizeof(struct pglist_data), + SMP_CACHE_BYTES, nid, nid_range); + if (!paddr) { + prom_printf("Cannot allocate pglist_data for nid[%d]\n", nid); + prom_halt(); + } + NODE_DATA(nid) = __va(paddr); + memset(NODE_DATA(nid), 0, sizeof(struct pglist_data)); + + NODE_DATA(nid)->bdata = &plat_node_bdata[nid]; +#endif + + p = NODE_DATA(nid); + + get_pfn_range_for_nid(nid, &start_pfn, &end_pfn); + p->node_start_pfn = start_pfn; + p->node_spanned_pages = end_pfn - start_pfn; + + if (p->node_spanned_pages) { + num_pages = bootmem_bootmap_pages(p->node_spanned_pages); + + paddr = lmb_alloc_nid(num_pages << PAGE_SHIFT, PAGE_SIZE, nid, + nid_range); + if (!paddr) { + prom_printf("Cannot allocate bootmap for nid[%d]\n", + nid); + prom_halt(); + } + node_masks[nid].bootmem_paddr = paddr; + } +} + +static void init_node_masks_nonnuma(void) { - unsigned long end_pfn; int i; - *pages_avail = lmb_phys_mem_size() >> PAGE_SHIFT; - end_pfn = lmb_end_of_DRAM() >> PAGE_SHIFT; + numadbg("Initializing tables for non-numa.\n"); - /* Initialize the boot-time allocator. */ - max_pfn = max_low_pfn = end_pfn; - min_low_pfn = (phys_base >> PAGE_SHIFT); + node_masks[0].mask = node_masks[0].val = 0; + num_node_masks = 1; - init_bootmem_node(NODE_DATA(0), - choose_bootmap_pfn(min_low_pfn, end_pfn), - min_low_pfn, end_pfn); + for (i = 0; i < NR_CPUS; i++) + numa_cpu_lookup_table[i] = 0; - /* Now register the available physical memory with the - * allocator. - */ - for (i = 0; i < lmb.memory.cnt; i++) - free_bootmem(lmb.memory.region[i].base, - lmb_size_bytes(&lmb.memory, i)); + numa_cpumask_lookup_table[0] = CPU_MASK_ALL; +} + +#ifdef CONFIG_NEED_MULTIPLE_NODES +struct pglist_data *node_data[MAX_NUMNODES]; + +EXPORT_SYMBOL(numa_cpu_lookup_table); +EXPORT_SYMBOL(numa_cpumask_lookup_table); +EXPORT_SYMBOL(node_data); + +struct mdesc_mlgroup { + u64 node; + u64 latency; + u64 match; + u64 mask; +}; +static struct mdesc_mlgroup *mlgroups; +static int num_mlgroups; + +static int scan_pio_for_cfg_handle(struct mdesc_handle *md, u64 pio, + u32 cfg_handle) +{ + u64 arc; + + mdesc_for_each_arc(arc, md, pio, MDESC_ARC_TYPE_FWD) { + u64 target = mdesc_arc_target(md, arc); + const u64 *val; + + val = mdesc_get_property(md, target, + "cfg-handle", NULL); + if (val && *val == cfg_handle) + return 0; + } + return -ENODEV; +} + +static int scan_arcs_for_cfg_handle(struct mdesc_handle *md, u64 grp, + u32 cfg_handle) +{ + u64 arc, candidate, best_latency = ~(u64)0; + + candidate = MDESC_NODE_NULL; + mdesc_for_each_arc(arc, md, grp, MDESC_ARC_TYPE_FWD) { + u64 target = mdesc_arc_target(md, arc); + const char *name = mdesc_node_name(md, target); + const u64 *val; + + if (strcmp(name, "pio-latency-group")) + continue; + + val = mdesc_get_property(md, target, "latency", NULL); + if (!val) + continue; + + if (*val < best_latency) { + candidate = target; + best_latency = *val; + } + } + + if (candidate == MDESC_NODE_NULL) + return -ENODEV; + + return scan_pio_for_cfg_handle(md, candidate, cfg_handle); +} + +int of_node_to_nid(struct device_node *dp) +{ + const struct linux_prom64_registers *regs; + struct mdesc_handle *md; + u32 cfg_handle; + int count, nid; + u64 grp; + + if (!mlgroups) + return -1; + + regs = of_get_property(dp, "reg", NULL); + if (!regs) + return -1; + + cfg_handle = (regs->phys_addr >> 32UL) & 0x0fffffff; + + md = mdesc_grab(); + + count = 0; + nid = -1; + mdesc_for_each_node_by_name(md, grp, "group") { + if (!scan_arcs_for_cfg_handle(md, grp, cfg_handle)) { + nid = count; + break; + } + count++; + } + + mdesc_release(md); + + return nid; +} + +static void add_node_ranges(void) +{ + int i; + + for (i = 0; i < lmb.memory.cnt; i++) { + unsigned long size = lmb_size_bytes(&lmb.memory, i); + unsigned long start, end; + + start = lmb.memory.region[i].base; + end = start + size; + while (start < end) { + unsigned long this_end; + int nid; + + this_end = nid_range(start, end, &nid); + + numadbg("Adding active range nid[%d] " + "start[%lx] end[%lx]\n", + nid, start, this_end); + + add_active_range(nid, + start >> PAGE_SHIFT, + this_end >> PAGE_SHIFT); + + start = this_end; + } + } +} - for (i = 0; i < lmb.reserved.cnt; i++) - reserve_bootmem(lmb.reserved.region[i].base, - lmb_size_bytes(&lmb.reserved, i), - BOOTMEM_DEFAULT); +static int __init grab_mlgroups(struct mdesc_handle *md) +{ + unsigned long paddr; + int count = 0; + u64 node; + + mdesc_for_each_node_by_name(md, node, "memory-latency-group") + count++; + if (!count) + return -ENOENT; + + paddr = lmb_alloc(count * sizeof(struct mdesc_mlgroup), + SMP_CACHE_BYTES); + if (!paddr) + return -ENOMEM; + + mlgroups = __va(paddr); + num_mlgroups = count; + + count = 0; + mdesc_for_each_node_by_name(md, node, "memory-latency-group") { + struct mdesc_mlgroup *m = &mlgroups[count++]; + const u64 *val; + + m->node = node; + + val = mdesc_get_property(md, node, "latency", NULL); + m->latency = *val; + val = mdesc_get_property(md, node, "address-match", NULL); + m->match = *val; + val = mdesc_get_property(md, node, "address-mask", NULL); + m->mask = *val; + + numadbg("MLGROUP[%d]: node[%lx] latency[%lx] " + "match[%lx] mask[%lx]\n", + count - 1, m->node, m->latency, m->match, m->mask); + } - *pages_avail -= PAGE_ALIGN(kern_size) >> PAGE_SHIFT; + return 0; +} - for (i = 0; i < lmb.memory.cnt; ++i) { - unsigned long start_pfn, end_pfn, pages; +static int __init grab_mblocks(struct mdesc_handle *md) +{ + unsigned long paddr; + int count = 0; + u64 node; + + mdesc_for_each_node_by_name(md, node, "mblock") + count++; + if (!count) + return -ENOENT; + + paddr = lmb_alloc(count * sizeof(struct mdesc_mblock), + SMP_CACHE_BYTES); + if (!paddr) + return -ENOMEM; + + mblocks = __va(paddr); + num_mblocks = count; + + count = 0; + mdesc_for_each_node_by_name(md, node, "mblock") { + struct mdesc_mblock *m = &mblocks[count++]; + const u64 *val; + + val = mdesc_get_property(md, node, "base", NULL); + m->base = *val; + val = mdesc_get_property(md, node, "size", NULL); + m->size = *val; + val = mdesc_get_property(md, node, + "address-congruence-offset", NULL); + m->offset = *val; + + numadbg("MBLOCK[%d]: base[%lx] size[%lx] offset[%lx]\n", + count - 1, m->base, m->size, m->offset); + } + + return 0; +} + +static void __init numa_parse_mdesc_group_cpus(struct mdesc_handle *md, + u64 grp, cpumask_t *mask) +{ + u64 arc; + + cpus_clear(*mask); + + mdesc_for_each_arc(arc, md, grp, MDESC_ARC_TYPE_BACK) { + u64 target = mdesc_arc_target(md, arc); + const char *name = mdesc_node_name(md, target); + const u64 *id; + + if (strcmp(name, "cpu")) + continue; + id = mdesc_get_property(md, target, "id", NULL); + if (*id < NR_CPUS) + cpu_set(*id, *mask); + } +} + +static struct mdesc_mlgroup * __init find_mlgroup(u64 node) +{ + int i; + + for (i = 0; i < num_mlgroups; i++) { + struct mdesc_mlgroup *m = &mlgroups[i]; + if (m->node == node) + return m; + } + return NULL; +} + +static int __init numa_attach_mlgroup(struct mdesc_handle *md, u64 grp, + int index) +{ + struct mdesc_mlgroup *candidate = NULL; + u64 arc, best_latency = ~(u64)0; + struct node_mem_mask *n; + + mdesc_for_each_arc(arc, md, grp, MDESC_ARC_TYPE_FWD) { + u64 target = mdesc_arc_target(md, arc); + struct mdesc_mlgroup *m = find_mlgroup(target); + if (!m) + continue; + if (m->latency < best_latency) { + candidate = m; + best_latency = m->latency; + } + } + if (!candidate) + return -ENOENT; + + if (num_node_masks != index) { + printk(KERN_ERR "Inconsistent NUMA state, " + "index[%d] != num_node_masks[%d]\n", + index, num_node_masks); + return -EINVAL; + } + + n = &node_masks[num_node_masks++]; + + n->mask = candidate->mask; + n->val = candidate->match; + + numadbg("NUMA NODE[%d]: mask[%lx] val[%lx] (latency[%lx])\n", + index, n->mask, n->val, candidate->latency); + + return 0; +} + +static int __init numa_parse_mdesc_group(struct mdesc_handle *md, u64 grp, + int index) +{ + cpumask_t mask; + int cpu; + + numa_parse_mdesc_group_cpus(md, grp, &mask); + + for_each_cpu_mask(cpu, mask) + numa_cpu_lookup_table[cpu] = index; + numa_cpumask_lookup_table[index] = mask; + + if (numa_debug) { + printk(KERN_INFO "NUMA GROUP[%d]: cpus [ ", index); + for_each_cpu_mask(cpu, mask) + printk("%d ", cpu); + printk("]\n"); + } + + return numa_attach_mlgroup(md, grp, index); +} + +static int __init numa_parse_mdesc(void) +{ + struct mdesc_handle *md = mdesc_grab(); + int i, err, count; + u64 node; + + node = mdesc_node_by_name(md, MDESC_NODE_NULL, "latency-groups"); + if (node == MDESC_NODE_NULL) { + mdesc_release(md); + return -ENOENT; + } + + err = grab_mblocks(md); + if (err < 0) + goto out; + + err = grab_mlgroups(md); + if (err < 0) + goto out; + + count = 0; + mdesc_for_each_node_by_name(md, node, "group") { + err = numa_parse_mdesc_group(md, node, count); + if (err < 0) + break; + count++; + } + + add_node_ranges(); + + for (i = 0; i < num_node_masks; i++) { + allocate_node_data(i); + node_set_online(i); + } + + err = 0; +out: + mdesc_release(md); + return err; +} + +static int __init numa_parse_sun4u(void) +{ + return -1; +} + +static int __init bootmem_init_numa(void) +{ + int err = -1; + + numadbg("bootmem_init_numa()\n"); + + if (numa_enabled) { + if (tlb_type == hypervisor) + err = numa_parse_mdesc(); + else + err = numa_parse_sun4u(); + } + return err; +} + +#else + +static int bootmem_init_numa(void) +{ + return -1; +} + +#endif + +static void __init bootmem_init_nonnuma(void) +{ + unsigned long top_of_ram = lmb_end_of_DRAM(); + unsigned long total_ram = lmb_phys_mem_size(); + unsigned int i; + + numadbg("bootmem_init_nonnuma()\n"); + + printk(KERN_INFO "Top of RAM: 0x%lx, Total RAM: 0x%lx\n", + top_of_ram, total_ram); + printk(KERN_INFO "Memory hole size: %ldMB\n", + (top_of_ram - total_ram) >> 20); + + init_node_masks_nonnuma(); + + for (i = 0; i < lmb.memory.cnt; i++) { + unsigned long size = lmb_size_bytes(&lmb.memory, i); + unsigned long start_pfn, end_pfn; + + if (!size) + continue; - pages = lmb_size_pages(&lmb.memory, i); start_pfn = lmb.memory.region[i].base >> PAGE_SHIFT; - end_pfn = start_pfn + pages; + end_pfn = start_pfn + lmb_size_pages(&lmb.memory, i); + add_active_range(0, start_pfn, end_pfn); + } - memory_present(0, start_pfn, end_pfn); + allocate_node_data(0); + + node_set_online(0); +} + +static void __init reserve_range_in_node(int nid, unsigned long start, + unsigned long end) +{ + numadbg(" reserve_range_in_node(nid[%d],start[%lx],end[%lx]\n", + nid, start, end); + while (start < end) { + unsigned long this_end; + int n; + + this_end = nid_range(start, end, &n); + if (n == nid) { + numadbg(" MATCH reserving range [%lx:%lx]\n", + start, this_end); + reserve_bootmem_node(NODE_DATA(nid), start, + (this_end - start), BOOTMEM_DEFAULT); + } else + numadbg(" NO MATCH, advancing start to %lx\n", + this_end