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