This source file includes following definitions.
- iwl_mvm_enter_ctkill
- iwl_mvm_exit_ctkill
- iwl_mvm_tt_temp_changed
- iwl_mvm_temp_notif_parse
- iwl_mvm_temp_notif_wait
- iwl_mvm_temp_notif
- iwl_mvm_ct_kill_notif
- iwl_mvm_get_temp_cmd
- iwl_mvm_get_temp
- check_exit_ctkill
- iwl_mvm_tt_smps_iterator
- iwl_mvm_tt_tx_protection
- iwl_mvm_tt_tx_backoff
- iwl_mvm_tt_handler
- iwl_mvm_ctdp_command
- compare_temps
- iwl_mvm_send_temp_report_ths_cmd
- iwl_mvm_tzone_get_temp
- iwl_mvm_tzone_get_trip_temp
- iwl_mvm_tzone_get_trip_type
- iwl_mvm_tzone_set_trip_temp
- iwl_mvm_thermal_zone_register
- iwl_mvm_tcool_get_max_state
- iwl_mvm_tcool_get_cur_state
- iwl_mvm_tcool_set_cur_state
- iwl_mvm_cooling_device_register
- iwl_mvm_thermal_zone_unregister
- iwl_mvm_cooling_device_unregister
- iwl_mvm_thermal_initialize
- iwl_mvm_thermal_exit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 #include <linux/sort.h>
64
65 #include "mvm.h"
66
67 #define IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT HZ
68
69 void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm)
70 {
71 struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle;
72 u32 duration = tt->params.ct_kill_duration;
73
74 if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status))
75 return;
76
77 IWL_ERR(mvm, "Enter CT Kill\n");
78 iwl_mvm_set_hw_ctkill_state(mvm, true);
79
80 if (!iwl_mvm_is_tt_in_fw(mvm)) {
81 tt->throttle = false;
82 tt->dynamic_smps = false;
83 }
84
85
86
87
88
89 if (!mvm->temperature_test)
90 schedule_delayed_work(&tt->ct_kill_exit,
91 round_jiffies_relative(duration * HZ));
92 }
93
94 static void iwl_mvm_exit_ctkill(struct iwl_mvm *mvm)
95 {
96 if (!test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status))
97 return;
98
99 IWL_ERR(mvm, "Exit CT Kill\n");
100 iwl_mvm_set_hw_ctkill_state(mvm, false);
101 }
102
103 void iwl_mvm_tt_temp_changed(struct iwl_mvm *mvm, u32 temp)
104 {
105
106 if (mvm->temperature_test)
107 return;
108
109 if (mvm->temperature == temp)
110 return;
111
112 mvm->temperature = temp;
113 iwl_mvm_tt_handler(mvm);
114 }
115
116 static int iwl_mvm_temp_notif_parse(struct iwl_mvm *mvm,
117 struct iwl_rx_packet *pkt)
118 {
119 struct iwl_dts_measurement_notif_v1 *notif_v1;
120 int len = iwl_rx_packet_payload_len(pkt);
121 int temp;
122
123
124
125
126 if (WARN_ON_ONCE(len < sizeof(*notif_v1))) {
127 IWL_ERR(mvm, "Invalid DTS_MEASUREMENT_NOTIFICATION\n");
128 return -EINVAL;
129 }
130
131 notif_v1 = (void *)pkt->data;
132
133 temp = le32_to_cpu(notif_v1->temp);
134
135
136 if (WARN_ON_ONCE(temp < 0))
137 temp = 0;
138
139 IWL_DEBUG_TEMP(mvm, "DTS_MEASUREMENT_NOTIFICATION - %d\n", temp);
140
141 return temp;
142 }
143
144 static bool iwl_mvm_temp_notif_wait(struct iwl_notif_wait_data *notif_wait,
145 struct iwl_rx_packet *pkt, void *data)
146 {
147 struct iwl_mvm *mvm =
148 container_of(notif_wait, struct iwl_mvm, notif_wait);
149 int *temp = data;
150 int ret;
151
152 ret = iwl_mvm_temp_notif_parse(mvm, pkt);
153 if (ret < 0)
154 return true;
155
156 *temp = ret;
157
158 return true;
159 }
160
161 void iwl_mvm_temp_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
162 {
163 struct iwl_rx_packet *pkt = rxb_addr(rxb);
164 struct iwl_dts_measurement_notif_v2 *notif_v2;
165 int len = iwl_rx_packet_payload_len(pkt);
166 int temp;
167 u32 ths_crossed;
168
169
170 if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status))
171 return;
172
173 temp = iwl_mvm_temp_notif_parse(mvm, pkt);
174
175 if (!iwl_mvm_is_tt_in_fw(mvm)) {
176 if (temp >= 0)
177 iwl_mvm_tt_temp_changed(mvm, temp);
178 return;
179 }
180
181 if (WARN_ON_ONCE(len < sizeof(*notif_v2))) {
182 IWL_ERR(mvm, "Invalid DTS_MEASUREMENT_NOTIFICATION\n");
183 return;
184 }
185
186 notif_v2 = (void *)pkt->data;
187 ths_crossed = le32_to_cpu(notif_v2->threshold_idx);
188
189
190
191
192 if (ths_crossed == 0xFF)
193 return;
194
195 IWL_DEBUG_TEMP(mvm, "Temp = %d Threshold crossed = %d\n",
196 temp, ths_crossed);
197
198 #ifdef CONFIG_THERMAL
199 if (WARN_ON(ths_crossed >= IWL_MAX_DTS_TRIPS))
200 return;
201
202 if (mvm->tz_device.tzone) {
203 struct iwl_mvm_thermal_device *tz_dev = &mvm->tz_device;
204
205 thermal_notify_framework(tz_dev->tzone,
206 tz_dev->fw_trips_index[ths_crossed]);
207 }
208 #endif
209 }
210
211 void iwl_mvm_ct_kill_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
212 {
213 struct iwl_rx_packet *pkt = rxb_addr(rxb);
214 struct ct_kill_notif *notif;
215 int len = iwl_rx_packet_payload_len(pkt);
216
217 if (WARN_ON_ONCE(len != sizeof(*notif))) {
218 IWL_ERR(mvm, "Invalid CT_KILL_NOTIFICATION\n");
219 return;
220 }
221
222 notif = (struct ct_kill_notif *)pkt->data;
223 IWL_DEBUG_TEMP(mvm, "CT Kill notification temperature = %d\n",
224 notif->temperature);
225
226 iwl_mvm_enter_ctkill(mvm);
227 }
228
229 static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm)
230 {
231 struct iwl_dts_measurement_cmd cmd = {
232 .flags = cpu_to_le32(DTS_TRIGGER_CMD_FLAGS_TEMP),
233 };
234 struct iwl_ext_dts_measurement_cmd extcmd = {
235 .control_mode = cpu_to_le32(DTS_AUTOMATIC),
236 };
237 u32 cmdid;
238
239 cmdid = iwl_cmd_id(CMD_DTS_MEASUREMENT_TRIGGER_WIDE,
240 PHY_OPS_GROUP, 0);
241
242 if (!fw_has_capa(&mvm->fw->ucode_capa,
243 IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE))
244 return iwl_mvm_send_cmd_pdu(mvm, cmdid, 0, sizeof(cmd), &cmd);
245
246 return iwl_mvm_send_cmd_pdu(mvm, cmdid, 0, sizeof(extcmd), &extcmd);
247 }
248
249 int iwl_mvm_get_temp(struct iwl_mvm *mvm, s32 *temp)
250 {
251 struct iwl_notification_wait wait_temp_notif;
252 static u16 temp_notif[] = { WIDE_ID(PHY_OPS_GROUP,
253 DTS_MEASUREMENT_NOTIF_WIDE) };
254 int ret;
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_get_temp_cmd(mvm);
263 if (ret) {
264 IWL_ERR(mvm, "Failed to get the temperature (err=%d)\n", ret);
265 iwl_remove_notification(&mvm->notif_wait, &wait_temp_notif);
266 return ret;
267 }
268
269 ret = iwl_wait_notification(&mvm->notif_wait, &wait_temp_notif,
270 IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT);
271 if (ret)
272 IWL_ERR(mvm, "Getting the temperature timed out\n");
273
274 return ret;
275 }
276
277 static void check_exit_ctkill(struct work_struct *work)
278 {
279 struct iwl_mvm_tt_mgmt *tt;
280 struct iwl_mvm *mvm;
281 u32 duration;
282 s32 temp;
283 int ret;
284
285 tt = container_of(work, struct iwl_mvm_tt_mgmt, ct_kill_exit.work);
286 mvm = container_of(tt, struct iwl_mvm, thermal_throttle);
287
288 if (iwl_mvm_is_tt_in_fw(mvm)) {
289 iwl_mvm_exit_ctkill(mvm);
290
291 return;
292 }
293
294 duration = tt->params.ct_kill_duration;
295
296 mutex_lock(&mvm->mutex);
297
298 if (__iwl_mvm_mac_start(mvm))
299 goto reschedule;
300
301 ret = iwl_mvm_get_temp(mvm, &temp);
302
303 __iwl_mvm_mac_stop(mvm);
304
305 if (ret)
306 goto reschedule;
307
308 IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", temp);
309
310 if (temp <= tt->params.ct_kill_exit) {
311 mutex_unlock(&mvm->mutex);
312 iwl_mvm_exit_ctkill(mvm);
313 return;
314 }
315
316 reschedule:
317 mutex_unlock(&mvm->mutex);
318 schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit,
319 round_jiffies(duration * HZ));
320 }
321
322 static void iwl_mvm_tt_smps_iterator(void *_data, u8 *mac,
323 struct ieee80211_vif *vif)
324 {
325 struct iwl_mvm *mvm = _data;
326 enum ieee80211_smps_mode smps_mode;
327
328 lockdep_assert_held(&mvm->mutex);
329
330 if (mvm->thermal_throttle.dynamic_smps)
331 smps_mode = IEEE80211_SMPS_DYNAMIC;
332 else
333 smps_mode = IEEE80211_SMPS_AUTOMATIC;
334
335 if (vif->type != NL80211_IFTYPE_STATION)
336 return;
337
338 iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_TT, smps_mode);
339 }
340
341 static void iwl_mvm_tt_tx_protection(struct iwl_mvm *mvm, bool enable)
342 {
343 struct iwl_mvm_sta *mvmsta;
344 int i, err;
345
346 for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++) {
347 mvmsta = iwl_mvm_sta_from_staid_protected(mvm, i);
348 if (!mvmsta)
349 continue;
350
351 if (enable == mvmsta->tt_tx_protection)
352 continue;
353 err = iwl_mvm_tx_protection(mvm, mvmsta, enable);
354 if (err) {
355 IWL_ERR(mvm, "Failed to %s Tx protection\n",
356 enable ? "enable" : "disable");
357 } else {
358 IWL_DEBUG_TEMP(mvm, "%s Tx protection\n",
359 enable ? "Enable" : "Disable");
360 mvmsta->tt_tx_protection = enable;
361 }
362 }
363 }
364
365 void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff)
366 {
367 struct iwl_host_cmd cmd = {
368 .id = REPLY_THERMAL_MNG_BACKOFF,
369 .len = { sizeof(u32), },
370 .data = { &backoff, },
371 };
372
373 backoff = max(backoff, mvm->thermal_throttle.min_backoff);
374
375 if (iwl_mvm_send_cmd(mvm, &cmd) == 0) {
376 IWL_DEBUG_TEMP(mvm, "Set Thermal Tx backoff to: %u\n",
377 backoff);
378 mvm->thermal_throttle.tx_backoff = backoff;
379 } else {
380 IWL_ERR(mvm, "Failed to change Thermal Tx backoff\n");
381 }
382 }
383
384 void iwl_mvm_tt_handler(struct iwl_mvm *mvm)
385 {
386 struct iwl_tt_params *params = &mvm->thermal_throttle.params;
387 struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle;
388 s32 temperature = mvm->temperature;
389 bool throttle_enable = false;
390 int i;
391 u32 tx_backoff;
392
393 IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", mvm->temperature);
394
395 if (params->support_ct_kill && temperature >= params->ct_kill_entry) {
396 iwl_mvm_enter_ctkill(mvm);
397 return;
398 }
399
400 if (params->support_ct_kill &&
401 temperature <= params->ct_kill_exit) {
402 iwl_mvm_exit_ctkill(mvm);
403 return;
404 }
405
406 if (params->support_dynamic_smps) {
407 if (!tt->dynamic_smps &&
408 temperature >= params->dynamic_smps_entry) {
409 IWL_DEBUG_TEMP(mvm, "Enable dynamic SMPS\n");
410 tt->dynamic_smps = true;
411 ieee80211_iterate_active_interfaces_atomic(
412 mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
413 iwl_mvm_tt_smps_iterator, mvm);
414 throttle_enable = true;
415 } else if (tt->dynamic_smps &&
416 temperature <= params->dynamic_smps_exit) {
417 IWL_DEBUG_TEMP(mvm, "Disable dynamic SMPS\n");
418 tt->dynamic_smps = false;
419 ieee80211_iterate_active_interfaces_atomic(
420 mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
421 iwl_mvm_tt_smps_iterator, mvm);
422 }
423 }
424
425 if (params->support_tx_protection) {
426 if (temperature >= params->tx_protection_entry) {
427 iwl_mvm_tt_tx_protection(mvm, true);
428 throttle_enable = true;
429 } else if (temperature <= params->tx_protection_exit) {
430 iwl_mvm_tt_tx_protection(mvm, false);
431 }
432 }
433
434 if (params->support_tx_backoff) {
435 tx_backoff = tt->min_backoff;
436 for (i = 0; i < TT_TX_BACKOFF_SIZE; i++) {
437 if (temperature < params->tx_backoff[i].temperature)
438 break;
439 tx_backoff = max(tt->min_backoff,
440 params->tx_backoff[i].backoff);
441 }
442 if (tx_backoff != tt->min_backoff)
443 throttle_enable = true;
444 if (tt->tx_backoff != tx_backoff)
445 iwl_mvm_tt_tx_backoff(mvm, tx_backoff);
446 }
447
448 if (!tt->throttle && throttle_enable) {
449 IWL_WARN(mvm,
450 "Due to high temperature thermal throttling initiated\n");
451 tt->throttle = true;
452 } else if (tt->throttle && !tt->dynamic_smps &&
453 tt->tx_backoff == tt->min_backoff &&
454 temperature <= params->tx_protection_exit) {
455 IWL_WARN(mvm,
456 "Temperature is back to normal thermal throttling stopped\n");
457 tt->throttle = false;
458 }
459 }
460
461 static const struct iwl_tt_params iwl_mvm_default_tt_params = {
462 .ct_kill_entry = 118,
463 .ct_kill_exit = 96,
464 .ct_kill_duration = 5,
465 .dynamic_smps_entry = 114,
466 .dynamic_smps_exit = 110,
467 .tx_protection_entry = 114,
468 .tx_protection_exit = 108,
469 .tx_backoff = {
470 {.temperature = 112, .backoff = 200},
471 {.temperature = 113, .backoff = 600},
472 {.temperature = 114, .backoff = 1200},
473 {.temperature = 115, .backoff = 2000},
474 {.temperature = 116, .backoff = 4000},
475 {.temperature = 117, .backoff = 10000},
476 },
477 .support_ct_kill = true,
478 .support_dynamic_smps = true,
479 .support_tx_protection = true,
480 .support_tx_backoff = true,
481 };
482
483
484 static const u32 iwl_mvm_cdev_budgets[] = {
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
507 int 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
553 static 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
560 int 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
602 send:
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
615 static 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
636 out:
637 mutex_unlock(&mvm->mutex);
638 return ret;
639 }
640
641 static 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
654 static 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
665 static 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);
716 out:
717 mutex_unlock(&mvm->mutex);
718 return ret;
719 }
720
721 static 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
731 static void iwl_mvm_thermal_zone_register(struct iwl_mvm *mvm)
732 {
733 int i;
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
760
761
762 for (i = 0 ; i < IWL_MAX_DTS_TRIPS; i++)
763 mvm->tz_device.temp_trips[i] = S16_MIN;
764 }
765
766 static int iwl_mvm_tcool_get_max_state(struct thermal_cooling_device *cdev,
767 unsigned long *state)
768 {
769 *state = ARRAY_SIZE(iwl_mvm_cdev_budgets) - 1;
770
771 return 0;
772 }
773
774 static int iwl_mvm_tcool_get_cur_state(struct thermal_cooling_device *cdev,
775 unsigned long *state)
776 {
777 struct iwl_mvm *mvm = (struct iwl_mvm *)(cdev->devdata);
778
779 *state = mvm->cooling_dev.cur_state;
780
781 return 0;
782 }
783
784 static int iwl_mvm_tcool_set_cur_state(struct thermal_cooling_device *cdev,
785 unsigned long new_state)
786 {
787 struct iwl_mvm *mvm = (struct iwl_mvm *)(cdev->devdata);
788 int ret;
789
790 mutex_lock(&mvm->mutex);
791
792 if (!iwl_mvm_firmware_running(mvm) ||
793 mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR) {
794 ret = -EIO;
795 goto unlock;
796 }
797
798 if (new_state >= ARRAY_SIZE(iwl_mvm_cdev_budgets)) {
799 ret = -EINVAL;
800 goto unlock;
801 }
802
803 ret = iwl_mvm_ctdp_command(mvm, CTDP_CMD_OPERATION_START,
804 new_state);
805
806 unlock:
807 mutex_unlock(&mvm->mutex);
808 return ret;
809 }
810
811 static const struct thermal_cooling_device_ops tcooling_ops = {
812 .get_max_state = iwl_mvm_tcool_get_max_state,
813 .get_cur_state = iwl_mvm_tcool_get_cur_state,
814 .set_cur_state = iwl_mvm_tcool_set_cur_state,
815 };
816
817 static void iwl_mvm_cooling_device_register(struct iwl_mvm *mvm)
818 {
819 char name[] = "iwlwifi";
820
821 if (!iwl_mvm_is_ctdp_supported(mvm))
822 return;
823
824 BUILD_BUG_ON(ARRAY_SIZE(name) >= THERMAL_NAME_LENGTH);
825
826 mvm->cooling_dev.cdev =
827 thermal_cooling_device_register(name,
828 mvm,
829 &tcooling_ops);
830
831 if (IS_ERR(mvm->cooling_dev.cdev)) {
832 IWL_DEBUG_TEMP(mvm,
833 "Failed to register to cooling device (err = %ld)\n",
834 PTR_ERR(mvm->cooling_dev.cdev));
835 mvm->cooling_dev.cdev = NULL;
836 return;
837 }
838 }
839
840 static void iwl_mvm_thermal_zone_unregister(struct iwl_mvm *mvm)
841 {
842 if (!iwl_mvm_is_tt_in_fw(mvm) || !mvm->tz_device.tzone)
843 return;
844
845 IWL_DEBUG_TEMP(mvm, "Thermal zone device unregister\n");
846 if (mvm->tz_device.tzone) {
847 thermal_zone_device_unregister(mvm->tz_device.tzone);
848 mvm->tz_device.tzone = NULL;
849 }
850 }
851
852 static void iwl_mvm_cooling_device_unregister(struct iwl_mvm *mvm)
853 {
854 if (!iwl_mvm_is_ctdp_supported(mvm) || !mvm->cooling_dev.cdev)
855 return;
856
857 IWL_DEBUG_TEMP(mvm, "Cooling device unregister\n");
858 if (mvm->cooling_dev.cdev) {
859 thermal_cooling_device_unregister(mvm->cooling_dev.cdev);
860 mvm->cooling_dev.cdev = NULL;
861 }
862 }
863 #endif
864
865 void iwl_mvm_thermal_initialize(struct iwl_mvm *mvm, u32 min_backoff)
866 {
867 struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle;
868
869 IWL_DEBUG_TEMP(mvm, "Initialize Thermal Throttling\n");
870
871 if (mvm->cfg->thermal_params)
872 tt->params = *mvm->cfg->thermal_params;
873 else
874 tt->params = iwl_mvm_default_tt_params;
875
876 tt->throttle = false;
877 tt->dynamic_smps = false;
878 tt->min_backoff = min_backoff;
879 INIT_DELAYED_WORK(&tt->ct_kill_exit, check_exit_ctkill);
880
881 #ifdef CONFIG_THERMAL
882 iwl_mvm_cooling_device_register(mvm);
883 iwl_mvm_thermal_zone_register(mvm);
884 #endif
885 mvm->init_status |= IWL_MVM_INIT_STATUS_THERMAL_INIT_COMPLETE;
886 }
887
888 void iwl_mvm_thermal_exit(struct iwl_mvm *mvm)
889 {
890 if (!(mvm->init_status & IWL_MVM_INIT_STATUS_THERMAL_INIT_COMPLETE))
891 return;
892
893 cancel_delayed_work_sync(&mvm->thermal_throttle.ct_kill_exit);
894 IWL_DEBUG_TEMP(mvm, "Exit Thermal Throttling\n");
895
896 #ifdef CONFIG_THERMAL
897 iwl_mvm_cooling_device_unregister(mvm);
898 iwl_mvm_thermal_zone_unregister(mvm);
899 #endif
900 mvm->init_status &= ~IWL_MVM_INIT_STATUS_THERMAL_INIT_COMPLETE;
901 }