Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * xen-acpi-pad.c - Xen pad interface
0004  *
0005  * Copyright (c) 2012, Intel Corporation.
0006  *    Author: Liu, Jinsong <jinsong.liu@intel.com>
0007  */
0008 
0009 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0010 
0011 #include <linux/kernel.h>
0012 #include <linux/types.h>
0013 #include <linux/acpi.h>
0014 #include <xen/xen.h>
0015 #include <xen/interface/version.h>
0016 #include <xen/xen-ops.h>
0017 #include <asm/xen/hypercall.h>
0018 
0019 #define ACPI_PROCESSOR_AGGREGATOR_CLASS "acpi_pad"
0020 #define ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME "Processor Aggregator"
0021 #define ACPI_PROCESSOR_AGGREGATOR_NOTIFY 0x80
0022 static DEFINE_MUTEX(xen_cpu_lock);
0023 
0024 static int xen_acpi_pad_idle_cpus(unsigned int idle_nums)
0025 {
0026     struct xen_platform_op op;
0027 
0028     op.cmd = XENPF_core_parking;
0029     op.u.core_parking.type = XEN_CORE_PARKING_SET;
0030     op.u.core_parking.idle_nums = idle_nums;
0031 
0032     return HYPERVISOR_platform_op(&op);
0033 }
0034 
0035 static int xen_acpi_pad_idle_cpus_num(void)
0036 {
0037     struct xen_platform_op op;
0038 
0039     op.cmd = XENPF_core_parking;
0040     op.u.core_parking.type = XEN_CORE_PARKING_GET;
0041 
0042     return HYPERVISOR_platform_op(&op)
0043            ?: op.u.core_parking.idle_nums;
0044 }
0045 
0046 /*
0047  * Query firmware how many CPUs should be idle
0048  * return -1 on failure
0049  */
0050 static int acpi_pad_pur(acpi_handle handle)
0051 {
0052     struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
0053     union acpi_object *package;
0054     int num = -1;
0055 
0056     if (ACPI_FAILURE(acpi_evaluate_object(handle, "_PUR", NULL, &buffer)))
0057         return num;
0058 
0059     if (!buffer.length || !buffer.pointer)
0060         return num;
0061 
0062     package = buffer.pointer;
0063 
0064     if (package->type == ACPI_TYPE_PACKAGE &&
0065         package->package.count == 2 &&
0066         package->package.elements[0].integer.value == 1) /* rev 1 */
0067         num = package->package.elements[1].integer.value;
0068 
0069     kfree(buffer.pointer);
0070     return num;
0071 }
0072 
0073 static void acpi_pad_handle_notify(acpi_handle handle)
0074 {
0075     int idle_nums;
0076     struct acpi_buffer param = {
0077         .length = 4,
0078         .pointer = (void *)&idle_nums,
0079     };
0080 
0081 
0082     mutex_lock(&xen_cpu_lock);
0083     idle_nums = acpi_pad_pur(handle);
0084     if (idle_nums < 0) {
0085         mutex_unlock(&xen_cpu_lock);
0086         return;
0087     }
0088 
0089     idle_nums = xen_acpi_pad_idle_cpus(idle_nums)
0090             ?: xen_acpi_pad_idle_cpus_num();
0091     if (idle_nums >= 0)
0092         acpi_evaluate_ost(handle, ACPI_PROCESSOR_AGGREGATOR_NOTIFY,
0093                   0, &param);
0094     mutex_unlock(&xen_cpu_lock);
0095 }
0096 
0097 static void acpi_pad_notify(acpi_handle handle, u32 event,
0098     void *data)
0099 {
0100     switch (event) {
0101     case ACPI_PROCESSOR_AGGREGATOR_NOTIFY:
0102         acpi_pad_handle_notify(handle);
0103         break;
0104     default:
0105         pr_warn("Unsupported event [0x%x]\n", event);
0106         break;
0107     }
0108 }
0109 
0110 static int acpi_pad_add(struct acpi_device *device)
0111 {
0112     acpi_status status;
0113 
0114     strcpy(acpi_device_name(device), ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME);
0115     strcpy(acpi_device_class(device), ACPI_PROCESSOR_AGGREGATOR_CLASS);
0116 
0117     status = acpi_install_notify_handler(device->handle,
0118         ACPI_DEVICE_NOTIFY, acpi_pad_notify, device);
0119     if (ACPI_FAILURE(status))
0120         return -ENODEV;
0121 
0122     return 0;
0123 }
0124 
0125 static int acpi_pad_remove(struct acpi_device *device)
0126 {
0127     mutex_lock(&xen_cpu_lock);
0128     xen_acpi_pad_idle_cpus(0);
0129     mutex_unlock(&xen_cpu_lock);
0130 
0131     acpi_remove_notify_handler(device->handle,
0132         ACPI_DEVICE_NOTIFY, acpi_pad_notify);
0133     return 0;
0134 }
0135 
0136 static const struct acpi_device_id pad_device_ids[] = {
0137     {"ACPI000C", 0},
0138     {"", 0},
0139 };
0140 
0141 static struct acpi_driver acpi_pad_driver = {
0142     .name = "processor_aggregator",
0143     .class = ACPI_PROCESSOR_AGGREGATOR_CLASS,
0144     .ids = pad_device_ids,
0145     .ops = {
0146         .add = acpi_pad_add,
0147         .remove = acpi_pad_remove,
0148     },
0149 };
0150 
0151 static int __init xen_acpi_pad_init(void)
0152 {
0153     /* Only DOM0 is responsible for Xen acpi pad */
0154     if (!xen_initial_domain())
0155         return -ENODEV;
0156 
0157     /* Only Xen4.2 or later support Xen acpi pad */
0158     if (!xen_running_on_version_or_later(4, 2))
0159         return -ENODEV;
0160 
0161     return acpi_bus_register_driver(&acpi_pad_driver);
0162 }
0163 subsys_initcall(xen_acpi_pad_init);