diff options
-rw-r--r-- | core/flash.c | 2 | ||||
-rw-r--r-- | core/hostservices.c | 2 | ||||
-rw-r--r-- | core/platform.c | 3 | ||||
-rw-r--r-- | core/vpd.c | 2 | ||||
-rw-r--r-- | hdata/test/stubs.c | 2 | ||||
-rw-r--r-- | hw/fsp/fsp.c | 378 | ||||
-rw-r--r-- | include/fsp.h | 2 | ||||
-rw-r--r-- | include/skiboot.h | 4 | ||||
-rw-r--r-- | platforms/astbmc/habanero.c | 2 | ||||
-rw-r--r-- | platforms/astbmc/palmetto.c | 2 | ||||
-rw-r--r-- | platforms/ibm-fsp/apollo.c | 1 | ||||
-rw-r--r-- | platforms/ibm-fsp/firenze.c | 1 |
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); } @@ -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, } ; |