Commit | Line | Data |
---|---|---|
8ca151b5 JB |
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 | |
410dc5aa | 25 | * in the file called COPYING. |
8ca151b5 JB |
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 | ||
5360cfb2 | 197 | return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_ASYNC, |
8ca151b5 JB |
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 */ |