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