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