aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath5k/pcu.c
diff options
context:
space:
mode:
authorJohn W. Linville <linville@tuxdriver.com>2010-10-01 11:12:36 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-10-01 11:12:36 -0400
commit41f4a6f71fe33faa7971c173c263fb431fe987fe (patch)
treefdc3e603162e3ad63f6ae4160f68eb803bb78d58 /drivers/net/wireless/ath/ath5k/pcu.c
parent94d57c4cfaa43e29ca5fa5ff874048cfc67276f5 (diff)
parent1728943d83e9fd919e454332fe344944123b3c3a (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6 into for-davem
Diffstat (limited to 'drivers/net/wireless/ath/ath5k/pcu.c')
-rw-r--r--drivers/net/wireless/ath/ath5k/pcu.c99
1 files changed, 98 insertions, 1 deletions
diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c
index 6a891c4484a0..095d30b50ec7 100644
--- a/drivers/net/wireless/ath/ath5k/pcu.c
+++ b/drivers/net/wireless/ath/ath5k/pcu.c
@@ -495,6 +495,10 @@ u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah)
495{ 495{
496 u32 tsf_lower, tsf_upper1, tsf_upper2; 496 u32 tsf_lower, tsf_upper1, tsf_upper2;
497 int i; 497 int i;
498 unsigned long flags;
499
500 /* This code is time critical - we don't want to be interrupted here */
501 local_irq_save(flags);
498 502
499 /* 503 /*
500 * While reading TSF upper and then lower part, the clock is still 504 * While reading TSF upper and then lower part, the clock is still
@@ -517,6 +521,8 @@ u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah)
517 tsf_upper1 = tsf_upper2; 521 tsf_upper1 = tsf_upper2;
518 } 522 }
519 523
524 local_irq_restore(flags);
525
520 WARN_ON( i == ATH5K_MAX_TSF_READ ); 526 WARN_ON( i == ATH5K_MAX_TSF_READ );
521 527
522 return (((u64)tsf_upper1 << 32) | tsf_lower); 528 return (((u64)tsf_upper1 << 32) | tsf_lower);
@@ -600,7 +606,7 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
600 /* Timer3 marks the end of our ATIM window 606 /* Timer3 marks the end of our ATIM window
601 * a zero length window is not allowed because 607 * a zero length window is not allowed because
602 * we 'll get no beacons */ 608 * we 'll get no beacons */
603 timer3 = next_beacon + (ah->ah_atim_window ? ah->ah_atim_window : 1); 609 timer3 = next_beacon + 1;
604 610
605 /* 611 /*
606 * Set the beacon register and enable all timers. 612 * Set the beacon register and enable all timers.
@@ -641,6 +647,97 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
641} 647}
642 648
643/** 649/**
650 * ath5k_check_timer_win - Check if timer B is timer A + window
651 *
652 * @a: timer a (before b)
653 * @b: timer b (after a)
654 * @window: difference between a and b
655 * @intval: timers are increased by this interval
656 *
657 * This helper function checks if timer B is timer A + window and covers
658 * cases where timer A or B might have already been updated or wrapped
659 * around (Timers are 16 bit).
660 *
661 * Returns true if O.K.
662 */
663static inline bool
664ath5k_check_timer_win(int a, int b, int window, int intval)
665{
666 /*
667 * 1.) usually B should be A + window
668 * 2.) A already updated, B not updated yet
669 * 3.) A already updated and has wrapped around
670 * 4.) B has wrapped around
671 */
672 if ((b - a == window) || /* 1.) */
673 (a - b == intval - window) || /* 2.) */
674 ((a | 0x10000) - b == intval - window) || /* 3.) */
675 ((b | 0x10000) - a == window)) /* 4.) */
676 return true; /* O.K. */
677 return false;
678}
679
680/**
681 * ath5k_hw_check_beacon_timers - Check if the beacon timers are correct
682 *
683 * @ah: The &struct ath5k_hw
684 * @intval: beacon interval
685 *
686 * This is a workaround for IBSS mode:
687 *
688 * The need for this function arises from the fact that we have 4 separate
689 * HW timer registers (TIMER0 - TIMER3), which are closely related to the
690 * next beacon target time (NBTT), and that the HW updates these timers
691 * seperately based on the current TSF value. The hardware increments each
692 * timer by the beacon interval, when the local TSF coverted to TU is equal
693 * to the value stored in the timer.
694 *
695 * The reception of a beacon with the same BSSID can update the local HW TSF
696 * at any time - this is something we can't avoid. If the TSF jumps to a
697 * time which is later than the time stored in a timer, this timer will not
698 * be updated until the TSF in TU wraps around at 16 bit (the size of the
699 * timers) and reaches the time which is stored in the timer.
700 *
701 * The problem is that these timers are closely related to TIMER0 (NBTT) and
702 * that they define a time "window". When the TSF jumps between two timers
703 * (e.g. ATIM and NBTT), the one in the past will be left behind (not
704 * updated), while the one in the future will be updated every beacon
705 * interval. This causes the window to get larger, until the TSF wraps
706 * around as described above and the timer which was left behind gets
707 * updated again. But - because the beacon interval is usually not an exact
708 * divisor of the size of the timers (16 bit), an unwanted "window" between
709 * these timers has developed!
710 *
711 * This is especially important with the ATIM window, because during
712 * the ATIM window only ATIM frames and no data frames are allowed to be
713 * sent, which creates transmission pauses after each beacon. This symptom
714 * has been described as "ramping ping" because ping times increase linearly
715 * for some time and then drop down again. A wrong window on the DMA beacon
716 * timer has the same effect, so we check for these two conditions.
717 *
718 * Returns true if O.K.
719 */
720bool
721ath5k_hw_check_beacon_timers(struct ath5k_hw *ah, int intval)
722{
723 unsigned int nbtt, atim, dma;
724
725 nbtt = ath5k_hw_reg_read(ah, AR5K_TIMER0);
726 atim = ath5k_hw_reg_read(ah, AR5K_TIMER3);
727 dma = ath5k_hw_reg_read(ah, AR5K_TIMER1) >> 3;
728
729 /* NOTE: SWBA is different. Having a wrong window there does not
730 * stop us from sending data and this condition is catched thru
731 * other means (SWBA interrupt) */
732
733 if (ath5k_check_timer_win(nbtt, atim, 1, intval) &&
734 ath5k_check_timer_win(dma, nbtt, AR5K_TUNE_DMA_BEACON_RESP,
735 intval))
736 return true; /* O.K. */
737 return false;
738}
739
740/**
644 * ath5k_hw_set_coverage_class - Set IEEE 802.11 coverage class 741 * ath5k_hw_set_coverage_class - Set IEEE 802.11 coverage class
645 * 742 *
646 * @ah: The &struct ath5k_hw 743 * @ah: The &struct ath5k_hw