Version:  2.0.40 2.2.26 2.4.37 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18

Linux/drivers/xen/xen-acpi-pad.c

  1 /*
  2  * xen-acpi-pad.c - Xen pad interface
  3  *
  4  * Copyright (c) 2012, Intel Corporation.
  5  *    Author: Liu, Jinsong <jinsong.liu@intel.com>
  6  *
  7  * This program is free software; you can redistribute it and/or modify it
  8  * under the terms and conditions of the GNU General Public License,
  9  * version 2, as published by the Free Software Foundation.
 10  *
 11  * This program is distributed in the hope it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 14  * more details.
 15  */
 16 
 17 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 18 
 19 #include <linux/kernel.h>
 20 #include <linux/types.h>
 21 #include <linux/acpi.h>
 22 #include <xen/interface/version.h>
 23 #include <xen/xen-ops.h>
 24 #include <asm/xen/hypercall.h>
 25 
 26 #define ACPI_PROCESSOR_AGGREGATOR_CLASS "acpi_pad"
 27 #define ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME "Processor Aggregator"
 28 #define ACPI_PROCESSOR_AGGREGATOR_NOTIFY 0x80
 29 static DEFINE_MUTEX(xen_cpu_lock);
 30 
 31 static int xen_acpi_pad_idle_cpus(unsigned int idle_nums)
 32 {
 33         struct xen_platform_op op;
 34 
 35         op.cmd = XENPF_core_parking;
 36         op.u.core_parking.type = XEN_CORE_PARKING_SET;
 37         op.u.core_parking.idle_nums = idle_nums;
 38 
 39         return HYPERVISOR_dom0_op(&op);
 40 }
 41 
 42 static int xen_acpi_pad_idle_cpus_num(void)
 43 {
 44         struct xen_platform_op op;
 45 
 46         op.cmd = XENPF_core_parking;
 47         op.u.core_parking.type = XEN_CORE_PARKING_GET;
 48 
 49         return HYPERVISOR_dom0_op(&op)
 50                ?: op.u.core_parking.idle_nums;
 51 }
 52 
 53 /*
 54  * Query firmware how many CPUs should be idle
 55  * return -1 on failure
 56  */
 57 static int acpi_pad_pur(acpi_handle handle)
 58 {
 59         struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
 60         union acpi_object *package;
 61         int num = -1;
 62 
 63         if (ACPI_FAILURE(acpi_evaluate_object(handle, "_PUR", NULL, &buffer)))
 64                 return num;
 65 
 66         if (!buffer.length || !buffer.pointer)
 67                 return num;
 68 
 69         package = buffer.pointer;
 70 
 71         if (package->type == ACPI_TYPE_PACKAGE &&
 72                 package->package.count == 2 &&
 73                 package->package.elements[0].integer.value == 1) /* rev 1 */
 74                 num = package->package.elements[1].integer.value;
 75 
 76         kfree(buffer.pointer);
 77         return num;
 78 }
 79 
 80 static void acpi_pad_handle_notify(acpi_handle handle)
 81 {
 82         int idle_nums;
 83         struct acpi_buffer param = {
 84                 .length = 4,
 85                 .pointer = (void *)&idle_nums,
 86         };
 87 
 88 
 89         mutex_lock(&xen_cpu_lock);
 90         idle_nums = acpi_pad_pur(handle);
 91         if (idle_nums < 0) {
 92                 mutex_unlock(&xen_cpu_lock);
 93                 return;
 94         }
 95 
 96         idle_nums = xen_acpi_pad_idle_cpus(idle_nums)
 97                     ?: xen_acpi_pad_idle_cpus_num();
 98         if (idle_nums >= 0)
 99                 acpi_evaluate_ost(handle, ACPI_PROCESSOR_AGGREGATOR_NOTIFY,
100                                   0, &param);
101         mutex_unlock(&xen_cpu_lock);
102 }
103 
104 static void acpi_pad_notify(acpi_handle handle, u32 event,
105         void *data)
106 {
107         switch (event) {
108         case ACPI_PROCESSOR_AGGREGATOR_NOTIFY:
109                 acpi_pad_handle_notify(handle);
110                 break;
111         default:
112                 pr_warn("Unsupported event [0x%x]\n", event);
113                 break;
114         }
115 }
116 
117 static int acpi_pad_add(struct acpi_device *device)
118 {
119         acpi_status status;
120 
121         strcpy(acpi_device_name(device), ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME);
122         strcpy(acpi_device_class(device), ACPI_PROCESSOR_AGGREGATOR_CLASS);
123 
124         status = acpi_install_notify_handler(device->handle,
125                 ACPI_DEVICE_NOTIFY, acpi_pad_notify, device);
126         if (ACPI_FAILURE(status))
127                 return -ENODEV;
128 
129         return 0;
130 }
131 
132 static int acpi_pad_remove(struct acpi_device *device)
133 {
134         mutex_lock(&xen_cpu_lock);
135         xen_acpi_pad_idle_cpus(0);
136         mutex_unlock(&xen_cpu_lock);
137 
138         acpi_remove_notify_handler(device->handle,
139                 ACPI_DEVICE_NOTIFY, acpi_pad_notify);
140         return 0;
141 }
142 
143 static const struct acpi_device_id pad_device_ids[] = {
144         {"ACPI000C", 0},
145         {"", 0},
146 };
147 
148 static struct acpi_driver acpi_pad_driver = {
149         .name = "processor_aggregator",
150         .class = ACPI_PROCESSOR_AGGREGATOR_CLASS,
151         .ids = pad_device_ids,
152         .ops = {
153                 .add = acpi_pad_add,
154                 .remove = acpi_pad_remove,
155         },
156 };
157 
158 static int __init xen_acpi_pad_init(void)
159 {
160         /* Only DOM0 is responsible for Xen acpi pad */
161         if (!xen_initial_domain())
162                 return -ENODEV;
163 
164         /* Only Xen4.2 or later support Xen acpi pad */
165         if (!xen_running_on_version_or_later(4, 2))
166                 return -ENODEV;
167 
168         return acpi_bus_register_driver(&acpi_pad_driver);
169 }
170 subsys_initcall(xen_acpi_pad_init);
171 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us