2 * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
4 * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics
6 * Copyright (c) 2010,2011 David Gibson, IBM Corporation.
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28 #include "qemu/osdep.h"
32 #include "qemu/timer.h"
33 #include "hw/ppc/spapr.h"
34 #include "hw/ppc/spapr_cpu_core.h"
35 #include "hw/ppc/xics.h"
36 #include "hw/ppc/xics_spapr.h"
37 #include "hw/ppc/fdt.h"
38 #include "qapi/visitor.h"
44 static bool check_emulated_xics(SpaprMachineState
*spapr
, const char *func
)
46 if (spapr_ovec_test(spapr
->ov5_cas
, OV5_XIVE_EXPLOIT
) ||
47 kvm_irqchip_in_kernel()) {
48 error_report("pseries: %s must only be called for emulated XICS",
56 #define CHECK_EMULATED_XICS_HCALL(spapr) \
58 if (!check_emulated_xics((spapr), __func__)) { \
63 static target_ulong
h_cppr(PowerPCCPU
*cpu
, SpaprMachineState
*spapr
,
64 target_ulong opcode
, target_ulong
*args
)
66 target_ulong cppr
= args
[0];
68 CHECK_EMULATED_XICS_HCALL(spapr
);
70 icp_set_cppr(spapr_cpu_state(cpu
)->icp
, cppr
);
74 static target_ulong
h_ipi(PowerPCCPU
*cpu
, SpaprMachineState
*spapr
,
75 target_ulong opcode
, target_ulong
*args
)
77 target_ulong mfrr
= args
[1];
78 ICPState
*icp
= xics_icp_get(XICS_FABRIC(spapr
), args
[0]);
80 CHECK_EMULATED_XICS_HCALL(spapr
);
86 icp_set_mfrr(icp
, mfrr
);
90 static target_ulong
h_xirr(PowerPCCPU
*cpu
, SpaprMachineState
*spapr
,
91 target_ulong opcode
, target_ulong
*args
)
93 uint32_t xirr
= icp_accept(spapr_cpu_state(cpu
)->icp
);
95 CHECK_EMULATED_XICS_HCALL(spapr
);
101 static target_ulong
h_xirr_x(PowerPCCPU
*cpu
, SpaprMachineState
*spapr
,
102 target_ulong opcode
, target_ulong
*args
)
104 uint32_t xirr
= icp_accept(spapr_cpu_state(cpu
)->icp
);
106 CHECK_EMULATED_XICS_HCALL(spapr
);
109 args
[1] = cpu_get_host_ticks();
113 static target_ulong
h_eoi(PowerPCCPU
*cpu
, SpaprMachineState
*spapr
,
114 target_ulong opcode
, target_ulong
*args
)
116 target_ulong xirr
= args
[0];
118 CHECK_EMULATED_XICS_HCALL(spapr
);
120 icp_eoi(spapr_cpu_state(cpu
)->icp
, xirr
);
124 static target_ulong
h_ipoll(PowerPCCPU
*cpu
, SpaprMachineState
*spapr
,
125 target_ulong opcode
, target_ulong
*args
)
127 ICPState
*icp
= xics_icp_get(XICS_FABRIC(spapr
), args
[0]);
131 CHECK_EMULATED_XICS_HCALL(spapr
);
137 xirr
= icp_ipoll(icp
, &mfrr
);
145 #define CHECK_EMULATED_XICS_RTAS(spapr, rets) \
147 if (!check_emulated_xics((spapr), __func__)) { \
148 rtas_st((rets), 0, RTAS_OUT_HW_ERROR); \
153 static void rtas_set_xive(PowerPCCPU
*cpu
, SpaprMachineState
*spapr
,
155 uint32_t nargs
, target_ulong args
,
156 uint32_t nret
, target_ulong rets
)
158 ICSState
*ics
= spapr
->ics
;
159 uint32_t nr
, srcno
, server
, priority
;
161 CHECK_EMULATED_XICS_RTAS(spapr
, rets
);
163 if ((nargs
!= 3) || (nret
!= 1)) {
164 rtas_st(rets
, 0, RTAS_OUT_PARAM_ERROR
);
168 rtas_st(rets
, 0, RTAS_OUT_HW_ERROR
);
172 nr
= rtas_ld(args
, 0);
173 server
= rtas_ld(args
, 1);
174 priority
= rtas_ld(args
, 2);
176 if (!ics_valid_irq(ics
, nr
) || !xics_icp_get(XICS_FABRIC(spapr
), server
)
177 || (priority
> 0xff)) {
178 rtas_st(rets
, 0, RTAS_OUT_PARAM_ERROR
);
182 srcno
= nr
- ics
->offset
;
183 ics_simple_write_xive(ics
, srcno
, server
, priority
, priority
);
185 rtas_st(rets
, 0, RTAS_OUT_SUCCESS
);
188 static void rtas_get_xive(PowerPCCPU
*cpu
, SpaprMachineState
*spapr
,
190 uint32_t nargs
, target_ulong args
,
191 uint32_t nret
, target_ulong rets
)
193 ICSState
*ics
= spapr
->ics
;
196 CHECK_EMULATED_XICS_RTAS(spapr
, rets
);
198 if ((nargs
!= 1) || (nret
!= 3)) {
199 rtas_st(rets
, 0, RTAS_OUT_PARAM_ERROR
);
203 rtas_st(rets
, 0, RTAS_OUT_HW_ERROR
);
207 nr
= rtas_ld(args
, 0);
209 if (!ics_valid_irq(ics
, nr
)) {
210 rtas_st(rets
, 0, RTAS_OUT_PARAM_ERROR
);
214 rtas_st(rets
, 0, RTAS_OUT_SUCCESS
);
215 srcno
= nr
- ics
->offset
;
216 rtas_st(rets
, 1, ics
->irqs
[srcno
].server
);
217 rtas_st(rets
, 2, ics
->irqs
[srcno
].priority
);
220 static void rtas_int_off(PowerPCCPU
*cpu
, SpaprMachineState
*spapr
,
222 uint32_t nargs
, target_ulong args
,
223 uint32_t nret
, target_ulong rets
)
225 ICSState
*ics
= spapr
->ics
;
228 CHECK_EMULATED_XICS_RTAS(spapr
, rets
);
230 if ((nargs
!= 1) || (nret
!= 1)) {
231 rtas_st(rets
, 0, RTAS_OUT_PARAM_ERROR
);
235 rtas_st(rets
, 0, RTAS_OUT_HW_ERROR
);
239 nr
= rtas_ld(args
, 0);
241 if (!ics_valid_irq(ics
, nr
)) {
242 rtas_st(rets
, 0, RTAS_OUT_PARAM_ERROR
);
246 srcno
= nr
- ics
->offset
;
247 ics_simple_write_xive(ics
, srcno
, ics
->irqs
[srcno
].server
, 0xff,
248 ics
->irqs
[srcno
].priority
);
250 rtas_st(rets
, 0, RTAS_OUT_SUCCESS
);
253 static void rtas_int_on(PowerPCCPU
*cpu
, SpaprMachineState
*spapr
,
255 uint32_t nargs
, target_ulong args
,
256 uint32_t nret
, target_ulong rets
)
258 ICSState
*ics
= spapr
->ics
;
261 CHECK_EMULATED_XICS_RTAS(spapr
, rets
);
263 if ((nargs
!= 1) || (nret
!= 1)) {
264 rtas_st(rets
, 0, RTAS_OUT_PARAM_ERROR
);
268 rtas_st(rets
, 0, RTAS_OUT_HW_ERROR
);
272 nr
= rtas_ld(args
, 0);
274 if (!ics_valid_irq(ics
, nr
)) {
275 rtas_st(rets
, 0, RTAS_OUT_PARAM_ERROR
);
279 srcno
= nr
- ics
->offset
;
280 ics_simple_write_xive(ics
, srcno
, ics
->irqs
[srcno
].server
,
281 ics
->irqs
[srcno
].saved_priority
,
282 ics
->irqs
[srcno
].saved_priority
);
284 rtas_st(rets
, 0, RTAS_OUT_SUCCESS
);
287 void xics_spapr_init(SpaprMachineState
*spapr
)
289 spapr_rtas_register(RTAS_IBM_SET_XIVE
, "ibm,set-xive", rtas_set_xive
);
290 spapr_rtas_register(RTAS_IBM_GET_XIVE
, "ibm,get-xive", rtas_get_xive
);
291 spapr_rtas_register(RTAS_IBM_INT_OFF
, "ibm,int-off", rtas_int_off
);
292 spapr_rtas_register(RTAS_IBM_INT_ON
, "ibm,int-on", rtas_int_on
);
294 spapr_register_hypercall(H_CPPR
, h_cppr
);
295 spapr_register_hypercall(H_IPI
, h_ipi
);
296 spapr_register_hypercall(H_XIRR
, h_xirr
);
297 spapr_register_hypercall(H_XIRR_X
, h_xirr_x
);
298 spapr_register_hypercall(H_EOI
, h_eoi
);
299 spapr_register_hypercall(H_IPOLL
, h_ipoll
);
302 void spapr_dt_xics(SpaprMachineState
*spapr
, uint32_t nr_servers
, void *fdt
,
305 uint32_t interrupt_server_ranges_prop
[] = {
306 0, cpu_to_be32(nr_servers
),
310 _FDT(node
= fdt_add_subnode(fdt
, 0, XICS_NODENAME
));
312 _FDT(fdt_setprop_string(fdt
, node
, "device_type",
313 "PowerPC-External-Interrupt-Presentation"));
314 _FDT(fdt_setprop_string(fdt
, node
, "compatible", "IBM,ppc-xicp"));
315 _FDT(fdt_setprop(fdt
, node
, "interrupt-controller", NULL
, 0));
316 _FDT(fdt_setprop(fdt
, node
, "ibm,interrupt-server-ranges",
317 interrupt_server_ranges_prop
,
318 sizeof(interrupt_server_ranges_prop
)));
319 _FDT(fdt_setprop_cell(fdt
, node
, "#interrupt-cells", 2));
320 _FDT(fdt_setprop_cell(fdt
, node
, "linux,phandle", phandle
));
321 _FDT(fdt_setprop_cell(fdt
, node
, "phandle", phandle
));