diff mbox

[1/2] Change load_resource() API to be all about preloading.

Message ID 1427167877-19573-2-git-send-email-stewart@linux.vnet.ibm.com
State Accepted
Headers show

Commit Message

Stewart Smith March 24, 2015, 3:31 a.m. UTC
No functional changes in what happens, just have two calls, one for
queueing preload the other for waiting until it has loaded.

future patches will introduce platform specific queueing.

Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
---
 core/flash.c                |    4 ++--
 core/init.c                 |   26 +++++++++++++++++++-------
 core/platform.c             |   33 ++++++++++++++++++++++++++++-----
 hw/fsp/fsp.c                |   14 +++++++-------
 hw/phb3.c                   |   10 +++++++++-
 include/fsp.h               |    4 ++--
 include/platform.h          |   29 +++++++++++++++++++++++------
 include/skiboot.h           |    4 ++--
 platforms/astbmc/habanero.c |    2 +-
 platforms/astbmc/palmetto.c |    2 +-
 platforms/ibm-fsp/apollo.c  |    2 +-
 platforms/ibm-fsp/firenze.c |    2 +-
 12 files changed, 96 insertions(+), 36 deletions(-)

Comments

Joel Stanley March 24, 2015, 6:28 a.m. UTC | #1
On Tue, 2015-03-24 at 14:31 +1100, Stewart Smith wrote:
> No functional changes in what happens, just have two calls, one for
> queueing preload the other for waiting until it has loaded.
> 
> future patches will introduce platform specific queueing.

I started to implement these calls for async loading on the BMC
platforms and had a few questions come up.

> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>

> ---
>  core/flash.c                |    4 ++--
>  core/init.c                 |   26 +++++++++++++++++++-------
>  core/platform.c             |   33 ++++++++++++++++++++++++++++-----
>  hw/fsp/fsp.c                |   14 +++++++-------
>  hw/phb3.c                   |   10 +++++++++-
>  include/fsp.h               |    4 ++--
>  include/platform.h          |   29 +++++++++++++++++++++++------
>  include/skiboot.h           |    4 ++--
>  platforms/astbmc/habanero.c |    2 +-
>  platforms/astbmc/palmetto.c |    2 +-
>  platforms/ibm-fsp/apollo.c  |    2 +-
>  platforms/ibm-fsp/firenze.c |    2 +-
>  12 files changed, 96 insertions(+), 36 deletions(-)
> 
> diff --git a/core/flash.c b/core/flash.c
> index f2d7501..270e6fc 100644
> --- a/core/flash.c
> +++ b/core/flash.c
> @@ -522,8 +522,8 @@ end:
>   * load a resource from FLASH
>   * buf and len shouldn't account for ECC even if partition is ECCed.
>   */
> -bool flash_load_resource(enum resource_id id, uint32_t subid,
> -		void *buf, size_t *len)
> +int flash_start_preload_resource(enum resource_id id, uint32_t subid,
> +				 void *buf, size_t *len)

Not convinced it's worth changing from bool to the opal error codes as
the callers only check for success. Up to you though.

