2013-12-02 20:51:45

by Emmanuel Grumbach

[permalink] [raw]
Subject: pull request: iwlwifi-next 2013-12-2

Hi John,

This is the fixed and enlarged pull request for 3.14. It includes the
patches in my previous pull request that was based on a bad patch.

I have here a big rework of the rate control by Eyal. This is obviously
the biggest part of this batch.
I also have enhancement of protection flags by Avri and a few bits for
WoWLAN by Eliad and Luca. Johannes cleans up the debugfs plus a few
fixes. I provided a few things for Bluetooth coexistence.
Besides this we have an implementation for low priority scan.

Note that I had to merge iwlwifi-fixes into -next to solve conflicts
before they hit linux-next.
Please let me know about issues you may face - Thanks!

The following changes since commit 9d8506cc2d7ea1f911c72c100193a3677f6668c3:

gso: handle new frag_list of frags GRO packets (2013-11-21 14:11:50 -0500)

are available in the git repository at:

git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next.git
for-john

for you to fetch changes up to d4da46c073ebc5d74d53649bcc091deea46cb81a:

Merge remote-tracking branch 'iwlwifi-fixes/master' into iwlwifi-next
(2013-12-02 22:28:46 +0200)

----------------------------------------------------------------

Alexander Bondar (2):
iwlwifi: pcie: stop sending commands to dead firmware
iwlwifi: mvm: Add debugfs entry to generate NMI to NIC

Avri Altman (1):
iwlwifi: mvm: fix ht protection flags

Eliad Peller (4):
iwlwifi: mvm: enable d3_test even if d3_test_pme_ptr is not available
iwlwifi: mvm: disconnect on disconnection wakeup event
iwlwifi: mvm: allow keeping connections in d3_test
iwlwifi: mvm: fix scan offloading flag definition

Emmanuel Grumbach (11):
iwlwifi: pcie: fix interrupt coalescing for 7260 / 3160
iwlwifi: mvm: BT Coex - don't enable MULTI_PRIO_LUT
iwlwifi: mvm: BT Coex fix another NULL pointer dereference
iwlwifi: mvm: don't WARN about unsuccessful time event
iwlwifi: bump required firmware API version for 3160/7260
iwlwifi: remove TX_CMD id from transport layer
iwlwifi: mvm: BT Coex - fine tune the aggregation size
iwlwifi: mvm: a few more SKUs for 7260 and 3160
iwlwifi: mvm: dump NVM from debugfs
iwlwifi: mvm: BT Coex - enable Sync to SCO
Merge remote-tracking branch 'iwlwifi-fixes/master' into iwlwifi-next

Eyal Shapira (21):
iwlwifi: mvm: fix and improve printing of rate scale table
iwlwifi: mvm: simplify iwl_mvm_send_lq_cmd
iwlwifi: mvm: refactor iwl_mvm_rs_rate_init
iwlwifi: mvm: implement rate_update hook in rs
iwlwifi: mvm: add LQ flags definitions
iwlwifi: fix check for a single rx antenna
iwlwifi: mvm: stop using MIMO in case BT doesn't allow it
iwlwifi: mvm: don't enable VHT MCS9 in 20Mhz
iwlwifi: mvm: don't configure mimo rates if nss is limited to 1
iwlwifi: mvm: rs: improve debug prints
iwlwifi: mvm: rs: reduce min failures to end test window
iwlwifi: mvm: rs: update expected TPT tables if aggregation changed
iwlwifi: mvm: rs: rename thresholds defines
iwlwifi: mvm: rs: increase stay in column timeout
iwlwifi: mvm: rs: remove unused timestamp field
iwlwifi: mvm: rs: refactor to use rs_rate
iwlwifi: mvm: rs: remove unused parameter to rs_get_supported_rates
iwlwifi: mvm: rs: set dual_stream_ant_msk to ANT_AB always
iwlwifi: mvm: rs: fix mapping from HT/VHT rates to legacy
iwlwifi: mvm: rs: use the proper channel width define for legacy rate
iwlwifi: mvm: rs: overhaul search cycle state machine

Haim Dreyfuss (1):
iwlwifi: mvm: Implement low-priority scan

Johannes Berg (8):
iwlwifi: mvm: check sta_id/drain values in debugfs
iwlwifi: pcie: remove useless condition test
iwlwifi: mvm: small debugfs cleanups
iwlwifi: mvm: move interface-specific debugfs to a new file
iwlwifi: mvm: don't use void pointers in debugfs
iwlwifi: mvm: refactor debugfs copy_from_user()
iwlwifi: mvm: add iwl_mvm_sta_from_mac80211
iwlwifi: mvm: quota command max_duration should be zero

Luciano Coelho (3):
iwlwifi: mvm: set seqno also when no keys are set
iwlwifi: mvm: use a cast to calculate the last seqno from the next one
iwlwifi: mvm: don't restart HW if suspending fails before D3 image
is loaded

Michal Nazarewicz (1):
iwlwifi: pcie: remove minor dead code

Oren Givon (1):
iwlwifi: add new HW - 7265 series

drivers/net/wireless/iwlwifi/dvm/rs.h | 7 -
drivers/net/wireless/iwlwifi/dvm/tx.c | 1 +
drivers/net/wireless/iwlwifi/iwl-7000.c | 29 +-
drivers/net/wireless/iwlwifi/iwl-config.h | 11 +
drivers/net/wireless/iwlwifi/iwl-csr.h | 5 +-
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 3 +-
drivers/net/wireless/iwlwifi/iwl-prph.h | 3 +
drivers/net/wireless/iwlwifi/mvm/Makefile | 1 +
drivers/net/wireless/iwlwifi/mvm/bt-coex.c | 19 +-
drivers/net/wireless/iwlwifi/mvm/d3.c | 43 +-
drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c | 190 +++
drivers/net/wireless/iwlwifi/mvm/debugfs.c | 640 +-------
drivers/net/wireless/iwlwifi/mvm/debugfs.h | 101 ++
drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h | 1 +
drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h | 27 +-
drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h | 5 +-
drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | 51 +-
drivers/net/wireless/iwlwifi/mvm/mac80211.c | 19 +-
drivers/net/wireless/iwlwifi/mvm/mvm.h | 11 +-
drivers/net/wireless/iwlwifi/mvm/nvm.c | 23 +
drivers/net/wireless/iwlwifi/mvm/quota.c | 3 +-
drivers/net/wireless/iwlwifi/mvm/rs.c | 1685
+++++++++++----------
drivers/net/wireless/iwlwifi/mvm/rs.h | 150 +-
drivers/net/wireless/iwlwifi/mvm/scan.c | 55 +-
drivers/net/wireless/iwlwifi/mvm/sta.c | 14 +-
drivers/net/wireless/iwlwifi/mvm/sta.h | 6 +
drivers/net/wireless/iwlwifi/mvm/time-event.c | 7 +-
drivers/net/wireless/iwlwifi/mvm/tt.c | 2 +-
drivers/net/wireless/iwlwifi/mvm/tx.c | 11 +-
drivers/net/wireless/iwlwifi/mvm/utils.c | 8 +-
drivers/net/wireless/iwlwifi/pcie/drv.c | 26 +
drivers/net/wireless/iwlwifi/pcie/internal.h | 8 +
drivers/net/wireless/iwlwifi/pcie/rx.c | 33 +-
drivers/net/wireless/iwlwifi/pcie/trans.c | 3 -
drivers/net/wireless/iwlwifi/pcie/tx.c | 37 +-
35 files changed, 1628 insertions(+), 1610 deletions(-)
create mode 100644 drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
create mode 100644 drivers/net/wireless/iwlwifi/mvm/debugfs.h


Attachments:
signature.asc (836.00 B)
OpenPGP digital signature

2013-12-02 20:59:40

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 01/13] iwlwifi: mvm: rs: improve debug prints

From: Eyal Shapira <[email protected]>

Enable better tracking of different decisions made
by the rate scale algorithm.

Signed-off-by: Eyal Shapira <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/rs.c | 116 +++++++++++++++++++++++----------
1 file changed, 83 insertions(+), 33 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index a7efeb3..0655209 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -174,7 +174,7 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm,
struct ieee80211_sta *sta,
struct iwl_lq_sta *lq_sta, u32 rate_n_flags);
static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search);
-
+static const char *rs_pretty_lq_type(enum iwl_table_type type);

#ifdef CONFIG_MAC80211_DEBUGFS
static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
@@ -778,9 +778,6 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
struct iwl_scale_tbl_info tbl_type;
struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl;

- IWL_DEBUG_RATE_LIMIT(mvm,
- "get frame ack response, update rate scale window\n");
-
/* Treat uninitialized rate scaling data same as non-existing. */
if (!lq_sta) {
IWL_DEBUG_RATE(mvm, "Station rate scaling not created yet.\n");
@@ -1499,8 +1496,10 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm,
u8 update_search_tbl_counter = 0;
int ret;

- if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta))
+ if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) {
+ IWL_DEBUG_RATE(mvm, "BT COEX force switch to SISO A\n");
tbl->action = IWL_MIMO2_SWITCH_SISO_A;
+ }

start_action = tbl->action;
while (1) {
@@ -1721,8 +1720,6 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
struct iwl_mvm_sta *sta_priv = (void *)sta->drv_priv;
struct iwl_mvm_tid_data *tid_data;

- IWL_DEBUG_RATE(mvm, "rate scale calculate new rate for skb\n");
-
/* Send management frames and NO_ACK data using lowest rate. */
/* TODO: this could probably be improved.. */
if (!ieee80211_is_data(hdr->frame_control) ||
@@ -1758,14 +1755,9 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
/* current tx rate */
index = lq_sta->last_txrate_idx;

- IWL_DEBUG_RATE(mvm, "Rate scale index %d for type %d\n", index,
- tbl->lq_type);
-
/* rates available for this association, and for modulation mode */
rate_mask = rs_get_supported_rates(lq_sta, hdr, tbl->lq_type);

- IWL_DEBUG_RATE(mvm, "mask 0x%04X\n", rate_mask);
-
/* mask with station rate restriction */
if (is_legacy(tbl->lq_type)) {
if (lq_sta->band == IEEE80211_BAND_5GHZ)
@@ -1809,6 +1801,9 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
index = lq_sta->max_rate_idx;
update_lq = 1;
window = &(tbl->win[index]);
+ IWL_DEBUG_RATE(mvm,
+ "Forcing user max rate %d\n",
+ index);
goto lq_update;
}

@@ -1825,8 +1820,9 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
if ((fail_count < IWL_RATE_MIN_FAILURE_TH) &&
(window->success_counter < IWL_RATE_MIN_SUCCESS_TH)) {
IWL_DEBUG_RATE(mvm,
- "LQ: still below TH. succ=%d total=%d for index %d\n",
- window->success_counter, window->counter, index);
+ "(%s: %d): Test Window: succ %d total %d\n",
+ rs_pretty_lq_type(tbl->lq_type),
+ index, window->success_counter, window->counter);

/* Can't calculate this yet; not enough history */
window->average_tpt = IWL_INVALID_VALUE;
@@ -1854,7 +1850,8 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
* continuing to use the setup that we've been trying. */
if (window->average_tpt > lq_sta->last_tpt) {
IWL_DEBUG_RATE(mvm,
- "LQ: SWITCHING TO NEW TABLE suc=%d cur-tpt=%d old-tpt=%d\n",
+ "SWITCHING TO NEW TABLE SR: %d "
+ "cur-tpt %d old-tpt %d\n",
window->success_ratio,
window->average_tpt,
lq_sta->last_tpt);
@@ -1868,7 +1865,8 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
/* Else poor success; go back to mode in "active" table */
} else {
IWL_DEBUG_RATE(mvm,
- "LQ: GOING BACK TO THE OLD TABLE suc=%d cur-tpt=%d old-tpt=%d\n",
+ "GOING BACK TO THE OLD TABLE: SR %d "
+ "cur-tpt %d old-tpt %d\n",
window->success_ratio,
window->average_tpt,
lq_sta->last_tpt);
@@ -1916,20 +1914,31 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
if (high != IWL_RATE_INVALID)
high_tpt = tbl->win[high].average_tpt;

+ IWL_DEBUG_RATE(mvm,
+ "(%s: %d): cur_tpt %d SR %d low %d high %d low_tpt %d high_tpt %d\n",
+ rs_pretty_lq_type(tbl->lq_type), index, current_tpt,
+ sr, low, high, low_tpt, high_tpt);
+
scale_action = 0;

/* Too many failures, decrease rate */
if ((sr <= IWL_RATE_DECREASE_TH) || (current_tpt == 0)) {
IWL_DEBUG_RATE(mvm,
- "decrease rate because of low success_ratio\n");
+ "decrease rate because of low SR\n");
scale_action = -1;
/* No throughput measured yet for adjacent rates; try increase. */
} else if ((low_tpt == IWL_INVALID_VALUE) &&
(high_tpt == IWL_INVALID_VALUE)) {
- if (high != IWL_RATE_INVALID && sr >= IWL_RATE_INCREASE_TH)
+ if (high != IWL_RATE_INVALID && sr >= IWL_RATE_INCREASE_TH) {
+ IWL_DEBUG_RATE(mvm,
+ "Good SR and no high rate measurement. "
+ "Increase rate\n");
scale_action = 1;
- else if (low != IWL_RATE_INVALID)
+ } else if (low != IWL_RATE_INVALID) {
+ IWL_DEBUG_RATE(mvm,
+ "Remain in current rate\n");
scale_action = 0;
+ }
}

/* Both adjacent throughputs are measured, but neither one has better
@@ -1937,8 +1946,12 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
else if ((low_tpt != IWL_INVALID_VALUE) &&
(high_tpt != IWL_INVALID_VALUE) &&
(low_tpt < current_tpt) &&
- (high_tpt < current_tpt))
+ (high_tpt < current_tpt)) {
+ IWL_DEBUG_RATE(mvm,
+ "Both high and low are worse. "
+ "Maintain rate\n");
scale_action = 0;
+ }

/* At least one adjacent rate's throughput is measured,
* and may have better performance. */
@@ -1948,8 +1961,14 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
/* Higher rate has better throughput */
if (high_tpt > current_tpt &&
sr >= IWL_RATE_INCREASE_TH) {
+ IWL_DEBUG_RATE(mvm,
+ "Higher rate is better and good "
+ "SR. Increate rate\n");
scale_action = 1;
} else {
+ IWL_DEBUG_RATE(mvm,
+ "Higher rate isn't better OR "
+ "no good SR. Maintain rate\n");
scale_action = 0;
}

@@ -1958,9 +1977,13 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
/* Lower rate has better throughput */
if (low_tpt > current_tpt) {
IWL_DEBUG_RATE(mvm,
- "decrease rate because of low tpt\n");
+ "Lower rate is better. "
+ "Decrease rate\n");
scale_action = -1;
} else if (sr >= IWL_RATE_INCREASE_TH) {
+ IWL_DEBUG_RATE(mvm,
+ "Lower rate isn't better and "
+ "good SR. Increase rate\n");
scale_action = 1;
}
}
@@ -1970,12 +1993,17 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
* has been good at old rate. Don't change it. */
if ((scale_action == -1) && (low != IWL_RATE_INVALID) &&
((sr > IWL_RATE_HIGH_TH) ||
- (current_tpt > (100 * tbl->expected_tpt[low]))))
+ (current_tpt > (100 * tbl->expected_tpt[low])))) {
+ IWL_DEBUG_RATE(mvm,
+ "Sanity check failed. Maintain rate\n");
scale_action = 0;
+ }

/* Force a search in case BT doesn't like us being in MIMO */
if (is_mimo(tbl->lq_type) &&
!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) {
+ IWL_DEBUG_RATE(mvm,
+ "BT Coex forbids MIMO. Search for new config\n");
rs_stay_in_table(lq_sta, true);
goto lq_update;
}
@@ -1986,6 +2014,9 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
if (low != IWL_RATE_INVALID) {
update_lq = 1;
index = low;
+ } else {
+ IWL_DEBUG_RATE(mvm,
+ "At the bottom rate. Can't decrease\n");
}

break;
@@ -1994,6 +2025,9 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
if (high != IWL_RATE_INVALID) {
update_lq = 1;
index = high;
+ } else {
+ IWL_DEBUG_RATE(mvm,
+ "At the top rate. Can't increase\n");
}

break;
@@ -2003,10 +2037,6 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
break;
}

- IWL_DEBUG_RATE(mvm,
- "choose rate scale index %d action %d low %d high %d type %d\n",
- index, scale_action, low, high, tbl->lq_type);
-
lq_update:
/* Replace uCode's rate table for the destination station. */
if (update_lq)
@@ -2025,6 +2055,10 @@ lq_update:
/* Save current throughput to compare with "search" throughput*/
lq_sta->last_tpt = current_tpt;

+ IWL_DEBUG_RATE(mvm,
+ "Start Search: update_lq %d done_search %d stay_in_tbl %d win->counter %d\n",
+ update_lq, done_search, lq_sta->stay_in_tbl,
+ window->counter);
/* Select a new "search" modulation mode to try.
* If one is found, set up the new "search" table. */
if (is_legacy(tbl->lq_type))
@@ -2047,8 +2081,11 @@ lq_update:
index = iwl_hwrate_to_plcp_idx(tbl->current_rate);

IWL_DEBUG_RATE(mvm,
- "Switch current mcs: %X index: %d\n",
- tbl->current_rate, index);
+ "Switch to SEARCH TABLE: "
+ "mcs %X (%s: %d)\n",
+ tbl->current_rate,
+ rs_pretty_lq_type(tbl->lq_type),
+ index);
rs_fill_link_cmd(mvm, sta, lq_sta, tbl->current_rate);
iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false);
} else {
@@ -2169,8 +2206,6 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct iwl_lq_sta *lq_sta = mvm_sta;

- IWL_DEBUG_RATE_LIMIT(mvm, "rate scale calculate new rate for skb\n");
-
/* Get max rate if user set max rate */
if (lq_sta) {
lq_sta->max_rate_idx = txrc->max_rate_idx;
@@ -2554,7 +2589,6 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
>> RATE_MCS_ANT_POS);
if ((valid_tx_ant & ant_sel_tx) == ant_sel_tx) {
*rate_n_flags = lq_sta->dbg_fixed_rate;
- IWL_DEBUG_RATE(mvm, "Fixed rate ON\n");
} else {
lq_sta->dbg_fixed_rate = 0;
IWL_ERR(mvm,
@@ -2562,8 +2596,6 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
ant_sel_tx, valid_tx_ant);
IWL_DEBUG_RATE(mvm, "Fixed rate OFF\n");
}
- } else {
- IWL_DEBUG_RATE(mvm, "Fixed rate OFF\n");
}
}

@@ -2593,6 +2625,24 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
return count;
}

