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

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. xen_acpi_pad_idle_cpus
  2. xen_acpi_pad_idle_cpus_num
  3. acpi_pad_pur
  4. acpi_pad_handle_notify
  5. acpi_pad_notify
  6. acpi_pad_add
  7. acpi_pad_remove
  8. xen_acpi_pad_init

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

/* [<][>][^][v][top][bottom][index][help] */