451 lines · c
1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause2/*3 * Copyright(c) 2015, 2016 Intel Corporation.4 */5 6#include <linux/delay.h>7#include "hfi.h"8#include "common.h"9#include "eprom.h"10 11/*12 * The EPROM is logically divided into three partitions:13 * partition 0: the first 128K, visible from PCI ROM BAR14 * partition 1: 4K config file (sector size)15 * partition 2: the rest16 */17#define P0_SIZE (128 * 1024)18#define P1_SIZE (4 * 1024)19#define P1_START P0_SIZE20#define P2_START (P0_SIZE + P1_SIZE)21 22/* controller page size, in bytes */23#define EP_PAGE_SIZE 25624#define EP_PAGE_MASK (EP_PAGE_SIZE - 1)25#define EP_PAGE_DWORDS (EP_PAGE_SIZE / sizeof(u32))26 27/* controller commands */28#define CMD_SHIFT 2429#define CMD_NOP (0)30#define CMD_READ_DATA(addr) ((0x03 << CMD_SHIFT) | addr)31#define CMD_RELEASE_POWERDOWN_NOID ((0xab << CMD_SHIFT))32 33/* controller interface speeds */34#define EP_SPEED_FULL 0x2 /* full speed */35 36/*37 * How long to wait for the EPROM to become available, in ms.38 * The spec 32 Mb EPROM takes around 40s to erase then write.39 * Double it for safety.40 */41#define EPROM_TIMEOUT 80000 /* ms */42 43/*44 * Read a 256 byte (64 dword) EPROM page.45 * All callers have verified the offset is at a page boundary.46 */47static void read_page(struct hfi1_devdata *dd, u32 offset, u32 *result)48{49 int i;50 51 write_csr(dd, ASIC_EEP_ADDR_CMD, CMD_READ_DATA(offset));52 for (i = 0; i < EP_PAGE_DWORDS; i++)53 result[i] = (u32)read_csr(dd, ASIC_EEP_DATA);54 write_csr(dd, ASIC_EEP_ADDR_CMD, CMD_NOP); /* close open page */55}56 57/*58 * Read length bytes starting at offset from the start of the EPROM.59 */60static int read_length(struct hfi1_devdata *dd, u32 start, u32 len, void *dest)61{62 u32 buffer[EP_PAGE_DWORDS];63 u32 end;64 u32 start_offset;65 u32 read_start;66 u32 bytes;67 68 if (len == 0)69 return 0;70 71 end = start + len;72 73 /*74 * Make sure the read range is not outside of the controller read75 * command address range. Note that '>' is correct below - the end76 * of the range is OK if it stops at the limit, but no higher.77 */78 if (end > (1 << CMD_SHIFT))79 return -EINVAL;80 81 /* read the first partial page */82 start_offset = start & EP_PAGE_MASK;83 if (start_offset) {84 /* partial starting page */85 86 /* align and read the page that contains the start */87 read_start = start & ~EP_PAGE_MASK;88 read_page(dd, read_start, buffer);89 90 /* the rest of the page is available data */91 bytes = EP_PAGE_SIZE - start_offset;92 93 if (len <= bytes) {94 /* end is within this page */95 memcpy(dest, (u8 *)buffer + start_offset, len);96 return 0;97 }98 99 memcpy(dest, (u8 *)buffer + start_offset, bytes);100 101 start += bytes;102 len -= bytes;103 dest += bytes;104 }105 /* start is now page aligned */106 107 /* read whole pages */108 while (len >= EP_PAGE_SIZE) {109 read_page(dd, start, buffer);110 memcpy(dest, buffer, EP_PAGE_SIZE);111 112 start += EP_PAGE_SIZE;113 len -= EP_PAGE_SIZE;114 dest += EP_PAGE_SIZE;115 }116 117 /* read the last partial page */118 if (len) {119 read_page(dd, start, buffer);120 memcpy(dest, buffer, len);121 }122 123 return 0;124}125 126/*127 * Initialize the EPROM handler.128 */129int eprom_init(struct hfi1_devdata *dd)130{131 int ret = 0;132 133 /* only the discrete chip has an EPROM */134 if (dd->pcidev->device != PCI_DEVICE_ID_INTEL0)135 return 0;136 137 /*138 * It is OK if both HFIs reset the EPROM as long as they don't139 * do it at the same time.140 */141 ret = acquire_chip_resource(dd, CR_EPROM, EPROM_TIMEOUT);142 if (ret) {143 dd_dev_err(dd,144 "%s: unable to acquire EPROM resource, no EPROM support\n",145 __func__);146 goto done_asic;147 }148 149 /* reset EPROM to be sure it is in a good state */150 151 /* set reset */152 write_csr(dd, ASIC_EEP_CTL_STAT, ASIC_EEP_CTL_STAT_EP_RESET_SMASK);153 /* clear reset, set speed */154 write_csr(dd, ASIC_EEP_CTL_STAT,155 EP_SPEED_FULL << ASIC_EEP_CTL_STAT_RATE_SPI_SHIFT);156 157 /* wake the device with command "release powerdown NoID" */158 write_csr(dd, ASIC_EEP_ADDR_CMD, CMD_RELEASE_POWERDOWN_NOID);159 160 dd->eprom_available = true;161 release_chip_resource(dd, CR_EPROM);162done_asic:163 return ret;164}165 166/* magic character sequence that begins an image */167#define IMAGE_START_MAGIC "APO="168 169/* magic character sequence that might trail an image */170#define IMAGE_TRAIL_MAGIC "egamiAPO"171 172/* EPROM file types */173#define HFI1_EFT_PLATFORM_CONFIG 2174 175/* segment size - 128 KiB */176#define SEG_SIZE (128 * 1024)177 178struct hfi1_eprom_footer {179 u32 oprom_size; /* size of the oprom, in bytes */180 u16 num_table_entries;181 u16 version; /* version of this footer */182 u32 magic; /* must be last */183};184 185struct hfi1_eprom_table_entry {186 u32 type; /* file type */187 u32 offset; /* file offset from start of EPROM */188 u32 size; /* file size, in bytes */189};190 191/*192 * Calculate the max number of table entries that will fit within a directory193 * buffer of size 'dir_size'.194 */195#define MAX_TABLE_ENTRIES(dir_size) \196 (((dir_size) - sizeof(struct hfi1_eprom_footer)) / \197 sizeof(struct hfi1_eprom_table_entry))198 199#define DIRECTORY_SIZE(n) (sizeof(struct hfi1_eprom_footer) + \200 (sizeof(struct hfi1_eprom_table_entry) * (n)))201 202#define MAGIC4(a, b, c, d) ((d) << 24 | (c) << 16 | (b) << 8 | (a))203#define FOOTER_MAGIC MAGIC4('e', 'p', 'r', 'm')204#define FOOTER_VERSION 1205 206/*207 * Read all of partition 1. The actual file is at the front. Adjust208 * the returned size if a trailing image magic is found.209 */210static int read_partition_platform_config(struct hfi1_devdata *dd, void **data,211 u32 *size)212{213 void *buffer;214 void *p;215 u32 length;216 int ret;217 218 buffer = kmalloc(P1_SIZE, GFP_KERNEL);219 if (!buffer)220 return -ENOMEM;221 222 ret = read_length(dd, P1_START, P1_SIZE, buffer);223 if (ret) {224 kfree(buffer);225 return ret;226 }227 228 /* config partition is valid only if it starts with IMAGE_START_MAGIC */229 if (memcmp(buffer, IMAGE_START_MAGIC, strlen(IMAGE_START_MAGIC))) {230 kfree(buffer);231 return -ENOENT;232 }233 234 /* scan for image magic that may trail the actual data */235 p = strnstr(buffer, IMAGE_TRAIL_MAGIC, P1_SIZE);236 if (p)237 length = p - buffer;238 else239 length = P1_SIZE;240 241 *data = buffer;242 *size = length;243 return 0;244}245 246/*247 * The segment magic has been checked. There is a footer and table of248 * contents present.249 *250 * directory is a u32 aligned buffer of size EP_PAGE_SIZE.251 */252static int read_segment_platform_config(struct hfi1_devdata *dd,253 void *directory, void **data, u32 *size)254{255 struct hfi1_eprom_footer *footer;256 struct hfi1_eprom_table_entry *table;257 struct hfi1_eprom_table_entry *entry;258 void *buffer = NULL;259 void *table_buffer = NULL;260 int ret, i;261 u32 directory_size;262 u32 seg_base, seg_offset;263 u32 bytes_available, ncopied, to_copy;264 265 /* the footer is at the end of the directory */266 footer = (struct hfi1_eprom_footer *)267 (directory + EP_PAGE_SIZE - sizeof(*footer));268 269 /* make sure the structure version is supported */270 if (footer->version != FOOTER_VERSION)271 return -EINVAL;272 273 /* oprom size cannot be larger than a segment */274 if (footer->oprom_size >= SEG_SIZE)275 return -EINVAL;276 277 /* the file table must fit in a segment with the oprom */278 if (footer->num_table_entries >279 MAX_TABLE_ENTRIES(SEG_SIZE - footer->oprom_size))280 return -EINVAL;281 282 /* find the file table start, which precedes the footer */283 directory_size = DIRECTORY_SIZE(footer->num_table_entries);284 if (directory_size <= EP_PAGE_SIZE) {285 /* the file table fits into the directory buffer handed in */286 table = (struct hfi1_eprom_table_entry *)287 (directory + EP_PAGE_SIZE - directory_size);288 } else {289 /* need to allocate and read more */290 table_buffer = kmalloc(directory_size, GFP_KERNEL);291 if (!table_buffer)292 return -ENOMEM;293 ret = read_length(dd, SEG_SIZE - directory_size,294 directory_size, table_buffer);295 if (ret)296 goto done;297 table = table_buffer;298 }299 300 /* look for the platform configuration file in the table */301 for (entry = NULL, i = 0; i < footer->num_table_entries; i++) {302 if (table[i].type == HFI1_EFT_PLATFORM_CONFIG) {303 entry = &table[i];304 break;305 }306 }307 if (!entry) {308 ret = -ENOENT;309 goto done;310 }311 312 /*313 * Sanity check on the configuration file size - it should never314 * be larger than 4 KiB.315 */316 if (entry->size > (4 * 1024)) {317 dd_dev_err(dd, "Bad configuration file size 0x%x\n",318 entry->size);319 ret = -EINVAL;320 goto done;321 }322 323 /* check for bogus offset and size that wrap when added together */324 if (entry->offset + entry->size < entry->offset) {325 dd_dev_err(dd,326 "Bad configuration file start + size 0x%x+0x%x\n",327 entry->offset, entry->size);328 ret = -EINVAL;329 goto done;330 }331 332 /* allocate the buffer to return */333 buffer = kmalloc(entry->size, GFP_KERNEL);334 if (!buffer) {335 ret = -ENOMEM;336 goto done;337 }338 339 /*340 * Extract the file by looping over segments until it is fully read.341 */342 seg_offset = entry->offset % SEG_SIZE;343 seg_base = entry->offset - seg_offset;344 ncopied = 0;345 while (ncopied < entry->size) {346 /* calculate data bytes available in this segment */347 348 /* start with the bytes from the current offset to the end */349 bytes_available = SEG_SIZE - seg_offset;350 /* subtract off footer and table from segment 0 */351 if (seg_base == 0) {352 /*353 * Sanity check: should not have a starting point354 * at or within the directory.355 */356 if (bytes_available <= directory_size) {357 dd_dev_err(dd,358 "Bad configuration file - offset 0x%x within footer+table\n",359 entry->offset);360 ret = -EINVAL;361 goto done;362 }363 bytes_available -= directory_size;364 }365 366 /* calculate bytes wanted */367 to_copy = entry->size - ncopied;368 369 /* max out at the available bytes in this segment */370 if (to_copy > bytes_available)371 to_copy = bytes_available;372 373 /*374 * Read from the EPROM.375 *376 * The sanity check for entry->offset is done in read_length().377 * The EPROM offset is validated against what the hardware378 * addressing supports. In addition, if the offset is larger379 * than the actual EPROM, it silently wraps. It will work380 * fine, though the reader may not get what they expected381 * from the EPROM.382 */383 ret = read_length(dd, seg_base + seg_offset, to_copy,384 buffer + ncopied);385 if (ret)386 goto done;387 388 ncopied += to_copy;389 390 /* set up for next segment */391 seg_offset = footer->oprom_size;392 seg_base += SEG_SIZE;393 }394 395 /* success */396 ret = 0;397 *data = buffer;398 *size = entry->size;399 400done:401 kfree(table_buffer);402 if (ret)403 kfree(buffer);404 return ret;405}406 407/*408 * Read the platform configuration file from the EPROM.409 *410 * On success, an allocated buffer containing the data and its size are411 * returned. It is up to the caller to free this buffer.412 *413 * Return value:414 * 0 - success415 * -ENXIO - no EPROM is available416 * -EBUSY - not able to acquire access to the EPROM417 * -ENOENT - no recognizable file written418 * -ENOMEM - buffer could not be allocated419 * -EINVAL - invalid EPROM contentents found420 */421int eprom_read_platform_config(struct hfi1_devdata *dd, void **data, u32 *size)422{423 u32 directory[EP_PAGE_DWORDS]; /* aligned buffer */424 int ret;425 426 if (!dd->eprom_available)427 return -ENXIO;428 429 ret = acquire_chip_resource(dd, CR_EPROM, EPROM_TIMEOUT);430 if (ret)431 return -EBUSY;432 433 /* read the last page of the segment for the EPROM format magic */434 ret = read_length(dd, SEG_SIZE - EP_PAGE_SIZE, EP_PAGE_SIZE, directory);435 if (ret)436 goto done;437 438 /* last dword of the segment contains a magic value */439 if (directory[EP_PAGE_DWORDS - 1] == FOOTER_MAGIC) {440 /* segment format */441 ret = read_segment_platform_config(dd, directory, data, size);442 } else {443 /* partition format */444 ret = read_partition_platform_config(dd, data, size);445 }446 447done:448 release_chip_resource(dd, CR_EPROM);449 return ret;450}451