aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/mvm/mac80211.c
diff options
context:
space:
mode:
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>2015-03-11 03:34:31 -0400
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2015-03-18 02:41:33 -0400
commitfe92e32ace11b21311fbeb8dbf14ac45b87e700d (patch)
treee565098169c5a85c6a2273bc0eab771ab035563c /drivers/net/wireless/iwlwifi/mvm/mac80211.c
parent9243efccd45373fd6431729f88deaa0cf0bbe0be (diff)
iwlwifi: mvm: properly flush the queues for buffering transport
There are transport that must buffer frames in the driver. This means that we have frames that are not in the op_mode and not visible to the firwmare. This causes issues when we flush the queues: the op_mode flushes a queue, and the firmware flushes all the frames that are *currently* on the rings, but if the transport buffers frames, it can submit these while we are flushing. This leads to a situation where we still have frames on the queues after we flushed them. Preventing those buffered frame from getting into the firmware is possible, but then, we have to run the Tx response path on frames that didn't reach the firmware which is not desirable. The way I solve this here is to let these frames go to the firmware, but make sure the firmware will not transmit them (by setting the station as draining). The op_mode then needs to wait until the transport itself is empty to be sure that the queue is really empty. Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/mac80211.c')
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c24
1 files changed, 24 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 5f26557e4197..babe8922faeb 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -1595,9 +1595,33 @@ static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm,
1595 u32 tfd_msk = iwl_mvm_mac_get_queues_mask(vif); 1595 u32 tfd_msk = iwl_mvm_mac_get_queues_mask(vif);
1596 1596
1597 if (tfd_msk) { 1597 if (tfd_msk) {
1598 /*
1599 * mac80211 first removes all the stations of the vif and
1600 * then removes the vif. When it removes a station it also
1601 * flushes the AMPDU session. So by now, all the AMPDU sessions
1602 * of all the stations of this vif are closed, and the queues
1603 * of these AMPDU sessions are properly closed.
1604 * We still need to take care of the shared queues of the vif.
1605 * Flush them here.
1606 */
1598 mutex_lock(&mvm->mutex); 1607 mutex_lock(&mvm->mutex);
1599 iwl_mvm_flush_tx_path(mvm, tfd_msk, true); 1608 iwl_mvm_flush_tx_path(mvm, tfd_msk, true);
1600 mutex_unlock(&mvm->mutex); 1609 mutex_unlock(&mvm->mutex);
1610
1611 /*
1612 * There are transports that buffer a few frames in the host.
1613 * For these, the flush above isn't enough since while we were
1614 * flushing, the transport might have sent more frames to the
1615 * device. To solve this, wait here until the transport is
1616 * empty. Technically, this could have replaced the flush
1617 * above, but flush is much faster than draining. So flush
1618 * first, and drain to make sure we have no frames in the
1619 * transport anymore.
1620 * If a station still had frames on the shared queues, it is
1621 * already marked as draining, so to complete the draining, we
1622 * just need to wait until the transport is empty.
1623 */
1624 iwl_trans_wait_tx_queue_empty(mvm->trans, tfd_msk);
1601 } 1625 }
1602 1626
1603 if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { 1627 if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {