]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
rt2x00: Move direct access to queue->entries to rt2x00queue.c
authorIvo van Doorn <ivdoorn@gmail.com>
Mon, 23 Aug 2010 17:54:21 +0000 (19:54 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 25 Aug 2010 18:34:54 +0000 (14:34 -0400)
All access to queue->entries through the Q_INDEX/Q_INDEX_DONE
variables must be done using spinlock protection. It is best
to manage this completely from rt2x00queue.c.

For safely looping through all entries in the queue, the function
rt2x00queue_for_each_entry is added which will walk from from a index
range in a safe manner.

This also fixes rt2x00usb which walked the entries list from
0 to length to kill each entry (killing entries must be done
from Q_INDEX_DONE to Q_INDEX to enforce TX status reporting to
occur in the correct order.

Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Acked-by: Gertjan van Wingerde <gwingerde@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/rt2x00/rt2800pci.c
drivers/net/wireless/rt2x00/rt2x00queue.c
drivers/net/wireless/rt2x00/rt2x00queue.h
drivers/net/wireless/rt2x00/rt2x00usb.c

index af1c6914d7b42919047eceabf31320913b0dfc2f..a5e58705b49b2e3b35c271bfff1477cdd6f96375 100644 (file)
@@ -629,7 +629,7 @@ static void rt2800pci_write_tx_desc(struct queue_entry *entry,
 static void rt2800pci_kick_tx_queue(struct data_queue *queue)
 {
        struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
-       unsigned int idx = queue->index[Q_INDEX];
+       struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX);
        unsigned int qidx = 0;
 
        if (queue->qid == QID_MGMT)
@@ -637,7 +637,7 @@ static void rt2800pci_kick_tx_queue(struct data_queue *queue)
        else
                qidx = queue->qid;
 
-       rt2800_register_write(rt2x00dev, TX_CTX_IDX(qidx), idx);
+       rt2800_register_write(rt2x00dev, TX_CTX_IDX(qidx), entry->entry_idx);
 }
 
 static void rt2800pci_kill_tx_queue(struct data_queue *queue)
index 189eaf72967ef412eec403ecd6feeabdf1522714..7fb9b6179af1d2b8b29f7a634494f9d458fa4474 100644 (file)
@@ -625,6 +625,51 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
        return 0;
 }
 
+void rt2x00queue_for_each_entry(struct data_queue *queue,
+                               enum queue_index start,
+                               enum queue_index end,
+                               void (*fn)(struct queue_entry *entry))
+{
+       unsigned long irqflags;
+       unsigned int index_start;
+       unsigned int index_end;
+       unsigned int i;
+
+       if (unlikely(start >= Q_INDEX_MAX || end >= Q_INDEX_MAX)) {
+               ERROR(queue->rt2x00dev,
+                     "Entry requested from invalid index range (%d - %d)\n",
+                     start, end);
+               return;
+       }
+
+       /*
+        * Only protect the range we are going to loop over,
+        * if during our loop a extra entry is set to pending
+        * it should not be kicked during this run, since it
+        * is part of another TX operation.
+        */
+       spin_lock_irqsave(&queue->lock, irqflags);
+       index_start = queue->index[start];
+       index_end = queue->index[end];
+       spin_unlock_irqrestore(&queue->lock, irqflags);
+
+       /*
+        * Start from the TX done pointer, this guarentees that we will
+        * send out all frames in the correct order.
+        */
+       if (index_start < index_end) {
+               for (i = index_start; i < index_end; i++)
+                       fn(&queue->entries[i]);
+       } else {
+               for (i = index_start; i < queue->limit; i++)
+                       fn(&queue->entries[i]);
+
+               for (i = 0; i < index_end; i++)
+                       fn(&queue->entries[i]);
+       }
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_for_each_entry);
+
 struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev,
                                         const enum data_queue_qid queue)
 {
index 2d3bf843735ffd87a8616997a893f2a3729e5a0b..46a3be1d82b925283963f8e9558497915efd945f 100644 (file)
@@ -570,6 +570,22 @@ struct data_queue_desc {
 #define txall_queue_for_each(__dev, __entry) \
        queue_loop(__entry, (__dev)->tx, queue_end(__dev))
 
+/**
+ * rt2x00queue_for_each_entry - Loop through all entries in the queue
+ * @queue: Pointer to @data_queue
+ * @start: &enum queue_index Pointer to start index
+ * @end: &enum queue_index Pointer to end index
+ * @fn: The function to call for each &struct queue_entry
+ *
+ * This will walk through all entries in the queue, in chronological
+ * order. This means it will start at the current @start pointer
+ * and will walk through the queue until it reaches the @end pointer.
+ */
+void rt2x00queue_for_each_entry(struct data_queue *queue,
+                               enum queue_index start,
+                               enum queue_index end,
+                               void (*fn)(struct queue_entry *entry));
+
 /**
  * rt2x00queue_empty - Check if the queue is empty.
  * @queue: Queue to check if empty.
index 1d2eb461329f6ffe8d6f357300f89f8ea98ecedd..6cc7aa418d8727db8f511a42b1424fd9a7c31671 100644 (file)
@@ -225,7 +225,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
        ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->txdone_work);
 }
 
-static inline void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
+static void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
 {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
        struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
@@ -252,69 +252,34 @@ static inline void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
 
 void rt2x00usb_kick_tx_queue(struct data_queue *queue)
 {
-       unsigned long irqflags;
-       unsigned int index;
-       unsigned int index_done;
-       unsigned int i;
-
-       /*
-        * Only protect the range we are going to loop over,
-        * if during our loop a extra entry is set to pending
-        * it should not be kicked during this run, since it
-        * is part of another TX operation.
-        */
-       spin_lock_irqsave(&queue->lock, irqflags);
-       index = queue->index[Q_INDEX];
-       index_done = queue->index[Q_INDEX_DONE];
-       spin_unlock_irqrestore(&queue->lock, irqflags);
-
-       /*
-        * Start from the TX done pointer, this guarentees that we will
-        * send out all frames in the correct order.
-        */
-       if (index_done < index) {
-               for (i = index_done; i < index; i++)
-                       rt2x00usb_kick_tx_entry(&queue->entries[i]);
-       } else {
-               for (i = index_done; i < queue->limit; i++)
-                       rt2x00usb_kick_tx_entry(&queue->entries[i]);
-
-               for (i = 0; i < index; i++)
-                       rt2x00usb_kick_tx_entry(&queue->entries[i]);
-       }
+       rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
+                                  rt2x00usb_kick_tx_entry);
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_kick_tx_queue);
 
