rt2800usb: read TX_STA_FIFO asynchronously

Trying to fix the "TX status report missed" warnings
by reading the TX_STA_FIFO entries as quickly as possible.
The TX_STA_FIFO is too small in hardware, thus reading
it only from the workqueue is too slow and entries get lost.

Start an asynchronous read of the TX_STA_FIFO directly from
the TX URB completion callback (atomic context, thus it cannot
use the blocking rt2800_register_read()). If the async
read returns a valid FIFO entry, it is pushed into a larger
FIFO inside struct rt2x00_dev, until rt2800_txdone() picks
it up.

A .tx_dma_done callback is added to struct rt2x00lib_ops
to trigger the async read from the URB completion callback.

Signed-off-by: Johannes Stezenbach <js@sig21.net>
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Johannes Stezenbach
2011-04-18 15:29:12 +02:00
committed by John W. Linville
parent 8da3efbb4a
commit 0e0d39e5f3
5 changed files with 110 additions and 24 deletions

View File

@@ -730,34 +730,20 @@ void rt2800_txdone(struct rt2x00_dev *rt2x00dev)
struct data_queue *queue;
struct queue_entry *entry;
u32 reg;
u8 pid;
int i;
u8 qid;
/*
* TX_STA_FIFO is a stack of X entries, hence read TX_STA_FIFO
* at most X times and also stop processing once the TX_STA_FIFO_VALID
* flag is not set anymore.
*
* The legacy drivers use X=TX_RING_SIZE but state in a comment
* that the TX_STA_FIFO stack has a size of 16. We stick to our
* tx ring size for now.
*/
for (i = 0; i < rt2x00dev->ops->tx->entry_num; i++) {
rt2800_register_read(rt2x00dev, TX_STA_FIFO, &reg);
if (!rt2x00_get_field32(reg, TX_STA_FIFO_VALID))
break;
while (kfifo_get(&rt2x00dev->txstatus_fifo, &reg)) {
/*
* Skip this entry when it contains an invalid
* queue identication number.
/* TX_STA_FIFO_PID_QUEUE is a 2-bit field, thus
* qid is guaranteed to be one of the TX QIDs
*/
pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE);
if (pid >= QID_RX)
continue;
queue = rt2x00queue_get_tx_queue(rt2x00dev, pid);
if (unlikely(!queue))
qid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE);
queue = rt2x00queue_get_tx_queue(rt2x00dev, qid);
if (unlikely(!queue)) {
WARNING(rt2x00dev, "Got TX status for an unavailable "
"queue %u, dropping\n", qid);
continue;
}
/*
* Inside each queue, we process each entry in a chronological