aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/flash.c2
-rw-r--r--core/hostservices.c2
-rw-r--r--core/platform.c3
-rw-r--r--core/vpd.c2
-rw-r--r--hdata/test/stubs.c2
-rw-r--r--hw/fsp/fsp.c378
-rw-r--r--include/fsp.h2
-rw-r--r--include/skiboot.h4
-rw-r--r--platforms/astbmc/habanero.c2
-rw-r--r--platforms/astbmc/palmetto.c2
-rw-r--r--platforms/ibm-fsp/apollo.c1
-rw-r--r--platforms/ibm-fsp/firenze.c1
12 files changed, 287 insertions, 114 deletions
diff --git a/core/flash.c b/core/flash.c
index 270e6fc..8d51c01 100644
--- a/core/flash.c
+++ b/core/flash.c
@@ -522,7 +522,7 @@ end:
* load a resource from FLASH
* buf and len shouldn't account for ECC even if partition is ECCed.
*/
-int flash_start_preload_resource(enum resource_id id, uint32_t subid,
+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;
diff --git a/core/hostservices.c b/core/hostservices.c
index 22d34e4..a2289c9 100644
--- a/core/hostservices.c
+++ b/core/hostservices.c
@@ -415,7 +415,7 @@ static int __hservice_lid_load(uint32_t lid, void **buf, size_t *len)
*/
*buf = malloc(HBRT_LOAD_LID_SIZE);
*len = HBRT_LOAD_LID_SIZE;
- rc = fsp_fetch_data(0, FSP_DATASET_NONSP_LID, lid, 0, *buf, len);
+ rc = fsp_load_lid(lid, *buf, len);
if (rc != 0)
/* Take advantage of realloc corner case here. */
*len = 0;
diff --git a/core/platform.c b/core/platform.c
index 5369092..f93b141 100644
--- a/core/platform.c
+++ b/core/platform.c
@@ -104,8 +104,7 @@ int wait_for_resource_loaded(enum resource_id id, uint32_t idx)
while(r == OPAL_BUSY) {
opal_run_pollers();
- time_wait_nopoll(msecs_to_tb(5));
- cpu_relax();
+ time_wait_ms_nopoll(5);
r = resource_loaded(id, idx);
}
diff --git a/core/vpd.c b/core/vpd.c
index deb552c..0e6f83b 100644
--- a/core/vpd.c
+++ b/core/vpd.c
@@ -155,7 +155,7 @@ static void *vpd_lid_load(const uint8_t *lx, uint8_t lxrn, size_t *size)
*size = VPD_LID_MAX_SIZE;
/* Load it from the FSP */
- rc = fsp_fetch_data(0, FSP_DATASET_NONSP_LID, lid_no, 0, data, size);
+ rc = fsp_load_lid(lid_no, data, size);
if (rc) {
prerror("VPD: Error %d loading VPD LID\n", rc);
goto fail;
diff --git a/hdata/test/stubs.c b/hdata/test/stubs.c
index c7dae5f..d0a8ef1 100644
--- a/hdata/test/stubs.c
+++ b/hdata/test/stubs.c
@@ -54,7 +54,7 @@ STUB(dt_next);
STUB(dt_has_node_property);
STUB(dt_get_address);
STUB(op_display);
-STUB(fsp_fetch_data);
+STUB(fsp_load_lid);
STUB(get_ics_phandle);
STUB(get_psi_interrupt);
STUB(fsp_adjust_lid_side);
diff --git a/hw/fsp/fsp.c b/hw/fsp/fsp.c
index 17d73b5..e5a3c1d 100644
--- a/hw/fsp/fsp.c
+++ b/hw/fsp/fsp.c
@@ -38,6 +38,7 @@
#include <opal.h>
#include <opal-api.h>
#include <opal-msg.h>
+#include <ccan/list/list.h>
DEFINE_LOG_ENTRY(OPAL_RC_FSP_POLL_TIMEOUT, OPAL_PLATFORM_ERR_EVT, OPAL_FSP,
OPAL_PLATFORM_FIRMWARE, OPAL_ERROR_PANIC, OPAL_NA, NULL);
@@ -2144,88 +2145,36 @@ uint32_t fsp_adjust_lid_side(uint32_t lid_no)
return lid_no;
}
-int fsp_fetch_data(uint8_t flags, uint16_t id, uint32_t sub_id,
- uint32_t offset, void *buffer, size_t *length)
-{
- uint32_t total, remaining = *length;
- uint64_t baddr;
- uint64_t balign, boff, bsize;
- struct fsp_msg *msg;
- static struct lock fsp_fetch_lock = LOCK_UNLOCKED;
-
- *length = total = 0;
-
- if (!fsp_present())
- return -ENODEV;
-
- prlog(PR_DEBUG, "FSP: Fetch data id: %02x sid: %08x to %p"
- "(0x%x bytes)\n",
- id, sub_id, buffer, remaining);
-
- /*
- * Use a lock to avoid multiple processors trying to fetch
- * at the same time and colliding on the TCE space
- */
- lock(&fsp_fetch_lock);
-
- while(remaining) {
- uint32_t chunk, taddr, woffset, wlen;
- uint8_t rc;
-
- /* Calculate alignment skew */
- baddr = (uint64_t)buffer;
- balign = baddr & ~TCE_MASK;
- boff = baddr & TCE_MASK;
-
- /* Get a chunk */
- chunk = remaining;
- if (chunk > (PSI_DMA_FETCH_SIZE - boff))
- chunk = PSI_DMA_FETCH_SIZE - boff;
- bsize = ((boff + chunk) + TCE_MASK) & ~TCE_MASK;
-
- prlog(PR_DEBUG, "FSP: 0x%08x bytes balign=%llx"
- " boff=%llx bsize=%llx\n",
- chunk, balign, boff, bsize);
- fsp_tce_map(PSI_DMA_FETCH, (void *)balign, bsize);
- taddr = PSI_DMA_FETCH + boff;
- msg = fsp_mkmsg(FSP_CMD_FETCH_SP_DATA, 6,
- flags << 16 | id, sub_id, offset,
- 0, taddr, chunk);
- rc = fsp_sync_msg(msg, false);
- fsp_tce_unmap(PSI_DMA_FETCH, bsize);
-
- woffset = msg->resp->data.words[1];
- wlen = msg->resp->data.words[2];
- prlog(PR_DEBUG, "FSP: -> rc=0x%02x off: %08x"
- " twritten: %08x\n",
- rc, woffset, wlen);
- fsp_freemsg(msg);
-
- /* XXX Is flash busy (0x3f) a reason for retry ? */
- if (rc != 0 && rc != 2) {
- unlock(&fsp_fetch_lock);
- return -EIO;
- }
-
- remaining -= wlen;
- total += wlen;
- buffer += wlen;
- offset += wlen;
-
- /* The doc seems to indicate that we get rc=2 if there's
- * more data and rc=0 if we reached the end of file, but
- * it looks like I always get rc=0, so let's consider
- * an EOF if we got less than what we asked
- */
- if (wlen < chunk)
- break;
- }
- unlock(&fsp_fetch_lock);
+struct fsp_fetch_lid_item {
+ enum resource_id id;
+ uint32_t idx;
- *length = total;
+ uint32_t lid;
+ uint32_t lid_no;
+ uint64_t bsize;
+ uint32_t offset;
+ void *buffer;
+ size_t *length;
+ size_t remaining;
+ struct list_node link;
+ int result;
+};
- return 0;
-}
+/*
+ * We have a queue of things to fetch
+ * when fetched, it moves to fsp_fetched_lid until we're asked if it
+ * has been fetched, in which case it's free()d.
+ *
+ * Everything is protected with fsp_fetch_lock.
+ *
+ * We use PSI_DMA_FETCH TCE entry for this fetching queue. If something
+ * is in the fsp_fetch_lid_queue, it means we're using this TCE entry!
+ *
+ * If we add the first entry to fsp_fetch_lid_queue, we trigger fetching!
+ */
+static LIST_HEAD(fsp_fetch_lid_queue);
+static LIST_HEAD(fsp_fetched_lid);
+static struct lock fsp_fetch_lock = LOCK_UNLOCKED;
/*
* Asynchronous fsp fetch data call
@@ -2275,12 +2224,156 @@ static struct {
{ RESOURCE_ID_CAPP, CAPP_IDX_VENICE_DD20, 0x80a02004 },
};
+static void fsp_start_fetching_next_lid(void);
+static void fsp_fetch_lid_next_chunk(struct fsp_fetch_lid_item *last);
+
+static void fsp_fetch_lid_complete(struct fsp_msg *msg)
+{
+ struct fsp_fetch_lid_item *last;
+ uint32_t woffset, wlen;
+ uint8_t rc;
+
+ lock(&fsp_fetch_lock);
+ last = list_top(&fsp_fetch_lid_queue, struct fsp_fetch_lid_item, link);
+ fsp_tce_unmap(PSI_DMA_FETCH, last->bsize);
+
+ woffset = msg->resp->data.words[1];
+ wlen = msg->resp->data.words[2];
+ rc = (msg->resp->word1 >> 8) & 0xff;
+
+ /* Fall back to a PHYP LID for kernel loads */
+ if (rc && last->lid_no == KERNEL_LID_OPAL) {
+ 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");
+ last->result = OPAL_PARAMETER;
+ last = list_pop(&fsp_fetch_lid_queue,
+ struct fsp_fetch_lid_item, link);
+ list_add_tail(&fsp_fetched_lid, &last->link);
+ fsp_start_fetching_next_lid();
+ unlock(&fsp_fetch_lock);
+ return;
+ }
+ printf("Trying to load as PHYP LID...\n");
+ last->lid = KERNEL_LID_PHYP;
+ /* Retry with different LID */
+ fsp_fetch_lid_next_chunk(last);
+ }
+
+ if (rc !=0 && rc != 2) {
+ last->result = -EIO;
+ last = list_pop(&fsp_fetch_lid_queue, struct fsp_fetch_lid_item, link);
+ list_add_tail(&fsp_fetched_lid, &last->link);
+ fsp_start_fetching_next_lid();
+ unlock(&fsp_fetch_lock);
+ return;
+ }
+
+ if (rc == 0)
+ last->result = OPAL_SUCCESS;
+
+ fsp_freemsg(msg);
+
+ last->remaining -= wlen;
+ *(last->length) += wlen;
+ last->buffer += wlen;
+ last->offset += wlen;
+
+ prlog(PR_DEBUG, "FSP: LID %x Chunk read -> rc=0x%02x off: %08x"
+ " twritten: %08x\n", last->lid, rc, woffset, wlen);
+
+ fsp_fetch_lid_next_chunk(last);
+
+ unlock(&fsp_fetch_lock);
+}
+
+static void fsp_fetch_lid_next_chunk(struct fsp_fetch_lid_item *last)
+{
+ uint64_t baddr;
+ uint64_t balign, boff;
+ uint32_t chunk;
+ uint32_t taddr;
+ struct fsp_msg *msg;
+ uint8_t flags = 0;
+ uint16_t id = FSP_DATASET_NONSP_LID;
+ uint32_t sub_id;
+
+ assert(lock_held_by_me(&fsp_fetch_lock));
+
+ if (last->remaining == 0 || last->result == OPAL_SUCCESS) {
+ last->result = OPAL_SUCCESS;
+ last = list_pop(&fsp_fetch_lid_queue,
+ struct fsp_fetch_lid_item, link);
+ list_add_tail(&fsp_fetched_lid, &last->link);
+ fsp_start_fetching_next_lid();
+ return;
+ }
+
+ baddr = (uint64_t)last->buffer;
+ balign = baddr & ~TCE_MASK;
+ boff = baddr & TCE_MASK;
+
+ chunk = last->remaining;
+ if (chunk > (PSI_DMA_FETCH_SIZE - boff))
+ chunk = PSI_DMA_FETCH_SIZE - boff;
+ last->bsize = ((boff + chunk) + TCE_MASK) & ~TCE_MASK;
+
+ prlog(PR_DEBUG, "FSP: Loading Chunk 0x%08x bytes balign=%llx"
+ " boff=%llx bsize=%llx\n",
+ chunk, balign, boff, last->bsize);
+
+ fsp_tce_map(PSI_DMA_FETCH, (void *)balign, last->bsize);
+ taddr = PSI_DMA_FETCH + boff;
+
+ sub_id = last->lid;
+
+ msg = fsp_mkmsg(FSP_CMD_FETCH_SP_DATA, 6,
+ flags << 16 | id, sub_id, last->offset,
+ 0, taddr, chunk);
+
+ if (fsp_queue_msg(msg, fsp_fetch_lid_complete)) {
+ fsp_freemsg(msg);
+ prerror("FSP: Failed to queue fetch data message\n");
+ last->result = OPAL_INTERNAL_ERROR;
+ last = list_pop(&fsp_fetch_lid_queue,
+ struct fsp_fetch_lid_item, link);
+ list_add_tail(&fsp_fetched_lid, &last->link);
+ }
+}
+
+static void fsp_start_fetching_next_lid(void)
+{
+ struct fsp_fetch_lid_item *last;
+
+ assert(lock_held_by_me(&fsp_fetch_lock));
+
+ last = list_top(&fsp_fetch_lid_queue, struct fsp_fetch_lid_item, link);
+
+ if (last == NULL)
+ return;
+
+ fsp_fetch_lid_next_chunk(last);
+}
+
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;
- int rc, i;
+ struct fsp_fetch_lid_item *resource;
+ uint32_t lid_no = 0;
+ int i;
+
+ resource = malloc(sizeof(struct fsp_fetch_lid_item));
+ assert(resource != NULL);
+
+ resource->id = id;
+ resource->idx = idx;
+
+ resource->offset = 0;
+ resource->buffer = buf;
+ resource->remaining = *size;
+ *size = 0;
+ resource->length = size;
+ resource->result = OPAL_BUSY;
for (i = 0; i < ARRAY_SIZE(fsp_lid_map); i++) {
if (id != fsp_lid_map[i].id)
@@ -2294,34 +2387,111 @@ int fsp_start_preload_resource(enum resource_id id, uint32_t idx,
if (lid_no == 0)
return OPAL_PARAMETER;
-retry:
- tmp_size = *size;
-
printf("Trying to load OPAL LID %08x...\n", lid_no);
- lid = fsp_adjust_lid_side(lid_no);
- rc = fsp_fetch_data(0, FSP_DATASET_NONSP_LID, lid, 0, buf, &tmp_size);
+ resource->lid_no = lid_no;
+ resource->lid = fsp_adjust_lid_side(lid_no);
- /* Fall back to a PHYP LID for kernel loads */
- if (rc && lid_no == KERNEL_LID_OPAL) {
- 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 OPAL_PARAMETER;
+ lock(&fsp_fetch_lock);
+ list_add_tail(&fsp_fetch_lid_queue, &resource->link);
+ fsp_start_fetching_next_lid();
+ unlock(&fsp_fetch_lock);
+
+ return OPAL_SUCCESS;
+}
+
+int fsp_resource_loaded(enum resource_id id, uint32_t idx)
+{
+ struct fsp_fetch_lid_item *resource = NULL;
+ struct fsp_fetch_lid_item *r;
+ int rc = OPAL_BUSY;
+
+ lock(&fsp_fetch_lock);
+ list_for_each(&fsp_fetched_lid, r, link) {
+ if (r->id == id && r->idx == idx) {
+ resource = r;
+ break;
}
- printf("Trying to load as PHYP LID...\n");
- lid_no = KERNEL_LID_PHYP;
- goto retry;
}
- if (rc) {
- prerror("Failed to load LID\n");
- return rc;
+ if (resource) {
+ rc = resource->result;
+ if (rc == OPAL_SUCCESS) {
+ list_del(&resource->link);
+ free(resource);
+ }
}
- if (*size < tmp_size)
- return OPAL_INTERNAL_ERROR;
- *size = tmp_size;
+ unlock(&fsp_fetch_lock);
+
+ return rc;
+}
+
+static int fsp_lid_loaded(uint32_t lid_no)
+{
+ struct fsp_fetch_lid_item *resource = NULL;
+ struct fsp_fetch_lid_item *r;
+ int rc = OPAL_BUSY;
+
+ lock(&fsp_fetch_lock);
+ list_for_each(&fsp_fetched_lid, r, link) {
+ if (r->lid_no == lid_no) {
+ resource = r;
+ break;
+ }
+ }
+
+ if (resource) {
+ rc = resource->result;
+ if (rc == OPAL_SUCCESS) {
+ list_del(&resource->link);
+ free(resource);
+ }
+ }
+ unlock(&fsp_fetch_lock);
+
+ return rc;
+}
+
+int fsp_load_lid(uint32_t lid_no, char *buf, size_t *size)
+{
+ struct fsp_fetch_lid_item *resource;
+ int r;
+
+ resource = malloc(sizeof(struct fsp_fetch_lid_item));
+ assert(resource != NULL);
+
+ resource->id = -1;
+ resource->idx = -1;
+
+ resource->offset = 0;
+ resource->buffer = buf;
+ resource->remaining = *size;
+ *size = 0;
+ resource->length = size;
+ resource->result = OPAL_BUSY;
+
+ if (lid_no == 0)
+ return OPAL_PARAMETER;
+
+ printf("Trying to load LID %08x from FSP\n", lid_no);
+ resource->lid_no = lid_no;
+ resource->lid = fsp_adjust_lid_side(lid_no);
+
+ lock(&fsp_fetch_lock);
+ list_add_tail(&fsp_fetch_lid_queue, &resource->link);
+ fsp_start_fetching_next_lid();
+ unlock(&fsp_fetch_lock);
+
+ r = fsp_lid_loaded(lid_no);
+
+ while(r == OPAL_BUSY) {
+ opal_run_pollers();
+ time_wait_nopoll(msecs_to_tb(5));
+ cpu_relax();
+ r = fsp_lid_loaded(lid_no);
+ }
+
+ return r;
- return OPAL_SUCCESS;
}
void fsp_used_by_console(void)
diff --git a/include/fsp.h b/include/fsp.h
index e05d7a4..b192490 100644
--- a/include/fsp.h
+++ b/include/fsp.h
@@ -724,6 +724,8 @@ extern int fsp_fetch_data_queue(uint8_t flags, uint16_t id, uint32_t sub_id,
void (*comp)(struct fsp_msg *msg)) __warn_unused_result;
extern int fsp_start_preload_resource(enum resource_id id, uint32_t idx,
void *buf, size_t *size);
+extern int fsp_resource_loaded(enum resource_id id, uint32_t idx);
+extern int fsp_load_lid(uint32_t lid_no, char *buf, size_t *size);
/* FSP console stuff */
extern void fsp_console_preinit(void);
diff --git a/include/skiboot.h b/include/skiboot.h
index 6cb9b2d..fc5bc1d 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 int flash_start_preload_resource(enum resource_id id, uint32_t subid,
- void *buf, size_t *len);
+extern int flash_load_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 d56e451..2812b40 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,
- .start_preload_resource = flash_start_preload_resource,
+ .start_preload_resource = flash_load_resource,
.exit = ipmi_wdt_final_reset,
};
diff --git a/platforms/astbmc/palmetto.c b/platforms/astbmc/palmetto.c
index fdc449e..02b0649 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,
- .start_preload_resource = flash_start_preload_resource,
+ .start_preload_resource = flash_load_resource,
.exit = ipmi_wdt_final_reset,
};
diff --git a/platforms/ibm-fsp/apollo.c b/platforms/ibm-fsp/apollo.c
index cc62c98..d03ff75 100644
--- a/platforms/ibm-fsp/apollo.c
+++ b/platforms/ibm-fsp/apollo.c
@@ -61,4 +61,5 @@ DECLARE_PLATFORM(apollo) = {
.nvram_write = fsp_nvram_write,
.elog_commit = elog_fsp_commit,
.start_preload_resource = fsp_start_preload_resource,
+ .resource_loaded = fsp_resource_loaded,
};
diff --git a/platforms/ibm-fsp/firenze.c b/platforms/ibm-fsp/firenze.c
index 9a696b7..fbdbcf3 100644
--- a/platforms/ibm-fsp/firenze.c
+++ b/platforms/ibm-fsp/firenze.c
@@ -415,4 +415,5 @@ DECLARE_PLATFORM(firenze) = {
.occ_timeout = ibm_fsp_occ_timeout,
.elog_commit = elog_fsp_commit,
.start_preload_resource = fsp_start_preload_resource,
+ .resource_loaded = fsp_resource_loaded,
} ;