aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath
diff options
context:
space:
mode:
authorVasanthakumar Thiagarajan <vasanth@atheros.com>2009-08-26 11:38:49 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-08-28 14:40:51 -0400
commitff155a45cea56ad7a90c3f5192db59a4c7812fde (patch)
tree3733ebad8263ba4c92e9ad429b901e56958d8c76 /drivers/net/wireless/ath
parent81fa16fbe06cb3a4d29cc5a6f925132554521c72 (diff)
ath9k: Add infrastructure for generic hw timers
Signed-off-by: Vasanthakumar Thiagarajan <vasanth@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c212
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h52
-rw-r--r--drivers/net/wireless/ath/ath9k/reg.h15
4 files changed, 278 insertions, 2 deletions
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index 5e56b79d0cb0..ea0dd1ec15c3 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -30,6 +30,7 @@ enum ATH_DEBUG {
30 ATH_DBG_CONFIG = 0x00000200, 30 ATH_DBG_CONFIG = 0x00000200,
31 ATH_DBG_FATAL = 0x00000400, 31 ATH_DBG_FATAL = 0x00000400,
32 ATH_DBG_PS = 0x00000800, 32 ATH_DBG_PS = 0x00000800,
33 ATH_DBG_HWTIMER = 0x00001000,
33 ATH_DBG_ANY = 0xffffffff 34 ATH_DBG_ANY = 0xffffffff
34}; 35};
35 36
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index c80be8c78e8b..3afd7a9fc8a3 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -3215,6 +3215,23 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
3215 if (AR_SREV_9100(ah)) 3215 if (AR_SREV_9100(ah))
3216 return true; 3216 return true;
3217 3217
3218 if (isr & AR_ISR_GENTMR) {
3219 u32 s5_s;
3220
3221 s5_s = REG_READ(ah, AR_ISR_S5_S);
3222 if (isr & AR_ISR_GENTMR) {
3223 ah->intr_gen_timer_trigger =
3224 MS(s5_s, AR_ISR_S5_GENTIMER_TRIG);
3225
3226 ah->intr_gen_timer_thresh =
3227 MS(s5_s, AR_ISR_S5_GENTIMER_THRESH);
3228
3229 if (ah->intr_gen_timer_trigger)
3230 *masked |= ATH9K_INT_GENTIMER;
3231
3232 }
3233 }
3234
3218 if (sync_cause) { 3235 if (sync_cause) {
3219 fatal_int = 3236 fatal_int =
3220 (sync_cause & 3237 (sync_cause &
@@ -4078,3 +4095,198 @@ void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode)
4078 4095
4079 REG_WRITE(ah, AR_2040_MODE, macmode); 4096 REG_WRITE(ah, AR_2040_MODE, macmode);
4080} 4097}
4098
4099/* HW Generic timers configuration */
4100
4101static const struct ath_gen_timer_configuration gen_tmr_configuration[] =
4102{
4103 {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
4104 {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
4105 {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
4106 {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
4107 {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
4108 {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
4109 {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
4110 {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
4111 {AR_NEXT_NDP2_TIMER, AR_NDP2_PERIOD, AR_NDP2_TIMER_MODE, 0x0001},
4112 {AR_NEXT_NDP2_TIMER + 1*4, AR_NDP2_PERIOD + 1*4,
4113 AR_NDP2_TIMER_MODE, 0x0002},
4114 {AR_NEXT_NDP2_TIMER + 2*4, AR_NDP2_PERIOD + 2*4,
4115 AR_NDP2_TIMER_MODE, 0x0004},
4116 {AR_NEXT_NDP2_TIMER + 3*4, AR_NDP2_PERIOD + 3*4,
4117 AR_NDP2_TIMER_MODE, 0x0008},
4118 {AR_NEXT_NDP2_TIMER + 4*4, AR_NDP2_PERIOD + 4*4,
4119 AR_NDP2_TIMER_MODE, 0x0010},
4120 {AR_NEXT_NDP2_TIMER + 5*4, AR_NDP2_PERIOD + 5*4,
4121 AR_NDP2_TIMER_MODE, 0x0020},
4122 {AR_NEXT_NDP2_TIMER + 6*4, AR_NDP2_PERIOD + 6*4,
4123 AR_NDP2_TIMER_MODE, 0x0040},
4124 {AR_NEXT_NDP2_TIMER + 7*4, AR_NDP2_PERIOD + 7*4,
4125 AR_NDP2_TIMER_MODE, 0x0080}
4126};
4127
4128/* HW generic timer primitives */
4129
4130/* compute and clear index of rightmost 1 */
4131static u32 rightmost_index(struct ath_gen_timer_table *timer_table, u32 *mask)
4132{
4133 u32 b;
4134
4135 b = *mask;
4136 b &= (0-b);
4137 *mask &= ~b;
4138 b *= debruijn32;
4139 b >>= 27;
4140
4141 return timer_table->gen_timer_index[b];
4142}
4143
4144static u32 ath9k_hw_gettsf32(struct ath_hw *ah)
4145{
4146 return REG_READ(ah, AR_TSF_L32);
4147}
4148
4149struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
4150 void (*trigger)(void *),
4151 void (*overflow)(void *),
4152 void *arg,
4153 u8 timer_index)
4154{
4155 struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
4156 struct ath_gen_timer *timer;
4157
4158 timer = kzalloc(sizeof(struct ath_gen_timer), GFP_KERNEL);
4159
4160 if (timer == NULL) {
4161 printk(KERN_DEBUG "Failed to allocate memory"
4162 "for hw timer[%d]\n", timer_index);
4163 return NULL;
4164 }
4165
4166 /* allocate a hardware generic timer slot */
4167 timer_table->timers[timer_index] = timer;
4168 timer->index = timer_index;
4169 timer->trigger = trigger;
4170 timer->overflow = overflow;
4171 timer->arg = arg;
4172
4173 return timer;
4174}
4175
4176void ath_gen_timer_start(struct ath_hw *ah,
4177 struct ath_gen_timer *timer,
4178 u32 timer_next, u32 timer_period)
4179{
4180 struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
4181 u32 tsf;
4182
4183 BUG_ON(!timer_period);
4184
4185 set_bit(timer->index, &timer_table->timer_mask.timer_bits);
4186
4187 tsf = ath9k_hw_gettsf32(ah);
4188
4189 DPRINTF(ah->ah_sc, ATH_DBG_HWTIMER, "curent tsf %x period %x"
4190 "timer_next %x\n", tsf, timer_period, timer_next);
4191
4192 /*
4193 * Pull timer_next forward if the current TSF already passed it
4194 * because of software latency
4195 */
4196 if (timer_next < tsf)
4197 timer_next = tsf + timer_period;
4198
4199 /*
4200 * Program generic timer registers
4201 */
4202 REG_WRITE(ah, gen_tmr_configuration[timer->index].next_addr,
4203 timer_next);
4204 REG_WRITE(ah, gen_tmr_configuration[timer->index].period_addr,
4205 timer_period);
4206 REG_SET_BIT(ah, gen_tmr_configuration[timer->index].mode_addr,
4207 gen_tmr_configuration[timer->index].mode_mask);
4208
4209 /* Enable both trigger and thresh interrupt masks */
4210 REG_SET_BIT(ah, AR_IMR_S5,
4211 (SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_THRESH) |
4212 SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_TRIG)));
4213
4214 if ((ah->ah_sc->imask & ATH9K_INT_GENTIMER) == 0) {
4215 ath9k_hw_set_interrupts(ah, 0);
4216 ah->ah_sc->imask |= ATH9K_INT_GENTIMER;
4217 ath9k_hw_set_interrupts(ah, ah->ah_sc->imask);
4218 }
4219}
4220
4221void ath_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
4222{
4223 struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
4224
4225 if ((timer->index < AR_FIRST_NDP_TIMER) ||
4226 (timer->index >= ATH_MAX_GEN_TIMER)) {
4227 return;
4228 }
4229
4230 /* Clear generic timer enable bits. */
4231 REG_CLR_BIT(ah, gen_tmr_configuration[timer->index].mode_addr,
4232 gen_tmr_configuration[timer->index].mode_mask);
4233
4234 /* Disable both trigger and thresh interrupt masks */
4235 REG_CLR_BIT(ah, AR_IMR_S5,
4236 (SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_THRESH) |
4237 SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_TRIG)));
4238
4239 clear_bit(timer->index, &timer_table->timer_mask.timer_bits);
4240
4241 /* if no timer is enabled, turn off interrupt mask */
4242 if (timer_table->timer_mask.val == 0) {
4243 ath9k_hw_set_interrupts(ah, 0);
4244 ah->ah_sc->imask &= ~ATH9K_INT_GENTIMER;
4245 ath9k_hw_set_interrupts(ah, ah->ah_sc->imask);
4246 }
4247}
4248
4249void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer)
4250{
4251 struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
4252
4253 /* free the hardware generic timer slot */
4254 timer_table->timers[timer->index] = NULL;
4255 kfree(timer);
4256}
4257
4258/*
4259 * Generic Timer Interrupts handling
4260 */
4261void ath_gen_timer_isr(struct ath_hw *ah)
4262{
4263 struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
4264 struct ath_gen_timer *timer;
4265 u32 trigger_mask, thresh_mask, index;
4266
4267 /* get hardware generic timer interrupt status */
4268 trigger_mask = ah->intr_gen_timer_trigger;
4269 thresh_mask = ah->intr_gen_timer_thresh;
4270 trigger_mask &= timer_table->timer_mask.val;
4271 thresh_mask &= timer_table->timer_mask.val;
4272
4273 trigger_mask &= ~thresh_mask;
4274
4275 while (thresh_mask) {
4276 index = rightmost_index(timer_table, &thresh_mask);
4277 timer = timer_table->timers[index];
4278 BUG_ON(!timer);
4279 DPRINTF(ah->ah_sc, ATH_DBG_HWTIMER,
4280 "TSF overflow for Gen timer %d\n", index);
4281 timer->overflow(timer->arg);
4282 }
4283
4284 while (trigger_mask) {
4285 index = rightmost_index(timer_table, &trigger_mask);
4286 timer = timer_table->timers[index];
4287 BUG_ON(!timer);
4288 DPRINTF(ah->ah_sc, ATH_DBG_HWTIMER,
4289 "Gen timer[%d] trigger\n", index);
4290 timer->trigger(timer->arg);
4291 }
4292}
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index de10de8370d2..052a9c4ebb92 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -237,6 +237,7 @@ enum ath9k_int {
237 ATH9K_INT_GPIO = 0x01000000, 237 ATH9K_INT_GPIO = 0x01000000,
238 ATH9K_INT_CABEND = 0x02000000, 238 ATH9K_INT_CABEND = 0x02000000,
239 ATH9K_INT_TSFOOR = 0x04000000, 239 ATH9K_INT_TSFOOR = 0x04000000,
240 ATH9K_INT_GENTIMER = 0x08000000,
240 ATH9K_INT_CST = 0x10000000, 241 ATH9K_INT_CST = 0x10000000,
241 ATH9K_INT_GTT = 0x20000000, 242 ATH9K_INT_GTT = 0x20000000,
242 ATH9K_INT_FATAL = 0x40000000, 243 ATH9K_INT_FATAL = 0x40000000,
@@ -390,6 +391,41 @@ struct ath9k_hw_version {
390 u16 analog2GhzRev; 391 u16 analog2GhzRev;
391}; 392};
392 393
394/* Generic TSF timer definitions */
395
396#define ATH_MAX_GEN_TIMER 16
397
398#define AR_GENTMR_BIT(_index) (1 << (_index))
399
400/*
401 * Using de Bruijin sequence to to look up 1's index in a 32 bit number
402 * debruijn32 = 0000 0111 0111 1100 1011 0101 0011 0001
403 */
404#define debruijn32 0x077CB531UL
405
406struct ath_gen_timer_configuration {
407 u32 next_addr;
408 u32 period_addr;
409 u32 mode_addr;
410 u32 mode_mask;
411};
412
413struct ath_gen_timer {
414 void (*trigger)(void *arg);
415 void (*overflow)(void *arg);
416 void *arg;
417 u8 index;
418};
419
420struct ath_gen_timer_table {
421 u32 gen_timer_index[32];
422 struct ath_gen_timer *timers[ATH_MAX_GEN_TIMER];
423 union {
424 unsigned long timer_bits;
425 u16 val;
426 } timer_mask;
427};
428
393struct ath_hw { 429struct ath_hw {
394 struct ath_softc *ah_sc; 430 struct ath_softc *ah_sc;
395 struct ath9k_hw_version hw_version; 431 struct ath9k_hw_version hw_version;
@@ -536,6 +572,10 @@ struct ath_hw {
536 struct ar5416IniArray iniModesAdditional; 572 struct ar5416IniArray iniModesAdditional;
537 struct ar5416IniArray iniModesRxGain; 573 struct ar5416IniArray iniModesRxGain;
538 struct ar5416IniArray iniModesTxGain; 574 struct ar5416IniArray iniModesTxGain;
575
576 u32 intr_gen_timer_trigger;
577 u32 intr_gen_timer_thresh;
578 struct ath_gen_timer_table hw_gen_timers;
539}; 579};
540 580
541/* Initialization, Detach, Reset */ 581/* Initialization, Detach, Reset */
@@ -611,4 +651,16 @@ bool ath9k_hw_intrpend(struct ath_hw *ah);
611bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked); 651bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked);
612enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints); 652enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints);
613 653
654/* Generic hw timer primitives */
655struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
656 void (*trigger)(void *),
657 void (*overflow)(void *),
658 void *arg,
659 u8 timer_index);
660void ath_gen_timer_start(struct ath_hw *ah, struct ath_gen_timer *timer,
661 u32 timer_next, u32 timer_period);
662void ath_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer);
663void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer);
664void ath_gen_timer_isr(struct ath_hw *hw);
665
614#endif 666#endif
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index c9e1ac92d0e9..1d8e0a8b587c 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -234,7 +234,15 @@
234#define AR_IMR_S5 0x00b8 234#define AR_IMR_S5 0x00b8
235#define AR_IMR_S5_TIM_TIMER 0x00000010 235#define AR_IMR_S5_TIM_TIMER 0x00000010
236#define AR_IMR_S5_DTIM_TIMER 0x00000020 236#define AR_IMR_S5_DTIM_TIMER 0x00000020
237 237#define AR_ISR_S5_GENTIMER_TRIG 0x0000FF80
238#define AR_ISR_S5_GENTIMER_TRIG_S 0
239#define AR_ISR_S5_GENTIMER_THRESH 0xFF800000
240#define AR_ISR_S5_GENTIMER_THRESH_S 16
241#define AR_ISR_S5_S 0x00d8
242#define AR_IMR_S5_GENTIMER_TRIG 0x0000FF80
243#define AR_IMR_S5_GENTIMER_TRIG_S 0
244#define AR_IMR_S5_GENTIMER_THRESH 0xFF800000
245#define AR_IMR_S5_GENTIMER_THRESH_S 16
238 246
239#define AR_IMR 0x00a0 247#define AR_IMR 0x00a0
240#define AR_IMR_RXOK 0x00000001 248#define AR_IMR_RXOK 0x00000001
@@ -1516,7 +1524,10 @@ enum {
1516#define AR_TXOP_8_11 0x81f8 1524#define AR_TXOP_8_11 0x81f8
1517#define AR_TXOP_12_15 0x81fc 1525#define AR_TXOP_12_15 0x81fc
1518 1526
1519 1527#define AR_NEXT_NDP2_TIMER 0x8180
1528#define AR_FIRST_NDP_TIMER 7
1529#define AR_NDP2_PERIOD 0x81a0
1530#define AR_NDP2_TIMER_MODE 0x81c0
1520#define AR_NEXT_TBTT_TIMER 0x8200 1531#define AR_NEXT_TBTT_TIMER 0x8200
1521#define AR_NEXT_DMA_BEACON_ALERT 0x8204 1532#define AR_NEXT_DMA_BEACON_ALERT 0x8204
1522#define AR_NEXT_SWBA 0x8208 1533#define AR_NEXT_SWBA 0x8208