aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi
diff options
context:
space:
mode:
authorWey-Yi Guy <wey-yi.w.guy@intel.com>2010-08-23 10:57:04 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-08-25 14:34:19 -0400
commitbee008b78307ccc2e17c7ec152dd2098d5f2e1fa (patch)
treea66fd8ef5e086df61c5f8e27a575e4877a06c680 /drivers/net/wireless/iwlwifi
parentbd6e2d579949aede258c673caf4b1eb39b95e172 (diff)
iwlwifi: add bt full concurrency support
Adding the bluetooth full concurrency support for WiFi/BT combo devices. Driver should configure uCode to operate in "full concurrency" mode (via LUT) if both conditions are met: - Antenna Coupling is more than 35dB - WiFi Channel Inhibition Request is hornored by BT Core Currently, there is no antenna coupling information provided by uCode; use module parameter to specified the antenna coupling in dB. When in "full concurrency" mode, driver need to download different LUT to uCode while sending bt configuration command; also, driver need to configure the device operate in 1x1 while in full concurrency mode. Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c34
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-calib.c6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-lib.c11
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.c70
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-tx.c7
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c49
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c11
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h7
9 files changed, 185 insertions, 11 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index 9d430987cc62..a4601b58a5db 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -201,6 +201,21 @@ static const __le32 iwl6000g2b_def_3w_lookup[12] = {
201 cpu_to_le32(0xf0004000), 201 cpu_to_le32(0xf0004000),
202}; 202};
203 203
204static const __le32 iwl6000g2b_concurrent_lookup[12] = {
205 cpu_to_le32(0xaaaaaaaa),
206 cpu_to_le32(0xaaaaaaaa),
207 cpu_to_le32(0xaaaaaaaa),
208 cpu_to_le32(0xaaaaaaaa),
209 cpu_to_le32(0xaaaaaaaa),
210 cpu_to_le32(0xaaaaaaaa),
211 cpu_to_le32(0xaaaaaaaa),
212 cpu_to_le32(0xaaaaaaaa),
213 cpu_to_le32(0x00000000),
214 cpu_to_le32(0x00000000),
215 cpu_to_le32(0x00000000),
216 cpu_to_le32(0x00000000),
217};
218
204static void iwl6000g2b_send_bt_config(struct iwl_priv *priv) 219static void iwl6000g2b_send_bt_config(struct iwl_priv *priv)
205{ 220{
206 struct iwl6000g2b_bt_cmd bt_cmd = { 221 struct iwl6000g2b_bt_cmd bt_cmd = {
@@ -233,11 +248,17 @@ static void iwl6000g2b_send_bt_config(struct iwl_priv *priv)
233 bt_cmd.valid |= IWL6000G2B_BT_ALL_VALID_MSK; 248 bt_cmd.valid |= IWL6000G2B_BT_ALL_VALID_MSK;
234 } 249 }
235 250
236 memcpy(bt_cmd.bt3_lookup_table, iwl6000g2b_def_3w_lookup, 251 if (priv->bt_full_concurrent)
237 sizeof(iwl6000g2b_def_3w_lookup)); 252 memcpy(bt_cmd.bt3_lookup_table, iwl6000g2b_concurrent_lookup,
253 sizeof(iwl6000g2b_concurrent_lookup));
254 else
255 memcpy(bt_cmd.bt3_lookup_table, iwl6000g2b_def_3w_lookup,
256 sizeof(iwl6000g2b_def_3w_lookup));
238 257
239 IWL_DEBUG_INFO(priv, "BT coex %s\n", 258 IWL_DEBUG_INFO(priv, "BT coex %s in %s mode\n",
240 bt_cmd.flags ? "active" : "disabled"); 259 bt_cmd.flags ? "active" : "disabled",
260 priv->bt_full_concurrent ?
261 "full concurrency" : "3-wire");
241 262
242 if (iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG, sizeof(bt_cmd), &bt_cmd)) 263 if (iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG, sizeof(bt_cmd), &bt_cmd))
243 IWL_ERR(priv, "failed to send BT Coex Config\n"); 264 IWL_ERR(priv, "failed to send BT Coex Config\n");
@@ -435,6 +456,7 @@ static void iwl6000g2b_bt_traffic_change_work(struct work_struct *work)
435static void iwl6000g2b_bt_coex_profile_notif(struct iwl_priv *priv, 456static void iwl6000g2b_bt_coex_profile_notif(struct iwl_priv *priv,
436 struct iwl_rx_mem_buffer *rxb) 457 struct iwl_rx_mem_buffer *rxb)
437{ 458{
459 unsigned long flags;
438 struct iwl_rx_packet *pkt = rxb_addr(rxb); 460 struct iwl_rx_packet *pkt = rxb_addr(rxb);
439 struct iwl_bt_coex_profile_notif *coex = &pkt->u.bt_coex_profile_notif; 461 struct iwl_bt_coex_profile_notif *coex = &pkt->u.bt_coex_profile_notif;
440 struct iwl6000g2b_bt_sco_cmd sco_cmd = { .flags = 0 }; 462 struct iwl6000g2b_bt_sco_cmd sco_cmd = { .flags = 0 };
@@ -466,6 +488,10 @@ static void iwl6000g2b_bt_coex_profile_notif(struct iwl_priv *priv,
466 iwl_send_cmd_pdu_async(priv, REPLY_BT_COEX_SCO, 488 iwl_send_cmd_pdu_async(priv, REPLY_BT_COEX_SCO,
467 sizeof(sco_cmd), &sco_cmd, NULL); 489 sizeof(sco_cmd), &sco_cmd, NULL);
468 } 490 }
491
492 spin_lock_irqsave(&priv->lock, flags);
493 priv->bt_ci_compliance = coex->bt_ci_compliance;
494 spin_unlock_irqrestore(&priv->lock, flags);
469} 495}
470 496
471void iwl6000g2b_rx_handler_setup(struct iwl_priv *priv) 497void iwl6000g2b_rx_handler_setup(struct iwl_priv *priv)
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
index c4c5691032a6..156b125dba71 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
@@ -914,7 +914,11 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
914 * To be safe, simply mask out any chains that we know 914 * To be safe, simply mask out any chains that we know
915 * are not on the device. 915 * are not on the device.
916 */ 916 */
917 active_chains &= priv->hw_params.valid_rx_ant; 917 if (priv->cfg->advanced_bt_coexist && priv->bt_full_concurrent) {
918 /* operated as 1x1 in full concurrency mode */
919 active_chains &= first_antenna(priv->hw_params.valid_rx_ant);
920 } else
921 active_chains &= priv->hw_params.valid_rx_ant;
918 922
919 num_tx_chains = 0; 923 num_tx_chains = 0;
920 for (i = 0; i < NUM_RX_CHAINS; i++) { 924 for (i = 0; i < NUM_RX_CHAINS; i++) {
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
index e1b5250ea637..e0ec6c08b222 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
@@ -1333,6 +1333,12 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
1333 if (priv->cfg->scan_tx_antennas[band]) 1333 if (priv->cfg->scan_tx_antennas[band])
1334 scan_tx_antennas = priv->cfg->scan_tx_antennas[band]; 1334 scan_tx_antennas = priv->cfg->scan_tx_antennas[band];
1335 1335
1336 if (priv->cfg->advanced_bt_coexist && priv->bt_full_concurrent) {
1337 /* operated as 1x1 in full concurrency mode */
1338 scan_tx_antennas =
1339 first_antenna(priv->cfg->scan_tx_antennas[band]);
1340 }
1341
1336 priv->scan_tx_ant[band] = iwl_toggle_tx_ant(priv, priv->scan_tx_ant[band], 1342 priv->scan_tx_ant[band] = iwl_toggle_tx_ant(priv, priv->scan_tx_ant[band],
1337 scan_tx_antennas); 1343 scan_tx_antennas);
1338 rate_flags |= iwl_ant_idx_to_flags(priv->scan_tx_ant[band]); 1344 rate_flags |= iwl_ant_idx_to_flags(priv->scan_tx_ant[band]);
@@ -1351,6 +1357,11 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
1351 1357
1352 rx_ant = first_antenna(active_chains); 1358 rx_ant = first_antenna(active_chains);
1353 } 1359 }
1360 if (priv->cfg->advanced_bt_coexist && priv->bt_full_concurrent) {
1361 /* operated as 1x1 in full concurrency mode */
1362 rx_ant = first_antenna(rx_ant);
1363 }
1364
1354 /* MIMO is not used here, but value is required */ 1365 /* MIMO is not used here, but value is required */
1355 rx_chain |= priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS; 1366 rx_chain |= priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS;
1356 rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS; 1367 rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS;
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index f8eed92c1add..687b534d83d0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -758,6 +758,32 @@ static bool table_type_matches(struct iwl_scale_tbl_info *a,
758 (a->is_SGI == b->is_SGI); 758 (a->is_SGI == b->is_SGI);
759} 759}
760 760
761static void rs_bt_update_lq(struct iwl_priv *priv,
762 struct iwl_lq_sta *lq_sta)
763{
764 struct iwl_scale_tbl_info *tbl;
765 bool full_concurrent;
766 unsigned long flags;
767
768 spin_lock_irqsave(&priv->lock, flags);
769 if (priv->bt_ci_compliance && priv->bt_ant_couple_ok)
770 full_concurrent = true;
771 else
772 full_concurrent = false;
773 spin_unlock_irqrestore(&priv->lock, flags);
774
775 if (priv->bt_full_concurrent != full_concurrent) {
776 priv->bt_full_concurrent = full_concurrent;
777
778 /* Update uCode's rate table. */
779 tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
780 rs_fill_link_cmd(priv, lq_sta, tbl->current_rate);
781 iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC, false);
782
783 queue_work(priv->workqueue, &priv->bt_full_concurrency);
784 }
785}
786
761/* 787/*
762 * mac80211 sends us Tx status 788 * mac80211 sends us Tx status
763 */ 789 */
@@ -940,6 +966,10 @@ done:
940 /* See if there's a better rate or modulation mode to try. */ 966 /* See if there's a better rate or modulation mode to try. */
941 if (sta && sta->supp_rates[sband->band]) 967 if (sta && sta->supp_rates[sband->band])
942 rs_rate_scale_perform(priv, skb, sta, lq_sta); 968 rs_rate_scale_perform(priv, skb, sta, lq_sta);
969
970 /* Is there a need to switch between full concurrency and 3-wire? */
971 if (priv->bt_ant_couple_ok)
972 rs_bt_update_lq(priv, lq_sta);
943} 973}
944 974
945/* 975/*
@@ -1325,6 +1355,15 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
1325 else if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE && 1355 else if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE &&
1326 tbl->action > IWL_LEGACY_SWITCH_SISO) 1356 tbl->action > IWL_LEGACY_SWITCH_SISO)
1327 tbl->action = IWL_LEGACY_SWITCH_SISO; 1357 tbl->action = IWL_LEGACY_SWITCH_SISO;
1358
1359 /* configure as 1x1 if bt full concurrency */
1360 if (priv->bt_full_concurrent) {
1361 if (!iwl_ht_enabled(priv))
1362 tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
1363 else if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2)
1364 tbl->action = IWL_LEGACY_SWITCH_SISO;
1365 }
1366
1328 start_action = tbl->action; 1367 start_action = tbl->action;
1329 for (; ;) { 1368 for (; ;) {
1330 lq_sta->action_counter++; 1369 lq_sta->action_counter++;
@@ -1484,6 +1523,12 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
1484 /* stay in SISO */ 1523 /* stay in SISO */
1485 tbl->action = IWL_SISO_SWITCH_ANTENNA1; 1524 tbl->action = IWL_SISO_SWITCH_ANTENNA1;
1486 } 1525 }
1526
1527 /* configure as 1x1 if bt full concurrency */
1528 if (priv->bt_full_concurrent &&
1529 tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2)
1530 tbl->action = IWL_SISO_SWITCH_ANTENNA1;
1531
1487 start_action = tbl->action; 1532 start_action = tbl->action;
1488 for (;;) { 1533 for (;;) {
1489 lq_sta->action_counter++; 1534 lq_sta->action_counter++;
@@ -1645,6 +1690,13 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv,
1645 /* switch in SISO */ 1690 /* switch in SISO */
1646 tbl->action = IWL_MIMO2_SWITCH_SISO_A; 1691 tbl->action = IWL_MIMO2_SWITCH_SISO_A;
1647 } 1692 }
1693
1694 /* configure as 1x1 if bt full concurrency */
1695 if (priv->bt_full_concurrent &&
1696 (tbl->action < IWL_MIMO2_SWITCH_SISO_A ||
1697 tbl->action > IWL_MIMO2_SWITCH_SISO_C))
1698 tbl->action = IWL_MIMO2_SWITCH_SISO_A;
1699
1648 start_action = tbl->action; 1700 start_action = tbl->action;
1649 for (;;) { 1701 for (;;) {
1650 lq_sta->action_counter++; 1702 lq_sta->action_counter++;
@@ -1810,6 +1862,13 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv,
1810 /* switch in SISO */ 1862 /* switch in SISO */
1811 tbl->action = IWL_MIMO3_SWITCH_SISO_A; 1863 tbl->action = IWL_MIMO3_SWITCH_SISO_A;
1812 } 1864 }
1865
1866 /* configure as 1x1 if bt full concurrency */
1867 if (priv->bt_full_concurrent &&
1868 (tbl->action < IWL_MIMO3_SWITCH_SISO_A ||
1869 tbl->action > IWL_MIMO3_SWITCH_SISO_C))
1870 tbl->action = IWL_MIMO3_SWITCH_SISO_A;
1871
1813 start_action = tbl->action; 1872 start_action = tbl->action;
1814 for (;;) { 1873 for (;;) {
1815 lq_sta->action_counter++; 1874 lq_sta->action_counter++;
@@ -2741,7 +2800,8 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
2741 /* Fill 1st table entry (index 0) */ 2800 /* Fill 1st table entry (index 0) */
2742 lq_cmd->rs_table[index].rate_n_flags = cpu_to_le32(new_rate); 2801 lq_cmd->rs_table[index].rate_n_flags = cpu_to_le32(new_rate);
2743 2802
2744 if (num_of_ant(tbl_type.ant_type) == 1) { 2803 if (num_of_ant(tbl_type.ant_type) == 1 ||
2804 (priv && priv->bt_full_concurrent)) {
2745 lq_cmd->general_params.single_stream_ant_msk = 2805 lq_cmd->general_params.single_stream_ant_msk =
2746 tbl_type.ant_type; 2806 tbl_type.ant_type;
2747 } else if (num_of_ant(tbl_type.ant_type) == 2) { 2807 } else if (num_of_ant(tbl_type.ant_type) == 2) {
@@ -2752,8 +2812,12 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
2752 index++; 2812 index++;
2753 repeat_rate--; 2813 repeat_rate--;
2754 2814
2755 if (priv) 2815 if (priv) {
2756 valid_tx_ant = priv->hw_params.valid_tx_ant; 2816 if (priv->bt_full_concurrent)
2817 valid_tx_ant = ANT_A;
2818 else
2819 valid_tx_ant = priv->hw_params.valid_tx_ant;
2820 }
2757 2821
2758 /* Fill rest of rate table */ 2822 /* Fill rest of rate table */
2759 while (index < LINK_QUAL_MAX_RETRY_NUM) { 2823 while (index < LINK_QUAL_MAX_RETRY_NUM) {
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index 8d2ffffe01b2..e2497e7ba926 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -461,7 +461,12 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv,
461 rate_flags |= RATE_MCS_CCK_MSK; 461 rate_flags |= RATE_MCS_CCK_MSK;
462 462
463 /* Set up antennas */ 463 /* Set up antennas */
464 priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant, 464 if (priv->cfg->advanced_bt_coexist && priv->bt_full_concurrent) {
465 /* operated as 1x1 in full concurrency mode */
466 priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
467 first_antenna(priv->hw_params.valid_tx_ant));
468 } else
469 priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
465 priv->hw_params.valid_tx_ant); 470 priv->hw_params.valid_tx_ant);
466 rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant); 471 rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
467 472
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index ecf7cf012679..807d697f6239 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -87,6 +87,8 @@ MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
87MODULE_LICENSE("GPL"); 87MODULE_LICENSE("GPL");
88MODULE_ALIAS("iwl4965"); 88MODULE_ALIAS("iwl4965");
89 89
90static int iwlagn_ant_coupling;
91
90/** 92/**
91 * iwl_commit_rxon - commit staging_rxon to hardware 93 * iwl_commit_rxon - commit staging_rxon to hardware
92 * 94 *
@@ -612,6 +614,33 @@ static void iwl_bg_beacon_update(struct work_struct *work)
612 iwl_send_beacon_cmd(priv); 614 iwl_send_beacon_cmd(priv);
613} 615}
614 616
617static void iwl_bg_bt_full_concurrency(struct work_struct *work)
618{
619 struct iwl_priv *priv =
620 container_of(work, struct iwl_priv, bt_full_concurrency);
621
622 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
623 return;
624
625 /* dont send host command if rf-kill is on */
626 if (!iwl_is_ready_rf(priv))
627 return;
628
629 IWL_DEBUG_INFO(priv, "BT coex in %s mode\n",
630 priv->bt_full_concurrent ?
631 "full concurrency" : "3-wire");
632
633 /*
634 * LQ & RXON updated cmds must be sent before BT Config cmd
635 * to avoid 3-wire collisions
636 */
637 if (priv->cfg->ops->hcmd->set_rxon_chain)
638 priv->cfg->ops->hcmd->set_rxon_chain(priv);
639 iwlcore_commit_rxon(priv);
640
641 priv->cfg->ops->hcmd->send_bt_config(priv);
642}
643
615/** 644/**
616 * iwl_bg_statistics_periodic - Timer callback to queue statistics 645 * iwl_bg_statistics_periodic - Timer callback to queue statistics
617 * 646 *
@@ -2776,6 +2805,8 @@ static void __iwl_down(struct iwl_priv *priv)
2776 /* reset BT coex data */ 2805 /* reset BT coex data */
2777 priv->bt_traffic_load = 0; 2806 priv->bt_traffic_load = 0;
2778 priv->bt_sco_active = false; 2807 priv->bt_sco_active = false;
2808 priv->bt_full_concurrent = false;
2809 priv->bt_ci_compliance = 0;
2779 2810
2780 /* Unblock any waiting calls */ 2811 /* Unblock any waiting calls */
2781 wake_up_interruptible_all(&priv->wait_command_queue); 2812 wake_up_interruptible_all(&priv->wait_command_queue);
@@ -3079,7 +3110,8 @@ static void iwl_bg_restart(struct work_struct *data)
3079 return; 3110 return;
3080 3111
3081 if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) { 3112 if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) {
3082 bool bt_sco; 3113 bool bt_sco, bt_full_concurrent;
3114 u8 bt_ci_compliance;
3083 u8 bt_load; 3115 u8 bt_load;
3084 3116
3085 mutex_lock(&priv->mutex); 3117 mutex_lock(&priv->mutex);
@@ -3096,11 +3128,15 @@ static void iwl_bg_restart(struct work_struct *data)
3096 * command. 3128 * command.
3097 */ 3129 */
3098 bt_sco = priv->bt_sco_active; 3130 bt_sco = priv->bt_sco_active;
3131 bt_full_concurrent = priv->bt_full_concurrent;
3132 bt_ci_compliance = priv->bt_ci_compliance;
3099 bt_load = priv->bt_traffic_load; 3133 bt_load = priv->bt_traffic_load;
3100 3134
3101 __iwl_down(priv); 3135 __iwl_down(priv);
3102 3136
3103 priv->bt_sco_active = bt_sco; 3137 priv->bt_sco_active = bt_sco;
3138 priv->bt_full_concurrent = bt_full_concurrent;
3139 priv->bt_ci_compliance = bt_ci_compliance;
3104 priv->bt_traffic_load = bt_load; 3140 priv->bt_traffic_load = bt_load;
3105 3141
3106 mutex_unlock(&priv->mutex); 3142 mutex_unlock(&priv->mutex);
@@ -3856,6 +3892,7 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
3856 INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update); 3892 INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
3857 INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work); 3893 INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work);
3858 INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush); 3894 INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush);
3895 INIT_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency);
3859 INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); 3896 INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
3860 INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); 3897 INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
3861 3898
@@ -3898,6 +3935,7 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
3898 cancel_delayed_work(&priv->alive_start); 3935 cancel_delayed_work(&priv->alive_start);
3899 cancel_work_sync(&priv->run_time_calib_work); 3936 cancel_work_sync(&priv->run_time_calib_work);
3900 cancel_work_sync(&priv->beacon_update); 3937 cancel_work_sync(&priv->beacon_update);
3938 cancel_work_sync(&priv->bt_full_concurrency);
3901 del_timer_sync(&priv->statistics_periodic); 3939 del_timer_sync(&priv->statistics_periodic);
3902 del_timer_sync(&priv->ucode_trace); 3940 del_timer_sync(&priv->ucode_trace);
3903} 3941}
@@ -4078,6 +4116,11 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
4078 priv->pci_dev = pdev; 4116 priv->pci_dev = pdev;
4079 priv->inta_mask = CSR_INI_SET_MASK; 4117 priv->inta_mask = CSR_INI_SET_MASK;
4080 4118
4119 /* is antenna coupling more than 35dB ? */
4120 priv->bt_ant_couple_ok =
4121 (iwlagn_ant_coupling > IWL_BT_ANTENNA_COUPLING_THRESHOLD) ?
4122 true : false;
4123
4081 if (iwl_alloc_traffic_mem(priv)) 4124 if (iwl_alloc_traffic_mem(priv))
4082 IWL_ERR(priv, "Not enough memory to generate traffic log\n"); 4125 IWL_ERR(priv, "Not enough memory to generate traffic log\n");
4083 4126
@@ -4611,3 +4654,7 @@ module_param_named(ucode_alternative, iwlagn_wanted_ucode_alternative, int,
4611 S_IRUGO); 4654 S_IRUGO);
4612MODULE_PARM_DESC(ucode_alternative, 4655MODULE_PARM_DESC(ucode_alternative,
4613 "specify ucode alternative to use from ucode file"); 4656 "specify ucode alternative to use from ucode file");
4657
4658module_param_named(antenna_coupling, iwlagn_ant_coupling, int, S_IRUGO);
4659MODULE_PARM_DESC(antenna_coupling,
4660 "specify antenna coupling in dB (defualt: 0 dB)");
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 5e8fc720c570..13d2dcea85d1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -780,6 +780,10 @@ EXPORT_SYMBOL(iwl_set_rxon_ht);
780 */ 780 */
781static int iwl_get_active_rx_chain_count(struct iwl_priv *priv) 781static int iwl_get_active_rx_chain_count(struct iwl_priv *priv)
782{ 782{
783 if (priv->cfg->advanced_bt_coexist && priv->bt_full_concurrent) {
784 /* operated as 1x1 in full concurrency mode */
785 return IWL_NUM_RX_CHAINS_SINGLE;
786 }
783 /* # of Rx chains to use when expecting MIMO. */ 787 /* # of Rx chains to use when expecting MIMO. */
784 if (is_single_rx_stream(priv)) 788 if (is_single_rx_stream(priv))
785 return IWL_NUM_RX_CHAINS_SINGLE; 789 return IWL_NUM_RX_CHAINS_SINGLE;
@@ -836,11 +840,16 @@ void iwl_set_rxon_chain(struct iwl_priv *priv)
836 * Before first association, we assume all antennas are connected. 840 * Before first association, we assume all antennas are connected.
837 * Just after first association, iwl_chain_noise_calibration() 841 * Just after first association, iwl_chain_noise_calibration()
838 * checks which antennas actually *are* connected. */ 842 * checks which antennas actually *are* connected. */
839 if (priv->chain_noise_data.active_chains) 843 if (priv->chain_noise_data.active_chains)
840 active_chains = priv->chain_noise_data.active_chains; 844 active_chains = priv->chain_noise_data.active_chains;
841 else 845 else
842 active_chains = priv->hw_params.valid_rx_ant; 846 active_chains = priv->hw_params.valid_rx_ant;
843 847
848 if (priv->cfg->advanced_bt_coexist && priv->bt_full_concurrent) {
849 /* operated as 1x1 in full concurrency mode */
850 active_chains = first_antenna(active_chains);
851 }
852
844 rx_chain = active_chains << RXON_RX_CHAIN_VALID_POS; 853 rx_chain = active_chains << RXON_RX_CHAIN_VALID_POS;
845 854
846 /* How many receivers should we use? */ 855 /* How many receivers should we use? */
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index d77337987156..146d0d5ec6b9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -736,5 +736,6 @@ static inline const struct ieee80211_supported_band *iwl_get_hw_mode(
736} 736}
737 737
738extern bool bt_coex_active; 738extern bool bt_coex_active;
739extern bool bt_siso_mode;
739 740
740#endif /* __iwl_core_h__ */ 741#endif /* __iwl_core_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 815ba0af94ce..7a96d9dd1732 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -1065,6 +1065,9 @@ struct iwl_event_log {
1065#define IWL_LONG_MONITORING_PERIOD (5000) 1065#define IWL_LONG_MONITORING_PERIOD (5000)
1066#define IWL_ONE_HUNDRED_MSECS (100) 1066#define IWL_ONE_HUNDRED_MSECS (100)
1067 1067
1068/* BT Antenna Coupling Threshold (dB) */
1069#define IWL_BT_ANTENNA_COUPLING_THRESHOLD (35)
1070
1068enum iwl_reset { 1071enum iwl_reset {
1069 IWL_RF_RESET = 0, 1072 IWL_RF_RESET = 0,
1070 IWL_FW_RESET, 1073 IWL_FW_RESET,
@@ -1364,6 +1367,9 @@ struct iwl_priv {
1364 1367
1365 u8 bt_traffic_load, notif_bt_traffic_load; 1368 u8 bt_traffic_load, notif_bt_traffic_load;
1366 bool bt_sco_active; 1369 bool bt_sco_active;
1370 bool bt_full_concurrent;
1371 bool bt_ant_couple_ok;
1372 u8 bt_ci_compliance;
1367 struct work_struct bt_traffic_change_work; 1373 struct work_struct bt_traffic_change_work;
1368 1374
1369 struct iwl_hw_params hw_params; 1375 struct iwl_hw_params hw_params;
@@ -1384,6 +1390,7 @@ struct iwl_priv {
1384 struct work_struct ct_exit; 1390 struct work_struct ct_exit;
1385 struct work_struct start_internal_scan; 1391 struct work_struct start_internal_scan;
1386 struct work_struct tx_flush; 1392 struct work_struct tx_flush;
1393 struct work_struct bt_full_concurrency;
1387 1394
1388 struct tasklet_struct irq_tasklet; 1395 struct tasklet_struct irq_tasklet;
1389 1396