diff --git a/include/linux/ioport.h b/include/linux/ioport.h index 71ea92319241..6187a8567bc7 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, int adjust_resource(struct resource *res, resource_size_t start, resource_size_t size); -/* get registered SYSTEM_RAM resources in specified area */ -extern int find_next_system_ram(struct resource *res); - /* Convenience shorthand with allocation */ #define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name)) #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 b573d1ec871f..0a14dad95453 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); extern int __add_pages(struct zone *zone, unsigned long start_pfn, unsigned long nr_pages); +/* + * Walk thorugh all memory which is registered as resource. + * arg is (start_pfn, nr_pages, private_arg_pointer) + */ +extern int walk_memory_resource(unsigned long start_pfn, + unsigned long nr_pages, void *arg, + int (*func)(unsigned long, unsigned long, void *)); + #ifdef CONFIG_NUMA extern int memory_add_physaddr_to_nid(u64 start); #else diff --git a/kernel/resource.c b/kernel/resource.c index 9bd14fd3e6de..a358142ff48f 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -234,7 +234,7 @@ EXPORT_SYMBOL(release_resource); * the caller must specify res->start, res->end, res->flags. * If found, returns 0, res is overwritten, if not found, returns -1. */ -int find_next_system_ram(struct resource *res) +static int find_next_system_ram(struct resource *res) { resource_size_t start, end; struct resource *p; @@ -267,6 +267,30 @@ int find_next_system_ram(struct resource *res) res->end = p->end; return 0; } +int +walk_memory_resource(unsigned long start_pfn, unsigned long nr_pages, void *arg, + int (*func)(unsigned long, unsigned long, void *)) +{ + struct resource res; + unsigned long pfn, len; + u64 orig_end; + int ret = -1; + res.start = (u64) start_pfn << PAGE_SHIFT; + res.end = ((u64)(start_pfn + nr_pages) << PAGE_SHIFT) - 1; + res.flags = IORESOURCE_MEM; + orig_end = res.end; + while ((res.start < res.end) && (find_next_system_ram(&res) >= 0)) { + pfn = (unsigned long)(res.start >> PAGE_SHIFT); + len = (unsigned long)((res.end + 1 - res.start) >> PAGE_SHIFT); + ret = (*func)(pfn, len, arg); + if (ret) + break; + res.start = res.end + 1; + res.end = orig_end; + } + return ret; +} + #endif /* diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 9c12ae5e3695..1cbe9579e233 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -161,14 +161,27 @@ static void grow_pgdat_span(struct pglist_data *pgdat, pgdat->node_start_pfn; } -int online_pages(unsigned long pfn, unsigned long nr_pages) +static int online_pages_range(unsigned long start_pfn, unsigned long nr_pages, + void *arg) { unsigned long i; + unsigned long onlined_pages = *(unsigned long *)arg; + struct page *page; + if (PageReserved(pfn_to_page(start_pfn))) + for (i = 0; i < nr_pages; i++) { + page = pfn_to_page(start_pfn + i); + online_page(page); + onlined_pages++; + } + *(unsigned long *)arg = onlined_pages; + return 0; +} + + +int online_pages(unsigned long pfn, unsigned long nr_pages) +{ unsigned long flags; unsigned long onlined_pages = 0; - struct resource res; - u64 section_end; - unsigned long start_pfn; struct zone *zone; int need_zonelists_rebuild = 0; @@ -191,28 +204,8 @@ int online_pages(unsigned long pfn, unsigned long nr_pages) if (!populated_zone(zone)) need_zonelists_rebuild = 1; - res.start = (u64)pfn << PAGE_SHIFT; - res.end = res.start + ((u64)nr_pages << PAGE_SHIFT) - 1; - res.flags = IORESOURCE_MEM; /* we just need system ram */ - section_end = res.end; - - while ((res.start < res.end) && (find_next_system_ram(&res) >= 0)) { - start_pfn = (unsigned long)(res.start >> PAGE_SHIFT); - nr_pages = (unsigned long) - ((res.end + 1 - res.start) >> PAGE_SHIFT); - - if (PageReserved(pfn_to_page(start_pfn))) { - /* this region's page is not onlined now */ - for (i = 0; i < nr_pages; i++) { - struct page *page = pfn_to_page(start_pfn + i); - online_page(page); - onlined_pages++; - } - } - - res.start = res.end + 1; - res.end = section_end; - } + walk_memory_resource(pfn, nr_pages, &onlined_pages, + online_pages_range); zone->present_pages += onlined_pages; zone->zone_pgdat->node_present_pages += onlined_pages;