s390x/kvm: migrate vcpu interrupt state
This patch adds support to migrate vcpu interrupts. We use ioctl KVM_S390_GET_IRQ_STATE and _SET_IRQ_STATE to get/set the complete interrupt state for a vcpu. Reviewed-by: David Hildenbrand <dahi@linux.vnet.ibm.com> Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
This commit is contained in:
parent
46c804def4
commit
3cda44f7ba
@ -66,6 +66,9 @@ typedef struct S390CPU {
|
|||||||
/*< public >*/
|
/*< public >*/
|
||||||
|
|
||||||
CPUS390XState env;
|
CPUS390XState env;
|
||||||
|
/* needed for live migration */
|
||||||
|
void *irqstate;
|
||||||
|
uint32_t irqstate_saved_size;
|
||||||
} S390CPU;
|
} S390CPU;
|
||||||
|
|
||||||
static inline S390CPU *s390_env_get_cpu(CPUS390XState *env)
|
static inline S390CPU *s390_env_get_cpu(CPUS390XState *env)
|
||||||
|
@ -213,6 +213,7 @@ static void s390_cpu_finalize(Object *obj)
|
|||||||
S390CPU *cpu = S390_CPU(obj);
|
S390CPU *cpu = S390_CPU(obj);
|
||||||
|
|
||||||
qemu_unregister_reset(s390_cpu_machine_reset_cb, cpu);
|
qemu_unregister_reset(s390_cpu_machine_reset_cb, cpu);
|
||||||
|
g_free(cpu->irqstate);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1079,6 +1079,8 @@ void kvm_s390_clear_cmma_callback(void *opaque);
|
|||||||
int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state);
|
int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state);
|
||||||
void kvm_s390_reset_vcpu(S390CPU *cpu);
|
void kvm_s390_reset_vcpu(S390CPU *cpu);
|
||||||
int kvm_s390_set_mem_limit(KVMState *s, uint64_t new_limit, uint64_t *hw_limit);
|
int kvm_s390_set_mem_limit(KVMState *s, uint64_t new_limit, uint64_t *hw_limit);
|
||||||
|
void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu);
|
||||||
|
int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu);
|
||||||
#else
|
#else
|
||||||
static inline void kvm_s390_io_interrupt(uint16_t subchannel_id,
|
static inline void kvm_s390_io_interrupt(uint16_t subchannel_id,
|
||||||
uint16_t subchannel_nr,
|
uint16_t subchannel_nr,
|
||||||
@ -1121,6 +1123,13 @@ static inline int kvm_s390_set_mem_limit(KVMState *s, uint64_t new_limit,
|
|||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
static inline void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
static inline int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit)
|
static inline int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit)
|
||||||
|
@ -109,6 +109,14 @@
|
|||||||
#define ICPT_CPU_STOP 0x28
|
#define ICPT_CPU_STOP 0x28
|
||||||
#define ICPT_IO 0x40
|
#define ICPT_IO 0x40
|
||||||
|
|
||||||
|
#define NR_LOCAL_IRQS 32
|
||||||
|
/*
|
||||||
|
* Needs to be big enough to contain max_cpus emergency signals
|
||||||
|
* and in addition NR_LOCAL_IRQS interrupts
|
||||||
|
*/
|
||||||
|
#define VCPU_IRQ_BUF_SIZE (sizeof(struct kvm_s390_irq) * \
|
||||||
|
(max_cpus + NR_LOCAL_IRQS))
|
||||||
|
|
||||||
static CPUWatchpoint hw_watchpoint;
|
static CPUWatchpoint hw_watchpoint;
|
||||||
/*
|
/*
|
||||||
* We don't use a list because this structure is also used to transmit the
|
* We don't use a list because this structure is also used to transmit the
|
||||||
@ -274,6 +282,7 @@ int kvm_arch_init_vcpu(CPUState *cs)
|
|||||||
{
|
{
|
||||||
S390CPU *cpu = S390_CPU(cs);
|
S390CPU *cpu = S390_CPU(cs);
|
||||||
kvm_s390_set_cpu_state(cpu, cpu->env.cpu_state);
|
kvm_s390_set_cpu_state(cpu, cpu->env.cpu_state);
|
||||||
|
cpu->irqstate = g_malloc0(VCPU_IRQ_BUF_SIZE);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2059,6 +2068,52 @@ int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu)
|
||||||
|
{
|
||||||
|
struct kvm_s390_irq_state irq_state;
|
||||||
|
CPUState *cs = CPU(cpu);
|
||||||
|
int32_t bytes;
|
||||||
|
|
||||||
|
if (!kvm_check_extension(kvm_state, KVM_CAP_S390_IRQ_STATE)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
irq_state.buf = (uint64_t) cpu->irqstate;
|
||||||
|
irq_state.len = VCPU_IRQ_BUF_SIZE;
|
||||||
|
|
||||||
|
bytes = kvm_vcpu_ioctl(cs, KVM_S390_GET_IRQ_STATE, &irq_state);
|
||||||
|
if (bytes < 0) {
|
||||||
|
cpu->irqstate_saved_size = 0;
|
||||||
|
error_report("Migration of interrupt state failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cpu->irqstate_saved_size = bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu)
|
||||||
|
{
|
||||||
|
CPUState *cs = CPU(cpu);
|
||||||
|
struct kvm_s390_irq_state irq_state;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (!kvm_check_extension(kvm_state, KVM_CAP_S390_IRQ_STATE)) {
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cpu->irqstate_saved_size == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
irq_state.buf = (uint64_t) cpu->irqstate;
|
||||||
|
irq_state.len = cpu->irqstate_saved_size;
|
||||||
|
|
||||||
|
r = kvm_vcpu_ioctl(cs, KVM_S390_SET_IRQ_STATE, &irq_state);
|
||||||
|
if (r) {
|
||||||
|
error_report("Setting interrupt state failed %d", r);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
|
int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
|
||||||
uint64_t address, uint32_t data)
|
uint64_t address, uint32_t data)
|
||||||
{
|
{
|
||||||
|
@ -28,10 +28,19 @@ static int cpu_post_load(void *opaque, int version_id)
|
|||||||
*/
|
*/
|
||||||
if (kvm_enabled()) {
|
if (kvm_enabled()) {
|
||||||
kvm_s390_set_cpu_state(cpu, cpu->env.cpu_state);
|
kvm_s390_set_cpu_state(cpu, cpu->env.cpu_state);
|
||||||
|
return kvm_s390_vcpu_interrupt_post_load(cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
static void cpu_pre_save(void *opaque)
|
||||||
|
{
|
||||||
|
S390CPU *cpu = opaque;
|
||||||
|
|
||||||
|
if (kvm_enabled()) {
|
||||||
|
kvm_s390_vcpu_interrupt_pre_save(cpu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const VMStateDescription vmstate_fpu = {
|
const VMStateDescription vmstate_fpu = {
|
||||||
.name = "cpu/fpu",
|
.name = "cpu/fpu",
|
||||||
@ -67,7 +76,8 @@ static inline bool fpu_needed(void *opaque)
|
|||||||
const VMStateDescription vmstate_s390_cpu = {
|
const VMStateDescription vmstate_s390_cpu = {
|
||||||
.name = "cpu",
|
.name = "cpu",
|
||||||
.post_load = cpu_post_load,
|
.post_load = cpu_post_load,
|
||||||
.version_id = 3,
|
.pre_save = cpu_pre_save,
|
||||||
|
.version_id = 4,
|
||||||
.minimum_version_id = 3,
|
.minimum_version_id = 3,
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT64_ARRAY(env.regs, S390CPU, 16),
|
VMSTATE_UINT64_ARRAY(env.regs, S390CPU, 16),
|
||||||
@ -86,6 +96,9 @@ const VMStateDescription vmstate_s390_cpu = {
|
|||||||
VMSTATE_UINT64_ARRAY(env.cregs, S390CPU, 16),
|
VMSTATE_UINT64_ARRAY(env.cregs, S390CPU, 16),
|
||||||
VMSTATE_UINT8(env.cpu_state, S390CPU),
|
VMSTATE_UINT8(env.cpu_state, S390CPU),
|
||||||
VMSTATE_UINT8(env.sigp_order, S390CPU),
|
VMSTATE_UINT8(env.sigp_order, S390CPU),
|
||||||
|
VMSTATE_UINT32_V(irqstate_saved_size, S390CPU, 4),
|
||||||
|
VMSTATE_VBUFFER_UINT32(irqstate, S390CPU, 4, NULL, 0,
|
||||||
|
irqstate_saved_size),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
},
|
},
|
||||||
.subsections = (VMStateSubsection[]) {
|
.subsections = (VMStateSubsection[]) {
|
||||||
|
Loading…
Reference in New Issue
Block a user