On 06.03.2025 09:39, Penny Zheng wrote:
> Make `xenpm get-cpureq-para/set-cpufreq-para` available in CPPC mode.
> --- a/tools/libs/ctrl/xc_pm.c
> +++ b/tools/libs/ctrl/xc_pm.c
> @@ -214,13 +214,12 @@ int xc_get_cpufreq_para(xc_interface *xch, int cpuid,
>                        user_para->gov_num * CPUFREQ_NAME_LEN * sizeof(char), 
> XC_HYPERCALL_BUFFER_BOUNCE_BOTH);
>  
>      bool has_num = user_para->cpu_num &&
> -                     user_para->freq_num &&
>                       user_para->gov_num;
>  
>      if ( has_num )

Something looks wrong here already before your patch: With how has_num is set
and with this conditional, ...

>      {
>          if ( (!user_para->affected_cpus)                    ||
> -             (!user_para->scaling_available_frequencies)    ||
> +             (user_para->freq_num && 
> !user_para->scaling_available_frequencies)    ||
>               (user_para->gov_num && !user_para->scaling_available_governors) 
> )

... this ->gov_num check, ...

>          {
>              errno = EINVAL;
> @@ -228,14 +227,16 @@ int xc_get_cpufreq_para(xc_interface *xch, int cpuid,
>          }
>          if ( xc_hypercall_bounce_pre(xch, affected_cpus) )
>              goto unlock_1;
> -        if ( xc_hypercall_bounce_pre(xch, scaling_available_frequencies) )
> +        if ( user_para->freq_num &&
> +             xc_hypercall_bounce_pre(xch, scaling_available_frequencies) )
>              goto unlock_2;
>          if ( user_para->gov_num &&

... this one, and ...

>               xc_hypercall_bounce_pre(xch, scaling_available_governors) )
>              goto unlock_3;
>  
>          set_xen_guest_handle(sys_para->affected_cpus, affected_cpus);
> -        set_xen_guest_handle(sys_para->scaling_available_frequencies, 
> scaling_available_frequencies);
> +        if ( user_para->freq_num )
> +            set_xen_guest_handle(sys_para->scaling_available_frequencies, 
> scaling_available_frequencies);

(Nit: Yet another overly long line. It was too long already before, yes, but
 that's no excuse to make it even longer.  The more that there is better
 formatting right in context below.)

>          if ( user_para->gov_num )

... this one are all dead code. Jason? I expect the has_num variable simply
wants dropping altogether, thus correcting the earlier anomaly and getting
the intended new behavior at the same time.

>              set_xen_guest_handle(sys_para->scaling_available_governors,
>                                   scaling_available_governors);

This is the piece of context I'm referring to in the nit above.

> @@ -301,7 +302,8 @@ unlock_4:
>      if ( user_para->gov_num )
>          xc_hypercall_bounce_post(xch, scaling_available_governors);
>  unlock_3:
> -    xc_hypercall_bounce_post(xch, scaling_available_frequencies);
> +    if ( user_para->freq_num )
> +        xc_hypercall_bounce_post(xch, scaling_available_frequencies);
>  unlock_2:
>      xc_hypercall_bounce_post(xch, affected_cpus);
>  unlock_1:

I'm also puzzled by the function's inconsistent return value - Anthony,
can you explain / spot why things are the way they are?

> --- a/tools/misc/xenpm.c
> +++ b/tools/misc/xenpm.c
> @@ -539,7 +539,7 @@ static void signal_int_handler(int signo)
>                          res / 1000000UL, 100UL * res / (double)sum_px[i]);
>              }
>          }
> -        if ( px_cap && avgfreq[i] )
> +        if ( avgfreq[i] )
>              printf("  Avg freq\t%d\tKHz\n", avgfreq[i]);
>      }

I wonder whether this shouldn't be an independent change (which then
could go in rather sooner).

