1 /*
2  * Copyright (c) 2017-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
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: offload lmac interface APIs definitions for P2P
22  */
23 
24 #include <wmi_unified_api.h>
25 #include <wlan_p2p_public_struct.h>
26 #include "target_if.h"
27 #include "target_if_p2p.h"
28 #include "target_if_p2p_mcc_quota.h"
29 #include "init_deinit_lmac.h"
30 
31 static inline struct wlan_lmac_if_p2p_rx_ops *
target_if_psoc_get_p2p_rx_ops(struct wlan_objmgr_psoc * psoc)32 target_if_psoc_get_p2p_rx_ops(struct wlan_objmgr_psoc *psoc)
33 {
34 	return &(psoc->soc_cb.rx_ops->p2p);
35 }
36 
37 #ifdef FEATURE_P2P_LISTEN_OFFLOAD
38 static inline void
target_if_p2p_lo_register_tx_ops(struct wlan_lmac_if_p2p_tx_ops * p2p_tx_ops)39 target_if_p2p_lo_register_tx_ops(struct wlan_lmac_if_p2p_tx_ops *p2p_tx_ops)
40 {
41 	p2p_tx_ops->lo_start = target_if_p2p_lo_start;
42 	p2p_tx_ops->lo_stop = target_if_p2p_lo_stop;
43 	p2p_tx_ops->reg_lo_ev_handler =
44 			target_if_p2p_register_lo_event_handler;
45 	p2p_tx_ops->unreg_lo_ev_handler =
46 			target_if_p2p_unregister_lo_event_handler;
47 }
48 
49 /**
50  * target_p2p_lo_event_handler() - WMI callback for lo stop event
51  * @scn:       pointer to scn
52  * @data:      event buffer
53  * @datalen:   buffer length
54  *
55  * This function gets called from WMI when triggered wmi event
56  * wmi_p2p_lo_stop_event_id.
57  *
58  * Return: 0 - success
59  * others - failure
60  */
target_p2p_lo_event_handler(ol_scn_t scn,uint8_t * data,uint32_t datalen)61 static int target_p2p_lo_event_handler(ol_scn_t scn, uint8_t *data,
62 	uint32_t datalen)
63 {
64 	struct wlan_objmgr_psoc *psoc;
65 	struct wmi_unified *wmi_handle;
66 	struct p2p_lo_event *event_info;
67 	struct wlan_lmac_if_p2p_rx_ops *p2p_rx_ops;
68 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
69 
70 	target_if_debug("scn:%pK, data:%pK, datalen:%d", scn, data, datalen);
71 
72 	if (!scn || !data) {
73 		target_if_err("scn: 0x%pK, data: 0x%pK", scn, data);
74 		return -EINVAL;
75 	}
76 
77 	psoc = target_if_get_psoc_from_scn_hdl(scn);
78 	if (!psoc) {
79 		target_if_err("null psoc");
80 		return -EINVAL;
81 	}
82 
83 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
84 	if (!wmi_handle) {
85 		target_if_err("null wmi handle");
86 		return -EINVAL;
87 	}
88 
89 	event_info = qdf_mem_malloc(sizeof(*event_info));
90 	if (!event_info)
91 		return -ENOMEM;
92 
93 	if (wmi_extract_p2p_lo_stop_ev_param(wmi_handle, data,
94 			event_info)) {
95 		target_if_err("Failed to extract wmi p2p lo stop event");
96 		qdf_mem_free(event_info);
97 		return -EINVAL;
98 	}
99 
100 	p2p_rx_ops = target_if_psoc_get_p2p_rx_ops(psoc);
101 	if (p2p_rx_ops->lo_ev_handler) {
102 		status = p2p_rx_ops->lo_ev_handler(psoc, event_info);
103 		target_if_debug("call lo event handler, status:%d",
104 			status);
105 	} else {
106 		qdf_mem_free(event_info);
107 		target_if_debug("no valid lo event handler");
108 	}
109 
110 	return qdf_status_to_os_return(status);
111 }
112 
target_if_p2p_register_lo_event_handler(struct wlan_objmgr_psoc * psoc,void * arg)113 QDF_STATUS target_if_p2p_register_lo_event_handler(
114 	struct wlan_objmgr_psoc *psoc, void *arg)
115 {
116 	QDF_STATUS status;
117 	wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc);
118 
119 	target_if_debug("psoc:%pK, arg:%pK", psoc, arg);
120 
121 	if (!wmi_handle) {
122 		target_if_err("Invalid wmi handle");
123 		return QDF_STATUS_E_INVAL;
124 	}
125 
126 	status = wmi_unified_register_event(wmi_handle,
127 					    wmi_p2p_lo_stop_event_id,
128 					    target_p2p_lo_event_handler);
129 
130 	target_if_debug("wmi register lo event handle, status:%d", status);
131 
132 	if (QDF_IS_STATUS_ERROR(status))
133 		return QDF_STATUS_E_FAILURE;
134 	else
135 		return QDF_STATUS_SUCCESS;
136 }
137 
target_if_p2p_unregister_lo_event_handler(struct wlan_objmgr_psoc * psoc,void * arg)138 QDF_STATUS target_if_p2p_unregister_lo_event_handler(
139 	struct wlan_objmgr_psoc *psoc, void *arg)
140 {
141 	QDF_STATUS status;
142 	wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc);
143 
144 	target_if_debug("psoc:%pK, arg:%pK", psoc, arg);
145 
146 	if (!wmi_handle) {
147 		target_if_err("Invalid wmi handle");
148 		return QDF_STATUS_E_INVAL;
149 	}
150 
151 	status = wmi_unified_unregister_event(wmi_handle,
152 					      wmi_p2p_lo_stop_event_id);
153 
154 	target_if_debug("wmi unregister lo event handle, status:%d", status);
155 
156 	if (QDF_IS_STATUS_ERROR(status))
157 		return QDF_STATUS_E_FAILURE;
158 	else
159 		return QDF_STATUS_SUCCESS;
160 }
161 
target_if_p2p_lo_start(struct wlan_objmgr_psoc * psoc,struct p2p_lo_start * lo_start)162 QDF_STATUS target_if_p2p_lo_start(struct wlan_objmgr_psoc *psoc,
163 				  struct p2p_lo_start *lo_start)
164 {
165 	wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc);
166 
167 	if (!wmi_handle) {
168 		target_if_err("Invalid wmi handle");
169 		return QDF_STATUS_E_INVAL;
170 	}
171 
172 	if (!lo_start) {
173 		target_if_err("lo start parameters is null");
174 		return QDF_STATUS_E_INVAL;
175 	}
176 	target_if_debug("psoc:%pK, vdev_id:%d", psoc, lo_start->vdev_id);
177 
178 	return wmi_unified_p2p_lo_start_cmd(wmi_handle, lo_start);
179 }
180 
target_if_p2p_lo_stop(struct wlan_objmgr_psoc * psoc,uint32_t vdev_id)181 QDF_STATUS target_if_p2p_lo_stop(struct wlan_objmgr_psoc *psoc,
182 				 uint32_t vdev_id)
183 {
184 	wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc);
185 
186 	target_if_debug("psoc:%pK, vdev_id:%d", psoc, vdev_id);
187 
188 	if (!wmi_handle) {
189 		target_if_err("Invalid wmi handle");
190 		return QDF_STATUS_E_INVAL;
191 	}
192 
193 	return wmi_unified_p2p_lo_stop_cmd(wmi_handle,
194 			(uint8_t)vdev_id);
195 }
196 #else
197 static inline void
target_if_p2p_lo_register_tx_ops(struct wlan_lmac_if_p2p_tx_ops * p2p_tx_ops)198 target_if_p2p_lo_register_tx_ops(struct wlan_lmac_if_p2p_tx_ops *p2p_tx_ops)
199 {
200 }
201 #endif /* FEATURE_P2P_LISTEN_OFFLOAD */
202 
203 /**
204  * target_p2p_noa_event_handler() - WMI callback for noa event
205  * @scn:       pointer to scn
206  * @data:      event buffer
207  * @datalen:   buffer length
208  *
209  * This function gets called from WMI when triggered WMI event
210  * wmi_p2p_noa_event_id.
211  *
212  * Return: 0 - success
213  * others - failure
214  */
target_p2p_noa_event_handler(ol_scn_t scn,uint8_t * data,uint32_t datalen)215 static int target_p2p_noa_event_handler(ol_scn_t scn, uint8_t *data,
216 	uint32_t datalen)
217 {
218 	struct wlan_objmgr_psoc *psoc;
219 	struct wmi_unified *wmi_handle;
220 	struct p2p_noa_info *event_info;
221 	struct wlan_lmac_if_p2p_rx_ops *p2p_rx_ops;
222 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
223 
224 	target_if_debug("scn:%pK, data:%pK, datalen:%d", scn, data, datalen);
225 
226 	if (!scn || !data) {
227 		target_if_err("scn: 0x%pK, data: 0x%pK", scn, data);
228 		return -EINVAL;
229 	}
230 
231 	psoc = target_if_get_psoc_from_scn_hdl(scn);
232 	if (!psoc) {
233 		target_if_err("null psoc");
234 		return -EINVAL;
235 	}
236 
237 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
238 	if (!wmi_handle) {
239 		target_if_err("null wmi handle");
240 		return -EINVAL;
241 	}
242 
243 	event_info = qdf_mem_malloc(sizeof(*event_info));
244 	if (!event_info)
245 		return -ENOMEM;
246 
247 	if (wmi_extract_p2p_noa_ev_param(wmi_handle, data,
248 			event_info)) {
249 		target_if_err("failed to extract wmi p2p noa event");
250 		qdf_mem_free(event_info);
251 		return -EINVAL;
252 	}
253 
254 	p2p_rx_ops = target_if_psoc_get_p2p_rx_ops(psoc);
255 	if (p2p_rx_ops->noa_ev_handler) {
256 		status = p2p_rx_ops->noa_ev_handler(psoc, event_info);
257 		target_if_debug("call noa event handler, status:%d",
258 			status);
259 	} else {
260 		qdf_mem_free(event_info);
261 		target_if_debug("no valid noa event handler");
262 	}
263 
264 	return qdf_status_to_os_return(status);
265 }
266 
target_if_p2p_register_noa_event_handler(struct wlan_objmgr_psoc * psoc,void * arg)267 QDF_STATUS target_if_p2p_register_noa_event_handler(
268 	struct wlan_objmgr_psoc *psoc, void *arg)
269 {
270 	int status;
271 	wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc);
272 
273 	target_if_debug("psoc:%pK, arg:%pK", psoc, arg);
274 
275 	if (!wmi_handle) {
276 		target_if_err("Invalid wmi handle");
277 		return QDF_STATUS_E_INVAL;
278 	}
279 
280 	status = wmi_unified_register_event(wmi_handle,
281 			wmi_p2p_noa_event_id,
282 			target_p2p_noa_event_handler);
283 
284 	target_if_debug("wmi register noa event handle, status:%d",
285 		status);
286 
287 	return status == 0 ? QDF_STATUS_SUCCESS : QDF_STATUS_E_FAILURE;
288 }
289 
target_if_p2p_unregister_noa_event_handler(struct wlan_objmgr_psoc * psoc,void * arg)290 QDF_STATUS target_if_p2p_unregister_noa_event_handler(
291 	struct wlan_objmgr_psoc *psoc, void *arg)
292 {
293 	QDF_STATUS status;
294 	wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc);
295 
296 	target_if_debug("psoc:%pK, arg:%pK", psoc, arg);
297 
298 	if (!wmi_handle) {
299 		target_if_err("Invalid wmi handle");
300 		return QDF_STATUS_E_INVAL;
301 	}
302 
303 	status = wmi_unified_unregister_event(wmi_handle,
304 			wmi_p2p_noa_event_id);
305 
306 	target_if_debug("wmi unregister noa event handle, status:%d",
307 		status);
308 
309 	if (QDF_IS_STATUS_ERROR(status))
310 		return QDF_STATUS_E_FAILURE;
311 	else
312 		return QDF_STATUS_SUCCESS;
313 }
314 
target_if_p2p_set_ps(struct wlan_objmgr_psoc * psoc,struct p2p_ps_config * ps_config)315 QDF_STATUS target_if_p2p_set_ps(struct wlan_objmgr_psoc *psoc,
316 	struct p2p_ps_config *ps_config)
317 {
318 	struct p2p_ps_params cmd;
319 	QDF_STATUS status;
320 	 wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc);
321 
322 	if (!wmi_handle) {
323 		target_if_err("Invalid wmi handle");
324 		return QDF_STATUS_E_INVAL;
325 	}
326 
327 	if (!ps_config) {
328 		target_if_err("ps config parameters is null");
329 		return QDF_STATUS_E_INVAL;
330 	}
331 
332 	target_if_debug("psoc:%pK, vdev_id:%d, opp_ps:%d", psoc,
333 			ps_config->vdev_id, ps_config->opp_ps);
334 
335 	cmd.opp_ps = ps_config->opp_ps;
336 	cmd.ctwindow = ps_config->ct_window;
337 	cmd.count = ps_config->count;
338 	cmd.duration = ps_config->duration;
339 	cmd.interval = ps_config->interval;
340 	cmd.single_noa_duration = ps_config->single_noa_duration;
341 	cmd.ps_selection = ps_config->ps_selection;
342 	cmd.session_id =  ps_config->vdev_id;
343 	cmd.start = ps_config->start;
344 
345 	if (ps_config->opp_ps)
346 		status = wmi_unified_set_p2pgo_oppps_req(wmi_handle,
347 				   &cmd);
348 	else
349 		status = wmi_unified_set_p2pgo_noa_req_cmd(wmi_handle,
350 				   &cmd);
351 
352 	if (status != QDF_STATUS_SUCCESS)
353 		target_if_err("Failed to send set uapsd param, %d",
354 				status);
355 
356 	return status;
357 }
358 
target_if_p2p_set_noa(struct wlan_objmgr_psoc * psoc,uint32_t vdev_id,bool disable_noa)359 QDF_STATUS target_if_p2p_set_noa(struct wlan_objmgr_psoc *psoc,
360 	uint32_t vdev_id, bool disable_noa)
361 {
362 	struct vdev_set_params param;
363 	wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc);
364 
365 	if (!wmi_handle) {
366 		target_if_err("Invalid wmi handle");
367 		return QDF_STATUS_E_INVAL;
368 	}
369 
370 	target_if_debug("psoc:%pK, vdev_id:%d disable_noa:%d",
371 				psoc, vdev_id, disable_noa);
372 	param.vdev_id = vdev_id;
373 	param.param_id = wmi_vdev_param_disable_noa_p2p_go;
374 	param.param_value = (uint32_t)disable_noa;
375 
376 	return wmi_unified_vdev_set_param_send(wmi_handle, &param);
377 }
378 
target_p2p_mac_rx_filter_event_handler(ol_scn_t scn,uint8_t * data,uint32_t datalen)379 static int target_p2p_mac_rx_filter_event_handler(ol_scn_t scn, uint8_t *data,
380 						  uint32_t datalen)
381 {
382 	struct wlan_objmgr_psoc *psoc;
383 	struct wmi_unified *wmi_handle;
384 	struct p2p_set_mac_filter_evt event_info;
385 	struct wlan_lmac_if_p2p_rx_ops *p2p_rx_ops;
386 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
387 
388 	if (!scn || !data) {
389 		target_if_err("scn: 0x%pK, data: 0x%pK", scn, data);
390 		return -EINVAL;
391 	}
392 
393 	psoc = target_if_get_psoc_from_scn_hdl(scn);
394 	if (!psoc) {
395 		target_if_err("null psoc");
396 		return -EINVAL;
397 	}
398 
399 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
400 	if (!wmi_handle) {
401 		target_if_err("null wmi handle");
402 		return -EINVAL;
403 	}
404 
405 	if (wmi_extract_mac_addr_rx_filter_evt_param(wmi_handle, data,
406 						     &event_info)) {
407 		target_if_err("failed to extract wmi p2p noa event");
408 		return -EINVAL;
409 	}
410 	target_if_debug("vdev_id %d status %d", event_info.vdev_id,
411 			event_info.status);
412 	p2p_rx_ops = target_if_psoc_get_p2p_rx_ops(psoc);
413 	if (p2p_rx_ops && p2p_rx_ops->add_mac_addr_filter_evt_handler)
414 		status = p2p_rx_ops->add_mac_addr_filter_evt_handler(
415 					psoc, &event_info);
416 	else
417 		target_if_debug("no add mac addr filter event handler");
418 
419 	return qdf_status_to_os_return(status);
420 }
421 
target_if_p2p_register_macaddr_rx_filter_evt_handler(struct wlan_objmgr_psoc * psoc,bool reg)422 static QDF_STATUS target_if_p2p_register_macaddr_rx_filter_evt_handler(
423 		struct wlan_objmgr_psoc *psoc, bool reg)
424 {
425 	int status;
426 	wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc);
427 
428 	target_if_debug("psoc:%pK, register %d mac addr rx evt", psoc, reg);
429 
430 	if (!wmi_handle) {
431 		target_if_err("Invalid wmi handle");
432 		return QDF_STATUS_E_INVAL;
433 	}
434 	if (reg)
435 		status = wmi_unified_register_event(
436 				wmi_handle,
437 				wmi_vdev_add_macaddr_rx_filter_event_id,
438 				target_p2p_mac_rx_filter_event_handler);
439 	else
440 		status = wmi_unified_unregister_event(
441 				wmi_handle,
442 				wmi_vdev_add_macaddr_rx_filter_event_id);
443 
444 	return status == 0 ? QDF_STATUS_SUCCESS : QDF_STATUS_E_FAILURE;
445 }
446 
target_if_p2p_set_mac_addr_rx_filter_cmd(struct wlan_objmgr_psoc * psoc,struct set_rx_mac_filter * param)447 static QDF_STATUS target_if_p2p_set_mac_addr_rx_filter_cmd(
448 	struct wlan_objmgr_psoc *psoc, struct set_rx_mac_filter *param)
449 {
450 	wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc);
451 
452 	if (!wmi_handle) {
453 		target_if_err("Invalid wmi handle");
454 		return QDF_STATUS_E_INVAL;
455 	}
456 
457 	return wmi_unified_set_mac_addr_rx_filter(wmi_handle, param);
458 }
459 
target_if_p2p_register_tx_ops(struct wlan_lmac_if_tx_ops * tx_ops)460 void target_if_p2p_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
461 {
462 	struct wlan_lmac_if_p2p_tx_ops *p2p_tx_ops;
463 
464 	if (!tx_ops) {
465 		target_if_err("lmac tx_ops is null");
466 		return;
467 	}
468 
469 	p2p_tx_ops = &tx_ops->p2p;
470 	p2p_tx_ops->set_ps = target_if_p2p_set_ps;
471 	p2p_tx_ops->set_noa = target_if_p2p_set_noa;
472 	p2p_tx_ops->reg_noa_ev_handler =
473 			target_if_p2p_register_noa_event_handler;
474 	p2p_tx_ops->unreg_noa_ev_handler =
475 			target_if_p2p_unregister_noa_event_handler;
476 	p2p_tx_ops->reg_mac_addr_rx_filter_handler =
477 		target_if_p2p_register_macaddr_rx_filter_evt_handler;
478 	p2p_tx_ops->set_mac_addr_rx_filter_cmd =
479 		target_if_p2p_set_mac_addr_rx_filter_cmd;
480 	target_if_mcc_quota_register_tx_ops(tx_ops);
481 
482 	/* register P2P listen offload callbacks */
483 	target_if_p2p_lo_register_tx_ops(p2p_tx_ops);
484 }
485