iwlagn: cosmetics in iwl-trans.h
[pandora-kernel.git] / drivers / net / wireless / iwlwifi / iwl-trans-tx-pcie.c
index 9392226..28c606c 100644 (file)
@@ -403,14 +403,15 @@ void iwl_trans_set_wr_ptrs(struct iwl_trans *trans,
        iwl_write_prph(bus(trans), SCD_QUEUE_RDPTR(txq_id), index);
 }
 
-void iwl_trans_tx_queue_set_status(struct iwl_priv *priv,
+void iwl_trans_tx_queue_set_status(struct iwl_trans *trans,
                                        struct iwl_tx_queue *txq,
                                        int tx_fifo_id, int scd_retry)
 {
        int txq_id = txq->q.id;
-       int active = test_bit(txq_id, &priv->txq_ctx_active_msk) ? 1 : 0;
+       int active =
+               test_bit(txq_id, &priv(trans)->txq_ctx_active_msk) ? 1 : 0;
 
-       iwl_write_prph(bus(priv), SCD_QUEUE_STATUS_BITS(txq_id),
+       iwl_write_prph(bus(trans), SCD_QUEUE_STATUS_BITS(txq_id),
                        (active << SCD_QUEUE_STTS_REG_POS_ACTIVE) |
                        (tx_fifo_id << SCD_QUEUE_STTS_REG_POS_TXF) |
                        (1 << SCD_QUEUE_STTS_REG_POS_WSL) |
@@ -418,7 +419,7 @@ void iwl_trans_tx_queue_set_status(struct iwl_priv *priv,
 
        txq->sched_retry = scd_retry;
 
-       IWL_DEBUG_INFO(priv, "%s %s Queue %d on FIFO %d\n",
+       IWL_DEBUG_INFO(trans, "%s %s Queue %d on FIFO %d\n",
                       active ? "Activate" : "Deactivate",
                       scd_retry ? "BA" : "AC/CMD", txq_id, tx_fifo_id);
 }
@@ -434,16 +435,15 @@ static inline int get_fifo_from_tid(struct iwl_trans_pcie *trans_pcie,
        return -EINVAL;
 }
 
-void iwl_trans_pcie_txq_agg_setup(struct iwl_priv *priv,
-                                 enum iwl_rxon_context_id ctx, int sta_id,
-                                 int tid, int frame_limit)
+void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans,
+                                enum iwl_rxon_context_id ctx, int sta_id,
+                                int tid, int frame_limit)
 {
        int tx_fifo, txq_id, ssn_idx;
        u16 ra_tid;
        unsigned long flags;
        struct iwl_tid_data *tid_data;
 
-       struct iwl_trans *trans = trans(priv);
        struct iwl_trans_pcie *trans_pcie =
                IWL_TRANS_GET_PCIE_TRANS(trans);
 
@@ -458,15 +458,15 @@ void iwl_trans_pcie_txq_agg_setup(struct iwl_priv *priv,
                return;
        }
 
-       spin_lock_irqsave(&priv->shrd->sta_lock, flags);
-       tid_data = &priv->shrd->tid_data[sta_id][tid];
+       spin_lock_irqsave(&trans->shrd->sta_lock, flags);
+       tid_data = &trans->shrd->tid_data[sta_id][tid];
        ssn_idx = SEQ_TO_SN(tid_data->seq_number);
        txq_id = tid_data->agg.txq_id;
-       spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+       spin_unlock_irqrestore(&trans->shrd->sta_lock, flags);
 
        ra_tid = BUILD_RAxTID(sta_id, tid);
 
-       spin_lock_irqsave(&priv->shrd->lock, flags);
+       spin_lock_irqsave(&trans->shrd->lock, flags);
 
        /* Stop this Tx queue before configuring it */
        iwlagn_tx_queue_stop_scheduler(trans, txq_id);
@@ -475,19 +475,19 @@ void iwl_trans_pcie_txq_agg_setup(struct iwl_priv *priv,
        iwlagn_tx_queue_set_q2ratid(trans, ra_tid, txq_id);
 
        /* Set this queue as a chain-building queue */
-       iwl_set_bits_prph(bus(priv), SCD_QUEUECHAIN_SEL, (1<<txq_id));
+       iwl_set_bits_prph(bus(trans), SCD_QUEUECHAIN_SEL, (1<<txq_id));
 
        /* enable aggregations for the queue */
-       iwl_set_bits_prph(bus(priv), SCD_AGGR_SEL, (1<<txq_id));
+       iwl_set_bits_prph(bus(trans), SCD_AGGR_SEL, (1<<txq_id));
 
        /* Place first TFD at index corresponding to start sequence number.
         * Assumes that ssn_idx is valid (!= 0xFFF) */
-       priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff);
-       priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff);
+       priv(trans)->txq[txq_id].q.read_ptr = (ssn_idx & 0xff);
+       priv(trans)->txq[txq_id].q.write_ptr = (ssn_idx & 0xff);
        iwl_trans_set_wr_ptrs(trans, txq_id, ssn_idx);
 
        /* Set up Tx window size and frame limit for this queue */
-       iwl_write_targ_mem(bus(priv), trans_pcie->scd_base_addr +
+       iwl_write_targ_mem(bus(trans), trans_pcie->scd_base_addr +
                        SCD_CONTEXT_QUEUE_OFFSET(txq_id) +
                        sizeof(u32),
                        ((frame_limit <<
@@ -497,15 +497,16 @@ void iwl_trans_pcie_txq_agg_setup(struct iwl_priv *priv,
                        SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
                        SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
 
-       iwl_set_bits_prph(bus(priv), SCD_INTERRUPT_MASK, (1 << txq_id));
+       iwl_set_bits_prph(bus(trans), SCD_INTERRUPT_MASK, (1 << txq_id));
 
        /* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */
-       iwl_trans_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1);
+       iwl_trans_tx_queue_set_status(trans, &priv(trans)->txq[txq_id],
+                                       tx_fifo, 1);
 
-       priv->txq[txq_id].sta_id = sta_id;
-       priv->txq[txq_id].tid = tid;
+       priv(trans)->txq[txq_id].sta_id = sta_id;
+       priv(trans)->txq[txq_id].tid = tid;
 
-       spin_unlock_irqrestore(&priv->shrd->lock, flags);
+       spin_unlock_irqrestore(&trans->shrd->lock, flags);
 }
 
 /*
@@ -560,32 +561,91 @@ int iwl_trans_pcie_tx_agg_alloc(struct iwl_trans *trans,
 
        return 0;
 }
-int iwl_trans_pcie_txq_agg_disable(struct iwl_priv *priv, u16 txq_id)
+
+void iwl_trans_pcie_txq_agg_disable(struct iwl_trans *trans, int txq_id)
 {
-       struct iwl_trans *trans = trans(priv);
+       iwlagn_tx_queue_stop_scheduler(trans, txq_id);
+
+       iwl_clear_bits_prph(bus(trans), SCD_AGGR_SEL, (1 << txq_id));
+
+       priv(trans)->txq[txq_id].q.read_ptr = 0;
+       priv(trans)->txq[txq_id].q.write_ptr = 0;
+       /* supposes that ssn_idx is valid (!= 0xFFF) */
+       iwl_trans_set_wr_ptrs(trans, txq_id, 0);
+
+       iwl_clear_bits_prph(bus(trans), SCD_INTERRUPT_MASK, (1 << txq_id));
+       iwl_txq_ctx_deactivate(priv(trans), txq_id);
+       iwl_trans_tx_queue_set_status(trans, &priv(trans)->txq[txq_id], 0, 0);
+}
+
+int iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans,
+                                 enum iwl_rxon_context_id ctx, int sta_id,
+                                 int tid)
+{
+       unsigned long flags;
+       int read_ptr, write_ptr;
+       struct iwl_tid_data *tid_data;
+       int txq_id;
+
+       spin_lock_irqsave(&trans->shrd->sta_lock, flags);
+
+       tid_data = &trans->shrd->tid_data[sta_id][tid];
+       txq_id = tid_data->agg.txq_id;
+
        if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) ||
            (IWLAGN_FIRST_AMPDU_QUEUE +
-               hw_params(priv).num_ampdu_queues <= txq_id)) {
-               IWL_ERR(priv,
+               hw_params(trans).num_ampdu_queues <= txq_id)) {
+               IWL_ERR(trans,
                        "queue number out of range: %d, must be %d to %d\n",
                        txq_id, IWLAGN_FIRST_AMPDU_QUEUE,
                        IWLAGN_FIRST_AMPDU_QUEUE +
-                       hw_params(priv).num_ampdu_queues - 1);
+                       hw_params(trans).num_ampdu_queues - 1);
+               spin_unlock_irqrestore(&trans->shrd->sta_lock, flags);
                return -EINVAL;
        }
 
-       iwlagn_tx_queue_stop_scheduler(trans, txq_id);
+       switch (trans->shrd->tid_data[sta_id][tid].agg.state) {
+       case IWL_EMPTYING_HW_QUEUE_ADDBA:
+               /*
+               * This can happen if the peer stops aggregation
+               * again before we've had a chance to drain the
+               * queue we selected previously, i.e. before the
+               * session was really started completely.
+               */
+               IWL_DEBUG_HT(trans, "AGG stop before setup done\n");
+               goto turn_off;
+       case IWL_AGG_ON:
+               break;
+       default:
+               IWL_WARN(trans, "Stopping AGG while state not ON"
+                               "or starting\n");
+       }
 
-       iwl_clear_bits_prph(bus(priv), SCD_AGGR_SEL, (1 << txq_id));
+       write_ptr = priv(trans)->txq[txq_id].q.write_ptr;
+       read_ptr = priv(trans)->txq[txq_id].q.read_ptr;
 
-       priv->txq[txq_id].q.read_ptr = 0;
-       priv->txq[txq_id].q.write_ptr = 0;
-       /* supposes that ssn_idx is valid (!= 0xFFF) */
-       iwl_trans_set_wr_ptrs(trans, txq_id, 0);
+       /* The queue is not empty */
+       if (write_ptr != read_ptr) {
+               IWL_DEBUG_HT(trans, "Stopping a non empty AGG HW QUEUE\n");
+               trans->shrd->tid_data[sta_id][tid].agg.state =
+                       IWL_EMPTYING_HW_QUEUE_DELBA;
+               spin_unlock_irqrestore(&trans->shrd->sta_lock, flags);
+               return 0;
+       }
+
+       IWL_DEBUG_HT(trans, "HW queue is empty\n");
+turn_off:
+       trans->shrd->tid_data[sta_id][tid].agg.state = IWL_AGG_OFF;
 
-       iwl_clear_bits_prph(bus(priv), SCD_INTERRUPT_MASK, (1 << txq_id));
-       iwl_txq_ctx_deactivate(priv, txq_id);
-       iwl_trans_tx_queue_set_status(priv, &priv->txq[txq_id], 0, 0);
+       /* do not restore/save irqs */
+       spin_unlock(&trans->shrd->sta_lock);
+       spin_lock(&trans->shrd->lock);
+
+       iwl_trans_pcie_txq_agg_disable(trans, txq_id);
+
+       spin_unlock_irqrestore(&trans->shrd->lock, flags);
+
+       iwl_stop_tx_ba_trans_ready(priv(trans), ctx, sta_id, tid);
 
        return 0;
 }
@@ -1118,12 +1178,13 @@ int iwl_trans_pcie_send_cmd_pdu(struct iwl_trans *trans, u8 id, u32 flags,
 }
 
 /* Frees buffers until index _not_ inclusive */
-void iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index,
-                           struct sk_buff_head *skbs)
+int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index,
+                        struct sk_buff_head *skbs)
 {
        struct iwl_tx_queue *txq = &priv(trans)->txq[txq_id];
        struct iwl_queue *q = &txq->q;
        int last_to_free;
+       int freed = 0;
 
        /*Since we free until index _not_ inclusive, the one before index is
         * the last we will free. This one must be used */
@@ -1135,14 +1196,14 @@ void iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index,
                          "last_to_free %d is out of range [0-%d] %d %d.\n",
                          __func__, txq_id, last_to_free, q->n_bd,
                          q->write_ptr, q->read_ptr);
-               return;
+               return 0;
        }
 
        IWL_DEBUG_TX_REPLY(trans, "reclaim: [%d, %d, %d]\n", txq_id,
                           q->read_ptr, index);
 
        if (WARN_ON(!skb_queue_empty(skbs)))
-               return;
+               return 0;
 
        for (;
             q->read_ptr != index;
@@ -1158,5 +1219,7 @@ void iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index,
                iwlagn_txq_inval_byte_cnt_tbl(trans, txq);
 
                iwlagn_txq_free_tfd(trans, txq, txq->q.read_ptr);
+               freed++;
        }
+       return freed;
 }