>  {
>  	int i, rc, part_num, part_size, part_start, size;
>  	struct ffs_handle *ffs;

> diff --git a/core/platform.c b/core/platform.c
> index 7cf9727..5369092 100644
> --- a/core/platform.c
> +++ b/core/platform.c

> +
> +int wait_for_resource_loaded(enum resource_id id, uint32_t idx)
> +{
> +	int r = resource_loaded(id, idx);
> +
> +	while(r == OPAL_BUSY) {
> +		opal_run_pollers();
> +		time_wait_nopoll(msecs_to_tb(5));

time_wait_ms_nopoll(5);

> +		cpu_relax();

time_wait calls cpu_relax while it loops.

> +		r = resource_loaded(id, idx);
> +	}
>  
> +	return r;
>  }

> diff --git a/include/platform.h b/include/platform.h
> index bdf8bdf..2900b4e 100644
> --- a/include/platform.h
> +++ b/include/platform.h
> @@ -129,11 +129,24 @@ struct platform {
>  	int		(*elog_commit)(struct errorlog *buf);
>  
>  	/*
> -	 * Load an external resource (eg, kernel payload) into a preallocated
> -	 * buffer. Returns true on success.
> +	 * Initiate loading an external resource (e.g. kernel payload, OCC)
> +	 * into a preallocated buffer.
> +	 * This is designed to asynchronously load external resources.

Not sure that the last line is true. It could say "The implementation
should asynchronously load external resources.", but I'm not sure if
that adds much.

> +	 * Returns OPAL_SUCCESS or error.
>  	 */
> -	bool		(*load_resource)(enum resource_id id, uint32_t idx,
> -					 void *buf, size_t *len);
> +	int		(*start_preload_resource)(enum resource_id id,
> +						  uint32_t idx,
> +						  void *buf, size_t *len);

With this scheme we need to know the final size in the synch path. On
the BMC platforms this would mean searching the TOC for the partition
we're after. We could hide more of the work if the size was returned
asynchronously.

> +
> diff --git a/include/skiboot.h b/include/skiboot.h
> index 0fe50e9..6cb9b2d 100644
> --- a/include/skiboot.h
> +++ b/include/skiboot.h
> @@ -199,8 +199,8 @@ extern void occ_fsp_init(void);
>  /* flash support */
>  struct flash_chip;
>  extern int flash_register(struct flash_chip *chip, bool is_system_flash);
> -extern bool flash_load_resource(enum resource_id id, uint32_t subid,
> -		void *buf, size_t *len);
> +extern int flash_start_preload_resource(enum resource_id id, uint32_t subid,
> +					void *buf, size_t *len);
>  extern bool flash_reserve(void);
>  extern void flash_release(void);
>  
> diff --git a/platforms/astbmc/habanero.c b/platforms/astbmc/habanero.c
> index c4875ef..d56e451 100644
> --- a/platforms/astbmc/habanero.c
> +++ b/platforms/astbmc/habanero.c
> @@ -53,6 +53,6 @@ DECLARE_PLATFORM(habanero) = {
>  	.cec_power_down         = astbmc_ipmi_power_down,
>  	.cec_reboot             = astbmc_ipmi_reboot,
>  	.elog_commit		= ipmi_elog_commit,
> -	.load_resource		= flash_load_resource,
> +	.start_preload_resource	= flash_start_preload_resource,

I think we should leave the name of the flash functions as they were as
they do not (yet) do any preloading.

>  	.exit			= ipmi_wdt_final_reset,
>  };
Stewart Smith March 24, 2015, 7:23 a.m. UTC | #2
Joel Stanley <joel@jms.id.au> writes:
> On Tue, 2015-03-24 at 14:31 +1100, Stewart Smith wrote:
>> No functional changes in what happens, just have two calls, one for
>> queueing preload the other for waiting until it has loaded.
>> 
>> future patches will introduce platform specific queueing.
>
> I started to implement these calls for async loading on the BMC
> platforms and had a few questions come up.

Excellent!
>> --- a/core/flash.c
>> +++ b/core/flash.c
>> @@ -522,8 +522,8 @@ end:
>>   * load a resource from FLASH
>>   * buf and len shouldn't account for ECC even if partition is ECCed.
>>   */
>> -bool flash_load_resource(enum resource_id id, uint32_t subid,
>> -		void *buf, size_t *len)
>> +int flash_start_preload_resource(enum resource_id id, uint32_t subid,
>> +				 void *buf, size_t *len)
>
> Not convinced it's worth changing from bool to the opal error codes as
> the callers only check for success. Up to you though.

I wasn't sure either... I deferred to bitter debugging experience of
prefering "error X" rather than "error" :)

>> --- a/core/platform.c
>> +++ b/core/platform.c
>
>> +
>> +int wait_for_resource_loaded(enum resource_id id, uint32_t idx)
>> +{
>> +	int r = resource_loaded(id, idx);
>> +
>> +	while(r == OPAL_BUSY) {
>> +		opal_run_pollers();
>> +		time_wait_nopoll(msecs_to_tb(5));
>
> time_wait_ms_nopoll(5);
>
>> +		cpu_relax();
>
> time_wait calls cpu_relax while it loops.

Good catch. Fixed.

>> diff --git a/include/platform.h b/include/platform.h
>> index bdf8bdf..2900b4e 100644
>> --- a/include/platform.h
>> +++ b/include/platform.h
>> @@ -129,11 +129,24 @@ struct platform {
>>  	int		(*elog_commit)(struct errorlog *buf);
>>  
>>  	/*
>> -	 * Load an external resource (eg, kernel payload) into a preallocated
>> -	 * buffer. Returns true on success.
>> +	 * Initiate loading an external resource (e.g. kernel payload, OCC)
>> +	 * into a preallocated buffer.
>> +	 * This is designed to asynchronously load external resources.
>
> Not sure that the last line is true. It could say "The implementation
> should asynchronously load external resources.", but I'm not sure if
> that adds much.
>
>> +	 * Returns OPAL_SUCCESS or error.
>>  	 */
>> -	bool		(*load_resource)(enum resource_id id, uint32_t idx,
>> -					 void *buf, size_t *len);
>> +	int		(*start_preload_resource)(enum resource_id id,
>> +						  uint32_t idx,
>> +						  void *buf, size_t *len);
>
> With this scheme we need to know the final size in the synch path. On
> the BMC platforms this would mean searching the TOC for the partition
> we're after. We could hide more of the work if the size was returned
> asynchronously.

The API is that the length is updated as it's fetced, which is kind of
weird considering you supply the pointer to start_preload_resource() and
it's not valid until the resource is loaded.

The FSP code does this in fsp_fetch_lid_complete(), where for each chunk
it updates size with what's been fetched.

So it's okay to update as it goes. size only valid once resource is loaded.

>> --- a/platforms/astbmc/habanero.c
>> +++ b/platforms/astbmc/habanero.c
>> @@ -53,6 +53,6 @@ DECLARE_PLATFORM(habanero) = {
>>  	.cec_power_down         = astbmc_ipmi_power_down,
>>  	.cec_reboot             = astbmc_ipmi_reboot,
>>  	.elog_commit		= ipmi_elog_commit,
>> -	.load_resource		= flash_load_resource,
>> +	.start_preload_resource	= flash_start_preload_resource,
>
> I think we should leave the name of the flash functions as they were as
> they do not (yet) do any preloading.

ack. fixed.
Benjamin Herrenschmidt March 24, 2015, 8:52 a.m. UTC | #3
On Tue, 2015-03-24 at 18:23 +1100, Stewart Smith wrote:
> >
> >> +
> >> +int wait_for_resource_loaded(enum resource_id id, uint32_t idx)
> >> +{
> >> +    int r = resource_loaded(id, idx);
> >> +
> >> +    while(r == OPAL_BUSY) {
> >> +            opal_run_pollers();
> >> +            time_wait_nopoll(msecs_to_tb(5));
> >
> > time_wait_ms_nopoll(5);
> >
> >> +            cpu_relax();
> >
> > time_wait calls cpu_relax while it loops.

Why open code opal_run_pollers + time_wait_nopoll + cpu_relax and not
just call time_wait() ?

Cheers,
Ben.
Stewart Smith March 25, 2015, 12:06 a.m. UTC | #4
Benjamin Herrenschmidt <benh@kernel.crashing.org> writes:
> On Tue, 2015-03-24 at 18:23 +1100, Stewart Smith wrote:
>> >
>> >> +
>> >> +int wait_for_resource_loaded(enum resource_id id, uint32_t idx)
>> >> +{
>> >> +    int r = resource_loaded(id, idx);
>> >> +
>> >> +    while(r == OPAL_BUSY) {
>> >> +            opal_run_pollers();
>> >> +            time_wait_nopoll(msecs_to_tb(5));
>> >
>> > time_wait_ms_nopoll(5);
>> >
>> >> +            cpu_relax();
>> >
>> > time_wait calls cpu_relax while it loops.
>
> Why open code opal_run_pollers + time_wait_nopoll + cpu_relax and not
> just call time_wait() ?

time_wait() will not call pollers if lock is held, and I think I'd
prefer to get the warning here.
Vasant Hegde March 30, 2015, 11:44 a.m. UTC | #5
On 03/24/2015 09:01 AM, Stewart Smith wrote:
> No functional changes in what happens, just have two calls, one for
> queueing preload the other for waiting until it has loaded.
> 
> future patches will introduce platform specific queueing.
> 
> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
> ---
>  core/flash.c                |    4 ++--
>  core/init.c                 |   26 +++++++++++++++++++-------
>  core/platform.c             |   33 ++++++++++++++++++++++++++++-----
>  hw/fsp/fsp.c                |   14 +++++++-------
>  hw/phb3.c                   |   10 +++++++++-
>  include/fsp.h               |    4 ++--
>  include/platform.h          |   29 +++++++++++++++++++++++------
>  include/skiboot.h           |    4 ++--
>  platforms/astbmc/habanero.c |    2 +-
>  platforms/astbmc/palmetto.c |    2 +-
>  platforms/ibm-fsp/apollo.c  |    2 +-
>  platforms/ibm-fsp/firenze.c |    2 +-
>  12 files changed, 96 insertions(+), 36 deletions(-)
> 
> diff --git a/core/flash.c b/core/flash.c
> index f2d7501..270e6fc 100644
> --- a/core/flash.c
> +++ b/core/flash.c
> @@ -522,8 +522,8 @@ end:
>   * load a resource from FLASH
>   * buf and len shouldn't account for ECC even if partition is ECCed.
>   */
> -bool flash_load_resource(enum resource_id id, uint32_t subid,
> -		void *buf, size_t *len)
> +int flash_start_preload_resource(enum resource_id id, uint32_t subid,
> +				 void *buf, size_t *len)
>  {
>  	int i, rc, part_num, part_size, part_start, size;
>  	struct ffs_handle *ffs;
> diff --git a/core/init.c b/core/init.c
> index 1fd8d2e..f15ae5d 100644
> --- a/core/init.c
> +++ b/core/init.c
> @@ -290,12 +290,19 @@ static bool load_kernel(void)
>  {
>  	struct elf_hdr *kh;
>  	size_t ksize;
> +	int loaded;
>  
>  	/* Try to load an external kernel payload through the platform hooks */
>  	ksize = KERNEL_LOAD_SIZE;
> -	if (!load_resource(RESOURCE_ID_KERNEL, RESOURCE_SUBID_NONE,
> -			   KERNEL_LOAD_BASE,
> -			   &ksize)) {
> +	loaded = start_preload_resource(RESOURCE_ID_KERNEL,
> +					RESOURCE_SUBID_NONE,
> +					KERNEL_LOAD_BASE,
> +					&ksize);
> +	if (loaded == OPAL_SUCCESS)
> +		loaded = wait_for_resource_loaded(RESOURCE_ID_KERNEL,
> +						  RESOURCE_SUBID_NONE);
> +
> +	if (loaded != OPAL_SUCCESS) {
>  		printf("INIT: platform kernel load failed\n");
>  		ksize = 0;
>  	}
> @@ -332,13 +339,18 @@ static bool load_kernel(void)
>  static void load_initramfs(void)
>  {
>  	size_t size;
> -	bool loaded;
> +	int loaded;
>  
>  	size = INITRAMFS_LOAD_SIZE;
> -	loaded = load_resource(RESOURCE_ID_INITRAMFS, RESOURCE_SUBID_NONE,
> -			       INITRAMFS_LOAD_BASE, &size);
> +	loaded = start_preload_resource(RESOURCE_ID_INITRAMFS,
> +					RESOURCE_SUBID_NONE,
> +					INITRAMFS_LOAD_BASE, &size);
>  
> -	if (!loaded || !size)
> +	if (loaded == OPAL_SUCCESS)
> +		loaded = wait_for_resource_loaded(RESOURCE_ID_INITRAMFS,
> +						  RESOURCE_SUBID_NONE);
> +
> +	if (loaded != OPAL_SUCCESS || !size)
>  		return;


Looks like we are continuing even initrd fails ..Do we really want to continue
or abort?


-Vasant
Stewart Smith March 31, 2015, 12:59 a.m. UTC | #6
Vasant Hegde <hegdevasant@linux.vnet.ibm.com> writes:
> Looks like we are continuing even initrd fails ..Do we really want to continue
> or abort?

Still being able to boot a single LID kernel+initramfs is a good
thing. I spoken to some people who may even use this setup in production
(their workload fits in flash).
diff mbox

Patch

diff --git a/core/flash.c b/core/flash.c
index f2d7501..270e6fc 100644
--- a/core/flash.c
+++ b/core/flash.c
@@ -522,8 +522,8 @@  end:
  * load a resource from FLASH
  * buf and len shouldn't account for ECC even if partition is ECCed.
  */
-bool flash_load_resource(enum resource_id id, uint32_t subid,
-		void *buf, size_t *len)
+int flash_start_preload_resource(enum resource_id id, uint32_t subid,
+				 void *buf, size_t *len)
 {
 	int i, rc, part_num, part_size, part_start, size;
 	struct ffs_handle *ffs;
diff --git a/core/init.c b/core/init.c
index 1fd8d2e..f15ae5d 100644
--- a/core/init.c
+++ b/core/init.c
@@ -290,12 +290,19 @@  static bool load_kernel(void)
 {
 	struct elf_hdr *kh;
 	size_t ksize;
+	int loaded;
 
 	/* Try to load an external kernel payload through the platform hooks */
 	ksize = KERNEL_LOAD_SIZE;
-	if (!load_resource(RESOURCE_ID_KERNEL, RESOURCE_SUBID_NONE,
-			   KERNEL_LOAD_BASE,
-			   &ksize)) {
+	loaded = start_preload_resource(RESOURCE_ID_KERNEL,
+					RESOURCE_SUBID_NONE,
+					KERNEL_LOAD_BASE,
+					&ksize);
+	if (loaded == OPAL_SUCCESS)
+		loaded = wait_for_resource_loaded(RESOURCE_ID_KERNEL,
+						  RESOURCE_SUBID_NONE);
+
+	if (loaded != OPAL_SUCCESS) {
 		printf("INIT: platform kernel load failed\n");
 		ksize = 0;
 	}
@@ -332,13 +339,18 @@  static bool load_kernel(void)
 static void load_initramfs(void)
 {
 	size_t size;
-	bool loaded;
+	int loaded;
 
 	size = INITRAMFS_LOAD_SIZE;
-	loaded = load_resource(RESOURCE_ID_INITRAMFS, RESOURCE_SUBID_NONE,
-			       INITRAMFS_LOAD_BASE, &size);
+	loaded = start_preload_resource(RESOURCE_ID_INITRAMFS,
+					RESOURCE_SUBID_NONE,
+					INITRAMFS_LOAD_BASE, &size);
 
-	if (!loaded || !size)
+	if (loaded == OPAL_SUCCESS)
+		loaded = wait_for_resource_loaded(RESOURCE_ID_INITRAMFS,
+						  RESOURCE_SUBID_NONE);
+
+	if (loaded != OPAL_SUCCESS || !size)
 		return;
 
 	printf("INIT: Initramfs loaded, size: %zu bytes\n", size);
diff --git a/core/platform.c b/core/platform.c
index 7cf9727..5369092 100644
--- a/core/platform.c
+++ b/core/platform.c
@@ -19,6 +19,8 @@ 
 #include <opal.h>
 #include <opal-api.h>
 #include <console.h>
+#include <timebase.h>
+#include <cpu.h>
 
 struct platform	platform;
 
@@ -79,12 +81,33 @@  void probe_platform(void)
 	printf("PLAT: Detected %s platform\n", platform.name);
 }
 
-bool load_resource(enum resource_id id, uint32_t subid,
-		   void *buf, size_t *len)
+int start_preload_resource(enum resource_id id, uint32_t subid,
+			   void *buf, size_t *len)
 {
-	if (!platform.load_resource)
-		return false;
+	if (!platform.start_preload_resource)
+		return OPAL_UNSUPPORTED;
 
-	return platform.load_resource(id, subid, buf, len);
+	return platform.start_preload_resource(id, subid, buf, len);
+}
+
+int resource_loaded(enum resource_id id, uint32_t idx)
+{
+	if (!platform.resource_loaded)
+		return OPAL_SUCCESS;
+
+	return platform.resource_loaded(id, idx);
+}
+
+int wait_for_resource_loaded(enum resource_id id, uint32_t idx)
+{
+	int r = resource_loaded(id, idx);
+
+	while(r == OPAL_BUSY) {
+		opal_run_pollers();
+		time_wait_nopoll(msecs_to_tb(5));
+		cpu_relax();
+		r = resource_loaded(id, idx);
+	}
 
+	return r;
 }
diff --git a/hw/fsp/fsp.c b/hw/fsp/fsp.c
index 779eef9..17d73b5 100644
--- a/hw/fsp/fsp.c
+++ b/hw/fsp/fsp.c
@@ -2275,8 +2275,8 @@  static struct {
 	{ RESOURCE_ID_CAPP,	CAPP_IDX_VENICE_DD20,	0x80a02004 },
 };
 
-bool fsp_load_resource(enum resource_id id, uint32_t idx,
-		       void *buf, size_t *size)
+int fsp_start_preload_resource(enum resource_id id, uint32_t idx,
+				void *buf, size_t *size)
 {
 	uint32_t lid_no = 0, lid;
 	size_t tmp_size;
@@ -2292,7 +2292,7 @@  bool fsp_load_resource(enum resource_id id, uint32_t idx,
 		}
 	}
 	if (lid_no == 0)
-		return false;
+		return OPAL_PARAMETER;
 
 retry:
 	tmp_size = *size;
@@ -2306,7 +2306,7 @@  retry:
 		const char *ltype = dt_prop_get_def(dt_root, "lid-type", NULL);
 		if (!ltype || strcmp(ltype, "opal")) {
 			prerror("Failed to load in OPAL mode...\n");
-			return false;
+			return OPAL_PARAMETER;
 		}
 		printf("Trying to load as PHYP LID...\n");
 		lid_no = KERNEL_LID_PHYP;
@@ -2315,13 +2315,13 @@  retry:
 
 	if (rc) {
 		prerror("Failed to load LID\n");
-		return false;
+		return rc;
 	}
 	if (*size < tmp_size)
-		return false;
+		return OPAL_INTERNAL_ERROR;
 	*size = tmp_size;
 
-	return true;
+	return OPAL_SUCCESS;
 }
 
 void fsp_used_by_console(void)
diff --git a/hw/phb3.c b/hw/phb3.c
index e7127bc..32da794 100644
--- a/hw/phb3.c
+++ b/hw/phb3.c
@@ -2178,6 +2178,7 @@  static int64_t capp_lid_download(struct phb3 *p)
 	uint32_t index;
 	struct capp_lid_hdr *lid;
 	uint64_t rc;
+	int loaded;
 
 	rc = xscom_read_cfam_chipid(chip->id, &index);
 	if (rc) {
@@ -2220,7 +2221,14 @@  static int64_t capp_lid_download(struct phb3 *p)
 		ret = OPAL_NO_MEM;
 		goto end;
 	}
-	if (!load_resource(RESOURCE_ID_CAPP, index, lid, &size)) {
+
+	loaded = start_preload_resource(RESOURCE_ID_CAPP, index,
+					    lid, &size);
+	if (loaded == OPAL_SUCCESS)
+		loaded = wait_for_resource_loaded(RESOURCE_ID_CAPP,
+						  index);
+
+	if (loaded != OPAL_SUCCESS) {
 		prerror("CAPP: Error loading ucode lid. index=%x\n", index);
 		ret = OPAL_RESOURCE;
 		free(lid);
diff --git a/include/fsp.h b/include/fsp.h
index 66fadb1..e05d7a4 100644
--- a/include/fsp.h
+++ b/include/fsp.h
@@ -722,8 +722,8 @@  extern int fsp_fetch_data(uint8_t flags, uint16_t id, uint32_t sub_id,
 extern int fsp_fetch_data_queue(uint8_t flags, uint16_t id, uint32_t sub_id,
 				uint32_t offset, void *buffer, size_t *length,
 				void (*comp)(struct fsp_msg *msg)) __warn_unused_result;
-extern bool fsp_load_resource(enum resource_id id, uint32_t subid,
-			      void *buf, size_t *size);
+extern int fsp_start_preload_resource(enum resource_id id, uint32_t idx,
+				      void *buf, size_t *size);
 
 /* FSP console stuff */
 extern void fsp_console_preinit(void);
diff --git a/include/platform.h b/include/platform.h
index bdf8bdf..2900b4e 100644
--- a/include/platform.h
+++ b/include/platform.h
@@ -129,11 +129,24 @@  struct platform {
 	int		(*elog_commit)(struct errorlog *buf);
 
 	/*
-	 * Load an external resource (eg, kernel payload) into a preallocated
-	 * buffer. Returns true on success.
+	 * Initiate loading an external resource (e.g. kernel payload, OCC)
+	 * into a preallocated buffer.
+	 * This is designed to asynchronously load external resources.
+	 * Returns OPAL_SUCCESS or error.
 	 */
-	bool		(*load_resource)(enum resource_id id, uint32_t idx,
-					 void *buf, size_t *len);
+	int		(*start_preload_resource)(enum resource_id id,
+						  uint32_t idx,
+						  void *buf, size_t *len);
+
+	/*
+	 * Returns true when resource is loaded.
+	 * Only has to return true once, for the
+	 * preivous start_preload_resource call for this resource.
+	 * If not implemented, will return true and start_preload_resource
+	 * *must* have synchronously done the load.
+	 * Retruns OPAL_SUCCESS, OPAL_BUSY or an error code
+	 */
+	int		(*resource_loaded)(enum resource_id id, uint32_t idx);
 
 	/*
 	 * Executed just prior to handing control over to the payload.
@@ -151,7 +164,11 @@  static const struct platform __used __section(".platforms") name ##_platform
 
 extern void probe_platform(void);
 
-extern bool load_resource(enum resource_id id, uint32_t subid,
-			  void *buf, size_t *len);
+extern int start_preload_resource(enum resource_id id, uint32_t subid,
+				  void *buf, size_t *len);
+
+extern int resource_loaded(enum resource_id id, uint32_t idx);
+
+extern int wait_for_resource_loaded(enum resource_id id, uint32_t idx);
 
 #endif /* __PLATFORM_H */
diff --git a/include/skiboot.h b/include/skiboot.h
index 0fe50e9..6cb9b2d 100644
--- a/include/skiboot.h
+++ b/include/skiboot.h
@@ -199,8 +199,8 @@  extern void occ_fsp_init(void);
 /* flash support */
 struct flash_chip;
 extern int flash_register(struct flash_chip *chip, bool is_system_flash);
-extern bool flash_load_resource(enum resource_id id, uint32_t subid,
-		void *buf, size_t *len);
+extern int flash_start_preload_resource(enum resource_id id, uint32_t subid,
+					void *buf, size_t *len);
 extern bool flash_reserve(void);
 extern void flash_release(void);
 
diff --git a/platforms/astbmc/habanero.c b/platforms/astbmc/habanero.c
index c4875ef..d56e451 100644
--- a/platforms/astbmc/habanero.c
+++ b/platforms/astbmc/habanero.c
@@ -53,6 +53,6 @@  DECLARE_PLATFORM(habanero) = {
 	.cec_power_down         = astbmc_ipmi_power_down,
 	.cec_reboot             = astbmc_ipmi_reboot,
 	.elog_commit		= ipmi_elog_commit,
-	.load_resource		= flash_load_resource,
+	.start_preload_resource	= flash_start_preload_resource,
 	.exit			= ipmi_wdt_final_reset,
 };
diff --git a/platforms/astbmc/palmetto.c b/platforms/astbmc/palmetto.c
index dee2b06..fdc449e 100644
--- a/platforms/astbmc/palmetto.c
+++ b/platforms/astbmc/palmetto.c
@@ -53,6 +53,6 @@  DECLARE_PLATFORM(palmetto) = {
 	.cec_power_down         = astbmc_ipmi_power_down,
 	.cec_reboot             = astbmc_ipmi_reboot,
 	.elog_commit		= ipmi_elog_commit,
-	.load_resource		= flash_load_resource,
+	.start_preload_resource	= flash_start_preload_resource,
 	.exit			= ipmi_wdt_final_reset,
 };
diff --git a/platforms/ibm-fsp/apollo.c b/platforms/ibm-fsp/apollo.c
index 54545de..cc62c98 100644
--- a/platforms/ibm-fsp/apollo.c
+++ b/platforms/ibm-fsp/apollo.c
@@ -60,5 +60,5 @@  DECLARE_PLATFORM(apollo) = {
 	.nvram_start_read	= fsp_nvram_start_read,
 	.nvram_write		= fsp_nvram_write,
 	.elog_commit		= elog_fsp_commit,
-	.load_resource		= fsp_load_resource,
+	.start_preload_resource	= fsp_start_preload_resource,
 };
diff --git a/platforms/ibm-fsp/firenze.c b/platforms/ibm-fsp/firenze.c
index 194a19d..9a696b7 100644
--- a/platforms/ibm-fsp/firenze.c
+++ b/platforms/ibm-fsp/firenze.c
@@ -414,5 +414,5 @@  DECLARE_PLATFORM(firenze) = {
 	.nvram_write		= fsp_nvram_write,
 	.occ_timeout		= ibm_fsp_occ_timeout,
 	.elog_commit		= elog_fsp_commit,
-	.load_resource		= fsp_load_resource,
+	.start_preload_resource	= fsp_start_preload_resource,
 } ;