1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 /* 3 * Copyright (C) 2012-2014, 2019-2022, 2024-2025 Intel Corporation 4 * Copyright (C) 2013-2014 Intel Mobile Communications GmbH 5 * Copyright (C) 2015-2016 Intel Deutschland GmbH 6 */ 7 #ifdef CONFIG_THERMAL 8 #include <linux/sort.h> 9 #endif 10 11 #include "mvm.h" 12 13 #define IWL_MVM_NUM_CTDP_STEPS 20 14 #define IWL_MVM_MIN_CTDP_BUDGET_MW 150 15 16 #define IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT HZ 17 18 void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm) 19 { 20 struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle; 21 u32 duration = tt->params.ct_kill_duration; 22 23 if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) 24 return; 25 26 IWL_ERR(mvm, "Enter CT Kill\n"); 27 iwl_mvm_set_hw_ctkill_state(mvm, true); 28 29 if (!iwl_mvm_is_tt_in_fw(mvm)) { 30 tt->throttle = false; 31 tt->dynamic_smps = false; 32 } 33 34 /* Don't schedule an exit work if we're in test mode, since 35 * the temperature will not change unless we manually set it 36 * again (or disable testing). 37 */ 38 if (!mvm->temperature_test) 39 schedule_delayed_work(&tt->ct_kill_exit, 40 round_jiffies_relative(duration * HZ)); 41 } 42 43 static void iwl_mvm_exit_ctkill(struct iwl_mvm *mvm) 44 { 45 if (!test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) 46 return; 47 48 IWL_ERR(mvm, "Exit CT Kill\n"); 49 iwl_mvm_set_hw_ctkill_state(mvm, false); 50 } 51 52 static void iwl_mvm_tt_temp_changed(struct iwl_mvm *mvm, u32 temp) 53 { 54 /* ignore the notification if we are in test mode */ 55 if (mvm->temperature_test) 56 return; 57 58 if (mvm->temperature == temp) 59 return; 60 61 mvm->temperature = temp; 62 iwl_mvm_tt_handler(mvm); 63 } 64 65 static int iwl_mvm_temp_notif_parse(struct iwl_mvm *mvm, 66 struct iwl_rx_packet *pkt) 67 { 68 struct iwl_dts_measurement_notif_v1 *notif_v1; 69 int len = iwl_rx_packet_payload_len(pkt); 70 int temp; 71 72 /* we can use notif_v1 only, because v2 only adds an additional 73 * parameter, which is not used in this function. 74 */ 75 if (WARN_ON_ONCE(len < sizeof(*notif_v1))) { 76 IWL_ERR(mvm, "Invalid DTS_MEASUREMENT_NOTIFICATION\n"); 77 return -EINVAL; 78 } 79 80 notif_v1 = (void *)pkt->data; 81 82 temp = le32_to_cpu(notif_v1->temp); 83 84 /* shouldn't be negative, but since it's s32, make sure it isn't */ 85 if (WARN_ON_ONCE(temp < 0)) 86 temp = 0; 87 88 IWL_DEBUG_TEMP(mvm, "DTS_MEASUREMENT_NOTIFICATION - %d\n", temp); 89 90 return temp; 91 } 92 93 static bool iwl_mvm_temp_notif_wait(struct iwl_notif_wait_data *notif_wait, 94 struct iwl_rx_packet *pkt, void *data) 95 { 96 struct iwl_mvm *mvm = 97 container_of(notif_wait, struct iwl_mvm, notif_wait); 98 int *temp = data; 99 int ret; 100 101 ret = iwl_mvm_temp_notif_parse(mvm, pkt); 102 if (ret < 0) 103 return true; 104 105 *temp = ret; 106 107 return true; 108 } 109 110 void iwl_mvm_temp_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) 111 { 112 struct iwl_rx_packet *pkt = rxb_addr(rxb); 113 struct iwl_dts_measurement_notif *notif_v2; 114 int len = iwl_rx_packet_payload_len(pkt); 115 int temp; 116 u32 ths_crossed; 117 118 /* the notification is handled synchronously in ctkill, so skip here */ 119 if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) 120 return; 121 122 temp = iwl_mvm_temp_notif_parse(mvm, pkt); 123 124 if (!iwl_mvm_is_tt_in_fw(mvm)) { 125 if (temp >= 0) 126 iwl_mvm_tt_temp_changed(mvm, temp); 127 return; 128 } 129 130 if (WARN_ON_ONCE(len < sizeof(*notif_v2))) { 131 IWL_ERR(mvm, "Invalid DTS_MEASUREMENT_NOTIFICATION\n"); 132 return; 133 } 134 135 notif_v2 = (void *)pkt->data; 136 ths_crossed = le32_to_cpu(notif_v2->threshold_idx); 137 138 /* 0xFF in ths_crossed means the notification is not related 139 * to a trip, so we can ignore it here. 140 */ 141 if (ths_crossed == 0xFF) 142 return; 143 144 IWL_DEBUG_TEMP(mvm, "Temp = %d Threshold crossed = %d\n", 145 temp, ths_crossed); 146 147 #ifdef CONFIG_THERMAL 148 if (WARN_ON(ths_crossed >= IWL_MAX_DTS_TRIPS)) 149 return; 150 151 if (mvm->tz_device.tzone) { 152 struct iwl_mvm_thermal_device *tz_dev = &mvm->tz_device; 153 154 thermal_zone_device_update(tz_dev->tzone, 155 THERMAL_TRIP_VIOLATED); 156 } 157 #endif /* CONFIG_THERMAL */ 158 } 159 160 void iwl_mvm_ct_kill_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) 161 { 162 struct iwl_rx_packet *pkt = rxb_addr(rxb); 163 struct ct_kill_notif *notif; 164 165 notif = (struct ct_kill_notif *)pkt->data; 166 IWL_DEBUG_TEMP(mvm, "CT Kill notification temperature = %d\n", 167 notif->temperature); 168 if (iwl_fw_lookup_notif_ver(mvm->fw, PHY_OPS_GROUP, 169 CT_KILL_NOTIFICATION, 0) > 1) 170 IWL_DEBUG_TEMP(mvm, 171 "CT kill notification DTS bitmap = 0x%x, Scheme = %d\n", 172 notif->dts, notif->scheme); 173 174 iwl_mvm_enter_ctkill(mvm); 175 } 176 177 /* 178 * send the DTS_MEASUREMENT_TRIGGER command with or without waiting for a 179 * response. If we get a response then the measurement is stored in 'temp' 180 */ 181 static int iwl_mvm_send_temp_cmd(struct iwl_mvm *mvm, bool response, s32 *temp) 182 { 183 struct iwl_host_cmd cmd = {}; 184 struct iwl_dts_measurement_cmd dts_cmd = { 185 .flags = cpu_to_le32(DTS_TRIGGER_CMD_FLAGS_TEMP), 186 }; 187 struct iwl_ext_dts_measurement_cmd ext_cmd = { 188 .control_mode = cpu_to_le32(DTS_DIRECT_WITHOUT_MEASURE), 189 }; 190 struct iwl_dts_measurement_resp *resp; 191 void *cmd_ptr; 192 int ret; 193 u32 cmd_flags = 0; 194 u16 len; 195 196 /* Check which command format is used (regular/extended) */ 197 if (fw_has_capa(&mvm->fw->ucode_capa, 198 IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE)) { 199 len = sizeof(ext_cmd); 200 cmd_ptr = &ext_cmd; 201 } else { 202 len = sizeof(dts_cmd); 203 cmd_ptr = &dts_cmd; 204 } 205 /* The command version where we get a response is zero length */ 206 if (response) { 207 cmd_flags = CMD_WANT_SKB; 208 len = 0; 209 } 210 211 cmd.id = WIDE_ID(PHY_OPS_GROUP, CMD_DTS_MEASUREMENT_TRIGGER_WIDE); 212 cmd.len[0] = len; 213 cmd.flags = cmd_flags; 214 cmd.data[0] = cmd_ptr; 215 216 IWL_DEBUG_TEMP(mvm, 217 "Sending temperature measurement command - %s response\n", 218 response ? "with" : "without"); 219 ret = iwl_mvm_send_cmd(mvm, &cmd); 220 221 if (ret) { 222 IWL_ERR(mvm, 223 "Failed to send the temperature measurement command (err=%d)\n", 224 ret); 225 return ret; 226 } 227 228 if (response) { 229 resp = (void *)cmd.resp_pkt->data; 230 *temp = le32_to_cpu(resp->temp); 231 IWL_DEBUG_TEMP(mvm, 232 "Got temperature measurement response: temp=%d\n", 233 *temp); 234 iwl_free_resp(&cmd); 235 } 236 237 return ret; 238 } 239 240 int iwl_mvm_get_temp(struct iwl_mvm *mvm, s32 *temp) 241 { 242 struct iwl_notification_wait wait_temp_notif; 243 static u16 temp_notif[] = { WIDE_ID(PHY_OPS_GROUP, 244 DTS_MEASUREMENT_NOTIF_WIDE) }; 245 int ret; 246 u8 cmd_ver; 247 248 /* 249 * If command version is 1 we send the command and immediately get 250 * a response. For older versions we send the command and wait for a 251 * notification (no command TLV for previous versions). 252 */ 253 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, 254 WIDE_ID(PHY_OPS_GROUP, CMD_DTS_MEASUREMENT_TRIGGER_WIDE), 255 IWL_FW_CMD_VER_UNKNOWN); 256 if (cmd_ver == 1) 257 return iwl_mvm_send_temp_cmd(mvm, true, temp); 258 259 lockdep_assert_held(&mvm->mutex); 260 261 iwl_init_notification_wait(&mvm->notif_wait, &wait_temp_notif, 262 temp_notif, ARRAY_SIZE(temp_notif), 263 iwl_mvm_temp_notif_wait, temp); 264 265 ret = iwl_mvm_send_temp_cmd(mvm, false, temp); 266 if (ret) { 267 iwl_remove_notification(&mvm->notif_wait, &wait_temp_notif); 268 return ret; 269 } 270 271 ret = iwl_wait_notification(&mvm->notif_wait, &wait_temp_notif, 272 IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT); 273 if (ret) 274 IWL_WARN(mvm, "Getting the temperature timed out\n"); 275 276 return ret; 277 } 278 279 static void check_exit_ctkill(struct work_struct *work) 280 { 281 struct iwl_mvm_tt_mgmt *tt; 282 struct iwl_mvm *mvm; 283 u32 duration; 284 s32 temp; 285 int ret; 286 287 tt = container_of(work, struct iwl_mvm_tt_mgmt, ct_kill_exit.work); 288 mvm = container_of(tt, struct iwl_mvm, thermal_throttle); 289 290 if (iwl_mvm_is_tt_in_fw(mvm)) { 291 iwl_mvm_exit_ctkill(mvm); 292 293 return; 294 } 295 296 duration = tt->params.ct_kill_duration; 297 298 flush_work(&mvm->roc_done_wk); 299 300 mutex_lock(&mvm->mutex); 301 302 if (__iwl_mvm_mac_start(mvm)) 303 goto reschedule; 304 305 ret = iwl_mvm_get_temp(mvm, &temp); 306 307 __iwl_mvm_mac_stop(mvm, false); 308 309 if (ret) 310 goto reschedule; 311 312 IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", temp); 313 314 if (temp <= tt->params.ct_kill_exit) { 315 mutex_unlock(&mvm->mutex); 316 iwl_mvm_exit_ctkill(mvm); 317 return; 318 } 319 320 reschedule: 321 mutex_unlock(&mvm->mutex); 322 schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit, 323 round_jiffies(duration * HZ)); 324 } 325 326 static void iwl_mvm_tt_smps_iterator(void *_data, u8 *mac, 327 struct ieee80211_vif *vif) 328 { 329 struct iwl_mvm *mvm = _data; 330 enum ieee80211_smps_mode smps_mode; 331 332 lockdep_assert_held(&mvm->mutex); 333 334 if (mvm->thermal_throttle.dynamic_smps) 335 smps_mode = IEEE80211_SMPS_DYNAMIC; 336 else 337 smps_mode = IEEE80211_SMPS_AUTOMATIC; 338 339 if (vif->type != NL80211_IFTYPE_STATION) 340 return; 341 342 iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_TT, smps_mode, 0); 343 } 344 345 static void iwl_mvm_tt_tx_protection(struct iwl_mvm *mvm, bool enable) 346 { 347 struct iwl_mvm_sta *mvmsta; 348 int i, err; 349 350 for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) { 351 mvmsta = iwl_mvm_sta_from_staid_protected(mvm, i); 352 if (!mvmsta) 353 continue; 354 355 if (enable == mvmsta->tt_tx_protection) 356 continue; 357 err = iwl_mvm_tx_protection(mvm, mvmsta, enable); 358 if (err) { 359 IWL_ERR(mvm, "Failed to %s Tx protection\n", 360 enable ? "enable" : "disable"); 361 } else { 362 IWL_DEBUG_TEMP(mvm, "%s Tx protection\n", 363 enable ? "Enable" : "Disable"); 364 mvmsta->tt_tx_protection = enable; 365 } 366 } 367 } 368 369 void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff) 370 { 371 struct iwl_host_cmd cmd = { 372 .id = REPLY_THERMAL_MNG_BACKOFF, 373 .len = { sizeof(u32), }, 374 .data = { &backoff, }, 375 }; 376 377 backoff = max(backoff, mvm->thermal_throttle.min_backoff); 378 379 if (iwl_mvm_send_cmd(mvm, &cmd) == 0) { 380 IWL_DEBUG_TEMP(mvm, "Set Thermal Tx backoff to: %u\n", 381 backoff); 382 mvm->thermal_throttle.tx_backoff = backoff; 383 } else { 384 IWL_ERR(mvm, "Failed to change Thermal Tx backoff\n"); 385 } 386 } 387 388 void iwl_mvm_tt_handler(struct iwl_mvm *mvm) 389 { 390 struct iwl_tt_params *params = &mvm->thermal_throttle.params; 391 struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle; 392 s32 temperature = mvm->temperature; 393 bool throttle_enable = false; 394 int i; 395 u32 tx_backoff; 396 397 IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", mvm->temperature); 398 399 if (params->support_ct_kill && temperature >= params->ct_kill_entry) { 400 iwl_mvm_enter_ctkill(mvm); 401 return; 402 } 403 404 if (params->support_ct_kill && 405 temperature <= params->ct_kill_exit) { 406 iwl_mvm_exit_ctkill(mvm); 407 return; 408 } 409 410 if (params->support_dynamic_smps) { 411 if (!tt->dynamic_smps && 412 temperature >= params->dynamic_smps_entry) { 413 IWL_DEBUG_TEMP(mvm, "Enable dynamic SMPS\n"); 414 tt->dynamic_smps = true; 415 ieee80211_iterate_active_interfaces_atomic( 416 mvm->hw, IEEE80211_IFACE_ITER_NORMAL, 417 iwl_mvm_tt_smps_iterator, mvm); 418 throttle_enable = true; 419 } else if (tt->dynamic_smps && 420 temperature <= params->dynamic_smps_exit) { 421 IWL_DEBUG_TEMP(mvm, "Disable dynamic SMPS\n"); 422 tt->dynamic_smps = false; 423 ieee80211_iterate_active_interfaces_atomic( 424 mvm->hw, IEEE80211_IFACE_ITER_NORMAL, 425 iwl_mvm_tt_smps_iterator, mvm); 426 } 427 } 428 429 if (params->support_tx_protection) { 430 if (temperature >= params->tx_protection_entry) { 431 iwl_mvm_tt_tx_protection(mvm, true); 432 throttle_enable = true; 433 } else if (temperature <= params->tx_protection_exit) { 434 iwl_mvm_tt_tx_protection(mvm, false); 435 } 436 } 437 438 if (params->support_tx_backoff) { 439 tx_backoff = tt->min_backoff; 440 for (i = 0; i < TT_TX_BACKOFF_SIZE; i++) { 441 if (temperature < params->tx_backoff[i].temperature) 442 break; 443 tx_backoff = max(tt->min_backoff, 444 params->tx_backoff[i].backoff); 445 } 446 if (tx_backoff != tt->min_backoff) 447 throttle_enable = true; 448 if (tt->tx_backoff != tx_backoff) 449 iwl_mvm_tt_tx_backoff(mvm, tx_backoff); 450 } 451 452 if (!tt->throttle && throttle_enable) { 453 IWL_WARN(mvm, 454 "Due to high temperature thermal throttling initiated\n"); 455 tt->throttle = true; 456 } else if (tt->throttle && !tt->dynamic_smps && 457 tt->tx_backoff == tt->min_backoff && 458 temperature <= params->tx_protection_exit) { 459 IWL_WARN(mvm, 460 "Temperature is back to normal thermal throttling stopped\n"); 461 tt->throttle = false; 462 } 463 } 464 465 static const struct iwl_tt_params iwl_mvm_default_tt_params = { 466 .ct_kill_entry = 118, 467 .ct_kill_exit = 96, 468 .ct_kill_duration = 5, 469 .dynamic_smps_entry = 114, 470 .dynamic_smps_exit = 110, 471 .tx_protection_entry = 114, 472 .tx_protection_exit = 108, 473 .tx_backoff = { 474 {.temperature = 112, .backoff = 200}, 475 {.temperature = 113, .backoff = 600}, 476 {.temperature = 114, .backoff = 1200}, 477 {.temperature = 115, .backoff = 2000}, 478 {.temperature = 116, .backoff = 4000}, 479 {.temperature = 117, .backoff = 10000}, 480 }, 481 .support_ct_kill = true, 482 .support_dynamic_smps = true, 483 .support_tx_protection = true, 484 .support_tx_backoff = true, 485 }; 486 487 int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 state) 488 { 489 struct iwl_ctdp_cmd cmd = { 490 .operation = cpu_to_le32(op), 491 .window_size = 0, 492 }; 493 u32 budget; 494 int ret; 495 u32 status; 496 497 lockdep_assert_held(&mvm->mutex); 498 499 /* Do a linear scale from IWL_MVM_MIN_CTDP_BUDGET_MW to the configured 500 * maximum in the predefined number of steps. 501 */ 502 budget = ((mvm->thermal_throttle.power_budget_mw - 503 IWL_MVM_MIN_CTDP_BUDGET_MW) * 504 (IWL_MVM_NUM_CTDP_STEPS - 1 - state)) / 505 (IWL_MVM_NUM_CTDP_STEPS - 1) + 506 IWL_MVM_MIN_CTDP_BUDGET_MW; 507 cmd.budget = cpu_to_le32(budget); 508 509 status = 0; 510 ret = iwl_mvm_send_cmd_pdu_status(mvm, WIDE_ID(PHY_OPS_GROUP, 511 CTDP_CONFIG_CMD), 512 sizeof(cmd), &cmd, &status); 513 514 if (ret) { 515 IWL_ERR(mvm, "cTDP command failed (err=%d)\n", ret); 516 return ret; 517 } 518 519 switch (op) { 520 case CTDP_CMD_OPERATION_START: 521 #ifdef CONFIG_THERMAL 522 mvm->cooling_dev.cur_state = state; 523 #endif /* CONFIG_THERMAL */ 524 break; 525 case CTDP_CMD_OPERATION_REPORT: 526 IWL_DEBUG_TEMP(mvm, "cTDP avg energy in mWatt = %d\n", status); 527 /* when the function is called with CTDP_CMD_OPERATION_REPORT 528 * option the function should return the average budget value 529 * that is received from the FW. 530 * The budget can't be less or equal to 0, so it's possible 531 * to distinguish between error values and budgets. 532 */ 533 return status; 534 case CTDP_CMD_OPERATION_STOP: 535 IWL_DEBUG_TEMP(mvm, "cTDP stopped successfully\n"); 536 break; 537 } 538 539 return 0; 540 } 541 542 #ifdef CONFIG_THERMAL 543 static int compare_temps(const void *a, const void *b) 544 { 545 return ((s16)le16_to_cpu(*(const __le16 *)a) - 546 (s16)le16_to_cpu(*(const __le16 *)b)); 547 } 548 549 struct iwl_trip_walk_data { 550 __le16 *thresholds; 551 int count; 552 }; 553 554 static int iwl_trip_temp_cb(struct thermal_trip *trip, void *arg) 555 { 556 struct iwl_trip_walk_data *twd = arg; 557 558 if (trip->temperature == THERMAL_TEMP_INVALID) 559 return 0; 560 561 twd->thresholds[twd->count++] = cpu_to_le16((s16)(trip->temperature / 1000)); 562 return 0; 563 } 564 #endif 565 566 int iwl_mvm_send_temp_report_ths_cmd(struct iwl_mvm *mvm) 567 { 568 struct temp_report_ths_cmd cmd = {0}; 569 int ret; 570 #ifdef CONFIG_THERMAL 571 struct iwl_trip_walk_data twd = { .thresholds = cmd.thresholds, .count = 0 }; 572 573 lockdep_assert_held(&mvm->mutex); 574 575 if (!mvm->tz_device.tzone) 576 goto send; 577 578 /* 579 * The thermal core holds an array of temperature trips that are 580 * unsorted and uncompressed, the FW should get it compressed and 581 * sorted. 582 */ 583 584 /* compress trips to cmd array, remove uninitialized values*/ 585 for_each_thermal_trip(mvm->tz_device.tzone, iwl_trip_temp_cb, &twd); 586 587 cmd.num_temps = cpu_to_le32(twd.count); 588 if (twd.count) 589 sort(cmd.thresholds, twd.count, sizeof(s16), compare_temps, NULL); 590 591 send: 592 #endif 593 ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(PHY_OPS_GROUP, 594 TEMP_REPORTING_THRESHOLDS_CMD), 595 0, sizeof(cmd), &cmd); 596 if (ret) 597 IWL_ERR(mvm, "TEMP_REPORT_THS_CMD command failed (err=%d)\n", 598 ret); 599 600 return ret; 601 } 602 603 #ifdef CONFIG_THERMAL 604 static int iwl_mvm_tzone_get_temp(struct thermal_zone_device *device, 605 int *temperature) 606 { 607 struct iwl_mvm *mvm = thermal_zone_device_priv(device); 608 int ret; 609 int temp; 610 611 guard(mvm)(mvm); 612 613 if (!iwl_mvm_firmware_running(mvm) || 614 mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR) { 615 /* 616 * Tell the core that there is no valid temperature value to 617 * return, but it need not worry about this. 618 */ 619 *temperature = THERMAL_TEMP_INVALID; 620 return 0; 621 } 622 623 ret = iwl_mvm_get_temp(mvm, &temp); 624 if (ret) 625 return ret; 626 627 *temperature = temp * 1000; 628 return 0; 629 } 630 631 static int iwl_mvm_tzone_set_trip_temp(struct thermal_zone_device *device, 632 const struct thermal_trip *trip, int temp) 633 { 634 struct iwl_mvm *mvm = thermal_zone_device_priv(device); 635 636 guard(mvm)(mvm); 637 638 if (!iwl_mvm_firmware_running(mvm) || 639 mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR) 640 return -EIO; 641 642 if ((temp / 1000) > S16_MAX) 643 return -EINVAL; 644 645 return iwl_mvm_send_temp_report_ths_cmd(mvm); 646 } 647 648 static struct thermal_zone_device_ops tzone_ops = { 649 .get_temp = iwl_mvm_tzone_get_temp, 650 .set_trip_temp = iwl_mvm_tzone_set_trip_temp, 651 }; 652 653 static void iwl_mvm_thermal_zone_register(struct iwl_mvm *mvm) 654 { 655 int i, ret; 656 char name[16]; 657 static atomic_t counter = ATOMIC_INIT(0); 658 659 if (!iwl_mvm_is_tt_in_fw(mvm)) { 660 mvm->tz_device.tzone = NULL; 661 662 return; 663 } 664 665 BUILD_BUG_ON(ARRAY_SIZE(name) >= THERMAL_NAME_LENGTH); 666 667 sprintf(name, "iwlwifi_%u", atomic_inc_return(&counter) & 0xFF); 668 /* 669 * 0 is a valid temperature, 670 * so initialize the array with S16_MIN which invalid temperature 671 */ 672 for (i = 0 ; i < IWL_MAX_DTS_TRIPS; i++) { 673 mvm->tz_device.trips[i].temperature = THERMAL_TEMP_INVALID; 674 mvm->tz_device.trips[i].type = THERMAL_TRIP_PASSIVE; 675 mvm->tz_device.trips[i].flags = THERMAL_TRIP_FLAG_RW_TEMP; 676 } 677 mvm->tz_device.tzone = thermal_zone_device_register_with_trips(name, 678 mvm->tz_device.trips, 679 IWL_MAX_DTS_TRIPS, 680 mvm, &tzone_ops, 681 NULL, 0, 0); 682 if (IS_ERR(mvm->tz_device.tzone)) { 683 IWL_DEBUG_TEMP(mvm, 684 "Failed to register to thermal zone (err = %ld)\n", 685 PTR_ERR(mvm->tz_device.tzone)); 686 mvm->tz_device.tzone = NULL; 687 return; 688 } 689 690 ret = thermal_zone_device_enable(mvm->tz_device.tzone); 691 if (ret) { 692 IWL_DEBUG_TEMP(mvm, "Failed to enable thermal zone\n"); 693 thermal_zone_device_unregister(mvm->tz_device.tzone); 694 } 695 } 696 697 static int iwl_mvm_tcool_get_max_state(struct thermal_cooling_device *cdev, 698 unsigned long *state) 699 { 700 *state = IWL_MVM_NUM_CTDP_STEPS - 1; 701 702 return 0; 703 } 704 705 static int iwl_mvm_tcool_get_cur_state(struct thermal_cooling_device *cdev, 706 unsigned long *state) 707 { 708 struct iwl_mvm *mvm = (struct iwl_mvm *)(cdev->devdata); 709 710 *state = mvm->cooling_dev.cur_state; 711 712 return 0; 713 } 714 715 static int iwl_mvm_tcool_set_cur_state(struct thermal_cooling_device *cdev, 716 unsigned long new_state) 717 { 718 struct iwl_mvm *mvm = (struct iwl_mvm *)(cdev->devdata); 719 720 guard(mvm)(mvm); 721 722 if (!iwl_mvm_firmware_running(mvm) || 723 mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR) 724 return -EIO; 725 726 if (new_state >= IWL_MVM_NUM_CTDP_STEPS) 727 return -EINVAL; 728 729 return iwl_mvm_ctdp_command(mvm, CTDP_CMD_OPERATION_START, 730 new_state); 731 } 732 733 static const struct thermal_cooling_device_ops tcooling_ops = { 734 .get_max_state = iwl_mvm_tcool_get_max_state, 735 .get_cur_state = iwl_mvm_tcool_get_cur_state, 736 .set_cur_state = iwl_mvm_tcool_set_cur_state, 737 }; 738 739 static void iwl_mvm_cooling_device_register(struct iwl_mvm *mvm) 740 { 741 char name[] = "iwlwifi"; 742 743 if (!iwl_mvm_is_ctdp_supported(mvm)) 744 return; 745 746 BUILD_BUG_ON(ARRAY_SIZE(name) >= THERMAL_NAME_LENGTH); 747 748 mvm->cooling_dev.cdev = 749 thermal_cooling_device_register(name, 750 mvm, 751 &tcooling_ops); 752 753 if (IS_ERR(mvm->cooling_dev.cdev)) { 754 IWL_DEBUG_TEMP(mvm, 755 "Failed to register to cooling device (err = %ld)\n", 756 PTR_ERR(mvm->cooling_dev.cdev)); 757 mvm->cooling_dev.cdev = NULL; 758 return; 759 } 760 } 761 762 static void iwl_mvm_thermal_zone_unregister(struct iwl_mvm *mvm) 763 { 764 if (!iwl_mvm_is_tt_in_fw(mvm) || !mvm->tz_device.tzone) 765 return; 766 767 IWL_DEBUG_TEMP(mvm, "Thermal zone device unregister\n"); 768 if (mvm->tz_device.tzone) { 769 thermal_zone_device_unregister(mvm->tz_device.tzone); 770 mvm->tz_device.tzone = NULL; 771 } 772 } 773 774 static void iwl_mvm_cooling_device_unregister(struct iwl_mvm *mvm) 775 { 776 if (!iwl_mvm_is_ctdp_supported(mvm) || !mvm->cooling_dev.cdev) 777 return; 778 779 IWL_DEBUG_TEMP(mvm, "Cooling device unregister\n"); 780 if (mvm->cooling_dev.cdev) { 781 thermal_cooling_device_unregister(mvm->cooling_dev.cdev); 782 mvm->cooling_dev.cdev = NULL; 783 } 784 } 785 #endif /* CONFIG_THERMAL */ 786 787 static u32 iwl_mvm_ctdp_get_max_budget(struct iwl_mvm *mvm) 788 { 789 u64 bios_power_budget = 0; 790 u32 default_power_budget; 791 792 switch (CSR_HW_RFID_TYPE(mvm->trans->info.hw_rf_id)) { 793 case IWL_CFG_RF_TYPE_JF2: 794 case IWL_CFG_RF_TYPE_JF1: 795 default_power_budget = 2000; 796 break; 797 case IWL_CFG_RF_TYPE_HR2: 798 case IWL_CFG_RF_TYPE_HR1: 799 default_power_budget = 2400; 800 break; 801 case IWL_CFG_RF_TYPE_GF: 802 /* dual-radio devices have a higher budget */ 803 if (CSR_HW_RFID_IS_CDB(mvm->trans->info.hw_rf_id)) 804 default_power_budget = 5200; 805 else 806 default_power_budget = 2880; 807 break; 808 case IWL_CFG_RF_TYPE_FM: 809 default_power_budget = 3450; 810 break; 811 default: 812 default_power_budget = 5550; 813 break; 814 } 815 816 iwl_bios_get_pwr_limit(&mvm->fwrt, &bios_power_budget); 817 818 /* 32bit in UEFI, 16bit in ACPI; use BIOS value if it is in range */ 819 if (bios_power_budget && 820 bios_power_budget != 0xffff && bios_power_budget != 0xffffffff && 821 bios_power_budget >= IWL_MVM_MIN_CTDP_BUDGET_MW && 822 bios_power_budget <= default_power_budget) 823 return (u32)bios_power_budget; 824 825 return default_power_budget; 826 } 827 828 void iwl_mvm_thermal_initialize(struct iwl_mvm *mvm, u32 min_backoff) 829 { 830 struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle; 831 832 IWL_DEBUG_TEMP(mvm, "Initialize Thermal Throttling\n"); 833 834 if (mvm->cfg->thermal_params) 835 tt->params = *mvm->cfg->thermal_params; 836 else 837 tt->params = iwl_mvm_default_tt_params; 838 839 tt->power_budget_mw = iwl_mvm_ctdp_get_max_budget(mvm); 840 IWL_DEBUG_TEMP(mvm, "cTDP power budget: %d mW\n", tt->power_budget_mw); 841 tt->throttle = false; 842 tt->dynamic_smps = false; 843 tt->min_backoff = min_backoff; 844 INIT_DELAYED_WORK(&tt->ct_kill_exit, check_exit_ctkill); 845 846 #ifdef CONFIG_THERMAL 847 iwl_mvm_cooling_device_register(mvm); 848 iwl_mvm_thermal_zone_register(mvm); 849 #endif 850 mvm->init_status |= IWL_MVM_INIT_STATUS_THERMAL_INIT_COMPLETE; 851 } 852 853 void iwl_mvm_thermal_exit(struct iwl_mvm *mvm) 854 { 855 if (!(mvm->init_status & IWL_MVM_INIT_STATUS_THERMAL_INIT_COMPLETE)) 856 return; 857 858 cancel_delayed_work_sync(&mvm->thermal_throttle.ct_kill_exit); 859 IWL_DEBUG_TEMP(mvm, "Exit Thermal Throttling\n"); 860 861 #ifdef CONFIG_THERMAL 862 iwl_mvm_cooling_device_unregister(mvm); 863 iwl_mvm_thermal_zone_unregister(mvm); 864 #endif 865 mvm->init_status &= ~IWL_MVM_INIT_STATUS_THERMAL_INIT_COMPLETE; 866 } 867