Commit 3f060292 authored by Peter Maydell's avatar Peter Maydell

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: 's avatarPeter Maydell <peter.maydell@linaro.org>
parents 6f153ceb 252a7a6a
......@@ -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
......
......@@ -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)
......
......@@ -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.
......
......@@ -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);
}
......
......@@ -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");
......
......@@ -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),
......
......@@ -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);
......
......@@ -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 = {
......
......@@ -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)
......
......@@ -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,
......
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
......
......@@ -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++;
......
This diff is collapsed.
......@@ -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);
}
......
......@@ -173,13 +173,10 @@ enum LocalTimerRegCntIndexes {
L_REG_CNT_AMOUNT
};