1f48ad614SDennis Dalessandro /* 2f48ad614SDennis Dalessandro * Copyright(c) 2015, 2016 Intel Corporation. 3f48ad614SDennis Dalessandro * 4f48ad614SDennis Dalessandro * This file is provided under a dual BSD/GPLv2 license. When using or 5f48ad614SDennis Dalessandro * redistributing this file, you may do so under either license. 6f48ad614SDennis Dalessandro * 7f48ad614SDennis Dalessandro * GPL LICENSE SUMMARY 8f48ad614SDennis Dalessandro * 9f48ad614SDennis Dalessandro * This program is free software; you can redistribute it and/or modify 10f48ad614SDennis Dalessandro * it under the terms of version 2 of the GNU General Public License as 11f48ad614SDennis Dalessandro * published by the Free Software Foundation. 12f48ad614SDennis Dalessandro * 13f48ad614SDennis Dalessandro * This program is distributed in the hope that it will be useful, but 14f48ad614SDennis Dalessandro * WITHOUT ANY WARRANTY; without even the implied warranty of 15f48ad614SDennis Dalessandro * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16f48ad614SDennis Dalessandro * General Public License for more details. 17f48ad614SDennis Dalessandro * 18f48ad614SDennis Dalessandro * BSD LICENSE 19f48ad614SDennis Dalessandro * 20f48ad614SDennis Dalessandro * Redistribution and use in source and binary forms, with or without 21f48ad614SDennis Dalessandro * modification, are permitted provided that the following conditions 22f48ad614SDennis Dalessandro * are met: 23f48ad614SDennis Dalessandro * 24f48ad614SDennis Dalessandro * - Redistributions of source code must retain the above copyright 25f48ad614SDennis Dalessandro * notice, this list of conditions and the following disclaimer. 26f48ad614SDennis Dalessandro * - Redistributions in binary form must reproduce the above copyright 27f48ad614SDennis Dalessandro * notice, this list of conditions and the following disclaimer in 28f48ad614SDennis Dalessandro * the documentation and/or other materials provided with the 29f48ad614SDennis Dalessandro * distribution. 30f48ad614SDennis Dalessandro * - Neither the name of Intel Corporation nor the names of its 31f48ad614SDennis Dalessandro * contributors may be used to endorse or promote products derived 32f48ad614SDennis Dalessandro * from this software without specific prior written permission. 33f48ad614SDennis Dalessandro * 34f48ad614SDennis Dalessandro * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 35f48ad614SDennis Dalessandro * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 36f48ad614SDennis Dalessandro * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 37f48ad614SDennis Dalessandro * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 38f48ad614SDennis Dalessandro * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 39f48ad614SDennis Dalessandro * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 40f48ad614SDennis Dalessandro * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 41f48ad614SDennis Dalessandro * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 42f48ad614SDennis Dalessandro * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 43f48ad614SDennis Dalessandro * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 44f48ad614SDennis Dalessandro * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 45f48ad614SDennis Dalessandro * 46f48ad614SDennis Dalessandro */ 47f48ad614SDennis Dalessandro #include <linux/delay.h> 48f48ad614SDennis Dalessandro #include "hfi.h" 49f48ad614SDennis Dalessandro #include "common.h" 50f48ad614SDennis Dalessandro #include "eprom.h" 51f48ad614SDennis Dalessandro 52e2113752SDean Luick /* 53e2113752SDean Luick * The EPROM is logically divided into three partitions: 54e2113752SDean Luick * partition 0: the first 128K, visible from PCI ROM BAR 55e2113752SDean Luick * partition 1: 4K config file (sector size) 56e2113752SDean Luick * partition 2: the rest 57e2113752SDean Luick */ 58e2113752SDean Luick #define P0_SIZE (128 * 1024) 59e2113752SDean Luick #define P1_SIZE (4 * 1024) 60e2113752SDean Luick #define P1_START P0_SIZE 61e2113752SDean Luick #define P2_START (P0_SIZE + P1_SIZE) 62e2113752SDean Luick 63e2113752SDean Luick /* controller page size, in bytes */ 64e2113752SDean Luick #define EP_PAGE_SIZE 256 65e2113752SDean Luick #define EP_PAGE_MASK (EP_PAGE_SIZE - 1) 66e2113752SDean Luick #define EP_PAGE_DWORDS (EP_PAGE_SIZE / sizeof(u32)) 67e2113752SDean Luick 68e2113752SDean Luick /* controller commands */ 69f48ad614SDennis Dalessandro #define CMD_SHIFT 24 70e2113752SDean Luick #define CMD_NOP (0) 71e2113752SDean Luick #define CMD_READ_DATA(addr) ((0x03 << CMD_SHIFT) | addr) 72f48ad614SDennis Dalessandro #define CMD_RELEASE_POWERDOWN_NOID ((0xab << CMD_SHIFT)) 73f48ad614SDennis Dalessandro 74f48ad614SDennis Dalessandro /* controller interface speeds */ 75f48ad614SDennis Dalessandro #define EP_SPEED_FULL 0x2 /* full speed */ 76f48ad614SDennis Dalessandro 77f48ad614SDennis Dalessandro /* 78f48ad614SDennis Dalessandro * How long to wait for the EPROM to become available, in ms. 79f48ad614SDennis Dalessandro * The spec 32 Mb EPROM takes around 40s to erase then write. 80f48ad614SDennis Dalessandro * Double it for safety. 81f48ad614SDennis Dalessandro */ 82f48ad614SDennis Dalessandro #define EPROM_TIMEOUT 80000 /* ms */ 83e2113752SDean Luick 84e2113752SDean Luick /* 85e2113752SDean Luick * Read a 256 byte (64 dword) EPROM page. 86e2113752SDean Luick * All callers have verified the offset is at a page boundary. 87e2113752SDean Luick */ 88e2113752SDean Luick static void read_page(struct hfi1_devdata *dd, u32 offset, u32 *result) 89e2113752SDean Luick { 90e2113752SDean Luick int i; 91e2113752SDean Luick 92e2113752SDean Luick write_csr(dd, ASIC_EEP_ADDR_CMD, CMD_READ_DATA(offset)); 93e2113752SDean Luick for (i = 0; i < EP_PAGE_DWORDS; i++) 94e2113752SDean Luick result[i] = (u32)read_csr(dd, ASIC_EEP_DATA); 95e2113752SDean Luick write_csr(dd, ASIC_EEP_ADDR_CMD, CMD_NOP); /* close open page */ 96e2113752SDean Luick } 97e2113752SDean Luick 98e2113752SDean Luick /* 99e2113752SDean Luick * Read length bytes starting at offset from the start of the EPROM. 100e2113752SDean Luick */ 101e2113752SDean Luick static int read_length(struct hfi1_devdata *dd, u32 start, u32 len, void *dest) 102e2113752SDean Luick { 103e2113752SDean Luick u32 buffer[EP_PAGE_DWORDS]; 104e2113752SDean Luick u32 end; 105e2113752SDean Luick u32 start_offset; 106e2113752SDean Luick u32 read_start; 107e2113752SDean Luick u32 bytes; 108e2113752SDean Luick 109e2113752SDean Luick if (len == 0) 110e2113752SDean Luick return 0; 111e2113752SDean Luick 112e2113752SDean Luick end = start + len; 113e2113752SDean Luick 114e2113752SDean Luick /* 115e2113752SDean Luick * Make sure the read range is not outside of the controller read 116e2113752SDean Luick * command address range. Note that '>' is correct below - the end 117e2113752SDean Luick * of the range is OK if it stops at the limit, but no higher. 118e2113752SDean Luick */ 119e2113752SDean Luick if (end > (1 << CMD_SHIFT)) 120e2113752SDean Luick return -EINVAL; 121e2113752SDean Luick 122e2113752SDean Luick /* read the first partial page */ 123e2113752SDean Luick start_offset = start & EP_PAGE_MASK; 124e2113752SDean Luick if (start_offset) { 125e2113752SDean Luick /* partial starting page */ 126e2113752SDean Luick 127e2113752SDean Luick /* align and read the page that contains the start */ 128e2113752SDean Luick read_start = start & ~EP_PAGE_MASK; 129e2113752SDean Luick read_page(dd, read_start, buffer); 130e2113752SDean Luick 131e2113752SDean Luick /* the rest of the page is available data */ 132e2113752SDean Luick bytes = EP_PAGE_SIZE - start_offset; 133e2113752SDean Luick 134e2113752SDean Luick if (len <= bytes) { 135e2113752SDean Luick /* end is within this page */ 136e2113752SDean Luick memcpy(dest, (u8 *)buffer + start_offset, len); 137e2113752SDean Luick return 0; 138e2113752SDean Luick } 139e2113752SDean Luick 140e2113752SDean Luick memcpy(dest, (u8 *)buffer + start_offset, bytes); 141e2113752SDean Luick 142e2113752SDean Luick start += bytes; 143e2113752SDean Luick len -= bytes; 144e2113752SDean Luick dest += bytes; 145e2113752SDean Luick } 146e2113752SDean Luick /* start is now page aligned */ 147e2113752SDean Luick 148e2113752SDean Luick /* read whole pages */ 149e2113752SDean Luick while (len >= EP_PAGE_SIZE) { 150e2113752SDean Luick read_page(dd, start, buffer); 151e2113752SDean Luick memcpy(dest, buffer, EP_PAGE_SIZE); 152e2113752SDean Luick 153e2113752SDean Luick start += EP_PAGE_SIZE; 154e2113752SDean Luick len -= EP_PAGE_SIZE; 155e2113752SDean Luick dest += EP_PAGE_SIZE; 156e2113752SDean Luick } 157e2113752SDean Luick 158e2113752SDean Luick /* read the last partial page */ 159e2113752SDean Luick if (len) { 160e2113752SDean Luick read_page(dd, start, buffer); 161e2113752SDean Luick memcpy(dest, buffer, len); 162e2113752SDean Luick } 163e2113752SDean Luick 164e2113752SDean Luick return 0; 165e2113752SDean Luick } 166e2113752SDean Luick 167f48ad614SDennis Dalessandro /* 168f48ad614SDennis Dalessandro * Initialize the EPROM handler. 169f48ad614SDennis Dalessandro */ 170f48ad614SDennis Dalessandro int eprom_init(struct hfi1_devdata *dd) 171f48ad614SDennis Dalessandro { 172f48ad614SDennis Dalessandro int ret = 0; 173f48ad614SDennis Dalessandro 174f48ad614SDennis Dalessandro /* only the discrete chip has an EPROM */ 175f48ad614SDennis Dalessandro if (dd->pcidev->device != PCI_DEVICE_ID_INTEL0) 176f48ad614SDennis Dalessandro return 0; 177f48ad614SDennis Dalessandro 178f48ad614SDennis Dalessandro /* 179f48ad614SDennis Dalessandro * It is OK if both HFIs reset the EPROM as long as they don't 180f48ad614SDennis Dalessandro * do it at the same time. 181f48ad614SDennis Dalessandro */ 182f48ad614SDennis Dalessandro ret = acquire_chip_resource(dd, CR_EPROM, EPROM_TIMEOUT); 183f48ad614SDennis Dalessandro if (ret) { 184f48ad614SDennis Dalessandro dd_dev_err(dd, 185f48ad614SDennis Dalessandro "%s: unable to acquire EPROM resource, no EPROM support\n", 186f48ad614SDennis Dalessandro __func__); 187f48ad614SDennis Dalessandro goto done_asic; 188f48ad614SDennis Dalessandro } 189f48ad614SDennis Dalessandro 190f48ad614SDennis Dalessandro /* reset EPROM to be sure it is in a good state */ 191f48ad614SDennis Dalessandro 192f48ad614SDennis Dalessandro /* set reset */ 193f48ad614SDennis Dalessandro write_csr(dd, ASIC_EEP_CTL_STAT, ASIC_EEP_CTL_STAT_EP_RESET_SMASK); 194f48ad614SDennis Dalessandro /* clear reset, set speed */ 195f48ad614SDennis Dalessandro write_csr(dd, ASIC_EEP_CTL_STAT, 196f48ad614SDennis Dalessandro EP_SPEED_FULL << ASIC_EEP_CTL_STAT_RATE_SPI_SHIFT); 197f48ad614SDennis Dalessandro 198f48ad614SDennis Dalessandro /* wake the device with command "release powerdown NoID" */ 199f48ad614SDennis Dalessandro write_csr(dd, ASIC_EEP_ADDR_CMD, CMD_RELEASE_POWERDOWN_NOID); 200f48ad614SDennis Dalessandro 201f48ad614SDennis Dalessandro dd->eprom_available = true; 202f48ad614SDennis Dalessandro release_chip_resource(dd, CR_EPROM); 203f48ad614SDennis Dalessandro done_asic: 204f48ad614SDennis Dalessandro return ret; 205f48ad614SDennis Dalessandro } 206107ffbc5SDean Luick 207107ffbc5SDean Luick /* magic character sequence that trails an image */ 208107ffbc5SDean Luick #define IMAGE_TRAIL_MAGIC "egamiAPO" 209107ffbc5SDean Luick 21062aeddbfSDean Luick /* EPROM file types */ 21162aeddbfSDean Luick #define HFI1_EFT_PLATFORM_CONFIG 2 21262aeddbfSDean Luick 21362aeddbfSDean Luick /* segment size - 128 KiB */ 21462aeddbfSDean Luick #define SEG_SIZE (128 * 1024) 21562aeddbfSDean Luick 21662aeddbfSDean Luick struct hfi1_eprom_footer { 21762aeddbfSDean Luick u32 oprom_size; /* size of the oprom, in bytes */ 21862aeddbfSDean Luick u16 num_table_entries; 21962aeddbfSDean Luick u16 version; /* version of this footer */ 22062aeddbfSDean Luick u32 magic; /* must be last */ 22162aeddbfSDean Luick }; 22262aeddbfSDean Luick 22362aeddbfSDean Luick struct hfi1_eprom_table_entry { 22462aeddbfSDean Luick u32 type; /* file type */ 22562aeddbfSDean Luick u32 offset; /* file offset from start of EPROM */ 22662aeddbfSDean Luick u32 size; /* file size, in bytes */ 22762aeddbfSDean Luick }; 22862aeddbfSDean Luick 22962aeddbfSDean Luick /* 23062aeddbfSDean Luick * Calculate the max number of table entries that will fit within a directory 23162aeddbfSDean Luick * buffer of size 'dir_size'. 23262aeddbfSDean Luick */ 23362aeddbfSDean Luick #define MAX_TABLE_ENTRIES(dir_size) \ 23462aeddbfSDean Luick (((dir_size) - sizeof(struct hfi1_eprom_footer)) / \ 23562aeddbfSDean Luick sizeof(struct hfi1_eprom_table_entry)) 23662aeddbfSDean Luick 23762aeddbfSDean Luick #define DIRECTORY_SIZE(n) (sizeof(struct hfi1_eprom_footer) + \ 23862aeddbfSDean Luick (sizeof(struct hfi1_eprom_table_entry) * (n))) 23962aeddbfSDean Luick 24062aeddbfSDean Luick #define MAGIC4(a, b, c, d) ((d) << 24 | (c) << 16 | (b) << 8 | (a)) 24162aeddbfSDean Luick #define FOOTER_MAGIC MAGIC4('e', 'p', 'r', 'm') 24262aeddbfSDean Luick #define FOOTER_VERSION 1 24362aeddbfSDean Luick 244107ffbc5SDean Luick /* 245107ffbc5SDean Luick * Read all of partition 1. The actual file is at the front. Adjust 246107ffbc5SDean Luick * the returned size if a trailing image magic is found. 247107ffbc5SDean Luick */ 248107ffbc5SDean Luick static int read_partition_platform_config(struct hfi1_devdata *dd, void **data, 249107ffbc5SDean Luick u32 *size) 250107ffbc5SDean Luick { 251107ffbc5SDean Luick void *buffer; 252107ffbc5SDean Luick void *p; 253107ffbc5SDean Luick int ret; 254107ffbc5SDean Luick 255107ffbc5SDean Luick buffer = kmalloc(P1_SIZE, GFP_KERNEL); 256107ffbc5SDean Luick if (!buffer) 257107ffbc5SDean Luick return -ENOMEM; 258107ffbc5SDean Luick 259107ffbc5SDean Luick ret = read_length(dd, P1_START, P1_SIZE, buffer); 260107ffbc5SDean Luick if (ret) { 261107ffbc5SDean Luick kfree(buffer); 262107ffbc5SDean Luick return ret; 263107ffbc5SDean Luick } 264107ffbc5SDean Luick 265107ffbc5SDean Luick /* scan for image magic that may trail the actual data */ 266107ffbc5SDean Luick p = strnstr(buffer, IMAGE_TRAIL_MAGIC, P1_SIZE); 267*bc5214eeSJan Sokolowski if (!p) { 268*bc5214eeSJan Sokolowski kfree(buffer); 269*bc5214eeSJan Sokolowski return -ENOENT; 270*bc5214eeSJan Sokolowski } 271107ffbc5SDean Luick 272107ffbc5SDean Luick *data = buffer; 273*bc5214eeSJan Sokolowski *size = p - buffer; 274107ffbc5SDean Luick return 0; 275107ffbc5SDean Luick } 276107ffbc5SDean Luick 277107ffbc5SDean Luick /* 27862aeddbfSDean Luick * The segment magic has been checked. There is a footer and table of 27962aeddbfSDean Luick * contents present. 28062aeddbfSDean Luick * 28162aeddbfSDean Luick * directory is a u32 aligned buffer of size EP_PAGE_SIZE. 28262aeddbfSDean Luick */ 28362aeddbfSDean Luick static int read_segment_platform_config(struct hfi1_devdata *dd, 28462aeddbfSDean Luick void *directory, void **data, u32 *size) 28562aeddbfSDean Luick { 28662aeddbfSDean Luick struct hfi1_eprom_footer *footer; 28762aeddbfSDean Luick struct hfi1_eprom_table_entry *table; 28862aeddbfSDean Luick struct hfi1_eprom_table_entry *entry; 28962aeddbfSDean Luick void *buffer = NULL; 29062aeddbfSDean Luick void *table_buffer = NULL; 29162aeddbfSDean Luick int ret, i; 29262aeddbfSDean Luick u32 directory_size; 29362aeddbfSDean Luick u32 seg_base, seg_offset; 29462aeddbfSDean Luick u32 bytes_available, ncopied, to_copy; 29562aeddbfSDean Luick 29662aeddbfSDean Luick /* the footer is at the end of the directory */ 29762aeddbfSDean Luick footer = (struct hfi1_eprom_footer *) 29862aeddbfSDean Luick (directory + EP_PAGE_SIZE - sizeof(*footer)); 29962aeddbfSDean Luick 30062aeddbfSDean Luick /* make sure the structure version is supported */ 30162aeddbfSDean Luick if (footer->version != FOOTER_VERSION) 30262aeddbfSDean Luick return -EINVAL; 30362aeddbfSDean Luick 30462aeddbfSDean Luick /* oprom size cannot be larger than a segment */ 30562aeddbfSDean Luick if (footer->oprom_size >= SEG_SIZE) 30662aeddbfSDean Luick return -EINVAL; 30762aeddbfSDean Luick 30862aeddbfSDean Luick /* the file table must fit in a segment with the oprom */ 30962aeddbfSDean Luick if (footer->num_table_entries > 31062aeddbfSDean Luick MAX_TABLE_ENTRIES(SEG_SIZE - footer->oprom_size)) 31162aeddbfSDean Luick return -EINVAL; 31262aeddbfSDean Luick 31362aeddbfSDean Luick /* find the file table start, which precedes the footer */ 31462aeddbfSDean Luick directory_size = DIRECTORY_SIZE(footer->num_table_entries); 31562aeddbfSDean Luick if (directory_size <= EP_PAGE_SIZE) { 31662aeddbfSDean Luick /* the file table fits into the directory buffer handed in */ 31762aeddbfSDean Luick table = (struct hfi1_eprom_table_entry *) 31862aeddbfSDean Luick (directory + EP_PAGE_SIZE - directory_size); 31962aeddbfSDean Luick } else { 32062aeddbfSDean Luick /* need to allocate and read more */ 32162aeddbfSDean Luick table_buffer = kmalloc(directory_size, GFP_KERNEL); 32262aeddbfSDean Luick if (!table_buffer) 32362aeddbfSDean Luick return -ENOMEM; 32462aeddbfSDean Luick ret = read_length(dd, SEG_SIZE - directory_size, 32562aeddbfSDean Luick directory_size, table_buffer); 32662aeddbfSDean Luick if (ret) 32762aeddbfSDean Luick goto done; 32862aeddbfSDean Luick table = table_buffer; 32962aeddbfSDean Luick } 33062aeddbfSDean Luick 33162aeddbfSDean Luick /* look for the platform configuration file in the table */ 33262aeddbfSDean Luick for (entry = NULL, i = 0; i < footer->num_table_entries; i++) { 33362aeddbfSDean Luick if (table[i].type == HFI1_EFT_PLATFORM_CONFIG) { 33462aeddbfSDean Luick entry = &table[i]; 33562aeddbfSDean Luick break; 33662aeddbfSDean Luick } 33762aeddbfSDean Luick } 33862aeddbfSDean Luick if (!entry) { 33962aeddbfSDean Luick ret = -ENOENT; 34062aeddbfSDean Luick goto done; 34162aeddbfSDean Luick } 34262aeddbfSDean Luick 34362aeddbfSDean Luick /* 34462aeddbfSDean Luick * Sanity check on the configuration file size - it should never 34562aeddbfSDean Luick * be larger than 4 KiB. 34662aeddbfSDean Luick */ 34762aeddbfSDean Luick if (entry->size > (4 * 1024)) { 34862aeddbfSDean Luick dd_dev_err(dd, "Bad configuration file size 0x%x\n", 34962aeddbfSDean Luick entry->size); 35062aeddbfSDean Luick ret = -EINVAL; 35162aeddbfSDean Luick goto done; 35262aeddbfSDean Luick } 35362aeddbfSDean Luick 35462aeddbfSDean Luick /* check for bogus offset and size that wrap when added together */ 35562aeddbfSDean Luick if (entry->offset + entry->size < entry->offset) { 35662aeddbfSDean Luick dd_dev_err(dd, 35762aeddbfSDean Luick "Bad configuration file start + size 0x%x+0x%x\n", 35862aeddbfSDean Luick entry->offset, entry->size); 35962aeddbfSDean Luick ret = -EINVAL; 36062aeddbfSDean Luick goto done; 36162aeddbfSDean Luick } 36262aeddbfSDean Luick 36362aeddbfSDean Luick /* allocate the buffer to return */ 36462aeddbfSDean Luick buffer = kmalloc(entry->size, GFP_KERNEL); 36562aeddbfSDean Luick if (!buffer) { 36662aeddbfSDean Luick ret = -ENOMEM; 36762aeddbfSDean Luick goto done; 36862aeddbfSDean Luick } 36962aeddbfSDean Luick 37062aeddbfSDean Luick /* 37162aeddbfSDean Luick * Extract the file by looping over segments until it is fully read. 37262aeddbfSDean Luick */ 37362aeddbfSDean Luick seg_offset = entry->offset % SEG_SIZE; 37462aeddbfSDean Luick seg_base = entry->offset - seg_offset; 37562aeddbfSDean Luick ncopied = 0; 37662aeddbfSDean Luick while (ncopied < entry->size) { 37762aeddbfSDean Luick /* calculate data bytes available in this segment */ 37862aeddbfSDean Luick 37962aeddbfSDean Luick /* start with the bytes from the current offset to the end */ 38062aeddbfSDean Luick bytes_available = SEG_SIZE - seg_offset; 38162aeddbfSDean Luick /* subtract off footer and table from segment 0 */ 38262aeddbfSDean Luick if (seg_base == 0) { 38362aeddbfSDean Luick /* 38462aeddbfSDean Luick * Sanity check: should not have a starting point 38562aeddbfSDean Luick * at or within the directory. 38662aeddbfSDean Luick */ 38762aeddbfSDean Luick if (bytes_available <= directory_size) { 38862aeddbfSDean Luick dd_dev_err(dd, 38962aeddbfSDean Luick "Bad configuration file - offset 0x%x within footer+table\n", 39062aeddbfSDean Luick entry->offset); 39162aeddbfSDean Luick ret = -EINVAL; 39262aeddbfSDean Luick goto done; 39362aeddbfSDean Luick } 39462aeddbfSDean Luick bytes_available -= directory_size; 39562aeddbfSDean Luick } 39662aeddbfSDean Luick 39762aeddbfSDean Luick /* calculate bytes wanted */ 39862aeddbfSDean Luick to_copy = entry->size - ncopied; 39962aeddbfSDean Luick 40062aeddbfSDean Luick /* max out at the available bytes in this segment */ 40162aeddbfSDean Luick if (to_copy > bytes_available) 40262aeddbfSDean Luick to_copy = bytes_available; 40362aeddbfSDean Luick 40462aeddbfSDean Luick /* 40562aeddbfSDean Luick * Read from the EPROM. 40662aeddbfSDean Luick * 40762aeddbfSDean Luick * The sanity check for entry->offset is done in read_length(). 40862aeddbfSDean Luick * The EPROM offset is validated against what the hardware 40962aeddbfSDean Luick * addressing supports. In addition, if the offset is larger 41062aeddbfSDean Luick * than the actual EPROM, it silently wraps. It will work 41162aeddbfSDean Luick * fine, though the reader may not get what they expected 41262aeddbfSDean Luick * from the EPROM. 41362aeddbfSDean Luick */ 41462aeddbfSDean Luick ret = read_length(dd, seg_base + seg_offset, to_copy, 41562aeddbfSDean Luick buffer + ncopied); 41662aeddbfSDean Luick if (ret) 41762aeddbfSDean Luick goto done; 41862aeddbfSDean Luick 41962aeddbfSDean Luick ncopied += to_copy; 42062aeddbfSDean Luick 42162aeddbfSDean Luick /* set up for next segment */ 42262aeddbfSDean Luick seg_offset = footer->oprom_size; 42362aeddbfSDean Luick seg_base += SEG_SIZE; 42462aeddbfSDean Luick } 42562aeddbfSDean Luick 42662aeddbfSDean Luick /* success */ 42762aeddbfSDean Luick ret = 0; 42862aeddbfSDean Luick *data = buffer; 42962aeddbfSDean Luick *size = entry->size; 43062aeddbfSDean Luick 43162aeddbfSDean Luick done: 43262aeddbfSDean Luick kfree(table_buffer); 43362aeddbfSDean Luick if (ret) 43462aeddbfSDean Luick kfree(buffer); 43562aeddbfSDean Luick return ret; 43662aeddbfSDean Luick } 43762aeddbfSDean Luick 43862aeddbfSDean Luick /* 439107ffbc5SDean Luick * Read the platform configuration file from the EPROM. 440107ffbc5SDean Luick * 441107ffbc5SDean Luick * On success, an allocated buffer containing the data and its size are 442107ffbc5SDean Luick * returned. It is up to the caller to free this buffer. 443107ffbc5SDean Luick * 444107ffbc5SDean Luick * Return value: 445107ffbc5SDean Luick * 0 - success 446107ffbc5SDean Luick * -ENXIO - no EPROM is available 447107ffbc5SDean Luick * -EBUSY - not able to acquire access to the EPROM 448107ffbc5SDean Luick * -ENOENT - no recognizable file written 449107ffbc5SDean Luick * -ENOMEM - buffer could not be allocated 45062aeddbfSDean Luick * -EINVAL - invalid EPROM contentents found 451107ffbc5SDean Luick */ 452107ffbc5SDean Luick int eprom_read_platform_config(struct hfi1_devdata *dd, void **data, u32 *size) 453107ffbc5SDean Luick { 454107ffbc5SDean Luick u32 directory[EP_PAGE_DWORDS]; /* aligned buffer */ 455107ffbc5SDean Luick int ret; 456107ffbc5SDean Luick 457107ffbc5SDean Luick if (!dd->eprom_available) 458107ffbc5SDean Luick return -ENXIO; 459107ffbc5SDean Luick 460107ffbc5SDean Luick ret = acquire_chip_resource(dd, CR_EPROM, EPROM_TIMEOUT); 461107ffbc5SDean Luick if (ret) 462107ffbc5SDean Luick return -EBUSY; 463107ffbc5SDean Luick 46462aeddbfSDean Luick /* read the last page of the segment for the EPROM format magic */ 46562aeddbfSDean Luick ret = read_length(dd, SEG_SIZE - EP_PAGE_SIZE, EP_PAGE_SIZE, directory); 466107ffbc5SDean Luick if (ret) 467107ffbc5SDean Luick goto done; 468107ffbc5SDean Luick 46962aeddbfSDean Luick /* last dword of the segment contains a magic value */ 47062aeddbfSDean Luick if (directory[EP_PAGE_DWORDS - 1] == FOOTER_MAGIC) { 47162aeddbfSDean Luick /* segment format */ 47262aeddbfSDean Luick ret = read_segment_platform_config(dd, directory, data, size); 47362aeddbfSDean Luick } else { 474107ffbc5SDean Luick /* partition format */ 475107ffbc5SDean Luick ret = read_partition_platform_config(dd, data, size); 476107ffbc5SDean Luick } 477107ffbc5SDean Luick 478107ffbc5SDean Luick done: 479107ffbc5SDean Luick release_chip_resource(dd, CR_EPROM); 480107ffbc5SDean Luick return ret; 481107ffbc5SDean Luick } 482