[rt2x00-users] [PATCH 05/12] rt2x00: Fix for TX_FIFO_STATUS interrupt on rt2800pci

Benoit PAPILLAULT benoit.papillault at free.fr
Fri Aug 14 22:06:11 UTC 2009


This patch make uses of WCID/PID field of the TXD in order to get an interrupt
for all transmitted packets. It seems that the hardware does not sent an
interrupt if PID is 0, so this patch avoid using this value. As a side
effect, it seems that WCID is used as an index to lookup the encryption keys
and as such, encryption no longers works.

Signed-off-by: Benoit PAPILLAULT <benoit.papillault at free.fr>
---
 drivers/net/wireless/rt2x00/rt2800pci.c |   86 +++++++++++++++++++------------
 1 files changed, 52 insertions(+), 34 deletions(-)

diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index d934f13..8626a71 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -2114,11 +2114,13 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 	__le32 *txd = skbdesc->desc;
 	__le32 *txwi = (__le32 *)(skb->data - rt2x00dev->hw->extra_tx_headroom);
 	u32 word;
+	int wcid = skbdesc->entry->entry_idx + 1;
+	int pid = skbdesc->entry->queue->qid + 1;
 
 	/*
 	 * Initialize TX Info descriptor
 	 */
-	rt2x00_desc_read(txwi, 0, &word);
+	word = 0;
 	rt2x00_set_field32(&word, TXWI_W0_FRAG,
 			   test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
 	rt2x00_set_field32(&word, TXWI_W0_MIMO_PS, 0);
@@ -2138,21 +2140,23 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 	rt2x00_set_field32(&word, TXWI_W0_PHYMODE, txdesc->rate_mode);
 	rt2x00_desc_write(txwi, 0, word);
 
-	rt2x00_desc_read(txwi, 1, &word);
+	word = 0;
 	rt2x00_set_field32(&word, TXWI_W1_ACK,
 			   test_bit(ENTRY_TXD_ACK, &txdesc->flags));
 	rt2x00_set_field32(&word, TXWI_W1_NSEQ,
 			   test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags));
 	rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->ba_size);
-	rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID,
-			   test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ?
-			       txdesc->key_idx : 0xff);
+	rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID, wcid);
 	rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT,
 			   skb->len - txdesc->l2pad);
-	rt2x00_set_field32(&word, TXWI_W1_PACKETID,
-			   skbdesc->entry->queue->qid);
+	printk("%s: skb=%p skb->data=%p skb->len=%d MPDU_TOTAL_BYTE_COUNT=%d\n",
+	       __func__, skb, skb->data, skb->len, skb->len - txdesc->l2pad);
+	rt2x00_set_field32(&word, TXWI_W1_PACKETID, pid);
 	rt2x00_desc_write(txwi, 1, word);
 
+	printk("%s: ACK=%d WCID=%d PID=%d\n", __func__, 
+	       test_bit(ENTRY_TXD_ACK, &txdesc->flags), wcid, pid);
+
 	/*
 	 * Always write 0 to IV/EIV fields, hardware will insert the IV
 	 * from the IVEIV register when ENTRY_TXD_ENCRYPT_IV is set to 0.
@@ -2166,28 +2170,37 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 	/*
 	 * Initialize TX descriptor
 	 */
-	rt2x00_desc_read(txd, 0, &word);
+
+	/* 
+	 * The buffers pointed by (SD_PTR0, SD_LEN0) and (SD_PTR1, SD_LEN1)
+	 * must contains a TXWI structure + 802.11 header + padding + 802.11
+	 * data. We choose to have (SD_PTR0, SD_LEN0) only contains TXWI and
+	 * (SD_PTR1, SD_LEN1) contains 802.11 header + padding + 802.11
+	 * data. It means that LAST_SEC0 is always 0.
+	 */
+
+	word = 0;
 	rt2x00_set_field32(&word, TXD_W0_SD_PTR0, skbdesc->skb_dma);
 	rt2x00_desc_write(txd, 0, word);
 
-	rt2x00_desc_read(txd, 1, &word);
+	word = 0;
 	rt2x00_set_field32(&word, TXD_W1_SD_LEN1, skb->len);
