root/drivers/acpi/acpi_processor.c
// SPDX-License-Identifier: GPL-2.0-only
/*
 * acpi_processor.c - ACPI processor enumeration support
 *
 * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
 * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
 * Copyright (C) 2004       Dominik Brodowski <linux@brodo.de>
 * Copyright (C) 2004  Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
 * Copyright (C) 2013, Intel Corporation
 *                     Rafael J. Wysocki <rafael.j.wysocki@intel.com>
 */
#define pr_fmt(fmt) "ACPI: " fmt

#include <linux/acpi.h>
#include <linux/cpu.h>
#include <linux/device.h>
#include <linux/dmi.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/platform_device.h>

#include <acpi/processor.h>

#include <asm/cpu.h>

#include <xen/xen.h>

#include "internal.h"

DEFINE_PER_CPU(struct acpi_processor *, processors);
EXPORT_PER_CPU_SYMBOL(processors);

/* Errata Handling */
struct acpi_processor_errata errata __read_mostly;
EXPORT_SYMBOL_GPL(errata);

acpi_handle acpi_get_processor_handle(int cpu)
{
        struct acpi_processor *pr;

        pr = per_cpu(processors, cpu);
        if (pr)
                return pr->handle;

        return NULL;
}

static int acpi_processor_errata_piix4(struct pci_dev *dev)
{
        u8 value1 = 0;
        u8 value2 = 0;
        struct pci_dev *ide_dev = NULL, *isa_dev = NULL;


        if (!dev)
                return -EINVAL;

        /*
         * Note that 'dev' references the PIIX4 ACPI Controller.
         */

        switch (dev->revision) {
        case 0:
                dev_dbg(&dev->dev, "Found PIIX4 A-step\n");
                break;
        case 1:
                dev_dbg(&dev->dev, "Found PIIX4 B-step\n");
                break;
        case 2:
                dev_dbg(&dev->dev, "Found PIIX4E\n");
                break;
        case 3:
                dev_dbg(&dev->dev, "Found PIIX4M\n");
                break;
        default:
                dev_dbg(&dev->dev, "Found unknown PIIX4\n");
                break;
        }

        switch (dev->revision) {

        case 0:         /* PIIX4 A-step */
        case 1:         /* PIIX4 B-step */
                /*
                 * See specification changes #13 ("Manual Throttle Duty Cycle")
                 * and #14 ("Enabling and Disabling Manual Throttle"), plus
                 * erratum #5 ("STPCLK# Deassertion Time") from the January
                 * 2002 PIIX4 specification update.  Applies to only older
                 * PIIX4 models.
                 */
                errata.piix4.throttle = 1;
                fallthrough;

        case 2:         /* PIIX4E */
        case 3:         /* PIIX4M */
                /*
                 * See erratum #18 ("C3 Power State/BMIDE and Type-F DMA
                 * Livelock") from the January 2002 PIIX4 specification update.
                 * Applies to all PIIX4 models.
                 */

                /*
                 * BM-IDE
                 * ------
                 * Find the PIIX4 IDE Controller and get the Bus Master IDE
                 * Status register address.  We'll use this later to read
                 * each IDE controller's DMA status to make sure we catch all
                 * DMA activity.
                 */
                ide_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
                                     PCI_DEVICE_ID_INTEL_82371AB,
                                     PCI_ANY_ID, PCI_ANY_ID, NULL);
                if (ide_dev) {
                        errata.piix4.bmisx = pci_resource_start(ide_dev, 4);
                        if (errata.piix4.bmisx)
                                dev_dbg(&ide_dev->dev,
                                        "Bus master activity detection (BM-IDE) erratum enabled\n");

                        pci_dev_put(ide_dev);
                }

                /*
                 * Type-F DMA
                 * ----------
                 * Find the PIIX4 ISA Controller and read the Motherboard
                 * DMA controller's status to see if Type-F (Fast) DMA mode
                 * is enabled (bit 7) on either channel.  Note that we'll
                 * disable C3 support if this is enabled, as some legacy
                 * devices won't operate well if fast DMA is disabled.
                 */
                isa_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
                                     PCI_DEVICE_ID_INTEL_82371AB_0,
                                     PCI_ANY_ID, PCI_ANY_ID, NULL);
                if (isa_dev) {
                        pci_read_config_byte(isa_dev, 0x76, &value1);
                        pci_read_config_byte(isa_dev, 0x77, &value2);
                        if ((value1 & 0x80) || (value2 & 0x80)) {
                                errata.piix4.fdma = 1;
                                dev_dbg(&isa_dev->dev,
                                        "Type-F DMA livelock erratum (C3 disabled)\n");
                        }
                        pci_dev_put(isa_dev);
                }

                break;
        }

        return 0;
}

