diff mbox

[v8,4/8] rsi: add coex support

Message ID 1519394098-24220-5-git-send-email-amitkarwar@gmail.com (mailing list archive)
State Superseded
Delegated to: Kalle Valo
Headers show

Commit Message

Amitkumar Karwar Feb. 23, 2018, 1:54 p.m. UTC
From: Prameela Rani Garnepudi <prameela.j04cs@gmail.com>

With BT support, driver has to handle two streams of data
(i.e. wlan and BT). Actual coex implementation is in firmware.
Coex module just schedule the packets to firmware by taking them
from the corresponding paths.

Structures for module and protocol operations are introduced for
this purpose. Protocol operations structure is global structure
which can be shared among different modules. Move initialization
of coex and operating mode values to rsi_91x_init().

Signed-off-by: Prameela Rani Garnepudi <prameela.j04cs@gmail.com>
Signed-off-by: Siva Rebbagondla <siva.rebbagondla@redpinesignals.com>
Signed-off-by: Amitkumar Karwar <amit.karwar@redpinesignals.com>
---
v8: Resolve error reported by 'kbuild test robot' by moving header
    file code under CONFIG_RSI_COEX flag
v7: Use mutex instead of semaphore (Kalle)
v6: Rename semaphore tx_bus_lock to tx_bus_sema. Modified coex
    scheduling loop to avoid while(1) (Kalle)
v5: Same as earlier versions
---
 drivers/net/wireless/rsi/Kconfig        |   9 ++
 drivers/net/wireless/rsi/Makefile       |   1 +
 drivers/net/wireless/rsi/rsi_91x_coex.c | 177 ++++++++++++++++++++++++++++++++
 drivers/net/wireless/rsi/rsi_91x_hal.c  |  17 +--
 drivers/net/wireless/rsi/rsi_91x_main.c |  30 +++++-
 drivers/net/wireless/rsi/rsi_91x_mgmt.c |   2 +-
 drivers/net/wireless/rsi/rsi_91x_sdio.c |   1 +
 drivers/net/wireless/rsi/rsi_91x_usb.c  |   2 +
 drivers/net/wireless/rsi/rsi_coex.h     |  37 +++++++
 drivers/net/wireless/rsi/rsi_main.h     |   6 ++
 drivers/net/wireless/rsi/rsi_mgmt.h     |   3 +
 include/net/rsi_91x.h                   |  20 ++++
 12 files changed, 295 insertions(+), 10 deletions(-)
 create mode 100644 drivers/net/wireless/rsi/rsi_91x_coex.c
 create mode 100644 drivers/net/wireless/rsi/rsi_coex.h

Comments

kernel test robot Feb. 26, 2018, 2:21 a.m. UTC | #1
Hi Prameela,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on wireless-drivers-next/master]
[also build test ERROR on v4.16-rc2 next-20180223]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Amitkumar-Karwar/rsi-add-bluetooth-and-coex-support/20180226-073244
base:   https://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next.git master
config: sh-allmodconfig (attached as .config)
compiler: sh4-linux-gnu-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=sh 

Note: the linux-review/Amitkumar-Karwar/rsi-add-bluetooth-and-coex-support/20180226-073244 HEAD 9c5222af2b3dbf5143bc1fa4dc0af78fcfa3559d builds fine.
      It only hurts bisectibility.

All errors (new ones prefixed by >>):

   drivers/net//wireless/rsi/rsi_91x_main.c: In function 'rsi_read_pkt':
>> drivers/net//wireless/rsi/rsi_91x_main.c:165:5: error: implicit declaration of function 'rsi_coex_recv_pkt'; did you mean 'rsi_read_pkt'? [-Werror=implicit-function-declaration]
        rsi_coex_recv_pkt(common, frame_desc + offset);
        ^~~~~~~~~~~~~~~~~
        rsi_read_pkt
   drivers/net//wireless/rsi/rsi_91x_main.c: In function 'rsi_91x_init':
