Commit ed61e2b0 authored by Stanislaw Gruszka's avatar Stanislaw Gruszka Committed by John W. Linville

rt2x00: rt2800usb: rework txdone code

Patch change txdone code to make it similar like txdone in rt2800pci,
process only one entry from queue matching tx status.

Before we processed all pending entries from queue until PACKEDID match,
that caused that we do not report tx statuses correctly.
Signed-off-by: default avatarStanislaw Gruszka <sgruszka@redhat.com>
Acked-by: default avatarGertjan van Wingerde <gwingerde@gmail.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 627fdaf7
...@@ -438,35 +438,25 @@ static int rt2800usb_get_tx_data_len(struct queue_entry *entry) ...@@ -438,35 +438,25 @@ static int rt2800usb_get_tx_data_len(struct queue_entry *entry)
/* /*
* TX control handlers * TX control handlers
*/ */
static bool rt2800usb_txdone_entry_check(struct queue_entry *entry, u32 reg) static enum txdone_entry_desc_flags
rt2800usb_txdone_entry_check(struct queue_entry *entry, u32 reg)
{ {
__le32 *txwi; __le32 *txwi;
u32 word; u32 word;
int wcid, ack, pid; int wcid, ack, pid;
int tx_wcid, tx_ack, tx_pid; int tx_wcid, tx_ack, tx_pid;
if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
!test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags)) {
WARNING(entry->queue->rt2x00dev,
"Data pending for entry %u in queue %u\n",
entry->entry_idx, entry->queue->qid);
cond_resched();
return false;
}
wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID);
ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED);
pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE);
/* /*
* This frames has returned with an IO error, * This frames has returned with an IO error,
* so the status report is not intended for this * so the status report is not intended for this
* frame. * frame.
*/ */
if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) { if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE); return TXDONE_FAILURE;
return false;
} wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID);
ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED);
pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE);
/* /*
* Validate if this TX status report is intended for * Validate if this TX status report is intended for
...@@ -483,11 +473,10 @@ static bool rt2800usb_txdone_entry_check(struct queue_entry *entry, u32 reg) ...@@ -483,11 +473,10 @@ static bool rt2800usb_txdone_entry_check(struct queue_entry *entry, u32 reg)
WARNING(entry->queue->rt2x00dev, WARNING(entry->queue->rt2x00dev,
"TX status report missed for queue %d entry %d\n", "TX status report missed for queue %d entry %d\n",
entry->queue->qid, entry->entry_idx); entry->queue->qid, entry->entry_idx);
rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN); return TXDONE_UNKNOWN;
return false;
} }
return true; return TXDONE_SUCCESS;
} }
static void rt2800usb_txdone(struct rt2x00_dev *rt2x00dev) static void rt2800usb_txdone(struct rt2x00_dev *rt2x00dev)
...@@ -496,35 +485,36 @@ static void rt2800usb_txdone(struct rt2x00_dev *rt2x00dev) ...@@ -496,35 +485,36 @@ static void rt2800usb_txdone(struct rt2x00_dev *rt2x00dev)
struct queue_entry *entry; struct queue_entry *entry;
u32 reg; u32 reg;
u8 qid; u8 qid;
enum txdone_entry_desc_flags done_status;
while (kfifo_get(&rt2x00dev->txstatus_fifo, &reg)) { while (kfifo_get(&rt2x00dev->txstatus_fifo, &reg)) {
/*
/* TX_STA_FIFO_PID_QUEUE is a 2-bit field, thus * TX_STA_FIFO_PID_QUEUE is a 2-bit field, thus qid is
* qid is guaranteed to be one of the TX QIDs * guaranteed to be one of the TX QIDs .
*/ */
qid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE); qid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE);
queue = rt2x00queue_get_tx_queue(rt2x00dev, qid); queue = rt2x00queue_get_tx_queue(rt2x00dev, qid);
if (unlikely(!queue)) {
WARNING(rt2x00dev, "Got TX status for an unavailable " if (unlikely(rt2x00queue_empty(queue))) {
WARNING(rt2x00dev, "Got TX status for an empty "
"queue %u, dropping\n", qid); "queue %u, dropping\n", qid);
continue; break;
} }
/*
* Inside each queue, we process each entry in a chronological
* order. We first check that the queue is not empty.
*/
entry = NULL;
while (!rt2x00queue_empty(queue)) {
entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
if (rt2800usb_txdone_entry_check(entry, reg))
if (unlikely(test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
!test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))) {
WARNING(rt2x00dev, "Data pending for entry %u "
"in queue %u\n", entry->entry_idx, qid);
break; break;
entry = NULL;
} }
if (entry) done_status = rt2800usb_txdone_entry_check(entry, reg);
rt2800_txdone_entry(entry, reg, if (likely(done_status == TXDONE_SUCCESS))
rt2800usb_get_txwi(entry)); rt2800_txdone_entry(entry, reg, rt2800usb_get_txwi(entry));
else
rt2x00lib_txdone_noinfo(entry, done_status);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment