aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/flash.c119
-rw-r--r--include/skiboot.h5
-rw-r--r--platforms/astbmc/firestone.c3
-rw-r--r--platforms/astbmc/habanero.c3
-rw-r--r--platforms/astbmc/palmetto.c3
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,
};