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