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