> @@ -926,7 +926,8 @@ static int show_cpufreq_para_by_cpuid(xc_interface 
> *xc_handle, int cpuid)
>              ret = -ENOMEM;
>              goto out;
>          }
> -        if (!(p_cpufreq->scaling_available_frequencies =
> +        if (p_cpufreq->freq_num &&
> +            !(p_cpufreq->scaling_available_frequencies =
>                malloc(p_cpufreq->freq_num * sizeof(uint32_t))))
>          {
>              fprintf(stderr,

Can someone explain to me how the pre-existing logic here works? All
three ->*_num start out as zero. Hence respective allocations (of zero
size) may conceivably return NULL (the behavior there is implementation
defined after all). Yet then we'd bail from the loop, and hence from the
function. IOW adding a ->freq_num check and also a ->cpu_num one (along
with the ->gov_num one that apparently was added during HWP development)
would once again look like an independent (latent) bugfix to me.

> --- a/xen/drivers/acpi/pmstat.c
> +++ b/xen/drivers/acpi/pmstat.c
> @@ -202,7 +202,7 @@ static int get_cpufreq_para(struct xen_sysctl_pm_op *op)
>      pmpt = processor_pminfo[op->cpuid];
>      policy = per_cpu(cpufreq_cpu_policy, op->cpuid);
>  
> -    if ( !pmpt || !pmpt->perf.states ||
> +    if ( !pmpt || ((pmpt->init & XEN_PX_INIT) && !pmpt->perf.states) ||
>           !policy || !policy->governor )
>          return -EINVAL;

Wouldn't this change better belong in the earlier patch, where the code
in context of the last hunk below was adjusted?

> @@ -229,17 +229,20 @@ static int get_cpufreq_para(struct xen_sysctl_pm_op *op)
>      if ( ret )
>          return ret;
>  
> -    if ( !(scaling_available_frequencies =
> -           xzalloc_array(uint32_t, op->u.get_para.freq_num)) )
> -        return -ENOMEM;
> -    for ( i = 0; i < op->u.get_para.freq_num; i++ )
> -        scaling_available_frequencies[i] =
> -                        pmpt->perf.states[i].core_frequency * 1000;
> -    ret = copy_to_guest(op->u.get_para.scaling_available_frequencies,
> -                   scaling_available_frequencies, op->u.get_para.freq_num);
> -    xfree(scaling_available_frequencies);
> -    if ( ret )
> -        return ret;
> +    if ( op->u.get_para.freq_num )
> +    {
> +        if ( !(scaling_available_frequencies =
> +               xzalloc_array(uint32_t, op->u.get_para.freq_num)) )
> +            return -ENOMEM;
> +        for ( i = 0; i < op->u.get_para.freq_num; i++ )
> +            scaling_available_frequencies[i] =
> +                            pmpt->perf.states[i].core_frequency * 1000;

Nit: Indentation was bogus here and ...

> +        ret = copy_to_guest(op->u.get_para.scaling_available_frequencies,
> +                    scaling_available_frequencies, op->u.get_para.freq_num);

... here before, and sadly continues to be bogus now.

> +        xfree(scaling_available_frequencies);
> +        if ( ret )
> +            return ret;
> +    }

While (beyond the nit above) I'm okay with this simple change, I think the
code here would benefit from folding the two allocations into one. There
simply is no reason to pay the price of the allocation overhead twice, when
we need a uint32_t[max(.cpu_num, .freq_num)] array anyway. That way the
churn introduced here would then also be smaller.

> @@ -465,7 +468,8 @@ int do_pm_op(struct xen_sysctl_pm_op *op)
>      switch ( op->cmd & PM_PARA_CATEGORY_MASK )
>      {
>      case CPUFREQ_PARA:
> -        if ( !(xen_processor_pmbits & XEN_PROCESSOR_PM_PX) )
> +        if ( !(xen_processor_pmbits & (XEN_PROCESSOR_PM_PX |
> +                                       XEN_PROCESSOR_PM_CPPC)) )
>              return -ENODEV;
>          if ( !pmpt || !(pmpt->init & (XEN_PX_INIT | XEN_CPPC_INIT)) )
>              return -EINVAL;

(This is the hunk I'm referring to further up.)

Jan

Reply via email to