add preliminary 2.6.32 support
[openwrt.git] / package / madwifi / patches / 375-atim_tsf_update.patch
1 --- a/ath/if_ath.c
2 +++ b/ath/if_ath.c
3 @@ -161,6 +161,7 @@ static void ath_beacon_send(struct ath_s
4  static void ath_beacon_return(struct ath_softc *, struct ath_buf *);
5  static void ath_beacon_free(struct ath_softc *);
6  static void ath_beacon_config(struct ath_softc *, struct ieee80211vap *);
7 +static void ath_hw_beacon_stop(struct ath_softc *sc);
8  static int ath_desc_alloc(struct ath_softc *);
9  static void ath_desc_free(struct ath_softc *);
10  static void ath_desc_swap(struct ath_desc *);
11 @@ -2793,6 +2794,72 @@ ath_set_ack_bitrate(struct ath_softc *sc
12         return 1;
13  }
14  
15 +static void
16 +ath_hw_beacon_stop(struct ath_softc *sc)
17 +{
18 +       HAL_BEACON_TIMERS btimers;
19 +
20 +       btimers.bt_intval = 0;
21 +       btimers.bt_nexttbtt = 0;
22 +       btimers.bt_nextdba = 0xffffffff;
23 +       btimers.bt_nextswba = 0xffffffff;
24 +       btimers.bt_nextatim = 0;
25 +
26 +       ath_hal_setbeacontimers(sc->sc_ah, &btimers);
27 +}
28 +
29 +/* Fix up the ATIM window after TSF resync */
30 +static int
31 +ath_hw_check_atim(struct ath_softc *sc, int window, int intval)
32 +{
33 +#define AR5K_TIMER0_5210       0x802c  /* Next beacon time register */
34 +#define AR5K_TIMER0_5211       0x8028
35 +#define AR5K_TIMER3_5210       0x8038  /* End of ATIM window time register */
36 +#define AR5K_TIMER3_5211       0x8034
37 +       struct ath_hal *ah = sc->sc_ah;
38 +       int dev = sc->sc_ah->ah_macType;
39 +       unsigned int nbtt, atim;
40 +       int is_5210 = 0;
41 +
42 +       /*
43 +        * check if the ATIM window is still correct:
44 +        *   1.) usually ATIM should be NBTT + window
45 +        *   2.) nbtt already updated
46 +        *   3.) nbtt already updated and has wrapped around
47 +        *   4.) atim has wrapped around
48 +        */
49 +       switch(dev) {
50 +       case 5210:
51 +               nbtt = OS_REG_READ(ah, AR5K_TIMER0_5210);
52 +               atim = OS_REG_READ(ah, AR5K_TIMER3_5210);
53 +               is_5210 = 1;
54 +               break;
55 +       case 5211:
56 +       case 5212:
57 +               nbtt = OS_REG_READ(ah, AR5K_TIMER0_5211);
58 +               atim = OS_REG_READ(ah, AR5K_TIMER3_5211);
59 +               break;
60 +       /* NB: 5416+ doesn't do ATIM in hw */
61 +       case 5416:
62 +       default:
63 +               return 0;
64 +       }
65 +
66 +       if ((atim - nbtt != window) &&                          /* 1.) */
67 +           (nbtt - atim != intval - window) &&                 /* 2.) */
68 +           ((nbtt | 0x10000) - atim != intval - window) &&     /* 3.) */
69 +           ((atim | 0x10000) - nbtt != window)) {              /* 4.) */
70 +               if (is_5210)
71 +                       OS_REG_WRITE(ah, AR5K_TIMER3_5210, nbtt + window );
72 +               else
73 +                       OS_REG_WRITE(ah, AR5K_TIMER3_5211, nbtt + window );
74 +               return atim - nbtt;
75 +       }
76 +
77 +       return 0;
78 +}
79 +
80 +
81  /*
82   * Reset the hardware w/o losing operational state.  This is
83   * basically a more efficient way of doing ath_stop, ath_init,
84 @@ -5294,6 +5361,7 @@ ath_beacon_config(struct ath_softc *sc, 
85         u_int64_t tsf, hw_tsf;
86         u_int32_t tsftu, hw_tsftu;
87         u_int32_t intval, nexttbtt = 0;
88 +       unsigned long flags;
89         int reset_tsf = 0;
90  
91         if (vap == NULL)
92 @@ -5301,6 +5369,9 @@ ath_beacon_config(struct ath_softc *sc, 
93  
94         ni = vap->iv_bss;
95  
96 +       /* TSF calculation is timing critical - we don't want to be interrupted here */
97 +       local_irq_save(flags);
98 +
99         hw_tsf = ath_hal_gettsf64(ah);
100         tsf = le64_to_cpu(ni->ni_tstamp.tsf);
101         hw_tsftu = hw_tsf >> 10;
102 @@ -5490,15 +5561,27 @@ ath_beacon_config(struct ath_softc *sc, 
103                                 <= ath_hal_sw_beacon_response_time)
104                         nexttbtt += intval;
105                 sc->sc_nexttbtt = nexttbtt;
106 +
107 +               /* stop beacons before reconfiguring the timers to avoid race
108 +                * conditions. ath_hal_beaconinit will start them again */
109 +               ath_hw_beacon_stop(sc);
110 +
111                 ath_hal_beaconinit(ah, nexttbtt, intval);
112                 if (intval & HAL_BEACON_RESET_TSF) {
113                         sc->sc_last_tsf = 0;
114                 }
115                 sc->sc_bmisscount = 0;
116                 ath_hal_intrset(ah, sc->sc_imask);
117 +
118 +               if ((sc->sc_opmode == HAL_M_IBSS) && ath_hw_check_atim(sc, 1, intval & HAL_BEACON_PERIOD)) {
119 +                       DPRINTF(sc, ATH_DEBUG_BEACON,
120 +                               "fixed atim window after beacon init\n");
121 +               }
122         }
123  
124  ath_beacon_config_debug:
125 +       local_irq_restore(flags);
126 +
127         /* We print all debug messages here, in order to preserve the
128          * time critical aspect of this function */
129         DPRINTF(sc, ATH_DEBUG_BEACON,
130 @@ -6401,6 +6484,11 @@ ath_recv_mgmt(struct ieee80211vap * vap,
131                         DPRINTF(sc, ATH_DEBUG_BEACON, 
132                                 "Updated beacon timers\n");
133                 }
134 +               if ((sc->sc_opmode == HAL_M_IBSS) &&
135 +                               IEEE80211_ADDR_EQ(ni->ni_bssid, vap->iv_bss->ni_bssid) &&
136 +                               ath_hw_check_atim(sc, 1, vap->iv_bss->ni_intval)) {
137 +                       DPRINTF(sc, ATH_DEBUG_ANY, "Fixed ATIM window after beacon recv\n");
138 +               }
139                 /* NB: Fall Through */
140         case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
141                 if (vap->iv_opmode == IEEE80211_M_IBSS &&