|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v6 10/19] xen/cpufreq: introduce new sub-hypercall to propagate CPPC data
On 11.07.2025 05:50, Penny Zheng wrote:
> --- a/xen/drivers/acpi/pm-op.c
> +++ b/xen/drivers/acpi/pm-op.c
> @@ -91,7 +91,8 @@ 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) ||
> + ((pmpt->init & XEN_CPPC_INIT) && pmpt->perf.state_count) ||
Nit: I think this would be neater if the PX_INIT part was also moved to its own
line.
> @@ -697,6 +703,122 @@ int acpi_set_pdc_bits(unsigned int acpi_id,
> XEN_GUEST_HANDLE(uint32) pdc)
> return ret;
> }
>
> +static void print_CPPC(const struct xen_processor_cppc *cppc_data)
> +{
> + printk("\t_CPC: highest_perf=%u, lowest_perf=%u, "
> + "nominal_perf=%u, lowest_nonlinear_perf=%u, "
> + "nominal_mhz=%uMHz, lowest_mhz=%uMHz\n",
> + cppc_data->cpc.highest_perf, cppc_data->cpc.lowest_perf,
> + cppc_data->cpc.nominal_perf, cppc_data->cpc.lowest_nonlinear_perf,
> + cppc_data->cpc.nominal_mhz, cppc_data->cpc.lowest_mhz);
> +}
> +
> +int set_cppc_pminfo(unsigned int acpi_id,
> + const struct xen_processor_cppc *cppc_data)
> +{
> + int ret = 0, cpuid;
> + struct processor_pminfo *pm_info;
> +
> + cpuid = get_cpu_id(acpi_id);
> + if ( cpuid < 0 )
> + {
> + ret = -EINVAL;
> + goto out;
> + }
> +
> + if ( cppc_data->pad[0] || cppc_data->pad[1] || cppc_data->pad[2] )
> + {
> + ret = -EINVAL;
> + goto out;
> + }
> +
> + if ( cpufreq_verbose )
> + printk("Set CPU acpi_id(%u) cpuid(%d) CPPC State info:\n",
May I suggest "Set CPU%d (ACPI ID %u) CPPC state info:\n"
> + acpi_id, cpuid);
> +
> + pm_info = processor_pminfo[cpuid];
> + if ( !pm_info )
> + {
> + pm_info = xvzalloc(struct processor_pminfo);
> + if ( !pm_info )
> + {
> + ret = -ENOMEM;
> + goto out;
> + }
> + processor_pminfo[cpuid] = pm_info;
> + }
> + pm_info->acpi_id = acpi_id;
> + pm_info->id = cpuid;
> + pm_info->cppc_data = *cppc_data;
> +
> + if ( cppc_data->flags & XEN_CPPC_PSD )
> + if ( !check_psd_pminfo(cppc_data->shared_type) )
Please convert these into a single if().
> + {
> + ret = -EINVAL;
> + goto out;
> + }
> +
> + if ( cppc_data->flags & XEN_CPPC_CPC )
> + {
> + if ( cppc_data->cpc.highest_perf == 0 ||
> + cppc_data->cpc.highest_perf > UINT8_MAX ||
> + cppc_data->cpc.nominal_perf == 0 ||
> + cppc_data->cpc.nominal_perf > UINT8_MAX ||
> + cppc_data->cpc.lowest_nonlinear_perf == 0 ||
> + cppc_data->cpc.lowest_nonlinear_perf > UINT8_MAX ||
> + cppc_data->cpc.lowest_perf == 0 ||
> + cppc_data->cpc.lowest_perf > UINT8_MAX ||
> + cppc_data->cpc.lowest_perf >
> + cppc_data->cpc.lowest_nonlinear_perf ||
> + cppc_data->cpc.lowest_nonlinear_perf >
> + cppc_data->cpc.nominal_perf ||
Indentation is a little odd here. Best may be to use parentheses:
cppc_data->cpc.lowest_perf > UINT8_MAX ||
(cppc_data->cpc.lowest_perf >
cppc_data->cpc.lowest_nonlinear_perf) ||
(cppc_data->cpc.lowest_nonlinear_perf >
cppc_data->cpc.nominal_perf) ||
Otherwise, strictly speaking, no extra indentation should be used. I can see
though that this would hamper readability, so the next best alternative would
appear to be to make the extra indentation a proper level (i.e. 4 blanks):
cppc_data->cpc.lowest_perf > UINT8_MAX ||
cppc_data->cpc.lowest_perf >
cppc_data->cpc.lowest_nonlinear_perf ||
cppc_data->cpc.lowest_nonlinear_perf >
cppc_data->cpc.nominal_perf ||
> + cppc_data->cpc.nominal_perf > cppc_data->cpc.highest_perf )
> + /*
> + * Right now, Xen doesn't actually use highest_perf/nominal_perf/
> + * lowest_nonlinear_perf/lowest_perf values read from ACPI _CPC
> + * table. Xen reads CPPC capability MSR to get these four values.
> + * So warning is enough.
> + */
> + printk_once(XENLOG_WARNING
> + "Broken CPPC perf values: lowest(%u),
> nonlinear_lowest(%u), nominal(%u), highest(%u)\n",
> + cppc_data->cpc.lowest_perf,
> + cppc_data->cpc.lowest_nonlinear_perf,
> + cppc_data->cpc.nominal_perf,
> + cppc_data->cpc.highest_perf);
> +
> + /* lowest_mhz and nominal_mhz are optional value */
> + if ( cppc_data->cpc.lowest_mhz > cppc_data->cpc.nominal_mhz )
If they're optional, what if lowest_mhz is provided but nominal_mhz isn't?
Wouldn't the warning needlessly trigger in that case?
> + {
> + printk_once(XENLOG_WARNING
> + "Broken CPPC freq values: lowest(%u), nominal(%u)\n",
> + cppc_data->cpc.lowest_mhz,
> + cppc_data->cpc.nominal_mhz);
> + /* Re-set with zero values, instead of keeping invalid values */
> + pm_info->cppc_data.cpc.nominal_mhz = 0;
> + pm_info->cppc_data.cpc.lowest_mhz = 0;
> + }
> + }
> +
> + if ( cppc_data->flags == (XEN_CPPC_PSD | XEN_CPPC_CPC) )
> + {
> + if ( cpufreq_verbose )
> + {
> + print_PSD(&pm_info->cppc_data.domain_info);
> + print_CPPC(&pm_info->cppc_data);
> + }
> +
> + pm_info->init = XEN_CPPC_INIT;
> + ret = cpufreq_cpu_init(cpuid);
> + if ( ret )
> + printk_once(XENLOG_WARNING
> + "CPU%u failed amd-cppc mode init; use
> \"cpufreq=xen\" instead",
> + cpuid);
cpuid is still int, so wants printing with %d.
> --- a/xen/include/public/platform.h
> +++ b/xen/include/public/platform.h
> @@ -363,6 +363,7 @@ DEFINE_XEN_GUEST_HANDLE(xenpf_getidletime_t);
> #define XEN_PM_PX 1
> #define XEN_PM_TX 2
> #define XEN_PM_PDC 3
> +#define XEN_PM_CPPC 4
>
> /* Px sub info type */
> #define XEN_PX_PCT 1
> @@ -370,6 +371,10 @@ DEFINE_XEN_GUEST_HANDLE(xenpf_getidletime_t);
> #define XEN_PX_PPC 4
> #define XEN_PX_PSD 8
>
> +/* CPPC sub info type */
> +#define XEN_CPPC_PSD 1
> +#define XEN_CPPC_CPC 2
As per this, ...
> @@ -457,6 +462,26 @@ struct xen_processor_performance {
> typedef struct xen_processor_performance xen_processor_performance_t;
> DEFINE_XEN_GUEST_HANDLE(xen_processor_performance_t);
>
> +struct xen_processor_cppc {
> + uint8_t flags; /* IN: XEN_CPPC_xxx */
... it's a type that's living here, not a collection of flags. Any reason the
field isn't named "type"?
> + uint8_t pad[3];
> + /*
> + * IN: Subset _CPC fields useful for CPPC-compatible cpufreq
> + * driver's initialization
> + */
> + struct {
> + uint32_t highest_perf;
> + uint32_t nominal_perf;
> + uint32_t lowest_nonlinear_perf;
> + uint32_t lowest_perf;
> + uint32_t lowest_mhz;
> + uint32_t nominal_mhz;
> + } cpc;
What, again, was the reason to wrap these into a sub-struct?
Jan
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |