diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/power.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/power.c | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c new file mode 100644 index 000000000000..63628739cf4a --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/power.c | |||
@@ -0,0 +1,207 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called LICENSE.GPL. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | |||
64 | #include <linux/kernel.h> | ||
65 | #include <linux/module.h> | ||
66 | #include <linux/slab.h> | ||
67 | #include <linux/init.h> | ||
68 | |||
69 | #include <net/mac80211.h> | ||
70 | |||
71 | #include "iwl-debug.h" | ||
72 | #include "mvm.h" | ||
73 | #include "iwl-modparams.h" | ||
74 | #include "fw-api-power.h" | ||
75 | |||
76 | #define POWER_KEEP_ALIVE_PERIOD_SEC 25 | ||
77 | |||
78 | static void iwl_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
79 | struct iwl_powertable_cmd *cmd) | ||
80 | { | ||
81 | struct ieee80211_hw *hw = mvm->hw; | ||
82 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
83 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
84 | struct ieee80211_channel *chan; | ||
85 | int dtimper, dtimper_msec; | ||
86 | int keep_alive; | ||
87 | bool radar_detect = false; | ||
88 | |||
89 | cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, | ||
90 | mvmvif->color)); | ||
91 | cmd->action = cpu_to_le32(FW_CTXT_ACTION_MODIFY); | ||
92 | |||
93 | if ((!vif->bss_conf.ps) || | ||
94 | (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM)) | ||
95 | return; | ||
96 | |||
97 | cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); | ||
98 | |||
99 | dtimper = hw->conf.ps_dtim_period ?: 1; | ||
100 | |||
101 | /* Check if radar detection is required on current channel */ | ||
102 | rcu_read_lock(); | ||
103 | chanctx_conf = rcu_dereference(vif->chanctx_conf); | ||
104 | WARN_ON(!chanctx_conf); | ||
105 | if (chanctx_conf) { | ||
106 | chan = chanctx_conf->def.chan; | ||
107 | radar_detect = chan->flags & IEEE80211_CHAN_RADAR; | ||
108 | } | ||
109 | rcu_read_unlock(); | ||
110 | |||
111 | /* Check skip over DTIM conditions */ | ||
112 | if (!radar_detect && (dtimper <= 10) && | ||
113 | (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP)) { | ||
114 | cmd->flags |= cpu_to_le16(POWER_FLAGS_SLEEP_OVER_DTIM_MSK); | ||
115 | cmd->num_skip_dtim = 2; | ||
116 | } | ||
117 | |||
118 | /* Check that keep alive period is at least 3 * DTIM */ | ||
119 | dtimper_msec = dtimper * vif->bss_conf.beacon_int; | ||
120 | keep_alive = max_t(int, 3 * dtimper_msec, | ||
121 | MSEC_PER_SEC * POWER_KEEP_ALIVE_PERIOD_SEC); | ||
122 | keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC); | ||
123 | |||
124 | cmd->keep_alive_seconds = cpu_to_le16(keep_alive); | ||
125 | |||
126 | if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP) { | ||
127 | /* TODO: Also for D3 (device sleep / WoWLAN) */ | ||
128 | cmd->rx_data_timeout = cpu_to_le32(10); | ||
129 | cmd->tx_data_timeout = cpu_to_le32(10); | ||
130 | } else { | ||
131 | cmd->rx_data_timeout = cpu_to_le32(50); | ||
132 | cmd->tx_data_timeout = cpu_to_le32(50); | ||
133 | } | ||
134 | } | ||
135 | |||
136 | int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | ||
137 | { | ||
138 | struct iwl_powertable_cmd cmd = {}; | ||
139 | |||
140 | if (!iwlwifi_mod_params.power_save) { | ||
141 | IWL_DEBUG_POWER(mvm, "Power management is not allowed\n"); | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) | ||
146 | return 0; | ||
147 | |||
148 | iwl_power_build_cmd(mvm, vif, &cmd); | ||
149 | |||
150 | IWL_DEBUG_POWER(mvm, | ||
151 | "Sending power table command on mac id 0x%X for power level %d, flags = 0x%X\n", | ||
152 | cmd.id_and_color, iwlmvm_mod_params.power_scheme, | ||
153 | le16_to_cpu(cmd.flags)); | ||
154 | |||
155 | if (cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) { | ||
156 | IWL_DEBUG_POWER(mvm, "Keep alive = %u sec\n", | ||
157 | le16_to_cpu(cmd.keep_alive_seconds)); | ||
158 | IWL_DEBUG_POWER(mvm, "Rx timeout = %u usec\n", | ||
159 | le32_to_cpu(cmd.rx_data_timeout)); | ||
160 | IWL_DEBUG_POWER(mvm, "Tx timeout = %u usec\n", | ||
161 | le32_to_cpu(cmd.tx_data_timeout)); | ||
162 | IWL_DEBUG_POWER(mvm, "Rx timeout (uAPSD) = %u usec\n", | ||
163 | le32_to_cpu(cmd.rx_data_timeout_uapsd)); | ||
164 | IWL_DEBUG_POWER(mvm, "Tx timeout = %u usec\n", | ||
165 | le32_to_cpu(cmd.tx_data_timeout_uapsd)); | ||
166 | IWL_DEBUG_POWER(mvm, "LP RX RSSI threshold = %u\n", | ||
167 | cmd.lprx_rssi_threshold); | ||
168 | IWL_DEBUG_POWER(mvm, "DTIMs to skip = %u\n", cmd.num_skip_dtim); | ||
169 | } | ||
170 | |||
171 | return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC, | ||
172 | sizeof(cmd), &cmd); | ||
173 | } | ||
174 | |||
175 | int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | ||
176 | { | ||
177 | struct iwl_powertable_cmd cmd = {}; | ||
178 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
179 | |||
180 | if (!iwlwifi_mod_params.power_save) { | ||
181 | IWL_DEBUG_POWER(mvm, "Power management is not allowed\n"); | ||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) | ||
186 | return 0; | ||
187 | |||
188 | cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, | ||
189 | mvmvif->color)); | ||
190 | cmd.action = cpu_to_le32(FW_CTXT_ACTION_MODIFY); | ||
191 | |||
192 | IWL_DEBUG_POWER(mvm, | ||
193 | "Sending power table command on mac id 0x%X for power level %d, flags = 0x%X\n", | ||
194 | cmd.id_and_color, iwlmvm_mod_params.power_scheme, | ||
195 | le16_to_cpu(cmd.flags)); | ||
196 | |||
197 | return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC, | ||
198 | sizeof(cmd), &cmd); | ||
199 | } | ||
200 | |||
201 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
202 | void iwl_power_get_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
203 | struct iwl_powertable_cmd *cmd) | ||
204 | { | ||
205 | iwl_power_build_cmd(mvm, vif, cmd); | ||
206 | } | ||
207 | #endif /* CONFIG_IWLWIFI_DEBUGFS */ | ||