diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2017-06-13 15:49:07 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2017-06-13 15:49:07 +0100 |
commit | 3f0602927b120a480b35dcf58cf6f95435b3ae91 (patch) | |
tree | 1fbc5246de0adb98a9800000374a3a1e977e0c6b | |
parent | 6f153ceb9bb8233dd3887320737aba90554ddd70 (diff) | |
parent | 252a7a6a968c279a4636a86b0559ba3a930a90b5 (diff) |
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20170613' into staging
target-arm queue:
* vITS: Support save/restore
* timer/aspeed: Fix timer enablement when reload is not set
* aspped: add temperature sensor device
* timer.h: Provide better monotonic time on ARM hosts
* exynos4210: various cleanups
* exynos4210: support system poweroff
# gpg: Signature made Tue 13 Jun 2017 15:05:49 BST
# gpg: using RSA key 0x3C2525ED14360CDE
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>"
# gpg: aka "Peter Maydell <pmaydell@gmail.com>"
# gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>"
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE
* remotes/pmaydell/tags/pull-target-arm-20170613:
hw/intc/arm_gicv3_its: Allow save/restore
hw/intc/arm_gicv3_kvm: Implement pending table save
hw/intc/arm_gicv3_its: Implement state save/restore
kvm-all: Pass an error object to kvm_device_access
timer/aspeed: fix timer enablement when a reload is not set
aspeed: add a temp sensor device on I2C bus 3
hw/misc: add a TMP42{1, 2, 3} device model
timer.h: Provide better monotonic time
hw/misc/exynos4210_pmu: Add support for system poweroff
hw/intc/exynos4210_gic: Constify array of combiner interrupts
hw/arm/exynos: Use type define instead of hard-coded a9mpcore_priv string
hw/arm/exynos: Declare local variables in some order
hw/arm/exynos: Move DRAM initialization next boards
hw/timer/exynos4210_mct: Remove unused defines
hw/timer/exynos4210_mct: Cleanup indentation and empty new lines
hw/timer/exynos4210_mct: Fix checkpatch style errors
hw/intc/exynos4210_gic: Use more meaningful name for local variable
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | default-configs/arm-softmmu.mak | 1 | ||||
-rw-r--r-- | hw/arm/aspeed.c | 9 | ||||
-rw-r--r-- | hw/arm/exynos4210.c | 27 | ||||
-rw-r--r-- | hw/arm/exynos4_boards.c | 50 | ||||
-rw-r--r-- | hw/intc/arm_gic_kvm.c | 9 | ||||
-rw-r--r-- | hw/intc/arm_gicv3_common.c | 1 | ||||
-rw-r--r-- | hw/intc/arm_gicv3_its_common.c | 12 | ||||
-rw-r--r-- | hw/intc/arm_gicv3_its_kvm.c | 131 | ||||
-rw-r--r-- | hw/intc/arm_gicv3_kvm.c | 48 | ||||
-rw-r--r-- | hw/intc/exynos4210_gic.c | 14 | ||||
-rw-r--r-- | hw/misc/Makefile.objs | 1 | ||||
-rw-r--r-- | hw/misc/exynos4210_pmu.c | 20 | ||||
-rw-r--r-- | hw/misc/tmp421.c | 402 | ||||
-rw-r--r-- | hw/timer/aspeed_timer.c | 37 | ||||
-rw-r--r-- | hw/timer/exynos4210_mct.c | 50 | ||||
-rw-r--r-- | include/hw/arm/exynos4210.h | 5 | ||||
-rw-r--r-- | include/hw/intc/arm_gicv3_its_common.h | 8 | ||||
-rw-r--r-- | include/migration/vmstate.h | 2 | ||||
-rw-r--r-- | include/qemu/timer.h | 5 | ||||
-rw-r--r-- | include/sysemu/kvm.h | 11 | ||||
-rw-r--r-- | kvm-all.c | 14 |
21 files changed, 741 insertions, 116 deletions
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index 78d7af03a2..93e995d318 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -15,6 +15,7 @@ CONFIG_TWL92230=y CONFIG_TSC2005=y CONFIG_LM832X=y CONFIG_TMP105=y +CONFIG_TMP421=y CONFIG_STELLARIS=y CONFIG_STELLARIS_INPUT=y CONFIG_STELLARIS_ENET=y diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index e824ea87a9..155eeb242b 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -239,10 +239,19 @@ static void aspeed_board_init(MachineState *machine, static void palmetto_bmc_i2c_init(AspeedBoardState *bmc) { AspeedSoCState *soc = &bmc->soc; + DeviceState *dev; /* The palmetto platform expects a ds3231 RTC but a ds1338 is * enough to provide basic RTC features. Alarms will be missing */ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 0), "ds1338", 0x68); + + /* add a TMP423 temperature sensor */ + dev = i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 2), + "tmp423", 0x4c); + object_property_set_int(OBJECT(dev), 31000, "temperature0", &error_abort); + object_property_set_int(OBJECT(dev), 28000, "temperature1", &error_abort); + object_property_set_int(OBJECT(dev), 20000, "temperature2", &error_abort); + object_property_set_int(OBJECT(dev), 110000, "temperature3", &error_abort); } static void palmetto_bmc_init(MachineState *machine) diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c index 960f27e45a..0050626a69 100644 --- a/hw/arm/exynos4210.c +++ b/hw/arm/exynos4210.c @@ -26,6 +26,7 @@ #include "qemu-common.h" #include "qemu/log.h" #include "cpu.h" +#include "hw/cpu/a9mpcore.h" #include "hw/boards.h" #include "sysemu/sysemu.h" #include "hw/sysbus.h" @@ -160,16 +161,14 @@ static uint64_t exynos4210_calc_affinity(int cpu) return mp_affinity; } -Exynos4210State *exynos4210_init(MemoryRegion *system_mem, - unsigned long ram_size) +Exynos4210State *exynos4210_init(MemoryRegion *system_mem) { - int i, n; Exynos4210State *s = g_new(Exynos4210State, 1); qemu_irq gate_irq[EXYNOS4210_NCPUS][EXYNOS4210_IRQ_GATE_NINPUTS]; - unsigned long mem_size; - DeviceState *dev; SysBusDevice *busdev; ObjectClass *cpu_oc; + DeviceState *dev; + int i, n; cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, "cortex-a9"); assert(cpu_oc); @@ -213,7 +212,7 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem, } /* Private memory region and Internal GIC */ - dev = qdev_create(NULL, "a9mpcore_priv"); + dev = qdev_create(NULL, TYPE_A9MPCORE_PRIV); qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS); qdev_init_nofail(dev); busdev = SYS_BUS_DEVICE(dev); @@ -299,22 +298,6 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem, memory_region_add_subregion(system_mem, EXYNOS4210_IRAM_BASE_ADDR, &s->iram_mem); - /* DRAM */ - mem_size = ram_size; - if (mem_size > EXYNOS4210_DRAM_MAX_SIZE) { - memory_region_init_ram(&s->dram1_mem, NULL, "exynos4210.dram1", - mem_size - EXYNOS4210_DRAM_MAX_SIZE, &error_fatal); - vmstate_register_ram_global(&s->dram1_mem); - memory_region_add_subregion(system_mem, EXYNOS4210_DRAM1_BASE_ADDR, - &s->dram1_mem); - mem_size = EXYNOS4210_DRAM_MAX_SIZE; - } - memory_region_init_ram(&s->dram0_mem, NULL, "exynos4210.dram0", mem_size, - &error_fatal); - vmstate_register_ram_global(&s->dram0_mem); - memory_region_add_subregion(system_mem, EXYNOS4210_DRAM0_BASE_ADDR, - &s->dram0_mem); - /* PMU. * The only reason of existence at the moment is that secondary CPU boot * loader uses PMU INFORM5 register as a holding pen. diff --git a/hw/arm/exynos4_boards.c b/hw/arm/exynos4_boards.c index 4853c31802..6240b26839 100644 --- a/hw/arm/exynos4_boards.c +++ b/hw/arm/exynos4_boards.c @@ -22,6 +22,7 @@ */ #include "qemu/osdep.h" +#include "qapi/error.h" #include "qemu/error-report.h" #include "qemu-common.h" #include "cpu.h" @@ -56,6 +57,12 @@ typedef enum Exynos4BoardType { EXYNOS4_NUM_OF_BOARDS } Exynos4BoardType; +typedef struct Exynos4BoardState { + Exynos4210State *soc; + MemoryRegion dram0_mem; + MemoryRegion dram1_mem; +} Exynos4BoardState; + static int exynos4_board_id[EXYNOS4_NUM_OF_BOARDS] = { [EXYNOS4_BOARD_NURI] = 0xD33, [EXYNOS4_BOARD_SMDKC210] = 0xB16, @@ -96,9 +103,34 @@ static void lan9215_init(uint32_t base, qemu_irq irq) } } -static Exynos4210State *exynos4_boards_init_common(MachineState *machine, - Exynos4BoardType board_type) +static void exynos4_boards_init_ram(Exynos4BoardState *s, + MemoryRegion *system_mem, + unsigned long ram_size) +{ + unsigned long mem_size = ram_size; + + if (mem_size > EXYNOS4210_DRAM_MAX_SIZE) { + memory_region_init_ram(&s->dram1_mem, NULL, "exynos4210.dram1", + mem_size - EXYNOS4210_DRAM_MAX_SIZE, + &error_fatal); + vmstate_register_ram_global(&s->dram1_mem); + memory_region_add_subregion(system_mem, EXYNOS4210_DRAM1_BASE_ADDR, + &s->dram1_mem); + mem_size = EXYNOS4210_DRAM_MAX_SIZE; + } + + memory_region_init_ram(&s->dram0_mem, NULL, "exynos4210.dram0", mem_size, + &error_fatal); + vmstate_register_ram_global(&s->dram0_mem); + memory_region_add_subregion(system_mem, EXYNOS4210_DRAM0_BASE_ADDR, + &s->dram0_mem); +} + +static Exynos4BoardState * +exynos4_boards_init_common(MachineState *machine, + Exynos4BoardType board_type) { + Exynos4BoardState *s = g_new(Exynos4BoardState, 1); MachineClass *mc = MACHINE_GET_CLASS(machine); if (smp_cpus != EXYNOS4210_NCPUS && !qtest_enabled()) { @@ -127,8 +159,12 @@ static Exynos4210State *exynos4_boards_init_common(MachineState *machine, machine->kernel_cmdline, machine->initrd_filename); - return exynos4210_init(get_system_memory(), - exynos4_board_ram_size[board_type]); + exynos4_boards_init_ram(s, get_system_memory(), + exynos4_board_ram_size[board_type]); + + s->soc = exynos4210_init(get_system_memory()); + + return s; } static void nuri_init(MachineState *machine) @@ -140,11 +176,11 @@ static void nuri_init(MachineState *machine) static void smdkc210_init(MachineState *machine) { - Exynos4210State *s = exynos4_boards_init_common(machine, - EXYNOS4_BOARD_SMDKC210); + Exynos4BoardState *s = exynos4_boards_init_common(machine, + EXYNOS4_BOARD_SMDKC210); lan9215_init(SMDK_LAN9118_BASE_ADDR, - qemu_irq_invert(s->irq_table[exynos4210_get_irq(37, 1)])); + qemu_irq_invert(s->soc->irq_table[exynos4210_get_irq(37, 1)])); arm_load_kernel(ARM_CPU(first_cpu), &exynos4_board_binfo); } diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index af5cd367e9..ae095d08a3 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -100,14 +100,14 @@ static void kvm_gicd_access(GICState *s, int offset, int cpu, uint32_t *val, bool write) { kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS, - KVM_VGIC_ATTR(offset, cpu), val, write); + KVM_VGIC_ATTR(offset, cpu), val, write, &error_abort); } static void kvm_gicc_access(GICState *s, int offset, int cpu, uint32_t *val, bool write) { kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_REGS, - KVM_VGIC_ATTR(offset, cpu), val, write); + KVM_VGIC_ATTR(offset, cpu), val, write, &error_abort); } #define for_each_irq_reg(_ctr, _max_irq, _field_width) \ @@ -538,13 +538,14 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0)) { uint32_t numirqs = s->num_irq; kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0, - &numirqs, true); + &numirqs, true, &error_abort); } /* Tell the kernel to complete VGIC initialization now */ if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, KVM_DEV_ARM_VGIC_CTRL_INIT)) { kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, - KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true); + KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true, + &error_abort); } } else if (ret != -ENODEV && ret != -ENOTSUP) { error_setg_errno(errp, -ret, "error creating in-kernel VGIC"); diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c index c6493d6c07..4228b7ca00 100644 --- a/hw/intc/arm_gicv3_common.c +++ b/hw/intc/arm_gicv3_common.c @@ -145,6 +145,7 @@ static const VMStateDescription vmstate_gicv3 = { .minimum_version_id = 1, .pre_save = gicv3_pre_save, .post_load = gicv3_post_load, + .priority = MIG_PRI_GICV3, .fields = (VMStateField[]) { VMSTATE_UINT32(gicd_ctlr, GICv3State), VMSTATE_UINT32_ARRAY(gicd_statusr, GICv3State, 2), diff --git a/hw/intc/arm_gicv3_its_common.c b/hw/intc/arm_gicv3_its_common.c index 9d67c5c1ee..68b20fccd1 100644 --- a/hw/intc/arm_gicv3_its_common.c +++ b/hw/intc/arm_gicv3_its_common.c @@ -48,7 +48,16 @@ static const VMStateDescription vmstate_its = { .name = "arm_gicv3_its", .pre_save = gicv3_its_pre_save, .post_load = gicv3_its_post_load, - .unmigratable = true, + .priority = MIG_PRI_GICV3_ITS, + .fields = (VMStateField[]) { + VMSTATE_UINT32(ctlr, GICv3ITSState), + VMSTATE_UINT32(iidr, GICv3ITSState), + VMSTATE_UINT64(cbaser, GICv3ITSState), + VMSTATE_UINT64(cwriter, GICv3ITSState), + VMSTATE_UINT64(creadr, GICv3ITSState), + VMSTATE_UINT64_ARRAY(baser, GICv3ITSState, 8), + VMSTATE_END_OF_LIST() + }, }; static MemTxResult gicv3_its_trans_read(void *opaque, hwaddr offset, @@ -118,6 +127,7 @@ static void gicv3_its_common_reset(DeviceState *dev) s->cbaser = 0; s->cwriter = 0; s->creadr = 0; + s->iidr = 0; memset(&s->baser, 0, sizeof(s->baser)); gicv3_its_post_load(s, 0); diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c index a0441d6bd1..1f8991b8a6 100644 --- a/hw/intc/arm_gicv3_its_kvm.c +++ b/hw/intc/arm_gicv3_its_kvm.c @@ -53,23 +53,38 @@ static int kvm_its_send_msi(GICv3ITSState *s, uint32_t value, uint16_t devid) return kvm_vm_ioctl(kvm_state, KVM_SIGNAL_MSI, &msi); } -static void kvm_arm_its_realize(DeviceState *dev, Error **errp) +/** + * vm_change_state_handler - VM change state callback aiming at flushing + * ITS tables into guest RAM + * + * The tables get flushed to guest RAM whenever the VM gets stopped. + */ +static void vm_change_state_handler(void *opaque, int running, + RunState state) { - GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev); - Error *local_err = NULL; + GICv3ITSState *s = (GICv3ITSState *)opaque; + Error *err = NULL; + int ret; - /* - * Block migration of a KVM GICv3 ITS device: the API for saving and - * restoring the state in the kernel is not yet available - */ - error_setg(&s->migration_blocker, "vITS migration is not implemented"); - migrate_add_blocker(s->migration_blocker, &local_err); - if (local_err) { - error_propagate(errp, local_err); - error_free(s->migration_blocker); + if (running) { return; } + ret = kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, + KVM_DEV_ARM_ITS_SAVE_TABLES, NULL, true, &err); + if (err) { + error_report_err(err); + } + if (ret < 0 && ret != -EFAULT) { + abort(); + } +} + +static void kvm_arm_its_realize(DeviceState *dev, Error **errp) +{ + GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev); + Error *local_err = NULL; + s->dev_fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_ITS, false); if (s->dev_fd < 0) { error_setg_errno(errp, -s->dev_fd, "error creating in-kernel ITS"); @@ -78,7 +93,7 @@ static void kvm_arm_its_realize(DeviceState *dev, Error **errp) /* explicit init of the ITS */ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, - KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true); + KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true, &error_abort); /* register the base address */ kvm_arm_register_device(&s->iomem_its_cntrl, -1, KVM_DEV_ARM_VGIC_GRP_ADDR, @@ -86,9 +101,23 @@ static void kvm_arm_its_realize(DeviceState *dev, Error **errp) gicv3_its_init_mmio(s, NULL); + if (!kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_CTLR)) { + error_setg(&s->migration_blocker, "This operating system kernel " + "does not support vITS migration"); + migrate_add_blocker(s->migration_blocker, &local_err); + if (local_err) { + error_propagate(errp, local_err); + error_free(s->migration_blocker); + return; + } + } + kvm_msi_use_devid = true; kvm_gsi_direct_mapping = false; kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled(); + + qemu_add_vm_change_state_handler(vm_change_state_handler, s); } static void kvm_arm_its_init(Object *obj) @@ -102,6 +131,80 @@ static void kvm_arm_its_init(Object *obj) &error_abort); } +/** + * kvm_arm_its_pre_save - handles the saving of ITS registers. + * ITS tables are flushed into guest RAM separately and earlier, + * through the VM change state handler, since at the moment pre_save() + * is called, the guest RAM has already been saved. + */ +static void kvm_arm_its_pre_save(GICv3ITSState *s) +{ + int i; + + for (i = 0; i < 8; i++) { + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_BASER + i * 8, &s->baser[i], false, + &error_abort); + } + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_CTLR, &s->ctlr, false, &error_abort); + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_CBASER, &s->cbaser, false, &error_abort); + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_CREADR, &s->creadr, false, &error_abort); + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_CWRITER, &s->cwriter, false, &error_abort); + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_IIDR, &s->iidr, false, &error_abort); +} + +/** + * kvm_arm_its_post_load - Restore both the ITS registers and tables + */ +static void kvm_arm_its_post_load(GICv3ITSState *s) +{ + int i; + + if (!s->iidr) { + return; + } + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_IIDR, &s->iidr, true, &error_abort); + + /* + * must be written before GITS_CREADR since GITS_CBASER write + * access resets GITS_CREADR. + */ + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_CBASER, &s->cbaser, true, &error_abort); + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_CREADR, &s->creadr, true, &error_abort); + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_CWRITER, &s->cwriter, true, &error_abort); + + + for (i = 0; i < 8; i++) { + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_BASER + i * 8, &s->baser[i], true, + &error_abort); + } + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, + KVM_DEV_ARM_ITS_RESTORE_TABLES, NULL, true, + &error_abort); + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_CTLR, &s->ctlr, true, &error_abort); +} + static void kvm_arm_its_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -109,6 +212,8 @@ static void kvm_arm_its_class_init(ObjectClass *klass, void *data) dc->realize = kvm_arm_its_realize; icc->send_msi = kvm_its_send_msi; + icc->pre_save = kvm_arm_its_pre_save; + icc->post_load = kvm_arm_its_post_load; } static const TypeInfo kvm_arm_its_info = { diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c index 4ee2baa691..6051c77705 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c @@ -25,6 +25,7 @@ #include "hw/sysbus.h" #include "qemu/error-report.h" #include "sysemu/kvm.h" +#include "sysemu/sysemu.h" #include "kvm_arm.h" #include "gicv3_internal.h" #include "vgic_common.h" @@ -93,7 +94,7 @@ static inline void kvm_gicd_access(GICv3State *s, int offset, { kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS, KVM_VGIC_ATTR(offset, 0), - val, write); + val, write, &error_abort); } static inline void kvm_gicr_access(GICv3State *s, int offset, int cpu, @@ -101,7 +102,7 @@ static inline void kvm_gicr_access(GICv3State *s, int offset, int cpu, { kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS, KVM_VGIC_ATTR(offset, s->cpu[cpu].gicr_typer), - val, write); + val, write, &error_abort); } static inline void kvm_gicc_access(GICv3State *s, uint64_t reg, int cpu, @@ -109,7 +110,7 @@ static inline void kvm_gicc_access(GICv3State *s, uint64_t reg, int cpu, { kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS, KVM_VGIC_ATTR(reg, s->cpu[cpu].gicr_typer), - val, write); + val, write, &error_abort); } static inline void kvm_gic_line_level_access(GICv3State *s, int irq, int cpu, @@ -119,7 +120,7 @@ static inline void kvm_gic_line_level_access(GICv3State *s, int irq, int cpu, KVM_VGIC_ATTR(irq, s->cpu[cpu].gicr_typer) | (VGIC_LEVEL_INFO_LINE_LEVEL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT), - val, write); + val, write, &error_abort); } /* Loop through each distributor IRQ related register; since bits @@ -630,7 +631,7 @@ static void arm_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri) /* Initialize to actual HW supported configuration */ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS, KVM_VGIC_ATTR(ICC_CTLR_EL1, cpu->mp_affinity), - &c->icc_ctlr_el1[GICV3_NS], false); + &c->icc_ctlr_el1[GICV3_NS], false, &error_abort); c->icc_ctlr_el1[GICV3_S] = c->icc_ctlr_el1[GICV3_NS]; } @@ -680,6 +681,35 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = { REGINFO_SENTINEL }; +/** + * vm_change_state_handler - VM change state callback aiming at flushing + * RDIST pending tables into guest RAM + * + * The tables get flushed to guest RAM whenever the VM gets stopped. + */ +static void vm_change_state_handler(void *opaque, int running, + RunState state) +{ + GICv3State *s = (GICv3State *)opaque; + Error *err = NULL; + int ret; + + if (running) { + return; + } + + ret = kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, + KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES, + NULL, true, &err); + if (err) { + error_report_err(err); + } + if (ret < 0 && ret != -EFAULT) { + abort(); + } +} + + static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) { GICv3State *s = KVM_ARM_GICV3(dev); @@ -717,11 +747,11 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) } kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, - 0, &s->num_irq, true); + 0, &s->num_irq, true, &error_abort); /* Tell the kernel to complete VGIC initialization now */ kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, - KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true); + KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true, &error_abort); kvm_arm_register_device(&s->iomem_dist, -1, KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V3_ADDR_TYPE_DIST, s->dev_fd); @@ -751,6 +781,10 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) return; } } + if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, + KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES)) { + qemu_add_vm_change_state_handler(vm_change_state_handler, s); + } } static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data) diff --git a/hw/intc/exynos4210_gic.c b/hw/intc/exynos4210_gic.c index 2a55817b76..b6b00a4f58 100644 --- a/hw/intc/exynos4210_gic.c +++ b/hw/intc/exynos4210_gic.c @@ -116,7 +116,7 @@ enum ExtInt { * which is INTG16 in Internal Interrupt Combiner. */ -static uint32_t +static const uint32_t combiner_grp_to_gic_id[64-EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][8] = { /* int combiner groups 16-19 */ { }, { }, { }, { }, @@ -286,21 +286,21 @@ static void exynos4210_gic_init(Object *obj) DeviceState *dev = DEVICE(obj); Exynos4210GicState *s = EXYNOS4210_GIC(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - uint32_t i; const char cpu_prefix[] = "exynos4210-gic-alias_cpu"; const char dist_prefix[] = "exynos4210-gic-alias_dist"; char cpu_alias_name[sizeof(cpu_prefix) + 3]; char dist_alias_name[sizeof(cpu_prefix) + 3]; - SysBusDevice *busdev; + SysBusDevice *gicbusdev; + uint32_t i; s->gic = qdev_create(NULL, "arm_gic"); qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu); qdev_prop_set_uint32(s->gic, "num-irq", EXYNOS4210_GIC_NIRQ); qdev_init_nofail(s->gic); - busdev = SYS_BUS_DEVICE(s->gic); + gicbusdev = SYS_BUS_DEVICE(s->gic); /* Pass through outbound IRQ lines from the GIC */ - sysbus_pass_irq(sbd, busdev); + sysbus_pass_irq(sbd, gicbusdev); /* Pass through inbound GPIO lines to the GIC */ qdev_init_gpio_in(dev, exynos4210_gic_set_irq, @@ -316,7 +316,7 @@ static void exynos4210_gic_init(Object *obj) sprintf(cpu_alias_name, "%s%x", cpu_prefix, i); memory_region_init_alias(&s->cpu_alias[i], obj, cpu_alias_name, - sysbus_mmio_get_region(busdev, 1), + sysbus_mmio_get_region(gicbusdev, 1), 0, EXYNOS4210_GIC_CPU_REGION_SIZE); memory_region_add_subregion(&s->cpu_container, @@ -326,7 +326,7 @@ static void exynos4210_gic_init(Object *obj) sprintf(dist_alias_name, "%s%x", dist_prefix, i); memory_region_init_alias(&s->dist_alias[i], obj, dist_alias_name, - sysbus_mmio_get_region(busdev, 0), + sysbus_mmio_get_region(gicbusdev, 0), 0, EXYNOS4210_GIC_DIST_REGION_SIZE); memory_region_add_subregion(&s->dist_container, diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index c8b489390f..20198466f0 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -1,6 +1,7 @@ common-obj-$(CONFIG_APPLESMC) += applesmc.o common-obj-$(CONFIG_MAX111X) += max111x.o common-obj-$(CONFIG_TMP105) += tmp105.o +common-obj-$(CONFIG_TMP421) += tmp421.o common-obj-$(CONFIG_ISA_DEBUG) += debugexit.o common-obj-$(CONFIG_SGA) += sga.o common-obj-$(CONFIG_ISA_TESTDEV) += pc-testdev.o diff --git a/hw/misc/exynos4210_pmu.c b/hw/misc/exynos4210_pmu.c index 63a8ccd355..0d7b64c5b3 100644 --- a/hw/misc/exynos4210_pmu.c +++ b/hw/misc/exynos4210_pmu.c @@ -26,6 +26,7 @@ #include "qemu/osdep.h" #include "hw/sysbus.h" +#include "sysemu/sysemu.h" #ifndef DEBUG_PMU #define DEBUG_PMU 0 @@ -350,7 +351,11 @@ static const Exynos4210PmuReg exynos4210_pmu_regs[] = { {"PAD_RETENTION_MMCB_OPTION", PAD_RETENTION_MMCB_OPTION, 0x00000000}, {"PAD_RETENTION_EBIA_OPTION", PAD_RETENTION_EBIA_OPTION, 0x00000000}, {"PAD_RETENTION_EBIB_OPTION", PAD_RETENTION_EBIB_OPTION, 0x00000000}, - {"PS_HOLD_CONTROL", PS_HOLD_CONTROL, 0x00005200}, + /* + * PS_HOLD_CONTROL: reset value and manually toggle high the DATA bit. + * DATA bit high, set usually by bootloader, keeps system on. + */ + {"PS_HOLD_CONTROL", PS_HOLD_CONTROL, 0x00005200 | BIT(8)}, {"XUSBXTI_CONFIGURATION", XUSBXTI_CONFIGURATION, 0x00000001}, {"XUSBXTI_STATUS", XUSBXTI_STATUS, 0x00000001}, {"XUSBXTI_DURATION", XUSBXTI_DURATION, 0xFFF00000}, @@ -397,6 +402,12 @@ typedef struct Exynos4210PmuState { uint32_t reg[PMU_NUM_OF_REGISTERS]; } Exynos4210PmuState; +static void exynos4210_pmu_poweroff(void) +{ + PRINT_DEBUG("QEMU PMU: PS_HOLD bit down, powering off\n"); + qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); +} + static uint64_t exynos4210_pmu_read(void *opaque, hwaddr offset, unsigned size) { @@ -428,6 +439,13 @@ static void exynos4210_pmu_write(void *opaque, hwaddr offset, PRINT_DEBUG_EXTEND("%s <0x%04x> <- 0x%04x\n", reg_p->name, (uint32_t)offset, (uint32_t)val); s->reg[i] = val; + if ((offset == PS_HOLD_CONTROL) && ((val & BIT(8)) == 0)) { + /* + * We are interested only in setting data bit + * of PS_HOLD_CONTROL register to indicate power off request. + */ + exynos4210_pmu_poweroff(); + } return; } reg_p++; diff --git a/hw/misc/tmp421.c b/hw/misc/tmp421.c new file mode 100644 index 0000000000..4a505abbce --- /dev/null +++ b/hw/misc/tmp421.c @@ -0,0 +1,402 @@ +/* + * Texas Instruments TMP421 temperature sensor. + * + * Copyright (c) 2016 IBM Corporation. + * + * Largely inspired by : + * + * Texas Instruments TMP105 temperature sensor. + * + * Copyright (C) 2008 Nokia Corporation + * Written by Andrzej Zaborowski <andrew@openedhand.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "hw/hw.h" +#include "hw/i2c/i2c.h" +#include "qapi/error.h" +#include "qapi/visitor.h" + +/* Manufacturer / Device ID's */ +#define TMP421_MANUFACTURER_ID 0x55 +#define TMP421_DEVICE_ID 0x21 +#define TMP422_DEVICE_ID 0x22 +#define TMP423_DEVICE_ID 0x23 + +typedef struct DeviceInfo { + int model; + const char *name; +} DeviceInfo; + +static const DeviceInfo devices[] = { + { TMP421_DEVICE_ID, "tmp421" }, + { TMP422_DEVICE_ID, "tmp422" }, + { TMP423_DEVICE_ID, "tmp423" }, +}; + +typedef struct TMP421State { + /*< private >*/ + I2CSlave i2c; + /*< public >*/ + + int16_t temperature[4]; + + uint8_t status; + uint8_t config[2]; + uint8_t rate; + + uint8_t len; + uint8_t buf[2]; + uint8_t pointer; + +} TMP421State; + +typedef struct TMP421Class { + I2CSlaveClass parent_class; + DeviceInfo *dev; +} TMP421Class; + +#define TYPE_TMP421 "tmp421-generic" +#define TMP421(obj) OBJECT_CHECK(TMP421State, (obj), TYPE_TMP421) + +#define TMP421_CLASS(klass) \ + OBJECT_CLASS_CHECK(TMP421Class, (klass), TYPE_TMP421) +#define TMP421_GET_CLASS(obj) \ + OBJECT_GET_CLASS(TMP421Class, (obj), TYPE_TMP421) + +/* the TMP421 registers */ +#define TMP421_STATUS_REG 0x08 +#define TMP421_STATUS_BUSY (1 << 7) +#define TMP421_CONFIG_REG_1 0x09 +#define TMP421_CONFIG_RANGE (1 << 2) +#define TMP421_CONFIG_SHUTDOWN (1 << 6) +#define TMP421_CONFIG_REG_2 0x0A +#define TMP421_CONFIG_RC (1 << 2) +#define TMP421_CONFIG_LEN (1 << 3) +#define TMP421_CONFIG_REN (1 << 4) +#define TMP421_CONFIG_REN2 (1 << 5) +#define TMP421_CONFIG_REN3 (1 << 6) + +#define TMP421_CONVERSION_RATE_REG 0x0B +#define TMP421_ONE_SHOT 0x0F + +#define TMP421_RESET 0xFC +#define TMP421_MANUFACTURER_ID_REG 0xFE +#define TMP421_DEVICE_ID_REG 0xFF + +#define TMP421_TEMP_MSB0 0x00 +#define TMP421_TEMP_MSB1 0x01 +#define TMP421_TEMP_MSB2 0x02 +#define TMP421_TEMP_MSB3 0x03 +#define TMP421_TEMP_LSB0 0x10 +#define TMP421_TEMP_LSB1 0x11 +#define TMP421_TEMP_LSB2 0x12 +#define TMP421_TEMP_LSB3 0x13 + +static const int32_t mins[2] = { -40000, -55000 }; +static const int32_t maxs[2] = { 127000, 150000 }; + +static void tmp421_get_temperature(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + TMP421State *s = TMP421(obj); + bool ext_range = (s->config[0] & TMP421_CONFIG_RANGE); + int offset = ext_range * 64 * 256; + int64_t value; + int tempid; + + if (sscanf(name, "temperature%d", &tempid) != 1) { + error_setg(errp, "error reading %s: %m", name); + return; + } + + if (tempid >= 4 || tempid < 0) { + error_setg(errp, "error reading %s", name); + return; + } + + value = ((s->temperature[tempid] - offset) * 1000 + 128) / 256; + + visit_type_int(v, name, &value, errp); +} + +/* Units are 0.001 centigrades relative to 0 C. s->temperature is 8.8 + * fixed point, so units are 1/256 centigrades. A simple ratio will do. + */ +static void tmp421_set_temperature(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + TMP421State *s = TMP421(obj); + Error *local_err = NULL; + int64_t temp; + bool ext_range = (s->config[0] & TMP421_CONFIG_RANGE); + int offset = ext_range * 64 * 256; + int tempid; + + visit_type_int(v, name, &temp, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + if (temp >= maxs[ext_range] || temp < mins[ext_range]) { + error_setg(errp, "value %" PRId64 ".%03" PRIu64 " °C is out of range", + temp / 1000, temp % 1000); + return; + } + + if (sscanf(name, "temperature%d", &tempid) != 1) { + error_setg(errp, "error reading %s: %m", name); + return; + } + + if (tempid >= 4 || tempid < 0) { + error_setg(errp, "error reading %s", name); + return; + } + + s->temperature[tempid] = (int16_t) ((temp * 256 - 128) / 1000) + offset; +} + +static void tmp421_read(TMP421State *s) +{ + TMP421Class *sc = TMP421_GET_CLASS(s); + + s->len = 0; + + switch (s->pointer) { + case TMP421_MANUFACTURER_ID_REG: + s->buf[s->len++] = TMP421_MANUFACTURER_ID; + break; + case TMP421_DEVICE_ID_REG: + s->buf[s->len++] = sc->dev->model; + break; + case TMP421_CONFIG_REG_1: + s->buf[s->len++] = s->config[0]; + break; + case TMP421_CONFIG_REG_2: + s->buf[s->len++] = s->config[1]; + break; + case TMP421_CONVERSION_RATE_REG: + s->buf[s->len++] = s->rate; + break; + case TMP421_STATUS_REG: + s->buf[s->len++] = s->status; + break; + + /* FIXME: check for channel enablement in config registers */ + case TMP421_TEMP_MSB0: + s->buf[s->len++] = (((uint16_t) s->temperature[0]) >> 8); + s->buf[s->len++] = (((uint16_t) s->temperature[0]) >> 0) & 0xf0; + break; + case TMP421_TEMP_MSB1: + s->buf[s->len++] = (((uint16_t) s->temperature[1]) >> 8); + s->buf[s->len++] = (((uint16_t) s->temperature[1]) >> 0) & 0xf0; + break; + case TMP421_TEMP_MSB2: + s->buf[s->len++] = (((uint16_t) s->temperature[2]) >> 8); + s->buf[s->len++] = (((uint16_t) s->temperature[2]) >> 0) & 0xf0; + break; + case TMP421_TEMP_MSB3: + s->buf[s->len++] = (((uint16_t) s->temperature[3]) >> 8); + s->buf[s->len++] = (((uint16_t) s->temperature[3]) >> 0) & 0xf0; + break; + case TMP421_TEMP_LSB0: + s->buf[s->len++] = (((uint16_t) s->temperature[0]) >> 0) & 0xf0; + break; + case TMP421_TEMP_LSB1: + s->buf[s->len++] = (((uint16_t) s->temperature[1]) >> 0) & 0xf0; + break; + case TMP421_TEMP_LSB2: + s->buf[s->len++] = (((uint16_t) s->temperature[2]) >> 0) & 0xf0; + break; + case TMP421_TEMP_LSB3: + s->buf[s->len++] = (((uint16_t) s->temperature[3]) >> 0) & 0xf0; + break; + } +} + +static void tmp421_reset(I2CSlave *i2c); + +static void tmp421_write(TMP421State *s) +{ + switch (s->pointer) { + case TMP421_CONVERSION_RATE_REG: + s->rate = s->buf[0]; + break; + case TMP421_CONFIG_REG_1: + s->config[0] = s->buf[0]; + break; + case TMP421_CONFIG_REG_2: + s->config[1] = s->buf[0]; + break; + case TMP421_RESET: + tmp421_reset(I2C_SLAVE(s)); + break; + } +} + +static int tmp421_rx(I2CSlave *i2c) +{ + TMP421State *s = TMP421(i2c); + + if (s->len < 2) { + return s->buf[s->len++]; + } else { + return 0xff; + } +} + +static int tmp421_tx(I2CSlave *i2c, uint8_t data) +{ + TMP421State *s = TMP421(i2c); + + if (s->len == 0) { + /* first byte is the register pointer for a read or write + * operation */ + s->pointer = data; + s->len++; + } else if (s->len == 1) { + /* second byte is the data to write. The device only supports + * one byte writes */ + s->buf[0] = data; + tmp421_write(s); + } + + return 0; +} + +static int tmp421_event(I2CSlave *i2c, enum i2c_event event) +{ + TMP421State *s = TMP421(i2c); + + if (event == I2C_START_RECV) { + tmp421_read(s); + } + + s->len = 0; + return 0; +} + +static const VMStateDescription vmstate_tmp421 = { + .name = "TMP421", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT8(len, TMP421State), + VMSTATE_UINT8_ARRAY(buf, TMP421State, 2), + VMSTATE_UINT8(pointer, TMP421State), + VMSTATE_UINT8_ARRAY(config, TMP421State, 2), + VMSTATE_UINT8(status, TMP421State), + VMSTATE_UINT8(rate, TMP421State), + VMSTATE_INT16_ARRAY(temperature, TMP421State, 4), + VMSTATE_I2C_SLAVE(i2c, TMP421State), + VMSTATE_END_OF_LIST() + } +}; + +static void tmp421_reset(I2CSlave *i2c) +{ + TMP421State *s = TMP421(i2c); + TMP421Class *sc = TMP421_GET_CLASS(s); + + memset(s->temperature, 0, sizeof(s->temperature)); + s->pointer = 0; + + s->config[0] = 0; /* TMP421_CONFIG_RANGE */ + + /* resistance correction and channel enablement */ + switch (sc->dev->model) { + case TMP421_DEVICE_ID: + s->config[1] = 0x1c; + break; + case TMP422_DEVICE_ID: + s->config[1] = 0x3c; + break; + case TMP423_DEVICE_ID: + s->config[1] = 0x7c; + break; + } + + s->rate = 0x7; /* 8Hz */ + s->status = 0; +} + +static int tmp421_init(I2CSlave *i2c) +{ + TMP421State *s = TMP421(i2c); + + tmp421_reset(&s->i2c); + + return 0; +} + +static void tmp421_initfn(Object *obj) +{ + object_property_add(obj, "temperature0", "int", + tmp421_get_temperature, + tmp421_set_temperature, NULL, NULL, NULL); + object_property_add(obj, "temperature1", "int", + tmp421_get_temperature, + tmp421_set_temperature, NULL, NULL, NULL); + object_property_add(obj, "temperature2", "int", + tmp421_get_temperature, + tmp421_set_temperature, NULL, NULL, NULL); + object_property_add(obj, "temperature3", "int", + tmp421_get_temperature, + tmp421_set_temperature, NULL, NULL, NULL); +} + +static void tmp421_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); + TMP421Class *sc = TMP421_CLASS(klass); + + k->init = tmp421_init; + k->event = tmp421_event; + k->recv = tmp421_rx; + k->send = tmp421_tx; + dc->vmsd = &vmstate_tmp421; + sc->dev = (DeviceInfo *) data; +} + +static const TypeInfo tmp421_info = { + .name = TYPE_TMP421, + .parent = TYPE_I2C_SLAVE, + .instance_size = sizeof(TMP421State), + .class_size = sizeof(TMP421Class), + .instance_init = tmp421_initfn, + .abstract = true, +}; + +static void tmp421_register_types(void) +{ + int i; + + type_register_static(&tmp421_info); + for (i = 0; i < ARRAY_SIZE(devices); ++i) { + TypeInfo ti = { + .name = devices[i].name, + .parent = TYPE_TMP421, + .class_init = tmp421_class_init, + .class_data = (void *) &devices[i], + }; + type_register(&ti); + } +} + +type_init(tmp421_register_types) diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c index 9b70ee09b0..50acbf530a 100644 --- a/hw/timer/aspeed_timer.c +++ b/hw/timer/aspeed_timer.c @@ -130,15 +130,26 @@ static uint64_t calculate_next(struct AspeedTimer *t) next = seq[1]; } else if (now < seq[2]) { next = seq[2]; - } else { + } else if (t->reload) { reload_ns = muldiv64(t->reload, NANOSECONDS_PER_SECOND, rate); t->start = now - ((now - t->start) % reload_ns); + } else { + /* no reload value, return 0 */ + break; } } return next; } +static void aspeed_timer_mod(AspeedTimer *t) +{ + uint64_t next = calculate_next(t); + if (next) { + timer_mod(&t->timer, next); + } +} + static void aspeed_timer_expire(void *opaque) { AspeedTimer *t = opaque; @@ -164,7 +175,7 @@ static void aspeed_timer_expire(void *opaque) qemu_set_irq(t->irq, t->level); } - timer_mod(&t->timer, calculate_next(t)); + aspeed_timer_mod(t); } static uint64_t aspeed_timer_get_value(AspeedTimer *t, int reg) @@ -227,10 +238,23 @@ static void aspeed_timer_set_value(AspeedTimerCtrlState *s, int timer, int reg, uint32_t value) { AspeedTimer *t; + uint32_t old_reload; trace_aspeed_timer_set_value(timer, reg, value); t = &s->timers[timer]; switch (reg) { + case TIMER_REG_RELOAD: + old_reload = t->reload; + t->reload = value; + + /* If the reload value was not previously set, or zero, and + * the current value is valid, try to start the timer if it is + * enabled. + */ + if (old_reload || !t->reload) { + break; + } + case TIMER_REG_STATUS: if (timer_enabled(t)) { uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); @@ -238,17 +262,14 @@ static void aspeed_timer_set_value(AspeedTimerCtrlState *s, int timer, int reg, uint32_t rate = calculate_rate(t); t->start += muldiv64(delta, NANOSECONDS_PER_SECOND, rate); - timer_mod(&t->timer, calculate_next(t)); + aspeed_timer_mod(t); } break; - case TIMER_REG_RELOAD: - t->reload = value; - break; case TIMER_REG_MATCH_FIRST: case TIMER_REG_MATCH_SECOND: t->match[reg - 2] = value; if (timer_enabled(t)) { - timer_mod(&t->timer, calculate_next(t)); + aspeed_timer_mod(t); } break; default: @@ -268,7 +289,7 @@ static void aspeed_timer_ctrl_enable(AspeedTimer *t, bool enable) trace_aspeed_timer_ctrl_enable(t->id, enable); if (enable) { t->start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - timer_mod(&t->timer, calculate_next(t)); + aspeed_timer_mod(t); } else { timer_del(&t->timer); } diff --git a/hw/timer/exynos4210_mct.c b/hw/timer/exynos4210_mct.c index a2ec3920f8..e4ef4cfd36 100644 --- a/hw/timer/exynos4210_mct.c +++ b/hw/timer/exynos4210_mct.c @@ -173,13 +173,10 @@ enum LocalTimerRegCntIndexes { L_REG_CNT_AMOUNT }; -#define MCT_NIRQ 6 #define MCT_SFR_SIZE 0x444 #define MCT_GT_CMP_NUM 4 -#define MCT_GT_MAX_VAL UINT64_MAX - #define MCT_GT_COUNTER_STEP 0x100000000ULL #define MCT_LT_COUNTER_STEP 0x100000000ULL #define MCT_LT_CNT_LOW_LIMIT 0x100 @@ -937,7 +934,7 @@ static void exynos4210_mct_update_freq(Exynos4210MCTState *s) { uint32_t freq = s->freq; s->freq = 24000000 / - ((MCT_CFG_GET_PRESCALER(s->reg_mct_cfg)+1) * + ((MCT_CFG_GET_PRESCALER(s->reg_mct_cfg) + 1) * MCT_CFG_GET_DIVIDER(s->reg_mct_cfg)); if (freq != s->freq) { @@ -1016,9 +1013,9 @@ static uint64_t exynos4210_mct_read(void *opaque, hwaddr offset, case G_COMP_L(0): case G_COMP_L(1): case G_COMP_L(2): case G_COMP_L(3): case G_COMP_U(0): case G_COMP_U(1): case G_COMP_U(2): case G_COMP_U(3): - index = GET_G_COMP_IDX(offset); - shift = 8 * (offset & 0x4); - value = UINT32_MAX & (s->g_timer.reg.comp[index] >> shift); + index = GET_G_COMP_IDX(offset); + shift = 8 * (offset & 0x4); + value = UINT32_MAX & (s->g_timer.reg.comp[index] >> shift); break; case G_TCON: @@ -1067,7 +1064,6 @@ static uint64_t exynos4210_mct_read(void *opaque, hwaddr offset, lt_i = GET_L_TIMER_IDX(offset); value = exynos4210_lfrc_get_count(&s->l_timer[lt_i]); - break; case L0_TCON: case L1_TCON: @@ -1153,23 +1149,23 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset, case G_COMP_L(0): case G_COMP_L(1): case G_COMP_L(2): case G_COMP_L(3): case G_COMP_U(0): case G_COMP_U(1): case G_COMP_U(2): case G_COMP_U(3): - index = GET_G_COMP_IDX(offset); - shift = 8 * (offset & 0x4); - s->g_timer.reg.comp[index] = - (s->g_timer.reg.comp[index] & - (((uint64_t)UINT32_MAX << 32) >> shift)) + - (value << shift); + index = GET_G_COMP_IDX(offset); + shift = 8 * (offset & 0x4); + s->g_timer.reg.comp[index] = + (s->g_timer.reg.comp[index] & + (((uint64_t)UINT32_MAX << 32) >> shift)) + + (value << shift); - DPRINTF("comparator %d write 0x%llx val << %d\n", index, value, shift); + DPRINTF("comparator %d write 0x%llx val << %d\n", index, value, shift); - if (offset&0x4) { - s->g_timer.reg.wstat |= G_WSTAT_COMP_U(index); - } else { - s->g_timer.reg.wstat |= G_WSTAT_COMP_L(index); - } + if (offset & 0x4) { + s->g_timer.reg.wstat |= G_WSTAT_COMP_U(index); + } else { + s->g_timer.reg.wstat |= G_WSTAT_COMP_L(index); + } - exynos4210_gfrc_restart(s); - break; + exynos4210_gfrc_restart(s); + break; case G_TCON: old_val = s->g_timer.reg.tcon; @@ -1207,7 +1203,6 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset, break; case G_INT_ENB: - /* Raise IRQ if transition from disabled to enabled and CSTAT pending */ for (i = 0; i < MCT_GT_CMP_NUM; i++) { if ((value & G_INT_ENABLE(i)) > (s->g_timer.reg.tcon & @@ -1288,7 +1283,6 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset, break; case L0_TCNTB: case L1_TCNTB: - lt_i = GET_L_TIMER_IDX(offset); index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i); @@ -1316,7 +1310,6 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset, break; case L0_ICNTB: case L1_ICNTB: - lt_i = GET_L_TIMER_IDX(offset); index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i); @@ -1353,13 +1346,12 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset, if (icntb_max[lt_i] < value) { icntb_max[lt_i] = value; } -DPRINTF("local timer[%d] ICNTB write %llx; max=%x, min=%x\n\n", - lt_i, value, icntb_max[lt_i], icntb_min[lt_i]); + DPRINTF("local timer[%d] ICNTB write %llx; max=%x, min=%x\n\n", + lt_i, value, icntb_max[lt_i], icntb_min[lt_i]); #endif -break; + break; case L0_FRCNTB: case L1_FRCNTB: - lt_i = GET_L_TIMER_IDX(offset); index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i); diff --git a/include/hw/arm/exynos4210.h b/include/hw/arm/exynos4210.h index d9e08014d6..098a69ec73 100644 --- a/include/hw/arm/exynos4210.h +++ b/include/hw/arm/exynos4210.h @@ -93,8 +93,6 @@ typedef struct Exynos4210State { MemoryRegion iram_mem; MemoryRegion irom_mem; MemoryRegion irom_alias_mem; - MemoryRegion dram0_mem; - MemoryRegion dram1_mem; MemoryRegion boot_secondary; MemoryRegion bootreg_mem; I2CBus *i2c_if[EXYNOS4210_I2C_NUMBER]; @@ -103,8 +101,7 @@ typedef struct Exynos4210State { void exynos4210_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info); -Exynos4210State *exynos4210_init(MemoryRegion *system_mem, - unsigned long ram_size); +Exynos4210State *exynos4210_init(MemoryRegion *system_mem); /* Initialize exynos4210 IRQ subsystem stub */ qemu_irq *exynos4210_init_irq(Exynos4210Irq *env); diff --git a/include/hw/intc/arm_gicv3_its_common.h b/include/hw/intc/arm_gicv3_its_common.h index 1ba18944cf..fd1fe64c03 100644 --- a/include/hw/intc/arm_gicv3_its_common.h +++ b/include/hw/intc/arm_gicv3_its_common.h @@ -28,6 +28,13 @@ #define ITS_TRANS_SIZE 0x10000 #define ITS_SIZE (ITS_CONTROL_SIZE + ITS_TRANS_SIZE) +#define GITS_CTLR 0x0 +#define GITS_IIDR 0x4 +#define GITS_CBASER 0x80 +#define GITS_CWRITER 0x88 +#define GITS_CREADR 0x90 +#define GITS_BASER 0x100 + struct GICv3ITSState { SysBusDevice parent_obj; @@ -43,6 +50,7 @@ struct GICv3ITSState { /* Registers */ uint32_t ctlr; + uint32_t iidr; uint64_t cbaser; uint64_t cwriter; uint64_t creadr; diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index 79a4b350a8..f3f3c2af4d 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -149,6 +149,8 @@ enum VMStateFlags { typedef enum { MIG_PRI_DEFAULT = 0, MIG_PRI_IOMMU, /* Must happen before PCI devices */ + MIG_PRI_GICV3_ITS, /* Must happen before PCI devices */ + MIG_PRI_GICV3, /* Must happen before the ITS */ MIG_PRI_MAX, } MigrationPriority; diff --git a/include/qemu/timer.h b/include/qemu/timer.h index 8a1eb74839..1b518bca30 100644 --- a/include/qemu/timer.h +++ b/include/qemu/timer.h @@ -1020,10 +1020,9 @@ static inline int64_t cpu_get_host_ticks(void) /* The host CPU doesn't have an easily accessible cycle counter. Just return a monotonically increasing value. This will be totally wrong, but hopefully better than nothing. */ -static inline int64_t cpu_get_host_ticks (void) +static inline int64_t cpu_get_host_ticks(void) { - static int64_t ticks = 0; - return ticks++; + return get_clock(); } #endif diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index a45c145560..1e91613ca9 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -294,12 +294,15 @@ int kvm_device_check_attr(int fd, uint32_t group, uint64_t attr); * @attr: the attribute of that group to set or get * @val: pointer to a storage area for the value * @write: true for set and false for get operation + * @errp: error object handle * - * This function is not allowed to fail. Use kvm_device_check_attr() - * in order to check for the availability of optional attributes. + * Returns: 0 on success + * < 0 on error + * Use kvm_device_check_attr() in order to check for the availability + * of optional attributes. */ -void kvm_device_access(int fd, int group, uint64_t attr, - void *val, bool write); +int kvm_device_access(int fd, int group, uint64_t attr, + void *val, bool write, Error **errp); /** * kvm_create_device - create a KVM device for the device control API @@ -23,6 +23,7 @@ #include "qemu/option.h" #include "qemu/config-file.h" #include "qemu/error-report.h" +#include "qapi/error.h" #include "hw/hw.h" #include "hw/pci/msi.h" #include "hw/pci/msix.h" @@ -2216,8 +2217,8 @@ int kvm_device_check_attr(int dev_fd, uint32_t group, uint64_t attr) return kvm_device_ioctl(dev_fd, KVM_HAS_DEVICE_ATTR, &attribute) ? 0 : 1; } -void kvm_device_access(int fd, int group, uint64_t attr, - void *val, bool write) +int kvm_device_access(int fd, int group, uint64_t attr, + void *val, bool write, Error **errp) { struct kvm_device_attr kvmattr; int err; @@ -2231,11 +2232,12 @@ void kvm_device_access(int fd, int group, uint64_t attr, write ? KVM_SET_DEVICE_ATTR : KVM_GET_DEVICE_ATTR, &kvmattr); if (err < 0) { - error_report("KVM_%s_DEVICE_ATTR failed: %s", - write ? "SET" : "GET", strerror(-err)); - error_printf("Group %d attr 0x%016" PRIx64 "\n", group, attr); - abort(); + error_setg_errno(errp, -err, + "KVM_%s_DEVICE_ATTR failed: Group %d " + "attr 0x%016" PRIx64, + write ? "SET" : "GET", group, attr); } + return err; } /* Return 1 on success, 0 on failure */ |