>> drivers/net//wireless/rsi/rsi_91x_main.c:287:7: error: implicit declaration of function 'rsi_coex_attach'; did you mean 'driver_attach'? [-Werror=implicit-function-declaration]
      if (rsi_coex_attach(common)) {
          ^~~~~~~~~~~~~~~
          driver_attach
   drivers/net//wireless/rsi/rsi_91x_main.c: In function 'rsi_91x_deinit':
>> drivers/net//wireless/rsi/rsi_91x_main.c:323:3: error: implicit declaration of function 'rsi_coex_detach'; did you mean 'rsi_91x_deinit'? [-Werror=implicit-function-declaration]
      rsi_coex_detach(common);
      ^~~~~~~~~~~~~~~
      rsi_91x_deinit
   cc1: some warnings being treated as errors

vim +165 drivers/net//wireless/rsi/rsi_91x_main.c

   133	
   134	/**
   135	 * rsi_read_pkt() - This function reads frames from the card.
   136	 * @common: Pointer to the driver private structure.
   137	 * @rcv_pkt_len: Received pkt length. In case of USB it is 0.
   138	 *
   139	 * Return: 0 on success, -1 on failure.
   140	 */
   141	int rsi_read_pkt(struct rsi_common *common, u8 *rx_pkt, s32 rcv_pkt_len)
   142	{
   143		u8 *frame_desc = NULL, extended_desc = 0;
   144		u32 index, length = 0, queueno = 0;
   145		u16 actual_length = 0, offset;
   146		struct sk_buff *skb = NULL;
   147	
   148		index = 0;
   149		do {
   150			frame_desc = &rx_pkt[index];
   151			actual_length = *(u16 *)&frame_desc[0];
   152			offset = *(u16 *)&frame_desc[2];
   153	
   154			queueno = rsi_get_queueno(frame_desc, offset);
   155			length = rsi_get_length(frame_desc, offset);
   156	
   157			/* Extended descriptor is valid for WLAN queues only */
   158			if (queueno == RSI_WIFI_DATA_Q || queueno == RSI_WIFI_MGMT_Q)
   159				extended_desc = rsi_get_extended_desc(frame_desc,
   160								      offset);
   161	
   162			switch (queueno) {
   163			case RSI_COEX_Q:
   164				if (common->coex_mode > 1)
 > 165					rsi_coex_recv_pkt(common, frame_desc + offset);
   166				else
   167					rsi_mgmt_pkt_recv(common,
   168							  (frame_desc + offset));
   169				break;
   170	
   171			case RSI_WIFI_DATA_Q:
   172				skb = rsi_prepare_skb(common,
   173						      (frame_desc + offset),
   174						      length,
   175						      extended_desc);
   176				if (skb == NULL)
   177					goto fail;
   178	
   179				rsi_indicate_pkt_to_os(common, skb);
   180				break;
   181	
   182			case RSI_WIFI_MGMT_Q:
   183				rsi_mgmt_pkt_recv(common, (frame_desc + offset));
   184				break;
   185	
   186			default:
   187				rsi_dbg(ERR_ZONE, "%s: pkt from invalid queue: %d\n",
   188					__func__,   queueno);
   189				goto fail;
   190			}
   191	
   192			index  += actual_length;
   193			rcv_pkt_len -= actual_length;
   194		} while (rcv_pkt_len > 0);
   195	
   196		return 0;
   197	fail:
   198		return -EINVAL;
   199	}
   200	EXPORT_SYMBOL_GPL(rsi_read_pkt);
   201	
   202	/**
   203	 * rsi_tx_scheduler_thread() - This function is a kernel thread to send the
   204	 *			       packets to the device.
   205	 * @common: Pointer to the driver private structure.
   206	 *
   207	 * Return: None.
   208	 */
   209	static void rsi_tx_scheduler_thread(struct rsi_common *common)
   210	{
   211		struct rsi_hw *adapter = common->priv;
   212		u32 timeout = EVENT_WAIT_FOREVER;
   213	
   214		do {
   215			if (adapter->determine_event_timeout)
   216				timeout = adapter->determine_event_timeout(adapter);
   217			rsi_wait_event(&common->tx_thread.event, timeout);
   218			rsi_reset_event(&common->tx_thread.event);
   219	
   220			if (common->init_done)
   221				rsi_core_qos_processor(common);
   222		} while (atomic_read(&common->tx_thread.thread_done) == 0);
   223		complete_and_exit(&common->tx_thread.completion, 0);
   224	}
   225	
   226	enum rsi_host_intf rsi_get_host_intf(void *priv)
   227	{
   228		struct rsi_common *common = (struct rsi_common *)priv;
   229	
   230		return common->priv->rsi_host_intf;
   231	}
   232	
   233	/**
   234	 * rsi_91x_init() - This function initializes os interface operations.
   235	 * @void: Void.
   236	 *
   237	 * Return: Pointer to the adapter structure on success, NULL on failure .
   238	 */
   239	struct rsi_hw *rsi_91x_init(void)
   240	{
   241		struct rsi_hw *adapter = NULL;
   242		struct rsi_common *common = NULL;
   243		u8 ii = 0;
   244	
   245		adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
   246		if (!adapter)
   247			return NULL;
   248	
   249		adapter->priv = kzalloc(sizeof(*common), GFP_KERNEL);
   250		if (adapter->priv == NULL) {
   251			rsi_dbg(ERR_ZONE, "%s: Failed in allocation of memory\n",
   252				__func__);
   253			kfree(adapter);
   254			return NULL;
   255		} else {
   256			common = adapter->priv;
   257			common->priv = adapter;
   258		}
   259	
   260		for (ii = 0; ii < NUM_SOFT_QUEUES; ii++)
   261			skb_queue_head_init(&common->tx_queue[ii]);
   262	
   263		rsi_init_event(&common->tx_thread.event);
   264		mutex_init(&common->mutex);
   265		mutex_init(&common->tx_lock);
   266		mutex_init(&common->rx_lock);
   267		mutex_init(&common->tx_bus_mutex);
   268	
   269		if (rsi_create_kthread(common,
   270				       &common->tx_thread,
   271				       rsi_tx_scheduler_thread,
   272				       "Tx-Thread")) {
   273			rsi_dbg(ERR_ZONE, "%s: Unable to init tx thrd\n", __func__);
   274			goto err;
   275		}
   276	
   277		rsi_default_ps_params(adapter);
   278		spin_lock_init(&adapter->ps_lock);
   279		timer_setup(&common->roc_timer, rsi_roc_timeout, 0);
   280		init_completion(&common->wlan_init_completion);
   281		common->init_done = true;
   282	
   283		common->coex_mode = RSI_DEV_COEX_MODE_WIFI_ALONE;
   284		common->oper_mode = RSI_DEV_OPMODE_WIFI_ALONE;
   285		adapter->device_model = RSI_DEV_9113;
   286		if (common->coex_mode > 1) {
 > 287			if (rsi_coex_attach(common)) {
   288				rsi_dbg(ERR_ZONE, "Failed to init coex module\n");
   289				goto err;
   290			}
   291		}
   292	
   293		return adapter;
   294	
   295	err:
   296		kfree(common);
   297		kfree(adapter);
   298		return NULL;
   299	}
   300	EXPORT_SYMBOL_GPL(rsi_91x_init);
   301	
   302	/**
   303	 * rsi_91x_deinit() - This function de-intializes os intf operations.
   304	 * @adapter: Pointer to the adapter structure.
   305	 *
   306	 * Return: None.
   307	 */
   308	void rsi_91x_deinit(struct rsi_hw *adapter)
   309	{
   310		struct rsi_common *common = adapter->priv;
   311		u8 ii;
   312	
   313		rsi_dbg(INFO_ZONE, "%s: Performing deinit os ops\n", __func__);
   314	
   315		rsi_kill_thread(&common->tx_thread);
   316	
   317		for (ii = 0; ii < NUM_SOFT_QUEUES; ii++)
   318			skb_queue_purge(&common->tx_queue[ii]);
   319	
   320		common->init_done = false;
   321	
   322		if (common->coex_mode > 1)
 > 323			rsi_coex_detach(common);
   324	
   325		kfree(common);
   326		kfree(adapter->rsi_dev);
   327		kfree(adapter);
   328	}
   329	EXPORT_SYMBOL_GPL(rsi_91x_deinit);
   330	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
kernel test robot Feb. 26, 2018, 6:03 a.m. UTC | #2
Hi Prameela,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on wireless-drivers-next/master]
[also build test ERROR on v4.16-rc3 next-20180223]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Amitkumar-Karwar/rsi-add-bluetooth-and-coex-support/20180226-073244
base:   https://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next.git master
config: x86_64-randconfig-ne0-02261019 (attached as .config)
compiler: gcc-6 (Debian 6.4.0-9) 6.4.0 20171026
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

Note: the linux-review/Amitkumar-Karwar/rsi-add-bluetooth-and-coex-support/20180226-073244 HEAD 9c5222af2b3dbf5143bc1fa4dc0af78fcfa3559d builds fine.
      It only hurts bisectibility.

All errors (new ones prefixed by >>):

   drivers/net/wireless/rsi/rsi_91x_main.c: In function 'rsi_read_pkt':
>> drivers/net/wireless/rsi/rsi_91x_main.c:165:5: error: implicit declaration of function 'rsi_coex_recv_pkt' [-Werror=implicit-function-declaration]
        rsi_coex_recv_pkt(common, frame_desc + offset);
        ^~~~~~~~~~~~~~~~~
   drivers/net/wireless/rsi/rsi_91x_main.c: In function 'rsi_91x_init':
>> drivers/net/wireless/rsi/rsi_91x_main.c:287:7: error: implicit declaration of function 'rsi_coex_attach' [-Werror=implicit-function-declaration]
      if (rsi_coex_attach(common)) {
          ^~~~~~~~~~~~~~~
   drivers/net/wireless/rsi/rsi_91x_main.c: In function 'rsi_91x_deinit':
>> drivers/net/wireless/rsi/rsi_91x_main.c:323:3: error: implicit declaration of function 'rsi_coex_detach' [-Werror=implicit-function-declaration]
      rsi_coex_detach(common);
      ^~~~~~~~~~~~~~~
   cc1: some warnings being treated as errors

vim +/rsi_coex_recv_pkt +165 drivers/net/wireless/rsi/rsi_91x_main.c

   133	
   134	/**
   135	 * rsi_read_pkt() - This function reads frames from the card.
   136	 * @common: Pointer to the driver private structure.
   137	 * @rcv_pkt_len: Received pkt length. In case of USB it is 0.
   138	 *
   139	 * Return: 0 on success, -1 on failure.
   140	 */
   141	int rsi_read_pkt(struct rsi_common *common, u8 *rx_pkt, s32 rcv_pkt_len)
   142	{
   143		u8 *frame_desc = NULL, extended_desc = 0;
   144		u32 index, length = 0, queueno = 0;
   145		u16 actual_length = 0, offset;
   146		struct sk_buff *skb = NULL;
   147	
   148		index = 0;
   149		do {
   150			frame_desc = &rx_pkt[index];
   151			actual_length = *(u16 *)&frame_desc[0];
   152			offset = *(u16 *)&frame_desc[2];
   153	
   154			queueno = rsi_get_queueno(frame_desc, offset);
   155			length = rsi_get_length(frame_desc, offset);
   156	
   157			/* Extended descriptor is valid for WLAN queues only */
   158			if (queueno == RSI_WIFI_DATA_Q || queueno == RSI_WIFI_MGMT_Q)
   159				extended_desc = rsi_get_extended_desc(frame_desc,
   160								      offset);
   161	
   162			switch (queueno) {
   163			case RSI_COEX_Q:
   164				if (common->coex_mode > 1)
 > 165					rsi_coex_recv_pkt(common, frame_desc + offset);
   166				else
   167					rsi_mgmt_pkt_recv(common,
   168							  (frame_desc + offset));
   169				break;
   170	
   171			case RSI_WIFI_DATA_Q:
   172				skb = rsi_prepare_skb(common,
   173						      (frame_desc + offset),
   174						      length,
   175						      extended_desc);
   176				if (skb == NULL)
   177					goto fail;
   178	
   179				rsi_indicate_pkt_to_os(common, skb);
   180				break;
   181	
   182			case RSI_WIFI_MGMT_Q:
   183				rsi_mgmt_pkt_recv(common, (frame_desc + offset));
   184				break;
   185	
   186			default:
   187				rsi_dbg(ERR_ZONE, "%s: pkt from invalid queue: %d\n",
   188					__func__,   queueno);
   189				goto fail;
   190			}
   191	
   192			index  += actual_length;
   193			rcv_pkt_len -= actual_length;
   194		} while (rcv_pkt_len > 0);
   195	
   196		return 0;
   197	fail:
   198		return -EINVAL;
   199	}
   200	EXPORT_SYMBOL_GPL(rsi_read_pkt);
   201	
   202	/**
   203	 * rsi_tx_scheduler_thread() - This function is a kernel thread to send the
   204	 *			       packets to the device.
   205	 * @common: Pointer to the driver private structure.
   206	 *
   207	 * Return: None.
   208	 */
   209	static void rsi_tx_scheduler_thread(struct rsi_common *common)
   210	{
   211		struct rsi_hw *adapter = common->priv;
   212		u32 timeout = EVENT_WAIT_FOREVER;
   213	
   214		do {
   215			if (adapter->determine_event_timeout)
   216				timeout = adapter->determine_event_timeout(adapter);
   217			rsi_wait_event(&common->tx_thread.event, timeout);
   218			rsi_reset_event(&common->tx_thread.event);
   219	
   220			if (common->init_done)
   221				rsi_core_qos_processor(common);
   222		} while (atomic_read(&common->tx_thread.thread_done) == 0);
   223		complete_and_exit(&common->tx_thread.completion, 0);
   224	}
   225	
   226	enum rsi_host_intf rsi_get_host_intf(void *priv)
   227	{
   228		struct rsi_common *common = (struct rsi_common *)priv;
   229	
   230		return common->priv->rsi_host_intf;
   231	}
   232	
   233	/**
   234	 * rsi_91x_init() - This function initializes os interface operations.
   235	 * @void: Void.
   236	 *
   237	 * Return: Pointer to the adapter structure on success, NULL on failure .
   238	 */
   239	struct rsi_hw *rsi_91x_init(void)
   240	{
   241		struct rsi_hw *adapter = NULL;
   242		struct rsi_common *common = NULL;
   243		u8 ii = 0;
   244	
   245		adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
   246		if (!adapter)
   247			return NULL;
   248	
   249		adapter->priv = kzalloc(sizeof(*common), GFP_KERNEL);
   250		if (adapter->priv == NULL) {
   251			rsi_dbg(ERR_ZONE, "%s: Failed in allocation of memory\n",
   252				__func__);
   253			kfree(adapter);
   254			return NULL;
   255		} else {
   256			common = adapter->priv;
   257			common->priv = adapter;
   258		}
   259	
   260		for (ii = 0; ii < NUM_SOFT_QUEUES; ii++)
   261			skb_queue_head_init(&common->tx_queue[ii]);
   262	
   263		rsi_init_event(&common->tx_thread.event);
   264		mutex_init(&common->mutex);
   265		mutex_init(&common->tx_lock);
   266		mutex_init(&common->rx_lock);
   267		mutex_init(&common->tx_bus_mutex);
   268	
   269		if (rsi_create_kthread(common,
   270				       &common->tx_thread,
   271				       rsi_tx_scheduler_thread,
   272				       "Tx-Thread")) {
   273			rsi_dbg(ERR_ZONE, "%s: Unable to init tx thrd\n", __func__);
   274			goto err;
   275		}
   276	
   277		rsi_default_ps_params(adapter);
   278		spin_lock_init(&adapter->ps_lock);
   279		timer_setup(&common->roc_timer, rsi_roc_timeout, 0);
   280		init_completion(&common->wlan_init_completion);
   281		common->init_done = true;
   282	
   283		common->coex_mode = RSI_DEV_COEX_MODE_WIFI_ALONE;
   284		common->oper_mode = RSI_DEV_OPMODE_WIFI_ALONE;
   285		adapter->device_model = RSI_DEV_9113;
   286		if (common->coex_mode > 1) {
 > 287			if (rsi_coex_attach(common)) {
   288				rsi_dbg(ERR_ZONE, "Failed to init coex module\n");
   289				goto err;
   290			}
   291		}
   292	
   293		return adapter;
   294	
   295	err:
   296		kfree(common);
   297		kfree(adapter);
   298		return NULL;
   299	}
   300	EXPORT_SYMBOL_GPL(rsi_91x_init);
   301	
   302	/**
   303	 * rsi_91x_deinit() - This function de-intializes os intf operations.
   304	 * @adapter: Pointer to the adapter structure.
   305	 *
   306	 * Return: None.
   307	 */
   308	void rsi_91x_deinit(struct rsi_hw *adapter)
   309	{
   310		struct rsi_common *common = adapter->priv;
   311		u8 ii;
   312	
   313		rsi_dbg(INFO_ZONE, "%s: Performing deinit os ops\n", __func__);
   314	
   315		rsi_kill_thread(&common->tx_thread);
   316	
   317		for (ii = 0; ii < NUM_SOFT_QUEUES; ii++)
   318			skb_queue_purge(&common->tx_queue[ii]);
   319	
   320		common->init_done = false;
   321	
   322		if (common->coex_mode > 1)
 > 323			rsi_coex_detach(common);
   324	
   325		kfree(common);
   326		kfree(adapter->rsi_dev);
   327		kfree(adapter);
   328	}
   329	EXPORT_SYMBOL_GPL(rsi_91x_deinit);
   330	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
diff mbox

Patch

diff --git a/drivers/net/wireless/rsi/Kconfig b/drivers/net/wireless/rsi/Kconfig
index 7c5e4ca..e6135ee 100644
--- a/drivers/net/wireless/rsi/Kconfig
+++ b/drivers/net/wireless/rsi/Kconfig
@@ -42,4 +42,13 @@  config RSI_USB
 	  This option enables the USB bus support in rsi drivers.
 	  Select M (recommended), if you have a RSI 1x1 wireless module.
 
+config RSI_COEX
+	bool "Redpine Signals WLAN BT Coexistence support"
+	depends on BT_HCIRSI && RSI_91X
+	default y
+	---help---
+	  This option enables the WLAN BT coex support in rsi drivers.
+	  Select M (recommended), if you have want to use this feature
+	  and you have RS9113 module.
+
 endif # WLAN_VENDOR_RSI
diff --git a/drivers/net/wireless/rsi/Makefile b/drivers/net/wireless/rsi/Makefile
index 47c4590..ff87121a 100644
--- a/drivers/net/wireless/rsi/Makefile
+++ b/drivers/net/wireless/rsi/Makefile
@@ -5,6 +5,7 @@  rsi_91x-y			+= rsi_91x_mac80211.o
 rsi_91x-y			+= rsi_91x_mgmt.o
 rsi_91x-y			+= rsi_91x_hal.o
 rsi_91x-y			+= rsi_91x_ps.o
+rsi_91x-$(CONFIG_RSI_COEX)	+= rsi_91x_coex.o
 rsi_91x-$(CONFIG_RSI_DEBUGFS)	+= rsi_91x_debugfs.o
 
 rsi_usb-y			+= rsi_91x_usb.o rsi_91x_usb_ops.o
diff --git a/drivers/net/wireless/rsi/rsi_91x_coex.c b/drivers/net/wireless/rsi/rsi_91x_coex.c
new file mode 100644
index 0000000..c07e839
--- /dev/null
+++ b/drivers/net/wireless/rsi/rsi_91x_coex.c
@@ -0,0 +1,177 @@ 
+/**
+ * Copyright (c) 2018 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "rsi_main.h"
+#include "rsi_coex.h"
+#include "rsi_mgmt.h"
+#include "rsi_hal.h"
+
+static enum rsi_coex_queues rsi_coex_determine_coex_q
+			(struct rsi_coex_ctrl_block *coex_cb)
+{
+	enum rsi_coex_queues q_num = RSI_COEX_Q_INVALID;
+
+	if (skb_queue_len(&coex_cb->coex_tx_qs[RSI_COEX_Q_COMMON]) > 0)
+		q_num = RSI_COEX_Q_COMMON;
+	if (skb_queue_len(&coex_cb->coex_tx_qs[RSI_COEX_Q_BT]) > 0)
+		q_num = RSI_COEX_Q_BT;
+	if (skb_queue_len(&coex_cb->coex_tx_qs[RSI_COEX_Q_WLAN]) > 0)
+		q_num = RSI_COEX_Q_WLAN;
+
+	return q_num;
+}
+
+static void rsi_coex_sched_tx_pkts(struct rsi_coex_ctrl_block *coex_cb)
+{
+	enum rsi_coex_queues coex_q = RSI_COEX_Q_INVALID;
+	struct sk_buff *skb;
+
+	do {
+		coex_q = rsi_coex_determine_coex_q(coex_cb);
+		rsi_dbg(INFO_ZONE, "queue = %d\n", coex_q);
+
+		if (coex_q == RSI_COEX_Q_BT)
+			skb = skb_dequeue(&coex_cb->coex_tx_qs[RSI_COEX_Q_BT]);
+	} while (coex_q != RSI_COEX_Q_INVALID);
+}
+
+static void rsi_coex_scheduler_thread(struct rsi_common *common)
+{
+	struct rsi_coex_ctrl_block *coex_cb =
+		(struct rsi_coex_ctrl_block *)common->coex_cb;
+	u32 timeout = EVENT_WAIT_FOREVER;
+
+	do {
+		rsi_wait_event(&coex_cb->coex_tx_thread.event, timeout);
+		rsi_reset_event(&coex_cb->coex_tx_thread.event);
+
+		rsi_coex_sched_tx_pkts(coex_cb);
+	} while (atomic_read(&coex_cb->coex_tx_thread.thread_done) == 0);
+
+	complete_and_exit(&coex_cb->coex_tx_thread.completion, 0);
+}
+
+int rsi_coex_recv_pkt(struct rsi_common *common, u8 *msg)
+{
+	u8 msg_type = msg[RSI_RX_DESC_MSG_TYPE_OFFSET];
+
+	switch (msg_type) {
+	case COMMON_CARD_READY_IND:
+		rsi_dbg(INFO_ZONE, "common card ready received\n");
+		rsi_handle_card_ready(common, msg);
+		break;
+	case SLEEP_NOTIFY_IND:
+		rsi_dbg(INFO_ZONE, "sleep notify received\n");
+		rsi_mgmt_pkt_recv(common, msg);
+		break;
+	}
+
+	return 0;
+}
+
+static inline int rsi_map_coex_q(u8 hal_queue)
+{
+	switch (hal_queue) {
+	case RSI_COEX_Q:
+		return RSI_COEX_Q_COMMON;
+	case RSI_WLAN_Q:
+		return RSI_COEX_Q_WLAN;
+	case RSI_BT_Q:
+		return RSI_COEX_Q_BT;
+	}
+	return RSI_COEX_Q_INVALID;
+}
+
+int rsi_coex_send_pkt(void *priv, struct sk_buff *skb, u8 hal_queue)
+{
+	struct rsi_common *common = (struct rsi_common *)priv;
+	struct rsi_coex_ctrl_block *coex_cb =
+		(struct rsi_coex_ctrl_block *)common->coex_cb;
+	struct skb_info *tx_params = NULL;
+	enum rsi_coex_queues coex_q;
+	int status;
+
+	coex_q = rsi_map_coex_q(hal_queue);
+	if (coex_q == RSI_COEX_Q_INVALID) {
+		rsi_dbg(ERR_ZONE, "Invalid coex queue\n");
+		return -EINVAL;
+	}
+	if (coex_q != RSI_COEX_Q_COMMON &&
+	    coex_q != RSI_COEX_Q_WLAN) {
+		skb_queue_tail(&coex_cb->coex_tx_qs[coex_q], skb);
+		rsi_set_event(&coex_cb->coex_tx_thread.event);
+		return 0;
+	}
+	if (common->iface_down) {
+		tx_params =
+			(struct skb_info *)&IEEE80211_SKB_CB(skb)->driver_data;
+
+		if (!(tx_params->flags & INTERNAL_MGMT_PKT)) {
+			rsi_indicate_tx_status(common->priv, skb, -EINVAL);
+			return 0;
+		}
+	}
+
+	/* Send packet to hal */
+	if (skb->priority == MGMT_SOFT_Q)
+		status = rsi_send_mgmt_pkt(common, skb);
+	else
+		status = rsi_send_data_pkt(common, skb);
+
+	return status;
+}
+
+int rsi_coex_attach(struct rsi_common *common)
+{
+	struct rsi_coex_ctrl_block *coex_cb;
+	int cnt;
+
+	coex_cb = kzalloc(sizeof(*coex_cb), GFP_KERNEL);
+	if (!coex_cb)
+		return -ENOMEM;
+
+	common->coex_cb = (void *)coex_cb;
+	coex_cb->priv = common;
+
+	/* Initialize co-ex queues */
+	for (cnt = 0; cnt < NUM_COEX_TX_QUEUES; cnt++)
+		skb_queue_head_init(&coex_cb->coex_tx_qs[cnt]);
+	rsi_init_event(&coex_cb->coex_tx_thread.event);
+
+	/* Initialize co-ex thread */
+	if (rsi_create_kthread(common,
+			       &coex_cb->coex_tx_thread,
+			       rsi_coex_scheduler_thread,
+			       "Coex-Tx-Thread")) {
+		rsi_dbg(ERR_ZONE, "%s: Unable to init tx thrd\n", __func__);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+void rsi_coex_detach(struct rsi_common *common)
+{
+	struct rsi_coex_ctrl_block *coex_cb =
+		(struct rsi_coex_ctrl_block *)common->coex_cb;
+	int cnt;
+
+	rsi_kill_thread(&coex_cb->coex_tx_thread);
+
+	for (cnt = 0; cnt < NUM_COEX_TX_QUEUES; cnt++)
+		skb_queue_purge(&coex_cb->coex_tx_qs[cnt]);
+
+	kfree(coex_cb);
+}
diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c
index 1176de6..151d228 100644
--- a/drivers/net/wireless/rsi/rsi_91x_hal.c
+++ b/drivers/net/wireless/rsi/rsi_91x_hal.c
@@ -31,8 +31,15 @@  int rsi_send_pkt_to_bus(struct rsi_common *common, struct sk_buff *skb)
 	struct rsi_hw *adapter = common->priv;
 	int status;
 
+	if (common->coex_mode > 1)
+		mutex_lock(&common->tx_bus_mutex);
+
 	status = adapter->host_intf_ops->write_pkt(common->priv,
 						   skb->data, skb->len);
+
+	if (common->coex_mode > 1)
+		mutex_unlock(&common->tx_bus_mutex);
+
 	return status;
 }
 
@@ -296,8 +303,7 @@  int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb)
 	if (status)
 		goto err;
 
