diff --git a/core/flash.c b/core/flash.c index 53e6eba08734..7e46f0a6d27d 100644 --- a/core/flash.c +++ b/core/flash.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +48,10 @@ static struct lock flash_lock; static struct flash *nvram_flash; static u32 nvram_offset, nvram_size; +/* ibm,firmware-versions support */ +static char *version_buf; +static size_t version_buf_size = 0x1000; + bool flash_reserve(void) { bool rc = false; @@ -148,6 +153,109 @@ static int flash_nvram_write(uint32_t dst, void *src, uint32_t len) return rc; } +static void __flash_dt_add_fw_version(struct dt_node *fw_version, char* data) +{ + char *prop; + int version_len, i; + int len = strlen(data); + const char * version_str[] = {"open-power", "buildroot", "skiboot", + "hostboot-binaries", "hostboot", "linux", + "petitboot", "occ", "capp-ucode", "sbe", + "machine-xml"}; + + /* + * PNOR version strings are not easily consumable. Split them into + * property, value. + * + * Example input from PNOR : + * "open-power-firestone-v1.8" + * "linux-4.4.6-openpower1-8420e0f" + * + * Desired output in device tree: + * open-power = "firestone-v1.8"; + * linux = "4.4.6-openpower1-8420e0f"; + */ + for(i = 0; i < ARRAY_SIZE(version_str); i++) + { + version_len = strlen(version_str[i]); + if (len < version_len) + continue; + + if (memcmp(data, version_str[i], version_len) != 0) + continue; + + /* Found a match, add property */ + if (dt_find_property(fw_version, version_str[i])) + continue; + + /* Increment past "key-" */ + prop = data + version_len + 1; + dt_add_property_string(fw_version, version_str[i], prop); + } +} + +void flash_dt_add_fw_version(void) +{ + uint8_t version_data[80]; + int rc; + int numbytes = 0, i = 0; + struct dt_node *fw_version; + + if (version_buf == NULL) + return; + + rc = wait_for_resource_loaded(RESOURCE_ID_VERSION, RESOURCE_SUBID_NONE); + if (rc != OPAL_SUCCESS) { + prlog(PR_WARNING, "FLASH: Failed to load VERSION data\n"); + free(version_buf); + return; + } + + fw_version = dt_new(dt_root, "ibm,firmware-versions"); + assert(fw_version); + + for ( ; (numbytes < version_buf_size) && version_buf[numbytes]; numbytes++) { + if (version_buf[numbytes] == '\n') { + version_data[i] = '\0'; + __flash_dt_add_fw_version(fw_version, version_data); + memset(version_data, 0, sizeof(version_data)); + i = 0; + continue; + } else if (version_buf[numbytes] == '\t') { + continue; /* skip tabs */ + } + + version_data[i++] = version_buf[numbytes]; + } + + free(version_buf); +} + +void flash_fw_version_preload(void) +{ + int rc; + + if (proc_gen < proc_gen_p9) + return; + + prlog(PR_INFO, "FLASH: Loading VERSION section\n"); + + version_buf = malloc(version_buf_size); + if (!version_buf) { + prlog(PR_WARNING, "FLASH: Failed to allocate memory\n"); + return; + } + + rc = start_preload_resource(RESOURCE_ID_VERSION, RESOURCE_SUBID_NONE, + version_buf, &version_buf_size); + if (rc != OPAL_SUCCESS) { + prlog(PR_WARNING, + "FLASH: Failed to start loading VERSION data\n"); + free(version_buf); + version_buf = NULL; + } +} + static int flash_nvram_probe(struct flash *flash, struct ffs_handle *ffs) { uint32_t start, size, part; @@ -422,6 +530,7 @@ static struct { { RESOURCE_ID_INITRAMFS,RESOURCE_SUBID_NONE, "ROOTFS" }, { RESOURCE_ID_CAPP, RESOURCE_SUBID_SUPPORTED, "CAPP" }, { RESOURCE_ID_IMA_CATALOG, RESOURCE_SUBID_SUPPORTED, "IMA_CATALOG" }, + { RESOURCE_ID_VERSION, RESOURCE_SUBID_NONE, "VERSION" }, }; diff --git a/include/platform.h b/include/platform.h index e6ebb1331fe0..f3af390705f7 100644 --- a/include/platform.h +++ b/include/platform.h @@ -28,6 +28,7 @@ enum resource_id { RESOURCE_ID_INITRAMFS, RESOURCE_ID_CAPP, RESOURCE_ID_IMA_CATALOG, + RESOURCE_ID_VERSION, }; #define RESOURCE_SUBID_NONE 0 #define RESOURCE_SUBID_SUPPORTED 1 diff --git a/include/skiboot.h b/include/skiboot.h index 4b7d51978892..0ab9f3883973 100644 --- a/include/skiboot.h +++ b/include/skiboot.h @@ -243,6 +243,9 @@ extern int flash_subpart_info(void *part_header, uint32_t header_len, uint32_t part_size, uint32_t *part_actual, uint32_t subid, uint32_t *offset, uint32_t *size); +extern void flash_fw_version_preload(void); +extern void flash_dt_add_fw_version(void); + /* NVRAM support */ extern void nvram_init(void); extern void nvram_read_complete(bool success); diff --git a/platforms/astbmc/common.c b/platforms/astbmc/common.c index 3c59f82a9b68..243ad9461239 100644 --- a/platforms/astbmc/common.c +++ b/platforms/astbmc/common.c @@ -134,6 +134,9 @@ void astbmc_init(void) astbmc_fru_init(); ipmi_sensor_init(); + /* Preload PNOR VERSION section */ + flash_fw_version_preload(); + /* As soon as IPMI is up, inform BMC we are in "S0" */ ipmi_set_power_state(IPMI_PWR_SYS_S0_WORKING, IPMI_PWR_NOCHANGE); @@ -144,6 +147,9 @@ void astbmc_init(void) /* Setup UART console for use by Linux via OPAL API */ set_opal_console(&uart_opal_con); + + /* Add ibm,firmware-versions node */ + flash_dt_add_fw_version(); } int64_t astbmc_ipmi_power_down(uint64_t request)