On Wed, Mar 22, 2023 at 12:13 PM Roger Pau Monne <roger.pau@xxxxxxxxxx> wrote: > > In ACPI systems, the OS can direct power management, as opposed to the > firmware. This OS-directed Power Management is called OSPM. Part of > telling the firmware that the OS going to direct power management is > making ACPI "_PDC" (Processor Driver Capabilities) calls. These _PDC > methods must be evaluated for every processor object. If these _PDC > calls are not completed for every processor it can lead to > inconsistency and later failures in things like the CPU frequency > driver. > > In a Xen system, the dom0 kernel is responsible for system-wide power > management. The dom0 kernel is in charge of OSPM. However, the > number of CPUs available to dom0 can be different than the number of > CPUs physically present on the system. > > This leads to a problem: the dom0 kernel needs to evaluate _PDC for > all the processors, but it can't always see them. > > In dom0 kernels, ignore the existing ACPI method for determining if a > processor is physically present because it might not be accurate. > Instead, ask the hypervisor for this information. > > Fix this by introducing a custom function to use when running as Xen > dom0 in order to check whether a processor object matches a CPU that's > online. Such checking is done using the existing information fetched > by the Xen pCPU subsystem, extending it to also store the ACPI ID. > > This ensures that _PDC method gets evaluated for all physically online > CPUs, regardless of the number of CPUs made available to dom0. > > Fixes: 5d554a7bb064 ('ACPI: processor: add internal processor_physically_present()') > Signed-off-by: Roger Pau Monné <roger.pau@xxxxxxxxxx> > --- > Changes since v5: > - Include bug.h header for the inline dummy helper. > - Constify pcpu local variable in xen_processor_present(). > > Changes since v4: > - Move definition/declaration of xen_processor_present() to different > header. > - Fold subject edit. > > Changes since v3: > - Protect xen_processor_present() definition with CONFIG_ACPI. > > Changes since v2: > - Extend and use the existing pcpu functionality. > > Changes since v1: > - Reword commit message. > --- > drivers/acpi/processor_pdc.c | 11 +++++++++++ > drivers/xen/pcpu.c | 20 ++++++++++++++++++++ > include/xen/xen.h | 11 +++++++++++ > 3 files changed, 42 insertions(+) > > diff --git a/drivers/acpi/processor_pdc.c b/drivers/acpi/processor_pdc.c > index 8c3f82c9fff3..18fb04523f93 100644 > --- a/drivers/acpi/processor_pdc.c > +++ b/drivers/acpi/processor_pdc.c > @@ -14,6 +14,8 @@ > #include <linux/acpi.h> > #include <acpi/processor.h> > > +#include <xen/xen.h> > + > #include "internal.h" > > static bool __init processor_physically_present(acpi_handle handle) > @@ -47,6 +49,15 @@ static bool __init processor_physically_present(acpi_handle handle) > return false; > } > > + if (xen_initial_domain()) > + /* > + * When running as a Xen dom0 the number of processors Linux > + * sees can be different from the real number of processors on > + * the system, and we still need to execute _PDC for all of > + * them. > + */ > + return xen_processor_present(acpi_id); > + > type = (acpi_type == ACPI_TYPE_DEVICE) ? 1 : 0; > cpuid = acpi_get_cpuid(handle, type, acpi_id); > > diff --git a/drivers/xen/pcpu.c b/drivers/xen/pcpu.c > index fd3a644b0855..b3e3d1bb37f3 100644 > --- a/drivers/xen/pcpu.c > +++ b/drivers/xen/pcpu.c > @@ -58,6 +58,7 @@ struct pcpu { > struct list_head list; > struct device dev; > uint32_t cpu_id; > + uint32_t acpi_id; > uint32_t flags; > }; > > @@ -249,6 +250,7 @@ static struct pcpu *create_and_register_pcpu(struct xenpf_pcpuinfo *info) > > INIT_LIST_HEAD(&pcpu->list); > pcpu->cpu_id = info->xen_cpuid; > + pcpu->acpi_id = info->acpi_id; > pcpu->flags = info->flags; > > /* Need hold on xen_pcpu_lock before pcpu list manipulations */ > @@ -381,3 +383,21 @@ static int __init xen_pcpu_init(void) > return ret; > } > arch_initcall(xen_pcpu_init); > + > +#ifdef CONFIG_ACPI > +bool __init xen_processor_present(uint32_t acpi_id) > +{ > + const struct pcpu *pcpu; > + bool online = false; > + > + mutex_lock(&xen_pcpu_lock); > + list_for_each_entry(pcpu, &xen_pcpus, list) > + if (pcpu->acpi_id == acpi_id) { > + online = pcpu->flags & XEN_PCPU_FLAGS_ONLINE; > + break; > + } > + mutex_unlock(&xen_pcpu_lock); > + > + return online; > +} > +#endif > diff --git a/include/xen/xen.h b/include/xen/xen.h > index 7adf59837c25..0efeb652f9b8 100644 > --- a/include/xen/xen.h > +++ b/include/xen/xen.h > @@ -71,4 +71,15 @@ static inline void xen_free_unpopulated_pages(unsigned int nr_pages, > } > #endif > > +#if defined(CONFIG_XEN_DOM0) && defined(CONFIG_ACPI) && defined(CONFIG_X86) > +bool __init xen_processor_present(uint32_t acpi_id); > +#else > +#include <linux/bug.h> > +static inline bool xen_processor_present(uint32_t acpi_id) > +{ > + BUG(); > + return false; > +} > +#endif > + > #endif /* _XEN_XEN_H */ > -- Applied as 6.4 material. I've added the R-by from Juergen to it, because the difference between it and the v4 for which the tag was provided is merely a build fix.