-	rt2x00_set_field32(&word, TXD_W1_LAST_SEC1, 1);
+	rt2x00_set_field32(&word, TXD_W1_LAST_SEC1,
+		!test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
 	rt2x00_set_field32(&word, TXD_W1_BURST,
 			   test_bit(ENTRY_TXD_BURST, &txdesc->flags));
 	rt2x00_set_field32(&word, TXD_W1_SD_LEN0,
 			   rt2x00dev->hw->extra_tx_headroom);
-	rt2x00_set_field32(&word, TXD_W1_LAST_SEC0,
-			   !test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
+	rt2x00_set_field32(&word, TXD_W1_LAST_SEC0, 0);
 	rt2x00_set_field32(&word, TXD_W1_DMA_DONE, 0);
 	rt2x00_desc_write(txd, 1, word);
 
-	rt2x00_desc_read(txd, 2, &word);
+	word = 0;
 	rt2x00_set_field32(&word, TXD_W2_SD_PTR1,
 			   skbdesc->skb_dma + rt2x00dev->hw->extra_tx_headroom);
 	rt2x00_desc_write(txd, 2, word);
 
-	rt2x00_desc_read(txd, 3, &word);
+	word = 0;
 	rt2x00_set_field32(&word, TXD_W3_WIV,
 			   !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags));
 	rt2x00_set_field32(&word, TXD_W3_QSEL, 2);
@@ -2261,6 +2274,7 @@ static void rt2800pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
 	else
 		qidx = queue_idx;
 
+	printk("%s: qidx=%d idx=%d\n", __func__, qidx, idx);
 	rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX(qidx), idx);
 }
 
@@ -2395,47 +2409,51 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
 	struct txdone_entry_desc txdesc;
 	u32 word;
 	u32 reg;
-	u32 old_reg;
-	int type;
-	int index;
+	int i;
+	int wcid, pid;
 
 	/*
-	 * During each loop we will compare the freshly read
-	 * TX_STA_FIFO register value with the value read from
-	 * the previous loop. If the 2 values are equal then
-	 * we should stop processing because the chance it
-	 * quite big that the device has been unplugged and
-	 * we risk going into an endless loop.
+	 * To avoid an endlees loop, we only read the TX_STA_FIFO register up
+	 * to 256 times (this should be enought to get all values from the
+	 * FIFO
 	 */
-	old_reg = 0;
 
-	while (1) {
+	for (i=0; i<256; i++) {
 		rt2x00pci_register_read(rt2x00dev, TX_STA_FIFO, &reg);
+
 		if (!rt2x00_get_field32(reg, TX_STA_FIFO_VALID))
 			break;
 
-		if (old_reg == reg)
-			break;
-		old_reg = reg;
+		pid  = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE);
+		wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID);
+
+		printk("%s: TX_STA_FIFO=%08x VALID=1 WCID=%d PID=%d\n",
+		       __func__, reg, wcid, pid);
 
 		/*
 		 * Skip this entry when it contains an invalid
 		 * queue identication number.
 		 */
-		type = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE);
-		queue = rt2x00queue_get_queue(rt2x00dev, type);
+		if (pid < 1)
+			continue;
+
+		queue = rt2x00queue_get_queue(rt2x00dev, pid - 1);
 		if (unlikely(!queue))
 			continue;
 
+		printk("%s: queue=%p\n", __func__, queue);
+
 		/*
 		 * Skip this entry when it contains an invalid
-		 * index number.
+		 * index number. We must have :
+		 * 0 <= wcid - 1 < queue->limit
 		 */
-		index = rt2x00_get_field32(reg, TX_STA_FIFO_WCID);
-		if (unlikely(index >= queue->limit))
+		if (unlikely(wcid < 1))
+			continue;
+		if (unlikely(wcid > queue->limit))
 			continue;
 
-		entry = &queue->entries[index];
+		entry = &queue->entries[wcid-1];
 		entry_priv = entry->priv_data;
 		rt2x00_desc_read((__le32 *)entry->skb->data, 0, &word);
 
-- 
1.6.2.4




More information about the users mailing list