mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	wifi: wilc1000: fix DMA on stack objects
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: 5625f965d7 ("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
			
			
This commit is contained in:
		
							parent
							
								
									fa3fbe6403
								
							
						
					
					
						commit
						40b717bfce
					
				
					 3 changed files with 47 additions and 8 deletions
				
			
		| 
						 | 
				
			
			@ -245,6 +245,7 @@ struct wilc {
 | 
			
		|||
	u8 *rx_buffer;
 | 
			
		||||
	u32 rx_buffer_offset;
 | 
			
		||||
	u8 *tx_buffer;
 | 
			
		||||
	u32 *vmm_table;
 | 
			
		||||
 | 
			
		||||
	struct txq_handle txq[NQUEUES];
 | 
			
		||||
	int txq_entries;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,6 +28,7 @@ struct wilc_sdio {
 | 
			
		|||
	u32 block_size;
 | 
			
		||||
	bool isinit;
 | 
			
		||||
	int has_thrpt_enh3;
 | 
			
		||||
	u8 *cmd53_buf;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct sdio_cmd52 {
 | 
			
		||||
| 
						 | 
				
			
			@ -47,6 +48,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;
 | 
			
		||||
| 
						 | 
				
			
			@ -91,6 +93,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);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -101,12 +105,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);
 | 
			
		||||
| 
						 | 
				
			
			@ -128,6 +143,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)
 | 
			
		||||
| 
						 | 
				
			
			@ -161,6 +182,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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -172,6 +194,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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -375,8 +398,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)
 | 
			
		||||
| 
						 | 
				
			
			@ -414,6 +438,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;
 | 
			
		||||
| 
						 | 
				
			
			@ -492,8 +517,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);
 | 
			
		||||
| 
						 | 
				
			
			@ -535,6 +561,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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -714,7 +714,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;
 | 
			
		||||
| 
						 | 
				
			
			@ -1252,6 +1252,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);
 | 
			
		||||
| 
						 | 
				
			
			@ -1489,6 +1491,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);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1513,7 +1523,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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue