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