ppc patch queue 2018-08-29

Another pull request for ppc-for-4.2.  Includes
 
   * Several powernv patches which were pulled last minute from the
     last PULL, now that some problems with them have been sorted out
   * A fix for -no-reboot which has been broken since the
     pseries-rhel4.1.0 machine type
   * Add some host threads information which AIX guests will need to
     properly scale the PURR and SPURR
   * Change behaviour to match x86 when unplugging function 0 of a
     multifunction PCI device
   * A number of TCG fixes in FPU emulation
 
 And a handful of other assorted fixes and cleanups.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEdfRlhq5hpmzETofcbDjKyiDZs5IFAl1nZFcACgkQbDjKyiDZ
 s5L8fBAA1QbR+f52mp8+v4rHm33nr7mLmOw1Dx4+fyFaEi1nwyacvg20APt8bPPC
 l3j33NpLCsSVjqHM4zzOfR49mwfsqrhfbdVPCP46Dx7R0jPJaukfuxqxrs90A9Xn
 F34pMIVS6AWJerj9+6IA4pfYDIlFfOEA0Fq02hg8qtnw4CRqDoCI97JHNyQjXqWI
 fBq7ZmBqOmdawNpeMCfus/pNA32FVC4BVznpeGQlpKO7aKOU8vp6JPbb2HYftoCm
 8/DLrLiF06PLqdtKYpErwZ+ZXNFmT25rRf6JVhjnVHhtRr5y3oTG/7Y+LM5Cydbj
 fQ8iQYQew8CxZ7Z3WsdsId3ovw7WM8vpf6dlyI7KTqVQEf108WISHPd68iWrzu10
 rw9g/wdCrPbZrFzsVWUff9tJevW1vjDAa8q8iwb2BORpjZykqWWzPMBKHxc/Uso8
 tZHMQIIbZ6UNESJj60yVJ44tXcVzxNSDXyjflN33PLjj8STHUKrZrOl2c4gjPGJy
 xskfiAwNWtZcnnHhUqbPnusJ99HJGhduyve6FvJQgTzSepqcrXmFFjq0+zfZG86i
 qw6LC70qU56ZpAjySZGw6oMU1cK6weJ6OR9pZvUbt8QQ0LTDoF5U8BePf3nGDOPh
 uR7+FtiraNo260P2UpLSzKq1sbRy+4SoLiePWBCxJC+Dr9NIVW4=
 =sJgq
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-4.2-20190829' into staging

ppc patch queue 2018-08-29

Another pull request for ppc-for-4.2.  Includes

  * Several powernv patches which were pulled last minute from the
    last PULL, now that some problems with them have been sorted out
  * A fix for -no-reboot which has been broken since the
    pseries-rhel4.1.0 machine type
  * Add some host threads information which AIX guests will need to
    properly scale the PURR and SPURR
  * Change behaviour to match x86 when unplugging function 0 of a
    multifunction PCI device
  * A number of TCG fixes in FPU emulation

And a handful of other assorted fixes and cleanups.

# gpg: Signature made Thu 29 Aug 2019 06:36:23 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-20190829:
  spapr: Set compat mode in spapr_core_plug()
  spapr/pci: Convert types to QEMU coding style
  spapr_pci: Advertise BAR reallocation capability
  spapr: Use SHUTDOWN_CAUSE_SUBSYSTEM_RESET for CAS reboots
  powerpc/spapr: Add host threads parameter to ibm,get_system_parameter
  pseries: Update SLOF firmware image
  target/ppc: Refactor emulation of vmrgew and vmrgow instructions
  target/ppc: Fix do_float_check_status vs inexact
  target/ppc: Set float_tininess_before_rounding at cpu reset
  pseries: Fix compat_pvr on reset
  spapr_pci: remove all child functions in function zero unplug
  ppc: Fix xscvdpspn for SNAN
  ppc: Fix xsmaddmdp and friends
  tests/boot-serial-test: add support for all the PowerNV machines
  ppc/pnv: Introduce PowerNV machines with fixed CPU models
  ppc/pnv: Generate phandle for the "interrupt-parent" property
  ppc/pnv: add more dummy XSCOM addresses for the P9 CAPP
  ppc/pnv: update skiboot to v6.4
  ppc/pnv: Set default ram size to 1.75GB

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2019-09-03 17:20:39 +01:00
commit 3b3f0646a4
22 changed files with 289 additions and 110 deletions

View File

