rsi: fix nommu_map_sg overflow kernel panic
authorSiva Rebbagondla <siva.rebbagondla@redpinesignals.com>
Wed, 11 Apr 2018 06:43:31 +0000 (12:13 +0530)
committerKalle Valo <kvalo@codeaurora.org>
Tue, 24 Apr 2018 17:25:57 +0000 (20:25 +0300)
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: Siva Rebbagondla <siva.rebbagondla@redpinesignals.com>
Signed-off-by: Amitkumar Karwar <amit.karwar@redpinesignals.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
drivers/net/wireless/rsi/rsi_91x_hal.c
drivers/net/wireless/rsi/rsi_91x_sdio.c
drivers/net/wireless/rsi/rsi_sdio.h

index b7c5403..0761e61 100644 (file)
@@ -635,28 +635,32 @@ static int bl_write_header(struct rsi_hw *adapter, u8 *flash_content,
                           u32 content_size)
 {
        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;
        int status;
 
-       bl_hdr.flags = 0;
-       bl_hdr.image_no = cpu_to_le32(adapter->priv->coex_mode);
-       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]);
+       bl_hdr = kzalloc(sizeof(*bl_hdr), GFP_KERNEL);
+       if (!bl_hdr)
+               return -ENOMEM;
+
+       bl_hdr->flags = 0;
+       bl_hdr->image_no = cpu_to_le32(adapter->priv->coex_mode);
+       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);
 
        if (adapter->rsi_host_intf == RSI_HOST_INTF_USB) {
                write_addr = PING_BUFFER_ADDRESS;
                status = hif_ops->write_reg_multiple(adapter, write_addr,
-                                                (u8 *)&bl_hdr, write_len);
+                                                (u8 *)bl_hdr, write_len);
                if (status < 0) {
                        rsi_dbg(ERR_ZONE,
                                "%s: Failed to load Version/CRC structure\n",
                                __func__);
-                       return status;
+                       goto fail;
                }
        } else {
                write_addr = PING_BUFFER_ADDRESS >> 16;
@@ -665,20 +669,23 @@ static int bl_write_header(struct rsi_hw *adapter, u8 *flash_content,
                        rsi_dbg(ERR_ZONE,
                                "%s: Unable to set ms word to common reg\n",
                                __func__);
-                       return status;
+                       goto fail;
                }
                write_addr = RSI_SD_REQUEST_MASTER |
                             (PING_BUFFER_ADDRESS & 0xFFFF);
                status = hif_ops->write_reg_multiple(adapter, write_addr,
-                                                (u8 *)&bl_hdr, write_len);
+                                                (u8 *)bl_hdr, write_len);
                if (status < 0) {
                        rsi_dbg(ERR_ZONE,
                                "%s: Failed to load Version/CRC structure\n",
                                __func__);
-                       return status;
+                       goto fail;
                }
        }
-       return 0;
+       status = 0;
+fail:
+       kfree(bl_hdr);
+       return status;
 }
 
 static u32 read_flash_capacity(struct rsi_hw *adapter)
index 8ef0058..f7f2820 100644 (file)
@@ -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.*/
 static void rsi_reset_chip(struct rsi_hw *adapter)
 {
-       __le32 data;
+       u8 *data;
        u8 sdio_interrupt_status = 0;
        u8 request = 1;
        int ret;
 
+       data = kzalloc(sizeof(u32), GFP_KERNEL);
+       if (!data)
+               return;
+
        rsi_dbg(INFO_ZONE, "Writing disable to wakeup register\n");
        ret =  rsi_sdio_write_register(adapter, 0, SDIO_WAKEUP_REG, &request);
        if (ret < 0) {
                rsi_dbg(ERR_ZONE,
                        "%s: Failed to write SDIO wakeup register\n", __func__);
-               return;
+               goto err;
        }
        msleep(20);
        ret =  rsi_sdio_read_register(adapter, RSI_FN1_INT_REGISTER,
@@ -1056,7 +1060,7 @@ static void rsi_reset_chip(struct rsi_hw *adapter)
        if (ret < 0) {
                rsi_dbg(ERR_ZONE, "%s: Failed to Read Intr Status Register\n",
                        __func__);
-               return;
+               goto err;
        }
        rsi_dbg(INFO_ZONE, "%s: Intr Status Register value = %d\n",
                __func__, sdio_interrupt_status);
@@ -1066,17 +1070,17 @@ static void rsi_reset_chip(struct rsi_hw *adapter)
                rsi_dbg(ERR_ZONE,
                        "%s: Unable to set ms word to common reg\n",
                        __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 |
                                             RSI_SD_REQUEST_MASTER,
-                                            (u8 *)&data, 4)) {
+                                            data, 4)) {
                rsi_dbg(ERR_ZONE,
                        "%s: Unable to hold Thread-Arch processor threads\n",
                        __func__);
-               return;
+               goto err;
        }
 
        /* This msleep will ensure Thread-Arch processor to go to hold
@@ -1097,6 +1101,9 @@ static void rsi_reset_chip(struct rsi_hw *adapter)
         * read write operations to complete for chip reset.
         */
        msleep(500);
+err:
+       kfree(data);
+       return;
 }
 
 /**
index ead8e7c..353dbdf 100644 (file)
@@ -87,7 +87,7 @@ enum sdio_interrupt_type {
 #define TA_SOFT_RST_CLR              0
 #define TA_SOFT_RST_SET              BIT(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_BASE_ADDR                 0x2200
 #define MISC_CFG_BASE_ADDR           0x4105