Commit f7005466 authored by Siva Rebbagondla's avatar Siva Rebbagondla Committed by Kalle Valo

rsi: fix nommu_map_sg overflow kernel panic

Following overflow kernel panic is observed on some platforms while
loading the driver. It is fixed if dynamically allocated memory is
passed to SDIO instead of static one

[  927.513963] nommu_map_sg: overflow 17d54064ba7c+20 of device mask ffffffff
[  927.517712] Modules linked in: rsi_sdio(+) cmac bnep arc4 rsi_91x mac80211 cfg80211
	       btrsi rfcomm bluetooth ecdh_generic snd_soc_sst_bytcr_rt5660
[  927.517861] CPU: 0 PID: 1624 Comm: insmod Tainted: G W 4.15.0-1000 #1
[  927.517870] RIP: 0010:sdhci_send_command+0x5f0/0xa90 [sdhci]
[  927.517873] RSP: 0000:ffffac3fc064b6d8 EFLAGS: 00010086
[  927.517895] Call Trace:
[  927.517908]  ? __schedule+0x3cd/0x890
[  927.517915]  ? mod_timer+0x17b/0x3c0
[  927.517922]  sdhci_request+0x7c/0xf0 [sdhci]
[  927.517928]  __mmc_start_request+0x5a/0x170
[  927.517932]  mmc_start_request+0x74/0x90
[  927.517936]  mmc_wait_for_req+0x87/0xe0
[  927.517940]  mmc_io_rw_extended+0x2fd/0x330
[  927.517946]  ? mmc_wait_data_done+0x30/0x30
[  927.517951]  sdio_io_rw_ext_helper+0x160/0x210
[  927.517956]  sdio_writesb+0x1d/0x20
[  927.517966]	rsi_sdio_write_register_multiple+0x68/0x110 [rsi_sdio]
[  927.517976]  rsi_hal_device_init+0x357/0x910 [rsi_91x]
[  927.517983]  ? rsi_hal_device_init+0x357/0x910 [rsi_91x]
[  927.517990]  rsi_probe+0x2c6/0x450 [rsi_sdio]
[  927.517995]  sdio_bus_probe+0xfc/0x110
[  927.518000]  driver_probe_device+0x2b3/0x490
[  927.518005]  __driver_attach+0xdf/0xf0
[  927.518008]  ? driver_probe_device+0x490/0x490
[  927.518014]  bus_for_each_dev+0x6c/0xc0
[  927.518018]  driver_attach+0x1e/0x20
[  927.518021]  bus_add_driver+0x1f4/0x270
[  927.518028]  ? rsi_sdio_ack_intr+0x50/0x50 [rsi_sdio]
[  927.518031]  driver_register+0x60/0xe0
[  927.518038]  ? rsi_sdio_ack_intr+0x50/0x50 [rsi_sdio]
[  927.518041]  sdio_register_driver+0x20/0x30
[  927.518047]  rsi_module_init+0x16/0x40 [rsi_sdio]
Signed-off-by: default avatarSiva Rebbagondla <siva.rebbagondla@redpinesignals.com>
Signed-off-by: default avatarAmitkumar Karwar <amit.karwar@redpinesignals.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent f0b147b8
...@@ -635,28 +635,32 @@ static int bl_write_header(struct rsi_hw *adapter, u8 *flash_content, ...@@ -635,28 +635,32 @@ static int bl_write_header(struct rsi_hw *adapter, u8 *flash_content,
u32 content_size) u32 content_size)
{ {
struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops; struct rsi_host_intf_ops *hif_ops = adapter->host_intf_ops;
struct bl_header bl_hdr; struct bl_header *bl_hdr;
u32 write_addr, write_len; u32 write_addr, write_len;
int status; int status;
bl_hdr.flags = 0; bl_hdr = kzalloc(sizeof(*bl_hdr), GFP_KERNEL);
bl_hdr.image_no = cpu_to_le32(adapter->priv->coex_mode); if (!bl_hdr)
bl_hdr.check_sum = cpu_to_le32( return -ENOMEM;
*(u32 *)&flash_content[CHECK_SUM_OFFSET]);
bl_hdr.flash_start_address = cpu_to_le32( bl_hdr->flags = 0;
*(u32 *)&flash_content[ADDR_OFFSET]); bl_hdr->image_no = cpu_to_le32(adapter->priv->coex_mode);
bl_hdr.flash_len = cpu_to_le32(*(u32 *)&flash_content[LEN_OFFSET]); bl_hdr->check_sum =
cpu_to_le32(*(u32 *)&flash_content[CHECK_SUM_OFFSET]);
bl_hdr->flash_start_address =
cpu_to_le32(*(u32 *)&flash_content[ADDR_OFFSET]);
bl_hdr->flash_len = cpu_to_le32(*(u32 *)&flash_content[LEN_OFFSET]);
write_len = sizeof(struct bl_header); write_len = sizeof(struct bl_header);
if (adapter->rsi_host_intf == RSI_HOST_INTF_USB) { if (adapter->rsi_host_intf == RSI_HOST_INTF_USB) {
write_addr = PING_BUFFER_ADDRESS; write_addr = PING_BUFFER_ADDRESS;
status = hif_ops->write_reg_multiple(adapter, write_addr, status = hif_ops->write_reg_multiple(adapter, write_addr,
(u8 *)&bl_hdr, write_len); (u8 *)bl_hdr, write_len);
if (status < 0) { if (status < 0) {
rsi_dbg(ERR_ZONE, rsi_dbg(ERR_ZONE,
"%s: Failed to load Version/CRC structure\n", "%s: Failed to load Version/CRC structure\n",
__func__); __func__);
return status; goto fail;
} }
} else { } else {
write_addr = PING_BUFFER_ADDRESS >> 16; write_addr = PING_BUFFER_ADDRESS >> 16;
...@@ -665,20 +669,23 @@ static int bl_write_header(struct rsi_hw *adapter, u8 *flash_content, ...@@ -665,20 +669,23 @@ static int bl_write_header(struct rsi_hw *adapter, u8 *flash_content,
rsi_dbg(ERR_ZONE, rsi_dbg(ERR_ZONE,
"%s: Unable to set ms word to common reg\n", "%s: Unable to set ms word to common reg\n",
__func__); __func__);
return status; goto fail;
} }
write_addr = RSI_SD_REQUEST_MASTER | write_addr = RSI_SD_REQUEST_MASTER |
(PING_BUFFER_ADDRESS & 0xFFFF); (PING_BUFFER_ADDRESS & 0xFFFF);
status = hif_ops->write_reg_multiple(adapter, write_addr, status = hif_ops->write_reg_multiple(adapter, write_addr,
(u8 *)&bl_hdr, write_len); (u8 *)bl_hdr, write_len);
if (status < 0) { if (status < 0) {
rsi_dbg(ERR_ZONE, rsi_dbg(ERR_ZONE,
"%s: Failed to load Version/CRC structure\n", "%s: Failed to load Version/CRC structure\n",
__func__); __func__);
return status; goto fail;
} }
} }
return 0; status = 0;
fail:
kfree(bl_hdr);
return status;
} }
static u32 read_flash_capacity(struct rsi_hw *adapter) static u32 read_flash_capacity(struct rsi_hw *adapter)
......
...@@ -1038,17 +1038,21 @@ static void ulp_read_write(struct rsi_hw *adapter, u16 addr, u32 data, ...@@ -1038,17 +1038,21 @@ static void ulp_read_write(struct rsi_hw *adapter, u16 addr, u32 data,
/*This function resets and re-initializes the chip.*/ /*This function resets and re-initializes the chip.*/
static void rsi_reset_chip(struct rsi_hw *adapter) static void rsi_reset_chip(struct rsi_hw *adapter)
{ {
__le32 data; u8 *data;
u8 sdio_interrupt_status = 0; u8 sdio_interrupt_status = 0;
u8 request = 1; u8 request = 1;
int ret; int ret;
data = kzalloc(sizeof(u32), GFP_KERNEL);
if (!data)
return;
rsi_dbg(INFO_ZONE, "Writing disable to wakeup register\n"); rsi_dbg(INFO_ZONE, "Writing disable to wakeup register\n");
ret = rsi_sdio_write_register(adapter, 0, SDIO_WAKEUP_REG, &request); ret = rsi_sdio_write_register(adapter, 0, SDIO_WAKEUP_REG, &request);
if (ret < 0) { if (ret < 0) {
rsi_dbg(ERR_ZONE, rsi_dbg(ERR_ZONE,
"%s: Failed to write SDIO wakeup register\n", __func__); "%s: Failed to write SDIO wakeup register\n", __func__);
return; goto err;
} }
msleep(20); msleep(20);
ret = rsi_sdio_read_register(adapter, RSI_FN1_INT_REGISTER, ret = rsi_sdio_read_register(adapter, RSI_FN1_INT_REGISTER,
...@@ -1056,7 +1060,7 @@ static void rsi_reset_chip(struct rsi_hw *adapter) ...@@ -1056,7 +1060,7 @@ static void rsi_reset_chip(struct rsi_hw *adapter)
if (ret < 0) { if (ret < 0) {
rsi_dbg(ERR_ZONE, "%s: Failed to Read Intr Status Register\n", rsi_dbg(ERR_ZONE, "%s: Failed to Read Intr Status Register\n",
__func__); __func__);
return; goto err;
} }
rsi_dbg(INFO_ZONE, "%s: Intr Status Register value = %d\n", rsi_dbg(INFO_ZONE, "%s: Intr Status Register value = %d\n",
__func__, sdio_interrupt_status); __func__, sdio_interrupt_status);
...@@ -1066,17 +1070,17 @@ static void rsi_reset_chip(struct rsi_hw *adapter) ...@@ -1066,17 +1070,17 @@ static void rsi_reset_chip(struct rsi_hw *adapter)
rsi_dbg(ERR_ZONE, rsi_dbg(ERR_ZONE,
"%s: Unable to set ms word to common reg\n", "%s: Unable to set ms word to common reg\n",
__func__); __func__);
return; goto err;
} }
data = TA_HOLD_THREAD_VALUE; put_unaligned_le32(TA_HOLD_THREAD_VALUE, data);
if (rsi_sdio_write_register_multiple(adapter, TA_HOLD_THREAD_REG | if (rsi_sdio_write_register_multiple(adapter, TA_HOLD_THREAD_REG |
RSI_SD_REQUEST_MASTER, RSI_SD_REQUEST_MASTER,
(u8 *)&data, 4)) { data, 4)) {
rsi_dbg(ERR_ZONE, rsi_dbg(ERR_ZONE,
"%s: Unable to hold Thread-Arch processor threads\n", "%s: Unable to hold Thread-Arch processor threads\n",
__func__); __func__);
return; goto err;
} }
/* This msleep will ensure Thread-Arch processor to go to hold /* This msleep will ensure Thread-Arch processor to go to hold
...@@ -1097,6 +1101,9 @@ static void rsi_reset_chip(struct rsi_hw *adapter) ...@@ -1097,6 +1101,9 @@ static void rsi_reset_chip(struct rsi_hw *adapter)
* read write operations to complete for chip reset. * read write operations to complete for chip reset.
*/ */
msleep(500); msleep(500);
err:
kfree(data);
return;
} }
/** /**
......
...@@ -87,7 +87,7 @@ enum sdio_interrupt_type { ...@@ -87,7 +87,7 @@ enum sdio_interrupt_type {
#define TA_SOFT_RST_CLR 0 #define TA_SOFT_RST_CLR 0
#define TA_SOFT_RST_SET BIT(0) #define TA_SOFT_RST_SET BIT(0)
#define TA_PC_ZERO 0 #define TA_PC_ZERO 0
#define TA_HOLD_THREAD_VALUE cpu_to_le32(0xF) #define TA_HOLD_THREAD_VALUE 0xF
#define TA_RELEASE_THREAD_VALUE cpu_to_le32(0xF) #define TA_RELEASE_THREAD_VALUE cpu_to_le32(0xF)
#define TA_BASE_ADDR 0x2200 #define TA_BASE_ADDR 0x2200
#define MISC_CFG_BASE_ADDR 0x4105 #define MISC_CFG_BASE_ADDR 0x4105
......
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