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