]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/mac80211/rc80211_pid_algo.c
sdhci: graceful handling of bad addresses
[linux-2.6-omap-h63xx.git] / net / mac80211 / rc80211_pid_algo.c
index c5a607ca84401421a631f450518934dbb6baf872..bcd27c1d75941d8b56d1802d99d1d0209c5c1187 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
@@ -14,8 +14,8 @@
 #include <linux/skbuff.h>
 #include <linux/debugfs.h>
 #include <net/mac80211.h>
-#include "ieee80211_rate.h"
-
+#include "rate.h"
+#include "mesh.h"
 #include "rc80211_pid.h"
 
 
  */
 
 
-/* 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_supported_band *sband;
-       int newidx;
-       int maxrate;
-       int back = (adj > 0) ? 1 : -1;
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+       int cur_sorted, new_sorted, probe, tmp, n_bitrates, band;
+       int cur = sta->txrate_idx;
 
+       sdata = sta->sdata;
        sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-       maxrate = sdata->bss ? sdata->bss->max_ratectrl_rateidx : -1;
+       band = sband->band;
+       n_bitrates = sband->n_bitrates;
 
-       newidx = rate_control_pid_shift_adjust(rinfo, adj, sta->txrate_idx,
-                                              sband->n_bitrates);
+       /* Map passed arguments to sorted values. */
+       cur_sorted = rinfo[cur].rev_index;
+       new_sorted = cur_sorted + adj;
 
-       while (newidx != sta->txrate_idx) {
-               if (rate_supported(sta, sband->band, newidx) &&
-                   (maxrate < 0 || newidx <= maxrate)) {
-                       sta->txrate_idx = 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;
+
+       tmp = new_sorted;
 
-               newidx += back;
+       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, band, 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, band, rinfo[probe].index))
+                               tmp = probe;
        }
 
+       /* Fit the rate found to the nearest supported rate. */
+       do {
+               if (rate_supported(sta, band, rinfo[tmp].index)) {
+                       sta->txrate_idx = 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, sband->bitrates[newidx].bitrate);
+               sta->txrate_idx, sband->bitrates[sta->txrate_idx].bitrate);
 #endif
 }
 
@@ -153,6 +148,9 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo,
                                    struct ieee80211_local *local,
                                    struct sta_info *sta)
 {
+#ifdef CONFIG_MAC80211_MESH
+       struct ieee80211_sub_if_data *sdata = sta->sdata;
+#endif
        struct rc_pid_sta_info *spinfo = sta->rate_ctrl_priv;
        struct rc_pid_rateinfo *rinfo = pinfo->rinfo;
        struct ieee80211_supported_band *sband;
@@ -183,7 +181,14 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo,
                pf = spinfo->last_pf;
        else {
                pf = spinfo->tx_num_failed * 100 / spinfo->tx_num_xmit;
+#ifdef CONFIG_MAC80211_MESH
+               if (pf == 100 &&
+                   sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT)
+                       mesh_plink_broken(sta);
+#endif
                pf <<= RC_PID_ARITH_SHIFT;
+               sta->fail_avg = ((pf + (spinfo->last_pf << 3)) / 9)
+                                       >> RC_PID_ARITH_SHIFT;
        }
 
        spinfo->tx_num_xmit = 0;
@@ -244,23 +249,25 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
        unsigned long period;
        struct ieee80211_supported_band *sband;
 
+       rcu_read_lock();
+
        sta = sta_info_get(local, hdr->addr1);
        sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 
        if (!sta)
-               return;
+               goto unlock;
 
        /* Don't update the state if we're not controlling the rate. */
-       sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+       sdata = sta->sdata;
        if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) {
                sta->txrate_idx = sdata->bss->max_ratectrl_rateidx;
-               return;
+               goto unlock;
        }
 
        /* Ignore all frames that were sent with a different rate than the rate
         * we currently advise mac80211 to use. */
        if (status->control.tx_rate != &sband->bitrates[sta->txrate_idx])
-               goto ignore;
+               goto unlock;
 
        spinfo = sta->rate_ctrl_priv;
        spinfo->tx_num_xmit++;
@@ -285,9 +292,6 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
                sta->tx_num_consecutive_failures++;
                sta->tx_num_mpdu_fail++;
        } else {
-               sta->last_ack_rssi[0] = sta->last_ack_rssi[1];
-               sta->last_ack_rssi[1] = sta->last_ack_rssi[2];
-               sta->last_ack_rssi[2] = status->ack_signal;
                sta->tx_num_consecutive_failures = 0;
                sta->tx_num_mpdu_ok++;
        }
@@ -301,8 +305,8 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
        if (time_after(jiffies, spinfo->last_sample + period))
                rate_control_pid_sample(pinfo, local, sta);
 
