diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2017-09-08 14:44:44 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2017-09-08 14:44:44 +0100 |
commit | a1ae46d1b4f2a95ad5d3da8d15bc6403bcdbb24a (patch) | |
tree | b2d02f48aa15e70cecc4c61401634d122d408035 /hw | |
parent | 74bbfe024da80a50dbe51fbb17f219d2f3e4d2dd (diff) | |
parent | 7cca3e466eb0baa36d1cc29d5aeb5da74a260711 (diff) |
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>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/i2c/Makefile.objs | 1 | ||||
-rw-r--r-- | hw/i2c/ppc4xx_i2c.c | 216 | ||||
-rw-r--r-- | hw/nvram/spapr_nvram.c | 2 | ||||
-rw-r--r-- | hw/ppc/e500.c | 8 | ||||
-rw-r--r-- | hw/ppc/ppc.c | 21 | ||||
-rw-r--r-- | hw/ppc/ppc405.h | 3 | ||||
-rw-r--r-- | hw/ppc/ppc405_uc.c | 515 | ||||
-rw-r--r-- | hw/ppc/ppc4xx_devs.c | 227 | ||||
-rw-r--r-- | hw/ppc/spapr.c | 166 | ||||
-rw-r--r-- | hw/ppc/spapr_cpu_core.c | 40 | ||||
-rw-r--r-- | hw/ppc/spapr_drc.c | 37 | ||||
-rw-r--r-- | hw/ppc/spapr_events.c | 11 | ||||
-rw-r--r-- | hw/ppc/spapr_hcall.c | 22 | ||||
-rw-r--r-- | hw/ppc/spapr_iommu.c | 57 | ||||
-rw-r--r-- | hw/ppc/spapr_pci.c | 6 | ||||
-rw-r--r-- | hw/ppc/spapr_rtas.c | 4 |
16 files changed, 727 insertions, 609 deletions
diff --git a/hw/i2c/Makefile.objs b/hw/i2c/Makefile.objs index a081b8ef2c..0594dea3ae 100644 --- a/hw/i2c/Makefile.objs +++ b/hw/i2c/Makefile.objs @@ -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 diff --git a/hw/i2c/ppc4xx_i2c.c b/hw/i2c/ppc4xx_i2c.c new file mode 100644 index 0000000000..5a6bde951e --- /dev/null +++ b/hw/i2c/ppc4xx_i2c.c @@ -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) diff --git a/hw/nvram/spapr_nvram.c b/hw/nvram/spapr_nvram.c index bc355a4348..4a0aec8e1d 100644 --- a/hw/nvram/spapr_nvram.c +++ b/hw/nvram/spapr_nvram.c @@ -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 = { diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index f0596f34ff..55cad780f4 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -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", diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c index 224184d66d..f76886f4d3 100644 --- a/hw/ppc/ppc.c +++ b/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; diff --git a/hw/ppc/ppc405.h b/hw/ppc/ppc405.h index a9ffc87f19..7ed25cfa1b 100644 --- a/hw/ppc/ppc405.h +++ b/hw/ppc/ppc405.h @@ -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], diff --git a/hw/ppc/ppc405_uc.c b/hw/ppc/ppc405_uc.c index f6fe3e6f5e..e621d0aec5 100644 --- a/hw/ppc/ppc405_uc.c +++ b/hw/ppc/ppc405_uc.c @@ -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; @@ -994,246 +993,6 @@ static void ppc405_ocm_init(CPUPPCState *env) } /*****************************************************************************/ -/* 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; struct ppc4xx_gpt_t { @@ -1513,268 +1272,6 @@ static void ppc4xx_gpt_init(hwaddr base, qemu_irq irqs[5]) } /*****************************************************************************/ -/* 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 */ diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c index 6b38ed7bc7..ec90f13295 100644 --- a/hw/ppc/ppc4xx_devs.c +++ b/hw/ppc/ppc4xx_devs.c @@ -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); + } +} diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index cec441cbf4..caffa12763 100644 --- a/hw/ppc/spapr.c +++ b/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); @@ -3538,18 +3664,36 @@ 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 diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index ea278ce2a7..85037ef71e 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -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[] = { diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 605697d8bd..915e9b51c4 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -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); } diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c index f952b78237..66b8164f30 100644 --- a/hw/ppc/spapr_events.c +++ b/hw/ppc/spapr_events.c @@ -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); diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 07b3da8dc4..8b3c0e17e7 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -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; } } diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c index ed2d53559a..fa8b969840 100644 --- a/hw/ppc/spapr_iommu.c +++ b/hw/ppc/spapr_iommu.c @@ -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; - } - - newtable = g_malloc(table_size); - memcpy(newtable, tcet->table, table_size); + 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); - kvmppc_remove_spapr_tce(tcet->table, tcet->fd, tcet->nb_table); + spapr_tce_free_table(oldtable, 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 */ diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index d84abf1070..d7880f257a 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -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); diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index 94a2799b99..cdf0b607a0 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -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; |