diff options
author | Andre Heider <a.heider@gmail.com> | 2011-08-11 23:31:07 +0400 |
---|---|---|
committer | Geoff Levand <geoff@infradead.org> | 2012-04-25 02:34:17 +0400 |
commit | 1e755c09926de2d9b0e239ba0ce10fdb6835551a (patch) | |
tree | aa60bd3bdc86d801980cc6d0de6bd90a649ca6d9 | |
parent | 6750edbd8d6d1d72365e29e58b05f164bc23755a (diff) | |
download | linux-1e755c09926de2d9b0e239ba0ce10fdb6835551a.tar.xz |
powerpc/ps3: Use highmem region from repository
Use any preallocated highmem region setup by the bootloader.
This implementation only checks for the existance of a single
region at region_index=0.
This feature allows the bootloader to preallocate highmem
regions and pass the region locations to the kernel through
the repository. Preallocated regions can be used to hold the
initrd or other large data. If no region info exists, the
kernel retains the old behavior and attempts to allocate the
highmem region itself.
Based on Hector Martin's patch "Get lv1 high memory region from
devtree".
CC: Hector Martin <hector@marcansoft.com>
Signed-off-by: Andre Heider <a.heider@gmail.com>
CC: Nathan Whitehorn <nwhitehorn@freebsd.org>
Signed-off-by: Geoff Levand <geoff@infradead.org>
-rw-r--r-- | arch/powerpc/platforms/ps3/mm.c | 51 |
1 files changed, 49 insertions, 2 deletions
diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c index de2aea421707..05a2bcb6a875 100644 --- a/arch/powerpc/platforms/ps3/mm.c +++ b/arch/powerpc/platforms/ps3/mm.c @@ -79,12 +79,14 @@ enum { * @base: base address * @size: size in bytes * @offset: difference between base and rm.size + * @destroy: flag if region should be destroyed upon shutdown */ struct mem_region { u64 base; u64 size; unsigned long offset; + int destroy; }; /** @@ -262,6 +264,7 @@ static int ps3_mm_region_create(struct mem_region *r, unsigned long size) goto zero_region; } + r->destroy = 1; r->offset = r->base - map.rm.size; return result; @@ -279,7 +282,14 @@ static void ps3_mm_region_destroy(struct mem_region *r) { int result; + if (!r->destroy) { + pr_info("%s:%d: Not destroying high region: %llxh %llxh\n", + __func__, __LINE__, r->base, r->size); + return; + } + DBG("%s:%d: r->base = %llxh\n", __func__, __LINE__, r->base); + if (r->base) { result = lv1_release_memory(r->base); BUG_ON(result); @@ -288,6 +298,36 @@ static void ps3_mm_region_destroy(struct mem_region *r) } } +static int ps3_mm_get_repository_highmem(struct mem_region *r) +{ + int result; + + /* Assume a single highmem region. */ + + result = ps3_repository_read_highmem_info(0, &r->base, &r->size); + + if (result) + goto zero_region; + + if (!r->base || !r->size) { + result = -1; + goto zero_region; + } + + r->offset = r->base - map.rm.size; + + DBG("%s:%d: Found high region in repository: %llxh %llxh\n", + __func__, __LINE__, r->base, r->size); + + return 0; + +zero_region: + DBG("%s:%d: No high region in repository.\n", __func__, __LINE__); + + r->size = r->base = r->offset = 0; + return result; +} + /** * ps3_mm_add_memory - hot add memory */ @@ -304,6 +344,12 @@ static int __init ps3_mm_add_memory(void) BUG_ON(!mem_init_done); + if (!map.r1.size) { + DBG("%s:%d: No region 1, not adding memory\n", + __func__, __LINE__); + return 0; + } + start_addr = map.rm.size; start_pfn = start_addr >> PAGE_SHIFT; nr_pages = (map.r1.size + PAGE_SIZE - 1) >> PAGE_SHIFT; @@ -1217,9 +1263,10 @@ void __init ps3_mm_init(void) BUG_ON(map.rm.base); BUG_ON(!map.rm.size); + /* Check if we got the highmem region from an earlier boot step */ - /* arrange to do this in ps3_mm_add_memory */ - ps3_mm_region_create(&map.r1, map.total - map.rm.size); + if (ps3_mm_get_repository_highmem(&map.r1)) + ps3_mm_region_create(&map.r1, map.total - map.rm.size); /* correct map.total for the real total amount of memory we use */ map.total = map.rm.size + map.r1.size; |