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: introduce a new set of OD interfaces

There will be multiple interfaces(sysfs files) exposed with each representing
a single OD functionality. And all those interface will be arranged in a tree
liked hierarchy with the top dir as "gpu_od". Meanwhile all functionalities
for the same component will be arranged under the same directory.

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
3e38b634 2cd1f65d

+266 -2
+2
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
··· 3624 3624 3625 3625 INIT_LIST_HEAD(&adev->ras_list); 3626 3626 3627 + INIT_LIST_HEAD(&adev->pm.od_kobj_list); 3628 + 3627 3629 INIT_DELAYED_WORK(&adev->delayed_init_work, 3628 3630 amdgpu_device_delayed_init_work_handler); 3629 3631 INIT_DELAYED_WORK(&adev->gfx.gfx_off_delay_work,
+262 -2
drivers/gpu/drm/amd/pm/amdgpu_pm.c
··· 35 35 #include <linux/pm_runtime.h> 36 36 #include <asm/processor.h> 37 37 38 + #define MAX_NUM_OF_FEATURES_PER_SUBSET 8 39 + #define MAX_NUM_OF_SUBSETS 8 40 + 41 + struct od_attribute { 42 + struct kobj_attribute attribute; 43 + struct list_head entry; 44 + }; 45 + 46 + struct od_kobj { 47 + struct kobject kobj; 48 + struct list_head entry; 49 + struct list_head attribute; 50 + void *priv; 51 + }; 52 + 53 + struct od_feature_ops { 54 + umode_t (*is_visible)(struct amdgpu_device *adev); 55 + ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr, 56 + char *buf); 57 + ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr, 58 + const char *buf, size_t count); 59 + }; 60 + 61 + struct od_feature_item { 62 + const char *name; 63 + struct od_feature_ops ops; 64 + }; 65 + 66 + struct od_feature_container { 67 + char *name; 68 + struct od_feature_ops ops; 69 + struct od_feature_item sub_feature[MAX_NUM_OF_FEATURES_PER_SUBSET]; 70 + }; 71 + 72 + struct od_feature_set { 73 + struct od_feature_container containers[MAX_NUM_OF_SUBSETS]; 74 + }; 75 + 38 76 static const struct hwmon_temp_label { 39 77 enum PP_HWMON_TEMP channel; 40 78 const char *label; ··· 3383 3345 NULL 3384 3346 }; 3385 3347 3348 + static struct od_feature_set amdgpu_od_set; 3349 + 3350 + static void od_kobj_release(struct kobject *kobj) 3351 + { 3352 + struct od_kobj *od_kobj = container_of(kobj, struct od_kobj, kobj); 3353 + 3354 + kfree(od_kobj); 3355 + } 3356 + 3357 + static const struct kobj_type od_ktype = { 3358 + .release = od_kobj_release, 3359 + .sysfs_ops = &kobj_sysfs_ops, 3360 + }; 3361 + 3362 + static void amdgpu_od_set_fini(struct amdgpu_device *adev) 3363 + { 3364 + struct od_kobj *container, *container_next; 3365 + struct od_attribute *attribute, *attribute_next; 3366 + 3367 + if (list_empty(&adev->pm.od_kobj_list)) 3368 + return; 3369 + 3370 + list_for_each_entry_safe(container, container_next, 3371 + &adev->pm.od_kobj_list, entry) { 3372 + list_del(&container->entry); 3373 + 3374 + list_for_each_entry_safe(attribute, attribute_next, 3375 + &container->attribute, entry) { 3376 + list_del(&attribute->entry); 3377 + sysfs_remove_file(&container->kobj, 3378 + &attribute->attribute.attr); 3379 + kfree(attribute); 3380 + } 3381 + 3382 + kobject_put(&container->kobj); 3383 + } 3384 + } 3385 + 3386 + static bool amdgpu_is_od_feature_supported(struct amdgpu_device *adev, 3387 + struct od_feature_ops *feature_ops) 3388 + { 3389 + umode_t mode; 3390 + 3391 + if (!feature_ops->is_visible) 3392 + return false; 3393 + 3394 + /* 3395 + * If the feature has no user read and write mode set, 3396 + * we can assume the feature is actually not supported.(?) 3397 + * And the revelant sysfs interface should not be exposed. 3398 + */ 3399 + mode = feature_ops->is_visible(adev); 3400 + if (mode & (S_IRUSR | S_IWUSR)) 3401 + return true; 3402 + 3403 + return false; 3404 + } 3405 + 3406 + static bool amdgpu_od_is_self_contained(struct amdgpu_device *adev, 3407 + struct od_feature_container *container) 3408 + { 3409 + int i; 3410 + 3411 + /* 3412 + * If there is no valid entry within the container, the container 3413 + * is recognized as a self contained container. And the valid entry 3414 + * here means it has a valid naming and it is visible/supported by 3415 + * the ASIC. 3416 + */ 3417 + for (i = 0; i < ARRAY_SIZE(container->sub_feature); i++) { 3418 + if (container->sub_feature[i].name && 3419 + amdgpu_is_od_feature_supported(adev, 3420 + &container->sub_feature[i].ops)) 3421 + return false; 3422 + } 3423 + 3424 + return true; 3425 + } 3426 + 3427 + static int amdgpu_od_set_init(struct amdgpu_device *adev) 3428 + { 3429 + struct od_kobj *top_set, *sub_set; 3430 + struct od_attribute *attribute; 3431 + struct od_feature_container *container; 3432 + struct od_feature_item *feature; 3433 + int i, j; 3434 + int ret; 3435 + 3436 + /* Setup the top `gpu_od` directory which holds all other OD interfaces */ 3437 + top_set = kzalloc(sizeof(*top_set), GFP_KERNEL); 3438 + if (!top_set) 3439 + return -ENOMEM; 3440 + list_add(&top_set->entry, &adev->pm.od_kobj_list); 3441 + 3442 + ret = kobject_init_and_add(&top_set->kobj, 3443 + &od_ktype, 3444 + &adev->dev->kobj, 3445 + "%s", 3446 + "gpu_od"); 3447 + if (ret) 3448 + goto err_out; 3449 + INIT_LIST_HEAD(&top_set->attribute); 3450 + top_set->priv = adev; 3451 + 3452 + for (i = 0; i < ARRAY_SIZE(amdgpu_od_set.containers); i++) { 3453 + container = &amdgpu_od_set.containers[i]; 3454 + 3455 + if (!container->name) 3456 + continue; 3457 + 3458 + /* 3459 + * If there is valid entries within the container, the container 3460 + * will be presented as a sub directory and all its holding entries 3461 + * will be presented as plain files under it. 3462 + * While if there is no valid entry within the container, the container 3463 + * itself will be presented as a plain file under top `gpu_od` directory. 3464 + */ 3465 + if (amdgpu_od_is_self_contained(adev, container)) { 3466 + if (!amdgpu_is_od_feature_supported(adev, 3467 + &container->ops)) 3468 + continue; 3469 + 3470 + /* 3471 + * The container is presented as a plain file under top `gpu_od` 3472 + * directory. 3473 + */ 3474 + attribute = kzalloc(sizeof(*attribute), GFP_KERNEL); 3475 + if (!attribute) { 3476 + ret = -ENOMEM; 3477 + goto err_out; 3478 + } 3479 + list_add(&attribute->entry, &top_set->attribute); 3480 + 3481 + attribute->attribute.attr.mode = 3482 + container->ops.is_visible(adev); 3483 + attribute->attribute.attr.name = container->name; 3484 + attribute->attribute.show = 3485 + container->ops.show; 3486 + attribute->attribute.store = 3487 + container->ops.store; 3488 + ret = sysfs_create_file(&top_set->kobj, 3489 + &attribute->attribute.attr); 3490 + if (ret) 3491 + goto err_out; 3492 + } else { 3493 + /* The container is presented as a sub directory. */ 3494 + sub_set = kzalloc(sizeof(*sub_set), GFP_KERNEL); 3495 + if (!sub_set) { 3496 + ret = -ENOMEM; 3497 + goto err_out; 3498 + } 3499 + list_add(&sub_set->entry, &adev->pm.od_kobj_list); 3500 + 3501 + ret = kobject_init_and_add(&sub_set->kobj, 3502 + &od_ktype, 3503 + &top_set->kobj, 3504 + "%s", 3505 + container->name); 3506 + if (ret) 3507 + goto err_out; 3508 + INIT_LIST_HEAD(&sub_set->attribute); 3509 + sub_set->priv = adev; 3510 + 3511 + for (j = 0; j < ARRAY_SIZE(container->sub_feature); j++) { 3512 + feature = &container->sub_feature[j]; 3513 + if (!feature->name) 3514 + continue; 3515 + 3516 + if (!amdgpu_is_od_feature_supported(adev, 3517 + &feature->ops)) 3518 + continue; 3519 + 3520 + /* 3521 + * With the container presented as a sub directory, the entry within 3522 + * it is presented as a plain file under the sub directory. 3523 + */ 3524 + attribute = kzalloc(sizeof(*attribute), GFP_KERNEL); 3525 + if (!attribute) { 3526 + ret = -ENOMEM; 3527 + goto err_out; 3528 + } 3529 + list_add(&attribute->entry, &sub_set->attribute); 3530 + 3531 + attribute->attribute.attr.mode = 3532 + feature->ops.is_visible(adev); 3533 + attribute->attribute.attr.name = feature->name; 3534 + attribute->attribute.show = 3535 + feature->ops.show; 3536 + attribute->attribute.store = 3537 + feature->ops.store; 3538 + ret = sysfs_create_file(&sub_set->kobj, 3539 + &attribute->attribute.attr); 3540 + if (ret) 3541 + goto err_out; 3542 + } 3543 + } 3544 + } 3545 + 3546 + return 0; 3547 + 3548 + err_out: 3549 + amdgpu_od_set_fini(adev); 3550 + 3551 + return ret; 3552 + } 3553 + 3386 3554 int amdgpu_pm_sysfs_init(struct amdgpu_device *adev) 3387 3555 { 3388 - int ret; 3389 3556 uint32_t mask = 0; 3557 + int ret; 3390 3558 3391 3559 if (adev->pm.sysfs_initialized) 3392 3560 return 0; ··· 3631 3387 mask, 3632 3388 &adev->pm.pm_attr_list); 3633 3389 if (ret) 3634 - return ret; 3390 + goto err_out0; 3391 + 3392 + if (amdgpu_dpm_is_overdrive_supported(adev)) { 3393 + ret = amdgpu_od_set_init(adev); 3394 + if (ret) 3395 + goto err_out1; 3396 + } 3635 3397 3636 3398 adev->pm.sysfs_initialized = true; 3637 3399 3638 3400 return 0; 3401 + 3402 + err_out1: 3403 + amdgpu_device_attr_remove_groups(adev, &adev->pm.pm_attr_list); 3404 + err_out0: 3405 + if (adev->pm.int_hwmon_dev) 3406 + hwmon_device_unregister(adev->pm.int_hwmon_dev); 3407 + 3408 + return ret; 3639 3409 } 3640 3410 3641 3411 void amdgpu_pm_sysfs_fini(struct amdgpu_device *adev) 3642 3412 { 3413 + amdgpu_od_set_fini(adev); 3414 + 3643 3415 if (adev->pm.int_hwmon_dev) 3644 3416 hwmon_device_unregister(adev->pm.int_hwmon_dev); 3645 3417
+2
drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
··· 366 366 struct config_table_setting config_table; 367 367 /* runtime mode */ 368 368 enum amdgpu_runpm_mode rpm_mode; 369 + 370 + struct list_head od_kobj_list; 369 371 }; 370 372 371 373 int amdgpu_dpm_read_sensor(struct amdgpu_device *adev, enum amd_pp_sensors sensor,