aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath9k
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2013-12-14 12:03:38 -0500
committerJohn W. Linville <linville@tuxdriver.com>2013-12-18 15:23:22 -0500
commitc67ce33919d57627e98fadceea555ddc01ad77b4 (patch)
treea4e481a7aabef73ebd0cbe1bf00d98d121652ac8 /drivers/net/wireless/ath/ath9k
parent168c6f89a27b605fb7dc3e1572ee5b2a6f56c935 (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/wireless/ath/ath9k')
-rw-r--r--drivers/net/wireless/ath/ath9k/btcoex.c6
-rw-r--r--drivers/net/wireless/ath/ath9k/gpio.c36
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c92
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h12
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c3
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}
97EXPORT_SYMBOL(ath9k_hw_init_btcoex_hw); 91EXPORT_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
160static 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
175static 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
190static void ath_mci_ftp_adjust(struct ath_softc *sc) 160static 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
374void ath9k_btcoex_handle_interrupt(struct ath_softc *sc, u32 status) 344void 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 */
2995static 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
3008u32 ath9k_hw_gettsf32(struct ath_hw *ah) 2995u32 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
3038void ath9k_hw_gen_timer_start(struct ath_hw *ah, 3029void 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}
3087EXPORT_SYMBOL(ath9k_hw_gen_timer_start); 3077EXPORT_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}
3119EXPORT_SYMBOL(ath9k_hw_gen_timer_stop); 3109EXPORT_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
508struct ath_gen_timer_configuration { 502struct 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
522struct ath_gen_timer_table { 516struct 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
531struct ath_hw_antcomb_conf { 521struct 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 */