/* * Copyright 2017 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: Rafał Miłecki <zajec5@gmail.com> * Alex Deucher <alexdeucher@gmail.com>
*/
/** * amdgpu_pm_dev_state_check - Check if device can be accessed. * @adev: Target device. * @runpm: Check runpm status for suspend state checks. * * Checks the state of the @adev for access. Return 0 if the device is * accessible or a negative error code otherwise.
*/ staticint amdgpu_pm_dev_state_check(struct amdgpu_device *adev, bool runpm)
{ bool runpm_check = runpm ? adev->in_runpm : false;
if (amdgpu_in_reset(adev)) return -EBUSY;
if (adev->in_suspend && !runpm_check) return -EBUSY;
return 0;
}
/** * amdgpu_pm_get_access - Check if device can be accessed, resume if needed. * @adev: Target device. * * Checks the state of the @adev for access. Use runtime pm API to resume if * needed. Return 0 if the device is accessible or a negative error code * otherwise.
*/ staticint amdgpu_pm_get_access(struct amdgpu_device *adev)
{ int ret;
ret = amdgpu_pm_dev_state_check(adev, true); if (ret) return ret;
return pm_runtime_resume_and_get(adev->dev);
}
/** * amdgpu_pm_get_access_if_active - Check if device is active for access. * @adev: Target device. * * Checks the state of the @adev for access. Use runtime pm API to determine * if device is active. Allow access only if device is active.Return 0 if the * device is accessible or a negative error code otherwise.
*/ staticint amdgpu_pm_get_access_if_active(struct amdgpu_device *adev)
{ int ret;
/* Ignore runpm status. If device is in suspended state, deny access */
ret = amdgpu_pm_dev_state_check(adev, false); if (ret) return ret;
/* * Allow only if device is active. If runpm is disabled also, as in * kernels without CONFIG_PM, allow access.
*/
ret = pm_runtime_get_if_active(adev->dev); if (!ret) return -EPERM;
return 0;
}
/** * amdgpu_pm_put_access - Put to auto suspend mode after a device access. * @adev: Target device. * * Should be paired with amdgpu_pm_get_access* calls
*/ staticinlinevoid amdgpu_pm_put_access(struct amdgpu_device *adev)
{
pm_runtime_mark_last_busy(adev->dev);
pm_runtime_put_autosuspend(adev->dev);
}
/** * DOC: power_dpm_state * * The power_dpm_state file is a legacy interface and is only provided for * backwards compatibility. The amdgpu driver provides a sysfs API for adjusting * certain power related parameters. The file power_dpm_state is used for this. * It accepts the following arguments: * * - battery * * - balanced * * - performance * * battery * * On older GPUs, the vbios provided a special power state for battery * operation. Selecting battery switched to this state. This is no * longer provided on newer GPUs so the option does nothing in that case. * * balanced * * On older GPUs, the vbios provided a special power state for balanced * operation. Selecting balanced switched to this state. This is no * longer provided on newer GPUs so the option does nothing in that case. * * performance * * On older GPUs, the vbios provided a special power state for performance * operation. Selecting performance switched to this state. This is no * longer provided on newer GPUs so the option does nothing in that case. *
*/
if (strncmp("battery", buf, strlen("battery")) == 0)
state = POWER_STATE_TYPE_BATTERY; elseif (strncmp("balanced", buf, strlen("balanced")) == 0)
state = POWER_STATE_TYPE_BALANCED; elseif (strncmp("performance", buf, strlen("performance")) == 0)
state = POWER_STATE_TYPE_PERFORMANCE; else return -EINVAL;
ret = amdgpu_pm_get_access(adev); if (ret < 0) return ret;
amdgpu_dpm_set_power_state(adev, state);
amdgpu_pm_put_access(adev);
return count;
}
/** * DOC: power_dpm_force_performance_level * * The amdgpu driver provides a sysfs API for adjusting certain power * related parameters. The file power_dpm_force_performance_level is * used for this. It accepts the following arguments: * * - auto * * - low * * - high * * - manual * * - profile_standard * * - profile_min_sclk * * - profile_min_mclk * * - profile_peak * * auto * * When auto is selected, the driver will attempt to dynamically select * the optimal power profile for current conditions in the driver. * * low * * When low is selected, the clocks are forced to the lowest power state. * * high * * When high is selected, the clocks are forced to the highest power state. * * manual * * When manual is selected, the user can manually adjust which power states * are enabled for each clock domain via the sysfs pp_dpm_mclk, pp_dpm_sclk, * and pp_dpm_pcie files and adjust the power state transition heuristics * via the pp_power_profile_mode sysfs file. * * profile_standard * profile_min_sclk * profile_min_mclk * profile_peak * * When the profiling modes are selected, clock and power gating are * disabled and the clocks are set for different profiling cases. This * mode is recommended for profiling specific work loads where you do * not want clock or power gating for clock fluctuation to interfere * with your results. profile_standard sets the clocks to a fixed clock * level which varies from asic to asic. profile_min_sclk forces the sclk * to the lowest level. profile_min_mclk forces the mclk to the lowest level. * profile_peak sets all clocks (mclk, sclk, pcie) to the highest levels. *
*/
ret = amdgpu_pm_get_access(adev); if (ret < 0) return ret;
mutex_lock(&adev->pm.stable_pstate_ctx_lock); if (amdgpu_dpm_force_performance_level(adev, level)) {
amdgpu_pm_put_access(adev);
mutex_unlock(&adev->pm.stable_pstate_ctx_lock); return -EINVAL;
} /* override whatever a user ctx may have set */
adev->pm.stable_pstate_ctx = NULL;
mutex_unlock(&adev->pm.stable_pstate_ctx_lock);
ret = amdgpu_pm_get_access(adev); if (ret < 0) return ret;
ret = amdgpu_dpm_get_pp_num_states(adev, &data); if (ret) goto err_out;
state = data.states[idx];
/* only set user selected power states */ if (state != POWER_STATE_TYPE_INTERNAL_BOOT &&
state != POWER_STATE_TYPE_DEFAULT) {
ret = amdgpu_dpm_dispatch_task(adev,
AMD_PP_TASK_ENABLE_USER_STATE, &state); if (ret) goto err_out;
adev->pm.pp_force_state_enabled = true;
}
amdgpu_pm_put_access(adev);
return count;
err_out:
amdgpu_pm_put_access(adev);
return ret;
}
/** * DOC: pp_table * * The amdgpu driver provides a sysfs API for uploading new powerplay * tables. The file pp_table is used for this. Reading the file * will dump the current power play table. Writing to the file * will attempt to upload a new powerplay table and re-initialize * powerplay using that new table. *
*/
ret = amdgpu_pm_get_access(adev); if (ret < 0) return ret;
ret = amdgpu_dpm_set_pp_table(adev, buf, count);
amdgpu_pm_put_access(adev);
if (ret) return ret;
return count;
}
/** * DOC: pp_od_clk_voltage * * The amdgpu driver provides a sysfs API for adjusting the clocks and voltages * in each power level within a power state. The pp_od_clk_voltage is used for * this. * * Note that the actual memory controller clock rate are exposed, not * the effective memory clock of the DRAMs. To translate it, use the * following formula: * * Clock conversion (Mhz): * * HBM: effective_memory_clock = memory_controller_clock * 1 * * G5: effective_memory_clock = memory_controller_clock * 1 * * G6: effective_memory_clock = memory_controller_clock * 2 * * DRAM data rate (MT/s): * * HBM: effective_memory_clock * 2 = data_rate * * G5: effective_memory_clock * 4 = data_rate * * G6: effective_memory_clock * 8 = data_rate * * Bandwidth (MB/s): * * data_rate * vram_bit_width / 8 = memory_bandwidth * * Some examples: * * G5 on RX460: * * memory_controller_clock = 1750 Mhz * * effective_memory_clock = 1750 Mhz * 1 = 1750 Mhz * * data rate = 1750 * 4 = 7000 MT/s * * memory_bandwidth = 7000 * 128 bits / 8 = 112000 MB/s * * G6 on RX5700: * * memory_controller_clock = 875 Mhz * * effective_memory_clock = 875 Mhz * 2 = 1750 Mhz * * data rate = 1750 * 8 = 14000 MT/s * * memory_bandwidth = 14000 * 256 bits / 8 = 448000 MB/s * * < For Vega10 and previous ASICs > * * Reading the file will display: * * - a list of engine clock levels and voltages labeled OD_SCLK * * - a list of memory clock levels and voltages labeled OD_MCLK * * - a list of valid ranges for sclk, mclk, and voltage labeled OD_RANGE * * To manually adjust these settings, first select manual using * power_dpm_force_performance_level. Enter a new value for each * level by writing a string that contains "s/m level clock voltage" to * the file. E.g., "s 1 500 820" will update sclk level 1 to be 500 MHz * at 820 mV; "m 0 350 810" will update mclk level 0 to be 350 MHz at * 810 mV. When you have edited all of the states as needed, write * "c" (commit) to the file to commit your changes. If you want to reset to the * default power levels, write "r" (reset) to the file to reset them. * * * < For Vega20 and newer ASICs > * * Reading the file will display: * * - minimum and maximum engine clock labeled OD_SCLK * * - minimum(not available for Vega20 and Navi1x) and maximum memory * clock labeled OD_MCLK * * - three <frequency, voltage> points labeled OD_VDDC_CURVE. * They can be used to calibrate the sclk voltage curve. This is * available for Vega20 and NV1X. * * - voltage offset(in mV) applied on target voltage calculation. * This is available for Sienna Cichlid, Navy Flounder, Dimgrey * Cavefish and some later SMU13 ASICs. For these ASICs, the target * voltage calculation can be illustrated by "voltage = voltage * calculated from v/f curve + overdrive vddgfx offset" * * - a list of valid ranges for sclk, mclk, voltage curve points * or voltage offset labeled OD_RANGE * * < For APUs > * * Reading the file will display: * * - minimum and maximum engine clock labeled OD_SCLK * * - a list of valid ranges for sclk labeled OD_RANGE * * < For VanGogh > * * Reading the file will display: * * - minimum and maximum engine clock labeled OD_SCLK * - minimum and maximum core clocks labeled OD_CCLK * * - a list of valid ranges for sclk and cclk labeled OD_RANGE * * To manually adjust these settings: * * - First select manual using power_dpm_force_performance_level * * - For clock frequency setting, enter a new value by writing a * string that contains "s/m index clock" to the file. The index * should be 0 if to set minimum clock. And 1 if to set maximum * clock. E.g., "s 0 500" will update minimum sclk to be 500 MHz. * "m 1 800" will update maximum mclk to be 800Mhz. For core * clocks on VanGogh, the string contains "p core index clock". * E.g., "p 2 0 800" would set the minimum core clock on core * 2 to 800Mhz. * * For sclk voltage curve supported by Vega20 and NV1X, enter the new * values by writing a string that contains "vc point clock voltage" * to the file. The points are indexed by 0, 1 and 2. E.g., "vc 0 300 * 600" will update point1 with clock set as 300Mhz and voltage as 600mV. * "vc 2 1000 1000" will update point3 with clock set as 1000Mhz and * voltage 1000mV. * * For voltage offset supported by Sienna Cichlid, Navy Flounder, Dimgrey * Cavefish and some later SMU13 ASICs, enter the new value by writing a * string that contains "vo offset". E.g., "vo -10" will update the extra * voltage offset applied to the whole v/f curve line as -10mv. * * - When you have edited all of the states as needed, write "c" (commit) * to the file to commit your changes * * - If you want to reset to the default power levels, write "r" (reset) * to the file to reset them *
*/
/** * DOC: pp_features * * The amdgpu driver provides a sysfs API for adjusting what powerplay * features to be enabled. The file pp_features is used for this. And * this is only available for Vega10 and later dGPUs. * * Reading back the file will show you the followings: * - Current ppfeature masks * - List of the all supported powerplay features with their naming, * bitmasks and enablement status('Y'/'N' means "enabled"/"disabled"). * * To manually enable or disable a specific feature, just set or clear * the corresponding bit from original ppfeature masks and input the * new ppfeature masks.
*/ static ssize_t amdgpu_set_pp_features(struct device *dev, struct device_attribute *attr, constchar *buf,
size_t count)
{ struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev);
uint64_t featuremask; int ret;
ret = kstrtou64(buf, 0, &featuremask); if (ret) return -EINVAL;
ret = amdgpu_pm_get_access(adev); if (ret < 0) return ret;
ret = amdgpu_dpm_set_ppfeature_status(adev, featuremask);
/** * DOC: pp_dpm_sclk pp_dpm_mclk pp_dpm_socclk pp_dpm_fclk pp_dpm_dcefclk pp_dpm_pcie * * The amdgpu driver provides a sysfs API for adjusting what power levels * are enabled for a given power state. The files pp_dpm_sclk, pp_dpm_mclk, * pp_dpm_socclk, pp_dpm_fclk, pp_dpm_dcefclk and pp_dpm_pcie are used for * this. * * pp_dpm_socclk and pp_dpm_dcefclk interfaces are only available for * Vega10 and later ASICs. * pp_dpm_fclk interface is only available for Vega20 and later ASICs. * * Reading back the files will show you the available power levels within * the power state and the clock information for those levels. If deep sleep is * applied to a clock, the level will be denoted by a special level 'S:' * E.g., :: * * S: 19Mhz * * 0: 615Mhz * 1: 800Mhz * 2: 888Mhz * 3: 1000Mhz * * * To manually adjust these states, first select manual using * power_dpm_force_performance_level. * Secondly, enter a new value for each level by inputing a string that * contains " echo xx xx xx > pp_dpm_sclk/mclk/pcie" * E.g., * * .. code-block:: bash * * echo "4 5 6" > pp_dpm_sclk * * will enable sclk levels 4, 5, and 6. * * NOTE: change to the dcefclk max dpm level is not supported now
*/
static ssize_t amdgpu_get_pp_dpm_clock(struct device *dev, enum pp_clock_type type, char *buf)
{ struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev); int size = 0; int ret = 0;
ret = amdgpu_pm_get_access_if_active(adev); if (ret) return ret;
ret = amdgpu_dpm_emit_clock_levels(adev, type, buf, &size); if (ret == -ENOENT)
size = amdgpu_dpm_print_clock_levels(adev, type, buf);
if (size == 0)
size = sysfs_emit(buf, "\n");
amdgpu_pm_put_access(adev);
return size;
}
/* * Worst case: 32 bits individually specified, in octal at 12 characters * per line (+1 for \n).
*/ #define AMDGPU_MASK_BUF_MAX (32 * 13)
ret = amdgpu_pm_get_access(adev); if (ret < 0) return ret;
amdgpu_dpm_set_mclk_od(adev, (uint32_t)value);
amdgpu_pm_put_access(adev);
return count;
}
/** * DOC: pp_power_profile_mode * * The amdgpu driver provides a sysfs API for adjusting the heuristics * related to switching between power levels in a power state. The file * pp_power_profile_mode is used for this. * * Reading this file outputs a list of all of the predefined power profiles * and the relevant heuristics settings for that profile. * * To select a profile or create a custom profile, first select manual using * power_dpm_force_performance_level. Writing the number of a predefined * profile to pp_power_profile_mode will enable those heuristics. To * create a custom set of heuristics, write a string of numbers to the file * starting with the number of the custom profile along with a setting * for each heuristic parameter. Due to differences across asic families * the heuristic parameters vary from family to family. Additionally, * you can apply the custom heuristics to different clock domains. Each * clock domain is considered a distinct operation so if you modify the * gfxclk heuristics and then the memclk heuristics, the all of the * custom heuristics will be retained until you switch to another profile. *
*/
r = amdgpu_pm_get_access_if_active(adev); if (r) return r;
/* get the sensor value */
r = amdgpu_dpm_read_sensor(adev, sensor, query, &size);
amdgpu_pm_put_access(adev);
return r;
}
/** * DOC: gpu_busy_percent * * The amdgpu driver provides a sysfs API for reading how busy the GPU * is as a percentage. The file gpu_busy_percent is used for this. * The SMU firmware computes a percentage of load based on the * aggregate activity level in the IP cores.
*/ static ssize_t amdgpu_get_gpu_busy_percent(struct device *dev, struct device_attribute *attr, char *buf)
{ struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev); unsignedint value; int r;
r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_GPU_LOAD, &value); if (r) return r;
return sysfs_emit(buf, "%d\n", value);
}
/** * DOC: mem_busy_percent * * The amdgpu driver provides a sysfs API for reading how busy the VRAM * is as a percentage. The file mem_busy_percent is used for this. * The SMU firmware computes a percentage of load based on the * aggregate activity level in the IP cores.
*/ static ssize_t amdgpu_get_mem_busy_percent(struct device *dev, struct device_attribute *attr, char *buf)
{ struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev); unsignedint value; int r;
r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_MEM_LOAD, &value); if (r) return r;
return sysfs_emit(buf, "%d\n", value);
}
/** * DOC: vcn_busy_percent * * The amdgpu driver provides a sysfs API for reading how busy the VCN * is as a percentage. The file vcn_busy_percent is used for this. * The SMU firmware computes a percentage of load based on the * aggregate activity level in the IP cores.
*/ static ssize_t amdgpu_get_vcn_busy_percent(struct device *dev, struct device_attribute *attr, char *buf)
{ struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev); unsignedint value; int r;
r = amdgpu_hwmon_get_sensor_generic(adev, AMDGPU_PP_SENSOR_VCN_LOAD, &value); if (r) return r;
return sysfs_emit(buf, "%d\n", value);
}
/** * DOC: pcie_bw * * The amdgpu driver provides a sysfs API for estimating how much data * has been received and sent by the GPU in the last second through PCIe. * The file pcie_bw is used for this. * The Perf counters count the number of received and sent messages and return * those values, as well as the maximum payload size of a PCIe packet (mps). * Note that it is not possible to easily and quickly obtain the size of each * packet transmitted, so we output the max payload size (mps) to allow for * quick estimation of the PCIe bandwidth usage
*/ static ssize_t amdgpu_get_pcie_bw(struct device *dev, struct device_attribute *attr, char *buf)
{ struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev);
uint64_t count0 = 0, count1 = 0; int ret;
if (adev->flags & AMD_IS_APU) return -ENODATA;
if (!adev->asic_funcs->get_pcie_usage) return -ENODATA;
ret = amdgpu_pm_get_access_if_active(adev); if (ret) return ret;
/** * DOC: unique_id * * The amdgpu driver provides a sysfs API for providing a unique ID for the GPU * The file unique_id is used for this. * This will provide a Unique ID that will persist from machine to machine * * NOTE: This will only work for GFX9 and newer. This file will be absent * on unsupported ASICs (GFX8 and older)
*/ static ssize_t amdgpu_get_unique_id(struct device *dev, struct device_attribute *attr, char *buf)
{ struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev);
if (adev->unique_id) return sysfs_emit(buf, "%016llx\n", adev->unique_id);
return 0;
}
/** * DOC: thermal_throttling_logging * * Thermal throttling pulls down the clock frequency and thus the performance. * It's an useful mechanism to protect the chip from overheating. Since it * impacts performance, the user controls whether it is enabled and if so, * the log frequency. * * Reading back the file shows you the status(enabled or disabled) and * the interval(in seconds) between each thermal logging. * * Writing an integer to the file, sets a new logging interval, in seconds. * The value should be between 1 and 3600. If the value is less than 1, * thermal logging is disabled. Values greater than 3600 are ignored.
*/ static ssize_t amdgpu_get_thermal_throttling_logging(struct device *dev, struct device_attribute *attr, char *buf)
{ struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev);
static ssize_t amdgpu_set_thermal_throttling_logging(struct device *dev, struct device_attribute *attr, constchar *buf,
size_t count)
{ struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev); long throttling_logging_interval; int ret = 0;
ret = kstrtol(buf, 0, &throttling_logging_interval); if (ret) return ret;
if (throttling_logging_interval > 3600) return -EINVAL;
if (throttling_logging_interval > 0) { /* * Reset the ratelimit timer internals. * This can effectively restart the timer.
*/
ratelimit_state_reset_interval(&adev->throttling_logging_rs,
(throttling_logging_interval - 1) * HZ);
atomic_set(&adev->throttling_logging_enabled, 1);
} else {
atomic_set(&adev->throttling_logging_enabled, 0);
}
return count;
}
/** * DOC: apu_thermal_cap * * The amdgpu driver provides a sysfs API for retrieving/updating thermal * limit temperature in millidegrees Celsius * * Reading back the file shows you core limit value * * Writing an integer to the file, sets a new thermal limit. The value * should be between 0 and 100. If the value is less than 0 or greater * than 100, then the write request will be ignored.
*/ static ssize_t amdgpu_get_apu_thermal_cap(struct device *dev, struct device_attribute *attr, char *buf)
{ int ret, size;
u32 limit; struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev);
ret = amdgpu_pm_get_access_if_active(adev); if (ret) return ret;
ret = amdgpu_dpm_get_apu_thermal_limit(adev, &limit); if (!ret)
size = sysfs_emit(buf, "%u\n", limit); else
size = sysfs_emit(buf, "failed to get thermal limit\n");
/** * DOC: gpu_metrics * * The amdgpu driver provides a sysfs API for retrieving current gpu * metrics data. The file gpu_metrics is used for this. Reading the * file will dump all the current gpu metrics data. * * These data include temperature, frequency, engines utilization, * power consume, throttler status, fan speed and cpu core statistics( * available for APU only). That's it will give a snapshot of all sensors * at the same time.
*/ static ssize_t amdgpu_get_gpu_metrics(struct device *dev, struct device_attribute *attr, char *buf)
{ struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev); void *gpu_metrics;
ssize_t size = 0; int ret;
ret = amdgpu_pm_get_access_if_active(adev); if (ret) return ret;
size = amdgpu_dpm_get_gpu_metrics(adev, &gpu_metrics); if (size <= 0) goto out;
r = amdgpu_hwmon_get_sensor_generic(adev, sensor, (void *)&ss_power); if (r == -EOPNOTSUPP) { /* sensor not available on dGPU, try to read from APU */
adev = NULL;
mutex_lock(&mgpu_info.mutex); for (i = 0; i < mgpu_info.num_gpu; i++) { if (mgpu_info.gpu_ins[i].adev->flags & AMD_IS_APU) {
adev = mgpu_info.gpu_ins[i].adev; break;
}
}
mutex_unlock(&mgpu_info.mutex); if (adev)
r = amdgpu_hwmon_get_sensor_generic(adev, sensor, (void *)&ss_power);
}
if (r) return r;
return sysfs_emit(buf, "%u%%\n", ss_power);
}
/** * DOC: smartshift_apu_power * * The amdgpu driver provides a sysfs API for reporting APU power * shift in percentage if platform supports smartshift. Value 0 means that * there is no powershift and values between [1-100] means that the power * is shifted to APU, the percentage of boost is with respect to APU power * limit on the platform.
*/
/** * DOC: smartshift_dgpu_power * * The amdgpu driver provides a sysfs API for reporting dGPU power * shift in percentage if platform supports smartshift. Value 0 means that * there is no powershift and values between [1-100] means that the power is * shifted to dGPU, the percentage of boost is with respect to dGPU power * limit on the platform.
*/
/** * DOC: smartshift_bias * * The amdgpu driver provides a sysfs API for reporting the * smartshift(SS2.0) bias level. The value ranges from -100 to 100 * and the default is 0. -100 sets maximum preference to APU * and 100 sets max perference to dGPU.
*/
static ssize_t amdgpu_get_smartshift_bias(struct device *dev, struct device_attribute *attr, char *buf)
{ int r = 0;
r = sysfs_emit(buf, "%d\n", amdgpu_smartshift_bias);
gc_ver = amdgpu_ip_version(adev, GC_HWIP, 0); /* dcefclk node is not available on gfx 11.0.3 sriov */ if ((gc_ver == IP_VERSION(11, 0, 3) && amdgpu_sriov_is_pp_one_vf(adev)) ||
gc_ver < IP_VERSION(9, 0, 0) ||
!amdgpu_device_has_display_hardware(adev))
*states = ATTR_STATE_UNSUPPORTED;
/* SMU MP1 does not support dcefclk level setting, * setting should not be allowed from VF if not in one VF mode.
*/ if (gc_ver >= IP_VERSION(10, 0, 0) ||
(amdgpu_sriov_multi_vf_mode(adev))) {
dev_attr->attr.mode &= ~S_IWUGO;
dev_attr->store = NULL;
}
switch (gc_ver) { case IP_VERSION(9, 4, 1): case IP_VERSION(9, 4, 2): /* the Mi series card does not support standalone mclk/socclk/fclk level setting */ if (DEVICE_ATTR_IS(pp_dpm_mclk) ||
DEVICE_ATTR_IS(pp_dpm_socclk) ||
DEVICE_ATTR_IS(pp_dpm_fclk)) {
dev_attr->attr.mode &= ~S_IWUGO;
dev_attr->store = NULL;
} break; default: break;
}
/* setting should not be allowed from VF if not in one VF mode */ if (amdgpu_sriov_vf(adev) && amdgpu_sriov_is_pp_one_vf(adev)) {
dev_attr->attr.mode &= ~S_IWUGO;
dev_attr->store = NULL;
}
/** * DOC: pm_policy * * Certain SOCs can support different power policies to optimize application * performance. However, this policy is provided only at SOC level and not at a * per-process level. This is useful especially when entire SOC is utilized for * dedicated workload. * * The amdgpu driver provides a sysfs API for selecting the policy. Presently, * only two types of policies are supported through this interface. * * Pstate Policy Selection - This is to select different Pstate profiles which * decides clock/throttling preferences. * * XGMI PLPD Policy Selection - When multiple devices are connected over XGMI, * this helps to select policy to be applied for per link power down. * * The list of available policies and policy levels vary between SOCs. They can * be viewed under pm_policy node directory. If SOC doesn't support any policy, * this node won't be available. The different policies supported will be * available as separate nodes under pm_policy. * * cat /sys/bus/pci/devices/.../pm_policy/<policy_type> * * Reading the policy file shows the different levels supported. The level which * is applied presently is denoted by * (asterisk). E.g., * * .. code-block:: console * * cat /sys/bus/pci/devices/.../pm_policy/soc_pstate * 0 : soc_pstate_default * 1 : soc_pstate_0 * 2 : soc_pstate_1* * 3 : soc_pstate_2 * * cat /sys/bus/pci/devices/.../pm_policy/xgmi_plpd * 0 : plpd_disallow * 1 : plpd_default * 2 : plpd_optimized* * * To apply a specific policy * * "echo <level> > /sys/bus/pci/devices/.../pm_policy/<policy_type>" * * For the levels listed in the example above, to select "plpd_optimized" for * XGMI and "soc_pstate_2" for soc pstate policy - * * .. code-block:: console * * echo "2" > /sys/bus/pci/devices/.../pm_policy/xgmi_plpd * echo "3" > /sys/bus/pci/devices/.../pm_policy/soc_pstate *
*/ static ssize_t amdgpu_get_pm_policy_attr(struct device *dev, struct device_attribute *attr, char *buf)
{ struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev); struct amdgpu_pm_policy_attr *policy_attr;
¤ 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.0.19Bemerkung:
¤
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.