qca / open-ath9k-htc-firmware

The firmware for QCA AR7010/AR9271 802.11n USB NICs
Other
429 stars 182 forks source link

Firmware sometimes returns erroneous timestamps (PATCH) #66

Open IanR778 opened 9 years ago

IanR778 commented 9 years ago

Firmware sometimes returns erroneous timestamps. This is caused by lack of proper synchronization while handling lower 32 bit and upper 32 bit parts in ar5416GetTsf64(), and incorrect wrapping handling in ath_extend_tsf(). Please consider applying the following patch:

diff --git a/target_firmware/wlan/ar5416_hw.c b/target_firmware/wlan/ar5416_hw.c
index 3f3c4bc..4b501b1 100644
--- a/target_firmware/wlan/ar5416_hw.c
+++ b/target_firmware/wlan/ar5416_hw.c
@@ -275,14 +275,23 @@ ar5416SetInterrupts(struct ath_hal *ah, HAL_INT ints)
 /* TSF Handling */
 /****************/

+#define ATH9K_HTC_MAX_TSF_READ 3
+
 u_int64_t ar5416GetTsf64(struct ath_hal *ah)
 {
-        u_int64_t tsf;
+   a_uint32_t tsf_lower, tsf_upper1, tsf_upper2;
+   a_int32_t i;

-   tsf = ioread32_mac(AR_TSF_U32);
-   tsf = (tsf << 32) | ioread32_mac(AR_TSF_L32);
+   tsf_upper1 = ioread32_mac(AR_TSF_U32);
+   for (i = 0; i < ATH9K_HTC_MAX_TSF_READ; i++) {
+       tsf_lower = ioread32_mac(AR_TSF_L32);
+       tsf_upper2 = ioread32_mac(AR_TSF_U32);
+       if (tsf_upper2 == tsf_upper1)
+           break;
+       tsf_upper1 = tsf_upper2;
+   }

-        return tsf;
+        return (((u_int64_t)tsf_upper1 << 32U) | tsf_lower);
 }

 /******/
diff --git a/target_firmware/wlan/if_ath.c b/target_firmware/wlan/if_ath.c
index 864f48f..206b5c0 100755
--- a/target_firmware/wlan/if_ath.c
+++ b/target_firmware/wlan/if_ath.c
@@ -88,20 +88,13 @@ static u_int64_t ath_extend_tsf(struct ath_softc_tgt *sc, u_int32_t rstamp)
 {
    struct ath_hal *ah = sc->sc_ah;
    u_int64_t tsf;
-   u_int32_t tsf_low;
-   u_int64_t tsf64;

    tsf = ah->ah_getTsf64(ah);
-   tsf_low = tsf & 0xffffffff;
-   tsf64 = (tsf & ~0xffffffffULL) | rstamp;

-   if (rstamp > tsf_low && (rstamp - tsf_low > 0x10000000))
-       tsf64 -= 0x100000000ULL;
+   if (rstamp > (tsf & 0xffffffffULL))
+       tsf -= 0x100000000ULL;

-   if (rstamp < tsf_low && (tsf_low - rstamp > 0x10000000))
-       tsf64 += 0x100000000ULL;
-
-   return tsf64;
+   return ((tsf & ~0xffffffffULL) | rstamp);
 }

 static a_int32_t ath_rate_setup(struct ath_softc_tgt *sc, a_uint32_t mode)