-void rt2x00usb_kill_tx_queue(struct data_queue *queue)
+static void rt2x00usb_kill_tx_entry(struct queue_entry *entry)
 {
-       struct queue_entry_priv_usb *entry_priv;
-       struct queue_entry_priv_usb_bcn *bcn_priv;
-       unsigned int i;
-       bool kill_guard;
+       struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+       struct queue_entry_priv_usb *entry_priv = entry->priv_data;
+       struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data;
 
-       /*
-        * When killing the beacon queue, we must also kill
-        * the beacon guard byte.
-        */
-       kill_guard =
-           (queue->qid == QID_BEACON) &&
-           (test_bit(DRIVER_REQUIRE_BEACON_GUARD, &queue->rt2x00dev->flags));
+       if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+               return;
+
+       usb_kill_urb(entry_priv->urb);
 
        /*
-        * Cancel all entries.
+        * Kill guardian urb (if required by driver).
         */
-       for (i = 0; i < queue->limit; i++) {
-               entry_priv = queue->entries[i].priv_data;
-               usb_kill_urb(entry_priv->urb);
+       if ((entry->queue->qid == QID_BEACON) &&
+           (test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags)))
+               usb_kill_urb(bcn_priv->guardian_urb);
+}
 
-               /*
-                * Kill guardian urb (if required by driver).
-                */
-               if (kill_guard) {
-                       bcn_priv = queue->entries[i].priv_data;
-                       usb_kill_urb(bcn_priv->guardian_urb);
-               }
-       }
+void rt2x00usb_kill_tx_queue(struct data_queue *queue)
+{
+       rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
+                                  rt2x00usb_kill_tx_entry);
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_kill_tx_queue);