2013-12-17 20:42:31

by Emmanuel Grumbach

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

Hi John,

here is another batch for 3.14.

I have hear quite a few things. Alex continues his work on power
management. Arik is reworking the transport API by unifying redudant
APIs and making error handling more generic. Eyal keeps on digging in
the rate scaling code.
We also have two new features - Max is using the brand new generic
cipher infrastructure in mac80211, and Lilach implements the smart fifo
which allows to save power by making interrupt coalescing smarter.

Let me know about issues you might have (hopefully none)!

The following changes since commit 9d10849e4ea8bf9d8da80afa73918a9fe45c09ef:

iwlwifi: mvm: rs: fix compilation without CONFIG_MAC80211_DEBUGFS
(2013-12-09 22:29:49 +0200)

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 cf4ef65446443eb485afe9419ea82b2efbe582a7:

iwlwifi: mvm: rs: fix variable shadowing (2013-12-17 22:32:57 +0200)

----------------------------------------------------------------
Alexander Bondar (6):
iwlwifi: mvm: Add uAPSD misbehaving AP notification handling
iwlwifi: mvm: Change power management dependency on multi MAC
iwlwifi: mvm: Disable power save for monitor interface
iwlwifi: mvm: Enable power save on a single P2P client interface
iwlwifi: mvm: add per-vif power debugfs hooks
iwlwifi: mvm: Add and examine TLV flag for P2P client uAPSD support

Arik Nemtsov (6):
iwlwifi: trans: divide stop_hw into stop_device/op_mode_leave
iwlwifi: trans: use a unified transport status
iwlwifi: trans: prevent tx and cmds during FW error
iwlwifi: trans: prevent reprobe on repeated FW errors before restart
iwlwifi: trans: clear FW_ERROR status in common code
iwlwifi: trans: turn set_pmi into an optional callback

Eliad Peller (3):
iwlwifi: mvm: add multicast filtering support
iwlwifi: mvm: configure phy_ctxt with min_def
iwlwifi: mvm: check iwl_nvm_init return value

Emmanuel Grumbach (4):
iwlwifi: mvm: don't send SMPS action frame with single RX antenna
iwlwifi: mvm: move iwl_mvm_set_tx_power to PHY area
iwlwifi: remove pointer to transport from op_mode
iwlwifi: mvm: fixup Makefile

Eyal Shapira (12):
iwlwifi: publish STBC support in HT
iwlwifi: set VHT beamformee STS cap correctly
iwlwifi: publish Tx STBC support in VHT
iwlwifi: mvm: rs: move rs_program_fix_rate to cleanup ifdefs
iwlwifi: mvm: rs: refactor building the LQ command
iwlwifi: mvm: rs: avoid recalc of supported legacy rate mask
iwlwifi: mvm: rs: improve rates table algo
iwlwifi: mvm: rs: remove unnecessary debug logs
iwlwifi: mvm: rs: refactor rate scale action decision
iwlwifi: mvm: rs: disable MCS9 Tx workaround
iwlwifi: mvm: set highest rate in VHT MCS Set
iwlwifi: mvm: rs: fix RTS protection being set indefinitely

Ilan Peer (1):
iwlwifi: mvm: Do not allow AP MAC context update if not active

Johannes Berg (2):
iwlwifi: mvm: clarify smps_requests documentation
iwlwifi: mvm: rs: fix variable shadowing

Lilach Edelstein (1):
iwlwifi: mvm: Add Smart FIFO support

Max Stepanov (1):
iwlwifi: mvm: add a generic cipher scheme support

drivers/net/wireless/iwlwifi/dvm/mac80211.c | 6 -
drivers/net/wireless/iwlwifi/dvm/main.c | 4 +-
drivers/net/wireless/iwlwifi/iwl-7000.c | 2 +-
drivers/net/wireless/iwlwifi/iwl-config.h | 2 +
drivers/net/wireless/iwlwifi/iwl-drv.c | 39 ++
drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c | 7 +
drivers/net/wireless/iwlwifi/iwl-fw-file.h | 1 +
drivers/net/wireless/iwlwifi/iwl-fw.h | 46 ++
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 15 +-
drivers/net/wireless/iwlwifi/iwl-op-mode.h | 4 +-
drivers/net/wireless/iwlwifi/iwl-trans.h | 66 ++-
drivers/net/wireless/iwlwifi/mvm/Makefile | 3 +-
drivers/net/wireless/iwlwifi/mvm/binding.c | 16 +-
drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c | 353 ++++++++++++
drivers/net/wireless/iwlwifi/mvm/fw-api-power.h | 16 +
drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h | 10 +-
drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h | 1 +
drivers/net/wireless/iwlwifi/mvm/fw-api.h | 65 +++
drivers/net/wireless/iwlwifi/mvm/fw.c | 28 +-
drivers/net/wireless/iwlwifi/mvm/mac80211.c | 252 ++++++---
drivers/net/wireless/iwlwifi/mvm/mvm.h | 45 +-
drivers/net/wireless/iwlwifi/mvm/ops.c | 20 +-
drivers/net/wireless/iwlwifi/mvm/power.c | 395 ++++++++-----
drivers/net/wireless/iwlwifi/mvm/rs.c | 686
++++++++++++-----------
drivers/net/wireless/iwlwifi/mvm/rs.h | 2 -
drivers/net/wireless/iwlwifi/mvm/rx.c | 6 +
drivers/net/wireless/iwlwifi/mvm/sf.c | 291 ++++++++++
drivers/net/wireless/iwlwifi/mvm/sta.c | 21 +-
drivers/net/wireless/iwlwifi/mvm/tt.c | 2 +-
drivers/net/wireless/iwlwifi/mvm/tx.c | 3 +-
drivers/net/wireless/iwlwifi/mvm/utils.c | 5 +
drivers/net/wireless/iwlwifi/pcie/internal.h | 33 +-
drivers/net/wireless/iwlwifi/pcie/rx.c | 35 +-
drivers/net/wireless/iwlwifi/pcie/trans.c | 86 ++-
drivers/net/wireless/iwlwifi/pcie/tx.c | 37 +-
35 files changed, 1837 insertions(+), 766 deletions(-)
create mode 100644 drivers/net/wireless/iwlwifi/mvm/sf.c


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

2013-12-17 20:45:09

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 16/36] iwlwifi: trans: divide stop_hw into stop_device/op_mode_leave

From: Arik Nemtsov <[email protected]>

The stop_hw trans callback is not well defined. It is missing in many
cleanup flows and the division of labor between stop_device/stop_hw
is cumbersome. Remove stop_hw and use stop_device to perform both.
Implement this for all current transports.

PCIE needs some extra configuration the op-mode is leaving to configure
RF kill. Expose this explicitly as a new op_mode_leave trans callback.
Take the call to stop_device outside iwl_run_mvm_init_ucode, this
makes more sense and WARN when we want to run the INIT firmware while
it has run already.

Signed-off-by: Arik Nemtsov <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/dvm/mac80211.c | 6 ----
drivers/net/wireless/iwlwifi/dvm/main.c | 4 +--
drivers/net/wireless/iwlwifi/iwl-trans.h | 25 +++++++-------
drivers/net/wireless/iwlwifi/mvm/fw.c | 24 +++++++------
drivers/net/wireless/iwlwifi/mvm/mac80211.c | 2 --
drivers/net/wireless/iwlwifi/mvm/ops.c | 9 ++---
drivers/net/wireless/iwlwifi/mvm/tt.c | 2 +-
drivers/net/wireless/iwlwifi/pcie/trans.c | 50 ++++++++++++---------------
8 files changed, 55 insertions(+), 67 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
index 217f1ca..9f4239d 100644
--- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
@@ -322,12 +322,6 @@ static void iwlagn_mac_stop(struct ieee80211_hw *hw)

flush_workqueue(priv->workqueue);

- /* User space software may expect getting rfkill changes
- * even if interface is down, trans->down will leave the RF
- * kill interrupt enabled
- */
- iwl_trans_stop_hw(priv->trans, false);
-
IWL_DEBUG_MAC80211(priv, "leave\n");
}

diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c
index 7aad766..fd9f6cf 100644
--- a/drivers/net/wireless/iwlwifi/dvm/main.c
+++ b/drivers/net/wireless/iwlwifi/dvm/main.c
@@ -1313,7 +1313,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
}

/* Reset chip to save power until we load uCode during "up". */
- iwl_trans_stop_hw(priv->trans, false);
+ iwl_trans_stop_device(priv->trans);

priv->nvm_data = iwl_parse_eeprom_data(priv->trans->dev, priv->cfg,
priv->eeprom_blob,
@@ -1458,7 +1458,7 @@ static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode)

dev_kfree_skb(priv->beacon_skb);

- iwl_trans_stop_hw(priv->trans, true);
+ iwl_trans_op_mode_leave(priv->trans);
ieee80211_free_hw(priv->hw);
}

diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index 143292b..43ea124 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -100,8 +100,7 @@
* start_fw
*
* 5) Then when finished (or reset):
- * stop_fw (a.k.a. stop device for the moment)
- * stop_hw
+ * stop_device
*
* 6) Eventually, the free function will be called.
*/
@@ -361,9 +360,7 @@ struct iwl_trans;
*
* @start_hw: starts the HW- from that point on, the HW can send interrupts
* May sleep
- * @stop_hw: stops the HW- from that point on, the HW will be in low power but
- * will still issue interrupt if the HW RF kill is triggered unless
- * op_mode_leaving is true.
+ * @op_mode_leave: Turn off the HW RF kill indication if on
* May sleep
* @start_fw: allocates and inits all the resources for the transport
* layer. Also kick a fw image.
@@ -371,8 +368,11 @@ struct iwl_trans;
* @fw_alive: called when the fw sends alive notification. If the fw provides
* the SCD base address in SRAM, then provide it here, or 0 otherwise.
* May sleep
- * @stop_device:stops the whole device (embedded CPU put to reset)
- * May sleep
+ * @stop_device: stops the whole device (embedded CPU put to reset) and stops
+ * the HW. From that point on, the HW will be in low power but will still
+ * issue interrupt if the HW RF kill is triggered. This callback must do
+ * the right thing and not crash even if start_hw() was called but not
+ * start_fw(). May sleep
* @d3_suspend: put the device into the correct mode for WoWLAN during
* suspend. This is optional, if not implemented WoWLAN will not be
* supported. This callback may sleep.
@@ -418,7 +418,7 @@ struct iwl_trans;
struct iwl_trans_ops {

int (*start_hw)(struct iwl_trans *iwl_trans);
- void (*stop_hw)(struct iwl_trans *iwl_trans, bool op_mode_leaving);
+ void (*op_mode_leave)(struct iwl_trans *iwl_trans);
int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw,
bool run_in_rfkill);
void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr);
@@ -540,15 +540,14 @@ static inline int iwl_trans_start_hw(struct iwl_trans *trans)
return trans->ops->start_hw(trans);
}

-static inline void iwl_trans_stop_hw(struct iwl_trans *trans,
- bool op_mode_leaving)
+static inline void iwl_trans_op_mode_leave(struct iwl_trans *trans)
{
might_sleep();

- trans->ops->stop_hw(trans, op_mode_leaving);
+ if (trans->ops->op_mode_leave)
+ trans->ops->op_mode_leave(trans);

- if (op_mode_leaving)
- trans->op_mode = NULL;
+ trans->op_mode = NULL;

trans->state = IWL_TRANS_NO_FW;
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c
index b2bfa73..27ba104 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/iwlwifi/mvm/fw.c
@@ -241,7 +241,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)

lockdep_assert_held(&mvm->mutex);

- if (mvm->init_ucode_complete)
+ if (WARN_ON_ONCE(mvm->init_ucode_complete))
return 0;

iwl_init_notification_wait(&mvm->notif_wait,
@@ -287,7 +287,8 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
IWL_DEBUG_RF_KILL(mvm,
"jump over all phy activities due to RF kill\n");
iwl_remove_notification(&mvm->notif_wait, &calib_wait);
- return 1;
+ ret = 1;
+ goto out;
}

/* Send TX valid antennas before triggering calibrations */
@@ -319,9 +320,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
error:
iwl_remove_notification(&mvm->notif_wait, &calib_wait);
out:
- if (!iwlmvm_mod_params.init_dbg) {
- iwl_trans_stop_device(mvm->trans);
- } else if (!mvm->nvm_data) {
+ if (iwlmvm_mod_params.init_dbg && !mvm->nvm_data) {
/* we want to debug INIT and we have no NVM - fake */
mvm->nvm_data = kzalloc(sizeof(struct iwl_nvm_data) +
sizeof(struct ieee80211_channel) +
@@ -370,11 +369,16 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
ret = -ERFKILL;
goto error;
}
- /* should stop & start HW since that INIT image just loaded */
- iwl_trans_stop_hw(mvm->trans, false);
- ret = iwl_trans_start_hw(mvm->trans);
- if (ret)
- return ret;
+ if (!iwlmvm_mod_params.init_dbg) {
+ /*
+ * should stop and start HW since that INIT
+ * image just loaded
+ */
+ iwl_trans_stop_device(mvm->trans);
+ ret = iwl_trans_start_hw(mvm->trans);
+ if (ret)
+ return ret;
+ }
}

if (iwlmvm_mod_params.init_dbg)
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index fbd3114..272aabd 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -405,7 +405,6 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
{
iwl_trans_stop_device(mvm->trans);
- iwl_trans_stop_hw(mvm->trans, false);

mvm->scan_status = IWL_MVM_SCAN_NONE;

@@ -477,7 +476,6 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
cancel_work_sync(&mvm->roc_done_wk);

iwl_trans_stop_device(mvm->trans);
- iwl_trans_stop_hw(mvm->trans, false);

iwl_mvm_async_handlers_purge(mvm);
/* async_handlers_list is empty and will stay empty: HW is stopped */
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
index 668525f..a6f4be8 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -436,16 +436,13 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,

mutex_lock(&mvm->mutex);
err = iwl_run_init_mvm_ucode(mvm, true);
+ iwl_trans_stop_device(trans);
mutex_unlock(&mvm->mutex);
/* returns 0 if successful, 1 if success but in rfkill */
if (err < 0 && !iwlmvm_mod_params.init_dbg) {
IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err);
goto out_free;
}
-
- /* Stop the hw after the ALIVE and NVM has been read */
- if (!iwlmvm_mod_params.init_dbg)
- iwl_trans_stop_hw(mvm->trans, false);
}

scan_size = sizeof(struct iwl_scan_cmd) +
@@ -478,7 +475,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
iwl_phy_db_free(mvm->phy_db);
kfree(mvm->scan_cmd);
if (!iwlwifi_mod_params.nvm_file)
- iwl_trans_stop_hw(trans, true);
+ iwl_trans_op_mode_leave(trans);
ieee80211_free_hw(mvm->hw);
return NULL;
}
@@ -502,7 +499,7 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
kfree(mvm->d3_resume_sram);
#endif

- iwl_trans_stop_hw(mvm->trans, true);
+ iwl_trans_op_mode_leave(mvm->trans);

iwl_phy_db_free(mvm->phy_db);
mvm->phy_db = NULL;
diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c
index 18be04d..a0ec7b3 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tt.c
@@ -340,7 +340,7 @@ static void check_exit_ctkill(struct work_struct *work)

iwl_trans_start_hw(mvm->trans);
temp = check_nic_temperature(mvm);
- iwl_trans_stop_hw(mvm->trans, false);
+ iwl_trans_stop_device(mvm->trans);

if (temp < MIN_TEMPERATURE || temp > MAX_TEMPERATURE) {
IWL_DEBUG_TEMP(mvm, "Failed to measure NIC temperature\n");
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index cde9c16..43eed4d 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -641,6 +641,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
unsigned long flags;
+ bool hw_rfkill;

/* tell the device to stop sending interrupts */
spin_lock_irqsave(&trans_pcie->irq_lock, flags);
@@ -681,8 +682,6 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
iwl_disable_interrupts(trans);
spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);

- iwl_enable_rfkill_int(trans);
-
/* stop and reset the on-board processor */
iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);

@@ -692,6 +691,25 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
clear_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status);
clear_bit(STATUS_TPOWER_PMI, &trans_pcie->status);
clear_bit(STATUS_RFKILL, &trans_pcie->status);
+
+ /*
+ * Even if we stop the HW, we still want the RF kill
+ * interrupt
+ */
+ iwl_enable_rfkill_int(trans);
+
+ /*
+ * Check again since the RF kill state may have changed while
+ * all the interrupts were disabled, in this case we couldn't
+ * receive the RF kill interrupt and update the state in the
+ * op_mode.
+ */
+ hw_rfkill = iwl_is_rfkill_set(trans);
+ if (hw_rfkill)
+ set_bit(STATUS_RFKILL, &trans_pcie->status);
+ else
+ clear_bit(STATUS_RFKILL, &trans_pcie->status);
+ iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
}

static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test)
@@ -806,13 +824,12 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
return 0;
}

-static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans,
- bool op_mode_leaving)
+static void iwl_trans_pcie_op_mode_leave(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
- bool hw_rfkill;
unsigned long flags;

+ /* disable interrupts - don't enable HW RF kill interrupt */
spin_lock_irqsave(&trans_pcie->irq_lock, flags);
iwl_disable_interrupts(trans);
spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
@@ -824,27 +841,6 @@ static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans,
spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);

iwl_pcie_disable_ict(trans);
-
- if (!op_mode_leaving) {
- /*
- * Even if we stop the HW, we still want the RF kill
- * interrupt
- */
- iwl_enable_rfkill_int(trans);
-
- /*
- * Check again since the RF kill state may have changed while
- * all the interrupts were disabled, in this case we couldn't
- * receive the RF kill interrupt and update the state in the
- * op_mode.
- */
- hw_rfkill = iwl_is_rfkill_set(trans);
- if (hw_rfkill)
- set_bit(STATUS_RFKILL, &trans_pcie->status);
- else
- clear_bit(STATUS_RFKILL, &trans_pcie->status);
- iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
- }
}

static void iwl_trans_pcie_write8(struct iwl_trans *trans, u32 ofs, u8 val)
@@ -1457,7 +1453,7 @@ static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,

static const struct iwl_trans_ops trans_ops_pcie = {
.start_hw = iwl_trans_pcie_start_hw,
- .stop_hw = iwl_trans_pcie_stop_hw,
+ .op_mode_leave = iwl_trans_pcie_op_mode_leave,
.fw_alive = iwl_trans_pcie_fw_alive,
.start_fw = iwl_trans_pcie_start_fw,
.stop_device = iwl_trans_pcie_stop_device,
--
1.7.9.5


2013-12-17 20:45:16

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 22/36] iwlwifi: trans: prevent reprobe on repeated FW errors before restart

From: Arik Nemtsov <[email protected]>

In case a sync command timeouts or Tx is stuck while a FW error
interrupt arrives, we might call iwl_op_mode_nic_error twice before
a restart has been initiated. This will cause a reprobe. Unify calls
to this function at the transport level and only call it on the first
FW error in a given by checking the transport FW error flag.

While at it, remove the privately defined iwl_nic_error from PCIE code
and use the common callback instead.

Signed-off-by: Arik Nemtsov <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-trans.h | 11 +++++++++++
drivers/net/wireless/iwlwifi/pcie/internal.h | 6 ------
drivers/net/wireless/iwlwifi/pcie/rx.c | 12 ++++++------
drivers/net/wireless/iwlwifi/pcie/tx.c | 6 +++---
4 files changed, 20 insertions(+), 15 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index c71519d..fa495ba 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -70,6 +70,7 @@
#include "iwl-debug.h"
#include "iwl-config.h"
#include "iwl-fw.h"
+#include "iwl-op-mode.h"

/**
* DOC: Transport layer - what is it ?
@@ -805,6 +806,16 @@ iwl_trans_release_nic_access(struct iwl_trans *trans, unsigned long *flags)
__release(nic_access);
}

+static inline void iwl_trans_fw_error(struct iwl_trans *trans)
+{
+ if (WARN_ON_ONCE(!trans->op_mode))
+ return;
+
+ /* prevent double restarts due to the same erroneous FW */
+ if (!test_and_set_bit(STATUS_FW_ERROR, &trans->status))
+ iwl_op_mode_nic_error(trans->op_mode);
+}
+
/*****************************************************
* driver (transport) register/unregister functions
******************************************************/
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h
index 8a2de33..674c75b 100644
--- a/drivers/net/wireless/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/iwlwifi/pcie/internal.h
@@ -456,10 +456,4 @@ static inline bool iwl_is_rfkill_set(struct iwl_trans *trans)
CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW);
}

-static inline void iwl_nic_error(struct iwl_trans *trans)
-{
- set_bit(STATUS_FW_ERROR, &trans->status);
- iwl_op_mode_nic_error(trans->op_mode);
-}
-
#endif /* __iwl_trans_int_pcie_h__ */
diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c
index bbbb3ca..7aeec5c 100644
--- a/drivers/net/wireless/iwlwifi/pcie/rx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/rx.c
@@ -797,14 +797,14 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans)
iwl_pcie_dump_csr(trans);
iwl_dump_fh(trans, NULL);

- /* set the ERROR bit before we wake up the caller */
- set_bit(STATUS_FW_ERROR, &trans->status);
- clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
- wake_up(&trans_pcie->wait_command_queue);
-
local_bh_disable();
- iwl_nic_error(trans);
+ /* The STATUS_FW_ERROR bit is set in this function. This must happen
+ * before we wake up the command caller, to ensure a proper cleanup. */
+ iwl_trans_fw_error(trans);
local_bh_enable();
+
+ clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
+ wake_up(&trans_pcie->wait_command_queue);
}

irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c
index 5b63948..8df2478 100644
--- a/drivers/net/wireless/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/tx.c
@@ -207,7 +207,7 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data)
IWL_ERR(trans, "scratch %d = 0x%08x\n", i,
le32_to_cpu(txq->scratchbufs[i].scratch));

- iwl_nic_error(trans);
+ iwl_trans_fw_error(trans);
}

/*
@@ -1021,7 +1021,7 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx)
if (nfreed++ > 0) {
IWL_ERR(trans, "HCMD skipped: index (%d) %d %d\n",
idx, q->write_ptr, q->read_ptr);
- iwl_nic_error(trans);
+ iwl_trans_fw_error(trans);
}
}

@@ -1555,7 +1555,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
get_cmd_string(trans_pcie, cmd->id));
ret = -ETIMEDOUT;

- iwl_nic_error(trans);
+ iwl_trans_fw_error(trans);

goto cancel;
}
--
1.7.9.5


2013-12-17 20:44:53

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 05/36] iwlwifi: set VHT beamformee STS cap correctly

From: Eyal Shapira <[email protected]>

It was set to zero which reflects support of a single STS.
Set according to the number of Rx antennas which correctly
reflects the number of STSs the STA can receive in a VHT NDP.
This improves beamforming and has been tested to improve Rx
throughput.

Signed-off-by: Eyal Shapira <[email protected]>
Reviewed-by: Johannes Berg <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 3 +++
1 file changed, 3 insertions(+)

diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
index 94aef22..e366f12 100644
--- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
@@ -263,11 +263,14 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
struct iwl_nvm_data *data,
struct ieee80211_sta_vht_cap *vht_cap)
{
+ int bf_sts_cap = num_of_ant(data->valid_rx_ant) - 1;
+
vht_cap->vht_supported = true;

vht_cap->cap = IEEE80211_VHT_CAP_SHORT_GI_80 |
IEEE80211_VHT_CAP_RXSTBC_1 |
IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
+ bf_sts_cap << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT |
7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;

if (iwlwifi_mod_params.amsdu_size_8K)
--
1.7.9.5


2013-12-18 20:15:17

by John W. Linville

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

On Tue, Dec 17, 2013 at 10:42:18PM +0200, Emmanuel Grumbach wrote:
> Hi John,
>
> here is another batch for 3.14.
>
> I have hear quite a few things. Alex continues his work on power
> management. Arik is reworking the transport API by unifying redudant
> APIs and making error handling more generic. Eyal keeps on digging in
> the rate scaling code.
> We also have two new features - Max is using the brand new generic
> cipher infrastructure in mac80211, and Lilach implements the smart fifo
> which allows to save power by making interrupt coalescing smarter.
>
> Let me know about issues you might have (hopefully none)!
>
> The following changes since commit 9d10849e4ea8bf9d8da80afa73918a9fe45c09ef:
>
> iwlwifi: mvm: rs: fix compilation without CONFIG_MAC80211_DEBUGFS
> (2013-12-09 22:29:49 +0200)
>
> 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 cf4ef65446443eb485afe9419ea82b2efbe582a7:
>
> iwlwifi: mvm: rs: fix variable shadowing (2013-12-17 22:32:57 +0200)

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-17 20:45:19

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 24/36] iwlwifi: trans: turn set_pmi into an optional callback

From: Arik Nemtsov <[email protected]>

It is not currently implemented for SDIO, and not required for other slave
buses as well.

Signed-off-by: Arik Nemtsov <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-trans.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index 8aaabdb..0c36478 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -787,7 +787,8 @@ static inline u32 iwl_trans_write_mem32(struct iwl_trans *trans, u32 addr,

static inline void iwl_trans_set_pmi(struct iwl_trans *trans, bool state)
{
- trans->ops->set_pmi(trans, state);
+ if (trans->ops->set_pmi)
+ trans->ops->set_pmi(trans, state);
}

static inline void
--
1.7.9.5


2013-12-17 20:45:32

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 33/36] iwlwifi: mvm: rs: disable MCS9 Tx workaround

From: Eyal Shapira <[email protected]>

MCS9 introduces some corner cases in the current rs
algorithm which may lead to non optimal throughput and
instability in the throughput. Until all the corner
cases are resolved disable MCS9 for Tx as a workaround
which yields better throughput results as MCS8 is much
more stable.

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

diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index 62b29d7..1f06450 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -2207,6 +2207,10 @@ static void rs_vht_set_enabled_rates(struct ieee80211_sta *sta,
if (i == IWL_RATE_9M_INDEX)
continue;

+ /* Disable MCS9 as a workaround */
+ if (i == IWL_RATE_MCS_9_INDEX)
+ continue;
+
/* VHT MCS9 isn't valid for 20Mhz for NSS=1,2 */
if (i == IWL_RATE_MCS_9_INDEX &&
sta->bandwidth == IEEE80211_STA_RX_BW_20)
@@ -2225,6 +2229,10 @@ static void rs_vht_set_enabled_rates(struct ieee80211_sta *sta,
if (i == IWL_RATE_9M_INDEX)
continue;

+ /* Disable MCS9 as a workaround */
+ if (i == IWL_RATE_MCS_9_INDEX)
+ continue;
+
/* VHT MCS9 isn't valid for 20Mhz for NSS=1,2 */
if (i == IWL_RATE_MCS_9_INDEX &&
sta->bandwidth == IEEE80211_STA_RX_BW_20)
--
1.7.9.5


2013-12-17 20:45:10

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 17/36] iwlwifi: trans: use a unified transport status

From: Arik Nemtsov <[email protected]>

The same bits are employed in all transport layers. Put the status
field in the common transport layer. This allows us to employ them
in common transport code.

Signed-off-by: Arik Nemtsov <[email protected]>
Reviewed-by: Johannes Berg <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-trans.h | 20 +++++++++++++
drivers/net/wireless/iwlwifi/pcie/internal.h | 29 ++-----------------
drivers/net/wireless/iwlwifi/pcie/rx.c | 27 ++++++++---------
drivers/net/wireless/iwlwifi/pcie/trans.c | 40 +++++++++++---------------
drivers/net/wireless/iwlwifi/pcie/tx.c | 30 +++++++++----------
5 files changed, 65 insertions(+), 81 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index 43ea124..6419603 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -317,6 +317,24 @@ enum iwl_d3_status {
};

/**
+ * enum iwl_trans_status: transport status flags
+ * @STATUS_SYNC_HCMD_ACTIVE: a SYNC command is being processed
+ * @STATUS_DEVICE_ENABLED: APM is enabled
+ * @STATUS_TPOWER_PMI: the device might be asleep (need to wake it up)
+ * @STATUS_INT_ENABLED: interrupts are enabled
+ * @STATUS_RFKILL: the HW RFkill switch is in KILL position
+ * @STATUS_FW_ERROR: the fw is in error state
+ */
+enum iwl_trans_status {
+ STATUS_SYNC_HCMD_ACTIVE,
+ STATUS_DEVICE_ENABLED,
+ STATUS_TPOWER_PMI,
+ STATUS_INT_ENABLED,
+ STATUS_RFKILL,
+ STATUS_FW_ERROR,
+};
+
+/**
* struct iwl_trans_config - transport configuration
*
* @op_mode: pointer to the upper layer.
@@ -479,6 +497,7 @@ enum iwl_trans_state {
* @ops - pointer to iwl_trans_ops
* @op_mode - pointer to the op_mode
* @cfg - pointer to the configuration
+ * @status: a bit-mask of transport status flags
* @dev - pointer to struct device * that represents the device
* @hw_id: a u32 with the ID of the device / subdevice.
* Set during transport allocation.
@@ -499,6 +518,7 @@ struct iwl_trans {
struct iwl_op_mode *op_mode;
const struct iwl_cfg *cfg;
enum iwl_trans_state state;
+ unsigned long status;

struct device *dev;
u32 hw_rev;
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h
index 051268c..8a2de33 100644
--- a/drivers/net/wireless/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/iwlwifi/pcie/internal.h
@@ -256,7 +256,6 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx)
* @hw_base: pci hardware address support
* @ucode_write_complete: indicates that the ucode has been copied.
* @ucode_write_waitq: wait queue for uCode load
- * @status - transport specific status flags
* @cmd_queue - command queue number
* @rx_buf_size_8k: 8 kB RX buffer size
* @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes)
@@ -296,7 +295,6 @@ struct iwl_trans_pcie {
wait_queue_head_t ucode_write_waitq;
wait_queue_head_t wait_command_queue;

- unsigned long status;
u8 cmd_queue;
u8 cmd_fifo;
u8 n_no_reclaim_cmds;
@@ -315,24 +313,6 @@ struct iwl_trans_pcie {
spinlock_t reg_lock;
};

-/**
- * enum iwl_pcie_status: status of the PCIe transport
- * @STATUS_HCMD_ACTIVE: a SYNC command is being processed
- * @STATUS_DEVICE_ENABLED: APM is enabled
- * @STATUS_TPOWER_PMI: the device might be asleep (need to wake it up)
- * @STATUS_INT_ENABLED: interrupts are enabled
- * @STATUS_RFKILL: the HW RFkill switch is in KILL position
- * @STATUS_FW_ERROR: the fw is in error state
- */
-enum iwl_pcie_status {
- STATUS_HCMD_ACTIVE,
- STATUS_DEVICE_ENABLED,
- STATUS_TPOWER_PMI,
- STATUS_INT_ENABLED,
- STATUS_RFKILL,
- STATUS_FW_ERROR,
-};
-
#define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \
((struct iwl_trans_pcie *) ((_iwl_trans)->trans_specific))

@@ -399,8 +379,7 @@ void iwl_pcie_dump_csr(struct iwl_trans *trans);
******************************************************/
static inline void iwl_disable_interrupts(struct iwl_trans *trans)
{
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
- clear_bit(STATUS_INT_ENABLED, &trans_pcie->status);
+ clear_bit(STATUS_INT_ENABLED, &trans->status);

/* disable interrupts from uCode/NIC to host */
iwl_write32(trans, CSR_INT_MASK, 0x00000000);
@@ -417,7 +396,7 @@ static inline void iwl_enable_interrupts(struct iwl_trans *trans)
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);

IWL_DEBUG_ISR(trans, "Enabling interrupts\n");
- set_bit(STATUS_INT_ENABLED, &trans_pcie->status);
+ set_bit(STATUS_INT_ENABLED, &trans->status);
iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask);
}

@@ -479,9 +458,7 @@ static inline bool iwl_is_rfkill_set(struct iwl_trans *trans)

static inline void iwl_nic_error(struct iwl_trans *trans)
{
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
- set_bit(STATUS_FW_ERROR, &trans_pcie->status);
+ set_bit(STATUS_FW_ERROR, &trans->status);
iwl_op_mode_nic_error(trans->op_mode);
}

diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c
index 1d6bf7b..bbbb3ca 100644
--- a/drivers/net/wireless/iwlwifi/pcie/rx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/rx.c
@@ -162,11 +162,8 @@ static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans,
rxq->write_actual = (rxq->write & ~0x7);
iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, rxq->write_actual);
} else {
- struct iwl_trans_pcie *trans_pcie =
- IWL_TRANS_GET_PCIE_TRANS(trans);
-
/* If power-saving is in use, make sure device is awake */
- if (test_bit(STATUS_TPOWER_PMI, &trans_pcie->status)) {
+ if (test_bit(STATUS_TPOWER_PMI, &trans->status)) {
reg = iwl_read32(trans, CSR_UCODE_DRV_GP1);

if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
@@ -222,7 +219,7 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
* stopped, we cannot access the HW (in particular not prph).
* So don't try to restock if the APM has been already stopped.
*/
- if (!test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status))
+ if (!test_bit(STATUS_DEVICE_ENABLED, &trans->status))
return;

spin_lock_irqsave(&rxq->lock, flags);
@@ -791,7 +788,7 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans)
APMS_CLK_VAL_MRB_FUNC_MODE) ||
(iwl_read_prph(trans, APMG_PS_CTRL_REG) &
APMG_PS_CTRL_VAL_RESET_REQ))) {
- clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
+ clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
iwl_op_mode_wimax_active(trans->op_mode);
wake_up(&trans_pcie->wait_command_queue);
return;
@@ -801,8 +798,8 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans)
iwl_dump_fh(trans, NULL);

/* set the ERROR bit before we wake up the caller */
- set_bit(STATUS_FW_ERROR, &trans_pcie->status);
- clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
+ set_bit(STATUS_FW_ERROR, &trans->status);
+ clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
wake_up(&trans_pcie->wait_command_queue);

local_bh_disable();
@@ -894,14 +891,14 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)

iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
if (hw_rfkill) {
- set_bit(STATUS_RFKILL, &trans_pcie->status);
- if (test_and_clear_bit(STATUS_HCMD_ACTIVE,
- &trans_pcie->status))
+ set_bit(STATUS_RFKILL, &trans->status);
+ if (test_and_clear_bit(STATUS_SYNC_HCMD_ACTIVE,
+ &trans->status))
IWL_DEBUG_RF_KILL(trans,
"Rfkill while SYNC HCMD in flight\n");
wake_up(&trans_pcie->wait_command_queue);
} else {
- clear_bit(STATUS_RFKILL, &trans_pcie->status);
+ clear_bit(STATUS_RFKILL, &trans->status);
}

handled |= CSR_INT_BIT_RF_KILL;
@@ -1005,7 +1002,7 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)

/* Re-enable all interrupts */
/* only Re-enable if disabled by irq */
- if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status))
+ if (test_bit(STATUS_INT_ENABLED, &trans->status))
iwl_enable_interrupts(trans);
/* Re-enable RF_KILL if it occurred */
else if (handled & CSR_INT_BIT_RF_KILL)
@@ -1160,7 +1157,7 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data)
* the handler can be scheduled because of a previous
* interrupt.
*/
- if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
+ if (test_bit(STATUS_INT_ENABLED, &trans->status) &&
!trans_pcie->inta)
iwl_enable_interrupts(trans);
return IRQ_NONE;
@@ -1290,7 +1287,7 @@ irqreturn_t iwl_pcie_isr_ict(int irq, void *data)
/* re-enable interrupts here since we don't have anything to service.
* only Re-enable if disabled by irq.
*/
- if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
+ if (test_bit(STATUS_INT_ENABLED, &trans->status) &&
!trans_pcie->inta)
iwl_enable_interrupts(trans);

diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index 43eed4d..28c62a5 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -150,7 +150,6 @@ static void iwl_pcie_apm_config(struct iwl_trans *trans)
*/
static int iwl_pcie_apm_init(struct iwl_trans *trans)
{
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
int ret = 0;
IWL_DEBUG_INFO(trans, "Init card's basic functions\n");

@@ -223,7 +222,7 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans)
/* Clear the interrupt in APMG if the NIC is in RFKILL */
iwl_write_prph(trans, APMG_RTC_INT_STT_REG, APMG_RTC_INT_STT_RFKILL);

- set_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status);
+ set_bit(STATUS_DEVICE_ENABLED, &trans->status);

out:
return ret;
@@ -249,10 +248,9 @@ static int iwl_pcie_apm_stop_master(struct iwl_trans *trans)

static void iwl_pcie_apm_stop(struct iwl_trans *trans)
{
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
IWL_DEBUG_INFO(trans, "Stop card, put in low power state\n");

- clear_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status);
+ clear_bit(STATUS_DEVICE_ENABLED, &trans->status);

/* Stop device's DMA activity */
iwl_pcie_apm_stop_master(trans);
@@ -582,7 +580,6 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
const struct fw_img *fw, bool run_in_rfkill)
{
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
int ret;
bool hw_rfkill;

@@ -592,16 +589,16 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
return -EIO;
}

- clear_bit(STATUS_FW_ERROR, &trans_pcie->status);
+ clear_bit(STATUS_FW_ERROR, &trans->status);

iwl_enable_rfkill_int(trans);

/* If platform's RF_KILL switch is NOT set to KILL */
hw_rfkill = iwl_is_rfkill_set(trans);
if (hw_rfkill)
- set_bit(STATUS_RFKILL, &trans_pcie->status);
+ set_bit(STATUS_RFKILL, &trans->status);
else
- clear_bit(STATUS_RFKILL, &trans_pcie->status);
+ clear_bit(STATUS_RFKILL, &trans->status);
iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
if (hw_rfkill && !run_in_rfkill)
return -ERFKILL;
@@ -658,7 +655,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
* restart. So don't process again if the device is
* already dead.
*/
- if (test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status)) {
+ if (test_bit(STATUS_DEVICE_ENABLED, &trans->status)) {
iwl_pcie_tx_stop(trans);
iwl_pcie_rx_stop(trans);

@@ -686,11 +683,11 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);

/* clear all status bits */
- clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
- clear_bit(STATUS_INT_ENABLED, &trans_pcie->status);
- clear_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status);
- clear_bit(STATUS_TPOWER_PMI, &trans_pcie->status);
- clear_bit(STATUS_RFKILL, &trans_pcie->status);
+ clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
+ clear_bit(STATUS_INT_ENABLED, &trans->status);
+ clear_bit(STATUS_DEVICE_ENABLED, &trans->status);
+ clear_bit(STATUS_TPOWER_PMI, &trans->status);
+ clear_bit(STATUS_RFKILL, &trans->status);

/*
* Even if we stop the HW, we still want the RF kill
@@ -706,9 +703,9 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
*/
hw_rfkill = iwl_is_rfkill_set(trans);
if (hw_rfkill)
- set_bit(STATUS_RFKILL, &trans_pcie->status);
+ set_bit(STATUS_RFKILL, &trans->status);
else
- clear_bit(STATUS_RFKILL, &trans_pcie->status);
+ clear_bit(STATUS_RFKILL, &trans->status);
iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
}

@@ -794,7 +791,6 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,

static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
{
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
bool hw_rfkill;
int err;

@@ -816,9 +812,9 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)

hw_rfkill = iwl_is_rfkill_set(trans);
if (hw_rfkill)
- set_bit(STATUS_RFKILL, &trans_pcie->status);
+ set_bit(STATUS_RFKILL, &trans->status);
else
- clear_bit(STATUS_RFKILL, &trans_pcie->status);
+ clear_bit(STATUS_RFKILL, &trans->status);
iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);

return 0;
@@ -924,12 +920,10 @@ void iwl_trans_pcie_free(struct iwl_trans *trans)

static void iwl_trans_pcie_set_pmi(struct iwl_trans *trans, bool state)
{
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
if (state)
- set_bit(STATUS_TPOWER_PMI, &trans_pcie->status);
+ set_bit(STATUS_TPOWER_PMI, &trans->status);
else
- clear_bit(STATUS_TPOWER_PMI, &trans_pcie->status);
+ clear_bit(STATUS_TPOWER_PMI, &trans->status);
}

static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent,
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c
index a4ef5cc..a36884e 100644
--- a/drivers/net/wireless/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/tx.c
@@ -300,10 +300,8 @@ void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_txq *txq)
iwl_write32(trans, HBUS_TARG_WRPTR,
txq->q.write_ptr | (txq_id << 8));
} else {
- struct iwl_trans_pcie *trans_pcie =
- IWL_TRANS_GET_PCIE_TRANS(trans);
/* if we're trying to save power */
- if (test_bit(STATUS_TPOWER_PMI, &trans_pcie->status)) {
+ if (test_bit(STATUS_TPOWER_PMI, &trans->status)) {
/* wake up nic if it's powered down ...
* uCode will wake up, and interrupt us again, so next
* time we'll skip this part. */
@@ -1449,12 +1447,12 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
iwl_pcie_cmdq_reclaim(trans, txq_id, index);

if (!(meta->flags & CMD_ASYNC)) {
- if (!test_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status)) {
+ if (!test_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status)) {
IWL_WARN(trans,
"HCMD_ACTIVE already clear for command %s\n",
get_cmd_string(trans_pcie, cmd->hdr.cmd));
}
- clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
+ clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n",
get_cmd_string(trans_pcie, cmd->hdr.cmd));
wake_up(&trans_pcie->wait_command_queue);
@@ -1499,8 +1497,8 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
IWL_DEBUG_INFO(trans, "Attempting to send sync command %s\n",
get_cmd_string(trans_pcie, cmd->id));

- if (WARN(test_and_set_bit(STATUS_HCMD_ACTIVE,
- &trans_pcie->status),
+ if (WARN(test_and_set_bit(STATUS_SYNC_HCMD_ACTIVE,
+ &trans->status),
"Command %s: a command is already active!\n",
get_cmd_string(trans_pcie, cmd->id)))
return -EIO;
@@ -1511,7 +1509,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
cmd_idx = iwl_pcie_enqueue_hcmd(trans, cmd);
if (cmd_idx < 0) {
ret = cmd_idx;
- clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
+ clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
IWL_ERR(trans,
"Error sending %s: enqueue_hcmd failed: %d\n",
get_cmd_string(trans_pcie, cmd->id), ret);
@@ -1523,8 +1521,8 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,

timeout -= COMMAND_POKE_TIMEOUT;
ret = wait_event_timeout(trans_pcie->wait_command_queue,
- !test_bit(STATUS_HCMD_ACTIVE,
- &trans_pcie->status),
+ !test_bit(STATUS_SYNC_HCMD_ACTIVE,
+ &trans->status),
COMMAND_POKE_TIMEOUT);
if (ret)
break;
@@ -1552,7 +1550,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
IWL_ERR(trans, "Current CMD queue read_ptr %d write_ptr %d\n",
q->read_ptr, q->write_ptr);

- clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
+ clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n",
get_cmd_string(trans_pcie, cmd->id));
ret = -ETIMEDOUT;
@@ -1562,7 +1560,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
goto cancel;
}

- if (test_bit(STATUS_FW_ERROR, &trans_pcie->status)) {
+ if (test_bit(STATUS_FW_ERROR, &trans->status)) {
IWL_ERR(trans, "FW error in SYNC CMD %s\n",
get_cmd_string(trans_pcie, cmd->id));
dump_stack();
@@ -1571,7 +1569,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
}

if (!(cmd->flags & CMD_SEND_IN_RFKILL) &&
- test_bit(STATUS_RFKILL, &trans_pcie->status)) {
+ test_bit(STATUS_RFKILL, &trans->status)) {
IWL_DEBUG_RF_KILL(trans, "RFKILL in SYNC CMD... no rsp\n");
ret = -ERFKILL;
goto cancel;
@@ -1608,13 +1606,11 @@ cancel:

int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
{
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
- if (test_bit(STATUS_FW_ERROR, &trans_pcie->status))
+ if (test_bit(STATUS_FW_ERROR, &trans->status))
return -EIO;

if (!(cmd->flags & CMD_SEND_IN_RFKILL) &&
- test_bit(STATUS_RFKILL, &trans_pcie->status)) {
+ test_bit(STATUS_RFKILL, &trans->status)) {
IWL_DEBUG_RF_KILL(trans, "Dropping CMD 0x%x: RF KILL\n",
cmd->id);
return -ERFKILL;
--
1.7.9.5


2013-12-17 20:44:54

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 06/36] iwlwifi: publish Tx STBC support in VHT

From: Eyal Shapira <[email protected]>

If the device is MIMO and VHT capable it supports Tx STBC.
Unlike HT, any chip that supports VHT also support STBC so
no need for a config parameter.
Using num_of_ants multiple times warranted caching it.

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

diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
index e366f12..ebf629b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
@@ -263,7 +263,8 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
struct iwl_nvm_data *data,
struct ieee80211_sta_vht_cap *vht_cap)
{
- int bf_sts_cap = num_of_ant(data->valid_rx_ant) - 1;
+ int num_ants = num_of_ant(data->valid_rx_ant);
+ int bf_sts_cap = num_ants - 1;

vht_cap->vht_supported = true;

@@ -273,6 +274,9 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
bf_sts_cap << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT |
7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;

+ if (num_ants > 1)
+ vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
+
if (iwlwifi_mod_params.amsdu_size_8K)
vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991;

@@ -286,7 +290,7 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 |
IEEE80211_VHT_MCS_NOT_SUPPORTED << 14);

- if (num_of_ant(data->valid_rx_ant) == 1 ||
+ if (num_ants == 1 ||
cfg->rx_with_siso_diversity) {
vht_cap->cap |= IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN;
--
1.7.9.5


2013-12-17 20:45:33

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 34/36] iwlwifi: mvm: set highest rate in VHT MCS Set

From: Eyal Shapira <[email protected]>

Set the Tx/Rx highest long GI rates in the VHT Supported MCS Set
field according to the chip capabilties.

Signed-off-by: Eyal Shapira <[email protected]>
Reviewed-by: Johannes Berg <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
index ebf629b..a48decc 100644
--- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
@@ -290,6 +290,9 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 |
IEEE80211_VHT_MCS_NOT_SUPPORTED << 14);

+ /* Max rate for Long GI NSS=2 80Mhz is 780Mbps */
+ vht_cap->vht_mcs.rx_highest = cpu_to_le16(780);
+
if (num_ants == 1 ||
cfg->rx_with_siso_diversity) {
vht_cap->cap |= IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
@@ -297,9 +300,12 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
/* this works because NOT_SUPPORTED == 3 */
vht_cap->vht_mcs.rx_mcs_map |=
cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << 2);
+ /* Max rate for Long GI NSS=1 80Mhz is 390Mbps */
+ vht_cap->vht_mcs.rx_highest = cpu_to_le16(390);
}

vht_cap->vht_mcs.tx_mcs_map = vht_cap->vht_mcs.rx_mcs_map;
+ vht_cap->vht_mcs.tx_highest = vht_cap->vht_mcs.rx_highest;
}

static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
--
1.7.9.5


2013-12-17 20:45:05

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 14/36] iwlwifi: mvm: configure phy_ctxt with min_def

From: Eliad Peller <[email protected]>

Configure the phy context to the minimum required
bandwidth, given by ctx->min_def.

Tuning to a narrower bandwidth should reduce the
noise level and consume less power.

Signed-off-by: Eliad Peller <[email protected]>
Reviewed-by: Johannes Berg <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/mac80211.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 01b58fc..fbd3114 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -1608,7 +1608,7 @@ static int iwl_mvm_add_chanctx(struct ieee80211_hw *hw,
goto out;
}

- ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->def,
+ ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->min_def,
ctx->rx_chains_static,
ctx->rx_chains_dynamic);
if (ret) {
@@ -1652,7 +1652,7 @@ static void iwl_mvm_change_chanctx(struct ieee80211_hw *hw,
return;

mutex_lock(&mvm->mutex);
- iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->def,
+ iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->min_def,
ctx->rx_chains_static,
ctx->rx_chains_dynamic);
iwl_mvm_bt_coex_vif_change(mvm);
--
1.7.9.5


2013-12-17 20:45:07

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 15/36] iwlwifi: mvm: clarify smps_requests documentation

From: Johannes Berg <[email protected]>

The documentation for smps_requests is unclear, rewrite it.

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/mvm.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index 4275720..84edf36 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -273,8 +273,8 @@ struct iwl_mvm_vif_bf_data {
* @bcast_sta: station used for broadcast packets. Used by the following
* vifs: P2P_DEVICE, GO and AP.
* @beacon_skb: the skb used to hold the AP/GO beacon template
- * @smps_requests: the requests of of differents parts of the driver, regard
- the desired smps mode.
+ * @smps_requests: the SMPS requests of differents parts of the driver,
+ * combined on update to yield the overall request to mac80211.
*/
struct iwl_mvm_vif {
u16 id;
--
1.7.9.5


2013-12-17 20:45:27

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 29/36] iwlwifi: mvm: rs: remove unnecessary debug logs

From: Eyal Shapira <[email protected]>

The logs are emitted in a flow in which there were retries
and the rates in the rate table entry didn't match the active
or search table. This doesn't indicate a problem and is
expected in most cases where there will be retries for some
reason. Remove the logs.

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

diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index bc86032..6d0bd45 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -1116,14 +1116,9 @@ 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 {
- 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:");
+ else
continue;
- }
+
rs_collect_tx_data(tmp_tbl, rate.index, 1,
i < retries ? 0 : legacy_success);
}
--
1.7.9.5


2013-12-17 20:44:56

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 07/36] iwlwifi: mvm: Add uAPSD misbehaving AP notification handling

From: Alexander Bondar <[email protected]>

FW implements protective algorithm to identify AP's improper uAPSD
behavior. FW sends misbehaving AP notification in this case.
Add this notification handling. Avoid using uAPSD in next association
to the exactly same AP. Refactor iwl_mvm_power_build_cmd() to move
uAPSD related code to a separate function.

Signed-off-by: Alexander Bondar <[email protected]>
Reviewed-by: Johannes Berg <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/fw-api-power.h | 16 ++
drivers/net/wireless/iwlwifi/mvm/fw-api.h | 1 +
drivers/net/wireless/iwlwifi/mvm/mac80211.c | 1 +
drivers/net/wireless/iwlwifi/mvm/mvm.h | 10 +
drivers/net/wireless/iwlwifi/mvm/ops.c | 3 +
drivers/net/wireless/iwlwifi/mvm/power.c | 318 +++++++++++++----------
6 files changed, 209 insertions(+), 140 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
index 5cb93ae..cb78e55 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
@@ -85,6 +85,8 @@
* PBW Snoozing enabled
* @POWER_FLAGS_ADVANCE_PM_ENA_MSK: Advanced PM (uAPSD) enable mask
* @POWER_FLAGS_LPRX_ENA_MSK: Low Power RX enable.
+ * @POWER_FLAGS_AP_UAPSD_MISBEHAVING_ENA_MSK: AP/GO's uAPSD misbehaving
+ * detection enablement
*/
enum iwl_power_flags {
POWER_FLAGS_POWER_SAVE_ENA_MSK = BIT(0),
@@ -94,6 +96,7 @@ enum iwl_power_flags {
POWER_FLAGS_BT_SCO_ENA = BIT(8),
POWER_FLAGS_ADVANCE_PM_ENA_MSK = BIT(9),
POWER_FLAGS_LPRX_ENA_MSK = BIT(11),
+ POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK = BIT(12),
};

#define IWL_POWER_VEC_SIZE 5
@@ -228,6 +231,19 @@ struct iwl_mac_power_cmd {
u8 reserved;
} __packed;

+/*
+ * struct iwl_uapsd_misbehaving_ap_notif - FW sends this notification when
+ * associated AP is identified as improperly implementing uAPSD protocol.
+ * PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION = 0x78
+ * @sta_id: index of station in uCode's station table - associated AP ID in
+ * this context.
+ */
+struct iwl_uapsd_misbehaving_ap_notif {
+ __le32 sta_id;
+ u8 mac_id;
+ u8 reserved[3];
+} __packed;
+
/**
* struct iwl_beacon_filter_cmd
* REPLY_BEACON_FILTERING_CMD = 0xd2 (command)
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
index c9cfaad..d0b9399 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
@@ -141,6 +141,7 @@ enum {

/* Power - legacy power table command */
POWER_TABLE_CMD = 0x77,
+ PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION = 0x78,

/* Thermal Throttling*/
REPLY_THERMAL_MNG_BACKOFF = 0x7e,
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 8a99ecc..8d80728 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -858,6 +858,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
}

iwl_mvm_sf_update(mvm, vif, false);
+ iwl_mvm_power_vif_assoc(mvm, vif);
} else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
/*
* If update fails - SF might be running in associated
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index bd072c7..5da5e2d 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -181,6 +181,7 @@ enum iwl_dbgfs_pm_mask {
MVM_DEBUGFS_PM_LPRX_ENA = BIT(6),
MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD = BIT(7),
MVM_DEBUGFS_PM_SNOOZE_ENABLE = BIT(8),
+ MVM_DEBUGFS_PM_UAPSD_MISBEHAVING = BIT(9),
};

struct iwl_dbgfs_pm {
@@ -193,6 +194,7 @@ struct iwl_dbgfs_pm {
bool lprx_ena;
u32 lprx_rssi_threshold;
bool snooze_ena;
+ bool uapsd_misbehaving;
int mask;
};

@@ -331,6 +333,9 @@ struct iwl_mvm_vif {
#endif

enum ieee80211_smps_mode smps_requests[NUM_IWL_MVM_SMPS_REQ];
+
+ /* FW identified misbehaving AP */
+ u8 uapsd_misbehaving_bssid[ETH_ALEN];
};

static inline struct iwl_mvm_vif *
@@ -781,6 +786,11 @@ static inline int iwl_mvm_power_update_device_mode(struct iwl_mvm *mvm)
return 0;
}

+void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
+
#ifdef CONFIG_IWLWIFI_DEBUGFS
static inline int iwl_mvm_power_dbgfs_read(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
index cae6123..2e9af9f 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -236,6 +236,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
false),

RX_HANDLER(REPLY_ERROR, iwl_mvm_rx_fw_error, false),
+ RX_HANDLER(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION,
+ iwl_mvm_power_uapsd_misbehaving_ap_notif, false),
};
#undef RX_HANDLER
#define CMD(x) [x] = #x
@@ -311,6 +313,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD(REPLY_THERMAL_MNG_BACKOFF),
CMD(MAC_PM_POWER_TABLE),
CMD(BT_COEX_CI),
+ CMD(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION),
};
#undef CMD

diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c
index 550824a..1817b2a 100644
--- a/drivers/net/wireless/iwlwifi/mvm/power.c
+++ b/drivers/net/wireless/iwlwifi/mvm/power.c
@@ -186,6 +186,92 @@ static void iwl_mvm_power_log(struct iwl_mvm *mvm,
}
}

+static void iwl_mvm_power_configure_uapsd(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct iwl_mac_power_cmd *cmd)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ enum ieee80211_ac_numbers ac;
+ bool tid_found = false;
+
+ for (ac = IEEE80211_AC_VO; ac <= IEEE80211_AC_BK; ac++) {
+ if (!mvmvif->queue_params[ac].uapsd)
+ continue;
+
+ if (mvm->cur_ucode != IWL_UCODE_WOWLAN)
+ cmd->flags |=
+ cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK);
+
+ cmd->uapsd_ac_flags |= BIT(ac);
+
+ /* QNDP TID - the highest TID with no admission control */
+ if (!tid_found && !mvmvif->queue_params[ac].acm) {
+ tid_found = true;
+ switch (ac) {
+ case IEEE80211_AC_VO:
+ cmd->qndp_tid = 6;
+ break;
+ case IEEE80211_AC_VI:
+ cmd->qndp_tid = 5;
+ break;
+ case IEEE80211_AC_BE:
+ cmd->qndp_tid = 0;
+ break;
+ case IEEE80211_AC_BK:
+ cmd->qndp_tid = 1;
+ break;
+ }
+ }
+ }
+
+ if (!(cmd->flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)))
+ return;
+
+ cmd->flags |= cpu_to_le16(POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK);
+
+ if (cmd->uapsd_ac_flags == (BIT(IEEE80211_AC_VO) |
+ BIT(IEEE80211_AC_VI) |
+ BIT(IEEE80211_AC_BE) |
+ BIT(IEEE80211_AC_BK))) {
+ cmd->flags |= cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK);
+ cmd->snooze_interval = cpu_to_le16(IWL_MVM_PS_SNOOZE_INTERVAL);
+ cmd->snooze_window = (mvm->cur_ucode == IWL_UCODE_WOWLAN) ?
+ cpu_to_le16(IWL_MVM_WOWLAN_PS_SNOOZE_WINDOW) :
+ cpu_to_le16(IWL_MVM_PS_SNOOZE_WINDOW);
+ }
+
+ cmd->uapsd_max_sp = IWL_UAPSD_MAX_SP;
+
+ if (mvm->cur_ucode == IWL_UCODE_WOWLAN || cmd->flags &
+ cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) {
+ cmd->rx_data_timeout_uapsd =
+ cpu_to_le32(IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT);
+ cmd->tx_data_timeout_uapsd =
+ cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT);
+ } else {
+ cmd->rx_data_timeout_uapsd =
+ cpu_to_le32(IWL_MVM_UAPSD_RX_DATA_TIMEOUT);
+ cmd->tx_data_timeout_uapsd =
+ cpu_to_le32(IWL_MVM_UAPSD_TX_DATA_TIMEOUT);
+ }
+
+ if (cmd->flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) {
+ cmd->heavy_tx_thld_packets =
+ IWL_MVM_PS_SNOOZE_HEAVY_TX_THLD_PACKETS;
+ cmd->heavy_rx_thld_packets =
+ IWL_MVM_PS_SNOOZE_HEAVY_RX_THLD_PACKETS;
+ } else {
+ cmd->heavy_tx_thld_packets =
+ IWL_MVM_PS_HEAVY_TX_THLD_PACKETS;
+ cmd->heavy_rx_thld_packets =
+ IWL_MVM_PS_HEAVY_RX_THLD_PACKETS;
+ }
+ cmd->heavy_tx_thld_percentage =
+ IWL_MVM_PS_HEAVY_TX_THLD_PERCENT;
+ cmd->heavy_rx_thld_percentage =
+ IWL_MVM_PS_HEAVY_RX_THLD_PERCENT;
+}
+
static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct iwl_mac_power_cmd *cmd)
@@ -198,8 +284,6 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
bool radar_detect = false;
struct iwl_mvm_vif *mvmvif __maybe_unused =
iwl_mvm_vif_from_mac80211(vif);
- enum ieee80211_ac_numbers ac;
- bool tid_found = false;

cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
mvmvif->color));
@@ -269,81 +353,9 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT);
}

- for (ac = IEEE80211_AC_VO; ac <= IEEE80211_AC_BK; ac++) {
- if (!mvmvif->queue_params[ac].uapsd)
- continue;
-
- if (mvm->cur_ucode != IWL_UCODE_WOWLAN)
- cmd->flags |=
- cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK);
-
- cmd->uapsd_ac_flags |= BIT(ac);
-
- /* QNDP TID - the highest TID with no admission control */
- if (!tid_found && !mvmvif->queue_params[ac].acm) {
- tid_found = true;
- switch (ac) {
- case IEEE80211_AC_VO:
- cmd->qndp_tid = 6;
- break;
- case IEEE80211_AC_VI:
- cmd->qndp_tid = 5;
- break;
- case IEEE80211_AC_BE:
- cmd->qndp_tid = 0;
- break;
- case IEEE80211_AC_BK:
- cmd->qndp_tid = 1;
- break;
- }
- }
- }
-
- if (cmd->flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)) {
- if (cmd->uapsd_ac_flags == (BIT(IEEE80211_AC_VO) |
- BIT(IEEE80211_AC_VI) |
- BIT(IEEE80211_AC_BE) |
- BIT(IEEE80211_AC_BK))) {
- cmd->flags |= cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK);
- cmd->snooze_interval =
- cpu_to_le16(IWL_MVM_PS_SNOOZE_INTERVAL);
- cmd->snooze_window =
- (mvm->cur_ucode == IWL_UCODE_WOWLAN) ?
- cpu_to_le16(IWL_MVM_WOWLAN_PS_SNOOZE_WINDOW) :
- cpu_to_le16(IWL_MVM_PS_SNOOZE_WINDOW);
- }
-
- cmd->uapsd_max_sp = IWL_UAPSD_MAX_SP;
-
- if (mvm->cur_ucode == IWL_UCODE_WOWLAN || cmd->flags &
- cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) {
- cmd->rx_data_timeout_uapsd =
- cpu_to_le32(IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT);
- cmd->tx_data_timeout_uapsd =
- cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT);
- } else {
- cmd->rx_data_timeout_uapsd =
- cpu_to_le32(IWL_MVM_UAPSD_RX_DATA_TIMEOUT);
- cmd->tx_data_timeout_uapsd =
- cpu_to_le32(IWL_MVM_UAPSD_TX_DATA_TIMEOUT);
- }
-
- if (cmd->flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) {
- cmd->heavy_tx_thld_packets =
- IWL_MVM_PS_SNOOZE_HEAVY_TX_THLD_PACKETS;
- cmd->heavy_rx_thld_packets =
- IWL_MVM_PS_SNOOZE_HEAVY_RX_THLD_PACKETS;
- } else {
- cmd->heavy_tx_thld_packets =
- IWL_MVM_PS_HEAVY_TX_THLD_PACKETS;
- cmd->heavy_rx_thld_packets =
- IWL_MVM_PS_HEAVY_RX_THLD_PACKETS;
- }
- cmd->heavy_tx_thld_percentage =
- IWL_MVM_PS_HEAVY_TX_THLD_PERCENT;
- cmd->heavy_rx_thld_percentage =
- IWL_MVM_PS_HEAVY_RX_THLD_PERCENT;
- }
+ if (memcmp(mvmvif->uapsd_misbehaving_bssid, vif->bss_conf.bssid,
+ ETH_ALEN))
+ iwl_mvm_power_configure_uapsd(mvm, vif, cmd);

#ifdef CONFIG_IWLWIFI_DEBUGFS
if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_KEEP_ALIVE)
@@ -472,6 +484,44 @@ static int iwl_mvm_power_update_device(struct iwl_mvm *mvm)
&cmd);
}

+void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+ if (memcmp(vif->bss_conf.bssid, mvmvif->uapsd_misbehaving_bssid,
+ ETH_ALEN))
+ memset(mvmvif->uapsd_misbehaving_bssid, 0, ETH_ALEN);
+}
+
+static void iwl_mvm_power_uapsd_misbehav_ap_iterator(void *_data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ u8 *ap_sta_id = _data;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+ /* The ap_sta_id is not expected to change during current association
+ * so no explicit protection is needed
+ */
+ if (mvmvif->ap_sta_id == *ap_sta_id)
+ memcpy(mvmvif->uapsd_misbehaving_bssid, vif->bss_conf.bssid,
+ ETH_ALEN);
+}
+
+int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd)
+{
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ struct iwl_uapsd_misbehaving_ap_notif *notif = (void *)pkt->data;
+ u8 ap_sta_id = le32_to_cpu(notif->sta_id);
+
+ ieee80211_iterate_active_interfaces_atomic(
+ mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+ iwl_mvm_power_uapsd_misbehav_ap_iterator, &ap_sta_id);
+
+ return 0;
+}
+
#ifdef CONFIG_IWLWIFI_DEBUGFS
static int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, char *buf,
@@ -494,70 +544,58 @@ static int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm,
pos += scnprintf(buf+pos, bufsz-pos, "keep_alive = %d\n",
le16_to_cpu(cmd.keep_alive_seconds));

- if (cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) {
- pos += scnprintf(buf+pos, bufsz-pos, "skip_over_dtim = %d\n",
- (cmd.flags &
- cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) ?
- 1 : 0);
- pos += scnprintf(buf+pos, bufsz-pos, "skip_dtim_periods = %d\n",
- cmd.skip_dtim_periods);
- if (!(cmd.flags &
- cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK))) {
- pos += scnprintf(buf+pos, bufsz-pos,
- "rx_data_timeout = %d\n",
- le32_to_cpu(cmd.rx_data_timeout));
- pos += scnprintf(buf+pos, bufsz-pos,
- "tx_data_timeout = %d\n",
- le32_to_cpu(cmd.tx_data_timeout));
- }
- if (cmd.flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK))
- pos += scnprintf(buf+pos, bufsz-pos,
- "lprx_rssi_threshold = %d\n",
- cmd.lprx_rssi_threshold);
- if (cmd.flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)) {
- pos +=
- scnprintf(buf+pos, bufsz-pos,
- "rx_data_timeout_uapsd = %d\n",
- le32_to_cpu(cmd.rx_data_timeout_uapsd));
- pos +=
- scnprintf(buf+pos, bufsz-pos,
- "tx_data_timeout_uapsd = %d\n",
- le32_to_cpu(cmd.tx_data_timeout_uapsd));
- pos += scnprintf(buf+pos, bufsz-pos, "qndp_tid = %d\n",
- cmd.qndp_tid);
- pos += scnprintf(buf+pos, bufsz-pos,
- "uapsd_ac_flags = 0x%x\n",
- cmd.uapsd_ac_flags);
- pos += scnprintf(buf+pos, bufsz-pos,
- "uapsd_max_sp = %d\n",
- cmd.uapsd_max_sp);
- pos += scnprintf(buf+pos, bufsz-pos,
- "heavy_tx_thld_packets = %d\n",
- cmd.heavy_tx_thld_packets);
- pos += scnprintf(buf+pos, bufsz-pos,
- "heavy_rx_thld_packets = %d\n",
- cmd.heavy_rx_thld_packets);
- pos += scnprintf(buf+pos, bufsz-pos,
- "heavy_tx_thld_percentage = %d\n",
- cmd.heavy_tx_thld_percentage);
- pos += scnprintf(buf+pos, bufsz-pos,
- "heavy_rx_thld_percentage = %d\n",
- cmd.heavy_rx_thld_percentage);
- pos +=
- scnprintf(buf+pos, bufsz-pos, "snooze_enable = %d\n",
- (cmd.flags &
- cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) ?
- 1 : 0);
- }
- if (cmd.flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) {
- pos += scnprintf(buf+pos, bufsz-pos,
- "snooze_interval = %d\n",
- cmd.snooze_interval);
- pos += scnprintf(buf+pos, bufsz-pos,
- "snooze_window = %d\n",
- cmd.snooze_window);
- }
+ if (!(cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)))
+ return pos;
+
+ pos += scnprintf(buf+pos, bufsz-pos, "skip_over_dtim = %d\n",
+ (cmd.flags &
+ cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) ? 1 : 0);
+ pos += scnprintf(buf+pos, bufsz-pos, "skip_dtim_periods = %d\n",
+ cmd.skip_dtim_periods);
+ if (!(cmd.flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK))) {
+ pos += scnprintf(buf+pos, bufsz-pos, "rx_data_timeout = %d\n",
+ le32_to_cpu(cmd.rx_data_timeout));
+ pos += scnprintf(buf+pos, bufsz-pos, "tx_data_timeout = %d\n",
+ le32_to_cpu(cmd.tx_data_timeout));
}
+ if (cmd.flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK))
+ pos += scnprintf(buf+pos, bufsz-pos,
+ "lprx_rssi_threshold = %d\n",
+ cmd.lprx_rssi_threshold);
+
+ if (!(cmd.flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)))
+ return pos;
+
+ pos += scnprintf(buf+pos, bufsz-pos, "rx_data_timeout_uapsd = %d\n",
+ le32_to_cpu(cmd.rx_data_timeout_uapsd));
+ pos += scnprintf(buf+pos, bufsz-pos, "tx_data_timeout_uapsd = %d\n",
+ le32_to_cpu(cmd.tx_data_timeout_uapsd));
+ pos += scnprintf(buf+pos, bufsz-pos, "qndp_tid = %d\n", cmd.qndp_tid);
+ pos += scnprintf(buf+pos, bufsz-pos, "uapsd_ac_flags = 0x%x\n",
+ cmd.uapsd_ac_flags);
+ pos += scnprintf(buf+pos, bufsz-pos, "uapsd_max_sp = %d\n",
+ cmd.uapsd_max_sp);
+ pos += scnprintf(buf+pos, bufsz-pos, "heavy_tx_thld_packets = %d\n",
+ cmd.heavy_tx_thld_packets);
+ pos += scnprintf(buf+pos, bufsz-pos, "heavy_rx_thld_packets = %d\n",
+ cmd.heavy_rx_thld_packets);
+ pos += scnprintf(buf+pos, bufsz-pos, "heavy_tx_thld_percentage = %d\n",
+ cmd.heavy_tx_thld_percentage);
+ pos += scnprintf(buf+pos, bufsz-pos, "heavy_rx_thld_percentage = %d\n",
+ cmd.heavy_rx_thld_percentage);
+ pos += scnprintf(buf+pos, bufsz-pos, "uapsd_misbehaving_enable = %d\n",
+ (cmd.flags &
+ cpu_to_le16(POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK)) ?
+ 1 : 0);
+
+ if (!(cmd.flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)))
+ return pos;
+
+ pos += scnprintf(buf+pos, bufsz-pos, "snooze_interval = %d\n",
+ cmd.snooze_interval);
+ pos += scnprintf(buf+pos, bufsz-pos, "snooze_window = %d\n",
+ cmd.snooze_window);
+
return pos;
}

--
1.7.9.5


2013-12-17 20:45:36

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 36/36] iwlwifi: mvm: rs: fix variable shadowing

From: Johannes Berg <[email protected]>

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

diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index 1f06450..d6d28d7 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -2718,12 +2718,10 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
lq_sta->lq.initial_rate_index[3]);

for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
- u32 rate = le32_to_cpu(lq_sta->lq.rs_table[i]);
- desc += sprintf(buff+desc,
- " rate[%d] 0x%X ",
- i, rate);
+ u32 r = le32_to_cpu(lq_sta->lq.rs_table[i]);

- desc += rs_pretty_print_rate(buff+desc, rate);
+ desc += sprintf(buff+desc, " rate[%d] 0x%X ", i, r);
+ desc += rs_pretty_print_rate(buff+desc, r);
}

ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
--
1.7.9.5


2013-12-17 20:44:57

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 08/36] iwlwifi: mvm: Change power management dependency on multi MAC

From: Alexander Bondar <[email protected]>

FW still does not support power management on multiple MAC interfaces.
Currently the driver enforce this limitation by disabling PM if second
interface is added. Change this behavior to allow PM on a single interface
even if other interfaces exist but not bound to any specific PHY.
PM will be enabled if only one single interface is bound.

Signed-off-by: Alexander Bondar <[email protected]>
Reviewed-by: Johannes Berg <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/mac80211.c | 63 +++++++--------------------
drivers/net/wireless/iwlwifi/mvm/mvm.h | 19 +++++---
drivers/net/wireless/iwlwifi/mvm/power.c | 36 ++++++++++-----
3 files changed, 53 insertions(+), 65 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 8d80728..e1c379a 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -494,17 +494,6 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
cancel_work_sync(&mvm->async_handlers_wk);
}

-static void iwl_mvm_pm_disable_iterator(void *data, u8 *mac,
- struct ieee80211_vif *vif)
-{
- struct iwl_mvm *mvm = data;
- int ret;
-
- ret = iwl_mvm_power_disable(mvm, vif);
- if (ret)
- IWL_ERR(mvm, "failed to disable power management\n");
-}
-
static void iwl_mvm_power_update_iterator(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
@@ -547,26 +536,9 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
if (ret)
goto out_unlock;

- /*
- * TODO: remove this temporary code.
- * Currently MVM FW supports power management only on single MAC.
- * If new interface added, disable PM on existing interface.
- * P2P device is a special case, since it is handled by FW similary to
- * scan. If P2P deviced is added, PM remains enabled on existing
- * interface.
- * Note: the method below does not count the new interface being added
- * at this moment.
- */
+ /* Counting number of interfaces is needed for legacy PM */
if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
mvm->vif_count++;
- if (mvm->vif_count > 1) {
- IWL_DEBUG_MAC80211(mvm,
- "Disable power on existing interfaces\n");
- ieee80211_iterate_active_interfaces_atomic(
- mvm->hw,
- IEEE80211_IFACE_ITER_NORMAL,
- iwl_mvm_pm_disable_iterator, mvm);
- }

/*
* The AP binding flow can be done only after the beacon
@@ -597,11 +569,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
if (ret)
goto out_release;

- /*
- * Update power state on the new interface. Admittedly, based on
- * mac80211 logics this power update will disable power management
- */
- iwl_mvm_power_update_mode(mvm, vif);
+ iwl_mvm_power_disable(mvm, vif);

/* beacon filtering */
ret = iwl_mvm_disable_beacon_filter(mvm, vif);
@@ -662,9 +630,12 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
out_release:
if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
mvm->vif_count--;
+
+ /* TODO: remove this when legacy PM will be discarded */
ieee80211_iterate_active_interfaces(
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
iwl_mvm_power_update_iterator, mvm);
+
iwl_mvm_mac_ctxt_release(mvm, vif);
out_unlock:
mutex_unlock(&mvm->mutex);
@@ -750,21 +721,13 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
mvmvif->phy_ctxt = NULL;
}

- /*
- * TODO: remove this temporary code.
- * Currently MVM FW supports power management only on single MAC.
- * Check if only one additional interface remains after removing
- * current one. Update power mode on the remaining interface.
- */
if (mvm->vif_count && vif->type != NL80211_IFTYPE_P2P_DEVICE)
mvm->vif_count--;
- IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n",
- mvm->vif_count);
- if (mvm->vif_count == 1) {
- ieee80211_iterate_active_interfaces(
- mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
- iwl_mvm_power_update_iterator, mvm);
- }
+
+ /* TODO: remove this when legacy PM will be discarded */
+ ieee80211_iterate_active_interfaces(
+ mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+ iwl_mvm_power_update_iterator, mvm);

iwl_mvm_mac_ctxt_remove(mvm, vif);

@@ -1658,6 +1621,9 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
goto out_remove_binding;
}

+ mvm->bound_vif_cnt++;
+ iwl_mvm_power_update_binding(mvm, vif);
+
goto out_unlock;

out_remove_binding:
@@ -1695,6 +1661,9 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw,
iwl_mvm_binding_remove_vif(mvm, vif);
out_unlock:
mvmvif->phy_ctxt = NULL;
+ mvm->bound_vif_cnt--;
+ iwl_mvm_power_update_binding(mvm, vif);
+
mutex_unlock(&mvm->mutex);
}

diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index 5da5e2d..51b0e9a 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -163,6 +163,8 @@ struct iwl_mvm_power_ops {
struct ieee80211_vif *vif);
int (*power_update_device_mode)(struct iwl_mvm *mvm);
int (*power_disable)(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+ void (*power_update_binding)(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif);
#ifdef CONFIG_IWLWIFI_DEBUGFS
int (*power_dbgfs_read)(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
char *buf, int bufsz);
@@ -336,6 +338,8 @@ struct iwl_mvm_vif {

/* FW identified misbehaving AP */
u8 uapsd_misbehaving_bssid[ETH_ALEN];
+
+ bool pm_prevented;
};

static inline struct iwl_mvm_vif *
@@ -520,12 +524,6 @@ struct iwl_mvm {
*/
unsigned long fw_key_table[BITS_TO_LONGS(STA_KEY_MAX_NUM)];

- /*
- * This counter of created interfaces is referenced only in conjunction
- * with FW limitation related to power management. Currently PM is
- * supported only on a single interface.
- * IMPORTANT: this variable counts all interfaces except P2P device.
- */
u8 vif_count;

/* -1 for always, 0 for never, >0 for that many times */
@@ -568,6 +566,8 @@ struct iwl_mvm {
u8 aux_queue;
u8 first_agg_queue;
u8 last_agg_queue;
+
+ u8 bound_vif_cnt;
};

/* Extract MVM priv from op_mode and _hw */
@@ -786,6 +786,13 @@ static inline int iwl_mvm_power_update_device_mode(struct iwl_mvm *mvm)
return 0;
}

+static inline void iwl_mvm_power_update_binding(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif)
+{
+ if (mvm->pm_ops->power_update_binding)
+ mvm->pm_ops->power_update_binding(mvm, vif);
+}
+
void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c
index 1817b2a..d5d4935 100644
--- a/drivers/net/wireless/iwlwifi/mvm/power.c
+++ b/drivers/net/wireless/iwlwifi/mvm/power.c
@@ -311,7 +311,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
mvmvif->dbgfs_pm.disable_power_off)
cmd->flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK);
#endif
- if (!vif->bss_conf.ps)
+ if (!vif->bss_conf.ps || mvmvif->pm_prevented)
return;

cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK);
@@ -406,17 +406,6 @@ static int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm,
if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
return 0;

- /*
- * TODO: The following vif_count verification is temporary condition.
- * Avoid power mode update if more than one interface is currently
- * active. Remove this condition when FW will support power management
- * on multiple MACs.
- */
- IWL_DEBUG_POWER(mvm, "Currently %d interfaces active\n",
- mvm->vif_count);
- if (mvm->vif_count > 1)
- return 0;
-
iwl_mvm_power_build_cmd(mvm, vif, &cmd);
iwl_mvm_power_log(mvm, &cmd);

@@ -522,6 +511,28 @@ int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm,
return 0;
}

+static void iwl_mvm_power_binding_iterator(void *_data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm *mvm = _data;
+ int ret;
+
+ mvmvif->pm_prevented = (mvm->bound_vif_cnt <= 1) ? false : true;
+
+ ret = iwl_mvm_power_mac_update_mode(mvm, vif);
+ WARN_ONCE(ret, "Failed to update power parameters on a specific vif\n");
+}
+
+static void _iwl_mvm_power_update_binding(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif)
+{
+ ieee80211_iterate_active_interfaces(mvm->hw,
+ IEEE80211_IFACE_ITER_NORMAL,
+ iwl_mvm_power_binding_iterator,
+ mvm);
+}
+
#ifdef CONFIG_IWLWIFI_DEBUGFS
static int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, char *buf,
@@ -692,6 +703,7 @@ const struct iwl_mvm_power_ops pm_mac_ops = {
.power_update_mode = iwl_mvm_power_mac_update_mode,
.power_update_device_mode = iwl_mvm_power_update_device,
.power_disable = iwl_mvm_power_mac_disable,
+ .power_update_binding = _iwl_mvm_power_update_binding,
#ifdef CONFIG_IWLWIFI_DEBUGFS
.power_dbgfs_read = iwl_mvm_power_mac_dbgfs_read,
#endif
--
1.7.9.5


2013-12-17 20:44:49

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 02/36] iwlwifi: mvm: Add Smart FIFO support

From: Lilach Edelstein <[email protected]>

Send firmware a Smart FIFO Configuration host command to allow
interrupt coalescing. The smart FIFO is enabled when there is
only one bound interface (other than p2p devices which are
ignored) and it is of type station, and activated while the
station is associated.

Smart Fifo allows aggragations of DMA transactions and by that
causes processor and memory controller to stay for a longer time
on lower c-states, thus saving platform power.
Firmware relies on driver to activate and disable it.

Signed-off-by: Lilach Edelstein <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/Makefile | 2 +-
drivers/net/wireless/iwlwifi/mvm/binding.c | 16 +-
drivers/net/wireless/iwlwifi/mvm/fw-api.h | 62 ++++++
drivers/net/wireless/iwlwifi/mvm/fw.c | 4 +
drivers/net/wireless/iwlwifi/mvm/mac80211.c | 21 ++
drivers/net/wireless/iwlwifi/mvm/mvm.h | 7 +
drivers/net/wireless/iwlwifi/mvm/ops.c | 1 +
drivers/net/wireless/iwlwifi/mvm/sf.c | 291 +++++++++++++++++++++++++++
8 files changed, 402 insertions(+), 2 deletions(-)
create mode 100644 drivers/net/wireless/iwlwifi/mvm/sf.c

diff --git a/drivers/net/wireless/iwlwifi/mvm/Makefile b/drivers/net/wireless/iwlwifi/mvm/Makefile
index 285d8c7..3ea47ab 100644
--- a/drivers/net/wireless/iwlwifi/mvm/Makefile
+++ b/drivers/net/wireless/iwlwifi/mvm/Makefile
@@ -1,6 +1,6 @@
obj-$(CONFIG_IWLMVM) += iwlmvm.o
iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o
-iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o
+iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o sf.o
iwlmvm-y += scan.o time-event.o rs.o
iwlmvm-y += power.o power_legacy.o bt-coex.o
iwlmvm-y += led.o tt.o
diff --git a/drivers/net/wireless/iwlwifi/mvm/binding.c b/drivers/net/wireless/iwlwifi/mvm/binding.c
index 93fd145..57d3eed 100644
--- a/drivers/net/wireless/iwlwifi/mvm/binding.c
+++ b/drivers/net/wireless/iwlwifi/mvm/binding.c
@@ -183,15 +183,29 @@ int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
if (WARN_ON_ONCE(!mvmvif->phy_ctxt))
return -EINVAL;

+ /*
+ * Update SF - Disable if needed. if this fails, SF might still be on
+ * while many macs are bound, which is forbidden - so fail the binding.
+ */
+ if (iwl_mvm_sf_update(mvm, vif, false))
+ return -EINVAL;
+
return iwl_mvm_binding_update(mvm, vif, mvmvif->phy_ctxt, true);
}

int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ int ret;

if (WARN_ON_ONCE(!mvmvif->phy_ctxt))
return -EINVAL;

- return iwl_mvm_binding_update(mvm, vif, mvmvif->phy_ctxt, false);
+ ret = iwl_mvm_binding_update(mvm, vif, mvmvif->phy_ctxt, false);
+
+ if (!ret)
+ if (iwl_mvm_sf_update(mvm, vif, true))
+ IWL_ERR(mvm, "Failed to update SF state\n");
+
+ return ret;
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
index bad5a55..3af4133 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
@@ -183,6 +183,7 @@ enum {
BT_PROFILE_NOTIFICATION = 0xce,
BT_COEX_CI = 0x5d,

+ REPLY_SF_CFG_CMD = 0xd1,
REPLY_BEACON_FILTERING_CMD = 0xd2,

REPLY_DEBUG_CMD = 0xf0,
@@ -1363,4 +1364,65 @@ struct iwl_notif_statistics { /* STATISTICS_NTFY_API_S_VER_8 */
struct mvm_statistics_general general;
} __packed;

+/***********************************
+ * Smart Fifo API
+ ***********************************/
+/* Smart Fifo state */
+enum iwl_sf_state {
+ SF_LONG_DELAY_ON = 0, /* should never be called by driver */
+ SF_FULL_ON,
+ SF_UNINIT,
+ SF_INIT_OFF,
+ SF_HW_NUM_STATES
+};
+
+/* Smart Fifo possible scenario */
+enum iwl_sf_scenario {
+ SF_SCENARIO_SINGLE_UNICAST,
+ SF_SCENARIO_AGG_UNICAST,
+ SF_SCENARIO_MULTICAST,
+ SF_SCENARIO_BA_RESP,
+ SF_SCENARIO_TX_RESP,
+ SF_NUM_SCENARIO
+};
+
+#define SF_TRANSIENT_STATES_NUMBER 2 /* SF_LONG_DELAY_ON and SF_FULL_ON */
+#define SF_NUM_TIMEOUT_TYPES 2 /* Aging timer and Idle timer */
+
+/* smart FIFO default values */
+#define SF_W_MARK_SISO 4096
+#define SF_W_MARK_MIMO2 8192
+#define SF_W_MARK_MIMO3 6144
+#define SF_W_MARK_LEGACY 4096
+#define SF_W_MARK_SCAN 4096
+
+/* SF Scenarios timers for FULL_ON state (aligned to 32 uSec) */
+#define SF_SINGLE_UNICAST_IDLE_TIMER 320 /* 300 uSec */
+#define SF_SINGLE_UNICAST_AGING_TIMER 2016 /* 2 mSec */
+#define SF_AGG_UNICAST_IDLE_TIMER 320 /* 300 uSec */
+#define SF_AGG_UNICAST_AGING_TIMER 2016 /* 2 mSec */
+#define SF_MCAST_IDLE_TIMER 2016 /* 2 mSec */
+#define SF_MCAST_AGING_TIMER 10016 /* 10 mSec */
+#define SF_BA_IDLE_TIMER 320 /* 300 uSec */
+#define SF_BA_AGING_TIMER 2016 /* 2 mSec */
+#define SF_TX_RE_IDLE_TIMER 320 /* 300 uSec */
+#define SF_TX_RE_AGING_TIMER 2016 /* 2 mSec */
+
+#define SF_LONG_DELAY_AGING_TIMER 1000000 /* 1 Sec */
+
+/**
+ * Smart Fifo configuration command.
+ * @state: smart fifo state, types listed in iwl_sf_sate.
+ * @watermark: Minimum allowed availabe free space in RXF for transient state.
+ * @long_delay_timeouts: aging and idle timer values for each scenario
+ * in long delay state.
+ * @full_on_timeouts: timer values for each scenario in full on state.
+ */
+struct iwl_sf_cfg_cmd {
+ enum iwl_sf_state state;
+ __le32 watermark[SF_TRANSIENT_STATES_NUMBER];
+ __le32 long_delay_timeouts[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES];
+ __le32 full_on_timeouts[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES];
+} __packed; /* SF_CFG_API_S_VER_2 */
+
#endif /* __fw_api_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c
index 70e5297..b2bfa73 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/iwlwifi/mvm/fw.c
@@ -386,6 +386,10 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
goto error;
}

+ ret = iwl_mvm_sf_update(mvm, NULL, false);
+ if (ret)
+ IWL_ERR(mvm, "Failed to initialize Smart Fifo\n");
+
ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw));
if (ret)
goto error;
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index afc4419..f0f8b2c 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -850,7 +850,16 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
iwl_mvm_protect_session(mvm, vif, dur, dur,
5 * dur);
}
+
+ iwl_mvm_sf_update(mvm, vif, false);
} else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
+ /*
+ * If update fails - SF might be running in associated
+ * mode while disassociated - which is forbidden.
+ */
+ WARN_ONCE(iwl_mvm_sf_update(mvm, vif, false),
+ "Failed to update SF upon disassociation\n");
+
/* remove AP station now that the MAC is unassoc */
ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id);
if (ret)
@@ -1200,6 +1209,17 @@ static int iwl_mvm_mac_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
return 0;
}

+static void iwl_mvm_sta_rc_update(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, u32 changed)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+ if (vif->type == NL80211_IFTYPE_STATION &&
+ changed & IEEE80211_RC_NSS_CHANGED)
+ iwl_mvm_sf_update(mvm, vif, false);
+}
+
static int iwl_mvm_mac_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 ac,
const struct ieee80211_tx_queue_params *params)
@@ -1765,6 +1785,7 @@ struct ieee80211_ops iwl_mvm_hw_ops = {
.sta_notify = iwl_mvm_mac_sta_notify,
.allow_buffered_frames = iwl_mvm_mac_allow_buffered_frames,
.set_rts_threshold = iwl_mvm_mac_set_rts_threshold,
+ .sta_rc_update = iwl_mvm_sta_rc_update,
.conf_tx = iwl_mvm_mac_conf_tx,
.mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx,
.sched_scan_start = iwl_mvm_mac_sched_scan_start,
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index 7dc57cf..bd072c7 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -489,6 +489,9 @@ struct iwl_mvm {
u8 scan_last_antenna_idx; /* to toggle TX between antennas */
u8 mgmt_last_antenna_idx;

+ /* last smart fifo state that was successfully sent to firmware */
+ enum iwl_sf_state sf_state;
+
#ifdef CONFIG_IWLWIFI_DEBUGFS
struct dentry *debugfs_dir;
u32 dbgfs_sram_offset, dbgfs_sram_len;
@@ -869,4 +872,8 @@ void iwl_mvm_tt_initialize(struct iwl_mvm *mvm);
void iwl_mvm_tt_exit(struct iwl_mvm *mvm);
void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state);

+/* smart fifo */
+int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ bool added_vif);
+
#endif /* __IWL_MVM_H__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
index d86083c..cae6123 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -359,6 +359,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
mvm->aux_queue = 11;
mvm->first_agg_queue = 12;
}
+ mvm->sf_state = SF_UNINIT;

mutex_init(&mvm->mutex);
spin_lock_init(&mvm->async_handlers_lock);
diff --git a/drivers/net/wireless/iwlwifi/mvm/sf.c b/drivers/net/wireless/iwlwifi/mvm/sf.c
new file mode 100644
index 0000000..97bb3c3
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/sf.c
@@ -0,0 +1,291 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called COPYING.
+ *
+ * Contact Information:
+ * Intel Linux Wireless <[email protected]>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+#include "mvm.h"
+
+/* For counting bound interfaces */
+struct iwl_mvm_active_iface_iterator_data {
+ struct ieee80211_vif *ignore_vif;
+ u8 sta_vif_ap_sta_id;
+ enum iwl_sf_state sta_vif_state;
+ int num_active_macs;
+};
+
+/*
+ * Count bound interfaces which are not p2p, besides data->ignore_vif.
+ * data->station_vif will point to one bound vif of type station, if exists.
+ */
+static void iwl_mvm_bound_iface_iterator(void *_data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_mvm_active_iface_iterator_data *data = _data;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+ if (vif == data->ignore_vif || !mvmvif->phy_ctxt ||
+ vif->type == NL80211_IFTYPE_P2P_DEVICE)
+ return;
+
+ data->num_active_macs++;
+
+ if (vif->type == NL80211_IFTYPE_STATION) {
+ data->sta_vif_ap_sta_id = mvmvif->ap_sta_id;
+ if (vif->bss_conf.assoc)
+ data->sta_vif_state = SF_FULL_ON;
+ else
+ data->sta_vif_state = SF_INIT_OFF;
+ }
+}
+
+/*
+ * Aging and idle timeouts for the different possible scenarios
+ * in SF_FULL_ON state.
+ */
+static const __le32 sf_full_timeout[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES] = {
+ {
+ cpu_to_le32(SF_SINGLE_UNICAST_AGING_TIMER),
+ cpu_to_le32(SF_SINGLE_UNICAST_IDLE_TIMER)
+ },
+ {
+ cpu_to_le32(SF_AGG_UNICAST_AGING_TIMER),
+ cpu_to_le32(SF_AGG_UNICAST_IDLE_TIMER)
+ },
+ {
+ cpu_to_le32(SF_MCAST_AGING_TIMER),
+ cpu_to_le32(SF_MCAST_IDLE_TIMER)
+ },
+ {
+ cpu_to_le32(SF_BA_AGING_TIMER),
+ cpu_to_le32(SF_BA_IDLE_TIMER)
+ },
+ {
+ cpu_to_le32(SF_TX_RE_AGING_TIMER),
+ cpu_to_le32(SF_TX_RE_IDLE_TIMER)
+ },
+};
+
+static void iwl_mvm_fill_sf_command(struct iwl_sf_cfg_cmd *sf_cmd,
+ struct ieee80211_sta *sta)
+{
+ int i, j, watermark;
+
+ sf_cmd->watermark[SF_LONG_DELAY_ON] = cpu_to_le32(SF_W_MARK_SCAN);
+
+ /*
+ * If we are in association flow - check antenna configuration
+ * capabilities of the AP station, and choose the watermark accordingly.
+ */
+ if (sta) {
+ if (sta->ht_cap.ht_supported || sta->vht_cap.vht_supported) {
+ switch (sta->rx_nss) {
+ case 1:
+ watermark = SF_W_MARK_SISO;
+ break;
+ case 2:
+ watermark = SF_W_MARK_MIMO2;
+ break;
+ default:
+ watermark = SF_W_MARK_MIMO3;
+ break;
+ }
+ } else {
+ watermark = SF_W_MARK_LEGACY;
+ }
+ /* default watermark value for unassociated mode. */
+ } else {
+ watermark = SF_W_MARK_MIMO2;
+ }
+ sf_cmd->watermark[SF_FULL_ON] = cpu_to_le32(watermark);
+
+ for (i = 0; i < SF_NUM_SCENARIO; i++) {
+ for (j = 0; j < SF_NUM_TIMEOUT_TYPES; j++) {
+ sf_cmd->long_delay_timeouts[i][j] =
+ cpu_to_le32(SF_LONG_DELAY_AGING_TIMER);
+ }
+ }
+ BUILD_BUG_ON(sizeof(sf_full_timeout) !=
+ sizeof(__le32) * SF_NUM_SCENARIO * SF_NUM_TIMEOUT_TYPES);
+
+ memcpy(sf_cmd->full_on_timeouts, sf_full_timeout,
+ sizeof(sf_full_timeout));
+}
+
+static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id,
+ enum iwl_sf_state new_state)
+{
+ struct iwl_sf_cfg_cmd sf_cmd = {
+ .state = new_state,
+ };
+ struct ieee80211_sta *sta;
+ int ret = 0;
+
+ /*
+ * If an associated AP sta changed its antenna configuration, the state
+ * will remain FULL_ON but SF parameters need to be reconsidered.
+ */
+ if (new_state != SF_FULL_ON && mvm->sf_state == new_state)
+ return 0;
+
+ switch (new_state) {
+ case SF_UNINIT:
+ break;
+ case SF_FULL_ON:
+ if (sta_id == IWL_MVM_STATION_COUNT) {
+ IWL_ERR(mvm,
+ "No station: Cannot switch SF to FULL_ON\n");
+ return -EINVAL;
+ }
+ rcu_read_lock();
+ sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
+ if (IS_ERR_OR_NULL(sta)) {
+ IWL_ERR(mvm, "Invalid station id\n");
+ rcu_read_unlock();
+ return -EINVAL;
+ }
+ iwl_mvm_fill_sf_command(&sf_cmd, sta);
+ rcu_read_unlock();
+ break;
+ case SF_INIT_OFF:
+ iwl_mvm_fill_sf_command(&sf_cmd, NULL);
+ break;
+ default:
+ WARN_ONCE(1, "Invalid state: %d. not sending Smart Fifo cmd\n",
+ new_state);
+ return -EINVAL;
+ }
+
+ ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_SF_CFG_CMD, CMD_ASYNC,
+ sizeof(sf_cmd), &sf_cmd);
+ if (!ret)
+ mvm->sf_state = new_state;
+
+ return ret;
+}
+
+/*
+ * Update Smart fifo:
+ * Count bound interfaces that are not to be removed, ignoring p2p devices,
+ * and set new state accordingly.
+ */
+int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *changed_vif,
+ bool remove_vif)
+{
+ enum iwl_sf_state new_state;
+ u8 sta_id = IWL_MVM_STATION_COUNT;
+ struct iwl_mvm_vif *mvmvif = NULL;
+ struct iwl_mvm_active_iface_iterator_data data = {
+ .ignore_vif = changed_vif,
+ .sta_vif_state = SF_UNINIT,
+ .sta_vif_ap_sta_id = IWL_MVM_STATION_COUNT,
+ };
+
+ if (IWL_UCODE_API(mvm->fw->ucode_ver) < 8)
+ return 0;
+
+ /*
+ * Ignore the call if we are in HW Restart flow, or if the handled
+ * vif is a p2p device.
+ */
+ if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) ||
+ (changed_vif && changed_vif->type == NL80211_IFTYPE_P2P_DEVICE))
+ return 0;
+
+ ieee80211_iterate_active_interfaces_atomic(mvm->hw,
+ IEEE80211_IFACE_ITER_NORMAL,
+ iwl_mvm_bound_iface_iterator,
+ &data);
+
+ /* If changed_vif exists and is not to be removed, add to the count */
+ if (changed_vif && !remove_vif)
+ data.num_active_macs++;
+
+ switch (data.num_active_macs) {
+ case 0:
+ /* If there are no active macs - change state to SF_INIT_OFF */
+ new_state = SF_INIT_OFF;
+ break;
+ case 1:
+ if (remove_vif) {
+ /* The one active mac left is of type station
+ * and we filled the relevant data during iteration
+ */
+ new_state = data.sta_vif_state;
+ sta_id = data.sta_vif_ap_sta_id;
+ } else {
+ if (WARN_ON(!changed_vif))
+ return -EINVAL;
+ if (changed_vif->type != NL80211_IFTYPE_STATION) {
+ new_state = SF_UNINIT;
+ } else if (changed_vif->bss_conf.assoc) {
+ mvmvif = iwl_mvm_vif_from_mac80211(changed_vif);
+ sta_id = mvmvif->ap_sta_id;
+ new_state = SF_FULL_ON;
+ } else {
+ new_state = SF_INIT_OFF;
+ }
+ }
+ break;
+ default:
+ /* If there are multiple active macs - change to SF_UNINIT */
+ new_state = SF_UNINIT;
+ }
+ return iwl_mvm_sf_config(mvm, sta_id, new_state);
+}
--
1.7.9.5


2013-12-17 20:45:31

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 32/36] iwlwifi: mvm: Do not allow AP MAC context update if not active

From: Ilan Peer <[email protected]>

Fix a regression introduced in "iwlwifi: mvm: fix ht protection flags"
where an AP/IBSS MAC context could have been updated even before the
context was added to the FW. This fix avoids the following warning:

WARNING: ... at .../drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c:1132
iwl_mvm_mac_ctxt_changed+0x75/0x90 [iwlmvm]()
Changing inactive MAC 0c:8b:fd:01:1a:30/3
Modules linked in: [...]
Call Trace:
[<c16041fd>] dump_stack+0x41/0x52
[<c1041074>] warn_slowpath_common+0x84/0xa0
[<f80d8f45>] ? iwl_mvm_mac_ctxt_changed+0x75/0x90 [iwlmvm]
[<f80d8f45>] ? iwl_mvm_mac_ctxt_changed+0x75/0x90 [iwlmvm]
[<c1041133>] warn_slowpath_fmt+0x33/0x40
[<f80d8f45>] iwl_mvm_mac_ctxt_changed+0x75/0x90 [iwlmvm]
[<f80d517a>] iwl_mvm_bss_info_changed+0x22a/0x4b0 [iwlmvm]
[<c160831d>] ? mutex_unlock+0xd/0x10
[<f80d4678>] ? iwl_mvm_configure_filter+0x58/0x70 [iwlmvm]
[<f80d4f50>] ? iwl_mvm_mac_tx+0xc0/0xc0 [iwlmvm]
[<f8132d83>] ieee80211_bss_info_change_notify+0xa3/0x1d0 [mac80211]
[<f8149247>] ? ieee80211_del_virtual_monitor+0x127/0x1f0 [mac80211]
[<f8149cac>] ieee80211_do_open+0x12c/0xeb0 [mac80211]
[<c106c6de>] ? __raw_notifier_call_chain+0x1e/0x30
[<c106c70f>] ? raw_notifier_call_chain+0x1f/0x30
[<f814aa8d>] ieee80211_open+0x5d/0x60 [mac80211]
[<c1500c7b>] __dev_open+0xab/0x140
[<c160b39a>] ? _raw_spin_unlock_bh+0x2a/0x30
[<c1500f41>] __dev_change_flags+0x81/0x160
[<c10ab6fc>] ? __lock_is_held+0x3c/0x60
[<c15010d1>] dev_change_flags+0x21/0x60

Signed-off-by: Ilan Peer <[email protected]>
Reported-by: Johannes Berg <[email protected]>
Reviewed-by: Johannes Berg <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/mac80211.c | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 272aabd..b61d5a2 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -1053,11 +1053,16 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm,
struct ieee80211_bss_conf *bss_conf,
u32 changes)
{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
enum ieee80211_bss_change ht_change = BSS_CHANGED_ERP_CTS_PROT |
BSS_CHANGED_HT |
BSS_CHANGED_BANDWIDTH;
int ret;

+ /* Changes will be applied when the AP/IBSS is started */
+ if (!mvmvif->ap_ibss_active)
+ return;
+
if (changes & ht_change) {
ret = iwl_mvm_mac_ctxt_changed(mvm, vif);
if (ret)
--
1.7.9.5


2013-12-17 20:45:26

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 28/36] iwlwifi: mvm: rs: improve rates table algo

From: Eyal Shapira <[email protected]>

The new logic will attempt more rates with less retries
per rate. Also when starting off with MIMO it will
fallback to SISO with the same MCS and only then to Legacy.
Previously we fell back directly to Legacy.

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

diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index 30470d4..bc86032 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -42,9 +42,16 @@

#define RS_NAME "iwl-mvm-rs"

-#define NUM_TRY_BEFORE_ANT_TOGGLE 1
-#define IWL_NUMBER_TRY 1
-#define IWL_HT_NUMBER_TRY 3
+#define NUM_TRY_BEFORE_ANT_TOGGLE 1
+#define RS_LEGACY_RETRIES_PER_RATE 1
+#define RS_HT_VHT_RETRIES_PER_RATE 2
+#define RS_HT_VHT_RETRIES_PER_RATE_TW 1
+#define RS_INITIAL_MIMO_NUM_RATES 3
+#define RS_INITIAL_SISO_NUM_RATES 3
+#define RS_INITIAL_LEGACY_NUM_RATES LINK_QUAL_MAX_RETRY_NUM
+#define RS_SECONDARY_LEGACY_NUM_RATES LINK_QUAL_MAX_RETRY_NUM
+#define RS_SECONDARY_SISO_NUM_RATES 3
+#define RS_SECONDARY_SISO_RETRIES 1

#define IWL_RATE_MAX_WINDOW 62 /* # tx in history window */
#define IWL_RATE_MIN_FAILURE_TH 3 /* min failures to calc tpt */
@@ -847,54 +854,73 @@ static u16 rs_get_adjacent_rate(struct iwl_mvm *mvm, u8 index, u16 rate_mask,
return (high << 8) | low;
}

-static void rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
- struct rs_rate *rate,
- u8 scale_index, u8 ht_possible)
+static inline bool rs_rate_supported(struct iwl_lq_sta *lq_sta,
+ struct rs_rate *rate)
{
- s32 low;
- u16 rate_mask;
+ return BIT(rate->index) & rs_get_supported_rates(lq_sta, rate);
+}
+
+/* Get the next supported lower rate in the current column.
+ * Return true if bottom rate in the current column was reached
+ */
+static bool rs_get_lower_rate_in_column(struct iwl_lq_sta *lq_sta,
+ struct rs_rate *rate)
+{
+ u8 low;
u16 high_low;
- u8 switch_to_legacy = 0;
+ u16 rate_mask;
+ struct iwl_mvm *mvm = lq_sta->drv;
+
+ rate_mask = rs_get_supported_rates(lq_sta, rate);
+ high_low = rs_get_adjacent_rate(mvm, rate->index, rate_mask,
+ rate->type);
+ low = high_low & 0xff;
+
+ /* Bottom rate of column reached */
+ if (low == IWL_RATE_INVALID)
+ return true;
+
+ rate->index = low;
+ return false;
+}
+
+/* Get the next rate to use following a column downgrade */
+static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta,
+ struct rs_rate *rate)
+{
struct iwl_mvm *mvm = lq_sta->drv;

- /* 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(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 (is_legacy(rate)) {
+ /* No column to downgrade from Legacy */
+ return;
+ } else if (is_siso(rate)) {
+ /* Downgrade to Legacy if we were in SISO */
if (lq_sta->band == IEEE80211_BAND_5GHZ)
rate->type = LQ_LEGACY_A;
else
rate->type = LQ_LEGACY_G;

- if (num_of_ant(rate->ant) > 1)
- rate->ant =
- first_antenna(iwl_fw_valid_tx_ant(mvm->fw));
-
rate->bw = RATE_MCS_CHAN_WIDTH_20;
- rate->sgi = false;
- }

- rate_mask = rs_get_supported_rates(lq_sta, rate);
+ WARN_ON_ONCE(rate->index < IWL_RATE_MCS_0_INDEX &&
+ rate->index > IWL_RATE_MCS_9_INDEX);

- /* If we switched from HT to legacy, check current rate */
- if (switch_to_legacy && (rate_mask & (1 << scale_index))) {
- low = scale_index;
- goto out;
+ rate->index = rs_ht_to_legacy[rate->index];
+ } else {
+ /* Downgrade to SISO with same MCS if in MIMO */
+ rate->type = is_vht_mimo2(rate) ?
+ LQ_VHT_SISO : LQ_HT_SISO;
}

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

- if (low == IWL_RATE_INVALID)
- low = scale_index;
+ if (num_of_ant(rate->ant) > 1)
+ rate->ant = first_antenna(iwl_fw_valid_tx_ant(mvm->fw));

-out:
- rate->index = low;
+ /* Relevant in both switching to SISO or Legacy */
+ rate->sgi = false;
+
+ if (!rs_rate_supported(lq_sta, rate))
+ rs_get_lower_rate_in_column(lq_sta, rate);
}

/* Simple function to compare two rate scale table types */
@@ -2333,96 +2359,118 @@ static void rs_build_rates_table_from_fixed(struct iwl_mvm *mvm,
}
#endif /* CONFIG_MAC80211_DEBUGFS */

+static void rs_fill_rates_for_column(struct iwl_mvm *mvm,
+ struct iwl_lq_sta *lq_sta,
+ struct rs_rate *rate,
+ __le32 *rs_table, int *rs_table_index,
+ int num_rates, int num_retries,
+ u8 valid_tx_ant, bool toggle_ant)
+{
+ int i, j;
+ __le32 ucode_rate;
+ bool bottom_reached = false;
+ int prev_rate_idx = rate->index;
+ int end = LINK_QUAL_MAX_RETRY_NUM;
+ int index = *rs_table_index;
+
+ for (i = 0; i < num_rates && index < end; i++) {
+ ucode_rate = cpu_to_le32(ucode_rate_from_rs_rate(mvm, rate));
+ for (j = 0; j < num_retries && index < end; j++, index++)
+ rs_table[index] = ucode_rate;
+
+ if (toggle_ant)
+ rs_toggle_antenna(valid_tx_ant, rate);
+
+ prev_rate_idx = rate->index;
+ bottom_reached = rs_get_lower_rate_in_column(lq_sta, rate);
+ if (bottom_reached && !is_legacy(rate))
+ break;
+ }
+
+ if (!bottom_reached)
+ rate->index = prev_rate_idx;
+
+ *rs_table_index = index;
+}
+
+/* Building the rate table is non trivial. When we're in MIMO2/VHT/80Mhz/SGI
+ * column the rate table should look like this:
+ *
+ * rate[0] 0x400D019 VHT | ANT: AB BW: 80Mhz MCS: 9 NSS: 2 SGI
+ * rate[1] 0x400D019 VHT | ANT: AB BW: 80Mhz MCS: 9 NSS: 2 SGI
+ * rate[2] 0x400D018 VHT | ANT: AB BW: 80Mhz MCS: 8 NSS: 2 SGI
+ * rate[3] 0x400D018 VHT | ANT: AB BW: 80Mhz MCS: 8 NSS: 2 SGI
+ * rate[4] 0x400D017 VHT | ANT: AB BW: 80Mhz MCS: 7 NSS: 2 SGI
+ * rate[5] 0x400D017 VHT | ANT: AB BW: 80Mhz MCS: 7 NSS: 2 SGI
+ * rate[6] 0x4005007 VHT | ANT: A BW: 80Mhz MCS: 7 NSS: 1 NGI
+ * rate[7] 0x4009006 VHT | ANT: B BW: 80Mhz MCS: 6 NSS: 1 NGI
+ * rate[8] 0x4005005 VHT | ANT: A BW: 80Mhz MCS: 5 NSS: 1 NGI
+ * rate[9] 0x800B Legacy | ANT: B Rate: 36 Mbps
+ * rate[10] 0x4009 Legacy | ANT: A Rate: 24 Mbps
+ * rate[11] 0x8007 Legacy | ANT: B Rate: 18 Mbps
+ * rate[12] 0x4005 Legacy | ANT: A Rate: 12 Mbps
+ * rate[13] 0x800F Legacy | ANT: B Rate: 9 Mbps
+ * rate[14] 0x400D Legacy | ANT: A Rate: 6 Mbps
+ * rate[15] 0x800D Legacy | ANT: B Rate: 6 Mbps
+ */
static void rs_build_rates_table(struct iwl_mvm *mvm,
struct iwl_lq_sta *lq_sta,
const struct rs_rate *initial_rate)
{
struct rs_rate rate;
- int index = 0;
- int repeat_rate = 0;
- u8 ant_toggle_cnt = 0;
- u8 use_ht_possible = 1;
+ int num_rates, num_retries, index = 0;
u8 valid_tx_ant = 0;
struct iwl_lq_cmd *lq_cmd = &lq_sta->lq;
+ bool toggle_ant = false;

memcpy(&rate, initial_rate, sizeof(struct rs_rate));

- lq_cmd->mimo_delim = is_mimo(&rate) ? 1 : 0;
-
- /* Fill 1st table entry (index 0) */
- lq_cmd->rs_table[index] = cpu_to_le32(
- ucode_rate_from_rs_rate(mvm, &rate));
+ if (mvm)
+ valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);

- /* How many times should we repeat the initial rate? */
- if (is_legacy(&rate)) {
- ant_toggle_cnt = 1;
- repeat_rate = IWL_NUMBER_TRY;
+ if (is_siso(&rate)) {
+ num_rates = RS_INITIAL_SISO_NUM_RATES;
+ num_retries = RS_HT_VHT_RETRIES_PER_RATE;
+ } else if (is_mimo(&rate)) {
+ num_rates = RS_INITIAL_MIMO_NUM_RATES;
+ num_retries = RS_HT_VHT_RETRIES_PER_RATE;
} else {
- repeat_rate = min(IWL_HT_NUMBER_TRY,
- LINK_QUAL_AGG_DISABLE_START_DEF - 1);
+ num_rates = RS_INITIAL_LEGACY_NUM_RATES;
+ num_retries = RS_LEGACY_RETRIES_PER_RATE;
+ toggle_ant = true;
}

- index++;
- repeat_rate--;
- if (mvm)
- valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
+ rs_fill_rates_for_column(mvm, lq_sta, &rate, lq_cmd->rs_table, &index,
+ num_rates, num_retries, valid_tx_ant,
+ toggle_ant);

- /* Fill rest of rate table */
- while (index < LINK_QUAL_MAX_RETRY_NUM) {
- /* Repeat initial/next rate.
- * 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(&rate)) {
- if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE)
- ant_toggle_cnt++;
- else if (mvm &&
- rs_toggle_antenna(valid_tx_ant, &rate))
- ant_toggle_cnt = 1;
- }
-
- /* Fill next table entry */
- lq_cmd->rs_table[index] = cpu_to_le32(
- ucode_rate_from_rs_rate(mvm, &rate));
- repeat_rate--;
- index++;
- }
+ rs_get_lower_rate_down_column(lq_sta, &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(&rate))
- lq_cmd->mimo_delim = index;
+ if (is_siso(&rate)) {
+ num_rates = RS_SECONDARY_SISO_NUM_RATES;
+ num_retries = RS_SECONDARY_SISO_RETRIES;
+ } else if (is_legacy(&rate)) {
+ num_rates = RS_SECONDARY_LEGACY_NUM_RATES;
+ num_retries = RS_LEGACY_RETRIES_PER_RATE;
+ } else {
+ WARN_ON_ONCE(1);
+ }

- /* Get next rate */
- rs_get_lower_rate(lq_sta, &rate, rate.index, use_ht_possible);
+ toggle_ant = true;

- /* How many times should we repeat the next rate? */
- 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, &rate))
- ant_toggle_cnt = 1;
+ rs_fill_rates_for_column(mvm, lq_sta, &rate, lq_cmd->rs_table, &index,
+ num_rates, num_retries, valid_tx_ant,
+ toggle_ant);

- repeat_rate = IWL_NUMBER_TRY;
- } else {
- repeat_rate = IWL_HT_NUMBER_TRY;
- }
+ rs_get_lower_rate_down_column(lq_sta, &rate);

- /* Don't allow HT rates after next pass.
- * rs_get_lower_rate() will change type to LQ_LEGACY_A
- * or LQ_LEGACY_G.
- */
- use_ht_possible = 0;
+ num_rates = RS_SECONDARY_LEGACY_NUM_RATES;
+ num_retries = RS_LEGACY_RETRIES_PER_RATE;

- /* Fill next table entry */
- lq_cmd->rs_table[index] = cpu_to_le32(
- ucode_rate_from_rs_rate(mvm, &rate));
+ rs_fill_rates_for_column(mvm, lq_sta, &rate, lq_cmd->rs_table, &index,
+ num_rates, num_retries, valid_tx_ant,
+ toggle_ant);

- index++;
- repeat_rate--;
- }
}

static void rs_fill_lq_cmd(struct iwl_mvm *mvm,
--
1.7.9.5


2013-12-17 20:45:22

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 26/36] iwlwifi: mvm: rs: refactor building the LQ command

From: Eyal Shapira <[email protected]>

Simplify the code a bit more by extracting the rates table
building logic into a separate function and handle setting
a fixed rate for debug in a separate flow.
Also avoid using and saving ucode rate format in different
places. Instead use rs_rate struct and convert to ucode format
only when filling the rates table in the LQ command.

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

diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index 83306a0..eee3381 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -351,20 +351,12 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
struct sk_buff *skb,
struct ieee80211_sta *sta,
struct iwl_lq_sta *lq_sta);
-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_fill_lq_cmd(struct iwl_mvm *mvm,
+ struct ieee80211_sta *sta,
+ struct iwl_lq_sta *lq_sta,
+ const struct rs_rate *initial_rate);
static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search);

-#ifdef CONFIG_MAC80211_DEBUGFS
-static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
- u32 *rate_n_flags);
-#else
-static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
- u32 *rate_n_flags)
-{}
-#endif
-
/**
* The following tables contain the expected throughput metrics for all rates
*
@@ -634,7 +626,7 @@ static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl,

/* Convert rs_rate object into ucode rate bitmask */
static u32 ucode_rate_from_rs_rate(struct iwl_mvm *mvm,
- struct rs_rate *rate)
+ struct rs_rate *rate)
{
u32 ucode_rate = 0;
int index = rate->index;
@@ -761,8 +753,7 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate,

/* 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 *ucode_rate,
- struct rs_rate *rate)
+static int rs_toggle_antenna(u32 valid_ant, struct rs_rate *rate)
{
u8 new_ant_type;

@@ -783,9 +774,6 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *ucode_rate,

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;
}

@@ -859,9 +847,9 @@ static u16 rs_get_adjacent_rate(struct iwl_mvm *mvm, u8 index, u16 rate_mask,
return (high << 8) | low;
}

-static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
- struct rs_rate *rate,
- u8 scale_index, u8 ht_possible)
+static void rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
+ struct rs_rate *rate,
+ u8 scale_index, u8 ht_possible)
{
s32 low;
u16 rate_mask;
@@ -917,7 +905,6 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta,

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

/* Simple function to compare two rate scale table types */
@@ -1447,10 +1434,7 @@ static void rs_update_rate_tbl(struct iwl_mvm *mvm,
struct iwl_lq_sta *lq_sta,
struct rs_rate *rate)
{
- u32 ucode_rate;
-
- ucode_rate = ucode_rate_from_rs_rate(mvm, rate);
- rs_fill_link_cmd(mvm, sta, lq_sta, ucode_rate);
+ rs_fill_lq_cmd(mvm, sta, lq_sta, rate);
iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false);
}

@@ -1610,10 +1594,6 @@ static int rs_switch_to_column(struct iwl_mvm *mvm,
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);

@@ -1730,9 +1710,6 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
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);
- tbl->rate.index = index;
rs_update_rate_tbl(mvm, sta, lq_sta, &tbl->rate);
}
return;
@@ -1823,7 +1800,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
tbl = &(lq_sta->lq_info[active_tbl]);

/* Revert to "active" rate and throughput info */
- index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
+ index = tbl->rate.index;
current_tpt = lq_sta->last_tpt;

/* Need to set up a new rate table in uCode */
@@ -2029,11 +2006,11 @@ lq_update:
rs_rate_scale_clear_window(&(tbl->win[i]));

/* Use new "search" start rate */
- index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
+ index = tbl->rate.index;

rs_dump_rate(mvm, &tbl->rate,
"Switch to SEARCH TABLE:");
- rs_fill_link_cmd(mvm, sta, lq_sta, tbl->current_rate);
+ rs_fill_lq_cmd(mvm, sta, lq_sta, &tbl->rate);
iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false);
} else {
done_search = 1;
@@ -2071,8 +2048,6 @@ lq_update:
}

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

@@ -2099,7 +2074,6 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
struct iwl_scale_tbl_info *tbl;
struct rs_rate *rate;
int i;
- u32 ucode_rate;
u8 active_tbl = 0;
u8 valid_tx_ant;

@@ -2130,9 +2104,6 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
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;
@@ -2140,7 +2111,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
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);
+ rs_fill_lq_cmd(NULL, NULL, lq_sta, rate);
/* TODO restore station should remember the lq cmd */
iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, init);
}
@@ -2371,9 +2342,32 @@ static void rs_rate_update(void *mvm_r,
iwl_mvm_rs_rate_init(mvm, sta, sband->band, false);
}

