aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wimax/i2400m/fw.c
diff options
context:
space:
mode:
authorInaky Perez-Gonzalez <inaky@linux.intel.com>2009-09-09 20:11:57 -0400
committerInaky Perez-Gonzalez <inaky@linux.intel.com>2009-10-19 02:55:58 -0400
commit10607c86e163e3da8bdf58a934da7dd3a68dcb7c (patch)
treeae12d72aec61824697dee9d0b509ef37d02f49e3 /drivers/net/wimax/i2400m/fw.c
parentbfc44187bbaeabf597be6566a24e8fa7d689b984 (diff)
wimax/i2400m: on firmware upload, select BCF header that matches device's request
Devices based on the i2400m emit a "barker" (32 bit unsigned) when they boot. This barker is used to select, in the firmware file image, which header should be used to process the rest of the file. This commit implements said support, completing the series started by previous commits. We modify the i2400m_fw_dnload() firmware loading path by adding a call to i2400m_bcf_hdr_find() [new function], in which the right BCF header [as listed in i2400m->fw_hdrs by i2400m_fw_check()] is located. Then this header is fed to i2400m_dnload_init() and i2400m_dnload_finalize(). The changes to i2400m_dnload_finalize() are smaller than they look; they add the bcf_hdr argument and use that instead of bcf. Likewise in i2400m_dnload_init(). Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
Diffstat (limited to 'drivers/net/wimax/i2400m/fw.c')
-rw-r--r--drivers/net/wimax/i2400m/fw.c111
1 files changed, 92 insertions, 19 deletions
diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c
index 897e0be698c6..84a39c30c3d3 100644
--- a/drivers/net/wimax/i2400m/fw.c
+++ b/drivers/net/wimax/i2400m/fw.c
@@ -665,8 +665,8 @@ static int i2400m_download_chunk(struct i2400m *i2400m, const void *chunk,
665 * Download a BCF file's sections to the device 665 * Download a BCF file's sections to the device
666 * 666 *
667 * @i2400m: device descriptor 667 * @i2400m: device descriptor
668 * @bcf: pointer to firmware data (followed by the payloads). Assumed 668 * @bcf: pointer to firmware data (first header followed by the
669 * verified and consistent. 669 * payloads). Assumed verified and consistent.
670 * @bcf_len: length (in bytes) of the @bcf buffer. 670 * @bcf_len: length (in bytes) of the @bcf buffer.
671 * 671 *
672 * Returns: < 0 errno code on error or the offset to the jump instruction. 672 * Returns: < 0 errno code on error or the offset to the jump instruction.
@@ -756,11 +756,17 @@ unsigned i2400m_boot_is_signed(struct i2400m *i2400m)
756/* 756/*
757 * Do the final steps of uploading firmware 757 * Do the final steps of uploading firmware
758 * 758 *
759 * @bcf_hdr: BCF header we are actually using
760 * @bcf: pointer to the firmware image (which matches the first header
761 * that is followed by the actual payloads).
762 * @offset: [byte] offset into @bcf for the command we need to send.
763 *
759 * Depending on the boot mode (signed vs non-signed), different 764 * Depending on the boot mode (signed vs non-signed), different
760 * actions need to be taken. 765 * actions need to be taken.
761 */ 766 */
762static 767static
763int i2400m_dnload_finalize(struct i2400m *i2400m, 768int i2400m_dnload_finalize(struct i2400m *i2400m,
769 const struct i2400m_bcf_hdr *bcf_hdr,
764 const struct i2400m_bcf_hdr *bcf, size_t offset) 770 const struct i2400m_bcf_hdr *bcf, size_t offset)
765{ 771{
766 int ret = 0; 772 int ret = 0;
@@ -792,12 +798,13 @@ int i2400m_dnload_finalize(struct i2400m *i2400m,
792 cmd_buf = i2400m->bm_cmd_buf; 798 cmd_buf = i2400m->bm_cmd_buf;
793 memcpy(&cmd_buf->cmd, cmd, sizeof(*cmd)); 799 memcpy(&cmd_buf->cmd, cmd, sizeof(*cmd));
794 signature_block_offset = 800 signature_block_offset =
795 sizeof(*bcf) 801 sizeof(*bcf_hdr)
796 + le32_to_cpu(bcf->key_size) * sizeof(u32) 802 + le32_to_cpu(bcf_hdr->key_size) * sizeof(u32)
797 + le32_to_cpu(bcf->exponent_size) * sizeof(u32); 803 + le32_to_cpu(bcf_hdr->exponent_size) * sizeof(u32);
798 signature_block_size = 804 signature_block_size =
799 le32_to_cpu(bcf->modulus_size) * sizeof(u32); 805 le32_to_cpu(bcf_hdr->modulus_size) * sizeof(u32);
800 memcpy(cmd_buf->cmd_pl, (void *) bcf + signature_block_offset, 806 memcpy(cmd_buf->cmd_pl,
807 (void *) bcf_hdr + signature_block_offset,
801 signature_block_size); 808 signature_block_size);
802 ret = i2400m_bm_cmd(i2400m, &cmd_buf->cmd, 809 ret = i2400m_bm_cmd(i2400m, &cmd_buf->cmd,
803 sizeof(cmd_buf->cmd) + signature_block_size, 810 sizeof(cmd_buf->cmd) + signature_block_size,
@@ -1122,14 +1129,15 @@ int i2400m_dnload_init_signed(struct i2400m *i2400m,
1122 * (signed or non-signed). 1129 * (signed or non-signed).
1123 */ 1130 */
1124static 1131static
1125int i2400m_dnload_init(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf) 1132int i2400m_dnload_init(struct i2400m *i2400m,
1133 const struct i2400m_bcf_hdr *bcf_hdr)
1126{ 1134{
1127 int result; 1135 int result;
1128 struct device *dev = i2400m_dev(i2400m); 1136 struct device *dev = i2400m_dev(i2400m);
1129 1137
1130 if (i2400m_boot_is_signed(i2400m)) { 1138 if (i2400m_boot_is_signed(i2400m)) {
1131 d_printf(1, dev, "signed boot\n"); 1139 d_printf(1, dev, "signed boot\n");
1132 result = i2400m_dnload_init_signed(i2400m, bcf); 1140 result = i2400m_dnload_init_signed(i2400m, bcf_hdr);
1133 if (result == -ERESTARTSYS) 1141 if (result == -ERESTARTSYS)
1134 return result; 1142 return result;
1135 if (result < 0) 1143 if (result < 0)
@@ -1182,15 +1190,15 @@ int i2400m_fw_hdr_check(struct i2400m *i2400m,
1182 date = le32_to_cpu(bcf_hdr->date); 1190 date = le32_to_cpu(bcf_hdr->date);
1183 size = sizeof(u32) * le32_to_cpu(bcf_hdr->size); 1191 size = sizeof(u32) * le32_to_cpu(bcf_hdr->size);
1184 1192
1185 d_printf(1, dev, "firmware %s #%d@%08x: BCF header " 1193 d_printf(1, dev, "firmware %s #%zd@%08zx: BCF header "
1186 "type:vendor:id 0x%x:%x:%x v%u.%u (%zu/%zu B) built %08x\n", 1194 "type:vendor:id 0x%x:%x:%x v%u.%u (%u/%u B) built %08x\n",
1187 i2400m->fw_name, index, offset, 1195 i2400m->fw_name, index, offset,
1188 module_type, module_vendor, module_id, 1196 module_type, module_vendor, module_id,
1189 major_version, minor_version, header_len, size, date); 1197 major_version, minor_version, header_len, size, date);
1190 1198
1191 /* Hard errors */ 1199 /* Hard errors */
1192 if (major_version != 1) { 1200 if (major_version != 1) {
1193 dev_err(dev, "firmware %s #%d@%08x: major header version " 1201 dev_err(dev, "firmware %s #%zd@%08zx: major header version "
1194 "v%u.%u not supported\n", 1202 "v%u.%u not supported\n",
1195 i2400m->fw_name, index, offset, 1203 i2400m->fw_name, index, offset,
1196 major_version, minor_version); 1204 major_version, minor_version);
@@ -1198,7 +1206,7 @@ int i2400m_fw_hdr_check(struct i2400m *i2400m,
1198 } 1206 }
1199 1207
1200 if (module_type != 6) { /* built for the right hardware? */ 1208 if (module_type != 6) { /* built for the right hardware? */
1201 dev_err(dev, "firmware %s #%d@%08x: unexpected module " 1209 dev_err(dev, "firmware %s #%zd@%08zx: unexpected module "
1202 "type 0x%x; aborting\n", 1210 "type 0x%x; aborting\n",
1203 i2400m->fw_name, index, offset, 1211 i2400m->fw_name, index, offset,
1204 module_type); 1212 module_type);
@@ -1206,14 +1214,14 @@ int i2400m_fw_hdr_check(struct i2400m *i2400m,
1206 } 1214 }
1207 1215
1208 if (module_vendor != 0x8086) { 1216 if (module_vendor != 0x8086) {
1209 dev_err(dev, "firmware %s #%d@%08x: unexpected module " 1217 dev_err(dev, "firmware %s #%zd@%08zx: unexpected module "
1210 "vendor 0x%x; aborting\n", 1218 "vendor 0x%x; aborting\n",
1211 i2400m->fw_name, index, offset, module_vendor); 1219 i2400m->fw_name, index, offset, module_vendor);
1212 return -EBADF; 1220 return -EBADF;
1213 } 1221 }
1214 1222
1215 if (date < 0x20080300) 1223 if (date < 0x20080300)
1216 dev_warn(dev, "firmware %s #%d@%08x: build date %08x " 1224 dev_warn(dev, "firmware %s #%zd@%08zx: build date %08x "
1217 "too old; unsupported\n", 1225 "too old; unsupported\n",
1218 i2400m->fw_name, index, offset, date); 1226 i2400m->fw_name, index, offset, date);
1219 return 0; 1227 return 0;
@@ -1239,7 +1247,7 @@ int i2400m_fw_check(struct i2400m *i2400m, const void *bcf, size_t bcf_size)
1239 size_t headers = 0; 1247 size_t headers = 0;
1240 const struct i2400m_bcf_hdr *bcf_hdr; 1248 const struct i2400m_bcf_hdr *bcf_hdr;
1241 const void *itr, *next, *top; 1249 const void *itr, *next, *top;
1242 unsigned slots = 0, used_slots = 0; 1250 size_t slots = 0, used_slots = 0;
1243 1251
1244 for (itr = bcf, top = itr + bcf_size; 1252 for (itr = bcf, top = itr + bcf_size;
1245 itr < top; 1253 itr < top;
@@ -1249,7 +1257,7 @@ int i2400m_fw_check(struct i2400m *i2400m, const void *bcf, size_t bcf_size)
1249 leftover = top - itr; 1257 leftover = top - itr;
1250 offset = itr - (const void *) bcf; 1258 offset = itr - (const void *) bcf;
1251 if (leftover <= sizeof(*bcf_hdr)) { 1259 if (leftover <= sizeof(*bcf_hdr)) {
1252 dev_err(dev, "firmware %s: %zu B left at @%x, " 1260 dev_err(dev, "firmware %s: %zu B left at @%zx, "
1253 "not enough for BCF header\n", 1261 "not enough for BCF header\n",
1254 i2400m->fw_name, leftover, offset); 1262 i2400m->fw_name, leftover, offset);
1255 break; 1263 break;
@@ -1293,6 +1301,60 @@ error_zrealloc:
1293 1301
1294 1302
1295/* 1303/*
1304 * Match a barker to a BCF header module ID
1305 *
1306 * The device sends a barker which tells the firmware loader which
1307 * header in the BCF file has to be used. This does the matching.
1308 */
1309static
1310unsigned i2400m_bcf_hdr_match(struct i2400m *i2400m,
1311 const struct i2400m_bcf_hdr *bcf_hdr)
1312{
1313 u32 barker = le32_to_cpu(i2400m->barker->data[0])
1314 & 0x7fffffff;
1315 u32 module_id = le32_to_cpu(bcf_hdr->module_id)
1316 & 0x7fffffff; /* high bit used for something else */
1317
1318 /* special case for 5x50 */
1319 if (barker == I2400M_SBOOT_BARKER && module_id == 0)
1320 return 1;
1321 if (module_id == barker)
1322 return 1;
1323 return 0;
1324}
1325
1326static
1327const struct i2400m_bcf_hdr *i2400m_bcf_hdr_find(struct i2400m *i2400m)
1328{
1329 struct device *dev = i2400m_dev(i2400m);
1330 const struct i2400m_bcf_hdr **bcf_itr, *bcf_hdr;
1331 unsigned i = 0;
1332 u32 barker = le32_to_cpu(i2400m->barker->data[0]);
1333
1334 d_printf(2, dev, "finding BCF header for barker %08x\n", barker);
1335 if (barker == I2400M_NBOOT_BARKER) {
1336 bcf_hdr = i2400m->fw_hdrs[0];
1337 d_printf(1, dev, "using BCF header #%u/%08x for non-signed "
1338 "barker\n", 0, le32_to_cpu(bcf_hdr->module_id));
1339 return bcf_hdr;
1340 }
1341 for (bcf_itr = i2400m->fw_hdrs; *bcf_itr != NULL; bcf_itr++, i++) {
1342 bcf_hdr = *bcf_itr;
1343 if (i2400m_bcf_hdr_match(i2400m, bcf_hdr)) {
1344 d_printf(1, dev, "hit on BCF hdr #%u/%08x\n",
1345 i, le32_to_cpu(bcf_hdr->module_id));
1346 return bcf_hdr;
1347 } else
1348 d_printf(1, dev, "miss on BCF hdr #%u/%08x\n",
1349 i, le32_to_cpu(bcf_hdr->module_id));
1350 }
1351 dev_err(dev, "cannot find a matching BCF header for barker %08x\n",
1352 barker);
1353 return NULL;
1354}
1355
1356
1357/*
1296 * Download the firmware to the device 1358 * Download the firmware to the device
1297 * 1359 *
1298 * @i2400m: device descriptor 1360 * @i2400m: device descriptor
@@ -1313,6 +1375,7 @@ int i2400m_fw_dnload(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf,
1313 int ret = 0; 1375 int ret = 0;
1314 struct device *dev = i2400m_dev(i2400m); 1376 struct device *dev = i2400m_dev(i2400m);
1315 int count = i2400m->bus_bm_retries; 1377 int count = i2400m->bus_bm_retries;
1378 const struct i2400m_bcf_hdr *bcf_hdr;
1316 1379
1317 d_fnstart(5, dev, "(i2400m %p bcf %p size %zu)\n", 1380 d_fnstart(5, dev, "(i2400m %p bcf %p size %zu)\n",
1318 i2400m, bcf, bcf_size); 1381 i2400m, bcf, bcf_size);
@@ -1337,8 +1400,17 @@ hw_reboot:
1337 * Initialize the download, push the bytes to the device and 1400 * Initialize the download, push the bytes to the device and
1338 * then jump to the new firmware. Note @ret is passed with the 1401 * then jump to the new firmware. Note @ret is passed with the
1339 * offset of the jump instruction to _dnload_finalize() 1402 * offset of the jump instruction to _dnload_finalize()
1403 *
1404 * Note we need to use the BCF header in the firmware image
1405 * that matches the barker that the device sent when it
1406 * rebooted, so it has to be passed along.
1340 */ 1407 */
1341 ret = i2400m_dnload_init(i2400m, bcf); /* Init device's dnload */ 1408 ret = -EBADF;
1409 bcf_hdr = i2400m_bcf_hdr_find(i2400m);
1410 if (bcf_hdr == NULL)
1411 goto error_bcf_hdr_find;
1412
1413 ret = i2400m_dnload_init(i2400m, bcf_hdr);
1342 if (ret == -ERESTARTSYS) 1414 if (ret == -ERESTARTSYS)
1343 goto error_dev_rebooted; 1415 goto error_dev_rebooted;
1344 if (ret < 0) 1416 if (ret < 0)
@@ -1353,7 +1425,7 @@ hw_reboot:
1353 goto error_dnload_bcf; 1425 goto error_dnload_bcf;
1354 } 1426 }
1355 1427
1356 ret = i2400m_dnload_finalize(i2400m, bcf, ret); 1428 ret = i2400m_dnload_finalize(i2400m, bcf_hdr, bcf, ret);
1357 if (ret == -ERESTARTSYS) 1429 if (ret == -ERESTARTSYS)
1358 goto error_dev_rebooted; 1430 goto error_dev_rebooted;
1359 if (ret < 0) { 1431 if (ret < 0) {
@@ -1370,6 +1442,7 @@ hw_reboot:
1370error_dnload_finalize: 1442error_dnload_finalize:
1371error_dnload_bcf: 1443error_dnload_bcf:
1372error_dnload_init: 1444error_dnload_init:
1445error_bcf_hdr_find:
1373error_bootrom_init: 1446error_bootrom_init:
1374error_too_many_reboots: 1447error_too_many_reboots:
1375 d_fnend(5, dev, "(i2400m %p bcf %p size %zu) = %d\n", 1448 d_fnend(5, dev, "(i2400m %p bcf %p size %zu) = %d\n",