KVM: s390: deliver floating interrupts in order of priority
This patch makes interrupt handling compliant to the z/Architecture Principles of Operation with regard to interrupt priorities. Add a bitmap for pending floating interrupts. Each bit relates to a interrupt type and its list. A turned on bit indicates that a list contains items (interrupts) which need to be delivered. When delivering interrupts on a cpu we can merge the existing bitmap for cpu-local interrupts and floating interrupts and have a single mechanism for delivery. Currently we have one list for all kinds of floating interrupts and a corresponding spin lock. This patch adds a separate list per interrupt type. An exception to this are service signal and machine check interrupts, as there can be only one pending interrupt at a time. Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com> Acked-by: Cornelia Huck <cornelia.huck@de.ibm.com>
This commit is contained in:
parent
94aa033efc
commit
6d3da24141
|
@ -344,6 +344,11 @@ enum irq_types {
|
||||||
IRQ_PEND_COUNT
|
IRQ_PEND_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* We have 2M for virtio device descriptor pages. Smallest amount of
|
||||||
|
* memory per page is 24 bytes (1 queue), so (2048*1024) / 24 = 87381
|
||||||
|
*/
|
||||||
|
#define KVM_S390_MAX_VIRTIO_IRQS 87381
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Repressible (non-floating) machine check interrupts
|
* Repressible (non-floating) machine check interrupts
|
||||||
* subclass bits in MCIC
|
* subclass bits in MCIC
|
||||||
|
@ -421,13 +426,32 @@ struct kvm_s390_local_interrupt {
|
||||||
unsigned long pending_irqs;
|
unsigned long pending_irqs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define FIRQ_LIST_IO_ISC_0 0
|
||||||
|
#define FIRQ_LIST_IO_ISC_1 1
|
||||||
|
#define FIRQ_LIST_IO_ISC_2 2
|
||||||
|
#define FIRQ_LIST_IO_ISC_3 3
|
||||||
|
#define FIRQ_LIST_IO_ISC_4 4
|
||||||
|
#define FIRQ_LIST_IO_ISC_5 5
|
||||||
|
#define FIRQ_LIST_IO_ISC_6 6
|
||||||
|
#define FIRQ_LIST_IO_ISC_7 7
|
||||||
|
#define FIRQ_LIST_PFAULT 8
|
||||||
|
#define FIRQ_LIST_VIRTIO 9
|
||||||
|
#define FIRQ_LIST_COUNT 10
|
||||||
|
#define FIRQ_CNTR_IO 0
|
||||||
|
#define FIRQ_CNTR_SERVICE 1
|
||||||
|
#define FIRQ_CNTR_VIRTIO 2
|
||||||
|
#define FIRQ_CNTR_PFAULT 3
|
||||||
|
#define FIRQ_MAX_COUNT 4
|
||||||
|
|
||||||
struct kvm_s390_float_interrupt {
|
struct kvm_s390_float_interrupt {
|
||||||
|
unsigned long pending_irqs;
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
struct list_head list;
|
struct list_head lists[FIRQ_LIST_COUNT];
|
||||||
atomic_t active;
|
int counters[FIRQ_MAX_COUNT];
|
||||||
|
struct kvm_s390_mchk_info mchk;
|
||||||
|
struct kvm_s390_ext_info srv_signal;
|
||||||
int next_rr_cpu;
|
int next_rr_cpu;
|
||||||
unsigned long idle_mask[BITS_TO_LONGS(KVM_MAX_VCPUS)];
|
unsigned long idle_mask[BITS_TO_LONGS(KVM_MAX_VCPUS)];
|
||||||
unsigned int irq_count;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct kvm_hw_wp_info_arch {
|
struct kvm_hw_wp_info_arch {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -31,6 +31,7 @@
|
||||||
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
||||||
#include <asm/nmi.h>
|
#include <asm/nmi.h>
|
||||||
#include <asm/switch_to.h>
|
#include <asm/switch_to.h>
|
||||||
|
#include <asm/isc.h>
|
||||||
#include <asm/sclp.h>
|
#include <asm/sclp.h>
|
||||||
#include "kvm-s390.h"
|
#include "kvm-s390.h"
|
||||||
#include "gaccess.h"
|
#include "gaccess.h"
|
||||||
|
@ -1069,7 +1070,8 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
|
||||||
goto out_err;
|
goto out_err;
|
||||||
|
|
||||||
spin_lock_init(&kvm->arch.float_int.lock);
|
spin_lock_init(&kvm->arch.float_int.lock);
|
||||||
INIT_LIST_HEAD(&kvm->arch.float_int.list);
|
for (i = 0; i < FIRQ_LIST_COUNT; i++)
|
||||||
|
INIT_LIST_HEAD(&kvm->arch.float_int.lists[i]);
|
||||||
init_waitqueue_head(&kvm->arch.ipte_wq);
|
init_waitqueue_head(&kvm->arch.ipte_wq);
|
||||||
mutex_init(&kvm->arch.ipte_mutex);
|
mutex_init(&kvm->arch.ipte_mutex);
|
||||||
|
|
||||||
|
|
|
@ -178,7 +178,7 @@ int __must_check kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
|
||||||
struct kvm_s390_irq *irq);
|
struct kvm_s390_irq *irq);
|
||||||
int __must_check kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code);
|
int __must_check kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code);
|
||||||
struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm,
|
struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm,
|
||||||
u64 cr6, u64 schid);
|
u64 isc_mask, u32 schid);
|
||||||
int kvm_s390_reinject_io_int(struct kvm *kvm,
|
int kvm_s390_reinject_io_int(struct kvm *kvm,
|
||||||
struct kvm_s390_interrupt_info *inti);
|
struct kvm_s390_interrupt_info *inti);
|
||||||
int kvm_s390_mask_adapter(struct kvm *kvm, unsigned int id, bool masked);
|
int kvm_s390_mask_adapter(struct kvm *kvm, unsigned int id, bool masked);
|
||||||
|
|
|
@ -294,10 +294,13 @@ static int handle_tpi(struct kvm_vcpu *vcpu)
|
||||||
|
|
||||||
static int handle_tsch(struct kvm_vcpu *vcpu)
|
static int handle_tsch(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
struct kvm_s390_interrupt_info *inti;
|
struct kvm_s390_interrupt_info *inti = NULL;
|
||||||
|
const u64 isc_mask = 0xffUL << 24; /* all iscs set */
|
||||||
|
|
||||||
inti = kvm_s390_get_io_int(vcpu->kvm, 0,
|
/* a valid schid has at least one bit set */
|
||||||
vcpu->run->s.regs.gprs[1]);
|
if (vcpu->run->s.regs.gprs[1])
|
||||||
|
inti = kvm_s390_get_io_int(vcpu->kvm, isc_mask,
|
||||||
|
vcpu->run->s.regs.gprs[1]);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prepare exit to userspace.
|
* Prepare exit to userspace.
|
||||||
|
|
Loading…
Reference in New Issue