* [PATCH -v4 00/08] use lmb with x86
@ 2010-03-24 10:37 Yinghai Lu
2010-03-24 10:37 ` [PATCH 1/8] x86: do not free zero sized per cpu areas Yinghai Lu
` (8 more replies)
0 siblings, 9 replies; 16+ messages in thread
From: Yinghai Lu @ 2010-03-24 10:37 UTC (permalink / raw)
To: Ingo Molnar, Thomas Gleixner, H. Peter Anvin, Andrew Morton,
David Miller, Benjamin Herrenschmidt, Linus Torvalds
Cc: linux-kernel, Yinghai Lu
new early_res is lmb extension. and it could be used to replace bootmem.
even could share some code before bootmem, like register_active_region, and
lm_reserved_to_bootmem
add test version for powerpc
Thanks
Yinghai
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 1/8] x86: do not free zero sized per cpu areas
2010-03-24 10:37 [PATCH -v4 00/08] use lmb with x86 Yinghai Lu
@ 2010-03-24 10:37 ` Yinghai Lu
2010-03-25 22:29 ` Joel Becker
2010-03-24 10:37 ` [PATCH 2/8] x86: add find_e820_area_node Yinghai Lu
` (7 subsequent siblings)
8 siblings, 1 reply; 16+ messages in thread
From: Yinghai Lu @ 2010-03-24 10:37 UTC (permalink / raw)
To: Ingo Molnar, Thomas Gleixner, H. Peter Anvin, Andrew Morton,
David Miller, Benjamin Herrenschmidt, Linus Torvalds
Cc: linux-kernel, Ian Campbell, Yinghai Lu, Peter Zijlstra, Ingo Molnar
From: Ian Campbell <ian.campbell@citrix.com>
This avoids an infinite loop in free_early_partial().
Add a warning to free_early_partial to catch future problems.
-v5: put back start > end back into WARN_ONCE()
-v6: use one line for if according to linus
Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ingo Molnar <mingo@elte.hu>
---
kernel/early_res.c | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/kernel/early_res.c b/kernel/early_res.c
index 3cb2c66..69bed5b 100644
--- a/kernel/early_res.c
+++ b/kernel/early_res.c
@@ -333,6 +333,12 @@ void __init free_early_partial(u64 start, u64 end)
struct early_res *r;
int i;
+ if (start == end)
+ return;
+
+ if (WARN_ONCE(start > end, "free_early_partial: wrong range [%#llx, %#llx]\n", start, end))
+ return;
+
try_next:
i = find_overlapped_early(start, end);
if (i >= max_early_res)
--
1.6.4.2
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 2/8] x86: add find_e820_area_node
2010-03-24 10:37 [PATCH -v4 00/08] use lmb with x86 Yinghai Lu
2010-03-24 10:37 ` [PATCH 1/8] x86: do not free zero sized per cpu areas Yinghai Lu
@ 2010-03-24 10:37 ` Yinghai Lu
2010-03-24 10:37 ` [PATCH 3/8] x86: add sanitize_e820_map Yinghai Lu
` (6 subsequent siblings)
8 siblings, 0 replies; 16+ messages in thread
From: Yinghai Lu @ 2010-03-24 10:37 UTC (permalink / raw)
To: Ingo Molnar, Thomas Gleixner, H. Peter Anvin, Andrew Morton,
David Miller, Benjamin Herrenschmidt, Linus Torvalds
Cc: linux-kernel, Yinghai Lu
David Miller pointed out that early_res have problem to find node data on correct node
when we have
node0: [0, 2g), [4g, 6g), [10g, 14g)
node1: [6g, 10g), [14g, 18g)
the cross node case
the problem is there for x86 bits even before we are using early_res for bootmem replacement.
after early_res for bootmem replacement, alloc_bootmem_node still can get range on correct node
this patch is fixing problem before bootmem or early_res replacement for bootmem.
now only user is for x86 64bit numa to find node data.
the point is use early_node_map with find_e820_area_node()
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
arch/x86/include/asm/e820.h | 1 +
arch/x86/kernel/e820.c | 15 +++++++++++++++
arch/x86/mm/numa_64.c | 4 ++--
include/linux/mm.h | 2 ++
mm/page_alloc.c | 37 +++++++++++++++++++++++--------------
5 files changed, 43 insertions(+), 16 deletions(-)
diff --git a/arch/x86/include/asm/e820.h b/arch/x86/include/asm/e820.h
index ec8a52d..41553af 100644
--- a/arch/x86/include/asm/e820.h
+++ b/arch/x86/include/asm/e820.h
@@ -116,6 +116,7 @@ extern unsigned long end_user_pfn;
extern u64 find_e820_area(u64 start, u64 end, u64 size, u64 align);
extern u64 find_e820_area_size(u64 start, u64 *sizep, u64 align);
+u64 find_e820_area_node(int nid, u64 start, u64 end, u64 size, u64 align);
extern u64 early_reserve_e820(u64 startt, u64 sizet, u64 align);
#include <linux/early_res.h>
diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c
index 740b440..05ee724 100644
--- a/arch/x86/kernel/e820.c
+++ b/arch/x86/kernel/e820.c
@@ -787,6 +787,21 @@ u64 __init find_e820_area_size(u64 start, u64 *sizep, u64 align)
return -1ULL;
}
+u64 __init find_e820_area_node(int nid, u64 start, u64 end, u64 size, u64 align)
+{
+ u64 addr;
+ /*
+ * need to call this function after e820_register_active_regions
+ * so early_node_map[] is set
+ */
+ addr = find_memory_core_early(nid, size, align, start, end);
+ if (addr != -1ULL)
+ return addr;
+
+ /* fallback, should already have start end in the node range */
+ return find_e820_area(start, end, size, align);
+}
+
/*
* pre allocated 4k and reserved it in e820
*/
diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c
index 8948f47..ffc5ad5 100644
--- a/arch/x86/mm/numa_64.c
+++ b/arch/x86/mm/numa_64.c
@@ -174,7 +174,7 @@ static void * __init early_node_mem(int nodeid, unsigned long start,
if (start < (MAX_DMA32_PFN<<PAGE_SHIFT) &&
end > (MAX_DMA32_PFN<<PAGE_SHIFT))
start = MAX_DMA32_PFN<<PAGE_SHIFT;
- mem = find_e820_area(start, end, size, align);
+ mem = find_e820_area_node(nodeid, start, end, size, align);
if (mem != -1L)
return __va(mem);
@@ -184,7 +184,7 @@ static void * __init early_node_mem(int nodeid, unsigned long start,
start = MAX_DMA32_PFN<<PAGE_SHIFT;
else
start = MAX_DMA_PFN<<PAGE_SHIFT;
- mem = find_e820_area(start, end, size, align);
+ mem = find_e820_area_node(nodeid, start, end, size, align);
if (mem != -1L)
return __va(mem);
diff --git a/include/linux/mm.h b/include/linux/mm.h
index e70f21b..5c2d17e 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1160,6 +1160,8 @@ extern void free_bootmem_with_active_regions(int nid,
unsigned long max_low_pfn);
int add_from_early_node_map(struct range *range, int az,
int nr_range, int nid);
+u64 __init find_memory_core_early(int nid, u64 size, u64 align,
+ u64 goal, u64 limit);
void *__alloc_memory_core_early(int nodeid, u64 size, u64 align,
u64 goal, u64 limit);
typedef int (*work_fn_t)(unsigned long, unsigned long, void *);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index d03c946..eef3757 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -3408,12 +3408,11 @@ int __init add_from_early_node_map(struct range *range, int az,
return nr_range;
}
-#ifdef CONFIG_NO_BOOTMEM
-void * __init __alloc_memory_core_early(int nid, u64 size, u64 align,
+#ifdef CONFIG_HAVE_EARLY_RES
+u64 __init find_memory_core_early(int nid, u64 size, u64 align,
u64 goal, u64 limit)
{
int i;
- void *ptr;
/* need to go over early_node_map to find out good range for node */
for_each_active_range_index_in_nid(i, nid) {
@@ -3430,20 +3429,30 @@ void * __init __alloc_memory_core_early(int nid, u64 size, u64 align,
if (addr == -1ULL)
continue;
-#if 0
- printk(KERN_DEBUG "alloc (nid=%d %llx - %llx) (%llx - %llx) %llx %llx => %llx\n",
- nid,
- ei_start, ei_last, goal, limit, size,
- align, addr);
+ return addr;
+ }
+
+ return -1ULL;
+}
#endif
- ptr = phys_to_virt(addr);
- memset(ptr, 0, size);
- reserve_early_without_check(addr, addr + size, "BOOTMEM");
- return ptr;
- }
+#ifdef CONFIG_NO_BOOTMEM
+void * __init __alloc_memory_core_early(int nid, u64 size, u64 align,
+ u64 goal, u64 limit)
+{
+ void *ptr;
- return NULL;
+ u64 addr;
+
+ addr = find_memory_core_early(nid, size, align, goal, limit);
+
+ if (addr == -1ULL)
+ return NULL;
+
+ ptr = phys_to_virt(addr);
+ memset(ptr, 0, size);
+ reserve_early_without_check(addr, addr + size, "BOOTMEM");
+ return ptr;
}
#endif
--
1.6.4.2
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 3/8] x86: add sanitize_e820_map
2010-03-24 10:37 [PATCH -v4 00/08] use lmb with x86 Yinghai Lu
2010-03-24 10:37 ` [PATCH 1/8] x86: do not free zero sized per cpu areas Yinghai Lu
2010-03-24 10:37 ` [PATCH 2/8] x86: add find_e820_area_node Yinghai Lu
@ 2010-03-24 10:37 ` Yinghai Lu
2010-03-24 10:37 ` [PATCH 4/8] lmb: seperate region array from lmb_region struct Yinghai Lu
` (5 subsequent siblings)
8 siblings, 0 replies; 16+ messages in thread
From: Yinghai Lu @ 2010-03-24 10:37 UTC (permalink / raw)
To: Ingo Molnar, Thomas Gleixner, H. Peter Anvin, Andrew Morton,
David Miller, Benjamin Herrenschmidt, Linus Torvalds
Cc: linux-kernel, Yinghai Lu
so we could not take e820.map directly.
and could change e820_saved to initdata
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
arch/x86/include/asm/e820.h | 5 ++---
arch/x86/kernel/e820.c | 26 ++++++++++++++++++--------
arch/x86/kernel/efi.c | 2 +-
arch/x86/kernel/setup.c | 10 +++++-----
arch/x86/xen/setup.c | 4 +---
5 files changed, 27 insertions(+), 20 deletions(-)
diff --git a/arch/x86/include/asm/e820.h b/arch/x86/include/asm/e820.h
index 41553af..01bc987 100644
--- a/arch/x86/include/asm/e820.h
+++ b/arch/x86/include/asm/e820.h
@@ -75,15 +75,14 @@ struct e820map {
#ifdef __KERNEL__
/* see comment in arch/x86/kernel/e820.c */
extern struct e820map e820;
-extern struct e820map e820_saved;
extern unsigned long pci_mem_start;
extern int e820_any_mapped(u64 start, u64 end, unsigned type);
extern int e820_all_mapped(u64 start, u64 end, unsigned type);
extern void e820_add_region(u64 start, u64 size, int type);
extern void e820_print_map(char *who);
-extern int
-sanitize_e820_map(struct e820entry *biosmap, int max_nr_map, u32 *pnr_map);
+int sanitize_e820_map(void);
+void save_e820_map(void);
extern u64 e820_update_range(u64 start, u64 size, unsigned old_type,
unsigned new_type);
extern u64 e820_remove_range(u64 start, u64 size, unsigned old_type,
diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c
index 05ee724..0c7143b 100644
--- a/arch/x86/kernel/e820.c
+++ b/arch/x86/kernel/e820.c
@@ -35,7 +35,7 @@
* next kernel with full memory.
*/
struct e820map e820;
-struct e820map e820_saved;
+static struct e820map __initdata e820_saved;
/* For PCI or other memory-mapped resources */
unsigned long pci_mem_start = 0xaeedbabe;
@@ -224,7 +224,7 @@ void __init e820_print_map(char *who)
* ______________________4_
*/
-int __init sanitize_e820_map(struct e820entry *biosmap, int max_nr_map,
+static int __init __sanitize_e820_map(struct e820entry *biosmap, int max_nr_map,
u32 *pnr_map)
{
struct change_member {
@@ -383,6 +383,11 @@ int __init sanitize_e820_map(struct e820entry *biosmap, int max_nr_map,
return 0;
}
+int __init sanitize_e820_map(void)
+{
+ return __sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
+}
+
static int __init __append_e820_map(struct e820entry *biosmap, int nr_map)
{
while (nr_map) {
@@ -555,7 +560,7 @@ void __init update_e820(void)
u32 nr_map;
nr_map = e820.nr_map;
- if (sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &nr_map))
+ if (__sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &nr_map))
return;
e820.nr_map = nr_map;
printk(KERN_INFO "modified physical RAM map:\n");
@@ -566,7 +571,7 @@ static void __init update_e820_saved(void)
u32 nr_map;
nr_map = e820_saved.nr_map;
- if (sanitize_e820_map(e820_saved.map, ARRAY_SIZE(e820_saved.map), &nr_map))
+ if (__sanitize_e820_map(e820_saved.map, ARRAY_SIZE(e820_saved.map), &nr_map))
return;
e820_saved.nr_map = nr_map;
}
@@ -661,7 +666,7 @@ void __init parse_e820_ext(struct setup_data *sdata, unsigned long pa_data)
sdata = early_ioremap(pa_data, map_len);
extmap = (struct e820entry *)(sdata->data);
__append_e820_map(extmap, entries);
- sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
+ sanitize_e820_map();
if (map_len > PAGE_SIZE)
early_iounmap(sdata, map_len);
printk(KERN_INFO "extended physical RAM map:\n");
@@ -1043,7 +1048,7 @@ void __init finish_e820_parsing(void)
if (userdef) {
u32 nr = e820.nr_map;
- if (sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &nr) < 0)
+ if (__sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &nr) < 0)
early_panic("Invalid user supplied memory map");
e820.nr_map = nr;
@@ -1173,7 +1178,7 @@ char *__init default_machine_specific_memory_setup(void)
* the next section from 1mb->appropriate_mem_k
*/
new_nr = boot_params.e820_entries;
- sanitize_e820_map(boot_params.e820_map,
+ __sanitize_e820_map(boot_params.e820_map,
ARRAY_SIZE(boot_params.e820_map),
&new_nr);
boot_params.e820_entries = new_nr;
@@ -1200,12 +1205,17 @@ char *__init default_machine_specific_memory_setup(void)
return who;
}
+void __init save_e820_map(void)
+{
+ memcpy(&e820_saved, &e820, sizeof(struct e820map));
+}
+
void __init setup_memory_map(void)
{
char *who;
who = x86_init.resources.memory_setup();
- memcpy(&e820_saved, &e820, sizeof(struct e820map));
+ save_e820_map();
printk(KERN_INFO "BIOS-provided physical RAM map:\n");
e820_print_map(who);
}
diff --git a/arch/x86/kernel/efi.c b/arch/x86/kernel/efi.c
index c2fa9b8..299f03f 100644
--- a/arch/x86/kernel/efi.c
+++ b/arch/x86/kernel/efi.c
@@ -272,7 +272,7 @@ static void __init do_add_efi_memmap(void)
}
e820_add_region(start, size, e820_type);
}
- sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
+ sanitize_e820_map();
}
void __init efi_reserve_early(void)
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 5d7ba1a..3787a82 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -461,8 +461,8 @@ static void __init e820_reserve_setup_data(void)
if (!found)
return;
- sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
- memcpy(&e820_saved, &e820, sizeof(struct e820map));
+ sanitize_e820_map();
+ save_e820_map();
printk(KERN_INFO "extended physical RAM map:\n");
e820_print_map("reserve setup_data");
}
@@ -614,7 +614,7 @@ static int __init dmi_low_memory_corruption(const struct dmi_system_id *d)
d->ident);
e820_update_range(0, 0x10000, E820_RAM, E820_RESERVED);
- sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
+ sanitize_e820_map();
return 0;
}
@@ -683,7 +683,7 @@ static void __init trim_bios_range(void)
* take them out.
*/
e820_remove_range(BIOS_BEGIN, BIOS_END - BIOS_BEGIN, E820_RAM, 1);
- sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
+ sanitize_e820_map();
}
/*
@@ -854,7 +854,7 @@ void __init setup_arch(char **cmdline_p)
if (ppro_with_ram_bug()) {
e820_update_range(0x70000000ULL, 0x40000ULL, E820_RAM,
E820_RESERVED);
- sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
+ sanitize_e820_map();
printk(KERN_INFO "fixed physical RAM map:\n");
e820_print_map("bad_ppro");
}
diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c
index ad0047f..3f2c411 100644
--- a/arch/x86/xen/setup.c
+++ b/arch/x86/xen/setup.c
@@ -43,8 +43,6 @@ char * __init xen_memory_setup(void)
max_pfn = min(MAX_DOMAIN_PAGES, max_pfn);
- e820.nr_map = 0;
-
e820_add_region(0, PFN_PHYS((u64)max_pfn), E820_RAM);
/*
@@ -65,7 +63,7 @@ char * __init xen_memory_setup(void)
__pa(xen_start_info->pt_base),
"XEN START INFO");
- sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
+ sanitize_e820_map();
return "Xen";
}
--
1.6.4.2
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 4/8] lmb: seperate region array from lmb_region struct
2010-03-24 10:37 [PATCH -v4 00/08] use lmb with x86 Yinghai Lu
` (2 preceding siblings ...)
2010-03-24 10:37 ` [PATCH 3/8] x86: add sanitize_e820_map Yinghai Lu
@ 2010-03-24 10:37 ` Yinghai Lu
2010-03-24 10:37 ` [PATCH 5/8] x86: use lmb to replace early_res Yinghai Lu
` (4 subsequent siblings)
8 siblings, 0 replies; 16+ messages in thread
From: Yinghai Lu @ 2010-03-24 10:37 UTC (permalink / raw)
To: Ingo Molnar, Thomas Gleixner, H. Peter Anvin, Andrew Morton,
David Miller, Benjamin Herrenschmidt, Linus Torvalds
Cc: linux-kernel, Yinghai Lu
lmb_init() connect them back.
also add nr_regions in lmb_region to tack the region array size.
-v3: seperate lmb core change to seperated patch
-v4: according to Ingo, change >= x -1 to > x
change region_array_size to nr_regions
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
include/linux/lmb.h | 5 ++++-
lib/lmb.c | 9 ++++++++-
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/include/linux/lmb.h b/include/linux/lmb.h
index f3d1433..37fd29e 100644
--- a/include/linux/lmb.h
+++ b/include/linux/lmb.h
@@ -26,7 +26,8 @@ struct lmb_property {
struct lmb_region {
unsigned long cnt;
u64 size;
- struct lmb_property region[MAX_LMB_REGIONS+1];
+ struct lmb_property *region;
+ unsigned long nr_regions;
};
struct lmb {
@@ -37,6 +38,8 @@ struct lmb {
};
extern struct lmb lmb;
+extern struct lmb_property lmb_memory_region[MAX_LMB_REGIONS + 1];
+extern struct lmb_property lmb_reserved_region[MAX_LMB_REGIONS + 1];
extern void __init lmb_init(void);
extern void __init lmb_analyze(void);
diff --git a/lib/lmb.c b/lib/lmb.c
index b1fc526..ed4e433 100644
--- a/lib/lmb.c
+++ b/lib/lmb.c
@@ -18,6 +18,8 @@
#define LMB_ALLOC_ANYWHERE 0
struct lmb lmb;
+struct lmb_property lmb_memory_region[MAX_LMB_REGIONS + 1];
+struct lmb_property lmb_reserved_region[MAX_LMB_REGIONS + 1];
static int lmb_debug;
@@ -106,6 +108,11 @@ static void lmb_coalesce_regions(struct lmb_region *rgn,
void __init lmb_init(void)
{
+ lmb.memory.region = lmb_memory_region;
+ lmb.reserved.region = lmb_reserved_region;
+ lmb.memory.nr_regions = ARRAY_SIZE(lmb_memory_region);
+ lmb.reserved.nr_regions = ARRAY_SIZE(lmb_reserved_region);
+
/* Create a dummy zero size LMB which will get coalesced away later.
* This simplifies the lmb_add() code below...
*/
@@ -169,7 +176,7 @@ static long lmb_add_region(struct lmb_region *rgn, u64 base, u64 size)
if (coalesced)
return coalesced;
- if (rgn->cnt >= MAX_LMB_REGIONS)
+ if (rgn->cnt > rgn->nr_regions)
return -1;
/* Couldn't coalesce the LMB, so add it to the sorted table. */
--
1.6.4.2
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 5/8] x86: use lmb to replace early_res
2010-03-24 10:37 [PATCH -v4 00/08] use lmb with x86 Yinghai Lu
` (3 preceding siblings ...)
2010-03-24 10:37 ` [PATCH 4/8] lmb: seperate region array from lmb_region struct Yinghai Lu
@ 2010-03-24 10:37 ` Yinghai Lu
2010-03-24 10:37 ` [PATCH 6/8] x86: remove find_e820_area Yinghai Lu
` (3 subsequent siblings)
8 siblings, 0 replies; 16+ messages in thread
From: Yinghai Lu @ 2010-03-24 10:37 UTC (permalink / raw)
To: Ingo Molnar, Thomas Gleixner, H. Peter Anvin, Andrew Morton,
David Miller, Benjamin Herrenschmidt, Linus Torvalds
Cc: linux-kernel, Yinghai Lu
still keep kernel/early_res.c for the extension.
should move those file to lib/lmb.c later?
in early_res.c
1. change find_e820_area_xxx, to find_lmb_area_xxx
2. e820_register_active_regions to lmb_register_active_regions.
3. reserve_early will call lmb_reserve directly.
4. free_early will call lmb_free directly.
5. remove functions that are used by old reserve_early and free_early
6. get_free_all_memory_range use lmb.reserved.
7. early_res_to_bootmem use lmb.reserved
8. add fill_lmb_memory() to fill lmb.memory according e820 RAM entries
-v2: fix NO_BOOTMEM hang with printk
-v4: add add_lmb_memory that could increase lmb.memory.region size
change region_array_size to nr_regions
make sure some find_lmb_area<_size> are called after fill_lmb_memory
todo:
1. make early_memtest to depend on early_res. and move it to mm/
2. make all lmb user to use extend early_res/nobootmem
3. merge lmb.c and early_res.c, move it to mm/
4. make other platform to use lmb/early_res/nobootmem
5. remove BOOTMEM related code
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
arch/x86/Kconfig | 1 +
arch/x86/include/asm/e820.h | 38 ++-
arch/x86/include/asm/lmb.h | 8 +
arch/x86/kernel/check.c | 14 +-
arch/x86/kernel/e820.c | 171 ++---------
arch/x86/kernel/head.c | 2 +-
arch/x86/kernel/head32.c | 5 +-
arch/x86/kernel/head64.c | 2 +
arch/x86/kernel/setup.c | 9 +-
arch/x86/kernel/setup_percpu.c | 6 -
arch/x86/mm/memtest.c | 5 +-
arch/x86/mm/numa_64.c | 4 +-
include/linux/early_res.h | 19 +-
kernel/early_res.c | 631 ++++++++++++++++------------------------
mm/page_alloc.c | 2 +-
mm/sparse-vmemmap.c | 11 -
16 files changed, 344 insertions(+), 584 deletions(-)
create mode 100644 arch/x86/include/asm/lmb.h
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 6a80bce..585f611 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -27,6 +27,7 @@ config X86
select HAVE_PERF_EVENTS if (!M386 && !M486)
select HAVE_IOREMAP_PROT
select HAVE_KPROBES
+ select HAVE_LMB
select ARCH_WANT_OPTIONAL_GPIOLIB
select ARCH_WANT_FRAME_POINTERS
select HAVE_DMA_ATTRS
diff --git a/arch/x86/include/asm/e820.h b/arch/x86/include/asm/e820.h
index 01bc987..e957101 100644
--- a/arch/x86/include/asm/e820.h
+++ b/arch/x86/include/asm/e820.h
@@ -111,24 +111,30 @@ static inline void early_memtest(unsigned long start, unsigned long end)
}
#endif
-extern unsigned long end_user_pfn;
-
-extern u64 find_e820_area(u64 start, u64 end, u64 size, u64 align);
-extern u64 find_e820_area_size(u64 start, u64 *sizep, u64 align);
-u64 find_e820_area_node(int nid, u64 start, u64 end, u64 size, u64 align);
-extern u64 early_reserve_e820(u64 startt, u64 sizet, u64 align);
-#include <linux/early_res.h>
-
extern unsigned long e820_end_of_ram_pfn(void);
extern unsigned long e820_end_of_low_ram_pfn(void);
-extern int e820_find_active_region(const struct e820entry *ei,
- unsigned long start_pfn,
- unsigned long last_pfn,
- unsigned long *ei_startpfn,
- unsigned long *ei_endpfn);
-extern void e820_register_active_regions(int nid, unsigned long start_pfn,
- unsigned long end_pfn);
-extern u64 e820_hole_size(u64 start, u64 end);
+#include <linux/early_res.h>
+extern u64 early_reserve_e820(u64 startt, u64 sizet, u64 align);
+
+/*
+ * next three functions will be removed, esp find_e820_area()
+ * can not be used before fill_lmb_memory()
+ */
+static inline u64 find_e820_area(u64 start, u64 end, u64 size, u64 align)
+{
+ return find_lmb_area(start, end, size, align);
+}
+static inline void e820_register_active_regions(int nid, unsigned long start_pfn, unsigned long end_pfn)
+{
+ lmb_register_active_regions(nid, start_pfn, end_pfn);
+}
+static inline u64 e820_hole_size(u64 start, u64 end)
+{
+ return lmb_hole_size(start, end);
+}
+
+void init_lmb_memory(void);
+void fill_lmb_memory(void);
extern void finish_e820_parsing(void);
extern void e820_reserve_resources(void);
extern void e820_reserve_resources_late(void);
diff --git a/arch/x86/include/asm/lmb.h b/arch/x86/include/asm/lmb.h
new file mode 100644
index 0000000..d8fbdbd
--- /dev/null
+++ b/arch/x86/include/asm/lmb.h
@@ -0,0 +1,8 @@
+#ifndef _X86_LMB_H
+#define _X86_LMB_H
+
+#define LMB_DBG(fmt...) printk(fmt)
+
+#define LMB_REAL_LIMIT 0
+
+#endif
diff --git a/arch/x86/kernel/check.c b/arch/x86/kernel/check.c
index fc999e6..e16952b 100644
--- a/arch/x86/kernel/check.c
+++ b/arch/x86/kernel/check.c
@@ -2,7 +2,8 @@
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/workqueue.h>
-#include <asm/e820.h>
+#include <linux/early_res.h>
+
#include <asm/proto.h>
/*
@@ -18,10 +19,12 @@ static int __read_mostly memory_corruption_check = -1;
static unsigned __read_mostly corruption_check_size = 64*1024;
static unsigned __read_mostly corruption_check_period = 60; /* seconds */
-static struct e820entry scan_areas[MAX_SCAN_AREAS];
+static struct scan_area {
+ u64 addr;
+ u64 size;
+} scan_areas[MAX_SCAN_AREAS];
static int num_scan_areas;
-
static __init int set_corruption_check(char *arg)
{
char *end;
@@ -81,7 +84,7 @@ void __init setup_bios_corruption_check(void)
while (addr < corruption_check_size && num_scan_areas < MAX_SCAN_AREAS) {
u64 size;
- addr = find_e820_area_size(addr, &size, PAGE_SIZE);
+ addr = find_lmb_area_size(addr, &size, PAGE_SIZE);
if (!(addr + 1))
break;
@@ -92,7 +95,7 @@ void __init setup_bios_corruption_check(void)
if ((addr + size) > corruption_check_size)
size = corruption_check_size - addr;
- e820_update_range(addr, size, E820_RAM, E820_RESERVED);
+ reserve_early(addr, addr + size, "SCAN RAM");
scan_areas[num_scan_areas].addr = addr;
scan_areas[num_scan_areas].size = size;
num_scan_areas++;
@@ -105,7 +108,6 @@ void __init setup_bios_corruption_check(void)
printk(KERN_INFO "Scanning %d areas for low memory corruption\n",
num_scan_areas);
- update_e820();
}
diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c
index 0c7143b..8381b1b 100644
--- a/arch/x86/kernel/e820.c
+++ b/arch/x86/kernel/e820.c
@@ -15,6 +15,7 @@
#include <linux/pfn.h>
#include <linux/suspend.h>
#include <linux/firmware-map.h>
+#include <linux/lmb.h>
#include <asm/e820.h>
#include <asm/proto.h>
@@ -726,37 +727,6 @@ static int __init e820_mark_nvs_memory(void)
core_initcall(e820_mark_nvs_memory);
#endif
-/*
- * Find a free area with specified alignment in a specific range.
- */
-u64 __init find_e820_area(u64 start, u64 end, u64 size, u64 align)
-{
- int i;
-
- for (i = 0; i < e820.nr_map; i++) {
- struct e820entry *ei = &e820.map[i];
- u64 addr;
- u64 ei_start, ei_last;
-
- if (ei->type != E820_RAM)
- continue;
-
- ei_last = ei->addr + ei->size;
- ei_start = ei->addr;
- addr = find_early_area(ei_start, ei_last, start, end,
- size, align);
-
- if (addr != -1ULL)
- return addr;
- }
- return -1ULL;
-}
-
-u64 __init find_fw_memmap_area(u64 start, u64 end, u64 size, u64 align)
-{
- return find_e820_area(start, end, size, align);
-}
-
u64 __init get_max_mapped(void)
{
u64 end = max_pfn_mapped;
@@ -765,50 +735,9 @@ u64 __init get_max_mapped(void)
return end;
}
-/*
- * Find next free range after *start
- */
-u64 __init find_e820_area_size(u64 start, u64 *sizep, u64 align)
-{
- int i;
-
- for (i = 0; i < e820.nr_map; i++) {
- struct e820entry *ei = &e820.map[i];
- u64 addr;
- u64 ei_start, ei_last;
-
- if (ei->type != E820_RAM)
- continue;
-
- ei_last = ei->addr + ei->size;
- ei_start = ei->addr;
- addr = find_early_area_size(ei_start, ei_last, start,
- sizep, align);
-
- if (addr != -1ULL)
- return addr;
- }
-
- return -1ULL;
-}
-
-u64 __init find_e820_area_node(int nid, u64 start, u64 end, u64 size, u64 align)
-{
- u64 addr;
- /*
- * need to call this function after e820_register_active_regions
- * so early_node_map[] is set
- */
- addr = find_memory_core_early(nid, size, align, start, end);
- if (addr != -1ULL)
- return addr;
-
- /* fallback, should already have start end in the node range */
- return find_e820_area(start, end, size, align);
-}
/*
- * pre allocated 4k and reserved it in e820
+ * pre allocated 4k and reserved it in lmb and e820_saved
*/
u64 __init early_reserve_e820(u64 startt, u64 sizet, u64 align)
{
@@ -817,7 +746,7 @@ u64 __init early_reserve_e820(u64 startt, u64 sizet, u64 align)
u64 start;
for (start = startt; ; start += size) {
- start = find_e820_area_size(start, &size, align);
+ start = find_lmb_area_size(start, &size, align);
if (!(start + 1))
return 0;
if (size >= sizet)
@@ -834,10 +763,9 @@ u64 __init early_reserve_e820(u64 startt, u64 sizet, u64 align)
addr = round_down(start + size - sizet, align);
if (addr < start)
return 0;
- e820_update_range(addr, sizet, E820_RAM, E820_RESERVED);
+ reserve_early(addr, addr + sizet, "new next");
e820_update_range_saved(addr, sizet, E820_RAM, E820_RESERVED);
- printk(KERN_INFO "update e820 for early_reserve_e820\n");
- update_e820();
+ printk(KERN_INFO "update e820_saved for early_reserve_e820\n");
update_e820_saved();
return addr;
@@ -899,74 +827,6 @@ unsigned long __init e820_end_of_low_ram_pfn(void)
{
return e820_end_pfn(1UL<<(32 - PAGE_SHIFT), E820_RAM);
}
-/*
- * Finds an active region in the address range from start_pfn to last_pfn and
- * returns its range in ei_startpfn and ei_endpfn for the e820 entry.
- */
-int __init e820_find_active_region(const struct e820entry *ei,
- unsigned long start_pfn,
- unsigned long last_pfn,
- unsigned long *ei_startpfn,
- unsigned long *ei_endpfn)
-{
- u64 align = PAGE_SIZE;
-
- *ei_startpfn = round_up(ei->addr, align) >> PAGE_SHIFT;
- *ei_endpfn = round_down(ei->addr + ei->size, align) >> PAGE_SHIFT;
-
- /* Skip map entries smaller than a page */
- if (*ei_startpfn >= *ei_endpfn)
- return 0;
-
- /* Skip if map is outside the node */
- if (ei->type != E820_RAM || *ei_endpfn <= start_pfn ||
- *ei_startpfn >= last_pfn)
- return 0;
-
- /* Check for overlaps */
- if (*ei_startpfn < start_pfn)
- *ei_startpfn = start_pfn;
- if (*ei_endpfn > last_pfn)
- *ei_endpfn = last_pfn;
-
- return 1;
-}
-
-/* Walk the e820 map and register active regions within a node */
-void __init e820_register_active_regions(int nid, unsigned long start_pfn,
- unsigned long last_pfn)
-{
- unsigned long ei_startpfn;
- unsigned long ei_endpfn;
- int i;
-
- for (i = 0; i < e820.nr_map; i++)
- if (e820_find_active_region(&e820.map[i],
- start_pfn, last_pfn,
- &ei_startpfn, &ei_endpfn))
- add_active_range(nid, ei_startpfn, ei_endpfn);
-}
-
-/*
- * Find the hole size (in bytes) in the memory range.
- * @start: starting address of the memory range to scan
- * @end: ending address of the memory range to scan
- */
-u64 __init e820_hole_size(u64 start, u64 end)
-{
- unsigned long start_pfn = start >> PAGE_SHIFT;
- unsigned long last_pfn = end >> PAGE_SHIFT;
- unsigned long ei_startpfn, ei_endpfn, ram = 0;
- int i;
-
- for (i = 0; i < e820.nr_map; i++) {
- if (e820_find_active_region(&e820.map[i],
- start_pfn, last_pfn,
- &ei_startpfn, &ei_endpfn))
- ram += ei_endpfn - ei_startpfn;
- }
- return end - start - ((u64)ram << PAGE_SHIFT);
-}
static void early_panic(char *msg)
{
@@ -1219,3 +1079,24 @@ void __init setup_memory_map(void)
printk(KERN_INFO "BIOS-provided physical RAM map:\n");
e820_print_map(who);
}
+
+void __init init_lmb_memory(void)
+{
+ lmb_init();
+}
+
+void __init fill_lmb_memory(void)
+{
+ int i;
+
+ for (i = 0; i < e820.nr_map; i++) {
+ struct e820entry *ei = &e820.map[i];
+
+ if (ei->type != E820_RAM)
+ continue;
+ add_lmb_memory(ei->addr, ei->addr + ei->size);
+ }
+
+ lmb_analyze();
+ lmb_dump_all();
+}
diff --git a/arch/x86/kernel/head.c b/arch/x86/kernel/head.c
index 3e66bd3..e0d0ce5 100644
--- a/arch/x86/kernel/head.c
+++ b/arch/x86/kernel/head.c
@@ -51,5 +51,5 @@ void __init reserve_ebda_region(void)
lowmem = 0x9f000;
/* reserve all memory between lowmem and the 1MB mark */
- reserve_early_overlap_ok(lowmem, 0x100000, "BIOS reserved");
+ reserve_early(lowmem, 0x100000, "BIOS reserved");
}
diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c
index adedeef..8983422 100644
--- a/arch/x86/kernel/head32.c
+++ b/arch/x86/kernel/head32.c
@@ -29,14 +29,15 @@ static void __init i386_default_early_setup(void)
void __init i386_start_kernel(void)
{
+ init_lmb_memory();
+
#ifdef CONFIG_X86_TRAMPOLINE
/*
* But first pinch a few for the stack/trampoline stuff
* FIXME: Don't need the extra page at 4K, but need to fix
* trampoline before removing it. (see the GDT stuff)
*/
- reserve_early_overlap_ok(PAGE_SIZE, PAGE_SIZE + PAGE_SIZE,
- "EX TRAMPOLINE");
+ reserve_early(PAGE_SIZE, PAGE_SIZE + PAGE_SIZE, "EX TRAMPOLINE");
#endif
reserve_early(__pa_symbol(&_text), __pa_symbol(&__bss_stop), "TEXT DATA BSS");
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index b5a9896..86e6a9b 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -96,6 +96,8 @@ void __init x86_64_start_kernel(char * real_mode_data)
void __init x86_64_start_reservations(char *real_mode_data)
{
+ init_lmb_memory();
+
copy_bootdata(__va(real_mode_data));
reserve_early(__pa_symbol(&_text), __pa_symbol(&__bss_stop), "TEXT DATA BSS");
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 3787a82..a9e99e6 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -868,8 +868,6 @@ void __init setup_arch(char **cmdline_p)
*/
max_pfn = e820_end_of_ram_pfn();
- /* preallocate 4k for mptable mpc */
- early_reserve_e820_mpc_new();
/* update e820 for memory not covered by WB MTRRs */
mtrr_bp_init();
if (mtrr_trim_uncached_memory(max_pfn))
@@ -894,6 +892,11 @@ void __init setup_arch(char **cmdline_p)
max_pfn_mapped = KERNEL_IMAGE_SIZE >> PAGE_SHIFT;
#endif
+ fill_lmb_memory();
+
+ /* preallocate 4k for mptable mpc */
+ early_reserve_e820_mpc_new();
+
#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
setup_bios_corruption_check();
#endif
@@ -970,7 +973,7 @@ void __init setup_arch(char **cmdline_p)
initmem_init(0, max_pfn, acpi, k8);
#ifndef CONFIG_NO_BOOTMEM
- early_res_to_bootmem(0, max_low_pfn<<PAGE_SHIFT);
+ lmb_reserved_to_bootmem(0, max_low_pfn<<PAGE_SHIFT);
#endif
dma32_reserve_bootmem();
diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c
index ef6370b..35abcb8 100644
--- a/arch/x86/kernel/setup_percpu.c
+++ b/arch/x86/kernel/setup_percpu.c
@@ -137,13 +137,7 @@ static void * __init pcpu_fc_alloc(unsigned int cpu, size_t size, size_t align)
static void __init pcpu_fc_free(void *ptr, size_t size)
{
-#ifdef CONFIG_NO_BOOTMEM
- u64 start = __pa(ptr);
- u64 end = start + size;
- free_early_partial(start, end);
-#else
free_bootmem(__pa(ptr), size);
-#endif
}
static int __init pcpu_cpu_distance(unsigned int from, unsigned int to)
diff --git a/arch/x86/mm/memtest.c b/arch/x86/mm/memtest.c
index 18d244f..216f832 100644
--- a/arch/x86/mm/memtest.c
+++ b/arch/x86/mm/memtest.c
@@ -6,8 +6,7 @@
#include <linux/smp.h>
#include <linux/init.h>
#include <linux/pfn.h>
-
-#include <asm/e820.h>
+#include <linux/early_res.h>
static u64 patterns[] __initdata = {
0,
@@ -74,7 +73,7 @@ static void __init do_one_pass(u64 pattern, u64 start, u64 end)
u64 size = 0;
while (start < end) {
- start = find_e820_area_size(start, &size, 1);
+ start = find_lmb_area_size(start, &size, 1);
/* done ? */
if (start >= end)
diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c
index ffc5ad5..45ac950 100644
--- a/arch/x86/mm/numa_64.c
+++ b/arch/x86/mm/numa_64.c
@@ -174,7 +174,7 @@ static void * __init early_node_mem(int nodeid, unsigned long start,
if (start < (MAX_DMA32_PFN<<PAGE_SHIFT) &&
end > (MAX_DMA32_PFN<<PAGE_SHIFT))
start = MAX_DMA32_PFN<<PAGE_SHIFT;
- mem = find_e820_area_node(nodeid, start, end, size, align);
+ mem = find_lmb_area_node(nodeid, start, end, size, align);
if (mem != -1L)
return __va(mem);
@@ -184,7 +184,7 @@ static void * __init early_node_mem(int nodeid, unsigned long start,
start = MAX_DMA32_PFN<<PAGE_SHIFT;
else
start = MAX_DMA_PFN<<PAGE_SHIFT;
- mem = find_e820_area_node(nodeid, start, end, size, align);
+ mem = find_lmb_area_node(nodeid, start, end, size, align);
if (mem != -1L)
return __va(mem);
diff --git a/include/linux/early_res.h b/include/linux/early_res.h
index 29c09f5..4fac619 100644
--- a/include/linux/early_res.h
+++ b/include/linux/early_res.h
@@ -3,19 +3,22 @@
#ifdef __KERNEL__
extern void reserve_early(u64 start, u64 end, char *name);
-extern void reserve_early_overlap_ok(u64 start, u64 end, char *name);
extern void free_early(u64 start, u64 end);
-void free_early_partial(u64 start, u64 end);
-extern void early_res_to_bootmem(u64 start, u64 end);
+void lmb_reserved_to_bootmem(u64 start, u64 end);
-void reserve_early_without_check(u64 start, u64 end, char *name);
u64 find_early_area(u64 ei_start, u64 ei_last, u64 start, u64 end,
u64 size, u64 align);
-u64 find_early_area_size(u64 ei_start, u64 ei_last, u64 start,
- u64 *sizep, u64 align);
-u64 find_fw_memmap_area(u64 start, u64 end, u64 size, u64 align);
+
+void add_lmb_memory(u64 start, u64 end);
+
+u64 find_lmb_area(u64 start, u64 end, u64 size, u64 align);
+u64 find_lmb_area_size(u64 start, u64 *sizep, u64 align);
+u64 find_lmb_area_node(int nid, u64 start, u64 end, u64 size, u64 align);
+void lmb_register_active_regions(int nid, unsigned long start_pfn,
+ unsigned long last_pfn);
+u64 lmb_hole_size(u64 start, u64 end);
u64 get_max_mapped(void);
-#include <linux/range.h>
+struct range;
int get_free_all_memory_range(struct range **rangep, int nodeid);
#endif /* __KERNEL__ */
diff --git a/kernel/early_res.c b/kernel/early_res.c
index 69bed5b..a793393 100644
--- a/kernel/early_res.c
+++ b/kernel/early_res.c
@@ -6,404 +6,140 @@
#include <linux/init.h>
#include <linux/bootmem.h>
#include <linux/mm.h>
+#include <linux/lmb.h>
+#include <linux/range.h>
#include <linux/early_res.h>
/*
* Early reserved memory areas.
*/
-/*
- * need to make sure this one is bigger enough before
- * find_fw_memmap_area could be used
- */
-#define MAX_EARLY_RES_X 32
-
-struct early_res {
- u64 start, end;
- char name[15];
- char overlap_ok;
-};
-static struct early_res early_res_x[MAX_EARLY_RES_X] __initdata;
-
-static int max_early_res __initdata = MAX_EARLY_RES_X;
-static struct early_res *early_res __initdata = &early_res_x[0];
-static int early_res_count __initdata;
-
-static int __init find_overlapped_early(u64 start, u64 end)
-{
- int i;
- struct early_res *r;
-
- for (i = 0; i < max_early_res && early_res[i].end; i++) {
- r = &early_res[i];
- if (end > r->start && start < r->end)
- break;
- }
- return i;
-}
-
-/*
- * Drop the i-th range from the early reservation map,
- * by copying any higher ranges down one over it, and
- * clearing what had been the last slot.
- */
-static void __init drop_range(int i)
-{
- int j;
-
- for (j = i + 1; j < max_early_res && early_res[j].end; j++)
- ;
-
- memmove(&early_res[i], &early_res[i + 1],
- (j - 1 - i) * sizeof(struct early_res));
-
- early_res[j - 1].end = 0;
- early_res_count--;
-}
-
-static void __init drop_range_partial(int i, u64 start, u64 end)
-{
- u64 common_start, common_end;
- u64 old_start, old_end;
-
- old_start = early_res[i].start;
- old_end = early_res[i].end;
- common_start = max(old_start, start);
- common_end = min(old_end, end);
-
- /* no overlap ? */
- if (common_start >= common_end)
- return;
-
- if (old_start < common_start) {
- /* make head segment */
- early_res[i].end = common_start;
- if (old_end > common_end) {
- char name[15];
-
- /*
- * Save a local copy of the name, since the
- * early_res array could get resized inside
- * reserve_early_without_check() ->
- * __check_and_double_early_res(), which would
- * make the current name pointer invalid.
- */
- strncpy(name, early_res[i].name,
- sizeof(early_res[i].name) - 1);
- /* add another for left over on tail */
- reserve_early_without_check(common_end, old_end, name);
- }
- return;
- } else {
- if (old_end > common_end) {
- /* reuse the entry for tail left */
- early_res[i].start = common_end;
- return;
- }
- /* all covered */
- drop_range(i);
- }
-}
-
-/*
- * Split any existing ranges that:
- * 1) are marked 'overlap_ok', and
- * 2) overlap with the stated range [start, end)
- * into whatever portion (if any) of the existing range is entirely
- * below or entirely above the stated range. Drop the portion
- * of the existing range that overlaps with the stated range,
- * which will allow the caller of this routine to then add that
- * stated range without conflicting with any existing range.
- */
-static void __init drop_overlaps_that_are_ok(u64 start, u64 end)
-{
- int i;
- struct early_res *r;
- u64 lower_start, lower_end;
- u64 upper_start, upper_end;
- char name[15];
-
- for (i = 0; i < max_early_res && early_res[i].end; i++) {
- r = &early_res[i];
-
- /* Continue past non-overlapping ranges */
- if (end <= r->start || start >= r->end)
- continue;
-
- /*
- * Leave non-ok overlaps as is; let caller
- * panic "Overlapping early reservations"
- * when it hits this overlap.
- */
- if (!r->overlap_ok)
- return;
-
- /*
- * We have an ok overlap. We will drop it from the early
- * reservation map, and add back in any non-overlapping
- * portions (lower or upper) as separate, overlap_ok,
- * non-overlapping ranges.
- */
-
- /* 1. Note any non-overlapping (lower or upper) ranges. */
- strncpy(name, r->name, sizeof(name) - 1);
-
- lower_start = lower_end = 0;
- upper_start = upper_end = 0;
- if (r->start < start) {
- lower_start = r->start;
- lower_end = start;
- }
- if (r->end > end) {
- upper_start = end;
- upper_end = r->end;
- }
-
- /* 2. Drop the original ok overlapping range */
- drop_range(i);
-
- i--; /* resume for-loop on copied down entry */
-
- /* 3. Add back in any non-overlapping ranges. */
- if (lower_end)
- reserve_early_overlap_ok(lower_start, lower_end, name);
- if (upper_end)
- reserve_early_overlap_ok(upper_start, upper_end, name);
- }
-}
-
-static void __init __reserve_early(u64 start, u64 end, char *name,
- int overlap_ok)
-{
- int i;
- struct early_res *r;
-
- i = find_overlapped_early(start, end);
- if (i >= max_early_res)
- panic("Too many early reservations");
- r = &early_res[i];
- if (r->end)
- panic("Overlapping early reservations "
- "%llx-%llx %s to %llx-%llx %s\n",
- start, end - 1, name ? name : "", r->start,
- r->end - 1, r->name);
- r->start = start;
- r->end = end;
- r->overlap_ok = overlap_ok;
- if (name)
- strncpy(r->name, name, sizeof(r->name) - 1);
- early_res_count++;
-}
-
-/*
- * A few early reservtations come here.
- *
- * The 'overlap_ok' in the name of this routine does -not- mean it
- * is ok for these reservations to overlap an earlier reservation.
- * Rather it means that it is ok for subsequent reservations to
- * overlap this one.
- *
- * Use this entry point to reserve early ranges when you are doing
- * so out of "Paranoia", reserving perhaps more memory than you need,
- * just in case, and don't mind a subsequent overlapping reservation
- * that is known to be needed.
- *
- * The drop_overlaps_that_are_ok() call here isn't really needed.
- * It would be needed if we had two colliding 'overlap_ok'
- * reservations, so that the second such would not panic on the
- * overlap with the first. We don't have any such as of this
- * writing, but might as well tolerate such if it happens in
- * the future.
- */
-void __init reserve_early_overlap_ok(u64 start, u64 end, char *name)
-{
- drop_overlaps_that_are_ok(start, end);
- __reserve_early(start, end, name, 1);
-}
-
-static void __init __check_and_double_early_res(u64 ex_start, u64 ex_end)
+static void __init __check_and_double_region_array(struct lmb_region *type,
+ struct lmb_property *static_region,
+ u64 ex_start, u64 ex_end)
{
u64 start, end, size, mem;
- struct early_res *new;
+ struct lmb_property *new, *old;
+ unsigned long rgnsz = type->nr_regions;
/* do we have enough slots left ? */
- if ((max_early_res - early_res_count) > max(max_early_res/8, 2))
+ if ((rgnsz - type->cnt) > max_t(unsigned long, rgnsz/8, 2))
return;
+ old = type->region;
/* double it */
mem = -1ULL;
- size = sizeof(struct early_res) * max_early_res * 2;
- if (early_res == early_res_x)
+ size = sizeof(struct lmb_property) * rgnsz * 2;
+ if (old == static_region)
start = 0;
else
- start = early_res[0].end;
+ start = __pa(old) + sizeof(struct lmb_property) * rgnsz;
end = ex_start;
if (start + size < end)
- mem = find_fw_memmap_area(start, end, size,
- sizeof(struct early_res));
+ mem = find_lmb_area(start, end, size,
+ sizeof(struct lmb_property));
if (mem == -1ULL) {
start = ex_end;
end = get_max_mapped();
if (start + size < end)
- mem = find_fw_memmap_area(start, end, size,
- sizeof(struct early_res));
+ mem = find_lmb_area(start, end, size, sizeof(struct lmb_property));
}
if (mem == -1ULL)
- panic("can not find more space for early_res array");
+ panic("can not find more space for lmb.reserved.region array");
new = __va(mem);
- /* save the first one for own */
- new[0].start = mem;
- new[0].end = mem + size;
- new[0].overlap_ok = 0;
/* copy old to new */
- if (early_res == early_res_x) {
- memcpy(&new[1], &early_res[0],
- sizeof(struct early_res) * max_early_res);
- memset(&new[max_early_res+1], 0,
- sizeof(struct early_res) * (max_early_res - 1));
- early_res_count++;
- } else {
- memcpy(&new[1], &early_res[1],
- sizeof(struct early_res) * (max_early_res - 1));
- memset(&new[max_early_res], 0,
- sizeof(struct early_res) * max_early_res);
- }
- memset(&early_res[0], 0, sizeof(struct early_res) * max_early_res);
- early_res = new;
- max_early_res *= 2;
- printk(KERN_DEBUG "early_res array is doubled to %d at [%llx - %llx]\n",
- max_early_res, mem, mem + size - 1);
+ memcpy(&new[0], &old[0], sizeof(struct lmb_property) * rgnsz);
+ memset(&new[rgnsz], 0, sizeof(struct lmb_property) * rgnsz);
+
+ memset(&old[0], 0, sizeof(struct lmb_property) * rgnsz);
+ type->region = new;
+ type->nr_regions = rgnsz * 2;
+ printk(KERN_DEBUG "lmb.reserved.region array is doubled to %ld at [%llx - %llx]\n",
+ type->nr_regions, mem, mem + size - 1);
+
+ /* reserve new array and free old one */
+ lmb_reserve(mem, sizeof(struct lmb_property) * rgnsz * 2);
+ if (old != static_region)
+ lmb_free(__pa(old), sizeof(struct lmb_property) * rgnsz);
}
-/*
- * Most early reservations come here.
- *
- * We first have drop_overlaps_that_are_ok() drop any pre-existing
- * 'overlap_ok' ranges, so that we can then reserve this memory
- * range without risk of panic'ing on an overlapping overlap_ok
- * early reservation.
- */
-void __init reserve_early(u64 start, u64 end, char *name)
+void __init add_lmb_memory(u64 start, u64 end)
{
- if (start >= end)
- return;
-
- __check_and_double_early_res(start, end);
-
- drop_overlaps_that_are_ok(start, end);
- __reserve_early(start, end, name, 0);
+ __check_and_double_region_array(&lmb.memory, &lmb_memory_region[0], start, end);
+ lmb_add(start, end - start);
}
-void __init reserve_early_without_check(u64 start, u64 end, char *name)
+void __init reserve_early(u64 start, u64 end, char *name)
{
- struct early_res *r;
-
- if (start >= end)
+ if (start == end)
return;
- __check_and_double_early_res(start, end);
-
- r = &early_res[early_res_count];
+ if (WARN_ONCE(start > end, "reserve_early: wrong range [%#llx, %#llx]\n", start, end))
+ return;
- r->start = start;
- r->end = end;
- r->overlap_ok = 0;
- if (name)
- strncpy(r->name, name, sizeof(r->name) - 1);
- early_res_count++;
+ __check_and_double_region_array(&lmb.reserved, &lmb_reserved_region[0], start, end);
+ lmb_reserve(start, end - start);
}
void __init free_early(u64 start, u64 end)
{
- struct early_res *r;
- int i;
-
- i = find_overlapped_early(start, end);
- r = &early_res[i];
- if (i >= max_early_res || r->end != end || r->start != start)
- panic("free_early on not reserved area: %llx-%llx!",
- start, end - 1);
-
- drop_range(i);
-}
-
-void __init free_early_partial(u64 start, u64 end)
-{
- struct early_res *r;
- int i;
-
if (start == end)
return;
- if (WARN_ONCE(start > end, "free_early_partial: wrong range [%#llx, %#llx]\n", start, end))
- return;
-
-try_next:
- i = find_overlapped_early(start, end);
- if (i >= max_early_res)
- return;
-
- r = &early_res[i];
- /* hole ? */
- if (r->end >= end && r->start <= start) {
- drop_range_partial(i, start, end);
+ if (WARN_ONCE(start > end, "free_early: wrong range [%#llx, %#llx]\n", start, end))
return;
- }
- drop_range_partial(i, start, end);
- goto try_next;
+ /* keep punching hole, could run out of slots too */
+ __check_and_double_region_array(&lmb.reserved, &lmb_reserved_region[0], start, end);
+ lmb_free(start, end - start);
}
#ifdef CONFIG_NO_BOOTMEM
-static void __init subtract_early_res(struct range *range, int az)
+static void __init subtract_lmb_reserved(struct range *range, int az)
{
int i, count;
u64 final_start, final_end;
- int idx = 0;
- count = 0;
- for (i = 0; i < max_early_res && early_res[i].end; i++)
- count++;
+ /*take out region array at first*/
+ if (lmb.reserved.region != lmb_reserved_region)
+ lmb_free(__pa(lmb.reserved.region), sizeof(struct lmb_property) * lmb.reserved.nr_regions);
- /* need to skip first one ?*/
- if (early_res != early_res_x)
- idx = 1;
+ count = lmb.reserved.cnt;
#define DEBUG_PRINT_EARLY_RES 1
#if DEBUG_PRINT_EARLY_RES
printk(KERN_INFO "Subtract (%d early reservations)\n", count);
#endif
- for (i = idx; i < count; i++) {
- struct early_res *r = &early_res[i];
+
+ for (i = 0; i < count; i++) {
+ struct lmb_property *r = &lmb.reserved.region[i];
#if DEBUG_PRINT_EARLY_RES
- printk(KERN_INFO " #%d [%010llx - %010llx] %15s\n", i,
- r->start, r->end, r->name);
+ printk(KERN_INFO " #%d [%010llx - %010llx]\n", i,
+ r->base, r->base + r->size);
#endif
- final_start = PFN_DOWN(r->start);
- final_end = PFN_UP(r->end);
+ final_start = PFN_DOWN(r->base);
+ final_end = PFN_UP(r->base + r->size);
if (final_start >= final_end)
continue;
subtract_range(range, az, final_start, final_end);
}
-
+ /* put region array back */
+ if (lmb.reserved.region != lmb_reserved_region)
+ lmb_reserve(__pa(lmb.reserved.region), sizeof(struct lmb_property) * lmb.reserved.nr_regions);
}
int __init get_free_all_memory_range(struct range **rangep, int nodeid)
{
- int i, count;
+ int count;
u64 start = 0, end;
u64 size;
u64 mem;
struct range *range;
int nr_range;
- count = 0;
- for (i = 0; i < max_early_res && early_res[i].end; i++)
- count++;
-
- count *= 2;
+ count = lmb.reserved.cnt * 2;
size = sizeof(struct range) * count;
end = get_max_mapped();
@@ -411,12 +147,15 @@ int __init get_free_all_memory_range(struct range **rangep, int nodeid)
if (end > (MAX_DMA32_PFN << PAGE_SHIFT))
start = MAX_DMA32_PFN << PAGE_SHIFT;
#endif
- mem = find_fw_memmap_area(start, end, size, sizeof(struct range));
+ mem = find_lmb_area(start, end, size, sizeof(struct range));
if (mem == -1ULL)
panic("can not find more space for range free");
range = __va(mem);
- /* use early_node_map[] and early_res to get range array at first */
+ /*
+ * use early_node_map[] and lmb.reserved.region to get range array
+ * at first
+ */
memset(range, 0, size);
nr_range = 0;
@@ -425,43 +164,39 @@ int __init get_free_all_memory_range(struct range **rangep, int nodeid)
#ifdef CONFIG_X86_32
subtract_range(range, count, max_low_pfn, -1ULL);
#endif
- subtract_early_res(range, count);
+ subtract_lmb_reserved(range, count);
nr_range = clean_sort_range(range, count);
/* need to clear it ? */
if (nodeid == MAX_NUMNODES) {
- memset(&early_res[0], 0,
- sizeof(struct early_res) * max_early_res);
- early_res = NULL;
- max_early_res = 0;
+ memset(&lmb.reserved.region[0], 0, sizeof(struct lmb_property) * lmb.reserved.nr_regions);
+ lmb.reserved.region = NULL;
+ lmb.reserved.nr_regions = 0;
+ lmb.reserved.cnt = 0;
}
*rangep = range;
return nr_range;
}
#else
-void __init early_res_to_bootmem(u64 start, u64 end)
+void __init lmb_reserved_to_bootmem(u64 start, u64 end)
{
int i, count;
u64 final_start, final_end;
- int idx = 0;
-
- count = 0;
- for (i = 0; i < max_early_res && early_res[i].end; i++)
- count++;
-
- /* need to skip first one ?*/
- if (early_res != early_res_x)
- idx = 1;
-
- printk(KERN_INFO "(%d/%d early reservations) ==> bootmem [%010llx - %010llx]\n",
- count - idx, max_early_res, start, end);
- for (i = idx; i < count; i++) {
- struct early_res *r = &early_res[i];
- printk(KERN_INFO " #%d [%010llx - %010llx] %16s", i,
- r->start, r->end, r->name);
- final_start = max(start, r->start);
- final_end = min(end, r->end);
+
+ /*take out region array */
+ if (lmb.reserved.region != lmb_reserved_region)
+ lmb_free(__pa(lmb.reserved.region), sizeof(struct lmb_property) * lmb.reserved.nr_regions);
+
+ count = lmb.reserved.cnt;
+ printk(KERN_INFO "(%d early reservations) ==> bootmem [%010llx - %010llx]\n",
+ count, start, end);
+ for (i = 0; i < count; i++) {
+ struct lmb_property *r = &lmb.reserved.region[i];
+ printk(KERN_INFO " #%d [%010llx - %010llx] ", i,
+ r->base, r->base + r->size);
+ final_start = max(start, r->base);
+ final_end = min(end, r->base + r->size);
if (final_start >= final_end) {
printk(KERN_CONT "\n");
continue;
@@ -471,57 +206,71 @@ void __init early_res_to_bootmem(u64 start, u64 end)
reserve_bootmem_generic(final_start, final_end - final_start,
BOOTMEM_DEFAULT);
}
- /* clear them */
- memset(&early_res[0], 0, sizeof(struct early_res) * max_early_res);
- early_res = NULL;
- max_early_res = 0;
- early_res_count = 0;
+ /* clear them to avoid misuse */
+ memset(&lmb.reserved.region[0], 0, sizeof(struct lmb_property) * lmb.reserved.nr_regions);
+ lmb.reserved.region = NULL;
+ lmb.reserved.nr_regions = 0;
+ lmb.reserved.cnt = 0;
}
#endif
+static int __init find_overlapped_early(u64 start, u64 end)
+{
+ int i;
+ struct lmb_property *r;
+
+ for (i = 0; i < lmb.reserved.cnt && lmb.reserved.region[i].size; i++) {
+ r = &lmb.reserved.region[i];
+ if (end > r->base && start < (r->base + r->size))
+ break;
+ }
+
+ return i;
+}
+
/* Check for already reserved areas */
-static inline int __init bad_addr(u64 *addrp, u64 size, u64 align)
+static inline bool __init bad_addr(u64 *addrp, u64 size, u64 align)
{
int i;
u64 addr = *addrp;
- int changed = 0;
- struct early_res *r;
+ bool changed = false;
+ struct lmb_property *r;
again:
i = find_overlapped_early(addr, addr + size);
- r = &early_res[i];
- if (i < max_early_res && r->end) {
- *addrp = addr = round_up(r->end, align);
- changed = 1;
+ r = &lmb.reserved.region[i];
+ if (i < lmb.reserved.cnt && r->size) {
+ *addrp = addr = round_up(r->base + r->size, align);
+ changed = true;
goto again;
}
return changed;
}
/* Check for already reserved areas */
-static inline int __init bad_addr_size(u64 *addrp, u64 *sizep, u64 align)
+static inline bool __init bad_addr_size(u64 *addrp, u64 *sizep, u64 align)
{
int i;
u64 addr = *addrp, last;
u64 size = *sizep;
- int changed = 0;
+ bool changed = false;
again:
last = addr + size;
- for (i = 0; i < max_early_res && early_res[i].end; i++) {
- struct early_res *r = &early_res[i];
- if (last > r->start && addr < r->start) {
- size = r->start - addr;
- changed = 1;
+ for (i = 0; i < lmb.reserved.cnt && lmb.reserved.region[i].size; i++) {
+ struct lmb_property *r = &lmb.reserved.region[i];
+ if (last > r->base && addr < r->base) {
+ size = r->base - addr;
+ changed = true;
goto again;
}
- if (last > r->end && addr < r->end) {
- addr = round_up(r->end, align);
+ if (last > (r->base + r->size) && addr < (r->base + r->size)) {
+ addr = round_up(r->base + r->size, align);
size = last - addr;
- changed = 1;
+ changed = true;
goto again;
}
- if (last <= r->end && addr >= r->start) {
+ if (last <= (r->base + r->size) && addr >= r->base) {
(*sizep)++;
- return 0;
+ return false;
}
}
if (changed) {
@@ -531,13 +280,8 @@ again:
return changed;
}
-/*
- * Find a free area with specified alignment in a specific range.
- * only with the area.between start to end is active range from early_node_map
- * so they are good as RAM
- */
u64 __init find_early_area(u64 ei_start, u64 ei_last, u64 start, u64 end,
- u64 size, u64 align)
+ u64 size, u64 align)
{
u64 addr, last;
@@ -560,7 +304,7 @@ out:
return -1ULL;
}
-u64 __init find_early_area_size(u64 ei_start, u64 ei_last, u64 start,
+static u64 __init find_early_area_size(u64 ei_start, u64 ei_last, u64 start,
u64 *sizep, u64 align)
{
u64 addr, last;
@@ -582,3 +326,130 @@ u64 __init find_early_area_size(u64 ei_start, u64 ei_last, u64 start,
out:
return -1ULL;
}
+
+/*
+ * Find a free area with specified alignment in a specific range.
+ */
+u64 __init find_lmb_area(u64 start, u64 end, u64 size, u64 align)
+{
+ int i;
+
+ for (i = 0; i < lmb.memory.cnt; i++) {
+ u64 ei_start = lmb.memory.region[i].base;
+ u64 ei_last = ei_start + lmb.memory.region[i].size;
+ u64 addr;
+
+ addr = find_early_area(ei_start, ei_last, start, end,
+ size, align);
+
+ if (addr != -1ULL)
+ return addr;
+ }
+ return -1ULL;
+}
+
+/*
+ * Find next free range after *start
+ */
+u64 __init find_lmb_area_size(u64 start, u64 *sizep, u64 align)
+{
+ int i;
+
+ for (i = 0; i < lmb.memory.cnt; i++) {
+ u64 ei_start = lmb.memory.region[i].base;
+ u64 ei_last = ei_start + lmb.memory.region[i].size;
+ u64 addr;
+
+ addr = find_early_area_size(ei_start, ei_last, start,
+ sizep, align);
+
+ if (addr != -1ULL)
+ return addr;
+ }
+
+ return -1ULL;
+}
+
+u64 __init find_lmb_area_node(int nid, u64 start, u64 end, u64 size, u64 align)
+{
+ u64 addr;
+ /*
+ * need to call this function after lmb_register_active_regions
+ * so early_node_map[] is set
+ */
+ addr = find_memory_core_early(nid, size, align, start, end);
+ if (addr != -1ULL)
+ return addr;
+
+ /* fallback, should already have start end in the node range */
+ return find_lmb_area(start, end, size, align);
+}
+
+/*
+ * Finds an active region in the address range from start_pfn to last_pfn and
+ * returns its range in ei_startpfn and ei_endpfn for the lmb entry.
+ */
+static int __init lmb_find_active_region(const struct lmb_property *ei,
+ unsigned long start_pfn,
+ unsigned long last_pfn,
+ unsigned long *ei_startpfn,
+ unsigned long *ei_endpfn)
+{
+ u64 align = PAGE_SIZE;
+
+ *ei_startpfn = round_up(ei->base, align) >> PAGE_SHIFT;
+ *ei_endpfn = round_down(ei->base + ei->size, align) >> PAGE_SHIFT;
+
+ /* Skip map entries smaller than a page */
+ if (*ei_startpfn >= *ei_endpfn)
+ return 0;
+
+ /* Skip if map is outside the node */
+ if (*ei_endpfn <= start_pfn || *ei_startpfn >= last_pfn)
+ return 0;
+
+ /* Check for overlaps */
+ if (*ei_startpfn < start_pfn)
+ *ei_startpfn = start_pfn;
+ if (*ei_endpfn > last_pfn)
+ *ei_endpfn = last_pfn;
+
+ return 1;
+}
+
+/* Walk the lmb.memory map and register active regions within a node */
+void __init lmb_register_active_regions(int nid, unsigned long start_pfn,
+ unsigned long last_pfn)
+{
+ unsigned long ei_startpfn;
+ unsigned long ei_endpfn;
+ int i;
+
+ for (i = 0; i < lmb.memory.cnt; i++)
+ if (lmb_find_active_region(&lmb.memory.region[i],
+ start_pfn, last_pfn,
+ &ei_startpfn, &ei_endpfn))
+ add_active_range(nid, ei_startpfn, ei_endpfn);
+}
+
+/*
+ * Find the hole size (in bytes) in the memory range.
+ * @start: starting address of the memory range to scan
+ * @end: ending address of the memory range to scan
+ */
+u64 __init lmb_hole_size(u64 start, u64 end)
+{
+ unsigned long start_pfn = start >> PAGE_SHIFT;
+ unsigned long last_pfn = end >> PAGE_SHIFT;
+ unsigned long ei_startpfn, ei_endpfn, ram = 0;
+ int i;
+
+ for (i = 0; i < lmb.memory.cnt; i++) {
+ if (lmb_find_active_region(&lmb.memory.region[i],
+ start_pfn, last_pfn,
+ &ei_startpfn, &ei_endpfn))
+ ram += ei_endpfn - ei_startpfn;
+ }
+ return end - start - ((u64)ram << PAGE_SHIFT);
+}
+
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index eef3757..04c241a 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -3451,7 +3451,7 @@ void * __init __alloc_memory_core_early(int nid, u64 size, u64 align,
ptr = phys_to_virt(addr);
memset(ptr, 0, size);
- reserve_early_without_check(addr, addr + size, "BOOTMEM");
+ reserve_early(addr, addr + size, "BOOTMEM");
return ptr;
}
#endif
diff --git a/mm/sparse-vmemmap.c b/mm/sparse-vmemmap.c
index 392b9bb..cb917d5 100644
--- a/mm/sparse-vmemmap.c
+++ b/mm/sparse-vmemmap.c
@@ -219,18 +219,7 @@ void __init sparse_mem_maps_populate_node(struct page **map_map,
if (vmemmap_buf_start) {
/* need to free left buf */
-#ifdef CONFIG_NO_BOOTMEM
- free_early(__pa(vmemmap_buf_start), __pa(vmemmap_buf_end));
- if (vmemmap_buf_start < vmemmap_buf) {
- char name[15];
-
- snprintf(name, sizeof(name), "MEMMAP %d", nodeid);
- reserve_early_without_check(__pa(vmemmap_buf_start),
- __pa(vmemmap_buf), name);
- }
-#else
free_bootmem(__pa(vmemmap_buf), vmemmap_buf_end - vmemmap_buf);
-#endif
vmemmap_buf = NULL;
vmemmap_buf_end = NULL;
}
--
1.6.4.2
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 6/8] x86: remove find_e820_area
2010-03-24 10:37 [PATCH -v4 00/08] use lmb with x86 Yinghai Lu
` (4 preceding siblings ...)
2010-03-24 10:37 ` [PATCH 5/8] x86: use lmb to replace early_res Yinghai Lu
@ 2010-03-24 10:37 ` Yinghai Lu
2010-03-24 10:37 ` [PATCH 7/8] early_res: prepare for other platform to use it Yinghai Lu
` (2 subsequent siblings)
8 siblings, 0 replies; 16+ messages in thread
From: Yinghai Lu @ 2010-03-24 10:37 UTC (permalink / raw)
To: Ingo Molnar, Thomas Gleixner, H. Peter Anvin, Andrew Morton,
David Miller, Benjamin Herrenschmidt, Linus Torvalds
Cc: linux-kernel, Yinghai Lu
and e820_register_active_region, e820_hole_size
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
arch/x86/include/asm/e820.h | 17 -----------------
arch/x86/kernel/acpi/sleep.c | 2 +-
arch/x86/kernel/apic/numaq_32.c | 2 +-
arch/x86/kernel/setup.c | 6 +++---
arch/x86/kernel/trampoline.c | 4 ++--
arch/x86/mm/init.c | 2 +-
arch/x86/mm/init_32.c | 6 +++---
arch/x86/mm/init_64.c | 6 +++---
arch/x86/mm/k8topology_64.c | 2 +-
arch/x86/mm/numa_32.c | 8 ++++----
arch/x86/mm/numa_64.c | 24 ++++++++++++------------
arch/x86/mm/srat_32.c | 2 +-
arch/x86/mm/srat_64.c | 6 +++---
13 files changed, 35 insertions(+), 52 deletions(-)
diff --git a/arch/x86/include/asm/e820.h b/arch/x86/include/asm/e820.h
index e957101..9234c78 100644
--- a/arch/x86/include/asm/e820.h
+++ b/arch/x86/include/asm/e820.h
@@ -116,23 +116,6 @@ extern unsigned long e820_end_of_low_ram_pfn(void);
#include <linux/early_res.h>
extern u64 early_reserve_e820(u64 startt, u64 sizet, u64 align);
-/*
- * next three functions will be removed, esp find_e820_area()
- * can not be used before fill_lmb_memory()
- */
-static inline u64 find_e820_area(u64 start, u64 end, u64 size, u64 align)
-{
- return find_lmb_area(start, end, size, align);
-}
-static inline void e820_register_active_regions(int nid, unsigned long start_pfn, unsigned long end_pfn)
-{
- lmb_register_active_regions(nid, start_pfn, end_pfn);
-}
-static inline u64 e820_hole_size(u64 start, u64 end)
-{
- return lmb_hole_size(start, end);
-}
-
void init_lmb_memory(void);
void fill_lmb_memory(void);
extern void finish_e820_parsing(void);
diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c
index f996103..700a3b7 100644
--- a/arch/x86/kernel/acpi/sleep.c
+++ b/arch/x86/kernel/acpi/sleep.c
@@ -133,7 +133,7 @@ void __init acpi_reserve_wakeup_memory(void)
return;
}
- mem = find_e820_area(0, 1<<20, WAKEUP_SIZE, PAGE_SIZE);
+ mem = find_lmb_area(0, 1<<20, WAKEUP_SIZE, PAGE_SIZE);
if (mem == -1L) {
printk(KERN_ERR "ACPI: Cannot allocate lowmem, S3 disabled.\n");
diff --git a/arch/x86/kernel/apic/numaq_32.c b/arch/x86/kernel/apic/numaq_32.c
index 3e28401..d021cd4 100644
--- a/arch/x86/kernel/apic/numaq_32.c
+++ b/arch/x86/kernel/apic/numaq_32.c
@@ -88,7 +88,7 @@ static inline void numaq_register_node(int node, struct sys_cfg_data *scd)
node_end_pfn[node] =
MB_TO_PAGES(eq->hi_shrd_mem_start + eq->hi_shrd_mem_size);
- e820_register_active_regions(node, node_start_pfn[node],
+ lmb_register_active_regions(node, node_start_pfn[node],
node_end_pfn[node]);
memory_present(node, node_start_pfn[node], node_end_pfn[node]);
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index a9e99e6..b716ea3 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -323,7 +323,7 @@ static void __init relocate_initrd(void)
char *p, *q;
/* We need to move the initrd down into lowmem */
- ramdisk_here = find_e820_area(0, end_of_lowmem, ramdisk_size,
+ ramdisk_here = find_lmb_area(0, end_of_lowmem, ramdisk_size,
PAGE_SIZE);
if (ramdisk_here == -1ULL)
@@ -517,7 +517,7 @@ static void __init reserve_crashkernel(void)
if (crash_base <= 0) {
const unsigned long long alignment = 16<<20; /* 16M */
- crash_base = find_e820_area(alignment, ULONG_MAX, crash_size,
+ crash_base = find_lmb_area(alignment, ULONG_MAX, crash_size,
alignment);
if (crash_base == -1ULL) {
pr_info("crashkernel reservation failed - No suitable area found.\n");
@@ -526,7 +526,7 @@ static void __init reserve_crashkernel(void)
} else {
unsigned long long start;
- start = find_e820_area(crash_base, ULONG_MAX, crash_size,
+ start = find_lmb_area(crash_base, ULONG_MAX, crash_size,
1<<20);
if (start != crash_base) {
pr_info("crashkernel reservation failed - memory is in use.\n");
diff --git a/arch/x86/kernel/trampoline.c b/arch/x86/kernel/trampoline.c
index c652ef6..2276e8b 100644
--- a/arch/x86/kernel/trampoline.c
+++ b/arch/x86/kernel/trampoline.c
@@ -1,7 +1,7 @@
#include <linux/io.h>
+#include <linux/early_res.h>
#include <asm/trampoline.h>
-#include <asm/e820.h>
#if defined(CONFIG_X86_64) && defined(CONFIG_ACPI_SLEEP)
#define __trampinit
@@ -19,7 +19,7 @@ void __init reserve_trampoline_memory(void)
unsigned long mem;
/* Has to be in very low memory so we can execute real-mode AP code. */
- mem = find_e820_area(0, 1<<20, TRAMPOLINE_SIZE, PAGE_SIZE);
+ mem = find_lmb_area(0, 1<<20, TRAMPOLINE_SIZE, PAGE_SIZE);
if (mem == -1L)
panic("Cannot allocate trampoline\n");
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index e71c5cb..7d40e37 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -74,7 +74,7 @@ static void __init find_early_table_space(unsigned long end, int use_pse,
#else
start = 0x8000;
#endif
- e820_table_start = find_e820_area(start, max_pfn_mapped<<PAGE_SHIFT,
+ e820_table_start = find_lmb_area(start, max_pfn_mapped<<PAGE_SHIFT,
tables, PAGE_SIZE);
if (e820_table_start == -1UL)
panic("Cannot find space for the kernel page tables");
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index 5cb3f0f..a7625d5 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -712,14 +712,14 @@ void __init initmem_init(unsigned long start_pfn, unsigned long end_pfn,
highstart_pfn = highend_pfn = max_pfn;
if (max_pfn > max_low_pfn)
highstart_pfn = max_low_pfn;
- e820_register_active_regions(0, 0, highend_pfn);
+ lmb_register_active_regions(0, 0, highend_pfn);
sparse_memory_present_with_active_regions(0);
printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
pages_to_mb(highend_pfn - highstart_pfn));
num_physpages = highend_pfn;
high_memory = (void *) __va(highstart_pfn * PAGE_SIZE - 1) + 1;
#else
- e820_register_active_regions(0, 0, max_low_pfn);
+ lmb_register_active_regions(0, 0, max_low_pfn);
sparse_memory_present_with_active_regions(0);
num_physpages = max_low_pfn;
high_memory = (void *) __va(max_low_pfn * PAGE_SIZE - 1) + 1;
@@ -781,7 +781,7 @@ void __init setup_bootmem_allocator(void)
* Initialize the boot-time allocator (with low memory only):
*/
bootmap_size = bootmem_bootmap_pages(max_low_pfn)<<PAGE_SHIFT;
- bootmap = find_e820_area(0, max_pfn_mapped<<PAGE_SHIFT, bootmap_size,
+ bootmap = find_lmb_area(0, max_pfn_mapped<<PAGE_SHIFT, bootmap_size,
PAGE_SIZE);
if (bootmap == -1L)
panic("Cannot find bootmem map of size %ld\n", bootmap_size);
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index e9b040e..dd88ef9 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -576,7 +576,7 @@ void __init initmem_init(unsigned long start_pfn, unsigned long end_pfn,
unsigned long bootmap_size, bootmap;
bootmap_size = bootmem_bootmap_pages(end_pfn)<<PAGE_SHIFT;
- bootmap = find_e820_area(0, end_pfn<<PAGE_SHIFT, bootmap_size,
+ bootmap = find_lmb_area(0, end_pfn<<PAGE_SHIFT, bootmap_size,
PAGE_SIZE);
if (bootmap == -1L)
panic("Cannot find bootmem map of size %ld\n", bootmap_size);
@@ -584,10 +584,10 @@ void __init initmem_init(unsigned long start_pfn, unsigned long end_pfn,
/* don't touch min_low_pfn */
bootmap_size = init_bootmem_node(NODE_DATA(0), bootmap >> PAGE_SHIFT,
0, end_pfn);
- e820_register_active_regions(0, start_pfn, end_pfn);
+ lmb_register_active_regions(0, start_pfn, end_pfn);
free_bootmem_with_active_regions(0, end_pfn);
#else
- e820_register_active_regions(0, start_pfn, end_pfn);
+ lmb_register_active_regions(0, start_pfn, end_pfn);
#endif
}
#endif
diff --git a/arch/x86/mm/k8topology_64.c b/arch/x86/mm/k8topology_64.c
index 970ed57..1c5b234 100644
--- a/arch/x86/mm/k8topology_64.c
+++ b/arch/x86/mm/k8topology_64.c
@@ -222,7 +222,7 @@ int __init k8_scan_nodes(void)
for_each_node_mask(i, node_possible_map) {
int j;
- e820_register_active_regions(i,
+ lmb_register_active_regions(i,
nodes[i].start >> PAGE_SHIFT,
nodes[i].end >> PAGE_SHIFT);
for (j = apicid_base; j < cores + apicid_base; j++)
diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c
index 809baaa..8780f4d 100644
--- a/arch/x86/mm/numa_32.c
+++ b/arch/x86/mm/numa_32.c
@@ -120,7 +120,7 @@ int __init get_memcfg_numa_flat(void)
node_start_pfn[0] = 0;
node_end_pfn[0] = max_pfn;
- e820_register_active_regions(0, 0, max_pfn);
+ lmb_register_active_regions(0, 0, max_pfn);
memory_present(0, 0, max_pfn);
node_remap_size[0] = node_memmap_size_bytes(0, 0, max_pfn);
@@ -161,7 +161,7 @@ static void __init allocate_pgdat(int nid)
NODE_DATA(nid) = (pg_data_t *)node_remap_start_vaddr[nid];
else {
unsigned long pgdat_phys;
- pgdat_phys = find_e820_area(min_low_pfn<<PAGE_SHIFT,
+ pgdat_phys = find_lmb_area(min_low_pfn<<PAGE_SHIFT,
max_pfn_mapped<<PAGE_SHIFT,
sizeof(pg_data_t),
PAGE_SIZE);
@@ -291,7 +291,7 @@ static __init unsigned long calculate_numa_remap_pages(void)
PTRS_PER_PTE);
node_kva_target <<= PAGE_SHIFT;
do {
- node_kva_final = find_e820_area(node_kva_target,
+ node_kva_final = find_lmb_area(node_kva_target,
((u64)node_end_pfn[nid])<<PAGE_SHIFT,
((u64)size)<<PAGE_SHIFT,
LARGE_PAGE_BYTES);
@@ -367,7 +367,7 @@ void __init initmem_init(unsigned long start_pfn, unsigned long end_pfn,
kva_target_pfn = round_down(max_low_pfn - kva_pages, PTRS_PER_PTE);
do {
- kva_start_pfn = find_e820_area(kva_target_pfn<<PAGE_SHIFT,
+ kva_start_pfn = find_lmb_area(kva_target_pfn<<PAGE_SHIFT,
max_low_pfn<<PAGE_SHIFT,
kva_pages<<PAGE_SHIFT,
PTRS_PER_PTE<<PAGE_SHIFT) >> PAGE_SHIFT;
diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c
index 45ac950..12c1268 100644
--- a/arch/x86/mm/numa_64.c
+++ b/arch/x86/mm/numa_64.c
@@ -89,7 +89,7 @@ static int __init allocate_cachealigned_memnodemap(void)
addr = 0x8000;
nodemap_size = roundup(sizeof(s16) * memnodemapsize, L1_CACHE_BYTES);
- nodemap_addr = find_e820_area(addr, max_pfn<<PAGE_SHIFT,
+ nodemap_addr = find_lmb_area(addr, max_pfn<<PAGE_SHIFT,
nodemap_size, L1_CACHE_BYTES);
if (nodemap_addr == -1UL) {
printk(KERN_ERR
@@ -248,7 +248,7 @@ setup_node_bootmem(int nodeid, unsigned long start, unsigned long end)
* Find a place for the bootmem map
* nodedata_phys could be on other nodes by alloc_bootmem,
* so need to sure bootmap_start not to be small, otherwise
- * early_node_mem will get that with find_e820_area instead
+ * early_node_mem will get that with find_lmb_area instead
* of alloc_bootmem, that could clash with reserved range
*/
bootmap_pages = bootmem_bootmap_pages(last_pfn - start_pfn);
@@ -419,7 +419,7 @@ static int __init split_nodes_interleave(u64 addr, u64 max_addr,
nr_nodes = MAX_NUMNODES;
}
- size = (max_addr - addr - e820_hole_size(addr, max_addr)) / nr_nodes;
+ size = (max_addr - addr - lmb_hole_size(addr, max_addr)) / nr_nodes;
/*
* Calculate the number of big nodes that can be allocated as a result
* of consolidating the remainder.
@@ -455,7 +455,7 @@ static int __init split_nodes_interleave(u64 addr, u64 max_addr,
* non-reserved memory is less than the per-node size.
*/
while (end - physnodes[i].start -
- e820_hole_size(physnodes[i].start, end) < size) {
+ lmb_hole_size(physnodes[i].start, end) < size) {
end += FAKE_NODE_MIN_SIZE;
if (end > physnodes[i].end) {
end = physnodes[i].end;
@@ -469,7 +469,7 @@ static int __init split_nodes_interleave(u64 addr, u64 max_addr,
* this one must extend to the boundary.
*/
if (end < dma32_end && dma32_end - end -
- e820_hole_size(end, dma32_end) < FAKE_NODE_MIN_SIZE)
+ lmb_hole_size(end, dma32_end) < FAKE_NODE_MIN_SIZE)
end = dma32_end;
/*
@@ -478,7 +478,7 @@ static int __init split_nodes_interleave(u64 addr, u64 max_addr,
* physical node.
*/
if (physnodes[i].end - end -
- e820_hole_size(end, physnodes[i].end) < size)
+ lmb_hole_size(end, physnodes[i].end) < size)
end = physnodes[i].end;
/*
@@ -506,7 +506,7 @@ static u64 __init find_end_of_node(u64 start, u64 max_addr, u64 size)
{
u64 end = start + size;
- while (end - start - e820_hole_size(start, end) < size) {
+ while (end - start - lmb_hole_size(start, end) < size) {
end += FAKE_NODE_MIN_SIZE;
if (end > max_addr) {
end = max_addr;
@@ -535,7 +535,7 @@ static int __init split_nodes_size_interleave(u64 addr, u64 max_addr, u64 size)
* creates a uniform distribution of node sizes across the entire
* machine (but not necessarily over physical nodes).
*/
- min_size = (max_addr - addr - e820_hole_size(addr, max_addr)) /
+ min_size = (max_addr - addr - lmb_hole_size(addr, max_addr)) /
MAX_NUMNODES;
min_size = max(min_size, FAKE_NODE_MIN_SIZE);
if ((min_size & FAKE_NODE_MIN_HASH_MASK) < min_size)
@@ -568,7 +568,7 @@ static int __init split_nodes_size_interleave(u64 addr, u64 max_addr, u64 size)
* this one must extend to the boundary.
*/
if (end < dma32_end && dma32_end - end -
- e820_hole_size(end, dma32_end) < FAKE_NODE_MIN_SIZE)
+ lmb_hole_size(end, dma32_end) < FAKE_NODE_MIN_SIZE)
end = dma32_end;
/*
@@ -577,7 +577,7 @@ static int __init split_nodes_size_interleave(u64 addr, u64 max_addr, u64 size)
* physical node.
*/
if (physnodes[i].end - end -
- e820_hole_size(end, physnodes[i].end) < size)
+ lmb_hole_size(end, physnodes[i].end) < size)
end = physnodes[i].end;
/*
@@ -641,7 +641,7 @@ static int __init numa_emulation(unsigned long start_pfn,
*/
remove_all_active_ranges();
for_each_node_mask(i, node_possible_map) {
- e820_register_active_regions(i, nodes[i].start >> PAGE_SHIFT,
+ lmb_register_active_regions(i, nodes[i].start >> PAGE_SHIFT,
nodes[i].end >> PAGE_SHIFT);
setup_node_bootmem(i, nodes[i].start, nodes[i].end);
}
@@ -694,7 +694,7 @@ void __init initmem_init(unsigned long start_pfn, unsigned long last_pfn,
node_set(0, node_possible_map);
for (i = 0; i < nr_cpu_ids; i++)
numa_set_node(i, 0);
- e820_register_active_regions(0, start_pfn, last_pfn);
+ lmb_register_active_regions(0, start_pfn, last_pfn);
setup_node_bootmem(0, start_pfn << PAGE_SHIFT, last_pfn << PAGE_SHIFT);
}
diff --git a/arch/x86/mm/srat_32.c b/arch/x86/mm/srat_32.c
index 9324f13..a97c922 100644
--- a/arch/x86/mm/srat_32.c
+++ b/arch/x86/mm/srat_32.c
@@ -264,7 +264,7 @@ int __init get_memcfg_from_srat(void)
if (node_read_chunk(chunk->nid, chunk))
continue;
- e820_register_active_regions(chunk->nid, chunk->start_pfn,
+ lmb_register_active_regions(chunk->nid, chunk->start_pfn,
min(chunk->end_pfn, max_pfn));
}
/* for out of order entries in SRAT */
diff --git a/arch/x86/mm/srat_64.c b/arch/x86/mm/srat_64.c
index 28c6876..634392d 100644
--- a/arch/x86/mm/srat_64.c
+++ b/arch/x86/mm/srat_64.c
@@ -98,7 +98,7 @@ void __init acpi_numa_slit_init(struct acpi_table_slit *slit)
unsigned long phys;
length = slit->header.length;
- phys = find_e820_area(0, max_pfn_mapped<<PAGE_SHIFT, length,
+ phys = find_lmb_area(0, max_pfn_mapped<<PAGE_SHIFT, length,
PAGE_SIZE);
if (phys == -1L)
@@ -324,7 +324,7 @@ static int __init nodes_cover_memory(const struct bootnode *nodes)
pxmram = 0;
}
- e820ram = max_pfn - (e820_hole_size(0, max_pfn<<PAGE_SHIFT)>>PAGE_SHIFT);
+ e820ram = max_pfn - (lmb_hole_size(0, max_pfn<<PAGE_SHIFT)>>PAGE_SHIFT);
/* We seem to lose 3 pages somewhere. Allow 1M of slack. */
if ((long)(e820ram - pxmram) >= (1<<(20 - PAGE_SHIFT))) {
printk(KERN_ERR
@@ -373,7 +373,7 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end)
}
for_each_node_mask(i, nodes_parsed)
- e820_register_active_regions(i, nodes[i].start >> PAGE_SHIFT,
+ lmb_register_active_regions(i, nodes[i].start >> PAGE_SHIFT,
nodes[i].end >> PAGE_SHIFT);
/* for out of order entries in SRAT */
sort_node_map();
--
1.6.4.2
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 7/8] early_res: prepare for other platform to use it
2010-03-24 10:37 [PATCH -v4 00/08] use lmb with x86 Yinghai Lu
` (5 preceding siblings ...)
2010-03-24 10:37 ` [PATCH 6/8] x86: remove find_e820_area Yinghai Lu
@ 2010-03-24 10:37 ` Yinghai Lu
2010-03-24 10:37 ` [PATCH 8/8] powerpc : use early_res/nobootmem Yinghai Lu
2010-03-24 10:48 ` [PATCH -v4 00/08] use lmb with x86 Ingo Molnar
8 siblings, 0 replies; 16+ messages in thread
From: Yinghai Lu @ 2010-03-24 10:37 UTC (permalink / raw)
To: Ingo Molnar, Thomas Gleixner, H. Peter Anvin, Andrew Morton,
David Miller, Benjamin Herrenschmidt, Linus Torvalds
Cc: linux-kernel, Yinghai Lu
add weak reserver_bootmem_generic()
also clean up x86 64 bit one.
add include for linux/early_res.h
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
arch/x86/mm/init_32.c | 5 -----
arch/x86/mm/init_64.c | 18 ------------------
mm/bootmem.c | 7 +++++++
mm/page_alloc.c | 1 +
4 files changed, 8 insertions(+), 23 deletions(-)
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index a7625d5..16001e1 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -1070,8 +1070,3 @@ void mark_rodata_ro(void)
}
#endif
-int __init reserve_bootmem_generic(unsigned long phys, unsigned long len,
- int flags)
-{
- return reserve_bootmem(phys, len, flags);
-}
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index dd88ef9..cc3627b 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -801,10 +801,6 @@ void mark_rodata_ro(void)
int __init reserve_bootmem_generic(unsigned long phys, unsigned long len,
int flags)
{
-#ifdef CONFIG_NUMA
- int nid, next_nid;
- int ret;
-#endif
unsigned long pfn = phys >> PAGE_SHIFT;
if (pfn >= max_pfn) {
@@ -820,21 +816,7 @@ int __init reserve_bootmem_generic(unsigned long phys, unsigned long len,
return -EFAULT;
}
- /* Should check here against the e820 map to avoid double free */
-#ifdef CONFIG_NUMA
- nid = phys_to_nid(phys);
- next_nid = phys_to_nid(phys + len - 1);
- if (nid == next_nid)
- ret = reserve_bootmem_node(NODE_DATA(nid), phys, len, flags);
- else
- ret = reserve_bootmem(phys, len, flags);
-
- if (ret != 0)
- return ret;
-
-#else
reserve_bootmem(phys, len, flags);
-#endif
if (phys+len <= MAX_DMA_PFN*PAGE_SIZE) {
dma_reserve += len / PAGE_SIZE;
diff --git a/mm/bootmem.c b/mm/bootmem.c
index d7c791e..760c279 100644
--- a/mm/bootmem.c
+++ b/mm/bootmem.c
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/kmemleak.h>
#include <linux/range.h>
+#include <linux/early_res.h>
#include <asm/bug.h>
#include <asm/io.h>
@@ -525,6 +526,12 @@ int __init reserve_bootmem(unsigned long addr, unsigned long size,
}
#ifndef CONFIG_NO_BOOTMEM
+int __weak __init reserve_bootmem_generic(unsigned long phys, unsigned long len,
+ int flags)
+{
+ return reserve_bootmem(phys, len, flags);
+}
+
static unsigned long __init align_idx(struct bootmem_data *bdata,
unsigned long idx, unsigned long step)
{
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 04c241a..e7b1d72 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -21,6 +21,7 @@
#include <linux/pagemap.h>
#include <linux/jiffies.h>
#include <linux/bootmem.h>
+#include <linux/early_res.h>
#include <linux/compiler.h>
#include <linux/kernel.h>
#include <linux/kmemcheck.h>
--
1.6.4.2
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 8/8] powerpc : use early_res/nobootmem
2010-03-24 10:37 [PATCH -v4 00/08] use lmb with x86 Yinghai Lu
` (6 preceding siblings ...)
2010-03-24 10:37 ` [PATCH 7/8] early_res: prepare for other platform to use it Yinghai Lu
@ 2010-03-24 10:37 ` Yinghai Lu
2010-03-24 10:48 ` [PATCH -v4 00/08] use lmb with x86 Ingo Molnar
8 siblings, 0 replies; 16+ messages in thread
From: Yinghai Lu @ 2010-03-24 10:37 UTC (permalink / raw)
To: Ingo Molnar, Thomas Gleixner, H. Peter Anvin, Andrew Morton,
David Miller, Benjamin Herrenschmidt, Linus Torvalds
Cc: linux-kernel, Yinghai Lu
new early_res is extension for lmb, and it could be used to replace bootmem
also even could be used to simplify the bootmem path if needed.
--NOT TESTED--
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
arch/powerpc/Kconfig | 14 ++++++++++++++
arch/powerpc/mm/mem.c | 23 +++++++++++++++++++++--
arch/powerpc/mm/numa.c | 11 ++++++++++-
3 files changed, 45 insertions(+), 3 deletions(-)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 2e19500..307c3ef 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -52,6 +52,9 @@ config HAVE_SETUP_PER_CPU_AREA
config NEED_PER_CPU_EMBED_FIRST_CHUNK
def_bool PPC64
+config HAVE_EARLY_RES
+ def_bool y
+
config IRQ_PER_CPU
bool
default y
@@ -443,6 +446,17 @@ config ARCH_SPARSEMEM_DEFAULT
def_bool y
depends on (SMP && PPC_PSERIES) || PPC_PS3
+config NO_BOOTMEM
+ default y
+ bool "Disable Bootmem code"
+ ---help---
+ Use early_res directly instead of bootmem before slab is ready.
+ - allocator (buddy) [generic]
+ - early allocator (bootmem) [generic]
+ - very early allocator (reserve_early*()/lmb)
+ So reduce one layer between early allocator to final allocator
+
+
config ARCH_POPULATES_NODE_MAP
def_bool y
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 448f972..7004f9e 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -179,9 +179,11 @@ EXPORT_SYMBOL_GPL(walk_system_ram_range);
void __init do_init_bootmem(void)
{
unsigned long i;
- unsigned long start, bootmap_pages;
unsigned long total_pages;
+#ifndef CONFIG_NO_BOOTMEM
+ unsigned long start, bootmap_pages;
int boot_mapsize;
+#endif
max_low_pfn = max_pfn = lmb_end_of_DRAM() >> PAGE_SHIFT;
total_pages = (lmb_end_of_DRAM() - memstart_addr) >> PAGE_SHIFT;
@@ -189,7 +191,9 @@ void __init do_init_bootmem(void)
total_pages = total_lowmem >> PAGE_SHIFT;
max_low_pfn = lowmem_end_addr >> PAGE_SHIFT;
#endif
+ min_low_pfn = MEMORY_START >> PAGE_SHIFT;
+#ifndef CONFIG_NO_BOOTMEM
/*
* Find an area to use for the bootmem bitmap. Calculate the size of
* bitmap required as (Total Memory) / PAGE_SIZE / BITS_PER_BYTE.
@@ -199,8 +203,8 @@ void __init do_init_bootmem(void)
start = lmb_alloc(bootmap_pages << PAGE_SHIFT, PAGE_SIZE);
- min_low_pfn = MEMORY_START >> PAGE_SHIFT;
boot_mapsize = init_bootmem_node(NODE_DATA(0), start >> PAGE_SHIFT, min_low_pfn, max_low_pfn);
+#endif
/* Add active regions with valid PFNs */
for (i = 0; i < lmb.memory.cnt; i++) {
@@ -210,6 +214,7 @@ void __init do_init_bootmem(void)
add_active_range(0, start_pfn, end_pfn);
}
+#ifndef CONFIG_NO_BOOTMEM
/* Add all physical memory to the bootmem map, mark each area
* present.
*/
@@ -241,6 +246,7 @@ void __init do_init_bootmem(void)
BOOTMEM_DEFAULT);
#endif
+#endif
/* XXX need to clip this if using highmem? */
sparse_memory_present_with_active_regions(0);
@@ -311,6 +317,16 @@ void __init paging_init(void)
}
#endif /* ! CONFIG_NEED_MULTIPLE_NODES */
+u64 __init get_max_mapped(void)
+{
+ u64 end = max_low_pfn;
+
+ end <<= PAGE_SHIFT;
+
+ return end;
+}
+
+
void __init mem_init(void)
{
#ifdef CONFIG_NEED_MULTIPLE_NODES
@@ -337,6 +353,9 @@ void __init mem_init(void)
free_all_bootmem_node(NODE_DATA(nid));
}
}
+#ifdef CONFIG_NO_BOOTMEM
+ totalram_pages += free_all_memory_core_early(MAX_NUMNODES);
+#endif
#else
max_mapnr = max_pfn;
totalram_pages += free_all_bootmem();
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index 64c0022..024c3ff 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -90,6 +90,7 @@ static int __cpuinit fake_numa_create_new_node(unsigned long end_pfn,
return 0;
}
+#ifndef CONFIG_NO_BOOTMEM
/*
* get_active_region_work_fn - A helper function for get_node_active_region
* Returns datax set to the start_pfn and end_pfn if they contain
@@ -131,6 +132,7 @@ static void __init get_node_active_region(unsigned long start_pfn,
node_ar->end_pfn = start_pfn;
work_with_active_regions(nid, get_active_region_work_fn, node_ar);
}
+#endif
static void __cpuinit map_cpu_to_node(int cpu, int node)
{
@@ -845,6 +847,7 @@ static struct notifier_block __cpuinitdata ppc64_numa_nb = {
.priority = 1 /* Must run before sched domains notifier. */
};
+#ifndef CONFIG_NO_BOOTMEM
static void mark_reserved_regions_for_nid(int nid)
{
struct pglist_data *node = NODE_DATA(nid);
@@ -911,7 +914,7 @@ static void mark_reserved_regions_for_nid(int nid)
}
}
}
-
+#endif
void __init do_init_bootmem(void)
{
@@ -932,8 +935,10 @@ void __init do_init_bootmem(void)
for_each_online_node(nid) {
unsigned long start_pfn, end_pfn;
+#ifndef CONFIG_NO_BOOTMEM
void *bootmem_vaddr;
unsigned long bootmap_pages;
+#endif
get_pfn_range_for_nid(nid, &start_pfn, &end_pfn);
@@ -951,7 +956,9 @@ void __init do_init_bootmem(void)
dbg("node %d\n", nid);
dbg("NODE_DATA() = %p\n", NODE_DATA(nid));
+#ifndef CONFIG_NO_BOOTMEM
NODE_DATA(nid)->bdata = &bootmem_node_data[nid];
+#endif
NODE_DATA(nid)->node_start_pfn = start_pfn;
NODE_DATA(nid)->node_spanned_pages = end_pfn - start_pfn;
@@ -961,6 +968,7 @@ void __init do_init_bootmem(void)
dbg("start_paddr = %lx\n", start_pfn << PAGE_SHIFT);
dbg("end_paddr = %lx\n", end_pfn << PAGE_SHIFT);
+#ifndef CONFIG_NO_BOOTMEM
bootmap_pages = bootmem_bootmap_pages(end_pfn - start_pfn);
bootmem_vaddr = careful_zallocation(nid,
bootmap_pages << PAGE_SHIFT,
@@ -979,6 +987,7 @@ void __init do_init_bootmem(void)
* done correctly.
*/
mark_reserved_regions_for_nid(nid);
+#endif
sparse_memory_present_with_active_regions(nid);
}
--
1.6.4.2
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH -v4 00/08] use lmb with x86
2010-03-24 10:37 [PATCH -v4 00/08] use lmb with x86 Yinghai Lu
` (7 preceding siblings ...)
2010-03-24 10:37 ` [PATCH 8/8] powerpc : use early_res/nobootmem Yinghai Lu
@ 2010-03-24 10:48 ` Ingo Molnar
2010-03-24 11:41 ` Michael Ellerman
2010-03-24 18:31 ` Yinghai Lu
8 siblings, 2 replies; 16+ messages in thread
From: Ingo Molnar @ 2010-03-24 10:48 UTC (permalink / raw)
To: Yinghai Lu
Cc: Thomas Gleixner, H. Peter Anvin, Andrew Morton, David Miller,
Benjamin Herrenschmidt, Linus Torvalds, linux-kernel
* Yinghai Lu <yinghai@kernel.org> wrote:
> new early_res is lmb extension. and it could be used to replace bootmem.
Why not do what we suggested: extend lmb.c to also offer the
early_res-equivalent functionality, and remove kernel/early_res.c and move
lib/lmb.c to mm/lmb.c?
We dont want two facilities (early_res and lmb) really ...
Ingo
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH -v4 00/08] use lmb with x86
2010-03-24 10:48 ` [PATCH -v4 00/08] use lmb with x86 Ingo Molnar
@ 2010-03-24 11:41 ` Michael Ellerman
2010-03-24 18:18 ` Yinghai Lu
2010-03-24 18:31 ` Yinghai Lu
1 sibling, 1 reply; 16+ messages in thread
From: Michael Ellerman @ 2010-03-24 11:41 UTC (permalink / raw)
To: Ingo Molnar
Cc: Yinghai Lu, Thomas Gleixner, H. Peter Anvin, Andrew Morton,
David Miller, Benjamin Herrenschmidt, Linus Torvalds,
linux-kernel
[-- Attachment #1: Type: text/plain, Size: 890 bytes --]
On Wed, 2010-03-24 at 11:48 +0100, Ingo Molnar wrote:
> * Yinghai Lu <yinghai@kernel.org> wrote:
>
> > new early_res is lmb extension. and it could be used to replace bootmem.
>
> Why not do what we suggested: extend lmb.c to also offer the
> early_res-equivalent functionality, and remove kernel/early_res.c and move
> lib/lmb.c to mm/lmb.c?
>
> We dont want two facilities (early_res and lmb) really ...
Exactly.
This series seems to leave us with kernel/early_res.c (which should
never have moved out of arch/x86 AFAICS) - as well as using some of
lmb.c.
It doesn't compile on powerpc, because early_res.c is looking for
find_fw_memmap_area() which is still under arch/x86.
And sprinkling CONFIG_NO_BOOTMEM everywhere is getting a bit gross. I
notice that's already happened to mm/(bootmem|page_alloc).c but
propagating it further is not nice.
cheers
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 197 bytes --]
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH -v4 00/08] use lmb with x86
2010-03-24 11:41 ` Michael Ellerman
@ 2010-03-24 18:18 ` Yinghai Lu
0 siblings, 0 replies; 16+ messages in thread
From: Yinghai Lu @ 2010-03-24 18:18 UTC (permalink / raw)
To: michael
Cc: Ingo Molnar, Thomas Gleixner, H. Peter Anvin, Andrew Morton,
David Miller, Benjamin Herrenschmidt, Linus Torvalds,
linux-kernel
On 03/24/2010 04:41 AM, Michael Ellerman wrote:
> On Wed, 2010-03-24 at 11:48 +0100, Ingo Molnar wrote:
>> * Yinghai Lu <yinghai@kernel.org> wrote:
>>
>>> new early_res is lmb extension. and it could be used to replace bootmem.
>>
>> Why not do what we suggested: extend lmb.c to also offer the
>> early_res-equivalent functionality, and remove kernel/early_res.c and move
>> lib/lmb.c to mm/lmb.c?
>>
>> We dont want two facilities (early_res and lmb) really ...
>
> Exactly.
>
> This series seems to leave us with kernel/early_res.c (which should
> never have moved out of arch/x86 AFAICS) - as well as using some of
> lmb.c.
the new version...
http://git.kernel.org/?p=linux/kernel/git/yinghai/linux-2.6-yinghai.git;a=blob;f=kernel/early_res.c;h=a7933939b44ae1ccb72e30203031f5b742c88a3f;hb=c9115b0731084ec0c0e164456b7434ea61c2a67b
should be clean.
>
> It doesn't compile on powerpc, because early_res.c is looking for
> find_fw_memmap_area() which is still under arch/x86.
it looks that you are looking at old version somehow.
please check
http://git.kernel.org/?p=linux/kernel/git/yinghai/linux-2.6-yinghai.git;a=summary
>
> And sprinkling CONFIG_NO_BOOTMEM everywhere is getting a bit gross. I
> notice that's already happened to mm/(bootmem|page_alloc).c but
> propagating it further is not nice.
for converting smoothly, before we remove bootmem core, we can keep it. and can compare bootmem and nobootmem side by side.
Thanks
Yinghai
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH -v4 00/08] use lmb with x86
2010-03-24 10:48 ` [PATCH -v4 00/08] use lmb with x86 Ingo Molnar
2010-03-24 11:41 ` Michael Ellerman
@ 2010-03-24 18:31 ` Yinghai Lu
1 sibling, 0 replies; 16+ messages in thread
From: Yinghai Lu @ 2010-03-24 18:31 UTC (permalink / raw)
To: Ingo Molnar, Benjamin Herrenschmidt
Cc: Thomas Gleixner, H. Peter Anvin, Andrew Morton, David Miller,
Linus Torvalds, linux-kernel
On 03/24/2010 03:48 AM, Ingo Molnar wrote:
>
> * Yinghai Lu <yinghai@kernel.org> wrote:
>
>> new early_res is lmb extension. and it could be used to replace bootmem.
>
> Why not do what we suggested: extend lmb.c to also offer the
> early_res-equivalent functionality, and remove kernel/early_res.c and move
> lib/lmb.c to mm/lmb.c?
>
> We dont want two facilities (early_res and lmb) really ...
the new early_res.c is extension to lmb.
it will
1. add find_lmb_area
2. add check_double_region array with find_lmb_area
3. free_early and reserve_early is wrapper for lmb_free, and lmb_reserve with array size checking
4. some other generizing function like lmb_register_active_regions and lmb_hole_size that could be all lmb users.
so it is seperated file at point.
if lmb guys are happy, we can merge early_res.c and lmb.c. just put them in one file.
Thanks
Yinghai
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/8] x86: do not free zero sized per cpu areas
2010-03-24 10:37 ` [PATCH 1/8] x86: do not free zero sized per cpu areas Yinghai Lu
@ 2010-03-25 22:29 ` Joel Becker
0 siblings, 0 replies; 16+ messages in thread
From: Joel Becker @ 2010-03-25 22:29 UTC (permalink / raw)
To: Yinghai Lu
Cc: Ingo Molnar, Thomas Gleixner, H. Peter Anvin, Andrew Morton,
David Miller, Benjamin Herrenschmidt, Linus Torvalds,
linux-kernel, Ian Campbell, Peter Zijlstra
On Wed, Mar 24, 2010 at 03:37:02AM -0700, Yinghai Lu wrote:
> From: Ian Campbell <ian.campbell@citrix.com>
>
> This avoids an infinite loop in free_early_partial().
>
> Add a warning to free_early_partial to catch future problems.
>
> -v5: put back start > end back into WARN_ONCE()
> -v6: use one line for if according to linus
>
> Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
> Signed-off-by: Yinghai Lu <yinghai@kernel.org>
> Cc: Peter Zijlstra <peterz@infradead.org>
> Cc: Ingo Molnar <mingo@elte.hu>
Tested-by: Joel Becker <joel.becker@oracle.com>
I ran into this when moving my paravirt_ops PVMs to 2.6.34-rc1.
I turned on CONFIG_NO_BOOTMEM to try it because it was the default. I
had to put earlyprintk=xen on the command line to debug the problem.
My boots hung after:
...
(early) Local APIC disabled by BIOS -- you can enable it with "lapic"
(early) APIC: disable apic facility
(early) APIC: switched to apic NOOP
(early) Allocating PCI resources starting at 78000000 (gap: 78000000:88000000)
(early) Booting paravirtualized kernel on Xen
(early) Xen version: 3.1.3-rc3
(early) setup_percpu: NR_CPUS:8 nr_cpumask_bits:8 nr_cpu_ids:2 nr_node_ids:1
Bisecting narrowed the problem to fb90ef [early_res: Add
free_early_partial()]. Turning off CONFIG_NO_BOOTMEM allowed me to
boot. I then hunted up references to this function, which found me this
patch.
This patch successfully resolved the problem.
Joel
--
"The nice thing about egotists is that they don't talk about other
people."
- Lucille S. Harper
Joel Becker
Principal Software Developer
Oracle
E-mail: joel.becker@oracle.com
Phone: (650) 506-8127
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH -v4 00/08] use lmb with x86
@ 2010-03-24 10:34 ` Yinghai Lu
0 siblings, 0 replies; 16+ messages in thread
From: Yinghai Lu @ 2010-03-24 10:34 UTC (permalink / raw)
To: Ingo Molnar, Thomas Gleixner, H. Peter Anvin, Andrew Morton,
David Miller, Benjamin Herrenschmidt, Linus Torvalds
Cc: linux-kernel, linux-arch, Yinghai Lu
new early_res is lmb extension. and it could be used to replace bootmem.
even could share some code before bootmem, like register_active_region, and
lm_reserved_to_bootmem
add test version for powerpc
Thanks
Yinghai
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH -v4 00/08] use lmb with x86
@ 2010-03-24 10:34 ` Yinghai Lu
0 siblings, 0 replies; 16+ messages in thread
From: Yinghai Lu @ 2010-03-24 10:34 UTC (permalink / raw)
To: Ingo Molnar, Thomas Gleixner, H. Peter Anvin, Andrew Morton,
David Miller, Be
Cc: linux-kernel, linux-arch, Yinghai Lu
new early_res is lmb extension. and it could be used to replace bootmem.
even could share some code before bootmem, like register_active_region, and
lm_reserved_to_bootmem
add test version for powerpc
Thanks
Yinghai
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2010-03-25 22:31 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-03-24 10:37 [PATCH -v4 00/08] use lmb with x86 Yinghai Lu
2010-03-24 10:37 ` [PATCH 1/8] x86: do not free zero sized per cpu areas Yinghai Lu
2010-03-25 22:29 ` Joel Becker
2010-03-24 10:37 ` [PATCH 2/8] x86: add find_e820_area_node Yinghai Lu
2010-03-24 10:37 ` [PATCH 3/8] x86: add sanitize_e820_map Yinghai Lu
2010-03-24 10:37 ` [PATCH 4/8] lmb: seperate region array from lmb_region struct Yinghai Lu
2010-03-24 10:37 ` [PATCH 5/8] x86: use lmb to replace early_res Yinghai Lu
2010-03-24 10:37 ` [PATCH 6/8] x86: remove find_e820_area Yinghai Lu
2010-03-24 10:37 ` [PATCH 7/8] early_res: prepare for other platform to use it Yinghai Lu
2010-03-24 10:37 ` [PATCH 8/8] powerpc : use early_res/nobootmem Yinghai Lu
2010-03-24 10:48 ` [PATCH -v4 00/08] use lmb with x86 Ingo Molnar
2010-03-24 11:41 ` Michael Ellerman
2010-03-24 18:18 ` Yinghai Lu
2010-03-24 18:31 ` Yinghai Lu
-- strict thread matches above, loose matches on Subject: below --
2010-03-24 10:34 Yinghai Lu
2010-03-24 10:34 ` Yinghai Lu
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.