-	status = adapter->host_intf_ops->write_pkt(common->priv, skb->data,
-						   skb->len);
+	status = rsi_send_pkt_to_bus(common, skb);
 	if (status)
 		rsi_dbg(ERR_ZONE, "%s: Failed to write pkt\n", __func__);
 
@@ -342,8 +348,7 @@  int rsi_send_mgmt_pkt(struct rsi_common *common,
 		goto err;
 
 	rsi_prepare_mgmt_desc(common, skb);
-	status = adapter->host_intf_ops->write_pkt(common->priv,
-						   (u8 *)skb->data, skb->len);
+	status = rsi_send_pkt_to_bus(common, skb);
 	if (status)
 		rsi_dbg(ERR_ZONE, "%s: Failed to write the packet\n", __func__);
 
@@ -926,10 +931,6 @@  int rsi_hal_device_init(struct rsi_hw *adapter)
 {
 	struct rsi_common *common = adapter->priv;
 
-	common->coex_mode = RSI_DEV_COEX_MODE_WIFI_ALONE;
-	common->oper_mode = RSI_DEV_OPMODE_WIFI_ALONE;
-	adapter->device_model = RSI_DEV_9113;
-
 	switch (adapter->device_model) {
 	case RSI_DEV_9113:
 		if (rsi_load_firmware(adapter)) {
diff --git a/drivers/net/wireless/rsi/rsi_91x_main.c b/drivers/net/wireless/rsi/rsi_91x_main.c
index 0413af8..fe08ebc 100644
--- a/drivers/net/wireless/rsi/rsi_91x_main.c
+++ b/drivers/net/wireless/rsi/rsi_91x_main.c
@@ -20,6 +20,7 @@ 
 #include <linux/firmware.h>
 #include "rsi_mgmt.h"
 #include "rsi_common.h"
+#include "rsi_coex.h"
 #include "rsi_hal.h"
 
 u32 rsi_zone_enabled = /* INFO_ZONE |
@@ -160,8 +161,13 @@  int rsi_read_pkt(struct rsi_common *common, u8 *rx_pkt, s32 rcv_pkt_len)
 
 		switch (queueno) {
 		case RSI_COEX_Q:
-			rsi_mgmt_pkt_recv(common, (frame_desc + offset));
+			if (common->coex_mode > 1)
+				rsi_coex_recv_pkt(common, frame_desc + offset);
+			else
+				rsi_mgmt_pkt_recv(common,
+						  (frame_desc + offset));
 			break;
+
 		case RSI_WIFI_DATA_Q:
 			skb = rsi_prepare_skb(common,
 					      (frame_desc + offset),
@@ -217,6 +223,13 @@  static void rsi_tx_scheduler_thread(struct rsi_common *common)
 	complete_and_exit(&common->tx_thread.completion, 0);
 }
 
+enum rsi_host_intf rsi_get_host_intf(void *priv)
+{
+	struct rsi_common *common = (struct rsi_common *)priv;
+
+	return common->priv->rsi_host_intf;
+}
+
 /**
  * rsi_91x_init() - This function initializes os interface operations.
  * @void: Void.
@@ -251,6 +264,7 @@  struct rsi_hw *rsi_91x_init(void)
 	mutex_init(&common->mutex);
 	mutex_init(&common->tx_lock);
 	mutex_init(&common->rx_lock);
+	mutex_init(&common->tx_bus_mutex);
 
 	if (rsi_create_kthread(common,
 			       &common->tx_thread,
@@ -265,6 +279,17 @@  struct rsi_hw *rsi_91x_init(void)
 	timer_setup(&common->roc_timer, rsi_roc_timeout, 0);
 	init_completion(&common->wlan_init_completion);
 	common->init_done = true;
+
+	common->coex_mode = RSI_DEV_COEX_MODE_WIFI_ALONE;
+	common->oper_mode = RSI_DEV_OPMODE_WIFI_ALONE;
+	adapter->device_model = RSI_DEV_9113;
+	if (common->coex_mode > 1) {
+		if (rsi_coex_attach(common)) {
+			rsi_dbg(ERR_ZONE, "Failed to init coex module\n");
+			goto err;
+		}
+	}
+
 	return adapter;
 
 err:
@@ -294,6 +319,9 @@  void rsi_91x_deinit(struct rsi_hw *adapter)
 
 	common->init_done = false;
 
+	if (common->coex_mode > 1)
+		rsi_coex_detach(common);
+
 	kfree(common);
 	kfree(adapter->rsi_dev);
 	kfree(adapter);
diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
index 46c9d54..c21fca7 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
@@ -1791,7 +1791,7 @@  static int rsi_handle_ta_confirm_type(struct rsi_common *common,
 	return -EINVAL;
 }
 
-static int rsi_handle_card_ready(struct rsi_common *common, u8 *msg)
+int rsi_handle_card_ready(struct rsi_common *common, u8 *msg)
 {
 	switch (common->fsm_state) {
 	case FSM_CARD_NOT_READY:
diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c
index b0cf411..ba38c6d 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c
@@ -18,6 +18,7 @@ 
 #include <linux/module.h>
 #include "rsi_sdio.h"
 #include "rsi_common.h"
+#include "rsi_coex.h"
 #include "rsi_hal.h"
 
 /**
diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c
index 9ab86fb..b33a05f 100644
--- a/drivers/net/wireless/rsi/rsi_91x_usb.c
+++ b/drivers/net/wireless/rsi/rsi_91x_usb.c
@@ -16,8 +16,10 @@ 
  */
 
 #include <linux/module.h>
+#include <net/rsi_91x.h>
 #include "rsi_usb.h"
 #include "rsi_hal.h"
+#include "rsi_coex.h"
 
 /**
  * rsi_usb_card_write() - This function writes to the USB Card.
diff --git a/drivers/net/wireless/rsi/rsi_coex.h b/drivers/net/wireless/rsi/rsi_coex.h
new file mode 100644
index 0000000..0fdc67f
--- /dev/null
+++ b/drivers/net/wireless/rsi/rsi_coex.h
@@ -0,0 +1,37 @@ 
+/**
+ * Copyright (c) 2018 Redpine Signals Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __RSI_COEX_H__
+#define __RSI_COEX_H__
+
+#include "rsi_common.h"
+
+#ifdef CONFIG_RSI_COEX
+#define COMMON_CARD_READY_IND           0
+#define NUM_COEX_TX_QUEUES              5
+
+struct rsi_coex_ctrl_block {
+	struct rsi_common *priv;
+	struct sk_buff_head coex_tx_qs[NUM_COEX_TX_QUEUES];
+	struct rsi_thread coex_tx_thread;
+};
+
+int rsi_coex_attach(struct rsi_common *common);
+void rsi_coex_detach(struct rsi_common *common);
+int rsi_coex_send_pkt(void *priv, struct sk_buff *skb, u8 proto_type);
+int rsi_coex_recv_pkt(struct rsi_common *common, u8 *msg);
+#endif
+#endif
diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h
index b0f4e2c..99a00a3 100644
--- a/drivers/net/wireless/rsi/rsi_main.h
+++ b/drivers/net/wireless/rsi/rsi_main.h
@@ -206,6 +206,7 @@  struct rsi_common {
 	struct rsi_hw *priv;
 	struct vif_priv vif_info[RSI_MAX_VIFS];
 
+	void *coex_cb;
 	bool mgmt_q_block;
 	struct version_info lmac_ver;
 
@@ -270,6 +271,8 @@  struct rsi_common {
 	u8 obm_ant_sel_val;
 	int tx_power;
 	u8 ant_in_use;
+	/* Mutex used for writing packet to bus */
+	struct mutex tx_bus_mutex;
 	bool hibernate_resume;
 	bool reinit_hw;
 	u8 wow_flags;
@@ -359,4 +362,7 @@  struct rsi_host_intf_ops {
 				      u8 *fw);
 	int (*reinit_device)(struct rsi_hw *adapter);
 };
+
+enum rsi_host_intf rsi_get_host_intf(void *priv);
+
 #endif
diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h
index 389094a..cf6567a 100644
--- a/drivers/net/wireless/rsi/rsi_mgmt.h
+++ b/drivers/net/wireless/rsi/rsi_mgmt.h
@@ -57,12 +57,14 @@ 
 #define WOW_PATTERN_SIZE 256
 
 /* Receive Frame Types */
+#define RSI_RX_DESC_MSG_TYPE_OFFSET	2
 #define TA_CONFIRM_TYPE                 0x01
 #define RX_DOT11_MGMT                   0x02
 #define TX_STATUS_IND                   0x04
 #define BEACON_EVENT_IND		0x08
 #define PROBEREQ_CONFIRM                2
 #define CARD_READY_IND                  0x00
+#define SLEEP_NOTIFY_IND                0x06
 
 #define RSI_DELETE_PEER                 0x0
 #define RSI_ADD_PEER                    0x1
@@ -638,6 +640,7 @@  static inline void rsi_set_len_qno(__le16 *addr, u16 len, u8 qno)
 	*addr = cpu_to_le16(len | ((qno & 7) << 12));
 }
 
+int rsi_handle_card_ready(struct rsi_common *common, u8 *msg);
 int rsi_mgmt_pkt_recv(struct rsi_common *common, u8 *msg);
 int rsi_set_vap_capabilities(struct rsi_common *common, enum opmode mode,
 			     u8 *mac_addr, u8 vap_id, u8 vap_status);
diff --git a/include/net/rsi_91x.h b/include/net/rsi_91x.h
index 16a447b..737ab4e 100644
--- a/include/net/rsi_91x.h
+++ b/include/net/rsi_91x.h
@@ -17,6 +17,8 @@ 
 #ifndef __RSI_HEADER_H__
 #define __RSI_HEADER_H__
 
+#include <linux/skbuff.h>
+
 /* HAL queue information */
 #define RSI_COEX_Q			0x0
 #define RSI_BT_Q			0x2
@@ -26,9 +28,27 @@ 
 #define RSI_BT_MGMT_Q			0x6
 #define RSI_BT_DATA_Q			0x7
 
+enum rsi_coex_queues {
+	RSI_COEX_Q_INVALID = -1,
+	RSI_COEX_Q_COMMON = 0,
+	RSI_COEX_Q_BT,
+	RSI_COEX_Q_WLAN
+};
+
 enum rsi_host_intf {
 	RSI_HOST_INTF_SDIO = 0,
 	RSI_HOST_INTF_USB
 };
 
+struct rsi_proto_ops {
+	int (*coex_send_pkt)(void *priv, struct sk_buff *skb, u8 hal_queue);
+	enum rsi_host_intf (*get_host_intf)(void *priv);
+	void (*set_bt_context)(void *priv, void *context);
+};
+
+struct rsi_mod_ops {
+	int (*attach)(void *priv, struct rsi_proto_ops *ops);
+	void (*detach)(void *priv);
+	int (*recv_pkt)(void *priv, u8 *msg);
+};
 #endif