0001
0002
0003
0004
0005
0006 #include <linux/delay.h>
0007 #include "hfi.h"
0008 #include "common.h"
0009 #include "eprom.h"
0010
0011
0012
0013
0014
0015
0016
0017 #define P0_SIZE (128 * 1024)
0018 #define P1_SIZE (4 * 1024)
0019 #define P1_START P0_SIZE
0020 #define P2_START (P0_SIZE + P1_SIZE)
0021
0022
0023 #define EP_PAGE_SIZE 256
0024 #define EP_PAGE_MASK (EP_PAGE_SIZE - 1)
0025 #define EP_PAGE_DWORDS (EP_PAGE_SIZE / sizeof(u32))
0026
0027
0028 #define CMD_SHIFT 24
0029 #define CMD_NOP (0)
0030 #define CMD_READ_DATA(addr) ((0x03 << CMD_SHIFT) | addr)
0031 #define CMD_RELEASE_POWERDOWN_NOID ((0xab << CMD_SHIFT))
0032
0033
0034 #define EP_SPEED_FULL 0x2
0035
0036
0037
0038
0039
0040
0041 #define EPROM_TIMEOUT 80000
0042
0043
0044
0045
0046
0047 static void read_page(struct hfi1_devdata *dd, u32 offset, u32 *result)
0048 {
0049 int i;
0050
0051 write_csr(dd, ASIC_EEP_ADDR_CMD, CMD_READ_DATA(offset));
0052 for (i = 0; i < EP_PAGE_DWORDS; i++)
0053 result[i] = (u32)read_csr(dd, ASIC_EEP_DATA);
0054 write_csr(dd, ASIC_EEP_ADDR_CMD, CMD_NOP);
0055 }
0056
0057
0058
0059
0060 static int read_length(struct hfi1_devdata *dd, u32 start, u32 len, void *dest)
0061 {
0062 u32 buffer[EP_PAGE_DWORDS];
0063 u32 end;
0064 u32 start_offset;
0065 u32 read_start;
0066 u32 bytes;
0067
0068 if (len == 0)
0069 return 0;
0070
0071 end = start + len;
0072
0073
0074
0075
0076
0077
0078 if (end > (1 << CMD_SHIFT))
0079 return -EINVAL;
0080
0081
0082 start_offset = start & EP_PAGE_MASK;
0083 if (start_offset) {
0084
0085
0086
0087 read_start = start & ~EP_PAGE_MASK;
0088 read_page(dd, read_start, buffer);
0089
0090
0091 bytes = EP_PAGE_SIZE - start_offset;
0092
0093 if (len <= bytes) {
0094
0095 memcpy(dest, (u8 *)buffer + start_offset, len);
0096 return 0;
0097 }
0098
0099 memcpy(dest, (u8 *)buffer + start_offset, bytes);
0100
0101 start += bytes;
0102 len -= bytes;
0103 dest += bytes;
0104 }
0105
0106
0107
0108 while (len >= EP_PAGE_SIZE) {
0109 read_page(dd, start, buffer);
0110 memcpy(dest, buffer, EP_PAGE_SIZE);
0111
0112 start += EP_PAGE_SIZE;
0113 len -= EP_PAGE_SIZE;
0114 dest += EP_PAGE_SIZE;
0115 }
0116
0117
0118 if (len) {
0119 read_page(dd, start, buffer);
0120 memcpy(dest, buffer, len);
0121 }
0122
0123 return 0;
0124 }
0125
0126
0127
0128
0129 int eprom_init(struct hfi1_devdata *dd)
0130 {
0131 int ret = 0;
0132
0133
0134 if (dd->pcidev->device != PCI_DEVICE_ID_INTEL0)
0135 return 0;
0136
0137
0138
0139
0140
0141 ret = acquire_chip_resource(dd, CR_EPROM, EPROM_TIMEOUT);
0142 if (ret) {
0143 dd_dev_err(dd,
0144 "%s: unable to acquire EPROM resource, no EPROM support\n",
0145 __func__);
0146 goto done_asic;
0147 }
0148
0149
0150
0151
0152 write_csr(dd, ASIC_EEP_CTL_STAT, ASIC_EEP_CTL_STAT_EP_RESET_SMASK);
0153
0154 write_csr(dd, ASIC_EEP_CTL_STAT,
0155 EP_SPEED_FULL << ASIC_EEP_CTL_STAT_RATE_SPI_SHIFT);
0156
0157
0158 write_csr(dd, ASIC_EEP_ADDR_CMD, CMD_RELEASE_POWERDOWN_NOID);
0159
0160 dd->eprom_available = true;
0161 release_chip_resource(dd, CR_EPROM);
0162 done_asic:
0163 return ret;
0164 }
0165
0166
0167 #define IMAGE_START_MAGIC "APO="
0168
0169
0170 #define IMAGE_TRAIL_MAGIC "egamiAPO"
0171
0172
0173 #define HFI1_EFT_PLATFORM_CONFIG 2
0174
0175
0176 #define SEG_SIZE (128 * 1024)
0177
0178 struct hfi1_eprom_footer {
0179 u32 oprom_size;
0180 u16 num_table_entries;
0181 u16 version;
0182 u32 magic;
0183 };
0184
0185 struct hfi1_eprom_table_entry {
0186 u32 type;
0187 u32 offset;
0188 u32 size;
0189 };
0190
0191
0192
0193
0194
0195 #define MAX_TABLE_ENTRIES(dir_size) \
0196 (((dir_size) - sizeof(struct hfi1_eprom_footer)) / \
0197 sizeof(struct hfi1_eprom_table_entry))
0198
0199 #define DIRECTORY_SIZE(n) (sizeof(struct hfi1_eprom_footer) + \
0200 (sizeof(struct hfi1_eprom_table_entry) * (n)))
0201
0202 #define MAGIC4(a, b, c, d) ((d) << 24 | (c) << 16 | (b) << 8 | (a))
0203 #define FOOTER_MAGIC MAGIC4('e', 'p', 'r', 'm')
0204 #define FOOTER_VERSION 1
0205
0206
0207
0208
0209
0210 static int read_partition_platform_config(struct hfi1_devdata *dd, void **data,
0211 u32 *size)
0212 {
0213 void *buffer;
0214 void *p;
0215 u32 length;
0216 int ret;
0217
0218 buffer = kmalloc(P1_SIZE, GFP_KERNEL);
0219 if (!buffer)
0220 return -ENOMEM;
0221
0222 ret = read_length(dd, P1_START, P1_SIZE, buffer);
0223 if (ret) {
0224 kfree(buffer);
0225 return ret;
0226 }
0227
0228
0229 if (memcmp(buffer, IMAGE_START_MAGIC, strlen(IMAGE_START_MAGIC))) {
0230 kfree(buffer);
0231 return -ENOENT;
0232 }
0233
0234
0235 p = strnstr(buffer, IMAGE_TRAIL_MAGIC, P1_SIZE);
0236 if (p)
0237 length = p - buffer;
0238 else
0239 length = P1_SIZE;
0240
0241 *data = buffer;
0242 *size = length;
0243 return 0;
0244 }
0245
0246
0247
0248
0249
0250
0251
0252 static int read_segment_platform_config(struct hfi1_devdata *dd,
0253 void *directory, void **data, u32 *size)
0254 {
0255 struct hfi1_eprom_footer *footer;
0256 struct hfi1_eprom_table_entry *table;
0257 struct hfi1_eprom_table_entry *entry;
0258 void *buffer = NULL;
0259 void *table_buffer = NULL;
0260 int ret, i;
0261 u32 directory_size;
0262 u32 seg_base, seg_offset;
0263 u32 bytes_available, ncopied, to_copy;
0264
0265
0266 footer = (struct hfi1_eprom_footer *)
0267 (directory + EP_PAGE_SIZE - sizeof(*footer));
0268
0269
0270 if (footer->version != FOOTER_VERSION)
0271 return -EINVAL;
0272
0273
0274 if (footer->oprom_size >= SEG_SIZE)
0275 return -EINVAL;
0276
0277
0278 if (footer->num_table_entries >
0279 MAX_TABLE_ENTRIES(SEG_SIZE - footer->oprom_size))
0280 return -EINVAL;
0281
0282
0283 directory_size = DIRECTORY_SIZE(footer->num_table_entries);
0284 if (directory_size <= EP_PAGE_SIZE) {
0285
0286 table = (struct hfi1_eprom_table_entry *)
0287 (directory + EP_PAGE_SIZE - directory_size);
0288 } else {
0289
0290 table_buffer = kmalloc(directory_size, GFP_KERNEL);
0291 if (!table_buffer)
0292 return -ENOMEM;
0293 ret = read_length(dd, SEG_SIZE - directory_size,
0294 directory_size, table_buffer);
0295 if (ret)
0296 goto done;
0297 table = table_buffer;
0298 }
0299
0300
0301 for (entry = NULL, i = 0; i < footer->num_table_entries; i++) {
0302 if (table[i].type == HFI1_EFT_PLATFORM_CONFIG) {
0303 entry = &table[i];
0304 break;
0305 }
0306 }
0307 if (!entry) {
0308 ret = -ENOENT;
0309 goto done;
0310 }
0311
0312
0313
0314
0315
0316 if (entry->size > (4 * 1024)) {
0317 dd_dev_err(dd, "Bad configuration file size 0x%x\n",
0318 entry->size);
0319 ret = -EINVAL;
0320 goto done;
0321 }
0322
0323
0324 if (entry->offset + entry->size < entry->offset) {
0325 dd_dev_err(dd,
0326 "Bad configuration file start + size 0x%x+0x%x\n",
0327 entry->offset, entry->size);
0328 ret = -EINVAL;
0329 goto done;
0330 }
0331
0332
0333 buffer = kmalloc(entry->size, GFP_KERNEL);
0334 if (!buffer) {
0335 ret = -ENOMEM;
0336 goto done;
0337 }
0338
0339
0340
0341
0342 seg_offset = entry->offset % SEG_SIZE;
0343 seg_base = entry->offset - seg_offset;
0344 ncopied = 0;
0345 while (ncopied < entry->size) {
0346
0347
0348
0349 bytes_available = SEG_SIZE - seg_offset;
0350
0351 if (seg_base == 0) {
0352
0353
0354
0355
0356 if (bytes_available <= directory_size) {
0357 dd_dev_err(dd,
0358 "Bad configuration file - offset 0x%x within footer+table\n",
0359 entry->offset);
0360 ret = -EINVAL;
0361 goto done;
0362 }
0363 bytes_available -= directory_size;
0364 }
0365
0366
0367 to_copy = entry->size - ncopied;
0368
0369
0370 if (to_copy > bytes_available)
0371 to_copy = bytes_available;
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382
0383 ret = read_length(dd, seg_base + seg_offset, to_copy,
0384 buffer + ncopied);
0385 if (ret)
0386 goto done;
0387
0388 ncopied += to_copy;
0389
0390
0391 seg_offset = footer->oprom_size;
0392 seg_base += SEG_SIZE;
0393 }
0394
0395
0396 ret = 0;
0397 *data = buffer;
0398 *size = entry->size;
0399
0400 done:
0401 kfree(table_buffer);
0402 if (ret)
0403 kfree(buffer);
0404 return ret;
0405 }
0406
0407
0408
0409
0410
0411
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421 int eprom_read_platform_config(struct hfi1_devdata *dd, void **data, u32 *size)
0422 {
0423 u32 directory[EP_PAGE_DWORDS];
0424 int ret;
0425
0426 if (!dd->eprom_available)
0427 return -ENXIO;
0428
0429 ret = acquire_chip_resource(dd, CR_EPROM, EPROM_TIMEOUT);
0430 if (ret)
0431 return -EBUSY;
0432
0433
0434 ret = read_length(dd, SEG_SIZE - EP_PAGE_SIZE, EP_PAGE_SIZE, directory);
0435 if (ret)
0436 goto done;
0437
0438
0439 if (directory[EP_PAGE_DWORDS - 1] == FOOTER_MAGIC) {
0440
0441 ret = read_segment_platform_config(dd, directory, data, size);
0442 } else {
0443
0444 ret = read_partition_platform_config(dd, data, size);
0445 }
0446
0447 done:
0448 release_chip_resource(dd, CR_EPROM);
0449 return ret;
0450 }