tt.c 23 KB

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