]>
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 CLG |
352 | { |
353 | return 0; | |
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 CLG |
374 | |
375 | xive_source_set_irq(&spapr->xive->source, srcno, val); | |
376 | } | |
377 | ||
ce2918cb | 378 | static const char *spapr_irq_get_nodename_xive(SpaprMachineState *spapr) |
743ed566 GK |
379 | { |
380 | return spapr->xive->nodename; | |
381 | } | |
382 | ||
dcc345b6 CLG |
383 | /* |
384 | * XIVE uses the full IRQ number space. Set it to 8K to be compatible | |
385 | * with XICS. | |
386 | */ | |
387 | ||
388 | #define SPAPR_IRQ_XIVE_NR_IRQS 0x2000 | |
389 | #define SPAPR_IRQ_XIVE_NR_MSIS (SPAPR_IRQ_XIVE_NR_IRQS - SPAPR_IRQ_MSI) | |
390 | ||
ce2918cb | 391 | SpaprIrq spapr_irq_xive = { |
dcc345b6 CLG |
392 | .nr_irqs = SPAPR_IRQ_XIVE_NR_IRQS, |
393 | .nr_msis = SPAPR_IRQ_XIVE_NR_MSIS, | |
db592b5b | 394 | .ov5 = SPAPR_OV5_XIVE_EXPLOIT, |
dcc345b6 CLG |
395 | |
396 | .init = spapr_irq_init_xive, | |
397 | .claim = spapr_irq_claim_xive, | |
398 | .free = spapr_irq_free_xive, | |
399 | .qirq = spapr_qirq_xive, | |
400 | .print_info = spapr_irq_print_info_xive, | |
6e21de4a | 401 | .dt_populate = spapr_dt_xive, |
1a937ad7 | 402 | .cpu_intc_create = spapr_irq_cpu_intc_create_xive, |
1c53b06c | 403 | .post_load = spapr_irq_post_load_xive, |
b2e22477 | 404 | .reset = spapr_irq_reset_xive, |
872ff3de | 405 | .set_irq = spapr_irq_set_irq_xive, |
743ed566 | 406 | .get_nodename = spapr_irq_get_nodename_xive, |
dcc345b6 CLG |
407 | }; |
408 | ||
13db0cd9 CLG |
409 | /* |
410 | * Dual XIVE and XICS IRQ backend. | |
411 | * | |
412 | * Both interrupt mode, XIVE and XICS, objects are created but the | |
413 | * machine starts in legacy interrupt mode (XICS). It can be changed | |
414 | * by the CAS negotiation process and, in that case, the new mode is | |
415 | * activated after an extra machine reset. | |
416 | */ | |
417 | ||
418 | /* | |
419 | * Returns the sPAPR IRQ backend negotiated by CAS. XICS is the | |
420 | * default. | |
421 | */ | |
ce2918cb | 422 | static SpaprIrq *spapr_irq_current(SpaprMachineState *spapr) |
13db0cd9 CLG |
423 | { |
424 | return spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT) ? | |
425 | &spapr_irq_xive : &spapr_irq_xics; | |
426 | } | |
427 | ||
ce2918cb | 428 | static void spapr_irq_init_dual(SpaprMachineState *spapr, int nr_irqs, |
2e66cdb7 | 429 | Error **errp) |
13db0cd9 CLG |
430 | { |
431 | MachineState *machine = MACHINE(spapr); | |
432 | Error *local_err = NULL; | |
433 | ||
434 | if (kvm_enabled() && machine_kernel_irqchip_allowed(machine)) { | |
435 | error_setg(errp, "No KVM support for the 'dual' machine"); | |
436 | return; | |
437 | } | |
438 | ||
2e66cdb7 | 439 | spapr_irq_xics.init(spapr, spapr_irq_xics.nr_irqs, &local_err); |
13db0cd9 CLG |
440 | if (local_err) { |
441 | error_propagate(errp, local_err); | |
442 | return; | |
443 | } | |
444 | ||
2e66cdb7 | 445 | spapr_irq_xive.init(spapr, spapr_irq_xive.nr_irqs, &local_err); |
13db0cd9 CLG |
446 | if (local_err) { |
447 | error_propagate(errp, local_err); | |
448 | return; | |
449 | } | |
450 | } | |
451 | ||
ce2918cb | 452 | static int spapr_irq_claim_dual(SpaprMachineState *spapr, int irq, bool lsi, |
13db0cd9 CLG |
453 | Error **errp) |
454 | { | |
455 | Error *local_err = NULL; | |
456 | int ret; | |
457 | ||
458 | ret = spapr_irq_xics.claim(spapr, irq, lsi, &local_err); | |
459 | if (local_err) { | |
460 | error_propagate(errp, local_err); | |
461 | return ret; | |
462 | } | |
463 | ||
464 | ret = spapr_irq_xive.claim(spapr, irq, lsi, &local_err); | |
465 | if (local_err) { | |
466 | error_propagate(errp, local_err); | |
467 | return ret; | |
468 | } | |
469 | ||
470 | return ret; | |
471 | } | |
472 | ||
ce2918cb | 473 | static void spapr_irq_free_dual(SpaprMachineState *spapr, int irq, int num) |
13db0cd9 CLG |
474 | { |
475 | spapr_irq_xics.free(spapr, irq, num); | |
476 | spapr_irq_xive.free(spapr, irq, num); | |
477 | } | |
478 | ||
ce2918cb | 479 | static qemu_irq spapr_qirq_dual(SpaprMachineState *spapr, int irq) |
13db0cd9 | 480 | { |
3a0d802c | 481 | return spapr_irq_current(spapr)->qirq(spapr, irq); |
13db0cd9 CLG |
482 | } |
483 | ||
ce2918cb | 484 | static void spapr_irq_print_info_dual(SpaprMachineState *spapr, Monitor *mon) |
13db0cd9 CLG |
485 | { |
486 | spapr_irq_current(spapr)->print_info(spapr, mon); | |
487 | } | |
488 | ||
ce2918cb | 489 | static void spapr_irq_dt_populate_dual(SpaprMachineState *spapr, |
13db0cd9 CLG |
490 | uint32_t nr_servers, void *fdt, |
491 | uint32_t phandle) | |
492 | { | |
493 | spapr_irq_current(spapr)->dt_populate(spapr, nr_servers, fdt, phandle); | |
494 | } | |
495 | ||
ce2918cb | 496 | static void spapr_irq_cpu_intc_create_dual(SpaprMachineState *spapr, |
13db0cd9 CLG |
497 | PowerPCCPU *cpu, Error **errp) |
498 | { | |
499 | Error *local_err = NULL; | |
500 | ||
501 | spapr_irq_xive.cpu_intc_create(spapr, cpu, &local_err); | |
502 | if (local_err) { | |
503 | error_propagate(errp, local_err); | |
504 | return; | |
505 | } | |
506 | ||
507 | spapr_irq_xics.cpu_intc_create(spapr, cpu, errp); | |
508 | } | |
509 | ||
ce2918cb | 510 | static int spapr_irq_post_load_dual(SpaprMachineState *spapr, int version_id) |
13db0cd9 CLG |
511 | { |
512 | /* | |
513 | * Force a reset of the XIVE backend after migration. The machine | |
514 | * defaults to XICS at startup. | |
515 | */ | |
516 | if (spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) { | |
517 | spapr_irq_xive.reset(spapr, &error_fatal); | |
518 | } | |
519 | ||
520 | return spapr_irq_current(spapr)->post_load(spapr, version_id); | |
521 | } | |
522 | ||
ce2918cb | 523 | static void spapr_irq_reset_dual(SpaprMachineState *spapr, Error **errp) |
13db0cd9 | 524 | { |
3a8eb78e CLG |
525 | /* |
526 | * Deactivate the XIVE MMIOs. The XIVE backend will reenable them | |
527 | * if selected. | |
528 | */ | |
529 | spapr_xive_mmio_set_enabled(spapr->xive, false); | |
530 | ||
13db0cd9 CLG |
531 | spapr_irq_current(spapr)->reset(spapr, errp); |
532 | } | |
533 | ||
534 | static void spapr_irq_set_irq_dual(void *opaque, int srcno, int val) | |
535 | { | |
ce2918cb | 536 | SpaprMachineState *spapr = opaque; |
13db0cd9 CLG |
537 | |
538 | spapr_irq_current(spapr)->set_irq(spapr, srcno, val); | |
539 | } | |
540 | ||
ce2918cb | 541 | static const char *spapr_irq_get_nodename_dual(SpaprMachineState *spapr) |
743ed566 GK |
542 | { |
543 | return spapr_irq_current(spapr)->get_nodename(spapr); | |
544 | } | |
545 | ||
13db0cd9 CLG |
546 | /* |
547 | * Define values in sync with the XIVE and XICS backend | |
548 | */ | |
549 | #define SPAPR_IRQ_DUAL_NR_IRQS 0x2000 | |
550 | #define SPAPR_IRQ_DUAL_NR_MSIS (SPAPR_IRQ_DUAL_NR_IRQS - SPAPR_IRQ_MSI) | |
551 | ||
ce2918cb | 552 | SpaprIrq spapr_irq_dual = { |
13db0cd9 CLG |
553 | .nr_irqs = SPAPR_IRQ_DUAL_NR_IRQS, |
554 | .nr_msis = SPAPR_IRQ_DUAL_NR_MSIS, | |
555 | .ov5 = SPAPR_OV5_XIVE_BOTH, | |
556 | ||
557 | .init = spapr_irq_init_dual, | |
558 | .claim = spapr_irq_claim_dual, | |
559 | .free = spapr_irq_free_dual, | |
560 | .qirq = spapr_qirq_dual, | |
561 | .print_info = spapr_irq_print_info_dual, | |
562 | .dt_populate = spapr_irq_dt_populate_dual, | |
563 | .cpu_intc_create = spapr_irq_cpu_intc_create_dual, | |
564 | .post_load = spapr_irq_post_load_dual, | |
565 | .reset = spapr_irq_reset_dual, | |
743ed566 GK |
566 | .set_irq = spapr_irq_set_irq_dual, |
567 | .get_nodename = spapr_irq_get_nodename_dual, | |
13db0cd9 CLG |
568 | }; |
569 | ||
273fef83 CLG |
570 | |
571 | static void spapr_irq_check(SpaprMachineState *spapr, Error **errp) | |
572 | { | |
573 | MachineState *machine = MACHINE(spapr); | |
574 | ||
575 | /* | |
576 | * Sanity checks on non-P9 machines. On these, XIVE is not | |
577 | * advertised, see spapr_dt_ov5_platform_support() | |
578 | */ | |
579 | if (!ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, | |
580 | 0, spapr->max_compat_pvr)) { | |
581 | /* | |
582 | * If the 'dual' interrupt mode is selected, force XICS as CAS | |
583 | * negotiation is useless. | |
584 | */ | |
585 | if (spapr->irq == &spapr_irq_dual) { | |
586 | spapr->irq = &spapr_irq_xics; | |
587 | return; | |
588 | } | |
589 | ||
590 | /* | |
591 | * Non-P9 machines using only XIVE is a bogus setup. We have two | |
592 | * scenarios to take into account because of the compat mode: | |
593 | * | |
594 | * 1. POWER7/8 machines should fail to init later on when creating | |
595 | * the XIVE interrupt presenters because a POWER9 exception | |
596 | * model is required. | |
597 | ||
598 | * 2. POWER9 machines using the POWER8 compat mode won't fail and | |
599 | * will let the OS boot with a partial XIVE setup : DT | |
600 | * properties but no hcalls. | |
601 | * | |
602 | * To cover both and not confuse the OS, add an early failure in | |
603 | * QEMU. | |
604 | */ | |
605 | if (spapr->irq == &spapr_irq_xive) { | |
606 | error_setg(errp, "XIVE-only machines require a POWER9 CPU"); | |
607 | return; | |
608 | } | |
609 | } | |
610 | } | |
611 | ||
ef01ed9d CLG |
612 | /* |
613 | * sPAPR IRQ frontend routines for devices | |
614 | */ | |
ce2918cb | 615 | void spapr_irq_init(SpaprMachineState *spapr, Error **errp) |
fab397d8 | 616 | { |
1a511340 | 617 | MachineState *machine = MACHINE(spapr); |
273fef83 | 618 | Error *local_err = NULL; |
1a511340 GK |
619 | |
620 | if (machine_kernel_irqchip_split(machine)) { | |
621 | error_setg(errp, "kernel_irqchip split mode not supported on pseries"); | |
622 | return; | |
623 | } | |
624 | ||
625 | if (!kvm_enabled() && machine_kernel_irqchip_required(machine)) { | |
626 | error_setg(errp, | |
627 | "kernel_irqchip requested but only available with KVM"); | |
628 | return; | |
629 | } | |
630 | ||
273fef83 CLG |
631 | spapr_irq_check(spapr, &local_err); |
632 | if (local_err) { | |
633 | error_propagate(errp, local_err); | |
634 | return; | |
635 | } | |
636 | ||
fab397d8 CLG |
637 | /* Initialize the MSI IRQ allocator. */ |
638 | if (!SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) { | |
3ba3d0bc | 639 | spapr_irq_msi_init(spapr, spapr->irq->nr_msis); |
fab397d8 CLG |
640 | } |
641 | ||
2e66cdb7 | 642 | spapr->irq->init(spapr, spapr->irq->nr_irqs, errp); |
872ff3de CLG |
643 | |
644 | spapr->qirqs = qemu_allocate_irqs(spapr->irq->set_irq, spapr, | |
645 | spapr->irq->nr_irqs); | |
fab397d8 | 646 | } |
ef01ed9d | 647 | |
ce2918cb | 648 | int spapr_irq_claim(SpaprMachineState *spapr, int irq, bool lsi, Error **errp) |
ef01ed9d | 649 | { |
3ba3d0bc | 650 | return spapr->irq->claim(spapr, irq, lsi, errp); |
ef01ed9d CLG |
651 | } |
652 | ||
ce2918cb | 653 | void spapr_irq_free(SpaprMachineState *spapr, int irq, int num) |
ef01ed9d | 654 | { |
3ba3d0bc | 655 | spapr->irq->free(spapr, irq, num); |
ef01ed9d CLG |
656 | } |
657 | ||
ce2918cb | 658 | qemu_irq spapr_qirq(SpaprMachineState *spapr, int irq) |
ef01ed9d | 659 | { |
3ba3d0bc | 660 | return spapr->irq->qirq(spapr, irq); |
ef01ed9d CLG |
661 | } |
662 | ||
ce2918cb | 663 | int spapr_irq_post_load(SpaprMachineState *spapr, int version_id) |
1c53b06c | 664 | { |
3ba3d0bc | 665 | return spapr->irq->post_load(spapr, version_id); |
1c53b06c CLG |
666 | } |
667 | ||
ce2918cb | 668 | void spapr_irq_reset(SpaprMachineState *spapr, Error **errp) |
b2e22477 | 669 | { |
3ba3d0bc CLG |
670 | if (spapr->irq->reset) { |
671 | spapr->irq->reset(spapr, errp); | |
b2e22477 CLG |
672 | } |
673 | } | |
674 | ||
ce2918cb | 675 | int spapr_irq_get_phandle(SpaprMachineState *spapr, void *fdt, Error **errp) |
ad62bff6 GK |
676 | { |
677 | const char *nodename = spapr->irq->get_nodename(spapr); | |
678 | int offset, phandle; | |
679 | ||
680 | offset = fdt_subnode_offset(fdt, 0, nodename); | |
681 | if (offset < 0) { | |
682 | error_setg(errp, "Can't find node \"%s\": %s", nodename, | |
683 | fdt_strerror(offset)); | |
684 | return -1; | |
685 | } | |
686 | ||
687 | phandle = fdt_get_phandle(fdt, offset); | |
688 | if (!phandle) { | |
689 | error_setg(errp, "Can't get phandle of node \"%s\"", nodename); | |
690 | return -1; | |
691 | } | |
692 | ||
693 | return phandle; | |
694 | } | |
695 | ||
ef01ed9d CLG |
696 | /* |
697 | * XICS legacy routines - to deprecate one day | |
698 | */ | |
699 | ||
700 | static int ics_find_free_block(ICSState *ics, int num, int alignnum) | |
701 | { | |
702 | int first, i; | |
703 | ||
704 | for (first = 0; first < ics->nr_irqs; first += alignnum) { | |
705 | if (num > (ics->nr_irqs - first)) { | |
706 | return -1; | |
707 | } | |
708 | for (i = first; i < first + num; ++i) { | |
709 | if (!ICS_IRQ_FREE(ics, i)) { | |
710 | break; | |
711 | } | |
712 | } | |
713 | if (i == (first + num)) { | |
714 | return first; | |
715 | } | |
716 | } | |
717 | ||
718 | return -1; | |
719 | } | |
720 | ||
ce2918cb | 721 | int spapr_irq_find(SpaprMachineState *spapr, int num, bool align, Error **errp) |
ef01ed9d CLG |
722 | { |
723 | ICSState *ics = spapr->ics; | |
724 | int first = -1; | |
725 | ||
726 | assert(ics); | |
727 | ||
728 | /* | |
729 | * MSIMesage::data is used for storing VIRQ so | |
730 | * it has to be aligned to num to support multiple | |
731 | * MSI vectors. MSI-X is not affected by this. | |
732 | * The hint is used for the first IRQ, the rest should | |
733 | * be allocated continuously. | |
734 | */ | |
735 | if (align) { | |
736 | assert((num == 1) || (num == 2) || (num == 4) || | |
737 | (num == 8) || (num == 16) || (num == 32)); | |
738 | first = ics_find_free_block(ics, num, num); | |
739 | } else { | |
740 | first = ics_find_free_block(ics, num, 1); | |
741 | } | |
742 | ||
743 | if (first < 0) { | |
744 | error_setg(errp, "can't find a free %d-IRQ block", num); | |
745 | return -1; | |
746 | } | |
747 | ||
748 | return first + ics->offset; | |
749 | } | |
ae837402 CLG |
750 | |
751 | #define SPAPR_IRQ_XICS_LEGACY_NR_IRQS 0x400 | |
752 | ||
ce2918cb | 753 | SpaprIrq spapr_irq_xics_legacy = { |
ae837402 CLG |
754 | .nr_irqs = SPAPR_IRQ_XICS_LEGACY_NR_IRQS, |
755 | .nr_msis = SPAPR_IRQ_XICS_LEGACY_NR_IRQS, | |
db592b5b | 756 | .ov5 = SPAPR_OV5_XIVE_LEGACY, |
ae837402 CLG |
757 | |
758 | .init = spapr_irq_init_xics, | |
759 | .claim = spapr_irq_claim_xics, | |
760 | .free = spapr_irq_free_xics, | |
761 | .qirq = spapr_qirq_xics, | |
762 | .print_info = spapr_irq_print_info_xics, | |
6e21de4a | 763 | .dt_populate = spapr_dt_xics, |
1a937ad7 | 764 | .cpu_intc_create = spapr_irq_cpu_intc_create_xics, |
1c53b06c | 765 | .post_load = spapr_irq_post_load_xics, |
872ff3de | 766 | .set_irq = spapr_irq_set_irq_xics, |
743ed566 | 767 | .get_nodename = spapr_irq_get_nodename_xics, |
ae837402 | 768 | }; |