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