From 58c46efa451caa3935224223f950216872e2eee3 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Fri, 30 Aug 2019 18:13:45 +0200 Subject: [PATCH 01/53] pseries: do not allow memory-less/cpu-less NUMA node When we hotplug a CPU on memory-less/cpu-less node, the linux kernel crashes. This happens because linux kernel needs to know the NUMA topology at start to be able to initialize the distance lookup table. On pseries, the topology is provided by the firmware via the existing CPUs and memory information. Thus a node without memory and CPU cannot be discovered by the kernel. To avoid the kernel crash, do not allow to start pseries with empty nodes. Signed-off-by: Laurent Vivier Message-Id: <20190830161345.22436-1-lvivier@redhat.com> [dwg: Rework to cope with movement of numa state from globals to MachineState] Signed-off-by: David Gibson --- hw/ppc/spapr.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 08a2a5a770..f976d76eca 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -2854,6 +2854,39 @@ static void spapr_machine_init(MachineState *machine) /* init CPUs */ spapr_init_cpus(spapr); + /* + * check we don't have a memory-less/cpu-less NUMA node + * Firmware relies on the existing memory/cpu topology to provide the + * NUMA topology to the kernel. + * And the linux kernel needs to know the NUMA topology at start + * to be able to hotplug CPUs later. + */ + if (machine->numa_state->num_nodes) { + for (i = 0; i < machine->numa_state->num_nodes; ++i) { + /* check for memory-less node */ + if (machine->numa_state->nodes[i].node_mem == 0) { + CPUState *cs; + int found = 0; + /* check for cpu-less node */ + CPU_FOREACH(cs) { + PowerPCCPU *cpu = POWERPC_CPU(cs); + if (cpu->node_id == i) { + found = 1; + break; + } + } + /* memory-less and cpu-less node */ + if (!found) { + error_report( + "Memory-less/cpu-less nodes are not supported (node %d)", + i); + exit(1); + } + } + } + + } + if ((!kvm_enabled() || kvmppc_has_cap_mmu_radix()) && ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, 0, spapr->max_compat_pvr)) { From f42b6f535c290046d10aebf1796fb46957dfa8e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 2 Sep 2019 11:29:32 +0200 Subject: [PATCH 02/53] ppc/pnv: fix "bmc" node name in DT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the dtc output : ERROR (node_name_chars): //bmc: Bad character '/' in node name Warning (avoid_unnecessary_addr_size): /bmc: unnecessary #address-cells/#size-cells without "ranges" or child "reg" property Signed-off-by: Cédric Le Goater Message-Id: <20190902092932.20200-1-clg@kaod.org> Signed-off-by: David Gibson --- hw/ppc/pnv_bmc.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/hw/ppc/pnv_bmc.c b/hw/ppc/pnv_bmc.c index e5eb6e5a70..dc5e918cb7 100644 --- a/hw/ppc/pnv_bmc.c +++ b/hw/ppc/pnv_bmc.c @@ -77,13 +77,10 @@ void pnv_dt_bmc_sensors(IPMIBmc *bmc, void *fdt) const struct ipmi_sdr_compact *sdr; uint16_t nextrec; - offset = fdt_add_subnode(fdt, 0, "/bmc"); + offset = fdt_add_subnode(fdt, 0, "bmc"); _FDT(offset); _FDT((fdt_setprop_string(fdt, offset, "name", "bmc"))); - _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 0x1))); - _FDT((fdt_setprop_cell(fdt, offset, "#size-cells", 0x0))); - offset = fdt_add_subnode(fdt, offset, "sensors"); _FDT(offset); From 226c9d15df0a9c9e94fc30c373cdefbc4156d8dd Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 9 Sep 2019 20:10:09 +0200 Subject: [PATCH 03/53] spapr-tpm-proxy: Drop misleading check Coverity is reporting in CID 1405304 that tpm_execute() may pass a NULL tpm_proxy->host_path pointer to open(). This is based on the fact that h_tpm_comm() does a NULL check on tpm_proxy->host_path and then passes tpm_proxy to tpm_execute(). The check in h_tpm_comm() is abusive actually since a spapr-proxy-tpm requires a non NULL host_path property, as checked during realize. Fixes: 0fb6bd073230 Signed-off-by: Greg Kurz Message-Id: <156805260916.1779401.11054185183758185247.stgit@bahia.lan> Reviewed-by: Michael Roth Signed-off-by: David Gibson --- hw/ppc/spapr_tpm_proxy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ppc/spapr_tpm_proxy.c b/hw/ppc/spapr_tpm_proxy.c index b835d25be6..ca1caec113 100644 --- a/hw/ppc/spapr_tpm_proxy.c +++ b/hw/ppc/spapr_tpm_proxy.c @@ -114,7 +114,7 @@ static target_ulong h_tpm_comm(PowerPCCPU *cpu, return H_FUNCTION; } - trace_spapr_h_tpm_comm(tpm_proxy->host_path ?: "null", op); + trace_spapr_h_tpm_comm(tpm_proxy->host_path, op); switch (op) { case TPM_COMM_OP_EXECUTE: From 59b7c1c283508ad5aa1c4064b17f8d368664029c Mon Sep 17 00:00:00 2001 From: Balamuruhan S Date: Wed, 11 Sep 2019 19:59:25 +0530 Subject: [PATCH 04/53] hw/ppc/pnv: fix checkpatch.pl coding style warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There were few trailing comments after `/*` instead in new line and line more than 80 character, these fixes are trivial and doesn't change any logic in code. Signed-off-by: Balamuruhan S Message-Id: <20190911142925.19197-5-bala24@linux.ibm.com> Reviewed-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/ppc/pnv.c | 49 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 3f08db7b9e..13126d675e 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -187,7 +187,8 @@ static void pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt) _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq))); _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq))); - _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", cpu->hash64_opts->slb_size))); + _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", + cpu->hash64_opts->slb_size))); _FDT((fdt_setprop_string(fdt, offset, "status", "okay"))); _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0))); @@ -200,19 +201,23 @@ static void pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt) segs, sizeof(segs)))); } - /* Advertise VMX/VSX (vector extensions) if available + /* + * Advertise VMX/VSX (vector extensions) if available * 0 / no property == no vector extensions * 1 == VMX / Altivec available - * 2 == VSX available */ + * 2 == VSX available + */ if (env->insns_flags & PPC_ALTIVEC) { uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1; _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx))); } - /* Advertise DFP (Decimal Floating Point) if available + /* + * Advertise DFP (Decimal Floating Point) if available * 0 / no property == no DFP - * 1 == DFP available */ + * 1 == DFP available + */ if (env->insns_flags2 & PPC2_DFP) { _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1))); } @@ -424,7 +429,8 @@ static int pnv_dt_isa_device(DeviceState *dev, void *opaque) return 0; } -/* The default LPC bus of a multichip system is on chip 0. It's +/* + * The default LPC bus of a multichip system is on chip 0. It's * recognized by the firmware (skiboot) using a "primary" property. */ static void pnv_dt_isa(PnvMachineState *pnv, void *fdt) @@ -442,8 +448,10 @@ static void pnv_dt_isa(PnvMachineState *pnv, void *fdt) assert(phandle > 0); _FDT((fdt_setprop_cell(fdt, isa_offset, "phandle", phandle))); - /* ISA devices are not necessarily parented to the ISA bus so we - * can not use object_child_foreach() */ + /* + * ISA devices are not necessarily parented to the ISA bus so we + * can not use object_child_foreach() + */ qbus_walk_children(BUS(pnv->isa_bus), pnv_dt_isa_device, NULL, NULL, NULL, &args); } @@ -545,7 +553,8 @@ static void pnv_reset(MachineState *machine) qemu_devices_reset(); - /* OpenPOWER systems have a BMC, which can be defined on the + /* + * OpenPOWER systems have a BMC, which can be defined on the * command line with: * * -device ipmi-bmc-sim,id=bmc0 @@ -705,7 +714,8 @@ static void pnv_init(MachineState *machine) pnv->chips[i] = PNV_CHIP(chip); - /* TODO: put all the memory in one node on chip 0 until we find a + /* + * TODO: put all the memory in one node on chip 0 until we find a * way to specify different ranges for each chip */ if (i == 0) { @@ -732,8 +742,10 @@ static void pnv_init(MachineState *machine) /* Create an RTC ISA device too */ mc146818_rtc_init(pnv->isa_bus, 2000, NULL); - /* OpenPOWER systems use a IPMI SEL Event message to notify the - * host to powerdown */ + /* + * OpenPOWER systems use a IPMI SEL Event message to notify the + * host to powerdown + */ pnv->powerdown_notifier.notify = pnv_powerdown_notify; qemu_register_powerdown_notifier(&pnv->powerdown_notifier); } @@ -803,7 +815,8 @@ static void pnv_chip_power9_intc_create(PnvChip *chip, PowerPCCPU *cpu, pnv_cpu->intc = obj; } -/* Allowed core identifiers on a POWER8 Processor Chip : +/* + * Allowed core identifiers on a POWER8 Processor Chip : * * * EX1 - Venice only @@ -923,8 +936,10 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) (uint64_t) PNV_XSCOM_BASE(chip), PNV_XSCOM_LPC_BASE); - /* Interrupt Management Area. This is the memory region holding - * all the Interrupt Control Presenter (ICP) registers */ + /* + * Interrupt Management Area. This is the memory region holding + * all the Interrupt Control Presenter (ICP) registers + */ pnv_chip_icp_realize(chip8, &local_err); if (local_err) { error_propagate(errp, local_err); @@ -1404,8 +1419,8 @@ static void pnv_machine_class_init(ObjectClass *oc, void *data) mc->init = pnv_init; mc->reset = pnv_reset; mc->max_cpus = MAX_CPUS; - mc->block_default_type = IF_IDE; /* Pnv provides a AHCI device for - * storage */ + /* Pnv provides a AHCI device for storage */ + mc->block_default_type = IF_IDE; mc->no_parallel = 1; mc->default_boot_order = NULL; /* From f041d6af55708a75851bfc4ef1373a565703f976 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Thu, 12 Sep 2019 16:30:09 +0200 Subject: [PATCH 05/53] spapr: Report kvm_irqchip_in_kernel() in 'info pic' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unless the machine was started with kernel-irqchip=on, we cannot easily tell if we're actually using an in-kernel or an emulated irqchip. This information is important enough that it is worth printing it in 'info pic'. Signed-off-by: Greg Kurz Message-Id: <156829860985.2073005.5893493824873412773.stgit@bahia.tls.ibm.com> Reviewed-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/ppc/spapr.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index f976d76eca..2725b139a7 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -81,6 +81,8 @@ #include "hw/mem/memory-device.h" #include "hw/ppc/spapr_tpm_proxy.h" +#include "monitor/monitor.h" + #include /* SLOF memory layout: @@ -4354,6 +4356,8 @@ static void spapr_pic_print_info(InterruptStatsProvider *obj, SpaprMachineState *spapr = SPAPR_MACHINE(obj); spapr->irq->print_info(spapr, mon); + monitor_printf(mon, "irqchip: %s\n", + kvm_irqchip_in_kernel() ? "in-kernel" : "emulated"); } int spapr_get_vcpu_id(PowerPCCPU *cpu) From 7454558c69b4fa4a9bb26d601b26330319b85f89 Mon Sep 17 00:00:00 2001 From: Balamuruhan S Date: Thu, 12 Sep 2019 15:00:52 +0530 Subject: [PATCH 06/53] hw/ppc/pnv_xscom: retrieve homer/occ base address from PBA BARs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit During PowerNV boot skiboot populates the device tree by retrieving base address of homer/occ common area from PBA BARs and prd ipoll mask by accessing xscom read/write accesses. Reviewed-by: Cédric Le Goater Signed-off-by: Balamuruhan S Message-Id: <20190912093056.4516-2-bala24@linux.ibm.com> Signed-off-by: David Gibson --- hw/ppc/pnv_xscom.c | 34 ++++++++++++++++++++++++++++++---- include/hw/ppc/pnv.h | 18 ++++++++++++++++++ 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/hw/ppc/pnv_xscom.c b/hw/ppc/pnv_xscom.c index 67aab98fef..f01d788a65 100644 --- a/hw/ppc/pnv_xscom.c +++ b/hw/ppc/pnv_xscom.c @@ -36,6 +36,16 @@ #define PRD_P9_IPOLL_REG_MASK 0x000F0033 #define PRD_P9_IPOLL_REG_STATUS 0x000F0034 +/* PBA BARs */ +#define P8_PBA_BAR0 0x2013f00 +#define P8_PBA_BAR2 0x2013f02 +#define P8_PBA_BARMASK0 0x2013f04 +#define P8_PBA_BARMASK2 0x2013f06 +#define P9_PBA_BAR0 0x5012b00 +#define P9_PBA_BAR2 0x5012b02 +#define P9_PBA_BARMASK0 0x5012b04 +#define P9_PBA_BARMASK2 0x5012b06 + static void xscom_complete(CPUState *cs, uint64_t hmer_bits) { /* @@ -74,6 +84,26 @@ static uint64_t xscom_read_default(PnvChip *chip, uint32_t pcba) case 0x18002: /* ECID2 */ return 0; + case P9_PBA_BAR0: + return PNV9_HOMER_BASE(chip); + case P8_PBA_BAR0: + return PNV_HOMER_BASE(chip); + + case P9_PBA_BARMASK0: /* P9 homer region size */ + return PNV9_HOMER_SIZE; + case P8_PBA_BARMASK0: /* P8 homer region size */ + return PNV_HOMER_SIZE; + + case P9_PBA_BAR2: /* P9 occ common area */ + return PNV9_OCC_COMMON_AREA(chip); + case P8_PBA_BAR2: /* P8 occ common area */ + return PNV_OCC_COMMON_AREA(chip); + + case P9_PBA_BARMASK2: /* P9 occ common area size */ + return PNV9_OCC_COMMON_AREA_SIZE; + case P8_PBA_BARMASK2: /* P8 occ common area size */ + return PNV_OCC_COMMON_AREA_SIZE; + case 0x1010c00: /* PIBAM FIR */ case 0x1010c03: /* PIBAM FIR MASK */ @@ -93,13 +123,9 @@ static uint64_t xscom_read_default(PnvChip *chip, uint32_t pcba) case 0x2020009: /* ADU stuff, error register */ case 0x202000f: /* ADU stuff, receive status register*/ return 0; - case 0x2013f00: /* PBA stuff */ case 0x2013f01: /* PBA stuff */ - case 0x2013f02: /* PBA stuff */ case 0x2013f03: /* PBA stuff */ - case 0x2013f04: /* PBA stuff */ case 0x2013f05: /* PBA stuff */ - case 0x2013f06: /* PBA stuff */ case 0x2013f07: /* PBA stuff */ return 0; case 0x2013028: /* CAPP stuff */ diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h index fb123edc4e..63a4b7b6a7 100644 --- a/include/hw/ppc/pnv.h +++ b/include/hw/ppc/pnv.h @@ -198,6 +198,16 @@ void pnv_bmc_powerdown(IPMIBmc *bmc); #define PNV_XSCOM_BASE(chip) \ (0x0003fc0000000000ull + ((uint64_t)(chip)->chip_id) * PNV_XSCOM_SIZE) +#define PNV_OCC_COMMON_AREA_SIZE 0x0000000000700000ull +#define PNV_OCC_COMMON_AREA(chip) \ + (0x7fff800000ull + ((uint64_t)PNV_CHIP_INDEX(chip) * \ + PNV_OCC_COMMON_AREA_SIZE)) + +#define PNV_HOMER_SIZE 0x0000000000300000ull +#define PNV_HOMER_BASE(chip) \ + (0x7ffd800000ull + ((uint64_t)PNV_CHIP_INDEX(chip)) * PNV_HOMER_SIZE) + + /* * XSCOM 0x20109CA defines the ICP BAR: * @@ -256,4 +266,12 @@ void pnv_bmc_powerdown(IPMIBmc *bmc); #define PNV9_XSCOM_SIZE 0x0000000400000000ull #define PNV9_XSCOM_BASE(chip) PNV9_CHIP_BASE(chip, 0x00603fc00000000ull) +#define PNV9_OCC_COMMON_AREA_SIZE 0x0000000000700000ull +#define PNV9_OCC_COMMON_AREA(chip) \ + (0x203fff800000ull + ((uint64_t)PNV_CHIP_INDEX(chip) * \ + PNV9_OCC_COMMON_AREA_SIZE)) + +#define PNV9_HOMER_SIZE 0x0000000000300000ull +#define PNV9_HOMER_BASE(chip) \ + (0x203ffd800000ull + ((uint64_t)PNV_CHIP_INDEX(chip)) * PNV9_HOMER_SIZE) #endif /* PPC_PNV_H */ From f3db82660d22def1ffaa122f3952b560ac386147 Mon Sep 17 00:00:00 2001 From: Balamuruhan S Date: Thu, 12 Sep 2019 15:00:53 +0530 Subject: [PATCH 07/53] hw/ppc/pnv_occ: add sram device model for occ common area MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit emulate occ common area region with occ sram device model which occ and skiboot uses it to communicate regarding sensors, slw and HWMON in PowerNV emulated host. Reviewed-by: Cédric Le Goater Signed-off-by: Balamuruhan S Message-Id: <20190912093056.4516-3-bala24@linux.ibm.com> Signed-off-by: David Gibson --- hw/ppc/pnv.c | 8 +++++ hw/ppc/pnv_occ.c | 78 ++++++++++++++++++++++++++++++++++++++++ include/hw/ppc/pnv_occ.h | 3 ++ 3 files changed, 89 insertions(+) diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 13126d675e..09d2d7c026 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -953,6 +953,10 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) return; } pnv_xscom_add_subregion(chip, PNV_XSCOM_OCC_BASE, &chip8->occ.xscom_regs); + + /* OCC SRAM model */ + memory_region_add_subregion(get_system_memory(), PNV_OCC_COMMON_AREA(chip), + &chip8->occ.sram_regs); } static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data) @@ -1141,6 +1145,10 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) return; } pnv_xscom_add_subregion(chip, PNV9_XSCOM_OCC_BASE, &chip9->occ.xscom_regs); + + /* OCC SRAM model */ + memory_region_add_subregion(get_system_memory(), PNV9_OCC_COMMON_AREA(chip), + &chip9->occ.sram_regs); } static void pnv_chip_power9_class_init(ObjectClass *klass, void *data) diff --git a/hw/ppc/pnv_occ.c b/hw/ppc/pnv_occ.c index 8bead2c930..785653bb67 100644 --- a/hw/ppc/pnv_occ.c +++ b/hw/ppc/pnv_occ.c @@ -30,6 +30,24 @@ #define OCB_OCI_OCCMISC_AND 0x4021 #define OCB_OCI_OCCMISC_OR 0x4022 +/* OCC sensors */ +#define OCC_SENSOR_DATA_BLOCK_OFFSET 0x580000 +#define OCC_SENSOR_DATA_VALID 0x580001 +#define OCC_SENSOR_DATA_VERSION 0x580002 +#define OCC_SENSOR_DATA_READING_VERSION 0x580004 +#define OCC_SENSOR_DATA_NR_SENSORS 0x580008 +#define OCC_SENSOR_DATA_NAMES_OFFSET 0x580010 +#define OCC_SENSOR_DATA_READING_PING_OFFSET 0x580014 +#define OCC_SENSOR_DATA_READING_PONG_OFFSET 0x58000c +#define OCC_SENSOR_DATA_NAME_LENGTH 0x58000d +#define OCC_SENSOR_NAME_STRUCTURE_TYPE 0x580023 +#define OCC_SENSOR_LOC_CORE 0x580022 +#define OCC_SENSOR_LOC_GPU 0x580020 +#define OCC_SENSOR_TYPE_POWER 0x580003 +#define OCC_SENSOR_NAME 0x580005 +#define HWMON_SENSORS_MASK 0x58001e +#define SLW_IMAGE_BASE 0x0 + static void pnv_occ_set_misc(PnvOCC *occ, uint64_t val) { bool irq_state; @@ -82,6 +100,48 @@ static void pnv_occ_power8_xscom_write(void *opaque, hwaddr addr, } } +static uint64_t pnv_occ_common_area_read(void *opaque, hwaddr addr, + unsigned width) +{ + switch (addr) { + /* + * occ-sensor sanity check that asserts the sensor + * header block + */ + case OCC_SENSOR_DATA_BLOCK_OFFSET: + case OCC_SENSOR_DATA_VALID: + case OCC_SENSOR_DATA_VERSION: + case OCC_SENSOR_DATA_READING_VERSION: + case OCC_SENSOR_DATA_NR_SENSORS: + case OCC_SENSOR_DATA_NAMES_OFFSET: + case OCC_SENSOR_DATA_READING_PING_OFFSET: + case OCC_SENSOR_DATA_READING_PONG_OFFSET: + case OCC_SENSOR_NAME_STRUCTURE_TYPE: + return 1; + case OCC_SENSOR_DATA_NAME_LENGTH: + return 0x30; + case OCC_SENSOR_LOC_CORE: + return 0x0040; + case OCC_SENSOR_TYPE_POWER: + return 0x0080; + case OCC_SENSOR_NAME: + return 0x1000; + case HWMON_SENSORS_MASK: + case OCC_SENSOR_LOC_GPU: + return 0x8e00; + case SLW_IMAGE_BASE: + return 0x1000000000000000; + } + return 0; +} + +static void pnv_occ_common_area_write(void *opaque, hwaddr addr, + uint64_t val, unsigned width) +{ + /* callback function defined to occ common area write */ + return; +} + static const MemoryRegionOps pnv_occ_power8_xscom_ops = { .read = pnv_occ_power8_xscom_read, .write = pnv_occ_power8_xscom_write, @@ -92,12 +152,24 @@ static const MemoryRegionOps pnv_occ_power8_xscom_ops = { .endianness = DEVICE_BIG_ENDIAN, }; +const MemoryRegionOps pnv_occ_sram_ops = { + .read = pnv_occ_common_area_read, + .write = pnv_occ_common_area_write, + .valid.min_access_size = 1, + .valid.max_access_size = 8, + .impl.min_access_size = 1, + .impl.max_access_size = 8, + .endianness = DEVICE_BIG_ENDIAN, +}; + static void pnv_occ_power8_class_init(ObjectClass *klass, void *data) { PnvOCCClass *poc = PNV_OCC_CLASS(klass); poc->xscom_size = PNV_XSCOM_OCC_SIZE; + poc->sram_size = PNV_OCC_COMMON_AREA_SIZE; poc->xscom_ops = &pnv_occ_power8_xscom_ops; + poc->sram_ops = &pnv_occ_sram_ops; poc->psi_irq = PSIHB_IRQ_OCC; } @@ -168,7 +240,9 @@ static void pnv_occ_power9_class_init(ObjectClass *klass, void *data) PnvOCCClass *poc = PNV_OCC_CLASS(klass); poc->xscom_size = PNV9_XSCOM_OCC_SIZE; + poc->sram_size = PNV9_OCC_COMMON_AREA_SIZE; poc->xscom_ops = &pnv_occ_power9_xscom_ops; + poc->sram_ops = &pnv_occ_sram_ops; poc->psi_irq = PSIHB9_IRQ_OCC; } @@ -199,6 +273,10 @@ static void pnv_occ_realize(DeviceState *dev, Error **errp) /* XScom region for OCC registers */ pnv_xscom_region_init(&occ->xscom_regs, OBJECT(dev), poc->xscom_ops, occ, "xscom-occ", poc->xscom_size); + + /* XScom region for OCC SRAM registers */ + pnv_xscom_region_init(&occ->sram_regs, OBJECT(dev), poc->sram_ops, + occ, "occ-common-area", poc->sram_size); } static void pnv_occ_class_init(ObjectClass *klass, void *data) diff --git a/include/hw/ppc/pnv_occ.h b/include/hw/ppc/pnv_occ.h index ed0709bfc0..66b0989be6 100644 --- a/include/hw/ppc/pnv_occ.h +++ b/include/hw/ppc/pnv_occ.h @@ -38,6 +38,7 @@ typedef struct PnvOCC { PnvPsi *psi; MemoryRegion xscom_regs; + MemoryRegion sram_regs; } PnvOCC; #define PNV_OCC_CLASS(klass) \ @@ -49,7 +50,9 @@ typedef struct PnvOCCClass { DeviceClass parent_class; int xscom_size; + int sram_size; const MemoryRegionOps *xscom_ops; + const MemoryRegionOps *sram_ops; int psi_irq; } PnvOCCClass; From 3887d241238c7b5960c7f153d2025891c5f5fc66 Mon Sep 17 00:00:00 2001 From: Balamuruhan S Date: Thu, 12 Sep 2019 15:00:54 +0530 Subject: [PATCH 08/53] hw/ppc/pnv_homer: add PowerNV homer device model MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit add PnvHomer device model to emulate homer memory access for pstate table, occ-sensors, slw, occ static and dynamic values for Power8 and Power9 chips. Signed-off-by: Balamuruhan S Message-Id: <20190912093056.4516-4-bala24@linux.ibm.com> Reviewed-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/ppc/Makefile.objs | 1 + hw/ppc/pnv.c | 30 ++++ hw/ppc/pnv_homer.c | 272 +++++++++++++++++++++++++++++++++++++ include/hw/ppc/pnv.h | 3 + include/hw/ppc/pnv_homer.h | 53 ++++++++ 5 files changed, 359 insertions(+) create mode 100644 hw/ppc/pnv_homer.c create mode 100644 include/hw/ppc/pnv_homer.h diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs index 2c4e1c8de0..580bb4f0dd 100644 --- a/hw/ppc/Makefile.objs +++ b/hw/ppc/Makefile.objs @@ -9,6 +9,7 @@ obj-$(CONFIG_PSERIES) += spapr_tpm_proxy.o obj-$(CONFIG_SPAPR_RNG) += spapr_rng.o # IBM PowerNV obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o pnv_core.o pnv_lpc.o pnv_psi.o pnv_occ.o pnv_bmc.o +obj-$(CONFIG_POWERNV) += pnv_homer.o ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy) obj-y += spapr_pci_vfio.o spapr_pci_nvlink2.o endif diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 09d2d7c026..77a86c6a23 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -860,6 +860,11 @@ static void pnv_chip_power8_instance_init(Object *obj) TYPE_PNV8_OCC, &error_abort, NULL); object_property_add_const_link(OBJECT(&chip8->occ), "psi", OBJECT(&chip8->psi), &error_abort); + + object_initialize_child(obj, "homer", &chip8->homer, sizeof(chip8->homer), + TYPE_PNV8_HOMER, &error_abort, NULL); + object_property_add_const_link(OBJECT(&chip8->homer), "chip", obj, + &error_abort); } static void pnv_chip_icp_realize(Pnv8Chip *chip8, Error **errp) @@ -957,6 +962,16 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) /* OCC SRAM model */ memory_region_add_subregion(get_system_memory(), PNV_OCC_COMMON_AREA(chip), &chip8->occ.sram_regs); + + /* HOMER */ + object_property_set_bool(OBJECT(&chip8->homer), true, "realized", + &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + memory_region_add_subregion(get_system_memory(), PNV_HOMER_BASE(chip), + &chip8->homer.regs); } static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data) @@ -1039,6 +1054,11 @@ static void pnv_chip_power9_instance_init(Object *obj) TYPE_PNV9_OCC, &error_abort, NULL); object_property_add_const_link(OBJECT(&chip9->occ), "psi", OBJECT(&chip9->psi), &error_abort); + + object_initialize_child(obj, "homer", &chip9->homer, sizeof(chip9->homer), + TYPE_PNV9_HOMER, &error_abort, NULL); + object_property_add_const_link(OBJECT(&chip9->homer), "chip", obj, + &error_abort); } static void pnv_chip_quad_realize(Pnv9Chip *chip9, Error **errp) @@ -1149,6 +1169,16 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) /* OCC SRAM model */ memory_region_add_subregion(get_system_memory(), PNV9_OCC_COMMON_AREA(chip), &chip9->occ.sram_regs); + + /* HOMER */ + object_property_set_bool(OBJECT(&chip9->homer), true, "realized", + &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + memory_region_add_subregion(get_system_memory(), PNV9_HOMER_BASE(chip), + &chip9->homer.regs); } static void pnv_chip_power9_class_init(ObjectClass *klass, void *data) diff --git a/hw/ppc/pnv_homer.c b/hw/ppc/pnv_homer.c new file mode 100644 index 0000000000..cc881a3b32 --- /dev/null +++ b/hw/ppc/pnv_homer.c @@ -0,0 +1,272 @@ +/* + * QEMU PowerPC PowerNV Emulation of a few HOMER related registers + * + * Copyright (c) 2019, IBM Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "exec/hwaddr.h" +#include "exec/memory.h" +#include "sysemu/cpus.h" +#include "hw/qdev-core.h" +#include "hw/ppc/pnv.h" +#include "hw/ppc/pnv_homer.h" + + +static bool core_max_array(PnvHomer *homer, hwaddr addr) +{ + int i; + PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer); + + for (i = 0; i <= homer->chip->nr_cores; i++) { + if (addr == (hmrc->core_max_base + i)) { + return true; + } + } + return false; +} + +/* P8 Pstate table */ + +#define PNV8_OCC_PSTATE_VERSION 0x1f8001 +#define PNV8_OCC_PSTATE_MIN 0x1f8003 +#define PNV8_OCC_PSTATE_VALID 0x1f8000 +#define PNV8_OCC_PSTATE_THROTTLE 0x1f8002 +#define PNV8_OCC_PSTATE_NOM 0x1f8004 +#define PNV8_OCC_PSTATE_TURBO 0x1f8005 +#define PNV8_OCC_PSTATE_ULTRA_TURBO 0x1f8006 +#define PNV8_OCC_PSTATE_DATA 0x1f8008 +#define PNV8_OCC_PSTATE_ID_ZERO 0x1f8010 +#define PNV8_OCC_PSTATE_ID_ONE 0x1f8018 +#define PNV8_OCC_PSTATE_ID_TWO 0x1f8020 +#define PNV8_OCC_VDD_VOLTAGE_IDENTIFIER 0x1f8012 +#define PNV8_OCC_VCS_VOLTAGE_IDENTIFIER 0x1f8013 +#define PNV8_OCC_PSTATE_ZERO_FREQUENCY 0x1f8014 +#define PNV8_OCC_PSTATE_ONE_FREQUENCY 0x1f801c +#define PNV8_OCC_PSTATE_TWO_FREQUENCY 0x1f8024 +#define PNV8_CORE_MAX_BASE 0x1f8810 + + +static uint64_t pnv_power8_homer_read(void *opaque, hwaddr addr, + unsigned size) +{ + PnvHomer *homer = PNV_HOMER(opaque); + + switch (addr) { + case PNV8_OCC_PSTATE_VERSION: + case PNV8_OCC_PSTATE_MIN: + case PNV8_OCC_PSTATE_ID_ZERO: + return 0; + case PNV8_OCC_PSTATE_VALID: + case PNV8_OCC_PSTATE_THROTTLE: + case PNV8_OCC_PSTATE_NOM: + case PNV8_OCC_PSTATE_TURBO: + case PNV8_OCC_PSTATE_ID_ONE: + case PNV8_OCC_VDD_VOLTAGE_IDENTIFIER: + case PNV8_OCC_VCS_VOLTAGE_IDENTIFIER: + return 1; + case PNV8_OCC_PSTATE_ULTRA_TURBO: + case PNV8_OCC_PSTATE_ID_TWO: + return 2; + case PNV8_OCC_PSTATE_DATA: + return 0x1000000000000000; + /* P8 frequency for 0, 1, and 2 pstates */ + case PNV8_OCC_PSTATE_ZERO_FREQUENCY: + case PNV8_OCC_PSTATE_ONE_FREQUENCY: + case PNV8_OCC_PSTATE_TWO_FREQUENCY: + return 3000; + } + /* pstate table core max array */ + if (core_max_array(homer, addr)) { + return 1; + } + return 0; +} + +static void pnv_power8_homer_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + /* callback function defined to homer write */ + return; +} + +static const MemoryRegionOps pnv_power8_homer_ops = { + .read = pnv_power8_homer_read, + .write = pnv_power8_homer_write, + .valid.min_access_size = 1, + .valid.max_access_size = 8, + .impl.min_access_size = 1, + .impl.max_access_size = 8, + .endianness = DEVICE_BIG_ENDIAN, +}; + +static void pnv_homer_power8_class_init(ObjectClass *klass, void *data) +{ + PnvHomerClass *homer = PNV_HOMER_CLASS(klass); + + homer->homer_size = PNV_HOMER_SIZE; + homer->homer_ops = &pnv_power8_homer_ops; + homer->core_max_base = PNV8_CORE_MAX_BASE; +} + +static const TypeInfo pnv_homer_power8_type_info = { + .name = TYPE_PNV8_HOMER, + .parent = TYPE_PNV_HOMER, + .instance_size = sizeof(PnvHomer), + .class_init = pnv_homer_power8_class_init, +}; + +/* P9 Pstate table */ + +#define PNV9_OCC_PSTATE_ID_ZERO 0xe2018 +#define PNV9_OCC_PSTATE_ID_ONE 0xe2020 +#define PNV9_OCC_PSTATE_ID_TWO 0xe2028 +#define PNV9_OCC_PSTATE_DATA 0xe2000 +#define PNV9_OCC_PSTATE_DATA_AREA 0xe2008 +#define PNV9_OCC_PSTATE_MIN 0xe2003 +#define PNV9_OCC_PSTATE_NOM 0xe2004 +#define PNV9_OCC_PSTATE_TURBO 0xe2005 +#define PNV9_OCC_PSTATE_ULTRA_TURBO 0xe2818 +#define PNV9_OCC_MAX_PSTATE_ULTRA_TURBO 0xe2006 +#define PNV9_OCC_PSTATE_MAJOR_VERSION 0xe2001 +#define PNV9_OCC_OPAL_RUNTIME_DATA 0xe2b85 +#define PNV9_CHIP_HOMER_IMAGE_POINTER 0x200008 +#define PNV9_CHIP_HOMER_BASE 0x0 +#define PNV9_OCC_PSTATE_ZERO_FREQUENCY 0xe201c +#define PNV9_OCC_PSTATE_ONE_FREQUENCY 0xe2024 +#define PNV9_OCC_PSTATE_TWO_FREQUENCY 0xe202c +#define PNV9_OCC_ROLE_MASTER_OR_SLAVE 0xe2002 +#define PNV9_CORE_MAX_BASE 0xe2819 + + +static uint64_t pnv_power9_homer_read(void *opaque, hwaddr addr, + unsigned size) +{ + PnvHomer *homer = PNV_HOMER(opaque); + + switch (addr) { + case PNV9_OCC_MAX_PSTATE_ULTRA_TURBO: + case PNV9_OCC_PSTATE_ID_ZERO: + return 0; + case PNV9_OCC_PSTATE_DATA: + case PNV9_OCC_ROLE_MASTER_OR_SLAVE: + case PNV9_OCC_PSTATE_NOM: + case PNV9_OCC_PSTATE_TURBO: + case PNV9_OCC_PSTATE_ID_ONE: + case PNV9_OCC_PSTATE_ULTRA_TURBO: + case PNV9_OCC_OPAL_RUNTIME_DATA: + return 1; + case PNV9_OCC_PSTATE_MIN: + case PNV9_OCC_PSTATE_ID_TWO: + return 2; + + /* 3000 khz frequency for 0, 1, and 2 pstates */ + case PNV9_OCC_PSTATE_ZERO_FREQUENCY: + case PNV9_OCC_PSTATE_ONE_FREQUENCY: + case PNV9_OCC_PSTATE_TWO_FREQUENCY: + return 3000; + case PNV9_OCC_PSTATE_MAJOR_VERSION: + return 0x90; + case PNV9_CHIP_HOMER_BASE: + case PNV9_OCC_PSTATE_DATA_AREA: + case PNV9_CHIP_HOMER_IMAGE_POINTER: + return 0x1000000000000000; + } + /* pstate table core max array */ + if (core_max_array(homer, addr)) { + return 1; + } + return 0; +} + +static void pnv_power9_homer_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + /* callback function defined to homer write */ + return; +} + +static const MemoryRegionOps pnv_power9_homer_ops = { + .read = pnv_power9_homer_read, + .write = pnv_power9_homer_write, + .valid.min_access_size = 1, + .valid.max_access_size = 8, + .impl.min_access_size = 1, + .impl.max_access_size = 8, + .endianness = DEVICE_BIG_ENDIAN, +}; + +static void pnv_homer_power9_class_init(ObjectClass *klass, void *data) +{ + PnvHomerClass *homer = PNV_HOMER_CLASS(klass); + + homer->homer_size = PNV9_HOMER_SIZE; + homer->homer_ops = &pnv_power9_homer_ops; + homer->core_max_base = PNV9_CORE_MAX_BASE; +} + +static const TypeInfo pnv_homer_power9_type_info = { + .name = TYPE_PNV9_HOMER, + .parent = TYPE_PNV_HOMER, + .instance_size = sizeof(PnvHomer), + .class_init = pnv_homer_power9_class_init, +}; + +static void pnv_homer_realize(DeviceState *dev, Error **errp) +{ + PnvHomer *homer = PNV_HOMER(dev); + PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer); + Object *obj; + Error *local_err = NULL; + + obj = object_property_get_link(OBJECT(dev), "chip", &local_err); + if (!obj) { + error_propagate(errp, local_err); + error_prepend(errp, "required link 'chip' not found: "); + return; + } + homer->chip = PNV_CHIP(obj); + /* homer region */ + memory_region_init_io(&homer->regs, OBJECT(dev), + hmrc->homer_ops, homer, "homer-main-memory", + hmrc->homer_size); +} + +static void pnv_homer_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = pnv_homer_realize; + dc->desc = "PowerNV HOMER Memory"; +} + +static const TypeInfo pnv_homer_type_info = { + .name = TYPE_PNV_HOMER, + .parent = TYPE_DEVICE, + .instance_size = sizeof(PnvHomer), + .class_init = pnv_homer_class_init, + .class_size = sizeof(PnvHomerClass), + .abstract = true, +}; + +static void pnv_homer_register_types(void) +{ + type_register_static(&pnv_homer_type_info); + type_register_static(&pnv_homer_power8_type_info); + type_register_static(&pnv_homer_power9_type_info); +} + +type_init(pnv_homer_register_types); diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h index 63a4b7b6a7..1cdbe55bf8 100644 --- a/include/hw/ppc/pnv.h +++ b/include/hw/ppc/pnv.h @@ -26,6 +26,7 @@ #include "hw/ppc/pnv_lpc.h" #include "hw/ppc/pnv_psi.h" #include "hw/ppc/pnv_occ.h" +#include "hw/ppc/pnv_homer.h" #include "hw/ppc/pnv_xive.h" #include "hw/ppc/pnv_core.h" @@ -76,6 +77,7 @@ typedef struct Pnv8Chip { PnvLpcController lpc; Pnv8Psi psi; PnvOCC occ; + PnvHomer homer; } Pnv8Chip; #define TYPE_PNV9_CHIP "pnv9-chip" @@ -90,6 +92,7 @@ typedef struct Pnv9Chip { Pnv9Psi psi; PnvLpcController lpc; PnvOCC occ; + PnvHomer homer; uint32_t nr_quads; PnvQuad *quads; diff --git a/include/hw/ppc/pnv_homer.h b/include/hw/ppc/pnv_homer.h new file mode 100644 index 0000000000..abaec43c2d --- /dev/null +++ b/include/hw/ppc/pnv_homer.h @@ -0,0 +1,53 @@ +/* + * QEMU PowerPC PowerNV Emulation of a few HOMER related registers + * + * Copyright (c) 2019, IBM Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#ifndef PPC_PNV_HOMER_H +#define PPC_PNV_HOMER_H + +#include "hw/ppc/pnv.h" + +#define TYPE_PNV_HOMER "pnv-homer" +#define PNV_HOMER(obj) OBJECT_CHECK(PnvHomer, (obj), TYPE_PNV_HOMER) +#define TYPE_PNV8_HOMER TYPE_PNV_HOMER "-POWER8" +#define PNV8_HOMER(obj) OBJECT_CHECK(PnvHomer, (obj), TYPE_PNV8_HOMER) +#define TYPE_PNV9_HOMER TYPE_PNV_HOMER "-POWER9" +#define PNV9_HOMER(obj) OBJECT_CHECK(PnvHomer, (obj), TYPE_PNV9_HOMER) + +typedef struct PnvHomer { + DeviceState parent; + + struct PnvChip *chip; + MemoryRegion regs; +} PnvHomer; + +#define PNV_HOMER_CLASS(klass) \ + OBJECT_CLASS_CHECK(PnvHomerClass, (klass), TYPE_PNV_HOMER) +#define PNV_HOMER_GET_CLASS(obj) \ + OBJECT_GET_CLASS(PnvHomerClass, (obj), TYPE_PNV_HOMER) + +typedef struct PnvHomerClass { + DeviceClass parent_class; + + int homer_size; + const MemoryRegionOps *homer_ops; + + hwaddr core_max_base; +} PnvHomerClass; + +#endif /* PPC_PNV_HOMER_H */ From 4a99d40551d265e56584bfa6657d9a549e729127 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 11 Sep 2019 15:39:36 +0200 Subject: [PATCH 09/53] spapr/irq: Introduce an ics_irq_free() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It will help us to discard interrupt numbers which have not been claimed in the next patch. Signed-off-by: Cédric Le Goater Message-Id: <20190911133937.2716-2-clg@kaod.org> Reviewed-by: Greg Kurz Signed-off-by: David Gibson --- hw/ppc/spapr_irq.c | 9 +++------ include/hw/ppc/xics.h | 5 +++++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index 06fe2432ba..d8f46b6797 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -114,9 +114,6 @@ static void spapr_irq_init_xics(SpaprMachineState *spapr, int nr_irqs, xics_spapr_init(spapr); } -#define ICS_IRQ_FREE(ics, srcno) \ - (!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK))) - static int spapr_irq_claim_xics(SpaprMachineState *spapr, int irq, bool lsi, Error **errp) { @@ -129,7 +126,7 @@ static int spapr_irq_claim_xics(SpaprMachineState *spapr, int irq, bool lsi, return -1; } - if (!ICS_IRQ_FREE(ics, irq - ics->offset)) { + if (!ics_irq_free(ics, irq - ics->offset)) { error_setg(errp, "IRQ %d is not free", irq); return -1; } @@ -147,7 +144,7 @@ static void spapr_irq_free_xics(SpaprMachineState *spapr, int irq, int num) if (ics_valid_irq(ics, irq)) { trace_spapr_irq_free(0, irq, num); for (i = srcno; i < srcno + num; ++i) { - if (ICS_IRQ_FREE(ics, i)) { + if (ics_irq_free(ics, i)) { trace_spapr_irq_free_warn(0, i); } memset(&ics->irqs[i], 0, sizeof(ICSIRQState)); @@ -767,7 +764,7 @@ static int ics_find_free_block(ICSState *ics, int num, int alignnum) return -1; } for (i = first; i < first + num; ++i) { - if (!ICS_IRQ_FREE(ics, i)) { + if (!ics_irq_free(ics, i)) { break; } } diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h index f2a8d6a4b4..64a2c8862a 100644 --- a/include/hw/ppc/xics.h +++ b/include/hw/ppc/xics.h @@ -179,6 +179,11 @@ void ics_simple_write_xive(ICSState *ics, int nr, int server, uint8_t priority, uint8_t saved_priority); void ics_simple_set_irq(void *opaque, int srcno, int val); +static inline bool ics_irq_free(ICSState *ics, uint32_t srcno) +{ + return !(ics->irqs[srcno].flags & XICS_FLAGS_IRQ_MASK); +} + void ics_set_irq_type(ICSState *ics, int srcno, bool lsi); void icp_pic_print_info(ICPState *icp, Monitor *mon); void ics_pic_print_info(ICSState *ics, Monitor *mon); From 4c3539d491026a0cc68e3b886f16cb7f57efd46b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 11 Sep 2019 15:39:37 +0200 Subject: [PATCH 10/53] spapr/irq: Only claim VALID interrupts at the KVM level MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A typical pseries VM with 16 vCPUs, one disk, one network adapater uses less than 100 interrupts but the whole IRQ number space of the QEMU machine is allocated at reset time and it is 8K wide. This is wasting a considerable amount of interrupt numbers in the global IRQ space which has 1M interrupts per socket on a POWER9. To optimise the HW resources, only request at the KVM level interrupts which have been claimed by the guest. This will help to increase the maximum number of VMs per system and also help supporting nested guests using the XIVE interrupt mode. Signed-off-by: Cédric Le Goater Message-Id: <20190911133937.2716-3-clg@kaod.org> Signed-off-by: Greg Kurz Message-Id: <156942766014.1274533.10792048853177121231.stgit@bahia.lan> [dwg: Folded in fix up from Greg Kurz] Signed-off-by: David Gibson --- hw/intc/spapr_xive_kvm.c | 40 +++++++++++++++++++++++++++++++++++++--- hw/intc/xics_kvm.c | 8 ++++++++ 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/hw/intc/spapr_xive_kvm.c b/hw/intc/spapr_xive_kvm.c index 17af4d19f5..2006f96aec 100644 --- a/hw/intc/spapr_xive_kvm.c +++ b/hw/intc/spapr_xive_kvm.c @@ -255,11 +255,16 @@ void kvmppc_xive_source_reset_one(XiveSource *xsrc, int srcno, Error **errp) static void kvmppc_xive_source_reset(XiveSource *xsrc, Error **errp) { + SpaprXive *xive = SPAPR_XIVE(xsrc->xive); int i; for (i = 0; i < xsrc->nr_irqs; i++) { Error *local_err = NULL; + if (!xive_eas_is_valid(&xive->eat[i])) { + continue; + } + kvmppc_xive_source_reset_one(xsrc, i, &local_err); if (local_err) { error_propagate(errp, local_err); @@ -328,11 +333,18 @@ uint64_t kvmppc_xive_esb_rw(XiveSource *xsrc, int srcno, uint32_t offset, static void kvmppc_xive_source_get_state(XiveSource *xsrc) { + SpaprXive *xive = SPAPR_XIVE(xsrc->xive); int i; for (i = 0; i < xsrc->nr_irqs; i++) { + uint8_t pq; + + if (!xive_eas_is_valid(&xive->eat[i])) { + continue; + } + /* Perform a load without side effect to retrieve the PQ bits */ - uint8_t pq = xive_esb_read(xsrc, i, XIVE_ESB_GET); + pq = xive_esb_read(xsrc, i, XIVE_ESB_GET); /* and save PQ locally */ xive_source_esb_set(xsrc, i, pq); @@ -521,9 +533,14 @@ static void kvmppc_xive_change_state_handler(void *opaque, int running, */ if (running) { for (i = 0; i < xsrc->nr_irqs; i++) { - uint8_t pq = xive_source_esb_get(xsrc, i); + uint8_t pq; uint8_t old_pq; + if (!xive_eas_is_valid(&xive->eat[i])) { + continue; + } + + pq = xive_source_esb_get(xsrc, i); old_pq = xive_esb_read(xsrc, i, XIVE_ESB_SET_PQ_00 + (pq << 8)); /* @@ -545,7 +562,13 @@ static void kvmppc_xive_change_state_handler(void *opaque, int running, * migration is in progress. */ for (i = 0; i < xsrc->nr_irqs; i++) { - uint8_t pq = xive_esb_read(xsrc, i, XIVE_ESB_GET); + uint8_t pq; + + if (!xive_eas_is_valid(&xive->eat[i])) { + continue; + } + + pq = xive_esb_read(xsrc, i, XIVE_ESB_GET); /* * PQ is set to PENDING to possibly catch a triggered @@ -655,6 +678,17 @@ int kvmppc_xive_post_load(SpaprXive *xive, int version_id) continue; } + /* + * We can only restore the source config if the source has been + * previously set in KVM. Since we don't do that for all interrupts + * at reset time anymore, let's do it now. + */ + kvmppc_xive_source_reset_one(&xive->source, i, &local_err); + if (local_err) { + error_report_err(local_err); + return -1; + } + kvmppc_xive_set_source_config(xive, i, &xive->eat[i], &local_err); if (local_err) { error_report_err(local_err); diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c index a4d2e876cc..ba90d6dc96 100644 --- a/hw/intc/xics_kvm.c +++ b/hw/intc/xics_kvm.c @@ -190,6 +190,10 @@ void ics_get_kvm_state(ICSState *ics) for (i = 0; i < ics->nr_irqs; i++) { ICSIRQState *irq = &ics->irqs[i]; + if (ics_irq_free(ics, i)) { + continue; + } + kvm_device_access(kernel_xics_fd, KVM_DEV_XICS_GRP_SOURCES, i + ics->offset, &state, false, &error_fatal); @@ -301,6 +305,10 @@ int ics_set_kvm_state(ICSState *ics, Error **errp) Error *local_err = NULL; int ret; + if (ics_irq_free(ics, i)) { + continue; + } + ret = ics_set_kvm_state_one(ics, i, &local_err); if (ret < 0) { error_propagate(errp, local_err); From a2735cf483814b1c0e5773eee4a52f8e32d438cf Mon Sep 17 00:00:00 2001 From: "Paul A. Clarke" Date: Wed, 18 Sep 2019 09:31:21 -0500 Subject: [PATCH 11/53] ppc: Add support for 'mffscrn','mffscrni' instructions ISA 3.0B added a set of Floating-Point Status and Control Register (FPSCR) instructions: mffsce, mffscdrn, mffscdrni, mffscrn, mffscrni, mffsl. This patch adds support for 'mffscrn' and 'mffscrni' instructions. 'mffscrn' and 'mffscrni' are similar to 'mffsl', except they do not return the status bits (FI, FR, FPRF) and they also set the rounding mode in the FPSCR. On CPUs without support for 'mffscrn'/'mffscrni' (below ISA 3.0), the instructions will execute identically to 'mffs'. Signed-off-by: Paul A. Clarke Message-Id: <1568817081-1345-1-git-send-email-pc@us.ibm.com> Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target/ppc/cpu.h | 9 +++- target/ppc/dfp_helper.c | 2 +- target/ppc/internal.h | 3 ++ target/ppc/translate/fp-impl.inc.c | 69 +++++++++++++++++++++++++++++- target/ppc/translate/fp-ops.inc.c | 4 ++ 5 files changed, 84 insertions(+), 3 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index eaee1a5575..a23c6455b9 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -559,6 +559,9 @@ enum { /*****************************************************************************/ /* Floating point status and control register */ +#define FPSCR_DRN2 34 /* Decimal Floating-Point rounding control */ +#define FPSCR_DRN1 33 /* Decimal Floating-Point rounding control */ +#define FPSCR_DRN0 32 /* Decimal Floating-Point rounding control */ #define FPSCR_FX 31 /* Floating-point exception summary */ #define FPSCR_FEX 30 /* Floating-point enabled exception summary */ #define FPSCR_VX 29 /* Floating-point invalid operation exception summ. */ @@ -592,6 +595,7 @@ enum { #define FPSCR_NI 2 /* Floating-point non-IEEE mode */ #define FPSCR_RN1 1 #define FPSCR_RN0 0 /* Floating-point rounding control */ +#define fpscr_drn (((env->fpscr) & FP_DRN) >> FPSCR_DRN0) #define fpscr_fex (((env->fpscr) >> FPSCR_FEX) & 0x1) #define fpscr_vx (((env->fpscr) >> FPSCR_VX) & 0x1) #define fpscr_ox (((env->fpscr) >> FPSCR_OX) & 0x1) @@ -627,6 +631,10 @@ enum { #define fpscr_eex (((env->fpscr) >> FPSCR_XX) & ((env->fpscr) >> FPSCR_XE) & \ 0x1F) +#define FP_DRN2 (1ull << FPSCR_DRN2) +#define FP_DRN1 (1ull << FPSCR_DRN1) +#define FP_DRN0 (1ull << FPSCR_DRN0) +#define FP_DRN (FP_DRN2 | FP_DRN1 | FP_DRN0) #define FP_FX (1ull << FPSCR_FX) #define FP_FEX (1ull << FPSCR_FEX) #define FP_VX (1ull << FPSCR_VX) @@ -662,7 +670,6 @@ enum { #define FP_RN0 (1ull << FPSCR_RN0) #define FP_RN (FP_RN1 | FP_RN0) -#define FP_MODE FP_RN #define FP_ENABLES (FP_VE | FP_OE | FP_UE | FP_ZE | FP_XE) #define FP_STATUS (FP_FR | FP_FI | FP_FPRF) diff --git a/target/ppc/dfp_helper.c b/target/ppc/dfp_helper.c index f102177572..da8e08a35c 100644 --- a/target/ppc/dfp_helper.c +++ b/target/ppc/dfp_helper.c @@ -48,7 +48,7 @@ static void dfp_prepare_rounding_mode(decContext *context, uint64_t fpscr) { enum rounding rnd; - switch ((fpscr >> 32) & 0x7) { + switch ((fpscr & FP_DRN) >> FPSCR_DRN0) { case 0: rnd = DEC_ROUND_HALF_EVEN; break; diff --git a/target/ppc/internal.h b/target/ppc/internal.h index d3d327e548..15d655b356 100644 --- a/target/ppc/internal.h +++ b/target/ppc/internal.h @@ -157,6 +157,9 @@ EXTRACT_HELPER(FPL, 25, 1); EXTRACT_HELPER(FPFLM, 17, 8); EXTRACT_HELPER(FPW, 16, 1); +/* mffscrni */ +EXTRACT_HELPER(RM, 11, 2); + /* addpcis */ EXTRACT_HELPER_SPLIT_3(DX, 10, 6, 6, 5, 16, 1, 1, 0, 0) #if defined(TARGET_PPC64) diff --git a/target/ppc/translate/fp-impl.inc.c b/target/ppc/translate/fp-impl.inc.c index 7cd9d8db05..75f9523b07 100644 --- a/target/ppc/translate/fp-impl.inc.c +++ b/target/ppc/translate/fp-impl.inc.c @@ -634,11 +634,78 @@ static void gen_mffsl(DisasContext *ctx) gen_reset_fpstatus(); tcg_gen_extu_tl_i64(t0, cpu_fpscr); /* Mask everything except mode, status, and enables. */ - tcg_gen_andi_i64(t0, t0, FP_MODE | FP_STATUS | FP_ENABLES); + tcg_gen_andi_i64(t0, t0, FP_DRN | FP_STATUS | FP_ENABLES | FP_RN); set_fpr(rD(ctx->opcode), t0); tcg_temp_free_i64(t0); } +static void gen_helper_mffscrn(DisasContext *ctx, TCGv_i64 t1) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i32 mask = tcg_const_i32(0x0001); + + gen_reset_fpstatus(); + tcg_gen_extu_tl_i64(t0, cpu_fpscr); + tcg_gen_andi_i64(t0, t0, FP_DRN | FP_ENABLES | FP_RN); + set_fpr(rD(ctx->opcode), t0); + + /* Mask FPSCR value to clear RN. */ + tcg_gen_andi_i64(t0, t0, ~FP_RN); + + /* Merge RN into FPSCR value. */ + tcg_gen_or_i64(t0, t0, t1); + + gen_helper_store_fpscr(cpu_env, t0, mask); + + tcg_temp_free_i32(mask); + tcg_temp_free_i64(t0); +} + +/* mffscrn */ +static void gen_mffscrn(DisasContext *ctx) +{ + TCGv_i64 t1; + + if (unlikely(!(ctx->insns_flags2 & PPC2_ISA300))) { + return gen_mffs(ctx); + } + + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + + t1 = tcg_temp_new_i64(); + get_fpr(t1, rB(ctx->opcode)); + /* Mask FRB to get just RN. */ + tcg_gen_andi_i64(t1, t1, FP_RN); + + gen_helper_mffscrn(ctx, t1); + + tcg_temp_free_i64(t1); +} + +/* mffscrni */ +static void gen_mffscrni(DisasContext *ctx) +{ + TCGv_i64 t1; + + if (unlikely(!(ctx->insns_flags2 & PPC2_ISA300))) { + return gen_mffs(ctx); + } + + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + + t1 = tcg_const_i64((uint64_t)RM(ctx->opcode)); + + gen_helper_mffscrn(ctx, t1); + + tcg_temp_free_i64(t1); +} + /* mtfsb0 */ static void gen_mtfsb0(DisasContext *ctx) { diff --git a/target/ppc/translate/fp-ops.inc.c b/target/ppc/translate/fp-ops.inc.c index 88ebc2526c..f2bcf0e67b 100644 --- a/target/ppc/translate/fp-ops.inc.c +++ b/target/ppc/translate/fp-ops.inc.c @@ -107,6 +107,10 @@ GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT), GEN_HANDLER_E_2(mffs, 0x3F, 0x07, 0x12, 0x00, 0x00000000, PPC_FLOAT, PPC_NONE), GEN_HANDLER_E_2(mffsl, 0x3F, 0x07, 0x12, 0x18, 0x00000000, PPC_FLOAT, PPC2_ISA300), +GEN_HANDLER_E_2(mffscrn, 0x3F, 0x07, 0x12, 0x16, 0x00000000, PPC_FLOAT, + PPC_NONE), +GEN_HANDLER_E_2(mffscrni, 0x3F, 0x07, 0x12, 0x17, 0x00000000, PPC_FLOAT, + PPC_NONE), GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT), GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT), GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x00000000, PPC_FLOAT), From bc7a45ab88281bbced8ebe9fb87d518102b22519 Mon Sep 17 00:00:00 2001 From: "Paul A. Clarke" Date: Wed, 18 Sep 2019 09:31:22 -0500 Subject: [PATCH 12/53] ppc: Add support for 'mffsce' instruction ISA 3.0B added a set of Floating-Point Status and Control Register (FPSCR) instructions: mffsce, mffscdrn, mffscdrni, mffscrn, mffscrni, mffsl. This patch adds support for 'mffsce' instruction. 'mffsce' is identical to 'mffs', except that it also clears the exception enable bits in the FPSCR. On CPUs without support for 'mffsce' (below ISA 3.0), the instruction will execute identically to 'mffs'. Signed-off-by: Paul A. Clarke Reviewed-by: Richard Henderson Message-Id: <1568817082-1384-1-git-send-email-pc@us.ibm.com> Signed-off-by: David Gibson --- target/ppc/translate/fp-impl.inc.c | 30 ++++++++++++++++++++++++++++++ target/ppc/translate/fp-ops.inc.c | 2 ++ 2 files changed, 32 insertions(+) diff --git a/target/ppc/translate/fp-impl.inc.c b/target/ppc/translate/fp-impl.inc.c index 75f9523b07..d8e27bf4d5 100644 --- a/target/ppc/translate/fp-impl.inc.c +++ b/target/ppc/translate/fp-impl.inc.c @@ -639,6 +639,36 @@ static void gen_mffsl(DisasContext *ctx) tcg_temp_free_i64(t0); } +/* mffsce */ +static void gen_mffsce(DisasContext *ctx) +{ + TCGv_i64 t0; + TCGv_i32 mask; + + if (unlikely(!(ctx->insns_flags2 & PPC2_ISA300))) { + return gen_mffs(ctx); + } + + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + + t0 = tcg_temp_new_i64(); + + gen_reset_fpstatus(); + tcg_gen_extu_tl_i64(t0, cpu_fpscr); + set_fpr(rD(ctx->opcode), t0); + + /* Clear exception enable bits in the FPSCR. */ + tcg_gen_andi_i64(t0, t0, ~FP_ENABLES); + mask = tcg_const_i32(0x0003); + gen_helper_store_fpscr(cpu_env, t0, mask); + + tcg_temp_free_i32(mask); + tcg_temp_free_i64(t0); +} + static void gen_helper_mffscrn(DisasContext *ctx, TCGv_i64 t1) { TCGv_i64 t0 = tcg_temp_new_i64(); diff --git a/target/ppc/translate/fp-ops.inc.c b/target/ppc/translate/fp-ops.inc.c index f2bcf0e67b..88fab65628 100644 --- a/target/ppc/translate/fp-ops.inc.c +++ b/target/ppc/translate/fp-ops.inc.c @@ -105,6 +105,8 @@ GEN_HANDLER_E(fmrgew, 0x3F, 0x06, 0x1E, 0x00000001, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(fmrgow, 0x3F, 0x06, 0x1A, 0x00000001, PPC_NONE, PPC2_VSX207), GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT), GEN_HANDLER_E_2(mffs, 0x3F, 0x07, 0x12, 0x00, 0x00000000, PPC_FLOAT, PPC_NONE), +GEN_HANDLER_E_2(mffsce, 0x3F, 0x07, 0x12, 0x01, 0x00000000, PPC_FLOAT, + PPC2_ISA300), GEN_HANDLER_E_2(mffsl, 0x3F, 0x07, 0x12, 0x18, 0x00000000, PPC_FLOAT, PPC2_ISA300), GEN_HANDLER_E_2(mffscrn, 0x3F, 0x07, 0x12, 0x16, 0x00000000, PPC_FLOAT, From 5c94dd3806b6cd4a9540a818ee87c335804bdc38 Mon Sep 17 00:00:00 2001 From: "Paul A. Clarke" Date: Wed, 18 Sep 2019 09:32:49 -0500 Subject: [PATCH 13/53] ppc: Use FPSCR defines instead of constants There are FPSCR-related defines in target/ppc/cpu.h which can be used in place of constants and explicit shifts which arguably improve the code a bit in places. Signed-off-by: Paul A. Clarke Message-Id: <1568817169-1721-1-git-send-email-pc@us.ibm.com> Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target/ppc/dfp_helper.c | 8 +-- target/ppc/fpu_helper.c | 122 ++++++++++++++++++++-------------------- 2 files changed, 65 insertions(+), 65 deletions(-) diff --git a/target/ppc/dfp_helper.c b/target/ppc/dfp_helper.c index da8e08a35c..753399177c 100644 --- a/target/ppc/dfp_helper.c +++ b/target/ppc/dfp_helper.c @@ -220,8 +220,8 @@ static void dfp_set_FPRF_from_FRT_with_context(struct PPC_DFP *dfp, default: assert(0); /* should never get here */ } - dfp->env->fpscr &= ~(0x1F << 12); - dfp->env->fpscr |= (fprf << 12); + dfp->env->fpscr &= ~FP_FPRF; + dfp->env->fpscr |= (fprf << FPSCR_FPRF); } static void dfp_set_FPRF_from_FRT(struct PPC_DFP *dfp) @@ -369,8 +369,8 @@ static void dfp_set_CRBF_from_T(struct PPC_DFP *dfp) static void dfp_set_FPCC_from_CRBF(struct PPC_DFP *dfp) { - dfp->env->fpscr &= ~(0xF << 12); - dfp->env->fpscr |= (dfp->crbf << 12); + dfp->env->fpscr &= ~FP_FPCC; + dfp->env->fpscr |= (dfp->crbf << FPSCR_FPCC); } static inline void dfp_makeQNaN(decNumber *dn) diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index 4b1a2e6178..dc383242f7 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -180,7 +180,7 @@ static void set_fprf_from_class(CPUPPCState *env, int class) }; bool isneg = class & is_neg; - env->fpscr &= ~(0x1F << FPSCR_FPRF); + env->fpscr &= ~FP_FPRF; env->fpscr |= fprf[ctz32(class)][isneg] << FPSCR_FPRF; } @@ -199,12 +199,12 @@ COMPUTE_FPRF(float128) static void finish_invalid_op_excp(CPUPPCState *env, int op, uintptr_t retaddr) { /* Update the floating-point invalid operation summary */ - env->fpscr |= 1 << FPSCR_VX; + env->fpscr |= FP_VX; /* Update the floating-point exception summary */ env->fpscr |= FP_FX; if (fpscr_ve != 0) { /* Update the floating-point enabled exception summary */ - env->fpscr |= 1 << FPSCR_FEX; + env->fpscr |= FP_FEX; if (fp_exceptions_enabled(env)) { raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_FP | op, retaddr); @@ -215,11 +215,11 @@ static void finish_invalid_op_excp(CPUPPCState *env, int op, uintptr_t retaddr) static void finish_invalid_op_arith(CPUPPCState *env, int op, bool set_fpcc, uintptr_t retaddr) { - env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); + env->fpscr &= ~(FP_FR | FP_FI); if (fpscr_ve == 0) { if (set_fpcc) { - env->fpscr &= ~(0xF << FPSCR_FPCC); - env->fpscr |= 0x11 << FPSCR_FPCC; + env->fpscr &= ~FP_FPCC; + env->fpscr |= (FP_C | FP_FU); } } finish_invalid_op_excp(env, op, retaddr); @@ -228,7 +228,7 @@ static void finish_invalid_op_arith(CPUPPCState *env, int op, /* Signalling NaN */ static void float_invalid_op_vxsnan(CPUPPCState *env, uintptr_t retaddr) { - env->fpscr |= 1 << FPSCR_VXSNAN; + env->fpscr |= FP_VXSNAN; finish_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, retaddr); } @@ -236,7 +236,7 @@ static void float_invalid_op_vxsnan(CPUPPCState *env, uintptr_t retaddr) static void float_invalid_op_vxisi(CPUPPCState *env, bool set_fpcc, uintptr_t retaddr) { - env->fpscr |= 1 << FPSCR_VXISI; + env->fpscr |= FP_VXISI; finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXISI, set_fpcc, retaddr); } @@ -244,7 +244,7 @@ static void float_invalid_op_vxisi(CPUPPCState *env, bool set_fpcc, static void float_invalid_op_vxidi(CPUPPCState *env, bool set_fpcc, uintptr_t retaddr) { - env->fpscr |= 1 << FPSCR_VXIDI; + env->fpscr |= FP_VXIDI; finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXIDI, set_fpcc, retaddr); } @@ -252,7 +252,7 @@ static void float_invalid_op_vxidi(CPUPPCState *env, bool set_fpcc, static void float_invalid_op_vxzdz(CPUPPCState *env, bool set_fpcc, uintptr_t retaddr) { - env->fpscr |= 1 << FPSCR_VXZDZ; + env->fpscr |= FP_VXZDZ; finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXZDZ, set_fpcc, retaddr); } @@ -260,7 +260,7 @@ static void float_invalid_op_vxzdz(CPUPPCState *env, bool set_fpcc, static void float_invalid_op_vximz(CPUPPCState *env, bool set_fpcc, uintptr_t retaddr) { - env->fpscr |= 1 << FPSCR_VXIMZ; + env->fpscr |= FP_VXIMZ; finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXIMZ, set_fpcc, retaddr); } @@ -268,7 +268,7 @@ static void float_invalid_op_vximz(CPUPPCState *env, bool set_fpcc, static void float_invalid_op_vxsqrt(CPUPPCState *env, bool set_fpcc, uintptr_t retaddr) { - env->fpscr |= 1 << FPSCR_VXSQRT; + env->fpscr |= FP_VXSQRT; finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXSQRT, set_fpcc, retaddr); } @@ -276,13 +276,13 @@ static void float_invalid_op_vxsqrt(CPUPPCState *env, bool set_fpcc, static void float_invalid_op_vxvc(CPUPPCState *env, bool set_fpcc, uintptr_t retaddr) { - env->fpscr |= 1 << FPSCR_VXVC; + env->fpscr |= FP_VXVC; if (set_fpcc) { - env->fpscr &= ~(0xF << FPSCR_FPCC); - env->fpscr |= 0x11 << FPSCR_FPCC; + env->fpscr &= ~FP_FPCC; + env->fpscr |= (FP_C | FP_FU); } /* Update the floating-point invalid operation summary */ - env->fpscr |= 1 << FPSCR_VX; + env->fpscr |= FP_VX; /* Update the floating-point exception summary */ env->fpscr |= FP_FX; /* We must update the target FPR before raising the exception */ @@ -292,7 +292,7 @@ static void float_invalid_op_vxvc(CPUPPCState *env, bool set_fpcc, cs->exception_index = POWERPC_EXCP_PROGRAM; env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC; /* Update the floating-point enabled exception summary */ - env->fpscr |= 1 << FPSCR_FEX; + env->fpscr |= FP_FEX; /* Exception is differed */ } } @@ -301,12 +301,12 @@ static void float_invalid_op_vxvc(CPUPPCState *env, bool set_fpcc, static void float_invalid_op_vxcvi(CPUPPCState *env, bool set_fpcc, uintptr_t retaddr) { - env->fpscr |= 1 << FPSCR_VXCVI; - env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); + env->fpscr |= FP_VXCVI; + env->fpscr &= ~(FP_FR | FP_FI); if (fpscr_ve == 0) { if (set_fpcc) { - env->fpscr &= ~(0xF << FPSCR_FPCC); - env->fpscr |= 0x11 << FPSCR_FPCC; + env->fpscr &= ~FP_FPCC; + env->fpscr |= (FP_C | FP_FU); } } finish_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, retaddr); @@ -314,13 +314,13 @@ static void float_invalid_op_vxcvi(CPUPPCState *env, bool set_fpcc, static inline void float_zero_divide_excp(CPUPPCState *env, uintptr_t raddr) { - env->fpscr |= 1 << FPSCR_ZX; - env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); + env->fpscr |= FP_ZX; + env->fpscr &= ~(FP_FR | FP_FI); /* Update the floating-point exception summary */ env->fpscr |= FP_FX; if (fpscr_ze != 0) { /* Update the floating-point enabled exception summary */ - env->fpscr |= 1 << FPSCR_FEX; + env->fpscr |= FP_FEX; if (fp_exceptions_enabled(env)) { raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX, @@ -333,19 +333,19 @@ static inline void float_overflow_excp(CPUPPCState *env) { CPUState *cs = env_cpu(env); - env->fpscr |= 1 << FPSCR_OX; + env->fpscr |= FP_OX; /* Update the floating-point exception summary */ env->fpscr |= FP_FX; if (fpscr_oe != 0) { /* XXX: should adjust the result */ /* Update the floating-point enabled exception summary */ - env->fpscr |= 1 << FPSCR_FEX; + env->fpscr |= FP_FEX; /* We must update the target FPR before raising the exception */ cs->exception_index = POWERPC_EXCP_PROGRAM; env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX; } else { - env->fpscr |= 1 << FPSCR_XX; - env->fpscr |= 1 << FPSCR_FI; + env->fpscr |= FP_XX; + env->fpscr |= FP_FI; } } @@ -353,13 +353,13 @@ static inline void float_underflow_excp(CPUPPCState *env) { CPUState *cs = env_cpu(env); - env->fpscr |= 1 << FPSCR_UX; + env->fpscr |= FP_UX; /* Update the floating-point exception summary */ env->fpscr |= FP_FX; if (fpscr_ue != 0) { /* XXX: should adjust the result */ /* Update the floating-point enabled exception summary */ - env->fpscr |= 1 << FPSCR_FEX; + env->fpscr |= FP_FEX; /* We must update the target FPR before raising the exception */ cs->exception_index = POWERPC_EXCP_PROGRAM; env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX; @@ -370,13 +370,13 @@ static inline void float_inexact_excp(CPUPPCState *env) { CPUState *cs = env_cpu(env); - env->fpscr |= 1 << FPSCR_FI; - env->fpscr |= 1 << FPSCR_XX; + env->fpscr |= FP_FI; + env->fpscr |= FP_XX; /* Update the floating-point exception summary */ env->fpscr |= FP_FX; if (fpscr_xe != 0) { /* Update the floating-point enabled exception summary */ - env->fpscr |= 1 << FPSCR_FEX; + env->fpscr |= FP_FEX; /* We must update the target FPR before raising the exception */ cs->exception_index = POWERPC_EXCP_PROGRAM; env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX; @@ -433,7 +433,7 @@ void helper_fpscr_clrbit(CPUPPCState *env, uint32_t bit) case FPSCR_VXCVI: if (!fpscr_ix) { /* Set VX bit to zero */ - env->fpscr &= ~(1 << FPSCR_VX); + env->fpscr &= ~FP_VX; } break; case FPSCR_OX: @@ -447,7 +447,7 @@ void helper_fpscr_clrbit(CPUPPCState *env, uint32_t bit) case FPSCR_XE: if (!fpscr_eex) { /* Set the FEX bit */ - env->fpscr &= ~(1 << FPSCR_FEX); + env->fpscr &= ~FP_FEX; } break; default: @@ -504,7 +504,7 @@ void helper_fpscr_setbit(CPUPPCState *env, uint32_t bit) case FPSCR_VXSOFT: case FPSCR_VXSQRT: case FPSCR_VXCVI: - env->fpscr |= 1 << FPSCR_VX; + env->fpscr |= FP_VX; env->fpscr |= FP_FX; if (fpscr_ve != 0) { goto raise_ve; @@ -580,7 +580,7 @@ void helper_fpscr_setbit(CPUPPCState *env, uint32_t bit) break; raise_excp: /* Update the floating-point enabled exception summary */ - env->fpscr |= 1 << FPSCR_FEX; + env->fpscr |= FP_FEX; /* We have to update Rc1 before raising the exception */ cs->exception_index = POWERPC_EXCP_PROGRAM; break; @@ -596,8 +596,8 @@ void helper_store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask) prev = env->fpscr; new = (target_ulong)arg; - new &= ~0x60000000LL; - new |= prev & 0x60000000LL; + new &= ~(FP_FEX | FP_VX); + new |= prev & (FP_FEX | FP_VX); for (i = 0; i < sizeof(target_ulong) * 2; i++) { if (mask & (1 << i)) { env->fpscr &= ~(0xFLL << (4 * i)); @@ -606,17 +606,17 @@ void helper_store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask) } /* Update VX and FEX */ if (fpscr_ix != 0) { - env->fpscr |= 1 << FPSCR_VX; + env->fpscr |= FP_VX; } else { - env->fpscr &= ~(1 << FPSCR_VX); + env->fpscr &= ~FP_VX; } if ((fpscr_ex & fpscr_eex) != 0) { - env->fpscr |= 1 << FPSCR_FEX; + env->fpscr |= FP_FEX; cs->exception_index = POWERPC_EXCP_PROGRAM; /* XXX: we should compute it properly */ env->error_code = POWERPC_EXCP_FP; } else { - env->fpscr &= ~(1 << FPSCR_FEX); + env->fpscr &= ~FP_FEX; } fpscr_set_rounding_mode(env); } @@ -639,7 +639,7 @@ static void do_float_check_status(CPUPPCState *env, uintptr_t raddr) if (status & float_flag_inexact) { float_inexact_excp(env); } else { - env->fpscr &= ~(1 << FPSCR_FI); /* clear the FPSCR[FI] bit */ + env->fpscr &= ~FP_FI; /* clear the FPSCR[FI] bit */ } if (cs->exception_index == POWERPC_EXCP_PROGRAM && @@ -1138,8 +1138,8 @@ void helper_fcmpu(CPUPPCState *env, uint64_t arg1, uint64_t arg2, ret = 0x02UL; } - env->fpscr &= ~(0x0F << FPSCR_FPRF); - env->fpscr |= ret << FPSCR_FPRF; + env->fpscr &= ~FP_FPCC; + env->fpscr |= ret << FPSCR_FPCC; env->crf[crfD] = ret; if (unlikely(ret == 0x01UL && (float64_is_signaling_nan(farg1.d, &env->fp_status) || @@ -1169,9 +1169,9 @@ void helper_fcmpo(CPUPPCState *env, uint64_t arg1, uint64_t arg2, ret = 0x02UL; } - env->fpscr &= ~(0x0F << FPSCR_FPRF); - env->fpscr |= ret << FPSCR_FPRF; - env->crf[crfD] = ret; + env->fpscr &= ~FP_FPCC; + env->fpscr |= ret << FPSCR_FPCC; + env->crf[crfD] = (uint32_t) ret; if (unlikely(ret == 0x01UL)) { float_invalid_op_vxvc(env, 1, GETPC()); if (float64_is_signaling_nan(farg1.d, &env->fp_status) || @@ -2431,8 +2431,8 @@ void helper_xscmpexpdp(CPUPPCState *env, uint32_t opcode, } } - env->fpscr &= ~(0x0F << FPSCR_FPRF); - env->fpscr |= cc << FPSCR_FPRF; + env->fpscr &= ~FP_FPCC; + env->fpscr |= cc << FPSCR_FPCC; env->crf[BF(opcode)] = cc; do_float_check_status(env, GETPC()); @@ -2460,8 +2460,8 @@ void helper_xscmpexpqp(CPUPPCState *env, uint32_t opcode, } } - env->fpscr &= ~(0x0F << FPSCR_FPRF); - env->fpscr |= cc << FPSCR_FPRF; + env->fpscr &= ~FP_FPCC; + env->fpscr |= cc << FPSCR_FPCC; env->crf[BF(opcode)] = cc; do_float_check_status(env, GETPC()); @@ -2505,8 +2505,8 @@ void helper_##op(CPUPPCState *env, uint32_t opcode, \ cc |= CRF_EQ; \ } \ \ - env->fpscr &= ~(0x0F << FPSCR_FPRF); \ - env->fpscr |= cc << FPSCR_FPRF; \ + env->fpscr &= ~FP_FPCC; \ + env->fpscr |= cc << FPSCR_FPCC; \ env->crf[BF(opcode)] = cc; \ \ do_float_check_status(env, GETPC()); \ @@ -2553,8 +2553,8 @@ void helper_##op(CPUPPCState *env, uint32_t opcode, \ cc |= CRF_EQ; \ } \ \ - env->fpscr &= ~(0x0F << FPSCR_FPRF); \ - env->fpscr |= cc << FPSCR_FPRF; \ + env->fpscr &= ~FP_FPCC; \ + env->fpscr |= cc << FPSCR_FPCC; \ env->crf[BF(opcode)] = cc; \ \ do_float_check_status(env, GETPC()); \ @@ -3242,8 +3242,8 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ \ if (scrf) { \ cc = sign << CRF_LT_BIT | match << CRF_EQ_BIT; \ - env->fpscr &= ~(0x0F << FPSCR_FPRF); \ - env->fpscr |= cc << FPSCR_FPRF; \ + env->fpscr &= ~FP_FPCC; \ + env->fpscr |= cc << FPSCR_FPCC; \ env->crf[BF(opcode)] = cc; \ } else { \ t.tfld = match ? fld_max : 0; \ @@ -3286,8 +3286,8 @@ void helper_xststdcsp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xb) &env->fp_status), &env->fp_status); cc = sign << CRF_LT_BIT | match << CRF_EQ_BIT | not_sp << CRF_SO_BIT; - env->fpscr &= ~(0x0F << FPSCR_FPRF); - env->fpscr |= cc << FPSCR_FPRF; + env->fpscr &= ~FP_FPCC; + env->fpscr |= cc << FPSCR_FPCC; env->crf[BF(opcode)] = cc; } From 972bd57689f1e11311d86b290134ea2ed9c7c11e Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Mon, 23 Sep 2019 18:41:10 +1000 Subject: [PATCH 14/53] ppc/kvm: Skip writing DPDES back when in run time state On POWER8 systems the Directed Privileged Door-bell Exception State register (DPDES) stores doorbell pending status, one bit per a thread of a core, set by "msgsndp" instruction. The register is shared among threads of the same core and KVM on POWER9 emulates it in a similar way (POWER9 does not have DPDES). DPDES is shared but QEMU assumes all SPRs are per thread so the only safe way to write DPDES back to VCPU before running a guest is doing so while all threads are pulled out of the guest so DPDES cannot change. There is only one situation when this condition is met: incoming migration when all threads are stopped. Otherwise any QEMU HMP/QMP command causing kvm_arch_put_registers() (for example printing registers or dumping memory) can clobber DPDES in a race with other vcpu threads. This changes DPDES handling so it is not written to KVM at runtime. Signed-off-by: Alexey Kardashevskiy Message-Id: <20190923084110.34643-1-aik@ozlabs.ru> Signed-off-by: David Gibson --- target/ppc/kvm.c | 5 +++++ target/ppc/translate_init.inc.c | 9 ++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index 8c5b1f25cc..820724cc7d 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -993,6 +993,10 @@ int kvm_arch_put_registers(CPUState *cs, int level) } kvm_set_one_reg(cs, KVM_REG_PPC_TB_OFFSET, &env->tb_env->tb_offset); + + if (level > KVM_PUT_RUNTIME_STATE) { + kvm_put_one_spr(cs, KVM_REG_PPC_DPDES, SPR_DPDES); + } #endif /* TARGET_PPC64 */ } @@ -1297,6 +1301,7 @@ int kvm_arch_get_registers(CPUState *cs) } kvm_get_one_reg(cs, KVM_REG_PPC_TB_OFFSET, &env->tb_env->tb_offset); + kvm_get_one_spr(cs, KVM_REG_PPC_DPDES, SPR_DPDES); #endif } diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c index 0fb11c7ac6..ba726dec4d 100644 --- a/target/ppc/translate_init.inc.c +++ b/target/ppc/translate_init.inc.c @@ -8200,11 +8200,10 @@ static void gen_spr_power8_dpdes(CPUPPCState *env) { #if !defined(CONFIG_USER_ONLY) /* Directed Privileged Door-bell Exception State, used for IPI */ - spr_register_kvm_hv(env, SPR_DPDES, "DPDES", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - KVM_REG_PPC_DPDES, 0x00000000); + spr_register(env, SPR_DPDES, "DPDES", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); #endif } From daa36379ce1a0a683562d40ca20f9b722ef595e1 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 28 Aug 2019 13:59:27 +1000 Subject: [PATCH 15/53] spapr: Simplify handling of pre ISA 3.0 guest workaround handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Certain old guest versions don't understand the radix MMU introduced with POWER ISA 3.0, but incorrectly select it if presented with the option at CAS time. We workaround this in qemu by explicitly excluding the radix (and other ISA 3.0 linked) options if the guest doesn't explicitly note support for ISA 3.0. This is handled by the 'cas_legacy_guest_workaround' flag, which is pretty vague. Rename it to 'cas_pre_isa3_guest' to be clearer about what it's for. In addition, we unnecessarily call spapr_populate_pa_features() with different options when initially constructing the device tree and when adjusting it at CAS time. At the initial construct time cas_pre_isa3_guest is already false, so we can still use the flag, rather than explicitly overriding it to be false at the callsite. Signed-off-by: David Gibson Reviewed-by: Cédric Le Goater Reviewed-by: Greg Kurz Reviewed-by: Alexey Kardashevskiy --- hw/ppc/spapr.c | 10 ++++------ hw/ppc/spapr_hcall.c | 3 +-- include/hw/ppc/spapr.h | 2 +- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 2725b139a7..b906ac6547 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -220,8 +220,7 @@ static int spapr_fixup_cpu_numa_dt(void *fdt, int offset, PowerPCCPU *cpu) /* Populate the "ibm,pa-features" property */ static void spapr_populate_pa_features(SpaprMachineState *spapr, PowerPCCPU *cpu, - void *fdt, int offset, - bool legacy_guest) + void *fdt, int offset) { uint8_t pa_features_206[] = { 6, 0, 0xf6, 0x1f, 0xc7, 0x00, 0x80, 0xc0 }; @@ -287,7 +286,7 @@ static void spapr_populate_pa_features(SpaprMachineState *spapr, if ((spapr_get_cap(spapr, SPAPR_CAP_HTM) != 0) && pa_size > 24) { pa_features[24] |= 0x80; /* Transactional memory support */ } - if (legacy_guest && pa_size > 40) { + if (spapr->cas_pre_isa3_guest && pa_size > 40) { /* Workaround for broken kernels that attempt (guest) radix * mode when they can't handle it, if they see the radix bit set * in pa-features. So hide it from them. */ @@ -350,8 +349,7 @@ static int spapr_fixup_cpu_dt(void *fdt, SpaprMachineState *spapr) return ret; } - spapr_populate_pa_features(spapr, cpu, fdt, offset, - spapr->cas_legacy_guest_workaround); + spapr_populate_pa_features(spapr, cpu, fdt, offset); } return ret; } @@ -553,7 +551,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset, page_sizes_prop, page_sizes_prop_size))); } - spapr_populate_pa_features(spapr, cpu, fdt, offset, false); + spapr_populate_pa_features(spapr, cpu, fdt, offset); _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", cs->cpu_index / vcpus_per_socket))); diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 23e4bdb829..3d3a67149a 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1765,8 +1765,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, exit(EXIT_FAILURE); } } - spapr->cas_legacy_guest_workaround = !spapr_ovec_test(ov1_guest, - OV1_PPC_3_00); + spapr->cas_pre_isa3_guest = !spapr_ovec_test(ov1_guest, OV1_PPC_3_00); spapr_ovec_cleanup(ov1_guest); if (!spapr->cas_reboot) { /* If spapr_machine_reset() did not set up a HPT but one is necessary diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 03111fd55b..dfec8e8e76 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -175,7 +175,7 @@ struct SpaprMachineState { /* ibm,client-architecture-support option negotiation */ bool cas_reboot; - bool cas_legacy_guest_workaround; + bool cas_pre_isa3_guest; SpaprOptionVector *ov5; /* QEMU-supported option vectors */ SpaprOptionVector *ov5_cas; /* negotiated (via CAS) option vectors */ uint32_t max_compat_pvr; From db5127b28ae1113bbc10f843d1cd219dc90a52d1 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Fri, 6 Sep 2019 14:48:28 +1000 Subject: [PATCH 16/53] spapr: Move handling of special NVLink numa node from reset to init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The number of NUMA nodes in the system is fixed from the command line. Therefore, there's no need to recalculate it at reset time, and we can determine the special gpu_numa_id value used for NVLink2 devices at init time. This simplifies the reset path a bit which will make further improvements easier. Signed-off-by: David Gibson Reviewed-by: Cédric Le Goater Reviewed-by: Greg Kurz Tested-by: Alexey Kardashevskiy Reviewed-by: Alexey Kardashevskiy --- hw/ppc/spapr.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index b906ac6547..7c3a443776 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1739,16 +1739,6 @@ static void spapr_machine_reset(MachineState *machine) spapr_setup_hpt_and_vrma(spapr); } - /* - * NVLink2-connected GPU RAM needs to be placed on a separate NUMA node. - * We assign a new numa ID per GPU in spapr_pci_collect_nvgpu() which is - * called from vPHB reset handler so we initialize the counter here. - * If no NUMA is configured from the QEMU side, we start from 1 as GPU RAM - * must be equally distant from any other node. - * The final value of spapr->gpu_numa_id is going to be written to - * max-associativity-domains in spapr_build_fdt(). - */ - spapr->gpu_numa_id = MAX(1, machine->numa_state->num_nodes); qemu_devices_reset(); /* @@ -2887,6 +2877,17 @@ static void spapr_machine_init(MachineState *machine) } + /* + * NVLink2-connected GPU RAM needs to be placed on a separate NUMA node. + * We assign a new numa ID per GPU in spapr_pci_collect_nvgpu() which is + * called from vPHB reset handler so we initialize the counter here. + * If no NUMA is configured from the QEMU side, we start from 1 as GPU RAM + * must be equally distant from any other node. + * The final value of spapr->gpu_numa_id is going to be written to + * max-associativity-domains in spapr_build_fdt(). + */ + spapr->gpu_numa_id = MAX(1, machine->numa_state->num_nodes); + if ((!kvm_enabled() || kvmppc_has_cap_mmu_radix()) && ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, 0, spapr->max_compat_pvr)) { From f767b1ac5766fcc48cc3939eeb7db7b95b98408b Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Fri, 23 Aug 2019 12:39:57 +1000 Subject: [PATCH 17/53] spapr: Fixes a leak in CAS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a missing g_free(fdt) if the resulting tree is bigger than the space allocated by SLOF. Signed-off-by: Alexey Kardashevskiy Signed-off-by: David Gibson Reviewed-by: Greg Kurz Reviewed-by: Cédric Le Goater --- hw/ppc/spapr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 7c3a443776..c69c034183 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1026,6 +1026,7 @@ int spapr_h_cas_compose_response(SpaprMachineState *spapr, _FDT((fdt_pack(fdt))); if (fdt_totalsize(fdt) + sizeof(hdr) > size) { + g_free(fdt); trace_spapr_cas_failed(size); return -1; } From 3a17e38f6eac0028f2e4ca052455b38a4048c85d Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Tue, 3 Sep 2019 12:34:34 +1000 Subject: [PATCH 18/53] spapr: Skip leading zeroes from memory@ DT node names The device tree build by QEMU at the machine reset time is used by SLOF to build its internal device tree but the node names are not preserved exactly so when QEMU provides a device tree update in response to H_CAS, it might become tricky to match a node from the update blob to the actual node in SLOF. This removed leading zeroes from "memory@" nodes and makes the DTC checker happy. Signed-off-by: Alexey Kardashevskiy Signed-off-by: David Gibson Reviewed-by: Greg Kurz --- hw/ppc/spapr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index c69c034183..42a5b8d2fd 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -388,7 +388,7 @@ static int spapr_populate_memory_node(void *fdt, int nodeid, hwaddr start, mem_reg_property[0] = cpu_to_be64(start); mem_reg_property[1] = cpu_to_be64(size); - sprintf(mem_name, "memory@" TARGET_FMT_lx, start); + sprintf(mem_name, "memory@%" HWADDR_PRIx, start); off = fdt_add_subnode(fdt, 0, mem_name); _FDT(off); _FDT((fdt_setprop_string(fdt, off, "device_type", "memory"))); From 5ced78955fe3f74002ad27676cf7c65cc89d6660 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Tue, 3 Sep 2019 12:35:33 +1000 Subject: [PATCH 19/53] spapr: Do not put empty properties for -kernel/-initrd/-append We are going to use spapr_build_fdt() for the boot time FDT and as an update for SLOF during handling of H_CAS. SLOF will apply all properties from the QEMU's FDT which is usually ok unless there are properties changed by grub or guest kernel. The properties are: bootargs, linux,initrd-start, linux,initrd-end, linux,stdout-path, linux,rtas-base, linux,rtas-entry. Resetting those during CAS will most likely cause grub failure. Don't create such properties if we're booting without "-kernel" and "-initrd" so they won't get included into the DT update blob and therefore the guest is more likely to boot successfully. Signed-off-by: Alexey Kardashevskiy [dwg: Tweaked commit message based on Greg Kurz's input] Signed-off-by: David Gibson --- hw/ppc/spapr.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 42a5b8d2fd..f1c57c21cc 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1179,11 +1179,16 @@ static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt) _FDT(chosen = fdt_add_subnode(fdt, 0, "chosen")); - _FDT(fdt_setprop_string(fdt, chosen, "bootargs", machine->kernel_cmdline)); - _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-start", - spapr->initrd_base)); - _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-end", - spapr->initrd_base + spapr->initrd_size)); + if (machine->kernel_cmdline && machine->kernel_cmdline[0]) { + _FDT(fdt_setprop_string(fdt, chosen, "bootargs", + machine->kernel_cmdline)); + } + if (spapr->initrd_size) { + _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-start", + spapr->initrd_base)); + _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-end", + spapr->initrd_base + spapr->initrd_size)); + } if (spapr->kernel_size) { uint64_t kprop[2] = { cpu_to_be64(KERNEL_LOAD_ADDR), From 744a928ccee92482385f58e835108aa6ebd54ecb Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Tue, 16 Jul 2019 15:27:43 +1000 Subject: [PATCH 20/53] spapr: Stop providing RTAS blob SLOF implements one itself so let's remove it from QEMU. It is one less image and simpler setup as the RTAS blob never stays in its initial place anyway as the guest OS always decides where to put it. Signed-off-by: Alexey Kardashevskiy Reviewed-by: Greg Kurz Signed-off-by: David Gibson --- MAINTAINERS | 2 -- Makefile | 2 +- configure | 6 +---- hw/ppc/spapr.c | 32 ++----------------------- hw/ppc/spapr_rtas.c | 41 -------------------------------- include/hw/ppc/spapr.h | 2 -- pc-bios/spapr-rtas.bin | Bin 20 -> 0 bytes pc-bios/spapr-rtas/Makefile | 27 --------------------- pc-bios/spapr-rtas/spapr-rtas.S | 37 ---------------------------- 9 files changed, 4 insertions(+), 145 deletions(-) delete mode 100644 pc-bios/spapr-rtas.bin delete mode 100644 pc-bios/spapr-rtas/Makefile delete mode 100644 pc-bios/spapr-rtas/spapr-rtas.S diff --git a/MAINTAINERS b/MAINTAINERS index 21264eae9c..3ca814850e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1077,8 +1077,6 @@ F: hw/*/spapr* F: include/hw/*/spapr* F: hw/*/xics* F: include/hw/*/xics* -F: pc-bios/spapr-rtas/* -F: pc-bios/spapr-rtas.bin F: pc-bios/slof.bin F: docs/specs/ppc-spapr-hcalls.txt F: docs/specs/ppc-spapr-hotplug.txt diff --git a/Makefile b/Makefile index 8da33595ed..30f0abfb42 100644 --- a/Makefile +++ b/Makefile @@ -769,7 +769,7 @@ qemu-nsis.bmp \ bamboo.dtb canyonlands.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \ multiboot.bin linuxboot.bin linuxboot_dma.bin kvmvapic.bin pvh.bin \ s390-ccw.img s390-netboot.img \ -spapr-rtas.bin slof.bin skiboot.lid \ +slof.bin skiboot.lid \ palcode-clipper \ u-boot.e500 u-boot-sam460-20100605.bin \ qemu_vga.ndrv \ diff --git a/configure b/configure index 8f8446f52b..08ca4bcb46 100755 --- a/configure +++ b/configure @@ -6166,9 +6166,6 @@ if { test "$cpu" = "i386" || test "$cpu" = "x86_64"; } && \ fi done fi -if test "$ARCH" = "ppc64" && test "$targetos" != "Darwin" ; then - roms="$roms spapr-rtas" -fi # Only build s390-ccw bios if we're on s390x and the compiler has -march=z900 if test "$cpu" = "s390x" ; then @@ -7800,13 +7797,12 @@ fi DIRS="tests tests/tcg tests/tcg/lm32 tests/libqos tests/qapi-schema tests/qemu-iotests tests/vm" DIRS="$DIRS tests/fp tests/qgraph" DIRS="$DIRS docs docs/interop fsdev scsi" -DIRS="$DIRS pc-bios/optionrom pc-bios/spapr-rtas pc-bios/s390-ccw" +DIRS="$DIRS pc-bios/optionrom pc-bios/s390-ccw" DIRS="$DIRS roms/seabios roms/vgabios" LINKS="Makefile" LINKS="$LINKS tests/tcg/lm32/Makefile po/Makefile" LINKS="$LINKS tests/tcg/Makefile.target tests/fp/Makefile" LINKS="$LINKS pc-bios/optionrom/Makefile pc-bios/keymaps" -LINKS="$LINKS pc-bios/spapr-rtas/Makefile" LINKS="$LINKS pc-bios/s390-ccw/Makefile" LINKS="$LINKS roms/seabios/Makefile roms/vgabios/Makefile" LINKS="$LINKS pc-bios/qemu-icon.bmp" diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index f1c57c21cc..3742a8cf06 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -96,7 +96,6 @@ * We load our kernel at 4M, leaving space for SLOF initial image */ #define FDT_MAX_SIZE 0x100000 -#define RTAS_MAX_SIZE 0x10000 #define RTAS_MAX_ADDR 0x80000000 /* RTAS must stay below that */ #define FW_MAX_SIZE 0x400000 #define FW_FILE_NAME "slof.bin" @@ -1723,8 +1722,7 @@ static void spapr_machine_reset(MachineState *machine) { SpaprMachineState *spapr = SPAPR_MACHINE(machine); PowerPCCPU *first_ppc_cpu; - uint32_t rtas_limit; - hwaddr rtas_addr, fdt_addr; + hwaddr fdt_addr; void *fdt; int rc; @@ -1788,14 +1786,10 @@ static void spapr_machine_reset(MachineState *machine) * or just below 2GB, whichever is lower, so that it can be * processed with 32-bit real mode code if necessary */ - rtas_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR); - rtas_addr = rtas_limit - RTAS_MAX_SIZE; - fdt_addr = rtas_addr - FDT_MAX_SIZE; + fdt_addr = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FDT_MAX_SIZE; fdt = spapr_build_fdt(spapr); - spapr_load_rtas(spapr, fdt, rtas_addr); - rc = fdt_pack(fdt); /* Should only fail if we've built a corrupted tree */ @@ -2955,28 +2949,6 @@ static void spapr_machine_init(MachineState *machine) spapr_create_lmb_dr_connectors(spapr); } - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin"); - if (!filename) { - error_report("Could not find LPAR rtas '%s'", "spapr-rtas.bin"); - exit(1); - } - spapr->rtas_size = get_image_size(filename); - if (spapr->rtas_size < 0) { - error_report("Could not get size of LPAR rtas '%s'", filename); - exit(1); - } - spapr->rtas_blob = g_malloc(spapr->rtas_size); - if (load_image_size(filename, spapr->rtas_blob, spapr->rtas_size) < 0) { - error_report("Could not load LPAR rtas '%s'", filename); - exit(1); - } - if (spapr->rtas_size > RTAS_MAX_SIZE) { - error_report("RTAS too big ! 0x%zx bytes (max is 0x%x)", - (size_t)spapr->rtas_size, RTAS_MAX_SIZE); - exit(1); - } - g_free(filename); - /* Set up RTAS event infrastructure */ spapr_events_init(spapr); diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index bee3835214..8d8d8cdfcb 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -477,47 +477,6 @@ void spapr_dt_rtas_tokens(void *fdt, int rtas) } } -void spapr_load_rtas(SpaprMachineState *spapr, void *fdt, hwaddr addr) -{ - int rtas_node; - int ret; - - /* Copy RTAS blob into guest RAM */ - cpu_physical_memory_write(addr, spapr->rtas_blob, spapr->rtas_size); - - ret = fdt_add_mem_rsv(fdt, addr, spapr->rtas_size); - if (ret < 0) { - error_report("Couldn't add RTAS reserve entry: %s", - fdt_strerror(ret)); - exit(1); - } - - /* Update the device tree with the blob's location */ - rtas_node = fdt_path_offset(fdt, "/rtas"); - assert(rtas_node >= 0); - - ret = fdt_setprop_cell(fdt, rtas_node, "linux,rtas-base", addr); - if (ret < 0) { - error_report("Couldn't add linux,rtas-base property: %s", - fdt_strerror(ret)); - exit(1); - } - - ret = fdt_setprop_cell(fdt, rtas_node, "linux,rtas-entry", addr); - if (ret < 0) { - error_report("Couldn't add linux,rtas-entry property: %s", - fdt_strerror(ret)); - exit(1); - } - - ret = fdt_setprop_cell(fdt, rtas_node, "rtas-size", spapr->rtas_size); - if (ret < 0) { - error_report("Couldn't add rtas-size property: %s", - fdt_strerror(ret)); - exit(1); - } -} - static void core_rtas_register_types(void) { spapr_rtas_register(RTAS_DISPLAY_CHARACTER, "display-character", diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index dfec8e8e76..cbd1a4c9f3 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -154,8 +154,6 @@ struct SpaprMachineState { hwaddr rma_size; int vrma_adjust; - ssize_t rtas_size; - void *rtas_blob; uint32_t fdt_size; uint32_t fdt_initial_size; void *fdt_blob; diff --git a/pc-bios/spapr-rtas.bin b/pc-bios/spapr-rtas.bin deleted file mode 100644 index fc24c8ed8b92a3a441aed6e2bd013b2ccece9229..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20 bcmbi{{=neEz@X&Uz@PvCJTV0q diff --git a/pc-bios/spapr-rtas/Makefile b/pc-bios/spapr-rtas/Makefile deleted file mode 100644 index 4b9bb12306..0000000000 --- a/pc-bios/spapr-rtas/Makefile +++ /dev/null @@ -1,27 +0,0 @@ -all: build-all -# Dummy command so that make thinks it has done something - @true - -include ../../config-host.mak -include $(SRC_PATH)/rules.mak - -$(call set-vpath, $(SRC_PATH)/pc-bios/spapr-rtas) - -.PHONY : all clean build-all - -#CFLAGS += -I$(SRC_PATH) -#QEMU_CFLAGS = $(CFLAGS) - -build-all: spapr-rtas.bin - -%.o: %.S - $(call quiet-command,$(CCAS) -mbig -c -o $@ $<,"CCAS","$(TARGET_DIR)$@") - -%.img: %.o - $(call quiet-command,$(CC) -nostdlib -mbig -o $@ $<,"Building","$(TARGET_DIR)$@") - -%.bin: %.img - $(call quiet-command,$(OBJCOPY) -O binary -j .text $< $@,"Building","$(TARGET_DIR)$@") - -clean: - rm -f *.o *.d *.img *.bin *~ diff --git a/pc-bios/spapr-rtas/spapr-rtas.S b/pc-bios/spapr-rtas/spapr-rtas.S deleted file mode 100644 index 903bec2150..0000000000 --- a/pc-bios/spapr-rtas/spapr-rtas.S +++ /dev/null @@ -1,37 +0,0 @@ -/* - * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator - * - * Trivial in-partition RTAS implementation, based on a hypercall - * - * 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. - * - */ - -#define KVMPPC_HCALL_BASE 0xf000 -#define KVMPPC_H_RTAS (KVMPPC_HCALL_BASE + 0x0) - -.globl _start -_start: - mr 4,3 - lis 3,KVMPPC_H_RTAS@h - ori 3,3,KVMPPC_H_RTAS@l - sc 1 - blr From 85164ad4ed9960cac842fa4cc067c6b6699b0994 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Wed, 11 Sep 2019 16:24:32 +1000 Subject: [PATCH 21/53] pseries: Update SLOF firmware image This fixes USB host bus adapter name in the device tree to match QEMU's one. Signed-off-by: Alexey Kardashevskiy Signed-off-by: David Gibson --- pc-bios/README | 2 +- pc-bios/slof.bin | Bin 930656 -> 930640 bytes roms/SLOF | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pc-bios/README b/pc-bios/README index ad78f6dc49..0b0b5d42ad 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -17,7 +17,7 @@ - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware implementation for certain IBM POWER hardware. The sources are at https://github.com/aik/SLOF, and the image currently in qemu is - built from git tag qemu-slof-20190827. + built from git tag qemu-slof-20190911. - sgabios (the Serial Graphics Adapter option ROM) provides a means for legacy x86 software to communicate with an attached serial console as diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin index a3a3e4933278461a08c8b58ad0da6741bb6b3d1b..2af0c5d5fc0c6aa06c34016f6deb767700ad4d3f 100644 GIT binary patch delta 329 zcmaFx%;Lf`iwWjp0qL0~x=G2&#>pnBrpZQziG``Tr3RA~8D-fNBsm4eR3;XP@Lb<` zv*14z0Hypk-dkiZfUL>D&@^rH1cxn57Qv|n3WkOXMh1qK3WjD@MkZE9hP+$~Zs7`H zsYS(^`FRSq3g}jXb=Nq1A0=CN`+p8bAZ7w$W*}w(Vpbq#+y0+}ed9$bjjSK(%0kNn zO^x%LuLq|Ec!*A#>F(@orJyl=tsb9j`}14uK+FNeoIuP4#N6AT-{P5Yo3n!f44A#A cH*Di|V=q=xC@oG>+J1K%Z+#8Rvgsum0R3EcBme*a delta 345 zcmccc%;Lc_iwWjp3F(<7x~YjqMuuhv28o7-W`(J_r3RA~8D-fNBstW@%qJFz@LZZ% z`13y$0Hypk-dkiZfUL>F!q{;01cxn57LKLq3P$D%Mh1qK3WjD@#^zQAmb_dFZs7`H zsYS(^`FRSq3g}jXb=Nq1A0=CN`+p8bAZ7w$W*}w(Vpbq#+y0+}ed9$bN9!%GngbU& zADehRaI;IBl7`udz3$G=Rtg%^=j!pvwm-kc4#XTl%n8I?K+L`U`7NFaw>f7pfB|## t^oDJ`ZsJM`rNv1~3PvfV1qvytWtqvTx_ODYsoT$P Date: Thu, 26 Sep 2019 19:57:55 +0100 Subject: [PATCH 22/53] target/ppc: introduce get_dfp{64,128}() helper functions The existing functions (now incorrectly) assume that the MSB and LSB of DFP numbers are stored as consecutive 64-bit words in memory. Instead of accessing the DFP numbers directly, introduce get_dfp{64,128}() helper functions to ease the switch to the correct representation. Signed-off-by: Mark Cave-Ayland Reviewed-by: Richard Henderson Message-Id: <20190926185801.11176-2-mark.cave-ayland@ilande.co.uk> Signed-off-by: David Gibson --- target/ppc/dfp_helper.c | 52 ++++++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/target/ppc/dfp_helper.c b/target/ppc/dfp_helper.c index 753399177c..e4369ebe9b 100644 --- a/target/ppc/dfp_helper.c +++ b/target/ppc/dfp_helper.c @@ -36,6 +36,17 @@ #define LO_IDX 0 #endif +static void get_dfp64(uint64_t *dst, uint64_t *dfp) +{ + dst[0] = dfp[0]; +} + +static void get_dfp128(uint64_t *dst, uint64_t *dfp) +{ + dst[0] = dfp[HI_IDX]; + dst[1] = dfp[LO_IDX]; +} + struct PPC_DFP { CPUPPCState *env; uint64_t t64[2], a64[2], b64[2]; @@ -129,7 +140,7 @@ static void dfp_prepare_decimal64(struct PPC_DFP *dfp, uint64_t *a, dfp->env = env; if (a) { - dfp->a64[0] = *a; + get_dfp64(dfp->a64, a); decimal64ToNumber((decimal64 *)dfp->a64, &dfp->a); } else { dfp->a64[0] = 0; @@ -137,7 +148,7 @@ static void dfp_prepare_decimal64(struct PPC_DFP *dfp, uint64_t *a, } if (b) { - dfp->b64[0] = *b; + get_dfp64(dfp->b64, b); decimal64ToNumber((decimal64 *)dfp->b64, &dfp->b); } else { dfp->b64[0] = 0; @@ -153,8 +164,7 @@ static void dfp_prepare_decimal128(struct PPC_DFP *dfp, uint64_t *a, dfp->env = env; if (a) { - dfp->a64[0] = a[HI_IDX]; - dfp->a64[1] = a[LO_IDX]; + get_dfp128(dfp->a64, a); decimal128ToNumber((decimal128 *)dfp->a64, &dfp->a); } else { dfp->a64[0] = dfp->a64[1] = 0; @@ -162,8 +172,7 @@ static void dfp_prepare_decimal128(struct PPC_DFP *dfp, uint64_t *a, } if (b) { - dfp->b64[0] = b[HI_IDX]; - dfp->b64[1] = b[LO_IDX]; + get_dfp128(dfp->b64, b); decimal128ToNumber((decimal128 *)dfp->b64, &dfp->b); } else { dfp->b64[0] = dfp->b64[1] = 0; @@ -617,10 +626,12 @@ uint32_t helper_##op(CPUPPCState *env, uint64_t *a, uint64_t *b) \ { \ struct PPC_DFP dfp; \ unsigned k; \ + uint64_t a64; \ \ dfp_prepare_decimal##size(&dfp, 0, b, env); \ \ - k = *a & 0x3F; \ + get_dfp64(&a64, a); \ + k = a64 & 0x3F; \ \ if (unlikely(decNumberIsSpecial(&dfp.b))) { \ dfp.crbf = 1; \ @@ -817,11 +828,15 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, \ uint64_t *b, uint32_t rmc) \ { \ struct PPC_DFP dfp; \ - int32_t ref_sig = *a & 0x3F; \ + uint64_t a64; \ + int32_t ref_sig; \ int32_t xmax = ((size) == 64) ? 369 : 6111; \ \ dfp_prepare_decimal##size(&dfp, 0, b, env); \ \ + get_dfp64(&a64, a); \ + ref_sig = a64 & 0x3f; \ + \ _dfp_reround(rmc, ref_sig, xmax, &dfp); \ decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \ &dfp.context); \ @@ -881,7 +896,12 @@ DFP_HELPER_RINT(drintnq, RINTN_PPs, 128) void helper_dctdp(CPUPPCState *env, uint64_t *t, uint64_t *b) { struct PPC_DFP dfp; - uint32_t b_short = *b; + uint64_t b64; + uint32_t b_short; + + get_dfp64(&b64, b); + b_short = (uint32_t)b64; + dfp_prepare_decimal64(&dfp, 0, 0, env); decimal32ToNumber((decimal32 *)&b_short, &dfp.t); decimal64FromNumber((decimal64 *)t, &dfp.t, &dfp.context); @@ -891,8 +911,10 @@ void helper_dctdp(CPUPPCState *env, uint64_t *t, uint64_t *b) void helper_dctqpq(CPUPPCState *env, uint64_t *t, uint64_t *b) { struct PPC_DFP dfp; + uint64_t b64; dfp_prepare_decimal128(&dfp, 0, 0, env); - decimal64ToNumber((decimal64 *)b, &dfp.t); + get_dfp64(&b64, b); + decimal64ToNumber((decimal64 *)&b64, &dfp.t); dfp_check_for_VXSNAN_and_convert_to_QNaN(&dfp); dfp_set_FPRF_from_FRT(&dfp); @@ -940,8 +962,10 @@ void helper_drdpq(CPUPPCState *env, uint64_t *t, uint64_t *b) void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b) \ { \ struct PPC_DFP dfp; \ + uint64_t b64; \ dfp_prepare_decimal##size(&dfp, 0, b, env); \ - decNumberFromInt64(&dfp.t, (int64_t)(*b)); \ + get_dfp64(&b64, b); \ + decNumberFromInt64(&dfp.t, (int64_t)b64); \ decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, &dfp.context); \ CFFIX_PPs(&dfp); \ \ @@ -1183,10 +1207,12 @@ static void dfp_set_raw_exp_128(uint64_t *t, uint64_t raw) void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, uint64_t *b) \ { \ struct PPC_DFP dfp; \ - uint64_t raw_qnan, raw_snan, raw_inf, max_exp; \ + uint64_t raw_qnan, raw_snan, raw_inf, max_exp, a64; \ int bias; \ - int64_t exp = *((int64_t *)a); \ + int64_t exp; \ \ + get_dfp64(&a64, a); \ + exp = (int64_t)a64; \ dfp_prepare_decimal##size(&dfp, 0, b, env); \ \ if ((size) == 64) { \ From 33432d7737b53c92791f90ece5dbe3b7bb1c79f5 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Thu, 26 Sep 2019 19:57:56 +0100 Subject: [PATCH 23/53] target/ppc: introduce set_dfp{64,128}() helper functions The existing functions (now incorrectly) assume that the MSB and LSB of DFP numbers are stored as consecutive 64-bit words in memory. Instead of accessing the DFP numbers directly, introduce set_dfp{64,128}() helper functions to ease the switch to the correct representation. Signed-off-by: Mark Cave-Ayland Reviewed-by: Richard Henderson Message-Id: <20190926185801.11176-3-mark.cave-ayland@ilande.co.uk> Signed-off-by: David Gibson --- target/ppc/dfp_helper.c | 90 ++++++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 42 deletions(-) diff --git a/target/ppc/dfp_helper.c b/target/ppc/dfp_helper.c index e4369ebe9b..3923a072b2 100644 --- a/target/ppc/dfp_helper.c +++ b/target/ppc/dfp_helper.c @@ -47,6 +47,17 @@ static void get_dfp128(uint64_t *dst, uint64_t *dfp) dst[1] = dfp[LO_IDX]; } +static void set_dfp64(uint64_t *dfp, uint64_t *src) +{ + dfp[0] = src[0]; +} + +static void set_dfp128(uint64_t *dfp, uint64_t *src) +{ + dfp[0] = src[HI_IDX]; + dfp[1] = src[LO_IDX]; +} + struct PPC_DFP { CPUPPCState *env; uint64_t t64[2], a64[2], b64[2]; @@ -413,10 +424,9 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, uint64_t *b) \ decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, &dfp.context); \ postprocs(&dfp); \ if (size == 64) { \ - t[0] = dfp.t64[0]; \ + set_dfp64(t, dfp.t64); \ } else if (size == 128) { \ - t[0] = dfp.t64[HI_IDX]; \ - t[1] = dfp.t64[LO_IDX]; \ + set_dfp128(t, dfp.t64); \ } \ } @@ -735,10 +745,9 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, \ QUA_PPs(&dfp); \ \ if (size == 64) { \ - t[0] = dfp.t64[0]; \ + set_dfp64(t, dfp.t64); \ } else if (size == 128) { \ - t[0] = dfp.t64[HI_IDX]; \ - t[1] = dfp.t64[LO_IDX]; \ + set_dfp128(t, dfp.t64); \ } \ } @@ -759,10 +768,9 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, \ QUA_PPs(&dfp); \ \ if (size == 64) { \ - t[0] = dfp.t64[0]; \ + set_dfp64(t, dfp.t64); \ } else if (size == 128) { \ - t[0] = dfp.t64[HI_IDX]; \ - t[1] = dfp.t64[LO_IDX]; \ + set_dfp128(t, dfp.t64); \ } \ } @@ -843,10 +851,9 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, \ QUA_PPs(&dfp); \ \ if (size == 64) { \ - t[0] = dfp.t64[0]; \ + set_dfp64(t, dfp.t64); \ } else if (size == 128) { \ - t[0] = dfp.t64[HI_IDX]; \ - t[1] = dfp.t64[LO_IDX]; \ + set_dfp128(t, dfp.t64); \ } \ } @@ -867,10 +874,9 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, \ postprocs(&dfp); \ \ if (size == 64) { \ - t[0] = dfp.t64[0]; \ + set_dfp64(t, dfp.t64); \ } else if (size == 128) { \ - t[0] = dfp.t64[HI_IDX]; \ - t[1] = dfp.t64[LO_IDX]; \ + set_dfp128(t, dfp.t64); \ } \ } @@ -904,7 +910,8 @@ void helper_dctdp(CPUPPCState *env, uint64_t *t, uint64_t *b) dfp_prepare_decimal64(&dfp, 0, 0, env); decimal32ToNumber((decimal32 *)&b_short, &dfp.t); - decimal64FromNumber((decimal64 *)t, &dfp.t, &dfp.context); + decimal64FromNumber((decimal64 *)&dfp.t64, &dfp.t, &dfp.context); + set_dfp64(t, dfp.t64); dfp_set_FPRF_from_FRT(&dfp); } @@ -920,14 +927,14 @@ void helper_dctqpq(CPUPPCState *env, uint64_t *t, uint64_t *b) dfp_set_FPRF_from_FRT(&dfp); decimal128FromNumber((decimal128 *)&dfp.t64, &dfp.t, &dfp.context); - t[0] = dfp.t64[HI_IDX]; - t[1] = dfp.t64[LO_IDX]; + set_dfp128(t, dfp.t64); } void helper_drsp(CPUPPCState *env, uint64_t *t, uint64_t *b) { struct PPC_DFP dfp; uint32_t t_short = 0; + uint64_t t64; dfp_prepare_decimal64(&dfp, 0, b, env); decimal32FromNumber((decimal32 *)&t_short, &dfp.b, &dfp.context); decimal32ToNumber((decimal32 *)&t_short, &dfp.t); @@ -937,7 +944,8 @@ void helper_drsp(CPUPPCState *env, uint64_t *t, uint64_t *b) dfp_check_for_UX(&dfp); dfp_check_for_XX(&dfp); - *t = t_short; + t64 = (uint64_t)t_short; + set_dfp64(t, &t64); } void helper_drdpq(CPUPPCState *env, uint64_t *t, uint64_t *b) @@ -953,9 +961,9 @@ void helper_drdpq(CPUPPCState *env, uint64_t *t, uint64_t *b) dfp_check_for_UX(&dfp); dfp_check_for_XX(&dfp); + dfp.t64[0] = dfp.t64[1] = 0; decimal64FromNumber((decimal64 *)dfp.t64, &dfp.t, &dfp.context); - t[0] = dfp.t64[0]; - t[1] = 0; + set_dfp128(t, dfp.t64); } #define DFP_HELPER_CFFIX(op, size) \ @@ -970,10 +978,9 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b) \ CFFIX_PPs(&dfp); \ \ if (size == 64) { \ - t[0] = dfp.t64[0]; \ + set_dfp64(t, dfp.t64); \ } else if (size == 128) { \ - t[0] = dfp.t64[HI_IDX]; \ - t[1] = dfp.t64[LO_IDX]; \ + set_dfp128(t, dfp.t64); \ } \ } @@ -1016,7 +1023,7 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b) \ } \ } \ \ - *t = dfp.t64[0]; \ + set_dfp64(t, dfp.t64); \ } DFP_HELPER_CTFIX(dctfix, 64) @@ -1078,10 +1085,9 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t sp) \ } \ \ if (size == 64) { \ - t[0] = dfp.t64[0]; \ + set_dfp64(t, dfp.t64); \ } else if (size == 128) { \ - t[0] = dfp.t64[HI_IDX]; \ - t[1] = dfp.t64[LO_IDX]; \ + set_dfp128(t, dfp.t64); \ } \ } @@ -1150,10 +1156,9 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t s) \ &dfp.context); \ dfp_set_FPRF_from_FRT(&dfp); \ if ((size) == 64) { \ - t[0] = dfp.t64[0]; \ + set_dfp64(t, dfp.t64); \ } else if ((size) == 128) { \ - t[0] = dfp.t64[HI_IDX]; \ - t[1] = dfp.t64[LO_IDX]; \ + set_dfp128(t, dfp.t64); \ } \ } @@ -1164,27 +1169,30 @@ DFP_HELPER_ENBCD(denbcdq, 128) void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b) \ { \ struct PPC_DFP dfp; \ + uint64_t t64; \ \ dfp_prepare_decimal##size(&dfp, 0, b, env); \ \ if (unlikely(decNumberIsSpecial(&dfp.b))) { \ if (decNumberIsInfinite(&dfp.b)) { \ - *t = -1; \ + t64 = -1; \ } else if (decNumberIsSNaN(&dfp.b)) { \ - *t = -3; \ + t64 = -3; \ } else if (decNumberIsQNaN(&dfp.b)) { \ - *t = -2; \ + t64 = -2; \ } else { \ assert(0); \ } \ + set_dfp64(t, &t64); \ } else { \ if ((size) == 64) { \ - *t = dfp.b.exponent + 398; \ + t64 = dfp.b.exponent + 398; \ } else if ((size) == 128) { \ - *t = dfp.b.exponent + 6176; \ + t64 = dfp.b.exponent + 6176; \ } else { \ assert(0); \ } \ + set_dfp64(t, &t64); \ } \ } @@ -1251,10 +1259,9 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, uint64_t *b) \ &dfp.context); \ } \ if (size == 64) { \ - t[0] = dfp.t64[0]; \ + set_dfp64(t, dfp.t64); \ } else if (size == 128) { \ - t[0] = dfp.t64[HI_IDX]; \ - t[1] = dfp.t64[LO_IDX]; \ + set_dfp128(t, dfp.t64); \ } \ } @@ -1344,10 +1351,9 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, \ } \ \ if ((size) == 64) { \ - t[0] = dfp.t64[0]; \ + set_dfp64(t, dfp.t64); \ } else { \ - t[0] = dfp.t64[HI_IDX]; \ - t[1] = dfp.t64[LO_IDX]; \ + set_dfp128(t, dfp.t64); \ } \ } From d9acba3130314e2e4239d39a99eeca147c255584 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Thu, 26 Sep 2019 19:57:57 +0100 Subject: [PATCH 24/53] target/ppc: update {get,set}_dfp{64,128}() helper functions to read/write DFP numbers correctly Since commit ef96e3ae96 "target/ppc: move FP and VMX registers into aligned vsr register array" FP registers are no longer stored consecutively in memory and so the current method of combining FP register pairs into DFP numbers is incorrect. Firstly update the definition of the dh_*_fprp defines in helper.h to reflect that FP registers are now stored as part of an array of ppc_vsr_t elements rather than plain uint64_t elements, and then introduce a new ppc_fprp_t type which conceptually represents a DFP even-odd register pair to be consumed by the DFP helper functions. Finally update the new DFP {get,set}_dfp{64,128}() helper functions to convert between DFP numbers and DFP even-odd register pairs correctly, making use of the existing VsrD() macro to access the correct elements regardless of host endian. Fixes: ef96e3ae96 "target/ppc: move FP and VMX registers into aligned vsr register array" Signed-off-by: Mark Cave-Ayland Reviewed-by: Richard Henderson Message-Id: <20190926185801.11176-4-mark.cave-ayland@ilande.co.uk> Signed-off-by: David Gibson --- target/ppc/cpu.h | 1 + target/ppc/dfp_helper.c | 80 +++++++++++++++++++++-------------------- target/ppc/helper.h | 2 +- 3 files changed, 44 insertions(+), 39 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index a23c6455b9..e3e82327b7 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -235,6 +235,7 @@ typedef union _ppc_vsr_t { } ppc_vsr_t; typedef ppc_vsr_t ppc_avr_t; +typedef ppc_vsr_t ppc_fprp_t; #if !defined(CONFIG_USER_ONLY) /* Software TLB cache */ diff --git a/target/ppc/dfp_helper.c b/target/ppc/dfp_helper.c index 3923a072b2..ab5e91d8ed 100644 --- a/target/ppc/dfp_helper.c +++ b/target/ppc/dfp_helper.c @@ -36,26 +36,26 @@ #define LO_IDX 0 #endif -static void get_dfp64(uint64_t *dst, uint64_t *dfp) +static void get_dfp64(uint64_t *dst, ppc_fprp_t *dfp) { - dst[0] = dfp[0]; + dst[0] = dfp->VsrD(0); } -static void get_dfp128(uint64_t *dst, uint64_t *dfp) +static void get_dfp128(uint64_t *dst, ppc_fprp_t *dfp) { - dst[0] = dfp[HI_IDX]; - dst[1] = dfp[LO_IDX]; + dst[HI_IDX] = dfp[0].VsrD(0); + dst[LO_IDX] = dfp[1].VsrD(0); } -static void set_dfp64(uint64_t *dfp, uint64_t *src) +static void set_dfp64(ppc_fprp_t *dfp, uint64_t *src) { - dfp[0] = src[0]; + dfp->VsrD(0) = src[0]; } -static void set_dfp128(uint64_t *dfp, uint64_t *src) +static void set_dfp128(ppc_fprp_t *dfp, uint64_t *src) { - dfp[0] = src[HI_IDX]; - dfp[1] = src[LO_IDX]; + dfp[0].VsrD(0) = src[HI_IDX]; + dfp[1].VsrD(0) = src[LO_IDX]; } struct PPC_DFP { @@ -143,8 +143,8 @@ static void dfp_set_round_mode_from_immediate(uint8_t r, uint8_t rmc, decContextSetRounding(&dfp->context, rnd); } -static void dfp_prepare_decimal64(struct PPC_DFP *dfp, uint64_t *a, - uint64_t *b, CPUPPCState *env) +static void dfp_prepare_decimal64(struct PPC_DFP *dfp, ppc_fprp_t *a, + ppc_fprp_t *b, CPUPPCState *env) { decContextDefault(&dfp->context, DEC_INIT_DECIMAL64); dfp_prepare_rounding_mode(&dfp->context, env->fpscr); @@ -167,8 +167,8 @@ static void dfp_prepare_decimal64(struct PPC_DFP *dfp, uint64_t *a, } } -static void dfp_prepare_decimal128(struct PPC_DFP *dfp, uint64_t *a, - uint64_t *b, CPUPPCState *env) +static void dfp_prepare_decimal128(struct PPC_DFP *dfp, ppc_fprp_t *a, + ppc_fprp_t *b, CPUPPCState *env) { decContextDefault(&dfp->context, DEC_INIT_DECIMAL128); dfp_prepare_rounding_mode(&dfp->context, env->fpscr); @@ -416,7 +416,8 @@ static inline int dfp_get_digit(decNumber *dn, int n) } #define DFP_HELPER_TAB(op, dnop, postprocs, size) \ -void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, uint64_t *b) \ +void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \ + ppc_fprp_t *b) \ { \ struct PPC_DFP dfp; \ dfp_prepare_decimal##size(&dfp, a, b, env); \ @@ -485,7 +486,7 @@ DFP_HELPER_TAB(ddiv, decNumberDivide, DIV_PPs, 64) DFP_HELPER_TAB(ddivq, decNumberDivide, DIV_PPs, 128) #define DFP_HELPER_BF_AB(op, dnop, postprocs, size) \ -uint32_t helper_##op(CPUPPCState *env, uint64_t *a, uint64_t *b) \ +uint32_t helper_##op(CPUPPCState *env, ppc_fprp_t *a, ppc_fprp_t *b) \ { \ struct PPC_DFP dfp; \ dfp_prepare_decimal##size(&dfp, a, b, env); \ @@ -517,7 +518,7 @@ DFP_HELPER_BF_AB(dcmpo, decNumberCompare, CMPO_PPs, 64) DFP_HELPER_BF_AB(dcmpoq, decNumberCompare, CMPO_PPs, 128) #define DFP_HELPER_TSTDC(op, size) \ -uint32_t helper_##op(CPUPPCState *env, uint64_t *a, uint32_t dcm) \ +uint32_t helper_##op(CPUPPCState *env, ppc_fprp_t *a, uint32_t dcm) \ { \ struct PPC_DFP dfp; \ int match = 0; \ @@ -545,7 +546,7 @@ DFP_HELPER_TSTDC(dtstdc, 64) DFP_HELPER_TSTDC(dtstdcq, 128) #define DFP_HELPER_TSTDG(op, size) \ -uint32_t helper_##op(CPUPPCState *env, uint64_t *a, uint32_t dcm) \ +uint32_t helper_##op(CPUPPCState *env, ppc_fprp_t *a, uint32_t dcm) \ { \ struct PPC_DFP dfp; \ int minexp, maxexp, nzero_digits, nzero_idx, is_negative, is_zero, \ @@ -600,7 +601,7 @@ DFP_HELPER_TSTDG(dtstdg, 64) DFP_HELPER_TSTDG(dtstdgq, 128) #define DFP_HELPER_TSTEX(op, size) \ -uint32_t helper_##op(CPUPPCState *env, uint64_t *a, uint64_t *b) \ +uint32_t helper_##op(CPUPPCState *env, ppc_fprp_t *a, ppc_fprp_t *b) \ { \ struct PPC_DFP dfp; \ int expa, expb, a_is_special, b_is_special; \ @@ -632,7 +633,7 @@ DFP_HELPER_TSTEX(dtstex, 64) DFP_HELPER_TSTEX(dtstexq, 128) #define DFP_HELPER_TSTSF(op, size) \ -uint32_t helper_##op(CPUPPCState *env, uint64_t *a, uint64_t *b) \ +uint32_t helper_##op(CPUPPCState *env, ppc_fprp_t *a, ppc_fprp_t *b) \ { \ struct PPC_DFP dfp; \ unsigned k; \ @@ -669,7 +670,7 @@ DFP_HELPER_TSTSF(dtstsf, 64) DFP_HELPER_TSTSF(dtstsfq, 128) #define DFP_HELPER_TSTSFI(op, size) \ -uint32_t helper_##op(CPUPPCState *env, uint32_t a, uint64_t *b) \ +uint32_t helper_##op(CPUPPCState *env, uint32_t a, ppc_fprp_t *b) \ { \ struct PPC_DFP dfp; \ unsigned uim; \ @@ -729,7 +730,7 @@ static void dfp_quantize(uint8_t rmc, struct PPC_DFP *dfp) } #define DFP_HELPER_QUAI(op, size) \ -void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, \ +void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \ uint32_t te, uint32_t rmc) \ { \ struct PPC_DFP dfp; \ @@ -755,8 +756,8 @@ DFP_HELPER_QUAI(dquai, 64) DFP_HELPER_QUAI(dquaiq, 128) #define DFP_HELPER_QUA(op, size) \ -void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, \ - uint64_t *b, uint32_t rmc) \ +void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \ + ppc_fprp_t *b, uint32_t rmc) \ { \ struct PPC_DFP dfp; \ \ @@ -832,8 +833,8 @@ static void _dfp_reround(uint8_t rmc, int32_t ref_sig, int32_t xmax, } #define DFP_HELPER_RRND(op, size) \ -void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, \ - uint64_t *b, uint32_t rmc) \ +void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \ + ppc_fprp_t *b, uint32_t rmc) \ { \ struct PPC_DFP dfp; \ uint64_t a64; \ @@ -861,7 +862,7 @@ DFP_HELPER_RRND(drrnd, 64) DFP_HELPER_RRND(drrndq, 128) #define DFP_HELPER_RINT(op, postprocs, size) \ -void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, \ +void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \ uint32_t r, uint32_t rmc) \ { \ struct PPC_DFP dfp; \ @@ -899,7 +900,7 @@ static void RINTN_PPs(struct PPC_DFP *dfp) DFP_HELPER_RINT(drintn, RINTN_PPs, 64) DFP_HELPER_RINT(drintnq, RINTN_PPs, 128) -void helper_dctdp(CPUPPCState *env, uint64_t *t, uint64_t *b) +void helper_dctdp(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) { struct PPC_DFP dfp; uint64_t b64; @@ -915,7 +916,7 @@ void helper_dctdp(CPUPPCState *env, uint64_t *t, uint64_t *b) dfp_set_FPRF_from_FRT(&dfp); } -void helper_dctqpq(CPUPPCState *env, uint64_t *t, uint64_t *b) +void helper_dctqpq(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) { struct PPC_DFP dfp; uint64_t b64; @@ -930,7 +931,7 @@ void helper_dctqpq(CPUPPCState *env, uint64_t *t, uint64_t *b) set_dfp128(t, dfp.t64); } -void helper_drsp(CPUPPCState *env, uint64_t *t, uint64_t *b) +void helper_drsp(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) { struct PPC_DFP dfp; uint32_t t_short = 0; @@ -948,7 +949,7 @@ void helper_drsp(CPUPPCState *env, uint64_t *t, uint64_t *b) set_dfp64(t, &t64); } -void helper_drdpq(CPUPPCState *env, uint64_t *t, uint64_t *b) +void helper_drdpq(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) { struct PPC_DFP dfp; dfp_prepare_decimal128(&dfp, 0, b, env); @@ -967,7 +968,7 @@ void helper_drdpq(CPUPPCState *env, uint64_t *t, uint64_t *b) } #define DFP_HELPER_CFFIX(op, size) \ -void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b) \ +void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) \ { \ struct PPC_DFP dfp; \ uint64_t b64; \ @@ -994,7 +995,7 @@ DFP_HELPER_CFFIX(dcffix, 64) DFP_HELPER_CFFIX(dcffixq, 128) #define DFP_HELPER_CTFIX(op, size) \ -void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b) \ +void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) \ { \ struct PPC_DFP dfp; \ dfp_prepare_decimal##size(&dfp, 0, b, env); \ @@ -1057,7 +1058,8 @@ static inline void dfp_set_sign_128(uint64_t *t, uint8_t sgn) } #define DFP_HELPER_DEDPD(op, size) \ -void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t sp) \ +void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \ + uint32_t sp) \ { \ struct PPC_DFP dfp; \ uint8_t digits[34]; \ @@ -1105,7 +1107,8 @@ static inline uint8_t dfp_get_bcd_digit_128(uint64_t *t, unsigned n) } #define DFP_HELPER_ENBCD(op, size) \ -void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t s) \ +void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \ + uint32_t s) \ { \ struct PPC_DFP dfp; \ uint8_t digits[32]; \ @@ -1166,7 +1169,7 @@ DFP_HELPER_ENBCD(denbcd, 64) DFP_HELPER_ENBCD(denbcdq, 128) #define DFP_HELPER_XEX(op, size) \ -void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b) \ +void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) \ { \ struct PPC_DFP dfp; \ uint64_t t64; \ @@ -1212,7 +1215,8 @@ static void dfp_set_raw_exp_128(uint64_t *t, uint64_t raw) } #define DFP_HELPER_IEX(op, size) \ -void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, uint64_t *b) \ +void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \ + ppc_fprp_t *b) \ { \ struct PPC_DFP dfp; \ uint64_t raw_qnan, raw_snan, raw_inf, max_exp, a64; \ @@ -1309,7 +1313,7 @@ static void dfp_clear_lmd_from_g5msb(uint64_t *t) } #define DFP_HELPER_SHIFT(op, size, shift_left) \ -void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, \ +void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \ uint32_t sh) \ { \ struct PPC_DFP dfp; \ diff --git a/target/ppc/helper.h b/target/ppc/helper.h index 54ea9b9500..f843814b8a 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -686,7 +686,7 @@ DEF_HELPER_3(store_601_batu, void, env, i32, tl) #endif #define dh_alias_fprp ptr -#define dh_ctype_fprp uint64_t * +#define dh_ctype_fprp ppc_fprp_t * #define dh_is_signed_fprp dh_is_signed_ptr DEF_HELPER_4(dadd, void, env, fprp, fprp, fprp) From 474c2e931d51bad00c20c65d6fe478a9391e5e2a Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Thu, 26 Sep 2019 19:57:58 +0100 Subject: [PATCH 25/53] target/ppc: introduce dfp_finalize_decimal{64,128}() helper functions Most of the DFP helper functions call decimal{64,128}FromNumber() just before returning in order to convert the decNumber stored in dfp.t64 back to a Decimal{64,128} to write back to the FP registers. Introduce new dfp_finalize_decimal{64,128}() helper functions which both enable the parameter list to be reduced considerably, and also help minimise the changes required in the next patch. Signed-off-by: Mark Cave-Ayland Reviewed-by: Richard Henderson Message-Id: <20190926185801.11176-5-mark.cave-ayland@ilande.co.uk> Signed-off-by: David Gibson --- target/ppc/dfp_helper.c | 42 ++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/target/ppc/dfp_helper.c b/target/ppc/dfp_helper.c index ab5e91d8ed..8e1ea2971a 100644 --- a/target/ppc/dfp_helper.c +++ b/target/ppc/dfp_helper.c @@ -191,6 +191,16 @@ static void dfp_prepare_decimal128(struct PPC_DFP *dfp, ppc_fprp_t *a, } } +static void dfp_finalize_decimal64(struct PPC_DFP *dfp) +{ + decimal64FromNumber((decimal64 *)&dfp->t64, &dfp->t, &dfp->context); +} + +static void dfp_finalize_decimal128(struct PPC_DFP *dfp) +{ + decimal128FromNumber((decimal128 *)&dfp->t64, &dfp->t, &dfp->context); +} + static void dfp_set_FPSCR_flag(struct PPC_DFP *dfp, uint64_t flag, uint64_t enabled) { @@ -422,7 +432,7 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \ struct PPC_DFP dfp; \ dfp_prepare_decimal##size(&dfp, a, b, env); \ dnop(&dfp.t, &dfp.a, &dfp.b, &dfp.context); \ - decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, &dfp.context); \ + dfp_finalize_decimal##size(&dfp); \ postprocs(&dfp); \ if (size == 64) { \ set_dfp64(t, dfp.t64); \ @@ -491,7 +501,7 @@ uint32_t helper_##op(CPUPPCState *env, ppc_fprp_t *a, ppc_fprp_t *b) \ struct PPC_DFP dfp; \ dfp_prepare_decimal##size(&dfp, a, b, env); \ dnop(&dfp.t, &dfp.a, &dfp.b, &dfp.context); \ - decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, &dfp.context); \ + dfp_finalize_decimal##size(&dfp); \ postprocs(&dfp); \ return dfp.crbf; \ } @@ -741,8 +751,7 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \ dfp.a.exponent = (int32_t)((int8_t)(te << 3) >> 3); \ \ dfp_quantize(rmc, &dfp); \ - decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \ - &dfp.context); \ + dfp_finalize_decimal##size(&dfp); \ QUA_PPs(&dfp); \ \ if (size == 64) { \ @@ -764,8 +773,7 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \ dfp_prepare_decimal##size(&dfp, a, b, env); \ \ dfp_quantize(rmc, &dfp); \ - decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \ - &dfp.context); \ + dfp_finalize_decimal##size(&dfp); \ QUA_PPs(&dfp); \ \ if (size == 64) { \ @@ -847,8 +855,7 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \ ref_sig = a64 & 0x3f; \ \ _dfp_reround(rmc, ref_sig, xmax, &dfp); \ - decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \ - &dfp.context); \ + dfp_finalize_decimal##size(&dfp); \ QUA_PPs(&dfp); \ \ if (size == 64) { \ @@ -871,7 +878,7 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \ \ dfp_set_round_mode_from_immediate(r, rmc, &dfp); \ decNumberToIntegralExact(&dfp.t, &dfp.b, &dfp.context); \ - decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, &dfp.context); \ + dfp_finalize_decimal##size(&dfp); \ postprocs(&dfp); \ \ if (size == 64) { \ @@ -911,7 +918,7 @@ void helper_dctdp(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) dfp_prepare_decimal64(&dfp, 0, 0, env); decimal32ToNumber((decimal32 *)&b_short, &dfp.t); - decimal64FromNumber((decimal64 *)&dfp.t64, &dfp.t, &dfp.context); + dfp_finalize_decimal64(&dfp); set_dfp64(t, dfp.t64); dfp_set_FPRF_from_FRT(&dfp); } @@ -927,7 +934,7 @@ void helper_dctqpq(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) dfp_check_for_VXSNAN_and_convert_to_QNaN(&dfp); dfp_set_FPRF_from_FRT(&dfp); - decimal128FromNumber((decimal128 *)&dfp.t64, &dfp.t, &dfp.context); + dfp_finalize_decimal128(&dfp); set_dfp128(t, dfp.t64); } @@ -963,7 +970,7 @@ void helper_drdpq(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) dfp_check_for_XX(&dfp); dfp.t64[0] = dfp.t64[1] = 0; - decimal64FromNumber((decimal64 *)dfp.t64, &dfp.t, &dfp.context); + dfp_finalize_decimal64(&dfp); set_dfp128(t, dfp.t64); } @@ -975,7 +982,7 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) \ dfp_prepare_decimal##size(&dfp, 0, b, env); \ get_dfp64(&b64, b); \ decNumberFromInt64(&dfp.t, (int64_t)b64); \ - decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, &dfp.context); \ + dfp_finalize_decimal##size(&dfp); \ CFFIX_PPs(&dfp); \ \ if (size == 64) { \ @@ -1155,8 +1162,7 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \ if (s && sgn) { \ dfp.t.bits |= DECNEG; \ } \ - decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \ - &dfp.context); \ + dfp_finalize_decimal##size(&dfp); \ dfp_set_FPRF_from_FRT(&dfp); \ if ((size) == 64) { \ set_dfp64(t, dfp.t64); \ @@ -1259,8 +1265,7 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \ dfp.t.bits &= ~DECSPECIAL; \ } \ dfp.t.exponent = exp - bias; \ - decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \ - &dfp.context); \ + dfp_finalize_decimal##size(&dfp); \ } \ if (size == 64) { \ set_dfp64(t, dfp.t64); \ @@ -1340,8 +1345,7 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \ dfp.t.digits = max_digits - 1; \ } \ \ - decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \ - &dfp.context); \ + dfp_finalize_decimal##size(&dfp); \ } else { \ if ((size) == 64) { \ dfp.t64[0] = dfp.a64[0] & 0xFFFC000000000000ULL; \ From 64b8574e143f2287009ad77a12b87e64516a0711 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Thu, 26 Sep 2019 19:57:59 +0100 Subject: [PATCH 26/53] target/ppc: change struct PPC_DFP decimal storage from uint64[2] to ppc_vsr_t There are several places in dfp_helper.c that access the decimal number representations in struct PPC_DFP via HI_IDX and LO_IDX defines which are set at the top of dfp_helper.c according to the host endian. However we can instead switch to using ppc_vsr_t for decimal numbers and then make subsequent use of the existing VsrD() macros to access the correct element regardless of host endian. Note that 64-bit decimals are stored in the LSB of ppc_vsr_t (equivalent to VsrD(1)). Signed-off-by: Mark Cave-Ayland Reviewed-by: Richard Henderson Message-Id: <20190926185801.11176-6-mark.cave-ayland@ilande.co.uk> Signed-off-by: David Gibson --- target/ppc/dfp_helper.c | 210 +++++++++++++++++++++------------------- 1 file changed, 108 insertions(+), 102 deletions(-) diff --git a/target/ppc/dfp_helper.c b/target/ppc/dfp_helper.c index 8e1ea2971a..b72084d50a 100644 --- a/target/ppc/dfp_helper.c +++ b/target/ppc/dfp_helper.c @@ -36,31 +36,31 @@ #define LO_IDX 0 #endif -static void get_dfp64(uint64_t *dst, ppc_fprp_t *dfp) +static void get_dfp64(ppc_vsr_t *dst, ppc_fprp_t *dfp) { - dst[0] = dfp->VsrD(0); + dst->VsrD(1) = dfp->VsrD(0); } -static void get_dfp128(uint64_t *dst, ppc_fprp_t *dfp) +static void get_dfp128(ppc_vsr_t *dst, ppc_fprp_t *dfp) { - dst[HI_IDX] = dfp[0].VsrD(0); - dst[LO_IDX] = dfp[1].VsrD(0); + dst->VsrD(0) = dfp[0].VsrD(0); + dst->VsrD(1) = dfp[1].VsrD(0); } -static void set_dfp64(ppc_fprp_t *dfp, uint64_t *src) +static void set_dfp64(ppc_fprp_t *dfp, ppc_vsr_t *src) { - dfp->VsrD(0) = src[0]; + dfp->VsrD(0) = src->VsrD(1); } -static void set_dfp128(ppc_fprp_t *dfp, uint64_t *src) +static void set_dfp128(ppc_fprp_t *dfp, ppc_vsr_t *src) { - dfp[0].VsrD(0) = src[HI_IDX]; - dfp[1].VsrD(0) = src[LO_IDX]; + dfp[0].VsrD(0) = src->VsrD(0); + dfp[1].VsrD(0) = src->VsrD(1); } struct PPC_DFP { CPUPPCState *env; - uint64_t t64[2], a64[2], b64[2]; + ppc_vsr_t vt, va, vb; decNumber t, a, b; decContext context; uint8_t crbf; @@ -151,18 +151,18 @@ static void dfp_prepare_decimal64(struct PPC_DFP *dfp, ppc_fprp_t *a, dfp->env = env; if (a) { - get_dfp64(dfp->a64, a); - decimal64ToNumber((decimal64 *)dfp->a64, &dfp->a); + get_dfp64(&dfp->va, a); + decimal64ToNumber((decimal64 *)&dfp->va.VsrD(1), &dfp->a); } else { - dfp->a64[0] = 0; + dfp->va.VsrD(1) = 0; decNumberZero(&dfp->a); } if (b) { - get_dfp64(dfp->b64, b); - decimal64ToNumber((decimal64 *)dfp->b64, &dfp->b); + get_dfp64(&dfp->vb, b); + decimal64ToNumber((decimal64 *)&dfp->vb.VsrD(1), &dfp->b); } else { - dfp->b64[0] = 0; + dfp->vb.VsrD(1) = 0; decNumberZero(&dfp->b); } } @@ -175,30 +175,30 @@ static void dfp_prepare_decimal128(struct PPC_DFP *dfp, ppc_fprp_t *a, dfp->env = env; if (a) { - get_dfp128(dfp->a64, a); - decimal128ToNumber((decimal128 *)dfp->a64, &dfp->a); + get_dfp128(&dfp->va, a); + decimal128ToNumber((decimal128 *)&dfp->va, &dfp->a); } else { - dfp->a64[0] = dfp->a64[1] = 0; + dfp->va.VsrD(0) = dfp->va.VsrD(1) = 0; decNumberZero(&dfp->a); } if (b) { - get_dfp128(dfp->b64, b); - decimal128ToNumber((decimal128 *)dfp->b64, &dfp->b); + get_dfp128(&dfp->vb, b); + decimal128ToNumber((decimal128 *)&dfp->vb, &dfp->b); } else { - dfp->b64[0] = dfp->b64[1] = 0; + dfp->vb.VsrD(0) = dfp->vb.VsrD(1) = 0; decNumberZero(&dfp->b); } } static void dfp_finalize_decimal64(struct PPC_DFP *dfp) { - decimal64FromNumber((decimal64 *)&dfp->t64, &dfp->t, &dfp->context); + decimal64FromNumber((decimal64 *)&dfp->vt.VsrD(1), &dfp->t, &dfp->context); } static void dfp_finalize_decimal128(struct PPC_DFP *dfp) { - decimal128FromNumber((decimal128 *)&dfp->t64, &dfp->t, &dfp->context); + decimal128FromNumber((decimal128 *)&dfp->vt, &dfp->t, &dfp->context); } static void dfp_set_FPSCR_flag(struct PPC_DFP *dfp, uint64_t flag, @@ -435,9 +435,9 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \ dfp_finalize_decimal##size(&dfp); \ postprocs(&dfp); \ if (size == 64) { \ - set_dfp64(t, dfp.t64); \ + set_dfp64(t, &dfp.vt); \ } else if (size == 128) { \ - set_dfp128(t, dfp.t64); \ + set_dfp128(t, &dfp.vt); \ } \ } @@ -647,12 +647,12 @@ uint32_t helper_##op(CPUPPCState *env, ppc_fprp_t *a, ppc_fprp_t *b) \ { \ struct PPC_DFP dfp; \ unsigned k; \ - uint64_t a64; \ + ppc_vsr_t va; \ \ dfp_prepare_decimal##size(&dfp, 0, b, env); \ \ - get_dfp64(&a64, a); \ - k = a64 & 0x3F; \ + get_dfp64(&va, a); \ + k = va.VsrD(1) & 0x3F; \ \ if (unlikely(decNumberIsSpecial(&dfp.b))) { \ dfp.crbf = 1; \ @@ -755,9 +755,9 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \ QUA_PPs(&dfp); \ \ if (size == 64) { \ - set_dfp64(t, dfp.t64); \ + set_dfp64(t, &dfp.vt); \ } else if (size == 128) { \ - set_dfp128(t, dfp.t64); \ + set_dfp128(t, &dfp.vt); \ } \ } @@ -777,9 +777,9 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \ QUA_PPs(&dfp); \ \ if (size == 64) { \ - set_dfp64(t, dfp.t64); \ + set_dfp64(t, &dfp.vt); \ } else if (size == 128) { \ - set_dfp128(t, dfp.t64); \ + set_dfp128(t, &dfp.vt); \ } \ } @@ -845,23 +845,23 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \ ppc_fprp_t *b, uint32_t rmc) \ { \ struct PPC_DFP dfp; \ - uint64_t a64; \ + ppc_vsr_t va; \ int32_t ref_sig; \ int32_t xmax = ((size) == 64) ? 369 : 6111; \ \ dfp_prepare_decimal##size(&dfp, 0, b, env); \ \ - get_dfp64(&a64, a); \ - ref_sig = a64 & 0x3f; \ + get_dfp64(&va, a); \ + ref_sig = va.VsrD(1) & 0x3f; \ \ _dfp_reround(rmc, ref_sig, xmax, &dfp); \ dfp_finalize_decimal##size(&dfp); \ QUA_PPs(&dfp); \ \ if (size == 64) { \ - set_dfp64(t, dfp.t64); \ + set_dfp64(t, &dfp.vt); \ } else if (size == 128) { \ - set_dfp128(t, dfp.t64); \ + set_dfp128(t, &dfp.vt); \ } \ } @@ -882,9 +882,9 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \ postprocs(&dfp); \ \ if (size == 64) { \ - set_dfp64(t, dfp.t64); \ + set_dfp64(t, &dfp.vt); \ } else if (size == 128) { \ - set_dfp128(t, dfp.t64); \ + set_dfp128(t, &dfp.vt); \ } \ } @@ -910,39 +910,39 @@ DFP_HELPER_RINT(drintnq, RINTN_PPs, 128) void helper_dctdp(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) { struct PPC_DFP dfp; - uint64_t b64; + ppc_vsr_t vb; uint32_t b_short; - get_dfp64(&b64, b); - b_short = (uint32_t)b64; + get_dfp64(&vb, b); + b_short = (uint32_t)vb.VsrD(1); dfp_prepare_decimal64(&dfp, 0, 0, env); decimal32ToNumber((decimal32 *)&b_short, &dfp.t); dfp_finalize_decimal64(&dfp); - set_dfp64(t, dfp.t64); + set_dfp64(t, &dfp.vt); dfp_set_FPRF_from_FRT(&dfp); } void helper_dctqpq(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) { struct PPC_DFP dfp; - uint64_t b64; + ppc_vsr_t vb; dfp_prepare_decimal128(&dfp, 0, 0, env); - get_dfp64(&b64, b); - decimal64ToNumber((decimal64 *)&b64, &dfp.t); + get_dfp64(&vb, b); + decimal64ToNumber((decimal64 *)&vb.VsrD(1), &dfp.t); dfp_check_for_VXSNAN_and_convert_to_QNaN(&dfp); dfp_set_FPRF_from_FRT(&dfp); dfp_finalize_decimal128(&dfp); - set_dfp128(t, dfp.t64); + set_dfp128(t, &dfp.vt); } void helper_drsp(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) { struct PPC_DFP dfp; uint32_t t_short = 0; - uint64_t t64; + ppc_vsr_t vt; dfp_prepare_decimal64(&dfp, 0, b, env); decimal32FromNumber((decimal32 *)&t_short, &dfp.b, &dfp.context); decimal32ToNumber((decimal32 *)&t_short, &dfp.t); @@ -952,16 +952,16 @@ void helper_drsp(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) dfp_check_for_UX(&dfp); dfp_check_for_XX(&dfp); - t64 = (uint64_t)t_short; - set_dfp64(t, &t64); + vt.VsrD(1) = (uint64_t)t_short; + set_dfp64(t, &vt); } void helper_drdpq(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) { struct PPC_DFP dfp; dfp_prepare_decimal128(&dfp, 0, b, env); - decimal64FromNumber((decimal64 *)&dfp.t64, &dfp.b, &dfp.context); - decimal64ToNumber((decimal64 *)&dfp.t64, &dfp.t); + decimal64FromNumber((decimal64 *)&dfp.vt.VsrD(1), &dfp.b, &dfp.context); + decimal64ToNumber((decimal64 *)&dfp.vt.VsrD(1), &dfp.t); dfp_check_for_VXSNAN_and_convert_to_QNaN(&dfp); dfp_set_FPRF_from_FRT_long(&dfp); @@ -969,26 +969,26 @@ void helper_drdpq(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) dfp_check_for_UX(&dfp); dfp_check_for_XX(&dfp); - dfp.t64[0] = dfp.t64[1] = 0; + dfp.vt.VsrD(0) = dfp.vt.VsrD(1) = 0; dfp_finalize_decimal64(&dfp); - set_dfp128(t, dfp.t64); + set_dfp128(t, &dfp.vt); } #define DFP_HELPER_CFFIX(op, size) \ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) \ { \ struct PPC_DFP dfp; \ - uint64_t b64; \ + ppc_vsr_t vb; \ dfp_prepare_decimal##size(&dfp, 0, b, env); \ - get_dfp64(&b64, b); \ - decNumberFromInt64(&dfp.t, (int64_t)b64); \ + get_dfp64(&vb, b); \ + decNumberFromInt64(&dfp.t, (int64_t)vb.VsrD(1)); \ dfp_finalize_decimal##size(&dfp); \ CFFIX_PPs(&dfp); \ \ if (size == 64) { \ - set_dfp64(t, dfp.t64); \ + set_dfp64(t, &dfp.vt); \ } else if (size == 128) { \ - set_dfp128(t, dfp.t64); \ + set_dfp128(t, &dfp.vt); \ } \ } @@ -1010,28 +1010,30 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) \ if (unlikely(decNumberIsSpecial(&dfp.b))) { \ uint64_t invalid_flags = FP_VX | FP_VXCVI; \ if (decNumberIsInfinite(&dfp.b)) { \ - dfp.t64[0] = decNumberIsNegative(&dfp.b) ? INT64_MIN : INT64_MAX; \ + dfp.vt.VsrD(1) = decNumberIsNegative(&dfp.b) ? INT64_MIN : \ + INT64_MAX; \ } else { /* NaN */ \ - dfp.t64[0] = INT64_MIN; \ + dfp.vt.VsrD(1) = INT64_MIN; \ if (decNumberIsSNaN(&dfp.b)) { \ invalid_flags |= FP_VXSNAN; \ } \ } \ dfp_set_FPSCR_flag(&dfp, invalid_flags, FP_VE); \ } else if (unlikely(decNumberIsZero(&dfp.b))) { \ - dfp.t64[0] = 0; \ + dfp.vt.VsrD(1) = 0; \ } else { \ decNumberToIntegralExact(&dfp.b, &dfp.b, &dfp.context); \ - dfp.t64[0] = decNumberIntegralToInt64(&dfp.b, &dfp.context); \ + dfp.vt.VsrD(1) = decNumberIntegralToInt64(&dfp.b, &dfp.context); \ if (decContextTestStatus(&dfp.context, DEC_Invalid_operation)) { \ - dfp.t64[0] = decNumberIsNegative(&dfp.b) ? INT64_MIN : INT64_MAX; \ + dfp.vt.VsrD(1) = decNumberIsNegative(&dfp.b) ? INT64_MIN : \ + INT64_MAX; \ dfp_set_FPSCR_flag(&dfp, FP_VX | FP_VXCVI, FP_VE); \ } else { \ dfp_check_for_XX(&dfp); \ } \ } \ \ - set_dfp64(t, dfp.t64); \ + set_dfp64(t, &dfp.vt); \ } DFP_HELPER_CTFIX(dctfix, 64) @@ -1075,11 +1077,11 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \ dfp_prepare_decimal##size(&dfp, 0, b, env); \ \ decNumberGetBCD(&dfp.b, digits); \ - dfp.t64[0] = dfp.t64[1] = 0; \ + dfp.vt.VsrD(0) = dfp.vt.VsrD(1) = 0; \ N = dfp.b.digits; \ \ for (i = 0; (i < N) && (i < (size)/4); i++) { \ - dfp_set_bcd_digit_##size(dfp.t64, digits[N-i-1], i); \ + dfp_set_bcd_digit_##size(&dfp.vt.u64[0], digits[N - i - 1], i); \ } \ \ if (sp & 2) { \ @@ -1090,13 +1092,13 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \ } else { \ sgn = ((sp & 1) ? 0xF : 0xC); \ } \ - dfp_set_sign_##size(dfp.t64, sgn); \ + dfp_set_sign_##size(&dfp.vt.u64[0], sgn); \ } \ \ if (size == 64) { \ - set_dfp64(t, dfp.t64); \ + set_dfp64(t, &dfp.vt); \ } else if (size == 128) { \ - set_dfp128(t, dfp.t64); \ + set_dfp128(t, &dfp.vt); \ } \ } @@ -1126,7 +1128,8 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \ decNumberZero(&dfp.t); \ \ if (s) { \ - uint8_t sgnNibble = dfp_get_bcd_digit_##size(dfp.b64, offset++); \ + uint8_t sgnNibble = dfp_get_bcd_digit_##size(&dfp.vb.u64[0], \ + offset++); \ switch (sgnNibble) { \ case 0xD: \ case 0xB: \ @@ -1146,7 +1149,8 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \ \ while (offset < (size) / 4) { \ n++; \ - digits[(size) / 4 - n] = dfp_get_bcd_digit_##size(dfp.b64, offset++); \ + digits[(size) / 4 - n] = dfp_get_bcd_digit_##size(&dfp.vb.u64[0], \ + offset++); \ if (digits[(size) / 4 - n] > 10) { \ dfp_set_FPSCR_flag(&dfp, FP_VX | FP_VXCVI, FPSCR_VE); \ return; \ @@ -1165,9 +1169,9 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \ dfp_finalize_decimal##size(&dfp); \ dfp_set_FPRF_from_FRT(&dfp); \ if ((size) == 64) { \ - set_dfp64(t, dfp.t64); \ + set_dfp64(t, &dfp.vt); \ } else if ((size) == 128) { \ - set_dfp128(t, dfp.t64); \ + set_dfp128(t, &dfp.vt); \ } \ } @@ -1178,30 +1182,30 @@ DFP_HELPER_ENBCD(denbcdq, 128) void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) \ { \ struct PPC_DFP dfp; \ - uint64_t t64; \ + ppc_vsr_t vt; \ \ dfp_prepare_decimal##size(&dfp, 0, b, env); \ \ if (unlikely(decNumberIsSpecial(&dfp.b))) { \ if (decNumberIsInfinite(&dfp.b)) { \ - t64 = -1; \ + vt.VsrD(1) = -1; \ } else if (decNumberIsSNaN(&dfp.b)) { \ - t64 = -3; \ + vt.VsrD(1) = -3; \ } else if (decNumberIsQNaN(&dfp.b)) { \ - t64 = -2; \ + vt.VsrD(1) = -2; \ } else { \ assert(0); \ } \ - set_dfp64(t, &t64); \ + set_dfp64(t, &vt); \ } else { \ if ((size) == 64) { \ - t64 = dfp.b.exponent + 398; \ + vt.VsrD(1) = dfp.b.exponent + 398; \ } else if ((size) == 128) { \ - t64 = dfp.b.exponent + 6176; \ + vt.VsrD(1) = dfp.b.exponent + 6176; \ } else { \ assert(0); \ } \ - set_dfp64(t, &t64); \ + set_dfp64(t, &vt); \ } \ } @@ -1225,12 +1229,13 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \ ppc_fprp_t *b) \ { \ struct PPC_DFP dfp; \ - uint64_t raw_qnan, raw_snan, raw_inf, max_exp, a64; \ + uint64_t raw_qnan, raw_snan, raw_inf, max_exp; \ + ppc_vsr_t va; \ int bias; \ int64_t exp; \ \ - get_dfp64(&a64, a); \ - exp = (int64_t)a64; \ + get_dfp64(&va, a); \ + exp = (int64_t)va.VsrD(1); \ dfp_prepare_decimal##size(&dfp, 0, b, env); \ \ if ((size) == 64) { \ @@ -1250,14 +1255,14 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \ } \ \ if (unlikely((exp < 0) || (exp > max_exp))) { \ - dfp.t64[0] = dfp.b64[0]; \ - dfp.t64[1] = dfp.b64[1]; \ + dfp.vt.VsrD(0) = dfp.vb.VsrD(0); \ + dfp.vt.VsrD(1) = dfp.vb.VsrD(1); \ if (exp == -1) { \ - dfp_set_raw_exp_##size(dfp.t64, raw_inf); \ + dfp_set_raw_exp_##size(&dfp.vt.u64[0], raw_inf); \ } else if (exp == -3) { \ - dfp_set_raw_exp_##size(dfp.t64, raw_snan); \ + dfp_set_raw_exp_##size(&dfp.vt.u64[0], raw_snan); \ } else { \ - dfp_set_raw_exp_##size(dfp.t64, raw_qnan); \ + dfp_set_raw_exp_##size(&dfp.vt.u64[0], raw_qnan); \ } \ } else { \ dfp.t = dfp.b; \ @@ -1268,9 +1273,9 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \ dfp_finalize_decimal##size(&dfp); \ } \ if (size == 64) { \ - set_dfp64(t, dfp.t64); \ + set_dfp64(t, &dfp.vt); \ } else if (size == 128) { \ - set_dfp128(t, dfp.t64); \ + set_dfp128(t, &dfp.vt); \ } \ } @@ -1348,20 +1353,21 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \ dfp_finalize_decimal##size(&dfp); \ } else { \ if ((size) == 64) { \ - dfp.t64[0] = dfp.a64[0] & 0xFFFC000000000000ULL; \ - dfp_clear_lmd_from_g5msb(dfp.t64); \ + dfp.vt.VsrD(1) = dfp.va.VsrD(1) & \ + 0xFFFC000000000000ULL; \ + dfp_clear_lmd_from_g5msb(&dfp.vt.VsrD(1)); \ } else { \ - dfp.t64[HI_IDX] = dfp.a64[HI_IDX] & \ - 0xFFFFC00000000000ULL; \ - dfp_clear_lmd_from_g5msb(dfp.t64 + HI_IDX); \ - dfp.t64[LO_IDX] = 0; \ + dfp.vt.VsrD(0) = dfp.va.VsrD(0) & \ + 0xFFFFC00000000000ULL; \ + dfp_clear_lmd_from_g5msb(&dfp.vt.VsrD(0)); \ + dfp.vt.VsrD(1) = 0; \ } \ } \ \ if ((size) == 64) { \ - set_dfp64(t, dfp.t64); \ + set_dfp64(t, &dfp.vt); \ } else { \ - set_dfp128(t, dfp.t64); \ + set_dfp128(t, &dfp.vt); \ } \ } From 1ea80bf7f4398099b6818f574cda8b4089c62340 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Thu, 26 Sep 2019 19:58:00 +0100 Subject: [PATCH 27/53] target/ppc: use existing VsrD() macro to eliminate HI_IDX and LO_IDX from dfp_helper.c Switch over all accesses to the decimal numbers held in struct PPC_DFP from using HI_IDX and LO_IDX to using the VsrD() macro instead. Not only does this allow the compiler to ensure that the various dfp_* functions are being passed a ppc_vsr_t rather than an arbitrary uint64_t pointer, but also allows the host endian-specific HI_IDX and LO_IDX to be completely removed from dfp_helper.c. Signed-off-by: Mark Cave-Ayland Reviewed-by: Richard Henderson Message-Id: <20190926185801.11176-7-mark.cave-ayland@ilande.co.uk> Signed-off-by: David Gibson --- target/ppc/dfp_helper.c | 70 ++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 39 deletions(-) diff --git a/target/ppc/dfp_helper.c b/target/ppc/dfp_helper.c index b72084d50a..c2bb458a78 100644 --- a/target/ppc/dfp_helper.c +++ b/target/ppc/dfp_helper.c @@ -28,13 +28,6 @@ #include "libdecnumber/dpd/decimal64.h" #include "libdecnumber/dpd/decimal128.h" -#if defined(HOST_WORDS_BIGENDIAN) -#define HI_IDX 0 -#define LO_IDX 1 -#else -#define HI_IDX 1 -#define LO_IDX 0 -#endif static void get_dfp64(ppc_vsr_t *dst, ppc_fprp_t *dfp) { @@ -1039,31 +1032,31 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) \ DFP_HELPER_CTFIX(dctfix, 64) DFP_HELPER_CTFIX(dctfixq, 128) -static inline void dfp_set_bcd_digit_64(uint64_t *t, uint8_t digit, - unsigned n) +static inline void dfp_set_bcd_digit_64(ppc_vsr_t *t, uint8_t digit, + unsigned n) { - *t |= ((uint64_t)(digit & 0xF) << (n << 2)); + t->VsrD(1) |= ((uint64_t)(digit & 0xF) << (n << 2)); } -static inline void dfp_set_bcd_digit_128(uint64_t *t, uint8_t digit, - unsigned n) +static inline void dfp_set_bcd_digit_128(ppc_vsr_t *t, uint8_t digit, + unsigned n) { - t[(n & 0x10) ? HI_IDX : LO_IDX] |= + t->VsrD((n & 0x10) ? 0 : 1) |= ((uint64_t)(digit & 0xF) << ((n & 15) << 2)); } -static inline void dfp_set_sign_64(uint64_t *t, uint8_t sgn) +static inline void dfp_set_sign_64(ppc_vsr_t *t, uint8_t sgn) { - *t <<= 4; - *t |= (sgn & 0xF); + t->VsrD(1) <<= 4; + t->VsrD(1) |= (sgn & 0xF); } -static inline void dfp_set_sign_128(uint64_t *t, uint8_t sgn) +static inline void dfp_set_sign_128(ppc_vsr_t *t, uint8_t sgn) { - t[HI_IDX] <<= 4; - t[HI_IDX] |= (t[LO_IDX] >> 60); - t[LO_IDX] <<= 4; - t[LO_IDX] |= (sgn & 0xF); + t->VsrD(0) <<= 4; + t->VsrD(0) |= (t->VsrD(1) >> 60); + t->VsrD(1) <<= 4; + t->VsrD(1) |= (sgn & 0xF); } #define DFP_HELPER_DEDPD(op, size) \ @@ -1081,7 +1074,7 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \ N = dfp.b.digits; \ \ for (i = 0; (i < N) && (i < (size)/4); i++) { \ - dfp_set_bcd_digit_##size(&dfp.vt.u64[0], digits[N - i - 1], i); \ + dfp_set_bcd_digit_##size(&dfp.vt, digits[N - i - 1], i); \ } \ \ if (sp & 2) { \ @@ -1092,7 +1085,7 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \ } else { \ sgn = ((sp & 1) ? 0xF : 0xC); \ } \ - dfp_set_sign_##size(&dfp.vt.u64[0], sgn); \ + dfp_set_sign_##size(&dfp.vt, sgn); \ } \ \ if (size == 64) { \ @@ -1105,14 +1098,14 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \ DFP_HELPER_DEDPD(ddedpd, 64) DFP_HELPER_DEDPD(ddedpdq, 128) -static inline uint8_t dfp_get_bcd_digit_64(uint64_t *t, unsigned n) +static inline uint8_t dfp_get_bcd_digit_64(ppc_vsr_t *t, unsigned n) { - return *t >> ((n << 2) & 63) & 15; + return t->VsrD(1) >> ((n << 2) & 63) & 15; } -static inline uint8_t dfp_get_bcd_digit_128(uint64_t *t, unsigned n) +static inline uint8_t dfp_get_bcd_digit_128(ppc_vsr_t *t, unsigned n) { - return t[(n & 0x10) ? HI_IDX : LO_IDX] >> ((n << 2) & 63) & 15; + return t->VsrD((n & 0x10) ? 0 : 1) >> ((n << 2) & 63) & 15; } #define DFP_HELPER_ENBCD(op, size) \ @@ -1128,8 +1121,7 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \ decNumberZero(&dfp.t); \ \ if (s) { \ - uint8_t sgnNibble = dfp_get_bcd_digit_##size(&dfp.vb.u64[0], \ - offset++); \ + uint8_t sgnNibble = dfp_get_bcd_digit_##size(&dfp.vb, offset++); \ switch (sgnNibble) { \ case 0xD: \ case 0xB: \ @@ -1149,7 +1141,7 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \ \ while (offset < (size) / 4) { \ n++; \ - digits[(size) / 4 - n] = dfp_get_bcd_digit_##size(&dfp.vb.u64[0], \ + digits[(size) / 4 - n] = dfp_get_bcd_digit_##size(&dfp.vb, \ offset++); \ if (digits[(size) / 4 - n] > 10) { \ dfp_set_FPSCR_flag(&dfp, FP_VX | FP_VXCVI, FPSCR_VE); \ @@ -1212,16 +1204,16 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) \ DFP_HELPER_XEX(dxex, 64) DFP_HELPER_XEX(dxexq, 128) -static void dfp_set_raw_exp_64(uint64_t *t, uint64_t raw) +static void dfp_set_raw_exp_64(ppc_vsr_t *t, uint64_t raw) { - *t &= 0x8003ffffffffffffULL; - *t |= (raw << (63 - 13)); + t->VsrD(1) &= 0x8003ffffffffffffULL; + t->VsrD(1) |= (raw << (63 - 13)); } -static void dfp_set_raw_exp_128(uint64_t *t, uint64_t raw) +static void dfp_set_raw_exp_128(ppc_vsr_t *t, uint64_t raw) { - t[HI_IDX] &= 0x80003fffffffffffULL; - t[HI_IDX] |= (raw << (63 - 17)); + t->VsrD(0) &= 0x80003fffffffffffULL; + t->VsrD(0) |= (raw << (63 - 17)); } #define DFP_HELPER_IEX(op, size) \ @@ -1258,11 +1250,11 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \ dfp.vt.VsrD(0) = dfp.vb.VsrD(0); \ dfp.vt.VsrD(1) = dfp.vb.VsrD(1); \ if (exp == -1) { \ - dfp_set_raw_exp_##size(&dfp.vt.u64[0], raw_inf); \ + dfp_set_raw_exp_##size(&dfp.vt, raw_inf); \ } else if (exp == -3) { \ - dfp_set_raw_exp_##size(&dfp.vt.u64[0], raw_snan); \ + dfp_set_raw_exp_##size(&dfp.vt, raw_snan); \ } else { \ - dfp_set_raw_exp_##size(&dfp.vt.u64[0], raw_qnan); \ + dfp_set_raw_exp_##size(&dfp.vt, raw_qnan); \ } \ } else { \ dfp.t = dfp.b; \ From f6d4c423a222f02bfa84a49c3d306d7341ec9bab Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Thu, 26 Sep 2019 19:58:01 +0100 Subject: [PATCH 28/53] target/ppc: remove unnecessary if() around calls to set_dfp{64,128}() in DFP macros Now that the parameters to both set_dfp64() and set_dfp128() are exactly the same, there is no need for an explicit if() statement to determine which function should be called based upon size. Instead we can simply use the preprocessor to generate the call to set_dfp##size() directly. Signed-off-by: Mark Cave-Ayland Reviewed-by: Richard Henderson Message-Id: <20190926185801.11176-8-mark.cave-ayland@ilande.co.uk> Signed-off-by: David Gibson --- target/ppc/dfp_helper.c | 60 +++++++---------------------------------- 1 file changed, 10 insertions(+), 50 deletions(-) diff --git a/target/ppc/dfp_helper.c b/target/ppc/dfp_helper.c index c2bb458a78..2c65badae4 100644 --- a/target/ppc/dfp_helper.c +++ b/target/ppc/dfp_helper.c @@ -427,11 +427,7 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \ dnop(&dfp.t, &dfp.a, &dfp.b, &dfp.context); \ dfp_finalize_decimal##size(&dfp); \ postprocs(&dfp); \ - if (size == 64) { \ - set_dfp64(t, &dfp.vt); \ - } else if (size == 128) { \ - set_dfp128(t, &dfp.vt); \ - } \ + set_dfp##size(t, &dfp.vt); \ } static void ADD_PPs(struct PPC_DFP *dfp) @@ -747,11 +743,7 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \ dfp_finalize_decimal##size(&dfp); \ QUA_PPs(&dfp); \ \ - if (size == 64) { \ - set_dfp64(t, &dfp.vt); \ - } else if (size == 128) { \ - set_dfp128(t, &dfp.vt); \ - } \ + set_dfp##size(t, &dfp.vt); \ } DFP_HELPER_QUAI(dquai, 64) @@ -769,11 +761,7 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \ dfp_finalize_decimal##size(&dfp); \ QUA_PPs(&dfp); \ \ - if (size == 64) { \ - set_dfp64(t, &dfp.vt); \ - } else if (size == 128) { \ - set_dfp128(t, &dfp.vt); \ - } \ + set_dfp##size(t, &dfp.vt); \ } DFP_HELPER_QUA(dqua, 64) @@ -851,11 +839,7 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \ dfp_finalize_decimal##size(&dfp); \ QUA_PPs(&dfp); \ \ - if (size == 64) { \ - set_dfp64(t, &dfp.vt); \ - } else if (size == 128) { \ - set_dfp128(t, &dfp.vt); \ - } \ + set_dfp##size(t, &dfp.vt); \ } DFP_HELPER_RRND(drrnd, 64) @@ -874,11 +858,7 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \ dfp_finalize_decimal##size(&dfp); \ postprocs(&dfp); \ \ - if (size == 64) { \ - set_dfp64(t, &dfp.vt); \ - } else if (size == 128) { \ - set_dfp128(t, &dfp.vt); \ - } \ + set_dfp##size(t, &dfp.vt); \ } static void RINTX_PPs(struct PPC_DFP *dfp) @@ -978,11 +958,7 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) \ dfp_finalize_decimal##size(&dfp); \ CFFIX_PPs(&dfp); \ \ - if (size == 64) { \ - set_dfp64(t, &dfp.vt); \ - } else if (size == 128) { \ - set_dfp128(t, &dfp.vt); \ - } \ + set_dfp##size(t, &dfp.vt); \ } static void CFFIX_PPs(struct PPC_DFP *dfp) @@ -1088,11 +1064,7 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \ dfp_set_sign_##size(&dfp.vt, sgn); \ } \ \ - if (size == 64) { \ - set_dfp64(t, &dfp.vt); \ - } else if (size == 128) { \ - set_dfp128(t, &dfp.vt); \ - } \ + set_dfp##size(t, &dfp.vt); \ } DFP_HELPER_DEDPD(ddedpd, 64) @@ -1160,11 +1132,7 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \ } \ dfp_finalize_decimal##size(&dfp); \ dfp_set_FPRF_from_FRT(&dfp); \ - if ((size) == 64) { \ - set_dfp64(t, &dfp.vt); \ - } else if ((size) == 128) { \ - set_dfp128(t, &dfp.vt); \ - } \ + set_dfp##size(t, &dfp.vt); \ } DFP_HELPER_ENBCD(denbcd, 64) @@ -1264,11 +1232,7 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \ dfp.t.exponent = exp - bias; \ dfp_finalize_decimal##size(&dfp); \ } \ - if (size == 64) { \ - set_dfp64(t, &dfp.vt); \ - } else if (size == 128) { \ - set_dfp128(t, &dfp.vt); \ - } \ + set_dfp##size(t, &dfp.vt); \ } DFP_HELPER_IEX(diex, 64) @@ -1356,11 +1320,7 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \ } \ } \ \ - if ((size) == 64) { \ - set_dfp64(t, &dfp.vt); \ - } else { \ - set_dfp128(t, &dfp.vt); \ - } \ + set_dfp##size(t, &dfp.vt); \ } DFP_HELPER_SHIFT(dscli, 64, 1) From c4ec08ab70bab90685d1443d6da47293e3aa312a Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Fri, 27 Sep 2019 12:26:51 +1000 Subject: [PATCH 29/53] spapr-pci: Stop providing assigned-addresses QEMU does not allocate PCI resources (BARs) in any case - coldplug devices are configured by the firmware and hotplug devices rely on the guest system to do the assignment via the PCI rescan mechanism. Also in order to create non empty "assigned-addresses", the device has to be enabled (i.e. PCI_COMMAND needs the MMIO bit set) first as otherwise io_regions[i].addr are -1, and devices are not enabled at this point. This removes "assigned-addresses" and leaves it to those who actually do resource allocation. Signed-off-by: Alexey Kardashevskiy Message-Id: <20190927022651.71642-1-aik@ozlabs.ru> Signed-off-by: David Gibson --- hw/ppc/spapr_pci.c | 42 +++++++----------------------------------- 1 file changed, 7 insertions(+), 35 deletions(-) diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 7b71ad7c74..c1c9634755 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -835,7 +835,7 @@ static char *spapr_phb_get_loc_code(SpaprPhbState *sphb, PCIDevice *pdev) #define b_fff(x) b_x((x), 8, 3) /* function number */ #define b_rrrrrrrr(x) b_x((x), 0, 8) /* register number */ -/* for 'reg'/'assigned-addresses' OF properties */ +/* for 'reg' OF properties */ #define RESOURCE_CELLS_SIZE 2 #define RESOURCE_CELLS_ADDRESS 3 @@ -849,17 +849,14 @@ typedef struct ResourceFields { typedef struct ResourceProps { ResourceFields reg[8]; - ResourceFields assigned[7]; uint32_t reg_len; - uint32_t assigned_len; } ResourceProps; -/* fill in the 'reg'/'assigned-resources' OF properties for +/* fill in the 'reg' OF properties for * a PCI device. 'reg' describes resource requirements for a - * device's IO/MEM regions, 'assigned-addresses' describes the - * actual resource assignments. + * device's IO/MEM regions. * - * the properties are arrays of ('phys-addr', 'size') pairs describing + * the property is an array of ('phys-addr', 'size') pairs describing * the addressable regions of the PCI device, where 'phys-addr' is a * RESOURCE_CELLS_ADDRESS-tuple of 32-bit integers corresponding to * (phys.hi, phys.mid, phys.lo), and 'size' is a @@ -888,18 +885,7 @@ typedef struct ResourceProps { * phys.mid and phys.lo correspond respectively to the hi/lo portions * of the actual address of the region. * - * how the phys-addr/size values are used differ slightly between - * 'reg' and 'assigned-addresses' properties. namely, 'reg' has - * an additional description for the config space region of the - * device, and in the case of QEMU has n=0 and phys.mid=phys.lo=0 - * to describe the region as relocatable, with an address-mapping - * that corresponds directly to the PHB's address space for the - * resource. 'assigned-addresses' always has n=1 set with an absolute - * address assigned for the resource. in general, 'assigned-addresses' - * won't be populated, since addresses for PCI devices are generally - * unmapped initially and left to the guest to assign. - * - * note also that addresses defined in these properties are, at least + * note also that addresses defined in this property are, at least * for PAPR guests, relative to the PHBs IO/MEM windows, and * correspond directly to the addresses in the BARs. * @@ -913,8 +899,8 @@ static void populate_resource_props(PCIDevice *d, ResourceProps *rp) uint32_t dev_id = (b_bbbbbbbb(bus_num) | b_ddddd(PCI_SLOT(d->devfn)) | b_fff(PCI_FUNC(d->devfn))); - ResourceFields *reg, *assigned; - int i, reg_idx = 0, assigned_idx = 0; + ResourceFields *reg; + int i, reg_idx = 0; /* config space region */ reg = &rp->reg[reg_idx++]; @@ -943,21 +929,9 @@ static void populate_resource_props(PCIDevice *d, ResourceProps *rp) reg->phys_lo = 0; reg->size_hi = cpu_to_be32(d->io_regions[i].size >> 32); reg->size_lo = cpu_to_be32(d->io_regions[i].size); - - if (d->io_regions[i].addr == PCI_BAR_UNMAPPED) { - continue; - } - - assigned = &rp->assigned[assigned_idx++]; - assigned->phys_hi = cpu_to_be32(be32_to_cpu(reg->phys_hi) | b_n(1)); - assigned->phys_mid = cpu_to_be32(d->io_regions[i].addr >> 32); - assigned->phys_lo = cpu_to_be32(d->io_regions[i].addr); - assigned->size_hi = reg->size_hi; - assigned->size_lo = reg->size_lo; } rp->reg_len = reg_idx * sizeof(ResourceFields); - rp->assigned_len = assigned_idx * sizeof(ResourceFields); } typedef struct PCIClass PCIClass; @@ -1471,8 +1445,6 @@ static int spapr_dt_pci_device(SpaprPhbState *sphb, PCIDevice *dev, populate_resource_props(dev, &rp); _FDT(fdt_setprop(fdt, offset, "reg", (uint8_t *)rp.reg, rp.reg_len)); - _FDT(fdt_setprop(fdt, offset, "assigned-addresses", - (uint8_t *)rp.assigned, rp.assigned_len)); if (sphb->pcie_ecs && pci_is_express(dev)) { _FDT(fdt_setprop_cell(fdt, offset, "ibm,pci-config-space-type", 0x1)); From e68cd0cb5cf49d334abe17231a1d2c28b846afa2 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Mon, 2 Sep 2019 15:41:16 +1000 Subject: [PATCH 30/53] spapr: Render full FDT on ibm,client-architecture-support The ibm,client-architecture-support call is a way for the guest to negotiate capabilities with a hypervisor. It is implemented as: - the guest calls SLOF via client interface; - SLOF calls QEMU (H_CAS hypercall) with an options vector from the guest; - QEMU returns a device tree diff (which uses FDT format with an additional header before it); - SLOF walks through the partial diff tree and updates its internal tree with the values from the diff. This changes QEMU to simply re-render the entire tree and send it as an update. SLOF can handle this already mostly, [1] is needed before this can be applied. This stores the resulting tree in the spapr machine to have the latest valid FDT copy possible (this should not matter much as H_UPDATE_DT happens right after that but nevertheless). The benefit is reduced code size as there is no need for another set of DT rendering helpers such as spapr_fixup_cpu_dt(). The downside is that the updates are bigger now (as they include all nodes and properties) but the difference on a '-smp 256,threads=1' system before/after is 2.35s vs. 2.5s. [1] https://patchwork.ozlabs.org/patch/1152915/ Signed-off-by: Alexey Kardashevskiy Signed-off-by: David Gibson --- hw/ppc/spapr.c | 88 ++++++-------------------------------------------- 1 file changed, 9 insertions(+), 79 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 3742a8cf06..43920c140d 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -295,64 +295,6 @@ static void spapr_populate_pa_features(SpaprMachineState *spapr, _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size))); } -static int spapr_fixup_cpu_dt(void *fdt, SpaprMachineState *spapr) -{ - MachineState *ms = MACHINE(spapr); - int ret = 0, offset, cpus_offset; - CPUState *cs; - char cpu_model[32]; - uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)}; - - CPU_FOREACH(cs) { - PowerPCCPU *cpu = POWERPC_CPU(cs); - DeviceClass *dc = DEVICE_GET_CLASS(cs); - int index = spapr_get_vcpu_id(cpu); - int compat_smt = MIN(ms->smp.threads, ppc_compat_max_vthreads(cpu)); - - if (!spapr_is_thread0_in_vcore(spapr, cpu)) { - continue; - } - - snprintf(cpu_model, 32, "%s@%x", dc->fw_name, index); - - cpus_offset = fdt_path_offset(fdt, "/cpus"); - if (cpus_offset < 0) { - cpus_offset = fdt_add_subnode(fdt, 0, "cpus"); - if (cpus_offset < 0) { - return cpus_offset; - } - } - offset = fdt_subnode_offset(fdt, cpus_offset, cpu_model); - if (offset < 0) { - offset = fdt_add_subnode(fdt, cpus_offset, cpu_model); - if (offset < 0) { - return offset; - } - } - - ret = fdt_setprop(fdt, offset, "ibm,pft-size", - pft_size_prop, sizeof(pft_size_prop)); - if (ret < 0) { - return ret; - } - - if (ms->numa_state->num_nodes > 1) { - ret = spapr_fixup_cpu_numa_dt(fdt, offset, cpu); - if (ret < 0) { - return ret; - } - } - - ret = spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt); - if (ret < 0) { - return ret; - } - - spapr_populate_pa_features(spapr, cpu, fdt, offset); - } - return ret; -} - static hwaddr spapr_node0_size(MachineState *machine) { if (machine->numa_state->num_nodes) { @@ -983,11 +925,13 @@ static bool spapr_hotplugged_dev_before_cas(void) return false; } +static void *spapr_build_fdt(SpaprMachineState *spapr); + int spapr_h_cas_compose_response(SpaprMachineState *spapr, target_ulong addr, target_ulong size, SpaprOptionVector *ov5_updates) { - void *fdt, *fdt_skel; + void *fdt; SpaprDeviceTreeUpdateHeader hdr = { .version_id = 1 }; if (spapr_hotplugged_dev_before_cas()) { @@ -1003,25 +947,7 @@ int spapr_h_cas_compose_response(SpaprMachineState *spapr, size -= sizeof(hdr); - /* Create skeleton */ - fdt_skel = g_malloc0(size); - _FDT((fdt_create(fdt_skel, size))); - _FDT((fdt_finish_reservemap(fdt_skel))); - _FDT((fdt_begin_node(fdt_skel, ""))); - _FDT((fdt_end_node(fdt_skel))); - _FDT((fdt_finish(fdt_skel))); - fdt = g_malloc0(size); - _FDT((fdt_open_into(fdt_skel, fdt, size))); - g_free(fdt_skel); - - /* Fixup cpu nodes */ - _FDT((spapr_fixup_cpu_dt(fdt, spapr))); - - if (spapr_dt_cas_updates(spapr, fdt, ov5_updates)) { - return -1; - } - - /* Pack resulting tree */ + fdt = spapr_build_fdt(spapr); _FDT((fdt_pack(fdt))); if (fdt_totalsize(fdt) + sizeof(hdr) > size) { @@ -1033,7 +959,11 @@ int spapr_h_cas_compose_response(SpaprMachineState *spapr, cpu_physical_memory_write(addr, &hdr, sizeof(hdr)); cpu_physical_memory_write(addr + sizeof(hdr), fdt, fdt_totalsize(fdt)); trace_spapr_cas_continue(fdt_totalsize(fdt) + sizeof(hdr)); - g_free(fdt); + + g_free(spapr->fdt_blob); + spapr->fdt_size = fdt_totalsize(fdt); + spapr->fdt_initial_size = spapr->fdt_size; + spapr->fdt_blob = fdt; return 0; } From 428115c3a9d0f64e1b9189986dbba4be0548c4a5 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Thu, 26 Sep 2019 21:44:53 +0100 Subject: [PATCH 31/53] target/ppc: use Vsr macros in BCD helpers This allows us to remove more endian-specific defines from int_helper.c. Signed-off-by: Mark Cave-Ayland Message-Id: <20190926204453.31837-1-mark.cave-ayland@ilande.co.uk> Signed-off-by: David Gibson Reviewed-by: Richard Henderson --- target/ppc/int_helper.c | 72 ++++++++++++++--------------------------- 1 file changed, 25 insertions(+), 47 deletions(-) diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c index 46deb57a34..6d238b989d 100644 --- a/target/ppc/int_helper.c +++ b/target/ppc/int_helper.c @@ -2052,15 +2052,11 @@ void helper_vsubecuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) #define NATIONAL_PLUS 0x2B #define NATIONAL_NEG 0x2D -#if defined(HOST_WORDS_BIGENDIAN) #define BCD_DIG_BYTE(n) (15 - ((n) / 2)) -#else -#define BCD_DIG_BYTE(n) ((n) / 2) -#endif static int bcd_get_sgn(ppc_avr_t *bcd) { - switch (bcd->u8[BCD_DIG_BYTE(0)] & 0xF) { + switch (bcd->VsrB(BCD_DIG_BYTE(0)) & 0xF) { case BCD_PLUS_PREF_1: case BCD_PLUS_PREF_2: case BCD_PLUS_ALT_1: @@ -2095,9 +2091,9 @@ static uint8_t bcd_get_digit(ppc_avr_t *bcd, int n, int *invalid) { uint8_t result; if (n & 1) { - result = bcd->u8[BCD_DIG_BYTE(n)] >> 4; + result = bcd->VsrB(BCD_DIG_BYTE(n)) >> 4; } else { - result = bcd->u8[BCD_DIG_BYTE(n)] & 0xF; + result = bcd->VsrB(BCD_DIG_BYTE(n)) & 0xF; } if (unlikely(result > 9)) { @@ -2109,11 +2105,11 @@ static uint8_t bcd_get_digit(ppc_avr_t *bcd, int n, int *invalid) static void bcd_put_digit(ppc_avr_t *bcd, uint8_t digit, int n) { if (n & 1) { - bcd->u8[BCD_DIG_BYTE(n)] &= 0x0F; - bcd->u8[BCD_DIG_BYTE(n)] |= (digit << 4); + bcd->VsrB(BCD_DIG_BYTE(n)) &= 0x0F; + bcd->VsrB(BCD_DIG_BYTE(n)) |= (digit << 4); } else { - bcd->u8[BCD_DIG_BYTE(n)] &= 0xF0; - bcd->u8[BCD_DIG_BYTE(n)] |= digit; + bcd->VsrB(BCD_DIG_BYTE(n)) &= 0xF0; + bcd->VsrB(BCD_DIG_BYTE(n)) |= digit; } } @@ -2228,21 +2224,21 @@ uint32_t helper_bcdadd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps) if (!invalid) { if (sgna == sgnb) { - result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgna, ps); + result.VsrB(BCD_DIG_BYTE(0)) = bcd_preferred_sgn(sgna, ps); bcd_add_mag(&result, a, b, &invalid, &overflow); cr = bcd_cmp_zero(&result); } else { int magnitude = bcd_cmp_mag(a, b); if (magnitude > 0) { - result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgna, ps); + result.VsrB(BCD_DIG_BYTE(0)) = bcd_preferred_sgn(sgna, ps); bcd_sub_mag(&result, a, b, &invalid, &overflow); cr = (sgna > 0) ? CRF_GT : CRF_LT; } else if (magnitude < 0) { - result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgnb, ps); + result.VsrB(BCD_DIG_BYTE(0)) = bcd_preferred_sgn(sgnb, ps); bcd_sub_mag(&result, b, a, &invalid, &overflow); cr = (sgnb > 0) ? CRF_GT : CRF_LT; } else { - result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(0, ps); + result.VsrB(BCD_DIG_BYTE(0)) = bcd_preferred_sgn(0, ps); cr = CRF_EQ; } } @@ -2353,15 +2349,15 @@ uint32_t helper_bcdcfz(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps) int zone_lead = ps ? 0xF : 0x3; int digit = 0; ppc_avr_t ret = { .u64 = { 0, 0 } }; - int sgnb = b->u8[BCD_DIG_BYTE(0)] >> 4; + int sgnb = b->VsrB(BCD_DIG_BYTE(0)) >> 4; if (unlikely((sgnb < 0xA) && ps)) { invalid = 1; } for (i = 0; i < 16; i++) { - zone_digit = i ? b->u8[BCD_DIG_BYTE(i * 2)] >> 4 : zone_lead; - digit = b->u8[BCD_DIG_BYTE(i * 2)] & 0xF; + zone_digit = i ? b->VsrB(BCD_DIG_BYTE(i * 2)) >> 4 : zone_lead; + digit = b->VsrB(BCD_DIG_BYTE(i * 2)) & 0xF; if (unlikely(zone_digit != zone_lead || digit > 0x9)) { invalid = 1; break; @@ -2407,7 +2403,7 @@ uint32_t helper_bcdctz(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps) break; } - ret.u8[BCD_DIG_BYTE(i * 2)] = zone_lead + digit; + ret.VsrB(BCD_DIG_BYTE(i * 2)) = zone_lead + digit; } if (ps) { @@ -2519,7 +2515,7 @@ uint32_t helper_bcdcpsgn(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps) } *r = *a; - bcd_put_digit(r, b->u8[BCD_DIG_BYTE(0)] & 0xF, 0); + bcd_put_digit(r, b->VsrB(BCD_DIG_BYTE(0)) & 0xF, 0); for (i = 1; i < 32; i++) { bcd_get_digit(a, i, &invalid); @@ -2549,11 +2545,7 @@ uint32_t helper_bcdsetsgn(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps) uint32_t helper_bcds(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps) { int cr; -#if defined(HOST_WORDS_BIGENDIAN) - int i = a->s8[7]; -#else - int i = a->s8[8]; -#endif + int i = a->VsrSB(7); bool ox_flag = false; int sgnb = bcd_get_sgn(b); ppc_avr_t ret = *b; @@ -2602,11 +2594,7 @@ uint32_t helper_bcdus(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps) } } -#if defined(HOST_WORDS_BIGENDIAN) - i = a->s8[7]; -#else - i = a->s8[8]; -#endif + i = a->VsrSB(7); if (i >= 32) { ox_flag = true; ret.VsrD(1) = ret.VsrD(0) = 0; @@ -2637,13 +2625,11 @@ uint32_t helper_bcdsr(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps) ppc_avr_t ret = *b; ret.VsrD(1) &= ~0xf; -#if defined(HOST_WORDS_BIGENDIAN) - int i = a->s8[7]; - ppc_avr_t bcd_one = { .u64 = { 0, 0x10 } }; -#else - int i = a->s8[8]; - ppc_avr_t bcd_one = { .u64 = { 0x10, 0 } }; -#endif + int i = a->VsrSB(7); + ppc_avr_t bcd_one; + + bcd_one.VsrD(0) = 0; + bcd_one.VsrD(1) = 0x10; if (bcd_is_valid(b) == false) { return CRF_SO; @@ -2679,11 +2665,7 @@ uint32_t helper_bcdtrunc(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps) { uint64_t mask; uint32_t ox_flag = 0; -#if defined(HOST_WORDS_BIGENDIAN) - int i = a->s16[3] + 1; -#else - int i = a->s16[4] + 1; -#endif + int i = a->VsrSH(3) + 1; ppc_avr_t ret = *b; if (bcd_is_valid(b) == false) { @@ -2728,11 +2710,7 @@ uint32_t helper_bcdutrunc(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps) } } -#if defined(HOST_WORDS_BIGENDIAN) - i = a->s16[3]; -#else - i = a->s16[4]; -#endif + i = a->VsrSH(3); if (i > 16 && i < 33) { mask = (uint64_t)-1 >> (128 - i * 4); if (ret.VsrD(0) & ~mask) { From 627fa61746f70f7c799f08e9048bb6a482402138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Tue, 1 Oct 2019 10:57:22 +0200 Subject: [PATCH 32/53] spapr/xive: skip partially initialized vCPUs in presenter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When vCPUs are hotplugged, they are added to the QEMU CPU list before being fully realized. This can crash the XIVE presenter because the 'tctx' pointer is not necessarily initialized when looking for a matching target. These vCPUs are not valid targets for the presenter. Skip them. Signed-off-by: Cédric Le Goater Message-Id: <20191001085722.32755-1-clg@kaod.org> Signed-off-by: David Gibson Reviewed-by: Greg Kurz --- hw/intc/xive.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hw/intc/xive.c b/hw/intc/xive.c index b7417210d8..29df06df11 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -1396,6 +1396,14 @@ static bool xive_presenter_match(XiveRouter *xrtr, uint8_t format, XiveTCTX *tctx = xive_router_get_tctx(xrtr, cs); int ring; + /* + * Skip partially initialized vCPUs. This can happen when + * vCPUs are hotplugged. + */ + if (!tctx) { + continue; + } + /* * HW checks that the CPU is enabled in the Physical Thread * Enable Register (PTER). From 00ed3da9b5c2e66e796a172df3e19545462b9c90 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 24 Sep 2019 16:00:33 +1000 Subject: [PATCH 33/53] xics: Minor fixes for XICSFabric interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Interface instances should never be directly dereferenced. So, the common practice is to make them incomplete types to make sure no-one does that. XICSFrabric, however, had a dummy type which is less safe. We were also using OBJECT_CHECK() where we should have been using INTERFACE_CHECK(). Signed-off-by: David Gibson Reviewed-by: Greg Kurz Reviewed-by: Cédric Le Goater --- include/hw/ppc/xics.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h index 64a2c8862a..faa33ae943 100644 --- a/include/hw/ppc/xics.h +++ b/include/hw/ppc/xics.h @@ -147,13 +147,9 @@ struct ICSIRQState { uint8_t flags; }; -struct XICSFabric { - Object parent; -}; - #define TYPE_XICS_FABRIC "xics-fabric" #define XICS_FABRIC(obj) \ - OBJECT_CHECK(XICSFabric, (obj), TYPE_XICS_FABRIC) + INTERFACE_CHECK(XICSFabric, (obj), TYPE_XICS_FABRIC) #define XICS_FABRIC_CLASS(klass) \ OBJECT_CLASS_CHECK(XICSFabricClass, (klass), TYPE_XICS_FABRIC) #define XICS_FABRIC_GET_CLASS(obj) \ From d5803c7319f5cc79afda066e2c8b9c61436b43df Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 24 Sep 2019 13:56:47 +1000 Subject: [PATCH 34/53] xics: Eliminate 'reject', 'resend' and 'eoi' class hooks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently ics_reject(), ics_resend() and ics_eoi() indirect through class methods. But there's only one implementation of each method, the one in TYPE_ICS_SIMPLE. TYPE_ICS_BASE has no implementation, but it's never instantiated, and has no other subtypes. So clean up by eliminating the method and just having ics_reject(), ics_resend() and ics_eoi() contain the logic directly. Signed-off-by: David Gibson Reviewed-by: Cédric Le Goater Reviewed-by: Greg Kurz --- hw/intc/trace-events | 4 ++-- hw/intc/xics.c | 54 +++++++++++-------------------------------- include/hw/ppc/xics.h | 4 ---- 3 files changed, 15 insertions(+), 47 deletions(-) diff --git a/hw/intc/trace-events b/hw/intc/trace-events index 719f46b516..fdc716c2cc 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -70,8 +70,8 @@ xics_ics_simple_set_irq_msi(int srcno, int nr) "set_irq_msi: srcno %d [irq 0x%x] xics_masked_pending(void) "set_irq_msi: masked pending" xics_ics_simple_set_irq_lsi(int srcno, int nr) "set_irq_lsi: srcno %d [irq 0x%x]" xics_ics_simple_write_xive(int nr, int srcno, int server, uint8_t priority) "ics_write_xive: irq 0x%x [src %d] server 0x%x prio 0x%x" -xics_ics_simple_reject(int nr, int srcno) "reject irq 0x%x [src %d]" -xics_ics_simple_eoi(int nr) "ics_eoi: irq 0x%x" +xics_ics_reject(int nr, int srcno) "reject irq 0x%x [src %d]" +xics_ics_eoi(int nr) "ics_eoi: irq 0x%x" # s390_flic_kvm.c flic_create_device(int err) "flic: create device failed %d" diff --git a/hw/intc/xics.c b/hw/intc/xics.c index b2fca2975c..93139b0189 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -98,32 +98,8 @@ void ics_pic_print_info(ICSState *ics, Monitor *mon) #define XISR(icp) (((icp)->xirr) & XISR_MASK) #define CPPR(icp) (((icp)->xirr) >> 24) -static void ics_reject(ICSState *ics, uint32_t nr) -{ - ICSStateClass *k = ICS_BASE_GET_CLASS(ics); - - if (k->reject) { - k->reject(ics, nr); - } -} - -void ics_resend(ICSState *ics) -{ - ICSStateClass *k = ICS_BASE_GET_CLASS(ics); - - if (k->resend) { - k->resend(ics); - } -} - -static void ics_eoi(ICSState *ics, int nr) -{ - ICSStateClass *k = ICS_BASE_GET_CLASS(ics); - - if (k->eoi) { - k->eoi(ics, nr); - } -} +static void ics_reject(ICSState *ics, uint32_t nr); +static void ics_eoi(ICSState *ics, uint32_t nr); static void icp_check_ipi(ICPState *icp) { @@ -427,7 +403,7 @@ Object *icp_create(Object *cpu, const char *type, XICSFabric *xi, Error **errp) /* * ICS: Source layer */ -static void ics_simple_resend_msi(ICSState *ics, int srcno) +static void ics_resend_msi(ICSState *ics, int srcno) { ICSIRQState *irq = ics->irqs + srcno; @@ -440,7 +416,7 @@ static void ics_simple_resend_msi(ICSState *ics, int srcno) } } -static void ics_simple_resend_lsi(ICSState *ics, int srcno) +static void ics_resend_lsi(ICSState *ics, int srcno) { ICSIRQState *irq = ics->irqs + srcno; @@ -478,7 +454,7 @@ static void ics_simple_set_irq_lsi(ICSState *ics, int srcno, int val) } else { irq->status &= ~XICS_STATUS_ASSERTED; } - ics_simple_resend_lsi(ics, srcno); + ics_resend_lsi(ics, srcno); } void ics_simple_set_irq(void *opaque, int srcno, int val) @@ -512,7 +488,7 @@ static void ics_simple_write_xive_msi(ICSState *ics, int srcno) static void ics_simple_write_xive_lsi(ICSState *ics, int srcno) { - ics_simple_resend_lsi(ics, srcno); + ics_resend_lsi(ics, srcno); } void ics_simple_write_xive(ICSState *ics, int srcno, int server, @@ -534,11 +510,11 @@ void ics_simple_write_xive(ICSState *ics, int srcno, int server, } } -static void ics_simple_reject(ICSState *ics, uint32_t nr) +static void ics_reject(ICSState *ics, uint32_t nr) { ICSIRQState *irq = ics->irqs + nr - ics->offset; - trace_xics_ics_simple_reject(nr, nr - ics->offset); + trace_xics_ics_reject(nr, nr - ics->offset); if (irq->flags & XICS_FLAGS_IRQ_MSI) { irq->status |= XICS_STATUS_REJECTED; } else if (irq->flags & XICS_FLAGS_IRQ_LSI) { @@ -546,26 +522,26 @@ static void ics_simple_reject(ICSState *ics, uint32_t nr) } } -static void ics_simple_resend(ICSState *ics) +void ics_resend(ICSState *ics) { int i; for (i = 0; i < ics->nr_irqs; i++) { /* FIXME: filter by server#? */ if (ics->irqs[i].flags & XICS_FLAGS_IRQ_LSI) { - ics_simple_resend_lsi(ics, i); + ics_resend_lsi(ics, i); } else { - ics_simple_resend_msi(ics, i); + ics_resend_msi(ics, i); } } } -static void ics_simple_eoi(ICSState *ics, uint32_t nr) +static void ics_eoi(ICSState *ics, uint32_t nr) { int srcno = nr - ics->offset; ICSIRQState *irq = ics->irqs + srcno; - trace_xics_ics_simple_eoi(nr); + trace_xics_ics_eoi(nr); if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) { irq->status &= ~XICS_STATUS_SENT; @@ -617,10 +593,6 @@ static void ics_simple_class_init(ObjectClass *klass, void *data) &isc->parent_realize); device_class_set_parent_reset(dc, ics_simple_reset, &isc->parent_reset); - - isc->reject = ics_simple_reject; - isc->resend = ics_simple_resend; - isc->eoi = ics_simple_eoi; } static const TypeInfo ics_simple_info = { diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h index faa33ae943..ecca17695d 100644 --- a/include/hw/ppc/xics.h +++ b/include/hw/ppc/xics.h @@ -106,10 +106,6 @@ struct ICSStateClass { DeviceRealize parent_realize; DeviceReset parent_reset; - - void (*reject)(ICSState *s, uint32_t irq); - void (*resend)(ICSState *s); - void (*eoi)(ICSState *s, uint32_t irq); }; struct ICSState { From 28976c99cfa59e1880a86a59af20099eba62f5e7 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 24 Sep 2019 14:13:39 +1000 Subject: [PATCH 35/53] xics: Rename misleading ics_simple_*() functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are a number of ics_simple_*() functions that aren't actually specific to TYPE_XICS_SIMPLE at all, and are equally valid on TYPE_XICS_BASE. Rename them to ics_*() accordingly. Signed-off-by: David Gibson Reviewed-by: Cédric Le Goater Reviewed-by: Greg Kurz --- hw/intc/trace-events | 6 +++--- hw/intc/xics.c | 29 ++++++++++++++--------------- hw/intc/xics_spapr.c | 12 ++++++------ hw/ppc/pnv_psi.c | 4 ++-- hw/ppc/spapr_irq.c | 2 +- include/hw/ppc/xics.h | 6 +++--- 6 files changed, 29 insertions(+), 30 deletions(-) diff --git a/hw/intc/trace-events b/hw/intc/trace-events index fdc716c2cc..527c3f76ca 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -66,10 +66,10 @@ xics_icp_accept(uint32_t old_xirr, uint32_t new_xirr) "icp_accept: XIRR 0x%"PRIx xics_icp_eoi(int server, uint32_t xirr, uint32_t new_xirr) "icp_eoi: server %d given XIRR 0x%"PRIx32" new XIRR 0x%"PRIx32 xics_icp_irq(int server, int nr, uint8_t priority) "cpu %d trying to deliver irq 0x%"PRIx32" priority 0x%x" xics_icp_raise(uint32_t xirr, uint8_t pending_priority) "raising IRQ new XIRR=0x%x new pending priority=0x%x" -xics_ics_simple_set_irq_msi(int srcno, int nr) "set_irq_msi: srcno %d [irq 0x%x]" +xics_ics_set_irq_msi(int srcno, int nr) "set_irq_msi: srcno %d [irq 0x%x]" xics_masked_pending(void) "set_irq_msi: masked pending" -xics_ics_simple_set_irq_lsi(int srcno, int nr) "set_irq_lsi: srcno %d [irq 0x%x]" -xics_ics_simple_write_xive(int nr, int srcno, int server, uint8_t priority) "ics_write_xive: irq 0x%x [src %d] server 0x%x prio 0x%x" +xics_ics_set_irq_lsi(int srcno, int nr) "set_irq_lsi: srcno %d [irq 0x%x]" +xics_ics_write_xive(int nr, int srcno, int server, uint8_t priority) "ics_write_xive: irq 0x%x [src %d] server 0x%x prio 0x%x" xics_ics_reject(int nr, int srcno) "reject irq 0x%x [src %d]" xics_ics_eoi(int nr) "ics_eoi: irq 0x%x" diff --git a/hw/intc/xics.c b/hw/intc/xics.c index 93139b0189..310dc72b46 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -428,11 +428,11 @@ static void ics_resend_lsi(ICSState *ics, int srcno) } } -static void ics_simple_set_irq_msi(ICSState *ics, int srcno, int val) +static void ics_set_irq_msi(ICSState *ics, int srcno, int val) { ICSIRQState *irq = ics->irqs + srcno; - trace_xics_ics_simple_set_irq_msi(srcno, srcno + ics->offset); + trace_xics_ics_set_irq_msi(srcno, srcno + ics->offset); if (val) { if (irq->priority == 0xff) { @@ -444,11 +444,11 @@ static void ics_simple_set_irq_msi(ICSState *ics, int srcno, int val) } } -static void ics_simple_set_irq_lsi(ICSState *ics, int srcno, int val) +static void ics_set_irq_lsi(ICSState *ics, int srcno, int val) { ICSIRQState *irq = ics->irqs + srcno; - trace_xics_ics_simple_set_irq_lsi(srcno, srcno + ics->offset); + trace_xics_ics_set_irq_lsi(srcno, srcno + ics->offset); if (val) { irq->status |= XICS_STATUS_ASSERTED; } else { @@ -457,7 +457,7 @@ static void ics_simple_set_irq_lsi(ICSState *ics, int srcno, int val) ics_resend_lsi(ics, srcno); } -void ics_simple_set_irq(void *opaque, int srcno, int val) +void ics_set_irq(void *opaque, int srcno, int val) { ICSState *ics = (ICSState *)opaque; @@ -467,13 +467,13 @@ void ics_simple_set_irq(void *opaque, int srcno, int val) } if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) { - ics_simple_set_irq_lsi(ics, srcno, val); + ics_set_irq_lsi(ics, srcno, val); } else { - ics_simple_set_irq_msi(ics, srcno, val); + ics_set_irq_msi(ics, srcno, val); } } -static void ics_simple_write_xive_msi(ICSState *ics, int srcno) +static void ics_write_xive_msi(ICSState *ics, int srcno) { ICSIRQState *irq = ics->irqs + srcno; @@ -486,13 +486,13 @@ static void ics_simple_write_xive_msi(ICSState *ics, int srcno) icp_irq(ics, irq->server, srcno + ics->offset, irq->priority); } -static void ics_simple_write_xive_lsi(ICSState *ics, int srcno) +static void ics_write_xive_lsi(ICSState *ics, int srcno) { ics_resend_lsi(ics, srcno); } -void ics_simple_write_xive(ICSState *ics, int srcno, int server, - uint8_t priority, uint8_t saved_priority) +void ics_write_xive(ICSState *ics, int srcno, int server, + uint8_t priority, uint8_t saved_priority) { ICSIRQState *irq = ics->irqs + srcno; @@ -500,13 +500,12 @@ void ics_simple_write_xive(ICSState *ics, int srcno, int server, irq->priority = priority; irq->saved_priority = saved_priority; - trace_xics_ics_simple_write_xive(ics->offset + srcno, srcno, server, - priority); + trace_xics_ics_write_xive(ics->offset + srcno, srcno, server, priority); if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) { - ics_simple_write_xive_lsi(ics, srcno); + ics_write_xive_lsi(ics, srcno); } else { - ics_simple_write_xive_msi(ics, srcno); + ics_write_xive_msi(ics, srcno); } } diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c index 6577be0d92..3e9444813a 100644 --- a/hw/intc/xics_spapr.c +++ b/hw/intc/xics_spapr.c @@ -179,7 +179,7 @@ static void rtas_set_xive(PowerPCCPU *cpu, SpaprMachineState *spapr, } srcno = nr - ics->offset; - ics_simple_write_xive(ics, srcno, server, priority, priority); + ics_write_xive(ics, srcno, server, priority, priority); rtas_st(rets, 0, RTAS_OUT_SUCCESS); } @@ -243,8 +243,8 @@ static void rtas_int_off(PowerPCCPU *cpu, SpaprMachineState *spapr, } srcno = nr - ics->offset; - ics_simple_write_xive(ics, srcno, ics->irqs[srcno].server, 0xff, - ics->irqs[srcno].priority); + ics_write_xive(ics, srcno, ics->irqs[srcno].server, 0xff, + ics->irqs[srcno].priority); rtas_st(rets, 0, RTAS_OUT_SUCCESS); } @@ -276,9 +276,9 @@ static void rtas_int_on(PowerPCCPU *cpu, SpaprMachineState *spapr, } srcno = nr - ics->offset; - ics_simple_write_xive(ics, srcno, ics->irqs[srcno].server, - ics->irqs[srcno].saved_priority, - ics->irqs[srcno].saved_priority); + ics_write_xive(ics, srcno, ics->irqs[srcno].server, + ics->irqs[srcno].saved_priority, + ics->irqs[srcno].saved_priority); rtas_st(rets, 0, RTAS_OUT_SUCCESS); } diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c index 88ba8e7b9b..8ea81e9d8e 100644 --- a/hw/ppc/pnv_psi.c +++ b/hw/ppc/pnv_psi.c @@ -311,7 +311,7 @@ static void pnv_psi_set_xivr(PnvPsi *psi, uint32_t reg, uint64_t val) * do for now but a more accurate implementation would instead * use a fixed server/prio and a remapper of the generated irq. */ - ics_simple_write_xive(ics, src, server, prio, prio); + ics_write_xive(ics, src, server, prio, prio); } static uint64_t pnv_psi_reg_read(PnvPsi *psi, uint32_t offset, bool mmio) @@ -514,7 +514,7 @@ static void pnv_psi_power8_realize(DeviceState *dev, Error **errp) ics_set_irq_type(ics, i, true); } - psi->qirqs = qemu_allocate_irqs(ics_simple_set_irq, ics, ics->nr_irqs); + psi->qirqs = qemu_allocate_irqs(ics_set_irq, ics, ics->nr_irqs); /* XSCOM region for PSI registers */ pnv_xscom_region_init(&psi->xscom_regs, OBJECT(dev), &pnv_psi_xscom_ops, diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index d8f46b6797..ac189c5796 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -210,7 +210,7 @@ static void spapr_irq_set_irq_xics(void *opaque, int srcno, int val) { SpaprMachineState *spapr = opaque; - ics_simple_set_irq(spapr->ics, srcno, val); + ics_set_irq(spapr->ics, srcno, val); } static void spapr_irq_reset_xics(SpaprMachineState *spapr, Error **errp) diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h index ecca17695d..8874bad328 100644 --- a/include/hw/ppc/xics.h +++ b/include/hw/ppc/xics.h @@ -167,9 +167,9 @@ uint32_t icp_accept(ICPState *ss); uint32_t icp_ipoll(ICPState *ss, uint32_t *mfrr); void icp_eoi(ICPState *icp, uint32_t xirr); -void ics_simple_write_xive(ICSState *ics, int nr, int server, - uint8_t priority, uint8_t saved_priority); -void ics_simple_set_irq(void *opaque, int srcno, int val); +void ics_write_xive(ICSState *ics, int nr, int server, + uint8_t priority, uint8_t saved_priority); +void ics_set_irq(void *opaque, int srcno, int val); static inline bool ics_irq_free(ICSState *ics, uint32_t srcno) { From da2ef5b2f24be70d4fa0b05fd6799031cd3a456e Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 24 Sep 2019 14:19:22 +1000 Subject: [PATCH 36/53] xics: Eliminate reset hook MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently TYPE_XICS_BASE and TYPE_XICS_SIMPLE have their own reset methods, using the standard technique for having the subtype call the supertype's methods before doing its own thing. But TYPE_XICS_SIMPLE is the only subtype of TYPE_XICS_BASE ever instantiated, so there's no point having the split here. Merge them together into just an ics_reset() function. Signed-off-by: David Gibson Reviewed-by: Cédric Le Goater Reviewed-by: Greg Kurz --- hw/intc/xics.c | 105 +++++++++++++++++++----------------------- include/hw/ppc/xics.h | 1 - 2 files changed, 48 insertions(+), 58 deletions(-) diff --git a/hw/intc/xics.c b/hw/intc/xics.c index 310dc72b46..82e6f09259 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -547,68 +547,13 @@ static void ics_eoi(ICSState *ics, uint32_t nr) } } -static void ics_simple_reset(DeviceState *dev) -{ - ICSStateClass *icsc = ICS_BASE_GET_CLASS(dev); - - icsc->parent_reset(dev); - - if (kvm_irqchip_in_kernel()) { - Error *local_err = NULL; - - ics_set_kvm_state(ICS_BASE(dev), &local_err); - if (local_err) { - error_report_err(local_err); - } - } -} - -static void ics_simple_reset_handler(void *dev) -{ - ics_simple_reset(dev); -} - -static void ics_simple_realize(DeviceState *dev, Error **errp) -{ - ICSState *ics = ICS_SIMPLE(dev); - ICSStateClass *icsc = ICS_BASE_GET_CLASS(ics); - Error *local_err = NULL; - - icsc->parent_realize(dev, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - qemu_register_reset(ics_simple_reset_handler, ics); -} - -static void ics_simple_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - ICSStateClass *isc = ICS_BASE_CLASS(klass); - - device_class_set_parent_realize(dc, ics_simple_realize, - &isc->parent_realize); - device_class_set_parent_reset(dc, ics_simple_reset, - &isc->parent_reset); -} - -static const TypeInfo ics_simple_info = { - .name = TYPE_ICS_SIMPLE, - .parent = TYPE_ICS_BASE, - .instance_size = sizeof(ICSState), - .class_init = ics_simple_class_init, - .class_size = sizeof(ICSStateClass), -}; - static void ics_reset_irq(ICSIRQState *irq) { irq->priority = 0xff; irq->saved_priority = 0xff; } -static void ics_base_reset(DeviceState *dev) +static void ics_reset(DeviceState *dev) { ICSState *ics = ICS_BASE(dev); int i; @@ -624,8 +569,54 @@ static void ics_base_reset(DeviceState *dev) ics_reset_irq(ics->irqs + i); ics->irqs[i].flags = flags[i]; } + + if (kvm_irqchip_in_kernel()) { + Error *local_err = NULL; + + ics_set_kvm_state(ICS_BASE(dev), &local_err); + if (local_err) { + error_report_err(local_err); + } + } } +static void ics_reset_handler(void *dev) +{ + ics_reset(dev); +} + +static void ics_simple_realize(DeviceState *dev, Error **errp) +{ + ICSState *ics = ICS_SIMPLE(dev); + ICSStateClass *icsc = ICS_BASE_GET_CLASS(ics); + Error *local_err = NULL; + + icsc->parent_realize(dev, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + qemu_register_reset(ics_reset_handler, ics); +} + +static void ics_simple_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ICSStateClass *isc = ICS_BASE_CLASS(klass); + + device_class_set_parent_realize(dc, ics_simple_realize, + &isc->parent_realize); +} + +static const TypeInfo ics_simple_info = { + .name = TYPE_ICS_SIMPLE, + .parent = TYPE_ICS_BASE, + .instance_size = sizeof(ICSState), + .class_init = ics_simple_class_init, + .class_size = sizeof(ICSStateClass), +}; + static void ics_base_realize(DeviceState *dev, Error **errp) { ICSState *ics = ICS_BASE(dev); @@ -726,7 +717,7 @@ static void ics_base_class_init(ObjectClass *klass, void *data) dc->realize = ics_base_realize; dc->props = ics_base_properties; - dc->reset = ics_base_reset; + dc->reset = ics_reset; dc->vmsd = &vmstate_ics_base; } diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h index 8874bad328..7efd49c02c 100644 --- a/include/hw/ppc/xics.h +++ b/include/hw/ppc/xics.h @@ -105,7 +105,6 @@ struct ICSStateClass { DeviceClass parent_class; DeviceRealize parent_realize; - DeviceReset parent_reset; }; struct ICSState { From 642e92719e2790dfa0e12be1cfd822a0ff2322aa Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 24 Sep 2019 15:29:25 +1000 Subject: [PATCH 37/53] xics: Merge TYPE_ICS_BASE and TYPE_ICS_SIMPLE classes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TYPE_ICS_SIMPLE is the only subtype of TYPE_ICS_BASE that's ever instantiated. The existence of different classes is mostly a hang over from when we (misguidedly) had separate subtypes for the KVM and non-KVM version of the device. There could be some call for an abstract base type for ICS variants that use a different representation of their state (PowerNV PHB3 might want this). The current split isn't really in the right place for that though. If we need this in future, we can re-implement it more in line with what we actually need. So, collapse the two classes together into just TYPE_ICS. Signed-off-by: David Gibson Reviewed-by: Cédric Le Goater Reviewed-by: Greg Kurz --- hw/intc/xics.c | 86 ++++++++++++++----------------------------- hw/ppc/pnv_psi.c | 2 +- hw/ppc/spapr_irq.c | 4 +- include/hw/ppc/xics.h | 16 +++----- 4 files changed, 36 insertions(+), 72 deletions(-) diff --git a/hw/intc/xics.c b/hw/intc/xics.c index 82e6f09259..dfe7dbd254 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -555,7 +555,7 @@ static void ics_reset_irq(ICSIRQState *irq) static void ics_reset(DeviceState *dev) { - ICSState *ics = ICS_BASE(dev); + ICSState *ics = ICS(dev); int i; uint8_t flags[ics->nr_irqs]; @@ -573,7 +573,7 @@ static void ics_reset(DeviceState *dev) if (kvm_irqchip_in_kernel()) { Error *local_err = NULL; - ics_set_kvm_state(ICS_BASE(dev), &local_err); + ics_set_kvm_state(ICS(dev), &local_err); if (local_err) { error_report_err(local_err); } @@ -585,47 +585,15 @@ static void ics_reset_handler(void *dev) ics_reset(dev); } -static void ics_simple_realize(DeviceState *dev, Error **errp) +static void ics_realize(DeviceState *dev, Error **errp) { - ICSState *ics = ICS_SIMPLE(dev); - ICSStateClass *icsc = ICS_BASE_GET_CLASS(ics); + ICSState *ics = ICS(dev); Error *local_err = NULL; - - icsc->parent_realize(dev, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - qemu_register_reset(ics_reset_handler, ics); -} - -static void ics_simple_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - ICSStateClass *isc = ICS_BASE_CLASS(klass); - - device_class_set_parent_realize(dc, ics_simple_realize, - &isc->parent_realize); -} - -static const TypeInfo ics_simple_info = { - .name = TYPE_ICS_SIMPLE, - .parent = TYPE_ICS_BASE, - .instance_size = sizeof(ICSState), - .class_init = ics_simple_class_init, - .class_size = sizeof(ICSStateClass), -}; - -static void ics_base_realize(DeviceState *dev, Error **errp) -{ - ICSState *ics = ICS_BASE(dev); Object *obj; - Error *err = NULL; - obj = object_property_get_link(OBJECT(dev), ICS_PROP_XICS, &err); + obj = object_property_get_link(OBJECT(dev), ICS_PROP_XICS, &local_err); if (!obj) { - error_propagate_prepend(errp, err, + error_propagate_prepend(errp, local_err, "required link '" ICS_PROP_XICS "' not found: "); return; @@ -637,16 +605,18 @@ static void ics_base_realize(DeviceState *dev, Error **errp) return; } ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState)); + + qemu_register_reset(ics_reset_handler, ics); } -static void ics_base_instance_init(Object *obj) +static void ics_instance_init(Object *obj) { - ICSState *ics = ICS_BASE(obj); + ICSState *ics = ICS(obj); ics->offset = XICS_IRQ_BASE; } -static int ics_base_pre_save(void *opaque) +static int ics_pre_save(void *opaque) { ICSState *ics = opaque; @@ -657,7 +627,7 @@ static int ics_base_pre_save(void *opaque) return 0; } -static int ics_base_post_load(void *opaque, int version_id) +static int ics_post_load(void *opaque, int version_id) { ICSState *ics = opaque; @@ -675,7 +645,7 @@ static int ics_base_post_load(void *opaque, int version_id) return 0; } -static const VMStateDescription vmstate_ics_base_irq = { +static const VMStateDescription vmstate_ics_irq = { .name = "ics/irq", .version_id = 2, .minimum_version_id = 1, @@ -689,45 +659,44 @@ static const VMStateDescription vmstate_ics_base_irq = { }, }; -static const VMStateDescription vmstate_ics_base = { +static const VMStateDescription vmstate_ics = { .name = "ics", .version_id = 1, .minimum_version_id = 1, - .pre_save = ics_base_pre_save, - .post_load = ics_base_post_load, + .pre_save = ics_pre_save, + .post_load = ics_post_load, .fields = (VMStateField[]) { /* Sanity check */ VMSTATE_UINT32_EQUAL(nr_irqs, ICSState, NULL), VMSTATE_STRUCT_VARRAY_POINTER_UINT32(irqs, ICSState, nr_irqs, - vmstate_ics_base_irq, + vmstate_ics_irq, ICSIRQState), VMSTATE_END_OF_LIST() }, }; -static Property ics_base_properties[] = { +static Property ics_properties[] = { DEFINE_PROP_UINT32("nr-irqs", ICSState, nr_irqs, 0), DEFINE_PROP_END_OF_LIST(), }; -static void ics_base_class_init(ObjectClass *klass, void *data) +static void ics_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - dc->realize = ics_base_realize; - dc->props = ics_base_properties; + dc->realize = ics_realize; + dc->props = ics_properties; dc->reset = ics_reset; - dc->vmsd = &vmstate_ics_base; + dc->vmsd = &vmstate_ics; } -static const TypeInfo ics_base_info = { - .name = TYPE_ICS_BASE, +static const TypeInfo ics_info = { + .name = TYPE_ICS, .parent = TYPE_DEVICE, - .abstract = true, .instance_size = sizeof(ICSState), - .instance_init = ics_base_instance_init, - .class_init = ics_base_class_init, + .instance_init = ics_instance_init, + .class_init = ics_class_init, .class_size = sizeof(ICSStateClass), }; @@ -767,8 +736,7 @@ void ics_set_irq_type(ICSState *ics, int srcno, bool lsi) static void xics_register_types(void) { - type_register_static(&ics_simple_info); - type_register_static(&ics_base_info); + type_register_static(&ics_info); type_register_static(&icp_info); type_register_static(&xics_fabric_info); } diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c index 8ea81e9d8e..a997f16bb4 100644 --- a/hw/ppc/pnv_psi.c +++ b/hw/ppc/pnv_psi.c @@ -469,7 +469,7 @@ static void pnv_psi_power8_instance_init(Object *obj) Pnv8Psi *psi8 = PNV8_PSI(obj); object_initialize_child(obj, "ics-psi", &psi8->ics, sizeof(psi8->ics), - TYPE_ICS_SIMPLE, &error_abort, NULL); + TYPE_ICS, &error_abort, NULL); } static const uint8_t irq_to_xivr[] = { diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index ac189c5796..6c45d2a3c0 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -98,7 +98,7 @@ static void spapr_irq_init_xics(SpaprMachineState *spapr, int nr_irqs, Object *obj; Error *local_err = NULL; - obj = object_new(TYPE_ICS_SIMPLE); + obj = object_new(TYPE_ICS); object_property_add_child(OBJECT(spapr), "ics", obj, &error_abort); object_property_add_const_link(obj, ICS_PROP_XICS, OBJECT(spapr), &error_fatal); @@ -109,7 +109,7 @@ static void spapr_irq_init_xics(SpaprMachineState *spapr, int nr_irqs, return; } - spapr->ics = ICS_BASE(obj); + spapr->ics = ICS(obj); xics_spapr_init(spapr); } diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h index 7efd49c02c..1e6a9300eb 100644 --- a/include/hw/ppc/xics.h +++ b/include/hw/ppc/xics.h @@ -89,17 +89,13 @@ struct PnvICPState { uint32_t links[3]; }; -#define TYPE_ICS_BASE "ics-base" -#define ICS_BASE(obj) OBJECT_CHECK(ICSState, (obj), TYPE_ICS_BASE) +#define TYPE_ICS "ics" +#define ICS(obj) OBJECT_CHECK(ICSState, (obj), TYPE_ICS) -/* Retain ics for sPAPR for migration from existing sPAPR guests */ -#define TYPE_ICS_SIMPLE "ics" -#define ICS_SIMPLE(obj) OBJECT_CHECK(ICSState, (obj), TYPE_ICS_SIMPLE) - -#define ICS_BASE_CLASS(klass) \ - OBJECT_CLASS_CHECK(ICSStateClass, (klass), TYPE_ICS_BASE) -#define ICS_BASE_GET_CLASS(obj) \ - OBJECT_GET_CLASS(ICSStateClass, (obj), TYPE_ICS_BASE) +#define ICS_CLASS(klass) \ + OBJECT_CLASS_CHECK(ICSStateClass, (klass), TYPE_ICS) +#define ICS_GET_CLASS(obj) \ + OBJECT_GET_CLASS(ICSStateClass, (obj), TYPE_ICS) struct ICSStateClass { DeviceClass parent_class; From 9db8c551c98c285bad2ed19ce28a721d33c20d2f Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 24 Sep 2019 15:51:55 +1000 Subject: [PATCH 38/53] xics: Create sPAPR specific ICS subtype MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We create a subtype of TYPE_ICS specifically for sPAPR. For now all this does is move the setup of the PAPR specific hcalls and RTAS calls to the realize() function for this, rather than requiring the PAPR code to explicitly call xics_spapr_init(). In future it will have some more function. Signed-off-by: David Gibson Reviewed-by: Cédric Le Goater Reviewed-by: Greg Kurz --- hw/intc/xics_spapr.c | 34 +++++++++++++++++++++++++++++++++- hw/ppc/spapr_irq.c | 6 ++---- include/hw/ppc/xics_spapr.h | 4 +++- 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c index 3e9444813a..e6dd004587 100644 --- a/hw/intc/xics_spapr.c +++ b/hw/intc/xics_spapr.c @@ -283,8 +283,18 @@ static void rtas_int_on(PowerPCCPU *cpu, SpaprMachineState *spapr, rtas_st(rets, 0, RTAS_OUT_SUCCESS); } -void xics_spapr_init(SpaprMachineState *spapr) +static void ics_spapr_realize(DeviceState *dev, Error **errp) { + ICSState *ics = ICS_SPAPR(dev); + ICSStateClass *icsc = ICS_GET_CLASS(ics); + Error *local_err = NULL; + + icsc->parent_realize(dev, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + 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); @@ -319,3 +329,25 @@ void spapr_dt_xics(SpaprMachineState *spapr, uint32_t nr_servers, void *fdt, _FDT(fdt_setprop_cell(fdt, node, "linux,phandle", phandle)); _FDT(fdt_setprop_cell(fdt, node, "phandle", phandle)); } + +static void ics_spapr_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ICSStateClass *isc = ICS_CLASS(klass); + + device_class_set_parent_realize(dc, ics_spapr_realize, + &isc->parent_realize); +} + +static const TypeInfo ics_spapr_info = { + .name = TYPE_ICS_SPAPR, + .parent = TYPE_ICS, + .class_init = ics_spapr_class_init, +}; + +static void xics_spapr_register_types(void) +{ + type_register_static(&ics_spapr_info); +} + +type_init(xics_spapr_register_types) diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index 6c45d2a3c0..8c26fa2d1e 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -98,7 +98,7 @@ static void spapr_irq_init_xics(SpaprMachineState *spapr, int nr_irqs, Object *obj; Error *local_err = NULL; - obj = object_new(TYPE_ICS); + obj = object_new(TYPE_ICS_SPAPR); object_property_add_child(OBJECT(spapr), "ics", obj, &error_abort); object_property_add_const_link(obj, ICS_PROP_XICS, OBJECT(spapr), &error_fatal); @@ -109,9 +109,7 @@ static void spapr_irq_init_xics(SpaprMachineState *spapr, int nr_irqs, return; } - spapr->ics = ICS(obj); - - xics_spapr_init(spapr); + spapr->ics = ICS_SPAPR(obj); } static int spapr_irq_claim_xics(SpaprMachineState *spapr, int irq, bool lsi, diff --git a/include/hw/ppc/xics_spapr.h b/include/hw/ppc/xics_spapr.h index 5dabc9a138..691a6d00f7 100644 --- a/include/hw/ppc/xics_spapr.h +++ b/include/hw/ppc/xics_spapr.h @@ -31,11 +31,13 @@ #define XICS_NODENAME "interrupt-controller" +#define TYPE_ICS_SPAPR "ics-spapr" +#define ICS_SPAPR(obj) OBJECT_CHECK(ICSState, (obj), TYPE_ICS_SPAPR) + void spapr_dt_xics(SpaprMachineState *spapr, uint32_t nr_servers, void *fdt, uint32_t phandle); int xics_kvm_connect(SpaprMachineState *spapr, Error **errp); void xics_kvm_disconnect(SpaprMachineState *spapr, Error **errp); bool xics_kvm_has_broken_disconnect(SpaprMachineState *spapr); -void xics_spapr_init(SpaprMachineState *spapr); #endif /* XICS_SPAPR_H */ From 258aa5ce1c62bf9cf28dc344f52e13ea3a0a38cd Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 23 Sep 2019 15:43:58 +1000 Subject: [PATCH 39/53] spapr: Fold spapr_phb_lsi_qirq() into its single caller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No point having a two-line helper that's used exactly once, and not likely to be used anywhere else in future. Signed-off-by: David Gibson Reviewed-by: Cédric Le Goater Reviewed-by: Greg Kurz Reviewed-by: Philippe Mathieu-Daudé --- hw/ppc/spapr_pci.c | 3 ++- include/hw/pci-host/spapr.h | 7 ------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index c1c9634755..01ff41d4c4 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -721,9 +721,10 @@ static void pci_spapr_set_irq(void *opaque, int irq_num, int level) * corresponding qemu_irq. */ SpaprPhbState *phb = opaque; + SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); trace_spapr_pci_lsi_set(phb->dtbusname, irq_num, phb->lsi_table[irq_num].irq); - qemu_set_irq(spapr_phb_lsi_qirq(phb, irq_num), level); + qemu_set_irq(spapr_qirq(spapr, phb->lsi_table[irq_num].irq), level); } static PCIINTxRoute spapr_route_intx_pin_to_irq(void *opaque, int pin) diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h index abd87605b2..23506f05d9 100644 --- a/include/hw/pci-host/spapr.h +++ b/include/hw/pci-host/spapr.h @@ -128,13 +128,6 @@ struct SpaprPhbState { #define SPAPR_PCI_NV2ATSD_WIN_SIZE (NVGPU_MAX_NUM * NVGPU_MAX_LINKS * \ 64 * KiB) -static inline qemu_irq spapr_phb_lsi_qirq(struct SpaprPhbState *phb, int pin) -{ - SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); - - return spapr_qirq(spapr, phb->lsi_table[pin].irq); -} - int spapr_dt_phb(SpaprPhbState *phb, uint32_t intc_phandle, void *fdt, uint32_t nr_msis, int *node_offset); From 7678b74a94a70186da3b3971d7ae92ca1a81c969 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 23 Sep 2019 15:50:09 +1000 Subject: [PATCH 40/53] spapr: Replace spapr_vio_qirq() helper with spapr_vio_irq_pulse() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every caller of spapr_vio_qirq() immediately calls qemu_irq_pulse() with the result, so we might as well just fold that into the helper. Signed-off-by: David Gibson Reviewed-by: Cédric Le Goater Reviewed-by: Greg Kurz Reviewed-by: Philippe Mathieu-Daudé --- hw/char/spapr_vty.c | 3 +-- hw/net/spapr_llan.c | 3 +-- hw/ppc/spapr_vio.c | 3 +-- include/hw/ppc/spapr_vio.h | 5 +++-- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/hw/char/spapr_vty.c b/hw/char/spapr_vty.c index 087c93e4fa..8f4d9fe472 100644 --- a/hw/char/spapr_vty.c +++ b/hw/char/spapr_vty.c @@ -5,7 +5,6 @@ #include "cpu.h" #include "migration/vmstate.h" #include "chardev/char-fe.h" -#include "hw/irq.h" #include "hw/ppc/spapr.h" #include "hw/ppc/spapr_vio.h" #include "hw/qdev-properties.h" @@ -37,7 +36,7 @@ static void vty_receive(void *opaque, const uint8_t *buf, int size) if ((dev->in == dev->out) && size) { /* toggle line to simulate edge interrupt */ - qemu_irq_pulse(spapr_vio_qirq(&dev->sdev)); + spapr_vio_irq_pulse(&dev->sdev); } for (i = 0; i < size; i++) { if (dev->in - dev->out >= VTERM_BUFSIZE) { diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c index 701e6e1514..3d96884d66 100644 --- a/hw/net/spapr_llan.c +++ b/hw/net/spapr_llan.c @@ -27,7 +27,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "hw/irq.h" #include "qemu/log.h" #include "qemu/module.h" #include "net/net.h" @@ -267,7 +266,7 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf, } if (sdev->signal_state & 1) { - qemu_irq_pulse(spapr_vio_qirq(sdev)); + spapr_vio_irq_pulse(sdev); } return size; diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c index 0803649658..554de9930d 100644 --- a/hw/ppc/spapr_vio.c +++ b/hw/ppc/spapr_vio.c @@ -23,7 +23,6 @@ #include "qemu/error-report.h" #include "qapi/error.h" #include "qapi/visitor.h" -#include "hw/irq.h" #include "qemu/log.h" #include "hw/loader.h" #include "elf.h" @@ -294,7 +293,7 @@ int spapr_vio_send_crq(SpaprVioDevice *dev, uint8_t *crq) dev->crq.qnext = (dev->crq.qnext + 16) % dev->crq.qsize; if (dev->signal_state & 1) { - qemu_irq_pulse(spapr_vio_qirq(dev)); + spapr_vio_irq_pulse(dev); } return 0; diff --git a/include/hw/ppc/spapr_vio.h b/include/hw/ppc/spapr_vio.h index 875be28cdd..72762ed16b 100644 --- a/include/hw/ppc/spapr_vio.h +++ b/include/hw/ppc/spapr_vio.h @@ -24,6 +24,7 @@ #include "hw/ppc/spapr.h" #include "sysemu/dma.h" +#include "hw/irq.h" #define TYPE_VIO_SPAPR_DEVICE "vio-spapr-device" #define VIO_SPAPR_DEVICE(obj) \ @@ -84,11 +85,11 @@ extern SpaprVioDevice *spapr_vio_find_by_reg(SpaprVioBus *bus, uint32_t reg); void spapr_dt_vdevice(SpaprVioBus *bus, void *fdt); extern gchar *spapr_vio_stdout_path(SpaprVioBus *bus); -static inline qemu_irq spapr_vio_qirq(SpaprVioDevice *dev) +static inline void spapr_vio_irq_pulse(SpaprVioDevice *dev) { SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); - return spapr_qirq(spapr, dev->irq); + qemu_irq_pulse(spapr_qirq(spapr, dev->irq)); } static inline bool spapr_vio_dma_valid(SpaprVioDevice *dev, uint64_t taddr, From ad8de98636e7cadeb1be4efa997cfe2a60bd5c30 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 24 Sep 2019 10:53:50 +1000 Subject: [PATCH 41/53] spapr: Clarify and fix handling of nr_irqs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both the XICS and XIVE interrupt backends have a "nr-irqs" property, but it means slightly different things. For XICS (or, strictly, the ICS) it indicates the number of "real" external IRQs. Those start at XICS_IRQ_BASE (0x1000) and don't include the special IPI vector. For XIVE, however, it includes the whole IRQ space, including XIVE's many IPI vectors. The spapr code currently doesn't handle this sensibly, with the nr_irqs value in SpaprIrq having different meanings depending on the backend. We fix this by renaming nr_irqs to nr_xirqs and making it always indicate just the number of external irqs, adjusting the value we pass to XIVE accordingly. We also move to using common constants in most of the irq configurations, to make it clearer that the IRQ space looks the same to the guest (and emulated devices), even if the backend is different. Signed-off-by: David Gibson Reviewed-by: Greg Kurz Reviewed-by: Cédric Le Goater --- hw/ppc/spapr_irq.c | 53 ++++++++++++++------------------------ include/hw/ppc/spapr_irq.h | 19 +++++++++----- 2 files changed, 31 insertions(+), 41 deletions(-) diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index 8c26fa2d1e..3207b6bd01 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -92,7 +92,7 @@ static void spapr_irq_init_kvm(SpaprMachineState *spapr, * XICS IRQ backend. */ -static void spapr_irq_init_xics(SpaprMachineState *spapr, int nr_irqs, +static void spapr_irq_init_xics(SpaprMachineState *spapr, int nr_xirqs, Error **errp) { Object *obj; @@ -102,7 +102,7 @@ static void spapr_irq_init_xics(SpaprMachineState *spapr, int nr_irqs, object_property_add_child(OBJECT(spapr), "ics", obj, &error_abort); object_property_add_const_link(obj, ICS_PROP_XICS, OBJECT(spapr), &error_fatal); - object_property_set_int(obj, nr_irqs, "nr-irqs", &error_fatal); + object_property_set_int(obj, nr_xirqs, "nr-irqs", &error_fatal); object_property_set_bool(obj, true, "realized", &local_err); if (local_err) { error_propagate(errp, local_err); @@ -234,13 +234,9 @@ static void spapr_irq_init_kvm_xics(SpaprMachineState *spapr, Error **errp) } } -#define SPAPR_IRQ_XICS_NR_IRQS 0x1000 -#define SPAPR_IRQ_XICS_NR_MSIS \ - (XICS_IRQ_BASE + SPAPR_IRQ_XICS_NR_IRQS - SPAPR_IRQ_MSI) - SpaprIrq spapr_irq_xics = { - .nr_irqs = SPAPR_IRQ_XICS_NR_IRQS, - .nr_msis = SPAPR_IRQ_XICS_NR_MSIS, + .nr_xirqs = SPAPR_NR_XIRQS, + .nr_msis = SPAPR_NR_MSIS, .ov5 = SPAPR_OV5_XIVE_LEGACY, .init = spapr_irq_init_xics, @@ -260,7 +256,7 @@ SpaprIrq spapr_irq_xics = { /* * XIVE IRQ backend. */ -static void spapr_irq_init_xive(SpaprMachineState *spapr, int nr_irqs, +static void spapr_irq_init_xive(SpaprMachineState *spapr, int nr_xirqs, Error **errp) { uint32_t nr_servers = spapr_max_server_number(spapr); @@ -268,7 +264,7 @@ static void spapr_irq_init_xive(SpaprMachineState *spapr, int nr_irqs, int i; dev = qdev_create(NULL, TYPE_SPAPR_XIVE); - qdev_prop_set_uint32(dev, "nr-irqs", nr_irqs); + qdev_prop_set_uint32(dev, "nr-irqs", nr_xirqs + SPAPR_XIRQ_BASE); /* * 8 XIVE END structures per CPU. One for each available priority */ @@ -308,7 +304,7 @@ static qemu_irq spapr_qirq_xive(SpaprMachineState *spapr, int irq) { SpaprXive *xive = spapr->xive; - if (irq >= xive->nr_irqs) { + if ((irq < SPAPR_XIRQ_BASE) || (irq >= xive->nr_irqs)) { return NULL; } @@ -404,17 +400,9 @@ static void spapr_irq_init_kvm_xive(SpaprMachineState *spapr, Error **errp) } } -/* - * XIVE uses the full IRQ number space. Set it to 8K to be compatible - * with XICS. - */ - -#define SPAPR_IRQ_XIVE_NR_IRQS 0x2000 -#define SPAPR_IRQ_XIVE_NR_MSIS (SPAPR_IRQ_XIVE_NR_IRQS - SPAPR_IRQ_MSI) - SpaprIrq spapr_irq_xive = { - .nr_irqs = SPAPR_IRQ_XIVE_NR_IRQS, - .nr_msis = SPAPR_IRQ_XIVE_NR_MSIS, + .nr_xirqs = SPAPR_NR_XIRQS, + .nr_msis = SPAPR_NR_MSIS, .ov5 = SPAPR_OV5_XIVE_EXPLOIT, .init = spapr_irq_init_xive, @@ -450,18 +438,18 @@ static SpaprIrq *spapr_irq_current(SpaprMachineState *spapr) &spapr_irq_xive : &spapr_irq_xics; } -static void spapr_irq_init_dual(SpaprMachineState *spapr, int nr_irqs, +static void spapr_irq_init_dual(SpaprMachineState *spapr, int nr_xirqs, Error **errp) { Error *local_err = NULL; - spapr_irq_xics.init(spapr, spapr_irq_xics.nr_irqs, &local_err); + spapr_irq_xics.init(spapr, spapr_irq_xics.nr_xirqs, &local_err); if (local_err) { error_propagate(errp, local_err); return; } - spapr_irq_xive.init(spapr, spapr_irq_xive.nr_irqs, &local_err); + spapr_irq_xive.init(spapr, spapr_irq_xive.nr_xirqs, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -586,12 +574,9 @@ static const char *spapr_irq_get_nodename_dual(SpaprMachineState *spapr) /* * Define values in sync with the XIVE and XICS backend */ -#define SPAPR_IRQ_DUAL_NR_IRQS 0x2000 -#define SPAPR_IRQ_DUAL_NR_MSIS (SPAPR_IRQ_DUAL_NR_IRQS - SPAPR_IRQ_MSI) - SpaprIrq spapr_irq_dual = { - .nr_irqs = SPAPR_IRQ_DUAL_NR_IRQS, - .nr_msis = SPAPR_IRQ_DUAL_NR_MSIS, + .nr_xirqs = SPAPR_NR_XIRQS, + .nr_msis = SPAPR_NR_MSIS, .ov5 = SPAPR_OV5_XIVE_BOTH, .init = spapr_irq_init_dual, @@ -693,10 +678,10 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp) spapr_irq_msi_init(spapr, spapr->irq->nr_msis); } - spapr->irq->init(spapr, spapr->irq->nr_irqs, errp); + spapr->irq->init(spapr, spapr->irq->nr_xirqs, errp); spapr->qirqs = qemu_allocate_irqs(spapr->irq->set_irq, spapr, - spapr->irq->nr_irqs); + spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE); } int spapr_irq_claim(SpaprMachineState *spapr, int irq, bool lsi, Error **errp) @@ -804,11 +789,11 @@ int spapr_irq_find(SpaprMachineState *spapr, int num, bool align, Error **errp) return first + ics->offset; } -#define SPAPR_IRQ_XICS_LEGACY_NR_IRQS 0x400 +#define SPAPR_IRQ_XICS_LEGACY_NR_XIRQS 0x400 SpaprIrq spapr_irq_xics_legacy = { - .nr_irqs = SPAPR_IRQ_XICS_LEGACY_NR_IRQS, - .nr_msis = SPAPR_IRQ_XICS_LEGACY_NR_IRQS, + .nr_xirqs = SPAPR_IRQ_XICS_LEGACY_NR_XIRQS, + .nr_msis = SPAPR_IRQ_XICS_LEGACY_NR_XIRQS, .ov5 = SPAPR_OV5_XIVE_LEGACY, .init = spapr_irq_init_xics, diff --git a/include/hw/ppc/spapr_irq.h b/include/hw/ppc/spapr_irq.h index 5db305165c..a8f9a2ab11 100644 --- a/include/hw/ppc/spapr_irq.h +++ b/include/hw/ppc/spapr_irq.h @@ -16,13 +16,18 @@ * IRQ range offsets per device type */ #define SPAPR_IRQ_IPI 0x0 -#define SPAPR_IRQ_EPOW 0x1000 /* XICS_IRQ_BASE offset */ -#define SPAPR_IRQ_HOTPLUG 0x1001 -#define SPAPR_IRQ_VIO 0x1100 /* 256 VIO devices */ -#define SPAPR_IRQ_PCI_LSI 0x1200 /* 32+ PHBs devices */ -#define SPAPR_IRQ_MSI 0x1300 /* Offset of the dynamic range covered - * by the bitmap allocator */ +#define SPAPR_XIRQ_BASE XICS_IRQ_BASE /* 0x1000 */ +#define SPAPR_IRQ_EPOW (SPAPR_XIRQ_BASE + 0x0000) +#define SPAPR_IRQ_HOTPLUG (SPAPR_XIRQ_BASE + 0x0001) +#define SPAPR_IRQ_VIO (SPAPR_XIRQ_BASE + 0x0100) /* 256 VIO devices */ +#define SPAPR_IRQ_PCI_LSI (SPAPR_XIRQ_BASE + 0x0200) /* 32+ PHBs devices */ + +/* Offset of the dynamic range covered by the bitmap allocator */ +#define SPAPR_IRQ_MSI (SPAPR_XIRQ_BASE + 0x0300) + +#define SPAPR_NR_XIRQS 0x1000 +#define SPAPR_NR_MSIS (SPAPR_XIRQ_BASE + SPAPR_NR_XIRQS - SPAPR_IRQ_MSI) typedef struct SpaprMachineState SpaprMachineState; @@ -32,7 +37,7 @@ int spapr_irq_msi_alloc(SpaprMachineState *spapr, uint32_t num, bool align, void spapr_irq_msi_free(SpaprMachineState *spapr, int irq, uint32_t num); typedef struct SpaprIrq { - uint32_t nr_irqs; + uint32_t nr_xirqs; uint32_t nr_msis; uint8_t ov5; From fe9b61b2468a6de170ae0e9afe92fa1daa7ab48b Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 24 Sep 2019 11:34:12 +1000 Subject: [PATCH 42/53] spapr: Eliminate nr_irqs parameter to SpaprIrq::init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The only reason this parameter was needed was to work around the inconsistent meaning of nr_irqs between xics and xive. Now that we've fixed that, we can consistently use the number directly in the SpaprIrq configuration. Signed-off-by: David Gibson Reviewed-by: Cédric Le Goater Reviewed-by: Greg Kurz --- hw/ppc/spapr_irq.c | 21 ++++++++++----------- include/hw/ppc/spapr_irq.h | 2 +- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index 3207b6bd01..cded3a0154 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -92,8 +92,7 @@ static void spapr_irq_init_kvm(SpaprMachineState *spapr, * XICS IRQ backend. */ -static void spapr_irq_init_xics(SpaprMachineState *spapr, int nr_xirqs, - Error **errp) +static void spapr_irq_init_xics(SpaprMachineState *spapr, Error **errp) { Object *obj; Error *local_err = NULL; @@ -102,7 +101,8 @@ static void spapr_irq_init_xics(SpaprMachineState *spapr, int nr_xirqs, object_property_add_child(OBJECT(spapr), "ics", obj, &error_abort); object_property_add_const_link(obj, ICS_PROP_XICS, OBJECT(spapr), &error_fatal); - object_property_set_int(obj, nr_xirqs, "nr-irqs", &error_fatal); + object_property_set_int(obj, spapr->irq->nr_xirqs, + "nr-irqs", &error_fatal); object_property_set_bool(obj, true, "realized", &local_err); if (local_err) { error_propagate(errp, local_err); @@ -256,15 +256,15 @@ SpaprIrq spapr_irq_xics = { /* * XIVE IRQ backend. */ -static void spapr_irq_init_xive(SpaprMachineState *spapr, int nr_xirqs, - Error **errp) +static void spapr_irq_init_xive(SpaprMachineState *spapr, Error **errp) { uint32_t nr_servers = spapr_max_server_number(spapr); DeviceState *dev; int i; dev = qdev_create(NULL, TYPE_SPAPR_XIVE); - qdev_prop_set_uint32(dev, "nr-irqs", nr_xirqs + SPAPR_XIRQ_BASE); + qdev_prop_set_uint32(dev, "nr-irqs", + spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE); /* * 8 XIVE END structures per CPU. One for each available priority */ @@ -438,18 +438,17 @@ static SpaprIrq *spapr_irq_current(SpaprMachineState *spapr) &spapr_irq_xive : &spapr_irq_xics; } -static void spapr_irq_init_dual(SpaprMachineState *spapr, int nr_xirqs, - Error **errp) +static void spapr_irq_init_dual(SpaprMachineState *spapr, Error **errp) { Error *local_err = NULL; - spapr_irq_xics.init(spapr, spapr_irq_xics.nr_xirqs, &local_err); + spapr_irq_xics.init(spapr, &local_err); if (local_err) { error_propagate(errp, local_err); return; } - spapr_irq_xive.init(spapr, spapr_irq_xive.nr_xirqs, &local_err); + spapr_irq_xive.init(spapr, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -678,7 +677,7 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp) spapr_irq_msi_init(spapr, spapr->irq->nr_msis); } - spapr->irq->init(spapr, spapr->irq->nr_xirqs, errp); + spapr->irq->init(spapr, errp); spapr->qirqs = qemu_allocate_irqs(spapr->irq->set_irq, spapr, spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE); diff --git a/include/hw/ppc/spapr_irq.h b/include/hw/ppc/spapr_irq.h index a8f9a2ab11..7e26288fcd 100644 --- a/include/hw/ppc/spapr_irq.h +++ b/include/hw/ppc/spapr_irq.h @@ -41,7 +41,7 @@ typedef struct SpaprIrq { uint32_t nr_msis; uint8_t ov5; - void (*init)(SpaprMachineState *spapr, int nr_irqs, Error **errp); + void (*init)(SpaprMachineState *spapr, Error **errp); int (*claim)(SpaprMachineState *spapr, int irq, bool lsi, Error **errp); void (*free)(SpaprMachineState *spapr, int irq, int num); qemu_irq (*qirq)(SpaprMachineState *spapr, int irq); From 9f53c0db19605f76324fb09af23d30e181a06211 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 24 Sep 2019 11:12:19 +1000 Subject: [PATCH 43/53] spapr: Fix indexing of XICS irqs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit spapr global irq numbers are different from the source numbers on the ICS when using XICS - they're offset by XICS_IRQ_BASE (0x1000). But spapr_irq_set_irq_xics() was passing through the global irq number to the ICS code unmodified. We only got away with this because of a counteracting bug - we were incorrectly adjusting the qemu_irq we returned for a requested global irq number. That approach mostly worked but is very confusing, incorrectly relies on the way the qemu_irq array is allocated, and undermines the intention of having the global array of qemu_irqs for spapr have a consistent meaning regardless of irq backend. So, fix both set_irq and qemu_irq indexing. We rename some parameters at the same time to make it clear that they are referring to spapr global irq numbers. Signed-off-by: David Gibson Reviewed-by: Cédric Le Goater Reviewed-by: Greg Kurz --- hw/ppc/spapr_irq.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index cded3a0154..8f79aa829f 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -153,10 +153,9 @@ static void spapr_irq_free_xics(SpaprMachineState *spapr, int irq, int num) static qemu_irq spapr_qirq_xics(SpaprMachineState *spapr, int irq) { ICSState *ics = spapr->ics; - uint32_t srcno = irq - ics->offset; if (ics_valid_irq(ics, irq)) { - return spapr->qirqs[srcno]; + return spapr->qirqs[irq]; } return NULL; @@ -204,9 +203,10 @@ static int spapr_irq_post_load_xics(SpaprMachineState *spapr, int version_id) return 0; } -static void spapr_irq_set_irq_xics(void *opaque, int srcno, int val) +static void spapr_irq_set_irq_xics(void *opaque, int irq, int val) { SpaprMachineState *spapr = opaque; + uint32_t srcno = irq - spapr->ics->offset; ics_set_irq(spapr->ics, srcno, val); } @@ -377,14 +377,14 @@ static void spapr_irq_reset_xive(SpaprMachineState *spapr, Error **errp) spapr_xive_mmio_set_enabled(spapr->xive, true); } -static void spapr_irq_set_irq_xive(void *opaque, int srcno, int val) +static void spapr_irq_set_irq_xive(void *opaque, int irq, int val) { SpaprMachineState *spapr = opaque; if (kvm_irqchip_in_kernel()) { - kvmppc_xive_source_set_irq(&spapr->xive->source, srcno, val); + kvmppc_xive_source_set_irq(&spapr->xive->source, irq, val); } else { - xive_source_set_irq(&spapr->xive->source, srcno, val); + xive_source_set_irq(&spapr->xive->source, irq, val); } } @@ -558,11 +558,11 @@ static void spapr_irq_reset_dual(SpaprMachineState *spapr, Error **errp) spapr_irq_current(spapr)->reset(spapr, errp); } -static void spapr_irq_set_irq_dual(void *opaque, int srcno, int val) +static void spapr_irq_set_irq_dual(void *opaque, int irq, int val) { SpaprMachineState *spapr = opaque; - spapr_irq_current(spapr)->set_irq(spapr, srcno, val); + spapr_irq_current(spapr)->set_irq(spapr, irq, val); } static const char *spapr_irq_get_nodename_dual(SpaprMachineState *spapr) From af1861511d3853664e5362ea3d2eb14b1f8d05b4 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 23 Sep 2019 16:18:28 +1000 Subject: [PATCH 44/53] spapr: Simplify spapr_qirq() handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently spapr_qirq(), whic is used to find the qemu_irq for an spapr global irq number, redirects through the SpaprIrq::qirq method. But the array of qemu_irqs is allocated in the PAPR layer, not the backends, and so the method implementations all return the same thing, just differing in the preliminary checks they make. So, we can remove the method, and just implement spapr_qirq() directly, including all the relevant checks in one place. We change all those checks into assert()s as well, since a failure here indicates an error in the calling code. Signed-off-by: David Gibson Reviewed-by: Cédric Le Goater Reviewed-by: Greg Kurz Reviewed-by: Philippe Mathieu-Daudé --- hw/ppc/spapr_irq.c | 54 ++++++++++++++------------------------ include/hw/ppc/spapr_irq.h | 1 - 2 files changed, 19 insertions(+), 36 deletions(-) diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index 8f79aa829f..8f179076c6 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -150,17 +150,6 @@ static void spapr_irq_free_xics(SpaprMachineState *spapr, int irq, int num) } } -static qemu_irq spapr_qirq_xics(SpaprMachineState *spapr, int irq) -{ - ICSState *ics = spapr->ics; - - if (ics_valid_irq(ics, irq)) { - return spapr->qirqs[irq]; - } - - return NULL; -} - static void spapr_irq_print_info_xics(SpaprMachineState *spapr, Monitor *mon) { CPUState *cs; @@ -242,7 +231,6 @@ SpaprIrq spapr_irq_xics = { .init = spapr_irq_init_xics, .claim = spapr_irq_claim_xics, .free = spapr_irq_free_xics, - .qirq = spapr_qirq_xics, .print_info = spapr_irq_print_info_xics, .dt_populate = spapr_dt_xics, .cpu_intc_create = spapr_irq_cpu_intc_create_xics, @@ -300,20 +288,6 @@ static void spapr_irq_free_xive(SpaprMachineState *spapr, int irq, int num) } } -static qemu_irq spapr_qirq_xive(SpaprMachineState *spapr, int irq) -{ - SpaprXive *xive = spapr->xive; - - if ((irq < SPAPR_XIRQ_BASE) || (irq >= xive->nr_irqs)) { - return NULL; - } - - /* The sPAPR machine/device should have claimed the IRQ before */ - assert(xive_eas_is_valid(&xive->eat[irq])); - - return spapr->qirqs[irq]; -} - static void spapr_irq_print_info_xive(SpaprMachineState *spapr, Monitor *mon) { @@ -408,7 +382,6 @@ SpaprIrq spapr_irq_xive = { .init = spapr_irq_init_xive, .claim = spapr_irq_claim_xive, .free = spapr_irq_free_xive, - .qirq = spapr_qirq_xive, .print_info = spapr_irq_print_info_xive, .dt_populate = spapr_dt_xive, .cpu_intc_create = spapr_irq_cpu_intc_create_xive, @@ -482,11 +455,6 @@ static void spapr_irq_free_dual(SpaprMachineState *spapr, int irq, int num) spapr_irq_xive.free(spapr, irq, num); } -static qemu_irq spapr_qirq_dual(SpaprMachineState *spapr, int irq) -{ - return spapr_irq_current(spapr)->qirq(spapr, irq); -} - static void spapr_irq_print_info_dual(SpaprMachineState *spapr, Monitor *mon) { spapr_irq_current(spapr)->print_info(spapr, mon); @@ -581,7 +549,6 @@ SpaprIrq spapr_irq_dual = { .init = spapr_irq_init_dual, .claim = spapr_irq_claim_dual, .free = spapr_irq_free_dual, - .qirq = spapr_qirq_dual, .print_info = spapr_irq_print_info_dual, .dt_populate = spapr_irq_dt_populate_dual, .cpu_intc_create = spapr_irq_cpu_intc_create_dual, @@ -695,7 +662,25 @@ void spapr_irq_free(SpaprMachineState *spapr, int irq, int num) qemu_irq spapr_qirq(SpaprMachineState *spapr, int irq) { - return spapr->irq->qirq(spapr, irq); + /* + * This interface is basically for VIO and PHB devices to find the + * right qemu_irq to manipulate, so we only allow access to the + * external irqs for now. Currently anything which needs to + * access the IPIs most naturally gets there via the guest side + * interfaces, we can change this if we need to in future. + */ + assert(irq >= SPAPR_XIRQ_BASE); + assert(irq < (spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE)); + + if (spapr->ics) { + assert(ics_valid_irq(spapr->ics, irq)); + } + if (spapr->xive) { + assert(irq < spapr->xive->nr_irqs); + assert(xive_eas_is_valid(&spapr->xive->eat[irq])); + } + + return spapr->qirqs[irq]; } int spapr_irq_post_load(SpaprMachineState *spapr, int version_id) @@ -798,7 +783,6 @@ SpaprIrq spapr_irq_xics_legacy = { .init = spapr_irq_init_xics, .claim = spapr_irq_claim_xics, .free = spapr_irq_free_xics, - .qirq = spapr_qirq_xics, .print_info = spapr_irq_print_info_xics, .dt_populate = spapr_dt_xics, .cpu_intc_create = spapr_irq_cpu_intc_create_xics, diff --git a/include/hw/ppc/spapr_irq.h b/include/hw/ppc/spapr_irq.h index 7e26288fcd..a4e790ef60 100644 --- a/include/hw/ppc/spapr_irq.h +++ b/include/hw/ppc/spapr_irq.h @@ -44,7 +44,6 @@ typedef struct SpaprIrq { void (*init)(SpaprMachineState *spapr, Error **errp); int (*claim)(SpaprMachineState *spapr, int irq, bool lsi, Error **errp); void (*free)(SpaprMachineState *spapr, int irq, int num); - qemu_irq (*qirq)(SpaprMachineState *spapr, int irq); void (*print_info)(SpaprMachineState *spapr, Monitor *mon); void (*dt_populate)(SpaprMachineState *spapr, uint32_t nr_servers, void *fdt, uint32_t phandle); From 14789694cd1ba57b1d548451b8b7630e888d679f Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 23 Sep 2019 15:19:28 +1000 Subject: [PATCH 45/53] spapr: Eliminate SpaprIrq:get_nodename method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This method is used to determine the name of the irq backend's node in the device tree, so that we can find its phandle (after SLOF may have modified it from the phandle we initially gave it). But, in the two cases the only difference between the node name is the presence of a unit address. Searching for a node name without considering unit address is standard practice for the device tree, and fdt_subnode_offset() will do exactly that, making this method unecessary. While we're there, remove the XICS_NODENAME define. The name "interrupt-controller" is required by PAPR (and IEEE1275), and a bunch of places assume it already. Signed-off-by: David Gibson Reviewed-by: Cédric Le Goater Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Greg Kurz --- hw/intc/xics_spapr.c | 2 +- hw/ppc/spapr_irq.c | 25 +++---------------------- include/hw/ppc/spapr_irq.h | 1 - include/hw/ppc/xics_spapr.h | 2 -- 4 files changed, 4 insertions(+), 26 deletions(-) diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c index e6dd004587..6e5eb24b3c 100644 --- a/hw/intc/xics_spapr.c +++ b/hw/intc/xics_spapr.c @@ -316,7 +316,7 @@ void spapr_dt_xics(SpaprMachineState *spapr, uint32_t nr_servers, void *fdt, }; int node; - _FDT(node = fdt_add_subnode(fdt, 0, XICS_NODENAME)); + _FDT(node = fdt_add_subnode(fdt, 0, "interrupt-controller")); _FDT(fdt_setprop_string(fdt, node, "device_type", "PowerPC-External-Interrupt-Presentation")); diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index 8f179076c6..ec2229d2d1 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -211,11 +211,6 @@ static void spapr_irq_reset_xics(SpaprMachineState *spapr, Error **errp) } } -static const char *spapr_irq_get_nodename_xics(SpaprMachineState *spapr) -{ - return XICS_NODENAME; -} - static void spapr_irq_init_kvm_xics(SpaprMachineState *spapr, Error **errp) { if (kvm_enabled()) { @@ -237,7 +232,6 @@ SpaprIrq spapr_irq_xics = { .post_load = spapr_irq_post_load_xics, .reset = spapr_irq_reset_xics, .set_irq = spapr_irq_set_irq_xics, - .get_nodename = spapr_irq_get_nodename_xics, .init_kvm = spapr_irq_init_kvm_xics, }; @@ -362,11 +356,6 @@ static void spapr_irq_set_irq_xive(void *opaque, int irq, int val) } } -static const char *spapr_irq_get_nodename_xive(SpaprMachineState *spapr) -{ - return spapr->xive->nodename; -} - static void spapr_irq_init_kvm_xive(SpaprMachineState *spapr, Error **errp) { if (kvm_enabled()) { @@ -388,7 +377,6 @@ SpaprIrq spapr_irq_xive = { .post_load = spapr_irq_post_load_xive, .reset = spapr_irq_reset_xive, .set_irq = spapr_irq_set_irq_xive, - .get_nodename = spapr_irq_get_nodename_xive, .init_kvm = spapr_irq_init_kvm_xive, }; @@ -533,11 +521,6 @@ static void spapr_irq_set_irq_dual(void *opaque, int irq, int val) spapr_irq_current(spapr)->set_irq(spapr, irq, val); } -static const char *spapr_irq_get_nodename_dual(SpaprMachineState *spapr) -{ - return spapr_irq_current(spapr)->get_nodename(spapr); -} - /* * Define values in sync with the XIVE and XICS backend */ @@ -555,7 +538,6 @@ SpaprIrq spapr_irq_dual = { .post_load = spapr_irq_post_load_dual, .reset = spapr_irq_reset_dual, .set_irq = spapr_irq_set_irq_dual, - .get_nodename = spapr_irq_get_nodename_dual, .init_kvm = NULL, /* should not be used */ }; @@ -699,13 +681,13 @@ void spapr_irq_reset(SpaprMachineState *spapr, Error **errp) int spapr_irq_get_phandle(SpaprMachineState *spapr, void *fdt, Error **errp) { - const char *nodename = spapr->irq->get_nodename(spapr); + const char *nodename = "interrupt-controller"; int offset, phandle; offset = fdt_subnode_offset(fdt, 0, nodename); if (offset < 0) { - error_setg(errp, "Can't find node \"%s\": %s", nodename, - fdt_strerror(offset)); + error_setg(errp, "Can't find node \"%s\": %s", + nodename, fdt_strerror(offset)); return -1; } @@ -789,6 +771,5 @@ SpaprIrq spapr_irq_xics_legacy = { .post_load = spapr_irq_post_load_xics, .reset = spapr_irq_reset_xics, .set_irq = spapr_irq_set_irq_xics, - .get_nodename = spapr_irq_get_nodename_xics, .init_kvm = spapr_irq_init_kvm_xics, }; diff --git a/include/hw/ppc/spapr_irq.h b/include/hw/ppc/spapr_irq.h index a4e790ef60..9b60378e28 100644 --- a/include/hw/ppc/spapr_irq.h +++ b/include/hw/ppc/spapr_irq.h @@ -52,7 +52,6 @@ typedef struct SpaprIrq { int (*post_load)(SpaprMachineState *spapr, int version_id); void (*reset)(SpaprMachineState *spapr, Error **errp); void (*set_irq)(void *opaque, int srcno, int val); - const char *(*get_nodename)(SpaprMachineState *spapr); void (*init_kvm)(SpaprMachineState *spapr, Error **errp); } SpaprIrq; diff --git a/include/hw/ppc/xics_spapr.h b/include/hw/ppc/xics_spapr.h index 691a6d00f7..0b35e85c26 100644 --- a/include/hw/ppc/xics_spapr.h +++ b/include/hw/ppc/xics_spapr.h @@ -29,8 +29,6 @@ #include "hw/ppc/spapr.h" -#define XICS_NODENAME "interrupt-controller" - #define TYPE_ICS_SPAPR "ics-spapr" #define ICS_SPAPR(obj) OBJECT_CHECK(ICSState, (obj), TYPE_ICS_SPAPR) From 85d0425652a5117164d716a284df5aa22ddf44fe Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 25 Sep 2019 00:05:03 +1000 Subject: [PATCH 46/53] spapr: Remove unhelpful tracepoints from spapr_irq_free_xics() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These traces contain some useless information (the always-0 source#) and have no equivalents for XIVE mode. For now just remove them, and we can put back something more sensible if and when we need it. Signed-off-by: David Gibson Reviewed-by: Cédric Le Goater Reviewed-by: Greg Kurz Reviewed-by: Philippe Mathieu-Daudé --- hw/ppc/spapr_irq.c | 4 ---- hw/ppc/trace-events | 4 ---- 2 files changed, 8 deletions(-) diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index ec2229d2d1..9919910a86 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -140,11 +140,7 @@ static void spapr_irq_free_xics(SpaprMachineState *spapr, int irq, int num) int i; if (ics_valid_irq(ics, irq)) { - trace_spapr_irq_free(0, irq, num); for (i = srcno; i < srcno + num; ++i) { - if (ics_irq_free(ics, i)) { - trace_spapr_irq_free_warn(0, i); - } memset(&ics->irqs[i], 0, sizeof(ICSIRQState)); } } diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events index 96dad767a1..9ea620f23c 100644 --- a/hw/ppc/trace-events +++ b/hw/ppc/trace-events @@ -13,10 +13,6 @@ spapr_pci_msi_retry(unsigned config_addr, unsigned req_num, unsigned max_irqs) " spapr_cas_failed(unsigned long n) "DT diff buffer is too small: %ld bytes" spapr_cas_continue(unsigned long n) "Copy changes to the guest: %ld bytes" -# spapr_irq.c -spapr_irq_free(int src, int irq, int num) "Source#%d, first irq %d, %d irqs" -spapr_irq_free_warn(int src, int irq) "Source#%d, irq %d is already free" - # spapr_hcall.c spapr_cas_pvr(uint32_t cur_pvr, bool explicit_match, uint32_t new_pvr) "current=0x%x, explicit_match=%u, new=0x%x" spapr_h_resize_hpt_prepare(uint64_t flags, uint64_t shift) "flags=0x%"PRIx64", shift=%"PRIu64 From f233cee97bfbab24517171ef5a56d8a54d8a96ef Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 25 Sep 2019 00:12:21 +1000 Subject: [PATCH 47/53] spapr: Handle freeing of multiple irqs in frontend only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit spapr_irq_free() can be used to free multiple irqs at once. That's useful for its callers, but there's no need to make the individual backend hooks handle this. We can loop across the irqs in spapr_irq_free() itself and have the hooks just do one at time. Signed-off-by: David Gibson Reviewed-by: Greg Kurz Reviewed-by: Cédric Le Goater --- hw/ppc/spapr_irq.c | 27 ++++++++++++--------------- include/hw/ppc/spapr_irq.h | 2 +- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index 9919910a86..d2ac35bbe1 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -133,16 +133,13 @@ static int spapr_irq_claim_xics(SpaprMachineState *spapr, int irq, bool lsi, return 0; } -static void spapr_irq_free_xics(SpaprMachineState *spapr, int irq, int num) +static void spapr_irq_free_xics(SpaprMachineState *spapr, int irq) { ICSState *ics = spapr->ics; uint32_t srcno = irq - ics->offset; - int i; if (ics_valid_irq(ics, irq)) { - for (i = srcno; i < srcno + num; ++i) { - memset(&ics->irqs[i], 0, sizeof(ICSIRQState)); - } + memset(&ics->irqs[srcno], 0, sizeof(ICSIRQState)); } } @@ -269,13 +266,9 @@ static int spapr_irq_claim_xive(SpaprMachineState *spapr, int irq, bool lsi, return 0; } -static void spapr_irq_free_xive(SpaprMachineState *spapr, int irq, int num) +static void spapr_irq_free_xive(SpaprMachineState *spapr, int irq) { - int i; - - for (i = irq; i < irq + num; ++i) { - spapr_xive_irq_free(spapr->xive, i); - } + spapr_xive_irq_free(spapr->xive, irq); } static void spapr_irq_print_info_xive(SpaprMachineState *spapr, @@ -433,10 +426,10 @@ static int spapr_irq_claim_dual(SpaprMachineState *spapr, int irq, bool lsi, return ret; } -static void spapr_irq_free_dual(SpaprMachineState *spapr, int irq, int num) +static void spapr_irq_free_dual(SpaprMachineState *spapr, int irq) { - spapr_irq_xics.free(spapr, irq, num); - spapr_irq_xive.free(spapr, irq, num); + spapr_irq_xics.free(spapr, irq); + spapr_irq_xive.free(spapr, irq); } static void spapr_irq_print_info_dual(SpaprMachineState *spapr, Monitor *mon) @@ -635,7 +628,11 @@ int spapr_irq_claim(SpaprMachineState *spapr, int irq, bool lsi, Error **errp) void spapr_irq_free(SpaprMachineState *spapr, int irq, int num) { - spapr->irq->free(spapr, irq, num); + int i; + + for (i = irq; i < (irq + num); i++) { + spapr->irq->free(spapr, i); + } } qemu_irq spapr_qirq(SpaprMachineState *spapr, int irq) diff --git a/include/hw/ppc/spapr_irq.h b/include/hw/ppc/spapr_irq.h index 9b60378e28..ed88b4599a 100644 --- a/include/hw/ppc/spapr_irq.h +++ b/include/hw/ppc/spapr_irq.h @@ -43,7 +43,7 @@ typedef struct SpaprIrq { void (*init)(SpaprMachineState *spapr, Error **errp); int (*claim)(SpaprMachineState *spapr, int irq, bool lsi, Error **errp); - void (*free)(SpaprMachineState *spapr, int irq, int num); + void (*free)(SpaprMachineState *spapr, int irq); void (*print_info)(SpaprMachineState *spapr, Monitor *mon); void (*dt_populate)(SpaprMachineState *spapr, uint32_t nr_servers, void *fdt, uint32_t phandle); From 580dde5e4a4597be26cb948a711727c2a406f158 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 25 Sep 2019 13:49:59 +1000 Subject: [PATCH 48/53] spapr, xics, xive: Better use of assert()s on irq claim/free paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The irq claim and free paths for both XICS and XIVE check for some validity conditions. Some of these represent genuine runtime failures, however others - particularly checking that the basic irq number is in a sane range - could only fail in the case of bugs in the callin code. Therefore use assert()s instead of runtime failures for those. In addition the non backend-specific part of the claim/free paths should only be used for PAPR external irqs, that is in the range SPAPR_XIRQ_BASE to the maximum irq number. Put assert()s for that into the top level dispatchers as well. Signed-off-by: David Gibson Reviewed-by: Cédric Le Goater Reviewed-by: Greg Kurz --- hw/intc/spapr_xive.c | 8 ++------ hw/ppc/spapr_irq.c | 18 ++++++++++-------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c index c1c97192a7..47b5ec0b56 100644 --- a/hw/intc/spapr_xive.c +++ b/hw/intc/spapr_xive.c @@ -532,9 +532,7 @@ bool spapr_xive_irq_claim(SpaprXive *xive, uint32_t lisn, bool lsi) { XiveSource *xsrc = &xive->source; - if (lisn >= xive->nr_irqs) { - return false; - } + assert(lisn < xive->nr_irqs); /* * Set default values when allocating an IRQ number @@ -559,9 +557,7 @@ bool spapr_xive_irq_claim(SpaprXive *xive, uint32_t lisn, bool lsi) bool spapr_xive_irq_free(SpaprXive *xive, uint32_t lisn) { - if (lisn >= xive->nr_irqs) { - return false; - } + assert(lisn < xive->nr_irqs); xive->eat[lisn].w &= cpu_to_be64(~EAS_VALID); return true; diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index d2ac35bbe1..025c802e7b 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -118,11 +118,7 @@ static int spapr_irq_claim_xics(SpaprMachineState *spapr, int irq, bool lsi, ICSState *ics = spapr->ics; assert(ics); - - if (!ics_valid_irq(ics, irq)) { - error_setg(errp, "IRQ %d is invalid", irq); - return -1; - } + assert(ics_valid_irq(ics, irq)); if (!ics_irq_free(ics, irq - ics->offset)) { error_setg(errp, "IRQ %d is not free", irq); @@ -138,9 +134,9 @@ static void spapr_irq_free_xics(SpaprMachineState *spapr, int irq) ICSState *ics = spapr->ics; uint32_t srcno = irq - ics->offset; - if (ics_valid_irq(ics, irq)) { - memset(&ics->irqs[srcno], 0, sizeof(ICSIRQState)); - } + assert(ics_valid_irq(ics, irq)); + + memset(&ics->irqs[srcno], 0, sizeof(ICSIRQState)); } static void spapr_irq_print_info_xics(SpaprMachineState *spapr, Monitor *mon) @@ -623,6 +619,9 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp) int spapr_irq_claim(SpaprMachineState *spapr, int irq, bool lsi, Error **errp) { + assert(irq >= SPAPR_XIRQ_BASE); + assert(irq < (spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE)); + return spapr->irq->claim(spapr, irq, lsi, errp); } @@ -630,6 +629,9 @@ void spapr_irq_free(SpaprMachineState *spapr, int irq, int num) { int i; + assert(irq >= SPAPR_XIRQ_BASE); + assert((irq + num) <= (spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE)); + for (i = irq; i < (irq + num); i++) { spapr->irq->free(spapr, i); } From e594c2ad1c3207ff308449203fd5abc002ac89c9 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 25 Sep 2019 13:24:14 +1000 Subject: [PATCH 49/53] xive: Improve irq claim/free path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit spapr_xive_irq_claim() returns a bool to indicate if it succeeded. But most of the callers and one callee use int return values and/or an Error * with more information instead. In any case, ints are a more common idiom for success/failure states than bools (one never knows what sense they'll be in). So instead change to an int return value to indicate presence of error + an Error * to describe the details through that call chain. It also didn't actually check if the irq was already claimed, which is one of the primary purposes of the claim path, so do that. spapr_xive_irq_free() also returned a bool... which no callers checked and was always true, so just drop it. Signed-off-by: David Gibson Reviewed-by: Cédric Le Goater Reviewed-by: Greg Kurz --- hw/intc/spapr_xive.c | 20 +++++++++----------- hw/intc/spapr_xive_kvm.c | 8 ++++---- hw/ppc/spapr_irq.c | 11 +++++------ include/hw/ppc/spapr_xive.h | 4 ++-- include/hw/ppc/xive.h | 2 +- 5 files changed, 21 insertions(+), 24 deletions(-) diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c index 47b5ec0b56..04879abf2e 100644 --- a/hw/intc/spapr_xive.c +++ b/hw/intc/spapr_xive.c @@ -528,12 +528,17 @@ static void spapr_xive_register_types(void) type_init(spapr_xive_register_types) -bool spapr_xive_irq_claim(SpaprXive *xive, uint32_t lisn, bool lsi) +int spapr_xive_irq_claim(SpaprXive *xive, int lisn, bool lsi, Error **errp) { XiveSource *xsrc = &xive->source; assert(lisn < xive->nr_irqs); + if (xive_eas_is_valid(&xive->eat[lisn])) { + error_setg(errp, "IRQ %d is not free", lisn); + return -EBUSY; + } + /* * Set default values when allocating an IRQ number */ @@ -543,24 +548,17 @@ bool spapr_xive_irq_claim(SpaprXive *xive, uint32_t lisn, bool lsi) } if (kvm_irqchip_in_kernel()) { - Error *local_err = NULL; - - kvmppc_xive_source_reset_one(xsrc, lisn, &local_err); - if (local_err) { - error_report_err(local_err); - return false; - } + return kvmppc_xive_source_reset_one(xsrc, lisn, errp); } - return true; + return 0; } -bool spapr_xive_irq_free(SpaprXive *xive, uint32_t lisn) +void spapr_xive_irq_free(SpaprXive *xive, int lisn) { assert(lisn < xive->nr_irqs); xive->eat[lisn].w &= cpu_to_be64(~EAS_VALID); - return true; } /* diff --git a/hw/intc/spapr_xive_kvm.c b/hw/intc/spapr_xive_kvm.c index 2006f96aec..51b334b676 100644 --- a/hw/intc/spapr_xive_kvm.c +++ b/hw/intc/spapr_xive_kvm.c @@ -232,14 +232,14 @@ void kvmppc_xive_sync_source(SpaprXive *xive, uint32_t lisn, Error **errp) * only need to inform the KVM XIVE device about their type: LSI or * MSI. */ -void kvmppc_xive_source_reset_one(XiveSource *xsrc, int srcno, Error **errp) +int kvmppc_xive_source_reset_one(XiveSource *xsrc, int srcno, Error **errp) { SpaprXive *xive = SPAPR_XIVE(xsrc->xive); uint64_t state = 0; /* The KVM XIVE device is not in use */ if (xive->fd == -1) { - return; + return -ENODEV; } if (xive_source_irq_is_lsi(xsrc, srcno)) { @@ -249,8 +249,8 @@ void kvmppc_xive_source_reset_one(XiveSource *xsrc, int srcno, Error **errp) } } - kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_SOURCE, srcno, &state, - true, errp); + return kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_SOURCE, srcno, &state, + true, errp); } static void kvmppc_xive_source_reset(XiveSource *xsrc, Error **errp) diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index 025c802e7b..516bf00a35 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -246,7 +246,10 @@ static void spapr_irq_init_xive(SpaprMachineState *spapr, Error **errp) /* Enable the CPU IPIs */ for (i = 0; i < nr_servers; ++i) { - spapr_xive_irq_claim(spapr->xive, SPAPR_IRQ_IPI + i, false); + if (spapr_xive_irq_claim(spapr->xive, SPAPR_IRQ_IPI + i, + false, errp) < 0) { + return; + } } spapr_xive_hcall_init(spapr); @@ -255,11 +258,7 @@ static void spapr_irq_init_xive(SpaprMachineState *spapr, Error **errp) static int spapr_irq_claim_xive(SpaprMachineState *spapr, int irq, bool lsi, Error **errp) { - if (!spapr_xive_irq_claim(spapr->xive, irq, lsi)) { - error_setg(errp, "IRQ %d is invalid", irq); - return -1; - } - return 0; + return spapr_xive_irq_claim(spapr->xive, irq, lsi, errp); } static void spapr_irq_free_xive(SpaprMachineState *spapr, int irq) diff --git a/include/hw/ppc/spapr_xive.h b/include/hw/ppc/spapr_xive.h index bfd40f01d8..0df20a6590 100644 --- a/include/hw/ppc/spapr_xive.h +++ b/include/hw/ppc/spapr_xive.h @@ -54,8 +54,8 @@ typedef struct SpaprXive { */ #define SPAPR_XIVE_BLOCK_ID 0x0 -bool spapr_xive_irq_claim(SpaprXive *xive, uint32_t lisn, bool lsi); -bool spapr_xive_irq_free(SpaprXive *xive, uint32_t lisn); +int spapr_xive_irq_claim(SpaprXive *xive, int lisn, bool lsi, Error **errp); +void spapr_xive_irq_free(SpaprXive *xive, int lisn); void spapr_xive_pic_print_info(SpaprXive *xive, Monitor *mon); int spapr_xive_post_load(SpaprXive *xive, int version_id); diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h index 6d38755f84..fd3319bd32 100644 --- a/include/hw/ppc/xive.h +++ b/include/hw/ppc/xive.h @@ -425,7 +425,7 @@ static inline uint32_t xive_nvt_cam_line(uint8_t nvt_blk, uint32_t nvt_idx) * KVM XIVE device helpers */ -void kvmppc_xive_source_reset_one(XiveSource *xsrc, int srcno, Error **errp); +int kvmppc_xive_source_reset_one(XiveSource *xsrc, int srcno, Error **errp); void kvmppc_xive_source_set_irq(void *opaque, int srcno, int val); void kvmppc_xive_cpu_connect(XiveTCTX *tctx, Error **errp); void kvmppc_xive_cpu_synchronize_state(XiveTCTX *tctx, Error **errp); From ca62823b79443e3f498c6e6b9fea5f8bbe61033e Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 25 Sep 2019 15:12:07 +1000 Subject: [PATCH 50/53] spapr: Use less cryptic representation of which irq backends are supported MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SpaprIrq::ov5 stores the value for a particular byte in PAPR option vector 5 which indicates whether XICS, XIVE or both interrupt controllers are available. As usual for PAPR, the encoding is kind of overly complicated and confusing (though to be fair there are some backwards compat things it has to handle). But to make our internal code clearer, have SpaprIrq encode more directly which backends are available as two booleans, and derive the OV5 value from that at the point we need it. Signed-off-by: David Gibson Reviewed-by: Cédric Le Goater Reviewed-by: Greg Kurz --- hw/ppc/spapr.c | 15 ++++++++++++--- hw/ppc/spapr_hcall.c | 6 +++--- hw/ppc/spapr_irq.c | 12 ++++++++---- include/hw/ppc/spapr_irq.h | 3 ++- 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 43920c140d..514a17ae74 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1066,19 +1066,28 @@ static void spapr_dt_ov5_platform_support(SpaprMachineState *spapr, void *fdt, PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu); char val[2 * 4] = { - 23, spapr->irq->ov5, /* Xive mode. */ + 23, 0x00, /* XICS / XIVE mode */ 24, 0x00, /* Hash/Radix, filled in below. */ 25, 0x00, /* Hash options: Segment Tables == no, GTSE == no. */ 26, 0x40, /* Radix options: GTSE == yes. */ }; + if (spapr->irq->xics && spapr->irq->xive) { + val[1] = SPAPR_OV5_XIVE_BOTH; + } else if (spapr->irq->xive) { + val[1] = SPAPR_OV5_XIVE_EXPLOIT; + } else { + assert(spapr->irq->xics); + val[1] = SPAPR_OV5_XIVE_LEGACY; + } + if (!ppc_check_compat(first_ppc_cpu, CPU_POWERPC_LOGICAL_3_00, 0, first_ppc_cpu->compat_pvr)) { /* * If we're in a pre POWER9 compat mode then the guest should * do hash and use the legacy interrupt mode */ - val[1] = 0x00; /* XICS */ + val[1] = SPAPR_OV5_XIVE_LEGACY; /* XICS */ val[3] = 0x00; /* Hash */ } else if (kvm_enabled()) { if (kvmppc_has_cap_mmu_radix() && kvmppc_has_cap_mmu_hash_v3()) { @@ -2767,7 +2776,7 @@ static void spapr_machine_init(MachineState *machine) spapr_ovec_set(spapr->ov5, OV5_DRMEM_V2); /* advertise XIVE on POWER9 machines */ - if (spapr->irq->ov5 & (SPAPR_OV5_XIVE_EXPLOIT | SPAPR_OV5_XIVE_BOTH)) { + if (spapr->irq->xive) { spapr_ovec_set(spapr->ov5, OV5_XIVE_EXPLOIT); } diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 3d3a67149a..140f05c1c6 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1784,13 +1784,13 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, * terminate the boot. */ if (guest_xive) { - if (spapr->irq->ov5 == SPAPR_OV5_XIVE_LEGACY) { + if (!spapr->irq->xive) { error_report( "Guest requested unavailable interrupt mode (XIVE), try the ic-mode=xive or ic-mode=dual machine property"); exit(EXIT_FAILURE); } } else { - if (spapr->irq->ov5 == SPAPR_OV5_XIVE_EXPLOIT) { + if (!spapr->irq->xics) { error_report( "Guest requested unavailable interrupt mode (XICS), either don't set the ic-mode machine property or try ic-mode=xics or ic-mode=dual"); exit(EXIT_FAILURE); @@ -1804,7 +1804,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, */ if (!spapr->cas_reboot) { spapr->cas_reboot = spapr_ovec_test(ov5_updates, OV5_XIVE_EXPLOIT) - && spapr->irq->ov5 & SPAPR_OV5_XIVE_BOTH; + && spapr->irq->xics && spapr->irq->xive; } spapr_ovec_cleanup(ov5_updates); diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index 516bf00a35..3ac67ba0c7 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -210,7 +210,8 @@ static void spapr_irq_init_kvm_xics(SpaprMachineState *spapr, Error **errp) SpaprIrq spapr_irq_xics = { .nr_xirqs = SPAPR_NR_XIRQS, .nr_msis = SPAPR_NR_MSIS, - .ov5 = SPAPR_OV5_XIVE_LEGACY, + .xics = true, + .xive = false, .init = spapr_irq_init_xics, .claim = spapr_irq_claim_xics, @@ -350,7 +351,8 @@ static void spapr_irq_init_kvm_xive(SpaprMachineState *spapr, Error **errp) SpaprIrq spapr_irq_xive = { .nr_xirqs = SPAPR_NR_XIRQS, .nr_msis = SPAPR_NR_MSIS, - .ov5 = SPAPR_OV5_XIVE_EXPLOIT, + .xics = false, + .xive = true, .init = spapr_irq_init_xive, .claim = spapr_irq_claim_xive, @@ -511,7 +513,8 @@ static void spapr_irq_set_irq_dual(void *opaque, int irq, int val) SpaprIrq spapr_irq_dual = { .nr_xirqs = SPAPR_NR_XIRQS, .nr_msis = SPAPR_NR_MSIS, - .ov5 = SPAPR_OV5_XIVE_BOTH, + .xics = true, + .xive = true, .init = spapr_irq_init_dual, .claim = spapr_irq_claim_dual, @@ -754,7 +757,8 @@ int spapr_irq_find(SpaprMachineState *spapr, int num, bool align, Error **errp) SpaprIrq spapr_irq_xics_legacy = { .nr_xirqs = SPAPR_IRQ_XICS_LEGACY_NR_XIRQS, .nr_msis = SPAPR_IRQ_XICS_LEGACY_NR_XIRQS, - .ov5 = SPAPR_OV5_XIVE_LEGACY, + .xics = true, + .xive = false, .init = spapr_irq_init_xics, .claim = spapr_irq_claim_xics, diff --git a/include/hw/ppc/spapr_irq.h b/include/hw/ppc/spapr_irq.h index ed88b4599a..d3f3b85eb9 100644 --- a/include/hw/ppc/spapr_irq.h +++ b/include/hw/ppc/spapr_irq.h @@ -39,7 +39,8 @@ void spapr_irq_msi_free(SpaprMachineState *spapr, int irq, uint32_t num); typedef struct SpaprIrq { uint32_t nr_xirqs; uint32_t nr_msis; - uint8_t ov5; + bool xics; + bool xive; void (*init)(SpaprMachineState *spapr, Error **errp); int (*claim)(SpaprMachineState *spapr, int irq, bool lsi, Error **errp); From 0a3fd3df6f6a9b318909ab8400172d2d5a42abf9 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 30 Sep 2019 12:20:47 +1000 Subject: [PATCH 51/53] spapr: Add return value to spapr_irq_check() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Explicitly return success or failure, rather than just relying on the Error ** parameter. This makes handling it less verbose in the caller. Signed-off-by: David Gibson Reviewed-by: Cédric Le Goater Reviewed-by: Greg Kurz --- hw/ppc/spapr_irq.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index 3ac67ba0c7..0413fbd0a3 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -529,7 +529,7 @@ SpaprIrq spapr_irq_dual = { }; -static void spapr_irq_check(SpaprMachineState *spapr, Error **errp) +static int spapr_irq_check(SpaprMachineState *spapr, Error **errp) { MachineState *machine = MACHINE(spapr); @@ -545,7 +545,7 @@ static void spapr_irq_check(SpaprMachineState *spapr, Error **errp) */ if (spapr->irq == &spapr_irq_dual) { spapr->irq = &spapr_irq_xics; - return; + return 0; } /* @@ -565,7 +565,7 @@ static void spapr_irq_check(SpaprMachineState *spapr, Error **errp) */ if (spapr->irq == &spapr_irq_xive) { error_setg(errp, "XIVE-only machines require a POWER9 CPU"); - return; + return -1; } } @@ -579,8 +579,10 @@ static void spapr_irq_check(SpaprMachineState *spapr, Error **errp) machine_kernel_irqchip_required(machine) && xics_kvm_has_broken_disconnect(spapr)) { error_setg(errp, "KVM is too old to support ic-mode=dual,kernel-irqchip=on"); - return; + return -1; } + + return 0; } /* @@ -589,7 +591,6 @@ static void spapr_irq_check(SpaprMachineState *spapr, Error **errp) void spapr_irq_init(SpaprMachineState *spapr, Error **errp) { MachineState *machine = MACHINE(spapr); - Error *local_err = NULL; if (machine_kernel_irqchip_split(machine)) { error_setg(errp, "kernel_irqchip split mode not supported on pseries"); @@ -602,9 +603,7 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp) return; } - spapr_irq_check(spapr, &local_err); - if (local_err) { - error_propagate(errp, local_err); + if (spapr_irq_check(spapr, errp) < 0) { return; } From f478d9af213f169449f7aaba7257aba1a4032e1e Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 30 Sep 2019 12:24:43 +1000 Subject: [PATCH 52/53] spapr: Eliminate SpaprIrq::init hook MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This method is used to set up the interrupt backends for the current configuration. However, this means some confusing redirection between the "dual" mode init and the init hooks for xics only and xive only modes. Since we now have simple flags indicating whether XICS and/or XIVE are supported, it's easier to just open code each initialization directly in spapr_irq_init(). This will also make some future cleanups simpler. Signed-off-by: David Gibson Reviewed-by: Cédric Le Goater Reviewed-by: Greg Kurz --- hw/ppc/spapr_irq.c | 130 +++++++++++++++++-------------------- include/hw/ppc/spapr_irq.h | 1 - 2 files changed, 61 insertions(+), 70 deletions(-) diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index 0413fbd0a3..457eabe24c 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -92,26 +92,6 @@ static void spapr_irq_init_kvm(SpaprMachineState *spapr, * XICS IRQ backend. */ -static void spapr_irq_init_xics(SpaprMachineState *spapr, Error **errp) -{ - Object *obj; - Error *local_err = NULL; - - obj = object_new(TYPE_ICS_SPAPR); - object_property_add_child(OBJECT(spapr), "ics", obj, &error_abort); - object_property_add_const_link(obj, ICS_PROP_XICS, OBJECT(spapr), - &error_fatal); - object_property_set_int(obj, spapr->irq->nr_xirqs, - "nr-irqs", &error_fatal); - object_property_set_bool(obj, true, "realized", &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - spapr->ics = ICS_SPAPR(obj); -} - static int spapr_irq_claim_xics(SpaprMachineState *spapr, int irq, bool lsi, Error **errp) { @@ -213,7 +193,6 @@ SpaprIrq spapr_irq_xics = { .xics = true, .xive = false, - .init = spapr_irq_init_xics, .claim = spapr_irq_claim_xics, .free = spapr_irq_free_xics, .print_info = spapr_irq_print_info_xics, @@ -228,33 +207,6 @@ SpaprIrq spapr_irq_xics = { /* * XIVE IRQ backend. */ -static void spapr_irq_init_xive(SpaprMachineState *spapr, Error **errp) -{ - uint32_t nr_servers = spapr_max_server_number(spapr); - DeviceState *dev; - int i; - - dev = qdev_create(NULL, TYPE_SPAPR_XIVE); - qdev_prop_set_uint32(dev, "nr-irqs", - spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE); - /* - * 8 XIVE END structures per CPU. One for each available priority - */ - qdev_prop_set_uint32(dev, "nr-ends", nr_servers << 3); - qdev_init_nofail(dev); - - spapr->xive = SPAPR_XIVE(dev); - - /* Enable the CPU IPIs */ - for (i = 0; i < nr_servers; ++i) { - if (spapr_xive_irq_claim(spapr->xive, SPAPR_IRQ_IPI + i, - false, errp) < 0) { - return; - } - } - - spapr_xive_hcall_init(spapr); -} static int spapr_irq_claim_xive(SpaprMachineState *spapr, int irq, bool lsi, Error **errp) @@ -354,7 +306,6 @@ SpaprIrq spapr_irq_xive = { .xics = false, .xive = true, - .init = spapr_irq_init_xive, .claim = spapr_irq_claim_xive, .free = spapr_irq_free_xive, .print_info = spapr_irq_print_info_xive, @@ -385,23 +336,6 @@ static SpaprIrq *spapr_irq_current(SpaprMachineState *spapr) &spapr_irq_xive : &spapr_irq_xics; } -static void spapr_irq_init_dual(SpaprMachineState *spapr, Error **errp) -{ - Error *local_err = NULL; - - spapr_irq_xics.init(spapr, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - spapr_irq_xive.init(spapr, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } -} - static int spapr_irq_claim_dual(SpaprMachineState *spapr, int irq, bool lsi, Error **errp) { @@ -516,7 +450,6 @@ SpaprIrq spapr_irq_dual = { .xics = true, .xive = true, - .init = spapr_irq_init_dual, .claim = spapr_irq_claim_dual, .free = spapr_irq_free_dual, .print_info = spapr_irq_print_info_dual, @@ -612,7 +545,67 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp) spapr_irq_msi_init(spapr, spapr->irq->nr_msis); } - spapr->irq->init(spapr, errp); + if (spapr->irq->xics) { + Error *local_err = NULL; + Object *obj; + + obj = object_new(TYPE_ICS_SPAPR); + object_property_add_child(OBJECT(spapr), "ics", obj, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + object_property_add_const_link(obj, ICS_PROP_XICS, OBJECT(spapr), + &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + object_property_set_int(obj, spapr->irq->nr_xirqs, "nr-irqs", + &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + object_property_set_bool(obj, true, "realized", &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + spapr->ics = ICS_SPAPR(obj); + } + + if (spapr->irq->xive) { + uint32_t nr_servers = spapr_max_server_number(spapr); + DeviceState *dev; + int i; + + dev = qdev_create(NULL, TYPE_SPAPR_XIVE); + qdev_prop_set_uint32(dev, "nr-irqs", + spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE); + /* + * 8 XIVE END structures per CPU. One for each available + * priority + */ + qdev_prop_set_uint32(dev, "nr-ends", nr_servers << 3); + qdev_init_nofail(dev); + + spapr->xive = SPAPR_XIVE(dev); + + /* Enable the CPU IPIs */ + for (i = 0; i < nr_servers; ++i) { + if (spapr_xive_irq_claim(spapr->xive, SPAPR_IRQ_IPI + i, + false, errp) < 0) { + return; + } + } + + spapr_xive_hcall_init(spapr); + } spapr->qirqs = qemu_allocate_irqs(spapr->irq->set_irq, spapr, spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE); @@ -759,7 +752,6 @@ SpaprIrq spapr_irq_xics_legacy = { .xics = true, .xive = false, - .init = spapr_irq_init_xics, .claim = spapr_irq_claim_xics, .free = spapr_irq_free_xics, .print_info = spapr_irq_print_info_xics, diff --git a/include/hw/ppc/spapr_irq.h b/include/hw/ppc/spapr_irq.h index d3f3b85eb9..69a37f608e 100644 --- a/include/hw/ppc/spapr_irq.h +++ b/include/hw/ppc/spapr_irq.h @@ -42,7 +42,6 @@ typedef struct SpaprIrq { bool xics; bool xive; - void (*init)(SpaprMachineState *spapr, Error **errp); int (*claim)(SpaprMachineState *spapr, int irq, bool lsi, Error **errp); void (*free)(SpaprMachineState *spapr, int irq); void (*print_info)(SpaprMachineState *spapr, Monitor *mon); From 1aba8716c8335e88b8c358002a6e1ac89f7dd258 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Thu, 3 Oct 2019 16:36:17 +0200 Subject: [PATCH 53/53] ppc/pnv: Remove the XICSFabric Interface from the POWER9 machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The POWER8 PowerNV machine needs to implement a XICSFabric interface as this is the POWER8 interrupt controller model. But the POWER9 machine uselessly inherits of XICSFabric from the common PowerNV machine definition. Open code machine definitions to have a better control on the different interfaces each machine should define. Fixes: f30c843ced50 ("ppc/pnv: Introduce PowerNV machines with fixed CPU models") Signed-off-by: Cédric Le Goater Message-Id: <20191003143617.21682-1-clg@kaod.org> Signed-off-by: David Gibson --- hw/ppc/pnv.c | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 77a86c6a23..7cf64b6d25 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -1485,23 +1485,21 @@ static void pnv_machine_class_init(ObjectClass *oc, void *data) .parent = TYPE_PNV9_CHIP, \ } -#define DEFINE_PNV_MACHINE_TYPE(cpu, class_initfn) \ - { \ - .name = MACHINE_TYPE_NAME(cpu), \ - .parent = TYPE_PNV_MACHINE, \ - .instance_size = sizeof(PnvMachineState), \ - .instance_init = pnv_machine_instance_init, \ - .class_init = class_initfn, \ - .interfaces = (InterfaceInfo[]) { \ - { TYPE_XICS_FABRIC }, \ - { TYPE_INTERRUPT_STATS_PROVIDER }, \ - { }, \ - }, \ - } - static const TypeInfo types[] = { - DEFINE_PNV_MACHINE_TYPE("powernv8", pnv_machine_power8_class_init), - DEFINE_PNV_MACHINE_TYPE("powernv9", pnv_machine_power9_class_init), + { + .name = MACHINE_TYPE_NAME("powernv9"), + .parent = TYPE_PNV_MACHINE, + .class_init = pnv_machine_power9_class_init, + }, + { + .name = MACHINE_TYPE_NAME("powernv8"), + .parent = TYPE_PNV_MACHINE, + .class_init = pnv_machine_power8_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_XICS_FABRIC }, + { }, + }, + }, { .name = TYPE_PNV_MACHINE, .parent = TYPE_MACHINE, @@ -1510,7 +1508,6 @@ static const TypeInfo types[] = { .instance_init = pnv_machine_instance_init, .class_init = pnv_machine_class_init, .interfaces = (InterfaceInfo[]) { - { TYPE_XICS_FABRIC }, { TYPE_INTERRUPT_STATS_PROVIDER }, { }, },