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