static int acpi_processor_errata(void)
{
        int result = 0;
        struct pci_dev *dev = NULL;

        /*
         * PIIX4
         */
        dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
                             PCI_DEVICE_ID_INTEL_82371AB_3, PCI_ANY_ID,
                             PCI_ANY_ID, NULL);
        if (dev) {
                result = acpi_processor_errata_piix4(dev);
                pci_dev_put(dev);
        }

        return result;
}

/* Create a platform device to represent a CPU frequency control mechanism. */
static void cpufreq_add_device(const char *name)
{
        struct platform_device *pdev;

        pdev = platform_device_register_simple(name, PLATFORM_DEVID_NONE, NULL, 0);
        if (IS_ERR(pdev))
                pr_info("%s device creation failed: %pe\n", name, pdev);
}

#ifdef CONFIG_X86
/* Check presence of Processor Clocking Control by searching for \_SB.PCCH. */
static void __init acpi_pcc_cpufreq_init(void)
{
        acpi_status status;
        acpi_handle handle;

        status = acpi_get_handle(NULL, "\\_SB", &handle);
        if (ACPI_FAILURE(status))
                return;

        if (acpi_has_method(handle, "PCCH"))
                cpufreq_add_device("pcc-cpufreq");
}
#else
static void __init acpi_pcc_cpufreq_init(void) {}
#endif /* CONFIG_X86 */

/* Initialization */
static DEFINE_PER_CPU(void *, processor_device_array);

static int acpi_processor_set_per_cpu(struct acpi_processor *pr,
                                      struct acpi_device *device)
{
        BUG_ON(pr->id >= nr_cpu_ids);

        /*
         * Buggy BIOS check.
         * ACPI id of processors can be reported wrongly by the BIOS.
         * Don't trust it blindly
         */
        if (per_cpu(processor_device_array, pr->id) != NULL &&
            per_cpu(processor_device_array, pr->id) != device) {
                dev_warn(&device->dev,
                         "BIOS reported wrong ACPI id %d for the processor\n",
                         pr->id);
                return -EINVAL;
        }
        /*
         * processor_device_array is not cleared on errors to allow buggy BIOS
         * checks.
         */
        per_cpu(processor_device_array, pr->id) = device;
        per_cpu(processors, pr->id) = pr;

        return 0;
}

#ifdef CONFIG_ACPI_HOTPLUG_CPU
static int acpi_processor_hotadd_init(struct acpi_processor *pr,
                                      struct acpi_device *device)
{
        int ret;

        if (invalid_phys_cpuid(pr->phys_id))
                return -ENODEV;

        cpu_maps_update_begin();
        cpus_write_lock();

        ret = acpi_map_cpu(pr->handle, pr->phys_id, pr->acpi_id, &pr->id);
        if (ret)
                goto out;

        ret = acpi_processor_set_per_cpu(pr, device);
        if (ret) {
                acpi_unmap_cpu(pr->id);
                goto out;
        }

        ret = arch_register_cpu(pr->id);
        if (ret) {
                /* Leave the processor device array in place to detect buggy bios */
                per_cpu(processors, pr->id) = NULL;
                acpi_unmap_cpu(pr->id);
                goto out;
        }

