iwlwifi: add Intel Mobile Communications copyright
[deliverable/linux.git] / drivers / net / wireless / iwlwifi / pcie / tx.c
index 6acccb19c4f3030956e0d701a037c1227d7121b1..a6336b4aa3a42f54ecc577b4c140e4adcad9290b 100644 (file)
@@ -1,6 +1,7 @@
 /******************************************************************************
  *
  * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
@@ -34,6 +35,7 @@
 #include "iwl-csr.h"
 #include "iwl-prph.h"
 #include "iwl-io.h"
+#include "iwl-scd.h"
 #include "iwl-op-mode.h"
 #include "internal.h"
 /* FIXME: need to abstract out TX command (once we know what it looks like) */
@@ -644,17 +646,6 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id)
        memset(txq, 0, sizeof(*txq));
 }
 
-/*
- * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask
- */
-static void iwl_pcie_txq_set_sched(struct iwl_trans *trans, u32 mask)
-{
-       struct iwl_trans_pcie __maybe_unused *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       iwl_write_prph(trans, SCD_TXFACT, mask);
-}
-
 void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
@@ -692,7 +683,7 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr)
                                trans_pcie->cmd_fifo);
 
        /* Activate all Tx DMA/FIFO channels */
-       iwl_pcie_txq_set_sched(trans, IWL_MASK(0, 7));
+       iwl_scd_activate_fifos(trans);
 
        /* Enable DMA channel */
        for (chan = 0; chan < FH_TCSR_CHNL_NUM; chan++)
@@ -745,7 +736,7 @@ int iwl_pcie_tx_stop(struct iwl_trans *trans)
        /* Turn off all Tx DMA fifos */
        spin_lock(&trans_pcie->irq_lock);
 
-       iwl_pcie_txq_set_sched(trans, 0);
+       iwl_scd_deactivate_fifos(trans);
 
        /* Stop each Tx DMA channel, and wait for it to be idle */
        for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) {
@@ -886,7 +877,7 @@ int iwl_pcie_tx_init(struct iwl_trans *trans)
        spin_lock(&trans_pcie->irq_lock);
 
        /* Turn off all Tx DMA fifos */
-       iwl_write_prph(trans, SCD_TXFACT, 0);
+       iwl_scd_deactivate_fifos(trans);
 
        /* Tell NIC where to find the "keep warm" buffer */
        iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG,
@@ -1072,55 +1063,52 @@ static int iwl_pcie_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid,
        return 0;
 }
 
-static inline void iwl_pcie_txq_set_inactive(struct iwl_trans *trans,
-                                            u16 txq_id)
-{
-       /* Simply stop the queue, but don't change any configuration;
-        * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */
-       iwl_write_prph(trans,
-               SCD_QUEUE_STATUS_BITS(txq_id),
-               (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)|
-               (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
-}
-
 /* Receiver address (actually, Rx station's index into station table),
  * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */
 #define BUILD_RAxTID(sta_id, tid)      (((sta_id) << 4) + (tid))
 
-void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo,
-                              int sta_id, int tid, int frame_limit, u16 ssn)
+void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn,
+                              const struct iwl_trans_txq_scd_cfg *cfg)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       int fifo = -1;
 
        if (test_and_set_bit(txq_id, trans_pcie->queue_used))
                WARN_ONCE(1, "queue %d already used - expect issues", txq_id);
 
