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
					
				
			
		
					 5 changed files with 509 additions and 366 deletions
				
			
		| 
						 | 
				
			
			@ -344,6 +344,11 @@ enum irq_types {
 | 
			
		|||
	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
 | 
			
		||||
 * subclass bits in MCIC
 | 
			
		||||
| 
						 | 
				
			
			@ -421,13 +426,32 @@ struct kvm_s390_local_interrupt {
 | 
			
		|||
	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 {
 | 
			
		||||
	unsigned long pending_irqs;
 | 
			
		||||
	spinlock_t lock;
 | 
			
		||||
	struct list_head list;
 | 
			
		||||
	atomic_t active;
 | 
			
		||||
	struct list_head lists[FIRQ_LIST_COUNT];
 | 
			
		||||
	int counters[FIRQ_MAX_COUNT];
 | 
			
		||||
	struct kvm_s390_mchk_info mchk;
 | 
			
		||||
	struct kvm_s390_ext_info srv_signal;
 | 
			
		||||
	int next_rr_cpu;
 | 
			
		||||
	unsigned long idle_mask[BITS_TO_LONGS(KVM_MAX_VCPUS)];
 | 
			
		||||
	unsigned int irq_count;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
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/nmi.h>
 | 
			
		||||
#include <asm/switch_to.h>
 | 
			
		||||
#include <asm/isc.h>
 | 
			
		||||
#include <asm/sclp.h>
 | 
			
		||||
#include "kvm-s390.h"
 | 
			
		||||
#include "gaccess.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -1069,7 +1070,8 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 | 
			
		|||
		goto out_err;
 | 
			
		||||
 | 
			
		||||
	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);
 | 
			
		||||
	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);
 | 
			
		||||
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,
 | 
			
		||||
						    u64 cr6, u64 schid);
 | 
			
		||||
						    u64 isc_mask, u32 schid);
 | 
			
		||||
int kvm_s390_reinject_io_int(struct kvm *kvm,
 | 
			
		||||
			     struct kvm_s390_interrupt_info *inti);
 | 
			
		||||
int kvm_s390_mask_adapter(struct kvm *kvm, unsigned int id, bool masked);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -294,10 +294,13 @@ reinject_interrupt:
 | 
			
		|||
 | 
			
		||||
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,
 | 
			
		||||
				   vcpu->run->s.regs.gprs[1]);
 | 
			
		||||
	/* a valid schid has at least one bit set */
 | 
			
		||||
	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.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue