diff options
author | Wey-Yi Guy <wey-yi.w.guy@intel.com> | 2010-08-23 10:57:04 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-08-25 14:34:19 -0400 |
commit | bee008b78307ccc2e17c7ec152dd2098d5f2e1fa (patch) | |
tree | a66fd8ef5e086df61c5f8e27a575e4877a06c680 /drivers/net | |
parent | bd6e2d579949aede258c673caf4b1eb39b95e172 (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')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-6000.c | 34 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-calib.c | 6 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-lib.c | 11 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 70 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-tx.c | 7 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 49 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.c | 11 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-dev.h | 7 |
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 | ||
204 | static 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 | |||
204 | static void iwl6000g2b_send_bt_config(struct iwl_priv *priv) | 219 | static 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) | |||
435 | static void iwl6000g2b_bt_coex_profile_notif(struct iwl_priv *priv, | 456 | static 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 | ||
471 | void iwl6000g2b_rx_handler_setup(struct iwl_priv *priv) | 497 | void 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 | ||
761 | static 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); | |||
87 | MODULE_LICENSE("GPL"); | 87 | MODULE_LICENSE("GPL"); |
88 | MODULE_ALIAS("iwl4965"); | 88 | MODULE_ALIAS("iwl4965"); |
89 | 89 | ||
90 | static 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 | ||
617 | static 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); |
4612 | MODULE_PARM_DESC(ucode_alternative, | 4655 | MODULE_PARM_DESC(ucode_alternative, |
4613 | "specify ucode alternative to use from ucode file"); | 4656 | "specify ucode alternative to use from ucode file"); |
4657 | |||
4658 | module_param_named(antenna_coupling, iwlagn_ant_coupling, int, S_IRUGO); | ||
4659 | MODULE_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 | */ |
781 | static int iwl_get_active_rx_chain_count(struct iwl_priv *priv) | 781 | static 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 | ||
738 | extern bool bt_coex_active; | 738 | extern bool bt_coex_active; |
739 | extern 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 | |||
1068 | enum iwl_reset { | 1071 | enum 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 | ||