rsi: handle BT traffic in driver
authorSiva Rebbagondla <siva.rebbagondla@redpinesignals.com>
Tue, 27 Feb 2018 14:26:16 +0000 (19:56 +0530)
committerKalle Valo <kvalo@codeaurora.org>
Tue, 13 Mar 2018 16:37:06 +0000 (18:37 +0200)
BT frames are passed through coex and hal modules to BUS.
After firmware is loaded, based on the operating mode CARD
READY frame comes for each protocol. When BT card ready is
received, BT attach is called.
Protocol operations are exchanged between the modules
at initialization time.
Build flag CONFIG_RSI_COEX is introduced to enable coex support
if CONFIG_BT_RSIHCI is enabled. Coex operations are valid if
coex mode is greater than 1 only.

Signed-off-by: Siva Rebbagondla <siva.rebbagondla@redpinesignals.com>
Signed-off-by: Prameela Rani Garnepudi <prameela.j04cs@gmail.com>
Signed-off-by: Amitkumar Karwar <amit.karwar@redpinesignals.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
drivers/net/wireless/rsi/rsi_91x_coex.c
drivers/net/wireless/rsi/rsi_91x_core.c
drivers/net/wireless/rsi/rsi_91x_hal.c
drivers/net/wireless/rsi/rsi_91x_main.c
drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
drivers/net/wireless/rsi/rsi_common.h
drivers/net/wireless/rsi/rsi_hal.h
drivers/net/wireless/rsi/rsi_main.h

index c07e839017ea0c0284af29d36cac383af578b464..d055099dadf17f29c5867b1fe27412f0f83fad9f 100644 (file)
@@ -43,8 +43,10 @@ static void rsi_coex_sched_tx_pkts(struct rsi_coex_ctrl_block *coex_cb)
                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)
+               if (coex_q == RSI_COEX_Q_BT) {
                        skb = skb_dequeue(&coex_cb->coex_tx_qs[RSI_COEX_Q_BT]);
+                       rsi_send_bt_pkt(coex_cb->priv, skb);
+               }
        } while (coex_q != RSI_COEX_Q_INVALID);
 }
 
index d0d2201830e8bbeaf8fd13cf2dd86d03d151f6fb..5dafd2e1306cbb76998a2a7f12fc890542129efc 100644 (file)
@@ -17,6 +17,7 @@
 #include "rsi_mgmt.h"
 #include "rsi_common.h"
 #include "rsi_hal.h"
+#include "rsi_coex.h"
 
 /**
  * rsi_determine_min_weight_queue() - This function determines the queue with
@@ -301,14 +302,23 @@ void rsi_core_qos_processor(struct rsi_common *common)
                        mutex_unlock(&common->tx_lock);
                        break;
                }
-
-               if (q_num == MGMT_SOFT_Q) {
-                       status = rsi_send_mgmt_pkt(common, skb);
-               } else if (q_num == MGMT_BEACON_Q) {
+               if (q_num == MGMT_BEACON_Q) {
                        status = rsi_send_pkt_to_bus(common, skb);
                        dev_kfree_skb(skb);
                } else {
-                       status = rsi_send_data_pkt(common, skb);
+#ifdef CONFIG_RSI_COEX
+                       if (common->coex_mode > 1) {
+                               status = rsi_coex_send_pkt(common, skb,
+                                                          RSI_WLAN_Q);
+                       } else {
+#endif
+                               if (q_num == MGMT_SOFT_Q)
+                                       status = rsi_send_mgmt_pkt(common, skb);
+                               else
+                                       status = rsi_send_data_pkt(common, skb);
+#ifdef CONFIG_RSI_COEX
+                       }
+#endif
                }
 
                if (status) {
index 151d228a61676092fe7d3bdddcb71f1efe83a181..de608ae365a45fa4fe20cb17c6c5fddaa2669621 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <linux/firmware.h>
+#include <net/bluetooth/bluetooth.h>
 #include "rsi_mgmt.h"
 #include "rsi_hal.h"
 #include "rsi_sdio.h"
@@ -24,6 +25,7 @@
 static struct ta_metadata metadata_flash_content[] = {
        {"flash_content", 0x00010000},
        {"rsi/rs9113_wlan_qspi.rps", 0x00010000},
+       {"rsi/rs9113_wlan_bt_dual_mode.rps", 0x00010000},
 };
 
 int rsi_send_pkt_to_bus(struct rsi_common *common, struct sk_buff *skb)
@@ -357,6 +359,43 @@ err:
        return status;
 }
 
+int rsi_send_bt_pkt(struct rsi_common *common, struct sk_buff *skb)
+{
+       int status = -EINVAL;
+       u8 header_size = 0;
+       struct rsi_bt_desc *bt_desc;
+       u8 queueno = ((skb->data[1] >> 4) & 0xf);
+
+       if (queueno == RSI_BT_MGMT_Q) {
+               status = rsi_send_pkt_to_bus(common, skb);
+               if (status)
+                       rsi_dbg(ERR_ZONE, "%s: Failed to write bt mgmt pkt\n",
+                               __func__);
+               goto out;
+       }
+       header_size = FRAME_DESC_SZ;
+       if (header_size > skb_headroom(skb)) {
+               rsi_dbg(ERR_ZONE, "%s: Not enough headroom\n", __func__);
+               status = -ENOSPC;
+               goto out;
+       }
+       skb_push(skb, header_size);
+       memset(skb->data, 0, header_size);
+       bt_desc = (struct rsi_bt_desc *)skb->data;
+
+       rsi_set_len_qno(&bt_desc->len_qno, (skb->len - FRAME_DESC_SZ),
+                       RSI_BT_DATA_Q);
+       bt_desc->bt_pkt_type = cpu_to_le16(bt_cb(skb)->pkt_type);
+
+       status = rsi_send_pkt_to_bus(common, skb);
+       if (status)
+               rsi_dbg(ERR_ZONE, "%s: Failed to write bt pkt\n", __func__);
+
+out:
+       dev_kfree_skb(skb);
+       return status;
+}
+
 int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb)
 {
        struct rsi_hw *adapter = (struct rsi_hw *)common->priv;
index 641c388b5666ca8575f76510cf052a9fddf82e82..b3e7d75dafae8f46b4507e88a8e5e55a777762f0 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <linux/module.h>
 #include <linux/firmware.h>
+#include <net/rsi_91x.h>
 #include "rsi_mgmt.h"
 #include "rsi_common.h"
 #include "rsi_coex.h"
@@ -35,6 +36,14 @@ u32 rsi_zone_enabled = /* INFO_ZONE |
                        0;
 EXPORT_SYMBOL_GPL(rsi_zone_enabled);
 
+#ifdef CONFIG_RSI_COEX
+static struct rsi_proto_ops g_proto_ops = {
+       .coex_send_pkt = rsi_coex_send_pkt,
+       .get_host_intf = rsi_get_host_intf,
+       .set_bt_context = rsi_set_bt_context,
+};
+#endif
+
 /**
  * rsi_dbg() - This function outputs informational messages.
  * @zone: Zone of interest for output message.
@@ -144,6 +153,9 @@ int rsi_read_pkt(struct rsi_common *common, u8 *rx_pkt, s32 rcv_pkt_len)
        u32 index, length = 0, queueno = 0;
        u16 actual_length = 0, offset;
        struct sk_buff *skb = NULL;
+#ifdef CONFIG_RSI_COEX
+       u8 bt_pkt_type;
+#endif
 
        index = 0;
        do {
@@ -185,6 +197,25 @@ int rsi_read_pkt(struct rsi_common *common, u8 *rx_pkt, s32 rcv_pkt_len)
                        rsi_mgmt_pkt_recv(common, (frame_desc + offset));
                        break;
 
+#ifdef CONFIG_RSI_COEX
+               case RSI_BT_MGMT_Q:
+               case RSI_BT_DATA_Q:
+#define BT_RX_PKT_TYPE_OFST    14
+#define BT_CARD_READY_IND      0x89
+                       bt_pkt_type = frame_desc[offset + BT_RX_PKT_TYPE_OFST];
+                       if (bt_pkt_type == BT_CARD_READY_IND) {
+                               rsi_dbg(INFO_ZONE, "BT Card ready recvd\n");
+                               if (rsi_bt_ops.attach(common, &g_proto_ops))
+                                       rsi_dbg(ERR_ZONE,
+                                               "Failed to attach BT module\n");
+                       } else {
+                               if (common->bt_adapter)
+                                       rsi_bt_ops.recv_pkt(common->bt_adapter,
+                                                       frame_desc + offset);
+                       }
+                       break;
+#endif
+
                default:
                        rsi_dbg(ERR_ZONE, "%s: pkt from invalid queue: %d\n",
                                __func__,   queueno);
@@ -232,6 +263,13 @@ enum rsi_host_intf rsi_get_host_intf(void *priv)
 
        return common->priv->rsi_host_intf;
 }
+
+void rsi_set_bt_context(void *priv, void *bt_context)
+{
+       struct rsi_common *common = (struct rsi_common *)priv;
+
+       common->bt_adapter = bt_context;
+}
 #endif
 
 /**
@@ -323,13 +361,18 @@ void rsi_91x_deinit(struct rsi_hw *adapter)
        for (ii = 0; ii < NUM_SOFT_QUEUES; ii++)
                skb_queue_purge(&common->tx_queue[ii]);
 
-       common->init_done = false;
-
 #ifdef CONFIG_RSI_COEX
-       if (common->coex_mode > 1)
+       if (common->coex_mode > 1) {
+               if (common->bt_adapter) {
+                       rsi_bt_ops.detach(common->bt_adapter);
+                       common->bt_adapter = NULL;
+               }
                rsi_coex_detach(common);
+       }
 #endif
 
+       common->init_done = false;
+
        kfree(common);
        kfree(adapter->rsi_dev);
        kfree(adapter);
index 9fbc0ef82559983674f2d3d56bf554ad5d46b824..169c98125202aa900d88453b909ebf8d11d28cb4 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 #include <linux/firmware.h>
+#include <net/rsi_91x.h>
 #include "rsi_sdio.h"
 #include "rsi_common.h"
 
index 1d8af419fb1f1dca2da3a6f49675c768861a5a38..461658522d0fab56984068e5d292ed73e74b63c1 100644 (file)
@@ -62,6 +62,7 @@ static inline int rsi_create_kthread(struct rsi_common *common,
                                     u8 *name)
 {
        init_completion(&thread->completion);
+       atomic_set(&thread->thread_done, 0);
        thread->task = kthread_run(func_ptr, common, "%s", name);
        if (IS_ERR(thread->task))
                return (int)PTR_ERR(thread->task);
index a09d36b6b765b3d865e6a6e6ae7f432175988e68..e7122239f969777218d31b499dc2b8ccf5d9dce2 100644 (file)
@@ -145,8 +145,18 @@ struct rsi_data_desc {
        u8 sta_id;
 } __packed;
 
+struct rsi_bt_desc {
+       __le16 len_qno;
+       __le16 reserved1;
+       __le32 reserved2;
+       __le32 reserved3;
+       __le16 reserved4;
+       __le16 bt_pkt_type;
+} __packed;
+
 int rsi_hal_device_init(struct rsi_hw *adapter);
 int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb);
 int rsi_send_pkt_to_bus(struct rsi_common *common, struct sk_buff *skb);
+int rsi_send_bt_pkt(struct rsi_common *common, struct sk_buff *skb);
 
 #endif
index 99a00a3ccaa477904b43fd648dc2ec3fed4ef005..47af0cb9de1d0c8b47acb637ed1e04c7b749c3bd 100644 (file)
@@ -291,6 +291,8 @@ struct rsi_common {
        bool p2p_enabled;
        struct timer_list roc_timer;
        struct ieee80211_vif *roc_vif;
+
+       void *bt_adapter;
 };
 
 struct eepromrw_info {
@@ -364,5 +366,6 @@ struct rsi_host_intf_ops {
 };
 
 enum rsi_host_intf rsi_get_host_intf(void *priv);
+void rsi_set_bt_context(void *priv, void *bt_context);
 
 #endif