These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / net / wireless / iwlwifi / mvm / tx.c
index 281451c..6743edf 100644 (file)
@@ -6,7 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 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
@@ -32,7 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #include "mvm.h"
 #include "sta.h"
 
+static void
+iwl_mvm_bar_check_trigger(struct iwl_mvm *mvm, const u8 *addr,
+                         u16 tid, u16 ssn)
+{
+       struct iwl_fw_dbg_trigger_tlv *trig;
+       struct iwl_fw_dbg_trigger_ba *ba_trig;
+
+       if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_BA))
+               return;
+
+       trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_BA);
+       ba_trig = (void *)trig->data;
+
+       if (!iwl_fw_dbg_trigger_check_stop(mvm, NULL, trig))
+               return;
+
+       if (!(le16_to_cpu(ba_trig->tx_bar) & BIT(tid)))
+               return;
+
+       iwl_mvm_fw_dbg_collect_trig(mvm, trig,
+                                   "BAR sent to %pM, tid %d, ssn %d",
+                                   addr, tid, ssn);
+}
+
 /*
  * Sets most of the Tx cmd's fields
  */
@@ -101,12 +125,15 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,
        } else if (ieee80211_is_back_req(fc)) {
                struct ieee80211_bar *bar = (void *)skb->data;
                u16 control = le16_to_cpu(bar->control);
+               u16 ssn = le16_to_cpu(bar->start_seq_num);
 
                tx_flags |= TX_CMD_FLG_ACK | TX_CMD_FLG_BAR;
                tx_cmd->tid_tspec = (control &
                                     IEEE80211_BAR_CTRL_TID_INFO_MASK) >>
                        IEEE80211_BAR_CTRL_TID_INFO_SHIFT;
                WARN_ON_ONCE(tx_cmd->tid_tspec >= IWL_MAX_TID_COUNT);
+               iwl_mvm_bar_check_trigger(mvm, bar->ra, tx_cmd->tid_tspec,
+                                         ssn);
        } else {
                tx_cmd->tid_tspec = IWL_TID_NON_QOS;
                if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
@@ -126,26 +153,28 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,
 
        if (ieee80211_is_mgmt(fc)) {
                if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc))
-                       tx_cmd->pm_frame_timeout = cpu_to_le16(3);
+                       tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_ASSOC);
+               else if (ieee80211_is_action(fc))
+                       tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_NONE);
                else
-                       tx_cmd->pm_frame_timeout = cpu_to_le16(2);
+                       tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_MGMT);
 
                /* The spec allows Action frames in A-MPDU, we don't support
                 * it
                 */
                WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_AMPDU);
        } else if (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO) {
-               tx_cmd->pm_frame_timeout = cpu_to_le16(2);
+               tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_MGMT);
        } else {
-               tx_cmd->pm_frame_timeout = 0;
+               tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_NONE);
        }
 
        if (ieee80211_is_data(fc) && len > mvm->rts_threshold &&
            !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) &&
+       if (fw_has_capa(&mvm->fw->ucode_capa,
+                       IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT) &&
            ieee80211_action_contains_tpc(skb))
                tx_flags |= TX_CMD_FLG_WRITE_TX_POWER;
 
@@ -241,19 +270,29 @@ void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd,
 /*
  * Sets the fields in the Tx cmd that are crypto related
  */
-void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm,
-                              struct ieee80211_tx_info *info,
-                              struct iwl_tx_cmd *tx_cmd,
-                              struct sk_buff *skb_frag)
+static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm,
+                                     struct ieee80211_tx_info *info,
+                                     struct iwl_tx_cmd *tx_cmd,
+                                     struct sk_buff *skb_frag,
+                                     int hdrlen)
 {
        struct ieee80211_key_conf *keyconf = info->control.hw_key;
+       u8 *crypto_hdr = skb_frag->data + hdrlen;
+       u64 pn;
 
        switch (keyconf->cipher) {
        case WLAN_CIPHER_SUITE_CCMP:
-               tx_cmd->sec_ctl = TX_CMD_SEC_CCM;
-               memcpy(tx_cmd->key, keyconf->key, keyconf->keylen);
-               if (info->flags & IEEE80211_TX_CTL_AMPDU)
-                       tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_CCMP_AGG);
+       case WLAN_CIPHER_SUITE_CCMP_256:
+               iwl_mvm_set_tx_cmd_ccmp(info, tx_cmd);
+               pn = atomic64_inc_return(&keyconf->tx_pn);
+               crypto_hdr[0] = pn;
+               crypto_hdr[2] = 0;
+               crypto_hdr[3] = 0x20 | (keyconf->keyidx << 6);
+               crypto_hdr[1] = pn >> 8;
+               crypto_hdr[4] = pn >> 16;
+               crypto_hdr[5] = pn >> 24;
+               crypto_hdr[6] = pn >> 32;
+               crypto_hdr[7] = pn >> 40;
                break;
 
        case WLAN_CIPHER_SUITE_TKIP:
@@ -281,7 +320,7 @@ void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm,
  */
 static struct iwl_device_cmd *
 iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb,
-                     struct ieee80211_sta *sta, u8 sta_id)
+                     int hdrlen, struct ieee80211_sta *sta, u8 sta_id)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -298,7 +337,7 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb,
        tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload;
 
        if (info->control.hw_key)
