diff options
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 46 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-calib.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-commands.h | 7 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.c | 15 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-debug.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-debugfs.c | 83 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-dev.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-power.c | 317 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-power.h | 30 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl3945-base.c | 66 |
10 files changed, 256 insertions, 313 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 319df4ab7f13..2232b1794e76 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -1606,7 +1606,7 @@ static void iwl_alive_start(struct iwl_priv *priv) | |||
1606 | set_bit(STATUS_READY, &priv->status); | 1606 | set_bit(STATUS_READY, &priv->status); |
1607 | wake_up_interruptible(&priv->wait_command_queue); | 1607 | wake_up_interruptible(&priv->wait_command_queue); |
1608 | 1608 | ||
1609 | iwl_power_update_mode(priv, 1); | 1609 | iwl_power_update_mode(priv, true); |
1610 | 1610 | ||
1611 | /* reassociate for ADHOC mode */ | 1611 | /* reassociate for ADHOC mode */ |
1612 | if (priv->vif && (priv->iw_mode == NL80211_IFTYPE_ADHOC)) { | 1612 | if (priv->vif && (priv->iw_mode == NL80211_IFTYPE_ADHOC)) { |
@@ -2075,7 +2075,7 @@ void iwl_post_associate(struct iwl_priv *priv) | |||
2075 | * If chain noise has already been run, then we need to enable | 2075 | * If chain noise has already been run, then we need to enable |
2076 | * power management here */ | 2076 | * power management here */ |
2077 | if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE) | 2077 | if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE) |
2078 | iwl_power_update_mode(priv, 0); | 2078 | iwl_power_update_mode(priv, false); |
2079 | 2079 | ||
2080 | /* Enable Rx differential gain and sensitivity calibrations */ | 2080 | /* Enable Rx differential gain and sensitivity calibrations */ |
2081 | iwl_chain_noise_reset(priv); | 2081 | iwl_chain_noise_reset(priv); |
@@ -2565,47 +2565,6 @@ static ssize_t store_filter_flags(struct device *d, | |||
2565 | static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags, | 2565 | static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags, |
2566 | store_filter_flags); | 2566 | store_filter_flags); |
2567 | 2567 | ||
2568 | static ssize_t store_power_level(struct device *d, | ||
2569 | struct device_attribute *attr, | ||
2570 | const char *buf, size_t count) | ||
2571 | { | ||
2572 | struct iwl_priv *priv = dev_get_drvdata(d); | ||
2573 | int ret; | ||
2574 | unsigned long mode; | ||
2575 | |||
2576 | |||
2577 | mutex_lock(&priv->mutex); | ||
2578 | |||
2579 | ret = strict_strtoul(buf, 10, &mode); | ||
2580 | if (ret) | ||
2581 | goto out; | ||
2582 | |||
2583 | ret = iwl_power_set_user_mode(priv, mode); | ||
2584 | if (ret) { | ||
2585 | IWL_DEBUG_MAC80211(priv, "failed setting power mode.\n"); | ||
2586 | goto out; | ||
2587 | } | ||
2588 | ret = count; | ||
2589 | |||
2590 | out: | ||
2591 | mutex_unlock(&priv->mutex); | ||
2592 | return ret; | ||
2593 | } | ||
2594 | |||
2595 | static ssize_t show_power_level(struct device *d, | ||
2596 | struct device_attribute *attr, char *buf) | ||
2597 | { | ||
2598 | struct iwl_priv *priv = dev_get_drvdata(d); | ||
2599 | int level = priv->power_data.power_mode; | ||
2600 | char *p = buf; | ||
2601 | |||
2602 | p += sprintf(p, "%d\n", level); | ||
2603 | return p - buf + 1; | ||
2604 | } | ||
2605 | |||
2606 | static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, | ||
2607 | store_power_level); | ||
2608 | |||
2609 | 2568 | ||
2610 | static ssize_t show_statistics(struct device *d, | 2569 | static ssize_t show_statistics(struct device *d, |
2611 | struct device_attribute *attr, char *buf) | 2570 | struct device_attribute *attr, char *buf) |
@@ -2698,7 +2657,6 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv) | |||
2698 | static struct attribute *iwl_sysfs_entries[] = { | 2657 | static struct attribute *iwl_sysfs_entries[] = { |
2699 | &dev_attr_flags.attr, | 2658 | &dev_attr_flags.attr, |
2700 | &dev_attr_filter_flags.attr, | 2659 | &dev_attr_filter_flags.attr, |
2701 | &dev_attr_power_level.attr, | ||
2702 | &dev_attr_statistics.attr, | 2660 | &dev_attr_statistics.attr, |
2703 | &dev_attr_temperature.attr, | 2661 | &dev_attr_temperature.attr, |
2704 | &dev_attr_tx_power.attr, | 2662 | &dev_attr_tx_power.attr, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index 13180d6ee2f7..c4b565a2de94 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c | |||
@@ -852,7 +852,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, | |||
852 | priv->cfg->ops->lib->update_chain_flags(priv); | 852 | priv->cfg->ops->lib->update_chain_flags(priv); |
853 | 853 | ||
854 | data->state = IWL_CHAIN_NOISE_DONE; | 854 | data->state = IWL_CHAIN_NOISE_DONE; |
855 | iwl_power_update_mode(priv, 0); | 855 | iwl_power_update_mode(priv, false); |
856 | } | 856 | } |
857 | EXPORT_SYMBOL(iwl_chain_noise_calibration); | 857 | EXPORT_SYMBOL(iwl_chain_noise_calibration); |
858 | 858 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 6188c54113b0..68d7719071f7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h | |||
@@ -2313,15 +2313,22 @@ struct iwl_spectrum_notification { | |||
2313 | * PM allow: | 2313 | * PM allow: |
2314 | * bit 0 - '0' Driver not allow power management | 2314 | * bit 0 - '0' Driver not allow power management |
2315 | * '1' Driver allow PM (use rest of parameters) | 2315 | * '1' Driver allow PM (use rest of parameters) |
2316 | * | ||
2316 | * uCode send sleep notifications: | 2317 | * uCode send sleep notifications: |
2317 | * bit 1 - '0' Don't send sleep notification | 2318 | * bit 1 - '0' Don't send sleep notification |
2318 | * '1' send sleep notification (SEND_PM_NOTIFICATION) | 2319 | * '1' send sleep notification (SEND_PM_NOTIFICATION) |
2320 | * | ||
2319 | * Sleep over DTIM | 2321 | * Sleep over DTIM |
2320 | * bit 2 - '0' PM have to walk up every DTIM | 2322 | * bit 2 - '0' PM have to walk up every DTIM |
2321 | * '1' PM could sleep over DTIM till listen Interval. | 2323 | * '1' PM could sleep over DTIM till listen Interval. |
2324 | * | ||
2322 | * PCI power managed | 2325 | * PCI power managed |
2323 | * bit 3 - '0' (PCI_CFG_LINK_CTRL & 0x1) | 2326 | * bit 3 - '0' (PCI_CFG_LINK_CTRL & 0x1) |
2324 | * '1' !(PCI_CFG_LINK_CTRL & 0x1) | 2327 | * '1' !(PCI_CFG_LINK_CTRL & 0x1) |
2328 | * | ||
2329 | * Fast PD | ||
2330 | * bit 4 - '1' Put radio to sleep when receiving frame for others | ||
2331 | * | ||
2325 | * Force sleep Modes | 2332 | * Force sleep Modes |
2326 | * bit 31/30- '00' use both mac/xtal sleeps | 2333 | * bit 31/30- '00' use both mac/xtal sleeps |
2327 | * '01' force Mac sleep | 2334 | * '01' force Mac sleep |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 36c6e16285de..af735128333a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c | |||
@@ -1568,7 +1568,8 @@ int iwl_setup_mac(struct iwl_priv *priv) | |||
1568 | IEEE80211_HW_NOISE_DBM | | 1568 | IEEE80211_HW_NOISE_DBM | |
1569 | IEEE80211_HW_AMPDU_AGGREGATION | | 1569 | IEEE80211_HW_AMPDU_AGGREGATION | |
1570 | IEEE80211_HW_SPECTRUM_MGMT | | 1570 | IEEE80211_HW_SPECTRUM_MGMT | |
1571 | IEEE80211_HW_SUPPORTS_PS; | 1571 | IEEE80211_HW_SUPPORTS_PS | |
1572 | IEEE80211_HW_SUPPORTS_DYNAMIC_PS; | ||
1572 | hw->wiphy->interface_modes = | 1573 | hw->wiphy->interface_modes = |
1573 | BIT(NL80211_IFTYPE_STATION) | | 1574 | BIT(NL80211_IFTYPE_STATION) | |
1574 | BIT(NL80211_IFTYPE_ADHOC); | 1575 | BIT(NL80211_IFTYPE_ADHOC); |
@@ -1663,8 +1664,6 @@ int iwl_init_drv(struct iwl_priv *priv) | |||
1663 | priv->qos_data.qos_cap.val = 0; | 1664 | priv->qos_data.qos_cap.val = 0; |
1664 | 1665 | ||
1665 | priv->rates_mask = IWL_RATES_MASK; | 1666 | priv->rates_mask = IWL_RATES_MASK; |
1666 | /* If power management is turned on, default to CAM mode */ | ||
1667 | priv->power_mode = IWL_POWER_MODE_CAM; | ||
1668 | priv->tx_power_user_lmt = IWL_TX_POWER_TARGET_POWER_MAX; | 1667 | priv->tx_power_user_lmt = IWL_TX_POWER_TARGET_POWER_MAX; |
1669 | 1668 | ||
1670 | ret = iwl_init_channel_map(priv); | 1669 | ret = iwl_init_channel_map(priv); |
@@ -2551,7 +2550,6 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw, | |||
2551 | if (bss_conf->assoc) { | 2550 | if (bss_conf->assoc) { |
2552 | priv->assoc_id = bss_conf->aid; | 2551 | priv->assoc_id = bss_conf->aid; |
2553 | priv->beacon_int = bss_conf->beacon_int; | 2552 | priv->beacon_int = bss_conf->beacon_int; |
2554 | priv->power_data.dtim_period = bss_conf->dtim_period; | ||
2555 | priv->timestamp = bss_conf->timestamp; | 2553 | priv->timestamp = bss_conf->timestamp; |
2556 | priv->assoc_capability = bss_conf->assoc_capability; | 2554 | priv->assoc_capability = bss_conf->assoc_capability; |
2557 | 2555 | ||
@@ -2801,13 +2799,10 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) | |||
2801 | iwl_set_rate(priv); | 2799 | iwl_set_rate(priv); |
2802 | } | 2800 | } |
2803 | 2801 | ||
2804 | if (changed & IEEE80211_CONF_CHANGE_PS && | 2802 | if (changed & IEEE80211_CONF_CHANGE_PS) { |
2805 | priv->iw_mode == NL80211_IFTYPE_STATION) { | 2803 | ret = iwl_power_update_mode(priv, false); |
2806 | priv->power_data.power_disabled = | ||
2807 | !(conf->flags & IEEE80211_CONF_PS); | ||
2808 | ret = iwl_power_update_mode(priv, 0); | ||
2809 | if (ret) | 2804 | if (ret) |
2810 | IWL_DEBUG_MAC80211(priv, "Error setting power level\n"); | 2805 | IWL_DEBUG_MAC80211(priv, "Error setting sleep level\n"); |
2811 | } | 2806 | } |
2812 | 2807 | ||
2813 | if (changed & IEEE80211_CONF_CHANGE_POWER) { | 2808 | if (changed & IEEE80211_CONF_CHANGE_POWER) { |
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 82befb7ce997..723f38a023ce 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h | |||
@@ -88,6 +88,8 @@ struct iwl_debugfs { | |||
88 | struct dentry *file_led; | 88 | struct dentry *file_led; |
89 | #endif | 89 | #endif |
90 | struct dentry *file_disable_ht40; | 90 | struct dentry *file_disable_ht40; |
91 | struct dentry *file_sleep_level_override; | ||
92 | struct dentry *file_current_sleep_command; | ||
91 | } dbgfs_data_files; | 93 | } dbgfs_data_files; |
92 | struct dir_rf_files { | 94 | struct dir_rf_files { |
93 | struct dentry *file_disable_sensitivity; | 95 | struct dentry *file_disable_sensitivity; |
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 | ||
779 | static 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 | |||
814 | static 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 | |||
832 | static 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 | |||
779 | DEBUGFS_READ_WRITE_FILE_OPS(sram); | 856 | DEBUGFS_READ_WRITE_FILE_OPS(sram); |
780 | DEBUGFS_WRITE_FILE_OPS(log_event); | 857 | DEBUGFS_WRITE_FILE_OPS(log_event); |
781 | DEBUGFS_READ_FILE_OPS(nvm); | 858 | DEBUGFS_READ_FILE_OPS(nvm); |
@@ -789,6 +866,8 @@ DEBUGFS_READ_FILE_OPS(led); | |||
789 | #endif | 866 | #endif |
790 | DEBUGFS_READ_FILE_OPS(thermal_throttling); | 867 | DEBUGFS_READ_FILE_OPS(thermal_throttling); |
791 | DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40); | 868 | DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40); |
869 | DEBUGFS_READ_WRITE_FILE_OPS(sleep_level_override); | ||
870 | DEBUGFS_READ_FILE_OPS(current_sleep_command); | ||
792 | 871 | ||
793 | static ssize_t iwl_dbgfs_traffic_log_read(struct file *file, | 872 | static 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); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 1aa2ae6d0756..b96c3c9e92a9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h | |||
@@ -1119,7 +1119,6 @@ struct iwl_priv { | |||
1119 | /* context information */ | 1119 | /* context information */ |
1120 | u16 rates_mask; | 1120 | u16 rates_mask; |
1121 | 1121 | ||
1122 | u32 power_mode; | ||
1123 | u8 bssid[ETH_ALEN]; | 1122 | u8 bssid[ETH_ALEN]; |
1124 | u16 rts_threshold; | 1123 | u16 rts_threshold; |
1125 | u8 mac_addr[ETH_ALEN]; | 1124 | u8 mac_addr[ETH_ALEN]; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 27ad59d8643e..0b16841f45f4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c | |||
@@ -42,20 +42,35 @@ | |||
42 | #include "iwl-power.h" | 42 | #include "iwl-power.h" |
43 | 43 | ||
44 | /* | 44 | /* |
45 | * Setting power level allow the card to go to sleep when not busy. | 45 | * Setting power level allows the card to go to sleep when not busy. |
46 | * | 46 | * |
47 | * The power level is set to INDEX_1 (the least deep state) by | 47 | * We calculate a sleep command based on the required latency, which |
48 | * default, and will, in the future, be the deepest state unless | 48 | * we get from mac80211. In order to handle thermal throttling, we can |
49 | * otherwise required by pm_qos network latency requirements. | 49 | * also use pre-defined power levels. |
50 | * | ||
51 | * Using INDEX_1 without pm_qos is ok because mac80211 will disable | ||
52 | * PS when even checking every beacon for the TIM bit would exceed | ||
53 | * the required latency. | ||
54 | */ | 50 | */ |
55 | 51 | ||
56 | #define IWL_POWER_RANGE_0_MAX (2) | 52 | /* |
57 | #define IWL_POWER_RANGE_1_MAX (10) | 53 | * For now, keep using power level 1 instead of automatically |
54 | * adjusting ... | ||
55 | */ | ||
56 | bool no_sleep_autoadjust = true; | ||
57 | module_param(no_sleep_autoadjust, bool, S_IRUGO); | ||
58 | MODULE_PARM_DESC(no_sleep_autoadjust, | ||
59 | "don't automatically adjust sleep level " | ||
60 | "according to maximum network latency"); | ||
58 | 61 | ||
62 | /* | ||
63 | * This defines the old power levels. They are still used by default | ||
64 | * (level 1) and for thermal throttle (levels 3 through 5) | ||
65 | */ | ||
66 | |||
67 | struct iwl_power_vec_entry { | ||
68 | struct iwl_powertable_cmd cmd; | ||
69 | u8 no_dtim; | ||
70 | }; | ||
71 | |||
72 | #define IWL_DTIM_RANGE_0_MAX 2 | ||
73 | #define IWL_DTIM_RANGE_1_MAX 10 | ||
59 | 74 | ||
60 | #define NOSLP cpu_to_le16(0), 0, 0 | 75 | #define NOSLP cpu_to_le16(0), 0, 0 |
61 | #define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0 | 76 | #define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0 |
@@ -67,9 +82,8 @@ | |||
67 | cpu_to_le32(X3), \ | 82 | cpu_to_le32(X3), \ |
68 | cpu_to_le32(X4)} | 83 | cpu_to_le32(X4)} |
69 | /* default power management (not Tx power) table values */ | 84 | /* default power management (not Tx power) table values */ |
70 | /* for DTIM period 0 through IWL_POWER_RANGE_0_MAX */ | 85 | /* for DTIM period 0 through IWL_DTIM_RANGE_0_MAX */ |
71 | static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = { | 86 | static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = { |
72 | {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, | ||
73 | {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, | 87 | {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, |
74 | {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, | 88 | {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, |
75 | {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 2, 2, 2, 0xFF)}, 0}, | 89 | {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 2, 2, 2, 0xFF)}, 0}, |
@@ -78,9 +92,8 @@ static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = { | |||
78 | }; | 92 | }; |
79 | 93 | ||
80 | 94 | ||
81 | /* for DTIM period IWL_POWER_RANGE_0_MAX + 1 through IWL_POWER_RANGE_1_MAX */ | 95 | /* for DTIM period IWL_DTIM_RANGE_0_MAX + 1 through IWL_DTIM_RANGE_1_MAX */ |
82 | static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = { | 96 | static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = { |
83 | {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, | ||
84 | {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, | 97 | {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, |
85 | {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 3, 4, 7)}, 0}, | 98 | {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 3, 4, 7)}, 0}, |
86 | {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 4, 6, 7, 9)}, 0}, | 99 | {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 4, 6, 7, 9)}, 0}, |
@@ -88,9 +101,8 @@ static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = { | |||
88 | {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 7, 10, 10)}, 2} | 101 | {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 7, 10, 10)}, 2} |
89 | }; | 102 | }; |
90 | 103 | ||
91 | /* for DTIM period > IWL_POWER_RANGE_1_MAX */ | 104 | /* for DTIM period > IWL_DTIM_RANGE_1_MAX */ |
92 | static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = { | 105 | static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = { |
93 | {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, | ||
94 | {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0}, | 106 | {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0}, |
95 | {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(2, 4, 6, 7, 0xFF)}, 0}, | 107 | {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(2, 4, 6, 7, 0xFF)}, 0}, |
96 | {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0}, | 108 | {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0}, |
@@ -98,6 +110,56 @@ static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = { | |||
98 | {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0} | 110 | {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0} |
99 | }; | 111 | }; |
100 | 112 | ||
113 | static void iwl_static_sleep_cmd(struct iwl_priv *priv, | ||
114 | struct iwl_powertable_cmd *cmd, | ||
115 | enum iwl_power_level lvl, int period) | ||
116 | { | ||
117 | const struct iwl_power_vec_entry *table; | ||
118 | int max_sleep, i; | ||
119 | bool skip; | ||
120 | |||
121 | table = range_2; | ||
122 | if (period < IWL_DTIM_RANGE_1_MAX) | ||
123 | table = range_1; | ||
124 | if (period < IWL_DTIM_RANGE_0_MAX) | ||
125 | table = range_0; | ||
126 | |||
127 | BUG_ON(lvl < 0 || lvl >= IWL_POWER_NUM); | ||
128 | |||
129 | *cmd = table[lvl].cmd; | ||
130 | |||
131 | if (period == 0) { | ||
132 | skip = false; | ||
133 | period = 1; | ||
134 | } else { | ||
135 | skip = !!table[lvl].no_dtim; | ||
136 | } | ||
137 | |||
138 | if (skip) { | ||
139 | __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]; | ||
140 | max_sleep = le32_to_cpu(slp_itrvl); | ||
141 | if (max_sleep == 0xFF) | ||
142 | max_sleep = period * (skip + 1); | ||
143 | else if (max_sleep > period) | ||
144 | max_sleep = (le32_to_cpu(slp_itrvl) / period) * period; | ||
145 | cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK; | ||
146 | } else { | ||
147 | max_sleep = period; | ||
148 | cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK; | ||
149 | } | ||
150 | |||
151 | for (i = 0; i < IWL_POWER_VEC_SIZE; i++) | ||
152 | if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep) | ||
153 | cmd->sleep_interval[i] = cpu_to_le32(max_sleep); | ||
154 | |||
155 | if (priv->power_data.pci_pm) | ||
156 | cmd->flags |= IWL_POWER_PCI_PM_MSK; | ||
157 | else | ||
158 | cmd->flags &= ~IWL_POWER_PCI_PM_MSK; | ||
159 | |||
160 | IWL_DEBUG_POWER(priv, "Sleep command for index %d\n", lvl + 1); | ||
161 | } | ||
162 | |||
101 | /* default Thermal Throttling transaction table | 163 | /* default Thermal Throttling transaction table |
102 | * Current state | Throttling Down | Throttling Up | 164 | * Current state | Throttling Down | Throttling Up |
103 | *============================================================================= | 165 | *============================================================================= |
@@ -138,98 +200,44 @@ static const struct iwl_tt_restriction restriction_range[IWL_TI_STATE_MAX] = { | |||
138 | {IWL_ANT_OK_NONE, IWL_ANT_OK_NONE, false } | 200 | {IWL_ANT_OK_NONE, IWL_ANT_OK_NONE, false } |
139 | }; | 201 | }; |
140 | 202 | ||
141 | /* set card power command */ | ||
142 | static int iwl_set_power(struct iwl_priv *priv, void *cmd) | ||
143 | { | ||
144 | return iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, | ||
145 | sizeof(struct iwl_powertable_cmd), cmd); | ||
146 | } | ||
147 | 203 | ||
148 | /* initialize to default */ | 204 | static void iwl_power_sleep_cam_cmd(struct iwl_priv *priv, |
149 | static void iwl_power_init_handle(struct iwl_priv *priv) | 205 | struct iwl_powertable_cmd *cmd) |
150 | { | 206 | { |
151 | struct iwl_power_mgr *pow_data; | 207 | memset(cmd, 0, sizeof(*cmd)); |
152 | int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_NUM; | ||
153 | struct iwl_powertable_cmd *cmd; | ||
154 | int i; | ||
155 | u16 lctl; | ||
156 | |||
157 | IWL_DEBUG_POWER(priv, "Initialize power \n"); | ||
158 | |||
159 | pow_data = &priv->power_data; | ||
160 | |||
161 | memset(pow_data, 0, sizeof(*pow_data)); | ||
162 | |||
163 | memcpy(&pow_data->pwr_range_0[0], &range_0[0], size); | ||
164 | memcpy(&pow_data->pwr_range_1[0], &range_1[0], size); | ||
165 | memcpy(&pow_data->pwr_range_2[0], &range_2[0], size); | ||
166 | |||
167 | lctl = iwl_pcie_link_ctl(priv); | ||
168 | 208 | ||
169 | IWL_DEBUG_POWER(priv, "adjust power command flags\n"); | 209 | if (priv->power_data.pci_pm) |
210 | cmd->flags |= IWL_POWER_PCI_PM_MSK; | ||
170 | 211 | ||
171 | for (i = 0; i < IWL_POWER_NUM; i++) { | 212 | IWL_DEBUG_POWER(priv, "Sleep command for CAM\n"); |
172 | cmd = &pow_data->pwr_range_0[i].cmd; | ||
173 | |||
174 | if (lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN) | ||
175 | cmd->flags &= ~IWL_POWER_PCI_PM_MSK; | ||
176 | else | ||
177 | cmd->flags |= IWL_POWER_PCI_PM_MSK; | ||
178 | } | ||
179 | } | 213 | } |
180 | 214 | ||
181 | /* adjust power command according to DTIM period and power level*/ | 215 | static void iwl_power_fill_sleep_cmd(struct iwl_priv *priv, |
182 | static int iwl_update_power_cmd(struct iwl_priv *priv, | 216 | struct iwl_powertable_cmd *cmd, |
183 | struct iwl_powertable_cmd *cmd, u16 mode) | 217 | int dynps_ms, int wakeup_period) |
184 | { | 218 | { |
185 | struct iwl_power_vec_entry *range; | ||
186 | struct iwl_power_mgr *pow_data; | ||
187 | int i; | 219 | int i; |
188 | u32 max_sleep = 0; | ||
189 | u8 period; | ||
190 | bool skip; | ||
191 | 220 | ||
192 | if (mode > IWL_POWER_INDEX_5) { | 221 | memset(cmd, 0, sizeof(*cmd)); |
193 | IWL_DEBUG_POWER(priv, "Error invalid power mode \n"); | ||
194 | return -EINVAL; | ||
195 | } | ||
196 | 222 | ||
197 | pow_data = &priv->power_data; | 223 | cmd->flags = IWL_POWER_DRIVER_ALLOW_SLEEP_MSK | |
224 | IWL_POWER_FAST_PD; /* no use seeing frames for others */ | ||
198 | 225 | ||
199 | if (pow_data->dtim_period <= IWL_POWER_RANGE_0_MAX) | 226 | if (priv->power_data.pci_pm) |
200 | range = &pow_data->pwr_range_0[0]; | 227 | cmd->flags |= IWL_POWER_PCI_PM_MSK; |
201 | else if (pow_data->dtim_period <= IWL_POWER_RANGE_1_MAX) | ||
202 | range = &pow_data->pwr_range_1[0]; | ||
203 | else | ||
204 | range = &pow_data->pwr_range_2[0]; | ||
205 | 228 | ||
206 | period = pow_data->dtim_period; | 229 | cmd->rx_data_timeout = cpu_to_le32(1000 * dynps_ms); |
207 | memcpy(cmd, &range[mode].cmd, sizeof(struct iwl_powertable_cmd)); | 230 | cmd->tx_data_timeout = cpu_to_le32(1000 * dynps_ms); |
208 | |||
209 | if (period == 0) { | ||
210 | period = 1; | ||
211 | skip = false; | ||
212 | } else { | ||
213 | skip = !!range[mode].no_dtim; | ||
214 | } | ||
215 | |||
216 | if (skip) { | ||
217 | __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1]; | ||
218 | max_sleep = le32_to_cpu(slp_itrvl); | ||
219 | if (max_sleep == 0xFF) | ||
220 | max_sleep = period * (skip + 1); | ||
221 | else if (max_sleep > period) | ||
222 | max_sleep = (le32_to_cpu(slp_itrvl) / period) * period; | ||
223 | cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK; | ||
224 | } else { | ||
225 | max_sleep = period; | ||
226 | cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK; | ||
227 | } | ||
228 | 231 | ||
229 | for (i = 0; i < IWL_POWER_VEC_SIZE; i++) | 232 | for (i = 0; i < IWL_POWER_VEC_SIZE; i++) |
230 | if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep) | 233 | cmd->sleep_interval[i] = cpu_to_le32(wakeup_period); |
231 | cmd->sleep_interval[i] = cpu_to_le32(max_sleep); | 234 | |
235 | IWL_DEBUG_POWER(priv, "Automatic sleep command\n"); | ||
236 | } | ||
232 | 237 | ||
238 | static int iwl_set_power(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd) | ||
239 | { | ||
240 | IWL_DEBUG_POWER(priv, "Sending power/sleep command\n"); | ||
233 | IWL_DEBUG_POWER(priv, "Flags value = 0x%08X\n", cmd->flags); | 241 | IWL_DEBUG_POWER(priv, "Flags value = 0x%08X\n", cmd->flags); |
234 | IWL_DEBUG_POWER(priv, "Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout)); | 242 | IWL_DEBUG_POWER(priv, "Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout)); |
235 | IWL_DEBUG_POWER(priv, "Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout)); | 243 | IWL_DEBUG_POWER(priv, "Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout)); |
@@ -240,50 +248,54 @@ static int iwl_update_power_cmd(struct iwl_priv *priv, | |||
240 | le32_to_cpu(cmd->sleep_interval[3]), | 248 | le32_to_cpu(cmd->sleep_interval[3]), |
241 | le32_to_cpu(cmd->sleep_interval[4])); | 249 | le32_to_cpu(cmd->sleep_interval[4])); |
242 | 250 | ||
243 | return 0; | 251 | return iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, |
252 | sizeof(struct iwl_powertable_cmd), cmd); | ||
244 | } | 253 | } |
245 | 254 | ||
246 | 255 | ||
247 | /* | ||
248 | * compute the final power mode index | ||
249 | */ | ||
250 | int iwl_power_update_mode(struct iwl_priv *priv, bool force) | 256 | int iwl_power_update_mode(struct iwl_priv *priv, bool force) |
251 | { | 257 | { |
252 | struct iwl_power_mgr *setting = &(priv->power_data); | ||
253 | int ret = 0; | 258 | int ret = 0; |
254 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; | 259 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; |
255 | u16 uninitialized_var(final_mode); | 260 | bool enabled = (priv->iw_mode == NL80211_IFTYPE_STATION) && |
261 | (priv->hw->conf.flags & IEEE80211_CONF_PS); | ||
256 | bool update_chains; | 262 | bool update_chains; |
263 | struct iwl_powertable_cmd cmd; | ||
264 | int dtimper; | ||
257 | 265 | ||
258 | /* Don't update the RX chain when chain noise calibration is running */ | 266 | /* Don't update the RX chain when chain noise calibration is running */ |
259 | update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE || | 267 | update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE || |
260 | priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE; | 268 | priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE; |
261 | 269 | ||
262 | final_mode = priv->power_data.user_power_setting; | 270 | if (priv->vif) |
263 | 271 | dtimper = priv->vif->bss_conf.dtim_period; | |
264 | if (setting->power_disabled) | 272 | else |
265 | final_mode = IWL_POWER_MODE_CAM; | 273 | dtimper = 1; |
274 | |||
275 | /* TT power setting overwrites everything */ | ||
276 | if (tt->state >= IWL_TI_1) | ||
277 | iwl_static_sleep_cmd(priv, &cmd, tt->tt_power_mode, dtimper); | ||
278 | else if (!enabled) | ||
279 | iwl_power_sleep_cam_cmd(priv, &cmd); | ||
280 | else if (priv->power_data.debug_sleep_level_override >= 0) | ||
281 | iwl_static_sleep_cmd(priv, &cmd, | ||
282 | priv->power_data.debug_sleep_level_override, | ||
283 | dtimper); | ||
284 | else if (no_sleep_autoadjust) | ||
285 | iwl_static_sleep_cmd(priv, &cmd, IWL_POWER_INDEX_1, dtimper); | ||
286 | else | ||
287 | iwl_power_fill_sleep_cmd(priv, &cmd, | ||
288 | priv->hw->conf.dynamic_ps_timeout, | ||
289 | priv->hw->conf.max_sleep_period); | ||
266 | 290 | ||
267 | if (tt->state >= IWL_TI_1) { | ||
268 | /* TT power setting overwrite user & system power setting */ | ||
269 | final_mode = tt->tt_power_mode; | ||
270 | } | ||
271 | if (iwl_is_ready_rf(priv) && | 291 | if (iwl_is_ready_rf(priv) && |
272 | ((setting->power_mode != final_mode) || force)) { | 292 | (memcmp(&priv->power_data.sleep_cmd, &cmd, sizeof(cmd)) || force)) { |
273 | struct iwl_powertable_cmd cmd; | 293 | if (cmd.flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK) |
274 | |||
275 | if (final_mode != IWL_POWER_MODE_CAM) | ||
276 | set_bit(STATUS_POWER_PMI, &priv->status); | 294 | set_bit(STATUS_POWER_PMI, &priv->status); |
277 | 295 | ||
278 | iwl_update_power_cmd(priv, &cmd, final_mode); | ||
279 | cmd.keep_alive_beacons = 0; | ||
280 | |||
281 | if (final_mode == IWL_POWER_INDEX_5) | ||
282 | cmd.flags |= IWL_POWER_FAST_PD; | ||
283 | |||
284 | ret = iwl_set_power(priv, &cmd); | 296 | ret = iwl_set_power(priv, &cmd); |
285 | if (!ret) { | 297 | if (!ret) { |
286 | if (final_mode == IWL_POWER_MODE_CAM) | 298 | if (!(cmd.flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK)) |
287 | clear_bit(STATUS_POWER_PMI, &priv->status); | 299 | clear_bit(STATUS_POWER_PMI, &priv->status); |
288 | 300 | ||
289 | if (priv->cfg->ops->lib->update_chain_flags && | 301 | if (priv->cfg->ops->lib->update_chain_flags && |
@@ -294,7 +306,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) | |||
294 | "Cannot update the power, chain noise " | 306 | "Cannot update the power, chain noise " |
295 | "calibration running: %d\n", | 307 | "calibration running: %d\n", |
296 | priv->chain_noise_data.state); | 308 | priv->chain_noise_data.state); |
297 | setting->power_mode = final_mode; | 309 | memcpy(&priv->power_data.sleep_cmd, &cmd, sizeof(cmd)); |
298 | } else | 310 | } else |
299 | IWL_ERR(priv, "set power fail, ret = %d", ret); | 311 | IWL_ERR(priv, "set power fail, ret = %d", ret); |
300 | } | 312 | } |
@@ -303,18 +315,6 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) | |||
303 | } | 315 | } |
304 | EXPORT_SYMBOL(iwl_power_update_mode); | 316 | EXPORT_SYMBOL(iwl_power_update_mode); |
305 | 317 | ||
306 | /* set user_power_setting */ | ||
307 | int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode) | ||
308 | { | ||
309 | if (mode >= IWL_POWER_NUM) | ||
310 | return -EINVAL; | ||
311 | |||
312 | priv->power_data.user_power_setting = mode; | ||
313 | |||
314 | return iwl_power_update_mode(priv, 0); | ||
315 | } | ||
316 | EXPORT_SYMBOL(iwl_power_set_user_mode); | ||
317 | |||
318 | bool iwl_ht_enabled(struct iwl_priv *priv) | 318 | bool iwl_ht_enabled(struct iwl_priv *priv) |
319 | { | 319 | { |
320 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; | 320 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; |
@@ -349,7 +349,6 @@ enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv) | |||
349 | restriction = tt->restriction + tt->state; | 349 | restriction = tt->restriction + tt->state; |
350 | return restriction->rx_stream; | 350 | return restriction->rx_stream; |
351 | } | 351 | } |
352 | EXPORT_SYMBOL(iwl_rx_ant_restriction); | ||
353 | 352 | ||
354 | #define CT_KILL_EXIT_DURATION (5) /* 5 seconds duration */ | 353 | #define CT_KILL_EXIT_DURATION (5) /* 5 seconds duration */ |
355 | 354 | ||
@@ -429,7 +428,6 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) | |||
429 | { | 428 | { |
430 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; | 429 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; |
431 | enum iwl_tt_state old_state; | 430 | enum iwl_tt_state old_state; |
432 | struct iwl_power_mgr *setting = &priv->power_data; | ||
433 | 431 | ||
434 | #ifdef CONFIG_IWLWIFI_DEBUG | 432 | #ifdef CONFIG_IWLWIFI_DEBUG |
435 | if ((tt->tt_previous_temp) && | 433 | if ((tt->tt_previous_temp) && |
@@ -456,24 +454,13 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) | |||
456 | tt->tt_previous_temp = temp; | 454 | tt->tt_previous_temp = temp; |
457 | #endif | 455 | #endif |
458 | if (tt->state != old_state) { | 456 | if (tt->state != old_state) { |
459 | if (old_state == IWL_TI_0) { | ||
460 | tt->sys_power_mode = setting->power_mode; | ||
461 | IWL_DEBUG_POWER(priv, "current power mode: %u\n", | ||
462 | setting->power_mode); | ||
463 | } | ||
464 | switch (tt->state) { | 457 | switch (tt->state) { |
465 | case IWL_TI_0: | 458 | case IWL_TI_0: |
466 | /* when system ready to go back to IWL_TI_0 state | 459 | /* |
467 | * using system power mode instead of TT power mode | 460 | * When the system is ready to go back to IWL_TI_0 |
468 | * revert back to the orginal power mode which was saved | 461 | * we only have to call iwl_power_update_mode() to |
469 | * before enter Thermal Throttling state | 462 | * do so. |
470 | * update priv->power_data.user_power_setting to the | ||
471 | * required power mode to make sure | ||
472 | * iwl_power_update_mode() will update power correctly. | ||
473 | */ | 463 | */ |
474 | priv->power_data.user_power_setting = | ||
475 | tt->sys_power_mode; | ||
476 | tt->tt_power_mode = tt->sys_power_mode; | ||
477 | break; | 464 | break; |
478 | case IWL_TI_1: | 465 | case IWL_TI_1: |
479 | tt->tt_power_mode = IWL_POWER_INDEX_3; | 466 | tt->tt_power_mode = IWL_POWER_INDEX_3; |
@@ -576,13 +563,8 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) | |||
576 | } | 563 | } |
577 | if (changed) { | 564 | if (changed) { |
578 | struct iwl_rxon_cmd *rxon = &priv->staging_rxon; | 565 | struct iwl_rxon_cmd *rxon = &priv->staging_rxon; |
579 | struct iwl_power_mgr *setting = &priv->power_data; | ||
580 | 566 | ||
581 | if (tt->state >= IWL_TI_1) { | 567 | if (tt->state >= IWL_TI_1) { |
582 | /* if switching from IWL_TI_0 to other TT state | ||
583 | * save previous power setting in tt->sys_power_mode */ | ||
584 | if (old_state == IWL_TI_0) | ||
585 | tt->sys_power_mode = setting->power_mode; | ||
586 | /* force PI = IWL_POWER_INDEX_5 in the case of TI > 0 */ | 568 | /* force PI = IWL_POWER_INDEX_5 in the case of TI > 0 */ |
587 | tt->tt_power_mode = IWL_POWER_INDEX_5; | 569 | tt->tt_power_mode = IWL_POWER_INDEX_5; |
588 | if (!iwl_ht_enabled(priv)) | 570 | if (!iwl_ht_enabled(priv)) |
@@ -599,17 +581,11 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp) | |||
599 | } | 581 | } |
600 | 582 | ||
601 | } else { | 583 | } else { |
602 | /* restore system power setting */ | 584 | /* |
603 | /* the previous power mode was saved in | 585 | * restore system power setting -- it will be |
604 | * tt->sys_power_mode when system move into | 586 | * recalculated automatically. |
605 | * Thermal Throttling state | ||
606 | * set power_data.user_power_setting to the previous | ||
607 | * system power mode to make sure power will get | ||
608 | * updated correctly | ||
609 | */ | 587 | */ |
610 | priv->power_data.user_power_setting = | 588 | |
611 | tt->sys_power_mode; | ||
612 | tt->tt_power_mode = tt->sys_power_mode; | ||
613 | /* check HT capability and set | 589 | /* check HT capability and set |
614 | * according to the system HT capability | 590 | * according to the system HT capability |
615 | * in case get disabled before */ | 591 | * in case get disabled before */ |
@@ -761,7 +737,6 @@ EXPORT_SYMBOL(iwl_tt_handler); | |||
761 | void iwl_tt_initialize(struct iwl_priv *priv) | 737 | void iwl_tt_initialize(struct iwl_priv *priv) |
762 | { | 738 | { |
763 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; | 739 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; |
764 | struct iwl_power_mgr *setting = &priv->power_data; | ||
765 | int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1); | 740 | int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1); |
766 | struct iwl_tt_trans *transaction; | 741 | struct iwl_tt_trans *transaction; |
767 | 742 | ||
@@ -770,8 +745,6 @@ void iwl_tt_initialize(struct iwl_priv *priv) | |||
770 | memset(tt, 0, sizeof(struct iwl_tt_mgmt)); | 745 | memset(tt, 0, sizeof(struct iwl_tt_mgmt)); |
771 | 746 | ||
772 | tt->state = IWL_TI_0; | 747 | tt->state = IWL_TI_0; |
773 | tt->sys_power_mode = setting->power_mode; | ||
774 | tt->tt_power_mode = tt->sys_power_mode; | ||
775 | init_timer(&priv->thermal_throttle.ct_kill_exit_tm); | 748 | init_timer(&priv->thermal_throttle.ct_kill_exit_tm); |
776 | priv->thermal_throttle.ct_kill_exit_tm.data = (unsigned long)priv; | 749 | priv->thermal_throttle.ct_kill_exit_tm.data = (unsigned long)priv; |
777 | priv->thermal_throttle.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill; | 750 | priv->thermal_throttle.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill; |
@@ -849,9 +822,13 @@ EXPORT_SYMBOL(iwl_tt_exit); | |||
849 | /* initialize to default */ | 822 | /* initialize to default */ |
850 | void iwl_power_initialize(struct iwl_priv *priv) | 823 | void iwl_power_initialize(struct iwl_priv *priv) |
851 | { | 824 | { |
852 | iwl_power_init_handle(priv); | 825 | u16 lctl = iwl_pcie_link_ctl(priv); |
853 | priv->power_data.user_power_setting = IWL_POWER_INDEX_1; | 826 | |
854 | /* default to disabled until mac80211 says otherwise */ | 827 | priv->power_data.pci_pm = !(lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN); |
855 | priv->power_data.power_disabled = 1; | 828 | |
829 | priv->power_data.debug_sleep_level_override = -1; | ||
830 | |||
831 | memset(&priv->power_data.sleep_cmd, 0, | ||
832 | sizeof(priv->power_data.sleep_cmd)); | ||
856 | } | 833 | } |
857 | EXPORT_SYMBOL(iwl_power_initialize); | 834 | EXPORT_SYMBOL(iwl_power_initialize); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index 15e3eabd2e84..df6f6a49712b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h | |||
@@ -28,11 +28,8 @@ | |||
28 | #ifndef __iwl_power_setting_h__ | 28 | #ifndef __iwl_power_setting_h__ |
29 | #define __iwl_power_setting_h__ | 29 | #define __iwl_power_setting_h__ |
30 | 30 | ||
31 | #include <net/mac80211.h> | ||
32 | #include "iwl-commands.h" | 31 | #include "iwl-commands.h" |
33 | 32 | ||
34 | struct iwl_priv; | ||
35 | |||
36 | #define IWL_ABSOLUTE_ZERO 0 | 33 | #define IWL_ABSOLUTE_ZERO 0 |
37 | #define IWL_ABSOLUTE_MAX 0xFFFFFFFF | 34 | #define IWL_ABSOLUTE_MAX 0xFFFFFFFF |
38 | #define IWL_TT_INCREASE_MARGIN 5 | 35 | #define IWL_TT_INCREASE_MARGIN 5 |
@@ -93,8 +90,6 @@ struct iwl_tt_trans { | |||
93 | * when thermal throttling state != IWL_TI_0 | 90 | * when thermal throttling state != IWL_TI_0 |
94 | * the tt_power_mode should set to different | 91 | * the tt_power_mode should set to different |
95 | * power mode based on the current tt state | 92 | * power mode based on the current tt state |
96 | * @sys_power_mode: previous system power mode | ||
97 | * before transition into TT state | ||
98 | * @tt_previous_temperature: last measured temperature | 93 | * @tt_previous_temperature: last measured temperature |
99 | * @iwl_tt_restriction: ptr to restriction tbl, used by advance | 94 | * @iwl_tt_restriction: ptr to restriction tbl, used by advance |
100 | * thermal throttling to determine how many tx/rx streams | 95 | * thermal throttling to determine how many tx/rx streams |
@@ -108,7 +103,6 @@ struct iwl_tt_mgmt { | |||
108 | enum iwl_tt_state state; | 103 | enum iwl_tt_state state; |
109 | bool advanced_tt; | 104 | bool advanced_tt; |
110 | u8 tt_power_mode; | 105 | u8 tt_power_mode; |
111 | u8 sys_power_mode; | ||
112 | bool ct_kill_toggle; | 106 | bool ct_kill_toggle; |
113 | #ifdef CONFIG_IWLWIFI_DEBUG | 107 | #ifdef CONFIG_IWLWIFI_DEBUG |
114 | s32 tt_previous_temp; | 108 | s32 tt_previous_temp; |
@@ -118,8 +112,7 @@ struct iwl_tt_mgmt { | |||
118 | struct timer_list ct_kill_exit_tm; | 112 | struct timer_list ct_kill_exit_tm; |
119 | }; | 113 | }; |
120 | 114 | ||
121 | enum { | 115 | enum iwl_power_level { |
122 | IWL_POWER_MODE_CAM, /* Continuously Aware Mode, always on */ | ||
123 | IWL_POWER_INDEX_1, | 116 | IWL_POWER_INDEX_1, |
124 | IWL_POWER_INDEX_2, | 117 | IWL_POWER_INDEX_2, |
125 | IWL_POWER_INDEX_3, | 118 | IWL_POWER_INDEX_3, |
@@ -128,26 +121,13 @@ enum { | |||
128 | IWL_POWER_NUM | 121 | IWL_POWER_NUM |
129 | }; | 122 | }; |
130 | 123 | ||
131 | /* Power management (not Tx power) structures */ | ||
132 | |||
133 | struct iwl_power_vec_entry { | ||
134 | struct iwl_powertable_cmd cmd; | ||
135 | u8 no_dtim; | ||
136 | }; | ||
137 | |||
138 | struct iwl_power_mgr { | 124 | struct iwl_power_mgr { |
139 | struct iwl_power_vec_entry pwr_range_0[IWL_POWER_NUM]; | 125 | struct iwl_powertable_cmd sleep_cmd; |
140 | struct iwl_power_vec_entry pwr_range_1[IWL_POWER_NUM]; | 126 | int debug_sleep_level_override; |
141 | struct iwl_power_vec_entry pwr_range_2[IWL_POWER_NUM]; | 127 | bool pci_pm; |
142 | u32 dtim_period; | ||
143 | /* final power level that used to calculate final power command */ | ||
144 | u8 power_mode; | ||
145 | u8 user_power_setting; /* set by user through sysfs */ | ||
146 | u8 power_disabled; /* set by mac80211's CONF_PS */ | ||
147 | }; | 128 | }; |
148 | 129 | ||
149 | int iwl_power_update_mode(struct iwl_priv *priv, bool force); | 130 | int iwl_power_update_mode(struct iwl_priv *priv, bool force); |
150 | int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode); | ||
151 | bool iwl_ht_enabled(struct iwl_priv *priv); | 131 | bool iwl_ht_enabled(struct iwl_priv *priv); |
152 | enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv); | 132 | enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv); |
153 | enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv); | 133 | enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv); |
@@ -158,4 +138,6 @@ void iwl_tt_initialize(struct iwl_priv *priv); | |||
158 | void iwl_tt_exit(struct iwl_priv *priv); | 138 | void iwl_tt_exit(struct iwl_priv *priv); |
159 | void iwl_power_initialize(struct iwl_priv *priv); | 139 | void iwl_power_initialize(struct iwl_priv *priv); |
160 | 140 | ||
141 | extern bool no_sleep_autoadjust; | ||
142 | |||
161 | #endif /* __iwl_power_setting_h__ */ | 143 | #endif /* __iwl_power_setting_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index e5fa672e8390..e617411d0c5e 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c | |||
@@ -3554,65 +3554,6 @@ static DEVICE_ATTR(retry_rate, S_IWUSR | S_IRUSR, show_retry_rate, | |||
3554 | store_retry_rate); | 3554 | store_retry_rate); |
3555 | 3555 | ||
3556 | 3556 | ||
3557 | static ssize_t store_power_level(struct device *d, | ||
3558 | struct device_attribute *attr, | ||
3559 | const char *buf, size_t count) | ||
3560 | { | ||
3561 | struct iwl_priv *priv = dev_get_drvdata(d); | ||
3562 | int ret; | ||
3563 | unsigned long mode; | ||
3564 | |||
3565 | |||
3566 | mutex_lock(&priv->mutex); | ||
3567 | |||
3568 | ret = strict_strtoul(buf, 10, &mode); | ||
3569 | if (ret) | ||
3570 | goto out; | ||
3571 | |||
3572 | ret = iwl_power_set_user_mode(priv, mode); | ||
3573 | if (ret) { | ||
3574 | IWL_DEBUG_MAC80211(priv, "failed setting power mode.\n"); | ||
3575 | goto out; | ||
3576 | } | ||
3577 | ret = count; | ||
3578 | |||
3579 | out: | ||
3580 | mutex_unlock(&priv->mutex); | ||
3581 | return ret; | ||
3582 | } | ||
3583 | |||
3584 | static ssize_t show_power_level(struct device *d, | ||
3585 | struct device_attribute *attr, char *buf) | ||
3586 | { | ||
3587 | struct iwl_priv *priv = dev_get_drvdata(d); | ||
3588 | int level = priv->power_data.power_mode; | ||
3589 | char *p = buf; | ||
3590 | |||
3591 | p += sprintf(p, "%d\n", level); | ||
3592 | return p - buf + 1; | ||
3593 | } | ||
3594 | |||
3595 | static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, | ||
3596 | show_power_level, store_power_level); | ||
3597 | |||
3598 | #define MAX_WX_STRING 80 | ||
3599 | |||
3600 | /* Values are in microsecond */ | ||
3601 | static const s32 timeout_duration[] = { | ||
3602 | 350000, | ||
3603 | 250000, | ||
3604 | 75000, | ||
3605 | 37000, | ||
3606 | 25000, | ||
3607 | }; | ||
3608 | static const s32 period_duration[] = { | ||
3609 | 400000, | ||
3610 | 700000, | ||
3611 | 1000000, | ||
3612 | 1000000, | ||
3613 | 1000000 | ||
3614 | }; | ||
3615 | |||
3616 | static ssize_t show_channels(struct device *d, | 3557 | static ssize_t show_channels(struct device *d, |
3617 | struct device_attribute *attr, char *buf) | 3558 | struct device_attribute *attr, char *buf) |
3618 | { | 3559 | { |
@@ -3789,7 +3730,6 @@ static struct attribute *iwl3945_sysfs_entries[] = { | |||
3789 | #ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT | 3730 | #ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT |
3790 | &dev_attr_measurement.attr, | 3731 | &dev_attr_measurement.attr, |
3791 | #endif | 3732 | #endif |
3792 | &dev_attr_power_level.attr, | ||
3793 | &dev_attr_retry_rate.attr, | 3733 | &dev_attr_retry_rate.attr, |
3794 | &dev_attr_statistics.attr, | 3734 | &dev_attr_statistics.attr, |
3795 | &dev_attr_status.attr, | 3735 | &dev_attr_status.attr, |
@@ -3854,8 +3794,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv) | |||
3854 | priv->qos_data.qos_cap.val = 0; | 3794 | priv->qos_data.qos_cap.val = 0; |
3855 | 3795 | ||
3856 | priv->rates_mask = IWL_RATES_MASK; | 3796 | priv->rates_mask = IWL_RATES_MASK; |
3857 | /* If power management is turned on, default to CAM mode */ | ||
3858 | priv->power_mode = IWL_POWER_MODE_CAM; | ||
3859 | priv->tx_power_user_lmt = IWL_DEFAULT_TX_POWER; | 3797 | priv->tx_power_user_lmt = IWL_DEFAULT_TX_POWER; |
3860 | 3798 | ||
3861 | if (eeprom->version < EEPROM_3945_EEPROM_VERSION) { | 3799 | if (eeprom->version < EEPROM_3945_EEPROM_VERSION) { |
@@ -3902,7 +3840,9 @@ static int iwl3945_setup_mac(struct iwl_priv *priv) | |||
3902 | /* Tell mac80211 our characteristics */ | 3840 | /* Tell mac80211 our characteristics */ |
3903 | hw->flags = IEEE80211_HW_SIGNAL_DBM | | 3841 | hw->flags = IEEE80211_HW_SIGNAL_DBM | |
3904 | IEEE80211_HW_NOISE_DBM | | 3842 | IEEE80211_HW_NOISE_DBM | |
3905 | IEEE80211_HW_SPECTRUM_MGMT; | 3843 | IEEE80211_HW_SPECTRUM_MGMT | |
3844 | IEEE80211_HW_SUPPORTS_PS | | ||
3845 | IEEE80211_HW_SUPPORTS_DYNAMIC_PS; | ||
3906 | 3846 | ||
3907 | hw->wiphy->interface_modes = | 3847 | hw->wiphy->interface_modes = |
3908 | BIT(NL80211_IFTYPE_STATION) | | 3848 | BIT(NL80211_IFTYPE_STATION) | |