-static void rs_fill_link_cmd(struct iwl_mvm *mvm,
- struct ieee80211_sta *sta,
- struct iwl_lq_sta *lq_sta, u32 new_rate)
+#ifdef CONFIG_MAC80211_DEBUGFS
+static void rs_build_rates_table_from_fixed(struct iwl_mvm *mvm,
+ struct iwl_lq_cmd *lq_cmd,
+ enum ieee80211_band band,
+ u32 ucode_rate)
+{
+ struct rs_rate rate;
+ int i;
+ int num_rates = ARRAY_SIZE(lq_cmd->rs_table);
+ __le32 ucode_rate_le32 = cpu_to_le32(ucode_rate);
+
+ for (i = 0; i < num_rates; i++)
+ lq_cmd->rs_table[i] = ucode_rate_le32;
+
+ rs_rate_from_ucode_rate(ucode_rate, band, &rate);
+
+ if (is_mimo(&rate))
+ lq_cmd->mimo_delim = num_rates - 1;
+ else
+ lq_cmd->mimo_delim = 0;
+}
+#endif /* CONFIG_MAC80211_DEBUGFS */
+
+static void rs_build_rates_table(struct iwl_mvm *mvm,
+ struct iwl_lq_sta *lq_sta,
+ const struct rs_rate *initial_rate)
{
struct rs_rate rate;
int index = 0;
@@ -2383,10 +2377,13 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm,
u8 valid_tx_ant = 0;
struct iwl_lq_cmd *lq_cmd = &lq_sta->lq;

- /* Override starting rate (index 0) if needed for debug purposes */
- rs_dbgfs_set_mcs(lq_sta, &new_rate);
+ memcpy(&rate, initial_rate, sizeof(struct rs_rate));
+
+ lq_cmd->mimo_delim = is_mimo(&rate) ? 1 : 0;

- rs_rate_from_ucode_rate(new_rate, lq_sta->band, &rate);
+ /* Fill 1st table entry (index 0) */
+ lq_cmd->rs_table[index] = cpu_to_le32(
+ ucode_rate_from_rs_rate(mvm, &rate));

/* How many times should we repeat the initial rate? */
if (is_legacy(&rate)) {
@@ -2397,15 +2394,6 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm,
LINK_QUAL_AGG_DISABLE_START_DEF - 1);
}

- 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(rate.ant) == 1)
- lq_cmd->single_stream_ant_msk = rate.ant;
- /* otherwise we don't modify the existing value */
-
index++;
repeat_rate--;
if (mvm)
@@ -2421,23 +2409,17 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm,
if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE)
ant_toggle_cnt++;
else if (mvm &&
- rs_toggle_antenna(valid_tx_ant,
- &new_rate, &rate))
+ rs_toggle_antenna(valid_tx_ant, &rate))
ant_toggle_cnt = 1;
}

- /* Override next rate if needed for debug purposes */
- rs_dbgfs_set_mcs(lq_sta, &new_rate);
-
/* Fill next table entry */
- lq_cmd->rs_table[index] =
- cpu_to_le32(new_rate);
+ lq_cmd->rs_table[index] = cpu_to_le32(
+ ucode_rate_from_rs_rate(mvm, &rate));
repeat_rate--;
index++;
}

- 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. */
@@ -2445,16 +2427,14 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm,
lq_cmd->mimo_delim = index;

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

/* How many times should we repeat the next rate? */
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, &rate))
+ rs_toggle_antenna(valid_tx_ant, &rate))
ant_toggle_cnt = 1;

repeat_rate = IWL_NUMBER_TRY;
@@ -2468,15 +2448,36 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm,
*/
use_ht_possible = 0;

- /* Override next rate if needed for debug purposes */
- rs_dbgfs_set_mcs(lq_sta, &new_rate);
-
/* Fill next table entry */
- lq_cmd->rs_table[index] = cpu_to_le32(new_rate);
+ lq_cmd->rs_table[index] = cpu_to_le32(
+ ucode_rate_from_rs_rate(mvm, &rate));

index++;
repeat_rate--;
}
+}
+
+static void rs_fill_lq_cmd(struct iwl_mvm *mvm,
+ struct ieee80211_sta *sta,
+ struct iwl_lq_sta *lq_sta,
+ const struct rs_rate *initial_rate)
+{
+ struct iwl_lq_cmd *lq_cmd = &lq_sta->lq;
+ u8 ant = initial_rate->ant;
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+ if (lq_sta->dbg_fixed_rate) {
+ rs_build_rates_table_from_fixed(mvm, lq_cmd,
+ lq_sta->band,
+ lq_sta->dbg_fixed_rate);
+ ant = (lq_sta->dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK) >>
+ RATE_MCS_ANT_POS;
+ } else
+#endif
+ rs_build_rates_table(mvm, lq_sta, initial_rate);
+
+ if (num_of_ant(ant) == 1)
+ lq_cmd->single_stream_ant_msk = ant;

lq_cmd->agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
lq_cmd->agg_disable_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
@@ -2510,31 +2511,6 @@ static void rs_free_sta(void *mvm_r, struct ieee80211_sta *sta,
}

#ifdef CONFIG_MAC80211_DEBUGFS
-static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
- u32 *rate_n_flags)
-{
- struct iwl_mvm *mvm;
- u8 valid_tx_ant;
- u8 ant_sel_tx;
-
- mvm = lq_sta->drv;
- valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
- if (lq_sta->dbg_fixed_rate) {
- ant_sel_tx =
- ((lq_sta->dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK)
- >> RATE_MCS_ANT_POS);
- if ((valid_tx_ant & ant_sel_tx) == ant_sel_tx) {
- *rate_n_flags = lq_sta->dbg_fixed_rate;
- } else {
- lq_sta->dbg_fixed_rate = 0;
- IWL_ERR(mvm,
- "Invalid antenna selection 0x%X, Valid is 0x%X\n",
- ant_sel_tx, valid_tx_ant);
- IWL_DEBUG_RATE(mvm, "Fixed rate OFF\n");
- }
- }
-}
-
static int rs_pretty_print_rate(char *buf, const u32 rate)
{

@@ -2605,7 +2581,10 @@ static void rs_program_fix_rate(struct iwl_mvm *mvm,
lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate);

if (lq_sta->dbg_fixed_rate) {
- rs_fill_link_cmd(NULL, NULL, lq_sta, lq_sta->dbg_fixed_rate);
+ struct rs_rate rate;
+ rs_rate_from_ucode_rate(lq_sta->dbg_fixed_rate,
+ lq_sta->band, &rate);
+ rs_fill_lq_cmd(NULL, NULL, lq_sta, &rate);
iwl_mvm_send_lq_cmd(lq_sta->drv, &lq_sta->lq, false);
}
}
@@ -2739,14 +2718,14 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
rate = &tbl->rate;
desc += sprintf(buff+desc,
"%s type=%d SGI=%d BW=%s DUP=0\n"
- "rate=0x%X\n",
+ "index=%d\n",
lq_sta->active_tbl == i ? "*" : "x",
rate->type,
rate->sgi,
is_ht20(rate) ? "20Mhz" :
is_ht40(rate) ? "40Mhz" :
is_ht80(rate) ? "80Mhz" : "ERR",
- tbl->current_rate);
+ rate->index);
for (j = 0; j < IWL_RATE_COUNT; j++) {
desc += sprintf(buff+desc,
"counter=%d success=%d %%=%d\n",
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h
index b329607..7b26e65 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.h
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.h
@@ -278,7 +278,6 @@ struct iwl_scale_tbl_info {
struct rs_rate rate;
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 */
};

--
1.7.9.5


2013-12-17 20:44:51

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 04/36] iwlwifi: publish STBC support in HT

From: Eyal Shapira <[email protected]>

Not all chips support STBC so allow this to be
another config parameter per chip type. If STBC
is supported then publish it in the HT caps.

Since 7260/7265/3160 chips support it - set the stbc
support bit.

Signed-off-by: Eyal Shapira <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-7000.c | 1 +
drivers/net/wireless/iwlwifi/iwl-config.h | 2 ++
drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c | 7 +++++++
3 files changed, 10 insertions(+)

diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c
index 3c34a72..5efc6d1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-7000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-7000.c
@@ -108,6 +108,7 @@ static const struct iwl_base_params iwl7000_base_params = {
};

static const struct iwl_ht_params iwl7000_ht_params = {
+ .stbc = true,
.use_rts_for_aggregation = true, /* use rts/cts protection */
.ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
};
diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h
index 0b91624..e05440f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-config.h
+++ b/drivers/net/wireless/iwlwifi/iwl-config.h
@@ -162,12 +162,14 @@ struct iwl_base_params {
};

/*
+ * @stbc: support Tx STBC and 1*SS Rx STBC
* @use_rts_for_aggregation: use rts/cts protection for HT traffic
* @ht40_bands: bitmap of bands (using %IEEE80211_BAND_*) that support HT40
*/
struct iwl_ht_params {
enum ieee80211_smps_mode smps_mode;
const bool ht_greenfield_support; /* if used set to true */
+ const bool stbc;
bool use_rts_for_aggregation;
u8 ht40_bands;
};
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
index f4a6d31..4380c16 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
@@ -751,6 +751,13 @@ void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg,
ht_info->ht_supported = true;
ht_info->cap = IEEE80211_HT_CAP_DSSSCCK40;

+ if (cfg->ht_params->stbc) {
+ ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
+
+ if (tx_chains > 1)
+ ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
+ }
+
if (iwlwifi_mod_params.amsdu_size_8K)
ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;

--
1.7.9.5


2013-12-17 20:44:47

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 01/36] iwlwifi: mvm: don't send SMPS action frame with single RX antenna

From: Emmanuel Grumbach <[email protected]>

Products that have only 1 antenna in Rx don't support MIMO
in RX. As a consequence, they will be in STATIC always.
Don't tell mac80211 to update SMPS in that case. mac80211
would send an action frame to the AP which is clearly
bogus.
As a matter of fact, we have seen that some APs send a
deauth when that happens.

Reviewed-by: Johannes Berg <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/utils.c | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c
index 56cf819..f4aff56 100644
--- a/drivers/net/wireless/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/iwlwifi/mvm/utils.c
@@ -518,6 +518,11 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
int i;

lockdep_assert_held(&mvm->mutex);
+
+ /* SMPS is irrelevant for NICs that don't have at least 2 RX antenna */
+ if (num_of_ant(iwl_fw_valid_rx_ant(mvm->fw)) == 1)
+ return;
+
mvmvif = iwl_mvm_vif_from_mac80211(vif);
mvmvif->smps_requests[req_type] = smps_request;
for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) {
--
1.7.9.5


2013-12-17 20:45:28

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 30/36] iwlwifi: mvm: rs: refactor rate scale action decision

From: Eyal Shapira <[email protected]>

Extract the scale action decision to a different function
in preparation of modifying it. While at it also convert
the scale action values from hardcoded values to a clear enum.

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

diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index 6d0bd45..62b29d7 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -130,6 +130,12 @@ static const struct iwl_rs_rate_info iwl_rates[IWL_RATE_COUNT] = {
IWL_DECLARE_MCS_RATE(9), /* MCS 9 */
};

+enum rs_action {
+ RS_ACTION_STAY = 0,
+ RS_ACTION_DOWNSCALE = -1,
+ RS_ACTION_UPSCALE = 1,
+};
+
enum rs_column_mode {
RS_INVALID = 0,
RS_LEGACY,
@@ -1616,6 +1622,97 @@ err:
return -1;
}

+static enum rs_action rs_get_rate_action(struct iwl_mvm *mvm,
+ struct iwl_scale_tbl_info *tbl,
+ s32 sr, int low, int high,
+ int current_tpt,
+ int low_tpt, int high_tpt)
+{
+ enum rs_action action = RS_ACTION_STAY;
+
+ /* Too many failures, decrease rate */
+ if ((sr <= RS_SR_FORCE_DECREASE) || (current_tpt == 0)) {
+ IWL_DEBUG_RATE(mvm,
+ "decrease rate because of low SR\n");
+ action = RS_ACTION_DOWNSCALE;
+ /* 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) {
+ IWL_DEBUG_RATE(mvm,
+ "Good SR and no high rate measurement. "
+ "Increase rate\n");
+ action = RS_ACTION_UPSCALE;
+ } else if (low != IWL_RATE_INVALID) {
+ IWL_DEBUG_RATE(mvm,
+ "Remain in current rate\n");
+ action = RS_ACTION_STAY;
+ }
+ }
+
+ /* Both adjacent throughputs are measured, but neither one has better
+ * throughput; we're using the best rate, don't change it!
+ */
+ else if ((low_tpt != IWL_INVALID_VALUE) &&
+ (high_tpt != IWL_INVALID_VALUE) &&
+ (low_tpt < current_tpt) &&
+ (high_tpt < current_tpt)) {
+ IWL_DEBUG_RATE(mvm,
+ "Both high and low are worse. "
+ "Maintain rate\n");
+ action = RS_ACTION_STAY;
+ }
+
+ /* At least one adjacent rate's throughput is measured,
+ * and may have better performance.
+ */
+ else {
+ /* Higher adjacent rate's throughput is measured */
+ if (high_tpt != IWL_INVALID_VALUE) {
+ /* 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");
+ action = RS_ACTION_UPSCALE;
+ } else {
+ IWL_DEBUG_RATE(mvm,
+ "Higher rate isn't better OR "
+ "no good SR. Maintain rate\n");
+ action = RS_ACTION_STAY;
+ }
+
+ /* Lower adjacent rate's throughput is measured */
+ } else if (low_tpt != IWL_INVALID_VALUE) {
+ /* Lower rate has better throughput */
+ if (low_tpt > current_tpt) {
+ IWL_DEBUG_RATE(mvm,
+ "Lower rate is better. "
+ "Decrease rate\n");
+ action = RS_ACTION_DOWNSCALE;
+ } else if (sr >= IWL_RATE_INCREASE_TH) {
+ IWL_DEBUG_RATE(mvm,
+ "Lower rate isn't better and "
+ "good SR. Increase rate\n");
+ action = RS_ACTION_UPSCALE;
+ }
+ }
+ }
+
+ /* Sanity check; asked for decrease, but success rate or throughput
+ * has been good at old rate. Don't change it.
+ */
+ if ((action == RS_ACTION_DOWNSCALE) && (low != IWL_RATE_INVALID) &&
+ ((sr > IWL_RATE_HIGH_TH) ||
+ (current_tpt > (100 * tbl->expected_tpt[low])))) {
+ IWL_DEBUG_RATE(mvm,
+ "Sanity check failed. Maintain rate\n");
+ action = RS_ACTION_STAY;
+ }
+
+ return action;
+}

/*
* Do rate scaling and search for new modulation mode.
@@ -1636,7 +1733,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
int low_tpt = IWL_INVALID_VALUE;
int high_tpt = IWL_INVALID_VALUE;
u32 fail_count;
- s8 scale_action = 0;
+ enum rs_action scale_action = RS_ACTION_STAY;
u16 rate_mask;
u8 update_lq = 0;
struct iwl_scale_tbl_info *tbl, *tbl1;
@@ -1830,85 +1927,8 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
rs_pretty_lq_type(rate->type), index, current_tpt, sr,
low, high, low_tpt, high_tpt);

- scale_action = 0;
-
- /* Too many failures, decrease rate */
- if ((sr <= RS_SR_FORCE_DECREASE) || (current_tpt == 0)) {
- IWL_DEBUG_RATE(mvm,
- "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) {
- IWL_DEBUG_RATE(mvm,
- "Good SR and no high rate measurement. "
- "Increase rate\n");
- scale_action = 1;
- } 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
- * throughput; we're using the best rate, don't change it! */
- else if ((low_tpt != IWL_INVALID_VALUE) &&
- (high_tpt != IWL_INVALID_VALUE) &&
- (low_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. */
- else {
- /* Higher adjacent rate's throughput is measured */
- if (high_tpt != IWL_INVALID_VALUE) {
- /* 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;
- }
-
- /* Lower adjacent rate's throughput is measured */
- } else if (low_tpt != IWL_INVALID_VALUE) {
- /* Lower rate has better throughput */
- if (low_tpt > current_tpt) {
- IWL_DEBUG_RATE(mvm,
- "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;
- }
- }
- }
-
- /* Sanity check; asked for decrease, but success rate or throughput
- * 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])))) {
- IWL_DEBUG_RATE(mvm,
- "Sanity check failed. Maintain rate\n");
- scale_action = 0;
- }
+ scale_action = rs_get_rate_action(mvm, tbl, sr, low, high,
+ current_tpt, low_tpt, high_tpt);

/* Force a search in case BT doesn't like us being in MIMO */
if (is_mimo(rate) &&
@@ -1920,7 +1940,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
}

switch (scale_action) {
- case -1:
+ case RS_ACTION_DOWNSCALE:
/* Decrease starting rate, update uCode's rate table */
if (low != IWL_RATE_INVALID) {
update_lq = 1;
@@ -1931,7 +1951,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
}

break;
- case 1:
+ case RS_ACTION_UPSCALE:
/* Increase starting rate, update uCode's rate table */
if (high != IWL_RATE_INVALID) {
update_lq = 1;
@@ -1942,7 +1962,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
}

break;
- case 0:
+ case RS_ACTION_STAY:
/* No change */
default:
break;
--
1.7.9.5


2013-12-17 20:45:21

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 25/36] iwlwifi: mvm: Add and examine TLV flag for P2P client uAPSD support

From: Alexander Bondar <[email protected]>

Current firmware doesn't handle well uAPSD in P2P Client.
When it will be fixed, the firmware will set a TLV flag to notify
the driver that uAPSD is supported in P2P client mode.
Check this flag when sending power command for P2P client.

Signed-off-by: Alexander Bondar <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-fw.h | 2 ++
drivers/net/wireless/iwlwifi/mvm/power.c | 4 ++++
2 files changed, 6 insertions(+)

diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h
index 959562d..8704e304 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw.h
@@ -94,6 +94,7 @@
* containing CAM (Continuous Active Mode) indication.
* @IWL_UCODE_TLV_FLAGS_P2P_PS: P2P client power save is supported (only on a
* single bound interface).
+ * @IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save
*/
enum iwl_ucode_tlv_flag {
IWL_UCODE_TLV_FLAGS_PAN = BIT(0),
@@ -117,6 +118,7 @@ enum iwl_ucode_tlv_flag {
IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD = BIT(20),
IWL_UCODE_TLV_FLAGS_P2P_PS = BIT(21),
IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT = BIT(24),
+ IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD = BIT(26),
};

/* The default calibrate table size if not specified by firmware file */
diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c
index d173ea2..483ecc6 100644
--- a/drivers/net/wireless/iwlwifi/mvm/power.c
+++ b/drivers/net/wireless/iwlwifi/mvm/power.c
@@ -358,6 +358,10 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
if (!memcmp(mvmvif->uapsd_misbehaving_bssid, vif->bss_conf.bssid,
ETH_ALEN))
allow_uapsd = false;
+
+ if (vif->p2p &&
+ !(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD))
+ allow_uapsd = false;
/*
* Avoid using uAPSD if P2P client is associated to GO that uses
* opportunistic power save. This is due to current FW limitation.
--
1.7.9.5


2013-12-17 20:45:15

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 21/36] iwlwifi: mvm: check iwl_nvm_init return value

From: Eliad Peller <[email protected]>

iwl_nvm_init() return value wasn't checked in some
path, which resulted in the following panic (if
there was some issue with the nvm):

Unable to handle kernel NULL pointer dereference at virtual address 00000004
pgd = d0460000
[00000004] *pgd=00000000
Internal error: Oops: 5 [#1] PREEMPT SMP
Modules linked in: iwlmvm(+) iwlwifi mac80211 cfg80211 compat [last unloaded: compat]
PC is at iwl_mvm_mac_setup_register+0x12c/0x460 [iwlmvm]
LR is at 0x2710
pc : [<bf50dd4c>] lr : [<00002710>] psr: 20800013
sp : d00cfe18 ip : 0000081e fp : d006b908
r10: d0711408 r9 : bf532e64 r8 : d006b5bc
r7 : d01af000 r6 : bf39cefc r5 : d006ab00 r4 : d006b5a4
r3 : 00000001 r2 : 00000000 r1 : d006a120 r0 : d006b860

Signed-off-by: Eliad Peller <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/ops.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
index ef3fdcf..a362430 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -427,7 +427,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
* there is no need to unnecessarily power up the NIC at driver load
*/
if (iwlwifi_mod_params.nvm_file) {
- iwl_nvm_init(mvm);
+ err = iwl_nvm_init(mvm);
+ if (err)
+ goto out_free;
} else {
err = iwl_trans_start_hw(mvm->trans);
if (err)
--
1.7.9.5


2013-12-17 20:44:59

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 09/36] iwlwifi: mvm: Disable power save for monitor interface

From: Alexander Bondar <[email protected]>

When monitor interface is activated device power save needs
to be disabled.
Re-consider power management status on other active
interfaces when monitor interface is bound or unbound.

Signed-off-by: Alexander Bondar <[email protected]>
Reviewed-by: Johannes Berg <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/mac80211.c | 15 ++++++++++-----
drivers/net/wireless/iwlwifi/mvm/mvm.h | 10 +++++++---
drivers/net/wireless/iwlwifi/mvm/power.c | 22 ++++++++++++++++++----
3 files changed, 35 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index e1c379a..d36105f 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -1610,7 +1610,13 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
goto out_unlock;

/*
- * Setting the quota at this stage is only required for monitor
+ * Power state must be updated before quotas,
+ * otherwise fw will complain.
+ */
+ mvm->bound_vif_cnt++;
+ iwl_mvm_power_update_binding(mvm, vif, true);
+
+ /* Setting the quota at this stage is only required for monitor
* interfaces. For the other types, the bss_info changed flow
* will handle quota settings.
*/
@@ -1621,13 +1627,12 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
goto out_remove_binding;
}

- mvm->bound_vif_cnt++;
- iwl_mvm_power_update_binding(mvm, vif);
-
goto out_unlock;

out_remove_binding:
iwl_mvm_binding_remove_vif(mvm, vif);
+ mvm->bound_vif_cnt--;
+ iwl_mvm_power_update_binding(mvm, vif, false);
out_unlock:
mutex_unlock(&mvm->mutex);
if (ret)
@@ -1662,7 +1667,7 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw,
out_unlock:
mvmvif->phy_ctxt = NULL;
mvm->bound_vif_cnt--;
- iwl_mvm_power_update_binding(mvm, vif);
+ iwl_mvm_power_update_binding(mvm, vif, false);

mutex_unlock(&mvm->mutex);
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index 51b0e9a..7295f8e 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -164,7 +164,7 @@ struct iwl_mvm_power_ops {
int (*power_update_device_mode)(struct iwl_mvm *mvm);
int (*power_disable)(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
void (*power_update_binding)(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif);
+ struct ieee80211_vif *vif, bool assign);
#ifdef CONFIG_IWLWIFI_DEBUGFS
int (*power_dbgfs_read)(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
char *buf, int bufsz);
@@ -568,6 +568,9 @@ struct iwl_mvm {
u8 last_agg_queue;

u8 bound_vif_cnt;
+
+ /* Indicate if device power save is allowed */
+ bool ps_prevented;
};

/* Extract MVM priv from op_mode and _hw */
@@ -787,10 +790,11 @@ static inline int iwl_mvm_power_update_device_mode(struct iwl_mvm *mvm)
}

static inline void iwl_mvm_power_update_binding(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif)
+ struct ieee80211_vif *vif,
+ bool assign)
{
if (mvm->pm_ops->power_update_binding)
- mvm->pm_ops->power_update_binding(mvm, vif);
+ mvm->pm_ops->power_update_binding(mvm, vif, assign);
}

void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c
index d5d4935..cfed105 100644
--- a/drivers/net/wireless/iwlwifi/mvm/power.c
+++ b/drivers/net/wireless/iwlwifi/mvm/power.c
@@ -301,7 +301,8 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC);
cmd->keep_alive_seconds = cpu_to_le16(keep_alive);

- if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM)
+ if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM ||
+ mvm->ps_prevented)
return;

cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK);
@@ -447,7 +448,7 @@ static int iwl_mvm_power_mac_disable(struct iwl_mvm *mvm,
sizeof(cmd), &cmd);
}

-static int iwl_mvm_power_update_device(struct iwl_mvm *mvm)
+static int _iwl_mvm_power_update_device(struct iwl_mvm *mvm, bool force_disable)
{
struct iwl_device_power_cmd cmd = {
.flags = cpu_to_le16(DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK),
@@ -456,7 +457,8 @@ static int iwl_mvm_power_update_device(struct iwl_mvm *mvm)
if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD))
return 0;

- if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM)
+ if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM ||
+ force_disable)
cmd.flags |= cpu_to_le16(DEVICE_POWER_FLAGS_CAM_MSK);

#ifdef CONFIG_IWLWIFI_DEBUGFS
@@ -473,6 +475,11 @@ static int iwl_mvm_power_update_device(struct iwl_mvm *mvm)
&cmd);
}

+static int iwl_mvm_power_update_device(struct iwl_mvm *mvm)
+{
+ return _iwl_mvm_power_update_device(mvm, false);
+}
+
void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
@@ -525,8 +532,15 @@ static void iwl_mvm_power_binding_iterator(void *_data, u8 *mac,
}

static void _iwl_mvm_power_update_binding(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif)
+ struct ieee80211_vif *vif,
+ bool assign)
{
+ if (vif->type == NL80211_IFTYPE_MONITOR) {
+ int ret = _iwl_mvm_power_update_device(mvm, assign);
+ mvm->ps_prevented = assign;
+ WARN_ONCE(ret, "Failed to update power device state\n");
+ }
+
ieee80211_iterate_active_interfaces(mvm->hw,
IEEE80211_IFACE_ITER_NORMAL,
iwl_mvm_power_binding_iterator,
--
1.7.9.5


2013-12-17 20:45:35

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 35/36] iwlwifi: mvm: rs: fix RTS protection being set indefinitely

From: Eyal Shapira <[email protected]>

RTS protection was turned on once aggregation was enabled but it
was never turned off. Remove turning on RTS protection in the LQ command
completely as TX_CMD_FLG_PROT_REQUIRE gets set in iwl_mvm_set_tx_cmd
for every Tx which is part of an aggregation. This would already cause
RTS protection to be used during aggregations.

Signed-off-by: Eyal Shapira <[email protected]>
Reviewed-by: Johannes Berg <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-7000.c | 1 -
drivers/net/wireless/iwlwifi/mvm/sta.c | 13 -------------
2 files changed, 14 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c
index 5efc6d1..5fb3772 100644
--- a/drivers/net/wireless/iwlwifi/iwl-7000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-7000.c
@@ -109,7 +109,6 @@ static const struct iwl_base_params iwl7000_base_params = {

static const struct iwl_ht_params iwl7000_ht_params = {
.stbc = true,
- .use_rts_for_aggregation = true, /* use rts/cts protection */
.ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
};

diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c
index 4ea00da..0b541ca 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.c
@@ -932,19 +932,6 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
IWL_DEBUG_HT(mvm, "Tx aggregation enabled on ra = %pM tid = %d\n",
sta->addr, tid);

- if (mvm->cfg->ht_params->use_rts_for_aggregation) {
- /*
- * switch to RTS/CTS if it is the prefer protection
- * method for HT traffic
- * this function also sends the LQ command
- */
- return iwl_mvm_tx_protection(mvm, mvmsta, true);
- /*
- * TODO: remove the TLC_RTS flag when we tear down the last
- * AGG session (agg_tids_count in DVM)
- */
- }
-
return iwl_mvm_send_lq_cmd(mvm, &mvmsta->lq_sta.lq, false);
}

--
1.7.9.5


2013-12-17 20:45:24

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 27/36] iwlwifi: mvm: rs: avoid recalc of supported legacy rate mask

From: Eyal Shapira <[email protected]>

The supported legacy rate mask is initialized when rs
is initialized based on the remote peer supported rates.
There's no need to re mask it repeatedly with the supported
remote peer rates.

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

diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index eee3381..30470d4 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -880,16 +880,6 @@ static void rs_get_lower_rate(struct iwl_lq_sta *lq_sta,

rate_mask = rs_get_supported_rates(lq_sta, rate);

- /* Mask with station rate restriction */
- 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 &
- (lq_sta->supp_rates << IWL_FIRST_OFDM_RATE));
- else
- rate_mask = (u16)(rate_mask & lq_sta->supp_rates);
- }
-
/* If we switched from HT to legacy, check current rate */
if (switch_to_legacy && (rate_mask & (1 << scale_index))) {
low = scale_index;
@@ -1629,7 +1619,6 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
u16 rate_mask;
u8 update_lq = 0;
struct iwl_scale_tbl_info *tbl, *tbl1;
- u16 rate_scale_index_msk = 0;
u8 active_tbl = 0;
u8 done_search = 0;
u16 high_low;
@@ -1646,8 +1635,6 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
info->flags & IEEE80211_TX_CTL_NO_ACK)
return;

- lq_sta->supp_rates = sta->supp_rates[lq_sta->band];
-
tid = rs_get_tid(lq_sta, hdr);
if ((tid != IWL_MAX_TID_COUNT) &&
(lq_sta->tx_agg_tid_en & (1 << tid))) {
@@ -1686,24 +1673,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
/* rates available for this association, and for modulation mode */
rate_mask = rs_get_supported_rates(lq_sta, rate);

- /* mask with station rate restriction */
- 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 &
- (lq_sta->supp_rates << IWL_FIRST_OFDM_RATE));
- else
- rate_scale_index_msk = (u16) (rate_mask &
- lq_sta->supp_rates);
-
- } else {
- rate_scale_index_msk = rate_mask;
- }
-
- if (!rate_scale_index_msk)
- rate_scale_index_msk = rate_mask;
-
- if (!((BIT(index) & rate_scale_index_msk))) {
+ if (!(BIT(index) & rate_mask)) {
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*/
@@ -1816,8 +1786,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,
- rate->type);
+ high_low = rs_get_adjacent_rate(mvm, index, rate_mask, rate->type);
low = high_low & 0xff;
high = (high_low >> 8) & 0xff;

@@ -2253,7 +2222,6 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]);

