aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorIvo van Doorn <ivdoorn@gmail.com>2010-08-30 15:13:30 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-08-31 14:22:24 -0400
commit3613884d96b186f58a77af05122f84167604aad9 (patch)
tree91daeb959fd679eaaa1c0e7ca1cb90153bf23a35 /drivers/net
parent5ffddc498c700bb45ea55efc37746cb28d601766 (diff)
rt2x00: Validate TX status results with current data entry
Instead of printing a warning when the PID, ACK, or WCID of an entry don't match the TX status report, we should skip the entry to search for the entry which actually does match the TX status data. This reduces the number of watchdog errors on the TX queues for rt2800usb, and seems to improve the reliability of the TX flow a bit. 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>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c73
1 files changed, 50 insertions, 23 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 7c68bf35951..1a8170068b1 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -581,6 +581,49 @@ void rt2800_process_rxwi(struct queue_entry *entry,
581} 581}
582EXPORT_SYMBOL_GPL(rt2800_process_rxwi); 582EXPORT_SYMBOL_GPL(rt2800_process_rxwi);
583 583
584static bool rt2800_txdone_entry_check(struct queue_entry *entry, u32 reg)
585{
586 __le32 *txwi;
587 u32 word;
588 int wcid, ack, pid;
589 int tx_wcid, tx_ack, tx_pid;
590
591 wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID);
592 ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED);
593 pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE);
594
595 /*
596 * This frames has returned with an IO error,
597 * so the status report is not intended for this
598 * frame.
599 */
600 if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) {
601 rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
602 return false;
603 }
604
605 /*
606 * Validate if this TX status report is intended for
607 * this entry by comparing the WCID/ACK/PID fields.
608 */
609 txwi = rt2800_drv_get_txwi(entry);
610
611 rt2x00_desc_read(txwi, 1, &word);
612 tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
613 tx_ack = rt2x00_get_field32(word, TXWI_W1_ACK);
614 tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID);
615
616 if ((wcid != tx_wcid) || (ack != tx_ack) || (pid != tx_pid)) {
617 WARNING(entry->queue->rt2x00dev,
618 "TX status report missed for queue %d entry %d\n",
619 entry->queue->qid, entry->entry_idx);
620 rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN);
621 return false;
622 }
623
624 return true;
625}
626
584void rt2800_txdone(struct rt2x00_dev *rt2x00dev) 627void rt2800_txdone(struct rt2x00_dev *rt2x00dev)
585{ 628{
586 struct data_queue *queue; 629 struct data_queue *queue;
@@ -589,8 +632,8 @@ void rt2800_txdone(struct rt2x00_dev *rt2x00dev)
589 struct txdone_entry_desc txdesc; 632 struct txdone_entry_desc txdesc;
590 u32 word; 633 u32 word;
591 u32 reg; 634 u32 reg;
592 int wcid, ack, pid, tx_wcid, tx_ack, tx_pid;
593 u16 mcs, real_mcs; 635 u16 mcs, real_mcs;
636 u8 pid;
594 int i; 637 int i;
595 638
596 /* 639 /*
@@ -607,18 +650,15 @@ void rt2800_txdone(struct rt2x00_dev *rt2x00dev)
607 if (!rt2x00_get_field32(reg, TX_STA_FIFO_VALID)) 650 if (!rt2x00_get_field32(reg, TX_STA_FIFO_VALID))
608 break; 651 break;
609 652
610 wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID);
611 ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED);
612 pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE);
613
614 /* 653 /*
615 * Skip this entry when it contains an invalid 654 * Skip this entry when it contains an invalid
616 * queue identication number. 655 * queue identication number.
617 */ 656 */
618 if (pid <= 0 || pid > QID_RX) 657 pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE) - 1;
658 if (pid >= QID_RX)
619 continue; 659 continue;
620 660
621 queue = rt2x00queue_get_queue(rt2x00dev, pid - 1); 661 queue = rt2x00queue_get_queue(rt2x00dev, pid);
622 if (unlikely(!queue)) 662 if (unlikely(!queue))
623 continue; 663 continue;
624 664
@@ -627,35 +667,22 @@ void rt2800_txdone(struct rt2x00_dev *rt2x00dev)
627 * order. We first check that the queue is not empty. 667 * order. We first check that the queue is not empty.
628 */ 668 */
629 entry = NULL; 669 entry = NULL;
670 txwi = NULL;
630 while (!rt2x00queue_empty(queue)) { 671 while (!rt2x00queue_empty(queue)) {
631 entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); 672 entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
632 if (!test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) 673 if (rt2800_txdone_entry_check(entry, reg))
633 break; 674 break;
634
635 rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
636 } 675 }
637 676
638 if (!entry || rt2x00queue_empty(queue)) 677 if (!entry || rt2x00queue_empty(queue))
639 break; 678 break;
640 679
641 /*
642 * Check if we got a match by looking at WCID/ACK/PID
643 * fields
644 */
645 txwi = rt2800_drv_get_txwi(entry);
646
647 rt2x00_desc_read(txwi, 1, &word);
648 tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
649 tx_ack = rt2x00_get_field32(word, TXWI_W1_ACK);
650 tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID);
651
652 if ((wcid != tx_wcid) || (ack != tx_ack) || (pid != tx_pid))
653 WARNING(rt2x00dev, "invalid TX_STA_FIFO content");
654 680
655 /* 681 /*
656 * Obtain the status about this packet. 682 * Obtain the status about this packet.
657 */ 683 */
658 txdesc.flags = 0; 684 txdesc.flags = 0;
685 txwi = rt2800_drv_get_txwi(entry);
659 rt2x00_desc_read(txwi, 0, &word); 686 rt2x00_desc_read(txwi, 0, &word);
660 mcs = rt2x00_get_field32(word, TXWI_W0_MCS); 687 mcs = rt2x00_get_field32(word, TXWI_W0_MCS);
661 real_mcs = rt2x00_get_field32(reg, TX_STA_FIFO_MCS); 688 real_mcs = rt2x00_get_field32(reg, TX_STA_FIFO_MCS);