diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/fw-api.h | 32 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mac80211.c | 34 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mvm.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/ops.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/tt.c | 326 |
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 | |||
1627 | enum 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 | */ | ||
1638 | struct 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 | */ | ||
1648 | struct 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 | ||
818 | static int iwl_mvm_mac_start(struct ieee80211_hw *hw) | 818 | int __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 | |||
842 | static 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 | ||
865 | static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) | 874 | void __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 | ||
900 | static 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 | ||
795 | void __iwl_mvm_mac_stop(struct iwl_mvm *mvm); | ||
796 | int __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 | ||
85 | static 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 | 74 | static 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 | */ | ||
108 | struct iwl_mvm_dts_diode_bits { | ||
109 | u8 digital_value; | ||
110 | u8 vref_low; | ||
111 | u8 vref_high; | ||
112 | u8 flags; | ||
113 | } __packed; | ||
114 | |||
115 | union dts_diode_results { | ||
116 | u32 reg_value; | ||
117 | struct iwl_mvm_dts_diode_bits bits; | ||
118 | } __packed; | ||
119 | |||
120 | static 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 | ||
138 | static u16 iwl_mvm_dts_get_ptat_deviation_offset(struct iwl_mvm *mvm) | 93 | static 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 | ||
165 | static u8 iwl_mvm_dts_calibrate_ptat_deviation(struct iwl_mvm *mvm, u8 value) | 102 | static 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 | ||
178 | static 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, ®, 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 | */ | ||
213 | static 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 | ||
237 | static s32 calculate_nic_temperature(union dts_diode_results avg_ptat, | 128 | static 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 | |||
289 | static 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 | ||
315 | static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm) | 138 | static 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 | ||
334 | static 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 | ||
343 | static void check_exit_ctkill(struct work_struct *work) | 167 | static 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 | ||
376 | reschedule: | 207 | reschedule: |
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 | } |