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