@ -434,9 +434,14 @@ static void pnv_dt_isa(PnvMachineState *pnv, void *fdt)
.fdt = fdt, .fdt = fdt,
.offset = isa_offset, .offset = isa_offset,
}; };
uint32_t phandle;
_FDT((fdt_setprop(fdt, isa_offset, "primary", NULL, 0))); _FDT((fdt_setprop(fdt, isa_offset, "primary", NULL, 0)));
phandle = qemu_fdt_alloc_phandle(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 /* ISA devices are not necessarily parented to the ISA bus so we
* can not use object_child_foreach() */ * can not use object_child_foreach() */
qbus_walk_children(BUS(pnv->isa_bus), pnv_dt_isa_device, NULL, NULL, NULL, qbus_walk_children(BUS(pnv->isa_bus), pnv_dt_isa_device, NULL, NULL, NULL,
@ -600,9 +605,20 @@ static void pnv_chip_power9_pic_print_info(PnvChip *chip, Monitor *mon)
pnv_psi_pic_print_info(&chip9->psi, mon); pnv_psi_pic_print_info(&chip9->psi, mon);
} }
static bool pnv_match_cpu(const char *default_type, const char *cpu_type)
{
PowerPCCPUClass *ppc_default =
POWERPC_CPU_CLASS(object_class_by_name(default_type));
PowerPCCPUClass *ppc =
POWERPC_CPU_CLASS(object_class_by_name(cpu_type));
return ppc_default->pvr_match(ppc_default, ppc->pvr);
}
static void pnv_init(MachineState *machine) static void pnv_init(MachineState *machine)
{ {
PnvMachineState *pnv = PNV_MACHINE(machine); PnvMachineState *pnv = PNV_MACHINE(machine);
MachineClass *mc = MACHINE_GET_CLASS(machine);
MemoryRegion *ram; MemoryRegion *ram;
char *fw_filename; char *fw_filename;
long fw_size; long fw_size;
@ -662,13 +678,23 @@ static void pnv_init(MachineState *machine)
} }
} }
/*
* Check compatibility of the specified CPU with the machine
* default.
*/
if (!pnv_match_cpu(mc->default_cpu_type, machine->cpu_type)) {
error_report("invalid CPU model '%s' for %s machine",
machine->cpu_type, mc->name);
exit(1);
}
/* Create the processor chips */ /* Create the processor chips */
i = strlen(machine->cpu_type) - strlen(POWERPC_CPU_TYPE_SUFFIX); i = strlen(machine->cpu_type) - strlen(POWERPC_CPU_TYPE_SUFFIX);
chip_typename = g_strdup_printf(PNV_CHIP_TYPE_NAME("%.*s"), chip_typename = g_strdup_printf(PNV_CHIP_TYPE_NAME("%.*s"),
i, machine->cpu_type); i, machine->cpu_type);
if (!object_class_by_name(chip_typename)) { if (!object_class_by_name(chip_typename)) {
error_report("invalid CPU model '%.*s' for %s machine", error_report("invalid chip model '%.*s' for %s machine",
i, machine->cpu_type, MACHINE_GET_CLASS(machine)->name); i, machine->cpu_type, mc->name);
exit(1); exit(1);
} }
@ -1346,25 +1372,47 @@ static void pnv_machine_class_props_init(ObjectClass *oc)
NULL); NULL);
} }
static void pnv_machine_class_init(ObjectClass *oc, void *data) static void pnv_machine_power8_class_init(ObjectClass *oc, void *data)
{ {
MachineClass *mc = MACHINE_CLASS(oc); MachineClass *mc = MACHINE_CLASS(oc);
XICSFabricClass *xic = XICS_FABRIC_CLASS(oc); XICSFabricClass *xic = XICS_FABRIC_CLASS(oc);
mc->desc = "IBM PowerNV (Non-Virtualized) POWER8";
mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0");
xic->icp_get = pnv_icp_get;
xic->ics_get = pnv_ics_get;
xic->ics_resend = pnv_ics_resend;
}
static void pnv_machine_power9_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
mc->desc = "IBM PowerNV (Non-Virtualized) POWER9";
mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power9_v2.0");
mc->alias = "powernv";
}
static void pnv_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc); InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc);
mc->desc = "IBM PowerNV (Non-Virtualized)"; mc->desc = "IBM PowerNV (Non-Virtualized)";
mc->init = pnv_init; mc->init = pnv_init;
mc->reset = pnv_reset; mc->reset = pnv_reset;
mc->max_cpus = MAX_CPUS; mc->max_cpus = MAX_CPUS;
mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0");
mc->block_default_type = IF_IDE; /* Pnv provides a AHCI device for mc->block_default_type = IF_IDE; /* Pnv provides a AHCI device for
* storage */ * storage */
mc->no_parallel = 1; mc->no_parallel = 1;
mc->default_boot_order = NULL; mc->default_boot_order = NULL;
mc->default_ram_size = 1 * GiB; /*
xic->icp_get = pnv_icp_get; * RAM defaults to less than 2048 for 32-bit hosts, and large
xic->ics_get = pnv_ics_get; * enough to fit the maximum initrd size at it's load address
xic->ics_resend = pnv_ics_resend; */
mc->default_ram_size = INITRD_LOAD_ADDR + INITRD_MAX_SIZE;
ispc->print_info = pnv_pic_print_info; ispc->print_info = pnv_pic_print_info;
pnv_machine_class_props_init(oc); pnv_machine_class_props_init(oc);
@ -1384,10 +1432,27 @@ static void pnv_machine_class_init(ObjectClass *oc, void *data)
.parent = TYPE_PNV9_CHIP, \ .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[] = { 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 = TYPE_PNV_MACHINE, .name = TYPE_PNV_MACHINE,
.parent = TYPE_MACHINE, .parent = TYPE_MACHINE,
.abstract = true,
.instance_size = sizeof(PnvMachineState), .instance_size = sizeof(PnvMachineState),
.instance_init = pnv_machine_instance_init, .instance_init = pnv_machine_instance_init,
.class_init = pnv_machine_class_init, .class_init = pnv_machine_class_init,

View File

@ -106,6 +106,16 @@ static uint64_t xscom_read_default(PnvChip *chip, uint32_t pcba)
case 0x201302a: /* CAPP stuff */ case 0x201302a: /* CAPP stuff */
case 0x2013801: /* CAPP stuff */ case 0x2013801: /* CAPP stuff */
case 0x2013802: /* CAPP stuff */ case 0x2013802: /* CAPP stuff */
/* P9 CAPP regs */
case 0x2010841:
case 0x2010842:
case 0x201082a:
case 0x2010828:
case 0x4010841:
case 0x4010842:
case 0x401082a:
case 0x4010828:
return 0; return 0;
default: default:
return -1; return -1;
@ -138,6 +148,16 @@ static bool xscom_write_default(PnvChip *chip, uint32_t pcba, uint64_t val)
case 0x2013801: /* CAPP stuff */ case 0x2013801: /* CAPP stuff */
case 0x2013802: /* CAPP stuff */ case 0x2013802: /* CAPP stuff */
/* P9 CAPP regs */
case 0x2010841:
case 0x2010842:
case 0x201082a:
case 0x2010828:
case 0x4010841:
case 0x4010842:
case 0x401082a:
case 0x4010828:
/* P8 PRD registers */ /* P8 PRD registers */
case PRD_P8_IPOLL_REG_MASK: case PRD_P8_IPOLL_REG_MASK:
case PRD_P8_IPOLL_REG_STATUS: case PRD_P8_IPOLL_REG_STATUS:

View File

@ -1168,6 +1168,7 @@ static void spapr_dt_ov5_platform_support(SpaprMachineState *spapr, void *fdt,
static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt) static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt)
{ {
MachineState *machine = MACHINE(spapr); MachineState *machine = MACHINE(spapr);
SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
int chosen; int chosen;
const char *boot_device = machine->boot_order; const char *boot_device = machine->boot_order;
char *stdout_path = spapr_vio_stdout_path(spapr->vio_bus); char *stdout_path = spapr_vio_stdout_path(spapr->vio_bus);
@ -1225,6 +1226,11 @@ static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt)
_FDT(fdt_setprop_string(fdt, chosen, "stdout-path", stdout_path)); _FDT(fdt_setprop_string(fdt, chosen, "stdout-path", stdout_path));
} }
/* We can deal with BAR reallocation just fine, advertise it to the guest */
if (smc->linux_pci_probe) {
_FDT(fdt_setprop_cell(fdt, chosen, "linux,pci-probe-only", 0));
}
spapr_dt_ov5_platform_support(spapr, fdt, chosen); spapr_dt_ov5_platform_support(spapr, fdt, chosen);
g_free(stdout_path); g_free(stdout_path);
@ -1752,7 +1758,7 @@ static void spapr_machine_reset(MachineState *machine)
spapr_ovec_cleanup(spapr->ov5_cas); spapr_ovec_cleanup(spapr->ov5_cas);
spapr->ov5_cas = spapr_ovec_new(); spapr->ov5_cas = spapr_ovec_new();
ppc_set_compat(first_ppc_cpu, spapr->max_compat_pvr, &error_fatal); ppc_set_compat_all(spapr->max_compat_pvr, &error_fatal);
} }
/* /*
@ -3829,6 +3835,7 @@ static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
CPUArchId *core_slot; CPUArchId *core_slot;
int index; int index;
bool hotplugged = spapr_drc_hotplugged(dev); bool hotplugged = spapr_drc_hotplugged(dev);
int i;
core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index); core_slot = spapr_find_cpu_slot(MACHINE(hotplug_dev), cc->core_id, &index);
if (!core_slot) { if (!core_slot) {
@ -3862,13 +3869,26 @@ static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
core_slot->cpu = OBJECT(dev); core_slot->cpu = OBJECT(dev);
if (smc->pre_2_10_has_unused_icps) { if (smc->pre_2_10_has_unused_icps) {
int i;
for (i = 0; i < cc->nr_threads; i++) { for (i = 0; i < cc->nr_threads; i++) {
cs = CPU(core->threads[i]); cs = CPU(core->threads[i]);
pre_2_10_vmstate_unregister_dummy_icp(cs->cpu_index); pre_2_10_vmstate_unregister_dummy_icp(cs->cpu_index);
} }
} }
/*
* Set compatibility mode to match the boot CPU, which was either set
* by the machine reset code or by CAS.
*/
if (hotplugged) {
for (i = 0; i < cc->nr_threads; i++) {
ppc_set_compat(core->threads[i], POWERPC_CPU(first_cpu)->compat_pvr,
&local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
}
}
} }
static void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, static void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
@ -4470,6 +4490,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
spapr_caps_add_properties(smc, &error_abort); spapr_caps_add_properties(smc, &error_abort);
smc->irq = &spapr_irq_dual; smc->irq = &spapr_irq_dual;
smc->dr_phb_enabled = true; smc->dr_phb_enabled = true;
smc->linux_pci_probe = true;
} }
static const TypeInfo spapr_machine_info = { static const TypeInfo spapr_machine_info = {
@ -4529,12 +4550,14 @@ DEFINE_SPAPR_MACHINE(4_2, "4.2", true);
*/ */
static void spapr_machine_4_1_class_options(MachineClass *mc) static void spapr_machine_4_1_class_options(MachineClass *mc)
{ {
SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
static GlobalProperty compat[] = { static GlobalProperty compat[] = {
/* Only allow 4kiB and 64kiB IOMMU pagesizes */ /* Only allow 4kiB and 64kiB IOMMU pagesizes */
{ TYPE_SPAPR_PCI_HOST_BRIDGE, "pgsz", "0x11000" }, { TYPE_SPAPR_PCI_HOST_BRIDGE, "pgsz", "0x11000" },
}; };
spapr_machine_4_2_class_options(mc); spapr_machine_4_2_class_options(mc);
smc->linux_pci_probe = false;
compat_props_add(mc->compat_props, hw_compat_4_1, hw_compat_4_1_len); compat_props_add(mc->compat_props, hw_compat_4_1, hw_compat_4_1_len);
compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat)); compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
} }

