diff options
author | Felix Fietkau <nbd@openwrt.org> | 2010-11-08 14:54:47 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-11-09 16:13:24 -0500 |
commit | 4df3071ebd92ef7115b409da64d0eb405d24a631 (patch) | |
tree | 825eaecb9d9e8d0fde7f61e5f98fdd823ccef718 /drivers/net | |
parent | 790a11f268373b60069bc1371dc05143107c607c (diff) |
ath9k_hw: optimize interrupt mask changes
OProfile showed that ath9k was spending way too much time in
ath9k_hw_set_interrupts. Since most of the interrupt mask changes only
need to globally enable/disable interrupts, it makes sense to split
this part into separate functions, replacing all calls to
ath9k_hw_set_interrupts(ah, 0) with ath9k_hw_disable_interrupts(ah).
ath9k_hw_set_interrupts(ah, ah->imask) only gets changed to
ath9k_hw_enable_interrupts(ah), whenever ah->imask was not changed
since the point where interrupts were disabled.
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/beacon.c | 6 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/gpio.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/mac.c | 86 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/mac.h | 6 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 18 |
5 files changed, 68 insertions, 52 deletions
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 19891e7d49a..333da7bf2d7 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c | |||
@@ -503,7 +503,7 @@ static void ath_beacon_config_ap(struct ath_softc *sc, | |||
503 | 503 | ||
504 | /* Set the computed AP beacon timers */ | 504 | /* Set the computed AP beacon timers */ |
505 | 505 | ||
506 | ath9k_hw_set_interrupts(ah, 0); | 506 | ath9k_hw_disable_interrupts(ah); |
507 | ath9k_beacon_init(sc, nexttbtt, intval); | 507 | ath9k_beacon_init(sc, nexttbtt, intval); |
508 | sc->beacon.bmisscnt = 0; | 508 | sc->beacon.bmisscnt = 0; |
509 | ath9k_hw_set_interrupts(ah, ah->imask); | 509 | ath9k_hw_set_interrupts(ah, ah->imask); |
@@ -638,7 +638,7 @@ static void ath_beacon_config_sta(struct ath_softc *sc, | |||
638 | 638 | ||
639 | /* Set the computed STA beacon timers */ | 639 | /* Set the computed STA beacon timers */ |
640 | 640 | ||
641 | ath9k_hw_set_interrupts(ah, 0); | 641 | ath9k_hw_disable_interrupts(ah); |
642 | ath9k_hw_set_sta_beacon_timers(ah, &bs); | 642 | ath9k_hw_set_sta_beacon_timers(ah, &bs); |
643 | ah->imask |= ATH9K_INT_BMISS; | 643 | ah->imask |= ATH9K_INT_BMISS; |
644 | ath9k_hw_set_interrupts(ah, ah->imask); | 644 | ath9k_hw_set_interrupts(ah, ah->imask); |
@@ -686,7 +686,7 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, | |||
686 | 686 | ||
687 | /* Set the computed ADHOC beacon timers */ | 687 | /* Set the computed ADHOC beacon timers */ |
688 | 688 | ||
689 | ath9k_hw_set_interrupts(ah, 0); | 689 | ath9k_hw_disable_interrupts(ah); |
690 | ath9k_beacon_init(sc, nexttbtt, intval); | 690 | ath9k_beacon_init(sc, nexttbtt, intval); |
691 | sc->beacon.bmisscnt = 0; | 691 | sc->beacon.bmisscnt = 0; |
692 | ath9k_hw_set_interrupts(ah, ah->imask); | 692 | ath9k_hw_set_interrupts(ah, ah->imask); |
diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index 4a9a68bba32..db9c6fed799 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c | |||
@@ -259,7 +259,7 @@ static void ath9k_gen_timer_start(struct ath_hw *ah, | |||
259 | ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period); | 259 | ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period); |
260 | 260 | ||
261 | if ((ah->imask & ATH9K_INT_GENTIMER) == 0) { | 261 | if ((ah->imask & ATH9K_INT_GENTIMER) == 0) { |
262 | ath9k_hw_set_interrupts(ah, 0); | 262 | ath9k_hw_disable_interrupts(ah); |
263 | ah->imask |= ATH9K_INT_GENTIMER; | 263 | ah->imask |= ATH9K_INT_GENTIMER; |
264 | ath9k_hw_set_interrupts(ah, ah->imask); | 264 | ath9k_hw_set_interrupts(ah, ah->imask); |
265 | } | 265 | } |
@@ -273,7 +273,7 @@ static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) | |||
273 | 273 | ||
274 | /* if no timer is enabled, turn off interrupt mask */ | 274 | /* if no timer is enabled, turn off interrupt mask */ |
275 | if (timer_table->timer_mask.val == 0) { | 275 | if (timer_table->timer_mask.val == 0) { |
276 | ath9k_hw_set_interrupts(ah, 0); | 276 | ath9k_hw_disable_interrupts(ah); |
277 | ah->imask &= ~ATH9K_INT_GENTIMER; | 277 | ah->imask &= ~ATH9K_INT_GENTIMER; |
278 | ath9k_hw_set_interrupts(ah, ah->imask); | 278 | ath9k_hw_set_interrupts(ah, ah->imask); |
279 | } | 279 | } |
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 8c13479b17c..65b1ee2a979 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c | |||
@@ -117,12 +117,11 @@ EXPORT_SYMBOL(ath9k_hw_numtxpending); | |||
117 | bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel) | 117 | bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel) |
118 | { | 118 | { |
119 | u32 txcfg, curLevel, newLevel; | 119 | u32 txcfg, curLevel, newLevel; |
120 | enum ath9k_int omask; | ||
121 | 120 | ||
122 | if (ah->tx_trig_level >= ah->config.max_txtrig_level) | 121 | if (ah->tx_trig_level >= ah->config.max_txtrig_level) |
123 | return false; | 122 | return false; |
124 | 123 | ||
125 | omask = ath9k_hw_set_interrupts(ah, ah->imask & ~ATH9K_INT_GLOBAL); | 124 | ath9k_hw_disable_interrupts(ah); |
126 | 125 | ||
127 | txcfg = REG_READ(ah, AR_TXCFG); | 126 | txcfg = REG_READ(ah, AR_TXCFG); |
128 | curLevel = MS(txcfg, AR_FTRIG); | 127 | curLevel = MS(txcfg, AR_FTRIG); |
@@ -136,7 +135,7 @@ bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel) | |||
136 | REG_WRITE(ah, AR_TXCFG, | 135 | REG_WRITE(ah, AR_TXCFG, |
137 | (txcfg & ~AR_FTRIG) | SM(newLevel, AR_FTRIG)); | 136 | (txcfg & ~AR_FTRIG) | SM(newLevel, AR_FTRIG)); |
138 | 137 | ||
139 | ath9k_hw_set_interrupts(ah, omask); | 138 | ath9k_hw_enable_interrupts(ah); |
140 | 139 | ||
141 | ah->tx_trig_level = newLevel; | 140 | ah->tx_trig_level = newLevel; |
142 | 141 | ||
@@ -849,28 +848,59 @@ bool ath9k_hw_intrpend(struct ath_hw *ah) | |||
849 | } | 848 | } |
850 | EXPORT_SYMBOL(ath9k_hw_intrpend); | 849 | EXPORT_SYMBOL(ath9k_hw_intrpend); |
851 | 850 | ||
852 | enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, | 851 | void ath9k_hw_disable_interrupts(struct ath_hw *ah) |
853 | enum ath9k_int ints) | 852 | { |
853 | struct ath_common *common = ath9k_hw_common(ah); | ||
854 | |||
855 | ath_print(common, ATH_DBG_INTERRUPT, "disable IER\n"); | ||
856 | REG_WRITE(ah, AR_IER, AR_IER_DISABLE); | ||
857 | (void) REG_READ(ah, AR_IER); | ||
858 | if (!AR_SREV_9100(ah)) { | ||
859 | REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, 0); | ||
860 | (void) REG_READ(ah, AR_INTR_ASYNC_ENABLE); | ||
861 | |||
862 | REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0); | ||
863 | (void) REG_READ(ah, AR_INTR_SYNC_ENABLE); | ||
864 | } | ||
865 | } | ||
866 | EXPORT_SYMBOL(ath9k_hw_disable_interrupts); | ||
867 | |||
868 | void ath9k_hw_enable_interrupts(struct ath_hw *ah) | ||
869 | { | ||
870 | struct ath_common *common = ath9k_hw_common(ah); | ||
871 | |||
872 | if (!(ah->imask & ATH9K_INT_GLOBAL)) | ||
873 | return; | ||
874 | |||
875 | ath_print(common, ATH_DBG_INTERRUPT, "enable IER\n"); | ||
876 | REG_WRITE(ah, AR_IER, AR_IER_ENABLE); | ||
877 | if (!AR_SREV_9100(ah)) { | ||
878 | REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, | ||
879 | AR_INTR_MAC_IRQ); | ||
880 | REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ); | ||
881 | |||
882 | |||
883 | REG_WRITE(ah, AR_INTR_SYNC_ENABLE, | ||
884 | AR_INTR_SYNC_DEFAULT); | ||
885 | REG_WRITE(ah, AR_INTR_SYNC_MASK, | ||
886 | AR_INTR_SYNC_DEFAULT); | ||
887 | } | ||
888 | ath_print(common, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n", | ||
889 | REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER)); | ||
890 | } | ||
891 | EXPORT_SYMBOL(ath9k_hw_enable_interrupts); | ||
892 | |||
893 | void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) | ||
854 | { | 894 | { |
855 | enum ath9k_int omask = ah->imask; | 895 | enum ath9k_int omask = ah->imask; |
856 | u32 mask, mask2; | 896 | u32 mask, mask2; |
857 | struct ath9k_hw_capabilities *pCap = &ah->caps; | 897 | struct ath9k_hw_capabilities *pCap = &ah->caps; |
858 | struct ath_common *common = ath9k_hw_common(ah); | 898 | struct ath_common *common = ath9k_hw_common(ah); |
859 | 899 | ||
860 | ath_print(common, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints); | 900 | if (!(ints & ATH9K_INT_GLOBAL)) |
861 | 901 | ath9k_hw_enable_interrupts(ah); | |
862 | if (omask & ATH9K_INT_GLOBAL) { | ||
863 | ath_print(common, ATH_DBG_INTERRUPT, "disable IER\n"); | ||
864 | REG_WRITE(ah, AR_IER, AR_IER_DISABLE); | ||
865 | (void) REG_READ(ah, AR_IER); | ||
866 | if (!AR_SREV_9100(ah)) { | ||
867 | REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, 0); | ||
868 | (void) REG_READ(ah, AR_INTR_ASYNC_ENABLE); | ||
869 | 902 | ||
870 | REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0); | 903 | ath_print(common, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints); |
871 | (void) REG_READ(ah, AR_INTR_SYNC_ENABLE); | ||
872 | } | ||
873 | } | ||
874 | 904 | ||
875 | /* TODO: global int Ref count */ | 905 | /* TODO: global int Ref count */ |
876 | mask = ints & ATH9K_INT_COMMON; | 906 | mask = ints & ATH9K_INT_COMMON; |
@@ -946,24 +976,8 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, | |||
946 | REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER); | 976 | REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER); |
947 | } | 977 | } |
948 | 978 | ||
949 | if (ints & ATH9K_INT_GLOBAL) { | 979 | ath9k_hw_enable_interrupts(ah); |
950 | ath_print(common, ATH_DBG_INTERRUPT, "enable IER\n"); | ||
951 | REG_WRITE(ah, AR_IER, AR_IER_ENABLE); | ||
952 | if (!AR_SREV_9100(ah)) { | ||
953 | REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, | ||
954 | AR_INTR_MAC_IRQ); | ||
955 | REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ); | ||
956 | |||
957 | |||
958 | REG_WRITE(ah, AR_INTR_SYNC_ENABLE, | ||
959 | AR_INTR_SYNC_DEFAULT); | ||
960 | REG_WRITE(ah, AR_INTR_SYNC_MASK, | ||
961 | AR_INTR_SYNC_DEFAULT); | ||
962 | } | ||
963 | ath_print(common, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n", | ||
964 | REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER)); | ||
965 | } | ||
966 | 980 | ||
967 | return omask; | 981 | return; |
968 | } | 982 | } |
969 | EXPORT_SYMBOL(ath9k_hw_set_interrupts); | 983 | EXPORT_SYMBOL(ath9k_hw_set_interrupts); |
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 7c1a34d64f6..538c676e799 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h | |||
@@ -669,6 +669,7 @@ enum ath9k_key_type { | |||
669 | 669 | ||
670 | struct ath_hw; | 670 | struct ath_hw; |
671 | struct ath9k_channel; | 671 | struct ath9k_channel; |
672 | enum ath9k_int; | ||
672 | 673 | ||
673 | u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q); | 674 | u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q); |
674 | void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp); | 675 | void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp); |
@@ -700,8 +701,9 @@ int ath9k_hw_beaconq_setup(struct ath_hw *ah); | |||
700 | 701 | ||
701 | /* Interrupt Handling */ | 702 | /* Interrupt Handling */ |
702 | bool ath9k_hw_intrpend(struct ath_hw *ah); | 703 | bool ath9k_hw_intrpend(struct ath_hw *ah); |
703 | enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, | 704 | void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints); |
704 | enum ath9k_int ints); | 705 | void ath9k_hw_enable_interrupts(struct ath_hw *ah); |
706 | void ath9k_hw_disable_interrupts(struct ath_hw *ah); | ||
705 | 707 | ||
706 | void ar9002_hw_attach_mac_ops(struct ath_hw *ah); | 708 | void ar9002_hw_attach_mac_ops(struct ath_hw *ah); |
707 | 709 | ||
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index b52f1cf8a60..ade9d7c1603 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -239,7 +239,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, | |||
239 | * hardware at the new frequency, and then re-enable | 239 | * hardware at the new frequency, and then re-enable |
240 | * the relevant bits of the h/w. | 240 | * the relevant bits of the h/w. |
241 | */ | 241 | */ |
242 | ath9k_hw_set_interrupts(ah, 0); | 242 | ath9k_hw_disable_interrupts(ah); |
243 | ath_drain_all_txq(sc, false); | 243 | ath_drain_all_txq(sc, false); |
244 | 244 | ||
245 | spin_lock_bh(&sc->rx.pcu_lock); | 245 | spin_lock_bh(&sc->rx.pcu_lock); |
@@ -653,7 +653,7 @@ void ath9k_tasklet(unsigned long data) | |||
653 | ath_gen_timer_isr(sc->sc_ah); | 653 | ath_gen_timer_isr(sc->sc_ah); |
654 | 654 | ||
655 | /* re-enable hardware interrupt */ | 655 | /* re-enable hardware interrupt */ |
656 | ath9k_hw_set_interrupts(ah, ah->imask); | 656 | ath9k_hw_enable_interrupts(ah); |
657 | ath9k_ps_restore(sc); | 657 | ath9k_ps_restore(sc); |
658 | } | 658 | } |
659 | 659 | ||
@@ -752,7 +752,7 @@ irqreturn_t ath_isr(int irq, void *dev) | |||
752 | * interrupt; otherwise it will continue to | 752 | * interrupt; otherwise it will continue to |
753 | * fire. | 753 | * fire. |
754 | */ | 754 | */ |
755 | ath9k_hw_set_interrupts(ah, 0); | 755 | ath9k_hw_disable_interrupts(ah); |
756 | /* | 756 | /* |
757 | * Let the hal handle the event. We assume | 757 | * Let the hal handle the event. We assume |
758 | * it will clear whatever condition caused | 758 | * it will clear whatever condition caused |
@@ -761,7 +761,7 @@ irqreturn_t ath_isr(int irq, void *dev) | |||
761 | spin_lock(&common->cc_lock); | 761 | spin_lock(&common->cc_lock); |
762 | ath9k_hw_proc_mib_event(ah); | 762 | ath9k_hw_proc_mib_event(ah); |
763 | spin_unlock(&common->cc_lock); | 763 | spin_unlock(&common->cc_lock); |
764 | ath9k_hw_set_interrupts(ah, ah->imask); | 764 | ath9k_hw_enable_interrupts(ah); |
765 | } | 765 | } |
766 | 766 | ||
767 | if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) | 767 | if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) |
@@ -778,8 +778,8 @@ chip_reset: | |||
778 | ath_debug_stat_interrupt(sc, status); | 778 | ath_debug_stat_interrupt(sc, status); |
779 | 779 | ||
780 | if (sched) { | 780 | if (sched) { |
781 | /* turn off every interrupt except SWBA */ | 781 | /* turn off every interrupt */ |
782 | ath9k_hw_set_interrupts(ah, (ah->imask & ATH9K_INT_SWBA)); | 782 | ath9k_hw_disable_interrupts(ah); |
783 | tasklet_schedule(&sc->intr_tq); | 783 | tasklet_schedule(&sc->intr_tq); |
784 | } | 784 | } |
785 | 785 | ||
@@ -937,7 +937,7 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) | |||
937 | } | 937 | } |
938 | 938 | ||
939 | /* Disable interrupts */ | 939 | /* Disable interrupts */ |
940 | ath9k_hw_set_interrupts(ah, 0); | 940 | ath9k_hw_disable_interrupts(ah); |
941 | 941 | ||
942 | ath_drain_all_txq(sc, false); /* clear pending tx frames */ | 942 | ath_drain_all_txq(sc, false); /* clear pending tx frames */ |
943 | 943 | ||
@@ -980,7 +980,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) | |||
980 | 980 | ||
981 | ieee80211_stop_queues(hw); | 981 | ieee80211_stop_queues(hw); |
982 | 982 | ||
983 | ath9k_hw_set_interrupts(ah, 0); | 983 | ath9k_hw_disable_interrupts(ah); |
984 | ath_drain_all_txq(sc, retry_tx); | 984 | ath_drain_all_txq(sc, retry_tx); |
985 | 985 | ||
986 | spin_lock_bh(&sc->rx.pcu_lock); | 986 | spin_lock_bh(&sc->rx.pcu_lock); |
@@ -1394,7 +1394,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) | |||
1394 | 1394 | ||
1395 | /* make sure h/w will not generate any interrupt | 1395 | /* make sure h/w will not generate any interrupt |
1396 | * before setting the invalid flag. */ | 1396 | * before setting the invalid flag. */ |
1397 | ath9k_hw_set_interrupts(ah, 0); | 1397 | ath9k_hw_disable_interrupts(ah); |
1398 | 1398 | ||
1399 | spin_lock_bh(&sc->rx.pcu_lock); | 1399 | spin_lock_bh(&sc->rx.pcu_lock); |
1400 | if (!(sc->sc_flags & SC_OP_INVALID)) { | 1400 | if (!(sc->sc_flags & SC_OP_INVALID)) { |