xen-acpi-pad.c 4.5 KB

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