lq_sta->flush_timer = 0;
- lq_sta->supp_rates = sta->supp_rates[sband->band];

IWL_DEBUG_RATE(mvm,
"LQ: *** rate scale station global init for station %d ***\n",
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h
index 7b26e65..c31aa59 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.h
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.h
@@ -314,7 +314,6 @@ struct iwl_lq_sta {
enum ieee80211_band band;

/* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
- u32 supp_rates;
u16 active_legacy_rate;
u16 active_siso_rate;
u16 active_mimo2_rate;
--
1.7.9.5


2013-12-17 20:45:18

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 23/36] iwlwifi: trans: clear FW_ERROR status in common code

From: Arik Nemtsov <[email protected]>

Clear the FW_ERROR status before the common start_fw transport code.
Remove the transport specific clears.

After these patches the FW_ERROR flag is only set and cleared by common
transport code.

Signed-off-by: Arik Nemtsov <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-trans.h | 1 +
drivers/net/wireless/iwlwifi/pcie/trans.c | 2 --
2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index fa495ba..8aaabdb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -590,6 +590,7 @@ static inline int iwl_trans_start_fw(struct iwl_trans *trans,

WARN_ON_ONCE(!trans->rx_mpdu_cmd);

+ clear_bit(STATUS_FW_ERROR, &trans->status);
return trans->ops->start_fw(trans, fw, run_in_rfkill);
}

diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index 28c62a5..eecd38e 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -589,8 +589,6 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
return -EIO;
}

- clear_bit(STATUS_FW_ERROR, &trans->status);
-
iwl_enable_rfkill_int(trans);

/* If platform's RF_KILL switch is NOT set to KILL */
--
1.7.9.5


2013-12-17 20:44:50

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 03/36] iwlwifi: mvm: add a generic cipher scheme support

From: Max Stepanov <[email protected]>

This patch adds a cipher scheme support to extend a set of
the supported ciphers. The driver reads a cipher scheme list TLV
from FW image and passes it to mac80211 on hw registration.
After the cipher schemes are registered the driver handles key
installation and Tx/Rx calls related to the new ciphers.

Signed-off-by: Max Stepanov <[email protected]>
Reviewed-by: Johannes Berg <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-drv.c | 39 +++++++++++++++++++++++
drivers/net/wireless/iwlwifi/iwl-fw-file.h | 1 +
drivers/net/wireless/iwlwifi/iwl-fw.h | 41 +++++++++++++++++++++++++
drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h | 10 +++++-
drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h | 1 +
drivers/net/wireless/iwlwifi/mvm/fw-api.h | 1 +
drivers/net/wireless/iwlwifi/mvm/mac80211.c | 13 +++++++-
drivers/net/wireless/iwlwifi/mvm/rx.c | 6 ++++
drivers/net/wireless/iwlwifi/mvm/sta.c | 8 ++---
drivers/net/wireless/iwlwifi/mvm/tx.c | 3 +-
10 files changed, 115 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c
index ff57002..4bebfb5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.c
@@ -322,6 +322,41 @@ static void set_sec_offset(struct iwl_firmware_pieces *pieces,
pieces->img[type].sec[sec].offset = offset;
}

+static int iwl_store_cscheme(struct iwl_fw *fw, const u8 *data, const u32 len)
+{
+ int i, j;
+ struct iwl_fw_cscheme_list *l = (struct iwl_fw_cscheme_list *)data;
+ struct iwl_fw_cipher_scheme *fwcs;
+ struct ieee80211_cipher_scheme *cs;
+ u32 cipher;
+
+ if (len < sizeof(*l) ||
+ len < sizeof(l->size) + l->size * sizeof(l->cs[0]))
+ return -EINVAL;
+
+ for (i = 0, j = 0; i < IWL_UCODE_MAX_CS && i < l->size; i++) {
+ fwcs = &l->cs[j];
+ cipher = le32_to_cpu(fwcs->cipher);
+
+ /* we skip schemes with zero cipher suite selector */
+ if (!cipher)
+ continue;
+
+ cs = &fw->cs[j++];
+ cs->cipher = cipher;
+ cs->iftype = BIT(NL80211_IFTYPE_STATION);
+ cs->hdr_len = fwcs->hdr_len;
+ cs->pn_len = fwcs->pn_len;
+ cs->pn_off = fwcs->pn_off;
+ cs->key_idx_off = fwcs->key_idx_off;
+ cs->key_idx_mask = fwcs->key_idx_mask;
+ cs->key_idx_shift = fwcs->key_idx_shift;
+ cs->mic_len = fwcs->mic_len;
+ }
+
+ return 0;
+}
+
/*
* Gets uCode section from tlv.
*/
@@ -729,6 +764,10 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
return -EINVAL;
}
break;
+ case IWL_UCODE_TLV_CSCHEME:
+ if (iwl_store_cscheme(&drv->fw, tlv_data, tlv_len))
+ goto invalid_tlv_len;
+ break;
default:
IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type);
break;
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
index 6c6c35c..4f95734 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
@@ -125,6 +125,7 @@ enum iwl_ucode_tlv_type {
IWL_UCODE_TLV_SECURE_SEC_INIT = 25,
IWL_UCODE_TLV_SECURE_SEC_WOWLAN = 26,
IWL_UCODE_TLV_NUM_OF_CPU = 27,
+ IWL_UCODE_TLV_CSCHEME = 28,
};

struct iwl_ucode_tlv {
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h
index 75db0871..b2a4c1d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw.h
@@ -209,6 +209,44 @@ enum iwl_fw_phy_cfg {
FW_PHY_CFG_RX_CHAIN = 0xf << FW_PHY_CFG_RX_CHAIN_POS,
};

+#define IWL_UCODE_MAX_CS 1
+
+/**
+ * struct iwl_fw_cipher_scheme - a cipher scheme supported by FW.
+ * @cipher: a cipher suite selector
+ * @flags: cipher scheme flags (currently reserved for a future use)
+ * @hdr_len: a size of MPDU security header
+ * @pn_len: a size of PN
+ * @pn_off: an offset of pn from the beginning of the security header
+ * @key_idx_off: an offset of key index byte in the security header
+ * @key_idx_mask: a bit mask of key_idx bits
+ * @key_idx_shift: bit shift needed to get key_idx
+ * @mic_len: mic length in bytes
+ * @hw_cipher: a HW cipher index used in host commands
+ */
+struct iwl_fw_cipher_scheme {
+ __le32 cipher;
+ u8 flags;
+ u8 hdr_len;
+ u8 pn_len;
+ u8 pn_off;
+ u8 key_idx_off;
+ u8 key_idx_mask;
+ u8 key_idx_shift;
+ u8 mic_len;
+ u8 hw_cipher;
+} __packed;
+
+/**
+ * struct iwl_fw_cscheme_list - a cipher scheme list
+ * @size: a number of entries
+ * @cs: cipher scheme entries
+ */
+struct iwl_fw_cscheme_list {
+ u8 size;
+ struct iwl_fw_cipher_scheme cs[];
+} __packed;
+
/**
* struct iwl_fw - variables associated with the firmware
*
@@ -224,6 +262,7 @@ enum iwl_fw_phy_cfg {
* @inst_evtlog_size: event log size for runtime ucode.
* @inst_errlog_ptr: error log offfset for runtime ucode.
* @mvm_fw: indicates this is MVM firmware
+ * @cipher_scheme: optional external cipher scheme.
*/
struct iwl_fw {
u32 ucode_ver;
@@ -243,6 +282,8 @@ struct iwl_fw {
u32 phy_config;

bool mvm_fw;
+
+ struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS];
};

static inline u8 iwl_fw_valid_tx_ant(const struct iwl_fw *fw)
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
index 4aca593..8c73ba7 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
@@ -138,7 +138,14 @@ enum iwl_sta_flags {

/**
* enum iwl_sta_key_flag - key flags for the ADD_STA host command
- * @STA_KEY_FLG_EN_MSK: mask for encryption algorithm
+ * @STA_KEY_FLG_NO_ENC: no encryption
+ * @STA_KEY_FLG_WEP: WEP encryption algorithm
+ * @STA_KEY_FLG_CCM: CCMP encryption algorithm
+ * @STA_KEY_FLG_TKIP: TKIP encryption algorithm
+ * @STA_KEY_FLG_EXT: extended cipher algorithm (depends on the FW support)
+ * @STA_KEY_FLG_CMAC: CMAC encryption algorithm
+ * @STA_KEY_FLG_ENC_UNKNOWN: unknown encryption algorithm
+ * @STA_KEY_FLG_EN_MSK: mask for encryption algorithmi value
* @STA_KEY_FLG_WEP_KEY_MAP: wep is either a group key (0 - legacy WEP) or from
* station info array (1 - n 1X mode)
* @STA_KEY_FLG_KEYID_MSK: the index of the key
@@ -152,6 +159,7 @@ enum iwl_sta_key_flag {
STA_KEY_FLG_WEP = (1 << 0),
STA_KEY_FLG_CCM = (2 << 0),
STA_KEY_FLG_TKIP = (3 << 0),
+ STA_KEY_FLG_EXT = (4 << 0),
STA_KEY_FLG_CMAC = (6 << 0),
STA_KEY_FLG_ENC_UNKNOWN = (7 << 0),
STA_KEY_FLG_EN_MSK = (7 << 0),
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
index d606197..2286467 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
@@ -132,6 +132,7 @@ enum iwl_tx_flags {
#define TX_CMD_SEC_WEP 0x01
#define TX_CMD_SEC_CCM 0x02
#define TX_CMD_SEC_TKIP 0x03
+#define TX_CMD_SEC_EXT 0x04
#define TX_CMD_SEC_MSK 0x07
#define TX_CMD_SEC_WEP_KEY_IDX_POS 6
#define TX_CMD_SEC_WEP_KEY_IDX_MSK 0xc0
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
index 3af4133..c9cfaad 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
@@ -1053,6 +1053,7 @@ enum iwl_mvm_rx_status {
RX_MPDU_RES_STATUS_SEC_WEP_ENC = (1 << 8),
RX_MPDU_RES_STATUS_SEC_CCM_ENC = (2 << 8),
RX_MPDU_RES_STATUS_SEC_TKIP_ENC = (3 << 8),
+ RX_MPDU_RES_STATUS_SEC_EXT_ENC = (4 << 8),
RX_MPDU_RES_STATUS_SEC_CCM_CMAC_ENC = (6 << 8),
RX_MPDU_RES_STATUS_SEC_ENC_ERR = (7 << 8),
RX_MPDU_RES_STATUS_SEC_ENC_MSK = (7 << 8),
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index f0f8b2c..8a99ecc 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -261,6 +261,12 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)

mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;

+ /* currently FW API supports only one optional cipher scheme */
+ if (mvm->fw->cs && mvm->fw->cs->cipher) {
+ mvm->hw->n_cipher_schemes = 1;
+ mvm->hw->cipher_schemes = mvm->fw->cs;
+ }
+
#ifdef CONFIG_PM_SLEEP
if (mvm->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
mvm->trans->ops->d3_suspend &&
@@ -1342,7 +1348,12 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
*/
return 0;
default:
- return -EOPNOTSUPP;
+ /* currently FW supports only one optional cipher scheme */
+ if (hw->n_cipher_schemes &&
+ hw->cipher_schemes->cipher == key->cipher)
+ key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
+ else
+ return -EOPNOTSUPP;
}

mutex_lock(&mvm->mutex);
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c
index 3a1f398..454341c 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rx.c
@@ -251,6 +251,12 @@ static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm,
stats->flag |= RX_FLAG_DECRYPTED;
return 0;

+ case RX_MPDU_RES_STATUS_SEC_EXT_ENC:
+ if (!(rx_pkt_status & RX_MPDU_RES_STATUS_MIC_OK))
+ return -1;
+ stats->flag |= RX_FLAG_DECRYPTED;
+ return 0;
+
default:
IWL_ERR(mvm, "Unhandled alg: 0x%x\n", rx_pkt_status);
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c
index 7a5b747..4ea00da 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.c
@@ -1123,8 +1123,8 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
memcpy(cmd.key, keyconf->key, keyconf->keylen);
break;
default:
- WARN_ON(1);
- return -EINVAL;
+ key_flags |= cpu_to_le16(STA_KEY_FLG_EXT);
+ memcpy(cmd.key, keyconf->key, keyconf->keylen);
}

if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE))
@@ -1288,8 +1288,8 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
0, NULL, CMD_SYNC);
break;
default:
- IWL_ERR(mvm, "Unknown cipher %x\n", keyconf->cipher);
- ret = -EINVAL;
+ ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf,
+ sta_id, 0, NULL, CMD_SYNC);
}

if (ret)
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c
index d87649a..735f86d 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tx.c
@@ -253,8 +253,7 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm,
memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen);
break;
default:
- IWL_ERR(mvm, "Unknown encode cipher %x\n", keyconf->cipher);
- break;
+ tx_cmd->sec_ctl |= TX_CMD_SEC_EXT;
}
}

--
1.7.9.5


2013-12-17 20:45:12

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 18/36] iwlwifi: trans: prevent tx and cmds during FW error

From: Arik Nemtsov <[email protected]>

Stop Tx and commands from arriving to the transport layer when a FW
error has occurred. A HW recovery should take place before. Remove
transport specific checks of the same nature (note that not all
transports were protected).

Signed-off-by: Arik Nemtsov <[email protected]>
Reviewed-by: Johannes Berg <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-trans.h | 6 ++++++
drivers/net/wireless/iwlwifi/pcie/tx.c | 3 ---
2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index 6419603..c71519d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -620,6 +620,9 @@ static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
{
int ret;

+ if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status)))
+ return -EIO;
+
if (unlikely(trans->state != IWL_TRANS_FW_ALIVE)) {
IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
return -EIO;
@@ -659,6 +662,9 @@ static inline void iwl_trans_free_tx_cmd(struct iwl_trans *trans,
static inline int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb,
struct iwl_device_cmd *dev_cmd, int queue)
{
+ if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status)))
+ return -EIO;
+
if (unlikely(trans->state != IWL_TRANS_FW_ALIVE))
IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);

diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c
index a36884e..5b63948 100644
--- a/drivers/net/wireless/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/tx.c
@@ -1606,9 +1606,6 @@ cancel:

int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
{
- if (test_bit(STATUS_FW_ERROR, &trans->status))
- return -EIO;
-
if (!(cmd->flags & CMD_SEND_IN_RFKILL) &&
test_bit(STATUS_RFKILL, &trans->status)) {
IWL_DEBUG_RF_KILL(trans, "Dropping CMD 0x%x: RF KILL\n",
--
1.7.9.5


2013-12-17 20:45:13

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 19/36] iwlwifi: mvm: rs: move rs_program_fix_rate to cleanup ifdefs

From: Eyal Shapira <[email protected]>

Move rs_program_fix_rate right before it's caller where we're
already in the context of an ifdef CPTCFG_MAC80211_DEBUGFS so
we can get rid of the extra ifdefs surrounding the original
location.

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

diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index bf6e29f..83306a0 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -504,30 +504,6 @@ static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type)
return (ant_type & valid_antenna) == ant_type;
}

-#ifdef CONFIG_MAC80211_DEBUGFS
-/**
- * Program the device to use fixed rate for frame transmit
- * This is for debugging/testing only
- * once the device start use fixed rate, we need to reload the module
- * to being back the normal operation.
- */
-static void rs_program_fix_rate(struct iwl_mvm *mvm,
- struct iwl_lq_sta *lq_sta)
-{
- lq_sta->active_legacy_rate = 0x0FFF; /* 1 - 54 MBits, includes CCK */
- lq_sta->active_siso_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */
- lq_sta->active_mimo2_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */
-
- IWL_DEBUG_RATE(mvm, "sta_id %d rate 0x%X\n",
- lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate);
-
- if (lq_sta->dbg_fixed_rate) {
- rs_fill_link_cmd(NULL, NULL, lq_sta, lq_sta->dbg_fixed_rate);
- iwl_mvm_send_lq_cmd(lq_sta->drv, &lq_sta->lq, false);
- }
-}
-#endif
-
static int rs_tl_turn_on_agg_for_tid(struct iwl_mvm *mvm,
struct iwl_lq_sta *lq_data, u8 tid,
struct ieee80211_sta *sta)
@@ -2612,6 +2588,28 @@ static int rs_pretty_print_rate(char *buf, const u32 rate)
(rate & RATE_MCS_ZLF_MSK) ? "ZLF " : "");
}

+/**
+ * Program the device to use fixed rate for frame transmit
+ * This is for debugging/testing only
+ * once the device start use fixed rate, we need to reload the module
+ * to being back the normal operation.
+ */
+static void rs_program_fix_rate(struct iwl_mvm *mvm,
+ struct iwl_lq_sta *lq_sta)
+{
+ lq_sta->active_legacy_rate = 0x0FFF; /* 1 - 54 MBits, includes CCK */
+ lq_sta->active_siso_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */
+ lq_sta->active_mimo2_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */
+
+ IWL_DEBUG_RATE(mvm, "sta_id %d rate 0x%X\n",
+ lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate);
+
+ if (lq_sta->dbg_fixed_rate) {
+ rs_fill_link_cmd(NULL, NULL, lq_sta, lq_sta->dbg_fixed_rate);
+ iwl_mvm_send_lq_cmd(lq_sta->drv, &lq_sta->lq, false);
+ }
+}
+
static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
const char __user *user_buf, size_t count, loff_t *ppos)
{
--
1.7.9.5


2013-12-17 20:45:04

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 13/36] iwlwifi: mvm: add multicast filtering support

From: Eliad Peller <[email protected]>

Configure the fw to filter multicast according to
the addresses given by mac80211.

Note that bssid should be given even if we want
to pass all the multicast frames.

Signed-off-by: Eliad Peller <[email protected]>
Reviewed-by: Johannes Berg <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/fw-api.h | 1 +
drivers/net/wireless/iwlwifi/mvm/mac80211.c | 111 +++++++++++++++++++++++----
drivers/net/wireless/iwlwifi/mvm/mvm.h | 1 +
drivers/net/wireless/iwlwifi/mvm/ops.c | 2 +
4 files changed, 102 insertions(+), 13 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
index d0b9399..1c30797 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
@@ -1134,6 +1134,7 @@ struct iwl_set_calib_default_cmd {
} __packed; /* PHY_CALIB_OVERRIDE_VALUES_S */

#define MAX_PORT_ID_NUM 2
+#define MAX_MCAST_FILTERING_ADDRESSES 256

/**
* struct iwl_mcast_filter_cmd - configure multicast filter.
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 9a27f57..01b58fc 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -755,26 +755,109 @@ static int iwl_mvm_mac_config(struct ieee80211_hw *hw, u32 changed)
return 0;
}

+struct iwl_mvm_mc_iter_data {
+ struct iwl_mvm *mvm;
+ int port_id;
+};
+
+static void iwl_mvm_mc_iface_iterator(void *_data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_mvm_mc_iter_data *data = _data;
+ struct iwl_mvm *mvm = data->mvm;
+ struct iwl_mcast_filter_cmd *cmd = mvm->mcast_filter_cmd;
+ int ret, len;
+
+ /* if we don't have free ports, mcast frames will be dropped */
+ if (WARN_ON_ONCE(data->port_id >= MAX_PORT_ID_NUM))
+ return;
+
+ if (vif->type != NL80211_IFTYPE_STATION ||
+ !vif->bss_conf.assoc)
+ return;
+
+ cmd->port_id = data->port_id++;
+ memcpy(cmd->bssid, vif->bss_conf.bssid, ETH_ALEN);
+ len = roundup(sizeof(*cmd) + cmd->count * ETH_ALEN, 4);
+
+ ret = iwl_mvm_send_cmd_pdu(mvm, MCAST_FILTER_CMD, CMD_SYNC, len, cmd);
+ if (ret)
+ IWL_ERR(mvm, "mcast filter cmd error. ret=%d\n", ret);
+}
+
+static void iwl_mvm_recalc_multicast(struct iwl_mvm *mvm)
+{
+ struct iwl_mvm_mc_iter_data iter_data = {
+ .mvm = mvm,
+ };
+
+ lockdep_assert_held(&mvm->mutex);
+
+ if (WARN_ON_ONCE(!mvm->mcast_filter_cmd))
+ return;
+
+ ieee80211_iterate_active_interfaces(
+ mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+ iwl_mvm_mc_iface_iterator, &iter_data);
+}
+
+static u64 iwl_mvm_prepare_multicast(struct ieee80211_hw *hw,
+ struct netdev_hw_addr_list *mc_list)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ struct iwl_mcast_filter_cmd *cmd;
+ struct netdev_hw_addr *addr;
+ int addr_count = netdev_hw_addr_list_count(mc_list);
+ bool pass_all = false;
+ int len;
+
+ if (addr_count > MAX_MCAST_FILTERING_ADDRESSES) {
+ pass_all = true;
+ addr_count = 0;
+ }
+
+ len = roundup(sizeof(*cmd) + addr_count * ETH_ALEN, 4);
+ cmd = kzalloc(len, GFP_ATOMIC);
+ if (!cmd)
+ return 0;
+
+ if (pass_all) {
+ cmd->pass_all = 1;
+ return (u64)(unsigned long)cmd;
+ }
+
+ netdev_hw_addr_list_for_each(addr, mc_list) {
+ IWL_DEBUG_MAC80211(mvm, "mcast addr (%d): %pM\n",
+ cmd->count, addr->addr);
+ memcpy(&cmd->addr_list[cmd->count * ETH_ALEN],
+ addr->addr, ETH_ALEN);
+ cmd->count++;
+ }
+
+ return (u64)(unsigned long)cmd;
+}
+
static void iwl_mvm_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *total_flags,
u64 multicast)
{
- *total_flags = 0;
-}
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ struct iwl_mcast_filter_cmd *cmd = (void *)(unsigned long)multicast;

-static int iwl_mvm_configure_mcast_filter(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif)
-{
- struct iwl_mcast_filter_cmd mcast_filter_cmd = {
- .pass_all = 1,
- };
+ mutex_lock(&mvm->mutex);

- memcpy(mcast_filter_cmd.bssid, vif->bss_conf.bssid, ETH_ALEN);
+ /* replace previous configuration */
+ kfree(mvm->mcast_filter_cmd);
+ mvm->mcast_filter_cmd = cmd;

- return iwl_mvm_send_cmd_pdu(mvm, MCAST_FILTER_CMD, CMD_SYNC,
- sizeof(mcast_filter_cmd),
- &mcast_filter_cmd);
+ if (!cmd)
+ goto out;
+
+ iwl_mvm_recalc_multicast(mvm);
+out:
+ mutex_unlock(&mvm->mutex);
+ *total_flags = 0;
}

static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
@@ -797,7 +880,6 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
IWL_ERR(mvm, "failed to update quotas\n");
return;
}
- iwl_mvm_configure_mcast_filter(mvm, vif);

if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART,
&mvm->status)) {
@@ -841,6 +923,8 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
IWL_ERR(mvm, "failed to update quotas\n");
}

+ iwl_mvm_recalc_multicast(mvm);
+
/* reset rssi values */
mvmvif->bf_data.ave_beacon_signal = 0;

@@ -1764,6 +1848,7 @@ struct ieee80211_ops iwl_mvm_hw_ops = {
.add_interface = iwl_mvm_mac_add_interface,
.remove_interface = iwl_mvm_mac_remove_interface,
.config = iwl_mvm_mac_config,
+ .prepare_multicast = iwl_mvm_prepare_multicast,
.configure_filter = iwl_mvm_configure_filter,
.bss_info_changed = iwl_mvm_bss_info_changed,
.hw_scan = iwl_mvm_mac_hw_scan,
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index 7295f8e..4275720 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -488,6 +488,7 @@ struct iwl_mvm {
/* Scan status, cmd (pre-allocated) and auxiliary station */
enum iwl_scan_status scan_status;
struct iwl_scan_cmd *scan_cmd;
+ struct iwl_mcast_filter_cmd *mcast_filter_cmd;

/* rx chain antennas set through debugfs for the scan command */
u8 scan_rx_ant;
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
index 2e9af9f..668525f 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -495,6 +495,8 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
ieee80211_unregister_hw(mvm->hw);

kfree(mvm->scan_cmd);
+ kfree(mvm->mcast_filter_cmd);
+ mvm->mcast_filter_cmd = NULL;

#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS)
kfree(mvm->d3_resume_sram);
--
1.7.9.5


2013-12-17 20:45:01

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 11/36] iwlwifi: mvm: add per-vif power debugfs hooks

From: Alexander Bondar <[email protected]>

This allows to tweak the power parameters per vif.

Signed-off-by: Alexander Bondar <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c | 353 ++++++++++++++++++++++++
drivers/net/wireless/iwlwifi/mvm/power.c | 7 +
2 files changed, 360 insertions(+)

diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
index 67f6a20..747adff 100644
--- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
+++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
@@ -63,6 +63,150 @@
#include "mvm.h"
#include "debugfs.h"

+static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ enum iwl_dbgfs_pm_mask param, int val)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_dbgfs_pm *dbgfs_pm = &mvmvif->dbgfs_pm;
+
+ dbgfs_pm->mask |= param;
+
+ switch (param) {
+ case MVM_DEBUGFS_PM_KEEP_ALIVE: {
+ struct ieee80211_hw *hw = mvm->hw;
+ int dtimper = hw->conf.ps_dtim_period ?: 1;
+ int dtimper_msec = dtimper * vif->bss_conf.beacon_int;
+
+ IWL_DEBUG_POWER(mvm, "debugfs: set keep_alive= %d sec\n", val);
+ if (val * MSEC_PER_SEC < 3 * dtimper_msec)
+ IWL_WARN(mvm,
+ "debugfs: keep alive period (%ld msec) is less than minimum required (%d msec)\n",
+ val * MSEC_PER_SEC, 3 * dtimper_msec);
+ dbgfs_pm->keep_alive_seconds = val;
+ break;
+ }
+ case MVM_DEBUGFS_PM_SKIP_OVER_DTIM:
+ IWL_DEBUG_POWER(mvm, "skip_over_dtim %s\n",
+ val ? "enabled" : "disabled");
+ dbgfs_pm->skip_over_dtim = val;
+ break;
+ case MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS:
+ IWL_DEBUG_POWER(mvm, "skip_dtim_periods=%d\n", val);
+ dbgfs_pm->skip_dtim_periods = val;
+ break;
+ case MVM_DEBUGFS_PM_RX_DATA_TIMEOUT:
+ IWL_DEBUG_POWER(mvm, "rx_data_timeout=%d\n", val);
+ dbgfs_pm->rx_data_timeout = val;
+ break;
+ case MVM_DEBUGFS_PM_TX_DATA_TIMEOUT:
+ IWL_DEBUG_POWER(mvm, "tx_data_timeout=%d\n", val);
+ dbgfs_pm->tx_data_timeout = val;
+ break;
+ case MVM_DEBUGFS_PM_DISABLE_POWER_OFF:
+ IWL_DEBUG_POWER(mvm, "disable_power_off=%d\n", val);
+ dbgfs_pm->disable_power_off = val;
+ break;
+ case MVM_DEBUGFS_PM_LPRX_ENA:
+ IWL_DEBUG_POWER(mvm, "lprx %s\n", val ? "enabled" : "disabled");
+ dbgfs_pm->lprx_ena = val;
+ break;
+ case MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD:
+ IWL_DEBUG_POWER(mvm, "lprx_rssi_threshold=%d\n", val);
+ dbgfs_pm->lprx_rssi_threshold = val;
+ break;
+ case MVM_DEBUGFS_PM_SNOOZE_ENABLE:
+ IWL_DEBUG_POWER(mvm, "snooze_enable=%d\n", val);
+ dbgfs_pm->snooze_ena = val;
+ break;
+ case MVM_DEBUGFS_PM_UAPSD_MISBEHAVING:
+ IWL_DEBUG_POWER(mvm, "uapsd_misbehaving_enable=%d\n", val);
+ dbgfs_pm->uapsd_misbehaving = val;
+ break;
+ }
+}
+
+static ssize_t iwl_dbgfs_pm_params_write(struct ieee80211_vif *vif, char *buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm *mvm = mvmvif->mvm;
+ enum iwl_dbgfs_pm_mask param;
+ int val, ret;
+
+ if (!strncmp("keep_alive=", buf, 11)) {
+ if (sscanf(buf + 11, "%d", &val) != 1)
+ return -EINVAL;
+ param = MVM_DEBUGFS_PM_KEEP_ALIVE;
+ } else if (!strncmp("skip_over_dtim=", buf, 15)) {
+ if (sscanf(buf + 15, "%d", &val) != 1)
+ return -EINVAL;
+ param = MVM_DEBUGFS_PM_SKIP_OVER_DTIM;
+ } else if (!strncmp("skip_dtim_periods=", buf, 18)) {
+ if (sscanf(buf + 18, "%d", &val) != 1)
+ return -EINVAL;
+ param = MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS;
+ } else if (!strncmp("rx_data_timeout=", buf, 16)) {
+ if (sscanf(buf + 16, "%d", &val) != 1)
+ return -EINVAL;
+ param = MVM_DEBUGFS_PM_RX_DATA_TIMEOUT;
+ } else if (!strncmp("tx_data_timeout=", buf, 16)) {
+ if (sscanf(buf + 16, "%d", &val) != 1)
+ return -EINVAL;
+ param = MVM_DEBUGFS_PM_TX_DATA_TIMEOUT;
+ } else if (!strncmp("disable_power_off=", buf, 18) &&
+ !(mvm->fw->ucode_capa.flags &
+ IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD)) {
+ if (sscanf(buf + 18, "%d", &val) != 1)
+ return -EINVAL;
+ param = MVM_DEBUGFS_PM_DISABLE_POWER_OFF;
+ } else if (!strncmp("lprx=", buf, 5)) {
+ if (sscanf(buf + 5, "%d", &val) != 1)
+ return -EINVAL;
+ param = MVM_DEBUGFS_PM_LPRX_ENA;
+ } else if (!strncmp("lprx_rssi_threshold=", buf, 20)) {
+ if (sscanf(buf + 20, "%d", &val) != 1)
+ return -EINVAL;
+ if (val > POWER_LPRX_RSSI_THRESHOLD_MAX || val <
+ POWER_LPRX_RSSI_THRESHOLD_MIN)
+ return -EINVAL;
+ param = MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD;
+ } else if (!strncmp("snooze_enable=", buf, 14)) {
+ if (sscanf(buf + 14, "%d", &val) != 1)
+ return -EINVAL;
+ param = MVM_DEBUGFS_PM_SNOOZE_ENABLE;
+ } else if (!strncmp("uapsd_misbehaving=", buf, 18)) {
+ if (sscanf(buf + 18, "%d", &val) != 1)
+ return -EINVAL;
+ param = MVM_DEBUGFS_PM_UAPSD_MISBEHAVING;
+ } else {
+ return -EINVAL;
+ }
+
+ mutex_lock(&mvm->mutex);
+ iwl_dbgfs_update_pm(mvm, vif, param, val);
+ ret = iwl_mvm_power_update_mode(mvm, vif);
+ mutex_unlock(&mvm->mutex);
+
+ return ret ?: count;
+}
+
+static ssize_t iwl_dbgfs_pm_params_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ieee80211_vif *vif = file->private_data;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm *mvm = mvmvif->mvm;
+ char buf[512];
+ int bufsz = sizeof(buf);
+ int pos;
+
+ pos = iwl_mvm_power_dbgfs_read(mvm, vif, buf, bufsz);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
@@ -122,6 +266,201 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}

