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