]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/net/wireless/iwlwifi/mvm/utils.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/ide
[karo-tx-linux.git] / drivers / net / wireless / iwlwifi / mvm / utils.c
index a7d434256423382af219c1ab9221efdfe686ea69..ad0f16909e2e243483334b9d9cb274c72a78be50 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright (C) 2015 Intel Deutschland 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
@@ -657,45 +658,143 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
        if (mvm->support_umac_log)
                iwl_mvm_dump_umac_error_log(mvm);
 }
-void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, u16 ssn,
-                       const struct iwl_trans_txq_scd_cfg *cfg,
+
+int iwl_mvm_find_free_queue(struct iwl_mvm *mvm, u8 minq, u8 maxq)
+{
+       int i;
+
+       lockdep_assert_held(&mvm->queue_info_lock);
+
+       for (i = minq; i <= maxq; i++)
+               if (mvm->queue_info[i].hw_queue_refcount == 0 &&
+                   !mvm->queue_info[i].setup_reserved)
+                       return i;
+
+       return -ENOSPC;
+}
+
+void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
+                       u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg,
                        unsigned int wdg_timeout)
 {
-       struct iwl_scd_txq_cfg_cmd cmd = {
-               .scd_queue = queue,
-               .enable = 1,
-               .window = cfg->frame_limit,
-               .sta_id = cfg->sta_id,
-               .ssn = cpu_to_le16(ssn),
-               .tx_fifo = cfg->fifo,
-               .aggregate = cfg->aggregate,
-               .tid = cfg->tid,
-       };
+       bool enable_queue = true;
 
-       if (!iwl_mvm_is_scd_cfg_supported(mvm)) {
-               iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, cfg,
-                                        wdg_timeout);
+       spin_lock_bh(&mvm->queue_info_lock);
+
+       /* Make sure this TID isn't already enabled */
+       if (mvm->queue_info[queue].tid_bitmap & BIT(cfg->tid)) {
+               spin_unlock_bh(&mvm->queue_info_lock);
+               IWL_ERR(mvm, "Trying to enable TXQ with existing TID %d\n",
+                       cfg->tid);
                return;
        }
 
-       iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, NULL, wdg_timeout);
-       WARN(iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, sizeof(cmd), &cmd),
-            "Failed to configure queue %d on FIFO %d\n", queue, cfg->fifo);
+       /* Update mappings and refcounts */
+       mvm->queue_info[queue].hw_queue_to_mac80211 |= BIT(mac80211_queue);
+       mvm->queue_info[queue].hw_queue_refcount++;
+       if (mvm->queue_info[queue].hw_queue_refcount > 1)
+               enable_queue = false;
+       mvm->queue_info[queue].tid_bitmap |= BIT(cfg->tid);
+
+       IWL_DEBUG_TX_QUEUES(mvm,
+                           "Enabling TXQ #%d refcount=%d (mac80211 map:0x%x)\n",
+                           queue, mvm->queue_info[queue].hw_queue_refcount,
+                           mvm->queue_info[queue].hw_queue_to_mac80211);
+
+       spin_unlock_bh(&mvm->queue_info_lock);
+
+       /* Send the enabling command if we need to */
+       if (enable_queue) {
+               struct iwl_scd_txq_cfg_cmd cmd = {
+                       .scd_queue = queue,
+                       .enable = 1,
+                       .window = cfg->frame_limit,
+                       .sta_id = cfg->sta_id,
+                       .ssn = cpu_to_le16(ssn),
+                       .tx_fifo = cfg->fifo,
+                       .aggregate = cfg->aggregate,
+                       .tid = cfg->tid,
+               };
+
+               iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, NULL,
+                                        wdg_timeout);
+               WARN(iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, sizeof(cmd),
+                                         &cmd),
+                    "Failed to configure queue %d on FIFO %d\n", queue,
+                    cfg->fifo);
+       }
 }
 
-void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, u8 flags)
+void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
+                        u8 tid, u8 flags)
 {
        struct iwl_scd_txq_cfg_cmd cmd = {
                .scd_queue = queue,
                .enable = 0,
        };
+       bool remove_mac_queue = true;
        int ret;
 
-       if (!iwl_mvm_is_scd_cfg_supported(mvm)) {
-               iwl_trans_txq_disable(mvm->trans, queue, true);
+       spin_lock_bh(&mvm->queue_info_lock);
+
+       if (WARN_ON(mvm->queue_info[queue].hw_queue_refcount == 0)) {
+               spin_unlock_bh(&mvm->queue_info_lock);
+               return;
+       }
+
+       mvm->queue_info[queue].tid_bitmap &= ~BIT(tid);
+
+       /*
+        * If there is another TID with the same AC - don't remove the MAC queue
+        * from the mapping
+        */
+       if (tid < IWL_MAX_TID_COUNT) {
+               unsigned long tid_bitmap =
+                       mvm->queue_info[queue].tid_bitmap;
+               int ac = tid_to_mac80211_ac[tid];
+               int i;
+
+               for_each_set_bit(i, &tid_bitmap, IWL_MAX_TID_COUNT) {
+                       if (tid_to_mac80211_ac[i] == ac)
+                               remove_mac_queue = false;
+               }
+       }
+
+       if (remove_mac_queue)
+               mvm->queue_info[queue].hw_queue_to_mac80211 &=
+                       ~BIT(mac80211_queue);
+       mvm->queue_info[queue].hw_queue_refcount--;
+
+       cmd.enable = mvm->queue_info[queue].hw_queue_refcount ? 1 : 0;
+
+       IWL_DEBUG_TX_QUEUES(mvm,
+                           "Disabling TXQ #%d refcount=%d (mac80211 map:0x%x)\n",
+                           queue,
+                           mvm->queue_info[queue].hw_queue_refcount,
+                           mvm->queue_info[queue].hw_queue_to_mac80211);
+
+       /* If the queue is still enabled - nothing left to do in this func */
+       if (cmd.enable) {
+               spin_unlock_bh(&mvm->queue_info_lock);
                return;
        }
 
+       /* Make sure queue info is correct even though we overwrite it */
+       WARN(mvm->queue_info[queue].hw_queue_refcount ||
+            mvm->queue_info[queue].tid_bitmap ||
+            mvm->queue_info[queue].hw_queue_to_mac80211,
+            "TXQ #%d info out-of-sync - refcount=%d, mac map=0x%x, tid=0x%x\n",
+            queue, mvm->queue_info[queue].hw_queue_refcount,
+            mvm->queue_info[queue].hw_queue_to_mac80211,
+            mvm->queue_info[queue].tid_bitmap);
+
+       /* If we are here - the queue is freed and we can zero out these vals */
+       mvm->queue_info[queue].hw_queue_refcount = 0;
+       mvm->queue_info[queue].tid_bitmap = 0;
+       mvm->queue_info[queue].hw_queue_to_mac80211 = 0;
+
+       spin_unlock_bh(&mvm->queue_info_lock);
+
        iwl_trans_txq_disable(mvm->trans, queue, false);
        ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, flags,
                                   sizeof(cmd), &cmd);