summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-03-15 13:26:52 -0700
committerJohn W. Linville <linville@tuxdriver.com>2012-04-09 16:37:22 -0400
commit9eae88fa9a02e31af69a215beaa5e1194da3a5a1 (patch)
tree147ed04cc911430969a4d256a0c41ae33f0a1b06 /drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
parente56103823716039418d099221dd2059fa7547fbf (diff)
downloadop-kernel-dev-9eae88fa9a02e31af69a215beaa5e1194da3a5a1.zip
op-kernel-dev-9eae88fa9a02e31af69a215beaa5e1194da3a5a1.tar.gz
iwlwifi: move queue mapping out of transport
The queue mapping is not only dynamic, it is also dependent on the uCode, as we can already see today with the dual-mode and non-dual-mode being different. Move the queue mapping out of the transport layer and let the higher layer manage it. Part of the transport configuration is how to set up the queues. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c201
1 files changed, 28 insertions, 173 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
index a1c4550..105c093 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
@@ -41,43 +41,6 @@
#define IWL_TX_CRC_SIZE 4
#define IWL_TX_DELIMITER_SIZE 4
-/*
- * mac80211 queues, ACs, hardware queues, FIFOs.
- *
- * Cf. http://wireless.kernel.org/en/developers/Documentation/mac80211/queues
- *
- * Mac80211 uses the following numbers, which we get as from it
- * by way of skb_get_queue_mapping(skb):
- *
- * VO 0
- * VI 1
- * BE 2
- * BK 3
- *
- *
- * Regular (not A-MPDU) frames are put into hardware queues corresponding
- * to the FIFOs, see comments in iwl-prph.h. Aggregated frames get their
- * own queue per aggregation session (RA/TID combination), such queues are
- * set up to map into FIFOs too, for which we need an AC->FIFO mapping. In
- * order to map frames to the right queue, we also need an AC->hw queue
- * mapping. This is implemented here.
- *
- * Due to the way hw queues are set up (by the hw specific code), the AC->hw
- * queue mapping is the identity mapping.
- */
-
-static const u8 tid_to_ac[] = {
- IEEE80211_AC_BE,
- IEEE80211_AC_BK,
- IEEE80211_AC_BK,
- IEEE80211_AC_BE,
- IEEE80211_AC_VI,
- IEEE80211_AC_VI,
- IEEE80211_AC_VO,
- IEEE80211_AC_VO
-};
-
-
/**
* iwl_trans_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
*/
@@ -455,13 +418,10 @@ void iwl_trans_set_wr_ptrs(struct iwl_trans *trans,
}
void iwl_trans_tx_queue_set_status(struct iwl_trans *trans,
- struct iwl_tx_queue *txq,
- int tx_fifo_id, int scd_retry)
+ struct iwl_tx_queue *txq,
+ int tx_fifo_id, bool active)
{
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
int txq_id = txq->q.id;
- int active =
- test_bit(txq_id, &trans_pcie->txq_ctx_active_msk) ? 1 : 0;
iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id),
(active << SCD_QUEUE_STTS_REG_POS_ACTIVE) |
@@ -469,77 +429,22 @@ void iwl_trans_tx_queue_set_status(struct iwl_trans *trans,
(1 << SCD_QUEUE_STTS_REG_POS_WSL) |
SCD_QUEUE_STTS_REG_MSK);
- txq->sched_retry = scd_retry;
-
if (active)
- IWL_DEBUG_TX_QUEUES(trans, "Activate %s Queue %d on FIFO %d\n",
- scd_retry ? "BA" : "AC/CMD", txq_id, tx_fifo_id);
+ IWL_DEBUG_TX_QUEUES(trans, "Activate queue %d on FIFO %d\n",
+ txq_id, tx_fifo_id);
else
- IWL_DEBUG_TX_QUEUES(trans, "Deactivate %s Queue %d\n",
- scd_retry ? "BA" : "AC/CMD", txq_id);
+ IWL_DEBUG_TX_QUEUES(trans, "Deactivate queue %d\n", txq_id);
}
-static inline int get_ac_from_tid(u16 tid)
+void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans, int txq_id, int fifo,
+ int sta_id, int tid, int frame_limit, u16 ssn)
{
- if (likely(tid < ARRAY_SIZE(tid_to_ac)))
- return tid_to_ac[tid];
-
- /* no support for TIDs 8-15 yet */
- return -EINVAL;
-}
-
-static inline int get_fifo_from_tid(struct iwl_trans_pcie *trans_pcie,
- u8 ctx, u16 tid)
-{
- const u8 *ac_to_fifo = trans_pcie->ac_to_fifo[ctx];
- if (likely(tid < ARRAY_SIZE(tid_to_ac)))
- return ac_to_fifo[tid_to_ac[tid]];
-
- /* no support for TIDs 8-15 yet */
- return -EINVAL;
-}
-
-static inline bool is_agg_txqid_valid(struct iwl_trans *trans, int txq_id)
-{
- if (txq_id < IWLAGN_FIRST_AMPDU_QUEUE)
- return false;
- return txq_id < (IWLAGN_FIRST_AMPDU_QUEUE +
- hw_params(trans).num_ampdu_queues);
-}
-
-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, u16 ssn)
-{
- int tx_fifo, txq_id;
- u16 ra_tid;
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
unsigned long flags;
+ u16 ra_tid = BUILD_RAxTID(sta_id, tid);
- struct iwl_trans_pcie *trans_pcie =
- IWL_TRANS_GET_PCIE_TRANS(trans);
-
- if (WARN_ON(sta_id == IWL_INVALID_STATION))
- return;
- if (WARN_ON(tid >= IWL_MAX_TID_COUNT))
- return;
-
- tx_fifo = get_fifo_from_tid(trans_pcie, ctx, tid);
- if (WARN_ON(tx_fifo < 0)) {
- IWL_ERR(trans, "txq_agg_setup, bad fifo: %d\n", tx_fifo);
- return;
- }
-
- txq_id = trans_pcie->agg_txq[sta_id][tid];
- if (WARN_ON_ONCE(!is_agg_txqid_valid(trans, 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(trans).num_ampdu_queues - 1);
- return;
- }
-
- ra_tid = BUILD_RAxTID(sta_id, tid);
+ if (test_and_set_bit(txq_id, trans_pcie->queue_used))
+ WARN_ONCE(1, "queue %d already used - expect issues", txq_id);
spin_lock_irqsave(&trans_pcie->irq_lock, flags);
@@ -550,10 +455,10 @@ void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans,
iwlagn_tx_queue_set_q2ratid(trans, ra_tid, txq_id);
/* Set this queue as a chain-building queue */
- iwl_set_bits_prph(trans, SCD_QUEUECHAIN_SEL, (1<<txq_id));
+ iwl_set_bits_prph(trans, SCD_QUEUECHAIN_SEL, BIT(txq_id));
/* enable aggregations for the queue */
- iwl_set_bits_prph(trans, SCD_AGGR_SEL, (1<<txq_id));
+ iwl_set_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id));
/* Place first TFD at index corresponding to start sequence number.
* Assumes that ssn_idx is valid (!= 0xFFF) */
@@ -563,92 +468,42 @@ void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans,
/* Set up Tx window size and frame limit for this queue */
iwl_write_targ_mem(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) |
- ((frame_limit <<
- SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
- SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
+ SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32),
+ ((frame_limit << SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
+ SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
+ ((frame_limit << SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
+ SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
iwl_set_bits_prph(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(trans, &trans_pcie->txq[txq_id],
- tx_fifo, 1);
-
- trans_pcie->txq[txq_id].sta_id = sta_id;
- trans_pcie->txq[txq_id].tid = tid;
+ fifo, true);
spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
}
-/*
- * Find first available (lowest unused) Tx Queue, mark it "active".
- * Called only when finding queue for aggregation.
- * Should never return anything < 7, because they should already
- * be in use as EDCA AC (0-3), Command (4), reserved (5, 6)
- */
-static int iwlagn_txq_ctx_activate_free(struct iwl_trans *trans)
+void iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans, int txq_id)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
- int txq_id;
-
- for (txq_id = 0; txq_id < cfg(trans)->base_params->num_of_queues;
- txq_id++)
- if (!test_and_set_bit(txq_id,
- &trans_pcie->txq_ctx_active_msk))
- return txq_id;
- return -1;
-}
-int iwl_trans_pcie_tx_agg_alloc(struct iwl_trans *trans,
- int sta_id, int tid)
-{
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
- int txq_id;
-
- txq_id = iwlagn_txq_ctx_activate_free(trans);
- if (txq_id == -1) {
- IWL_ERR(trans, "No free aggregation queue available\n");
- return -ENXIO;
- }
-
- trans_pcie->agg_txq[sta_id][tid] = txq_id;
- iwl_set_swq_id(&trans_pcie->txq[txq_id], get_ac_from_tid(tid), txq_id);
-
- return 0;
-}
-
-int iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans, int sta_id, int tid)
-{
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
- u8 txq_id = trans_pcie->agg_txq[sta_id][tid];
-
- if (WARN_ON_ONCE(!is_agg_txqid_valid(trans, 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(trans).num_ampdu_queues - 1);
- return -EINVAL;
+ if (!test_and_clear_bit(txq_id, trans_pcie->queue_used)) {
+ WARN_ONCE(1, "queue %d not used", txq_id);
+ return;
}
iwlagn_tx_queue_stop_scheduler(trans, txq_id);
- iwl_clear_bits_prph(trans, SCD_AGGR_SEL, (1 << txq_id));
+ iwl_clear_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id));
- trans_pcie->agg_txq[sta_id][tid] = 0;
trans_pcie->txq[txq_id].q.read_ptr = 0;
trans_pcie->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(trans, SCD_INTERRUPT_MASK, (1 << txq_id));
- iwl_txq_ctx_deactivate(trans_pcie, txq_id);
- iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[txq_id], 0, 0);
- return 0;
+ iwl_clear_bits_prph(trans, SCD_INTERRUPT_MASK, BIT(txq_id));
+
+ iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[txq_id],
+ 0, false);
}
/*************** HOST COMMAND QUEUE FUNCTIONS *****/
OpenPOWER on IntegriCloud