rc80211-pid: fix rate adjustment
authorStefano Brivio <stefano.brivio@polimi.it>
Sun, 2 Mar 2008 10:33:10 +0000 (11:33 +0100)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 4 Mar 2008 23:36:35 +0000 (18:36 -0500)
Merge rate_control_pid_shift_adjust() to rate_control_pid_adjust_rate()
in order to make the learning algorithm aware of constraints on rates. Also
add some comments and rename variables.

This fixes a bug which prevented 802.11b/g non-AP STAs from working with
802.11b only AP STAs.

This patch was originally destined for 2.6.26, and is being backported
to fix a user reported problem in post-2.6.24 kernels.

Signed-off-by: Stefano Brivio <stefano.brivio@polimi.it>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
net/mac80211/rc80211_pid_algo.c

index c339571..3b77410 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright 2002-2005, Instant802 Networks, Inc.
  * Copyright 2005, Devicescape Software, Inc.
  * Copyright 2007, Mattias Nissler <mattias.nissler@gmx.de>
- * Copyright 2007, Stefano Brivio <stefano.brivio@polimi.it>
+ * Copyright 2007-2008, Stefano Brivio <stefano.brivio@polimi.it>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * RC_PID_ARITH_SHIFT.
  */
 
-
-/* Shift the adjustment so that we won't switch to a lower rate if it exhibited
- * a worse failed frames behaviour and we'll choose the highest rate whose
- * failed frames behaviour is not worse than the one of the original rate
- * target. While at it, check that the adjustment is within the ranges. Then,
- * provide the new rate index. */
-static int rate_control_pid_shift_adjust(struct rc_pid_rateinfo *r,
-                                        int adj, int cur, int l)
-{
-       int i, j, k, tmp;
-
-       j = r[cur].rev_index;
-       i = j + adj;
-
-       if (i < 0)
-               return r[0].index;
-       if (i >= l - 1)
-               return r[l - 1].index;
-
-       tmp = i;
-
-       if (adj < 0) {
-               for (k = j; k >= i; k--)
-                       if (r[k].diff <= r[j].diff)
-                               tmp = k;
-       } else {
-               for (k = i + 1; k + i < l; k++)
-                       if (r[k].diff <= r[i].diff)
-                               tmp = k;
-       }
-
-       return r[tmp].index;
-}
-
+/* Adjust the rate while ensuring that we won't switch to a lower rate if it
+ * exhibited a worse failed frames behaviour and we'll choose the highest rate
+ * whose failed frames behaviour is not worse than the one of the original rate
+ * target. While at it, check that the new rate is valid. */
 static void rate_control_pid_adjust_rate(struct ieee80211_local *local,
                                         struct sta_info *sta, int adj,
                                         struct rc_pid_rateinfo *rinfo)
 {
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_hw_mode *mode;
-       int newidx;
-       int maxrate;
-       int back = (adj > 0) ? 1 : -1;
+       int cur_sorted, new_sorted, probe, tmp, n_bitrates;
+       int cur = sta->txrate;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
 
        mode = local->oper_hw_mode;
-       maxrate = sdata->bss ? sdata->bss->max_ratectrl_rateidx : -1;
+       n_bitrates = mode->num_rates;
 
-       newidx = rate_control_pid_shift_adjust(rinfo, adj, sta->txrate,
-                                              mode->num_rates);
+       /* Map passed arguments to sorted values. */
+       cur_sorted = rinfo[cur].rev_index;
+       new_sorted = cur_sorted + adj;
 
-       while (newidx != sta->txrate) {
-               if (rate_supported(sta, mode, newidx) &&
-                   (maxrate < 0 || newidx <= maxrate)) {
-                       sta->txrate = newidx;
-                       break;
-               }
+       /* Check limits. */
+       if (new_sorted < 0)
+               new_sorted = rinfo[0].rev_index;
+       else if (new_sorted >= n_bitrates)
+               new_sorted = rinfo[n_bitrates - 1].rev_index;
 
-               newidx += back;
+       tmp = new_sorted;
+
+       if (adj < 0) {
+               /* Ensure that the rate decrease isn't disadvantageous. */
+               for (probe = cur_sorted; probe >= new_sorted; probe--)
+                       if (rinfo[probe].diff <= rinfo[cur_sorted].diff &&
+                           rate_supported(sta, mode, rinfo[probe].index))
+                               tmp = probe;
+       } else {
+               /* Look for rate increase with zero (or below) cost. */
+               for (probe = new_sorted + 1; probe < n_bitrates; probe++)
+                       if (rinfo[probe].diff <= rinfo[new_sorted].diff &&
+                           rate_supported(sta, mode, rinfo[probe].index))
+                               tmp = probe;
        }
 
+       /* Fit the rate found to the nearest supported rate. */
+       do {
+               if (rate_supported(sta, mode, rinfo[tmp].index)) {
+                       sta->txrate = rinfo[tmp].index;
+                       break;
+               }
+               if (adj < 0)
+                       tmp--;
+               else
+                       tmp++;
+       } while (tmp < n_bitrates && tmp >= 0);
+
 #ifdef CONFIG_MAC80211_DEBUGFS
        rate_control_pid_event_rate_change(
                &((struct rc_pid_sta_info *)sta->rate_ctrl_priv)->events,
-               newidx, mode->rates[newidx].rate);
+               cur, mode->rates[cur].rate);
 #endif
 }