diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 55 |
1 files changed, 32 insertions, 23 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index ad5002211ab4..6b874dab4120 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -1284,7 +1284,7 @@ static void iwl_nic_start(struct iwl_priv *priv) | |||
1284 | */ | 1284 | */ |
1285 | static int iwl_read_ucode(struct iwl_priv *priv) | 1285 | static int iwl_read_ucode(struct iwl_priv *priv) |
1286 | { | 1286 | { |
1287 | struct iwl_ucode *ucode; | 1287 | struct iwl_ucode_header *ucode; |
1288 | int ret = -EINVAL, index; | 1288 | int ret = -EINVAL, index; |
1289 | const struct firmware *ucode_raw; | 1289 | const struct firmware *ucode_raw; |
1290 | const char *name_pre = priv->cfg->fw_name_pre; | 1290 | const char *name_pre = priv->cfg->fw_name_pre; |
@@ -1293,7 +1293,8 @@ static int iwl_read_ucode(struct iwl_priv *priv) | |||
1293 | char buf[25]; | 1293 | char buf[25]; |
1294 | u8 *src; | 1294 | u8 *src; |
1295 | size_t len; | 1295 | size_t len; |
1296 | u32 api_ver, inst_size, data_size, init_size, init_data_size, boot_size; | 1296 | u32 api_ver, build; |
1297 | u32 inst_size, data_size, init_size, init_data_size, boot_size; | ||
1297 | 1298 | ||
1298 | /* Ask kernel firmware_class module to get the boot firmware off disk. | 1299 | /* Ask kernel firmware_class module to get the boot firmware off disk. |
1299 | * request_firmware() is synchronous, file is in memory on return. */ | 1300 | * request_firmware() is synchronous, file is in memory on return. */ |
@@ -1323,23 +1324,26 @@ static int iwl_read_ucode(struct iwl_priv *priv) | |||
1323 | if (ret < 0) | 1324 | if (ret < 0) |
1324 | goto error; | 1325 | goto error; |
1325 | 1326 | ||
1326 | /* Make sure that we got at least our header! */ | 1327 | /* Make sure that we got at least the v1 header! */ |
1327 | if (ucode_raw->size < sizeof(*ucode)) { | 1328 | if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) { |
1328 | IWL_ERR(priv, "File size way too small!\n"); | 1329 | IWL_ERR(priv, "File size way too small!\n"); |
1329 | ret = -EINVAL; | 1330 | ret = -EINVAL; |
1330 | goto err_release; | 1331 | goto err_release; |
1331 | } | 1332 | } |
1332 | 1333 | ||
1333 | /* Data from ucode file: header followed by uCode images */ | 1334 | /* Data from ucode file: header followed by uCode images */ |
1334 | ucode = (void *)ucode_raw->data; | 1335 | ucode = (struct iwl_ucode_header *)ucode_raw->data; |
1335 | 1336 | ||
1336 | priv->ucode_ver = le32_to_cpu(ucode->ver); | 1337 | priv->ucode_ver = le32_to_cpu(ucode->ver); |
1337 | api_ver = IWL_UCODE_API(priv->ucode_ver); | 1338 | api_ver = IWL_UCODE_API(priv->ucode_ver); |
1338 | inst_size = le32_to_cpu(ucode->inst_size); | 1339 | build = priv->cfg->ops->ucode->get_build(ucode, api_ver); |
1339 | data_size = le32_to_cpu(ucode->data_size); | 1340 | inst_size = priv->cfg->ops->ucode->get_inst_size(ucode, api_ver); |
1340 | init_size = le32_to_cpu(ucode->init_size); | 1341 | data_size = priv->cfg->ops->ucode->get_data_size(ucode, api_ver); |
1341 | init_data_size = le32_to_cpu(ucode->init_data_size); | 1342 | init_size = priv->cfg->ops->ucode->get_init_size(ucode, api_ver); |
1342 | boot_size = le32_to_cpu(ucode->boot_size); | 1343 | init_data_size = |
1344 | priv->cfg->ops->ucode->get_init_data_size(ucode, api_ver); | ||
1345 | boot_size = priv->cfg->ops->ucode->get_boot_size(ucode, api_ver); | ||
1346 | src = priv->cfg->ops->ucode->get_data(ucode, api_ver); | ||
1343 | 1347 | ||
1344 | /* api_ver should match the api version forming part of the | 1348 | /* api_ver should match the api version forming part of the |
1345 | * firmware filename ... but we don't check for that and only rely | 1349 | * firmware filename ... but we don't check for that and only rely |
@@ -1365,6 +1369,9 @@ static int iwl_read_ucode(struct iwl_priv *priv) | |||
1365 | IWL_UCODE_API(priv->ucode_ver), | 1369 | IWL_UCODE_API(priv->ucode_ver), |
1366 | IWL_UCODE_SERIAL(priv->ucode_ver)); | 1370 | IWL_UCODE_SERIAL(priv->ucode_ver)); |
1367 | 1371 | ||
1372 | if (build) | ||
1373 | IWL_DEBUG_INFO(priv, "Build %u\n", build); | ||
1374 | |||
1368 | IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n", | 1375 | IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n", |
1369 | priv->ucode_ver); | 1376 | priv->ucode_ver); |
1370 | IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %u\n", | 1377 | IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %u\n", |
@@ -1379,12 +1386,14 @@ static int iwl_read_ucode(struct iwl_priv *priv) | |||
1379 | boot_size); | 1386 | boot_size); |
1380 | 1387 | ||
1381 | /* Verify size of file vs. image size info in file's header */ | 1388 | /* Verify size of file vs. image size info in file's header */ |
1382 | if (ucode_raw->size < sizeof(*ucode) + | 1389 | if (ucode_raw->size != |
1390 | priv->cfg->ops->ucode->get_header_size(api_ver) + | ||
1383 | inst_size + data_size + init_size + | 1391 | inst_size + data_size + init_size + |
1384 | init_data_size + boot_size) { | 1392 | init_data_size + boot_size) { |
1385 | 1393 | ||
1386 | IWL_DEBUG_INFO(priv, "uCode file size %d too small\n", | 1394 | IWL_DEBUG_INFO(priv, |
1387 | (int)ucode_raw->size); | 1395 | "uCode file size %d does not match expected size\n", |
1396 | (int)ucode_raw->size); | ||
1388 | ret = -EINVAL; | 1397 | ret = -EINVAL; |
1389 | goto err_release; | 1398 | goto err_release; |
1390 | } | 1399 | } |
@@ -1464,42 +1473,42 @@ static int iwl_read_ucode(struct iwl_priv *priv) | |||
1464 | /* Copy images into buffers for card's bus-master reads ... */ | 1473 | /* Copy images into buffers for card's bus-master reads ... */ |
1465 | 1474 | ||
1466 | /* Runtime instructions (first block of data in file) */ | 1475 | /* Runtime instructions (first block of data in file) */ |
1467 | src = &ucode->data[0]; | 1476 | len = inst_size; |
1468 | len = priv->ucode_code.len; | ||
1469 | IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %Zd\n", len); | 1477 | IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %Zd\n", len); |
1470 | memcpy(priv->ucode_code.v_addr, src, len); | 1478 | memcpy(priv->ucode_code.v_addr, src, len); |
1479 | src += len; | ||
1480 | |||
1471 | IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n", | 1481 | IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n", |
1472 | priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr); | 1482 | priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr); |
1473 | 1483 | ||
1474 | /* Runtime data (2nd block) | 1484 | /* Runtime data (2nd block) |
1475 | * NOTE: Copy into backup buffer will be done in iwl_up() */ | 1485 | * NOTE: Copy into backup buffer will be done in iwl_up() */ |
1476 | src = &ucode->data[inst_size]; | 1486 | len = data_size; |
1477 | len = priv->ucode_data.len; | ||
1478 | IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n", len); | 1487 | IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n", len); |
1479 | memcpy(priv->ucode_data.v_addr, src, len); | 1488 | memcpy(priv->ucode_data.v_addr, src, len); |
1480 | memcpy(priv->ucode_data_backup.v_addr, src, len); | 1489 | memcpy(priv->ucode_data_backup.v_addr, src, len); |
1490 | src += len; | ||
1481 | 1491 | ||
1482 | /* Initialization instructions (3rd block) */ | 1492 | /* Initialization instructions (3rd block) */ |
1483 | if (init_size) { | 1493 | if (init_size) { |
1484 | src = &ucode->data[inst_size + data_size]; | 1494 | len = init_size; |
1485 | len = priv->ucode_init.len; | ||
1486 | IWL_DEBUG_INFO(priv, "Copying (but not loading) init instr len %Zd\n", | 1495 | IWL_DEBUG_INFO(priv, "Copying (but not loading) init instr len %Zd\n", |
1487 | len); | 1496 | len); |
1488 | memcpy(priv->ucode_init.v_addr, src, len); | 1497 | memcpy(priv->ucode_init.v_addr, src, len); |
1498 | src += len; | ||
1489 | } | 1499 | } |
1490 | 1500 | ||
1491 | /* Initialization data (4th block) */ | 1501 | /* Initialization data (4th block) */ |
1492 | if (init_data_size) { | 1502 | if (init_data_size) { |
1493 | src = &ucode->data[inst_size + data_size + init_size]; | 1503 | len = init_data_size; |
1494 | len = priv->ucode_init_data.len; | ||
1495 | IWL_DEBUG_INFO(priv, "Copying (but not loading) init data len %Zd\n", | 1504 | IWL_DEBUG_INFO(priv, "Copying (but not loading) init data len %Zd\n", |
1496 | len); | 1505 | len); |
1497 | memcpy(priv->ucode_init_data.v_addr, src, len); | 1506 | memcpy(priv->ucode_init_data.v_addr, src, len); |
1507 | src += len; | ||
1498 | } | 1508 | } |
1499 | 1509 | ||
1500 | /* Bootstrap instructions (5th block) */ | 1510 | /* Bootstrap instructions (5th block) */ |
1501 | src = &ucode->data[inst_size + data_size + init_size + init_data_size]; | 1511 | len = boot_size; |
1502 | len = priv->ucode_boot.len; | ||
1503 | IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n", len); | 1512 | IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n", len); |
1504 | memcpy(priv->ucode_boot.v_addr, src, len); | 1513 | memcpy(priv->ucode_boot.v_addr, src, len); |
1505 | 1514 | ||