View File

@ -41,11 +41,6 @@ static void spapr_cpu_reset(void *opaque)
* using an RTAS call */ * using an RTAS call */
cs->halted = 1; cs->halted = 1;
/* Set compatibility mode to match the boot CPU, which was either set
* by the machine reset code or by CAS. This should never fail.
*/
ppc_set_compat(cpu, POWERPC_CPU(first_cpu)->compat_pvr, &error_abort);
env->spr[SPR_HIOR] = 0; env->spr[SPR_HIOR] = 0;
lpcr = env->spr[SPR_LPCR]; lpcr = env->spr[SPR_LPCR];

View File

@ -1811,7 +1811,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
spapr_ovec_cleanup(ov5_updates); spapr_ovec_cleanup(ov5_updates);
if (spapr->cas_reboot) { if (spapr->cas_reboot) {
qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); qemu_system_reset_request(SHUTDOWN_CAUSE_SUBSYSTEM_RESET);
} }
return H_SUCCESS; return H_SUCCESS;

View File

@ -280,7 +280,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, SpaprMachineState *spapr,
unsigned int irq, max_irqs = 0; unsigned int irq, max_irqs = 0;
SpaprPhbState *phb = NULL; SpaprPhbState *phb = NULL;
PCIDevice *pdev = NULL; PCIDevice *pdev = NULL;
spapr_pci_msi *msi; SpaprPciMsi *msi;
int *config_addr_key; int *config_addr_key;
Error *err = NULL; Error *err = NULL;
int i; int i;
@ -328,7 +328,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, SpaprMachineState *spapr,
return; return;
} }
msi = (spapr_pci_msi *) g_hash_table_lookup(phb->msi, &config_addr); msi = (SpaprPciMsi *) g_hash_table_lookup(phb->msi, &config_addr);
/* Releasing MSIs */ /* Releasing MSIs */
if (!req_num) { if (!req_num) {
@ -415,7 +415,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, SpaprMachineState *spapr,
irq, req_num); irq, req_num);
/* Add MSI device to cache */ /* Add MSI device to cache */
msi = g_new(spapr_pci_msi, 1); msi = g_new(SpaprPciMsi, 1);
msi->first_irq = irq; msi->first_irq = irq;
msi->num = req_num; msi->num = req_num;
config_addr_key = g_new(int, 1); config_addr_key = g_new(int, 1);
@ -446,7 +446,7 @@ static void rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu,
unsigned int intr_src_num = -1, ioa_intr_num = rtas_ld(args, 3); unsigned int intr_src_num = -1, ioa_intr_num = rtas_ld(args, 3);
SpaprPhbState *phb = NULL; SpaprPhbState *phb = NULL;
PCIDevice *pdev = NULL; PCIDevice *pdev = NULL;
spapr_pci_msi *msi; SpaprPciMsi *msi;
/* Find SpaprPhbState */ /* Find SpaprPhbState */
phb = spapr_pci_find_phb(spapr, buid); phb = spapr_pci_find_phb(spapr, buid);
@ -459,7 +459,7 @@ static void rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu,
} }
/* Find device descriptor and start IRQ */ /* Find device descriptor and start IRQ */
msi = (spapr_pci_msi *) g_hash_table_lookup(phb->msi, &config_addr); msi = (SpaprPciMsi *) g_hash_table_lookup(phb->msi, &config_addr);
if (!msi || !msi->first_irq || !msi->num || (ioa_intr_num >= msi->num)) { if (!msi || !msi->first_irq || !msi->num || (ioa_intr_num >= msi->num)) {
trace_spapr_pci_msi("Failed to return vector", config_addr); trace_spapr_pci_msi("Failed to return vector", config_addr);
rtas_st(rets, 0, RTAS_OUT_HW_ERROR); rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
@ -1700,11 +1700,13 @@ static void spapr_pci_unplug_request(HotplugHandler *plug_handler,
state = func_drck->dr_entity_sense(func_drc); state = func_drck->dr_entity_sense(func_drc);
if (state == SPAPR_DR_ENTITY_SENSE_PRESENT if (state == SPAPR_DR_ENTITY_SENSE_PRESENT
&& !spapr_drc_unplug_requested(func_drc)) { && !spapr_drc_unplug_requested(func_drc)) {
error_setg(errp, /*
"PCI: slot %d, function %d still present. " * Attempting to remove function 0 of a multifunction
"Must unplug all non-0 functions first.", * device will will cascade into removing all child
slotnr, i); * functions, even if their unplug weren't requested
return; * beforehand.
*/
spapr_drc_detach(func_drc);
} }
} }
} }
@ -1804,7 +1806,7 @@ static void spapr_phb_destroy_msi(gpointer opaque)
{ {
SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
spapr_pci_msi *msi = opaque; SpaprPciMsi *msi = opaque;
if (!smc->legacy_irq_allocation) { if (!smc->legacy_irq_allocation) {
spapr_irq_msi_free(spapr, msi->first_irq, msi->num); spapr_irq_msi_free(spapr, msi->first_irq, msi->num);
@ -2118,7 +2120,7 @@ static const VMStateDescription vmstate_spapr_pci_lsi = {
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_UINT32_EQUAL(irq, struct spapr_pci_lsi, NULL), VMSTATE_UINT32_EQUAL(irq, SpaprPciLsi, NULL),
VMSTATE_END_OF_LIST() VMSTATE_END_OF_LIST()
}, },
@ -2129,9 +2131,9 @@ static const VMStateDescription vmstate_spapr_pci_msi = {
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.fields = (VMStateField []) { .fields = (VMStateField []) {
VMSTATE_UINT32(key, spapr_pci_msi_mig), VMSTATE_UINT32(key, SpaprPciMsiMig),
VMSTATE_UINT32(value.first_irq, spapr_pci_msi_mig), VMSTATE_UINT32(value.first_irq, SpaprPciMsiMig),
VMSTATE_UINT32(value.num, spapr_pci_msi_mig), VMSTATE_UINT32(value.num, SpaprPciMsiMig),
VMSTATE_END_OF_LIST() VMSTATE_END_OF_LIST()
}, },
}; };
@ -2163,12 +2165,12 @@ static int spapr_pci_pre_save(void *opaque)
if (!sphb->msi_devs_num) { if (!sphb->msi_devs_num) {
return 0; return 0;
} }
sphb->msi_devs = g_new(spapr_pci_msi_mig, sphb->msi_devs_num); sphb->msi_devs = g_new(SpaprPciMsiMig, sphb->msi_devs_num);
g_hash_table_iter_init(&iter, sphb->msi); g_hash_table_iter_init(&iter, sphb->msi);
for (i = 0; g_hash_table_iter_next(&iter, &key, &value); ++i) { for (i = 0; g_hash_table_iter_next(&iter, &key, &value); ++i) {
sphb->msi_devs[i].key = *(uint32_t *) key; sphb->msi_devs[i].key = *(uint32_t *) key;
sphb->msi_devs[i].value = *(spapr_pci_msi *) value; sphb->msi_devs[i].value = *(SpaprPciMsi *) value;
} }
return 0; return 0;
@ -2215,10 +2217,10 @@ static const VMStateDescription vmstate_spapr_pci = {
VMSTATE_UINT64_TEST(mig_io_win_addr, SpaprPhbState, pre_2_8_migration), VMSTATE_UINT64_TEST(mig_io_win_addr, SpaprPhbState, pre_2_8_migration),
VMSTATE_UINT64_TEST(mig_io_win_size, SpaprPhbState, pre_2_8_migration), VMSTATE_UINT64_TEST(mig_io_win_size, SpaprPhbState, pre_2_8_migration),
VMSTATE_STRUCT_ARRAY(lsi_table, SpaprPhbState, PCI_NUM_PINS, 0, VMSTATE_STRUCT_ARRAY(lsi_table, SpaprPhbState, PCI_NUM_PINS, 0,
vmstate_spapr_pci_lsi, struct spapr_pci_lsi), vmstate_spapr_pci_lsi, SpaprPciLsi),
VMSTATE_INT32(msi_devs_num, SpaprPhbState), VMSTATE_INT32(msi_devs_num, SpaprPhbState),
VMSTATE_STRUCT_VARRAY_ALLOC(msi_devs, SpaprPhbState, msi_devs_num, 0, VMSTATE_STRUCT_VARRAY_ALLOC(msi_devs, SpaprPhbState, msi_devs_num, 0,
vmstate_spapr_pci_msi, spapr_pci_msi_mig), vmstate_spapr_pci_msi, SpaprPciMsiMig),
VMSTATE_END_OF_LIST() VMSTATE_END_OF_LIST()
}, },
}; };

