Re: [RFC 2/2] platform/x86/amd: pmf: Add manual control support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, 19 Dec 2024 at 15:50, Mario Limonciello <superm1@xxxxxxxxxx> wrote:
>
> On 12/19/2024 07:12, Antheas Kapenekakis wrote:
> > Hi Mario,
> > given that there is a Legion Go driver in the works, and Asus already
> > has a driver, the only thing that would be left for locking down ACPI
> > access is manufacturers w/o vendor APIs.
> >
> > So, can we restart the conversation about this driver? It would be
> > nice to get to a place where we can lock down /dev/mem and ACPI by
> > spring.
>
> As Shyam mentioned we don't have control for limits by the PMF driver
> for this on PMF v2 (Strix) or later platforms.
>
> So if we were to revive this custom discussion it would only be for
> Phoenix and Hawk Point platforms.

That's unfortunate.

> >
> > Moreover, since the other two proposed drivers use the
> > firmware_attributes API, should this be used here as well?
>
> I do feel that if we revive this conversation specifically for Phoenix
> and Hawk Point platforms yes we should use the same API to expose it to
> userspace as those other two drivers do.
>
> I'd like Shyam's temperature on this idea though before anyone spends
> time on it.  If he's amenable would you want to work on it?

We currently expect the 2025 lineup to include a lot of Strix Point
handhelds, so I'd like a solution that works with that. OneXPlayer
released a model already, and GPD is getting ready to ship as well.

Yeah, I could throw some hours to it after I go through some overdue stuff.

> >
> > By the way, you were right about needing a taint for this. Strix Point
> > fails to enter a lower power state during sleep if you set it to lower
> > than 10W. This is not ideal, as hawk point could go down to 5 while
> > still showing a power difference, but I am unsure where this bug
> > should be reported. This is both through ryzenadj/ALIB
>
> Who is to say this is a bug?  Abusing a debugging interface with a
> reverse engineered tool means you might be able to configure a platform
> out of specifications.

The spec being 10+W would be very undesirable for handhelds with Strix
Point, so I'd hope somebody looks into it, esp. if it can be fixed
with a BIOS fw update before more handhelds come out. I can raise the
minimum TDP to 10W, with some user complaints.

Asus and Lenovo use the same mailbox so they'd share the issue too.

FYI for a typical handheld with e.g., a 60Wh battery, a 10W envelope
results in around 20-22W total consumption which is around 2.5 hours.
Hawk Point can be TDP limited down to 16W total consumption (TDP ~7W)
and can go down to 8W with frame limiting etc. I do not have numbers
for Strix Point yet, but to match Hawk Point it has to allow TDP to go
down to 7W. I think for 2025, customer expectation will be 6-8 hours+
at low wattages.

Antheas