+static void iwl_dbgfs_update_bf(struct ieee80211_vif *vif,
+ enum iwl_dbgfs_bf_mask param, int value)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_dbgfs_bf *dbgfs_bf = &mvmvif->dbgfs_bf;
+
+ dbgfs_bf->mask |= param;
+
+ switch (param) {
+ case MVM_DEBUGFS_BF_ENERGY_DELTA:
+ dbgfs_bf->bf_energy_delta = value;
+ break;
+ case MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA:
+ dbgfs_bf->bf_roaming_energy_delta = value;
+ break;
+ case MVM_DEBUGFS_BF_ROAMING_STATE:
+ dbgfs_bf->bf_roaming_state = value;
+ break;
+ case MVM_DEBUGFS_BF_TEMP_THRESHOLD:
+ dbgfs_bf->bf_temp_threshold = value;
+ break;
+ case MVM_DEBUGFS_BF_TEMP_FAST_FILTER:
+ dbgfs_bf->bf_temp_fast_filter = value;
+ break;
+ case MVM_DEBUGFS_BF_TEMP_SLOW_FILTER:
+ dbgfs_bf->bf_temp_slow_filter = value;
+ break;
+ case MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER:
+ dbgfs_bf->bf_enable_beacon_filter = value;
+ break;
+ case MVM_DEBUGFS_BF_DEBUG_FLAG:
+ dbgfs_bf->bf_debug_flag = value;
+ break;
+ case MVM_DEBUGFS_BF_ESCAPE_TIMER:
+ dbgfs_bf->bf_escape_timer = value;
+ break;
+ case MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT:
+ dbgfs_bf->ba_enable_beacon_abort = value;
+ break;
+ case MVM_DEBUGFS_BA_ESCAPE_TIMER:
+ dbgfs_bf->ba_escape_timer = value;
+ break;
+ }
+}
+
+static ssize_t iwl_dbgfs_bf_params_write(struct ieee80211_vif *vif, char *buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm *mvm = mvmvif->mvm;
+ enum iwl_dbgfs_bf_mask param;
+ int value, ret = 0;
+
+ if (!strncmp("bf_energy_delta=", buf, 16)) {
+ if (sscanf(buf+16, "%d", &value) != 1)
+ return -EINVAL;
+ if (value < IWL_BF_ENERGY_DELTA_MIN ||
+ value > IWL_BF_ENERGY_DELTA_MAX)
+ return -EINVAL;
+ param = MVM_DEBUGFS_BF_ENERGY_DELTA;
+ } else if (!strncmp("bf_roaming_energy_delta=", buf, 24)) {
+ if (sscanf(buf+24, "%d", &value) != 1)
+ return -EINVAL;
+ if (value < IWL_BF_ROAMING_ENERGY_DELTA_MIN ||
+ value > IWL_BF_ROAMING_ENERGY_DELTA_MAX)
+ return -EINVAL;
+ param = MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA;
+ } else if (!strncmp("bf_roaming_state=", buf, 17)) {
+ if (sscanf(buf+17, "%d", &value) != 1)
+ return -EINVAL;
+ if (value < IWL_BF_ROAMING_STATE_MIN ||
+ value > IWL_BF_ROAMING_STATE_MAX)
+ return -EINVAL;
+ param = MVM_DEBUGFS_BF_ROAMING_STATE;
+ } else if (!strncmp("bf_temp_threshold=", buf, 18)) {
+ if (sscanf(buf+18, "%d", &value) != 1)
+ return -EINVAL;
+ if (value < IWL_BF_TEMP_THRESHOLD_MIN ||
+ value > IWL_BF_TEMP_THRESHOLD_MAX)
+ return -EINVAL;
+ param = MVM_DEBUGFS_BF_TEMP_THRESHOLD;
+ } else if (!strncmp("bf_temp_fast_filter=", buf, 20)) {
+ if (sscanf(buf+20, "%d", &value) != 1)
+ return -EINVAL;
+ if (value < IWL_BF_TEMP_FAST_FILTER_MIN ||
+ value > IWL_BF_TEMP_FAST_FILTER_MAX)
+ return -EINVAL;
+ param = MVM_DEBUGFS_BF_TEMP_FAST_FILTER;
+ } else if (!strncmp("bf_temp_slow_filter=", buf, 20)) {
+ if (sscanf(buf+20, "%d", &value) != 1)
+ return -EINVAL;
+ if (value < IWL_BF_TEMP_SLOW_FILTER_MIN ||
+ value > IWL_BF_TEMP_SLOW_FILTER_MAX)
+ return -EINVAL;
+ param = MVM_DEBUGFS_BF_TEMP_SLOW_FILTER;
+ } else if (!strncmp("bf_enable_beacon_filter=", buf, 24)) {
+ if (sscanf(buf+24, "%d", &value) != 1)
+ return -EINVAL;
+ if (value < 0 || value > 1)
+ return -EINVAL;
+ param = MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER;
+ } else if (!strncmp("bf_debug_flag=", buf, 14)) {
+ if (sscanf(buf+14, "%d", &value) != 1)
+ return -EINVAL;
+ if (value < 0 || value > 1)
+ return -EINVAL;
+ param = MVM_DEBUGFS_BF_DEBUG_FLAG;
+ } else if (!strncmp("bf_escape_timer=", buf, 16)) {
+ if (sscanf(buf+16, "%d", &value) != 1)
+ return -EINVAL;
+ if (value < IWL_BF_ESCAPE_TIMER_MIN ||
+ value > IWL_BF_ESCAPE_TIMER_MAX)
+ return -EINVAL;
+ param = MVM_DEBUGFS_BF_ESCAPE_TIMER;
+ } else if (!strncmp("ba_escape_timer=", buf, 16)) {
+ if (sscanf(buf+16, "%d", &value) != 1)
+ return -EINVAL;
+ if (value < IWL_BA_ESCAPE_TIMER_MIN ||
+ value > IWL_BA_ESCAPE_TIMER_MAX)
+ return -EINVAL;
+ param = MVM_DEBUGFS_BA_ESCAPE_TIMER;
+ } else if (!strncmp("ba_enable_beacon_abort=", buf, 23)) {
+ if (sscanf(buf+23, "%d", &value) != 1)
+ return -EINVAL;
+ if (value < 0 || value > 1)
+ return -EINVAL;
+ param = MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT;
+ } else {
+ return -EINVAL;
+ }
+
+ mutex_lock(&mvm->mutex);
+ iwl_dbgfs_update_bf(vif, param, value);
+ if (param == MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER && !value)
+ ret = iwl_mvm_disable_beacon_filter(mvm, vif);
+ else
+ ret = iwl_mvm_enable_beacon_filter(mvm, vif);
+ mutex_unlock(&mvm->mutex);
+
+ return ret ?: count;
+}
+
+static ssize_t iwl_dbgfs_bf_params_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ieee80211_vif *vif = file->private_data;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ char buf[256];
+ int pos = 0;
+ const size_t bufsz = sizeof(buf);
+ struct iwl_beacon_filter_cmd cmd = {
+ IWL_BF_CMD_CONFIG_DEFAULTS,
+ .bf_enable_beacon_filter =
+ cpu_to_le32(IWL_BF_ENABLE_BEACON_FILTER_DEFAULT),
+ .ba_enable_beacon_abort =
+ cpu_to_le32(IWL_BA_ENABLE_BEACON_ABORT_DEFAULT),
+ };
+
+ iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd);
+ if (mvmvif->bf_data.bf_enabled)
+ cmd.bf_enable_beacon_filter = cpu_to_le32(1);
+ else
+ cmd.bf_enable_beacon_filter = 0;
+
+ pos += scnprintf(buf+pos, bufsz-pos, "bf_energy_delta = %d\n",
+ le32_to_cpu(cmd.bf_energy_delta));
+ pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_energy_delta = %d\n",
+ le32_to_cpu(cmd.bf_roaming_energy_delta));
+ pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_state = %d\n",
+ le32_to_cpu(cmd.bf_roaming_state));
+ pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_threshold = %d\n",
+ le32_to_cpu(cmd.bf_temp_threshold));
+ pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_fast_filter = %d\n",
+ le32_to_cpu(cmd.bf_temp_fast_filter));
+ pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_slow_filter = %d\n",
+ le32_to_cpu(cmd.bf_temp_slow_filter));
+ pos += scnprintf(buf+pos, bufsz-pos, "bf_enable_beacon_filter = %d\n",
+ le32_to_cpu(cmd.bf_enable_beacon_filter));
+ pos += scnprintf(buf+pos, bufsz-pos, "bf_debug_flag = %d\n",
+ le32_to_cpu(cmd.bf_debug_flag));
+ pos += scnprintf(buf+pos, bufsz-pos, "bf_escape_timer = %d\n",
+ le32_to_cpu(cmd.bf_escape_timer));
+ pos += scnprintf(buf+pos, bufsz-pos, "ba_escape_timer = %d\n",
+ le32_to_cpu(cmd.ba_escape_timer));
+ pos += scnprintf(buf+pos, bufsz-pos, "ba_enable_beacon_abort = %d\n",
+ le32_to_cpu(cmd.ba_enable_beacon_abort));
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+#define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
+ _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
+#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
+ _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
#define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do { \
if (!debugfs_create_file(#name, mode, parent, vif, \
&iwl_dbgfs_##name##_ops)) \
@@ -129,6 +468,8 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
} while (0)

MVM_DEBUGFS_READ_FILE_OPS(mac_params);
+MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32);
+MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256);

void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
@@ -152,9 +493,21 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
return;
}

+ if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM &&
+ ((vif->type == NL80211_IFTYPE_STATION && !vif->p2p) ||
+ (vif->type == NL80211_IFTYPE_STATION && vif->p2p &&
+ mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS)))
+ MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, S_IWUSR |
+ S_IRUSR);
+
MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir,
S_IRUSR);

+ if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
+ mvmvif == mvm->bf_allowed_vif)
+ MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir,
+ S_IRUSR | S_IWUSR);
+
/*
* Create symlink for convenience pointing to interface specific
* debugfs entries for the driver. For example, under
diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c
index 0ef4674..d173ea2 100644
--- a/drivers/net/wireless/iwlwifi/mvm/power.c
+++ b/drivers/net/wireless/iwlwifi/mvm/power.c
@@ -406,6 +406,13 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
cmd->flags &=
cpu_to_le16(~POWER_FLAGS_SNOOZE_ENA_MSK);
}
+ if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_UAPSD_MISBEHAVING) {
+ u16 flag = POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK;
+ if (mvmvif->dbgfs_pm.uapsd_misbehaving)
+ cmd->flags |= cpu_to_le16(flag);
+ else
+ cmd->flags &= cpu_to_le16(flag);
+ }
#endif /* CONFIG_IWLWIFI_DEBUGFS */
}

--
1.7.9.5


2013-12-17 20:45:14

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 20/36] iwlwifi: remove pointer to transport from op_mode

From: Emmanuel Grumbach <[email protected]>

This pointer was not used anywhere.

Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-op-mode.h | 4 +---
drivers/net/wireless/iwlwifi/mvm/ops.c | 1 -
2 files changed, 1 insertion(+), 4 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h
index 976448a..f50e6c6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-op-mode.h
+++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h
@@ -155,14 +155,12 @@ void iwl_opmode_deregister(const char *name);

/**
* struct iwl_op_mode - operational mode
+ * @ops - pointer to its own ops
*
* This holds an implementation of the mac80211 / fw API.
- *
- * @ops - pointer to its own ops
*/
struct iwl_op_mode {
const struct iwl_op_mode_ops *ops;
- const struct iwl_trans *trans;

char op_mode_specific[0] __aligned(sizeof(void *));
};
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
index a6f4be8..ef3fdcf 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -344,7 +344,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,

op_mode = hw->priv;
op_mode->ops = &iwl_mvm_ops;
- op_mode->trans = trans;

mvm = IWL_OP_MODE_GET_MVM(op_mode);
mvm->dev = trans->dev;
--
1.7.9.5


2013-12-17 20:45:03

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 12/36] iwlwifi: mvm: move iwl_mvm_set_tx_power to PHY area

From: Emmanuel Grumbach <[email protected]>

This is more related to phy contexts than to mac context.
Move this function to there.

Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/mac80211.c | 28 +++++++++++++--------------
1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index b42ce2c..9a27f57 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -516,6 +516,20 @@ static struct iwl_mvm_phy_ctxt *iwl_mvm_get_free_phy_ctxt(struct iwl_mvm *mvm)
return NULL;
}

+static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ s8 tx_power)
+{
+ /* FW is in charge of regulatory enforcement */
+ struct iwl_reduce_tx_power_cmd reduce_txpwr_cmd = {
+ .mac_context_id = iwl_mvm_vif_from_mac80211(vif)->id,
+ .pwr_restriction = cpu_to_le16(tx_power),
+ };
+
+ return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, CMD_SYNC,
+ sizeof(reduce_txpwr_cmd),
+ &reduce_txpwr_cmd);
+}
+
static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
@@ -736,20 +750,6 @@ out_release:
mutex_unlock(&mvm->mutex);
}

-static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- s8 tx_power)
-{
- /* FW is in charge of regulatory enforcement */
- struct iwl_reduce_tx_power_cmd reduce_txpwr_cmd = {
- .mac_context_id = iwl_mvm_vif_from_mac80211(vif)->id,
- .pwr_restriction = cpu_to_le16(tx_power),
- };
-
- return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, CMD_SYNC,
- sizeof(reduce_txpwr_cmd),
- &reduce_txpwr_cmd);
-}
-
static int iwl_mvm_mac_config(struct ieee80211_hw *hw, u32 changed)
{
return 0;
--
1.7.9.5


2013-12-17 20:45:29

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 31/36] iwlwifi: mvm: fixup Makefile

From: Emmanuel Grumbach <[email protected]>

debufs.o appeared twice in the Makefile. Fix that.

Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/mvm/Makefile | 1 -
1 file changed, 1 deletion(-)

diff --git a/drivers/net/wireless/iwlwifi/mvm/Makefile b/drivers/net/wireless/iwlwifi/mvm/Makefile
index 3ea47ab..f98ec2b 100644
--- a/drivers/net/wireless/iwlwifi/mvm/Makefile
+++ b/drivers/net/wireless/iwlwifi/mvm/Makefile
@@ -4,7 +4,6 @@ iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o sf.o
iwlmvm-y += scan.o time-event.o rs.o
iwlmvm-y += power.o power_legacy.o bt-coex.o
iwlmvm-y += led.o tt.o
-iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o
iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o
iwlmvm-$(CONFIG_PM_SLEEP) += d3.o

--
1.7.9.5


2013-12-17 20:45:00

by Emmanuel Grumbach

[permalink] [raw]
Subject: [PATCH 10/36] iwlwifi: mvm: Enable power save on a single P2P client interface

From: Alexander Bondar <[email protected]>

Enable power save on P2P client interface only if it is the
only bound interface.
Avoid using uAPSD if P2P client is associated to GO that uses
opportunistic power save. This is due to current FW limitation.

Signed-off-by: Alexander Bondar <[email protected]>
Reviewed-by: Johannes Berg <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-fw.h | 3 +++
drivers/net/wireless/iwlwifi/mvm/mac80211.c | 3 ++-
drivers/net/wireless/iwlwifi/mvm/power.c | 22 +++++++++++++++++++---
3 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h
index b2a4c1d..959562d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw.h
@@ -92,6 +92,8 @@
* @IWL_UCODE_TLV_FLAGS_STA_KEY_CMD: new ADD_STA and ADD_STA_KEY command API
* @IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD: support device wide power command
* containing CAM (Continuous Active Mode) indication.
+ * @IWL_UCODE_TLV_FLAGS_P2P_PS: P2P client power save is supported (only on a
+ * single bound interface).
*/
enum iwl_ucode_tlv_flag {
IWL_UCODE_TLV_FLAGS_PAN = BIT(0),
@@ -113,6 +115,7 @@ enum iwl_ucode_tlv_flag {
IWL_UCODE_TLV_FLAGS_SCHED_SCAN = BIT(17),
IWL_UCODE_TLV_FLAGS_STA_KEY_CMD = BIT(19),
IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD = BIT(20),
+ IWL_UCODE_TLV_FLAGS_P2P_PS = BIT(21),
IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT = BIT(24),
};

diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index d36105f..b42ce2c 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -861,7 +861,8 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
*/
iwl_mvm_remove_time_event(mvm, mvmvif,
&mvmvif->time_event_data);
- } else if (changes & (BSS_CHANGED_PS | BSS_CHANGED_QOS)) {
+ } else if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS |
+ BSS_CHANGED_QOS)) {
ret = iwl_mvm_power_update_mode(mvm, vif);
if (ret)
IWL_ERR(mvm, "failed to update power mode\n");
diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c
index cfed105..0ef4674 100644
--- a/drivers/net/wireless/iwlwifi/mvm/power.c
+++ b/drivers/net/wireless/iwlwifi/mvm/power.c
@@ -284,6 +284,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
bool radar_detect = false;
struct iwl_mvm_vif *mvmvif __maybe_unused =
iwl_mvm_vif_from_mac80211(vif);
+ bool allow_uapsd = true;

cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
mvmvif->color));
@@ -354,8 +355,19 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT);
}

- if (memcmp(mvmvif->uapsd_misbehaving_bssid, vif->bss_conf.bssid,
- ETH_ALEN))
+ if (!memcmp(mvmvif->uapsd_misbehaving_bssid, vif->bss_conf.bssid,
+ ETH_ALEN))
+ allow_uapsd = false;
+ /*
+ * Avoid using uAPSD if P2P client is associated to GO that uses
+ * opportunistic power save. This is due to current FW limitation.
+ */
+ if (vif->p2p &&
+ vif->bss_conf.p2p_noa_attr.oppps_ctwindow &
+ IEEE80211_P2P_OPPPS_ENABLE_BIT)
+ allow_uapsd = false;
+
+ if (allow_uapsd)
iwl_mvm_power_configure_uapsd(mvm, vif, cmd);

#ifdef CONFIG_IWLWIFI_DEBUGFS
@@ -404,7 +416,11 @@ static int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm,
bool ba_enable;
struct iwl_mac_power_cmd cmd = {};

- if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
+ if (vif->type != NL80211_IFTYPE_STATION)
+ return 0;
+
+ if (vif->p2p &&
+ !(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS))
return 0;

iwl_mvm_power_build_cmd(mvm, vif, &cmd);
--
1.7.9.5


2014-01-16 20:08:58

by Emmanuel Grumbach

[permalink] [raw]
Subject: Re: [PATCH 08/36] iwlwifi: mvm: Change power management dependency on multi MAC

>>>
>>> Hi,
>>>
>>> This broke monitor mode:
>>> (unsetting .power_update_binding does not hang)
>>>
>>> modprobe iwlmvm
>>> iw dev wlan0 set type monitor
>>> iw dev wlan0 set freq 5180 40 5190 # hangs
>>>
>>> Can you reproduce it easily or do you need me to post further dbg info ?
>>>
>>
>> We have an open bug on this internally - thanks for reporting.
>
> OK, BTW I have errors like
> - "Microcode SW error detected." upon monitor up

reading your mail again - is this related to monitor mode or not?

> - "iwlwifi 0000:02:00.0: FW error in SYNC CMD TXPATH_FLUSH" sometimes
> after the subsequent ieee80211_restart_hw
> - "WARNING: ... iwlwifi/mvm/binding.c:201 iwl_mvm_binding_remove_vif"
> when removing a monitor iface
>
> You must have seen those too. I will avoid this tree with iwlwifi then.
>

I probably misunderstood this last sentence?

2014-01-13 11:15:58

by Grumbach, Emmanuel

[permalink] [raw]
Subject: RE: [PATCH 08/36] iwlwifi: mvm: Change power management dependency on multi MAC

PiA+DQo+ID4gRlcgc3RpbGwgZG9lcyBub3Qgc3VwcG9ydCBwb3dlciBtYW5hZ2VtZW50IG9uIG11
bHRpcGxlIE1BQyBpbnRlcmZhY2VzLg0KPiA+IEN1cnJlbnRseSB0aGUgZHJpdmVyIGVuZm9yY2Ug
dGhpcyBsaW1pdGF0aW9uIGJ5IGRpc2FibGluZyBQTSBpZiBzZWNvbmQNCj4gPiBpbnRlcmZhY2Ug
aXMgYWRkZWQuIENoYW5nZSB0aGlzIGJlaGF2aW9yIHRvIGFsbG93IFBNIG9uIGEgc2luZ2xlDQo+
ID4gaW50ZXJmYWNlIGV2ZW4gaWYgb3RoZXIgaW50ZXJmYWNlcyBleGlzdCBidXQgbm90IGJvdW5k
IHRvIGFueSBzcGVjaWZpYyBQSFkuDQo+ID4gUE0gd2lsbCBiZSBlbmFibGVkIGlmIG9ubHkgb25l
IHNpbmdsZSBpbnRlcmZhY2UgaXMgYm91bmQuDQo+ID4NCj4gPiBTaWduZWQtb2ZmLWJ5OiBBbGV4
YW5kZXIgQm9uZGFyIDxhbGV4YW5kZXIuYm9uZGFyQGludGVsLmNvbT4NCj4gPiBSZXZpZXdlZC1i
eTogSm9oYW5uZXMgQmVyZyA8am9oYW5uZXMuYmVyZ0BpbnRlbC5jb20+DQo+ID4gU2lnbmVkLW9m
Zi1ieTogRW1tYW51ZWwgR3J1bWJhY2ggPGVtbWFudWVsLmdydW1iYWNoQGludGVsLmNvbT4NCj4g
DQo+IEhpLA0KPiANCj4gVGhpcyBicm9rZSBtb25pdG9yIG1vZGU6DQo+ICh1bnNldHRpbmcgLnBv
d2VyX3VwZGF0ZV9iaW5kaW5nIGRvZXMgbm90IGhhbmcpDQo+IA0KPiBtb2Rwcm9iZSBpd2xtdm0N
Cj4gaXcgZGV2IHdsYW4wIHNldCB0eXBlIG1vbml0b3INCj4gaXcgZGV2IHdsYW4wIHNldCBmcmVx
IDUxODAgNDAgNTE5MCAgIyBoYW5ncw0KPiANCj4gQ2FuIHlvdSByZXByb2R1Y2UgaXQgZWFzaWx5
IG9yIGRvIHlvdSBuZWVkIG1lIHRvIHBvc3QgZnVydGhlciBkYmcgaW5mbyA/DQo+IA0KDQpXZSBo
YXZlIGFuIG9wZW4gYnVnIG9uIHRoaXMgaW50ZXJuYWxseSAtIHRoYW5rcyBmb3IgcmVwb3J0aW5n
Lg0K

2014-01-13 11:14:41

by Karl Beldan

[permalink] [raw]
Subject: Re: [PATCH 08/36] iwlwifi: mvm: Change power management dependency on multi MAC

On Tue, Dec 17, 2013 at 10:44:11PM +0200, Emmanuel Grumbach wrote:
> From: Alexander Bondar <[email protected]>
>
> FW still does not support power management on multiple MAC interfaces.
> Currently the driver enforce this limitation by disabling PM if second
> interface is added. Change this behavior to allow PM on a single interface
> even if other interfaces exist but not bound to any specific PHY.
> PM will be enabled if only one single interface is bound.
>
> Signed-off-by: Alexander Bondar <[email protected]>
> Reviewed-by: Johannes Berg <[email protected]>
> Signed-off-by: Emmanuel Grumbach <[email protected]>

Hi,

This broke monitor mode:
(unsetting .power_update_binding does not hang)

modprobe iwlmvm
iw dev wlan0 set type monitor
iw dev wlan0 set freq 5180 40 5190 # hangs

Can you reproduce it easily or do you need me to post further dbg info ?


Karl

2014-01-13 12:41:51

by Karl Beldan

[permalink] [raw]
Subject: Re: [PATCH 08/36] iwlwifi: mvm: Change power management dependency on multi MAC

On Mon, Jan 13, 2014 at 11:15:53AM +0000, Grumbach, Emmanuel wrote:
> > >
> > > FW still does not support power management on multiple MAC interfaces.
> > > Currently the driver enforce this limitation by disabling PM if second
> > > interface is added. Change this behavior to allow PM on a single
> > > interface even if other interfaces exist but not bound to any specific PHY.
> > > PM will be enabled if only one single interface is bound.
> > >
> > > Signed-off-by: Alexander Bondar <[email protected]>
> > > Reviewed-by: Johannes Berg <[email protected]>
> > > Signed-off-by: Emmanuel Grumbach <[email protected]>
> >
> > Hi,
> >
> > This broke monitor mode:
> > (unsetting .power_update_binding does not hang)
> >
> > modprobe iwlmvm
> > iw dev wlan0 set type monitor
> > iw dev wlan0 set freq 5180 40 5190 # hangs
> >
> > Can you reproduce it easily or do you need me to post further dbg info ?
> >
>
> We have an open bug on this internally - thanks for reporting.

OK, BTW I have errors like
- "Microcode SW error detected." upon monitor up
- "iwlwifi 0000:02:00.0: FW error in SYNC CMD TXPATH_FLUSH" sometimes
after the subsequent ieee80211_restart_hw
- "WARNING: ... iwlwifi/mvm/binding.c:201 iwl_mvm_binding_remove_vif"
when removing a monitor iface

You must have seen those too. I will avoid this tree with iwlwifi then.


Karl

2014-01-16 21:39:53

by Karl Beldan

[permalink] [raw]
Subject: Re: [PATCH 08/36] iwlwifi: mvm: Change power management dependency on multi MAC

On Thu, Jan 16, 2014 at 10:08:54PM +0200, Emmanuel Grumbach wrote:
> >>>
> >>> Hi,
> >>>
> >>> This broke monitor mode:
> >>> (unsetting .power_update_binding does not hang)
> >>>
> >>> modprobe iwlmvm
> >>> iw dev wlan0 set type monitor
> >>> iw dev wlan0 set freq 5180 40 5190 # hangs
> >>>
> >>> Can you reproduce it easily or do you need me to post further dbg info ?
> >>>
> >>
> >> We have an open bug on this internally - thanks for reporting.
> >
> > OK, BTW I have errors like
> > - "Microcode SW error detected." upon monitor up
>
> reading your mail again - is this related to monitor mode or not?
>
Yes, at least that's part of what I meant by "upon monitor up", it seems
to happen systematically when I bring a monitor iface up.

> > - "iwlwifi 0000:02:00.0: FW error in SYNC CMD TXPATH_FLUSH" sometimes
> > after the subsequent ieee80211_restart_hw
> > - "WARNING: ... iwlwifi/mvm/binding.c:201 iwl_mvm_binding_remove_vif"
> > when removing a monitor iface
> >
> > You must have seen those too. I will avoid this tree with iwlwifi then.
> >
>
> I probably misunderstood this last sentence?

