1*145eba1aSCai Huoqing // SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause 2f48ad614SDennis Dalessandro /* 3f48ad614SDennis Dalessandro * Copyright(c) 2015, 2016 Intel Corporation. 4f48ad614SDennis Dalessandro */ 5*145eba1aSCai Huoqing 6f48ad614SDennis Dalessandro #include <linux/delay.h> 7f48ad614SDennis Dalessandro #include "hfi.h" 8f48ad614SDennis Dalessandro #include "common.h" 9f48ad614SDennis Dalessandro #include "eprom.h" 10f48ad614SDennis Dalessandro 11e2113752SDean Luick /* 12e2113752SDean Luick * The EPROM is logically divided into three partitions: 13e2113752SDean Luick * partition 0: the first 128K, visible from PCI ROM BAR 14e2113752SDean Luick * partition 1: 4K config file (sector size) 15e2113752SDean Luick * partition 2: the rest 16e2113752SDean Luick */ 17e2113752SDean Luick #define P0_SIZE (128 * 1024) 18e2113752SDean Luick #define P1_SIZE (4 * 1024) 19e2113752SDean Luick #define P1_START P0_SIZE 20e2113752SDean Luick #define P2_START (P0_SIZE + P1_SIZE) 21e2113752SDean Luick 22e2113752SDean Luick /* controller page size, in bytes */ 23e2113752SDean Luick #define EP_PAGE_SIZE 256 24e2113752SDean Luick #define EP_PAGE_MASK (EP_PAGE_SIZE - 1) 25e2113752SDean Luick #define EP_PAGE_DWORDS (EP_PAGE_SIZE / sizeof(u32)) 26e2113752SDean Luick 27e2113752SDean Luick /* controller commands */ 28f48ad614SDennis Dalessandro #define CMD_SHIFT 24 29e2113752SDean Luick #define CMD_NOP (0) 30e2113752SDean Luick #define CMD_READ_DATA(addr) ((0x03 << CMD_SHIFT) | addr) 31f48ad614SDennis Dalessandro #define CMD_RELEASE_POWERDOWN_NOID ((0xab << CMD_SHIFT)) 32f48ad614SDennis Dalessandro 33f48ad614SDennis Dalessandro /* controller interface speeds */ 34f48ad614SDennis Dalessandro #define EP_SPEED_FULL 0x2 /* full speed */ 35f48ad614SDennis Dalessandro 36f48ad614SDennis Dalessandro /* 37f48ad614SDennis Dalessandro * How long to wait for the EPROM to become available, in ms. 38f48ad614SDennis Dalessandro * The spec 32 Mb EPROM takes around 40s to erase then write. 39f48ad614SDennis Dalessandro * Double it for safety. 40f48ad614SDennis Dalessandro */ 41f48ad614SDennis Dalessandro #define EPROM_TIMEOUT 80000 /* ms */ 42e2113752SDean Luick 43e2113752SDean Luick /* 44e2113752SDean Luick * Read a 256 byte (64 dword) EPROM page. 45e2113752SDean Luick * All callers have verified the offset is at a page boundary. 46e2113752SDean Luick */ 47e2113752SDean Luick static void read_page(struct hfi1_devdata *dd, u32 offset, u32 *result) 48e2113752SDean Luick { 49e2113752SDean Luick int i; 50e2113752SDean Luick 51e2113752SDean Luick write_csr(dd, ASIC_EEP_ADDR_CMD, CMD_READ_DATA(offset)); 52e2113752SDean Luick for (i = 0; i < EP_PAGE_DWORDS; i++) 53e2113752SDean Luick result[i] = (u32)read_csr(dd, ASIC_EEP_DATA); 54e2113752SDean Luick write_csr(dd, ASIC_EEP_ADDR_CMD, CMD_NOP); /* close open page */ 55e2113752SDean Luick } 56e2113752SDean Luick 57e2113752SDean Luick /* 58e2113752SDean Luick * Read length bytes starting at offset from the start of the EPROM. 59e2113752SDean Luick */ 60e2113752SDean Luick static int read_length(struct hfi1_devdata *dd, u32 start, u32 len, void *dest) 61e2113752SDean Luick { 62e2113752SDean Luick u32 buffer[EP_PAGE_DWORDS]; 63e2113752SDean Luick u32 end; 64e2113752SDean Luick u32 start_offset; 65e2113752SDean Luick u32 read_start; 66e2113752SDean Luick u32 bytes; 67e2113752SDean Luick 68e2113752SDean Luick if (len == 0) 69e2113752SDean Luick return 0; 70e2113752SDean Luick 71e2113752SDean Luick end = start + len; 72e2113752SDean Luick 73e2113752SDean Luick /* 74e2113752SDean Luick * Make sure the read range is not outside of the controller read 75e2113752SDean Luick * command address range. Note that '>' is correct below - the end 76e2113752SDean Luick * of the range is OK if it stops at the limit, but no higher. 77e2113752SDean Luick */ 78e2113752SDean Luick if (end > (1 << CMD_SHIFT)) 79e2113752SDean Luick return -EINVAL; 80e2113752SDean Luick 81e2113752SDean Luick /* read the first partial page */ 82e2113752SDean Luick start_offset = start & EP_PAGE_MASK; 83e2113752SDean Luick if (start_offset) { 84e2113752SDean Luick /* partial starting page */ 85e2113752SDean Luick 86e2113752SDean Luick /* align and read the page that contains the start */ 87e2113752SDean Luick read_start = start & ~EP_PAGE_MASK; 88e2113752SDean Luick read_page(dd, read_start, buffer); 89e2113752SDean Luick 90e2113752SDean Luick /* the rest of the page is available data */ 91e2113752SDean Luick bytes = EP_PAGE_SIZE - start_offset; 92e2113752SDean Luick 93e2113752SDean Luick if (len <= bytes) { 94e2113752SDean Luick /* end is within this page */ 95e2113752SDean Luick memcpy(dest, (u8 *)buffer + start_offset, len); 96e2113752SDean Luick return 0; 97e2113752SDean Luick } 98e2113752SDean Luick 99e2113752SDean Luick memcpy(dest, (u8 *)buffer + start_offset, bytes); 100e2113752SDean Luick 101e2113752SDean Luick start += bytes; 102e2113752SDean Luick len -= bytes; 103e2113752SDean Luick dest += bytes; 104e2113752SDean Luick } 105e2113752SDean Luick /* start is now page aligned */ 106e2113752SDean Luick 107e2113752SDean Luick /* read whole pages */ 108e2113752SDean Luick while (len >= EP_PAGE_SIZE) { 109e2113752SDean Luick read_page(dd, start, buffer); 110e2113752SDean Luick memcpy(dest, buffer, EP_PAGE_SIZE); 111e2113752SDean Luick 112e2113752SDean Luick start += EP_PAGE_SIZE; 113e2113752SDean Luick len -= EP_PAGE_SIZE; 114e2113752SDean Luick dest += EP_PAGE_SIZE; 115e2113752SDean Luick } 116e2113752SDean Luick 117e2113752SDean Luick /* read the last partial page */ 118e2113752SDean Luick if (len) { 119e2113752SDean Luick read_page(dd, start, buffer); 120e2113752SDean Luick memcpy(dest, buffer, len); 121e2113752SDean Luick } 122e2113752SDean Luick 123e2113752SDean Luick return 0; 124e2113752SDean Luick } 125e2113752SDean Luick 126f48ad614SDennis Dalessandro /* 127f48ad614SDennis Dalessandro * Initialize the EPROM handler. 128f48ad614SDennis Dalessandro */ 129f48ad614SDennis Dalessandro int eprom_init(struct hfi1_devdata *dd) 130f48ad614SDennis Dalessandro { 131f48ad614SDennis Dalessandro int ret = 0; 132f48ad614SDennis Dalessandro 133f48ad614SDennis Dalessandro /* only the discrete chip has an EPROM */ 134f48ad614SDennis Dalessandro if (dd->pcidev->device != PCI_DEVICE_ID_INTEL0) 135f48ad614SDennis Dalessandro return 0; 136f48ad614SDennis Dalessandro 137f48ad614SDennis Dalessandro /* 138f48ad614SDennis Dalessandro * It is OK if both HFIs reset the EPROM as long as they don't 139f48ad614SDennis Dalessandro * do it at the same time. 140f48ad614SDennis Dalessandro */ 141f48ad614SDennis Dalessandro ret = acquire_chip_resource(dd, CR_EPROM, EPROM_TIMEOUT); 142f48ad614SDennis Dalessandro if (ret) { 143f48ad614SDennis Dalessandro dd_dev_err(dd, 144f48ad614SDennis Dalessandro "%s: unable to acquire EPROM resource, no EPROM support\n", 145f48ad614SDennis Dalessandro __func__); 146f48ad614SDennis Dalessandro goto done_asic; 147f48ad614SDennis Dalessandro } 148f48ad614SDennis Dalessandro 149f48ad614SDennis Dalessandro /* reset EPROM to be sure it is in a good state */ 150f48ad614SDennis Dalessandro 151f48ad614SDennis Dalessandro /* set reset */ 152f48ad614SDennis Dalessandro write_csr(dd, ASIC_EEP_CTL_STAT, ASIC_EEP_CTL_STAT_EP_RESET_SMASK); 153f48ad614SDennis Dalessandro /* clear reset, set speed */ 154f48ad614SDennis Dalessandro write_csr(dd, ASIC_EEP_CTL_STAT, 155f48ad614SDennis Dalessandro EP_SPEED_FULL << ASIC_EEP_CTL_STAT_RATE_SPI_SHIFT); 156f48ad614SDennis Dalessandro 157f48ad614SDennis Dalessandro /* wake the device with command "release powerdown NoID" */ 158f48ad614SDennis Dalessandro write_csr(dd, ASIC_EEP_ADDR_CMD, CMD_RELEASE_POWERDOWN_NOID); 159f48ad614SDennis Dalessandro 160f48ad614SDennis Dalessandro dd->eprom_available = true; 161f48ad614SDennis Dalessandro release_chip_resource(dd, CR_EPROM); 162f48ad614SDennis Dalessandro done_asic: 163f48ad614SDennis Dalessandro return ret; 164f48ad614SDennis Dalessandro } 165107ffbc5SDean Luick 166753b19afSJan Sokolowski /* magic character sequence that begins an image */ 167753b19afSJan Sokolowski #define IMAGE_START_MAGIC "APO=" 168753b19afSJan Sokolowski 169753b19afSJan Sokolowski /* magic character sequence that might trail an image */ 170107ffbc5SDean Luick #define IMAGE_TRAIL_MAGIC "egamiAPO" 171107ffbc5SDean Luick 17262aeddbfSDean Luick /* EPROM file types */ 17362aeddbfSDean Luick #define HFI1_EFT_PLATFORM_CONFIG 2 17462aeddbfSDean Luick 17562aeddbfSDean Luick /* segment size - 128 KiB */ 17662aeddbfSDean Luick #define SEG_SIZE (128 * 1024) 17762aeddbfSDean Luick 17862aeddbfSDean Luick struct hfi1_eprom_footer { 17962aeddbfSDean Luick u32 oprom_size; /* size of the oprom, in bytes */ 18062aeddbfSDean Luick u16 num_table_entries; 18162aeddbfSDean Luick u16 version; /* version of this footer */ 18262aeddbfSDean Luick u32 magic; /* must be last */ 18362aeddbfSDean Luick }; 18462aeddbfSDean Luick 18562aeddbfSDean Luick struct hfi1_eprom_table_entry { 18662aeddbfSDean Luick u32 type; /* file type */ 18762aeddbfSDean Luick u32 offset; /* file offset from start of EPROM */ 18862aeddbfSDean Luick u32 size; /* file size, in bytes */ 18962aeddbfSDean Luick }; 19062aeddbfSDean Luick 19162aeddbfSDean Luick /* 19262aeddbfSDean Luick * Calculate the max number of table entries that will fit within a directory 19362aeddbfSDean Luick * buffer of size 'dir_size'. 19462aeddbfSDean Luick */ 19562aeddbfSDean Luick #define MAX_TABLE_ENTRIES(dir_size) \ 19662aeddbfSDean Luick (((dir_size) - sizeof(struct hfi1_eprom_footer)) / \ 19762aeddbfSDean Luick sizeof(struct hfi1_eprom_table_entry)) 19862aeddbfSDean Luick 19962aeddbfSDean Luick #define DIRECTORY_SIZE(n) (sizeof(struct hfi1_eprom_footer) + \ 20062aeddbfSDean Luick (sizeof(struct hfi1_eprom_table_entry) * (n))) 20162aeddbfSDean Luick 20262aeddbfSDean Luick #define MAGIC4(a, b, c, d) ((d) << 24 | (c) << 16 | (b) << 8 | (a)) 20362aeddbfSDean Luick #define FOOTER_MAGIC MAGIC4('e', 'p', 'r', 'm') 20462aeddbfSDean Luick #define FOOTER_VERSION 1 20562aeddbfSDean Luick 206107ffbc5SDean Luick /* 207107ffbc5SDean Luick * Read all of partition 1. The actual file is at the front. Adjust 208107ffbc5SDean Luick * the returned size if a trailing image magic is found. 209107ffbc5SDean Luick */ 210107ffbc5SDean Luick static int read_partition_platform_config(struct hfi1_devdata *dd, void **data, 211107ffbc5SDean Luick u32 *size) 212107ffbc5SDean Luick { 213107ffbc5SDean Luick void *buffer; 214107ffbc5SDean Luick void *p; 215753b19afSJan Sokolowski u32 length; 216107ffbc5SDean Luick int ret; 217107ffbc5SDean Luick 218107ffbc5SDean Luick buffer = kmalloc(P1_SIZE, GFP_KERNEL); 219107ffbc5SDean Luick if (!buffer) 220107ffbc5SDean Luick return -ENOMEM; 221107ffbc5SDean Luick 222107ffbc5SDean Luick ret = read_length(dd, P1_START, P1_SIZE, buffer); 223107ffbc5SDean Luick if (ret) { 224107ffbc5SDean Luick kfree(buffer); 225107ffbc5SDean Luick return ret; 226107ffbc5SDean Luick } 227107ffbc5SDean Luick 228753b19afSJan Sokolowski /* config partition is valid only if it starts with IMAGE_START_MAGIC */ 229753b19afSJan Sokolowski if (memcmp(buffer, IMAGE_START_MAGIC, strlen(IMAGE_START_MAGIC))) { 230bc5214eeSJan Sokolowski kfree(buffer); 231bc5214eeSJan Sokolowski return -ENOENT; 232bc5214eeSJan Sokolowski } 233107ffbc5SDean Luick 234753b19afSJan Sokolowski /* scan for image magic that may trail the actual data */ 235753b19afSJan Sokolowski p = strnstr(buffer, IMAGE_TRAIL_MAGIC, P1_SIZE); 236753b19afSJan Sokolowski if (p) 237753b19afSJan Sokolowski length = p - buffer; 238753b19afSJan Sokolowski else 239753b19afSJan Sokolowski length = P1_SIZE; 240753b19afSJan Sokolowski 241107ffbc5SDean Luick *data = buffer; 242753b19afSJan Sokolowski *size = length; 243107ffbc5SDean Luick return 0; 244107ffbc5SDean Luick } 245107ffbc5SDean Luick 246107ffbc5SDean Luick /* 24762aeddbfSDean Luick * The segment magic has been checked. There is a footer and table of 24862aeddbfSDean Luick * contents present. 24962aeddbfSDean Luick * 25062aeddbfSDean Luick * directory is a u32 aligned buffer of size EP_PAGE_SIZE. 25162aeddbfSDean Luick */ 25262aeddbfSDean Luick static int read_segment_platform_config(struct hfi1_devdata *dd, 25362aeddbfSDean Luick void *directory, void **data, u32 *size) 25462aeddbfSDean Luick { 25562aeddbfSDean Luick struct hfi1_eprom_footer *footer; 25662aeddbfSDean Luick struct hfi1_eprom_table_entry *table; 25762aeddbfSDean Luick struct hfi1_eprom_table_entry *entry; 25862aeddbfSDean Luick void *buffer = NULL; 25962aeddbfSDean Luick void *table_buffer = NULL; 26062aeddbfSDean Luick int ret, i; 26162aeddbfSDean Luick u32 directory_size; 26262aeddbfSDean Luick u32 seg_base, seg_offset; 26362aeddbfSDean Luick u32 bytes_available, ncopied, to_copy; 26462aeddbfSDean Luick 26562aeddbfSDean Luick /* the footer is at the end of the directory */ 26662aeddbfSDean Luick footer = (struct hfi1_eprom_footer *) 26762aeddbfSDean Luick (directory + EP_PAGE_SIZE - sizeof(*footer)); 26862aeddbfSDean Luick 26962aeddbfSDean Luick /* make sure the structure version is supported */ 27062aeddbfSDean Luick if (footer->version != FOOTER_VERSION) 27162aeddbfSDean Luick return -EINVAL; 27262aeddbfSDean Luick 27362aeddbfSDean Luick /* oprom size cannot be larger than a segment */ 27462aeddbfSDean Luick if (footer->oprom_size >= SEG_SIZE) 27562aeddbfSDean Luick return -EINVAL; 27662aeddbfSDean Luick 27762aeddbfSDean Luick /* the file table must fit in a segment with the oprom */ 27862aeddbfSDean Luick if (footer->num_table_entries > 27962aeddbfSDean Luick MAX_TABLE_ENTRIES(SEG_SIZE - footer->oprom_size)) 28062aeddbfSDean Luick return -EINVAL; 28162aeddbfSDean Luick 28262aeddbfSDean Luick /* find the file table start, which precedes the footer */ 28362aeddbfSDean Luick directory_size = DIRECTORY_SIZE(footer->num_table_entries); 28462aeddbfSDean Luick if (directory_size <= EP_PAGE_SIZE) { 28562aeddbfSDean Luick /* the file table fits into the directory buffer handed in */ 28662aeddbfSDean Luick table = (struct hfi1_eprom_table_entry *) 28762aeddbfSDean Luick (directory + EP_PAGE_SIZE - directory_size); 28862aeddbfSDean Luick } else { 28962aeddbfSDean Luick /* need to allocate and read more */ 29062aeddbfSDean Luick table_buffer = kmalloc(directory_size, GFP_KERNEL); 29162aeddbfSDean Luick if (!table_buffer) 29262aeddbfSDean Luick return -ENOMEM; 29362aeddbfSDean Luick ret = read_length(dd, SEG_SIZE - directory_size, 29462aeddbfSDean Luick directory_size, table_buffer); 29562aeddbfSDean Luick if (ret) 29662aeddbfSDean Luick goto done; 29762aeddbfSDean Luick table = table_buffer; 29862aeddbfSDean Luick } 29962aeddbfSDean Luick 30062aeddbfSDean Luick /* look for the platform configuration file in the table */ 30162aeddbfSDean Luick for (entry = NULL, i = 0; i < footer->num_table_entries; i++) { 30262aeddbfSDean Luick if (table[i].type == HFI1_EFT_PLATFORM_CONFIG) { 30362aeddbfSDean Luick entry = &table[i]; 30462aeddbfSDean Luick break; 30562aeddbfSDean Luick } 30662aeddbfSDean Luick } 30762aeddbfSDean Luick if (!entry) { 30862aeddbfSDean Luick ret = -ENOENT; 30962aeddbfSDean Luick goto done; 31062aeddbfSDean Luick } 31162aeddbfSDean Luick 31262aeddbfSDean Luick /* 31362aeddbfSDean Luick * Sanity check on the configuration file size - it should never 31462aeddbfSDean Luick * be larger than 4 KiB. 31562aeddbfSDean Luick */ 31662aeddbfSDean Luick if (entry->size > (4 * 1024)) { 31762aeddbfSDean Luick dd_dev_err(dd, "Bad configuration file size 0x%x\n", 31862aeddbfSDean Luick entry->size); 31962aeddbfSDean Luick ret = -EINVAL; 32062aeddbfSDean Luick goto done; 32162aeddbfSDean Luick } 32262aeddbfSDean Luick 32362aeddbfSDean Luick /* check for bogus offset and size that wrap when added together */ 32462aeddbfSDean Luick if (entry->offset + entry->size < entry->offset) { 32562aeddbfSDean Luick dd_dev_err(dd, 32662aeddbfSDean Luick "Bad configuration file start + size 0x%x+0x%x\n", 32762aeddbfSDean Luick entry->offset, entry->size); 32862aeddbfSDean Luick ret = -EINVAL; 32962aeddbfSDean Luick goto done; 33062aeddbfSDean Luick } 33162aeddbfSDean Luick 33262aeddbfSDean Luick /* allocate the buffer to return */ 33362aeddbfSDean Luick buffer = kmalloc(entry->size, GFP_KERNEL); 33462aeddbfSDean Luick if (!buffer) { 33562aeddbfSDean Luick ret = -ENOMEM; 33662aeddbfSDean Luick goto done; 33762aeddbfSDean Luick } 33862aeddbfSDean Luick 33962aeddbfSDean Luick /* 34062aeddbfSDean Luick * Extract the file by looping over segments until it is fully read. 34162aeddbfSDean Luick */ 34262aeddbfSDean Luick seg_offset = entry->offset % SEG_SIZE; 34362aeddbfSDean Luick seg_base = entry->offset - seg_offset; 34462aeddbfSDean Luick ncopied = 0; 34562aeddbfSDean Luick while (ncopied < entry->size) { 34662aeddbfSDean Luick /* calculate data bytes available in this segment */ 34762aeddbfSDean Luick 34862aeddbfSDean Luick /* start with the bytes from the current offset to the end */ 34962aeddbfSDean Luick bytes_available = SEG_SIZE - seg_offset; 35062aeddbfSDean Luick /* subtract off footer and table from segment 0 */ 35162aeddbfSDean Luick if (seg_base == 0) { 35262aeddbfSDean Luick /* 35362aeddbfSDean Luick * Sanity check: should not have a starting point 35462aeddbfSDean Luick * at or within the directory. 35562aeddbfSDean Luick */ 35662aeddbfSDean Luick if (bytes_available <= directory_size) { 35762aeddbfSDean Luick dd_dev_err(dd, 35862aeddbfSDean Luick "Bad configuration file - offset 0x%x within footer+table\n", 35962aeddbfSDean Luick entry->offset); 36062aeddbfSDean Luick ret = -EINVAL; 36162aeddbfSDean Luick goto done; 36262aeddbfSDean Luick } 36362aeddbfSDean Luick bytes_available -= directory_size; 36462aeddbfSDean Luick } 36562aeddbfSDean Luick 36662aeddbfSDean Luick /* calculate bytes wanted */ 36762aeddbfSDean Luick to_copy = entry->size - ncopied; 36862aeddbfSDean Luick 36962aeddbfSDean Luick /* max out at the available bytes in this segment */ 37062aeddbfSDean Luick if (to_copy > bytes_available) 37162aeddbfSDean Luick to_copy = bytes_available; 37262aeddbfSDean Luick 37362aeddbfSDean Luick /* 37462aeddbfSDean Luick * Read from the EPROM. 37562aeddbfSDean Luick * 37662aeddbfSDean Luick * The sanity check for entry->offset is done in read_length(). 37762aeddbfSDean Luick * The EPROM offset is validated against what the hardware 37862aeddbfSDean Luick * addressing supports. In addition, if the offset is larger 37962aeddbfSDean Luick * than the actual EPROM, it silently wraps. It will work 38062aeddbfSDean Luick * fine, though the reader may not get what they expected 38162aeddbfSDean Luick * from the EPROM. 38262aeddbfSDean Luick */ 38362aeddbfSDean Luick ret = read_length(dd, seg_base + seg_offset, to_copy, 38462aeddbfSDean Luick buffer + ncopied); 38562aeddbfSDean Luick if (ret) 38662aeddbfSDean Luick goto done; 38762aeddbfSDean Luick 38862aeddbfSDean Luick ncopied += to_copy; 38962aeddbfSDean Luick 39062aeddbfSDean Luick /* set up for next segment */ 39162aeddbfSDean Luick seg_offset = footer->oprom_size; 39262aeddbfSDean Luick seg_base += SEG_SIZE; 39362aeddbfSDean Luick } 39462aeddbfSDean Luick 39562aeddbfSDean Luick /* success */ 39662aeddbfSDean Luick ret = 0; 39762aeddbfSDean Luick *data = buffer; 39862aeddbfSDean Luick *size = entry->size; 39962aeddbfSDean Luick 40062aeddbfSDean Luick done: 40162aeddbfSDean Luick kfree(table_buffer); 40262aeddbfSDean Luick if (ret) 40362aeddbfSDean Luick kfree(buffer); 40462aeddbfSDean Luick return ret; 40562aeddbfSDean Luick } 40662aeddbfSDean Luick 40762aeddbfSDean Luick /* 408107ffbc5SDean Luick * Read the platform configuration file from the EPROM. 409107ffbc5SDean Luick * 410107ffbc5SDean Luick * On success, an allocated buffer containing the data and its size are 411107ffbc5SDean Luick * returned. It is up to the caller to free this buffer. 412107ffbc5SDean Luick * 413107ffbc5SDean Luick * Return value: 414107ffbc5SDean Luick * 0 - success 415107ffbc5SDean Luick * -ENXIO - no EPROM is available 416107ffbc5SDean Luick * -EBUSY - not able to acquire access to the EPROM 417107ffbc5SDean Luick * -ENOENT - no recognizable file written 418107ffbc5SDean Luick * -ENOMEM - buffer could not be allocated 41962aeddbfSDean Luick * -EINVAL - invalid EPROM contentents found 420107ffbc5SDean Luick */ 421107ffbc5SDean Luick int eprom_read_platform_config(struct hfi1_devdata *dd, void **data, u32 *size) 422107ffbc5SDean Luick { 423107ffbc5SDean Luick u32 directory[EP_PAGE_DWORDS]; /* aligned buffer */ 424107ffbc5SDean Luick int ret; 425107ffbc5SDean Luick 426107ffbc5SDean Luick if (!dd->eprom_available) 427107ffbc5SDean Luick return -ENXIO; 428107ffbc5SDean Luick 429107ffbc5SDean Luick ret = acquire_chip_resource(dd, CR_EPROM, EPROM_TIMEOUT); 430107ffbc5SDean Luick if (ret) 431107ffbc5SDean Luick return -EBUSY; 432107ffbc5SDean Luick 43362aeddbfSDean Luick /* read the last page of the segment for the EPROM format magic */ 43462aeddbfSDean Luick ret = read_length(dd, SEG_SIZE - EP_PAGE_SIZE, EP_PAGE_SIZE, directory); 435107ffbc5SDean Luick if (ret) 436107ffbc5SDean Luick goto done; 437107ffbc5SDean Luick 43862aeddbfSDean Luick /* last dword of the segment contains a magic value */ 43962aeddbfSDean Luick if (directory[EP_PAGE_DWORDS - 1] == FOOTER_MAGIC) { 44062aeddbfSDean Luick /* segment format */ 44162aeddbfSDean Luick ret = read_segment_platform_config(dd, directory, data, size); 44262aeddbfSDean Luick } else { 443107ffbc5SDean Luick /* partition format */ 444107ffbc5SDean Luick ret = read_partition_platform_config(dd, data, size); 445107ffbc5SDean Luick } 446107ffbc5SDean Luick 447107ffbc5SDean Luick done: 448107ffbc5SDean Luick release_chip_resource(dd, CR_EPROM); 449107ffbc5SDean Luick return ret; 450107ffbc5SDean Luick } 451