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