mac80211/drivers: rewrite the rate control API
[pandora-kernel.git] / net / mac80211 / rate.c
index 0388c09..3fa7ab2 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/rtnetlink.h>
 #include "rate.h"
 #include "ieee80211_i.h"
+#include "debugfs.h"
 
 struct rate_control_alg {
        struct list_head list;
@@ -127,19 +128,46 @@ static void ieee80211_rate_control_ops_put(struct rate_control_ops *ops)
        module_put(ops->module);
 }
 
+#ifdef CONFIG_MAC80211_DEBUGFS
+static ssize_t rcname_read(struct file *file, char __user *userbuf,
+                          size_t count, loff_t *ppos)
+{
+       struct rate_control_ref *ref = file->private_data;
+       int len = strlen(ref->ops->name);
+
+       return simple_read_from_buffer(userbuf, count, ppos,
+                                      ref->ops->name, len);
+}
+
+static const struct file_operations rcname_ops = {
+       .read = rcname_read,
+       .open = mac80211_open_file_generic,
+};
+#endif
+
 struct rate_control_ref *rate_control_alloc(const char *name,
                                            struct ieee80211_local *local)
 {
+       struct dentry *debugfsdir = NULL;
        struct rate_control_ref *ref;
 
        ref = kmalloc(sizeof(struct rate_control_ref), GFP_KERNEL);
        if (!ref)
                goto fail_ref;
        kref_init(&ref->kref);
+       ref->local = local;
        ref->ops = ieee80211_rate_control_ops_get(name);
        if (!ref->ops)
                goto fail_ops;
-       ref->priv = ref->ops->alloc(local);
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+       debugfsdir = debugfs_create_dir("rc", local->hw.wiphy->debugfsdir);
+       local->debugfs.rcdir = debugfsdir;
+       local->debugfs.rcname = debugfs_create_file("name", 0400, debugfsdir,
+                                                   ref, &rcname_ops);
+#endif
+
+       ref->priv = ref->ops->alloc(&local->hw, debugfsdir);
        if (!ref->priv)
                goto fail_priv;
        return ref;
@@ -158,46 +186,57 @@ static void rate_control_release(struct kref *kref)
 
        ctrl_ref = container_of(kref, struct rate_control_ref, kref);
        ctrl_ref->ops->free(ctrl_ref->priv);
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+       debugfs_remove(ctrl_ref->local->debugfs.rcname);
+       ctrl_ref->local->debugfs.rcname = NULL;
+       debugfs_remove(ctrl_ref->local->debugfs.rcdir);
+       ctrl_ref->local->debugfs.rcdir = NULL;
+#endif
+
        ieee80211_rate_control_ops_put(ctrl_ref->ops);
        kfree(ctrl_ref);
 }
 
-void rate_control_get_rate(struct net_device *dev,
-                          struct ieee80211_supported_band *sband,
-                          struct sk_buff *skb,
-                          struct rate_selection *sel)
+void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
+                          struct sta_info *sta,
+                          struct ieee80211_tx_rate_control *txrc)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct rate_control_ref *ref = local->rate_ctrl;
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-       struct sta_info *sta;
+       struct rate_control_ref *ref = sdata->local->rate_ctrl;
+       void *priv_sta = NULL;
+       struct ieee80211_sta *ista = NULL;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb);
        int i;
 
-       rcu_read_lock();
-       sta = sta_info_get(local, hdr->addr1);
-
-       sel->rate_idx = -1;
-       sel->nonerp_idx = -1;
-       sel->probe_idx = -1;
-
-       ref->ops->get_rate(ref->priv, dev, sband, skb, sel);
-
-       BUG_ON(sel->rate_idx < 0);
+       if (sta) {
+               ista = &sta->sta;
+               priv_sta = sta->rate_ctrl_priv;
+       }
 
-       /* Select a non-ERP backup rate. */
-       if (sel->nonerp_idx < 0) {
-               for (i = 0; i < sband->n_bitrates; i++) {
-                       struct ieee80211_rate *rate = &sband->bitrates[i];
-                       if (sband->bitrates[sel->rate_idx].bitrate < rate->bitrate)
-                               break;
+       for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
+               info->control.rates[i].idx = -1;
+               info->control.rates[i].flags = 0;
+               info->control.rates[i].count = 1;
+       }
 
-                       if (rate_supported(sta, sband->band, i) &&
-                           !(rate->flags & IEEE80211_RATE_ERP_G))
-                               sel->nonerp_idx = i;
-               }
+       if (sta && sdata->force_unicast_rateidx > -1)
+               info->control.rates[0].idx = sdata->force_unicast_rateidx;
+       else
+               ref->ops->get_rate(ref->priv, ista, priv_sta, txrc);
+
+       /*
+        * try to enforce the maximum rate the user wanted
+        */
+       if (sdata->max_ratectrl_rateidx > -1)
+               for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
+                       if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS)
+                               continue;
+                       info->control.rates[i].idx =
+                               min_t(s8, info->control.rates[i].idx,
+                                     sdata->max_ratectrl_rateidx);
        }
 
-       rcu_read_unlock();
+       BUG_ON(info->control.rates[0].idx < 0);
 }
 
 struct rate_control_ref *rate_control_get(struct rate_control_ref *ref)