iwlwifi: mvm: Add support for Low Power RX
authorAlexander Bondar <alexander.bondar@intel.com>
Thu, 21 Mar 2013 15:14:14 +0000 (17:14 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Tue, 25 Jun 2013 10:21:19 +0000 (12:21 +0200)
To improve power consumption in idle associated mode FW may lower
RX power. This low linearity mode is acceptable for listening low rate
RX such as beacons and groupcast. The driver enables LPRX only if PM
is enabled and associated AP's beacon TX rate is 1Mbps or 6Mbps.
LPRX RSSI threshold is used to limit a range where LPRX is applied.

Signed-off-by: Alexander Bondar <alexander.bondar@intel.com>
Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/iwlwifi/mvm/debugfs.c
drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/power.c

index 63d19d94b018ffa29db6ef99649c5093e107502d..e56ed2a848886ce6c9001ef9a69a12d54c5f102b 100644 (file)
@@ -344,6 +344,13 @@ static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm,
        case MVM_DEBUGFS_PM_DISABLE_POWER_OFF:
                IWL_DEBUG_POWER(mvm, "disable_power_off=%d\n", val);
                dbgfs_pm->disable_power_off = val;
+       case MVM_DEBUGFS_PM_LPRX_ENA:
+               IWL_DEBUG_POWER(mvm, "lprx %s\n", val ? "enabled" : "disabled");
+               dbgfs_pm->lprx_ena = val;
+               break;
+       case MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD:
+               IWL_DEBUG_POWER(mvm, "lprx_rssi_threshold=%d\n", val);
+               dbgfs_pm->lprx_rssi_threshold = val;
                break;
        }
 }
@@ -387,6 +394,17 @@ static ssize_t iwl_dbgfs_pm_params_write(struct file *file,
                if (sscanf(buf + 18, "%d", &val) != 1)
                        return -EINVAL;
                param = MVM_DEBUGFS_PM_DISABLE_POWER_OFF;
+       } else if (!strncmp("lprx=", buf, 5)) {
+               if (sscanf(buf + 5, "%d", &val) != 1)
+                       return -EINVAL;
+               param = MVM_DEBUGFS_PM_LPRX_ENA;
+       } else if (!strncmp("lprx_rssi_threshold=", buf, 20)) {
+               if (sscanf(buf + 20, "%d", &val) != 1)
+                       return -EINVAL;
+               if (val > POWER_LPRX_RSSI_THRESHOLD_MAX || val <
+                   POWER_LPRX_RSSI_THRESHOLD_MIN)
+                       return -EINVAL;
+               param = MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD;
        } else {
                return -EINVAL;
        }
@@ -421,7 +439,7 @@ static ssize_t iwl_dbgfs_pm_params_read(struct file *file,
                         le32_to_cpu(cmd.skip_dtim_periods));
        pos += scnprintf(buf+pos, bufsz-pos, "power_scheme = %d\n",
                         iwlmvm_mod_params.power_scheme);
-       pos += scnprintf(buf+pos, bufsz-pos, "flags = %d\n",
+       pos += scnprintf(buf+pos, bufsz-pos, "flags = 0x%x\n",
                         le16_to_cpu(cmd.flags));
        pos += scnprintf(buf+pos, bufsz-pos, "keep_alive = %d\n",
                         cmd.keep_alive_seconds);
@@ -435,6 +453,10 @@ static ssize_t iwl_dbgfs_pm_params_read(struct file *file,
                                 le32_to_cpu(cmd.rx_data_timeout));
                pos += scnprintf(buf+pos, bufsz-pos, "tx_data_timeout = %d\n",
                                 le32_to_cpu(cmd.tx_data_timeout));
+               if (cmd.flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK))
+                       pos += scnprintf(buf+pos, bufsz-pos,
+                                        "lprx_rssi_threshold = %d\n",
+                                        le32_to_cpu(cmd.lprx_rssi_threshold));
        }
 
        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
index d8e19290b0f327f27b29b7d2fc5d716ed781b4de..a6da359a80c3e1125a7b0733b5ae9863d8740e12 100644 (file)
 
 /* Power Management Commands, Responses, Notifications */
 
+/* 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
  * @POWER_FLAGS_POWER_SAVE_ENA_MSK: '1' Allow to save power by turning off
index c6ba553845cd129f2ddef5cf1e1727dd9ca64a18..d40d7db185d6cdbb22ca2a2d1fefef0794970971 100644 (file)
@@ -158,6 +158,8 @@ enum iwl_dbgfs_pm_mask {
        MVM_DEBUGFS_PM_RX_DATA_TIMEOUT = BIT(3),
        MVM_DEBUGFS_PM_TX_DATA_TIMEOUT = BIT(4),
        MVM_DEBUGFS_PM_DISABLE_POWER_OFF = BIT(5),
+       MVM_DEBUGFS_PM_LPRX_ENA = BIT(6),
+       MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD = BIT(7),
 };
 
 struct iwl_dbgfs_pm {
@@ -167,6 +169,8 @@ struct iwl_dbgfs_pm {
        bool skip_over_dtim;
        u8 skip_dtim_periods;
        bool disable_power_off;
+       bool lprx_ena;
+       u32 lprx_rssi_threshold;
        int mask;
 };
 
index 3760a33ca3a40cbb13a266cd7c96912017bfce1e..e7ca965a89b82a833366651d27d31f63501ff313 100644 (file)
@@ -137,11 +137,12 @@ static void iwl_mvm_power_log(struct iwl_mvm *mvm,
                                le32_to_cpu(cmd->rx_data_timeout));
                IWL_DEBUG_POWER(mvm, "Tx timeout = %u usec\n",
                                le32_to_cpu(cmd->tx_data_timeout));
-               IWL_DEBUG_POWER(mvm, "LP RX RSSI threshold = %u\n",
-                               cmd->lprx_rssi_threshold);
                if (cmd->flags & cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK))
                        IWL_DEBUG_POWER(mvm, "DTIM periods to skip = %u\n",
                                        le32_to_cpu(cmd->skip_dtim_periods));
+               if (cmd->flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK))
+                       IWL_DEBUG_POWER(mvm, "LP RX RSSI threshold = %u\n",
+                                       le32_to_cpu(cmd->lprx_rssi_threshold));
        }
 }
 
@@ -181,6 +182,14 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 
        cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK);
 
+       if (vif->bss_conf.beacon_rate &&
+           (vif->bss_conf.beacon_rate->bitrate == 10 ||
+            vif->bss_conf.beacon_rate->bitrate == 60)) {
+               cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK);
+               cmd->lprx_rssi_threshold =
+                       cpu_to_le32(POWER_LPRX_RSSI_THRESHOLD);
+       }
+
        dtimper = hw->conf.ps_dtim_period ?: 1;
 
        /* Check if radar detection is required on current channel */
@@ -236,6 +245,15 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS)
                cmd->skip_dtim_periods =
                        cpu_to_le32(mvmvif->dbgfs_pm.skip_dtim_periods);
+       if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_ENA) {
+               if (mvmvif->dbgfs_pm.lprx_ena)
+                       cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK);
+               else
+                       cmd->flags &= cpu_to_le16(~POWER_FLAGS_LPRX_ENA_MSK);
+       }
+       if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD)
+               cmd->lprx_rssi_threshold =
+                       cpu_to_le32(mvmvif->dbgfs_pm.lprx_rssi_threshold);
 #endif /* CONFIG_IWLWIFI_DEBUGFS */
 }