iwlwifi: mvm: update SMPS when BT gets active
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Sun, 10 Feb 2013 15:06:17 +0000 (17:06 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 6 Mar 2013 15:47:59 +0000 (16:47 +0100)
When BT traffic load gets higher, we want to avoid using the
shared antenna. In order to do so, we need to tell the AP
that we don't support MIMO any more, or at least not all
the time: in short, use the SMPS to achieve this.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/iwlwifi/mvm/bt-coex.c

index 61159f8..fa054b3 100644 (file)
@@ -242,12 +242,60 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
                                    sizeof(cmd), &cmd);
 }
 
+struct iwl_bt_notif_iterator_data {
+       struct iwl_mvm *mvm;
+       struct iwl_bt_coex_profile_notif *notif;
+};
+
+static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
+                                     struct ieee80211_vif *vif)
+{
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       struct iwl_bt_notif_iterator_data *data = _data;
+       struct ieee80211_chanctx_conf *chanctx_conf;
+       enum ieee80211_smps_mode smps_mode;
+       enum ieee80211_band band;
+
+       if (vif->type != NL80211_IFTYPE_STATION)
+               return;
+
+       rcu_read_lock();
+       chanctx_conf = rcu_dereference(vif->chanctx_conf);
+       if (chanctx_conf && chanctx_conf->def.chan)
+               band = chanctx_conf->def.chan->band;
+       else
+               band = -1;
+       rcu_read_unlock();
+
+       if (band != IEEE80211_BAND_2GHZ)
+               return;
+
+       smps_mode = IEEE80211_SMPS_AUTOMATIC;
+
+       if (data->notif->bt_status)
+               smps_mode = IEEE80211_SMPS_DYNAMIC;
+
+       if (data->notif->bt_traffic_load)
+               smps_mode = IEEE80211_SMPS_STATIC;
+
+       IWL_DEBUG_COEX(data->mvm,
+                      "mac %d: bt_status %d traffic_load %d smps_req %d\n",
+                      mvmvif->id,  data->notif->bt_status,
+                      data->notif->bt_traffic_load, smps_mode);
+
+       ieee80211_request_smps(vif, smps_mode);
+}
+
 int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
                             struct iwl_rx_cmd_buffer *rxb,
                             struct iwl_device_cmd *dev_cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwl_bt_coex_profile_notif *notif = (void *)pkt->data;
+       struct iwl_bt_notif_iterator_data data = {
+               .mvm = mvm,
+               .notif = notif,
+       };
        struct iwl_bt_coex_cmd cmd = {};
        enum iwl_bt_kill_msk bt_kill_msk;
 
@@ -259,6 +307,10 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
                       notif->bt_agg_traffic_load);
        IWL_DEBUG_COEX(mvm, "\tBT ci compliance %d\n", notif->bt_ci_compliance);
 
+       ieee80211_iterate_active_interfaces_atomic(
+                                       mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+                                       iwl_mvm_bt_notif_iterator, &data);
+
        /* Low latency BT profile is active: give higher prio to BT */
        if (BT_MBOX_MSG(notif, 3, SCO_STATE)  ||
            BT_MBOX_MSG(notif, 3, A2DP_STATE) ||