        /*
         * CPU got hot-added, but cpu_data is not initialized yet. Do
         * cpu_idle/throttling initialization when the CPU gets online for
         * the first time.
         */
        pr_info("CPU%d has been hot-added\n", pr->id);

out:
        cpus_write_unlock();
        cpu_maps_update_done();
        return ret;
}
#else
static inline int acpi_processor_hotadd_init(struct acpi_processor *pr,
                                             struct acpi_device *device)
{
        return -ENODEV;
}
#endif /* CONFIG_ACPI_HOTPLUG_CPU */

static int acpi_processor_get_info(struct acpi_device *device)
{
        union acpi_object object = { .processor = { 0 } };
        struct acpi_buffer buffer = { sizeof(union acpi_object), &object };
        struct acpi_processor *pr = acpi_driver_data(device);
        int device_declaration = 0;
        acpi_status status = AE_OK;
        static int cpu0_initialized;
        unsigned long long value;
        int ret;

        acpi_processor_errata();

        /*
         * Check to see if we have bus mastering arbitration control.  This
         * is required for proper C3 usage (to maintain cache coherency).
         */
        if (acpi_gbl_FADT.pm2_control_block && acpi_gbl_FADT.pm2_control_length) {
                pr->flags.bm_control = 1;
                dev_dbg(&device->dev, "Bus mastering arbitration control present\n");
        } else
                dev_dbg(&device->dev, "No bus mastering arbitration control\n");

        if (!strcmp(acpi_device_hid(device), ACPI_PROCESSOR_OBJECT_HID)) {
                /* Declared with "Processor" statement; match ProcessorID */
                status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer);
                if (ACPI_FAILURE(status)) {
                        dev_err(&device->dev,
                                "Failed to evaluate processor object (0x%x)\n",
                                status);
                        return -ENODEV;
                }

                pr->acpi_id = object.processor.proc_id;
        } else {
                /*
                 * Declared with "Device" statement; match _UID.
                 */
                status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID,
                                                NULL, &value);
                if (ACPI_FAILURE(status)) {
                        dev_err(&device->dev,
                                "Failed to evaluate processor _UID (0x%x)\n",
                                status);
                        return -ENODEV;
                }
                device_declaration = 1;
                pr->acpi_id = value;
        }

        if (acpi_duplicate_processor_id(pr->acpi_id)) {
                if (pr->acpi_id == 0xff)
                        dev_info_once(&device->dev,
                                "Entry not well-defined, consider updating BIOS\n");
                else
                        dev_err(&device->dev,
                                "Failed to get unique processor _UID (0x%x)\n",
                                pr->acpi_id);
                return -ENODEV;
        }

        pr->phys_id = acpi_get_phys_id(pr->handle, device_declaration,
                                        pr->acpi_id);
        if (invalid_phys_cpuid(pr->phys_id))
                dev_dbg(&device->dev, "Failed to get CPU physical ID.\n");

        pr->id = acpi_map_cpuid(pr->phys_id, pr->acpi_id);
        if (!cpu0_initialized) {
                cpu0_initialized = 1;
                /*
                 * Handle UP system running SMP kernel, with no CPU
                 * entry in MADT
                 */
                if (!acpi_has_cpu_in_madt() && invalid_logical_cpuid(pr->id) &&
                    (num_online_cpus() == 1))
                        pr->id = 0;
                /*
                 * Check availability of Processor Performance Control by
                 * looking at the presence of the _PCT object under the first
                 * processor definition.
                 */
                if (acpi_has_method(pr->handle, "_PCT"))
                        cpufreq_add_device("acpi-cpufreq");
        }

        /*
         *  This code is not called unless we know the CPU is present and
         *  enabled. The two paths are:
         *  a) Initially present CPUs on architectures that do not defer
         *     their arch_register_cpu() calls until this point.
         *  b) Hotplugged CPUs (enabled bit in _STA has transitioned from not
         *     enabled to enabled)
         */
        if (!get_cpu_device(pr->id))
                ret = acpi_processor_hotadd_init(pr, device);
        else
                ret = acpi_processor_set_per_cpu(pr, device);
        if (ret)
                return ret;

        /*
         * On some boxes several processors use the same processor bus id.
         * But they are located in different scope. For example:
         * \_SB.SCK0.CPU0
         * \_SB.SCK1.CPU0
         * Rename the processor device bus id. And the new bus id will be
         * generated as the following format:
         * CPU+CPU ID.
         */
        sprintf(acpi_device_bid(device), "CPU%X", pr->id);
        dev_dbg(&device->dev, "Processor [%d:%d]\n", pr->id, pr->acpi_id);

        if (!object.processor.pblk_address)
                dev_dbg(&device->dev, "No PBLK (NULL address)\n");
        else if (object.processor.pblk_length != 6)
                dev_err(&device->dev, "Invalid PBLK length [%d]\n",
                            object.processor.pblk_length);
        else {
                pr->throttling.address = object.processor.pblk_address;
                pr->throttling.duty_offset = acpi_gbl_FADT.duty_offset;
                pr->throttling.duty_width = acpi_gbl_FADT.duty_width;

                pr->pblk = object.processor.pblk_address;
        }

        /*
         * If ACPI describes a slot number for this CPU, we can use it to
         * ensure we get the right value in the "physical id" field
         * of /proc/cpuinfo
         */
        status = acpi_evaluate_integer(pr->handle, "_SUN", NULL, &value);
        if (ACPI_SUCCESS(status))
                arch_fix_phys_package_id(pr->id, value);

        return 0;
}

/*
 * Do not put anything in here which needs the core to be online.
 * For example MSR access or setting up things which check for cpuinfo_x86
 * (cpu_data(cpu)) values, like CPU feature flags, family, model, etc.
 * Such things have to be put in and set up by the processor driver's .probe().
 */
static int acpi_processor_add(struct acpi_device *device,
                                        const struct acpi_device_id *id)
{
        struct acpi_processor *pr;
        struct device *dev;
        int result = 0;

        if (!acpi_device_is_enabled(device))
                return -ENODEV;

        pr = kzalloc_obj(struct acpi_processor);
        if (!pr)
                return -ENOMEM;

        if (!zalloc_cpumask_var(&pr->throttling.shared_cpu_map, GFP_KERNEL)) {
                result = -ENOMEM;
                goto err_free_pr;
        }

        pr->handle = device->handle;
        strscpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME);
        strscpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS);
        device->driver_data = pr;

        result = acpi_processor_get_info(device);
        if (result) /* Processor is not physically present or unavailable */
                goto err_clear_driver_data;

        dev = get_cpu_device(pr->id);
        if (!dev) {
                result = -ENODEV;
                goto err_clear_per_cpu;
        }

        result = acpi_bind_one(dev, device);
        if (result)
                goto err_clear_per_cpu;

        pr->dev = dev;

        /* Trigger the processor driver's .probe() if present. */
        if (device_attach(dev) >= 0)
                return 1;

        dev_err(dev, "Processor driver could not be attached\n");
        acpi_unbind_one(dev);

 err_clear_per_cpu:
        per_cpu(processors, pr->id) = NULL;
 err_clear_driver_data:
        device->driver_data = NULL;
        free_cpumask_var(pr->throttling.shared_cpu_map);
 err_free_pr:
        kfree(pr);
        return result;
}

#ifdef CONFIG_ACPI_HOTPLUG_CPU
/* Removal */
static void acpi_processor_post_eject(struct acpi_device *device)
{
        struct acpi_processor *pr;

        if (!device || !acpi_driver_data(device))
                return;

        pr = acpi_driver_data(device);
        if (pr->id >= nr_cpu_ids)
                goto out;

        /*
         * The only reason why we ever get here is CPU hot-removal.  The CPU is
         * already offline and the ACPI device removal locking prevents it from
         * being put back online at this point.
         *
         * Unbind the driver from the processor device and detach it from the
         * ACPI companion object.
         */
        device_release_driver(pr->dev);
        acpi_unbind_one(pr->dev);

        cpu_maps_update_begin();
        cpus_write_lock();

        /* Remove the CPU. */
        arch_unregister_cpu(pr->id);
        acpi_unmap_cpu(pr->id);

        /* Clean up. */
        per_cpu(processor_device_array, pr->id) = NULL;
        per_cpu(processors, pr->id) = NULL;

        cpus_write_unlock();
        cpu_maps_update_done();

        try_offline_node(cpu_to_node(pr->id));

 out:
        free_cpumask_var(pr->throttling.shared_cpu_map);
        kfree(pr);
}
#endif /* CONFIG_ACPI_HOTPLUG_CPU */

#ifdef CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC
bool __init processor_physically_present(acpi_handle handle)
{
        int cpuid, type;
        u32 acpi_id;
        acpi_status status;
        acpi_object_type acpi_type;
        unsigned long long tmp;
        union acpi_object object = {};
        struct acpi_buffer buffer = { sizeof(union acpi_object), &object };

        status = acpi_get_type(handle, &acpi_type);
        if (ACPI_FAILURE(status))
                return false;

        switch (acpi_type) {
        case ACPI_TYPE_PROCESSOR:
                status = acpi_evaluate_object(handle, NULL, NULL, &buffer);
                if (ACPI_FAILURE(status))
                        return false;
                acpi_id = object.processor.proc_id;
                break;
        case ACPI_TYPE_DEVICE:
                status = acpi_evaluate_integer(handle, METHOD_NAME__UID,
                                               NULL, &tmp);
                if (ACPI_FAILURE(status))
                        return false;
                acpi_id = tmp;
                break;
        default:
                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 or _OSC 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);

        return !invalid_logical_cpuid(cpuid);
}

/* vendor specific UUID indicating an Intel platform */
static u8 sb_uuid_str[] = "4077A616-290C-47BE-9EBD-D87058713953";

static acpi_status __init acpi_processor_osc(acpi_handle handle, u32 lvl,
                                             void *context, void **rv)
{
        u32 capbuf[2] = {};
        struct acpi_osc_context osc_context = {
                .uuid_str = sb_uuid_str,
                .rev = 1,
                .cap.length = 8,
                .cap.pointer = capbuf,
        };
        acpi_status status;

        if (!processor_physically_present(handle))
                return AE_OK;

        arch_acpi_set_proc_cap_bits(&capbuf[OSC_SUPPORT_DWORD]);

        status = acpi_run_osc(handle, &osc_context);
        if (ACPI_FAILURE(status))
                return status;

        kfree(osc_context.ret.pointer);

        return AE_OK;
}

static bool __init acpi_early_processor_osc(void)
{
        acpi_status status;

        acpi_proc_quirk_mwait_check();

        status = acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,
                                     ACPI_UINT32_MAX, acpi_processor_osc, NULL,
                                     NULL, NULL);
        if (ACPI_FAILURE(status))
                return false;

        status = acpi_get_devices(ACPI_PROCESSOR_DEVICE_HID, acpi_processor_osc,
                                  NULL, NULL);
        if (ACPI_FAILURE(status))
                return false;

        return true;
}

void __init acpi_early_processor_control_setup(void)
{
        if (acpi_early_processor_osc()) {
                pr_debug("_OSC evaluated successfully for all CPUs\n");
        } else {
                pr_debug("_OSC evaluation for CPUs failed, trying _PDC\n");
                acpi_early_processor_set_pdc();
        }
}
#endif

/*
 * The following ACPI IDs are known to be suitable for representing as
 * processor devices.
 */
static const struct acpi_device_id processor_device_ids[] = {

        { ACPI_PROCESSOR_OBJECT_HID, },
        { ACPI_PROCESSOR_DEVICE_HID, },

        { }
};

static struct acpi_scan_handler processor_handler = {
        .ids = processor_device_ids,
        .attach = acpi_processor_add,
#ifdef CONFIG_ACPI_HOTPLUG_CPU
        .post_eject = acpi_processor_post_eject,
#endif
        .hotplug = {
                .enabled = true,
        },
};

static int acpi_processor_container_attach(struct acpi_device *dev,
                                           const struct acpi_device_id *id)
{
        return 1;
}

static const struct acpi_device_id processor_container_ids[] = {
        { ACPI_PROCESSOR_CONTAINER_HID, },
        { }
};

static struct acpi_scan_handler processor_container_handler = {
        .ids = processor_container_ids,
        .attach = acpi_processor_container_attach,
};

/* The number of the unique processor IDs */
static int nr_unique_ids __initdata;

/* The number of the duplicate processor IDs */
static int nr_duplicate_ids;

/* Used to store the unique processor IDs */
static int unique_processor_ids[] __initdata = {
        [0 ... NR_CPUS - 1] = -1,
};

/* Used to store the duplicate processor IDs */
static int duplicate_processor_ids[] = {
        [0 ... NR_CPUS - 1] = -1,
};

static void __init processor_validated_ids_update(int proc_id)
{
        int i;

        if (nr_unique_ids == NR_CPUS||nr_duplicate_ids == NR_CPUS)
                return;

        /*
         * Firstly, compare the proc_id with duplicate IDs, if the proc_id is
         * already in the IDs, do nothing.
         */
        for (i = 0; i < nr_duplicate_ids; i++) {
                if (duplicate_processor_ids[i] == proc_id)
                        return;
        }

        /*
         * Secondly, compare the proc_id with unique IDs, if the proc_id is in
         * the IDs, put it in the duplicate IDs.
         */
        for (i = 0; i < nr_unique_ids; i++) {
                if (unique_processor_ids[i] == proc_id) {
                        duplicate_processor_ids[nr_duplicate_ids] = proc_id;
                        nr_duplicate_ids++;
                        return;
                }
        }

        /*
         * Lastly, the proc_id is a unique ID, put it in the unique IDs.
         */
        unique_processor_ids[nr_unique_ids] = proc_id;
        nr_unique_ids++;
}

static acpi_status __init acpi_processor_ids_walk(acpi_handle handle,
                                                  u32 lvl,
                                                  void *context,
                                                  void **rv)
{
        acpi_status status;
        acpi_object_type acpi_type;
        unsigned long long uid;
        union acpi_object object = { 0 };
        struct acpi_buffer buffer = { sizeof(union acpi_object), &object };

        status = acpi_get_type(handle, &acpi_type);
        if (ACPI_FAILURE(status))
                return status;

        switch (acpi_type) {
        case ACPI_TYPE_PROCESSOR:
                status = acpi_evaluate_object(handle, NULL, NULL, &buffer);
                if (ACPI_FAILURE(status))
                        goto err;
                uid = object.processor.proc_id;
                break;

        case ACPI_TYPE_DEVICE:
                status = acpi_evaluate_integer(handle, "_UID", NULL, &uid);
                if (ACPI_FAILURE(status))
                        goto err;
                break;
        default:
                goto err;
        }

        processor_validated_ids_update(uid);
        return AE_OK;

err:
        /* Exit on error, but don't abort the namespace walk */
        acpi_handle_info(handle, "Invalid processor object\n");
        return AE_OK;

}

static void __init acpi_processor_check_duplicates(void)
{
        /* check the correctness for all processors in ACPI namespace */
        acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,
                                                ACPI_UINT32_MAX,
                                                acpi_processor_ids_walk,
                                                NULL, NULL, NULL);
        acpi_get_devices(ACPI_PROCESSOR_DEVICE_HID, acpi_processor_ids_walk,
                                                NULL, NULL);
}

