linux/drivers/net/wireless/iwlwifi/dvm/tt.c
<<
>>
Prefs
   1/******************************************************************************
   2 *
   3 * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
   4 *
   5 * Portions of this file are derived from the ipw3945 project, as well
   6 * as portions of the ieee80211 subsystem header files.
   7 *
   8 * This program is free software; you can redistribute it and/or modify it
   9 * under the terms of version 2 of the GNU General Public License as
  10 * published by the Free Software Foundation.
  11 *
  12 * This program is distributed in the hope that it will be useful, but WITHOUT
  13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  15 * more details.
  16 *
  17 * You should have received a copy of the GNU General Public License along with
  18 * this program; if not, write to the Free Software Foundation, Inc.,
  19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
  20 *
  21 * The full GNU General Public License is included in this distribution in the
  22 * file called LICENSE.
  23 *
  24 * Contact Information:
  25 *  Intel Linux Wireless <ilw@linux.intel.com>
  26 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  27 *****************************************************************************/
  28
  29
  30#include <linux/kernel.h>
  31#include <linux/module.h>
  32#include <linux/slab.h>
  33#include <linux/init.h>
  34#include <net/mac80211.h>
  35#include "iwl-io.h"
  36#include "iwl-modparams.h"
  37#include "iwl-debug.h"
  38#include "agn.h"
  39#include "dev.h"
  40#include "commands.h"
  41#include "tt.h"
  42
  43/* default Thermal Throttling transaction table
  44 * Current state   |         Throttling Down               |  Throttling Up
  45 *=============================================================================
  46 *                 Condition Nxt State  Condition Nxt State Condition Nxt State
  47 *-----------------------------------------------------------------------------
  48 *     IWL_TI_0     T >= 114   CT_KILL  114>T>=105   TI_1      N/A      N/A
  49 *     IWL_TI_1     T >= 114   CT_KILL  114>T>=110   TI_2     T<=95     TI_0
  50 *     IWL_TI_2     T >= 114   CT_KILL                        T<=100    TI_1
  51 *    IWL_CT_KILL      N/A       N/A       N/A        N/A     T<=95     TI_0
  52 *=============================================================================
  53 */
  54static const struct iwl_tt_trans tt_range_0[IWL_TI_STATE_MAX - 1] = {
  55        {IWL_TI_0, IWL_ABSOLUTE_ZERO, 104},
  56        {IWL_TI_1, 105, CT_KILL_THRESHOLD - 1},
  57        {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
  58};
  59static const struct iwl_tt_trans tt_range_1[IWL_TI_STATE_MAX - 1] = {
  60        {IWL_TI_0, IWL_ABSOLUTE_ZERO, 95},
  61        {IWL_TI_2, 110, CT_KILL_THRESHOLD - 1},
  62        {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
  63};
  64static const struct iwl_tt_trans tt_range_2[IWL_TI_STATE_MAX - 1] = {
  65        {IWL_TI_1, IWL_ABSOLUTE_ZERO, 100},
  66        {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX},
  67        {IWL_TI_CT_KILL, CT_KILL_THRESHOLD, IWL_ABSOLUTE_MAX}
  68};
  69static const struct iwl_tt_trans tt_range_3[IWL_TI_STATE_MAX - 1] = {
  70        {IWL_TI_0, IWL_ABSOLUTE_ZERO, CT_KILL_EXIT_THRESHOLD},
  71        {IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX},
  72        {IWL_TI_CT_KILL, CT_KILL_EXIT_THRESHOLD + 1, IWL_ABSOLUTE_MAX}
  73};
  74
  75/* Advance Thermal Throttling default restriction table */
  76static const struct iwl_tt_restriction restriction_range[IWL_TI_STATE_MAX] = {
  77        {IWL_ANT_OK_MULTI, IWL_ANT_OK_MULTI, true },
  78        {IWL_ANT_OK_SINGLE, IWL_ANT_OK_MULTI, true },
  79        {IWL_ANT_OK_SINGLE, IWL_ANT_OK_SINGLE, false },
  80        {IWL_ANT_OK_NONE, IWL_ANT_OK_NONE, false }
  81};
  82
  83bool iwl_tt_is_low_power_state(struct iwl_priv *priv)
  84{
  85        struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
  86
  87        if (tt->state >= IWL_TI_1)
  88                return true;
  89        return false;
  90}
  91
  92u8 iwl_tt_current_power_mode(struct iwl_priv *priv)
  93{
  94        struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
  95
  96        return tt->tt_power_mode;
  97}
  98
  99bool iwl_ht_enabled(struct iwl_priv *priv)
 100{
 101        struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
 102        struct iwl_tt_restriction *restriction;
 103
 104        if (!priv->thermal_throttle.advanced_tt)
 105                return true;
 106        restriction = tt->restriction + tt->state;
 107        return restriction->is_ht;
 108}
 109
 110static bool iwl_within_ct_kill_margin(struct iwl_priv *priv)
 111{
 112        s32 temp = priv->temperature; /* degrees CELSIUS except specified */
 113        bool within_margin = false;
 114
 115        if (!priv->thermal_throttle.advanced_tt)
 116                within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >=
 117                                CT_KILL_THRESHOLD_LEGACY) ? true : false;
 118        else
 119                within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >=
 120                                CT_KILL_THRESHOLD) ? true : false;
 121        return within_margin;
 122}
 123
 124bool iwl_check_for_ct_kill(struct iwl_priv *priv)
 125{
 126        bool is_ct_kill = false;
 127
 128        if (iwl_within_ct_kill_margin(priv)) {
 129                iwl_tt_enter_ct_kill(priv);
 130                is_ct_kill = true;
 131        }
 132        return is_ct_kill;
 133}
 134
 135enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv)
 136{
 137        struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
 138        struct iwl_tt_restriction *restriction;
 139
 140        if (!priv->thermal_throttle.advanced_tt)
 141                return IWL_ANT_OK_MULTI;
 142        restriction = tt->restriction + tt->state;
 143        return restriction->tx_stream;
 144}
 145
 146enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv)
 147{
 148        struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
 149        struct iwl_tt_restriction *restriction;
 150
 151        if (!priv->thermal_throttle.advanced_tt)
 152                return IWL_ANT_OK_MULTI;
 153        restriction = tt->restriction + tt->state;
 154        return restriction->rx_stream;
 155}
 156
 157#define CT_KILL_EXIT_DURATION (5)       /* 5 seconds duration */
 158#define CT_KILL_WAITING_DURATION (300)  /* 300ms duration */
 159
 160/*
 161 * toggle the bit to wake up uCode and check the temperature
 162 * if the temperature is below CT, uCode will stay awake and send card
 163 * state notification with CT_KILL bit clear to inform Thermal Throttling
 164 * Management to change state. Otherwise, uCode will go back to sleep
 165 * without doing anything, driver should continue the 5 seconds timer
 166 * to wake up uCode for temperature check until temperature drop below CT
 167 */
 168static void iwl_tt_check_exit_ct_kill(unsigned long data)
 169{
 170        struct iwl_priv *priv = (struct iwl_priv *)data;
 171        struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
 172        unsigned long flags;
 173
 174        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 175                return;
 176
 177        if (tt->state == IWL_TI_CT_KILL) {
 178                if (priv->thermal_throttle.ct_kill_toggle) {
 179                        iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR,
 180                                    CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
 181                        priv->thermal_throttle.ct_kill_toggle = false;
 182                } else {
 183                        iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET,
 184                                    CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
 185                        priv->thermal_throttle.ct_kill_toggle = true;
 186                }
 187                iwl_read32(priv->trans, CSR_UCODE_DRV_GP1);
 188                if (iwl_trans_grab_nic_access(priv->trans, false, &flags))
 189                        iwl_trans_release_nic_access(priv->trans, &flags);
 190
 191                /* Reschedule the ct_kill timer to occur in
 192                 * CT_KILL_EXIT_DURATION seconds to ensure we get a
 193                 * thermal update */
 194                IWL_DEBUG_TEMP(priv, "schedule ct_kill exit timer\n");
 195                mod_timer(&priv->thermal_throttle.ct_kill_exit_tm,
 196                          jiffies + CT_KILL_EXIT_DURATION * HZ);
 197        }
 198}
 199
 200static void iwl_perform_ct_kill_task(struct iwl_priv *priv,
 201                           bool stop)
 202{
 203        if (stop) {
 204                IWL_DEBUG_TEMP(priv, "Stop all queues\n");
 205                if (priv->mac80211_registered)
 206                        ieee80211_stop_queues(priv->hw);
 207                IWL_DEBUG_TEMP(priv,
 208                                "Schedule 5 seconds CT_KILL Timer\n");
 209                mod_timer(&priv->thermal_throttle.ct_kill_exit_tm,
 210                          jiffies + CT_KILL_EXIT_DURATION * HZ);
 211        } else {
 212                IWL_DEBUG_TEMP(priv, "Wake all queues\n");
 213                if (priv->mac80211_registered)
 214                        ieee80211_wake_queues(priv->hw);
 215        }
 216}
 217
 218static void iwl_tt_ready_for_ct_kill(unsigned long data)
 219{
 220        struct iwl_priv *priv = (struct iwl_priv *)data;
 221        struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
 222
 223        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 224                return;
 225
 226        /* temperature timer expired, ready to go into CT_KILL state */
 227        if (tt->state != IWL_TI_CT_KILL) {
 228                IWL_DEBUG_TEMP(priv, "entering CT_KILL state when "
 229                                "temperature timer expired\n");
 230                tt->state = IWL_TI_CT_KILL;
 231                set_bit(STATUS_CT_KILL, &priv->status);
 232                iwl_perform_ct_kill_task(priv, true);
 233        }
 234}
 235
 236static void iwl_prepare_ct_kill_task(struct iwl_priv *priv)
 237{
 238        IWL_DEBUG_TEMP(priv, "Prepare to enter IWL_TI_CT_KILL\n");
 239        /* make request to retrieve statistics information */
 240        iwl_send_statistics_request(priv, CMD_SYNC, false);
 241        /* Reschedule the ct_kill wait timer */
 242        mod_timer(&priv->thermal_throttle.ct_kill_waiting_tm,
 243                 jiffies + msecs_to_jiffies(CT_KILL_WAITING_DURATION));
 244}
 245
 246#define IWL_MINIMAL_POWER_THRESHOLD             (CT_KILL_THRESHOLD_LEGACY)
 247#define IWL_REDUCED_PERFORMANCE_THRESHOLD_2     (100)
 248#define IWL_REDUCED_PERFORMANCE_THRESHOLD_1     (90)
 249
 250/*
 251 * Legacy thermal throttling
 252 * 1) Avoid NIC destruction due to high temperatures
 253 *      Chip will identify dangerously high temperatures that can
 254 *      harm the device and will power down
 255 * 2) Avoid the NIC power down due to high temperature
 256 *      Throttle early enough to lower the power consumption before
 257 *      drastic steps are needed
 258 */
 259static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
 260{
 261        struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
 262        enum iwl_tt_state old_state;
 263
 264#ifdef CONFIG_IWLWIFI_DEBUG
 265        if ((tt->tt_previous_temp) &&
 266            (temp > tt->tt_previous_temp) &&
 267            ((temp - tt->tt_previous_temp) >
 268            IWL_TT_INCREASE_MARGIN)) {
 269                IWL_DEBUG_TEMP(priv,
 270                        "Temperature increase %d degree Celsius\n",
 271                        (temp - tt->tt_previous_temp));
 272        }
 273#endif
 274        old_state = tt->state;
 275        /* in Celsius */
 276        if (temp >= IWL_MINIMAL_POWER_THRESHOLD)
 277                tt->state = IWL_TI_CT_KILL;
 278        else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_2)
 279                tt->state = IWL_TI_2;
 280        else if (temp >= IWL_REDUCED_PERFORMANCE_THRESHOLD_1)
 281                tt->state = IWL_TI_1;
 282        else
 283                tt->state = IWL_TI_0;
 284
 285#ifdef CONFIG_IWLWIFI_DEBUG
 286        tt->tt_previous_temp = temp;
 287#endif
 288        /* stop ct_kill_waiting_tm timer */
 289        del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
 290        if (tt->state != old_state) {
 291                switch (tt->state) {
 292                case IWL_TI_0:
 293                        /*
 294                         * When the system is ready to go back to IWL_TI_0
 295                         * we only have to call iwl_power_update_mode() to
 296                         * do so.
 297                         */
 298                        break;
 299                case IWL_TI_1:
 300                        tt->tt_power_mode = IWL_POWER_INDEX_3;
 301                        break;
 302                case IWL_TI_2:
 303                        tt->tt_power_mode = IWL_POWER_INDEX_4;
 304                        break;
 305                default:
 306                        tt->tt_power_mode = IWL_POWER_INDEX_5;
 307                        break;
 308                }
 309                mutex_lock(&priv->mutex);
 310                if (old_state == IWL_TI_CT_KILL)
 311                        clear_bit(STATUS_CT_KILL, &priv->status);
 312                if (tt->state != IWL_TI_CT_KILL &&
 313                    iwl_power_update_mode(priv, true)) {
 314                        /* TT state not updated
 315                         * try again during next temperature read
 316                         */
 317                        if (old_state == IWL_TI_CT_KILL)
 318                                set_bit(STATUS_CT_KILL, &priv->status);
 319                        tt->state = old_state;
 320                        IWL_ERR(priv, "Cannot update power mode, "
 321                                        "TT state not updated\n");
 322                } else {
 323                        if (tt->state == IWL_TI_CT_KILL) {
 324                                if (force) {
 325                                        set_bit(STATUS_CT_KILL, &priv->status);
 326                                        iwl_perform_ct_kill_task(priv, true);
 327                                } else {
 328                                        iwl_prepare_ct_kill_task(priv);
 329                                        tt->state = old_state;
 330                                }
 331                        } else if (old_state == IWL_TI_CT_KILL &&
 332                                 tt->state != IWL_TI_CT_KILL)
 333                                iwl_perform_ct_kill_task(priv, false);
 334                        IWL_DEBUG_TEMP(priv, "Temperature state changed %u\n",
 335                                        tt->state);
 336                        IWL_DEBUG_TEMP(priv, "Power Index change to %u\n",
 337                                        tt->tt_power_mode);
 338                }
 339                mutex_unlock(&priv->mutex);
 340        }
 341}
 342
 343/*
 344 * Advance thermal throttling
 345 * 1) Avoid NIC destruction due to high temperatures
 346 *      Chip will identify dangerously high temperatures that can
 347 *      harm the device and will power down
 348 * 2) Avoid the NIC power down due to high temperature
 349 *      Throttle early enough to lower the power consumption before
 350 *      drastic steps are needed
 351 *      Actions include relaxing the power down sleep thresholds and
 352 *      decreasing the number of TX streams
 353 * 3) Avoid throughput performance impact as much as possible
 354 *
 355 *=============================================================================
 356 *                 Condition Nxt State  Condition Nxt State Condition Nxt State
 357 *-----------------------------------------------------------------------------
 358 *     IWL_TI_0     T >= 114   CT_KILL  114>T>=105   TI_1      N/A      N/A
 359 *     IWL_TI_1     T >= 114   CT_KILL  114>T>=110   TI_2     T<=95     TI_0
 360 *     IWL_TI_2     T >= 114   CT_KILL                        T<=100    TI_1
 361 *    IWL_CT_KILL      N/A       N/A       N/A        N/A     T<=95     TI_0
 362 *=============================================================================
 363 */
 364static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp, bool force)
 365{
 366        struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
 367        int i;
 368        bool changed = false;
 369        enum iwl_tt_state old_state;
 370        struct iwl_tt_trans *transaction;
 371
 372        old_state = tt->state;
 373        for (i = 0; i < IWL_TI_STATE_MAX - 1; i++) {
 374                /* based on the current TT state,
 375                 * find the curresponding transaction table
 376                 * each table has (IWL_TI_STATE_MAX - 1) entries
 377                 * tt->transaction + ((old_state * (IWL_TI_STATE_MAX - 1))
 378                 * will advance to the correct table.
 379                 * then based on the current temperature
 380                 * find the next state need to transaction to
 381                 * go through all the possible (IWL_TI_STATE_MAX - 1) entries
 382                 * in the current table to see if transaction is needed
 383                 */
 384                transaction = tt->transaction +
 385                        ((old_state * (IWL_TI_STATE_MAX - 1)) + i);
 386                if (temp >= transaction->tt_low &&
 387                    temp <= transaction->tt_high) {
 388#ifdef CONFIG_IWLWIFI_DEBUG
 389                        if ((tt->tt_previous_temp) &&
 390                            (temp > tt->tt_previous_temp) &&
 391                            ((temp - tt->tt_previous_temp) >
 392                            IWL_TT_INCREASE_MARGIN)) {
 393                                IWL_DEBUG_TEMP(priv,
 394                                        "Temperature increase %d "
 395                                        "degree Celsius\n",
 396                                        (temp - tt->tt_previous_temp));
 397                        }
 398                        tt->tt_previous_temp = temp;
 399#endif
 400                        if (old_state !=
 401                            transaction->next_state) {
 402                                changed = true;
 403                                tt->state =
 404                                        transaction->next_state;
 405                        }
 406                        break;
 407                }
 408        }
 409        /* stop ct_kill_waiting_tm timer */
 410        del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
 411        if (changed) {
 412                if (tt->state >= IWL_TI_1) {
 413                        /* force PI = IWL_POWER_INDEX_5 in the case of TI > 0 */
 414                        tt->tt_power_mode = IWL_POWER_INDEX_5;
 415
 416                        if (!iwl_ht_enabled(priv)) {
 417                                struct iwl_rxon_context *ctx;
 418
 419                                for_each_context(priv, ctx) {
 420                                        struct iwl_rxon_cmd *rxon;
 421
 422                                        rxon = &ctx->staging;
 423
 424                                        /* disable HT */
 425                                        rxon->flags &= ~(
 426                                                RXON_FLG_CHANNEL_MODE_MSK |
 427                                                RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK |
 428                                                RXON_FLG_HT40_PROT_MSK |
 429                                                RXON_FLG_HT_PROT_MSK);
 430                                }
 431                        } else {
 432                                /* check HT capability and set
 433                                 * according to the system HT capability
 434                                 * in case get disabled before */
 435                                iwl_set_rxon_ht(priv, &priv->current_ht_config);
 436                        }
 437
 438                } else {
 439                        /*
 440                         * restore system power setting -- it will be
 441                         * recalculated automatically.
 442                         */
 443
 444                        /* check HT capability and set
 445                         * according to the system HT capability
 446                         * in case get disabled before */
 447                        iwl_set_rxon_ht(priv, &priv->current_ht_config);
 448                }
 449                mutex_lock(&priv->mutex);
 450                if (old_state == IWL_TI_CT_KILL)
 451                        clear_bit(STATUS_CT_KILL, &priv->status);
 452                if (tt->state != IWL_TI_CT_KILL &&
 453                    iwl_power_update_mode(priv, true)) {
 454                        /* TT state not updated
 455                         * try again during next temperature read
 456                         */
 457                        IWL_ERR(priv, "Cannot update power mode, "
 458                                        "TT state not updated\n");
 459                        if (old_state == IWL_TI_CT_KILL)
 460                                set_bit(STATUS_CT_KILL, &priv->status);
 461                        tt->state = old_state;
 462                } else {
 463                        IWL_DEBUG_TEMP(priv,
 464                                        "Thermal Throttling to new state: %u\n",
 465                                        tt->state);
 466                        if (old_state != IWL_TI_CT_KILL &&
 467                            tt->state == IWL_TI_CT_KILL) {
 468                                if (force) {
 469                                        IWL_DEBUG_TEMP(priv,
 470                                                "Enter IWL_TI_CT_KILL\n");
 471                                        set_bit(STATUS_CT_KILL, &priv->status);
 472                                        iwl_perform_ct_kill_task(priv, true);
 473                                } else {
 474                                        tt->state = old_state;
 475                                        iwl_prepare_ct_kill_task(priv);
 476                                }
 477                        } else if (old_state == IWL_TI_CT_KILL &&
 478                                  tt->state != IWL_TI_CT_KILL) {
 479                                IWL_DEBUG_TEMP(priv, "Exit IWL_TI_CT_KILL\n");
 480                                iwl_perform_ct_kill_task(priv, false);
 481                        }
 482                }
 483                mutex_unlock(&priv->mutex);
 484        }
 485}
 486
 487/* Card State Notification indicated reach critical temperature
 488 * if PSP not enable, no Thermal Throttling function will be performed
 489 * just set the GP1 bit to acknowledge the event
 490 * otherwise, go into IWL_TI_CT_KILL state
 491 * since Card State Notification will not provide any temperature reading
 492 * for Legacy mode
 493 * so just pass the CT_KILL temperature to iwl_legacy_tt_handler()
 494 * for advance mode
 495 * pass CT_KILL_THRESHOLD+1 to make sure move into IWL_TI_CT_KILL state
 496 */
 497static void iwl_bg_ct_enter(struct work_struct *work)
 498{
 499        struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_enter);
 500        struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
 501
 502        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 503                return;
 504
 505        if (!iwl_is_ready(priv))
 506                return;
 507
 508        if (tt->state != IWL_TI_CT_KILL) {
 509                IWL_ERR(priv, "Device reached critical temperature "
 510                              "- ucode going to sleep!\n");
 511                if (!priv->thermal_throttle.advanced_tt)
 512                        iwl_legacy_tt_handler(priv,
 513                                              IWL_MINIMAL_POWER_THRESHOLD,
 514                                              true);
 515                else
 516                        iwl_advance_tt_handler(priv,
 517                                               CT_KILL_THRESHOLD + 1, true);
 518        }
 519}
 520
 521/* Card State Notification indicated out of critical temperature
 522 * since Card State Notification will not provide any temperature reading
 523 * so pass the IWL_REDUCED_PERFORMANCE_THRESHOLD_2 temperature
 524 * to iwl_legacy_tt_handler() to get out of IWL_CT_KILL state
 525 */
 526static void iwl_bg_ct_exit(struct work_struct *work)
 527{
 528        struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_exit);
 529        struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
 530
 531        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 532                return;
 533
 534        if (!iwl_is_ready(priv))
 535                return;
 536
 537        /* stop ct_kill_exit_tm timer */
 538        del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm);
 539
 540        if (tt->state == IWL_TI_CT_KILL) {
 541                IWL_ERR(priv,
 542                        "Device temperature below critical"
 543                        "- ucode awake!\n");
 544                /*
 545                 * exit from CT_KILL state
 546                 * reset the current temperature reading
 547                 */
 548                priv->temperature = 0;
 549                if (!priv->thermal_throttle.advanced_tt)
 550                        iwl_legacy_tt_handler(priv,
 551                                      IWL_REDUCED_PERFORMANCE_THRESHOLD_2,
 552                                      true);
 553                else
 554                        iwl_advance_tt_handler(priv, CT_KILL_EXIT_THRESHOLD,
 555                                               true);
 556        }
 557}
 558
 559void iwl_tt_enter_ct_kill(struct iwl_priv *priv)
 560{
 561        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 562                return;
 563
 564        IWL_DEBUG_TEMP(priv, "Queueing critical temperature enter.\n");
 565        queue_work(priv->workqueue, &priv->ct_enter);
 566}
 567
 568void iwl_tt_exit_ct_kill(struct iwl_priv *priv)
 569{
 570        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 571                return;
 572
 573        IWL_DEBUG_TEMP(priv, "Queueing critical temperature exit.\n");
 574        queue_work(priv->workqueue, &priv->ct_exit);
 575}
 576
 577static void iwl_bg_tt_work(struct work_struct *work)
 578{
 579        struct iwl_priv *priv = container_of(work, struct iwl_priv, tt_work);
 580        s32 temp = priv->temperature; /* degrees CELSIUS except specified */
 581
 582        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 583                return;
 584
 585        if (!priv->thermal_throttle.advanced_tt)
 586                iwl_legacy_tt_handler(priv, temp, false);
 587        else
 588                iwl_advance_tt_handler(priv, temp, false);
 589}
 590
 591void iwl_tt_handler(struct iwl_priv *priv)
 592{
 593        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 594                return;
 595
 596        IWL_DEBUG_TEMP(priv, "Queueing thermal throttling work.\n");
 597        queue_work(priv->workqueue, &priv->tt_work);
 598}
 599
 600/* Thermal throttling initialization
 601 * For advance thermal throttling:
 602 *     Initialize Thermal Index and temperature threshold table
 603 *     Initialize thermal throttling restriction table
 604 */
 605void iwl_tt_initialize(struct iwl_priv *priv)
 606{
 607        struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
 608        int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1);
 609        struct iwl_tt_trans *transaction;
 610
 611        IWL_DEBUG_TEMP(priv, "Initialize Thermal Throttling\n");
 612
 613        memset(tt, 0, sizeof(struct iwl_tt_mgmt));
 614
 615        tt->state = IWL_TI_0;
 616        init_timer(&priv->thermal_throttle.ct_kill_exit_tm);
 617        priv->thermal_throttle.ct_kill_exit_tm.data = (unsigned long)priv;
 618        priv->thermal_throttle.ct_kill_exit_tm.function =
 619                iwl_tt_check_exit_ct_kill;
 620        init_timer(&priv->thermal_throttle.ct_kill_waiting_tm);
 621        priv->thermal_throttle.ct_kill_waiting_tm.data =
 622                (unsigned long)priv;
 623        priv->thermal_throttle.ct_kill_waiting_tm.function =
 624                iwl_tt_ready_for_ct_kill;
 625        /* setup deferred ct kill work */
 626        INIT_WORK(&priv->tt_work, iwl_bg_tt_work);
 627        INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter);
 628        INIT_WORK(&priv->ct_exit, iwl_bg_ct_exit);
 629
 630        if (priv->lib->adv_thermal_throttle) {
 631                IWL_DEBUG_TEMP(priv, "Advanced Thermal Throttling\n");
 632                tt->restriction = kcalloc(IWL_TI_STATE_MAX,
 633                                          sizeof(struct iwl_tt_restriction),
 634                                          GFP_KERNEL);
 635                tt->transaction = kcalloc(IWL_TI_STATE_MAX *
 636                                          (IWL_TI_STATE_MAX - 1),
 637                                          sizeof(struct iwl_tt_trans),
 638                                          GFP_KERNEL);
 639                if (!tt->restriction || !tt->transaction) {
 640                        IWL_ERR(priv, "Fallback to Legacy Throttling\n");
 641                        priv->thermal_throttle.advanced_tt = false;
 642                        kfree(tt->restriction);
 643                        tt->restriction = NULL;
 644                        kfree(tt->transaction);
 645                        tt->transaction = NULL;
 646                } else {
 647                        transaction = tt->transaction +
 648                                (IWL_TI_0 * (IWL_TI_STATE_MAX - 1));
 649                        memcpy(transaction, &tt_range_0[0], size);
 650                        transaction = tt->transaction +
 651                                (IWL_TI_1 * (IWL_TI_STATE_MAX - 1));
 652                        memcpy(transaction, &tt_range_1[0], size);
 653                        transaction = tt->transaction +
 654                                (IWL_TI_2 * (IWL_TI_STATE_MAX - 1));
 655                        memcpy(transaction, &tt_range_2[0], size);
 656                        transaction = tt->transaction +
 657                                (IWL_TI_CT_KILL * (IWL_TI_STATE_MAX - 1));
 658                        memcpy(transaction, &tt_range_3[0], size);
 659                        size = sizeof(struct iwl_tt_restriction) *
 660                                IWL_TI_STATE_MAX;
 661                        memcpy(tt->restriction,
 662                                &restriction_range[0], size);
 663                        priv->thermal_throttle.advanced_tt = true;
 664                }
 665        } else {
 666                IWL_DEBUG_TEMP(priv, "Legacy Thermal Throttling\n");
 667                priv->thermal_throttle.advanced_tt = false;
 668        }
 669}
 670
 671/* cleanup thermal throttling management related memory and timer */
 672void iwl_tt_exit(struct iwl_priv *priv)
 673{
 674        struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
 675
 676        /* stop ct_kill_exit_tm timer if activated */
 677        del_timer_sync(&priv->thermal_throttle.ct_kill_exit_tm);
 678        /* stop ct_kill_waiting_tm timer if activated */
 679        del_timer_sync(&priv->thermal_throttle.ct_kill_waiting_tm);
 680        cancel_work_sync(&priv->tt_work);
 681        cancel_work_sync(&priv->ct_enter);
 682        cancel_work_sync(&priv->ct_exit);
 683
 684        if (priv->thermal_throttle.advanced_tt) {
 685                /* free advance thermal throttling memory */
 686                kfree(tt->restriction);
 687                tt->restriction = NULL;
 688                kfree(tt->transaction);
 689                tt->transaction = NULL;
 690        }
 691}
 692