mirror of
https://github.com/xemu-project/xemu.git
synced 2025-02-12 23:58:38 +00:00
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 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJZP/E9AAoJEDwlJe0UNgzephAQAIwy0Zc0oHWEX9lanN1FNqMI 8bIXu+yFB+E5zdLtDOuWxmQpJ9EqTYfS7hPSR/WRro4RGJsZiYTEIDpDRSjRt+MR kZw+LqDaA/8O6ZqJ0dSQMsH1P9YkcJhVOwe0BLVvkt3b3sZzC7+cM+Y1THlpXeC5 MwZ81zZNz7Q3J6LV/ZatVx+pI/cn9R6HFpMqPhGsGfn7bqIa+H+9uWKQfRbDBz32 q6cP33TbF57Of3RNMT3E0Frn+eSxiAyZ3tH61NkjIJ7uJ+WwZts7/kUX4b4ILCJ8 dwiTHyKwdzvlDhTbgI9UwsBIzFhBAYs8/SufOVjZFooiDapy3JaRL5OI+2JIUHHr SQUXLMU11Qhe4imOyL0GcW72eG9tH1r4sxc/yu7T+fr8N2wK/buSMvbTSRLPG9uD xb5vODyoq6A6HIs67e86SYHuOJtnTjPPyJexK39bvIvLy5vlPoL5DDzW9ZcuJSeW i0v/3FFUQNwFwhtsOos8XQ935ym2MXdChautu7jq/KqaIZY76kl1ux+5ejkFMKyw sVNoOhBrxm8278VMKKJpr7v25koRp+eE1+BeBXSvCCOUFsRRL+Fens9A+sd7Ue8H xihpLKUP9030/cmhpoO7uk5qsTG4z+TT4S5aUtOYv/AbkL8ckIjQrL0sup2O+YUO RDz8uhcU2YGs9PaU58C1 =1qO0 -----END PGP SIGNATURE----- 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>
This commit is contained in:
commit
3f0602927b
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = (GICv3ITSState *)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_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;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
return;
|
||||
}
|
||||
|
||||
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,
|
||||
|
@ -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
|
||||
|
@ -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++;
|
||||
|
402
hw/misc/tmp421.c
Normal file
402
hw/misc/tmp421.c
Normal file
@ -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)
|
@ -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
|
||||
};
|
||||
|
||||
#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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
14
kvm-all.c
14
kvm-all.c
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user