Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1abbe498 authored by Mattias Nissler's avatar Mattias Nissler Committed by David S. Miller
Browse files

mac80211: clean up rate selection



Move some code out of rc80211_simple since it's probably needed for all rate
selection algorithms, and fix iwlwifi accordingly. While at it, clean up the
rate_control_get_rate() interface.

Signed-off-by: default avatarStefano Brivio <stefano.brivio@polimi.it>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 98f0b0a3
Loading
Loading
Loading
Loading
+7 −37
Original line number Diff line number Diff line
@@ -562,22 +562,6 @@ static void rs_tx_status(void *priv_rate,
	return;
}

static struct ieee80211_rate *iwl_get_lowest_rate(struct ieee80211_local
						  *local)
{
	struct ieee80211_hw_mode *mode = local->oper_hw_mode;
	int i;

	for (i = 0; i < mode->num_rates; i++) {
		struct ieee80211_rate *rate = &mode->rates[i];

		if (rate->flags & IEEE80211_RATE_SUPPORTED)
			return rate;
	}

	return &mode->rates[0];
}

static u16 iwl_get_adjacent_rate(struct iwl_rate_scale_priv *rs_priv,
				 u8 index, u16 rate_mask, int phymode)
{
@@ -656,10 +640,9 @@ static u16 iwl_get_adjacent_rate(struct iwl_rate_scale_priv *rs_priv,
 * rate table and must reference the driver allocated rate table
 *
 */
static struct ieee80211_rate *rs_get_rate(void *priv_rate,
					  struct net_device *dev,
					  struct sk_buff *skb,
					  struct rate_control_extra *extra)
static void rs_get_rate(void *priv_rate, struct net_device *dev,
			struct ieee80211_hw_mode *mode, struct sk_buff *skb,
			struct rate_selection *sel)
{
	u8 low = IWL_RATE_INVALID;
	u8 high = IWL_RATE_INVALID;
@@ -676,32 +659,19 @@ static struct ieee80211_rate *rs_get_rate(void *priv_rate,
	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
	struct sta_info *sta;
	u16 fc, rate_mask;
	u16 rate_mask;
	struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
	DECLARE_MAC_BUF(mac);

	IWL_DEBUG_RATE("enter\n");

	memset(extra, 0, sizeof(*extra));

	fc = le16_to_cpu(hdr->frame_control);
	if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
	    (is_multicast_ether_addr(hdr->addr1))) {
		/* Send management frames and broadcast/multicast data using
		 * lowest rate. */
		/* TODO: this could probably be improved.. */
		IWL_DEBUG_RATE("leave: lowest rate (not data or is "
			       "multicast)\n");

		return iwl_get_lowest_rate(local);
	}

	sta = sta_info_get(local, hdr->addr1);
	if (!sta || !sta->rate_ctrl_priv) {
		IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
		sel->rate = rate_lowest(local, local->oper_hw_mode, sta);
		if (sta)
			sta_info_put(sta);
		return NULL;
		return;
	}

	rate_mask = sta->supp_rates;
@@ -846,7 +816,7 @@ static struct ieee80211_rate *rs_get_rate(void *priv_rate,

	IWL_DEBUG_RATE("leave: %d\n", index);

	return &priv->ieee_rates[index];
	sel->rate = &priv->ieee_rates[index];
}

static struct rate_control_ops rs_ops = {
+10 −36
Original line number Diff line number Diff line
@@ -1693,55 +1693,27 @@ static void rs_initialize_lq(struct iwl_priv *priv,
	return;
}

static struct ieee80211_rate *rs_get_lowest_rate(struct ieee80211_local
						 *local)
{
	struct ieee80211_hw_mode *mode = local->oper_hw_mode;
	int i;

	for (i = 0; i < mode->num_rates; i++) {
		struct ieee80211_rate *rate = &mode->rates[i];

		if (rate->flags & IEEE80211_RATE_SUPPORTED)
			return rate;
	}

	return &mode->rates[0];
}

static struct ieee80211_rate *rs_get_rate(void *priv_rate,
					       struct net_device *dev,
					       struct sk_buff *skb,
					       struct rate_control_extra
					       *extra)
static void rs_get_rate(void *priv_rate, struct net_device *dev,
			struct ieee80211_hw_mode *mode, struct sk_buff *skb,
			struct rate_selection *sel)
{

	int i;
	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
	struct sta_info *sta;
	u16 fc;
	struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
	struct iwl_rate_scale_priv *lq;

	IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n");

	memset(extra, 0, sizeof(*extra));

	fc = le16_to_cpu(hdr->frame_control);
	if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) {
		/* Send management frames and broadcast/multicast data using
		 * lowest rate. */
		/* TODO: this could probably be improved.. */
		return rs_get_lowest_rate(local);
	}

	sta = sta_info_get(local, hdr->addr1);

	if (!sta || !sta->rate_ctrl_priv) {
		sel->rate = rate_lowest(local, local->oper_hw_mode, sta);
		if (sta)
			sta_info_put(sta);
		return rs_get_lowest_rate(local);
		return;
	}

	lq = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv;
@@ -1768,11 +1740,13 @@ static struct ieee80211_rate *rs_get_rate(void *priv_rate,
	}

 done:
	if ((i < 0) || (i > IWL_RATE_COUNT)) {
		sel->rate = rate_lowest(local, local->oper_hw_mode, sta);
		return;
	}
	sta_info_put(sta);
	if ((i < 0) || (i > IWL_RATE_COUNT))
		return rs_get_lowest_rate(local);

	return &priv->ieee_rates[i];
	sel->rate = &priv->ieee_rates[i];
}

static void *rs_alloc_sta(void *priv, gfp_t gfp)
+2 −4
Original line number Diff line number Diff line
@@ -859,10 +859,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
			sta_info_put(sta);
			return;
		}
	} else {
		/* FIXME: STUPID to call this with both local and local->mdev */
		rate_control_tx_status(local, local->mdev, skb, status);
	}
	} else
		rate_control_tx_status(local->mdev, skb, status);

	ieee80211_led_tx(local, 0);

