[AMD Official Use Only - AMD Internal Distribution Only]

Hi,

> -----Original Message-----
> From: Jan Beulich <jbeul...@suse.com>
> Sent: Thursday, January 9, 2025 6:55 PM
> To: Penny, Zheng <penny.zh...@amd.com>
> Cc: Stabellini, Stefano <stefano.stabell...@amd.com>; Huang, Ray
> <ray.hu...@amd.com>; Ragiadakou, Xenia <xenia.ragiada...@amd.com>;
> Andryuk, Jason <jason.andr...@amd.com>; Andrew Cooper
> <andrew.coop...@citrix.com>; Roger Pau Monné <roger....@citrix.com>; xen-
> de...@lists.xenproject.org
> Subject: Re: [PATCH v1 05/11] xen/x86: introduce a new amd pstate driver for
> cpufreq scaling
>
> On 03.12.2024 09:11, Penny Zheng wrote:
> > --- a/xen/arch/x86/acpi/cpufreq/amd-pstate.c
> > +++ b/xen/arch/x86/acpi/cpufreq/amd-pstate.c
> > @@ -15,6 +15,53 @@
> >  #include <xen/init.h>
> >  #include <xen/param.h>
> >  #include <acpi/cpufreq/cpufreq.h>
> > +#include <asm/msr.h>
> > +
> > +#define amd_pstate_err(cpu, fmt, args...) \
> > +    printk(XENLOG_ERR "AMD_PSTATE: CPU%u error: " fmt, cpu, ## args)
> > +#define amd_pstate_verbose(fmt, args...)                         \
> > +({                                                               \
> > +    if ( cpufreq_verbose )                                       \
> > +        printk(XENLOG_DEBUG "AMD_PSTATE: " fmt, ## args);        \
> > +})
> > +#define amd_pstate_warn(fmt, args...) \
> > +    printk(XENLOG_WARNING "AMD_PSTATE: CPU%u warning: " fmt, cpu,
> ##
> > +args)
> > +
> > +struct amd_pstate_drv_data
> > +{
> > +    struct xen_processor_cppc *cppc_data;
> > +    union
> > +    {
> > +        uint64_t amd_caps;
> > +        struct
> > +        {
> > +            unsigned int lowest_perf:8;
> > +            unsigned int lowest_nonlinear_perf:8;
> > +            unsigned int nominal_perf:8;
> > +            unsigned int highest_perf:8;
> > +            unsigned int :32;
> > +        } hw;
>
> Please can this be
>
>
>     union {
>         uint64_t raw;
>         struct {
>             unsigned int lowest_perf:8;
>             unsigned int lowest_nonlinear_perf:8;
>             unsigned int nominal_perf:8;
>             unsigned int highest_perf:8;
>             unsigned int :32;
>         };
>     } caps;
>
> such that at use sites (e.g. amd_pstate_write_request()) it is possible to 
> actually
> spot that the same thing is being accessed through the two parts of the union?
>

Understood.

> > +    {
> > +        /* Read Processor Max Speed(mhz) from DMI table as anchor point */
> > +        mul = dmi_max_speed_mhz;
> > +        div = data->hw.highest_perf;
> > +
> > +        return (unsigned int)(mul / div) * data->hw.lowest_perf *
> > + 1000;
>
> No risk of the cast chopping off set bits?

Mul shall be uint64_t, highest_perf and lowest_perf shall be uint8_t, and 
normally
the equation output shall not be a too big value...
If you think it's safer to do cast after comparing with the UINT32_MAX, I will 
add the check

>
> > +
> > +static int cf_check amd_pstate_cpufreq_verify(struct cpufreq_policy
> > +*policy) {
> > +    struct amd_pstate_drv_data *data = per_cpu(amd_pstate_drv_data,
> > +policy->cpu);
>
> Const? (I won't further repeat this. Please make pointers pointer-to- const
> wherever possible. We aim at having fully const-correct code.)
>

Sure.

> > +}
> > +
> > +static void cf_check amd_pstate_init_msrs(void *info) {
> > +    struct cpufreq_policy *policy = info;
> > +    struct amd_pstate_drv_data *data = this_cpu(amd_pstate_drv_data);
> > +    uint64_t val;
> > +    unsigned int min_freq, nominal_freq, max_freq;
> > +
> > +    /* Package level MSR */
> > +    if ( rdmsr_safe(MSR_AMD_CPPC_ENABLE, val) )
>
> Before trying this, wouldn't you better exclude certain very old families?
> Even looking at a random Fam17 PPR I can't spot documentation of this MSR
> (nor the other two), despite you merely saying Zen elsewhere (without any
> version number).
>

I shall comment more specifically, this feature is firstly introduced on some 
Zen2 serie, like Renoir
I'll exclude the families before Zen(Fam17h)

> > +    {
> > +        amd_pstate_err(policy->cpu,
> "rdmsr_safe(MSR_AMD_CPPC_ENABLE)\n");
> > +        data->err = -EINVAL;
> > +        return;
> > +    }
> > +
> > +    if ( !(val & AMD_CPPC_ENABLE) )
> > +    {
> > +        val |= AMD_CPPC_ENABLE;
> > +        if ( wrmsr_safe(MSR_AMD_CPPC_ENABLE, val) )
> > +        {
> > +            amd_pstate_err(policy->cpu,
> "wrmsr_safe(MSR_AMD_CPPC_ENABLE, %lx)\n", val);
> > +            data->err = -EINVAL;
> > +            return;
> > +        }
> > +    }
>
> Do you really need to enable befor reading ...
>
> > +    if ( rdmsr_safe(MSR_AMD_CPPC_CAP1, data->amd_caps) )
>
> ... capabilities and ...
>

Yes.
Only when CPPC is enabled, the hardware will calculate the processor’s 
performance capabilities and
initialize the performance level fields in the CPPC capability registers.
See 17.6.3 
https://www.amd.com/content/dam/amd/en/documents/processor-tech-docs/programmer-references/24593.pdf

> > +    {
> > +        amd_pstate_err(policy->cpu, "rdmsr_safe(MSR_AMD_CPPC_CAP1)\n");
> > +        goto error;
> > +    }
> > +
> > +    if ( data->hw.highest_perf == 0 || data->hw.lowest_perf == 0 ||
> > +         data->hw.nominal_perf == 0 || data->hw.lowest_nonlinear_perf == 0 
> > )
> > +    {
> > +        amd_pstate_err(policy->cpu, "Platform malfunction, read CPPC
> highest_perf: %u, lowest_perf: %u, nominal_perf: %u, lowest_nonlinear_perf: %u
> zero value\n",
> > +                       data->hw.highest_perf, data->hw.lowest_perf,
> > +                       data->hw.nominal_perf, 
> > data->hw.lowest_nonlinear_perf);
> > +        goto error;
> > +    }
> > +
> > +    min_freq = amd_get_min_freq(data);
> > +    nominal_freq = amd_get_nominal_freq(data);
> > +    max_freq = amd_get_max_freq(data);
> > +    if ( min_freq > max_freq )
> > +    {
> > +        amd_pstate_err(policy->cpu, "min_freq(%u) or max_freq(%u) value is
> incorrect\n",
> > +                       min_freq, max_freq);
> > +        goto error;
> > +    }
>
> ... checking them? Error handling would be easier if you enabled only 
> afterwards.
>
> > +    highest_perf = data->hw.highest_perf;
> > +    nominal_perf = data->hw.nominal_perf;
> > +
> > +    if ( highest_perf <= nominal_perf )
> > +        return;
> > +
> > +    policy->turbo = CPUFREQ_TURBO_ENABLED; }
>
> And why the helper variables in the first place?
>

Sorry, maybe a bit more specific, got confused about the question ;/

>
> Jan

Many thanks,
Penny

Reply via email to