diff options
author | Felix Fietkau <nbd@openwrt.org> | 2013-12-14 12:03:38 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-12-18 15:23:22 -0500 |
commit | c67ce33919d57627e98fadceea555ddc01ad77b4 (patch) | |
tree | a4e481a7aabef73ebd0cbe1bf00d98d121652ac8 /drivers/net | |
parent | 168c6f89a27b605fb7dc3e1572ee5b2a6f56c935 (diff) |
ath9k_hw: clean up generic timer code
- Use generic bitops instead of custom hackery
- Move interrupt enable/disable logic from ath9k to ath9k_hw
- Decouple ISR call from btcoex
- Make the overflow callback optional (to prevent IRQ storms)
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/btcoex.c | 6 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/gpio.c | 36 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/hw.c | 92 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/hw.h | 12 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 3 |
5 files changed, 45 insertions, 104 deletions
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index 9963b0bf9f72..3dfc2c7f1f07 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c | |||
@@ -66,7 +66,6 @@ void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum) | |||
66 | .bt_first_slot_time = 5, | 66 | .bt_first_slot_time = 5, |
67 | .bt_hold_rx_clear = true, | 67 | .bt_hold_rx_clear = true, |
68 | }; | 68 | }; |
69 | u32 i, idx; | ||
70 | bool rxclear_polarity = ath_bt_config.bt_rxclear_polarity; | 69 | bool rxclear_polarity = ath_bt_config.bt_rxclear_polarity; |
71 | 70 | ||
72 | if (AR_SREV_9300_20_OR_LATER(ah)) | 71 | if (AR_SREV_9300_20_OR_LATER(ah)) |
@@ -88,11 +87,6 @@ void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum) | |||
88 | SM(ath_bt_config.bt_hold_rx_clear, AR_BT_HOLD_RX_CLEAR) | | 87 | SM(ath_bt_config.bt_hold_rx_clear, AR_BT_HOLD_RX_CLEAR) | |
89 | SM(ATH_BTCOEX_BMISS_THRESH, AR_BT_BCN_MISS_THRESH) | | 88 | SM(ATH_BTCOEX_BMISS_THRESH, AR_BT_BCN_MISS_THRESH) | |
90 | AR_BT_DISABLE_BT_ANT; | 89 | AR_BT_DISABLE_BT_ANT; |
91 | |||
92 | for (i = 0; i < 32; i++) { | ||
93 | idx = (debruijn32 << i) >> 27; | ||
94 | ah->hw_gen_timers.gen_timer_index[idx] = i; | ||
95 | } | ||
96 | } | 90 | } |
97 | EXPORT_SYMBOL(ath9k_hw_init_btcoex_hw); | 91 | EXPORT_SYMBOL(ath9k_hw_init_btcoex_hw); |
98 | 92 | ||
diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index a85e220c8d9c..b1956bf6e01e 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c | |||
@@ -157,36 +157,6 @@ static void ath_detect_bt_priority(struct ath_softc *sc) | |||
157 | } | 157 | } |
158 | } | 158 | } |
159 | 159 | ||
160 | static void ath9k_gen_timer_start(struct ath_hw *ah, | ||
161 | struct ath_gen_timer *timer, | ||
162 | u32 trig_timeout, | ||
163 | u32 timer_period) | ||
164 | { | ||
165 | ath9k_hw_gen_timer_start(ah, timer, trig_timeout, timer_period); | ||
166 | |||
167 | if ((ah->imask & ATH9K_INT_GENTIMER) == 0) { | ||
168 | ath9k_hw_disable_interrupts(ah); | ||
169 | ah->imask |= ATH9K_INT_GENTIMER; | ||
170 | ath9k_hw_set_interrupts(ah); | ||
171 | ath9k_hw_enable_interrupts(ah); | ||
172 | } | ||
173 | } | ||
174 | |||
175 | static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) | ||
176 | { | ||
177 | struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; | ||
178 | |||
179 | ath9k_hw_gen_timer_stop(ah, timer); | ||
180 | |||
181 | /* if no timer is enabled, turn off interrupt mask */ | ||
182 | if (timer_table->timer_mask.val == 0) { | ||
183 | ath9k_hw_disable_interrupts(ah); | ||
184 | ah->imask &= ~ATH9K_INT_GENTIMER; | ||
185 | ath9k_hw_set_interrupts(ah); | ||
186 | ath9k_hw_enable_interrupts(ah); | ||
187 | } | ||
188 | } | ||
189 | |||
190 | static void ath_mci_ftp_adjust(struct ath_softc *sc) | 160 | static void ath_mci_ftp_adjust(struct ath_softc *sc) |
191 | { | 161 | { |
192 | struct ath_btcoex *btcoex = &sc->btcoex; | 162 | struct ath_btcoex *btcoex = &sc->btcoex; |
@@ -373,12 +343,6 @@ u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen) | |||
373 | 343 | ||
374 | void ath9k_btcoex_handle_interrupt(struct ath_softc *sc, u32 status) | 344 | void ath9k_btcoex_handle_interrupt(struct ath_softc *sc, u32 status) |
375 | { | 345 | { |
376 | struct ath_hw *ah = sc->sc_ah; | ||
377 | |||
378 | if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) | ||
379 | if (status & ATH9K_INT_GENTIMER) | ||
380 | ath_gen_timer_isr(sc->sc_ah); | ||
381 | |||
382 | if (status & ATH9K_INT_MCI) | 346 | if (status & ATH9K_INT_MCI) |
383 | ath_mci_intr(sc); | 347 | ath_mci_intr(sc); |
384 | } | 348 | } |
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 1de98b895356..3b10a6bb07d4 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/time.h> | 20 | #include <linux/time.h> |
21 | #include <linux/bitops.h> | ||
21 | #include <asm/unaligned.h> | 22 | #include <asm/unaligned.h> |
22 | 23 | ||
23 | #include "hw.h" | 24 | #include "hw.h" |
@@ -2991,20 +2992,6 @@ static const struct ath_gen_timer_configuration gen_tmr_configuration[] = | |||
2991 | 2992 | ||
2992 | /* HW generic timer primitives */ | 2993 | /* HW generic timer primitives */ |
2993 | 2994 | ||
2994 | /* compute and clear index of rightmost 1 */ | ||
2995 | static u32 rightmost_index(struct ath_gen_timer_table *timer_table, u32 *mask) | ||
2996 | { | ||
2997 | u32 b; | ||
2998 | |||
2999 | b = *mask; | ||
3000 | b &= (0-b); | ||
3001 | *mask &= ~b; | ||
3002 | b *= debruijn32; | ||
3003 | b >>= 27; | ||
3004 | |||
3005 | return timer_table->gen_timer_index[b]; | ||
3006 | } | ||
3007 | |||
3008 | u32 ath9k_hw_gettsf32(struct ath_hw *ah) | 2995 | u32 ath9k_hw_gettsf32(struct ath_hw *ah) |
3009 | { | 2996 | { |
3010 | return REG_READ(ah, AR_TSF_L32); | 2997 | return REG_READ(ah, AR_TSF_L32); |
@@ -3020,6 +3007,10 @@ struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, | |||
3020 | struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; | 3007 | struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; |
3021 | struct ath_gen_timer *timer; | 3008 | struct ath_gen_timer *timer; |
3022 | 3009 | ||
3010 | if ((timer_index < AR_FIRST_NDP_TIMER) || | ||
3011 | (timer_index >= ATH_MAX_GEN_TIMER)) | ||
3012 | return NULL; | ||
3013 | |||
3023 | timer = kzalloc(sizeof(struct ath_gen_timer), GFP_KERNEL); | 3014 | timer = kzalloc(sizeof(struct ath_gen_timer), GFP_KERNEL); |
3024 | if (timer == NULL) | 3015 | if (timer == NULL) |
3025 | return NULL; | 3016 | return NULL; |
@@ -3037,23 +3028,13 @@ EXPORT_SYMBOL(ath_gen_timer_alloc); | |||
3037 | 3028 | ||
3038 | void ath9k_hw_gen_timer_start(struct ath_hw *ah, | 3029 | void ath9k_hw_gen_timer_start(struct ath_hw *ah, |
3039 | struct ath_gen_timer *timer, | 3030 | struct ath_gen_timer *timer, |
3040 | u32 trig_timeout, | 3031 | u32 timer_next, |
3041 | u32 timer_period) | 3032 | u32 timer_period) |
3042 | { | 3033 | { |
3043 | struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; | 3034 | struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; |
3044 | u32 tsf, timer_next; | 3035 | u32 mask = 0; |
3045 | |||
3046 | BUG_ON(!timer_period); | ||
3047 | |||
3048 | set_bit(timer->index, &timer_table->timer_mask.timer_bits); | ||
3049 | |||
3050 | tsf = ath9k_hw_gettsf32(ah); | ||
3051 | |||
3052 | timer_next = tsf + trig_timeout; | ||
3053 | 3036 | ||
3054 | ath_dbg(ath9k_hw_common(ah), BTCOEX, | 3037 | timer_table->timer_mask |= BIT(timer->index); |
3055 | "current tsf %x period %x timer_next %x\n", | ||
3056 | tsf, timer_period, timer_next); | ||
3057 | 3038 | ||
3058 | /* | 3039 | /* |
3059 | * Program generic timer registers | 3040 | * Program generic timer registers |
@@ -3079,10 +3060,19 @@ void ath9k_hw_gen_timer_start(struct ath_hw *ah, | |||
3079 | (1 << timer->index)); | 3060 | (1 << timer->index)); |
3080 | } | 3061 | } |
3081 | 3062 | ||
3082 | /* Enable both trigger and thresh interrupt masks */ | 3063 | if (timer->trigger) |
3083 | REG_SET_BIT(ah, AR_IMR_S5, | 3064 | mask |= SM(AR_GENTMR_BIT(timer->index), |
3084 | (SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_THRESH) | | 3065 | AR_IMR_S5_GENTIMER_TRIG); |
3085 | SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_TRIG))); | 3066 | if (timer->overflow) |
3067 | mask |= SM(AR_GENTMR_BIT(timer->index), | ||
3068 | AR_IMR_S5_GENTIMER_THRESH); | ||
3069 | |||
3070 | REG_SET_BIT(ah, AR_IMR_S5, mask); | ||
3071 | |||
3072 | if ((ah->imask & ATH9K_INT_GENTIMER) == 0) { | ||
3073 | ah->imask |= ATH9K_INT_GENTIMER; | ||
3074 | ath9k_hw_set_interrupts(ah); | ||
3075 | } | ||
3086 | } | 3076 | } |
3087 | EXPORT_SYMBOL(ath9k_hw_gen_timer_start); | 3077 | EXPORT_SYMBOL(ath9k_hw_gen_timer_start); |
3088 | 3078 | ||
@@ -3090,11 +3080,6 @@ void ath9k_hw_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) | |||
3090 | { | 3080 | { |
3091 | struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; | 3081 | struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; |
3092 | 3082 | ||
3093 | if ((timer->index < AR_FIRST_NDP_TIMER) || | ||
3094 | (timer->index >= ATH_MAX_GEN_TIMER)) { | ||
3095 | return; | ||
3096 | } | ||
3097 | |||
3098 | /* Clear generic timer enable bits. */ | 3083 | /* Clear generic timer enable bits. */ |
3099 | REG_CLR_BIT(ah, gen_tmr_configuration[timer->index].mode_addr, | 3084 | REG_CLR_BIT(ah, gen_tmr_configuration[timer->index].mode_addr, |
3100 | gen_tmr_configuration[timer->index].mode_mask); | 3085 | gen_tmr_configuration[timer->index].mode_mask); |
@@ -3114,7 +3099,12 @@ void ath9k_hw_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) | |||
3114 | (SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_THRESH) | | 3099 | (SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_THRESH) | |
3115 | SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_TRIG))); | 3100 | SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_TRIG))); |
3116 | 3101 | ||
3117 | clear_bit(timer->index, &timer_table->timer_mask.timer_bits); | 3102 | timer_table->timer_mask &= ~BIT(timer->index); |
3103 | |||
3104 | if (timer_table->timer_mask == 0) { | ||
3105 | ah->imask &= ~ATH9K_INT_GENTIMER; | ||
3106 | ath9k_hw_set_interrupts(ah); | ||
3107 | } | ||
3118 | } | 3108 | } |
3119 | EXPORT_SYMBOL(ath9k_hw_gen_timer_stop); | 3109 | EXPORT_SYMBOL(ath9k_hw_gen_timer_stop); |
3120 | 3110 | ||
@@ -3135,32 +3125,32 @@ void ath_gen_timer_isr(struct ath_hw *ah) | |||
3135 | { | 3125 | { |
3136 | struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; | 3126 | struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; |
3137 | struct ath_gen_timer *timer; | 3127 | struct ath_gen_timer *timer; |
3138 | struct ath_common *common = ath9k_hw_common(ah); | 3128 | unsigned long trigger_mask, thresh_mask; |
3139 | u32 trigger_mask, thresh_mask, index; | 3129 | unsigned int index; |
3140 | 3130 | ||
3141 | /* get hardware generic timer interrupt status */ | 3131 | /* get hardware generic timer interrupt status */ |
3142 | trigger_mask = ah->intr_gen_timer_trigger; | 3132 | trigger_mask = ah->intr_gen_timer_trigger; |
3143 | thresh_mask = ah->intr_gen_timer_thresh; | 3133 | thresh_mask = ah->intr_gen_timer_thresh; |
3144 | trigger_mask &= timer_table->timer_mask.val; | 3134 | trigger_mask &= timer_table->timer_mask; |
3145 | thresh_mask &= timer_table->timer_mask.val; | 3135 | thresh_mask &= timer_table->timer_mask; |
3146 | 3136 | ||
3147 | trigger_mask &= ~thresh_mask; | 3137 | trigger_mask &= ~thresh_mask; |
3148 | 3138 | ||
3149 | while (thresh_mask) { | 3139 | for_each_set_bit(index, &thresh_mask, ARRAY_SIZE(timer_table->timers)) { |
3150 | index = rightmost_index(timer_table, &thresh_mask); | ||
3151 | timer = timer_table->timers[index]; | 3140 | timer = timer_table->timers[index]; |
3152 | BUG_ON(!timer); | 3141 | if (!timer) |
3153 | ath_dbg(common, BTCOEX, "TSF overflow for Gen timer %d\n", | 3142 | continue; |
3154 | index); | 3143 | if (!timer->overflow) |
3144 | continue; | ||
3155 | timer->overflow(timer->arg); | 3145 | timer->overflow(timer->arg); |
3156 | } | 3146 | } |
3157 | 3147 | ||
3158 | while (trigger_mask) { | 3148 | for_each_set_bit(index, &trigger_mask, ARRAY_SIZE(timer_table->timers)) { |
3159 | index = rightmost_index(timer_table, &trigger_mask); | ||
3160 | timer = timer_table->timers[index]; | 3149 | timer = timer_table->timers[index]; |
3161 | BUG_ON(!timer); | 3150 | if (!timer) |
3162 | ath_dbg(common, BTCOEX, | 3151 | continue; |
3163 | "Gen timer[%d] trigger\n", index); | 3152 | if (!timer->trigger) |
3153 | continue; | ||
3164 | timer->trigger(timer->arg); | 3154 | timer->trigger(timer->arg); |
3165 | } | 3155 | } |
3166 | } | 3156 | } |
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index b1ff54631dca..1b45920f0448 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h | |||
@@ -499,12 +499,6 @@ struct ath9k_hw_version { | |||
499 | 499 | ||
500 | #define AR_GENTMR_BIT(_index) (1 << (_index)) | 500 | #define AR_GENTMR_BIT(_index) (1 << (_index)) |
501 | 501 | ||
502 | /* | ||
503 | * Using de Bruijin sequence to look up 1's index in a 32 bit number | ||
504 | * debruijn32 = 0000 0111 0111 1100 1011 0101 0011 0001 | ||
505 | */ | ||
506 | #define debruijn32 0x077CB531U | ||
507 | |||
508 | struct ath_gen_timer_configuration { | 502 | struct ath_gen_timer_configuration { |
509 | u32 next_addr; | 503 | u32 next_addr; |
510 | u32 period_addr; | 504 | u32 period_addr; |
@@ -520,12 +514,8 @@ struct ath_gen_timer { | |||
520 | }; | 514 | }; |
521 | 515 | ||
522 | struct ath_gen_timer_table { | 516 | struct ath_gen_timer_table { |
523 | u32 gen_timer_index[32]; | ||
524 | struct ath_gen_timer *timers[ATH_MAX_GEN_TIMER]; | 517 | struct ath_gen_timer *timers[ATH_MAX_GEN_TIMER]; |
525 | union { | 518 | u16 timer_mask; |
526 | unsigned long timer_bits; | ||
527 | u16 val; | ||
528 | } timer_mask; | ||
529 | }; | 519 | }; |
530 | 520 | ||
531 | struct ath_hw_antcomb_conf { | 521 | struct ath_hw_antcomb_conf { |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index b1dcf89138d3..4798f6ae061e 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -508,6 +508,9 @@ void ath9k_tasklet(unsigned long data) | |||
508 | wake_up(&sc->tx_wait); | 508 | wake_up(&sc->tx_wait); |
509 | } | 509 | } |
510 | 510 | ||
511 | if (status & ATH9K_INT_GENTIMER) | ||
512 | ath_gen_timer_isr(sc->sc_ah); | ||
513 | |||
511 | ath9k_btcoex_handle_interrupt(sc, status); | 514 | ath9k_btcoex_handle_interrupt(sc, status); |
512 | 515 | ||
513 | /* re-enable hardware interrupt */ | 516 | /* re-enable hardware interrupt */ |