aboutsummaryrefslogtreecommitdiff
path: root/hw/ppc/spapr_irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/ppc/spapr_irq.c')
-rw-r--r--hw/ppc/spapr_irq.c345
1 files changed, 139 insertions, 206 deletions
diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c
index 06fe2432ba..457eabe24c 100644
--- a/hw/ppc/spapr_irq.c
+++ b/hw/ppc/spapr_irq.c
@@ -92,44 +92,15 @@ static void spapr_irq_init_kvm(SpaprMachineState *spapr,
* XICS IRQ backend.
*/
-static void spapr_irq_init_xics(SpaprMachineState *spapr, int nr_irqs,
- Error **errp)
-{
- Object *obj;
- Error *local_err = NULL;
-
- obj = object_new(TYPE_ICS_SIMPLE);
- object_property_add_child(OBJECT(spapr), "ics", obj, &error_abort);
- object_property_add_const_link(obj, ICS_PROP_XICS, OBJECT(spapr),
- &error_fatal);
- object_property_set_int(obj, nr_irqs, "nr-irqs", &error_fatal);
- object_property_set_bool(obj, true, "realized", &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- spapr->ics = ICS_BASE(obj);
-
- xics_spapr_init(spapr);
-}
-
-#define ICS_IRQ_FREE(ics, srcno) \
- (!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK)))
-
static int spapr_irq_claim_xics(SpaprMachineState *spapr, int irq, bool lsi,
Error **errp)
{
ICSState *ics = spapr->ics;
assert(ics);
+ assert(ics_valid_irq(ics, irq));
- if (!ics_valid_irq(ics, irq)) {
- error_setg(errp, "IRQ %d is invalid", irq);
- return -1;
- }
-
- if (!ICS_IRQ_FREE(ics, irq - ics->offset)) {
+ if (!ics_irq_free(ics, irq - ics->offset)) {
error_setg(errp, "IRQ %d is not free", irq);
return -1;
}
@@ -138,33 +109,14 @@ static int spapr_irq_claim_xics(SpaprMachineState *spapr, int irq, bool lsi,
return 0;
}
-static void spapr_irq_free_xics(SpaprMachineState *spapr, int irq, int num)
+static void spapr_irq_free_xics(SpaprMachineState *spapr, int irq)
{
ICSState *ics = spapr->ics;
uint32_t srcno = irq - ics->offset;
- int i;
- if (ics_valid_irq(ics, irq)) {
- trace_spapr_irq_free(0, irq, num);
- for (i = srcno; i < srcno + num; ++i) {
- if (ICS_IRQ_FREE(ics, i)) {
- trace_spapr_irq_free_warn(0, i);
- }
- memset(&ics->irqs[i], 0, sizeof(ICSIRQState));
- }
- }
-}
+ assert(ics_valid_irq(ics, irq));
-static qemu_irq spapr_qirq_xics(SpaprMachineState *spapr, int irq)
-{
- ICSState *ics = spapr->ics;
- uint32_t srcno = irq - ics->offset;
-
- if (ics_valid_irq(ics, irq)) {
- return spapr->qirqs[srcno];
- }
-
- return NULL;
+ memset(&ics->irqs[srcno], 0, sizeof(ICSIRQState));
}
static void spapr_irq_print_info_xics(SpaprMachineState *spapr, Monitor *mon)
@@ -209,11 +161,12 @@ static int spapr_irq_post_load_xics(SpaprMachineState *spapr, int version_id)
return 0;
}
-static void spapr_irq_set_irq_xics(void *opaque, int srcno, int val)
+static void spapr_irq_set_irq_xics(void *opaque, int irq, int val)
{
SpaprMachineState *spapr = opaque;
+ uint32_t srcno = irq - spapr->ics->offset;
- ics_simple_set_irq(spapr->ics, srcno, val);
+ ics_set_irq(spapr->ics, srcno, val);
}
static void spapr_irq_reset_xics(SpaprMachineState *spapr, Error **errp)
@@ -227,11 +180,6 @@ static void spapr_irq_reset_xics(SpaprMachineState *spapr, Error **errp)
}
}
-static const char *spapr_irq_get_nodename_xics(SpaprMachineState *spapr)
-{
- return XICS_NODENAME;
-}
-
static void spapr_irq_init_kvm_xics(SpaprMachineState *spapr, Error **errp)
{
if (kvm_enabled()) {
@@ -239,88 +187,36 @@ static void spapr_irq_init_kvm_xics(SpaprMachineState *spapr, Error **errp)
}
}
-#define SPAPR_IRQ_XICS_NR_IRQS 0x1000
-#define SPAPR_IRQ_XICS_NR_MSIS \
- (XICS_IRQ_BASE + SPAPR_IRQ_XICS_NR_IRQS - SPAPR_IRQ_MSI)
-
SpaprIrq spapr_irq_xics = {
- .nr_irqs = SPAPR_IRQ_XICS_NR_IRQS,
- .nr_msis = SPAPR_IRQ_XICS_NR_MSIS,
- .ov5 = SPAPR_OV5_XIVE_LEGACY,
+ .nr_xirqs = SPAPR_NR_XIRQS,
+ .nr_msis = SPAPR_NR_MSIS,
+ .xics = true,
+ .xive = false,
- .init = spapr_irq_init_xics,
.claim = spapr_irq_claim_xics,
.free = spapr_irq_free_xics,
- .qirq = spapr_qirq_xics,
.print_info = spapr_irq_print_info_xics,
.dt_populate = spapr_dt_xics,
.cpu_intc_create = spapr_irq_cpu_intc_create_xics,
.post_load = spapr_irq_post_load_xics,
.reset = spapr_irq_reset_xics,
.set_irq = spapr_irq_set_irq_xics,
- .get_nodename = spapr_irq_get_nodename_xics,
.init_kvm = spapr_irq_init_kvm_xics,
};
/*
* XIVE IRQ backend.
*/
-static void spapr_irq_init_xive(SpaprMachineState *spapr, int nr_irqs,
- Error **errp)
-{
- uint32_t nr_servers = spapr_max_server_number(spapr);
- DeviceState *dev;
- int i;
-
- dev = qdev_create(NULL, TYPE_SPAPR_XIVE);
- qdev_prop_set_uint32(dev, "nr-irqs", nr_irqs);
- /*
- * 8 XIVE END structures per CPU. One for each available priority
- */
- qdev_prop_set_uint32(dev, "nr-ends", nr_servers << 3);
- qdev_init_nofail(dev);
-
- spapr->xive = SPAPR_XIVE(dev);
-
- /* Enable the CPU IPIs */
- for (i = 0; i < nr_servers; ++i) {
- spapr_xive_irq_claim(spapr->xive, SPAPR_IRQ_IPI + i, false);
- }
-
- spapr_xive_hcall_init(spapr);
-}
static int spapr_irq_claim_xive(SpaprMachineState *spapr, int irq, bool lsi,
Error **errp)
{
- if (!spapr_xive_irq_claim(spapr->xive, irq, lsi)) {
- error_setg(errp, "IRQ %d is invalid", irq);
- return -1;
- }
- return 0;
+ return spapr_xive_irq_claim(spapr->xive, irq, lsi, errp);
}
-static void spapr_irq_free_xive(SpaprMachineState *spapr, int irq, int num)
+static void spapr_irq_free_xive(SpaprMachineState *spapr, int irq)
{
- int i;
-
- for (i = irq; i < irq + num; ++i) {
- spapr_xive_irq_free(spapr->xive, i);
- }
-}
-
-static qemu_irq spapr_qirq_xive(SpaprMachineState *spapr, int irq)
-{
- SpaprXive *xive = spapr->xive;
-
- if (irq >= xive->nr_irqs) {
- return NULL;
- }
-
- /* The sPAPR machine/device should have claimed the IRQ before */
- assert(xive_eas_is_valid(&xive->eat[irq]));
-
- return spapr->qirqs[irq];
+ spapr_xive_irq_free(spapr->xive, irq);
}
static void spapr_irq_print_info_xive(SpaprMachineState *spapr,
@@ -386,22 +282,17 @@ static void spapr_irq_reset_xive(SpaprMachineState *spapr, Error **errp)
spapr_xive_mmio_set_enabled(spapr->xive, true);
}
-static void spapr_irq_set_irq_xive(void *opaque, int srcno, int val)
+static void spapr_irq_set_irq_xive(void *opaque, int irq, int val)
{
SpaprMachineState *spapr = opaque;
if (kvm_irqchip_in_kernel()) {
- kvmppc_xive_source_set_irq(&spapr->xive->source, srcno, val);
+ kvmppc_xive_source_set_irq(&spapr->xive->source, irq, val);
} else {
- xive_source_set_irq(&spapr->xive->source, srcno, val);
+ xive_source_set_irq(&spapr->xive->source, irq, val);
}
}
-static const char *spapr_irq_get_nodename_xive(SpaprMachineState *spapr)
-{
- return spapr->xive->nodename;
-}
-
static void spapr_irq_init_kvm_xive(SpaprMachineState *spapr, Error **errp)
{
if (kvm_enabled()) {
@@ -409,30 +300,20 @@ static void spapr_irq_init_kvm_xive(SpaprMachineState *spapr, Error **errp)
}
}
-/*
- * XIVE uses the full IRQ number space. Set it to 8K to be compatible
- * with XICS.
- */
-
-#define SPAPR_IRQ_XIVE_NR_IRQS 0x2000
-#define SPAPR_IRQ_XIVE_NR_MSIS (SPAPR_IRQ_XIVE_NR_IRQS - SPAPR_IRQ_MSI)
-
SpaprIrq spapr_irq_xive = {
- .nr_irqs = SPAPR_IRQ_XIVE_NR_IRQS,
- .nr_msis = SPAPR_IRQ_XIVE_NR_MSIS,
- .ov5 = SPAPR_OV5_XIVE_EXPLOIT,
+ .nr_xirqs = SPAPR_NR_XIRQS,
+ .nr_msis = SPAPR_NR_MSIS,
+ .xics = false,
+ .xive = true,
- .init = spapr_irq_init_xive,
.claim = spapr_irq_claim_xive,
.free = spapr_irq_free_xive,
- .qirq = spapr_qirq_xive,
.print_info = spapr_irq_print_info_xive,
.dt_populate = spapr_dt_xive,
.cpu_intc_create = spapr_irq_cpu_intc_create_xive,
.post_load = spapr_irq_post_load_xive,
.reset = spapr_irq_reset_xive,
.set_irq = spapr_irq_set_irq_xive,
- .get_nodename = spapr_irq_get_nodename_xive,
.init_kvm = spapr_irq_init_kvm_xive,
};
@@ -455,24 +336,6 @@ static SpaprIrq *spapr_irq_current(SpaprMachineState *spapr)
&spapr_irq_xive : &spapr_irq_xics;
}
-static void spapr_irq_init_dual(SpaprMachineState *spapr, int nr_irqs,
- Error **errp)
-{
- Error *local_err = NULL;
-
- spapr_irq_xics.init(spapr, spapr_irq_xics.nr_irqs, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-
- spapr_irq_xive.init(spapr, spapr_irq_xive.nr_irqs, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-}
-
static int spapr_irq_claim_dual(SpaprMachineState *spapr, int irq, bool lsi,
Error **errp)
{
@@ -494,15 +357,10 @@ static int spapr_irq_claim_dual(SpaprMachineState *spapr, int irq, bool lsi,
return ret;
}
-static void spapr_irq_free_dual(SpaprMachineState *spapr, int irq, int num)
+static void spapr_irq_free_dual(SpaprMachineState *spapr, int irq)
{
- spapr_irq_xics.free(spapr, irq, num);
- spapr_irq_xive.free(spapr, irq, num);
-}
-
-static qemu_irq spapr_qirq_dual(SpaprMachineState *spapr, int irq)
-{
- return spapr_irq_current(spapr)->qirq(spapr, irq);
+ spapr_irq_xics.free(spapr, irq);
+ spapr_irq_xive.free(spapr, irq);
}
static void spapr_irq_print_info_dual(SpaprMachineState *spapr, Monitor *mon)
@@ -576,45 +434,35 @@ static void spapr_irq_reset_dual(SpaprMachineState *spapr, Error **errp)
spapr_irq_current(spapr)->reset(spapr, errp);
}
-static void spapr_irq_set_irq_dual(void *opaque, int srcno, int val)
+static void spapr_irq_set_irq_dual(void *opaque, int irq, int val)
{
SpaprMachineState *spapr = opaque;
- spapr_irq_current(spapr)->set_irq(spapr, srcno, val);
-}
-
-static const char *spapr_irq_get_nodename_dual(SpaprMachineState *spapr)
-{
- return spapr_irq_current(spapr)->get_nodename(spapr);
+ spapr_irq_current(spapr)->set_irq(spapr, irq, val);
}
/*
* Define values in sync with the XIVE and XICS backend
*/
-#define SPAPR_IRQ_DUAL_NR_IRQS 0x2000
-#define SPAPR_IRQ_DUAL_NR_MSIS (SPAPR_IRQ_DUAL_NR_IRQS - SPAPR_IRQ_MSI)
-
SpaprIrq spapr_irq_dual = {
- .nr_irqs = SPAPR_IRQ_DUAL_NR_IRQS,
- .nr_msis = SPAPR_IRQ_DUAL_NR_MSIS,
- .ov5 = SPAPR_OV5_XIVE_BOTH,
+ .nr_xirqs = SPAPR_NR_XIRQS,
+ .nr_msis = SPAPR_NR_MSIS,
+ .xics = true,
+ .xive = true,
- .init = spapr_irq_init_dual,
.claim = spapr_irq_claim_dual,
.free = spapr_irq_free_dual,
- .qirq = spapr_qirq_dual,
.print_info = spapr_irq_print_info_dual,
.dt_populate = spapr_irq_dt_populate_dual,
.cpu_intc_create = spapr_irq_cpu_intc_create_dual,
.post_load = spapr_irq_post_load_dual,
.reset = spapr_irq_reset_dual,
.set_irq = spapr_irq_set_irq_dual,
- .get_nodename = spapr_irq_get_nodename_dual,
.init_kvm = NULL, /* should not be used */
};
-static void spapr_irq_check(SpaprMachineState *spapr, Error **errp)
+static int spapr_irq_check(SpaprMachineState *spapr, Error **errp)
{
MachineState *machine = MACHINE(spapr);
@@ -630,7 +478,7 @@ static void spapr_irq_check(SpaprMachineState *spapr, Error **errp)
*/
if (spapr->irq == &spapr_irq_dual) {
spapr->irq = &spapr_irq_xics;
- return;
+ return 0;
}
/*
@@ -650,7 +498,7 @@ static void spapr_irq_check(SpaprMachineState *spapr, Error **errp)
*/
if (spapr->irq == &spapr_irq_xive) {
error_setg(errp, "XIVE-only machines require a POWER9 CPU");
- return;
+ return -1;
}
}
@@ -664,8 +512,10 @@ static void spapr_irq_check(SpaprMachineState *spapr, Error **errp)
machine_kernel_irqchip_required(machine) &&
xics_kvm_has_broken_disconnect(spapr)) {
error_setg(errp, "KVM is too old to support ic-mode=dual,kernel-irqchip=on");
- return;
+ return -1;
}
+
+ return 0;
}
/*
@@ -674,7 +524,6 @@ static void spapr_irq_check(SpaprMachineState *spapr, Error **errp)
void spapr_irq_init(SpaprMachineState *spapr, Error **errp)
{
MachineState *machine = MACHINE(spapr);
- Error *local_err = NULL;
if (machine_kernel_irqchip_split(machine)) {
error_setg(errp, "kernel_irqchip split mode not supported on pseries");
@@ -687,9 +536,7 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp)
return;
}
- spapr_irq_check(spapr, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
+ if (spapr_irq_check(spapr, errp) < 0) {
return;
}
@@ -698,25 +545,113 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp)
spapr_irq_msi_init(spapr, spapr->irq->nr_msis);
}
- spapr->irq->init(spapr, spapr->irq->nr_irqs, errp);
+ if (spapr->irq->xics) {
+ Error *local_err = NULL;
+ Object *obj;
+
+ obj = object_new(TYPE_ICS_SPAPR);
+ object_property_add_child(OBJECT(spapr), "ics", obj, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ object_property_add_const_link(obj, ICS_PROP_XICS, OBJECT(spapr),
+ &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ object_property_set_int(obj, spapr->irq->nr_xirqs, "nr-irqs",
+ &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ object_property_set_bool(obj, true, "realized", &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ spapr->ics = ICS_SPAPR(obj);
+ }
+
+ if (spapr->irq->xive) {
+ uint32_t nr_servers = spapr_max_server_number(spapr);
+ DeviceState *dev;
+ int i;
+
+ dev = qdev_create(NULL, TYPE_SPAPR_XIVE);
+ qdev_prop_set_uint32(dev, "nr-irqs",
+ spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE);
+ /*
+ * 8 XIVE END structures per CPU. One for each available
+ * priority
+ */
+ qdev_prop_set_uint32(dev, "nr-ends", nr_servers << 3);
+ qdev_init_nofail(dev);
+
+ spapr->xive = SPAPR_XIVE(dev);
+
+ /* Enable the CPU IPIs */
+ for (i = 0; i < nr_servers; ++i) {
+ if (spapr_xive_irq_claim(spapr->xive, SPAPR_IRQ_IPI + i,
+ false, errp) < 0) {
+ return;
+ }
+ }
+
+ spapr_xive_hcall_init(spapr);
+ }
spapr->qirqs = qemu_allocate_irqs(spapr->irq->set_irq, spapr,
- spapr->irq->nr_irqs);
+ spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE);
}
int spapr_irq_claim(SpaprMachineState *spapr, int irq, bool lsi, Error **errp)
{
+ assert(irq >= SPAPR_XIRQ_BASE);
+ assert(irq < (spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE));
+
return spapr->irq->claim(spapr, irq, lsi, errp);
}
void spapr_irq_free(SpaprMachineState *spapr, int irq, int num)
{
- spapr->irq->free(spapr, irq, num);
+ int i;
+
+ assert(irq >= SPAPR_XIRQ_BASE);
+ assert((irq + num) <= (spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE));
+
+ for (i = irq; i < (irq + num); i++) {
+ spapr->irq->free(spapr, i);
+ }
}
qemu_irq spapr_qirq(SpaprMachineState *spapr, int irq)
{
- return spapr->irq->qirq(spapr, irq);
+ /*
+ * This interface is basically for VIO and PHB devices to find the
+ * right qemu_irq to manipulate, so we only allow access to the
+ * external irqs for now. Currently anything which needs to
+ * access the IPIs most naturally gets there via the guest side
+ * interfaces, we can change this if we need to in future.
+ */
+ assert(irq >= SPAPR_XIRQ_BASE);
+ assert(irq < (spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE));
+
+ if (spapr->ics) {
+ assert(ics_valid_irq(spapr->ics, irq));
+ }
+ if (spapr->xive) {
+ assert(irq < spapr->xive->nr_irqs);
+ assert(xive_eas_is_valid(&spapr->xive->eat[irq]));
+ }
+
+ return spapr->qirqs[irq];
}
int spapr_irq_post_load(SpaprMachineState *spapr, int version_id)
@@ -735,13 +670,13 @@ void spapr_irq_reset(SpaprMachineState *spapr, Error **errp)
int spapr_irq_get_phandle(SpaprMachineState *spapr, void *fdt, Error **errp)
{
- const char *nodename = spapr->irq->get_nodename(spapr);
+ const char *nodename = "interrupt-controller";
int offset, phandle;
offset = fdt_subnode_offset(fdt, 0, nodename);
if (offset < 0) {
- error_setg(errp, "Can't find node \"%s\": %s", nodename,
- fdt_strerror(offset));
+ error_setg(errp, "Can't find node \"%s\": %s",
+ nodename, fdt_strerror(offset));
return -1;
}
@@ -767,7 +702,7 @@ static int ics_find_free_block(ICSState *ics, int num, int alignnum)
return -1;
}
for (i = first; i < first + num; ++i) {
- if (!ICS_IRQ_FREE(ics, i)) {
+ if (!ics_irq_free(ics, i)) {
break;
}
}
@@ -809,23 +744,21 @@ int spapr_irq_find(SpaprMachineState *spapr, int num, bool align, Error **errp)
return first + ics->offset;
}
-#define SPAPR_IRQ_XICS_LEGACY_NR_IRQS 0x400
+#define SPAPR_IRQ_XICS_LEGACY_NR_XIRQS 0x400
SpaprIrq spapr_irq_xics_legacy = {
- .nr_irqs = SPAPR_IRQ_XICS_LEGACY_NR_IRQS,
- .nr_msis = SPAPR_IRQ_XICS_LEGACY_NR_IRQS,
- .ov5 = SPAPR_OV5_XIVE_LEGACY,
+ .nr_xirqs = SPAPR_IRQ_XICS_LEGACY_NR_XIRQS,
+ .nr_msis = SPAPR_IRQ_XICS_LEGACY_NR_XIRQS,
+ .xics = true,
+ .xive = false,
- .init = spapr_irq_init_xics,
.claim = spapr_irq_claim_xics,
.free = spapr_irq_free_xics,
- .qirq = spapr_qirq_xics,
.print_info = spapr_irq_print_info_xics,
.dt_populate = spapr_dt_xics,
.cpu_intc_create = spapr_irq_cpu_intc_create_xics,
.post_load = spapr_irq_post_load_xics,
.reset = spapr_irq_reset_xics,
.set_irq = spapr_irq_set_irq_xics,
- .get_nodename = spapr_irq_get_nodename_xics,
.init_kvm = spapr_irq_init_kvm_xics,
};