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 Intel Corporation. All rights reserved.
9  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
10  * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of version 2 of the GNU General Public License as
14  * published by the Free Software Foundation.
15  *
16  * This program is distributed in the hope that it will be useful, but
17  * WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * General Public License for more details.
20  *
21  * The full GNU General Public License is included in this distribution
22  * in the file called COPYING.
23  *
24  * Contact Information:
25  *  Intel Linux Wireless <linuxwifi@intel.com>
26  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
27  *
28  * BSD LICENSE
29  *
30  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
31  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
32  * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
33  * All rights reserved.
34  *
35  * Redistribution and use in source and binary forms, with or without
36  * modification, are permitted provided that the following conditions
37  * are met:
38  *
39  *  * Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  *  * Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in
43  *    the documentation and/or other materials provided with the
44  *    distribution.
45  *  * Neither the name Intel Corporation nor the names of its
46  *    contributors may be used to endorse or promote products derived
47  *    from this software without specific prior written permission.
48  *
49  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
50  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
51  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
52  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
53  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
54  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
55  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
56  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
57  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
58  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
59  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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 	/* Don't schedule an exit work if we're in test mode, since
86 	 * the temperature will not change unless we manually set it
87 	 * again (or disable testing).
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 	/* ignore the notification if we are in test mode */
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 	/* we can use notif_v1 only, because v2 only adds an additional
124 	 * parameter, which is not used in this function.
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 	/* shouldn't be negative, but since it's s32, make sure it isn't */
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 	/* the notification is handled synchronously in ctkill, so skip here */
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 	/* 0xFF in ths_crossed means the notification is not related
190 	 * to a trip, so we can ignore it here.
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 /* CONFIG_THERMAL */
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 	/* make sure the device is available for direct read/writes */
302 	if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_CHECK_CTKILL)) {
303 		__iwl_mvm_mac_stop(mvm);
304 		goto reschedule;
305 	}
306 
307 	ret = iwl_mvm_get_temp(mvm, &temp);
308 
309 	iwl_mvm_unref(mvm, IWL_MVM_REF_CHECK_CTKILL);
310 
311 	__iwl_mvm_mac_stop(mvm);
312 
313 	if (ret)
314 		goto reschedule;
315 
316 	IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", temp);
317 
318 	if (temp <= tt->params.ct_kill_exit) {
319 		mutex_unlock(&mvm->mutex);
320 		iwl_mvm_exit_ctkill(mvm);
321 		return;
322 	}
323 
324 reschedule:
325 	mutex_unlock(&mvm->mutex);
326 	schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit,
327 			      round_jiffies(duration * HZ));
328 }
329 
330 static void iwl_mvm_tt_smps_iterator(void *_data, u8 *mac,
331 				     struct ieee80211_vif *vif)
332 {
333 	struct iwl_mvm *mvm = _data;
334 	enum ieee80211_smps_mode smps_mode;
335 
336 	lockdep_assert_held(&mvm->mutex);
337 
338 	if (mvm->thermal_throttle.dynamic_smps)
339 		smps_mode = IEEE80211_SMPS_DYNAMIC;
340 	else
341 		smps_mode = IEEE80211_SMPS_AUTOMATIC;
342 
343 	if (vif->type != NL80211_IFTYPE_STATION)
344 		return;
345 
346 	iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_TT, smps_mode);
347 }
348 
349 static void iwl_mvm_tt_tx_protection(struct iwl_mvm *mvm, bool enable)
350 {
351 	struct iwl_mvm_sta *mvmsta;
352 	int i, err;
353 
354 	for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++) {
355 		mvmsta = iwl_mvm_sta_from_staid_protected(mvm, i);
356 		if (!mvmsta)
357 			continue;
358 
359 		if (enable == mvmsta->tt_tx_protection)
360 			continue;
361 		err = iwl_mvm_tx_protection(mvm, mvmsta, enable);
362 		if (err) {
363 			IWL_ERR(mvm, "Failed to %s Tx protection\n",
364 				enable ? "enable" : "disable");
365 		} else {
366 			IWL_DEBUG_TEMP(mvm, "%s Tx protection\n",
367 				       enable ? "Enable" : "Disable");
368 			mvmsta->tt_tx_protection = enable;
369 		}
370 	}
371 }
372 
373 void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff)
374 {
375 	struct iwl_host_cmd cmd = {
376 		.id = REPLY_THERMAL_MNG_BACKOFF,
377 		.len = { sizeof(u32), },
378 		.data = { &backoff, },
379 	};
380 
381 	backoff = max(backoff, mvm->thermal_throttle.min_backoff);
382 
383 	if (iwl_mvm_send_cmd(mvm, &cmd) == 0) {
384 		IWL_DEBUG_TEMP(mvm, "Set Thermal Tx backoff to: %u\n",
385 			       backoff);
386 		mvm->thermal_throttle.tx_backoff = backoff;
387 	} else {
388 		IWL_ERR(mvm, "Failed to change Thermal Tx backoff\n");
389 	}
390 }
391 
392 void iwl_mvm_tt_handler(struct iwl_mvm *mvm)
393 {
394 	struct iwl_tt_params *params = &mvm->thermal_throttle.params;
395 	struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle;
396 	s32 temperature = mvm->temperature;
397 	bool throttle_enable = false;
398 	int i;
399 	u32 tx_backoff;
400 
401 	IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", mvm->temperature);
402 
403 	if (params->support_ct_kill && temperature >= params->ct_kill_entry) {
404 		iwl_mvm_enter_ctkill(mvm);
405 		return;
406 	}
407 
408 	if (params->support_ct_kill &&
409 	    temperature <= params->ct_kill_exit) {
410 		iwl_mvm_exit_ctkill(mvm);
411 		return;
412 	}
413 
414 	if (params->support_dynamic_smps) {
415 		if (!tt->dynamic_smps &&
416 		    temperature >= params->dynamic_smps_entry) {
417 			IWL_DEBUG_TEMP(mvm, "Enable dynamic SMPS\n");
418 			tt->dynamic_smps = true;
419 			ieee80211_iterate_active_interfaces_atomic(
420 					mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
421 					iwl_mvm_tt_smps_iterator, mvm);
422 			throttle_enable = true;
423 		} else if (tt->dynamic_smps &&
424 			   temperature <= params->dynamic_smps_exit) {
425 			IWL_DEBUG_TEMP(mvm, "Disable dynamic SMPS\n");
426 			tt->dynamic_smps = false;
427 			ieee80211_iterate_active_interfaces_atomic(
428 					mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
429 					iwl_mvm_tt_smps_iterator, mvm);
430 		}
431 	}
432 
433 	if (params->support_tx_protection) {
434 		if (temperature >= params->tx_protection_entry) {
435 			iwl_mvm_tt_tx_protection(mvm, true);
436 			throttle_enable = true;
437 		} else if (temperature <= params->tx_protection_exit) {
438 			iwl_mvm_tt_tx_protection(mvm, false);
439 		}
440 	}
441 
442 	if (params->support_tx_backoff) {
443 		tx_backoff = tt->min_backoff;
444 		for (i = 0; i < TT_TX_BACKOFF_SIZE; i++) {
445 			if (temperature < params->tx_backoff[i].temperature)
446 				break;
447 			tx_backoff = max(tt->min_backoff,
448 					 params->tx_backoff[i].backoff);
449 		}
450 		if (tx_backoff != tt->min_backoff)
451 			throttle_enable = true;
452 		if (tt->tx_backoff != tx_backoff)
453 			iwl_mvm_tt_tx_backoff(mvm, tx_backoff);
454 	}
455 
456 	if (!tt->throttle && throttle_enable) {
457 		IWL_WARN(mvm,
458 			 "Due to high temperature thermal throttling initiated\n");
459 		tt->throttle = true;
460 	} else if (tt->throttle && !tt->dynamic_smps &&
461 		   tt->tx_backoff == tt->min_backoff &&
462 		   temperature <= params->tx_protection_exit) {
463 		IWL_WARN(mvm,
464 			 "Temperature is back to normal thermal throttling stopped\n");
465 		tt->throttle = false;
466 	}
467 }
468 
469 static const struct iwl_tt_params iwl_mvm_default_tt_params = {
470 	.ct_kill_entry = 118,
471 	.ct_kill_exit = 96,
472 	.ct_kill_duration = 5,
473 	.dynamic_smps_entry = 114,
474 	.dynamic_smps_exit = 110,
475 	.tx_protection_entry = 114,
476 	.tx_protection_exit = 108,
477 	.tx_backoff = {
478 		{.temperature = 112, .backoff = 200},
479 		{.temperature = 113, .backoff = 600},
480 		{.temperature = 114, .backoff = 1200},
481 		{.temperature = 115, .backoff = 2000},
482 		{.temperature = 116, .backoff = 4000},
483 		{.temperature = 117, .backoff = 10000},
484 	},
485 	.support_ct_kill = true,
486 	.support_dynamic_smps = true,
487 	.support_tx_protection = true,
488 	.support_tx_backoff = true,
489 };
490 
491 /* budget in mWatt */
492 static const u32 iwl_mvm_cdev_budgets[] = {
493 	2000,	/* cooling state 0 */
494 	1800,	/* cooling state 1 */
495 	1600,	/* cooling state 2 */
496 	1400,	/* cooling state 3 */
497 	1200,	/* cooling state 4 */
498 	1000,	/* cooling state 5 */
499 	900,	/* cooling state 6 */
500 	800,	/* cooling state 7 */
501 	700,	/* cooling state 8 */
502 	650,	/* cooling state 9 */
503 	600,	/* cooling state 10 */
504 	550,	/* cooling state 11 */
505 	500,	/* cooling state 12 */
506 	450,	/* cooling state 13 */
507 	400,	/* cooling state 14 */
508 	350,	/* cooling state 15 */
509 	300,	/* cooling state 16 */
510 	250,	/* cooling state 17 */
511 	200,	/* cooling state 18 */
512 	150,	/* cooling state 19 */
513 };
514 
515 int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 state)
516 {
517 	struct iwl_mvm_ctdp_cmd cmd = {
518 		.operation = cpu_to_le32(op),
519 		.budget = cpu_to_le32(iwl_mvm_cdev_budgets[state]),
520 		.window_size = 0,
521 	};
522 	int ret;
523 	u32 status;
524 
525 	lockdep_assert_held(&mvm->mutex);
526 
527 	status = 0;
528 	ret = iwl_mvm_send_cmd_pdu_status(mvm, WIDE_ID(PHY_OPS_GROUP,
529 						       CTDP_CONFIG_CMD),
530 					  sizeof(cmd), &cmd, &status);
531 
532 	if (ret) {
533 		IWL_ERR(mvm, "cTDP command failed (err=%d)\n", ret);
534 		return ret;
535 	}
536 
537 	switch (op) {
538 	case CTDP_CMD_OPERATION_START:
539 #ifdef CONFIG_THERMAL
540 		mvm->cooling_dev.cur_state = state;
541 #endif /* CONFIG_THERMAL */
542 		break;
543 	case CTDP_CMD_OPERATION_REPORT:
544 		IWL_DEBUG_TEMP(mvm, "cTDP avg energy in mWatt = %d\n", status);
545 		/* when the function is called with CTDP_CMD_OPERATION_REPORT
546 		 * option the function should return the average budget value
547 		 * that is received from the FW.
548 		 * The budget can't be less or equal to 0, so it's possible
549 		 * to distinguish between error values and budgets.
550 		 */
551 		return status;
552 	case CTDP_CMD_OPERATION_STOP:
553 		IWL_DEBUG_TEMP(mvm, "cTDP stopped successfully\n");
554 		break;
555 	}
556 
557 	return 0;
558 }
559 
560 #ifdef CONFIG_THERMAL
561 static int compare_temps(const void *a, const void *b)
562 {
563 	return ((s16)le16_to_cpu(*(__le16 *)a) -
564 		(s16)le16_to_cpu(*(__le16 *)b));
565 }
566 
567 int iwl_mvm_send_temp_report_ths_cmd(struct iwl_mvm *mvm)
568 {
569 	struct temp_report_ths_cmd cmd = {0};
570 	int ret, i, j, idx = 0;
571 
572 	lockdep_assert_held(&mvm->mutex);
573 
574 	if (!mvm->tz_device.tzone)
575 		return -EINVAL;
576 
577 	/* The driver holds array of temperature trips that are unsorted
578 	 * and uncompressed, the FW should get it compressed and sorted
579 	 */
580 
581 	/* compress temp_trips to cmd array, remove uninitialized values*/
582 	for (i = 0; i < IWL_MAX_DTS_TRIPS; i++) {
583 		if (mvm->tz_device.temp_trips[i] != S16_MIN) {
584 			cmd.thresholds[idx++] =
585 				cpu_to_le16(mvm->tz_device.temp_trips[i]);
586 		}
587 	}
588 	cmd.num_temps = cpu_to_le32(idx);
589 
590 	if (!idx)
591 		goto send;
592 
593 	/*sort cmd array*/
594 	sort(cmd.thresholds, idx, sizeof(s16), compare_temps, NULL);
595 
596 	/* we should save the indexes of trips because we sort
597 	 * and compress the orginal array
598 	 */
599 	for (i = 0; i < idx; i++) {
600 		for (j = 0; j < IWL_MAX_DTS_TRIPS; j++) {
601 			if (le16_to_cpu(cmd.thresholds[i]) ==
602 				mvm->tz_device.temp_trips[j])
603 				mvm->tz_device.fw_trips_index[i] = j;
604 		}
605 	}
606 
607 send:
608 	ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(PHY_OPS_GROUP,
609 						TEMP_REPORTING_THRESHOLDS_CMD),
610 				   0, sizeof(cmd), &cmd);
611 	if (ret)
612 		IWL_ERR(mvm, "TEMP_REPORT_THS_CMD command failed (err=%d)\n",
613 			ret);
614 
615 	return ret;
616 }
617 
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;
737 	char name[] = "iwlwifi";
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 	mvm->tz_device.tzone = thermal_zone_device_register(name,
748 							IWL_MAX_DTS_TRIPS,
749 							IWL_WRITABLE_TRIPS_MSK,
750 							mvm, &tzone_ops,
751 							NULL, 0, 0);
752 	if (IS_ERR(mvm->tz_device.tzone)) {
753 		IWL_DEBUG_TEMP(mvm,
754 			       "Failed to register to thermal zone (err = %ld)\n",
755 			       PTR_ERR(mvm->tz_device.tzone));
756 		mvm->tz_device.tzone = NULL;
757 		return;
758 	}
759 
760 	/* 0 is a valid temperature,
761 	 * so initialize the array with S16_MIN which invalid temperature
762 	 */
763 	for (i = 0 ; i < IWL_MAX_DTS_TRIPS; i++)
764 		mvm->tz_device.temp_trips[i] = S16_MIN;
765 }
766 
767 static int iwl_mvm_tcool_get_max_state(struct thermal_cooling_device *cdev,
768 				       unsigned long *state)
769 {
770 	*state = ARRAY_SIZE(iwl_mvm_cdev_budgets) - 1;
771 
772 	return 0;
773 }
774 
775 static int iwl_mvm_tcool_get_cur_state(struct thermal_cooling_device *cdev,
776 				       unsigned long *state)
777 {
778 	struct iwl_mvm *mvm = (struct iwl_mvm *)(cdev->devdata);
779 
780 	*state = mvm->cooling_dev.cur_state;
781 
782 	return 0;
783 }
784 
785 static int iwl_mvm_tcool_set_cur_state(struct thermal_cooling_device *cdev,
786 				       unsigned long new_state)
787 {
788 	struct iwl_mvm *mvm = (struct iwl_mvm *)(cdev->devdata);
789 	int ret;
790 
791 	mutex_lock(&mvm->mutex);
792 
793 	if (!iwl_mvm_firmware_running(mvm) ||
794 	    mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR) {
795 		ret = -EIO;
796 		goto unlock;
797 	}
798 
799 	if (new_state >= ARRAY_SIZE(iwl_mvm_cdev_budgets)) {
800 		ret = -EINVAL;
801 		goto unlock;
802 	}
803 
804 	ret = iwl_mvm_ctdp_command(mvm, CTDP_CMD_OPERATION_START,
805 				   new_state);
806 
807 unlock:
808 	mutex_unlock(&mvm->mutex);
809 	return ret;
810 }
811 
812 static const struct thermal_cooling_device_ops tcooling_ops = {
813 	.get_max_state = iwl_mvm_tcool_get_max_state,
814 	.get_cur_state = iwl_mvm_tcool_get_cur_state,
815 	.set_cur_state = iwl_mvm_tcool_set_cur_state,
816 };
817 
818 static void iwl_mvm_cooling_device_register(struct iwl_mvm *mvm)
819 {
820 	char name[] = "iwlwifi";
821 
822 	if (!iwl_mvm_is_ctdp_supported(mvm))
823 		return;
824 
825 	BUILD_BUG_ON(ARRAY_SIZE(name) >= THERMAL_NAME_LENGTH);
826 
827 	mvm->cooling_dev.cdev =
828 		thermal_cooling_device_register(name,
829 						mvm,
830 						&tcooling_ops);
831 
832 	if (IS_ERR(mvm->cooling_dev.cdev)) {
833 		IWL_DEBUG_TEMP(mvm,
834 			       "Failed to register to cooling device (err = %ld)\n",
835 			       PTR_ERR(mvm->cooling_dev.cdev));
836 		mvm->cooling_dev.cdev = NULL;
837 		return;
838 	}
839 }
840 
841 static void iwl_mvm_thermal_zone_unregister(struct iwl_mvm *mvm)
842 {
843 	if (!iwl_mvm_is_tt_in_fw(mvm) || !mvm->tz_device.tzone)
844 		return;
845 
846 	IWL_DEBUG_TEMP(mvm, "Thermal zone device unregister\n");
847 	if (mvm->tz_device.tzone) {
848 		thermal_zone_device_unregister(mvm->tz_device.tzone);
849 		mvm->tz_device.tzone = NULL;
850 	}
851 }
852 
853 static void iwl_mvm_cooling_device_unregister(struct iwl_mvm *mvm)
854 {
855 	if (!iwl_mvm_is_ctdp_supported(mvm) || !mvm->cooling_dev.cdev)
856 		return;
857 
858 	IWL_DEBUG_TEMP(mvm, "Cooling device unregister\n");
859 	if (mvm->cooling_dev.cdev) {
860 		thermal_cooling_device_unregister(mvm->cooling_dev.cdev);
861 		mvm->cooling_dev.cdev = NULL;
862 	}
863 }
864 #endif /* CONFIG_THERMAL */
865 
866 void iwl_mvm_thermal_initialize(struct iwl_mvm *mvm, u32 min_backoff)
867 {
868 	struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle;
869 
870 	IWL_DEBUG_TEMP(mvm, "Initialize Thermal Throttling\n");
871 
872 	if (mvm->cfg->thermal_params)
873 		tt->params = *mvm->cfg->thermal_params;
874 	else
875 		tt->params = iwl_mvm_default_tt_params;
876 
877 	tt->throttle = false;
878 	tt->dynamic_smps = false;
879 	tt->min_backoff = min_backoff;
880 	INIT_DELAYED_WORK(&tt->ct_kill_exit, check_exit_ctkill);
881 
882 #ifdef CONFIG_THERMAL
883 	iwl_mvm_cooling_device_register(mvm);
884 	iwl_mvm_thermal_zone_register(mvm);
885 #endif
886 	mvm->init_status |= IWL_MVM_INIT_STATUS_THERMAL_INIT_COMPLETE;
887 }
888 
889 void iwl_mvm_thermal_exit(struct iwl_mvm *mvm)
890 {
891 	if (!(mvm->init_status & IWL_MVM_INIT_STATUS_THERMAL_INIT_COMPLETE))
892 		return;
893 
894 	cancel_delayed_work_sync(&mvm->thermal_throttle.ct_kill_exit);
895 	IWL_DEBUG_TEMP(mvm, "Exit Thermal Throttling\n");
896 
897 #ifdef CONFIG_THERMAL
898 	iwl_mvm_cooling_device_unregister(mvm);
899 	iwl_mvm_thermal_zone_unregister(mvm);
900 #endif
901 	mvm->init_status &= ~IWL_MVM_INIT_STATUS_THERMAL_INIT_COMPLETE;
902 }
903