Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Felix Fietkau and committed by
John W. Linville
c67ce339 168c6f89

+45 -104
-6
drivers/net/wireless/ath/ath9k/btcoex.c
··· 66 66 .bt_first_slot_time = 5, 67 67 .bt_hold_rx_clear = true, 68 68 }; 69 - u32 i, idx; 70 69 bool rxclear_polarity = ath_bt_config.bt_rxclear_polarity; 71 70 72 71 if (AR_SREV_9300_20_OR_LATER(ah)) ··· 87 88 SM(ath_bt_config.bt_hold_rx_clear, AR_BT_HOLD_RX_CLEAR) | 88 89 SM(ATH_BTCOEX_BMISS_THRESH, AR_BT_BCN_MISS_THRESH) | 89 90 AR_BT_DISABLE_BT_ANT; 90 - 91 - for (i = 0; i < 32; i++) { 92 - idx = (debruijn32 << i) >> 27; 93 - ah->hw_gen_timers.gen_timer_index[idx] = i; 94 - } 95 91 } 96 92 EXPORT_SYMBOL(ath9k_hw_init_btcoex_hw); 97 93
-36
drivers/net/wireless/ath/ath9k/gpio.c
··· 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 160 static void ath_mci_ftp_adjust(struct ath_softc *sc) 191 161 { 192 162 struct ath_btcoex *btcoex = &sc->btcoex; ··· 343 373 344 374 void ath9k_btcoex_handle_interrupt(struct ath_softc *sc, u32 status) 345 375 { 346 - struct ath_hw *ah = sc->sc_ah; 347 - 348 - if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) 349 - if (status & ATH9K_INT_GENTIMER) 350 - ath_gen_timer_isr(sc->sc_ah); 351 - 352 376 if (status & ATH9K_INT_MCI) 353 377 ath_mci_intr(sc); 354 378 }
+41 -51
drivers/net/wireless/ath/ath9k/hw.c
··· 18 18 #include <linux/slab.h> 19 19 #include <linux/module.h> 20 20 #include <linux/time.h> 21 + #include <linux/bitops.h> 21 22 #include <asm/unaligned.h> 22 23 23 24 #include "hw.h" ··· 2992 2991 2993 2992 /* HW generic timer primitives */ 2994 2993 2995 - /* compute and clear index of rightmost 1 */ 2996 - static u32 rightmost_index(struct ath_gen_timer_table *timer_table, u32 *mask) 2997 - { 2998 - u32 b; 2999 - 3000 - b = *mask; 3001 - b &= (0-b); 3002 - *mask &= ~b; 3003 - b *= debruijn32; 3004 - b >>= 27; 3005 - 3006 - return timer_table->gen_timer_index[b]; 3007 - } 3008 - 3009 2994 u32 ath9k_hw_gettsf32(struct ath_hw *ah) 3010 2995 { 3011 2996 return REG_READ(ah, AR_TSF_L32); ··· 3006 3019 { 3007 3020 struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; 3008 3021 struct ath_gen_timer *timer; 3022 + 3023 + if ((timer_index < AR_FIRST_NDP_TIMER) || 3024 + (timer_index >= ATH_MAX_GEN_TIMER)) 3025 + return NULL; 3009 3026 3010 3027 timer = kzalloc(sizeof(struct ath_gen_timer), GFP_KERNEL); 3011 3028 if (timer == NULL) ··· 3028 3037 3029 3038 void ath9k_hw_gen_timer_start(struct ath_hw *ah, 3030 3039 struct ath_gen_timer *timer, 3031 - u32 trig_timeout, 3040 + u32 timer_next, 3032 3041 u32 timer_period) 3033 3042 { 3034 3043 struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; 3035 - u32 tsf, timer_next; 3044 + u32 mask = 0; 3036 3045 3037 - BUG_ON(!timer_period); 3038 - 3039 - set_bit(timer->index, &timer_table->timer_mask.timer_bits); 3040 - 3041 - tsf = ath9k_hw_gettsf32(ah); 3042 - 3043 - timer_next = tsf + trig_timeout; 3044 - 3045 - ath_dbg(ath9k_hw_common(ah), BTCOEX, 3046 - "current tsf %x period %x timer_next %x\n", 3047 - tsf, timer_period, timer_next); 3046 + timer_table->timer_mask |= BIT(timer->index); 3048 3047 3049 3048 /* 3050 3049 * Program generic timer registers ··· 3060 3079 (1 << timer->index)); 3061 3080 } 3062 3081 3063 - /* Enable both trigger and thresh interrupt masks */ 3064 - REG_SET_BIT(ah, AR_IMR_S5, 3065 - (SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_THRESH) | 3066 - SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_TRIG))); 3082 + if (timer->trigger) 3083 + mask |= SM(AR_GENTMR_BIT(timer->index), 3084 + AR_IMR_S5_GENTIMER_TRIG); 3085 + if (timer->overflow) 3086 + mask |= SM(AR_GENTMR_BIT(timer->index), 3087 + AR_IMR_S5_GENTIMER_THRESH); 3088 + 3089 + REG_SET_BIT(ah, AR_IMR_S5, mask); 3090 + 3091 + if ((ah->imask & ATH9K_INT_GENTIMER) == 0) { 3092 + ah->imask |= ATH9K_INT_GENTIMER; 3093 + ath9k_hw_set_interrupts(ah); 3094 + } 3067 3095 } 3068 3096 EXPORT_SYMBOL(ath9k_hw_gen_timer_start); 3069 3097 3070 3098 void ath9k_hw_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) 3071 3099 { 3072 3100 struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; 3073 - 3074 - if ((timer->index < AR_FIRST_NDP_TIMER) || 3075 - (timer->index >= ATH_MAX_GEN_TIMER)) { 3076 - return; 3077 - } 3078 3101 3079 3102 /* Clear generic timer enable bits. */ 3080 3103 REG_CLR_BIT(ah, gen_tmr_configuration[timer->index].mode_addr, ··· 3099 3114 (SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_THRESH) | 3100 3115 SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_TRIG))); 3101 3116 3102 - clear_bit(timer->index, &timer_table->timer_mask.timer_bits); 3117 + timer_table->timer_mask &= ~BIT(timer->index); 3118 + 3119 + if (timer_table->timer_mask == 0) { 3120 + ah->imask &= ~ATH9K_INT_GENTIMER; 3121 + ath9k_hw_set_interrupts(ah); 3122 + } 3103 3123 } 3104 3124 EXPORT_SYMBOL(ath9k_hw_gen_timer_stop); 3105 3125 ··· 3125 3135 { 3126 3136 struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; 3127 3137 struct ath_gen_timer *timer; 3128 - struct ath_common *common = ath9k_hw_common(ah); 3129 - u32 trigger_mask, thresh_mask, index; 3138 + unsigned long trigger_mask, thresh_mask; 3139 + unsigned int index; 3130 3140 3131 3141 /* get hardware generic timer interrupt status */ 3132 3142 trigger_mask = ah->intr_gen_timer_trigger; 3133 3143 thresh_mask = ah->intr_gen_timer_thresh; 3134 - trigger_mask &= timer_table->timer_mask.val; 3135 - thresh_mask &= timer_table->timer_mask.val; 3144 + trigger_mask &= timer_table->timer_mask; 3145 + thresh_mask &= timer_table->timer_mask; 3136 3146 3137 3147 trigger_mask &= ~thresh_mask; 3138 3148 3139 - while (thresh_mask) { 3140 - index = rightmost_index(timer_table, &thresh_mask); 3149 + for_each_set_bit(index, &thresh_mask, ARRAY_SIZE(timer_table->timers)) { 3141 3150 timer = timer_table->timers[index]; 3142 - BUG_ON(!timer); 3143 - ath_dbg(common, BTCOEX, "TSF overflow for Gen timer %d\n", 3144 - index); 3151 + if (!timer) 3152 + continue; 3153 + if (!timer->overflow) 3154 + continue; 3145 3155 timer->overflow(timer->arg); 3146 3156 } 3147 3157 3148 - while (trigger_mask) { 3149 - index = rightmost_index(timer_table, &trigger_mask); 3158 + for_each_set_bit(index, &trigger_mask, ARRAY_SIZE(timer_table->timers)) { 3150 3159 timer = timer_table->timers[index]; 3151 - BUG_ON(!timer); 3152 - ath_dbg(common, BTCOEX, 3153 - "Gen timer[%d] trigger\n", index); 3160 + if (!timer) 3161 + continue; 3162 + if (!timer->trigger) 3163 + continue; 3154 3164 timer->trigger(timer->arg); 3155 3165 } 3156 3166 }
+1 -11
drivers/net/wireless/ath/ath9k/hw.h
··· 499 499 500 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 502 struct ath_gen_timer_configuration { 509 503 u32 next_addr; 510 504 u32 period_addr; ··· 514 520 }; 515 521 516 522 struct ath_gen_timer_table { 517 - u32 gen_timer_index[32]; 518 523 struct ath_gen_timer *timers[ATH_MAX_GEN_TIMER]; 519 - union { 520 - unsigned long timer_bits; 521 - u16 val; 522 - } timer_mask; 524 + u16 timer_mask; 523 525 }; 524 526 525 527 struct ath_hw_antcomb_conf {
+3
drivers/net/wireless/ath/ath9k/main.c
··· 508 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 514 ath9k_btcoex_handle_interrupt(sc, status); 512 515 513 516 /* re-enable hardware interrupt */