Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rsi: add coex support

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>

authored by

Prameela Rani Garnepudi and committed by
Kalle Valo
2108df3c 4c10d56a

+303 -10
+9
drivers/net/wireless/rsi/Kconfig
··· 42 42 This option enables the USB bus support in rsi drivers. 43 43 Select M (recommended), if you have a RSI 1x1 wireless module. 44 44 45 + config RSI_COEX 46 + bool "Redpine Signals WLAN BT Coexistence support" 47 + depends on BT_HCIRSI && RSI_91X 48 + default y 49 + ---help--- 50 + This option enables the WLAN BT coex support in rsi drivers. 51 + Select M (recommended), if you have want to use this feature 52 + and you have RS9113 module. 53 + 45 54 endif # WLAN_VENDOR_RSI
+1
drivers/net/wireless/rsi/Makefile
··· 5 5 rsi_91x-y += rsi_91x_mgmt.o 6 6 rsi_91x-y += rsi_91x_hal.o 7 7 rsi_91x-y += rsi_91x_ps.o 8 + rsi_91x-$(CONFIG_RSI_COEX) += rsi_91x_coex.o 8 9 rsi_91x-$(CONFIG_RSI_DEBUGFS) += rsi_91x_debugfs.o 9 10 10 11 rsi_usb-y += rsi_91x_usb.o rsi_91x_usb_ops.o
+177
drivers/net/wireless/rsi/rsi_91x_coex.c
··· 1 + /** 2 + * Copyright (c) 2018 Redpine Signals Inc. 3 + * 4 + * Permission to use, copy, modify, and/or distribute this software for any 5 + * purpose with or without fee is hereby granted, provided that the above 6 + * copyright notice and this permission notice appear in all copies. 7 + * 8 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + */ 16 + 17 + #include "rsi_main.h" 18 + #include "rsi_coex.h" 19 + #include "rsi_mgmt.h" 20 + #include "rsi_hal.h" 21 + 22 + static enum rsi_coex_queues rsi_coex_determine_coex_q 23 + (struct rsi_coex_ctrl_block *coex_cb) 24 + { 25 + enum rsi_coex_queues q_num = RSI_COEX_Q_INVALID; 26 + 27 + if (skb_queue_len(&coex_cb->coex_tx_qs[RSI_COEX_Q_COMMON]) > 0) 28 + q_num = RSI_COEX_Q_COMMON; 29 + if (skb_queue_len(&coex_cb->coex_tx_qs[RSI_COEX_Q_BT]) > 0) 30 + q_num = RSI_COEX_Q_BT; 31 + if (skb_queue_len(&coex_cb->coex_tx_qs[RSI_COEX_Q_WLAN]) > 0) 32 + q_num = RSI_COEX_Q_WLAN; 33 + 34 + return q_num; 35 + } 36 + 37 + static void rsi_coex_sched_tx_pkts(struct rsi_coex_ctrl_block *coex_cb) 38 + { 39 + enum rsi_coex_queues coex_q = RSI_COEX_Q_INVALID; 40 + struct sk_buff *skb; 41 + 42 + do { 43 + coex_q = rsi_coex_determine_coex_q(coex_cb); 44 + rsi_dbg(INFO_ZONE, "queue = %d\n", coex_q); 45 + 46 + if (coex_q == RSI_COEX_Q_BT) 47 + skb = skb_dequeue(&coex_cb->coex_tx_qs[RSI_COEX_Q_BT]); 48 + } while (coex_q != RSI_COEX_Q_INVALID); 49 + } 50 + 51 + static void rsi_coex_scheduler_thread(struct rsi_common *common) 52 + { 53 + struct rsi_coex_ctrl_block *coex_cb = 54 + (struct rsi_coex_ctrl_block *)common->coex_cb; 55 + u32 timeout = EVENT_WAIT_FOREVER; 56 + 57 + do { 58 + rsi_wait_event(&coex_cb->coex_tx_thread.event, timeout); 59 + rsi_reset_event(&coex_cb->coex_tx_thread.event); 60 + 61 + rsi_coex_sched_tx_pkts(coex_cb); 62 + } while (atomic_read(&coex_cb->coex_tx_thread.thread_done) == 0); 63 + 64 + complete_and_exit(&coex_cb->coex_tx_thread.completion, 0); 65 + } 66 + 67 + int rsi_coex_recv_pkt(struct rsi_common *common, u8 *msg) 68 + { 69 + u8 msg_type = msg[RSI_RX_DESC_MSG_TYPE_OFFSET]; 70 + 71 + switch (msg_type) { 72 + case COMMON_CARD_READY_IND: 73 + rsi_dbg(INFO_ZONE, "common card ready received\n"); 74 + rsi_handle_card_ready(common, msg); 75 + break; 76 + case SLEEP_NOTIFY_IND: 77 + rsi_dbg(INFO_ZONE, "sleep notify received\n"); 78 + rsi_mgmt_pkt_recv(common, msg); 79 + break; 80 + } 81 + 82 + return 0; 83 + } 84 + 85 + static inline int rsi_map_coex_q(u8 hal_queue) 86 + { 87 + switch (hal_queue) { 88 + case RSI_COEX_Q: 89 + return RSI_COEX_Q_COMMON; 90 + case RSI_WLAN_Q: 91 + return RSI_COEX_Q_WLAN; 92 + case RSI_BT_Q: 93 + return RSI_COEX_Q_BT; 94 + } 95 + return RSI_COEX_Q_INVALID; 96 + } 97 + 98 + int rsi_coex_send_pkt(void *priv, struct sk_buff *skb, u8 hal_queue) 99 + { 100 + struct rsi_common *common = (struct rsi_common *)priv; 101 + struct rsi_coex_ctrl_block *coex_cb = 102 + (struct rsi_coex_ctrl_block *)common->coex_cb; 103 + struct skb_info *tx_params = NULL; 104 + enum rsi_coex_queues coex_q; 105 + int status; 106 + 107 + coex_q = rsi_map_coex_q(hal_queue); 108 + if (coex_q == RSI_COEX_Q_INVALID) { 109 + rsi_dbg(ERR_ZONE, "Invalid coex queue\n"); 110 + return -EINVAL; 111 + } 112 + if (coex_q != RSI_COEX_Q_COMMON && 113 + coex_q != RSI_COEX_Q_WLAN) { 114 + skb_queue_tail(&coex_cb->coex_tx_qs[coex_q], skb); 115 + rsi_set_event(&coex_cb->coex_tx_thread.event); 116 + return 0; 117 + } 118 + if (common->iface_down) { 119 + tx_params = 120 + (struct skb_info *)&IEEE80211_SKB_CB(skb)->driver_data; 121 + 122 + if (!(tx_params->flags & INTERNAL_MGMT_PKT)) { 123 + rsi_indicate_tx_status(common->priv, skb, -EINVAL); 124 + return 0; 125 + } 126 + } 127 + 128 + /* Send packet to hal */ 129 + if (skb->priority == MGMT_SOFT_Q) 130 + status = rsi_send_mgmt_pkt(common, skb); 131 + else 132 + status = rsi_send_data_pkt(common, skb); 133 + 134 + return status; 135 + } 136 + 137 + int rsi_coex_attach(struct rsi_common *common) 138 + { 139 + struct rsi_coex_ctrl_block *coex_cb; 140 + int cnt; 141 + 142 + coex_cb = kzalloc(sizeof(*coex_cb), GFP_KERNEL); 143 + if (!coex_cb) 144 + return -ENOMEM; 145 + 146 + common->coex_cb = (void *)coex_cb; 147 + coex_cb->priv = common; 148 + 149 + /* Initialize co-ex queues */ 150 + for (cnt = 0; cnt < NUM_COEX_TX_QUEUES; cnt++) 151 + skb_queue_head_init(&coex_cb->coex_tx_qs[cnt]); 152 + rsi_init_event(&coex_cb->coex_tx_thread.event); 153 + 154 + /* Initialize co-ex thread */ 155 + if (rsi_create_kthread(common, 156 + &coex_cb->coex_tx_thread, 157 + rsi_coex_scheduler_thread, 158 + "Coex-Tx-Thread")) { 159 + rsi_dbg(ERR_ZONE, "%s: Unable to init tx thrd\n", __func__); 160 + return -EINVAL; 161 + } 162 + return 0; 163 + } 164 + 165 + void rsi_coex_detach(struct rsi_common *common) 166 + { 167 + struct rsi_coex_ctrl_block *coex_cb = 168 + (struct rsi_coex_ctrl_block *)common->coex_cb; 169 + int cnt; 170 + 171 + rsi_kill_thread(&coex_cb->coex_tx_thread); 172 + 173 + for (cnt = 0; cnt < NUM_COEX_TX_QUEUES; cnt++) 174 + skb_queue_purge(&coex_cb->coex_tx_qs[cnt]); 175 + 176 + kfree(coex_cb); 177 + }
+9 -8
drivers/net/wireless/rsi/rsi_91x_hal.c
··· 31 31 struct rsi_hw *adapter = common->priv; 32 32 int status; 33 33 34 + if (common->coex_mode > 1) 35 + mutex_lock(&common->tx_bus_mutex); 36 + 34 37 status = adapter->host_intf_ops->write_pkt(common->priv, 35 38 skb->data, skb->len); 39 + 40 + if (common->coex_mode > 1) 41 + mutex_unlock(&common->tx_bus_mutex); 42 + 36 43 return status; 37 44 } 38 45 ··· 303 296 if (status) 304 297 goto err; 305 298 306 - status = adapter->host_intf_ops->write_pkt(common->priv, skb->data, 307 - skb->len); 299 + status = rsi_send_pkt_to_bus(common, skb); 308 300 if (status) 309 301 rsi_dbg(ERR_ZONE, "%s: Failed to write pkt\n", __func__); 310 302 ··· 348 342 goto err; 349 343 350 344 rsi_prepare_mgmt_desc(common, skb); 351 - status = adapter->host_intf_ops->write_pkt(common->priv, 352 - (u8 *)skb->data, skb->len); 345 + status = rsi_send_pkt_to_bus(common, skb); 353 346 if (status) 354 347 rsi_dbg(ERR_ZONE, "%s: Failed to write the packet\n", __func__); 355 348 ··· 930 925 int rsi_hal_device_init(struct rsi_hw *adapter) 931 926 { 932 927 struct rsi_common *common = adapter->priv; 933 - 934 - common->coex_mode = RSI_DEV_COEX_MODE_WIFI_ALONE; 935 - common->oper_mode = RSI_DEV_OPMODE_WIFI_ALONE; 936 - adapter->device_model = RSI_DEV_9113; 937 928 938 929 switch (adapter->device_model) { 939 930 case RSI_DEV_9113:
+37 -1
drivers/net/wireless/rsi/rsi_91x_main.c
··· 20 20 #include <linux/firmware.h> 21 21 #include "rsi_mgmt.h" 22 22 #include "rsi_common.h" 23 + #include "rsi_coex.h" 23 24 #include "rsi_hal.h" 24 25 25 26 u32 rsi_zone_enabled = /* INFO_ZONE | ··· 161 160 162 161 switch (queueno) { 163 162 case RSI_COEX_Q: 164 - rsi_mgmt_pkt_recv(common, (frame_desc + offset)); 163 + #ifdef CONFIG_RSI_COEX 164 + if (common->coex_mode > 1) 165 + rsi_coex_recv_pkt(common, frame_desc + offset); 166 + else 167 + #endif 168 + rsi_mgmt_pkt_recv(common, 169 + (frame_desc + offset)); 165 170 break; 171 + 166 172 case RSI_WIFI_DATA_Q: 167 173 skb = rsi_prepare_skb(common, 168 174 (frame_desc + offset), ··· 225 217 complete_and_exit(&common->tx_thread.completion, 0); 226 218 } 227 219 220 + #ifdef CONFIG_RSI_COEX 221 + enum rsi_host_intf rsi_get_host_intf(void *priv) 222 + { 223 + struct rsi_common *common = (struct rsi_common *)priv; 224 + 225 + return common->priv->rsi_host_intf; 226 + } 227 + #endif 228 + 228 229 /** 229 230 * rsi_91x_init() - This function initializes os interface operations. 230 231 * @void: Void. ··· 268 251 mutex_init(&common->mutex); 269 252 mutex_init(&common->tx_lock); 270 253 mutex_init(&common->rx_lock); 254 + mutex_init(&common->tx_bus_mutex); 271 255 272 256 if (rsi_create_kthread(common, 273 257 &common->tx_thread, ··· 283 265 timer_setup(&common->roc_timer, rsi_roc_timeout, 0); 284 266 init_completion(&common->wlan_init_completion); 285 267 common->init_done = true; 268 + 269 + common->coex_mode = RSI_DEV_COEX_MODE_WIFI_ALONE; 270 + common->oper_mode = RSI_DEV_OPMODE_WIFI_ALONE; 271 + adapter->device_model = RSI_DEV_9113; 272 + #ifdef CONFIG_RSI_COEX 273 + if (common->coex_mode > 1) { 274 + if (rsi_coex_attach(common)) { 275 + rsi_dbg(ERR_ZONE, "Failed to init coex module\n"); 276 + goto err; 277 + } 278 + } 279 + #endif 280 + 286 281 return adapter; 287 282 288 283 err: ··· 324 293 skb_queue_purge(&common->tx_queue[ii]); 325 294 326 295 common->init_done = false; 296 + 297 + #ifdef CONFIG_RSI_COEX 298 + if (common->coex_mode > 1) 299 + rsi_coex_detach(common); 300 + #endif 327 301 328 302 kfree(common); 329 303 kfree(adapter->rsi_dev);
+1 -1
drivers/net/wireless/rsi/rsi_91x_mgmt.c
··· 1791 1791 return -EINVAL; 1792 1792 } 1793 1793 1794 - static int rsi_handle_card_ready(struct rsi_common *common, u8 *msg) 1794 + int rsi_handle_card_ready(struct rsi_common *common, u8 *msg) 1795 1795 { 1796 1796 switch (common->fsm_state) { 1797 1797 case FSM_CARD_NOT_READY:
+1
drivers/net/wireless/rsi/rsi_91x_sdio.c
··· 18 18 #include <linux/module.h> 19 19 #include "rsi_sdio.h" 20 20 #include "rsi_common.h" 21 + #include "rsi_coex.h" 21 22 #include "rsi_hal.h" 22 23 23 24 /**
+2
drivers/net/wireless/rsi/rsi_91x_usb.c
··· 16 16 */ 17 17 18 18 #include <linux/module.h> 19 + #include <net/rsi_91x.h> 19 20 #include "rsi_usb.h" 20 21 #include "rsi_hal.h" 22 + #include "rsi_coex.h" 21 23 22 24 /** 23 25 * rsi_usb_card_write() - This function writes to the USB Card.
+37
drivers/net/wireless/rsi/rsi_coex.h
··· 1 + /** 2 + * Copyright (c) 2018 Redpine Signals Inc. 3 + * 4 + * Permission to use, copy, modify, and/or distribute this software for any 5 + * purpose with or without fee is hereby granted, provided that the above 6 + * copyright notice and this permission notice appear in all copies. 7 + * 8 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + */ 16 + 17 + #ifndef __RSI_COEX_H__ 18 + #define __RSI_COEX_H__ 19 + 20 + #include "rsi_common.h" 21 + 22 + #ifdef CONFIG_RSI_COEX 23 + #define COMMON_CARD_READY_IND 0 24 + #define NUM_COEX_TX_QUEUES 5 25 + 26 + struct rsi_coex_ctrl_block { 27 + struct rsi_common *priv; 28 + struct sk_buff_head coex_tx_qs[NUM_COEX_TX_QUEUES]; 29 + struct rsi_thread coex_tx_thread; 30 + }; 31 + 32 + int rsi_coex_attach(struct rsi_common *common); 33 + void rsi_coex_detach(struct rsi_common *common); 34 + int rsi_coex_send_pkt(void *priv, struct sk_buff *skb, u8 proto_type); 35 + int rsi_coex_recv_pkt(struct rsi_common *common, u8 *msg); 36 + #endif 37 + #endif
+6
drivers/net/wireless/rsi/rsi_main.h
··· 206 206 struct rsi_hw *priv; 207 207 struct vif_priv vif_info[RSI_MAX_VIFS]; 208 208 209 + void *coex_cb; 209 210 bool mgmt_q_block; 210 211 struct version_info lmac_ver; 211 212 ··· 271 270 u8 obm_ant_sel_val; 272 271 int tx_power; 273 272 u8 ant_in_use; 273 + /* Mutex used for writing packet to bus */ 274 + struct mutex tx_bus_mutex; 274 275 bool hibernate_resume; 275 276 bool reinit_hw; 276 277 u8 wow_flags; ··· 362 359 u8 *fw); 363 360 int (*reinit_device)(struct rsi_hw *adapter); 364 361 }; 362 + 363 + enum rsi_host_intf rsi_get_host_intf(void *priv); 364 + 365 365 #endif
+3
drivers/net/wireless/rsi/rsi_mgmt.h
··· 57 57 #define WOW_PATTERN_SIZE 256 58 58 59 59 /* Receive Frame Types */ 60 + #define RSI_RX_DESC_MSG_TYPE_OFFSET 2 60 61 #define TA_CONFIRM_TYPE 0x01 61 62 #define RX_DOT11_MGMT 0x02 62 63 #define TX_STATUS_IND 0x04 63 64 #define BEACON_EVENT_IND 0x08 64 65 #define PROBEREQ_CONFIRM 2 65 66 #define CARD_READY_IND 0x00 67 + #define SLEEP_NOTIFY_IND 0x06 66 68 67 69 #define RSI_DELETE_PEER 0x0 68 70 #define RSI_ADD_PEER 0x1 ··· 640 638 *addr = cpu_to_le16(len | ((qno & 7) << 12)); 641 639 } 642 640 641 + int rsi_handle_card_ready(struct rsi_common *common, u8 *msg); 643 642 int rsi_mgmt_pkt_recv(struct rsi_common *common, u8 *msg); 644 643 int rsi_set_vap_capabilities(struct rsi_common *common, enum opmode mode, 645 644 u8 *mac_addr, u8 vap_id, u8 vap_status);
+20
include/net/rsi_91x.h
··· 17 17 #ifndef __RSI_HEADER_H__ 18 18 #define __RSI_HEADER_H__ 19 19 20 + #include <linux/skbuff.h> 21 + 20 22 /* HAL queue information */ 21 23 #define RSI_COEX_Q 0x0 22 24 #define RSI_BT_Q 0x2 ··· 28 26 #define RSI_BT_MGMT_Q 0x6 29 27 #define RSI_BT_DATA_Q 0x7 30 28 29 + enum rsi_coex_queues { 30 + RSI_COEX_Q_INVALID = -1, 31 + RSI_COEX_Q_COMMON = 0, 32 + RSI_COEX_Q_BT, 33 + RSI_COEX_Q_WLAN 34 + }; 35 + 31 36 enum rsi_host_intf { 32 37 RSI_HOST_INTF_SDIO = 0, 33 38 RSI_HOST_INTF_USB 34 39 }; 35 40 41 + struct rsi_proto_ops { 42 + int (*coex_send_pkt)(void *priv, struct sk_buff *skb, u8 hal_queue); 43 + enum rsi_host_intf (*get_host_intf)(void *priv); 44 + void (*set_bt_context)(void *priv, void *context); 45 + }; 46 + 47 + struct rsi_mod_ops { 48 + int (*attach)(void *priv, struct rsi_proto_ops *ops); 49 + void (*detach)(void *priv); 50 + int (*recv_pkt)(void *priv, u8 *msg); 51 + }; 36 52 #endif