Commit 830fb67b authored by Juuso Oikarinen's avatar Juuso Oikarinen Committed by John W. Linville

wl1271: Fix supported rate management

Previously, only basic rates were used for data transmission - resulting in
reduced transfer rates. This patch takes enables the firmware to take advantage
of the full set of data rates supported by the AP.
Signed-off-by: default avatarJuuso Oikarinen <juuso.oikarinen@nokia.com>
Reviewed-by: default avatarLuciano Coelho <luciano.coelho@nokia.com>
Signed-off-by: default avatarLuciano Coelho <luciano.coelho@nokia.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent ec078d94
...@@ -322,6 +322,10 @@ struct wl1271 { ...@@ -322,6 +322,10 @@ struct wl1271 {
enum wl1271_state state; enum wl1271_state state;
struct mutex mutex; struct mutex mutex;
#define WL1271_FLAG_STA_RATES_CHANGED (0)
#define WL1271_FLAG_STA_ASSOCIATED (1)
unsigned long flags;
struct wl1271_partition_set part; struct wl1271_partition_set part;
struct wl1271_chip chip; struct wl1271_chip chip;
...@@ -394,7 +398,9 @@ struct wl1271 { ...@@ -394,7 +398,9 @@ struct wl1271 {
u16 aid; u16 aid;
/* currently configured rate set */ /* currently configured rate set */
u32 sta_rate_set;
u32 basic_rate_set; u32 basic_rate_set;
u32 rate_set;
/* The current band */ /* The current band */
enum ieee80211_band band; enum ieee80211_band band;
...@@ -416,7 +422,6 @@ struct wl1271 { ...@@ -416,7 +422,6 @@ struct wl1271 {
/* PSM mode requested */ /* PSM mode requested */
bool psm_requested; bool psm_requested;
bool associated;
/* retry counter for PSM entries */ /* retry counter for PSM entries */
u8 psm_entry_retry; u8 psm_entry_retry;
......
...@@ -787,10 +787,11 @@ int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats) ...@@ -787,10 +787,11 @@ int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats)
return 0; return 0;
} }
int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates) int wl1271_acx_rate_policies(struct wl1271 *wl)
{ {
struct acx_rate_policy *acx; struct acx_rate_policy *acx;
struct conf_tx_rate_class *c = &wl->conf.tx.rc_conf; struct conf_tx_rate_class *c = &wl->conf.tx.rc_conf;
int idx = 0;
int ret = 0; int ret = 0;
wl1271_debug(DEBUG_ACX, "acx rate policies"); wl1271_debug(DEBUG_ACX, "acx rate policies");
...@@ -802,12 +803,21 @@ int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates) ...@@ -802,12 +803,21 @@ int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates)
goto out; goto out;
} }
/* configure one default (one-size-fits-all) rate class */ /* configure one basic rate class */
acx->rate_class_cnt = cpu_to_le32(1); idx = ACX_TX_BASIC_RATE;
acx->rate_class[0].enabled_rates = cpu_to_le32(enabled_rates); acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->basic_rate_set);
acx->rate_class[0].short_retry_limit = c->short_retry_limit; acx->rate_class[idx].short_retry_limit = c->short_retry_limit;
acx->rate_class[0].long_retry_limit = c->long_retry_limit; acx->rate_class[idx].long_retry_limit = c->long_retry_limit;
acx->rate_class[0].aflags = c->aflags; acx->rate_class[idx].aflags = c->aflags;
/* configure one AP supported rate class */
idx = ACX_TX_AP_FULL_RATE;
acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->rate_set);
acx->rate_class[idx].short_retry_limit = c->short_retry_limit;
acx->rate_class[idx].long_retry_limit = c->long_retry_limit;
acx->rate_class[idx].aflags = c->aflags;
acx->rate_class_cnt = cpu_to_le32(ACX_TX_RATE_POLICY_CNT);
ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx));
if (ret < 0) { if (ret < 0) {
......
...@@ -826,6 +826,9 @@ struct acx_rate_class { ...@@ -826,6 +826,9 @@ struct acx_rate_class {
u8 reserved; u8 reserved;
}; };
#define ACX_TX_BASIC_RATE 0
#define ACX_TX_AP_FULL_RATE 1
#define ACX_TX_RATE_POLICY_CNT 2
struct acx_rate_policy { struct acx_rate_policy {
struct acx_header header; struct acx_header header;
...@@ -1058,7 +1061,7 @@ int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble); ...@@ -1058,7 +1061,7 @@ int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble);
int wl1271_acx_cts_protect(struct wl1271 *wl, int wl1271_acx_cts_protect(struct wl1271 *wl,
enum acx_ctsprotect_type ctsprotect); enum acx_ctsprotect_type ctsprotect);
int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats); int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats);
int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates); int wl1271_acx_rate_policies(struct wl1271 *wl);
int wl1271_acx_ac_cfg(struct wl1271 *wl); int wl1271_acx_ac_cfg(struct wl1271 *wl);
int wl1271_acx_tid_cfg(struct wl1271 *wl); int wl1271_acx_tid_cfg(struct wl1271 *wl);
int wl1271_acx_frag_threshold(struct wl1271 *wl); int wl1271_acx_frag_threshold(struct wl1271 *wl);
......
...@@ -284,7 +284,7 @@ int wl1271_hw_init(struct wl1271 *wl) ...@@ -284,7 +284,7 @@ int wl1271_hw_init(struct wl1271 *wl)
goto out_free_memmap; goto out_free_memmap;
/* Configure TX rate classes */ /* Configure TX rate classes */
ret = wl1271_acx_rate_policies(wl, CONF_TX_RATE_MASK_BASIC); ret = wl1271_acx_rate_policies(wl);
if (ret < 0) if (ret < 0)
goto out_free_memmap; goto out_free_memmap;
......
...@@ -777,7 +777,20 @@ int wl1271_plt_stop(struct wl1271 *wl) ...@@ -777,7 +777,20 @@ int wl1271_plt_stop(struct wl1271 *wl)
static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{ {
struct wl1271 *wl = hw->priv; struct wl1271 *wl = hw->priv;
struct ieee80211_conf *conf = &hw->conf;
struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
struct ieee80211_sta *sta = txinfo->control.sta;
unsigned long flags;
/* peek into the rates configured in the STA entry */
spin_lock_irqsave(&wl->wl_lock, flags);
if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
wl->sta_rate_set = sta->supp_rates[conf->channel->band];
set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
}
spin_unlock_irqrestore(&wl->wl_lock, flags);
/* queue the packet */
skb_queue_tail(&wl->tx_queue, skb); skb_queue_tail(&wl->tx_queue, skb);
/* /*
...@@ -1004,7 +1017,6 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) ...@@ -1004,7 +1017,6 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
wl->elp = false; wl->elp = false;
wl->psm = 0; wl->psm = 0;
wl->psm_entry_retry = 0; wl->psm_entry_retry = 0;
wl->associated = false;
wl->tx_queue_stopped = false; wl->tx_queue_stopped = false;
wl->power_level = WL1271_DEFAULT_POWER_LEVEL; wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
wl->tx_blocks_available = 0; wl->tx_blocks_available = 0;
...@@ -1016,6 +1028,9 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) ...@@ -1016,6 +1028,9 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
wl->time_offset = 0; wl->time_offset = 0;
wl->session_counter = 0; wl->session_counter = 0;
wl->joined = false; wl->joined = false;
wl->rate_set = CONF_TX_RATE_MASK_BASIC;
wl->sta_rate_set = 0;
wl->flags = 0;
for (i = 0; i < NUM_TX_QUEUES; i++) for (i = 0; i < NUM_TX_QUEUES; i++)
wl->tx_blocks_freed[i] = 0; wl->tx_blocks_freed[i] = 0;
...@@ -1212,8 +1227,9 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) ...@@ -1212,8 +1227,9 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
wl1271_join_channel(wl, channel); wl1271_join_channel(wl, channel);
if (conf->flags & IEEE80211_CONF_IDLE) { if (conf->flags & IEEE80211_CONF_IDLE) {
wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC; wl->rate_set = CONF_TX_RATE_MASK_BASIC;
wl1271_acx_rate_policies(wl, CONF_TX_RATE_MASK_BASIC); wl->sta_rate_set = 0;
wl1271_acx_rate_policies(wl);
} }
} }
...@@ -1229,7 +1245,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) ...@@ -1229,7 +1245,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
* If we're not, we'll enter it when joining an SSID, * If we're not, we'll enter it when joining an SSID,
* through the bss_info_changed() hook. * through the bss_info_changed() hook.
*/ */
if (wl->associated) { if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
wl1271_info("psm enabled"); wl1271_info("psm enabled");
ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE); ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
} }
...@@ -1522,22 +1538,6 @@ static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) ...@@ -1522,22 +1538,6 @@ static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
return ret; return ret;
} }
static u32 wl1271_enabled_rates_get(struct wl1271 *wl, u64 basic_rate_set)
{
struct ieee80211_supported_band *band;
u32 enabled_rates = 0;
int bit;
band = wl->hw->wiphy->bands[wl->band];
for (bit = 0; bit < band->n_bitrates; bit++) {
if (basic_rate_set & 0x1)
enabled_rates |= band->bitrates[bit].hw_value;
basic_rate_set >>= 1;
}
return enabled_rates;
}
static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf, struct ieee80211_bss_conf *bss_conf,
...@@ -1616,7 +1616,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, ...@@ -1616,7 +1616,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_ASSOC) { if (changed & BSS_CHANGED_ASSOC) {
if (bss_conf->assoc) { if (bss_conf->assoc) {
wl->aid = bss_conf->aid; wl->aid = bss_conf->aid;
wl->associated = true; set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
/* /*
* with wl1271, we don't need to update the * with wl1271, we don't need to update the
...@@ -1641,7 +1641,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, ...@@ -1641,7 +1641,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
} }
} else { } else {
/* use defaults when not associated */ /* use defaults when not associated */
wl->associated = false; clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
wl->aid = 0; wl->aid = 0;
} }
...@@ -1676,17 +1676,6 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, ...@@ -1676,17 +1676,6 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
} }
} }
if (changed & BSS_CHANGED_BASIC_RATES) {
wl->basic_rate_set = wl1271_enabled_rates_get(
wl, bss_conf->basic_rates);
ret = wl1271_acx_rate_policies(wl, wl->basic_rate_set);
if (ret < 0) {
wl1271_warning("Set rate policies failed %d", ret);
goto out_sleep;
}
}
out_sleep: out_sleep:
wl1271_ps_elp_sleep(wl); wl1271_ps_elp_sleep(wl);
...@@ -1969,14 +1958,16 @@ static int __devinit wl1271_probe(struct spi_device *spi) ...@@ -1969,14 +1958,16 @@ static int __devinit wl1271_probe(struct spi_device *spi)
wl->psm = 0; wl->psm = 0;
wl->psm_requested = false; wl->psm_requested = false;
wl->psm_entry_retry = 0; wl->psm_entry_retry = 0;
wl->associated = false;
wl->tx_queue_stopped = false; wl->tx_queue_stopped = false;
wl->power_level = WL1271_DEFAULT_POWER_LEVEL; wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC; wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
wl->rate_set = CONF_TX_RATE_MASK_BASIC;
wl->sta_rate_set = 0;
wl->band = IEEE80211_BAND_2GHZ; wl->band = IEEE80211_BAND_2GHZ;
wl->vif = NULL; wl->vif = NULL;
wl->joined = false; wl->joined = false;
wl->gpio_power = false; wl->gpio_power = false;
wl->flags = 0;
for (i = 0; i < ACX_TX_DESCRIPTORS; i++) for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
wl->tx_frames[i] = NULL; wl->tx_frames[i] = NULL;
......
...@@ -121,6 +121,11 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, ...@@ -121,6 +121,11 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
pad = pad - skb->len; pad = pad - skb->len;
tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD;
/* if the packets are destined for AP (have a STA entry) send them
with AP rate policies, otherwise use default basic rates */
if (control->control.sta)
tx_attr |= ACX_TX_AP_FULL_RATE << TX_HW_ATTR_OFST_RATE_POLICY;
desc->tx_attr = cpu_to_le16(tx_attr); desc->tx_attr = cpu_to_le16(tx_attr);
wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d", pad); wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d", pad);
...@@ -214,18 +219,50 @@ static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb) ...@@ -214,18 +219,50 @@ static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb)
return ret; return ret;
} }
static u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set)
{
struct ieee80211_supported_band *band;
u32 enabled_rates = 0;
int bit;
band = wl->hw->wiphy->bands[wl->band];
for (bit = 0; bit < band->n_bitrates; bit++) {
if (rate_set & 0x1)
enabled_rates |= band->bitrates[bit].hw_value;
rate_set >>= 1;
}
return enabled_rates;
}
void wl1271_tx_work(struct work_struct *work) void wl1271_tx_work(struct work_struct *work)
{ {
struct wl1271 *wl = container_of(work, struct wl1271, tx_work); struct wl1271 *wl = container_of(work, struct wl1271, tx_work);
struct sk_buff *skb; struct sk_buff *skb;
bool woken_up = false; bool woken_up = false;
u32 sta_rates = 0;
int ret; int ret;
/* check if the rates supported by the AP have changed */
if (unlikely(test_and_clear_bit(WL1271_FLAG_STA_RATES_CHANGED,
&wl->flags))) {
unsigned long flags;
spin_lock_irqsave(&wl->wl_lock, flags);
sta_rates = wl->sta_rate_set;
spin_unlock_irqrestore(&wl->wl_lock, flags);
}
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
if (unlikely(wl->state == WL1271_STATE_OFF)) if (unlikely(wl->state == WL1271_STATE_OFF))
goto out; goto out;
/* if rates have changed, re-configure the rate policy */
if (unlikely(sta_rates)) {
wl->rate_set = wl1271_tx_enabled_rates_get(wl, sta_rates);
wl1271_acx_rate_policies(wl);
}
while ((skb = skb_dequeue(&wl->tx_queue))) { while ((skb = skb_dequeue(&wl->tx_queue))) {
if (!woken_up) { if (!woken_up) {
ret = wl1271_ps_elp_wakeup(wl, false); ret = wl1271_ps_elp_wakeup(wl, false);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment