diff options
-rw-r--r-- | core/flash.c | 119 | ||||
-rw-r--r-- | include/skiboot.h | 5 | ||||
-rw-r--r-- | platforms/astbmc/firestone.c | 3 | ||||
-rw-r--r-- | platforms/astbmc/habanero.c | 3 | ||||
-rw-r--r-- | platforms/astbmc/palmetto.c | 3 |
5 files changed, 126 insertions, 7 deletions
diff --git a/core/flash.c b/core/flash.c index 7d32c8d..092f8f2 100644 --- a/core/flash.c +++ b/core/flash.c @@ -15,6 +15,7 @@ */ #include <skiboot.h> +#include <cpu.h> #include <lock.h> #include <opal.h> #include <opal-msg.h> @@ -521,8 +522,8 @@ end: * load a resource from FLASH * buf and len shouldn't account for ECC even if partition is ECCed. */ -int flash_load_resource(enum resource_id id, uint32_t subid, - void *buf, size_t *len) +static int flash_load_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; @@ -628,3 +629,117 @@ out_unlock: unlock(&flash_lock); return status ? OPAL_SUCCESS : rc; } + + +struct flash_load_resource_item { + enum resource_id id; + uint32_t subid; + int result; + void *buf; + size_t *len; + struct list_node link; +}; + +static LIST_HEAD(flash_load_resource_queue); +static LIST_HEAD(flash_loaded_resources); +static struct lock flash_load_resource_lock = LOCK_UNLOCKED; +static struct cpu_job *flash_load_job = NULL; + +int flash_resource_loaded(enum resource_id id, uint32_t subid) +{ + struct flash_load_resource_item *resource = NULL; + struct flash_load_resource_item *r; + int rc = OPAL_BUSY; + + lock(&flash_load_resource_lock); + list_for_each(&flash_loaded_resources, r, link) { + if (r->id == id && r->subid == subid) { + resource = r; + break; + } + } + + if (resource) { + rc = resource->result; + list_del(&resource->link); + free(resource); + } + + if (list_empty(&flash_load_resource_queue) && flash_load_job) { + cpu_wait_job(flash_load_job, true); + flash_load_job = NULL; + } + + unlock(&flash_load_resource_lock); + + return rc; +} + +static void flash_load_resources(void *data __unused) +{ + struct flash_load_resource_item *r; + int result; + + do { + lock(&flash_load_resource_lock); + if (list_empty(&flash_load_resource_queue)) { + unlock(&flash_load_resource_lock); + break; + } + r = list_top(&flash_load_resource_queue, + struct flash_load_resource_item, link); + assert(r->result == OPAL_EMPTY); + r->result = OPAL_BUSY; + unlock(&flash_load_resource_lock); + + result = flash_load_resource(r->id, r->subid, r->buf, r->len); + + lock(&flash_load_resource_lock); + r = list_pop(&flash_load_resource_queue, + struct flash_load_resource_item, link); + r->result = result; + list_add_tail(&flash_loaded_resources, &r->link); + unlock(&flash_load_resource_lock); + } while(true); +} + +static void start_flash_load_resource_job(void) +{ + if (flash_load_job) + cpu_wait_job(flash_load_job, true); + + flash_load_job = cpu_queue_job(NULL, "flash_load_resources", + flash_load_resources, NULL); + + cpu_process_local_jobs(); +} + +int flash_start_preload_resource(enum resource_id id, uint32_t subid, + void *buf, size_t *len) +{ + struct flash_load_resource_item *r; + bool start_thread = false; + + r = malloc(sizeof(struct flash_load_resource_item)); + + assert(r != NULL); + r->id = id; + r->subid = subid; + r->buf = buf; + r->len = len; + r->result = OPAL_EMPTY; + + printf("FLASH: Queueing preload of %x/%x\n", r->id, r->subid); + + lock(&flash_load_resource_lock); + if (list_empty(&flash_load_resource_queue)) { + start_thread = true; + } + list_add_tail(&flash_load_resource_queue, &r->link); + unlock(&flash_load_resource_lock); + + if (start_thread) + start_flash_load_resource_job(); + + return OPAL_SUCCESS; +} diff --git a/include/skiboot.h b/include/skiboot.h index fc5bc1d..d021b33 100644 --- a/include/skiboot.h +++ b/include/skiboot.h @@ -199,8 +199,9 @@ extern void occ_fsp_init(void); /* flash support */ struct flash_chip; extern int flash_register(struct flash_chip *chip, bool is_system_flash); -extern int 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 int flash_resource_loaded(enum resource_id id, uint32_t idx); extern bool flash_reserve(void); extern void flash_release(void); diff --git a/platforms/astbmc/firestone.c b/platforms/astbmc/firestone.c index 03ecc2b..4d3be19 100644 --- a/platforms/astbmc/firestone.c +++ b/platforms/astbmc/firestone.c @@ -43,6 +43,7 @@ DECLARE_PLATFORM(firestone) = { .cec_power_down = astbmc_ipmi_power_down, .cec_reboot = astbmc_ipmi_reboot, .elog_commit = ipmi_elog_commit, - .start_preload_resource = flash_load_resource, + .start_preload_resource = flash_start_preload_resource, + .resource_loaded = flash_resource_loaded, .exit = ipmi_wdt_final_reset, }; diff --git a/platforms/astbmc/habanero.c b/platforms/astbmc/habanero.c index 2812b40..a2eec4a 100644 --- a/platforms/astbmc/habanero.c +++ b/platforms/astbmc/habanero.c @@ -53,6 +53,7 @@ DECLARE_PLATFORM(habanero) = { .cec_power_down = astbmc_ipmi_power_down, .cec_reboot = astbmc_ipmi_reboot, .elog_commit = ipmi_elog_commit, - .start_preload_resource = flash_load_resource, + .start_preload_resource = flash_start_preload_resource, + .resource_loaded = flash_resource_loaded, .exit = ipmi_wdt_final_reset, }; diff --git a/platforms/astbmc/palmetto.c b/platforms/astbmc/palmetto.c index 02b0649..803ca46 100644 --- a/platforms/astbmc/palmetto.c +++ b/platforms/astbmc/palmetto.c @@ -53,6 +53,7 @@ DECLARE_PLATFORM(palmetto) = { .cec_power_down = astbmc_ipmi_power_down, .cec_reboot = astbmc_ipmi_reboot, .elog_commit = ipmi_elog_commit, - .start_preload_resource = flash_load_resource, + .start_preload_resource = flash_start_preload_resource, + .resource_loaded = flash_resource_loaded, .exit = ipmi_wdt_final_reset, }; |