diff options
author | Jeremy Kerr <jk@ozlabs.org> | 2015-02-19 06:34:53 +0800 |
---|---|---|
committer | Stewart Smith <stewart@linux.vnet.ibm.com> | 2015-02-19 10:48:13 +1100 |
commit | 73b262e768529f152ec64b4418b0c31691bc15c3 (patch) | |
tree | 1ff236173025725b84335ced477ec98e2fd619c8 | |
parent | e7d1f60eb49bfd81e1fe153cece899de2542f83e (diff) | |
download | skiboot-73b262e768529f152ec64b4418b0c31691bc15c3.zip skiboot-73b262e768529f152ec64b4418b0c31691bc15c3.tar.gz skiboot-73b262e768529f152ec64b4418b0c31691bc15c3.tar.bz2 |
core/flash: port pnor_load_resource to flash code
Since we have a flash device registered as the system flash, use this as
a generic load_resource backend.
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Reviewed-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
-rw-r--r-- | core/flash.c | 186 | ||||
-rw-r--r-- | include/skiboot.h | 3 | ||||
-rw-r--r-- | platforms/astbmc/astbmc.h | 3 | ||||
-rw-r--r-- | platforms/astbmc/habanero.c | 2 | ||||
-rw-r--r-- | platforms/astbmc/palmetto.c | 2 | ||||
-rw-r--r-- | platforms/astbmc/pnor.c | 167 |
6 files changed, 190 insertions, 173 deletions
diff --git a/core/flash.c b/core/flash.c index 33e9242..c6b01ad 100644 --- a/core/flash.c +++ b/core/flash.c @@ -223,3 +223,189 @@ static int64_t opal_flash_erase(uint64_t id, uint64_t offset, uint64_t size, opal_call(OPAL_FLASH_READ, opal_flash_read, 5); opal_call(OPAL_FLASH_WRITE, opal_flash_write, 5); opal_call(OPAL_FLASH_ERASE, opal_flash_erase, 4); + +/* flash resource API */ +static struct { + enum resource_id id; + uint32_t subid; + char name[PART_NAME_MAX+1]; +} part_name_map[] = { + { RESOURCE_ID_KERNEL, RESOURCE_SUBID_NONE, "KERNEL" }, + { RESOURCE_ID_INITRAMFS,RESOURCE_SUBID_NONE, "ROOTFS" }, +}; + +/* This mimics the hostboot SBE format */ +#define FLASH_SUBPART_ALIGNMENT 0x1000 +#define FLASH_SUBPART_HEADER_SIZE FLASH_SUBPART_ALIGNMENT + +struct flash_hostboot_toc { + be32 ec; + be32 offset; /* From start of header. 4K aligned */ + be32 size; +}; +#define FLASH_HOSTBOOT_TOC_MAX_ENTRIES ((FLASH_SUBPART_HEADER_SIZE - 8) \ + /sizeof(struct flash_hostboot_toc)) + +struct flash_hostboot_header { + char eyecatcher[4]; + be32 version; + struct flash_hostboot_toc toc[FLASH_HOSTBOOT_TOC_MAX_ENTRIES]; +}; + +static int flash_find_subpartition(struct flash_chip *chip, uint32_t subid, + uint32_t *start, uint32_t *total_size) +{ + struct flash_hostboot_header *header; + char eyecatcher[5]; + uint32_t i; + bool rc; + + header = malloc(FLASH_SUBPART_HEADER_SIZE); + if (!header) + return false; + + /* Get the TOC */ + rc = flash_read(chip, *start, header, FLASH_SUBPART_HEADER_SIZE); + if (rc) { + prerror("FLASH: flash subpartition TOC read failed %i", rc); + goto end; + } + + /* Perform sanity */ + i = be32_to_cpu(header->version); + if (i != 1) { + prerror("FLASH: flash subpartition TOC version unknown %i", i); + rc = OPAL_RESOURCE; + goto end; + } + /* NULL terminate eyecatcher */ + strncpy(eyecatcher, header->eyecatcher, 4); + eyecatcher[4] = 0; + prlog(PR_DEBUG, "FLASH: flash subpartition eyecatcher %s\n", + eyecatcher); + + rc = OPAL_RESOURCE; + for (i = 0; i< FLASH_HOSTBOOT_TOC_MAX_ENTRIES; i++) { + uint32_t ec, offset, size; + + ec = be32_to_cpu(header->toc[i].ec); + offset = be32_to_cpu(header->toc[i].offset); + size = be32_to_cpu(header->toc[i].size); + /* Check for null terminating entry */ + if (!ec && !offset && !size) { + prerror("FLASH: flash subpartition not found."); + goto end; + } + + if (ec != subid) + continue; + + /* Sanity check the offset and size */ + if (offset + size > *total_size) { + prerror("FLASH: flash subpartition too big: %i", i); + goto end; + } + if (!size) { + prerror("FLASH: flash subpartition zero size: %i", i); + goto end; + } + if (offset < FLASH_SUBPART_HEADER_SIZE) { + prerror("FLASH: flash subpartition " + "offset too small: %i", i); + goto end; + } + + /* All good, let's adjust the start and size */ + prlog(PR_DEBUG, "FLASH: flash found subpartition: " + "%i size: %i offset %i\n", + i, size, offset); + *start += offset; + size = (size + (FLASH_SUBPART_ALIGNMENT - 1)) & + ~(FLASH_SUBPART_ALIGNMENT - 1); + *total_size = size; + rc = 0; + goto end; + } + +end: + free(header); + return rc; +} + +bool flash_load_resource(enum resource_id id, uint32_t subid, + void *buf, size_t *len) +{ + int i, rc, part_num, part_size, part_start; + struct ffs_handle *ffs; + struct flash *flash; + const char *name; + bool status; + + status = false; + + lock(&flash_lock); + + if (!system_flash) + goto out_unlock; + + flash = system_flash; + + for (i = 0, name = NULL; i < ARRAY_SIZE(part_name_map); i++) { + if (part_name_map[i].id == id) { + name = part_name_map[i].name; + subid = part_name_map[i].subid; + break; + } + } + if (!name) { + prerror("FLASH: Couldn't find partition for id %d\n", id); + goto out_unlock; + } + + rc = ffs_open_flash(flash->chip, 0, flash->size, &ffs); + if (rc) { + prerror("FLASH: Can't open ffs handle\n"); + goto out_unlock; + } + + rc = ffs_lookup_part(ffs, name, &part_num); + if (rc) { + prerror("FLASH: No %s partition\n", name); + goto out_free_ffs; + } + rc = ffs_part_info(ffs, part_num, NULL, + &part_start, &part_size, NULL); + if (rc) { + prerror("FLASH: Failed to get %s partition info\n", name); + goto out_free_ffs; + } + + if (part_size > *len) { + prerror("FLASH: %s image too large (%d > %zd)\n", name, + part_size, *len); + goto out_free_ffs; + } + + /* Find the sub partition if required */ + if (subid != RESOURCE_SUBID_NONE) { + rc = flash_find_subpartition(flash->chip, subid, &part_start, + &part_size); + if (rc) + return false; + } + + rc = flash_read(flash->chip, part_start, buf, part_size); + if (rc) { + prerror("FLASH: failed to read %s partition\n", name); + goto out_free_ffs; + } + + *len = part_size; + status = true; + +out_free_ffs: + ffs_close(ffs); +out_unlock: + unlock(&flash_lock); + return status; +} diff --git a/include/skiboot.h b/include/skiboot.h index dbc2057..f6fcc63 100644 --- a/include/skiboot.h +++ b/include/skiboot.h @@ -199,7 +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 bool flash_load_resource(enum resource_id id, void *buf, size_t *len); +extern bool flash_load_resource(enum resource_id id, uint32_t subid, + void *buf, size_t *len); /* NVRAM support */ extern void nvram_init(void); diff --git a/platforms/astbmc/astbmc.h b/platforms/astbmc/astbmc.h index cff4757..cee475a 100644 --- a/platforms/astbmc/astbmc.h +++ b/platforms/astbmc/astbmc.h @@ -24,8 +24,5 @@ extern int64_t astbmc_ipmi_power_down(uint64_t request); extern void astbmc_init(void); extern void astbmc_ext_irq(unsigned int chip_id); extern int pnor_init(void); -extern int pnor_load_part(const char *name, void *addr, size_t *len); -extern bool pnor_load_resource(enum resource_id id, uint32_t subid, - void *buf, size_t *len); #endif /* __ASTBMC_H */ diff --git a/platforms/astbmc/habanero.c b/platforms/astbmc/habanero.c index a19aafd..0ec867f 100644 --- a/platforms/astbmc/habanero.c +++ b/platforms/astbmc/habanero.c @@ -49,5 +49,5 @@ DECLARE_PLATFORM(habanero) = { .external_irq = astbmc_ext_irq, .cec_power_down = astbmc_ipmi_power_down, .cec_reboot = astbmc_ipmi_reboot, - .load_resource = pnor_load_resource, + .load_resource = flash_load_resource, }; diff --git a/platforms/astbmc/palmetto.c b/platforms/astbmc/palmetto.c index 210d10a..3435d0b 100644 --- a/platforms/astbmc/palmetto.c +++ b/platforms/astbmc/palmetto.c @@ -51,6 +51,6 @@ DECLARE_PLATFORM(palmetto) = { .cec_power_down = astbmc_ipmi_power_down, .cec_reboot = astbmc_ipmi_reboot, .elog_commit = ipmi_elog_commit, - .load_resource = pnor_load_resource, + .load_resource = flash_load_resource, .exit = ipmi_wdt_final_reset, }; diff --git a/platforms/astbmc/pnor.c b/platforms/astbmc/pnor.c index c566877..e5bc269 100644 --- a/platforms/astbmc/pnor.c +++ b/platforms/astbmc/pnor.c @@ -84,170 +84,3 @@ int pnor_init(void) return rc; } -static struct { - enum resource_id id; - uint32_t subid; - char name[PART_NAME_MAX+1]; -} part_name_map[] = { - { RESOURCE_ID_KERNEL, RESOURCE_SUBID_NONE, "KERNEL" }, - { RESOURCE_ID_INITRAMFS,RESOURCE_SUBID_NONE, "ROOTFS" }, -}; - -/* This mimics the hostboot SBE format */ -#define PNOR_SUBPART_ALIGNMENT 0x1000 -#define PNOR_SUBPART_HEADER_SIZE PNOR_SUBPART_ALIGNMENT -struct pnor_hostboot_toc { - be32 ec; - be32 offset; /* From start of header. 4K aligned */ - be32 size; -}; -#define PNOR_HOSTBOOT_TOC_MAX_ENTRIES ((PNOR_SUBPART_HEADER_SIZE - 8)/sizeof(struct pnor_hostboot_toc)) -struct pnor_hostboot_header { - char eyecatcher[4]; - be32 version; - struct pnor_hostboot_toc toc[PNOR_HOSTBOOT_TOC_MAX_ENTRIES]; -}; - -static int pnor_find_subpartition(struct flash_chip *chip, - uint32_t subid, - uint32_t *start, - uint32_t *total_size) -{ - struct pnor_hostboot_header *header; - uint32_t i; - bool rc; - char eyecatcher[5]; - - header = malloc(PNOR_SUBPART_HEADER_SIZE); - if (!header) - return false; - - /* Get the TOC */ - rc = flash_read(chip, *start, header, PNOR_SUBPART_HEADER_SIZE); - if (rc) { - prerror("PLAT: pnor subpartition TOC read failed %i", rc); - goto end; - } - - /* Perform sanity */ - i = be32_to_cpu(header->version); - if (i != 1) { - prerror("PLAT: pnor subpartition TOC version unknown %i", i); - rc = OPAL_RESOURCE; - goto end; - } - /* NULL terminate eyecatcher */ - strncpy(eyecatcher, header->eyecatcher, 4); - eyecatcher[4] = 0; - printf("PLAT: pnor subpartition eyecatcher %s\n", eyecatcher); - - rc = OPAL_RESOURCE; - for (i = 0; i< PNOR_HOSTBOOT_TOC_MAX_ENTRIES; i++) { - uint32_t ec, offset, size; - - ec = be32_to_cpu(header->toc[i].ec); - offset = be32_to_cpu(header->toc[i].offset); - size = be32_to_cpu(header->toc[i].size); - /* Check for null terminating entry */ - if (!ec && !offset && !size) { - prerror("PLAT: pnor subpartition not found."); - goto end; - } - - if (ec != subid) - continue; - - /* Sanity check the offset and size */ - if (offset + size > *total_size) { - prerror("PLAT: pnor subpartition too big: %i", i); - goto end; - } - if (!size) { - prerror("PLAT: pnor subpartition zero size: %i", i); - goto end; - } - if (offset < PNOR_SUBPART_HEADER_SIZE) { - prerror("PLAT: pnor subpartition offset too small: %i", i); - goto end; - } - - /* All good, let's adjust the start and size */ - printf("PLAT: pnor found subpartition: %i size: %i offset %i\n", - i, size, offset); - *start += offset; - size = (size + (PNOR_SUBPART_ALIGNMENT - 1)) & ~(PNOR_SUBPART_ALIGNMENT - 1); - *total_size = size; - rc = 0; - goto end; - } - -end: - free(header); - return rc; -} - -bool pnor_load_resource(enum resource_id id, uint32_t subid, - void *buf, size_t *len) -{ - int i, rc, part_num, part_size, part_start; - const char *name; - - if (!pnor_ffs || !pnor_chip) - return false; - - for (i = 0, name = NULL; i < ARRAY_SIZE(part_name_map); i++) { - if (part_name_map[i].id == id) { - name = part_name_map[i].name; - break; - } - } - if (!name) { - prerror("PLAT: Couldn't find partition for id %d\n", id); - return false; - } - - /* - * If partition doesn't have a subindex but the caller specifies one, - * we fail. eg. kernel partition doesn't have a subindex - */ - if ((part_name_map[i].subid == RESOURCE_SUBID_NONE) && - (subid != RESOURCE_SUBID_NONE)) { - prerror("PLAT: Partition %s doesn't have subindex\n", name); - return false; - } - - rc = ffs_lookup_part(pnor_ffs, name, &part_num); - if (rc) { - prerror("PLAT: No %s partition in PNOR\n", name); - return false; - } - rc = ffs_part_info(pnor_ffs, part_num, NULL, - &part_start, &part_size, NULL); - if (rc) { - prerror("PLAT: Failed to get %s partition info\n", name); - return false; - } - - /* Find the sub partition if required */ - if (subid != RESOURCE_SUBID_NONE) { - rc = pnor_find_subpartition(pnor_chip, subid, &part_start, - &part_size); - if (rc) - return false; - } - if (part_size > *len) { - prerror("PLAT: %s image too large (%d > %zd)\n", name, - part_size, *len); - return false; - } - - rc = flash_read(pnor_chip, part_start, buf, part_size); - if (rc) { - prerror("PLAT: failed to read %s partition\n", name); - return false; - } - - *len = part_size; - - return true; -} |