tt.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915
  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. * You should have received a copy of the GNU General Public License
  22. * along with this program; if not, write to the Free Software
  23. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
  24. * USA
  25. *
  26. * The full GNU General Public License is included in this distribution
  27. * in the file called COPYING.
  28. *
  29. * Contact Information:
  30. * Intel Linux Wireless <linuxwifi@intel.com>
  31. * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  32. *
  33. * BSD LICENSE
  34. *
  35. * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  36. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  37. * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
  38. * All rights reserved.
  39. *
  40. * Redistribution and use in source and binary forms, with or without
  41. * modification, are permitted provided that the following conditions
  42. * are met:
  43. *
  44. * * Redistributions of source code must retain the above copyright
  45. * notice, this list of conditions and the following disclaimer.
  46. * * Redistributions in binary form must reproduce the above copyright
  47. * notice, this list of conditions and the following disclaimer in
  48. * the documentation and/or other materials provided with the
  49. * distribution.
  50. * * Neither the name Intel Corporation nor the names of its
  51. * contributors may be used to endorse or promote products derived
  52. * from this software without specific prior written permission.
  53. *
  54. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  55. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  56. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  57. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  58. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  59. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  60. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  61. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  62. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  63. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  64. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  65. *
  66. *****************************************************************************/
  67. #include <linux/sort.h>
  68. #include "mvm.h"
  69. #define IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT HZ
  70. static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm)
  71. {
  72. struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle;
  73. u32 duration = tt->params.ct_kill_duration;
  74. if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status))
  75. return;
  76. IWL_ERR(mvm, "Enter CT Kill\n");
  77. iwl_mvm_set_hw_ctkill_state(mvm, true);
  78. if (!iwl_mvm_is_tt_in_fw(mvm)) {
  79. tt->throttle = false;
  80. tt->dynamic_smps = false;
  81. }
  82. /* Don't schedule an exit work if we're in test mode, since
  83. * the temperature will not change unless we manually set it
  84. * again (or disable testing).
  85. */
  86. if (!mvm->temperature_test)
  87. schedule_delayed_work(&tt->ct_kill_exit,
  88. round_jiffies_relative(duration * HZ));
  89. }
  90. static void iwl_mvm_exit_ctkill(struct iwl_mvm *mvm)
  91. {
  92. if (!test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status))
  93. return;
  94. IWL_ERR(mvm, "Exit CT Kill\n");
  95. iwl_mvm_set_hw_ctkill_state(mvm, false);
  96. }
  97. void iwl_mvm_tt_temp_changed(struct iwl_mvm *mvm, u32 temp)
  98. {
  99. /* ignore the notification if we are in test mode */
  100. if (mvm->temperature_test)
  101. return;
  102. if (mvm->temperature == temp)
  103. return;
  104. mvm->temperature = temp;
  105. iwl_mvm_tt_handler(mvm);
  106. }
  107. static int iwl_mvm_temp_notif_parse(struct iwl_mvm *mvm,
  108. struct iwl_rx_packet *pkt)
  109. {
  110. struct iwl_dts_measurement_notif_v1 *notif_v1;
  111. int len = iwl_rx_packet_payload_len(pkt);
  112. int temp;
  113. /* we can use notif_v1 only, because v2 only adds an additional
  114. * parameter, which is not used in this function.
  115. */
  116. if (WARN_ON_ONCE(len < sizeof(*notif_v1))) {
  117. IWL_ERR(mvm, "Invalid DTS_MEASUREMENT_NOTIFICATION\n");
  118. return -EINVAL;
  119. }
  120. notif_v1 = (void *)pkt->data;
  121. temp = le32_to_cpu(notif_v1->temp);
  122. /* shouldn't be negative, but since it's s32, make sure it isn't */
  123. if (WARN_ON_ONCE(temp < 0))
  124. temp = 0;
  125. IWL_DEBUG_TEMP(mvm, "DTS_MEASUREMENT_NOTIFICATION - %d\n", temp);
  126. return temp;
  127. }
  128. static bool iwl_mvm_temp_notif_wait(struct iwl_notif_wait_data *notif_wait,
  129. struct iwl_rx_packet *pkt, void *data)
  130. {
  131. struct iwl_mvm *mvm =
  132. container_of(notif_wait, struct iwl_mvm, notif_wait);
  133. int *temp = data;
  134. int ret;
  135. ret = iwl_mvm_temp_notif_parse(mvm, pkt);
  136. if (ret < 0)
  137. return true;
  138. *temp = ret;
  139. return true;
  140. }
  141. void iwl_mvm_temp_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
  142. {
  143. struct iwl_rx_packet *pkt = rxb_addr(rxb);
  144. struct iwl_dts_measurement_notif_v2 *notif_v2;
  145. int len = iwl_rx_packet_payload_len(pkt);
  146. int temp;
  147. u32 ths_crossed;
  148. /* the notification is handled synchronously in ctkill, so skip here */
  149. if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status))
  150. return;
  151. temp = iwl_mvm_temp_notif_parse(mvm, pkt);
  152. if (!iwl_mvm_is_tt_in_fw(mvm)) {
  153. if (temp >= 0)
  154. iwl_mvm_tt_temp_changed(mvm, temp);
  155. return;
  156. }
  157. if (WARN_ON_ONCE(len < sizeof(*notif_v2))) {
  158. IWL_ERR(mvm, "Invalid DTS_MEASUREMENT_NOTIFICATION\n");
  159. return;
  160. }
  161. notif_v2 = (void *)pkt->data;
  162. ths_crossed = le32_to_cpu(notif_v2->threshold_idx);
  163. /* 0xFF in ths_crossed means the notification is not related
  164. * to a trip, so we can ignore it here.
  165. */
  166. if (ths_crossed == 0xFF)
  167. return;
  168. IWL_DEBUG_TEMP(mvm, "Temp = %d Threshold crossed = %d\n",
  169. temp, ths_crossed);
  170. #ifdef CONFIG_THERMAL
  171. if (WARN_ON(ths_crossed >= IWL_MAX_DTS_TRIPS))
  172. return;
  173. /*
  174. * We are now handling a temperature notification from the firmware
  175. * in ASYNC and hold the mutex. thermal_notify_framework will call
  176. * us back through get_temp() which ought to send a SYNC command to
  177. * the firmware and hence to take the mutex.
  178. * Avoid the deadlock by unlocking the mutex here.
  179. */
  180. if (mvm->tz_device.tzone) {
  181. struct iwl_mvm_thermal_device *tz_dev = &mvm->tz_device;
  182. mutex_unlock(&mvm->mutex);
  183. thermal_notify_framework(tz_dev->tzone,
  184. tz_dev->fw_trips_index[ths_crossed]);
  185. mutex_lock(&mvm->mutex);
  186. }
  187. #endif /* CONFIG_THERMAL */
  188. }
  189. void iwl_mvm_ct_kill_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
  190. {
  191. struct iwl_rx_packet *pkt = rxb_addr(rxb);
  192. struct ct_kill_notif *notif;
  193. int len = iwl_rx_packet_payload_len(pkt);
  194. if (WARN_ON_ONCE(len != sizeof(*notif))) {
  195. IWL_ERR(mvm, "Invalid CT_KILL_NOTIFICATION\n");
  196. return;
  197. }
  198. notif = (struct ct_kill_notif *)pkt->data;
  199. IWL_DEBUG_TEMP(mvm, "CT Kill notification temperature = %d\n",
  200. notif->temperature);
  201. iwl_mvm_enter_ctkill(mvm);
  202. }
  203. static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm)
  204. {
  205. struct iwl_dts_measurement_cmd cmd = {
  206. .flags = cpu_to_le32(DTS_TRIGGER_CMD_FLAGS_TEMP),
  207. };
  208. struct iwl_ext_dts_measurement_cmd extcmd = {
  209. .control_mode = cpu_to_le32(DTS_AUTOMATIC),
  210. };
  211. u32 cmdid;
  212. if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_WIDE_CMD_HDR))
  213. cmdid = iwl_cmd_id(CMD_DTS_MEASUREMENT_TRIGGER_WIDE,
  214. PHY_OPS_GROUP, 0);
  215. else
  216. cmdid = CMD_DTS_MEASUREMENT_TRIGGER;
  217. if (!fw_has_capa(&mvm->fw->ucode_capa,
  218. IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE))
  219. return iwl_mvm_send_cmd_pdu(mvm, cmdid, 0, sizeof(cmd), &cmd);
  220. return iwl_mvm_send_cmd_pdu(mvm, cmdid, 0, sizeof(extcmd), &extcmd);
  221. }
  222. int iwl_mvm_get_temp(struct iwl_mvm *mvm, s32 *temp)
  223. {
  224. struct iwl_notification_wait wait_temp_notif;
  225. static u16 temp_notif[] = { WIDE_ID(PHY_OPS_GROUP,
  226. DTS_MEASUREMENT_NOTIF_WIDE) };
  227. int ret;
  228. if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_WIDE_CMD_HDR))
  229. temp_notif[0] = DTS_MEASUREMENT_NOTIFICATION;
  230. lockdep_assert_held(&mvm->mutex);
  231. iwl_init_notification_wait(&mvm->notif_wait, &wait_temp_notif,
  232. temp_notif, ARRAY_SIZE(temp_notif),
  233. iwl_mvm_temp_notif_wait, temp);
  234. ret = iwl_mvm_get_temp_cmd(mvm);
  235. if (ret) {
  236. IWL_ERR(mvm, "Failed to get the temperature (err=%d)\n", ret);
  237. iwl_remove_notification(&mvm->notif_wait, &wait_temp_notif);
  238. return ret;
  239. }
  240. ret = iwl_wait_notification(&mvm->notif_wait, &wait_temp_notif,
  241. IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT);
  242. if (ret)
  243. IWL_ERR(mvm, "Getting the temperature timed out\n");
  244. return ret;
  245. }
  246. static void check_exit_ctkill(struct work_struct *work)
  247. {
  248. struct iwl_mvm_tt_mgmt *tt;
  249. struct iwl_mvm *mvm;
  250. u32 duration;
  251. s32 temp;
  252. int ret;
  253. tt = container_of(work, struct iwl_mvm_tt_mgmt, ct_kill_exit.work);
  254. mvm = container_of(tt, struct iwl_mvm, thermal_throttle);
  255. if (iwl_mvm_is_tt_in_fw(mvm)) {
  256. iwl_mvm_exit_ctkill(mvm);
  257. return;
  258. }
  259. duration = tt->params.ct_kill_duration;
  260. mutex_lock(&mvm->mutex);
  261. if (__iwl_mvm_mac_start(mvm))
  262. goto reschedule;
  263. /* make sure the device is available for direct read/writes */
  264. if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_CHECK_CTKILL)) {
  265. __iwl_mvm_mac_stop(mvm);
  266. goto reschedule;
  267. }
  268. ret = iwl_mvm_get_temp(mvm, &temp);
  269. iwl_mvm_unref(mvm, IWL_MVM_REF_CHECK_CTKILL);
  270. __iwl_mvm_mac_stop(mvm);
  271. if (ret)
  272. goto reschedule;
  273. IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", temp);
  274. if (temp <= tt->params.ct_kill_exit) {
  275. mutex_unlock(&mvm->mutex);
  276. iwl_mvm_exit_ctkill(mvm);
  277. return;
  278. }
  279. reschedule:
  280. mutex_unlock(&mvm->mutex);
  281. schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit,
  282. round_jiffies(duration * HZ));
  283. }
  284. static void iwl_mvm_tt_smps_iterator(void *_data, u8 *mac,
  285. struct ieee80211_vif *vif)
  286. {
  287. struct iwl_mvm *mvm = _data;
  288. enum ieee80211_smps_mode smps_mode;
  289. lockdep_assert_held(&mvm->mutex);
  290. if (mvm->thermal_throttle.dynamic_smps)
  291. smps_mode = IEEE80211_SMPS_DYNAMIC;
  292. else
  293. smps_mode = IEEE80211_SMPS_AUTOMATIC;
  294. if (vif->type != NL80211_IFTYPE_STATION)
  295. return;
  296. iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_TT, smps_mode);
  297. }
  298. static void iwl_mvm_tt_tx_protection(struct iwl_mvm *mvm, bool enable)
  299. {
  300. struct ieee80211_sta *sta;
  301. struct iwl_mvm_sta *mvmsta;
  302. int i, err;
  303. for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
  304. sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
  305. lockdep_is_held(&mvm->mutex));
  306. if (IS_ERR_OR_NULL(sta))
  307. continue;
  308. mvmsta = iwl_mvm_sta_from_mac80211(sta);
  309. if (enable == mvmsta->tt_tx_protection)
  310. continue;
  311. err = iwl_mvm_tx_protection(mvm, mvmsta, enable);
  312. if (err) {
  313. IWL_ERR(mvm, "Failed to %s Tx protection\n",
  314. enable ? "enable" : "disable");
  315. } else {
  316. IWL_DEBUG_TEMP(mvm, "%s Tx protection\n",
  317. enable ? "Enable" : "Disable");
  318. mvmsta->tt_tx_protection = enable;
  319. }
  320. }
  321. }
  322. void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff)
  323. {
  324. struct iwl_host_cmd cmd = {
  325. .id = REPLY_THERMAL_MNG_BACKOFF,
  326. .len = { sizeof(u32), },
  327. .data = { &backoff, },
  328. };
  329. backoff = max(backoff, mvm->thermal_throttle.min_backoff);
  330. if (iwl_mvm_send_cmd(mvm, &cmd) == 0) {
  331. IWL_DEBUG_TEMP(mvm, "Set Thermal Tx backoff to: %u\n",
  332. backoff);
  333. mvm->thermal_throttle.tx_backoff = backoff;
  334. } else {
  335. IWL_ERR(mvm, "Failed to change Thermal Tx backoff\n");
  336. }
  337. }
  338. void iwl_mvm_tt_handler(struct iwl_mvm *mvm)
  339. {
  340. struct iwl_tt_params *params = &mvm->thermal_throttle.params;
  341. struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle;
  342. s32 temperature = mvm->temperature;
  343. bool throttle_enable = false;
  344. int i;
  345. u32 tx_backoff;
  346. IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", mvm->temperature);
  347. if (params->support_ct_kill && temperature >= params->ct_kill_entry) {
  348. iwl_mvm_enter_ctkill(mvm);
  349. return;
  350. }
  351. if (params->support_ct_kill &&
  352. temperature <= params->ct_kill_exit) {
  353. iwl_mvm_exit_ctkill(mvm);
  354. return;
  355. }
  356. if (params->support_dynamic_smps) {
  357. if (!tt->dynamic_smps &&
  358. temperature >= params->dynamic_smps_entry) {
  359. IWL_DEBUG_TEMP(mvm, "Enable dynamic SMPS\n");
  360. tt->dynamic_smps = true;
  361. ieee80211_iterate_active_interfaces_atomic(
  362. mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
  363. iwl_mvm_tt_smps_iterator, mvm);
  364. throttle_enable = true;
  365. } else if (tt->dynamic_smps &&
  366. temperature <= params->dynamic_smps_exit) {
  367. IWL_DEBUG_TEMP(mvm, "Disable dynamic SMPS\n");
  368. tt->dynamic_smps = false;
  369. ieee80211_iterate_active_interfaces_atomic(
  370. mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
  371. iwl_mvm_tt_smps_iterator, mvm);
  372. }
  373. }
  374. if (params->support_tx_protection) {
  375. if (temperature >= params->tx_protection_entry) {
  376. iwl_mvm_tt_tx_protection(mvm, true);
  377. throttle_enable = true;
  378. } else if (temperature <= params->tx_protection_exit) {
  379. iwl_mvm_tt_tx_protection(mvm, false);
  380. }
  381. }
  382. if (params->support_tx_backoff) {
  383. tx_backoff = tt->min_backoff;
  384. for (i = 0; i < TT_TX_BACKOFF_SIZE; i++) {
  385. if (temperature < params->tx_backoff[i].temperature)
  386. break;
  387. tx_backoff = max(tt->min_backoff,
  388. params->tx_backoff[i].backoff);
  389. }
  390. if (tx_backoff != tt->min_backoff)
  391. throttle_enable = true;
  392. if (tt->tx_backoff != tx_backoff)
  393. iwl_mvm_tt_tx_backoff(mvm, tx_backoff);
  394. }
  395. if (!tt->throttle && throttle_enable) {
  396. IWL_WARN(mvm,
  397. "Due to high temperature thermal throttling initiated\n");
  398. tt->throttle = true;
  399. } else if (tt->throttle && !tt->dynamic_smps &&
  400. tt->tx_backoff == tt->min_backoff &&
  401. temperature <= params->tx_protection_exit) {
  402. IWL_WARN(mvm,
  403. "Temperature is back to normal thermal throttling stopped\n");
  404. tt->throttle = false;
  405. }
  406. }
  407. static const struct iwl_tt_params iwl_mvm_default_tt_params = {
  408. .ct_kill_entry = 118,
  409. .ct_kill_exit = 96,
  410. .ct_kill_duration = 5,
  411. .dynamic_smps_entry = 114,
  412. .dynamic_smps_exit = 110,
  413. .tx_protection_entry = 114,
  414. .tx_protection_exit = 108,
  415. .tx_backoff = {
  416. {.temperature = 112, .backoff = 200},
  417. {.temperature = 113, .backoff = 600},
  418. {.temperature = 114, .backoff = 1200},
  419. {.temperature = 115, .backoff = 2000},
  420. {.temperature = 116, .backoff = 4000},
  421. {.temperature = 117, .backoff = 10000},
  422. },
  423. .support_ct_kill = true,
  424. .support_dynamic_smps = true,
  425. .support_tx_protection = true,
  426. .support_tx_backoff = true,
  427. };
  428. /* budget in mWatt */
  429. static const u32 iwl_mvm_cdev_budgets[] = {
  430. 2000, /* cooling state 0 */
  431. 1800, /* cooling state 1 */
  432. 1600, /* cooling state 2 */
  433. 1400, /* cooling state 3 */
  434. 1200, /* cooling state 4 */
  435. 1000, /* cooling state 5 */
  436. 900, /* cooling state 6 */
  437. 800, /* cooling state 7 */
  438. 700, /* cooling state 8 */
  439. 650, /* cooling state 9 */
  440. 600, /* cooling state 10 */
  441. 550, /* cooling state 11 */
  442. 500, /* cooling state 12 */
  443. 450, /* cooling state 13 */
  444. 400, /* cooling state 14 */
  445. 350, /* cooling state 15 */
  446. 300, /* cooling state 16 */
  447. 250, /* cooling state 17 */
  448. 200, /* cooling state 18 */
  449. 150, /* cooling state 19 */
  450. };
  451. int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 state)
  452. {
  453. struct iwl_mvm_ctdp_cmd cmd = {
  454. .operation = cpu_to_le32(op),
  455. .budget = cpu_to_le32(iwl_mvm_cdev_budgets[state]),
  456. .window_size = 0,
  457. };
  458. int ret;
  459. u32 status;
  460. lockdep_assert_held(&mvm->mutex);
  461. ret = iwl_mvm_send_cmd_pdu_status(mvm, WIDE_ID(PHY_OPS_GROUP,
  462. CTDP_CONFIG_CMD),
  463. sizeof(cmd), &cmd, &status);
  464. if (ret) {
  465. IWL_ERR(mvm, "cTDP command failed (err=%d)\n", ret);
  466. return ret;
  467. }
  468. switch (op) {
  469. case CTDP_CMD_OPERATION_START:
  470. #ifdef CONFIG_THERMAL
  471. mvm->cooling_dev.cur_state = state;
  472. #endif /* CONFIG_THERMAL */
  473. break;
  474. case CTDP_CMD_OPERATION_REPORT:
  475. IWL_DEBUG_TEMP(mvm, "cTDP avg energy in mWatt = %d\n", status);
  476. /* when the function is called with CTDP_CMD_OPERATION_REPORT
  477. * option the function should return the average budget value
  478. * that is received from the FW.
  479. * The budget can't be less or equal to 0, so it's possible
  480. * to distinguish between error values and budgets.
  481. */
  482. return status;
  483. case CTDP_CMD_OPERATION_STOP:
  484. IWL_DEBUG_TEMP(mvm, "cTDP stopped successfully\n");
  485. break;
  486. }
  487. return 0;
  488. }
  489. #ifdef CONFIG_THERMAL
  490. static int compare_temps(const void *a, const void *b)
  491. {
  492. return ((s16)le16_to_cpu(*(__le16 *)a) -
  493. (s16)le16_to_cpu(*(__le16 *)b));
  494. }
  495. int iwl_mvm_send_temp_report_ths_cmd(struct iwl_mvm *mvm)
  496. {
  497. struct temp_report_ths_cmd cmd = {0};
  498. int ret, i, j, idx = 0;
  499. lockdep_assert_held(&mvm->mutex);
  500. if (!mvm->tz_device.tzone)
  501. return -EINVAL;
  502. /* The driver holds array of temperature trips that are unsorted
  503. * and uncompressed, the FW should get it compressed and sorted
  504. */
  505. /* compress temp_trips to cmd array, remove uninitialized values*/
  506. for (i = 0; i < IWL_MAX_DTS_TRIPS; i++) {
  507. if (mvm->tz_device.temp_trips[i] != S16_MIN) {
  508. cmd.thresholds[idx++] =
  509. cpu_to_le16(mvm->tz_device.temp_trips[i]);
  510. }
  511. }
  512. cmd.num_temps = cpu_to_le32(idx);
  513. if (!idx)
  514. goto send;
  515. /*sort cmd array*/
  516. sort(cmd.thresholds, idx, sizeof(s16), compare_temps, NULL);
  517. /* we should save the indexes of trips because we sort
  518. * and compress the orginal array
  519. */
  520. for (i = 0; i < idx; i++) {
  521. for (j = 0; j < IWL_MAX_DTS_TRIPS; j++) {
  522. if (le16_to_cpu(cmd.thresholds[i]) ==
  523. mvm->tz_device.temp_trips[j])
  524. mvm->tz_device.fw_trips_index[i] = j;
  525. }
  526. }
  527. send:
  528. ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(PHY_OPS_GROUP,
  529. TEMP_REPORTING_THRESHOLDS_CMD),
  530. 0, sizeof(cmd), &cmd);
  531. if (ret)
  532. IWL_ERR(mvm, "TEMP_REPORT_THS_CMD command failed (err=%d)\n",
  533. ret);
  534. return ret;
  535. }
  536. static int iwl_mvm_tzone_get_temp(struct thermal_zone_device *device,
  537. int *temperature)
  538. {
  539. struct iwl_mvm *mvm = (struct iwl_mvm *)device->devdata;
  540. int ret;
  541. int temp;
  542. mutex_lock(&mvm->mutex);
  543. if (!mvm->ucode_loaded || !(mvm->cur_ucode == IWL_UCODE_REGULAR)) {
  544. ret = -EIO;
  545. goto out;
  546. }
  547. ret = iwl_mvm_get_temp(mvm, &temp);
  548. if (ret)
  549. goto out;
  550. *temperature = temp * 1000;
  551. out:
  552. mutex_unlock(&mvm->mutex);
  553. return ret;
  554. }
  555. static int iwl_mvm_tzone_get_trip_temp(struct thermal_zone_device *device,
  556. int trip, int *temp)
  557. {
  558. struct iwl_mvm *mvm = (struct iwl_mvm *)device->devdata;
  559. if (trip < 0 || trip >= IWL_MAX_DTS_TRIPS)
  560. return -EINVAL;
  561. *temp = mvm->tz_device.temp_trips[trip] * 1000;
  562. return 0;
  563. }
  564. static int iwl_mvm_tzone_get_trip_type(struct thermal_zone_device *device,
  565. int trip, enum thermal_trip_type *type)
  566. {
  567. if (trip < 0 || trip >= IWL_MAX_DTS_TRIPS)
  568. return -EINVAL;
  569. *type = THERMAL_TRIP_PASSIVE;
  570. return 0;
  571. }
  572. static int iwl_mvm_tzone_set_trip_temp(struct thermal_zone_device *device,
  573. int trip, int temp)
  574. {
  575. struct iwl_mvm *mvm = (struct iwl_mvm *)device->devdata;
  576. struct iwl_mvm_thermal_device *tzone;
  577. int i, ret;
  578. s16 temperature;
  579. mutex_lock(&mvm->mutex);
  580. if (!mvm->ucode_loaded || !(mvm->cur_ucode == IWL_UCODE_REGULAR)) {
  581. ret = -EIO;
  582. goto out;
  583. }
  584. if (trip < 0 || trip >= IWL_MAX_DTS_TRIPS) {
  585. ret = -EINVAL;
  586. goto out;
  587. }
  588. if ((temp / 1000) > S16_MAX) {
  589. ret = -EINVAL;
  590. goto out;
  591. }
  592. temperature = (s16)(temp / 1000);
  593. tzone = &mvm->tz_device;
  594. if (!tzone) {
  595. ret = -EIO;
  596. goto out;
  597. }
  598. /* no updates*/
  599. if (tzone->temp_trips[trip] == temperature) {
  600. ret = 0;
  601. goto out;
  602. }
  603. /* already existing temperature */
  604. for (i = 0; i < IWL_MAX_DTS_TRIPS; i++) {
  605. if (tzone->temp_trips[i] == temperature) {
  606. ret = -EINVAL;
  607. goto out;
  608. }
  609. }
  610. tzone->temp_trips[trip] = temperature;
  611. ret = iwl_mvm_send_temp_report_ths_cmd(mvm);
  612. out:
  613. mutex_unlock(&mvm->mutex);
  614. return ret;
  615. }
  616. static struct thermal_zone_device_ops tzone_ops = {
  617. .get_temp = iwl_mvm_tzone_get_temp,
  618. .get_trip_temp = iwl_mvm_tzone_get_trip_temp,
  619. .get_trip_type = iwl_mvm_tzone_get_trip_type,
  620. .set_trip_temp = iwl_mvm_tzone_set_trip_temp,
  621. };
  622. /* make all trips writable */
  623. #define IWL_WRITABLE_TRIPS_MSK (BIT(IWL_MAX_DTS_TRIPS) - 1)
  624. static void iwl_mvm_thermal_zone_register(struct iwl_mvm *mvm)
  625. {
  626. int i;
  627. char name[] = "iwlwifi";
  628. if (!iwl_mvm_is_tt_in_fw(mvm)) {
  629. mvm->tz_device.tzone = NULL;
  630. return;
  631. }
  632. BUILD_BUG_ON(ARRAY_SIZE(name) >= THERMAL_NAME_LENGTH);
  633. mvm->tz_device.tzone = thermal_zone_device_register(name,
  634. IWL_MAX_DTS_TRIPS,
  635. IWL_WRITABLE_TRIPS_MSK,
  636. mvm, &tzone_ops,
  637. NULL, 0, 0);
  638. if (IS_ERR(mvm->tz_device.tzone)) {
  639. IWL_DEBUG_TEMP(mvm,
  640. "Failed to register to thermal zone (err = %ld)\n",
  641. PTR_ERR(mvm->tz_device.tzone));
  642. mvm->tz_device.tzone = NULL;
  643. return;
  644. }
  645. /* 0 is a valid temperature,
  646. * so initialize the array with S16_MIN which invalid temperature
  647. */
  648. for (i = 0 ; i < IWL_MAX_DTS_TRIPS; i++)
  649. mvm->tz_device.temp_trips[i] = S16_MIN;
  650. }
  651. static int iwl_mvm_tcool_get_max_state(struct thermal_cooling_device *cdev,
  652. unsigned long *state)
  653. {
  654. *state = ARRAY_SIZE(iwl_mvm_cdev_budgets) - 1;
  655. return 0;
  656. }
  657. static int iwl_mvm_tcool_get_cur_state(struct thermal_cooling_device *cdev,
  658. unsigned long *state)
  659. {
  660. struct iwl_mvm *mvm = (struct iwl_mvm *)(cdev->devdata);
  661. if (test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status))
  662. return -EBUSY;
  663. *state = mvm->cooling_dev.cur_state;
  664. return 0;
  665. }
  666. static int iwl_mvm_tcool_set_cur_state(struct thermal_cooling_device *cdev,
  667. unsigned long new_state)
  668. {
  669. struct iwl_mvm *mvm = (struct iwl_mvm *)(cdev->devdata);
  670. int ret;
  671. if (!mvm->ucode_loaded || !(mvm->cur_ucode == IWL_UCODE_REGULAR))
  672. return -EIO;
  673. if (test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status))
  674. return -EBUSY;
  675. mutex_lock(&mvm->mutex);
  676. if (new_state >= ARRAY_SIZE(iwl_mvm_cdev_budgets)) {
  677. ret = -EINVAL;
  678. goto unlock;
  679. }
  680. ret = iwl_mvm_ctdp_command(mvm, CTDP_CMD_OPERATION_START,
  681. new_state);
  682. unlock:
  683. mutex_unlock(&mvm->mutex);
  684. return ret;
  685. }
  686. static struct thermal_cooling_device_ops tcooling_ops = {
  687. .get_max_state = iwl_mvm_tcool_get_max_state,
  688. .get_cur_state = iwl_mvm_tcool_get_cur_state,
  689. .set_cur_state = iwl_mvm_tcool_set_cur_state,
  690. };
  691. static void iwl_mvm_cooling_device_register(struct iwl_mvm *mvm)
  692. {
  693. char name[] = "iwlwifi";
  694. if (!iwl_mvm_is_ctdp_supported(mvm))
  695. return;
  696. BUILD_BUG_ON(ARRAY_SIZE(name) >= THERMAL_NAME_LENGTH);
  697. mvm->cooling_dev.cdev =
  698. thermal_cooling_device_register(name,
  699. mvm,
  700. &tcooling_ops);
  701. if (IS_ERR(mvm->cooling_dev.cdev)) {
  702. IWL_DEBUG_TEMP(mvm,
  703. "Failed to register to cooling device (err = %ld)\n",
  704. PTR_ERR(mvm->cooling_dev.cdev));
  705. mvm->cooling_dev.cdev = NULL;
  706. return;
  707. }
  708. }
  709. static void iwl_mvm_thermal_zone_unregister(struct iwl_mvm *mvm)
  710. {
  711. if (!iwl_mvm_is_tt_in_fw(mvm) || !mvm->tz_device.tzone)
  712. return;
  713. IWL_DEBUG_TEMP(mvm, "Thermal zone device unregister\n");
  714. thermal_zone_device_unregister(mvm->tz_device.tzone);
  715. mvm->tz_device.tzone = NULL;
  716. }
  717. static void iwl_mvm_cooling_device_unregister(struct iwl_mvm *mvm)
  718. {
  719. if (!iwl_mvm_is_ctdp_supported(mvm) || !mvm->cooling_dev.cdev)
  720. return;
  721. IWL_DEBUG_TEMP(mvm, "Cooling device unregister\n");
  722. thermal_cooling_device_unregister(mvm->cooling_dev.cdev);
  723. mvm->cooling_dev.cdev = NULL;
  724. }
  725. #endif /* CONFIG_THERMAL */
  726. void iwl_mvm_thermal_initialize(struct iwl_mvm *mvm, u32 min_backoff)
  727. {
  728. struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle;
  729. IWL_DEBUG_TEMP(mvm, "Initialize Thermal Throttling\n");
  730. if (mvm->cfg->thermal_params)
  731. tt->params = *mvm->cfg->thermal_params;
  732. else
  733. tt->params = iwl_mvm_default_tt_params;
  734. tt->throttle = false;
  735. tt->dynamic_smps = false;
  736. tt->min_backoff = min_backoff;
  737. INIT_DELAYED_WORK(&tt->ct_kill_exit, check_exit_ctkill);
  738. #ifdef CONFIG_THERMAL
  739. iwl_mvm_cooling_device_register(mvm);
  740. iwl_mvm_thermal_zone_register(mvm);
  741. #endif
  742. }
  743. void iwl_mvm_thermal_exit(struct iwl_mvm *mvm)
  744. {
  745. cancel_delayed_work_sync(&mvm->thermal_throttle.ct_kill_exit);
  746. IWL_DEBUG_TEMP(mvm, "Exit Thermal Throttling\n");
  747. #ifdef CONFIG_THERMAL
  748. iwl_mvm_cooling_device_unregister(mvm);
  749. iwl_mvm_thermal_zone_unregister(mvm);
  750. #endif
  751. }