Skip to content

Commit

Permalink
rsi: add coex support
Browse files Browse the repository at this point in the history
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>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
  • Loading branch information
Prameela Rani Garnepudi authored and Kalle Valo committed Mar 13, 2018
1 parent 4c10d56 commit 2108df3
Show file tree
Hide file tree
Showing 12 changed files with 303 additions and 10 deletions.
9 changes: 9 additions & 0 deletions drivers/net/wireless/rsi/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 1 addition & 0 deletions drivers/net/wireless/rsi/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
177 changes: 177 additions & 0 deletions drivers/net/wireless/rsi/rsi_91x_coex.c
Original file line number Diff line number Diff line change
@@ -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);
}
17 changes: 9 additions & 8 deletions drivers/net/wireless/rsi/rsi_91x_hal.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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__);

Expand Down Expand Up @@ -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__);

Expand Down Expand Up @@ -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)) {
Expand Down
38 changes: 37 additions & 1 deletion drivers/net/wireless/rsi/rsi_91x_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down Expand Up @@ -160,8 +161,15 @@ 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));
#ifdef CONFIG_RSI_COEX
if (common->coex_mode > 1)
rsi_coex_recv_pkt(common, frame_desc + offset);
else
#endif
rsi_mgmt_pkt_recv(common,
(frame_desc + offset));
break;

case RSI_WIFI_DATA_Q:
skb = rsi_prepare_skb(common,
(frame_desc + offset),
Expand Down Expand Up @@ -217,6 +225,15 @@ static void rsi_tx_scheduler_thread(struct rsi_common *common)
complete_and_exit(&common->tx_thread.completion, 0);
}

#ifdef CONFIG_RSI_COEX
enum rsi_host_intf rsi_get_host_intf(void *priv)
{
struct rsi_common *common = (struct rsi_common *)priv;

return common->priv->rsi_host_intf;
}
#endif

/**
* rsi_91x_init() - This function initializes os interface operations.
* @void: Void.
Expand Down Expand Up @@ -251,6 +268,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,
Expand All @@ -265,6 +283,19 @@ 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;
#ifdef CONFIG_RSI_COEX
if (common->coex_mode > 1) {
if (rsi_coex_attach(common)) {
rsi_dbg(ERR_ZONE, "Failed to init coex module\n");
goto err;
}
}
#endif

return adapter;

err:
Expand Down Expand Up @@ -294,6 +325,11 @@ void rsi_91x_deinit(struct rsi_hw *adapter)

common->init_done = false;

#ifdef CONFIG_RSI_COEX
if (common->coex_mode > 1)
rsi_coex_detach(common);
#endif

kfree(common);
kfree(adapter->rsi_dev);
kfree(adapter);
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/wireless/rsi/rsi_91x_mgmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
1 change: 1 addition & 0 deletions drivers/net/wireless/rsi/rsi_91x_sdio.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <linux/module.h>
#include "rsi_sdio.h"
#include "rsi_common.h"
#include "rsi_coex.h"
#include "rsi_hal.h"

/**
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/wireless/rsi/rsi_91x_usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
37 changes: 37 additions & 0 deletions drivers/net/wireless/rsi/rsi_coex.h
Original file line number Diff line number Diff line change
@@ -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
Loading

0 comments on commit 2108df3

Please sign in to comment.