diff options
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2800lib.c | 73 |
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 | } |
582 | EXPORT_SYMBOL_GPL(rt2800_process_rxwi); | 582 | EXPORT_SYMBOL_GPL(rt2800_process_rxwi); |
583 | 583 | ||
584 | static 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 | |||
584 | void rt2800_txdone(struct rt2x00_dev *rt2x00dev) | 627 | void 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); |