diff options
author | Evan Quan <evan.quan@amd.com> | 2019-01-14 01:06:54 -0500 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2019-01-25 16:15:34 -0500 |
commit | 7ca881a8651bdeffd99ba8e0010160f9bf60673e (patch) | |
tree | 2eae8b802c105eac32ca7d4027eb7dd7d52115b1 /drivers/gpu | |
parent | b61857b5e365889d67a6296c413df396032d374d (diff) |
drm/amd/powerplay: support enabled ppfeatures retrieving and setting V3
User can use "ppfeatures" sysfs interface to retrieve and set enabled
powerplay features.
V2: expose this feature for Vega10 and later dGPUs
V3: squash in removal of unused variable (Alex)
Signed-off-by: Evan Quan <evan.quan@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 71 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/include/kgd_pp_interface.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/powerplay/amd_powerplay.c | 42 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c | 104 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/powerplay/inc/hwmgr.h | 2 |
6 files changed, 229 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h index f972cd156795..2f61e9edb1c1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h | |||
@@ -364,6 +364,14 @@ enum amdgpu_pcie_gen { | |||
364 | ((adev)->powerplay.pp_funcs->enable_mgpu_fan_boost(\ | 364 | ((adev)->powerplay.pp_funcs->enable_mgpu_fan_boost(\ |
365 | (adev)->powerplay.pp_handle)) | 365 | (adev)->powerplay.pp_handle)) |
366 | 366 | ||
367 | #define amdgpu_dpm_get_ppfeature_status(adev, buf) \ | ||
368 | ((adev)->powerplay.pp_funcs->get_ppfeature_status(\ | ||
369 | (adev)->powerplay.pp_handle, (buf))) | ||
370 | |||
371 | #define amdgpu_dpm_set_ppfeature_status(adev, ppfeatures) \ | ||
372 | ((adev)->powerplay.pp_funcs->set_ppfeature_status(\ | ||
373 | (adev)->powerplay.pp_handle, (ppfeatures))) | ||
374 | |||
367 | struct amdgpu_dpm { | 375 | struct amdgpu_dpm { |
368 | struct amdgpu_ps *ps; | 376 | struct amdgpu_ps *ps; |
369 | /* number of valid power states */ | 377 | /* number of valid power states */ |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c index 51eb2cf42b81..f21f294e6735 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | |||
@@ -626,6 +626,60 @@ static ssize_t amdgpu_get_pp_od_clk_voltage(struct device *dev, | |||
626 | } | 626 | } |
627 | 627 | ||
628 | /** | 628 | /** |
629 | * DOC: ppfeatures | ||
630 | * | ||
631 | * The amdgpu driver provides a sysfs API for adjusting what powerplay | ||
632 | * features to be enabled. The file ppfeatures is used for this. And | ||
633 | * this is only available for Vega10 and later dGPUs. | ||
634 | * | ||
635 | * Reading back the file will show you the followings: | ||
636 | * - Current ppfeature masks | ||
637 | * - List of the all supported powerplay features with their naming, | ||
638 | * bitmasks and enablement status('Y'/'N' means "enabled"/"disabled"). | ||
639 | * | ||
640 | * To manually enable or disable a specific feature, just set or clear | ||
641 | * the corresponding bit from original ppfeature masks and input the | ||
642 | * new ppfeature masks. | ||
643 | */ | ||
644 | static ssize_t amdgpu_set_ppfeature_status(struct device *dev, | ||
645 | struct device_attribute *attr, | ||
646 | const char *buf, | ||
647 | size_t count) | ||
648 | { | ||
649 | struct drm_device *ddev = dev_get_drvdata(dev); | ||
650 | struct amdgpu_device *adev = ddev->dev_private; | ||
651 | uint64_t featuremask; | ||
652 | int ret; | ||
653 | |||
654 | ret = kstrtou64(buf, 0, &featuremask); | ||
655 | if (ret) | ||
656 | return -EINVAL; | ||
657 | |||
658 | pr_debug("featuremask = 0x%llx\n", featuremask); | ||
659 | |||
660 | if (adev->powerplay.pp_funcs->set_ppfeature_status) { | ||
661 | ret = amdgpu_dpm_set_ppfeature_status(adev, featuremask); | ||
662 | if (ret) | ||
663 | return -EINVAL; | ||
664 | } | ||
665 | |||
666 | return count; | ||
667 | } | ||
668 | |||
669 | static ssize_t amdgpu_get_ppfeature_status(struct device *dev, | ||
670 | struct device_attribute *attr, | ||
671 | char *buf) | ||
672 | { | ||
673 | struct drm_device *ddev = dev_get_drvdata(dev); | ||
674 | struct amdgpu_device *adev = ddev->dev_private; | ||
675 | |||
676 | if (adev->powerplay.pp_funcs->get_ppfeature_status) | ||
677 | return amdgpu_dpm_get_ppfeature_status(adev, buf); | ||
678 | |||
679 | return snprintf(buf, PAGE_SIZE, "\n"); | ||
680 | } | ||
681 | |||
682 | /** | ||
629 | * DOC: pp_dpm_sclk pp_dpm_mclk pp_dpm_pcie | 683 | * DOC: pp_dpm_sclk pp_dpm_mclk pp_dpm_pcie |
630 | * | 684 | * |
631 | * The amdgpu driver provides a sysfs API for adjusting what power levels | 685 | * The amdgpu driver provides a sysfs API for adjusting what power levels |
@@ -1051,6 +1105,9 @@ static DEVICE_ATTR(pp_od_clk_voltage, S_IRUGO | S_IWUSR, | |||
1051 | static DEVICE_ATTR(gpu_busy_percent, S_IRUGO, | 1105 | static DEVICE_ATTR(gpu_busy_percent, S_IRUGO, |
1052 | amdgpu_get_busy_percent, NULL); | 1106 | amdgpu_get_busy_percent, NULL); |
1053 | static DEVICE_ATTR(pcie_bw, S_IRUGO, amdgpu_get_pcie_bw, NULL); | 1107 | static DEVICE_ATTR(pcie_bw, S_IRUGO, amdgpu_get_pcie_bw, NULL); |
1108 | static DEVICE_ATTR(ppfeatures, S_IRUGO | S_IWUSR, | ||
1109 | amdgpu_get_ppfeature_status, | ||
1110 | amdgpu_set_ppfeature_status); | ||
1054 | 1111 | ||
1055 | static ssize_t amdgpu_hwmon_show_temp(struct device *dev, | 1112 | static ssize_t amdgpu_hwmon_show_temp(struct device *dev, |
1056 | struct device_attribute *attr, | 1113 | struct device_attribute *attr, |
@@ -2241,6 +2298,17 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev) | |||
2241 | return ret; | 2298 | return ret; |
2242 | } | 2299 | } |
2243 | 2300 | ||
2301 | if ((adev->asic_type >= CHIP_VEGA10) && | ||
2302 | !(adev->flags & AMD_IS_APU)) { | ||
2303 | ret = device_create_file(adev->dev, | ||
2304 | &dev_attr_ppfeatures); | ||
2305 | if (ret) { | ||
2306 | DRM_ERROR("failed to create device file " | ||
2307 | "ppfeatures\n"); | ||
2308 | return ret; | ||
2309 | } | ||
2310 | } | ||
2311 | |||
2244 | adev->pm.sysfs_initialized = true; | 2312 | adev->pm.sysfs_initialized = true; |
2245 | 2313 | ||
2246 | return 0; | 2314 | return 0; |
@@ -2276,6 +2344,9 @@ void amdgpu_pm_sysfs_fini(struct amdgpu_device *adev) | |||
2276 | device_remove_file(adev->dev, &dev_attr_gpu_busy_percent); | 2344 | device_remove_file(adev->dev, &dev_attr_gpu_busy_percent); |
2277 | if (adev->flags & !AMD_IS_APU) | 2345 | if (adev->flags & !AMD_IS_APU) |
2278 | device_remove_file(adev->dev, &dev_attr_pcie_bw); | 2346 | device_remove_file(adev->dev, &dev_attr_pcie_bw); |
2347 | if ((adev->asic_type >= CHIP_VEGA10) && | ||
2348 | !(adev->flags & AMD_IS_APU)) | ||
2349 | device_remove_file(adev->dev, &dev_attr_ppfeatures); | ||
2279 | } | 2350 | } |
2280 | 2351 | ||
2281 | void amdgpu_pm_compute_clocks(struct amdgpu_device *adev) | 2352 | void amdgpu_pm_compute_clocks(struct amdgpu_device *adev) |
diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index a2ea4c933360..1130f293c4ee 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h | |||
@@ -284,6 +284,8 @@ struct amd_pm_funcs { | |||
284 | int (*get_asic_baco_capability)(void *handle, bool *cap); | 284 | int (*get_asic_baco_capability)(void *handle, bool *cap); |
285 | int (*get_asic_baco_state)(void *handle, int *state); | 285 | int (*get_asic_baco_state)(void *handle, int *state); |
286 | int (*set_asic_baco_state)(void *handle, int state); | 286 | int (*set_asic_baco_state)(void *handle, int state); |
287 | int (*get_ppfeature_status)(void *handle, char *buf); | ||
288 | int (*set_ppfeature_status)(void *handle, uint64_t ppfeature_masks); | ||
287 | }; | 289 | }; |
288 | 290 | ||
289 | #endif | 291 | #endif |
diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c index 5d8b5d3c2453..3f73f7cd18b9 100644 --- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c | |||
@@ -1455,6 +1455,46 @@ static int pp_set_asic_baco_state(void *handle, int state) | |||
1455 | return 0; | 1455 | return 0; |
1456 | } | 1456 | } |
1457 | 1457 | ||
1458 | static int pp_get_ppfeature_status(void *handle, char *buf) | ||
1459 | { | ||
1460 | struct pp_hwmgr *hwmgr = handle; | ||
1461 | int ret = 0; | ||
1462 | |||
1463 | if (!hwmgr || !hwmgr->pm_en || !buf) | ||
1464 | return -EINVAL; | ||
1465 | |||
1466 | if (hwmgr->hwmgr_func->get_ppfeature_status == NULL) { | ||
1467 | pr_info_ratelimited("%s was not implemented.\n", __func__); | ||
1468 | return -EINVAL; | ||
1469 | } | ||
1470 | |||
1471 | mutex_lock(&hwmgr->smu_lock); | ||
1472 | ret = hwmgr->hwmgr_func->get_ppfeature_status(hwmgr, buf); | ||
1473 | mutex_unlock(&hwmgr->smu_lock); | ||
1474 | |||
1475 | return ret; | ||
1476 | } | ||
1477 | |||
1478 | static int pp_set_ppfeature_status(void *handle, uint64_t ppfeature_masks) | ||
1479 | { | ||
1480 | struct pp_hwmgr *hwmgr = handle; | ||
1481 | int ret = 0; | ||
1482 | |||
1483 | if (!hwmgr || !hwmgr->pm_en) | ||
1484 | return -EINVAL; | ||
1485 | |||
1486 | if (hwmgr->hwmgr_func->set_ppfeature_status == NULL) { | ||
1487 | pr_info_ratelimited("%s was not implemented.\n", __func__); | ||
1488 | return -EINVAL; | ||
1489 | } | ||
1490 | |||
1491 | mutex_lock(&hwmgr->smu_lock); | ||
1492 | ret = hwmgr->hwmgr_func->set_ppfeature_status(hwmgr, ppfeature_masks); | ||
1493 | mutex_unlock(&hwmgr->smu_lock); | ||
1494 | |||
1495 | return ret; | ||
1496 | } | ||
1497 | |||
1458 | static const struct amd_pm_funcs pp_dpm_funcs = { | 1498 | static const struct amd_pm_funcs pp_dpm_funcs = { |
1459 | .load_firmware = pp_dpm_load_fw, | 1499 | .load_firmware = pp_dpm_load_fw, |
1460 | .wait_for_fw_loading_complete = pp_dpm_fw_loading_complete, | 1500 | .wait_for_fw_loading_complete = pp_dpm_fw_loading_complete, |
@@ -1508,4 +1548,6 @@ static const struct amd_pm_funcs pp_dpm_funcs = { | |||
1508 | .get_asic_baco_capability = pp_get_asic_baco_capability, | 1548 | .get_asic_baco_capability = pp_get_asic_baco_capability, |
1509 | .get_asic_baco_state = pp_get_asic_baco_state, | 1549 | .get_asic_baco_state = pp_get_asic_baco_state, |
1510 | .set_asic_baco_state = pp_set_asic_baco_state, | 1550 | .set_asic_baco_state = pp_set_asic_baco_state, |
1551 | .get_ppfeature_status = pp_get_ppfeature_status, | ||
1552 | .set_ppfeature_status = pp_set_ppfeature_status, | ||
1511 | }; | 1553 | }; |
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c index 2ba387b0f27c..3e97b9d6f450 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c | |||
@@ -2776,6 +2776,108 @@ static int vega20_odn_edit_dpm_table(struct pp_hwmgr *hwmgr, | |||
2776 | return 0; | 2776 | return 0; |
2777 | } | 2777 | } |
2778 | 2778 | ||
2779 | static int vega20_get_ppfeature_status(struct pp_hwmgr *hwmgr, char *buf) | ||
2780 | { | ||
2781 | static const char *ppfeature_name[] = { | ||
2782 | "DPM_PREFETCHER", | ||
2783 | "GFXCLK_DPM", | ||
2784 | "UCLK_DPM", | ||
2785 | "SOCCLK_DPM", | ||
2786 | "UVD_DPM", | ||
2787 | "VCE_DPM", | ||
2788 | "ULV", | ||
2789 | "MP0CLK_DPM", | ||
2790 | "LINK_DPM", | ||
2791 | "DCEFCLK_DPM", | ||
2792 | "GFXCLK_DS", | ||
2793 | "SOCCLK_DS", | ||
2794 | "LCLK_DS", | ||
2795 | "PPT", | ||
2796 | "TDC", | ||
2797 | "THERMAL", | ||
2798 | "GFX_PER_CU_CG", | ||
2799 | "RM", | ||
2800 | "DCEFCLK_DS", | ||
2801 | "ACDC", | ||
2802 | "VR0HOT", | ||
2803 | "VR1HOT", | ||
2804 | "FW_CTF", | ||
2805 | "LED_DISPLAY", | ||
2806 | "FAN_CONTROL", | ||
2807 | "GFX_EDC", | ||
2808 | "GFXOFF", | ||
2809 | "CG", | ||
2810 | "FCLK_DPM", | ||
2811 | "FCLK_DS", | ||
2812 | "MP1CLK_DS", | ||
2813 | "MP0CLK_DS", | ||
2814 | "XGMI"}; | ||
2815 | static const char *output_title[] = { | ||
2816 | "FEATURES", | ||
2817 | "BITMASK", | ||
2818 | "ENABLEMENT"}; | ||
2819 | uint64_t features_enabled; | ||
2820 | int i; | ||
2821 | int ret = 0; | ||
2822 | int size = 0; | ||
2823 | |||
2824 | ret = vega20_get_enabled_smc_features(hwmgr, &features_enabled); | ||
2825 | PP_ASSERT_WITH_CODE(!ret, | ||
2826 | "[EnableAllSmuFeatures] Failed to get enabled smc features!", | ||
2827 | return ret); | ||
2828 | |||
2829 | size += sprintf(buf + size, "Current ppfeatures: 0x%016llx\n", features_enabled); | ||
2830 | size += sprintf(buf + size, "%-19s %-22s %s\n", | ||
2831 | output_title[0], | ||
2832 | output_title[1], | ||
2833 | output_title[2]); | ||
2834 | for (i = 0; i < GNLD_FEATURES_MAX; i++) { | ||
2835 | size += sprintf(buf + size, "%-19s 0x%016llx %6s\n", | ||
2836 | ppfeature_name[i], | ||
2837 | 1ULL << i, | ||
2838 | (features_enabled & (1ULL << i)) ? "Y" : "N"); | ||
2839 | } | ||
2840 | |||
2841 | return size; | ||
2842 | } | ||
2843 | |||
2844 | static int vega20_set_ppfeature_status(struct pp_hwmgr *hwmgr, uint64_t new_ppfeature_masks) | ||
2845 | { | ||
2846 | uint64_t features_enabled; | ||
2847 | uint64_t features_to_enable; | ||
2848 | uint64_t features_to_disable; | ||
2849 | int ret = 0; | ||
2850 | |||
2851 | if (new_ppfeature_masks >= (1ULL << GNLD_FEATURES_MAX)) | ||
2852 | return -EINVAL; | ||
2853 | |||
2854 | ret = vega20_get_enabled_smc_features(hwmgr, &features_enabled); | ||
2855 | if (ret) | ||
2856 | return ret; | ||
2857 | |||
2858 | features_to_disable = | ||
2859 | (features_enabled ^ new_ppfeature_masks) & features_enabled; | ||
2860 | features_to_enable = | ||
2861 | (features_enabled ^ new_ppfeature_masks) ^ features_to_disable; | ||
2862 | |||
2863 | pr_debug("features_to_disable 0x%llx\n", features_to_disable); | ||
2864 | pr_debug("features_to_enable 0x%llx\n", features_to_enable); | ||
2865 | |||
2866 | if (features_to_disable) { | ||
2867 | ret = vega20_enable_smc_features(hwmgr, false, features_to_disable); | ||
2868 | if (ret) | ||
2869 | return ret; | ||
2870 | } | ||
2871 | |||
2872 | if (features_to_enable) { | ||
2873 | ret = vega20_enable_smc_features(hwmgr, true, features_to_enable); | ||
2874 | if (ret) | ||
2875 | return ret; | ||
2876 | } | ||
2877 | |||
2878 | return 0; | ||
2879 | } | ||
2880 | |||
2779 | static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr, | 2881 | static int vega20_print_clock_levels(struct pp_hwmgr *hwmgr, |
2780 | enum pp_clock_type type, char *buf) | 2882 | enum pp_clock_type type, char *buf) |
2781 | { | 2883 | { |
@@ -3572,6 +3674,8 @@ static const struct pp_hwmgr_func vega20_hwmgr_funcs = { | |||
3572 | .force_clock_level = vega20_force_clock_level, | 3674 | .force_clock_level = vega20_force_clock_level, |
3573 | .print_clock_levels = vega20_print_clock_levels, | 3675 | .print_clock_levels = vega20_print_clock_levels, |
3574 | .read_sensor = vega20_read_sensor, | 3676 | .read_sensor = vega20_read_sensor, |
3677 | .get_ppfeature_status = vega20_get_ppfeature_status, | ||
3678 | .set_ppfeature_status = vega20_set_ppfeature_status, | ||
3575 | /* powergate related */ | 3679 | /* powergate related */ |
3576 | .powergate_uvd = vega20_power_gate_uvd, | 3680 | .powergate_uvd = vega20_power_gate_uvd, |
3577 | .powergate_vce = vega20_power_gate_vce, | 3681 | .powergate_vce = vega20_power_gate_vce, |
diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h index 577cec90aef1..b1cd70dcd6e7 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h | |||
@@ -341,6 +341,8 @@ struct pp_hwmgr_func { | |||
341 | int (*get_asic_baco_capability)(struct pp_hwmgr *hwmgr, bool *cap); | 341 | int (*get_asic_baco_capability)(struct pp_hwmgr *hwmgr, bool *cap); |
342 | int (*get_asic_baco_state)(struct pp_hwmgr *hwmgr, enum BACO_STATE *state); | 342 | int (*get_asic_baco_state)(struct pp_hwmgr *hwmgr, enum BACO_STATE *state); |
343 | int (*set_asic_baco_state)(struct pp_hwmgr *hwmgr, enum BACO_STATE state); | 343 | int (*set_asic_baco_state)(struct pp_hwmgr *hwmgr, enum BACO_STATE state); |
344 | int (*get_ppfeature_status)(struct pp_hwmgr *hwmgr, char *buf); | ||
345 | int (*set_ppfeature_status)(struct pp_hwmgr *hwmgr, uint64_t ppfeature_masks); | ||
344 | }; | 346 | }; |
345 | 347 | ||
346 | struct pp_table_func { | 348 | struct pp_table_func { |