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