aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Sternberg <jay.e.sternberg@intel.com>2009-07-17 12:30:16 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-07-24 15:05:24 -0400
commitcc0f555d511a5fe9d4519334c8f674a1dbab9e3a (patch)
tree33308c826deaf26796112df7ffb983b67146bb7f
parent244294e83f7637e31bbf64060301904860a32051 (diff)
iwlwifi: Handle new firmware file with ucode build number in header
Adding new API version to account for change to ucode file format. New header includes the build number of the ucode. This build number is the SVN revision thus allowing for exact correlation to the code that generated it. The header adds the build number so that older ucode images can also be enhanced to include the build in the future. some cleanup in iwl_read_ucode needed to ensure old header not used and reduce unnecessary references through pointer with the data is already in heap variable. Signed-off-by: Jay Sternberg <jay.e.sternberg@intel.com> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c40
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c39
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c51
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c55
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h12
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h31
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c45
8 files changed, 224 insertions, 54 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 1227ed2960fb..14a47c0a1583 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -2786,11 +2786,50 @@ static int iwl3945_load_bsm(struct iwl_priv *priv)
2786 return 0; 2786 return 0;
2787} 2787}
2788 2788
2789#define IWL3945_UCODE_GET(item) \
2790static u32 iwl3945_ucode_get_##item(const struct iwl_ucode_header *ucode,\
2791 u32 api_ver) \
2792{ \
2793 return le32_to_cpu(ucode->u.v1.item); \
2794}
2795
2796static u32 iwl3945_ucode_get_header_size(u32 api_ver)
2797{
2798 return UCODE_HEADER_SIZE(1);
2799}
2800static u32 iwl3945_ucode_get_build(const struct iwl_ucode_header *ucode,
2801 u32 api_ver)
2802{
2803 return 0;
2804}
2805static u8 *iwl3945_ucode_get_data(const struct iwl_ucode_header *ucode,
2806 u32 api_ver)
2807{
2808 return (u8 *) ucode->u.v1.data;
2809}
2810
2811IWL3945_UCODE_GET(inst_size);
2812IWL3945_UCODE_GET(data_size);
2813IWL3945_UCODE_GET(init_size);
2814IWL3945_UCODE_GET(init_data_size);
2815IWL3945_UCODE_GET(boot_size);
2816
2789static struct iwl_hcmd_ops iwl3945_hcmd = { 2817static struct iwl_hcmd_ops iwl3945_hcmd = {
2790 .rxon_assoc = iwl3945_send_rxon_assoc, 2818 .rxon_assoc = iwl3945_send_rxon_assoc,
2791 .commit_rxon = iwl3945_commit_rxon, 2819 .commit_rxon = iwl3945_commit_rxon,
2792}; 2820};
2793 2821
2822static struct iwl_ucode_ops iwl3945_ucode = {
2823 .get_header_size = iwl3945_ucode_get_header_size,
2824 .get_build = iwl3945_ucode_get_build,
2825 .get_inst_size = iwl3945_ucode_get_inst_size,
2826 .get_data_size = iwl3945_ucode_get_data_size,
2827 .get_init_size = iwl3945_ucode_get_init_size,
2828 .get_init_data_size = iwl3945_ucode_get_init_data_size,
2829 .get_boot_size = iwl3945_ucode_get_boot_size,
2830 .get_data = iwl3945_ucode_get_data,
2831};
2832
2794static struct iwl_lib_ops iwl3945_lib = { 2833static struct iwl_lib_ops iwl3945_lib = {
2795 .txq_attach_buf_to_tfd = iwl3945_hw_txq_attach_buf_to_tfd, 2834 .txq_attach_buf_to_tfd = iwl3945_hw_txq_attach_buf_to_tfd,
2796 .txq_free_tfd = iwl3945_hw_txq_free_tfd, 2835 .txq_free_tfd = iwl3945_hw_txq_free_tfd,
@@ -2831,6 +2870,7 @@ static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
2831}; 2870};
2832 2871
2833static struct iwl_ops iwl3945_ops = { 2872static struct iwl_ops iwl3945_ops = {
2873 .ucode = &iwl3945_ucode,
2834 .lib = &iwl3945_lib, 2874 .lib = &iwl3945_lib,
2835 .hcmd = &iwl3945_hcmd, 2875 .hcmd = &iwl3945_hcmd,
2836 .utils = &iwl3945_hcmd_utils, 2876 .utils = &iwl3945_hcmd_utils,
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index edbb0bfd8cb7..f4eb683aa2d5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -2221,12 +2221,50 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv)
2221 cancel_work_sync(&priv->txpower_work); 2221 cancel_work_sync(&priv->txpower_work);
2222} 2222}
2223 2223
2224#define IWL4965_UCODE_GET(item) \
2225static u32 iwl4965_ucode_get_##item(const struct iwl_ucode_header *ucode,\
2226 u32 api_ver) \
2227{ \
2228 return le32_to_cpu(ucode->u.v1.item); \
2229}
2230
2231static u32 iwl4965_ucode_get_header_size(u32 api_ver)
2232{
2233 return UCODE_HEADER_SIZE(1);
2234}
2235static u32 iwl4965_ucode_get_build(const struct iwl_ucode_header *ucode,
2236 u32 api_ver)
2237{
2238 return 0;
2239}
2240static u8 *iwl4965_ucode_get_data(const struct iwl_ucode_header *ucode,
2241 u32 api_ver)
2242{
2243 return (u8 *) ucode->u.v1.data;
2244}
2245
2246IWL4965_UCODE_GET(inst_size);
2247IWL4965_UCODE_GET(data_size);
2248IWL4965_UCODE_GET(init_size);
2249IWL4965_UCODE_GET(init_data_size);
2250IWL4965_UCODE_GET(boot_size);
2251
2224static struct iwl_hcmd_ops iwl4965_hcmd = { 2252static struct iwl_hcmd_ops iwl4965_hcmd = {
2225 .rxon_assoc = iwl4965_send_rxon_assoc, 2253 .rxon_assoc = iwl4965_send_rxon_assoc,
2226 .commit_rxon = iwl_commit_rxon, 2254 .commit_rxon = iwl_commit_rxon,
2227 .set_rxon_chain = iwl_set_rxon_chain, 2255 .set_rxon_chain = iwl_set_rxon_chain,
2228}; 2256};
2229 2257
2258static struct iwl_ucode_ops iwl4965_ucode = {
2259 .get_header_size = iwl4965_ucode_get_header_size,
2260 .get_build = iwl4965_ucode_get_build,
2261 .get_inst_size = iwl4965_ucode_get_inst_size,
2262 .get_data_size = iwl4965_ucode_get_data_size,
2263 .get_init_size = iwl4965_ucode_get_init_size,
2264 .get_init_data_size = iwl4965_ucode_get_init_data_size,
2265 .get_boot_size = iwl4965_ucode_get_boot_size,
2266 .get_data = iwl4965_ucode_get_data,
2267};
2230static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { 2268static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
2231 .get_hcmd_size = iwl4965_get_hcmd_size, 2269 .get_hcmd_size = iwl4965_get_hcmd_size,
2232 .build_addsta_hcmd = iwl4965_build_addsta_hcmd, 2270 .build_addsta_hcmd = iwl4965_build_addsta_hcmd,
@@ -2287,6 +2325,7 @@ static struct iwl_lib_ops iwl4965_lib = {
2287}; 2325};
2288 2326
2289static struct iwl_ops iwl4965_ops = { 2327static struct iwl_ops iwl4965_ops = {
2328 .ucode = &iwl4965_ucode,
2290 .lib = &iwl4965_lib, 2329 .lib = &iwl4965_lib,
2291 .hcmd = &iwl4965_hcmd, 2330 .hcmd = &iwl4965_hcmd,
2292 .utils = &iwl4965_hcmd_utils, 2331 .utils = &iwl4965_hcmd_utils,
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index 3f9da6e47108..74103cfcaceb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -1456,6 +1456,44 @@ int iwl5000_calc_rssi(struct iwl_priv *priv,
1456 return max_rssi - agc - IWL49_RSSI_OFFSET; 1456 return max_rssi - agc - IWL49_RSSI_OFFSET;
1457} 1457}
1458 1458
1459#define IWL5000_UCODE_GET(item) \
1460static u32 iwl5000_ucode_get_##item(const struct iwl_ucode_header *ucode,\
1461 u32 api_ver) \
1462{ \
1463 if (api_ver <= 2) \
1464 return le32_to_cpu(ucode->u.v1.item); \
1465 return le32_to_cpu(ucode->u.v2.item); \
1466}
1467
1468static u32 iwl5000_ucode_get_header_size(u32 api_ver)
1469{
1470 if (api_ver <= 2)
1471 return UCODE_HEADER_SIZE(1);
1472 return UCODE_HEADER_SIZE(2);
1473}
1474
1475static u32 iwl5000_ucode_get_build(const struct iwl_ucode_header *ucode,
1476 u32 api_ver)
1477{
1478 if (api_ver <= 2)
1479 return 0;
1480 return le32_to_cpu(ucode->u.v2.build);
1481}
1482
1483static u8 *iwl5000_ucode_get_data(const struct iwl_ucode_header *ucode,
1484 u32 api_ver)
1485{
1486 if (api_ver <= 2)
1487 return (u8 *) ucode->u.v1.data;
1488 return (u8 *) ucode->u.v2.data;
1489}
1490
1491IWL5000_UCODE_GET(inst_size);
1492IWL5000_UCODE_GET(data_size);
1493IWL5000_UCODE_GET(init_size);
1494IWL5000_UCODE_GET(init_data_size);
1495IWL5000_UCODE_GET(boot_size);
1496
1459struct iwl_hcmd_ops iwl5000_hcmd = { 1497struct iwl_hcmd_ops iwl5000_hcmd = {
1460 .rxon_assoc = iwl5000_send_rxon_assoc, 1498 .rxon_assoc = iwl5000_send_rxon_assoc,
1461 .commit_rxon = iwl_commit_rxon, 1499 .commit_rxon = iwl_commit_rxon,
@@ -1471,6 +1509,17 @@ struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
1471 .calc_rssi = iwl5000_calc_rssi, 1509 .calc_rssi = iwl5000_calc_rssi,
1472}; 1510};
1473 1511
1512struct iwl_ucode_ops iwl5000_ucode = {
1513 .get_header_size = iwl5000_ucode_get_header_size,
1514 .get_build = iwl5000_ucode_get_build,
1515 .get_inst_size = iwl5000_ucode_get_inst_size,
1516 .get_data_size = iwl5000_ucode_get_data_size,
1517 .get_init_size = iwl5000_ucode_get_init_size,
1518 .get_init_data_size = iwl5000_ucode_get_init_data_size,
1519 .get_boot_size = iwl5000_ucode_get_boot_size,
1520 .get_data = iwl5000_ucode_get_data,
1521};
1522
1474struct iwl_lib_ops iwl5000_lib = { 1523struct iwl_lib_ops iwl5000_lib = {
1475 .set_hw_params = iwl5000_hw_set_hw_params, 1524 .set_hw_params = iwl5000_hw_set_hw_params,
1476 .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, 1525 .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
@@ -1572,12 +1621,14 @@ static struct iwl_lib_ops iwl5150_lib = {
1572}; 1621};
1573 1622
1574struct iwl_ops iwl5000_ops = { 1623struct iwl_ops iwl5000_ops = {
1624 .ucode = &iwl5000_ucode,
1575 .lib = &iwl5000_lib, 1625 .lib = &iwl5000_lib,
1576 .hcmd = &iwl5000_hcmd, 1626 .hcmd = &iwl5000_hcmd,
1577 .utils = &iwl5000_hcmd_utils, 1627 .utils = &iwl5000_hcmd_utils,
1578}; 1628};
1579 1629
1580static struct iwl_ops iwl5150_ops = { 1630static struct iwl_ops iwl5150_ops = {
1631 .ucode = &iwl5000_ucode,
1581 .lib = &iwl5150_lib, 1632 .lib = &iwl5150_lib,
1582 .hcmd = &iwl5000_hcmd, 1633 .hcmd = &iwl5000_hcmd,
1583 .utils = &iwl5000_hcmd_utils, 1634 .utils = &iwl5000_hcmd_utils,
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index bd438d8acf55..26c5d4a60d17 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -46,8 +46,8 @@
46#include "iwl-5000-hw.h" 46#include "iwl-5000-hw.h"
47 47
48/* Highest firmware API version supported */ 48/* Highest firmware API version supported */
49#define IWL6000_UCODE_API_MAX 2 49#define IWL6000_UCODE_API_MAX 3
50#define IWL6050_UCODE_API_MAX 2 50#define IWL6050_UCODE_API_MAX 3
51 51
52/* Lowest firmware API version supported */ 52/* Lowest firmware API version supported */
53#define IWL6000_UCODE_API_MIN 1 53#define IWL6000_UCODE_API_MIN 1
@@ -69,6 +69,7 @@ static struct iwl_hcmd_utils_ops iwl6000_hcmd_utils = {
69}; 69};
70 70
71static struct iwl_ops iwl6000_ops = { 71static struct iwl_ops iwl6000_ops = {
72 .ucode = &iwl5000_ucode,
72 .lib = &iwl5000_lib, 73 .lib = &iwl5000_lib,
73 .hcmd = &iwl5000_hcmd, 74 .hcmd = &iwl5000_hcmd,
74 .utils = &iwl6000_hcmd_utils, 75 .utils = &iwl6000_hcmd_utils,
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 */
1285static int iwl_read_ucode(struct iwl_priv *priv) 1285static 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
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 640c4644a165..c844fab95abb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -116,6 +116,17 @@ struct iwl_temp_ops {
116 void (*set_ct_kill)(struct iwl_priv *priv); 116 void (*set_ct_kill)(struct iwl_priv *priv);
117}; 117};
118 118
119struct iwl_ucode_ops {
120 u32 (*get_header_size)(u32);
121 u32 (*get_build)(const struct iwl_ucode_header *, u32);
122 u32 (*get_inst_size)(const struct iwl_ucode_header *, u32);
123 u32 (*get_data_size)(const struct iwl_ucode_header *, u32);
124 u32 (*get_init_size)(const struct iwl_ucode_header *, u32);
125 u32 (*get_init_data_size)(const struct iwl_ucode_header *, u32);
126 u32 (*get_boot_size)(const struct iwl_ucode_header *, u32);
127 u8 * (*get_data)(const struct iwl_ucode_header *, u32);
128};
129
119struct iwl_lib_ops { 130struct iwl_lib_ops {
120 /* set hw dependent parameters */ 131 /* set hw dependent parameters */
121 int (*set_hw_params)(struct iwl_priv *priv); 132 int (*set_hw_params)(struct iwl_priv *priv);
@@ -171,6 +182,7 @@ struct iwl_lib_ops {
171}; 182};
172 183
173struct iwl_ops { 184struct iwl_ops {
185 const struct iwl_ucode_ops *ucode;
174 const struct iwl_lib_ops *lib; 186 const struct iwl_lib_ops *lib;
175 const struct iwl_hcmd_ops *hcmd; 187 const struct iwl_hcmd_ops *hcmd;
176 const struct iwl_hcmd_utils_ops *utils; 188 const struct iwl_hcmd_utils_ops *utils;
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index b989d5c08d34..f4afd0c3265f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -66,6 +66,7 @@ extern struct iwl_cfg iwl1000_bgn_cfg;
66/* shared structures from iwl-5000.c */ 66/* shared structures from iwl-5000.c */
67extern struct iwl_mod_params iwl50_mod_params; 67extern struct iwl_mod_params iwl50_mod_params;
68extern struct iwl_ops iwl5000_ops; 68extern struct iwl_ops iwl5000_ops;
69extern struct iwl_ucode_ops iwl5000_ucode;
69extern struct iwl_lib_ops iwl5000_lib; 70extern struct iwl_lib_ops iwl5000_lib;
70extern struct iwl_hcmd_ops iwl5000_hcmd; 71extern struct iwl_hcmd_ops iwl5000_hcmd;
71extern struct iwl_hcmd_utils_ops iwl5000_hcmd_utils; 72extern struct iwl_hcmd_utils_ops iwl5000_hcmd_utils;
@@ -525,15 +526,29 @@ struct fw_desc {
525}; 526};
526 527
527/* uCode file layout */ 528/* uCode file layout */
528struct iwl_ucode { 529struct iwl_ucode_header {
529 __le32 ver; /* major/minor/API/serial */ 530 __le32 ver; /* major/minor/API/serial */
530 __le32 inst_size; /* bytes of runtime instructions */ 531 union {
531 __le32 data_size; /* bytes of runtime data */ 532 struct {
532 __le32 init_size; /* bytes of initialization instructions */ 533 __le32 inst_size; /* bytes of runtime code */
533 __le32 init_data_size; /* bytes of initialization data */ 534 __le32 data_size; /* bytes of runtime data */
534 __le32 boot_size; /* bytes of bootstrap instructions */ 535 __le32 init_size; /* bytes of init code */
535 u8 data[0]; /* data in same order as "size" elements */ 536 __le32 init_data_size; /* bytes of init data */
537 __le32 boot_size; /* bytes of bootstrap code */
538 u8 data[0]; /* in same order as sizes */
539 } v1;
540 struct {
541 __le32 build; /* build number */
542 __le32 inst_size; /* bytes of runtime code */
543 __le32 data_size; /* bytes of runtime data */
544 __le32 init_size; /* bytes of init code */
545 __le32 init_data_size; /* bytes of init data */
546 __le32 boot_size; /* bytes of bootstrap code */
547 u8 data[0]; /* in same order as sizes */
548 } v2;
549 } u;
536}; 550};
551#define UCODE_HEADER_SIZE(ver) ((ver) == 1 ? 24 : 28)
537 552
538struct iwl4965_ibss_seq { 553struct iwl4965_ibss_seq {
539 u8 mac[ETH_ALEN]; 554 u8 mac[ETH_ALEN];
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index c9b3ea927144..bd6a067b4881 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -2041,7 +2041,7 @@ static void iwl3945_nic_start(struct iwl_priv *priv)
2041 */ 2041 */
2042static int iwl3945_read_ucode(struct iwl_priv *priv) 2042static int iwl3945_read_ucode(struct iwl_priv *priv)
2043{ 2043{
2044 struct iwl_ucode *ucode; 2044 const struct iwl_ucode_header *ucode;
2045 int ret = -EINVAL, index; 2045 int ret = -EINVAL, index;
2046 const struct firmware *ucode_raw; 2046 const struct firmware *ucode_raw;
2047 /* firmware file name contains uCode/driver compatibility version */ 2047 /* firmware file name contains uCode/driver compatibility version */
@@ -2082,22 +2082,24 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
2082 goto error; 2082 goto error;
2083 2083
2084 /* Make sure that we got at least our header! */ 2084 /* Make sure that we got at least our header! */
2085 if (ucode_raw->size < sizeof(*ucode)) { 2085 if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) {
2086 IWL_ERR(priv, "File size way too small!\n"); 2086 IWL_ERR(priv, "File size way too small!\n");
2087 ret = -EINVAL; 2087 ret = -EINVAL;
2088 goto err_release; 2088 goto err_release;
2089 } 2089 }
2090 2090
2091 /* Data from ucode file: header followed by uCode images */ 2091 /* Data from ucode file: header followed by uCode images */
2092 ucode = (void *)ucode_raw->data; 2092 ucode = (struct iwl_ucode_header *)ucode_raw->data;
2093 2093
2094 priv->ucode_ver = le32_to_cpu(ucode->ver); 2094 priv->ucode_ver = le32_to_cpu(ucode->ver);
2095 api_ver = IWL_UCODE_API(priv->ucode_ver); 2095 api_ver = IWL_UCODE_API(priv->ucode_ver);
2096 inst_size = le32_to_cpu(ucode->inst_size); 2096 inst_size = priv->cfg->ops->ucode->get_inst_size(ucode, api_ver);
2097 data_size = le32_to_cpu(ucode->data_size); 2097 data_size = priv->cfg->ops->ucode->get_data_size(ucode, api_ver);
2098 init_size = le32_to_cpu(ucode->init_size); 2098 init_size = priv->cfg->ops->ucode->get_init_size(ucode, api_ver);
2099 init_data_size = le32_to_cpu(ucode->init_data_size); 2099 init_data_size =
2100 boot_size = le32_to_cpu(ucode->boot_size); 2100 priv->cfg->ops->ucode->get_init_data_size(ucode, api_ver);
2101 boot_size = priv->cfg->ops->ucode->get_boot_size(ucode, api_ver);
2102 src = priv->cfg->ops->ucode->get_data(ucode, api_ver);
2101 2103
2102 /* api_ver should match the api version forming part of the 2104 /* api_ver should match the api version forming part of the
2103 * firmware filename ... but we don't check for that and only rely 2105 * firmware filename ... but we don't check for that and only rely
@@ -2138,12 +2140,13 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
2138 2140
2139 2141
2140 /* Verify size of file vs. image size info in file's header */ 2142 /* Verify size of file vs. image size info in file's header */
2141 if (ucode_raw->size < sizeof(*ucode) + 2143 if (ucode_raw->size != priv->cfg->ops->ucode->get_header_size(api_ver) +
2142 inst_size + data_size + init_size + 2144 inst_size + data_size + init_size +
2143 init_data_size + boot_size) { 2145 init_data_size + boot_size) {
2144 2146
2145 IWL_DEBUG_INFO(priv, "uCode file size %zd too small\n", 2147 IWL_DEBUG_INFO(priv,
2146 ucode_raw->size); 2148 "uCode file size %zd does not match expected size\n",
2149 ucode_raw->size);
2147 ret = -EINVAL; 2150 ret = -EINVAL;
2148 goto err_release; 2151 goto err_release;
2149 } 2152 }
@@ -2226,44 +2229,44 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
2226 /* Copy images into buffers for card's bus-master reads ... */ 2229 /* Copy images into buffers for card's bus-master reads ... */
2227 2230
2228 /* Runtime instructions (first block of data in file) */ 2231 /* Runtime instructions (first block of data in file) */
2229 src = &ucode->data[0]; 2232 len = inst_size;
2230 len = priv->ucode_code.len;
2231 IWL_DEBUG_INFO(priv, 2233 IWL_DEBUG_INFO(priv,
2232 "Copying (but not loading) uCode instr len %zd\n", len); 2234 "Copying (but not loading) uCode instr len %zd\n", len);
2233 memcpy(priv->ucode_code.v_addr, src, len); 2235 memcpy(priv->ucode_code.v_addr, src, len);
2236 src += len;
2237
2234 IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n", 2238 IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
2235 priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr); 2239 priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
2236 2240
2237 /* Runtime data (2nd block) 2241 /* Runtime data (2nd block)
2238 * NOTE: Copy into backup buffer will be done in iwl3945_up() */ 2242 * NOTE: Copy into backup buffer will be done in iwl3945_up() */
2239 src = &ucode->data[inst_size]; 2243 len = data_size;
2240 len = priv->ucode_data.len;
2241 IWL_DEBUG_INFO(priv, 2244 IWL_DEBUG_INFO(priv,
2242 "Copying (but not loading) uCode data len %zd\n", len); 2245 "Copying (but not loading) uCode data len %zd\n", len);
2243 memcpy(priv->ucode_data.v_addr, src, len); 2246 memcpy(priv->ucode_data.v_addr, src, len);
2244 memcpy(priv->ucode_data_backup.v_addr, src, len); 2247 memcpy(priv->ucode_data_backup.v_addr, src, len);
2248 src += len;
2245 2249
2246 /* Initialization instructions (3rd block) */ 2250 /* Initialization instructions (3rd block) */
2247 if (init_size) { 2251 if (init_size) {
2248 src = &ucode->data[inst_size + data_size]; 2252 len = init_size;
2249 len = priv->ucode_init.len;
2250 IWL_DEBUG_INFO(priv, 2253 IWL_DEBUG_INFO(priv,
2251 "Copying (but not loading) init instr len %zd\n", len); 2254 "Copying (but not loading) init instr len %zd\n", len);
2252 memcpy(priv->ucode_init.v_addr, src, len); 2255 memcpy(priv->ucode_init.v_addr, src, len);
2256 src += len;
2253 } 2257 }
2254 2258
2255 /* Initialization data (4th block) */ 2259 /* Initialization data (4th block) */
2256 if (init_data_size) { 2260 if (init_data_size) {
2257 src = &ucode->data[inst_size + data_size + init_size]; 2261 len = init_data_size;
2258 len = priv->ucode_init_data.len;
2259 IWL_DEBUG_INFO(priv, 2262 IWL_DEBUG_INFO(priv,
2260 "Copying (but not loading) init data len %zd\n", len); 2263 "Copying (but not loading) init data len %zd\n", len);
2261 memcpy(priv->ucode_init_data.v_addr, src, len); 2264 memcpy(priv->ucode_init_data.v_addr, src, len);
2265 src += len;
2262 } 2266 }
2263 2267
2264 /* Bootstrap instructions (5th block) */ 2268 /* Bootstrap instructions (5th block) */
2265 src = &ucode->data[inst_size + data_size + init_size + init_data_size]; 2269 len = boot_size;
2266 len = priv->ucode_boot.len;
2267 IWL_DEBUG_INFO(priv, 2270 IWL_DEBUG_INFO(priv,
2268 "Copying (but not loading) boot instr len %zd\n", len); 2271 "Copying (but not loading) boot instr len %zd\n", len);
2269 memcpy(priv->ucode_boot.v_addr, src, len); 2272 memcpy(priv->ucode_boot.v_addr, src, len);