Blame view

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