aboutsummaryrefslogtreecommitdiff
path: root/hw/ppc
diff options
context:
space:
mode:
Diffstat (limited to 'hw/ppc')
-rw-r--r--hw/ppc/pnv.c18
-rw-r--r--hw/ppc/pnv_core.c31
-rw-r--r--hw/ppc/pnv_psi.c15
-rw-r--r--hw/ppc/spapr.c26
-rw-r--r--hw/ppc/spapr_cpu_core.c47
-rw-r--r--hw/ppc/spapr_irq.c611
-rw-r--r--hw/ppc/spapr_pci.c7
7 files changed, 324 insertions, 431 deletions
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 7cf64b6d25..4a51fb65a8 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 b1a7489e7a..e81cd3a3e0 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 a997f16bb4..68d0dfacfe 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 4eb97d3a9b..94f9d27096 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 1d93de8161..ef7b27a66d 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 457eabe24c..b941608b69 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 01ff41d4c4..cc0e7829b6 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) {