aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHelmut Schaa <helmut.schaa@googlemail.com>2011-01-30 07:18:38 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-01-31 15:06:23 -0500
commita9d61e9e779579c66c0d4c8af203d51dbca1473c (patch)
tree05f2923aa5c397f605ea4ef0c819e043cb797521
parentc8e15a1e2c93880160f31ed2e6b02c1322f7f48d (diff)
rt2x00: Convert rt2800pci to use tasklets
Fix interrupt processing on slow machines by using individual tasklets for each different device interrupt. This ensures that while a RX or TX status tasklet is scheduled only the according device interrupt is masked and other interrupts such as TBTT can still be processed. Also, this allows us to use tasklet_hi_schedule for TBTT and PRETBTT processing which is required to not send out beacons with a wrong DTIM count (due to delayed periodic beacon updates). Furthermore, this improves the latency between the TBTT and sending out buffered multi- and broadcast traffic. As a nice bonus, the interrupt handling overhead is reduced such that rt2800pci gains around 25% more throuhput on a rt3052 MIPS board. Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com> Acked-by: Gertjan van Wingerde <gwingerde@gmail.com> Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.c173
1 files changed, 114 insertions, 59 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index e4d97ad25bf4..31483c79a457 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -200,6 +200,13 @@ static void rt2800pci_start_queue(struct data_queue *queue)
200 rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); 200 rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
201 break; 201 break;
202 case QID_BEACON: 202 case QID_BEACON:
203 /*
204 * Allow beacon tasklets to be scheduled for periodic
205 * beacon updates.
206 */
207 tasklet_enable(&rt2x00dev->tbtt_tasklet);
208 tasklet_enable(&rt2x00dev->pretbtt_tasklet);
209
203 rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg); 210 rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
204 rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1); 211 rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
205 rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1); 212 rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
@@ -258,6 +265,12 @@ static void rt2800pci_stop_queue(struct data_queue *queue)
258 rt2800_register_read(rt2x00dev, INT_TIMER_EN, &reg); 265 rt2800_register_read(rt2x00dev, INT_TIMER_EN, &reg);
259 rt2x00_set_field32(&reg, INT_TIMER_EN_PRE_TBTT_TIMER, 0); 266 rt2x00_set_field32(&reg, INT_TIMER_EN_PRE_TBTT_TIMER, 0);
260 rt2800_register_write(rt2x00dev, INT_TIMER_EN, reg); 267 rt2800_register_write(rt2x00dev, INT_TIMER_EN, reg);
268
269 /*
270 * Wait for tbtt tasklets to finish.
271 */
272 tasklet_disable(&rt2x00dev->tbtt_tasklet);
273 tasklet_disable(&rt2x00dev->pretbtt_tasklet);
261 break; 274 break;
262 default: 275 default:
263 break; 276 break;
@@ -408,6 +421,7 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
408 int mask = (state == STATE_RADIO_IRQ_ON) || 421 int mask = (state == STATE_RADIO_IRQ_ON) ||
409 (state == STATE_RADIO_IRQ_ON_ISR); 422 (state == STATE_RADIO_IRQ_ON_ISR);
410 u32 reg; 423 u32 reg;
424 unsigned long flags;
411 425
412 /* 426 /*
413 * When interrupts are being enabled, the interrupt registers 427 * When interrupts are being enabled, the interrupt registers
@@ -417,10 +431,16 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
417 rt2800_register_read(rt2x00dev, INT_SOURCE_CSR, &reg); 431 rt2800_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
418 rt2800_register_write(rt2x00dev, INT_SOURCE_CSR, reg); 432 rt2800_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
419 433
434 /*
435 * Enable tasklets. The beacon related tasklets are
436 * enabled when the beacon queue is started.
437 */
420 tasklet_enable(&rt2x00dev->txstatus_tasklet); 438 tasklet_enable(&rt2x00dev->txstatus_tasklet);
421 } else if (state == STATE_RADIO_IRQ_OFF) 439 tasklet_enable(&rt2x00dev->rxdone_tasklet);
422 tasklet_disable(&rt2x00dev->txstatus_tasklet); 440 tasklet_enable(&rt2x00dev->autowake_tasklet);
441 }
423 442
443 spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
424 rt2800_register_read(rt2x00dev, INT_MASK_CSR, &reg); 444 rt2800_register_read(rt2x00dev, INT_MASK_CSR, &reg);
425 rt2x00_set_field32(&reg, INT_MASK_CSR_RXDELAYINT, 0); 445 rt2x00_set_field32(&reg, INT_MASK_CSR_RXDELAYINT, 0);
426 rt2x00_set_field32(&reg, INT_MASK_CSR_TXDELAYINT, 0); 446 rt2x00_set_field32(&reg, INT_MASK_CSR_TXDELAYINT, 0);
@@ -441,6 +461,17 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
441 rt2x00_set_field32(&reg, INT_MASK_CSR_RX_COHERENT, 0); 461 rt2x00_set_field32(&reg, INT_MASK_CSR_RX_COHERENT, 0);
442 rt2x00_set_field32(&reg, INT_MASK_CSR_TX_COHERENT, 0); 462 rt2x00_set_field32(&reg, INT_MASK_CSR_TX_COHERENT, 0);
443 rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg); 463 rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg);
464 spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
465
466 if (state == STATE_RADIO_IRQ_OFF) {
467 /*
468 * Ensure that all tasklets are finished before
469 * disabling the interrupts.
470 */
471 tasklet_disable(&rt2x00dev->txstatus_tasklet);
472 tasklet_disable(&rt2x00dev->rxdone_tasklet);
473 tasklet_disable(&rt2x00dev->autowake_tasklet);
474 }
444} 475}
445 476
446static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev) 477static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev)
@@ -721,45 +752,60 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
721 } 752 }
722} 753}
723 754
724static void rt2800pci_txstatus_tasklet(unsigned long data) 755static void rt2800pci_enable_interrupt(struct rt2x00_dev *rt2x00dev,
725{ 756 struct rt2x00_field32 irq_field)
726 rt2800pci_txdone((struct rt2x00_dev *)data);
727}
728
729static irqreturn_t rt2800pci_interrupt_thread(int irq, void *dev_instance)
730{ 757{
731 struct rt2x00_dev *rt2x00dev = dev_instance; 758 unsigned long flags;
732 u32 reg = rt2x00dev->irqvalue[0]; 759 u32 reg;
733 760
734 /* 761 /*
735 * 1 - Pre TBTT interrupt. 762 * Enable a single interrupt. The interrupt mask register
763 * access needs locking.
736 */ 764 */
737 if (rt2x00_get_field32(reg, INT_SOURCE_CSR_PRE_TBTT)) 765 spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
738 rt2x00lib_pretbtt(rt2x00dev); 766 rt2800_register_read(rt2x00dev, INT_MASK_CSR, &reg);
767 rt2x00_set_field32(&reg, irq_field, 1);
768 rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg);
769 spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
770}
739 771
740 /* 772static void rt2800pci_txstatus_tasklet(unsigned long data)
741 * 2 - Beacondone interrupt. 773{
742 */ 774 rt2800pci_txdone((struct rt2x00_dev *)data);
743 if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TBTT))
744 rt2x00lib_beacondone(rt2x00dev);
745 775
746 /* 776 /*
747 * 3 - Rx ring done interrupt. 777 * No need to enable the tx status interrupt here as we always
778 * leave it enabled to minimize the possibility of a tx status
779 * register overflow. See comment in interrupt handler.
748 */ 780 */
749 if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RX_DONE)) 781}
750 rt2x00pci_rxdone(rt2x00dev);
751 782
752 /* 783static void rt2800pci_pretbtt_tasklet(unsigned long data)
753 * 4 - Auto wakeup interrupt. 784{
754 */ 785 struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
755 if (rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP)) 786 rt2x00lib_pretbtt(rt2x00dev);
756 rt2800pci_wakeup(rt2x00dev); 787 rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_PRE_TBTT);
788}
757 789
758 /* Enable interrupts again. */ 790static void rt2800pci_tbtt_tasklet(unsigned long data)
759 rt2x00dev->ops->lib->set_device_state(rt2x00dev, 791{
760 STATE_RADIO_IRQ_ON_ISR); 792 struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
793 rt2x00lib_beacondone(rt2x00dev);
794 rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_TBTT);
795}
761 796
762 return IRQ_HANDLED; 797static void rt2800pci_rxdone_tasklet(unsigned long data)
798{
799 struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
800 rt2x00pci_rxdone(rt2x00dev);
801 rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RX_DONE);
802}
803
804static void rt2800pci_autowake_tasklet(unsigned long data)
805{
806 struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
807 rt2800pci_wakeup(rt2x00dev);
808 rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_AUTO_WAKEUP);
763} 809}
764 810
765static void rt2800pci_txstatus_interrupt(struct rt2x00_dev *rt2x00dev) 811static void rt2800pci_txstatus_interrupt(struct rt2x00_dev *rt2x00dev)
@@ -805,8 +851,8 @@ static void rt2800pci_txstatus_interrupt(struct rt2x00_dev *rt2x00dev)
805static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance) 851static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
806{ 852{
807 struct rt2x00_dev *rt2x00dev = dev_instance; 853 struct rt2x00_dev *rt2x00dev = dev_instance;
808 u32 reg; 854 u32 reg, mask;
809 irqreturn_t ret = IRQ_HANDLED; 855 unsigned long flags;
810 856
811 /* Read status and ACK all interrupts */ 857 /* Read status and ACK all interrupts */
812 rt2800_register_read(rt2x00dev, INT_SOURCE_CSR, &reg); 858 rt2800_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
@@ -818,38 +864,44 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
818 if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) 864 if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
819 return IRQ_HANDLED; 865 return IRQ_HANDLED;
820 866
821 if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) 867 /*
822 rt2800pci_txstatus_interrupt(rt2x00dev); 868 * Since INT_MASK_CSR and INT_SOURCE_CSR use the same bits
869 * for interrupts and interrupt masks we can just use the value of
870 * INT_SOURCE_CSR to create the interrupt mask.
871 */
872 mask = ~reg;
823 873
824 if (rt2x00_get_field32(reg, INT_SOURCE_CSR_PRE_TBTT) || 874 if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) {
825 rt2x00_get_field32(reg, INT_SOURCE_CSR_TBTT) || 875 rt2800pci_txstatus_interrupt(rt2x00dev);
826 rt2x00_get_field32(reg, INT_SOURCE_CSR_RX_DONE) ||
827 rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP)) {
828 /* 876 /*
829 * All other interrupts are handled in the interrupt thread. 877 * Never disable the TX_FIFO_STATUS interrupt.
830 * Store irqvalue for use in the interrupt thread.
831 */ 878 */
832 rt2x00dev->irqvalue[0] = reg; 879 rt2x00_set_field32(&mask, INT_MASK_CSR_TX_FIFO_STATUS, 1);
880 }
833 881
834 /* 882 if (rt2x00_get_field32(reg, INT_SOURCE_CSR_PRE_TBTT))
835 * Disable interrupts, will be enabled again in the 883 tasklet_hi_schedule(&rt2x00dev->pretbtt_tasklet);
836 * interrupt thread.
837 */
838 rt2x00dev->ops->lib->set_device_state(rt2x00dev,
839 STATE_RADIO_IRQ_OFF_ISR);
840 884
841 /* 885 if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TBTT))
842 * Leave the TX_FIFO_STATUS interrupt enabled to not lose any 886 tasklet_hi_schedule(&rt2x00dev->tbtt_tasklet);
843 * tx status reports.
844 */
845 rt2800_register_read(rt2x00dev, INT_MASK_CSR, &reg);
846 rt2x00_set_field32(&reg, INT_MASK_CSR_TX_FIFO_STATUS, 1);
847 rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg);
848 887
849 ret = IRQ_WAKE_THREAD; 888 if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RX_DONE))
850 } 889 tasklet_schedule(&rt2x00dev->rxdone_tasklet);
851 890
852 return ret; 891 if (rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP))
892 tasklet_schedule(&rt2x00dev->autowake_tasklet);
893
894 /*
895 * Disable all interrupts for which a tasklet was scheduled right now,
896 * the tasklet will reenable the appropriate interrupts.
897 */
898 spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
899 rt2800_register_read(rt2x00dev, INT_MASK_CSR, &reg);
900 reg &= mask;
901 rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg);
902 spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
903
904 return IRQ_HANDLED;
853} 905}
854 906
855/* 907/*
@@ -964,8 +1016,11 @@ static const struct rt2800_ops rt2800pci_rt2800_ops = {
964 1016
965static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = { 1017static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
966 .irq_handler = rt2800pci_interrupt, 1018 .irq_handler = rt2800pci_interrupt,
967 .irq_handler_thread = rt2800pci_interrupt_thread, 1019 .txstatus_tasklet = rt2800pci_txstatus_tasklet,
968 .txstatus_tasklet = rt2800pci_txstatus_tasklet, 1020 .pretbtt_tasklet = rt2800pci_pretbtt_tasklet,
1021 .tbtt_tasklet = rt2800pci_tbtt_tasklet,
1022 .rxdone_tasklet = rt2800pci_rxdone_tasklet,
1023 .autowake_tasklet = rt2800pci_autowake_tasklet,
969 .probe_hw = rt2800pci_probe_hw, 1024 .probe_hw = rt2800pci_probe_hw,
970 .get_firmware_name = rt2800pci_get_firmware_name, 1025 .get_firmware_name = rt2800pci_get_firmware_name,
971 .check_firmware = rt2800_check_firmware, 1026 .check_firmware = rt2800_check_firmware,