1 /*
2  * Copyright (c) 2020, The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 /**
19  * DOC: Implement various notification handlers which are accessed
20  * internally in ftm_time_sync component only.
21  */
22 
23 #include "ftm_time_sync_main.h"
24 #include "target_if_ftm_time_sync.h"
25 #include "wlan_objmgr_vdev_obj.h"
26 #include "cfg_ftm_time_sync.h"
27 #include "cfg_ucfg_api.h"
28 #include <pld_common.h>
29 
ftm_time_sync_set_enable(struct wlan_objmgr_psoc * psoc,bool value)30 void ftm_time_sync_set_enable(struct wlan_objmgr_psoc *psoc, bool value)
31 {
32 	struct ftm_time_sync_psoc_priv *psoc_priv;
33 
34 	if (!psoc) {
35 		ftm_time_sync_err("psoc is NULL");
36 		return;
37 	}
38 
39 	psoc_priv = ftm_time_sync_psoc_get_priv(psoc);
40 	if (!psoc_priv) {
41 		ftm_time_sync_err("psoc priv is NULL");
42 		return;
43 	}
44 
45 	psoc_priv->cfg_param.enable &= value;
46 }
47 
ftm_time_sync_is_enable(struct wlan_objmgr_psoc * psoc)48 bool ftm_time_sync_is_enable(struct wlan_objmgr_psoc *psoc)
49 {
50 	struct ftm_time_sync_psoc_priv *psoc_priv;
51 
52 	if (!psoc) {
53 		ftm_time_sync_err("psoc is NULL");
54 		return false;
55 	}
56 
57 	psoc_priv = ftm_time_sync_psoc_get_priv(psoc);
58 	if (!psoc_priv) {
59 		ftm_time_sync_err("psoc priv is NULL");
60 		return false;
61 	}
62 
63 	return psoc_priv->cfg_param.enable;
64 }
65 
ftm_time_sync_get_mode(struct wlan_objmgr_psoc * psoc)66 enum ftm_time_sync_mode ftm_time_sync_get_mode(struct wlan_objmgr_psoc *psoc)
67 {
68 	struct ftm_time_sync_psoc_priv *psoc_priv;
69 
70 	if (!psoc) {
71 		ftm_time_sync_err("psoc is NULL");
72 		return FTM_TIMESYNC_AGGREGATED_MODE;
73 	}
74 
75 	psoc_priv = ftm_time_sync_psoc_get_priv(psoc);
76 	if (!psoc_priv) {
77 		ftm_time_sync_err("psoc priv is NULL");
78 		return FTM_TIMESYNC_AGGREGATED_MODE;
79 	}
80 
81 	return psoc_priv->cfg_param.mode;
82 }
83 
ftm_time_sync_get_role(struct wlan_objmgr_psoc * psoc)84 enum ftm_time_sync_role ftm_time_sync_get_role(struct wlan_objmgr_psoc *psoc)
85 {
86 	struct ftm_time_sync_psoc_priv *psoc_priv;
87 
88 	if (!psoc) {
89 		ftm_time_sync_err("psoc is NULL");
90 		return FTM_TIMESYNC_TARGET_ROLE;
91 	}
92 
93 	psoc_priv = ftm_time_sync_psoc_get_priv(psoc);
94 	if (!psoc_priv) {
95 		ftm_time_sync_err("psoc priv is NULL");
96 		return FTM_TIMESYNC_TARGET_ROLE;
97 	}
98 
99 	return psoc_priv->cfg_param.role;
100 }
101 
ftm_time_sync_work_handler(void * arg)102 static void ftm_time_sync_work_handler(void *arg)
103 {
104 	struct ftm_time_sync_vdev_priv *vdev_priv = arg;
105 	struct wlan_objmgr_psoc *psoc;
106 	qdf_device_t qdf_dev;
107 	QDF_STATUS status;
108 	uint8_t vdev_id;
109 	uint64_t lpass_ts;
110 
111 	if (!vdev_priv) {
112 		ftm_time_sync_err("ftm vdev priv is Null");
113 		return;
114 	}
115 
116 	psoc = wlan_vdev_get_psoc(vdev_priv->vdev);
117 	if (!psoc) {
118 		ftm_time_sync_err("Failed to get psoc");
119 		return;
120 	}
121 
122 	vdev_id = wlan_vdev_get_id(vdev_priv->vdev);
123 
124 	qdf_dev = wlan_psoc_get_qdf_dev(psoc);
125 	pld_get_audio_wlan_timestamp(qdf_dev->dev, PLD_TRIGGER_NEGATIVE_EDGE,
126 				     &lpass_ts);
127 
128 	qdf_mutex_acquire(&vdev_priv->ftm_time_sync_mutex);
129 
130 	if (vdev_priv->num_reads) {
131 		vdev_priv->num_reads--;
132 		qdf_mutex_release(&vdev_priv->ftm_time_sync_mutex);
133 		qdf_delayed_work_start(&vdev_priv->ftm_time_sync_work,
134 				       vdev_priv->time_sync_interval);
135 	} else {
136 		qdf_mutex_release(&vdev_priv->ftm_time_sync_mutex);
137 	}
138 
139 	if (vdev_priv->valid) {
140 		status = vdev_priv->tx_ops.ftm_time_sync_send_qtime(
141 						psoc, vdev_id, lpass_ts);
142 		if (status != QDF_STATUS_SUCCESS)
143 			ftm_time_sync_err("send_ftm_time_sync_qtime failed %d",
144 					  status);
145 		vdev_priv->valid = false;
146 	} else {
147 		vdev_priv->valid = true;
148 	}
149 }
150 
151 QDF_STATUS
ftm_time_sync_vdev_create_notification(struct wlan_objmgr_vdev * vdev,void * arg)152 ftm_time_sync_vdev_create_notification(struct wlan_objmgr_vdev *vdev, void *arg)
153 {
154 	struct ftm_time_sync_vdev_priv *vdev_priv;
155 	struct wlan_objmgr_psoc *psoc;
156 	QDF_STATUS status;
157 
158 	psoc = wlan_vdev_get_psoc(vdev);
159 	if (!psoc) {
160 		ftm_time_sync_err("Failed to get psoc");
161 		return QDF_STATUS_E_INVAL;
162 	}
163 
164 	if (!ftm_time_sync_is_enable(psoc))
165 		return QDF_STATUS_SUCCESS;
166 
167 	vdev_priv = qdf_mem_malloc(sizeof(*vdev_priv));
168 	if (!vdev_priv) {
169 		status = QDF_STATUS_E_NOMEM;
170 		goto exit;
171 	}
172 
173 	status = wlan_objmgr_vdev_component_obj_attach(
174 				vdev, WLAN_UMAC_COMP_FTM_TIME_SYNC,
175 				(void *)vdev_priv, QDF_STATUS_SUCCESS);
176 	if (QDF_IS_STATUS_ERROR(status)) {
177 		ftm_time_sync_err("Failed to attach priv with vdev");
178 		goto free_vdev_priv;
179 	}
180 
181 	vdev_priv->vdev = vdev;
182 	status = qdf_delayed_work_create(&vdev_priv->ftm_time_sync_work,
183 					 ftm_time_sync_work_handler, vdev_priv);
184 	if (QDF_IS_STATUS_ERROR(status)) {
185 		ftm_time_sync_err("Failed to create ftm time sync work\n");
186 		goto free_vdev_priv;
187 	}
188 
189 	qdf_mutex_create(&vdev_priv->ftm_time_sync_mutex);
190 
191 	target_if_ftm_time_sync_register_tx_ops(&vdev_priv->tx_ops);
192 	target_if_ftm_time_sync_register_rx_ops(&vdev_priv->rx_ops);
193 
194 	vdev_priv->rx_ops.ftm_time_sync_register_start_stop(psoc);
195 	vdev_priv->rx_ops.ftm_time_sync_regiser_initiator_target_offset(psoc);
196 
197 	vdev_priv->valid = true;
198 
199 	goto exit;
200 
201 free_vdev_priv:
202 	qdf_mem_free(vdev_priv);
203 	status = QDF_STATUS_E_INVAL;
204 exit:
205 	return status;
206 }
207 
208 static QDF_STATUS
ftm_time_sync_deregister_wmi_events(struct wlan_objmgr_vdev * vdev)209 ftm_time_sync_deregister_wmi_events(struct wlan_objmgr_vdev *vdev)
210 {
211 	struct wlan_objmgr_psoc *psoc;
212 	QDF_STATUS status;
213 
214 	psoc = wlan_vdev_get_psoc(vdev);
215 	if (!psoc) {
216 		ftm_time_sync_err("Failed to get psoc");
217 		return QDF_STATUS_E_INVAL;
218 	}
219 
220 	status = target_if_ftm_time_sync_unregister_ev_handlers(psoc);
221 	return status;
222 }
223 
224 QDF_STATUS
ftm_time_sync_vdev_destroy_notification(struct wlan_objmgr_vdev * vdev,void * arg)225 ftm_time_sync_vdev_destroy_notification(struct wlan_objmgr_vdev *vdev,
226 					void *arg)
227 
228 {
229 	struct ftm_time_sync_vdev_priv *vdev_priv = NULL;
230 	struct wlan_objmgr_psoc *psoc;
231 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
232 
233 	psoc = wlan_vdev_get_psoc(vdev);
234 	if (!psoc) {
235 		ftm_time_sync_err("Failed to get psoc");
236 		return QDF_STATUS_E_INVAL;
237 	}
238 
239 	if (!ftm_time_sync_is_enable(psoc))
240 		return QDF_STATUS_SUCCESS;
241 
242 	vdev_priv = ftm_time_sync_vdev_get_priv(vdev);
243 	if (!vdev_priv) {
244 		ftm_time_sync_err("vdev priv is NULL");
245 		goto exit;
246 	}
247 
248 	qdf_mutex_destroy(&vdev_priv->ftm_time_sync_mutex);
249 	qdf_delayed_work_destroy(&vdev_priv->ftm_time_sync_work);
250 
251 	ftm_time_sync_deregister_wmi_events(vdev);
252 
253 	status = wlan_objmgr_vdev_component_obj_detach(
254 					vdev, WLAN_UMAC_COMP_FTM_TIME_SYNC,
255 					(void *)vdev_priv);
256 	if (QDF_IS_STATUS_ERROR(status))
257 		ftm_time_sync_err("Failed to detach priv with vdev");
258 
259 	qdf_mem_free(vdev_priv);
260 	vdev_priv = NULL;
261 
262 exit:
263 	return status;
264 }
265 
266 static void
ftm_time_sync_cfg_init(struct ftm_time_sync_psoc_priv * psoc_priv)267 ftm_time_sync_cfg_init(struct ftm_time_sync_psoc_priv *psoc_priv)
268 {
269 	psoc_priv->cfg_param.enable = cfg_get(psoc_priv->psoc,
270 					      CFG_ENABLE_TIME_SYNC_FTM);
271 	psoc_priv->cfg_param.role = cfg_get(psoc_priv->psoc,
272 					    CFG_TIME_SYNC_FTM_ROLE);
273 	psoc_priv->cfg_param.mode = cfg_get(psoc_priv->psoc,
274 					    CFG_TIME_SYNC_FTM_MODE);
275 }
276 
277 QDF_STATUS
ftm_time_sync_psoc_create_notification(struct wlan_objmgr_psoc * psoc,void * arg)278 ftm_time_sync_psoc_create_notification(struct wlan_objmgr_psoc *psoc, void *arg)
279 {
280 	struct ftm_time_sync_psoc_priv *psoc_priv;
281 	QDF_STATUS status;
282 
283 	psoc_priv = qdf_mem_malloc(sizeof(*psoc_priv));
284 	if (!psoc_priv)
285 		return QDF_STATUS_E_NOMEM;
286 
287 	status = wlan_objmgr_psoc_component_obj_attach(
288 				psoc, WLAN_UMAC_COMP_FTM_TIME_SYNC,
289 				psoc_priv, QDF_STATUS_SUCCESS);
290 	if (QDF_IS_STATUS_ERROR(status)) {
291 		ftm_time_sync_err("Failed to attach psoc component obj");
292 		goto free_psoc_priv;
293 	}
294 
295 	psoc_priv->psoc = psoc;
296 	ftm_time_sync_cfg_init(psoc_priv);
297 
298 	return status;
299 
300 free_psoc_priv:
301 	qdf_mem_free(psoc_priv);
302 	return status;
303 }
304 
305 QDF_STATUS
ftm_time_sync_psoc_destroy_notification(struct wlan_objmgr_psoc * psoc,void * arg)306 ftm_time_sync_psoc_destroy_notification(struct wlan_objmgr_psoc *psoc,
307 					void *arg)
308 {
309 	struct ftm_time_sync_psoc_priv *psoc_priv;
310 	QDF_STATUS status;
311 
312 	psoc_priv = ftm_time_sync_psoc_get_priv(psoc);
313 	if (!psoc_priv) {
314 		ftm_time_sync_err("psoc priv is NULL");
315 		return QDF_STATUS_E_FAILURE;
316 	}
317 
318 	status = wlan_objmgr_psoc_component_obj_detach(
319 					psoc, WLAN_UMAC_COMP_FTM_TIME_SYNC,
320 					psoc_priv);
321 	if (QDF_IS_STATUS_ERROR(status)) {
322 		ftm_time_sync_err("Failed to detach psoc component obj");
323 		return status;
324 	}
325 
326 	qdf_mem_free(psoc_priv);
327 	return status;
328 }
329 
ftm_time_sync_send_trigger(struct wlan_objmgr_vdev * vdev)330 QDF_STATUS ftm_time_sync_send_trigger(struct wlan_objmgr_vdev *vdev)
331 {
332 	struct ftm_time_sync_vdev_priv *vdev_priv;
333 	struct wlan_objmgr_psoc *psoc;
334 	enum ftm_time_sync_mode mode;
335 	uint8_t vdev_id;
336 	QDF_STATUS status;
337 
338 	psoc = wlan_vdev_get_psoc(vdev);
339 	if (!psoc) {
340 		ftm_time_sync_err("Failed to get psoc");
341 		return QDF_STATUS_E_INVAL;
342 	}
343 
344 	vdev_priv = ftm_time_sync_vdev_get_priv(vdev);
345 	if (!vdev_priv) {
346 		ftm_time_sync_err("Failed to get ftm time sync vdev_priv");
347 		return QDF_STATUS_E_INVAL;
348 	}
349 
350 	vdev_id = wlan_vdev_get_id(vdev_priv->vdev);
351 	mode = ftm_time_sync_get_mode(psoc);
352 
353 	status = vdev_priv->tx_ops.ftm_time_sync_send_trigger(psoc,
354 							      vdev_id, mode);
355 	if (QDF_IS_STATUS_ERROR(status))
356 		ftm_time_sync_err("send_ftm_time_sync_trigger failed %d",
357 				  status);
358 
359 	return QDF_STATUS_SUCCESS;
360 }
361 
ftm_time_sync_stop(struct wlan_objmgr_vdev * vdev)362 QDF_STATUS ftm_time_sync_stop(struct wlan_objmgr_vdev *vdev)
363 {
364 	struct ftm_time_sync_vdev_priv *vdev_priv;
365 	int iter;
366 
367 	vdev_priv = ftm_time_sync_vdev_get_priv(vdev);
368 	if (!vdev_priv) {
369 		ftm_time_sync_err("Failed to get ftm time sync vdev_priv");
370 		return QDF_STATUS_E_INVAL;
371 	}
372 
373 	qdf_delayed_work_stop_sync(&vdev_priv->ftm_time_sync_work);
374 
375 	for (iter = 0; iter < vdev_priv->num_qtime_pair; iter++) {
376 		vdev_priv->ftm_ts_priv.time_pair[iter].qtime_initiator = 0;
377 		vdev_priv->ftm_ts_priv.time_pair[iter].qtime_target = 0;
378 	}
379 
380 	vdev_priv->num_qtime_pair = 0;
381 
382 	return QDF_STATUS_SUCCESS;
383 }
384 
ftm_time_sync_show(struct wlan_objmgr_vdev * vdev,char * buf)385 ssize_t ftm_time_sync_show(struct wlan_objmgr_vdev *vdev, char *buf)
386 {
387 	struct ftm_time_sync_vdev_priv *vdev_priv;
388 	uint64_t q_initiator, q_target;
389 	ssize_t size = 0;
390 	int iter;
391 
392 	vdev_priv = ftm_time_sync_vdev_get_priv(vdev);
393 	if (!vdev_priv) {
394 		ftm_time_sync_debug("Failed to get ftm time sync vdev_priv");
395 		return 0;
396 	}
397 
398 	size = qdf_scnprintf(buf, PAGE_SIZE,
399 			     "%s " QDF_MAC_ADDR_FMT "\n", "BSSID",
400 			     QDF_MAC_ADDR_REF(vdev_priv->bssid.bytes));
401 
402 	for (iter = 0; iter < vdev_priv->num_qtime_pair; iter++) {
403 		q_initiator = vdev_priv->ftm_ts_priv.time_pair[iter].qtime_initiator;
404 		q_target = vdev_priv->ftm_ts_priv.time_pair[iter].qtime_target;
405 
406 		size += qdf_scnprintf(buf + size, PAGE_SIZE - size,
407 				      "%s %llu %s %llu %s %lld\n",
408 
409 				      "Qtime_initiator", q_initiator, "Qtime_target",
410 				      q_target, "Offset", q_target > q_initiator ?
411 				      q_target - q_initiator : q_initiator - q_target);
412 	}
413 	return size;
414 }
415 
ftm_time_sync_update_bssid(struct wlan_objmgr_vdev * vdev,struct qdf_mac_addr bssid)416 void ftm_time_sync_update_bssid(struct wlan_objmgr_vdev *vdev,
417 				struct qdf_mac_addr bssid)
418 {
419 	struct ftm_time_sync_vdev_priv *vdev_priv;
420 
421 	vdev_priv = ftm_time_sync_vdev_get_priv(vdev);
422 	if (!vdev_priv) {
423 		ftm_time_sync_debug("Failed to get ftm time sync vdev_priv");
424 		return;
425 	}
426 
427 	vdev_priv->bssid = bssid;
428 }
429