1 /*
2 * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for
6 * any purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /**
21 * DOC: target_if_psoc_wake_lock.c
22 *
23 * This file provide definition for APIs related to wake lock
24 */
25
26 #include "qdf_lock.h"
27 #include <target_if_psoc_wake_lock.h>
28 #include <wlan_lmac_if_def.h>
29 #include <host_diag_core_event.h>
30 #include <wlan_objmgr_psoc_obj.h>
31 #include <target_if.h>
32 #include <target_if_vdev_mgr_rx_ops.h>
33 #include <wlan_reg_services_api.h>
34 #include "init_deinit_lmac.h"
35
target_if_wake_lock_init(struct wlan_objmgr_psoc * psoc)36 void target_if_wake_lock_init(struct wlan_objmgr_psoc *psoc)
37 {
38 struct psoc_mlme_wakelock *psoc_wakelock;
39 struct wlan_lmac_if_mlme_rx_ops *rx_ops;
40
41 rx_ops = target_if_vdev_mgr_get_rx_ops(psoc);
42 if (!rx_ops || !rx_ops->psoc_get_wakelock_info) {
43 mlme_err("psoc_id:%d No Rx Ops",
44 wlan_psoc_get_id(psoc));
45 return;
46 }
47
48 psoc_wakelock = rx_ops->psoc_get_wakelock_info(psoc);
49
50 qdf_wake_lock_create(&psoc_wakelock->start_wakelock, "vdev_start");
51 qdf_wake_lock_create(&psoc_wakelock->stop_wakelock, "vdev_stop");
52 qdf_wake_lock_create(&psoc_wakelock->delete_wakelock, "vdev_delete");
53
54 qdf_runtime_lock_init(&psoc_wakelock->wmi_cmd_rsp_runtime_lock);
55 qdf_runtime_lock_init(&psoc_wakelock->prevent_runtime_lock);
56 qdf_runtime_lock_init(&psoc_wakelock->roam_sync_runtime_lock);
57
58 psoc_wakelock->is_link_up = false;
59 }
60
target_if_wake_lock_deinit(struct wlan_objmgr_psoc * psoc)61 void target_if_wake_lock_deinit(struct wlan_objmgr_psoc *psoc)
62 {
63 struct psoc_mlme_wakelock *psoc_wakelock;
64 struct wlan_lmac_if_mlme_rx_ops *rx_ops;
65
66 rx_ops = target_if_vdev_mgr_get_rx_ops(psoc);
67 if (!rx_ops || !rx_ops->psoc_get_wakelock_info) {
68 mlme_err("psoc_id:%d No Rx Ops",
69 wlan_psoc_get_id(psoc));
70 return;
71 }
72
73 psoc_wakelock = rx_ops->psoc_get_wakelock_info(psoc);
74
75 qdf_wake_lock_destroy(&psoc_wakelock->start_wakelock);
76 qdf_wake_lock_destroy(&psoc_wakelock->stop_wakelock);
77 qdf_wake_lock_destroy(&psoc_wakelock->delete_wakelock);
78
79 qdf_runtime_lock_deinit(&psoc_wakelock->wmi_cmd_rsp_runtime_lock);
80 qdf_runtime_lock_deinit(&psoc_wakelock->prevent_runtime_lock);
81 qdf_runtime_lock_deinit(&psoc_wakelock->roam_sync_runtime_lock);
82 }
83
target_if_wake_lock_timeout_acquire(struct wlan_objmgr_psoc * psoc,enum wakelock_mode mode)84 QDF_STATUS target_if_wake_lock_timeout_acquire(
85 struct wlan_objmgr_psoc *psoc,
86 enum wakelock_mode mode)
87 {
88 struct psoc_mlme_wakelock *psoc_wakelock;
89 struct wlan_lmac_if_mlme_rx_ops *rx_ops;
90
91 rx_ops = target_if_vdev_mgr_get_rx_ops(psoc);
92 if (!rx_ops || !rx_ops->psoc_get_wakelock_info) {
93 mlme_err("psoc_id:%d No Rx Ops",
94 wlan_psoc_get_id(psoc));
95 return QDF_STATUS_E_INVAL;
96 }
97
98 psoc_wakelock = rx_ops->psoc_get_wakelock_info(psoc);
99 switch (mode) {
100 case START_WAKELOCK:
101 qdf_wake_lock_timeout_acquire(&psoc_wakelock->start_wakelock,
102 START_RESPONSE_TIMER);
103 break;
104 case STOP_WAKELOCK:
105 qdf_wake_lock_timeout_acquire(&psoc_wakelock->stop_wakelock,
106 STOP_RESPONSE_TIMER);
107 break;
108 case DELETE_WAKELOCK:
109 qdf_wake_lock_timeout_acquire(&psoc_wakelock->delete_wakelock,
110 DELETE_RESPONSE_TIMER);
111 break;
112 default:
113 target_if_err("operation mode is invalid");
114 return QDF_STATUS_E_FAILURE;
115 }
116
117 qdf_runtime_pm_prevent_suspend(
118 &psoc_wakelock->wmi_cmd_rsp_runtime_lock);
119
120 return QDF_STATUS_SUCCESS;
121 }
122
target_if_wake_lock_timeout_release(struct wlan_objmgr_psoc * psoc,enum wakelock_mode mode)123 QDF_STATUS target_if_wake_lock_timeout_release(
124 struct wlan_objmgr_psoc *psoc,
125 enum wakelock_mode mode)
126 {
127 struct psoc_mlme_wakelock *psoc_wakelock;
128 struct wlan_lmac_if_mlme_rx_ops *rx_ops;
129
130 rx_ops = target_if_vdev_mgr_get_rx_ops(psoc);
131 if (!rx_ops || !rx_ops->psoc_get_wakelock_info) {
132 mlme_err("psoc_id:%d No Rx Ops", wlan_psoc_get_id(psoc));
133 return QDF_STATUS_E_INVAL;
134 }
135
136 psoc_wakelock = rx_ops->psoc_get_wakelock_info(psoc);
137 switch (mode) {
138 case START_WAKELOCK:
139 qdf_wake_lock_release(&psoc_wakelock->start_wakelock,
140 WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP);
141 break;
142 case STOP_WAKELOCK:
143 qdf_wake_lock_release(&psoc_wakelock->stop_wakelock,
144 WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP);
145 break;
146 case DELETE_WAKELOCK:
147 qdf_wake_lock_release(&psoc_wakelock->delete_wakelock,
148 WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP);
149 break;
150 default:
151 target_if_err("operation mode is invalid");
152 return QDF_STATUS_E_FAILURE;
153 }
154
155 qdf_runtime_pm_allow_suspend(&psoc_wakelock->wmi_cmd_rsp_runtime_lock);
156
157 return QDF_STATUS_SUCCESS;
158 }
159
160 static void
target_if_vote_for_link_down(struct wlan_objmgr_psoc * psoc,struct psoc_mlme_wakelock * psoc_wakelock)161 target_if_vote_for_link_down(struct wlan_objmgr_psoc *psoc,
162 struct psoc_mlme_wakelock *psoc_wakelock)
163 {
164 void *htc_handle;
165
166 htc_handle = lmac_get_htc_hdl(psoc);
167 if (!htc_handle) {
168 mlme_err("HTC handle is NULL");
169 return;
170 }
171
172 if (psoc_wakelock->is_link_up) {
173 htc_vote_link_down(htc_handle, HTC_LINK_VOTE_SAP_DFS_USER_ID);
174 qdf_runtime_pm_allow_suspend(&psoc_wakelock->prevent_runtime_lock);
175 psoc_wakelock->is_link_up = false;
176 }
177 }
178
179 static void
target_if_vote_for_link_up(struct wlan_objmgr_psoc * psoc,struct psoc_mlme_wakelock * psoc_wakelock)180 target_if_vote_for_link_up(struct wlan_objmgr_psoc *psoc,
181 struct psoc_mlme_wakelock *psoc_wakelock)
182 {
183 void *htc_handle;
184
185 htc_handle = lmac_get_htc_hdl(psoc);
186 if (!htc_handle) {
187 mlme_err("HTC handle is NULL");
188 return;
189 }
190
191 if (!psoc_wakelock->is_link_up) {
192 htc_vote_link_up(htc_handle, HTC_LINK_VOTE_SAP_DFS_USER_ID);
193 qdf_runtime_pm_prevent_suspend(&psoc_wakelock->prevent_runtime_lock);
194 psoc_wakelock->is_link_up = true;
195 }
196 }
197
target_if_vdev_start_link_handler(struct wlan_objmgr_vdev * vdev,bool is_restart)198 void target_if_vdev_start_link_handler(struct wlan_objmgr_vdev *vdev,
199 bool is_restart)
200 {
201 struct wlan_objmgr_psoc *psoc;
202 struct wlan_objmgr_pdev *pdev;
203 struct psoc_mlme_wakelock *psoc_wakelock;
204 struct wlan_lmac_if_mlme_rx_ops *rx_ops;
205 struct wlan_channel *curr_channel, *prev_channel;
206 uint32_t ch_freq, prev_ch_freq;
207 enum phy_ch_width ch_width, prev_ch_width;
208 uint32_t is_dfs, prev_ch_is_dfs;
209 enum channel_state ch_state, prev_ch_state;
210 struct ch_params ch_params = {0};
211
212 psoc = wlan_vdev_get_psoc(vdev);
213 pdev = wlan_vdev_get_pdev(vdev);
214
215 if (!pdev) {
216 mlme_err("pdev is NULL");
217 return;
218 }
219
220 curr_channel = wlan_vdev_mlme_get_des_chan(vdev);
221 ch_freq = curr_channel->ch_freq;
222 ch_width = curr_channel->ch_width;
223 is_dfs = wlan_reg_is_dfs_for_freq(pdev, ch_freq);
224
225 ch_params.ch_width = ch_width;
226 ch_state =
227 wlan_reg_get_5g_bonded_channel_state_for_pwrmode(
228 pdev, ch_freq, &ch_params,
229 REG_CURRENT_PWR_MODE);
230 rx_ops = target_if_vdev_mgr_get_rx_ops(psoc);
231 if (!rx_ops || !rx_ops->psoc_get_wakelock_info) {
232 mlme_err("psoc_id:%d No Rx Ops",
233 wlan_psoc_get_id(psoc));
234 return;
235 }
236
237 psoc_wakelock = rx_ops->psoc_get_wakelock_info(psoc);
238 if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) {
239 if (is_restart) {
240 prev_channel = wlan_vdev_mlme_get_bss_chan(vdev);
241 prev_ch_freq = prev_channel->ch_freq;
242 prev_ch_width = prev_channel->ch_width;
243 prev_ch_is_dfs = wlan_reg_is_dfs_for_freq(pdev,
244 prev_ch_freq);
245 ch_params.ch_width = prev_ch_width;
246 prev_ch_state =
247 wlan_reg_get_5g_bonded_channel_state_for_pwrmode(
248 pdev,
249 prev_ch_freq, &ch_params,
250 REG_CURRENT_PWR_MODE);
251 /*
252 * In restart case, if SAP is on non DFS channel and
253 * previously it was on DFS channel then vote for link
254 * down.
255 */
256 if ((prev_ch_is_dfs ||
257 prev_ch_state == CHANNEL_STATE_DFS) &&
258 !(is_dfs || ch_state == CHANNEL_STATE_DFS))
259 target_if_vote_for_link_down(psoc,
260 psoc_wakelock);
261
262 /*
263 * If SAP is on DFS channel and previously it was on
264 * non DFS channel then vote for link up
265 */
266 if (!(prev_ch_is_dfs ||
267 prev_ch_state == CHANNEL_STATE_DFS) &&
268 (is_dfs || ch_state == CHANNEL_STATE_DFS))
269 target_if_vote_for_link_up(psoc, psoc_wakelock);
270 } else if (is_dfs || ch_state == CHANNEL_STATE_DFS)
271 target_if_vote_for_link_up(psoc, psoc_wakelock);
272 }
273 }
274
target_if_vdev_stop_link_handler(struct wlan_objmgr_vdev * vdev)275 void target_if_vdev_stop_link_handler(struct wlan_objmgr_vdev *vdev)
276 {
277 struct wlan_objmgr_psoc *psoc;
278 struct wlan_objmgr_pdev *pdev;
279 struct psoc_mlme_wakelock *psoc_wakelock;
280 struct wlan_lmac_if_mlme_rx_ops *rx_ops;
281 struct wlan_channel *curr_channel;
282 uint32_t ch_freq;
283 enum phy_ch_width ch_width;
284 uint32_t is_dfs;
285 struct ch_params ch_params = {0};
286
287 psoc = wlan_vdev_get_psoc(vdev);
288 pdev = wlan_vdev_get_pdev(vdev);
289
290 if (!pdev) {
291 mlme_err("pdev is NULL");
292 return;
293 }
294
295 curr_channel = wlan_vdev_mlme_get_bss_chan(vdev);
296 ch_freq = curr_channel->ch_freq;
297 ch_width = curr_channel->ch_width;
298 is_dfs = wlan_reg_is_dfs_for_freq(pdev, ch_freq);
299
300 rx_ops = target_if_vdev_mgr_get_rx_ops(psoc);
301 if (!rx_ops || !rx_ops->psoc_get_wakelock_info) {
302 mlme_err("psoc_id:%d No Rx Ops",
303 wlan_psoc_get_id(psoc));
304 return;
305 }
306
307 psoc_wakelock = rx_ops->psoc_get_wakelock_info(psoc);
308 ch_params.ch_width = ch_width;
309 if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE)
310 if (is_dfs ||
311 (wlan_reg_get_5g_bonded_channel_state_for_pwrmode(
312 pdev,
313 ch_freq,
314 &ch_params,
315 REG_CURRENT_PWR_MODE) == CHANNEL_STATE_DFS))
316 target_if_vote_for_link_down(psoc, psoc_wakelock);
317 }
318
target_if_prevent_pm_during_roam_sync(struct wlan_objmgr_psoc * psoc)319 void target_if_prevent_pm_during_roam_sync(struct wlan_objmgr_psoc *psoc)
320 {
321 struct psoc_mlme_wakelock *psoc_wakelock;
322 struct wlan_lmac_if_mlme_rx_ops *rx_ops;
323
324 rx_ops = target_if_vdev_mgr_get_rx_ops(psoc);
325 if (!rx_ops || !rx_ops->psoc_get_wakelock_info) {
326 target_if_err("psoc_id:%d No Rx Ops",
327 wlan_psoc_get_id(psoc));
328 return;
329 }
330
331 psoc_wakelock = rx_ops->psoc_get_wakelock_info(psoc);
332 qdf_runtime_pm_prevent_suspend(&psoc_wakelock->roam_sync_runtime_lock);
333 }
334
target_if_allow_pm_after_roam_sync(struct wlan_objmgr_psoc * psoc)335 void target_if_allow_pm_after_roam_sync(struct wlan_objmgr_psoc *psoc)
336 {
337 struct psoc_mlme_wakelock *psoc_wakelock;
338 struct wlan_lmac_if_mlme_rx_ops *rx_ops;
339
340 rx_ops = target_if_vdev_mgr_get_rx_ops(psoc);
341 if (!rx_ops || !rx_ops->psoc_get_wakelock_info) {
342 target_if_err("psoc_id:%d No Rx Ops",
343 wlan_psoc_get_id(psoc));
344 return;
345 }
346
347 psoc_wakelock = rx_ops->psoc_get_wakelock_info(psoc);
348 qdf_runtime_pm_allow_suspend(&psoc_wakelock->roam_sync_runtime_lock);
349 }
350