aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/mvm/tx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/tx.c')
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tx.c72
1 files changed, 56 insertions, 16 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c
index dbc870713882..1cb793a498ac 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tx.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
@@ -131,6 +133,11 @@ static void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,
!is_multicast_ether_addr(ieee80211_get_DA(hdr)))
tx_flags |= TX_CMD_FLG_PROT_REQUIRE;
+ if ((mvm->fw->ucode_capa.capa[0] &
+ IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT) &&
+ ieee80211_action_contains_tpc(skb))
+ tx_flags |= TX_CMD_FLG_WRITE_TX_POWER;
+
tx_cmd->tx_flags = cpu_to_le32(tx_flags);
/* Total # bytes to be transmitted */
tx_cmd->len = cpu_to_le16((u16)skb->len);
@@ -168,10 +175,14 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm,
/*
* for data packets, rate info comes from the table inside the fw. This
- * table is controlled by LINK_QUALITY commands
+ * table is controlled by LINK_QUALITY commands. Exclude ctrl port
+ * frames like EAPOLs which should be treated as mgmt frames. This
+ * avoids them being sent initially in high rates which increases the
+ * chances for completion of the 4-Way handshake.
*/
- if (ieee80211_is_data(fc) && sta) {
+ if (ieee80211_is_data(fc) && sta &&
+ !(info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)) {
tx_cmd->initial_rate_index = 0;
tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE);
return;
@@ -207,7 +218,7 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm,
if (info->band == IEEE80211_BAND_2GHZ &&
!iwl_mvm_bt_coex_is_shared_ant_avail(mvm))
- rate_flags = BIT(ANT_A) << RATE_MCS_ANT_POS;
+ rate_flags = BIT(mvm->cfg->non_shared_ant) << RATE_MCS_ANT_POS;
else
rate_flags =
BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS;
@@ -482,11 +493,11 @@ static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm,
IWL_DEBUG_TX_QUEUES(mvm,
"Can continue DELBA flow ssn = next_recl = %d\n",
tid_data->next_reclaimed);
- iwl_trans_txq_disable(mvm->trans, tid_data->txq_id);
+ iwl_mvm_disable_txq(mvm, tid_data->txq_id);
tid_data->state = IWL_AGG_OFF;
/*
* we can't hold the mutex - but since we are after a sequence
- * point (call to iwl_trans_txq_disable), so we don't even need
+ * point (call to iwl_mvm_disable_txq(), so we don't even need
* a memory barrier.
*/
mvm->queue_to_mac80211[tid_data->txq_id] =
@@ -862,6 +873,19 @@ int iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
return 0;
}
+static void iwl_mvm_tx_info_from_ba_notif(struct ieee80211_tx_info *info,
+ struct iwl_mvm_ba_notif *ba_notif,
+ struct iwl_mvm_tid_data *tid_data)
+{
+ info->flags |= IEEE80211_TX_STAT_AMPDU;
+ info->status.ampdu_ack_len = ba_notif->txed_2_done;
+ info->status.ampdu_len = ba_notif->txed;
+ iwl_mvm_hwrate_to_tx_status(tid_data->rate_n_flags,
+ info);
+ info->status.status_driver_data[0] =
+ (void *)(uintptr_t)tid_data->reduced_tpc;
+}
+
int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd)
{
@@ -948,21 +972,37 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
*/
info->flags |= IEEE80211_TX_STAT_ACK;
- if (freed == 1) {
- /* this is the first skb we deliver in this batch */
- /* put the rate scaling data there */
- info->flags |= IEEE80211_TX_STAT_AMPDU;
- info->status.ampdu_ack_len = ba_notif->txed_2_done;
- info->status.ampdu_len = ba_notif->txed;
- iwl_mvm_hwrate_to_tx_status(tid_data->rate_n_flags,
- info);
- info->status.status_driver_data[0] =
- (void *)(uintptr_t)tid_data->reduced_tpc;
- }
+ /* this is the first skb we deliver in this batch */
+ /* put the rate scaling data there */
+ if (freed == 1)
+ iwl_mvm_tx_info_from_ba_notif(info, ba_notif, tid_data);
}
spin_unlock_bh(&mvmsta->lock);
+ /* We got a BA notif with 0 acked or scd_ssn didn't progress which is
+ * possible (i.e. first MPDU in the aggregation wasn't acked)
+ * Still it's important to update RS about sent vs. acked.
+ */
+ if (skb_queue_empty(&reclaimed_skbs)) {
+ struct ieee80211_tx_info ba_info = {};
+ struct ieee80211_chanctx_conf *chanctx_conf = NULL;
+
+ if (mvmsta->vif)
+ chanctx_conf =
+ rcu_dereference(mvmsta->vif->chanctx_conf);
+
+ if (WARN_ON_ONCE(!chanctx_conf))
+ goto out;
+
+ ba_info.band = chanctx_conf->def.chan->band;
+ iwl_mvm_tx_info_from_ba_notif(&ba_info, ba_notif, tid_data);
+
+ IWL_DEBUG_TX_REPLY(mvm, "No reclaim. Update rs directly\n");
+ iwl_mvm_rs_tx_status(mvm, sta, tid, &ba_info);
+ }
+
+out:
rcu_read_unlock();
while (!skb_queue_empty(&reclaimed_skbs)) {