aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShahed Shaikh <shahed.shaikh@qlogic.com>2014-08-18 09:31:55 -0400
committerDavid S. Miller <davem@davemloft.net>2014-08-21 20:43:15 -0400
commit3d8623e60054e6ada897e6295f137fa7f1399a97 (patch)
tree71abe07837d62bbf92fabc65b1b2c1a1bd234ce7
parentd874df58ff2eefadd22623d4e53ff92e38117b40 (diff)
qlcnic: Fix endianess issue in firmware load from file operation
Firmware binary file is in little endian. On big-endian architecture, while writing this binary FW file to adapters memory, writel() swaps the data resulting into corruption of FW image. So, swap the data before writing into adapters memory. Signed-off-by: Shahed Shaikh <shahed.shaikh@qlogic.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c35
1 files changed, 25 insertions, 10 deletions
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
index f33559b72528..86783e1afcf7 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
@@ -1378,31 +1378,45 @@ static int qlcnic_83xx_copy_fw_file(struct qlcnic_adapter *adapter)
1378{ 1378{
1379 struct qlc_83xx_fw_info *fw_info = adapter->ahw->fw_info; 1379 struct qlc_83xx_fw_info *fw_info = adapter->ahw->fw_info;
1380 const struct firmware *fw = fw_info->fw; 1380 const struct firmware *fw = fw_info->fw;
1381 u32 dest, *p_cache; 1381 u32 dest, *p_cache, *temp;
1382 int i, ret = -EIO; 1382 int i, ret = -EIO;
1383 __le32 *temp_le;
1383 u8 data[16]; 1384 u8 data[16];
1384 size_t size; 1385 size_t size;
1385 u64 addr; 1386 u64 addr;
1386 1387
1388 temp = kzalloc(fw->size, GFP_KERNEL);
1389 if (!temp) {
1390 release_firmware(fw);
1391 fw_info->fw = NULL;
1392 return -ENOMEM;
1393 }
1394
1395 temp_le = (__le32 *)fw->data;
1396
1397 /* FW image in file is in little endian, swap the data to nullify
1398 * the effect of writel() operation on big endian platform.
1399 */
1400 for (i = 0; i < fw->size / sizeof(u32); i++)
1401 temp[i] = __le32_to_cpu(temp_le[i]);
1402
1387 dest = QLCRDX(adapter->ahw, QLCNIC_FW_IMAGE_ADDR); 1403 dest = QLCRDX(adapter->ahw, QLCNIC_FW_IMAGE_ADDR);
1388 size = (fw->size & ~0xF); 1404 size = (fw->size & ~0xF);
1389 p_cache = (u32 *)fw->data; 1405 p_cache = temp;
1390 addr = (u64)dest; 1406 addr = (u64)dest;
1391 1407
1392 ret = qlcnic_ms_mem_write128(adapter, addr, 1408 ret = qlcnic_ms_mem_write128(adapter, addr,
1393 p_cache, size / 16); 1409 p_cache, size / 16);
1394 if (ret) { 1410 if (ret) {
1395 dev_err(&adapter->pdev->dev, "MS memory write failed\n"); 1411 dev_err(&adapter->pdev->dev, "MS memory write failed\n");
1396 release_firmware(fw); 1412 goto exit;
1397 fw_info->fw = NULL;
1398 return -EIO;
1399 } 1413 }
1400 1414
1401 /* alignment check */ 1415 /* alignment check */
1402 if (fw->size & 0xF) { 1416 if (fw->size & 0xF) {
1403 addr = dest + size; 1417 addr = dest + size;
1404 for (i = 0; i < (fw->size & 0xF); i++) 1418 for (i = 0; i < (fw->size & 0xF); i++)
1405 data[i] = fw->data[size + i]; 1419 data[i] = temp[size + i];
1406 for (; i < 16; i++) 1420 for (; i < 16; i++)
1407 data[i] = 0; 1421 data[i] = 0;
1408 ret = qlcnic_ms_mem_write128(adapter, addr, 1422 ret = qlcnic_ms_mem_write128(adapter, addr,
@@ -1410,15 +1424,16 @@ static int qlcnic_83xx_copy_fw_file(struct qlcnic_adapter *adapter)
1410 if (ret) { 1424 if (ret) {
1411 dev_err(&adapter->pdev->dev, 1425 dev_err(&adapter->pdev->dev,
1412 "MS memory write failed\n"); 1426 "MS memory write failed\n");
1413 release_firmware(fw); 1427 goto exit;
1414 fw_info->fw = NULL;
1415 return -EIO;
1416 } 1428 }
1417 } 1429 }
1430
1431exit:
1418 release_firmware(fw); 1432 release_firmware(fw);
1419 fw_info->fw = NULL; 1433 fw_info->fw = NULL;
1434 kfree(temp);
1420 1435
1421 return 0; 1436 return ret;
1422} 1437}
1423 1438
1424static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter) 1439static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter)