Commit 3d8623e6 authored by Shahed Shaikh's avatar Shahed Shaikh Committed by David S. Miller

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: default avatarShahed Shaikh <shahed.shaikh@qlogic.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d874df58
...@@ -1378,31 +1378,45 @@ static int qlcnic_83xx_copy_fw_file(struct qlcnic_adapter *adapter) ...@@ -1378,31 +1378,45 @@ static int qlcnic_83xx_copy_fw_file(struct qlcnic_adapter *adapter)
{ {
struct qlc_83xx_fw_info *fw_info = adapter->ahw->fw_info; struct qlc_83xx_fw_info *fw_info = adapter->ahw->fw_info;
const struct firmware *fw = fw_info->fw; const struct firmware *fw = fw_info->fw;
u32 dest, *p_cache; u32 dest, *p_cache, *temp;
int i, ret = -EIO; int i, ret = -EIO;
__le32 *temp_le;
u8 data[16]; u8 data[16];
size_t size; size_t size;
u64 addr; u64 addr;
temp = kzalloc(fw->size, GFP_KERNEL);
if (!temp) {
release_firmware(fw);
fw_info->fw = NULL;
return -ENOMEM;
}
temp_le = (__le32 *)fw->data;
/* FW image in file is in little endian, swap the data to nullify
* the effect of writel() operation on big endian platform.
*/
for (i = 0; i < fw->size / sizeof(u32); i++)
temp[i] = __le32_to_cpu(temp_le[i]);
dest = QLCRDX(adapter->ahw, QLCNIC_FW_IMAGE_ADDR); dest = QLCRDX(adapter->ahw, QLCNIC_FW_IMAGE_ADDR);
size = (fw->size & ~0xF); size = (fw->size & ~0xF);
p_cache = (u32 *)fw->data; p_cache = temp;
addr = (u64)dest; addr = (u64)dest;
ret = qlcnic_ms_mem_write128(adapter, addr, ret = qlcnic_ms_mem_write128(adapter, addr,
p_cache, size / 16); p_cache, size / 16);
if (ret) { if (ret) {
dev_err(&adapter->pdev->dev, "MS memory write failed\n"); dev_err(&adapter->pdev->dev, "MS memory write failed\n");
release_firmware(fw); goto exit;
fw_info->fw = NULL;
return -EIO;
} }
/* alignment check */ /* alignment check */
if (fw->size & 0xF) { if (fw->size & 0xF) {
addr = dest + size; addr = dest + size;
for (i = 0; i < (fw->size & 0xF); i++) for (i = 0; i < (fw->size & 0xF); i++)
data[i] = fw->data[size + i]; data[i] = temp[size + i];
for (; i < 16; i++) for (; i < 16; i++)
data[i] = 0; data[i] = 0;
ret = qlcnic_ms_mem_write128(adapter, addr, ret = qlcnic_ms_mem_write128(adapter, addr,
...@@ -1410,15 +1424,16 @@ static int qlcnic_83xx_copy_fw_file(struct qlcnic_adapter *adapter) ...@@ -1410,15 +1424,16 @@ static int qlcnic_83xx_copy_fw_file(struct qlcnic_adapter *adapter)
if (ret) { if (ret) {
dev_err(&adapter->pdev->dev, dev_err(&adapter->pdev->dev,
"MS memory write failed\n"); "MS memory write failed\n");
release_firmware(fw); goto exit;
fw_info->fw = NULL;
return -EIO;
} }
} }
exit:
release_firmware(fw); release_firmware(fw);
fw_info->fw = NULL; fw_info->fw = NULL;
kfree(temp);
return 0; return ret;
} }
static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter) static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment