0001
0002
0003
0004
0005
0006
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
0048
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)
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, ¶m);
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
0154 if (!xen_initial_domain())
0155 return -ENODEV;
0156
0157
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);