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_TSC2005=y
|
||||||
CONFIG_LM832X=y
|
CONFIG_LM832X=y
|
||||||
CONFIG_TMP105=y
|
CONFIG_TMP105=y
|
||||||
|
CONFIG_TMP421=y
|
||||||
CONFIG_STELLARIS=y
|
CONFIG_STELLARIS=y
|
||||||
CONFIG_STELLARIS_INPUT=y
|
CONFIG_STELLARIS_INPUT=y
|
||||||
CONFIG_STELLARIS_ENET=y
|
CONFIG_STELLARIS_ENET=y
|
||||||
|
|
|
@ -239,10 +239,19 @@ static void aspeed_board_init(MachineState *machine,
|
||||||
static void palmetto_bmc_i2c_init(AspeedBoardState *bmc)
|
static void palmetto_bmc_i2c_init(AspeedBoardState *bmc)
|
||||||
{
|
{
|
||||||
AspeedSoCState *soc = &bmc->soc;
|
AspeedSoCState *soc = &bmc->soc;
|
||||||
|
DeviceState *dev;
|
||||||
|
|
||||||
/* The palmetto platform expects a ds3231 RTC but a ds1338 is
|
/* The palmetto platform expects a ds3231 RTC but a ds1338 is
|
||||||
* enough to provide basic RTC features. Alarms will be missing */
|
* enough to provide basic RTC features. Alarms will be missing */
|
||||||
i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 0), "ds1338", 0x68);
|
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)
|
static void palmetto_bmc_init(MachineState *machine)
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "qemu-common.h"
|
#include "qemu-common.h"
|
||||||
#include "qemu/log.h"
|
#include "qemu/log.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
|
#include "hw/cpu/a9mpcore.h"
|
||||||
#include "hw/boards.h"
|
#include "hw/boards.h"
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
#include "hw/sysbus.h"
|
#include "hw/sysbus.h"
|
||||||
|
@ -160,16 +161,14 @@ static uint64_t exynos4210_calc_affinity(int cpu)
|
||||||
return mp_affinity;
|
return mp_affinity;
|
||||||
}
|
}
|
||||||
|
|
||||||
Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
|
Exynos4210State *exynos4210_init(MemoryRegion *system_mem)
|
||||||
unsigned long ram_size)
|
|
||||||
{
|
{
|
||||||
int i, n;
|
|
||||||
Exynos4210State *s = g_new(Exynos4210State, 1);
|
Exynos4210State *s = g_new(Exynos4210State, 1);
|
||||||
qemu_irq gate_irq[EXYNOS4210_NCPUS][EXYNOS4210_IRQ_GATE_NINPUTS];
|
qemu_irq gate_irq[EXYNOS4210_NCPUS][EXYNOS4210_IRQ_GATE_NINPUTS];
|
||||||
unsigned long mem_size;
|
|
||||||
DeviceState *dev;
|
|
||||||
SysBusDevice *busdev;
|
SysBusDevice *busdev;
|
||||||
ObjectClass *cpu_oc;
|
ObjectClass *cpu_oc;
|
||||||
|
DeviceState *dev;
|
||||||
|
int i, n;
|
||||||
|
|
||||||
cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, "cortex-a9");
|
cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, "cortex-a9");
|
||||||
assert(cpu_oc);
|
assert(cpu_oc);
|
||||||
|
@ -213,7 +212,7 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Private memory region and Internal GIC */
|
/* 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_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS);
|
||||||
qdev_init_nofail(dev);
|
qdev_init_nofail(dev);
|
||||||
busdev = SYS_BUS_DEVICE(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,
|
memory_region_add_subregion(system_mem, EXYNOS4210_IRAM_BASE_ADDR,
|
||||||
&s->iram_mem);
|
&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.
|
/* PMU.
|
||||||
* The only reason of existence at the moment is that secondary CPU boot
|
* The only reason of existence at the moment is that secondary CPU boot
|
||||||
* loader uses PMU INFORM5 register as a holding pen.
|
* loader uses PMU INFORM5 register as a holding pen.
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
#include "qemu-common.h"
|
#include "qemu-common.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
|
@ -56,6 +57,12 @@ typedef enum Exynos4BoardType {
|
||||||
EXYNOS4_NUM_OF_BOARDS
|
EXYNOS4_NUM_OF_BOARDS
|
||||||
} Exynos4BoardType;
|
} Exynos4BoardType;
|
||||||
|
|
||||||
|
typedef struct Exynos4BoardState {
|
||||||
|
Exynos4210State *soc;
|
||||||
|
MemoryRegion dram0_mem;
|
||||||
|
MemoryRegion dram1_mem;
|
||||||
|
} Exynos4BoardState;
|
||||||
|
|
||||||
static int exynos4_board_id[EXYNOS4_NUM_OF_BOARDS] = {
|
static int exynos4_board_id[EXYNOS4_NUM_OF_BOARDS] = {
|
||||||
[EXYNOS4_BOARD_NURI] = 0xD33,
|
[EXYNOS4_BOARD_NURI] = 0xD33,
|
||||||
[EXYNOS4_BOARD_SMDKC210] = 0xB16,
|
[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,
|
static void exynos4_boards_init_ram(Exynos4BoardState *s,
|
||||||
Exynos4BoardType board_type)
|
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);
|
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||||
|
|
||||||
if (smp_cpus != EXYNOS4210_NCPUS && !qtest_enabled()) {
|
if (smp_cpus != EXYNOS4210_NCPUS && !qtest_enabled()) {
|
||||||
|
@ -127,8 +159,12 @@ static Exynos4210State *exynos4_boards_init_common(MachineState *machine,
|
||||||
machine->kernel_cmdline,
|
machine->kernel_cmdline,
|
||||||
machine->initrd_filename);
|
machine->initrd_filename);
|
||||||
|
|
||||||
return exynos4210_init(get_system_memory(),
|
exynos4_boards_init_ram(s, get_system_memory(),
|
||||||
exynos4_board_ram_size[board_type]);
|
exynos4_board_ram_size[board_type]);
|
||||||
|
|
||||||
|
s->soc = exynos4210_init(get_system_memory());
|
||||||
|
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nuri_init(MachineState *machine)
|
static void nuri_init(MachineState *machine)
|
||||||
|
@ -140,11 +176,11 @@ static void nuri_init(MachineState *machine)
|
||||||
|
|
||||||
static void smdkc210_init(MachineState *machine)
|
static void smdkc210_init(MachineState *machine)
|
||||||
{
|
{
|
||||||
Exynos4210State *s = exynos4_boards_init_common(machine,
|
Exynos4BoardState *s = exynos4_boards_init_common(machine,
|
||||||
EXYNOS4_BOARD_SMDKC210);
|
EXYNOS4_BOARD_SMDKC210);
|
||||||
|
|
||||||
lan9215_init(SMDK_LAN9118_BASE_ADDR,
|
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);
|
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)
|
uint32_t *val, bool write)
|
||||||
{
|
{
|
||||||
kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS,
|
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,
|
static void kvm_gicc_access(GICState *s, int offset, int cpu,
|
||||||
uint32_t *val, bool write)
|
uint32_t *val, bool write)
|
||||||
{
|
{
|
||||||
kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_REGS,
|
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) \
|
#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)) {
|
if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0)) {
|
||||||
uint32_t numirqs = s->num_irq;
|
uint32_t numirqs = s->num_irq;
|
||||||
kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0,
|
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 */
|
/* Tell the kernel to complete VGIC initialization now */
|
||||||
if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
|
if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
|
||||||
KVM_DEV_ARM_VGIC_CTRL_INIT)) {
|
KVM_DEV_ARM_VGIC_CTRL_INIT)) {
|
||||||
kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
|
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) {
|
} else if (ret != -ENODEV && ret != -ENOTSUP) {
|
||||||
error_setg_errno(errp, -ret, "error creating in-kernel VGIC");
|
error_setg_errno(errp, -ret, "error creating in-kernel VGIC");
|
||||||
|
|
|
@ -145,6 +145,7 @@ static const VMStateDescription vmstate_gicv3 = {
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.pre_save = gicv3_pre_save,
|
.pre_save = gicv3_pre_save,
|
||||||
.post_load = gicv3_post_load,
|
.post_load = gicv3_post_load,
|
||||||
|
.priority = MIG_PRI_GICV3,
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT32(gicd_ctlr, GICv3State),
|
VMSTATE_UINT32(gicd_ctlr, GICv3State),
|
||||||
VMSTATE_UINT32_ARRAY(gicd_statusr, GICv3State, 2),
|
VMSTATE_UINT32_ARRAY(gicd_statusr, GICv3State, 2),
|
||||||
|
|
|
@ -48,7 +48,16 @@ static const VMStateDescription vmstate_its = {
|
||||||
.name = "arm_gicv3_its",
|
.name = "arm_gicv3_its",
|
||||||
.pre_save = gicv3_its_pre_save,
|
.pre_save = gicv3_its_pre_save,
|
||||||
.post_load = gicv3_its_post_load,
|
.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,
|
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->cbaser = 0;
|
||||||
s->cwriter = 0;
|
s->cwriter = 0;
|
||||||
s->creadr = 0;
|
s->creadr = 0;
|
||||||
|
s->iidr = 0;
|
||||||
memset(&s->baser, 0, sizeof(s->baser));
|
memset(&s->baser, 0, sizeof(s->baser));
|
||||||
|
|
||||||
gicv3_its_post_load(s, 0);
|
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);
|
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)
|
static void kvm_arm_its_realize(DeviceState *dev, Error **errp)
|
||||||
{
|
{
|
||||||
GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev);
|
GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev);
|
||||||
Error *local_err = NULL;
|
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);
|
s->dev_fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_ITS, false);
|
||||||
if (s->dev_fd < 0) {
|
if (s->dev_fd < 0) {
|
||||||
error_setg_errno(errp, -s->dev_fd, "error creating in-kernel ITS");
|
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 */
|
/* explicit init of the ITS */
|
||||||
kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
|
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 */
|
/* register the base address */
|
||||||
kvm_arm_register_device(&s->iomem_its_cntrl, -1, KVM_DEV_ARM_VGIC_GRP_ADDR,
|
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);
|
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_msi_use_devid = true;
|
||||||
kvm_gsi_direct_mapping = false;
|
kvm_gsi_direct_mapping = false;
|
||||||
kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled();
|
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)
|
static void kvm_arm_its_init(Object *obj)
|
||||||
|
@ -102,6 +131,80 @@ static void kvm_arm_its_init(Object *obj)
|
||||||
&error_abort);
|
&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)
|
static void kvm_arm_its_class_init(ObjectClass *klass, void *data)
|
||||||
{
|
{
|
||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
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;
|
dc->realize = kvm_arm_its_realize;
|
||||||
icc->send_msi = kvm_its_send_msi;
|
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 = {
|
static const TypeInfo kvm_arm_its_info = {
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "hw/sysbus.h"
|
#include "hw/sysbus.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
#include "sysemu/kvm.h"
|
#include "sysemu/kvm.h"
|
||||||
|
#include "sysemu/sysemu.h"
|
||||||
#include "kvm_arm.h"
|
#include "kvm_arm.h"
|
||||||
#include "gicv3_internal.h"
|
#include "gicv3_internal.h"
|
||||||
#include "vgic_common.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_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS,
|
||||||
KVM_VGIC_ATTR(offset, 0),
|
KVM_VGIC_ATTR(offset, 0),
|
||||||
val, write);
|
val, write, &error_abort);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void kvm_gicr_access(GICv3State *s, int offset, int cpu,
|
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_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS,
|
||||||
KVM_VGIC_ATTR(offset, s->cpu[cpu].gicr_typer),
|
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,
|
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_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS,
|
||||||
KVM_VGIC_ATTR(reg, s->cpu[cpu].gicr_typer),
|
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,
|
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) |
|
KVM_VGIC_ATTR(irq, s->cpu[cpu].gicr_typer) |
|
||||||
(VGIC_LEVEL_INFO_LINE_LEVEL <<
|
(VGIC_LEVEL_INFO_LINE_LEVEL <<
|
||||||
KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT),
|
KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT),
|
||||||
val, write);
|
val, write, &error_abort);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loop through each distributor IRQ related register; since bits
|
/* 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 */
|
/* Initialize to actual HW supported configuration */
|
||||||
kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS,
|
kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS,
|
||||||
KVM_VGIC_ATTR(ICC_CTLR_EL1, cpu->mp_affinity),
|
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];
|
c->icc_ctlr_el1[GICV3_S] = c->icc_ctlr_el1[GICV3_NS];
|
||||||
}
|
}
|
||||||
|
@ -680,6 +681,35 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = {
|
||||||
REGINFO_SENTINEL
|
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)
|
static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
|
||||||
{
|
{
|
||||||
GICv3State *s = KVM_ARM_GICV3(dev);
|
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,
|
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 */
|
/* Tell the kernel to complete VGIC initialization now */
|
||||||
kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
|
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_arm_register_device(&s->iomem_dist, -1, KVM_DEV_ARM_VGIC_GRP_ADDR,
|
||||||
KVM_VGIC_V3_ADDR_TYPE_DIST, s->dev_fd);
|
KVM_VGIC_V3_ADDR_TYPE_DIST, s->dev_fd);
|
||||||
|
@ -751,6 +781,10 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
|
||||||
return;
|
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)
|
static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data)
|
||||||
|
|
|
@ -116,7 +116,7 @@ enum ExtInt {
|
||||||
* which is INTG16 in Internal Interrupt Combiner.
|
* 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] = {
|
combiner_grp_to_gic_id[64-EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][8] = {
|
||||||
/* int combiner groups 16-19 */
|
/* int combiner groups 16-19 */
|
||||||
{ }, { }, { }, { },
|
{ }, { }, { }, { },
|
||||||
|
@ -286,21 +286,21 @@ static void exynos4210_gic_init(Object *obj)
|
||||||
DeviceState *dev = DEVICE(obj);
|
DeviceState *dev = DEVICE(obj);
|
||||||
Exynos4210GicState *s = EXYNOS4210_GIC(obj);
|
Exynos4210GicState *s = EXYNOS4210_GIC(obj);
|
||||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||||
uint32_t i;
|
|
||||||
const char cpu_prefix[] = "exynos4210-gic-alias_cpu";
|
const char cpu_prefix[] = "exynos4210-gic-alias_cpu";
|
||||||
const char dist_prefix[] = "exynos4210-gic-alias_dist";
|
const char dist_prefix[] = "exynos4210-gic-alias_dist";
|
||||||
char cpu_alias_name[sizeof(cpu_prefix) + 3];
|
char cpu_alias_name[sizeof(cpu_prefix) + 3];
|
||||||
char dist_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");
|
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-cpu", s->num_cpu);
|
||||||
qdev_prop_set_uint32(s->gic, "num-irq", EXYNOS4210_GIC_NIRQ);
|
qdev_prop_set_uint32(s->gic, "num-irq", EXYNOS4210_GIC_NIRQ);
|
||||||
qdev_init_nofail(s->gic);
|
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 */
|
/* 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 */
|
/* Pass through inbound GPIO lines to the GIC */
|
||||||
qdev_init_gpio_in(dev, exynos4210_gic_set_irq,
|
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);
|
sprintf(cpu_alias_name, "%s%x", cpu_prefix, i);
|
||||||
memory_region_init_alias(&s->cpu_alias[i], obj,
|
memory_region_init_alias(&s->cpu_alias[i], obj,
|
||||||
cpu_alias_name,
|
cpu_alias_name,
|
||||||
sysbus_mmio_get_region(busdev, 1),
|
sysbus_mmio_get_region(gicbusdev, 1),
|
||||||
0,
|
0,
|
||||||
EXYNOS4210_GIC_CPU_REGION_SIZE);
|
EXYNOS4210_GIC_CPU_REGION_SIZE);
|
||||||
memory_region_add_subregion(&s->cpu_container,
|
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);
|
sprintf(dist_alias_name, "%s%x", dist_prefix, i);
|
||||||
memory_region_init_alias(&s->dist_alias[i], obj,
|
memory_region_init_alias(&s->dist_alias[i], obj,
|
||||||
dist_alias_name,
|
dist_alias_name,
|
||||||
sysbus_mmio_get_region(busdev, 0),
|
sysbus_mmio_get_region(gicbusdev, 0),
|
||||||
0,
|
0,
|
||||||
EXYNOS4210_GIC_DIST_REGION_SIZE);
|
EXYNOS4210_GIC_DIST_REGION_SIZE);
|
||||||
memory_region_add_subregion(&s->dist_container,
|
memory_region_add_subregion(&s->dist_container,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
common-obj-$(CONFIG_APPLESMC) += applesmc.o
|
common-obj-$(CONFIG_APPLESMC) += applesmc.o
|
||||||
common-obj-$(CONFIG_MAX111X) += max111x.o
|
common-obj-$(CONFIG_MAX111X) += max111x.o
|
||||||
common-obj-$(CONFIG_TMP105) += tmp105.o
|
common-obj-$(CONFIG_TMP105) += tmp105.o
|
||||||
|
common-obj-$(CONFIG_TMP421) += tmp421.o
|
||||||
common-obj-$(CONFIG_ISA_DEBUG) += debugexit.o
|
common-obj-$(CONFIG_ISA_DEBUG) += debugexit.o
|
||||||
common-obj-$(CONFIG_SGA) += sga.o
|
common-obj-$(CONFIG_SGA) += sga.o
|
||||||
common-obj-$(CONFIG_ISA_TESTDEV) += pc-testdev.o
|
common-obj-$(CONFIG_ISA_TESTDEV) += pc-testdev.o
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "hw/sysbus.h"
|
#include "hw/sysbus.h"
|
||||||
|
#include "sysemu/sysemu.h"
|
||||||
|
|
||||||
#ifndef DEBUG_PMU
|
#ifndef DEBUG_PMU
|
||||||
#define DEBUG_PMU 0
|
#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_MMCB_OPTION", PAD_RETENTION_MMCB_OPTION, 0x00000000},
|
||||||
{"PAD_RETENTION_EBIA_OPTION", PAD_RETENTION_EBIA_OPTION, 0x00000000},
|
{"PAD_RETENTION_EBIA_OPTION", PAD_RETENTION_EBIA_OPTION, 0x00000000},
|
||||||
{"PAD_RETENTION_EBIB_OPTION", PAD_RETENTION_EBIB_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_CONFIGURATION", XUSBXTI_CONFIGURATION, 0x00000001},
|
||||||
{"XUSBXTI_STATUS", XUSBXTI_STATUS, 0x00000001},
|
{"XUSBXTI_STATUS", XUSBXTI_STATUS, 0x00000001},
|
||||||
{"XUSBXTI_DURATION", XUSBXTI_DURATION, 0xFFF00000},
|
{"XUSBXTI_DURATION", XUSBXTI_DURATION, 0xFFF00000},
|
||||||
|
@ -397,6 +402,12 @@ typedef struct Exynos4210PmuState {
|
||||||
uint32_t reg[PMU_NUM_OF_REGISTERS];
|
uint32_t reg[PMU_NUM_OF_REGISTERS];
|
||||||
} Exynos4210PmuState;
|
} 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,
|
static uint64_t exynos4210_pmu_read(void *opaque, hwaddr offset,
|
||||||
unsigned size)
|
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,
|
PRINT_DEBUG_EXTEND("%s <0x%04x> <- 0x%04x\n", reg_p->name,
|
||||||
(uint32_t)offset, (uint32_t)val);
|
(uint32_t)offset, (uint32_t)val);
|
||||||
s->reg[i] = 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;
|
return;
|
||||||
}
|
}
|
||||||
reg_p++;
|
reg_p++;
|
||||||
|
|
|
@ -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];
|
next = seq[1];
|
||||||
} else if (now < seq[2]) {
|
} else if (now < seq[2]) {
|
||||||
next = seq[2];
|
next = seq[2];
|
||||||
} else {
|
} else if (t->reload) {
|
||||||
reload_ns = muldiv64(t->reload, NANOSECONDS_PER_SECOND, rate);
|
reload_ns = muldiv64(t->reload, NANOSECONDS_PER_SECOND, rate);
|
||||||
t->start = now - ((now - t->start) % reload_ns);
|
t->start = now - ((now - t->start) % reload_ns);
|
||||||
|
} else {
|
||||||
|
/* no reload value, return 0 */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return next;
|
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)
|
static void aspeed_timer_expire(void *opaque)
|
||||||
{
|
{
|
||||||
AspeedTimer *t = opaque;
|
AspeedTimer *t = opaque;
|
||||||
|
@ -164,7 +175,7 @@ static void aspeed_timer_expire(void *opaque)
|
||||||
qemu_set_irq(t->irq, t->level);
|
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)
|
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)
|
uint32_t value)
|
||||||
{
|
{
|
||||||
AspeedTimer *t;
|
AspeedTimer *t;
|
||||||
|
uint32_t old_reload;
|
||||||
|
|
||||||
trace_aspeed_timer_set_value(timer, reg, value);
|
trace_aspeed_timer_set_value(timer, reg, value);
|
||||||
t = &s->timers[timer];
|
t = &s->timers[timer];
|
||||||
switch (reg) {
|
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:
|
case TIMER_REG_STATUS:
|
||||||
if (timer_enabled(t)) {
|
if (timer_enabled(t)) {
|
||||||
uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
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);
|
uint32_t rate = calculate_rate(t);
|
||||||
|
|
||||||
t->start += muldiv64(delta, NANOSECONDS_PER_SECOND, rate);
|
t->start += muldiv64(delta, NANOSECONDS_PER_SECOND, rate);
|
||||||
timer_mod(&t->timer, calculate_next(t));
|
aspeed_timer_mod(t);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TIMER_REG_RELOAD:
|
|
||||||
t->reload = value;
|
|
||||||
break;
|
|
||||||
case TIMER_REG_MATCH_FIRST:
|
case TIMER_REG_MATCH_FIRST:
|
||||||
case TIMER_REG_MATCH_SECOND:
|
case TIMER_REG_MATCH_SECOND:
|
||||||
t->match[reg - 2] = value;
|
t->match[reg - 2] = value;
|
||||||
if (timer_enabled(t)) {
|
if (timer_enabled(t)) {
|
||||||
timer_mod(&t->timer, calculate_next(t));
|
aspeed_timer_mod(t);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -268,7 +289,7 @@ static void aspeed_timer_ctrl_enable(AspeedTimer *t, bool enable)
|
||||||
trace_aspeed_timer_ctrl_enable(t->id, enable);
|
trace_aspeed_timer_ctrl_enable(t->id, enable);
|
||||||
if (enable) {
|
if (enable) {
|
||||||
t->start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
t->start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||||
timer_mod(&t->timer, calculate_next(t));
|
aspeed_timer_mod(t);
|
||||||
} else {
|
} else {
|
||||||
timer_del(&t->timer);
|
timer_del(&t->timer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,13 +173,10 @@ enum LocalTimerRegCntIndexes {
|
||||||
L_REG_CNT_AMOUNT
|
L_REG_CNT_AMOUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MCT_NIRQ 6
|
|
||||||
#define MCT_SFR_SIZE 0x444
|
#define MCT_SFR_SIZE 0x444
|
||||||
|
|
||||||
#define MCT_GT_CMP_NUM 4
|
#define MCT_GT_CMP_NUM 4
|
||||||
|
|
||||||
#define MCT_GT_MAX_VAL UINT64_MAX
|
|
||||||
|
|
||||||
#define MCT_GT_COUNTER_STEP 0x100000000ULL
|
#define MCT_GT_COUNTER_STEP 0x100000000ULL
|
||||||
#define MCT_LT_COUNTER_STEP 0x100000000ULL
|
#define MCT_LT_COUNTER_STEP 0x100000000ULL
|
||||||
#define MCT_LT_CNT_LOW_LIMIT 0x100
|
#define MCT_LT_CNT_LOW_LIMIT 0x100
|
||||||
|
@ -937,7 +934,7 @@ static void exynos4210_mct_update_freq(Exynos4210MCTState *s)
|
||||||
{
|
{
|
||||||
uint32_t freq = s->freq;
|
uint32_t freq = s->freq;
|
||||||
s->freq = 24000000 /
|
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));
|
MCT_CFG_GET_DIVIDER(s->reg_mct_cfg));
|
||||||
|
|
||||||
if (freq != s->freq) {
|
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_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):
|
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);
|
index = GET_G_COMP_IDX(offset);
|
||||||
shift = 8 * (offset & 0x4);
|
shift = 8 * (offset & 0x4);
|
||||||
value = UINT32_MAX & (s->g_timer.reg.comp[index] >> shift);
|
value = UINT32_MAX & (s->g_timer.reg.comp[index] >> shift);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case G_TCON:
|
case G_TCON:
|
||||||
|
@ -1067,7 +1064,6 @@ static uint64_t exynos4210_mct_read(void *opaque, hwaddr offset,
|
||||||
lt_i = GET_L_TIMER_IDX(offset);
|
lt_i = GET_L_TIMER_IDX(offset);
|
||||||
|
|
||||||
value = exynos4210_lfrc_get_count(&s->l_timer[lt_i]);
|
value = exynos4210_lfrc_get_count(&s->l_timer[lt_i]);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case L0_TCON: case L1_TCON:
|
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_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):
|
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);
|
index = GET_G_COMP_IDX(offset);
|
||||||
shift = 8 * (offset & 0x4);
|
shift = 8 * (offset & 0x4);
|
||||||
s->g_timer.reg.comp[index] =
|
s->g_timer.reg.comp[index] =
|
||||||
(s->g_timer.reg.comp[index] &
|
(s->g_timer.reg.comp[index] &
|
||||||
(((uint64_t)UINT32_MAX << 32) >> shift)) +
|
(((uint64_t)UINT32_MAX << 32) >> shift)) +
|
||||||
(value << 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) {
|
if (offset & 0x4) {
|
||||||
s->g_timer.reg.wstat |= G_WSTAT_COMP_U(index);
|
s->g_timer.reg.wstat |= G_WSTAT_COMP_U(index);
|
||||||
} else {
|
} else {
|
||||||
s->g_timer.reg.wstat |= G_WSTAT_COMP_L(index);
|
s->g_timer.reg.wstat |= G_WSTAT_COMP_L(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
exynos4210_gfrc_restart(s);
|
exynos4210_gfrc_restart(s);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case G_TCON:
|
case G_TCON:
|
||||||
old_val = s->g_timer.reg.tcon;
|
old_val = s->g_timer.reg.tcon;
|
||||||
|
@ -1207,7 +1203,6 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case G_INT_ENB:
|
case G_INT_ENB:
|
||||||
|
|
||||||
/* Raise IRQ if transition from disabled to enabled and CSTAT pending */
|
/* Raise IRQ if transition from disabled to enabled and CSTAT pending */
|
||||||
for (i = 0; i < MCT_GT_CMP_NUM; i++) {
|
for (i = 0; i < MCT_GT_CMP_NUM; i++) {
|
||||||
if ((value & G_INT_ENABLE(i)) > (s->g_timer.reg.tcon &
|
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;
|
break;
|
||||||
|
|
||||||
case L0_TCNTB: case L1_TCNTB:
|
case L0_TCNTB: case L1_TCNTB:
|
||||||
|
|
||||||
lt_i = GET_L_TIMER_IDX(offset);
|
lt_i = GET_L_TIMER_IDX(offset);
|
||||||
index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
|
index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
|
||||||
|
|
||||||
|
@ -1316,7 +1310,6 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case L0_ICNTB: case L1_ICNTB:
|
case L0_ICNTB: case L1_ICNTB:
|
||||||
|
|
||||||
lt_i = GET_L_TIMER_IDX(offset);
|
lt_i = GET_L_TIMER_IDX(offset);
|
||||||
index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
|
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) {
|
if (icntb_max[lt_i] < value) {
|
||||||
icntb_max[lt_i] = value;
|
icntb_max[lt_i] = value;
|
||||||
}
|
}
|
||||||
DPRINTF("local timer[%d] ICNTB write %llx; max=%x, min=%x\n\n",
|
DPRINTF("local timer[%d] ICNTB write %llx; max=%x, min=%x\n\n",
|
||||||
lt_i, value, icntb_max[lt_i], icntb_min[lt_i]);
|
lt_i, value, icntb_max[lt_i], icntb_min[lt_i]);
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case L0_FRCNTB: case L1_FRCNTB:
|
case L0_FRCNTB: case L1_FRCNTB:
|
||||||
|
|
||||||
lt_i = GET_L_TIMER_IDX(offset);
|
lt_i = GET_L_TIMER_IDX(offset);
|
||||||
index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
|
index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i);
|
||||||
|
|
||||||
|
|
|
@ -93,8 +93,6 @@ typedef struct Exynos4210State {
|
||||||
MemoryRegion iram_mem;
|
MemoryRegion iram_mem;
|
||||||
MemoryRegion irom_mem;
|
MemoryRegion irom_mem;
|
||||||
MemoryRegion irom_alias_mem;
|
MemoryRegion irom_alias_mem;
|
||||||
MemoryRegion dram0_mem;
|
|
||||||
MemoryRegion dram1_mem;
|
|
||||||
MemoryRegion boot_secondary;
|
MemoryRegion boot_secondary;
|
||||||
MemoryRegion bootreg_mem;
|
MemoryRegion bootreg_mem;
|
||||||
I2CBus *i2c_if[EXYNOS4210_I2C_NUMBER];
|
I2CBus *i2c_if[EXYNOS4210_I2C_NUMBER];
|
||||||
|
@ -103,8 +101,7 @@ typedef struct Exynos4210State {
|
||||||
void exynos4210_write_secondary(ARMCPU *cpu,
|
void exynos4210_write_secondary(ARMCPU *cpu,
|
||||||
const struct arm_boot_info *info);
|
const struct arm_boot_info *info);
|
||||||
|
|
||||||
Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
|
Exynos4210State *exynos4210_init(MemoryRegion *system_mem);
|
||||||
unsigned long ram_size);
|
|
||||||
|
|
||||||
/* Initialize exynos4210 IRQ subsystem stub */
|
/* Initialize exynos4210 IRQ subsystem stub */
|
||||||
qemu_irq *exynos4210_init_irq(Exynos4210Irq *env);
|
qemu_irq *exynos4210_init_irq(Exynos4210Irq *env);
|
||||||
|
|
|
@ -28,6 +28,13 @@
|
||||||
#define ITS_TRANS_SIZE 0x10000
|
#define ITS_TRANS_SIZE 0x10000
|
||||||
#define ITS_SIZE (ITS_CONTROL_SIZE + ITS_TRANS_SIZE)
|
#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 {
|
struct GICv3ITSState {
|
||||||
SysBusDevice parent_obj;
|
SysBusDevice parent_obj;
|
||||||
|
|
||||||
|
@ -43,6 +50,7 @@ struct GICv3ITSState {
|
||||||
|
|
||||||
/* Registers */
|
/* Registers */
|
||||||
uint32_t ctlr;
|
uint32_t ctlr;
|
||||||
|
uint32_t iidr;
|
||||||
uint64_t cbaser;
|
uint64_t cbaser;
|
||||||
uint64_t cwriter;
|
uint64_t cwriter;
|
||||||
uint64_t creadr;
|
uint64_t creadr;
|
||||||
|
|
|
@ -149,6 +149,8 @@ enum VMStateFlags {
|
||||||
typedef enum {
|
typedef enum {
|
||||||
MIG_PRI_DEFAULT = 0,
|
MIG_PRI_DEFAULT = 0,
|
||||||
MIG_PRI_IOMMU, /* Must happen before PCI devices */
|
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,
|
MIG_PRI_MAX,
|
||||||
} MigrationPriority;
|
} 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.
|
/* The host CPU doesn't have an easily accessible cycle counter.
|
||||||
Just return a monotonically increasing value. This will be
|
Just return a monotonically increasing value. This will be
|
||||||
totally wrong, but hopefully better than nothing. */
|
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 get_clock();
|
||||||
return ticks++;
|
|
||||||
}
|
}
|
||||||
#endif
|
#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
|
* @attr: the attribute of that group to set or get
|
||||||
* @val: pointer to a storage area for the value
|
* @val: pointer to a storage area for the value
|
||||||
* @write: true for set and false for get operation
|
* @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()
|
* Returns: 0 on success
|
||||||
* in order to check for the availability of optional attributes.
|
* < 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,
|
int kvm_device_access(int fd, int group, uint64_t attr,
|
||||||
void *val, bool write);
|
void *val, bool write, Error **errp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* kvm_create_device - create a KVM device for the device control API
|
* 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/option.h"
|
||||||
#include "qemu/config-file.h"
|
#include "qemu/config-file.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
#include "hw/hw.h"
|
#include "hw/hw.h"
|
||||||
#include "hw/pci/msi.h"
|
#include "hw/pci/msi.h"
|
||||||
#include "hw/pci/msix.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;
|
return kvm_device_ioctl(dev_fd, KVM_HAS_DEVICE_ATTR, &attribute) ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void kvm_device_access(int fd, int group, uint64_t attr,
|
int kvm_device_access(int fd, int group, uint64_t attr,
|
||||||
void *val, bool write)
|
void *val, bool write, Error **errp)
|
||||||
{
|
{
|
||||||
struct kvm_device_attr kvmattr;
|
struct kvm_device_attr kvmattr;
|
||||||
int err;
|
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,
|
write ? KVM_SET_DEVICE_ATTR : KVM_GET_DEVICE_ATTR,
|
||||||
&kvmattr);
|
&kvmattr);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
error_report("KVM_%s_DEVICE_ATTR failed: %s",
|
error_setg_errno(errp, -err,
|
||||||
write ? "SET" : "GET", strerror(-err));
|
"KVM_%s_DEVICE_ATTR failed: Group %d "
|
||||||
error_printf("Group %d attr 0x%016" PRIx64 "\n", group, attr);
|
"attr 0x%016" PRIx64,
|
||||||
abort();
|
write ? "SET" : "GET", group, attr);
|
||||||
}
|
}
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return 1 on success, 0 on failure */
|
/* Return 1 on success, 0 on failure */
|
||||||
|
|
Loading…
Reference in New Issue