rt2x00: Fix QOS sequence counting
authorIvo van Doorn <ivdoorn@gmail.com>
Sun, 20 Jul 2008 16:03:38 +0000 (18:03 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 29 Jul 2008 20:55:05 +0000 (16:55 -0400)
When IEEE80211_TX_CTL_ASSIGN_SEQ is not set,
the driver should disable hardware sequence counting
to make sure the mac80211 provided counter is used.
This fixes QOS sequence counting, since that is one
of the cases where mac80211 provides a seperate
sequence counter.

By moving the sequence counting code to rt2x00queue
we make sure that _all_ frames get the sequence counter,
including RTS/CTS and Beacon frames.

Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/rt2x00/rt2x00mac.c
drivers/net/wireless/rt2x00/rt2x00queue.c
drivers/net/wireless/rt2x00/rt2x00queue.h
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt73usb.c

index f1dcbaa80c3c2415e3f2de1c7f88945d9cfbf09b..9d346bd2db0efbec08a3daac7728a3e18c6aba24 100644 (file)
@@ -96,7 +96,6 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
        struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
        enum data_queue_qid qid = skb_get_queue_mapping(skb);
-       struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
        struct data_queue *queue;
        u16 frame_control;
 
@@ -152,18 +151,6 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
                }
        }
 
-       /*
-        * XXX: This is as wrong as the old mac80211 code was,
-        *      due to beacons not getting sequence numbers assigned
-        *      properly.
-        */
-       if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
-               if (tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
-                       intf->seqno += 0x10;
-               ieee80211hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
-               ieee80211hdr->seq_ctrl |= cpu_to_le16(intf->seqno);
-       }
-
        if (rt2x00queue_write_tx_frame(queue, skb)) {
                ieee80211_stop_queue(rt2x00dev->hw, qid);
                return NETDEV_TX_BUSY;
index 7f442030f5ad187a34b375a7ab4f19fa05c19a7b..7b581a370fde56019c095363ba58cdb434bb2086 100644 (file)
@@ -120,6 +120,7 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
 {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
+       struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data;
        struct ieee80211_rate *rate =
            ieee80211_get_tx_rate(rt2x00dev->hw, tx_info);
@@ -199,6 +200,31 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
                txdesc->ifs = IFS_SIFS;
        }
 
+       /*
+        * Hardware should insert sequence counter.
+        * FIXME: We insert a software sequence counter first for
+        * hardware that doesn't support hardware sequence counting.
+        *
+        * This is wrong because beacons are not getting sequence
+        * numbers assigned properly.
+        *
+        * A secondary problem exists for drivers that cannot toggle
+        * sequence counting per-frame, since those will override the
+        * sequence counter given by mac80211.
+        */
+       if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
+               spin_lock(&intf->lock);
+
+               if (test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags))
+                       intf->seqno += 0x10;
+               hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+               hdr->seq_ctrl |= cpu_to_le16(intf->seqno);
+
+               spin_unlock(&intf->lock);
+
+               __set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags);
+       }
+
        /*
         * PLCP setup
         * Length calculation depends on OFDM/CCK rate.
index 8945945c892e04f5c6ea3cc728366499e64d3a09..a4a8c57004db179d2df8777c45e421786f68a6af 100644 (file)
@@ -199,6 +199,7 @@ struct txdone_entry_desc {
  * @ENTRY_TXD_RTS_FRAME: This frame is a RTS frame.
  * @ENTRY_TXD_CTS_FRAME: This frame is a CTS-to-self frame.
  * @ENTRY_TXD_OFDM_RATE: This frame is send out with an OFDM rate.
+ * @ENTRY_TXD_GENERATE_SEQ: This frame requires sequence counter.
  * @ENTRY_TXD_FIRST_FRAGMENT: This is the first frame.
  * @ENTRY_TXD_MORE_FRAG: This frame is followed by another fragment.
  * @ENTRY_TXD_REQ_TIMESTAMP: Require timestamp to be inserted.
@@ -210,6 +211,7 @@ enum txentry_desc_flags {
        ENTRY_TXD_RTS_FRAME,
        ENTRY_TXD_CTS_FRAME,
        ENTRY_TXD_OFDM_RATE,
+       ENTRY_TXD_GENERATE_SEQ,
        ENTRY_TXD_FIRST_FRAGMENT,
        ENTRY_TXD_MORE_FRAG,
        ENTRY_TXD_REQ_TIMESTAMP,
index ec4ec65d94fd622bbff1f0815bef1688b407904f..fbe2a652e014b0c194aee79d0c3aa82ad2045dfe 100644 (file)
@@ -1544,7 +1544,8 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min);
        rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max);
        rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER);
-       rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1);
+       rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE,
+                          test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags));
        rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1);
        rt2x00_desc_write(txd, 1, word);
 
index 866504612e8ab27609386b86f3d4bbe1d7fa9f83..9761eaaa08be789e0cc970272719860ca3116526 100644 (file)
@@ -1281,7 +1281,8 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min);
        rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max);
        rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER);
-       rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1);
+       rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE,
+                          test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags));
        rt2x00_desc_write(txd, 1, word);
 
        rt2x00_desc_read(txd, 2, &word);