bool acpi_duplicate_processor_id(int proc_id)
{
        int i;

        /*
         * compare the proc_id with duplicate IDs, if the proc_id is already
         * in the duplicate IDs, return true, otherwise, return false.
         */
        for (i = 0; i < nr_duplicate_ids; i++) {
                if (duplicate_processor_ids[i] == proc_id)
                        return true;
        }
        return false;
}

void __init acpi_processor_init(void)
{
        acpi_processor_check_duplicates();
        acpi_scan_add_handler_with_hotplug(&processor_handler, "processor");
        acpi_scan_add_handler(&processor_container_handler);
        acpi_pcc_cpufreq_init();
}

#ifdef CONFIG_ACPI_PROCESSOR_CSTATE
/**
 * acpi_processor_claim_cst_control - Request _CST control from the platform.
 */
bool acpi_processor_claim_cst_control(void)
{
        static bool cst_control_claimed;
        acpi_status status;

        if (!acpi_gbl_FADT.cst_control || cst_control_claimed)
                return true;

        status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
                                    acpi_gbl_FADT.cst_control, 8);
        if (ACPI_FAILURE(status)) {
                pr_warn("ACPI: Failed to claim processor _CST control\n");
                return false;
        }

        cst_control_claimed = true;
        return true;
}
EXPORT_SYMBOL_NS_GPL(acpi_processor_claim_cst_control, "ACPI_PROCESSOR_IDLE");

/**
 * acpi_processor_evaluate_cst - Evaluate the processor _CST control method.
 * @handle: ACPI handle of the processor object containing the _CST.
 * @cpu: The numeric ID of the target CPU.
 * @info: Object write the C-states information into.
 *
 * Extract the C-state information for the given CPU from the output of the _CST
 * control method under the corresponding ACPI processor object (or processor
 * device object) and populate @info with it.
 *
 * If any ACPI_ADR_SPACE_FIXED_HARDWARE C-states are found, invoke
 * acpi_processor_ffh_cstate_probe() to verify them and update the
 * cpu_cstate_entry data for @cpu.
 */
int acpi_processor_evaluate_cst(acpi_handle handle, u32 cpu,
                                struct acpi_processor_power *info)
{
        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
        union acpi_object *cst;
        acpi_status status;
        u64 count;
        int last_index = 0;
        int i, ret = 0;

        status = acpi_evaluate_object(handle, "_CST", NULL, &buffer);
        if (ACPI_FAILURE(status)) {
                acpi_handle_debug(handle, "No _CST\n");
                return -ENODEV;
        }

        cst = buffer.pointer;

        /* There must be at least 2 elements. */
        if (!cst || cst->type != ACPI_TYPE_PACKAGE || cst->package.count < 2) {
                acpi_handle_warn(handle, "Invalid _CST output\n");
                ret = -EFAULT;
                goto end;
        }

        count = cst->package.elements[0].integer.value;

        /* Validate the number of C-states. */
        if (count < 1 || count != cst->package.count - 1) {
                acpi_handle_warn(handle, "Inconsistent _CST data\n");
                ret = -EFAULT;
                goto end;
        }

