aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-debugfs.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-08-07 18:41:51 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-08-14 09:13:50 -0400
commite312c24cf8229f9b6e76dbfd5d99eefe21f4ac0a (patch)
tree79e3b967f3905716baef4bc73b4510543b38ceb5 /drivers/net/wireless/iwlwifi/iwl-debugfs.c
parentd91b1ba37744bc7fb7524516be855c9fa81142e2 (diff)
iwlwifi: automatically adjust sleep level
Depending on required latency requested by pm_qos (via mac80211) we can automatically adjust the sleep state. Also, mac80211 has a user-visible dynamic sleep feature where we are supposed to stay awake after sending/receiving frames to better receive response frames to our packets, this can be integrated into the sleep command. Currently, and this patch doesn't change that yet, we default to using sleep level 1 if PS is enabled. With a module parameter to iwlcore, automatic adjustment to changing network latency requirements can be enabled -- this isn't yet the default due to requiring more testing. The goal is to enable automatic adjustment and then go into the deepest possible sleep state possible depending on the networking latency requirements. This patch does, however, enable IEEE80211_HW_SUPPORTS_DYNAMIC_PS to avoid the double-timer (one in software and one in the device) when transmitting -- the exact timeout may be ignored but that is not of big concern. Note also that we keep the hard-coded power indices around for thermal throttling -- the specification of that calls for using the specified power levels. Those can also be selected in debugfs to allow easier testing of such parameters. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-debugfs.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debugfs.c83
1 files changed, 83 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 7b578d41101f..f68fb4711da2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -776,6 +776,83 @@ static ssize_t iwl_dbgfs_disable_ht40_read(struct file *file,
776 return ret; 776 return ret;
777} 777}
778 778
779static ssize_t iwl_dbgfs_sleep_level_override_write(struct file *file,
780 const char __user *user_buf,
781 size_t count, loff_t *ppos)
782{
783 struct iwl_priv *priv = file->private_data;
784 char buf[8];
785 int buf_size;
786 int value;
787
788 memset(buf, 0, sizeof(buf));
789 buf_size = min(count, sizeof(buf) - 1);
790 if (copy_from_user(buf, user_buf, buf_size))
791 return -EFAULT;
792
793 if (sscanf(buf, "%d", &value) != 1)
794 return -EINVAL;
795
796 /*
797 * Our users expect 0 to be "CAM", but 0 isn't actually
798 * valid here. However, let's not confuse them and present
799 * IWL_POWER_INDEX_1 as "1", not "0".
800 */
801 if (value > 0)
802 value -= 1;
803
804 if (value != -1 && (value < 0 || value >= IWL_POWER_NUM))
805 return -EINVAL;
806
807 priv->power_data.debug_sleep_level_override = value;
808
809 iwl_power_update_mode(priv, false);
810
811 return count;
812}
813
814static ssize_t iwl_dbgfs_sleep_level_override_read(struct file *file,
815 char __user *user_buf,
816 size_t count, loff_t *ppos)
817{
818 struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
819 char buf[10];
820 int pos, value;
821 const size_t bufsz = sizeof(buf);
822
823 /* see the write function */
824 value = priv->power_data.debug_sleep_level_override;
825 if (value >= 0)
826 value += 1;
827
828 pos = scnprintf(buf, bufsz, "%d\n", value);
829 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
830}
831
832static ssize_t iwl_dbgfs_current_sleep_command_read(struct file *file,
833 char __user *user_buf,
834 size_t count, loff_t *ppos)
835{
836 struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
837 char buf[200];
838 int pos = 0, i;
839 const size_t bufsz = sizeof(buf);
840 struct iwl_powertable_cmd *cmd = &priv->power_data.sleep_cmd;
841
842 pos += scnprintf(buf + pos, bufsz - pos,
843 "flags: %#.2x\n", le16_to_cpu(cmd->flags));
844 pos += scnprintf(buf + pos, bufsz - pos,
845 "RX/TX timeout: %d/%d usec\n",
846 le32_to_cpu(cmd->rx_data_timeout),
847 le32_to_cpu(cmd->tx_data_timeout));
848 for (i = 0; i < IWL_POWER_VEC_SIZE; i++)
849 pos += scnprintf(buf + pos, bufsz - pos,
850 "sleep_interval[%d]: %d\n", i,
851 le32_to_cpu(cmd->sleep_interval[i]));
852
853 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
854}
855
779DEBUGFS_READ_WRITE_FILE_OPS(sram); 856DEBUGFS_READ_WRITE_FILE_OPS(sram);
780DEBUGFS_WRITE_FILE_OPS(log_event); 857DEBUGFS_WRITE_FILE_OPS(log_event);
781DEBUGFS_READ_FILE_OPS(nvm); 858DEBUGFS_READ_FILE_OPS(nvm);
@@ -789,6 +866,8 @@ DEBUGFS_READ_FILE_OPS(led);
789#endif 866#endif
790DEBUGFS_READ_FILE_OPS(thermal_throttling); 867DEBUGFS_READ_FILE_OPS(thermal_throttling);
791DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40); 868DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40);
869DEBUGFS_READ_WRITE_FILE_OPS(sleep_level_override);
870DEBUGFS_READ_FILE_OPS(current_sleep_command);
792 871
793static ssize_t iwl_dbgfs_traffic_log_read(struct file *file, 872static ssize_t iwl_dbgfs_traffic_log_read(struct file *file,
794 char __user *user_buf, 873 char __user *user_buf,
@@ -1533,6 +1612,8 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
1533#ifdef CONFIG_IWLWIFI_LEDS 1612#ifdef CONFIG_IWLWIFI_LEDS
1534 DEBUGFS_ADD_FILE(led, data); 1613 DEBUGFS_ADD_FILE(led, data);
1535#endif 1614#endif
1615 DEBUGFS_ADD_FILE(sleep_level_override, data);
1616 DEBUGFS_ADD_FILE(current_sleep_command, data);
1536 DEBUGFS_ADD_FILE(thermal_throttling, data); 1617 DEBUGFS_ADD_FILE(thermal_throttling, data);
1537 DEBUGFS_ADD_FILE(disable_ht40, data); 1618 DEBUGFS_ADD_FILE(disable_ht40, data);
1538 DEBUGFS_ADD_FILE(rx_statistics, debug); 1619 DEBUGFS_ADD_FILE(rx_statistics, debug);
@@ -1572,6 +1653,8 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
1572 if (!priv->dbgfs) 1653 if (!priv->dbgfs)
1573 return; 1654 return;
1574 1655
1656 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sleep_level_override);
1657 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_current_sleep_command);
1575 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_nvm); 1658 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_nvm);
1576 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram); 1659 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram);
1577 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_log_event); 1660 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_log_event);