xref: /wlan-dirver/qca-wifi-host-cmn/ipa/core/src/wlan_ipa_rm.c (revision 93830f424d9ddc2ed54b338975b4f4fb38ca46e6)
1 /*
2  * Copyright (c) 2013-2021 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 /* Include Files */
21 #include "qdf_delayed_work.h"
22 #include "wlan_ipa_core.h"
23 #include "wlan_ipa_main.h"
24 #include "cdp_txrx_ipa.h"
25 #include "host_diag_core_event.h"
26 #include "wlan_reg_services_api.h"
27 
28 QDF_STATUS wlan_ipa_set_perf_level(struct wlan_ipa_priv *ipa_ctx,
29 				    uint64_t tx_packets,
30 				    uint64_t rx_packets)
31 {
32 	int ret;
33 	uint32_t next_bw;
34 	uint64_t total_packets = tx_packets + rx_packets;
35 
36 	if ((!wlan_ipa_is_enabled(ipa_ctx->config)) ||
37 		(!wlan_ipa_is_clk_scaling_enabled(ipa_ctx->config)))
38 		return 0;
39 
40 	if (total_packets > (ipa_ctx->config->bus_bw_high / 2))
41 		next_bw = ipa_ctx->config->ipa_bw_high;
42 	else if (total_packets > (ipa_ctx->config->bus_bw_medium / 2))
43 		next_bw = ipa_ctx->config->ipa_bw_medium;
44 	else
45 		next_bw = ipa_ctx->config->ipa_bw_low;
46 
47 	if (ipa_ctx->curr_cons_bw != next_bw) {
48 		ipa_debug("Requesting IPA perf curr: %d, next: %d",
49 			  ipa_ctx->curr_cons_bw, next_bw);
50 		ret = cdp_ipa_set_perf_level(ipa_ctx->dp_soc,
51 					     QDF_IPA_CLIENT_WLAN1_CONS,
52 					     next_bw, ipa_ctx->hdl);
53 		if (ret) {
54 			ipa_err("RM CONS set perf profile failed: %d", ret);
55 
56 			return QDF_STATUS_E_FAILURE;
57 		}
58 		ret = cdp_ipa_set_perf_level(ipa_ctx->dp_soc,
59 					     QDF_IPA_CLIENT_WLAN1_PROD,
60 					     next_bw, ipa_ctx->hdl);
61 		if (ret) {
62 			ipa_err("RM PROD set perf profile failed: %d", ret);
63 			return QDF_STATUS_E_FAILURE;
64 		}
65 		ipa_ctx->curr_cons_bw = next_bw;
66 		ipa_ctx->stats.num_cons_perf_req++;
67 	}
68 
69 	return QDF_STATUS_SUCCESS;
70 }
71 
72 #ifdef QCA_IPA_LL_TX_FLOW_CONTROL
73 static inline
74 QDF_STATUS wlan_ipa_update_perf_level(struct wlan_ipa_priv *ipa_ctx, int client)
75 {
76 	struct wlan_objmgr_pdev *pdev = ipa_ctx->pdev;
77 	qdf_freq_t low_2g, high_2g;
78 
79 	wlan_reg_get_freq_range(pdev, &low_2g, &high_2g, NULL, NULL);
80 
81 	if (low_2g != 0 || high_2g != 0) {
82 		return cdp_ipa_set_perf_level(
83 				ipa_ctx->dp_soc,
84 				client,
85 				WLAN_IPA_MAX_BANDWIDTH_2G, ipa_ctx->hdl);
86 	} else {
87 		return cdp_ipa_set_perf_level(
88 				ipa_ctx->dp_soc,
89 				client,
90 				WLAN_IPA_MAX_BANDWIDTH, ipa_ctx->hdl);
91 	}
92 }
93 #else
94 static inline
95 QDF_STATUS wlan_ipa_update_perf_level(struct wlan_ipa_priv *ipa_ctx, int client)
96 {
97 	uint32_t bw;
98 
99 	if (ipa_ctx->opt_wifi_datapath)
100 		bw = WLAN_IPA_MAX_BANDWIDTH;
101 	else
102 		bw = WLAN_IPA_MAX_BW_NOMINAL;
103 
104 	return cdp_ipa_set_perf_level(ipa_ctx->dp_soc, client, bw,
105 				      ipa_ctx->hdl);
106 }
107 #endif
108 
109 QDF_STATUS wlan_ipa_init_perf_level(struct wlan_ipa_priv *ipa_ctx)
110 {
111 	int ret;
112 
113 	/* Set lowest bandwidth to start with */
114 	if (wlan_ipa_is_clk_scaling_enabled(ipa_ctx->config))
115 		return wlan_ipa_set_perf_level(ipa_ctx, 0, 0);
116 
117 	ipa_debug("IPA clk scaling disabled. Set perf level to maximum %d",
118 		  WLAN_IPA_MAX_BANDWIDTH);
119 
120 	ret = wlan_ipa_update_perf_level(ipa_ctx, QDF_IPA_CLIENT_WLAN1_CONS);
121 	if (ret) {
122 		ipa_err("CONS set perf profile failed: %d", ret);
123 		return QDF_STATUS_E_FAILURE;
124 	}
125 
126 	ret = wlan_ipa_update_perf_level(ipa_ctx, QDF_IPA_CLIENT_WLAN1_PROD);
127 	if (ret) {
128 		ipa_err("PROD set perf profile failed: %d", ret);
129 		return QDF_STATUS_E_FAILURE;
130 	}
131 
132 	return QDF_STATUS_SUCCESS;
133 }
134 
135 #ifdef FEATURE_METERING
136 void wlan_ipa_init_metering(struct wlan_ipa_priv *ipa_ctx)
137 {
138 	qdf_event_create(&ipa_ctx->ipa_uc_sharing_stats_comp);
139 	qdf_event_create(&ipa_ctx->ipa_uc_set_quota_comp);
140 }
141 #endif
142 
143 #ifdef IPA_OPT_WIFI_DP
144 void wlan_ipa_add_rem_flt_cb_event(struct wlan_ipa_priv *ipa_ctx)
145 {
146 	qdf_event_create(&ipa_ctx->ipa_flt_evnt);
147 }
148 #endif
149 
150 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) && \
151 	!defined(CONFIG_IPA_WDI_UNIFIED_API)
152 /**
153  * wlan_ipa_rm_cons_release() - WLAN consumer resource release handler
154  *
155  * Callback function registered with IPA that is called when IPA wants
156  * to release the WLAN consumer resource
157  *
158  * Return: 0 if the request is granted, negative errno otherwise
159  */
160 static int wlan_ipa_rm_cons_release(void)
161 {
162 	return 0;
163 }
164 
165 /**
166  * wlan_ipa_wdi_rm_request() - Request resource from IPA
167  * @ipa_ctx: IPA context
168  *
169  * Return: QDF_STATUS
170  */
171 QDF_STATUS wlan_ipa_wdi_rm_request(struct wlan_ipa_priv *ipa_ctx)
172 {
173 	int ret;
174 
175 	if (!wlan_ipa_is_rm_enabled(ipa_ctx->config))
176 		return QDF_STATUS_SUCCESS;
177 
178 	qdf_spin_lock_bh(&ipa_ctx->rm_lock);
179 
180 	switch (ipa_ctx->rm_state) {
181 	case WLAN_IPA_RM_GRANTED:
182 		qdf_spin_unlock_bh(&ipa_ctx->rm_lock);
183 		return QDF_STATUS_SUCCESS;
184 	case WLAN_IPA_RM_GRANT_PENDING:
185 		qdf_spin_unlock_bh(&ipa_ctx->rm_lock);
186 		return QDF_STATUS_E_PENDING;
187 	case WLAN_IPA_RM_RELEASED:
188 		ipa_ctx->rm_state = WLAN_IPA_RM_GRANT_PENDING;
189 		break;
190 	}
191 
192 	qdf_spin_unlock_bh(&ipa_ctx->rm_lock);
193 
194 	ret = qdf_ipa_rm_inactivity_timer_request_resource(
195 			QDF_IPA_RM_RESOURCE_WLAN_PROD);
196 
197 	qdf_spin_lock_bh(&ipa_ctx->rm_lock);
198 	if (ret == 0) {
199 		ipa_ctx->rm_state = WLAN_IPA_RM_GRANTED;
200 		ipa_ctx->stats.num_rm_grant_imm++;
201 	}
202 
203 	if (ipa_ctx->wake_lock_released) {
204 		qdf_wake_lock_acquire(&ipa_ctx->wake_lock,
205 				      WIFI_POWER_EVENT_WAKELOCK_IPA);
206 		ipa_ctx->wake_lock_released = false;
207 	}
208 	qdf_spin_unlock_bh(&ipa_ctx->rm_lock);
209 
210 	qdf_delayed_work_stop_sync(&ipa_ctx->wake_lock_work);
211 
212 	return QDF_STATUS_SUCCESS;
213 }
214 
215 QDF_STATUS wlan_ipa_wdi_rm_try_release(struct wlan_ipa_priv *ipa_ctx)
216 {
217 	int ret;
218 
219 	if (!wlan_ipa_is_rm_enabled(ipa_ctx->config))
220 		return QDF_STATUS_SUCCESS;
221 
222 	if (qdf_atomic_read(&ipa_ctx->tx_ref_cnt))
223 		return QDF_STATUS_E_AGAIN;
224 
225 	qdf_spin_lock_bh(&ipa_ctx->pm_lock);
226 
227 	if (!qdf_nbuf_is_queue_empty(&ipa_ctx->pm_queue_head)) {
228 		qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
229 		return QDF_STATUS_E_AGAIN;
230 	}
231 	qdf_spin_unlock_bh(&ipa_ctx->pm_lock);
232 
233 	qdf_spin_lock_bh(&ipa_ctx->rm_lock);
234 	switch (ipa_ctx->rm_state) {
235 	case WLAN_IPA_RM_GRANTED:
236 		break;
237 	case WLAN_IPA_RM_GRANT_PENDING:
238 		qdf_spin_unlock_bh(&ipa_ctx->rm_lock);
239 		return QDF_STATUS_E_PENDING;
240 	case WLAN_IPA_RM_RELEASED:
241 		qdf_spin_unlock_bh(&ipa_ctx->rm_lock);
242 		return QDF_STATUS_SUCCESS;
243 	}
244 
245 	/* IPA driver returns immediately so set the state here to avoid any
246 	 * race condition.
247 	 */
248 	ipa_ctx->rm_state = WLAN_IPA_RM_RELEASED;
249 	ipa_ctx->stats.num_rm_release++;
250 	qdf_spin_unlock_bh(&ipa_ctx->rm_lock);
251 
252 	ret = qdf_ipa_rm_inactivity_timer_release_resource(
253 				QDF_IPA_RM_RESOURCE_WLAN_PROD);
254 
255 	if (qdf_unlikely(ret != 0)) {
256 		qdf_spin_lock_bh(&ipa_ctx->rm_lock);
257 		ipa_ctx->rm_state = WLAN_IPA_RM_GRANTED;
258 		qdf_spin_unlock_bh(&ipa_ctx->rm_lock);
259 		QDF_ASSERT(0);
260 		ipa_warn("rm_inactivity_timer_release_resource ret fail");
261 	}
262 
263 	/*
264 	 * If wake_lock is released immediately, kernel would try to suspend
265 	 * immediately as well, Just avoid ping-pong between suspend-resume
266 	 * while there is healthy amount of data transfer going on by
267 	 * releasing the wake_lock after some delay.
268 	 */
269 	qdf_delayed_work_start(&ipa_ctx->wake_lock_work,
270 			       WLAN_IPA_RX_INACTIVITY_MSEC_DELAY);
271 
272 	return QDF_STATUS_SUCCESS;
273 }
274 
275 /**
276  * wlan_ipa_uc_rm_notify_handler() - IPA uC resource notification handler
277  * @ipa_ctx: IPA context
278  * @event: IPA RM event
279  *
280  * Return: None
281  */
282 static void
283 wlan_ipa_uc_rm_notify_handler(struct wlan_ipa_priv *ipa_ctx,
284 			      qdf_ipa_rm_event_t event)
285 {
286 	if (!wlan_ipa_is_rm_enabled(ipa_ctx->config))
287 		return;
288 
289 	ipa_debug("event code %d", event);
290 
291 	switch (event) {
292 	case QDF_IPA_RM_RESOURCE_GRANTED:
293 		/* Differed RM Granted */
294 		qdf_mutex_acquire(&ipa_ctx->ipa_lock);
295 		if ((!ipa_ctx->resource_unloading) &&
296 		    (!ipa_ctx->activated_fw_pipe)) {
297 			wlan_ipa_uc_enable_pipes(ipa_ctx);
298 			ipa_ctx->resource_loading = false;
299 		}
300 		qdf_mutex_release(&ipa_ctx->ipa_lock);
301 		break;
302 
303 	case QDF_IPA_RM_RESOURCE_RELEASED:
304 		/* Differed RM Released */
305 		ipa_ctx->resource_unloading = false;
306 		break;
307 
308 	default:
309 		ipa_err("invalid event code %d", event);
310 		break;
311 	}
312 }
313 
314 /**
315  * wlan_ipa_uc_rm_notify_defer() - Defer IPA uC notification
316  * * @data: IPA context
317  *
318  * This function is called when a resource manager event is received
319  * from firmware in interrupt context.  This function will defer the
320  * handling to the OL RX thread
321  *
322  * Return: None
323  */
324 static void wlan_ipa_uc_rm_notify_defer(void *data)
325 {
326 	struct wlan_ipa_priv *ipa_ctx = data;
327 	qdf_ipa_rm_event_t event;
328 	struct uc_rm_work_struct *uc_rm_work = &ipa_ctx->uc_rm_work;
329 
330 	event = uc_rm_work->event;
331 
332 	wlan_ipa_uc_rm_notify_handler(ipa_ctx, event);
333 }
334 
335 /**
336  * wlan_ipa_wake_lock_timer_func() - Wake lock work handler
337  * @data: IPA context
338  *
339  * When IPA resources are released in wlan_ipa_wdi_rm_try_release() we do
340  * not want to immediately release the wake lock since the system
341  * would then potentially try to suspend when there is a healthy data
342  * rate.  Deferred work is scheduled and this function handles the
343  * work.  When this function is called, if the IPA resource is still
344  * released then we release the wake lock.
345  *
346  * Return: None
347  */
348 static void wlan_ipa_wake_lock_timer_func(void *data)
349 {
350 	struct wlan_ipa_priv *ipa_ctx = data;
351 
352 	qdf_spin_lock_bh(&ipa_ctx->rm_lock);
353 
354 	if (ipa_ctx->rm_state != WLAN_IPA_RM_RELEASED)
355 		goto end;
356 
357 	ipa_ctx->wake_lock_released = true;
358 	qdf_wake_lock_release(&ipa_ctx->wake_lock,
359 			      WIFI_POWER_EVENT_WAKELOCK_IPA);
360 
361 end:
362 	qdf_spin_unlock_bh(&ipa_ctx->rm_lock);
363 }
364 
365 /**
366  * wlan_ipa_rm_cons_request() - WLAN consumer resource request handler
367  *
368  * Callback function registered with IPA that is called when IPA wants
369  * to access the WLAN consumer resource
370  *
371  * Return: 0 if the request is granted, negative errno otherwise
372  */
373 static int wlan_ipa_rm_cons_request(void)
374 {
375 	struct wlan_ipa_priv *ipa_ctx;
376 	QDF_STATUS status = QDF_STATUS_SUCCESS;
377 
378 	ipa_ctx = wlan_ipa_get_obj_context();
379 
380 	if (ipa_ctx->resource_loading) {
381 		ipa_err("IPA resource loading in progress");
382 		ipa_ctx->pending_cons_req = true;
383 		status = QDF_STATUS_E_PENDING;
384 	} else if (ipa_ctx->resource_unloading) {
385 		ipa_err("IPA resource unloading in progress");
386 		ipa_ctx->pending_cons_req = true;
387 		status = QDF_STATUS_E_PERM;
388 	}
389 
390 	return qdf_status_to_os_return(status);
391 }
392 
393 /**
394  * wlan_ipa_rm_notify() - IPA resource manager notifier callback
395  * @user_data: user data registered with IPA
396  * @event: the IPA resource manager event that occurred
397  * @data: the data associated with the event
398  *
399  * Return: None
400  */
401 static void wlan_ipa_rm_notify(void *user_data, qdf_ipa_rm_event_t event,
402 			       unsigned long data)
403 {
404 	struct wlan_ipa_priv *ipa_ctx = user_data;
405 
406 	if (qdf_unlikely(!ipa_ctx))
407 		return;
408 
409 	if (!wlan_ipa_is_rm_enabled(ipa_ctx->config))
410 		return;
411 
412 	ipa_debug("Evt: %d", event);
413 
414 	switch (event) {
415 	case QDF_IPA_RM_RESOURCE_GRANTED:
416 		if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
417 			/* RM Notification comes with ISR context
418 			 * it should be serialized into work queue to avoid
419 			 * ISR sleep problem
420 			 */
421 			ipa_ctx->uc_rm_work.event = event;
422 			qdf_sched_work(0, &ipa_ctx->uc_rm_work.work);
423 			break;
424 		}
425 		qdf_spin_lock_bh(&ipa_ctx->rm_lock);
426 		ipa_ctx->rm_state = WLAN_IPA_RM_GRANTED;
427 		qdf_spin_unlock_bh(&ipa_ctx->rm_lock);
428 		ipa_ctx->stats.num_rm_grant++;
429 		break;
430 
431 	case QDF_IPA_RM_RESOURCE_RELEASED:
432 		ipa_debug("RM Release");
433 		ipa_ctx->resource_unloading = false;
434 		break;
435 
436 	default:
437 		ipa_err("Unknown RM Evt: %d", event);
438 		break;
439 	}
440 }
441 
442 QDF_STATUS wlan_ipa_wdi_setup_rm(struct wlan_ipa_priv *ipa_ctx)
443 {
444 	qdf_ipa_rm_create_params_t create_params;
445 	QDF_STATUS status;
446 	int ret;
447 
448 	if (!wlan_ipa_is_rm_enabled(ipa_ctx->config))
449 		return 0;
450 
451 	qdf_create_work(0, &ipa_ctx->uc_rm_work.work,
452 			wlan_ipa_uc_rm_notify_defer, ipa_ctx);
453 	qdf_mem_zero(&create_params, sizeof(create_params));
454 	create_params.name = QDF_IPA_RM_RESOURCE_WLAN_PROD;
455 	create_params.reg_params.user_data = ipa_ctx;
456 	create_params.reg_params.notify_cb = wlan_ipa_rm_notify;
457 	create_params.floor_voltage = QDF_IPA_VOLTAGE_LEVEL;
458 
459 	ret = qdf_ipa_rm_create_resource(&create_params);
460 	if (ret) {
461 		ipa_err("Create RM resource failed: %d", ret);
462 		goto setup_rm_fail;
463 	}
464 
465 	qdf_mem_zero(&create_params, sizeof(create_params));
466 	create_params.name = QDF_IPA_RM_RESOURCE_WLAN_CONS;
467 	create_params.request_resource = wlan_ipa_rm_cons_request;
468 	create_params.release_resource = wlan_ipa_rm_cons_release;
469 	create_params.floor_voltage = QDF_IPA_VOLTAGE_LEVEL;
470 
471 	ret = qdf_ipa_rm_create_resource(&create_params);
472 	if (ret) {
473 		ipa_err("Create RM CONS resource failed: %d", ret);
474 		goto delete_prod;
475 	}
476 
477 	qdf_ipa_rm_add_dependency(QDF_IPA_RM_RESOURCE_WLAN_PROD,
478 				  QDF_IPA_RM_RESOURCE_APPS_CONS);
479 
480 	ret = qdf_ipa_rm_inactivity_timer_init(QDF_IPA_RM_RESOURCE_WLAN_PROD,
481 					WLAN_IPA_RX_INACTIVITY_MSEC_DELAY);
482 	if (ret) {
483 		ipa_err("Timer init failed: %d", ret);
484 		goto timer_init_failed;
485 	}
486 
487 	status = qdf_delayed_work_create(&ipa_ctx->wake_lock_work,
488 					 wlan_ipa_wake_lock_timer_func,
489 					 ipa_ctx);
490 	if (QDF_IS_STATUS_ERROR(status))
491 		goto timer_destroy;
492 
493 	qdf_wake_lock_create(&ipa_ctx->wake_lock, "wlan_ipa");
494 	qdf_spinlock_create(&ipa_ctx->rm_lock);
495 	ipa_ctx->rm_state = WLAN_IPA_RM_RELEASED;
496 	ipa_ctx->wake_lock_released = true;
497 	qdf_atomic_set(&ipa_ctx->tx_ref_cnt, 0);
498 
499 	return QDF_STATUS_SUCCESS;
500 
501 timer_destroy:
502 	qdf_ipa_rm_inactivity_timer_destroy(QDF_IPA_RM_RESOURCE_WLAN_PROD);
503 
504 timer_init_failed:
505 	qdf_ipa_rm_delete_resource(QDF_IPA_RM_RESOURCE_APPS_CONS);
506 
507 delete_prod:
508 	qdf_ipa_rm_delete_resource(QDF_IPA_RM_RESOURCE_WLAN_PROD);
509 
510 setup_rm_fail:
511 	return QDF_STATUS_E_FAILURE;
512 }
513 
514 void wlan_ipa_wdi_destroy_rm(struct wlan_ipa_priv *ipa_ctx)
515 {
516 	int ret;
517 
518 	if (!wlan_ipa_is_rm_enabled(ipa_ctx->config))
519 		return;
520 
521 	qdf_wake_lock_destroy(&ipa_ctx->wake_lock);
522 	qdf_delayed_work_destroy(&ipa_ctx->wake_lock_work);
523 	qdf_cancel_work(&ipa_ctx->uc_rm_work.work);
524 	qdf_spinlock_destroy(&ipa_ctx->rm_lock);
525 
526 	qdf_ipa_rm_inactivity_timer_destroy(QDF_IPA_RM_RESOURCE_WLAN_PROD);
527 
528 	ret = qdf_ipa_rm_delete_resource(QDF_IPA_RM_RESOURCE_WLAN_CONS);
529 	if (ret)
530 		ipa_err("RM CONS resource delete failed %d", ret);
531 
532 	ret = qdf_ipa_rm_delete_resource(QDF_IPA_RM_RESOURCE_WLAN_PROD);
533 	if (ret)
534 		ipa_err("RM PROD resource delete failed %d", ret);
535 }
536 
537 bool wlan_ipa_is_rm_released(struct wlan_ipa_priv *ipa_ctx)
538 {
539 	qdf_spin_lock_bh(&ipa_ctx->rm_lock);
540 
541 	if (ipa_ctx->rm_state != WLAN_IPA_RM_RELEASED) {
542 		qdf_spin_unlock_bh(&ipa_ctx->rm_lock);
543 		return false;
544 	}
545 
546 	qdf_spin_unlock_bh(&ipa_ctx->rm_lock);
547 
548 	return true;
549 }
550 #endif /* CONFIG_IPA_WDI_UNIFIED_API */
551