diff options
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c')
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 100 |
1 files changed, 42 insertions, 58 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c index f1404adc3a90..15a1192c1ec5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | |||
@@ -606,40 +606,59 @@ static ssize_t amdgpu_get_pp_dpm_sclk(struct device *dev, | |||
606 | return snprintf(buf, PAGE_SIZE, "\n"); | 606 | return snprintf(buf, PAGE_SIZE, "\n"); |
607 | } | 607 | } |
608 | 608 | ||
609 | static ssize_t amdgpu_set_pp_dpm_sclk(struct device *dev, | 609 | /* |
610 | struct device_attribute *attr, | 610 | * Worst case: 32 bits individually specified, in octal at 12 characters |
611 | const char *buf, | 611 | * per line (+1 for \n). |
612 | size_t count) | 612 | */ |
613 | #define AMDGPU_MASK_BUF_MAX (32 * 13) | ||
614 | |||
615 | static ssize_t amdgpu_read_mask(const char *buf, size_t count, uint32_t *mask) | ||
613 | { | 616 | { |
614 | struct drm_device *ddev = dev_get_drvdata(dev); | ||
615 | struct amdgpu_device *adev = ddev->dev_private; | ||
616 | int ret; | 617 | int ret; |
617 | long level; | 618 | long level; |
618 | uint32_t mask = 0; | ||
619 | char *sub_str = NULL; | 619 | char *sub_str = NULL; |
620 | char *tmp; | 620 | char *tmp; |
621 | char buf_cpy[count]; | 621 | char buf_cpy[AMDGPU_MASK_BUF_MAX + 1]; |
622 | const char delimiter[3] = {' ', '\n', '\0'}; | 622 | const char delimiter[3] = {' ', '\n', '\0'}; |
623 | size_t bytes; | ||
623 | 624 | ||
624 | memcpy(buf_cpy, buf, count+1); | 625 | *mask = 0; |
626 | |||
627 | bytes = min(count, sizeof(buf_cpy) - 1); | ||
628 | memcpy(buf_cpy, buf, bytes); | ||
629 | buf_cpy[bytes] = '\0'; | ||
625 | tmp = buf_cpy; | 630 | tmp = buf_cpy; |
626 | while (tmp[0]) { | 631 | while (tmp[0]) { |
627 | sub_str = strsep(&tmp, delimiter); | 632 | sub_str = strsep(&tmp, delimiter); |
628 | if (strlen(sub_str)) { | 633 | if (strlen(sub_str)) { |
629 | ret = kstrtol(sub_str, 0, &level); | 634 | ret = kstrtol(sub_str, 0, &level); |
630 | 635 | if (ret) | |
631 | if (ret) { | 636 | return -EINVAL; |
632 | count = -EINVAL; | 637 | *mask |= 1 << level; |
633 | goto fail; | ||
634 | } | ||
635 | mask |= 1 << level; | ||
636 | } else | 638 | } else |
637 | break; | 639 | break; |
638 | } | 640 | } |
641 | |||
642 | return 0; | ||
643 | } | ||
644 | |||
645 | static ssize_t amdgpu_set_pp_dpm_sclk(struct device *dev, | ||
646 | struct device_attribute *attr, | ||
647 | const char *buf, | ||
648 | size_t count) | ||
649 | { | ||
650 | struct drm_device *ddev = dev_get_drvdata(dev); | ||
651 | struct amdgpu_device *adev = ddev->dev_private; | ||
652 | int ret; | ||
653 | uint32_t mask = 0; | ||
654 | |||
655 | ret = amdgpu_read_mask(buf, count, &mask); | ||
656 | if (ret) | ||
657 | return ret; | ||
658 | |||
639 | if (adev->powerplay.pp_funcs->force_clock_level) | 659 | if (adev->powerplay.pp_funcs->force_clock_level) |
640 | amdgpu_dpm_force_clock_level(adev, PP_SCLK, mask); | 660 | amdgpu_dpm_force_clock_level(adev, PP_SCLK, mask); |
641 | 661 | ||
642 | fail: | ||
643 | return count; | 662 | return count; |
644 | } | 663 | } |
645 | 664 | ||
@@ -664,32 +683,15 @@ static ssize_t amdgpu_set_pp_dpm_mclk(struct device *dev, | |||
664 | struct drm_device *ddev = dev_get_drvdata(dev); | 683 | struct drm_device *ddev = dev_get_drvdata(dev); |
665 | struct amdgpu_device *adev = ddev->dev_private; | 684 | struct amdgpu_device *adev = ddev->dev_private; |
666 | int ret; | 685 | int ret; |
667 | long level; | ||
668 | uint32_t mask = 0; | 686 | uint32_t mask = 0; |
669 | char *sub_str = NULL; | ||
670 | char *tmp; | ||
671 | char buf_cpy[count]; | ||
672 | const char delimiter[3] = {' ', '\n', '\0'}; | ||
673 | 687 | ||
674 | memcpy(buf_cpy, buf, count+1); | 688 | ret = amdgpu_read_mask(buf, count, &mask); |
675 | tmp = buf_cpy; | 689 | if (ret) |
676 | while (tmp[0]) { | 690 | return ret; |
677 | sub_str = strsep(&tmp, delimiter); | ||
678 | if (strlen(sub_str)) { | ||
679 | ret = kstrtol(sub_str, 0, &level); | ||
680 | 691 | ||
681 | if (ret) { | ||
682 | count = -EINVAL; | ||
683 | goto fail; | ||
684 | } | ||
685 | mask |= 1 << level; | ||
686 | } else | ||
687 | break; | ||
688 | } | ||
689 | if (adev->powerplay.pp_funcs->force_clock_level) | 692 | if (adev->powerplay.pp_funcs->force_clock_level) |
690 | amdgpu_dpm_force_clock_level(adev, PP_MCLK, mask); | 693 | amdgpu_dpm_force_clock_level(adev, PP_MCLK, mask); |
691 | 694 | ||
692 | fail: | ||
693 | return count; | 695 | return count; |
694 | } | 696 | } |
695 | 697 | ||
@@ -714,33 +716,15 @@ static ssize_t amdgpu_set_pp_dpm_pcie(struct device *dev, | |||
714 | struct drm_device *ddev = dev_get_drvdata(dev); | 716 | struct drm_device *ddev = dev_get_drvdata(dev); |
715 | struct amdgpu_device *adev = ddev->dev_private; | 717 | struct amdgpu_device *adev = ddev->dev_private; |
716 | int ret; | 718 | int ret; |
717 | long level; | ||
718 | uint32_t mask = 0; | 719 | uint32_t mask = 0; |
719 | char *sub_str = NULL; | ||
720 | char *tmp; | ||
721 | char buf_cpy[count]; | ||
722 | const char delimiter[3] = {' ', '\n', '\0'}; | ||
723 | |||
724 | memcpy(buf_cpy, buf, count+1); | ||
725 | tmp = buf_cpy; | ||
726 | 720 | ||
727 | while (tmp[0]) { | 721 | ret = amdgpu_read_mask(buf, count, &mask); |
728 | sub_str = strsep(&tmp, delimiter); | 722 | if (ret) |
729 | if (strlen(sub_str)) { | 723 | return ret; |
730 | ret = kstrtol(sub_str, 0, &level); | ||
731 | 724 | ||
732 | if (ret) { | ||
733 | count = -EINVAL; | ||
734 | goto fail; | ||
735 | } | ||
736 | mask |= 1 << level; | ||
737 | } else | ||
738 | break; | ||
739 | } | ||
740 | if (adev->powerplay.pp_funcs->force_clock_level) | 725 | if (adev->powerplay.pp_funcs->force_clock_level) |
741 | amdgpu_dpm_force_clock_level(adev, PP_PCIE, mask); | 726 | amdgpu_dpm_force_clock_level(adev, PP_PCIE, mask); |
742 | 727 | ||
743 | fail: | ||
744 | return count; | 728 | return count; |
745 | } | 729 | } |
746 | 730 | ||