aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorMeenakshi Venkataraman <meenakshi.venkataraman@intel.com>2011-07-08 11:46:23 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-07-11 15:02:07 -0400
commit207ecc5eab908843449c167f7264a35d7d5d5e0b (patch)
tree3425f0964810c9d1edd0bcc097a5838ce1f5c726 /drivers/net
parent615f7b9bb1f8e0e3188470245cec44f175189084 (diff)
iwlagn: Enable/disable PS poll based on RSSI and BT coex traffic state
WiFi throughput drops drastically when BT is turned on, BT and WiFi are simultaneously transmitting/receiving traffic. This is particularly true when BT has higher priority over WiFi, and hence the device defers TX frames. The AP assumes that the channel is bad and reduces the data rate, implying longer airtime, which exacerbates the problem further, resulting ultimately in what is popularly called the "death-spiral" phenomenon. The use of PS-poll in such scenarios guarantees a low but consistent throughput. Since the death-spiral phenomenon is observed only when the RSSI is low, use PS-poll only when RSSI is low and disable when high, with a known hysterisis. This feature specifies the high and low thresholds and implements the callbacks registered with mac80211, which will be called when threshold events occur. iwlwifi: dynamic pspoll: optimize rssi monitor code Signed-off-by: Meenakshi Venkataraman <meenakshi.venkataraman@intel.com> 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-agn-lib.c106
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rxon.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c36
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h3
6 files changed, 150 insertions, 2 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
index 94f6d6068661..eb2be0d30483 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
@@ -1634,9 +1634,11 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv)
1634 } else { 1634 } else {
1635 basic.flags = IWLAGN_BT_FLAG_COEX_MODE_3W << 1635 basic.flags = IWLAGN_BT_FLAG_COEX_MODE_3W <<
1636 IWLAGN_BT_FLAG_COEX_MODE_SHIFT; 1636 IWLAGN_BT_FLAG_COEX_MODE_SHIFT;
1637 if (priv->cfg->bt_params && 1637
1638 priv->cfg->bt_params->bt_sco_disable) 1638 if (!priv->bt_enable_pspoll)
1639 basic.flags |= IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE; 1639 basic.flags |= IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE;
1640 else
1641 basic.flags &= ~IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE;
1640 1642
1641 if (priv->bt_ch_announce) 1643 if (priv->bt_ch_announce)
1642 basic.flags |= IWLAGN_BT_FLAG_CHANNEL_INHIBITION; 1644 basic.flags |= IWLAGN_BT_FLAG_CHANNEL_INHIBITION;
@@ -1671,6 +1673,84 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv)
1671 1673
1672} 1674}
1673 1675
1676void iwlagn_bt_adjust_rssi_monitor(struct iwl_priv *priv, bool rssi_ena)
1677{
1678 struct iwl_rxon_context *ctx, *found_ctx = NULL;
1679 bool found_ap = false;
1680
1681 lockdep_assert_held(&priv->mutex);
1682
1683 /* Check whether AP or GO mode is active. */
1684 if (rssi_ena) {
1685 for_each_context(priv, ctx) {
1686 if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_AP &&
1687 iwl_is_associated_ctx(ctx)) {
1688 found_ap = true;
1689 break;
1690 }
1691 }
1692 }
1693
1694 /*
1695 * If disable was received or If GO/AP mode, disable RSSI
1696 * measurements.
1697 */
1698 if (!rssi_ena || found_ap) {
1699 if (priv->cur_rssi_ctx) {
1700 ctx = priv->cur_rssi_ctx;
1701 ieee80211_disable_rssi_reports(ctx->vif);
1702 priv->cur_rssi_ctx = NULL;
1703 }
1704 return;
1705 }
1706
1707 /*
1708 * If rssi measurements need to be enabled, consider all cases now.
1709 * Figure out how many contexts are active.
1710 */
1711 for_each_context(priv, ctx) {
1712 if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION &&
1713 iwl_is_associated_ctx(ctx)) {
1714 found_ctx = ctx;
1715 break;
1716 }
1717 }
1718
1719 /*
1720 * rssi monitor already enabled for the correct interface...nothing
1721 * to do.
1722 */
1723 if (found_ctx == priv->cur_rssi_ctx)
1724 return;
1725
1726 /*
1727 * Figure out if rssi monitor is currently enabled, and needs
1728 * to be changed. If rssi monitor is already enabled, disable
1729 * it first else just enable rssi measurements on the
1730 * interface found above.
1731 */
1732 if (priv->cur_rssi_ctx) {
1733 ctx = priv->cur_rssi_ctx;
1734 if (ctx->vif)
1735 ieee80211_disable_rssi_reports(ctx->vif);
1736 }
1737
1738 priv->cur_rssi_ctx = found_ctx;
1739
1740 if (!found_ctx)
1741 return;
1742
1743 ieee80211_enable_rssi_reports(found_ctx->vif,
1744 IWLAGN_BT_PSP_MIN_RSSI_THRESHOLD,
1745 IWLAGN_BT_PSP_MAX_RSSI_THRESHOLD);
1746}
1747
1748static bool iwlagn_bt_traffic_is_sco(struct iwl_bt_uart_msg *uart_msg)
1749{
1750 return BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3 >>
1751 BT_UART_MSG_FRAME3SCOESCO_POS;
1752}
1753
1674static void iwlagn_bt_traffic_change_work(struct work_struct *work) 1754static void iwlagn_bt_traffic_change_work(struct work_struct *work)
1675{ 1755{
1676 struct iwl_priv *priv = 1756 struct iwl_priv *priv =
@@ -1732,10 +1812,30 @@ static void iwlagn_bt_traffic_change_work(struct work_struct *work)
1732 ieee80211_request_smps(ctx->vif, smps_request); 1812 ieee80211_request_smps(ctx->vif, smps_request);
1733 } 1813 }
1734 } 1814 }
1815
1816 /*
1817 * Dynamic PS poll related functionality. Adjust RSSI measurements if
1818 * necessary.
1819 */
1820 iwlagn_bt_coex_rssi_monitor(priv);
1735out: 1821out:
1736 mutex_unlock(&priv->mutex); 1822 mutex_unlock(&priv->mutex);
1737} 1823}
1738 1824
1825/*
1826 * If BT sco traffic, and RSSI monitor is enabled, move measurements to the
1827 * correct interface or disable it if this is the last interface to be
1828 * removed.
1829 */
1830void iwlagn_bt_coex_rssi_monitor(struct iwl_priv *priv)
1831{
1832 if (priv->bt_is_sco &&
1833 priv->bt_traffic_load == IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS)
1834 iwlagn_bt_adjust_rssi_monitor(priv, true);
1835 else
1836 iwlagn_bt_adjust_rssi_monitor(priv, false);
1837}
1838
1739static void iwlagn_print_uartmsg(struct iwl_priv *priv, 1839static void iwlagn_print_uartmsg(struct iwl_priv *priv,
1740 struct iwl_bt_uart_msg *uart_msg) 1840 struct iwl_bt_uart_msg *uart_msg)
1741{ 1841{
@@ -1851,6 +1951,8 @@ void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
1851 iwlagn_print_uartmsg(priv, uart_msg); 1951 iwlagn_print_uartmsg(priv, uart_msg);
1852 1952
1853 priv->last_bt_traffic_load = priv->bt_traffic_load; 1953 priv->last_bt_traffic_load = priv->bt_traffic_load;
1954 priv->bt_is_sco = iwlagn_bt_traffic_is_sco(uart_msg);
1955
1854 if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { 1956 if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
1855 if (priv->bt_status != coex->bt_status || 1957 if (priv->bt_status != coex->bt_status ||
1856 priv->last_bt_traffic_load != coex->bt_traffic_load) { 1958 priv->last_bt_traffic_load != coex->bt_traffic_load) {
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
index d32cee1a758a..fca376e91541 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
@@ -731,6 +731,8 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
731 } 731 }
732 ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; 732 ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
733 } 733 }
734
735 iwlagn_bt_coex_rssi_monitor(priv);
734 } 736 }
735 737
736 if (ctx->ht.enabled) { 738 if (ctx->ht.enabled) {
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 3a4fca14fef8..cbd8d101f6f8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -2015,11 +2015,18 @@ int iwl_alive_start(struct iwl_priv *priv)
2015 if (priv->cfg->bt_params && 2015 if (priv->cfg->bt_params &&
2016 priv->cfg->bt_params->advanced_bt_coexist) { 2016 priv->cfg->bt_params->advanced_bt_coexist) {
2017 /* Configure Bluetooth device coexistence support */ 2017 /* Configure Bluetooth device coexistence support */
2018 if (priv->cfg->bt_params->bt_sco_disable)
2019 priv->bt_enable_pspoll = false;
2020 else
2021 priv->bt_enable_pspoll = true;
2022
2018 priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK; 2023 priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK;
2019 priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT; 2024 priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT;
2020 priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT; 2025 priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT;
2021 iwlagn_send_advance_bt_config(priv); 2026 iwlagn_send_advance_bt_config(priv);
2022 priv->bt_valid = IWLAGN_BT_VALID_ENABLE_FLAGS; 2027 priv->bt_valid = IWLAGN_BT_VALID_ENABLE_FLAGS;
2028 priv->cur_rssi_ctx = NULL;
2029
2023 iwlagn_send_prio_tbl(priv); 2030 iwlagn_send_prio_tbl(priv);
2024 2031
2025 /* FIXME: w/a to force change uCode BT state machine */ 2032 /* FIXME: w/a to force change uCode BT state machine */
@@ -2102,6 +2109,8 @@ static void __iwl_down(struct iwl_priv *priv)
2102 2109
2103 /* reset BT coex data */ 2110 /* reset BT coex data */
2104 priv->bt_status = 0; 2111 priv->bt_status = 0;
2112 priv->cur_rssi_ctx = NULL;
2113 priv->bt_is_sco = 0;
2105 if (priv->cfg->bt_params) 2114 if (priv->cfg->bt_params)
2106 priv->bt_traffic_load = 2115 priv->bt_traffic_load =
2107 priv->cfg->bt_params->bt_init_traffic_load; 2116 priv->cfg->bt_params->bt_init_traffic_load;
@@ -2277,6 +2286,7 @@ static void iwlagn_prepare_restart(struct iwl_priv *priv)
2277 u8 bt_ci_compliance; 2286 u8 bt_ci_compliance;
2278 u8 bt_load; 2287 u8 bt_load;
2279 u8 bt_status; 2288 u8 bt_status;
2289 bool bt_is_sco;
2280 2290
2281 lockdep_assert_held(&priv->mutex); 2291 lockdep_assert_held(&priv->mutex);
2282 2292
@@ -2297,6 +2307,7 @@ static void iwlagn_prepare_restart(struct iwl_priv *priv)
2297 bt_ci_compliance = priv->bt_ci_compliance; 2307 bt_ci_compliance = priv->bt_ci_compliance;
2298 bt_load = priv->bt_traffic_load; 2308 bt_load = priv->bt_traffic_load;
2299 bt_status = priv->bt_status; 2309 bt_status = priv->bt_status;
2310 bt_is_sco = priv->bt_is_sco;
2300 2311
2301 __iwl_down(priv); 2312 __iwl_down(priv);
2302 2313
@@ -2304,6 +2315,7 @@ static void iwlagn_prepare_restart(struct iwl_priv *priv)
2304 priv->bt_ci_compliance = bt_ci_compliance; 2315 priv->bt_ci_compliance = bt_ci_compliance;
2305 priv->bt_traffic_load = bt_load; 2316 priv->bt_traffic_load = bt_load;
2306 priv->bt_status = bt_status; 2317 priv->bt_status = bt_status;
2318 priv->bt_is_sco = bt_is_sco;
2307} 2319}
2308 2320
2309static void iwl_bg_restart(struct work_struct *data) 2321static void iwl_bg_restart(struct work_struct *data)
@@ -3330,6 +3342,29 @@ static void iwl_uninit_drv(struct iwl_priv *priv)
3330 kfree(priv->beacon_cmd); 3342 kfree(priv->beacon_cmd);
3331} 3343}
3332 3344
3345void iwl_mac_rssi_callback(struct ieee80211_hw *hw,
3346 enum ieee80211_rssi_event rssi_event)
3347{
3348 struct iwl_priv *priv = hw->priv;
3349
3350 mutex_lock(&priv->mutex);
3351
3352 if (priv->cfg->bt_params &&
3353 priv->cfg->bt_params->advanced_bt_coexist) {
3354 if (rssi_event == RSSI_EVENT_LOW)
3355 priv->bt_enable_pspoll = true;
3356 else if (rssi_event == RSSI_EVENT_HIGH)
3357 priv->bt_enable_pspoll = false;
3358
3359 iwlagn_send_advance_bt_config(priv);
3360 } else {
3361 IWL_DEBUG_MAC80211(priv, "Advanced BT coex disabled,"
3362 "ignoring RSSI callback\n");
3363 }
3364
3365 mutex_unlock(&priv->mutex);
3366}
3367
3333struct ieee80211_ops iwlagn_hw_ops = { 3368struct ieee80211_ops iwlagn_hw_ops = {
3334 .tx = iwlagn_mac_tx, 3369 .tx = iwlagn_mac_tx,
3335 .start = iwlagn_mac_start, 3370 .start = iwlagn_mac_start,
@@ -3355,6 +3390,7 @@ struct ieee80211_ops iwlagn_hw_ops = {
3355 .cancel_remain_on_channel = iwl_mac_cancel_remain_on_channel, 3390 .cancel_remain_on_channel = iwl_mac_cancel_remain_on_channel,
3356 .offchannel_tx = iwl_mac_offchannel_tx, 3391 .offchannel_tx = iwl_mac_offchannel_tx,
3357 .offchannel_tx_cancel_wait = iwl_mac_offchannel_tx_cancel_wait, 3392 .offchannel_tx_cancel_wait = iwl_mac_offchannel_tx_cancel_wait,
3393 .rssi_callback = iwl_mac_rssi_callback,
3358 CFG80211_TESTMODE_CMD(iwl_testmode_cmd) 3394 CFG80211_TESTMODE_CMD(iwl_testmode_cmd)
3359 CFG80211_TESTMODE_DUMP(iwl_testmode_dump) 3395 CFG80211_TESTMODE_DUMP(iwl_testmode_dump)
3360}; 3396};
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h
index bde03b4f3864..81a009bdd67b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.h
@@ -261,6 +261,8 @@ void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
261void iwlagn_bt_rx_handler_setup(struct iwl_priv *priv); 261void iwlagn_bt_rx_handler_setup(struct iwl_priv *priv);
262void iwlagn_bt_setup_deferred_work(struct iwl_priv *priv); 262void iwlagn_bt_setup_deferred_work(struct iwl_priv *priv);
263void iwlagn_bt_cancel_deferred_work(struct iwl_priv *priv); 263void iwlagn_bt_cancel_deferred_work(struct iwl_priv *priv);
264void iwlagn_bt_coex_rssi_monitor(struct iwl_priv *priv);
265void iwlagn_bt_adjust_rssi_monitor(struct iwl_priv *priv, bool rssi_ena);
264 266
265#ifdef CONFIG_IWLWIFI_DEBUG 267#ifdef CONFIG_IWLWIFI_DEBUG
266const char *iwl_get_tx_fail_reason(u32 status); 268const char *iwl_get_tx_fail_reason(u32 status);
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index 8a2edf8dce32..ee2563777e8d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -1931,6 +1931,9 @@ struct iwl_bt_cmd {
1931/* Disable Sync PSPoll on SCO/eSCO */ 1931/* Disable Sync PSPoll on SCO/eSCO */
1932#define IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE BIT(7) 1932#define IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE BIT(7)
1933 1933
1934#define IWLAGN_BT_PSP_MIN_RSSI_THRESHOLD -75 /* dBm */
1935#define IWLAGN_BT_PSP_MAX_RSSI_THRESHOLD -65 /* dBm */
1936
1934#define IWLAGN_BT_PRIO_BOOST_MAX 0xFF 1937#define IWLAGN_BT_PRIO_BOOST_MAX 0xFF
1935#define IWLAGN_BT_PRIO_BOOST_MIN 0x00 1938#define IWLAGN_BT_PRIO_BOOST_MIN 0x00
1936#define IWLAGN_BT_PRIO_BOOST_DEFAULT 0xF0 1939#define IWLAGN_BT_PRIO_BOOST_DEFAULT 0xF0
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 92f8ce9d5a41..29eb41dcb9c3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -1525,6 +1525,9 @@ struct iwl_priv {
1525 u16 dynamic_frag_thresh; 1525 u16 dynamic_frag_thresh;
1526 u8 bt_ci_compliance; 1526 u8 bt_ci_compliance;
1527 struct work_struct bt_traffic_change_work; 1527 struct work_struct bt_traffic_change_work;
1528 bool bt_enable_pspoll;
1529 struct iwl_rxon_context *cur_rssi_ctx;
1530 bool bt_is_sco;
1528 1531
1529 struct iwl_hw_params hw_params; 1532 struct iwl_hw_params hw_params;
1530 1533