diff options
Diffstat (limited to 'hw/ppc')
-rw-r--r-- | hw/ppc/pnv.c | 18 | ||||
-rw-r--r-- | hw/ppc/pnv_core.c | 31 | ||||
-rw-r--r-- | hw/ppc/pnv_psi.c | 15 | ||||
-rw-r--r-- | hw/ppc/spapr.c | 26 | ||||
-rw-r--r-- | hw/ppc/spapr_cpu_core.c | 47 | ||||
-rw-r--r-- | hw/ppc/spapr_irq.c | 611 | ||||
-rw-r--r-- | hw/ppc/spapr_pci.c | 7 |
7 files changed, 324 insertions, 431 deletions
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 7cf64b6..4a51fb6 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -778,6 +778,13 @@ static void pnv_chip_power8_intc_create(PnvChip *chip, PowerPCCPU *cpu, pnv_cpu->intc = obj; } +static void pnv_chip_power8_intc_reset(PnvChip *chip, PowerPCCPU *cpu) +{ + PnvCPUState *pnv_cpu = pnv_cpu_state(cpu); + + icp_reset(ICP(pnv_cpu->intc)); +} + /* * 0:48 Reserved - Read as zeroes * 49:52 Node ID @@ -815,6 +822,13 @@ static void pnv_chip_power9_intc_create(PnvChip *chip, PowerPCCPU *cpu, pnv_cpu->intc = obj; } +static void pnv_chip_power9_intc_reset(PnvChip *chip, PowerPCCPU *cpu) +{ + PnvCPUState *pnv_cpu = pnv_cpu_state(cpu); + + xive_tctx_reset(XIVE_TCTX(pnv_cpu->intc)); +} + /* * Allowed core identifiers on a POWER8 Processor Chip : * @@ -984,6 +998,7 @@ static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data) k->cores_mask = POWER8E_CORE_MASK; k->core_pir = pnv_chip_core_pir_p8; k->intc_create = pnv_chip_power8_intc_create; + k->intc_reset = pnv_chip_power8_intc_reset; k->isa_create = pnv_chip_power8_isa_create; k->dt_populate = pnv_chip_power8_dt_populate; k->pic_print_info = pnv_chip_power8_pic_print_info; @@ -1003,6 +1018,7 @@ static void pnv_chip_power8_class_init(ObjectClass *klass, void *data) k->cores_mask = POWER8_CORE_MASK; k->core_pir = pnv_chip_core_pir_p8; k->intc_create = pnv_chip_power8_intc_create; + k->intc_reset = pnv_chip_power8_intc_reset; k->isa_create = pnv_chip_power8_isa_create; k->dt_populate = pnv_chip_power8_dt_populate; k->pic_print_info = pnv_chip_power8_pic_print_info; @@ -1022,6 +1038,7 @@ static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data) k->cores_mask = POWER8_CORE_MASK; k->core_pir = pnv_chip_core_pir_p8; k->intc_create = pnv_chip_power8_intc_create; + k->intc_reset = pnv_chip_power8_intc_reset; k->isa_create = pnv_chip_power8nvl_isa_create; k->dt_populate = pnv_chip_power8_dt_populate; k->pic_print_info = pnv_chip_power8_pic_print_info; @@ -1191,6 +1208,7 @@ static void pnv_chip_power9_class_init(ObjectClass *klass, void *data) k->cores_mask = POWER9_CORE_MASK; k->core_pir = pnv_chip_core_pir_p9; k->intc_create = pnv_chip_power9_intc_create; + k->intc_reset = pnv_chip_power9_intc_reset; k->isa_create = pnv_chip_power9_isa_create; k->dt_populate = pnv_chip_power9_dt_populate; k->pic_print_info = pnv_chip_power9_pic_print_info; diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c index b1a7489..e81cd3a 100644 --- a/hw/ppc/pnv_core.c +++ b/hw/ppc/pnv_core.c @@ -40,11 +40,11 @@ static const char *pnv_core_cpu_typename(PnvCore *pc) return cpu_type; } -static void pnv_cpu_reset(void *opaque) +static void pnv_core_cpu_reset(PowerPCCPU *cpu, PnvChip *chip) { - PowerPCCPU *cpu = opaque; CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; + PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip); cpu_reset(cs); @@ -55,6 +55,8 @@ static void pnv_cpu_reset(void *opaque) env->gpr[3] = PNV_FDT_ADDR; env->nip = 0x10; env->msr |= MSR_HVB; /* Hypervisor mode */ + + pcc->intc_reset(chip, cpu); } /* @@ -160,7 +162,7 @@ static const MemoryRegionOps pnv_core_power9_xscom_ops = { .endianness = DEVICE_BIG_ENDIAN, }; -static void pnv_realize_vcpu(PowerPCCPU *cpu, PnvChip *chip, Error **errp) +static void pnv_core_cpu_realize(PowerPCCPU *cpu, PnvChip *chip, Error **errp) { CPUPPCState *env = &cpu->env; int core_pir; @@ -192,8 +194,17 @@ static void pnv_realize_vcpu(PowerPCCPU *cpu, PnvChip *chip, Error **errp) /* Set time-base frequency to 512 MHz */ cpu_ppc_tb_init(env, PNV_TIMEBASE_FREQ); +} + +static void pnv_core_reset(void *dev) +{ + CPUCore *cc = CPU_CORE(dev); + PnvCore *pc = PNV_CORE(dev); + int i; - qemu_register_reset(pnv_cpu_reset, cpu); + for (i = 0; i < cc->nr_threads; i++) { + pnv_core_cpu_reset(pc->threads[i], pc->chip); + } } static void pnv_core_realize(DeviceState *dev, Error **errp) @@ -214,6 +225,7 @@ static void pnv_core_realize(DeviceState *dev, Error **errp) "required link 'chip' not found: "); return; } + pc->chip = PNV_CHIP(chip); pc->threads = g_new(PowerPCCPU *, cc->nr_threads); for (i = 0; i < cc->nr_threads; i++) { @@ -235,7 +247,7 @@ static void pnv_core_realize(DeviceState *dev, Error **errp) } for (j = 0; j < cc->nr_threads; j++) { - pnv_realize_vcpu(pc->threads[j], PNV_CHIP(chip), &local_err); + pnv_core_cpu_realize(pc->threads[j], pc->chip, &local_err); if (local_err) { goto err; } @@ -244,6 +256,8 @@ static void pnv_core_realize(DeviceState *dev, Error **errp) snprintf(name, sizeof(name), "xscom-core.%d", cc->core_id); pnv_xscom_region_init(&pc->xscom_regs, OBJECT(dev), pcc->xscom_ops, pc, name, PNV_XSCOM_EX_SIZE); + + qemu_register_reset(pnv_core_reset, pc); return; err: @@ -255,11 +269,10 @@ err: error_propagate(errp, local_err); } -static void pnv_unrealize_vcpu(PowerPCCPU *cpu) +static void pnv_core_cpu_unrealize(PowerPCCPU *cpu) { PnvCPUState *pnv_cpu = pnv_cpu_state(cpu); - qemu_unregister_reset(pnv_cpu_reset, cpu); object_unparent(OBJECT(pnv_cpu_state(cpu)->intc)); cpu_remove_sync(CPU(cpu)); cpu->machine_data = NULL; @@ -273,8 +286,10 @@ static void pnv_core_unrealize(DeviceState *dev, Error **errp) CPUCore *cc = CPU_CORE(dev); int i; + qemu_unregister_reset(pnv_core_reset, pc); + for (i = 0; i < cc->nr_threads; i++) { - pnv_unrealize_vcpu(pc->threads[i]); + pnv_core_cpu_unrealize(pc->threads[i]); } g_free(pc->threads); } diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c index a997f16..68d0dfa 100644 --- a/hw/ppc/pnv_psi.c +++ b/hw/ppc/pnv_psi.c @@ -660,10 +660,19 @@ static void pnv_psi_notify(XiveNotifier *xf, uint32_t srcno) uint32_t offset = (psi->regs[PSIHB_REG(PSIHB9_IVT_OFFSET)] >> PSIHB9_IVT_OFF_SHIFT); - uint64_t lisn = cpu_to_be64(offset + srcno); + uint64_t data = XIVE_TRIGGER_PQ | offset | srcno; + MemTxResult result; - if (valid) { - cpu_physical_memory_write(notify_addr, &lisn, sizeof(lisn)); + if (!valid) { + return; + } + + address_space_stq_be(&address_space_memory, notify_addr, data, + MEMTXATTRS_UNSPECIFIED, &result); + if (result != MEMTX_OK) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: trigger failed @%" + HWADDR_PRIx "\n", __func__, notif_port); + return; } } diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 4eb97d3..94f9d27 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1247,8 +1247,7 @@ static void *spapr_build_fdt(SpaprMachineState *spapr) _FDT(fdt_setprop_cell(fdt, 0, "#size-cells", 2)); /* /interrupt controller */ - spapr->irq->dt_populate(spapr, spapr_max_server_number(spapr), fdt, - PHANDLE_INTC); + spapr_irq_dt(spapr, spapr_max_server_number(spapr), fdt, PHANDLE_INTC); ret = spapr_populate_memory(spapr, fdt); if (ret < 0) { @@ -1268,7 +1267,7 @@ static void *spapr_build_fdt(SpaprMachineState *spapr) } QLIST_FOREACH(phb, &spapr->phbs, list) { - ret = spapr_dt_phb(phb, PHANDLE_INTC, fdt, spapr->irq->nr_msis, NULL); + ret = spapr_dt_phb(spapr, phb, PHANDLE_INTC, fdt, NULL); if (ret < 0) { error_report("couldn't setup PCI devices in fdt"); exit(1); @@ -2496,6 +2495,7 @@ static CPUArchId *spapr_find_cpu_slot(MachineState *ms, uint32_t id, int *idx) static void spapr_set_vsmt_mode(SpaprMachineState *spapr, Error **errp) { MachineState *ms = MACHINE(spapr); + SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); Error *local_err = NULL; bool vsmt_user = !!spapr->vsmt; int kvm_smt = kvmppc_smt_threads(); @@ -2522,7 +2522,7 @@ static void spapr_set_vsmt_mode(SpaprMachineState *spapr, Error **errp) goto out; } /* In this case, spapr->vsmt has been set by the command line */ - } else { + } else if (!smc->smp_threads_vsmt) { /* * Default VSMT value is tricky, because we need it to be as * consistent as possible (for migration), but this requires @@ -2531,6 +2531,8 @@ static void spapr_set_vsmt_mode(SpaprMachineState *spapr, Error **errp) * overwhelmingly common case in production systems. */ spapr->vsmt = MAX(8, smp_threads); + } else { + spapr->vsmt = smp_threads; } /* KVM: If necessary, set the SMT mode: */ @@ -3739,9 +3741,10 @@ void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev, spapr_vcpu_id(spapr, cc->core_id)); g_assert(drc); - spapr_drc_detach(drc); - - spapr_hotplug_req_remove_by_index(drc); + if (!spapr_drc_unplug_requested(drc)) { + spapr_drc_detach(drc); + spapr_hotplug_req_remove_by_index(drc); + } } int spapr_core_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr, @@ -3903,8 +3906,7 @@ int spapr_phb_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr, return -1; } - if (spapr_dt_phb(sphb, intc_phandle, fdt, spapr->irq->nr_msis, - fdt_start_offset)) { + if (spapr_dt_phb(spapr, sphb, intc_phandle, fdt, fdt_start_offset)) { error_setg(errp, "unable to create FDT node for PHB %d", sphb->index); return -1; } @@ -4263,7 +4265,7 @@ static void spapr_pic_print_info(InterruptStatsProvider *obj, { SpaprMachineState *spapr = SPAPR_MACHINE(obj); - spapr->irq->print_info(spapr, mon); + spapr_irq_print_info(spapr, mon); monitor_printf(mon, "irqchip: %s\n", kvm_irqchip_in_kernel() ? "in-kernel" : "emulated"); } @@ -4438,6 +4440,8 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) smc->irq = &spapr_irq_dual; smc->dr_phb_enabled = true; smc->linux_pci_probe = true; + smc->smp_threads_vsmt = true; + smc->nr_xirqs = SPAPR_NR_XIRQS; } static const TypeInfo spapr_machine_info = { @@ -4505,6 +4509,7 @@ static void spapr_machine_4_1_class_options(MachineClass *mc) spapr_machine_4_2_class_options(mc); smc->linux_pci_probe = false; + smc->smp_threads_vsmt = false; compat_props_add(mc->compat_props, hw_compat_4_1, hw_compat_4_1_len); compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat)); } @@ -4573,6 +4578,7 @@ static void spapr_machine_3_0_class_options(MachineClass *mc) compat_props_add(mc->compat_props, hw_compat_3_0, hw_compat_3_0_len); smc->legacy_irq_allocation = true; + smc->nr_xirqs = 0x400; smc->irq = &spapr_irq_xics_legacy; } diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index 1d93de8..ef7b27a 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -25,14 +25,14 @@ #include "sysemu/hw_accel.h" #include "qemu/error-report.h" -static void spapr_cpu_reset(void *opaque) +static void spapr_reset_vcpu(PowerPCCPU *cpu) { - PowerPCCPU *cpu = opaque; CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu); target_ulong lpcr; + SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); cpu_reset(cs); @@ -77,9 +77,11 @@ static void spapr_cpu_reset(void *opaque) spapr_cpu->dtl_addr = 0; spapr_cpu->dtl_size = 0; - spapr_caps_cpu_apply(SPAPR_MACHINE(qdev_get_machine()), cpu); + spapr_caps_cpu_apply(spapr, cpu); kvm_check_mmu(cpu, &error_fatal); + + spapr_irq_cpu_intc_reset(spapr, cpu); } void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip, target_ulong r3) @@ -193,7 +195,6 @@ static void spapr_unrealize_vcpu(PowerPCCPU *cpu, SpaprCpuCore *sc) if (!sc->pre_3_0_migration) { vmstate_unregister(NULL, &vmstate_spapr_cpu_state, cpu->machine_data); } - qemu_unregister_reset(spapr_cpu_reset, cpu); if (spapr_cpu_state(cpu)->icp) { object_unparent(OBJECT(spapr_cpu_state(cpu)->icp)); } @@ -204,12 +205,36 @@ static void spapr_unrealize_vcpu(PowerPCCPU *cpu, SpaprCpuCore *sc) object_unparent(OBJECT(cpu)); } +/* + * Called when CPUs are hot-plugged. + */ +static void spapr_cpu_core_reset(DeviceState *dev) +{ + CPUCore *cc = CPU_CORE(dev); + SpaprCpuCore *sc = SPAPR_CPU_CORE(dev); + int i; + + for (i = 0; i < cc->nr_threads; i++) { + spapr_reset_vcpu(sc->threads[i]); + } +} + +/* + * Called by the machine reset. + */ +static void spapr_cpu_core_reset_handler(void *opaque) +{ + spapr_cpu_core_reset(opaque); +} + static void spapr_cpu_core_unrealize(DeviceState *dev, Error **errp) { SpaprCpuCore *sc = SPAPR_CPU_CORE(OBJECT(dev)); CPUCore *cc = CPU_CORE(dev); int i; + qemu_unregister_reset(spapr_cpu_core_reset_handler, sc); + for (i = 0; i < cc->nr_threads; i++) { spapr_unrealize_vcpu(sc->threads[i], sc); } @@ -234,12 +259,8 @@ static void spapr_realize_vcpu(PowerPCCPU *cpu, SpaprMachineState *spapr, cpu_ppc_set_vhyp(cpu, PPC_VIRTUAL_HYPERVISOR(spapr)); kvmppc_set_papr(cpu); - qemu_register_reset(spapr_cpu_reset, cpu); - spapr_cpu_reset(cpu); - - spapr->irq->cpu_intc_create(spapr, cpu, &local_err); - if (local_err) { - goto error_unregister; + if (spapr_irq_cpu_intc_create(spapr, cpu, &local_err) < 0) { + goto error_intc_create; } if (!sc->pre_3_0_migration) { @@ -249,8 +270,7 @@ static void spapr_realize_vcpu(PowerPCCPU *cpu, SpaprMachineState *spapr, return; -error_unregister: - qemu_unregister_reset(spapr_cpu_reset, cpu); +error_intc_create: cpu_remove_sync(CPU(cpu)); error: error_propagate(errp, local_err); @@ -337,6 +357,8 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp) goto err_unrealize; } } + + qemu_register_reset(spapr_cpu_core_reset_handler, sc); return; err_unrealize: @@ -365,6 +387,7 @@ static void spapr_cpu_core_class_init(ObjectClass *oc, void *data) dc->realize = spapr_cpu_core_realize; dc->unrealize = spapr_cpu_core_unrealize; + dc->reset = spapr_cpu_core_reset; dc->props = spapr_cpu_core_properties; scc->cpu_type = data; } diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index 457eabe..b941608 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -23,9 +23,20 @@ #include "trace.h" -void spapr_irq_msi_init(SpaprMachineState *spapr, uint32_t nr_msis) +static const TypeInfo spapr_intc_info = { + .name = TYPE_SPAPR_INTC, + .parent = TYPE_INTERFACE, + .class_size = sizeof(SpaprInterruptControllerClass), +}; + +static void spapr_irq_msi_init(SpaprMachineState *spapr) { - spapr->irq_map_nr = nr_msis; + if (SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) { + /* Legacy mode doesn't use this allocator */ + return; + } + + spapr->irq_map_nr = spapr_irq_nr_msis(spapr); spapr->irq_map = bitmap_new(spapr->irq_map_nr); } @@ -59,262 +70,53 @@ void spapr_irq_msi_free(SpaprMachineState *spapr, int irq, uint32_t num) bitmap_clear(spapr->irq_map, irq - SPAPR_IRQ_MSI, num); } -static void spapr_irq_init_kvm(SpaprMachineState *spapr, - SpaprIrq *irq, Error **errp) +int spapr_irq_init_kvm(int (*fn)(SpaprInterruptController *, Error **), + SpaprInterruptController *intc, + Error **errp) { - MachineState *machine = MACHINE(spapr); + MachineState *machine = MACHINE(qdev_get_machine()); Error *local_err = NULL; if (kvm_enabled() && machine_kernel_irqchip_allowed(machine)) { - irq->init_kvm(spapr, &local_err); - if (local_err && machine_kernel_irqchip_required(machine)) { - error_prepend(&local_err, - "kernel_irqchip requested but unavailable: "); - error_propagate(errp, local_err); - return; - } + if (fn(intc, &local_err) < 0) { + if (machine_kernel_irqchip_required(machine)) { + error_prepend(&local_err, + "kernel_irqchip requested but unavailable: "); + error_propagate(errp, local_err); + return -1; + } - if (!local_err) { - return; + /* + * We failed to initialize the KVM device, fallback to + * emulated mode + */ + error_prepend(&local_err, + "kernel_irqchip allowed but unavailable: "); + error_append_hint(&local_err, + "Falling back to kernel-irqchip=off\n"); + warn_report_err(local_err); } - - /* - * We failed to initialize the KVM device, fallback to - * emulated mode - */ - error_prepend(&local_err, "kernel_irqchip allowed but unavailable: "); - error_append_hint(&local_err, "Falling back to kernel-irqchip=off\n"); - warn_report_err(local_err); } + + return 0; } /* * XICS IRQ backend. */ -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_irq_free(ics, irq - ics->offset)) { - error_setg(errp, "IRQ %d is not free", irq); - return -1; - } - - ics_set_irq_type(ics, irq - ics->offset, lsi); - return 0; -} - -static void spapr_irq_free_xics(SpaprMachineState *spapr, int irq) -{ - ICSState *ics = spapr->ics; - uint32_t srcno = irq - ics->offset; - - assert(ics_valid_irq(ics, irq)); - - memset(&ics->irqs[srcno], 0, sizeof(ICSIRQState)); -} - -static void spapr_irq_print_info_xics(SpaprMachineState *spapr, Monitor *mon) -{ - CPUState *cs; - - CPU_FOREACH(cs) { - PowerPCCPU *cpu = POWERPC_CPU(cs); - - icp_pic_print_info(spapr_cpu_state(cpu)->icp, mon); - } - - ics_pic_print_info(spapr->ics, mon); -} - -static void spapr_irq_cpu_intc_create_xics(SpaprMachineState *spapr, - PowerPCCPU *cpu, Error **errp) -{ - Error *local_err = NULL; - Object *obj; - SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu); - - obj = icp_create(OBJECT(cpu), TYPE_ICP, XICS_FABRIC(spapr), - &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - spapr_cpu->icp = ICP(obj); -} - -static int spapr_irq_post_load_xics(SpaprMachineState *spapr, 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 void spapr_irq_set_irq_xics(void *opaque, int irq, int val) -{ - SpaprMachineState *spapr = opaque; - uint32_t srcno = irq - spapr->ics->offset; - - ics_set_irq(spapr->ics, srcno, val); -} - -static void spapr_irq_reset_xics(SpaprMachineState *spapr, Error **errp) -{ - Error *local_err = NULL; - - spapr_irq_init_kvm(spapr, &spapr_irq_xics, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } -} - -static void spapr_irq_init_kvm_xics(SpaprMachineState *spapr, Error **errp) -{ - if (kvm_enabled()) { - xics_kvm_connect(spapr, errp); - } -} - SpaprIrq spapr_irq_xics = { - .nr_xirqs = SPAPR_NR_XIRQS, - .nr_msis = SPAPR_NR_MSIS, .xics = true, .xive = false, - - .claim = spapr_irq_claim_xics, - .free = spapr_irq_free_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, - .init_kvm = spapr_irq_init_kvm_xics, }; /* * XIVE IRQ backend. */ -static int spapr_irq_claim_xive(SpaprMachineState *spapr, int irq, bool lsi, - Error **errp) -{ - return spapr_xive_irq_claim(spapr->xive, irq, lsi, errp); -} - -static void spapr_irq_free_xive(SpaprMachineState *spapr, int irq) -{ - spapr_xive_irq_free(spapr->xive, irq); -} - -static void spapr_irq_print_info_xive(SpaprMachineState *spapr, - Monitor *mon) -{ - 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(spapr->xive, mon); -} - -static void spapr_irq_cpu_intc_create_xive(SpaprMachineState *spapr, - PowerPCCPU *cpu, Error **errp) -{ - Error *local_err = NULL; - Object *obj; - SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu); - - obj = xive_tctx_create(OBJECT(cpu), XIVE_ROUTER(spapr->xive), &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - spapr_cpu->tctx = XIVE_TCTX(obj); - - /* - * (TCG) Early setting the OS CAM line for hotplugged CPUs as they - * don't beneficiate from the reset of the XIVE IRQ backend - */ - spapr_xive_set_tctx_os_cam(spapr_cpu->tctx); -} - -static int spapr_irq_post_load_xive(SpaprMachineState *spapr, int version_id) -{ - return spapr_xive_post_load(spapr->xive, version_id); -} - -static void spapr_irq_reset_xive(SpaprMachineState *spapr, Error **errp) -{ - CPUState *cs; - Error *local_err = NULL; - - CPU_FOREACH(cs) { - PowerPCCPU *cpu = POWERPC_CPU(cs); - - /* (TCG) Set the OS CAM line of the thread interrupt context. */ - spapr_xive_set_tctx_os_cam(spapr_cpu_state(cpu)->tctx); - } - - spapr_irq_init_kvm(spapr, &spapr_irq_xive, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - /* Activate the XIVE MMIOs */ - spapr_xive_mmio_set_enabled(spapr->xive, true); -} - -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, irq, val); - } else { - xive_source_set_irq(&spapr->xive->source, irq, val); - } -} - -static void spapr_irq_init_kvm_xive(SpaprMachineState *spapr, Error **errp) -{ - if (kvm_enabled()) { - kvmppc_xive_connect(spapr->xive, errp); - } -} - SpaprIrq spapr_irq_xive = { - .nr_xirqs = SPAPR_NR_XIRQS, - .nr_msis = SPAPR_NR_MSIS, .xics = false, .xive = true, - - .claim = spapr_irq_claim_xive, - .free = spapr_irq_free_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, - .init_kvm = spapr_irq_init_kvm_xive, }; /* @@ -327,138 +129,11 @@ SpaprIrq spapr_irq_xive = { */ /* - * Returns the sPAPR IRQ backend negotiated by CAS. XICS is the - * default. - */ -static SpaprIrq *spapr_irq_current(SpaprMachineState *spapr) -{ - return spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT) ? - &spapr_irq_xive : &spapr_irq_xics; -} - -static int spapr_irq_claim_dual(SpaprMachineState *spapr, int irq, bool lsi, - Error **errp) -{ - Error *local_err = NULL; - int ret; - - ret = spapr_irq_xics.claim(spapr, irq, lsi, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return ret; - } - - ret = spapr_irq_xive.claim(spapr, irq, lsi, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return ret; - } - - return ret; -} - -static void spapr_irq_free_dual(SpaprMachineState *spapr, int irq) -{ - spapr_irq_xics.free(spapr, irq); - spapr_irq_xive.free(spapr, irq); -} - -static void spapr_irq_print_info_dual(SpaprMachineState *spapr, Monitor *mon) -{ - spapr_irq_current(spapr)->print_info(spapr, mon); -} - -static void spapr_irq_dt_populate_dual(SpaprMachineState *spapr, - uint32_t nr_servers, void *fdt, - uint32_t phandle) -{ - spapr_irq_current(spapr)->dt_populate(spapr, nr_servers, fdt, phandle); -} - -static void spapr_irq_cpu_intc_create_dual(SpaprMachineState *spapr, - PowerPCCPU *cpu, Error **errp) -{ - Error *local_err = NULL; - - spapr_irq_xive.cpu_intc_create(spapr, cpu, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - spapr_irq_xics.cpu_intc_create(spapr, cpu, errp); -} - -static int spapr_irq_post_load_dual(SpaprMachineState *spapr, int version_id) -{ - /* - * Force a reset of the XIVE backend after migration. The machine - * defaults to XICS at startup. - */ - if (spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) { - if (kvm_irqchip_in_kernel()) { - xics_kvm_disconnect(spapr, &error_fatal); - } - spapr_irq_xive.reset(spapr, &error_fatal); - } - - return spapr_irq_current(spapr)->post_load(spapr, version_id); -} - -static void spapr_irq_reset_dual(SpaprMachineState *spapr, Error **errp) -{ - Error *local_err = NULL; - - /* - * Deactivate the XIVE MMIOs. The XIVE backend will reenable them - * if selected. - */ - spapr_xive_mmio_set_enabled(spapr->xive, false); - - /* Destroy all KVM devices */ - if (kvm_irqchip_in_kernel()) { - xics_kvm_disconnect(spapr, &local_err); - if (local_err) { - error_propagate(errp, local_err); - error_prepend(errp, "KVM XICS disconnect failed: "); - return; - } - kvmppc_xive_disconnect(spapr->xive, &local_err); - if (local_err) { - error_propagate(errp, local_err); - error_prepend(errp, "KVM XIVE disconnect failed: "); - return; - } - } - - spapr_irq_current(spapr)->reset(spapr, errp); -} - -static void spapr_irq_set_irq_dual(void *opaque, int irq, int val) -{ - SpaprMachineState *spapr = opaque; - - spapr_irq_current(spapr)->set_irq(spapr, irq, val); -} - -/* * Define values in sync with the XIVE and XICS backend */ SpaprIrq spapr_irq_dual = { - .nr_xirqs = SPAPR_NR_XIRQS, - .nr_msis = SPAPR_NR_MSIS, .xics = true, .xive = true, - - .claim = spapr_irq_claim_dual, - .free = spapr_irq_free_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, - .init_kvm = NULL, /* should not be used */ }; @@ -521,9 +196,85 @@ static int spapr_irq_check(SpaprMachineState *spapr, Error **errp) /* * sPAPR IRQ frontend routines for devices */ +#define ALL_INTCS(spapr_) \ + { SPAPR_INTC((spapr_)->ics), SPAPR_INTC((spapr_)->xive), } + +int spapr_irq_cpu_intc_create(SpaprMachineState *spapr, + PowerPCCPU *cpu, Error **errp) +{ + SpaprInterruptController *intcs[] = ALL_INTCS(spapr); + int i; + int rc; + + for (i = 0; i < ARRAY_SIZE(intcs); i++) { + SpaprInterruptController *intc = intcs[i]; + if (intc) { + SpaprInterruptControllerClass *sicc = SPAPR_INTC_GET_CLASS(intc); + rc = sicc->cpu_intc_create(intc, cpu, errp); + if (rc < 0) { + return rc; + } + } + } + + return 0; +} + +void spapr_irq_cpu_intc_reset(SpaprMachineState *spapr, PowerPCCPU *cpu) +{ + SpaprInterruptController *intcs[] = ALL_INTCS(spapr); + int i; + + for (i = 0; i < ARRAY_SIZE(intcs); i++) { + SpaprInterruptController *intc = intcs[i]; + if (intc) { + SpaprInterruptControllerClass *sicc = SPAPR_INTC_GET_CLASS(intc); + sicc->cpu_intc_reset(intc, cpu); + } + } +} + +static void spapr_set_irq(void *opaque, int irq, int level) +{ + SpaprMachineState *spapr = SPAPR_MACHINE(opaque); + SpaprInterruptControllerClass *sicc + = SPAPR_INTC_GET_CLASS(spapr->active_intc); + + sicc->set_irq(spapr->active_intc, irq, level); +} + +void spapr_irq_print_info(SpaprMachineState *spapr, Monitor *mon) +{ + SpaprInterruptControllerClass *sicc + = SPAPR_INTC_GET_CLASS(spapr->active_intc); + + sicc->print_info(spapr->active_intc, mon); +} + +void spapr_irq_dt(SpaprMachineState *spapr, uint32_t nr_servers, + void *fdt, uint32_t phandle) +{ + SpaprInterruptControllerClass *sicc + = SPAPR_INTC_GET_CLASS(spapr->active_intc); + + sicc->dt(spapr->active_intc, nr_servers, fdt, phandle); +} + +uint32_t spapr_irq_nr_msis(SpaprMachineState *spapr) +{ + SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); + + if (smc->legacy_irq_allocation) { + return smc->nr_xirqs; + } else { + return SPAPR_XIRQ_BASE + smc->nr_xirqs - SPAPR_IRQ_MSI; + } +} + void spapr_irq_init(SpaprMachineState *spapr, Error **errp) { MachineState *machine = MACHINE(spapr); + SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); if (machine_kernel_irqchip_split(machine)) { error_setg(errp, "kernel_irqchip split mode not supported on pseries"); @@ -541,9 +292,7 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp) } /* Initialize the MSI IRQ allocator. */ - if (!SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) { - spapr_irq_msi_init(spapr, spapr->irq->nr_msis); - } + spapr_irq_msi_init(spapr); if (spapr->irq->xics) { Error *local_err = NULL; @@ -563,8 +312,7 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp) return; } - object_property_set_int(obj, spapr->irq->nr_xirqs, "nr-irqs", - &local_err); + object_property_set_int(obj, smc->nr_xirqs, "nr-irqs", &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -585,8 +333,7 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp) int i; dev = qdev_create(NULL, TYPE_SPAPR_XIVE); - qdev_prop_set_uint32(dev, "nr-irqs", - spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE); + qdev_prop_set_uint32(dev, "nr-irqs", smc->nr_xirqs + SPAPR_XIRQ_BASE); /* * 8 XIVE END structures per CPU. One for each available * priority @@ -598,8 +345,11 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp) /* 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) { + SpaprInterruptControllerClass *sicc + = SPAPR_INTC_GET_CLASS(spapr->xive); + + if (sicc->claim_irq(SPAPR_INTC(spapr->xive), SPAPR_IRQ_IPI + i, + false, errp) < 0) { return; } } @@ -607,32 +357,60 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp) spapr_xive_hcall_init(spapr); } - spapr->qirqs = qemu_allocate_irqs(spapr->irq->set_irq, spapr, - spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE); + spapr->qirqs = qemu_allocate_irqs(spapr_set_irq, spapr, + smc->nr_xirqs + SPAPR_XIRQ_BASE); } int spapr_irq_claim(SpaprMachineState *spapr, int irq, bool lsi, Error **errp) { + SpaprInterruptController *intcs[] = ALL_INTCS(spapr); + int i; + SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); + int rc; + assert(irq >= SPAPR_XIRQ_BASE); - assert(irq < (spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE)); + assert(irq < (smc->nr_xirqs + SPAPR_XIRQ_BASE)); + + for (i = 0; i < ARRAY_SIZE(intcs); i++) { + SpaprInterruptController *intc = intcs[i]; + if (intc) { + SpaprInterruptControllerClass *sicc = SPAPR_INTC_GET_CLASS(intc); + rc = sicc->claim_irq(intc, irq, lsi, errp); + if (rc < 0) { + return rc; + } + } + } - return spapr->irq->claim(spapr, irq, lsi, errp); + return 0; } void spapr_irq_free(SpaprMachineState *spapr, int irq, int num) { - int i; + SpaprInterruptController *intcs[] = ALL_INTCS(spapr); + int i, j; + SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); assert(irq >= SPAPR_XIRQ_BASE); - assert((irq + num) <= (spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE)); + assert((irq + num) <= (smc->nr_xirqs + SPAPR_XIRQ_BASE)); for (i = irq; i < (irq + num); i++) { - spapr->irq->free(spapr, i); + for (j = 0; j < ARRAY_SIZE(intcs); j++) { + SpaprInterruptController *intc = intcs[j]; + + if (intc) { + SpaprInterruptControllerClass *sicc + = SPAPR_INTC_GET_CLASS(intc); + sicc->free_irq(intc, i); + } + } } } qemu_irq spapr_qirq(SpaprMachineState *spapr, int irq) { + SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); + /* * This interface is basically for VIO and PHB devices to find the * right qemu_irq to manipulate, so we only allow access to the @@ -641,7 +419,7 @@ qemu_irq spapr_qirq(SpaprMachineState *spapr, int irq) * 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)); + assert(irq < (smc->nr_xirqs + SPAPR_XIRQ_BASE)); if (spapr->ics) { assert(ics_valid_irq(spapr->ics, irq)); @@ -656,16 +434,18 @@ qemu_irq spapr_qirq(SpaprMachineState *spapr, int irq) int spapr_irq_post_load(SpaprMachineState *spapr, int version_id) { - return spapr->irq->post_load(spapr, version_id); + SpaprInterruptControllerClass *sicc; + + spapr_irq_update_active_intc(spapr); + sicc = SPAPR_INTC_GET_CLASS(spapr->active_intc); + return sicc->post_load(spapr->active_intc, version_id); } void spapr_irq_reset(SpaprMachineState *spapr, Error **errp) { assert(!spapr->irq_map || bitmap_empty(spapr->irq_map, spapr->irq_map_nr)); - if (spapr->irq->reset) { - spapr->irq->reset(spapr, errp); - } + spapr_irq_update_active_intc(spapr); } int spapr_irq_get_phandle(SpaprMachineState *spapr, void *fdt, Error **errp) @@ -689,6 +469,54 @@ int spapr_irq_get_phandle(SpaprMachineState *spapr, void *fdt, Error **errp) return phandle; } +static void set_active_intc(SpaprMachineState *spapr, + SpaprInterruptController *new_intc) +{ + SpaprInterruptControllerClass *sicc; + + assert(new_intc); + + if (new_intc == spapr->active_intc) { + /* Nothing to do */ + return; + } + + if (spapr->active_intc) { + sicc = SPAPR_INTC_GET_CLASS(spapr->active_intc); + if (sicc->deactivate) { + sicc->deactivate(spapr->active_intc); + } + } + + sicc = SPAPR_INTC_GET_CLASS(new_intc); + if (sicc->activate) { + sicc->activate(new_intc, &error_fatal); + } + + spapr->active_intc = new_intc; +} + +void spapr_irq_update_active_intc(SpaprMachineState *spapr) +{ + SpaprInterruptController *new_intc; + + if (!spapr->ics) { + /* + * XXX before we run CAS, ov5_cas is initialized empty, which + * indicates XICS, even if we have ic-mode=xive. TODO: clean + * up the CAS path so that we have a clearer way of handling + * this. + */ + new_intc = SPAPR_INTC(spapr->xive); + } else if (spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) { + new_intc = SPAPR_INTC(spapr->xive); + } else { + new_intc = SPAPR_INTC(spapr->ics); + } + + set_active_intc(spapr, new_intc); +} + /* * XICS legacy routines - to deprecate one day */ @@ -744,21 +572,14 @@ int spapr_irq_find(SpaprMachineState *spapr, int num, bool align, Error **errp) return first + ics->offset; } -#define SPAPR_IRQ_XICS_LEGACY_NR_XIRQS 0x400 - SpaprIrq spapr_irq_xics_legacy = { - .nr_xirqs = SPAPR_IRQ_XICS_LEGACY_NR_XIRQS, - .nr_msis = SPAPR_IRQ_XICS_LEGACY_NR_XIRQS, .xics = true, .xive = false, - - .claim = spapr_irq_claim_xics, - .free = spapr_irq_free_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, - .init_kvm = spapr_irq_init_kvm_xics, }; + +static void spapr_irq_register_types(void) +{ + type_register_static(&spapr_intc_info); +} + +type_init(spapr_irq_register_types) diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 01ff41d..cc0e782 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -2277,8 +2277,8 @@ static void spapr_phb_pci_enumerate(SpaprPhbState *phb) } -int spapr_dt_phb(SpaprPhbState *phb, uint32_t intc_phandle, void *fdt, - uint32_t nr_msis, int *node_offset) +int spapr_dt_phb(SpaprMachineState *spapr, SpaprPhbState *phb, + uint32_t intc_phandle, void *fdt, int *node_offset) { int bus_off, i, j, ret; uint32_t bus_range[] = { cpu_to_be32(0), cpu_to_be32(0xff) }; @@ -2343,7 +2343,8 @@ int spapr_dt_phb(SpaprPhbState *phb, uint32_t intc_phandle, void *fdt, _FDT(fdt_setprop(fdt, bus_off, "ranges", &ranges, sizeof_ranges)); _FDT(fdt_setprop(fdt, bus_off, "reg", &bus_reg, sizeof(bus_reg))); _FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pci-config-space-type", 0x1)); - _FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pe-total-#msi", nr_msis)); + _FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pe-total-#msi", + spapr_irq_nr_msis(spapr))); /* Dynamic DMA window */ if (phb->ddw_enabled) { |