aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSara Sharon <sara.sharon@intel.com>2016-12-07 08:04:37 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-05-14 08:00:17 -0400
commit4d6f2ac95bc55bd78c415006a67c03e787d79989 (patch)
treeb1e5b98d5c7e896fa834bc0767d620acfefd191f
parent48aa5ec292f3eba8f22a5b4d3a8eee123e7680dc (diff)
iwlwifi: mvm: fix pending frame counter calculation
commit 94c3e614df2117626fccfac8f821c66e30556384 upstream. In DQA mode the check whether to decrement the pending frames counter relies on the tid status and not on the txq id. This may result in an inconsistent state of the pending frames counter in case frame is queued on a non aggregation queue but with this TID, and will be followed by a failure to remove the station and later on SYSASSERT 0x3421 when trying to remove the MAC. Such frames are for example bar and qos NDPs. Fix it by aligning the condition of incrementing the counter with the condition of decrementing it - rely on TID state for DQA mode. Also, avoid internal error like this affecting station removal for DQA mode - since we can know for sure it is an internal error. Fixes: cf961e16620f ("iwlwifi: mvm: support dqa-mode agg on non-shared queue") Signed-off-by: Sara Sharon <sara.sharon@intel.com> Signed-off-by: Luca Coelho <luciano.coelho@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/sta.c31
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/tx.c5
2 files changed, 24 insertions, 12 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
index 52de3c6d760c..e64aeb4a2204 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
@@ -1466,6 +1466,7 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
1466{ 1466{
1467 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1467 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1468 struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); 1468 struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
1469 u8 sta_id = mvm_sta->sta_id;
1469 int ret; 1470 int ret;
1470 1471
1471 lockdep_assert_held(&mvm->mutex); 1472 lockdep_assert_held(&mvm->mutex);
@@ -1474,7 +1475,7 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
1474 kfree(mvm_sta->dup_data); 1475 kfree(mvm_sta->dup_data);
1475 1476
1476 if ((vif->type == NL80211_IFTYPE_STATION && 1477 if ((vif->type == NL80211_IFTYPE_STATION &&
1477 mvmvif->ap_sta_id == mvm_sta->sta_id) || 1478 mvmvif->ap_sta_id == sta_id) ||
1478 iwl_mvm_is_dqa_supported(mvm)){ 1479 iwl_mvm_is_dqa_supported(mvm)){
1479 ret = iwl_mvm_drain_sta(mvm, mvm_sta, true); 1480 ret = iwl_mvm_drain_sta(mvm, mvm_sta, true);
1480 if (ret) 1481 if (ret)
@@ -1497,6 +1498,15 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
1497 iwl_mvm_disable_sta_queues(mvm, vif, mvm_sta); 1498 iwl_mvm_disable_sta_queues(mvm, vif, mvm_sta);
1498 1499
1499 /* 1500 /*
1501 * If pending_frames is set at this point - it must be
1502 * driver internal logic error, since queues are empty
1503 * and removed successuly.
1504 * warn on it but set it to 0 anyway to avoid station
1505 * not being removed later in the function
1506 */
1507 WARN_ON(atomic_xchg(&mvm->pending_frames[sta_id], 0));
1508
1509 /*
1500 * If no traffic has gone through the reserved TXQ - it 1510 * If no traffic has gone through the reserved TXQ - it
1501 * is still marked as IWL_MVM_QUEUE_RESERVED, and 1511 * is still marked as IWL_MVM_QUEUE_RESERVED, and
1502 * should be manually marked as free again 1512 * should be manually marked as free again
@@ -1506,7 +1516,7 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
1506 if (WARN((*status != IWL_MVM_QUEUE_RESERVED) && 1516 if (WARN((*status != IWL_MVM_QUEUE_RESERVED) &&
1507 (*status != IWL_MVM_QUEUE_FREE), 1517 (*status != IWL_MVM_QUEUE_FREE),
1508 "sta_id %d reserved txq %d status %d", 1518 "sta_id %d reserved txq %d status %d",
1509 mvm_sta->sta_id, reserved_txq, *status)) { 1519 sta_id, reserved_txq, *status)) {
1510 spin_unlock_bh(&mvm->queue_info_lock); 1520 spin_unlock_bh(&mvm->queue_info_lock);
1511 return -EINVAL; 1521 return -EINVAL;
1512 } 1522 }
@@ -1516,7 +1526,7 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
1516 } 1526 }
1517 1527
1518 if (vif->type == NL80211_IFTYPE_STATION && 1528 if (vif->type == NL80211_IFTYPE_STATION &&
1519 mvmvif->ap_sta_id == mvm_sta->sta_id) { 1529 mvmvif->ap_sta_id == sta_id) {
1520 /* if associated - we can't remove the AP STA now */ 1530 /* if associated - we can't remove the AP STA now */
1521 if (vif->bss_conf.assoc) 1531 if (vif->bss_conf.assoc)
1522 return ret; 1532 return ret;
@@ -1525,7 +1535,7 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
1525 mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; 1535 mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT;
1526 1536
1527 /* clear d0i3_ap_sta_id if no longer relevant */ 1537 /* clear d0i3_ap_sta_id if no longer relevant */
1528 if (mvm->d0i3_ap_sta_id == mvm_sta->sta_id) 1538 if (mvm->d0i3_ap_sta_id == sta_id)
1529 mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; 1539 mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT;
1530 } 1540 }
1531 } 1541 }
@@ -1534,7 +1544,7 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
1534 * This shouldn't happen - the TDLS channel switch should be canceled 1544 * This shouldn't happen - the TDLS channel switch should be canceled
1535 * before the STA is removed. 1545 * before the STA is removed.
1536 */ 1546 */
1537 if (WARN_ON_ONCE(mvm->tdls_cs.peer.sta_id == mvm_sta->sta_id)) { 1547 if (WARN_ON_ONCE(mvm->tdls_cs.peer.sta_id == sta_id)) {
1538 mvm->tdls_cs.peer.sta_id = IWL_MVM_STATION_COUNT; 1548 mvm->tdls_cs.peer.sta_id = IWL_MVM_STATION_COUNT;
1539 cancel_delayed_work(&mvm->tdls_cs.dwork); 1549 cancel_delayed_work(&mvm->tdls_cs.dwork);
1540 } 1550 }
@@ -1544,21 +1554,20 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
1544 * calls the drain worker. 1554 * calls the drain worker.
1545 */ 1555 */
1546 spin_lock_bh(&mvm_sta->lock); 1556 spin_lock_bh(&mvm_sta->lock);
1557
1547 /* 1558 /*
1548 * There are frames pending on the AC queues for this station. 1559 * There are frames pending on the AC queues for this station.
1549 * We need to wait until all the frames are drained... 1560 * We need to wait until all the frames are drained...
1550 */ 1561 */
1551 if (atomic_read(&mvm->pending_frames[mvm_sta->sta_id])) { 1562 if (atomic_read(&mvm->pending_frames[sta_id])) {
1552 rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], 1563 rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id],
1553 ERR_PTR(-EBUSY)); 1564 ERR_PTR(-EBUSY));
1554 spin_unlock_bh(&mvm_sta->lock); 1565 spin_unlock_bh(&mvm_sta->lock);
1555 1566
1556 /* disable TDLS sta queues on drain complete */ 1567 /* disable TDLS sta queues on drain complete */
1557 if (sta->tdls) { 1568 if (sta->tdls) {
1558 mvm->tfd_drained[mvm_sta->sta_id] = 1569 mvm->tfd_drained[sta_id] = mvm_sta->tfd_queue_msk;
1559 mvm_sta->tfd_queue_msk; 1570 IWL_DEBUG_TDLS(mvm, "Draining TDLS sta %d\n", sta_id);
1560 IWL_DEBUG_TDLS(mvm, "Draining TDLS sta %d\n",
1561 mvm_sta->sta_id);
1562 } 1571 }
1563 1572
1564 ret = iwl_mvm_drain_sta(mvm, mvm_sta, true); 1573 ret = iwl_mvm_drain_sta(mvm, mvm_sta, true);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
index 1d116c06cd1c..4cb839ae3e22 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
@@ -1008,7 +1008,10 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
1008 spin_unlock(&mvmsta->lock); 1008 spin_unlock(&mvmsta->lock);
1009 1009
1010 /* Increase pending frames count if this isn't AMPDU */ 1010 /* Increase pending frames count if this isn't AMPDU */
1011 if (!is_ampdu) 1011 if ((iwl_mvm_is_dqa_supported(mvm) &&
1012 mvmsta->tid_data[tx_cmd->tid_tspec].state != IWL_AGG_ON &&
1013 mvmsta->tid_data[tx_cmd->tid_tspec].state != IWL_AGG_STARTING) ||
1014 (!iwl_mvm_is_dqa_supported(mvm) && !is_ampdu))
1012 atomic_inc(&mvm->pending_frames[mvmsta->sta_id]); 1015 atomic_inc(&mvm->pending_frames[mvmsta->sta_id]);
1013 1016
1014 return 0; 1017 return 0;