aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.c150
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h17
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c34
3 files changed, 188 insertions, 13 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index 005ee153e0cc..3806454b827b 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -660,6 +660,63 @@ static void rt2800pci_wakeup(struct rt2x00_dev *rt2x00dev)
660 rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS); 660 rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS);
661} 661}
662 662
663static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
664{
665 struct data_queue *queue;
666 struct queue_entry *entry;
667 u32 status;
668 u8 qid;
669
670 while (!kfifo_is_empty(&rt2x00dev->txstatus_fifo)) {
671 /* Now remove the tx status from the FIFO */
672 if (kfifo_out(&rt2x00dev->txstatus_fifo, &status,
673 sizeof(status)) != sizeof(status)) {
674 WARN_ON(1);
675 break;
676 }
677
678 qid = rt2x00_get_field32(status, TX_STA_FIFO_PID_TYPE) - 1;
679 if (qid >= QID_RX) {
680 /*
681 * Unknown queue, this shouldn't happen. Just drop
682 * this tx status.
683 */
684 WARNING(rt2x00dev, "Got TX status report with "
685 "unexpected pid %u, dropping", qid);
686 break;
687 }
688
689 queue = rt2x00queue_get_queue(rt2x00dev, qid);
690 if (unlikely(queue == NULL)) {
691 /*
692 * The queue is NULL, this shouldn't happen. Stop
693 * processing here and drop the tx status
694 */
695 WARNING(rt2x00dev, "Got TX status for an unavailable "
696 "queue %u, dropping", qid);
697 break;
698 }
699
700 if (rt2x00queue_empty(queue)) {
701 /*
702 * The queue is empty. Stop processing here
703 * and drop the tx status.
704 */
705 WARNING(rt2x00dev, "Got TX status for an empty "
706 "queue %u, dropping", qid);
707 break;
708 }
709
710 entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
711 rt2800_txdone_entry(entry, status);
712 }
713}
714
715static void rt2800pci_txstatus_tasklet(unsigned long data)
716{
717 rt2800pci_txdone((struct rt2x00_dev *)data);
718}
719
663static irqreturn_t rt2800pci_interrupt_thread(int irq, void *dev_instance) 720static irqreturn_t rt2800pci_interrupt_thread(int irq, void *dev_instance)
664{ 721{
665 struct rt2x00_dev *rt2x00dev = dev_instance; 722 struct rt2x00_dev *rt2x00dev = dev_instance;
@@ -684,13 +741,7 @@ static irqreturn_t rt2800pci_interrupt_thread(int irq, void *dev_instance)
684 rt2x00pci_rxdone(rt2x00dev); 741 rt2x00pci_rxdone(rt2x00dev);
685 742
686 /* 743 /*
687 * 4 - Tx done interrupt. 744 * 4 - Auto wakeup interrupt.
688 */
689 if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS))
690 rt2800_txdone(rt2x00dev);
691
692 /*
693 * 5 - Auto wakeup interrupt.
694 */ 745 */
695 if (rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP)) 746 if (rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP))
696 rt2800pci_wakeup(rt2x00dev); 747 rt2800pci_wakeup(rt2x00dev);
@@ -702,10 +753,58 @@ static irqreturn_t rt2800pci_interrupt_thread(int irq, void *dev_instance)
702 return IRQ_HANDLED; 753 return IRQ_HANDLED;
703} 754}
704 755
756static void rt2800pci_txstatus_interrupt(struct rt2x00_dev *rt2x00dev)
757{
758 u32 status;
759 int i;
760
761 /*
762 * The TX_FIFO_STATUS interrupt needs special care. We should
763 * read TX_STA_FIFO but we should do it immediately as otherwise
764 * the register can overflow and we would lose status reports.
765 *
766 * Hence, read the TX_STA_FIFO register and copy all tx status
767 * reports into a kernel FIFO which is handled in the txstatus
768 * tasklet. We use a tasklet to process the tx status reports
769 * because we can schedule the tasklet multiple times (when the
770 * interrupt fires again during tx status processing).
771 *
772 * Furthermore we don't disable the TX_FIFO_STATUS
773 * interrupt here but leave it enabled so that the TX_STA_FIFO
774 * can also be read while the interrupt thread gets executed.
775 *
776 * Since we have only one producer and one consumer we don't
777 * need to lock the kfifo.
778 */
779 for (i = 0; i < TX_ENTRIES; i++) {
780 rt2800_register_read(rt2x00dev, TX_STA_FIFO, &status);
781
782 if (!rt2x00_get_field32(status, TX_STA_FIFO_VALID))
783 break;
784
785 if (kfifo_is_full(&rt2x00dev->txstatus_fifo)) {
786 WARNING(rt2x00dev, "TX status FIFO overrun,"
787 " drop tx status report.\n");
788 break;
789 }
790
791 if (kfifo_in(&rt2x00dev->txstatus_fifo, &status,
792 sizeof(status)) != sizeof(status)) {
793 WARNING(rt2x00dev, "TX status FIFO overrun,"
794 "drop tx status report.\n");
795 break;
796 }
797 }
798
799 /* Schedule the tasklet for processing the tx status. */
800 tasklet_schedule(&rt2x00dev->txstatus_tasklet);
801}
802
705static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance) 803static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
706{ 804{
707 struct rt2x00_dev *rt2x00dev = dev_instance; 805 struct rt2x00_dev *rt2x00dev = dev_instance;
708 u32 reg; 806 u32 reg;
807 irqreturn_t ret = IRQ_HANDLED;
709 808
710 /* Read status and ACK all interrupts */ 809 /* Read status and ACK all interrupts */
711 rt2800_register_read(rt2x00dev, INT_SOURCE_CSR, &reg); 810 rt2800_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
@@ -717,15 +816,38 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
717 if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) 816 if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
718 return IRQ_HANDLED; 817 return IRQ_HANDLED;
719 818
720 /* Store irqvalue for use in the interrupt thread. */ 819 if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS))
721 rt2x00dev->irqvalue[0] = reg; 820 rt2800pci_txstatus_interrupt(rt2x00dev);
821
822 if (rt2x00_get_field32(reg, INT_SOURCE_CSR_PRE_TBTT) ||
823 rt2x00_get_field32(reg, INT_SOURCE_CSR_TBTT) ||
824 rt2x00_get_field32(reg, INT_SOURCE_CSR_RX_DONE) ||
825 rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP)) {
826 /*
827 * All other interrupts are handled in the interrupt thread.
828 * Store irqvalue for use in the interrupt thread.
829 */
830 rt2x00dev->irqvalue[0] = reg;
722 831
723 /* Disable interrupts, will be enabled again in the interrupt thread. */ 832 /*
724 rt2x00dev->ops->lib->set_device_state(rt2x00dev, 833 * Disable interrupts, will be enabled again in the
725 STATE_RADIO_IRQ_OFF_ISR); 834 * interrupt thread.
835 */
836 rt2x00dev->ops->lib->set_device_state(rt2x00dev,
837 STATE_RADIO_IRQ_OFF_ISR);
726 838
839 /*
840 * Leave the TX_FIFO_STATUS interrupt enabled to not lose any
841 * tx status reports.
842 */
843 rt2800_register_read(rt2x00dev, INT_MASK_CSR, &reg);
844 rt2x00_set_field32(&reg, INT_MASK_CSR_TX_FIFO_STATUS, 1);
845 rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg);
727 846
728 return IRQ_WAKE_THREAD; 847 ret = IRQ_WAKE_THREAD;
848 }
849
850 return ret;
729} 851}
730 852
731/* 853/*
@@ -788,6 +910,7 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
788 __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); 910 __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
789 __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags); 911 __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
790 __set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags); 912 __set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags);
913 __set_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags);
791 if (!modparam_nohwcrypt) 914 if (!modparam_nohwcrypt)
792 __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); 915 __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
793 __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags); 916 __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
@@ -837,6 +960,7 @@ static const struct rt2800_ops rt2800pci_rt2800_ops = {
837static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = { 960static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
838 .irq_handler = rt2800pci_interrupt, 961 .irq_handler = rt2800pci_interrupt,
839 .irq_handler_thread = rt2800pci_interrupt_thread, 962 .irq_handler_thread = rt2800pci_interrupt_thread,
963 .txstatus_tasklet = rt2800pci_txstatus_tasklet,
840 .probe_hw = rt2800pci_probe_hw, 964 .probe_hw = rt2800pci_probe_hw,
841 .get_firmware_name = rt2800pci_get_firmware_name, 965 .get_firmware_name = rt2800pci_get_firmware_name,
842 .check_firmware = rt2800_check_firmware, 966 .check_firmware = rt2800_check_firmware,
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 7832a5996a8c..bab10adae537 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -36,6 +36,7 @@
36#include <linux/mutex.h> 36#include <linux/mutex.h>
37#include <linux/etherdevice.h> 37#include <linux/etherdevice.h>
38#include <linux/input-polldev.h> 38#include <linux/input-polldev.h>
39#include <linux/kfifo.h>
39 40
40#include <net/mac80211.h> 41#include <net/mac80211.h>
41 42
@@ -522,6 +523,11 @@ struct rt2x00lib_ops {
522 irq_handler_t irq_handler_thread; 523 irq_handler_t irq_handler_thread;
523 524
524 /* 525 /*
526 * TX status tasklet handler.
527 */
528 void (*txstatus_tasklet) (unsigned long data);
529
530 /*
525 * Device init handlers. 531 * Device init handlers.
526 */ 532 */
527 int (*probe_hw) (struct rt2x00_dev *rt2x00dev); 533 int (*probe_hw) (struct rt2x00_dev *rt2x00dev);
@@ -651,6 +657,7 @@ enum rt2x00_flags {
651 DRIVER_REQUIRE_DMA, 657 DRIVER_REQUIRE_DMA,
652 DRIVER_REQUIRE_COPY_IV, 658 DRIVER_REQUIRE_COPY_IV,
653 DRIVER_REQUIRE_L2PAD, 659 DRIVER_REQUIRE_L2PAD,
660 DRIVER_REQUIRE_TXSTATUS_FIFO,
654 661
655 /* 662 /*
656 * Driver features 663 * Driver features
@@ -884,6 +891,16 @@ struct rt2x00_dev {
884 * and interrupt thread routine. 891 * and interrupt thread routine.
885 */ 892 */
886 u32 irqvalue[2]; 893 u32 irqvalue[2];
894
895 /*
896 * FIFO for storing tx status reports between isr and tasklet.
897 */
898 struct kfifo txstatus_fifo;
899
900 /*
901 * Tasklet for processing tx status reports (rt2800pci).
902 */
903 struct tasklet_struct txstatus_tasklet;
887}; 904};
888 905
889/* 906/*
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 053fdd3bd720..b03e6e41dc1e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -813,6 +813,30 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
813 rt2x00dev->hw->extra_tx_headroom += RT2X00_ALIGN_SIZE; 813 rt2x00dev->hw->extra_tx_headroom += RT2X00_ALIGN_SIZE;
814 814
815 /* 815 /*
816 * Allocate tx status FIFO for driver use.
817 */
818 if (test_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags) &&
819 rt2x00dev->ops->lib->txstatus_tasklet) {
820 /*
821 * Allocate txstatus fifo and tasklet, we use a size of 512
822 * for the kfifo which is big enough to store 512/4=128 tx
823 * status reports. In the worst case (tx status for all tx
824 * queues gets reported before we've got a chance to handle
825 * them) 24*4=384 tx status reports need to be cached.
826 */
827 status = kfifo_alloc(&rt2x00dev->txstatus_fifo, 512,
828 GFP_KERNEL);
829 if (status)
830 return status;
831
832 /* tasklet for processing the tx status reports. */
833 tasklet_init(&rt2x00dev->txstatus_tasklet,
834 rt2x00dev->ops->lib->txstatus_tasklet,
835 (unsigned long)rt2x00dev);
836
837 }
838
839 /*
816 * Register HW. 840 * Register HW.
817 */ 841 */
818 status = ieee80211_register_hw(rt2x00dev->hw); 842 status = ieee80211_register_hw(rt2x00dev->hw);
@@ -1028,6 +1052,16 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
1028 cancel_work_sync(&rt2x00dev->txdone_work); 1052 cancel_work_sync(&rt2x00dev->txdone_work);
1029 1053
1030 /* 1054 /*
1055 * Free the tx status fifo.
1056 */
1057 kfifo_free(&rt2x00dev->txstatus_fifo);
1058
1059 /*
1060 * Kill the tx status tasklet.
1061 */
1062 tasklet_kill(&rt2x00dev->txstatus_tasklet);
1063
1064 /*
1031 * Uninitialize device. 1065 * Uninitialize device.
1032 */ 1066 */
1033 rt2x00lib_uninitialize(rt2x00dev); 1067 rt2x00lib_uninitialize(rt2x00dev);