]>
Commit | Line | Data |
---|---|---|
82cffa2e CLG |
1 | /* |
2 | * QEMU PowerPC sPAPR IRQ interface | |
3 | * | |
4 | * Copyright (c) 2018, IBM Corporation. | |
5 | * | |
6 | * This code is licensed under the GPL version 2 or later. See the | |
7 | * COPYING file in the top-level directory. | |
8 | */ | |
9 | ||
10 | #include "qemu/osdep.h" | |
11 | #include "qemu/log.h" | |
12 | #include "qemu/error-report.h" | |
13 | #include "qapi/error.h" | |
14 | #include "hw/ppc/spapr.h" | |
a28b9a5a | 15 | #include "hw/ppc/spapr_cpu_core.h" |
dcc345b6 | 16 | #include "hw/ppc/spapr_xive.h" |
82cffa2e | 17 | #include "hw/ppc/xics.h" |
a51d5afc | 18 | #include "hw/ppc/xics_spapr.h" |
273fef83 | 19 | #include "cpu-models.h" |
ef01ed9d CLG |
20 | #include "sysemu/kvm.h" |
21 | ||
22 | #include "trace.h" | |
82cffa2e | 23 | |
ce2918cb | 24 | void spapr_irq_msi_init(SpaprMachineState *spapr, uint32_t nr_msis) |
82cffa2e CLG |
25 | { |
26 | spapr->irq_map_nr = nr_msis; | |
27 | spapr->irq_map = bitmap_new(spapr->irq_map_nr); | |
28 | } | |
29 | ||
ce2918cb | 30 | int spapr_irq_msi_alloc(SpaprMachineState *spapr, uint32_t num, bool align, |
82cffa2e CLG |
31 | Error **errp) |
32 | { | |
33 | int irq; | |
34 | ||
35 | /* | |
36 | * The 'align_mask' parameter of bitmap_find_next_zero_area() | |
37 | * should be one less than a power of 2; 0 means no | |
38 | * alignment. Adapt the 'align' value of the former allocator | |
39 | * to fit the requirements of bitmap_find_next_zero_area() | |
40 | */ | |
41 | align -= 1; | |
42 | ||
43 | irq = bitmap_find_next_zero_area(spapr->irq_map, spapr->irq_map_nr, 0, num, | |
44 | align); | |
45 | if (irq == spapr->irq_map_nr) { | |
46 | error_setg(errp, "can't find a free %d-IRQ block", num); | |
47 | return -1; | |
48 | } | |
49 | ||
50 | bitmap_set(spapr->irq_map, irq, num); | |
51 | ||
52 | return irq + SPAPR_IRQ_MSI; | |
53 | } | |
54 | ||
ce2918cb | 55 | void spapr_irq_msi_free(SpaprMachineState *spapr, int irq, uint32_t num) |
82cffa2e CLG |
56 | { |
57 | bitmap_clear(spapr->irq_map, irq - SPAPR_IRQ_MSI, num); | |
58 | } | |
59 | ||
ce2918cb | 60 | void spapr_irq_msi_reset(SpaprMachineState *spapr) |
82cffa2e CLG |
61 | { |
62 | bitmap_clear(spapr->irq_map, 0, spapr->irq_map_nr); | |
63 | } | |
ef01ed9d CLG |
64 | |
65 | ||
66 | /* | |
67 | * XICS IRQ backend. | |
68 | */ | |
69 | ||
ce2918cb | 70 | static void spapr_irq_init_xics(SpaprMachineState *spapr, int nr_irqs, |
2e66cdb7 | 71 | Error **errp) |
ef01ed9d CLG |
72 | { |
73 | MachineState *machine = MACHINE(spapr); | |
f56275a2 | 74 | Object *obj; |
ef01ed9d | 75 | Error *local_err = NULL; |
444d6ca3 | 76 | bool xics_kvm = false; |
ef01ed9d | 77 | |
ef01ed9d CLG |
78 | if (kvm_enabled()) { |
79 | if (machine_kernel_irqchip_allowed(machine) && | |
80 | !xics_kvm_init(spapr, &local_err)) { | |
444d6ca3 | 81 | xics_kvm = true; |
ef01ed9d | 82 | } |
444d6ca3 | 83 | if (machine_kernel_irqchip_required(machine) && !xics_kvm) { |
ef01ed9d CLG |
84 | error_prepend(&local_err, |
85 | "kernel_irqchip requested but unavailable: "); | |
f56275a2 CLG |
86 | error_propagate(errp, local_err); |
87 | return; | |
ef01ed9d CLG |
88 | } |
89 | error_free(local_err); | |
90 | local_err = NULL; | |
91 | } | |
92 | ||
444d6ca3 | 93 | if (!xics_kvm) { |
ef01ed9d | 94 | xics_spapr_init(spapr); |
ef01ed9d CLG |
95 | } |
96 | ||
f56275a2 CLG |
97 | obj = object_new(TYPE_ICS_SIMPLE); |
98 | object_property_add_child(OBJECT(spapr), "ics", obj, &error_abort); | |
99 | object_property_add_const_link(obj, ICS_PROP_XICS, OBJECT(spapr), | |
100 | &error_fatal); | |
101 | object_property_set_int(obj, nr_irqs, "nr-irqs", &error_fatal); | |
102 | object_property_set_bool(obj, true, "realized", &local_err); | |
103 | if (local_err) { | |
104 | error_propagate(errp, local_err); | |
105 | return; | |
106 | } | |
444d6ca3 | 107 | |
f56275a2 | 108 | spapr->ics = ICS_BASE(obj); |
ef01ed9d CLG |
109 | } |
110 | ||
111 | #define ICS_IRQ_FREE(ics, srcno) \ | |
112 | (!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK))) | |
113 | ||
ce2918cb | 114 | static int spapr_irq_claim_xics(SpaprMachineState *spapr, int irq, bool lsi, |
ef01ed9d CLG |
115 | Error **errp) |
116 | { | |
117 | ICSState *ics = spapr->ics; | |
118 | ||
119 | assert(ics); | |
120 | ||
121 | if (!ics_valid_irq(ics, irq)) { | |
122 | error_setg(errp, "IRQ %d is invalid", irq); | |
123 | return -1; | |
124 | } | |
125 | ||
126 | if (!ICS_IRQ_FREE(ics, irq - ics->offset)) { | |
127 | error_setg(errp, "IRQ %d is not free", irq); | |
128 | return -1; | |
129 | } | |
130 | ||
131 | ics_set_irq_type(ics, irq - ics->offset, lsi); | |
132 | return 0; | |
133 | } | |
134 | ||
ce2918cb | 135 | static void spapr_irq_free_xics(SpaprMachineState *spapr, int irq, int num) |
ef01ed9d CLG |
136 | { |
137 | ICSState *ics = spapr->ics; | |
138 | uint32_t srcno = irq - ics->offset; | |
139 | int i; | |
140 | ||
141 | if (ics_valid_irq(ics, irq)) { | |
142 | trace_spapr_irq_free(0, irq, num); | |
143 | for (i = srcno; i < srcno + num; ++i) { | |
144 | if (ICS_IRQ_FREE(ics, i)) { | |
145 | trace_spapr_irq_free_warn(0, i); | |
146 | } | |
147 | memset(&ics->irqs[i], 0, sizeof(ICSIRQState)); | |
148 | } | |
149 | } | |
150 | } | |
151 | ||
ce2918cb | 152 | static qemu_irq spapr_qirq_xics(SpaprMachineState *spapr, int irq) |
ef01ed9d CLG |
153 | { |
154 | ICSState *ics = spapr->ics; | |
155 | uint32_t srcno = irq - ics->offset; | |
156 | ||
157 | if (ics_valid_irq(ics, irq)) { | |
872ff3de | 158 | return spapr->qirqs[srcno]; |
ef01ed9d CLG |
159 | } |
160 | ||
161 | return NULL; | |
162 | } | |
163 | ||
ce2918cb | 164 | static void spapr_irq_print_info_xics(SpaprMachineState *spapr, Monitor *mon) |
ef01ed9d CLG |
165 | { |
166 | CPUState *cs; | |
167 | ||
168 | CPU_FOREACH(cs) { | |
169 | PowerPCCPU *cpu = POWERPC_CPU(cs); | |
170 | ||
a28b9a5a | 171 | icp_pic_print_info(spapr_cpu_state(cpu)->icp, mon); |
ef01ed9d CLG |
172 | } |
173 | ||
174 | ics_pic_print_info(spapr->ics, mon); | |
175 | } | |
176 | ||
ce2918cb | 177 | static void spapr_irq_cpu_intc_create_xics(SpaprMachineState *spapr, |
8fa1f4ef | 178 | PowerPCCPU *cpu, Error **errp) |
1a937ad7 | 179 | { |
8fa1f4ef CLG |
180 | Error *local_err = NULL; |
181 | Object *obj; | |
ce2918cb | 182 | SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu); |
8fa1f4ef | 183 | |
56af6656 | 184 | obj = icp_create(OBJECT(cpu), TYPE_ICP, XICS_FABRIC(spapr), |
8fa1f4ef CLG |
185 | &local_err); |
186 | if (local_err) { | |
187 | error_propagate(errp, local_err); | |
188 | return; | |
189 | } | |
190 | ||
a28b9a5a | 191 | spapr_cpu->icp = ICP(obj); |
1a937ad7 CLG |
192 | } |
193 | ||
ce2918cb | 194 | static int spapr_irq_post_load_xics(SpaprMachineState *spapr, int version_id) |
1c53b06c | 195 | { |
3272752a | 196 | if (!kvm_irqchip_in_kernel()) { |
1c53b06c CLG |
197 | CPUState *cs; |
198 | CPU_FOREACH(cs) { | |
199 | PowerPCCPU *cpu = POWERPC_CPU(cs); | |
a28b9a5a | 200 | icp_resend(spapr_cpu_state(cpu)->icp); |
1c53b06c CLG |
201 | } |
202 | } | |
203 | return 0; | |
204 | } | |
205 | ||
872ff3de CLG |
206 | static void spapr_irq_set_irq_xics(void *opaque, int srcno, int val) |
207 | { | |
ce2918cb | 208 | SpaprMachineState *spapr = opaque; |
872ff3de | 209 | |
557b4567 | 210 | ics_simple_set_irq(spapr->ics, srcno, val); |
872ff3de CLG |
211 | } |
212 | ||
ce2918cb | 213 | static void spapr_irq_reset_xics(SpaprMachineState *spapr, Error **errp) |
13db0cd9 CLG |
214 | { |
215 | /* TODO: create the KVM XICS device */ | |
216 | } | |
217 | ||
ce2918cb | 218 | static const char *spapr_irq_get_nodename_xics(SpaprMachineState *spapr) |
743ed566 GK |
219 | { |
220 | return XICS_NODENAME; | |
221 | } | |
222 | ||
ae837402 | 223 | #define SPAPR_IRQ_XICS_NR_IRQS 0x1000 |
e39de895 CLG |
224 | #define SPAPR_IRQ_XICS_NR_MSIS \ |
225 | (XICS_IRQ_BASE + SPAPR_IRQ_XICS_NR_IRQS - SPAPR_IRQ_MSI) | |
226 | ||
ce2918cb | 227 | SpaprIrq spapr_irq_xics = { |
e39de895 CLG |
228 | .nr_irqs = SPAPR_IRQ_XICS_NR_IRQS, |
229 | .nr_msis = SPAPR_IRQ_XICS_NR_MSIS, | |
db592b5b | 230 | .ov5 = SPAPR_OV5_XIVE_LEGACY, |
ef01ed9d CLG |
231 | |
232 | .init = spapr_irq_init_xics, | |
233 | .claim = spapr_irq_claim_xics, | |
234 | .free = spapr_irq_free_xics, | |
235 | .qirq = spapr_qirq_xics, | |
236 | .print_info = spapr_irq_print_info_xics, | |
6e21de4a | 237 | .dt_populate = spapr_dt_xics, |
1a937ad7 | 238 | .cpu_intc_create = spapr_irq_cpu_intc_create_xics, |
1c53b06c | 239 | .post_load = spapr_irq_post_load_xics, |
13db0cd9 | 240 | .reset = spapr_irq_reset_xics, |
872ff3de | 241 | .set_irq = spapr_irq_set_irq_xics, |
743ed566 | 242 | .get_nodename = spapr_irq_get_nodename_xics, |
ef01ed9d CLG |
243 | }; |
244 | ||
dcc345b6 CLG |
245 | /* |
246 | * XIVE IRQ backend. | |
247 | */ | |
ce2918cb | 248 | static void spapr_irq_init_xive(SpaprMachineState *spapr, int nr_irqs, |
2e66cdb7 | 249 | Error **errp) |
dcc345b6 CLG |
250 | { |
251 | MachineState *machine = MACHINE(spapr); | |
dcc345b6 CLG |
252 | uint32_t nr_servers = spapr_max_server_number(spapr); |
253 | DeviceState *dev; | |
254 | int i; | |
255 | ||
256 | /* KVM XIVE device not yet available */ | |
257 | if (kvm_enabled()) { | |
258 | if (machine_kernel_irqchip_required(machine)) { | |
259 | error_setg(errp, "kernel_irqchip requested. no KVM XIVE support"); | |
260 | return; | |
261 | } | |
262 | } | |
263 | ||
264 | dev = qdev_create(NULL, TYPE_SPAPR_XIVE); | |
2e66cdb7 | 265 | qdev_prop_set_uint32(dev, "nr-irqs", nr_irqs); |
dcc345b6 CLG |
266 | /* |
267 | * 8 XIVE END structures per CPU. One for each available priority | |
268 | */ | |
269 | qdev_prop_set_uint32(dev, "nr-ends", nr_servers << 3); | |
270 | qdev_init_nofail(dev); | |
271 | ||
272 | spapr->xive = SPAPR_XIVE(dev); | |
273 | ||
274 | /* Enable the CPU IPIs */ | |
275 | for (i = 0; i < nr_servers; ++i) { | |
276 | spapr_xive_irq_claim(spapr->xive, SPAPR_IRQ_IPI + i, false); | |
277 | } | |
23bcd5eb CLG |
278 | |
279 | spapr_xive_hcall_init(spapr); | |
dcc345b6 CLG |
280 | } |
281 | ||
ce2918cb | 282 | static int spapr_irq_claim_xive(SpaprMachineState *spapr, int irq, bool lsi, |
dcc345b6 CLG |
283 | Error **errp) |
284 | { | |
285 | if (!spapr_xive_irq_claim(spapr->xive, irq, lsi)) { | |
286 | error_setg(errp, "IRQ %d is invalid", irq); | |
287 | return -1; | |
288 | } | |
289 | return 0; | |
290 | } | |
291 | ||
ce2918cb | 292 | static void spapr_irq_free_xive(SpaprMachineState *spapr, int irq, int num) |
dcc345b6 CLG |
293 | { |
294 | int i; | |
295 | ||
296 | for (i = irq; i < irq + num; ++i) { | |
297 | spapr_xive_irq_free(spapr->xive, i); | |
298 | } | |
299 | } | |
300 | ||
ce2918cb | 301 | static qemu_irq spapr_qirq_xive(SpaprMachineState *spapr, int irq) |
dcc345b6 | 302 | { |
ce2918cb | 303 | SpaprXive *xive = spapr->xive; |
a0c493ae CLG |
304 | |
305 | if (irq >= xive->nr_irqs) { | |
306 | return NULL; | |
307 | } | |
308 | ||
309 | /* The sPAPR machine/device should have claimed the IRQ before */ | |
310 | assert(xive_eas_is_valid(&xive->eat[irq])); | |
311 | ||
872ff3de | 312 | return spapr->qirqs[irq]; |
dcc345b6 CLG |
313 | } |
314 | ||
ce2918cb | 315 | static void spapr_irq_print_info_xive(SpaprMachineState *spapr, |
dcc345b6 CLG |
316 | Monitor *mon) |
317 | { | |
318 | CPUState *cs; | |
319 | ||
320 | CPU_FOREACH(cs) { | |
321 | PowerPCCPU *cpu = POWERPC_CPU(cs); | |
322 | ||
a28b9a5a | 323 | xive_tctx_pic_print_info(spapr_cpu_state(cpu)->tctx, mon); |
dcc345b6 CLG |
324 | } |
325 | ||
326 | spapr_xive_pic_print_info(spapr->xive, mon); | |
327 | } | |
328 | ||
ce2918cb | 329 | static void spapr_irq_cpu_intc_create_xive(SpaprMachineState *spapr, |
8fa1f4ef | 330 | PowerPCCPU *cpu, Error **errp) |
1a937ad7 | 331 | { |
8fa1f4ef CLG |
332 | Error *local_err = NULL; |
333 | Object *obj; | |
ce2918cb | 334 | SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu); |
8fa1f4ef CLG |
335 | |
336 | obj = xive_tctx_create(OBJECT(cpu), XIVE_ROUTER(spapr->xive), &local_err); | |
337 | if (local_err) { | |
338 | error_propagate(errp, local_err); | |
339 | return; | |
340 | } | |
341 | ||
a28b9a5a | 342 | spapr_cpu->tctx = XIVE_TCTX(obj); |
b2e22477 CLG |
343 | |
344 | /* | |
345 | * (TCG) Early setting the OS CAM line for hotplugged CPUs as they | |
8fa1f4ef | 346 | * don't beneficiate from the reset of the XIVE IRQ backend |
b2e22477 | 347 | */ |
a28b9a5a | 348 | spapr_xive_set_tctx_os_cam(spapr_cpu->tctx); |
1a937ad7 CLG |
349 | } |
350 | ||
ce2918cb | 351 | static int spapr_irq_post_load_xive(SpaprMachineState *spapr, int version_id) |
1c53b06c | 352 | { |
277dd3d7 | 353 | return spapr_xive_post_load(spapr->xive, version_id); |
1c53b06c CLG |
354 | } |
355 | ||
ce2918cb | 356 | static void spapr_irq_reset_xive(SpaprMachineState *spapr, Error **errp) |
b2e22477 CLG |
357 | { |
358 | CPUState *cs; | |
359 | ||
360 | CPU_FOREACH(cs) { | |
361 | PowerPCCPU *cpu = POWERPC_CPU(cs); | |
362 | ||
363 | /* (TCG) Set the OS CAM line of the thread interrupt context. */ | |
a28b9a5a | 364 | spapr_xive_set_tctx_os_cam(spapr_cpu_state(cpu)->tctx); |
b2e22477 | 365 | } |
3a8eb78e CLG |
366 | |
367 | /* Activate the XIVE MMIOs */ | |
368 | spapr_xive_mmio_set_enabled(spapr->xive, true); | |
b2e22477 CLG |
369 | } |
370 | ||
872ff3de CLG |
371 | static void spapr_irq_set_irq_xive(void *opaque, int srcno, int val) |
372 | { | |
ce2918cb | 373 | SpaprMachineState *spapr = opaque; |
872ff3de | 374 | |
38afd772 CLG |
375 | if (kvm_irqchip_in_kernel()) { |
376 | kvmppc_xive_source_set_irq(&spapr->xive->source, srcno, val); | |
377 | } else { | |
378 | xive_source_set_irq(&spapr->xive->source, srcno, val); | |
379 | } | |
872ff3de CLG |
380 | } |
381 | ||
ce2918cb | 382 | static const char *spapr_irq_get_nodename_xive(SpaprMachineState *spapr) |
743ed566 GK |
383 | { |
384 | return spapr->xive->nodename; | |
385 | } | |
386 | ||
dcc345b6 CLG |
387 | /* |
388 | * XIVE uses the full IRQ number space. Set it to 8K to be compatible | |
389 | * with XICS. | |
390 | */ | |
391 | ||
392 | #define SPAPR_IRQ_XIVE_NR_IRQS 0x2000 | |
393 | #define SPAPR_IRQ_XIVE_NR_MSIS (SPAPR_IRQ_XIVE_NR_IRQS - SPAPR_IRQ_MSI) | |
394 | ||
ce2918cb | 395 | SpaprIrq spapr_irq_xive = { |
dcc345b6 CLG |
396 | .nr_irqs = SPAPR_IRQ_XIVE_NR_IRQS, |
397 | .nr_msis = SPAPR_IRQ_XIVE_NR_MSIS, | |
db592b5b | 398 | .ov5 = SPAPR_OV5_XIVE_EXPLOIT, |
dcc345b6 CLG |
399 | |
400 | .init = spapr_irq_init_xive, | |
401 | .claim = spapr_irq_claim_xive, | |
402 | .free = spapr_irq_free_xive, | |
403 | .qirq = spapr_qirq_xive, | |
404 | .print_info = spapr_irq_print_info_xive, | |
6e21de4a | 405 | .dt_populate = spapr_dt_xive, |
1a937ad7 | 406 | .cpu_intc_create = spapr_irq_cpu_intc_create_xive, |
1c53b06c | 407 | .post_load = spapr_irq_post_load_xive, |
b2e22477 | 408 | .reset = spapr_irq_reset_xive, |
872ff3de | 409 | .set_irq = spapr_irq_set_irq_xive, |
743ed566 | 410 | .get_nodename = spapr_irq_get_nodename_xive, |
dcc345b6 CLG |
411 | }; |
412 | ||
13db0cd9 CLG |
413 | /* |
414 | * Dual XIVE and XICS IRQ backend. | |
415 | * | |
416 | * Both interrupt mode, XIVE and XICS, objects are created but the | |
417 | * machine starts in legacy interrupt mode (XICS). It can be changed | |
418 | * by the CAS negotiation process and, in that case, the new mode is | |
419 | * activated after an extra machine reset. | |
420 | */ | |
421 | ||
422 | /* | |
423 | * Returns the sPAPR IRQ backend negotiated by CAS. XICS is the | |
424 | * default. | |
425 | */ | |
ce2918cb | 426 | static SpaprIrq *spapr_irq_current(SpaprMachineState *spapr) |
13db0cd9 CLG |
427 | { |
428 | return spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT) ? | |
429 | &spapr_irq_xive : &spapr_irq_xics; | |
430 | } | |
431 | ||
ce2918cb | 432 | static void spapr_irq_init_dual(SpaprMachineState *spapr, int nr_irqs, |
2e66cdb7 | 433 | Error **errp) |
13db0cd9 CLG |
434 | { |
435 | MachineState *machine = MACHINE(spapr); | |
436 | Error *local_err = NULL; | |
437 | ||
438 | if (kvm_enabled() && machine_kernel_irqchip_allowed(machine)) { | |
439 | error_setg(errp, "No KVM support for the 'dual' machine"); | |
440 | return; | |
441 | } | |
442 | ||
2e66cdb7 | 443 | spapr_irq_xics.init(spapr, spapr_irq_xics.nr_irqs, &local_err); |
13db0cd9 CLG |
444 | if (local_err) { |
445 | error_propagate(errp, local_err); | |
446 | return; | |
447 | } | |
448 | ||
2e66cdb7 | 449 | spapr_irq_xive.init(spapr, spapr_irq_xive.nr_irqs, &local_err); |
13db0cd9 CLG |
450 | if (local_err) { |
451 | error_propagate(errp, local_err); | |
452 | return; | |
453 | } | |
454 | } | |
455 | ||
ce2918cb | 456 | static int spapr_irq_claim_dual(SpaprMachineState *spapr, int irq, bool lsi, |
13db0cd9 CLG |
457 | Error **errp) |
458 | { | |
459 | Error *local_err = NULL; | |
460 | int ret; | |
461 | ||
462 | ret = spapr_irq_xics.claim(spapr, irq, lsi, &local_err); | |
463 | if (local_err) { | |
464 | error_propagate(errp, local_err); | |
465 | return ret; | |
466 | } | |
467 | ||
468 | ret = spapr_irq_xive.claim(spapr, irq, lsi, &local_err); | |
469 | if (local_err) { | |
470 | error_propagate(errp, local_err); | |
471 | return ret; | |
472 | } | |
473 | ||
474 | return ret; | |
475 | } | |
476 | ||
ce2918cb | 477 | static void spapr_irq_free_dual(SpaprMachineState *spapr, int irq, int num) |
13db0cd9 CLG |
478 | { |
479 | spapr_irq_xics.free(spapr, irq, num); | |
480 | spapr_irq_xive.free(spapr, irq, num); | |
481 | } | |
482 | ||
ce2918cb | 483 | static qemu_irq spapr_qirq_dual(SpaprMachineState *spapr, int irq) |
13db0cd9 | 484 | { |
3a0d802c | 485 | return spapr_irq_current(spapr)->qirq(spapr, irq); |
13db0cd9 CLG |
486 | } |
487 | ||
ce2918cb | 488 | static void spapr_irq_print_info_dual(SpaprMachineState *spapr, Monitor *mon) |
13db0cd9 CLG |
489 | { |
490 | spapr_irq_current(spapr)->print_info(spapr, mon); | |
491 | } | |
492 | ||
ce2918cb | 493 | static void spapr_irq_dt_populate_dual(SpaprMachineState *spapr, |
13db0cd9 CLG |
494 | uint32_t nr_servers, void *fdt, |
495 | uint32_t phandle) | |
496 | { | |
497 | spapr_irq_current(spapr)->dt_populate(spapr, nr_servers, fdt, phandle); | |
498 | } | |
499 | ||
ce2918cb | 500 | static void spapr_irq_cpu_intc_create_dual(SpaprMachineState *spapr, |
13db0cd9 CLG |
501 | PowerPCCPU *cpu, Error **errp) |
502 | { | |
503 | Error *local_err = NULL; | |
504 | ||
505 | spapr_irq_xive.cpu_intc_create(spapr, cpu, &local_err); | |
506 | if (local_err) { | |
507 | error_propagate(errp, local_err); | |
508 | return; | |
509 | } | |
510 | ||
511 | spapr_irq_xics.cpu_intc_create(spapr, cpu, errp); | |
512 | } | |
513 | ||
ce2918cb | 514 | static int spapr_irq_post_load_dual(SpaprMachineState *spapr, int version_id) |
13db0cd9 CLG |
515 | { |
516 | /* | |
517 | * Force a reset of the XIVE backend after migration. The machine | |
518 | * defaults to XICS at startup. | |
519 | */ | |
520 | if (spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) { | |
521 | spapr_irq_xive.reset(spapr, &error_fatal); | |
522 | } | |
523 | ||
524 | return spapr_irq_current(spapr)->post_load(spapr, version_id); | |
525 | } | |
526 | ||
ce2918cb | 527 | static void spapr_irq_reset_dual(SpaprMachineState *spapr, Error **errp) |
13db0cd9 | 528 | { |
3a8eb78e CLG |
529 | /* |
530 | * Deactivate the XIVE MMIOs. The XIVE backend will reenable them | |
531 | * if selected. | |
532 | */ | |
533 | spapr_xive_mmio_set_enabled(spapr->xive, false); | |
534 | ||
13db0cd9 CLG |
535 | spapr_irq_current(spapr)->reset(spapr, errp); |
536 | } | |
537 | ||
538 | static void spapr_irq_set_irq_dual(void *opaque, int srcno, int val) | |
539 | { | |
ce2918cb | 540 | SpaprMachineState *spapr = opaque; |
13db0cd9 CLG |
541 | |
542 | spapr_irq_current(spapr)->set_irq(spapr, srcno, val); | |
543 | } | |
544 | ||
ce2918cb | 545 | static const char *spapr_irq_get_nodename_dual(SpaprMachineState *spapr) |
743ed566 GK |
546 | { |
547 | return spapr_irq_current(spapr)->get_nodename(spapr); | |
548 | } | |
549 | ||
13db0cd9 CLG |
550 | /* |
551 | * Define values in sync with the XIVE and XICS backend | |
552 | */ | |
553 | #define SPAPR_IRQ_DUAL_NR_IRQS 0x2000 | |
554 | #define SPAPR_IRQ_DUAL_NR_MSIS (SPAPR_IRQ_DUAL_NR_IRQS - SPAPR_IRQ_MSI) | |
555 | ||
ce2918cb | 556 | SpaprIrq spapr_irq_dual = { |
13db0cd9 CLG |
557 | .nr_irqs = SPAPR_IRQ_DUAL_NR_IRQS, |
558 | .nr_msis = SPAPR_IRQ_DUAL_NR_MSIS, | |
559 | .ov5 = SPAPR_OV5_XIVE_BOTH, | |
560 | ||
561 | .init = spapr_irq_init_dual, | |
562 | .claim = spapr_irq_claim_dual, | |
563 | .free = spapr_irq_free_dual, | |
564 | .qirq = spapr_qirq_dual, | |
565 | .print_info = spapr_irq_print_info_dual, | |
566 | .dt_populate = spapr_irq_dt_populate_dual, | |
567 | .cpu_intc_create = spapr_irq_cpu_intc_create_dual, | |
568 | .post_load = spapr_irq_post_load_dual, | |
569 | .reset = spapr_irq_reset_dual, | |
743ed566 GK |
570 | .set_irq = spapr_irq_set_irq_dual, |
571 | .get_nodename = spapr_irq_get_nodename_dual, | |
13db0cd9 CLG |
572 | }; |
573 | ||
273fef83 CLG |
574 | |
575 | static void spapr_irq_check(SpaprMachineState *spapr, Error **errp) | |
576 | { | |
577 | MachineState *machine = MACHINE(spapr); | |
578 | ||
579 | /* | |
580 | * Sanity checks on non-P9 machines. On these, XIVE is not | |
581 | * advertised, see spapr_dt_ov5_platform_support() | |
582 | */ | |
583 | if (!ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, | |
584 | 0, spapr->max_compat_pvr)) { | |
585 | /* | |
586 | * If the 'dual' interrupt mode is selected, force XICS as CAS | |
587 | * negotiation is useless. | |
588 | */ | |
589 | if (spapr->irq == &spapr_irq_dual) { | |
590 | spapr->irq = &spapr_irq_xics; | |
591 | return; | |
592 | } | |
593 | ||
594 | /* | |
595 | * Non-P9 machines using only XIVE is a bogus setup. We have two | |
596 | * scenarios to take into account because of the compat mode: | |
597 | * | |
598 | * 1. POWER7/8 machines should fail to init later on when creating | |
599 | * the XIVE interrupt presenters because a POWER9 exception | |
600 | * model is required. | |
601 | ||
602 | * 2. POWER9 machines using the POWER8 compat mode won't fail and | |
603 | * will let the OS boot with a partial XIVE setup : DT | |
604 | * properties but no hcalls. | |
605 | * | |
606 | * To cover both and not confuse the OS, add an early failure in | |
607 | * QEMU. | |
608 | */ | |
609 | if (spapr->irq == &spapr_irq_xive) { | |
610 | error_setg(errp, "XIVE-only machines require a POWER9 CPU"); | |
611 | return; | |
612 | } | |
613 | } | |
614 | } | |
615 | ||
ef01ed9d CLG |
616 | /* |
617 | * sPAPR IRQ frontend routines for devices | |
618 | */ | |
ce2918cb | 619 | void spapr_irq_init(SpaprMachineState *spapr, Error **errp) |
fab397d8 | 620 | { |
1a511340 | 621 | MachineState *machine = MACHINE(spapr); |
273fef83 | 622 | Error *local_err = NULL; |
1a511340 GK |
623 | |
624 | if (machine_kernel_irqchip_split(machine)) { | |
625 | error_setg(errp, "kernel_irqchip split mode not supported on pseries"); | |
626 | return; | |
627 | } | |
628 | ||
629 | if (!kvm_enabled() && machine_kernel_irqchip_required(machine)) { | |
630 | error_setg(errp, | |
631 | "kernel_irqchip requested but only available with KVM"); | |
632 | return; | |
633 | } | |
634 | ||
273fef83 CLG |
635 | spapr_irq_check(spapr, &local_err); |
636 | if (local_err) { | |
637 | error_propagate(errp, local_err); | |
638 | return; | |
639 | } | |
640 | ||
fab397d8 CLG |
641 | /* Initialize the MSI IRQ allocator. */ |
642 | if (!SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) { | |
3ba3d0bc | 643 | spapr_irq_msi_init(spapr, spapr->irq->nr_msis); |
fab397d8 CLG |
644 | } |
645 | ||
2e66cdb7 | 646 | spapr->irq->init(spapr, spapr->irq->nr_irqs, errp); |
872ff3de CLG |
647 | |
648 | spapr->qirqs = qemu_allocate_irqs(spapr->irq->set_irq, spapr, | |
649 | spapr->irq->nr_irqs); | |
fab397d8 | 650 | } |
ef01ed9d | 651 | |
ce2918cb | 652 | int spapr_irq_claim(SpaprMachineState *spapr, int irq, bool lsi, Error **errp) |
ef01ed9d | 653 | { |
3ba3d0bc | 654 | return spapr->irq->claim(spapr, irq, lsi, errp); |
ef01ed9d CLG |
655 | } |
656 | ||
ce2918cb | 657 | void spapr_irq_free(SpaprMachineState *spapr, int irq, int num) |
ef01ed9d | 658 | { |
3ba3d0bc | 659 | spapr->irq->free(spapr, irq, num); |
ef01ed9d CLG |
660 | } |
661 | ||
ce2918cb | 662 | qemu_irq spapr_qirq(SpaprMachineState *spapr, int irq) |
ef01ed9d | 663 | { |
3ba3d0bc | 664 | return spapr->irq->qirq(spapr, irq); |
ef01ed9d CLG |
665 | } |
666 | ||
ce2918cb | 667 | int spapr_irq_post_load(SpaprMachineState *spapr, int version_id) |
1c53b06c | 668 | { |
3ba3d0bc | 669 | return spapr->irq->post_load(spapr, version_id); |
1c53b06c CLG |
670 | } |
671 | ||
ce2918cb | 672 | void spapr_irq_reset(SpaprMachineState *spapr, Error **errp) |
b2e22477 | 673 | { |
3ba3d0bc CLG |
674 | if (spapr->irq->reset) { |
675 | spapr->irq->reset(spapr, errp); | |
b2e22477 CLG |
676 | } |
677 | } | |
678 | ||
ce2918cb | 679 | int spapr_irq_get_phandle(SpaprMachineState *spapr, void *fdt, Error **errp) |
ad62bff6 GK |
680 | { |
681 | const char *nodename = spapr->irq->get_nodename(spapr); | |
682 | int offset, phandle; | |
683 | ||
684 | offset = fdt_subnode_offset(fdt, 0, nodename); | |
685 | if (offset < 0) { | |
686 | error_setg(errp, "Can't find node \"%s\": %s", nodename, | |
687 | fdt_strerror(offset)); | |
688 | return -1; | |
689 | } | |
690 | ||
691 | phandle = fdt_get_phandle(fdt, offset); | |
692 | if (!phandle) { | |
693 | error_setg(errp, "Can't get phandle of node \"%s\"", nodename); | |
694 | return -1; | |
695 | } | |
696 | ||
697 | return phandle; | |
698 | } | |
699 | ||
ef01ed9d CLG |
700 | /* |
701 | * XICS legacy routines - to deprecate one day | |
702 | */ | |
703 | ||
704 | static int ics_find_free_block(ICSState *ics, int num, int alignnum) | |
705 | { | |
706 | int first, i; | |
707 | ||
708 | for (first = 0; first < ics->nr_irqs; first += alignnum) { | |
709 | if (num > (ics->nr_irqs - first)) { | |
710 | return -1; | |
711 | } | |
712 | for (i = first; i < first + num; ++i) { | |
713 | if (!ICS_IRQ_FREE(ics, i)) { | |
714 | break; | |
715 | } | |
716 | } | |
717 | if (i == (first + num)) { | |
718 | return first; | |
719 | } | |
720 | } | |
721 | ||
722 | return -1; | |
723 | } | |
724 | ||
ce2918cb | 725 | int spapr_irq_find(SpaprMachineState *spapr, int num, bool align, Error **errp) |
ef01ed9d CLG |
726 | { |
727 | ICSState *ics = spapr->ics; | |
728 | int first = -1; | |
729 | ||
730 | assert(ics); | |
731 | ||
732 | /* | |
733 | * MSIMesage::data is used for storing VIRQ so | |
734 | * it has to be aligned to num to support multiple | |
735 | * MSI vectors. MSI-X is not affected by this. | |
736 | * The hint is used for the first IRQ, the rest should | |
737 | * be allocated continuously. | |
738 | */ | |
739 | if (align) { | |
740 | assert((num == 1) || (num == 2) || (num == 4) || | |
741 | (num == 8) || (num == 16) || (num == 32)); | |
742 | first = ics_find_free_block(ics, num, num); | |
743 | } else { | |
744 | first = ics_find_free_block(ics, num, 1); | |
745 | } | |
746 | ||
747 | if (first < 0) { | |
748 | error_setg(errp, "can't find a free %d-IRQ block", num); | |
749 | return -1; | |
750 | } | |
751 | ||
752 | return first + ics->offset; | |
753 | } | |
ae837402 CLG |
754 | |
755 | #define SPAPR_IRQ_XICS_LEGACY_NR_IRQS 0x400 | |
756 | ||
ce2918cb | 757 | SpaprIrq spapr_irq_xics_legacy = { |
ae837402 CLG |
758 | .nr_irqs = SPAPR_IRQ_XICS_LEGACY_NR_IRQS, |
759 | .nr_msis = SPAPR_IRQ_XICS_LEGACY_NR_IRQS, | |
db592b5b | 760 | .ov5 = SPAPR_OV5_XIVE_LEGACY, |
ae837402 CLG |
761 | |
762 | .init = spapr_irq_init_xics, | |
763 | .claim = spapr_irq_claim_xics, | |
764 | .free = spapr_irq_free_xics, | |
765 | .qirq = spapr_qirq_xics, | |
766 | .print_info = spapr_irq_print_info_xics, | |
6e21de4a | 767 | .dt_populate = spapr_dt_xics, |
1a937ad7 | 768 | .cpu_intc_create = spapr_irq_cpu_intc_create_xics, |
1c53b06c | 769 | .post_load = spapr_irq_post_load_xics, |
872ff3de | 770 | .set_irq = spapr_irq_set_irq_xics, |
743ed566 | 771 | .get_nodename = spapr_irq_get_nodename_xics, |
ae837402 | 772 | }; |