diff options
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2800lib.c | 82 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2800lib.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2800usb.c | 83 |
3 files changed, 82 insertions, 84 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index f0988d8736c3..75d2c6cc93eb 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c | |||
@@ -601,49 +601,6 @@ void rt2800_process_rxwi(struct queue_entry *entry, | |||
601 | } | 601 | } |
602 | EXPORT_SYMBOL_GPL(rt2800_process_rxwi); | 602 | EXPORT_SYMBOL_GPL(rt2800_process_rxwi); |
603 | 603 | ||
604 | static bool rt2800_txdone_entry_check(struct queue_entry *entry, u32 reg) | ||
605 | { | ||
606 | __le32 *txwi; | ||
607 | u32 word; | ||
608 | int wcid, ack, pid; | ||
609 | int tx_wcid, tx_ack, tx_pid; | ||
610 | |||
611 | wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID); | ||
612 | ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED); | ||
613 | pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE); | ||
614 | |||
615 | /* | ||
616 | * This frames has returned with an IO error, | ||
617 | * so the status report is not intended for this | ||
618 | * frame. | ||
619 | */ | ||
620 | if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) { | ||
621 | rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE); | ||
622 | return false; | ||
623 | } | ||
624 | |||
625 | /* | ||
626 | * Validate if this TX status report is intended for | ||
627 | * this entry by comparing the WCID/ACK/PID fields. | ||
628 | */ | ||
629 | txwi = rt2800_drv_get_txwi(entry); | ||
630 | |||
631 | rt2x00_desc_read(txwi, 1, &word); | ||
632 | tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID); | ||
633 | tx_ack = rt2x00_get_field32(word, TXWI_W1_ACK); | ||
634 | tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID); | ||
635 | |||
636 | if ((wcid != tx_wcid) || (ack != tx_ack) || (pid != tx_pid)) { | ||
637 | WARNING(entry->queue->rt2x00dev, | ||
638 | "TX status report missed for queue %d entry %d\n", | ||
639 | entry->queue->qid, entry->entry_idx); | ||
640 | rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN); | ||
641 | return false; | ||
642 | } | ||
643 | |||
644 | return true; | ||
645 | } | ||
646 | |||
647 | void rt2800_txdone_entry(struct queue_entry *entry, u32 status) | 604 | void rt2800_txdone_entry(struct queue_entry *entry, u32 status) |
648 | { | 605 | { |
649 | struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; | 606 | struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; |
@@ -726,45 +683,6 @@ void rt2800_txdone_entry(struct queue_entry *entry, u32 status) | |||
726 | } | 683 | } |
727 | EXPORT_SYMBOL_GPL(rt2800_txdone_entry); | 684 | EXPORT_SYMBOL_GPL(rt2800_txdone_entry); |
728 | 685 | ||
729 | void rt2800_txdone(struct rt2x00_dev *rt2x00dev) | ||
730 | { | ||
731 | struct data_queue *queue; | ||
732 | struct queue_entry *entry; | ||
733 | u32 reg; | ||
734 | u8 qid; | ||
735 | |||
736 | while (kfifo_get(&rt2x00dev->txstatus_fifo, ®)) { | ||
737 | |||
738 | /* TX_STA_FIFO_PID_QUEUE is a 2-bit field, thus | ||
739 | * qid is guaranteed to be one of the TX QIDs | ||
740 | */ | ||
741 | qid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE); | ||
742 | queue = rt2x00queue_get_tx_queue(rt2x00dev, qid); | ||
743 | if (unlikely(!queue)) { | ||
744 | WARNING(rt2x00dev, "Got TX status for an unavailable " | ||
745 | "queue %u, dropping\n", qid); | ||
746 | continue; | ||
747 | } | ||
748 | |||
749 | /* | ||
750 | * Inside each queue, we process each entry in a chronological | ||
751 | * order. We first check that the queue is not empty. | ||
752 | */ | ||
753 | entry = NULL; | ||
754 | while (!rt2x00queue_empty(queue)) { | ||
755 | entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); | ||
756 | if (rt2800_txdone_entry_check(entry, reg)) | ||
757 | break; | ||
758 | } | ||
759 | |||
760 | if (!entry || rt2x00queue_empty(queue)) | ||
761 | break; | ||
762 | |||
763 | rt2800_txdone_entry(entry, reg); | ||
764 | } | ||
765 | } | ||
766 | EXPORT_SYMBOL_GPL(rt2800_txdone); | ||
767 | |||
768 | void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc) | 686 | void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc) |
769 | { | 687 | { |
770 | struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; | 688 | struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; |
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index f2d15941c71a..69deb3148ae7 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h | |||
@@ -152,7 +152,6 @@ void rt2800_write_tx_data(struct queue_entry *entry, | |||
152 | struct txentry_desc *txdesc); | 152 | struct txentry_desc *txdesc); |
153 | void rt2800_process_rxwi(struct queue_entry *entry, struct rxdone_entry_desc *txdesc); | 153 | void rt2800_process_rxwi(struct queue_entry *entry, struct rxdone_entry_desc *txdesc); |
154 | 154 | ||
155 | void rt2800_txdone(struct rt2x00_dev *rt2x00dev); | ||
156 | void rt2800_txdone_entry(struct queue_entry *entry, u32 status); | 155 | void rt2800_txdone_entry(struct queue_entry *entry, u32 status); |
157 | 156 | ||
158 | void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc); | 157 | void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc); |
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index ba82c972703a..6e9229830a29 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c | |||
@@ -457,6 +457,87 @@ static int rt2800usb_get_tx_data_len(struct queue_entry *entry) | |||
457 | /* | 457 | /* |
458 | * TX control handlers | 458 | * TX control handlers |
459 | */ | 459 | */ |
460 | static bool rt2800usb_txdone_entry_check(struct queue_entry *entry, u32 reg) | ||
461 | { | ||
462 | __le32 *txwi; | ||
463 | u32 word; | ||
464 | int wcid, ack, pid; | ||
465 | int tx_wcid, tx_ack, tx_pid; | ||
466 | |||
467 | wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID); | ||
468 | ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED); | ||
469 | pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE); | ||
470 | |||
471 | /* | ||
472 | * This frames has returned with an IO error, | ||
473 | * so the status report is not intended for this | ||
474 | * frame. | ||
475 | */ | ||
476 | if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) { | ||
477 | rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE); | ||
478 | return false; | ||
479 | } | ||
480 | |||
481 | /* | ||
482 | * Validate if this TX status report is intended for | ||
483 | * this entry by comparing the WCID/ACK/PID fields. | ||
484 | */ | ||
485 | txwi = rt2800usb_get_txwi(entry); | ||
486 | |||
487 | rt2x00_desc_read(txwi, 1, &word); | ||
488 | tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID); | ||
489 | tx_ack = rt2x00_get_field32(word, TXWI_W1_ACK); | ||
490 | tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID); | ||
491 | |||
492 | if ((wcid != tx_wcid) || (ack != tx_ack) || (pid != tx_pid)) { | ||
493 | WARNING(entry->queue->rt2x00dev, | ||
494 | "TX status report missed for queue %d entry %d\n", | ||
495 | entry->queue->qid, entry->entry_idx); | ||
496 | rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN); | ||
497 | return false; | ||
498 | } | ||
499 | |||
500 | return true; | ||
501 | } | ||
502 | |||
503 | static void rt2800usb_txdone(struct rt2x00_dev *rt2x00dev) | ||
504 | { | ||
505 | struct data_queue *queue; | ||
506 | struct queue_entry *entry; | ||
507 | u32 reg; | ||
508 | u8 qid; | ||
509 | |||
510 | while (kfifo_get(&rt2x00dev->txstatus_fifo, ®)) { | ||
511 | |||
512 | /* TX_STA_FIFO_PID_QUEUE is a 2-bit field, thus | ||
513 | * qid is guaranteed to be one of the TX QIDs | ||
514 | */ | ||
515 | qid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE); | ||
516 | queue = rt2x00queue_get_tx_queue(rt2x00dev, qid); | ||
517 | if (unlikely(!queue)) { | ||
518 | WARNING(rt2x00dev, "Got TX status for an unavailable " | ||
519 | "queue %u, dropping\n", qid); | ||
520 | continue; | ||
521 | } | ||
522 | |||
523 | /* | ||
524 | * Inside each queue, we process each entry in a chronological | ||
525 | * order. We first check that the queue is not empty. | ||
526 | */ | ||
527 | entry = NULL; | ||
528 | while (!rt2x00queue_empty(queue)) { | ||
529 | entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); | ||
530 | if (rt2800usb_txdone_entry_check(entry, reg)) | ||
531 | break; | ||
532 | } | ||
533 | |||
534 | if (!entry || rt2x00queue_empty(queue)) | ||
535 | break; | ||
536 | |||
537 | rt2800_txdone_entry(entry, reg); | ||
538 | } | ||
539 | } | ||
540 | |||
460 | static void rt2800usb_work_txdone(struct work_struct *work) | 541 | static void rt2800usb_work_txdone(struct work_struct *work) |
461 | { | 542 | { |
462 | struct rt2x00_dev *rt2x00dev = | 543 | struct rt2x00_dev *rt2x00dev = |
@@ -464,7 +545,7 @@ static void rt2800usb_work_txdone(struct work_struct *work) | |||
464 | struct data_queue *queue; | 545 | struct data_queue *queue; |
465 | struct queue_entry *entry; | 546 | struct queue_entry *entry; |
466 | 547 | ||
467 | rt2800_txdone(rt2x00dev); | 548 | rt2800usb_txdone(rt2x00dev); |
468 | 549 | ||
469 | /* | 550 | /* |
470 | * Process any trailing TX status reports for IO failures, | 551 | * Process any trailing TX status reports for IO failures, |