summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-trans-pcie.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans-pcie.c218
1 files changed, 34 insertions, 184 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
index 98cd71fb385..0a233725353 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
@@ -369,21 +369,13 @@ error:
}
static int iwl_trans_txq_init(struct iwl_trans *trans, struct iwl_tx_queue *txq,
- int slots_num, u32 txq_id)
+ int slots_num, u32 txq_id)
{
int ret;
txq->need_update = 0;
memset(txq->meta, 0, sizeof(txq->meta[0]) * slots_num);
- /*
- * For the default queues 0-3, set up the swq_id
- * already -- all others need to get one later
- * (if they need one at all).
- */
- if (txq_id < 4)
- iwl_set_swq_id(txq, txq_id, txq_id);
-
/* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
* iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
@@ -894,59 +886,6 @@ static int iwl_prepare_card_hw(struct iwl_trans *trans)
return ret;
}
-#define IWL_AC_UNSET -1
-
-struct queue_to_fifo_ac {
- s8 fifo, ac;
-};
-
-static const struct queue_to_fifo_ac iwlagn_default_queue_to_tx_fifo[] = {
- { IWL_TX_FIFO_VO, IEEE80211_AC_VO, },
- { IWL_TX_FIFO_VI, IEEE80211_AC_VI, },
- { IWL_TX_FIFO_BE, IEEE80211_AC_BE, },
- { IWL_TX_FIFO_BK, IEEE80211_AC_BK, },
- { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, },
- { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
- { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
- { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
- { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
- { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
- { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
-};
-
-static const struct queue_to_fifo_ac iwlagn_ipan_queue_to_tx_fifo[] = {
- { IWL_TX_FIFO_VO, IEEE80211_AC_VO, },
- { IWL_TX_FIFO_VI, IEEE80211_AC_VI, },
- { IWL_TX_FIFO_BE, IEEE80211_AC_BE, },
- { IWL_TX_FIFO_BK, IEEE80211_AC_BK, },
- { IWL_TX_FIFO_BK_IPAN, IEEE80211_AC_BK, },
- { IWL_TX_FIFO_BE_IPAN, IEEE80211_AC_BE, },
- { IWL_TX_FIFO_VI_IPAN, IEEE80211_AC_VI, },
- { IWL_TX_FIFO_VO_IPAN, IEEE80211_AC_VO, },
- { IWL_TX_FIFO_BE_IPAN, 2, },
- { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, },
- { IWL_TX_FIFO_AUX, IWL_AC_UNSET, },
-};
-
-static const u8 iwlagn_bss_ac_to_fifo[] = {
- IWL_TX_FIFO_VO,
- IWL_TX_FIFO_VI,
- IWL_TX_FIFO_BE,
- IWL_TX_FIFO_BK,
-};
-static const u8 iwlagn_bss_ac_to_queue[] = {
- 0, 1, 2, 3,
-};
-static const u8 iwlagn_pan_ac_to_fifo[] = {
- IWL_TX_FIFO_VO_IPAN,
- IWL_TX_FIFO_VI_IPAN,
- IWL_TX_FIFO_BE_IPAN,
- IWL_TX_FIFO_BK_IPAN,
-};
-static const u8 iwlagn_pan_ac_to_queue[] = {
- 7, 6, 5, 4,
-};
-
/*
* ucode
*/
@@ -1027,19 +966,8 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
const struct fw_img *fw)
{
int ret;
- struct iwl_trans_pcie *trans_pcie =
- IWL_TRANS_GET_PCIE_TRANS(trans);
bool hw_rfkill;
- trans_pcie->ac_to_queue[IWL_RXON_CTX_BSS] = iwlagn_bss_ac_to_queue;
- trans_pcie->ac_to_queue[IWL_RXON_CTX_PAN] = iwlagn_pan_ac_to_queue;
-
- trans_pcie->ac_to_fifo[IWL_RXON_CTX_BSS] = iwlagn_bss_ac_to_fifo;
- trans_pcie->ac_to_fifo[IWL_RXON_CTX_PAN] = iwlagn_pan_ac_to_fifo;
-
- trans_pcie->mcast_queue[IWL_RXON_CTX_BSS] = 0;
- trans_pcie->mcast_queue[IWL_RXON_CTX_PAN] = IWL_IPAN_MCAST_QUEUE;
-
/* This may fail if AMT took ownership of the device */
if (iwl_prepare_card_hw(trans)) {
IWL_WARN(trans, "Exit HW not ready\n");
@@ -1097,9 +1025,7 @@ static void iwl_trans_txq_set_sched(struct iwl_trans *trans, u32 mask)
static void iwl_tx_start(struct iwl_trans *trans)
{
- const struct queue_to_fifo_ac *queue_to_fifo;
- struct iwl_trans_pcie *trans_pcie =
- IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
u32 a;
unsigned long flags;
int i, chan;
@@ -1165,41 +1091,19 @@ static void iwl_tx_start(struct iwl_trans *trans)
/* Activate all Tx DMA/FIFO channels */
iwl_trans_txq_set_sched(trans, IWL_MASK(0, 7));
- /* map queues to FIFOs */
- if (trans->shrd->valid_contexts != BIT(IWL_RXON_CTX_BSS))
- queue_to_fifo = iwlagn_ipan_queue_to_tx_fifo;
- else
- queue_to_fifo = iwlagn_default_queue_to_tx_fifo;
-
iwl_trans_set_wr_ptrs(trans, trans_pcie->cmd_queue, 0);
- /* make sure all queue are not stopped */
- memset(&trans_pcie->queue_stopped[0], 0,
- sizeof(trans_pcie->queue_stopped));
- for (i = 0; i < 4; i++)
- atomic_set(&trans_pcie->queue_stop_count[i], 0);
-
- /* reset to 0 to enable all the queue first */
- trans_pcie->txq_ctx_active_msk = 0;
+ /* make sure all queue are not stopped/used */
+ memset(trans_pcie->queue_stopped, 0, sizeof(trans_pcie->queue_stopped));
+ memset(trans_pcie->queue_used, 0, sizeof(trans_pcie->queue_used));
- BUILD_BUG_ON(ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo) <
- IWLAGN_FIRST_AMPDU_QUEUE);
- BUILD_BUG_ON(ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo) <
- IWLAGN_FIRST_AMPDU_QUEUE);
+ for (i = 0; i < trans_pcie->n_q_to_fifo; i++) {
+ int fifo = trans_pcie->setup_q_to_fifo[i];
- for (i = 0; i < IWLAGN_FIRST_AMPDU_QUEUE; i++) {
- int fifo = queue_to_fifo[i].fifo;
- int ac = queue_to_fifo[i].ac;
+ set_bit(i, trans_pcie->queue_used);
- iwl_txq_ctx_activate(trans_pcie, i);
-
- if (fifo == IWL_TX_FIFO_UNUSED)
- continue;
-
- if (ac != IWL_AC_UNSET)
- iwl_set_swq_id(&trans_pcie->txq[i], ac, i);
iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[i],
- fifo, 0);
+ fifo, true);
}
spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
@@ -1324,70 +1228,32 @@ static void iwl_trans_pcie_wowlan_suspend(struct iwl_trans *trans)
}
static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
- struct iwl_device_cmd *dev_cmd, enum iwl_rxon_context_id ctx,
- u8 sta_id, u8 tid)
+ struct iwl_device_cmd *dev_cmd, int txq_id)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct iwl_tx_cmd *tx_cmd = (struct iwl_tx_cmd *) dev_cmd->payload;
struct iwl_cmd_meta *out_meta;
struct iwl_tx_queue *txq;
struct iwl_queue *q;
-
dma_addr_t phys_addr = 0;
dma_addr_t txcmd_phys;
dma_addr_t scratch_phys;
u16 len, firstlen, secondlen;
u8 wait_write_ptr = 0;
- u8 txq_id;
- bool is_agg = false;
__le16 fc = hdr->frame_control;
u8 hdr_len = ieee80211_hdrlen(fc);
u16 __maybe_unused wifi_seq;
- /*
- * Send this frame after DTIM -- there's a special queue
- * reserved for this for contexts that support AP mode.
- */
- if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
- txq_id = trans_pcie->mcast_queue[ctx];
-
- /*
- * The microcode will clear the more data
- * bit in the last frame it transmits.
- */
- hdr->frame_control |=
- cpu_to_le16(IEEE80211_FCTL_MOREDATA);
- } else if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
- txq_id = IWL_AUX_QUEUE;
- else
- txq_id =
- trans_pcie->ac_to_queue[ctx][skb_get_queue_mapping(skb)];
-
- /* aggregation is on for this <sta,tid> */
- if (info->flags & IEEE80211_TX_CTL_AMPDU) {
- WARN_ON(tid >= IWL_MAX_TID_COUNT);
- txq_id = trans_pcie->agg_txq[sta_id][tid];
- is_agg = true;
- }
-
txq = &trans_pcie->txq[txq_id];
q = &txq->q;
- spin_lock(&txq->lock);
+ if (unlikely(!test_bit(txq_id, trans_pcie->queue_used))) {
+ WARN_ON_ONCE(1);
+ return -EINVAL;
+ }
- /* In AGG mode, the index in the ring must correspond to the WiFi
- * sequence number. This is a HW requirements to help the SCD to parse
- * the BA.
- * Check here that the packets are in the right place on the ring.
- */
-#ifdef CONFIG_IWLWIFI_DEBUG
- wifi_seq = SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl));
- WARN_ONCE(is_agg && ((wifi_seq & 0xff) != q->write_ptr),
- "Q: %d WiFi Seq %d tfdNum %d",
- txq_id, wifi_seq, q->write_ptr);
-#endif
+ spin_lock(&txq->lock);
/* Set up driver data for this TFD */
txq->skbs[q->write_ptr] = skb;
@@ -1564,8 +1430,8 @@ static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans)
iwl_enable_rfkill_int(trans);
}
-static int iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid,
- int txq_id, int ssn, struct sk_buff_head *skbs)
+static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
+ struct sk_buff_head *skbs)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
@@ -1577,33 +1443,15 @@ static int iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid,
txq->time_stamp = jiffies;
- if (unlikely(txq_id >= IWLAGN_FIRST_AMPDU_QUEUE &&
- tid != IWL_TID_NON_QOS &&
- txq_id != trans_pcie->agg_txq[sta_id][tid])) {
- /*
- * FIXME: this is a uCode bug which need to be addressed,
- * log the information and return for now.
- * Since it is can possibly happen very often and in order
- * not to fill the syslog, don't use IWL_ERR or IWL_WARN
- */
- IWL_DEBUG_TX_QUEUES(trans, "Bad queue mapping txq_id %d, "
- "agg_txq[sta_id[tid] %d", txq_id,
- trans_pcie->agg_txq[sta_id][tid]);
- spin_unlock(&txq->lock);
- return 1;
- }
-
if (txq->q.read_ptr != tfd_num) {
- IWL_DEBUG_TX_REPLY(trans, "[Q %d | AC %d] %d -> %d (%d)\n",
- txq_id, iwl_get_queue_ac(txq), txq->q.read_ptr,
- tfd_num, ssn);
+ IWL_DEBUG_TX_REPLY(trans, "[Q %d] %d -> %d (%d)\n",
+ txq_id, txq->q.read_ptr, tfd_num, ssn);
freed = iwl_tx_queue_reclaim(trans, txq_id, tfd_num, skbs);
if (iwl_queue_space(&txq->q) > txq->q.low_mark)
iwl_wake_queue(trans, txq);
}
spin_unlock(&txq->lock);
- return 0;
}
static void iwl_trans_pcie_write8(struct iwl_trans *trans, u32 ofs, u8 val)
@@ -1622,7 +1470,7 @@ static u32 iwl_trans_pcie_read32(struct iwl_trans *trans, u32 ofs)
}
static void iwl_trans_pcie_configure(struct iwl_trans *trans,
- const struct iwl_trans_config *trans_cfg)
+ const struct iwl_trans_config *trans_cfg)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
@@ -1634,6 +1482,17 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans,
if (trans_pcie->n_no_reclaim_cmds)
memcpy(trans_pcie->no_reclaim_cmds, trans_cfg->no_reclaim_cmds,
trans_pcie->n_no_reclaim_cmds * sizeof(u8));
+
+ trans_pcie->n_q_to_fifo = trans_cfg->n_queue_to_fifo;
+
+ if (WARN_ON(trans_pcie->n_q_to_fifo > IWL_MAX_HW_QUEUES))
+ trans_pcie->n_q_to_fifo = IWL_MAX_HW_QUEUES;
+
+ /* at least the command queue must be mapped */
+ WARN_ON(!trans_pcie->n_q_to_fifo);
+
+ memcpy(trans_pcie->setup_q_to_fifo, trans_cfg->queue_to_fifo,
+ trans_pcie->n_q_to_fifo * sizeof(u8));
}
static void iwl_trans_pcie_free(struct iwl_trans *trans)
@@ -1957,18 +1816,10 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
txq = &trans_pcie->txq[cnt];
q = &txq->q;
pos += scnprintf(buf + pos, bufsz - pos,
- "hwq %.2d: read=%u write=%u stop=%d"
- " swq_id=%#.2x (ac %d/hwq %d)\n",
+ "hwq %.2d: read=%u write=%u use=%d stop=%d\n",
cnt, q->read_ptr, q->write_ptr,
- !!test_bit(cnt, trans_pcie->queue_stopped),
- txq->swq_id, txq->swq_id & 3,
- (txq->swq_id >> 2) & 0x1f);
- if (cnt >= 4)
- continue;
- /* for the ACs, display the stop count too */
- pos += scnprintf(buf + pos, bufsz - pos,
- " stop-count: %d\n",
- atomic_read(&trans_pcie->queue_stop_count[cnt]));
+ !!test_bit(cnt, trans_pcie->queue_used),
+ !!test_bit(cnt, trans_pcie->queue_stopped));
}
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
kfree(buf);
@@ -2210,7 +2061,6 @@ const struct iwl_trans_ops trans_ops_pcie = {
.reclaim = iwl_trans_pcie_reclaim,
.tx_agg_disable = iwl_trans_pcie_tx_agg_disable,
- .tx_agg_alloc = iwl_trans_pcie_tx_agg_alloc,
.tx_agg_setup = iwl_trans_pcie_tx_agg_setup,
.free = iwl_trans_pcie_free,