        for (i = 1; i <= count; i++) {
                union acpi_object *element;
                union acpi_object *obj;
                struct acpi_power_register *reg;
                struct acpi_processor_cx cx;

                /*
                 * If there is not enough space for all C-states, skip the
                 * excess ones and log a warning.
                 */
                if (last_index >= ACPI_PROCESSOR_MAX_POWER - 1) {
                        acpi_handle_warn(handle,
                                         "No room for more idle states (limit: %d)\n",
                                         ACPI_PROCESSOR_MAX_POWER - 1);
                        break;
                }

                memset(&cx, 0, sizeof(cx));

                element = &cst->package.elements[i];
                if (element->type != ACPI_TYPE_PACKAGE) {
                        acpi_handle_info(handle, "_CST C%d type(%x) is not package, skip...\n",
                                         i, element->type);
                        continue;
                }

                if (element->package.count != 4) {
                        acpi_handle_info(handle, "_CST C%d package count(%d) is not 4, skip...\n",
                                         i, element->package.count);
                        continue;
                }

                obj = &element->package.elements[0];

                if (obj->type != ACPI_TYPE_BUFFER) {
                        acpi_handle_info(handle, "_CST C%d package element[0] type(%x) is not buffer, skip...\n",
                                         i, obj->type);
                        continue;
                }

                reg = (struct acpi_power_register *)obj->buffer.pointer;

                obj = &element->package.elements[1];
                if (obj->type != ACPI_TYPE_INTEGER) {
                        acpi_handle_info(handle, "_CST C[%d] package element[1] type(%x) is not integer, skip...\n",
                                         i, obj->type);
                        continue;
                }

                cx.type = obj->integer.value;
                /*
                 * There are known cases in which the _CST output does not
                 * contain C1, so if the type of the first state found is not
                 * C1, leave an empty slot for C1 to be filled in later.
                 */
                if (i == 1 && cx.type != ACPI_STATE_C1)
                        last_index = 1;

                cx.address = reg->address;
                cx.index = last_index + 1;

                if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) {
                        if (!acpi_processor_ffh_cstate_probe(cpu, &cx, reg)) {
                                /*
                                 * In the majority of cases _CST describes C1 as
                                 * a FIXED_HARDWARE C-state, but if the command
                                 * line forbids using MWAIT, use CSTATE_HALT for
                                 * C1 regardless.
                                 */
                                if (cx.type == ACPI_STATE_C1 &&
                                    boot_option_idle_override == IDLE_NOMWAIT) {
                                        cx.entry_method = ACPI_CSTATE_HALT;
                                        snprintf(cx.desc, ACPI_CX_DESC_LEN, "ACPI HLT");
                                } else {
                                        cx.entry_method = ACPI_CSTATE_FFH;
                                }
                        } else if (cx.type == ACPI_STATE_C1) {
                                /*
                                 * In the special case of C1, FIXED_HARDWARE can
                                 * be handled by executing the HLT instruction.
                                 */
                                cx.entry_method = ACPI_CSTATE_HALT;
                                snprintf(cx.desc, ACPI_CX_DESC_LEN, "ACPI HLT");
                        } else {
                                acpi_handle_info(handle, "_CST C%d declares FIXED_HARDWARE C-state but not supported in hardware, skip...\n",
                                                 i);
                                continue;
                        }
                } else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
                        cx.entry_method = ACPI_CSTATE_SYSTEMIO;
                        snprintf(cx.desc, ACPI_CX_DESC_LEN, "ACPI IOPORT 0x%x",
                                 cx.address);
                } else {
                        acpi_handle_info(handle, "_CST C%d space_id(%x) neither FIXED_HARDWARE nor SYSTEM_IO, skip...\n",
                                         i, reg->space_id);
                        continue;
                }

                if (cx.type == ACPI_STATE_C1)
                        cx.valid = 1;

                obj = &element->package.elements[2];
                if (obj->type != ACPI_TYPE_INTEGER) {
                        acpi_handle_info(handle, "_CST C%d package element[2] type(%x) not integer, skip...\n",
                                         i, obj->type);
                        continue;
                }

                cx.latency = obj->integer.value;

                obj = &element->package.elements[3];
                if (obj->type != ACPI_TYPE_INTEGER) {
                        acpi_handle_info(handle, "_CST C%d package element[3] type(%x) not integer, skip...\n",
                                         i, obj->type);
                        continue;
                }

                memcpy(&info->states[++last_index], &cx, sizeof(cx));
        }

        acpi_handle_debug(handle, "Found %d idle states\n", last_index);

        info->count = last_index;

end:
        kfree(buffer.pointer);

        return ret;
}
EXPORT_SYMBOL_NS_GPL(acpi_processor_evaluate_cst, "ACPI_PROCESSOR_IDLE");
#endif /* CONFIG_ACPI_PROCESSOR_CSTATE */