diff options
author | Wey-Yi Guy <wey-yi.w.guy@intel.com> | 2009-07-24 14:13:02 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-07-27 15:24:20 -0400 |
commit | 39b73fb15e4704fd4d1e33688135810637f5f3fb (patch) | |
tree | d0efed58f5a52ccdc19d8f133aa64af7a0691e70 | |
parent | 672639de13c4db92ed6a47e68043a4317e219902 (diff) |
iwlwifi: Thermal Throttling Management - Part 1
Part 1 of Thermal Throttling Management -
Thermal Throttling feature is used to put NIC into low power state when
driver detect the Radio temperature reach pre-defined threshold
Two Thermal Throttling Management Methods; this patch introduce the
Legacy Thermal Management:
IWL_TI_0: normal temperature, system power state
IWL_TI_1: high temperature detect, low power state
IWL_TI_2: higher temperature detected, lower power state
IWL_TI_CT_KILL: critical temperature detected, lowest power state
Once get into CT_KILL state, uCode go into sleep, driver will stop all
the active queues, then move to IWL_TI_CT_KILL state; also set up 5
seconds timer to toggle CSR flag, uCode wake up upon CSR flag change,
then measure the temperature.
If temperature is above CT_KILL exit threshold, uCode go backto sleep;
if temperature is below CT_KILL exit threshold, uCode send Card State
Notification response with appropriate CT_KILL status flag, and uCode
remain awake, Driver receive Card State Notification Response and update
the card temperature to the CT_KILL exit threshold.
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-4965.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-5000.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 19 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-power.c | 249 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-power.h | 42 |
6 files changed, 301 insertions, 12 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 23925bd81c62..670214823cb9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c | |||
@@ -1797,6 +1797,7 @@ static void iwl4965_temperature_calib(struct iwl_priv *priv) | |||
1797 | } | 1797 | } |
1798 | 1798 | ||
1799 | priv->temperature = temp; | 1799 | priv->temperature = temp; |
1800 | iwl_tt_handler(priv); | ||
1800 | set_bit(STATUS_TEMPERATURE, &priv->status); | 1801 | set_bit(STATUS_TEMPERATURE, &priv->status); |
1801 | 1802 | ||
1802 | if (!priv->disable_tx_power_cal && | 1803 | if (!priv->disable_tx_power_cal && |
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 076acb13ba6d..ddd64fef3039 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c | |||
@@ -1405,6 +1405,7 @@ void iwl5000_temperature(struct iwl_priv *priv) | |||
1405 | { | 1405 | { |
1406 | /* store temperature from statistics (in Celsius) */ | 1406 | /* store temperature from statistics (in Celsius) */ |
1407 | priv->temperature = le32_to_cpu(priv->statistics.general.temperature); | 1407 | priv->temperature = le32_to_cpu(priv->statistics.general.temperature); |
1408 | iwl_tt_handler(priv); | ||
1408 | } | 1409 | } |
1409 | 1410 | ||
1410 | static void iwl5150_temperature(struct iwl_priv *priv) | 1411 | static void iwl5150_temperature(struct iwl_priv *priv) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 44c7f236a7a3..23ae9914c84b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -637,7 +637,6 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, | |||
637 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; | 637 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; |
638 | u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); | 638 | u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); |
639 | unsigned long status = priv->status; | 639 | unsigned long status = priv->status; |
640 | unsigned long reg_flags; | ||
641 | 640 | ||
642 | IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s\n", | 641 | IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s\n", |
643 | (flags & HW_CARD_DISABLED) ? "Kill" : "On", | 642 | (flags & HW_CARD_DISABLED) ? "Kill" : "On", |
@@ -657,19 +656,12 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, | |||
657 | CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); | 656 | CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); |
658 | iwl_write_direct32(priv, HBUS_TARG_MBX_C, | 657 | iwl_write_direct32(priv, HBUS_TARG_MBX_C, |
659 | HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); | 658 | HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); |
660 | |||
661 | } | ||
662 | |||
663 | if (flags & RF_CARD_DISABLED) { | ||
664 | iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, | ||
665 | CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); | ||
666 | iwl_read32(priv, CSR_UCODE_DRV_GP1); | ||
667 | spin_lock_irqsave(&priv->reg_lock, reg_flags); | ||
668 | if (!iwl_grab_nic_access(priv)) | ||
669 | iwl_release_nic_access(priv); | ||
670 | spin_unlock_irqrestore(&priv->reg_lock, reg_flags); | ||
671 | } | 659 | } |
660 | if (flags & RF_CARD_DISABLED) | ||
661 | iwl_tt_enter_ct_kill(priv); | ||
672 | } | 662 | } |
663 | if (!(flags & RF_CARD_DISABLED)) | ||
664 | iwl_tt_exit_ct_kill(priv); | ||
673 | 665 | ||
674 | if (flags & HW_CARD_DISABLED) | 666 | if (flags & HW_CARD_DISABLED) |
675 | set_bit(STATUS_RF_KILL_HW, &priv->status); | 667 | set_bit(STATUS_RF_KILL_HW, &priv->status); |
@@ -3015,6 +3007,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
3015 | test_bit(STATUS_RF_KILL_HW, &priv->status)); | 3007 | test_bit(STATUS_RF_KILL_HW, &priv->status)); |
3016 | 3008 | ||
3017 | iwl_power_initialize(priv); | 3009 | iwl_power_initialize(priv); |
3010 | iwl_tt_initialize(priv); | ||
3018 | return 0; | 3011 | return 0; |
3019 | 3012 | ||
3020 | out_remove_sysfs: | 3013 | out_remove_sysfs: |
@@ -3067,6 +3060,8 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) | |||
3067 | iwl_down(priv); | 3060 | iwl_down(priv); |
3068 | } | 3061 | } |
3069 | 3062 | ||
3063 | iwl_tt_exit(priv); | ||
3064 | |||
3070 | /* make sure we flush any pending irq or | 3065 | /* make sure we flush any pending irq or |
3071 | * tasklet for the driver | 3066 | * tasklet for the driver |
3072 | */ | 3067 | */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 5ef3c37b5813..d8aeb24db90a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c | |||
@@ -2232,6 +2232,7 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv) | |||
2232 | iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, | 2232 | iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, |
2233 | CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); | 2233 | CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); |
2234 | spin_unlock_irqrestore(&priv->lock, flags); | 2234 | spin_unlock_irqrestore(&priv->lock, flags); |
2235 | priv->power_data.ct_kill_toggle = false; | ||
2235 | 2236 | ||
2236 | switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { | 2237 | switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { |
2237 | case CSR_HW_REV_TYPE_1000: | 2238 | case CSR_HW_REV_TYPE_1000: |
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index f2ea3f05f6e1..d7fdb5825450 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include "iwl-eeprom.h" | 36 | #include "iwl-eeprom.h" |
37 | #include "iwl-dev.h" | 37 | #include "iwl-dev.h" |
38 | #include "iwl-core.h" | 38 | #include "iwl-core.h" |
39 | #include "iwl-io.h" | ||
39 | #include "iwl-commands.h" | 40 | #include "iwl-commands.h" |
40 | #include "iwl-debug.h" | 41 | #include "iwl-debug.h" |
41 | #include "iwl-power.h" | 42 | #include "iwl-power.h" |
@@ -211,6 +212,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) | |||
211 | { | 212 | { |
212 | struct iwl_power_mgr *setting = &(priv->power_data); | 213 | struct iwl_power_mgr *setting = &(priv->power_data); |
213 | int ret = 0; | 214 | int ret = 0; |
215 | struct iwl_tt_mgmt *tt = &priv->power_data.tt; | ||
214 | u16 uninitialized_var(final_mode); | 216 | u16 uninitialized_var(final_mode); |
215 | bool update_chains; | 217 | bool update_chains; |
216 | 218 | ||
@@ -223,6 +225,10 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) | |||
223 | if (setting->power_disabled) | 225 | if (setting->power_disabled) |
224 | final_mode = IWL_POWER_MODE_CAM; | 226 | final_mode = IWL_POWER_MODE_CAM; |
225 | 227 | ||
228 | if (tt->state >= IWL_TI_1) { | ||
229 | /* TT power setting overwrite user & system power setting */ | ||
230 | final_mode = tt->tt_power_mode; | ||
231 | } | ||
226 | if (iwl_is_ready_rf(priv) && | 232 | if (iwl_is_ready_rf(priv) && |
227 | ((setting->power_mode != final_mode) || force)) { | 233 | ((setting->power_mode != final_mode) || force)) { |
228 | struct iwl_powertable_cmd cmd; | 234 | struct iwl_powertable_cmd cmd; |
@@ -267,6 +273,249 @@ int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode) | |||
267 | } | 273 | } |
268 | EXPORT_SYMBOL(iwl_power_set_user_mode); | 274 | EXPORT_SYMBOL(iwl_power_set_user_mode); |
269 | 275 | ||
276 | #define CT_KILL_EXIT_DURATION (5) /* 5 seconds duration */ | ||
277 | |||
278 | /* | ||
279 | * toggle the bit to wake up uCode and check the temperature | ||
280 | * if the temperature is below CT, uCode will stay awake and send card | ||
281 | * state notification with CT_KILL bit clear to inform Thermal Throttling | ||
282 | * Management to change state. Otherwise, uCode will go back to sleep | ||
283 | * without doing anything, driver should continue the 5 seconds timer | ||
284 | * to wake up uCode for temperature check until temperature drop below CT | ||
285 | */ | ||
286 | static void iwl_tt_check_exit_ct_kill(unsigned long data) | ||
287 | { | ||
288 | struct iwl_priv *priv = (struct iwl_priv *)data; | ||
289 | struct iwl_tt_mgmt *tt = &priv->power_data.tt; | ||
290 | unsigned long flags; | ||
291 | |||
292 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | ||
293 | return; | ||
294 | |||
295 | if (tt->state == IWL_TI_CT_KILL) { | ||
296 | if (priv->power_data.ct_kill_toggle) { | ||
297 | iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, | ||
298 | CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); | ||
299 | priv->power_data.ct_kill_toggle = false; | ||
300 | } else { | ||
301 | iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, | ||
302 | CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); | ||
303 | priv->power_data.ct_kill_toggle = true; | ||
304 | } | ||
305 | iwl_read32(priv, CSR_UCODE_DRV_GP1); | ||
306 | spin_lock_irqsave(&priv->reg_lock, flags); | ||
307 | if (!iwl_grab_nic_access(priv)) | ||
308 | iwl_release_nic_access(priv); | ||
309 | spin_unlock_irqrestore(&priv->reg_lock, flags); | ||
310 | |||
311 | /* Reschedule the ct_kill timer to occur in | ||
312 | * CT_KILL_EXIT_DURATION seconds to ensure we get a | ||
313 | * thermal update */ | ||
314 | mod_timer(&priv->power_data.ct_kill_exit_tm, jiffies + | ||
315 | CT_KILL_EXIT_DURATION * HZ); | ||
316 | } | ||
317 | } | ||
318 | |||
319 | static void iwl_perform_ct_kill_task(struct iwl_priv *priv, | ||
320 | bool stop) | ||
321 | { | ||
322 | if (stop) { | ||
323 | IWL_DEBUG_POWER(priv, "Stop all queues\n"); | ||
324 | if (priv->mac80211_registered) | ||
325 | ieee80211_stop_queues(priv->hw); | ||
326 | IWL_DEBUG_POWER(priv, | ||
327 | "Schedule 5 seconds CT_KILL Timer\n"); | ||
328 | mod_timer(&priv->power_data.ct_kill_exit_tm, jiffies + | ||
329 | CT_KILL_EXIT_DURATION * HZ); | ||
330 | } else { | ||
331 | IWL_DEBUG_POWER(priv, "Wake all queues\n"); | ||
332 | if (priv->mac80211_registered) | ||
333 | ieee80211_wake_queues(priv->hw); | ||
334 | } | ||
335 | } | ||
336 | |||
337 | #define IWL_MINIMAL_POWER_THRESHOLD (CT_KILL_THRESHOLD_LEGACY) | ||
338 | #define IWL_REDUCED_PERFORMANCE_THRESHOLD_2 (100) | ||
339 | #define IWL_REDUCED_PERFORMANCE_THRESHOLD_1 (90) | ||
340 | |||
341 | /* | ||
342 | * Legacy thermal throttling | ||
343 | * 1) Avoid NIC destruction due to high temperatures | ||
344 | * Chip will identify dangerously high temperatures that can | ||
345 | * harm the device and will power down | ||
346 | * 2) Avoid the NIC power down due to high temperature | ||
347 | * Throttle early enough to lower the power consumption before | ||
348 | * drastic steps are needed | ||
349 | */ | ||
350 | static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp) | ||
351 | { | ||
352 | struct iwl_tt_mgmt *tt = &priv->power_data.tt; | ||
353 | enum iwl_tt_state new_state; | ||
354 | struct iwl_power_mgr *setting = &priv->power_data; | ||
355 | |||
356 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
357 | if ((tt->tt_previous_temp) && | ||
358 | (temp > tt->tt_previous_temp) && | ||
359 | ((temp - tt->tt_previous_temp) > | ||
360 | IWL_TT_INCREASE_MARGIN)) { | ||
361 | IWL_DEBUG_POWER(priv, | ||
362 | "Temperature increase %d degree Celsius\n", | ||
363 | (temp - tt->tt_previous_temp)); | ||
364 | } | ||
365 | #endif | ||
366 | /* in Celsius */ | ||
367 | if (temp >= IWL_MINIMAL_POWER_THRESHOLD) | ||
368 | new_state = IWL_TI_CT_KILL; | ||
369 | else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_2) | ||
370 | new_state = IWL_TI_2; | ||
371 | else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_1) | ||
372 | new_state = IWL_TI_1; | ||
373 | else | ||
374 | new_state = IWL_TI_0; | ||
375 | |||
376 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
377 | tt->tt_previous_temp = temp; | ||
378 | #endif | ||
379 | if (tt->state != new_state) { | ||
380 | if (tt->state == IWL_TI_0) { | ||
381 | tt->sys_power_mode = setting->power_mode; | ||
382 | IWL_DEBUG_POWER(priv, "current power mode: %u\n", | ||
383 | setting->power_mode); | ||
384 | } | ||
385 | switch (new_state) { | ||
386 | case IWL_TI_0: | ||
387 | /* when system ready to go back to IWL_TI_0 state | ||
388 | * using system power mode instead of TT power mode | ||
389 | * revert back to the orginal power mode which was saved | ||
390 | * before enter Thermal Throttling state | ||
391 | * update priv->power_data.user_power_setting to the | ||
392 | * required power mode to make sure | ||
393 | * iwl_power_update_mode() will update power correctly. | ||
394 | */ | ||
395 | priv->power_data.user_power_setting = | ||
396 | tt->sys_power_mode; | ||
397 | tt->tt_power_mode = tt->sys_power_mode; | ||
398 | break; | ||
399 | case IWL_TI_1: | ||
400 | tt->tt_power_mode = IWL_POWER_INDEX_3; | ||
401 | break; | ||
402 | case IWL_TI_2: | ||
403 | tt->tt_power_mode = IWL_POWER_INDEX_4; | ||
404 | break; | ||
405 | default: | ||
406 | tt->tt_power_mode = IWL_POWER_INDEX_5; | ||
407 | break; | ||
408 | } | ||
409 | if (iwl_power_update_mode(priv, true)) { | ||
410 | /* TT state not updated | ||
411 | * try again during next temperature read | ||
412 | */ | ||
413 | IWL_ERR(priv, "Cannot update power mode, " | ||
414 | "TT state not updated\n"); | ||
415 | } else { | ||
416 | if (new_state == IWL_TI_CT_KILL) | ||
417 | iwl_perform_ct_kill_task(priv, true); | ||
418 | else if (tt->state == IWL_TI_CT_KILL && | ||
419 | new_state != IWL_TI_CT_KILL) | ||
420 | iwl_perform_ct_kill_task(priv, false); | ||
421 | tt->state = new_state; | ||
422 | IWL_DEBUG_POWER(priv, "Temperature state changed %u\n", | ||
423 | tt->state); | ||
424 | IWL_DEBUG_POWER(priv, "Power Index change to %u\n", | ||
425 | tt->tt_power_mode); | ||
426 | } | ||
427 | } | ||
428 | } | ||
429 | |||
430 | /* Card State Notification indicated reach critical temperature | ||
431 | * if PSP not enable, no Thermal Throttling function will be performed | ||
432 | * just set the GP1 bit to acknowledge the event | ||
433 | * otherwise, go into IWL_TI_CT_KILL state | ||
434 | * since Card State Notification will not provide any temperature reading | ||
435 | * so just pass the CT_KILL temperature to iwl_legacy_tt_handler() | ||
436 | */ | ||
437 | void iwl_tt_enter_ct_kill(struct iwl_priv *priv) | ||
438 | { | ||
439 | struct iwl_tt_mgmt *tt = &priv->power_data.tt; | ||
440 | |||
441 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | ||
442 | return; | ||
443 | |||
444 | if (tt->state != IWL_TI_CT_KILL) { | ||
445 | IWL_ERR(priv, "Device reached critical temperature " | ||
446 | "- ucode going to sleep!\n"); | ||
447 | iwl_legacy_tt_handler(priv, IWL_MINIMAL_POWER_THRESHOLD); | ||
448 | } | ||
449 | } | ||
450 | EXPORT_SYMBOL(iwl_tt_enter_ct_kill); | ||
451 | |||
452 | /* Card State Notification indicated out of critical temperature | ||
453 | * since Card State Notification will not provide any temperature reading | ||
454 | * so pass the IWL_REDUCED_PERFORMANCE_THRESHOLD_2 temperature | ||
455 | * to iwl_legacy_tt_handler() to get out of IWL_CT_KILL state | ||
456 | */ | ||
457 | void iwl_tt_exit_ct_kill(struct iwl_priv *priv) | ||
458 | { | ||
459 | struct iwl_tt_mgmt *tt = &priv->power_data.tt; | ||
460 | |||
461 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | ||
462 | return; | ||
463 | |||
464 | /* stop ct_kill_exit_tm timer */ | ||
465 | del_timer_sync(&priv->power_data.ct_kill_exit_tm); | ||
466 | |||
467 | if (tt->state == IWL_TI_CT_KILL) { | ||
468 | IWL_ERR(priv, | ||
469 | "Device temperature below critical" | ||
470 | "- ucode awake!\n"); | ||
471 | iwl_legacy_tt_handler(priv, | ||
472 | IWL_REDUCED_PERFORMANCE_THRESHOLD_2); | ||
473 | } | ||
474 | } | ||
475 | EXPORT_SYMBOL(iwl_tt_exit_ct_kill); | ||
476 | |||
477 | void iwl_tt_handler(struct iwl_priv *priv) | ||
478 | { | ||
479 | s32 temp = priv->temperature; /* degrees CELSIUS except 4965 */ | ||
480 | |||
481 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | ||
482 | return; | ||
483 | |||
484 | if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) | ||
485 | temp = KELVIN_TO_CELSIUS(priv->temperature); | ||
486 | |||
487 | iwl_legacy_tt_handler(priv, temp); | ||
488 | } | ||
489 | EXPORT_SYMBOL(iwl_tt_handler); | ||
490 | |||
491 | /* Thermal throttling initialization | ||
492 | */ | ||
493 | void iwl_tt_initialize(struct iwl_priv *priv) | ||
494 | { | ||
495 | struct iwl_tt_mgmt *tt = &priv->power_data.tt; | ||
496 | struct iwl_power_mgr *setting = &priv->power_data; | ||
497 | |||
498 | IWL_DEBUG_POWER(priv, "Initialize Thermal Throttling \n"); | ||
499 | |||
500 | memset(tt, 0, sizeof(struct iwl_tt_mgmt)); | ||
501 | |||
502 | tt->state = IWL_TI_0; | ||
503 | tt->sys_power_mode = setting->power_mode; | ||
504 | tt->tt_power_mode = tt->sys_power_mode; | ||
505 | init_timer(&priv->power_data.ct_kill_exit_tm); | ||
506 | priv->power_data.ct_kill_exit_tm.data = (unsigned long)priv; | ||
507 | priv->power_data.ct_kill_exit_tm.function = iwl_tt_check_exit_ct_kill; | ||
508 | } | ||
509 | EXPORT_SYMBOL(iwl_tt_initialize); | ||
510 | |||
511 | /* cleanup thermal throttling management related memory and timer */ | ||
512 | void iwl_tt_exit(struct iwl_priv *priv) | ||
513 | { | ||
514 | /* stop ct_kill_exit_tm timer if activated */ | ||
515 | del_timer_sync(&priv->power_data.ct_kill_exit_tm); | ||
516 | } | ||
517 | EXPORT_SYMBOL(iwl_tt_exit); | ||
518 | |||
270 | /* initialize to default */ | 519 | /* initialize to default */ |
271 | void iwl_power_initialize(struct iwl_priv *priv) | 520 | void iwl_power_initialize(struct iwl_priv *priv) |
272 | { | 521 | { |
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index 37ba3bb7a25a..7bb10d41ae5f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h | |||
@@ -33,6 +33,38 @@ | |||
33 | 33 | ||
34 | struct iwl_priv; | 34 | struct iwl_priv; |
35 | 35 | ||
36 | #define IWL_TT_INCREASE_MARGIN 5 | ||
37 | |||
38 | /* Thermal Throttling State Machine states */ | ||
39 | enum iwl_tt_state { | ||
40 | IWL_TI_0, /* normal temperature, system power state */ | ||
41 | IWL_TI_1, /* high temperature detect, low power state */ | ||
42 | IWL_TI_2, /* higher temperature detected, lower power state */ | ||
43 | IWL_TI_CT_KILL, /* critical temperature detected, lowest power state */ | ||
44 | IWL_TI_STATE_MAX | ||
45 | }; | ||
46 | |||
47 | /** | ||
48 | * struct iwl_tt_mgnt - Thermal Throttling Management structure | ||
49 | * @state: current Thermal Throttling state | ||
50 | * @tt_power_mode: Thermal Throttling power mode index | ||
51 | * being used to set power level when | ||
52 | * when thermal throttling state != IWL_TI_0 | ||
53 | * the tt_power_mode should set to different | ||
54 | * power mode based on the current tt state | ||
55 | * @sys_power_mode: previous system power mode | ||
56 | * before transition into TT state | ||
57 | * @tt_previous_temperature: last measured temperature | ||
58 | */ | ||
59 | struct iwl_tt_mgmt { | ||
60 | enum iwl_tt_state state; | ||
61 | u8 tt_power_mode; | ||
62 | u8 sys_power_mode; | ||
63 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
64 | s32 tt_previous_temp; | ||
65 | #endif | ||
66 | }; | ||
67 | |||
36 | enum { | 68 | enum { |
37 | IWL_POWER_MODE_CAM, /* Continuously Aware Mode, always on */ | 69 | IWL_POWER_MODE_CAM, /* Continuously Aware Mode, always on */ |
38 | IWL_POWER_INDEX_1, | 70 | IWL_POWER_INDEX_1, |
@@ -59,10 +91,20 @@ struct iwl_power_mgr { | |||
59 | u8 power_mode; | 91 | u8 power_mode; |
60 | u8 user_power_setting; /* set by user through sysfs */ | 92 | u8 user_power_setting; /* set by user through sysfs */ |
61 | u8 power_disabled; /* set by mac80211's CONF_PS */ | 93 | u8 power_disabled; /* set by mac80211's CONF_PS */ |
94 | struct iwl_tt_mgmt tt; /* Thermal Throttling Management */ | ||
95 | bool ct_kill_toggle; /* use to toggle the CSR bit when | ||
96 | * checking uCode temperature | ||
97 | */ | ||
98 | struct timer_list ct_kill_exit_tm; | ||
62 | }; | 99 | }; |
63 | 100 | ||
64 | int iwl_power_update_mode(struct iwl_priv *priv, bool force); | 101 | int iwl_power_update_mode(struct iwl_priv *priv, bool force); |
65 | int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode); | 102 | int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode); |
103 | void iwl_tt_enter_ct_kill(struct iwl_priv *priv); | ||
104 | void iwl_tt_exit_ct_kill(struct iwl_priv *priv); | ||
105 | void iwl_tt_handler(struct iwl_priv *priv); | ||
106 | void iwl_tt_initialize(struct iwl_priv *priv); | ||
107 | void iwl_tt_exit(struct iwl_priv *priv); | ||
66 | void iwl_power_initialize(struct iwl_priv *priv); | 108 | void iwl_power_initialize(struct iwl_priv *priv); |
67 | 109 | ||
68 | #endif /* __iwl_power_setting_h__ */ | 110 | #endif /* __iwl_power_setting_h__ */ |