GIT 6a2d322e4b81edc2ab35573f1c52f93d1d16eebb git+ssh://master.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc.git commit Author: Benjamin Herrenschmidt Date: Fri Feb 22 14:26:43 2008 +1100 [POWERPC] Fix thinko in cpu_thread_mask_to_cores() The function cpu_thread_mask_to_cores() which returns a cpumask of one and only one thread enabled for a given core has a bug as it's shifting things in the wrong direction. Note: The implementation is still sub-optimal in the sense that for a given core, the thread set in the result may not be any of the threads set in the input, which can lead to more IPIs then strictly necessary, but it isn't incorrect per-se. I'll improve that later. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras commit 50530378161fa8d7837243119ed9140ee65e55d4 Author: Anton Vorontsov Date: Fri Feb 22 06:45:08 2008 +1100 [POWERPC] 8xx: Timebase frequency should not depend on bus-frequency m8xx_setup.c says: /* Force all 8xx processors to use divide by 16 processor clock. */ And at the same time it is using bus-frequency for calculating timebase. It is okay for most setups because bus-frequency is equal to clock-frequency. The problem emerges when cpu frequency is > 66MHz, quoting u-boot/cpu/mpc8xx/speed.c: if (gd->cpu_clk <= 66000000) { sccr_reg |= SCCR_EBDF00; /* bus division factor = 1 */ gd->bus_clk = gd->cpu_clk; } else { sccr_reg |= SCCR_EBDF01; /* bus division factor = 2 */ gd->bus_clk = gd->cpu_clk / 2; } So in case of cpu clock > 66MHz, bus_clk = cpu_clk / 2. An then, from Linux, we calculate timebase frequency as tb_freq = bus_clk / 16, that is cpu_clk / 2 / 16, which is wrong. This fixes the system time drifting problem on the EP885C board running at 133MHz. Signed-off-by: Anton Vorontsov Signed-off-by: Paul Mackerras commit d9d1063d47cbfe45f8b369475a35c3cdd64fb69c Author: Johannes Berg Date: Thu Feb 21 20:39:01 2008 +1100 [POWERPC] mpic: Make sparse happy I was running sparse on something else and noticed sparse warnings and especially the bogus code that is fixed by the first hunk of this patch, so I fixed them all while at it. Signed-off-by: Johannes Berg Cc: Benjamin Herrenschmidt Cc: Milton Miller Signed-off-by: Paul Mackerras commit 4217c7b529af3abea090d875f0ef133ed2d44285 Author: Julia Lawall Date: Mon Feb 11 07:07:59 2008 +1100 [POWERPC] Use FIELD_SIZEOF in arch/ppc Robert P.J. Day proposed to use the macro FIELD_SIZEOF in replace of code that matches its definition. The modification was made using the following semantic patch (http://www.emn.fr/x-info/coccinelle/) // @haskernel@ @@ #include @depends on haskernel@ type t; identifier f; @@ - (sizeof(((t*)0)->f)) + FIELD_SIZEOF(t, f) @depends on haskernel@ type t; identifier f; @@ - sizeof(((t*)0)->f) + FIELD_SIZEOF(t, f) // Signed-off-by: Julia Lawall Signed-off-by: Paul Mackerras commit 445857e0fc16ba3f74e778dd5a8707459c84f933 Author: Dale Farnsworth Date: Fri Feb 1 08:11:41 2008 +1100 [POWERPC] Remove dead code at KernelAltiVec This code isn't referenced anywhere, so remove it. Signed-off-by: Dale Farnsworth Signed-off-by: Paul Mackerras commit f8c8803bda4db47cbbdadb9b27b024e903e1d645 Author: Badari Pulavarty Date: Tue Jan 29 09:19:24 2008 +1100 [POWERPC] Add code for removing HPTEs for parts of the linear mapping For memory remove, we need to clean up htab mappings for the section of the memory we are removing. This implements support for removing htab bolted mappings for pSeries logical partitions. Other sub-archs may need to implement similar functionality for hotplug memory remove to work on them. Signed-off-by: Badari Pulavarty Signed-off-by: Paul Mackerras commit 74b20dad1c4cc0fd13ceca62fbab808919e1a7ea Author: Kumar Gala Date: Tue Feb 19 21:28:18 2008 -0800 [LMB]: Fix lmb_add_region if region should be added at the head We introduced a bug in fixing lmb_add_region to handle an initial region being non-zero. Before that fix it was impossible to insert a region at the head of the list since the first region always started at zero. Now that its possible for the first region to be non-zero we need to check to see if the new region should be added at the head and if so actually add it. Signed-off-by: Kumar Gala Signed-off-by: David S. Miller commit e5f270954364a4add74e8445b1db925ac534fcfb Author: Becky Bruce Date: Wed Feb 13 16:58:39 2008 -0800 [LMB]: Make lmb support large physical addressing Convert the lmb code to use u64 instead of unsigned long for physical addresses and sizes. This is needed to support large amounts of RAM on 32-bit systems that support 36-bit physical addressing. Signed-off-by: Becky Bruce Signed-off-by: David S. Miller commit 27e6672bb9912d3e3a41cf88e6142d3ae5e534b3 Author: Kumar Gala Date: Wed Feb 13 16:58:11 2008 -0800 [LMB]: Fix initial lmb add region with a non-zero base If we add to an empty lmb region with a non-zero base we will not coalesce the number of regions down to one. This causes problems on ppc32 for the memory region as its assumed to only have one region. We can fix this be easily specially casing the initial add to just replace the dummy region. Signed-off-by: Kumar Gala Signed-off-by: David S. Miller commit eea89e13a9c61d3928223d2f9bf2295e22e0efb6 Author: David S. Miller Date: Wed Feb 13 16:57:09 2008 -0800 [LMB]: Fix bug in __lmb_alloc_base(). We need to check lmb_add_region() for errors, it can run out of regions etc. Also, the size needs to be padded to the given alignment or else the lmb.reserved regions don't get expanded and instead we get tons of holes and eventually run out of regions prematurely. Signed-off-by: David S. Miller commit d9b2b2a277219d4812311d995054ce4f95067725 Author: David S. Miller Date: Wed Feb 13 16:56:49 2008 -0800 [LIB]: Make PowerPC LMB code generic so sparc64 can use it too. Signed-off-by: David S. Miller arch/powerpc/Kconfig | 1 + arch/powerpc/kernel/btext.c | 3 +- arch/powerpc/kernel/crash.c | 3 +- arch/powerpc/kernel/crash_dump.c | 3 +- arch/powerpc/kernel/head_32.S | 17 -- arch/powerpc/kernel/machine_kexec.c | 3 +- arch/powerpc/kernel/prom.c | 2 +- arch/powerpc/kernel/rtas.c | 2 +- arch/powerpc/kernel/setup-common.c | 2 +- arch/powerpc/kernel/setup_64.c | 2 +- arch/powerpc/kernel/vdso.c | 3 +- arch/powerpc/mm/Makefile | 2 +- arch/powerpc/mm/hash_utils_64.c | 26 ++- arch/powerpc/mm/init_32.c | 2 +- arch/powerpc/mm/init_64.c | 2 +- arch/powerpc/mm/lmb.c | 357 ----------------------------- arch/powerpc/mm/mem.c | 2 +- arch/powerpc/mm/numa.c | 3 +- arch/powerpc/mm/ppc_mmu_32.c | 2 +- arch/powerpc/mm/stab.c | 4 +- arch/powerpc/platforms/8xx/m8xx_setup.c | 7 +- arch/powerpc/platforms/cell/iommu.c | 2 +- arch/powerpc/platforms/maple/setup.c | 2 +- arch/powerpc/platforms/powermac/setup.c | 2 +- arch/powerpc/platforms/ps3/htab.c | 3 +- arch/powerpc/platforms/ps3/mm.c | 3 +- arch/powerpc/platforms/ps3/os-area.c | 3 +- arch/powerpc/platforms/pseries/lpar.c | 15 ++ arch/powerpc/sysdev/dart_iommu.c | 2 +- arch/powerpc/sysdev/mpic.c | 32 ++-- arch/ppc/8xx_io/commproc.c | 2 +- arch/ppc/kernel/head.S | 17 -- arch/sparc64/Kconfig | 1 + include/asm-powerpc/abs_addr.h | 3 +- include/asm-powerpc/cputhreads.h | 2 +- include/asm-powerpc/lmb.h | 82 +------ include/asm-powerpc/machdep.h | 2 + include/asm-powerpc/sparsemem.h | 1 + include/asm-sparc64/lmb.h | 10 + include/linux/lmb.h | 83 +++++++ lib/Kconfig | 3 + lib/Makefile | 2 + lib/lmb.c | 370 +++++++++++++++++++++++++++++++ 43 files changed, 578 insertions(+), 512 deletions(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 5b8d838..e4e13e0 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -90,6 +90,7 @@ config PPC select HAVE_IDE select HAVE_OPROFILE select HAVE_KPROBES + select HAVE_LMB config EARLY_PRINTK bool diff --git a/arch/powerpc/kernel/btext.c b/arch/powerpc/kernel/btext.c index 80e2eef..9f93777 100644 --- a/arch/powerpc/kernel/btext.c +++ b/arch/powerpc/kernel/btext.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -15,7 +16,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c index 571132e..eae401d 100644 --- a/arch/powerpc/kernel/crash.c +++ b/arch/powerpc/kernel/crash.c @@ -24,12 +24,13 @@ #include #include #include +#include #include #include #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c index 29ff77c..9ee3c52 100644 --- a/arch/powerpc/kernel/crash_dump.c +++ b/arch/powerpc/kernel/crash_dump.c @@ -13,8 +13,9 @@ #include #include +#include #include -#include +#include #include #include diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index 0f4fac5..c16d135 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S @@ -763,23 +763,6 @@ load_up_altivec: b fast_exception_return /* - * AltiVec unavailable trap from kernel - print a message, but let - * the task use AltiVec in the kernel until it returns to user mode. - */ -KernelAltiVec: - lwz r3,_MSR(r1) - oris r3,r3,MSR_VEC@h - stw r3,_MSR(r1) /* enable use of AltiVec after return */ - lis r3,87f@h - ori r3,r3,87f@l - mr r4,r2 /* current */ - lwz r5,_NIP(r1) - bl printk - b ret_from_except -87: .string "AltiVec used in kernel (task=%p, pc=%x) \n" - .align 4,0 - -/* * giveup_altivec(tsk) * Disable AltiVec for the task given as the argument, * and save the AltiVec registers in its thread_struct. diff --git a/arch/powerpc/kernel/machine_kexec.c b/arch/powerpc/kernel/machine_kexec.c index c0c8e8c..2d202f2 100644 --- a/arch/powerpc/kernel/machine_kexec.c +++ b/arch/powerpc/kernel/machine_kexec.c @@ -12,8 +12,9 @@ #include #include #include +#include #include -#include +#include void machine_crash_shutdown(struct pt_regs *regs) { diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index eac97f4..ff600ef 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -31,10 +31,10 @@ #include #include #include +#include #include #include -#include #include #include #include diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index 52e95c2..e2e78d9 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -34,7 +35,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 6adb5a1..12cc41c 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -56,7 +57,6 @@ #include #include #include -#include #include #include diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 3b1529c..2c2d831 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -55,7 +56,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c index d3437c4..c21a626 100644 --- a/arch/powerpc/kernel/vdso.c +++ b/arch/powerpc/kernel/vdso.c @@ -21,13 +21,14 @@ #include #include #include +#include #include #include #include #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile index 41649a5..1c00e01 100644 --- a/arch/powerpc/mm/Makefile +++ b/arch/powerpc/mm/Makefile @@ -6,7 +6,7 @@ ifeq ($(CONFIG_PPC64),y) EXTRA_CFLAGS += -mno-minimal-toc endif -obj-y := fault.o mem.o lmb.o \ +obj-y := fault.o mem.o \ init_$(CONFIG_WORD_SIZE).o \ pgtable_$(CONFIG_WORD_SIZE).o \ mmu_context_$(CONFIG_WORD_SIZE).o diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 32f4161..4cc53f9 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -41,7 +42,7 @@ #include #include #include -#include +#include #include #include #include @@ -191,6 +192,24 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend, return ret < 0 ? ret : 0; } +static void htab_remove_mapping(unsigned long vstart, unsigned long vend, + int psize, int ssize) +{ + unsigned long vaddr; + unsigned int step, shift; + + shift = mmu_psize_defs[psize].shift; + step = 1 << shift; + + if (!ppc_md.hpte_removebolted) { + printk("Sub-arch doesn't implement hpte_removebolted\n"); + return; + } + + for (vaddr = vstart; vaddr < vend; vaddr += step) + ppc_md.hpte_removebolted(vaddr, psize, ssize); +} + static int __init htab_dt_scan_seg_sizes(unsigned long node, const char *uname, int depth, void *data) @@ -429,6 +448,11 @@ void create_section_mapping(unsigned long start, unsigned long end) _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_COHERENT | PP_RWXX, mmu_linear_psize, mmu_kernel_ssize)); } + +void remove_section_mapping(unsigned long start, unsigned long end) +{ + htab_remove_mapping(start, end, mmu_linear_psize, mmu_kernel_ssize); +} #endif /* CONFIG_MEMORY_HOTPLUG */ static inline void make_bl(unsigned int *insn_addr, void *func) diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c index 977cb1e..59a725b 100644 --- a/arch/powerpc/mm/init_32.c +++ b/arch/powerpc/mm/init_32.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -41,7 +42,6 @@ #include #include #include -#include #include #include "mmu_decl.h" diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c index c0f5cff..abeb0eb 100644 --- a/arch/powerpc/mm/init_64.c +++ b/arch/powerpc/mm/init_64.c @@ -38,11 +38,11 @@ #include #include #include +#include #include #include #include -#include #include #include #include diff --git a/arch/powerpc/mm/lmb.c b/arch/powerpc/mm/lmb.c deleted file mode 100644 index 4ce23bc..0000000 --- a/arch/powerpc/mm/lmb.c +++ /dev/null @@ -1,357 +0,0 @@ -/* - * Procedures for maintaining information about logical memory blocks. - * - * Peter Bergner, IBM Corp. June 2001. - * Copyright (C) 2001 Peter Bergner. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_PPC32 -#include "mmu_decl.h" /* for __max_low_memory */ -#endif - -#undef DEBUG - -#ifdef DEBUG -#include -#define DBG(fmt...) udbg_printf(fmt) -#else -#define DBG(fmt...) -#endif - -#define LMB_ALLOC_ANYWHERE 0 - -struct lmb lmb; - -void lmb_dump_all(void) -{ -#ifdef DEBUG - unsigned long i; - - DBG("lmb_dump_all:\n"); - DBG(" memory.cnt = 0x%lx\n", lmb.memory.cnt); - DBG(" memory.size = 0x%lx\n", lmb.memory.size); - for (i=0; i < lmb.memory.cnt ;i++) { - DBG(" memory.region[0x%x].base = 0x%lx\n", - i, lmb.memory.region[i].base); - DBG(" .size = 0x%lx\n", - lmb.memory.region[i].size); - } - - DBG("\n reserved.cnt = 0x%lx\n", lmb.reserved.cnt); - DBG(" reserved.size = 0x%lx\n", lmb.reserved.size); - for (i=0; i < lmb.reserved.cnt ;i++) { - DBG(" reserved.region[0x%x].base = 0x%lx\n", - i, lmb.reserved.region[i].base); - DBG(" .size = 0x%lx\n", - lmb.reserved.region[i].size); - } -#endif /* DEBUG */ -} - -static unsigned long __init lmb_addrs_overlap(unsigned long base1, - unsigned long size1, unsigned long base2, unsigned long size2) -{ - return ((base1 < (base2+size2)) && (base2 < (base1+size1))); -} - -static long __init lmb_addrs_adjacent(unsigned long base1, unsigned long size1, - unsigned long base2, unsigned long size2) -{ - if (base2 == base1 + size1) - return 1; - else if (base1 == base2 + size2) - return -1; - - return 0; -} - -static long __init lmb_regions_adjacent(struct lmb_region *rgn, - unsigned long r1, unsigned long r2) -{ - unsigned long base1 = rgn->region[r1].base; - unsigned long size1 = rgn->region[r1].size; - unsigned long base2 = rgn->region[r2].base; - unsigned long size2 = rgn->region[r2].size; - - return lmb_addrs_adjacent(base1, size1, base2, size2); -} - -static void __init lmb_remove_region(struct lmb_region *rgn, unsigned long r) -{ - unsigned long i; - - for (i = r; i < rgn->cnt - 1; i++) { - rgn->region[i].base = rgn->region[i + 1].base; - rgn->region[i].size = rgn->region[i + 1].size; - } - rgn->cnt--; -} - -/* Assumption: base addr of region 1 < base addr of region 2 */ -static void __init lmb_coalesce_regions(struct lmb_region *rgn, - unsigned long r1, unsigned long r2) -{ - rgn->region[r1].size += rgn->region[r2].size; - lmb_remove_region(rgn, r2); -} - -/* This routine called with relocation disabled. */ -void __init lmb_init(void) -{ - /* Create a dummy zero size LMB which will get coalesced away later. - * This simplifies the lmb_add() code below... - */ - lmb.memory.region[0].base = 0; - lmb.memory.region[0].size = 0; - lmb.memory.cnt = 1; - - /* Ditto. */ - lmb.reserved.region[0].base = 0; - lmb.reserved.region[0].size = 0; - lmb.reserved.cnt = 1; -} - -/* This routine may be called with relocation disabled. */ -void __init lmb_analyze(void) -{ - int i; - - lmb.memory.size = 0; - - for (i = 0; i < lmb.memory.cnt; i++) - lmb.memory.size += lmb.memory.region[i].size; -} - -/* This routine called with relocation disabled. */ -static long __init lmb_add_region(struct lmb_region *rgn, unsigned long base, - unsigned long size) -{ - unsigned long coalesced = 0; - long adjacent, i; - - /* First try and coalesce this LMB with another. */ - for (i=0; i < rgn->cnt; i++) { - unsigned long rgnbase = rgn->region[i].base; - unsigned long rgnsize = rgn->region[i].size; - - if ((rgnbase == base) && (rgnsize == size)) - /* Already have this region, so we're done */ - return 0; - - adjacent = lmb_addrs_adjacent(base,size,rgnbase,rgnsize); - if ( adjacent > 0 ) { - rgn->region[i].base -= size; - rgn->region[i].size += size; - coalesced++; - break; - } - else if ( adjacent < 0 ) { - rgn->region[i].size += size; - coalesced++; - break; - } - } - - if ((i < rgn->cnt-1) && lmb_regions_adjacent(rgn, i, i+1) ) { - lmb_coalesce_regions(rgn, i, i+1); - coalesced++; - } - - if (coalesced) - return coalesced; - if (rgn->cnt >= MAX_LMB_REGIONS) - return -1; - - /* Couldn't coalesce the LMB, so add it to the sorted table. */ - for (i = rgn->cnt-1; i >= 0; i--) { - if (base < rgn->region[i].base) { - rgn->region[i+1].base = rgn->region[i].base; - rgn->region[i+1].size = rgn->region[i].size; - } else { - rgn->region[i+1].base = base; - rgn->region[i+1].size = size; - break; - } - } - rgn->cnt++; - - return 0; -} - -/* This routine may be called with relocation disabled. */ -long __init lmb_add(unsigned long base, unsigned long size) -{ - struct lmb_region *_rgn = &(lmb.memory); - - /* On pSeries LPAR systems, the first LMB is our RMO region. */ - if (base == 0) - lmb.rmo_size = size; - - return lmb_add_region(_rgn, base, size); - -} - -long __init lmb_reserve(unsigned long base, unsigned long size) -{ - struct lmb_region *_rgn = &(lmb.reserved); - - BUG_ON(0 == size); - - return lmb_add_region(_rgn, base, size); -} - -long __init lmb_overlaps_region(struct lmb_region *rgn, unsigned long base, - unsigned long size) -{ - unsigned long i; - - for (i=0; i < rgn->cnt; i++) { - unsigned long rgnbase = rgn->region[i].base; - unsigned long rgnsize = rgn->region[i].size; - if ( lmb_addrs_overlap(base,size,rgnbase,rgnsize) ) { - break; - } - } - - return (i < rgn->cnt) ? i : -1; -} - -unsigned long __init lmb_alloc(unsigned long size, unsigned long align) -{ - return lmb_alloc_base(size, align, LMB_ALLOC_ANYWHERE); -} - -unsigned long __init lmb_alloc_base(unsigned long size, unsigned long align, - unsigned long max_addr) -{ - unsigned long alloc; - - alloc = __lmb_alloc_base(size, align, max_addr); - - if (alloc == 0) - panic("ERROR: Failed to allocate 0x%lx bytes below 0x%lx.\n", - size, max_addr); - - return alloc; -} - -unsigned long __init __lmb_alloc_base(unsigned long size, unsigned long align, - unsigned long max_addr) -{ - long i, j; - unsigned long base = 0; - - BUG_ON(0 == size); - -#ifdef CONFIG_PPC32 - /* On 32-bit, make sure we allocate lowmem */ - if (max_addr == LMB_ALLOC_ANYWHERE) - max_addr = __max_low_memory; -#endif - for (i = lmb.memory.cnt-1; i >= 0; i--) { - unsigned long lmbbase = lmb.memory.region[i].base; - unsigned long lmbsize = lmb.memory.region[i].size; - - if (max_addr == LMB_ALLOC_ANYWHERE) - base = _ALIGN_DOWN(lmbbase + lmbsize - size, align); - else if (lmbbase < max_addr) { - base = min(lmbbase + lmbsize, max_addr); - base = _ALIGN_DOWN(base - size, align); - } else - continue; - - while ((lmbbase <= base) && - ((j = lmb_overlaps_region(&lmb.reserved, base, size)) >= 0) ) - base = _ALIGN_DOWN(lmb.reserved.region[j].base - size, - align); - - if ((base != 0) && (lmbbase <= base)) - break; - } - - if (i < 0) - return 0; - - lmb_add_region(&lmb.reserved, base, size); - - return base; -} - -/* You must call lmb_analyze() before this. */ -unsigned long __init lmb_phys_mem_size(void) -{ - return lmb.memory.size; -} - -unsigned long __init lmb_end_of_DRAM(void) -{ - int idx = lmb.memory.cnt - 1; - - return (lmb.memory.region[idx].base + lmb.memory.region[idx].size); -} - -/* You must call lmb_analyze() after this. */ -void __init lmb_enforce_memory_limit(unsigned long memory_limit) -{ - unsigned long i, limit; - struct lmb_property *p; - - if (! memory_limit) - return; - - /* Truncate the lmb regions to satisfy the memory limit. */ - limit = memory_limit; - for (i = 0; i < lmb.memory.cnt; i++) { - if (limit > lmb.memory.region[i].size) { - limit -= lmb.memory.region[i].size; - continue; - } - - lmb.memory.region[i].size = limit; - lmb.memory.cnt = i + 1; - break; - } - - if (lmb.memory.region[0].size < lmb.rmo_size) - lmb.rmo_size = lmb.memory.region[0].size; - - /* And truncate any reserves above the limit also. */ - for (i = 0; i < lmb.reserved.cnt; i++) { - p = &lmb.reserved.region[i]; - - if (p->base > memory_limit) - p->size = 0; - else if ((p->base + p->size) > memory_limit) - p->size = memory_limit - p->base; - - if (p->size == 0) { - lmb_remove_region(&lmb.reserved, i); - i--; - } - } -} - -int __init lmb_is_reserved(unsigned long addr) -{ - int i; - - for (i = 0; i < lmb.reserved.cnt; i++) { - unsigned long upper = lmb.reserved.region[i].base + - lmb.reserved.region[i].size - 1; - if ((addr >= lmb.reserved.region[i].base) && (addr <= upper)) - return 1; - } - return 0; -} diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index be5c506..60c019c 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -42,7 +43,6 @@ #include #include #include -#include #include #include diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index a300d25..1efd631 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -17,8 +17,9 @@ #include #include #include +#include #include -#include +#include #include #include diff --git a/arch/powerpc/mm/ppc_mmu_32.c b/arch/powerpc/mm/ppc_mmu_32.c index 5c45d47..72de3c7 100644 --- a/arch/powerpc/mm/ppc_mmu_32.c +++ b/arch/powerpc/mm/ppc_mmu_32.c @@ -26,11 +26,11 @@ #include #include #include +#include #include #include #include -#include #include "mmu_decl.h" diff --git a/arch/powerpc/mm/stab.c b/arch/powerpc/mm/stab.c index 50448d5..efbbd13 100644 --- a/arch/powerpc/mm/stab.c +++ b/arch/powerpc/mm/stab.c @@ -12,12 +12,14 @@ * 2 of the License, or (at your option) any later version. */ +#include + #include #include #include #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c index 184f998..0d9f75c 100644 --- a/arch/powerpc/platforms/8xx/m8xx_setup.c +++ b/arch/powerpc/platforms/8xx/m8xx_setup.c @@ -111,17 +111,12 @@ void __init mpc8xx_calibrate_decr(void) /* Processor frequency is MHz. */ - ppc_tb_freq = 50000000; - if (!get_freq("bus-frequency", &ppc_tb_freq)) { - printk(KERN_ERR "WARNING: Estimating decrementer frequency " - "(not found)\n"); - } - ppc_tb_freq /= 16; ppc_proc_freq = 50000000; if (!get_freq("clock-frequency", &ppc_proc_freq)) printk(KERN_ERR "WARNING: Estimating processor frequency " "(not found)\n"); + ppc_tb_freq = ppc_proc_freq / 16; printk("Decrementer Frequency = 0x%lx\n", ppc_tb_freq); /* Perform some more timer/timebase initialization. This used diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index 20ea0e1..d6a7325 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c @@ -28,13 +28,13 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c index 3ce2d73..dadf33b 100644 --- a/arch/powerpc/platforms/maple/setup.c +++ b/arch/powerpc/platforms/maple/setup.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -57,7 +58,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 36ff1b6..59404ba 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -53,6 +53,7 @@ #include #include #include +#include #include #include @@ -74,7 +75,6 @@ #include #include #include -#include #include #include "pmac.h" diff --git a/arch/powerpc/platforms/ps3/htab.c b/arch/powerpc/platforms/ps3/htab.c index 7382f19..1cf901f 100644 --- a/arch/powerpc/platforms/ps3/htab.c +++ b/arch/powerpc/platforms/ps3/htab.c @@ -19,9 +19,10 @@ */ #include +#include #include -#include +#include #include #include #include diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c index 6890047..5b3fb2b 100644 --- a/arch/powerpc/platforms/ps3/mm.c +++ b/arch/powerpc/platforms/ps3/mm.c @@ -21,9 +21,10 @@ #include #include #include +#include #include -#include +#include #include #include diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c index b9ea09d..c73379e 100644 --- a/arch/powerpc/platforms/ps3/os-area.c +++ b/arch/powerpc/platforms/ps3/os-area.c @@ -24,8 +24,9 @@ #include #include #include +#include -#include +#include #include "platform.h" diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 9a455d4..233d9be 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -520,6 +520,20 @@ static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va, BUG_ON(lpar_rc != H_SUCCESS); } +static void pSeries_lpar_hpte_removebolted(unsigned long ea, + int psize, int ssize) +{ + unsigned long slot, vsid, va; + + vsid = get_kernel_vsid(ea, ssize); + va = hpt_va(ea, vsid, ssize); + + slot = pSeries_lpar_hpte_find(va, psize, ssize); + BUG_ON(slot == -1); + + pSeries_lpar_hpte_invalidate(slot, va, psize, ssize, 0); +} + /* Flag bits for H_BULK_REMOVE */ #define HBR_REQUEST 0x4000000000000000UL #define HBR_RESPONSE 0x8000000000000000UL @@ -597,6 +611,7 @@ void __init hpte_init_lpar(void) ppc_md.hpte_updateboltedpp = pSeries_lpar_hpte_updateboltedpp; ppc_md.hpte_insert = pSeries_lpar_hpte_insert; ppc_md.hpte_remove = pSeries_lpar_hpte_remove; + ppc_md.hpte_removebolted = pSeries_lpar_hpte_removebolted; ppc_md.flush_hash_range = pSeries_lpar_flush_hash_range; ppc_md.hpte_clear_all = pSeries_lpar_hptab_clear; } diff --git a/arch/powerpc/sysdev/dart_iommu.c b/arch/powerpc/sysdev/dart_iommu.c index e0e24b0..005c2ec 100644 --- a/arch/powerpc/sysdev/dart_iommu.c +++ b/arch/powerpc/sysdev/dart_iommu.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -44,7 +45,6 @@ #include #include #include -#include #include #include "dart.h" diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 6ffdda2..6131fd2 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -175,13 +175,16 @@ static inline void _mpic_write(enum mpic_reg_type type, switch(type) { #ifdef CONFIG_PPC_DCR case mpic_access_dcr: - return dcr_write(rb->dhost, reg, value); + dcr_write(rb->dhost, reg, value); + break; #endif case mpic_access_mmio_be: - return out_be32(rb->base + (reg >> 2), value); + out_be32(rb->base + (reg >> 2), value); + break; case mpic_access_mmio_le: default: - return out_le32(rb->base + (reg >> 2), value); + out_le32(rb->base + (reg >> 2), value); + break; } } @@ -1000,7 +1003,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, const char *name) { struct mpic *mpic; - u32 reg; + u32 greg_feature; const char *vers; int i; int intvec_top; @@ -1064,7 +1067,8 @@ struct mpic * __init mpic_alloc(struct device_node *node, /* Look for protected sources */ if (node) { - unsigned int psize, bits, mapsize; + int psize; + unsigned int bits, mapsize; const u32 *psrc = of_get_property(node, "protected-sources", &psize); if (psrc) { @@ -1107,8 +1111,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, * in, try to obtain one */ if (paddr == 0 && !(mpic->flags & MPIC_USES_DCR)) { - const u32 *reg; - reg = of_get_property(node, "reg", NULL); + const u32 *reg = of_get_property(node, "reg", NULL); BUG_ON(reg == NULL); paddr = of_translate_address(node, reg); BUG_ON(paddr == OF_BAD_ADDR); @@ -1137,12 +1140,13 @@ struct mpic * __init mpic_alloc(struct device_node *node, * MPICs, num sources as well. On ISU MPICs, sources are counted * as ISUs are added */ - reg = mpic_read(mpic->gregs, MPIC_INFO(GREG_FEATURE_0)); - mpic->num_cpus = ((reg & MPIC_GREG_FEATURE_LAST_CPU_MASK) + greg_feature = mpic_read(mpic->gregs, MPIC_INFO(GREG_FEATURE_0)); + mpic->num_cpus = ((greg_feature & MPIC_GREG_FEATURE_LAST_CPU_MASK) >> MPIC_GREG_FEATURE_LAST_CPU_SHIFT) + 1; if (isu_size == 0) - mpic->num_sources = ((reg & MPIC_GREG_FEATURE_LAST_SRC_MASK) - >> MPIC_GREG_FEATURE_LAST_SRC_SHIFT) + 1; + mpic->num_sources = + ((greg_feature & MPIC_GREG_FEATURE_LAST_SRC_MASK) + >> MPIC_GREG_FEATURE_LAST_SRC_SHIFT) + 1; /* Map the per-CPU registers */ for (i = 0; i < mpic->num_cpus; i++) { @@ -1161,7 +1165,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, mpic->isu_mask = (1 << mpic->isu_shift) - 1; /* Display version */ - switch (reg & MPIC_GREG_FEATURE_VERSION_MASK) { + switch (greg_feature & MPIC_GREG_FEATURE_VERSION_MASK) { case 1: vers = "1.0"; break; @@ -1321,7 +1325,7 @@ void __init mpic_set_serial_int(struct mpic *mpic, int enable) void mpic_irq_set_priority(unsigned int irq, unsigned int pri) { - int is_ipi; + unsigned int is_ipi; struct mpic *mpic = mpic_find(irq, &is_ipi); unsigned int src = mpic_irq_to_hw(irq); unsigned long flags; @@ -1344,7 +1348,7 @@ void mpic_irq_set_priority(unsigned int irq, unsigned int pri) unsigned int mpic_irq_get_priority(unsigned int irq) { - int is_ipi; + unsigned int is_ipi; struct mpic *mpic = mpic_find(irq, &is_ipi); unsigned int src = mpic_irq_to_hw(irq); unsigned long flags; diff --git a/arch/ppc/8xx_io/commproc.c b/arch/ppc/8xx_io/commproc.c index 9d656de..752443d 100644 --- a/arch/ppc/8xx_io/commproc.c +++ b/arch/ppc/8xx_io/commproc.c @@ -43,7 +43,7 @@ ({ \ u32 offset = offsetof(immap_t, member); \ void *addr = ioremap (IMAP_ADDR + offset, \ - sizeof( ((immap_t*)0)->member)); \ + FIELD_SIZEOF(immap_t, member)); \ addr; \ }) diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S index 1b0ec72..e7e642b 100644 --- a/arch/ppc/kernel/head.S +++ b/arch/ppc/kernel/head.S @@ -701,23 +701,6 @@ load_up_altivec: b fast_exception_return /* - * AltiVec unavailable trap from kernel - print a message, but let - * the task use AltiVec in the kernel until it returns to user mode. - */ -KernelAltiVec: - lwz r3,_MSR(r1) - oris r3,r3,MSR_VEC@h - stw r3,_MSR(r1) /* enable use of AltiVec after return */ - lis r3,87f@h - ori r3,r3,87f@l - mr r4,r2 /* current */ - lwz r5,_NIP(r1) - bl printk - b ret_from_except -87: .string "AltiVec used in kernel (task=%p, pc=%x) \n" - .align 4,0 - -/* * giveup_altivec(tsk) * Disable AltiVec for the task given as the argument, * and save the AltiVec registers in its thread_struct. diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index 3af378d..b18d24d 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig @@ -15,6 +15,7 @@ config SPARC64 bool default y select HAVE_IDE + select HAVE_LMB help SPARC is a family of RISC microprocessors designed and marketed by Sun Microsystems, incorporated. This port covers the newer 64-bit diff --git a/include/asm-powerpc/abs_addr.h b/include/asm-powerpc/abs_addr.h index 4aa2207..98324c5 100644 --- a/include/asm-powerpc/abs_addr.h +++ b/include/asm-powerpc/abs_addr.h @@ -12,10 +12,11 @@ * 2 of the License, or (at your option) any later version. */ +#include + #include #include #include -#include #include struct mschunks_map { diff --git a/include/asm-powerpc/cputhreads.h b/include/asm-powerpc/cputhreads.h index 8485c28..fb11b0c 100644 --- a/include/asm-powerpc/cputhreads.h +++ b/include/asm-powerpc/cputhreads.h @@ -35,7 +35,7 @@ static inline cpumask_t cpu_thread_mask_to_cores(cpumask_t threads) res = CPU_MASK_NONE; for (i = 0; i < NR_CPUS; i += threads_per_core) { - cpus_shift_right(tmp, threads_core_mask, i); + cpus_shift_left(tmp, threads_core_mask, i); if (cpus_intersects(threads, tmp)) cpu_set(i, res); } diff --git a/include/asm-powerpc/lmb.h b/include/asm-powerpc/lmb.h index 5d1dc48..028184b 100644 --- a/include/asm-powerpc/lmb.h +++ b/include/asm-powerpc/lmb.h @@ -1,81 +1,15 @@ #ifndef _ASM_POWERPC_LMB_H #define _ASM_POWERPC_LMB_H -#ifdef __KERNEL__ -/* - * Definitions for talking to the Open Firmware PROM on - * Power Macintosh computers. - * - * Copyright (C) 2001 Peter Bergner, IBM Corp. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ +#include -#include -#include +#define LMB_DBG(fmt...) udbg_printf(fmt) -#define MAX_LMB_REGIONS 128 +#ifdef CONFIG_PPC32 +extern unsigned long __max_low_memory; +#define LMB_REAL_LIMIT __max_low_memory +#else +#define LMB_REAL_LIMIT 0 +#endif -struct lmb_property { - unsigned long base; - unsigned long size; -}; - -struct lmb_region { - unsigned long cnt; - unsigned long size; - struct lmb_property region[MAX_LMB_REGIONS+1]; -}; - -struct lmb { - unsigned long debug; - unsigned long rmo_size; - struct lmb_region memory; - struct lmb_region reserved; -}; - -extern struct lmb lmb; - -extern void __init lmb_init(void); -extern void __init lmb_analyze(void); -extern long __init lmb_add(unsigned long base, unsigned long size); -extern long __init lmb_reserve(unsigned long base, unsigned long size); -extern unsigned long __init lmb_alloc(unsigned long size, unsigned long align); -extern unsigned long __init lmb_alloc_base(unsigned long size, - unsigned long align, unsigned long max_addr); -extern unsigned long __init __lmb_alloc_base(unsigned long size, - unsigned long align, unsigned long max_addr); -extern unsigned long __init lmb_phys_mem_size(void); -extern unsigned long __init lmb_end_of_DRAM(void); -extern void __init lmb_enforce_memory_limit(unsigned long memory_limit); -extern int __init lmb_is_reserved(unsigned long addr); - -extern void lmb_dump_all(void); - -static inline unsigned long -lmb_size_bytes(struct lmb_region *type, unsigned long region_nr) -{ - return type->region[region_nr].size; -} -static inline unsigned long -lmb_size_pages(struct lmb_region *type, unsigned long region_nr) -{ - return lmb_size_bytes(type, region_nr) >> PAGE_SHIFT; -} -static inline unsigned long -lmb_start_pfn(struct lmb_region *type, unsigned long region_nr) -{ - return type->region[region_nr].base >> PAGE_SHIFT; -} -static inline unsigned long -lmb_end_pfn(struct lmb_region *type, unsigned long region_nr) -{ - return lmb_start_pfn(type, region_nr) + - lmb_size_pages(type, region_nr); -} - -#endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_LMB_H */ diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h index 0872ec2..b95386a 100644 --- a/include/asm-powerpc/machdep.h +++ b/include/asm-powerpc/machdep.h @@ -68,6 +68,8 @@ struct machdep_calls { unsigned long vflags, int psize, int ssize); long (*hpte_remove)(unsigned long hpte_group); + void (*hpte_removebolted)(unsigned long ea, + int psize, int ssize); void (*flush_hash_range)(unsigned long number, int local); /* special for kexec, to be called in real mode, linar mapping is diff --git a/include/asm-powerpc/sparsemem.h b/include/asm-powerpc/sparsemem.h index e8b493d..c5acf4c 100644 --- a/include/asm-powerpc/sparsemem.h +++ b/include/asm-powerpc/sparsemem.h @@ -15,6 +15,7 @@ #ifdef CONFIG_MEMORY_HOTPLUG extern void create_section_mapping(unsigned long start, unsigned long end); +extern void remove_section_mapping(unsigned long start, unsigned long end); #ifdef CONFIG_NUMA extern int hot_add_scn_to_nid(unsigned long scn_addr); #else diff --git a/include/asm-sparc64/lmb.h b/include/asm-sparc64/lmb.h new file mode 100644 index 0000000..6a352cb --- /dev/null +++ b/include/asm-sparc64/lmb.h @@ -0,0 +1,10 @@ +#ifndef _SPARC64_LMB_H +#define _SPARC64_LMB_H + +#include + +#define LMB_DBG(fmt...) prom_printf(fmt) + +#define LMB_REAL_LIMIT 0 + +#endif /* !(_SPARC64_LMB_H) */ diff --git a/include/linux/lmb.h b/include/linux/lmb.h new file mode 100644 index 0000000..632717c --- /dev/null +++ b/include/linux/lmb.h @@ -0,0 +1,83 @@ +#ifndef _LINUX_LMB_H +#define _LINUX_LMB_H +#ifdef __KERNEL__ + +/* + * Logical memory blocks. + * + * Copyright (C) 2001 Peter Bergner, IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include + +#define MAX_LMB_REGIONS 128 + +struct lmb_property { + u64 base; + u64 size; +}; + +struct lmb_region { + unsigned long cnt; + u64 size; + struct lmb_property region[MAX_LMB_REGIONS+1]; +}; + +struct lmb { + unsigned long debug; + u64 rmo_size; + struct lmb_region memory; + struct lmb_region reserved; +}; + +extern struct lmb lmb; + +extern void __init lmb_init(void); +extern void __init lmb_analyze(void); +extern long __init lmb_add(u64 base, u64 size); +extern long __init lmb_reserve(u64 base, u64 size); +extern u64 __init lmb_alloc(u64 size, u64 align); +extern u64 __init lmb_alloc_base(u64 size, + u64, u64 max_addr); +extern u64 __init __lmb_alloc_base(u64 size, + u64 align, u64 max_addr); +extern u64 __init lmb_phys_mem_size(void); +extern u64 __init lmb_end_of_DRAM(void); +extern void __init lmb_enforce_memory_limit(u64 memory_limit); +extern int __init lmb_is_reserved(u64 addr); + +extern void lmb_dump_all(void); + +static inline u64 +lmb_size_bytes(struct lmb_region *type, unsigned long region_nr) +{ + return type->region[region_nr].size; +} +static inline u64 +lmb_size_pages(struct lmb_region *type, unsigned long region_nr) +{ + return lmb_size_bytes(type, region_nr) >> PAGE_SHIFT; +} +static inline u64 +lmb_start_pfn(struct lmb_region *type, unsigned long region_nr) +{ + return type->region[region_nr].base >> PAGE_SHIFT; +} +static inline u64 +lmb_end_pfn(struct lmb_region *type, unsigned long region_nr) +{ + return lmb_start_pfn(type, region_nr) + + lmb_size_pages(type, region_nr); +} + +#include + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_LMB_H */ diff --git a/lib/Kconfig b/lib/Kconfig index ba3d104..2d53dc0 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -141,4 +141,7 @@ config HAS_DMA config CHECK_SIGNATURE bool +config HAVE_LMB + boolean + endmenu diff --git a/lib/Makefile b/lib/Makefile index 23de261..61bba16 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -70,6 +70,8 @@ obj-$(CONFIG_FAULT_INJECTION) += fault-inject.o lib-$(CONFIG_GENERIC_BUG) += bug.o +obj-$(CONFIG_HAVE_LMB) += lmb.o + hostprogs-y := gen_crc32table clean-files := crc32table.h diff --git a/lib/lmb.c b/lib/lmb.c new file mode 100644 index 0000000..3c43b95 --- /dev/null +++ b/lib/lmb.c @@ -0,0 +1,370 @@ +/* + * Procedures for maintaining information about logical memory blocks. + * + * Peter Bergner, IBM Corp. June 2001. + * Copyright (C) 2001 Peter Bergner. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include + +#undef DEBUG + +#ifdef DEBUG +#define DBG(fmt...) LMB_DBG(fmt) +#else +#define DBG(fmt...) +#endif + +#define LMB_ALLOC_ANYWHERE 0 + +struct lmb lmb; + +void lmb_dump_all(void) +{ +#ifdef DEBUG + unsigned long i; + + DBG("lmb_dump_all:\n"); + DBG(" memory.cnt = 0x%lx\n", lmb.memory.cnt); + DBG(" memory.size = 0x%llx\n", + (unsigned long long)lmb.memory.size); + for (i=0; i < lmb.memory.cnt ;i++) { + DBG(" memory.region[0x%x].base = 0x%llx\n", + i, (unsigned long long)lmb.memory.region[i].base); + DBG(" .size = 0x%llx\n", + (unsigned long long)lmb.memory.region[i].size); + } + + DBG("\n reserved.cnt = 0x%lx\n", lmb.reserved.cnt); + DBG(" reserved.size = 0x%lx\n", lmb.reserved.size); + for (i=0; i < lmb.reserved.cnt ;i++) { + DBG(" reserved.region[0x%x].base = 0x%llx\n", + i, (unsigned long long)lmb.reserved.region[i].base); + DBG(" .size = 0x%llx\n", + (unsigned long long)lmb.reserved.region[i].size); + } +#endif /* DEBUG */ +} + +static unsigned long __init lmb_addrs_overlap(u64 base1, + u64 size1, u64 base2, u64 size2) +{ + return ((base1 < (base2+size2)) && (base2 < (base1+size1))); +} + +static long __init lmb_addrs_adjacent(u64 base1, u64 size1, + u64 base2, u64 size2) +{ + if (base2 == base1 + size1) + return 1; + else if (base1 == base2 + size2) + return -1; + + return 0; +} + +static long __init lmb_regions_adjacent(struct lmb_region *rgn, + unsigned long r1, unsigned long r2) +{ + u64 base1 = rgn->region[r1].base; + u64 size1 = rgn->region[r1].size; + u64 base2 = rgn->region[r2].base; + u64 size2 = rgn->region[r2].size; + + return lmb_addrs_adjacent(base1, size1, base2, size2); +} + +static void __init lmb_remove_region(struct lmb_region *rgn, unsigned long r) +{ + unsigned long i; + + for (i = r; i < rgn->cnt - 1; i++) { + rgn->region[i].base = rgn->region[i + 1].base; + rgn->region[i].size = rgn->region[i + 1].size; + } + rgn->cnt--; +} + +/* Assumption: base addr of region 1 < base addr of region 2 */ +static void __init lmb_coalesce_regions(struct lmb_region *rgn, + unsigned long r1, unsigned long r2) +{ + rgn->region[r1].size += rgn->region[r2].size; + lmb_remove_region(rgn, r2); +} + +/* This routine called with relocation disabled. */ +void __init lmb_init(void) +{ + /* Create a dummy zero size LMB which will get coalesced away later. + * This simplifies the lmb_add() code below... + */ + lmb.memory.region[0].base = 0; + lmb.memory.region[0].size = 0; + lmb.memory.cnt = 1; + + /* Ditto. */ + lmb.reserved.region[0].base = 0; + lmb.reserved.region[0].size = 0; + lmb.reserved.cnt = 1; +} + +/* This routine may be called with relocation disabled. */ +void __init lmb_analyze(void) +{ + int i; + + lmb.memory.size = 0; + + for (i = 0; i < lmb.memory.cnt; i++) + lmb.memory.size += lmb.memory.region[i].size; +} + +/* This routine called with relocation disabled. */ +static long __init lmb_add_region(struct lmb_region *rgn, u64 base, u64 size) +{ + unsigned long coalesced = 0; + long adjacent, i; + + if ((rgn->cnt == 1) && (rgn->region[0].size == 0)) { + rgn->region[0].base = base; + rgn->region[0].size = size; + return 0; + } + + /* First try and coalesce this LMB with another. */ + for (i=0; i < rgn->cnt; i++) { + u64 rgnbase = rgn->region[i].base; + u64 rgnsize = rgn->region[i].size; + + if ((rgnbase == base) && (rgnsize == size)) + /* Already have this region, so we're done */ + return 0; + + adjacent = lmb_addrs_adjacent(base,size,rgnbase,rgnsize); + if ( adjacent > 0 ) { + rgn->region[i].base -= size; + rgn->region[i].size += size; + coalesced++; + break; + } + else if ( adjacent < 0 ) { + rgn->region[i].size += size; + coalesced++; + break; + } + } + + if ((i < rgn->cnt-1) && lmb_regions_adjacent(rgn, i, i+1) ) { + lmb_coalesce_regions(rgn, i, i+1); + coalesced++; + } + + if (coalesced) + return coalesced; + if (rgn->cnt >= MAX_LMB_REGIONS) + return -1; + + /* Couldn't coalesce the LMB, so add it to the sorted table. */ + for (i = rgn->cnt-1; i >= 0; i--) { + if (base < rgn->region[i].base) { + rgn->region[i+1].base = rgn->region[i].base; + rgn->region[i+1].size = rgn->region[i].size; + } else { + rgn->region[i+1].base = base; + rgn->region[i+1].size = size; + break; + } + } + + if (base < rgn->region[0].base) { + rgn->region[0].base = base; + rgn->region[0].size = size; + } + rgn->cnt++; + + return 0; +} + +/* This routine may be called with relocation disabled. */ +long __init lmb_add(u64 base, u64 size) +{ + struct lmb_region *_rgn = &(lmb.memory); + + /* On pSeries LPAR systems, the first LMB is our RMO region. */ + if (base == 0) + lmb.rmo_size = size; + + return lmb_add_region(_rgn, base, size); + +} + +long __init lmb_reserve(u64 base, u64 size) +{ + struct lmb_region *_rgn = &(lmb.reserved); + + BUG_ON(0 == size); + + return lmb_add_region(_rgn, base, size); +} + +long __init lmb_overlaps_region(struct lmb_region *rgn, u64 base, + u64 size) +{ + unsigned long i; + + for (i=0; i < rgn->cnt; i++) { + u64 rgnbase = rgn->region[i].base; + u64 rgnsize = rgn->region[i].size; + if ( lmb_addrs_overlap(base,size,rgnbase,rgnsize) ) { + break; + } + } + + return (i < rgn->cnt) ? i : -1; +} + +u64 __init lmb_alloc(u64 size, u64 align) +{ + return lmb_alloc_base(size, align, LMB_ALLOC_ANYWHERE); +} + +u64 __init lmb_alloc_base(u64 size, u64 align, u64 max_addr) +{ + u64 alloc; + + alloc = __lmb_alloc_base(size, align, max_addr); + + if (alloc == 0) + panic("ERROR: Failed to allocate 0x%llx bytes below 0x%llx.\n", + (unsigned long long) size, (unsigned long long) max_addr); + + return alloc; +} + +static u64 lmb_align_down(u64 addr, u64 size) +{ + return addr & ~(size - 1); +} + +static u64 lmb_align_up(u64 addr, u64 size) +{ + return (addr + (size - 1)) & ~(size - 1); +} + +u64 __init __lmb_alloc_base(u64 size, u64 align, u64 max_addr) +{ + long i, j; + u64 base = 0; + + BUG_ON(0 == size); + + /* On some platforms, make sure we allocate lowmem */ + if (max_addr == LMB_ALLOC_ANYWHERE) + max_addr = LMB_REAL_LIMIT; + + for (i = lmb.memory.cnt-1; i >= 0; i--) { + u64 lmbbase = lmb.memory.region[i].base; + u64 lmbsize = lmb.memory.region[i].size; + + if (max_addr == LMB_ALLOC_ANYWHERE) + base = lmb_align_down(lmbbase + lmbsize - size, align); + else if (lmbbase < max_addr) { + base = min(lmbbase + lmbsize, max_addr); + base = lmb_align_down(base - size, align); + } else + continue; + + while ((lmbbase <= base) && + ((j = lmb_overlaps_region(&lmb.reserved, base, size)) >= 0) ) + base = lmb_align_down(lmb.reserved.region[j].base - size, + align); + + if ((base != 0) && (lmbbase <= base)) + break; + } + + if (i < 0) + return 0; + + if (lmb_add_region(&lmb.reserved, base, lmb_align_up(size, align)) < 0) + return 0; + + return base; +} + +/* You must call lmb_analyze() before this. */ +u64 __init lmb_phys_mem_size(void) +{ + return lmb.memory.size; +} + +u64 __init lmb_end_of_DRAM(void) +{ + int idx = lmb.memory.cnt - 1; + + return (lmb.memory.region[idx].base + lmb.memory.region[idx].size); +} + +/* You must call lmb_analyze() after this. */ +void __init lmb_enforce_memory_limit(u64 memory_limit) +{ + unsigned long i; + u64 limit; + struct lmb_property *p; + + if (! memory_limit) + return; + + /* Truncate the lmb regions to satisfy the memory limit. */ + limit = memory_limit; + for (i = 0; i < lmb.memory.cnt; i++) { + if (limit > lmb.memory.region[i].size) { + limit -= lmb.memory.region[i].size; + continue; + } + + lmb.memory.region[i].size = limit; + lmb.memory.cnt = i + 1; + break; + } + + if (lmb.memory.region[0].size < lmb.rmo_size) + lmb.rmo_size = lmb.memory.region[0].size; + + /* And truncate any reserves above the limit also. */ + for (i = 0; i < lmb.reserved.cnt; i++) { + p = &lmb.reserved.region[i]; + + if (p->base > memory_limit) + p->size = 0; + else if ((p->base + p->size) > memory_limit) + p->size = memory_limit - p->base; + + if (p->size == 0) { + lmb_remove_region(&lmb.reserved, i); + i--; + } + } +} + +int __init lmb_is_reserved(u64 addr) +{ + int i; + + for (i = 0; i < lmb.reserved.cnt; i++) { + u64 upper = lmb.reserved.region[i].base + + lmb.reserved.region[i].size - 1; + if ((addr >= lmb.reserved.region[i].base) && (addr <= upper)) + return 1; + } + return 0; +}