ppc patch queue 2017-09-08
This is the first batch of ppc related patches for qemu-2.11, and it's accumulated quite a few things. Includes: * A cleanup to handling of ppc cpu models from Igor * First parts of fixes to handling of guest vs. host SMT modes from Sam Bobroff * Preliminary patches towards supporting the Sam460 board from Balaton Zoltan * Several fixes for hotplug logic * Assorted other fixes and cleanups -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEdfRlhq5hpmzETofcbDjKyiDZs5IFAlmyKooACgkQbDjKyiDZ s5Jprw/7BYdf0FwmSy3UVuwfVTzqW+TzaAQRqUlqtDNwEnYL6D7iuL0u3tuhip9c a3+AKHk9A0fj8syoN17NTwZbuo4VGf0I26Gesp26QvDmOUeQhkFbFAtU2mXrgjI4 O/Fz+gddKEJd7qrSBi78kySP1GdaGS2HHOR+3Bc5qIZOR/BE8hFQxeSUCCkeN24A wcnGn11vAGFk3HrAfAsFCGKvPOp+F9XBh5Rr3qqJ59RBvUBpsx5Th9e470NZ5iDY Cv9sJKesj39Jr4kduFvmFX3r4bEhv/sBqtk7tdY66T3IA5XN6TEaOH2hwSw3rYW8 INfjVfAccK9J8aBz8qiYfmj2FhPiwurqzp4f+Xrz9XbqeBX7ASQOzfK/c3id1uv8 jODdpRY0+8eHH9wYMGBjy6yeweyHF5K00Uz6snnskCAC7TtxhGOzIyRcGhEeMlXf 0r+YfWF59ZzYRGTD/J4qg4arJCXO8Vi9zuQLA7pO2jsgyyjxKkPcz0ufdfn8S2hw WDCOrJxn38mwmrbf90q3DDcfrAwUFjWmHmBhirUVBUQZVg+Zsc/bSWBN05+oXc/a ZXd1P20QQx/RBRQBU/pbwiUseERqBY0FrkHm6T6Y3n0+3XD93hwRBtYpfni8pXv0 tszuFEQTZlhEADH4NXcS+pq3PVy68lT4DG+DhPhexjQXxJ7B46c= =OGJZ -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-2.11-20170908' into staging ppc patch queue 2017-09-08 This is the first batch of ppc related patches for qemu-2.11, and it's accumulated quite a few things. Includes: * A cleanup to handling of ppc cpu models from Igor * First parts of fixes to handling of guest vs. host SMT modes from Sam Bobroff * Preliminary patches towards supporting the Sam460 board from Balaton Zoltan * Several fixes for hotplug logic * Assorted other fixes and cleanups # gpg: Signature made Fri 08 Sep 2017 06:28:42 BST # gpg: using RSA key 0x6C38CACA20D9B392 # gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>" # gpg: aka "David Gibson (Red Hat) <dgibson@redhat.com>" # gpg: aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>" # gpg: aka "David Gibson (kernel.org) <dwg@kernel.org>" # Primary key fingerprint: 75F4 6586 AE61 A66C C44E 87DC 6C38 CACA 20D9 B392 * remotes/dgibson/tags/ppc-for-2.11-20170908: (40 commits) ppc: spapr: Move VCPU ID calculation into sPAPR ppc: remove non implemented cpu models ppc: drop caching ObjectClass from PowerPCCPUAlias ppc: simplify cpu model lookup by PVR ppc: replace inter-function cyclic dependency/recurssion with 2 simple lookups ppc: make cpu alias point only to real cpu models ppc: make cpu_model translation to type consistent ppc: use macros to make cpu type name from string literal target/ppc: Remove old STATUS file PPC: KVM: Support machine option to set VSMT mode spapr: fallback to raw mode if best compat mode cannot be set during CAS hw/nvram/spapr_nvram: Device can not be created by the users hw/ppc/spapr_cpu_core: Add a proper check for spapr machine ppc4xx: Export ECB and PLB emulation ppc4xx_i2c: Move to hw/i2c ppc4xx_i2c: QOMify ppc4xx: Split off 4xx I2C emulation from ppc405_uc to its own file ppc4xx: Make MAL emulation more generic ppc4xx: Move MAL from ppc405_uc to ppc4xx_devs spapr_iommu: Realloc guest visible TCE table when hot(un)plugging vfio-pci ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
a1ae46d1b4
|
@ -3,6 +3,7 @@
|
|||
include pci.mak
|
||||
include sound.mak
|
||||
include usb.mak
|
||||
CONFIG_PPC4XX=y
|
||||
CONFIG_ESCC=y
|
||||
CONFIG_M48T59=y
|
||||
CONFIG_SERIAL=y
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
include pci.mak
|
||||
include sound.mak
|
||||
include usb.mak
|
||||
CONFIG_PPC4XX=y
|
||||
CONFIG_VIRTIO_VGA=y
|
||||
CONFIG_ESCC=y
|
||||
CONFIG_M48T59=y
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
include pci.mak
|
||||
include sound.mak
|
||||
include usb.mak
|
||||
CONFIG_PPC4XX=y
|
||||
CONFIG_M48T59=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_SERIAL_ISA=y
|
||||
|
|
|
@ -8,3 +8,4 @@ common-obj-$(CONFIG_EXYNOS4) += exynos4210_i2c.o
|
|||
common-obj-$(CONFIG_IMX_I2C) += imx_i2c.o
|
||||
common-obj-$(CONFIG_ASPEED_SOC) += aspeed_i2c.o
|
||||
obj-$(CONFIG_OMAP) += omap_i2c.o
|
||||
obj-$(CONFIG_PPC4XX) += ppc4xx_i2c.o
|
||||
|
|
216
hw/i2c/ppc4xx_i2c.c
Normal file
216
hw/i2c/ppc4xx_i2c.c
Normal file
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
* PPC4xx I2C controller emulation
|
||||
*
|
||||
* Copyright (c) 2007 Jocelyn Mayer
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu-common.h"
|
||||
#include "cpu.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/i2c/ppc4xx_i2c.h"
|
||||
|
||||
/*#define DEBUG_I2C*/
|
||||
|
||||
#define PPC4xx_I2C_MEM_SIZE 0x11
|
||||
|
||||
static uint64_t ppc4xx_i2c_readb(void *opaque, hwaddr addr, unsigned int size)
|
||||
{
|
||||
PPC4xxI2CState *i2c = PPC4xx_I2C(opaque);
|
||||
uint64_t ret;
|
||||
|
||||
#ifdef DEBUG_I2C
|
||||
printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
|
||||
#endif
|
||||
switch (addr) {
|
||||
case 0x00:
|
||||
/*i2c_readbyte(&i2c->mdata);*/
|
||||
ret = i2c->mdata;
|
||||
break;
|
||||
case 0x02:
|
||||
ret = i2c->sdata;
|
||||
break;
|
||||
case 0x04:
|
||||
ret = i2c->lmadr;
|
||||
break;
|
||||
case 0x05:
|
||||
ret = i2c->hmadr;
|
||||
break;
|
||||
case 0x06:
|
||||
ret = i2c->cntl;
|
||||
break;
|
||||
case 0x07:
|
||||
ret = i2c->mdcntl;
|
||||
break;
|
||||
case 0x08:
|
||||
ret = i2c->sts;
|
||||
break;
|
||||
case 0x09:
|
||||
ret = i2c->extsts;
|
||||
break;
|
||||
case 0x0A:
|
||||
ret = i2c->lsadr;
|
||||
break;
|
||||
case 0x0B:
|
||||
ret = i2c->hsadr;
|
||||
break;
|
||||
case 0x0C:
|
||||
ret = i2c->clkdiv;
|
||||
break;
|
||||
case 0x0D:
|
||||
ret = i2c->intrmsk;
|
||||
break;
|
||||
case 0x0E:
|
||||
ret = i2c->xfrcnt;
|
||||
break;
|
||||
case 0x0F:
|
||||
ret = i2c->xtcntlss;
|
||||
break;
|
||||
case 0x10:
|
||||
ret = i2c->directcntl;
|
||||
break;
|
||||
default:
|
||||
ret = 0x00;
|
||||
break;
|
||||
}
|
||||
#ifdef DEBUG_I2C
|
||||
printf("%s: addr " TARGET_FMT_plx " %02" PRIx64 "\n", __func__, addr, ret);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ppc4xx_i2c_writeb(void *opaque, hwaddr addr, uint64_t value,
|
||||
unsigned int size)
|
||||
{
|
||||
PPC4xxI2CState *i2c = opaque;
|
||||
#ifdef DEBUG_I2C
|
||||
printf("%s: addr " TARGET_FMT_plx " val %08" PRIx64 "\n",
|
||||
__func__, addr, value);
|
||||
#endif
|
||||
switch (addr) {
|
||||
case 0x00:
|
||||
i2c->mdata = value;
|
||||
/*i2c_sendbyte(&i2c->mdata);*/
|
||||
break;
|
||||
case 0x02:
|
||||
i2c->sdata = value;
|
||||
break;
|
||||
case 0x04:
|
||||
i2c->lmadr = value;
|
||||
break;
|
||||
case 0x05:
|
||||
i2c->hmadr = value;
|
||||
break;
|
||||
case 0x06:
|
||||
i2c->cntl = value;
|
||||
break;
|
||||
case 0x07:
|
||||
i2c->mdcntl = value & 0xDF;
|
||||
break;
|
||||
case 0x08:
|
||||
i2c->sts &= ~(value & 0x0A);
|
||||
break;
|
||||
case 0x09:
|
||||
i2c->extsts &= ~(value & 0x8F);
|
||||
break;
|
||||
case 0x0A:
|
||||
i2c->lsadr = value;
|
||||
break;
|
||||
case 0x0B:
|
||||
i2c->hsadr = value;
|
||||
break;
|
||||
case 0x0C:
|
||||
i2c->clkdiv = value;
|
||||
break;
|
||||
case 0x0D:
|
||||
i2c->intrmsk = value;
|
||||
break;
|
||||
case 0x0E:
|
||||
i2c->xfrcnt = value & 0x77;
|
||||
break;
|
||||
case 0x0F:
|
||||
i2c->xtcntlss = value;
|
||||
break;
|
||||
case 0x10:
|
||||
i2c->directcntl = value & 0x7;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps ppc4xx_i2c_ops = {
|
||||
.read = ppc4xx_i2c_readb,
|
||||
.write = ppc4xx_i2c_writeb,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 4,
|
||||
.impl.min_access_size = 1,
|
||||
.impl.max_access_size = 1,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void ppc4xx_i2c_reset(DeviceState *s)
|
||||
{
|
||||
PPC4xxI2CState *i2c = PPC4xx_I2C(s);
|
||||
|
||||
i2c->mdata = 0x00;
|
||||
i2c->sdata = 0x00;
|
||||
i2c->cntl = 0x00;
|
||||
i2c->mdcntl = 0x00;
|
||||
i2c->sts = 0x00;
|
||||
i2c->extsts = 0x00;
|
||||
i2c->clkdiv = 0x00;
|
||||
i2c->xfrcnt = 0x00;
|
||||
i2c->directcntl = 0x0F;
|
||||
}
|
||||
|
||||
static void ppc4xx_i2c_init(Object *o)
|
||||
{
|
||||
PPC4xxI2CState *s = PPC4xx_I2C(o);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &ppc4xx_i2c_ops, s,
|
||||
TYPE_PPC4xx_I2C, PPC4xx_I2C_MEM_SIZE);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
|
||||
sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq);
|
||||
s->bus = i2c_init_bus(DEVICE(s), "i2c");
|
||||
}
|
||||
|
||||
static void ppc4xx_i2c_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->reset = ppc4xx_i2c_reset;
|
||||
}
|
||||
|
||||
static const TypeInfo ppc4xx_i2c_type_info = {
|
||||
.name = TYPE_PPC4xx_I2C,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(PPC4xxI2CState),
|
||||
.instance_init = ppc4xx_i2c_init,
|
||||
.class_init = ppc4xx_i2c_class_init,
|
||||
};
|
||||
|
||||
static void ppc4xx_i2c_register_types(void)
|
||||
{
|
||||
type_register_static(&ppc4xx_i2c_type_info);
|
||||
}
|
||||
|
||||
type_init(ppc4xx_i2c_register_types)
|
|
@ -264,6 +264,8 @@ static void spapr_nvram_class_init(ObjectClass *klass, void *data)
|
|||
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||
dc->props = spapr_nvram_properties;
|
||||
dc->vmsd = &vmstate_spapr_nvram;
|
||||
/* Reason: Internal device only, uses spapr_rtas_register() in realize() */
|
||||
dc->user_creatable = false;
|
||||
}
|
||||
|
||||
static const TypeInfo spapr_nvram_type_info = {
|
||||
|
|
|
@ -382,7 +382,6 @@ static int ppce500_load_device_tree(MachineState *machine,
|
|||
the first node as boot node and be happy */
|
||||
for (i = smp_cpus - 1; i >= 0; i--) {
|
||||
CPUState *cpu;
|
||||
PowerPCCPU *pcpu;
|
||||
char cpu_name[128];
|
||||
uint64_t cpu_release_addr = params->spin_base + (i * 0x20);
|
||||
|
||||
|
@ -391,16 +390,13 @@ static int ppce500_load_device_tree(MachineState *machine,
|
|||
continue;
|
||||
}
|
||||
env = cpu->env_ptr;
|
||||
pcpu = POWERPC_CPU(cpu);
|
||||
|
||||
snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x",
|
||||
ppc_get_vcpu_dt_id(pcpu));
|
||||
snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x", i);
|
||||
qemu_fdt_add_subnode(fdt, cpu_name);
|
||||
qemu_fdt_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
|
||||
qemu_fdt_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
|
||||
qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu");
|
||||
qemu_fdt_setprop_cell(fdt, cpu_name, "reg",
|
||||
ppc_get_vcpu_dt_id(pcpu));
|
||||
qemu_fdt_setprop_cell(fdt, cpu_name, "reg", i);
|
||||
qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-line-size",
|
||||
env->dcache_line_size);
|
||||
qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-line-size",
|
||||
|
|
21
hw/ppc/ppc.c
21
hw/ppc/ppc.c
|
@ -1358,27 +1358,6 @@ void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val)
|
|||
}
|
||||
}
|
||||
|
||||
/* CPU device-tree ID helpers */
|
||||
int ppc_get_vcpu_dt_id(PowerPCCPU *cpu)
|
||||
{
|
||||
return cpu->cpu_dt_id;
|
||||
}
|
||||
|
||||
PowerPCCPU *ppc_get_vcpu_by_dt_id(int cpu_dt_id)
|
||||
{
|
||||
CPUState *cs;
|
||||
|
||||
CPU_FOREACH(cs) {
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
|
||||
if (cpu->cpu_dt_id == cpu_dt_id) {
|
||||
return cpu;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ppc_cpu_parse_features(const char *cpu_model)
|
||||
{
|
||||
CPUClass *cc;
|
||||
|
|
|
@ -59,6 +59,9 @@ struct ppc4xx_bd_info_t {
|
|||
ram_addr_t ppc405_set_bootinfo (CPUPPCState *env, ppc4xx_bd_info_t *bd,
|
||||
uint32_t flags);
|
||||
|
||||
void ppc4xx_plb_init(CPUPPCState *env);
|
||||
void ppc405_ebc_init(CPUPPCState *env);
|
||||
|
||||
CPUPPCState *ppc405cr_init(MemoryRegion *address_space_mem,
|
||||
MemoryRegion ram_memories[4],
|
||||
hwaddr ram_bases[4],
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "hw/hw.h"
|
||||
#include "hw/ppc/ppc.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/i2c/ppc4xx_i2c.h"
|
||||
#include "ppc405.h"
|
||||
#include "hw/char/serial.h"
|
||||
#include "qemu/timer.h"
|
||||
|
@ -40,9 +41,7 @@
|
|||
//#define DEBUG_GPIO
|
||||
//#define DEBUG_SERIAL
|
||||
//#define DEBUG_OCM
|
||||
//#define DEBUG_I2C
|
||||
//#define DEBUG_GPT
|
||||
//#define DEBUG_MAL
|
||||
//#define DEBUG_CLOCKS
|
||||
//#define DEBUG_CLOCKS_LL
|
||||
|
||||
|
@ -175,7 +174,7 @@ static void ppc4xx_plb_reset (void *opaque)
|
|||
plb->besr = 0x00000000;
|
||||
}
|
||||
|
||||
static void ppc4xx_plb_init(CPUPPCState *env)
|
||||
void ppc4xx_plb_init(CPUPPCState *env)
|
||||
{
|
||||
ppc4xx_plb_t *plb;
|
||||
|
||||
|
@ -586,7 +585,7 @@ static void ebc_reset (void *opaque)
|
|||
ebc->cfg = 0x80400000;
|
||||
}
|
||||
|
||||
static void ppc405_ebc_init(CPUPPCState *env)
|
||||
void ppc405_ebc_init(CPUPPCState *env)
|
||||
{
|
||||
ppc4xx_ebc_t *ebc;
|
||||
|
||||
|
@ -993,246 +992,6 @@ static void ppc405_ocm_init(CPUPPCState *env)
|
|||
ocm, &dcr_read_ocm, &dcr_write_ocm);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* I2C controller */
|
||||
typedef struct ppc4xx_i2c_t ppc4xx_i2c_t;
|
||||
struct ppc4xx_i2c_t {
|
||||
qemu_irq irq;
|
||||
MemoryRegion iomem;
|
||||
uint8_t mdata;
|
||||
uint8_t lmadr;
|
||||
uint8_t hmadr;
|
||||
uint8_t cntl;
|
||||
uint8_t mdcntl;
|
||||
uint8_t sts;
|
||||
uint8_t extsts;
|
||||
uint8_t sdata;
|
||||
uint8_t lsadr;
|
||||
uint8_t hsadr;
|
||||
uint8_t clkdiv;
|
||||
uint8_t intrmsk;
|
||||
uint8_t xfrcnt;
|
||||
uint8_t xtcntlss;
|
||||
uint8_t directcntl;
|
||||
};
|
||||
|
||||
static uint32_t ppc4xx_i2c_readb (void *opaque, hwaddr addr)
|
||||
{
|
||||
ppc4xx_i2c_t *i2c;
|
||||
uint32_t ret;
|
||||
|
||||
#ifdef DEBUG_I2C
|
||||
printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
|
||||
#endif
|
||||
i2c = opaque;
|
||||
switch (addr) {
|
||||
case 0x00:
|
||||
// i2c_readbyte(&i2c->mdata);
|
||||
ret = i2c->mdata;
|
||||
break;
|
||||
case 0x02:
|
||||
ret = i2c->sdata;
|
||||
break;
|
||||
case 0x04:
|
||||
ret = i2c->lmadr;
|
||||
break;
|
||||
case 0x05:
|
||||
ret = i2c->hmadr;
|
||||
break;
|
||||
case 0x06:
|
||||
ret = i2c->cntl;
|
||||
break;
|
||||
case 0x07:
|
||||
ret = i2c->mdcntl;
|
||||
break;
|
||||
case 0x08:
|
||||
ret = i2c->sts;
|
||||
break;
|
||||
case 0x09:
|
||||
ret = i2c->extsts;
|
||||
break;
|
||||
case 0x0A:
|
||||
ret = i2c->lsadr;
|
||||
break;
|
||||
case 0x0B:
|
||||
ret = i2c->hsadr;
|
||||
break;
|
||||
case 0x0C:
|
||||
ret = i2c->clkdiv;
|
||||
break;
|
||||
case 0x0D:
|
||||
ret = i2c->intrmsk;
|
||||
break;
|
||||
case 0x0E:
|
||||
ret = i2c->xfrcnt;
|
||||
break;
|
||||
case 0x0F:
|
||||
ret = i2c->xtcntlss;
|
||||
break;
|
||||
case 0x10:
|
||||
ret = i2c->directcntl;
|
||||
break;
|
||||
default:
|
||||
ret = 0x00;
|
||||
break;
|
||||
}
|
||||
#ifdef DEBUG_I2C
|
||||
printf("%s: addr " TARGET_FMT_plx " %02" PRIx32 "\n", __func__, addr, ret);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ppc4xx_i2c_writeb (void *opaque,
|
||||
hwaddr addr, uint32_t value)
|
||||
{
|
||||
ppc4xx_i2c_t *i2c;
|
||||
|
||||
#ifdef DEBUG_I2C
|
||||
printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
|
||||
value);
|
||||
#endif
|
||||
i2c = opaque;
|
||||
switch (addr) {
|
||||
case 0x00:
|
||||
i2c->mdata = value;
|
||||
// i2c_sendbyte(&i2c->mdata);
|
||||
break;
|
||||
case 0x02:
|
||||
i2c->sdata = value;
|
||||
break;
|
||||
case 0x04:
|
||||
i2c->lmadr = value;
|
||||
break;
|
||||
case 0x05:
|
||||
i2c->hmadr = value;
|
||||
break;
|
||||
case 0x06:
|
||||
i2c->cntl = value;
|
||||
break;
|
||||
case 0x07:
|
||||
i2c->mdcntl = value & 0xDF;
|
||||
break;
|
||||
case 0x08:
|
||||
i2c->sts &= ~(value & 0x0A);
|
||||
break;
|
||||
case 0x09:
|
||||
i2c->extsts &= ~(value & 0x8F);
|
||||
break;
|
||||
case 0x0A:
|
||||
i2c->lsadr = value;
|
||||
break;
|
||||
case 0x0B:
|
||||
i2c->hsadr = value;
|
||||
break;
|
||||
case 0x0C:
|
||||
i2c->clkdiv = value;
|
||||
break;
|
||||
case 0x0D:
|
||||
i2c->intrmsk = value;
|
||||
break;
|
||||
case 0x0E:
|
||||
i2c->xfrcnt = value & 0x77;
|
||||
break;
|
||||
case 0x0F:
|
||||
i2c->xtcntlss = value;
|
||||
break;
|
||||
case 0x10:
|
||||
i2c->directcntl = value & 0x7;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t ppc4xx_i2c_readw (void *opaque, hwaddr addr)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
#ifdef DEBUG_I2C
|
||||
printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
|
||||
#endif
|
||||
ret = ppc4xx_i2c_readb(opaque, addr) << 8;
|
||||
ret |= ppc4xx_i2c_readb(opaque, addr + 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ppc4xx_i2c_writew (void *opaque,
|
||||
hwaddr addr, uint32_t value)
|
||||
{
|
||||
#ifdef DEBUG_I2C
|
||||
printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
|
||||
value);
|
||||
#endif
|
||||
ppc4xx_i2c_writeb(opaque, addr, value >> 8);
|
||||
ppc4xx_i2c_writeb(opaque, addr + 1, value);
|
||||
}
|
||||
|
||||
static uint32_t ppc4xx_i2c_readl (void *opaque, hwaddr addr)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
#ifdef DEBUG_I2C
|
||||
printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
|
||||
#endif
|
||||
ret = ppc4xx_i2c_readb(opaque, addr) << 24;
|
||||
ret |= ppc4xx_i2c_readb(opaque, addr + 1) << 16;
|
||||
ret |= ppc4xx_i2c_readb(opaque, addr + 2) << 8;
|
||||
ret |= ppc4xx_i2c_readb(opaque, addr + 3);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ppc4xx_i2c_writel (void *opaque,
|
||||
hwaddr addr, uint32_t value)
|
||||
{
|
||||
#ifdef DEBUG_I2C
|
||||
printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
|
||||
value);
|
||||
#endif
|
||||
ppc4xx_i2c_writeb(opaque, addr, value >> 24);
|
||||
ppc4xx_i2c_writeb(opaque, addr + 1, value >> 16);
|
||||
ppc4xx_i2c_writeb(opaque, addr + 2, value >> 8);
|
||||
ppc4xx_i2c_writeb(opaque, addr + 3, value);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps i2c_ops = {
|
||||
.old_mmio = {
|
||||
.read = { ppc4xx_i2c_readb, ppc4xx_i2c_readw, ppc4xx_i2c_readl, },
|
||||
.write = { ppc4xx_i2c_writeb, ppc4xx_i2c_writew, ppc4xx_i2c_writel, },
|
||||
},
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void ppc4xx_i2c_reset (void *opaque)
|
||||
{
|
||||
ppc4xx_i2c_t *i2c;
|
||||
|
||||
i2c = opaque;
|
||||
i2c->mdata = 0x00;
|
||||
i2c->sdata = 0x00;
|
||||
i2c->cntl = 0x00;
|
||||
i2c->mdcntl = 0x00;
|
||||
i2c->sts = 0x00;
|
||||
i2c->extsts = 0x00;
|
||||
i2c->clkdiv = 0x00;
|
||||
i2c->xfrcnt = 0x00;
|
||||
i2c->directcntl = 0x0F;
|
||||
}
|
||||
|
||||
static void ppc405_i2c_init(hwaddr base, qemu_irq irq)
|
||||
{
|
||||
ppc4xx_i2c_t *i2c;
|
||||
|
||||
i2c = g_malloc0(sizeof(ppc4xx_i2c_t));
|
||||
i2c->irq = irq;
|
||||
#ifdef DEBUG_I2C
|
||||
printf("%s: offset " TARGET_FMT_plx "\n", __func__, base);
|
||||
#endif
|
||||
memory_region_init_io(&i2c->iomem, NULL, &i2c_ops, i2c, "i2c", 0x011);
|
||||
memory_region_add_subregion(get_system_memory(), base, &i2c->iomem);
|
||||
qemu_register_reset(ppc4xx_i2c_reset, i2c);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* General purpose timers */
|
||||
typedef struct ppc4xx_gpt_t ppc4xx_gpt_t;
|
||||
|
@ -1512,268 +1271,6 @@ static void ppc4xx_gpt_init(hwaddr base, qemu_irq irqs[5])
|
|||
qemu_register_reset(ppc4xx_gpt_reset, gpt);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* MAL */
|
||||
enum {
|
||||
MAL0_CFG = 0x180,
|
||||
MAL0_ESR = 0x181,
|
||||
MAL0_IER = 0x182,
|
||||
MAL0_TXCASR = 0x184,
|
||||
MAL0_TXCARR = 0x185,
|
||||
MAL0_TXEOBISR = 0x186,
|
||||
MAL0_TXDEIR = 0x187,
|
||||
MAL0_RXCASR = 0x190,
|
||||
MAL0_RXCARR = 0x191,
|
||||
MAL0_RXEOBISR = 0x192,
|
||||
MAL0_RXDEIR = 0x193,
|
||||
MAL0_TXCTP0R = 0x1A0,
|
||||
MAL0_TXCTP1R = 0x1A1,
|
||||
MAL0_TXCTP2R = 0x1A2,
|
||||
MAL0_TXCTP3R = 0x1A3,
|
||||
MAL0_RXCTP0R = 0x1C0,
|
||||
MAL0_RXCTP1R = 0x1C1,
|
||||
MAL0_RCBS0 = 0x1E0,
|
||||
MAL0_RCBS1 = 0x1E1,
|
||||
};
|
||||
|
||||
typedef struct ppc40x_mal_t ppc40x_mal_t;
|
||||
struct ppc40x_mal_t {
|
||||
qemu_irq irqs[4];
|
||||
uint32_t cfg;
|
||||
uint32_t esr;
|
||||
uint32_t ier;
|
||||
uint32_t txcasr;
|
||||
uint32_t txcarr;
|
||||
uint32_t txeobisr;
|
||||
uint32_t txdeir;
|
||||
uint32_t rxcasr;
|
||||
uint32_t rxcarr;
|
||||
uint32_t rxeobisr;
|
||||
uint32_t rxdeir;
|
||||
uint32_t txctpr[4];
|
||||
uint32_t rxctpr[2];
|
||||
uint32_t rcbs[2];
|
||||
};
|
||||
|
||||
static void ppc40x_mal_reset (void *opaque);
|
||||
|
||||
static uint32_t dcr_read_mal (void *opaque, int dcrn)
|
||||
{
|
||||
ppc40x_mal_t *mal;
|
||||
uint32_t ret;
|
||||
|
||||
mal = opaque;
|
||||
switch (dcrn) {
|
||||
case MAL0_CFG:
|
||||
ret = mal->cfg;
|
||||
break;
|
||||
case MAL0_ESR:
|
||||
ret = mal->esr;
|
||||
break;
|
||||
case MAL0_IER:
|
||||
ret = mal->ier;
|
||||
break;
|
||||
case MAL0_TXCASR:
|
||||
ret = mal->txcasr;
|
||||
break;
|
||||
case MAL0_TXCARR:
|
||||
ret = mal->txcarr;
|
||||
break;
|
||||
case MAL0_TXEOBISR:
|
||||
ret = mal->txeobisr;
|
||||
break;
|
||||
case MAL0_TXDEIR:
|
||||
ret = mal->txdeir;
|
||||
break;
|
||||
case MAL0_RXCASR:
|
||||
ret = mal->rxcasr;
|
||||
break;
|
||||
case MAL0_RXCARR:
|
||||
ret = mal->rxcarr;
|
||||
break;
|
||||
case MAL0_RXEOBISR:
|
||||
ret = mal->rxeobisr;
|
||||
break;
|
||||
case MAL0_RXDEIR:
|
||||
ret = mal->rxdeir;
|
||||
break;
|
||||
case MAL0_TXCTP0R:
|
||||
ret = mal->txctpr[0];
|
||||
break;
|
||||
case MAL0_TXCTP1R:
|
||||
ret = mal->txctpr[1];
|
||||
break;
|
||||
case MAL0_TXCTP2R:
|
||||
ret = mal->txctpr[2];
|
||||
break;
|
||||
case MAL0_TXCTP3R:
|
||||
ret = mal->txctpr[3];
|
||||
break;
|
||||
case MAL0_RXCTP0R:
|
||||
ret = mal->rxctpr[0];
|
||||
break;
|
||||
case MAL0_RXCTP1R:
|
||||
ret = mal->rxctpr[1];
|
||||
break;
|
||||
case MAL0_RCBS0:
|
||||
ret = mal->rcbs[0];
|
||||
break;
|
||||
case MAL0_RCBS1:
|
||||
ret = mal->rcbs[1];
|
||||
break;
|
||||
default:
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dcr_write_mal (void *opaque, int dcrn, uint32_t val)
|
||||
{
|
||||
ppc40x_mal_t *mal;
|
||||
int idx;
|
||||
|
||||
mal = opaque;
|
||||
switch (dcrn) {
|
||||
case MAL0_CFG:
|
||||
if (val & 0x80000000)
|
||||
ppc40x_mal_reset(mal);
|
||||
mal->cfg = val & 0x00FFC087;
|
||||
break;
|
||||
case MAL0_ESR:
|
||||
/* Read/clear */
|
||||
mal->esr &= ~val;
|
||||
break;
|
||||
case MAL0_IER:
|
||||
mal->ier = val & 0x0000001F;
|
||||
break;
|
||||
case MAL0_TXCASR:
|
||||
mal->txcasr = val & 0xF0000000;
|
||||
break;
|
||||
case MAL0_TXCARR:
|
||||
mal->txcarr = val & 0xF0000000;
|
||||
break;
|
||||
case MAL0_TXEOBISR:
|
||||
/* Read/clear */
|
||||
mal->txeobisr &= ~val;
|
||||
break;
|
||||
case MAL0_TXDEIR:
|
||||
/* Read/clear */
|
||||
mal->txdeir &= ~val;
|
||||
break;
|
||||
case MAL0_RXCASR:
|
||||
mal->rxcasr = val & 0xC0000000;
|
||||
break;
|
||||
case MAL0_RXCARR:
|
||||
mal->rxcarr = val & 0xC0000000;
|
||||
break;
|
||||
case MAL0_RXEOBISR:
|
||||
/* Read/clear */
|
||||
mal->rxeobisr &= ~val;
|
||||
break;
|
||||
case MAL0_RXDEIR:
|
||||
/* Read/clear */
|
||||
mal->rxdeir &= ~val;
|
||||
break;
|
||||
case MAL0_TXCTP0R:
|
||||
idx = 0;
|
||||
goto update_tx_ptr;
|
||||
case MAL0_TXCTP1R:
|
||||
idx = 1;
|
||||
goto update_tx_ptr;
|
||||
case MAL0_TXCTP2R:
|
||||
idx = 2;
|
||||
goto update_tx_ptr;
|
||||
case MAL0_TXCTP3R:
|
||||
idx = 3;
|
||||
update_tx_ptr:
|
||||
mal->txctpr[idx] = val;
|
||||
break;
|
||||
case MAL0_RXCTP0R:
|
||||
idx = 0;
|
||||
goto update_rx_ptr;
|
||||
case MAL0_RXCTP1R:
|
||||
idx = 1;
|
||||
update_rx_ptr:
|
||||
mal->rxctpr[idx] = val;
|
||||
break;
|
||||
case MAL0_RCBS0:
|
||||
idx = 0;
|
||||
goto update_rx_size;
|
||||
case MAL0_RCBS1:
|
||||
idx = 1;
|
||||
update_rx_size:
|
||||
mal->rcbs[idx] = val & 0x000000FF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void ppc40x_mal_reset (void *opaque)
|
||||
{
|
||||
ppc40x_mal_t *mal;
|
||||
|
||||
mal = opaque;
|
||||
mal->cfg = 0x0007C000;
|
||||
mal->esr = 0x00000000;
|
||||
mal->ier = 0x00000000;
|
||||
mal->rxcasr = 0x00000000;
|
||||
mal->rxdeir = 0x00000000;
|
||||
mal->rxeobisr = 0x00000000;
|
||||
mal->txcasr = 0x00000000;
|
||||
mal->txdeir = 0x00000000;
|
||||
mal->txeobisr = 0x00000000;
|
||||
}
|
||||
|
||||
static void ppc405_mal_init(CPUPPCState *env, qemu_irq irqs[4])
|
||||
{
|
||||
ppc40x_mal_t *mal;
|
||||
int i;
|
||||
|
||||
mal = g_malloc0(sizeof(ppc40x_mal_t));
|
||||
for (i = 0; i < 4; i++)
|
||||
mal->irqs[i] = irqs[i];
|
||||
qemu_register_reset(&ppc40x_mal_reset, mal);
|
||||
ppc_dcr_register(env, MAL0_CFG,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
ppc_dcr_register(env, MAL0_ESR,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
ppc_dcr_register(env, MAL0_IER,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
ppc_dcr_register(env, MAL0_TXCASR,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
ppc_dcr_register(env, MAL0_TXCARR,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
ppc_dcr_register(env, MAL0_TXEOBISR,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
ppc_dcr_register(env, MAL0_TXDEIR,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
ppc_dcr_register(env, MAL0_RXCASR,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
ppc_dcr_register(env, MAL0_RXCARR,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
ppc_dcr_register(env, MAL0_RXEOBISR,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
ppc_dcr_register(env, MAL0_RXDEIR,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
ppc_dcr_register(env, MAL0_TXCTP0R,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
ppc_dcr_register(env, MAL0_TXCTP1R,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
ppc_dcr_register(env, MAL0_TXCTP2R,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
ppc_dcr_register(env, MAL0_TXCTP3R,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
ppc_dcr_register(env, MAL0_RXCTP0R,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
ppc_dcr_register(env, MAL0_RXCTP1R,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
ppc_dcr_register(env, MAL0_RCBS0,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
ppc_dcr_register(env, MAL0_RCBS1,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* SPR */
|
||||
void ppc40x_core_reset(PowerPCCPU *cpu)
|
||||
|
@ -2167,7 +1664,7 @@ CPUPPCState *ppc405cr_init(MemoryRegion *address_space_mem,
|
|||
DEVICE_BIG_ENDIAN);
|
||||
}
|
||||
/* IIC controller */
|
||||
ppc405_i2c_init(0xef600500, pic[2]);
|
||||
sysbus_create_simple(TYPE_PPC4xx_I2C, 0xef600500, pic[2]);
|
||||
/* GPIO */
|
||||
ppc405_gpio_init(0xef600700);
|
||||
/* CPU control */
|
||||
|
@ -2514,7 +2011,7 @@ CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem,
|
|||
dma_irqs[3] = pic[8];
|
||||
ppc405_dma_init(env, dma_irqs);
|
||||
/* IIC controller */
|
||||
ppc405_i2c_init(0xef600500, pic[2]);
|
||||
sysbus_create_simple(TYPE_PPC4xx_I2C, 0xef600500, pic[2]);
|
||||
/* GPIO */
|
||||
ppc405_gpio_init(0xef600700);
|
||||
/* Serial ports */
|
||||
|
@ -2544,7 +2041,7 @@ CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem,
|
|||
mal_irqs[1] = pic[12];
|
||||
mal_irqs[2] = pic[13];
|
||||
mal_irqs[3] = pic[14];
|
||||
ppc405_mal_init(env, mal_irqs);
|
||||
ppc4xx_mal_init(env, 4, 2, mal_irqs);
|
||||
/* Ethernet */
|
||||
/* Uses pic[9], pic[15], pic[17] */
|
||||
/* CPU control */
|
||||
|
|
|
@ -734,3 +734,230 @@ ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks,
|
|||
|
||||
return ram_size;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* MAL */
|
||||
|
||||
enum {
|
||||
MAL0_CFG = 0x180,
|
||||
MAL0_ESR = 0x181,
|
||||
MAL0_IER = 0x182,
|
||||
MAL0_TXCASR = 0x184,
|
||||
MAL0_TXCARR = 0x185,
|
||||
MAL0_TXEOBISR = 0x186,
|
||||
MAL0_TXDEIR = 0x187,
|
||||
MAL0_RXCASR = 0x190,
|
||||
MAL0_RXCARR = 0x191,
|
||||
MAL0_RXEOBISR = 0x192,
|
||||
MAL0_RXDEIR = 0x193,
|
||||
MAL0_TXCTP0R = 0x1A0,
|
||||
MAL0_RXCTP0R = 0x1C0,
|
||||
MAL0_RCBS0 = 0x1E0,
|
||||
MAL0_RCBS1 = 0x1E1,
|
||||
};
|
||||
|
||||
typedef struct ppc4xx_mal_t ppc4xx_mal_t;
|
||||
struct ppc4xx_mal_t {
|
||||
qemu_irq irqs[4];
|
||||
uint32_t cfg;
|
||||
uint32_t esr;
|
||||
uint32_t ier;
|
||||
uint32_t txcasr;
|
||||
uint32_t txcarr;
|
||||
uint32_t txeobisr;
|
||||
uint32_t txdeir;
|
||||
uint32_t rxcasr;
|
||||
uint32_t rxcarr;
|
||||
uint32_t rxeobisr;
|
||||
uint32_t rxdeir;
|
||||
uint32_t *txctpr;
|
||||
uint32_t *rxctpr;
|
||||
uint32_t *rcbs;
|
||||
uint8_t txcnum;
|
||||
uint8_t rxcnum;
|
||||
};
|
||||
|
||||
static void ppc4xx_mal_reset(void *opaque)
|
||||
{
|
||||
ppc4xx_mal_t *mal;
|
||||
|
||||
mal = opaque;
|
||||
mal->cfg = 0x0007C000;
|
||||
mal->esr = 0x00000000;
|
||||
mal->ier = 0x00000000;
|
||||
mal->rxcasr = 0x00000000;
|
||||
mal->rxdeir = 0x00000000;
|
||||
mal->rxeobisr = 0x00000000;
|
||||
mal->txcasr = 0x00000000;
|
||||
mal->txdeir = 0x00000000;
|
||||
mal->txeobisr = 0x00000000;
|
||||
}
|
||||
|
||||
static uint32_t dcr_read_mal(void *opaque, int dcrn)
|
||||
{
|
||||
ppc4xx_mal_t *mal;
|
||||
uint32_t ret;
|
||||
|
||||
mal = opaque;
|
||||
switch (dcrn) {
|
||||
case MAL0_CFG:
|
||||
ret = mal->cfg;
|
||||
break;
|
||||
case MAL0_ESR:
|
||||
ret = mal->esr;
|
||||
break;
|
||||
case MAL0_IER:
|
||||
ret = mal->ier;
|
||||
break;
|
||||
case MAL0_TXCASR:
|
||||
ret = mal->txcasr;
|
||||
break;
|
||||
case MAL0_TXCARR:
|
||||
ret = mal->txcarr;
|
||||
break;
|
||||
case MAL0_TXEOBISR:
|
||||
ret = mal->txeobisr;
|
||||
break;
|
||||
case MAL0_TXDEIR:
|
||||
ret = mal->txdeir;
|
||||
break;
|
||||
case MAL0_RXCASR:
|
||||
ret = mal->rxcasr;
|
||||
break;
|
||||
case MAL0_RXCARR:
|
||||
ret = mal->rxcarr;
|
||||
break;
|
||||
case MAL0_RXEOBISR:
|
||||
ret = mal->rxeobisr;
|
||||
break;
|
||||
case MAL0_RXDEIR:
|
||||
ret = mal->rxdeir;
|
||||
break;
|
||||
default:
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
if (dcrn >= MAL0_TXCTP0R && dcrn < MAL0_TXCTP0R + mal->txcnum) {
|
||||
ret = mal->txctpr[dcrn - MAL0_TXCTP0R];
|
||||
}
|
||||
if (dcrn >= MAL0_RXCTP0R && dcrn < MAL0_RXCTP0R + mal->rxcnum) {
|
||||
ret = mal->rxctpr[dcrn - MAL0_RXCTP0R];
|
||||
}
|
||||
if (dcrn >= MAL0_RCBS0 && dcrn < MAL0_RCBS0 + mal->rxcnum) {
|
||||
ret = mal->rcbs[dcrn - MAL0_RCBS0];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dcr_write_mal(void *opaque, int dcrn, uint32_t val)
|
||||
{
|
||||
ppc4xx_mal_t *mal;
|
||||
|
||||
mal = opaque;
|
||||
switch (dcrn) {
|
||||
case MAL0_CFG:
|
||||
if (val & 0x80000000) {
|
||||
ppc4xx_mal_reset(mal);
|
||||
}
|
||||
mal->cfg = val & 0x00FFC087;
|
||||
break;
|
||||
case MAL0_ESR:
|
||||
/* Read/clear */
|
||||
mal->esr &= ~val;
|
||||
break;
|
||||
case MAL0_IER:
|
||||
mal->ier = val & 0x0000001F;
|
||||
break;
|
||||
case MAL0_TXCASR:
|
||||
mal->txcasr = val & 0xF0000000;
|
||||
break;
|
||||
case MAL0_TXCARR:
|
||||
mal->txcarr = val & 0xF0000000;
|
||||
break;
|
||||
case MAL0_TXEOBISR:
|
||||
/* Read/clear */
|
||||
mal->txeobisr &= ~val;
|
||||
break;
|
||||
case MAL0_TXDEIR:
|
||||
/* Read/clear */
|
||||
mal->txdeir &= ~val;
|
||||
break;
|
||||
case MAL0_RXCASR:
|
||||
mal->rxcasr = val & 0xC0000000;
|
||||
break;
|
||||
case MAL0_RXCARR:
|
||||
mal->rxcarr = val & 0xC0000000;
|
||||
break;
|
||||
case MAL0_RXEOBISR:
|
||||
/* Read/clear */
|
||||
mal->rxeobisr &= ~val;
|
||||
break;
|
||||
case MAL0_RXDEIR:
|
||||
/* Read/clear */
|
||||
mal->rxdeir &= ~val;
|
||||
break;
|
||||
}
|
||||
if (dcrn >= MAL0_TXCTP0R && dcrn < MAL0_TXCTP0R + mal->txcnum) {
|
||||
mal->txctpr[dcrn - MAL0_TXCTP0R] = val;
|
||||
}
|
||||
if (dcrn >= MAL0_RXCTP0R && dcrn < MAL0_RXCTP0R + mal->rxcnum) {
|
||||
mal->rxctpr[dcrn - MAL0_RXCTP0R] = val;
|
||||
}
|
||||
if (dcrn >= MAL0_RCBS0 && dcrn < MAL0_RCBS0 + mal->rxcnum) {
|
||||
mal->rcbs[dcrn - MAL0_RCBS0] = val & 0x000000FF;
|
||||
}
|
||||
}
|
||||
|
||||
void ppc4xx_mal_init(CPUPPCState *env, uint8_t txcnum, uint8_t rxcnum,
|
||||
qemu_irq irqs[4])
|
||||
{
|
||||
ppc4xx_mal_t *mal;
|
||||
int i;
|
||||
|
||||
assert(txcnum <= 32 && rxcnum <= 32);
|
||||
mal = g_malloc0(sizeof(*mal));
|
||||
mal->txcnum = txcnum;
|
||||
mal->rxcnum = rxcnum;
|
||||
mal->txctpr = g_new0(uint32_t, txcnum);
|
||||
mal->rxctpr = g_new0(uint32_t, rxcnum);
|
||||
mal->rcbs = g_new0(uint32_t, rxcnum);
|
||||
for (i = 0; i < 4; i++) {
|
||||
mal->irqs[i] = irqs[i];
|
||||
}
|
||||
qemu_register_reset(&ppc4xx_mal_reset, mal);
|
||||
ppc_dcr_register(env, MAL0_CFG,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
ppc_dcr_register(env, MAL0_ESR,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
ppc_dcr_register(env, MAL0_IER,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
ppc_dcr_register(env, MAL0_TXCASR,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
ppc_dcr_register(env, MAL0_TXCARR,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
ppc_dcr_register(env, MAL0_TXEOBISR,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
ppc_dcr_register(env, MAL0_TXDEIR,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
ppc_dcr_register(env, MAL0_RXCASR,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
ppc_dcr_register(env, MAL0_RXCARR,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
ppc_dcr_register(env, MAL0_RXEOBISR,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
ppc_dcr_register(env, MAL0_RXDEIR,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
for (i = 0; i < txcnum; i++) {
|
||||
ppc_dcr_register(env, MAL0_TXCTP0R + i,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
}
|
||||
for (i = 0; i < rxcnum; i++) {
|
||||
ppc_dcr_register(env, MAL0_RXCTP0R + i,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
}
|
||||
for (i = 0; i < rxcnum; i++) {
|
||||
ppc_dcr_register(env, MAL0_RCBS0 + i,
|
||||
mal, &dcr_read_mal, &dcr_write_mal);
|
||||
}
|
||||
}
|
||||
|
|
166
hw/ppc/spapr.c
166
hw/ppc/spapr.c
|
@ -26,6 +26,7 @@
|
|||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/numa.h"
|
||||
#include "hw/hw.h"
|
||||
|
@ -208,7 +209,7 @@ static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu,
|
|||
int i, ret = 0;
|
||||
uint32_t servers_prop[smt_threads];
|
||||
uint32_t gservers_prop[smt_threads * 2];
|
||||
int index = ppc_get_vcpu_dt_id(cpu);
|
||||
int index = spapr_vcpu_id(cpu);
|
||||
|
||||
if (cpu->compat_pvr) {
|
||||
ret = fdt_setprop_cell(fdt, offset, "cpu-version", cpu->compat_pvr);
|
||||
|
@ -237,7 +238,7 @@ static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu,
|
|||
|
||||
static int spapr_fixup_cpu_numa_dt(void *fdt, int offset, PowerPCCPU *cpu)
|
||||
{
|
||||
int index = ppc_get_vcpu_dt_id(cpu);
|
||||
int index = spapr_vcpu_id(cpu);
|
||||
uint32_t associativity[] = {cpu_to_be32(0x5),
|
||||
cpu_to_be32(0x0),
|
||||
cpu_to_be32(0x0),
|
||||
|
@ -341,7 +342,7 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPRMachineState *spapr)
|
|||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
DeviceClass *dc = DEVICE_GET_CLASS(cs);
|
||||
int index = ppc_get_vcpu_dt_id(cpu);
|
||||
int index = spapr_vcpu_id(cpu);
|
||||
int compat_smt = MIN(smp_threads, ppc_compat_max_threads(cpu));
|
||||
|
||||
if ((index % smt) != 0) {
|
||||
|
@ -493,7 +494,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
|
|||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
|
||||
int index = ppc_get_vcpu_dt_id(cpu);
|
||||
int index = spapr_vcpu_id(cpu);
|
||||
uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
|
||||
0xffffffff, 0xffffffff};
|
||||
uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq()
|
||||
|
@ -626,7 +627,7 @@ static void spapr_populate_cpus_dt_node(void *fdt, sPAPRMachineState *spapr)
|
|||
*/
|
||||
CPU_FOREACH_REVERSE(cs) {
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
int index = ppc_get_vcpu_dt_id(cpu);
|
||||
int index = spapr_vcpu_id(cpu);
|
||||
DeviceClass *dc = DEVICE_GET_CLASS(cs);
|
||||
int offset;
|
||||
|
||||
|
@ -790,6 +791,26 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static bool spapr_hotplugged_dev_before_cas(void)
|
||||
{
|
||||
Object *drc_container, *obj;
|
||||
ObjectProperty *prop;
|
||||
ObjectPropertyIterator iter;
|
||||
|
||||
drc_container = container_get(object_get_root(), "/dr-connector");
|
||||
object_property_iter_init(&iter, drc_container);
|
||||
while ((prop = object_property_iter_next(&iter))) {
|
||||
if (!strstart(prop->type, "link<", NULL)) {
|
||||
continue;
|
||||
}
|
||||
obj = object_property_get_link(drc_container, prop->name, NULL);
|
||||
if (spapr_drc_needed(obj)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int spapr_h_cas_compose_response(sPAPRMachineState *spapr,
|
||||
target_ulong addr, target_ulong size,
|
||||
sPAPROptionVector *ov5_updates)
|
||||
|
@ -797,9 +818,13 @@ int spapr_h_cas_compose_response(sPAPRMachineState *spapr,
|
|||
void *fdt, *fdt_skel;
|
||||
sPAPRDeviceTreeUpdateHeader hdr = { .version_id = 1 };
|
||||
|
||||
if (spapr_hotplugged_dev_before_cas()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
size -= sizeof(hdr);
|
||||
|
||||
/* Create sceleton */
|
||||
/* Create skeleton */
|
||||
fdt_skel = g_malloc0(size);
|
||||
_FDT((fdt_create(fdt_skel, size)));
|
||||
_FDT((fdt_begin_node(fdt_skel, "")));
|
||||
|
@ -1392,6 +1417,7 @@ static void ppc_spapr_reset(void)
|
|||
}
|
||||
|
||||
qemu_devices_reset();
|
||||
spapr_clear_pending_events(spapr);
|
||||
|
||||
/*
|
||||
* We place the device tree and RTAS just below either the top of the RMA,
|
||||
|
@ -2140,6 +2166,61 @@ static void spapr_init_cpus(sPAPRMachineState *spapr)
|
|||
g_free(type);
|
||||
}
|
||||
|
||||
static void spapr_set_vsmt_mode(sPAPRMachineState *spapr, Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
bool vsmt_user = !!spapr->vsmt;
|
||||
int kvm_smt = kvmppc_smt_threads();
|
||||
int ret;
|
||||
|
||||
if (!kvm_enabled() && (smp_threads > 1)) {
|
||||
error_setg(&local_err, "TCG cannot support more than 1 thread/core "
|
||||
"on a pseries machine");
|
||||
goto out;
|
||||
}
|
||||
if (!is_power_of_2(smp_threads)) {
|
||||
error_setg(&local_err, "Cannot support %d threads/core on a pseries "
|
||||
"machine because it must be a power of 2", smp_threads);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Detemine the VSMT mode to use: */
|
||||
if (vsmt_user) {
|
||||
if (spapr->vsmt < smp_threads) {
|
||||
error_setg(&local_err, "Cannot support VSMT mode %d"
|
||||
" because it must be >= threads/core (%d)",
|
||||
spapr->vsmt, smp_threads);
|
||||
goto out;
|
||||
}
|
||||
/* In this case, spapr->vsmt has been set by the command line */
|
||||
} else {
|
||||
/* Choose a VSMT mode that may be higher than necessary but is
|
||||
* likely to be compatible with hosts that don't have VSMT. */
|
||||
spapr->vsmt = MAX(kvm_smt, smp_threads);
|
||||
}
|
||||
|
||||
/* KVM: If necessary, set the SMT mode: */
|
||||
if (kvm_enabled() && (spapr->vsmt != kvm_smt)) {
|
||||
ret = kvmppc_set_smt_threads(spapr->vsmt);
|
||||
if (ret) {
|
||||
error_setg(&local_err,
|
||||
"Failed to set KVM's VSMT mode to %d (errno %d)",
|
||||
spapr->vsmt, ret);
|
||||
if (!vsmt_user) {
|
||||
error_append_hint(&local_err, "On PPC, a VM with %d threads/"
|
||||
"core on a host with %d threads/core requires "
|
||||
" the use of VSMT mode %d.\n",
|
||||
smp_threads, kvm_smt, spapr->vsmt);
|
||||
}
|
||||
kvmppc_hint_smt_possible(&local_err);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
/* else TCG: nothing to do currently */
|
||||
out:
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
/* pSeries LPAR / sPAPR hardware init */
|
||||
static void ppc_spapr_init(MachineState *machine)
|
||||
{
|
||||
|
@ -2272,6 +2353,8 @@ static void ppc_spapr_init(MachineState *machine)
|
|||
|
||||
spapr_cpu_parse_features(spapr);
|
||||
|
||||
spapr_set_vsmt_mode(spapr, &error_fatal);
|
||||
|
||||
spapr_init_cpus(spapr);
|
||||
|
||||
if (kvm_enabled()) {
|
||||
|
@ -2656,6 +2739,18 @@ static void spapr_set_resize_hpt(Object *obj, const char *value, Error **errp)
|
|||
}
|
||||
}
|
||||
|
||||
static void spapr_get_vsmt(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
visit_type_uint32(v, name, (uint32_t *)opaque, errp);
|
||||
}
|
||||
|
||||
static void spapr_set_vsmt(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
visit_type_uint32(v, name, (uint32_t *)opaque, errp);
|
||||
}
|
||||
|
||||
static void spapr_machine_initfn(Object *obj)
|
||||
{
|
||||
sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
|
||||
|
@ -2686,6 +2781,11 @@ static void spapr_machine_initfn(Object *obj)
|
|||
object_property_set_description(obj, "resize-hpt",
|
||||
"Resizing of the Hash Page Table (enabled, disabled, required)",
|
||||
NULL);
|
||||
object_property_add(obj, "vsmt", "uint32", spapr_get_vsmt,
|
||||
spapr_set_vsmt, NULL, &spapr->vsmt, &error_abort);
|
||||
object_property_set_description(obj, "vsmt",
|
||||
"Virtual SMT: KVM behaves as if this were"
|
||||
" the host's SMT mode", &error_abort);
|
||||
}
|
||||
|
||||
static void spapr_machine_finalizefn(Object *obj)
|
||||
|
@ -3000,7 +3100,7 @@ static void *spapr_populate_hotplug_cpu_dt(CPUState *cs, int *fdt_offset,
|
|||
{
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
DeviceClass *dc = DEVICE_GET_CLASS(cs);
|
||||
int id = ppc_get_vcpu_dt_id(cpu);
|
||||
int id = spapr_vcpu_id(cpu);
|
||||
void *fdt;
|
||||
int offset, fdt_size;
|
||||
char *nodename;
|
||||
|
@ -3408,9 +3508,9 @@ static void spapr_ics_resend(XICSFabric *dev)
|
|||
ics_resend(spapr->ics);
|
||||
}
|
||||
|
||||
static ICPState *spapr_icp_get(XICSFabric *xi, int cpu_dt_id)
|
||||
static ICPState *spapr_icp_get(XICSFabric *xi, int vcpu_id)
|
||||
{
|
||||
PowerPCCPU *cpu = ppc_get_vcpu_by_dt_id(cpu_dt_id);
|
||||
PowerPCCPU *cpu = spapr_find_cpu(vcpu_id);
|
||||
|
||||
return cpu ? ICP(cpu->intc) : NULL;
|
||||
}
|
||||
|
@ -3430,6 +3530,32 @@ static void spapr_pic_print_info(InterruptStatsProvider *obj,
|
|||
ics_pic_print_info(spapr->ics, mon);
|
||||
}
|
||||
|
||||
int spapr_vcpu_id(PowerPCCPU *cpu)
|
||||
{
|
||||
CPUState *cs = CPU(cpu);
|
||||
|
||||
if (kvm_enabled()) {
|
||||
return kvm_arch_vcpu_id(cs);
|
||||
} else {
|
||||
return cs->cpu_index;
|
||||
}
|
||||
}
|
||||
|
||||
PowerPCCPU *spapr_find_cpu(int vcpu_id)
|
||||
{
|
||||
CPUState *cs;
|
||||
|
||||
CPU_FOREACH(cs) {
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
|
||||
if (spapr_vcpu_id(cpu) == vcpu_id) {
|
||||
return cpu;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void spapr_machine_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
@ -3537,19 +3663,37 @@ static const TypeInfo spapr_machine_info = {
|
|||
} \
|
||||
type_init(spapr_machine_register_##suffix)
|
||||
|
||||
/*
|
||||
* pseries-2.11
|
||||
*/
|
||||
static void spapr_machine_2_11_instance_options(MachineState *machine)
|
||||
{
|
||||
}
|
||||
|
||||
static void spapr_machine_2_11_class_options(MachineClass *mc)
|
||||
{
|
||||
/* Defaults for the latest behaviour inherited from the base class */
|
||||
}
|
||||
|
||||
DEFINE_SPAPR_MACHINE(2_11, "2.11", true);
|
||||
|
||||
/*
|
||||
* pseries-2.10
|
||||
*/
|
||||
#define SPAPR_COMPAT_2_10 \
|
||||
HW_COMPAT_2_10 \
|
||||
|
||||
static void spapr_machine_2_10_instance_options(MachineState *machine)
|
||||
{
|
||||
}
|
||||
|
||||
static void spapr_machine_2_10_class_options(MachineClass *mc)
|
||||
{
|
||||
/* Defaults for the latest behaviour inherited from the base class */
|
||||
spapr_machine_2_11_class_options(mc);
|
||||
SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_10);
|
||||
}
|
||||
|
||||
DEFINE_SPAPR_MACHINE(2_10, "2.10", true);
|
||||
DEFINE_SPAPR_MACHINE(2_10, "2.10", false);
|
||||
|
||||
/*
|
||||
* pseries-2.9
|
||||
|
|
|
@ -130,8 +130,10 @@ char *spapr_get_cpu_core_type(const char *model)
|
|||
{
|
||||
char *core_type;
|
||||
gchar **model_pieces = g_strsplit(model, ",", 2);
|
||||
gchar *cpu_model = g_ascii_strdown(model_pieces[0], -1);
|
||||
g_strfreev(model_pieces);
|
||||
|
||||
core_type = g_strdup_printf("%s-%s", model_pieces[0], TYPE_SPAPR_CPU_CORE);
|
||||
core_type = g_strdup_printf("%s-" TYPE_SPAPR_CPU_CORE, cpu_model);
|
||||
|
||||
/* Check whether it exists or whether we have to look up an alias name */
|
||||
if (!object_class_by_name(core_type)) {
|
||||
|
@ -139,13 +141,13 @@ char *spapr_get_cpu_core_type(const char *model)
|
|||
|
||||
g_free(core_type);
|
||||
core_type = NULL;
|
||||
realmodel = ppc_cpu_lookup_alias(model_pieces[0]);
|
||||
realmodel = ppc_cpu_lookup_alias(cpu_model);
|
||||
if (realmodel) {
|
||||
core_type = spapr_get_cpu_core_type(realmodel);
|
||||
}
|
||||
}
|
||||
g_free(cpu_model);
|
||||
|
||||
g_strfreev(model_pieces);
|
||||
return core_type;
|
||||
}
|
||||
|
||||
|
@ -211,6 +213,7 @@ error:
|
|||
|
||||
static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
|
||||
sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
|
||||
sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(dev));
|
||||
CPUCore *cc = CPU_CORE(OBJECT(dev));
|
||||
|
@ -220,6 +223,11 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
|
|||
void *obj;
|
||||
int i, j;
|
||||
|
||||
if (!object_dynamic_cast(qdev_get_machine(), TYPE_SPAPR_MACHINE)) {
|
||||
error_setg(errp, "spapr-cpu-core needs a pseries machine");
|
||||
return;
|
||||
}
|
||||
|
||||
sc->threads = g_malloc0(size * cc->nr_threads);
|
||||
for (i = 0; i < cc->nr_threads; i++) {
|
||||
char id[32];
|
||||
|
@ -232,6 +240,16 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
|
|||
cs = CPU(obj);
|
||||
cpu = POWERPC_CPU(cs);
|
||||
cs->cpu_index = cc->core_id + i;
|
||||
cpu->vcpu_id = (cc->core_id * spapr->vsmt / smp_threads) + i;
|
||||
if (kvm_enabled() && !kvm_vcpu_id_is_valid(cpu->vcpu_id)) {
|
||||
error_setg(&local_err, "Can't create CPU with id %d in KVM",
|
||||
cpu->vcpu_id);
|
||||
error_append_hint(&local_err, "Adjust the number of cpus to %d "
|
||||
"or try to raise the number of threads per core\n",
|
||||
cpu->vcpu_id * smp_threads / spapr->vsmt);
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
||||
/* Set NUMA node for the threads belonged to core */
|
||||
cpu->node_id = sc->node_id;
|
||||
|
@ -268,31 +286,29 @@ static const char *spapr_core_models[] = {
|
|||
"970_v2.2",
|
||||
|
||||
/* 970MP variants */
|
||||
"970MP_v1.0",
|
||||
"970mp_v1.0",
|
||||
"970MP_v1.1",
|
||||
"970mp_v1.1",
|
||||
|
||||
/* POWER5+ */
|
||||
"POWER5+_v2.1",
|
||||
"power5+_v2.1",
|
||||
|
||||
/* POWER7 */
|
||||
"POWER7_v2.3",
|
||||
"power7_v2.3",
|
||||
|
||||
/* POWER7+ */
|
||||
"POWER7+_v2.1",
|
||||
"power7+_v2.1",
|
||||
|
||||
/* POWER8 */
|
||||
"POWER8_v2.0",
|
||||
"power8_v2.0",
|
||||
|
||||
/* POWER8E */
|
||||
"POWER8E_v2.1",
|
||||
"power8e_v2.1",
|
||||
|
||||
/* POWER8NVL */
|
||||
"POWER8NVL_v1.0",
|
||||
"power8nvl_v1.0",
|
||||
|
||||
/* POWER9 */
|
||||
"POWER9_v1.0",
|
||||
"power9_v1.0",
|
||||
};
|
||||
|
||||
static Property spapr_cpu_core_properties[] = {
|
||||
|
|
|
@ -460,14 +460,13 @@ static void drc_reset(void *opaque)
|
|||
spapr_drc_reset(SPAPR_DR_CONNECTOR(opaque));
|
||||
}
|
||||
|
||||
static bool spapr_drc_needed(void *opaque)
|
||||
bool spapr_drc_needed(void *opaque)
|
||||
{
|
||||
sPAPRDRConnector *drc = (sPAPRDRConnector *)opaque;
|
||||
sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
|
||||
sPAPRDREntitySense value = drck->dr_entity_sense(drc);
|
||||
|
||||
/* If no dev is plugged in there is no need to migrate the DRC state */
|
||||
if (value != SPAPR_DR_ENTITY_SENSE_PRESENT) {
|
||||
if (!drc->dev) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -493,7 +492,7 @@ static void realize(DeviceState *d, Error **errp)
|
|||
{
|
||||
sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(d);
|
||||
Object *root_container;
|
||||
char link_name[256];
|
||||
gchar *link_name;
|
||||
gchar *child_name;
|
||||
Error *err = NULL;
|
||||
|
||||
|
@ -506,12 +505,13 @@ static void realize(DeviceState *d, Error **errp)
|
|||
* existing in the composition tree
|
||||
*/
|
||||
root_container = container_get(object_get_root(), DRC_CONTAINER_PATH);
|
||||
snprintf(link_name, sizeof(link_name), "%x", spapr_drc_index(drc));
|
||||
link_name = g_strdup_printf("%x", spapr_drc_index(drc));
|
||||
child_name = object_get_canonical_path_component(OBJECT(drc));
|
||||
trace_spapr_drc_realize_child(spapr_drc_index(drc), child_name);
|
||||
object_property_add_alias(root_container, link_name,
|
||||
drc->owner, child_name, &err);
|
||||
g_free(child_name);
|
||||
g_free(link_name);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
|
@ -526,14 +526,15 @@ static void unrealize(DeviceState *d, Error **errp)
|
|||
{
|
||||
sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(d);
|
||||
Object *root_container;
|
||||
char name[256];
|
||||
gchar *name;
|
||||
|
||||
trace_spapr_drc_unrealize(spapr_drc_index(drc));
|
||||
qemu_unregister_reset(drc_reset, drc);
|
||||
vmstate_unregister(DEVICE(drc), &vmstate_spapr_drc, drc);
|
||||
root_container = container_get(object_get_root(), DRC_CONTAINER_PATH);
|
||||
snprintf(name, sizeof(name), "%x", spapr_drc_index(drc));
|
||||
name = g_strdup_printf("%x", spapr_drc_index(drc));
|
||||
object_property_del(root_container, name, errp);
|
||||
g_free(name);
|
||||
}
|
||||
|
||||
sPAPRDRConnector *spapr_dr_connector_new(Object *owner, const char *type,
|
||||
|
@ -547,6 +548,7 @@ sPAPRDRConnector *spapr_dr_connector_new(Object *owner, const char *type,
|
|||
prop_name = g_strdup_printf("dr-connector[%"PRIu32"]",
|
||||
spapr_drc_index(drc));
|
||||
object_property_add_child(owner, prop_name, OBJECT(drc), &error_abort);
|
||||
object_unref(OBJECT(drc));
|
||||
object_property_set_bool(OBJECT(drc), true, "realized", NULL);
|
||||
g_free(prop_name);
|
||||
|
||||
|
@ -629,12 +631,28 @@ static void realize_physical(DeviceState *d, Error **errp)
|
|||
qemu_register_reset(drc_physical_reset, drcp);
|
||||
}
|
||||
|
||||
static void unrealize_physical(DeviceState *d, Error **errp)
|
||||
{
|
||||
sPAPRDRCPhysical *drcp = SPAPR_DRC_PHYSICAL(d);
|
||||
Error *local_err = NULL;
|
||||
|
||||
unrealize(d, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
vmstate_unregister(DEVICE(drcp), &vmstate_spapr_drc_physical, drcp);
|
||||
qemu_unregister_reset(drc_physical_reset, drcp);
|
||||
}
|
||||
|
||||
static void spapr_drc_physical_class_init(ObjectClass *k, void *data)
|
||||
{
|
||||
DeviceClass *dk = DEVICE_CLASS(k);
|
||||
sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
|
||||
|
||||
dk->realize = realize_physical;
|
||||
dk->unrealize = unrealize_physical;
|
||||
drck->dr_entity_sense = physical_entity_sense;
|
||||
drck->isolate = drc_isolate_physical;
|
||||
drck->unisolate = drc_unisolate_physical;
|
||||
|
@ -731,10 +749,11 @@ static const TypeInfo spapr_drc_lmb_info = {
|
|||
sPAPRDRConnector *spapr_drc_by_index(uint32_t index)
|
||||
{
|
||||
Object *obj;
|
||||
char name[256];
|
||||
gchar *name;
|
||||
|
||||
snprintf(name, sizeof(name), "%s/%x", DRC_CONTAINER_PATH, index);
|
||||
name = g_strdup_printf("%s/%x", DRC_CONTAINER_PATH, index);
|
||||
obj = object_resolve_path(name, NULL);
|
||||
g_free(name);
|
||||
|
||||
return !obj ? NULL : SPAPR_DR_CONNECTOR(obj);
|
||||
}
|
||||
|
|
|
@ -700,6 +700,17 @@ static void event_scan(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
|||
rtas_st(rets, 0, RTAS_OUT_NO_ERRORS_FOUND);
|
||||
}
|
||||
|
||||
void spapr_clear_pending_events(sPAPRMachineState *spapr)
|
||||
{
|
||||
sPAPREventLogEntry *entry = NULL;
|
||||
|
||||
QTAILQ_FOREACH(entry, &spapr->pending_events, next) {
|
||||
QTAILQ_REMOVE(&spapr->pending_events, entry, next);
|
||||
g_free(entry->extended_log);
|
||||
g_free(entry);
|
||||
}
|
||||
}
|
||||
|
||||
void spapr_events_init(sPAPRMachineState *spapr)
|
||||
{
|
||||
QTAILQ_INIT(&spapr->pending_events);
|
||||
|
|
|
@ -999,7 +999,7 @@ static target_ulong h_register_vpa(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
|||
CPUPPCState *tenv;
|
||||
PowerPCCPU *tcpu;
|
||||
|
||||
tcpu = ppc_get_vcpu_by_dt_id(procno);
|
||||
tcpu = spapr_find_cpu(procno);
|
||||
if (!tcpu) {
|
||||
return H_PARAMETER;
|
||||
}
|
||||
|
@ -1431,7 +1431,7 @@ static target_ulong h_signal_sys_reset(PowerPCCPU *cpu,
|
|||
|
||||
} else {
|
||||
/* Unicast */
|
||||
cs = CPU(ppc_get_vcpu_by_dt_id(target));
|
||||
cs = CPU(spapr_find_cpu(target));
|
||||
if (cs) {
|
||||
run_on_cpu(cs, spapr_do_system_reset_on_cpu, RUN_ON_CPU_NULL);
|
||||
return H_SUCCESS;
|
||||
|
@ -1441,7 +1441,8 @@ static target_ulong h_signal_sys_reset(PowerPCCPU *cpu,
|
|||
}
|
||||
|
||||
static uint32_t cas_check_pvr(sPAPRMachineState *spapr, PowerPCCPU *cpu,
|
||||
target_ulong *addr, Error **errp)
|
||||
target_ulong *addr, bool *raw_mode_supported,
|
||||
Error **errp)
|
||||
{
|
||||
bool explicit_match = false; /* Matched the CPU's real PVR */
|
||||
uint32_t max_compat = spapr->max_compat_pvr;
|
||||
|
@ -1481,6 +1482,8 @@ static uint32_t cas_check_pvr(sPAPRMachineState *spapr, PowerPCCPU *cpu,
|
|||
return 0;
|
||||
}
|
||||
|
||||
*raw_mode_supported = explicit_match;
|
||||
|
||||
/* Parsing finished */
|
||||
trace_spapr_cas_pvr(cpu->compat_pvr, explicit_match, best_compat);
|
||||
|
||||
|
@ -1499,8 +1502,9 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
|
|||
sPAPROptionVector *ov1_guest, *ov5_guest, *ov5_cas_old, *ov5_updates;
|
||||
bool guest_radix;
|
||||
Error *local_err = NULL;
|
||||
bool raw_mode_supported = false;
|
||||
|
||||
cas_pvr = cas_check_pvr(spapr, cpu, &addr, &local_err);
|
||||
cas_pvr = cas_check_pvr(spapr, cpu, &addr, &raw_mode_supported, &local_err);
|
||||
if (local_err) {
|
||||
error_report_err(local_err);
|
||||
return H_HARDWARE;
|
||||
|
@ -1510,8 +1514,14 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
|
|||
if (cpu->compat_pvr != cas_pvr) {
|
||||
ppc_set_compat_all(cas_pvr, &local_err);
|
||||
if (local_err) {
|
||||
error_report_err(local_err);
|
||||
return H_HARDWARE;
|
||||
/* We fail to set compat mode (likely because running with KVM PR),
|
||||
* but maybe we can fallback to raw mode if the guest supports it.
|
||||
*/
|
||||
if (!raw_mode_supported) {
|
||||
error_report_err(local_err);
|
||||
return H_HARDWARE;
|
||||
}
|
||||
local_err = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -248,66 +248,59 @@ static const VMStateDescription vmstate_spapr_tce_table = {
|
|||
}
|
||||
};
|
||||
|
||||
static int spapr_tce_table_realize(DeviceState *dev)
|
||||
static void spapr_tce_table_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
sPAPRTCETable *tcet = SPAPR_TCE_TABLE(dev);
|
||||
Object *tcetobj = OBJECT(tcet);
|
||||
char tmp[32];
|
||||
gchar *tmp;
|
||||
|
||||
tcet->fd = -1;
|
||||
tcet->need_vfio = false;
|
||||
snprintf(tmp, sizeof(tmp), "tce-root-%x", tcet->liobn);
|
||||
tmp = g_strdup_printf("tce-root-%x", tcet->liobn);
|
||||
memory_region_init(&tcet->root, tcetobj, tmp, UINT64_MAX);
|
||||
g_free(tmp);
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "tce-iommu-%x", tcet->liobn);
|
||||
tmp = g_strdup_printf("tce-iommu-%x", tcet->liobn);
|
||||
memory_region_init_iommu(&tcet->iommu, sizeof(tcet->iommu),
|
||||
TYPE_SPAPR_IOMMU_MEMORY_REGION,
|
||||
tcetobj, tmp, 0);
|
||||
g_free(tmp);
|
||||
|
||||
QLIST_INSERT_HEAD(&spapr_tce_tables, tcet, list);
|
||||
|
||||
vmstate_register(DEVICE(tcet), tcet->liobn, &vmstate_spapr_tce_table,
|
||||
tcet);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void spapr_tce_set_need_vfio(sPAPRTCETable *tcet, bool need_vfio)
|
||||
{
|
||||
size_t table_size = tcet->nb_table * sizeof(uint64_t);
|
||||
void *newtable;
|
||||
uint64_t *oldtable;
|
||||
int newfd = -1;
|
||||
|
||||
if (need_vfio == tcet->need_vfio) {
|
||||
/* Nothing to do */
|
||||
return;
|
||||
}
|
||||
g_assert(need_vfio != tcet->need_vfio);
|
||||
|
||||
if (!need_vfio) {
|
||||
/* FIXME: We don't support transition back to KVM accelerated
|
||||
* TCEs yet */
|
||||
return;
|
||||
}
|
||||
tcet->need_vfio = need_vfio;
|
||||
|
||||
tcet->need_vfio = true;
|
||||
oldtable = tcet->table;
|
||||
|
||||
if (tcet->fd < 0) {
|
||||
/* Table is already in userspace, nothing to be do */
|
||||
return;
|
||||
}
|
||||
tcet->table = spapr_tce_alloc_table(tcet->liobn,
|
||||
tcet->page_shift,
|
||||
tcet->bus_offset,
|
||||
tcet->nb_table,
|
||||
&newfd,
|
||||
need_vfio);
|
||||
memcpy(tcet->table, oldtable, table_size);
|
||||
|
||||
newtable = g_malloc(table_size);
|
||||
memcpy(newtable, tcet->table, table_size);
|
||||
spapr_tce_free_table(oldtable, tcet->fd, tcet->nb_table);
|
||||
|
||||
kvmppc_remove_spapr_tce(tcet->table, tcet->fd, tcet->nb_table);
|
||||
|
||||
tcet->fd = -1;
|
||||
tcet->table = newtable;
|
||||
tcet->fd = newfd;
|
||||
}
|
||||
|
||||
sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn)
|
||||
{
|
||||
sPAPRTCETable *tcet;
|
||||
char tmp[32];
|
||||
gchar *tmp;
|
||||
|
||||
if (spapr_tce_find_by_liobn(liobn)) {
|
||||
error_report("Attempted to create TCE table with duplicate"
|
||||
|
@ -318,8 +311,10 @@ sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn)
|
|||
tcet = SPAPR_TCE_TABLE(object_new(TYPE_SPAPR_TCE_TABLE));
|
||||
tcet->liobn = liobn;
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "tce-table-%x", liobn);
|
||||
tmp = g_strdup_printf("tce-table-%x", liobn);
|
||||
object_property_add_child(OBJECT(owner), tmp, OBJECT(tcet), NULL);
|
||||
g_free(tmp);
|
||||
object_unref(OBJECT(tcet));
|
||||
|
||||
object_property_set_bool(OBJECT(tcet), true, "realized", NULL);
|
||||
|
||||
|
@ -372,6 +367,8 @@ static void spapr_tce_table_unrealize(DeviceState *dev, Error **errp)
|
|||
{
|
||||
sPAPRTCETable *tcet = SPAPR_TCE_TABLE(dev);
|
||||
|
||||
vmstate_unregister(DEVICE(tcet), &vmstate_spapr_tce_table, tcet);
|
||||
|
||||
QLIST_REMOVE(tcet, list);
|
||||
|
||||
spapr_tce_table_disable(tcet);
|
||||
|
@ -615,7 +612,7 @@ int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname,
|
|||
static void spapr_tce_table_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
dc->init = spapr_tce_table_realize;
|
||||
dc->realize = spapr_tce_table_realize;
|
||||
dc->reset = spapr_tce_reset;
|
||||
dc->unrealize = spapr_tce_table_unrealize;
|
||||
/* Reason: This is just an internal device for handling the hypercalls */
|
||||
|
|
|
@ -1703,7 +1703,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
|
|||
}
|
||||
#endif
|
||||
|
||||
memory_region_init_io(&sphb->msiwindow, NULL, &spapr_msi_ops, spapr,
|
||||
memory_region_init_io(&sphb->msiwindow, OBJECT(sphb), &spapr_msi_ops, spapr,
|
||||
"msi", msi_window_size);
|
||||
memory_region_add_subregion(&sphb->iommu_root, SPAPR_PCI_MSI_WINDOW,
|
||||
&sphb->msiwindow);
|
||||
|
@ -1752,8 +1752,8 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
|
|||
i, sphb->dtbusname);
|
||||
return;
|
||||
}
|
||||
memory_region_add_subregion_overlap(&sphb->iommu_root, 0,
|
||||
spapr_tce_get_iommu(tcet), 0);
|
||||
memory_region_add_subregion(&sphb->iommu_root, 0,
|
||||
spapr_tce_get_iommu(tcet));
|
||||
}
|
||||
|
||||
sphb->msi = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, g_free);
|
||||
|
|
|
@ -104,7 +104,7 @@ static void rtas_query_cpu_stopped_state(PowerPCCPU *cpu_,
|
|||
}
|
||||
|
||||
id = rtas_ld(args, 0);
|
||||
cpu = ppc_get_vcpu_by_dt_id(id);
|
||||
cpu = spapr_find_cpu(id);
|
||||
if (cpu != NULL) {
|
||||
if (CPU(cpu)->halted) {
|
||||
rtas_st(rets, 1, 0);
|
||||
|
@ -158,7 +158,7 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPRMachineState *spapr,
|
|||
start = rtas_ld(args, 1);
|
||||
r3 = rtas_ld(args, 2);
|
||||
|
||||
cpu = ppc_get_vcpu_by_dt_id(id);
|
||||
cpu = spapr_find_cpu(id);
|
||||
if (cpu != NULL) {
|
||||
CPUState *cs = CPU(cpu);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
|
61
include/hw/i2c/ppc4xx_i2c.h
Normal file
61
include/hw/i2c/ppc4xx_i2c.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* PPC4xx I2C controller emulation
|
||||
*
|
||||
* Copyright (c) 2007 Jocelyn Mayer
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef PPC4XX_I2C_H
|
||||
#define PPC4XX_I2C_H
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/i2c/i2c.h"
|
||||
|
||||
#define TYPE_PPC4xx_I2C "ppc4xx-i2c"
|
||||
#define PPC4xx_I2C(obj) OBJECT_CHECK(PPC4xxI2CState, (obj), TYPE_PPC4xx_I2C)
|
||||
|
||||
typedef struct PPC4xxI2CState {
|
||||
/*< private >*/
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
/*< public >*/
|
||||
I2CBus *bus;
|
||||
qemu_irq irq;
|
||||
MemoryRegion iomem;
|
||||
uint8_t mdata;
|
||||
uint8_t lmadr;
|
||||
uint8_t hmadr;
|
||||
uint8_t cntl;
|
||||
uint8_t mdcntl;
|
||||
uint8_t sts;
|
||||
uint8_t extsts;
|
||||
uint8_t sdata;
|
||||
uint8_t lsadr;
|
||||
uint8_t hsadr;
|
||||
uint8_t clkdiv;
|
||||
uint8_t intrmsk;
|
||||
uint8_t xfrcnt;
|
||||
uint8_t xtcntlss;
|
||||
uint8_t directcntl;
|
||||
} PPC4xxI2CState;
|
||||
|
||||
#endif /* PPC4XX_I2C_H */
|
|
@ -53,6 +53,9 @@ void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks,
|
|||
hwaddr *ram_sizes,
|
||||
int do_init);
|
||||
|
||||
void ppc4xx_mal_init(CPUPPCState *env, uint8_t txcnum, uint8_t rxcnum,
|
||||
qemu_irq irqs[4]);
|
||||
|
||||
#define TYPE_PPC4xx_PCI_HOST_BRIDGE "ppc4xx-pcihost"
|
||||
|
||||
#endif /* PPC4XX_H */
|
||||
|
|
|
@ -99,6 +99,7 @@ struct sPAPRMachineState {
|
|||
uint64_t rtc_offset; /* Now used only during incoming migration */
|
||||
struct PPCTimebase tb;
|
||||
bool has_graphics;
|
||||
uint32_t vsmt; /* Virtual SMT mode (KVM's "core stride") */
|
||||
|
||||
Notifier epow_notifier;
|
||||
QTAILQ_HEAD(, sPAPREventLogEntry) pending_events;
|
||||
|
@ -662,6 +663,7 @@ void spapr_cpu_parse_features(sPAPRMachineState *spapr);
|
|||
int spapr_hpt_shift_for_ramsize(uint64_t ramsize);
|
||||
void spapr_reallocate_hpt(sPAPRMachineState *spapr, int shift,
|
||||
Error **errp);
|
||||
void spapr_clear_pending_events(sPAPRMachineState *spapr);
|
||||
|
||||
/* CPU and LMB DRC release callbacks. */
|
||||
void spapr_core_release(DeviceState *dev);
|
||||
|
@ -704,4 +706,7 @@ void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg);
|
|||
|
||||
#define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift))
|
||||
|
||||
int spapr_vcpu_id(PowerPCCPU *cpu);
|
||||
PowerPCCPU *spapr_find_cpu(int vcpu_id);
|
||||
|
||||
#endif /* HW_SPAPR_H */
|
||||
|
|
|
@ -257,6 +257,7 @@ int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner,
|
|||
void spapr_drc_attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt,
|
||||
int fdt_start_offset, Error **errp);
|
||||
void spapr_drc_detach(sPAPRDRConnector *drc);
|
||||
bool spapr_drc_needed(void *opaque);
|
||||
|
||||
static inline bool spapr_drc_unplug_requested(sPAPRDRConnector *drc)
|
||||
{
|
||||
|
|
|
@ -160,6 +160,9 @@ ERROR_WHITELIST = [
|
|||
{'machine':'q35|pc.*', 'device':'kvm-ioapic', 'expected':True}, # Only 1 ioapics allowed
|
||||
{'machine':'q35|pc.*', 'device':'ioapic', 'expected':True}, # Only 1 ioapics allowed
|
||||
|
||||
# "spapr-cpu-core needs a pseries machine"
|
||||
{'machine':'(?!pseries).*', 'device':'.*-spapr-cpu-core', 'expected':True},
|
||||
|
||||
# KVM-specific devices shouldn't be tried without accel=kvm:
|
||||
{'accel':'(?!kvm).*', 'device':'kvmclock', 'expected':True},
|
||||
{'accel':'(?!kvm).*', 'device':'kvm-pci-assign', 'expected':True},
|
||||
|
|
|
@ -1,550 +0,0 @@
|
|||
PowerPC emulation status.
|
||||
The goal of this file is to provide a reference status to avoid regressions.
|
||||
|
||||
===============================================================================
|
||||
PowerPC core emulation status
|
||||
|
||||
INSN: instruction set.
|
||||
OK => all instructions are emulated
|
||||
KO => some insns are missing or some should be removed
|
||||
? => unchecked
|
||||
SPR: special purpose registers set
|
||||
OK => all SPR registered (but some may be fake)
|
||||
KO => some SPR are missing or should be removed
|
||||
? => unchecked
|
||||
MSR: MSR bits definitions
|
||||
OK => all MSR bits properly defined
|
||||
KO => MSR definition is incorrect
|
||||
? => unchecked
|
||||
IRQ: input signals definitions (mostly interrupts)
|
||||
OK => input signals are properly defined
|
||||
KO => input signals are not implemented (system emulation does not work)
|
||||
? => input signals definitions may be incorrect
|
||||
MMU: MMU model implementation
|
||||
OK => MMU model is implemented and Linux is able to boot
|
||||
KO => MMU model not implemented or bugged
|
||||
? => MMU model not tested
|
||||
EXCP: exceptions model implementation
|
||||
OK => exception model is implemented and Linux is able to boot
|
||||
KO => exception model not implemented or known to be buggy
|
||||
? => exception model may be incorrect or is untested
|
||||
|
||||
Embedded PowerPC cores
|
||||
***
|
||||
PowerPC 401:
|
||||
INSN OK
|
||||
SPR OK 401A1
|
||||
MSR OK
|
||||
IRQ KO partially implemented
|
||||
MMU OK
|
||||
EXCP ?
|
||||
|
||||
PowerPC 401x2:
|
||||
INSN OK
|
||||
SPR OK 401B2 401C2 401D2 401E2 401F2
|
||||
MSR OK
|
||||
IRQ KO partially implemented
|
||||
MMU OK
|
||||
EXCP ?
|
||||
|
||||
PowerPC IOP480:
|
||||
INSN OK
|
||||
SPR OK IOP480
|
||||
MSR OK
|
||||
IRQ KO partially implemented
|
||||
MMU OK
|
||||
EXCP ?
|
||||
|
||||
To be checked: 401G2 401B3 Cobra
|
||||
|
||||
***
|
||||
PowerPC 403:
|
||||
INSN OK
|
||||
SPR OK 403GA 403GB
|
||||
MMU OK
|
||||
MSR OK
|
||||
IRQ KO not implemented
|
||||
EXCP ?
|
||||
|
||||
PowerPC 403GCX:
|
||||
INSN OK
|
||||
SPR OK 403GCX
|
||||
MMU OK
|
||||
MSR OK
|
||||
IRQ KO not implemented
|
||||
EXCP ?
|
||||
|
||||
To be checked: 403GC
|
||||
|
||||
***
|
||||
PowerPC 405:
|
||||
Checked: 405CRa 405CRb 405CRc 405EP 405GPa 405GPb 405GPc 405GPd 405GPe 405GPR
|
||||
Npe405H Npe405H2 Npe405L
|
||||
INSN OK
|
||||
SPR OK
|
||||
MSR OK
|
||||
IRQ OK
|
||||
MMU OK
|
||||
EXCP OK
|
||||
Remarks: Linux 2.4 boots (at least 1 proprietary firmware).
|
||||
uboot seems to freeze at boot time.
|
||||
To be checked: 405D2 405D4 405EZ 405LP Npe4GS3 STB03 STB04 STB25
|
||||
x2vp4 x2vp7 x2vp20 x2vp50
|
||||
|
||||
XXX: find what is IBM e407b4
|
||||
|
||||
***
|
||||
PowerPC 440:
|
||||
Checked: 440EPa 440EPb 440GXa 440GXb 440GXc 440GXf 440SP 440SP2
|
||||
INSN OK
|
||||
SPR OK
|
||||
MSR OK
|
||||
IRQ KO not implemented
|
||||
MMU ?
|
||||
EXCP ?
|
||||
|
||||
PowerPC 440GP:
|
||||
Checked: 440GPb 440GPc
|
||||
INSN OK
|
||||
SPR OK
|
||||
MSR OK
|
||||
IRQ KO not implemented
|
||||
MMU ?
|
||||
EXCP ?
|
||||
|
||||
PowerPC 440x4:
|
||||
Checked: 440A4 440B4 440G4 440H4
|
||||
INSN OK
|
||||
SPR OK
|
||||
MSR OK
|
||||
IRQ KO not implemented
|
||||
MMU ?
|
||||
EXCP ?
|
||||
|
||||
PowerPC 440x5:
|
||||
Checked: 440A5 440F5 440G5 440H6 440GRa
|
||||
INSN OK
|
||||
SPR OK
|
||||
MSR OK
|
||||
IRQ KO not implemented
|
||||
MMU ?
|
||||
EXCP ?
|
||||
|
||||
To be checked: 440EPx 440GRx 440SPE
|
||||
|
||||
***
|
||||
PowerPC 460: (disabled: lack of detailed specifications)
|
||||
INSN KO
|
||||
SPR KO
|
||||
MSR KO
|
||||
IRQ KO
|
||||
MMU KO
|
||||
EXCP KO
|
||||
|
||||
PowerPC 460F: (disabled: lack of detailed specifications)
|
||||
INSN KO
|
||||
SPR KO
|
||||
MSR KO
|
||||
IRQ KO
|
||||
MMU KO
|
||||
EXCP KO
|
||||
|
||||
***
|
||||
PowerPC e200: (not implemented)
|
||||
INSN KO
|
||||
SPR KO
|
||||
MSR KO
|
||||
IRQ KO
|
||||
MMU KO
|
||||
EXCP KO
|
||||
|
||||
***
|
||||
PowerPC e300: (not implemented)
|
||||
INSN KO
|
||||
SPR KO
|
||||
MSR KO
|
||||
IRQ KO
|
||||
MMU KO
|
||||
EXCP KO
|
||||
|
||||
***
|
||||
PowerPC e500: (not implemented)
|
||||
INSN KO
|
||||
SPR KO
|
||||
MSR KO
|
||||
IRQ KO
|
||||
MMU KO
|
||||
EXCP KO
|
||||
|
||||
***
|
||||
PowerPC e600: (not implemented)
|
||||
INSN KO
|
||||
SPR KO
|
||||
MSR KO
|
||||
IRQ KO
|
||||
MMU KO
|
||||
EXCP KO
|
||||
|
||||
***
|
||||
32 bits PowerPC
|
||||
PowerPC 601: (601 601v2)
|
||||
INSN OK
|
||||
SPR OK is HID15 only on 601v2 ?
|
||||
MSR OK
|
||||
IRQ KO not implemented
|
||||
MMU ?
|
||||
EXCP ?
|
||||
Remarks: some instructions should have a specific behavior (not implemented)
|
||||
|
||||
PowerPC 602: 602
|
||||
INSN OK
|
||||
SPR OK
|
||||
MSR OK
|
||||
IRQ OK
|
||||
MMU ?
|
||||
EXCP ? at least timer and external interrupt are OK
|
||||
Remarks: Linux 2.4 crashes when entering user-mode.
|
||||
Linux 2.6.22 boots on this CPU but does not recognize it.
|
||||
|
||||
PowerPC 603: (603)
|
||||
INSN OK
|
||||
SPR OK
|
||||
MSR OK
|
||||
IRQ OK
|
||||
MMU OK
|
||||
EXCP OK
|
||||
Remarks: Linux 2.4 boots and properly recognizes the CPU
|
||||
Linux 2.6.22 idem.
|
||||
|
||||
PowerPC 603e: (603e11)
|
||||
INSN OK
|
||||
SPR OK
|
||||
MSR OK
|
||||
IRQ OK
|
||||
MMU OK
|
||||
EXCP OK
|
||||
Remarks: Linux 2.4 boots and properly recognizes the CPU
|
||||
Linux 2.6.22 idem.
|
||||
|
||||
PowerPC G2:
|
||||
INSN OK
|
||||
SPR OK
|
||||
MSR OK
|
||||
IRQ OK
|
||||
MMU OK
|
||||
EXCP OK
|
||||
Remarks: Linux 2.4 boots, recognizes the CPU as a 82xx.
|
||||
Linux 2.6.22 idem.
|
||||
|
||||
PowerPC G2le:
|
||||
INSN OK
|
||||
SPR OK
|
||||
MSR OK
|
||||
IRQ OK
|
||||
MMU OK
|
||||
EXCP OK
|
||||
Remarks: Linux 2.4 does not boots. Same symptoms as 602.
|
||||
Linux 2.6.22 boots and properly recognizes the CPU.
|
||||
|
||||
PowerPC 604:
|
||||
INSN OK
|
||||
SPR OK
|
||||
MSR OK
|
||||
IRQ OK
|
||||
MMU OK
|
||||
EXCP OK
|
||||
Remarks: Linux 2.4 boots and properly recognizes the CPU.
|
||||
Linux 2.6.22 idem.
|
||||
|
||||
PowerPC 7x0:
|
||||
INSN OK
|
||||
SPR OK
|
||||
MSR OK
|
||||
IRQ OK
|
||||
MMU OK
|
||||
EXCP OK
|
||||
Remarks: Linux 2.4 boots and properly recognizes the CPU.
|
||||
Linux 2.6.22 idem.
|
||||
|
||||
PowerPC 750fx:
|
||||
INSN OK
|
||||
SPR OK
|
||||
MSR OK
|
||||
IRQ OK
|
||||
MMU OK
|
||||
EXCP OK
|
||||
Remarks: Linux 2.4 boots but does not properly recognizes the CPU.
|
||||
Linux 2.6.22 boots and properly recognizes the CPU.
|
||||
|
||||
PowerPC 7x5:
|
||||
INSN ?
|
||||
SPR ?
|
||||
MSR ?
|
||||
IRQ OK
|
||||
MMU ?
|
||||
EXCP OK
|
||||
Remarks: Linux 2.4 does not boot.
|
||||
Linux 2.6.22 idem.
|
||||
|
||||
PowerPC 7400:
|
||||
INSN KO Altivec missing
|
||||
SPR OK
|
||||
MSR OK
|
||||
IRQ OK
|
||||
MMU OK
|
||||
EXCP ? Altivec, ...
|
||||
Remarks: Linux 2.4 boots and properly recognize the CPU.
|
||||
Linux 2.6.22 idem.
|
||||
|
||||
PowerPC 7410:
|
||||
INSN KO Altivec missing
|
||||
SPR OK
|
||||
MSR OK
|
||||
IRQ OK
|
||||
MMU OK
|
||||
EXCP ? Altivec, ...
|
||||
Remarks: Linux 2.4 boots and properly recognize the CPU.
|
||||
Linux 2.6.22 idem.
|
||||
Note that UM says tlbld & tlbli are implemented but this may be a mistake
|
||||
as TLB loads are managed by the hardware and the CPU does not implement the
|
||||
needed registers.
|
||||
|
||||
PowerPC 7441:
|
||||
INSN KO Altivec missing
|
||||
SPR OK
|
||||
MSR OK
|
||||
IRQ OK
|
||||
MMU OK
|
||||
EXCP ? Altivec, ...
|
||||
Remarks: Linux does not have the code to handle TLB miss on this CPU
|
||||
Linux 2.6.22 idem.
|
||||
|
||||
PowerPC 7450/7451:
|
||||
INSN KO Altivec missing
|
||||
SPR OK
|
||||
MSR OK
|
||||
IRQ OK
|
||||
MMU OK
|
||||
EXCP ? Altivec, ...
|
||||
Remarks: Linux does not have the code to handle TLB miss on this CPU
|
||||
Linux 2.6.22 idem.
|
||||
|
||||
PowerPC 7445/7447:
|
||||
INSN KO Altivec missing
|
||||
SPR OK
|
||||
MSR OK
|
||||
IRQ OK
|
||||
MMU OK
|
||||
EXCP ? Altivec, ...
|
||||
Remarks: Linux does not have the code to handle TLB miss on this CPU
|
||||
Linux 2.6.22 idem.
|
||||
|
||||
PowerPC 7455/7457:
|
||||
INSN KO Altivec missing
|
||||
SPR OK
|
||||
MSR OK
|
||||
IRQ OK
|
||||
MMU OK
|
||||
EXCP ? Altivec, ...
|
||||
Remarks: Linux does not have the code to handle TLB miss on this CPU
|
||||
Linux 2.6.22 idem.
|
||||
|
||||
64 bits PowerPC
|
||||
PowerPC 620: (disabled)
|
||||
INSN KO
|
||||
SPR KO
|
||||
MSR ?
|
||||
IRQ KO
|
||||
MMU KO
|
||||
EXCP KO
|
||||
Remarks: not much documentation for this implementation...
|
||||
|
||||
PowerPC 970:
|
||||
INSN KO Altivec missing and more
|
||||
SPR KO
|
||||
MSR ?
|
||||
IRQ OK
|
||||
MMU OK
|
||||
EXCP KO partially implemented
|
||||
Remarks: Should be able to boot but there is no hw platform currently emulated.
|
||||
|
||||
PowerPC 970FX:
|
||||
INSN KO Altivec missing and more
|
||||
SPR KO
|
||||
MSR ?
|
||||
IRQ OK
|
||||
MMU OK
|
||||
EXCP KO partially implemented
|
||||
Remarks: Should be able to boot but there is no hw platform currently emulated.
|
||||
|
||||
PowerPC Cell:
|
||||
INSN KO Altivec missing and more
|
||||
SPR KO
|
||||
MSR ?
|
||||
IRQ ?
|
||||
MMU ?
|
||||
EXCP ? partially implemented
|
||||
Remarks: As the core is mostly a 970, should be able to boot.
|
||||
SPE are not implemented.
|
||||
|
||||
PowerPC 630: (disabled: lack of detailed specifications)
|
||||
INSN KO
|
||||
SPR KO
|
||||
MSR KO
|
||||
IRQ KO
|
||||
MMU KO
|
||||
EXCP KO
|
||||
|
||||
PowerPC 631: (disabled: lack of detailed specifications)
|
||||
INSN KO
|
||||
SPR KO
|
||||
MSR KO
|
||||
IRQ KO
|
||||
MMU KO
|
||||
EXCP KO
|
||||
|
||||
POWER4: (disabled: lack of detailed specifications)
|
||||
INSN KO
|
||||
SPR KO
|
||||
MSR KO
|
||||
IRQ KO
|
||||
MMU KO
|
||||
EXCP KO
|
||||
|
||||
POWER4+: (disabled: lack of detailed specifications)
|
||||
INSN KO
|
||||
SPR KO
|
||||
MSR KO
|
||||
IRQ KO
|
||||
MMU KO
|
||||
EXCP KO
|
||||
|
||||
POWER5: (disabled: lack of detailed specifications)
|
||||
INSN KO
|
||||
SPR KO
|
||||
MSR KO
|
||||
IRQ KO
|
||||
MMU KO
|
||||
EXCP KO
|
||||
|
||||
POWER5+: (disabled: lack of detailed specifications)
|
||||
INSN KO
|
||||
SPR KO
|
||||
MSR KO
|
||||
IRQ KO
|
||||
MMU KO
|
||||
EXCP KO
|
||||
|
||||
POWER6: (disabled: lack of detailed specifications)
|
||||
INSN KO
|
||||
SPR KO
|
||||
MSR KO
|
||||
IRQ KO
|
||||
MMU KO
|
||||
EXCP KO
|
||||
|
||||
RS64: (disabled: lack of detailed specifications)
|
||||
INSN KO
|
||||
SPR KO
|
||||
MSR KO
|
||||
IRQ KO
|
||||
MMU KO
|
||||
EXCP KO
|
||||
|
||||
RS64-II: (disabled: lack of detailed specifications)
|
||||
INSN KO
|
||||
SPR KO
|
||||
MSR KO
|
||||
IRQ KO
|
||||
MMU KO
|
||||
EXCP KO
|
||||
|
||||
RS64-III: (disabled: lack of detailed specifications)
|
||||
INSN KO
|
||||
SPR KO
|
||||
MSR KO
|
||||
IRQ KO
|
||||
MMU KO
|
||||
EXCP KO
|
||||
|
||||
RS64-IV: (disabled: lack of detailed specifications)
|
||||
INSN KO
|
||||
SPR KO
|
||||
MSR KO
|
||||
IRQ KO
|
||||
MMU KO
|
||||
EXCP KO
|
||||
|
||||
Original POWER
|
||||
POWER: (disabled: lack of detailed specifications)
|
||||
INSN KO
|
||||
SPR KO
|
||||
MSR KO
|
||||
IRQ KO
|
||||
MMU KO
|
||||
EXCP KO
|
||||
|
||||
POWER2: (disabled: lack of detailed specifications)
|
||||
INSN KO
|
||||
SPR KO
|
||||
MSR KO
|
||||
IRQ KO
|
||||
MMU KO
|
||||
EXCP KO
|
||||
|
||||
===============================================================================
|
||||
PowerPC microcontrollers emulation status
|
||||
|
||||
Implemementation should be sufficient to boot Linux:
|
||||
(there seem to be problems with uboot freezing at some point)
|
||||
- PowerPC 405CR
|
||||
- PowerPC 405EP
|
||||
|
||||
TODO:
|
||||
- PowerPC 401 microcontrollers emulation
|
||||
- PowerPC 403 microcontrollers emulation
|
||||
- more PowerPC 405 microcontrollers emulation
|
||||
- Fixes / more features for implemented PowerPC 405 microcontrollers emulation
|
||||
- PowerPC 440 microcontrollers emulation
|
||||
- e200 microcontrollers emulation
|
||||
- e300 microcontrollers emulation
|
||||
- e500 microcontrollers emulation
|
||||
- e600 microcontrollers emulation
|
||||
|
||||
===============================================================================
|
||||
PowerPC based platforms emulation status
|
||||
|
||||
* PREP platform (RS/6000 7043...) - TO BE CHECKED (broken)
|
||||
- Gentoo Linux live CDROM 1.4
|
||||
- Debian Linux 3.0
|
||||
- Mandrake Linux 9
|
||||
|
||||
* heathrow PowerMac platform (beige PowerMac) - TO BE CHECKED (broken)
|
||||
- Gentoo Linux live CDROM 1.4
|
||||
- Debian Linux 3.0
|
||||
- Mandrake Linux 9
|
||||
|
||||
* mac99 platform (white and blue PowerMac, ...)
|
||||
- Gentoo Linux live CDROM 1.4 - boots, compiles linux kernel
|
||||
- Debian Linux woody - boots from CDROM and HDD
|
||||
- Mandrake Linux 9 - boots from CDROM, freezes during install
|
||||
- Knoppix 2003-07-13_4 boots from CDROM, pb with X configuration
|
||||
distribution bug: X runs with a properly hand-coded configuration.
|
||||
- rock Linux 2.0 runs from CDROM
|
||||
|
||||
* Linux 2.6 support seems deadly broken (used to boot...).
|
||||
|
||||
* PowerPC 405EP reference boards:
|
||||
- can boot Linux 2.4 & 2.6.
|
||||
Need to provide a flash image ready to boot for reproductible tests.
|
||||
|
||||
TODO:
|
||||
- URGENT: fix PreP and heathrow platforms
|
||||
- PowerPC 64 reference platform
|
||||
- MCA based RS/6000 emulation
|
||||
- CHRP emulation (not PowerMac)
|
||||
- PPAR emulation
|
||||
- ePPAR emulation
|
||||
- misc PowerPC reference boards emulation
|
||||
|
||||
===============================================================================
|
File diff suppressed because it is too large
Load diff
|
@ -24,14 +24,13 @@
|
|||
/**
|
||||
* PowerPCCPUAlias:
|
||||
* @alias: The alias name.
|
||||
* @model: The CPU model @alias refers to.
|
||||
* @model: The CPU model @alias refers to, that directly resolves into CPU type
|
||||
*
|
||||
* A mapping entry from CPU @alias to CPU @model.
|
||||
*/
|
||||
typedef struct PowerPCCPUAlias {
|
||||
const char *alias;
|
||||
const char *model;
|
||||
ObjectClass *oc;
|
||||
} PowerPCCPUAlias;
|
||||
|
||||
extern PowerPCCPUAlias ppc_cpu_aliases[];
|
||||
|
@ -346,6 +345,7 @@ enum {
|
|||
CPU_POWERPC_e500v2_v30 = 0x80210030,
|
||||
CPU_POWERPC_e500mc = 0x80230020,
|
||||
CPU_POWERPC_e5500 = 0x80240020,
|
||||
CPU_POWERPC_e6500 = 0x80400020,
|
||||
/* MPC85xx microcontrollers */
|
||||
#define CPU_POWERPC_MPC8533_v10 CPU_POWERPC_e500v2_v21
|
||||
#define CPU_POWERPC_MPC8533_v11 CPU_POWERPC_e500v2_v22
|
||||
|
|
|
@ -1188,7 +1188,7 @@ typedef struct PPCVirtualHypervisorClass PPCVirtualHypervisorClass;
|
|||
/**
|
||||
* PowerPCCPU:
|
||||
* @env: #CPUPPCState
|
||||
* @cpu_dt_id: CPU index used in the device tree. KVM uses this index too
|
||||
* @vcpu_id: vCPU identifier given to KVM
|
||||
* @compat_pvr: Current logical PVR, zero if in "raw" mode
|
||||
*
|
||||
* A PowerPC CPU.
|
||||
|
@ -1199,7 +1199,7 @@ struct PowerPCCPU {
|
|||
/*< public >*/
|
||||
|
||||
CPUPPCState env;
|
||||
int cpu_dt_id;
|
||||
int vcpu_id;
|
||||
uint32_t compat_pvr;
|
||||
PPCVirtualHypervisor *vhyp;
|
||||
Object *intc;
|
||||
|
@ -1354,6 +1354,9 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val);
|
|||
|
||||
#define cpu_init(cpu_model) cpu_generic_init(TYPE_POWERPC_CPU, cpu_model)
|
||||
|
||||
#define POWERPC_CPU_TYPE_SUFFIX "-" TYPE_POWERPC_CPU
|
||||
#define POWERPC_CPU_TYPE_NAME(model) model POWERPC_CPU_TYPE_SUFFIX
|
||||
|
||||
#define cpu_signal_handler cpu_ppc_signal_handler
|
||||
#define cpu_list ppc_cpu_list
|
||||
|
||||
|
@ -2473,10 +2476,10 @@ static inline ppcmas_tlb_t *booke206_get_tlbm(CPUPPCState *env, const int tlbn,
|
|||
/* returns bitmap of supported page sizes for a given TLB */
|
||||
static inline uint32_t booke206_tlbnps(CPUPPCState *env, const int tlbn)
|
||||
{
|
||||
bool mav2 = false;
|
||||
uint32_t ret = 0;
|
||||
|
||||
if (mav2) {
|
||||
if ((env->spr[SPR_MMUCFG] & MMUCFG_MAVN) == MMUCFG_MAVN_V2) {
|
||||
/* MAV2 */
|
||||
ret = env->spr[SPR_BOOKE_TLB0PS + tlbn];
|
||||
} else {
|
||||
uint32_t tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
|
||||
|
@ -2491,6 +2494,28 @@ static inline uint32_t booke206_tlbnps(CPUPPCState *env, const int tlbn)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static inline void booke206_fixed_size_tlbn(CPUPPCState *env, const int tlbn,
|
||||
ppcmas_tlb_t *tlb)
|
||||
{
|
||||
uint8_t i;
|
||||
int32_t tsize = -1;
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
if ((env->spr[SPR_BOOKE_TLB0PS + tlbn]) & (1ULL << i)) {
|
||||
if (tsize == -1) {
|
||||
tsize = i;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* TLBnPS unimplemented? Odd.. */
|
||||
assert(tsize != -1);
|
||||
tlb->mas1 &= ~MAS1_TSIZE_MASK;
|
||||
tlb->mas1 |= ((uint32_t)tsize) << MAS1_TSIZE_SHIFT;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static inline bool msr_is_64bit(CPUPPCState *env, target_ulong msr)
|
||||
|
@ -2514,23 +2539,5 @@ static inline bool lsw_reg_in_range(int start, int nregs, int rx)
|
|||
|
||||
void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env);
|
||||
|
||||
/**
|
||||
* ppc_get_vcpu_dt_id:
|
||||
* @cs: a PowerPCCPU struct.
|
||||
*
|
||||
* Returns a device-tree ID for a CPU.
|
||||
*/
|
||||
int ppc_get_vcpu_dt_id(PowerPCCPU *cpu);
|
||||
|
||||
/**
|
||||
* ppc_get_vcpu_by_dt_id:
|
||||
* @cpu_dt_id: a device tree id
|
||||
*
|
||||
* Searches for a CPU by @cpu_dt_id.
|
||||
*
|
||||
* Returns: a PowerPCCPU struct
|
||||
*/
|
||||
PowerPCCPU *ppc_get_vcpu_by_dt_id(int cpu_dt_id);
|
||||
|
||||
void ppc_maybe_bswap_register(CPUPPCState *env, uint8_t *mem_buf, int len);
|
||||
#endif /* PPC_CPU_H */
|
||||
|
|
|
@ -74,6 +74,7 @@ static int cap_interrupt_level = false;
|
|||
static int cap_segstate;
|
||||
static int cap_booke_sregs;
|
||||
static int cap_ppc_smt;
|
||||
static int cap_ppc_smt_possible;
|
||||
static int cap_ppc_rma;
|
||||
static int cap_spapr_tce;
|
||||
static int cap_spapr_tce_64;
|
||||
|
@ -130,7 +131,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
|
|||
cap_interrupt_level = kvm_check_extension(s, KVM_CAP_PPC_IRQ_LEVEL);
|
||||
cap_segstate = kvm_check_extension(s, KVM_CAP_PPC_SEGSTATE);
|
||||
cap_booke_sregs = kvm_check_extension(s, KVM_CAP_PPC_BOOKE_SREGS);
|
||||
cap_ppc_smt = kvm_check_extension(s, KVM_CAP_PPC_SMT);
|
||||
cap_ppc_smt_possible = kvm_check_extension(s, KVM_CAP_PPC_SMT_POSSIBLE);
|
||||
cap_ppc_rma = kvm_check_extension(s, KVM_CAP_PPC_RMA);
|
||||
cap_spapr_tce = kvm_check_extension(s, KVM_CAP_SPAPR_TCE);
|
||||
cap_spapr_tce_64 = kvm_check_extension(s, KVM_CAP_SPAPR_TCE_64);
|
||||
|
@ -144,6 +145,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
|
|||
* only activated after this by kvmppc_set_papr() */
|
||||
cap_htab_fd = kvm_check_extension(s, KVM_CAP_PPC_HTAB_FD);
|
||||
cap_fixup_hcalls = kvm_check_extension(s, KVM_CAP_PPC_FIXUP_HCALL);
|
||||
cap_ppc_smt = kvm_vm_check_extension(s, KVM_CAP_PPC_SMT);
|
||||
cap_htm = kvm_vm_check_extension(s, KVM_CAP_PPC_HTM);
|
||||
cap_mmu_radix = kvm_vm_check_extension(s, KVM_CAP_PPC_MMU_RADIX);
|
||||
cap_mmu_hash_v3 = kvm_vm_check_extension(s, KVM_CAP_PPC_MMU_HASH_V3);
|
||||
|
@ -520,7 +522,7 @@ bool kvmppc_is_mem_backend_page_size_ok(const char *obj_path)
|
|||
|
||||
unsigned long kvm_arch_vcpu_id(CPUState *cpu)
|
||||
{
|
||||
return ppc_get_vcpu_dt_id(POWERPC_CPU(cpu));
|
||||
return POWERPC_CPU(cpu)->vcpu_id;
|
||||
}
|
||||
|
||||
/* e500 supports 2 h/w breakpoint and 2 watchpoint.
|
||||
|
@ -2134,6 +2136,41 @@ int kvmppc_smt_threads(void)
|
|||
return cap_ppc_smt ? cap_ppc_smt : 1;
|
||||
}
|
||||
|
||||
int kvmppc_set_smt_threads(int smt)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_PPC_SMT, 0, smt, 0);
|
||||
if (!ret) {
|
||||
cap_ppc_smt = smt;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void kvmppc_hint_smt_possible(Error **errp)
|
||||
{
|
||||
int i;
|
||||
GString *g;
|
||||
char *s;
|
||||
|
||||
assert(kvm_enabled());
|
||||
if (cap_ppc_smt_possible) {
|
||||
g = g_string_new("Available VSMT modes:");
|
||||
for (i = 63; i >= 0; i--) {
|
||||
if ((1UL << i) & cap_ppc_smt_possible) {
|
||||
g_string_append_printf(g, " %lu", (1UL << i));
|
||||
}
|
||||
}
|
||||
s = g_string_free(g, false);
|
||||
error_append_hint(errp, "%s.\n", s);
|
||||
g_free(s);
|
||||
} else {
|
||||
error_append_hint(errp,
|
||||
"This KVM seems to be too old to support VSMT.\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef TARGET_PPC64
|
||||
off_t kvmppc_alloc_rma(void **rma)
|
||||
{
|
||||
|
@ -2488,15 +2525,14 @@ static int kvm_ppc_register_host_cpu_type(void)
|
|||
*/
|
||||
dc = DEVICE_CLASS(ppc_cpu_get_family_class(pvr_pcc));
|
||||
for (i = 0; ppc_cpu_aliases[i].alias != NULL; i++) {
|
||||
if (strcmp(ppc_cpu_aliases[i].alias, dc->desc) == 0) {
|
||||
if (strcasecmp(ppc_cpu_aliases[i].alias, dc->desc) == 0) {
|
||||
char *suffix;
|
||||
|
||||
ppc_cpu_aliases[i].model = g_strdup(object_class_get_name(oc));
|
||||
suffix = strstr(ppc_cpu_aliases[i].model, "-"TYPE_POWERPC_CPU);
|
||||
suffix = strstr(ppc_cpu_aliases[i].model, POWERPC_CPU_TYPE_SUFFIX);
|
||||
if (suffix) {
|
||||
*suffix = 0;
|
||||
}
|
||||
ppc_cpu_aliases[i].oc = oc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#ifndef KVM_PPC_H
|
||||
#define KVM_PPC_H
|
||||
|
||||
#define TYPE_HOST_POWERPC_CPU "host-" TYPE_POWERPC_CPU
|
||||
#define TYPE_HOST_POWERPC_CPU POWERPC_CPU_TYPE_NAME("host")
|
||||
|
||||
#ifdef CONFIG_KVM
|
||||
|
||||
|
@ -29,6 +29,8 @@ void kvmppc_set_papr(PowerPCCPU *cpu);
|
|||
int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr);
|
||||
void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy);
|
||||
int kvmppc_smt_threads(void);
|
||||
void kvmppc_hint_smt_possible(Error **errp);
|
||||
int kvmppc_set_smt_threads(int smt);
|
||||
int kvmppc_clear_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits);
|
||||
int kvmppc_or_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits);
|
||||
int kvmppc_set_tcr(PowerPCCPU *cpu);
|
||||
|
@ -148,6 +150,16 @@ static inline int kvmppc_smt_threads(void)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static inline void kvmppc_hint_smt_possible(Error **errp)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline int kvmppc_set_smt_threads(int smt)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int kvmppc_or_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits)
|
||||
{
|
||||
return 0;
|
||||
|
|
|
@ -2632,12 +2632,16 @@ void helper_booke206_tlbwe(CPUPPCState *env)
|
|||
env->spr[SPR_BOOKE_MAS3];
|
||||
tlb->mas1 = env->spr[SPR_BOOKE_MAS1];
|
||||
|
||||
/* MAV 1.0 only */
|
||||
if (!(tlbncfg & TLBnCFG_AVAIL)) {
|
||||
/* force !AVAIL TLB entries to correct page size */
|
||||
tlb->mas1 &= ~MAS1_TSIZE_MASK;
|
||||
/* XXX can be configured in MMUCSR0 */
|
||||
tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12;
|
||||
if ((env->spr[SPR_MMUCFG] & MMUCFG_MAVN) == MMUCFG_MAVN_V2) {
|
||||
/* For TLB which has a fixed size TSIZE is ignored with MAV2 */
|
||||
booke206_fixed_size_tlbn(env, tlbn, tlb);
|
||||
} else {
|
||||
if (!(tlbncfg & TLBnCFG_AVAIL)) {
|
||||
/* force !AVAIL TLB entries to correct page size */
|
||||
tlb->mas1 &= ~MAS1_TSIZE_MASK;
|
||||
/* XXX can be configured in MMUCSR0 */
|
||||
tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make a mask from TLB size to discard invalid bits in EPN field */
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "hw/ppc/ppc.h"
|
||||
#include "mmu-book3s-v3.h"
|
||||
#include "sysemu/qtest.h"
|
||||
#include "qemu/cutils.h"
|
||||
|
||||
//#define PPC_DUMP_CPU
|
||||
//#define PPC_DEBUG_SPR
|
||||
|
@ -1842,7 +1843,7 @@ static inline uint32_t gen_tlbncfg(uint32_t assoc, uint32_t minsize,
|
|||
|
||||
/* BookE 2.06 storage control registers */
|
||||
static void gen_spr_BookE206(CPUPPCState *env, uint32_t mas_mask,
|
||||
uint32_t *tlbncfg)
|
||||
uint32_t *tlbncfg, uint32_t mmucfg)
|
||||
{
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
const char *mas_names[8] = {
|
||||
|
@ -1886,7 +1887,7 @@ static void gen_spr_BookE206(CPUPPCState *env, uint32_t mas_mask,
|
|||
spr_register(env, SPR_MMUCFG, "MMUCFG",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, SPR_NOACCESS,
|
||||
0x00000000); /* TOFIX */
|
||||
mmucfg);
|
||||
switch (env->nb_ways) {
|
||||
case 4:
|
||||
spr_register(env, SPR_BOOKE_TLB3CFG, "TLB3CFG",
|
||||
|
@ -4615,7 +4616,7 @@ static void init_proc_e200(CPUPPCState *env)
|
|||
&spr_read_spefscr, &spr_write_spefscr,
|
||||
0x00000000);
|
||||
/* Memory management */
|
||||
gen_spr_BookE206(env, 0x0000005D, NULL);
|
||||
gen_spr_BookE206(env, 0x0000005D, NULL, 0);
|
||||
/* XXX : not implemented */
|
||||
spr_register(env, SPR_HID0, "HID0",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
|
@ -4888,6 +4889,7 @@ enum fsl_e500_version {
|
|||
fsl_e500v2,
|
||||
fsl_e500mc,
|
||||
fsl_e5500,
|
||||
fsl_e6500,
|
||||
};
|
||||
|
||||
static void init_proc_e500(CPUPPCState *env, int version)
|
||||
|
@ -4900,6 +4902,7 @@ static void init_proc_e500(CPUPPCState *env, int version)
|
|||
| 0x0020; /* 32 kb */
|
||||
uint32_t l1cfg1 = 0x3800 /* 8 ways */
|
||||
| 0x0020; /* 32 kb */
|
||||
uint32_t mmucfg = 0;
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
int i;
|
||||
#endif
|
||||
|
@ -4921,6 +4924,9 @@ static void init_proc_e500(CPUPPCState *env, int version)
|
|||
case fsl_e5500:
|
||||
ivor_mask = 0x000003FE0000FFFFULL;
|
||||
break;
|
||||
case fsl_e6500:
|
||||
ivor_mask = 0x000003FF0000FFFFULL;
|
||||
break;
|
||||
}
|
||||
gen_spr_BookE(env, ivor_mask);
|
||||
gen_spr_usprg3(env);
|
||||
|
@ -4953,6 +4959,12 @@ static void init_proc_e500(CPUPPCState *env, int version)
|
|||
tlbncfg[0] = gen_tlbncfg(4, 1, 1, 0, 512);
|
||||
tlbncfg[1] = gen_tlbncfg(64, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 64);
|
||||
break;
|
||||
case fsl_e6500:
|
||||
mmucfg = 0x6510B45;
|
||||
env->nb_pids = 1;
|
||||
tlbncfg[0] = 0x08052400;
|
||||
tlbncfg[1] = 0x40028040;
|
||||
break;
|
||||
default:
|
||||
cpu_abort(CPU(cpu), "Unknown CPU: " TARGET_FMT_lx "\n", env->spr[SPR_PVR]);
|
||||
}
|
||||
|
@ -4971,10 +4983,16 @@ static void init_proc_e500(CPUPPCState *env, int version)
|
|||
l1cfg0 |= 0x1000000; /* 64 byte cache block size */
|
||||
l1cfg1 |= 0x1000000; /* 64 byte cache block size */
|
||||
break;
|
||||
case fsl_e6500:
|
||||
env->dcache_line_size = 32;
|
||||
env->icache_line_size = 32;
|
||||
l1cfg0 |= 0x0F83820;
|
||||
l1cfg1 |= 0x0B83820;
|
||||
break;
|
||||
default:
|
||||
cpu_abort(CPU(cpu), "Unknown CPU: " TARGET_FMT_lx "\n", env->spr[SPR_PVR]);
|
||||
}
|
||||
gen_spr_BookE206(env, 0x000000DF, tlbncfg);
|
||||
gen_spr_BookE206(env, 0x000000DF, tlbncfg, mmucfg);
|
||||
/* XXX : not implemented */
|
||||
spr_register(env, SPR_HID0, "HID0",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
|
@ -5049,7 +5067,7 @@ static void init_proc_e500(CPUPPCState *env, int version)
|
|||
&spr_read_generic, SPR_NOACCESS,
|
||||
0x00000000);
|
||||
/* XXX better abstract into Emb.xxx features */
|
||||
if (version == fsl_e5500) {
|
||||
if ((version == fsl_e5500) || (version == fsl_e6500)) {
|
||||
spr_register(env, SPR_BOOKE_EPCR, "EPCR",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
|
@ -5061,6 +5079,30 @@ static void init_proc_e500(CPUPPCState *env, int version)
|
|||
ivpr_mask = (target_ulong)~0xFFFFULL;
|
||||
}
|
||||
|
||||
if (version == fsl_e6500) {
|
||||
spr_register(env, SPR_BOOKE_SPRG8, "SPRG8",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_BOOKE_SPRG9, "SPRG9",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
/* Thread identification */
|
||||
spr_register(env, SPR_TIR, "TIR",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, SPR_NOACCESS,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_BOOKE_TLB0PS, "TLB0PS",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, SPR_NOACCESS,
|
||||
0x00000004);
|
||||
spr_register(env, SPR_BOOKE_TLB1PS, "TLB1PS",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, SPR_NOACCESS,
|
||||
0x7FFFFFFC);
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
env->nb_tlb = 0;
|
||||
env->tlb_type = TLB_MAS;
|
||||
|
@ -5253,6 +5295,55 @@ POWERPC_FAMILY(e5500)(ObjectClass *oc, void *data)
|
|||
pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DE |
|
||||
POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK;
|
||||
}
|
||||
|
||||
static void init_proc_e6500(CPUPPCState *env)
|
||||
{
|
||||
init_proc_e500(env, fsl_e6500);
|
||||
}
|
||||
|
||||
POWERPC_FAMILY(e6500)(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
|
||||
|
||||
dc->desc = "e6500 core";
|
||||
pcc->init_proc = init_proc_e6500;
|
||||
pcc->check_pow = check_pow_none;
|
||||
pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_MFTB |
|
||||
PPC_WRTEE | PPC_RFDI | PPC_RFMCI |
|
||||
PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI |
|
||||
PPC_CACHE_DCBZ | PPC_CACHE_DCBA |
|
||||
PPC_FLOAT | PPC_FLOAT_FRES |
|
||||
PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSEL |
|
||||
PPC_FLOAT_STFIWX | PPC_WAIT |
|
||||
PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC |
|
||||
PPC_64B | PPC_POPCNTB | PPC_POPCNTWD | PPC_ALTIVEC;
|
||||
pcc->insns_flags2 = PPC2_BOOKE206 | PPC2_PRCNTL | PPC2_PERM_ISA206 | \
|
||||
PPC2_FP_CVT_S64 | PPC2_ATOMIC_ISA206;
|
||||
pcc->msr_mask = (1ull << MSR_CM) |
|
||||
(1ull << MSR_GS) |
|
||||
(1ull << MSR_UCLE) |
|
||||
(1ull << MSR_CE) |
|
||||
(1ull << MSR_EE) |
|
||||
(1ull << MSR_PR) |
|
||||
(1ull << MSR_FP) |
|
||||
(1ull << MSR_ME) |
|
||||
(1ull << MSR_FE0) |
|
||||
(1ull << MSR_DE) |
|
||||
(1ull << MSR_FE1) |
|
||||
(1ull << MSR_IS) |
|
||||
(1ull << MSR_DS) |
|
||||
(1ull << MSR_PX) |
|
||||
(1ull << MSR_RI) |
|
||||
(1ull << MSR_VR);
|
||||
pcc->mmu_model = POWERPC_MMU_BOOKE206;
|
||||
pcc->excp_model = POWERPC_EXCP_BOOKE;
|
||||
pcc->bus_model = PPC_FLAGS_INPUT_BookE;
|
||||
pcc->bfd_mach = bfd_mach_ppc_e500;
|
||||
pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DE |
|
||||
POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_VRE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Non-embedded PowerPC */
|
||||
|
@ -9813,42 +9904,15 @@ static void ppc_cpu_realizefn(DeviceState *dev, Error **errp)
|
|||
PowerPCCPU *cpu = POWERPC_CPU(dev);
|
||||
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
|
||||
Error *local_err = NULL;
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
int max_smt = kvmppc_smt_threads();
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
if (smp_threads > max_smt) {
|
||||
error_setg(errp, "Cannot support more than %d threads on PPC with %s",
|
||||
max_smt, kvm_enabled() ? "KVM" : "TCG");
|
||||
return;
|
||||
}
|
||||
if (!is_power_of_2(smp_threads)) {
|
||||
error_setg(errp, "Cannot support %d threads on PPC with %s, "
|
||||
"threads count must be a power of 2.",
|
||||
smp_threads, kvm_enabled() ? "KVM" : "TCG");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
cpu_exec_realizefn(cs, &local_err);
|
||||
if (local_err != NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
cpu->cpu_dt_id = (cs->cpu_index / smp_threads) * max_smt
|
||||
+ (cs->cpu_index % smp_threads);
|
||||
|
||||
if (kvm_enabled() && !kvm_vcpu_id_is_valid(cpu->cpu_dt_id)) {
|
||||
error_setg(errp, "Can't create CPU with id %d in KVM", cpu->cpu_dt_id);
|
||||
error_append_hint(errp, "Adjust the number of cpus to %d "
|
||||
"or try to raise the number of threads per core\n",
|
||||
cpu->cpu_dt_id * smp_threads / max_smt);
|
||||
goto unrealize;
|
||||
if (cpu->vcpu_id == UNASSIGNED_CPU_INDEX) {
|
||||
cpu->vcpu_id = cs->cpu_index;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (tcg_enabled()) {
|
||||
if (ppc_fixup_cpu(cpu) != 0) {
|
||||
|
@ -10176,83 +10240,38 @@ PowerPCCPUClass *ppc_cpu_class_by_pvr_mask(uint32_t pvr)
|
|||
return pcc;
|
||||
}
|
||||
|
||||
static gint ppc_cpu_compare_class_name(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
ObjectClass *oc = (ObjectClass *)a;
|
||||
const char *name = b;
|
||||
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
|
||||
|
||||
if (strncasecmp(name, object_class_get_name(oc), strlen(name)) == 0 &&
|
||||
ppc_cpu_is_valid(pcc) &&
|
||||
strcmp(object_class_get_name(oc) + strlen(name),
|
||||
"-" TYPE_POWERPC_CPU) == 0) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static ObjectClass *ppc_cpu_class_by_name(const char *name);
|
||||
|
||||
static ObjectClass *ppc_cpu_class_by_alias(PowerPCCPUAlias *alias)
|
||||
{
|
||||
ObjectClass *invalid_class = (void*)ppc_cpu_class_by_alias;
|
||||
|
||||
/* Cache target class lookups in the alias table */
|
||||
if (!alias->oc) {
|
||||
alias->oc = ppc_cpu_class_by_name(alias->model);
|
||||
if (!alias->oc) {
|
||||
/* Fast check for non-existing aliases */
|
||||
alias->oc = invalid_class;
|
||||
}
|
||||
}
|
||||
|
||||
if (alias->oc == invalid_class) {
|
||||
return NULL;
|
||||
} else {
|
||||
return alias->oc;
|
||||
}
|
||||
}
|
||||
|
||||
static ObjectClass *ppc_cpu_class_by_name(const char *name)
|
||||
{
|
||||
GSList *list, *item;
|
||||
ObjectClass *ret = NULL;
|
||||
char *cpu_model, *typename;
|
||||
ObjectClass *oc;
|
||||
const char *p;
|
||||
int i, len;
|
||||
unsigned long pvr;
|
||||
|
||||
/* Check if the given name is a PVR */
|
||||
len = strlen(name);
|
||||
if (len == 10 && name[0] == '0' && name[1] == 'x') {
|
||||
p = name + 2;
|
||||
goto check_pvr;
|
||||
} else if (len == 8) {
|
||||
p = name;
|
||||
check_pvr:
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (!qemu_isxdigit(*p++))
|
||||
break;
|
||||
}
|
||||
if (i == 8) {
|
||||
return OBJECT_CLASS(ppc_cpu_class_by_pvr(strtoul(name, NULL, 16)));
|
||||
/* Lookup by PVR if cpu_model is valid 8 digit hex number
|
||||
* (excl: 0x prefix if present)
|
||||
*/
|
||||
if (!qemu_strtoul(name, &p, 16, &pvr)) {
|
||||
int len = p - name;
|
||||
len = (len == 10) && (name[1] == 'x') ? len - 2 : len;
|
||||
if ((len == 8) && (*p == '\0')) {
|
||||
return OBJECT_CLASS(ppc_cpu_class_by_pvr(pvr));
|
||||
}
|
||||
}
|
||||
|
||||
list = object_class_get_list(TYPE_POWERPC_CPU, false);
|
||||
item = g_slist_find_custom(list, name, ppc_cpu_compare_class_name);
|
||||
if (item != NULL) {
|
||||
ret = OBJECT_CLASS(item->data);
|
||||
}
|
||||
g_slist_free(list);
|
||||
|
||||
if (ret) {
|
||||
return ret;
|
||||
cpu_model = g_ascii_strdown(name, -1);
|
||||
p = ppc_cpu_lookup_alias(cpu_model);
|
||||
if (p) {
|
||||
g_free(cpu_model);
|
||||
cpu_model = g_strdup(p);
|
||||
}
|
||||
|
||||
for (i = 0; ppc_cpu_aliases[i].alias != NULL; i++) {
|
||||
if (strcmp(ppc_cpu_aliases[i].alias, name) == 0) {
|
||||
return ppc_cpu_class_by_alias(&ppc_cpu_aliases[i]);
|
||||
}
|
||||
typename = g_strdup_printf("%s" POWERPC_CPU_TYPE_SUFFIX, cpu_model);
|
||||
oc = object_class_by_name(typename);
|
||||
g_free(typename);
|
||||
g_free(cpu_model);
|
||||
|
||||
if (oc && ppc_cpu_is_valid(POWERPC_CPU_CLASS(oc))) {
|
||||
return oc;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
@ -10327,12 +10346,12 @@ static void ppc_cpu_list_entry(gpointer data, gpointer user_data)
|
|||
}
|
||||
|
||||
name = g_strndup(typename,
|
||||
strlen(typename) - strlen("-" TYPE_POWERPC_CPU));
|
||||
strlen(typename) - strlen(POWERPC_CPU_TYPE_SUFFIX));
|
||||
(*s->cpu_fprintf)(s->file, "PowerPC %-16s PVR %08x\n",
|
||||
name, pcc->pvr);
|
||||
for (i = 0; ppc_cpu_aliases[i].alias != NULL; i++) {
|
||||
PowerPCCPUAlias *alias = &ppc_cpu_aliases[i];
|
||||
ObjectClass *alias_oc = ppc_cpu_class_by_alias(alias);
|
||||
ObjectClass *alias_oc = ppc_cpu_class_by_name(alias->model);
|
||||
|
||||
if (alias_oc != oc) {
|
||||
continue;
|
||||
|
@ -10388,7 +10407,7 @@ static void ppc_cpu_defs_entry(gpointer data, gpointer user_data)
|
|||
typename = object_class_get_name(oc);
|
||||
info = g_malloc0(sizeof(*info));
|
||||
info->name = g_strndup(typename,
|
||||
strlen(typename) - strlen("-" TYPE_POWERPC_CPU));
|
||||
strlen(typename) - strlen(POWERPC_CPU_TYPE_SUFFIX));
|
||||
|
||||
entry = g_malloc0(sizeof(*entry));
|
||||
entry->value = info;
|
||||
|
@ -10412,7 +10431,7 @@ CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
|
|||
CpuDefinitionInfoList *entry;
|
||||
CpuDefinitionInfo *info;
|
||||
|
||||
oc = ppc_cpu_class_by_alias(alias);
|
||||
oc = ppc_cpu_class_by_name(alias->model);
|
||||
if (oc == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
@ -10544,6 +10563,7 @@ static void ppc_cpu_initfn(Object *obj)
|
|||
CPUPPCState *env = &cpu->env;
|
||||
|
||||
cs->env_ptr = env;
|
||||
cpu->vcpu_id = UNASSIGNED_CPU_INDEX;
|
||||
|
||||
env->msr_mask = pcc->msr_mask;
|
||||
env->mmu_model = pcc->mmu_model;
|
||||
|
|
Loading…
Reference in a new issue