From: Yinghai Lu <yinghai@kernel.org> Date: 2010-07-22 18:25:19
New memblock could be used to replace early_res in x86.
Suggested by: David, Ben, and Thomas
-v25: update to mainline with kmemleak fix on nobootmem
also rename lmb to memblock alread in mainline
-v26: according to Linus and hpa, seperate the big patchset to small ones.
This one is rebase of Ben's changeset to current mainline/tip
Last 6 are needed for x86 memblock transistion, but change mm/memblock.c
Thanks
Yinghai Lu
[PATCH 01/31] memblock: Rename memblock_region to memblock_type and memblock_property to memblock_region
[PATCH 02/31] memblock: No reason to include asm/memblock.h late
[PATCH 03/31] memblock: Introduce for_each_memblock() and new accessors, and use it
[PATCH 04/31] memblock: Remove nid_range argument, arch provides memblock_nid_range() instead
[PATCH 05/31] memblock: Factor the lowest level alloc function
[PATCH 06/31] memblock: Expose MEMBLOCK_ALLOC_ANYWHERE
[PATCH 07/31] memblock: Introduce default allocation limit and use it to replace explicit ones
[PATCH 08/31] memblock: Remove rmo_size, burry it in arch/powerpc where it belongs
[PATCH 09/31] memblock: Change u64 to phys_addr_t
[PATCH 10/31] memblock: Remove unused memblock.debug struct member
[PATCH 11/31] memblock: Remove memblock_type.size and add memblock.memory_size instead
[PATCH 12/31] memblock: Move memblock arrays to static storage in memblock.c and make their size a variable
[PATCH 13/31] memblock: Add debug markers at the end of the array
[PATCH 14/31] memblock: Make memblock_find_region() out of memblock_alloc_region()
[PATCH 15/31] memblock: Define MEMBLOCK_ERROR internally instead of using ~(phys_addr_t)0
[PATCH 16/31] memblock: Move memblock_init() to the bottom of the file
[PATCH 17/31] memblock: split memblock_find_base() out of __memblock_alloc_base()
[PATCH 18/31] memblock: Move functions around into a more sensible order
[PATCH 19/31] memblock: Add array resizing support
[PATCH 20/31] memblock: Add arch function to control coalescing of memblock memory regions
[PATCH 21/31] memblock: Add "start" argument to memblock_find_base()
[PATCH 22/31] memblock: NUMA allocate can now use early_pfn_map
[PATCH 23/31] memblock: Separate memblock_alloc_nid() and memblock_alloc_try_nid()
[PATCH 24/31] memblock: Make memblock_alloc_try_nid() fallback to MEMBLOCK_ALLOC_ANYWHERE
[PATCH 25/31] memblock: Add debugfs files to dump the arrays content
[PATCH 26/31] memblock: Prepare x86 to use memblock to replace early_res
[PATCH 27/31] memblock: Print new doubled array location info
[PATCH 28/31] memblock: Export MEMBLOCK_ERROR again
[PATCH 29/31] memblock: Prepare to include linux/memblock.h in core file
[PATCH 30/31] memblock: Add ARCH_DISCARD_MEMBLOCK to put memblock code to .init
[PATCH 31/31] memblock: Add memblock_find_in_range()
arch/microblaze/include/asm/memblock.h | 3 -
arch/microblaze/mm/init.c | 18 +-
arch/powerpc/include/asm/memblock.h | 7 -
arch/powerpc/include/asm/mmu.h | 12 +
arch/powerpc/kernel/head_40x.S | 6 +-
arch/powerpc/kernel/paca.c | 2 +-
arch/powerpc/kernel/prom.c | 15 +-
arch/powerpc/kernel/rtas.c | 2 +-
arch/powerpc/kernel/setup_32.c | 2 +-
arch/powerpc/kernel/setup_64.c | 2 +-
arch/powerpc/mm/40x_mmu.c | 17 +-
arch/powerpc/mm/44x_mmu.c | 14 +
arch/powerpc/mm/fsl_booke_mmu.c | 12 +-
arch/powerpc/mm/hash_utils_64.c | 35 ++-
arch/powerpc/mm/init_32.c | 43 +-
arch/powerpc/mm/init_64.c | 1 +
arch/powerpc/mm/mem.c | 94 ++---
arch/powerpc/mm/numa.c | 17 +-
arch/powerpc/mm/ppc_mmu_32.c | 18 +-
arch/powerpc/mm/tlb_nohash.c | 16 +
arch/powerpc/platforms/embedded6xx/wii.c | 2 +-
arch/sh/include/asm/memblock.h | 2 -
arch/sh/mm/init.c | 16 +-
arch/sparc/include/asm/memblock.h | 2 -
arch/sparc/mm/init_64.c | 46 +--
include/linux/memblock.h | 162 +++++--
mm/memblock.c | 764 +++++++++++++++++++-----------
27 files changed, 846 insertions(+), 484 deletions(-)
From: Yinghai Lu <yinghai@kernel.org> Date: 2010-07-22 18:22:14
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
This introduce memblock.current_limit which is used to limit allocations
from memblock_alloc() or memblock_alloc_base(..., MEMBLOCK_ALLOC_ACCESSIBLE).
The old MEMBLOCK_ALLOC_ANYWHERE changes value from 0 to ~(u64)0 and can still
be used with memblock_alloc_base() to allocate really anywhere.
It is -no-longer- cropped to MEMBLOCK_REAL_LIMIT which disappears.
Note to archs: I'm leaving the default limit to MEMBLOCK_ALLOC_ANYWHERE. I
strongly recommend that you ensure that you set an appropriate limit
during boot in order to guarantee that an memblock_alloc() at any time
results in something that is accessible with a simple __va().
The reason is that a subsequent patch will introduce the ability for
the array to resize itself by reallocating itself. The MEMBLOCK core will
honor the current limit when performing those allocations.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/microblaze/include/asm/memblock.h | 3 ---
arch/powerpc/include/asm/memblock.h | 7 -------
arch/powerpc/kernel/prom.c | 20 +++++++++++++++++++-
arch/powerpc/kernel/setup_32.c | 2 +-
arch/powerpc/mm/40x_mmu.c | 5 +++--
arch/powerpc/mm/fsl_booke_mmu.c | 3 ++-
arch/powerpc/mm/hash_utils_64.c | 3 ++-
arch/powerpc/mm/init_32.c | 29 +++++++----------------------
arch/powerpc/mm/ppc_mmu_32.c | 3 +--
arch/powerpc/mm/tlb_nohash.c | 2 ++
arch/sh/include/asm/memblock.h | 2 --
arch/sparc/include/asm/memblock.h | 2 --
include/linux/memblock.h | 16 +++++++++++++++-
mm/memblock.c | 19 +++++++++++--------
14 files changed, 63 insertions(+), 53 deletions(-)
@@ -98,7 +98,7 @@ static void __init move_device_tree(void)if((memory_limit&&(start+size)>memory_limit)||overlaps_crashkernel(start,size)){-p=__va(memblock_alloc_base(size,PAGE_SIZE,memblock.rmo_size));+p=__va(memblock_alloc(size,PAGE_SIZE));memcpy(p,initial_boot_params,size);initial_boot_params=(structboot_param_header*)p;DBG("Moved device tree to 0x%p\n",p);
@@ -655,6 +655,21 @@ static void __init phyp_dump_reserve_mem(void)staticinlinevoid__initphyp_dump_reserve_mem(void){}#endif /* CONFIG_PHYP_DUMP && CONFIG_PPC_RTAS */+staticvoidset_boot_memory_limit(void)+{+#ifdef CONFIG_PPC32+/* 601 can only access 16MB at the moment */+if(PVR_VER(mfspr(SPRN_PVR))==1)+memblock_set_current_limit(0x01000000);+/* 8xx can only access 8MB at the moment */+elseif(PVR_VER(mfspr(SPRN_PVR))==0x50)+memblock_set_current_limit(0x00800000);+else+memblock_set_current_limit(0x10000000);+#else+memblock_set_current_limit(memblock.rmo_size);+#endif+}void__initearly_init_devtree(void*params){
@@ -718,6 +734,8 @@ void __init early_init_devtree(void *params)DBG("Phys. mem: %llx\n",memblock_phys_mem_size());+set_boot_memory_limit();+/* We may need to relocate the flat tree, do it now.*FIXME..andtheinitrdtoo?*/move_device_tree();
@@ -246,7 +246,7 @@ static void __init irqstack_early_init(void)unsignedinti;/* interrupt stacks must be in lowmem, we get that for free on ppc32-*asthememblockislimitedtolowmembyMEMBLOCK_REAL_LIMIT*/+*asthememblockislimitedtolowmembydefault*/for_each_possible_cpu(i){softirq_ctx[i]=(structthread_info*)__va(memblock_alloc(THREAD_SIZE,THREAD_SIZE));
@@ -139,8 +141,7 @@ unsigned long __init mmu_mapin_ram(unsigned long top)*coveragewithnormal-sizedpages(orotherreasons)donot*attempttoallocateoutsidetheallowedrange.*/--__initial_memory_limit_addr=memstart_addr+mapped;+memblock_set_current_limit(memstart_addr+mapped);returnmapped;}
@@ -92,12 +92,6 @@ int __allow_ioremap_reserved;unsignedlong__max_low_memory=MAX_LOW_MEM;/*-*addressofthelimitofwhatisaccessiblewithinitialMMUsetup--*256MBusually,butonly16MBon601.-*/-phys_addr_t__initial_memory_limit_addr=(phys_addr_t)0x10000000;--/**Checkforcommand-lineoptionsthataffectwhatMMU_initwilldo.*/voidMMU_setup(void)
@@ -126,13 +120,6 @@ void __init MMU_init(void)if(ppc_md.progress)ppc_md.progress("MMU:enter",0x111);-/* 601 can only access 16MB at the moment */-if(PVR_VER(mfspr(SPRN_PVR))==1)-__initial_memory_limit_addr=0x01000000;-/* 8xx can only access 8MB at the moment */-if(PVR_VER(mfspr(SPRN_PVR))==0x50)-__initial_memory_limit_addr=0x00800000;-/* parse args from command line */MMU_setup();
@@ -190,20 +177,18 @@ void __init MMU_init(void)#ifdef CONFIG_BOOTX_TEXTbtext_unmap();#endif++/* Shortly after that, the entire linear mapping will be available */+memblock_set_current_limit(lowmem_end_addr);}/* This is only called until mem_init is done. */void__init*early_get_page(void){-void*p;--if(init_bootmem_done){-p=alloc_bootmem_pages(PAGE_SIZE);-}else{-p=__va(memblock_alloc_base(PAGE_SIZE,PAGE_SIZE,-__initial_memory_limit_addr));-}-returnp;+if(init_bootmem_done)+returnalloc_bootmem_pages(PAGE_SIZE);+else+return__va(memblock_alloc(PAGE_SIZE,PAGE_SIZE));}/* Free up now-unused memory */
@@ -399,14 +401,9 @@ u64 __init __memblock_alloc_base(u64 size, u64 align, u64 max_addr)size=memblock_align_up(size,align);-/* On some platforms, make sure we allocate lowmem */-/* Note that MEMBLOCK_REAL_LIMIT may be MEMBLOCK_ALLOC_ANYWHERE */-if(max_addr==MEMBLOCK_ALLOC_ANYWHERE)-max_addr=MEMBLOCK_REAL_LIMIT;-/* Pump up max_addr */-if(max_addr==MEMBLOCK_ALLOC_ANYWHERE)-max_addr=~(u64)0;+if(max_addr==MEMBLOCK_ALLOC_ACCESSIBLE)+max_addr=memblock.current_limit;/* We do a top-down search, this tends to limit memory*fragmentationbykeepingearlybootallocsnearthe
@@ -501,3 +498,9 @@ int memblock_is_region_reserved(u64 base, u64 size)returnmemblock_overlaps_region(&memblock.reserved,base,size);}++void__initmemblock_set_current_limit(u64limit)+{+memblock.current_limit=limit;+}+
@@ -785,8 +785,7 @@ static int find_node(unsigned long addr)return-1;}-staticunsignedlonglongnid_range(unsignedlonglongstart,-unsignedlonglongend,int*nid)+u64memblock_nid_range(u64start,u64end,int*nid){*nid=find_node(start);start+=PAGE_SIZE;
@@ -804,8 +803,7 @@ static unsigned long long nid_range(unsigned long long start,returnstart;}#else-staticunsignedlonglongnid_range(unsignedlonglongstart,-unsignedlonglongend,int*nid)+u64memblock_nid_range(u64start,u64end,int*nid){*nid=0;returnend;
@@ -46,8 +46,7 @@ extern long memblock_add(u64 base, u64 size);externlongmemblock_remove(u64base,u64size);externlong__initmemblock_free(u64base,u64size);externlong__initmemblock_reserve(u64base,u64size);-externu64__initmemblock_alloc_nid(u64size,u64align,intnid,-u64(*nid_range)(u64,u64,int*));+externu64__initmemblock_alloc_nid(u64size,u64align,intnid);externu64__initmemblock_alloc(u64size,u64align);externu64__initmemblock_alloc_base(u64size,u64,u64max_addr);
@@ -61,6 +60,10 @@ extern int memblock_is_region_reserved(u64 base, u64 size);externvoidmemblock_dump_all(void);+/* Provided by the architecture */+externu64memblock_nid_range(u64start,u64end,int*nid);++/**pfnconversionfunctions*
From: Yinghai Lu <yinghai@kernel.org> Date: 2010-07-22 18:22:36
Need to add protection in linux/memblock.h, to prepare to include it in
mm/page_alloc.c and mm/bootmem.c etc.
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
include/linux/memblock.h | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
From: Yinghai Lu <yinghai@kernel.org> Date: 2010-07-22 18:22:39
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
To constraint the search of a region between two boundaries,
which will be used by the new NUMA aware allocator among others.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
mm/memblock.c | 27 ++++++++++++++++-----------
1 files changed, 16 insertions(+), 11 deletions(-)
@@ -117,19 +117,18 @@ static phys_addr_t __init memblock_find_region(phys_addr_t start, phys_addr_t enreturnMEMBLOCK_ERROR;}-staticphys_addr_t__initmemblock_find_base(phys_addr_tsize,phys_addr_talign,phys_addr_tmax_addr)+staticphys_addr_t__initmemblock_find_base(phys_addr_tsize,phys_addr_talign,+phys_addr_tstart,phys_addr_tend){longi;-phys_addr_tbase=0;-phys_addr_tres_base;BUG_ON(0==size);size=memblock_align_up(size,align);/* Pump up max_addr */-if(max_addr==MEMBLOCK_ALLOC_ACCESSIBLE)-max_addr=memblock.current_limit;+if(end==MEMBLOCK_ALLOC_ACCESSIBLE)+end=memblock.current_limit;/* We do a top-down search, this tends to limit memory*fragmentationbykeepingearlybootallocsnearthe
@@ -204,7 +209,7 @@ static int memblock_double_array(struct memblock_type *type)new_array=kmalloc(new_size,GFP_KERNEL);addr=new_array==NULL?MEMBLOCK_ERROR:__pa(new_array);}else-addr=memblock_find_base(new_size,sizeof(phys_addr_t),MEMBLOCK_ALLOC_ACCESSIBLE);+addr=memblock_find_base(new_size,sizeof(phys_addr_t),0,MEMBLOCK_ALLOC_ACCESSIBLE);if(addr==MEMBLOCK_ERROR){pr_err("memblock: Failed to double %s array from %ld to %ld entries !\n",memblock_type_name(type),type->max,type->max*2);
From: Yinghai Lu <yinghai@kernel.org> Date: 2010-07-22 18:22:53
So those memblock bits could be released after kernel is booted up.
Arch code could define ARCH_DISCARD_MEMBLOCK in asm/memblock.h,
__init_memblock will become __init, __initdata_memblock will becom __initdata
x86 code will use that.
if ARCH_DISCARD_MEMBLOCK is defined, debugfs is not used
-v2: use ARCH_DISCARD_MEMBLOCK according to Michael Ellerman
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
include/linux/memblock.h | 8 +++++++
mm/memblock.c | 48 +++++++++++++++++++++++-----------------------
2 files changed, 32 insertions(+), 24 deletions(-)
@@ -20,12 +20,12 @@#include<linux/seq_file.h>#include<linux/memblock.h>-structmemblockmemblock;+structmemblockmemblock__initdata_memblock;-intmemblock_debug;-intmemblock_can_resize;-staticstructmemblock_regionmemblock_memory_init_regions[INIT_MEMBLOCK_REGIONS+1];-structmemblock_regionmemblock_reserved_init_regions[INIT_MEMBLOCK_REGIONS+1];+intmemblock_debug__initdata_memblock;+intmemblock_can_resize__initdata_memblock;+staticstructmemblock_regionmemblock_memory_init_regions[INIT_MEMBLOCK_REGIONS+1]__initdata_memblock;+structmemblock_regionmemblock_reserved_init_regions[INIT_MEMBLOCK_REGIONS+1]__initdata_memblock;/* inline so we don't get a warning when pr_debug is compiled out */staticinlineconstchar*memblock_type_name(structmemblock_type*type)
@@ -168,7 +168,7 @@ static void memblock_remove_region(struct memblock_type *type, unsigned long r)}/* Assumption: base addr of region 1 < base addr of region 2 */-staticvoidmemblock_coalesce_regions(structmemblock_type*type,+staticvoid__init_memblockmemblock_coalesce_regions(structmemblock_type*type,unsignedlongr1,unsignedlongr2){type->regions[r1].size+=type->regions[r2].size;
@@ -178,7 +178,7 @@ static void memblock_coalesce_regions(struct memblock_type *type,/* Defined below but needed now */staticlongmemblock_add_region(structmemblock_type*type,phys_addr_tbase,phys_addr_tsize);-staticintmemblock_double_array(structmemblock_type*type)+staticint__init_memblockmemblock_double_array(structmemblock_type*type){structmemblock_region*new_array,*old_array;phys_addr_told_size,new_size,addr;
@@ -249,13 +249,13 @@ static int memblock_double_array(struct memblock_type *type)return0;}-externint__weakmemblock_memory_can_coalesce(phys_addr_taddr1,phys_addr_tsize1,+externint__init_memblock__weakmemblock_memory_can_coalesce(phys_addr_taddr1,phys_addr_tsize1,phys_addr_taddr2,phys_addr_tsize2){return1;}-staticlongmemblock_add_region(structmemblock_type*type,phys_addr_tbase,phys_addr_tsize)+staticlong__init_memblockmemblock_add_region(structmemblock_type*type,phys_addr_tbase,phys_addr_tsize){unsignedlongcoalesced=0;longadjacent,i;
From: Yinghai Lu <yinghai@kernel.org> Date: 2010-07-22 18:22:56
it is a wrapper for memblock_find_base
make it more easy for x86 to use memblock. ( rebase )
x86 early_res is using find/reserve pattern instead of alloc.
keep it in weak version, so later We can use x86 own version if needed.
also We need it in mm/memblock.c, so one caller mm/page_alloc.c could get compiled
-v2: Change name to memblock_find_in_range() according to Michael Ellerman
-v3: Add generic weak version __memblock_find_in_range()
so keep the path for fallback to x86 version that handle from low
-v4: use 0 for failing path
-v5: use MEMBLOCK_ERROR again
-v6: remove __memblock_find_in_range()
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
include/linux/memblock.h | 2 ++
mm/memblock.c | 8 ++++++++
2 files changed, 10 insertions(+), 0 deletions(-)
@@ -351,6 +357,10 @@ u64 __init memblock_alloc_nid(u64 size, u64 align, int nid)BUG_ON(0==size);+/* We do a bottom-up search for a region with the right+*nidsincethat'seasierconsideringhowmemblock_nid_range()+*works+*/size=memblock_align_up(size,align);for(i=0;i<mem->cnt;i++){
@@ -396,33 +406,24 @@ u64 __init __memblock_alloc_base(u64 size, u64 align, u64 max_addr)if(max_addr==MEMBLOCK_ALLOC_ANYWHERE)max_addr=MEMBLOCK_REAL_LIMIT;+/* Pump up max_addr */+if(max_addr==MEMBLOCK_ALLOC_ANYWHERE)+max_addr=~(u64)0;++/* We do a top-down search, this tends to limit memory+*fragmentationbykeepingearlybootallocsnearthe+*topofmemory+*/for(i=memblock.memory.cnt-1;i>=0;i--){u64memblockbase=memblock.memory.regions[i].base;u64memblocksize=memblock.memory.regions[i].size;if(memblocksize<size)continue;-if(max_addr==MEMBLOCK_ALLOC_ANYWHERE)-base=memblock_align_down(memblockbase+memblocksize-size,align);-elseif(memblockbase<max_addr){-base=min(memblockbase+memblocksize,max_addr);-base=memblock_align_down(base-size,align);-}else-continue;--while(base&&memblockbase<=base){-j=memblock_overlaps_region(&memblock.reserved,base,size);-if(j<0){-/* this area isn't reserved, take it */-if(memblock_add_region(&memblock.reserved,base,size)<0)-return0;-returnbase;-}-res_base=memblock.reserved.regions[j].base;-if(res_base<size)-break;-base=memblock_align_down(res_base-size,align);-}+base=min(memblockbase+memblocksize,max_addr);+res_base=memblock_alloc_region(memblockbase,base,size,align);+if(res_base!=~(u64)0)+returnres_base;}return0;}
@@ -502,9 +503,3 @@ int memblock_is_region_reserved(u64 base, u64 size)returnmemblock_overlaps_region(&memblock.reserved,base,size);}-u64__weakmemblock_nid_range(u64start,u64end,int*nid)-{-*nid=0;--returnend;-}
From: Yinghai Lu <yinghai@kernel.org> Date: 2010-07-22 18:23:35
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
The RMA (RMO is a misnomer) is a concept specific to ppc64 (in fact
server ppc64 though I hijack it on embedded ppc64 for similar purposes)
and represents the area of memory that can be accessed in real mode
(aka with MMU off), or on embedded, from the exception vectors (which
is bolted in the TLB) which pretty much boils down to the same thing.
We take that out of the generic MEMBLOCK data structure and move it into
arch/powerpc where it belongs, renaming it to "RMA" while at it.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/include/asm/mmu.h | 12 ++++++++++++
arch/powerpc/kernel/head_40x.S | 6 +-----
arch/powerpc/kernel/paca.c | 2 +-
arch/powerpc/kernel/prom.c | 29 ++++++++---------------------
arch/powerpc/kernel/rtas.c | 2 +-
arch/powerpc/kernel/setup_64.c | 2 +-
arch/powerpc/mm/40x_mmu.c | 14 +++++++++++++-
arch/powerpc/mm/44x_mmu.c | 14 ++++++++++++++
arch/powerpc/mm/fsl_booke_mmu.c | 9 +++++++++
arch/powerpc/mm/hash_utils_64.c | 22 +++++++++++++++++++++-
arch/powerpc/mm/init_32.c | 14 ++++++++++++++
arch/powerpc/mm/init_64.c | 1 +
arch/powerpc/mm/ppc_mmu_32.c | 15 +++++++++++++++
arch/powerpc/mm/tlb_nohash.c | 14 ++++++++++++++
include/linux/memblock.h | 1 -
mm/memblock.c | 8 --------
16 files changed, 125 insertions(+), 40 deletions(-)
@@ -82,6 +84,16 @@ extern unsigned int __start___mmu_ftr_fixup, __stop___mmu_ftr_fixup;externvoidearly_init_mmu(void);externvoidearly_init_mmu_secondary(void);+externvoidsetup_initial_memory_limit(phys_addr_tfirst_memblock_base,+phys_addr_tfirst_memblock_size);++#ifdef CONFIG_PPC64+/* This is our real memory area size on ppc64 server, on embedded, we+*makeitmatchthesizeourofboltedTLBarea+*/+externu64ppc64_rma_size;+#endif /* CONFIG_PPC64 */+#endif /* !__ASSEMBLY__ *//* The kernel use the constants below to index in the page sizes array.
@@ -492,7 +493,7 @@ static int __init early_init_dt_scan_memory_ppc(unsigned long node,void__initearly_init_dt_add_memory_arch(u64base,u64size){-#if defined(CONFIG_PPC64)+#ifdef CONFIG_PPC64if(iommu_is_off){if(base>=0x80000000ul)return;
@@ -501,9 +502,13 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size)}#endif-memblock_add(base,size);-+/* First MEMBLOCK added, do some special initializations */+if(memstart_addr==~(phys_addr_t)0)+setup_initial_memory_limit(base,size);memstart_addr=min((u64)memstart_addr,base);++/* Add the chunk to the MEMBLOCK list */+memblock_add(base,size);}u64__initearly_init_dt_alloc_memory_arch(u64size,u64align)
@@ -655,22 +660,6 @@ static void __init phyp_dump_reserve_mem(void)staticinlinevoid__initphyp_dump_reserve_mem(void){}#endif /* CONFIG_PHYP_DUMP && CONFIG_PPC_RTAS */-staticvoidset_boot_memory_limit(void)-{-#ifdef CONFIG_PPC32-/* 601 can only access 16MB at the moment */-if(PVR_VER(mfspr(SPRN_PVR))==1)-memblock_set_current_limit(0x01000000);-/* 8xx can only access 8MB at the moment */-elseif(PVR_VER(mfspr(SPRN_PVR))==0x50)-memblock_set_current_limit(0x00800000);-else-memblock_set_current_limit(0x10000000);-#else-memblock_set_current_limit(memblock.rmo_size);-#endif-}-void__initearly_init_devtree(void*params){phys_addr_tlimit;
@@ -734,8 +723,6 @@ void __init early_init_devtree(void *params)DBG("Phys. mem: %llx\n",memblock_phys_mem_size());-set_boot_memory_limit();-/* We may need to relocate the flat tree, do it now.*FIXME..andtheinitrdtoo?*/move_device_tree();
@@ -141,7 +141,19 @@ unsigned long __init mmu_mapin_ram(unsigned long top)*coveragewithnormal-sizedpages(orotherreasons)donot*attempttoallocateoutsidetheallowedrange.*/-memblock_set_current_limit(memstart_addr+mapped);+memblock_set_current_limit(mapped);returnmapped;}++voidsetup_initial_memory_limit(phys_addr_tfirst_memblock_base,+phys_addr_tfirst_memblock_size)+{+/* We don't currently support the first MEMBLOCK not mapping 0+*physicalonthoseprocessors+*/+BUG_ON(first_memblock_base!=0);++/* 40x can only access 16MB at the moment (see head_40x.S) */+memblock_set_current_limit(min_t(u64,first_memblock_size,0x00800000));+}
@@ -213,6 +215,18 @@ unsigned long __init mmu_mapin_ram(unsigned long top)returntotal_lowmem;}+voidsetup_initial_memory_limit(phys_addr_tfirst_memblock_base,+phys_addr_tfirst_memblock_size)+{+/* We don't currently support the first MEMBLOCK not mapping 0+*physicalonthoseprocessors+*/+BUG_ON(first_memblock_base!=0);++/* 44x has a 256M TLB entry pinned at boot */+memblock_set_current_limit(min_t(u64,first_memblock_size,PPC_PIN_SIZE));+}+#ifdef CONFIG_SMPvoid__cpuinitmmu_init_secondary(intcpu){
@@ -1221,3 +1221,23 @@ void kernel_map_pages(struct page *page, int numpages, int enable)local_irq_restore(flags);}#endif /* CONFIG_DEBUG_PAGEALLOC */++voidsetup_initial_memory_limit(phys_addr_tfirst_memblock_base,+phys_addr_tfirst_memblock_size)+{+/* We don't currently support the first MEMBLOCK not mapping 0+*physicalonthoseprocessors+*/+BUG_ON(first_memblock_base!=0);++/* On LPAR systems, the first entry is our RMA region,+*non-LPAR64-bithashMMUsystemsdon'thavealimitation+*onrealmodeaccess,butusingthefirstentryworkswell+*enough.Wealsoclampitto1Gtoavoidsomefunkythings+*suchasRTASbugsetc...+*/+ppc64_rma_size=min_t(u64,first_memblock_size,0x40000000);++/* Finally limit subsequent allocations */+memblock_set_current_limit(ppc64_rma_size);+}
@@ -237,3 +237,17 @@ void free_initrd_mem(unsigned long start, unsigned long end)}#endif++#ifdef CONFIG_8xx /* No 8xx specific .c file to put that in ... */+voidsetup_initial_memory_limit(phys_addr_tfirst_memblock_base,+phys_addr_tfirst_memblock_size)+{+/* We don't currently support the first MEMBLOCK not mapping 0+*physicalonthoseprocessors+*/+BUG_ON(first_memblock_base!=0);++/* 8xx can only access 8MB at the moment */+memblock_set_current_limit(min_t(u64,first_memblock_size,0x00800000));+}+#endif /* CONFIG_8xx */
@@ -271,3 +271,18 @@ void __init MMU_init_hw(void)if(ppc_md.progress)ppc_md.progress("hash:done",0x205);}++voidsetup_initial_memory_limit(phys_addr_tfirst_memblock_base,+phys_addr_tfirst_memblock_size)+{+/* We don't currently support the first MEMBLOCK not mapping 0+*physicalonthoseprocessors+*/+BUG_ON(first_memblock_base!=0);++/* 601 can only access 16MB at the moment */+if(PVR_VER(mfspr(SPRN_PVR))==1)+memblock_set_current_limit(min_t(u64,first_memblock_size,0x01000000));+else/* Anything else has 256M mapped */+memblock_set_current_limit(min_t(u64,first_memblock_size,0x10000000));+}
@@ -195,10 +194,6 @@ static long memblock_add_region(struct memblock_type *type, u64 base, u64 size)longmemblock_add(u64base,u64size){-/* On pSeries LPAR systems, the first MEMBLOCK is our RMO region. */-if(base==0)-memblock.rmo_size=size;-returnmemblock_add_region(&memblock.memory,base,size);}
@@ -459,9 +454,6 @@ void __init memblock_enforce_memory_limit(u64 memory_limit)break;}-if(memblock.memory.regions[0].size<memblock.rmo_size)-memblock.rmo_size=memblock.memory.regions[0].size;-memory_limit=memblock_end_of_DRAM();/* And truncate any reserves above the limit also. */
@@ -77,8 +77,8 @@ void __init setup_memory(void)/* Find main memory where is the kernel */for(i=0;i<memblock.memory.cnt;i++){-memory_start=(u32)memblock.memory.region[i].base;-memory_end=(u32)memblock.memory.region[i].base+memory_start=(u32)memblock.memory.regions[i].base;+memory_end=(u32)memblock.memory.regions[i].base+(u32)memblock.memory.region[i].size;if((memory_start<=(u32)_text)&&((u32)_text<=memory_end)){
@@ -660,7 +660,7 @@ static void __init htab_initialize(void)/* create bolted the linear mapping in the hash table */for(i=0;i<memblock.memory.cnt;i++){-base=(unsignedlong)__va(memblock.memory.region[i].base);+base=(unsignedlong)__va(memblock.memory.regions[i].base);size=memblock.memory.region[i].size;DBG("creating mapping for region: %lx..%lx (prot: %lx)\n",
@@ -86,10 +86,10 @@ int page_is_ram(unsigned long pfn)for(i=0;i<memblock.memory.cnt;i++){unsignedlongbase;-base=memblock.memory.region[i].base;+base=memblock.memory.regions[i].base;if((paddr>=base)&&-(paddr<(base+memblock.memory.region[i].size))){+(paddr<(base+memblock.memory.regions[i].size))){return1;}}
@@ -206,7 +206,7 @@ void __init do_init_bootmem(void)/* Add active regions with valid PFNs */for(i=0;i<memblock.memory.cnt;i++){unsignedlongstart_pfn,end_pfn;-start_pfn=memblock.memory.region[i].base>>PAGE_SHIFT;+start_pfn=memblock.memory.regions[i].base>>PAGE_SHIFT;end_pfn=start_pfn+memblock_size_pages(&memblock.memory,i);add_active_range(0,start_pfn,end_pfn);}
@@ -219,16 +219,16 @@ void __init do_init_bootmem(void)/* reserve the sections we're already using */for(i=0;i<memblock.reserved.cnt;i++){-unsignedlongaddr=memblock.reserved.region[i].base++unsignedlongaddr=memblock.reserved.regions[i].base+memblock_size_bytes(&memblock.reserved,i)-1;if(addr<lowmem_end_addr)-reserve_bootmem(memblock.reserved.region[i].base,+reserve_bootmem(memblock.reserved.regions[i].base,memblock_size_bytes(&memblock.reserved,i),BOOTMEM_DEFAULT);-elseif(memblock.reserved.region[i].base<lowmem_end_addr){+elseif(memblock.reserved.regions[i].base<lowmem_end_addr){unsignedlongadjusted_size=lowmem_end_addr--memblock.reserved.region[i].base;-reserve_bootmem(memblock.reserved.region[i].base,+memblock.reserved.regions[i].base;+reserve_bootmem(memblock.reserved.regions[i].base,adjusted_size,BOOTMEM_DEFAULT);}}
@@ -237,7 +237,7 @@ void __init do_init_bootmem(void)/* reserve the sections we're already using */for(i=0;i<memblock.reserved.cnt;i++)-reserve_bootmem(memblock.reserved.region[i].base,+reserve_bootmem(memblock.reserved.regions[i].base,memblock_size_bytes(&memblock.reserved,i),BOOTMEM_DEFAULT);
@@ -257,10 +257,10 @@ static int __init mark_nonram_nosave(void)for(i=0;i<memblock.memory.cnt-1;i++){memblock_region_max_pfn=-(memblock.memory.region[i].base>>PAGE_SHIFT)+-(memblock.memory.region[i].size>>PAGE_SHIFT);+(memblock.memory.regions[i].base>>PAGE_SHIFT)++(memblock.memory.regions[i].size>>PAGE_SHIFT);memblock_next_region_start_pfn=-memblock.memory.region[i+1].base>>PAGE_SHIFT;+memblock.memory.regions[i+1].base>>PAGE_SHIFT;if(memblock_region_max_pfn<memblock_next_region_start_pfn)register_nosave_region(memblock_region_max_pfn,
@@ -65,7 +65,7 @@ static int __init page_aligned(unsigned long x)void__initwii_memory_fixups(void){-structmemblock_property*p=memblock.memory.region;+structmemblock_region*p=memblock.memory.region;/**Thisispartofaworkaroundtoallowtheuseoftwo
@@ -74,34 +74,34 @@ static long memblock_addrs_adjacent(u64 base1, u64 size1, u64 base2, u64 size2)return0;}-staticlongmemblock_regions_adjacent(structmemblock_region*rgn,+staticlongmemblock_regions_adjacent(structmemblock_type*type,unsignedlongr1,unsignedlongr2){-u64base1=rgn->region[r1].base;-u64size1=rgn->region[r1].size;-u64base2=rgn->region[r2].base;-u64size2=rgn->region[r2].size;+u64base1=type->regions[r1].base;+u64size1=type->regions[r1].size;+u64base2=type->regions[r2].base;+u64size2=type->regions[r2].size;returnmemblock_addrs_adjacent(base1,size1,base2,size2);}-staticvoidmemblock_remove_region(structmemblock_region*rgn,unsignedlongr)+staticvoidmemblock_remove_region(structmemblock_type*type,unsignedlongr){unsignedlongi;-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;+for(i=r;i<type->cnt-1;i++){+type->regions[i].base=type->regions[i+1].base;+type->regions[i].size=type->regions[i+1].size;}-rgn->cnt--;+type->cnt--;}/* Assumption: base addr of region 1 < base addr of region 2 */-staticvoidmemblock_coalesce_regions(structmemblock_region*rgn,+staticvoidmemblock_coalesce_regions(structmemblock_type*type,unsignedlongr1,unsignedlongr2){-rgn->region[r1].size+=rgn->region[r2].size;-memblock_remove_region(rgn,r2);+type->regions[r1].size+=type->regions[r2].size;+memblock_remove_region(type,r2);}void__initmemblock_init(void)
@@ -109,13 +109,13 @@ void __init memblock_init(void)/* Create a dummy zero size MEMBLOCK which will get coalesced away later.*Thissimplifiesthememblock_add()codebelow...*/-memblock.memory.region[0].base=0;-memblock.memory.region[0].size=0;+memblock.memory.regions[0].base=0;+memblock.memory.regions[0].size=0;memblock.memory.cnt=1;/* Ditto. */-memblock.reserved.region[0].base=0;-memblock.reserved.region[0].size=0;+memblock.reserved.regions[0].base=0;+memblock.reserved.regions[0].size=0;memblock.reserved.cnt=1;}
@@ -126,24 +126,24 @@ void __init memblock_analyze(void)memblock.memory.size=0;for(i=0;i<memblock.memory.cnt;i++)-memblock.memory.size+=memblock.memory.region[i].size;+memblock.memory.size+=memblock.memory.regions[i].size;}-staticlongmemblock_add_region(structmemblock_region*rgn,u64base,u64size)+staticlongmemblock_add_region(structmemblock_type*type,u64base,u64size){unsignedlongcoalesced=0;longadjacent,i;-if((rgn->cnt==1)&&(rgn->region[0].size==0)){-rgn->region[0].base=base;-rgn->region[0].size=size;+if((type->cnt==1)&&(type->regions[0].size==0)){+type->regions[0].base=base;+type->regions[0].size=size;return0;}/* First try and coalesce this MEMBLOCK with another. */-for(i=0;i<rgn->cnt;i++){-u64rgnbase=rgn->region[i].base;-u64rgnsize=rgn->region[i].size;+for(i=0;i<type->cnt;i++){+u64rgnbase=type->regions[i].base;+u64rgnsize=type->regions[i].size;if((rgnbase==base)&&(rgnsize==size))/* Already have this region, so we're done */
@@ -151,61 +151,59 @@ static long memblock_add_region(struct memblock_region *rgn, u64 base, u64 size)adjacent=memblock_addrs_adjacent(base,size,rgnbase,rgnsize);if(adjacent>0){-rgn->region[i].base-=size;-rgn->region[i].size+=size;+type->regions[i].base-=size;+type->regions[i].size+=size;coalesced++;break;}elseif(adjacent<0){-rgn->region[i].size+=size;+type->regions[i].size+=size;coalesced++;break;}}-if((i<rgn->cnt-1)&&memblock_regions_adjacent(rgn,i,i+1)){-memblock_coalesce_regions(rgn,i,i+1);+if((i<type->cnt-1)&&memblock_regions_adjacent(type,i,i+1)){+memblock_coalesce_regions(type,i,i+1);coalesced++;}if(coalesced)returncoalesced;-if(rgn->cnt>=MAX_MEMBLOCK_REGIONS)+if(type->cnt>=MAX_MEMBLOCK_REGIONS)return-1;/* Couldn't coalesce the MEMBLOCK, 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;+for(i=type->cnt-1;i>=0;i--){+if(base<type->regions[i].base){+type->regions[i+1].base=type->regions[i].base;+type->regions[i+1].size=type->regions[i].size;}else{-rgn->region[i+1].base=base;-rgn->region[i+1].size=size;+type->regions[i+1].base=base;+type->regions[i+1].size=size;break;}}-if(base<rgn->region[0].base){-rgn->region[0].base=base;-rgn->region[0].size=size;+if(base<type->regions[0].base){+type->regions[0].base=base;+type->regions[0].size=size;}-rgn->cnt++;+type->cnt++;return0;}longmemblock_add(u64base,u64size){-structmemblock_region*_rgn=&memblock.memory;-/* On pSeries LPAR systems, the first MEMBLOCK is our RMO region. */if(base==0)memblock.rmo_size=size;-returnmemblock_add_region(_rgn,base,size);+returnmemblock_add_region(&memblock.memory,base,size);}-staticlong__memblock_remove(structmemblock_region*rgn,u64base,u64size)+staticlong__memblock_remove(structmemblock_type*type,u64base,u64size){u64rgnbegin,rgnend;u64end=base+size;
@@ -214,34 +212,34 @@ static long __memblock_remove(struct memblock_region *rgn, u64 base, u64 size)rgnbegin=rgnend=0;/* supress gcc warnings *//* Find the region where (base, size) belongs to */-for(i=0;i<rgn->cnt;i++){-rgnbegin=rgn->region[i].base;-rgnend=rgnbegin+rgn->region[i].size;+for(i=0;i<type->cnt;i++){+rgnbegin=type->regions[i].base;+rgnend=rgnbegin+type->regions[i].size;if((rgnbegin<=base)&&(end<=rgnend))break;}/* Didn't find the region */-if(i==rgn->cnt)+if(i==type->cnt)return-1;/* Check to see if we are removing entire region */if((rgnbegin==base)&&(rgnend==end)){-memblock_remove_region(rgn,i);+memblock_remove_region(type,i);return0;}/* Check to see if region is matching at the front */if(rgnbegin==base){-rgn->region[i].base=end;-rgn->region[i].size-=size;+type->regions[i].base=end;+type->regions[i].size-=size;return0;}/* Check to see if the region is matching at the end */if(rgnend==end){-rgn->region[i].size-=size;+type->regions[i].size-=size;return0;}
@@ -442,7 +440,7 @@ u64 memblock_end_of_DRAM(void){intidx=memblock.memory.cnt-1;-return(memblock.memory.region[idx].base+memblock.memory.region[idx].size);+return(memblock.memory.regions[idx].base+memblock.memory.regions[idx].size);}/* You must call memblock_analyze() after this. */
@@ -458,24 +456,24 @@ void __init memblock_enforce_memory_limit(u64 memory_limit)/* Truncate the memblock regions to satisfy the memory limit. */limit=memory_limit;for(i=0;i<memblock.memory.cnt;i++){-if(limit>memblock.memory.region[i].size){-limit-=memblock.memory.region[i].size;+if(limit>memblock.memory.regions[i].size){+limit-=memblock.memory.regions[i].size;continue;}-memblock.memory.region[i].size=limit;+memblock.memory.regions[i].size=limit;memblock.memory.cnt=i+1;break;}-if(memblock.memory.region[0].size<memblock.rmo_size)-memblock.rmo_size=memblock.memory.region[0].size;+if(memblock.memory.regions[0].size<memblock.rmo_size)+memblock.rmo_size=memblock.memory.regions[0].size;memory_limit=memblock_end_of_DRAM();/* And truncate any reserves above the limit also. */for(i=0;i<memblock.reserved.cnt;i++){-p=&memblock.reserved.region[i];+p=&memblock.reserved.regions[i];if(p->base>memory_limit)p->size=0;
@@ -494,9 +492,9 @@ int __init memblock_is_reserved(u64 addr)inti;for(i=0;i<memblock.reserved.cnt;i++){-u64upper=memblock.reserved.region[i].base+-memblock.reserved.region[i].size-1;-if((addr>=memblock.reserved.region[i].base)&&(addr<=upper))+u64upper=memblock.reserved.regions[i].base++memblock.reserved.regions[i].size-1;+if((addr>=memblock.reserved.regions[i].base)&&(addr<=upper))return1;}return0;
@@ -511,7 +509,7 @@ int memblock_is_region_reserved(u64 base, u64 size)*Givena<base,len>,findwhichmemoryregionsbelongtothisrange.*Adjusttherequestandreturnacontiguouschunk.*/-intmemblock_find(structmemblock_property*res)+intmemblock_find(structmemblock_region*res){inti;u64rstart,rend;
@@ -520,8 +518,8 @@ int memblock_find(struct memblock_property *res)rend=rstart+res->size-1;for(i=0;i<memblock.memory.cnt;i++){-u64start=memblock.memory.region[i].base;-u64end=start+memblock.memory.region[i].size-1;+u64start=memblock.memory.regions[i].base;+u64end=start+memblock.memory.regions[i].size-1;if(start>rend)return-1;
From: Yinghai Lu <yinghai@kernel.org> Date: 2010-07-22 18:24:13
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Since we allocate one more than needed, why not do a bit of sanity checking
here to ensure we don't walk past the end of the array ?
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
mm/memblock.c | 11 +++++++++++
1 files changed, 11 insertions(+), 0 deletions(-)
@@ -112,6 +113,10 @@ void __init memblock_init(void)memblock.reserved.regions=memblock_reserved_init_regions;memblock.reserved.max=INIT_MEMBLOCK_REGIONS;+/* Write a marker in the unused last array entry */+memblock.memory.regions[INIT_MEMBLOCK_REGIONS].base=(phys_addr_t)RED_INACTIVE;+memblock.reserved.regions[INIT_MEMBLOCK_REGIONS].base=(phys_addr_t)RED_INACTIVE;+/* Create a dummy zero size MEMBLOCK which will get coalesced away later.*Thissimplifiesthememblock_add()codebelow...*/
@@ -131,6 +136,12 @@ void __init memblock_analyze(void){inti;+/* Check marker in the unused last array entry */+WARN_ON(memblock_memory_init_regions[INIT_MEMBLOCK_REGIONS].base+!=(phys_addr_t)RED_INACTIVE);+WARN_ON(memblock_reserved_init_regions[INIT_MEMBLOCK_REGIONS].base+!=(phys_addr_t)RED_INACTIVE);+memblock.memory_size=0;for(i=0;i<memblock.memory.cnt;i++)
From: Yinghai Lu <yinghai@kernel.org> Date: 2010-07-22 18:24:27
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
When one of the array gets full, we resize it. After much thinking and
a few iterations of that code, I went back to on-demand resizing using
the (new) internal memblock_find_base() function, which is pretty much what
Yinghai initially proposed, though there some differences in the details.
To work this relies on the default alloc limit being set sensibly by
the architecture.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
mm/memblock.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 102 insertions(+), 2 deletions(-)
@@ -18,12 +19,23 @@structmemblockmemblock;-staticintmemblock_debug;+staticintmemblock_debug,memblock_can_resize;staticstructmemblock_regionmemblock_memory_init_regions[INIT_MEMBLOCK_REGIONS+1];staticstructmemblock_regionmemblock_reserved_init_regions[INIT_MEMBLOCK_REGIONS+1];#define MEMBLOCK_ERROR (~(phys_addr_t)0)+/* inline so we don't get a warning when pr_debug is compiled out */+staticinlineconstchar*memblock_type_name(structmemblock_type*type)+{+if(type==&memblock.memory)+return"memory";+elseif(type==&memblock.reserved)+return"reserved";+else+return"unknown";+}+/**Addresscomparisonutilities*/
@@ -156,6 +168,79 @@ static void memblock_coalesce_regions(struct memblock_type *type,memblock_remove_region(type,r2);}+/* Defined below but needed now */+staticlongmemblock_add_region(structmemblock_type*type,phys_addr_tbase,phys_addr_tsize);++staticintmemblock_double_array(structmemblock_type*type)+{+structmemblock_region*new_array,*old_array;+phys_addr_told_size,new_size,addr;+intuse_slab=slab_is_available();++/* We don't allow resizing until we know about the reserved regions+*ofmemorythataren'tsuitableforallocation+*/+if(!memblock_can_resize)+return-1;++pr_debug("memblock: %s array full, doubling...",memblock_type_name(type));++/* Calculate new doubled size */+old_size=type->max*sizeof(structmemblock_region);+new_size=old_size<<1;++/* Try to find some space for it.+*+*WARNING:Weassumethateitherslab_is_available()andweuseitor+*weuseMEMBLOCKforallocations.Thatmeansthatthisisunsafetouse+*whenbootmemiscurrentlyactive(unlessbootmemitselfisimplemented+*ontopofMEMBLOCKwhichisn'tthecaseyet)+*+*Thisshouldhowevernotbeanissuefornow,aswecurrentlyonly+*callintoMEMBLOCKwhileit'sstillactive,ormuchlaterwhenslabis+*activeformemoryhotplugoperations+*/+if(use_slab){+new_array=kmalloc(new_size,GFP_KERNEL);+addr=new_array==NULL?MEMBLOCK_ERROR:__pa(new_array);+}else+addr=memblock_find_base(new_size,sizeof(phys_addr_t),MEMBLOCK_ALLOC_ACCESSIBLE);+if(addr==MEMBLOCK_ERROR){+pr_err("memblock: Failed to double %s array from %ld to %ld entries !\n",+memblock_type_name(type),type->max,type->max*2);+return-1;+}+new_array=__va(addr);++/* Found space, we now need to move the array over before+*weaddthereservedregionsinceitmaybeourreserved+*arrayitselfthatisfull.+*/+memcpy(new_array,type->regions,old_size);+memset(new_array+type->max,0,old_size);+old_array=type->regions;+type->regions=new_array;+type->max<<=1;++/* If we use SLAB that's it, we are done */+if(use_slab)+return0;++/* Add the new reserved region now. Should not fail ! */+BUG_ON(memblock_add_region(&memblock.reserved,addr,new_size)<0);++/* If the array wasn't our static init one, then free it. We only do+*thatbeforeSLABisavailableaslateron,wedon'tknowwhether+*tousekfreeorfree_bootmem_pages().Shouldn'tbeabigdeal+*anyways+*/+if(old_array!=memblock_memory_init_regions&&+old_array!=memblock_reserved_init_regions)+memblock_free(__pa(old_array),old_size);++return0;+}+staticlongmemblock_add_region(structmemblock_type*type,phys_addr_tbase,phys_addr_tsize){unsignedlongcoalesced=0;
@@ -196,7 +281,11 @@ static long memblock_add_region(struct memblock_type *type, phys_addr_t base, phif(coalesced)returncoalesced;-if(type->cnt>=type->max)++/* If we are out of space, we fail. It's too late to resize the array+*butthenthisshouldn'thavehappenedinthefirstplace.+*/+if(WARN_ON(type->cnt>=type->max))return-1;/* Couldn't coalesce the MEMBLOCK, so add it to the sorted table. */
@@ -217,6 +306,14 @@ static long memblock_add_region(struct memblock_type *type, phys_addr_t base, ph}type->cnt++;+/* The array is full ? Try to resize it. If that fails, we undo+*ourallocationandreturnanerror+*/+if(type->cnt==type->max&&memblock_double_array(type)){+type->cnt--;+return-1;+}+return0;}
@@ -515,6 +612,9 @@ void __init memblock_analyze(void)for(i=0;i<memblock.memory.cnt;i++)memblock.memory_size+=memblock.memory.regions[i].size;++/* We allow resizing from there */+memblock_can_resize=1;}void__initmemblock_init(void)
From: Yinghai Lu <yinghai@kernel.org> Date: 2010-07-22 18:24:39
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
This function will be used to locate a free area to put the new memblock
arrays when attempting to resize them. memblock_alloc_region() is gone,
the two callsites now call memblock_add_region().
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
mm/memblock.c | 20 +++++++++-----------
1 files changed, 9 insertions(+), 11 deletions(-)
@@ -318,12 +318,8 @@ static phys_addr_t __init memblock_alloc_region(phys_addr_t start, phys_addr_t ebase=memblock_align_down((end-size),align);while(start<=base){j=memblock_overlaps_region(&memblock.reserved,base,size);-if(j<0){-/* this area isn't reserved, take it */-if(memblock_add_region(&memblock.reserved,base,size)<0)-base=~(phys_addr_t)0;+if(j<0)returnbase;-}res_base=memblock.reserved.regions[j].base;if(res_base<size)break;
From: Yinghai Lu <yinghai@kernel.org> Date: 2010-07-22 18:24:50
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
The former is now strict, it will fail if it cannot honor the allocation
within the node, while the later implements the previous semantic which
falls back to allocating anywhere.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/sparc/mm/init_64.c | 4 ++--
include/linux/memblock.h | 6 +++++-
mm/memblock.c | 14 ++++++++++++++
3 files changed, 21 insertions(+), 3 deletions(-)
@@ -50,7 +50,11 @@ extern long __init memblock_reserve(phys_addr_t base, phys_addr_t size);/* The numa aware allocator is only available if*CONFIG_ARCH_POPULATES_NODE_MAPisset*/-externphys_addr_t__initmemblock_alloc_nid(phys_addr_tsize,phys_addr_talign,intnid);+externphys_addr_t__initmemblock_alloc_nid(phys_addr_tsize,phys_addr_talign,+intnid);+externphys_addr_t__initmemblock_alloc_try_nid(phys_addr_tsize,phys_addr_talign,+intnid);+externphys_addr_t__initmemblock_alloc(phys_addr_tsize,phys_addr_talign);/* Flags for memblock_alloc_base() amd __memblock_alloc_base() */
@@ -537,9 +537,23 @@ phys_addr_t __init memblock_alloc_nid(phys_addr_t size, phys_addr_t align, int nreturnret;}+return0;+}++phys_addr_t__initmemblock_alloc_try_nid(phys_addr_tsize,phys_addr_talign,intnid)+{+phys_addr_tres=memblock_alloc_nid(size,align,nid);++if(res)+returnres;returnmemblock_alloc(size,align);}++/*+*RemainingAPIfunctions+*/+/* You must call memblock_analyze() before this. */phys_addr_t__initmemblock_phys_mem_size(void){
From: Yinghai Lu <yinghai@kernel.org> Date: 2010-07-22 18:25:00
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Walk memblock's using for_each_memblock() and use memblock_region_base/end_pfn() for
getting to PFNs. Update sparc, powerpc, microblaze and sh.
Note: This is -almost- a direct conversion. It doesn't fix some existing
crap when/if memblock's aren't page aligned in the first place. This will be
sorted out separately.
This removes memblock_find() as well, which isn't used anymore
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/microblaze/mm/init.c | 18 +++----
arch/powerpc/mm/hash_utils_64.c | 8 ++--
arch/powerpc/mm/mem.c | 92 ++++++++++++++-------------------------
arch/powerpc/mm/numa.c | 17 ++++---
arch/sh/mm/init.c | 16 ++++---
arch/sparc/mm/init_64.c | 30 +++++--------
include/linux/memblock.h | 56 ++++++++++++++++++------
mm/memblock.c | 32 -------------
8 files changed, 117 insertions(+), 152 deletions(-)
@@ -70,16 +70,16 @@ static void __init paging_init(void)void__initsetup_memory(void){-inti;unsignedlongmap_size;+structmemblock_region*reg;+#ifndef CONFIG_MMUu32kernel_align_start,kernel_align_size;/* Find main memory where is the kernel */-for(i=0;i<memblock.memory.cnt;i++){-memory_start=(u32)memblock.memory.regions[i].base;-memory_end=(u32)memblock.memory.regions[i].base-+(u32)memblock.memory.region[i].size;+for_each_memblock(memory,reg){+memory_start=(u32)reg->base;+memory_end=(u32)reg->base+reg->size;if((memory_start<=(u32)_text)&&((u32)_text<=memory_end)){memory_size=memory_end-memory_start;
@@ -659,9 +659,9 @@ static void __init htab_initialize(void)*//* create bolted the linear mapping in the hash table */-for(i=0;i<memblock.memory.cnt;i++){-base=(unsignedlong)__va(memblock.memory.regions[i].base);-size=memblock.memory.region[i].size;+for_each_memblock(memory,reg){+base=(unsignedlong)__va(reg->base);+size=reg->size;DBG("creating mapping for region: %lx..%lx (prot: %lx)\n",base,size,prot);
@@ -82,18 +82,11 @@ int page_is_ram(unsigned long pfn)returnpfn<max_pfn;#elseunsignedlongpaddr=(pfn<<PAGE_SHIFT);-inti;-for(i=0;i<memblock.memory.cnt;i++){-unsignedlongbase;+structmemblock_region*reg;-base=memblock.memory.regions[i].base;--if((paddr>=base)&&-(paddr<(base+memblock.memory.regions[i].size))){+for_each_memblock(memory,reg)+if(paddr>=reg->base&&paddr<(reg->base+reg->size))return1;-}-}-return0;#endif}
@@ -204,10 +193,10 @@ void __init do_init_bootmem(void)boot_mapsize=init_bootmem_node(NODE_DATA(0),start>>PAGE_SHIFT,min_low_pfn,max_low_pfn);/* Add active regions with valid PFNs */-for(i=0;i<memblock.memory.cnt;i++){+for_each_memblock(memory,reg){unsignedlongstart_pfn,end_pfn;-start_pfn=memblock.memory.regions[i].base>>PAGE_SHIFT;-end_pfn=start_pfn+memblock_size_pages(&memblock.memory,i);+start_pfn=memblock_region_base_pfn(reg);+end_pfn=memblock_region_end_pfn(reg);add_active_range(0,start_pfn,end_pfn);}
@@ -218,29 +207,21 @@ void __init do_init_bootmem(void)free_bootmem_with_active_regions(0,lowmem_end_addr>>PAGE_SHIFT);/* reserve the sections we're already using */-for(i=0;i<memblock.reserved.cnt;i++){-unsignedlongaddr=memblock.reserved.regions[i].base+-memblock_size_bytes(&memblock.reserved,i)-1;-if(addr<lowmem_end_addr)-reserve_bootmem(memblock.reserved.regions[i].base,-memblock_size_bytes(&memblock.reserved,i),-BOOTMEM_DEFAULT);-elseif(memblock.reserved.regions[i].base<lowmem_end_addr){-unsignedlongadjusted_size=lowmem_end_addr--memblock.reserved.regions[i].base;-reserve_bootmem(memblock.reserved.regions[i].base,-adjusted_size,BOOTMEM_DEFAULT);+for_each_memblock(reserved,reg){+unsignedlongtop=reg->base+reg->size-1;+if(top<lowmem_end_addr)+reserve_bootmem(reg->base,reg->size,BOOTMEM_DEFAULT);+elseif(reg->base<lowmem_end_addr){+unsignedlongtrunc_size=lowmem_end_addr-reg->base;+reserve_bootmem(reg->base,trunc_size,BOOTMEM_DEFAULT);}}#elsefree_bootmem_with_active_regions(0,max_pfn);/* reserve the sections we're already using */-for(i=0;i<memblock.reserved.cnt;i++)-reserve_bootmem(memblock.reserved.regions[i].base,-memblock_size_bytes(&memblock.reserved,i),-BOOTMEM_DEFAULT);-+for_each_memblock(reserved,reg)+reserve_bootmem(reg->base,reg->size,BOOTMEM_DEFAULT);#endif/* XXX need to clip this if using highmem? */sparse_memory_present_with_active_regions(0);
@@ -251,22 +232,15 @@ void __init do_init_bootmem(void)/* mark pages that don't exist as nosave */staticint__initmark_nonram_nosave(void){-unsignedlongmemblock_next_region_start_pfn,-memblock_region_max_pfn;-inti;--for(i=0;i<memblock.memory.cnt-1;i++){-memblock_region_max_pfn=-(memblock.memory.regions[i].base>>PAGE_SHIFT)+-(memblock.memory.regions[i].size>>PAGE_SHIFT);-memblock_next_region_start_pfn=-memblock.memory.regions[i+1].base>>PAGE_SHIFT;--if(memblock_region_max_pfn<memblock_next_region_start_pfn)-register_nosave_region(memblock_region_max_pfn,-memblock_next_region_start_pfn);+structmemblock_region*reg,*prev=NULL;++for_each_memblock(memory,reg){+if(prev&&+memblock_region_end_pfn(prev)<memblock_region_base_pfn(reg))+register_nosave_region(memblock_region_end_pfn(prev),+memblock_region_base_pfn(reg));+prev=reg;}-return0;}
@@ -226,11 +226,12 @@ static void __init bootmem_init_one_node(unsigned int nid)*reservationsinothernodes.*/if(nid==0){+structmemblock_region*reg;+/* Reserve the sections we're already using. */-for(i=0;i<memblock.reserved.cnt;i++)-reserve_bootmem(memblock.reserved.region[i].base,-memblock_size_bytes(&memblock.reserved,i),-BOOTMEM_DEFAULT);+for_each_memblock(reserved,reg){+reserve_bootmem(reg->base,reg->size,BOOTMEM_DEFAULT);+}}sparse_memory_present_with_active_regions(nid);
@@ -238,13 +239,14 @@ static void __init bootmem_init_one_node(unsigned int nid)staticvoid__initdo_init_bootmem(void){+structmemblock_region*reg;inti;/* Add active regions with valid PFNs. */-for(i=0;i<memblock.memory.cnt;i++){+for_each_memblock(memory,reg){unsignedlongstart_pfn,end_pfn;-start_pfn=memblock.memory.region[i].base>>PAGE_SHIFT;-end_pfn=start_pfn+memblock_size_pages(&memblock.memory,i);+start_pfn=memblock_region_base_pfn(reg);+end_pfn=memblock_region_end_pfn(reg);__add_active_range(0,start_pfn,end_pfn);}
From: Yinghai Lu <yinghai@kernel.org> Date: 2010-07-22 18:25:53
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
memblock_alloc_nid() used to fallback to allocating anywhere by using
memblock_alloc() as a fallback.
However, some of my previous patches limit memblock_alloc() to the region
covered by MEMBLOCK_ALLOC_ACCESSIBLE which is not quite what we want
for memblock_alloc_try_nid().
So we fix it by explicitely using MEMBLOCK_ALLOC_ANYWHERE.
Not that so far only sparc uses memblock_alloc_nid() and it hasn't been updated
to clamp the accessible zone yet. Thus the temporary "breakage" should have
no effect.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
mm/memblock.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
From: Yinghai Lu <yinghai@kernel.org> Date: 2010-07-22 18:26:10
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Some archs such as ARM want to avoid coalescing accross things such
as the lowmem/highmem boundary or similar. This provides the option
to control it via an arch callback for which a weak default is provided
which always allows coalescing.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
include/linux/memblock.h | 2 ++
mm/memblock.c | 19 ++++++++++++++++++-
2 files changed, 20 insertions(+), 1 deletions(-)
@@ -241,6 +241,12 @@ static int memblock_double_array(struct memblock_type *type)return0;}+externint__weakmemblock_memory_can_coalesce(phys_addr_taddr1,phys_addr_tsize1,+phys_addr_taddr2,phys_addr_tsize2)+{+return1;+}+staticlongmemblock_add_region(structmemblock_type*type,phys_addr_tbase,phys_addr_tsize){unsignedlongcoalesced=0;
@@ -262,6 +268,10 @@ static long memblock_add_region(struct memblock_type *type, phys_addr_t base, phreturn0;adjacent=memblock_addrs_adjacent(base,size,rgnbase,rgnsize);+/* Check if arch allows coalescing */+if(adjacent!=0&&type==&memblock.memory&&+!memblock_memory_can_coalesce(base,size,rgnbase,rgnsize))+break;if(adjacent>0){type->regions[i].base-=size;type->regions[i].size+=size;
@@ -274,7 +284,14 @@ static long memblock_add_region(struct memblock_type *type, phys_addr_t base, ph}}-if((i<type->cnt-1)&&memblock_regions_adjacent(type,i,i+1)){+/* If we plugged a hole, we may want to also coalesce with the+*nextregion+*/+if((i<type->cnt-1)&&memblock_regions_adjacent(type,i,i+1)&&+((type!=&memblock.memory||memblock_memory_can_coalesce(type->regions[i].base,+type->regions[i].size,+type->regions[i+1].base,+type->regions[i+1].size)))){memblock_coalesce_regions(type,i,i+1);coalesced++;}
From: Yinghai Lu <yinghai@kernel.org> Date: 2010-07-22 18:26:27
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Let's not waste space and cycles on archs that don't support >32-bit
physical address space.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
include/linux/memblock.h | 44 +++++++++---------
mm/memblock.c | 114 +++++++++++++++++++++++----------------------
2 files changed, 80 insertions(+), 78 deletions(-)
@@ -141,8 +142,8 @@ static long memblock_add_region(struct memblock_type *type, u64 base, u64 size)/* First try and coalesce this MEMBLOCK with another. */for(i=0;i<type->cnt;i++){-u64rgnbase=type->regions[i].base;-u64rgnsize=type->regions[i].size;+phys_addr_trgnbase=type->regions[i].base;+phys_addr_trgnsize=type->regions[i].size;if((rgnbase==base)&&(rgnsize==size))/* Already have this region, so we're done */
@@ -301,7 +302,7 @@ static u64 __init memblock_alloc_region(u64 start, u64 end,if(j<0){/* this area isn't reserved, take it */if(memblock_add_region(&memblock.reserved,base,size)<0)-base=~(u64)0;+base=~(phys_addr_t)0;returnbase;}res_base=memblock.reserved.regions[j].base;
@@ -405,26 +407,26 @@ u64 __init __memblock_alloc_base(u64 size, u64 align, u64 max_addr)*topofmemory*/for(i=memblock.memory.cnt-1;i>=0;i--){-u64memblockbase=memblock.memory.regions[i].base;-u64memblocksize=memblock.memory.regions[i].size;+phys_addr_tmemblockbase=memblock.memory.regions[i].base;+phys_addr_tmemblocksize=memblock.memory.regions[i].size;if(memblocksize<size)continue;base=min(memblockbase+memblocksize,max_addr);res_base=memblock_alloc_region(memblockbase,base,size,align);-if(res_base!=~(u64)0)+if(res_base!=~(phys_addr_t)0)returnres_base;}return0;}/* You must call memblock_analyze() before this. */-u64__initmemblock_phys_mem_size(void)+phys_addr_t__initmemblock_phys_mem_size(void){returnmemblock.memory.size;}-u64memblock_end_of_DRAM(void)+phys_addr_tmemblock_end_of_DRAM(void){intidx=memblock.memory.cnt-1;
@@ -432,10 +434,10 @@ u64 memblock_end_of_DRAM(void)}/* You must call memblock_analyze() after this. */-void__initmemblock_enforce_memory_limit(u64memory_limit)+void__initmemblock_enforce_memory_limit(phys_addr_tmemory_limit){unsignedlongi;-u64limit;+phys_addr_tlimit;structmemblock_region*p;if(!memory_limit)
From: Yinghai Lu <yinghai@kernel.org> Date: 2010-07-22 18:26:31
so will have more idea where it is, use memblock_debug to controll it
-v2: use memblock_dbg instead of " if (memblock_debug) "
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
mm/memblock.c | 7 ++++---
1 files changed, 4 insertions(+), 3 deletions(-)
@@ -192,8 +192,6 @@ static int memblock_double_array(struct memblock_type *type)if(!memblock_can_resize)return-1;-pr_debug("memblock: %s array full, doubling...",memblock_type_name(type));-/* Calculate new doubled size */old_size=type->max*sizeof(structmemblock_region);new_size=old_size<<1;
@@ -221,6 +219,9 @@ static int memblock_double_array(struct memblock_type *type)}new_array=__va(addr);+memblock_dbg("memblock: %s array is doubled to %ld at [%#010llx-%#010llx]",+memblock_type_name(type),type->max*2,(u64)addr,(u64)addr+new_size-1);+/* Found space, we now need to move the array over before*weaddthereservedregionsinceitmaybeourreserved*arrayitselfthatisfull.
From: Yinghai Lu <yinghai@kernel.org> Date: 2010-07-22 18:26:35
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
This will be used by the array resize code and might prove useful
to some arch code as well at which point it can be made non-static.
Also add comment as to why aligning size is important
[ Yinghai Lu ]: it should return MEMBLOCK_ERROR when it fail to find a range
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
mm/memblock.c | 58 +++++++++++++++++++++++++++++++++++++-------------------
1 files changed, 38 insertions(+), 20 deletions(-)
@@ -345,12 +345,15 @@ phys_addr_t __init memblock_alloc_nid(phys_addr_t size, phys_addr_t align, int nBUG_ON(0==size);+/* We align the size to limit fragmentation. Without this, a lot of+*smallallocsquicklyeatupthewholereservearrayonsparc+*/+size=memblock_align_up(size,align);+/* We do a bottom-up search for a region with the right*nidsincethat'seasierconsideringhowmemblock_nid_range()*works*/-size=memblock_align_up(size,align);-for(i=0;i<mem->cnt;i++){phys_addr_tret=memblock_alloc_nid_region(&mem->regions[i],size,align,nid);
@@ -405,13 +393,43 @@ phys_addr_t __init __memblock_alloc_base(phys_addr_t size, phys_addr_t align, phcontinue;base=min(memblockbase+memblocksize,max_addr);res_base=memblock_find_region(memblockbase,base,size,align);-if(res_base!=MEMBLOCK_ERROR&&-memblock_add_region(&memblock.reserved,res_base,size)>=0)+if(res_base!=MEMBLOCK_ERROR)returnres_base;}+returnMEMBLOCK_ERROR;+}++phys_addr_t__init__memblock_alloc_base(phys_addr_tsize,phys_addr_talign,phys_addr_tmax_addr)+{+phys_addr_tfound;++/* We align the size to limit fragmentation. Without this, a lot of+*smallallocsquicklyeatupthewholereservearrayonsparc+*/+size=memblock_align_up(size,align);++found=memblock_find_base(size,align,max_addr);+if(found!=MEMBLOCK_ERROR&&+memblock_add_region(&memblock.reserved,found,size)>=0)+returnfound;+return0;}+phys_addr_t__initmemblock_alloc_base(phys_addr_tsize,phys_addr_talign,phys_addr_tmax_addr)+{+phys_addr_talloc;++alloc=__memblock_alloc_base(size,align,max_addr);++if(alloc==0)+panic("ERROR: Failed to allocate 0x%llx bytes below 0x%llx.\n",+(unsignedlonglong)size,(unsignedlonglong)max_addr);++returnalloc;+}++/* You must call memblock_analyze() before this. */phys_addr_t__initmemblock_phys_mem_size(void){
From: Yinghai Lu <yinghai@kernel.org> Date: 2010-07-22 18:27:22
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
It's a real PITA to have to search for it in the middle
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
mm/memblock.c | 54 +++++++++++++++++++++++++++---------------------------
1 files changed, 27 insertions(+), 27 deletions(-)
@@ -107,33 +107,6 @@ static void memblock_coalesce_regions(struct memblock_type *type,memblock_remove_region(type,r2);}-void__initmemblock_init(void)-{-/* Hookup the initial arrays */-memblock.memory.regions=memblock_memory_init_regions;-memblock.memory.max=INIT_MEMBLOCK_REGIONS;-memblock.reserved.regions=memblock_reserved_init_regions;-memblock.reserved.max=INIT_MEMBLOCK_REGIONS;--/* Write a marker in the unused last array entry */-memblock.memory.regions[INIT_MEMBLOCK_REGIONS].base=(phys_addr_t)RED_INACTIVE;-memblock.reserved.regions[INIT_MEMBLOCK_REGIONS].base=(phys_addr_t)RED_INACTIVE;--/* Create a dummy zero size MEMBLOCK which will get coalesced away later.-*Thissimplifiesthememblock_add()codebelow...-*/-memblock.memory.regions[0].base=0;-memblock.memory.regions[0].size=0;-memblock.memory.cnt=1;--/* Ditto. */-memblock.reserved.regions[0].base=0;-memblock.reserved.regions[0].size=0;-memblock.reserved.cnt=1;--memblock.current_limit=MEMBLOCK_ALLOC_ANYWHERE;-}-void__initmemblock_analyze(void){inti;
@@ -517,3 +490,30 @@ void __init memblock_set_current_limit(phys_addr_t limit)memblock.current_limit=limit;}+void__initmemblock_init(void)+{+/* Hookup the initial arrays */+memblock.memory.regions=memblock_memory_init_regions;+memblock.memory.max=INIT_MEMBLOCK_REGIONS;+memblock.reserved.regions=memblock_reserved_init_regions;+memblock.reserved.max=INIT_MEMBLOCK_REGIONS;++/* Write a marker in the unused last array entry */+memblock.memory.regions[INIT_MEMBLOCK_REGIONS].base=(phys_addr_t)RED_INACTIVE;+memblock.reserved.regions[INIT_MEMBLOCK_REGIONS].base=(phys_addr_t)RED_INACTIVE;++/* Create a dummy zero size MEMBLOCK which will get coalesced away later.+*Thissimplifiesthememblock_add()codebelow...+*/+memblock.memory.regions[0].base=0;+memblock.memory.regions[0].size=0;+memblock.memory.cnt=1;++/* Ditto. */+memblock.reserved.regions[0].base=0;+memblock.reserved.regions[0].size=0;+memblock.reserved.cnt=1;++memblock.current_limit=MEMBLOCK_ALLOC_ANYWHERE;+}+
From: Yinghai Lu <yinghai@kernel.org> Date: 2010-07-22 18:27:39
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
We now provide a default (weak) implementation of memblock_nid_range()
which uses the early_pfn_map[] if CONFIG_ARCH_POPULATES_NODE_MAP
is set. Sparc still needs to use its own method due to the way
the pages can be scattered between nodes.
This implementation is inefficient due to our main algorithm and
callback construct wanting to work on an ascending addresses bases
while early_pfn_map[] would rather work with nid's (it's unsorted
at that stage). But it should work and we can look into improving
it subsequently, possibly using arch compile options to chose a
different algorithm alltogether.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
include/linux/memblock.h | 3 +++
mm/memblock.c | 28 +++++++++++++++++++++++++++-
2 files changed, 30 insertions(+), 1 deletions(-)
@@ -47,6 +47,9 @@ extern long memblock_remove(phys_addr_t base, phys_addr_t size);externlong__initmemblock_free(phys_addr_tbase,phys_addr_tsize);externlong__initmemblock_reserve(phys_addr_tbase,phys_addr_tsize);+/* The numa aware allocator is only available if+*CONFIG_ARCH_POPULATES_NODE_MAPisset+*/externphys_addr_t__initmemblock_alloc_nid(phys_addr_tsize,phys_addr_talign,intnid);externphys_addr_t__initmemblock_alloc(phys_addr_tsize,phys_addr_talign);
From: Yinghai Lu <yinghai@kernel.org> Date: 2010-07-22 18:28:17
will used by x86 memblock_x86_find_in_range_node and nobootmem replacement
-v2: use 0 instead -1ULL, Suggested by Linus, so we don't need cast them later to unsigned long
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
include/linux/memblock.h | 1 +
mm/memblock.c | 2 --
2 files changed, 1 insertions(+), 2 deletions(-)
@@ -27,8 +27,6 @@ int memblock_can_resize;staticstructmemblock_regionmemblock_memory_init_regions[INIT_MEMBLOCK_REGIONS+1];structmemblock_regionmemblock_reserved_init_regions[INIT_MEMBLOCK_REGIONS+1];-#define MEMBLOCK_ERROR (~(phys_addr_t)0)-/* inline so we don't get a warning when pr_debug is compiled out */staticinlineconstchar*memblock_type_name(structmemblock_type*type){
From: Yinghai Lu <yinghai@kernel.org> Date: 2010-07-22 18:28:44
1. expose memblock_debug
2. expose memblock_reserved_init_regions
-v2: drop memblock_add_region() and MEMBLOCK_ERROR export
-v3: seperate wrong return of memblock_fin_base to another patch
-v4: expose memblock_can_resize to handle x86 EFI that could have more than
128 entries
-v5: add memblock_dbg, so we can spare some if (memblock_debug) suggested by Ingo.
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
include/linux/memblock.h | 6 ++++++
mm/memblock.c | 5 +++--
2 files changed, 9 insertions(+), 2 deletions(-)
From: Yinghai Lu <yinghai@kernel.org> Date: 2010-07-22 18:29:08
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Some shuffling is needed for doing array resize so we may as well
put some sense into the ordering of the functions in the whole memblock.c
file. No code change. Added some comments.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
mm/memblock.c | 301 ++++++++++++++++++++++++++++++---------------------------
1 files changed, 159 insertions(+), 142 deletions(-)
@@ -88,6 +66,77 @@ static long memblock_regions_adjacent(struct memblock_type *type,returnmemblock_addrs_adjacent(base1,size1,base2,size2);}+longmemblock_overlaps_region(structmemblock_type*type,phys_addr_tbase,phys_addr_tsize)+{+unsignedlongi;++for(i=0;i<type->cnt;i++){+phys_addr_trgnbase=type->regions[i].base;+phys_addr_trgnsize=type->regions[i].size;+if(memblock_addrs_overlap(base,size,rgnbase,rgnsize))+break;+}++return(i<type->cnt)?i:-1;+}++/*+*Find,allocate,deallocateorreserveunreservedregions.Allallocations+*aretop-down.+*/++staticphys_addr_t__initmemblock_find_region(phys_addr_tstart,phys_addr_tend,+phys_addr_tsize,phys_addr_talign)+{+phys_addr_tbase,res_base;+longj;++base=memblock_align_down((end-size),align);+while(start<=base){+j=memblock_overlaps_region(&memblock.reserved,base,size);+if(j<0)+returnbase;+res_base=memblock.reserved.regions[j].base;+if(res_base<size)+break;+base=memblock_align_down(res_base-size,align);+}++returnMEMBLOCK_ERROR;+}++staticphys_addr_t__initmemblock_find_base(phys_addr_tsize,phys_addr_talign,phys_addr_tmax_addr)+{+longi;+phys_addr_tbase=0;+phys_addr_tres_base;++BUG_ON(0==size);++size=memblock_align_up(size,align);++/* Pump up max_addr */+if(max_addr==MEMBLOCK_ALLOC_ACCESSIBLE)+max_addr=memblock.current_limit;++/* We do a top-down search, this tends to limit memory+*fragmentationbykeepingearlybootallocsnearthe+*topofmemory+*/+for(i=memblock.memory.cnt-1;i>=0;i--){+phys_addr_tmemblockbase=memblock.memory.regions[i].base;+phys_addr_tmemblocksize=memblock.memory.regions[i].size;++if(memblocksize<size)+continue;+base=min(memblockbase+memblocksize,max_addr);+res_base=memblock_find_region(memblockbase,base,size,align);+if(res_base!=MEMBLOCK_ERROR)+returnres_base;+}+returnMEMBLOCK_ERROR;+}+staticvoidmemblock_remove_region(structmemblock_type*type,unsignedlongr){unsignedlongi;
@@ -107,22 +156,6 @@ static void memblock_coalesce_regions(struct memblock_type *type,memblock_remove_region(type,r2);}-void__initmemblock_analyze(void)-{-inti;--/* Check marker in the unused last array entry */-WARN_ON(memblock_memory_init_regions[INIT_MEMBLOCK_REGIONS].base-!=(phys_addr_t)RED_INACTIVE);-WARN_ON(memblock_reserved_init_regions[INIT_MEMBLOCK_REGIONS].base-!=(phys_addr_t)RED_INACTIVE);--memblock.memory_size=0;--for(i=0;i<memblock.memory.cnt;i++)-memblock.memory_size+=memblock.memory.regions[i].size;-}-staticlongmemblock_add_region(structmemblock_type*type,phys_addr_tbase,phys_addr_tsize){unsignedlongcoalesced=0;
@@ -260,49 +293,47 @@ long __init memblock_reserve(phys_addr_t base, phys_addr_t size)returnmemblock_add_region(_rgn,base,size);}-longmemblock_overlaps_region(structmemblock_type*type,phys_addr_tbase,phys_addr_tsize)+phys_addr_t__init__memblock_alloc_base(phys_addr_tsize,phys_addr_talign,phys_addr_tmax_addr){-unsignedlongi;+phys_addr_tfound;-for(i=0;i<type->cnt;i++){-phys_addr_trgnbase=type->regions[i].base;-phys_addr_trgnsize=type->regions[i].size;-if(memblock_addrs_overlap(base,size,rgnbase,rgnsize))-break;-}+/* We align the size to limit fragmentation. Without this, a lot of+*smallallocsquicklyeatupthewholereservearrayonsparc+*/+size=memblock_align_up(size,align);-return(i<type->cnt)?i:-1;-}+found=memblock_find_base(size,align,max_addr);+if(found!=MEMBLOCK_ERROR&&+memblock_add_region(&memblock.reserved,found,size)>=0)+returnfound;-staticphys_addr_tmemblock_align_down(phys_addr_taddr,phys_addr_tsize)-{-returnaddr&~(size-1);+return0;}-staticphys_addr_tmemblock_align_up(phys_addr_taddr,phys_addr_tsize)+phys_addr_t__initmemblock_alloc_base(phys_addr_tsize,phys_addr_talign,phys_addr_tmax_addr){-return(addr+(size-1))&~(size-1);+phys_addr_talloc;++alloc=__memblock_alloc_base(size,align,max_addr);++if(alloc==0)+panic("ERROR: Failed to allocate 0x%llx bytes below 0x%llx.\n",+(unsignedlonglong)size,(unsignedlonglong)max_addr);++returnalloc;}-staticphys_addr_t__initmemblock_find_region(phys_addr_tstart,phys_addr_tend,-phys_addr_tsize,phys_addr_talign)+phys_addr_t__initmemblock_alloc(phys_addr_tsize,phys_addr_talign){-phys_addr_tbase,res_base;-longj;+returnmemblock_alloc_base(size,align,MEMBLOCK_ALLOC_ACCESSIBLE);+}-base=memblock_align_down((end-size),align);-while(start<=base){-j=memblock_overlaps_region(&memblock.reserved,base,size);-if(j<0)-returnbase;-res_base=memblock.reserved.regions[j].base;-if(res_base<size)-break;-base=memblock_align_down(res_base-size,align);-}-returnMEMBLOCK_ERROR;-}+/*+*Additionalnode-localallocators.Searchfornodememoryisbottomup+*andwalksmemblockregionswithinthatnodebottom-upaswell,butallocation+*withinanmemblockregionistop-down.+*/phys_addr_t__weak__initmemblock_nid_range(phys_addr_tstart,phys_addr_tend,int*nid){
@@ -364,72 +395,6 @@ phys_addr_t __init memblock_alloc_nid(phys_addr_t size, phys_addr_t align, int nreturnmemblock_alloc(size,align);}-phys_addr_t__initmemblock_alloc(phys_addr_tsize,phys_addr_talign)-{-returnmemblock_alloc_base(size,align,MEMBLOCK_ALLOC_ACCESSIBLE);-}--staticphys_addr_t__initmemblock_find_base(phys_addr_tsize,phys_addr_talign,phys_addr_tmax_addr)-{-longi;-phys_addr_tbase=0;-phys_addr_tres_base;--BUG_ON(0==size);--/* Pump up max_addr */-if(max_addr==MEMBLOCK_ALLOC_ACCESSIBLE)-max_addr=memblock.current_limit;--/* We do a top-down search, this tends to limit memory-*fragmentationbykeepingearlybootallocsnearthe-*topofmemory-*/-for(i=memblock.memory.cnt-1;i>=0;i--){-phys_addr_tmemblockbase=memblock.memory.regions[i].base;-phys_addr_tmemblocksize=memblock.memory.regions[i].size;--if(memblocksize<size)-continue;-base=min(memblockbase+memblocksize,max_addr);-res_base=memblock_find_region(memblockbase,base,size,align);-if(res_base!=MEMBLOCK_ERROR)-returnres_base;-}-returnMEMBLOCK_ERROR;-}--phys_addr_t__init__memblock_alloc_base(phys_addr_tsize,phys_addr_talign,phys_addr_tmax_addr)-{-phys_addr_tfound;--/* We align the size to limit fragmentation. Without this, a lot of-*smallallocsquicklyeatupthewholereservearrayonsparc-*/-size=memblock_align_up(size,align);--found=memblock_find_base(size,align,max_addr);-if(found!=MEMBLOCK_ERROR&&-memblock_add_region(&memblock.reserved,found,size)>=0)-returnfound;--return0;-}--phys_addr_t__initmemblock_alloc_base(phys_addr_tsize,phys_addr_talign,phys_addr_tmax_addr)-{-phys_addr_talloc;--alloc=__memblock_alloc_base(size,align,max_addr);--if(alloc==0)-panic("ERROR: Failed to allocate 0x%llx bytes below 0x%llx.\n",-(unsignedlonglong)size,(unsignedlonglong)max_addr);--returnalloc;-}--/* You must call memblock_analyze() before this. */phys_addr_t__initmemblock_phys_mem_size(void){
@@ -508,6 +473,50 @@ void __init memblock_set_current_limit(phys_addr_t limit)memblock.current_limit=limit;}+staticvoidmemblock_dump(structmemblock_type*region,char*name)+{+unsignedlonglongbase,size;+inti;++pr_info(" %s.cnt = 0x%lx\n",name,region->cnt);++for(i=0;i<region->cnt;i++){+base=region->regions[i].base;+size=region->regions[i].size;++pr_info(" %s[0x%x]\t0x%016llx - 0x%016llx, 0x%llx bytes\n",+name,i,base,base+size-1,size);+}+}++voidmemblock_dump_all(void)+{+if(!memblock_debug)+return;++pr_info("MEMBLOCK configuration:\n");+pr_info(" memory size = 0x%llx\n",(unsignedlonglong)memblock.memory_size);++memblock_dump(&memblock.memory,"memory");+memblock_dump(&memblock.reserved,"reserved");+}++void__initmemblock_analyze(void)+{+inti;++/* Check marker in the unused last array entry */+WARN_ON(memblock_memory_init_regions[INIT_MEMBLOCK_REGIONS].base+!=(phys_addr_t)RED_INACTIVE);+WARN_ON(memblock_reserved_init_regions[INIT_MEMBLOCK_REGIONS].base+!=(phys_addr_t)RED_INACTIVE);++memblock.memory_size=0;++for(i=0;i<memblock.memory.cnt;i++)+memblock.memory_size+=memblock.memory.regions[i].size;+}+void__initmemblock_init(void){/* Hookup the initial arrays */
From: Yinghai Lu <yinghai@kernel.org> Date: 2010-07-22 18:33:07
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
This is in preparation for having resizable arrays.
Note that we still allocate one more than needed, this is unchanged from
the previous implementation.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
include/linux/memblock.h | 7 ++++---
mm/memblock.c | 10 +++++++++-
2 files changed, 13 insertions(+), 4 deletions(-)
@@ -26,8 +26,9 @@ struct memblock_region {};structmemblock_type{-unsignedlongcnt;-structmemblock_regionregions[MAX_MEMBLOCK_REGIONS+1];+unsignedlongcnt;/* number of regions */+unsignedlongmax;/* size of the allocated array */+structmemblock_region*regions;};structmemblock{
@@ -104,6 +106,12 @@ static void memblock_coalesce_regions(struct memblock_type *type,void__initmemblock_init(void){+/* Hookup the initial arrays */+memblock.memory.regions=memblock_memory_init_regions;+memblock.memory.max=INIT_MEMBLOCK_REGIONS;+memblock.reserved.regions=memblock_reserved_init_regions;+memblock.reserved.max=INIT_MEMBLOCK_REGIONS;+/* Create a dummy zero size MEMBLOCK which will get coalesced away later.*Thissimplifiesthememblock_add()codebelow...*/
@@ -169,7 +177,7 @@ static long memblock_add_region(struct memblock_type *type, phys_addr_t base, phif(coalesced)returncoalesced;-if(type->cnt>=MAX_MEMBLOCK_REGIONS)+if(type->cnt>=type->max)return-1;/* Couldn't coalesce the MEMBLOCK, so add it to the sorted table. */
From: Yinghai Lu <yinghai@kernel.org> Date: 2010-07-22 18:39:27
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Right now, both the "memory" and "reserved" memblock_type structures have
a "size" member. It's unused in the later case, and represent the
calculated memory size in the later case.
This moves it out to the main memblock structure instead
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/mm/mem.c | 2 +-
include/linux/memblock.h | 2 +-
mm/memblock.c | 8 ++++----
3 files changed, 6 insertions(+), 6 deletions(-)
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2010-07-22 21:37:36
On Thu, 2010-07-22 at 11:20 -0700, Yinghai Lu wrote:
New memblock could be used to replace early_res in x86.
Suggested by: David, Ben, and Thomas
-v25: update to mainline with kmemleak fix on nobootmem
also rename lmb to memblock alread in mainline
-v26: according to Linus and hpa, seperate the big patchset to small ones.
This one is rebase of Ben's changeset to current mainline/tip
Last 6 are needed for x86 memblock transistion, but change mm/memblock.c
Are there any change from my original series other than an automated
rebase ? If yes, let me know as I do plan to do that rebase myself, I
just haven't got to it yet.
Ben.
Thanks
Yinghai Lu
[PATCH 01/31] memblock: Rename memblock_region to memblock_type and memblock_property to memblock_region
[PATCH 02/31] memblock: No reason to include asm/memblock.h late
[PATCH 03/31] memblock: Introduce for_each_memblock() and new accessors, and use it
[PATCH 04/31] memblock: Remove nid_range argument, arch provides memblock_nid_range() instead
[PATCH 05/31] memblock: Factor the lowest level alloc function
[PATCH 06/31] memblock: Expose MEMBLOCK_ALLOC_ANYWHERE
[PATCH 07/31] memblock: Introduce default allocation limit and use it to replace explicit ones
[PATCH 08/31] memblock: Remove rmo_size, burry it in arch/powerpc where it belongs
[PATCH 09/31] memblock: Change u64 to phys_addr_t
[PATCH 10/31] memblock: Remove unused memblock.debug struct member
[PATCH 11/31] memblock: Remove memblock_type.size and add memblock.memory_size instead
[PATCH 12/31] memblock: Move memblock arrays to static storage in memblock.c and make their size a variable
[PATCH 13/31] memblock: Add debug markers at the end of the array
[PATCH 14/31] memblock: Make memblock_find_region() out of memblock_alloc_region()
[PATCH 15/31] memblock: Define MEMBLOCK_ERROR internally instead of using ~(phys_addr_t)0
[PATCH 16/31] memblock: Move memblock_init() to the bottom of the file
[PATCH 17/31] memblock: split memblock_find_base() out of __memblock_alloc_base()
[PATCH 18/31] memblock: Move functions around into a more sensible order
[PATCH 19/31] memblock: Add array resizing support
[PATCH 20/31] memblock: Add arch function to control coalescing of memblock memory regions
[PATCH 21/31] memblock: Add "start" argument to memblock_find_base()
[PATCH 22/31] memblock: NUMA allocate can now use early_pfn_map
[PATCH 23/31] memblock: Separate memblock_alloc_nid() and memblock_alloc_try_nid()
[PATCH 24/31] memblock: Make memblock_alloc_try_nid() fallback to MEMBLOCK_ALLOC_ANYWHERE
[PATCH 25/31] memblock: Add debugfs files to dump the arrays content
[PATCH 26/31] memblock: Prepare x86 to use memblock to replace early_res
[PATCH 27/31] memblock: Print new doubled array location info
[PATCH 28/31] memblock: Export MEMBLOCK_ERROR again
[PATCH 29/31] memblock: Prepare to include linux/memblock.h in core file
[PATCH 30/31] memblock: Add ARCH_DISCARD_MEMBLOCK to put memblock code to .init
[PATCH 31/31] memblock: Add memblock_find_in_range()
arch/microblaze/include/asm/memblock.h | 3 -
arch/microblaze/mm/init.c | 18 +-
arch/powerpc/include/asm/memblock.h | 7 -
arch/powerpc/include/asm/mmu.h | 12 +
arch/powerpc/kernel/head_40x.S | 6 +-
arch/powerpc/kernel/paca.c | 2 +-
arch/powerpc/kernel/prom.c | 15 +-
arch/powerpc/kernel/rtas.c | 2 +-
arch/powerpc/kernel/setup_32.c | 2 +-
arch/powerpc/kernel/setup_64.c | 2 +-
arch/powerpc/mm/40x_mmu.c | 17 +-
arch/powerpc/mm/44x_mmu.c | 14 +
arch/powerpc/mm/fsl_booke_mmu.c | 12 +-
arch/powerpc/mm/hash_utils_64.c | 35 ++-
arch/powerpc/mm/init_32.c | 43 +-
arch/powerpc/mm/init_64.c | 1 +
arch/powerpc/mm/mem.c | 94 ++---
arch/powerpc/mm/numa.c | 17 +-
arch/powerpc/mm/ppc_mmu_32.c | 18 +-
arch/powerpc/mm/tlb_nohash.c | 16 +
arch/powerpc/platforms/embedded6xx/wii.c | 2 +-
arch/sh/include/asm/memblock.h | 2 -
arch/sh/mm/init.c | 16 +-
arch/sparc/include/asm/memblock.h | 2 -
arch/sparc/mm/init_64.c | 46 +--
include/linux/memblock.h | 162 +++++--
mm/memblock.c | 764 +++++++++++++++++++-----------
27 files changed, 846 insertions(+), 484 deletions(-)
From: Yinghai Lu <yinghai@kernel.org> Date: 2010-07-22 22:01:48
On 07/22/2010 02:35 PM, Benjamin Herrenschmidt wrote:
On Thu, 2010-07-22 at 11:20 -0700, Yinghai Lu wrote:
quoted
New memblock could be used to replace early_res in x86.
Suggested by: David, Ben, and Thomas
-v25: update to mainline with kmemleak fix on nobootmem
also rename lmb to memblock alread in mainline
-v26: according to Linus and hpa, seperate the big patchset to small ones.
This one is rebase of Ben's changeset to current mainline/tip
Last 6 are needed for x86 memblock transistion, but change mm/memblock.c
Are there any change from my original series other than an automated
rebase ? If yes, let me know as I do plan to do that rebase myself, I
just haven't got to it yet.
quoted
[PATCH 01/31] memblock: Rename memblock_region to memblock_type and memblock_property to memblock_region
[PATCH 02/31] memblock: No reason to include asm/memblock.h late
[PATCH 03/31] memblock: Introduce for_each_memblock() and new accessors, and use it
[PATCH 04/31] memblock: Remove nid_range argument, arch provides memblock_nid_range() instead
[PATCH 05/31] memblock: Factor the lowest level alloc function
[PATCH 06/31] memblock: Expose MEMBLOCK_ALLOC_ANYWHERE
[PATCH 07/31] memblock: Introduce default allocation limit and use it to replace explicit ones
[PATCH 08/31] memblock: Remove rmo_size, burry it in arch/powerpc where it belongs
[PATCH 09/31] memblock: Change u64 to phys_addr_t
[PATCH 10/31] memblock: Remove unused memblock.debug struct member
[PATCH 11/31] memblock: Remove memblock_type.size and add memblock.memory_size instead
[PATCH 12/31] memblock: Move memblock arrays to static storage in memblock.c and make their size a variable
[PATCH 13/31] memblock: Add debug markers at the end of the array
[PATCH 14/31] memblock: Make memblock_find_region() out of memblock_alloc_region()
[PATCH 15/31] memblock: Define MEMBLOCK_ERROR internally instead of using ~(phys_addr_t)0
[PATCH 16/31] memblock: Move memblock_init() to the bottom of the file
[PATCH 17/31] memblock: split memblock_find_base() out of __memblock_alloc_base()
i folded the patch that make make memblock_find_base() to return MEMBLOCK_ERROR into patch 17
and following one or two patches need to change too accordingly.
quoted
[PATCH 18/31] memblock: Move functions around into a more sensible order
[PATCH 19/31] memblock: Add array resizing support
[PATCH 20/31] memblock: Add arch function to control coalescing of memblock memory regions
[PATCH 21/31] memblock: Add "start" argument to memblock_find_base()
[PATCH 22/31] memblock: NUMA allocate can now use early_pfn_map
[PATCH 23/31] memblock: Separate memblock_alloc_nid() and memblock_alloc_try_nid()
[PATCH 24/31] memblock: Make memblock_alloc_try_nid() fallback to MEMBLOCK_ALLOC_ANYWHERE
[PATCH 25/31] memblock: Add debugfs files to dump the arrays content
quoted
[PATCH 26/31] memblock: Prepare x86 to use memblock to replace early_res
[PATCH 27/31] memblock: Print new doubled array location info
[PATCH 28/31] memblock: Export MEMBLOCK_ERROR again
[PATCH 29/31] memblock: Prepare to include linux/memblock.h in core file
[PATCH 30/31] memblock: Add ARCH_DISCARD_MEMBLOCK to put memblock code to .init
[PATCH 31/31] memblock: Add memblock_find_in_range()
please check if you can those 6 into your new branch.
Thanks
Yinghai
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2010-07-28 05:16:06
On Thu, 2010-07-22 at 11:21 -0700, Yinghai Lu wrote:
will used by x86 memblock_x86_find_in_range_node and nobootmem replacement
-v2: use 0 instead -1ULL, Suggested by Linus, so we don't need cast them later to unsigned long
The patch in its current form is a NAK.
You can't just do those two things in one commit.
If we're going to switch LMB errors to always be 0, we need to ensure we
cannot realistically hand out 0 as a result of lmb_alloc().
I'll cook up a patch to do that.
Ben.
@@ -27,8 +27,6 @@ int memblock_can_resize;staticstructmemblock_regionmemblock_memory_init_regions[INIT_MEMBLOCK_REGIONS+1];structmemblock_regionmemblock_reserved_init_regions[INIT_MEMBLOCK_REGIONS+1];-#define MEMBLOCK_ERROR (~(phys_addr_t)0)-/* inline so we don't get a warning when pr_debug is compiled out */staticinlineconstchar*memblock_type_name(structmemblock_type*type){
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2010-07-28 05:20:09
On Wed, 2010-07-28 at 15:15 +1000, Benjamin Herrenschmidt wrote:
On Thu, 2010-07-22 at 11:21 -0700, Yinghai Lu wrote:
quoted
will used by x86 memblock_x86_find_in_range_node and nobootmem replacement
-v2: use 0 instead -1ULL, Suggested by Linus, so we don't need cast them later to unsigned long
The patch in its current form is a NAK.
You can't just do those two things in one commit.
If we're going to switch LMB errors to always be 0, we need to ensure we
cannot realistically hand out 0 as a result of lmb_alloc().
I'll cook up a patch to do that.
Screw it, I don't like it but I'll just split your patch in two for now
and keep 0. It's a bit fishy but memblock does mostly top-down
allocations and so shouldn't hit 0, and in practice the region at 0 is,
I beleive, reserved, but we need to be extra careful and might need to
revisit that a bit.
That's an area where I don't completely agree with Linus, ie, 0 is a
perfectly valid physical address for memblock to return :-)
Cheers,
Ben.
@@ -27,8 +27,6 @@ int memblock_can_resize;staticstructmemblock_regionmemblock_memory_init_regions[INIT_MEMBLOCK_REGIONS+1];structmemblock_regionmemblock_reserved_init_regions[INIT_MEMBLOCK_REGIONS+1];-#define MEMBLOCK_ERROR (~(phys_addr_t)0)-/* inline so we don't get a warning when pr_debug is compiled out */staticinlineconstchar*memblock_type_name(structmemblock_type*type){
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2010-07-28 05:24:52
On Wed, 2010-07-28 at 15:15 +1000, Benjamin Herrenschmidt wrote:
On Thu, 2010-07-22 at 11:21 -0700, Yinghai Lu wrote:
quoted
will used by x86 memblock_x86_find_in_range_node and nobootmem replacement
-v2: use 0 instead -1ULL, Suggested by Linus, so we don't need cast them later to unsigned long
The patch in its current form is a NAK.
You can't just do those two things in one commit.
If we're going to switch LMB errors to always be 0, we need to ensure we
cannot realistically hand out 0 as a result of lmb_alloc().
I'll cook up a patch to do that.
BTW. After that, maybe send a patch completely removing
MEMBLOCK_ERROR ?
I find 0 to be self-explanatory enough.
Cheers,
Ben.
@@ -27,8 +27,6 @@ int memblock_can_resize;staticstructmemblock_regionmemblock_memory_init_regions[INIT_MEMBLOCK_REGIONS+1];structmemblock_regionmemblock_reserved_init_regions[INIT_MEMBLOCK_REGIONS+1];-#define MEMBLOCK_ERROR (~(phys_addr_t)0)-/* inline so we don't get a warning when pr_debug is compiled out */staticinlineconstchar*memblock_type_name(structmemblock_type*type){
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2010-07-28 05:28:00
On Thu, 2010-07-22 at 11:21 -0700, Yinghai Lu wrote:
Need to add protection in linux/memblock.h, to prepare to include it in
mm/page_alloc.c and mm/bootmem.c etc.
Not really no ... having the definitions shouldn't hurt whether memblock
is used or not, no ?
I'm going to keep that patch in the queue because it has one advantage
that you don't mention, which is to more easily catch attempts to
use those functions when CONFIG_HAVE_MEMBLOCK isn't set, but I'll update
the commit message.
Ben.
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2010-07-28 05:37:31
On Thu, 2010-07-22 at 11:21 -0700, Yinghai Lu wrote:
it is a wrapper for memblock_find_base
make it more easy for x86 to use memblock. ( rebase )
x86 early_res is using find/reserve pattern instead of alloc.
keep it in weak version, so later We can use x86 own version if needed.
also We need it in mm/memblock.c, so one caller mm/page_alloc.c could get compiled
-v2: Change name to memblock_find_in_range() according to Michael Ellerman
-v3: Add generic weak version __memblock_find_in_range()
so keep the path for fallback to x86 version that handle from low
-v4: use 0 for failing path
-v5: use MEMBLOCK_ERROR again
-v6: remove __memblock_find_in_range()
It's very gross to have this weak and not memblock_find_base()... IE.
You create a new function defined as a wrapper on an existing one to
provide an easier set of arguments ... but also make it weak so the
arch can completely change its semantics without actually changing
the semantics of the function it wraps.
This is going to cause confusion and bugs. I'm adding the patch without
the weak bit to my branch for now, we need to discuss what is the best
approach for x86 here. Might be to use a different function. I don't
understand yet -why- x86 needs to override it, maybe the right way is
to reserve things more intelligently on x86 ?
In any case, you can always use your own wrapper there if needed
Cheers,
Ben.
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2010-07-28 05:45:38
On Thu, 2010-07-22 at 11:21 -0700, Yinghai Lu wrote:
So those memblock bits could be released after kernel is booted up.
Arch code could define ARCH_DISCARD_MEMBLOCK in asm/memblock.h,
__init_memblock will become __init, __initdata_memblock will becom __initdata
Actually, that sucks.
A bunch of memblock is already __init. The bits that aren't fall mostly
into two categories:
- Stuff used by powerpc memory hotplug. Most of this could be covered
by __meminit
- The arrays themselves. We really only care about keeping the memory
array and a couple of things to walk it.
I'm merging the patch now to avoid further delays but we need to
revisit that too.
Ben.
quoted hunk
x86 code will use that.
if ARCH_DISCARD_MEMBLOCK is defined, debugfs is not used
-v2: use ARCH_DISCARD_MEMBLOCK according to Michael Ellerman
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
include/linux/memblock.h | 8 +++++++
mm/memblock.c | 48 +++++++++++++++++++++++-----------------------
2 files changed, 32 insertions(+), 24 deletions(-)
@@ -20,12 +20,12 @@#include<linux/seq_file.h>#include<linux/memblock.h>-structmemblockmemblock;+structmemblockmemblock__initdata_memblock;-intmemblock_debug;-intmemblock_can_resize;-staticstructmemblock_regionmemblock_memory_init_regions[INIT_MEMBLOCK_REGIONS+1];-structmemblock_regionmemblock_reserved_init_regions[INIT_MEMBLOCK_REGIONS+1];+intmemblock_debug__initdata_memblock;+intmemblock_can_resize__initdata_memblock;+staticstructmemblock_regionmemblock_memory_init_regions[INIT_MEMBLOCK_REGIONS+1]__initdata_memblock;+structmemblock_regionmemblock_reserved_init_regions[INIT_MEMBLOCK_REGIONS+1]__initdata_memblock;/* inline so we don't get a warning when pr_debug is compiled out */staticinlineconstchar*memblock_type_name(structmemblock_type*type)
@@ -168,7 +168,7 @@ static void memblock_remove_region(struct memblock_type *type, unsigned long r)}/* Assumption: base addr of region 1 < base addr of region 2 */-staticvoidmemblock_coalesce_regions(structmemblock_type*type,+staticvoid__init_memblockmemblock_coalesce_regions(structmemblock_type*type,unsignedlongr1,unsignedlongr2){type->regions[r1].size+=type->regions[r2].size;
@@ -178,7 +178,7 @@ static void memblock_coalesce_regions(struct memblock_type *type,/* Defined below but needed now */staticlongmemblock_add_region(structmemblock_type*type,phys_addr_tbase,phys_addr_tsize);-staticintmemblock_double_array(structmemblock_type*type)+staticint__init_memblockmemblock_double_array(structmemblock_type*type){structmemblock_region*new_array,*old_array;phys_addr_told_size,new_size,addr;
@@ -249,13 +249,13 @@ static int memblock_double_array(struct memblock_type *type)return0;}-externint__weakmemblock_memory_can_coalesce(phys_addr_taddr1,phys_addr_tsize1,+externint__init_memblock__weakmemblock_memory_can_coalesce(phys_addr_taddr1,phys_addr_tsize1,phys_addr_taddr2,phys_addr_tsize2){return1;}-staticlongmemblock_add_region(structmemblock_type*type,phys_addr_tbase,phys_addr_tsize)+staticlong__init_memblockmemblock_add_region(structmemblock_type*type,phys_addr_tbase,phys_addr_tsize){unsignedlongcoalesced=0;longadjacent,i;
From: "H. Peter Anvin" <hpa@zytor.com> Date: 2010-07-28 05:54:14
On 07/27/2010 10:19 PM, Benjamin Herrenschmidt wrote:
Screw it, I don't like it but I'll just split your patch in two for now
and keep 0. It's a bit fishy but memblock does mostly top-down
allocations and so shouldn't hit 0, and in practice the region at 0 is,
I beleive, reserved, but we need to be extra careful and might need to
revisit that a bit.
That's an area where I don't completely agree with Linus, ie, 0 is a
perfectly valid physical address for memblock to return :-)
On x86, physical address 0 contains the real-mode IVT and will thus be
reserved, at least for the forseeable future. Other architectures may
very well have non-special RAM there.
-hpa
--
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel. I don't speak on their behalf.
On 07/27/2010 10:19 PM, Benjamin Herrenschmidt wrote:
quoted
Screw it, I don't like it but I'll just split your patch in two for now
and keep 0. It's a bit fishy but memblock does mostly top-down
allocations and so shouldn't hit 0, and in practice the region at 0 is,
I beleive, reserved, but we need to be extra careful and might need to
revisit that a bit.
That's an area where I don't completely agree with Linus, ie, 0 is a
perfectly valid physical address for memblock to return :-)
On x86, physical address 0 contains the real-mode IVT and will thus be
reserved, at least for the forseeable future. Other architectures may
very well have non-special RAM there.
From: Yinghai Lu <yinghai@kernel.org> Date: 2010-07-28 06:09:27
On 07/27/2010 10:36 PM, Benjamin Herrenschmidt wrote:
On Thu, 2010-07-22 at 11:21 -0700, Yinghai Lu wrote:
quoted
it is a wrapper for memblock_find_base
make it more easy for x86 to use memblock. ( rebase )
x86 early_res is using find/reserve pattern instead of alloc.
keep it in weak version, so later We can use x86 own version if needed.
also We need it in mm/memblock.c, so one caller mm/page_alloc.c could get compiled
-v2: Change name to memblock_find_in_range() according to Michael Ellerman
-v3: Add generic weak version __memblock_find_in_range()
so keep the path for fallback to x86 version that handle from low
-v4: use 0 for failing path
-v5: use MEMBLOCK_ERROR again
-v6: remove __memblock_find_in_range()
It's very gross to have this weak and not memblock_find_base()... IE.
You create a new function defined as a wrapper on an existing one to
provide an easier set of arguments ... but also make it weak so the
arch can completely change its semantics without actually changing
the semantics of the function it wraps.
This is going to cause confusion and bugs. I'm adding the patch without
the weak bit to my branch for now, we need to discuss what is the best
approach for x86 here. Might be to use a different function. I don't
understand yet -why- x86 needs to override it, maybe the right way is
to reserve things more intelligently on x86 ?
again there is a difference between low/high to high/low.
for example:
high/low allocation, from first kernel to kexec second kernel, always work fine except system with Qlogic card.
because Qlogic card is using main RAM as EFT etc for card's FW log trace. second kernel have not idea that those RAM
is used by first kernel for that purpose. that the CARD still use that between two kernels.
second kernel could have crash it try to use those ram.
low/high allocation seems to be safe, second kernel can slip to boot fine.
Thanks
Yinghai
On 07/27/2010 10:19 PM, Benjamin Herrenschmidt wrote:
quoted
Screw it, I don't like it but I'll just split your patch in two for now
and keep 0. It's a bit fishy but memblock does mostly top-down
allocations and so shouldn't hit 0, and in practice the region at 0 is,
I beleive, reserved, but we need to be extra careful and might need to
revisit that a bit.
That's an area where I don't completely agree with Linus, ie, 0 is a
perfectly valid physical address for memblock to return :-)
On x86, physical address 0 contains the real-mode IVT and will thus be
reserved, at least for the forseeable future. Other architectures may
very well have non-special RAM there.
0 is very much possible on sparc64
So still keep MEMBLOCK_ERROR to (~(phys_addr_t)0) ?
We can change some variable from unsigned long to phys_addr_t that will be
assigned by memblock_find_base().
that could avoid casting too.
Thanks
Yinghai
From: "H. Peter Anvin" <hpa@zytor.com> Date: 2010-07-28 06:23:39
On 07/27/2010 10:36 PM, Benjamin Herrenschmidt wrote:
It's very gross to have this weak and not memblock_find_base()... IE.
You create a new function defined as a wrapper on an existing one to
provide an easier set of arguments ... but also make it weak so the
arch can completely change its semantics without actually changing
the semantics of the function it wraps.
This is going to cause confusion and bugs. I'm adding the patch without
the weak bit to my branch for now, we need to discuss what is the best
approach for x86 here. Might be to use a different function. I don't
understand yet -why- x86 needs to override it, maybe the right way is
to reserve things more intelligently on x86 ?
In any case, you can always use your own wrapper there if needed
I'm really confused by this as well. First of all this only looks like
a prototype which swizzles the argument order, which is a good start for
making problems.
The second thing is that the proposed x86 code seems to do something I
would consider to be a core service, which is find an allocation outside
any reserved region, but it does so by looking at two different data
structures. Instead the logical thing would be to knock a reserved
block out of the available set, so that there is always a data structure
which contains the currently free and available memory. I think the
best thing would be if the same data structure could also handle
reserved memory types (by carrying an attribute), but if that is not
possible, there can be a reserved memblock structure and an available
memblock structure, alternatively (and equivalently) an "all memory"
memblock structure and an available memblock structure, but unavailable
memory should not be in the available structure.
-hpa
--
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel. I don't speak on their behalf.
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2010-07-28 06:30:28
On Tue, 2010-07-27 at 22:53 -0700, H. Peter Anvin wrote:
On 07/27/2010 10:19 PM, Benjamin Herrenschmidt wrote:
quoted
Screw it, I don't like it but I'll just split your patch in two for now
and keep 0. It's a bit fishy but memblock does mostly top-down
allocations and so shouldn't hit 0, and in practice the region at 0 is,
I beleive, reserved, but we need to be extra careful and might need to
revisit that a bit.
That's an area where I don't completely agree with Linus, ie, 0 is a
perfectly valid physical address for memblock to return :-)
On x86, physical address 0 contains the real-mode IVT and will thus be
reserved, at least for the forseeable future. Other architectures may
very well have non-special RAM there.
Right, that's my point. Anyways, I'm making 0 special for now and adding
a wart to prevent the allocator from returning something below
PAGE_SIZE. If we want to revisit that later we can.
Cheers,
Ben.
From: "H. Peter Anvin" <hpa@zytor.com> Date: 2010-07-28 06:38:55
On 07/27/2010 11:08 PM, Yinghai Lu wrote:
for example:
high/low allocation, from first kernel to kexec second kernel, always work fine except system with Qlogic card.
because Qlogic card is using main RAM as EFT etc for card's FW log trace. second kernel have not idea that those RAM
is used by first kernel for that purpose. that the CARD still use that between two kernels.
second kernel could have crash it try to use those ram.
Uhm, no. That's a bug in the Qlogic driver not shutting the card down
cleanly. Hacking around that in memory allocation order is braindamaged
in the extreme. kexec *cannot* be safe in any way if we don't shut down
pending DMA, and what you describe above is DMA.
low/high allocation seems to be safe, second kernel can slip to boot fine.
Low to high is just broken. Low memory is a special, desirable
resource, and we should minimize the use of it.
-hpa
--
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel. I don't speak on their behalf.
From: Yinghai Lu <yinghai@kernel.org> Date: 2010-07-28 07:14:14
On 07/27/2010 11:38 PM, H. Peter Anvin wrote:
On 07/27/2010 11:08 PM, Yinghai Lu wrote:
quoted
for example:
high/low allocation, from first kernel to kexec second kernel, always work fine except system with Qlogic card.
because Qlogic card is using main RAM as EFT etc for card's FW log trace. second kernel have not idea that those RAM
is used by first kernel for that purpose. that the CARD still use that between two kernels.
second kernel could have crash it try to use those ram.
Uhm, no. That's a bug in the Qlogic driver not shutting the card down
cleanly. Hacking around that in memory allocation order is braindamaged
in the extreme. kexec *cannot* be safe in any way if we don't shut down
pending DMA, and what you describe above is DMA.
the problem is later if the user hit the problem, it will be called "Regression" after bisecting to the memblock/x86 changes.
because low/high does work before.
BTW, that design from qlogic to save log in RAM is not good one, they may save some cents for the ram in card.
other vendors seems put log/trace in the ram on card.
Thanks
Yinghai
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2010-07-28 09:26:46
On Tue, 2010-07-27 at 23:01 -0700, David Miller wrote:
quoted
On x86, physical address 0 contains the real-mode IVT and will thus be
reserved, at least for the forseeable future. Other architectures may
very well have non-special RAM there.
0 is very much possible on sparc64
Yup, we need to fix that.
For now I made MEMBLOCK_ERROR 0 and added a blurb to prevent allocating
the first page since it would cause other problems with the current code
(0 is after all the normal error result from membloc_alloc(), ie, our
API wasn't quite consistent there).
So I don't think I'm introducing a regression here, on the contrary. But
if we are going to allow lmb_alloc() to return 0, we need to fix all
callers first and then we can look into turning MEMBLOCK_ERROR back to
~0
Cheers,
Ben.
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2010-07-28 09:30:06
On Tue, 2010-07-27 at 23:13 -0700, Yinghai Lu wrote:
So still keep MEMBLOCK_ERROR to (~(phys_addr_t)0) ?
No point for now. lmb_alloc() etc... are defined as returning 0 for
failure so we would need to fix that too.
As I said in a previous email we do need to revisit the memblock error
handling.
We can change some variable from unsigned long to phys_addr_t that
will be assigned by memblock_find_base().
that could avoid casting too.
That would be a good idea anyways if those are indeed carrying a
physical address.
Ben.
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2010-07-28 10:02:46
On Tue, 2010-07-27 at 23:08 -0700, Yinghai Lu wrote:
for example:
high/low allocation, from first kernel to kexec second kernel, always
work fine except system with Qlogic card.
because Qlogic card is using main RAM as EFT etc for card's FW log
trace. second kernel have not idea that those RAM
is used by first kernel for that purpose. that the CARD still use
that between two kernels.
second kernel could have crash it try to use those ram.
low/high allocation seems to be safe, second kernel can slip to boot
fine.
No, it works 'by chance'. You need kexec to somewhat mark those regions
as reserved. I don't know how x86 does those things, on architectures
using the flat device-tree, we have added a concept of "reserve map" to
the flat device tree blob to mark that kind of region.
Also, because you mark your new function as weak but not the one that's
actually used by memblock_alloc(), it will still end up being top-down,
so if you want to switch to bottom up, make the internal function weak,
not the wrapper.
Cheers,
Ben.
From: "H. Peter Anvin" <hpa@zytor.com> Date: 2010-07-28 16:06:56
On 07/28/2010 12:12 AM, Yinghai Lu wrote:
the problem is later if the user hit the problem, it will be called "Regression" after bisecting to the memblock/x86 changes.
because low/high does work before.
BTW, that design from qlogic to save log in RAM is not good one, they may save some cents for the ram in card.
other vendors seems put log/trace in the ram on card.
It's broken NOW. The only reason it's not exploding is by accident.
The fact that you knew about the problem and had the notion of working
around it instead of fixing the root cause by either fixing or
blacklisting the broken driver is disgusting beyond belief.
Either the driver needs to map the memory off limit in the e820 map
passed to kexec, or better yet it should have its DMA disabled across
kexec. I'm truly appalled.
-hpa
--
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel. I don't speak on their behalf.
From: James Bottomley <James.Bottomley@HansenPartnership.com> Date: 2010-07-28 17:02:36
On Tue, 2010-07-27 at 23:38 -0700, H. Peter Anvin wrote:
On 07/27/2010 11:08 PM, Yinghai Lu wrote:
quoted
for example:
high/low allocation, from first kernel to kexec second kernel, always work fine except system with Qlogic card.
because Qlogic card is using main RAM as EFT etc for card's FW log trace. second kernel have not idea that those RAM
is used by first kernel for that purpose. that the CARD still use that between two kernels.
second kernel could have crash it try to use those ram.
Uhm, no. That's a bug in the Qlogic driver not shutting the card down
cleanly. Hacking around that in memory allocation order is braindamaged
in the extreme. kexec *cannot* be safe in any way if we don't shut down
pending DMA, and what you describe above is DMA.
That's not the kexec for crash dump requirement as it was communicated
to us. We were specifically told that the shutdown routines *may* not
be called before booting the kexec kernel and thus we have to take
action to stop the DMA engines in the init routines so the kexec kernel
can halt all in-progress DMA as it boots. This implies that kexec must
be able to cope with in-progress DMA.
James
From: "H. Peter Anvin" <hpa@zytor.com> Date: 2010-07-28 17:54:48
On 07/28/2010 10:02 AM, James Bottomley wrote:
On Tue, 2010-07-27 at 23:38 -0700, H. Peter Anvin wrote:
quoted
On 07/27/2010 11:08 PM, Yinghai Lu wrote:
quoted
for example:
high/low allocation, from first kernel to kexec second kernel, always work fine except system with Qlogic card.
because Qlogic card is using main RAM as EFT etc for card's FW log trace. second kernel have not idea that those RAM
is used by first kernel for that purpose. that the CARD still use that between two kernels.
second kernel could have crash it try to use those ram.
Uhm, no. That's a bug in the Qlogic driver not shutting the card down
cleanly. Hacking around that in memory allocation order is braindamaged
in the extreme. kexec *cannot* be safe in any way if we don't shut down
pending DMA, and what you describe above is DMA.
That's not the kexec for crash dump requirement as it was communicated
to us. We were specifically told that the shutdown routines *may* not
be called before booting the kexec kernel and thus we have to take
action to stop the DMA engines in the init routines so the kexec kernel
can halt all in-progress DMA as it boots. This implies that kexec must
be able to cope with in-progress DMA.
kexec for crash dump is a special case: for crash dump, there is a chunk
of memory pre-reserved for the crash kernel, and that is the *only*
memory that the crash kernel will use. In other words, everything else
is reserved memory as far as the crash kernel is concerned. As such, it
should not be affected; there may be DMA still pending to the main
kernel's memory area, of course, but as far as the crash kernel is
concerned, that should just be input data.
If allocation order somehow matters for the *crash kernel*, then we have
even more fundamental problems...
Obviously, if there is DMA going on to the crash kernel reserved region
then all bets are off, but at that point the system is so screwed anyway
that it shouldn't matter.
-hpa
From: James Bottomley <James.Bottomley@HansenPartnership.com> Date: 2010-07-28 18:10:40
On Wed, 2010-07-28 at 10:53 -0700, H. Peter Anvin wrote:
On 07/28/2010 10:02 AM, James Bottomley wrote:
quoted
On Tue, 2010-07-27 at 23:38 -0700, H. Peter Anvin wrote:
quoted
On 07/27/2010 11:08 PM, Yinghai Lu wrote:
quoted
for example:
high/low allocation, from first kernel to kexec second kernel, always work fine except system with Qlogic card.
because Qlogic card is using main RAM as EFT etc for card's FW log trace. second kernel have not idea that those RAM
is used by first kernel for that purpose. that the CARD still use that between two kernels.
second kernel could have crash it try to use those ram.
Uhm, no. That's a bug in the Qlogic driver not shutting the card down
cleanly. Hacking around that in memory allocation order is braindamaged
in the extreme. kexec *cannot* be safe in any way if we don't shut down
pending DMA, and what you describe above is DMA.
That's not the kexec for crash dump requirement as it was communicated
to us. We were specifically told that the shutdown routines *may* not
be called before booting the kexec kernel and thus we have to take
action to stop the DMA engines in the init routines so the kexec kernel
can halt all in-progress DMA as it boots. This implies that kexec must
be able to cope with in-progress DMA.
kexec for crash dump is a special case: for crash dump, there is a chunk
of memory pre-reserved for the crash kernel, and that is the *only*
memory that the crash kernel will use. In other words, everything else
is reserved memory as far as the crash kernel is concerned. As such, it
should not be affected; there may be DMA still pending to the main
kernel's memory area, of course, but as far as the crash kernel is
concerned, that should just be input data.
If allocation order somehow matters for the *crash kernel*, then we have
even more fundamental problems...
Obviously, if there is DMA going on to the crash kernel reserved region
then all bets are off, but at that point the system is so screwed anyway
that it shouldn't matter.
So I don't understand the problem. Proper shutdown of the old kernel
will halt all the DMA engines (by design ... we can't have DMA ongoing
if the next action might be power off). The only case I know where DMA
engines may be active is the crash kernel case.
James
From: "H. Peter Anvin" <hpa@zytor.com> Date: 2010-07-28 18:30:55
On 07/28/2010 11:10 AM, James Bottomley wrote:
So I don't understand the problem. Proper shutdown of the old kernel
will halt all the DMA engines (by design ... we can't have DMA ongoing
if the next action might be power off). The only case I know where DMA
engines may be active is the crash kernel case.
I'm not sure I fully understand the exact problem, either; not being
familiar with this putative "logging" facility of the Qlogic devices.
My point was largely that if a device causes failures because of the
choice of the allocation order, then we have a much bigger problem and
papering over it by trying to muck with the allocation order is just wrong.
This logging facility of Qlogic is DMA, no more, no less. It needs to
be shut down on a "overwrite" kexec, where we replace one kernel with
another, as opposed to a crash dump kexec, where we use a reserved chunk
of virgin memory. What I don't know/understand at the moment is if
there is something "special" about this particular logging facility,
e.g. if the Qlogic card ignore the bus mastering control bit -- which
would be reckless but I can see someone having the bright idea to do that.
Yinghai, do you have any more detail, or know who would? Also copying
the Qlogic Infinipath maintainer email...
-hpa
From: Yinghai Lu <yinghai@kernel.org> Date: 2010-07-28 19:29:09
On 07/28/2010 11:30 AM, H. Peter Anvin wrote:
On 07/28/2010 11:10 AM, James Bottomley wrote:
quoted
So I don't understand the problem. Proper shutdown of the old kernel
will halt all the DMA engines (by design ... we can't have DMA ongoing
if the next action might be power off). The only case I know where DMA
engines may be active is the crash kernel case.
I'm not sure I fully understand the exact problem, either; not being
familiar with this putative "logging" facility of the Qlogic devices.
My point was largely that if a device causes failures because of the
choice of the allocation order, then we have a much bigger problem and
papering over it by trying to muck with the allocation order is just wrong.
This logging facility of Qlogic is DMA, no more, no less. It needs to
be shut down on a "overwrite" kexec, where we replace one kernel with
another, as opposed to a crash dump kexec, where we use a reserved chunk
of virgin memory. What I don't know/understand at the moment is if
there is something "special" about this particular logging facility,
e.g. if the Qlogic card ignore the bus mastering control bit -- which
would be reckless but I can see someone having the bright idea to do that.
Yinghai, do you have any more detail, or know who would? Also copying
the Qlogic Infinipath maintainer email...
when I was debug memblock with x86, found the strange crash when high/low.
then use kexec with "memtest" in command line, and the early memtest does find
some bad memory.
then I add more print about EPT physical address for first kernel,
it does show that range is used by qla driver in first kernel.
I built all needed drivers in kernel so can pxeboot the kernel on all test platforms easily.
Thanks
Yinghai
---
drivers/scsi/qla2xxx/qla_init.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
Index: linux-2.6/drivers/scsi/qla2xxx/qla_init.c
===================================================================
@@ -1327,8 +1327,8 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vgototry_eft;}-qla_printk(KERN_INFO,ha,"Allocated (%d KB) for FCE...\n",-FCE_SIZE/1024);+qla_printk(KERN_INFO,ha,"Allocated (%d KB) at %p for FCE...\n",+FCE_SIZE/1024,tc);fce_size=sizeof(structqla2xxx_fce_chain)+FCE_SIZE;ha->flags.fce_enabled=1;
@@ -1354,8 +1354,8 @@ try_eft:gotocont_alloc;}-qla_printk(KERN_INFO,ha,"Allocated (%d KB) for EFT...\n",-EFT_SIZE/1024);+qla_printk(KERN_INFO,ha,"Allocated (%d KB) at %p for EFT...\n",+EFT_SIZE/1024,tc);eft_size=EFT_SIZE;ha->eft_dma=tc_dma;
@@ -1383,8 +1383,8 @@ cont_alloc:}return;}-qla_printk(KERN_INFO,ha,"Allocated (%d KB) for firmware dump...\n",-dump_size/1024);+qla_printk(KERN_INFO,ha,"Allocated (%d KB) at %p for firmware dump...\n",+dump_size/1024,ha->fw_dump);ha->fw_dump_len=dump_size;ha->fw_dump->signature[0]='Q';
From: "H. Peter Anvin" <hpa@zytor.com> Date: 2010-07-28 20:00:10
On 07/28/2010 12:27 PM, Yinghai Lu wrote:
quoted
Yinghai, do you have any more detail, or know who would? Also copying
the Qlogic Infinipath maintainer email...
when I was debug memblock with x86, found the strange crash when high/low.
then use kexec with "memtest" in command line, and the early memtest does find
some bad memory.
then I add more print about EPT physical address for first kernel,
it does show that range is used by qla driver in first kernel.
I built all needed drivers in kernel so can pxeboot the kernel on all test platforms easily.
[Cc: Andrew Vasquez, who seems to have written the offending code,
checkin df613b96077cee826b14089ae6e75eeabf71faa3.]
The question is still open why this particular DMA activity was not shut
down before the kexec. I'm not familiar with how non-crashdump kexec
idles the hardware, but it obviously better do so.
-hpa
From: Ralph Campbell <hidden> Date: 2010-07-28 22:58:33
On Wed, 2010-07-28 at 11:30 -0700, H. Peter Anvin wrote:
On 07/28/2010 11:10 AM, James Bottomley wrote:
quoted
So I don't understand the problem. Proper shutdown of the old kernel
will halt all the DMA engines (by design ... we can't have DMA ongoing
if the next action might be power off). The only case I know where DMA
engines may be active is the crash kernel case.
I'm not sure I fully understand the exact problem, either; not being
familiar with this putative "logging" facility of the Qlogic devices.
My point was largely that if a device causes failures because of the
choice of the allocation order, then we have a much bigger problem and
papering over it by trying to muck with the allocation order is just wrong.
This logging facility of Qlogic is DMA, no more, no less. It needs to
be shut down on a "overwrite" kexec, where we replace one kernel with
another, as opposed to a crash dump kexec, where we use a reserved chunk
of virgin memory. What I don't know/understand at the moment is if
there is something "special" about this particular logging facility,
e.g. if the Qlogic card ignore the bus mastering control bit -- which
would be reckless but I can see someone having the bright idea to do that.
Yinghai, do you have any more detail, or know who would? Also copying
the Qlogic Infinipath maintainer email...
-hpa
I read the messages in this thread but I don't understand what the
problem is. Something to do with logging, DMA and crash dumps but
it also sounds like the original discussion may be confused about
how the Infiniband HCA cards work.
Can someone summarize what is going on...
From: "H. Peter Anvin" <hpa@zytor.com> Date: 2010-07-28 23:42:53
On 07/28/2010 03:58 PM, Ralph Campbell wrote:
I read the messages in this thread but I don't understand what the
problem is. Something to do with logging, DMA and crash dumps but
it also sounds like the original discussion may be confused about
how the Infiniband HCA cards work.
Can someone summarize what is going on...
Sorry, I was confused... this had to do with the qla driver, not Infinipath.
-hpa