tt.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899
  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. if (mvm->tz_device.tzone) {
  174. struct iwl_mvm_thermal_device *tz_dev = &mvm->tz_device;
  175. thermal_notify_framework(tz_dev->tzone,
  176. tz_dev->fw_trips_index[ths_crossed]);
  177. }
  178. #endif /* CONFIG_THERMAL */
  179. }
  180. void iwl_mvm_ct_kill_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
  181. {
  182. struct iwl_rx_packet *pkt = rxb_addr(rxb);
  183. struct ct_kill_notif *notif;
  184. int len = iwl_rx_packet_payload_len(pkt);
  185. if (WARN_ON_ONCE(len != sizeof(*notif))) {
  186. IWL_ERR(mvm, "Invalid CT_KILL_NOTIFICATION\n");
  187. return;
  188. }
  189. notif = (struct ct_kill_notif *)pkt->data;
  190. IWL_DEBUG_TEMP(mvm, "CT Kill notification temperature = %d\n",
  191. notif->temperature);
  192. iwl_mvm_enter_ctkill(mvm);
  193. }
  194. static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm)
  195. {
  196. struct iwl_dts_measurement_cmd cmd = {
  197. .flags = cpu_to_le32(DTS_TRIGGER_CMD_FLAGS_TEMP),
  198. };
  199. struct iwl_ext_dts_measurement_cmd extcmd = {
  200. .control_mode = cpu_to_le32(DTS_AUTOMATIC),
  201. };
  202. u32 cmdid;
  203. cmdid = iwl_cmd_id(CMD_DTS_MEASUREMENT_TRIGGER_WIDE,
  204. PHY_OPS_GROUP, 0);
  205. if (!fw_has_capa(&mvm->fw->ucode_capa,
  206. IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE))
  207. return iwl_mvm_send_cmd_pdu(mvm, cmdid, 0, sizeof(cmd), &cmd);
  208. return iwl_mvm_send_cmd_pdu(mvm, cmdid, 0, sizeof(extcmd), &extcmd);
  209. }
  210. int iwl_mvm_get_temp(struct iwl_mvm *mvm, s32 *temp)
  211. {
  212. struct iwl_notification_wait wait_temp_notif;
  213. static u16 temp_notif[] = { WIDE_ID(PHY_OPS_GROUP,
  214. DTS_MEASUREMENT_NOTIF_WIDE) };
  215. int ret;
  216. lockdep_assert_held(&mvm->mutex);
  217. iwl_init_notification_wait(&mvm->notif_wait, &wait_temp_notif,
  218. temp_notif, ARRAY_SIZE(temp_notif),
  219. iwl_mvm_temp_notif_wait, temp);
  220. ret = iwl_mvm_get_temp_cmd(mvm);
  221. if (ret) {
  222. IWL_ERR(mvm, "Failed to get the temperature (err=%d)\n", ret);
  223. iwl_remove_notification(&mvm->notif_wait, &wait_temp_notif);
  224. return ret;
  225. }
  226. ret = iwl_wait_notification(&mvm->notif_wait, &wait_temp_notif,
  227. IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT);
  228. if (ret)
  229. IWL_ERR(mvm, "Getting the temperature timed out\n");
  230. return ret;
  231. }
  232. static void check_exit_ctkill(struct work_struct *work)
  233. {
  234. struct iwl_mvm_tt_mgmt *tt;
  235. struct iwl_mvm *mvm;
  236. u32 duration;
  237. s32 temp;
  238. int ret;
  239. tt = container_of(work, struct iwl_mvm_tt_mgmt, ct_kill_exit.work);
  240. mvm = container_of(tt, struct iwl_mvm, thermal_throttle);
  241. if (iwl_mvm_is_tt_in_fw(mvm)) {
  242. iwl_mvm_exit_ctkill(mvm);
  243. return;
  244. }
  245. duration = tt->params.ct_kill_duration;
  246. mutex_lock(&mvm->mutex);
  247. if (__iwl_mvm_mac_start(mvm))
  248. goto reschedule;
  249. /* make sure the device is available for direct read/writes */
  250. if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_CHECK_CTKILL)) {
  251. __iwl_mvm_mac_stop(mvm);
  252. goto reschedule;
  253. }
  254. ret = iwl_mvm_get_temp(mvm, &temp);
  255. iwl_mvm_unref(mvm, IWL_MVM_REF_CHECK_CTKILL);
  256. __iwl_mvm_mac_stop(mvm);
  257. if (ret)
  258. goto reschedule;
  259. IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", temp);
  260. if (temp <= tt->params.ct_kill_exit) {
  261. mutex_unlock(&mvm->mutex);
  262. iwl_mvm_exit_ctkill(mvm);
  263. return;
  264. }
  265. reschedule:
  266. mutex_unlock(&mvm->mutex);
  267. schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit,
  268. round_jiffies(duration * HZ));
  269. }
  270. static void iwl_mvm_tt_smps_iterator(void *_data, u8 *mac,
  271. struct ieee80211_vif *vif)
  272. {
  273. struct iwl_mvm *mvm = _data;
  274. enum ieee80211_smps_mode smps_mode;
  275. lockdep_assert_held(&mvm->mutex);
  276. if (mvm->thermal_throttle.dynamic_smps)
  277. smps_mode = IEEE80211_SMPS_DYNAMIC;
  278. else
  279. smps_mode = IEEE80211_SMPS_AUTOMATIC;
  280. if (vif->type != NL80211_IFTYPE_STATION)
  281. return;
  282. iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_TT, smps_mode);
  283. }
  284. static void iwl_mvm_tt_tx_protection(struct iwl_mvm *mvm, bool enable)
  285. {
  286. struct iwl_mvm_sta *mvmsta;
  287. int i, err;
  288. for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
  289. mvmsta = iwl_mvm_sta_from_staid_protected(mvm, i);
  290. if (!mvmsta)
  291. continue;
  292. if (enable == mvmsta->tt_tx_protection)
  293. continue;
  294. err = iwl_mvm_tx_protection(mvm, mvmsta, enable);
  295. if (err) {
  296. IWL_ERR(mvm, "Failed to %s Tx protection\n",
  297. enable ? "enable" : "disable");
  298. } else {
  299. IWL_DEBUG_TEMP(mvm, "%s Tx protection\n",
  300. enable ? "Enable" : "Disable");
  301. mvmsta->tt_tx_protection = enable;
  302. }
  303. }
  304. }
  305. void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff)
  306. {
  307. struct iwl_host_cmd cmd = {
  308. .id = REPLY_THERMAL_MNG_BACKOFF,
  309. .len = { sizeof(u32), },
  310. .data = { &backoff, },
  311. };
  312. backoff = max(backoff, mvm->thermal_throttle.min_backoff);
  313. if (iwl_mvm_send_cmd(mvm, &cmd) == 0) {
  314. IWL_DEBUG_TEMP(mvm, "Set Thermal Tx backoff to: %u\n",
  315. backoff);
  316. mvm->thermal_throttle.tx_backoff = backoff;
  317. } else {
  318. IWL_ERR(mvm, "Failed to change Thermal Tx backoff\n");
  319. }
  320. }
  321. void iwl_mvm_tt_handler(struct iwl_mvm *mvm)
  322. {
  323. struct iwl_tt_params *params = &mvm->thermal_throttle.params;
  324. struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle;
  325. s32 temperature = mvm->temperature;
  326. bool throttle_enable = false;
  327. int i;
  328. u32 tx_backoff;
  329. IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", mvm->temperature);
  330. if (params->support_ct_kill && temperature >= params->ct_kill_entry) {
  331. iwl_mvm_enter_ctkill(mvm);
  332. return;
  333. }
  334. if (params->support_ct_kill &&
  335. temperature <= params->ct_kill_exit) {
  336. iwl_mvm_exit_ctkill(mvm);
  337. return;
  338. }
  339. if (params->support_dynamic_smps) {
  340. if (!tt->dynamic_smps &&
  341. temperature >= params->dynamic_smps_entry) {
  342. IWL_DEBUG_TEMP(mvm, "Enable dynamic SMPS\n");
  343. tt->dynamic_smps = true;
  344. ieee80211_iterate_active_interfaces_atomic(
  345. mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
  346. iwl_mvm_tt_smps_iterator, mvm);
  347. throttle_enable = true;
  348. } else if (tt->dynamic_smps &&
  349. temperature <= params->dynamic_smps_exit) {
  350. IWL_DEBUG_TEMP(mvm, "Disable dynamic SMPS\n");
  351. tt->dynamic_smps = false;
  352. ieee80211_iterate_active_interfaces_atomic(
  353. mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
  354. iwl_mvm_tt_smps_iterator, mvm);
  355. }
  356. }
  357. if (params->support_tx_protection) {
  358. if (temperature >= params->tx_protection_entry) {
  359. iwl_mvm_tt_tx_protection(mvm, true);
  360. throttle_enable = true;
  361. } else if (temperature <= params->tx_protection_exit) {
  362. iwl_mvm_tt_tx_protection(mvm, false);
  363. }
  364. }
  365. if (params->support_tx_backoff) {
  366. tx_backoff = tt->min_backoff;
  367. for (i = 0; i < TT_TX_BACKOFF_SIZE; i++) {
  368. if (temperature < params->tx_backoff[i].temperature)
  369. break;
  370. tx_backoff = max(tt->min_backoff,
  371. params->tx_backoff[i].backoff);
  372. }
  373. if (tx_backoff != tt->min_backoff)
  374. throttle_enable = true;
  375. if (tt->tx_backoff != tx_backoff)
  376. iwl_mvm_tt_tx_backoff(mvm, tx_backoff);
  377. }
  378. if (!tt->throttle && throttle_enable) {
  379. IWL_WARN(mvm,
  380. "Due to high temperature thermal throttling initiated\n");
  381. tt->throttle = true;
  382. } else if (tt->throttle && !tt->dynamic_smps &&
  383. tt->tx_backoff == tt->min_backoff &&
  384. temperature <= params->tx_protection_exit) {
  385. IWL_WARN(mvm,
  386. "Temperature is back to normal thermal throttling stopped\n");
  387. tt->throttle = false;
  388. }
  389. }
  390. static const struct iwl_tt_params iwl_mvm_default_tt_params = {
  391. .ct_kill_entry = 118,
  392. .ct_kill_exit = 96,
  393. .ct_kill_duration = 5,
  394. .dynamic_smps_entry = 114,
  395. .dynamic_smps_exit = 110,
  396. .tx_protection_entry = 114,
  397. .tx_protection_exit = 108,
  398. .tx_backoff = {
  399. {.temperature = 112, .backoff = 200},
  400. {.temperature = 113, .backoff = 600},
  401. {.temperature = 114, .backoff = 1200},
  402. {.temperature = 115, .backoff = 2000},
  403. {.temperature = 116, .backoff = 4000},
  404. {.temperature = 117, .backoff = 10000},
  405. },
  406. .support_ct_kill = true,
  407. .support_dynamic_smps = true,
  408. .support_tx_protection = true,
  409. .support_tx_backoff = true,
  410. };
  411. /* budget in mWatt */
  412. static const u32 iwl_mvm_cdev_budgets[] = {
  413. 2000, /* cooling state 0 */
  414. 1800, /* cooling state 1 */
  415. 1600, /* cooling state 2 */
  416. 1400, /* cooling state 3 */
  417. 1200, /* cooling state 4 */
  418. 1000, /* cooling state 5 */
  419. 900, /* cooling state 6 */
  420. 800, /* cooling state 7 */
  421. 700, /* cooling state 8 */
  422. 650, /* cooling state 9 */
  423. 600, /* cooling state 10 */
  424. 550, /* cooling state 11 */
  425. 500, /* cooling state 12 */
  426. 450, /* cooling state 13 */
  427. 400, /* cooling state 14 */
  428. 350, /* cooling state 15 */
  429. 300, /* cooling state 16 */
  430. 250, /* cooling state 17 */
  431. 200, /* cooling state 18 */
  432. 150, /* cooling state 19 */
  433. };
  434. int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 state)
  435. {
  436. struct iwl_mvm_ctdp_cmd cmd = {
  437. .operation = cpu_to_le32(op),
  438. .budget = cpu_to_le32(iwl_mvm_cdev_budgets[state]),
  439. .window_size = 0,
  440. };
  441. int ret;
  442. u32 status;
  443. lockdep_assert_held(&mvm->mutex);
  444. ret = iwl_mvm_send_cmd_pdu_status(mvm, WIDE_ID(PHY_OPS_GROUP,
  445. CTDP_CONFIG_CMD),
  446. sizeof(cmd), &cmd, &status);
  447. if (ret) {
  448. IWL_ERR(mvm, "cTDP command failed (err=%d)\n", ret);
  449. return ret;
  450. }
  451. switch (op) {
  452. case CTDP_CMD_OPERATION_START:
  453. #ifdef CONFIG_THERMAL
  454. mvm->cooling_dev.cur_state = state;
  455. #endif /* CONFIG_THERMAL */
  456. break;
  457. case CTDP_CMD_OPERATION_REPORT:
  458. IWL_DEBUG_TEMP(mvm, "cTDP avg energy in mWatt = %d\n", status);
  459. /* when the function is called with CTDP_CMD_OPERATION_REPORT
  460. * option the function should return the average budget value
  461. * that is received from the FW.
  462. * The budget can't be less or equal to 0, so it's possible
  463. * to distinguish between error values and budgets.
  464. */
  465. return status;
  466. case CTDP_CMD_OPERATION_STOP:
  467. IWL_DEBUG_TEMP(mvm, "cTDP stopped successfully\n");
  468. break;
  469. }
  470. return 0;
  471. }
  472. #ifdef CONFIG_THERMAL
  473. static int compare_temps(const void *a, const void *b)
  474. {
  475. return ((s16)le16_to_cpu(*(__le16 *)a) -
  476. (s16)le16_to_cpu(*(__le16 *)b));
  477. }
  478. int iwl_mvm_send_temp_report_ths_cmd(struct iwl_mvm *mvm)
  479. {
  480. struct temp_report_ths_cmd cmd = {0};
  481. int ret, i, j, idx = 0;
  482. lockdep_assert_held(&mvm->mutex);
  483. if (!mvm->tz_device.tzone)
  484. return -EINVAL;
  485. /* The driver holds array of temperature trips that are unsorted
  486. * and uncompressed, the FW should get it compressed and sorted
  487. */
  488. /* compress temp_trips to cmd array, remove uninitialized values*/
  489. for (i = 0; i < IWL_MAX_DTS_TRIPS; i++) {
  490. if (mvm->tz_device.temp_trips[i] != S16_MIN) {
  491. cmd.thresholds[idx++] =
  492. cpu_to_le16(mvm->tz_device.temp_trips[i]);
  493. }
  494. }
  495. cmd.num_temps = cpu_to_le32(idx);
  496. if (!idx)
  497. goto send;
  498. /*sort cmd array*/
  499. sort(cmd.thresholds, idx, sizeof(s16), compare_temps, NULL);
  500. /* we should save the indexes of trips because we sort
  501. * and compress the orginal array
  502. */
  503. for (i = 0; i < idx; i++) {
  504. for (j = 0; j < IWL_MAX_DTS_TRIPS; j++) {
  505. if (le16_to_cpu(cmd.thresholds[i]) ==
  506. mvm->tz_device.temp_trips[j])
  507. mvm->tz_device.fw_trips_index[i] = j;
  508. }
  509. }
  510. send:
  511. ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(PHY_OPS_GROUP,
  512. TEMP_REPORTING_THRESHOLDS_CMD),
  513. 0, sizeof(cmd), &cmd);
  514. if (ret)
  515. IWL_ERR(mvm, "TEMP_REPORT_THS_CMD command failed (err=%d)\n",
  516. ret);
  517. return ret;
  518. }
  519. static int iwl_mvm_tzone_get_temp(struct thermal_zone_device *device,
  520. int *temperature)
  521. {
  522. struct iwl_mvm *mvm = (struct iwl_mvm *)device->devdata;
  523. int ret;
  524. int temp;
  525. mutex_lock(&mvm->mutex);
  526. if (!mvm->ucode_loaded || !(mvm->cur_ucode == IWL_UCODE_REGULAR)) {
  527. ret = -EIO;
  528. goto out;
  529. }
  530. ret = iwl_mvm_get_temp(mvm, &temp);
  531. if (ret)
  532. goto out;
  533. *temperature = temp * 1000;
  534. out:
  535. mutex_unlock(&mvm->mutex);
  536. return ret;
  537. }
  538. static int iwl_mvm_tzone_get_trip_temp(struct thermal_zone_device *device,
  539. int trip, int *temp)
  540. {
  541. struct iwl_mvm *mvm = (struct iwl_mvm *)device->devdata;
  542. if (trip < 0 || trip >= IWL_MAX_DTS_TRIPS)
  543. return -EINVAL;
  544. *temp = mvm->tz_device.temp_trips[trip] * 1000;
  545. return 0;
  546. }
  547. static int iwl_mvm_tzone_get_trip_type(struct thermal_zone_device *device,
  548. int trip, enum thermal_trip_type *type)
  549. {
  550. if (trip < 0 || trip >= IWL_MAX_DTS_TRIPS)
  551. return -EINVAL;
  552. *type = THERMAL_TRIP_PASSIVE;
  553. return 0;
  554. }
  555. static int iwl_mvm_tzone_set_trip_temp(struct thermal_zone_device *device,
  556. int trip, int temp)
  557. {
  558. struct iwl_mvm *mvm = (struct iwl_mvm *)device->devdata;
  559. struct iwl_mvm_thermal_device *tzone;
  560. int i, ret;
  561. s16 temperature;
  562. mutex_lock(&mvm->mutex);
  563. if (!mvm->ucode_loaded || !(mvm->cur_ucode == IWL_UCODE_REGULAR)) {
  564. ret = -EIO;
  565. goto out;
  566. }
  567. if (trip < 0 || trip >= IWL_MAX_DTS_TRIPS) {
  568. ret = -EINVAL;
  569. goto out;
  570. }
  571. if ((temp / 1000) > S16_MAX) {
  572. ret = -EINVAL;
  573. goto out;
  574. }
  575. temperature = (s16)(temp / 1000);
  576. tzone = &mvm->tz_device;
  577. if (!tzone) {
  578. ret = -EIO;
  579. goto out;
  580. }
  581. /* no updates*/
  582. if (tzone->temp_trips[trip] == temperature) {
  583. ret = 0;
  584. goto out;
  585. }
  586. /* already existing temperature */
  587. for (i = 0; i < IWL_MAX_DTS_TRIPS; i++) {
  588. if (tzone->temp_trips[i] == temperature) {
  589. ret = -EINVAL;
  590. goto out;
  591. }
  592. }
  593. tzone->temp_trips[trip] = temperature;
  594. ret = iwl_mvm_send_temp_report_ths_cmd(mvm);
  595. out:
  596. mutex_unlock(&mvm->mutex);
  597. return ret;
  598. }
  599. static struct thermal_zone_device_ops tzone_ops = {
  600. .get_temp = iwl_mvm_tzone_get_temp,
  601. .get_trip_temp = iwl_mvm_tzone_get_trip_temp,
  602. .get_trip_type = iwl_mvm_tzone_get_trip_type,
  603. .set_trip_temp = iwl_mvm_tzone_set_trip_temp,
  604. };
  605. /* make all trips writable */
  606. #define IWL_WRITABLE_TRIPS_MSK (BIT(IWL_MAX_DTS_TRIPS) - 1)
  607. static void iwl_mvm_thermal_zone_register(struct iwl_mvm *mvm)
  608. {
  609. int i;
  610. char name[] = "iwlwifi";
  611. if (!iwl_mvm_is_tt_in_fw(mvm)) {
  612. mvm->tz_device.tzone = NULL;
  613. return;
  614. }
  615. BUILD_BUG_ON(ARRAY_SIZE(name) >= THERMAL_NAME_LENGTH);
  616. mvm->tz_device.tzone = thermal_zone_device_register(name,
  617. IWL_MAX_DTS_TRIPS,
  618. IWL_WRITABLE_TRIPS_MSK,
  619. mvm, &tzone_ops,
  620. NULL, 0, 0);
  621. if (IS_ERR(mvm->tz_device.tzone)) {
  622. IWL_DEBUG_TEMP(mvm,
  623. "Failed to register to thermal zone (err = %ld)\n",
  624. PTR_ERR(mvm->tz_device.tzone));
  625. mvm->tz_device.tzone = NULL;
  626. return;
  627. }
  628. /* 0 is a valid temperature,
  629. * so initialize the array with S16_MIN which invalid temperature
  630. */
  631. for (i = 0 ; i < IWL_MAX_DTS_TRIPS; i++)
  632. mvm->tz_device.temp_trips[i] = S16_MIN;
  633. }
  634. static int iwl_mvm_tcool_get_max_state(struct thermal_cooling_device *cdev,
  635. unsigned long *state)
  636. {
  637. *state = ARRAY_SIZE(iwl_mvm_cdev_budgets) - 1;
  638. return 0;
  639. }
  640. static int iwl_mvm_tcool_get_cur_state(struct thermal_cooling_device *cdev,
  641. unsigned long *state)
  642. {
  643. struct iwl_mvm *mvm = (struct iwl_mvm *)(cdev->devdata);
  644. *state = mvm->cooling_dev.cur_state;
  645. return 0;
  646. }
  647. static int iwl_mvm_tcool_set_cur_state(struct thermal_cooling_device *cdev,
  648. unsigned long new_state)
  649. {
  650. struct iwl_mvm *mvm = (struct iwl_mvm *)(cdev->devdata);
  651. int ret;
  652. mutex_lock(&mvm->mutex);
  653. if (!mvm->ucode_loaded || !(mvm->cur_ucode == IWL_UCODE_REGULAR)) {
  654. ret = -EIO;
  655. goto unlock;
  656. }
  657. if (new_state >= ARRAY_SIZE(iwl_mvm_cdev_budgets)) {
  658. ret = -EINVAL;
  659. goto unlock;
  660. }
  661. ret = iwl_mvm_ctdp_command(mvm, CTDP_CMD_OPERATION_START,
  662. new_state);
  663. unlock:
  664. mutex_unlock(&mvm->mutex);
  665. return ret;
  666. }
  667. static struct thermal_cooling_device_ops tcooling_ops = {
  668. .get_max_state = iwl_mvm_tcool_get_max_state,
  669. .get_cur_state = iwl_mvm_tcool_get_cur_state,
  670. .set_cur_state = iwl_mvm_tcool_set_cur_state,
  671. };
  672. static void iwl_mvm_cooling_device_register(struct iwl_mvm *mvm)
  673. {
  674. char name[] = "iwlwifi";
  675. if (!iwl_mvm_is_ctdp_supported(mvm))
  676. return;
  677. BUILD_BUG_ON(ARRAY_SIZE(name) >= THERMAL_NAME_LENGTH);
  678. mvm->cooling_dev.cdev =
  679. thermal_cooling_device_register(name,
  680. mvm,
  681. &tcooling_ops);
  682. if (IS_ERR(mvm->cooling_dev.cdev)) {
  683. IWL_DEBUG_TEMP(mvm,
  684. "Failed to register to cooling device (err = %ld)\n",
  685. PTR_ERR(mvm->cooling_dev.cdev));
  686. mvm->cooling_dev.cdev = NULL;
  687. return;
  688. }
  689. }
  690. static void iwl_mvm_thermal_zone_unregister(struct iwl_mvm *mvm)
  691. {
  692. if (!iwl_mvm_is_tt_in_fw(mvm) || !mvm->tz_device.tzone)
  693. return;
  694. IWL_DEBUG_TEMP(mvm, "Thermal zone device unregister\n");
  695. if (mvm->tz_device.tzone) {
  696. thermal_zone_device_unregister(mvm->tz_device.tzone);
  697. mvm->tz_device.tzone = NULL;
  698. }
  699. }
  700. static void iwl_mvm_cooling_device_unregister(struct iwl_mvm *mvm)
  701. {
  702. if (!iwl_mvm_is_ctdp_supported(mvm) || !mvm->cooling_dev.cdev)
  703. return;
  704. IWL_DEBUG_TEMP(mvm, "Cooling device unregister\n");
  705. if (mvm->cooling_dev.cdev) {
  706. thermal_cooling_device_unregister(mvm->cooling_dev.cdev);
  707. mvm->cooling_dev.cdev = NULL;
  708. }
  709. }
  710. #endif /* CONFIG_THERMAL */
  711. void iwl_mvm_thermal_initialize(struct iwl_mvm *mvm, u32 min_backoff)
  712. {
  713. struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle;
  714. IWL_DEBUG_TEMP(mvm, "Initialize Thermal Throttling\n");
  715. if (mvm->cfg->thermal_params)
  716. tt->params = *mvm->cfg->thermal_params;
  717. else
  718. tt->params = iwl_mvm_default_tt_params;
  719. tt->throttle = false;
  720. tt->dynamic_smps = false;
  721. tt->min_backoff = min_backoff;
  722. INIT_DELAYED_WORK(&tt->ct_kill_exit, check_exit_ctkill);
  723. #ifdef CONFIG_THERMAL
  724. iwl_mvm_cooling_device_register(mvm);
  725. iwl_mvm_thermal_zone_register(mvm);
  726. #endif
  727. }
  728. void iwl_mvm_thermal_exit(struct iwl_mvm *mvm)
  729. {
  730. cancel_delayed_work_sync(&mvm->thermal_throttle.ct_kill_exit);
  731. IWL_DEBUG_TEMP(mvm, "Exit Thermal Throttling\n");
  732. #ifdef CONFIG_THERMAL
  733. iwl_mvm_cooling_device_unregister(mvm);
  734. iwl_mvm_thermal_zone_unregister(mvm);
  735. #endif
  736. }