+47 −0
Original line number Diff line number Diff line
@@ -147,6 +147,53 @@ static void rate_control_release(struct kref *kref)
	kfree(ctrl_ref);
}

void rate_control_get_rate(struct net_device *dev,
			   struct ieee80211_hw_mode *mode, struct sk_buff *skb,
			   struct rate_selection *sel)
{
	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
	struct rate_control_ref *ref = local->rate_ctrl;
	struct ieee80211_sub_if_data *sdata;
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
	struct sta_info *sta = sta_info_get(local, hdr->addr1);
	int i;
	u16 fc;

	memset(sel, 0, sizeof(struct rate_selection));

	/* Send management frames and broadcast/multicast data using lowest
	 * rate. */
	fc = le16_to_cpu(hdr->frame_control);
	if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
	    is_multicast_ether_addr(hdr->addr1))
		sel->rate = rate_lowest(local, mode, sta);

	/* If a forced rate is in effect, select it. */
	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
	if (sdata->bss && sdata->bss->force_unicast_rateidx > -1)
		sel->rate = &mode->rates[sdata->bss->force_unicast_rateidx];

	/* If we haven't found the rate yet, ask the rate control algo. */
	if (!sel->rate)
		ref->ops->get_rate(ref->priv, dev, mode, skb, sel);

	/* Select a non-ERP backup rate. */
	if (!sel->nonerp) {
		for (i = 0; i < mode->num_rates - 1; i++) {
			struct ieee80211_rate *rate = &mode->rates[i];
			if (sel->rate->rate < rate->rate)
				break;

			if (rate_supported(sta, mode, i) &&
			    !(rate->flags & IEEE80211_RATE_ERP))
				sel->nonerp = rate;
		}
	}

	if (sta)
		sta_info_put(sta);
}

