Commit 6e21de4a authored by Cédric Le Goater's avatar Cédric Le Goater Committed by David Gibson
Browse files

spapr: add device tree support for the XIVE exploitation mode



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), 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 IRQ interrupt number ranges assigned to the guest for the IPIs.

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. OPAL uses the priority 7 queue to automatically
   escalate interrupts for all other queues (DD2.X POWER9). So only
   priorities [0..6] are allowed for the guest.

Extend the sPAPR IRQ backend with a new handler to populate the DT
with the appropriate "interrupt-controller" node.

Signed-off-by: default avatarCédric Le Goater <clg@kaod.org>
[dwg: Fix style nits]
Signed-off-by: default avatarDavid Gibson <david@gibson.dropbear.id.au>
parent 23bcd5eb
Loading
Loading
Loading
Loading
+67 −0
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
#include "target/ppc/cpu.h"
#include "sysemu/cpus.h"
#include "monitor/monitor.h"
#include "hw/ppc/fdt.h"
#include "hw/ppc/spapr.h"
#include "hw/ppc/spapr_xive.h"
#include "hw/ppc/xive.h"
@@ -1400,3 +1401,69 @@ 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_dt_xive(sPAPRMachineState *spapr, uint32_t nr_servers, void *fdt,
                   uint32_t phandle)
{
    sPAPRXive *xive = spapr->xive;
    int node;
    uint64_t timas[2 * 2];
    /* Interrupt number ranges for the IPIs */
    uint32_t lisn_ranges[] = {
        cpu_to_be32(0),
        cpu_to_be32(nr_servers),
    };
    /*
     * EQ size - the sizes of pages supported by the system 4K, 64K,
     * 2M, 16M. We only advertise 64K for the moment.
     */
    uint32_t eq_sizes[] = {
        cpu_to_be32(16), /* 64K */
    };
    /*
     * The following array is in sync with the reserved priorities
     * defined by the 'spapr_xive_priority_is_reserved' routine.
     */
    uint32_t plat_res_int_priorities[] = {
        cpu_to_be32(7),    /* start */
        cpu_to_be32(0xf8), /* count */
    };
    gchar *nodename;

    /* Thread Interrupt Management Area : User (ring 3) and OS (ring 2) */
    timas[0] = cpu_to_be64(xive->tm_base +
                           XIVE_TM_USER_PAGE * (1ull << TM_SHIFT));
    timas[1] = cpu_to_be64(1ull << TM_SHIFT);
    timas[2] = cpu_to_be64(xive->tm_base +
                           XIVE_TM_OS_PAGE * (1ull << TM_SHIFT));
    timas[3] = cpu_to_be64(1ull << TM_SHIFT);

    nodename = g_strdup_printf("interrupt-controller@%" PRIx64,
                           xive->tm_base + XIVE_TM_USER_PAGE * (1 << TM_SHIFT));
    _FDT(node = fdt_add_subnode(fdt, 0, nodename));
    g_free(nodename);

    _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 Linux to link the LSIs to the interrupt controller. */
    _FDT(fdt_setprop(fdt, node, "interrupt-controller", NULL, 0));
    _FDT(fdt_setprop_cell(fdt, node, "#interrupt-cells", 2));

    /* For SLOF */
    _FDT(fdt_setprop_cell(fdt, node, "linux,phandle", phandle));
    _FDT(fdt_setprop_cell(fdt, node, "phandle", phandle));

    /*
     * The "ibm,plat-res-int-priorities" property defines the priority
     * ranges reserved by the hypervisor
     */
    _FDT(fdt_setprop(fdt, 0, "ibm,plat-res-int-priorities",
                     plat_res_int_priorities, sizeof(plat_res_int_priorities)));
}
+2 −1
Original line number Diff line number Diff line
@@ -244,7 +244,8 @@ void xics_spapr_init(sPAPRMachineState *spapr)
    spapr_register_hypercall(H_IPOLL, h_ipoll);
}

void spapr_dt_xics(int nr_servers, void *fdt, uint32_t phandle)
void spapr_dt_xics(sPAPRMachineState *spapr, uint32_t nr_servers, void *fdt,
                   uint32_t phandle)
{
    uint32_t interrupt_server_ranges_prop[] = {
        0, cpu_to_be32(nr_servers),
+2 −1
Original line number Diff line number Diff line
@@ -1268,7 +1268,8 @@ static void *spapr_build_fdt(sPAPRMachineState *spapr,
    _FDT(fdt_setprop_cell(fdt, 0, "#size-cells", 2));

    /* /interrupt controller */
    spapr_dt_xics(spapr_max_server_number(spapr), fdt, PHANDLE_XICP);
    smc->irq->dt_populate(spapr, spapr_max_server_number(spapr), fdt,
                          PHANDLE_XICP);

    ret = spapr_populate_memory(spapr, fdt);
    if (ret < 0) {
+3 −0
Original line number Diff line number Diff line
@@ -204,6 +204,7 @@ sPAPRIrq spapr_irq_xics = {
    .free        = spapr_irq_free_xics,
    .qirq        = spapr_qirq_xics,
    .print_info  = spapr_irq_print_info_xics,
    .dt_populate = spapr_dt_xics,
};

/*
@@ -298,6 +299,7 @@ sPAPRIrq spapr_irq_xive = {
    .free        = spapr_irq_free_xive,
    .qirq        = spapr_qirq_xive,
    .print_info  = spapr_irq_print_info_xive,
    .dt_populate = spapr_dt_xive,
};

/*
@@ -402,4 +404,5 @@ sPAPRIrq spapr_irq_xics_legacy = {
    .free        = spapr_irq_free_xics,
    .qirq        = spapr_qirq_xics,
    .print_info  = spapr_irq_print_info_xics,
    .dt_populate = spapr_dt_xics,
};
+2 −0
Original line number Diff line number Diff line
@@ -39,6 +39,8 @@ typedef struct sPAPRIrq {
    void (*free)(sPAPRMachineState *spapr, int irq, int num);
    qemu_irq (*qirq)(sPAPRMachineState *spapr, int irq);
    void (*print_info)(sPAPRMachineState *spapr, Monitor *mon);
    void (*dt_populate)(sPAPRMachineState *spapr, uint32_t nr_servers,
                        void *fdt, uint32_t phandle);
} sPAPRIrq;

extern sPAPRIrq spapr_irq_xics;
Loading