>From Ivo van Doorn <[EMAIL PROTECTED]>

rt61pci irq is a bit different compared to the others,
when the irq is raised, we should read from the register which
ring and which entry has been send. And this entry should
be processed. Using a for loop to go through all entries
is no longer working since we require certain statistics
from the registers.

Signed-off-by: Ivo van Doorn <[EMAIL PROTECTED]>

diff -rU3 wireless-dev-ringentry/drivers/net/wireless/d80211/rt2x00/rt61pci.c 
wireless-dev-rt61irq/drivers/net/wireless/d80211/rt2x00/rt61pci.c
--- wireless-dev-ringentry/drivers/net/wireless/d80211/rt2x00/rt61pci.c 
2006-07-25 14:55:25.000000000 +0200
+++ wireless-dev-rt61irq/drivers/net/wireless/d80211/rt2x00/rt61pci.c   
2006-07-25 16:13:19.000000000 +0200
@@ -1473,72 +1473,119 @@
        rt61pci_activity_led(rt2x00dev, total_rssi);
 }
 
-static void rt61pci_txdone(void *data)
+static void rt61pci_txdone_entry(struct data_entry *entry, u32 sta_csr4)
 {
-       struct data_ring *ring = data;
-       struct rt2x00_dev *rt2x00dev = ieee80211_dev_hw_data(ring->net_dev);
-       struct data_entry *entry;
+       struct rt2x00_dev *rt2x00dev =
+               ieee80211_dev_hw_data(entry->ring->net_dev);
        struct txd *txd;
        int tx_status;
        int ack;
-       int reg;
        int ring_full;
 
+       txd = rt2x00pci_desc_addr(entry);
+
+       if (rt2x00_get_field32(txd->word0, TXD_W0_OWNER_NIC) ||
+           !rt2x00_get_field32(txd->word0, TXD_W0_VALID))
+               return;
+
+       ack = rt2x00_get_field32(txd->word0, TXD_W0_ACK);
+
        /*
-        * Store the current status of the ring.
+        * TODO: How can te below field be set correctly?
         */
-       ring_full = rt2x00_ring_full(ring);
+       entry->tx_status.tx_filtered = 0;
 
-       while (!rt2x00_ring_empty(ring)) {
-               entry = rt2x00_get_data_entry_done(ring);
-               txd = rt2x00pci_desc_addr(entry);
+       entry->tx_status.queue_length = entry->ring->stats.limit;
 
-               rt2x00_register_read(rt2x00dev, STA_CSR4, &reg);
+       /*
+        * The TXD_W0_RESULT field will only be set when
+        * we had requested an ACK. So we have received an
+        * ACK response when ACK was requested and status
+        * was succesfull.
+        */
+       tx_status = rt2x00_get_field32(sta_csr4, STA_CSR4_TX_RESULT);
+       entry->tx_status.ack = 0;
+       if (ack && (tx_status == TX_SUCCESS ||
+           tx_status == TX_SUCCESS_RETRY))
+               entry->tx_status.ack = 1;
+       else if (ack && tx_status == TX_FAIL_RETRY) {
+               rt2x00dev->low_level_stats.dot11ACKFailureCount++;
+               entry->tx_status.excessive_retries++;
+       }
 
-               if (rt2x00_get_field32(txd->word0, TXD_W0_OWNER_NIC) ||
-                   !rt2x00_get_field32(txd->word0, TXD_W0_VALID) ||
-                   !rt2x00_get_field32(reg, STA_CSR4_VALID))
-                       break;
+       rt2x00_bbp_read(rt2x00dev, 32,
+               (u8*)&entry->tx_status.ack_signal);
 
-               ack = rt2x00_get_field32(txd->word0, TXD_W0_ACK);
+       entry->tx_status.retry_count = rt2x00_get_field32(
+               sta_csr4, STA_CSR4_RETRY_COUNT);
 
-               /*
-                * TODO: How can te below field be set correctly?
-                */
-               entry->tx_status.tx_filtered = 0;
+       if (!GET_FLAG(entry, ENTRY_RTS_FRAME))
+               ieee80211_tx_status(entry->ring->net_dev,
+                       entry->skb, &entry->tx_status);
 
-               entry->tx_status.queue_length = ring->stats.limit;
+       rt2x00_set_field32(&txd->word0, TXD_W0_VALID, 0);
+       entry->skb = NULL;
 
-               /*
-                * The TXD_W0_RESULT field will only be set when
-                * we had requested an ACK. So we have received an
-                * ACK response when ACK was requested and status
-                * was succesfull.
-                */
-               tx_status = rt2x00_get_field32(reg, STA_CSR4_TX_RESULT);
-               entry->tx_status.ack = 0;
-               if (ack && (tx_status == TX_SUCCESS ||
-                   tx_status == TX_SUCCESS_RETRY))
-                       entry->tx_status.ack = 1;
-               else if (ack && tx_status == TX_FAIL_RETRY) {
-                       rt2x00dev->low_level_stats.dot11ACKFailureCount++;
-                       entry->tx_status.excessive_retries++;
-               }
+       /*
+        * Store the current status of the ring.
+        */
+       ring_full = rt2x00_ring_full(entry->ring);
 
-               rt2x00_bbp_read(rt2x00dev, 32,
-                       (u8*)&entry->tx_status.ack_signal);
+       rt2x00_ring_index_done_inc(entry->ring);
 
-               entry->tx_status.retry_count = rt2x00_get_field32(
-                       reg, STA_CSR4_RETRY_COUNT);
+       /*
+        * If the data ring was full before the txdone handler
+        * we must make sure the packet queue in the d80211 stack
+        * is reenabled when the txdone handler has finished.
+        */
+       if (ring_full && !rt2x00_ring_full(entry->ring))
+               ieee80211_wake_queue(entry->ring->net_dev,
+                       entry->tx_status.control.queue);
+}
 
-               if (!GET_FLAG(entry, ENTRY_RTS_FRAME))
-                       ieee80211_tx_status(ring->net_dev,
-                               entry->skb, &entry->tx_status);
+static void rt61pci_txdone(void *data)
+{
+       struct data_ring *ring = data;
+       struct rt2x00_dev *rt2x00dev = ieee80211_dev_hw_data(ring->net_dev);
+       int index;
+       int reg;
 
-               rt2x00_set_field32(&txd->word0, TXD_W0_VALID, 0);
-               entry->skb = NULL;
+       /*
+        * Keep looping while STA_CSR4 contains value data.
+        * at each read the value will be reset to a new value,
+        * which we should check since it contains the ring
+        * and index number of the entry which has been
+        * completely transmitted.
+        */
+       while (1) {
+               /*
+                * Stop looping when the entry is invalid.
+                */
+               rt2x00_register_read(rt2x00dev, STA_CSR4, &reg);
+               if (!rt2x00_get_field32(reg, STA_CSR4_VALID))
+                       break;
 
-               rt2x00_ring_index_done_inc(ring);
+               /*
+                * Skip this entry when it contains an invalid
+                * ring identication number.
+                */
+               ring = rt2x00_get_ring(rt2x00dev,
+                       rt2x00_get_field32(reg, STA_CSR4_PID_TYPE));
+               if (unlikely(!ring))
+                       continue;
+
+               /*
+                * Skip this entry when it contains an invalid
+                * index number.
+                */
+               index = rt2x00_get_field32(reg, STA_CSR4_PID_SUBTYPE);
+               if (unlikely(index >= ring->stats.limit))
+                       continue;
+
+               /*
+                * Packet received correctly, we can now process it.
+                */
+               rt61pci_txdone_entry(&ring->entry[index], reg);
        }
 
        /*
@@ -1554,16 +1601,6 @@
                rt2x00dev->scan->status = SCANNING_READY;
                complete(&rt2x00dev->scan->completion);
        }
-
-       /*
-        * If the data ring was full before the txdone handler
-        * we must make sure the packet queue in the d80211 stack
-        * is reenabled when the txdone handler has finished.
-        */
-       entry = ring->entry;
-       if (ring_full && !rt2x00_ring_full(ring))
-               ieee80211_wake_queue(ring->net_dev,
-                       entry->tx_status.control.queue);
 }
 
 static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance,
@@ -1966,6 +2003,8 @@
                rt2x00_set_field32(&txd->word1, TXD_W1_BUFFER_COUNT, 1);
                rt2x00_set_field32(&txd->word6, TXD_W6_BUFFER_PHYSICAL_ADDRESS,
                        ring->entry[i].data_dma);
+               rt2x00_set_field32(&txd->word5, TXD_W5_PID_TYPE, ring->type);
+               rt2x00_set_field32(&txd->word5, TXD_W5_PID_SUBTYPE, i);
        }
 
        rt2x00_ring_index_clear(ring);
