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