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