build: create pkginfo dir earlier to avoid build breakage
[openwrt.git] / package / madwifi / patches / 389-autochannel.patch
1 --- a/ath/if_ath.c
2 +++ b/ath/if_ath.c
3 @@ -384,6 +384,7 @@ static u_int32_t ath_get_real_maxtxpower
4  
5  static void ath_poll_disable(struct net_device *dev);
6  static void ath_poll_enable(struct net_device *dev);
7 +static void ath_fetch_idle_time(struct ath_softc *sc);
8  
9  /* calibrate every 30 secs in steady state but check every second at first. */
10  static int ath_calinterval = ATH_SHORT_CALINTERVAL;
11 @@ -2581,6 +2582,7 @@ ath_init(struct net_device *dev)
12          * be followed by initialization of the appropriate bits
13          * and then setup of the interrupt mask.
14          */
15 +       ath_fetch_idle_time(sc);
16         sc->sc_curchan.channel = ic->ic_curchan->ic_freq;
17         sc->sc_curchan.channelFlags = ath_chan2flags(ic->ic_curchan);
18         if (!ath_hal_reset(ah, sc->sc_opmode, &sc->sc_curchan, AH_FALSE, &status)) {
19 @@ -2914,6 +2916,48 @@ ath_hw_check_atim(struct ath_softc *sc,
20         return 0;
21  }
22  
23 +#define AR5K_MIBC       0x0040
24 +#define AR5K_MIBC_FREEZE   (1 << 1)
25 +#define AR5K_TXFC       0x80ec
26 +#define AR5K_RXFC       0x80f0
27 +#define AR5K_RXCLEAR   0x80f4
28 +#define AR5K_CYCLES            0x80f8
29 +static void
30 +ath_fetch_idle_time(struct ath_softc *sc)
31 +{
32 +       struct ieee80211com *ic = &sc->sc_ic;
33 +       struct ath_hal *ah = sc->sc_ah;
34 +       u_int32_t cc, rx;
35 +       u_int32_t time = 0;
36 +
37 +       if (sc->sc_ah->ah_macType < 5212)
38 +               return;
39 +
40 +       if (!ic->ic_curchan || (ic->ic_curchan == IEEE80211_CHAN_ANYC))
41 +               return;
42 +
43 +       OS_REG_WRITE(ah, AR5K_MIBC, AR5K_MIBC_FREEZE);
44 +       rx = OS_REG_READ(ah, AR5K_RXCLEAR);
45 +       cc = OS_REG_READ(ah, AR5K_CYCLES);
46 +
47 +       if (!cc)
48 +               return;
49 +
50 +       if (rx > cc)
51 +               return; /* should not happen */
52 +
53 +       if (sc->sc_last_chan)
54 +               sc->sc_last_chan->ic_idletime = 100 * (cc - rx) / cc;
55 +       sc->sc_last_chan = ic->ic_curchan;
56 +
57 +       OS_REG_WRITE(ah, AR5K_RXCLEAR, 0);
58 +       OS_REG_WRITE(ah, AR5K_CYCLES, 0);
59 +       OS_REG_WRITE(ah, AR5K_TXFC, 0);
60 +       OS_REG_WRITE(ah, AR5K_RXFC, 0);
61 +       OS_REG_WRITE(ah, AR5K_MIBC, 0);
62 +}
63 +#undef AR5K_RXCLEAR
64 +#undef AR5K_CYCLES
65  
66  /*
67   * Reset the hardware w/o losing operational state.  This is
68 @@ -2941,6 +2985,7 @@ ath_reset(struct net_device *dev)
69          * Convert to a HAL channel description with the flags
70          * constrained to reflect the current operating mode.
71          */
72 +       ath_fetch_idle_time(sc);
73         c = ic->ic_curchan;
74         sc->sc_curchan.channel = c->ic_freq;
75         sc->sc_curchan.channelFlags = ath_chan2flags(c);
76 @@ -9023,6 +9068,7 @@ ath_chan_set(struct ath_softc *sc, struc
77         u_int8_t channel_change_required = 0;
78         struct timeval tv;
79  
80 +
81         /*
82          * Convert to a HAL channel description with
83          * the flags constrained to reflect the current
84 @@ -9031,6 +9077,14 @@ ath_chan_set(struct ath_softc *sc, struc
85         memset(&hchan, 0, sizeof(HAL_CHANNEL));
86         hchan.channel = chan->ic_freq;
87         hchan.channelFlags = ath_chan2flags(chan);
88 +
89 +       /* don't do duplicate channel changes, but do
90 +        * store the available idle time */
91 +       ath_fetch_idle_time(sc);
92 +       if ((sc->sc_curchan.channel == hchan.channel) &&
93 +               (sc->sc_curchan.channelFlags == hchan.channelFlags))
94 +               return 0;
95 +
96         KASSERT(hchan.channel != 0,
97                 ("bogus channel %u/0x%x", hchan.channel, hchan.channelFlags));
98         do_gettimeofday(&tv);
99 --- a/ath/if_athvar.h
100 +++ b/ath/if_athvar.h
101 @@ -774,6 +774,7 @@ struct ath_softc {
102         struct ieee80211vap **sc_bslot;         /* beacon xmit slots */
103         int sc_bnext;                           /* next slot for beacon xmit */
104  
105 +       struct ieee80211_channel *sc_last_chan;
106         int sc_beacon_cal;                      /* use beacon timer for calibration */
107         u_int64_t sc_lastcal;                   /* last time the calibration was performed */
108         struct timer_list sc_cal_ch;            /* calibration timer */
109 --- a/net80211/_ieee80211.h
110 +++ b/net80211/_ieee80211.h
111 @@ -148,6 +148,7 @@ struct ieee80211_channel {
112         int8_t ic_maxpower;     /* maximum tx power in dBm */
113         int8_t ic_minpower;     /* minimum tx power in dBm */
114         u_int8_t ic_scanflags;
115 +       u_int8_t ic_idletime; /* phy idle time in % */
116  };
117  
118  #define        IEEE80211_CHAN_MAX      255
119 --- a/net80211/ieee80211_scan_ap.c
120 +++ b/net80211/ieee80211_scan_ap.c
121 @@ -417,6 +417,19 @@ pc_cmp_rssi(struct ap_state *as, struct
122  
123  /* This function must be invoked with locks acquired */
124  static int
125 +pc_cmp_idletime(struct ieee80211_channel *a,
126 +               struct ieee80211_channel *b)
127 +{
128 +       if (!a->ic_idletime || !b->ic_idletime)
129 +               return 0;
130 +
131 +       /* a is better than b (return < 0) when a has more idle time than b */
132 +       return b->ic_idletime - a->ic_idletime;
133 +}
134 +
135 +
136 +/* This function must be invoked with locks acquired */
137 +static int
138  pc_cmp_samechan(struct ieee80211com *ic, struct ieee80211_channel *a,
139                 struct ieee80211_channel *b)
140  {
141 @@ -451,6 +464,7 @@ pc_cmp(const void *_a, const void *_b)
142  
143         EVALUATE_CRITERION(radar, a, b);
144         EVALUATE_CRITERION(keepmode, params, a, b);
145 +       EVALUATE_CRITERION(idletime, a, b);
146         EVALUATE_CRITERION(sc, ic, a, b);
147         /* XXX: rssi useless? pick_channel evaluates it anyway */
148         EVALUATE_CRITERION(rssi, params->ss->ss_priv, a, b);
149 @@ -519,16 +533,9 @@ pick_channel(struct ieee80211_scan_state
150  #endif
151  
152         best = NULL;
153 -       best_rssi = 0xff; /* If signal is bigger than 0xff, we'd be melting. */
154  
155         for (i = 0; i < ss_last; i++) {
156                 c = &chans[i];
157 -               benefit = best_rssi - as->as_maxrssi[c->chan->ic_ieee];
158 -               sta_assoc = ic->ic_sta_assoc;
159 -
160 -               /* Don't switch... */
161 -               if (benefit <= 0)
162 -                       continue;
163  
164                 /* Verify channel is not marked for non-occupancy */
165                 if (IEEE80211_IS_CHAN_RADAR(c->chan))
166 @@ -546,31 +553,8 @@ pick_channel(struct ieee80211_scan_state
167                                 break;
168                 }
169  
170 -               if (sta_assoc != 0) {
171 -                       int sl = ic->ic_cn_total - 
172 -                               ic->ic_chan_nodes[c->chan->ic_ieee]; /* count */
173 -                       if (ic->ic_sc_algorithm == IEEE80211_SC_LOOSE) {
174 -                               int sl_max = ic->ic_sc_sldg * benefit;
175 -                               sl = 1000 * sl / sta_assoc; /* permil */
176 -                               IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
177 -                                               "%s: chan %d, dB gained: %d, "
178 -                                               "STAs lost: %d permil (max %d)\n",
179 -                                               __func__, c->chan->ic_ieee, 
180 -                                               benefit, sl, sl_max);
181 -                               if (sl > sl_max)
182 -                                       continue;
183 -                       } else if (((ic->ic_sc_algorithm == 
184 -                                                IEEE80211_SC_TIGHT) ||
185 -                                       (ic->ic_sc_algorithm == 
186 -                                                IEEE80211_SC_STRICT)) && 
187 -                                       (sl > 0)) {
188 -                               /* Break the loop as the subsequent chans 
189 -                                * won't be better. */
190 -                               break;
191 -                       }
192 -               }
193                 best = c->chan;
194 -               best_rssi = as->as_maxrssi[best->ic_ieee];
195 +               break;
196         }
197  
198         if (best != NULL) {
199 @@ -599,6 +583,9 @@ ap_end(struct ieee80211_scan_state *ss,
200                 ("wrong opmode %u", vap->iv_opmode));
201  
202         ic = vap->iv_ic;
203 +
204 +       /* record stats for the channel that was scanned last */
205 +       ic->ic_set_channel(ic);
206         bestchan = pick_channel(ss, vap, flags);
207         if (bestchan == NULL) {
208                 if (ss->ss_last > 0) {
209 --- a/net80211/ieee80211_scan.c
210 +++ b/net80211/ieee80211_scan.c
211 @@ -1002,20 +1002,34 @@ ieee80211_scan_add_channels(struct ieee8
212  {
213         struct ieee80211_channel *c, *cg;
214         u_int modeflags;
215 +       int has_non_turbo = 0;
216         int i;
217  
218         KASSERT(mode < ARRAY_SIZE(chanflags), ("Unexpected mode %u", mode));
219         modeflags = chanflags[mode];
220         for (i = 0; i < ic->ic_nchans; i++) {
221                 c = &ic->ic_channels[i];
222 +               if (c->ic_flags & (IEEE80211_CHAN_TURBO | IEEE80211_CHAN_STURBO))
223 +                       continue;
224 +
225 +               has_non_turbo = 1;
226 +               break;
227 +       }
228 +       for (i = 0; i < ic->ic_nchans; i++) {
229 +               c = &ic->ic_channels[i];
230                 if (c == NULL || isclr(ic->ic_chan_active, c->ic_ieee))
231                         continue;
232                 if (c->ic_scanflags & IEEE80211_NOSCAN_SET)
233                         continue;
234 -               if (modeflags &&
235 -                       ((c->ic_flags & IEEE80211_CHAN_ALLTURBO) !=
236 -                        (modeflags & IEEE80211_CHAN_ALLTURBO)))
237 -                       continue;
238 +               if (modeflags) {
239 +                       if ((c->ic_flags & IEEE80211_CHAN_ALLTURBO) !=
240 +                                (modeflags & IEEE80211_CHAN_ALLTURBO))
241 +                               continue;
242 +               } else if (has_non_turbo) {
243 +                       if ((ss->ss_vap->iv_opmode == IEEE80211_M_HOSTAP) &&
244 +                               (c->ic_flags & (IEEE80211_CHAN_TURBO | IEEE80211_CHAN_STURBO)))
245 +                               continue;
246 +               }
247                 if (mode == IEEE80211_MODE_AUTO) {
248                         /*
249                          * XXX special-case 11b/g channels so we select