iwlwifi: configure the LTR
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Tue, 23 Sep 2014 20:02:41 +0000 (23:02 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 21 Nov 2014 17:22:53 +0000 (09:22 -0800)
commit 9180ac50716a097a407c6d7e7e4589754a922260 upstream.

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.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
drivers/net/wireless/iwlwifi/mvm/fw-api.h
drivers/net/wireless/iwlwifi/mvm/fw.c
drivers/net/wireless/iwlwifi/mvm/ops.c
drivers/net/wireless/iwlwifi/pcie/trans.c

index 72d2ecce0b8d7614c870cfb41e5d7e4773cd1bd8..d8df1d9b0de3ce3337965fa4626a5f6ed7449b1f 100644 (file)
@@ -489,6 +489,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
@@ -513,6 +514,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;
index 81fe45f46be7e97f1d346ada8c457d065b9a377e..ac38ecf13c18103de520b66706877881aa62fd63 100644 (file)
 /* Power Management Commands, Responses, Notifications */
 
 /**
- * enum iwl_scan_flags - masks for power table command flags
+ * 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;
+
+/**
+ * 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,
index c6384555aab4de0172c7f1a7c5662cce776e76ed..4b6730db42a5e47c5de9d25df3b7ee005e9f7a46 100644 (file)
@@ -138,6 +138,7 @@ enum {
 
        /* Power */
        POWER_TABLE_CMD = 0x77,
+       LTR_CONFIG = 0xee,
 
        /* Scanning */
        SCAN_REQUEST_CMD = 0x80,
index e18c92dd60ecdd768c86e23fe6d0f6505f396018..d250d451fd015fb645ba49cd3d9048300fea6dc4 100644 (file)
@@ -443,6 +443,15 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
        if (ret)
                goto error;
 
+       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));
+       }
+
        IWL_DEBUG_INFO(mvm, "RT uCode started.\n");
 
        return 0;
index 388c8a91496046e99b9d91d837c195dc2c4f0118..649d301cfa2ac82567b49f68edcf10e1f2428cc7 100644 (file)
@@ -293,6 +293,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
        CMD(BT_PROFILE_NOTIFICATION),
        CMD(BT_CONFIG),
        CMD(MCAST_FILTER_CMD),
+       CMD(LTR_CONFIG),
 };
 #undef CMD
 
index ff04135d37afa74c5832e0452934bea631ac4304..6a5eb2b29418da1a60b091b162271ddca0fcede3 100644 (file)
@@ -116,11 +116,13 @@ static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux)
 
 /* PCI registers */
 #define PCI_CFG_RETRY_TIMEOUT  0x041
+#define PCI_EXP_DEVCTL2_LTR_EN 0x0400
 
 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.
@@ -131,16 +133,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");
 }
 
 /*