aboutsummaryrefslogtreecommitdiff
path: root/hw/intc
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2019-10-24 16:22:58 +0100
committerPeter Maydell <peter.maydell@linaro.org>2019-10-24 16:22:58 +0100
commit58560ad254fbda71d4daa6622d71683190070ee2 (patch)
treeb5fc3eb6758fc2ccbaab4506c8e11b27c0493353 /hw/intc
parent81c1f71eeb874c4cbbb9c5c4d1a1dc0ba7391dff (diff)
parent97c00c54449b4ff349f85c6ce409dadd1b935a7d (diff)
downloadqemu-58560ad254fbda71d4daa6622d71683190070ee2.zip
qemu-58560ad254fbda71d4daa6622d71683190070ee2.tar.gz
qemu-58560ad254fbda71d4daa6622d71683190070ee2.tar.bz2
Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-4.2-20191024' into staging
ppc patch queue 2019-10-24 Last pull request before soft freeze. * Lots of fixes and cleanups for spapr interrupt controllers * More SLOF updates to fix problems with full FDT rendering at CAS time (alas, more yet are to come) * A few other assorted changes This isn't quite as well tested as I usually try to do before a pull request. But I've been sick and running into some other difficulties, and wanted to get this sent out before heading towards KVM forum. # gpg: Signature made Thu 24 Oct 2019 09:14:31 BST # gpg: using RSA key 75F46586AE61A66CC44E87DC6C38CACA20D9B392 # gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>" [full] # gpg: aka "David Gibson (Red Hat) <dgibson@redhat.com>" [full] # gpg: aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>" [full] # gpg: aka "David Gibson (kernel.org) <dwg@kernel.org>" [unknown] # Primary key fingerprint: 75F4 6586 AE61 A66C C44E 87DC 6C38 CACA 20D9 B392 * remotes/dgibson/tags/ppc-for-4.2-20191024: (28 commits) spapr/xive: Set the OS CAM line at reset ppc/pnv: Fix naming of routines realizing the CPUs ppc: Reset the interrupt presenter from the CPU reset handler ppc/pnv: Add a PnvChip pointer to PnvCore ppc/pnv: Introduce a PnvCore reset handler spapr_cpu_core: Implement DeviceClass::reset spapr: move CPU reset after presenter creation spapr: Don't request to unplug the same core twice pseries: Update SLOF firmware image spapr: Move SpaprIrq::nr_xirqs to SpaprMachineClass spapr: Remove SpaprIrq::nr_msis spapr, xics, xive: Move SpaprIrq::post_load hook to backends spapr, xics, xive: Move SpaprIrq::reset hook logic into activate/deactivate spapr: Remove SpaprIrq::init_kvm hook spapr, xics, xive: Match signatures for XICS and XIVE KVM connect routines spapr, xics, xive: Move dt_populate from SpaprIrq to SpaprInterruptController spapr, xics, xive: Move print_info from SpaprIrq to SpaprInterruptController spapr, xics, xive: Move set_irq from SpaprIrq to SpaprInterruptController spapr: Formalize notion of active interrupt controller spapr, xics, xive: Move irq claim and free from SpaprIrq to SpaprInterruptController ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/intc')
-rw-r--r--hw/intc/pnv_xive.c20
-rw-r--r--hw/intc/spapr_xive.c324
-rw-r--r--hw/intc/spapr_xive_kvm.c22
-rw-r--r--hw/intc/xics.c18
-rw-r--r--hw/intc/xics_kvm.c9
-rw-r--r--hw/intc/xics_spapr.c117
-rw-r--r--hw/intc/xive.c31
7 files changed, 386 insertions, 155 deletions
diff --git a/hw/intc/pnv_xive.c b/hw/intc/pnv_xive.c
index ed6e9d7..348f2fd 100644
--- a/hw/intc/pnv_xive.c
+++ b/hw/intc/pnv_xive.c
@@ -385,7 +385,7 @@ static int pnv_xive_get_eas(XiveRouter *xrtr, uint8_t blk, uint32_t idx,
PnvXive *xive = PNV_XIVE(xrtr);
if (pnv_xive_get_ic(blk) != xive) {
- xive_error(xive, "VST: EAS %x is remote !?", XIVE_SRCNO(blk, idx));
+ xive_error(xive, "VST: EAS %x is remote !?", XIVE_EAS(blk, idx));
return -1;
}
@@ -431,7 +431,7 @@ static void pnv_xive_notify(XiveNotifier *xn, uint32_t srcno)
PnvXive *xive = PNV_XIVE(xn);
uint8_t blk = xive->chip->chip_id;
- xive_router_notify(xn, XIVE_SRCNO(blk, srcno));
+ xive_router_notify(xn, XIVE_EAS(blk, srcno));
}
/*
@@ -1225,12 +1225,24 @@ static const MemoryRegionOps pnv_xive_ic_reg_ops = {
static void pnv_xive_ic_hw_trigger(PnvXive *xive, hwaddr addr, uint64_t val)
{
+ uint8_t blk;
+ uint32_t idx;
+
+ if (val & XIVE_TRIGGER_END) {
+ xive_error(xive, "IC: END trigger at @0x%"HWADDR_PRIx" data 0x%"PRIx64,
+ addr, val);
+ return;
+ }
+
/*
* Forward the source event notification directly to the Router.
* The source interrupt number should already be correctly encoded
* with the chip block id by the sending device (PHB, PSI).
*/
- xive_router_notify(XIVE_NOTIFIER(xive), val);
+ blk = XIVE_EAS_BLOCK(val);
+ idx = XIVE_EAS_INDEX(val);
+
+ xive_router_notify(XIVE_NOTIFIER(xive), XIVE_EAS(blk, idx));
}
static void pnv_xive_ic_notify_write(void *opaque, hwaddr addr, uint64_t val,
@@ -1566,7 +1578,7 @@ void pnv_xive_pic_print_info(PnvXive *xive, Monitor *mon)
{
XiveRouter *xrtr = XIVE_ROUTER(xive);
uint8_t blk = xive->chip->chip_id;
- uint32_t srcno0 = XIVE_SRCNO(blk, 0);
+ uint32_t srcno0 = XIVE_EAS(blk, 0);
uint32_t nr_ipis = pnv_xive_nr_ipis(xive);
uint32_t nr_ends = pnv_xive_nr_ends(xive);
XiveEAS eas;
diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c
index 04879ab..d8e1291 100644
--- a/hw/intc/spapr_xive.c
+++ b/hw/intc/spapr_xive.c
@@ -205,23 +205,6 @@ void spapr_xive_mmio_set_enabled(SpaprXive *xive, bool enable)
memory_region_set_enabled(&xive->end_source.esb_mmio, false);
}
-/*
- * When a Virtual Processor is scheduled to run on a HW thread, the
- * hypervisor pushes its identifier in the OS CAM line. Emulate the
- * same behavior under QEMU.
- */
-void spapr_xive_set_tctx_os_cam(XiveTCTX *tctx)
-{
- uint8_t nvt_blk;
- uint32_t nvt_idx;
- uint32_t nvt_cam;
-
- spapr_xive_cpu_to_nvt(POWERPC_CPU(tctx->cs), &nvt_blk, &nvt_idx);
-
- nvt_cam = cpu_to_be32(TM_QW1W2_VO | xive_nvt_cam_line(nvt_blk, nvt_idx));
- memcpy(&tctx->regs[TM_QW1_OS + TM_WORD2], &nvt_cam, 4);
-}
-
static void spapr_xive_end_reset(XiveEND *end)
{
memset(end, 0, sizeof(*end));
@@ -462,10 +445,10 @@ static int vmstate_spapr_xive_pre_save(void *opaque)
* Called by the sPAPR IRQ backend 'post_load' method at the machine
* level.
*/
-int spapr_xive_post_load(SpaprXive *xive, int version_id)
+static int spapr_xive_post_load(SpaprInterruptController *intc, int version_id)
{
if (kvm_irqchip_in_kernel()) {
- return kvmppc_xive_post_load(xive, version_id);
+ return kvmppc_xive_post_load(SPAPR_XIVE(intc), version_id);
}
return 0;
@@ -487,6 +470,42 @@ static const VMStateDescription vmstate_spapr_xive = {
},
};
+static int spapr_xive_claim_irq(SpaprInterruptController *intc, int lisn,
+ bool lsi, Error **errp)
+{
+ SpaprXive *xive = SPAPR_XIVE(intc);
+ XiveSource *xsrc = &xive->source;
+
+ assert(lisn < xive->nr_irqs);
+
+ if (xive_eas_is_valid(&xive->eat[lisn])) {
+ error_setg(errp, "IRQ %d is not free", lisn);
+ return -EBUSY;
+ }
+
+ /*
+ * Set default values when allocating an IRQ number
+ */
+ xive->eat[lisn].w |= cpu_to_be64(EAS_VALID | EAS_MASKED);
+ if (lsi) {
+ xive_source_irq_set_lsi(xsrc, lisn);
+ }
+
+ if (kvm_irqchip_in_kernel()) {
+ return kvmppc_xive_source_reset_one(xsrc, lisn, errp);
+ }
+
+ return 0;
+}
+
+static void spapr_xive_free_irq(SpaprInterruptController *intc, int lisn)
+{
+ SpaprXive *xive = SPAPR_XIVE(intc);
+ assert(lisn < xive->nr_irqs);
+
+ xive->eat[lisn].w &= cpu_to_be64(~EAS_VALID);
+}
+
static Property spapr_xive_properties[] = {
DEFINE_PROP_UINT32("nr-irqs", SpaprXive, nr_irqs, 0),
DEFINE_PROP_UINT32("nr-ends", SpaprXive, nr_ends, 0),
@@ -495,10 +514,167 @@ static Property spapr_xive_properties[] = {
DEFINE_PROP_END_OF_LIST(),
};
+static int spapr_xive_cpu_intc_create(SpaprInterruptController *intc,
+ PowerPCCPU *cpu, Error **errp)
+{
+ SpaprXive *xive = SPAPR_XIVE(intc);
+ Object *obj;
+ SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
+
+ obj = xive_tctx_create(OBJECT(cpu), XIVE_ROUTER(xive), errp);
+ if (!obj) {
+ return -1;
+ }
+
+ spapr_cpu->tctx = XIVE_TCTX(obj);
+ return 0;
+}
+
+static void xive_tctx_set_os_cam(XiveTCTX *tctx, uint32_t os_cam)
+{
+ uint32_t qw1w2 = cpu_to_be32(TM_QW1W2_VO | os_cam);
+ memcpy(&tctx->regs[TM_QW1_OS + TM_WORD2], &qw1w2, 4);
+}
+
+static void spapr_xive_cpu_intc_reset(SpaprInterruptController *intc,
+ PowerPCCPU *cpu)
+{
+ XiveTCTX *tctx = spapr_cpu_state(cpu)->tctx;
+ uint8_t nvt_blk;
+ uint32_t nvt_idx;
+
+ xive_tctx_reset(tctx);
+
+ /*
+ * When a Virtual Processor is scheduled to run on a HW thread,
+ * the hypervisor pushes its identifier in the OS CAM line.
+ * Emulate the same behavior under QEMU.
+ */
+ spapr_xive_cpu_to_nvt(cpu, &nvt_blk, &nvt_idx);
+
+ xive_tctx_set_os_cam(tctx, xive_nvt_cam_line(nvt_blk, nvt_idx));
+}
+
+static void spapr_xive_set_irq(SpaprInterruptController *intc, int irq, int val)
+{
+ SpaprXive *xive = SPAPR_XIVE(intc);
+
+ if (kvm_irqchip_in_kernel()) {
+ kvmppc_xive_source_set_irq(&xive->source, irq, val);
+ } else {
+ xive_source_set_irq(&xive->source, irq, val);
+ }
+}
+
+static void spapr_xive_print_info(SpaprInterruptController *intc, Monitor *mon)
+{
+ SpaprXive *xive = SPAPR_XIVE(intc);
+ CPUState *cs;
+
+ CPU_FOREACH(cs) {
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+
+ xive_tctx_pic_print_info(spapr_cpu_state(cpu)->tctx, mon);
+ }
+
+ spapr_xive_pic_print_info(xive, mon);
+}
+
+static void spapr_xive_dt(SpaprInterruptController *intc, uint32_t nr_servers,
+ void *fdt, uint32_t phandle)
+{
+ SpaprXive *xive = SPAPR_XIVE(intc);
+ 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 */
+ };
+
+ /* 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);
+
+ _FDT(node = fdt_add_subnode(fdt, 0, xive->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)));
+}
+
+static int spapr_xive_activate(SpaprInterruptController *intc, Error **errp)
+{
+ SpaprXive *xive = SPAPR_XIVE(intc);
+
+ if (kvm_enabled()) {
+ int rc = spapr_irq_init_kvm(kvmppc_xive_connect, intc, errp);
+ if (rc < 0) {
+ return rc;
+ }
+ }
+
+ /* Activate the XIVE MMIOs */
+ spapr_xive_mmio_set_enabled(xive, true);
+
+ return 0;
+}
+
+static void spapr_xive_deactivate(SpaprInterruptController *intc)
+{
+ SpaprXive *xive = SPAPR_XIVE(intc);
+
+ spapr_xive_mmio_set_enabled(xive, false);
+
+ if (kvm_irqchip_in_kernel()) {
+ kvmppc_xive_disconnect(intc);
+ }
+}
+
static void spapr_xive_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
XiveRouterClass *xrc = XIVE_ROUTER_CLASS(klass);
+ SpaprInterruptControllerClass *sicc = SPAPR_INTC_CLASS(klass);
dc->desc = "sPAPR XIVE Interrupt Controller";
dc->props = spapr_xive_properties;
@@ -511,6 +687,17 @@ static void spapr_xive_class_init(ObjectClass *klass, void *data)
xrc->get_nvt = spapr_xive_get_nvt;
xrc->write_nvt = spapr_xive_write_nvt;
xrc->get_tctx = spapr_xive_get_tctx;
+
+ sicc->activate = spapr_xive_activate;
+ sicc->deactivate = spapr_xive_deactivate;
+ sicc->cpu_intc_create = spapr_xive_cpu_intc_create;
+ sicc->cpu_intc_reset = spapr_xive_cpu_intc_reset;
+ sicc->claim_irq = spapr_xive_claim_irq;
+ sicc->free_irq = spapr_xive_free_irq;
+ sicc->set_irq = spapr_xive_set_irq;
+ sicc->print_info = spapr_xive_print_info;
+ sicc->dt = spapr_xive_dt;
+ sicc->post_load = spapr_xive_post_load;
}
static const TypeInfo spapr_xive_info = {
@@ -519,6 +706,10 @@ static const TypeInfo spapr_xive_info = {
.instance_init = spapr_xive_instance_init,
.instance_size = sizeof(SpaprXive),
.class_init = spapr_xive_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_SPAPR_INTC },
+ { }
+ },
};
static void spapr_xive_register_types(void)
@@ -528,39 +719,6 @@ static void spapr_xive_register_types(void)
type_init(spapr_xive_register_types)
-int spapr_xive_irq_claim(SpaprXive *xive, int lisn, bool lsi, Error **errp)
-{
- XiveSource *xsrc = &xive->source;
-
- assert(lisn < xive->nr_irqs);
-
- if (xive_eas_is_valid(&xive->eat[lisn])) {
- error_setg(errp, "IRQ %d is not free", lisn);
- return -EBUSY;
- }
-
- /*
- * Set default values when allocating an IRQ number
- */
- xive->eat[lisn].w |= cpu_to_be64(EAS_VALID | EAS_MASKED);
- if (lsi) {
- xive_source_irq_set_lsi(xsrc, lisn);
- }
-
- if (kvm_irqchip_in_kernel()) {
- return kvmppc_xive_source_reset_one(xsrc, lisn, errp);
- }
-
- return 0;
-}
-
-void spapr_xive_irq_free(SpaprXive *xive, int lisn)
-{
- assert(lisn < xive->nr_irqs);
-
- xive->eat[lisn].w &= cpu_to_be64(~EAS_VALID);
-}
-
/*
* XIVE hcalls
*
@@ -1540,65 +1698,3 @@ 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 */
- };
-
- /* 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);
-
- _FDT(node = fdt_add_subnode(fdt, 0, xive->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)));
-}
diff --git a/hw/intc/spapr_xive_kvm.c b/hw/intc/spapr_xive_kvm.c
index 51b334b..08012ac 100644
--- a/hw/intc/spapr_xive_kvm.c
+++ b/hw/intc/spapr_xive_kvm.c
@@ -740,8 +740,9 @@ static void *kvmppc_xive_mmap(SpaprXive *xive, int pgoff, size_t len,
* All the XIVE memory regions are now backed by mappings from the KVM
* XIVE device.
*/
-void kvmppc_xive_connect(SpaprXive *xive, Error **errp)
+int kvmppc_xive_connect(SpaprInterruptController *intc, Error **errp)
{
+ SpaprXive *xive = SPAPR_XIVE(intc);
XiveSource *xsrc = &xive->source;
Error *local_err = NULL;
size_t esb_len = (1ull << xsrc->esb_shift) * xsrc->nr_irqs;
@@ -753,19 +754,19 @@ void kvmppc_xive_connect(SpaprXive *xive, Error **errp)
* rebooting under the XIVE-only interrupt mode.
*/
if (xive->fd != -1) {
- return;
+ return 0;
}
if (!kvmppc_has_cap_xive()) {
error_setg(errp, "IRQ_XIVE capability must be present for KVM");
- return;
+ return -1;
}
/* First, create the KVM XIVE device */
xive->fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_XIVE, false);
if (xive->fd < 0) {
error_setg_errno(errp, -xive->fd, "XIVE: error creating KVM device");
- return;
+ return -1;
}
/*
@@ -821,15 +822,17 @@ void kvmppc_xive_connect(SpaprXive *xive, Error **errp)
kvm_kernel_irqchip = true;
kvm_msi_via_irqfd_allowed = true;
kvm_gsi_direct_mapping = true;
- return;
+ return 0;
fail:
error_propagate(errp, local_err);
- kvmppc_xive_disconnect(xive, NULL);
+ kvmppc_xive_disconnect(intc);
+ return -1;
}
-void kvmppc_xive_disconnect(SpaprXive *xive, Error **errp)
+void kvmppc_xive_disconnect(SpaprInterruptController *intc)
{
+ SpaprXive *xive = SPAPR_XIVE(intc);
XiveSource *xsrc;
size_t esb_len;
@@ -838,11 +841,6 @@ void kvmppc_xive_disconnect(SpaprXive *xive, Error **errp)
return;
}
- if (!kvmppc_has_cap_xive()) {
- error_setg(errp, "IRQ_XIVE capability must be present for KVM");
- return;
- }
-
/* Clear the KVM mapping */
xsrc = &xive->source;
esb_len = (1ull << xsrc->esb_shift) * xsrc->nr_irqs;
diff --git a/hw/intc/xics.c b/hw/intc/xics.c
index dfe7dbd..6da0576 100644
--- a/hw/intc/xics.c
+++ b/hw/intc/xics.c
@@ -274,10 +274,8 @@ static const VMStateDescription vmstate_icp_server = {
},
};
-static void icp_reset_handler(void *dev)
+void icp_reset(ICPState *icp)
{
- ICPState *icp = ICP(dev);
-
icp->xirr = 0;
icp->pending_priority = 0xff;
icp->mfrr = 0xff;
@@ -288,7 +286,7 @@ static void icp_reset_handler(void *dev)
if (kvm_irqchip_in_kernel()) {
Error *local_err = NULL;
- icp_set_kvm_state(ICP(dev), &local_err);
+ icp_set_kvm_state(icp, &local_err);
if (local_err) {
error_report_err(local_err);
}
@@ -351,7 +349,6 @@ static void icp_realize(DeviceState *dev, Error **errp)
}
}
- qemu_register_reset(icp_reset_handler, dev);
vmstate_register(NULL, icp->cs->cpu_index, &vmstate_icp_server, icp);
}
@@ -360,7 +357,6 @@ static void icp_unrealize(DeviceState *dev, Error **errp)
ICPState *icp = ICP(dev);
vmstate_unregister(NULL, &vmstate_icp_server, icp);
- qemu_unregister_reset(icp_reset_handler, dev);
}
static void icp_class_init(ObjectClass *klass, void *data)
@@ -369,6 +365,11 @@ static void icp_class_init(ObjectClass *klass, void *data)
dc->realize = icp_realize;
dc->unrealize = icp_unrealize;
+ /*
+ * Reason: part of XICS interrupt controller, needs to be wired up
+ * by icp_create().
+ */
+ dc->user_creatable = false;
}
static const TypeInfo icp_info = {
@@ -689,6 +690,11 @@ static void ics_class_init(ObjectClass *klass, void *data)
dc->props = ics_properties;
dc->reset = ics_reset;
dc->vmsd = &vmstate_ics;
+ /*
+ * Reason: part of XICS interrupt controller, needs to be wired up,
+ * e.g. by spapr_irq_init().
+ */
+ dc->user_creatable = false;
}
static const TypeInfo ics_info = {
diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c
index ba90d6d..954c424 100644
--- a/hw/intc/xics_kvm.c
+++ b/hw/intc/xics_kvm.c
@@ -342,8 +342,9 @@ void ics_kvm_set_irq(ICSState *ics, int srcno, int val)
}
}
-int xics_kvm_connect(SpaprMachineState *spapr, Error **errp)
+int xics_kvm_connect(SpaprInterruptController *intc, Error **errp)
{
+ ICSState *ics = ICS_SPAPR(intc);
int rc;
CPUState *cs;
Error *local_err = NULL;
@@ -413,7 +414,7 @@ int xics_kvm_connect(SpaprMachineState *spapr, Error **errp)
}
/* Update the KVM sources */
- ics_set_kvm_state(spapr->ics, &local_err);
+ ics_set_kvm_state(ics, &local_err);
if (local_err) {
goto fail;
}
@@ -431,11 +432,11 @@ int xics_kvm_connect(SpaprMachineState *spapr, Error **errp)
fail:
error_propagate(errp, local_err);
- xics_kvm_disconnect(spapr, NULL);
+ xics_kvm_disconnect(intc);
return -1;
}
-void xics_kvm_disconnect(SpaprMachineState *spapr, Error **errp)
+void xics_kvm_disconnect(SpaprInterruptController *intc)
{
/*
* Only on P9 using the XICS-on XIVE KVM device:
diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c
index 6e5eb24..7418fb9 100644
--- a/hw/intc/xics_spapr.c
+++ b/hw/intc/xics_spapr.c
@@ -308,8 +308,8 @@ static void ics_spapr_realize(DeviceState *dev, Error **errp)
spapr_register_hypercall(H_IPOLL, h_ipoll);
}
-void spapr_dt_xics(SpaprMachineState *spapr, uint32_t nr_servers, void *fdt,
- uint32_t phandle)
+static void xics_spapr_dt(SpaprInterruptController *intc, uint32_t nr_servers,
+ void *fdt, uint32_t phandle)
{
uint32_t interrupt_server_ranges_prop[] = {
0, cpu_to_be32(nr_servers),
@@ -330,19 +330,132 @@ void spapr_dt_xics(SpaprMachineState *spapr, uint32_t nr_servers, void *fdt,
_FDT(fdt_setprop_cell(fdt, node, "phandle", phandle));
}
+static int xics_spapr_cpu_intc_create(SpaprInterruptController *intc,
+ PowerPCCPU *cpu, Error **errp)
+{
+ ICSState *ics = ICS_SPAPR(intc);
+ Object *obj;
+ SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
+
+ obj = icp_create(OBJECT(cpu), TYPE_ICP, ics->xics, errp);
+ if (!obj) {
+ return -1;
+ }
+
+ spapr_cpu->icp = ICP(obj);
+ return 0;
+}
+
+static void xics_spapr_cpu_intc_reset(SpaprInterruptController *intc,
+ PowerPCCPU *cpu)
+{
+ icp_reset(spapr_cpu_state(cpu)->icp);
+}
+
+static int xics_spapr_claim_irq(SpaprInterruptController *intc, int irq,
+ bool lsi, Error **errp)
+{
+ ICSState *ics = ICS_SPAPR(intc);
+
+ assert(ics);
+ assert(ics_valid_irq(ics, irq));
+
+ if (!ics_irq_free(ics, irq - ics->offset)) {
+ error_setg(errp, "IRQ %d is not free", irq);
+ return -EBUSY;
+ }
+
+ ics_set_irq_type(ics, irq - ics->offset, lsi);
+ return 0;
+}
+
+static void xics_spapr_free_irq(SpaprInterruptController *intc, int irq)
+{
+ ICSState *ics = ICS_SPAPR(intc);
+ uint32_t srcno = irq - ics->offset;
+
+ assert(ics_valid_irq(ics, irq));
+
+ memset(&ics->irqs[srcno], 0, sizeof(ICSIRQState));
+}
+
+static void xics_spapr_set_irq(SpaprInterruptController *intc, int irq, int val)
+{
+ ICSState *ics = ICS_SPAPR(intc);
+ uint32_t srcno = irq - ics->offset;
+
+ ics_set_irq(ics, srcno, val);
+}
+
+static void xics_spapr_print_info(SpaprInterruptController *intc, Monitor *mon)
+{
+ ICSState *ics = ICS_SPAPR(intc);
+ CPUState *cs;
+
+ CPU_FOREACH(cs) {
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+
+ icp_pic_print_info(spapr_cpu_state(cpu)->icp, mon);
+ }
+
+ ics_pic_print_info(ics, mon);
+}
+
+static int xics_spapr_post_load(SpaprInterruptController *intc, int version_id)
+{
+ if (!kvm_irqchip_in_kernel()) {
+ CPUState *cs;
+ CPU_FOREACH(cs) {
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ icp_resend(spapr_cpu_state(cpu)->icp);
+ }
+ }
+ return 0;
+}
+
+static int xics_spapr_activate(SpaprInterruptController *intc, Error **errp)
+{
+ if (kvm_enabled()) {
+ return spapr_irq_init_kvm(xics_kvm_connect, intc, errp);
+ }
+ return 0;
+}
+
+static void xics_spapr_deactivate(SpaprInterruptController *intc)
+{
+ if (kvm_irqchip_in_kernel()) {
+ xics_kvm_disconnect(intc);
+ }
+}
+
static void ics_spapr_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ICSStateClass *isc = ICS_CLASS(klass);
+ SpaprInterruptControllerClass *sicc = SPAPR_INTC_CLASS(klass);
device_class_set_parent_realize(dc, ics_spapr_realize,
&isc->parent_realize);
+ sicc->activate = xics_spapr_activate;
+ sicc->deactivate = xics_spapr_deactivate;
+ sicc->cpu_intc_create = xics_spapr_cpu_intc_create;
+ sicc->cpu_intc_reset = xics_spapr_cpu_intc_reset;
+ sicc->claim_irq = xics_spapr_claim_irq;
+ sicc->free_irq = xics_spapr_free_irq;
+ sicc->set_irq = xics_spapr_set_irq;
+ sicc->print_info = xics_spapr_print_info;
+ sicc->dt = xics_spapr_dt;
+ sicc->post_load = xics_spapr_post_load;
}
static const TypeInfo ics_spapr_info = {
.name = TYPE_ICS_SPAPR,
.parent = TYPE_ICS,
.class_init = ics_spapr_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_SPAPR_INTC },
+ { }
+ },
};
static void xics_spapr_register_types(void)
diff --git a/hw/intc/xive.c b/hw/intc/xive.c
index 29df06d..f066be5 100644
--- a/hw/intc/xive.c
+++ b/hw/intc/xive.c
@@ -547,10 +547,8 @@ void xive_tctx_pic_print_info(XiveTCTX *tctx, Monitor *mon)
}
}
-static void xive_tctx_reset(void *dev)
+void xive_tctx_reset(XiveTCTX *tctx)
{
- XiveTCTX *tctx = XIVE_TCTX(dev);
-
memset(tctx->regs, 0, sizeof(tctx->regs));
/* Set some defaults */
@@ -607,13 +605,6 @@ static void xive_tctx_realize(DeviceState *dev, Error **errp)
return;
}
}
-
- qemu_register_reset(xive_tctx_reset, dev);
-}
-
-static void xive_tctx_unrealize(DeviceState *dev, Error **errp)
-{
- qemu_unregister_reset(xive_tctx_reset, dev);
}
static int vmstate_xive_tctx_pre_save(void *opaque)
@@ -668,8 +659,12 @@ static void xive_tctx_class_init(ObjectClass *klass, void *data)
dc->desc = "XIVE Interrupt Thread Context";
dc->realize = xive_tctx_realize;
- dc->unrealize = xive_tctx_unrealize;
dc->vmsd = &vmstate_xive_tctx;
+ /*
+ * Reason: part of XIVE interrupt controller, needs to be wired up
+ * by xive_tctx_create().
+ */
+ dc->user_creatable = false;
}
static const TypeInfo xive_tctx_info = {
@@ -1118,6 +1113,11 @@ static void xive_source_class_init(ObjectClass *klass, void *data)
dc->props = xive_source_properties;
dc->realize = xive_source_realize;
dc->vmsd = &vmstate_xive_source;
+ /*
+ * Reason: part of XIVE interrupt controller, needs to be wired up,
+ * e.g. by spapr_xive_instance_init().
+ */
+ dc->user_creatable = false;
}
static const TypeInfo xive_source_info = {
@@ -1648,8 +1648,8 @@ do_escalation:
void xive_router_notify(XiveNotifier *xn, uint32_t lisn)
{
XiveRouter *xrtr = XIVE_ROUTER(xn);
- uint8_t eas_blk = XIVE_SRCNO_BLOCK(lisn);
- uint32_t eas_idx = XIVE_SRCNO_INDEX(lisn);
+ uint8_t eas_blk = XIVE_EAS_BLOCK(lisn);
+ uint32_t eas_idx = XIVE_EAS_INDEX(lisn);
XiveEAS eas;
/* EAS cache lookup */
@@ -1853,6 +1853,11 @@ static void xive_end_source_class_init(ObjectClass *klass, void *data)
dc->desc = "XIVE END Source";
dc->props = xive_end_source_properties;
dc->realize = xive_end_source_realize;
+ /*
+ * Reason: part of XIVE interrupt controller, needs to be wired up,
+ * e.g. by spapr_xive_instance_init().
+ */
+ dc->user_creatable = false;
}
static const TypeInfo xive_end_source_info = {