I ecountered many problems with mvm in this tree, Eyal quickly fixed the
rs unending search cycle, you told me the monitor deadlock was already
filed internally on your side, the ones I mentioned in this thread, also
it seems that with the 7260-8.ucode I don't get anything on a monitor
iface except the mere traffic of another associated iface (when I have
such one).
Except maybe for the latter?, these bugs seem easy enough to trigger
and alarming enough that I suspect you already must be on your way to
fixing what you deem needs to .. and thus I did not feel bad not
dissecting or reporting further and droping this tree with iwlwifi.
I hope this clarifies the meaning and intention of the last sentence.

I have been using the 7260 since last summer and, as I already mentioned
to Johannes, found it very useful, and wouldn't mind giving some
other out-of-tree patches a go.


Karl

2014-02-13 12:01:44

by Emmanuel Grumbach

[permalink] [raw]
Subject: Re: [PATCH 08/36] iwlwifi: mvm: Change power management dependency on multi MAC

On Thu, Jan 16, 2014 at 11:43 PM, Karl Beldan <[email protected]> wrote:
> On Thu, Jan 16, 2014 at 10:08:54PM +0200, Emmanuel Grumbach wrote:
>> >>>
>> >>> Hi,
>> >>>
>> >>> This broke monitor mode:
>> >>> (unsetting .power_update_binding does not hang)
>> >>>
>> >>> modprobe iwlmvm
>> >>> iw dev wlan0 set type monitor
>> >>> iw dev wlan0 set freq 5180 40 5190 # hangs
>> >>>
>> >>> Can you reproduce it easily or do you need me to post further dbg info ?
>> >>>
>> >>
>> >> We have an open bug on this internally - thanks for reporting.
>> >
>> > OK, BTW I have errors like
>> > - "Microcode SW error detected." upon monitor up
>>
>> reading your mail again - is this related to monitor mode or not?
>>
> Yes, at least that's part of what I meant by "upon monitor up", it seems
> to happen systematically when I bring a monitor iface up.
>
>> > - "iwlwifi 0000:02:00.0: FW error in SYNC CMD TXPATH_FLUSH" sometimes
>> > after the subsequent ieee80211_restart_hw
>> > - "WARNING: ... iwlwifi/mvm/binding.c:201 iwl_mvm_binding_remove_vif"
>> > when removing a monitor iface
>> >
>> > You must have seen those too. I will avoid this tree with iwlwifi then.
>> >
>>
>> I probably misunderstood this last sentence?
>
> I ecountered many problems with mvm in this tree, Eyal quickly fixed the
> rs unending search cycle, you told me the monitor deadlock was already
> filed internally on your side, the ones I mentioned in this thread, also
> it seems that with the 7260-8.ucode I don't get anything on a monitor
> iface except the mere traffic of another associated iface (when I have
> such one).
> Except maybe for the latter?, these bugs seem easy enough to trigger
> and alarming enough that I suspect you already must be on your way to
> fixing what you deem needs to .. and thus I did not feel bad not
> dissecting or reporting further and droping this tree with iwlwifi.
> I hope this clarifies the meaning and intention of the last sentence.
>
> I have been using the 7260 since last summer and, as I already mentioned
> to Johannes, found it very useful, and wouldn't mind giving some
> other out-of-tree patches a go.
>

Monitor mode should work with latest wireless-testing now.

2014-03-06 11:59:14

by Karl Beldan

[permalink] [raw]
Subject: Re: [PATCH 08/36] iwlwifi: mvm: Change power management dependency on multi MAC

On Thu, Mar 06, 2014 at 10:22:49AM +0000, Grumbach, Emmanuel wrote:
> >
> > Hi,
> >
> > Thanks for the update, indeed monitor is in better shape, however I am
> > still seeing some issues.
> > E.g. short-guard or > 20MHz bw frames are not visible when not
> > aggregated, I still see "Microcode SW error detected." but in a
> > different scenario (monitoring with main managed iface down, then upping
> > the main managed iface up), it also seems that we filter out many frames
> > when the main managed iface is up and/or? associated.
> > Also, I started working on AMSDUs this week and yesterday my laptop
> > crashed immediately when monitoring. This morning I see that this
> > happens when my aggregates start getting above the ~4k limit and
> > modprobing with amsdu_size_8K=1 seems to 'fix' the issue, I guess some
> > places need some oflows checks.
> > All this with wireless-next@704445d9 (i.e. circa the time I got your
> > email) and fw 22.15.8.0.
> >
>
> Please paste the data for the firmware assert. Also, take https://git.kernel.org/cgit/linux/kernel/git/jberg/mac80211.git/commit/?id=1c37a72c1bd0b83be8b95cff7f1bc9b1f32bd433 into account.

Just tried it, does not help for >20MHz bw .. I think the fact that I
cannot see them when not aggregated but can when they are might be a
good lead.


Karl

2014-03-06 11:03:07

by Grumbach, Emmanuel

[permalink] [raw]
Subject: RE: [PATCH 08/36] iwlwifi: mvm: Change power management dependency on multi MAC

PiA+IE9uIFRodSwgTWFyIDA2LCAyMDE0IGF0IDEwOjI1OjM0QU0gKzAwMDAsIEdydW1iYWNoLCBF
bW1hbnVlbCB3cm90ZToNCj4gPiA+ID4gPg0KPiA+ID4gPiA+IEhpLA0KPiA+ID4gPiA+DQo+ID4g
PiA+ID4gVGhhbmtzIGZvciB0aGUgdXBkYXRlLCBpbmRlZWQgbW9uaXRvciBpcyBpbiBiZXR0ZXIg
c2hhcGUsDQo+ID4gPiA+ID4gaG93ZXZlciBJIGFtIHN0aWxsIHNlZWluZyBzb21lIGlzc3Vlcy4N
Cj4gPiA+ID4gPiBFLmcuIHNob3J0LWd1YXJkIG9yID4gMjBNSHogYncgZnJhbWVzIGFyZSBub3Qg
dmlzaWJsZSB3aGVuIG5vdA0KPiA+ID4gPiA+IGFnZ3JlZ2F0ZWQsIEkgc3RpbGwgc2VlICJNaWNy
b2NvZGUgU1cgZXJyb3IgZGV0ZWN0ZWQuIiBidXQgaW4gYQ0KPiA+ID4gPiA+IGRpZmZlcmVudCBz
Y2VuYXJpbyAobW9uaXRvcmluZyB3aXRoIG1haW4gbWFuYWdlZCBpZmFjZSBkb3duLA0KPiA+ID4g
PiA+IHRoZW4gdXBwaW5nIHRoZSBtYWluIG1hbmFnZWQgaWZhY2UgdXApLCBpdCBhbHNvIHNlZW1z
IHRoYXQgd2UNCj4gPiA+ID4gPiBmaWx0ZXIgb3V0IG1hbnkgZnJhbWVzIHdoZW4gdGhlIG1haW4g
bWFuYWdlZCBpZmFjZSBpcyB1cCBhbmQvb3I/DQo+ID4gYXNzb2NpYXRlZC4NCj4gPiA+ID4gPiBB
bHNvLCBJIHN0YXJ0ZWQgd29ya2luZyBvbiBBTVNEVXMgdGhpcyB3ZWVrIGFuZCB5ZXN0ZXJkYXkg
bXkNCj4gPiA+ID4gPiBsYXB0b3AgY3Jhc2hlZCBpbW1lZGlhdGVseSB3aGVuIG1vbml0b3Jpbmcu
IFRoaXMgbW9ybmluZyBJIHNlZQ0KPiA+ID4gPiA+IHRoYXQgdGhpcyBoYXBwZW5zIHdoZW4gbXkg
YWdncmVnYXRlcyBzdGFydCBnZXR0aW5nIGFib3ZlIHRoZSB+NGsNCj4gPiA+ID4gPiBsaW1pdCBh
bmQgbW9kcHJvYmluZyB3aXRoIGFtc2R1X3NpemVfOEs9MSBzZWVtcyB0byAnZml4JyB0aGUNCj4g
PiA+ID4gPiBpc3N1ZSwgSSBndWVzcyBzb21lIHBsYWNlcyBuZWVkIHNvbWUgb2Zsb3dzIGNoZWNr
cy4NCj4gPiA+DQo+ID4gPiBIbW0uLi4gVGhhbmtzIGZvciB0aGUgaGVhZHMgLSB1cC4gRG8geW91
IGhhdmUgdGhlIGNyYXNoIGRhdGE/DQo+ID4gPg0KPiA+IFlvdSBtZWFuIGEgcGNhcCBvZiB0aGUg
dHJhZmZpYyBjcmFzaGluZyB0aGUgc3lzdGVtIG9yIHRoZSBpd2xtdm0gZGF0YSA/DQo+ID4gVGhl
IGNyYXNoZXMgYXJlIHNldmVyZSBlbm91Z2ggdGhhdCB0aGV5IGhhbmcgbXkgd2hvbGUgbGFwdG9w
IHJpZ2h0IGF3YXkuDQo+IA0KPiBPaCBvayAtIEkgd2FzIHRhbGtpbmcgYWJvdXQgdGhlIFdBUk5J
TkcgLyBCVUcgbWVzc2FnZSB3aGF0ZXZlci4NCj4gDQo+ID4NCj4gPiA+ID4gPiBBbGwgdGhpcyB3
aXRoIHdpcmVsZXNzLW5leHRANzA0NDQ1ZDkgKGkuZS4gY2lyY2EgdGhlIHRpbWUgSSBnb3QNCj4g
PiA+ID4gPiB5b3VyDQo+ID4gPiA+ID4gZW1haWwpIGFuZCBmdyAyMi4xNS44LjAuDQo+ID4gPiA+
ID4NCj4gPiA+ID4NCj4gPiA+ID4gUGxlYXNlIHBhc3RlIHRoZSBkYXRhIGZvciB0aGUgZmlybXdh
cmUgYXNzZXJ0LiBBbHNvLCB0YWtlDQo+ID4gPiA+IGh0dHBzOi8vZ2l0Lmtlcm5lbC5vcmcvY2dp
dC9saW51eC9rZXJuZWwvZ2l0L2piZXJnL21hYzgwMjExLmdpdC9jbw0KPiA+ID4gPiBtbQ0KPiA+
ID4gPiBpdC8/aWQ9DQo+ID4gPiA+IDFjMzdhNzJjMWJkMGI4M2JlOGI5NWNmZjdmMWJjOWIxZjMy
YmQ0MzMgaW50byBhY2NvdW50Lg0KPiA+IEF0dGFjaGVkLiBMb29rcyBsaWtlIHRoaXMgY2hhbmdl
IHdpbGwgaGVscC4NCj4gPg0KPiANCj4gQlRXIC0gbmV3ZXIgRlcgaXMgYXZhaWxhYmxlOiAyMi4y
NC44LjANCg0KSnVzdCBsb29rZWQgYXQgeW91ciBsb2cgLSBJJ2QgaG9wZSB0aGUgbmV3IEZXIHdp
bGwgZml4IGl0Lg0KQ2FuIHlvdSBnaXZlIGl0IGEgdHJ5Pw0KDQo=

2014-03-06 11:54:18

by Karl Beldan

[permalink] [raw]
Subject: Re: [PATCH 08/36] iwlwifi: mvm: Change power management dependency on multi MAC

On Thu, Mar 06, 2014 at 11:02:48AM +0000, Grumbach, Emmanuel wrote:
> > > On Thu, Mar 06, 2014 at 10:25:34AM +0000, Grumbach, Emmanuel wrote:
> > > > > >
> > > > > > Hi,
> > > > > >
> > > > > > Thanks for the update, indeed monitor is in better shape,
> > > > > > however I am still seeing some issues.
> > > > > > E.g. short-guard or > 20MHz bw frames are not visible when not
> > > > > > aggregated, I still see "Microcode SW error detected." but in a
> > > > > > different scenario (monitoring with main managed iface down,
> > > > > > then upping the main managed iface up), it also seems that we
> > > > > > filter out many frames when the main managed iface is up and/or?
> > > associated.
> > > > > > Also, I started working on AMSDUs this week and yesterday my
> > > > > > laptop crashed immediately when monitoring. This morning I see
> > > > > > that this happens when my aggregates start getting above the ~4k
> > > > > > limit and modprobing with amsdu_size_8K=1 seems to 'fix' the
> > > > > > issue, I guess some places need some oflows checks.
> > > >
> > > > Hmm... Thanks for the heads - up. Do you have the crash data?
> > > >
> > > You mean a pcap of the traffic crashing the system or the iwlmvm data ?
> > > The crashes are severe enough that they hang my whole laptop right away.
> >
> > Oh ok - I was talking about the WARNING / BUG message whatever.
> >
> > >
> > > > > > All this with wireless-next@704445d9 (i.e. circa the time I got
> > > > > > your
> > > > > > email) and fw 22.15.8.0.
> > > > > >
> > > > >
> > > > > Please paste the data for the firmware assert. Also, take
> > > > > https://git.kernel.org/cgit/linux/kernel/git/jberg/mac80211.git/co
> > > > > mm
> > > > > it/?id=
> > > > > 1c37a72c1bd0b83be8b95cff7f1bc9b1f32bd433 into account.
> > > Attached. Looks like this change will help.
> > >
> >
> > BTW - newer FW is available: 22.24.8.0
>
> Just looked at your log - I'd hope the new FW will fix it.
> Can you give it a try?
>
Just did, seems to fix the issue, thanks.


Karl

2014-03-06 10:58:19

by Grumbach, Emmanuel

[permalink] [raw]
Subject: RE: [PATCH 08/36] iwlwifi: mvm: Change power management dependency on multi MAC

PiANCj4gT24gVGh1LCBNYXIgMDYsIDIwMTQgYXQgMTA6MjU6MzRBTSArMDAwMCwgR3J1bWJhY2gs
IEVtbWFudWVsIHdyb3RlOg0KPiA+ID4gPg0KPiA+ID4gPiBIaSwNCj4gPiA+ID4NCj4gPiA+ID4g
VGhhbmtzIGZvciB0aGUgdXBkYXRlLCBpbmRlZWQgbW9uaXRvciBpcyBpbiBiZXR0ZXIgc2hhcGUs
IGhvd2V2ZXINCj4gPiA+ID4gSSBhbSBzdGlsbCBzZWVpbmcgc29tZSBpc3N1ZXMuDQo+ID4gPiA+
IEUuZy4gc2hvcnQtZ3VhcmQgb3IgPiAyME1IeiBidyBmcmFtZXMgYXJlIG5vdCB2aXNpYmxlIHdo
ZW4gbm90DQo+ID4gPiA+IGFnZ3JlZ2F0ZWQsIEkgc3RpbGwgc2VlICJNaWNyb2NvZGUgU1cgZXJy
b3IgZGV0ZWN0ZWQuIiBidXQgaW4gYQ0KPiA+ID4gPiBkaWZmZXJlbnQgc2NlbmFyaW8gKG1vbml0
b3Jpbmcgd2l0aCBtYWluIG1hbmFnZWQgaWZhY2UgZG93biwgdGhlbg0KPiA+ID4gPiB1cHBpbmcg
dGhlIG1haW4gbWFuYWdlZCBpZmFjZSB1cCksIGl0IGFsc28gc2VlbXMgdGhhdCB3ZSBmaWx0ZXIN
Cj4gPiA+ID4gb3V0IG1hbnkgZnJhbWVzIHdoZW4gdGhlIG1haW4gbWFuYWdlZCBpZmFjZSBpcyB1
cCBhbmQvb3I/DQo+IGFzc29jaWF0ZWQuDQo+ID4gPiA+IEFsc28sIEkgc3RhcnRlZCB3b3JraW5n
IG9uIEFNU0RVcyB0aGlzIHdlZWsgYW5kIHllc3RlcmRheSBteQ0KPiA+ID4gPiBsYXB0b3AgY3Jh
c2hlZCBpbW1lZGlhdGVseSB3aGVuIG1vbml0b3JpbmcuIFRoaXMgbW9ybmluZyBJIHNlZQ0KPiA+
ID4gPiB0aGF0IHRoaXMgaGFwcGVucyB3aGVuIG15IGFnZ3JlZ2F0ZXMgc3RhcnQgZ2V0dGluZyBh
Ym92ZSB0aGUgfjRrDQo+ID4gPiA+IGxpbWl0IGFuZCBtb2Rwcm9iaW5nIHdpdGggYW1zZHVfc2l6
ZV84Sz0xIHNlZW1zIHRvICdmaXgnIHRoZQ0KPiA+ID4gPiBpc3N1ZSwgSSBndWVzcyBzb21lIHBs
YWNlcyBuZWVkIHNvbWUgb2Zsb3dzIGNoZWNrcy4NCj4gPg0KPiA+IEhtbS4uLiBUaGFua3MgZm9y
IHRoZSBoZWFkcyAtIHVwLiBEbyB5b3UgaGF2ZSB0aGUgY3Jhc2ggZGF0YT8NCj4gPg0KPiBZb3Ug
bWVhbiBhIHBjYXAgb2YgdGhlIHRyYWZmaWMgY3Jhc2hpbmcgdGhlIHN5c3RlbSBvciB0aGUgaXds
bXZtIGRhdGEgPw0KPiBUaGUgY3Jhc2hlcyBhcmUgc2V2ZXJlIGVub3VnaCB0aGF0IHRoZXkgaGFu
ZyBteSB3aG9sZSBsYXB0b3AgcmlnaHQgYXdheS4NCg0KT2ggb2sgLSBJIHdhcyB0YWxraW5nIGFi
b3V0IHRoZSBXQVJOSU5HIC8gQlVHIG1lc3NhZ2Ugd2hhdGV2ZXIuDQoNCj4gDQo+ID4gPiA+IEFs
bCB0aGlzIHdpdGggd2lyZWxlc3MtbmV4dEA3MDQ0NDVkOSAoaS5lLiBjaXJjYSB0aGUgdGltZSBJ
IGdvdA0KPiA+ID4gPiB5b3VyDQo+ID4gPiA+IGVtYWlsKSBhbmQgZncgMjIuMTUuOC4wLg0KPiA+
ID4gPg0KPiA+ID4NCj4gPiA+IFBsZWFzZSBwYXN0ZSB0aGUgZGF0YSBmb3IgdGhlIGZpcm13YXJl
IGFzc2VydC4gQWxzbywgdGFrZQ0KPiA+ID4gaHR0cHM6Ly9naXQua2VybmVsLm9yZy9jZ2l0L2xp
bnV4L2tlcm5lbC9naXQvamJlcmcvbWFjODAyMTEuZ2l0L2NvbW0NCj4gPiA+IGl0Lz9pZD0NCj4g
PiA+IDFjMzdhNzJjMWJkMGI4M2JlOGI5NWNmZjdmMWJjOWIxZjMyYmQ0MzMgaW50byBhY2NvdW50
Lg0KPiBBdHRhY2hlZC4gTG9va3MgbGlrZSB0aGlzIGNoYW5nZSB3aWxsIGhlbHAuDQo+IA0KDQpC
VFcgLSBuZXdlciBGVyBpcyBhdmFpbGFibGU6IDIyLjI0LjguMA0K

2014-03-06 10:21:10

by Karl Beldan

[permalink] [raw]
Subject: Re: [PATCH 08/36] iwlwifi: mvm: Change power management dependency on multi MAC

On Thu, Feb 13, 2014 at 02:01:43PM +0200, Emmanuel Grumbach wrote:
> Monitor mode should work with latest wireless-testing now.

Hi,

Thanks for the update, indeed monitor is in better shape, however I am
still seeing some issues.
E.g. short-guard or > 20MHz bw frames are not visible when not
aggregated, I still see "Microcode SW error detected." but in a
different scenario (monitoring with main managed iface down, then upping
the main managed iface up), it also seems that we filter out many frames
when the main managed iface is up and/or? associated.
Also, I started working on AMSDUs this week and yesterday my laptop
crashed immediately when monitoring. This morning I see that this
happens when my aggregates start getting above the ~4k limit and
modprobing with amsdu_size_8K=1 seems to 'fix' the issue, I guess some
places need some oflows checks.
All this with wireless-next@704445d9 (i.e. circa the time I got your
email) and fw 22.15.8.0.



Karl

2014-03-06 10:25:39

by Grumbach, Emmanuel

[permalink] [raw]
Subject: RE: [PATCH 08/36] iwlwifi: mvm: Change power management dependency on multi MAC

PiA+DQo+ID4gSGksDQo+ID4NCj4gPiBUaGFua3MgZm9yIHRoZSB1cGRhdGUsIGluZGVlZCBtb25p
dG9yIGlzIGluIGJldHRlciBzaGFwZSwgaG93ZXZlciBJIGFtDQo+ID4gc3RpbGwgc2VlaW5nIHNv
bWUgaXNzdWVzLg0KPiA+IEUuZy4gc2hvcnQtZ3VhcmQgb3IgPiAyME1IeiBidyBmcmFtZXMgYXJl
IG5vdCB2aXNpYmxlIHdoZW4gbm90DQo+ID4gYWdncmVnYXRlZCwgSSBzdGlsbCBzZWUgIk1pY3Jv
Y29kZSBTVyBlcnJvciBkZXRlY3RlZC4iIGJ1dCBpbiBhDQo+ID4gZGlmZmVyZW50IHNjZW5hcmlv
IChtb25pdG9yaW5nIHdpdGggbWFpbiBtYW5hZ2VkIGlmYWNlIGRvd24sIHRoZW4NCj4gPiB1cHBp
bmcgdGhlIG1haW4gbWFuYWdlZCBpZmFjZSB1cCksIGl0IGFsc28gc2VlbXMgdGhhdCB3ZSBmaWx0
ZXIgb3V0DQo+ID4gbWFueSBmcmFtZXMgd2hlbiB0aGUgbWFpbiBtYW5hZ2VkIGlmYWNlIGlzIHVw
IGFuZC9vcj8gYXNzb2NpYXRlZC4NCj4gPiBBbHNvLCBJIHN0YXJ0ZWQgd29ya2luZyBvbiBBTVNE
VXMgdGhpcyB3ZWVrIGFuZCB5ZXN0ZXJkYXkgbXkgbGFwdG9wDQo+ID4gY3Jhc2hlZCBpbW1lZGlh
dGVseSB3aGVuIG1vbml0b3JpbmcuIFRoaXMgbW9ybmluZyBJIHNlZSB0aGF0IHRoaXMNCj4gPiBo
YXBwZW5zIHdoZW4gbXkgYWdncmVnYXRlcyBzdGFydCBnZXR0aW5nIGFib3ZlIHRoZSB+NGsgbGlt
aXQgYW5kDQo+ID4gbW9kcHJvYmluZyB3aXRoIGFtc2R1X3NpemVfOEs9MSBzZWVtcyB0byAnZml4
JyB0aGUgaXNzdWUsIEkgZ3Vlc3Mgc29tZQ0KPiA+IHBsYWNlcyBuZWVkIHNvbWUgb2Zsb3dzIGNo
ZWNrcy4NCg0KSG1tLi4uIFRoYW5rcyBmb3IgdGhlIGhlYWRzIC0gdXAuIERvIHlvdSBoYXZlIHRo
ZSBjcmFzaCBkYXRhPw0KDQo+ID4gQWxsIHRoaXMgd2l0aCB3aXJlbGVzcy1uZXh0QDcwNDQ0NWQ5
IChpLmUuIGNpcmNhIHRoZSB0aW1lIEkgZ290IHlvdXINCj4gPiBlbWFpbCkgYW5kIGZ3IDIyLjE1
LjguMC4NCj4gPg0KPiANCj4gUGxlYXNlIHBhc3RlIHRoZSBkYXRhIGZvciB0aGUgZmlybXdhcmUg
YXNzZXJ0LiBBbHNvLCB0YWtlDQo+IGh0dHBzOi8vZ2l0Lmtlcm5lbC5vcmcvY2dpdC9saW51eC9r
ZXJuZWwvZ2l0L2piZXJnL21hYzgwMjExLmdpdC9jb21taXQvP2lkPQ0KPiAxYzM3YTcyYzFiZDBi
ODNiZThiOTVjZmY3ZjFiYzliMWYzMmJkNDMzIGludG8gYWNjb3VudC4NCg==

2014-03-06 10:23:04

by Grumbach, Emmanuel

[permalink] [raw]
Subject: RE: [PATCH 08/36] iwlwifi: mvm: Change power management dependency on multi MAC

PiANCj4gSGksDQo+IA0KPiBUaGFua3MgZm9yIHRoZSB1cGRhdGUsIGluZGVlZCBtb25pdG9yIGlz
IGluIGJldHRlciBzaGFwZSwgaG93ZXZlciBJIGFtDQo+IHN0aWxsIHNlZWluZyBzb21lIGlzc3Vl
cy4NCj4gRS5nLiBzaG9ydC1ndWFyZCBvciA+IDIwTUh6IGJ3IGZyYW1lcyBhcmUgbm90IHZpc2li
bGUgd2hlbiBub3QNCj4gYWdncmVnYXRlZCwgSSBzdGlsbCBzZWUgIk1pY3JvY29kZSBTVyBlcnJv
ciBkZXRlY3RlZC4iIGJ1dCBpbiBhDQo+IGRpZmZlcmVudCBzY2VuYXJpbyAobW9uaXRvcmluZyB3
aXRoIG1haW4gbWFuYWdlZCBpZmFjZSBkb3duLCB0aGVuIHVwcGluZw0KPiB0aGUgbWFpbiBtYW5h
Z2VkIGlmYWNlIHVwKSwgaXQgYWxzbyBzZWVtcyB0aGF0IHdlIGZpbHRlciBvdXQgbWFueSBmcmFt
ZXMNCj4gd2hlbiB0aGUgbWFpbiBtYW5hZ2VkIGlmYWNlIGlzIHVwIGFuZC9vcj8gYXNzb2NpYXRl
ZC4NCj4gQWxzbywgSSBzdGFydGVkIHdvcmtpbmcgb24gQU1TRFVzIHRoaXMgd2VlayBhbmQgeWVz
dGVyZGF5IG15IGxhcHRvcA0KPiBjcmFzaGVkIGltbWVkaWF0ZWx5IHdoZW4gbW9uaXRvcmluZy4g
VGhpcyBtb3JuaW5nIEkgc2VlIHRoYXQgdGhpcw0KPiBoYXBwZW5zIHdoZW4gbXkgYWdncmVnYXRl
cyBzdGFydCBnZXR0aW5nIGFib3ZlIHRoZSB+NGsgbGltaXQgYW5kDQo+IG1vZHByb2Jpbmcgd2l0
aCBhbXNkdV9zaXplXzhLPTEgc2VlbXMgdG8gJ2ZpeCcgdGhlIGlzc3VlLCBJIGd1ZXNzIHNvbWUN
Cj4gcGxhY2VzIG5lZWQgc29tZSBvZmxvd3MgY2hlY2tzLg0KPiBBbGwgdGhpcyB3aXRoIHdpcmVs
ZXNzLW5leHRANzA0NDQ1ZDkgKGkuZS4gY2lyY2EgdGhlIHRpbWUgSSBnb3QgeW91cg0KPiBlbWFp
bCkgYW5kIGZ3IDIyLjE1LjguMC4NCj4gDQoNClBsZWFzZSBwYXN0ZSB0aGUgZGF0YSBmb3IgdGhl
IGZpcm13YXJlIGFzc2VydC4gQWxzbywgdGFrZSBodHRwczovL2dpdC5rZXJuZWwub3JnL2NnaXQv
bGludXgva2VybmVsL2dpdC9qYmVyZy9tYWM4MDIxMS5naXQvY29tbWl0Lz9pZD0xYzM3YTcyYzFi
ZDBiODNiZThiOTVjZmY3ZjFiYzliMWYzMmJkNDMzIGludG8gYWNjb3VudC4NCg==

2014-03-06 10:49:47

by Karl Beldan

[permalink] [raw]
Subject: Re: [PATCH 08/36] iwlwifi: mvm: Change power management dependency on multi MAC

On Thu, Mar 06, 2014 at 10:25:34AM +0000, Grumbach, Emmanuel wrote:
> > >
> > > Hi,
> > >
> > > Thanks for the update, indeed monitor is in better shape, however I am
> > > still seeing some issues.
> > > E.g. short-guard or > 20MHz bw frames are not visible when not
> > > aggregated, I still see "Microcode SW error detected." but in a
> > > different scenario (monitoring with main managed iface down, then
> > > upping the main managed iface up), it also seems that we filter out
> > > many frames when the main managed iface is up and/or? associated.
> > > Also, I started working on AMSDUs this week and yesterday my laptop
> > > crashed immediately when monitoring. This morning I see that this
> > > happens when my aggregates start getting above the ~4k limit and
> > > modprobing with amsdu_size_8K=1 seems to 'fix' the issue, I guess some
> > > places need some oflows checks.
>
> Hmm... Thanks for the heads - up. Do you have the crash data?
>
You mean a pcap of the traffic crashing the system or the iwlmvm data ?
The crashes are severe enough that they hang my whole laptop right away.

> > > All this with wireless-next@704445d9 (i.e. circa the time I got your
> > > email) and fw 22.15.8.0.
> > >
> >
> > Please paste the data for the firmware assert. Also, take
> > https://git.kernel.org/cgit/linux/kernel/git/jberg/mac80211.git/commit/?id=
> > 1c37a72c1bd0b83be8b95cff7f1bc9b1f32bd433 into account.
Attached. Looks like this change will help.


Karl


Attachments:
(No filename) (1.44 kB)
iwlmvm.txt.gzip (3.73 kB)
Download all attachments