tt.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913
  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. int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 budget)
  429. {
  430. struct iwl_mvm_ctdp_cmd cmd = {
  431. .operation = cpu_to_le32(op),
  432. .budget = cpu_to_le32(budget),
  433. .window_size = 0,
  434. };
  435. int ret;
  436. u32 status;
  437. lockdep_assert_held(&mvm->mutex);
  438. ret = iwl_mvm_send_cmd_pdu_status(mvm, WIDE_ID(PHY_OPS_GROUP,
  439. CTDP_CONFIG_CMD),
  440. sizeof(cmd), &cmd, &status);
  441. if (ret) {
  442. IWL_ERR(mvm, "cTDP command failed (err=%d)\n", ret);
  443. return ret;
  444. }
  445. switch (op) {
  446. case CTDP_CMD_OPERATION_START:
  447. #ifdef CONFIG_THERMAL
  448. mvm->cooling_dev.cur_state = budget;
  449. #endif /* CONFIG_THERMAL */
  450. break;
  451. case CTDP_CMD_OPERATION_REPORT:
  452. IWL_DEBUG_TEMP(mvm, "cTDP avg energy in mWatt = %d\n", status);
  453. /* when the function is called with CTDP_CMD_OPERATION_REPORT
  454. * option the function should return the average budget value
  455. * that is received from the FW.
  456. * The budget can't be less or equal to 0, so it's possible
  457. * to distinguish between error values and budgets.
  458. */
  459. return status;
  460. case CTDP_CMD_OPERATION_STOP:
  461. IWL_DEBUG_TEMP(mvm, "cTDP stopped successfully\n");
  462. break;
  463. }
  464. return 0;
  465. }
  466. #ifdef CONFIG_THERMAL
  467. static int compare_temps(const void *a, const void *b)
  468. {
  469. return ((s16)le16_to_cpu(*(__le16 *)a) -
  470. (s16)le16_to_cpu(*(__le16 *)b));
  471. }
  472. int iwl_mvm_send_temp_report_ths_cmd(struct iwl_mvm *mvm)
  473. {
  474. struct temp_report_ths_cmd cmd = {0};
  475. int ret, i, j, idx = 0;
  476. lockdep_assert_held(&mvm->mutex);
  477. if (!mvm->tz_device.tzone)
  478. return -EINVAL;
  479. /* The driver holds array of temperature trips that are unsorted
  480. * and uncompressed, the FW should get it compressed and sorted
  481. */
  482. /* compress temp_trips to cmd array, remove uninitialized values*/
  483. for (i = 0; i < IWL_MAX_DTS_TRIPS; i++) {
  484. if (mvm->tz_device.temp_trips[i] != S16_MIN) {
  485. cmd.thresholds[idx++] =
  486. cpu_to_le16(mvm->tz_device.temp_trips[i]);
  487. }
  488. }
  489. cmd.num_temps = cpu_to_le32(idx);
  490. if (!idx)
  491. goto send;
  492. /*sort cmd array*/
  493. sort(cmd.thresholds, idx, sizeof(s16), compare_temps, NULL);
  494. /* we should save the indexes of trips because we sort
  495. * and compress the orginal array
  496. */
  497. for (i = 0; i < idx; i++) {
  498. for (j = 0; j < IWL_MAX_DTS_TRIPS; j++) {
  499. if (le16_to_cpu(cmd.thresholds[i]) ==
  500. mvm->tz_device.temp_trips[j])
  501. mvm->tz_device.fw_trips_index[i] = j;
  502. }
  503. }
  504. send:
  505. ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(PHY_OPS_GROUP,
  506. TEMP_REPORTING_THRESHOLDS_CMD),
  507. 0, sizeof(cmd), &cmd);
  508. if (ret)
  509. IWL_ERR(mvm, "TEMP_REPORT_THS_CMD command failed (err=%d)\n",
  510. ret);
  511. return ret;
  512. }
  513. static int iwl_mvm_tzone_get_temp(struct thermal_zone_device *device,
  514. int *temperature)
  515. {
  516. struct iwl_mvm *mvm = (struct iwl_mvm *)device->devdata;
  517. int ret;
  518. int temp;
  519. mutex_lock(&mvm->mutex);
  520. if (!mvm->ucode_loaded || !(mvm->cur_ucode == IWL_UCODE_REGULAR)) {
  521. ret = -EIO;
  522. goto out;
  523. }
  524. ret = iwl_mvm_get_temp(mvm, &temp);
  525. if (ret)
  526. goto out;
  527. *temperature = temp * 1000;
  528. out:
  529. mutex_unlock(&mvm->mutex);
  530. return ret;
  531. }
  532. static int iwl_mvm_tzone_get_trip_temp(struct thermal_zone_device *device,
  533. int trip, int *temp)
  534. {
  535. struct iwl_mvm *mvm = (struct iwl_mvm *)device->devdata;
  536. if (trip < 0 || trip >= IWL_MAX_DTS_TRIPS)
  537. return -EINVAL;
  538. *temp = mvm->tz_device.temp_trips[trip] * 1000;
  539. return 0;
  540. }
  541. static int iwl_mvm_tzone_get_trip_type(struct thermal_zone_device *device,
  542. int trip, enum thermal_trip_type *type)
  543. {
  544. if (trip < 0 || trip >= IWL_MAX_DTS_TRIPS)
  545. return -EINVAL;
  546. *type = THERMAL_TRIP_PASSIVE;
  547. return 0;
  548. }
  549. static int iwl_mvm_tzone_set_trip_temp(struct thermal_zone_device *device,
  550. int trip, int temp)
  551. {
  552. struct iwl_mvm *mvm = (struct iwl_mvm *)device->devdata;
  553. struct iwl_mvm_thermal_device *tzone;
  554. int i, ret;
  555. s16 temperature;
  556. mutex_lock(&mvm->mutex);
  557. if (!mvm->ucode_loaded || !(mvm->cur_ucode == IWL_UCODE_REGULAR)) {
  558. ret = -EIO;
  559. goto out;
  560. }
  561. if (trip < 0 || trip >= IWL_MAX_DTS_TRIPS) {
  562. ret = -EINVAL;
  563. goto out;
  564. }
  565. if ((temp / 1000) > S16_MAX) {
  566. ret = -EINVAL;
  567. goto out;
  568. }
  569. temperature = (s16)(temp / 1000);
  570. tzone = &mvm->tz_device;
  571. if (!tzone) {
  572. ret = -EIO;
  573. goto out;
  574. }
  575. /* no updates*/
  576. if (tzone->temp_trips[trip] == temperature) {
  577. ret = 0;
  578. goto out;
  579. }
  580. /* already existing temperature */
  581. for (i = 0; i < IWL_MAX_DTS_TRIPS; i++) {
  582. if (tzone->temp_trips[i] == temperature) {
  583. ret = -EINVAL;
  584. goto out;
  585. }
  586. }
  587. tzone->temp_trips[trip] = temperature;
  588. ret = iwl_mvm_send_temp_report_ths_cmd(mvm);
  589. out:
  590. mutex_unlock(&mvm->mutex);
  591. return ret;
  592. }
  593. static struct thermal_zone_device_ops tzone_ops = {
  594. .get_temp = iwl_mvm_tzone_get_temp,
  595. .get_trip_temp = iwl_mvm_tzone_get_trip_temp,
  596. .get_trip_type = iwl_mvm_tzone_get_trip_type,
  597. .set_trip_temp = iwl_mvm_tzone_set_trip_temp,
  598. };
  599. /* make all trips writable */
  600. #define IWL_WRITABLE_TRIPS_MSK (BIT(IWL_MAX_DTS_TRIPS) - 1)
  601. static void iwl_mvm_thermal_zone_register(struct iwl_mvm *mvm)
  602. {
  603. int i;
  604. char name[] = "iwlwifi";
  605. if (!iwl_mvm_is_tt_in_fw(mvm)) {
  606. mvm->tz_device.tzone = NULL;
  607. return;
  608. }
  609. BUILD_BUG_ON(ARRAY_SIZE(name) >= THERMAL_NAME_LENGTH);
  610. mvm->tz_device.tzone = thermal_zone_device_register(name,
  611. IWL_MAX_DTS_TRIPS,
  612. IWL_WRITABLE_TRIPS_MSK,
  613. mvm, &tzone_ops,
  614. NULL, 0, 0);
  615. if (IS_ERR(mvm->tz_device.tzone)) {
  616. IWL_DEBUG_TEMP(mvm,
  617. "Failed to register to thermal zone (err = %ld)\n",
  618. PTR_ERR(mvm->tz_device.tzone));
  619. mvm->tz_device.tzone = NULL;
  620. return;
  621. }
  622. /* 0 is a valid temperature,
  623. * so initialize the array with S16_MIN which invalid temperature
  624. */
  625. for (i = 0 ; i < IWL_MAX_DTS_TRIPS; i++)
  626. mvm->tz_device.temp_trips[i] = S16_MIN;
  627. }
  628. static const u32 iwl_mvm_cdev_budgets[] = {
  629. 2000, /* cooling state 0 */
  630. 1800, /* cooling state 1 */
  631. 1600, /* cooling state 2 */
  632. 1400, /* cooling state 3 */
  633. 1200, /* cooling state 4 */
  634. 1000, /* cooling state 5 */
  635. 900, /* cooling state 6 */
  636. 800, /* cooling state 7 */
  637. 700, /* cooling state 8 */
  638. 650, /* cooling state 9 */
  639. 600, /* cooling state 10 */
  640. 550, /* cooling state 11 */
  641. 500, /* cooling state 12 */
  642. 450, /* cooling state 13 */
  643. 400, /* cooling state 14 */
  644. 350, /* cooling state 15 */
  645. 300, /* cooling state 16 */
  646. 250, /* cooling state 17 */
  647. 200, /* cooling state 18 */
  648. 150, /* cooling state 19 */
  649. };
  650. static int iwl_mvm_tcool_get_max_state(struct thermal_cooling_device *cdev,
  651. unsigned long *state)
  652. {
  653. *state = ARRAY_SIZE(iwl_mvm_cdev_budgets) - 1;
  654. return 0;
  655. }
  656. static int iwl_mvm_tcool_get_cur_state(struct thermal_cooling_device *cdev,
  657. unsigned long *state)
  658. {
  659. struct iwl_mvm *mvm = (struct iwl_mvm *)(cdev->devdata);
  660. if (test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status))
  661. return -EBUSY;
  662. *state = mvm->cooling_dev.cur_state;
  663. return 0;
  664. }
  665. static int iwl_mvm_tcool_set_cur_state(struct thermal_cooling_device *cdev,
  666. unsigned long new_state)
  667. {
  668. struct iwl_mvm *mvm = (struct iwl_mvm *)(cdev->devdata);
  669. int ret;
  670. if (!mvm->ucode_loaded || !(mvm->cur_ucode == IWL_UCODE_REGULAR))
  671. return -EIO;
  672. if (test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status))
  673. return -EBUSY;
  674. mutex_lock(&mvm->mutex);
  675. if (new_state >= ARRAY_SIZE(iwl_mvm_cdev_budgets)) {
  676. ret = -EINVAL;
  677. goto unlock;
  678. }
  679. ret = iwl_mvm_ctdp_command(mvm, CTDP_CMD_OPERATION_START,
  680. iwl_mvm_cdev_budgets[new_state]);
  681. unlock:
  682. mutex_unlock(&mvm->mutex);
  683. return ret;
  684. }
  685. static struct thermal_cooling_device_ops tcooling_ops = {
  686. .get_max_state = iwl_mvm_tcool_get_max_state,
  687. .get_cur_state = iwl_mvm_tcool_get_cur_state,
  688. .set_cur_state = iwl_mvm_tcool_set_cur_state,
  689. };
  690. static void iwl_mvm_cooling_device_register(struct iwl_mvm *mvm)
  691. {
  692. char name[] = "iwlwifi";
  693. if (!iwl_mvm_is_ctdp_supported(mvm))
  694. return;
  695. BUILD_BUG_ON(ARRAY_SIZE(name) >= THERMAL_NAME_LENGTH);
  696. mvm->cooling_dev.cdev =
  697. thermal_cooling_device_register(name,
  698. mvm,
  699. &tcooling_ops);
  700. if (IS_ERR(mvm->cooling_dev.cdev)) {
  701. IWL_DEBUG_TEMP(mvm,
  702. "Failed to register to cooling device (err = %ld)\n",
  703. PTR_ERR(mvm->cooling_dev.cdev));
  704. mvm->cooling_dev.cdev = NULL;
  705. return;
  706. }
  707. }
  708. static void iwl_mvm_thermal_zone_unregister(struct iwl_mvm *mvm)
  709. {
  710. if (!iwl_mvm_is_tt_in_fw(mvm) || !mvm->tz_device.tzone)
  711. return;
  712. IWL_DEBUG_TEMP(mvm, "Thermal zone device unregister\n");
  713. thermal_zone_device_unregister(mvm->tz_device.tzone);
  714. mvm->tz_device.tzone = NULL;
  715. }
  716. static void iwl_mvm_cooling_device_unregister(struct iwl_mvm *mvm)
  717. {
  718. if (!iwl_mvm_is_ctdp_supported(mvm) || !mvm->cooling_dev.cdev)
  719. return;
  720. IWL_DEBUG_TEMP(mvm, "Cooling device unregister\n");
  721. thermal_cooling_device_unregister(mvm->cooling_dev.cdev);
  722. mvm->cooling_dev.cdev = NULL;
  723. }
  724. #endif /* CONFIG_THERMAL */
  725. void iwl_mvm_thermal_initialize(struct iwl_mvm *mvm, u32 min_backoff)
  726. {
  727. struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle;
  728. IWL_DEBUG_TEMP(mvm, "Initialize Thermal Throttling\n");
  729. if (mvm->cfg->thermal_params)
  730. tt->params = *mvm->cfg->thermal_params;
  731. else
  732. tt->params = iwl_mvm_default_tt_params;
  733. tt->throttle = false;
  734. tt->dynamic_smps = false;
  735. tt->min_backoff = min_backoff;
  736. INIT_DELAYED_WORK(&tt->ct_kill_exit, check_exit_ctkill);
  737. #ifdef CONFIG_THERMAL
  738. iwl_mvm_cooling_device_register(mvm);
  739. iwl_mvm_thermal_zone_register(mvm);
  740. #endif
  741. }
  742. void iwl_mvm_thermal_exit(struct iwl_mvm *mvm)
  743. {
  744. cancel_delayed_work_sync(&mvm->thermal_throttle.ct_kill_exit);
  745. IWL_DEBUG_TEMP(mvm, "Exit Thermal Throttling\n");
  746. #ifdef CONFIG_THERMAL
  747. iwl_mvm_cooling_device_unregister(mvm);
  748. iwl_mvm_thermal_zone_unregister(mvm);
  749. #endif
  750. }