-       /* Stop this Tx queue before configuring it */
-       iwl_pcie_txq_set_inactive(trans, txq_id);
+       if (cfg) {
+               fifo = cfg->fifo;
 
-       /* Set this queue as a chain-building queue unless it is CMD queue */
-       if (txq_id != trans_pcie->cmd_queue)
-               iwl_set_bits_prph(trans, SCD_QUEUECHAIN_SEL, BIT(txq_id));
+               /* Disable the scheduler prior configuring the cmd queue */
+               if (txq_id == trans_pcie->cmd_queue)
+                       iwl_scd_enable_set_active(trans, 0);
 
-       /* If this queue is mapped to a certain station: it is an AGG queue */
-       if (sta_id >= 0) {
-               u16 ra_tid = BUILD_RAxTID(sta_id, tid);
+               /* Stop this Tx queue before configuring it */
+               iwl_scd_txq_set_inactive(trans, txq_id);
 
-               /* Map receiver-address / traffic-ID to this queue */
-               iwl_pcie_txq_set_ratid_map(trans, ra_tid, txq_id);
+               /* Set this queue as a chain-building queue unless it is CMD */
+               if (txq_id != trans_pcie->cmd_queue)
+                       iwl_scd_txq_set_chain(trans, txq_id);
 
-               /* enable aggregations for the queue */
-               iwl_set_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id));
-               trans_pcie->txq[txq_id].ampdu = true;
-       } else {
-               /*
-                * disable aggregations for the queue, this will also make the
-                * ra_tid mapping configuration irrelevant since it is now a
-                * non-AGG queue.
-                */
-               iwl_clear_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id));
+               if (cfg->aggregate) {
+                       u16 ra_tid = BUILD_RAxTID(cfg->sta_id, cfg->tid);
+
+                       /* Map receiver-address / traffic-ID to this queue */
+                       iwl_pcie_txq_set_ratid_map(trans, ra_tid, txq_id);
+
+                       /* enable aggregations for the queue */
+                       iwl_scd_txq_enable_agg(trans, txq_id);
+                       trans_pcie->txq[txq_id].ampdu = true;
+               } else {
+                       /*
+                        * disable aggregations for the queue, this will also
+                        * make the ra_tid mapping configuration irrelevant
+                        * since it is now a non-AGG queue.
+                        */
+                       iwl_scd_txq_disable_agg(trans, txq_id);
 
-               ssn = trans_pcie->txq[txq_id].q.read_ptr;
+                       ssn = trans_pcie->txq[txq_id].q.read_ptr;
+               }
        }
 
        /* Place first TFD at index corresponding to start sequence number.
@@ -1128,32 +1116,43 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo,
        trans_pcie->txq[txq_id].q.read_ptr = (ssn & 0xff);
        trans_pcie->txq[txq_id].q.write_ptr = (ssn & 0xff);
 
-       iwl_write_direct32(trans, HBUS_TARG_WRPTR,
-                          (ssn & 0xff) | (txq_id << 8));
-       iwl_write_prph(trans, SCD_QUEUE_RDPTR(txq_id), ssn);
+       if (cfg) {
+               u8 frame_limit = cfg->frame_limit;
+
+               iwl_write_direct32(trans, HBUS_TARG_WRPTR,
+                                  (ssn & 0xff) | (txq_id << 8));
+               iwl_write_prph(trans, SCD_QUEUE_RDPTR(txq_id), ssn);
 
-       /* Set up Tx window size and frame limit for this queue */
-       iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr +
-                       SCD_CONTEXT_QUEUE_OFFSET(txq_id), 0);
-       iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr +
+               /* Set up Tx window size and frame limit for this queue */
+               iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr +
+                               SCD_CONTEXT_QUEUE_OFFSET(txq_id), 0);
+               iwl_trans_write_mem32(trans,
+                       trans_pcie->scd_base_addr +
                        SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32),
                        ((frame_limit << SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
-                               SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
+                                       SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
                        ((frame_limit << SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
-                               SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
-
-       /* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */
-       iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id),
-                      (1 << SCD_QUEUE_STTS_REG_POS_ACTIVE) |
-                      (fifo << SCD_QUEUE_STTS_REG_POS_TXF) |
-                      (1 << SCD_QUEUE_STTS_REG_POS_WSL) |
-                      SCD_QUEUE_STTS_REG_MSK);
+                                       SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
+
+               /* Set up status area in SRAM, map to Tx DMA/FIFO, activate */
+               iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id),
+                              (1 << SCD_QUEUE_STTS_REG_POS_ACTIVE) |
+                              (cfg->fifo << SCD_QUEUE_STTS_REG_POS_TXF) |
+                              (1 << SCD_QUEUE_STTS_REG_POS_WSL) |
+                              SCD_QUEUE_STTS_REG_MSK);
+
+               /* enable the scheduler for this queue (only) */
+               if (txq_id == trans_pcie->cmd_queue)
+                       iwl_scd_enable_set_active(trans, BIT(txq_id));
+       }
+
        trans_pcie->txq[txq_id].active = true;
        IWL_DEBUG_TX_QUEUES(trans, "Activate queue %d on FIFO %d WrPtr: %d\n",
                            txq_id, fifo, ssn & 0xff);
 }
 
-void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id)
+void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id,
+                               bool configure_scd)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        u32 stts_addr = trans_pcie->scd_base_addr +
@@ -1172,10 +1171,12 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id)
                return;
        }
 
-       iwl_pcie_txq_set_inactive(trans, txq_id);
+       if (configure_scd) {
+               iwl_scd_txq_set_inactive(trans, txq_id);
 
-       iwl_trans_write_mem(trans, stts_addr, (void *)zero_val,
-                           ARRAY_SIZE(zero_val));
+               iwl_trans_write_mem(trans, stts_addr, (void *)zero_val,
+                                   ARRAY_SIZE(zero_val));
+       }
 
        iwl_pcie_txq_unmap(trans, txq_id);
        trans_pcie->txq[txq_id].ampdu = false;
This page took 0.046638 seconds and 5 git commands to generate.