diff options
Diffstat (limited to 'drivers/net/wireless/rsi/rsi_91x_sdio.c')
-rw-r--r-- | drivers/net/wireless/rsi/rsi_91x_sdio.c | 113 |
1 files changed, 84 insertions, 29 deletions
diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index b0cf41195051..d76e69c0beaa 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -18,8 +18,17 @@ #include <linux/module.h> #include "rsi_sdio.h" #include "rsi_common.h" +#include "rsi_coex.h" #include "rsi_hal.h" +/* Default operating mode is wlan STA + BT */ +static u16 dev_oper_mode = DEV_OPMODE_STA_BT_DUAL; +module_param(dev_oper_mode, ushort, 0444); +MODULE_PARM_DESC(dev_oper_mode, + "1[Wi-Fi], 4[BT], 8[BT LE], 5[Wi-Fi STA + BT classic]\n" + "9[Wi-Fi STA + BT LE], 13[Wi-Fi STA + BT classic + BT LE]\n" + "6[AP + BT classic], 14[AP + BT classic + BT LE]"); + /** * rsi_sdio_set_cmd52_arg() - This function prepares cmd 52 read/write arg. * @rw: Read/write @@ -567,7 +576,7 @@ static int rsi_sdio_load_data_master_write(struct rsi_hw *adapter, { u32 num_blocks, offset, i; u16 msb_address, lsb_address; - u8 temp_buf[block_size]; + u8 *temp_buf; int status; num_blocks = instructions_sz / block_size; @@ -576,11 +585,15 @@ static int rsi_sdio_load_data_master_write(struct rsi_hw *adapter, rsi_dbg(INFO_ZONE, "ins_size: %d, num_blocks: %d\n", instructions_sz, num_blocks); + temp_buf = kmalloc(block_size, GFP_KERNEL); + if (!temp_buf) + return -ENOMEM; + /* Loading DM ms word in the sdio slave */ status = rsi_sdio_master_access_msword(adapter, msb_address); if (status < 0) { rsi_dbg(ERR_ZONE, "%s: Unable to set ms word reg\n", __func__); - return status; + goto out_free; } for (offset = 0, i = 0; i < num_blocks; i++, offset += block_size) { @@ -592,7 +605,7 @@ static int rsi_sdio_load_data_master_write(struct rsi_hw *adapter, temp_buf, block_size); if (status < 0) { rsi_dbg(ERR_ZONE, "%s: failed to write\n", __func__); - return status; + goto out_free; } rsi_dbg(INFO_ZONE, "%s: loading block: %d\n", __func__, i); base_address += block_size; @@ -607,7 +620,7 @@ static int rsi_sdio_load_data_master_write(struct rsi_hw *adapter, rsi_dbg(ERR_ZONE, "%s: Unable to set ms word reg\n", __func__); - return status; + goto out_free; } } } @@ -623,12 +636,16 @@ static int rsi_sdio_load_data_master_write(struct rsi_hw *adapter, temp_buf, instructions_sz % block_size); if (status < 0) - return status; + goto out_free; rsi_dbg(INFO_ZONE, "Written Last Block in Address 0x%x Successfully\n", offset | RSI_SD_REQUEST_MASTER); } - return 0; + + status = 0; +out_free: + kfree(temp_buf); + return status; } #define FLASH_SIZE_ADDR 0x04000016 @@ -636,11 +653,14 @@ static int rsi_sdio_master_reg_read(struct rsi_hw *adapter, u32 addr, u32 *read_buf, u16 size) { u32 addr_on_bus, *data; - u32 align[2] = {}; u16 ms_addr; int status; - data = PTR_ALIGN(&align[0], 8); + data = kzalloc(RSI_MASTER_REG_BUF_SIZE, GFP_KERNEL); + if (!data) + return -ENOMEM; + + data = PTR_ALIGN(data, 8); ms_addr = (addr >> 16); status = rsi_sdio_master_access_msword(adapter, ms_addr); @@ -648,7 +668,7 @@ static int rsi_sdio_master_reg_read(struct rsi_hw *adapter, u32 addr, rsi_dbg(ERR_ZONE, "%s: Unable to set ms word to common reg\n", __func__); - return status; + goto err; } addr &= 0xFFFF; @@ -666,7 +686,7 @@ static int rsi_sdio_master_reg_read(struct rsi_hw *adapter, u32 addr, (u8 *)data, 4); if (status < 0) { rsi_dbg(ERR_ZONE, "%s: AHB register read failed\n", __func__); - return status; + goto err; } if (size == 2) { if ((addr & 0x3) == 0) @@ -688,17 +708,23 @@ static int rsi_sdio_master_reg_read(struct rsi_hw *adapter, u32 addr, *read_buf = *data; } - return 0; +err: + kfree(data); + return status; } static int rsi_sdio_master_reg_write(struct rsi_hw *adapter, unsigned long addr, unsigned long data, u16 size) { - unsigned long data1[2], *data_aligned; + unsigned long *data_aligned; int status; - data_aligned = PTR_ALIGN(&data1[0], 8); + data_aligned = kzalloc(RSI_MASTER_REG_BUF_SIZE, GFP_KERNEL); + if (!data_aligned) + return -ENOMEM; + + data_aligned = PTR_ALIGN(data_aligned, 8); if (size == 2) { *data_aligned = ((data << 16) | (data & 0xFFFF)); @@ -717,6 +743,7 @@ static int rsi_sdio_master_reg_write(struct rsi_hw *adapter, rsi_dbg(ERR_ZONE, "%s: Unable to set ms word to common reg\n", __func__); + kfree(data_aligned); return -EIO; } addr = addr & 0xFFFF; @@ -726,12 +753,12 @@ static int rsi_sdio_master_reg_write(struct rsi_hw *adapter, (adapter, (addr | RSI_SD_REQUEST_MASTER), (u8 *)data_aligned, size); - if (status < 0) { + if (status < 0) rsi_dbg(ERR_ZONE, "%s: Unable to do AHB reg write\n", __func__); - return status; - } - return 0; + + kfree(data_aligned); + return status; } /** @@ -754,6 +781,8 @@ static int rsi_sdio_host_intf_write_pkt(struct rsi_hw *adapter, int status; queueno = ((pkt[1] >> 4) & 0xf); + if (queueno == RSI_BT_MGMT_Q || queueno == RSI_BT_DATA_Q) + queueno = RSI_BT_Q; num_blocks = len / block_size; @@ -922,14 +951,16 @@ static int rsi_probe(struct sdio_func *pfunction, const struct sdio_device_id *id) { struct rsi_hw *adapter; + struct rsi_91x_sdiodev *sdev; + int status; rsi_dbg(INIT_ZONE, "%s: Init function called\n", __func__); - adapter = rsi_91x_init(); + adapter = rsi_91x_init(dev_oper_mode); if (!adapter) { rsi_dbg(ERR_ZONE, "%s: Failed to init os intf ops\n", __func__); - return 1; + return -EINVAL; } adapter->rsi_host_intf = RSI_HOST_INTF_SDIO; adapter->host_intf_ops = &sdio_host_intf_ops; @@ -937,39 +968,61 @@ static int rsi_probe(struct sdio_func *pfunction, if (rsi_init_sdio_interface(adapter, pfunction)) { rsi_dbg(ERR_ZONE, "%s: Failed to init sdio interface\n", __func__); - goto fail; + status = -EIO; + goto fail_free_adapter; } + sdev = (struct rsi_91x_sdiodev *)adapter->rsi_dev; + rsi_init_event(&sdev->rx_thread.event); + status = rsi_create_kthread(adapter->priv, &sdev->rx_thread, + rsi_sdio_rx_thread, "SDIO-RX-Thread"); + if (status) { + rsi_dbg(ERR_ZONE, "%s: Unable to init rx thrd\n", __func__); + goto fail_kill_thread; + } + skb_queue_head_init(&sdev->rx_q.head); + sdev->rx_q.num_rx_pkts = 0; + sdio_claim_host(pfunction); if (sdio_claim_irq(pfunction, rsi_handle_interrupt)) { rsi_dbg(ERR_ZONE, "%s: Failed to request IRQ\n", __func__); sdio_release_host(pfunction); - goto fail; + status = -EIO; + goto fail_claim_irq; } sdio_release_host(pfunction); rsi_dbg(INIT_ZONE, "%s: Registered Interrupt handler\n", __func__); if (rsi_hal_device_init(adapter)) { rsi_dbg(ERR_ZONE, "%s: Failed in device init\n", __func__); - sdio_claim_host(pfunction); - sdio_release_irq(pfunction); - sdio_disable_func(pfunction); - sdio_release_host(pfunction); - goto fail; + status = -EINVAL; + goto fail_dev_init; } rsi_dbg(INFO_ZONE, "===> RSI Device Init Done <===\n"); if (rsi_sdio_master_access_msword(adapter, MISC_CFG_BASE_ADDR)) { rsi_dbg(ERR_ZONE, "%s: Unable to set ms word reg\n", __func__); - return -EIO; + status = -EIO; + goto fail_dev_init; } adapter->priv->hibernate_resume = false; adapter->priv->reinit_hw = false; return 0; -fail: + +fail_dev_init: + sdio_claim_host(pfunction); + sdio_release_irq(pfunction); + sdio_release_host(pfunction); +fail_claim_irq: + rsi_kill_thread(&sdev->rx_thread); +fail_kill_thread: + sdio_claim_host(pfunction); + sdio_disable_func(pfunction); + sdio_release_host(pfunction); +fail_free_adapter: rsi_91x_deinit(adapter); rsi_dbg(ERR_ZONE, "%s: Failed in probe...Exiting\n", __func__); - return 1; + return status; } static void ulp_read_write(struct rsi_hw *adapter, u16 addr, u32 data, @@ -1065,6 +1118,8 @@ static void rsi_disconnect(struct sdio_func *pfunction) return; dev = (struct rsi_91x_sdiodev *)adapter->rsi_dev; + + rsi_kill_thread(&dev->rx_thread); sdio_claim_host(pfunction); sdio_release_irq(pfunction); sdio_release_host(pfunction); |