The current logic in the Intel PMC driver will forcefully attach it when detecting any CPU on the intel_pmc_core_platform_ids array, even if the matching ACPI device is not present. There's no checking in pmc_core_probe() to assert that the PMC device is present, and hence on virtualized environments the PMC device probes successfully, even if the underlying registers are not present. Before commit21ae435709
("platform/x86: intel_pmc_core: Substitute PCI with CPUID enumeration") the driver would check for the presence of a specific PCI device, and that prevented the driver from attaching when running virtualized. Fix by only forcefully attaching the PMC device when not running virtualized. Note that virtualized platforms can still get the device to load if the appropriate ACPI device is present on the tables provided to the VM. Make an exception for the Xen initial domain, which does have full hardware access, and hence can attach to the PMC if present. Fixes:21ae435709
("platform/x86: intel_pmc_core: Substitute PCI with CPUID enumeration") Signed-off-by: Roger Pau Monné <roger.pau@citrix.com> Acked-by: David E. Box <david.e.box@linux.intel.com> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Link: https://lore.kernel.org/r/20221110163145.80374-1-roger.pau@citrix.com Reviewed-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
89 lines
2.7 KiB
C
89 lines
2.7 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
/*
|
|
* Intel PMC Core platform init
|
|
* Copyright (c) 2019, Google Inc.
|
|
* Author - Rajat Jain
|
|
*
|
|
* This code instantiates platform devices for intel_pmc_core driver, only
|
|
* on supported platforms that may not have the ACPI devices in the ACPI tables.
|
|
* No new platforms should be added here, because we expect that new platforms
|
|
* should all have the ACPI device, which is the preferred way of enumeration.
|
|
*/
|
|
|
|
#include <linux/acpi.h>
|
|
#include <linux/module.h>
|
|
#include <linux/platform_device.h>
|
|
|
|
#include <asm/cpu_device_id.h>
|
|
#include <asm/intel-family.h>
|
|
|
|
#include <xen/xen.h>
|
|
|
|
static void intel_pmc_core_release(struct device *dev)
|
|
{
|
|
kfree(dev);
|
|
}
|
|
|
|
static struct platform_device *pmc_core_device;
|
|
|
|
/*
|
|
* intel_pmc_core_platform_ids is the list of platforms where we want to
|
|
* instantiate the platform_device if not already instantiated. This is
|
|
* different than intel_pmc_core_ids in intel_pmc_core.c which is the
|
|
* list of platforms that the driver supports for pmc_core device. The
|
|
* other list may grow, but this list should not.
|
|
*/
|
|
static const struct x86_cpu_id intel_pmc_core_platform_ids[] = {
|
|
X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L, &pmc_core_device),
|
|
X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE, &pmc_core_device),
|
|
X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L, &pmc_core_device),
|
|
X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE, &pmc_core_device),
|
|
X86_MATCH_INTEL_FAM6_MODEL(CANNONLAKE_L, &pmc_core_device),
|
|
X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L, &pmc_core_device),
|
|
X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE, &pmc_core_device),
|
|
X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE_L, &pmc_core_device),
|
|
{}
|
|
};
|
|
MODULE_DEVICE_TABLE(x86cpu, intel_pmc_core_platform_ids);
|
|
|
|
static int __init pmc_core_platform_init(void)
|
|
{
|
|
int retval;
|
|
|
|
/* Skip creating the platform device if ACPI already has a device */
|
|
if (acpi_dev_present("INT33A1", NULL, -1))
|
|
return -ENODEV;
|
|
|
|
/*
|
|
* Skip forcefully attaching the device for VMs. Make an exception for
|
|
* Xen dom0, which does have full hardware access.
|
|
*/
|
|
if (cpu_feature_enabled(X86_FEATURE_HYPERVISOR) && !xen_initial_domain())
|
|
return -ENODEV;
|
|
|
|
if (!x86_match_cpu(intel_pmc_core_platform_ids))
|
|
return -ENODEV;
|
|
|
|
pmc_core_device = kzalloc(sizeof(*pmc_core_device), GFP_KERNEL);
|
|
if (!pmc_core_device)
|
|
return -ENOMEM;
|
|
|
|
pmc_core_device->name = "intel_pmc_core";
|
|
pmc_core_device->dev.release = intel_pmc_core_release;
|
|
|
|
retval = platform_device_register(pmc_core_device);
|
|
if (retval)
|
|
platform_device_put(pmc_core_device);
|
|
|
|
return retval;
|
|
}
|
|
|
|
static void __exit pmc_core_platform_exit(void)
|
|
{
|
|
platform_device_unregister(pmc_core_device);
|
|
}
|
|
|
|
module_init(pmc_core_platform_init);
|
|
module_exit(pmc_core_platform_exit);
|
|
MODULE_LICENSE("GPL v2");
|