aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYinghai Lu <yinghai@kernel.org>2010-10-12 17:07:09 -0400
committerH. Peter Anvin <hpa@linux.intel.com>2010-10-12 18:37:51 -0400
commitc7fc2de0c83dbd2eaf759c5cd0e2b9cf1eb4df3a (patch)
treec4413e9b3bc164394c2daccf34e18e0b1d6c8811
parent8e4029ee3517084ae00fbfbcb51cc365d8857061 (diff)
memblock, bootmem: Round pfn properly for memory and reserved regions
We need to round memory regions correctly -- specifically, we need to round reserved region in the more expansive direction (lower limit down, upper limit up) whereas usable memory regions need to be rounded in the more restrictive direction (lower limit up, upper limit down). This introduces two set of inlines: memblock_region_memory_base_pfn() memblock_region_memory_end_pfn() memblock_region_reserved_base_pfn() memblock_region_reserved_end_pfn() Although they are antisymmetric (and therefore are technically duplicates) the use of the different inlines explicitly documents the programmer's intention. The lack of proper rounding caused a bug on ARM, which was then found to also affect other architectures. Reported-by: Russell King <rmk@arm.linux.org.uk> Signed-off-by: Yinghai Lu <yinghai@kernel.org> LKML-Reference: <4CB4CDFD.4020105@kernel.org> Cc: Jeremy Fitzhardinge <jeremy@goop.org> Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
-rw-r--r--arch/arm/mm/init.c8
-rw-r--r--arch/powerpc/mm/mem.c14
-rw-r--r--arch/powerpc/mm/numa.c4
-rw-r--r--arch/sh/mm/init.c4
-rw-r--r--arch/sparc/mm/init_64.c4
-rw-r--r--include/linux/memblock.h25
6 files changed, 29 insertions, 30 deletions
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index d6022d1f51d1..63f441797c96 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -182,8 +182,8 @@ static void __init arm_bootmem_init(struct meminfo *mi,
182 * Reserve the memblock reserved regions in bootmem. 182 * Reserve the memblock reserved regions in bootmem.
183 */ 183 */
184 for_each_memblock(reserved, reg) { 184 for_each_memblock(reserved, reg) {
185 phys_addr_t start = memblock_region_base_pfn(reg); 185 phys_addr_t start = memblock_region_reserved_base_pfn(reg);
186 phys_addr_t end = memblock_region_end_pfn(reg); 186 phys_addr_t end = memblock_region_reserved_end_pfn(reg);
187 if (start >= start_pfn && end <= end_pfn) 187 if (start >= start_pfn && end <= end_pfn)
188 reserve_bootmem_node(pgdat, __pfn_to_phys(start), 188 reserve_bootmem_node(pgdat, __pfn_to_phys(start),
189 (end - start) << PAGE_SHIFT, 189 (end - start) << PAGE_SHIFT,
@@ -251,8 +251,8 @@ static void arm_memory_present(void)
251 struct memblock_region *reg; 251 struct memblock_region *reg;
252 252
253 for_each_memblock(memory, reg) 253 for_each_memblock(memory, reg)
254 memory_present(0, memblock_region_base_pfn(reg), 254 memory_present(0, memblock_region_memory_base_pfn(reg),
255 memblock_region_end_pfn(reg)); 255 memblock_region_memory_end_pfn(reg));
256} 256}
257#endif 257#endif
258 258
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index f661f6c527da..a66499650909 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -148,8 +148,8 @@ walk_system_ram_range(unsigned long start_pfn, unsigned long nr_pages,
148 int ret = -1; 148 int ret = -1;
149 149
150 for_each_memblock(memory, reg) { 150 for_each_memblock(memory, reg) {
151 tstart = max(start_pfn, memblock_region_base_pfn(reg)); 151 tstart = max(start_pfn, memblock_region_memory_base_pfn(reg));
152 tend = min(end_pfn, memblock_region_end_pfn(reg)); 152 tend = min(end_pfn, memblock_region_memory_end_pfn(reg));
153 if (tstart >= tend) 153 if (tstart >= tend)
154 continue; 154 continue;
155 ret = (*func)(tstart, tend - tstart, arg); 155 ret = (*func)(tstart, tend - tstart, arg);
@@ -195,8 +195,8 @@ void __init do_init_bootmem(void)
195 /* Add active regions with valid PFNs */ 195 /* Add active regions with valid PFNs */
196 for_each_memblock(memory, reg) { 196 for_each_memblock(memory, reg) {
197 unsigned long start_pfn, end_pfn; 197 unsigned long start_pfn, end_pfn;
198 start_pfn = memblock_region_base_pfn(reg); 198 start_pfn = memblock_region_memory_base_pfn(reg);
199 end_pfn = memblock_region_end_pfn(reg); 199 end_pfn = memblock_region_memory_end_pfn(reg);
200 add_active_range(0, start_pfn, end_pfn); 200 add_active_range(0, start_pfn, end_pfn);
201 } 201 }
202 202
@@ -236,9 +236,9 @@ static int __init mark_nonram_nosave(void)
236 236
237 for_each_memblock(memory, reg) { 237 for_each_memblock(memory, reg) {
238 if (prev && 238 if (prev &&
239 memblock_region_end_pfn(prev) < memblock_region_base_pfn(reg)) 239 memblock_region_memory_end_pfn(prev) < memblock_region_memory_base_pfn(reg))
240 register_nosave_region(memblock_region_end_pfn(prev), 240 register_nosave_region(memblock_region_memory_end_pfn(prev),
241 memblock_region_base_pfn(reg)); 241 memblock_region_memory_base_pfn(reg));
242 prev = reg; 242 prev = reg;
243 } 243 }
244 return 0; 244 return 0;
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index 066fb443ba5a..74505b245374 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -811,8 +811,8 @@ static void __init setup_nonnuma(void)
811 (top_of_ram - total_ram) >> 20); 811 (top_of_ram - total_ram) >> 20);
812 812
813 for_each_memblock(memory, reg) { 813 for_each_memblock(memory, reg) {
814 start_pfn = memblock_region_base_pfn(reg); 814 start_pfn = memblock_region_memory_base_pfn(reg);
815 end_pfn = memblock_region_end_pfn(reg); 815 end_pfn = memblock_region_memory_end_pfn(reg);
816 816
817 fake_numa_create_new_node(end_pfn, &nid); 817 fake_numa_create_new_node(end_pfn, &nid);
818 add_active_range(nid, start_pfn, end_pfn); 818 add_active_range(nid, start_pfn, end_pfn);
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c
index b977475f7446..552bea5113f5 100644
--- a/arch/sh/mm/init.c
+++ b/arch/sh/mm/init.c
@@ -244,8 +244,8 @@ static void __init do_init_bootmem(void)
244 /* Add active regions with valid PFNs. */ 244 /* Add active regions with valid PFNs. */
245 for_each_memblock(memory, reg) { 245 for_each_memblock(memory, reg) {
246 unsigned long start_pfn, end_pfn; 246 unsigned long start_pfn, end_pfn;
247 start_pfn = memblock_region_base_pfn(reg); 247 start_pfn = memblock_region_memory_base_pfn(reg);
248 end_pfn = memblock_region_end_pfn(reg); 248 end_pfn = memblock_region_memory_end_pfn(reg);
249 __add_active_range(0, start_pfn, end_pfn); 249 __add_active_range(0, start_pfn, end_pfn);
250 } 250 }
251 251
diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c
index dc584d26d597..4c2572773b55 100644
--- a/arch/sparc/mm/init_64.c
+++ b/arch/sparc/mm/init_64.c
@@ -1294,8 +1294,8 @@ static void __init bootmem_init_nonnuma(void)
1294 if (!reg->size) 1294 if (!reg->size)
1295 continue; 1295 continue;
1296 1296
1297 start_pfn = memblock_region_base_pfn(reg); 1297 start_pfn = memblock_region_memory_base_pfn(reg);
1298 end_pfn = memblock_region_end_pfn(reg); 1298 end_pfn = memblock_region_memory_end_pfn(reg);
1299 add_active_range(0, start_pfn, end_pfn); 1299 add_active_range(0, start_pfn, end_pfn);
1300 } 1300 }
1301 1301
diff --git a/include/linux/memblock.h b/include/linux/memblock.h
index 5096458c7535..62a10c2a11f2 100644
--- a/include/linux/memblock.h
+++ b/include/linux/memblock.h
@@ -111,40 +111,39 @@ extern void memblock_set_current_limit(phys_addr_t limit);
111 */ 111 */
112 112
113/** 113/**
114 * memblock_region_base_pfn - Return the lowest pfn intersecting with the region 114 * memblock_region_memory_base_pfn - Return the lowest pfn intersecting with the memory region
115 * @reg: memblock_region structure 115 * @reg: memblock_region structure
116 */ 116 */
117static inline unsigned long memblock_region_base_pfn(const struct memblock_region *reg) 117static inline unsigned long memblock_region_memory_base_pfn(const struct memblock_region *reg)
118{ 118{
119 return reg->base >> PAGE_SHIFT; 119 return PFN_UP(reg->base);
120} 120}
121 121
122/** 122/**
123 * memblock_region_last_pfn - Return the highest pfn intersecting with the region 123 * memblock_region_memory_end_pfn - Return the end_pfn this region
124 * @reg: memblock_region structure 124 * @reg: memblock_region structure
125 */ 125 */
126static inline unsigned long memblock_region_last_pfn(const struct memblock_region *reg) 126static inline unsigned long memblock_region_memory_end_pfn(const struct memblock_region *reg)
127{ 127{
128 return (reg->base + reg->size - 1) >> PAGE_SHIFT; 128 return PFN_DOWN(reg->base + reg->size);
129} 129}
130 130
131/** 131/**
132 * memblock_region_end_pfn - Return the pfn of the first page following the region 132 * memblock_region_reserved_base_pfn - Return the lowest pfn intersecting with the reserved region
133 * but not intersecting it
134 * @reg: memblock_region structure 133 * @reg: memblock_region structure
135 */ 134 */
136static inline unsigned long memblock_region_end_pfn(const struct memblock_region *reg) 135static inline unsigned long memblock_region_reserved_base_pfn(const struct memblock_region *reg)
137{ 136{
138 return memblock_region_last_pfn(reg) + 1; 137 return PFN_DOWN(reg->base);
139} 138}
140 139
141/** 140/**
142 * memblock_region_pages - Return the number of pages covering a region 141 * memblock_region_reserved_end_pfn - Return the end_pfn this region
143 * @reg: memblock_region structure 142 * @reg: memblock_region structure
144 */ 143 */
145static inline unsigned long memblock_region_pages(const struct memblock_region *reg) 144static inline unsigned long memblock_region_reserved_end_pfn(const struct memblock_region *reg)
146{ 145{
147 return memblock_region_end_pfn(reg) - memblock_region_end_pfn(reg); 146 return PFN_UP(reg->base + reg->size);
148} 147}
149 148
150#define for_each_memblock(memblock_type, region) \ 149#define for_each_memblock(memblock_type, region) \