diff options
Diffstat (limited to 'hw/ppc/spapr_irq.c')
-rw-r--r-- | hw/ppc/spapr_irq.c | 345 |
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, }; |