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: contains coex target if functions
20  */
21 #include <wlan_coex_main.h>
22 #include <target_if_coex.h>
23 #include "wlan_coex_public_structs.h"
24 
25 /**
26  * target_if_coex_config_send() - Function to send coex config command
27  * @pdev: PDEV object
28  * @param: Pointer to coex config parameters
29  *
30  * Return: QDF STATUS
31  */
32 static QDF_STATUS
target_if_coex_config_send(struct wlan_objmgr_pdev * pdev,struct coex_config_params * param)33 target_if_coex_config_send(struct wlan_objmgr_pdev *pdev,
34 			   struct coex_config_params *param)
35 {
36 	wmi_unified_t pdev_wmi_handle;
37 
38 	pdev_wmi_handle = GET_WMI_HDL_FROM_PDEV(pdev);
39 	if (!pdev_wmi_handle) {
40 		coex_err("Invalid PDEV WMI handle");
41 		return QDF_STATUS_E_FAILURE;
42 	}
43 
44 	return wmi_unified_send_coex_config_cmd(pdev_wmi_handle, param);
45 }
46 
47 /**
48  * target_if_coex_multi_config_send() - Function to send coex multiple config
49  * command
50  * @pdev: PDEV object
51  * @param: Pointer to coex multiple config parameters
52  *
53  * Return: QDF STATUS
54  */
55 static QDF_STATUS
target_if_coex_multi_config_send(struct wlan_objmgr_pdev * pdev,struct coex_multi_config * param)56 target_if_coex_multi_config_send(struct wlan_objmgr_pdev *pdev,
57 				 struct coex_multi_config *param)
58 {
59 	wmi_unified_t pdev_wmi_handle;
60 
61 	pdev_wmi_handle = GET_WMI_HDL_FROM_PDEV(pdev);
62 	if (!pdev_wmi_handle) {
63 		coex_err("Invalid PDEV WMI handle");
64 		return QDF_STATUS_E_FAILURE;
65 	}
66 
67 	return wmi_unified_send_coex_multi_config_cmd(pdev_wmi_handle, param);
68 }
69 
70 /**
71  * target_if_coex_get_multi_config_support() - Function to get coex multiple
72  * config command support
73  * @psoc: PSOC object
74  *
75  * Return: true if target support coex multiple config command
76  */
77 static bool
target_if_coex_get_multi_config_support(struct wlan_objmgr_psoc * psoc)78 target_if_coex_get_multi_config_support(struct wlan_objmgr_psoc *psoc)
79 {
80 	wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
81 
82 	if (!wmi_handle) {
83 		target_if_err("Invalid wmi handle");
84 		return false;
85 	}
86 
87 	return wmi_service_enabled(wmi_handle,
88 				   wmi_service_multiple_coex_config_support);
89 }
90 
91 QDF_STATUS
target_if_coex_register_tx_ops(struct wlan_lmac_if_tx_ops * tx_ops)92 target_if_coex_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
93 {
94 	struct wlan_lmac_if_coex_tx_ops *coex_ops;
95 
96 	if (!tx_ops) {
97 		coex_err("target if tx ops is NULL!");
98 		return QDF_STATUS_E_INVAL;
99 	}
100 
101 	coex_ops = &tx_ops->coex_ops;
102 	coex_ops->coex_config_send = target_if_coex_config_send;
103 	coex_ops->coex_multi_config_send = target_if_coex_multi_config_send;
104 	coex_ops->coex_get_multi_config_support =
105 				target_if_coex_get_multi_config_support;
106 
107 	return QDF_STATUS_SUCCESS;
108 }
109 
110 #ifdef WLAN_FEATURE_DBAM_CONFIG
111 QDF_STATUS
target_if_dbam_process_event(struct wlan_objmgr_psoc * psoc,enum coex_dbam_comp_status resp)112 target_if_dbam_process_event(struct wlan_objmgr_psoc *psoc,
113 			     enum coex_dbam_comp_status resp)
114 {
115 	struct coex_psoc_obj *coex_obj;
116 	struct wlan_coex_callback *cb;
117 
118 	if (!psoc) {
119 		coex_err("psoc is null");
120 		return QDF_STATUS_E_INVAL;
121 	}
122 
123 	coex_obj = wlan_psoc_get_coex_obj(psoc);
124 	if (!coex_obj) {
125 		coex_err("failed to get coex_obj");
126 		return QDF_STATUS_E_INVAL;
127 	}
128 
129 	cb = &coex_obj->cb;
130 	if (cb->set_dbam_config_cb)
131 		cb->set_dbam_config_cb(cb->set_dbam_config_ctx, &resp);
132 
133 	return QDF_STATUS_SUCCESS;
134 }
135 
136 /**
137  * target_if_dbam_response_event_handler() - function to handle dbam response
138  * event from firmware.
139  * @scn: scn handle
140  * @data: data buffer foe the event
141  * @len: data length
142  *
143  * Return: 0 on success, and error code on failure
144  */
target_if_dbam_response_event_handler(ol_scn_t scn,uint8_t * data,uint32_t len)145 static int target_if_dbam_response_event_handler(ol_scn_t scn,
146 						 uint8_t *data,
147 						 uint32_t len)
148 {
149 	QDF_STATUS status;
150 	struct wlan_objmgr_psoc *psoc;
151 	wmi_unified_t wmi_handle;
152 	struct wlan_lmac_if_dbam_rx_ops *rx_ops;
153 	struct coex_dbam_config_resp resp = {0};
154 
155 	target_if_debug("scn:%pK, data:%pK, datalen:%d", scn, data, len);
156 	if (!scn || !data) {
157 		target_if_err("scn: 0x%pK, data: 0x%pK", scn, data);
158 		return -EINVAL;
159 	}
160 
161 	psoc = target_if_get_psoc_from_scn_hdl(scn);
162 	if (!psoc) {
163 		target_if_err("psoc is Null");
164 		return -EINVAL;
165 	}
166 
167 	rx_ops = wlan_psoc_get_dbam_rx_ops(psoc);
168 	if (!rx_ops || !rx_ops->dbam_resp_event) {
169 		target_if_err("callback not registered");
170 		return -EINVAL;
171 	}
172 
173 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
174 	if (!wmi_handle) {
175 		target_if_err("wmi_handle is null");
176 		return -EINVAL;
177 	}
178 
179 	status = wmi_extract_dbam_config_response(wmi_handle, data, &resp);
180 	if (QDF_IS_STATUS_ERROR(status)) {
181 		target_if_err("Failed to extract dbam config response");
182 		return -EINVAL;
183 	}
184 
185 	status = rx_ops->dbam_resp_event(psoc, resp.dbam_resp);
186 	if (QDF_IS_STATUS_ERROR(status)) {
187 		target_if_err("process dbam response event failed");
188 		return -EINVAL;
189 	}
190 
191 	return 0;
192 }
193 
194 /**
195  * target_if_dbam_config_send() - Send WMI command for DBAM configuration
196  * @psoc: psoc pointer
197  * @param: dbam config parameters
198  *
199  * Return: QDF_STATUS
200  */
201 static QDF_STATUS
target_if_dbam_config_send(struct wlan_objmgr_psoc * psoc,struct coex_dbam_config_params * param)202 target_if_dbam_config_send(struct wlan_objmgr_psoc *psoc,
203 			   struct coex_dbam_config_params *param)
204 {
205 	QDF_STATUS status;
206 	wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
207 
208 	if (!wmi_handle) {
209 		target_if_err("Invalid WMI handle");
210 		return QDF_STATUS_E_FAILURE;
211 	}
212 
213 	status = wmi_unified_send_dbam_config_cmd(wmi_handle, param);
214 	if (QDF_IS_STATUS_ERROR(status))
215 		target_if_err("Failed to send DBAM config %d", status);
216 
217 	return status;
218 }
219 
220 static QDF_STATUS
target_if_dbam_register_event_handler(struct wlan_objmgr_psoc * psoc)221 target_if_dbam_register_event_handler(struct wlan_objmgr_psoc *psoc)
222 {
223 	QDF_STATUS status;
224 	wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
225 
226 	if (!wmi_handle) {
227 		target_if_err("Invalid WMI handle");
228 		return QDF_STATUS_E_INVAL;
229 	}
230 
231 	status = wmi_unified_register_event_handler(wmi_handle,
232 					wmi_coex_dbam_complete_event_id,
233 					target_if_dbam_response_event_handler,
234 					WMI_RX_WORK_CTX);
235 
236 	if (QDF_IS_STATUS_ERROR(status))
237 		target_if_err("Failed to register dbam complete event cb");
238 
239 	return status;
240 }
241 
242 static QDF_STATUS
target_if_dbam_unregister_event_handler(struct wlan_objmgr_psoc * psoc)243 target_if_dbam_unregister_event_handler(struct wlan_objmgr_psoc *psoc)
244 {
245 	wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
246 
247 	if (!wmi_handle) {
248 		target_if_err("Invalid WMI handle");
249 		return QDF_STATUS_E_INVAL;
250 	}
251 
252 	wmi_unified_unregister_event_handler(wmi_handle,
253 					     wmi_coex_dbam_complete_event_id);
254 
255 	return QDF_STATUS_SUCCESS;
256 }
257 
258 QDF_STATUS
target_if_dbam_register_tx_ops(struct wlan_lmac_if_tx_ops * tx_ops)259 target_if_dbam_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
260 {
261 	struct wlan_lmac_if_dbam_tx_ops *dbam_tx_ops;
262 
263 	if (!tx_ops) {
264 		target_if_err("target if tx ops is NULL!");
265 		return QDF_STATUS_E_INVAL;
266 	}
267 
268 	dbam_tx_ops = &tx_ops->dbam_tx_ops;
269 	if (!dbam_tx_ops) {
270 		target_if_err("target if dbam ops is NULL!");
271 		return QDF_STATUS_E_FAILURE;
272 	}
273 
274 	dbam_tx_ops->set_dbam_config = target_if_dbam_config_send;
275 	dbam_tx_ops->dbam_event_attach = target_if_dbam_register_event_handler;
276 	dbam_tx_ops->dbam_event_detach =
277 		target_if_dbam_unregister_event_handler;
278 
279 	return QDF_STATUS_SUCCESS;
280 }
281 #endif
282