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, ¶m);
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