mirror of https://gitee.com/openkylin/qemu.git
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 -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEdfRlhq5hpmzETofcbDjKyiDZs5IFAl2XEn0ACgkQbDjKyiDZ s5I6bA/7B5sjY/QxuE8axm5KupoAnE8zf205hN8mbYASwtDfFwgaeNreVaOSJUpr fgcx/g9G3rAryGZv3O6i02+wcRgNw1DnJ3ynCthIrExZEcfbTYJiS4s9apwPEQy8 HFmBNdPDqrhFI0aFvXEUauiOp1aapPUUklm34eFscs94lJXxphRUEfa3XT5uEhUh xrIZwYq20A+ih4UHwk3Onyx/cvFpl6BRB2nVEllQFqzwF5eTTfz9t8+JGTebxD/7 8qqt8ti0KM3wxSDTQnmyMUmpgy+C1iCvNYvv6nWFg+07QuGs48EHlQUUVVni4r9j kUrDwKS2eC+8e8gP/xdIXEq3R2DsAMq+wFIswXZ3X6x4DoUV0OAJSHc9iMD4l+pr LyWnVpDprc6XhJHWKpuHZ5w9EuBnZFbIXdlZGFno+8UvXtusnbbuwAZzHTrRJRqe /AWVpFwGAoOF4KxIOFlPVBI8m4vFad/soVojC0vzIbRqaogOFZAjiL/yD5GwLmMa tywOEMBUJ/j2lgudTCyKn5uCa/Ew3DS1TSdenJjyqRi/gZM0IaORIhJhyFYW/eO1 U7Uh8BnbC+4J11wwvFR5+W789dgM2+EEtAX9uI08VcE/R2ASabZlN4Zwrl0w4cb/ VRybMT4bgmjzHRpfrqYPxpn8wqPcIw0BCeipSOjY3QU1Q25TEYQ= =PXXe -----END PGP SIGNATURE----- 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>
This commit is contained in:
commit
0f0b43868a
|
@ -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
|
||||
|
|
2
Makefile
2
Makefile
|
@ -769,7 +769,7 @@ qemu-nsis.bmp \
|
|||
bamboo.dtb canyonlands.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \
|
||||
multiboot.bin linuxboot.bin linuxboot_dma.bin kvmvapic.bin pvh.bin \
|
||||
s390-ccw.img s390-netboot.img \
|
||||
spapr-rtas.bin slof.bin skiboot.lid \
|
||||
slof.bin skiboot.lid \
|
||||
palcode-clipper \
|
||||
u-boot.e500 u-boot-sam460-20100605.bin \
|
||||
qemu_vga.ndrv \
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
|
212
hw/intc/xics.c
212
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_base_realize(DeviceState *dev, Error **errp)
|
||||
static void ics_reset_handler(void *dev)
|
||||
{
|
||||
ICSState *ics = ICS_BASE(dev);
|
||||
Object *obj;
|
||||
Error *err = NULL;
|
||||
ics_reset(dev);
|
||||
}
|
||||
|
||||
obj = object_property_get_link(OBJECT(dev), ICS_PROP_XICS, &err);
|
||||
static void ics_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
ICSState *ics = ICS(dev);
|
||||
Error *local_err = NULL;
|
||||
Object *obj;
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1396,6 +1396,14 @@ static bool xive_presenter_match(XiveRouter *xrtr, uint8_t format,
|
|||
XiveTCTX *tctx = xive_router_get_tctx(xrtr, cs);
|
||||
int ring;
|
||||
|
||||
/*
|
||||
* Skip partially initialized vCPUs. This can happen when
|
||||
* vCPUs are hotplugged.
|
||||
*/
|
||||
if (!tctx) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* HW checks that the CPU is enabled in the Physical Thread
|
||||
* Enable Register (PTER).
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
118
hw/ppc/pnv.c
118
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 },
|
||||
{ },
|
||||
},
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
|
219
hw/ppc/spapr.c
219
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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static qemu_irq spapr_qirq_xics(SpaprMachineState *spapr, int irq)
|
||||
static void spapr_irq_free_xics(SpaprMachineState *spapr, int irq)
|
||||
{
|
||||
ICSState *ics = spapr->ics;
|
||||
uint32_t srcno = irq - ics->offset;
|
||||
|
||||
if (ics_valid_irq(ics, irq)) {
|
||||
return spapr->qirqs[srcno];
|
||||
}
|
||||
assert(ics_valid_irq(ics, irq));
|
||||
|
||||
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,
|
||||
};
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
BIN
pc-bios/slof.bin
BIN
pc-bios/slof.bin
Binary file not shown.
Binary file not shown.
|
@ -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 *~
|
|
@ -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
|
|
@ -1 +1 @@
|
|||
Subproject commit ea221600a116883137ef90b2b7ab7d2472bc4f10
|
||||
Subproject commit bcc3c4e5c21a015f4680894c4ec978a90d4a2d69
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue