return ret;
}
+/*
+ * This function sends delba to specific tid
+ */
+void mwifiex_11n_delba(struct mwifiex_private *priv, int tid)
+{
+ struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
+
+ if (list_empty(&priv->rx_reorder_tbl_ptr)) {
+ dev_dbg(priv->adapter->dev,
+ "mwifiex_11n_delba: rx_reorder_tbl_ptr empty\n");
+ return;
+ }
+
+ list_for_each_entry(rx_reor_tbl_ptr, &priv->rx_reorder_tbl_ptr, list) {
+ if (rx_reor_tbl_ptr->tid == tid) {
+ dev_dbg(priv->adapter->dev,
+ "Send delba to tid=%d, %pM\n",
+ tid, rx_reor_tbl_ptr->ta);
+ mwifiex_send_delba(priv, tid, rx_reor_tbl_ptr->ta, 0);
+ return;
+ }
+ }
+}
+
/*
* This function handles the command response of a delete BA request.
*/
return sec_offset;
}
+
+/* This function will send DELBA to entries in the priv's
+ * Tx BA stream table
+ */
+static void
+mwifiex_send_delba_txbastream_tbl(struct mwifiex_private *priv, u8 tid)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct mwifiex_tx_ba_stream_tbl *tx_ba_stream_tbl_ptr;
+
+ if (list_empty(&priv->tx_ba_stream_tbl_ptr))
+ return;
+
+ list_for_each_entry(tx_ba_stream_tbl_ptr,
+ &priv->tx_ba_stream_tbl_ptr, list) {
+ if (tx_ba_stream_tbl_ptr->ba_status == BA_SETUP_COMPLETE) {
+ if (tid == tx_ba_stream_tbl_ptr->tid) {
+ dev_dbg(adapter->dev,
+ "Tx:Send delba to tid=%d, %pM\n", tid,
+ tx_ba_stream_tbl_ptr->ra);
+ mwifiex_send_delba(priv,
+ tx_ba_stream_tbl_ptr->tid,
+ tx_ba_stream_tbl_ptr->ra, 1);
+ return;
+ }
+ }
+ }
+}
+
+/* This function updates all the tx_win_size
+ */
+void mwifiex_update_ampdu_txwinsize(struct mwifiex_adapter *adapter)
+{
+ u8 i;
+ u32 tx_win_size;
+ struct mwifiex_private *priv;
+
+ for (i = 0; i < adapter->priv_num; i++) {
+ if (!adapter->priv[i])
+ continue;
+ priv = adapter->priv[i];
+ tx_win_size = priv->add_ba_param.tx_win_size;
+
+ if (priv->bss_type == MWIFIEX_BSS_TYPE_STA)
+ priv->add_ba_param.tx_win_size =
+ MWIFIEX_STA_AMPDU_DEF_TXWINSIZE;
+
+ if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P)
+ priv->add_ba_param.tx_win_size =
+ MWIFIEX_STA_AMPDU_DEF_TXWINSIZE;
+
+ if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP)
+ priv->add_ba_param.tx_win_size =
+ MWIFIEX_UAP_AMPDU_DEF_TXWINSIZE;
+
+ if (adapter->coex_win_size) {
+ if (adapter->coex_tx_win_size)
+ priv->add_ba_param.tx_win_size =
+ adapter->coex_tx_win_size;
+ }
+
+ if (tx_win_size != priv->add_ba_param.tx_win_size) {
+ if (!priv->media_connected)
+ continue;
+ for (i = 0; i < MAX_NUM_TID; i++)
+ mwifiex_send_delba_txbastream_tbl(priv, i);
+ }
+ }
+}
return;
}
+
+/* This function update all the rx_win_size based on coex flag
+ */
+static void mwifiex_update_ampdu_rxwinsize(struct mwifiex_adapter *adapter,
+ bool coex_flag)
+{
+ u8 i;
+ u32 rx_win_size;
+ struct mwifiex_private *priv;
+
+ dev_dbg(adapter->dev, "Update rxwinsize %d\n", coex_flag);
+
+ for (i = 0; i < adapter->priv_num; i++) {
+ if (!adapter->priv[i])
+ continue;
+ priv = adapter->priv[i];
+ rx_win_size = priv->add_ba_param.rx_win_size;
+ if (coex_flag) {
+ if (priv->bss_type == MWIFIEX_BSS_TYPE_STA)
+ priv->add_ba_param.rx_win_size =
+ MWIFIEX_STA_COEX_AMPDU_DEF_RXWINSIZE;
+ if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P)
+ priv->add_ba_param.rx_win_size =
+ MWIFIEX_STA_COEX_AMPDU_DEF_RXWINSIZE;
+ if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP)
+ priv->add_ba_param.rx_win_size =
+ MWIFIEX_UAP_COEX_AMPDU_DEF_RXWINSIZE;
+ } else {
+ if (priv->bss_type == MWIFIEX_BSS_TYPE_STA)
+ priv->add_ba_param.rx_win_size =
+ MWIFIEX_STA_AMPDU_DEF_RXWINSIZE;
+ if (priv->bss_type == MWIFIEX_BSS_TYPE_P2P)
+ priv->add_ba_param.rx_win_size =
+ MWIFIEX_STA_AMPDU_DEF_RXWINSIZE;
+ if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP)
+ priv->add_ba_param.rx_win_size =
+ MWIFIEX_UAP_AMPDU_DEF_RXWINSIZE;
+ }
+
+ if (adapter->coex_win_size && adapter->coex_rx_win_size)
+ priv->add_ba_param.rx_win_size =
+ adapter->coex_rx_win_size;
+
+ if (rx_win_size != priv->add_ba_param.rx_win_size) {
+ if (!priv->media_connected)
+ continue;
+ for (i = 0; i < MAX_NUM_TID; i++)
+ mwifiex_11n_delba(priv, i);
+ }
+ }
+}
+
+/* This function check coex for RX BA
+ */
+void mwifiex_coex_ampdu_rxwinsize(struct mwifiex_adapter *adapter)
+{
+ u8 i;
+ struct mwifiex_private *priv;
+ u8 count = 0;
+
+ for (i = 0; i < adapter->priv_num; i++) {
+ if (adapter->priv[i]) {
+ priv = adapter->priv[i];
+ if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) {
+ if (priv->media_connected)
+ count++;
+ }
+ if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
+ if (priv->bss_started)
+ count++;
+ }
+ }
+ if (count >= MWIFIEX_BSS_COEX_COUNT)
+ break;
+ }
+ if (count >= MWIFIEX_BSS_COEX_COUNT)
+ mwifiex_update_ampdu_rxwinsize(adapter, true);
+ else
+ mwifiex_update_ampdu_rxwinsize(adapter, false);
+}
#include <uapi/linux/if_arp.h>
#include <net/mac80211.h>
-
+#define MWIFIEX_BSS_COEX_COUNT 2
#define MWIFIEX_MAX_BSS_NUM (3)
#define MWIFIEX_DMA_ALIGN_SZ 64
#define MWIFIEX_STA_AMPDU_DEF_TXWINSIZE 64
#define MWIFIEX_STA_AMPDU_DEF_RXWINSIZE 64
+#define MWIFIEX_STA_COEX_AMPDU_DEF_RXWINSIZE 16
+
#define MWIFIEX_UAP_AMPDU_DEF_TXWINSIZE 32
+
+#define MWIFIEX_UAP_COEX_AMPDU_DEF_RXWINSIZE 16
+
#define MWIFIEX_UAP_AMPDU_DEF_RXWINSIZE 16
#define MWIFIEX_11AC_STA_AMPDU_DEF_TXWINSIZE 64
#define MWIFIEX_11AC_STA_AMPDU_DEF_RXWINSIZE 64
#define TLV_TYPE_SCAN_CHANNEL_GAP (PROPRIETARY_TLV_BASE_ID + 197)
#define TLV_TYPE_API_REV (PROPRIETARY_TLV_BASE_ID + 199)
#define TLV_TYPE_CHANNEL_STATS (PROPRIETARY_TLV_BASE_ID + 198)
+#define TLV_BTCOEX_WL_AGGR_WINSIZE (PROPRIETARY_TLV_BASE_ID + 202)
+#define TLV_BTCOEX_WL_SCANTIME (PROPRIETARY_TLV_BASE_ID + 203)
#define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048
#define EVENT_EXT_SCAN_REPORT 0x00000058
#define EVENT_REMAIN_ON_CHAN_EXPIRED 0x0000005f
#define EVENT_TX_STATUS_REPORT 0x00000074
+#define EVENT_BT_COEX_WLAN_PARA_CHANGE 0X00000076
#define EVENT_ID_MASK 0xffff
#define BSS_NUM_MASK 0xf
u8 constraint;
} __packed;
+struct mwifiex_ie_types_btcoex_scan_time {
+ struct mwifiex_ie_types_header header;
+ u8 coex_scan;
+ u8 reserved;
+ u16 min_scan_time;
+ u16 max_scan_time;
+} __packed;
+
+struct mwifiex_ie_types_btcoex_aggr_win_size {
+ struct mwifiex_ie_types_header header;
+ u8 coex_win_size;
+ u8 tx_win_size;
+ u8 rx_win_size;
+ u8 reserved;
+} __packed;
+
struct host_cmd_ds_version_ext {
u8 version_str_sel;
char version_str[128];
u32 num_in_chan_stats;
int survey_idx;
bool auto_tdls;
+ u8 coex_scan;
+ u8 coex_min_scan_time;
+ u8 coex_max_scan_time;
+ u8 coex_win_size;
+ u8 coex_tx_win_size;
+ u8 coex_rx_win_size;
};
void mwifiex_process_tx_queue(struct mwifiex_adapter *adapter);
struct mwifiex_uap_bss_param *bss_cfg,
struct cfg80211_ap_settings *params);
void mwifiex_set_ba_params(struct mwifiex_private *priv);
+
+void mwifiex_update_ampdu_txwinsize(struct mwifiex_adapter *pmadapter);
+void mwifiex_bt_coex_wlan_param_update_event(struct mwifiex_private *priv,
+ struct sk_buff *event_skb);
+
void mwifiex_set_11ac_ba_params(struct mwifiex_private *priv);
int mwifiex_cmd_802_11_scan_ext(struct mwifiex_private *priv,
struct host_cmd_ds_command *cmd,
void mwifiex_upload_device_dump(struct mwifiex_adapter *adapter);
void *mwifiex_alloc_dma_align_buf(int rx_len, gfp_t flags);
void mwifiex_queue_main_work(struct mwifiex_adapter *adapter);
-
+void mwifiex_coex_ampdu_rxwinsize(struct mwifiex_adapter *adapter);
+void mwifiex_11n_delba(struct mwifiex_private *priv, int tid);
#ifdef CONFIG_DEBUG_FS
void mwifiex_debugfs_init(void);
void mwifiex_debugfs_remove(void);
return ret;
}
+/*
+* This function handles coex events generated by firmware
+*/
+void mwifiex_bt_coex_wlan_param_update_event(struct mwifiex_private *priv,
+ struct sk_buff *event_skb)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct mwifiex_ie_types_header *tlv;
+ struct mwifiex_ie_types_btcoex_aggr_win_size *winsizetlv;
+ struct mwifiex_ie_types_btcoex_scan_time *scantlv;
+ s32 len = event_skb->len - sizeof(u32);
+ u8 *cur_ptr = event_skb->data + sizeof(u32);
+ u16 tlv_type, tlv_len;
+
+ while (len >= sizeof(struct mwifiex_ie_types_header)) {
+ tlv = (struct mwifiex_ie_types_header *)cur_ptr;
+ tlv_len = le16_to_cpu(tlv->len);
+ tlv_type = le16_to_cpu(tlv->type);
+
+ if ((tlv_len + sizeof(struct mwifiex_ie_types_header)) > len)
+ break;
+ switch (tlv_type) {
+ case TLV_BTCOEX_WL_AGGR_WINSIZE:
+ winsizetlv =
+ (struct mwifiex_ie_types_btcoex_aggr_win_size *)tlv;
+ adapter->coex_win_size = winsizetlv->coex_win_size;
+ adapter->coex_tx_win_size =
+ winsizetlv->tx_win_size;
+ adapter->coex_rx_win_size =
+ winsizetlv->rx_win_size;
+ mwifiex_coex_ampdu_rxwinsize(adapter);
+ mwifiex_update_ampdu_txwinsize(adapter);
+ break;
+
+ case TLV_BTCOEX_WL_SCANTIME:
+ scantlv =
+ (struct mwifiex_ie_types_btcoex_scan_time *)tlv;
+ adapter->coex_scan = scantlv->coex_scan;
+ adapter->coex_min_scan_time = scantlv->min_scan_time;
+ adapter->coex_max_scan_time = scantlv->max_scan_time;
+ break;
+
+ default:
+ break;
+ }
+
+ len -= tlv_len + sizeof(struct mwifiex_ie_types_header);
+ cur_ptr += tlv_len +
+ sizeof(struct mwifiex_ie_types_header);
+ }
+
+ dev_dbg(adapter->dev, "coex_scan=%d min_scan=%d coex_win=%d, tx_win=%d rx_win=%d\n",
+ adapter->coex_scan, adapter->coex_min_scan_time,
+ adapter->coex_win_size, adapter->coex_tx_win_size,
+ adapter->coex_rx_win_size);
+}
+
/*
* This function handles events generated by firmware.
*
ret = mwifiex_11h_handle_radar_detected(priv,
adapter->event_skb);
break;
+ case EVENT_BT_COEX_WLAN_PARA_CHANGE:
+ dev_dbg(adapter->dev, "EVENT: BT coex wlan param update\n");
+ mwifiex_bt_coex_wlan_param_update_event(priv,
+ adapter->event_skb);
default:
mwifiex_dbg(adapter, ERROR, "event: unknown event id: %#x\n",
eventcause);
mwifiex_dbg(adapter, EVENT, "event: Radar detected\n");
mwifiex_11h_handle_radar_detected(priv, adapter->event_skb);
break;
+ case EVENT_BT_COEX_WLAN_PARA_CHANGE:
+ dev_err(adapter->dev, "EVENT: BT coex wlan param update\n");
+ mwifiex_bt_coex_wlan_param_update_event(priv,
+ adapter->event_skb);
+ break;
default:
mwifiex_dbg(adapter, EVENT,
"event: unknown event id: %#x\n", eventcause);