View File

@ -39,11 +39,7 @@
#define SPAPR_GPU_NUMA_ID (cpu_to_be32(1)) #define SPAPR_GPU_NUMA_ID (cpu_to_be32(1))
struct spapr_phb_pci_nvgpu_config { typedef struct SpaprPhbPciNvGpuSlot {
uint64_t nv2_ram_current;
uint64_t nv2_atsd_current;
int num; /* number of non empty (i.e. tgt!=0) entries in slots[] */
struct spapr_phb_pci_nvgpu_slot {
uint64_t tgt; uint64_t tgt;
uint64_t gpa; uint64_t gpa;
unsigned numa_id; unsigned numa_id;
@ -54,12 +50,18 @@ struct spapr_phb_pci_nvgpu_config {
PCIDevice *npdev; PCIDevice *npdev;
uint32_t link_speed; uint32_t link_speed;
} links[NVGPU_MAX_LINKS]; } links[NVGPU_MAX_LINKS];
} slots[NVGPU_MAX_NUM]; } SpaprPhbPciNvGpuSlot;
struct SpaprPhbPciNvGpuConfig {
uint64_t nv2_ram_current;
uint64_t nv2_atsd_current;
int num; /* number of non empty (i.e. tgt!=0) entries in slots[] */
SpaprPhbPciNvGpuSlot slots[NVGPU_MAX_NUM];
Error *errp; Error *errp;
}; };
static struct spapr_phb_pci_nvgpu_slot * static SpaprPhbPciNvGpuSlot *
spapr_nvgpu_get_slot(struct spapr_phb_pci_nvgpu_config *nvgpus, uint64_t tgt) spapr_nvgpu_get_slot(SpaprPhbPciNvGpuConfig *nvgpus, uint64_t tgt)
{ {
int i; int i;
@ -81,13 +83,13 @@ spapr_nvgpu_get_slot(struct spapr_phb_pci_nvgpu_config *nvgpus, uint64_t tgt)
return &nvgpus->slots[i]; return &nvgpus->slots[i];
} }
static void spapr_pci_collect_nvgpu(struct spapr_phb_pci_nvgpu_config *nvgpus, static void spapr_pci_collect_nvgpu(SpaprPhbPciNvGpuConfig *nvgpus,
PCIDevice *pdev, uint64_t tgt, PCIDevice *pdev, uint64_t tgt,
MemoryRegion *mr, Error **errp) MemoryRegion *mr, Error **errp)
{ {
MachineState *machine = MACHINE(qdev_get_machine()); MachineState *machine = MACHINE(qdev_get_machine());
SpaprMachineState *spapr = SPAPR_MACHINE(machine); SpaprMachineState *spapr = SPAPR_MACHINE(machine);
struct spapr_phb_pci_nvgpu_slot *nvslot = spapr_nvgpu_get_slot(nvgpus, tgt); SpaprPhbPciNvGpuSlot *nvslot = spapr_nvgpu_get_slot(nvgpus, tgt);
if (!nvslot) { if (!nvslot) {
error_setg(errp, "Found too many GPUs per vPHB"); error_setg(errp, "Found too many GPUs per vPHB");
@ -102,11 +104,11 @@ static void spapr_pci_collect_nvgpu(struct spapr_phb_pci_nvgpu_config *nvgpus,
++spapr->gpu_numa_id; ++spapr->gpu_numa_id;
} }
static void spapr_pci_collect_nvnpu(struct spapr_phb_pci_nvgpu_config *nvgpus, static void spapr_pci_collect_nvnpu(SpaprPhbPciNvGpuConfig *nvgpus,
PCIDevice *pdev, uint64_t tgt, PCIDevice *pdev, uint64_t tgt,
MemoryRegion *mr, Error **errp) MemoryRegion *mr, Error **errp)
{ {
struct spapr_phb_pci_nvgpu_slot *nvslot = spapr_nvgpu_get_slot(nvgpus, tgt); SpaprPhbPciNvGpuSlot *nvslot = spapr_nvgpu_get_slot(nvgpus, tgt);
int j; int j;
if (!nvslot) { if (!nvslot) {
@ -138,7 +140,7 @@ static void spapr_phb_pci_collect_nvgpu(PCIBus *bus, PCIDevice *pdev,
if (tgt) { if (tgt) {
Error *local_err = NULL; Error *local_err = NULL;
struct spapr_phb_pci_nvgpu_config *nvgpus = opaque; SpaprPhbPciNvGpuConfig *nvgpus = opaque;
Object *mr_gpu = object_property_get_link(po, "nvlink2-mr[0]", NULL); Object *mr_gpu = object_property_get_link(po, "nvlink2-mr[0]", NULL);
Object *mr_npu = object_property_get_link(po, "nvlink2-atsd-mr[0]", Object *mr_npu = object_property_get_link(po, "nvlink2-atsd-mr[0]",
NULL); NULL);
@ -177,7 +179,7 @@ void spapr_phb_nvgpu_setup(SpaprPhbState *sphb, Error **errp)
return; return;
} }
sphb->nvgpus = g_new0(struct spapr_phb_pci_nvgpu_config, 1); sphb->nvgpus = g_new0(SpaprPhbPciNvGpuConfig, 1);
sphb->nvgpus->nv2_ram_current = sphb->nv2_gpa_win_addr; sphb->nvgpus->nv2_ram_current = sphb->nv2_gpa_win_addr;
sphb->nvgpus->nv2_atsd_current = sphb->nv2_atsd_win_addr; sphb->nvgpus->nv2_atsd_current = sphb->nv2_atsd_win_addr;
@ -194,7 +196,7 @@ void spapr_phb_nvgpu_setup(SpaprPhbState *sphb, Error **errp)
/* Add found GPU RAM and ATSD MRs if found */ /* Add found GPU RAM and ATSD MRs if found */
for (i = 0, valid_gpu_num = 0; i < sphb->nvgpus->num; ++i) { for (i = 0, valid_gpu_num = 0; i < sphb->nvgpus->num; ++i) {
Object *nvmrobj; Object *nvmrobj;
struct spapr_phb_pci_nvgpu_slot *nvslot = &sphb->nvgpus->slots[i]; SpaprPhbPciNvGpuSlot *nvslot = &sphb->nvgpus->slots[i];
if (!nvslot->gpdev) { if (!nvslot->gpdev) {
continue; continue;
@ -242,7 +244,7 @@ void spapr_phb_nvgpu_free(SpaprPhbState *sphb)
} }
for (i = 0; i < sphb->nvgpus->num; ++i) { for (i = 0; i < sphb->nvgpus->num; ++i) {
struct spapr_phb_pci_nvgpu_slot *nvslot = &sphb->nvgpus->slots[i]; SpaprPhbPciNvGpuSlot *nvslot = &sphb->nvgpus->slots[i];
Object *nv_mrobj = object_property_get_link(OBJECT(nvslot->gpdev), Object *nv_mrobj = object_property_get_link(OBJECT(nvslot->gpdev),
"nvlink2-mr[0]", NULL); "nvlink2-mr[0]", NULL);
@ -276,7 +278,7 @@ void spapr_phb_nvgpu_populate_dt(SpaprPhbState *sphb, void *fdt, int bus_off,
} }
for (i = 0; (i < sphb->nvgpus->num) && (atsdnum < ARRAY_SIZE(atsd)); ++i) { for (i = 0; (i < sphb->nvgpus->num) && (atsdnum < ARRAY_SIZE(atsd)); ++i) {
struct spapr_phb_pci_nvgpu_slot *nvslot = &sphb->nvgpus->slots[i]; SpaprPhbPciNvGpuSlot *nvslot = &sphb->nvgpus->slots[i];
if (!nvslot->gpdev) { if (!nvslot->gpdev) {
continue; continue;
@ -354,7 +356,7 @@ void spapr_phb_nvgpu_ram_populate_dt(SpaprPhbState *sphb, void *fdt)
/* Add memory nodes for GPU RAM and mark them unusable */ /* Add memory nodes for GPU RAM and mark them unusable */
for (i = 0; i < sphb->nvgpus->num; ++i) { for (i = 0; i < sphb->nvgpus->num; ++i) {
struct spapr_phb_pci_nvgpu_slot *nvslot = &sphb->nvgpus->slots[i]; SpaprPhbPciNvGpuSlot *nvslot = &sphb->nvgpus->slots[i];
Object *nv_mrobj = object_property_get_link(OBJECT(nvslot->gpdev), Object *nv_mrobj = object_property_get_link(OBJECT(nvslot->gpdev),
"nvlink2-mr[0]", NULL); "nvlink2-mr[0]", NULL);
uint32_t associativity[] = { uint32_t associativity[] = {
@ -398,7 +400,7 @@ void spapr_phb_nvgpu_populate_pcidev_dt(PCIDevice *dev, void *fdt, int offset,
} }
for (i = 0; i < sphb->nvgpus->num; ++i) { for (i = 0; i < sphb->nvgpus->num; ++i) {
struct spapr_phb_pci_nvgpu_slot *nvslot = &sphb->nvgpus->slots[i]; SpaprPhbPciNvGpuSlot *nvslot = &sphb->nvgpus->slots[i];
/* Skip "slot" without attached GPU */ /* Skip "slot" without attached GPU */
if (!nvslot->gpdev) { if (!nvslot->gpdev) {

View File

@ -266,6 +266,7 @@ static void rtas_ibm_get_system_parameter(PowerPCCPU *cpu,
target_ulong args, target_ulong args,
uint32_t nret, target_ulong rets) uint32_t nret, target_ulong rets)
{ {
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
MachineState *ms = MACHINE(qdev_get_machine()); MachineState *ms = MACHINE(qdev_get_machine());
unsigned int max_cpus = ms->smp.max_cpus; unsigned int max_cpus = ms->smp.max_cpus;
target_ulong parameter = rtas_ld(args, 0); target_ulong parameter = rtas_ld(args, 0);
@ -283,6 +284,20 @@ static void rtas_ibm_get_system_parameter(PowerPCCPU *cpu,
current_machine->ram_size / MiB, current_machine->ram_size / MiB,
ms->smp.cpus, ms->smp.cpus,
max_cpus); max_cpus);
if (pcc->n_host_threads > 0) {
char *hostthr_val, *old = param_val;
/*
* Add HostThrs property. This property is not present in PAPR but
* is expected by some guests to communicate the number of physical
* host threads per core on the system so that they can scale
* information which varies based on the thread configuration.
*/
hostthr_val = g_strdup_printf(",HostThrs=%d", pcc->n_host_threads);
param_val = g_strconcat(param_val, hostthr_val, NULL);
g_free(hostthr_val);
g_free(old);
}
ret = sysparm_st(buffer, length, param_val, strlen(param_val) + 1); ret = sysparm_st(buffer, length, param_val, strlen(param_val) + 1);
g_free(param_val); g_free(param_val);
break; break;

View File

@ -34,15 +34,21 @@
typedef struct SpaprPhbState SpaprPhbState; typedef struct SpaprPhbState SpaprPhbState;
typedef struct spapr_pci_msi { typedef struct SpaprPciMsi {
uint32_t first_irq; uint32_t first_irq;
uint32_t num; uint32_t num;
} spapr_pci_msi; } SpaprPciMsi;
typedef struct spapr_pci_msi_mig { typedef struct SpaprPciMsiMig {
uint32_t key; uint32_t key;
spapr_pci_msi value; SpaprPciMsi value;
} spapr_pci_msi_mig; } SpaprPciMsiMig;
typedef struct SpaprPciLsi {
uint32_t irq;
} SpaprPciLsi;
typedef struct SpaprPhbPciNvGpuConfig SpaprPhbPciNvGpuConfig;
struct SpaprPhbState { struct SpaprPhbState {
PCIHostState parent_obj; PCIHostState parent_obj;
@ -63,14 +69,12 @@ struct SpaprPhbState {
AddressSpace iommu_as; AddressSpace iommu_as;
MemoryRegion iommu_root; MemoryRegion iommu_root;
struct spapr_pci_lsi { SpaprPciLsi lsi_table[PCI_NUM_PINS];
uint32_t irq;
} lsi_table[PCI_NUM_PINS];
GHashTable *msi; GHashTable *msi;
/* Temporary cache for migration purposes */ /* Temporary cache for migration purposes */
int32_t msi_devs_num; int32_t msi_devs_num;
spapr_pci_msi_mig *msi_devs; SpaprPciMsiMig *msi_devs;
QLIST_ENTRY(SpaprPhbState) list; QLIST_ENTRY(SpaprPhbState) list;
@ -89,7 +93,7 @@ struct SpaprPhbState {
hwaddr mig_io_win_addr, mig_io_win_size; hwaddr mig_io_win_addr, mig_io_win_size;
hwaddr nv2_gpa_win_addr; hwaddr nv2_gpa_win_addr;
hwaddr nv2_atsd_win_addr; hwaddr nv2_atsd_win_addr;
struct spapr_phb_pci_nvgpu_config *nvgpus; SpaprPhbPciNvGpuConfig *nvgpus;
}; };
#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL #define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL

View File

@ -121,6 +121,7 @@ struct SpaprMachineClass {
bool legacy_irq_allocation; bool legacy_irq_allocation;
bool broken_host_serial_model; /* present real host info to the guest */ bool broken_host_serial_model; /* present real host info to the guest */
bool pre_4_1_migration; /* don't migrate hpt-max-page-size */ bool pre_4_1_migration; /* don't migrate hpt-max-page-size */
bool linux_pci_probe;
void (*phb_placement)(SpaprMachineState *spapr, uint32_t index, void (*phb_placement)(SpaprMachineState *spapr, uint32_t index,
uint64_t *buid, hwaddr *pio, uint64_t *buid, hwaddr *pio,

View File

@ -17,7 +17,7 @@
- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
implementation for certain IBM POWER hardware. The sources are at implementation for certain IBM POWER hardware. The sources are at
https://github.com/aik/SLOF, and the image currently in qemu is https://github.com/aik/SLOF, and the image currently in qemu is
built from git tag qemu-slof-20190719. built from git tag qemu-slof-20190827.
- sgabios (the Serial Graphics Adapter option ROM) provides a means for - sgabios (the Serial Graphics Adapter option ROM) provides a means for
legacy x86 software to communicate with an attached serial console as legacy x86 software to communicate with an attached serial console as

Binary file not shown.

Binary file not shown.

@ -1 +1 @@
Subproject commit 7bfe584e321946771692711ff83ad2b5850daca7 Subproject commit ea221600a116883137ef90b2b7ab7d2472bc4f10

@ -1 +1 @@
Subproject commit 261ca8e779e5138869a45f174caa49be6a274501 Subproject commit 3a6fdede6ce117facec0108afe716cf5d0472c3f

View File

@ -191,6 +191,7 @@ typedef struct PowerPCCPUClass {
const PPCHash64Options *hash64_opts; const PPCHash64Options *hash64_opts;
struct ppc_radix_page_info *radix_page_info; struct ppc_radix_page_info *radix_page_info;
uint32_t lrg_decr_bits; uint32_t lrg_decr_bits;
int n_host_threads;
void (*init_proc)(CPUPPCState *env); void (*init_proc)(CPUPPCState *env);
int (*check_pow)(CPUPPCState *env); int (*check_pow)(CPUPPCState *env);
int (*handle_mmu_fault)(PowerPCCPU *cpu, vaddr eaddr, int rwx, int mmu_idx); int (*handle_mmu_fault)(PowerPCCPU *cpu, vaddr eaddr, int rwx, int mmu_idx);

View File

@ -630,19 +630,15 @@ static void do_float_check_status(CPUPPCState *env, uintptr_t raddr)
{ {
CPUState *cs = env_cpu(env); CPUState *cs = env_cpu(env);
int status = get_float_exception_flags(&env->fp_status); int status = get_float_exception_flags(&env->fp_status);
bool inexact_happened = false;
if (status & float_flag_overflow) { if (status & float_flag_overflow) {
float_overflow_excp(env); float_overflow_excp(env);
} else if (status & float_flag_underflow) { } else if (status & float_flag_underflow) {
float_underflow_excp(env); float_underflow_excp(env);
} else if (status & float_flag_inexact) {
float_inexact_excp(env);
inexact_happened = true;
} }
if (status & float_flag_inexact) {
/* if the inexact flag was not set */ float_inexact_excp(env);
if (inexact_happened == false) { } else {
env->fpscr &= ~(1 << FPSCR_FI); /* clear the FPSCR[FI] bit */ env->fpscr &= ~(1 << FPSCR_FI); /* clear the FPSCR[FI] bit */
} }
@ -2887,12 +2883,40 @@ void helper_xscvqpdp(CPUPPCState *env, uint32_t opcode,
uint64_t helper_xscvdpspn(CPUPPCState *env, uint64_t xb) uint64_t helper_xscvdpspn(CPUPPCState *env, uint64_t xb)
{ {
uint64_t result; uint64_t result, sign, exp, frac;
float_status tstat = env->fp_status; float_status tstat = env->fp_status;
set_float_exception_flags(0, &tstat); set_float_exception_flags(0, &tstat);
result = (uint64_t)float64_to_float32(xb, &tstat); sign = extract64(xb, 63, 1);
exp = extract64(xb, 52, 11);
frac = extract64(xb, 0, 52) | 0x10000000000000ULL;
if (unlikely(exp == 0 && extract64(frac, 0, 52) != 0)) {
/* DP denormal operand. */
/* Exponent override to DP min exp. */
exp = 1;
/* Implicit bit override to 0. */
frac = deposit64(frac, 53, 1, 0);
}
if (unlikely(exp < 897 && frac != 0)) {
/* SP tiny operand. */
if (897 - exp > 63) {
frac = 0;
} else {
/* Denormalize until exp = SP min exp. */
frac >>= (897 - exp);
}
/* Exponent override to SP min exp - 1. */
exp = 896;
}
result = sign << 31;
result |= extract64(exp, 10, 1) << 30;
result |= extract64(exp, 0, 7) << 23;
result |= extract64(frac, 29, 23);
/* hardware replicates result to both words of the doubleword result. */ /* hardware replicates result to both words of the doubleword result. */
return (result << 32) | result; return (result << 32) | result;
} }

View File

@ -350,6 +350,28 @@ static void glue(gen_, name0##_##name1)(DisasContext *ctx) \
} \ } \
} }
/*
* We use this macro if one instruction is realized with direct
* translation, and second one with helper.
*/
#define GEN_VXFORM_TRANS_DUAL(name0, flg0, flg2_0, name1, flg1, flg2_1)\
static void glue(gen_, name0##_##name1)(DisasContext *ctx) \
{ \
if ((Rc(ctx->opcode) == 0) && \
((ctx->insns_flags & flg0) || (ctx->insns_flags2 & flg2_0))) { \
if (unlikely(!ctx->altivec_enabled)) { \
gen_exception(ctx, POWERPC_EXCP_VPU); \
return; \
} \
trans_##name0(ctx); \
} else if ((Rc(ctx->opcode) == 1) && \
((ctx->insns_flags & flg1) || (ctx->insns_flags2 & flg2_1))) { \
gen_##name1(ctx); \
} else { \
gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); \
} \
}
/* Adds support to provide invalid mask */ /* Adds support to provide invalid mask */
#define GEN_VXFORM_DUAL_EXT(name0, flg0, flg2_0, inval0, \ #define GEN_VXFORM_DUAL_EXT(name0, flg0, flg2_0, inval0, \
name1, flg1, flg2_1, inval1) \ name1, flg1, flg2_1, inval1) \
@ -431,20 +453,13 @@ GEN_VXFORM(vmrglb, 6, 4);
GEN_VXFORM(vmrglh, 6, 5); GEN_VXFORM(vmrglh, 6, 5);
GEN_VXFORM(vmrglw, 6, 6); GEN_VXFORM(vmrglw, 6, 6);
static void gen_vmrgew(DisasContext *ctx) static void trans_vmrgew(DisasContext *ctx)
{ {
TCGv_i64 tmp; int VT = rD(ctx->opcode);
TCGv_i64 avr; int VA = rA(ctx->opcode);
int VT, VA, VB; int VB = rB(ctx->opcode);
if (unlikely(!ctx->altivec_enabled)) { TCGv_i64 tmp = tcg_temp_new_i64();
gen_exception(ctx, POWERPC_EXCP_VPU); TCGv_i64 avr = tcg_temp_new_i64();
return;
}
VT = rD(ctx->opcode);
VA = rA(ctx->opcode);
VB = rB(ctx->opcode);
tmp = tcg_temp_new_i64();
avr = tcg_temp_new_i64();
get_avr64(avr, VB, true); get_avr64(avr, VB, true);
tcg_gen_shri_i64(tmp, avr, 32); tcg_gen_shri_i64(tmp, avr, 32);
@ -462,21 +477,14 @@ static void gen_vmrgew(DisasContext *ctx)
tcg_temp_free_i64(avr); tcg_temp_free_i64(avr);
} }
static void gen_vmrgow(DisasContext *ctx) static void trans_vmrgow(DisasContext *ctx)
{ {
TCGv_i64 t0, t1; int VT = rD(ctx->opcode);
TCGv_i64 avr; int VA = rA(ctx->opcode);
int VT, VA, VB; int VB = rB(ctx->opcode);
if (unlikely(!ctx->altivec_enabled)) { TCGv_i64 t0 = tcg_temp_new_i64();
gen_exception(ctx, POWERPC_EXCP_VPU); TCGv_i64 t1 = tcg_temp_new_i64();
return; TCGv_i64 avr = tcg_temp_new_i64();
}
VT = rD(ctx->opcode);
VA = rA(ctx->opcode);
VB = rB(ctx->opcode);
t0 = tcg_temp_new_i64();
t1 = tcg_temp_new_i64();
avr = tcg_temp_new_i64();
get_avr64(t0, VB, true); get_avr64(t0, VB, true);
get_avr64(t1, VA, true); get_avr64(t1, VA, true);
@ -936,14 +944,14 @@ GEN_VXFORM_ENV(vminfp, 5, 17);
GEN_VXFORM_HETRO(vextublx, 6, 24) GEN_VXFORM_HETRO(vextublx, 6, 24)
GEN_VXFORM_HETRO(vextuhlx, 6, 25) GEN_VXFORM_HETRO(vextuhlx, 6, 25)
GEN_VXFORM_HETRO(vextuwlx, 6, 26) GEN_VXFORM_HETRO(vextuwlx, 6, 26)
GEN_VXFORM_DUAL(vmrgow, PPC_NONE, PPC2_ALTIVEC_207, GEN_VXFORM_TRANS_DUAL(vmrgow, PPC_NONE, PPC2_ALTIVEC_207,
vextuwlx, PPC_NONE, PPC2_ISA300) vextuwlx, PPC_NONE, PPC2_ISA300)
GEN_VXFORM_HETRO(vextubrx, 6, 28) GEN_VXFORM_HETRO(vextubrx, 6, 28)
GEN_VXFORM_HETRO(vextuhrx, 6, 29) GEN_VXFORM_HETRO(vextuhrx, 6, 29)
GEN_VXFORM_HETRO(vextuwrx, 6, 30) GEN_VXFORM_HETRO(vextuwrx, 6, 30)
GEN_VXFORM_TRANS(lvsl, 6, 31) GEN_VXFORM_TRANS(lvsl, 6, 31)
GEN_VXFORM_TRANS(lvsr, 6, 32) GEN_VXFORM_TRANS(lvsr, 6, 32)
GEN_VXFORM_DUAL(vmrgew, PPC_NONE, PPC2_ALTIVEC_207, \ GEN_VXFORM_TRANS_DUAL(vmrgew, PPC_NONE, PPC2_ALTIVEC_207,
vextuwrx, PPC_NONE, PPC2_ISA300) vextuwrx, PPC_NONE, PPC2_ISA300)
#define GEN_VXRFORM1(opname, name, str, opc2, opc3) \ #define GEN_VXRFORM1(opname, name, str, opc2, opc3) \

View File

@ -1308,7 +1308,7 @@ static void gen_##name(DisasContext *ctx) \
} \ } \
xt = gen_vsr_ptr(xT(ctx->opcode)); \ xt = gen_vsr_ptr(xT(ctx->opcode)); \
xa = gen_vsr_ptr(xA(ctx->opcode)); \ xa = gen_vsr_ptr(xA(ctx->opcode)); \
if (ctx->opcode & PPC_BIT(25)) { \ if (ctx->opcode & PPC_BIT32(25)) { \
/* \ /* \
* AxT + B \ * AxT + B \
*/ \ */ \

View File

@ -8770,6 +8770,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault; pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
pcc->hash64_opts = &ppc_hash64_opts_POWER7; pcc->hash64_opts = &ppc_hash64_opts_POWER7;
pcc->lrg_decr_bits = 32; pcc->lrg_decr_bits = 32;
pcc->n_host_threads = 8;
#endif #endif
pcc->excp_model = POWERPC_EXCP_POWER8; pcc->excp_model = POWERPC_EXCP_POWER8;
pcc->bus_model = PPC_FLAGS_INPUT_POWER7; pcc->bus_model = PPC_FLAGS_INPUT_POWER7;
@ -8981,6 +8982,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
pcc->hash64_opts = &ppc_hash64_opts_POWER7; pcc->hash64_opts = &ppc_hash64_opts_POWER7;
pcc->radix_page_info = &POWER9_radix_page_info; pcc->radix_page_info = &POWER9_radix_page_info;
pcc->lrg_decr_bits = 56; pcc->lrg_decr_bits = 56;
pcc->n_host_threads = 4;
#endif #endif
pcc->excp_model = POWERPC_EXCP_POWER9; pcc->excp_model = POWERPC_EXCP_POWER9;
pcc->bus_model = PPC_FLAGS_INPUT_POWER9; pcc->bus_model = PPC_FLAGS_INPUT_POWER9;
@ -10461,6 +10463,10 @@ static void ppc_cpu_reset(CPUState *s)
s->exception_index = POWERPC_EXCP_NONE; s->exception_index = POWERPC_EXCP_NONE;
env->error_code = 0; env->error_code = 0;
/* tininess for underflow is detected before rounding */
set_float_detect_tininess(float_tininess_before_rounding,
&env->fp_status);
for (i = 0; i < ARRAY_SIZE(env->spr_cb); i++) { for (i = 0; i < ARRAY_SIZE(env->spr_cb); i++) {
ppc_spr_t *spr = &env->spr_cb[i]; ppc_spr_t *spr = &env->spr_cb[i];

View File

@ -103,7 +103,8 @@ static testdef_t tests[] = {
{ "ppc64", "pseries", { "ppc64", "pseries",
"-machine cap-cfpc=broken,cap-sbbc=broken,cap-ibs=broken", "-machine cap-cfpc=broken,cap-sbbc=broken,cap-ibs=broken",
"Open Firmware" }, "Open Firmware" },
{ "ppc64", "powernv", "-cpu POWER8", "OPAL" }, { "ppc64", "powernv8", "", "OPAL" },
{ "ppc64", "powernv9", "", "OPAL" },
{ "ppc64", "sam460ex", "-device e1000", "8086 100e" }, { "ppc64", "sam460ex", "-device e1000", "8086 100e" },
{ "i386", "isapc", "-cpu qemu32 -device sga", "SGABIOS" }, { "i386", "isapc", "-cpu qemu32 -device sga", "SGABIOS" },
{ "i386", "pc", "-device sga", "SGABIOS" }, { "i386", "pc", "-device sga", "SGABIOS" },

View File

@ -77,9 +77,15 @@ static void test_xscom_cfam_id(QTestState *qts, const PnvChip *chip)
static void test_cfam_id(const void *data) static void test_cfam_id(const void *data)
{ {
const PnvChip *chip = data; const PnvChip *chip = data;
const char *machine = "powernv8";
QTestState *qts; QTestState *qts;
qts = qtest_initf("-M powernv,accel=tcg -cpu %s", chip->cpu_model); if (chip->chip_type == PNV_CHIP_POWER9) {
machine = "powernv9";
}
qts = qtest_initf("-M %s,accel=tcg -cpu %s",
machine, chip->cpu_model);
test_xscom_cfam_id(qts, chip); test_xscom_cfam_id(qts, chip);
qtest_quit(qts); qtest_quit(qts);
} }
@ -113,8 +119,14 @@ static void test_core(const void *data)
{ {
const PnvChip *chip = data; const PnvChip *chip = data;
QTestState *qts; QTestState *qts;
const char *machine = "powernv8";
qts = qtest_initf("-M powernv,accel=tcg -cpu %s", chip->cpu_model); if (chip->chip_type == PNV_CHIP_POWER9) {
machine = "powernv9";
}
qts = qtest_initf("-M %s,accel=tcg -cpu %s",
machine, chip->cpu_model);
test_xscom_core(qts, chip); test_xscom_core(qts, chip);
qtest_quit(qts); qtest_quit(qts);
} }