summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/iwlwifi/mvm/sta.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/sta.c')
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.c94
1 files changed, 66 insertions, 28 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c
index 763548880399..dd9f3a4347f6 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.c
@@ -6,6 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -250,10 +252,14 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
if (ret)
return ret;
- /* The first station added is the AP, the others are TDLS STAs */
- if (vif->type == NL80211_IFTYPE_STATION &&
- mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)
- mvmvif->ap_sta_id = sta_id;
+ if (vif->type == NL80211_IFTYPE_STATION) {
+ if (!sta->tdls) {
+ WARN_ON(mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT);
+ mvmvif->ap_sta_id = sta_id;
+ } else {
+ WARN_ON(mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT);
+ }
+ }
rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], sta);
@@ -458,8 +464,9 @@ int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm,
return ret;
}
-int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta,
- u32 qmask, enum nl80211_iftype iftype)
+static int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm,
+ struct iwl_mvm_int_sta *sta,
+ 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, iftype);
@@ -474,7 +481,8 @@ int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta,
return 0;
}
-void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta)
+static void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm,
+ struct iwl_mvm_int_sta *sta)
{
RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta->sta_id], NULL);
memset(sta, 0, sizeof(struct iwl_mvm_int_sta));
@@ -544,6 +552,13 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm)
return ret;
}
+void iwl_mvm_del_aux_sta(struct iwl_mvm *mvm)
+{
+ lockdep_assert_held(&mvm->mutex);
+
+ iwl_mvm_dealloc_int_sta(mvm, &mvm->aux_sta);
+}
+
/*
* Send the add station command for the vif's broadcast station.
* Assumes that the station was already allocated.
@@ -552,10 +567,10 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm)
* @vif: the interface to which the broadcast station is added
* @bsta: the broadcast station to add.
*/
-int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- struct iwl_mvm_int_sta *bsta)
+int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm_int_sta *bsta = &mvmvif->bcast_sta;
static const u8 _baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
const u8 *baddr = _baddr;
@@ -573,19 +588,40 @@ int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
/* Send the FW a request to remove the station from it's internal data
* structures, but DO NOT remove the entry from the local data structures. */
-int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm,
- struct iwl_mvm_int_sta *bsta)
+int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
int ret;
lockdep_assert_held(&mvm->mutex);
- ret = iwl_mvm_rm_sta_common(mvm, bsta->sta_id);
+ ret = iwl_mvm_rm_sta_common(mvm, mvmvif->bcast_sta.sta_id);
if (ret)
IWL_WARN(mvm, "Failed sending remove station\n");
return ret;
}
+int iwl_mvm_alloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ u32 qmask;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ qmask = iwl_mvm_mac_get_queues_mask(mvm, vif);
+
+ /*
+ * The firmware defines the TFD queue mask to only be relevant
+ * for *unicast* queues, so the multicast (CAB) queue shouldn't
+ * be included.
+ */
+ if (vif->type == NL80211_IFTYPE_AP)
+ qmask &= ~BIT(vif->cab_queue);
+
+ return iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta, qmask,
+ ieee80211_vif_type_p2p(vif));
+}
+
/* Allocate a new station entry for the broadcast station to the given vif,
* and send it to the FW.
* Note that each P2P mac should have its own broadcast station.
@@ -593,45 +629,47 @@ int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm,
* @mvm: the mvm component
* @vif: the interface to which the broadcast station is added
* @bsta: the broadcast station to add. */
-int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- struct iwl_mvm_int_sta *bsta)
+int iwl_mvm_add_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};
- u32 qmask;
+ struct iwl_mvm_int_sta *bsta = &mvmvif->bcast_sta;
int ret;
lockdep_assert_held(&mvm->mutex);
- qmask = iwl_mvm_mac_get_queues_mask(mvm, vif);
- ret = iwl_mvm_allocate_int_sta(mvm, bsta, qmask,
- ieee80211_vif_type_p2p(vif));
+ ret = iwl_mvm_alloc_bcast_sta(mvm, vif);
if (ret)
return ret;
- ret = iwl_mvm_add_int_sta_common(mvm, bsta, baddr,
- mvmvif->id, mvmvif->color);
+ ret = iwl_mvm_send_add_bcast_sta(mvm, vif);
if (ret)
iwl_mvm_dealloc_int_sta(mvm, bsta);
+
return ret;
}
+void iwl_mvm_dealloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+ iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta);
+}
+
/*
* Send the FW a request to remove the station from it's internal data
* structures, and in addition remove it from the local data structure.
*/
-int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *bsta)
+int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
int ret;
lockdep_assert_held(&mvm->mutex);
- ret = iwl_mvm_rm_sta_common(mvm, bsta->sta_id);
- if (ret)
- return ret;
+ ret = iwl_mvm_send_rm_bcast_sta(mvm, vif);
+
+ iwl_mvm_dealloc_bcast_sta(mvm, vif);
- iwl_mvm_dealloc_int_sta(mvm, bsta);
return ret;
}
@@ -910,7 +948,7 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
}
tid_data->ssn = 0xffff;
- iwl_trans_txq_disable(mvm->trans, txq_id);
+ iwl_trans_txq_disable(mvm->trans, txq_id, true);
/* fall through */
case IWL_AGG_STARTING:
case IWL_EMPTYING_HW_QUEUE_ADDBA:
@@ -965,7 +1003,7 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true))
IWL_ERR(mvm, "Couldn't flush the AGG queue\n");
- iwl_trans_txq_disable(mvm->trans, tid_data->txq_id);
+ iwl_trans_txq_disable(mvm->trans, tid_data->txq_id, true);
}
mvm->queue_to_mac80211[tid_data->txq_id] =