aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rsi/rsi_91x_sdio.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/rsi/rsi_91x_sdio.c')
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_sdio.c113
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);