+static const char *rs_pretty_lq_type(enum iwl_table_type type)
+{
+ static const char * const lq_type[] = {
+ [LQ_NONE] = "NONE",
+ [LQ_LEGACY_A] = "LEGACY_A",
+ [LQ_LEGACY_G] = "LEGACY_G",
+ [LQ_HT_SISO] = "HT SISO",
+ [LQ_HT_MIMO2] = "HT MIMO",
+ [LQ_VHT_SISO] = "VHT SISO",
+ [LQ_VHT_MIMO2] = "VHT MIMO",
+ };
+
+ if (type < LQ_NONE || type >= LQ_MAX)
+ return "UNKNOWN";
+
+ return lq_type[type];
+}
+
static int rs_pretty_print_rate(char *buf, const u32 rate)
{
static const char * const ant_name[] = {
--
1.7.9.5


2013-12-03 17:19:33

by Emmanuel Grumbach

[permalink] [raw]
Subject: Re: pull request: iwlwifi-next 2013-12-2



On 12/02/2013 10:51 PM, Emmanuel Grumbach wrote:
> Hi John,
>
> This is the fixed and enlarged pull request for 3.14. It includes the
> patches in my previous pull request that was based on a bad patch.
>
> I have here a big rework of the rate control by Eyal. This is obviously
> the biggest part of this batch.
> I also have enhancement of protection flags by Avri and a few bits for
> WoWLAN by Eliad and Luca. Johannes cleans up the debugfs plus a few
> fixes. I provided a few things for Bluetooth coexistence.
> Besides this we have an implementation for low priority scan.
>
> Note that I had to merge iwlwifi-fixes into -next to solve conflicts
> before they hit linux-next.
> Please let me know about issues you may face - Thanks!
>

So - I found out that merging iwlwifi-fixes wasn't a good idea... So I
updated my tree and added a trivial compilation fix.

New head: 2f579448f3a60c8ede544dd0951b8d2a2e282ba2.

I hope that I have done all the possible mistakes now and that next time
I will get it right the first time... Sorry for all the mess...


Attachments:
signature.asc (836.00 B)
OpenPGP digital signature

2013-12-09 20:30:13

by John W. Linville

[permalink] [raw]
Subject: Re: pull request: iwlwifi-next 2013-12-2

On Tue, Dec 03, 2013 at 07:19:23PM +0200, Emmanuel Grumbach wrote:
>
>
> On 12/02/2013 10:51 PM, Emmanuel Grumbach wrote:
> > Hi John,
> >
> > This is the fixed and enlarged pull request for 3.14. It includes the
> > patches in my previous pull request that was based on a bad patch.
> >
> > I have here a big rework of the rate control by Eyal. This is obviously
> > the biggest part of this batch.
> > I also have enhancement of protection flags by Avri and a few bits for
> > WoWLAN by Eliad and Luca. Johannes cleans up the debugfs plus a few
> > fixes. I provided a few things for Bluetooth coexistence.
> > Besides this we have an implementation for low priority scan.
> >
> > Note that I had to merge iwlwifi-fixes into -next to solve conflicts
> > before they hit linux-next.
> > Please let me know about issues you may face - Thanks!
> >
>
> So - I found out that merging iwlwifi-fixes wasn't a good idea... So I
> updated my tree and added a trivial compilation fix.
>
> New head: 2f579448f3a60c8ede544dd0951b8d2a2e282ba2.
>
> I hope that I have done all the possible mistakes now and that next time
> I will get it right the first time... Sorry for all the mess...

This has a couple of merge conflicts when pulling it into
wireless-next. I don't have the time to work through them today,
so I'm not pulling.

If you would like to work through the resolution and advise me on
how to do it, I'd love to hear about it. :-)

John
--
John W. Linville Someday the world will need a hero, and you
[email protected] might be all we have. Be ready.

2013-12-09 20:33:05

by Emmanuel Grumbach

[permalink] [raw]
Subject: Re: pull request: iwlwifi-next 2013-12-2

Hi John,

On 12/03/2013 07:19 PM, Emmanuel Grumbach wrote:
>
>
> On 12/02/2013 10:51 PM, Emmanuel Grumbach wrote:
>> Hi John,
>>
>> This is the fixed and enlarged pull request for 3.14. It includes the
>> patches in my previous pull request that was based on a bad patch.
>>
>> I have here a big rework of the rate control by Eyal. This is obviously
>> the biggest part of this batch.
>> I also have enhancement of protection flags by Avri and a few bits for
>> WoWLAN by Eliad and Luca. Johannes cleans up the debugfs plus a few
>> fixes. I provided a few things for Bluetooth coexistence.
>> Besides this we have an implementation for low priority scan.
>>
>> Note that I had to merge iwlwifi-fixes into -next to solve conflicts
>> before they hit linux-next.
>> Please let me know about issues you may face - Thanks!
>>
>
> So - I found out that merging iwlwifi-fixes wasn't a good idea... So I
> updated my tree and added a trivial compilation fix.
>
> New head: 2f579448f3a60c8ede544dd0951b8d2a2e282ba2.
>
> I hope that I have done all the possible mistakes now and that next time
> I will get it right the first time... Sorry for all the mess...
>

Since you merged wireless into wireless-next, I decided to rebase my
tree on top of wireless-next to make your life easier. I solved the
conflicts you would have faced.
New head: 9d10849e4ea8bf9d8da80afa73918a9fe45c09ef.


Attachments:
signature.asc (836.00 B)
OpenPGP digital signature

2013-12-02 20:59:53

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 08/13] iwlwifi: mvm: rs: remove unused parameter to rs_get_supported_rates

From: Eyal Shapira <[email protected]>

No use of the ieee80211 header. Drop it.

Signed-off-by: Eyal Shapira <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/rs.c | 12 ++----------
1 file changed, 2 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index 3af9062..7beb548 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -597,15 +597,7 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *ucode_rate,
return 1;
}

-/**
- * rs_get_supported_rates - get the available rates
- *
- * if management frame or broadcast frame only return
- * basic available rates.
- *
- */
static u16 rs_get_supported_rates(struct iwl_lq_sta *lq_sta,
- struct ieee80211_hdr *hdr,
struct rs_rate *rate)
{
if (is_legacy(rate))
@@ -704,7 +696,7 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
rate->sgi = false;
}

- rate_mask = rs_get_supported_rates(lq_sta, NULL, rate);
+ rate_mask = rs_get_supported_rates(lq_sta, rate);

/* Mask with station rate restriction */
if (is_legacy(rate)) {
@@ -1762,7 +1754,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
index = lq_sta->last_txrate_idx;

/* rates available for this association, and for modulation mode */
- rate_mask = rs_get_supported_rates(lq_sta, hdr, rate);
+ rate_mask = rs_get_supported_rates(lq_sta, rate);

/* mask with station rate restriction */
if (is_legacy(rate)) {
--
1.7.9.5


2013-12-02 20:59:49

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 05/13] iwlwifi: mvm: rs: increase stay in column timeout

From: Eyal Shapira <[email protected]>

Remain in the same Tx modulation (i.e. column) for a longer
time before starting a search cycle for a better modulation.
This has been shown to give better results.
Also change the name of the timeout define to better match its
description.

Signed-off-by: Eyal Shapira <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/rs.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index a289b77..9249e52 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -52,8 +52,8 @@

/* max allowed rate miss before sync LQ cmd */
#define IWL_MISSED_RATE_MAX 15
-/* max time to accum history 2 seconds */
-#define IWL_RATE_SCALE_FLUSH_INTVL (3*HZ)
+#define RS_STAY_IN_COLUMN_TIMEOUT (5*HZ)
+

static u8 rs_ht_to_legacy[] = {
[IWL_RATE_1M_INDEX] = IWL_RATE_6M_INDEX,
@@ -1599,7 +1599,7 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
flush_interval_passed =
time_after(jiffies,
(unsigned long)(lq_sta->flush_timer +
- IWL_RATE_SCALE_FLUSH_INTVL));
+ RS_STAY_IN_COLUMN_TIMEOUT));

/*
* Check if we should allow search for new modulation mode.
--
1.7.9.5


2013-12-11 16:00:16

by John W. Linville

[permalink] [raw]
Subject: Re: pull request: iwlwifi-next 2013-12-2

On Mon, Dec 09, 2013 at 10:38:48PM +0200, Emmanuel Grumbach wrote:
>
>
> On 12/09/2013 10:27 PM, John W. Linville wrote:
> > On Tue, Dec 03, 2013 at 07:19:23PM +0200, Emmanuel Grumbach wrote:
> >>
> >>
> >> On 12/02/2013 10:51 PM, Emmanuel Grumbach wrote:
> >>> Hi John,
> >>>
> >>> This is the fixed and enlarged pull request for 3.14. It includes the
> >>> patches in my previous pull request that was based on a bad patch.
> >>>
> >>> I have here a big rework of the rate control by Eyal. This is obviously
> >>> the biggest part of this batch.
> >>> I also have enhancement of protection flags by Avri and a few bits for
> >>> WoWLAN by Eliad and Luca. Johannes cleans up the debugfs plus a few
> >>> fixes. I provided a few things for Bluetooth coexistence.
> >>> Besides this we have an implementation for low priority scan.
> >>>
> >>> Note that I had to merge iwlwifi-fixes into -next to solve conflicts
> >>> before they hit linux-next.
> >>> Please let me know about issues you may face - Thanks!
> >>>
> >>
> >> So - I found out that merging iwlwifi-fixes wasn't a good idea... So I
> >> updated my tree and added a trivial compilation fix.
> >>
> >> New head: 2f579448f3a60c8ede544dd0951b8d2a2e282ba2.
> >>
> >> I hope that I have done all the possible mistakes now and that next time
> >> I will get it right the first time... Sorry for all the mess...
> >
> > This has a couple of merge conflicts when pulling it into
> > wireless-next. I don't have the time to work through them today,
> > so I'm not pulling.
> >
> > If you would like to work through the resolution and advise me on
> > how to do it, I'd love to hear about it. :-)
> >
> > John
> >
>
> Cool - I rebased my tree before I read your mail.

Pulling now...

--
John W. Linville Someday the world will need a hero, and you
[email protected] might be all we have. Be ready.

2013-12-02 20:59:47

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 04/13] iwlwifi: mvm: rs: rename thresholds defines

From: Eyal Shapira <[email protected]>

Rename for clearer names.

Signed-off-by: Eyal Shapira <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/rs.c | 4 ++--
drivers/net/wireless/iwlwifi/mvm/rs.h | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index 882ecd3..a289b77 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -1107,7 +1107,7 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm,
* "active" throughput (under perfect conditions).
*/
if ((((100 * tpt_tbl[rate]) > lq_sta->last_tpt) &&
- ((active_sr > IWL_RATE_DECREASE_TH) &&
+ ((active_sr > RS_SR_FORCE_DECREASE) &&
(active_sr <= IWL_RATE_HIGH_TH) &&
(tpt_tbl[rate] <= active_tpt))) ||
((active_sr >= IWL_RATE_SCALE_SWITCH) &&
@@ -1928,7 +1928,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
scale_action = 0;

/* Too many failures, decrease rate */
- if ((sr <= IWL_RATE_DECREASE_TH) || (current_tpt == 0)) {
+ if ((sr <= RS_SR_FORCE_DECREASE) || (current_tpt == 0)) {
IWL_DEBUG_RATE(mvm,
"decrease rate because of low SR\n");
scale_action = -1;
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h
index 5dd30ea..e5d448c 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.h
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.h
@@ -155,7 +155,7 @@ enum {
#define IWL_RATE_SCALE_SWITCH 10880 /* 85% */
#define IWL_RATE_HIGH_TH 10880 /* 85% */
#define IWL_RATE_INCREASE_TH 6400 /* 50% */
-#define IWL_RATE_DECREASE_TH 1920 /* 15% */
+#define RS_SR_FORCE_DECREASE 1920 /* 15% */

/* possible actions when in legacy mode */
enum {
--
1.7.9.5


2013-12-02 20:59:59

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 12/13] iwlwifi: mvm: rs: overhaul search cycle state machine

From: Eyal Shapira <[email protected]>

Rewrite the search cycle state machine to use a more data
oriented approach where the different Tx columns (configs)
limitations and next columns to search are reprsented in
tables which are easy to change. This overhaul also includes
several major fixes:

1. Prevent going back to a specific Tx column in a search
cycle if it was already explored.

2. Avoid switching to a Tx column that doesn't have any chance
if it performs perfectly to beat the current throughput we're
getting.

These issues were degrading throughput as they were causing
switching to "bad" Tx columns.

Signed-off-by: Eyal Shapira <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/rs.c | 921 +++++++++++++++------------------
drivers/net/wireless/iwlwifi/mvm/rs.h | 64 +--
2 files changed, 458 insertions(+), 527 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index 1bfdde5..1bb6581 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -123,6 +123,190 @@ static const struct iwl_rs_rate_info iwl_rates[IWL_RATE_COUNT] = {
IWL_DECLARE_MCS_RATE(9), /* MCS 9 */
};

+enum rs_column_mode {
+ RS_INVALID = 0,
+ RS_LEGACY,
+ RS_SISO,
+ RS_MIMO2,
+};
+
+#define MAX_NEXT_COLUMNS 5
+#define MAX_COLUMN_CHECKS 3
+
+typedef bool (*allow_column_func_t) (struct iwl_mvm *mvm,
+ struct ieee80211_sta *sta,
+ struct iwl_scale_tbl_info *tbl);
+
+struct rs_tx_column {
+ enum rs_column_mode mode;
+ u8 ant;
+ bool sgi;
+ enum rs_column next_columns[MAX_NEXT_COLUMNS];
+ allow_column_func_t checks[MAX_COLUMN_CHECKS];
+};
+
+static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
+ struct iwl_scale_tbl_info *tbl)
+{
+ if (!sta->ht_cap.ht_supported)
+ return false;
+
+ if (sta->smps_mode == IEEE80211_SMPS_STATIC)
+ return false;
+
+ if (num_of_ant(iwl_fw_valid_tx_ant(mvm->fw)) < 2)
+ return false;
+
+ if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta))
+ return false;
+
+ return true;
+}
+
+static bool rs_siso_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
+ struct iwl_scale_tbl_info *tbl)
+{
+ if (!sta->ht_cap.ht_supported)
+ return false;
+
+ return true;
+}
+
+static bool rs_sgi_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
+ struct iwl_scale_tbl_info *tbl)
+{
+ struct rs_rate *rate = &tbl->rate;
+ struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
+ struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
+
+ if (is_ht20(rate) && (ht_cap->cap &
+ IEEE80211_HT_CAP_SGI_20))
+ return true;
+ if (is_ht40(rate) && (ht_cap->cap &
+ IEEE80211_HT_CAP_SGI_40))
+ return true;
+ if (is_ht80(rate) && (vht_cap->cap &
+ IEEE80211_VHT_CAP_SHORT_GI_80))
+ return true;
+
+ return false;
+}
+
+static const struct rs_tx_column rs_tx_columns[] = {
+ [RS_COLUMN_LEGACY_ANT_A] = {
+ .mode = RS_LEGACY,
+ .ant = ANT_A,
+ .next_columns = {
+ RS_COLUMN_LEGACY_ANT_B,
+ RS_COLUMN_SISO_ANT_A,
+ RS_COLUMN_MIMO2,
+ RS_COLUMN_INVALID,
+ RS_COLUMN_INVALID,
+ },
+ },
+ [RS_COLUMN_LEGACY_ANT_B] = {
+ .mode = RS_LEGACY,
+ .ant = ANT_B,
+ .next_columns = {
+ RS_COLUMN_LEGACY_ANT_A,
+ RS_COLUMN_SISO_ANT_B,
+ RS_COLUMN_MIMO2,
+ RS_COLUMN_INVALID,
+ RS_COLUMN_INVALID,
+ },
+ },
+ [RS_COLUMN_SISO_ANT_A] = {
+ .mode = RS_SISO,
+ .ant = ANT_A,
+ .next_columns = {
+ RS_COLUMN_SISO_ANT_B,
+ RS_COLUMN_MIMO2,
+ RS_COLUMN_SISO_ANT_A_SGI,
+ RS_COLUMN_INVALID,
+ RS_COLUMN_INVALID,
+ },
+ .checks = {
+ rs_siso_allow,
+ },
+ },
+ [RS_COLUMN_SISO_ANT_B] = {
+ .mode = RS_SISO,
+ .ant = ANT_B,
+ .next_columns = {
+ RS_COLUMN_SISO_ANT_A,
+ RS_COLUMN_MIMO2,
+ RS_COLUMN_SISO_ANT_B_SGI,
+ RS_COLUMN_INVALID,
+ RS_COLUMN_INVALID,
+ },
+ .checks = {
+ rs_siso_allow,
+ },
+ },
+ [RS_COLUMN_SISO_ANT_A_SGI] = {
+ .mode = RS_SISO,
+ .ant = ANT_A,
+ .sgi = true,
+ .next_columns = {
+ RS_COLUMN_SISO_ANT_B_SGI,
+ RS_COLUMN_MIMO2_SGI,
+ RS_COLUMN_SISO_ANT_A,
+ RS_COLUMN_INVALID,
+ RS_COLUMN_INVALID,
+ },
+ .checks = {
+ rs_siso_allow,
+ rs_sgi_allow,
+ },
+ },
+ [RS_COLUMN_SISO_ANT_B_SGI] = {
+ .mode = RS_SISO,
+ .ant = ANT_B,
+ .sgi = true,
+ .next_columns = {
+ RS_COLUMN_SISO_ANT_A_SGI,
+ RS_COLUMN_MIMO2_SGI,
+ RS_COLUMN_SISO_ANT_B,
+ RS_COLUMN_INVALID,
+ RS_COLUMN_INVALID,
+ },
+ .checks = {
+ rs_siso_allow,
+ rs_sgi_allow,
+ },
+ },
+ [RS_COLUMN_MIMO2] = {
+ .mode = RS_MIMO2,
+ .ant = ANT_AB,
+ .next_columns = {
+ RS_COLUMN_SISO_ANT_A,
+ RS_COLUMN_MIMO2_SGI,
+ RS_COLUMN_INVALID,
+ RS_COLUMN_INVALID,
+ RS_COLUMN_INVALID,
+ },
+ .checks = {
+ rs_mimo_allow,
+ },
+ },
+ [RS_COLUMN_MIMO2_SGI] = {
+ .mode = RS_MIMO2,
+ .ant = ANT_AB,
+ .sgi = true,
+ .next_columns = {
+ RS_COLUMN_SISO_ANT_A_SGI,
+ RS_COLUMN_MIMO2,
+ RS_COLUMN_INVALID,
+ RS_COLUMN_INVALID,
+ RS_COLUMN_INVALID,
+ },
+ .checks = {
+ rs_mimo_allow,
+ rs_sgi_allow,
+ },
+ },
+};
+
static inline u8 rs_extract_rate(u32 rate_n_flags)
{
/* also works for HT because bits 7:6 are zero there */
@@ -839,6 +1023,9 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
lq_sta->missed_rate_counter++;
if (lq_sta->missed_rate_counter > IWL_MISSED_RATE_MAX) {
lq_sta->missed_rate_counter = 0;
+ IWL_DEBUG_RATE(mvm,
+ "Too many rates mismatch. Send sync LQ. rs_state %d\n",
+ lq_sta->rs_state);
iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false);
}
/* Regardless, ignore this status info for outdated rate */
@@ -888,7 +1075,7 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
info->status.ampdu_ack_len);

/* Update success/fail counts if not searching for new mode */
- if (lq_sta->stay_in_tbl) {
+ if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) {
lq_sta->total_success += info->status.ampdu_ack_len;
lq_sta->total_failed += (info->status.ampdu_len -
info->status.ampdu_ack_len);
@@ -915,14 +1102,20 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
tmp_tbl = curr_tbl;
else if (rs_rate_match(&rate, &other_tbl->rate))
tmp_tbl = other_tbl;
- else
+ else {
+ IWL_DEBUG_RATE(mvm,
+ "Tx packet rate doesn't match ACTIVE or SEARCH tables\n");
+ rs_dump_rate(mvm, &rate, "Tx PACKET:");
+ rs_dump_rate(mvm, &curr_tbl->rate, "CURRENT:");
+ rs_dump_rate(mvm, &other_tbl->rate, "OTHER:");
continue;
+ }
rs_collect_tx_data(tmp_tbl, rate.index, 1,
i < retries ? 0 : legacy_success);
}

