diff options
-rw-r--r-- | include/linux/ioport.h | 3 | ||||
-rw-r--r-- | include/linux/memory_hotplug.h | 8 | ||||
-rw-r--r-- | kernel/resource.c | 26 | ||||
-rw-r--r-- | mm/memory_hotplug.c | 45 |
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, | |||
110 | int adjust_resource(struct resource *res, resource_size_t start, | 110 | int 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 */ | ||
114 | extern 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); | |||
63 | extern int __add_pages(struct zone *zone, unsigned long start_pfn, | 63 | extern 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 | */ | ||
70 | extern 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 |
67 | extern int memory_add_physaddr_to_nid(u64 start); | 75 | extern 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 | */ |
237 | int find_next_system_ram(struct resource *res) | 237 | static 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 | } |
270 | int | ||
271 | walk_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 | ||
164 | int online_pages(unsigned long pfn, unsigned long nr_pages) | 164 | static 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 | |||
181 | int 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 | ||