madwifi patch cleanup and stability fixes
[openwrt/svn-archive/archive.git] / package / madwifi / patches / 375-atim_tsf_update.patch
index bbe380ed47d4626be03fc142ee68b424eac0da51..3800b90c1bbd60fc809faae6beb2e89f940e4b8a 100644 (file)
@@ -1,43 +1,79 @@
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -2785,6 +2785,44 @@
+@@ -161,6 +161,7 @@
+ static void ath_beacon_return(struct ath_softc *, struct ath_buf *);
+ static void ath_beacon_free(struct ath_softc *);
+ static void ath_beacon_config(struct ath_softc *, struct ieee80211vap *);
++static void ath_hw_beacon_stop(struct ath_softc *sc);
+ static int ath_desc_alloc(struct ath_softc *);
+ static void ath_desc_free(struct ath_softc *);
+ static void ath_desc_swap(struct ath_desc *);
+@@ -2783,6 +2784,72 @@
        return 1;
  }
  
++static void
++ath_hw_beacon_stop(struct ath_softc *sc)
++{
++      HAL_BEACON_TIMERS btimers;
++
++      btimers.bt_intval = 0;
++      btimers.bt_nexttbtt = 0;
++      btimers.bt_nextdba = 0xffffffff;
++      btimers.bt_nextswba = 0xffffffff;
++      btimers.bt_nextatim = 0;
++
++      ath_hal_setbeacontimers(sc->sc_ah, &btimers);
++}
++
 +/* Fix up the ATIM window after TSF resync */
 +static int
-+ath_hw_check_atim(struct ath_softc *sc, int window)
++ath_hw_check_atim(struct ath_softc *sc, int window, int intval)
 +{
 +#define AR5K_TIMER0_5210       0x802c  /* Next beacon time register */
 +#define AR5K_TIMER0_5211       0x8028
 +#define AR5K_TIMER3_5210       0x8038  /* End of ATIM window time register */
 +#define AR5K_TIMER3_5211       0x8034
 +      struct ath_hal *ah = sc->sc_ah;
++      int dev = sc->sc_ah->ah_macType;
 +      unsigned int nbtt, atim;
-+      int dev = ar_device(sc->devid);
++      bool is_5210 = false;
 +
++      /*
++       * check if the ATIM window is still correct:
++       *   1.) usually ATIM should be NBTT + window
++       *   2.) nbtt already updated
++       *   3.) nbtt already updated and has wrapped around
++       *   4.) atim has wrapped around
++       */
 +      switch(dev) {
 +      case 5210:
 +              nbtt = OS_REG_READ(ah, AR5K_TIMER0_5210);
 +              atim = OS_REG_READ(ah, AR5K_TIMER3_5210);
-+              if (atim - nbtt != window) {
-+                      OS_REG_WRITE(ah, AR5K_TIMER3_5210, nbtt + window );
-+                      return atim - nbtt;
-+              }
++              is_5210 = true;
 +              break;
 +      case 5211:
 +      case 5212:
 +              nbtt = OS_REG_READ(ah, AR5K_TIMER0_5211);
 +              atim = OS_REG_READ(ah, AR5K_TIMER3_5211);
-+              if (atim - nbtt != window) {
-+                      OS_REG_WRITE(ah, AR5K_TIMER3_5211, nbtt + window );
-+                      return atim - nbtt;
-+              }
 +              break;
 +      /* NB: 5416+ doesn't do ATIM in hw */
++      case 5416:
 +      default:
-+              break;
++              return 0;
++      }
++
++      if ((atim - nbtt != window) &&                          /* 1.) */
++          (nbtt - atim != intval - window) &&                 /* 2.) */
++          ((nbtt | 0x10000) - atim != intval - window) &&     /* 3.) */
++          ((atim | 0x10000) - nbtt != window)) {              /* 4.) */
++              if (is_5210)
++                      OS_REG_WRITE(ah, AR5K_TIMER3_5210, nbtt + window );
++              else
++                      OS_REG_WRITE(ah, AR5K_TIMER3_5211, nbtt + window );
++              return atim - nbtt;
 +      }
++
 +      return 0;
 +}
 +
  /*
   * Reset the hardware w/o losing operational state.  This is
   * basically a more efficient way of doing ath_stop, ath_init,
-@@ -6391,6 +6429,11 @@
+@@ -5282,6 +5349,7 @@
+       u_int64_t tsf, hw_tsf;
+       u_int32_t tsftu, hw_tsftu;
+       u_int32_t intval, nexttbtt = 0;
++      unsigned long flags;
+       int reset_tsf = 0;
+       if (vap == NULL)
+@@ -5289,6 +5357,9 @@
+       ni = vap->iv_bss;
++      /* TSF calculation is timing critical - we don't want to be interrupted here */
++      local_irq_save(flags);
++
+       hw_tsf = ath_hal_gettsf64(ah);
+       tsf = le64_to_cpu(ni->ni_tstamp.tsf);
+       hw_tsftu = hw_tsf >> 10;
+@@ -5478,15 +5549,27 @@
+                               <= ath_hal_sw_beacon_response_time)
+                       nexttbtt += intval;
+               sc->sc_nexttbtt = nexttbtt;
++
++              /* stop beacons before reconfiguring the timers to avoid race
++               * conditions. ath_hal_beaconinit will start them again */
++              ath_hw_beacon_stop(sc);
++
+               ath_hal_beaconinit(ah, nexttbtt, intval);
+               if (intval & HAL_BEACON_RESET_TSF) {
+                       sc->sc_last_tsf = 0;
+               }
+               sc->sc_bmisscount = 0;
+               ath_hal_intrset(ah, sc->sc_imask);
++
++              if (ath_hw_check_atim(sc, 1, intval & HAL_BEACON_PERIOD)) {
++                      DPRINTF(sc, ATH_DEBUG_BEACON,
++                              "fixed atim window after beacon init\n");
++              }
+       }
+ ath_beacon_config_debug:
++      local_irq_restore(flags);
++
+       /* We print all debug messages here, in order to preserve the
+        * time critical aspect of this function */
+       DPRINTF(sc, ATH_DEBUG_BEACON,
+@@ -6389,6 +6472,11 @@
                        DPRINTF(sc, ATH_DEBUG_BEACON, 
                                "Updated beacon timers\n");
                }
 +              if ((sc->sc_opmode == IEEE80211_M_IBSS) &&
 +                              IEEE80211_ADDR_EQ(ni->ni_bssid, vap->iv_bss->ni_bssid) &&
-+                              ath_hw_check_atim(sc, 1)) {
++                              ath_hw_check_atim(sc, 1, vap->iv_bss->ni_intval)) {
 +                      DPRINTF(sc, ATH_DEBUG_ANY, "Fixed ATIM window after beacon recv\n");
 +              }
                /* NB: Fall Through */