/* Update success/fail counts if not searching for new mode */
- if (lq_sta->stay_in_tbl) {
+ if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) {
lq_sta->total_success += legacy_success;
lq_sta->total_failed += retries + (1 - legacy_success);
}
@@ -946,8 +1139,8 @@ done:
static void rs_set_stay_in_table(struct iwl_mvm *mvm, u8 is_legacy,
struct iwl_lq_sta *lq_sta)
{
- IWL_DEBUG_RATE(mvm, "we are staying in the same table\n");
- lq_sta->stay_in_tbl = 1; /* only place this gets set */
+ IWL_DEBUG_RATE(mvm, "Moving to RS_STATE_STAY_IN_COLUMN\n");
+ lq_sta->rs_state = RS_STATE_STAY_IN_COLUMN;
if (is_legacy) {
lq_sta->table_count_limit = IWL_LEGACY_TABLE_COUNT;
lq_sta->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT;
@@ -961,38 +1154,31 @@ static void rs_set_stay_in_table(struct iwl_mvm *mvm, u8 is_legacy,
lq_sta->total_failed = 0;
lq_sta->total_success = 0;
lq_sta->flush_timer = jiffies;
- lq_sta->action_counter = 0;
+ lq_sta->visited_columns = 0;
}

-/*
- * Find correct throughput table for given mode of modulation
- */
-static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
- struct iwl_scale_tbl_info *tbl)
+static s32 *rs_get_expected_tpt_table(struct iwl_lq_sta *lq_sta,
+ const struct rs_tx_column *column,
+ u32 bw)
{
/* Used to choose among HT tables */
s32 (*ht_tbl_pointer)[IWL_RATE_COUNT];
- struct rs_rate *rate = &tbl->rate;

- /* Check for invalid LQ type */
- if (WARN_ON_ONCE(!is_legacy(rate) && !is_ht(rate) &&
- !(is_vht(rate)))) {
- tbl->expected_tpt = expected_tpt_legacy;
- return;
- }
+ if (WARN_ON_ONCE(column->mode != RS_LEGACY &&
+ column->mode != RS_SISO &&
+ column->mode != RS_MIMO2))
+ return expected_tpt_legacy;

/* Legacy rates have only one table */
- if (is_legacy(rate)) {
- tbl->expected_tpt = expected_tpt_legacy;
- return;
- }
+ if (column->mode == RS_LEGACY)
+ return expected_tpt_legacy;

ht_tbl_pointer = expected_tpt_mimo2_20MHz;
/* Choose among many HT tables depending on number of streams
* (SISO/MIMO2), channel width (20/40/80), SGI, and aggregation
* status */
- if (is_siso(rate)) {
- switch (rate->bw) {
+ if (column->mode == RS_SISO) {
+ switch (bw) {
case RATE_MCS_CHAN_WIDTH_20:
ht_tbl_pointer = expected_tpt_siso_20MHz;
break;
@@ -1005,8 +1191,8 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
default:
WARN_ON_ONCE(1);
}
- } else if (is_mimo2(rate)) {
- switch (rate->bw) {
+ } else if (column->mode == RS_MIMO2) {
+ switch (bw) {
case RATE_MCS_CHAN_WIDTH_20:
ht_tbl_pointer = expected_tpt_mimo2_20MHz;
break;
@@ -1023,14 +1209,23 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
WARN_ON_ONCE(1);
}

- if (!rate->sgi && !lq_sta->is_agg) /* Normal */
- tbl->expected_tpt = ht_tbl_pointer[0];
- else if (rate->sgi && !lq_sta->is_agg) /* SGI */
- tbl->expected_tpt = ht_tbl_pointer[1];
- else if (!rate->sgi && lq_sta->is_agg) /* AGG */
- tbl->expected_tpt = ht_tbl_pointer[2];
+ if (!column->sgi && !lq_sta->is_agg) /* Normal */
+ return ht_tbl_pointer[0];
+ else if (column->sgi && !lq_sta->is_agg) /* SGI */
+ return ht_tbl_pointer[1];
+ else if (!column->sgi && lq_sta->is_agg) /* AGG */
+ return ht_tbl_pointer[2];
else /* AGG+SGI */
- tbl->expected_tpt = ht_tbl_pointer[3];
+ return ht_tbl_pointer[3];
+}
+
+static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
+ struct iwl_scale_tbl_info *tbl)
+{
+ struct rs_rate *rate = &tbl->rate;
+ const struct rs_tx_column *column = &rs_tx_columns[tbl->column];
+
+ tbl->expected_tpt = rs_get_expected_tpt_table(lq_sta, column, rate->bw);
}

/*
@@ -1135,19 +1330,6 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm,
return new_rate;
}

-/* Move to the next action and wrap around to the first action in case
- * we're at the last action. Assumes actions start at 0.
- */
-static inline void rs_move_next_action(struct iwl_scale_tbl_info *tbl,
- u8 last_action)
-{
- BUILD_BUG_ON(IWL_LEGACY_FIRST_ACTION != 0);
- BUILD_BUG_ON(IWL_SISO_FIRST_ACTION != 0);
- BUILD_BUG_ON(IWL_MIMO2_FIRST_ACTION != 0);
-
- tbl->action = (tbl->action + 1) % (last_action + 1);
-}
-
static u32 rs_bw_from_sta_bw(struct ieee80211_sta *sta)
{
if (sta->bandwidth >= IEEE80211_STA_RX_BW_80)
@@ -1158,409 +1340,6 @@ static u32 rs_bw_from_sta_bw(struct ieee80211_sta *sta)
return RATE_MCS_CHAN_WIDTH_20;
}

-static bool rs_sgi_allowed(struct rs_rate *rate,
- struct ieee80211_sta *sta)
-{
- struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
- struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
-
- if (is_ht20(rate) && (ht_cap->cap &
- IEEE80211_HT_CAP_SGI_20))
- return true;
- if (is_ht40(rate) && (ht_cap->cap &
- IEEE80211_HT_CAP_SGI_40))
- return true;
- if (is_ht80(rate) && (vht_cap->cap &
- IEEE80211_VHT_CAP_SHORT_GI_80))
- return true;
-
- return false;
-}
-
-/*
- * Set up search table for MIMO2
- */
-static int rs_switch_to_mimo2(struct iwl_mvm *mvm,
- struct iwl_lq_sta *lq_sta,
- struct ieee80211_sta *sta,
- struct iwl_scale_tbl_info *tbl, int index)
-{
- u16 rate_mask;
- s32 rate_idx;
-
- if (!sta->ht_cap.ht_supported)
- return -1;
-
- if (sta->smps_mode == IEEE80211_SMPS_STATIC)
- return -1;
-
- /* Need both Tx chains/antennas to support MIMO */
- if (num_of_ant(iwl_fw_valid_tx_ant(mvm->fw)) < 2)
- return -1;
-
- IWL_DEBUG_RATE(mvm, "LQ: try to switch to MIMO2\n");
-
- tbl->rate.type = lq_sta->is_vht ? LQ_VHT_MIMO2 : LQ_HT_MIMO2;
- tbl->action = 0;
- tbl->max_search = IWL_MAX_SEARCH;
- rate_mask = lq_sta->active_mimo2_rate;
-
- tbl->rate.bw = rs_bw_from_sta_bw(sta);
- rs_set_expected_tpt_table(lq_sta, tbl);
-
- rate_idx = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index);
-
- IWL_DEBUG_RATE(mvm, "LQ: MIMO2 best rate %d mask %X\n",
- rate_idx, rate_mask);
- if ((rate_idx == IWL_RATE_INVALID) || !((1 << rate_idx) & rate_mask)) {
- IWL_DEBUG_RATE(mvm, "Can't switch with index %d rate mask %x\n",
- rate_idx, rate_mask);
- return -1;
- }
-
- tbl->rate.index = rate_idx;
- tbl->current_rate = ucode_rate_from_rs_rate(mvm, &tbl->rate);
-
- IWL_DEBUG_RATE(mvm, "LQ: Switch to new mcs %X index\n",
- tbl->current_rate);
- return 0;
-}
-
-/*
- * Set up search table for SISO
- */
-static int rs_switch_to_siso(struct iwl_mvm *mvm,
- struct iwl_lq_sta *lq_sta,
- struct ieee80211_sta *sta,
- struct iwl_scale_tbl_info *tbl, int index)
-{
- u16 rate_mask;
- s32 rate_idx;
-
- if (!sta->ht_cap.ht_supported)
- return -1;
-
- IWL_DEBUG_RATE(mvm, "LQ: try to switch to SISO\n");
-
- tbl->rate.type = lq_sta->is_vht ? LQ_VHT_SISO : LQ_HT_SISO;
- tbl->action = 0;
- tbl->max_search = IWL_MAX_SEARCH;
- rate_mask = lq_sta->active_siso_rate;
-
- tbl->rate.bw = rs_bw_from_sta_bw(sta);
- rs_set_expected_tpt_table(lq_sta, tbl);
- rate_idx = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index);
-
- IWL_DEBUG_RATE(mvm, "LQ: get best rate %d mask %X\n",
- rate_idx, rate_mask);
- if ((rate_idx == IWL_RATE_INVALID) || !((1 << rate_idx) & rate_mask)) {
- IWL_DEBUG_RATE(mvm,
- "can not switch with index %d rate mask %x\n",
- rate_idx, rate_mask);
- return -1;
- }
-
- tbl->rate.index = rate_idx;
- tbl->current_rate = ucode_rate_from_rs_rate(mvm, &tbl->rate);
-
- IWL_DEBUG_RATE(mvm, "LQ: Switch to new mcs %X index\n",
- tbl->current_rate);
- return 0;
-}
-
-/*
- * Try to switch to new modulation mode from legacy
- */
-static int rs_move_legacy_other(struct iwl_mvm *mvm,
- struct iwl_lq_sta *lq_sta,
- struct ieee80211_sta *sta,
- int index)
-{
- struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
- struct iwl_scale_tbl_info *search_tbl =
- &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
- struct rs_rate *rate = &search_tbl->rate;
- struct iwl_rate_scale_data *window = &(tbl->win[index]);
- u32 sz = (sizeof(struct iwl_scale_tbl_info) -
- (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
- u8 start_action;
- u8 valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
- u8 tx_chains_num = num_of_ant(valid_tx_ant);
- int ret;
- u8 update_search_tbl_counter = 0;
-
- start_action = tbl->action;
- while (1) {
- lq_sta->action_counter++;
- switch (tbl->action) {
- case IWL_LEGACY_SWITCH_ANTENNA:
- IWL_DEBUG_RATE(mvm, "LQ: Legacy toggle Antenna\n");
-
- if (tx_chains_num <= 1)
- break;
-
- /* Don't change antenna if success has been great */
- if (window->success_ratio >= IWL_RS_GOOD_RATIO)
- break;
-
- /* Set up search table to try other antenna */
- memcpy(search_tbl, tbl, sz);
-
- if (rs_toggle_antenna(valid_tx_ant,
- &search_tbl->current_rate,
- &search_tbl->rate)) {
- update_search_tbl_counter = 1;
- rs_set_expected_tpt_table(lq_sta, search_tbl);
- goto out;
- }
- break;
- case IWL_LEGACY_SWITCH_SISO:
- IWL_DEBUG_RATE(mvm, "LQ: Legacy switch to SISO\n");
-
- /* Set up search table to try SISO */
- memcpy(search_tbl, tbl, sz);
- rate->sgi = false;
- ret = rs_switch_to_siso(mvm, lq_sta, sta,
- search_tbl, index);
- if (!ret) {
- lq_sta->action_counter = 0;
- goto out;
- }
-
- break;
- case IWL_LEGACY_SWITCH_MIMO2:
- IWL_DEBUG_RATE(mvm, "LQ: Legacy switch to MIMO2\n");
-
- /* Set up search table to try MIMO */
- memcpy(search_tbl, tbl, sz);
- rate->sgi = false;
- rate->ant = ANT_AB;
-
- if (!rs_is_valid_ant(valid_tx_ant,
- rate->ant))
- break;
-
- ret = rs_switch_to_mimo2(mvm, lq_sta, sta,
- search_tbl, index);
- if (!ret) {
- lq_sta->action_counter = 0;
- goto out;
- }
- break;
- default:
- WARN_ON_ONCE(1);
- }
- rs_move_next_action(tbl, IWL_LEGACY_LAST_ACTION);
-
- if (tbl->action == start_action)
- break;
- }
- rate->type = LQ_NONE;
- return 0;
-
-out:
- lq_sta->search_better_tbl = 1;
- rs_move_next_action(tbl, IWL_LEGACY_LAST_ACTION);
- if (update_search_tbl_counter)
- search_tbl->action = tbl->action;
- return 0;
-}
-
-/*
- * Try to switch to new modulation mode from SISO
- */
-static int rs_move_siso_to_other(struct iwl_mvm *mvm,
- struct iwl_lq_sta *lq_sta,
- struct ieee80211_sta *sta, int index)
-{
- struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
- struct iwl_scale_tbl_info *search_tbl =
- &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
- struct rs_rate *rate = &search_tbl->rate;
- struct iwl_rate_scale_data *window = &(tbl->win[index]);
- u32 sz = (sizeof(struct iwl_scale_tbl_info) -
- (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
- u8 start_action;
- u8 valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
- u8 tx_chains_num = num_of_ant(valid_tx_ant);
- u8 update_search_tbl_counter = 0;
- int ret;
-
- if (tbl->action == IWL_SISO_SWITCH_MIMO2 &&
- !iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta))
- tbl->action = IWL_SISO_SWITCH_ANTENNA;
-
- start_action = tbl->action;
- while (1) {
- lq_sta->action_counter++;
- switch (tbl->action) {
- case IWL_SISO_SWITCH_ANTENNA:
- IWL_DEBUG_RATE(mvm, "LQ: SISO toggle Antenna\n");
- if (tx_chains_num <= 1)
- break;
-
- if (window->success_ratio >= IWL_RS_GOOD_RATIO &&
- BT_MBOX_MSG(&mvm->last_bt_notif, 3,
- TRAFFIC_LOAD) == 0)
- break;
-
- memcpy(search_tbl, tbl, sz);
- if (rs_toggle_antenna(valid_tx_ant,
- &search_tbl->current_rate,
- rate)) {
- update_search_tbl_counter = 1;
- goto out;
- }
- break;
- case IWL_SISO_SWITCH_MIMO2:
- IWL_DEBUG_RATE(mvm, "LQ: SISO switch to MIMO2\n");
- memcpy(search_tbl, tbl, sz);
- rate->sgi = false;
- rate->ant = ANT_AB;
-
- if (!rs_is_valid_ant(valid_tx_ant,
- rate->ant))
- break;
-
- ret = rs_switch_to_mimo2(mvm, lq_sta, sta,
- search_tbl, index);
- if (!ret)
- goto out;
- break;
- case IWL_SISO_SWITCH_GI:
- if (!rs_sgi_allowed(rate, sta))
- break;
-
- IWL_DEBUG_RATE(mvm, "LQ: SISO toggle SGI/NGI\n");
-
- memcpy(search_tbl, tbl, sz);
- rate->sgi = !tbl->rate.sgi;
- rs_set_expected_tpt_table(lq_sta, search_tbl);
- if (tbl->rate.sgi) {
- s32 tpt = lq_sta->last_tpt / 100;
- if (tpt >= search_tbl->expected_tpt[index])
- break;
- }
- rate->index = index;
- search_tbl->current_rate =
- ucode_rate_from_rs_rate(mvm, rate);
- update_search_tbl_counter = 1;
- goto out;
- default:
- WARN_ON_ONCE(1);
- }
- rs_move_next_action(tbl, IWL_SISO_LAST_ACTION);
-
- if (tbl->action == start_action)
- break;
- }
- rate->type = LQ_NONE;
- return 0;
-
- out:
- lq_sta->search_better_tbl = 1;
- rs_move_next_action(tbl, IWL_SISO_LAST_ACTION);
- if (update_search_tbl_counter)
- search_tbl->action = tbl->action;
-
- return 0;
-}
-
-/*
- * Try to switch to new modulation mode from MIMO2
- */
-static int rs_move_mimo2_to_other(struct iwl_mvm *mvm,
- struct iwl_lq_sta *lq_sta,
- struct ieee80211_sta *sta, int index)
-{
- struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
- struct iwl_scale_tbl_info *search_tbl =
- &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
- struct rs_rate *rate = &search_tbl->rate;
- u32 sz = (sizeof(struct iwl_scale_tbl_info) -
- (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
- u8 start_action;
- u8 valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
- u8 update_search_tbl_counter = 0;
- int ret;
-
- if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) {
- IWL_DEBUG_RATE(mvm, "BT COEX force switch to SISO A\n");
- tbl->action = IWL_MIMO2_SWITCH_SISO_A;
- }
-
- start_action = tbl->action;
- while (1) {
- lq_sta->action_counter++;
- switch (tbl->action) {
- case IWL_MIMO2_SWITCH_SISO_A:
- case IWL_MIMO2_SWITCH_SISO_B:
- IWL_DEBUG_RATE(mvm, "LQ: MIMO2 switch to SISO\n");
-
- /* Set up new search table for SISO */
- memcpy(search_tbl, tbl, sz);
-
- if (tbl->action == IWL_MIMO2_SWITCH_SISO_A)
- rate->ant = ANT_A;
- else /* tbl->action == IWL_MIMO2_SWITCH_SISO_B */
- rate->ant = ANT_B;
-
- if (!rs_is_valid_ant(valid_tx_ant,
- rate->ant))
- break;
-
- ret = rs_switch_to_siso(mvm, lq_sta, sta,
- search_tbl, index);
- if (!ret)
- goto out;
-
- break;
-
- case IWL_MIMO2_SWITCH_GI:
- if (!rs_sgi_allowed(rate, sta))
- break;
-
- IWL_DEBUG_RATE(mvm, "LQ: MIMO2 toggle SGI/NGI\n");
-
- /* Set up new search table for MIMO2 */
- memcpy(search_tbl, tbl, sz);
- rate->sgi = !tbl->rate.sgi;
- rs_set_expected_tpt_table(lq_sta, search_tbl);
- /*
- * If active table already uses the fastest possible
- * modulation (dual stream with short guard interval),
- * and it's working well, there's no need to look
- * for a better type of modulation!
- */
- if (tbl->rate.sgi) {
- s32 tpt = lq_sta->last_tpt / 100;
- if (tpt >= search_tbl->expected_tpt[index])
- break;
- }
- rate->index = index;
- search_tbl->current_rate =
- ucode_rate_from_rs_rate(mvm, rate);
- update_search_tbl_counter = 1;
- goto out;
- default:
- WARN_ON_ONCE(1);
- }
- rs_move_next_action(tbl, IWL_MIMO2_LAST_ACTION);
-
- if (tbl->action == start_action)
- break;
- }
- rate->type = LQ_NONE;
- return 0;
- out:
- lq_sta->search_better_tbl = 1;
- rs_move_next_action(tbl, IWL_MIMO2_LAST_ACTION);
- if (update_search_tbl_counter)
- search_tbl->action = tbl->action;
-
- return 0;
-}
-
/*
* Check whether we should continue using same modulation mode, or
* begin search for a new mode, based on:
@@ -1582,7 +1361,7 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
tbl = &(lq_sta->lq_info[active_tbl]);

/* If we've been disallowing search, see if we should now allow it */
- if (lq_sta->stay_in_tbl) {
+ if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) {
/* Elapsed time using current modulation mode */
if (lq_sta->flush_timer)
flush_interval_passed =
@@ -1610,10 +1389,14 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
flush_interval_passed);

/* Allow search for new mode */
- lq_sta->stay_in_tbl = 0; /* only place reset */
+ lq_sta->rs_state = RS_STATE_SEARCH_CYCLE_STARTED;
+ IWL_DEBUG_RATE(mvm,
+ "Moving to RS_STATE_SEARCH_CYCLE_STARTED\n");
lq_sta->total_failed = 0;
lq_sta->total_success = 0;
lq_sta->flush_timer = 0;
+ /* mark the current column as visited */
+ lq_sta->visited_columns = BIT(tbl->column);
/*
* Else if we've used this modulation mode enough repetitions
* (regardless of elapsed time or success/failure), reset
@@ -1637,7 +1420,8 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
/* If transitioning to allow "search", reset all history
* bitmaps and stats in active table (this will become the new
* "search" table). */
- if (!lq_sta->stay_in_tbl) {
+ if (lq_sta->rs_state == RS_STATE_SEARCH_CYCLE_STARTED) {
+ IWL_DEBUG_RATE(mvm, "Clearing up window stats\n");
for (i = 0; i < IWL_RATE_COUNT; i++)
rs_rate_scale_clear_window(&(tbl->win[i]));
}
@@ -1675,6 +1459,162 @@ static u8 rs_get_tid(struct iwl_lq_sta *lq_data,
return tid;
}

+static enum rs_column rs_get_next_column(struct iwl_mvm *mvm,
+ struct iwl_lq_sta *lq_sta,
+ struct ieee80211_sta *sta,
+ struct iwl_scale_tbl_info *tbl)
+{
+ int i, j, n;
+ enum rs_column next_col_id;
+ const struct rs_tx_column *curr_col = &rs_tx_columns[tbl->column];
+ const struct rs_tx_column *next_col;
+ allow_column_func_t allow_func;
+ u8 valid_ants = iwl_fw_valid_tx_ant(mvm->fw);
+ s32 *expected_tpt_tbl;
+ s32 tpt, max_expected_tpt;
+
+ for (i = 0; i < MAX_NEXT_COLUMNS; i++) {
+ next_col_id = curr_col->next_columns[i];
+
+ if (next_col_id == RS_COLUMN_INVALID)
+ continue;
+
+ if (lq_sta->visited_columns & BIT(next_col_id)) {
+ IWL_DEBUG_RATE(mvm, "Skip already visited column %d\n",
+ next_col_id);
+ continue;
+ }
+
+ next_col = &rs_tx_columns[next_col_id];
+
+ if (!rs_is_valid_ant(valid_ants, next_col->ant)) {
+ IWL_DEBUG_RATE(mvm,
+ "Skip column %d as ANT config isn't supported by chip. valid_ants 0x%x column ant 0x%x\n",
+ next_col_id, valid_ants, next_col->ant);
+ continue;
+ }
+
+ for (j = 0; j < MAX_COLUMN_CHECKS; j++) {
+ allow_func = next_col->checks[j];
+ if (allow_func && !allow_func(mvm, sta, tbl))
+ break;
+ }
+
+ if (j != MAX_COLUMN_CHECKS) {
+ IWL_DEBUG_RATE(mvm,
+ "Skip column %d: not allowed (check %d failed)\n",
+ next_col_id, j);
+
+ continue;
+ }
+
+ tpt = lq_sta->last_tpt / 100;
+ expected_tpt_tbl = rs_get_expected_tpt_table(lq_sta, next_col,
+ tbl->rate.bw);
+ if (WARN_ON_ONCE(!expected_tpt_tbl))
+ continue;
+
+ max_expected_tpt = 0;
+ for (n = 0; n < IWL_RATE_COUNT; n++)
+ if (expected_tpt_tbl[n] > max_expected_tpt)
+ max_expected_tpt = expected_tpt_tbl[n];
+
+ if (tpt >= max_expected_tpt) {
+ IWL_DEBUG_RATE(mvm,
+ "Skip column %d: can't beat current TPT. Max expected %d current %d\n",
+ next_col_id, max_expected_tpt, tpt);
+ continue;
+ }
+
+ break;
+ }
+
+ if (i == MAX_NEXT_COLUMNS)
+ return RS_COLUMN_INVALID;
+
+ IWL_DEBUG_RATE(mvm, "Found potential column %d\n", next_col_id);
+
+ return next_col_id;
+}
+
+static int rs_switch_to_column(struct iwl_mvm *mvm,
+ struct iwl_lq_sta *lq_sta,
+ struct ieee80211_sta *sta,
+ enum rs_column col_id)
+{
+ struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+ struct iwl_scale_tbl_info *search_tbl =
+ &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+ struct rs_rate *rate = &search_tbl->rate;
+ const struct rs_tx_column *column = &rs_tx_columns[col_id];
+ const struct rs_tx_column *curr_column = &rs_tx_columns[tbl->column];
+ u32 sz = (sizeof(struct iwl_scale_tbl_info) -
+ (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+ u16 rate_mask = 0;
+ u32 rate_idx = 0;
+
+ memcpy(search_tbl, tbl, sz);
+
+ rate->sgi = column->sgi;
+ rate->ant = column->ant;
+
+ if (column->mode == RS_LEGACY) {
+ if (lq_sta->band == IEEE80211_BAND_5GHZ)
+ rate->type = LQ_LEGACY_A;
+ else
+ rate->type = LQ_LEGACY_G;
+
+ rate_mask = lq_sta->active_legacy_rate;
+ } else if (column->mode == RS_SISO) {
+ rate->type = lq_sta->is_vht ? LQ_VHT_SISO : LQ_HT_SISO;
+ rate_mask = lq_sta->active_siso_rate;
+ } else if (column->mode == RS_MIMO2) {
+ rate->type = lq_sta->is_vht ? LQ_VHT_MIMO2 : LQ_HT_MIMO2;
+ rate_mask = lq_sta->active_mimo2_rate;
+ } else {
+ WARN_ON_ONCE("Bad column mode");
+ }
+
+ rate->bw = rs_bw_from_sta_bw(sta);
+ search_tbl->column = col_id;
+ rs_set_expected_tpt_table(lq_sta, search_tbl);
+
+ /* Get the best matching rate if we're changing modes. e.g.
+ * SISO->MIMO, LEGACY->SISO, MIMO->SISO
+ */
+ if (curr_column->mode != column->mode) {
+ rate_idx = rs_get_best_rate(mvm, lq_sta, search_tbl,
+ rate_mask, rate->index);
+
+ if ((rate_idx == IWL_RATE_INVALID) ||
+ !(BIT(rate_idx) & rate_mask)) {
+ IWL_DEBUG_RATE(mvm,
+ "can not switch with index %d"
+ " rate mask %x\n",
+ rate_idx, rate_mask);
+
+ goto err;
+ }
+
+ rate->index = rate_idx;
+ }
+
+ /* TODO: remove current_rate and keep using rs_rate all the way until
+ * we need to fill in the rs_table in the LQ command
+ */
+ search_tbl->current_rate = ucode_rate_from_rs_rate(mvm, rate);
+ IWL_DEBUG_RATE(mvm, "Switched to column %d: Index %d\n",
+ col_id, rate->index);
+
+ lq_sta->visited_columns |= BIT(col_id);
+ return 0;
+
+err:
+ rate->type = LQ_NONE;
+ return -1;
+}
+
+
/*
* Do rate scaling and search for new modulation mode.
*/
@@ -1772,7 +1712,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
if (!rate_scale_index_msk)
rate_scale_index_msk = rate_mask;

- if (!((1 << index) & rate_scale_index_msk)) {
+ if (!((BIT(index) & rate_scale_index_msk))) {
IWL_ERR(mvm, "Current Rate is not valid\n");
if (lq_sta->search_better_tbl) {
/* revert to active table if search table is not valid*/
@@ -1852,9 +1792,6 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
window->average_tpt,
lq_sta->last_tpt);

- if (!is_legacy(rate))
- lq_sta->enable_counter = 1;
-
/* Swap tables; "search" becomes "active" */
lq_sta->active_tbl = active_tbl;
current_tpt = window->average_tpt;
@@ -2049,24 +1986,29 @@ lq_update:
* 3) Allowing a new search
*/
if (!update_lq && !done_search &&
- !lq_sta->stay_in_tbl && window->counter) {
+ lq_sta->rs_state == RS_STATE_SEARCH_CYCLE_STARTED
+ && window->counter) {
+ enum rs_column next_column;
+
/* Save current throughput to compare with "search" throughput*/
lq_sta->last_tpt = current_tpt;

IWL_DEBUG_RATE(mvm,
- "Start Search: update_lq %d done_search %d stay_in_tbl %d win->counter %d\n",
- update_lq, done_search, lq_sta->stay_in_tbl,
+ "Start Search: update_lq %d done_search %d rs_state %d win->counter %d\n",
+ update_lq, done_search, lq_sta->rs_state,
window->counter);
- /* Select a new "search" modulation mode to try.
- * If one is found, set up the new "search" table. */
- if (is_legacy(&tbl->rate))
- rs_move_legacy_other(mvm, lq_sta, sta, index);
- else if (is_siso(&tbl->rate))
- rs_move_siso_to_other(mvm, lq_sta, sta, index);
- else if (is_mimo2(&tbl->rate))
- rs_move_mimo2_to_other(mvm, lq_sta, sta, index);
- else
- WARN_ON_ONCE(1);
+
+ next_column = rs_get_next_column(mvm, lq_sta, sta, tbl);
+ if (next_column != RS_COLUMN_INVALID) {
+ int ret = rs_switch_to_column(mvm, lq_sta, sta,
+ next_column);
+ if (!ret)
+ lq_sta->search_better_tbl = 1;
+ } else {
+ IWL_DEBUG_RATE(mvm,
+ "No more columns to explore in search cycle. Go to RS_STATE_SEARCH_CYCLE_ENDED\n");
+ lq_sta->rs_state = RS_STATE_SEARCH_CYCLE_ENDED;
+ }

/* If new "search" mode was selected, set up in uCode table */
if (lq_sta->search_better_tbl) {
@@ -2078,12 +2020,8 @@ lq_update:
/* Use new "search" start rate */
index = iwl_hwrate_to_plcp_idx(tbl->current_rate);

- IWL_DEBUG_RATE(mvm,
- "Switch to SEARCH TABLE: "
- "mcs %X (%s: %d)\n",
- tbl->current_rate,
- rs_pretty_lq_type(tbl->rate.type),
- index);
+ rs_dump_rate(mvm, &tbl->rate,
+ "Switch to SEARCH TABLE:");
rs_fill_link_cmd(mvm, sta, lq_sta, tbl->current_rate);
iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false);
} else {
@@ -2091,24 +2029,20 @@ lq_update:
}
}

- if (done_search && !lq_sta->stay_in_tbl) {
+ if (done_search && lq_sta->rs_state == RS_STATE_SEARCH_CYCLE_ENDED) {
/* If the "active" (non-search) mode was legacy,
* and we've tried switching antennas,
* but we haven't been able to try HT modes (not available),
* stay with best antenna legacy modulation for a while
* before next round of mode comparisons. */
tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]);
- if (is_legacy(&tbl1->rate) && !sta->ht_cap.ht_supported &&
- lq_sta->action_counter > tbl1->max_search) {
+ if (is_legacy(&tbl1->rate) && !sta->ht_cap.ht_supported) {
IWL_DEBUG_RATE(mvm, "LQ: STAY in legacy table\n");
rs_set_stay_in_table(mvm, 1, lq_sta);
- }
-
+ } else {
/* If we're in an HT mode, and all 3 mode switch actions
* have been tried and compared, stay in this best modulation
* mode for a while before next round of mode comparisons. */
- if (lq_sta->enable_counter &&
- (lq_sta->action_counter >= tbl1->max_search)) {
if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) &&
(lq_sta->tx_agg_tid_en & (1 << tid)) &&
(tid != IWL_MAX_TID_COUNT)) {
@@ -2176,19 +2110,24 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
if ((i < 0) || (i >= IWL_RATE_COUNT))
i = 0;

- ucode_rate = iwl_rates[i].plcp;
+ rate->index = i;
rate->ant = first_antenna(valid_tx_ant);
- ucode_rate |= rate->ant << RATE_MCS_ANT_POS;
-
- if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE)
- ucode_rate |= RATE_MCS_CCK_MSK;
-
- rs_rate_from_ucode_rate(ucode_rate, band, rate);
- if (!rs_is_valid_ant(valid_tx_ant, rate->ant))
- rs_toggle_antenna(valid_tx_ant, &ucode_rate, rate);
+ rate->sgi = false;
+ rate->bw = RATE_MCS_CHAN_WIDTH_20;
+ if (band == IEEE80211_BAND_5GHZ)
+ rate->type = LQ_LEGACY_A;
+ else
+ rate->type = LQ_LEGACY_G;

ucode_rate = ucode_rate_from_rs_rate(mvm, rate);
tbl->current_rate = ucode_rate;
+
+ WARN_ON_ONCE(rate->ant != ANT_A && rate->ant != ANT_B);
+ if (rate->ant == ANT_A)
+ tbl->column = RS_COLUMN_LEGACY_ANT_A;
+ else
+ tbl->column = RS_COLUMN_LEGACY_ANT_B;
+
rs_set_expected_tpt_table(lq_sta, tbl);
rs_fill_link_cmd(NULL, NULL, lq_sta, ucode_rate);
/* TODO restore station should remember the lq cmd */
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h
index 8fa26af..b329607 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.h
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.h
@@ -157,37 +157,6 @@ enum {
#define IWL_RATE_INCREASE_TH 6400 /* 50% */
#define RS_SR_FORCE_DECREASE 1920 /* 15% */

-/* possible actions when in legacy mode */
-enum {
- IWL_LEGACY_SWITCH_ANTENNA,
- IWL_LEGACY_SWITCH_SISO,
- IWL_LEGACY_SWITCH_MIMO2,
- IWL_LEGACY_FIRST_ACTION = IWL_LEGACY_SWITCH_ANTENNA,
- IWL_LEGACY_LAST_ACTION = IWL_LEGACY_SWITCH_MIMO2,
-};
-
-/* possible actions when in siso mode */
-enum {
- IWL_SISO_SWITCH_ANTENNA,
- IWL_SISO_SWITCH_MIMO2,
- IWL_SISO_SWITCH_GI,
- IWL_SISO_FIRST_ACTION = IWL_SISO_SWITCH_ANTENNA,
- IWL_SISO_LAST_ACTION = IWL_SISO_SWITCH_GI,
-};
-
-/* possible actions when in mimo mode */
-enum {
- IWL_MIMO2_SWITCH_SISO_A,
- IWL_MIMO2_SWITCH_SISO_B,
- IWL_MIMO2_SWITCH_GI,
- IWL_MIMO2_FIRST_ACTION = IWL_MIMO2_SWITCH_SISO_A,
- IWL_MIMO2_LAST_ACTION = IWL_MIMO2_SWITCH_GI,
-};
-
-#define IWL_MAX_SEARCH IWL_MIMO2_LAST_ACTION
-
-#define IWL_ACTION_LIMIT 3 /* # possible actions */
-
#define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) /* 4 milliseconds */
#define LINK_QUAL_AGG_TIME_LIMIT_MAX (8000)
#define LINK_QUAL_AGG_TIME_LIMIT_MIN (100)
@@ -282,6 +251,23 @@ struct iwl_rate_scale_data {
s32 average_tpt; /* success ratio * expected throughput */
};

+/* Possible Tx columns
+ * Tx Column = a combo of legacy/siso/mimo x antenna x SGI
+ */
+enum rs_column {
+ RS_COLUMN_LEGACY_ANT_A = 0,
+ RS_COLUMN_LEGACY_ANT_B,
+ RS_COLUMN_SISO_ANT_A,
+ RS_COLUMN_SISO_ANT_B,
+ RS_COLUMN_SISO_ANT_A_SGI,
+ RS_COLUMN_SISO_ANT_B_SGI,
+ RS_COLUMN_MIMO2,
+ RS_COLUMN_MIMO2_SGI,
+
+ RS_COLUMN_LAST = RS_COLUMN_MIMO2_SGI,
+ RS_COLUMN_INVALID,
+};
+
/**
* struct iwl_scale_tbl_info -- tx params and success history for all rates
*
@@ -290,13 +276,18 @@ struct iwl_rate_scale_data {
*/
struct iwl_scale_tbl_info {
struct rs_rate rate;
- u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */
- u8 max_search; /* maximun number of tables we can search */
+ enum rs_column column;
s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */
u32 current_rate; /* rate_n_flags, uCode API format */
struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */
};

+enum {
+ RS_STATE_SEARCH_CYCLE_STARTED,
+ RS_STATE_SEARCH_CYCLE_ENDED,
+ RS_STATE_STAY_IN_COLUMN,
+};
+
/**
* struct iwl_lq_sta -- driver's rate scaling private structure
*
@@ -304,8 +295,7 @@ struct iwl_scale_tbl_info {
*/
struct iwl_lq_sta {
u8 active_tbl; /* index of active table, range 0-1 */
- u8 enable_counter; /* indicates HT mode */
- u8 stay_in_tbl; /* 1: disallow, 0: allow search for new mode */
+ u8 rs_state; /* RS_STATE_* */
u8 search_better_tbl; /* 1: currently trying alternate mode */
s32 last_tpt;

@@ -318,7 +308,9 @@ struct iwl_lq_sta {
u32 total_success; /* total successful frames, any/all rates */
u64 flush_timer; /* time staying in mode before new search */

- u8 action_counter; /* # mode-switch actions tried */
+ u32 visited_columns; /* Bitmask marking which Tx columns were
+ * explored during a search cycle
+ */
bool is_vht;
enum ieee80211_band band;

--
1.7.9.5


2013-12-02 20:59:57

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 11/13] iwlwifi: mvm: rs: use the proper channel width define for legacy rate

From: Eyal Shapira <[email protected]>

Use the 20Mhz channel width define instead of just the number
zero for legacy rates. Note that the define has the same value
so this is just a minor cleanup.

Signed-off-by: Eyal Shapira <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/rs.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index ef7126a..1bfdde5 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -691,7 +691,7 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
rate->ant =
first_antenna(iwl_fw_valid_tx_ant(mvm->fw));

- rate->bw = 0;
+ rate->bw = RATE_MCS_CHAN_WIDTH_20;
rate->sgi = false;
}

--
1.7.9.5


2013-12-09 20:38:51

by Emmanuel Grumbach

[permalink] [raw]
Subject: Re: pull request: iwlwifi-next 2013-12-2



On 12/09/2013 10:27 PM, John W. Linville wrote:
> On Tue, Dec 03, 2013 at 07:19:23PM +0200, Emmanuel Grumbach wrote:
>>
>>
>> On 12/02/2013 10:51 PM, Emmanuel Grumbach wrote:
>>> Hi John,
>>>
>>> This is the fixed and enlarged pull request for 3.14. It includes the
>>> patches in my previous pull request that was based on a bad patch.
>>>
>>> I have here a big rework of the rate control by Eyal. This is obviously
>>> the biggest part of this batch.
>>> I also have enhancement of protection flags by Avri and a few bits for
>>> WoWLAN by Eliad and Luca. Johannes cleans up the debugfs plus a few
>>> fixes. I provided a few things for Bluetooth coexistence.
>>> Besides this we have an implementation for low priority scan.
>>>
>>> Note that I had to merge iwlwifi-fixes into -next to solve conflicts
>>> before they hit linux-next.
>>> Please let me know about issues you may face - Thanks!
>>>
>>
>> So - I found out that merging iwlwifi-fixes wasn't a good idea... So I
>> updated my tree and added a trivial compilation fix.
>>
>> New head: 2f579448f3a60c8ede544dd0951b8d2a2e282ba2.
>>
>> I hope that I have done all the possible mistakes now and that next time
>> I will get it right the first time... Sorry for all the mess...
>
> This has a couple of merge conflicts when pulling it into
> wireless-next. I don't have the time to work through them today,
> so I'm not pulling.
>
> If you would like to work through the resolution and advise me on
> how to do it, I'd love to hear about it. :-)
>
> John
>

Cool - I rebased my tree before I read your mail.

2013-12-02 21:00:00

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 13/13] iwlwifi: mvm: BT Coex - enable Sync to SCO

From: Emmanuel Grumbach <[email protected]>

Sync to SCO is a feature that allows to synchronise the
wifi activity with the predictable BT activity in
SCO profile. This allows to reduce the collisions and
improve overall quality.

Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/bt-coex.c | 3 ++-
drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h | 1 +
2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c
index f0eed69..fba997e 100644
--- a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c
+++ b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c
@@ -397,7 +397,8 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
BT_VALID_ANT_ISOLATION |
BT_VALID_ANT_ISOLATION_THRS |
BT_VALID_TXTX_DELTA_FREQ_THRS |
- BT_VALID_TXRX_MAX_FREQ_0);
+ BT_VALID_TXRX_MAX_FREQ_0 |
+ BT_VALID_SYNC_TO_SCO);

if (mvm->cfg->bt_shared_single_ant)
memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant,
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h
index 4ea5e24..af50099 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h
@@ -127,6 +127,7 @@ enum iwl_bt_coex_valid_bit_msk {
BT_VALID_ANT_ISOLATION_THRS = BIT(15),
BT_VALID_TXTX_DELTA_FREQ_THRS = BIT(16),
BT_VALID_TXRX_MAX_FREQ_0 = BIT(17),
+ BT_VALID_SYNC_TO_SCO = BIT(18),
};

/**
--
1.7.9.5


2013-12-02 20:59:46

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 03/13] iwlwifi: mvm: rs: update expected TPT tables if aggregation changed

From: Eyal Shapira <[email protected]>

Expected TPT table was updated only when switching to a new
modulation. This is wrong as toggling aggregation changes
the expected TPT signficantly.
This leads to scenarios where turning aggregation on after
being in MIMO sends us back to SISO despite a perfect success
ratio.
This occurred because the TPT of the SISO mode was being
estimated based on aggregation while the MIMO one wasn't.

Also remove an error print which isn't an error anymore
since we might be updating the expected TPT table due
to aggregation changes.

Signed-off-by: Eyal Shapira <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/rs.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index ecf24cb..882ecd3 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -1717,6 +1717,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
u16 high_low;
s32 sr;
u8 tid = IWL_MAX_TID_COUNT;
+ u8 prev_agg = lq_sta->is_agg;
struct iwl_mvm_sta *sta_priv = (void *)sta->drv_priv;
struct iwl_mvm_tid_data *tid_data;

@@ -1752,6 +1753,13 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,

tbl = &(lq_sta->lq_info[active_tbl]);

+ if (prev_agg != lq_sta->is_agg) {
+ IWL_DEBUG_RATE(mvm,
+ "Aggregation changed: prev %d current %d. Update expected TPT table\n",
+ prev_agg, lq_sta->is_agg);
+ rs_set_expected_tpt_table(lq_sta, tbl);
+ }
+
/* current tx rate */
index = lq_sta->last_txrate_idx;

@@ -1837,8 +1845,6 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
* actual average throughput */
if (window->average_tpt != ((window->success_ratio *
tbl->expected_tpt[index] + 64) / 128)) {
- IWL_ERR(mvm,
- "expected_tpt should have been calculated by now\n");
window->average_tpt = ((window->success_ratio *
tbl->expected_tpt[index] + 64) / 128);
}
--
1.7.9.5


2013-12-02 20:59:55

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 09/13] iwlwifi: mvm: rs: set dual_stream_ant_msk to ANT_AB always

From: Eyal Shapira <[email protected]>

Drop code which was relevant when there were chips with
3 antennas. Setting to ANT_AB should be ok with all mvm
supported chips.

Signed-off-by: Eyal Shapira <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/rs.c | 12 +-----------
1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index 7beb548..5c98d462 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -2386,15 +2386,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
/* These values will be overridden later */
lq_sta->lq.single_stream_ant_msk =
first_antenna(iwl_fw_valid_tx_ant(mvm->fw));
- lq_sta->lq.dual_stream_ant_msk =
- iwl_fw_valid_tx_ant(mvm->fw) &
- ~first_antenna(iwl_fw_valid_tx_ant(mvm->fw));
- if (!lq_sta->lq.dual_stream_ant_msk) {
- lq_sta->lq.dual_stream_ant_msk = ANT_AB;
- } else if (num_of_ant(iwl_fw_valid_tx_ant(mvm->fw)) == 2) {
- lq_sta->lq.dual_stream_ant_msk =
- iwl_fw_valid_tx_ant(mvm->fw);
- }
+ lq_sta->lq.dual_stream_ant_msk = ANT_AB;

/* as default allow aggregation for all tids */
lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID;
@@ -2463,8 +2455,6 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm,

if (num_of_ant(rate.ant) == 1)
lq_cmd->single_stream_ant_msk = rate.ant;
- else if (num_of_ant(rate.ant) == 2)
- lq_cmd->dual_stream_ant_msk = rate.ant;
/* otherwise we don't modify the existing value */

index++;
--
1.7.9.5


2013-12-02 20:59:52

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 07/13] iwlwifi: mvm: rs: refactor to use rs_rate

From: Eyal Shapira <[email protected]>

Introduce rs_rate which represents a rate. Use this structure
instead of iwl_scale_tbl_info where we're dealing with a single
rate.
This avoids allocating the big iwl_scale_tbl_info structure
on the stack in several cases like converting to ucode rate
format or from ucode rate format.

Signed-off-by: Eyal Shapira <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/rs.c | 568 +++++++++++++++++----------------
drivers/net/wireless/iwlwifi/mvm/rs.h | 60 ++--
2 files changed, 331 insertions(+), 297 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index 0598f26..3af9062 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -175,6 +175,7 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm,
struct iwl_lq_sta *lq_sta, u32 rate_n_flags);
static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search);
static const char *rs_pretty_lq_type(enum iwl_table_type type);
+static const char *rs_pretty_ant(u8 ant);

#ifdef CONFIG_MAC80211_DEBUGFS
static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
@@ -264,6 +265,15 @@ static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = {

#define MCS_INDEX_PER_STREAM (8)

+static inline void rs_dump_rate(struct iwl_mvm *mvm, const struct rs_rate *rate,
+ const char *prefix)
+{
+ IWL_DEBUG_RATE(mvm, "%s: (%s: %d) ANT: %s BW: %d SGI: %d\n",
+ prefix, rs_pretty_lq_type(rate->type),
+ rate->index, rs_pretty_ant(rate->ant),
+ rate->bw, rate->sgi);
+}
+
static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window)
{
window->data = 0;
@@ -430,167 +440,160 @@ static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl,
return 0;
}

-/*
- * Fill uCode API rate_n_flags field, based on "search" or "active" table.
- */
-/* FIXME:RS:remove this function and put the flags statically in the table */
-static u32 rate_n_flags_from_tbl(struct iwl_mvm *mvm,
- struct iwl_scale_tbl_info *tbl, int index)
+/* Convert rs_rate object into ucode rate bitmask */
+static u32 ucode_rate_from_rs_rate(struct iwl_mvm *mvm,
+ struct rs_rate *rate)
{
- u32 rate_n_flags = 0;
+ u32 ucode_rate = 0;
+ int index = rate->index;

- rate_n_flags |= ((tbl->ant_type << RATE_MCS_ANT_POS) &
+ ucode_rate |= ((rate->ant << RATE_MCS_ANT_POS) &
RATE_MCS_ANT_ABC_MSK);

- if (is_legacy(tbl->lq_type)) {
- rate_n_flags |= iwl_rates[index].plcp;
+ if (is_legacy(rate)) {
+ ucode_rate |= iwl_rates[index].plcp;
if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE)
- rate_n_flags |= RATE_MCS_CCK_MSK;
- return rate_n_flags;
+ ucode_rate |= RATE_MCS_CCK_MSK;
+ return ucode_rate;
}

- if (is_ht(tbl->lq_type)) {
+ if (is_ht(rate)) {
if (index < IWL_FIRST_HT_RATE || index > IWL_LAST_HT_RATE) {
IWL_ERR(mvm, "Invalid HT rate index %d\n", index);
index = IWL_LAST_HT_RATE;
}
- rate_n_flags |= RATE_MCS_HT_MSK;
+ ucode_rate |= RATE_MCS_HT_MSK;

- if (is_ht_siso(tbl->lq_type))
- rate_n_flags |= iwl_rates[index].plcp_ht_siso;
- else if (is_ht_mimo2(tbl->lq_type))
- rate_n_flags |= iwl_rates[index].plcp_ht_mimo2;
+ if (is_ht_siso(rate))
+ ucode_rate |= iwl_rates[index].plcp_ht_siso;
+ else if (is_ht_mimo2(rate))
+ ucode_rate |= iwl_rates[index].plcp_ht_mimo2;
else
WARN_ON_ONCE(1);
- } else if (is_vht(tbl->lq_type)) {
+ } else if (is_vht(rate)) {
if (index < IWL_FIRST_VHT_RATE || index > IWL_LAST_VHT_RATE) {
IWL_ERR(mvm, "Invalid VHT rate index %d\n", index);
index = IWL_LAST_VHT_RATE;
}
- rate_n_flags |= RATE_MCS_VHT_MSK;
- if (is_vht_siso(tbl->lq_type))
- rate_n_flags |= iwl_rates[index].plcp_vht_siso;
- else if (is_vht_mimo2(tbl->lq_type))
- rate_n_flags |= iwl_rates[index].plcp_vht_mimo2;
+ ucode_rate |= RATE_MCS_VHT_MSK;
+ if (is_vht_siso(rate))
+ ucode_rate |= iwl_rates[index].plcp_vht_siso;
+ else if (is_vht_mimo2(rate))
+ ucode_rate |= iwl_rates[index].plcp_vht_mimo2;
else
WARN_ON_ONCE(1);

} else {
- IWL_ERR(mvm, "Invalid tbl->lq_type %d\n", tbl->lq_type);
+ IWL_ERR(mvm, "Invalid rate->type %d\n", rate->type);
}

- rate_n_flags |= tbl->bw;
- if (tbl->is_SGI)
- rate_n_flags |= RATE_MCS_SGI_MSK;
+ ucode_rate |= rate->bw;
+ if (rate->sgi)
+ ucode_rate |= RATE_MCS_SGI_MSK;

- return rate_n_flags;
+ return ucode_rate;
}

-/*
- * Interpret uCode API's rate_n_flags format,
- * fill "search" or "active" tx mode table.
- */
-static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags,
- enum ieee80211_band band,
- struct iwl_scale_tbl_info *tbl,
- int *rate_idx)
+/* Convert a ucode rate into an rs_rate object */
+static int rs_rate_from_ucode_rate(const u32 ucode_rate,
+ enum ieee80211_band band,
+ struct rs_rate *rate)
{
- u32 ant_msk = (rate_n_flags & RATE_MCS_ANT_ABC_MSK);
- u8 num_of_ant = get_num_of_ant_from_rate(rate_n_flags);
+ u32 ant_msk = ucode_rate & RATE_MCS_ANT_ABC_MSK;
+ u8 num_of_ant = get_num_of_ant_from_rate(ucode_rate);
u8 nss;

- memset(tbl, 0, offsetof(struct iwl_scale_tbl_info, win));
- *rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags);
+ memset(rate, 0, sizeof(struct rs_rate));
+ rate->index = iwl_hwrate_to_plcp_idx(ucode_rate);

- if (*rate_idx == IWL_RATE_INVALID) {
- *rate_idx = -1;
+ if (rate->index == IWL_RATE_INVALID) {
+ rate->index = -1;
return -EINVAL;
}
- tbl->is_SGI = 0; /* default legacy setup */
- tbl->bw = 0;
- tbl->ant_type = (ant_msk >> RATE_MCS_ANT_POS);
- tbl->lq_type = LQ_NONE;
- tbl->max_search = IWL_MAX_SEARCH;
+
+ rate->ant = (ant_msk >> RATE_MCS_ANT_POS);

/* Legacy */
- if (!(rate_n_flags & RATE_MCS_HT_MSK) &&
- !(rate_n_flags & RATE_MCS_VHT_MSK)) {
+ if (!(ucode_rate & RATE_MCS_HT_MSK) &&
+ !(ucode_rate & RATE_MCS_VHT_MSK)) {
if (num_of_ant == 1) {
if (band == IEEE80211_BAND_5GHZ)
- tbl->lq_type = LQ_LEGACY_A;
+ rate->type = LQ_LEGACY_A;
else
- tbl->lq_type = LQ_LEGACY_G;
+ rate->type = LQ_LEGACY_G;
}

return 0;
}

/* HT or VHT */
- if (rate_n_flags & RATE_MCS_SGI_MSK)
- tbl->is_SGI = 1;
+ if (ucode_rate & RATE_MCS_SGI_MSK)
+ rate->sgi = true;

- tbl->bw = rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK;
+ rate->bw = ucode_rate & RATE_MCS_CHAN_WIDTH_MSK;

- if (rate_n_flags & RATE_MCS_HT_MSK) {
- nss = ((rate_n_flags & RATE_HT_MCS_NSS_MSK) >>
+ if (ucode_rate & RATE_MCS_HT_MSK) {
+ nss = ((ucode_rate & RATE_HT_MCS_NSS_MSK) >>
RATE_HT_MCS_NSS_POS) + 1;

if (nss == 1) {
- tbl->lq_type = LQ_HT_SISO;
+ rate->type = LQ_HT_SISO;
WARN_ON_ONCE(num_of_ant != 1);
} else if (nss == 2) {
- tbl->lq_type = LQ_HT_MIMO2;
+ rate->type = LQ_HT_MIMO2;
WARN_ON_ONCE(num_of_ant != 2);
} else {
WARN_ON_ONCE(1);
}
- } else if (rate_n_flags & RATE_MCS_VHT_MSK) {
- nss = ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >>
+ } else if (ucode_rate & RATE_MCS_VHT_MSK) {
+ nss = ((ucode_rate & RATE_VHT_MCS_NSS_MSK) >>
RATE_VHT_MCS_NSS_POS) + 1;

if (nss == 1) {
- tbl->lq_type = LQ_VHT_SISO;
+ rate->type = LQ_VHT_SISO;
WARN_ON_ONCE(num_of_ant != 1);
} else if (nss == 2) {
- tbl->lq_type = LQ_VHT_MIMO2;
+ rate->type = LQ_VHT_MIMO2;
WARN_ON_ONCE(num_of_ant != 2);
} else {
WARN_ON_ONCE(1);
}
}

- WARN_ON_ONCE(tbl->bw == RATE_MCS_CHAN_WIDTH_160);
- WARN_ON_ONCE(tbl->bw == RATE_MCS_CHAN_WIDTH_80 &&
- !is_vht(tbl->lq_type));
+ WARN_ON_ONCE(rate->bw == RATE_MCS_CHAN_WIDTH_160);
+ WARN_ON_ONCE(rate->bw == RATE_MCS_CHAN_WIDTH_80 &&
+ !is_vht(rate));

return 0;
}

/* switch to another antenna/antennas and return 1 */
/* if no other valid antenna found, return 0 */
-static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags,
- struct iwl_scale_tbl_info *tbl)
+static int rs_toggle_antenna(u32 valid_ant, u32 *ucode_rate,
+ struct rs_rate *rate)
{
u8 new_ant_type;

- if (!tbl->ant_type || tbl->ant_type > ANT_ABC)
+ if (!rate->ant || rate->ant > ANT_ABC)
return 0;

- if (!rs_is_valid_ant(valid_ant, tbl->ant_type))
+ if (!rs_is_valid_ant(valid_ant, rate->ant))
return 0;

- new_ant_type = ant_toggle_lookup[tbl->ant_type];
+ new_ant_type = ant_toggle_lookup[rate->ant];

- while ((new_ant_type != tbl->ant_type) &&
+ while ((new_ant_type != rate->ant) &&
!rs_is_valid_ant(valid_ant, new_ant_type))
new_ant_type = ant_toggle_lookup[new_ant_type];

- if (new_ant_type == tbl->ant_type)
+ if (new_ant_type == rate->ant)
return 0;

- tbl->ant_type = new_ant_type;
- *rate_n_flags &= ~RATE_MCS_ANT_ABC_MSK;
- *rate_n_flags |= new_ant_type << RATE_MCS_ANT_POS;
+ rate->ant = new_ant_type;
+
+ /* TODO: get rid of ucode_rate here. This should handle only rs_rate */
+ *ucode_rate &= ~RATE_MCS_ANT_ABC_MSK;
+ *ucode_rate |= new_ant_type << RATE_MCS_ANT_POS;
return 1;
}

@@ -603,13 +606,13 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags,
*/
static u16 rs_get_supported_rates(struct iwl_lq_sta *lq_sta,
struct ieee80211_hdr *hdr,
- enum iwl_table_type rate_type)
+ struct rs_rate *rate)
{
- if (is_legacy(rate_type))
+ if (is_legacy(rate))
return lq_sta->active_legacy_rate;
- else if (is_siso(rate_type))
+ else if (is_siso(rate))
return lq_sta->active_siso_rate;
- else if (is_mimo2(rate_type))
+ else if (is_mimo2(rate))
return lq_sta->active_mimo2_rate;

WARN_ON_ONCE(1);
@@ -624,7 +627,7 @@ static u16 rs_get_adjacent_rate(struct iwl_mvm *mvm, u8 index, u16 rate_mask,

/* 802.11A or ht walks to the next literal adjacent rate in
* the rate table */
- if (is_a_band(rate_type) || !is_legacy(rate_type)) {
+ if (is_type_a_band(rate_type) || !is_type_legacy(rate_type)) {
int i;
u32 mask;

@@ -673,7 +676,7 @@ static u16 rs_get_adjacent_rate(struct iwl_mvm *mvm, u8 index, u16 rate_mask,
}

static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
- struct iwl_scale_tbl_info *tbl,
+ struct rs_rate *rate,
u8 scale_index, u8 ht_possible)
{
s32 low;
@@ -685,30 +688,29 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
/* check if we need to switch from HT to legacy rates.
* assumption is that mandatory rates (1Mbps or 6Mbps)
* are always supported (spec demand) */
- if (!is_legacy(tbl->lq_type) && (!ht_possible || !scale_index)) {
+ if (!is_legacy(rate) && (!ht_possible || !scale_index)) {
switch_to_legacy = 1;
scale_index = rs_ht_to_legacy[scale_index];
if (lq_sta->band == IEEE80211_BAND_5GHZ)
- tbl->lq_type = LQ_LEGACY_A;
+ rate->type = LQ_LEGACY_A;
else
- tbl->lq_type = LQ_LEGACY_G;
+ rate->type = LQ_LEGACY_G;

- if (num_of_ant(tbl->ant_type) > 1)
- tbl->ant_type =
+ if (num_of_ant(rate->ant) > 1)
+ rate->ant =
first_antenna(iwl_fw_valid_tx_ant(mvm->fw));

- tbl->bw = 0;
- tbl->is_SGI = 0;
- tbl->max_search = IWL_MAX_SEARCH;
+ rate->bw = 0;
+ rate->sgi = false;
}

- rate_mask = rs_get_supported_rates(lq_sta, NULL, tbl->lq_type);
+ rate_mask = rs_get_supported_rates(lq_sta, NULL, rate);

/* Mask with station rate restriction */
- if (is_legacy(tbl->lq_type)) {
+ if (is_legacy(rate)) {
/* supp_rates has no CCK bits in A mode */
if (lq_sta->band == IEEE80211_BAND_5GHZ)
- rate_mask = (u16)(rate_mask &
+ rate_mask = (u16)(rate_mask &
(lq_sta->supp_rates << IWL_FIRST_OFDM_RATE));
else
rate_mask = (u16)(rate_mask & lq_sta->supp_rates);
@@ -721,24 +723,22 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
}

high_low = rs_get_adjacent_rate(lq_sta->drv, scale_index, rate_mask,
- tbl->lq_type);
+ rate->type);
low = high_low & 0xff;

if (low == IWL_RATE_INVALID)
low = scale_index;

out:
- return rate_n_flags_from_tbl(lq_sta->drv, tbl, low);
+ rate->index = low;
+ return ucode_rate_from_rs_rate(lq_sta->drv, rate);
}

-/*
- * Simple function to compare two rate scale table types
- */
-static bool table_type_matches(struct iwl_scale_tbl_info *a,
- struct iwl_scale_tbl_info *b)
+/* Simple function to compare two rate scale table types */
+static inline bool rs_rate_match(struct rs_rate *a,
+ struct rs_rate *b)
{
- return (a->lq_type == b->lq_type) && (a->ant_type == b->ant_type) &&
- (a->is_SGI == b->is_SGI);
+ return (a->type == b->type) && (a->ant == b->ant) && (a->sgi == b->sgi);
}

static u32 rs_ch_width_from_mac_flags(enum mac80211_rate_control_flags flags)
@@ -762,7 +762,7 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
{
int legacy_success;
int retries;
- int rs_index, mac_index, i;
+ int mac_index, i;
struct iwl_lq_sta *lq_sta = priv_sta;
struct iwl_lq_cmd *table;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
@@ -770,8 +770,8 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
enum mac80211_rate_control_flags mac_flags;
- u32 tx_rate;
- struct iwl_scale_tbl_info tbl_type;
+ u32 ucode_rate;
+ struct rs_rate rate;
struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl;

/* Treat uninitialized rate scaling data same as non-existing. */
@@ -801,10 +801,10 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
* to a new "search" mode (which might become the new "active" mode).
*/
table = &lq_sta->lq;
- tx_rate = le32_to_cpu(table->rs_table[0]);
- rs_get_tbl_info_from_mcs(tx_rate, info->band, &tbl_type, &rs_index);
+ ucode_rate = le32_to_cpu(table->rs_table[0]);
+ rs_rate_from_ucode_rate(ucode_rate, info->band, &rate);
if (info->band == IEEE80211_BAND_5GHZ)
- rs_index -= IWL_FIRST_OFDM_RATE;
+ rate.index -= IWL_FIRST_OFDM_RATE;
mac_flags = info->status.rates[0].flags;
mac_index = info->status.rates[0].idx;
/* For HT packets, map MCS to PLCP */
@@ -827,19 +827,19 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,

/* Here we actually compare this rate to the latest LQ command */
if ((mac_index < 0) ||
- (tbl_type.is_SGI != !!(mac_flags & IEEE80211_TX_RC_SHORT_GI)) ||
- (tbl_type.bw != rs_ch_width_from_mac_flags(mac_flags)) ||
- (tbl_type.ant_type != info->status.antenna) ||
- (!!(tx_rate & RATE_MCS_HT_MSK) !=
+ (rate.sgi != !!(mac_flags & IEEE80211_TX_RC_SHORT_GI)) ||
+ (rate.bw != rs_ch_width_from_mac_flags(mac_flags)) ||
+ (rate.ant != info->status.antenna) ||
+ (!!(ucode_rate & RATE_MCS_HT_MSK) !=
!!(mac_flags & IEEE80211_TX_RC_MCS)) ||
- (!!(tx_rate & RATE_MCS_VHT_MSK) !=
+ (!!(ucode_rate & RATE_MCS_VHT_MSK) !=
!!(mac_flags & IEEE80211_TX_RC_VHT_MCS)) ||
- (!!(tx_rate & RATE_HT_MCS_GF_MSK) !=
+ (!!(ucode_rate & RATE_HT_MCS_GF_MSK) !=
!!(mac_flags & IEEE80211_TX_RC_GREEN_FIELD)) ||
- (rs_index != mac_index)) {
+ (rate.index != mac_index)) {
IWL_DEBUG_RATE(mvm,
"initial rate %d does not match %d (0x%x)\n",
- mac_index, rs_index, tx_rate);
+ mac_index, rate.index, ucode_rate);
/*
* Since rates mis-match, the last LQ command may have failed.
* After IWL_MISSED_RATE_MAX mis-matches, resync the uCode with
@@ -857,28 +857,23 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
lq_sta->missed_rate_counter = 0;

/* Figure out if rate scale algorithm is in active or search table */
- if (table_type_matches(&tbl_type,
- &(lq_sta->lq_info[lq_sta->active_tbl]))) {
+ if (rs_rate_match(&rate,
+ &(lq_sta->lq_info[lq_sta->active_tbl].rate))) {
curr_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
other_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
- } else if (table_type_matches(
- &tbl_type, &lq_sta->lq_info[1 - lq_sta->active_tbl])) {
+ } else if (rs_rate_match(&rate,
+ &lq_sta->lq_info[1 - lq_sta->active_tbl].rate)) {
curr_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
other_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
} else {
IWL_DEBUG_RATE(mvm,
"Neither active nor search matches tx rate\n");
tmp_tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
- IWL_DEBUG_RATE(mvm, "active- lq:%x, ant:%x, SGI:%d\n",
- tmp_tbl->lq_type, tmp_tbl->ant_type,
- tmp_tbl->is_SGI);
+ rs_dump_rate(mvm, &tmp_tbl->rate, "ACTIVE");
tmp_tbl = &(lq_sta->lq_info[1 - lq_sta->active_tbl]);
- IWL_DEBUG_RATE(mvm, "search- lq:%x, ant:%x, SGI:%d\n",
- tmp_tbl->lq_type, tmp_tbl->ant_type,
- tmp_tbl->is_SGI);
- IWL_DEBUG_RATE(mvm, "actual- lq:%x, ant:%x, SGI:%d\n",
- tbl_type.lq_type, tbl_type.ant_type,
- tbl_type.is_SGI);
+ rs_dump_rate(mvm, &tmp_tbl->rate, "SEARCH");
+ rs_dump_rate(mvm, &rate, "ACTUAL");
+
/*
* no matching table found, let's by-pass the data collection
* and continue to perform rate scale to find the rate table
@@ -895,10 +890,9 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
* first index into rate scale table.
*/
if (info->flags & IEEE80211_TX_STAT_AMPDU) {
- tx_rate = le32_to_cpu(table->rs_table[0]);
- rs_get_tbl_info_from_mcs(tx_rate, info->band, &tbl_type,
- &rs_index);
- rs_collect_tx_data(curr_tbl, rs_index,
+ ucode_rate = le32_to_cpu(table->rs_table[0]);
+ rs_rate_from_ucode_rate(ucode_rate, info->band, &rate);
+ rs_collect_tx_data(curr_tbl, rate.index,
info->status.ampdu_len,
info->status.ampdu_ack_len);

@@ -920,20 +914,19 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
legacy_success = !!(info->flags & IEEE80211_TX_STAT_ACK);
/* Collect data for each rate used during failed TX attempts */
for (i = 0; i <= retries; ++i) {
- tx_rate = le32_to_cpu(table->rs_table[i]);
- rs_get_tbl_info_from_mcs(tx_rate, info->band,
- &tbl_type, &rs_index);
+ ucode_rate = le32_to_cpu(table->rs_table[i]);
+ rs_rate_from_ucode_rate(ucode_rate, info->band, &rate);
/*
* Only collect stats if retried rate is in the same RS
* table as active/search.
*/
- if (table_type_matches(&tbl_type, curr_tbl))
+ if (rs_rate_match(&rate, &curr_tbl->rate))
tmp_tbl = curr_tbl;
- else if (table_type_matches(&tbl_type, other_tbl))
+ else if (rs_rate_match(&rate, &other_tbl->rate))
tmp_tbl = other_tbl;
else
continue;
- rs_collect_tx_data(tmp_tbl, rs_index, 1,
+ rs_collect_tx_data(tmp_tbl, rate.index, 1,
i < retries ? 0 : legacy_success);
}

@@ -944,7 +937,7 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband,
}
}
/* The last TX rate is cached in lq_sta; it's set in if/else above */
- lq_sta->last_rate_n_flags = tx_rate;
+ lq_sta->last_rate_n_flags = ucode_rate;
done:
/* See if there's a better rate or modulation mode to try. */
if (sta && sta->supp_rates[sband->band])
@@ -988,16 +981,17 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
{
/* Used to choose among HT tables */
s32 (*ht_tbl_pointer)[IWL_RATE_COUNT];
+ struct rs_rate *rate = &tbl->rate;

/* Check for invalid LQ type */
- if (WARN_ON_ONCE(!is_legacy(tbl->lq_type) && !is_ht(tbl->lq_type) &&
- !(is_vht(tbl->lq_type)))) {
+ if (WARN_ON_ONCE(!is_legacy(rate) && !is_ht(rate) &&
+ !(is_vht(rate)))) {
tbl->expected_tpt = expected_tpt_legacy;
return;
}

/* Legacy rates have only one table */
- if (is_legacy(tbl->lq_type)) {
+ if (is_legacy(rate)) {
tbl->expected_tpt = expected_tpt_legacy;
return;
}
@@ -1006,8 +1000,8 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
/* Choose among many HT tables depending on number of streams
* (SISO/MIMO2), channel width (20/40/80), SGI, and aggregation
* status */
- if (is_siso(tbl->lq_type)) {
- switch (tbl->bw) {
+ if (is_siso(rate)) {
+ switch (rate->bw) {
case RATE_MCS_CHAN_WIDTH_20:
ht_tbl_pointer = expected_tpt_siso_20MHz;
break;
@@ -1020,8 +1014,8 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
default:
WARN_ON_ONCE(1);
}
- } else if (is_mimo2(tbl->lq_type)) {
- switch (tbl->bw) {
+ } else if (is_mimo2(rate)) {
+ switch (rate->bw) {
case RATE_MCS_CHAN_WIDTH_20:
ht_tbl_pointer = expected_tpt_mimo2_20MHz;
break;
@@ -1038,11 +1032,11 @@ static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
WARN_ON_ONCE(1);
}

- if (!tbl->is_SGI && !lq_sta->is_agg) /* Normal */
+ if (!rate->sgi && !lq_sta->is_agg) /* Normal */
tbl->expected_tpt = ht_tbl_pointer[0];
- else if (tbl->is_SGI && !lq_sta->is_agg) /* SGI */
+ else if (rate->sgi && !lq_sta->is_agg) /* SGI */
tbl->expected_tpt = ht_tbl_pointer[1];
- else if (!tbl->is_SGI && lq_sta->is_agg) /* AGG */
+ else if (!rate->sgi && lq_sta->is_agg) /* AGG */
tbl->expected_tpt = ht_tbl_pointer[2];
else /* AGG+SGI */
tbl->expected_tpt = ht_tbl_pointer[3];
@@ -1082,7 +1076,7 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm,

while (1) {
high_low = rs_get_adjacent_rate(mvm, rate, rate_mask,
- tbl->lq_type);
+ tbl->rate.type);

low = high_low & 0xff;
high = (high_low >> 8) & 0xff;
@@ -1163,30 +1157,29 @@ static inline void rs_move_next_action(struct iwl_scale_tbl_info *tbl,
tbl->action = (tbl->action + 1) % (last_action + 1);
}

-static void rs_set_bw_from_sta(struct iwl_scale_tbl_info *tbl,
- struct ieee80211_sta *sta)
+static u32 rs_bw_from_sta_bw(struct ieee80211_sta *sta)
{
if (sta->bandwidth >= IEEE80211_STA_RX_BW_80)
- tbl->bw = RATE_MCS_CHAN_WIDTH_80;
+ return RATE_MCS_CHAN_WIDTH_80;
else if (sta->bandwidth >= IEEE80211_STA_RX_BW_40)
- tbl->bw = RATE_MCS_CHAN_WIDTH_40;
- else
- tbl->bw = RATE_MCS_CHAN_WIDTH_20;
+ return RATE_MCS_CHAN_WIDTH_40;
+
+ return RATE_MCS_CHAN_WIDTH_20;
}

-static bool rs_sgi_allowed(struct iwl_scale_tbl_info *tbl,
+static bool rs_sgi_allowed(struct rs_rate *rate,
struct ieee80211_sta *sta)
{
struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;

- if (is_ht20(tbl) && (ht_cap->cap &
+ if (is_ht20(rate) && (ht_cap->cap &
IEEE80211_HT_CAP_SGI_20))
return true;
- if (is_ht40(tbl) && (ht_cap->cap &
+ if (is_ht40(rate) && (ht_cap->cap &
IEEE80211_HT_CAP_SGI_40))
return true;
- if (is_ht80(tbl) && (vht_cap->cap &
+ if (is_ht80(rate) && (vht_cap->cap &
IEEE80211_VHT_CAP_SHORT_GI_80))
return true;

@@ -1202,7 +1195,7 @@ static int rs_switch_to_mimo2(struct iwl_mvm *mvm,
struct iwl_scale_tbl_info *tbl, int index)
{
u16 rate_mask;
- s32 rate;
+ s32 rate_idx;

if (!sta->ht_cap.ht_supported)
return -1;
@@ -1216,24 +1209,26 @@ static int rs_switch_to_mimo2(struct iwl_mvm *mvm,

IWL_DEBUG_RATE(mvm, "LQ: try to switch to MIMO2\n");

- tbl->lq_type = lq_sta->is_vht ? LQ_VHT_MIMO2 : LQ_HT_MIMO2;
+ tbl->rate.type = lq_sta->is_vht ? LQ_VHT_MIMO2 : LQ_HT_MIMO2;
tbl->action = 0;
tbl->max_search = IWL_MAX_SEARCH;
rate_mask = lq_sta->active_mimo2_rate;

- rs_set_bw_from_sta(tbl, sta);
+ tbl->rate.bw = rs_bw_from_sta_bw(sta);
rs_set_expected_tpt_table(lq_sta, tbl);

- rate = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index);
+ rate_idx = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index);

IWL_DEBUG_RATE(mvm, "LQ: MIMO2 best rate %d mask %X\n",
- rate, rate_mask);
- if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
+ rate_idx, rate_mask);
+ if ((rate_idx == IWL_RATE_INVALID) || !((1 << rate_idx) & rate_mask)) {
IWL_DEBUG_RATE(mvm, "Can't switch with index %d rate mask %x\n",
- rate, rate_mask);
+ rate_idx, rate_mask);
return -1;
}
- tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, rate);
+
+ tbl->rate.index = rate_idx;
+ tbl->current_rate = ucode_rate_from_rs_rate(mvm, &tbl->rate);

IWL_DEBUG_RATE(mvm, "LQ: Switch to new mcs %X index\n",
tbl->current_rate);
@@ -1249,30 +1244,34 @@ static int rs_switch_to_siso(struct iwl_mvm *mvm,
struct iwl_scale_tbl_info *tbl, int index)
{
u16 rate_mask;
- s32 rate;
+ s32 rate_idx;

if (!sta->ht_cap.ht_supported)
return -1;

IWL_DEBUG_RATE(mvm, "LQ: try to switch to SISO\n");

- tbl->lq_type = lq_sta->is_vht ? LQ_VHT_SISO : LQ_HT_SISO;
+ tbl->rate.type = lq_sta->is_vht ? LQ_VHT_SISO : LQ_HT_SISO;
tbl->action = 0;
tbl->max_search = IWL_MAX_SEARCH;
rate_mask = lq_sta->active_siso_rate;

- rs_set_bw_from_sta(tbl, sta);
+ tbl->rate.bw = rs_bw_from_sta_bw(sta);
rs_set_expected_tpt_table(lq_sta, tbl);
- rate = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index);
+ rate_idx = rs_get_best_rate(mvm, lq_sta, tbl, rate_mask, index);

- IWL_DEBUG_RATE(mvm, "LQ: get best rate %d mask %X\n", rate, rate_mask);
- if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
+ IWL_DEBUG_RATE(mvm, "LQ: get best rate %d mask %X\n",
+ rate_idx, rate_mask);
+ if ((rate_idx == IWL_RATE_INVALID) || !((1 << rate_idx) & rate_mask)) {
IWL_DEBUG_RATE(mvm,
"can not switch with index %d rate mask %x\n",
- rate, rate_mask);
+ rate_idx, rate_mask);
return -1;
}
- tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, rate);
+
+ tbl->rate.index = rate_idx;
+ tbl->current_rate = ucode_rate_from_rs_rate(mvm, &tbl->rate);
+
IWL_DEBUG_RATE(mvm, "LQ: Switch to new mcs %X index\n",
tbl->current_rate);
return 0;
@@ -1289,6 +1288,7 @@ static int rs_move_legacy_other(struct iwl_mvm *mvm,
struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
struct iwl_scale_tbl_info *search_tbl =
&(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+ struct rs_rate *rate = &search_tbl->rate;
struct iwl_rate_scale_data *window = &(tbl->win[index]);
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
@@ -1317,7 +1317,7 @@ static int rs_move_legacy_other(struct iwl_mvm *mvm,

if (rs_toggle_antenna(valid_tx_ant,
&search_tbl->current_rate,
- search_tbl)) {
+ &search_tbl->rate)) {
update_search_tbl_counter = 1;
rs_set_expected_tpt_table(lq_sta, search_tbl);
goto out;
@@ -1328,7 +1328,7 @@ static int rs_move_legacy_other(struct iwl_mvm *mvm,

/* Set up search table to try SISO */
memcpy(search_tbl, tbl, sz);
- search_tbl->is_SGI = 0;
+ rate->sgi = false;
ret = rs_switch_to_siso(mvm, lq_sta, sta,
search_tbl, index);
if (!ret) {
@@ -1342,12 +1342,11 @@ static int rs_move_legacy_other(struct iwl_mvm *mvm,

/* Set up search table to try MIMO */
memcpy(search_tbl, tbl, sz);
- search_tbl->is_SGI = 0;
-
- search_tbl->ant_type = ANT_AB;
+ rate->sgi = false;
+ rate->ant = ANT_AB;

if (!rs_is_valid_ant(valid_tx_ant,
- search_tbl->ant_type))
+ rate->ant))
break;

ret = rs_switch_to_mimo2(mvm, lq_sta, sta,
@@ -1365,7 +1364,7 @@ static int rs_move_legacy_other(struct iwl_mvm *mvm,
if (tbl->action == start_action)
break;
}
- search_tbl->lq_type = LQ_NONE;
+ rate->type = LQ_NONE;
return 0;

out:
@@ -1386,6 +1385,7 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm,
struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
struct iwl_scale_tbl_info *search_tbl =
&(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+ struct rs_rate *rate = &search_tbl->rate;
struct iwl_rate_scale_data *window = &(tbl->win[index]);
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
@@ -1416,7 +1416,7 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm,
memcpy(search_tbl, tbl, sz);
if (rs_toggle_antenna(valid_tx_ant,
&search_tbl->current_rate,
- search_tbl)) {
+ rate)) {
update_search_tbl_counter = 1;
goto out;
}
@@ -1424,12 +1424,11 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm,
case IWL_SISO_SWITCH_MIMO2:
IWL_DEBUG_RATE(mvm, "LQ: SISO switch to MIMO2\n");
memcpy(search_tbl, tbl, sz);
- search_tbl->is_SGI = 0;
-
- search_tbl->ant_type = ANT_AB;
+ rate->sgi = false;
+ rate->ant = ANT_AB;

if (!rs_is_valid_ant(valid_tx_ant,
- search_tbl->ant_type))
+ rate->ant))
break;

ret = rs_switch_to_mimo2(mvm, lq_sta, sta,
@@ -1438,21 +1437,22 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm,
goto out;
break;
case IWL_SISO_SWITCH_GI:
- if (!rs_sgi_allowed(tbl, sta))
+ if (!rs_sgi_allowed(rate, sta))
break;

IWL_DEBUG_RATE(mvm, "LQ: SISO toggle SGI/NGI\n");

memcpy(search_tbl, tbl, sz);
- search_tbl->is_SGI = !tbl->is_SGI;
+ rate->sgi = !tbl->rate.sgi;
rs_set_expected_tpt_table(lq_sta, search_tbl);
- if (tbl->is_SGI) {
+ if (tbl->rate.sgi) {
s32 tpt = lq_sta->last_tpt / 100;
if (tpt >= search_tbl->expected_tpt[index])
break;
}
+ rate->index = index;
search_tbl->current_rate =
- rate_n_flags_from_tbl(mvm, search_tbl, index);
+ ucode_rate_from_rs_rate(mvm, rate);
update_search_tbl_counter = 1;
goto out;
default:
@@ -1463,7 +1463,7 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm,
if (tbl->action == start_action)
break;
}
- search_tbl->lq_type = LQ_NONE;
+ rate->type = LQ_NONE;
return 0;

out:
@@ -1485,6 +1485,7 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm,
struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
struct iwl_scale_tbl_info *search_tbl =
&(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+ struct rs_rate *rate = &search_tbl->rate;
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
u8 start_action;
@@ -1509,12 +1510,12 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm,
memcpy(search_tbl, tbl, sz);

if (tbl->action == IWL_MIMO2_SWITCH_SISO_A)
- search_tbl->ant_type = ANT_A;
+ rate->ant = ANT_A;
else /* tbl->action == IWL_MIMO2_SWITCH_SISO_B */
- search_tbl->ant_type = ANT_B;
+ rate->ant = ANT_B;

if (!rs_is_valid_ant(valid_tx_ant,
- search_tbl->ant_type))
+ rate->ant))
break;

ret = rs_switch_to_siso(mvm, lq_sta, sta,
@@ -1525,14 +1526,14 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm,
break;

case IWL_MIMO2_SWITCH_GI:
- if (!rs_sgi_allowed(tbl, sta))
+ if (!rs_sgi_allowed(rate, sta))
break;

IWL_DEBUG_RATE(mvm, "LQ: MIMO2 toggle SGI/NGI\n");

/* Set up new search table for MIMO2 */
memcpy(search_tbl, tbl, sz);
- search_tbl->is_SGI = !tbl->is_SGI;
+ rate->sgi = !tbl->rate.sgi;
rs_set_expected_tpt_table(lq_sta, search_tbl);
/*
* If active table already uses the fastest possible
@@ -1540,13 +1541,14 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm,
* and it's working well, there's no need to look
* for a better type of modulation!
*/
- if (tbl->is_SGI) {
+ if (tbl->rate.sgi) {
s32 tpt = lq_sta->last_tpt / 100;
if (tpt >= search_tbl->expected_tpt[index])
break;
}
+ rate->index = index;
search_tbl->current_rate =
- rate_n_flags_from_tbl(mvm, search_tbl, index);
+ ucode_rate_from_rs_rate(mvm, rate);
update_search_tbl_counter = 1;
goto out;
default:
@@ -1557,7 +1559,7 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm,
if (tbl->action == start_action)
break;
}
- search_tbl->lq_type = LQ_NONE;
+ rate->type = LQ_NONE;
return 0;
out:
lq_sta->search_better_tbl = 1;
@@ -1657,14 +1659,12 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
static void rs_update_rate_tbl(struct iwl_mvm *mvm,
struct ieee80211_sta *sta,
struct iwl_lq_sta *lq_sta,
- struct iwl_scale_tbl_info *tbl,
- int index)
+ struct rs_rate *rate)
{
- u32 rate;
+ u32 ucode_rate;

- /* Update uCode's rate table. */
- rate = rate_n_flags_from_tbl(mvm, tbl, index);
- rs_fill_link_cmd(mvm, sta, lq_sta, rate);
+ ucode_rate = ucode_rate_from_rs_rate(mvm, rate);
+ rs_fill_link_cmd(mvm, sta, lq_sta, ucode_rate);
iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false);
}

@@ -1716,6 +1716,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
u8 prev_agg = lq_sta->is_agg;
struct iwl_mvm_sta *sta_priv = (void *)sta->drv_priv;
struct iwl_mvm_tid_data *tid_data;
+ struct rs_rate *rate;

/* Send management frames and NO_ACK data using lowest rate. */
/* TODO: this could probably be improved.. */
@@ -1748,6 +1749,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
active_tbl = 1 - lq_sta->active_tbl;

tbl = &(lq_sta->lq_info[active_tbl]);
+ rate = &tbl->rate;

if (prev_agg != lq_sta->is_agg) {
IWL_DEBUG_RATE(mvm,
@@ -1760,10 +1762,10 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
index = lq_sta->last_txrate_idx;

/* rates available for this association, and for modulation mode */
- rate_mask = rs_get_supported_rates(lq_sta, hdr, tbl->lq_type);
+ rate_mask = rs_get_supported_rates(lq_sta, hdr, rate);

/* mask with station rate restriction */
- if (is_legacy(tbl->lq_type)) {
+ if (is_legacy(rate)) {
if (lq_sta->band == IEEE80211_BAND_5GHZ)
/* supp_rates has no CCK bits in A mode */
rate_scale_index_msk = (u16) (rate_mask &
@@ -1783,12 +1785,13 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
IWL_ERR(mvm, "Current Rate is not valid\n");
if (lq_sta->search_better_tbl) {
/* revert to active table if search table is not valid*/
- tbl->lq_type = LQ_NONE;
+ rate->type = LQ_NONE;
lq_sta->search_better_tbl = 0;
tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
/* get "active" rate info */
index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
- rs_update_rate_tbl(mvm, sta, lq_sta, tbl, index);
+ tbl->rate.index = index;
+ rs_update_rate_tbl(mvm, sta, lq_sta, &tbl->rate);
}
return;
}
@@ -1825,7 +1828,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
(window->success_counter < IWL_RATE_MIN_SUCCESS_TH)) {
IWL_DEBUG_RATE(mvm,
"(%s: %d): Test Window: succ %d total %d\n",
- rs_pretty_lq_type(tbl->lq_type),
+ rs_pretty_lq_type(rate->type),
index, window->success_counter, window->counter);

/* Can't calculate this yet; not enough history */
@@ -1858,7 +1861,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
window->average_tpt,
lq_sta->last_tpt);

- if (!is_legacy(tbl->lq_type))
+ if (!is_legacy(rate))
lq_sta->enable_counter = 1;

/* Swap tables; "search" becomes "active" */
@@ -1874,7 +1877,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
lq_sta->last_tpt);

/* Nullify "search" table */
- tbl->lq_type = LQ_NONE;
+ rate->type = LQ_NONE;

/* Revert to "active" table */
active_tbl = lq_sta->active_tbl;
@@ -1898,7 +1901,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
/* (Else) not in search of better modulation mode, try for better
* starting rate, while staying in this mode. */
high_low = rs_get_adjacent_rate(mvm, index, rate_scale_index_msk,
- tbl->lq_type);
+ rate->type);
low = high_low & 0xff;
high = (high_low >> 8) & 0xff;

@@ -1918,8 +1921,8 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,

IWL_DEBUG_RATE(mvm,
"(%s: %d): cur_tpt %d SR %d low %d high %d low_tpt %d high_tpt %d\n",
- rs_pretty_lq_type(tbl->lq_type), index, current_tpt,
- sr, low, high, low_tpt, high_tpt);
+ rs_pretty_lq_type(rate->type), index, current_tpt, sr,
+ low, high, low_tpt, high_tpt);

scale_action = 0;

@@ -2002,7 +2005,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
}

/* Force a search in case BT doesn't like us being in MIMO */
- if (is_mimo(tbl->lq_type) &&
+ if (is_mimo(rate) &&
!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) {
IWL_DEBUG_RATE(mvm,
"BT Coex forbids MIMO. Search for new config\n");
@@ -2041,8 +2044,10 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,

lq_update:
/* Replace uCode's rate table for the destination station. */
- if (update_lq)
- rs_update_rate_tbl(mvm, sta, lq_sta, tbl, index);
+ if (update_lq) {
+ tbl->rate.index = index;
+ rs_update_rate_tbl(mvm, sta, lq_sta, &tbl->rate);
+ }

rs_stay_in_table(lq_sta, false);

@@ -2063,11 +2068,11 @@ lq_update:
window->counter);
/* Select a new "search" modulation mode to try.
* If one is found, set up the new "search" table. */
- if (is_legacy(tbl->lq_type))
+ if (is_legacy(&tbl->rate))
rs_move_legacy_other(mvm, lq_sta, sta, index);
- else if (is_siso(tbl->lq_type))
+ else if (is_siso(&tbl->rate))
rs_move_siso_to_other(mvm, lq_sta, sta, index);
- else if (is_mimo2(tbl->lq_type))
+ else if (is_mimo2(&tbl->rate))
rs_move_mimo2_to_other(mvm, lq_sta, sta, index);
else
WARN_ON_ONCE(1);
@@ -2086,7 +2091,7 @@ lq_update:
"Switch to SEARCH TABLE: "
"mcs %X (%s: %d)\n",
tbl->current_rate,
- rs_pretty_lq_type(tbl->lq_type),
+ rs_pretty_lq_type(tbl->rate.type),
index);
rs_fill_link_cmd(mvm, sta, lq_sta, tbl->current_rate);
iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false);
@@ -2102,7 +2107,7 @@ lq_update:
* stay with best antenna legacy modulation for a while
* before next round of mode comparisons. */
tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]);
- if (is_legacy(tbl1->lq_type) && !sta->ht_cap.ht_supported &&
+ if (is_legacy(&tbl1->rate) && !sta->ht_cap.ht_supported &&
lq_sta->action_counter > tbl1->max_search) {
IWL_DEBUG_RATE(mvm, "LQ: STAY in legacy table\n");
rs_set_stay_in_table(mvm, 1, lq_sta);
@@ -2130,7 +2135,8 @@ lq_update:
}

out:
- tbl->current_rate = rate_n_flags_from_tbl(mvm, tbl, index);
+ tbl->rate.index = index;
+ tbl->current_rate = ucode_rate_from_rs_rate(mvm, &tbl->rate);
lq_sta->last_txrate_idx = index;
}

@@ -2155,9 +2161,9 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
bool init)
{
struct iwl_scale_tbl_info *tbl;
- int rate_idx;
+ struct rs_rate *rate;
int i;
- u32 rate;
+ u32 ucode_rate;
u8 active_tbl = 0;
u8 valid_tx_ant;

@@ -2174,25 +2180,26 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
active_tbl = 1 - lq_sta->active_tbl;

tbl = &(lq_sta->lq_info[active_tbl]);
+ rate = &tbl->rate;

if ((i < 0) || (i >= IWL_RATE_COUNT))
i = 0;

- rate = iwl_rates[i].plcp;
- tbl->ant_type = first_antenna(valid_tx_ant);
- rate |= tbl->ant_type << RATE_MCS_ANT_POS;
+ ucode_rate = iwl_rates[i].plcp;
+ rate->ant = first_antenna(valid_tx_ant);
+ ucode_rate |= rate->ant << RATE_MCS_ANT_POS;

if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE)
- rate |= RATE_MCS_CCK_MSK;
+ ucode_rate |= RATE_MCS_CCK_MSK;

- rs_get_tbl_info_from_mcs(rate, band, tbl, &rate_idx);
- if (!rs_is_valid_ant(valid_tx_ant, tbl->ant_type))
- rs_toggle_antenna(valid_tx_ant, &rate, tbl);
+ rs_rate_from_ucode_rate(ucode_rate, band, rate);
+ if (!rs_is_valid_ant(valid_tx_ant, rate->ant))
+ rs_toggle_antenna(valid_tx_ant, &ucode_rate, rate);

- rate = rate_n_flags_from_tbl(mvm, tbl, rate_idx);
- tbl->current_rate = rate;
+ ucode_rate = ucode_rate_from_rs_rate(mvm, rate);
+ tbl->current_rate = ucode_rate;
rs_set_expected_tpt_table(lq_sta, tbl);
- rs_fill_link_cmd(NULL, NULL, lq_sta, rate);
+ rs_fill_link_cmd(NULL, NULL, lq_sta, ucode_rate);
/* TODO restore station should remember the lq cmd */
iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, init);
}
@@ -2435,9 +2442,8 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm,
struct ieee80211_sta *sta,
struct iwl_lq_sta *lq_sta, u32 new_rate)
{
- struct iwl_scale_tbl_info tbl_type;
+ struct rs_rate rate;
int index = 0;
- int rate_idx;
int repeat_rate = 0;
u8 ant_toggle_cnt = 0;
u8 use_ht_possible = 1;
@@ -2447,12 +2453,10 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm,
/* Override starting rate (index 0) if needed for debug purposes */
rs_dbgfs_set_mcs(lq_sta, &new_rate);

- /* Interpret new_rate (rate_n_flags) */
- rs_get_tbl_info_from_mcs(new_rate, lq_sta->band,
- &tbl_type, &rate_idx);
+ rs_rate_from_ucode_rate(new_rate, lq_sta->band, &rate);

/* How many times should we repeat the initial rate? */
- if (is_legacy(tbl_type.lq_type)) {
+ if (is_legacy(&rate)) {
ant_toggle_cnt = 1;
repeat_rate = IWL_NUMBER_TRY;
} else {
@@ -2460,15 +2464,15 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm,
LINK_QUAL_AGG_DISABLE_START_DEF - 1);
}

- lq_cmd->mimo_delim = is_mimo(tbl_type.lq_type) ? 1 : 0;
+ lq_cmd->mimo_delim = is_mimo(&rate) ? 1 : 0;

/* Fill 1st table entry (index 0) */
lq_cmd->rs_table[index] = cpu_to_le32(new_rate);

- if (num_of_ant(tbl_type.ant_type) == 1)
- lq_cmd->single_stream_ant_msk = tbl_type.ant_type;
- else if (num_of_ant(tbl_type.ant_type) == 2)
- lq_cmd->dual_stream_ant_msk = tbl_type.ant_type;
+ if (num_of_ant(rate.ant) == 1)
+ lq_cmd->single_stream_ant_msk = rate.ant;
+ else if (num_of_ant(rate.ant) == 2)
+ lq_cmd->dual_stream_ant_msk = rate.ant;
/* otherwise we don't modify the existing value */

index++;
@@ -2482,12 +2486,12 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm,
* For legacy IWL_NUMBER_TRY == 1, this loop will not execute.
* For HT IWL_HT_NUMBER_TRY == 3, this executes twice. */
while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) {
- if (is_legacy(tbl_type.lq_type)) {
+ if (is_legacy(&rate)) {
if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE)
ant_toggle_cnt++;
else if (mvm &&
rs_toggle_antenna(valid_tx_ant,
- &new_rate, &tbl_type))
+ &new_rate, &rate))
ant_toggle_cnt = 1;
}

@@ -2501,26 +2505,25 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm,
index++;
}

- rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, &tbl_type,
- &rate_idx);
+ rs_rate_from_ucode_rate(new_rate, lq_sta->band, &rate);

/* Indicate to uCode which entries might be MIMO.
* If initial rate was MIMO, this will finally end up
* as (IWL_HT_NUMBER_TRY * 2), after 2nd pass, otherwise 0. */
- if (is_mimo(tbl_type.lq_type))
+ if (is_mimo(&rate))
lq_cmd->mimo_delim = index;

/* Get next rate */
- new_rate = rs_get_lower_rate(lq_sta, &tbl_type, rate_idx,
+ new_rate = rs_get_lower_rate(lq_sta, &rate, rate.index,
use_ht_possible);

/* How many times should we repeat the next rate? */
- if (is_legacy(tbl_type.lq_type)) {
+ if (is_legacy(&rate)) {
if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE)
ant_toggle_cnt++;
else if (mvm &&
rs_toggle_antenna(valid_tx_ant,
- &new_rate, &tbl_type))
+ &new_rate, &rate))
ant_toggle_cnt = 1;

repeat_rate = IWL_NUMBER_TRY;
@@ -2629,7 +2632,7 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,

static const char *rs_pretty_lq_type(enum iwl_table_type type)
{
- static const char * const lq_type[] = {
+ static const char * const lq_types[] = {
[LQ_NONE] = "NONE",
[LQ_LEGACY_A] = "LEGACY_A",
[LQ_LEGACY_G] = "LEGACY_G",
@@ -2642,10 +2645,10 @@ static const char *rs_pretty_lq_type(enum iwl_table_type type)
if (type < LQ_NONE || type >= LQ_MAX)
return "UNKNOWN";

- return lq_type[type];
+ return lq_types[type];
}

-static int rs_pretty_print_rate(char *buf, const u32 rate)
+static const char *rs_pretty_ant(u8 ant)
{
static const char * const ant_name[] = {
[ANT_NONE] = "None",
@@ -2658,6 +2661,15 @@ static int rs_pretty_print_rate(char *buf, const u32 rate)
[ANT_ABC] = "ABC",
};

+ if (ant > ANT_ABC)
+ return "UNKNOWN";
+
+ return ant_name[ant];
+}
+
+static int rs_pretty_print_rate(char *buf, const u32 rate)
+{
+
char *type, *bw;
u8 mcs = 0, nss = 0;
u8 ant = (rate & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS;
@@ -2667,7 +2679,7 @@ static int rs_pretty_print_rate(char *buf, const u32 rate)
int index = iwl_hwrate_to_plcp_idx(rate);

return sprintf(buf, "Legacy | ANT: %s Rate: %s Mbps\n",
- ant_name[ant], iwl_rate_mcs[index].mbps);
+ rs_pretty_ant(ant), iwl_rate_mcs[index].mbps);
}

if (rate & RATE_MCS_VHT_MSK) {
@@ -2700,7 +2712,7 @@ static int rs_pretty_print_rate(char *buf, const u32 rate)
}

return sprintf(buf, "%s | ANT: %s BW: %s MCS: %d NSS: %d %s%s%s%s%s\n",
- type, ant_name[ant], bw, mcs, nss,
+ type, rs_pretty_ant(ant), bw, mcs, nss,
(rate & RATE_MCS_SGI_MSK) ? "SGI " : "NGI ",
(rate & RATE_MCS_STBC_MSK) ? "STBC " : "",
(rate & RATE_MCS_LDPC_MSK) ? "LDPC " : "",
@@ -2719,7 +2731,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
struct iwl_lq_sta *lq_sta = file->private_data;
struct iwl_mvm *mvm;
struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
-
+ struct rs_rate *rate = &tbl->rate;
mvm = lq_sta->drv;
buff = kmalloc(2048, GFP_KERNEL);
if (!buff)
@@ -2736,17 +2748,17 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
(iwl_fw_valid_tx_ant(mvm->fw) & ANT_B) ? "ANT_B," : "",
(iwl_fw_valid_tx_ant(mvm->fw) & ANT_C) ? "ANT_C" : "");
desc += sprintf(buff+desc, "lq type %s\n",
- (is_legacy(tbl->lq_type)) ? "legacy" :
- is_vht(tbl->lq_type) ? "VHT" : "HT");
- if (!is_legacy(tbl->lq_type)) {
+ (is_legacy(rate)) ? "legacy" :
+ is_vht(rate) ? "VHT" : "HT");
+ if (!is_legacy(rate)) {
desc += sprintf(buff+desc, " %s",
- (is_siso(tbl->lq_type)) ? "SISO" : "MIMO2");
+ (is_siso(rate)) ? "SISO" : "MIMO2");
desc += sprintf(buff+desc, " %s",
- (is_ht20(tbl)) ? "20MHz" :
- (is_ht40(tbl)) ? "40MHz" :
- (is_ht80(tbl)) ? "80Mhz" : "BAD BW");
+ (is_ht20(rate)) ? "20MHz" :
+ (is_ht40(rate)) ? "40MHz" :
+ (is_ht80(rate)) ? "80Mhz" : "BAD BW");
desc += sprintf(buff+desc, " %s %s\n",
- (tbl->is_SGI) ? "SGI" : "NGI",
+ (rate->sgi) ? "SGI" : "NGI",
(lq_sta->is_agg) ? "AGG on" : "");
}
desc += sprintf(buff+desc, "last tx rate=0x%X\n",
@@ -2799,6 +2811,7 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
int i, j;
ssize_t ret;
struct iwl_scale_tbl_info *tbl;
+ struct rs_rate *rate;
struct iwl_lq_sta *lq_sta = file->private_data;

buff = kmalloc(1024, GFP_KERNEL);
@@ -2807,15 +2820,16 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,

for (i = 0; i < LQ_SIZE; i++) {
tbl = &(lq_sta->lq_info[i]);
+ rate = &tbl->rate;
desc += sprintf(buff+desc,
"%s type=%d SGI=%d BW=%s DUP=0\n"
"rate=0x%X\n",
lq_sta->active_tbl == i ? "*" : "x",
- tbl->lq_type,
- tbl->is_SGI,
- is_ht20(tbl) ? "20Mhz" :
- is_ht40(tbl) ? "40Mhz" :
- is_ht80(tbl) ? "80Mhz" : "ERR",
+ rate->type,
+ rate->sgi,
+ is_ht20(rate) ? "20Mhz" :
+ is_ht40(rate) ? "40Mhz" :
+ is_ht80(rate) ? "80Mhz" : "ERR",
tbl->current_rate);
for (j = 0; j < IWL_RATE_COUNT; j++) {
desc += sprintf(buff+desc,
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h
index ae983bc..8fa26af 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.h
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.h
@@ -224,22 +224,45 @@ enum iwl_table_type {
LQ_MAX,
};

-#define is_legacy(tbl) (((tbl) == LQ_LEGACY_G) || ((tbl) == LQ_LEGACY_A))
-#define is_ht_siso(tbl) ((tbl) == LQ_HT_SISO)
-#define is_ht_mimo2(tbl) ((tbl) == LQ_HT_MIMO2)
-#define is_vht_siso(tbl) ((tbl) == LQ_VHT_SISO)
-#define is_vht_mimo2(tbl) ((tbl) == LQ_VHT_MIMO2)
-#define is_siso(tbl) (is_ht_siso(tbl) || is_vht_siso(tbl))
-#define is_mimo2(tbl) (is_ht_mimo2(tbl) || is_vht_mimo2(tbl))
-#define is_mimo(tbl) (is_mimo2(tbl))
-#define is_ht(tbl) (is_ht_siso(tbl) || is_ht_mimo2(tbl))
-#define is_vht(tbl) (is_vht_siso(tbl) || is_vht_mimo2(tbl))
-#define is_a_band(tbl) ((tbl) == LQ_LEGACY_A)
-#define is_g_band(tbl) ((tbl) == LQ_LEGACY_G)
-
-#define is_ht20(tbl) (tbl->bw == RATE_MCS_CHAN_WIDTH_20)
-#define is_ht40(tbl) (tbl->bw == RATE_MCS_CHAN_WIDTH_40)
-#define is_ht80(tbl) (tbl->bw == RATE_MCS_CHAN_WIDTH_80)
+struct rs_rate {
+ int index;
+ enum iwl_table_type type;
+ u8 ant;
+ u32 bw;
+ bool sgi;
+};
+
+
+#define is_type_legacy(type) (((type) == LQ_LEGACY_G) || \
+ ((type) == LQ_LEGACY_A))
+#define is_type_ht_siso(type) ((type) == LQ_HT_SISO)
+#define is_type_ht_mimo2(type) ((type) == LQ_HT_MIMO2)
+#define is_type_vht_siso(type) ((type) == LQ_VHT_SISO)
+#define is_type_vht_mimo2(type) ((type) == LQ_VHT_MIMO2)
+#define is_type_siso(type) (is_type_ht_siso(type) || is_type_vht_siso(type))
+#define is_type_mimo2(type) (is_type_ht_mimo2(type) || is_type_vht_mimo2(type))
+#define is_type_mimo(type) (is_type_mimo2(type))
+#define is_type_ht(type) (is_type_ht_siso(type) || is_type_ht_mimo2(type))
+#define is_type_vht(type) (is_type_vht_siso(type) || is_type_vht_mimo2(type))
+#define is_type_a_band(type) ((type) == LQ_LEGACY_A)
+#define is_type_g_band(type) ((type) == LQ_LEGACY_G)
+
+#define is_legacy(rate) is_type_legacy((rate)->type)
+#define is_ht_siso(rate) is_type_ht_siso((rate)->type)
+#define is_ht_mimo2(rate) is_type_ht_mimo2((rate)->type)
+#define is_vht_siso(rate) is_type_vht_siso((rate)->type)
+#define is_vht_mimo2(rate) is_type_vht_mimo2((rate)->type)
+#define is_siso(rate) is_type_siso((rate)->type)
+#define is_mimo2(rate) is_type_mimo2((rate)->type)
+#define is_mimo(rate) is_type_mimo((rate)->type)
+#define is_ht(rate) is_type_ht((rate)->type)
+#define is_vht(rate) is_type_vht((rate)->type)
+#define is_a_band(rate) is_type_a_band((rate)->type)
+#define is_g_band(rate) is_type_g_band((rate)->type)
+
+#define is_ht20(rate) ((rate)->bw == RATE_MCS_CHAN_WIDTH_20)
+#define is_ht40(rate) ((rate)->bw == RATE_MCS_CHAN_WIDTH_40)
+#define is_ht80(rate) ((rate)->bw == RATE_MCS_CHAN_WIDTH_80)

#define IWL_MAX_MCS_DISPLAY_SIZE 12

@@ -266,10 +289,7 @@ struct iwl_rate_scale_data {
* one for "active", and one for "search".
*/
struct iwl_scale_tbl_info {
- enum iwl_table_type lq_type;
- u8 ant_type;
- u8 is_SGI; /* 1 = short guard interval */
- u32 bw; /* channel bandwidth; RATE_MCS_CHAN_WIDTH_XX */
+ struct rs_rate rate;
u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */
u8 max_search; /* maximun number of tables we can search */
s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */
--
1.7.9.5


2013-12-02 20:59:50

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 06/13] iwlwifi: mvm: rs: remove unused timestamp field

From: Eyal Shapira <[email protected]>

Remove this as it's unused.

Signed-off-by: Eyal Shapira <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/rs.c | 4 ----
drivers/net/wireless/iwlwifi/mvm/rs.h | 1 -
2 files changed, 5 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index 9249e52..0598f26 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -271,7 +271,6 @@ static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window)
window->success_ratio = IWL_INVALID_VALUE;
window->counter = 0;
window->average_tpt = IWL_INVALID_VALUE;
- window->stamp = 0;
}

static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type)
@@ -428,9 +427,6 @@ static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl,
else
window->average_tpt = IWL_INVALID_VALUE;

- /* Tag this window as having been updated */
- window->stamp = jiffies;
-
return 0;
}

diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h
index e5d448c..ae983bc 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.h
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.h
@@ -257,7 +257,6 @@ struct iwl_rate_scale_data {
s32 success_ratio; /* per-cent * 128 */
s32 counter; /* number of frames attempted */
s32 average_tpt; /* success ratio * expected throughput */
- unsigned long stamp;
};

/**
--
1.7.9.5


2013-12-02 20:59:56

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 10/13] iwlwifi: mvm: rs: fix mapping from HT/VHT rates to legacy

From: Eyal Shapira <[email protected]>

The table rs_ht_to_legacy is used to get the next legacy rate
following the last HT or VHT rate in the LQ rates table.
The mapping wasn't correct as well as didn't include entries
for MCS8/9 which led to out of bounds access. This didn't
trigger a crash but led to legacy rate entries using 1Mbps
rate.
In 5Ghz this probably caused the Tx to fail completely given
that Tx attempt would have reached the legacy entries and 1Mbps
isn't valid.

Signed-off-by: Eyal Shapira <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/rs.c | 25 ++++++++++++-------------
1 file changed, 12 insertions(+), 13 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index 5c98d462..ef7126a 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -56,19 +56,16 @@


static u8 rs_ht_to_legacy[] = {
- [IWL_RATE_1M_INDEX] = IWL_RATE_6M_INDEX,
- [IWL_RATE_2M_INDEX] = IWL_RATE_6M_INDEX,
- [IWL_RATE_5M_INDEX] = IWL_RATE_6M_INDEX,
- [IWL_RATE_11M_INDEX] = IWL_RATE_6M_INDEX,
- [IWL_RATE_6M_INDEX] = IWL_RATE_6M_INDEX,
- [IWL_RATE_9M_INDEX] = IWL_RATE_6M_INDEX,
- [IWL_RATE_12M_INDEX] = IWL_RATE_9M_INDEX,
- [IWL_RATE_18M_INDEX] = IWL_RATE_12M_INDEX,
- [IWL_RATE_24M_INDEX] = IWL_RATE_18M_INDEX,
- [IWL_RATE_36M_INDEX] = IWL_RATE_24M_INDEX,
- [IWL_RATE_48M_INDEX] = IWL_RATE_36M_INDEX,
- [IWL_RATE_54M_INDEX] = IWL_RATE_48M_INDEX,
- [IWL_RATE_60M_INDEX] = IWL_RATE_54M_INDEX,
+ [IWL_RATE_MCS_0_INDEX] = IWL_RATE_6M_INDEX,
+ [IWL_RATE_MCS_1_INDEX] = IWL_RATE_9M_INDEX,
+ [IWL_RATE_MCS_2_INDEX] = IWL_RATE_12M_INDEX,
+ [IWL_RATE_MCS_3_INDEX] = IWL_RATE_18M_INDEX,
+ [IWL_RATE_MCS_4_INDEX] = IWL_RATE_24M_INDEX,
+ [IWL_RATE_MCS_5_INDEX] = IWL_RATE_36M_INDEX,
+ [IWL_RATE_MCS_6_INDEX] = IWL_RATE_48M_INDEX,
+ [IWL_RATE_MCS_7_INDEX] = IWL_RATE_54M_INDEX,
+ [IWL_RATE_MCS_8_INDEX] = IWL_RATE_54M_INDEX,
+ [IWL_RATE_MCS_9_INDEX] = IWL_RATE_54M_INDEX,
};

static const u8 ant_toggle_lookup[] = {
@@ -682,6 +679,8 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
* are always supported (spec demand) */
if (!is_legacy(rate) && (!ht_possible || !scale_index)) {
switch_to_legacy = 1;
+ WARN_ON_ONCE(scale_index < IWL_RATE_MCS_0_INDEX &&
+ scale_index > IWL_RATE_MCS_9_INDEX);
scale_index = rs_ht_to_legacy[scale_index];
if (lq_sta->band == IEEE80211_BAND_5GHZ)
rate->type = LQ_LEGACY_A;
--
1.7.9.5


2013-12-02 20:59:45

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 02/13] iwlwifi: mvm: rs: reduce min failures to end test window

From: Eyal Shapira <[email protected]>

This terminates a test window of a new rate quicker in case
we've hit a bad rate and should recover better.

Signed-off-by: Eyal Shapira <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/rs.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index 0655209..ecf24cb 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -47,7 +47,7 @@
#define IWL_HT_NUMBER_TRY 3

#define IWL_RATE_MAX_WINDOW 62 /* # tx in history window */
-#define IWL_RATE_MIN_FAILURE_TH 6 /* min failures to calc tpt */
+#define IWL_RATE_MIN_FAILURE_TH 3 /* min failures to calc tpt */
#define IWL_RATE_MIN_SUCCESS_TH 8 /* min successes to calc tpt */

/* max allowed rate miss before sync LQ cmd */
--
1.7.9.5


2014-01-06 18:04:24

by Eyal Shapira

[permalink] [raw]
Subject: Re: [PATCH 12/13] iwlwifi: mvm: rs: overhaul search cycle state machine

On Mon, Jan 6, 2014 at 5:07 PM, Karl Beldan <[email protected]> wrote:
> On Mon, Dec 02, 2013 at 10:59:24PM +0200, Emmanuel Grumbach wrote:
>> From: Eyal Shapira <[email protected]>
>>
>> Rewrite the search cycle state machine to use a more data
>> oriented approach where the different Tx columns (configs)
>> limitations and next columns to search are reprsented in
>> tables which are easy to change. This overhaul also includes
>> several major fixes:
>>
>> 1. Prevent going back to a specific Tx column in a search
>> cycle if it was already explored.
>>
>> 2. Avoid switching to a Tx column that doesn't have any chance
>> if it performs perfectly to beat the current throughput we're
>> getting.
>>
>> These issues were degrading throughput as they were causing
>> switching to "bad" Tx columns.
>>
>> Signed-off-by: Eyal Shapira <[email protected]>
>> Signed-off-by: Emmanuel Grumbach <[email protected]>
>> ---
>> drivers/net/wireless/iwlwifi/mvm/rs.c | 921 +++++++++++++++------------------
>> drivers/net/wireless/iwlwifi/mvm/rs.h | 64 +--
>> 2 files changed, 458 insertions(+), 527 deletions(-)
>>
>> @@ -1772,7 +1712,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
> [...]
>> - if (done_search && !lq_sta->stay_in_tbl) {
>> + if (done_search && lq_sta->rs_state == RS_STATE_SEARCH_CYCLE_ENDED) {
>> /* If the "active" (non-search) mode was legacy,
> [...]
>
> Hi,
>
> Trying -testing right now on my laptop and this commit broke aggregation.
>

Thanks Karl for the report.
I'm seeing Tx aggregation. Note that it doesn't start off immediately
but only after enough traffic went through for us to explore different
Tx configurations.

Some questions:
1. How do you see aggregation is broken ? sniffer or just lower
throughput you're getting ?
2. What's the chip ?
3. Do you connect in 11n or 11ac ?
4. Any chance you can set module parameter debug=0x04100000 and send the logs ?
Configuring IWLWIFI_DEBUG is required.

> I haven't looked at the code but this seemed to help :
> - if (done_search && lq_sta->rs_state == RS_STATE_SEARCH_CYCLE_ENDED) {
> + if (done_search && lq_sta->rs_state != RS_STATE_STAY_IN_COLUMN)

This wouldn't be good as it might get us stuck on non optimal Tx
configurations before exploring other better ones.

Thanks,
Eyal

2014-01-07 18:14:25

by Karl Beldan

[permalink] [raw]
Subject: Re: [PATCH 12/13] iwlwifi: mvm: rs: overhaul search cycle state machine

On Tue, Jan 07, 2014 at 06:30:07PM +0200, Eyal Shapira wrote:
> Thanks. Seems like we decided the AP doesn't support any MIMO rates.
> This wasn't handled well and caused the search cycle for an optimal Tx
> configuration to get stuck.
> Can you try the attached patch ?
>
Working, thanks.

> Also, any chance you can send a traffic capture of some beacons and the assoc ?
> I'd like to understand why we come to the conclusion no MIMO is supported.
>
AP limitation, but here is a capture anyway.

Karl


Attachments:
(No filename) (506.00 B)
iwlwifi-11n-5180_40MHz.pcap (821.00 B)
Download all attachments

2014-01-07 16:30:28

by Eyal Shapira

[permalink] [raw]
Subject: Re: [PATCH 12/13] iwlwifi: mvm: rs: overhaul search cycle state machine

On Tue, Jan 7, 2014 at 12:27 PM, Karl Beldan <[email protected]> wrote:
> On Mon, Jan 06, 2014 at 08:04:03PM +0200, Eyal Shapira wrote:
>> On Mon, Jan 6, 2014 at 5:07 PM, Karl Beldan <[email protected]> wrote:
>> > On Mon, Dec 02, 2013 at 10:59:24PM +0200, Emmanuel Grumbach wrote:
>> >> From: Eyal Shapira <[email protected]>
>> >>
>> >> Rewrite the search cycle state machine to use a more data
>> >> oriented approach where the different Tx columns (configs)
>> >> limitations and next columns to search are reprsented in
>> >> tables which are easy to change. This overhaul also includes
>> >> several major fixes:
>> >>
>> >> 1. Prevent going back to a specific Tx column in a search
>> >> cycle if it was already explored.
>> >>
>> >> 2. Avoid switching to a Tx column that doesn't have any chance
>> >> if it performs perfectly to beat the current throughput we're
>> >> getting.
>> >>
>> >> These issues were degrading throughput as they were causing
>> >> switching to "bad" Tx columns.
>> >>
>> >> Signed-off-by: Eyal Shapira <[email protected]>
>> >> Signed-off-by: Emmanuel Grumbach <[email protected]>
>> >> ---
>> >> drivers/net/wireless/iwlwifi/mvm/rs.c | 921 +++++++++++++++------------------
>> >> drivers/net/wireless/iwlwifi/mvm/rs.h | 64 +--
>> >> 2 files changed, 458 insertions(+), 527 deletions(-)
>> >>
>> >> @@ -1772,7 +1712,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
>> > [...]
>> >> - if (done_search && !lq_sta->stay_in_tbl) {
>> >> + if (done_search && lq_sta->rs_state == RS_STATE_SEARCH_CYCLE_ENDED) {
>> >> /* If the "active" (non-search) mode was legacy,
>> > [...]
>> >
>> > Hi,
>> >
>> > Trying -testing right now on my laptop and this commit broke aggregation.
>> >
>>
>> Thanks Karl for the report.
>> I'm seeing Tx aggregation. Note that it doesn't start off immediately
>> but only after enough traffic went through for us to explore different
>> Tx configurations.
>>
>> Some questions:
>> 1. How do you see aggregation is broken ? sniffer or just lower
>> throughput you're getting ?
> It doesn't send any addBA action frame and traffic is not aggregated.
>
>> 2. What's the chip ?
> AC 7260, REV=0x144
>
>> 3. Do you connect in 11n or 11ac ?
> Tried both
>
>> 4. Any chance you can set module parameter debug=0x04100000 and send the logs ?
>> Configuring IWLWIFI_DEBUG is required.
> Here you are.
>

Thanks. Seems like we decided the AP doesn't support any MIMO rates.
This wasn't handled well and caused the search cycle for an optimal Tx
configuration to get stuck.
Can you try the attached patch ?

Also, any chance you can send a traffic capture of some beacons and the assoc ?
I'd like to understand why we come to the conclusion no MIMO is supported.

Thanks,
Eyal


Attachments:
0001-iwlwifi-mvm-rs-fix-handling-of-column-switch-error.patch (1.47 kB)

2014-01-07 10:28:50

by Karl Beldan

[permalink] [raw]
Subject: Re: [PATCH 12/13] iwlwifi: mvm: rs: overhaul search cycle state machine

On Mon, Jan 06, 2014 at 08:04:03PM +0200, Eyal Shapira wrote:
> On Mon, Jan 6, 2014 at 5:07 PM, Karl Beldan <[email protected]> wrote:
> > On Mon, Dec 02, 2013 at 10:59:24PM +0200, Emmanuel Grumbach wrote:
> >> From: Eyal Shapira <[email protected]>
> >>
> >> Rewrite the search cycle state machine to use a more data
> >> oriented approach where the different Tx columns (configs)
> >> limitations and next columns to search are reprsented in
> >> tables which are easy to change. This overhaul also includes
> >> several major fixes:
> >>
> >> 1. Prevent going back to a specific Tx column in a search
> >> cycle if it was already explored.
> >>
> >> 2. Avoid switching to a Tx column that doesn't have any chance
> >> if it performs perfectly to beat the current throughput we're
> >> getting.
> >>
> >> These issues were degrading throughput as they were causing
> >> switching to "bad" Tx columns.
> >>
> >> Signed-off-by: Eyal Shapira <[email protected]>
> >> Signed-off-by: Emmanuel Grumbach <[email protected]>
> >> ---
> >> drivers/net/wireless/iwlwifi/mvm/rs.c | 921 +++++++++++++++------------------
> >> drivers/net/wireless/iwlwifi/mvm/rs.h | 64 +--
> >> 2 files changed, 458 insertions(+), 527 deletions(-)
> >>
> >> @@ -1772,7 +1712,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
> > [...]
> >> - if (done_search && !lq_sta->stay_in_tbl) {
> >> + if (done_search && lq_sta->rs_state == RS_STATE_SEARCH_CYCLE_ENDED) {
> >> /* If the "active" (non-search) mode was legacy,
> > [...]
> >
> > Hi,
> >
> > Trying -testing right now on my laptop and this commit broke aggregation.
> >
>
> Thanks Karl for the report.
> I'm seeing Tx aggregation. Note that it doesn't start off immediately
> but only after enough traffic went through for us to explore different
> Tx configurations.
>
> Some questions:
> 1. How do you see aggregation is broken ? sniffer or just lower
> throughput you're getting ?
It doesn't send any addBA action frame and traffic is not aggregated.

> 2. What's the chip ?
AC 7260, REV=0x144

> 3. Do you connect in 11n or 11ac ?
Tried both

> 4. Any chance you can set module parameter debug=0x04100000 and send the logs ?
> Configuring IWLWIFI_DEBUG is required.
Here you are.


Karl


Attachments:
(No filename) (2.22 kB)
iwlwifi-11n-5180_40MHz.txt (532.85 kB)
Download all attachments

2014-01-06 15:08:11

by Karl Beldan

[permalink] [raw]
Subject: Re: [PATCH 12/13] iwlwifi: mvm: rs: overhaul search cycle state machine

On Mon, Dec 02, 2013 at 10:59:24PM +0200, Emmanuel Grumbach wrote:
> From: Eyal Shapira <[email protected]>
>
> Rewrite the search cycle state machine to use a more data
> oriented approach where the different Tx columns (configs)
> limitations and next columns to search are reprsented in
> tables which are easy to change. This overhaul also includes
> several major fixes:
>
> 1. Prevent going back to a specific Tx column in a search
> cycle if it was already explored.
>
> 2. Avoid switching to a Tx column that doesn't have any chance
> if it performs perfectly to beat the current throughput we're
> getting.
>
> These issues were degrading throughput as they were causing
> switching to "bad" Tx columns.
>
> Signed-off-by: Eyal Shapira <[email protected]>
> Signed-off-by: Emmanuel Grumbach <[email protected]>
> ---
> drivers/net/wireless/iwlwifi/mvm/rs.c | 921 +++++++++++++++------------------
> drivers/net/wireless/iwlwifi/mvm/rs.h | 64 +--
> 2 files changed, 458 insertions(+), 527 deletions(-)
>
> @@ -1772,7 +1712,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
[...]
> - if (done_search && !lq_sta->stay_in_tbl) {
> + if (done_search && lq_sta->rs_state == RS_STATE_SEARCH_CYCLE_ENDED) {
> /* If the "active" (non-search) mode was legacy,
[...]

Hi,

Trying -testing right now on my laptop and this commit broke aggregation.

I haven't looked at the code but this seemed to help :
- if (done_search && lq_sta->rs_state == RS_STATE_SEARCH_CYCLE_ENDED) {
+ if (done_search && lq_sta->rs_state != RS_STATE_STAY_IN_COLUMN)



Karl

2014-01-07 18:35:20

by Eyal Shapira

[permalink] [raw]
Subject: Re: [PATCH 12/13] iwlwifi: mvm: rs: overhaul search cycle state machine

On Tue, Jan 7, 2014 at 8:13 PM, Karl Beldan <[email protected]> wrote:
> On Tue, Jan 07, 2014 at 06:30:07PM +0200, Eyal Shapira wrote:
>> Thanks. Seems like we decided the AP doesn't support any MIMO rates.
>> This wasn't handled well and caused the search cycle for an optimal Tx
>> configuration to get stuck.
>> Can you try the attached patch ?
>>
> Working, thanks.
>

great. thanks for testing and again for reporting to begin with.

>> Also, any chance you can send a traffic capture of some beacons and the assoc ?
>> I'd like to understand why we come to the conclusion no MIMO is supported.
>>
> AP limitation, but here is a capture anyway.

ok. so everything here makes sense.