mac80211: make software rate control optional
authorJohannes Berg <johannes@sipsolutions.net>
Tue, 17 Nov 2009 17:18:36 +0000 (18:18 +0100)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 18 Nov 2009 22:09:24 +0000 (17:09 -0500)
Some devices implement the entire rate control in
firmware in some way, like wl1271 or like iwlwifi
which does some things in software but not a lot.
Therefore generic software rate control is rather
useless for them and just adds avoidable overhead
to the transmit path.

It's fairly simple to let drivers indicate that
they do not need rate control, but they need to
fulfil a number of conditions that we encode in
WARN_ONs.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
include/net/mac80211.h
net/mac80211/debugfs.c
net/mac80211/rate.c
net/mac80211/rate.h
net/mac80211/sta_info.c
net/mac80211/tx.c

index 4af0ffb98aaf8a533be353f80bc81a5c2a4c73fb..f34f4ca7016cb6efbd5f254b6cabfefcfc05b89a 100644 (file)
@@ -855,6 +855,19 @@ enum ieee80211_tkip_key_type {
  * any particular flags. There are some exceptions to this rule,
  * however, so you are advised to review these flags carefully.
  *
+ * @IEEE80211_HW_HAS_RATE_CONTROL:
+ *     The hardware or firmware includes rate control, and cannot be
+ *     controlled by the stack. As such, no rate control algorithm
+ *     should be instantiated, and the TX rate reported to userspace
+ *     will be taken from the TX status instead of the rate control
+ *     algorithm.
+ *     Note that this requires that the driver implement a number of
+ *     callbacks so it has the correct information, it needs to have
+ *     the @set_rts_threshold callback and must look at the BSS config
+ *     @use_cts_prot for G/N protection, @use_short_slot for slot
+ *     timing in 2.4 GHz and @use_short_preamble for preambles for
+ *     CCK frames.
+ *
  * @IEEE80211_HW_RX_INCLUDES_FCS:
  *     Indicates that received frames passed to the stack include
  *     the FCS at the end.
@@ -913,6 +926,7 @@ enum ieee80211_tkip_key_type {
  *     avoid waking up cpu.
  */
 enum ieee80211_hw_flags {
+       IEEE80211_HW_HAS_RATE_CONTROL                   = 1<<0,
        IEEE80211_HW_RX_INCLUDES_FCS                    = 1<<1,
        IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING        = 1<<2,
        IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE          = 1<<3,
index 82c807723b6f913b4dc1d763b6367e706f830326..e4b54093d41b3bafd4bdc3458040bc57ad5fc6cb 100644 (file)
@@ -52,7 +52,7 @@ DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d",
 DEBUGFS_READONLY_FILE(wep_iv, 20, "%#08x",
                      local->wep_iv & 0xffffff);
 DEBUGFS_READONLY_FILE(rate_ctrl_alg, 100, "%s",
-                     local->rate_ctrl ? local->rate_ctrl->ops->name : "<unset>");
+       local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver");
 
 static ssize_t tsf_read(struct file *file, char __user *user_buf,
                             size_t count, loff_t *ppos)
index ccda7454fb17fbc21d86bdf561fb3a48ffecf5d9..b9007f80cb9231bb99bb9a726d3e286ccabfb8ff 100644 (file)
@@ -284,9 +284,16 @@ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
        struct rate_control_ref *ref, *old;
 
        ASSERT_RTNL();
+
        if (local->open_count)
                return -EBUSY;
 
+       if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) {
+               if (WARN_ON(!local->ops->set_rts_threshold))
+                       return -EINVAL;
+               return 0;
+       }
+
        ref = rate_control_alloc(name, local);
        if (!ref) {
                printk(KERN_WARNING "%s: Failed to select rate control "
@@ -305,7 +312,6 @@ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
               "algorithm '%s'\n", wiphy_name(local->hw.wiphy),
               ref->ops->name);
 
-
        return 0;
 }
 
@@ -314,6 +320,10 @@ void rate_control_deinitialize(struct ieee80211_local *local)
        struct rate_control_ref *ref;
 
        ref = local->rate_ctrl;
+
+       if (!ref)
+               return;
+
        local->rate_ctrl = NULL;
        rate_control_put(ref);
 }
index 2ab5ad9e71ce206a7c93efce93c80a4ce75c42b5..cb9bd1f65e2710bb9931abb3bcc32e5d577d7a39 100644 (file)
@@ -59,6 +59,9 @@ static inline void rate_control_rate_init(struct sta_info *sta)
        void *priv_sta = sta->rate_ctrl_priv;
        struct ieee80211_supported_band *sband;
 
+       if (!ref)
+               return;
+
        sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 
        ref->ops->rate_init(ref->priv, sband, ista, priv_sta);
@@ -72,7 +75,7 @@ static inline void rate_control_rate_update(struct ieee80211_local *local,
        struct ieee80211_sta *ista = &sta->sta;
        void *priv_sta = sta->rate_ctrl_priv;
 
-       if (ref->ops->rate_update)
+       if (ref && ref->ops->rate_update)
                ref->ops->rate_update(ref->priv, sband, ista,
                                      priv_sta, changed);
 }
@@ -97,7 +100,7 @@ static inline void rate_control_add_sta_debugfs(struct sta_info *sta)
 {
 #ifdef CONFIG_MAC80211_DEBUGFS
        struct rate_control_ref *ref = sta->rate_ctrl;
-       if (sta->debugfs.dir && ref->ops->add_sta_debugfs)
+       if (ref && sta->debugfs.dir && ref->ops->add_sta_debugfs)
                ref->ops->add_sta_debugfs(ref->priv, sta->rate_ctrl_priv,
                                          sta->debugfs.dir);
 #endif
@@ -107,7 +110,7 @@ static inline void rate_control_remove_sta_debugfs(struct sta_info *sta)
 {
 #ifdef CONFIG_MAC80211_DEBUGFS
        struct rate_control_ref *ref = sta->rate_ctrl;
-       if (ref->ops->remove_sta_debugfs)
+       if (ref && ref->ops->remove_sta_debugfs)
                ref->ops->remove_sta_debugfs(ref->priv, sta->rate_ctrl_priv);
 #endif
 }
index aa017a56afc80b140ca98450996e076efc145138..71f370dd24bcee545775eb6f9489c0d14b868aee 100644 (file)
@@ -148,8 +148,10 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata,
 static void __sta_info_free(struct ieee80211_local *local,
                            struct sta_info *sta)
 {
-       rate_control_free_sta(sta);
-       rate_control_put(sta->rate_ctrl);
+       if (sta->rate_ctrl) {
+               rate_control_free_sta(sta);
+               rate_control_put(sta->rate_ctrl);
+       }
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
        printk(KERN_DEBUG "%s: Destroyed STA %pM\n",
@@ -277,6 +279,23 @@ static void sta_unblock(struct work_struct *wk)
                ieee80211_sta_ps_deliver_poll_response(sta);
 }
 
+static int sta_prepare_rate_control(struct ieee80211_local *local,
+                                   struct sta_info *sta, gfp_t gfp)
+{
+       if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)
+               return 0;
+
+       sta->rate_ctrl = rate_control_get(local->rate_ctrl);
+       sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl,
+                                                    &sta->sta, gfp);
+       if (!sta->rate_ctrl_priv) {
+               rate_control_put(sta->rate_ctrl);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
 struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
                                u8 *addr, gfp_t gfp)
 {
@@ -296,11 +315,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
        sta->local = local;
        sta->sdata = sdata;
 
-       sta->rate_ctrl = rate_control_get(local->rate_ctrl);
-       sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl,
-                                                    &sta->sta, gfp);
-       if (!sta->rate_ctrl_priv) {
-               rate_control_put(sta->rate_ctrl);
+       if (sta_prepare_rate_control(local, sta, gfp)) {
                kfree(sta);
                return NULL;
        }
index 3466e1f7fd12d62e7e9fd601330575b0680ed3d5..bd916437e2fb97d4e7a110efe4c7516eb5030f0b 100644 (file)
@@ -1219,7 +1219,8 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
        CALL_TXH(ieee80211_tx_h_ps_buf);
        CALL_TXH(ieee80211_tx_h_select_key);
        CALL_TXH(ieee80211_tx_h_michael_mic_add);
-       CALL_TXH(ieee80211_tx_h_rate_ctrl);
+       if (!(tx->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL))
+               CALL_TXH(ieee80211_tx_h_rate_ctrl);
        CALL_TXH(ieee80211_tx_h_misc);
        CALL_TXH(ieee80211_tx_h_sequence);
        CALL_TXH(ieee80211_tx_h_fragment);