-ignore:
-       sta_info_put(sta);
+ unlock:
+       rcu_read_unlock();
 }
 
 static void rate_control_pid_get_rate(void *priv, struct net_device *dev,
@@ -317,6 +321,8 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev,
        int rateidx;
        u16 fc;
 
+       rcu_read_lock();
+
        sta = sta_info_get(local, hdr->addr1);
 
        /* Send management frames and broadcast/multicast data using lowest
@@ -325,8 +331,7 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev,
        if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
            is_multicast_ether_addr(hdr->addr1) || !sta) {
                sel->rate = rate_lowest(local, sband, sta);
-               if (sta)
-                       sta_info_put(sta);
+               rcu_read_unlock();
                return;
        }
 
@@ -342,7 +347,7 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev,
 
        sta->last_txrate_idx = rateidx;
 
-       sta_info_put(sta);
+       rcu_read_unlock();
 
        sel->rate = &sband->bitrates[rateidx];
 
@@ -365,6 +370,7 @@ static void rate_control_pid_rate_init(void *priv, void *priv_sta,
 
        sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
        sta->txrate_idx = rate_lowest_index(local, sband, sta);
+       sta->fail_avg = 0;
 }
 
 static void *rate_control_pid_alloc(struct ieee80211_local *local)
@@ -392,13 +398,25 @@ static void *rate_control_pid_alloc(struct ieee80211_local *local)
                return NULL;
        }
 
+       pinfo->target = RC_PID_TARGET_PF;
+       pinfo->sampling_period = RC_PID_INTERVAL;
+       pinfo->coeff_p = RC_PID_COEFF_P;
+       pinfo->coeff_i = RC_PID_COEFF_I;
+       pinfo->coeff_d = RC_PID_COEFF_D;
+       pinfo->smoothing_shift = RC_PID_SMOOTHING_SHIFT;
+       pinfo->sharpen_factor = RC_PID_SHARPENING_FACTOR;
+       pinfo->sharpen_duration = RC_PID_SHARPENING_DURATION;
+       pinfo->norm_offset = RC_PID_NORM_OFFSET;
+       pinfo->rinfo = rinfo;
+       pinfo->oldrate = 0;
+
        /* Sort the rates. This is optimized for the most common case (i.e.
         * almost-sorted CCK+OFDM rates). Kind of bubble-sort with reversed
         * mapping too. */
        for (i = 0; i < sband->n_bitrates; i++) {
                rinfo[i].index = i;
                rinfo[i].rev_index = i;
-               if (pinfo->fast_start)
+               if (RC_PID_FAST_START)
                        rinfo[i].diff = 0;
                else
                        rinfo[i].diff = i * pinfo->norm_offset;
@@ -419,19 +437,6 @@ static void *rate_control_pid_alloc(struct ieee80211_local *local)
                        break;
        }
 
-       pinfo->target = RC_PID_TARGET_PF;
-       pinfo->sampling_period = RC_PID_INTERVAL;
-       pinfo->coeff_p = RC_PID_COEFF_P;
-       pinfo->coeff_i = RC_PID_COEFF_I;
-       pinfo->coeff_d = RC_PID_COEFF_D;
-       pinfo->smoothing_shift = RC_PID_SMOOTHING_SHIFT;
-       pinfo->sharpen_factor = RC_PID_SHARPENING_FACTOR;
-       pinfo->sharpen_duration = RC_PID_SHARPENING_DURATION;
-       pinfo->norm_offset = RC_PID_NORM_OFFSET;
-       pinfo->fast_start = RC_PID_FAST_START;
-       pinfo->rinfo = rinfo;
-       pinfo->oldrate = 0;
-
 #ifdef CONFIG_MAC80211_DEBUGFS
        de = &pinfo->dentries;
        de->dir = debugfs_create_dir("rc80211_pid",
@@ -459,9 +464,6 @@ static void *rate_control_pid_alloc(struct ieee80211_local *local)
        de->norm_offset = debugfs_create_u32("norm_offset",
                                             S_IRUSR | S_IWUSR, de->dir,
                                             &pinfo->norm_offset);
-       de->fast_start = debugfs_create_bool("fast_start",
-                                            S_IRUSR | S_IWUSR, de->dir,
-                                            &pinfo->fast_start);
 #endif
 
        return pinfo;
@@ -473,7 +475,6 @@ static void rate_control_pid_free(void *priv)
 #ifdef CONFIG_MAC80211_DEBUGFS
        struct rc_pid_debugfs_entries *de = &pinfo->dentries;
 
-       debugfs_remove(de->fast_start);
        debugfs_remove(de->norm_offset);
        debugfs_remove(de->sharpen_duration);
        debugfs_remove(de->sharpen_factor);