]> Git Repo - qemu.git/blame - hw/acpi/cpu.c
pc: acpi: introduce AcpiDeviceIfClass.madt_cpu hook
[qemu.git] / hw / acpi / cpu.c
CommitLineData
5e1b5d93
IM
1#include "qemu/osdep.h"
2#include "hw/boards.h"
3#include "hw/acpi/cpu.h"
4#include "qapi/error.h"
5#include "trace.h"
6
7#define ACPI_CPU_HOTPLUG_REG_LEN 12
8#define ACPI_CPU_SELECTOR_OFFSET_WR 0
9#define ACPI_CPU_FLAGS_OFFSET_RW 4
10
11static uint64_t cpu_hotplug_rd(void *opaque, hwaddr addr, unsigned size)
12{
13 uint64_t val = 0;
14 CPUHotplugState *cpu_st = opaque;
15 AcpiCpuStatus *cdev;
16
17 if (cpu_st->selector >= cpu_st->dev_count) {
18 return val;
19 }
20
21 cdev = &cpu_st->devs[cpu_st->selector];
22 switch (addr) {
23 case ACPI_CPU_FLAGS_OFFSET_RW: /* pack and return is_* fields */
24 val |= cdev->cpu ? 1 : 0;
25 trace_cpuhp_acpi_read_flags(cpu_st->selector, val);
26 break;
27 default:
28 break;
29 }
30 return val;
31}
32
33static void cpu_hotplug_wr(void *opaque, hwaddr addr, uint64_t data,
34 unsigned int size)
35{
36 CPUHotplugState *cpu_st = opaque;
37
38 assert(cpu_st->dev_count);
39
40 if (addr) {
41 if (cpu_st->selector >= cpu_st->dev_count) {
42 trace_cpuhp_acpi_invalid_idx_selected(cpu_st->selector);
43 return;
44 }
45 }
46
47 switch (addr) {
48 case ACPI_CPU_SELECTOR_OFFSET_WR: /* current CPU selector */
49 cpu_st->selector = data;
50 trace_cpuhp_acpi_write_idx(cpu_st->selector);
51 break;
52 default:
53 break;
54 }
55}
56
57static const MemoryRegionOps cpu_hotplug_ops = {
58 .read = cpu_hotplug_rd,
59 .write = cpu_hotplug_wr,
60 .endianness = DEVICE_LITTLE_ENDIAN,
61 .valid = {
62 .min_access_size = 1,
63 .max_access_size = 4,
64 },
65};
66
67void cpu_hotplug_hw_init(MemoryRegion *as, Object *owner,
68 CPUHotplugState *state, hwaddr base_addr)
69{
70 MachineState *machine = MACHINE(qdev_get_machine());
71 MachineClass *mc = MACHINE_GET_CLASS(machine);
72 CPUArchIdList *id_list;
73 int i;
74
75 assert(mc->possible_cpu_arch_ids);
76 id_list = mc->possible_cpu_arch_ids(machine);
77 state->dev_count = id_list->len;
78 state->devs = g_new0(typeof(*state->devs), state->dev_count);
79 for (i = 0; i < id_list->len; i++) {
80 state->devs[i].cpu = id_list->cpus[i].cpu;
81 state->devs[i].arch_id = id_list->cpus[i].arch_id;
82 }
83 g_free(id_list);
84 memory_region_init_io(&state->ctrl_reg, owner, &cpu_hotplug_ops, state,
85 "acpi-mem-hotplug", ACPI_CPU_HOTPLUG_REG_LEN);
86 memory_region_add_subregion(as, base_addr, &state->ctrl_reg);
87}
88
89static AcpiCpuStatus *get_cpu_status(CPUHotplugState *cpu_st, DeviceState *dev)
90{
91 CPUClass *k = CPU_GET_CLASS(dev);
92 uint64_t cpu_arch_id = k->get_arch_id(CPU(dev));
93 int i;
94
95 for (i = 0; i < cpu_st->dev_count; i++) {
96 if (cpu_arch_id == cpu_st->devs[i].arch_id) {
97 return &cpu_st->devs[i];
98 }
99 }
100 return NULL;
101}
102
103void acpi_cpu_plug_cb(HotplugHandler *hotplug_dev,
104 CPUHotplugState *cpu_st, DeviceState *dev, Error **errp)
105{
106 AcpiCpuStatus *cdev;
107
108 cdev = get_cpu_status(cpu_st, dev);
109 if (!cdev) {
110 return;
111 }
112
113 cdev->cpu = CPU(dev);
114}
115
116const VMStateDescription vmstate_cpu_hotplug = {
117 .name = "CPU hotplug state",
118 .version_id = 1,
119 .minimum_version_id = 1,
120 .minimum_version_id_old = 1,
121 .fields = (VMStateField[]) {
122 VMSTATE_UINT32(selector, CPUHotplugState),
123 VMSTATE_END_OF_LIST()
124 }
125};
126
127#define CPU_NAME_FMT "C%.03X"
128#define CPUHP_RES_DEVICE "PRES"
129#define CPU_LOCK "CPLK"
130#define CPU_STS_METHOD "CSTA"
131
132#define CPU_ENABLED "CPEN"
133#define CPU_SELECTOR "CSEL"
134
135void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
136 hwaddr io_base,
137 const char *res_root)
138{
139 Aml *ifctx;
140 Aml *field;
141 Aml *method;
142 Aml *cpu_ctrl_dev;
143 Aml *cpus_dev;
144 Aml *zero = aml_int(0);
145 Aml *one = aml_int(1);
146 Aml *sb_scope = aml_scope("_SB");
147 MachineClass *mc = MACHINE_GET_CLASS(machine);
148 CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(machine);
149 char *cphp_res_path = g_strdup_printf("%s." CPUHP_RES_DEVICE, res_root);
150
151 cpu_ctrl_dev = aml_device("%s", cphp_res_path);
152 {
153 Aml *crs;
154
155 aml_append(cpu_ctrl_dev,
156 aml_name_decl("_HID", aml_eisaid("PNP0A06")));
157 aml_append(cpu_ctrl_dev,
158 aml_name_decl("_UID", aml_string("CPU Hotplug resources")));
159 aml_append(cpu_ctrl_dev, aml_mutex(CPU_LOCK, 0));
160
161 crs = aml_resource_template();
162 aml_append(crs, aml_io(AML_DECODE16, io_base, io_base, 1,
163 ACPI_CPU_HOTPLUG_REG_LEN));
164 aml_append(cpu_ctrl_dev, aml_name_decl("_CRS", crs));
165
166 /* declare CPU hotplug MMIO region with related access fields */
167 aml_append(cpu_ctrl_dev,
168 aml_operation_region("PRST", AML_SYSTEM_IO, aml_int(io_base),
169 ACPI_CPU_HOTPLUG_REG_LEN));
170
171 field = aml_field("PRST", AML_BYTE_ACC, AML_NOLOCK,
172 AML_WRITE_AS_ZEROS);
173 aml_append(field, aml_reserved_field(ACPI_CPU_FLAGS_OFFSET_RW * 8));
174 /* 1 if enabled, read only */
175 aml_append(field, aml_named_field(CPU_ENABLED, 1));
176 aml_append(cpu_ctrl_dev, field);
177
178 field = aml_field("PRST", AML_DWORD_ACC, AML_NOLOCK, AML_PRESERVE);
179 /* CPU selector, write only */
180 aml_append(field, aml_named_field(CPU_SELECTOR, 32));
181 aml_append(cpu_ctrl_dev, field);
182
183 }
184 aml_append(sb_scope, cpu_ctrl_dev);
185
186 cpus_dev = aml_device("\\_SB.CPUS");
187 {
188 int i;
189 Aml *ctrl_lock = aml_name("%s.%s", cphp_res_path, CPU_LOCK);
190 Aml *cpu_selector = aml_name("%s.%s", cphp_res_path, CPU_SELECTOR);
191 Aml *is_enabled = aml_name("%s.%s", cphp_res_path, CPU_ENABLED);
192
193 aml_append(cpus_dev, aml_name_decl("_HID", aml_string("ACPI0010")));
194 aml_append(cpus_dev, aml_name_decl("_CID", aml_eisaid("PNP0A05")));
195
196 method = aml_method(CPU_STS_METHOD, 1, AML_SERIALIZED);
197 {
198 Aml *idx = aml_arg(0);
199 Aml *sta = aml_local(0);
200
201 aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
202 aml_append(method, aml_store(idx, cpu_selector));
203 aml_append(method, aml_store(zero, sta));
204 ifctx = aml_if(aml_equal(is_enabled, one));
205 {
206 aml_append(ifctx, aml_store(aml_int(0xF), sta));
207 }
208 aml_append(method, ifctx);
209 aml_append(method, aml_release(ctrl_lock));
210 aml_append(method, aml_return(sta));
211 }
212 aml_append(cpus_dev, method);
213
214 /* build Processor object for each processor */
215 for (i = 0; i < arch_ids->len; i++) {
216 Aml *dev;
217 Aml *uid = aml_int(i);
218 int arch_id = arch_ids->cpus[i].arch_id;
219
220 if (opts.apci_1_compatible && arch_id < 255) {
221 dev = aml_processor(i, 0, 0, CPU_NAME_FMT, i);
222 } else {
223 dev = aml_device(CPU_NAME_FMT, i);
224 aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0007")));
225 aml_append(dev, aml_name_decl("_UID", uid));
226 }
227
228 method = aml_method("_STA", 0, AML_SERIALIZED);
229 aml_append(method, aml_return(aml_call1(CPU_STS_METHOD, uid)));
230 aml_append(dev, method);
231
232 aml_append(cpus_dev, dev);
233 }
234 }
235 aml_append(sb_scope, cpus_dev);
236 aml_append(table, sb_scope);
237
238 g_free(cphp_res_path);
239 g_free(arch_ids);
240}
This page took 0.045485 seconds and 4 git commands to generate.