aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/pcie/tx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/pcie/tx.c')
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/tx.c60
1 files changed, 34 insertions, 26 deletions
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c
index c47c92165aba..f45eb29c2ede 100644
--- a/drivers/net/wireless/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/tx.c
@@ -65,18 +65,30 @@
65 ***************************************************/ 65 ***************************************************/
66static int iwl_queue_space(const struct iwl_queue *q) 66static int iwl_queue_space(const struct iwl_queue *q)
67{ 67{
68 int s = q->read_ptr - q->write_ptr; 68 unsigned int max;
69 69 unsigned int used;
70 if (q->read_ptr > q->write_ptr) 70
71 s -= q->n_bd; 71 /*
72 72 * To avoid ambiguity between empty and completely full queues, there
73 if (s <= 0) 73 * should always be less than q->n_bd elements in the queue.
74 s += q->n_window; 74 * If q->n_window is smaller than q->n_bd, there is no need to reserve
75 /* keep some reserve to not confuse empty and full situations */ 75 * any queue entries for this purpose.
76 s -= 2; 76 */
77 if (s < 0) 77 if (q->n_window < q->n_bd)
78 s = 0; 78 max = q->n_window;
79 return s; 79 else
80 max = q->n_bd - 1;
81
82 /*
83 * q->n_bd is a power of 2, so the following is equivalent to modulo by
84 * q->n_bd and is well defined for negative dividends.
85 */
86 used = (q->write_ptr - q->read_ptr) & (q->n_bd - 1);
87
88 if (WARN_ON(used > max))
89 return 0;
90
91 return max - used;
80} 92}
81 93
82/* 94/*
@@ -451,13 +463,10 @@ static int iwl_pcie_txq_build_tfd(struct iwl_trans *trans, struct iwl_txq *txq,
451 return -EINVAL; 463 return -EINVAL;
452 } 464 }
453 465
454 if (WARN_ON(addr & ~DMA_BIT_MASK(36))) 466 if (WARN(addr & ~IWL_TX_DMA_MASK,
467 "Unaligned address = %llx\n", (unsigned long long)addr))
455 return -EINVAL; 468 return -EINVAL;
456 469
457 if (unlikely(addr & ~IWL_TX_DMA_MASK))
458 IWL_ERR(trans, "Unaligned address = %llx\n",
459 (unsigned long long)addr);
460
461 iwl_pcie_tfd_set_tb(tfd, num_tbs, addr, len); 470 iwl_pcie_tfd_set_tb(tfd, num_tbs, addr, len);
462 471
463 return 0; 472 return 0;
@@ -829,7 +838,7 @@ static int iwl_pcie_tx_alloc(struct iwl_trans *trans)
829 sizeof(struct iwl_txq), GFP_KERNEL); 838 sizeof(struct iwl_txq), GFP_KERNEL);
830 if (!trans_pcie->txq) { 839 if (!trans_pcie->txq) {
831 IWL_ERR(trans, "Not enough memory for txq\n"); 840 IWL_ERR(trans, "Not enough memory for txq\n");
832 ret = ENOMEM; 841 ret = -ENOMEM;
833 goto error; 842 goto error;
834 } 843 }
835 844
@@ -1153,10 +1162,10 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id)
1153/* 1162/*
1154 * iwl_pcie_enqueue_hcmd - enqueue a uCode command 1163 * iwl_pcie_enqueue_hcmd - enqueue a uCode command
1155 * @priv: device private data point 1164 * @priv: device private data point
1156 * @cmd: a point to the ucode command structure 1165 * @cmd: a pointer to the ucode command structure
1157 * 1166 *
1158 * The function returns < 0 values to indicate the operation is 1167 * The function returns < 0 values to indicate the operation
1159 * failed. On success, it turns the index (> 0) of command in the 1168 * failed. On success, it returns the index (>= 0) of command in the
1160 * command queue. 1169 * command queue.
1161 */ 1170 */
1162static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, 1171static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
@@ -1619,10 +1628,9 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
1619 txq = &trans_pcie->txq[txq_id]; 1628 txq = &trans_pcie->txq[txq_id];
1620 q = &txq->q; 1629 q = &txq->q;
1621 1630
1622 if (unlikely(!test_bit(txq_id, trans_pcie->queue_used))) { 1631 if (WARN_ONCE(!test_bit(txq_id, trans_pcie->queue_used),
1623 WARN_ON_ONCE(1); 1632 "TX on unused queue %d\n", txq_id))
1624 return -EINVAL; 1633 return -EINVAL;
1625 }
1626 1634
1627 spin_lock(&txq->lock); 1635 spin_lock(&txq->lock);
1628 1636
@@ -1632,7 +1640,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
1632 * Check here that the packets are in the right place on the ring. 1640 * Check here that the packets are in the right place on the ring.
1633 */ 1641 */
1634 wifi_seq = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); 1642 wifi_seq = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl));
1635 WARN_ONCE(trans_pcie->txq[txq_id].ampdu && 1643 WARN_ONCE(txq->ampdu &&
1636 (wifi_seq & 0xff) != q->write_ptr, 1644 (wifi_seq & 0xff) != q->write_ptr,
1637 "Q: %d WiFi Seq %d tfdNum %d", 1645 "Q: %d WiFi Seq %d tfdNum %d",
1638 txq_id, wifi_seq, q->write_ptr); 1646 txq_id, wifi_seq, q->write_ptr);
@@ -1664,7 +1672,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
1664 */ 1672 */
1665 len = sizeof(struct iwl_tx_cmd) + sizeof(struct iwl_cmd_header) + 1673 len = sizeof(struct iwl_tx_cmd) + sizeof(struct iwl_cmd_header) +
1666 hdr_len - IWL_HCMD_SCRATCHBUF_SIZE; 1674 hdr_len - IWL_HCMD_SCRATCHBUF_SIZE;
1667 tb1_len = (len + 3) & ~3; 1675 tb1_len = ALIGN(len, 4);
1668 1676
1669 /* Tell NIC about any 2-byte padding after MAC header */ 1677 /* Tell NIC about any 2-byte padding after MAC header */
1670 if (tb1_len != len) 1678 if (tb1_len != len)