Signed-off-by: Benjamin Herrenschmidt <b...@kernel.crashing.org>
---
 hw/ppc/pnv.c          | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/hw/ppc/pnv.h  |  2 ++
 include/hw/ppc/xics.h |  2 ++
 3 files changed, 73 insertions(+)

diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 2eac877..a7a9b0f 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -41,6 +41,7 @@
 #include "hw/ppc/ppc.h"
 #include "hw/ppc/pnv.h"
 #include "hw/loader.h"
+#include "hw/ppc/xics.h"
 #include "hw/ppc/pnv_xscom.h"
 
 #include "exec/address-spaces.h"
@@ -81,6 +82,59 @@ struct sPowerNVMachineState {
     PnvSystem sys;
 };
 
+static XICSState *try_create_xics(const char *type, int nr_servers,
+                                  int nr_irqs, Error **errp)
+{
+    Error *err = NULL;
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, type);
+    qdev_prop_set_uint32(dev, "nr_servers", nr_servers);
+    object_property_set_bool(OBJECT(dev), true, "realized", &err);
+    if (err) {
+        error_propagate(errp, err);
+        object_unparent(OBJECT(dev));
+        return NULL;
+    }
+
+    return XICS_COMMON(dev);
+}
+
+static XICSState *xics_system_init(int nr_servers, int nr_irqs)
+{
+    XICSState *xics = NULL;
+
+#if 0 /* Some fixing needed to handle native ICS in KVM mode */
+    if (kvm_enabled()) {
+        QemuOpts *machine_opts = qemu_get_machine_opts();
+        bool irqchip_allowed = qemu_opt_get_bool(machine_opts,
+                                                "kernel_irqchip", true);
+        bool irqchip_required = qemu_opt_get_bool(machine_opts,
+                                                  "kernel_irqchip", false);
+        if (irqchip_allowed) {
+                icp = try_create_xics(TYPE_KVM_XICS, nr_servers, nr_irqs,
+                                      &error_abort);
+        }
+
+        if (irqchip_required && !icp) {
+            perror("Failed to create in-kernel XICS\n");
+            abort();
+        }
+    }
+#endif
+
+    if (!xics) {
+        xics = try_create_xics(TYPE_XICS_NATIVE, nr_servers, nr_irqs,
+                               &error_abort);
+    }
+
+    if (!xics) {
+        perror("Failed to create XICS\n");
+        abort();
+    }
+    return xics;
+}
+
 static size_t create_page_sizes_prop(CPUPPCState *env, uint32_t *prop,
                                      size_t maxsize)
 {
@@ -366,6 +420,13 @@ static void *powernv_create_fdt(PnvSystem *sys, uint32_t 
initrd_base, uint32_t i
 
     _FDT((fdt_end_node(fdt)));
 
+    /* ICPs */
+    CPU_FOREACH(cs) {
+        PowerPCCPU *cpu = POWERPC_CPU(cs);
+        uint32_t base_server = ppc_get_vcpu_dt_id(cpu);
+        xics_create_native_icp_node(sys->xics, fdt, base_server, smt);
+    }
+
     /* Memory */
     _FDT((powernv_populate_memory(fdt)));
 
@@ -451,11 +512,17 @@ static void ppc_powernv_init(MachineState *machine)
     MemoryRegion *ram = g_new(MemoryRegion, 1);
     sPowerNVMachineState *pnv_machine = POWERNV_MACHINE(machine);
     PnvSystem *sys = &pnv_machine->sys;
+    XICSState *xics;
     long fw_size;
     char *filename;
     void *fdt;
     int i;
 
+    /* Set up Interrupt Controller before we create the VCPUs */
+    xics = xics_system_init(smp_cpus * kvmppc_smt_threads() / smp_threads,
+                            XICS_IRQS_POWERNV);
+    sys->xics = xics;
+
     /* init CPUs */
     if (cpu_model == NULL) {
         cpu_model = kvm_enabled() ? "host" : "POWER8";
@@ -475,6 +542,8 @@ static void ppc_powernv_init(MachineState *machine)
         /* MSR[IP] doesn't exist nowadays */
         env->msr_mask &= ~(1 << 6);
 
+        xics_cpu_setup(xics, cpu);
+
         qemu_register_reset(powernv_cpu_reset, cpu);
     }
 
diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
index cb157eb..80617b4 100644
--- a/include/hw/ppc/pnv.h
+++ b/include/hw/ppc/pnv.h
@@ -21,6 +21,7 @@
 
 #include "hw/hw.h"
 typedef struct XScomBus XScomBus;
+typedef struct XICSState XICSState;
 
 /* Should we turn that into a QOjb of some sort ? */
 typedef struct PnvChip {
@@ -29,6 +30,7 @@ typedef struct PnvChip {
 } PnvChip;
 
 typedef struct PnvSystem {
+    XICSState *xics;
     uint32_t  num_chips;
 #define PNV_MAX_CHIPS          1
     PnvChip   chips[PNV_MAX_CHIPS];
diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h
index 1cf7037..85d2fb9 100644
--- a/include/hw/ppc/xics.h
+++ b/include/hw/ppc/xics.h
@@ -183,6 +183,8 @@ struct ICSIRQState {
 };
 
 #define XICS_IRQS_SPAPR               1024
+#define XICS_IRQS_POWERNV             (1 << 19)
+
 
 qemu_irq xics_get_qirq(XICSState *icp, int irq);
 
-- 
2.5.0


Reply via email to