Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/amd/pm: add fan temperature/pwm curve OD setting support for SMU13

Add SMU13 fan temperature/pwm curve OD setting support.

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>

authored by

Evan Quan and committed by
Alex Deucher
d7bf1b55 1cf36599

+423 -8
+6
Documentation/gpu/amdgpu/thermal.rst
··· 64 64 .. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c 65 65 :doc: gpu_metrics 66 66 67 + fan_curve 68 + --------- 69 + 70 + .. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c 71 + :doc: fan_curve 72 + 67 73 GFXOFF 68 74 ====== 69 75
+3 -1
drivers/gpu/drm/amd/include/kgd_pp_interface.h
··· 113 113 OD_RANGE, 114 114 OD_VDDGFX_OFFSET, 115 115 OD_CCLK, 116 + OD_FAN_CURVE, 116 117 }; 117 118 118 119 enum amd_pp_sensors { ··· 187 186 PP_OD_EDIT_VDDC_CURVE, 188 187 PP_OD_RESTORE_DEFAULT_TABLE, 189 188 PP_OD_COMMIT_DPM_TABLE, 190 - PP_OD_EDIT_VDDGFX_OFFSET 189 + PP_OD_EDIT_VDDGFX_OFFSET, 190 + PP_OD_EDIT_FAN_CURVE, 191 191 }; 192 192 193 193 struct pp_states_info {
+209 -1
drivers/gpu/drm/amd/pm/amdgpu_pm.c
··· 3383 3383 NULL 3384 3384 }; 3385 3385 3386 - static struct od_feature_set amdgpu_od_set; 3386 + static int amdgpu_retrieve_od_settings(struct amdgpu_device *adev, 3387 + enum pp_clock_type od_type, 3388 + char *buf) 3389 + { 3390 + int size = 0; 3391 + int ret; 3392 + 3393 + if (amdgpu_in_reset(adev)) 3394 + return -EPERM; 3395 + if (adev->in_suspend && !adev->in_runpm) 3396 + return -EPERM; 3397 + 3398 + ret = pm_runtime_get_sync(adev->dev); 3399 + if (ret < 0) { 3400 + pm_runtime_put_autosuspend(adev->dev); 3401 + return ret; 3402 + } 3403 + 3404 + size = amdgpu_dpm_print_clock_levels(adev, od_type, buf); 3405 + if (size == 0) 3406 + size = sysfs_emit(buf, "\n"); 3407 + 3408 + pm_runtime_mark_last_busy(adev->dev); 3409 + pm_runtime_put_autosuspend(adev->dev); 3410 + 3411 + return size; 3412 + } 3413 + 3414 + static int parse_input_od_command_lines(const char *buf, 3415 + size_t count, 3416 + u32 *type, 3417 + long *params, 3418 + uint32_t *num_of_params) 3419 + { 3420 + const char delimiter[3] = {' ', '\n', '\0'}; 3421 + uint32_t parameter_size = 0; 3422 + char buf_cpy[128] = {0}; 3423 + char *tmp_str, *sub_str; 3424 + int ret; 3425 + 3426 + if (count > sizeof(buf_cpy) - 1) 3427 + return -EINVAL; 3428 + 3429 + memcpy(buf_cpy, buf, count); 3430 + tmp_str = buf_cpy; 3431 + 3432 + /* skip heading spaces */ 3433 + while (isspace(*tmp_str)) 3434 + tmp_str++; 3435 + 3436 + switch (*tmp_str) { 3437 + case 'c': 3438 + *type = PP_OD_COMMIT_DPM_TABLE; 3439 + return 0; 3440 + default: 3441 + break; 3442 + } 3443 + 3444 + while ((sub_str = strsep(&tmp_str, delimiter)) != NULL) { 3445 + if (strlen(sub_str) == 0) 3446 + continue; 3447 + 3448 + ret = kstrtol(sub_str, 0, &params[parameter_size]); 3449 + if (ret) 3450 + return -EINVAL; 3451 + parameter_size++; 3452 + 3453 + while (isspace(*tmp_str)) 3454 + tmp_str++; 3455 + } 3456 + 3457 + *num_of_params = parameter_size; 3458 + 3459 + return 0; 3460 + } 3461 + 3462 + static int 3463 + amdgpu_distribute_custom_od_settings(struct amdgpu_device *adev, 3464 + enum PP_OD_DPM_TABLE_COMMAND cmd_type, 3465 + const char *in_buf, 3466 + size_t count) 3467 + { 3468 + uint32_t parameter_size = 0; 3469 + long parameter[64]; 3470 + int ret; 3471 + 3472 + if (amdgpu_in_reset(adev)) 3473 + return -EPERM; 3474 + if (adev->in_suspend && !adev->in_runpm) 3475 + return -EPERM; 3476 + 3477 + ret = parse_input_od_command_lines(in_buf, 3478 + count, 3479 + &cmd_type, 3480 + parameter, 3481 + &parameter_size); 3482 + if (ret) 3483 + return ret; 3484 + 3485 + ret = pm_runtime_get_sync(adev->dev); 3486 + if (ret < 0) 3487 + goto err_out0; 3488 + 3489 + ret = amdgpu_dpm_odn_edit_dpm_table(adev, 3490 + cmd_type, 3491 + parameter, 3492 + parameter_size); 3493 + if (ret) 3494 + goto err_out1; 3495 + 3496 + if (cmd_type == PP_OD_COMMIT_DPM_TABLE) { 3497 + ret = amdgpu_dpm_dispatch_task(adev, 3498 + AMD_PP_TASK_READJUST_POWER_STATE, 3499 + NULL); 3500 + if (ret) 3501 + goto err_out1; 3502 + } 3503 + 3504 + pm_runtime_mark_last_busy(adev->dev); 3505 + pm_runtime_put_autosuspend(adev->dev); 3506 + 3507 + return count; 3508 + 3509 + err_out1: 3510 + pm_runtime_mark_last_busy(adev->dev); 3511 + err_out0: 3512 + pm_runtime_put_autosuspend(adev->dev); 3513 + 3514 + return ret; 3515 + } 3516 + 3517 + /** 3518 + * DOC: fan_curve 3519 + * 3520 + * The amdgpu driver provides a sysfs API for checking and adjusting the fan 3521 + * control curve line. 3522 + * 3523 + * Reading back the file shows you the current settings(temperature in Celsius 3524 + * degree and fan speed in pwm) applied to every anchor point of the curve line 3525 + * and their permitted ranges if changable. 3526 + * 3527 + * Writing a desired string(with the format like "anchor_point_index temperature 3528 + * fan_speed_in_pwm") to the file, change the settings for the specific anchor 3529 + * point accordingly. 3530 + * 3531 + * When you have finished the editing, write "c" (commit) to the file to commit 3532 + * your changes. 3533 + * 3534 + * There are two fan control modes supported: auto and manual. With auto mode, 3535 + * PMFW handles the fan speed control(how fan speed reacts to ASIC temperature). 3536 + * While with manual mode, users can set their own fan curve line as what 3537 + * described here. Normally the ASIC is booted up with auto mode. Any 3538 + * settings via this interface will switch the fan control to manual mode 3539 + * implicitly. 3540 + */ 3541 + static ssize_t fan_curve_show(struct kobject *kobj, 3542 + struct kobj_attribute *attr, 3543 + char *buf) 3544 + { 3545 + struct od_kobj *container = container_of(kobj, struct od_kobj, kobj); 3546 + struct amdgpu_device *adev = (struct amdgpu_device *)container->priv; 3547 + 3548 + return (ssize_t)amdgpu_retrieve_od_settings(adev, OD_FAN_CURVE, buf); 3549 + } 3550 + 3551 + static ssize_t fan_curve_store(struct kobject *kobj, 3552 + struct kobj_attribute *attr, 3553 + const char *buf, 3554 + size_t count) 3555 + { 3556 + struct od_kobj *container = container_of(kobj, struct od_kobj, kobj); 3557 + struct amdgpu_device *adev = (struct amdgpu_device *)container->priv; 3558 + 3559 + return (ssize_t)amdgpu_distribute_custom_od_settings(adev, 3560 + PP_OD_EDIT_FAN_CURVE, 3561 + buf, 3562 + count); 3563 + } 3564 + 3565 + static umode_t fan_curve_visible(struct amdgpu_device *adev) 3566 + { 3567 + umode_t umode = 0000; 3568 + 3569 + if (adev->pm.od_feature_mask & OD_OPS_SUPPORT_FAN_CURVE_RETRIEVE) 3570 + umode |= S_IRUSR | S_IRGRP | S_IROTH; 3571 + 3572 + if (adev->pm.od_feature_mask & OD_OPS_SUPPORT_FAN_CURVE_SET) 3573 + umode |= S_IWUSR; 3574 + 3575 + return umode; 3576 + } 3577 + 3578 + static struct od_feature_set amdgpu_od_set = { 3579 + .containers = { 3580 + [0] = { 3581 + .name = "fan_ctrl", 3582 + .sub_feature = { 3583 + [0] = { 3584 + .name = "fan_curve", 3585 + .ops = { 3586 + .is_visible = fan_curve_visible, 3587 + .show = fan_curve_show, 3588 + .store = fan_curve_store, 3589 + }, 3590 + }, 3591 + }, 3592 + }, 3593 + }, 3594 + }; 3387 3595 3388 3596 static void od_kobj_release(struct kobject *kobj) 3389 3597 {
+4
drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
··· 314 314 uint16_t fclk_average_tau; 315 315 }; 316 316 317 + #define OD_OPS_SUPPORT_FAN_CURVE_RETRIEVE BIT(0) 318 + #define OD_OPS_SUPPORT_FAN_CURVE_SET BIT(1) 319 + 317 320 struct amdgpu_pm { 318 321 struct mutex mutex; 319 322 u32 current_sclk; ··· 371 368 enum amdgpu_runpm_mode rpm_mode; 372 369 373 370 struct list_head od_kobj_list; 371 + uint32_t od_feature_mask; 374 372 }; 375 373 376 374 int amdgpu_dpm_read_sensor(struct amdgpu_device *adev, enum amd_pp_sensors sensor,
+2
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
··· 2481 2481 clk_type = SMU_OD_VDDGFX_OFFSET; break; 2482 2482 case OD_CCLK: 2483 2483 clk_type = SMU_OD_CCLK; break; 2484 + case OD_FAN_CURVE: 2485 + clk_type = SMU_OD_FAN_CURVE; break; 2484 2486 default: 2485 2487 clk_type = SMU_CLK_COUNT; break; 2486 2488 }
+1
drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h
··· 280 280 SMU_OD_VDDC_CURVE, 281 281 SMU_OD_RANGE, 282 282 SMU_OD_VDDGFX_OFFSET, 283 + SMU_OD_FAN_CURVE, 283 284 SMU_CLK_COUNT, 284 285 }; 285 286
+99 -3
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
··· 101 101 #define PP_OD_FEATURE_UCLK_FMIN 2 102 102 #define PP_OD_FEATURE_UCLK_FMAX 3 103 103 #define PP_OD_FEATURE_GFX_VF_CURVE 4 104 + #define PP_OD_FEATURE_FAN_CURVE_TEMP 5 105 + #define PP_OD_FEATURE_FAN_CURVE_PWM 6 104 106 105 107 #define LINK_SPEED_MAX 3 106 108 ··· 1124 1122 od_min_setting = overdrive_lowerlimits->VoltageOffsetPerZoneBoundary; 1125 1123 od_max_setting = overdrive_upperlimits->VoltageOffsetPerZoneBoundary; 1126 1124 break; 1125 + case PP_OD_FEATURE_FAN_CURVE_TEMP: 1126 + od_min_setting = overdrive_lowerlimits->FanLinearTempPoints; 1127 + od_max_setting = overdrive_upperlimits->FanLinearTempPoints; 1128 + break; 1129 + case PP_OD_FEATURE_FAN_CURVE_PWM: 1130 + od_min_setting = overdrive_lowerlimits->FanLinearPwmPoints; 1131 + od_max_setting = overdrive_upperlimits->FanLinearPwmPoints; 1132 + break; 1127 1133 default: 1128 1134 od_min_setting = od_max_setting = INT_MAX; 1129 1135 break; ··· 1351 1341 od_table->OverDriveTable.VoltageOffsetPerZoneBoundary[0]); 1352 1342 break; 1353 1343 1344 + case SMU_OD_FAN_CURVE: 1345 + if (!smu_v13_0_0_is_od_feature_supported(smu, 1346 + PP_OD_FEATURE_FAN_CURVE_BIT)) 1347 + break; 1348 + 1349 + size += sysfs_emit_at(buf, size, "OD_FAN_CURVE:\n"); 1350 + for (i = 0; i < NUM_OD_FAN_MAX_POINTS - 1; i++) 1351 + size += sysfs_emit_at(buf, size, "%d: %dC %d%%\n", 1352 + i, 1353 + (int)od_table->OverDriveTable.FanLinearTempPoints[i], 1354 + (int)od_table->OverDriveTable.FanLinearPwmPoints[i]); 1355 + 1356 + size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE"); 1357 + smu_v13_0_0_get_od_setting_limits(smu, 1358 + PP_OD_FEATURE_FAN_CURVE_TEMP, 1359 + &min_value, 1360 + &max_value); 1361 + size += sysfs_emit_at(buf, size, "FAN_CURVE(hotspot temp): %uC %uC\n", 1362 + min_value, max_value); 1363 + 1364 + smu_v13_0_0_get_od_setting_limits(smu, 1365 + PP_OD_FEATURE_FAN_CURVE_PWM, 1366 + &min_value, 1367 + &max_value); 1368 + size += sysfs_emit_at(buf, size, "FAN_CURVE(fan speed): %u%% %u%%\n", 1369 + min_value, max_value); 1370 + 1371 + break; 1372 + 1354 1373 case SMU_OD_RANGE: 1355 1374 if (!smu_v13_0_0_is_od_feature_supported(smu, PP_OD_FEATURE_GFXCLK_BIT) && 1356 1375 !smu_v13_0_0_is_od_feature_supported(smu, PP_OD_FEATURE_UCLK_BIT) && ··· 1588 1549 for (i = 0; i < PP_NUM_OD_VF_CURVE_POINTS; i++) 1589 1550 od_table->OverDriveTable.VoltageOffsetPerZoneBoundary[i] = input[0]; 1590 1551 od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_GFX_VF_CURVE_BIT); 1552 + break; 1553 + 1554 + case PP_OD_EDIT_FAN_CURVE: 1555 + if (!smu_v13_0_0_is_od_feature_supported(smu, PP_OD_FEATURE_FAN_CURVE_BIT)) { 1556 + dev_warn(adev->dev, "Fan curve setting not supported!\n"); 1557 + return -ENOTSUPP; 1558 + } 1559 + 1560 + if (input[0] >= NUM_OD_FAN_MAX_POINTS - 1 || 1561 + input[0] < 0) 1562 + return -EINVAL; 1563 + 1564 + smu_v13_0_0_get_od_setting_limits(smu, 1565 + PP_OD_FEATURE_FAN_CURVE_TEMP, 1566 + &minimum, 1567 + &maximum); 1568 + if (input[1] < minimum || 1569 + input[1] > maximum) { 1570 + dev_info(adev->dev, "Fan curve temp setting(%ld) must be within [%d, %d]!\n", 1571 + input[1], minimum, maximum); 1572 + return -EINVAL; 1573 + } 1574 + 1575 + smu_v13_0_0_get_od_setting_limits(smu, 1576 + PP_OD_FEATURE_FAN_CURVE_PWM, 1577 + &minimum, 1578 + &maximum); 1579 + if (input[2] < minimum || 1580 + input[2] > maximum) { 1581 + dev_info(adev->dev, "Fan curve pwm setting(%ld) must be within [%d, %d]!\n", 1582 + input[2], minimum, maximum); 1583 + return -EINVAL; 1584 + } 1585 + 1586 + od_table->OverDriveTable.FanLinearTempPoints[input[0]] = input[1]; 1587 + od_table->OverDriveTable.FanLinearPwmPoints[input[0]] = input[2]; 1588 + od_table->OverDriveTable.FanMode = FAN_MODE_MANUAL_LINEAR; 1589 + od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT); 1591 1590 break; 1592 1591 1593 1592 case PP_OD_RESTORE_DEFAULT_TABLE: ··· 1878 1801 return sizeof(struct gpu_metrics_v1_3); 1879 1802 } 1880 1803 1804 + static void smu_v13_0_0_set_supported_od_feature_mask(struct smu_context *smu) 1805 + { 1806 + struct amdgpu_device *adev = smu->adev; 1807 + 1808 + if (smu_v13_0_0_is_od_feature_supported(smu, 1809 + PP_OD_FEATURE_FAN_CURVE_BIT)) 1810 + adev->pm.od_feature_mask |= OD_OPS_SUPPORT_FAN_CURVE_RETRIEVE | 1811 + OD_OPS_SUPPORT_FAN_CURVE_SET; 1812 + } 1813 + 1881 1814 static int smu_v13_0_0_set_default_od_settings(struct smu_context *smu) 1882 1815 { 1883 1816 OverDriveTableExternal_t *od_table = ··· 1937 1850 for (i = 0; i < PP_NUM_OD_VF_CURVE_POINTS; i++) 1938 1851 user_od_table->OverDriveTable.VoltageOffsetPerZoneBoundary[i] = 1939 1852 user_od_table_bak.OverDriveTable.VoltageOffsetPerZoneBoundary[i]; 1853 + for (i = 0; i < NUM_OD_FAN_MAX_POINTS - 1; i++) { 1854 + user_od_table->OverDriveTable.FanLinearTempPoints[i] = 1855 + user_od_table_bak.OverDriveTable.FanLinearTempPoints[i]; 1856 + user_od_table->OverDriveTable.FanLinearPwmPoints[i] = 1857 + user_od_table_bak.OverDriveTable.FanLinearPwmPoints[i]; 1858 + } 1940 1859 } 1860 + 1861 + smu_v13_0_0_set_supported_od_feature_mask(smu); 1941 1862 1942 1863 return 0; 1943 1864 } ··· 1957 1862 OverDriveTableExternal_t *user_od_table = table_context->user_overdrive_table; 1958 1863 int res; 1959 1864 1960 - user_od_table->OverDriveTable.FeatureCtrlMask = 1U << PP_OD_FEATURE_GFXCLK_BIT | 1961 - 1U << PP_OD_FEATURE_UCLK_BIT | 1962 - 1U << PP_OD_FEATURE_GFX_VF_CURVE_BIT; 1865 + user_od_table->OverDriveTable.FeatureCtrlMask = BIT(PP_OD_FEATURE_GFXCLK_BIT) | 1866 + BIT(PP_OD_FEATURE_UCLK_BIT) | 1867 + BIT(PP_OD_FEATURE_GFX_VF_CURVE_BIT) | 1868 + BIT(PP_OD_FEATURE_FAN_CURVE_BIT); 1963 1869 res = smu_v13_0_0_upload_overdrive_table(smu, user_od_table); 1964 1870 user_od_table->OverDriveTable.FeatureCtrlMask = 0; 1965 1871 if (res == 0)
+99 -3
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
··· 77 77 #define PP_OD_FEATURE_UCLK_FMIN 2 78 78 #define PP_OD_FEATURE_UCLK_FMAX 3 79 79 #define PP_OD_FEATURE_GFX_VF_CURVE 4 80 + #define PP_OD_FEATURE_FAN_CURVE_TEMP 5 81 + #define PP_OD_FEATURE_FAN_CURVE_PWM 6 80 82 81 83 #define LINK_SPEED_MAX 3 82 84 ··· 1104 1102 od_min_setting = overdrive_lowerlimits->VoltageOffsetPerZoneBoundary; 1105 1103 od_max_setting = overdrive_upperlimits->VoltageOffsetPerZoneBoundary; 1106 1104 break; 1105 + case PP_OD_FEATURE_FAN_CURVE_TEMP: 1106 + od_min_setting = overdrive_lowerlimits->FanLinearTempPoints; 1107 + od_max_setting = overdrive_upperlimits->FanLinearTempPoints; 1108 + break; 1109 + case PP_OD_FEATURE_FAN_CURVE_PWM: 1110 + od_min_setting = overdrive_lowerlimits->FanLinearPwmPoints; 1111 + od_max_setting = overdrive_upperlimits->FanLinearPwmPoints; 1112 + break; 1107 1113 default: 1108 1114 od_min_setting = od_max_setting = INT_MAX; 1109 1115 break; ··· 1331 1321 od_table->OverDriveTable.VoltageOffsetPerZoneBoundary[0]); 1332 1322 break; 1333 1323 1324 + case SMU_OD_FAN_CURVE: 1325 + if (!smu_v13_0_7_is_od_feature_supported(smu, 1326 + PP_OD_FEATURE_FAN_CURVE_BIT)) 1327 + break; 1328 + 1329 + size += sysfs_emit_at(buf, size, "OD_FAN_CURVE:\n"); 1330 + for (i = 0; i < NUM_OD_FAN_MAX_POINTS - 1; i++) 1331 + size += sysfs_emit_at(buf, size, "%d: %dC %d%%\n", 1332 + i, 1333 + (int)od_table->OverDriveTable.FanLinearTempPoints[i], 1334 + (int)od_table->OverDriveTable.FanLinearPwmPoints[i]); 1335 + 1336 + size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE"); 1337 + smu_v13_0_7_get_od_setting_limits(smu, 1338 + PP_OD_FEATURE_FAN_CURVE_TEMP, 1339 + &min_value, 1340 + &max_value); 1341 + size += sysfs_emit_at(buf, size, "FAN_CURVE(hotspot temp): %uC %uC\n", 1342 + min_value, max_value); 1343 + 1344 + smu_v13_0_7_get_od_setting_limits(smu, 1345 + PP_OD_FEATURE_FAN_CURVE_PWM, 1346 + &min_value, 1347 + &max_value); 1348 + size += sysfs_emit_at(buf, size, "FAN_CURVE(fan speed): %u%% %u%%\n", 1349 + min_value, max_value); 1350 + 1351 + break; 1352 + 1334 1353 case SMU_OD_RANGE: 1335 1354 if (!smu_v13_0_7_is_od_feature_supported(smu, PP_OD_FEATURE_GFXCLK_BIT) && 1336 1355 !smu_v13_0_7_is_od_feature_supported(smu, PP_OD_FEATURE_UCLK_BIT) && ··· 1568 1529 for (i = 0; i < PP_NUM_OD_VF_CURVE_POINTS; i++) 1569 1530 od_table->OverDriveTable.VoltageOffsetPerZoneBoundary[i] = input[0]; 1570 1531 od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_GFX_VF_CURVE_BIT); 1532 + break; 1533 + 1534 + case PP_OD_EDIT_FAN_CURVE: 1535 + if (!smu_v13_0_7_is_od_feature_supported(smu, PP_OD_FEATURE_FAN_CURVE_BIT)) { 1536 + dev_warn(adev->dev, "Fan curve setting not supported!\n"); 1537 + return -ENOTSUPP; 1538 + } 1539 + 1540 + if (input[0] >= NUM_OD_FAN_MAX_POINTS - 1 || 1541 + input[0] < 0) 1542 + return -EINVAL; 1543 + 1544 + smu_v13_0_7_get_od_setting_limits(smu, 1545 + PP_OD_FEATURE_FAN_CURVE_TEMP, 1546 + &minimum, 1547 + &maximum); 1548 + if (input[1] < minimum || 1549 + input[1] > maximum) { 1550 + dev_info(adev->dev, "Fan curve temp setting(%ld) must be within [%d, %d]!\n", 1551 + input[1], minimum, maximum); 1552 + return -EINVAL; 1553 + } 1554 + 1555 + smu_v13_0_7_get_od_setting_limits(smu, 1556 + PP_OD_FEATURE_FAN_CURVE_PWM, 1557 + &minimum, 1558 + &maximum); 1559 + if (input[2] < minimum || 1560 + input[2] > maximum) { 1561 + dev_info(adev->dev, "Fan curve pwm setting(%ld) must be within [%d, %d]!\n", 1562 + input[2], minimum, maximum); 1563 + return -EINVAL; 1564 + } 1565 + 1566 + od_table->OverDriveTable.FanLinearTempPoints[input[0]] = input[1]; 1567 + od_table->OverDriveTable.FanLinearPwmPoints[input[0]] = input[2]; 1568 + od_table->OverDriveTable.FanMode = FAN_MODE_MANUAL_LINEAR; 1569 + od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT); 1571 1570 break; 1572 1571 1573 1572 case PP_OD_RESTORE_DEFAULT_TABLE: ··· 1853 1776 return sizeof(struct gpu_metrics_v1_3); 1854 1777 } 1855 1778 1779 + static void smu_v13_0_7_set_supported_od_feature_mask(struct smu_context *smu) 1780 + { 1781 + struct amdgpu_device *adev = smu->adev; 1782 + 1783 + if (smu_v13_0_7_is_od_feature_supported(smu, 1784 + PP_OD_FEATURE_FAN_CURVE_BIT)) 1785 + adev->pm.od_feature_mask |= OD_OPS_SUPPORT_FAN_CURVE_RETRIEVE | 1786 + OD_OPS_SUPPORT_FAN_CURVE_SET; 1787 + } 1788 + 1856 1789 static int smu_v13_0_7_set_default_od_settings(struct smu_context *smu) 1857 1790 { 1858 1791 OverDriveTableExternal_t *od_table = ··· 1912 1825 for (i = 0; i < PP_NUM_OD_VF_CURVE_POINTS; i++) 1913 1826 user_od_table->OverDriveTable.VoltageOffsetPerZoneBoundary[i] = 1914 1827 user_od_table_bak.OverDriveTable.VoltageOffsetPerZoneBoundary[i]; 1828 + for (i = 0; i < NUM_OD_FAN_MAX_POINTS - 1; i++) { 1829 + user_od_table->OverDriveTable.FanLinearTempPoints[i] = 1830 + user_od_table_bak.OverDriveTable.FanLinearTempPoints[i]; 1831 + user_od_table->OverDriveTable.FanLinearPwmPoints[i] = 1832 + user_od_table_bak.OverDriveTable.FanLinearPwmPoints[i]; 1833 + } 1915 1834 } 1835 + 1836 + smu_v13_0_7_set_supported_od_feature_mask(smu); 1916 1837 1917 1838 return 0; 1918 1839 } ··· 1932 1837 OverDriveTableExternal_t *user_od_table = table_context->user_overdrive_table; 1933 1838 int res; 1934 1839 1935 - user_od_table->OverDriveTable.FeatureCtrlMask = 1U << PP_OD_FEATURE_GFXCLK_BIT | 1936 - 1U << PP_OD_FEATURE_UCLK_BIT | 1937 - 1U << PP_OD_FEATURE_GFX_VF_CURVE_BIT; 1840 + user_od_table->OverDriveTable.FeatureCtrlMask = BIT(PP_OD_FEATURE_GFXCLK_BIT) | 1841 + BIT(PP_OD_FEATURE_UCLK_BIT) | 1842 + BIT(PP_OD_FEATURE_GFX_VF_CURVE_BIT) | 1843 + BIT(PP_OD_FEATURE_FAN_CURVE_BIT); 1938 1844 res = smu_v13_0_7_upload_overdrive_table(smu, user_od_table); 1939 1845 user_od_table->OverDriveTable.FeatureCtrlMask = 0; 1940 1846 if (res == 0)