-               iwl_mvm_set_tx_cmd_crypto(mvm, info, tx_cmd, skb);
+               iwl_mvm_set_tx_cmd_crypto(mvm, info, tx_cmd, skb, hdrlen);
 
        iwl_mvm_set_tx_cmd(mvm, skb, tx_cmd, info, sta_id);
 
@@ -319,6 +358,7 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
        struct iwl_device_cmd *dev_cmd;
        struct iwl_tx_cmd *tx_cmd;
        u8 sta_id;
+       int hdrlen = ieee80211_hdrlen(hdr->frame_control);
 
        if (WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_AMPDU))
                return -1;
@@ -339,23 +379,34 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
                IEEE80211_SKB_CB(skb)->hw_queue = mvm->aux_queue;
 
        /*
-        * If the interface on which frame is sent is the P2P_DEVICE
+        * If the interface on which the frame is sent is the P2P_DEVICE
         * or an AP/GO interface use the broadcast station associated
-        * with it; otherwise use the AUX station.
+        * with it; otherwise if the interface is a managed interface
+        * use the AP station associated with it for multicast traffic
+        * (this is not possible for unicast packets as a TLDS discovery
+        * response are sent without a station entry); otherwise use the
+        * AUX station.
         */
-       if (info->control.vif &&
-           (info->control.vif->type == NL80211_IFTYPE_P2P_DEVICE ||
-            info->control.vif->type == NL80211_IFTYPE_AP)) {
+       sta_id = mvm->aux_sta.sta_id;
+       if (info->control.vif) {
                struct iwl_mvm_vif *mvmvif =
                        iwl_mvm_vif_from_mac80211(info->control.vif);
-               sta_id = mvmvif->bcast_sta.sta_id;
-       } else {
-               sta_id = mvm->aux_sta.sta_id;
+
+               if (info->control.vif->type == NL80211_IFTYPE_P2P_DEVICE ||
+                   info->control.vif->type == NL80211_IFTYPE_AP)
+                       sta_id = mvmvif->bcast_sta.sta_id;
+               else if (info->control.vif->type == NL80211_IFTYPE_STATION &&
+                        is_multicast_ether_addr(hdr->addr1)) {
+                       u8 ap_sta_id = ACCESS_ONCE(mvmvif->ap_sta_id);
+
+                       if (ap_sta_id != IWL_MVM_STATION_COUNT)
+                               sta_id = ap_sta_id;
+               }
        }
 
        IWL_DEBUG_TX(mvm, "station Id %d, queue=%d\n", sta_id, info->hw_queue);
 
-       dev_cmd = iwl_mvm_set_tx_params(mvm, skb, NULL, sta_id);
+       dev_cmd = iwl_mvm_set_tx_params(mvm, skb, hdrlen, NULL, sta_id);
        if (!dev_cmd)
                return -1;
 
@@ -363,13 +414,22 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
        tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload;
 
        /* Copy MAC header from skb into command buffer */
-       memcpy(tx_cmd->hdr, hdr, ieee80211_hdrlen(hdr->frame_control));
+       memcpy(tx_cmd->hdr, hdr, hdrlen);
 
        if (iwl_trans_tx(mvm->trans, skb, dev_cmd, info->hw_queue)) {
                iwl_trans_free_tx_cmd(mvm->trans, dev_cmd);
                return -1;
        }
 
+       /*
+        * Increase the pending frames counter, so that later when a reply comes
+        * in and the counter is decreased - we don't start getting negative
+        * values.
+        * Note that we don't need to make sure it isn't agg'd, since we're
+        * TXing non-sta
+        */
+       atomic_inc(&mvm->pending_frames[sta_id]);
+
        return 0;
 }
 