diff -rU3 wireless-dev-ringentry/drivers/net/wireless/d80211/rt2x00/rt61pci.h 
wireless-dev-rt61irq/drivers/net/wireless/d80211/rt2x00/rt61pci.h
--- wireless-dev-ringentry/drivers/net/wireless/d80211/rt2x00/rt61pci.h 
2006-07-25 10:09:44.000000000 +0200
+++ wireless-dev-rt61irq/drivers/net/wireless/d80211/rt2x00/rt61pci.h   
2006-07-25 16:10:20.000000000 +0200
@@ -633,8 +633,8 @@
 #define STA_CSR4_VALID                 FIELD32(0x00000001)
 #define STA_CSR4_TX_RESULT             FIELD32(0x0000000e)
 #define STA_CSR4_RETRY_COUNT           FIELD32(0x000000f0)
-#define STA_CSR4_PID_SUBTYPE           FIELD32(0x00003f00)
-#define STA_CSR4_PID_TYPE              FIELD32(0x0000c000)
+#define STA_CSR4_PID_SUBTYPE           FIELD32(0x00001f00)
+#define STA_CSR4_PID_TYPE              FIELD32(0x0000e000)
 #define STA_CSR4_TXRATE                        FIELD32(0x000f0000)
 
 /*
@@ -1172,13 +1172,15 @@
 /*
  * WORD5
  * FRAME_OFFSET: Frame start offset inside ASIC TXFIFO (after TXINFO field).
- * PACKET_ID: Driver assigned packet ID to categorize TXResult in interrupt.
+ * TXD_W5_PID_SUBTYPE: Driver assigned packet ID index for txdone handler.
+ * TXD_W5_PID_TYPE: Driver assigned packet ID type for txdone handler.
  * WAITING_DMA_DONE_INT: TXD been filled with data
  * and waiting for TxDoneISR housekeeping.
  */
        __le32 word5;
 #define TXD_W5_FRAME_OFFSET            FIELD32(0x000000ff)
-#define TXD_W5_PACKET_ID               FIELD32(0x0000ff00)
+#define TXD_W5_PID_SUBTYPE             FIELD32(0x00001f00)
+#define TXD_W5_PID_TYPE                        FIELD32(0x0000e000)
 #define TXD_W5_TX_POWER                        FIELD32(0x00ff0000)
 #define TXD_W5_WAITING_DMA_DONE_INT    FIELD32(0x01000000)
 
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to