if (!iwl_mvm_is_tt_in_fw(mvm)) {
tt->throttle = false;
tt->dynamic_smps = false;
}
/* Don't schedule an exit work if we're in test mode, since * the temperature will not change unless we manually set it * again (or disable testing).
*/ if (!mvm->temperature_test)
schedule_delayed_work(&tt->ct_kill_exit,
round_jiffies_relative(duration * HZ));
}
staticvoid iwl_mvm_exit_ctkill(struct iwl_mvm *mvm)
{ if (!test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) return;
staticvoid iwl_mvm_tt_temp_changed(struct iwl_mvm *mvm, u32 temp)
{ /* ignore the notification if we are in test mode */ if (mvm->temperature_test) return;
staticint iwl_mvm_temp_notif_parse(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt)
{ struct iwl_dts_measurement_notif_v1 *notif_v1; int len = iwl_rx_packet_payload_len(pkt); int temp;
/* we can use notif_v1 only, because v2 only adds an additional * parameter, which is not used in this function.
*/ if (WARN_ON_ONCE(len < sizeof(*notif_v1))) {
IWL_ERR(mvm, "Invalid DTS_MEASUREMENT_NOTIFICATION\n"); return -EINVAL;
}
notif_v1 = (void *)pkt->data;
temp = le32_to_cpu(notif_v1->temp);
/* shouldn't be negative, but since it's s32, make sure it isn't */ if (WARN_ON_ONCE(temp < 0))
temp = 0;
/* * send the DTS_MEASUREMENT_TRIGGER command with or without waiting for a * response. If we get a response then the measurement is stored in 'temp'
*/ staticint iwl_mvm_send_temp_cmd(struct iwl_mvm *mvm, bool response, s32 *temp)
{ struct iwl_host_cmd cmd = {}; struct iwl_dts_measurement_cmd dts_cmd = {
.flags = cpu_to_le32(DTS_TRIGGER_CMD_FLAGS_TEMP),
}; struct iwl_ext_dts_measurement_cmd ext_cmd = {
.control_mode = cpu_to_le32(DTS_DIRECT_WITHOUT_MEASURE),
}; struct iwl_dts_measurement_resp *resp; void *cmd_ptr; int ret;
u32 cmd_flags = 0;
u16 len;
/* Check which command format is used (regular/extended) */ if (fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE)) {
len = sizeof(ext_cmd);
cmd_ptr = &ext_cmd;
} else {
len = sizeof(dts_cmd);
cmd_ptr = &dts_cmd;
} /* The command version where we get a response is zero length */ if (response) {
cmd_flags = CMD_WANT_SKB;
len = 0;
}
/* * If command version is 1 we send the command and immediately get * a response. For older versions we send the command and wait for a * notification (no command TLV for previous versions).
*/
cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw,
WIDE_ID(PHY_OPS_GROUP, CMD_DTS_MEASUREMENT_TRIGGER_WIDE),
IWL_FW_CMD_VER_UNKNOWN); if (cmd_ver == 1) return iwl_mvm_send_temp_cmd(mvm, true, temp);
ret = iwl_mvm_send_temp_cmd(mvm, false, temp); if (ret) {
iwl_remove_notification(&mvm->notif_wait, &wait_temp_notif); return ret;
}
ret = iwl_wait_notification(&mvm->notif_wait, &wait_temp_notif,
IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT); if (ret)
IWL_WARN(mvm, "Getting the temperature timed out\n");
if (params->support_tx_backoff) {
tx_backoff = tt->min_backoff; for (i = 0; i < TT_TX_BACKOFF_SIZE; i++) { if (temperature < params->tx_backoff[i].temperature) break;
tx_backoff = max(tt->min_backoff,
params->tx_backoff[i].backoff);
} if (tx_backoff != tt->min_backoff)
throttle_enable = true; if (tt->tx_backoff != tx_backoff)
iwl_mvm_tt_tx_backoff(mvm, tx_backoff);
}
if (!tt->throttle && throttle_enable) {
IWL_WARN(mvm, "Due to high temperature thermal throttling initiated\n");
tt->throttle = true;
} elseif (tt->throttle && !tt->dynamic_smps &&
tt->tx_backoff == tt->min_backoff &&
temperature <= params->tx_protection_exit) {
IWL_WARN(mvm, "Temperature is back to normal thermal throttling stopped\n");
tt->throttle = false;
}
}
/* Do a linear scale from IWL_MVM_MIN_CTDP_BUDGET_MW to the configured * maximum in the predefined number of steps.
*/
budget = ((mvm->thermal_throttle.power_budget_mw -
IWL_MVM_MIN_CTDP_BUDGET_MW) *
(IWL_MVM_NUM_CTDP_STEPS - 1 - state)) /
(IWL_MVM_NUM_CTDP_STEPS - 1) +
IWL_MVM_MIN_CTDP_BUDGET_MW;
cmd.budget = cpu_to_le32(budget);
status = 0;
ret = iwl_mvm_send_cmd_pdu_status(mvm, WIDE_ID(PHY_OPS_GROUP,
CTDP_CONFIG_CMD), sizeof(cmd), &cmd, &status);
switch (op) { case CTDP_CMD_OPERATION_START: #ifdef CONFIG_THERMAL
mvm->cooling_dev.cur_state = state; #endif/* CONFIG_THERMAL */ break; case CTDP_CMD_OPERATION_REPORT:
IWL_DEBUG_TEMP(mvm, "cTDP avg energy in mWatt = %d\n", status); /* when the function is called with CTDP_CMD_OPERATION_REPORT * option the function should return the average budget value * that is received from the FW. * The budget can't be less or equal to 0, so it's possible * to distinguish between error values and budgets.
*/ return status; case CTDP_CMD_OPERATION_STOP:
IWL_DEBUG_TEMP(mvm, "cTDP stopped successfully\n"); break;
}
cmd.num_temps = cpu_to_le32(twd.count); if (twd.count)
sort(cmd.thresholds, twd.count, sizeof(s16), compare_temps, NULL);
send: #endif
ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(PHY_OPS_GROUP,
TEMP_REPORTING_THRESHOLDS_CMD),
0, sizeof(cmd), &cmd); if (ret)
IWL_ERR(mvm, "TEMP_REPORT_THS_CMD command failed (err=%d)\n",
ret);
return ret;
}
#ifdef CONFIG_THERMAL staticint iwl_mvm_tzone_get_temp(struct thermal_zone_device *device, int *temperature)
{ struct iwl_mvm *mvm = thermal_zone_device_priv(device); int ret; int temp;
guard(mvm)(mvm);
if (!iwl_mvm_firmware_running(mvm) ||
mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR) { /* * Tell the core that there is no valid temperature value to * return, but it need not worry about this.
*/
*temperature = THERMAL_TEMP_INVALID; return 0;
}
ret = iwl_mvm_get_temp(mvm, &temp); if (ret) return ret;
sprintf(name, "iwlwifi_%u", atomic_inc_return(&counter) & 0xFF); /* * 0 is a valid temperature, * so initialize the array with S16_MIN which invalid temperature
*/ for (i = 0 ; i < IWL_MAX_DTS_TRIPS; i++) {
mvm->tz_device.trips[i].temperature = THERMAL_TEMP_INVALID;
mvm->tz_device.trips[i].type = THERMAL_TRIP_PASSIVE;
mvm->tz_device.trips[i].flags = THERMAL_TRIP_FLAG_RW_TEMP;
}
mvm->tz_device.tzone = thermal_zone_device_register_with_trips(name,
mvm->tz_device.trips,
IWL_MAX_DTS_TRIPS,
mvm, &tzone_ops,
NULL, 0, 0); if (IS_ERR(mvm->tz_device.tzone)) {
IWL_DEBUG_TEMP(mvm, "Failed to register to thermal zone (err = %ld)\n",
PTR_ERR(mvm->tz_device.tzone));
mvm->tz_device.tzone = NULL; return;
}
ret = thermal_zone_device_enable(mvm->tz_device.tzone); if (ret) {
IWL_DEBUG_TEMP(mvm, "Failed to enable thermal zone\n");
thermal_zone_device_unregister(mvm->tz_device.tzone);
}
}
/* 32bit in UEFI, 16bit in ACPI; use BIOS value if it is in range */ if (bios_power_budget &&
bios_power_budget != 0xffff && bios_power_budget != 0xffffffff &&
bios_power_budget >= IWL_MVM_MIN_CTDP_BUDGET_MW &&
bios_power_budget <= default_power_budget) return (u32)bios_power_budget;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.