@@ -389,9 +449,11 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
        u8 tid = IWL_MAX_TID_COUNT;
        u8 txq_id = info->hw_queue;
        bool is_data_qos = false, is_ampdu = false;
+       int hdrlen;
 
        mvmsta = iwl_mvm_sta_from_mac80211(sta);
        fc = hdr->frame_control;
+       hdrlen = ieee80211_hdrlen(fc);
 
        if (WARN_ON_ONCE(!mvmsta))
                return -1;
@@ -399,7 +461,7 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
        if (WARN_ON_ONCE(mvmsta->sta_id == IWL_MVM_STATION_COUNT))
                return -1;
 
-       dev_cmd = iwl_mvm_set_tx_params(mvm, skb, sta, mvmsta->sta_id);
+       dev_cmd = iwl_mvm_set_tx_params(mvm, skb, hdrlen, sta, mvmsta->sta_id);
        if (!dev_cmd)
                goto drop;
 
@@ -431,7 +493,7 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
        }
 
        /* Copy MAC header from skb into command buffer */
-       memcpy(tx_cmd->hdr, hdr, ieee80211_hdrlen(fc));
+       memcpy(tx_cmd->hdr, hdr, hdrlen);
 
        WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM);
 
@@ -507,15 +569,10 @@ 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_mvm_disable_txq(mvm, tid_data->txq_id, CMD_ASYNC);
+               iwl_mvm_disable_txq(mvm, tid_data->txq_id,
+                                   vif->hw_queue[tid_to_mac80211_ac[tid]], tid,
+                                   CMD_ASYNC);
                tid_data->state = IWL_AGG_OFF;
-               /*
-                * we can't hold the mutex - but since we are after a sequence
-                * point (call to iwl_mvm_disable_txq(), so we don't even need
-                * a memory barrier.
-                */
-               mvm->queue_to_mac80211[tid_data->txq_id] =
-                                       IWL_INVALID_MAC80211_QUEUE;
                ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
                break;
 
@@ -884,8 +941,7 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm,
        rcu_read_unlock();
 }
 
-int iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
-                     struct iwl_device_cmd *cmd)
+void iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data;
@@ -894,8 +950,6 @@ int iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
                iwl_mvm_rx_tx_cmd_single(mvm, pkt);
        else
                iwl_mvm_rx_tx_cmd_agg(mvm, pkt);
-
-       return 0;
 }
 
 static void iwl_mvm_tx_info_from_ba_notif(struct ieee80211_tx_info *info,
@@ -915,8 +969,7 @@ static void iwl_mvm_tx_info_from_ba_notif(struct ieee80211_tx_info *info,
                (void *)(uintptr_t)tid_data->rate_n_flags;
 }
 
-int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
-                       struct iwl_device_cmd *cmd)
+void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwl_mvm_ba_notif *ba_notif = (void *)pkt->data;
@@ -938,7 +991,7 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
        if (WARN_ONCE(sta_id >= IWL_MVM_STATION_COUNT ||
                      tid >= IWL_MAX_TID_COUNT,
                      "sta_id %d tid %d", sta_id, tid))
-               return 0;
+               return;
 
        rcu_read_lock();
 
@@ -947,7 +1000,7 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
        /* Reclaiming frames for a station that has been deleted ? */
        if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) {
                rcu_read_unlock();
-               return 0;
+               return;
        }
 
        mvmsta = iwl_mvm_sta_from_mac80211(sta);
@@ -958,7 +1011,7 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
                        "invalid BA notification: Q %d, tid %d, flow %d\n",
                        tid_data->txq_id, tid, scd_flow);
                rcu_read_unlock();
-               return 0;
+               return;
        }
 
        spin_lock_bh(&mvmsta->lock);
@@ -1045,8 +1098,6 @@ out:
                skb = __skb_dequeue(&reclaimed_skbs);
                ieee80211_tx_status(mvm->hw, skb);
        }
-
-       return 0;
 }
 
 /*
@@ -1057,7 +1108,7 @@ out:
  * 2) flush the Tx path
  * 3) wait for the transport queues to be empty
  */
-int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, bool sync)
+int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, u32 flags)
 {
        int ret;
        struct iwl_tx_path_flush_cmd flush_cmd = {
@@ -1065,8 +1116,6 @@ int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, bool sync)
                .flush_ctl = cpu_to_le16(DUMP_TX_FIFO_FLUSH),
        };
 
-       u32 flags = sync ? 0 : CMD_ASYNC;
-
        ret = iwl_mvm_send_cmd_pdu(mvm, TXPATH_FLUSH, flags,
                                   sizeof(flush_cmd), &flush_cmd);
        if (ret)