From 9180ac50716a097a407c6d7e7e4589754a922260 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 23 Sep 2014 23:02:41 +0300 Subject: iwlwifi: configure the LTR The LTR is the handshake between the device and the root complex about the latency allowed when the bus exits power save. This configuration was missing and this led to high latency in the link power up. The end user could experience high latency in the network because of this. Cc: [3.10+] Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-trans.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/fw-api-power.h | 35 ++++++++++++++++++++++++- drivers/net/wireless/iwlwifi/mvm/fw-api.h | 1 + drivers/net/wireless/iwlwifi/mvm/fw.c | 9 +++++++ drivers/net/wireless/iwlwifi/mvm/ops.c | 1 + drivers/net/wireless/iwlwifi/pcie/trans.c | 16 ++++++----- 6 files changed, 56 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 9eb85249e89c..d8fc548c0d6c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -563,6 +563,7 @@ enum iwl_trans_state { * Set during transport allocation. * @hw_id_str: a string with info about HW ID. Set during transport allocation. * @pm_support: set to true in start_hw if link pm is supported + * @ltr_enabled: set to true if the LTR is enabled * @dev_cmd_pool: pool for Tx cmd allocation - for internal use only. * The user should use iwl_trans_{alloc,free}_tx_cmd. * @dev_cmd_headroom: room needed for the transport's private use before the @@ -589,6 +590,7 @@ struct iwl_trans { u8 rx_mpdu_cmd, rx_mpdu_cmd_hdr_size; bool pm_support; + bool ltr_enabled; /* The following fields are internal only */ struct kmem_cache *dev_cmd_pool; diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h index 27dd86395b39..2fd8ad4633e0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h @@ -68,13 +68,46 @@ /* Power Management Commands, Responses, Notifications */ +/** + * enum iwl_ltr_config_flags - masks for LTR config command flags + * @LTR_CFG_FLAG_FEATURE_ENABLE: Feature operational status + * @LTR_CFG_FLAG_HW_DIS_ON_SHADOW_REG_ACCESS: allow LTR change on shadow + * memory access + * @LTR_CFG_FLAG_HW_EN_SHRT_WR_THROUGH: allow LTR msg send on ANY LTR + * reg change + * @LTR_CFG_FLAG_HW_DIS_ON_D0_2_D3: allow LTR msg send on transition from + * D0 to D3 + * @LTR_CFG_FLAG_SW_SET_SHORT: fixed static short LTR register + * @LTR_CFG_FLAG_SW_SET_LONG: fixed static short LONG register + * @LTR_CFG_FLAG_DENIE_C10_ON_PD: allow going into C10 on PD + */ +enum iwl_ltr_config_flags { + LTR_CFG_FLAG_FEATURE_ENABLE = BIT(0), + LTR_CFG_FLAG_HW_DIS_ON_SHADOW_REG_ACCESS = BIT(1), + LTR_CFG_FLAG_HW_EN_SHRT_WR_THROUGH = BIT(2), + LTR_CFG_FLAG_HW_DIS_ON_D0_2_D3 = BIT(3), + LTR_CFG_FLAG_SW_SET_SHORT = BIT(4), + LTR_CFG_FLAG_SW_SET_LONG = BIT(5), + LTR_CFG_FLAG_DENIE_C10_ON_PD = BIT(6), +}; + +/** + * struct iwl_ltr_config_cmd - configures the LTR + * @flags: See %enum iwl_ltr_config_flags + */ +struct iwl_ltr_config_cmd { + __le32 flags; + __le32 static_long; + __le32 static_short; +} __packed; + /* Radio LP RX Energy Threshold measured in dBm */ #define POWER_LPRX_RSSI_THRESHOLD 75 #define POWER_LPRX_RSSI_THRESHOLD_MAX 94 #define POWER_LPRX_RSSI_THRESHOLD_MIN 30 /** - * enum iwl_scan_flags - masks for power table command flags + * enum iwl_power_flags - masks for power table command flags * @POWER_FLAGS_POWER_SAVE_ENA_MSK: '1' Allow to save power by turning off * receiver and transmitter. '0' - does not allow. * @POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK: '0' Driver disables power management, diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 667a92274c87..c62575d86bcd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -157,6 +157,7 @@ enum { /* Power - legacy power table command */ POWER_TABLE_CMD = 0x77, PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION = 0x78, + LTR_CONFIG = 0xee, /* Thermal Throttling*/ REPLY_THERMAL_MNG_BACKOFF = 0x7e, diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index 23fd711a67e4..e0d9f19650b0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -480,6 +480,15 @@ int iwl_mvm_up(struct iwl_mvm *mvm) /* Initialize tx backoffs to the minimal possible */ iwl_mvm_tt_tx_backoff(mvm, 0); + if (mvm->trans->ltr_enabled) { + struct iwl_ltr_config_cmd cmd = { + .flags = cpu_to_le32(LTR_CFG_FLAG_FEATURE_ENABLE), + }; + + WARN_ON(iwl_mvm_send_cmd_pdu(mvm, LTR_CONFIG, 0, + sizeof(cmd), &cmd)); + } + ret = iwl_mvm_power_update_device(mvm); if (ret) goto error; diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 15aa298ee79c..48cb25a93591 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -336,6 +336,7 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = { CMD(DTS_MEASUREMENT_NOTIFICATION), CMD(REPLY_THERMAL_MNG_BACKOFF), CMD(MAC_PM_POWER_TABLE), + CMD(LTR_CONFIG), CMD(BT_COEX_CI), CMD(BT_COEX_UPDATE_SW_BOOST), CMD(BT_COEX_UPDATE_CORUN_LUT), diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 1393bac0025c..c706dba67cdd 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -174,6 +174,7 @@ static void iwl_pcie_apm_config(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); u16 lctl; + u16 cap; /* * HW bug W/A for instability in PCIe bus L0S->L1 transition. @@ -184,16 +185,17 @@ static void iwl_pcie_apm_config(struct iwl_trans *trans) * power savings, even without L1. */ pcie_capability_read_word(trans_pcie->pci_dev, PCI_EXP_LNKCTL, &lctl); - if (lctl & PCI_EXP_LNKCTL_ASPM_L1) { - /* L1-ASPM enabled; disable(!) L0S */ + if (lctl & PCI_EXP_LNKCTL_ASPM_L1) iwl_set_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); - dev_info(trans->dev, "L1 Enabled; Disabling L0S\n"); - } else { - /* L1-ASPM disabled; enable(!) L0S */ + else iwl_clear_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); - dev_info(trans->dev, "L1 Disabled; Enabling L0S\n"); - } trans->pm_support = !(lctl & PCI_EXP_LNKCTL_ASPM_L0S); + + pcie_capability_read_word(trans_pcie->pci_dev, PCI_EXP_DEVCTL2, &cap); + trans->ltr_enabled = cap & PCI_EXP_DEVCTL2_LTR_EN; + dev_info(trans->dev, "L1 %sabled - LTR %sabled\n", + (lctl & PCI_EXP_LNKCTL_ASPM_L1) ? "En" : "Dis", + trans->ltr_enabled ? "En" : "Dis"); } /* -- cgit v1.2.3 From 405b7338abc5ceac4a420ce7f49cc9b530d4e78b Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Tue, 23 Sep 2014 15:15:17 +0300 Subject: iwlwifi: 8000: fix string given to MODULE_FIRMWARE I changed the string but forgot to update the fix also to MODULE_FIRMWARE(). Signed-off-by: Liad Kaufman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-8000.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index e4351487ca72..d2b7234b1c73 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -82,7 +82,8 @@ #define IWL8000_TX_POWER_VERSION 0xffff /* meaningless */ #define IWL8000_FW_PRE "iwlwifi-8000" -#define IWL8000_MODULE_FIRMWARE(api) IWL8000_FW_PRE __stringify(api) ".ucode" +#define IWL8000_MODULE_FIRMWARE(api) \ + IWL8000_FW_PRE "-" __stringify(api) ".ucode" #define NVM_HW_SECTION_NUM_FAMILY_8000 10 #define DEFAULT_NVM_FILE_FAMILY_8000 "iwl_nvm_8000.bin" -- cgit v1.2.3 From d14b28fd2c61af0bf310230472e342864d799c98 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 22 Sep 2014 16:12:24 +0300 Subject: iwlwifi: mvm: BT Coex - update the MPLUT Boost register value Cc: [3.16+] Fixes: 2adc8949efab ("iwlwifi: mvm: BT Coex - fix boost register / LUT values") Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/coex.c | 4 ++-- drivers/net/wireless/iwlwifi/mvm/coex_legacy.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index 8df2021f9856..da2ffb785194 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -303,8 +303,8 @@ static const __le64 iwl_ci_mask[][3] = { }; static const __le32 iwl_bt_mprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE] = { - cpu_to_le32(0x28412201), - cpu_to_le32(0x11118451), + cpu_to_le32(0x2e402280), + cpu_to_le32(0x7711a751), }; struct corunning_block_luts { diff --git a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c index 585c0ab4a3ec..8a1d2f33d5b7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c @@ -291,8 +291,8 @@ static const __le64 iwl_ci_mask[][3] = { }; static const __le32 iwl_bt_mprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE] = { - cpu_to_le32(0x28412201), - cpu_to_le32(0x11118451), + cpu_to_le32(0x2e402280), + cpu_to_le32(0x7711a751), }; struct corunning_block_luts { -- cgit v1.2.3 From 3856b78c1be32a2afe0618c7a84e05ff8c03cf10 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 22 Sep 2014 12:03:41 +0300 Subject: iwlwifi: mvm: BT coex - fix BT prio for probe requests The probe requests sent during scan must get BT prio 3. Fix that. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/scan.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index cb85e63c20aa..b280d5d87127 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -459,7 +459,8 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm, basic_ssid ? 1 : 0); cmd->tx_cmd.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL | - TX_CMD_FLG_BT_DIS); + 3 << TX_CMD_FLG_BT_PRIO_POS); + cmd->tx_cmd.sta_id = mvm->aux_sta.sta_id; cmd->tx_cmd.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); cmd->tx_cmd.rate_n_flags = -- cgit v1.2.3 From 79b7a69d730180d8bf535e52fe2b4f3dd5904007 Mon Sep 17 00:00:00 2001 From: Haim Dreyfuss Date: Sun, 14 Sep 2014 12:40:00 +0300 Subject: iwlwifi: mvm: Add tx power condition to bss_info_changed_ap_ibss The tx power should be limited from many reasons. currently, setting the tx power is available by the mvm only for station interface. Adding the tx power condition to bss_info_changed_ap_ibss make it available also for AP. Signed-off-by: Haim Dreyfuss Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index c7a73c68bdab..892a6bc26686 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1734,6 +1734,13 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm, if (changes & BSS_CHANGED_BEACON && iwl_mvm_mac_ctxt_beacon_changed(mvm, vif)) IWL_WARN(mvm, "Failed updating beacon data\n"); + + if (changes & BSS_CHANGED_TXPOWER) { + IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d\n", + bss_conf->txpower); + iwl_mvm_set_tx_power(mvm, vif, bss_conf->txpower); + } + } static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw, -- cgit v1.2.3 From a6cc5163149532734b84c86cbffa4994e527074b Mon Sep 17 00:00:00 2001 From: Matti Gottlieb Date: Mon, 29 Sep 2014 11:46:04 +0300 Subject: iwlwifi: mvm: ROC - bug fixes around time events and locking Don't add the time event to the list. We added it several times the same time event, which leads to an infinite loop when walking the list. Since we (currently) don't support more than one ROC for STA vif at a time, enforce this and don't add the time event to any list. We were also missing the locking of the mutex which led to a lockdep splat - fix that. Signed-off-by: Matti Gottlieb Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 25 ++++++++++++++++--------- drivers/net/wireless/iwlwifi/mvm/time-event.c | 2 +- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 892a6bc26686..585fe5b7100f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -526,7 +526,8 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw, } if (IEEE80211_SKB_CB(skb)->hw_queue == IWL_MVM_OFFCHANNEL_QUEUE && - !test_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status)) + !test_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status) && + !test_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status)) goto drop; /* treat non-bufferable MMPDUs as broadcast if sta is sleeping */ @@ -2374,14 +2375,19 @@ static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm, /* Set the node address */ memcpy(aux_roc_req.node_addr, vif->addr, ETH_ALEN); + lockdep_assert_held(&mvm->mutex); + + spin_lock_bh(&mvm->time_event_lock); + + if (WARN_ON(te_data->id == HOT_SPOT_CMD)) { + spin_unlock_bh(&mvm->time_event_lock); + return -EIO; + } + te_data->vif = vif; te_data->duration = duration; te_data->id = HOT_SPOT_CMD; - lockdep_assert_held(&mvm->mutex); - - spin_lock_bh(&mvm->time_event_lock); - list_add_tail(&te_data->list, &mvm->time_event_list); spin_unlock_bh(&mvm->time_event_lock); /* @@ -2437,22 +2443,23 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value, duration, type); + mutex_lock(&mvm->mutex); + switch (vif->type) { case NL80211_IFTYPE_STATION: /* Use aux roc framework (HS20) */ ret = iwl_mvm_send_aux_roc_cmd(mvm, channel, vif, duration); - return ret; + goto out_unlock; case NL80211_IFTYPE_P2P_DEVICE: /* handle below */ break; default: IWL_ERR(mvm, "vif isn't P2P_DEVICE: %d\n", vif->type); - return -EINVAL; + ret = -EINVAL; + goto out_unlock; } - mutex_lock(&mvm->mutex); - for (i = 0; i < NUM_PHY_CTX; i++) { phy_ctxt = &mvm->phy_ctxts[i]; if (phy_ctxt->ref == 0 || mvmvif->phy_ctxt == phy_ctxt) diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index b7f9e61d14e2..6dfad230be5e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c @@ -305,8 +305,8 @@ static int iwl_mvm_aux_roc_te_handle_notif(struct iwl_mvm *mvm, te_data->running = false; te_data->vif = NULL; te_data->uid = 0; + te_data->id = TE_MAX; } else if (le32_to_cpu(notif->action) == TE_V2_NOTIF_HOST_EVENT_START) { - set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); set_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status); te_data->running = true; ieee80211_ready_on_channel(mvm->hw); /* Start TE */ -- cgit v1.2.3 From a0855054e59b0c5b2b00237fdb5147f7bcc18efb Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 5 Oct 2014 09:11:14 +0300 Subject: iwlwifi: dvm: drop non VO frames when flushing When mac80211 wants to ensure that a frame is sent, it calls the flush() callback. Until now, iwldvm implemented this by waiting that all the frames are sent (ACKed or timeout). In case of weak signal, this can take a significant amount of time, delaying the next connection (in case of roaming). Many users have reported that the flush would take too long leading to the following error messages to be printed: iwlwifi 0000:03:00.0: fail to flush all tx fifo queues Q 2 iwlwifi 0000:03:00.0: Current SW read_ptr 161 write_ptr 201 iwl data: 00000000: 00 00 00 00 00 00 00 00 fe ff 01 00 00 00 00 00 [snip] iwlwifi 0000:03:00.0: FH TRBs(0) = 0x00000000 [snip] iwlwifi 0000:03:00.0: Q 0 is active and mapped to fifo 3 ra_tid 0x0000 [9,9] [snip] Instead of waiting for these packets, simply drop them. This significantly improves the responsiveness of the network. Note that all the queues are flushed, but the VO one. This is not typically used by the applications and it likely contains management frames that are useful for connection or roaming. This bug is tracked here: https://bugzilla.kernel.org/show_bug.cgi?id=56581 But it is duplicated in distributions' trackers. A simple search in Ubuntu's database led to these bugs: https://bugs.launchpad.net/ubuntu/+source/linux-firmware/+bug/1270808 https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1305406 https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1356236 https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1360597 https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1361809 Cc: Depends-on: 77be2c54c5bd ("mac80211: add vif to flush call") Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/mac80211.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index 2364a3c09b9e..cae692ff1013 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c @@ -1095,6 +1095,7 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop) { struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); + u32 scd_queues; mutex_lock(&priv->mutex); IWL_DEBUG_MAC80211(priv, "enter\n"); @@ -1108,18 +1109,19 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, goto done; } - /* - * mac80211 will not push any more frames for transmit - * until the flush is completed - */ - if (drop) { - IWL_DEBUG_MAC80211(priv, "send flush command\n"); - if (iwlagn_txfifo_flush(priv, 0)) { - IWL_ERR(priv, "flush request fail\n"); - goto done; - } + scd_queues = BIT(priv->cfg->base_params->num_of_queues) - 1; + scd_queues &= ~(BIT(IWL_IPAN_CMD_QUEUE_NUM) | + BIT(IWL_DEFAULT_CMD_QUEUE_NUM)); + + if (vif) + scd_queues &= ~BIT(vif->hw_queue[IEEE80211_AC_VO]); + + IWL_DEBUG_TX_QUEUES(priv, "Flushing SCD queues: 0x%x\n", scd_queues); + if (iwlagn_txfifo_flush(priv, scd_queues)) { + IWL_ERR(priv, "flush request fail\n"); + goto done; } - IWL_DEBUG_MAC80211(priv, "wait transmit/flush all frames\n"); + IWL_DEBUG_TX_QUEUES(priv, "wait transmit/flush all frames\n"); iwl_trans_wait_tx_queue_empty(priv->trans, 0xffffffff); done: mutex_unlock(&priv->mutex); -- cgit v1.2.3 From 1ffde699aae127e7abdb98dbdedc2cc6a973a1a1 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 20 Oct 2014 08:29:55 +0300 Subject: Revert "iwlwifi: mvm: treat EAPOLs like mgmt frames wrt rate" This reverts commit aa11bbf3df026d6b1c6b528bef634fd9de7c2619. This commit was causing connection issues and is not needed if IWL_MVM_RS_RSSI_BASED_INIT_RATE is set to false by default. Regardless of the issues mentioned above, this patch added the following WARNING: WARNING: CPU: 0 PID: 3946 at drivers/net/wireless/iwlwifi/mvm/tx.c:190 iwl_mvm_set_tx_params+0x60a/0x6f0 [iwlmvm]() Got an HT rate for a non data frame 0x8 CPU: 0 PID: 3946 Comm: wpa_supplicant Tainted: G O 3.17.0+ #6 Hardware name: LENOVO 20ANCTO1WW/20ANCTO1WW, BIOS GLET71WW (2.25 ) 07/02/2014 0000000000000009 ffffffff814fa911 ffff8804288db8f8 ffffffff81064f52 0000000000001808 ffff8804288db948 ffff88040add8660 ffff8804291b5600 0000000000000000 ffffffff81064fb7 ffffffffa07b73d0 0000000000000020 Call Trace: [] ? dump_stack+0x41/0x51 [] ? warn_slowpath_common+0x72/0x90 [] ? warn_slowpath_fmt+0x47/0x50 [] ? iwl_mvm_set_tx_params+0x60a/0x6f0 [iwlmvm] [] ? iwl_mvm_tx_skb+0x48/0x3c0 [iwlmvm] [] ? iwl_mvm_mac_tx+0x7b/0x180 [iwlmvm] [] ? __ieee80211_tx+0x2b9/0x3c0 [mac80211] [] ? ieee80211_tx+0xb3/0x100 [mac80211] [] ? ieee80211_subif_start_xmit+0x459/0xca0 [mac80211] [] ? dev_hard_start_xmit+0x337/0x5f0 [] ? sch_direct_xmit+0x96/0x1f0 [] ? __dev_queue_xmit+0x203/0x4f0 [] ? ether_setup+0x70/0x70 [] ? packet_sendmsg+0xf81/0x1110 [] ? skb_free_datagram+0xc/0x40 [] ? sock_sendmsg+0x88/0xc0 [] ? move_addr_to_kernel.part.20+0x14/0x60 [] ? __inode_wait_for_writeback+0x62/0xb0 [] ? SYSC_sendto+0xf1/0x180 [] ? __sys_recvmsg+0x39/0x70 [] ? system_call_fastpath+0x1a/0x1f ---[ end trace cc19a150d311fc63 ]--- which was reported here: https://bugzilla.kernel.org/show_bug.cgi?id=85691 CC: [3.13+] Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/tx.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 1cb793a498ac..c6a517c771df 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -175,14 +175,10 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, /* * for data packets, rate info comes from the table inside the fw. This - * table is controlled by LINK_QUALITY commands. Exclude ctrl port - * frames like EAPOLs which should be treated as mgmt frames. This - * avoids them being sent initially in high rates which increases the - * chances for completion of the 4-Way handshake. + * table is controlled by LINK_QUALITY commands */ - if (ieee80211_is_data(fc) && sta && - !(info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)) { + if (ieee80211_is_data(fc) && sta) { tx_cmd->initial_rate_index = 0; tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE); return; -- cgit v1.2.3 From 7f2ac8fb31896c9fb70dbd2a2e6642b79996fc13 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 23 Oct 2014 08:53:21 +0300 Subject: iwlwifi: pcie: fix polling in various places iwl_poll_bit may return a strictly positive value when the poll doesn't match on the first try. This was caught when WoWLAN started failing upon resume even if the poll_bit actually succeeded. Also change a wrong print. If we reach the end of iwl_pcie_prepare_card_hw, it means that we couldn't get the devices. Reviewed-by: Johannes Berg Reviewed-by: Luciano Coelho Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/trans.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index c706dba67cdd..3781b029e54a 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -430,7 +430,7 @@ static int iwl_pcie_apm_stop_master(struct iwl_trans *trans) ret = iwl_poll_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_MASTER_DISABLED, CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); - if (ret) + if (ret < 0) IWL_WARN(trans, "Master Disable Timed Out, 100 usec\n"); IWL_DEBUG_INFO(trans, "stop master\n"); @@ -546,7 +546,7 @@ static int iwl_pcie_prepare_card_hw(struct iwl_trans *trans) msleep(25); } - IWL_DEBUG_INFO(trans, "got NIC after %d iterations\n", iter); + IWL_ERR(trans, "Couldn't prepare the card\n"); return ret; } @@ -1045,7 +1045,7 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); - if (ret) { + if (ret < 0) { IWL_ERR(trans, "Failed to resume the device (mac ready)\n"); return ret; } -- cgit v1.2.3 From dc574e526381ddcc7e5103ca091fd93c29129c6d Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Wed, 17 Sep 2014 13:56:29 +0300 Subject: iwlwifi: rs: option to easily disable Tx MIMO The current TLC isn't optimized for low latency and some devices have issues with MIMO. This kind of combo creates latency issues. Allow to temporarily disable MIMO for tests in order to solve the latency issues without the added complexity of MIMO. Signed-off-by: Eyal Shapira Signed-off-by: Arik Nemtsov Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/constants.h | 1 + drivers/net/wireless/iwlwifi/mvm/rs.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index d4dfbe4cb66d..dfec5b5e7e14 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h @@ -95,5 +95,6 @@ #define IWL_MVM_FW_MCAST_FILTER_PASS_ALL 0 #define IWL_MVM_QUOTA_THRESHOLD 8 #define IWL_MVM_RS_RSSI_BASED_INIT_RATE 0 +#define IWL_MVM_RS_DISABLE_MIMO 0 #endif /* __MVM_CONSTANTS_H */ diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 18a539999580..0d836fe67e83 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -2684,6 +2684,9 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, lq_sta->ldpc = true; } + if (IWL_MVM_RS_DISABLE_MIMO) + lq_sta->active_mimo2_rate = 0; + lq_sta->max_legacy_rate_idx = find_last_bit(&lq_sta->active_legacy_rate, BITS_PER_LONG); lq_sta->max_siso_rate_idx = find_last_bit(&lq_sta->active_siso_rate, -- cgit v1.2.3 From 8dfc275109e794371c58be69e4286fa7061cd3a1 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 21 Sep 2014 13:29:48 +0300 Subject: iwlwifi: mvm: remove unneeded NULL pointer check mac80211 will never call rate_control_tx_status with a NULL pointer for sta. Remove the superfluous check. This check misled smatch. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 0d836fe67e83..66e971a99d7c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -1225,7 +1225,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, IWL_DEBUG_RATE(mvm, "reduced txpower: %d\n", reduced_txp); done: /* See if there's a better rate or modulation mode to try. */ - if (sta && sta->supp_rates[info->band]) + if (sta->supp_rates[info->band]) rs_rate_scale_perform(mvm, sta, lq_sta, tid); } -- cgit v1.2.3 From 31ca09dd6becfd954098ca7ddb6c1e27b13fe5d7 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 22 Sep 2014 13:22:51 +0300 Subject: iwlwifi: mvm: hold the rtnl when resuming from a d3 test We use ieee80211_iter_keys() which requires the rtnl to be held. If we don't lock the rtnl, like we do when we suspend during a d3 test, we get the following splat: RTNL: assertion failed at net/mac80211/key.c (566) CPU: 1 PID: 26529 Comm: cat Tainted: G W O 3.10.29-dev #1 Hardware name: Dell Inc. Latitude E6430/0CPWYR, BIOS A09 12/13/2012 e7b15008 e7b15008 e68adc1c c168aa62 e68adc54 f91f20b6 f923700c f9236fd8 00000236 00000000 ece23874 00000000 f94941e0 00000000 e43b8e48 e7b15008 00000000 e8b69e78 e68adcc0 f9493ab9 e68adc68 00000000 e43b8e48 e7b15008 Call Trace: [] dump_stack+0x16/0x18 [] ieee80211_iter_keys+0x166/0x170 [mac80211] [] ? iwl_mvm_query_wakeup_reasons+0x5f0/0x5f0 [iwlmvm] [] iwl_mvm_setup_connection_keep.isra.5+0x99/0x1d0 [iwlmvm] [] ? cfg80211_report_wowlan_wakeup+0x308/0x510 [cfg80211] [] iwl_mvm_query_wakeup_reasons+0x3f5/0x5f0 [iwlmvm] [] ? init_object+0x3a/0x70 [] ? iwl_trans_pcie_d3_resume+0x1be/0x3a0 [iwlwifi] [] __iwl_mvm_resume+0x14a/0x180 [iwlmvm] [] iwl_mvm_d3_test_release+0x26/0xc0 [iwlmvm] [] __fput+0xad/0x210 [] ____fput+0xd/0x10 [] task_work_run+0x81/0xb0 [] do_exit+0x255/0xac0 [] ? dequeue_signal+0x31/0x1a0 [] do_group_exit+0x38/0xa0 [] ? trace_hardirqs_on+0xb/0x10 [] get_signal_to_deliver+0x1e1/0x8e0 [] ? try_to_del_timer_sync+0x42/0x60 [] ? try_to_del_timer_sync+0x60/0x60 [] ? schedule_timeout+0x102/0x2a0 [] do_signal+0x3a/0x8e0 [] ? __internal_add_timer+0xb0/0xb0 [] ? schedule_timeout_interruptible+0x1a/0x20 [] ? msleep_interruptible+0x39/0x40 [] ? iwl_mvm_d3_test_read+0x49/0x70 [iwlmvm] [] ? vfs_read+0x8c/0x160 [] ? SyS_fadvise64_64+0x15f/0x2b0 [] ? iwl_mvm_wowlan_program_keys+0x4a0/0x4a0 [iwlmvm] [] ? SyS_read+0x57/0xa0 [] do_notify_resume+0x6f/0xa0 [] work_notifysig+0x29/0x31 Fix this by hold the rtnl lock when calling __iwl_mvm_resume() in the d3 test wake up path. Signed-off-by: Luciano Coelho Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/d3.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index c17be0fb7283..5b269224f817 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -1741,7 +1741,9 @@ static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file) int remaining_time = 10; mvm->d3_test_active = false; + rtnl_lock(); __iwl_mvm_resume(mvm, true); + rtnl_unlock(); iwl_abort_notification_waits(&mvm->notif_wait); ieee80211_restart_hw(mvm->hw); -- cgit v1.2.3 From 671b58202e485f26abf1f92c1b52ed45d03d0438 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 22 Sep 2014 10:59:53 +0300 Subject: iwlwifi: mvm: split wowlan handling out of the main suspend function Take the WoWLAN handling code out of the main suspend function, dividing it into three parts: get_config (which is used before the firmware is switched), switch_to_d3 (which handles the rebooting of the hardware with the D3 firmware) and config (which configures the D3 firmware for WoWLAN operation). This is necessary to prepare for the net-detect implementation, which will use only the switch_to_d3 part of this flow. Signed-off-by: Luciano Coelho Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/d3.c | 266 +++++++++++++++++++--------------- 1 file changed, 151 insertions(+), 115 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 5b269224f817..b8e8a97e002c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -783,6 +783,35 @@ void iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif) IWL_ERR(mvm, "failed to set non-QoS seqno\n"); } +static int iwl_mvm_switch_to_d3(struct iwl_mvm *mvm) +{ + iwl_mvm_cancel_scan(mvm); + + iwl_trans_stop_device(mvm->trans); + + /* + * Set the HW restart bit -- this is mostly true as we're + * going to load new firmware and reprogram that, though + * the reprogramming is going to be manual to avoid adding + * all the MACs that aren't support. + * We don't have to clear up everything though because the + * reprogramming is manual. When we resume, we'll actually + * go through a proper restart sequence again to switch + * back to the runtime firmware image. + */ + set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); + + /* We reprogram keys and shouldn't allocate new key indices */ + memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); + + mvm->ptk_ivlen = 0; + mvm->ptk_icvlen = 0; + mvm->ptk_ivlen = 0; + mvm->ptk_icvlen = 0; + + return iwl_mvm_load_d3_fw(mvm); +} + static int iwl_mvm_send_wowlan_config_cmd(struct iwl_mvm *mvm, const struct iwl_wowlan_config_cmd_v3 *cmd) @@ -797,116 +826,52 @@ iwl_mvm_send_wowlan_config_cmd(struct iwl_mvm *mvm, cmd_len, cmd); } -static int __iwl_mvm_suspend(struct ieee80211_hw *hw, - struct cfg80211_wowlan *wowlan, - bool test) +static int +iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, + struct cfg80211_wowlan *wowlan, + struct iwl_wowlan_config_cmd_v3 *wowlan_config_cmd, + struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif, + struct ieee80211_sta *ap_sta) { - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_d3_iter_data suspend_iter_data = { - .mvm = mvm, - }; - struct ieee80211_vif *vif; - struct iwl_mvm_vif *mvmvif; - struct ieee80211_sta *ap_sta; - struct iwl_mvm_sta *mvm_ap_sta; - struct iwl_wowlan_config_cmd_v3 wowlan_config_cmd = {}; - struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {}; - struct iwl_wowlan_tkip_params_cmd tkip_cmd = {}; - struct iwl_d3_manager_config d3_cfg_cmd_data = { - /* - * Program the minimum sleep time to 10 seconds, as many - * platforms have issues processing a wakeup signal while - * still being in the process of suspending. - */ - .min_sleep_time = cpu_to_le32(10 * 1000 * 1000), - }; - struct iwl_host_cmd d3_cfg_cmd = { - .id = D3_CONFIG_CMD, - .flags = CMD_WANT_SKB, - .data[0] = &d3_cfg_cmd_data, - .len[0] = sizeof(d3_cfg_cmd_data), - }; - struct wowlan_key_data key_data = { - .use_rsc_tsc = false, - .tkip = &tkip_cmd, - .use_tkip = false, - }; int ret; - int len __maybe_unused; - - if (!wowlan) { - /* - * mac80211 shouldn't get here, but for D3 test - * it doesn't warrant a warning - */ - WARN_ON(!test); - return -EINVAL; - } - - key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL); - if (!key_data.rsc_tsc) - return -ENOMEM; - - mutex_lock(&mvm->mutex); - - /* see if there's only a single BSS vif and it's associated */ - ieee80211_iterate_active_interfaces_atomic( - mvm->hw, IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_d3_iface_iterator, &suspend_iter_data); + struct iwl_mvm_sta *mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv; - if (suspend_iter_data.error || !suspend_iter_data.vif) { - ret = 1; - goto out_noreset; - } - - vif = suspend_iter_data.vif; - mvmvif = iwl_mvm_vif_from_mac80211(vif); - - ap_sta = rcu_dereference_protected( - mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], - lockdep_is_held(&mvm->mutex)); - if (IS_ERR_OR_NULL(ap_sta)) { - ret = -EINVAL; - goto out_noreset; - } + /* TODO: wowlan_config_cmd->common.wowlan_ba_teardown_tids */ - mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv; - - /* TODO: wowlan_config_cmd.common.wowlan_ba_teardown_tids */ - - wowlan_config_cmd.common.is_11n_connection = + wowlan_config_cmd->common.is_11n_connection = ap_sta->ht_cap.ht_supported; /* Query the last used seqno and set it */ ret = iwl_mvm_get_last_nonqos_seq(mvm, vif); if (ret < 0) - goto out_noreset; - wowlan_config_cmd.common.non_qos_seq = cpu_to_le16(ret); + return ret; + + wowlan_config_cmd->common.non_qos_seq = cpu_to_le16(ret); - iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, &wowlan_config_cmd.common); + iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, &wowlan_config_cmd->common); if (wowlan->disconnect) - wowlan_config_cmd.common.wakeup_filter |= + wowlan_config_cmd->common.wakeup_filter |= cpu_to_le32(IWL_WOWLAN_WAKEUP_BEACON_MISS | IWL_WOWLAN_WAKEUP_LINK_CHANGE); if (wowlan->magic_pkt) - wowlan_config_cmd.common.wakeup_filter |= + wowlan_config_cmd->common.wakeup_filter |= cpu_to_le32(IWL_WOWLAN_WAKEUP_MAGIC_PACKET); if (wowlan->gtk_rekey_failure) - wowlan_config_cmd.common.wakeup_filter |= + wowlan_config_cmd->common.wakeup_filter |= cpu_to_le32(IWL_WOWLAN_WAKEUP_GTK_REKEY_FAIL); if (wowlan->eap_identity_req) - wowlan_config_cmd.common.wakeup_filter |= + wowlan_config_cmd->common.wakeup_filter |= cpu_to_le32(IWL_WOWLAN_WAKEUP_EAP_IDENT_REQ); if (wowlan->four_way_handshake) - wowlan_config_cmd.common.wakeup_filter |= + wowlan_config_cmd->common.wakeup_filter |= cpu_to_le32(IWL_WOWLAN_WAKEUP_4WAY_HANDSHAKE); if (wowlan->n_patterns) - wowlan_config_cmd.common.wakeup_filter |= + wowlan_config_cmd->common.wakeup_filter |= cpu_to_le32(IWL_WOWLAN_WAKEUP_PATTERN_MATCH); if (wowlan->rfkill_release) - wowlan_config_cmd.common.wakeup_filter |= + wowlan_config_cmd->common.wakeup_filter |= cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT); if (wowlan->tcp) { @@ -914,44 +879,39 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, * Set the "link change" (really "link lost") flag as well * since that implies losing the TCP connection. */ - wowlan_config_cmd.common.wakeup_filter |= + wowlan_config_cmd->common.wakeup_filter |= cpu_to_le32(IWL_WOWLAN_WAKEUP_REMOTE_LINK_LOSS | IWL_WOWLAN_WAKEUP_REMOTE_SIGNATURE_TABLE | IWL_WOWLAN_WAKEUP_REMOTE_WAKEUP_PACKET | IWL_WOWLAN_WAKEUP_LINK_CHANGE); } - iwl_mvm_cancel_scan(mvm); - - iwl_trans_stop_device(mvm->trans); - - /* - * Set the HW restart bit -- this is mostly true as we're - * going to load new firmware and reprogram that, though - * the reprogramming is going to be manual to avoid adding - * all the MACs that aren't support. - * We don't have to clear up everything though because the - * reprogramming is manual. When we resume, we'll actually - * go through a proper restart sequence again to switch - * back to the runtime firmware image. - */ - set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); - - /* We reprogram keys and shouldn't allocate new key indices */ - memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); - - mvm->ptk_ivlen = 0; - mvm->ptk_icvlen = 0; - mvm->ptk_ivlen = 0; - mvm->ptk_icvlen = 0; + return 0; +} - ret = iwl_mvm_load_d3_fw(mvm); - if (ret) - goto out; +static int +iwl_mvm_wowlan_config(struct iwl_mvm *mvm, + struct cfg80211_wowlan *wowlan, + struct iwl_wowlan_config_cmd_v3 *wowlan_config_cmd, + struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif, + struct ieee80211_sta *ap_sta) +{ + struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {}; + struct iwl_wowlan_tkip_params_cmd tkip_cmd = {}; + struct wowlan_key_data key_data = { + .use_rsc_tsc = false, + .tkip = &tkip_cmd, + .use_tkip = false, + }; + int ret; ret = iwl_mvm_d3_reprogram(mvm, vif, ap_sta); if (ret) - goto out; + return ret; + + key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL); + if (!key_data.rsc_tsc) + return -ENOMEM; if (!iwlwifi_mod_params.sw_crypto) { /* @@ -1010,7 +970,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, } } - ret = iwl_mvm_send_wowlan_config_cmd(mvm, &wowlan_config_cmd); + ret = iwl_mvm_send_wowlan_config_cmd(mvm, wowlan_config_cmd); if (ret) goto out; @@ -1023,6 +983,84 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, goto out; ret = iwl_mvm_send_remote_wake_cfg(mvm, vif, wowlan->tcp); + +out: + kfree(key_data.rsc_tsc); + return ret; +} + +static int __iwl_mvm_suspend(struct ieee80211_hw *hw, + struct cfg80211_wowlan *wowlan, + bool test) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + struct iwl_d3_iter_data suspend_iter_data = { + .mvm = mvm, + }; + struct ieee80211_vif *vif = NULL; + struct iwl_mvm_vif *mvmvif = NULL; + struct ieee80211_sta *ap_sta = NULL; + struct iwl_wowlan_config_cmd_v3 wowlan_config_cmd = {}; + struct iwl_d3_manager_config d3_cfg_cmd_data = { + /* + * Program the minimum sleep time to 10 seconds, as many + * platforms have issues processing a wakeup signal while + * still being in the process of suspending. + */ + .min_sleep_time = cpu_to_le32(10 * 1000 * 1000), + }; + struct iwl_host_cmd d3_cfg_cmd = { + .id = D3_CONFIG_CMD, + .flags = CMD_WANT_SKB, + .data[0] = &d3_cfg_cmd_data, + .len[0] = sizeof(d3_cfg_cmd_data), + }; + int ret; + int len __maybe_unused; + + if (!wowlan) { + /* + * mac80211 shouldn't get here, but for D3 test + * it doesn't warrant a warning + */ + WARN_ON(!test); + return -EINVAL; + } + + mutex_lock(&mvm->mutex); + + /* see if there's only a single BSS vif and it's associated */ + ieee80211_iterate_active_interfaces_atomic( + mvm->hw, IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_d3_iface_iterator, &suspend_iter_data); + + if (suspend_iter_data.error || !suspend_iter_data.vif) { + ret = 1; + goto out_noreset; + } + + vif = suspend_iter_data.vif; + mvmvif = iwl_mvm_vif_from_mac80211(vif); + + ap_sta = rcu_dereference_protected( + mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], + lockdep_is_held(&mvm->mutex)); + if (IS_ERR_OR_NULL(ap_sta)) { + ret = -EINVAL; + goto out_noreset; + } + + ret = iwl_mvm_get_wowlan_config(mvm, wowlan, &wowlan_config_cmd, vif, + mvmvif, ap_sta); + if (ret) + goto out_noreset; + + ret = iwl_mvm_switch_to_d3(mvm); + if (ret) + goto out; + + ret = iwl_mvm_wowlan_config(mvm, wowlan, &wowlan_config_cmd, + vif, mvmvif, ap_sta); if (ret) goto out; @@ -1060,8 +1098,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, if (ret < 0) ieee80211_restart_hw(mvm->hw); out_noreset: - kfree(key_data.rsc_tsc); - mutex_unlock(&mvm->mutex); return ret; -- cgit v1.2.3 From 1e4d19ca6efba26964c9597b643a1dcda79ad296 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Mon, 22 Sep 2014 13:01:59 +0300 Subject: iwlwifi: mvm: move the check if associated outside of the iterator for wowlan Instead of checking if we are associated when suspending with wowlan enabled in the interface iterator, allow it to return an unassociated vif and move the check to the main suspend function. This will be needed by netdetect, since it should also work when we are not associated but the vif is active. Signed-off-by: Luciano Coelho Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/d3.c | 48 ++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index b8e8a97e002c..7a66a0903515 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -611,14 +611,10 @@ static void iwl_mvm_d3_iface_iterator(void *_data, u8 *mac, struct ieee80211_vif *vif) { struct iwl_d3_iter_data *data = _data; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) return; - if (mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT) - return; - if (data->vif) { IWL_ERR(data->mvm, "More than one managed interface active!\n"); data->error = true; @@ -1029,7 +1025,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, mutex_lock(&mvm->mutex); - /* see if there's only a single BSS vif and it's associated */ + /* see if there's only a single BSS vif */ ieee80211_iterate_active_interfaces_atomic( mvm->hw, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_d3_iface_iterator, &suspend_iter_data); @@ -1042,27 +1038,33 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, vif = suspend_iter_data.vif; mvmvif = iwl_mvm_vif_from_mac80211(vif); - ap_sta = rcu_dereference_protected( - mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], - lockdep_is_held(&mvm->mutex)); - if (IS_ERR_OR_NULL(ap_sta)) { - ret = -EINVAL; - goto out_noreset; - } + /* if we're associated, this is wowlan */ + if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { + ap_sta = rcu_dereference_protected( + mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], + lockdep_is_held(&mvm->mutex)); + if (IS_ERR_OR_NULL(ap_sta)) { + ret = -EINVAL; + goto out_noreset; + } - ret = iwl_mvm_get_wowlan_config(mvm, wowlan, &wowlan_config_cmd, vif, - mvmvif, ap_sta); - if (ret) - goto out_noreset; + ret = iwl_mvm_get_wowlan_config(mvm, wowlan, &wowlan_config_cmd, + vif, mvmvif, ap_sta); + if (ret) + goto out_noreset; - ret = iwl_mvm_switch_to_d3(mvm); - if (ret) - goto out; + ret = iwl_mvm_switch_to_d3(mvm); + if (ret) + goto out; - ret = iwl_mvm_wowlan_config(mvm, wowlan, &wowlan_config_cmd, - vif, mvmvif, ap_sta); - if (ret) - goto out; + ret = iwl_mvm_wowlan_config(mvm, wowlan, &wowlan_config_cmd, + vif, mvmvif, ap_sta); + if (ret) + goto out; + } else { + ret = 1; + goto out_noreset; + } ret = iwl_mvm_power_update_device(mvm); if (ret) -- cgit v1.2.3 From b141c23581164bfa7eb5eb19c2f00cb303c70d3b Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Wed, 1 Oct 2014 13:22:40 +0300 Subject: iwlwifi: mvm: spin off a function to start scan offload The net-detect feature will require a scan offload to be started in the same way it is done now for scheduled scan. Spin a new function off of the sched_scan_start op code for reuse. Additionally, restructure the function a bit for more readability. Signed-off-by: Luciano Coelho Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 20 ++------------------ drivers/net/wireless/iwlwifi/mvm/mvm.h | 4 ++++ drivers/net/wireless/iwlwifi/mvm/scan.c | 25 +++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 585fe5b7100f..b17877ce207f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -2170,25 +2170,9 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, mvm->scan_status = IWL_MVM_SCAN_SCHED; - if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) { - ret = iwl_mvm_config_sched_scan(mvm, vif, req, ies); - if (ret) - goto err; - } - - ret = iwl_mvm_config_sched_scan_profiles(mvm, req); + ret = iwl_mvm_scan_offload_start(mvm, vif, req, ies); if (ret) - goto err; - - if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) - ret = iwl_mvm_unified_sched_scan_lmac(mvm, vif, req, ies); - else - ret = iwl_mvm_sched_scan_start(mvm, req); - - if (!ret) - goto out; -err: - mvm->scan_status = IWL_MVM_SCAN_NONE; + mvm->scan_status = IWL_MVM_SCAN_NONE; out: mutex_unlock(&mvm->mutex); return ret; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index b153ced7015b..14ec67864bf2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -949,6 +949,10 @@ int iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm, struct cfg80211_sched_scan_request *req); int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, struct cfg80211_sched_scan_request *req); +int iwl_mvm_scan_offload_start(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct cfg80211_sched_scan_request *req, + struct ieee80211_scan_ies *ies); int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify); int iwl_mvm_rx_scan_offload_results(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index b280d5d87127..64c02a274f76 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -1007,6 +1007,31 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, sizeof(scan_req), &scan_req); } +int iwl_mvm_scan_offload_start(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct cfg80211_sched_scan_request *req, + struct ieee80211_scan_ies *ies) +{ + int ret; + + if ((mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) { + ret = iwl_mvm_config_sched_scan_profiles(mvm, req); + if (ret) + return ret; + ret = iwl_mvm_unified_sched_scan_lmac(mvm, vif, req, ies); + } else { + ret = iwl_mvm_config_sched_scan(mvm, vif, req, ies); + if (ret) + return ret; + ret = iwl_mvm_config_sched_scan_profiles(mvm, req); + if (ret) + return ret; + ret = iwl_mvm_sched_scan_start(mvm, req); + } + + return ret; +} + static int iwl_mvm_send_scan_offload_abort(struct iwl_mvm *mvm) { int ret; -- cgit v1.2.3 From 3c2f3b20e4a834f1d8ae34002b22f9021a861715 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Wed, 24 Sep 2014 08:29:11 +0300 Subject: iwlwifi: mvm: add debugfs entry to configure netdetect SSIDs Before we get all the chain (ie. mac80211, cfg80211, nl80211 and userspace) changed to support net-detect, we can use this debugfs entry for easy testing and as a proof of concept. Signed-off-by: Luciano Coelho Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/d3.c | 9 +++ drivers/net/wireless/iwlwifi/mvm/debugfs.c | 122 +++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 4 + drivers/net/wireless/iwlwifi/mvm/ops.c | 7 ++ 4 files changed, 142 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 7a66a0903515..0b3295e3f6a6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -1061,6 +1061,15 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, vif, mvmvif, ap_sta); if (ret) goto out; + } else if (mvm->nd_config) { + ret = iwl_mvm_switch_to_d3(mvm); + if (ret) + goto out; + + ret = iwl_mvm_scan_offload_start(mvm, vif, mvm->nd_config, + mvm->nd_ies); + if (ret) + goto out; } else { ret = 1; goto out_noreset; diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 50527a9bb267..2a61baca5081 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -1250,6 +1250,126 @@ static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf, return ret; } + +#define MAX_NUM_ND_MATCHSETS 10 + +static ssize_t iwl_dbgfs_netdetect_write(struct iwl_mvm *mvm, char *buf, + size_t count, loff_t *ppos) +{ + const char *seps = ",\n"; + char *buf_ptr = buf; + char *value_str = NULL; + int ret, i; + + /* TODO: don't free if write is being called several times in one go */ + if (mvm->nd_config) { + kfree(mvm->nd_config->match_sets); + kfree(mvm->nd_config); + mvm->nd_config = NULL; + kfree(mvm->nd_ies); + mvm->nd_ies = NULL; + } + + mvm->nd_ies = kzalloc(sizeof(*mvm->nd_ies), GFP_KERNEL); + if (!mvm->nd_ies) + return -ENOMEM; + + mvm->nd_config = kzalloc(sizeof(*mvm->nd_config) + + (11 * sizeof(struct ieee80211_channel *)), + GFP_KERNEL); + if (!mvm->nd_config) { + ret = -ENOMEM; + goto out_free; + } + + mvm->nd_config->n_channels = 11; + mvm->nd_config->scan_width = NL80211_BSS_CHAN_WIDTH_20; + mvm->nd_config->interval = 5; + mvm->nd_config->min_rssi_thold = -80; + for (i = 0; i < mvm->nd_config->n_channels; i++) + mvm->nd_config->channels[i] = &mvm->nvm_data->channels[i]; + + mvm->nd_config->match_sets = + kcalloc(MAX_NUM_ND_MATCHSETS, + sizeof(*mvm->nd_config->match_sets), + GFP_KERNEL); + if (!mvm->nd_config->match_sets) { + ret = -ENOMEM; + goto out_free; + } + + while ((value_str = strsep(&buf_ptr, seps)) && + strlen(value_str)) { + struct cfg80211_match_set *set; + + if (mvm->nd_config->n_match_sets >= MAX_NUM_ND_MATCHSETS) { + ret = -EINVAL; + goto out_free; + } + + set = &mvm->nd_config->match_sets[mvm->nd_config->n_match_sets]; + set->ssid.ssid_len = strlen(value_str); + + if (set->ssid.ssid_len > IEEE80211_MAX_SSID_LEN) { + ret = -EINVAL; + goto out_free; + } + + memcpy(set->ssid.ssid, value_str, set->ssid.ssid_len); + + mvm->nd_config->n_match_sets++; + } + + ret = count; + + if (mvm->nd_config->n_match_sets) + goto out; + +out_free: + if (mvm->nd_config) + kfree(mvm->nd_config->match_sets); + kfree(mvm->nd_config); + mvm->nd_config = NULL; + kfree(mvm->nd_ies); + mvm->nd_ies = NULL; +out: + return ret; +} + +static ssize_t +iwl_dbgfs_netdetect_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_mvm *mvm = file->private_data; + size_t bufsz, ret; + char *buf; + int i, n_match_sets, pos = 0; + + n_match_sets = mvm->nd_config ? mvm->nd_config->n_match_sets : 0; + + bufsz = n_match_sets * (IEEE80211_MAX_SSID_LEN + 1) + 1; + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + for (i = 0; i < n_match_sets; i++) { + if (pos + + mvm->nd_config->match_sets[i].ssid.ssid_len + 2 > bufsz) { + ret = -EIO; + goto out; + } + + memcpy(buf + pos, mvm->nd_config->match_sets[i].ssid.ssid, + mvm->nd_config->match_sets[i].ssid.ssid_len); + pos += mvm->nd_config->match_sets[i].ssid.ssid_len; + buf[pos++] = '\n'; + } + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); +out: + kfree(buf); + return ret; +} #endif #define PRINT_MVM_REF(ref) do { \ @@ -1428,6 +1548,7 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256); #ifdef CONFIG_PM_SLEEP MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(netdetect, 384); #endif int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) @@ -1487,6 +1608,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) if (!debugfs_create_bool("d3_wake_sysassert", S_IRUSR | S_IWUSR, mvm->debugfs_dir, &mvm->d3_wake_sysassert)) goto err; + MVM_DEBUGFS_ADD_FILE(netdetect, mvm->debugfs_dir, S_IRUSR | S_IWUSR); #endif if (!debugfs_create_u8("low_latency_agg_frame_limit", S_IRUSR | S_IWUSR, diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 14ec67864bf2..60aee625b966 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -659,6 +659,10 @@ struct iwl_mvm { #ifdef CONFIG_PM_SLEEP struct wiphy_wowlan_support wowlan; int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen; + + /* sched scan settings for net detect */ + struct cfg80211_sched_scan_request *nd_config; + struct ieee80211_scan_ies *nd_ies; #ifdef CONFIG_IWLWIFI_DEBUGFS u32 d3_wake_sysassert; /* must be u32 for debugfs_create_bool */ bool d3_test_active; diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 48cb25a93591..047d83d8b25a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -594,6 +594,13 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS) kfree(mvm->d3_resume_sram); + if (mvm->nd_config) { + kfree(mvm->nd_config->match_sets); + kfree(mvm->nd_config); + mvm->nd_config = NULL; + kfree(mvm->nd_ies); + mvm->nd_ies = NULL; + } #endif iwl_trans_op_mode_leave(mvm->trans); -- cgit v1.2.3 From 7f549e2c45ba216f629aad7c463c00a3fc1ec2ea Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 2 Oct 2014 15:38:04 +0300 Subject: iwlwifi: mvm: change the iwl_mvm_d3_iface_iterator into a generic function Getting the BSS station vif is something that may be needed by other parts of the code. So, instead of having an iterator specifically for d3, change it into a generic one in utils.c. Additionally, add a iwl_mvm_get_bss_vif() function to make it easier to retrieving it. Signed-off-by: Luciano Coelho Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/d3.c | 47 +++----------------------------- drivers/net/wireless/iwlwifi/mvm/mvm.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/utils.c | 37 +++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 43 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 0b3295e3f6a6..3bbb511b0b38 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -601,29 +601,6 @@ static int iwl_mvm_send_remote_wake_cfg(struct iwl_mvm *mvm, return ret; } -struct iwl_d3_iter_data { - struct iwl_mvm *mvm; - struct ieee80211_vif *vif; - bool error; -}; - -static void iwl_mvm_d3_iface_iterator(void *_data, u8 *mac, - struct ieee80211_vif *vif) -{ - struct iwl_d3_iter_data *data = _data; - - if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) - return; - - if (data->vif) { - IWL_ERR(data->mvm, "More than one managed interface active!\n"); - data->error = true; - return; - } - - data->vif = vif; -} - static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *ap_sta) { @@ -990,9 +967,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, bool test) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_d3_iter_data suspend_iter_data = { - .mvm = mvm, - }; struct ieee80211_vif *vif = NULL; struct iwl_mvm_vif *mvmvif = NULL; struct ieee80211_sta *ap_sta = NULL; @@ -1025,17 +999,12 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, mutex_lock(&mvm->mutex); - /* see if there's only a single BSS vif */ - ieee80211_iterate_active_interfaces_atomic( - mvm->hw, IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_d3_iface_iterator, &suspend_iter_data); - - if (suspend_iter_data.error || !suspend_iter_data.vif) { + vif = iwl_mvm_get_bss_vif(mvm); + if (IS_ERR_OR_NULL(vif)) { ret = 1; goto out_noreset; } - vif = suspend_iter_data.vif; mvmvif = iwl_mvm_vif_from_mac80211(vif); /* if we're associated, this is wowlan */ @@ -1639,9 +1608,6 @@ static void iwl_mvm_d3_disconnect_iter(void *data, u8 *mac, static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) { - struct iwl_d3_iter_data resume_iter_data = { - .mvm = mvm, - }; struct ieee80211_vif *vif = NULL; int ret; enum iwl_d3_status d3_status; @@ -1650,15 +1616,10 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) mutex_lock(&mvm->mutex); /* get the BSS vif pointer again */ - ieee80211_iterate_active_interfaces_atomic( - mvm->hw, IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_d3_iface_iterator, &resume_iter_data); - - if (WARN_ON(resume_iter_data.error || !resume_iter_data.vif)) + vif = iwl_mvm_get_bss_vif(mvm); + if (IS_ERR_OR_NULL(vif)) goto out_unlock; - vif = resume_iter_data.vif; - ret = iwl_trans_d3_resume(mvm->trans, &d3_status, test); if (ret) goto out_unlock; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 60aee625b966..aec9f579f5a9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -1214,6 +1214,8 @@ void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, struct ieee80211_vif *vif, void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm); + void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error); #ifdef CONFIG_IWLWIFI_DEBUGFS void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm); diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index 8021f6eec27f..e56e77ef5d2e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -734,3 +734,40 @@ bool iwl_mvm_is_idle(struct iwl_mvm *mvm) return idle; } + +struct iwl_bss_iter_data { + struct ieee80211_vif *vif; + bool error; +}; + +static void iwl_mvm_bss_iface_iterator(void *_data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct iwl_bss_iter_data *data = _data; + + if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) + return; + + if (data->vif) { + data->error = true; + return; + } + + data->vif = vif; +} + +struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm) +{ + struct iwl_bss_iter_data bss_iter_data = {}; + + ieee80211_iterate_active_interfaces_atomic( + mvm->hw, IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_bss_iface_iterator, &bss_iter_data); + + if (bss_iter_data.error) { + IWL_ERR(mvm, "More than one managed interface active!\n"); + return ERR_PTR(-EINVAL); + } + + return bss_iter_data.vif; +} -- cgit v1.2.3 From 77d96730db597ec82d78f3063daab2f17d14eff4 Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Tue, 2 Sep 2014 16:04:58 +0200 Subject: iwlwifi: allow to restrict Tx aggregation size per-device A few slave bus devices show better performance when we reduce the size of the Tx A-MPDU. Signed-off-by: Gregory Greenman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-config.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/ops.c | 3 +++ 2 files changed, 5 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 2ef83a39ff10..76d363d1a497 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -246,6 +246,7 @@ struct iwl_pwr_tx_backoff { * @nvm_hw_section_num: the ID of the HW NVM section * @pwr_tx_backoffs: translation table between power limits and backoffs * @max_rx_agg_size: max RX aggregation size of the ADDBA request/response + * @max_tx_agg_size: max TX aggregation size of the ADDBA request/response * * We enable the driver to be backward compatible wrt. hardware features. * API differences in uCode shouldn't be handled here but through TLVs @@ -285,6 +286,7 @@ struct iwl_cfg { const char *default_nvm_file; unsigned int max_rx_agg_size; bool disable_dummy_notification; + unsigned int max_tx_agg_size; }; /* diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 047d83d8b25a..91b28e869969 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -403,6 +403,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, if (cfg->max_rx_agg_size) hw->max_rx_aggregation_subframes = cfg->max_rx_agg_size; + if (cfg->max_tx_agg_size) + hw->max_tx_aggregation_subframes = cfg->max_tx_agg_size; + op_mode = hw->priv; op_mode->ops = &iwl_mvm_ops; -- cgit v1.2.3 From 40a76905ad85903dc35ca9967056817e21a6d5d7 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 18 Sep 2014 15:44:04 +0300 Subject: iwlwifi: pcie: warn if extern fw_debug buffer failed Otherwise we have no way to know that the buffer hasn't been allocated. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/trans.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 3781b029e54a..5c9064fdbfda 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -133,7 +133,7 @@ static void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans) break; } - if (!page) + if (WARN_ON_ONCE(!page)) return; trans_pcie->fw_mon_page = page; -- cgit v1.2.3 From a3ead6568c511d47b6cdc3d624ef0b4924e9dd27 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 12 Oct 2014 13:23:40 +0300 Subject: iwlwifi: pcie: fix recovery from ARC reset in WoWLAN When the ARC is reset when we exit from Sx in case we had WoWLAN running, we can't access the prph before we reset the NIC. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/trans.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 5c9064fdbfda..aea0fe9d1779 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -1023,14 +1023,6 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, return 0; } - iwl_pcie_set_pwr(trans, false); - - val = iwl_read32(trans, CSR_RESET); - if (val & CSR_RESET_REG_FLAG_NEVO_RESET) { - *status = IWL_D3_STATUS_RESET; - return 0; - } - /* * Also enables interrupts - none will happen as the device doesn't * know we're waking it up, only when the opmode actually tells it @@ -1050,6 +1042,8 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, return ret; } + iwl_pcie_set_pwr(trans, false); + iwl_trans_pcie_tx_reset(trans); ret = iwl_pcie_rx_init(trans); @@ -1058,7 +1052,12 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, return ret; } - *status = IWL_D3_STATUS_ALIVE; + val = iwl_read32(trans, CSR_RESET); + if (val & CSR_RESET_REG_FLAG_NEVO_RESET) + *status = IWL_D3_STATUS_RESET; + else + *status = IWL_D3_STATUS_ALIVE; + return 0; } -- cgit v1.2.3 From c7583d7dd62d44a5e930d67e7e6b881a569a5561 Mon Sep 17 00:00:00 2001 From: Eran Harary Date: Mon, 29 Sep 2014 08:27:56 +0200 Subject: iwlwifi: always run the secured flow for family 8000 In the new format the "CSS section" has the same TLV type as the "mem section". So we need to run the secured flow for all the 8000 products. Signed-off-by: Eran Harary Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-config.h | 10 ++++++++++ drivers/net/wireless/iwlwifi/iwl-drv.c | 3 --- drivers/net/wireless/iwlwifi/iwl-fw.h | 1 - drivers/net/wireless/iwlwifi/pcie/trans.c | 10 ++++------ 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 76d363d1a497..f8aa9cf08279 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -87,6 +87,16 @@ enum iwl_device_family { IWL_DEVICE_FAMILY_8000, }; +static inline bool iwl_has_secure_boot(u32 hw_rev, + enum iwl_device_family family) +{ + /* return 1 only for family 8000 B0 */ + if ((family == IWL_DEVICE_FAMILY_8000) && (hw_rev & 0xC)) + return 1; + + return 0; +} + /* * LED mode * IWL_LED_DEFAULT: use device default diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 0f1084f09caa..d9fa8e034da2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -807,19 +807,16 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_REGULAR, tlv_len); drv->fw.mvm_fw = true; - drv->fw.img[IWL_UCODE_REGULAR].is_secure = true; break; case IWL_UCODE_TLV_SECURE_SEC_INIT: iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_INIT, tlv_len); drv->fw.mvm_fw = true; - drv->fw.img[IWL_UCODE_INIT].is_secure = true; break; case IWL_UCODE_TLV_SECURE_SEC_WOWLAN: iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_WOWLAN, tlv_len); drv->fw.mvm_fw = true; - drv->fw.img[IWL_UCODE_WOWLAN].is_secure = true; break; case IWL_UCODE_TLV_NUM_OF_CPU: if (tlv_len != sizeof(u32)) diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index 4f6e66892acc..6f7ae5f7bdae 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -227,7 +227,6 @@ struct fw_desc { struct fw_img { struct fw_desc sec[IWL_UCODE_SECTION_MAX]; - bool is_secure; bool is_dual_cpus; }; diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index aea0fe9d1779..8027138c47e9 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -746,15 +746,12 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, int ret = 0; int first_ucode_section; - IWL_DEBUG_FW(trans, - "working with %s image\n", - image->is_secure ? "Secured" : "Non Secured"); IWL_DEBUG_FW(trans, "working with %s CPU\n", image->is_dual_cpus ? "Dual" : "Single"); /* configure the ucode to be ready to get the secured image */ - if (image->is_secure) { + if (iwl_has_secure_boot(trans->hw_rev, trans->cfg->device_family)) { /* set secure boot inspector addresses */ iwl_write_prph(trans, LMPM_SECURE_INSPECTOR_CODE_ADDR, @@ -790,7 +787,8 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, LMPM_SECURE_CPU2_HDR_MEM_SPACE); /* load to FW the binary sections of CPU2 */ - if (image->is_secure) + if (iwl_has_secure_boot(trans->hw_rev, + trans->cfg->device_family)) ret = iwl_pcie_load_cpu_secured_sections( trans, image, 2, &first_ucode_section); @@ -821,7 +819,7 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, else iwl_write32(trans, CSR_RESET, 0); - if (image->is_secure) { + if (iwl_has_secure_boot(trans->hw_rev, trans->cfg->device_family)) { /* wait for image verification to complete */ ret = iwl_poll_prph_bit(trans, LMPM_SECURE_BOOT_CPU1_STATUS_ADDR, -- cgit v1.2.3 From f3b2098d98d88a8137f795cbd5c58be90632f548 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 7 Oct 2014 14:44:18 +0300 Subject: iwlwifi: mvm: BT Coex - move BT_ANTENNA_COUPLING_THRESHOLD to constants This is were it really needs to be. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/coex.c | 4 +--- drivers/net/wireless/iwlwifi/mvm/coex_legacy.c | 5 ++--- drivers/net/wireless/iwlwifi/mvm/constants.h | 1 + 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index da2ffb785194..515f9cbcf289 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -72,8 +72,6 @@ #include "mvm.h" #include "iwl-debug.h" -#define BT_ANTENNA_COUPLING_THRESHOLD (30) - const u32 iwl_bt_ctl_kill_msk[BT_KILL_MSK_MAX] = { [BT_KILL_MSK_DEFAULT] = 0xfffffc00, [BT_KILL_MSK_NEVER] = 0xffffffff, @@ -605,7 +603,7 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) bt_cmd->max_kill = cpu_to_le32(5); bt_cmd->bt4_antenna_isolation_thr = - cpu_to_le32(BT_ANTENNA_COUPLING_THRESHOLD); + cpu_to_le32(IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS); bt_cmd->bt4_tx_tx_delta_freq_thr = cpu_to_le32(15); bt_cmd->bt4_tx_rx_max_freq0 = cpu_to_le32(15); bt_cmd->override_primary_lut = cpu_to_le32(BT_COEX_INVALID_LUT); diff --git a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c index 8a1d2f33d5b7..3f3b8ee51b1c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c @@ -102,8 +102,6 @@ static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = { #undef EVENT_PRIO_ANT -#define BT_ANTENNA_COUPLING_THRESHOLD (30) - static int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm) { if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) @@ -593,7 +591,8 @@ int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm) } bt_cmd->max_kill = 5; - bt_cmd->bt4_antenna_isolation_thr = BT_ANTENNA_COUPLING_THRESHOLD; + bt_cmd->bt4_antenna_isolation_thr = + IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS; bt_cmd->bt4_antenna_isolation = iwlwifi_mod_params.ant_coupling; bt_cmd->bt4_tx_tx_delta_freq_thr = 15; bt_cmd->bt4_tx_rx_max_freq0 = 15; diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index dfec5b5e7e14..f2887838cd39 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h @@ -96,5 +96,6 @@ #define IWL_MVM_QUOTA_THRESHOLD 8 #define IWL_MVM_RS_RSSI_BASED_INIT_RATE 0 #define IWL_MVM_RS_DISABLE_MIMO 0 +#define IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS 30 #endif /* __MVM_CONSTANTS_H */ -- cgit v1.2.3 From 3b8983b17c78f08e40e1ddc8051bdf839097ba27 Mon Sep 17 00:00:00 2001 From: Max Stepanov Date: Wed, 15 Oct 2014 11:27:16 +0300 Subject: iwlwifi: mvm: add MVM_FW_BCAST_FILTER_PASS_ALL option The MVM_FW_BCAST_FILTER_PASS_ALL option defined in iwl-dbg-cfg.ini configuration file allows to enable/disable FW broadcast filtering. If MVM_FW_BCAST_FILTER_PASS_ALL is not defined in iwl-dbg-cfg.ini or its value is 0, the mvm broadcast filtering is enabled. Setting MVM_FW_BCAST_FILTER_PASS_ALL=1 in iwl-dbg-cfg.ini blocks sending of BCAST_FILTER_CMD to FW. Signed-off-by: Max Stepanov Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/constants.h | 3 ++- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index f2887838cd39..a2b473d50362 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h @@ -92,10 +92,11 @@ #define IWL_MVM_BT_COEX_SYNC2SCO 1 #define IWL_MVM_BT_COEX_CORUNNING 0 #define IWL_MVM_BT_COEX_MPLUT 1 +#define IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS 30 #define IWL_MVM_FW_MCAST_FILTER_PASS_ALL 0 +#define IWL_MVM_FW_BCAST_FILTER_PASS_ALL 0 #define IWL_MVM_QUOTA_THRESHOLD 8 #define IWL_MVM_RS_RSSI_BASED_INIT_RATE 0 #define IWL_MVM_RS_DISABLE_MIMO 0 -#define IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS 30 #endif /* __MVM_CONSTANTS_H */ diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index b17877ce207f..9fc843e6dd2a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1382,6 +1382,9 @@ bool iwl_mvm_bcast_filter_build_cmd(struct iwl_mvm *mvm, .cmd = cmd, }; + if (IWL_MVM_FW_BCAST_FILTER_PASS_ALL) + return false; + memset(cmd, 0, sizeof(*cmd)); cmd->max_bcast_filters = ARRAY_SIZE(cmd->filters); cmd->max_macs = ARRAY_SIZE(cmd->macs); -- cgit v1.2.3 From d92b732e35432d473d18b068597a6220a10e9a96 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Sun, 21 Sep 2014 19:00:42 +0300 Subject: iwlwifi: mvm: remove mvm argument from get_queues_mask It is unused and won't be available in some future invocations of the function. Signed-off-by: Arik Nemtsov Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | 5 ++--- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 2 +- drivers/net/wireless/iwlwifi/mvm/mvm.h | 3 +-- drivers/net/wireless/iwlwifi/mvm/sta.c | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index 0c5c0b0e23f5..b8ab4a108720 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -197,8 +197,7 @@ static void iwl_mvm_mac_tsf_id_iter(void *_data, u8 *mac, /* * Get the mask of the queues used by the vif */ -u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) +u32 iwl_mvm_mac_get_queues_mask(struct ieee80211_vif *vif) { u32 qmask = 0, ac; @@ -227,7 +226,7 @@ static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac, } /* Mark the queues used by the vif */ - data->used_hw_queues |= iwl_mvm_mac_get_queues_mask(data->mvm, vif); + data->used_hw_queues |= iwl_mvm_mac_get_queues_mask(vif); /* Mark MAC IDs as used by clearing the available bit, and * (below) mark TSFs as used if their existing use is not diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 9fc843e6dd2a..c087bf69d290 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1086,7 +1086,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { - u32 tfd_msk = iwl_mvm_mac_get_queues_mask(mvm, vif); + u32 tfd_msk = iwl_mvm_mac_get_queues_mask(vif); if (tfd_msk) { mutex_lock(&mvm->mutex); diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index aec9f579f5a9..d14dc061d1c2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -909,8 +909,7 @@ int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool force_assoc_off, const u8 *bssid_override); int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif); -u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm, - struct ieee80211_vif *vif); +u32 iwl_mvm_mac_get_queues_mask(struct ieee80211_vif *vif); int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 1731c205c81d..dd0dc5bf8583 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -609,7 +609,7 @@ int iwl_mvm_alloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) lockdep_assert_held(&mvm->mutex); - qmask = iwl_mvm_mac_get_queues_mask(mvm, vif); + qmask = iwl_mvm_mac_get_queues_mask(vif); /* * The firmware defines the TFD queue mask to only be relevant -- cgit v1.2.3 From ee00aed175e64c570e9da7052e39cdcc4ec822af Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 19 Oct 2014 14:18:14 +0300 Subject: iwlwifi: mvm: BT Coex - make the multiprio lut a constant This makes it easier to tune the values during the testing. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/coex.c | 9 ++------- drivers/net/wireless/iwlwifi/mvm/coex_legacy.c | 9 ++------- drivers/net/wireless/iwlwifi/mvm/constants.h | 2 ++ 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index 515f9cbcf289..508c81359e41 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -300,11 +300,6 @@ static const __le64 iwl_ci_mask[][3] = { }, }; -static const __le32 iwl_bt_mprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE] = { - cpu_to_le32(0x2e402280), - cpu_to_le32(0x7711a751), -}; - struct corunning_block_luts { u8 range; __le32 lut20[BT_COEX_CORUN_LUT_SIZE]; @@ -636,8 +631,8 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) memcpy(&bt_cmd->mplut_prio_boost, iwl_bt_prio_boost, sizeof(iwl_bt_prio_boost)); - memcpy(&bt_cmd->multiprio_lut, iwl_bt_mprio_lut, - sizeof(iwl_bt_mprio_lut)); + bt_cmd->multiprio_lut[0] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG0); + bt_cmd->multiprio_lut[1] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG1); send_cmd: memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); diff --git a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c index 3f3b8ee51b1c..b571e1b0550c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c @@ -288,11 +288,6 @@ static const __le64 iwl_ci_mask[][3] = { }, }; -static const __le32 iwl_bt_mprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE] = { - cpu_to_le32(0x2e402280), - cpu_to_le32(0x7711a751), -}; - struct corunning_block_luts { u8 range; __le32 lut20[BT_COEX_CORUN_LUT_SIZE]; @@ -648,8 +643,8 @@ int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm) memcpy(&bt_cmd->bt_prio_boost, iwl_bt_prio_boost, sizeof(iwl_bt_prio_boost)); - memcpy(&bt_cmd->bt4_multiprio_lut, iwl_bt_mprio_lut, - sizeof(iwl_bt_mprio_lut)); + bt_cmd->bt4_multiprio_lut[0] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG0); + bt_cmd->bt4_multiprio_lut[1] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG1); send_cmd: memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old)); diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index a2b473d50362..5c1ea80d5e3b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h @@ -92,6 +92,8 @@ #define IWL_MVM_BT_COEX_SYNC2SCO 1 #define IWL_MVM_BT_COEX_CORUNNING 0 #define IWL_MVM_BT_COEX_MPLUT 1 +#define IWL_MVM_BT_COEX_MPLUT_REG0 0x2e402280 +#define IWL_MVM_BT_COEX_MPLUT_REG1 0x7711a751 #define IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS 30 #define IWL_MVM_FW_MCAST_FILTER_PASS_ALL 0 #define IWL_MVM_FW_BCAST_FILTER_PASS_ALL 0 -- cgit v1.2.3 From f85e9d19d451b9cc3b0381a9422320f9b630441c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 8 Oct 2014 09:57:29 +0200 Subject: iwlwifi: mvm: improve MCS rate warning The warning gives no information about the frame, and presents the flags so that one might think they're the frame. Clarify and add more information. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/tx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index c6a517c771df..8d848735cdb8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -189,8 +189,10 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, /* HT rate doesn't make sense for a non data frame */ WARN_ONCE(info->control.rates[0].flags & IEEE80211_TX_RC_MCS, - "Got an HT rate for a non data frame 0x%x\n", - info->control.rates[0].flags); + "Got an HT rate (flags:0x%x/mcs:%d) for a non data frame (fc:0x%x)\n", + info->control.rates[0].flags, + info->control.rates[0].idx, + le16_to_cpu(fc)); rate_idx = info->control.rates[0].idx; /* if the rate isn't a well known legacy rate, take the lowest one */ -- cgit v1.2.3 From 480acbcee4e25ea3af0df3c0423dc29540551258 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 10 Oct 2014 08:59:27 +0200 Subject: iwlwifi: mvm: flush queues without mutex held For WMM-AC we may have to be changing QoS parameters while the queues are being flushed. This is not relevant in the "drop" case, but matters when we wait for the device to finish the transmissions. To allow this, do the actual waiting without holding the mutex. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index c087bf69d290..14be10829510 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -2997,18 +2997,24 @@ static void iwl_mvm_mac_flush(struct ieee80211_hw *hw, mvmvif = iwl_mvm_vif_from_mac80211(vif); mvmsta = iwl_mvm_sta_from_staid_protected(mvm, mvmvif->ap_sta_id); - if (WARN_ON_ONCE(!mvmsta)) - goto done; + if (WARN_ON_ONCE(!mvmsta)) { + mutex_unlock(&mvm->mutex); + return; + } if (drop) { if (iwl_mvm_flush_tx_path(mvm, mvmsta->tfd_queue_msk, true)) IWL_ERR(mvm, "flush request fail\n"); + mutex_unlock(&mvm->mutex); } else { - iwl_trans_wait_tx_queue_empty(mvm->trans, - mvmsta->tfd_queue_msk); + u32 tfd_queue_msk = mvmsta->tfd_queue_msk; + mutex_unlock(&mvm->mutex); + + /* this can take a while, and we may need/want other operations + * to succeed while doing this, so do it without the mutex held + */ + iwl_trans_wait_tx_queue_empty(mvm->trans, tfd_queue_msk); } -done: - mutex_unlock(&mvm->mutex); } const struct ieee80211_ops iwl_mvm_hw_ops = { -- cgit v1.2.3 From 7ae83d00825b39347b9a591703cd7cc3163523fb Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 10 Oct 2014 10:03:02 +0300 Subject: iwlwifi: mvm: remove unnecessary includes in tt.c We used to need to include some headers in order to read the registers and do all the calculations by ourselves, but this is not done anymore (i.e. we let the firmware do this for us), so we don't need to include those headers anymore. Signed-off-by: Luciano Coelho Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/tt.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c index acca44a45086..d4f2c29025c7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/iwlwifi/mvm/tt.c @@ -64,10 +64,6 @@ *****************************************************************************/ #include "mvm.h" -#include "iwl-config.h" -#include "iwl-io.h" -#include "iwl-csr.h" -#include "iwl-prph.h" #define IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT HZ -- cgit v1.2.3 From 50f6635afe565a0e1c5ab78f040294fe1dc41de0 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 26 Oct 2014 22:25:03 -0700 Subject: iwlwifi: dvm: Fix probable mask then right shift defect Precedence of & and >> is not the same and is not left to right. shift has higher precedence and should be done after the mask. Add parentheses around the mask. Signed-off-by: Joe Perches Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/lib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/dvm/lib.c b/drivers/net/wireless/iwlwifi/dvm/lib.c index 2191621d69c1..02e4ede2b042 100644 --- a/drivers/net/wireless/iwlwifi/dvm/lib.c +++ b/drivers/net/wireless/iwlwifi/dvm/lib.c @@ -418,8 +418,8 @@ void iwlagn_bt_adjust_rssi_monitor(struct iwl_priv *priv, bool rssi_ena) static bool iwlagn_bt_traffic_is_sco(struct iwl_bt_uart_msg *uart_msg) { - return BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3 >> - BT_UART_MSG_FRAME3SCOESCO_POS; + return (BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3) >> + BT_UART_MSG_FRAME3SCOESCO_POS; } static void iwlagn_bt_traffic_change_work(struct work_struct *work) -- cgit v1.2.3 From b260362ab70f5a37179192465f901b9729718cbc Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Thu, 23 Oct 2014 15:30:47 +0300 Subject: iwlwifi: enable STBC support for 8000 chips These chips support STBC in both Tx and Rx. Given that we've added STBC Tx support enable it. Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-8000.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index d2b7234b1c73..896ea906549c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -104,6 +104,7 @@ static const struct iwl_base_params iwl8000_base_params = { }; static const struct iwl_ht_params iwl8000_ht_params = { + .stbc = true, .ldpc = true, .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ), }; -- cgit v1.2.3 From aadede6e9f4c8ee46808b2f697b714ee50810e23 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 9 Oct 2014 17:01:36 +0200 Subject: iwlwifi: mvm: port to devcoredump framework iwlwifi features a debug mechanism that allows to dump binary data which is helpful to debug the firmware. Until now, this data was made available for the userspace through debugfs. For this exact purpose, devcoredump was created. Move to the new infrastructure. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/Kconfig | 1 + drivers/net/wireless/iwlwifi/iwl-trans.h | 4 -- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 79 ----------------------------- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 57 +++++++++++++++++---- drivers/net/wireless/iwlwifi/mvm/mvm.h | 5 -- drivers/net/wireless/iwlwifi/mvm/ops.c | 5 -- drivers/net/wireless/iwlwifi/pcie/trans.c | 16 +++--- 7 files changed, 55 insertions(+), 112 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 267e48a2915e..139de90c2aaf 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -59,6 +59,7 @@ config IWLDVM config IWLMVM tristate "Intel Wireless WiFi MVM Firmware support" + select BACKPORT_WANT_DEV_COREDUMP help This is the driver that supports the MVM firmware which is currently only available for 7260 and 3160 devices. diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index d8fc548c0d6c..0768f83e709d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -535,9 +535,7 @@ struct iwl_trans_ops { void (*ref)(struct iwl_trans *trans); void (*unref)(struct iwl_trans *trans); -#ifdef CONFIG_IWLWIFI_DEBUGFS struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans); -#endif }; /** @@ -704,7 +702,6 @@ static inline void iwl_trans_unref(struct iwl_trans *trans) trans->ops->unref(trans); } -#ifdef CONFIG_IWLWIFI_DEBUGFS static inline struct iwl_trans_dump_data * iwl_trans_dump_data(struct iwl_trans *trans) { @@ -712,7 +709,6 @@ iwl_trans_dump_data(struct iwl_trans *trans) return NULL; return trans->ops->dump_data(trans); } -#endif static inline int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 2a61baca5081..51b7116965ed 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -121,78 +121,6 @@ static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf, return ret; } -static int iwl_dbgfs_fw_error_dump_open(struct inode *inode, struct file *file) -{ - struct iwl_mvm *mvm = inode->i_private; - int ret; - - if (!mvm) - return -EINVAL; - - mutex_lock(&mvm->mutex); - if (!mvm->fw_error_dump) { - ret = -ENODATA; - goto out; - } - - file->private_data = mvm->fw_error_dump; - mvm->fw_error_dump = NULL; - ret = 0; - -out: - mutex_unlock(&mvm->mutex); - return ret; -} - -static ssize_t iwl_dbgfs_fw_error_dump_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_mvm_dump_ptrs *dump_ptrs = (void *)file->private_data; - ssize_t bytes_read = 0; - ssize_t bytes_read_trans = 0; - - if (*ppos < dump_ptrs->op_mode_len) - bytes_read += - simple_read_from_buffer(user_buf, count, ppos, - dump_ptrs->op_mode_ptr, - dump_ptrs->op_mode_len); - - if (bytes_read < 0 || *ppos < dump_ptrs->op_mode_len) - return bytes_read; - - if (dump_ptrs->trans_ptr) { - *ppos -= dump_ptrs->op_mode_len; - bytes_read_trans = - simple_read_from_buffer(user_buf + bytes_read, - count - bytes_read, ppos, - dump_ptrs->trans_ptr->data, - dump_ptrs->trans_ptr->len); - *ppos += dump_ptrs->op_mode_len; - - if (bytes_read_trans >= 0) - bytes_read += bytes_read_trans; - else if (!bytes_read) - /* propagate the failure */ - return bytes_read_trans; - } - - return bytes_read; - -} - -static int iwl_dbgfs_fw_error_dump_release(struct inode *inode, - struct file *file) -{ - struct iwl_mvm_dump_ptrs *dump_ptrs = (void *)file->private_data; - - vfree(dump_ptrs->op_mode_ptr); - vfree(dump_ptrs->trans_ptr); - kfree(dump_ptrs); - - return 0; -} - static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -1535,12 +1463,6 @@ MVM_DEBUGFS_WRITE_FILE_OPS(bt_force_ant, 10); MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8); MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8); -static const struct file_operations iwl_dbgfs_fw_error_dump_ops = { - .open = iwl_dbgfs_fw_error_dump_open, - .read = iwl_dbgfs_fw_error_dump_read, - .release = iwl_dbgfs_fw_error_dump_release, -}; - #ifdef CONFIG_IWLWIFI_BCAST_FILTERING MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256); MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256); @@ -1567,7 +1489,6 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) S_IWUSR | S_IRUSR); MVM_DEBUGFS_ADD_FILE(nic_temp, dbgfs_dir, S_IRUSR); MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR); - MVM_DEBUGFS_ADD_FILE(fw_error_dump, dbgfs_dir, S_IRUSR); MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR); MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR); MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir, diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 14be10829510..3276b31898da 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -69,6 +69,7 @@ #include #include #include +#include #include #include #include @@ -679,10 +680,51 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, memset(&mvmvif->bf_data, 0, sizeof(mvmvif->bf_data)); } -#ifdef CONFIG_IWLWIFI_DEBUGFS +static ssize_t iwl_mvm_read_coredump(char *buffer, loff_t offset, size_t count, + const void *data, size_t datalen) +{ + const struct iwl_mvm_dump_ptrs *dump_ptrs = data; + ssize_t bytes_read; + ssize_t bytes_read_trans; + + if (offset < dump_ptrs->op_mode_len) { + bytes_read = min_t(ssize_t, count, + dump_ptrs->op_mode_len - offset); + memcpy(buffer, (u8 *)dump_ptrs->op_mode_ptr + offset, + bytes_read); + offset += bytes_read; + count -= bytes_read; + + if (count == 0) + return bytes_read; + } else { + bytes_read = 0; + } + + if (!dump_ptrs->trans_ptr) + return bytes_read; + + offset -= dump_ptrs->op_mode_len; + bytes_read_trans = min_t(ssize_t, count, + dump_ptrs->trans_ptr->len - offset); + memcpy(buffer + bytes_read, + (u8 *)dump_ptrs->trans_ptr->data + offset, + bytes_read_trans); + + return bytes_read + bytes_read_trans; +} + +static void iwl_mvm_free_coredump(const void *data) +{ + const struct iwl_mvm_dump_ptrs *fw_error_dump = data; + + vfree(fw_error_dump->op_mode_ptr); + vfree(fw_error_dump->trans_ptr); + kfree(fw_error_dump); +} + void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) { - static char *env[] = { "DRIVER=iwlwifi", "EVENT=error_dump", NULL }; struct iwl_fw_error_dump_file *dump_file; struct iwl_fw_error_dump_data *dump_data; struct iwl_fw_error_dump_info *dump_info; @@ -695,10 +737,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) lockdep_assert_held(&mvm->mutex); - if (mvm->fw_error_dump) - return; - - fw_error_dump = kzalloc(sizeof(*mvm->fw_error_dump), GFP_KERNEL); + fw_error_dump = kzalloc(sizeof(*fw_error_dump), GFP_KERNEL); if (!fw_error_dump) return; @@ -773,12 +812,10 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) if (fw_error_dump->trans_ptr) file_len += fw_error_dump->trans_ptr->len; dump_file->file_len = cpu_to_le32(file_len); - mvm->fw_error_dump = fw_error_dump; - /* notify the userspace about the error we had */ - kobject_uevent_env(&mvm->hw->wiphy->dev.kobj, KOBJ_CHANGE, env); + dev_coredumpm(mvm->trans->dev, THIS_MODULE, fw_error_dump, 0, + GFP_KERNEL, iwl_mvm_read_coredump, iwl_mvm_free_coredump); } -#endif static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) { diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index d14dc061d1c2..256765accbc6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -648,7 +648,6 @@ struct iwl_mvm { /* -1 for always, 0 for never, >0 for that many times */ s8 restart_fw; struct work_struct fw_error_dump_wk; - struct iwl_mvm_dump_ptrs *fw_error_dump; #ifdef CONFIG_IWLWIFI_LEDS struct led_classdev led; @@ -1216,10 +1215,6 @@ void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm); void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error); -#ifdef CONFIG_IWLWIFI_DEBUGFS void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm); -#else -static inline void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) {} -#endif #endif /* __IWL_MVM_H__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 91b28e869969..bd52ecfabedb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -587,11 +587,6 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) ieee80211_unregister_hw(mvm->hw); kfree(mvm->scan_cmd); - if (mvm->fw_error_dump) { - vfree(mvm->fw_error_dump->op_mode_ptr); - vfree(mvm->fw_error_dump->trans_ptr); - kfree(mvm->fw_error_dump); - } kfree(mvm->mcast_filter_cmd); mvm->mcast_filter_cmd = NULL; diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 8027138c47e9..40a290603ead 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -1764,6 +1764,13 @@ err: IWL_ERR(trans, "failed to create the trans debugfs entry\n"); return -ENOMEM; } +#else +static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, + struct dentry *dir) +{ + return 0; +} +#endif /*CONFIG_IWLWIFI_DEBUGFS */ static u32 iwl_trans_pcie_get_cmdlen(struct iwl_tfd *tfd) { @@ -2042,13 +2049,6 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) return dump_data; } -#else -static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, - struct dentry *dir) -{ - return 0; -} -#endif /*CONFIG_IWLWIFI_DEBUGFS */ static const struct iwl_trans_ops trans_ops_pcie = { .start_hw = iwl_trans_pcie_start_hw, @@ -2085,9 +2085,7 @@ static const struct iwl_trans_ops trans_ops_pcie = { .release_nic_access = iwl_trans_pcie_release_nic_access, .set_bits_mask = iwl_trans_pcie_set_bits_mask, -#ifdef CONFIG_IWLWIFI_DEBUGFS .dump_data = iwl_trans_pcie_dump_data, -#endif }; struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, -- cgit v1.2.3 From 1e2ebe0e407159ae94974a93264260883f9a39ad Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Sun, 26 Oct 2014 15:53:27 +0200 Subject: iwlwifi: mvm: fix scan condition iterator Scan condition iterator assumes that an interface is associated if phy_ctxt is assigned, but this isn't the sutuation in P2P device. OTOH P2P device is never associated so we can simply ignore it. Signed-off-by: David Spinadel Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/scan.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 64c02a274f76..042fcdc81f41 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -270,7 +270,8 @@ static void iwl_mvm_scan_condition_iterator(void *data, u8 *mac, struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); bool *global_bound = data; - if (mvmvif->phy_ctxt && mvmvif->phy_ctxt->id < MAX_PHYS) + if (vif->type != NL80211_IFTYPE_P2P_DEVICE && mvmvif->phy_ctxt && + mvmvif->phy_ctxt->id < MAX_PHYS) *global_bound = true; } -- cgit v1.2.3 From d8bafeaf46a0e442723859f58fbf863f7c39875f Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Thu, 23 Oct 2014 13:58:38 +0300 Subject: iwlwifi: mvm: rs: add Tx STBC support STBC is enabled on HT/VHT SISO rates in case we don't care about power consumption and it won't hurt BT. This is done only in case the peer and our chip support STBC of course. While at it fixed a bug which was causing bw and ldpc flags to be set incorrectly in the rate scale table in case we are switching to a legacy Tx column. This had no real impact. Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 75 ++++++++++++++++++++++++++++++----- drivers/net/wireless/iwlwifi/mvm/rs.h | 2 + 2 files changed, 68 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 66e971a99d7c..ce884847cc8a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -505,10 +505,11 @@ static const char *rs_pretty_lq_type(enum iwl_table_type type) static inline void rs_dump_rate(struct iwl_mvm *mvm, const struct rs_rate *rate, const char *prefix) { - IWL_DEBUG_RATE(mvm, "%s: (%s: %d) ANT: %s BW: %d SGI: %d LDPC: %d\n", + IWL_DEBUG_RATE(mvm, + "%s: (%s: %d) ANT: %s BW: %d SGI: %d LDPC: %d STBC %d\n", prefix, rs_pretty_lq_type(rate->type), rate->index, rs_pretty_ant(rate->ant), - rate->bw, rate->sgi, rate->ldpc); + rate->bw, rate->sgi, rate->ldpc, rate->stbc); } static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) @@ -741,6 +742,12 @@ static u32 ucode_rate_from_rs_rate(struct iwl_mvm *mvm, IWL_ERR(mvm, "Invalid rate->type %d\n", rate->type); } + if (is_siso(rate) && rate->stbc) { + /* To enable STBC we need to set both a flag and ANT_AB */ + ucode_rate |= RATE_MCS_ANT_AB_MSK; + ucode_rate |= RATE_MCS_VHT_STBC_MSK; + } + ucode_rate |= rate->bw; if (rate->sgi) ucode_rate |= RATE_MCS_SGI_MSK; @@ -785,6 +792,8 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate, rate->sgi = true; if (ucode_rate & RATE_MCS_LDPC_MSK) rate->ldpc = true; + if (ucode_rate & RATE_MCS_VHT_STBC_MSK) + rate->stbc = true; rate->bw = ucode_rate & RATE_MCS_CHAN_WIDTH_MSK; @@ -794,7 +803,7 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate, if (nss == 1) { rate->type = LQ_HT_SISO; - WARN_ON_ONCE(num_of_ant != 1); + WARN_ON_ONCE(!rate->stbc && num_of_ant != 1); } else if (nss == 2) { rate->type = LQ_HT_MIMO2; WARN_ON_ONCE(num_of_ant != 2); @@ -992,7 +1001,15 @@ static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta, static inline bool rs_rate_match(struct rs_rate *a, struct rs_rate *b) { - return (a->type == b->type) && (a->ant == b->ant) && (a->sgi == b->sgi); + bool ant_match; + + if (a->stbc) + ant_match = (b->ant == ANT_A || b->ant == ANT_B); + else + ant_match = (a->ant == b->ant); + + return (a->type == b->type) && (a->bw == b->bw) && (a->sgi == b->sgi) + && ant_match; } static u32 rs_ch_width_from_mac_flags(enum mac80211_rate_control_flags flags) @@ -1623,6 +1640,8 @@ static int rs_switch_to_column(struct iwl_mvm *mvm, else rate->type = LQ_LEGACY_G; + rate->bw = RATE_MCS_CHAN_WIDTH_20; + rate->ldpc = false; rate_mask = lq_sta->active_legacy_rate; } else if (column->mode == RS_SISO) { rate->type = lq_sta->is_vht ? LQ_VHT_SISO : LQ_HT_SISO; @@ -1634,8 +1653,11 @@ static int rs_switch_to_column(struct iwl_mvm *mvm, WARN_ON_ONCE("Bad column mode"); } - rate->bw = rs_bw_from_sta_bw(sta); - rate->ldpc = lq_sta->ldpc; + if (column->mode != RS_LEGACY) { + rate->bw = rs_bw_from_sta_bw(sta); + rate->ldpc = lq_sta->ldpc; + } + search_tbl->column = col_id; rs_set_expected_tpt_table(lq_sta, search_tbl); @@ -1754,6 +1776,29 @@ out: return action; } +static bool rs_stbc_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta, + struct iwl_lq_sta *lq_sta) +{ + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + struct ieee80211_vif *vif = mvmsta->vif; + bool sta_ps_disabled = (vif->type == NL80211_IFTYPE_STATION && + !vif->bss_conf.ps); + + /* Our chip supports Tx STBC and the peer is an HT/VHT STA which + * supports STBC of at least 1*SS + */ + if (!lq_sta->stbc) + return false; + + if (!mvm->ps_disabled && !sta_ps_disabled) + return false; + + if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) + return false; + + return true; +} + static void rs_get_adjacent_txp(struct iwl_mvm *mvm, int index, int *weaker, int *stronger) { @@ -2675,6 +2720,11 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, if (mvm->cfg->ht_params->ldpc && (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING)) lq_sta->ldpc = true; + + if (mvm->cfg->ht_params->stbc && + (num_of_ant(mvm->fw->valid_tx_ant) > 1) && + (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC)) + lq_sta->stbc = true; } else { rs_vht_set_enabled_rates(sta, vht_cap, lq_sta); lq_sta->is_vht = true; @@ -2682,6 +2732,11 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, if (mvm->cfg->ht_params->ldpc && (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC)) lq_sta->ldpc = true; + + if (mvm->cfg->ht_params->stbc && + (num_of_ant(mvm->fw->valid_tx_ant) > 1) && + (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK)) + lq_sta->stbc = true; } if (IWL_MVM_RS_DISABLE_MIMO) @@ -2695,11 +2750,11 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, BITS_PER_LONG); IWL_DEBUG_RATE(mvm, - "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d\n", + "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d STBC%d\n", lq_sta->active_legacy_rate, lq_sta->active_siso_rate, lq_sta->active_mimo2_rate, - lq_sta->is_vht, lq_sta->ldpc); + lq_sta->is_vht, lq_sta->ldpc, lq_sta->stbc); IWL_DEBUG_RATE(mvm, "MAX RATE: LEGACY=%d SISO=%d MIMO2=%d\n", lq_sta->max_legacy_rate_idx, lq_sta->max_siso_rate_idx, @@ -2823,6 +2878,7 @@ static void rs_fill_rates_for_column(struct iwl_mvm *mvm, * rate[15] 0x800D Legacy | ANT: B Rate: 6 Mbps */ static void rs_build_rates_table(struct iwl_mvm *mvm, + struct ieee80211_sta *sta, struct iwl_lq_sta *lq_sta, const struct rs_rate *initial_rate) { @@ -2835,6 +2891,7 @@ static void rs_build_rates_table(struct iwl_mvm *mvm, memcpy(&rate, initial_rate, sizeof(rate)); valid_tx_ant = mvm->fw->valid_tx_ant; + rate.stbc = rs_stbc_allow(mvm, sta, lq_sta); if (is_siso(&rate)) { num_rates = RS_INITIAL_SISO_NUM_RATES; @@ -2906,7 +2963,7 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm, if (WARN_ON_ONCE(!sta || !initial_rate)) return; - rs_build_rates_table(mvm, lq_sta, initial_rate); + rs_build_rates_table(mvm, sta, lq_sta, initial_rate); if (num_of_ant(initial_rate->ant) == 1) lq_cmd->single_stream_ant_msk = initial_rate->ant; diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index eb34c1209acc..defd70a6d9e6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -208,6 +208,7 @@ struct rs_rate { u32 bw; bool sgi; bool ldpc; + bool stbc; }; @@ -331,6 +332,7 @@ struct iwl_lq_sta { u64 last_tx; bool is_vht; bool ldpc; /* LDPC Rx is supported by the STA */ + bool stbc; /* Tx STBC is supported by chip and Rx by STA */ enum ieee80211_band band; /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ -- cgit v1.2.3 From 4ff78181f4efa91e914e2d0940f3bdc4685aae6b Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 22 Jun 2014 14:44:44 +0300 Subject: iwlwifi: mvm: unref SCAN ref on scan completion The scan reference wasn't released in case of offloaded scan, causing the refcount to go wrong and prevent the device from going into d0i3. Signed-off-by: Eliad Peller Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/scan.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 042fcdc81f41..5cd59a43e1da 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -673,6 +673,7 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm, mvm->scan_status = IWL_MVM_SCAN_NONE; ieee80211_scan_completed(mvm->hw, status == IWL_SCAN_OFFLOAD_ABORTED); + iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); } mvm->last_ebs_successful = !ebs_status; @@ -1107,8 +1108,12 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify) /* * Clear the scan status so the next scan requests will succeed. This * also ensures the Rx handler doesn't do anything, as the scan was - * stopped from above. + * stopped from above. Since the rx handler won't do anything now, + * we have to release the scan reference here. */ + if (mvm->scan_status == IWL_MVM_SCAN_OS) + iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); + mvm->scan_status = IWL_MVM_SCAN_NONE; if (notify) { -- cgit v1.2.3