The XIVE interface for the guest is described in the device tree under the "interrupt-controller" node. A couple of new properties are specific to XIVE :
- "reg" contains the base address and size of the thread interrupt managnement areas (TIMA), also called rings, for the User level and for the Guest OS level. Only the Guest OS level is taken into account today. - "ibm,xive-eq-sizes" the size of the event queues. One cell per size supported, contains log2 of size, in ascending order. - "ibm,xive-lisn-ranges" the interrupt numbers ranges assigned to the guest. These are allocated using a simple bitmap. and also under the root node : - "ibm,plat-res-int-priorities" contains a list of priorities that the hypervisor has reserved for its own use. Simulate ranges as defined by the PowerVM Hypervisor. When the XIVE interrupt mode is activated after the CAS negotiation, the machine will perform a reboot to rebuild the device tree. Signed-off-by: Cédric Le Goater <c...@kaod.org> --- hw/intc/spapr_xive_hcall.c | 50 +++++++++++++++++++++++++++++++++++++++++++++ hw/ppc/spapr.c | 7 ++++++- hw/ppc/spapr_hcall.c | 6 ++++++ include/hw/ppc/spapr_xive.h | 2 ++ 4 files changed, 64 insertions(+), 1 deletion(-) diff --git a/hw/intc/spapr_xive_hcall.c b/hw/intc/spapr_xive_hcall.c index 676fe0e2d5c7..60c6c9f4be8f 100644 --- a/hw/intc/spapr_xive_hcall.c +++ b/hw/intc/spapr_xive_hcall.c @@ -883,3 +883,53 @@ void spapr_xive_hcall_init(sPAPRMachineState *spapr) spapr_register_hypercall(H_INT_SYNC, h_int_sync); spapr_register_hypercall(H_INT_RESET, h_int_reset); } + +void spapr_xive_populate(sPAPRMachineState *spapr, int nr_servers, + void *fdt, uint32_t phandle) +{ + sPAPRXive *xive = spapr->xive; + int node; + uint64_t timas[2 * 2]; + uint32_t lisn_ranges[] = { + cpu_to_be32(0), + cpu_to_be32(nr_servers), + }; + uint32_t eq_sizes[] = { + cpu_to_be32(12), /* 4K */ + cpu_to_be32(16), /* 64K */ + cpu_to_be32(21), /* 2M */ + cpu_to_be32(24), /* 16M */ + }; + uint32_t plat_res_int_priorities[ARRAY_SIZE(reserved_priorities)]; + int i; + + for (i = 0; i < ARRAY_SIZE(plat_res_int_priorities); i++) { + plat_res_int_priorities[i] = cpu_to_be32(reserved_priorities[i]); + } + + /* Thread Interrupt Management Areas : User and OS */ + for (i = 0; i < 2; i++) { + timas[i * 2] = cpu_to_be64(xive->tm_base + i * (1 << xive->tm_shift)); + timas[i * 2 + 1] = cpu_to_be64(1 << xive->tm_shift); + } + + _FDT(node = fdt_add_subnode(fdt, 0, "interrupt-controller")); + + _FDT(fdt_setprop_string(fdt, node, "name", "interrupt-controller")); + _FDT(fdt_setprop_string(fdt, node, "device_type", "power-ivpe")); + _FDT(fdt_setprop(fdt, node, "reg", timas, sizeof(timas))); + + _FDT(fdt_setprop_string(fdt, node, "compatible", "ibm,power-ivpe")); + _FDT(fdt_setprop(fdt, node, "ibm,xive-eq-sizes", eq_sizes, + sizeof(eq_sizes))); + _FDT(fdt_setprop(fdt, node, "ibm,xive-lisn-ranges", lisn_ranges, + sizeof(lisn_ranges))); + + /* For SLOF */ + _FDT(fdt_setprop_cell(fdt, node, "linux,phandle", phandle)); + _FDT(fdt_setprop_cell(fdt, node, "phandle", phandle)); + + /* top properties */ + _FDT(fdt_setprop(fdt, 0, "ibm,plat-res-int-priorities", + plat_res_int_priorities, sizeof(plat_res_int_priorities))); +} diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 8b15c0b500d0..3a62369883cc 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1127,7 +1127,12 @@ static void *spapr_build_fdt(sPAPRMachineState *spapr, _FDT(fdt_setprop_cell(fdt, 0, "#size-cells", 2)); /* /interrupt controller */ - spapr_dt_xics(xics_max_server_number(), fdt, PHANDLE_XICP); + if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) { + spapr_dt_xics(xics_max_server_number(), fdt, PHANDLE_XICP); + } else { + /* Populate device tree for XIVE */ + spapr_xive_populate(spapr, xics_max_server_number(), fdt, PHANDLE_XICP); + } ret = spapr_populate_memory(spapr, fdt); if (ret < 0) { diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index be22a6b2895f..e2a1665beee9 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1646,6 +1646,12 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, (spapr_h_cas_compose_response(spapr, args[1], args[2], ov5_updates) != 0); } + + /* We need to rebuild the device tree for XIVE, generate a reset */ + if (!spapr->cas_reboot) { + spapr->cas_reboot = spapr_ovec_test(ov5_updates, OV5_XIVE_EXPLOIT); + } + spapr_ovec_cleanup(ov5_updates); if (spapr->cas_reboot) { diff --git a/include/hw/ppc/spapr_xive.h b/include/hw/ppc/spapr_xive.h index 3f822220647f..f6d4bf26e06a 100644 --- a/include/hw/ppc/spapr_xive.h +++ b/include/hw/ppc/spapr_xive.h @@ -82,5 +82,7 @@ void spapr_xive_icp_pic_print_info(sPAPRXiveICP *xicp, Monitor *mon); typedef struct sPAPRMachineState sPAPRMachineState; void spapr_xive_hcall_init(sPAPRMachineState *spapr); +void spapr_xive_populate(sPAPRMachineState *spapr, int nr_servers, void *fdt, + uint32_t phandle); #endif /* PPC_SPAPR_XIVE_H */ -- 2.13.6