]> git.itanic.dy.fi Git - linux-stable/commitdiff
wifi: wilc1000: fix DMA on stack objects
authorAjay.Kathat@microchip.com <Ajay.Kathat@microchip.com>
Tue, 9 Aug 2022 07:57:56 +0000 (07:57 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 15 Sep 2022 09:30:04 +0000 (11:30 +0200)
[ Upstream commit 40b717bfcefab28a0656b8caa5e43d5449e5a671 ]

Sometimes 'wilc_sdio_cmd53' is called with addresses pointing to an
object on the stack. Use dynamically allocated memory for cmd53 instead
of stack address which is not DMA'able.

Fixes: 5625f965d764 ("wilc1000: move wilc driver out of staging")
Reported-by: Michael Walle <mwalle@kernel.org>
Suggested-by: Michael Walle <mwalle@kernel.org>
Signed-off-by: Ajay Singh <ajay.kathat@microchip.com>
Reviewed-by: Michael Walle <mwalle@kernel.org>
Tested-by: Michael Walle <mwalle@kernel.org>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20220809075749.62752-1-ajay.kathat@microchip.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/net/wireless/microchip/wilc1000/netdev.h
drivers/net/wireless/microchip/wilc1000/sdio.c
drivers/net/wireless/microchip/wilc1000/wlan.c

index 86209b391a3d6f7512104e77b4df95e952ce0fe2..e6e23fc585ee8d1ab453abd23ff30ceb5cbfa404 100644 (file)
@@ -252,6 +252,7 @@ struct wilc {
        u8 *rx_buffer;
        u32 rx_buffer_offset;
        u8 *tx_buffer;
+       u32 *vmm_table;
 
        struct txq_handle txq[NQUEUES];
        int txq_entries;
index 8b3b7352310858c092f26d0710d620f9f386ebf9..6c0727fc4abd99259ef66de81062c8f8652d8dd8 100644 (file)
@@ -27,6 +27,7 @@ struct wilc_sdio {
        bool irq_gpio;
        u32 block_size;
        int has_thrpt_enh3;
+       u8 *cmd53_buf;
 };
 
 struct sdio_cmd52 {
@@ -46,6 +47,7 @@ struct sdio_cmd53 {
        u32 count:              9;
        u8 *buffer;
        u32 block_size;
+       bool use_global_buf;
 };
 
 static const struct wilc_hif_func wilc_hif_sdio;
@@ -90,6 +92,8 @@ static int wilc_sdio_cmd53(struct wilc *wilc, struct sdio_cmd53 *cmd)
 {
        struct sdio_func *func = container_of(wilc->dev, struct sdio_func, dev);
        int size, ret;
+       struct wilc_sdio *sdio_priv = wilc->bus_data;
+       u8 *buf = cmd->buffer;
 
        sdio_claim_host(func);
 
@@ -100,12 +104,23 @@ static int wilc_sdio_cmd53(struct wilc *wilc, struct sdio_cmd53 *cmd)
        else
                size = cmd->count;
 
+       if (cmd->use_global_buf) {
+               if (size > sizeof(u32))
+                       return -EINVAL;
+
+               buf = sdio_priv->cmd53_buf;
+       }
+
        if (cmd->read_write) {  /* write */
-               ret = sdio_memcpy_toio(func, cmd->address,
-                                      (void *)cmd->buffer, size);
+               if (cmd->use_global_buf)
+                       memcpy(buf, cmd->buffer, size);
+
+               ret = sdio_memcpy_toio(func, cmd->address, buf, size);
        } else {        /* read */
-               ret = sdio_memcpy_fromio(func, (void *)cmd->buffer,
-                                        cmd->address,  size);
+               ret = sdio_memcpy_fromio(func, buf, cmd->address, size);
+
+               if (cmd->use_global_buf)
+                       memcpy(cmd->buffer, buf, size);
        }
 
        sdio_release_host(func);
@@ -127,6 +142,12 @@ static int wilc_sdio_probe(struct sdio_func *func,
        if (!sdio_priv)
                return -ENOMEM;
 
+       sdio_priv->cmd53_buf = kzalloc(sizeof(u32), GFP_KERNEL);
+       if (!sdio_priv->cmd53_buf) {
+               ret = -ENOMEM;
+               goto free;
+       }
+
        ret = wilc_cfg80211_init(&wilc, &func->dev, WILC_HIF_SDIO,
                                 &wilc_hif_sdio);
        if (ret)
@@ -160,6 +181,7 @@ static int wilc_sdio_probe(struct sdio_func *func,
        irq_dispose_mapping(wilc->dev_irq_num);
        wilc_netdev_cleanup(wilc);
 free:
+       kfree(sdio_priv->cmd53_buf);
        kfree(sdio_priv);
        return ret;
 }
@@ -171,6 +193,7 @@ static void wilc_sdio_remove(struct sdio_func *func)
 
        clk_disable_unprepare(wilc->rtc_clk);
        wilc_netdev_cleanup(wilc);
+       kfree(sdio_priv->cmd53_buf);
        kfree(sdio_priv);
 }
 
@@ -367,8 +390,9 @@ static int wilc_sdio_write_reg(struct wilc *wilc, u32 addr, u32 data)
                cmd.address = WILC_SDIO_FBR_DATA_REG;
                cmd.block_mode = 0;
                cmd.increment = 1;
-               cmd.count = 4;
+               cmd.count = sizeof(u32);
                cmd.buffer = (u8 *)&data;
+               cmd.use_global_buf = true;
                cmd.block_size = sdio_priv->block_size;
                ret = wilc_sdio_cmd53(wilc, &cmd);
                if (ret)
@@ -406,6 +430,7 @@ static int wilc_sdio_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
        nblk = size / block_size;
        nleft = size % block_size;
 
+       cmd.use_global_buf = false;
        if (nblk > 0) {
                cmd.block_mode = 1;
                cmd.increment = 1;
@@ -484,8 +509,9 @@ static int wilc_sdio_read_reg(struct wilc *wilc, u32 addr, u32 *data)
                cmd.address = WILC_SDIO_FBR_DATA_REG;
                cmd.block_mode = 0;
                cmd.increment = 1;
-               cmd.count = 4;
+               cmd.count = sizeof(u32);
                cmd.buffer = (u8 *)data;
+               cmd.use_global_buf = true;
 
                cmd.block_size = sdio_priv->block_size;
                ret = wilc_sdio_cmd53(wilc, &cmd);
@@ -527,6 +553,7 @@ static int wilc_sdio_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
        nblk = size / block_size;
        nleft = size % block_size;
 
+       cmd.use_global_buf = false;
        if (nblk > 0) {
                cmd.block_mode = 1;
                cmd.increment = 1;
index 200a103a0a858fa7f7d98ce3258bd0edabfa5923..380699983a75b2ed9575b744fc46dfcbb088f2d2 100644 (file)
@@ -701,7 +701,7 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
        int ret = 0;
        int counter;
        int timeout;
-       u32 vmm_table[WILC_VMM_TBL_SIZE];
+       u32 *vmm_table = wilc->vmm_table;
        u8 ac_pkt_num_to_chip[NQUEUES] = {0, 0, 0, 0};
        const struct wilc_hif_func *func;
        int srcu_idx;
@@ -1220,6 +1220,8 @@ void wilc_wlan_cleanup(struct net_device *dev)
        while ((rqe = wilc_wlan_rxq_remove(wilc)))
                kfree(rqe);
 
+       kfree(wilc->vmm_table);
+       wilc->vmm_table = NULL;
        kfree(wilc->rx_buffer);
        wilc->rx_buffer = NULL;
        kfree(wilc->tx_buffer);
@@ -1455,6 +1457,14 @@ int wilc_wlan_init(struct net_device *dev)
                goto fail;
        }
 
+       if (!wilc->vmm_table)
+               wilc->vmm_table = kzalloc(WILC_VMM_TBL_SIZE, GFP_KERNEL);
+
+       if (!wilc->vmm_table) {
+               ret = -ENOBUFS;
+               goto fail;
+       }
+
        if (!wilc->tx_buffer)
                wilc->tx_buffer = kmalloc(WILC_TX_BUFF_SIZE, GFP_KERNEL);
 
@@ -1479,7 +1489,8 @@ int wilc_wlan_init(struct net_device *dev)
        return 0;
 
 fail:
-
+       kfree(wilc->vmm_table);
+       wilc->vmm_table = NULL;
        kfree(wilc->rx_buffer);
        wilc->rx_buffer = NULL;
        kfree(wilc->tx_buffer);