aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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",