iwlwifi: mvm: handle platform PCIe power limitation
authorIdo Yariv <ido@wizery.com>
Fri, 17 Jan 2014 02:12:02 +0000 (21:12 -0500)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Mon, 3 Feb 2014 20:23:38 +0000 (22:23 +0200)
The tx backoff settings used by the thermal throttling mechanism can
also be used for enforcing a limit on the power consumption of the module.

Handle the platform PCIe power limitation by translating the limit
(measured in mw) to its respective tx backoff value. The translation is
module specific.

The resulting tx backoff value is sent to the ucode, and also serves as the
minimal backoff value that can be set by the thermal throttling mechanism.

Signed-off-by: Ido Yariv <idox.yariv@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
drivers/net/wireless/iwlwifi/iwl-config.h
drivers/net/wireless/iwlwifi/mvm/fw.c
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/ops.c
drivers/net/wireless/iwlwifi/mvm/tt.c

index df7d409023b672eb0ec9b4c449e23adab8e47c6e..456fccaf1cbbd3b6dbd0f96c255ec5909c37d1a4 100644 (file)
@@ -193,6 +193,15 @@ struct iwl_eeprom_params {
        bool enhanced_txpower;
 };
 
+/* Tx-backoff power threshold
+ * @pwr: The power limit in mw
+ * @backoff: The tx-backoff in uSec
+ */
+struct iwl_pwr_tx_backoff {
+       u32 pwr;
+       u32 backoff;
+};
+
 /**
  * struct iwl_cfg
  * @name: Offical name of the device
@@ -219,6 +228,7 @@ struct iwl_eeprom_params {
  * @host_interrupt_operation_mode: device needs host interrupt operation
  *     mode set
  * @nvm_hw_section_num: the ID of the HW NVM section
+ * @pwr_tx_backoffs: translation table between power limits and backoffs
  *
  * We enable the driver to be backward compatible wrt. hardware features.
  * API differences in uCode shouldn't be handled here but through TLVs
@@ -250,6 +260,7 @@ struct iwl_cfg {
        const bool host_interrupt_operation_mode;
        bool high_temp;
        u8   nvm_hw_section_num;
+       const struct iwl_pwr_tx_backoff *pwr_tx_backoffs;
 };
 
 /*
index c03d39541f9ee50d7f179982d4a688d3f90c4246..5798f1ae74829c73e8e5a354f521adc0ef722b6f 100644 (file)
@@ -439,6 +439,9 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
                        goto error;
        }
 
+       /* Initialize tx backoffs to the minimal possible */
+       iwl_mvm_tt_tx_backoff(mvm, 0);
+
        ret = iwl_mvm_power_update_device_mode(mvm);
        if (ret)
                goto error;
index 80052d9c28ef275c78536781df6671bab670f13f..3202a6ee7e96c8057e783bf7a64d892c1974cedb 100644 (file)
@@ -418,6 +418,7 @@ struct iwl_tt_params {
  * @ct_kill_exit: worker to exit thermal kill
  * @dynamic_smps: Is thermal throttling enabled dynamic_smps?
  * @tx_backoff: The current thremal throttling tx backoff in uSec.
+ * @min_backoff: The minimal tx backoff due to power restrictions
  * @params: Parameters to configure the thermal throttling algorithm.
  * @throttle: Is thermal throttling is active?
  */
@@ -425,6 +426,7 @@ struct iwl_mvm_tt_mgmt {
        struct delayed_work ct_kill_exit;
        bool dynamic_smps;
        u32 tx_backoff;
+       u32 min_backoff;
        const struct iwl_tt_params *params;
        bool throttle;
 };
@@ -947,8 +949,9 @@ static inline bool iwl_mvm_vif_low_latency(struct iwl_mvm_vif *mvmvif)
 }
 
 /* Thermal management and CT-kill */
+void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff);
 void iwl_mvm_tt_handler(struct iwl_mvm *mvm);
-void iwl_mvm_tt_initialize(struct iwl_mvm *mvm);
+void iwl_mvm_tt_initialize(struct iwl_mvm *mvm, u32 min_backoff);
 void iwl_mvm_tt_exit(struct iwl_mvm *mvm);
 void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state);
 
index 24afbd60c02e19a96ad56c8dc0da75e11d1db7e9..cf33a128ef05e4030bed79841d235c8a138045f2 100644 (file)
@@ -326,6 +326,23 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
 /* this forward declaration can avoid to export the function */
 static void iwl_mvm_async_handlers_wk(struct work_struct *wk);
 
+static u32 calc_min_backoff(struct iwl_trans *trans, const struct iwl_cfg *cfg)
+{
+       const struct iwl_pwr_tx_backoff *pwr_tx_backoff = cfg->pwr_tx_backoffs;
+
+       if (!pwr_tx_backoff)
+               return 0;
+
+       while (pwr_tx_backoff->pwr) {
+               if (trans->dflt_pwr_limit >= pwr_tx_backoff->pwr)
+                       return pwr_tx_backoff->backoff;
+
+               pwr_tx_backoff++;
+       }
+
+       return 0;
+}
+
 static struct iwl_op_mode *
 iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
                      const struct iwl_fw *fw, struct dentry *dbgfs_dir)
@@ -338,6 +355,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
                TX_CMD,
        };
        int err, scan_size;
+       u32 min_backoff;
 
        /*
         * We use IWL_MVM_STATION_COUNT to check the validity of the station
@@ -433,7 +451,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
        IWL_INFO(mvm, "Detected %s, REV=0x%X\n",
                 mvm->cfg->name, mvm->trans->hw_rev);
 
-       iwl_mvm_tt_initialize(mvm);
+       min_backoff = calc_min_backoff(trans, cfg);
+       iwl_mvm_tt_initialize(mvm, min_backoff);
 
        /*
         * If the NVM exists in an external file,
index 3afa6b6bf83571734eae30e9042c798a0bdb65ed..7a99fa361954e0bc1d5e9e82bf94130b0692ac6f 100644 (file)
@@ -403,7 +403,7 @@ static void iwl_mvm_tt_tx_protection(struct iwl_mvm *mvm, bool enable)
        }
 }
 
-static void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff)
+void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff)
 {
        struct iwl_host_cmd cmd = {
                .id = REPLY_THERMAL_MNG_BACKOFF,
@@ -412,6 +412,8 @@ static void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff)
                .flags = CMD_SYNC,
        };
 
+       backoff = max(backoff, mvm->thermal_throttle.min_backoff);
+
        if (iwl_mvm_send_cmd(mvm, &cmd) == 0) {
                IWL_DEBUG_TEMP(mvm, "Set Thermal Tx backoff to: %u\n",
                               backoff);
@@ -534,7 +536,7 @@ static const struct iwl_tt_params iwl7000_high_temp_tt_params = {
        .support_tx_backoff = true,
 };
 
-void iwl_mvm_tt_initialize(struct iwl_mvm *mvm)
+void iwl_mvm_tt_initialize(struct iwl_mvm *mvm, u32 min_backoff)
 {
        struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle;
 
@@ -546,6 +548,7 @@ void iwl_mvm_tt_initialize(struct iwl_mvm *mvm)
                tt->params = &iwl7000_tt_params;
 
        tt->throttle = false;
+       tt->min_backoff = min_backoff;
        INIT_DELAYED_WORK(&tt->ct_kill_exit, check_exit_ctkill);
 }