aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api.h32
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c34
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h3
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/ops.c2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tt.c326
5 files changed, 140 insertions, 257 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
index b599b5288982..fbcc036b1e44 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
@@ -205,6 +205,10 @@ enum {
205 REPLY_SF_CFG_CMD = 0xd1, 205 REPLY_SF_CFG_CMD = 0xd1,
206 REPLY_BEACON_FILTERING_CMD = 0xd2, 206 REPLY_BEACON_FILTERING_CMD = 0xd2,
207 207
208 /* DTS measurements */
209 CMD_DTS_MEASUREMENT_TRIGGER = 0xdc,
210 DTS_MEASUREMENT_NOTIFICATION = 0xdd,
211
208 REPLY_DEBUG_CMD = 0xf0, 212 REPLY_DEBUG_CMD = 0xf0,
209 DEBUG_LOG_MSG = 0xf7, 213 DEBUG_LOG_MSG = 0xf7,
210 214
@@ -1618,4 +1622,32 @@ struct iwl_sf_cfg_cmd {
1618 __le32 full_on_timeouts[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES]; 1622 __le32 full_on_timeouts[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES];
1619} __packed; /* SF_CFG_API_S_VER_2 */ 1623} __packed; /* SF_CFG_API_S_VER_2 */
1620 1624
1625/* DTS measurements */
1626
1627enum iwl_dts_measurement_flags {
1628 DTS_TRIGGER_CMD_FLAGS_TEMP = BIT(0),
1629 DTS_TRIGGER_CMD_FLAGS_VOLT = BIT(1),
1630};
1631
1632/**
1633 * iwl_dts_measurement_cmd - request DTS temperature and/or voltage measurements
1634 *
1635 * @flags: indicates which measurements we want as specified in &enum
1636 * iwl_dts_measurement_flags
1637 */
1638struct iwl_dts_measurement_cmd {
1639 __le32 flags;
1640} __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_CMD_S */
1641
1642/**
1643 * iwl_dts_measurement_notif - notification received with the measurements
1644 *
1645 * @temp: the measured temperature
1646 * @voltage: the measured voltage
1647 */
1648struct iwl_dts_measurement_notif {
1649 __le32 temp;
1650 __le32 voltage;
1651} __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_NTFY_S */
1652
1621#endif /* __fw_api_h__ */ 1653#endif /* __fw_api_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 089d7b37cf90..5c33d2d15488 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -815,12 +815,11 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
815 mvm->rx_ba_sessions = 0; 815 mvm->rx_ba_sessions = 0;
816} 816}
817 817
818static int iwl_mvm_mac_start(struct ieee80211_hw *hw) 818int __iwl_mvm_mac_start(struct iwl_mvm *mvm)
819{ 819{
820 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
821 int ret; 820 int ret;
822 821
823 mutex_lock(&mvm->mutex); 822 lockdep_assert_held(&mvm->mutex);
824 823
825 /* Clean up some internal and mac80211 state on restart */ 824 /* Clean up some internal and mac80211 state on restart */
826 if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) 825 if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
@@ -837,6 +836,16 @@ static int iwl_mvm_mac_start(struct ieee80211_hw *hw)
837 iwl_mvm_d0i3_enable_tx(mvm, NULL); 836 iwl_mvm_d0i3_enable_tx(mvm, NULL);
838 } 837 }
839 838
839 return ret;
840}
841
842static int iwl_mvm_mac_start(struct ieee80211_hw *hw)
843{
844 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
845 int ret;
846
847 mutex_lock(&mvm->mutex);
848 ret = __iwl_mvm_mac_start(mvm);
840 mutex_unlock(&mvm->mutex); 849 mutex_unlock(&mvm->mutex);
841 850
842 return ret; 851 return ret;
@@ -862,14 +871,9 @@ static void iwl_mvm_mac_restart_complete(struct ieee80211_hw *hw)
862 mutex_unlock(&mvm->mutex); 871 mutex_unlock(&mvm->mutex);
863} 872}
864 873
865static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) 874void __iwl_mvm_mac_stop(struct iwl_mvm *mvm)
866{ 875{
867 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 876 lockdep_assert_held(&mvm->mutex);
868
869 flush_work(&mvm->d0i3_exit_work);
870 flush_work(&mvm->async_handlers_wk);
871
872 mutex_lock(&mvm->mutex);
873 877
874 /* disallow low power states when the FW is down */ 878 /* disallow low power states when the FW is down */
875 iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); 879 iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
@@ -891,7 +895,17 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
891 iwl_mvm_del_aux_sta(mvm); 895 iwl_mvm_del_aux_sta(mvm);
892 896
893 mvm->ucode_loaded = false; 897 mvm->ucode_loaded = false;
898}
894 899
900static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
901{
902 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
903
904 flush_work(&mvm->d0i3_exit_work);
905 flush_work(&mvm->async_handlers_wk);
906
907 mutex_lock(&mvm->mutex);
908 __iwl_mvm_mac_stop(mvm);
895 mutex_unlock(&mvm->mutex); 909 mutex_unlock(&mvm->mutex);
896 910
897 /* 911 /*
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index 4b1db9a3e65c..a36fa6c658d3 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -792,6 +792,9 @@ struct iwl_rate_info {
792 u8 ieee; /* MAC header: IWL_RATE_6M_IEEE, etc. */ 792 u8 ieee; /* MAC header: IWL_RATE_6M_IEEE, etc. */
793}; 793};
794 794
795void __iwl_mvm_mac_stop(struct iwl_mvm *mvm);
796int __iwl_mvm_mac_start(struct iwl_mvm *mvm);
797
795/****************** 798/******************
796 * MVM Methods 799 * MVM Methods
797 ******************/ 800 ******************/
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
index 5d8c562d1a78..9710084ad286 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -332,6 +332,8 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = {
332 CMD(BCAST_FILTER_CMD), 332 CMD(BCAST_FILTER_CMD),
333 CMD(REPLY_SF_CFG_CMD), 333 CMD(REPLY_SF_CFG_CMD),
334 CMD(REPLY_BEACON_FILTERING_CMD), 334 CMD(REPLY_BEACON_FILTERING_CMD),
335 CMD(CMD_DTS_MEASUREMENT_TRIGGER),
336 CMD(DTS_MEASUREMENT_NOTIFICATION),
335 CMD(REPLY_THERMAL_MNG_BACKOFF), 337 CMD(REPLY_THERMAL_MNG_BACKOFF),
336 CMD(MAC_PM_POWER_TABLE), 338 CMD(MAC_PM_POWER_TABLE),
337 CMD(BT_COEX_CI), 339 CMD(BT_COEX_CI),
diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c
index c3e1fe4282f1..c750ca7b8269 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tt.c
@@ -69,275 +69,99 @@
69#include "iwl-csr.h" 69#include "iwl-csr.h"
70#include "iwl-prph.h" 70#include "iwl-prph.h"
71 71
72#define OTP_DTS_DIODE_DEVIATION 96 /*in words*/ 72#define IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT HZ
73/* VBG - Voltage Band Gap error data (temperature offset) */
74#define OTP_WP_DTS_VBG (OTP_DTS_DIODE_DEVIATION + 2)
75#define MEAS_VBG_MIN_VAL 2300
76#define MEAS_VBG_MAX_VAL 3000
77#define MEAS_VBG_DEFAULT_VAL 2700
78#define DTS_DIODE_VALID(flags) (flags & DTS_DIODE_REG_FLAGS_PASS_ONCE)
79#define MIN_TEMPERATURE 0
80#define MAX_TEMPERATURE 125
81#define TEMPERATURE_ERROR (MAX_TEMPERATURE + 1)
82#define PTAT_DIGITAL_VALUE_MIN_VALUE 0
83#define PTAT_DIGITAL_VALUE_MAX_VALUE 0xFF
84#define DTS_VREFS_NUM 5
85static inline u32 DTS_DIODE_GET_VREFS_ID(u32 flags)
86{
87 return (flags & DTS_DIODE_REG_FLAGS_VREFS_ID) >>
88 DTS_DIODE_REG_FLAGS_VREFS_ID_POS;
89}
90 73
91#define CALC_VREFS_MIN_DIFF 43 74static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm)
92#define CALC_VREFS_MAX_DIFF 51
93#define CALC_LUT_SIZE (1 + CALC_VREFS_MAX_DIFF - CALC_VREFS_MIN_DIFF)
94#define CALC_LUT_INDEX_OFFSET CALC_VREFS_MIN_DIFF
95#define CALC_TEMPERATURE_RESULT_SHIFT_OFFSET 23
96
97/*
98 * @digital_value: The diode's digital-value sampled (temperature/voltage)
99 * @vref_low: The lower voltage-reference (the vref just below the diode's
100 * sampled digital-value)
101 * @vref_high: The higher voltage-reference (the vref just above the diode's
102 * sampled digital-value)
103 * @flags: bits[1:0]: The ID of the Vrefs pair (lowVref,highVref)
104 * bits[6:2]: Reserved.
105 * bits[7:7]: Indicates completion of at least 1 successful sample
106 * since last DTS reset.
107 */
108struct iwl_mvm_dts_diode_bits {
109 u8 digital_value;
110 u8 vref_low;
111 u8 vref_high;
112 u8 flags;
113} __packed;
114
115union dts_diode_results {
116 u32 reg_value;
117 struct iwl_mvm_dts_diode_bits bits;
118} __packed;
119
120static s16 iwl_mvm_dts_get_volt_band_gap(struct iwl_mvm *mvm)
121{ 75{
122 struct iwl_nvm_section calib_sec; 76 u32 duration = mvm->thermal_throttle.params->ct_kill_duration;
123 const __le16 *calib;
124 u16 vbg;
125
126 /* TODO: move parsing to NVM code */
127 calib_sec = mvm->nvm_sections[NVM_SECTION_TYPE_CALIBRATION];
128 calib = (__le16 *)calib_sec.data;
129 77
130 vbg = le16_to_cpu(calib[OTP_WP_DTS_VBG]); 78 if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status))
79 return;
131 80
132 if (vbg < MEAS_VBG_MIN_VAL || vbg > MEAS_VBG_MAX_VAL) 81 IWL_ERR(mvm, "Enter CT Kill\n");
133 vbg = MEAS_VBG_DEFAULT_VAL; 82 iwl_mvm_set_hw_ctkill_state(mvm, true);
134 83
135 return vbg; 84 /* Don't schedule an exit work if we're in test mode, since
85 * the temperature will not change unless we manually set it
86 * again (or disable testing).
87 */
88 if (!mvm->temperature_test)
89 schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit,
90 round_jiffies_relative(duration * HZ));
136} 91}
137 92
138static u16 iwl_mvm_dts_get_ptat_deviation_offset(struct iwl_mvm *mvm) 93static void iwl_mvm_exit_ctkill(struct iwl_mvm *mvm)
139{ 94{
140 const u8 *calib; 95 if (!test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status))
141 u8 ptat, pa1, pa2, median; 96 return;
142
143 /* TODO: move parsing to NVM code */
144 calib = mvm->nvm_sections[NVM_SECTION_TYPE_CALIBRATION].data;
145 ptat = calib[OTP_DTS_DIODE_DEVIATION * 2];
146 pa1 = calib[OTP_DTS_DIODE_DEVIATION * 2 + 1];
147 pa2 = calib[OTP_DTS_DIODE_DEVIATION * 2 + 2];
148
149 /* get the median: */
150 if (ptat > pa1) {
151 if (ptat > pa2)
152 median = (pa1 > pa2) ? pa1 : pa2;
153 else
154 median = ptat;
155 } else {
156 if (pa1 > pa2)
157 median = (ptat > pa2) ? ptat : pa2;
158 else
159 median = pa1;
160 }
161 97
162 return ptat - median; 98 IWL_ERR(mvm, "Exit CT Kill\n");
99 iwl_mvm_set_hw_ctkill_state(mvm, false);
163} 100}
164 101
165static u8 iwl_mvm_dts_calibrate_ptat_deviation(struct iwl_mvm *mvm, u8 value) 102static bool iwl_mvm_temp_notif(struct iwl_notif_wait_data *notif_wait,
103 struct iwl_rx_packet *pkt, void *data)
166{ 104{
167 /* Calibrate the PTAT digital value, based on PTAT deviation data: */ 105 struct iwl_mvm *mvm =
168 s16 new_val = value - iwl_mvm_dts_get_ptat_deviation_offset(mvm); 106 container_of(notif_wait, struct iwl_mvm, notif_wait);
107 int *temp = data;
108 struct iwl_dts_measurement_notif *notif;
109 int len = iwl_rx_packet_payload_len(pkt);
110
111 if (WARN_ON_ONCE(len != sizeof(*notif))) {
112 IWL_ERR(mvm, "Invalid DTS_MEASUREMENT_NOTIFICATION\n");
113 return true;
114 }
169 115
170 if (new_val > PTAT_DIGITAL_VALUE_MAX_VALUE) 116 notif = (void *)pkt->data;
171 new_val = PTAT_DIGITAL_VALUE_MAX_VALUE;
172 else if (new_val < PTAT_DIGITAL_VALUE_MIN_VALUE)
173 new_val = PTAT_DIGITAL_VALUE_MIN_VALUE;
174 117
175 return new_val; 118 *temp = le32_to_cpu(notif->temp);
176}
177 119
178static bool dts_get_adjacent_vrefs(struct iwl_mvm *mvm, 120 /* shouldn't be negative, but since it's s32, make sure it isn't */
179 union dts_diode_results *avg_ptat) 121 if (WARN_ON_ONCE(*temp < 0))
180{ 122 *temp = 0;
181 u8 vrefs_results[DTS_VREFS_NUM];
182 u8 low_vref_index = 0, flags;
183 u32 reg;
184
185 reg = iwl_read_prph(mvm->trans, DTSC_VREF_AVG);
186 memcpy(vrefs_results, &reg, sizeof(reg));
187 reg = iwl_read_prph(mvm->trans, DTSC_VREF5_AVG);
188 vrefs_results[4] = reg & 0xff;
189
190 if (avg_ptat->bits.digital_value < vrefs_results[0] ||
191 avg_ptat->bits.digital_value > vrefs_results[4])
192 return false;
193
194 if (avg_ptat->bits.digital_value > vrefs_results[3])
195 low_vref_index = 3;
196 else if (avg_ptat->bits.digital_value > vrefs_results[2])
197 low_vref_index = 2;
198 else if (avg_ptat->bits.digital_value > vrefs_results[1])
199 low_vref_index = 1;
200
201 avg_ptat->bits.vref_low = vrefs_results[low_vref_index];
202 avg_ptat->bits.vref_high = vrefs_results[low_vref_index + 1];
203 flags = avg_ptat->bits.flags;
204 avg_ptat->bits.flags =
205 (flags & ~DTS_DIODE_REG_FLAGS_VREFS_ID) |
206 (low_vref_index & DTS_DIODE_REG_FLAGS_VREFS_ID);
207 return true;
208}
209 123
210/* 124 IWL_DEBUG_TEMP(mvm, "DTS_MEASUREMENT_NOTIFICATION - %d\n", *temp);
211 * return true it the results are valid, and false otherwise. 125 return true;
212 */
213static bool dts_read_ptat_avg_results(struct iwl_mvm *mvm,
214 union dts_diode_results *avg_ptat)
215{
216 u32 reg;
217 u8 tmp;
218
219 /* fill the diode value and pass_once with avg-reg results */
220 reg = iwl_read_prph(mvm->trans, DTSC_PTAT_AVG);
221 reg &= DTS_DIODE_REG_DIG_VAL | DTS_DIODE_REG_PASS_ONCE;
222 avg_ptat->reg_value = reg;
223
224 /* calibrate the PTAT digital value */
225 tmp = avg_ptat->bits.digital_value;
226 tmp = iwl_mvm_dts_calibrate_ptat_deviation(mvm, tmp);
227 avg_ptat->bits.digital_value = tmp;
228
229 /*
230 * fill vrefs fields, based on the avgVrefs results
231 * and the diode value
232 */
233 return dts_get_adjacent_vrefs(mvm, avg_ptat) &&
234 DTS_DIODE_VALID(avg_ptat->bits.flags);
235} 126}
236 127
237static s32 calculate_nic_temperature(union dts_diode_results avg_ptat, 128static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm)
238 u16 volt_band_gap)
239{ 129{
240 u32 tmp_result; 130 struct iwl_dts_measurement_cmd cmd = {
241 u8 vrefs_diff; 131 .flags = cpu_to_le32(DTS_TRIGGER_CMD_FLAGS_TEMP),
242 /*
243 * For temperature calculation (at the end, shift right by 23)
244 * LUT[(D2-D1)] = ROUND{ 2^23 / ((D2-D1)*9*10) }
245 * (D2-D1) == 43 44 45 46 47 48 49 50 51
246 */
247 static const u16 calc_lut[CALC_LUT_SIZE] = {
248 2168, 2118, 2071, 2026, 1983, 1942, 1902, 1864, 1828,
249 }; 132 };
250 133
251 /* 134 return iwl_mvm_send_cmd_pdu(mvm, CMD_DTS_MEASUREMENT_TRIGGER, 0,
252 * The diff between the high and low voltage-references is assumed 135 sizeof(cmd), &cmd);
253 * to be strictly be in range of [60,68]
254 */
255 vrefs_diff = avg_ptat.bits.vref_high - avg_ptat.bits.vref_low;
256
257 if (vrefs_diff < CALC_VREFS_MIN_DIFF ||
258 vrefs_diff > CALC_VREFS_MAX_DIFF)
259 return TEMPERATURE_ERROR;
260
261 /* calculate the result: */
262 tmp_result =
263 vrefs_diff * (DTS_DIODE_GET_VREFS_ID(avg_ptat.bits.flags) + 9);
264 tmp_result += avg_ptat.bits.digital_value;
265 tmp_result -= avg_ptat.bits.vref_high;
266
267 /* multiply by the LUT value (based on the diff) */
268 tmp_result *= calc_lut[vrefs_diff - CALC_LUT_INDEX_OFFSET];
269
270 /*
271 * Get the BandGap (the voltage refereces source) error data
272 * (temperature offset)
273 */
274 tmp_result *= volt_band_gap;
275
276 /*
277 * here, tmp_result value can be up to 32-bits. We want to right-shift
278 * it *without* sign-extend.
279 */
280 tmp_result = tmp_result >> CALC_TEMPERATURE_RESULT_SHIFT_OFFSET;
281
282 /*
283 * at this point, tmp_result should be in the range:
284 * 200 <= tmp_result <= 365
285 */
286 return (s16)tmp_result - 240;
287}
288
289static s32 check_nic_temperature(struct iwl_mvm *mvm)
290{
291 u16 volt_band_gap;
292 union dts_diode_results avg_ptat;
293
294 volt_band_gap = iwl_mvm_dts_get_volt_band_gap(mvm);
295
296 /* disable DTS */
297 iwl_write_prph(mvm->trans, SHR_MISC_WFM_DTS_EN, 0);
298
299 /* SV initialization */
300 iwl_write_prph(mvm->trans, SHR_MISC_WFM_DTS_EN, 1);
301 iwl_write_prph(mvm->trans, DTSC_CFG_MODE,
302 DTSC_CFG_MODE_PERIODIC);
303
304 /* wait for results */
305 msleep(100);
306 if (!dts_read_ptat_avg_results(mvm, &avg_ptat))
307 return TEMPERATURE_ERROR;
308
309 /* disable DTS */
310 iwl_write_prph(mvm->trans, SHR_MISC_WFM_DTS_EN, 0);
311
312 return calculate_nic_temperature(avg_ptat, volt_band_gap);
313} 136}
314 137
315static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm) 138static int iwl_mvm_get_temp(struct iwl_mvm *mvm)
316{ 139{
317 u32 duration = mvm->thermal_throttle.params->ct_kill_duration; 140 struct iwl_notification_wait wait_temp_notif;
141 static const u8 temp_notif[] = { DTS_MEASUREMENT_NOTIFICATION };
142 int ret, temp;
318 143
319 if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) 144 lockdep_assert_held(&mvm->mutex);
320 return;
321 145
322 IWL_ERR(mvm, "Enter CT Kill\n"); 146 iwl_init_notification_wait(&mvm->notif_wait, &wait_temp_notif,
323 iwl_mvm_set_hw_ctkill_state(mvm, true); 147 temp_notif, ARRAY_SIZE(temp_notif),
148 iwl_mvm_temp_notif, &temp);
324 149
325 /* Don't schedule an exit work if we're in test mode, since 150 ret = iwl_mvm_get_temp_cmd(mvm);
326 * the temperature will not change unless we manually set it 151 if (ret) {
327 * again (or disable testing). 152 IWL_ERR(mvm, "Failed to get the temperature (err=%d)\n", ret);
328 */ 153 iwl_remove_notification(&mvm->notif_wait, &wait_temp_notif);
329 if (!mvm->temperature_test) 154 return ret;
330 schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit, 155 }
331 round_jiffies_relative(duration * HZ));
332}
333 156
334static void iwl_mvm_exit_ctkill(struct iwl_mvm *mvm) 157 ret = iwl_wait_notification(&mvm->notif_wait, &wait_temp_notif,
335{ 158 IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT);
336 if (!test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) 159 if (ret) {
337 return; 160 IWL_ERR(mvm, "Getting the temperature timed out\n");
161 return ret;
162 }
338 163
339 IWL_ERR(mvm, "Exit CT Kill\n"); 164 return temp;
340 iwl_mvm_set_hw_ctkill_state(mvm, false);
341} 165}
342 166
343static void check_exit_ctkill(struct work_struct *work) 167static void check_exit_ctkill(struct work_struct *work)
@@ -352,28 +176,36 @@ static void check_exit_ctkill(struct work_struct *work)
352 176
353 duration = tt->params->ct_kill_duration; 177 duration = tt->params->ct_kill_duration;
354 178
179 mutex_lock(&mvm->mutex);
180
181 if (__iwl_mvm_mac_start(mvm))
182 goto reschedule;
183
355 /* make sure the device is available for direct read/writes */ 184 /* make sure the device is available for direct read/writes */
356 if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_CHECK_CTKILL)) 185 if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_CHECK_CTKILL)) {
186 __iwl_mvm_mac_stop(mvm);
357 goto reschedule; 187 goto reschedule;
188 }
358 189
359 iwl_trans_start_hw(mvm->trans); 190 temp = iwl_mvm_get_temp(mvm);
360 temp = check_nic_temperature(mvm);
361 iwl_trans_stop_device(mvm->trans);
362 191
363 iwl_mvm_unref(mvm, IWL_MVM_REF_CHECK_CTKILL); 192 iwl_mvm_unref(mvm, IWL_MVM_REF_CHECK_CTKILL);
364 193
365 if (temp < MIN_TEMPERATURE || temp > MAX_TEMPERATURE) { 194 __iwl_mvm_mac_stop(mvm);
366 IWL_DEBUG_TEMP(mvm, "Failed to measure NIC temperature\n"); 195
196 if (temp < 0)
367 goto reschedule; 197 goto reschedule;
368 } 198
369 IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", temp); 199 IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", temp);
370 200
371 if (temp <= tt->params->ct_kill_exit) { 201 if (temp <= tt->params->ct_kill_exit) {
202 mutex_unlock(&mvm->mutex);
372 iwl_mvm_exit_ctkill(mvm); 203 iwl_mvm_exit_ctkill(mvm);
373 return; 204 return;
374 } 205 }
375 206
376reschedule: 207reschedule:
208 mutex_unlock(&mvm->mutex);
377 schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit, 209 schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit,
378 round_jiffies(duration * HZ)); 210 round_jiffies(duration * HZ));
379} 211}