> >
> > Antheas
> >
> > On Thu, 26 Sept 2024 at 05:00, Mario Limonciello <superm1@xxxxxxxxxx> wrote:
> >>
> >> From: Mario Limonciello <mario.limonciello@xxxxxxx>
> >>
> >> A number of users resort to using reverse engineered software like
> >> ryzenadj to manipulate debugging interfaces for modifying APU settings.
> >>
> >> At a glance these tools are useful, but the problem is they break
> >> state machines in other software such as the PMF driver or the OEM
> >> EC.
> >>
> >> Offer a knob for PMF to allow 'manual control' which will users can
> >> directly change things like fPPT and sPPT. As this can be harmful for
> >> a system to try to push limits outside of a thermal design, taint the
> >> kernel and show a critical message when in use.
> >>
> >> Signed-off-by: Mario Limonciello <mario.limonciello@xxxxxxx>
> >> ---
> >>   Documentation/ABI/testing/sysfs-amd-pmf | 10 +++
> >>   drivers/platform/x86/amd/pmf/Makefile   |  1 +
> >>   drivers/platform/x86/amd/pmf/core.c     |  9 +++
> >>   drivers/platform/x86/amd/pmf/manual.c   | 88 +++++++++++++++++++++++++
> >>   drivers/platform/x86/amd/pmf/pmf.h      |  5 ++
> >>   drivers/platform/x86/amd/pmf/sps.c      |  4 ++
> >>   6 files changed, 117 insertions(+)
> >>   create mode 100644 drivers/platform/x86/amd/pmf/manual.c
> >>
> >> diff --git a/Documentation/ABI/testing/sysfs-amd-pmf b/Documentation/ABI/testing/sysfs-amd-pmf
> >> index 7fc0e1c2b76b..6f3d5cbf443f 100644
> >> --- a/Documentation/ABI/testing/sysfs-amd-pmf
> >> +++ b/Documentation/ABI/testing/sysfs-amd-pmf
> >> @@ -11,3 +11,13 @@ Description: Reading this file tells if the AMD Platform Management(PMF)
> >>                  To turn off CnQF user can write "off" to the sysfs node.
> >>                  Note: Systems that support auto mode will not have this sysfs file
> >>                  available.
> >> +
> >> +What:          /sys/devices/platform/*/{spl, fppt, sppt, sppt_apu_only, stt_min, stt_limit_apu, stt_skip_temp}
> >> +Date:          December 2024
> >> +Contact:       Mario Limonciello <mario.limonciello@xxxxxxx>
> >> +Description:   Manual control of AMD PMF APU coefficients
> >> +               .
> >> +               These files are used to manually control the APU coefficients.
> >> +               In order to write to these files the module most be
> >> +               loaded with manual_control=1 and the user must write "custom"
> >> +               to the ACPI platform profile.
> >> diff --git a/drivers/platform/x86/amd/pmf/Makefile b/drivers/platform/x86/amd/pmf/Makefile
> >> index 7d6079b02589..81444d6f4428 100644
> >> --- a/drivers/platform/x86/amd/pmf/Makefile
> >> +++ b/drivers/platform/x86/amd/pmf/Makefile
> >> @@ -7,4 +7,5 @@
> >>   obj-$(CONFIG_AMD_PMF) += amd-pmf.o
> >>   amd-pmf-objs := core.o acpi.o sps.o \
> >>                  auto-mode.o cnqf.o \
> >> +               manual.o \
> >>                  tee-if.o spc.o pmf-quirks.o
> >> diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c
> >> index d6af0ca036f1..52a68ca094be 100644
> >> --- a/drivers/platform/x86/amd/pmf/core.c
> >> +++ b/drivers/platform/x86/amd/pmf/core.c
> >> @@ -53,6 +53,10 @@ static bool force_load;
> >>   module_param(force_load, bool, 0444);
> >>   MODULE_PARM_DESC(force_load, "Force load this driver on supported older platforms (experimental)");
> >>
> >> +bool pmf_manual_control;
> >> +module_param_named(manual_control, pmf_manual_control, bool, 0444);
> >> +MODULE_PARM_DESC(manual_control, "Expose manual control knobs (experimental)");
> >> +
> >>   static int amd_pmf_pwr_src_notify_call(struct notifier_block *nb, unsigned long event, void *data)
> >>   {
> >>          struct amd_pmf_dev *pmf = container_of(nb, struct amd_pmf_dev, pwr_src_notifier);
> >> @@ -349,6 +353,10 @@ static void amd_pmf_init_features(struct amd_pmf_dev *dev)
> >>                  dev_dbg(dev->dev, "SPS enabled and Platform Profiles registered\n");
> >>          }
> >>
> >> +       if (pmf_manual_control) {
> >> +               amd_pmf_init_manual_control(dev);
> >> +               return;
> >> +       }
> >>          amd_pmf_init_smart_pc(dev);
> >>          if (dev->smart_pc_enabled) {
> >>                  dev_dbg(dev->dev, "Smart PC Solution Enabled\n");
> >> @@ -485,6 +493,7 @@ static void amd_pmf_remove(struct platform_device *pdev)
> >>
> >>   static const struct attribute_group *amd_pmf_driver_groups[] = {
> >>          &cnqf_feature_attribute_group,
> >> +       &manual_attribute_group,
> >>          NULL,
> >>   };
> >>
> >> diff --git a/drivers/platform/x86/amd/pmf/manual.c b/drivers/platform/x86/amd/pmf/manual.c
> >> new file mode 100644
> >> index 000000000000..b33fc3cd8d61
> >> --- /dev/null
> >> +++ b/drivers/platform/x86/amd/pmf/manual.c
> >> @@ -0,0 +1,88 @@
> >> +// SPDX-License-Identifier: GPL-2.0-or-later
> >> +/*
> >> + * AMD Platform Management Framework Driver
> >> + *
> >> + * Copyright (c) 2024, Advanced Micro Devices, Inc.
> >> + * All Rights Reserved.
> >> + *
> >> + * Author: Mario Limonciello <mario.limonciello@xxxxxxx>
> >> + */
> >> +
> >> +#include "pmf.h"
> >> +
> >> +#define pmf_manual_attribute(_name, _set_command, _get_command)                \
> >> +static ssize_t _name##_store(struct device *d,                         \
> >> +                            struct device_attribute *attr,             \
> >> +                            const char *buf, size_t count)             \
> >> +{                                                                      \
> >> +       struct amd_pmf_dev *dev = dev_get_drvdata(d);                   \
> >> +       uint val;                                                       \
> >> +                                                                       \
> >> +       if (dev->current_profile != PLATFORM_PROFILE_CUSTOM) {          \
> >> +               dev_warn_once(dev->dev,                                 \
> >> +                             "Manual control is disabled, please set " \
> >> +                             "platform profile to custom.\n");         \
> >> +               return -EINVAL;                                         \
> >> +       }                                                               \
> >> +                                                                       \
> >> +       if (kstrtouint(buf, 10, &val) < 0)                              \
> >> +               return -EINVAL;                                         \
> >> +                                                                       \
> >> +       amd_pmf_send_cmd(dev, _set_command, false, val, NULL);          \
> >> +                                                                       \
> >> +       return count;                                                   \
> >> +}                                                                      \
> >> +static ssize_t _name##_show(struct device *d,                          \
> >> +                          struct device_attribute *attr,               \
> >> +                          char *buf)                                   \
> >> +{                                                                      \
> >> +       struct amd_pmf_dev *dev = dev_get_drvdata(d);                   \
> >> +       uint val;                                                       \
> >> +                                                                       \
> >> +       amd_pmf_send_cmd(dev, _get_command, true, ARG_NONE, &val);      \
> >> +                                                                       \
> >> +       return sysfs_emit(buf, "%u\n", val);                            \
> >> +}
> >> +
> >> +pmf_manual_attribute(spl, SET_SPL, GET_SPL);
> >> +static DEVICE_ATTR_RW(spl);
> >> +pmf_manual_attribute(fppt, SET_FPPT, GET_FPPT);
> >> +static DEVICE_ATTR_RW(fppt);
> >> +pmf_manual_attribute(sppt, SET_SPPT, GET_SPPT);
> >> +static DEVICE_ATTR_RW(sppt);
> >> +pmf_manual_attribute(sppt_apu_only, SET_SPPT_APU_ONLY, GET_SPPT_APU_ONLY);
> >> +static DEVICE_ATTR_RW(sppt_apu_only);
> >> +pmf_manual_attribute(stt_min, SET_STT_MIN_LIMIT, GET_STT_MIN_LIMIT);
> >> +static DEVICE_ATTR_RW(stt_min);
> >> +pmf_manual_attribute(stt_limit_apu, SET_STT_LIMIT_APU, GET_STT_LIMIT_APU);
> >> +static DEVICE_ATTR_RW(stt_limit_apu);
> >> +pmf_manual_attribute(stt_skin_temp, SET_STT_LIMIT_HS2, GET_STT_LIMIT_HS2);
> >> +static DEVICE_ATTR_RW(stt_skin_temp);
> >> +
> >> +static umode_t manual_attr_is_visible(struct kobject *kobj, struct attribute *attr, int idx)
> >> +{
> >> +       return pmf_manual_control ? 0660 : 0;
> >> +}
> >> +
> >> +static struct attribute *manual_attrs[] = {
> >> +       &dev_attr_spl.attr,
> >> +       &dev_attr_fppt.attr,
> >> +       &dev_attr_sppt.attr,
> >> +       &dev_attr_sppt_apu_only.attr,
> >> +       &dev_attr_stt_min.attr,
> >> +       &dev_attr_stt_limit_apu.attr,
> >> +       &dev_attr_stt_skin_temp.attr,
> >> +       NULL,
> >> +};
> >> +
> >> +const struct attribute_group manual_attribute_group = {
> >> +       .attrs = manual_attrs,
> >> +       .is_visible = manual_attr_is_visible,
> >> +};
> >> +
> >> +void amd_pmf_init_manual_control(struct amd_pmf_dev *dev)
> >> +{
> >> +       add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
> >> +       pr_crit("Manual PMF control is enabled, please disable it before "
> >> +               "reporting any bugs unrelated to PMF.\n");
> >> +}
> >> diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h
> >> index 8ce8816da9c1..ca3df63cf190 100644
> >> --- a/drivers/platform/x86/amd/pmf/pmf.h
> >> +++ b/drivers/platform/x86/amd/pmf/pmf.h
> >> @@ -798,4 +798,9 @@ void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *
> >>   /* Quirk infrastructure */
> >>   void amd_pmf_quirks_init(struct amd_pmf_dev *dev);
> >>
> >> +/* Manual configuration */
> >> +extern bool pmf_manual_control;
> >> +extern const struct attribute_group manual_attribute_group;
> >> +void amd_pmf_init_manual_control(struct amd_pmf_dev *dev);
> >> +
> >>   #endif /* PMF_H */
> >> diff --git a/drivers/platform/x86/amd/pmf/sps.c b/drivers/platform/x86/amd/pmf/sps.c
> >> index 92f7fb22277d..6db88e523a86 100644
> >> --- a/drivers/platform/x86/amd/pmf/sps.c
> >> +++ b/drivers/platform/x86/amd/pmf/sps.c
> >> @@ -305,6 +305,8 @@ int amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf)
> >>          case PLATFORM_PROFILE_LOW_POWER:
> >>                  mode = POWER_MODE_POWER_SAVER;
> >>                  break;
> >> +       case PLATFORM_PROFILE_CUSTOM:
> >> +               return 0;
> >>          default:
> >>                  dev_err(pmf->dev, "Unknown Platform Profile.\n");
> >>                  return -EOPNOTSUPP;
> >> @@ -412,6 +414,8 @@ int amd_pmf_init_sps(struct amd_pmf_dev *dev)
> >>          set_bit(PLATFORM_PROFILE_LOW_POWER, dev->pprof.choices);
> >>          set_bit(PLATFORM_PROFILE_BALANCED, dev->pprof.choices);
> >>          set_bit(PLATFORM_PROFILE_PERFORMANCE, dev->pprof.choices);
> >> +       if (pmf_manual_control)
> >> +               set_bit(PLATFORM_PROFILE_CUSTOM, dev->pprof.choices);
> >>
> >>          /* Create platform_profile structure and register */
> >>          err = platform_profile_register(&dev->pprof);
> >> --
> >> 2.43.0
> >>
>




[Index of Archives]     [Linux Kernel Development]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux