1 /*
2  * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /**
20  * DOC: This file contains fw offload south bound interface definitions
21  */
22 
23 #include "scheduler_api.h"
24 #include "wlan_objmgr_psoc_obj.h"
25 #include "wlan_objmgr_global_obj.h"
26 #include "wlan_objmgr_pdev_obj.h"
27 #include "wlan_fwol_public_structs.h"
28 #include "wlan_fwol_ucfg_api.h"
29 #include "wlan_fwol_tgt_api.h"
30 #include "wlan_fw_offload_main.h"
31 #include "target_if.h"
32 
tgt_fwol_register_ev_handler(struct wlan_objmgr_psoc * psoc)33 QDF_STATUS tgt_fwol_register_ev_handler(struct wlan_objmgr_psoc *psoc)
34 {
35 	struct wlan_fwol_psoc_obj *fwol_obj;
36 	struct wlan_fwol_tx_ops *tx_ops;
37 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
38 
39 	if (!psoc) {
40 		fwol_err("NULL psoc handle");
41 		return QDF_STATUS_E_INVAL;
42 	}
43 
44 	fwol_obj = fwol_get_psoc_obj(psoc);
45 	if (!fwol_obj) {
46 		fwol_err("Failed to get FWOL Obj");
47 		return QDF_STATUS_E_INVAL;
48 	}
49 
50 	tx_ops = &fwol_obj->tx_ops;
51 	if (tx_ops->reg_evt_handler) {
52 		status = tx_ops->reg_evt_handler(psoc, NULL);
53 		fwol_debug("reg_evt_handler, status:%d", status);
54 	} else {
55 		fwol_alert("No reg_evt_handler");
56 	}
57 
58 	return status;
59 }
60 
tgt_fwol_unregister_ev_handler(struct wlan_objmgr_psoc * psoc)61 QDF_STATUS tgt_fwol_unregister_ev_handler(struct wlan_objmgr_psoc *psoc)
62 {
63 	struct wlan_fwol_psoc_obj *fwol_obj;
64 	struct wlan_fwol_tx_ops *tx_ops;
65 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
66 
67 	if (!psoc) {
68 		fwol_err("NNULL psoc handle");
69 		return QDF_STATUS_E_INVAL;
70 	}
71 
72 	fwol_obj = fwol_get_psoc_obj(psoc);
73 	if (!fwol_obj) {
74 		fwol_err("Failed to get FWOL Obj");
75 		return QDF_STATUS_E_INVAL;
76 	}
77 
78 	tx_ops = &fwol_obj->tx_ops;
79 	if (tx_ops->unreg_evt_handler) {
80 		status = tx_ops->unreg_evt_handler(psoc, NULL);
81 		fwol_debug("unreg_evt_handler, status:%d", status);
82 	} else {
83 		fwol_alert("No unreg_evt_handler");
84 	}
85 
86 	return status;
87 }
88 
89 /**
90  * fwol_flush_callback() - fw offload message flush callback
91  * @msg: fw offload message
92  *
93  * Return: QDF_STATUS_SUCCESS on success.
94  */
95 __attribute__((unused))
fwol_flush_callback(struct scheduler_msg * msg)96 static QDF_STATUS fwol_flush_callback(struct scheduler_msg *msg)
97 {
98 	struct wlan_fwol_rx_event *event;
99 
100 	if (!msg) {
101 		fwol_err("NULL pointer for eLNA message");
102 		return QDF_STATUS_E_INVAL;
103 	}
104 
105 	event = msg->bodyptr;
106 	msg->bodyptr = NULL;
107 	fwol_release_rx_event(event);
108 
109 	return QDF_STATUS_SUCCESS;
110 }
111 
112 #ifdef WLAN_FEATURE_ELNA
113 /**
114  * tgt_fwol_get_elna_bypass_resp() - handler for get eLNA bypass response
115  * @psoc: psoc handle
116  * @resp: status for last channel config
117  *
118  * Return: QDF_STATUS_SUCCESS on success
119  */
120 static QDF_STATUS
tgt_fwol_get_elna_bypass_resp(struct wlan_objmgr_psoc * psoc,struct get_elna_bypass_response * resp)121 tgt_fwol_get_elna_bypass_resp(struct wlan_objmgr_psoc *psoc,
122 			      struct get_elna_bypass_response *resp)
123 {
124 	QDF_STATUS status;
125 	struct scheduler_msg msg = {0};
126 	struct wlan_fwol_rx_event *event;
127 
128 	event = qdf_mem_malloc(sizeof(*event));
129 	if (!event)
130 		return QDF_STATUS_E_NOMEM;
131 
132 	status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_FWOL_SB_ID);
133 	if (QDF_IS_STATUS_ERROR(status)) {
134 		fwol_err("Failed to get psoc ref");
135 		fwol_release_rx_event(event);
136 		return status;
137 	}
138 
139 	event->psoc = psoc;
140 	event->event_id = WLAN_FWOL_EVT_GET_ELNA_BYPASS_RESPONSE;
141 	event->get_elna_bypass_response = *resp;
142 	msg.type = WLAN_FWOL_EVT_GET_ELNA_BYPASS_RESPONSE;
143 	msg.bodyptr = event;
144 	msg.callback = fwol_process_event;
145 	msg.flush_callback = fwol_flush_callback;
146 	status = scheduler_post_message(QDF_MODULE_ID_FWOL,
147 					QDF_MODULE_ID_FWOL,
148 					QDF_MODULE_ID_TARGET_IF, &msg);
149 
150 	if (QDF_IS_STATUS_SUCCESS(status))
151 		return QDF_STATUS_SUCCESS;
152 
153 	fwol_err("failed to send WLAN_FWOL_GET_ELNA_BYPASS_RESPONSE msg");
154 	fwol_flush_callback(&msg);
155 
156 	return status;
157 }
158 
tgt_fwol_register_elna_rx_ops(struct wlan_fwol_rx_ops * rx_ops)159 static void tgt_fwol_register_elna_rx_ops(struct wlan_fwol_rx_ops *rx_ops)
160 {
161 	rx_ops->get_elna_bypass_resp = tgt_fwol_get_elna_bypass_resp;
162 }
163 #else
tgt_fwol_register_elna_rx_ops(struct wlan_fwol_rx_ops * rx_ops)164 static void tgt_fwol_register_elna_rx_ops(struct wlan_fwol_rx_ops *rx_ops)
165 {
166 }
167 #endif /* WLAN_FEATURE_ELNA */
168 
169 #ifdef FW_THERMAL_THROTTLE_SUPPORT
170 /**
171  * notify_thermal_throttle_handler() - Thermal throttle stats event handler
172  * @psoc: psoc object
173  * @info: thermal throttle stats info from target if layer
174  *
175  * The handle will be registered to target if layer. Target if layer
176  * will notify the new level from firmware thermal stats event.
177  *
178  * Return: QDF_STATUS_SUCCESS for success
179  */
180 static QDF_STATUS
notify_thermal_throttle_handler(struct wlan_objmgr_psoc * psoc,struct thermal_throttle_info * info)181 notify_thermal_throttle_handler(struct wlan_objmgr_psoc *psoc,
182 				struct thermal_throttle_info *info)
183 {
184 	struct wlan_fwol_psoc_obj *fwol_obj;
185 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
186 	struct fwol_thermal_callbacks *thermal_cbs;
187 
188 	if (!psoc) {
189 		fwol_err("NULL psoc handle");
190 		return QDF_STATUS_E_INVAL;
191 	}
192 
193 	fwol_obj = fwol_get_psoc_obj(psoc);
194 	if (!fwol_obj) {
195 		fwol_err("Failed to get FWOL Obj");
196 		return QDF_STATUS_E_INVAL;
197 	}
198 	thermal_cbs = &fwol_obj->thermal_cbs;
199 	fwol_nofl_debug("thermal evt: pdev %d lvl %d",
200 			info->pdev_id, info->level);
201 	if (info->pdev_id <= fwol_obj->thermal_throttle.pdev_id ||
202 	    fwol_obj->thermal_throttle.pdev_id == WLAN_INVALID_PDEV_ID) {
203 		fwol_obj->thermal_throttle.level = info->level;
204 		fwol_obj->thermal_throttle.pdev_id = info->pdev_id;
205 		if (thermal_cbs->notify_thermal_throttle_handler)
206 			status =
207 			thermal_cbs->notify_thermal_throttle_handler(psoc,
208 								     info);
209 		else
210 			fwol_debug("no thermal throttle handler");
211 	}
212 
213 	return status;
214 }
215 #endif
216 
217 #ifdef THERMAL_STATS_SUPPORT
218 static QDF_STATUS
tgt_fwol_get_thermal_stats_resp(struct wlan_objmgr_psoc * psoc,struct thermal_throttle_info * resp)219 tgt_fwol_get_thermal_stats_resp(struct wlan_objmgr_psoc *psoc,
220 				struct thermal_throttle_info *resp)
221 {
222 	QDF_STATUS status;
223 	struct scheduler_msg msg = {0};
224 	struct wlan_fwol_rx_event *event;
225 
226 	event = qdf_mem_malloc(sizeof(*event));
227 	if (!event)
228 		return QDF_STATUS_E_NOMEM;
229 
230 	status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_FWOL_SB_ID);
231 	if (QDF_IS_STATUS_ERROR(status)) {
232 		fwol_err("Failed to get psoc ref");
233 		fwol_release_rx_event(event);
234 		return status;
235 	}
236 
237 	event->psoc = psoc;
238 	event->event_id = WLAN_FWOL_EVT_GET_THERMAL_STATS_RESPONSE;
239 	event->get_thermal_stats_response = *resp;
240 	msg.type = WLAN_FWOL_EVT_GET_THERMAL_STATS_RESPONSE;
241 	msg.bodyptr = event;
242 	msg.callback = fwol_process_event;
243 	msg.flush_callback = fwol_flush_callback;
244 	status = scheduler_post_message(QDF_MODULE_ID_FWOL,
245 					QDF_MODULE_ID_FWOL,
246 					QDF_MODULE_ID_TARGET_IF, &msg);
247 
248 	if (QDF_IS_STATUS_SUCCESS(status))
249 		return QDF_STATUS_SUCCESS;
250 
251 	fwol_err("failed to send WLAN_FWOL_EVT_GET_THERMAL_STATS_RESPONSE msg");
252 	fwol_flush_callback(&msg);
253 
254 	return status;
255 
256 }
257 #endif
258 
259 #ifdef THERMAL_STATS_SUPPORT
260 static void
tgt_fwol_register_thermal_stats_resp(struct wlan_fwol_rx_ops * rx_ops)261 tgt_fwol_register_thermal_stats_resp(struct wlan_fwol_rx_ops *rx_ops)
262 {
263 	rx_ops->get_thermal_stats_resp = tgt_fwol_get_thermal_stats_resp;
264 }
265 #else
266 static void
tgt_fwol_register_thermal_stats_resp(struct wlan_fwol_rx_ops * rx_ops)267 tgt_fwol_register_thermal_stats_resp(struct wlan_fwol_rx_ops *rx_ops)
268 {
269 }
270 #endif
271 #ifdef FW_THERMAL_THROTTLE_SUPPORT
272 static void
tgt_fwol_register_notify_thermal_throttle_evt(struct wlan_fwol_rx_ops * rx_ops)273 tgt_fwol_register_notify_thermal_throttle_evt(struct wlan_fwol_rx_ops *rx_ops)
274 {
275 	rx_ops->notify_thermal_throttle_handler =
276 					notify_thermal_throttle_handler;
277 }
278 #else
279 static void
tgt_fwol_register_notify_thermal_throttle_evt(struct wlan_fwol_rx_ops * rx_ops)280 tgt_fwol_register_notify_thermal_throttle_evt(struct wlan_fwol_rx_ops *rx_ops)
281 {
282 }
283 #endif
284 
tgt_fwol_register_thermal_rx_ops(struct wlan_fwol_rx_ops * rx_ops)285 static void tgt_fwol_register_thermal_rx_ops(struct wlan_fwol_rx_ops *rx_ops)
286 {
287 	tgt_fwol_register_notify_thermal_throttle_evt(rx_ops);
288 	tgt_fwol_register_thermal_stats_resp(rx_ops);
289 }
290 
tgt_fwol_register_rx_ops(struct wlan_fwol_rx_ops * rx_ops)291 QDF_STATUS tgt_fwol_register_rx_ops(struct wlan_fwol_rx_ops *rx_ops)
292 {
293 	tgt_fwol_register_elna_rx_ops(rx_ops);
294 	tgt_fwol_register_thermal_rx_ops(rx_ops);
295 
296 	return QDF_STATUS_SUCCESS;
297 }
298 
tgt_fwol_pdev_param_send(struct wlan_objmgr_pdev * pdev,struct pdev_params pdev_param)299 QDF_STATUS tgt_fwol_pdev_param_send(struct wlan_objmgr_pdev *pdev,
300 				    struct pdev_params pdev_param)
301 {
302 	struct wmi_unified *wmi_handle = get_wmi_unified_hdl_from_pdev(pdev);
303 
304 	if (!wmi_handle)
305 		return QDF_STATUS_E_FAILURE;
306 
307 	return wmi_unified_pdev_param_send(wmi_handle, &pdev_param,
308 					   FWOL_WILDCARD_PDEV_ID);
309 }
310 
tgt_fwol_vdev_param_send(struct wlan_objmgr_psoc * psoc,struct vdev_set_params vdev_param)311 QDF_STATUS tgt_fwol_vdev_param_send(struct wlan_objmgr_psoc *psoc,
312 				    struct vdev_set_params vdev_param)
313 {
314 	wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
315 
316 	if (!wmi_handle)
317 		return QDF_STATUS_E_FAILURE;
318 
319 	return wmi_unified_vdev_set_param_send(wmi_handle, &vdev_param);
320 }
321