diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2019-10-07 13:49:02 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2019-10-07 13:49:02 +0100 |
commit | 0f0b43868a566068fc137632fd51bd3cbb23f350 (patch) | |
tree | 8b992bb855eb2edd7215faebbd2f10ff00481741 | |
parent | 9e5319ca52a5b9e84d55ad9c36e2c0b317a122bb (diff) | |
parent | 1aba8716c8335e88b8c358002a6e1ac89f7dd258 (diff) |
Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-4.2-20191004' into staging
ppc patch queue 2019-10-04
Here's the next batch of ppc and spapr patches. Includes:
* Fist part of a large cleanup to irq infrastructure
* Recreate the full FDT at CAS time, instead of making a difficult
to follow set of updates. This will help us move towards
eliminating CAS reboots altogether
* No longer provide RTAS blob to SLOF - SLOF can include it just as
well itself, since guests will generally need to relocate it with
a call to instantiate-rtas
* A number of DFP fixes and cleanups from Mark Cave-Ayland
* Assorted bugfixes
* Several new small devices for powernv
# gpg: Signature made Fri 04 Oct 2019 10:35:57 BST
# gpg: using RSA key 75F46586AE61A66CC44E87DC6C38CACA20D9B392
# gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>" [full]
# gpg: aka "David Gibson (Red Hat) <dgibson@redhat.com>" [full]
# gpg: aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>" [full]
# gpg: aka "David Gibson (kernel.org) <dwg@kernel.org>" [unknown]
# Primary key fingerprint: 75F4 6586 AE61 A66C C44E 87DC 6C38 CACA 20D9 B392
* remotes/dgibson/tags/ppc-for-4.2-20191004: (53 commits)
ppc/pnv: Remove the XICSFabric Interface from the POWER9 machine
spapr: Eliminate SpaprIrq::init hook
spapr: Add return value to spapr_irq_check()
spapr: Use less cryptic representation of which irq backends are supported
xive: Improve irq claim/free path
spapr, xics, xive: Better use of assert()s on irq claim/free paths
spapr: Handle freeing of multiple irqs in frontend only
spapr: Remove unhelpful tracepoints from spapr_irq_free_xics()
spapr: Eliminate SpaprIrq:get_nodename method
spapr: Simplify spapr_qirq() handling
spapr: Fix indexing of XICS irqs
spapr: Eliminate nr_irqs parameter to SpaprIrq::init
spapr: Clarify and fix handling of nr_irqs
spapr: Replace spapr_vio_qirq() helper with spapr_vio_irq_pulse() helper
spapr: Fold spapr_phb_lsi_qirq() into its single caller
xics: Create sPAPR specific ICS subtype
xics: Merge TYPE_ICS_BASE and TYPE_ICS_SIMPLE classes
xics: Eliminate reset hook
xics: Rename misleading ics_simple_*() functions
xics: Eliminate 'reject', 'resend' and 'eoi' class hooks
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
54 files changed, 1420 insertions, 1092 deletions
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 @@ -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 \ @@ -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/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/intc/spapr_xive.c b/hw/intc/spapr_xive.c index c1c97192a7..04879abf2e 100644 --- a/hw/intc/spapr_xive.c +++ b/hw/intc/spapr_xive.c @@ -528,12 +528,15 @@ 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; - if (lisn >= xive->nr_irqs) { - return false; + assert(lisn < xive->nr_irqs); + + if (xive_eas_is_valid(&xive->eat[lisn])) { + error_setg(errp, "IRQ %d is not free", lisn); + return -EBUSY; } /* @@ -545,26 +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) { - 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/intc/spapr_xive_kvm.c b/hw/intc/spapr_xive_kvm.c index 17af4d19f5..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,17 +249,22 @@ 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) { + 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/trace-events b/hw/intc/trace-events index 719f46b516..527c3f76ca 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -66,12 +66,12 @@ 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_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_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" # 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..dfe7dbd254 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; @@ -452,11 +428,11 @@ static void ics_simple_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) { @@ -468,20 +444,20 @@ 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 { 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) +void ics_set_irq(void *opaque, int srcno, int val) { ICSState *ics = (ICSState *)opaque; @@ -491,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; @@ -510,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_simple_resend_lsi(ics, 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; @@ -524,21 +500,20 @@ 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); } } -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,100 +521,41 @@ 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; } } -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); - - isc->reject = ics_simple_reject; - isc->resend = ics_simple_resend; - isc->eoi = ics_simple_eoi; -} - -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); + ICSState *ics = ICS(dev); int i; uint8_t flags[ics->nr_irqs]; @@ -653,17 +569,31 @@ 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(dev), &local_err); + if (local_err) { + error_report_err(local_err); + } + } +} + +static void ics_reset_handler(void *dev) +{ + ics_reset(dev); } -static void ics_base_realize(DeviceState *dev, Error **errp) +static void ics_realize(DeviceState *dev, Error **errp) { - ICSState *ics = ICS_BASE(dev); + ICSState *ics = ICS(dev); + Error *local_err = NULL; 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; @@ -675,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; @@ -695,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; @@ -713,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, @@ -727,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->reset = ics_base_reset; - dc->vmsd = &vmstate_ics_base; + dc->realize = ics_realize; + dc->props = ics_properties; + dc->reset = ics_reset; + 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), }; @@ -805,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/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); diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c index 6577be0d92..6e5eb24b3c 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,15 +276,25 @@ 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); } -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); @@ -306,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")); @@ -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/intc/xive.c b/hw/intc/xive.c index b7417210d8..29df06df11 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -1397,6 +1397,14 @@ static bool xive_presenter_match(XiveRouter *xrtr, uint8_t format, 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). */ 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/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 3f08db7b9e..7cf64b6d25 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 : * * <EX0 reserved> * EX1 - Venice only @@ -847,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) @@ -923,8 +941,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); @@ -938,6 +958,20 @@ 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); + + /* 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) @@ -1020,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) @@ -1126,6 +1165,20 @@ 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); + + /* 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) @@ -1404,8 +1457,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; /* @@ -1432,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, @@ -1457,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 }, { }, }, 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); 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 <http://www.gnu.org/licenses/>. + */ + +#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/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/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c index 88ba8e7b9b..a997f16bb4 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) @@ -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[] = { @@ -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/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/hw/ppc/spapr.c b/hw/ppc/spapr.c index 08a2a5a770..514a17ae74 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 <libfdt.h> /* SLOF memory layout: @@ -94,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" @@ -218,8 +219,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 }; @@ -285,7 +285,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. */ @@ -295,65 +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, - spapr->cas_legacy_guest_workaround); - } - return ret; -} - static hwaddr spapr_node0_size(MachineState *machine) { if (machine->numa_state->num_nodes) { @@ -388,7 +329,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"))); @@ -551,7 +492,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))); @@ -984,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()) { @@ -1004,28 +947,11 @@ 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) { + g_free(fdt); trace_spapr_cas_failed(size); return -1; } @@ -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; } @@ -1136,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()) { @@ -1178,11 +1117,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), @@ -1717,8 +1661,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; @@ -1739,16 +1682,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(); /* @@ -1792,14 +1725,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 */ @@ -2847,13 +2776,57 @@ 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); } /* 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); + } + } + } + + } + + /* + * 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)) { @@ -2915,28 +2888,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); @@ -4321,6 +4272,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) diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 23e4bdb829..140f05c1c6 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 @@ -1785,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); @@ -1805,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 06fe2432ba..457eabe24c 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -92,44 +92,15 @@ static void spapr_irq_init_kvm(SpaprMachineState *spapr, * XICS IRQ backend. */ -static void spapr_irq_init_xics(SpaprMachineState *spapr, int nr_irqs, - Error **errp) -{ - Object *obj; - Error *local_err = NULL; - - obj = object_new(TYPE_ICS_SIMPLE); - object_property_add_child(OBJECT(spapr), "ics", obj, &error_abort); - object_property_add_const_link(obj, ICS_PROP_XICS, OBJECT(spapr), - &error_fatal); - object_property_set_int(obj, nr_irqs, "nr-irqs", &error_fatal); - object_property_set_bool(obj, true, "realized", &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - spapr->ics = ICS_BASE(obj); - - xics_spapr_init(spapr); -} - -#define ICS_IRQ_FREE(ics, srcno) \ - (!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK))) - static int spapr_irq_claim_xics(SpaprMachineState *spapr, int irq, bool lsi, Error **errp) { ICSState *ics = spapr->ics; assert(ics); + assert(ics_valid_irq(ics, irq)); - if (!ics_valid_irq(ics, irq)) { - error_setg(errp, "IRQ %d is invalid", irq); - return -1; - } - - if (!ICS_IRQ_FREE(ics, irq - ics->offset)) { + if (!ics_irq_free(ics, irq - ics->offset)) { error_setg(errp, "IRQ %d is not free", irq); return -1; } @@ -138,33 +109,14 @@ static int spapr_irq_claim_xics(SpaprMachineState *spapr, int irq, bool lsi, return 0; } -static void spapr_irq_free_xics(SpaprMachineState *spapr, int irq, int num) +static void spapr_irq_free_xics(SpaprMachineState *spapr, int irq) { ICSState *ics = spapr->ics; uint32_t srcno = irq - ics->offset; - int i; - if (ics_valid_irq(ics, irq)) { - trace_spapr_irq_free(0, irq, num); - for (i = srcno; i < srcno + num; ++i) { - if (ICS_IRQ_FREE(ics, i)) { - trace_spapr_irq_free_warn(0, i); - } - memset(&ics->irqs[i], 0, sizeof(ICSIRQState)); - } - } -} + assert(ics_valid_irq(ics, irq)); -static qemu_irq spapr_qirq_xics(SpaprMachineState *spapr, int irq) -{ - ICSState *ics = spapr->ics; - uint32_t srcno = irq - ics->offset; - - if (ics_valid_irq(ics, irq)) { - return spapr->qirqs[srcno]; - } - - return NULL; + memset(&ics->irqs[srcno], 0, sizeof(ICSIRQState)); } static void spapr_irq_print_info_xics(SpaprMachineState *spapr, Monitor *mon) @@ -209,11 +161,12 @@ static int spapr_irq_post_load_xics(SpaprMachineState *spapr, int version_id) return 0; } -static void spapr_irq_set_irq_xics(void *opaque, int srcno, int val) +static void spapr_irq_set_irq_xics(void *opaque, int irq, int val) { SpaprMachineState *spapr = opaque; + uint32_t srcno = irq - spapr->ics->offset; - ics_simple_set_irq(spapr->ics, srcno, val); + ics_set_irq(spapr->ics, srcno, val); } static void spapr_irq_reset_xics(SpaprMachineState *spapr, Error **errp) @@ -227,11 +180,6 @@ static void spapr_irq_reset_xics(SpaprMachineState *spapr, Error **errp) } } -static const char *spapr_irq_get_nodename_xics(SpaprMachineState *spapr) -{ - return XICS_NODENAME; -} - static void spapr_irq_init_kvm_xics(SpaprMachineState *spapr, Error **errp) { if (kvm_enabled()) { @@ -239,88 +187,36 @@ static void spapr_irq_init_kvm_xics(SpaprMachineState *spapr, Error **errp) } } -#define SPAPR_IRQ_XICS_NR_IRQS 0x1000 -#define SPAPR_IRQ_XICS_NR_MSIS \ - (XICS_IRQ_BASE + SPAPR_IRQ_XICS_NR_IRQS - SPAPR_IRQ_MSI) - SpaprIrq spapr_irq_xics = { - .nr_irqs = SPAPR_IRQ_XICS_NR_IRQS, - .nr_msis = SPAPR_IRQ_XICS_NR_MSIS, - .ov5 = SPAPR_OV5_XIVE_LEGACY, + .nr_xirqs = SPAPR_NR_XIRQS, + .nr_msis = SPAPR_NR_MSIS, + .xics = true, + .xive = false, - .init = spapr_irq_init_xics, .claim = spapr_irq_claim_xics, .free = spapr_irq_free_xics, - .qirq = spapr_qirq_xics, .print_info = spapr_irq_print_info_xics, .dt_populate = spapr_dt_xics, .cpu_intc_create = spapr_irq_cpu_intc_create_xics, .post_load = spapr_irq_post_load_xics, .reset = spapr_irq_reset_xics, .set_irq = spapr_irq_set_irq_xics, - .get_nodename = spapr_irq_get_nodename_xics, .init_kvm = spapr_irq_init_kvm_xics, }; /* * XIVE IRQ backend. */ -static void spapr_irq_init_xive(SpaprMachineState *spapr, int nr_irqs, - Error **errp) -{ - uint32_t nr_servers = spapr_max_server_number(spapr); - DeviceState *dev; - int i; - - dev = qdev_create(NULL, TYPE_SPAPR_XIVE); - qdev_prop_set_uint32(dev, "nr-irqs", nr_irqs); - /* - * 8 XIVE END structures per CPU. One for each available priority - */ - qdev_prop_set_uint32(dev, "nr-ends", nr_servers << 3); - qdev_init_nofail(dev); - - spapr->xive = SPAPR_XIVE(dev); - - /* Enable the CPU IPIs */ - for (i = 0; i < nr_servers; ++i) { - spapr_xive_irq_claim(spapr->xive, SPAPR_IRQ_IPI + i, false); - } - - spapr_xive_hcall_init(spapr); -} static int spapr_irq_claim_xive(SpaprMachineState *spapr, int irq, bool lsi, Error **errp) { - if (!spapr_xive_irq_claim(spapr->xive, irq, lsi)) { - error_setg(errp, "IRQ %d is invalid", irq); - return -1; - } - return 0; + return spapr_xive_irq_claim(spapr->xive, irq, lsi, errp); } -static void spapr_irq_free_xive(SpaprMachineState *spapr, int irq, int num) +static void spapr_irq_free_xive(SpaprMachineState *spapr, int irq) { - int i; - - for (i = irq; i < irq + num; ++i) { - spapr_xive_irq_free(spapr->xive, i); - } -} - -static qemu_irq spapr_qirq_xive(SpaprMachineState *spapr, int irq) -{ - SpaprXive *xive = spapr->xive; - - if (irq >= xive->nr_irqs) { - return NULL; - } - - /* The sPAPR machine/device should have claimed the IRQ before */ - assert(xive_eas_is_valid(&xive->eat[irq])); - - return spapr->qirqs[irq]; + spapr_xive_irq_free(spapr->xive, irq); } static void spapr_irq_print_info_xive(SpaprMachineState *spapr, @@ -386,22 +282,17 @@ static void spapr_irq_reset_xive(SpaprMachineState *spapr, Error **errp) spapr_xive_mmio_set_enabled(spapr->xive, true); } -static void spapr_irq_set_irq_xive(void *opaque, int srcno, int val) +static void spapr_irq_set_irq_xive(void *opaque, int irq, int val) { SpaprMachineState *spapr = opaque; if (kvm_irqchip_in_kernel()) { - kvmppc_xive_source_set_irq(&spapr->xive->source, srcno, val); + kvmppc_xive_source_set_irq(&spapr->xive->source, irq, val); } else { - xive_source_set_irq(&spapr->xive->source, srcno, val); + xive_source_set_irq(&spapr->xive->source, irq, val); } } -static const char *spapr_irq_get_nodename_xive(SpaprMachineState *spapr) -{ - return spapr->xive->nodename; -} - static void spapr_irq_init_kvm_xive(SpaprMachineState *spapr, Error **errp) { if (kvm_enabled()) { @@ -409,30 +300,20 @@ static void spapr_irq_init_kvm_xive(SpaprMachineState *spapr, Error **errp) } } -/* - * XIVE uses the full IRQ number space. Set it to 8K to be compatible - * with XICS. - */ - -#define SPAPR_IRQ_XIVE_NR_IRQS 0x2000 -#define SPAPR_IRQ_XIVE_NR_MSIS (SPAPR_IRQ_XIVE_NR_IRQS - SPAPR_IRQ_MSI) - SpaprIrq spapr_irq_xive = { - .nr_irqs = SPAPR_IRQ_XIVE_NR_IRQS, - .nr_msis = SPAPR_IRQ_XIVE_NR_MSIS, - .ov5 = SPAPR_OV5_XIVE_EXPLOIT, + .nr_xirqs = SPAPR_NR_XIRQS, + .nr_msis = SPAPR_NR_MSIS, + .xics = false, + .xive = true, - .init = spapr_irq_init_xive, .claim = spapr_irq_claim_xive, .free = spapr_irq_free_xive, - .qirq = spapr_qirq_xive, .print_info = spapr_irq_print_info_xive, .dt_populate = spapr_dt_xive, .cpu_intc_create = spapr_irq_cpu_intc_create_xive, .post_load = spapr_irq_post_load_xive, .reset = spapr_irq_reset_xive, .set_irq = spapr_irq_set_irq_xive, - .get_nodename = spapr_irq_get_nodename_xive, .init_kvm = spapr_irq_init_kvm_xive, }; @@ -455,24 +336,6 @@ static SpaprIrq *spapr_irq_current(SpaprMachineState *spapr) &spapr_irq_xive : &spapr_irq_xics; } -static void spapr_irq_init_dual(SpaprMachineState *spapr, int nr_irqs, - Error **errp) -{ - Error *local_err = NULL; - - spapr_irq_xics.init(spapr, spapr_irq_xics.nr_irqs, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - spapr_irq_xive.init(spapr, spapr_irq_xive.nr_irqs, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } -} - static int spapr_irq_claim_dual(SpaprMachineState *spapr, int irq, bool lsi, Error **errp) { @@ -494,15 +357,10 @@ static int spapr_irq_claim_dual(SpaprMachineState *spapr, int irq, bool lsi, return ret; } -static void spapr_irq_free_dual(SpaprMachineState *spapr, int irq, int num) +static void spapr_irq_free_dual(SpaprMachineState *spapr, int irq) { - spapr_irq_xics.free(spapr, irq, num); - spapr_irq_xive.free(spapr, irq, num); -} - -static qemu_irq spapr_qirq_dual(SpaprMachineState *spapr, int irq) -{ - return spapr_irq_current(spapr)->qirq(spapr, irq); + spapr_irq_xics.free(spapr, irq); + spapr_irq_xive.free(spapr, irq); } static void spapr_irq_print_info_dual(SpaprMachineState *spapr, Monitor *mon) @@ -576,45 +434,35 @@ static void spapr_irq_reset_dual(SpaprMachineState *spapr, Error **errp) spapr_irq_current(spapr)->reset(spapr, errp); } -static void spapr_irq_set_irq_dual(void *opaque, int srcno, int val) +static void spapr_irq_set_irq_dual(void *opaque, int irq, int val) { SpaprMachineState *spapr = opaque; - spapr_irq_current(spapr)->set_irq(spapr, srcno, val); -} - -static const char *spapr_irq_get_nodename_dual(SpaprMachineState *spapr) -{ - return spapr_irq_current(spapr)->get_nodename(spapr); + spapr_irq_current(spapr)->set_irq(spapr, irq, val); } /* * Define values in sync with the XIVE and XICS backend */ -#define SPAPR_IRQ_DUAL_NR_IRQS 0x2000 -#define SPAPR_IRQ_DUAL_NR_MSIS (SPAPR_IRQ_DUAL_NR_IRQS - SPAPR_IRQ_MSI) - SpaprIrq spapr_irq_dual = { - .nr_irqs = SPAPR_IRQ_DUAL_NR_IRQS, - .nr_msis = SPAPR_IRQ_DUAL_NR_MSIS, - .ov5 = SPAPR_OV5_XIVE_BOTH, + .nr_xirqs = SPAPR_NR_XIRQS, + .nr_msis = SPAPR_NR_MSIS, + .xics = true, + .xive = true, - .init = spapr_irq_init_dual, .claim = spapr_irq_claim_dual, .free = spapr_irq_free_dual, - .qirq = spapr_qirq_dual, .print_info = spapr_irq_print_info_dual, .dt_populate = spapr_irq_dt_populate_dual, .cpu_intc_create = spapr_irq_cpu_intc_create_dual, .post_load = spapr_irq_post_load_dual, .reset = spapr_irq_reset_dual, .set_irq = spapr_irq_set_irq_dual, - .get_nodename = spapr_irq_get_nodename_dual, .init_kvm = NULL, /* should not be used */ }; -static void spapr_irq_check(SpaprMachineState *spapr, Error **errp) +static int spapr_irq_check(SpaprMachineState *spapr, Error **errp) { MachineState *machine = MACHINE(spapr); @@ -630,7 +478,7 @@ static void spapr_irq_check(SpaprMachineState *spapr, Error **errp) */ if (spapr->irq == &spapr_irq_dual) { spapr->irq = &spapr_irq_xics; - return; + return 0; } /* @@ -650,7 +498,7 @@ static void spapr_irq_check(SpaprMachineState *spapr, Error **errp) */ if (spapr->irq == &spapr_irq_xive) { error_setg(errp, "XIVE-only machines require a POWER9 CPU"); - return; + return -1; } } @@ -664,8 +512,10 @@ static void spapr_irq_check(SpaprMachineState *spapr, Error **errp) machine_kernel_irqchip_required(machine) && xics_kvm_has_broken_disconnect(spapr)) { error_setg(errp, "KVM is too old to support ic-mode=dual,kernel-irqchip=on"); - return; + return -1; } + + return 0; } /* @@ -674,7 +524,6 @@ static void spapr_irq_check(SpaprMachineState *spapr, Error **errp) void spapr_irq_init(SpaprMachineState *spapr, Error **errp) { MachineState *machine = MACHINE(spapr); - Error *local_err = NULL; if (machine_kernel_irqchip_split(machine)) { error_setg(errp, "kernel_irqchip split mode not supported on pseries"); @@ -687,9 +536,7 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp) return; } - spapr_irq_check(spapr, &local_err); - if (local_err) { - error_propagate(errp, local_err); + if (spapr_irq_check(spapr, errp) < 0) { return; } @@ -698,25 +545,113 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp) spapr_irq_msi_init(spapr, spapr->irq->nr_msis); } - spapr->irq->init(spapr, spapr->irq->nr_irqs, errp); + if (spapr->irq->xics) { + Error *local_err = NULL; + Object *obj; + + obj = object_new(TYPE_ICS_SPAPR); + object_property_add_child(OBJECT(spapr), "ics", obj, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + object_property_add_const_link(obj, ICS_PROP_XICS, OBJECT(spapr), + &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + object_property_set_int(obj, spapr->irq->nr_xirqs, "nr-irqs", + &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + object_property_set_bool(obj, true, "realized", &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + spapr->ics = ICS_SPAPR(obj); + } + + if (spapr->irq->xive) { + uint32_t nr_servers = spapr_max_server_number(spapr); + DeviceState *dev; + int i; + + dev = qdev_create(NULL, TYPE_SPAPR_XIVE); + qdev_prop_set_uint32(dev, "nr-irqs", + spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE); + /* + * 8 XIVE END structures per CPU. One for each available + * priority + */ + qdev_prop_set_uint32(dev, "nr-ends", nr_servers << 3); + qdev_init_nofail(dev); + + spapr->xive = SPAPR_XIVE(dev); + + /* Enable the CPU IPIs */ + for (i = 0; i < nr_servers; ++i) { + if (spapr_xive_irq_claim(spapr->xive, SPAPR_IRQ_IPI + i, + false, errp) < 0) { + return; + } + } + + spapr_xive_hcall_init(spapr); + } spapr->qirqs = qemu_allocate_irqs(spapr->irq->set_irq, spapr, - spapr->irq->nr_irqs); + spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE); } int spapr_irq_claim(SpaprMachineState *spapr, int irq, bool lsi, Error **errp) { + assert(irq >= SPAPR_XIRQ_BASE); + assert(irq < (spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE)); + return spapr->irq->claim(spapr, irq, lsi, errp); } void spapr_irq_free(SpaprMachineState *spapr, int irq, int num) { - spapr->irq->free(spapr, irq, num); + int i; + + assert(irq >= SPAPR_XIRQ_BASE); + assert((irq + num) <= (spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE)); + + for (i = irq; i < (irq + num); i++) { + spapr->irq->free(spapr, i); + } } qemu_irq spapr_qirq(SpaprMachineState *spapr, int irq) { - return spapr->irq->qirq(spapr, irq); + /* + * This interface is basically for VIO and PHB devices to find the + * right qemu_irq to manipulate, so we only allow access to the + * external irqs for now. Currently anything which needs to + * access the IPIs most naturally gets there via the guest side + * interfaces, we can change this if we need to in future. + */ + assert(irq >= SPAPR_XIRQ_BASE); + assert(irq < (spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE)); + + if (spapr->ics) { + assert(ics_valid_irq(spapr->ics, irq)); + } + if (spapr->xive) { + assert(irq < spapr->xive->nr_irqs); + assert(xive_eas_is_valid(&spapr->xive->eat[irq])); + } + + return spapr->qirqs[irq]; } int spapr_irq_post_load(SpaprMachineState *spapr, int version_id) @@ -735,13 +670,13 @@ void spapr_irq_reset(SpaprMachineState *spapr, Error **errp) int spapr_irq_get_phandle(SpaprMachineState *spapr, void *fdt, Error **errp) { - const char *nodename = spapr->irq->get_nodename(spapr); + const char *nodename = "interrupt-controller"; int offset, phandle; offset = fdt_subnode_offset(fdt, 0, nodename); if (offset < 0) { - error_setg(errp, "Can't find node \"%s\": %s", nodename, - fdt_strerror(offset)); + error_setg(errp, "Can't find node \"%s\": %s", + nodename, fdt_strerror(offset)); return -1; } @@ -767,7 +702,7 @@ static int ics_find_free_block(ICSState *ics, int num, int alignnum) return -1; } for (i = first; i < first + num; ++i) { - if (!ICS_IRQ_FREE(ics, i)) { + if (!ics_irq_free(ics, i)) { break; } } @@ -809,23 +744,21 @@ int spapr_irq_find(SpaprMachineState *spapr, int num, bool align, Error **errp) return first + ics->offset; } -#define SPAPR_IRQ_XICS_LEGACY_NR_IRQS 0x400 +#define SPAPR_IRQ_XICS_LEGACY_NR_XIRQS 0x400 SpaprIrq spapr_irq_xics_legacy = { - .nr_irqs = SPAPR_IRQ_XICS_LEGACY_NR_IRQS, - .nr_msis = SPAPR_IRQ_XICS_LEGACY_NR_IRQS, - .ov5 = SPAPR_OV5_XIVE_LEGACY, + .nr_xirqs = SPAPR_IRQ_XICS_LEGACY_NR_XIRQS, + .nr_msis = SPAPR_IRQ_XICS_LEGACY_NR_XIRQS, + .xics = true, + .xive = false, - .init = spapr_irq_init_xics, .claim = spapr_irq_claim_xics, .free = spapr_irq_free_xics, - .qirq = spapr_qirq_xics, .print_info = spapr_irq_print_info_xics, .dt_populate = spapr_dt_xics, .cpu_intc_create = spapr_irq_cpu_intc_create_xics, .post_load = spapr_irq_post_load_xics, .reset = spapr_irq_reset_xics, .set_irq = spapr_irq_set_irq_xics, - .get_nodename = spapr_irq_get_nodename_xics, .init_kvm = spapr_irq_init_kvm_xics, }; diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 7b71ad7c74..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) @@ -835,7 +836,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 +850,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 +886,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 +900,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 +930,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 +1446,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)); 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/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: 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/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 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); diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h index fb123edc4e..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; @@ -198,6 +201,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 +269,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 */ 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 <http://www.gnu.org/licenses/>. + */ + +#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 */ 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; diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 03111fd55b..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; @@ -175,7 +173,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; diff --git a/include/hw/ppc/spapr_irq.h b/include/hw/ppc/spapr_irq.h index 5db305165c..69a37f608e 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,14 +37,13 @@ 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; + bool xics; + bool xive; - void (*init)(SpaprMachineState *spapr, int nr_irqs, 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 (*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); @@ -48,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/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, 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/xics.h b/include/hw/ppc/xics.h index f2a8d6a4b4..1e6a9300eb 100644 --- a/include/hw/ppc/xics.h +++ b/include/hw/ppc/xics.h @@ -89,27 +89,18 @@ 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; 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 { @@ -147,13 +138,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) \ @@ -175,9 +162,14 @@ 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) +{ + 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); diff --git a/include/hw/ppc/xics_spapr.h b/include/hw/ppc/xics_spapr.h index 5dabc9a138..0b35e85c26 100644 --- a/include/hw/ppc/xics_spapr.h +++ b/include/hw/ppc/xics_spapr.h @@ -29,13 +29,13 @@ #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) 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 */ 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); 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 Binary files differindex a3a3e49332..2af0c5d5fc 100644 --- a/pc-bios/slof.bin +++ b/pc-bios/slof.bin diff --git a/pc-bios/spapr-rtas.bin b/pc-bios/spapr-rtas.bin Binary files differdeleted file mode 100644 index fc24c8ed8b..0000000000 --- a/pc-bios/spapr-rtas.bin +++ /dev/null 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 diff --git a/roms/SLOF b/roms/SLOF -Subproject ea221600a116883137ef90b2b7ab7d2472bc4f1 +Subproject bcc3c4e5c21a015f4680894c4ec978a90d4a2d6 diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index eaee1a5575..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 */ @@ -559,6 +560,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 +596,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 +632,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 +671,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..2c65badae4 100644 --- a/target/ppc/dfp_helper.c +++ b/target/ppc/dfp_helper.c @@ -28,17 +28,32 @@ #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) +{ + dst->VsrD(1) = dfp->VsrD(0); +} + +static void get_dfp128(ppc_vsr_t *dst, ppc_fprp_t *dfp) +{ + dst->VsrD(0) = dfp[0].VsrD(0); + dst->VsrD(1) = dfp[1].VsrD(0); +} + +static void set_dfp64(ppc_fprp_t *dfp, ppc_vsr_t *src) +{ + dfp->VsrD(0) = src->VsrD(1); +} + +static void set_dfp128(ppc_fprp_t *dfp, ppc_vsr_t *src) +{ + 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; @@ -48,7 +63,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; @@ -121,56 +136,64 @@ 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); dfp->env = env; if (a) { - dfp->a64[0] = *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) { - dfp->b64[0] = *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); } } -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); dfp->env = env; if (a) { - dfp->a64[0] = a[HI_IDX]; - dfp->a64[1] = a[LO_IDX]; - 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) { - dfp->b64[0] = b[HI_IDX]; - dfp->b64[1] = b[LO_IDX]; - 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->vt.VsrD(1), &dfp->t, &dfp->context); +} + +static void dfp_finalize_decimal128(struct PPC_DFP *dfp) +{ + decimal128FromNumber((decimal128 *)&dfp->vt, &dfp->t, &dfp->context); +} + static void dfp_set_FPSCR_flag(struct PPC_DFP *dfp, uint64_t flag, uint64_t enabled) { @@ -220,8 +243,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 +392,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) @@ -396,19 +419,15 @@ 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); \ 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) { \ - t[0] = dfp.t64[0]; \ - } else if (size == 128) { \ - t[0] = dfp.t64[HI_IDX]; \ - t[1] = dfp.t64[LO_IDX]; \ - } \ + set_dfp##size(t, &dfp.vt); \ } static void ADD_PPs(struct PPC_DFP *dfp) @@ -466,12 +485,12 @@ 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); \ 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; \ } @@ -498,7 +517,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; \ @@ -526,7 +545,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, \ @@ -581,7 +600,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; \ @@ -613,14 +632,16 @@ 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; \ + ppc_vsr_t va; \ \ dfp_prepare_decimal##size(&dfp, 0, b, env); \ \ - k = *a & 0x3F; \ + get_dfp64(&va, a); \ + k = va.VsrD(1) & 0x3F; \ \ if (unlikely(decNumberIsSpecial(&dfp.b))) { \ dfp.crbf = 1; \ @@ -648,7 +669,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; \ @@ -708,7 +729,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; \ @@ -719,40 +740,28 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_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) { \ - t[0] = dfp.t64[0]; \ - } else if (size == 128) { \ - t[0] = dfp.t64[HI_IDX]; \ - t[1] = dfp.t64[LO_IDX]; \ - } \ + set_dfp##size(t, &dfp.vt); \ } 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; \ \ 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) { \ - t[0] = dfp.t64[0]; \ - } else if (size == 128) { \ - t[0] = dfp.t64[HI_IDX]; \ - t[1] = dfp.t64[LO_IDX]; \ - } \ + set_dfp##size(t, &dfp.vt); \ } DFP_HELPER_QUA(dqua, 64) @@ -813,33 +822,31 @@ 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; \ - int32_t ref_sig = *a & 0x3F; \ + 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(&va, a); \ + ref_sig = va.VsrD(1) & 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) { \ - t[0] = dfp.t64[0]; \ - } else if (size == 128) { \ - t[0] = dfp.t64[HI_IDX]; \ - t[1] = dfp.t64[LO_IDX]; \ - } \ + set_dfp##size(t, &dfp.vt); \ } 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; \ @@ -848,15 +855,10 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_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) { \ - t[0] = dfp.t64[0]; \ - } else if (size == 128) { \ - t[0] = dfp.t64[HI_IDX]; \ - t[1] = dfp.t64[LO_IDX]; \ - } \ + set_dfp##size(t, &dfp.vt); \ } static void RINTX_PPs(struct PPC_DFP *dfp) @@ -878,34 +880,42 @@ 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; - uint32_t b_short = *b; + ppc_vsr_t vb; + uint32_t b_short; + + get_dfp64(&vb, b); + b_short = (uint32_t)vb.VsrD(1); + dfp_prepare_decimal64(&dfp, 0, 0, env); decimal32ToNumber((decimal32 *)&b_short, &dfp.t); - decimal64FromNumber((decimal64 *)t, &dfp.t, &dfp.context); + dfp_finalize_decimal64(&dfp); + set_dfp64(t, &dfp.vt); 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; + ppc_vsr_t vb; dfp_prepare_decimal128(&dfp, 0, 0, env); - decimal64ToNumber((decimal64 *)b, &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); - decimal128FromNumber((decimal128 *)&dfp.t64, &dfp.t, &dfp.context); - t[0] = dfp.t64[HI_IDX]; - t[1] = dfp.t64[LO_IDX]; + dfp_finalize_decimal128(&dfp); + set_dfp128(t, &dfp.vt); } -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; + 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); @@ -915,15 +925,16 @@ void helper_drsp(CPUPPCState *env, uint64_t *t, uint64_t *b) dfp_check_for_UX(&dfp); dfp_check_for_XX(&dfp); - *t = t_short; + vt.VsrD(1) = (uint64_t)t_short; + set_dfp64(t, &vt); } -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); - 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); @@ -931,26 +942,23 @@ void helper_drdpq(CPUPPCState *env, uint64_t *t, uint64_t *b) dfp_check_for_UX(&dfp); dfp_check_for_XX(&dfp); - decimal64FromNumber((decimal64 *)dfp.t64, &dfp.t, &dfp.context); - t[0] = dfp.t64[0]; - t[1] = 0; + dfp.vt.VsrD(0) = dfp.vt.VsrD(1) = 0; + dfp_finalize_decimal64(&dfp); + set_dfp128(t, &dfp.vt); } #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; \ + ppc_vsr_t vb; \ dfp_prepare_decimal##size(&dfp, 0, b, env); \ - decNumberFromInt64(&dfp.t, (int64_t)(*b)); \ - decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, &dfp.context); \ + get_dfp64(&vb, b); \ + decNumberFromInt64(&dfp.t, (int64_t)vb.VsrD(1)); \ + dfp_finalize_decimal##size(&dfp); \ CFFIX_PPs(&dfp); \ \ - if (size == 64) { \ - t[0] = dfp.t64[0]; \ - } else if (size == 128) { \ - t[0] = dfp.t64[HI_IDX]; \ - t[1] = dfp.t64[LO_IDX]; \ - } \ + set_dfp##size(t, &dfp.vt); \ } static void CFFIX_PPs(struct PPC_DFP *dfp) @@ -963,7 +971,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); \ @@ -971,62 +979,65 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_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); \ } \ } \ \ - *t = dfp.t64[0]; \ + set_dfp64(t, &dfp.vt); \ } 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) \ -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]; \ @@ -1035,11 +1046,11 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t sp) \ 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, digits[N - i - 1], i); \ } \ \ if (sp & 2) { \ @@ -1050,32 +1061,28 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t sp) \ } else { \ sgn = ((sp & 1) ? 0xF : 0xC); \ } \ - dfp_set_sign_##size(dfp.t64, sgn); \ + dfp_set_sign_##size(&dfp.vt, sgn); \ } \ \ - if (size == 64) { \ - t[0] = dfp.t64[0]; \ - } else if (size == 128) { \ - t[0] = dfp.t64[HI_IDX]; \ - t[1] = dfp.t64[LO_IDX]; \ - } \ + set_dfp##size(t, &dfp.vt); \ } 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) \ -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]; \ @@ -1086,7 +1093,7 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t s) \ 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, offset++); \ switch (sgnNibble) { \ case 0xD: \ case 0xB: \ @@ -1106,7 +1113,8 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t s) \ \ 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, \ + offset++); \ if (digits[(size) / 4 - n] > 10) { \ dfp_set_FPSCR_flag(&dfp, FP_VX | FP_VXCVI, FPSCR_VE); \ return; \ @@ -1122,71 +1130,72 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t s) \ 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) { \ - t[0] = dfp.t64[0]; \ - } else if ((size) == 128) { \ - t[0] = dfp.t64[HI_IDX]; \ - t[1] = dfp.t64[LO_IDX]; \ - } \ + set_dfp##size(t, &dfp.vt); \ } 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; \ + ppc_vsr_t vt; \ \ dfp_prepare_decimal##size(&dfp, 0, b, env); \ \ if (unlikely(decNumberIsSpecial(&dfp.b))) { \ if (decNumberIsInfinite(&dfp.b)) { \ - *t = -1; \ + vt.VsrD(1) = -1; \ } else if (decNumberIsSNaN(&dfp.b)) { \ - *t = -3; \ + vt.VsrD(1) = -3; \ } else if (decNumberIsQNaN(&dfp.b)) { \ - *t = -2; \ + vt.VsrD(1) = -2; \ } else { \ assert(0); \ } \ + set_dfp64(t, &vt); \ } else { \ if ((size) == 64) { \ - *t = dfp.b.exponent + 398; \ + vt.VsrD(1) = dfp.b.exponent + 398; \ } else if ((size) == 128) { \ - *t = dfp.b.exponent + 6176; \ + vt.VsrD(1) = dfp.b.exponent + 6176; \ } else { \ assert(0); \ } \ + set_dfp64(t, &vt); \ } \ } 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) \ -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; \ + ppc_vsr_t va; \ int bias; \ - int64_t exp = *((int64_t *)a); \ + int64_t exp; \ \ + get_dfp64(&va, a); \ + exp = (int64_t)va.VsrD(1); \ dfp_prepare_decimal##size(&dfp, 0, b, env); \ \ if ((size) == 64) { \ @@ -1206,14 +1215,14 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, uint64_t *b) \ } \ \ 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, raw_inf); \ } else if (exp == -3) { \ - dfp_set_raw_exp_##size(dfp.t64, raw_snan); \ + dfp_set_raw_exp_##size(&dfp.vt, raw_snan); \ } else { \ - dfp_set_raw_exp_##size(dfp.t64, raw_qnan); \ + dfp_set_raw_exp_##size(&dfp.vt, raw_qnan); \ } \ } else { \ dfp.t = dfp.b; \ @@ -1221,15 +1230,9 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, uint64_t *b) \ dfp.t.bits &= ~DECSPECIAL; \ } \ dfp.t.exponent = exp - bias; \ - decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \ - &dfp.context); \ - } \ - if (size == 64) { \ - t[0] = dfp.t64[0]; \ - } else if (size == 128) { \ - t[0] = dfp.t64[HI_IDX]; \ - t[1] = dfp.t64[LO_IDX]; \ + dfp_finalize_decimal##size(&dfp); \ } \ + set_dfp##size(t, &dfp.vt); \ } DFP_HELPER_IEX(diex, 64) @@ -1276,7 +1279,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; \ @@ -1303,26 +1306,21 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_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; \ - 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) { \ - t[0] = dfp.t64[0]; \ - } else { \ - t[0] = dfp.t64[HI_IDX]; \ - t[1] = dfp.t64[LO_IDX]; \ - } \ + set_dfp##size(t, &dfp.vt); \ } DFP_HELPER_SHIFT(dscli, 64, 1) 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; } 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) 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) { 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/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/fp-impl.inc.c b/target/ppc/translate/fp-impl.inc.c index 7cd9d8db05..d8e27bf4d5 100644 --- a/target/ppc/translate/fp-impl.inc.c +++ b/target/ppc/translate/fp-impl.inc.c @@ -634,11 +634,108 @@ 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); } +/* 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(); + 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..88fab65628 100644 --- a/target/ppc/translate/fp-ops.inc.c +++ b/target/ppc/translate/fp-ops.inc.c @@ -105,8 +105,14 @@ 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, + 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), 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 } |