struct rate_control_ref *rate_control_get(struct rate_control_ref *ref)
{
	kref_get(&ref->kref);
+46 −27
Original line number Diff line number Diff line
@@ -18,31 +18,24 @@
#include "ieee80211_i.h"
#include "sta_info.h"

#define RATE_CONTROL_NUM_DOWN 20
#define RATE_CONTROL_NUM_UP   15


struct rate_control_extra {
	/* values from rate_control_get_rate() to the caller: */
	struct ieee80211_rate *probe; /* probe with this rate, or NULL for no
				       * probing */
struct rate_selection {
	/* Selected transmission rate */
	struct ieee80211_rate *rate;
	/* Non-ERP rate to use if mac80211 decides it cannot use an ERP rate */
	struct ieee80211_rate *nonerp;

	/* parameters from the caller to rate_control_get_rate(): */
	struct ieee80211_hw_mode *mode;
	u16 ethertype;
	/* probe with this rate, or NULL for no probing */
	struct ieee80211_rate *probe;
};


struct rate_control_ops {
	struct module *module;
	const char *name;
	void (*tx_status)(void *priv, struct net_device *dev,
			  struct sk_buff *skb,
			  struct ieee80211_tx_status *status);
	struct ieee80211_rate *(*get_rate)(void *priv, struct net_device *dev,
					   struct sk_buff *skb,
					   struct rate_control_extra *extra);
	void (*get_rate)(void *priv, struct net_device *dev,
			 struct ieee80211_hw_mode *mode, struct sk_buff *skb,
			 struct rate_selection *sel);
	void (*rate_init)(void *priv, void *priv_sta,
			  struct ieee80211_local *local, struct sta_info *sta);
	void (*clear)(void *priv);
@@ -75,25 +68,20 @@ void ieee80211_rate_control_unregister(struct rate_control_ops *ops);
 * first available algorithm. */
struct rate_control_ref *rate_control_alloc(const char *name,
					    struct ieee80211_local *local);
void rate_control_get_rate(struct net_device *dev,
			   struct ieee80211_hw_mode *mode, struct sk_buff *skb,
			   struct rate_selection *sel);
struct rate_control_ref *rate_control_get(struct rate_control_ref *ref);
void rate_control_put(struct rate_control_ref *ref);

static inline void rate_control_tx_status(struct ieee80211_local *local,
					  struct net_device *dev,
static inline void rate_control_tx_status(struct net_device *dev,
					  struct sk_buff *skb,
					  struct ieee80211_tx_status *status)
{
	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
	struct rate_control_ref *ref = local->rate_ctrl;
	ref->ops->tx_status(ref->priv, dev, skb, status);
}


static inline struct ieee80211_rate *
rate_control_get_rate(struct ieee80211_local *local, struct net_device *dev,
		      struct sk_buff *skb, struct rate_control_extra *extra)
{
	struct rate_control_ref *ref = local->rate_ctrl;
	return ref->ops->get_rate(ref->priv, dev, skb, extra);
	ref->ops->tx_status(ref->priv, dev, skb, status);
}


@@ -142,6 +130,37 @@ static inline void rate_control_remove_sta_debugfs(struct sta_info *sta)
#endif
}

static inline int
rate_supported(struct sta_info *sta, struct ieee80211_hw_mode *mode, int index)
{
	return (sta == NULL || sta->supp_rates & BIT(index)) &&
	       (mode->rates[index].flags & IEEE80211_RATE_SUPPORTED);
}

static inline int
rate_lowest_index(struct ieee80211_local *local, struct ieee80211_hw_mode *mode,
		  struct sta_info *sta)
{
	int i;

	for (i = 0; i < mode->num_rates; i++) {
		if (rate_supported(sta, mode, i))
			return i;
	}

	/* warn when we cannot find a rate. */
	WARN_ON(1);

	return 0;
}

static inline struct ieee80211_rate *
rate_lowest(struct ieee80211_local *local, struct ieee80211_hw_mode *mode,
	    struct sta_info *sta)
{
	return &mode->rates[rate_lowest_index(local, mode, sta)];
}


/* functions for rate control related to a device */
int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
Loading