Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless
[pandora-kernel.git] / drivers / net / wireless / iwlwifi / mvm / sta.c
index af94f75..2677d1c 100644 (file)
@@ -175,19 +175,30 @@ static int iwl_mvm_send_add_sta_key_cmd(struct iwl_mvm *mvm,
                                    &sta_cmd);
 }
 
-static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm)
+static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm,
+                                   enum nl80211_iftype iftype)
 {
        int sta_id;
+       u32 reserved_ids = 0;
 
+       BUILD_BUG_ON(IWL_MVM_STATION_COUNT > 32);
        WARN_ON_ONCE(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status));
 
        lockdep_assert_held(&mvm->mutex);
 
+       /* d0i3/d3 assumes the AP's sta_id (of sta vif) is 0. reserve it. */
+       if (iftype != NL80211_IFTYPE_STATION)
+               reserved_ids = BIT(0);
+
        /* Don't take rcu_read_lock() since we are protected by mvm->mutex */
-       for (sta_id = 0; sta_id < IWL_MVM_STATION_COUNT; sta_id++)
+       for (sta_id = 0; sta_id < IWL_MVM_STATION_COUNT; sta_id++) {
+               if (BIT(sta_id) & reserved_ids)
+                       continue;
+
                if (!rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
                                               lockdep_is_held(&mvm->mutex)))
                        return sta_id;
+       }
        return IWL_MVM_STATION_COUNT;
 }
 
@@ -312,7 +323,8 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
        lockdep_assert_held(&mvm->mutex);
 
        if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
-               sta_id = iwl_mvm_find_free_sta_id(mvm);
+               sta_id = iwl_mvm_find_free_sta_id(mvm,
+                                                 ieee80211_vif_type_p2p(vif));
        else
                sta_id = mvm_sta->sta_id;
 
@@ -522,6 +534,10 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
 
                /* unassoc - go ahead - remove the AP STA now */
                mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT;
+
+               /* clear d0i3_ap_sta_id if no longer relevant */
+               if (mvm->d0i3_ap_sta_id == mvm_sta->sta_id)
+                       mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT;
        }
 
        /*
@@ -560,10 +576,10 @@ int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm,
 }
 
 int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta,
-                            u32 qmask)
+                            u32 qmask, enum nl80211_iftype iftype)
 {
        if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
-               sta->sta_id = iwl_mvm_find_free_sta_id(mvm);
+               sta->sta_id = iwl_mvm_find_free_sta_id(mvm, iftype);
                if (WARN_ON_ONCE(sta->sta_id == IWL_MVM_STATION_COUNT))
                        return -ENOSPC;
        }
@@ -627,7 +643,8 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm)
        lockdep_assert_held(&mvm->mutex);
 
        /* Add the aux station, but without any queues */
-       ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, 0);
+       ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, 0,
+                                      NL80211_IFTYPE_UNSPECIFIED);
        if (ret)
                return ret;
 
@@ -652,7 +669,7 @@ int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        static const u8 _baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
-       static const u8 *baddr = _baddr;
+       const u8 *baddr = _baddr;
 
        lockdep_assert_held(&mvm->mutex);
 
@@ -699,7 +716,8 @@ int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        lockdep_assert_held(&mvm->mutex);
 
        qmask = iwl_mvm_mac_get_queues_mask(mvm, vif);
-       ret = iwl_mvm_allocate_int_sta(mvm, bsta, qmask);
+       ret = iwl_mvm_allocate_int_sta(mvm, bsta, qmask,
+                                      ieee80211_vif_type_p2p(vif));
        if (ret)
                return ret;