aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/ioport.h3
-rw-r--r--include/linux/memory_hotplug.h8
-rw-r--r--kernel/resource.c26
-rw-r--r--mm/memory_hotplug.c45
4 files changed, 52 insertions, 30 deletions
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index 71ea9231924..6187a8567bc 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -110,9 +110,6 @@ extern int allocate_resource(struct resource *root, struct resource *new,
110int adjust_resource(struct resource *res, resource_size_t start, 110int adjust_resource(struct resource *res, resource_size_t start,
111 resource_size_t size); 111 resource_size_t size);
112 112
113/* get registered SYSTEM_RAM resources in specified area */
114extern int find_next_system_ram(struct resource *res);
115
116/* Convenience shorthand with allocation */ 113/* Convenience shorthand with allocation */
117#define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name)) 114#define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name))
118#define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name)) 115#define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name))
diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h
index b573d1ec871..0a14dad9545 100644
--- a/include/linux/memory_hotplug.h
+++ b/include/linux/memory_hotplug.h
@@ -63,6 +63,14 @@ extern int online_pages(unsigned long, unsigned long);
63extern int __add_pages(struct zone *zone, unsigned long start_pfn, 63extern int __add_pages(struct zone *zone, unsigned long start_pfn,
64 unsigned long nr_pages); 64 unsigned long nr_pages);
65 65
66/*
67 * Walk thorugh all memory which is registered as resource.
68 * arg is (start_pfn, nr_pages, private_arg_pointer)
69 */
70extern int walk_memory_resource(unsigned long start_pfn,
71 unsigned long nr_pages, void *arg,
72 int (*func)(unsigned long, unsigned long, void *));
73
66#ifdef CONFIG_NUMA 74#ifdef CONFIG_NUMA
67extern int memory_add_physaddr_to_nid(u64 start); 75extern int memory_add_physaddr_to_nid(u64 start);
68#else 76#else
diff --git a/kernel/resource.c b/kernel/resource.c
index 9bd14fd3e6d..a358142ff48 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -234,7 +234,7 @@ EXPORT_SYMBOL(release_resource);
234 * the caller must specify res->start, res->end, res->flags. 234 * the caller must specify res->start, res->end, res->flags.
235 * If found, returns 0, res is overwritten, if not found, returns -1. 235 * If found, returns 0, res is overwritten, if not found, returns -1.
236 */ 236 */
237int find_next_system_ram(struct resource *res) 237static int find_next_system_ram(struct resource *res)
238{ 238{
239 resource_size_t start, end; 239 resource_size_t start, end;
240 struct resource *p; 240 struct resource *p;
@@ -267,6 +267,30 @@ int find_next_system_ram(struct resource *res)
267 res->end = p->end; 267 res->end = p->end;
268 return 0; 268 return 0;
269} 269}
270int
271walk_memory_resource(unsigned long start_pfn, unsigned long nr_pages, void *arg,
272 int (*func)(unsigned long, unsigned long, void *))
273{
274 struct resource res;
275 unsigned long pfn, len;
276 u64 orig_end;
277 int ret = -1;
278 res.start = (u64) start_pfn << PAGE_SHIFT;
279 res.end = ((u64)(start_pfn + nr_pages) << PAGE_SHIFT) - 1;
280 res.flags = IORESOURCE_MEM;
281 orig_end = res.end;
282 while ((res.start < res.end) && (find_next_system_ram(&res) >= 0)) {
283 pfn = (unsigned long)(res.start >> PAGE_SHIFT);
284 len = (unsigned long)((res.end + 1 - res.start) >> PAGE_SHIFT);
285 ret = (*func)(pfn, len, arg);
286 if (ret)
287 break;
288 res.start = res.end + 1;
289 res.end = orig_end;
290 }
291 return ret;
292}
293
270#endif 294#endif
271 295
272/* 296/*
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 9c12ae5e369..1cbe9579e23 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -161,14 +161,27 @@ static void grow_pgdat_span(struct pglist_data *pgdat,
161 pgdat->node_start_pfn; 161 pgdat->node_start_pfn;
162} 162}
163 163
164int online_pages(unsigned long pfn, unsigned long nr_pages) 164static int online_pages_range(unsigned long start_pfn, unsigned long nr_pages,
165 void *arg)
165{ 166{
166 unsigned long i; 167 unsigned long i;
168 unsigned long onlined_pages = *(unsigned long *)arg;
169 struct page *page;
170 if (PageReserved(pfn_to_page(start_pfn)))
171 for (i = 0; i < nr_pages; i++) {
172 page = pfn_to_page(start_pfn + i);
173 online_page(page);
174 onlined_pages++;
175 }
176 *(unsigned long *)arg = onlined_pages;
177 return 0;
178}
179
180
181int online_pages(unsigned long pfn, unsigned long nr_pages)
182{
167 unsigned long flags; 183 unsigned long flags;
168 unsigned long onlined_pages = 0; 184 unsigned long onlined_pages = 0;
169 struct resource res;
170 u64 section_end;
171 unsigned long start_pfn;
172 struct zone *zone; 185 struct zone *zone;
173 int need_zonelists_rebuild = 0; 186 int need_zonelists_rebuild = 0;
174 187
@@ -191,28 +204,8 @@ int online_pages(unsigned long pfn, unsigned long nr_pages)
191 if (!populated_zone(zone)) 204 if (!populated_zone(zone))
192 need_zonelists_rebuild = 1; 205 need_zonelists_rebuild = 1;
193 206
194 res.start = (u64)pfn << PAGE_SHIFT; 207 walk_memory_resource(pfn, nr_pages, &onlined_pages,
195 res.end = res.start + ((u64)nr_pages << PAGE_SHIFT) - 1; 208 online_pages_range);
196 res.flags = IORESOURCE_MEM; /* we just need system ram */
197 section_end = res.end;
198
199 while ((res.start < res.end) && (find_next_system_ram(&res) >= 0)) {
200 start_pfn = (unsigned long)(res.start >> PAGE_SHIFT);
201 nr_pages = (unsigned long)
202 ((res.end + 1 - res.start) >> PAGE_SHIFT);
203
204 if (PageReserved(pfn_to_page(start_pfn))) {
205 /* this region's page is not onlined now */
206 for (i = 0; i < nr_pages; i++) {
207 struct page *page = pfn_to_page(start_pfn + i);
208 online_page(page);
209 onlined_pages++;
210 }
211 }
212
213 res.start = res.end + 1;
214 res.end = section_end;
215 }
216 zone->present_pages += onlined_pages; 209 zone->present_pages += onlined_pages;
217 zone->zone_pgdat->node_present_pages += onlined_pages; 210 zone->zone_pgdat->node_present_pages += onlined_pages;
218 211