*/
void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev);
void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev);
+void rt2x00lib_dmadone(struct queue_entry *entry);
void rt2x00lib_txdone(struct queue_entry *entry,
struct txdone_entry_desc *txdesc);
void rt2x00lib_txdone_noinfo(struct queue_entry *entry, u32 status);
return -ENOMEM;
temp = data +
- sprintf(data, "qid\tcount\tlimit\tlength\tindex\tdone\n");
+ sprintf(data, "qid\tcount\tlimit\tlength\tindex\tdma done\tdone\n");
queue_for_each(intf->rt2x00dev, queue) {
spin_lock_irqsave(&queue->lock, irqflags);
- temp += sprintf(temp, "%d\t%d\t%d\t%d\t%d\t%d\n", queue->qid,
+ temp += sprintf(temp, "%d\t%d\t%d\t%d\t%d\t%d\t%d\n", queue->qid,
queue->count, queue->limit, queue->length,
queue->index[Q_INDEX],
+ queue->index[Q_INDEX_DMA_DONE],
queue->index[Q_INDEX_DONE]);
spin_unlock_irqrestore(&queue->lock, irqflags);
}
EXPORT_SYMBOL_GPL(rt2x00lib_pretbtt);
+void rt2x00lib_dmadone(struct queue_entry *entry)
+{
+ rt2x00queue_index_inc(entry->queue, Q_INDEX_DMA_DONE);
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_dmadone);
+
void rt2x00lib_txdone(struct queue_entry *entry,
struct txdone_entry_desc *txdesc)
{
if (queue->index[index] >= queue->limit)
queue->index[index] = 0;
+ queue->last_action[index] = jiffies;
+
if (index == Q_INDEX) {
queue->length++;
- queue->last_index = jiffies;
} else if (index == Q_INDEX_DONE) {
queue->length--;
queue->count++;
- queue->last_index_done = jiffies;
}
spin_unlock_irqrestore(&queue->lock, irqflags);
static void rt2x00queue_reset(struct data_queue *queue)
{
unsigned long irqflags;
+ unsigned int i;
spin_lock_irqsave(&queue->lock, irqflags);
queue->count = 0;
queue->length = 0;
- queue->last_index = jiffies;
- queue->last_index_done = jiffies;
- memset(queue->index, 0, sizeof(queue->index));
+
+ for (i = 0; i < Q_INDEX_MAX; i++) {
+ queue->index[i] = 0;
+ queue->last_action[i] = jiffies;
+ }
spin_unlock_irqrestore(&queue->lock, irqflags);
}
*
* @Q_INDEX: Index pointer to the current entry in the queue, if this entry is
* owned by the hardware then the queue is considered to be full.
+ * @Q_INDEX_DMA_DONE: Index pointer for the next entry which will have been
+ * transfered to the hardware.
* @Q_INDEX_DONE: Index pointer to the next entry which will be completed by
* the hardware and for which we need to run the txdone handler. If this
* entry is not owned by the hardware the queue is considered to be empty.
*/
enum queue_index {
Q_INDEX,
+ Q_INDEX_DMA_DONE,
Q_INDEX_DONE,
Q_INDEX_MAX,
};
enum data_queue_qid qid;
spinlock_t lock;
- unsigned long last_index;
- unsigned long last_index_done;
unsigned int count;
unsigned short limit;
unsigned short threshold;
unsigned short length;
unsigned short index[Q_INDEX_MAX];
+ unsigned long last_action[Q_INDEX_MAX];
unsigned short txop;
unsigned short aifs;
}
/**
- * rt2x00queue_timeout - Check if a timeout occured for this queue
+ * rt2x00queue_timeout - Check if a timeout occured for STATUS reorts
* @queue: Queue to check.
*/
static inline int rt2x00queue_timeout(struct data_queue *queue)
{
- return time_after(queue->last_index, queue->last_index_done + (HZ / 10));
+ return time_after(queue->last_action[Q_INDEX_DMA_DONE],
+ queue->last_action[Q_INDEX_DONE] + (HZ / 10));
+}
+
+/**
+ * rt2x00queue_timeout - Check if a timeout occured for DMA transfers
+ * @queue: Queue to check.
+ */
+static inline int rt2x00queue_dma_timeout(struct data_queue *queue)
+{
+ return time_after(queue->last_action[Q_INDEX],
+ queue->last_action[Q_INDEX_DMA_DONE] + (HZ / 10));
}
/**
!__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
return;
+ /*
+ * Report the frame as DMA done
+ */
+ rt2x00lib_dmadone(entry);
+
/*
* Check if the frame was correctly uploaded
*/
}
EXPORT_SYMBOL_GPL(rt2x00usb_kill_tx_queue);
-static void rt2x00usb_watchdog_reset_tx(struct data_queue *queue)
+static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue)
{
struct queue_entry *entry;
struct queue_entry_priv_usb *entry_priv;
unsigned short threshold = queue->threshold;
- WARNING(queue->rt2x00dev, "TX queue %d timed out, invoke reset", queue->qid);
+ WARNING(queue->rt2x00dev, "TX queue %d DMA timed out,"
+ " invoke forced forced reset", queue->qid);
/*
* Temporarily disable the TX queue, this will force mac80211
ieee80211_wake_queue(queue->rt2x00dev->hw, queue->qid);
}
+static void rt2x00usb_watchdog_tx_status(struct data_queue *queue)
+{
+ WARNING(queue->rt2x00dev, "TX queue %d status timed out,"
+ " invoke forced tx handler", queue->qid);
+
+ ieee80211_queue_work(queue->rt2x00dev->hw, &queue->rt2x00dev->txdone_work);
+}
+
void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
tx_queue_for_each(rt2x00dev, queue) {
+ if (rt2x00queue_dma_timeout(queue))
+ rt2x00usb_watchdog_tx_dma(queue);
if (rt2x00queue_timeout(queue))
- rt2x00usb_watchdog_reset_tx(queue);
+ rt2x00usb_watchdog_tx_status(queue);
}
}
EXPORT_SYMBOL_GPL(rt2x00usb_watchdog);
!__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
return;
+ /*
+ * Report the frame as DMA done
+ */
+ rt2x00lib_dmadone(entry);
+
/*
* Check if the received data is simply too small
* to be actually valid, or if the urb is signaling