From 4b236b621bf090509c4a0be372edfd31d13b289a Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 27 Jun 2016 08:55:19 +0200 Subject: ppc: Initial HDEC support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current behaviour isn't completely right, as for the DEC, we don't properly re-arm when wrapping around, but I will fix this in a separate patch. Signed-off-by: Benjamin Herrenschmidt [clg: fixed checkpatch.pl errors ] Signed-off-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/ppc/ppc.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'hw') diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c index 1bcf740..e425252 100644 --- a/hw/ppc/ppc.c +++ b/hw/ppc/ppc.c @@ -699,9 +699,18 @@ static inline void cpu_ppc_decr_lower(PowerPCCPU *cpu) static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu) { + CPUPPCState *env = &cpu->env; + /* Raise it */ - LOG_TB("raise decrementer exception\n"); - ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1); + LOG_TB("raise hv decrementer exception\n"); + + /* The architecture specifies that we don't deliver HDEC + * interrupts in a PM state. Not only they don't cause a + * wakeup but they also get effectively discarded. + */ + if (!env->in_pm_state) { + ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1); + } } static inline void cpu_ppc_hdecr_lower(PowerPCCPU *cpu) @@ -928,9 +937,7 @@ clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq) } /* Create new timer */ tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_decr_cb, cpu); - if (0) { - /* XXX: find a suitable condition to enable the hypervisor decrementer - */ + if (env->has_hv_mode) { tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_hdecr_cb, cpu); } else { -- cgit v1.1 From 6cc09e261b267e5b06c03efdf0c8e7a0d9e59721 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 27 Jun 2016 13:25:03 +0200 Subject: hw/ppc/spapr: Add some missing hcall function set strings Add "hcall-sprg0" (for H_SET_SPRG0), "hcall-copy" (for H_PAGE_INIT) and "hcall-debug" (for H_LOGICAL_CI_LOAD/STORE) to the property "ibm,hypertas-functions" to indicate that we support these hypercalls. Signed-off-by: Thomas Huth Signed-off-by: David Gibson --- hw/ppc/spapr.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'hw') diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 0b6bb9c..d26b4c2 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -339,6 +339,9 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base, add_str(hypertas, "hcall-splpar"); add_str(hypertas, "hcall-bulk"); add_str(hypertas, "hcall-set-mode"); + add_str(hypertas, "hcall-sprg0"); + add_str(hypertas, "hcall-copy"); + add_str(hypertas, "hcall-debug"); add_str(qemu_hypertas, "hcall-memop1"); fdt = g_malloc0(FDT_MAX_SIZE); -- cgit v1.1 From dde35bc966ef8c1afb4f4e0f3c0e99fc0f27ca04 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 27 Jun 2016 18:28:15 +0200 Subject: spapr: fix write-past-end-of-array error in cpu core device init code This fixes a potential QEMU crash introduced by commit 3b542549661. Signed-off-by: Greg Kurz Signed-off-by: David Gibson --- hw/ppc/spapr_cpu_core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'hw') diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index 3a5da09..8b802a6 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -309,10 +309,9 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp) } err: - while (i >= 0) { + while (--i >= 0) { obj = sc->threads + i * size; object_unparent(obj); - i--; } g_free(sc->threads); error_propagate(errp, local_err); -- cgit v1.1 From ff461b8da9d3444bf1c33a9a94edcf88435c4268 Mon Sep 17 00:00:00 2001 From: Bharata B Rao Date: Tue, 28 Jun 2016 20:35:02 +0530 Subject: spapr: Restore support for older PowerPC CPU cores Introduction of core based CPU hotplug for PowerPC sPAPR didn't add support for 970 and POWER5+ based core types. Add support for the same. Signed-off-by: Bharata B Rao Signed-off-by: David Gibson --- hw/ppc/spapr_cpu_core.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index 8b802a6..cebeef5 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -325,7 +325,6 @@ static void spapr_cpu_core_class_init(ObjectClass *oc, void *data) /* * instance_init routines from different flavours of sPAPR CPU cores. - * TODO: Add support for 'host' core type. */ #define SPAPR_CPU_CORE_INITFN(_type, _fname) \ static void glue(glue(spapr_cpu_core_, _fname), _initfn(Object *obj)) \ @@ -338,6 +337,8 @@ static void glue(glue(spapr_cpu_core_, _fname), _initfn(Object *obj)) \ core->cpu_class = oc; \ } +SPAPR_CPU_CORE_INITFN(970_v2.2, 970); +SPAPR_CPU_CORE_INITFN(POWER5+_v2.1, POWER5plus); SPAPR_CPU_CORE_INITFN(POWER7_v2.3, POWER7); SPAPR_CPU_CORE_INITFN(POWER7+_v2.1, POWER7plus); SPAPR_CPU_CORE_INITFN(POWER8_v2.0, POWER8); @@ -349,6 +350,12 @@ typedef struct SPAPRCoreInfo { } SPAPRCoreInfo; static const SPAPRCoreInfo spapr_cores[] = { + /* 970 */ + { .name = "970", .initfn = spapr_cpu_core_970_initfn }, + + /* POWER5 */ + { .name = "POWER5+", .initfn = spapr_cpu_core_POWER5plus_initfn }, + /* POWER7 and aliases */ { .name = "POWER7_v2.3", .initfn = spapr_cpu_core_POWER7_initfn }, { .name = "POWER7", .initfn = spapr_cpu_core_POWER7_initfn }, -- cgit v1.1 From a36848ff7ca54d9181ec6c2202ce7563a2c5cfdc Mon Sep 17 00:00:00 2001 From: Aaron Larson Date: Tue, 28 Jun 2016 06:50:05 -0700 Subject: target-ppc: Eliminate redundant and incorrect function booke206_page_size_to_tlb Eliminate redundant and incorrect booke206_page_size_to_tlb function from ppce500_spin.c in preference to previously existing but newly exported definition from e500.c Defect analysis: The booke206_page_size_to_tlb function in e500.c was updated in commit 2bd9543 "ppc: booke206: use MAV=2.0 TSIZE definition, fix 4G pages" to reflect a change in the definition of MAS1_TSIZE_SHIFT from 8 (corresponding to a min TLB page size of 4kb) to a value of 7 (TLB page size 2k). The booke206_page_size_to_tlb() function defined in ppce500_spin.c was never updated to reflect the change in MAS1_TSIZE_SHIFT. In http://lists.nongnu.org/archive/html/qemu-ppc/2016-06/msg00533.html, Scott Wood suggested this "root cause" explanation: SW> The patch that changed MAS1_TSIZE_SHIFT from 8 to 7 was around the SW> same time as the patch that added this code, which is probably why SW> adjusting it got missed. Commit 2bd9543cd3 did update the SW> equivalent code in ppce500_mpc8544ds.c, which now resides in SW> hw/ppc/e500.c and has been changed to not assume a power-of-2 SW> size. The ppce500_spin version should be eliminated. Signed-off-by: Aaron Larson Signed-off-by: David Gibson --- hw/ppc/e500.c | 2 +- hw/ppc/e500.h | 2 ++ hw/ppc/ppce500_spin.c | 7 +------ 3 files changed, 4 insertions(+), 7 deletions(-) (limited to 'hw') diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index ee1c60b..0cd534d 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -601,7 +601,7 @@ static int ppce500_prep_device_tree(MachineState *machine, } /* Create -kernel TLB entries for BookE. */ -static inline hwaddr booke206_page_size_to_tlb(uint64_t size) +hwaddr booke206_page_size_to_tlb(uint64_t size) { return 63 - clz64(size >> 10); } diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h index ef224ea..70ba1d8 100644 --- a/hw/ppc/e500.h +++ b/hw/ppc/e500.h @@ -26,4 +26,6 @@ typedef struct PPCE500Params { void ppce500_init(MachineState *machine, PPCE500Params *params); +hwaddr booke206_page_size_to_tlb(uint64_t size); + #endif diff --git a/hw/ppc/ppce500_spin.c b/hw/ppc/ppce500_spin.c index 225177b..22c584e 100644 --- a/hw/ppc/ppce500_spin.c +++ b/hw/ppc/ppce500_spin.c @@ -32,6 +32,7 @@ #include "sysemu/sysemu.h" #include "hw/sysbus.h" #include "sysemu/kvm.h" +#include "e500.h" #define MAX_CPUS 32 @@ -72,12 +73,6 @@ static void spin_reset(void *opaque) } } -/* Create -kernel TLB entries for BookE, linearly spanning 256MB. */ -static inline hwaddr booke206_page_size_to_tlb(uint64_t size) -{ - return ctz32(size >> 10) >> 1; -} - static void mmubooke_create_initial_mapping(CPUPPCState *env, target_ulong va, hwaddr pa, -- cgit v1.1 From 161deaf225e70dee991744cd3164a30726a1b0eb Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 29 Jun 2016 00:35:12 +0530 Subject: ppc/xics: Rename existing xics to xics_spapr The common class doesn't change, the KVM one is sPAPR specific. Rename variables and functions to xics_spapr. Retain the type name as "xics" to preserve migration for existing sPAPR guests. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Nikunj A Dadhania Signed-off-by: David Gibson --- hw/intc/xics.c | 33 +++++++++++++++++---------------- hw/intc/xics_kvm.c | 14 +++++++------- hw/ppc/spapr.c | 7 ++++--- hw/ppc/spapr_events.c | 2 +- hw/ppc/spapr_pci.c | 10 +++++----- hw/ppc/spapr_vio.c | 2 +- 6 files changed, 35 insertions(+), 33 deletions(-) (limited to 'hw') diff --git a/hw/intc/xics.c b/hw/intc/xics.c index 2e83d41..bf5eb56 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -718,7 +718,8 @@ static int ics_find_free_block(ICSState *ics, int num, int alignnum) return -1; } -int xics_alloc(XICSState *icp, int src, int irq_hint, bool lsi, Error **errp) +int xics_spapr_alloc(XICSState *icp, int src, int irq_hint, bool lsi, + Error **errp) { ICSState *ics = &icp->ics[src]; int irq; @@ -749,8 +750,8 @@ int xics_alloc(XICSState *icp, int src, int irq_hint, bool lsi, Error **errp) * Allocate block of consecutive IRQs, and return the number of the first IRQ in the block. * If align==true, aligns the first IRQ number to num. */ -int xics_alloc_block(XICSState *icp, int src, int num, bool lsi, bool align, - Error **errp) +int xics_spapr_alloc_block(XICSState *icp, int src, int num, bool lsi, + bool align, Error **errp) { int i, first = -1; ICSState *ics = &icp->ics[src]; @@ -799,7 +800,7 @@ static void ics_free(ICSState *ics, int srcno, int num) } } -void xics_free(XICSState *icp, int irq, int num) +void xics_spapr_free(XICSState *icp, int irq, int num) { int src = xics_find_source(icp, irq); @@ -1018,9 +1019,9 @@ static void xics_set_nr_servers(XICSState *icp, uint32_t nr_servers, } } -static void xics_realize(DeviceState *dev, Error **errp) +static void xics_spapr_realize(DeviceState *dev, Error **errp) { - XICSState *icp = XICS(dev); + XICSState *icp = XICS_SPAPR(dev); Error *error = NULL; int i; @@ -1057,38 +1058,38 @@ static void xics_realize(DeviceState *dev, Error **errp) } } -static void xics_initfn(Object *obj) +static void xics_spapr_initfn(Object *obj) { - XICSState *xics = XICS(obj); + XICSState *xics = XICS_SPAPR(obj); xics->ics = ICS(object_new(TYPE_ICS)); object_property_add_child(obj, "ics", OBJECT(xics->ics), NULL); xics->ics->icp = xics; } -static void xics_class_init(ObjectClass *oc, void *data) +static void xics_spapr_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); - XICSStateClass *xsc = XICS_CLASS(oc); + XICSStateClass *xsc = XICS_SPAPR_CLASS(oc); - dc->realize = xics_realize; + dc->realize = xics_spapr_realize; xsc->set_nr_irqs = xics_set_nr_irqs; xsc->set_nr_servers = xics_set_nr_servers; } -static const TypeInfo xics_info = { - .name = TYPE_XICS, +static const TypeInfo xics_spapr_info = { + .name = TYPE_XICS_SPAPR, .parent = TYPE_XICS_COMMON, .instance_size = sizeof(XICSState), .class_size = sizeof(XICSStateClass), - .class_init = xics_class_init, - .instance_init = xics_initfn, + .class_init = xics_spapr_class_init, + .instance_init = xics_spapr_initfn, }; static void xics_register_types(void) { type_register_static(&xics_common_info); - type_register_static(&xics_info); + type_register_static(&xics_spapr_info); type_register_static(&ics_info); type_register_static(&icp_info); } diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c index b17d6a9..a533e3d 100644 --- a/hw/intc/xics_kvm.c +++ b/hw/intc/xics_kvm.c @@ -145,7 +145,7 @@ static const TypeInfo icp_kvm_info = { */ static void ics_get_kvm_state(ICSState *ics) { - KVMXICSState *icpkvm = KVM_XICS(ics->icp); + KVMXICSState *icpkvm = XICS_SPAPR_KVM(ics->icp); uint64_t state; struct kvm_device_attr attr = { .flags = 0, @@ -204,7 +204,7 @@ static void ics_get_kvm_state(ICSState *ics) static int ics_set_kvm_state(ICSState *ics, int version_id) { - KVMXICSState *icpkvm = KVM_XICS(ics->icp); + KVMXICSState *icpkvm = XICS_SPAPR_KVM(ics->icp); uint64_t state; struct kvm_device_attr attr = { .flags = 0, @@ -328,7 +328,7 @@ static void xics_kvm_cpu_setup(XICSState *icp, PowerPCCPU *cpu) { CPUState *cs; ICPState *ss; - KVMXICSState *icpkvm = KVM_XICS(icp); + KVMXICSState *icpkvm = XICS_SPAPR_KVM(icp); cs = CPU(cpu); ss = &icp->ss[cs->cpu_index]; @@ -394,7 +394,7 @@ static void rtas_dummy(PowerPCCPU *cpu, sPAPRMachineState *spapr, static void xics_kvm_realize(DeviceState *dev, Error **errp) { - KVMXICSState *icpkvm = KVM_XICS(dev); + KVMXICSState *icpkvm = XICS_SPAPR_KVM(dev); XICSState *icp = XICS_COMMON(dev); int i, rc; Error *error = NULL; @@ -495,8 +495,8 @@ static void xics_kvm_class_init(ObjectClass *oc, void *data) xsc->set_nr_servers = xics_kvm_set_nr_servers; } -static const TypeInfo xics_kvm_info = { - .name = TYPE_KVM_XICS, +static const TypeInfo xics_spapr_kvm_info = { + .name = TYPE_XICS_SPAPR_KVM, .parent = TYPE_XICS_COMMON, .instance_size = sizeof(KVMXICSState), .class_init = xics_kvm_class_init, @@ -505,7 +505,7 @@ static const TypeInfo xics_kvm_info = { static void xics_kvm_register_types(void) { - type_register_static(&xics_kvm_info); + type_register_static(&xics_spapr_kvm_info); type_register_static(&ics_kvm_info); type_register_static(&icp_kvm_info); } diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index d26b4c2..3f0ea03 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -122,7 +122,8 @@ static XICSState *xics_system_init(MachineState *machine, Error *err = NULL; if (machine_kernel_irqchip_allowed(machine)) { - icp = try_create_xics(TYPE_KVM_XICS, nr_servers, nr_irqs, &err); + icp = try_create_xics(TYPE_XICS_SPAPR_KVM, nr_servers, nr_irqs, + &err); } if (machine_kernel_irqchip_required(machine) && !icp) { error_reportf_err(err, @@ -133,7 +134,7 @@ static XICSState *xics_system_init(MachineState *machine, } if (!icp) { - icp = try_create_xics(TYPE_XICS, nr_servers, nr_irqs, errp); + icp = try_create_xics(TYPE_XICS_SPAPR, nr_servers, nr_irqs, errp); } return icp; @@ -1784,7 +1785,7 @@ static void ppc_spapr_init(MachineState *machine) /* Set up Interrupt Controller before we create the VCPUs */ spapr->icp = xics_system_init(machine, DIV_ROUND_UP(max_cpus * smt, smp_threads), - XICS_IRQS, &error_fatal); + XICS_IRQS_SPAPR, &error_fatal); if (smc->dr_lmb_enabled) { spapr_validate_node_memory(machine, &error_fatal); diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c index af80992..0585f8a 100644 --- a/hw/ppc/spapr_events.c +++ b/hw/ppc/spapr_events.c @@ -603,7 +603,7 @@ out_no_events: void spapr_events_init(sPAPRMachineState *spapr) { QTAILQ_INIT(&spapr->pending_events); - spapr->check_exception_irq = xics_alloc(spapr->icp, 0, 0, false, + spapr->check_exception_irq = xics_spapr_alloc(spapr->icp, 0, 0, false, &error_fatal); spapr->epow_notifier.notify = spapr_powerdown_req; qemu_register_powerdown_notifier(&spapr->epow_notifier); diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 9f28fb3..451651d 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -322,7 +322,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr, return; } - xics_free(spapr->icp, msi->first_irq, msi->num); + xics_spapr_free(spapr->icp, msi->first_irq, msi->num); if (msi_present(pdev)) { spapr_msi_setmsg(pdev, 0, false, 0, 0); } @@ -360,7 +360,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr, } /* Allocate MSIs */ - irq = xics_alloc_block(spapr->icp, 0, req_num, false, + irq = xics_spapr_alloc_block(spapr->icp, 0, req_num, false, ret_intr_type == RTAS_TYPE_MSI, &err); if (err) { error_reportf_err(err, "Can't allocate MSIs for device %x: ", @@ -371,7 +371,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr, /* Release previous MSIs */ if (msi) { - xics_free(spapr->icp, msi->first_irq, msi->num); + xics_spapr_free(spapr->icp, msi->first_irq, msi->num); g_hash_table_remove(phb->msi, &config_addr); } @@ -1442,7 +1442,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) uint32_t irq; Error *local_err = NULL; - irq = xics_alloc_block(spapr->icp, 0, 1, true, false, &local_err); + irq = xics_spapr_alloc_block(spapr->icp, 0, 1, true, false, &local_err); if (local_err) { error_propagate(errp, local_err); error_prepend(errp, "can't allocate LSIs: "); @@ -1801,7 +1801,7 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb, _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", XICS_IRQS)); + _FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pe-total-#msi", XICS_IRQS_SPAPR)); /* Build the interrupt-map, this must matches what is done * in pci_spapr_map_irq diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c index ae40db8..7ffd23e 100644 --- a/hw/ppc/spapr_vio.c +++ b/hw/ppc/spapr_vio.c @@ -463,7 +463,7 @@ static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp) dev->qdev.id = id; } - dev->irq = xics_alloc(spapr->icp, 0, dev->irq, false, &local_err); + dev->irq = xics_spapr_alloc(spapr->icp, 0, dev->irq, false, &local_err); if (local_err) { error_propagate(errp, local_err); return; -- cgit v1.1 From 9c7027ba947d95dedaa760758cc378c8496e0316 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 29 Jun 2016 00:35:13 +0530 Subject: ppc/xics: Move SPAPR specific code to a separate file Leave the core ICP/ICS logic in xics.c and move the top level class wrapper, hypercall and RTAS handlers to xics_spapr.c Signed-off-by: Benjamin Herrenschmidt [add cpu.h in xics_spapr.c, move set_nr_irqs and set_nr_servers to xics_spapr.c] Signed-off-by: Nikunj A Dadhania Signed-off-by: David Gibson --- hw/intc/Makefile.objs | 1 + hw/intc/xics.c | 418 ++---------------------------------------------- hw/intc/xics_spapr.c | 432 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 442 insertions(+), 409 deletions(-) create mode 100644 hw/intc/xics_spapr.c (limited to 'hw') diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs index c7bbf88..530df2e 100644 --- a/hw/intc/Makefile.objs +++ b/hw/intc/Makefile.objs @@ -30,6 +30,7 @@ obj-$(CONFIG_OPENPIC_KVM) += openpic_kvm.o obj-$(CONFIG_RASPI) += bcm2835_ic.o bcm2836_control.o obj-$(CONFIG_SH4) += sh_intc.o obj-$(CONFIG_XICS) += xics.o +obj-$(CONFIG_XICS_SPAPR) += xics_spapr.o obj-$(CONFIG_XICS_KVM) += xics_kvm.o obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o obj-$(CONFIG_S390_FLIC) += s390_flic.o diff --git a/hw/intc/xics.c b/hw/intc/xics.c index bf5eb56..f01af08 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -32,12 +32,11 @@ #include "hw/hw.h" #include "trace.h" #include "qemu/timer.h" -#include "hw/ppc/spapr.h" #include "hw/ppc/xics.h" #include "qemu/error-report.h" #include "qapi/visitor.h" -static int get_cpu_index_by_dt_id(int cpu_dt_id) +int xics_get_cpu_index_by_dt_id(int cpu_dt_id) { PowerPCCPU *cpu = ppc_get_vcpu_by_dt_id(cpu_dt_id); @@ -242,7 +241,7 @@ static void icp_resend(XICSState *icp, int server) ics_resend(icp->ics); } -static void icp_set_cppr(XICSState *icp, int server, uint8_t cppr) +void icp_set_cppr(XICSState *icp, int server, uint8_t cppr) { ICPState *ss = icp->ss + server; uint8_t old_cppr; @@ -266,7 +265,7 @@ static void icp_set_cppr(XICSState *icp, int server, uint8_t cppr) } } -static void icp_set_mfrr(XICSState *icp, int server, uint8_t mfrr) +void icp_set_mfrr(XICSState *icp, int server, uint8_t mfrr) { ICPState *ss = icp->ss + server; @@ -276,7 +275,7 @@ static void icp_set_mfrr(XICSState *icp, int server, uint8_t mfrr) } } -static uint32_t icp_accept(ICPState *ss) +uint32_t icp_accept(ICPState *ss) { uint32_t xirr = ss->xirr; @@ -289,7 +288,7 @@ static uint32_t icp_accept(ICPState *ss) return xirr; } -static void icp_eoi(XICSState *icp, int server, uint32_t xirr) +void icp_eoi(XICSState *icp, int server, uint32_t xirr) { ICPState *ss = icp->ss + server; @@ -390,12 +389,6 @@ static const TypeInfo icp_info = { /* * ICS: Source layer */ -static int ics_valid_irq(ICSState *ics, uint32_t nr) -{ - return (nr >= ics->offset) - && (nr < (ics->offset + ics->nr_irqs)); -} - static void resend_msi(ICSState *ics, int srcno) { ICSIRQState *irq = ics->irqs + srcno; @@ -480,8 +473,8 @@ static void write_xive_lsi(ICSState *ics, int srcno) resend_lsi(ics, srcno); } -static void ics_write_xive(ICSState *ics, int nr, int server, - uint8_t priority, uint8_t saved_priority) +void ics_write_xive(ICSState *ics, int nr, int server, + uint8_t priority, uint8_t saved_priority) { int srcno = nr - ics->offset; ICSIRQState *irq = ics->irqs + srcno; @@ -658,7 +651,7 @@ static const TypeInfo ics_info = { /* * Exported functions */ -static int xics_find_source(XICSState *icp, int irq) +int xics_find_source(XICSState *icp, int irq) { int sources = 1; int src; @@ -686,7 +679,7 @@ qemu_irq xics_get_qirq(XICSState *icp, int irq) return NULL; } -static void ics_set_irq_type(ICSState *ics, int srcno, bool lsi) +void ics_set_irq_type(ICSState *ics, int srcno, bool lsi) { assert(!(ics->irqs[srcno].flags & XICS_FLAGS_IRQ_MASK)); @@ -694,402 +687,9 @@ static void ics_set_irq_type(ICSState *ics, int srcno, bool lsi) lsi ? XICS_FLAGS_IRQ_LSI : XICS_FLAGS_IRQ_MSI; } -#define ICS_IRQ_FREE(ics, srcno) \ - (!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK))) - -static int ics_find_free_block(ICSState *ics, int num, int alignnum) -{ - int first, i; - - for (first = 0; first < ics->nr_irqs; first += alignnum) { - if (num > (ics->nr_irqs - first)) { - return -1; - } - for (i = first; i < first + num; ++i) { - if (!ICS_IRQ_FREE(ics, i)) { - break; - } - } - if (i == (first + num)) { - return first; - } - } - - return -1; -} - -int xics_spapr_alloc(XICSState *icp, int src, int irq_hint, bool lsi, - Error **errp) -{ - ICSState *ics = &icp->ics[src]; - int irq; - - if (irq_hint) { - assert(src == xics_find_source(icp, irq_hint)); - if (!ICS_IRQ_FREE(ics, irq_hint - ics->offset)) { - error_setg(errp, "can't allocate IRQ %d: already in use", irq_hint); - return -1; - } - irq = irq_hint; - } else { - irq = ics_find_free_block(ics, 1, 1); - if (irq < 0) { - error_setg(errp, "can't allocate IRQ: no IRQ left"); - return -1; - } - irq += ics->offset; - } - - ics_set_irq_type(ics, irq - ics->offset, lsi); - trace_xics_alloc(src, irq); - - return irq; -} - -/* - * Allocate block of consecutive IRQs, and return the number of the first IRQ in the block. - * If align==true, aligns the first IRQ number to num. - */ -int xics_spapr_alloc_block(XICSState *icp, int src, int num, bool lsi, - bool align, Error **errp) -{ - int i, first = -1; - ICSState *ics = &icp->ics[src]; - - assert(src == 0); - /* - * MSIMesage::data is used for storing VIRQ so - * it has to be aligned to num to support multiple - * MSI vectors. MSI-X is not affected by this. - * The hint is used for the first IRQ, the rest should - * be allocated continuously. - */ - if (align) { - assert((num == 1) || (num == 2) || (num == 4) || - (num == 8) || (num == 16) || (num == 32)); - first = ics_find_free_block(ics, num, num); - } else { - first = ics_find_free_block(ics, num, 1); - } - if (first < 0) { - error_setg(errp, "can't find a free %d-IRQ block", num); - return -1; - } - - if (first >= 0) { - for (i = first; i < first + num; ++i) { - ics_set_irq_type(ics, i, lsi); - } - } - first += ics->offset; - - trace_xics_alloc_block(src, first, num, lsi, align); - - return first; -} - -static void ics_free(ICSState *ics, int srcno, int num) -{ - int i; - - for (i = srcno; i < srcno + num; ++i) { - if (ICS_IRQ_FREE(ics, i)) { - trace_xics_ics_free_warn(ics - ics->icp->ics, i + ics->offset); - } - memset(&ics->irqs[i], 0, sizeof(ICSIRQState)); - } -} - -void xics_spapr_free(XICSState *icp, int irq, int num) -{ - int src = xics_find_source(icp, irq); - - if (src >= 0) { - ICSState *ics = &icp->ics[src]; - - /* FIXME: implement multiple sources */ - assert(src == 0); - - trace_xics_ics_free(ics - icp->ics, irq, num); - ics_free(ics, irq - ics->offset, num); - } -} - -/* - * Guest interfaces - */ - -static target_ulong h_cppr(PowerPCCPU *cpu, sPAPRMachineState *spapr, - target_ulong opcode, target_ulong *args) -{ - CPUState *cs = CPU(cpu); - target_ulong cppr = args[0]; - - icp_set_cppr(spapr->icp, cs->cpu_index, cppr); - return H_SUCCESS; -} - -static target_ulong h_ipi(PowerPCCPU *cpu, sPAPRMachineState *spapr, - target_ulong opcode, target_ulong *args) -{ - target_ulong server = get_cpu_index_by_dt_id(args[0]); - target_ulong mfrr = args[1]; - - if (server >= spapr->icp->nr_servers) { - return H_PARAMETER; - } - - icp_set_mfrr(spapr->icp, server, mfrr); - return H_SUCCESS; -} - -static target_ulong h_xirr(PowerPCCPU *cpu, sPAPRMachineState *spapr, - target_ulong opcode, target_ulong *args) -{ - CPUState *cs = CPU(cpu); - uint32_t xirr = icp_accept(spapr->icp->ss + cs->cpu_index); - - args[0] = xirr; - return H_SUCCESS; -} - -static target_ulong h_xirr_x(PowerPCCPU *cpu, sPAPRMachineState *spapr, - target_ulong opcode, target_ulong *args) -{ - CPUState *cs = CPU(cpu); - ICPState *ss = &spapr->icp->ss[cs->cpu_index]; - uint32_t xirr = icp_accept(ss); - - args[0] = xirr; - args[1] = cpu_get_host_ticks(); - return H_SUCCESS; -} - -static target_ulong h_eoi(PowerPCCPU *cpu, sPAPRMachineState *spapr, - target_ulong opcode, target_ulong *args) -{ - CPUState *cs = CPU(cpu); - target_ulong xirr = args[0]; - - icp_eoi(spapr->icp, cs->cpu_index, xirr); - return H_SUCCESS; -} - -static target_ulong h_ipoll(PowerPCCPU *cpu, sPAPRMachineState *spapr, - target_ulong opcode, target_ulong *args) -{ - CPUState *cs = CPU(cpu); - ICPState *ss = &spapr->icp->ss[cs->cpu_index]; - - args[0] = ss->xirr; - args[1] = ss->mfrr; - - return H_SUCCESS; -} - -static void rtas_set_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr, - uint32_t token, - uint32_t nargs, target_ulong args, - uint32_t nret, target_ulong rets) -{ - ICSState *ics = spapr->icp->ics; - uint32_t nr, server, priority; - - if ((nargs != 3) || (nret != 1)) { - rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); - return; - } - - nr = rtas_ld(args, 0); - server = get_cpu_index_by_dt_id(rtas_ld(args, 1)); - priority = rtas_ld(args, 2); - - if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers) - || (priority > 0xff)) { - rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); - return; - } - - ics_write_xive(ics, nr, server, priority, priority); - - rtas_st(rets, 0, RTAS_OUT_SUCCESS); -} - -static void rtas_get_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr, - uint32_t token, - uint32_t nargs, target_ulong args, - uint32_t nret, target_ulong rets) -{ - ICSState *ics = spapr->icp->ics; - uint32_t nr; - - if ((nargs != 1) || (nret != 3)) { - rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); - return; - } - - nr = rtas_ld(args, 0); - - if (!ics_valid_irq(ics, nr)) { - rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); - return; - } - - rtas_st(rets, 0, RTAS_OUT_SUCCESS); - rtas_st(rets, 1, ics->irqs[nr - ics->offset].server); - rtas_st(rets, 2, ics->irqs[nr - ics->offset].priority); -} - -static void rtas_int_off(PowerPCCPU *cpu, sPAPRMachineState *spapr, - uint32_t token, - uint32_t nargs, target_ulong args, - uint32_t nret, target_ulong rets) -{ - ICSState *ics = spapr->icp->ics; - uint32_t nr; - - if ((nargs != 1) || (nret != 1)) { - rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); - return; - } - - nr = rtas_ld(args, 0); - - if (!ics_valid_irq(ics, nr)) { - rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); - return; - } - - ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, 0xff, - ics->irqs[nr - ics->offset].priority); - - rtas_st(rets, 0, RTAS_OUT_SUCCESS); -} - -static void rtas_int_on(PowerPCCPU *cpu, sPAPRMachineState *spapr, - uint32_t token, - uint32_t nargs, target_ulong args, - uint32_t nret, target_ulong rets) -{ - ICSState *ics = spapr->icp->ics; - uint32_t nr; - - if ((nargs != 1) || (nret != 1)) { - rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); - return; - } - - nr = rtas_ld(args, 0); - - if (!ics_valid_irq(ics, nr)) { - rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); - return; - } - - ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, - ics->irqs[nr - ics->offset].saved_priority, - ics->irqs[nr - ics->offset].saved_priority); - - rtas_st(rets, 0, RTAS_OUT_SUCCESS); -} - -/* - * XICS - */ - -static void xics_set_nr_irqs(XICSState *icp, uint32_t nr_irqs, Error **errp) -{ - icp->nr_irqs = icp->ics->nr_irqs = nr_irqs; -} - -static void xics_set_nr_servers(XICSState *icp, uint32_t nr_servers, - Error **errp) -{ - int i; - - icp->nr_servers = nr_servers; - - icp->ss = g_malloc0(icp->nr_servers*sizeof(ICPState)); - for (i = 0; i < icp->nr_servers; i++) { - char buffer[32]; - object_initialize(&icp->ss[i], sizeof(icp->ss[i]), TYPE_ICP); - snprintf(buffer, sizeof(buffer), "icp[%d]", i); - object_property_add_child(OBJECT(icp), buffer, OBJECT(&icp->ss[i]), - errp); - } -} - -static void xics_spapr_realize(DeviceState *dev, Error **errp) -{ - XICSState *icp = XICS_SPAPR(dev); - Error *error = NULL; - int i; - - if (!icp->nr_servers) { - error_setg(errp, "Number of servers needs to be greater 0"); - return; - } - - /* Registration of global state belongs into realize */ - spapr_rtas_register(RTAS_IBM_SET_XIVE, "ibm,set-xive", rtas_set_xive); - spapr_rtas_register(RTAS_IBM_GET_XIVE, "ibm,get-xive", rtas_get_xive); - spapr_rtas_register(RTAS_IBM_INT_OFF, "ibm,int-off", rtas_int_off); - spapr_rtas_register(RTAS_IBM_INT_ON, "ibm,int-on", rtas_int_on); - - spapr_register_hypercall(H_CPPR, h_cppr); - spapr_register_hypercall(H_IPI, h_ipi); - spapr_register_hypercall(H_XIRR, h_xirr); - spapr_register_hypercall(H_XIRR_X, h_xirr_x); - spapr_register_hypercall(H_EOI, h_eoi); - spapr_register_hypercall(H_IPOLL, h_ipoll); - - object_property_set_bool(OBJECT(icp->ics), true, "realized", &error); - if (error) { - error_propagate(errp, error); - return; - } - - for (i = 0; i < icp->nr_servers; i++) { - object_property_set_bool(OBJECT(&icp->ss[i]), true, "realized", &error); - if (error) { - error_propagate(errp, error); - return; - } - } -} - -static void xics_spapr_initfn(Object *obj) -{ - XICSState *xics = XICS_SPAPR(obj); - - xics->ics = ICS(object_new(TYPE_ICS)); - object_property_add_child(obj, "ics", OBJECT(xics->ics), NULL); - xics->ics->icp = xics; -} - -static void xics_spapr_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - XICSStateClass *xsc = XICS_SPAPR_CLASS(oc); - - dc->realize = xics_spapr_realize; - xsc->set_nr_irqs = xics_set_nr_irqs; - xsc->set_nr_servers = xics_set_nr_servers; -} - -static const TypeInfo xics_spapr_info = { - .name = TYPE_XICS_SPAPR, - .parent = TYPE_XICS_COMMON, - .instance_size = sizeof(XICSState), - .class_size = sizeof(XICSStateClass), - .class_init = xics_spapr_class_init, - .instance_init = xics_spapr_initfn, -}; - static void xics_register_types(void) { type_register_static(&xics_common_info); - type_register_static(&xics_spapr_info); type_register_static(&ics_info); type_register_static(&icp_info); } diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c new file mode 100644 index 0000000..89190ef --- /dev/null +++ b/hw/intc/xics_spapr.c @@ -0,0 +1,432 @@ +/* + * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator + * + * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics + * + * Copyright (c) 2010,2011 David Gibson, IBM Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "hw/hw.h" +#include "trace.h" +#include "qemu/timer.h" +#include "hw/ppc/spapr.h" +#include "hw/ppc/xics.h" +#include "qapi/visitor.h" +#include "qapi/error.h" + +/* + * Guest interfaces + */ + +static target_ulong h_cppr(PowerPCCPU *cpu, sPAPRMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + CPUState *cs = CPU(cpu); + target_ulong cppr = args[0]; + + icp_set_cppr(spapr->icp, cs->cpu_index, cppr); + return H_SUCCESS; +} + +static target_ulong h_ipi(PowerPCCPU *cpu, sPAPRMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong server = xics_get_cpu_index_by_dt_id(args[0]); + target_ulong mfrr = args[1]; + + if (server >= spapr->icp->nr_servers) { + return H_PARAMETER; + } + + icp_set_mfrr(spapr->icp, server, mfrr); + return H_SUCCESS; +} + +static target_ulong h_xirr(PowerPCCPU *cpu, sPAPRMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + CPUState *cs = CPU(cpu); + uint32_t xirr = icp_accept(spapr->icp->ss + cs->cpu_index); + + args[0] = xirr; + return H_SUCCESS; +} + +static target_ulong h_xirr_x(PowerPCCPU *cpu, sPAPRMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + CPUState *cs = CPU(cpu); + ICPState *ss = &spapr->icp->ss[cs->cpu_index]; + uint32_t xirr = icp_accept(ss); + + args[0] = xirr; + args[1] = cpu_get_host_ticks(); + return H_SUCCESS; +} + +static target_ulong h_eoi(PowerPCCPU *cpu, sPAPRMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + CPUState *cs = CPU(cpu); + target_ulong xirr = args[0]; + + icp_eoi(spapr->icp, cs->cpu_index, xirr); + return H_SUCCESS; +} + +static target_ulong h_ipoll(PowerPCCPU *cpu, sPAPRMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + CPUState *cs = CPU(cpu); + ICPState *ss = &spapr->icp->ss[cs->cpu_index]; + + args[0] = ss->xirr; + args[1] = ss->mfrr; + + return H_SUCCESS; +} + +static void rtas_set_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr, + uint32_t token, + uint32_t nargs, target_ulong args, + uint32_t nret, target_ulong rets) +{ + ICSState *ics = spapr->icp->ics; + uint32_t nr, server, priority; + + if ((nargs != 3) || (nret != 1)) { + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); + return; + } + + nr = rtas_ld(args, 0); + server = xics_get_cpu_index_by_dt_id(rtas_ld(args, 1)); + priority = rtas_ld(args, 2); + + if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers) + || (priority > 0xff)) { + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); + return; + } + + ics_write_xive(ics, nr, server, priority, priority); + + rtas_st(rets, 0, RTAS_OUT_SUCCESS); +} + +static void rtas_get_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr, + uint32_t token, + uint32_t nargs, target_ulong args, + uint32_t nret, target_ulong rets) +{ + ICSState *ics = spapr->icp->ics; + uint32_t nr; + + if ((nargs != 1) || (nret != 3)) { + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); + return; + } + + nr = rtas_ld(args, 0); + + if (!ics_valid_irq(ics, nr)) { + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); + return; + } + + rtas_st(rets, 0, RTAS_OUT_SUCCESS); + rtas_st(rets, 1, ics->irqs[nr - ics->offset].server); + rtas_st(rets, 2, ics->irqs[nr - ics->offset].priority); +} + +static void rtas_int_off(PowerPCCPU *cpu, sPAPRMachineState *spapr, + uint32_t token, + uint32_t nargs, target_ulong args, + uint32_t nret, target_ulong rets) +{ + ICSState *ics = spapr->icp->ics; + uint32_t nr; + + if ((nargs != 1) || (nret != 1)) { + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); + return; + } + + nr = rtas_ld(args, 0); + + if (!ics_valid_irq(ics, nr)) { + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); + return; + } + + ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, 0xff, + ics->irqs[nr - ics->offset].priority); + + rtas_st(rets, 0, RTAS_OUT_SUCCESS); +} + +static void rtas_int_on(PowerPCCPU *cpu, sPAPRMachineState *spapr, + uint32_t token, + uint32_t nargs, target_ulong args, + uint32_t nret, target_ulong rets) +{ + ICSState *ics = spapr->icp->ics; + uint32_t nr; + + if ((nargs != 1) || (nret != 1)) { + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); + return; + } + + nr = rtas_ld(args, 0); + + if (!ics_valid_irq(ics, nr)) { + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); + return; + } + + ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, + ics->irqs[nr - ics->offset].saved_priority, + ics->irqs[nr - ics->offset].saved_priority); + + rtas_st(rets, 0, RTAS_OUT_SUCCESS); +} + +static void xics_spapr_set_nr_irqs(XICSState *icp, uint32_t nr_irqs, + Error **errp) +{ + icp->nr_irqs = icp->ics->nr_irqs = nr_irqs; +} + +static void xics_spapr_set_nr_servers(XICSState *icp, uint32_t nr_servers, + Error **errp) +{ + int i; + + icp->nr_servers = nr_servers; + + icp->ss = g_malloc0(icp->nr_servers * sizeof(ICPState)); + for (i = 0; i < icp->nr_servers; i++) { + char buffer[32]; + object_initialize(&icp->ss[i], sizeof(icp->ss[i]), TYPE_ICP); + snprintf(buffer, sizeof(buffer), "icp[%d]", i); + object_property_add_child(OBJECT(icp), buffer, OBJECT(&icp->ss[i]), + errp); + } +} + +static void xics_spapr_realize(DeviceState *dev, Error **errp) +{ + XICSState *icp = XICS_SPAPR(dev); + Error *error = NULL; + int i; + + if (!icp->nr_servers) { + error_setg(errp, "Number of servers needs to be greater 0"); + return; + } + + /* Registration of global state belongs into realize */ + spapr_rtas_register(RTAS_IBM_SET_XIVE, "ibm,set-xive", rtas_set_xive); + spapr_rtas_register(RTAS_IBM_GET_XIVE, "ibm,get-xive", rtas_get_xive); + spapr_rtas_register(RTAS_IBM_INT_OFF, "ibm,int-off", rtas_int_off); + spapr_rtas_register(RTAS_IBM_INT_ON, "ibm,int-on", rtas_int_on); + + spapr_register_hypercall(H_CPPR, h_cppr); + spapr_register_hypercall(H_IPI, h_ipi); + spapr_register_hypercall(H_XIRR, h_xirr); + spapr_register_hypercall(H_XIRR_X, h_xirr_x); + spapr_register_hypercall(H_EOI, h_eoi); + spapr_register_hypercall(H_IPOLL, h_ipoll); + + object_property_set_bool(OBJECT(icp->ics), true, "realized", &error); + if (error) { + error_propagate(errp, error); + return; + } + + for (i = 0; i < icp->nr_servers; i++) { + object_property_set_bool(OBJECT(&icp->ss[i]), true, "realized", &error); + if (error) { + error_propagate(errp, error); + return; + } + } +} + +static void xics_spapr_initfn(Object *obj) +{ + XICSState *xics = XICS_SPAPR(obj); + + xics->ics = ICS(object_new(TYPE_ICS)); + object_property_add_child(obj, "ics", OBJECT(xics->ics), NULL); + xics->ics->icp = xics; +} + +static void xics_spapr_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + XICSStateClass *xsc = XICS_SPAPR_CLASS(oc); + + dc->realize = xics_spapr_realize; + xsc->set_nr_irqs = xics_spapr_set_nr_irqs; + xsc->set_nr_servers = xics_spapr_set_nr_servers; +} + +static const TypeInfo xics_spapr_info = { + .name = TYPE_XICS_SPAPR, + .parent = TYPE_XICS_COMMON, + .instance_size = sizeof(XICSState), + .class_size = sizeof(XICSStateClass), + .class_init = xics_spapr_class_init, + .instance_init = xics_spapr_initfn, +}; + +#define ICS_IRQ_FREE(ics, srcno) \ + (!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK))) + +static int ics_find_free_block(ICSState *ics, int num, int alignnum) +{ + int first, i; + + for (first = 0; first < ics->nr_irqs; first += alignnum) { + if (num > (ics->nr_irqs - first)) { + return -1; + } + for (i = first; i < first + num; ++i) { + if (!ICS_IRQ_FREE(ics, i)) { + break; + } + } + if (i == (first + num)) { + return first; + } + } + + return -1; +} + +int xics_spapr_alloc(XICSState *icp, int src, int irq_hint, bool lsi, + Error **errp) +{ + ICSState *ics = &icp->ics[src]; + int irq; + + if (irq_hint) { + assert(src == xics_find_source(icp, irq_hint)); + if (!ICS_IRQ_FREE(ics, irq_hint - ics->offset)) { + error_setg(errp, "can't allocate IRQ %d: already in use", irq_hint); + return -1; + } + irq = irq_hint; + } else { + irq = ics_find_free_block(ics, 1, 1); + if (irq < 0) { + error_setg(errp, "can't allocate IRQ: no IRQ left"); + return -1; + } + irq += ics->offset; + } + + ics_set_irq_type(ics, irq - ics->offset, lsi); + trace_xics_alloc(src, irq); + + return irq; +} + +/* + * Allocate block of consecutive IRQs, and return the number of the first IRQ in + * the block. If align==true, aligns the first IRQ number to num. + */ +int xics_spapr_alloc_block(XICSState *icp, int src, int num, bool lsi, + bool align, Error **errp) +{ + int i, first = -1; + ICSState *ics = &icp->ics[src]; + + assert(src == 0); + /* + * MSIMesage::data is used for storing VIRQ so + * it has to be aligned to num to support multiple + * MSI vectors. MSI-X is not affected by this. + * The hint is used for the first IRQ, the rest should + * be allocated continuously. + */ + if (align) { + assert((num == 1) || (num == 2) || (num == 4) || + (num == 8) || (num == 16) || (num == 32)); + first = ics_find_free_block(ics, num, num); + } else { + first = ics_find_free_block(ics, num, 1); + } + if (first < 0) { + error_setg(errp, "can't find a free %d-IRQ block", num); + return -1; + } + + if (first >= 0) { + for (i = first; i < first + num; ++i) { + ics_set_irq_type(ics, i, lsi); + } + } + first += ics->offset; + + trace_xics_alloc_block(src, first, num, lsi, align); + + return first; +} + +static void ics_free(ICSState *ics, int srcno, int num) +{ + int i; + + for (i = srcno; i < srcno + num; ++i) { + if (ICS_IRQ_FREE(ics, i)) { + trace_xics_ics_free_warn(ics - ics->icp->ics, i + ics->offset); + } + memset(&ics->irqs[i], 0, sizeof(ICSIRQState)); + } +} + +void xics_spapr_free(XICSState *icp, int irq, int num) +{ + int src = xics_find_source(icp, irq); + + if (src >= 0) { + ICSState *ics = &icp->ics[src]; + + /* FIXME: implement multiple sources */ + assert(src == 0); + + trace_xics_ics_free(ics - icp->ics, irq, num); + ics_free(ics, irq - ics->offset, num); + } +} + +static void xics_spapr_register_types(void) +{ + type_register_static(&xics_spapr_info); +} + +type_init(xics_spapr_register_types) -- cgit v1.1 From 1cbd22205594c4cf024c50cb437755c64f385da1 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 29 Jun 2016 00:35:14 +0530 Subject: ppc/xics: Implement H_IPOLL using an accessor None of the other presenter functions directly mucks with the internal state, so don't do it there either. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Nikunj A Dadhania Reviewed-by: David Gibson Signed-off-by: David Gibson --- hw/intc/xics.c | 8 ++++++++ hw/intc/xics_spapr.c | 7 ++++--- 2 files changed, 12 insertions(+), 3 deletions(-) (limited to 'hw') diff --git a/hw/intc/xics.c b/hw/intc/xics.c index f01af08..f43f98a 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -288,6 +288,14 @@ uint32_t icp_accept(ICPState *ss) return xirr; } +uint32_t icp_ipoll(ICPState *ss, uint32_t *mfrr) +{ + if (mfrr) { + *mfrr = ss->mfrr; + } + return ss->xirr; +} + void icp_eoi(XICSState *icp, int server, uint32_t xirr) { ICPState *ss = icp->ss + server; diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c index 89190ef..94571dd 100644 --- a/hw/intc/xics_spapr.c +++ b/hw/intc/xics_spapr.c @@ -99,10 +99,11 @@ static target_ulong h_ipoll(PowerPCCPU *cpu, sPAPRMachineState *spapr, target_ulong opcode, target_ulong *args) { CPUState *cs = CPU(cpu); - ICPState *ss = &spapr->icp->ss[cs->cpu_index]; + uint32_t mfrr; + uint32_t xirr = icp_ipoll(spapr->icp->ss + cs->cpu_index, &mfrr); - args[0] = ss->xirr; - args[1] = ss->mfrr; + args[0] = xirr; + args[1] = mfrr; return H_SUCCESS; } -- cgit v1.1 From 27f2458245e259618beb2635abccf00286ea8b2d Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 29 Jun 2016 00:35:15 +0530 Subject: ppc/xics: Replace "icp" with "xics" in most places The "ICP" is a different object than the "XICS". For historical reasons, we have a number of places where we name a variable "icp" while it contains a XICSState pointer. There *is* an ICPState structure too so this makes the code really confusing. This is a mechanical replacement of all those instances to use the name "xics" instead. There should be no functional change. Signed-off-by: Benjamin Herrenschmidt [spapr_cpu_init has been moved to spapr_cpu_core.c, change there] Signed-off-by: Nikunj A Dadhania Reviewed-by: David Gibson Signed-off-by: David Gibson --- hw/intc/xics.c | 120 ++++++++++++++++++++++++------------------------ hw/intc/xics_kvm.c | 57 ++++++++++++----------- hw/intc/xics_spapr.c | 73 ++++++++++++++--------------- hw/ppc/spapr.c | 20 ++++---- hw/ppc/spapr_cpu_core.c | 4 +- hw/ppc/spapr_events.c | 8 ++-- hw/ppc/spapr_pci.c | 11 +++-- hw/ppc/spapr_vio.c | 2 +- 8 files changed, 150 insertions(+), 145 deletions(-) (limited to 'hw') diff --git a/hw/intc/xics.c b/hw/intc/xics.c index f43f98a..cd48f42 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -47,31 +47,31 @@ int xics_get_cpu_index_by_dt_id(int cpu_dt_id) return -1; } -void xics_cpu_destroy(XICSState *icp, PowerPCCPU *cpu) +void xics_cpu_destroy(XICSState *xics, PowerPCCPU *cpu) { CPUState *cs = CPU(cpu); - ICPState *ss = &icp->ss[cs->cpu_index]; + ICPState *ss = &xics->ss[cs->cpu_index]; - assert(cs->cpu_index < icp->nr_servers); + assert(cs->cpu_index < xics->nr_servers); assert(cs == ss->cs); ss->output = NULL; ss->cs = NULL; } -void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu) +void xics_cpu_setup(XICSState *xics, PowerPCCPU *cpu) { CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; - ICPState *ss = &icp->ss[cs->cpu_index]; - XICSStateClass *info = XICS_COMMON_GET_CLASS(icp); + ICPState *ss = &xics->ss[cs->cpu_index]; + XICSStateClass *info = XICS_COMMON_GET_CLASS(xics); - assert(cs->cpu_index < icp->nr_servers); + assert(cs->cpu_index < xics->nr_servers); ss->cs = cs; if (info->cpu_setup) { - info->cpu_setup(icp, cpu); + info->cpu_setup(xics, cpu); } switch (PPC_INPUT(env)) { @@ -95,21 +95,21 @@ void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu) */ static void xics_common_reset(DeviceState *d) { - XICSState *icp = XICS_COMMON(d); + XICSState *xics = XICS_COMMON(d); int i; - for (i = 0; i < icp->nr_servers; i++) { - device_reset(DEVICE(&icp->ss[i])); + for (i = 0; i < xics->nr_servers; i++) { + device_reset(DEVICE(&xics->ss[i])); } - device_reset(DEVICE(icp->ics)); + device_reset(DEVICE(xics->ics)); } static void xics_prop_get_nr_irqs(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - XICSState *icp = XICS_COMMON(obj); - int64_t value = icp->nr_irqs; + XICSState *xics = XICS_COMMON(obj); + int64_t value = xics->nr_irqs; visit_type_int(v, name, &value, errp); } @@ -117,8 +117,8 @@ static void xics_prop_get_nr_irqs(Object *obj, Visitor *v, const char *name, static void xics_prop_set_nr_irqs(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - XICSState *icp = XICS_COMMON(obj); - XICSStateClass *info = XICS_COMMON_GET_CLASS(icp); + XICSState *xics = XICS_COMMON(obj); + XICSStateClass *info = XICS_COMMON_GET_CLASS(xics); Error *error = NULL; int64_t value; @@ -127,23 +127,23 @@ static void xics_prop_set_nr_irqs(Object *obj, Visitor *v, const char *name, error_propagate(errp, error); return; } - if (icp->nr_irqs) { + if (xics->nr_irqs) { error_setg(errp, "Number of interrupts is already set to %u", - icp->nr_irqs); + xics->nr_irqs); return; } assert(info->set_nr_irqs); - assert(icp->ics); - info->set_nr_irqs(icp, value, errp); + assert(xics->ics); + info->set_nr_irqs(xics, value, errp); } static void xics_prop_get_nr_servers(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - XICSState *icp = XICS_COMMON(obj); - int64_t value = icp->nr_servers; + XICSState *xics = XICS_COMMON(obj); + int64_t value = xics->nr_servers; visit_type_int(v, name, &value, errp); } @@ -152,8 +152,8 @@ static void xics_prop_set_nr_servers(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - XICSState *icp = XICS_COMMON(obj); - XICSStateClass *info = XICS_COMMON_GET_CLASS(icp); + XICSState *xics = XICS_COMMON(obj); + XICSStateClass *info = XICS_COMMON_GET_CLASS(xics); Error *error = NULL; int64_t value; @@ -162,14 +162,14 @@ static void xics_prop_set_nr_servers(Object *obj, Visitor *v, error_propagate(errp, error); return; } - if (icp->nr_servers) { + if (xics->nr_servers) { error_setg(errp, "Number of servers is already set to %u", - icp->nr_servers); + xics->nr_servers); return; } assert(info->set_nr_servers); - info->set_nr_servers(icp, value, errp); + info->set_nr_servers(xics, value, errp); } static void xics_common_initfn(Object *obj) @@ -212,9 +212,9 @@ static void ics_reject(ICSState *ics, int nr); static void ics_resend(ICSState *ics); static void ics_eoi(ICSState *ics, int nr); -static void icp_check_ipi(XICSState *icp, int server) +static void icp_check_ipi(XICSState *xics, int server) { - ICPState *ss = icp->ss + server; + ICPState *ss = xics->ss + server; if (XISR(ss) && (ss->pending_priority <= ss->mfrr)) { return; @@ -223,7 +223,7 @@ static void icp_check_ipi(XICSState *icp, int server) trace_xics_icp_check_ipi(server, ss->mfrr); if (XISR(ss)) { - ics_reject(icp->ics, XISR(ss)); + ics_reject(xics->ics, XISR(ss)); } ss->xirr = (ss->xirr & ~XISR_MASK) | XICS_IPI; @@ -231,19 +231,19 @@ static void icp_check_ipi(XICSState *icp, int server) qemu_irq_raise(ss->output); } -static void icp_resend(XICSState *icp, int server) +static void icp_resend(XICSState *xics, int server) { - ICPState *ss = icp->ss + server; + ICPState *ss = xics->ss + server; if (ss->mfrr < CPPR(ss)) { - icp_check_ipi(icp, server); + icp_check_ipi(xics, server); } - ics_resend(icp->ics); + ics_resend(xics->ics); } -void icp_set_cppr(XICSState *icp, int server, uint8_t cppr) +void icp_set_cppr(XICSState *xics, int server, uint8_t cppr) { - ICPState *ss = icp->ss + server; + ICPState *ss = xics->ss + server; uint8_t old_cppr; uint32_t old_xisr; @@ -256,22 +256,22 @@ void icp_set_cppr(XICSState *icp, int server, uint8_t cppr) ss->xirr &= ~XISR_MASK; /* Clear XISR */ ss->pending_priority = 0xff; qemu_irq_lower(ss->output); - ics_reject(icp->ics, old_xisr); + ics_reject(xics->ics, old_xisr); } } else { if (!XISR(ss)) { - icp_resend(icp, server); + icp_resend(xics, server); } } } -void icp_set_mfrr(XICSState *icp, int server, uint8_t mfrr) +void icp_set_mfrr(XICSState *xics, int server, uint8_t mfrr) { - ICPState *ss = icp->ss + server; + ICPState *ss = xics->ss + server; ss->mfrr = mfrr; if (mfrr < CPPR(ss)) { - icp_check_ipi(icp, server); + icp_check_ipi(xics, server); } } @@ -296,31 +296,31 @@ uint32_t icp_ipoll(ICPState *ss, uint32_t *mfrr) return ss->xirr; } -void icp_eoi(XICSState *icp, int server, uint32_t xirr) +void icp_eoi(XICSState *xics, int server, uint32_t xirr) { - ICPState *ss = icp->ss + server; + ICPState *ss = xics->ss + server; /* Send EOI -> ICS */ ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK); trace_xics_icp_eoi(server, xirr, ss->xirr); - ics_eoi(icp->ics, xirr & XISR_MASK); + ics_eoi(xics->ics, xirr & XISR_MASK); if (!XISR(ss)) { - icp_resend(icp, server); + icp_resend(xics, server); } } -static void icp_irq(XICSState *icp, int server, int nr, uint8_t priority) +static void icp_irq(XICSState *xics, int server, int nr, uint8_t priority) { - ICPState *ss = icp->ss + server; + ICPState *ss = xics->ss + server; trace_xics_icp_irq(server, nr, priority); if ((priority >= CPPR(ss)) || (XISR(ss) && (ss->pending_priority <= priority))) { - ics_reject(icp->ics, nr); + ics_reject(xics->ics, nr); } else { if (XISR(ss)) { - ics_reject(icp->ics, XISR(ss)); + ics_reject(xics->ics, XISR(ss)); } ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK); ss->pending_priority = priority; @@ -405,7 +405,7 @@ static void resend_msi(ICSState *ics, int srcno) if (irq->status & XICS_STATUS_REJECTED) { irq->status &= ~XICS_STATUS_REJECTED; if (irq->priority != 0xff) { - icp_irq(ics->icp, irq->server, srcno + ics->offset, + icp_irq(ics->xics, irq->server, srcno + ics->offset, irq->priority); } } @@ -419,7 +419,7 @@ static void resend_lsi(ICSState *ics, int srcno) && (irq->status & XICS_STATUS_ASSERTED) && !(irq->status & XICS_STATUS_SENT)) { irq->status |= XICS_STATUS_SENT; - icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); + icp_irq(ics->xics, irq->server, srcno + ics->offset, irq->priority); } } @@ -434,7 +434,7 @@ static void set_irq_msi(ICSState *ics, int srcno, int val) irq->status |= XICS_STATUS_MASKED_PENDING; trace_xics_masked_pending(); } else { - icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); + icp_irq(ics->xics, irq->server, srcno + ics->offset, irq->priority); } } } @@ -473,7 +473,7 @@ static void write_xive_msi(ICSState *ics, int srcno) } irq->status &= ~XICS_STATUS_MASKED_PENDING; - icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); + icp_irq(ics->xics, irq->server, srcno + ics->offset, irq->priority); } static void write_xive_lsi(ICSState *ics, int srcno) @@ -558,8 +558,8 @@ static int ics_post_load(ICSState *ics, int version_id) { int i; - for (i = 0; i < ics->icp->nr_servers; i++) { - icp_resend(ics->icp, i); + for (i = 0; i < ics->xics->nr_servers; i++) { + icp_resend(ics->xics, i); } return 0; @@ -659,14 +659,14 @@ static const TypeInfo ics_info = { /* * Exported functions */ -int xics_find_source(XICSState *icp, int irq) +int xics_find_source(XICSState *xics, int irq) { int sources = 1; int src; /* FIXME: implement multiple sources */ for (src = 0; src < sources; ++src) { - ICSState *ics = &icp->ics[src]; + ICSState *ics = &xics->ics[src]; if (ics_valid_irq(ics, irq)) { return src; } @@ -675,12 +675,12 @@ int xics_find_source(XICSState *icp, int irq) return -1; } -qemu_irq xics_get_qirq(XICSState *icp, int irq) +qemu_irq xics_get_qirq(XICSState *xics, int irq) { - int src = xics_find_source(icp, irq); + int src = xics_find_source(xics, irq); if (src >= 0) { - ICSState *ics = &icp->ics[src]; + ICSState *ics = &xics->ics[src]; return ics->qirqs[irq - ics->offset]; } diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c index a533e3d..edbd62f 100644 --- a/hw/intc/xics_kvm.c +++ b/hw/intc/xics_kvm.c @@ -145,7 +145,7 @@ static const TypeInfo icp_kvm_info = { */ static void ics_get_kvm_state(ICSState *ics) { - KVMXICSState *icpkvm = XICS_SPAPR_KVM(ics->icp); + KVMXICSState *xicskvm = XICS_SPAPR_KVM(ics->xics); uint64_t state; struct kvm_device_attr attr = { .flags = 0, @@ -160,7 +160,7 @@ static void ics_get_kvm_state(ICSState *ics) attr.attr = i + ics->offset; - ret = ioctl(icpkvm->kernel_xics_fd, KVM_GET_DEVICE_ATTR, &attr); + ret = ioctl(xicskvm->kernel_xics_fd, KVM_GET_DEVICE_ATTR, &attr); if (ret != 0) { error_report("Unable to retrieve KVM interrupt controller state" " for IRQ %d: %s", i + ics->offset, strerror(errno)); @@ -204,7 +204,7 @@ static void ics_get_kvm_state(ICSState *ics) static int ics_set_kvm_state(ICSState *ics, int version_id) { - KVMXICSState *icpkvm = XICS_SPAPR_KVM(ics->icp); + KVMXICSState *xicskvm = XICS_SPAPR_KVM(ics->xics); uint64_t state; struct kvm_device_attr attr = { .flags = 0, @@ -238,7 +238,7 @@ static int ics_set_kvm_state(ICSState *ics, int version_id) } } - ret = ioctl(icpkvm->kernel_xics_fd, KVM_SET_DEVICE_ATTR, &attr); + ret = ioctl(xicskvm->kernel_xics_fd, KVM_SET_DEVICE_ATTR, &attr); if (ret != 0) { error_report("Unable to restore KVM interrupt controller state" " for IRQs %d: %s", i + ics->offset, strerror(errno)); @@ -324,17 +324,17 @@ static const TypeInfo ics_kvm_info = { /* * XICS-KVM */ -static void xics_kvm_cpu_setup(XICSState *icp, PowerPCCPU *cpu) +static void xics_kvm_cpu_setup(XICSState *xics, PowerPCCPU *cpu) { CPUState *cs; ICPState *ss; - KVMXICSState *icpkvm = XICS_SPAPR_KVM(icp); + KVMXICSState *xicskvm = XICS_SPAPR_KVM(xics); cs = CPU(cpu); - ss = &icp->ss[cs->cpu_index]; + ss = &xics->ss[cs->cpu_index]; - assert(cs->cpu_index < icp->nr_servers); - if (icpkvm->kernel_xics_fd == -1) { + assert(cs->cpu_index < xics->nr_servers); + if (xicskvm->kernel_xics_fd == -1) { abort(); } @@ -347,11 +347,12 @@ static void xics_kvm_cpu_setup(XICSState *icp, PowerPCCPU *cpu) return; } - if (icpkvm->kernel_xics_fd != -1) { + if (xicskvm->kernel_xics_fd != -1) { int ret; ret = kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_XICS, 0, - icpkvm->kernel_xics_fd, kvm_arch_vcpu_id(cs)); + xicskvm->kernel_xics_fd, + kvm_arch_vcpu_id(cs)); if (ret < 0) { error_report("Unable to connect CPU%ld to kernel XICS: %s", kvm_arch_vcpu_id(cs), strerror(errno)); @@ -361,24 +362,25 @@ static void xics_kvm_cpu_setup(XICSState *icp, PowerPCCPU *cpu) } } -static void xics_kvm_set_nr_irqs(XICSState *icp, uint32_t nr_irqs, Error **errp) +static void xics_kvm_set_nr_irqs(XICSState *xics, uint32_t nr_irqs, + Error **errp) { - icp->nr_irqs = icp->ics->nr_irqs = nr_irqs; + xics->nr_irqs = xics->ics->nr_irqs = nr_irqs; } -static void xics_kvm_set_nr_servers(XICSState *icp, uint32_t nr_servers, +static void xics_kvm_set_nr_servers(XICSState *xics, uint32_t nr_servers, Error **errp) { int i; - icp->nr_servers = nr_servers; + xics->nr_servers = nr_servers; - icp->ss = g_malloc0(icp->nr_servers*sizeof(ICPState)); - for (i = 0; i < icp->nr_servers; i++) { + xics->ss = g_malloc0(xics->nr_servers * sizeof(ICPState)); + for (i = 0; i < xics->nr_servers; i++) { char buffer[32]; - object_initialize(&icp->ss[i], sizeof(icp->ss[i]), TYPE_KVM_ICP); + object_initialize(&xics->ss[i], sizeof(xics->ss[i]), TYPE_KVM_ICP); snprintf(buffer, sizeof(buffer), "icp[%d]", i); - object_property_add_child(OBJECT(icp), buffer, OBJECT(&icp->ss[i]), + object_property_add_child(OBJECT(xics), buffer, OBJECT(&xics->ss[i]), errp); } } @@ -394,8 +396,8 @@ static void rtas_dummy(PowerPCCPU *cpu, sPAPRMachineState *spapr, static void xics_kvm_realize(DeviceState *dev, Error **errp) { - KVMXICSState *icpkvm = XICS_SPAPR_KVM(dev); - XICSState *icp = XICS_COMMON(dev); + KVMXICSState *xicskvm = XICS_SPAPR_KVM(dev); + XICSState *xics = XICS_COMMON(dev); int i, rc; Error *error = NULL; struct kvm_create_device xics_create_device = { @@ -445,17 +447,18 @@ static void xics_kvm_realize(DeviceState *dev, Error **errp) goto fail; } - icpkvm->kernel_xics_fd = xics_create_device.fd; + xicskvm->kernel_xics_fd = xics_create_device.fd; - object_property_set_bool(OBJECT(icp->ics), true, "realized", &error); + object_property_set_bool(OBJECT(xics->ics), true, "realized", &error); if (error) { error_propagate(errp, error); goto fail; } - assert(icp->nr_servers); - for (i = 0; i < icp->nr_servers; i++) { - object_property_set_bool(OBJECT(&icp->ss[i]), true, "realized", &error); + assert(xics->nr_servers); + for (i = 0; i < xics->nr_servers; i++) { + object_property_set_bool(OBJECT(&xics->ss[i]), true, "realized", + &error); if (error) { error_propagate(errp, error); goto fail; @@ -481,7 +484,7 @@ static void xics_kvm_initfn(Object *obj) xics->ics = ICS(object_new(TYPE_KVM_ICS)); object_property_add_child(obj, "ics", OBJECT(xics->ics), NULL); - xics->ics->icp = xics; + xics->ics->xics = xics; } static void xics_kvm_class_init(ObjectClass *oc, void *data) diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c index 94571dd..618826d 100644 --- a/hw/intc/xics_spapr.c +++ b/hw/intc/xics_spapr.c @@ -45,7 +45,7 @@ static target_ulong h_cppr(PowerPCCPU *cpu, sPAPRMachineState *spapr, CPUState *cs = CPU(cpu); target_ulong cppr = args[0]; - icp_set_cppr(spapr->icp, cs->cpu_index, cppr); + icp_set_cppr(spapr->xics, cs->cpu_index, cppr); return H_SUCCESS; } @@ -55,11 +55,11 @@ static target_ulong h_ipi(PowerPCCPU *cpu, sPAPRMachineState *spapr, target_ulong server = xics_get_cpu_index_by_dt_id(args[0]); target_ulong mfrr = args[1]; - if (server >= spapr->icp->nr_servers) { + if (server >= spapr->xics->nr_servers) { return H_PARAMETER; } - icp_set_mfrr(spapr->icp, server, mfrr); + icp_set_mfrr(spapr->xics, server, mfrr); return H_SUCCESS; } @@ -67,7 +67,7 @@ static target_ulong h_xirr(PowerPCCPU *cpu, sPAPRMachineState *spapr, target_ulong opcode, target_ulong *args) { CPUState *cs = CPU(cpu); - uint32_t xirr = icp_accept(spapr->icp->ss + cs->cpu_index); + uint32_t xirr = icp_accept(spapr->xics->ss + cs->cpu_index); args[0] = xirr; return H_SUCCESS; @@ -77,7 +77,7 @@ static target_ulong h_xirr_x(PowerPCCPU *cpu, sPAPRMachineState *spapr, target_ulong opcode, target_ulong *args) { CPUState *cs = CPU(cpu); - ICPState *ss = &spapr->icp->ss[cs->cpu_index]; + ICPState *ss = &spapr->xics->ss[cs->cpu_index]; uint32_t xirr = icp_accept(ss); args[0] = xirr; @@ -91,7 +91,7 @@ static target_ulong h_eoi(PowerPCCPU *cpu, sPAPRMachineState *spapr, CPUState *cs = CPU(cpu); target_ulong xirr = args[0]; - icp_eoi(spapr->icp, cs->cpu_index, xirr); + icp_eoi(spapr->xics, cs->cpu_index, xirr); return H_SUCCESS; } @@ -100,7 +100,7 @@ static target_ulong h_ipoll(PowerPCCPU *cpu, sPAPRMachineState *spapr, { CPUState *cs = CPU(cpu); uint32_t mfrr; - uint32_t xirr = icp_ipoll(spapr->icp->ss + cs->cpu_index, &mfrr); + uint32_t xirr = icp_ipoll(spapr->xics->ss + cs->cpu_index, &mfrr); args[0] = xirr; args[1] = mfrr; @@ -113,7 +113,7 @@ static void rtas_set_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) { - ICSState *ics = spapr->icp->ics; + ICSState *ics = spapr->xics->ics; uint32_t nr, server, priority; if ((nargs != 3) || (nret != 1)) { @@ -125,7 +125,7 @@ static void rtas_set_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr, server = xics_get_cpu_index_by_dt_id(rtas_ld(args, 1)); priority = rtas_ld(args, 2); - if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers) + if (!ics_valid_irq(ics, nr) || (server >= ics->xics->nr_servers) || (priority > 0xff)) { rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; @@ -141,7 +141,7 @@ static void rtas_get_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) { - ICSState *ics = spapr->icp->ics; + ICSState *ics = spapr->xics->ics; uint32_t nr; if ((nargs != 1) || (nret != 3)) { @@ -166,7 +166,7 @@ static void rtas_int_off(PowerPCCPU *cpu, sPAPRMachineState *spapr, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) { - ICSState *ics = spapr->icp->ics; + ICSState *ics = spapr->xics->ics; uint32_t nr; if ((nargs != 1) || (nret != 1)) { @@ -192,7 +192,7 @@ static void rtas_int_on(PowerPCCPU *cpu, sPAPRMachineState *spapr, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) { - ICSState *ics = spapr->icp->ics; + ICSState *ics = spapr->xics->ics; uint32_t nr; if ((nargs != 1) || (nret != 1)) { @@ -214,36 +214,36 @@ static void rtas_int_on(PowerPCCPU *cpu, sPAPRMachineState *spapr, rtas_st(rets, 0, RTAS_OUT_SUCCESS); } -static void xics_spapr_set_nr_irqs(XICSState *icp, uint32_t nr_irqs, +static void xics_spapr_set_nr_irqs(XICSState *xics, uint32_t nr_irqs, Error **errp) { - icp->nr_irqs = icp->ics->nr_irqs = nr_irqs; + xics->nr_irqs = xics->ics->nr_irqs = nr_irqs; } -static void xics_spapr_set_nr_servers(XICSState *icp, uint32_t nr_servers, +static void xics_spapr_set_nr_servers(XICSState *xics, uint32_t nr_servers, Error **errp) { int i; - icp->nr_servers = nr_servers; + xics->nr_servers = nr_servers; - icp->ss = g_malloc0(icp->nr_servers * sizeof(ICPState)); - for (i = 0; i < icp->nr_servers; i++) { + xics->ss = g_malloc0(xics->nr_servers * sizeof(ICPState)); + for (i = 0; i < xics->nr_servers; i++) { char buffer[32]; - object_initialize(&icp->ss[i], sizeof(icp->ss[i]), TYPE_ICP); + object_initialize(&xics->ss[i], sizeof(xics->ss[i]), TYPE_ICP); snprintf(buffer, sizeof(buffer), "icp[%d]", i); - object_property_add_child(OBJECT(icp), buffer, OBJECT(&icp->ss[i]), + object_property_add_child(OBJECT(xics), buffer, OBJECT(&xics->ss[i]), errp); } } static void xics_spapr_realize(DeviceState *dev, Error **errp) { - XICSState *icp = XICS_SPAPR(dev); + XICSState *xics = XICS_SPAPR(dev); Error *error = NULL; int i; - if (!icp->nr_servers) { + if (!xics->nr_servers) { error_setg(errp, "Number of servers needs to be greater 0"); return; } @@ -261,14 +261,15 @@ static void xics_spapr_realize(DeviceState *dev, Error **errp) spapr_register_hypercall(H_EOI, h_eoi); spapr_register_hypercall(H_IPOLL, h_ipoll); - object_property_set_bool(OBJECT(icp->ics), true, "realized", &error); + object_property_set_bool(OBJECT(xics->ics), true, "realized", &error); if (error) { error_propagate(errp, error); return; } - for (i = 0; i < icp->nr_servers; i++) { - object_property_set_bool(OBJECT(&icp->ss[i]), true, "realized", &error); + for (i = 0; i < xics->nr_servers; i++) { + object_property_set_bool(OBJECT(&xics->ss[i]), true, "realized", + &error); if (error) { error_propagate(errp, error); return; @@ -282,7 +283,7 @@ static void xics_spapr_initfn(Object *obj) xics->ics = ICS(object_new(TYPE_ICS)); object_property_add_child(obj, "ics", OBJECT(xics->ics), NULL); - xics->ics->icp = xics; + xics->ics->xics = xics; } static void xics_spapr_class_init(ObjectClass *oc, void *data) @@ -328,14 +329,14 @@ static int ics_find_free_block(ICSState *ics, int num, int alignnum) return -1; } -int xics_spapr_alloc(XICSState *icp, int src, int irq_hint, bool lsi, +int xics_spapr_alloc(XICSState *xics, int src, int irq_hint, bool lsi, Error **errp) { - ICSState *ics = &icp->ics[src]; + ICSState *ics = &xics->ics[src]; int irq; if (irq_hint) { - assert(src == xics_find_source(icp, irq_hint)); + assert(src == xics_find_source(xics, irq_hint)); if (!ICS_IRQ_FREE(ics, irq_hint - ics->offset)) { error_setg(errp, "can't allocate IRQ %d: already in use", irq_hint); return -1; @@ -360,11 +361,11 @@ int xics_spapr_alloc(XICSState *icp, int src, int irq_hint, bool lsi, * Allocate block of consecutive IRQs, and return the number of the first IRQ in * the block. If align==true, aligns the first IRQ number to num. */ -int xics_spapr_alloc_block(XICSState *icp, int src, int num, bool lsi, +int xics_spapr_alloc_block(XICSState *xics, int src, int num, bool lsi, bool align, Error **errp) { int i, first = -1; - ICSState *ics = &icp->ics[src]; + ICSState *ics = &xics->ics[src]; assert(src == 0); /* @@ -404,23 +405,23 @@ static void ics_free(ICSState *ics, int srcno, int num) for (i = srcno; i < srcno + num; ++i) { if (ICS_IRQ_FREE(ics, i)) { - trace_xics_ics_free_warn(ics - ics->icp->ics, i + ics->offset); + trace_xics_ics_free_warn(ics - ics->xics->ics, i + ics->offset); } memset(&ics->irqs[i], 0, sizeof(ICSIRQState)); } } -void xics_spapr_free(XICSState *icp, int irq, int num) +void xics_spapr_free(XICSState *xics, int irq, int num) { - int src = xics_find_source(icp, irq); + int src = xics_find_source(xics, irq); if (src >= 0) { - ICSState *ics = &icp->ics[src]; + ICSState *ics = &xics->ics[src]; /* FIXME: implement multiple sources */ assert(src == 0); - trace_xics_ics_free(ics - icp->ics, irq, num); + trace_xics_ics_free(ics - xics->ics, irq, num); ics_free(ics, irq - ics->offset, num); } } diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 3f0ea03..78ebd9e 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -116,16 +116,16 @@ static XICSState *try_create_xics(const char *type, int nr_servers, static XICSState *xics_system_init(MachineState *machine, int nr_servers, int nr_irqs, Error **errp) { - XICSState *icp = NULL; + XICSState *xics = NULL; if (kvm_enabled()) { Error *err = NULL; if (machine_kernel_irqchip_allowed(machine)) { - icp = try_create_xics(TYPE_XICS_SPAPR_KVM, nr_servers, nr_irqs, - &err); + xics = try_create_xics(TYPE_XICS_SPAPR_KVM, nr_servers, nr_irqs, + &err); } - if (machine_kernel_irqchip_required(machine) && !icp) { + if (machine_kernel_irqchip_required(machine) && !xics) { error_reportf_err(err, "kernel_irqchip requested but unavailable: "); } else { @@ -133,11 +133,11 @@ static XICSState *xics_system_init(MachineState *machine, } } - if (!icp) { - icp = try_create_xics(TYPE_XICS_SPAPR, nr_servers, nr_irqs, errp); + if (!xics) { + xics = try_create_xics(TYPE_XICS_SPAPR, nr_servers, nr_irqs, errp); } - return icp; + return xics; } static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu, @@ -1783,9 +1783,9 @@ static void ppc_spapr_init(MachineState *machine) load_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FW_OVERHEAD; /* Set up Interrupt Controller before we create the VCPUs */ - spapr->icp = xics_system_init(machine, - DIV_ROUND_UP(max_cpus * smt, smp_threads), - XICS_IRQS_SPAPR, &error_fatal); + spapr->xics = xics_system_init(machine, + DIV_ROUND_UP(max_cpus * smt, smp_threads), + XICS_IRQS_SPAPR, &error_fatal); if (smc->dr_lmb_enabled) { spapr_validate_node_memory(machine, &error_fatal); diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index cebeef5..2aa0dc5 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -42,7 +42,7 @@ static void spapr_cpu_destroy(PowerPCCPU *cpu) { sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); - xics_cpu_destroy(spapr->icp, cpu); + xics_cpu_destroy(spapr->xics, cpu); qemu_unregister_reset(spapr_cpu_reset, cpu); } @@ -76,7 +76,7 @@ void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, Error **errp) } } - xics_cpu_setup(spapr->icp, cpu); + xics_cpu_setup(spapr->xics, cpu); qemu_register_reset(spapr_cpu_reset, cpu); spapr_cpu_reset(cpu); diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c index 0585f8a..b0668b3 100644 --- a/hw/ppc/spapr_events.c +++ b/hw/ppc/spapr_events.c @@ -386,7 +386,7 @@ static void spapr_powerdown_req(Notifier *n, void *opaque) rtas_event_log_queue(RTAS_LOG_TYPE_EPOW, new_epow, true); - qemu_irq_pulse(xics_get_qirq(spapr->icp, spapr->check_exception_irq)); + qemu_irq_pulse(xics_get_qirq(spapr->xics, spapr->check_exception_irq)); } static void spapr_hotplug_set_signalled(uint32_t drc_index) @@ -468,7 +468,7 @@ static void spapr_hotplug_req_event(uint8_t hp_id, uint8_t hp_action, rtas_event_log_queue(RTAS_LOG_TYPE_HOTPLUG, new_hp, true); - qemu_irq_pulse(xics_get_qirq(spapr->icp, spapr->check_exception_irq)); + qemu_irq_pulse(xics_get_qirq(spapr->xics, spapr->check_exception_irq)); } void spapr_hotplug_req_add_by_index(sPAPRDRConnector *drc) @@ -551,7 +551,7 @@ static void check_exception(PowerPCCPU *cpu, sPAPRMachineState *spapr, * interrupts. */ if (rtas_event_log_contains(mask, true)) { - qemu_irq_pulse(xics_get_qirq(spapr->icp, spapr->check_exception_irq)); + qemu_irq_pulse(xics_get_qirq(spapr->xics, spapr->check_exception_irq)); } return; @@ -603,7 +603,7 @@ out_no_events: void spapr_events_init(sPAPRMachineState *spapr) { QTAILQ_INIT(&spapr->pending_events); - spapr->check_exception_irq = xics_spapr_alloc(spapr->icp, 0, 0, false, + spapr->check_exception_irq = xics_spapr_alloc(spapr->xics, 0, 0, false, &error_fatal); spapr->epow_notifier.notify = spapr_powerdown_req; qemu_register_powerdown_notifier(&spapr->epow_notifier); diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 451651d..8c1e6b1 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -322,7 +322,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr, return; } - xics_spapr_free(spapr->icp, msi->first_irq, msi->num); + xics_spapr_free(spapr->xics, msi->first_irq, msi->num); if (msi_present(pdev)) { spapr_msi_setmsg(pdev, 0, false, 0, 0); } @@ -360,7 +360,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr, } /* Allocate MSIs */ - irq = xics_spapr_alloc_block(spapr->icp, 0, req_num, false, + irq = xics_spapr_alloc_block(spapr->xics, 0, req_num, false, ret_intr_type == RTAS_TYPE_MSI, &err); if (err) { error_reportf_err(err, "Can't allocate MSIs for device %x: ", @@ -371,7 +371,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr, /* Release previous MSIs */ if (msi) { - xics_spapr_free(spapr->icp, msi->first_irq, msi->num); + xics_spapr_free(spapr->xics, msi->first_irq, msi->num); g_hash_table_remove(phb->msi, &config_addr); } @@ -733,7 +733,7 @@ static void spapr_msi_write(void *opaque, hwaddr addr, trace_spapr_pci_msi_write(addr, data, irq); - qemu_irq_pulse(xics_get_qirq(spapr->icp, irq)); + qemu_irq_pulse(xics_get_qirq(spapr->xics, irq)); } static const MemoryRegionOps spapr_msi_ops = { @@ -1442,7 +1442,8 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) uint32_t irq; Error *local_err = NULL; - irq = xics_spapr_alloc_block(spapr->icp, 0, 1, true, false, &local_err); + irq = xics_spapr_alloc_block(spapr->xics, 0, 1, true, false, + &local_err); if (local_err) { error_propagate(errp, local_err); error_prepend(errp, "can't allocate LSIs: "); diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c index 7ffd23e..f93244d 100644 --- a/hw/ppc/spapr_vio.c +++ b/hw/ppc/spapr_vio.c @@ -463,7 +463,7 @@ static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp) dev->qdev.id = id; } - dev->irq = xics_spapr_alloc(spapr->icp, 0, dev->irq, false, &local_err); + dev->irq = xics_spapr_alloc(spapr->xics, 0, dev->irq, false, &local_err); if (local_err) { error_propagate(errp, local_err); return; -- cgit v1.1 From 470f2157877d49034d2ae0e755fbd4d059def164 Mon Sep 17 00:00:00 2001 From: Bharata B Rao Date: Wed, 29 Jun 2016 17:07:26 +0530 Subject: spapr: Restore support for 970MP and POWER8NVL CPU cores Introduction of core based CPU hotplug for PowerPC sPAPR didn't add support for 970MP and POWER8NVL based core types. Add support for the same. While we are here, add support for explicit specification of POWER5+_v2.1 core type. Signed-off-by: Bharata B Rao Signed-off-by: David Gibson --- hw/ppc/spapr_cpu_core.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'hw') diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index 2aa0dc5..e30b159 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -337,12 +337,15 @@ static void glue(glue(spapr_cpu_core_, _fname), _initfn(Object *obj)) \ core->cpu_class = oc; \ } +SPAPR_CPU_CORE_INITFN(970mp_v1.0, 970MP_v10); +SPAPR_CPU_CORE_INITFN(970mp_v1.1, 970MP_v11); SPAPR_CPU_CORE_INITFN(970_v2.2, 970); SPAPR_CPU_CORE_INITFN(POWER5+_v2.1, POWER5plus); SPAPR_CPU_CORE_INITFN(POWER7_v2.3, POWER7); SPAPR_CPU_CORE_INITFN(POWER7+_v2.1, POWER7plus); SPAPR_CPU_CORE_INITFN(POWER8_v2.0, POWER8); SPAPR_CPU_CORE_INITFN(POWER8E_v2.1, POWER8E); +SPAPR_CPU_CORE_INITFN(POWER8NVL_v1.0, POWER8NVL); typedef struct SPAPRCoreInfo { const char *name; @@ -350,10 +353,19 @@ typedef struct SPAPRCoreInfo { } SPAPRCoreInfo; static const SPAPRCoreInfo spapr_cores[] = { - /* 970 */ + /* 970 and aliaes */ + { .name = "970_v2.2", .initfn = spapr_cpu_core_970_initfn }, { .name = "970", .initfn = spapr_cpu_core_970_initfn }, - /* POWER5 */ + /* 970MP variants and aliases */ + { .name = "970MP_v1.0", .initfn = spapr_cpu_core_970MP_v10_initfn }, + { .name = "970mp_v1.0", .initfn = spapr_cpu_core_970MP_v10_initfn }, + { .name = "970MP_v1.1", .initfn = spapr_cpu_core_970MP_v11_initfn }, + { .name = "970mp_v1.1", .initfn = spapr_cpu_core_970MP_v11_initfn }, + { .name = "970mp", .initfn = spapr_cpu_core_970MP_v11_initfn }, + + /* POWER5 and aliases */ + { .name = "POWER5+_v2.1", .initfn = spapr_cpu_core_POWER5plus_initfn }, { .name = "POWER5+", .initfn = spapr_cpu_core_POWER5plus_initfn }, /* POWER7 and aliases */ @@ -373,6 +385,10 @@ static const SPAPRCoreInfo spapr_cores[] = { { .name = "POWER8E_v2.1", .initfn = spapr_cpu_core_POWER8E_initfn }, { .name = "POWER8E", .initfn = spapr_cpu_core_POWER8E_initfn }, + /* POWER8NVL and aliases */ + { .name = "POWER8NVL_v1.0", .initfn = spapr_cpu_core_POWER8NVL_initfn }, + { .name = "POWER8NVL", .initfn = spapr_cpu_core_POWER8NVL_initfn }, + { .name = NULL } }; -- cgit v1.1 From 8e758dee663bfda2ccfe0076914bf49108055386 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Wed, 29 Jun 2016 22:50:20 +0200 Subject: spapr: drop reference on child object during core realization When a core is being realized, we create a child object for each thread of the core. The child is first initialized with object_initialize() which sets its ref count to 1, and then added to the core with object_property_add_child() which bumps the ref count to 2. When the core gets released, object_unparent() decreases the ref count to 1, and we g_free() the object: we hence loose the reference on an unfinalized object. This is likely to cause random crashes. Let's drop the extra reference as soon as we don't need it, after the thread is added to the core. Signed-off-by: Greg Kurz Reviewed-by: Bharata B Rao Signed-off-by: David Gibson --- hw/ppc/spapr_cpu_core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'hw') diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index e30b159..bba3612 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -300,6 +300,7 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp) if (local_err) { goto err; } + object_unref(obj); } object_child_foreach(OBJECT(dev), spapr_cpu_core_realize_child, &local_err); if (local_err) { -- cgit v1.1 From f11235b92065e06e789ee1b523dd71999bc6b3e6 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Wed, 29 Jun 2016 22:50:32 +0200 Subject: spapr: do proper error propagation in spapr_cpu_core_realize_child() This patch changes spapr_cpu_core_realize_child() to have a local error pointer and use error_propagate() as it is supposed to be done. Signed-off-by: Greg Kurz Reviewed-by: Bharata B Rao Signed-off-by: David Gibson --- hw/ppc/spapr_cpu_core.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'hw') diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index bba3612..2e264fa 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -262,18 +262,20 @@ out: static int spapr_cpu_core_realize_child(Object *child, void *opaque) { - Error **errp = opaque; + Error **errp = opaque, *local_err = NULL; sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); CPUState *cs = CPU(child); PowerPCCPU *cpu = POWERPC_CPU(cs); - object_property_set_bool(child, true, "realized", errp); - if (*errp) { + object_property_set_bool(child, true, "realized", &local_err); + if (local_err) { + error_propagate(errp, local_err); return 1; } - spapr_cpu_init(spapr, cpu, errp); - if (*errp) { + spapr_cpu_init(spapr, cpu, &local_err); + if (local_err) { + error_propagate(errp, local_err); return 1; } return 0; -- cgit v1.1 From 8a1eb71bd8cf46a0fd163bc8805a3e86762ea798 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Wed, 29 Jun 2016 22:50:45 +0200 Subject: spapr: drop duplicate variable in spapr_core_release() Signed-off-by: Greg Kurz Reviewed-by: Bharata B Rao Signed-off-by: David Gibson --- hw/ppc/spapr_cpu_core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'hw') diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index 2e264fa..a384db5 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -102,7 +102,6 @@ static void spapr_core_release(DeviceState *dev, void *opaque) const char *typename = object_class_get_name(sc->cpu_class); size_t size = object_type_get_instance_size(typename); sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); - sPAPRCPUCore *core = SPAPR_CPU_CORE(OBJECT(dev)); CPUCore *cc = CPU_CORE(dev); int smt = kvmppc_smt_threads(); int i; @@ -120,7 +119,7 @@ static void spapr_core_release(DeviceState *dev, void *opaque) spapr->cores[cc->core_id / smt] = NULL; - g_free(core->threads); + g_free(sc->threads); object_unparent(OBJECT(dev)); } -- cgit v1.1