iwlagn: let bluetooth traffic load impact rate scale
authorJohannes Berg <johannes.berg@intel.com>
Mon, 23 Aug 2010 14:56:58 +0000 (07:56 -0700)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 25 Aug 2010 18:33:22 +0000 (14:33 -0400)
Depending on the amount of bluetooth traffic,
using the shared antenna (antenna B) will have
adverse impact on both bluetooth and wireless
traffic. Add controls to improve the situation
by making rate scaling depend on the BT load.

When there's high bluetooth traffic load, there's
little point in trying to aggregate as BT traffic
would disrupt the aggregated frames all the time,
so simply don't start sessions then.

When BT traffic returns to lower levels, the rate
scaling will come here again automatically when
wifi traffic is high enough, and then it will be
able to successfully enable aggregation.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/iwlwifi/iwl-agn-rs.c
drivers/net/wireless/iwlwifi/iwl-agn-rs.h

index a4563389bad0db18eb5f2106903e85c3521f6ad2..f8eed92c1addc6b09dd2d9fc5c815ff4f5efe216 100644 (file)
@@ -301,7 +301,19 @@ static int rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
                                      struct ieee80211_sta *sta)
 {
        int ret = -EAGAIN;
-       u32 load = rs_tl_get_load(lq_data, tid);
+       u32 load;
+
+       /*
+        * Don't create TX aggregation sessions when in high
+        * BT traffic, as they would just be disrupted by BT.
+        */
+       if (priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) {
+               IWL_ERR(priv, "BT traffic (%d), no aggregation allowed\n",
+                       priv->bt_traffic_load);
+               return ret;
+       }
+
+       load = rs_tl_get_load(lq_data, tid);
 
        if (load > IWL_AGG_LOAD_THRESHOLD) {
                IWL_DEBUG_HT(priv, "Starting Tx agg: STA: %pM tid: %d\n",
@@ -1286,6 +1298,27 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
        int ret = 0;
        u8 update_search_tbl_counter = 0;
 
+       switch (priv->bt_traffic_load) {
+       case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+               /* nothing */
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+               /* avoid antenna B unless MIMO */
+               if (tbl->action == IWL_LEGACY_SWITCH_ANTENNA2)
+                       tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+       case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+               /* avoid antenna B and MIMO */
+               if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2 &&
+                   tbl->action != IWL_LEGACY_SWITCH_SISO)
+                       tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+               break;
+       default:
+               IWL_ERR(priv, "Invalid BT load %d", priv->bt_traffic_load);
+               break;
+       }
+
        if (!iwl_ht_enabled(priv))
                /* stay in Legacy */
                tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
@@ -1425,6 +1458,27 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
        u8 update_search_tbl_counter = 0;
        int ret;
 
+       switch (priv->bt_traffic_load) {
+       case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+               /* nothing */
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+               /* avoid antenna B unless MIMO */
+               if (tbl->action == IWL_SISO_SWITCH_ANTENNA2)
+                       tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+       case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+               /* avoid antenna B and MIMO */
+               if (tbl->action >= IWL_SISO_SWITCH_ANTENNA2 &&
+                   tbl->action != IWL_SISO_SWITCH_GI)
+                       tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+               break;
+       default:
+               IWL_ERR(priv, "Invalid BT load %d", priv->bt_traffic_load);
+               break;
+       }
+
        if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE &&
            tbl->action > IWL_SISO_SWITCH_ANTENNA2) {
                /* stay in SISO */
@@ -1564,6 +1618,27 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv,
        u8 update_search_tbl_counter = 0;
        int ret;
 
+       switch (priv->bt_traffic_load) {
+       case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+               /* nothing */
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+       case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+               /* avoid antenna B and MIMO */
+               if (tbl->action == IWL_MIMO2_SWITCH_MIMO3_ABC)
+                       tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+       case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+               /* avoid antenna B unless MIMO */
+               if (tbl->action == IWL_MIMO2_SWITCH_ANTENNA2)
+                       tbl->action = IWL_MIMO2_SWITCH_ANTENNA1;
+               else if (tbl->action == IWL_MIMO2_SWITCH_SISO_B)
+                       tbl->action = IWL_MIMO2_SWITCH_SISO_A;
+               break;
+       default:
+               IWL_ERR(priv, "Invalid BT load %d", priv->bt_traffic_load);
+               break;
+       }
+
        if ((iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE) &&
            (tbl->action < IWL_MIMO2_SWITCH_SISO_A ||
             tbl->action > IWL_MIMO2_SWITCH_SISO_C)) {
@@ -1706,6 +1781,29 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv,
        int ret;
        u8 update_search_tbl_counter = 0;
 
+       switch (priv->bt_traffic_load) {
+       case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+               /* nothing */
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+       case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+               /* avoid antenna B and MIMO */
+               if (tbl->action == IWL_MIMO3_SWITCH_MIMO2_AB ||
+                   tbl->action == IWL_MIMO3_SWITCH_MIMO2_AC ||
+                   tbl->action == IWL_MIMO3_SWITCH_MIMO2_BC)
+                       tbl->action = IWL_MIMO3_SWITCH_SISO_A;
+       case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+               /* avoid antenna B unless MIMO */
+               if (tbl->action == IWL_MIMO3_SWITCH_SISO_B)
+                       tbl->action = IWL_MIMO3_SWITCH_SISO_A;
+               else if (tbl->action == IWL_MIMO3_SWITCH_ANTENNA2)
+                       tbl->action = IWL_MIMO3_SWITCH_ANTENNA1;
+               break;
+       default:
+               IWL_ERR(priv, "Invalid BT load %d", priv->bt_traffic_load);
+               break;
+       }
+
        if ((iwl_tx_ant_restriction(priv) == IWL_ANT_OK_SINGLE) &&
            (tbl->action < IWL_MIMO3_SWITCH_SISO_A ||
             tbl->action > IWL_MIMO3_SWITCH_SISO_C)) {
@@ -2234,6 +2332,19 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
        if (iwl_tx_ant_restriction(priv) != IWL_ANT_OK_MULTI &&
                (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type)))
                scale_action = -1;
+
+       if (lq_sta->last_bt_traffic > priv->bt_traffic_load) {
+               lq_sta->last_bt_traffic = priv->bt_traffic_load;
+               /*
+                * don't set scale_action, don't want to scale up if
+                * the rate scale doesn't otherwise think that is a
+                * good idea.
+                */
+       } else if (lq_sta->last_bt_traffic < priv->bt_traffic_load) {
+               lq_sta->last_bt_traffic = priv->bt_traffic_load;
+               scale_action = -1;
+       }
+
        switch (scale_action) {
        case -1:
                /* Decrease starting rate, update uCode's rate table */
index 8292f6d48ec62067cb5dec7f4076038ad0b46430..3970ab1deaf99cbbe8c8437afd91315ac38705fe 100644 (file)
@@ -432,6 +432,8 @@ struct iwl_lq_sta {
        u32 last_rate_n_flags;
        /* packets destined for this STA are aggregated */
        u8 is_agg;
+       /* BT traffic this sta was last updated in */
+       u8 last_bt_traffic;
 };
 
 static inline u8 num_of_ant(u8 mask)