From 07c044c86e05818c2d5e99b8ff881e2e4543c6ad Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Sat, 31 Mar 2012 18:03:30 -0700 Subject: powerpc/ps3: Add PS3 repository write support Add a new config option CONFIG_PS3_REPOSITORY_WRITE that conditionally builds in support to create, write and delete nodes in the PS3 system repository. This support will allow Linux based bootloaders to manage data in the system repository for use by later boot stages, Signed-off-by: Geoff Levand --- arch/powerpc/platforms/ps3/Kconfig | 13 ++++++++ arch/powerpc/platforms/ps3/repository.c | 58 +++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig index 476d9d9b240..4210aaae6e0 100644 --- a/arch/powerpc/platforms/ps3/Kconfig +++ b/arch/powerpc/platforms/ps3/Kconfig @@ -88,6 +88,19 @@ config PS3_SYS_MANAGER This support is required for system control. In general, all users will say Y or M. +config PS3_REPOSITORY_WRITE + bool "PS3 Repository write support" if PS3_ADVANCED + depends on PPC_PS3 + default n + help + Enables support for writing to the PS3 System Repository. + + This support is intended for bootloaders that need to store data + in the repository for later boot stages. + + If in doubt, say N here and reduce the size of the kernel by a + small amount. + config PS3_STORAGE depends on PPC_PS3 tristate diff --git a/arch/powerpc/platforms/ps3/repository.c b/arch/powerpc/platforms/ps3/repository.c index 7bdfea336f5..b31142cb9e5 100644 --- a/arch/powerpc/platforms/ps3/repository.c +++ b/arch/powerpc/platforms/ps3/repository.c @@ -1002,6 +1002,64 @@ int ps3_repository_read_lpm_privileges(unsigned int be_index, u64 *lpar, lpar, rights); } +#if defined(CONFIG_PS3_REPOSITORY_WRITE) + +static int create_node(u64 n1, u64 n2, u64 n3, u64 n4, u64 v1, u64 v2) +{ + int result; + + dump_node(0, n1, n2, n3, n4, v1, v2); + + result = lv1_create_repository_node(n1, n2, n3, n4, v1, v2); + + if (result) { + pr_devel("%s:%d: lv1_create_repository_node failed: %s\n", + __func__, __LINE__, ps3_result(result)); + return -ENOENT; + } + + return 0; +} + +static int delete_node(u64 n1, u64 n2, u64 n3, u64 n4) +{ + int result; + + dump_node(0, n1, n2, n3, n4, 0, 0); + + result = lv1_delete_repository_node(n1, n2, n3, n4); + + if (result) { + pr_devel("%s:%d: lv1_delete_repository_node failed: %s\n", + __func__, __LINE__, ps3_result(result)); + return -ENOENT; + } + + return 0; +} + +static int write_node(u64 n1, u64 n2, u64 n3, u64 n4, u64 v1, u64 v2) +{ + int result; + + result = create_node(n1, n2, n3, n4, v1, v2); + + if (!result) + return 0; + + result = lv1_write_repository_node(n1, n2, n3, n4, v1, v2); + + if (result) { + pr_devel("%s:%d: lv1_write_repository_node failed: %s\n", + __func__, __LINE__, ps3_result(result)); + return -ENOENT; + } + + return 0; +} + +#endif /* defined(CONFIG_PS3_WRITE_REPOSITORY) */ + #if defined(DEBUG) int ps3_repository_dump_resource_info(const struct ps3_repository_device *repo) -- cgit v1.2.3-18-g5258 From 79f2a81bf117ffea757b0f298467333cf4e835a8 Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Sat, 31 Mar 2012 18:13:36 -0700 Subject: powerpc/ps3: Add highmem repository write routines Add routines to allow Linux based bootloaders to create and/or modify highmem region info in the PS3 system repository where it can be retrived by later boot stages. Signed-off-by: Geoff Levand --- arch/powerpc/platforms/ps3/platform.h | 9 ++++ arch/powerpc/platforms/ps3/repository.c | 74 +++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h index 1a633ed0fe9..4012a86515c 100644 --- a/arch/powerpc/platforms/ps3/platform.h +++ b/arch/powerpc/platforms/ps3/platform.h @@ -189,6 +189,15 @@ int ps3_repository_read_region_total(u64 *region_total); int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size, u64 *region_total); +int ps3_repository_write_highmem_region_count(unsigned int region_count); +int ps3_repository_write_highmem_base(unsigned int region_index, + u64 highmem_base); +int ps3_repository_write_highmem_size(unsigned int region_index, + u64 highmem_size); +int ps3_repository_write_highmem_info(unsigned int region_index, + u64 highmem_base, u64 highmem_size); +int ps3_repository_delete_highmem_info(unsigned int region_index); + /* repository pme info */ int ps3_repository_read_num_be(unsigned int *num_be); diff --git a/arch/powerpc/platforms/ps3/repository.c b/arch/powerpc/platforms/ps3/repository.c index b31142cb9e5..c73f3a68d2a 100644 --- a/arch/powerpc/platforms/ps3/repository.c +++ b/arch/powerpc/platforms/ps3/repository.c @@ -1058,6 +1058,80 @@ static int write_node(u64 n1, u64 n2, u64 n3, u64 n4, u64 v1, u64 v2) return 0; } +int ps3_repository_write_highmem_region_count(unsigned int region_count) +{ + int result; + u64 v1 = (u64)region_count; + + result = write_node( + make_first_field("highmem", 0), + make_field("region", 0), + make_field("count", 0), + 0, + v1, 0); + return result; +} + +int ps3_repository_write_highmem_base(unsigned int region_index, + u64 highmem_base) +{ + return write_node( + make_first_field("highmem", 0), + make_field("region", region_index), + make_field("base", 0), + 0, + highmem_base, 0); +} + +int ps3_repository_write_highmem_size(unsigned int region_index, + u64 highmem_size) +{ + return write_node( + make_first_field("highmem", 0), + make_field("region", region_index), + make_field("size", 0), + 0, + highmem_size, 0); +} + +int ps3_repository_write_highmem_info(unsigned int region_index, + u64 highmem_base, u64 highmem_size) +{ + int result; + + result = ps3_repository_write_highmem_base(region_index, highmem_base); + return result ? result + : ps3_repository_write_highmem_size(region_index, highmem_size); +} + +static int ps3_repository_delete_highmem_base(unsigned int region_index) +{ + return delete_node( + make_first_field("highmem", 0), + make_field("region", region_index), + make_field("base", 0), + 0); +} + +static int ps3_repository_delete_highmem_size(unsigned int region_index) +{ + return delete_node( + make_first_field("highmem", 0), + make_field("region", region_index), + make_field("size", 0), + 0); +} + +int ps3_repository_delete_highmem_info(unsigned int region_index) +{ + int result; + + result = ps3_repository_delete_highmem_base(region_index); + result += ps3_repository_delete_highmem_size(region_index); + + return result ? -1 : 0; +} + #endif /* defined(CONFIG_PS3_WRITE_REPOSITORY) */ #if defined(DEBUG) -- cgit v1.2.3-18-g5258 From 6750edbd8d6d1d72365e29e58b05f164bc23755a Mon Sep 17 00:00:00 2001 From: Andre Heider Date: Thu, 11 Aug 2011 21:31:06 +0200 Subject: powerpc/ps3: Add highmem repository read routines Add repository helper routines to read highmem region info. Bootloaders that preallocate highmem regions must place the region info into the repository at these well known nodes. These routines allow second stage kernles to read the region info from those nodes. Signed-off-by: Andre Heider CC: Nathan Whitehorn Signed-off-by: Geoff Levand --- arch/powerpc/platforms/ps3/platform.h | 7 ++++ arch/powerpc/platforms/ps3/repository.c | 66 +++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h index 4012a86515c..d71329a8e32 100644 --- a/arch/powerpc/platforms/ps3/platform.h +++ b/arch/powerpc/platforms/ps3/platform.h @@ -188,6 +188,13 @@ int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size); int ps3_repository_read_region_total(u64 *region_total); int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size, u64 *region_total); +int ps3_repository_read_highmem_region_count(unsigned int *region_count); +int ps3_repository_read_highmem_base(unsigned int region_index, + u64 *highmem_base); +int ps3_repository_read_highmem_size(unsigned int region_index, + u64 *highmem_size); +int ps3_repository_read_highmem_info(unsigned int region_index, + u64 *highmem_base, u64 *highmem_size); int ps3_repository_write_highmem_region_count(unsigned int region_count); int ps3_repository_write_highmem_base(unsigned int region_index, diff --git a/arch/powerpc/platforms/ps3/repository.c b/arch/powerpc/platforms/ps3/repository.c index c73f3a68d2a..9b47ba7a5de 100644 --- a/arch/powerpc/platforms/ps3/repository.c +++ b/arch/powerpc/platforms/ps3/repository.c @@ -778,6 +778,72 @@ int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size, u64 *region_total) : ps3_repository_read_region_total(region_total); } +/** + * ps3_repository_read_highmem_region_count - Read the number of highmem regions + * + * Bootloaders must arrange the repository nodes such that regions are indexed + * with a region_index from 0 to region_count-1. + */ + +int ps3_repository_read_highmem_region_count(unsigned int *region_count) +{ + int result; + u64 v1 = 0; + + result = read_node(PS3_LPAR_ID_CURRENT, + make_first_field("highmem", 0), + make_field("region", 0), + make_field("count", 0), + 0, + &v1, NULL); + *region_count = v1; + return result; +} + + +int ps3_repository_read_highmem_base(unsigned int region_index, + u64 *highmem_base) +{ + return read_node(PS3_LPAR_ID_CURRENT, + make_first_field("highmem", 0), + make_field("region", region_index), + make_field("base", 0), + 0, + highmem_base, NULL); +} + +int ps3_repository_read_highmem_size(unsigned int region_index, + u64 *highmem_size) +{ + return read_node(PS3_LPAR_ID_CURRENT, + make_first_field("highmem", 0), + make_field("region", region_index), + make_field("size", 0), + 0, + highmem_size, NULL); +} + +/** + * ps3_repository_read_highmem_info - Read high memory region info + * @region_index: Region index, {0,..,region_count-1}. + * @highmem_base: High memory base address. + * @highmem_size: High memory size. + * + * Bootloaders that preallocate highmem regions must place the + * region info into the repository at these well known nodes. + */ + +int ps3_repository_read_highmem_info(unsigned int region_index, + u64 *highmem_base, u64 *highmem_size) +{ + int result; + + *highmem_base = 0; + result = ps3_repository_read_highmem_base(region_index, highmem_base); + return result ? result + : ps3_repository_read_highmem_size(region_index, highmem_size); +} + /** * ps3_repository_read_num_spu_reserved - Number of physical spus reserved. * @num_spu: Number of physical spus. -- cgit v1.2.3-18-g5258 From 1e755c09926de2d9b0e239ba0ce10fdb6835551a Mon Sep 17 00:00:00 2001 From: Andre Heider Date: Thu, 11 Aug 2011 21:31:07 +0200 Subject: 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 Signed-off-by: Andre Heider CC: Nathan Whitehorn Signed-off-by: Geoff Levand --- arch/powerpc/platforms/ps3/mm.c | 51 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c index de2aea42170..05a2bcb6a87 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; -- cgit v1.2.3-18-g5258 From 8ac5fd118cd137db5ca8c786778ba600f87111a0 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Thu, 11 Aug 2011 21:31:08 +0200 Subject: powerpc/ps3: Add highmem region memory early Real mode memory can be limited and runs out quickly as memory is allocated during kernel startup. Having the highmem available sooner fixes this. This change simplifies the memory management code by converting from hotplug memory to logical memory blocks. Signed-off-by: Hector Martin Signed-off-by: Andre Heider Signed-off-by: Geoff Levand --- arch/powerpc/platforms/ps3/mm.c | 66 +++++++---------------------------------- 1 file changed, 10 insertions(+), 56 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c index 05a2bcb6a87..0c9f643d9e2 100644 --- a/arch/powerpc/platforms/ps3/mm.c +++ b/arch/powerpc/platforms/ps3/mm.c @@ -20,7 +20,6 @@ #include #include -#include #include #include @@ -98,7 +97,7 @@ struct mem_region { * The HV virtual address space (vas) allows for hotplug memory regions. * Memory regions can be created and destroyed in the vas at runtime. * @rm: real mode (bootmem) region - * @r1: hotplug memory region(s) + * @r1: highmem region(s) * * ps3 addresses * virt_addr: a cpu 'translated' effective address @@ -224,10 +223,6 @@ void ps3_mm_vas_destroy(void) } } -/*============================================================================*/ -/* memory hotplug routines */ -/*============================================================================*/ - /** * ps3_mm_region_create - create a memory region in the vas * @r: pointer to a struct mem_region to accept initialized values @@ -328,56 +323,6 @@ zero_region: return result; } -/** - * ps3_mm_add_memory - hot add memory - */ - -static int __init ps3_mm_add_memory(void) -{ - int result; - unsigned long start_addr; - unsigned long start_pfn; - unsigned long nr_pages; - - if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) - return -ENODEV; - - 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; - - DBG("%s:%d: start_addr %lxh, start_pfn %lxh, nr_pages %lxh\n", - __func__, __LINE__, start_addr, start_pfn, nr_pages); - - result = add_memory(0, start_addr, map.r1.size); - - if (result) { - pr_err("%s:%d: add_memory failed: (%d)\n", - __func__, __LINE__, result); - return result; - } - - memblock_add(start_addr, map.r1.size); - - result = online_pages(start_pfn, nr_pages); - - if (result) - pr_err("%s:%d: online_pages failed: (%d)\n", - __func__, __LINE__, result); - - return result; -} - -device_initcall(ps3_mm_add_memory); - /*============================================================================*/ /* dma routines */ /*============================================================================*/ @@ -1271,6 +1216,15 @@ void __init ps3_mm_init(void) /* correct map.total for the real total amount of memory we use */ map.total = map.rm.size + map.r1.size; + if (!map.r1.size) { + DBG("%s:%d: No highmem region found\n", __func__, __LINE__); + } else { + DBG("%s:%d: Adding highmem region: %llxh %llxh\n", + __func__, __LINE__, map.rm.size, + map.total - map.rm.size); + memblock_add(map.rm.size, map.total - map.rm.size); + } + DBG(" <- %s:%d\n", __func__, __LINE__); } -- cgit v1.2.3-18-g5258 From bdf0ccd43e7becc78c0f4895eb3f330a708443c0 Mon Sep 17 00:00:00 2001 From: Andre Heider Date: Thu, 11 Aug 2011 21:31:09 +0200 Subject: powerpc/ps3: Remove MEMORY_HOTPLUG requirement The dependency on hotplug memory was removed, so remove the dependency in the Kconfig. Signed-off-by: Andre Heider Signed-off-by: Geoff Levand --- arch/powerpc/platforms/ps3/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig index 4210aaae6e0..b72425a59b9 100644 --- a/arch/powerpc/platforms/ps3/Kconfig +++ b/arch/powerpc/platforms/ps3/Kconfig @@ -7,7 +7,6 @@ config PPC_PS3 select USB_OHCI_BIG_ENDIAN_MMIO select USB_ARCH_HAS_EHCI select USB_EHCI_BIG_ENDIAN_MMIO - select MEMORY_HOTPLUG select PPC_PCI_CHOICE help This option enables support for the Sony PS3 game console -- cgit v1.2.3-18-g5258 From 02ec92b3f312b7201928dc6d3225ed51635211b4 Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Sat, 31 Mar 2012 15:23:10 -0700 Subject: powerpc/ps3: Minor Kconfig cleanup Signed-off-by: Geoff Levand --- arch/powerpc/platforms/ps3/Kconfig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig index b72425a59b9..46b7f023252 100644 --- a/arch/powerpc/platforms/ps3/Kconfig +++ b/arch/powerpc/platforms/ps3/Kconfig @@ -73,7 +73,7 @@ config PS3_PS3AV help Include support for the PS3 AV Settings driver. - This support is required for graphics and sound. In + This support is required for PS3 graphics and sound. In general, all users will say Y or M. config PS3_SYS_MANAGER @@ -84,7 +84,7 @@ config PS3_SYS_MANAGER help Include support for the PS3 System Manager. - This support is required for system control. In + This support is required for PS3 system control. In general, all users will say Y or M. config PS3_REPOSITORY_WRITE @@ -134,7 +134,7 @@ config PS3_FLASH This support is required to access the PS3 FLASH ROM, which contains the boot loader and some boot options. - In general, all users will say Y or M. + In general, PS3 OtherOS users will say Y or M. As this driver needs a fixed buffer of 256 KiB of memory, it can be disabled on the kernel command line using "ps3flash=off", to @@ -168,7 +168,7 @@ config PS3GELIC_UDBG via the Ethernet port (UDP port number 18194). This driver uses a trivial implementation and is independent - from the main network driver. + from the main PS3 gelic network driver. If in doubt, say N here. -- cgit v1.2.3-18-g5258