* [GIT PULL 00/11] KVM: s390: Several changes for 3.19 (kvm/next)
@ 2014-11-28 13:25 Christian Borntraeger
2014-11-28 13:25 ` [GIT PULL 01/11] KVM: s390: Small fixes for the PFMF handler Christian Borntraeger
` (11 more replies)
0 siblings, 12 replies; 23+ messages in thread
From: Christian Borntraeger @ 2014-11-28 13:25 UTC (permalink / raw)
To: Paolo Bonzini
Cc: KVM, Alexander Graf, Cornelia Huck, Jens Freimann, linux-s390,
Christian Borntraeger
Paolo,
here is a bunch of changes dealing mostly with architectural compliance.
I have deferred the TOD clock interface (as well as a storage key
read/write) as we found some issues in our final internal review.
Depending on Linus schedule these might have to wait for the next merge
window or might still come next week as I want to gives other a chance
to comment on interface changes.
The following changes since commit b65d6e17fe2239c9b2051727903955d922083fbf:
kvm: x86: mask out XSAVES (2014-11-23 18:33:37 +0100)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux.git tags/kvm-s390-next-20141128
for you to fetch changes up to fc2020cfe9f8102d17dad79ed96dc68a9d84b19e:
KVM: s390: allow injecting all kinds of machine checks (2014-11-28 13:59:05 +0100)
----------------------------------------------------------------
KVM: s390: Several fixes,cleanups and reworks
Here is a bunch of fixes that deal mostly with architectural compliance:
- interrupt priorities
- interrupt handling
- intruction exit handling
We also provide a helper function for getting the guest visible storage key.
----------------------------------------------------------------
Christian Borntraeger (1):
KVM: s390: trigger the right CPU exit for floating interrupts
David Hildenbrand (1):
KVM: s390: external param not valid for cpu timer and ckc
Jason J. Herne (1):
KVM: S390: Create helper function get_guest_storage_key
Jens Freimann (6):
KVM: s390: refactor interrupt injection code
KVM: s390: add defines for virtio and pfault interrupt code
KVM: s390: refactor interrupt delivery code
KVM: s390: add bitmap for handling cpu-local interrupts
KVM: s390: handle pending local interrupts via bitmap
KVM: s390: allow injecting all kinds of machine checks
Thomas Huth (2):
KVM: s390: Small fixes for the PFMF handler
KVM: s390: Fix rewinding of the PSW pointing to an EXECUTE instruction
arch/s390/include/asm/kvm_host.h | 90 +++-
arch/s390/include/asm/pgalloc.h | 1 +
arch/s390/kvm/intercept.c | 20 +-
arch/s390/kvm/interrupt.c | 1037 +++++++++++++++++++++++++-------------
arch/s390/kvm/kvm-s390.c | 14 +-
arch/s390/kvm/kvm-s390.h | 11 +-
arch/s390/kvm/priv.c | 23 +-
arch/s390/kvm/sigp.c | 36 +-
arch/s390/mm/pgtable.c | 39 ++
9 files changed, 872 insertions(+), 399 deletions(-)
^ permalink raw reply [flat|nested] 23+ messages in thread
* [GIT PULL 01/11] KVM: s390: Small fixes for the PFMF handler
2014-11-28 13:25 [GIT PULL 00/11] KVM: s390: Several changes for 3.19 (kvm/next) Christian Borntraeger
@ 2014-11-28 13:25 ` Christian Borntraeger
2014-11-28 13:25 ` [GIT PULL 02/11] KVM: s390: Fix rewinding of the PSW pointing to an EXECUTE instruction Christian Borntraeger
` (10 subsequent siblings)
11 siblings, 0 replies; 23+ messages in thread
From: Christian Borntraeger @ 2014-11-28 13:25 UTC (permalink / raw)
To: Paolo Bonzini
Cc: KVM, Alexander Graf, Cornelia Huck, Jens Freimann, linux-s390,
Thomas Huth, Christian Borntraeger
From: Thomas Huth <thuth@linux.vnet.ibm.com>
This patch includes two small fixes for the PFMF handler: First, the
start address for PFMF has to be masked according to the current
addressing mode, which is now done with kvm_s390_logical_to_effective().
Second, the protection exceptions have a lower priority than the
specification exceptions, so the check for low-address protection
has to be moved after the last spot where we inject a specification
exception.
Signed-off-by: Thomas Huth <thuth@linux.vnet.ibm.com>
Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
---
arch/s390/kvm/priv.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index 9bde32f..04f70fd 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -646,10 +646,7 @@ static int handle_pfmf(struct kvm_vcpu *vcpu)
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
start = vcpu->run->s.regs.gprs[reg2] & PAGE_MASK;
- if (vcpu->run->s.regs.gprs[reg1] & PFMF_CF) {
- if (kvm_s390_check_low_addr_protection(vcpu, start))
- return kvm_s390_inject_prog_irq(vcpu, &vcpu->arch.pgm);
- }
+ start = kvm_s390_logical_to_effective(vcpu, start);
switch (vcpu->run->s.regs.gprs[reg1] & PFMF_FSC) {
case 0x00000000:
@@ -665,6 +662,12 @@ static int handle_pfmf(struct kvm_vcpu *vcpu)
default:
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
}
+
+ if (vcpu->run->s.regs.gprs[reg1] & PFMF_CF) {
+ if (kvm_s390_check_low_addr_protection(vcpu, start))
+ return kvm_s390_inject_prog_irq(vcpu, &vcpu->arch.pgm);
+ }
+
while (start < end) {
unsigned long useraddr, abs_addr;
--
1.9.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [GIT PULL 02/11] KVM: s390: Fix rewinding of the PSW pointing to an EXECUTE instruction
2014-11-28 13:25 [GIT PULL 00/11] KVM: s390: Several changes for 3.19 (kvm/next) Christian Borntraeger
2014-11-28 13:25 ` [GIT PULL 01/11] KVM: s390: Small fixes for the PFMF handler Christian Borntraeger
@ 2014-11-28 13:25 ` Christian Borntraeger
2014-11-28 13:25 ` [GIT PULL 03/11] KVM: s390: trigger the right CPU exit for floating interrupts Christian Borntraeger
` (9 subsequent siblings)
11 siblings, 0 replies; 23+ messages in thread
From: Christian Borntraeger @ 2014-11-28 13:25 UTC (permalink / raw)
To: Paolo Bonzini
Cc: KVM, Alexander Graf, Cornelia Huck, Jens Freimann, linux-s390,
Thomas Huth, Christian Borntraeger
From: Thomas Huth <thuth@linux.vnet.ibm.com>
A couple of our interception handlers rewind the PSW to the beginning
of the instruction to run the intercepted instruction again during the
next SIE entry. This normally works fine, but there is also the
possibility that the instruction did not get run directly but via an
EXECUTE instruction.
In this case, the PSW does not point to the instruction that caused the
interception, but to the EXECUTE instruction! So we've got to rewind the
PSW to the beginning of the EXECUTE instruction instead.
This is now accomplished with a new helper function kvm_s390_rewind_psw().
Signed-off-by: Thomas Huth <thuth@linux.vnet.ibm.com>
Reviewed-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
---
arch/s390/include/asm/kvm_host.h | 2 +-
arch/s390/kvm/intercept.c | 16 ++++++++++++++--
arch/s390/kvm/kvm-s390.h | 6 ++++--
arch/s390/kvm/priv.c | 12 ++++--------
4 files changed, 23 insertions(+), 13 deletions(-)
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index 7e02d77..ac7b074 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -123,7 +123,7 @@ struct kvm_s390_sie_block {
#define ICPT_PARTEXEC 0x38
#define ICPT_IOINST 0x40
__u8 icptcode; /* 0x0050 */
- __u8 reserved51; /* 0x0051 */
+ __u8 icptstatus; /* 0x0051 */
__u16 ihcpu; /* 0x0052 */
__u8 reserved54[2]; /* 0x0054 */
__u16 ipa; /* 0x0056 */
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index eaf4629..1d244df 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -38,6 +38,19 @@ static const intercept_handler_t instruction_handlers[256] = {
[0xeb] = kvm_s390_handle_eb,
};
+void kvm_s390_rewind_psw(struct kvm_vcpu *vcpu, int ilc)
+{
+ struct kvm_s390_sie_block *sie_block = vcpu->arch.sie_block;
+
+ /* Use the length of the EXECUTE instruction if necessary */
+ if (sie_block->icptstatus & 1) {
+ ilc = (sie_block->icptstatus >> 4) & 0x6;
+ if (!ilc)
+ ilc = 4;
+ }
+ sie_block->gpsw.addr = __rewind_psw(sie_block->gpsw, ilc);
+}
+
static int handle_noop(struct kvm_vcpu *vcpu)
{
switch (vcpu->arch.sie_block->icptcode) {
@@ -288,7 +301,6 @@ static int handle_external_interrupt(struct kvm_vcpu *vcpu)
*/
static int handle_mvpg_pei(struct kvm_vcpu *vcpu)
{
- psw_t *psw = &vcpu->arch.sie_block->gpsw;
unsigned long srcaddr, dstaddr;
int reg1, reg2, rc;
@@ -310,7 +322,7 @@ static int handle_mvpg_pei(struct kvm_vcpu *vcpu)
if (rc != 0)
return rc;
- psw->addr = __rewind_psw(*psw, 4);
+ kvm_s390_rewind_psw(vcpu, 4);
return 0;
}
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index 244d023..ff8d977 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -24,8 +24,6 @@ typedef int (*intercept_handler_t)(struct kvm_vcpu *vcpu);
/* declare vfacilities extern */
extern unsigned long *vfacilities;
-int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu);
-
/* Transactional Memory Execution related macros */
#define IS_TE_ENABLED(vcpu) ((vcpu->arch.sie_block->ecb & 0x10))
#define TDB_FORMAT1 1
@@ -152,6 +150,10 @@ void 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);
+/* implemented in intercept.c */
+void kvm_s390_rewind_psw(struct kvm_vcpu *vcpu, int ilc);
+int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu);
+
/* implemented in priv.c */
int is_valid_psw(psw_t *psw);
int kvm_s390_handle_b2(struct kvm_vcpu *vcpu);
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index 04f70fd..b37db1a 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -176,21 +176,18 @@ static int handle_skey(struct kvm_vcpu *vcpu)
if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
- vcpu->arch.sie_block->gpsw.addr =
- __rewind_psw(vcpu->arch.sie_block->gpsw, 4);
+ kvm_s390_rewind_psw(vcpu, 4);
VCPU_EVENT(vcpu, 4, "%s", "retrying storage key operation");
return 0;
}
static int handle_ipte_interlock(struct kvm_vcpu *vcpu)
{
- psw_t *psw = &vcpu->arch.sie_block->gpsw;
-
vcpu->stat.instruction_ipte_interlock++;
- if (psw_bits(*psw).p)
+ if (psw_bits(vcpu->arch.sie_block->gpsw).p)
return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
wait_event(vcpu->kvm->arch.ipte_wq, !ipte_lock_held(vcpu));
- psw->addr = __rewind_psw(*psw, 4);
+ kvm_s390_rewind_psw(vcpu, 4);
VCPU_EVENT(vcpu, 4, "%s", "retrying ipte interlock operation");
return 0;
}
@@ -721,8 +718,7 @@ static int handle_essa(struct kvm_vcpu *vcpu)
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
/* Rewind PSW to repeat the ESSA instruction */
- vcpu->arch.sie_block->gpsw.addr =
- __rewind_psw(vcpu->arch.sie_block->gpsw, 4);
+ kvm_s390_rewind_psw(vcpu, 4);
vcpu->arch.sie_block->cbrlo &= PAGE_MASK; /* reset nceo */
cbrlo = phys_to_virt(vcpu->arch.sie_block->cbrlo);
down_read(&gmap->mm->mmap_sem);
--
1.9.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [GIT PULL 03/11] KVM: s390: trigger the right CPU exit for floating interrupts
2014-11-28 13:25 [GIT PULL 00/11] KVM: s390: Several changes for 3.19 (kvm/next) Christian Borntraeger
2014-11-28 13:25 ` [GIT PULL 01/11] KVM: s390: Small fixes for the PFMF handler Christian Borntraeger
2014-11-28 13:25 ` [GIT PULL 02/11] KVM: s390: Fix rewinding of the PSW pointing to an EXECUTE instruction Christian Borntraeger
@ 2014-11-28 13:25 ` Christian Borntraeger
2014-11-28 13:25 ` [GIT PULL 04/11] KVM: S390: Create helper function get_guest_storage_key Christian Borntraeger
` (8 subsequent siblings)
11 siblings, 0 replies; 23+ messages in thread
From: Christian Borntraeger @ 2014-11-28 13:25 UTC (permalink / raw)
To: Paolo Bonzini
Cc: KVM, Alexander Graf, Cornelia Huck, Jens Freimann, linux-s390,
Christian Borntraeger
When injecting a floating interrupt and no CPU is idle we
kick one CPU to do an external exit. In case of I/O we
should trigger an I/O exit instead. This does not matter
for Linux guests as external and I/O interrupts are
enabled/disabled at the same time, but play safe anyway.
The same holds true for machine checks. Since there is no
special exit, just reuse the generic stop exit. The injection
code inside the VCPU loop will recheck anyway and rearm the
proper exits (e.g. control registers) if necessary.
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Reviewed-by: Thomas Huth <thuth@linux.vnet.ibm.com>
Reviewed-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
---
arch/s390/kvm/interrupt.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 4fc3fed..ead52bf 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -851,7 +851,17 @@ static int __inject_vm(struct kvm *kvm, struct kvm_s390_interrupt_info *inti)
dst_vcpu = kvm_get_vcpu(kvm, sigcpu);
li = &dst_vcpu->arch.local_int;
spin_lock(&li->lock);
- atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
+ switch (inti->type) {
+ case KVM_S390_MCHK:
+ atomic_set_mask(CPUSTAT_STOP_INT, li->cpuflags);
+ break;
+ case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
+ atomic_set_mask(CPUSTAT_IO_INT, li->cpuflags);
+ break;
+ default:
+ atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
+ break;
+ }
spin_unlock(&li->lock);
kvm_s390_vcpu_wakeup(kvm_get_vcpu(kvm, sigcpu));
unlock_fi:
--
1.9.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [GIT PULL 04/11] KVM: S390: Create helper function get_guest_storage_key
2014-11-28 13:25 [GIT PULL 00/11] KVM: s390: Several changes for 3.19 (kvm/next) Christian Borntraeger
` (2 preceding siblings ...)
2014-11-28 13:25 ` [GIT PULL 03/11] KVM: s390: trigger the right CPU exit for floating interrupts Christian Borntraeger
@ 2014-11-28 13:25 ` Christian Borntraeger
2014-11-28 13:25 ` [GIT PULL 05/11] KVM: s390: refactor interrupt injection code Christian Borntraeger
` (7 subsequent siblings)
11 siblings, 0 replies; 23+ messages in thread
From: Christian Borntraeger @ 2014-11-28 13:25 UTC (permalink / raw)
To: Paolo Bonzini
Cc: KVM, Alexander Graf, Cornelia Huck, Jens Freimann, linux-s390,
Jason J. Herne, Christian Borntraeger
From: "Jason J. Herne" <jjherne@linux.vnet.ibm.com>
Define get_guest_storage_key which can be used to get the value of a guest
storage key. This compliments the functionality provided by the helper function
set_guest_storage_key. Both functions are needed for live migration of s390
guests that use storage keys.
Signed-off-by: Jason J. Herne <jjherne@linux.vnet.ibm.com>
Reviewed-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
---
arch/s390/include/asm/pgalloc.h | 1 +
arch/s390/mm/pgtable.c | 39 +++++++++++++++++++++++++++++++++++++++
2 files changed, 40 insertions(+)
diff --git a/arch/s390/include/asm/pgalloc.h b/arch/s390/include/asm/pgalloc.h
index d39a31c..ede2eab 100644
--- a/arch/s390/include/asm/pgalloc.h
+++ b/arch/s390/include/asm/pgalloc.h
@@ -26,6 +26,7 @@ void page_table_reset_pgste(struct mm_struct *, unsigned long, unsigned long,
bool init_skey);
int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
unsigned long key, bool nq);
+unsigned long get_guest_storage_key(struct mm_struct *mm, unsigned long addr);
static inline void clear_table(unsigned long *s, unsigned long val, size_t n)
{
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
index cfecc24..0b18585 100644
--- a/arch/s390/mm/pgtable.c
+++ b/arch/s390/mm/pgtable.c
@@ -980,6 +980,45 @@ retry:
}
EXPORT_SYMBOL(set_guest_storage_key);
+unsigned long get_guest_storage_key(struct mm_struct *mm, unsigned long addr)
+{
+ spinlock_t *ptl;
+ pgste_t pgste;
+ pte_t *ptep;
+ uint64_t physaddr;
+ unsigned long key = 0;
+
+ down_read(&mm->mmap_sem);
+ ptep = get_locked_pte(mm, addr, &ptl);
+ if (unlikely(!ptep)) {
+ up_read(&mm->mmap_sem);
+ return -EFAULT;
+ }
+ pgste = pgste_get_lock(ptep);
+
+ if (pte_val(*ptep) & _PAGE_INVALID) {
+ key |= (pgste_val(pgste) & PGSTE_ACC_BITS) >> 56;
+ key |= (pgste_val(pgste) & PGSTE_FP_BIT) >> 56;
+ key |= (pgste_val(pgste) & PGSTE_GR_BIT) >> 48;
+ key |= (pgste_val(pgste) & PGSTE_GC_BIT) >> 48;
+ } else {
+ physaddr = pte_val(*ptep) & PAGE_MASK;
+ key = page_get_storage_key(physaddr);
+
+ /* Reflect guest's logical view, not physical */
+ if (pgste_val(pgste) & PGSTE_GR_BIT)
+ key |= _PAGE_REFERENCED;
+ if (pgste_val(pgste) & PGSTE_GC_BIT)
+ key |= _PAGE_CHANGED;
+ }
+
+ pgste_set_unlock(ptep, pgste);
+ pte_unmap_unlock(ptep, ptl);
+ up_read(&mm->mmap_sem);
+ return key;
+}
+EXPORT_SYMBOL(get_guest_storage_key);
+
#else /* CONFIG_PGSTE */
static inline int page_table_with_pgste(struct page *page)
--
1.9.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [GIT PULL 05/11] KVM: s390: refactor interrupt injection code
2014-11-28 13:25 [GIT PULL 00/11] KVM: s390: Several changes for 3.19 (kvm/next) Christian Borntraeger
` (3 preceding siblings ...)
2014-11-28 13:25 ` [GIT PULL 04/11] KVM: S390: Create helper function get_guest_storage_key Christian Borntraeger
@ 2014-11-28 13:25 ` Christian Borntraeger
2014-11-28 17:16 ` Paolo Bonzini
2014-11-28 13:25 ` [GIT PULL 06/11] KVM: s390: external param not valid for cpu timer and ckc Christian Borntraeger
` (6 subsequent siblings)
11 siblings, 1 reply; 23+ messages in thread
From: Christian Borntraeger @ 2014-11-28 13:25 UTC (permalink / raw)
To: Paolo Bonzini
Cc: KVM, Alexander Graf, Cornelia Huck, Jens Freimann, linux-s390,
Christian Borntraeger
From: Jens Freimann <jfrei@linux.vnet.ibm.com>
In preparation for the rework of the local interrupt injection code,
factor out injection routines from kvm_s390_inject_vcpu().
Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com>
Reviewed-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
---
arch/s390/kvm/interrupt.c | 221 +++++++++++++++++++++++++++++++++++-----------
1 file changed, 167 insertions(+), 54 deletions(-)
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index ead52bf..8f50f8c 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -719,6 +719,16 @@ int __must_check kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
return rc;
}
+static int __inject_prog_irq(struct kvm_vcpu *vcpu,
+ struct kvm_s390_interrupt_info *inti)
+{
+ struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
+
+ list_add(&inti->list, &li->list);
+ atomic_set(&li->active, 1);
+ return 0;
+}
+
int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code)
{
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
@@ -746,6 +756,7 @@ int kvm_s390_inject_prog_irq(struct kvm_vcpu *vcpu,
{
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
struct kvm_s390_interrupt_info *inti;
+ int rc;
inti = kzalloc(sizeof(*inti), GFP_KERNEL);
if (!inti)
@@ -759,10 +770,133 @@ int kvm_s390_inject_prog_irq(struct kvm_vcpu *vcpu,
inti->type = KVM_S390_PROGRAM_INT;
memcpy(&inti->pgm, pgm_info, sizeof(inti->pgm));
spin_lock(&li->lock);
- list_add(&inti->list, &li->list);
- atomic_set(&li->active, 1);
+ rc = __inject_prog_irq(vcpu, inti);
BUG_ON(waitqueue_active(li->wq));
spin_unlock(&li->lock);
+ return rc;
+}
+
+static int __inject_pfault_init(struct kvm_vcpu *vcpu,
+ struct kvm_s390_interrupt *s390int,
+ struct kvm_s390_interrupt_info *inti)
+{
+ struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
+
+ inti->ext.ext_params2 = s390int->parm64;
+ list_add_tail(&inti->list, &li->list);
+ atomic_set(&li->active, 1);
+ atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
+ return 0;
+}
+
+static int __inject_extcall(struct kvm_vcpu *vcpu,
+ struct kvm_s390_interrupt *s390int,
+ struct kvm_s390_interrupt_info *inti)
+{
+ struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
+
+ VCPU_EVENT(vcpu, 3, "inject: external call source-cpu:%u",
+ s390int->parm);
+ if (s390int->parm & 0xffff0000)
+ return -EINVAL;
+ inti->extcall.code = s390int->parm;
+ list_add_tail(&inti->list, &li->list);
+ atomic_set(&li->active, 1);
+ atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
+ return 0;
+}
+
+static int __inject_set_prefix(struct kvm_vcpu *vcpu,
+ struct kvm_s390_interrupt *s390int,
+ struct kvm_s390_interrupt_info *inti)
+{
+ struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
+
+ VCPU_EVENT(vcpu, 3, "inject: set prefix to %x (from user)",
+ s390int->parm);
+ inti->prefix.address = s390int->parm;
+ list_add_tail(&inti->list, &li->list);
+ atomic_set(&li->active, 1);
+ return 0;
+}
+
+static int __inject_sigp_stop(struct kvm_vcpu *vcpu,
+ struct kvm_s390_interrupt *s390int,
+ struct kvm_s390_interrupt_info *inti)
+{
+ struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
+
+ list_add_tail(&inti->list, &li->list);
+ atomic_set(&li->active, 1);
+ li->action_bits |= ACTION_STOP_ON_STOP;
+ return 0;
+}
+
+static int __inject_sigp_restart(struct kvm_vcpu *vcpu,
+ struct kvm_s390_interrupt *s390int,
+ struct kvm_s390_interrupt_info *inti)
+{
+ struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
+
+ VCPU_EVENT(vcpu, 3, "inject: type %x", s390int->type);
+ list_add_tail(&inti->list, &li->list);
+ atomic_set(&li->active, 1);
+ return 0;
+}
+
+static int __inject_sigp_emergency(struct kvm_vcpu *vcpu,
+ struct kvm_s390_interrupt *s390int,
+ struct kvm_s390_interrupt_info *inti)
+{
+ struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
+
+ VCPU_EVENT(vcpu, 3, "inject: emergency %u\n", s390int->parm);
+ if (s390int->parm & 0xffff0000)
+ return -EINVAL;
+ inti->emerg.code = s390int->parm;
+ list_add_tail(&inti->list, &li->list);
+ atomic_set(&li->active, 1);
+ atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
+ return 0;
+}
+
+static int __inject_mchk(struct kvm_vcpu *vcpu,
+ struct kvm_s390_interrupt *s390int,
+ struct kvm_s390_interrupt_info *inti)
+{
+ struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
+
+ VCPU_EVENT(vcpu, 5, "inject: machine check parm64:%llx",
+ s390int->parm64);
+ inti->mchk.mcic = s390int->parm64;
+ list_add_tail(&inti->list, &li->list);
+ atomic_set(&li->active, 1);
+ return 0;
+}
+
+static int __inject_ckc(struct kvm_vcpu *vcpu,
+ struct kvm_s390_interrupt *s390int,
+ struct kvm_s390_interrupt_info *inti)
+{
+ struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
+
+ VCPU_EVENT(vcpu, 3, "inject: type %x", s390int->type);
+ list_add_tail(&inti->list, &li->list);
+ atomic_set(&li->active, 1);
+ atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
+ return 0;
+}
+
+static int __inject_cpu_timer(struct kvm_vcpu *vcpu,
+ struct kvm_s390_interrupt *s390int,
+ struct kvm_s390_interrupt_info *inti)
+{
+ struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
+
+ VCPU_EVENT(vcpu, 3, "inject: type %x", s390int->type);
+ list_add_tail(&inti->list, &li->list);
+ atomic_set(&li->active, 1);
+ atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
return 0;
}
@@ -933,89 +1067,68 @@ void kvm_s390_reinject_io_int(struct kvm *kvm,
int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
struct kvm_s390_interrupt *s390int)
{
- struct kvm_s390_local_interrupt *li;
+ struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
struct kvm_s390_interrupt_info *inti;
+ int rc;
inti = kzalloc(sizeof(*inti), GFP_KERNEL);
if (!inti)
return -ENOMEM;
- switch (s390int->type) {
+ inti->type = s390int->type;
+
+ trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, s390int->type,
+ s390int->parm, 0, 2);
+ spin_lock(&li->lock);
+ switch (inti->type) {
case KVM_S390_PROGRAM_INT:
- if (s390int->parm & 0xffff0000) {
- kfree(inti);
- return -EINVAL;
- }
- inti->type = s390int->type;
- inti->pgm.code = s390int->parm;
VCPU_EVENT(vcpu, 3, "inject: program check %d (from user)",
s390int->parm);
+ inti->pgm.code = s390int->parm;
+ if (s390int->parm & 0xffff0000)
+ rc = -EINVAL;
+ else
+ rc = __inject_prog_irq(vcpu, inti);
break;
case KVM_S390_SIGP_SET_PREFIX:
- inti->prefix.address = s390int->parm;
- inti->type = s390int->type;
- VCPU_EVENT(vcpu, 3, "inject: set prefix to %x (from user)",
- s390int->parm);
+ rc = __inject_set_prefix(vcpu, s390int, inti);
break;
case KVM_S390_SIGP_STOP:
+ rc = __inject_sigp_stop(vcpu, s390int, inti);
+ break;
case KVM_S390_RESTART:
+ rc = __inject_sigp_restart(vcpu, s390int, inti);
+ break;
case KVM_S390_INT_CLOCK_COMP:
+ rc = __inject_ckc(vcpu, s390int, inti);
+ break;
case KVM_S390_INT_CPU_TIMER:
- VCPU_EVENT(vcpu, 3, "inject: type %x", s390int->type);
- inti->type = s390int->type;
+ rc = __inject_cpu_timer(vcpu, s390int, inti);
break;
case KVM_S390_INT_EXTERNAL_CALL:
- if (s390int->parm & 0xffff0000) {
- kfree(inti);
- return -EINVAL;
- }
- VCPU_EVENT(vcpu, 3, "inject: external call source-cpu:%u",
- s390int->parm);
- inti->type = s390int->type;
- inti->extcall.code = s390int->parm;
+ rc = __inject_extcall(vcpu, s390int, inti);
break;
case KVM_S390_INT_EMERGENCY:
- if (s390int->parm & 0xffff0000) {
- kfree(inti);
- return -EINVAL;
- }
- VCPU_EVENT(vcpu, 3, "inject: emergency %u\n", s390int->parm);
- inti->type = s390int->type;
- inti->emerg.code = s390int->parm;
+ rc = __inject_sigp_emergency(vcpu, s390int, inti);
break;
case KVM_S390_MCHK:
- VCPU_EVENT(vcpu, 5, "inject: machine check parm64:%llx",
- s390int->parm64);
- inti->type = s390int->type;
- inti->mchk.mcic = s390int->parm64;
+ rc = __inject_mchk(vcpu, s390int, inti);
break;
case KVM_S390_INT_PFAULT_INIT:
- inti->type = s390int->type;
- inti->ext.ext_params2 = s390int->parm64;
+ rc = __inject_pfault_init(vcpu, s390int, inti);
break;
case KVM_S390_INT_VIRTIO:
case KVM_S390_INT_SERVICE:
case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
default:
- kfree(inti);
- return -EINVAL;
+ rc = -EINVAL;
}
- trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, s390int->type, s390int->parm,
- s390int->parm64, 2);
-
- li = &vcpu->arch.local_int;
- spin_lock(&li->lock);
- if (inti->type == KVM_S390_PROGRAM_INT)
- list_add(&inti->list, &li->list);
- else
- list_add_tail(&inti->list, &li->list);
- atomic_set(&li->active, 1);
- if (inti->type == KVM_S390_SIGP_STOP)
- li->action_bits |= ACTION_STOP_ON_STOP;
- atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
spin_unlock(&li->lock);
- kvm_s390_vcpu_wakeup(vcpu);
- return 0;
+ if (!rc)
+ kvm_s390_vcpu_wakeup(vcpu);
+ else
+ kfree(inti);
+ return rc;
}
void kvm_s390_clear_float_irqs(struct kvm *kvm)
--
1.9.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [GIT PULL 06/11] KVM: s390: external param not valid for cpu timer and ckc
2014-11-28 13:25 [GIT PULL 00/11] KVM: s390: Several changes for 3.19 (kvm/next) Christian Borntraeger
` (4 preceding siblings ...)
2014-11-28 13:25 ` [GIT PULL 05/11] KVM: s390: refactor interrupt injection code Christian Borntraeger
@ 2014-11-28 13:25 ` Christian Borntraeger
2014-11-28 13:25 ` [GIT PULL 07/11] KVM: s390: add defines for virtio and pfault interrupt code Christian Borntraeger
` (5 subsequent siblings)
11 siblings, 0 replies; 23+ messages in thread
From: Christian Borntraeger @ 2014-11-28 13:25 UTC (permalink / raw)
To: Paolo Bonzini
Cc: KVM, Alexander Graf, Cornelia Huck, Jens Freimann, linux-s390,
David Hildenbrand, Christian Borntraeger
From: David Hildenbrand <dahi@linux.vnet.ibm.com>
The 32bit external interrupt parameter is only valid for timing-alert and
service-signal interrupts.
Signed-off-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
---
arch/s390/kvm/interrupt.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 8f50f8c..bccda76 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -345,12 +345,12 @@ static int __must_check __do_deliver_interrupt(struct kvm_vcpu *vcpu,
break;
case KVM_S390_INT_CLOCK_COMP:
trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
- inti->ext.ext_params, 0);
+ 0, 0);
rc = deliver_ckc_interrupt(vcpu);
break;
case KVM_S390_INT_CPU_TIMER:
trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
- inti->ext.ext_params, 0);
+ 0, 0);
rc = put_guest_lc(vcpu, EXT_IRQ_CPU_TIMER,
(u16 *)__LC_EXT_INT_CODE);
rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW,
@@ -358,8 +358,6 @@ static int __must_check __do_deliver_interrupt(struct kvm_vcpu *vcpu,
sizeof(psw_t));
rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW,
&vcpu->arch.sie_block->gpsw, sizeof(psw_t));
- rc |= put_guest_lc(vcpu, inti->ext.ext_params,
- (u32 *)__LC_EXT_PARAMS);
break;
case KVM_S390_INT_SERVICE:
VCPU_EVENT(vcpu, 4, "interrupt: sclp parm:%x",
--
1.9.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [GIT PULL 07/11] KVM: s390: add defines for virtio and pfault interrupt code
2014-11-28 13:25 [GIT PULL 00/11] KVM: s390: Several changes for 3.19 (kvm/next) Christian Borntraeger
` (5 preceding siblings ...)
2014-11-28 13:25 ` [GIT PULL 06/11] KVM: s390: external param not valid for cpu timer and ckc Christian Borntraeger
@ 2014-11-28 13:25 ` Christian Borntraeger
2014-11-28 13:25 ` [GIT PULL 08/11] KVM: s390: refactor interrupt delivery code Christian Borntraeger
` (4 subsequent siblings)
11 siblings, 0 replies; 23+ messages in thread
From: Christian Borntraeger @ 2014-11-28 13:25 UTC (permalink / raw)
To: Paolo Bonzini
Cc: KVM, Alexander Graf, Cornelia Huck, Jens Freimann, linux-s390,
Christian Borntraeger
From: Jens Freimann <jfrei@linux.vnet.ibm.com>
Get rid of open coded value for virtio and pfault completion interrupts.
Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com>
Reviewed-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
---
arch/s390/kvm/interrupt.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index bccda76..481f136 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -27,6 +27,8 @@
#define IOINT_CSSID_MASK 0x03fc0000
#define IOINT_AI_MASK 0x04000000
#define PFAULT_INIT 0x0600
+#define PFAULT_DONE 0x0680
+#define VIRTIO_PARAM 0x0d00
static int __must_check deliver_ckc_interrupt(struct kvm_vcpu *vcpu);
@@ -391,7 +393,7 @@ static int __must_check __do_deliver_interrupt(struct kvm_vcpu *vcpu,
trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, 0,
inti->ext.ext_params2);
rc = put_guest_lc(vcpu, 0x2603, (u16 *)__LC_EXT_INT_CODE);
- rc |= put_guest_lc(vcpu, 0x0680, (u16 *)__LC_EXT_CPU_ADDR);
+ rc |= put_guest_lc(vcpu, PFAULT_DONE, (u16 *)__LC_EXT_CPU_ADDR);
rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW,
&vcpu->arch.sie_block->gpsw,
sizeof(psw_t));
@@ -408,7 +410,7 @@ static int __must_check __do_deliver_interrupt(struct kvm_vcpu *vcpu,
inti->ext.ext_params,
inti->ext.ext_params2);
rc = put_guest_lc(vcpu, 0x2603, (u16 *)__LC_EXT_INT_CODE);
- rc |= put_guest_lc(vcpu, 0x0d00, (u16 *)__LC_EXT_CPU_ADDR);
+ rc |= put_guest_lc(vcpu, VIRTIO_PARAM, (u16 *)__LC_EXT_CPU_ADDR);
rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW,
&vcpu->arch.sie_block->gpsw,
sizeof(psw_t));
--
1.9.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [GIT PULL 08/11] KVM: s390: refactor interrupt delivery code
2014-11-28 13:25 [GIT PULL 00/11] KVM: s390: Several changes for 3.19 (kvm/next) Christian Borntraeger
` (6 preceding siblings ...)
2014-11-28 13:25 ` [GIT PULL 07/11] KVM: s390: add defines for virtio and pfault interrupt code Christian Borntraeger
@ 2014-11-28 13:25 ` Christian Borntraeger
2014-11-28 17:17 ` Paolo Bonzini
2014-11-28 13:25 ` [GIT PULL 09/11] KVM: s390: add bitmap for handling cpu-local interrupts Christian Borntraeger
` (3 subsequent siblings)
11 siblings, 1 reply; 23+ messages in thread
From: Christian Borntraeger @ 2014-11-28 13:25 UTC (permalink / raw)
To: Paolo Bonzini
Cc: KVM, Alexander Graf, Cornelia Huck, Jens Freimann, linux-s390,
Christian Borntraeger
From: Jens Freimann <jfrei@linux.vnet.ibm.com>
Move delivery code for cpu-local interrupt from the huge do_deliver_interrupt()
to smaller functions which handle one type of interrupt.
Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com>
Reviewed-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
---
arch/s390/kvm/interrupt.c | 459 ++++++++++++++++++++++++++++------------------
1 file changed, 282 insertions(+), 177 deletions(-)
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 481f136..0d7f0a7 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -30,8 +30,6 @@
#define PFAULT_DONE 0x0680
#define VIRTIO_PARAM 0x0d00
-static int __must_check deliver_ckc_interrupt(struct kvm_vcpu *vcpu);
-
static int is_ioint(u64 type)
{
return ((type & 0xfffe0000u) != 0xfffe0000u);
@@ -228,12 +226,183 @@ static u16 get_ilc(struct kvm_vcpu *vcpu)
}
}
-static int __must_check __deliver_prog_irq(struct kvm_vcpu *vcpu,
- struct kvm_s390_pgm_info *pgm_info)
+static int __must_check __deliver_cpu_timer(struct kvm_vcpu *vcpu)
+{
+ int rc;
+
+ trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_INT_CPU_TIMER,
+ 0, 0);
+
+ rc = put_guest_lc(vcpu, EXT_IRQ_CPU_TIMER,
+ (u16 *)__LC_EXT_INT_CODE);
+ rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW,
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW,
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ return rc;
+}
+
+static int __must_check __deliver_ckc(struct kvm_vcpu *vcpu)
+{
+ int rc;
+
+ trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_INT_CLOCK_COMP,
+ 0, 0);
+
+ rc = put_guest_lc(vcpu, EXT_IRQ_CLK_COMP,
+ (u16 __user *)__LC_EXT_INT_CODE);
+ rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW,
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW,
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ return rc;
+}
+
+static int __must_check __deliver_pfault_init(struct kvm_vcpu *vcpu,
+ struct kvm_s390_interrupt_info *inti)
+{
+ struct kvm_s390_ext_info *ext = &inti->ext;
+ int rc;
+
+ VCPU_EVENT(vcpu, 4, "interrupt: pfault init parm:%x,parm64:%llx",
+ 0, ext->ext_params2);
+ trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id,
+ KVM_S390_INT_PFAULT_INIT,
+ 0, ext->ext_params2);
+
+ rc = put_guest_lc(vcpu, EXT_IRQ_CP_SERVICE, (u16 *) __LC_EXT_INT_CODE);
+ rc |= put_guest_lc(vcpu, PFAULT_INIT, (u16 *) __LC_EXT_CPU_ADDR);
+ rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW,
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW,
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ rc |= put_guest_lc(vcpu, ext->ext_params2, (u64 *) __LC_EXT_PARAMS2);
+ return rc;
+}
+
+static int __must_check __deliver_machine_check(struct kvm_vcpu *vcpu,
+ struct kvm_s390_interrupt_info *inti)
+{
+ struct kvm_s390_mchk_info *mchk = &inti->mchk;
+ int rc;
+
+ VCPU_EVENT(vcpu, 4, "interrupt: machine check mcic=%llx",
+ mchk->mcic);
+ trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_MCHK,
+ mchk->cr14, mchk->mcic);
+
+ rc = kvm_s390_vcpu_store_status(vcpu, KVM_S390_STORE_STATUS_PREFIXED);
+ rc |= put_guest_lc(vcpu, mchk->mcic,
+ (u64 __user *) __LC_MCCK_CODE);
+ rc |= put_guest_lc(vcpu, mchk->failing_storage_address,
+ (u64 __user *) __LC_MCCK_FAIL_STOR_ADDR);
+ rc |= write_guest_lc(vcpu, __LC_PSW_SAVE_AREA,
+ &mchk->fixed_logout, sizeof(mchk->fixed_logout));
+ rc |= write_guest_lc(vcpu, __LC_MCK_OLD_PSW,
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ rc |= read_guest_lc(vcpu, __LC_MCK_NEW_PSW,
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ return rc;
+}
+
+static int __must_check __deliver_restart(struct kvm_vcpu *vcpu)
+{
+ int rc;
+
+ VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu restart");
+ vcpu->stat.deliver_restart_signal++;
+ trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_RESTART, 0, 0);
+
+ rc = write_guest_lc(vcpu,
+ offsetof(struct _lowcore, restart_old_psw),
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ rc |= read_guest_lc(vcpu, offsetof(struct _lowcore, restart_psw),
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ return rc;
+}
+
+static int __must_check __deliver_stop(struct kvm_vcpu *vcpu)
+{
+ VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu stop");
+ vcpu->stat.deliver_stop_signal++;
+ trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_SIGP_STOP,
+ 0, 0);
+
+ __set_cpuflag(vcpu, CPUSTAT_STOP_INT);
+ return 0;
+}
+
+static int __must_check __deliver_set_prefix(struct kvm_vcpu *vcpu,
+ struct kvm_s390_interrupt_info *inti)
+{
+ struct kvm_s390_prefix_info *prefix = &inti->prefix;
+
+ VCPU_EVENT(vcpu, 4, "interrupt: set prefix to %x", prefix->address);
+ vcpu->stat.deliver_prefix_signal++;
+ trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id,
+ KVM_S390_SIGP_SET_PREFIX,
+ prefix->address, 0);
+
+ kvm_s390_set_prefix(vcpu, prefix->address);
+ return 0;
+}
+
+static int __must_check __deliver_emergency_signal(struct kvm_vcpu *vcpu,
+ struct kvm_s390_interrupt_info *inti)
+{
+ struct kvm_s390_emerg_info *emerg = &inti->emerg;
+ int rc;
+
+ VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp emerg");
+ vcpu->stat.deliver_emergency_signal++;
+ trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
+ inti->emerg.code, 0);
+
+ rc = put_guest_lc(vcpu, EXT_IRQ_EMERGENCY_SIG,
+ (u16 *)__LC_EXT_INT_CODE);
+ rc |= put_guest_lc(vcpu, emerg->code, (u16 *)__LC_EXT_CPU_ADDR);
+ rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW,
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW,
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ return rc;
+}
+
+static int __must_check __deliver_external_call(struct kvm_vcpu *vcpu,
+ struct kvm_s390_interrupt_info *inti)
+{
+ struct kvm_s390_extcall_info *extcall = &inti->extcall;
+ int rc;
+
+ VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp ext call");
+ vcpu->stat.deliver_external_call++;
+ trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id,
+ KVM_S390_INT_EXTERNAL_CALL,
+ extcall->code, 0);
+
+ rc = put_guest_lc(vcpu, EXT_IRQ_EXTERNAL_CALL,
+ (u16 *)__LC_EXT_INT_CODE);
+ rc |= put_guest_lc(vcpu, extcall->code, (u16 *)__LC_EXT_CPU_ADDR);
+ rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW,
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW, &vcpu->arch.sie_block->gpsw,
+ sizeof(psw_t));
+ return rc;
+}
+
+static int __must_check __deliver_prog(struct kvm_vcpu *vcpu,
+ struct kvm_s390_interrupt_info *inti)
{
+ struct kvm_s390_pgm_info *pgm_info = &inti->pgm;
int rc = 0;
u16 ilc = get_ilc(vcpu);
+ VCPU_EVENT(vcpu, 4, "interrupt: pgm check code:%x, ilc:%x",
+ pgm_info->code, ilc);
+ vcpu->stat.deliver_program_int++;
+ trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_PROGRAM_INT,
+ pgm_info->code, 0);
+
switch (pgm_info->code & ~PGM_PER) {
case PGM_AFX_TRANSLATION:
case PGM_ASX_TRANSLATION:
@@ -306,202 +475,151 @@ static int __must_check __deliver_prog_irq(struct kvm_vcpu *vcpu,
&vcpu->arch.sie_block->gpsw, sizeof(psw_t));
rc |= read_guest_lc(vcpu, __LC_PGM_NEW_PSW,
&vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ return rc;
+}
+
+static int __must_check __deliver_service(struct kvm_vcpu *vcpu,
+ struct kvm_s390_interrupt_info *inti)
+{
+ int rc;
+
+ VCPU_EVENT(vcpu, 4, "interrupt: sclp parm:%x",
+ inti->ext.ext_params);
+ vcpu->stat.deliver_service_signal++;
+ trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
+ inti->ext.ext_params, 0);
+
+ rc = put_guest_lc(vcpu, EXT_IRQ_SERVICE_SIG, (u16 *)__LC_EXT_INT_CODE);
+ rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW,
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW,
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ rc |= put_guest_lc(vcpu, inti->ext.ext_params,
+ (u32 *)__LC_EXT_PARAMS);
+ return rc;
+}
+
+static int __must_check __deliver_pfault_done(struct kvm_vcpu *vcpu,
+ struct kvm_s390_interrupt_info *inti)
+{
+ int rc;
+
+ trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id,
+ KVM_S390_INT_PFAULT_DONE, 0,
+ inti->ext.ext_params2);
+ rc = put_guest_lc(vcpu, EXT_IRQ_CP_SERVICE, (u16 *)__LC_EXT_INT_CODE);
+ rc |= put_guest_lc(vcpu, PFAULT_DONE, (u16 *)__LC_EXT_CPU_ADDR);
+ rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW,
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW,
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ rc |= put_guest_lc(vcpu, inti->ext.ext_params2,
+ (u64 *)__LC_EXT_PARAMS2);
+ return rc;
+}
+
+static int __must_check __deliver_virtio(struct kvm_vcpu *vcpu,
+ struct kvm_s390_interrupt_info *inti)
+{
+ int rc;
+
+ VCPU_EVENT(vcpu, 4, "interrupt: virtio parm:%x,parm64:%llx",
+ inti->ext.ext_params, inti->ext.ext_params2);
+ vcpu->stat.deliver_virtio_interrupt++;
+ trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
+ inti->ext.ext_params,
+ inti->ext.ext_params2);
+
+ rc = put_guest_lc(vcpu, EXT_IRQ_CP_SERVICE, (u16 *)__LC_EXT_INT_CODE);
+ rc |= put_guest_lc(vcpu, VIRTIO_PARAM, (u16 *)__LC_EXT_CPU_ADDR);
+ rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW,
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW,
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ rc |= put_guest_lc(vcpu, inti->ext.ext_params,
+ (u32 *)__LC_EXT_PARAMS);
+ rc |= put_guest_lc(vcpu, inti->ext.ext_params2,
+ (u64 *)__LC_EXT_PARAMS2);
+ return rc;
+}
+
+static int __must_check __deliver_io(struct kvm_vcpu *vcpu,
+ struct kvm_s390_interrupt_info *inti)
+{
+ int rc;
+
+ VCPU_EVENT(vcpu, 4, "interrupt: I/O %llx", inti->type);
+ vcpu->stat.deliver_io_int++;
+ trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
+ ((__u32)inti->io.subchannel_id << 16) |
+ inti->io.subchannel_nr,
+ ((__u64)inti->io.io_int_parm << 32) |
+ inti->io.io_int_word);
+
+ rc = put_guest_lc(vcpu, inti->io.subchannel_id,
+ (u16 *)__LC_SUBCHANNEL_ID);
+ rc |= put_guest_lc(vcpu, inti->io.subchannel_nr,
+ (u16 *)__LC_SUBCHANNEL_NR);
+ rc |= put_guest_lc(vcpu, inti->io.io_int_parm,
+ (u32 *)__LC_IO_INT_PARM);
+ rc |= put_guest_lc(vcpu, inti->io.io_int_word,
+ (u32 *)__LC_IO_INT_WORD);
+ rc |= write_guest_lc(vcpu, __LC_IO_OLD_PSW,
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ rc |= read_guest_lc(vcpu, __LC_IO_NEW_PSW,
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
return rc;
}
static int __must_check __do_deliver_interrupt(struct kvm_vcpu *vcpu,
struct kvm_s390_interrupt_info *inti)
{
- const unsigned short table[] = { 2, 4, 4, 6 };
- int rc = 0;
+ int rc;
switch (inti->type) {
case KVM_S390_INT_EMERGENCY:
- VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp emerg");
- vcpu->stat.deliver_emergency_signal++;
- trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
- inti->emerg.code, 0);
- rc = put_guest_lc(vcpu, 0x1201, (u16 *)__LC_EXT_INT_CODE);
- rc |= put_guest_lc(vcpu, inti->emerg.code,
- (u16 *)__LC_EXT_CPU_ADDR);
- rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW,
- &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
- rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW,
- &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ rc = __deliver_emergency_signal(vcpu, inti);
break;
case KVM_S390_INT_EXTERNAL_CALL:
- VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp ext call");
- vcpu->stat.deliver_external_call++;
- trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
- inti->extcall.code, 0);
- rc = put_guest_lc(vcpu, 0x1202, (u16 *)__LC_EXT_INT_CODE);
- rc |= put_guest_lc(vcpu, inti->extcall.code,
- (u16 *)__LC_EXT_CPU_ADDR);
- rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW,
- &vcpu->arch.sie_block->gpsw,
- sizeof(psw_t));
- rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW,
- &vcpu->arch.sie_block->gpsw,
- sizeof(psw_t));
+ rc = __deliver_external_call(vcpu, inti);
break;
case KVM_S390_INT_CLOCK_COMP:
- trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
- 0, 0);
- rc = deliver_ckc_interrupt(vcpu);
+ rc = __deliver_ckc(vcpu);
break;
case KVM_S390_INT_CPU_TIMER:
- trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
- 0, 0);
- rc = put_guest_lc(vcpu, EXT_IRQ_CPU_TIMER,
- (u16 *)__LC_EXT_INT_CODE);
- rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW,
- &vcpu->arch.sie_block->gpsw,
- sizeof(psw_t));
- rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW,
- &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ rc = __deliver_cpu_timer(vcpu);
break;
case KVM_S390_INT_SERVICE:
- VCPU_EVENT(vcpu, 4, "interrupt: sclp parm:%x",
- inti->ext.ext_params);
- vcpu->stat.deliver_service_signal++;
- trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
- inti->ext.ext_params, 0);
- rc = put_guest_lc(vcpu, 0x2401, (u16 *)__LC_EXT_INT_CODE);
- rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW,
- &vcpu->arch.sie_block->gpsw,
- sizeof(psw_t));
- rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW,
- &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
- rc |= put_guest_lc(vcpu, inti->ext.ext_params,
- (u32 *)__LC_EXT_PARAMS);
+ rc = __deliver_service(vcpu, inti);
break;
case KVM_S390_INT_PFAULT_INIT:
- trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, 0,
- inti->ext.ext_params2);
- rc = put_guest_lc(vcpu, EXT_IRQ_CP_SERVICE,
- (u16 *) __LC_EXT_INT_CODE);
- rc |= put_guest_lc(vcpu, PFAULT_INIT, (u16 *) __LC_EXT_CPU_ADDR);
- rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW,
- &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
- rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW,
- &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
- rc |= put_guest_lc(vcpu, inti->ext.ext_params2,
- (u64 *) __LC_EXT_PARAMS2);
+ rc = __deliver_pfault_init(vcpu, inti);
break;
case KVM_S390_INT_PFAULT_DONE:
- trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, 0,
- inti->ext.ext_params2);
- rc = put_guest_lc(vcpu, 0x2603, (u16 *)__LC_EXT_INT_CODE);
- rc |= put_guest_lc(vcpu, PFAULT_DONE, (u16 *)__LC_EXT_CPU_ADDR);
- rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW,
- &vcpu->arch.sie_block->gpsw,
- sizeof(psw_t));
- rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW,
- &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
- rc |= put_guest_lc(vcpu, inti->ext.ext_params2,
- (u64 *)__LC_EXT_PARAMS2);
+ rc = __deliver_pfault_done(vcpu, inti);
break;
case KVM_S390_INT_VIRTIO:
- VCPU_EVENT(vcpu, 4, "interrupt: virtio parm:%x,parm64:%llx",
- inti->ext.ext_params, inti->ext.ext_params2);
- vcpu->stat.deliver_virtio_interrupt++;
- trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
- inti->ext.ext_params,
- inti->ext.ext_params2);
- rc = put_guest_lc(vcpu, 0x2603, (u16 *)__LC_EXT_INT_CODE);
- rc |= put_guest_lc(vcpu, VIRTIO_PARAM, (u16 *)__LC_EXT_CPU_ADDR);
- rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW,
- &vcpu->arch.sie_block->gpsw,
- sizeof(psw_t));
- rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW,
- &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
- rc |= put_guest_lc(vcpu, inti->ext.ext_params,
- (u32 *)__LC_EXT_PARAMS);
- rc |= put_guest_lc(vcpu, inti->ext.ext_params2,
- (u64 *)__LC_EXT_PARAMS2);
+ rc = __deliver_virtio(vcpu, inti);
break;
case KVM_S390_SIGP_STOP:
- VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu stop");
- vcpu->stat.deliver_stop_signal++;
- trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
- 0, 0);
- __set_intercept_indicator(vcpu, inti);
+ rc = __deliver_stop(vcpu);
break;
-
case KVM_S390_SIGP_SET_PREFIX:
- VCPU_EVENT(vcpu, 4, "interrupt: set prefix to %x",
- inti->prefix.address);
- vcpu->stat.deliver_prefix_signal++;
- trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
- inti->prefix.address, 0);
- kvm_s390_set_prefix(vcpu, inti->prefix.address);
+ rc = __deliver_set_prefix(vcpu, inti);
break;
-
case KVM_S390_RESTART:
- VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu restart");
- vcpu->stat.deliver_restart_signal++;
- trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
- 0, 0);
- rc = write_guest_lc(vcpu,
- offsetof(struct _lowcore, restart_old_psw),
- &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
- rc |= read_guest_lc(vcpu, offsetof(struct _lowcore, restart_psw),
- &vcpu->arch.sie_block->gpsw,
- sizeof(psw_t));
+ rc = __deliver_restart(vcpu);
break;
case KVM_S390_PROGRAM_INT:
- VCPU_EVENT(vcpu, 4, "interrupt: pgm check code:%x, ilc:%x",
- inti->pgm.code,
- table[vcpu->arch.sie_block->ipa >> 14]);
- vcpu->stat.deliver_program_int++;
- trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
- inti->pgm.code, 0);
- rc = __deliver_prog_irq(vcpu, &inti->pgm);
+ rc = __deliver_prog(vcpu, inti);
break;
-
case KVM_S390_MCHK:
- VCPU_EVENT(vcpu, 4, "interrupt: machine check mcic=%llx",
- inti->mchk.mcic);
- trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
- inti->mchk.cr14,
- inti->mchk.mcic);
- rc = kvm_s390_vcpu_store_status(vcpu,
- KVM_S390_STORE_STATUS_PREFIXED);
- rc |= put_guest_lc(vcpu, inti->mchk.mcic, (u64 *)__LC_MCCK_CODE);
- rc |= write_guest_lc(vcpu, __LC_MCK_OLD_PSW,
- &vcpu->arch.sie_block->gpsw,
- sizeof(psw_t));
- rc |= read_guest_lc(vcpu, __LC_MCK_NEW_PSW,
- &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ rc = __deliver_machine_check(vcpu, inti);
break;
-
case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
- {
- __u32 param0 = ((__u32)inti->io.subchannel_id << 16) |
- inti->io.subchannel_nr;
- __u64 param1 = ((__u64)inti->io.io_int_parm << 32) |
- inti->io.io_int_word;
- VCPU_EVENT(vcpu, 4, "interrupt: I/O %llx", inti->type);
- vcpu->stat.deliver_io_int++;
- trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
- param0, param1);
- rc = put_guest_lc(vcpu, inti->io.subchannel_id,
- (u16 *)__LC_SUBCHANNEL_ID);
- rc |= put_guest_lc(vcpu, inti->io.subchannel_nr,
- (u16 *)__LC_SUBCHANNEL_NR);
- rc |= put_guest_lc(vcpu, inti->io.io_int_parm,
- (u32 *)__LC_IO_INT_PARM);
- rc |= put_guest_lc(vcpu, inti->io.io_int_word,
- (u32 *)__LC_IO_INT_WORD);
- rc |= write_guest_lc(vcpu, __LC_IO_OLD_PSW,
- &vcpu->arch.sie_block->gpsw,
- sizeof(psw_t));
- rc |= read_guest_lc(vcpu, __LC_IO_NEW_PSW,
- &vcpu->arch.sie_block->gpsw,
- sizeof(psw_t));
+ rc = __deliver_io(vcpu, inti);
break;
- }
default:
BUG();
}
@@ -509,19 +627,6 @@ static int __must_check __do_deliver_interrupt(struct kvm_vcpu *vcpu,
return rc;
}
-static int __must_check deliver_ckc_interrupt(struct kvm_vcpu *vcpu)
-{
- int rc;
-
- rc = put_guest_lc(vcpu, 0x1004, (u16 __user *)__LC_EXT_INT_CODE);
- rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW,
- &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
- rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW,
- &vcpu->arch.sie_block->gpsw,
- sizeof(psw_t));
- return rc;
-}
-
/* Check whether SIGP interpretation facility has an external call pending */
int kvm_s390_si_ext_call_pending(struct kvm_vcpu *vcpu)
{
@@ -691,7 +796,7 @@ int __must_check kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
}
if (!rc && kvm_cpu_has_pending_timer(vcpu))
- rc = deliver_ckc_interrupt(vcpu);
+ rc = __deliver_ckc(vcpu);
if (!rc && atomic_read(&fi->active)) {
do {
--
1.9.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [GIT PULL 09/11] KVM: s390: add bitmap for handling cpu-local interrupts
2014-11-28 13:25 [GIT PULL 00/11] KVM: s390: Several changes for 3.19 (kvm/next) Christian Borntraeger
` (7 preceding siblings ...)
2014-11-28 13:25 ` [GIT PULL 08/11] KVM: s390: refactor interrupt delivery code Christian Borntraeger
@ 2014-11-28 13:25 ` Christian Borntraeger
2014-11-28 17:18 ` Paolo Bonzini
2014-11-28 13:25 ` [GIT PULL 10/11] KVM: s390: handle pending local interrupts via bitmap Christian Borntraeger
` (2 subsequent siblings)
11 siblings, 1 reply; 23+ messages in thread
From: Christian Borntraeger @ 2014-11-28 13:25 UTC (permalink / raw)
To: Paolo Bonzini
Cc: KVM, Alexander Graf, Cornelia Huck, Jens Freimann, linux-s390,
Christian Borntraeger
From: Jens Freimann <jfrei@linux.vnet.ibm.com>
Adds a bitmap to the vcpu structure which is used to keep track
of local pending interrupts. Also add enum with all interrupt
types sorted in order of priority (highest to lowest)
Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <thuth@linux.vnet.ibm.com>
Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Reviewed-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
---
arch/s390/include/asm/kvm_host.h | 86 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 86 insertions(+)
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index ac7b074..624a821 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -295,6 +295,79 @@ struct kvm_vcpu_stat {
#define PGM_PER 0x80
#define PGM_CRYPTO_OPERATION 0x119
+/* irq types in order of priority */
+enum irq_types {
+ IRQ_PEND_MCHK_EX = 0,
+ IRQ_PEND_SVC,
+ IRQ_PEND_PROG,
+ IRQ_PEND_MCHK_REP,
+ IRQ_PEND_EXT_IRQ_KEY,
+ IRQ_PEND_EXT_MALFUNC,
+ IRQ_PEND_EXT_EMERGENCY,
+ IRQ_PEND_EXT_EXTERNAL,
+ IRQ_PEND_EXT_CLOCK_COMP,
+ IRQ_PEND_EXT_CPU_TIMER,
+ IRQ_PEND_EXT_TIMING,
+ IRQ_PEND_EXT_SERVICE,
+ IRQ_PEND_EXT_HOST,
+ IRQ_PEND_PFAULT_INIT,
+ IRQ_PEND_PFAULT_DONE,
+ IRQ_PEND_VIRTIO,
+ IRQ_PEND_IO_ISC_0,
+ IRQ_PEND_IO_ISC_1,
+ IRQ_PEND_IO_ISC_2,
+ IRQ_PEND_IO_ISC_3,
+ IRQ_PEND_IO_ISC_4,
+ IRQ_PEND_IO_ISC_5,
+ IRQ_PEND_IO_ISC_6,
+ IRQ_PEND_IO_ISC_7,
+ IRQ_PEND_SIGP_STOP,
+ IRQ_PEND_RESTART,
+ IRQ_PEND_SET_PREFIX,
+ IRQ_PEND_COUNT
+};
+
+/*
+ * Repressible (non-floating) machine check interrupts
+ * subclass bits in MCIC
+ */
+#define MCHK_EXTD_BIT 58
+#define MCHK_DEGR_BIT 56
+#define MCHK_WARN_BIT 55
+#define MCHK_REP_MASK ((1UL << MCHK_DEGR_BIT) | \
+ (1UL << MCHK_EXTD_BIT) | \
+ (1UL << MCHK_WARN_BIT))
+
+/* Exigent machine check interrupts subclass bits in MCIC */
+#define MCHK_SD_BIT 63
+#define MCHK_PD_BIT 62
+#define MCHK_EX_MASK ((1UL << MCHK_SD_BIT) | (1UL << MCHK_PD_BIT))
+
+#define IRQ_PEND_EXT_MASK ((1UL << IRQ_PEND_EXT_IRQ_KEY) | \
+ (1UL << IRQ_PEND_EXT_CLOCK_COMP) | \
+ (1UL << IRQ_PEND_EXT_CPU_TIMER) | \
+ (1UL << IRQ_PEND_EXT_MALFUNC) | \
+ (1UL << IRQ_PEND_EXT_EMERGENCY) | \
+ (1UL << IRQ_PEND_EXT_EXTERNAL) | \
+ (1UL << IRQ_PEND_EXT_TIMING) | \
+ (1UL << IRQ_PEND_EXT_HOST) | \
+ (1UL << IRQ_PEND_EXT_SERVICE) | \
+ (1UL << IRQ_PEND_VIRTIO) | \
+ (1UL << IRQ_PEND_PFAULT_INIT) | \
+ (1UL << IRQ_PEND_PFAULT_DONE))
+
+#define IRQ_PEND_IO_MASK ((1UL << IRQ_PEND_IO_ISC_0) | \
+ (1UL << IRQ_PEND_IO_ISC_1) | \
+ (1UL << IRQ_PEND_IO_ISC_2) | \
+ (1UL << IRQ_PEND_IO_ISC_3) | \
+ (1UL << IRQ_PEND_IO_ISC_4) | \
+ (1UL << IRQ_PEND_IO_ISC_5) | \
+ (1UL << IRQ_PEND_IO_ISC_6) | \
+ (1UL << IRQ_PEND_IO_ISC_7))
+
+#define IRQ_PEND_MCHK_MASK ((1UL << IRQ_PEND_MCHK_REP) | \
+ (1UL << IRQ_PEND_MCHK_EX))
+
struct kvm_s390_interrupt_info {
struct list_head list;
u64 type;
@@ -313,6 +386,16 @@ struct kvm_s390_interrupt_info {
#define ACTION_STORE_ON_STOP (1<<0)
#define ACTION_STOP_ON_STOP (1<<1)
+struct kvm_s390_irq_payload {
+ struct kvm_s390_io_info io;
+ struct kvm_s390_ext_info ext;
+ struct kvm_s390_pgm_info pgm;
+ struct kvm_s390_emerg_info emerg;
+ struct kvm_s390_extcall_info extcall;
+ struct kvm_s390_prefix_info prefix;
+ struct kvm_s390_mchk_info mchk;
+};
+
struct kvm_s390_local_interrupt {
spinlock_t lock;
struct list_head list;
@@ -321,6 +404,9 @@ struct kvm_s390_local_interrupt {
wait_queue_head_t *wq;
atomic_t *cpuflags;
unsigned int action_bits;
+ DECLARE_BITMAP(sigp_emerg_pending, KVM_MAX_VCPUS);
+ struct kvm_s390_irq_payload irq;
+ unsigned long pending_irqs;
};
struct kvm_s390_float_interrupt {
--
1.9.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [GIT PULL 10/11] KVM: s390: handle pending local interrupts via bitmap
2014-11-28 13:25 [GIT PULL 00/11] KVM: s390: Several changes for 3.19 (kvm/next) Christian Borntraeger
` (8 preceding siblings ...)
2014-11-28 13:25 ` [GIT PULL 09/11] KVM: s390: add bitmap for handling cpu-local interrupts Christian Borntraeger
@ 2014-11-28 13:25 ` Christian Borntraeger
2014-12-01 8:19 ` Heiko Carstens
2014-11-28 13:25 ` [GIT PULL 11/11] KVM: s390: allow injecting all kinds of machine checks Christian Borntraeger
2014-11-28 17:20 ` [GIT PULL 00/11] KVM: s390: Several changes for 3.19 (kvm/next) Paolo Bonzini
11 siblings, 1 reply; 23+ messages in thread
From: Christian Borntraeger @ 2014-11-28 13:25 UTC (permalink / raw)
To: Paolo Bonzini
Cc: KVM, Alexander Graf, Cornelia Huck, Jens Freimann, linux-s390,
Christian Borntraeger
From: Jens Freimann <jfrei@linux.vnet.ibm.com>
This patch adapts handling of local interrupts to be more compliant with
the z/Architecture Principles of Operation and introduces a data
structure
which allows more efficient handling of interrupts.
* get rid of li->active flag, use bitmap instead
* Keep interrupts in a bitmap instead of a list
* Deliver interrupts in the order of their priority as defined in the
PoP
* Use a second bitmap for sigp emergency requests, as a CPU can have
one request pending from every other CPU in the system.
Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com>
Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Reviewed-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
---
arch/s390/include/asm/kvm_host.h | 2 -
arch/s390/kvm/intercept.c | 4 +-
arch/s390/kvm/interrupt.c | 601 +++++++++++++++++++++++----------------
arch/s390/kvm/kvm-s390.c | 14 +-
arch/s390/kvm/kvm-s390.h | 5 +-
arch/s390/kvm/sigp.c | 36 +--
6 files changed, 380 insertions(+), 282 deletions(-)
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index 624a821..9cba74d5 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -398,8 +398,6 @@ struct kvm_s390_irq_payload {
struct kvm_s390_local_interrupt {
spinlock_t lock;
- struct list_head list;
- atomic_t active;
struct kvm_s390_float_interrupt *float_int;
wait_queue_head_t *wq;
atomic_t *cpuflags;
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index 1d244df..81c77ab 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -257,7 +257,7 @@ static int handle_instruction_and_prog(struct kvm_vcpu *vcpu)
static int handle_external_interrupt(struct kvm_vcpu *vcpu)
{
u16 eic = vcpu->arch.sie_block->eic;
- struct kvm_s390_interrupt irq;
+ struct kvm_s390_irq irq;
psw_t newpsw;
int rc;
@@ -282,7 +282,7 @@ static int handle_external_interrupt(struct kvm_vcpu *vcpu)
if (kvm_s390_si_ext_call_pending(vcpu))
return 0;
irq.type = KVM_S390_INT_EXTERNAL_CALL;
- irq.parm = vcpu->arch.sie_block->extcpuaddr;
+ irq.u.extcall.code = vcpu->arch.sie_block->extcpuaddr;
break;
default:
return -EOPNOTSUPP;
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 0d7f0a7..1aa7f28 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -16,6 +16,7 @@
#include <linux/mmu_context.h>
#include <linux/signal.h>
#include <linux/slab.h>
+#include <linux/bitmap.h>
#include <asm/asm-offsets.h>
#include <asm/uaccess.h>
#include "kvm-s390.h"
@@ -136,6 +137,31 @@ static int __must_check __interrupt_is_deliverable(struct kvm_vcpu *vcpu,
return 0;
}
+static inline unsigned long pending_local_irqs(struct kvm_vcpu *vcpu)
+{
+ return vcpu->arch.local_int.pending_irqs;
+}
+
+static unsigned long deliverable_local_irqs(struct kvm_vcpu *vcpu)
+{
+ unsigned long active_mask = pending_local_irqs(vcpu);
+
+ if (psw_extint_disabled(vcpu))
+ active_mask &= ~IRQ_PEND_EXT_MASK;
+ if (!(vcpu->arch.sie_block->gcr[0] & 0x2000ul))
+ __clear_bit(IRQ_PEND_EXT_EXTERNAL, &active_mask);
+ if (!(vcpu->arch.sie_block->gcr[0] & 0x4000ul))
+ __clear_bit(IRQ_PEND_EXT_EMERGENCY, &active_mask);
+ if (!(vcpu->arch.sie_block->gcr[0] & 0x800ul))
+ __clear_bit(IRQ_PEND_EXT_CLOCK_COMP, &active_mask);
+ if (!(vcpu->arch.sie_block->gcr[0] & 0x400ul))
+ __clear_bit(IRQ_PEND_EXT_CPU_TIMER, &active_mask);
+ if (psw_mchk_disabled(vcpu))
+ active_mask &= ~IRQ_PEND_MCHK_MASK;
+
+ return active_mask;
+}
+
static void __set_cpu_idle(struct kvm_vcpu *vcpu)
{
atomic_set_mask(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags);
@@ -170,26 +196,45 @@ static void __set_cpuflag(struct kvm_vcpu *vcpu, u32 flag)
atomic_set_mask(flag, &vcpu->arch.sie_block->cpuflags);
}
+static void set_intercept_indicators_ext(struct kvm_vcpu *vcpu)
+{
+ if (!(pending_local_irqs(vcpu) & IRQ_PEND_EXT_MASK))
+ return;
+ if (psw_extint_disabled(vcpu))
+ __set_cpuflag(vcpu, CPUSTAT_EXT_INT);
+ else
+ vcpu->arch.sie_block->lctl |= LCTL_CR0;
+}
+
+static void set_intercept_indicators_mchk(struct kvm_vcpu *vcpu)
+{
+ if (!(pending_local_irqs(vcpu) & IRQ_PEND_MCHK_MASK))
+ return;
+ if (psw_mchk_disabled(vcpu))
+ vcpu->arch.sie_block->ictl |= ICTL_LPSW;
+ else
+ vcpu->arch.sie_block->lctl |= LCTL_CR14;
+}
+
+/* Set interception request for non-deliverable local interrupts */
+static void set_intercept_indicators_local(struct kvm_vcpu *vcpu)
+{
+ set_intercept_indicators_ext(vcpu);
+ set_intercept_indicators_mchk(vcpu);
+}
+
static void __set_intercept_indicator(struct kvm_vcpu *vcpu,
struct kvm_s390_interrupt_info *inti)
{
switch (inti->type) {
- case KVM_S390_INT_EXTERNAL_CALL:
- case KVM_S390_INT_EMERGENCY:
case KVM_S390_INT_SERVICE:
- case KVM_S390_INT_PFAULT_INIT:
case KVM_S390_INT_PFAULT_DONE:
case KVM_S390_INT_VIRTIO:
- case KVM_S390_INT_CLOCK_COMP:
- case KVM_S390_INT_CPU_TIMER:
if (psw_extint_disabled(vcpu))
__set_cpuflag(vcpu, CPUSTAT_EXT_INT);
else
vcpu->arch.sie_block->lctl |= LCTL_CR0;
break;
- case KVM_S390_SIGP_STOP:
- __set_cpuflag(vcpu, CPUSTAT_STOP_INT);
- break;
case KVM_S390_MCHK:
if (psw_mchk_disabled(vcpu))
vcpu->arch.sie_block->ictl |= ICTL_LPSW;
@@ -228,6 +273,7 @@ static u16 get_ilc(struct kvm_vcpu *vcpu)
static int __must_check __deliver_cpu_timer(struct kvm_vcpu *vcpu)
{
+ struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
int rc;
trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_INT_CPU_TIMER,
@@ -239,11 +285,13 @@ static int __must_check __deliver_cpu_timer(struct kvm_vcpu *vcpu)
&vcpu->arch.sie_block->gpsw, sizeof(psw_t));
rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW,
&vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ clear_bit(IRQ_PEND_EXT_CPU_TIMER, &li->pending_irqs);
return rc;
}
static int __must_check __deliver_ckc(struct kvm_vcpu *vcpu)
{
+ struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
int rc;
trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_INT_CLOCK_COMP,
@@ -255,20 +303,27 @@ static int __must_check __deliver_ckc(struct kvm_vcpu *vcpu)
&vcpu->arch.sie_block->gpsw, sizeof(psw_t));
rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW,
&vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ clear_bit(IRQ_PEND_EXT_CLOCK_COMP, &li->pending_irqs);
return rc;
}
-static int __must_check __deliver_pfault_init(struct kvm_vcpu *vcpu,
- struct kvm_s390_interrupt_info *inti)
+static int __must_check __deliver_pfault_init(struct kvm_vcpu *vcpu)
{
- struct kvm_s390_ext_info *ext = &inti->ext;
+ struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
+ struct kvm_s390_ext_info ext;
int rc;
+ spin_lock(&li->lock);
+ ext = li->irq.ext;
+ clear_bit(IRQ_PEND_PFAULT_INIT, &li->pending_irqs);
+ li->irq.ext.ext_params2 = 0;
+ spin_unlock(&li->lock);
+
VCPU_EVENT(vcpu, 4, "interrupt: pfault init parm:%x,parm64:%llx",
- 0, ext->ext_params2);
+ 0, ext.ext_params2);
trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id,
KVM_S390_INT_PFAULT_INIT,
- 0, ext->ext_params2);
+ 0, ext.ext_params2);
rc = put_guest_lc(vcpu, EXT_IRQ_CP_SERVICE, (u16 *) __LC_EXT_INT_CODE);
rc |= put_guest_lc(vcpu, PFAULT_INIT, (u16 *) __LC_EXT_CPU_ADDR);
@@ -276,28 +331,40 @@ static int __must_check __deliver_pfault_init(struct kvm_vcpu *vcpu,
&vcpu->arch.sie_block->gpsw, sizeof(psw_t));
rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW,
&vcpu->arch.sie_block->gpsw, sizeof(psw_t));
- rc |= put_guest_lc(vcpu, ext->ext_params2, (u64 *) __LC_EXT_PARAMS2);
+ rc |= put_guest_lc(vcpu, ext.ext_params2, (u64 *) __LC_EXT_PARAMS2);
return rc;
}
-static int __must_check __deliver_machine_check(struct kvm_vcpu *vcpu,
- struct kvm_s390_interrupt_info *inti)
+static int __must_check __deliver_machine_check(struct kvm_vcpu *vcpu)
{
- struct kvm_s390_mchk_info *mchk = &inti->mchk;
+ struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
+ struct kvm_s390_mchk_info mchk;
int rc;
+ spin_lock(&li->lock);
+ mchk = li->irq.mchk;
+ /*
+ * If there was an exigent machine check pending, then any repressible
+ * machine checks that might have been pending are indicated along
+ * with it, so always clear both bits
+ */
+ clear_bit(IRQ_PEND_MCHK_EX, &li->pending_irqs);
+ clear_bit(IRQ_PEND_MCHK_REP, &li->pending_irqs);
+ memset(&li->irq.mchk, 0, sizeof(mchk));
+ spin_unlock(&li->lock);
+
VCPU_EVENT(vcpu, 4, "interrupt: machine check mcic=%llx",
- mchk->mcic);
+ mchk.mcic);
trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_MCHK,
- mchk->cr14, mchk->mcic);
+ mchk.cr14, mchk.mcic);
rc = kvm_s390_vcpu_store_status(vcpu, KVM_S390_STORE_STATUS_PREFIXED);
- rc |= put_guest_lc(vcpu, mchk->mcic,
+ rc |= put_guest_lc(vcpu, mchk.mcic,
(u64 __user *) __LC_MCCK_CODE);
- rc |= put_guest_lc(vcpu, mchk->failing_storage_address,
+ rc |= put_guest_lc(vcpu, mchk.failing_storage_address,
(u64 __user *) __LC_MCCK_FAIL_STOR_ADDR);
rc |= write_guest_lc(vcpu, __LC_PSW_SAVE_AREA,
- &mchk->fixed_logout, sizeof(mchk->fixed_logout));
+ &mchk.fixed_logout, sizeof(mchk.fixed_logout));
rc |= write_guest_lc(vcpu, __LC_MCK_OLD_PSW,
&vcpu->arch.sie_block->gpsw, sizeof(psw_t));
rc |= read_guest_lc(vcpu, __LC_MCK_NEW_PSW,
@@ -307,6 +374,7 @@ static int __must_check __deliver_machine_check(struct kvm_vcpu *vcpu,
static int __must_check __deliver_restart(struct kvm_vcpu *vcpu)
{
+ struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
int rc;
VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu restart");
@@ -318,6 +386,7 @@ static int __must_check __deliver_restart(struct kvm_vcpu *vcpu)
&vcpu->arch.sie_block->gpsw, sizeof(psw_t));
rc |= read_guest_lc(vcpu, offsetof(struct _lowcore, restart_psw),
&vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ clear_bit(IRQ_PEND_RESTART, &li->pending_irqs);
return rc;
}
@@ -329,38 +398,52 @@ static int __must_check __deliver_stop(struct kvm_vcpu *vcpu)
0, 0);
__set_cpuflag(vcpu, CPUSTAT_STOP_INT);
+ clear_bit(IRQ_PEND_SIGP_STOP, &vcpu->arch.local_int.pending_irqs);
return 0;
}
-static int __must_check __deliver_set_prefix(struct kvm_vcpu *vcpu,
- struct kvm_s390_interrupt_info *inti)
+static int __must_check __deliver_set_prefix(struct kvm_vcpu *vcpu)
{
- struct kvm_s390_prefix_info *prefix = &inti->prefix;
+ struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
+ struct kvm_s390_prefix_info prefix;
+
+ spin_lock(&li->lock);
+ prefix = li->irq.prefix;
+ li->irq.prefix.address = 0;
+ clear_bit(IRQ_PEND_SET_PREFIX, &li->pending_irqs);
+ spin_unlock(&li->lock);
- VCPU_EVENT(vcpu, 4, "interrupt: set prefix to %x", prefix->address);
+ VCPU_EVENT(vcpu, 4, "interrupt: set prefix to %x", prefix.address);
vcpu->stat.deliver_prefix_signal++;
trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id,
KVM_S390_SIGP_SET_PREFIX,
- prefix->address, 0);
+ prefix.address, 0);
- kvm_s390_set_prefix(vcpu, prefix->address);
+ kvm_s390_set_prefix(vcpu, prefix.address);
return 0;
}
-static int __must_check __deliver_emergency_signal(struct kvm_vcpu *vcpu,
- struct kvm_s390_interrupt_info *inti)
+static int __must_check __deliver_emergency_signal(struct kvm_vcpu *vcpu)
{
- struct kvm_s390_emerg_info *emerg = &inti->emerg;
+ struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
int rc;
+ int cpu_addr;
+
+ spin_lock(&li->lock);
+ cpu_addr = find_first_bit(li->sigp_emerg_pending, KVM_MAX_VCPUS);
+ clear_bit(cpu_addr, li->sigp_emerg_pending);
+ if (bitmap_empty(li->sigp_emerg_pending, KVM_MAX_VCPUS))
+ clear_bit(IRQ_PEND_EXT_EMERGENCY, &li->pending_irqs);
+ spin_unlock(&li->lock);
VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp emerg");
vcpu->stat.deliver_emergency_signal++;
- trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
- inti->emerg.code, 0);
+ trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_INT_EMERGENCY,
+ cpu_addr, 0);
rc = put_guest_lc(vcpu, EXT_IRQ_EMERGENCY_SIG,
(u16 *)__LC_EXT_INT_CODE);
- rc |= put_guest_lc(vcpu, emerg->code, (u16 *)__LC_EXT_CPU_ADDR);
+ rc |= put_guest_lc(vcpu, cpu_addr, (u16 *)__LC_EXT_CPU_ADDR);
rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW,
&vcpu->arch.sie_block->gpsw, sizeof(psw_t));
rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW,
@@ -368,21 +451,27 @@ static int __must_check __deliver_emergency_signal(struct kvm_vcpu *vcpu,
return rc;
}
-static int __must_check __deliver_external_call(struct kvm_vcpu *vcpu,
- struct kvm_s390_interrupt_info *inti)
+static int __must_check __deliver_external_call(struct kvm_vcpu *vcpu)
{
- struct kvm_s390_extcall_info *extcall = &inti->extcall;
+ struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
+ struct kvm_s390_extcall_info extcall;
int rc;
+ spin_lock(&li->lock);
+ extcall = li->irq.extcall;
+ li->irq.extcall.code = 0;
+ clear_bit(IRQ_PEND_EXT_EXTERNAL, &li->pending_irqs);
+ spin_unlock(&li->lock);
+
VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp ext call");
vcpu->stat.deliver_external_call++;
trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id,
KVM_S390_INT_EXTERNAL_CALL,
- extcall->code, 0);
+ extcall.code, 0);
rc = put_guest_lc(vcpu, EXT_IRQ_EXTERNAL_CALL,
(u16 *)__LC_EXT_INT_CODE);
- rc |= put_guest_lc(vcpu, extcall->code, (u16 *)__LC_EXT_CPU_ADDR);
+ rc |= put_guest_lc(vcpu, extcall.code, (u16 *)__LC_EXT_CPU_ADDR);
rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW,
&vcpu->arch.sie_block->gpsw, sizeof(psw_t));
rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW, &vcpu->arch.sie_block->gpsw,
@@ -390,20 +479,26 @@ static int __must_check __deliver_external_call(struct kvm_vcpu *vcpu,
return rc;
}
-static int __must_check __deliver_prog(struct kvm_vcpu *vcpu,
- struct kvm_s390_interrupt_info *inti)
+static int __must_check __deliver_prog(struct kvm_vcpu *vcpu)
{
- struct kvm_s390_pgm_info *pgm_info = &inti->pgm;
+ struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
+ struct kvm_s390_pgm_info pgm_info;
int rc = 0;
u16 ilc = get_ilc(vcpu);
+ spin_lock(&li->lock);
+ pgm_info = li->irq.pgm;
+ clear_bit(IRQ_PEND_PROG, &li->pending_irqs);
+ memset(&li->irq.pgm, 0, sizeof(pgm_info));
+ spin_unlock(&li->lock);
+
VCPU_EVENT(vcpu, 4, "interrupt: pgm check code:%x, ilc:%x",
- pgm_info->code, ilc);
+ pgm_info.code, ilc);
vcpu->stat.deliver_program_int++;
trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_PROGRAM_INT,
- pgm_info->code, 0);
+ pgm_info.code, 0);
- switch (pgm_info->code & ~PGM_PER) {
+ switch (pgm_info.code & ~PGM_PER) {
case PGM_AFX_TRANSLATION:
case PGM_ASX_TRANSLATION:
case PGM_EX_TRANSLATION:
@@ -414,7 +509,7 @@ static int __must_check __deliver_prog(struct kvm_vcpu *vcpu,
case PGM_PRIMARY_AUTHORITY:
case PGM_SECONDARY_AUTHORITY:
case PGM_SPACE_SWITCH:
- rc = put_guest_lc(vcpu, pgm_info->trans_exc_code,
+ rc = put_guest_lc(vcpu, pgm_info.trans_exc_code,
(u64 *)__LC_TRANS_EXC_CODE);
break;
case PGM_ALEN_TRANSLATION:
@@ -423,7 +518,7 @@ static int __must_check __deliver_prog(struct kvm_vcpu *vcpu,
case PGM_ASTE_SEQUENCE:
case PGM_ASTE_VALIDITY:
case PGM_EXTENDED_AUTHORITY:
- rc = put_guest_lc(vcpu, pgm_info->exc_access_id,
+ rc = put_guest_lc(vcpu, pgm_info.exc_access_id,
(u8 *)__LC_EXC_ACCESS_ID);
break;
case PGM_ASCE_TYPE:
@@ -432,44 +527,44 @@ static int __must_check __deliver_prog(struct kvm_vcpu *vcpu,
case PGM_REGION_SECOND_TRANS:
case PGM_REGION_THIRD_TRANS:
case PGM_SEGMENT_TRANSLATION:
- rc = put_guest_lc(vcpu, pgm_info->trans_exc_code,
+ rc = put_guest_lc(vcpu, pgm_info.trans_exc_code,
(u64 *)__LC_TRANS_EXC_CODE);
- rc |= put_guest_lc(vcpu, pgm_info->exc_access_id,
+ rc |= put_guest_lc(vcpu, pgm_info.exc_access_id,
(u8 *)__LC_EXC_ACCESS_ID);
- rc |= put_guest_lc(vcpu, pgm_info->op_access_id,
+ rc |= put_guest_lc(vcpu, pgm_info.op_access_id,
(u8 *)__LC_OP_ACCESS_ID);
break;
case PGM_MONITOR:
- rc = put_guest_lc(vcpu, pgm_info->mon_class_nr,
+ rc = put_guest_lc(vcpu, pgm_info.mon_class_nr,
(u16 *)__LC_MON_CLASS_NR);
- rc |= put_guest_lc(vcpu, pgm_info->mon_code,
+ rc |= put_guest_lc(vcpu, pgm_info.mon_code,
(u64 *)__LC_MON_CODE);
break;
case PGM_DATA:
- rc = put_guest_lc(vcpu, pgm_info->data_exc_code,
+ rc = put_guest_lc(vcpu, pgm_info.data_exc_code,
(u32 *)__LC_DATA_EXC_CODE);
break;
case PGM_PROTECTION:
- rc = put_guest_lc(vcpu, pgm_info->trans_exc_code,
+ rc = put_guest_lc(vcpu, pgm_info.trans_exc_code,
(u64 *)__LC_TRANS_EXC_CODE);
- rc |= put_guest_lc(vcpu, pgm_info->exc_access_id,
+ rc |= put_guest_lc(vcpu, pgm_info.exc_access_id,
(u8 *)__LC_EXC_ACCESS_ID);
break;
}
- if (pgm_info->code & PGM_PER) {
- rc |= put_guest_lc(vcpu, pgm_info->per_code,
+ if (pgm_info.code & PGM_PER) {
+ rc |= put_guest_lc(vcpu, pgm_info.per_code,
(u8 *) __LC_PER_CODE);
- rc |= put_guest_lc(vcpu, pgm_info->per_atmid,
+ rc |= put_guest_lc(vcpu, pgm_info.per_atmid,
(u8 *)__LC_PER_ATMID);
- rc |= put_guest_lc(vcpu, pgm_info->per_address,
+ rc |= put_guest_lc(vcpu, pgm_info.per_address,
(u64 *) __LC_PER_ADDRESS);
- rc |= put_guest_lc(vcpu, pgm_info->per_access_id,
+ rc |= put_guest_lc(vcpu, pgm_info.per_access_id,
(u8 *) __LC_PER_ACCESS_ID);
}
rc |= put_guest_lc(vcpu, ilc, (u16 *) __LC_PGM_ILC);
- rc |= put_guest_lc(vcpu, pgm_info->code,
+ rc |= put_guest_lc(vcpu, pgm_info.code,
(u16 *)__LC_PGM_INT_CODE);
rc |= write_guest_lc(vcpu, __LC_PGM_OLD_PSW,
&vcpu->arch.sie_block->gpsw, sizeof(psw_t));
@@ -572,50 +667,63 @@ static int __must_check __deliver_io(struct kvm_vcpu *vcpu,
return rc;
}
-static int __must_check __do_deliver_interrupt(struct kvm_vcpu *vcpu,
- struct kvm_s390_interrupt_info *inti)
+static int __must_check __deliver_mchk_floating(struct kvm_vcpu *vcpu,
+ struct kvm_s390_interrupt_info *inti)
+{
+ struct kvm_s390_mchk_info *mchk = &inti->mchk;
+ int rc;
+
+ VCPU_EVENT(vcpu, 4, "interrupt: machine check mcic=%llx",
+ mchk->mcic);
+ trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_MCHK,
+ mchk->cr14, mchk->mcic);
+
+ rc = kvm_s390_vcpu_store_status(vcpu, KVM_S390_STORE_STATUS_PREFIXED);
+ rc |= put_guest_lc(vcpu, mchk->mcic,
+ (u64 __user *) __LC_MCCK_CODE);
+ rc |= put_guest_lc(vcpu, mchk->failing_storage_address,
+ (u64 __user *) __LC_MCCK_FAIL_STOR_ADDR);
+ rc |= write_guest_lc(vcpu, __LC_PSW_SAVE_AREA,
+ &mchk->fixed_logout, sizeof(mchk->fixed_logout));
+ rc |= write_guest_lc(vcpu, __LC_MCK_OLD_PSW,
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ rc |= read_guest_lc(vcpu, __LC_MCK_NEW_PSW,
+ &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+ return rc;
+}
+
+typedef int (*deliver_irq_t)(struct kvm_vcpu *vcpu);
+
+static const deliver_irq_t deliver_irq_funcs[] = {
+ [IRQ_PEND_MCHK_EX] = __deliver_machine_check,
+ [IRQ_PEND_PROG] = __deliver_prog,
+ [IRQ_PEND_EXT_EMERGENCY] = __deliver_emergency_signal,
+ [IRQ_PEND_EXT_EXTERNAL] = __deliver_external_call,
+ [IRQ_PEND_EXT_CLOCK_COMP] = __deliver_ckc,
+ [IRQ_PEND_EXT_CPU_TIMER] = __deliver_cpu_timer,
+ [IRQ_PEND_RESTART] = __deliver_restart,
+ [IRQ_PEND_SIGP_STOP] = __deliver_stop,
+ [IRQ_PEND_SET_PREFIX] = __deliver_set_prefix,
+ [IRQ_PEND_PFAULT_INIT] = __deliver_pfault_init,
+};
+
+static int __must_check __deliver_floating_interrupt(struct kvm_vcpu *vcpu,
+ struct kvm_s390_interrupt_info *inti)
{
int rc;
switch (inti->type) {
- case KVM_S390_INT_EMERGENCY:
- rc = __deliver_emergency_signal(vcpu, inti);
- break;
- case KVM_S390_INT_EXTERNAL_CALL:
- rc = __deliver_external_call(vcpu, inti);
- break;
- case KVM_S390_INT_CLOCK_COMP:
- rc = __deliver_ckc(vcpu);
- break;
- case KVM_S390_INT_CPU_TIMER:
- rc = __deliver_cpu_timer(vcpu);
- break;
case KVM_S390_INT_SERVICE:
rc = __deliver_service(vcpu, inti);
break;
- case KVM_S390_INT_PFAULT_INIT:
- rc = __deliver_pfault_init(vcpu, inti);
- break;
case KVM_S390_INT_PFAULT_DONE:
rc = __deliver_pfault_done(vcpu, inti);
break;
case KVM_S390_INT_VIRTIO:
rc = __deliver_virtio(vcpu, inti);
break;
- case KVM_S390_SIGP_STOP:
- rc = __deliver_stop(vcpu);
- break;
- case KVM_S390_SIGP_SET_PREFIX:
- rc = __deliver_set_prefix(vcpu, inti);
- break;
- case KVM_S390_RESTART:
- rc = __deliver_restart(vcpu);
- break;
- case KVM_S390_PROGRAM_INT:
- rc = __deliver_prog(vcpu, inti);
- break;
case KVM_S390_MCHK:
- rc = __deliver_machine_check(vcpu, inti);
+ rc = __deliver_mchk_floating(vcpu, inti);
break;
case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
rc = __deliver_io(vcpu, inti);
@@ -643,20 +751,11 @@ int kvm_s390_si_ext_call_pending(struct kvm_vcpu *vcpu)
int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu)
{
- struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
struct kvm_s390_float_interrupt *fi = vcpu->arch.local_int.float_int;
struct kvm_s390_interrupt_info *inti;
- int rc = 0;
+ int rc;
- if (atomic_read(&li->active)) {
- spin_lock(&li->lock);
- list_for_each_entry(inti, &li->list, list)
- if (__interrupt_is_deliverable(vcpu, inti)) {
- rc = 1;
- break;
- }
- spin_unlock(&li->lock);
- }
+ rc = !!deliverable_local_irqs(vcpu);
if ((!rc) && atomic_read(&fi->active)) {
spin_lock(&fi->lock);
@@ -748,18 +847,15 @@ enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer)
void kvm_s390_clear_local_irqs(struct kvm_vcpu *vcpu)
{
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
- struct kvm_s390_interrupt_info *n, *inti = NULL;
spin_lock(&li->lock);
- list_for_each_entry_safe(inti, n, &li->list, list) {
- list_del(&inti->list);
- kfree(inti);
- }
- atomic_set(&li->active, 0);
+ li->pending_irqs = 0;
+ bitmap_zero(li->sigp_emerg_pending, KVM_MAX_VCPUS);
+ memset(&li->irq, 0, sizeof(li->irq));
spin_unlock(&li->lock);
/* clear pending external calls set by sigp interpretation facility */
- atomic_clear_mask(CPUSTAT_ECALL_PEND, &vcpu->arch.sie_block->cpuflags);
+ atomic_clear_mask(CPUSTAT_ECALL_PEND, li->cpuflags);
atomic_clear_mask(SIGP_CTRL_C,
&vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].ctrl);
}
@@ -769,34 +865,35 @@ int __must_check kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
struct kvm_s390_float_interrupt *fi = vcpu->arch.local_int.float_int;
struct kvm_s390_interrupt_info *n, *inti = NULL;
+ deliver_irq_t func;
int deliver;
int rc = 0;
+ unsigned long irq_type;
+ unsigned long deliverable_irqs;
__reset_intercept_indicators(vcpu);
- if (atomic_read(&li->active)) {
- do {
- deliver = 0;
- spin_lock(&li->lock);
- list_for_each_entry_safe(inti, n, &li->list, list) {
- if (__interrupt_is_deliverable(vcpu, inti)) {
- list_del(&inti->list);
- deliver = 1;
- break;
- }
- __set_intercept_indicator(vcpu, inti);
- }
- if (list_empty(&li->list))
- atomic_set(&li->active, 0);
- spin_unlock(&li->lock);
- if (deliver) {
- rc = __do_deliver_interrupt(vcpu, inti);
- kfree(inti);
- }
- } while (!rc && deliver);
- }
- if (!rc && kvm_cpu_has_pending_timer(vcpu))
- rc = __deliver_ckc(vcpu);
+ /* pending ckc conditions might have been invalidated */
+ clear_bit(IRQ_PEND_EXT_CLOCK_COMP, &li->pending_irqs);
+ if (kvm_cpu_has_pending_timer(vcpu))
+ set_bit(IRQ_PEND_EXT_CLOCK_COMP, &li->pending_irqs);
+
+ do {
+ deliverable_irqs = deliverable_local_irqs(vcpu);
+ /* bits are in the order of interrupt priority */
+ irq_type = find_first_bit(&deliverable_irqs, IRQ_PEND_COUNT);
+ if (irq_type == IRQ_PEND_COUNT)
+ break;
+ func = deliver_irq_funcs[irq_type];
+ if (!func) {
+ WARN_ON_ONCE(func == NULL);
+ clear_bit(irq_type, &li->pending_irqs);
+ continue;
+ }
+ rc = func(vcpu);
+ } while (!rc && irq_type != IRQ_PEND_COUNT);
+
+ set_intercept_indicators_local(vcpu);
if (!rc && atomic_read(&fi->active)) {
do {
@@ -815,7 +912,7 @@ int __must_check kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
atomic_set(&fi->active, 0);
spin_unlock(&fi->lock);
if (deliver) {
- rc = __do_deliver_interrupt(vcpu, inti);
+ rc = __deliver_floating_interrupt(vcpu, inti);
kfree(inti);
}
} while (!rc && deliver);
@@ -824,33 +921,26 @@ int __must_check kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
return rc;
}
-static int __inject_prog_irq(struct kvm_vcpu *vcpu,
- struct kvm_s390_interrupt_info *inti)
+static int __inject_prog(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
{
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
- list_add(&inti->list, &li->list);
- atomic_set(&li->active, 1);
+ li->irq.pgm = irq->u.pgm;
+ __set_bit(IRQ_PEND_PROG, &li->pending_irqs);
return 0;
}
int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code)
{
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
- struct kvm_s390_interrupt_info *inti;
-
- inti = kzalloc(sizeof(*inti), GFP_KERNEL);
- if (!inti)
- return -ENOMEM;
-
- inti->type = KVM_S390_PROGRAM_INT;
- inti->pgm.code = code;
+ struct kvm_s390_irq irq;
VCPU_EVENT(vcpu, 3, "inject: program check %d (from kernel)", code);
- trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, inti->type, code, 0, 1);
+ trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_PROGRAM_INT, code,
+ 0, 1);
spin_lock(&li->lock);
- list_add(&inti->list, &li->list);
- atomic_set(&li->active, 1);
+ irq.u.pgm.code = code;
+ __inject_prog(vcpu, &irq);
BUG_ON(waitqueue_active(li->wq));
spin_unlock(&li->lock);
return 0;
@@ -860,151 +950,158 @@ int kvm_s390_inject_prog_irq(struct kvm_vcpu *vcpu,
struct kvm_s390_pgm_info *pgm_info)
{
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
- struct kvm_s390_interrupt_info *inti;
+ struct kvm_s390_irq irq;
int rc;
- inti = kzalloc(sizeof(*inti), GFP_KERNEL);
- if (!inti)
- return -ENOMEM;
-
VCPU_EVENT(vcpu, 3, "inject: prog irq %d (from kernel)",
pgm_info->code);
trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_PROGRAM_INT,
pgm_info->code, 0, 1);
-
- inti->type = KVM_S390_PROGRAM_INT;
- memcpy(&inti->pgm, pgm_info, sizeof(inti->pgm));
spin_lock(&li->lock);
- rc = __inject_prog_irq(vcpu, inti);
+ irq.u.pgm = *pgm_info;
+ rc = __inject_prog(vcpu, &irq);
BUG_ON(waitqueue_active(li->wq));
spin_unlock(&li->lock);
return rc;
}
-static int __inject_pfault_init(struct kvm_vcpu *vcpu,
- struct kvm_s390_interrupt *s390int,
- struct kvm_s390_interrupt_info *inti)
+static int __inject_pfault_init(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
{
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
- inti->ext.ext_params2 = s390int->parm64;
- list_add_tail(&inti->list, &li->list);
- atomic_set(&li->active, 1);
+ VCPU_EVENT(vcpu, 3, "inject: external irq params:%x, params2:%llx",
+ irq->u.ext.ext_params, irq->u.ext.ext_params2);
+ trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_INT_PFAULT_INIT,
+ irq->u.ext.ext_params,
+ irq->u.ext.ext_params2, 2);
+
+ li->irq.ext = irq->u.ext;
+ set_bit(IRQ_PEND_PFAULT_INIT, &li->pending_irqs);
atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
return 0;
}
-static int __inject_extcall(struct kvm_vcpu *vcpu,
- struct kvm_s390_interrupt *s390int,
- struct kvm_s390_interrupt_info *inti)
+int __inject_extcall(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
{
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
+ struct kvm_s390_extcall_info *extcall = &li->irq.extcall;
VCPU_EVENT(vcpu, 3, "inject: external call source-cpu:%u",
- s390int->parm);
- if (s390int->parm & 0xffff0000)
- return -EINVAL;
- inti->extcall.code = s390int->parm;
- list_add_tail(&inti->list, &li->list);
- atomic_set(&li->active, 1);
+ irq->u.extcall.code);
+ trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_INT_EXTERNAL_CALL,
+ irq->u.extcall.code, 0, 2);
+
+ *extcall = irq->u.extcall;
+ __set_bit(IRQ_PEND_EXT_EXTERNAL, &li->pending_irqs);
atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
return 0;
}
-static int __inject_set_prefix(struct kvm_vcpu *vcpu,
- struct kvm_s390_interrupt *s390int,
- struct kvm_s390_interrupt_info *inti)
+static int __inject_set_prefix(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
{
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
+ struct kvm_s390_prefix_info *prefix = &li->irq.prefix;
VCPU_EVENT(vcpu, 3, "inject: set prefix to %x (from user)",
- s390int->parm);
- inti->prefix.address = s390int->parm;
- list_add_tail(&inti->list, &li->list);
- atomic_set(&li->active, 1);
+ prefix->address);
+ trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_SIGP_SET_PREFIX,
+ prefix->address, 0, 2);
+
+ *prefix = irq->u.prefix;
+ set_bit(IRQ_PEND_SET_PREFIX, &li->pending_irqs);
return 0;
}
-static int __inject_sigp_stop(struct kvm_vcpu *vcpu,
- struct kvm_s390_interrupt *s390int,
- struct kvm_s390_interrupt_info *inti)
+static int __inject_sigp_stop(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
{
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
- list_add_tail(&inti->list, &li->list);
- atomic_set(&li->active, 1);
+ trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_SIGP_STOP, 0, 0, 2);
+
li->action_bits |= ACTION_STOP_ON_STOP;
+ set_bit(IRQ_PEND_SIGP_STOP, &li->pending_irqs);
return 0;
}
static int __inject_sigp_restart(struct kvm_vcpu *vcpu,
- struct kvm_s390_interrupt *s390int,
- struct kvm_s390_interrupt_info *inti)
+ struct kvm_s390_irq *irq)
{
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
- VCPU_EVENT(vcpu, 3, "inject: type %x", s390int->type);
- list_add_tail(&inti->list, &li->list);
- atomic_set(&li->active, 1);
+ VCPU_EVENT(vcpu, 3, "inject: restart type %llx", irq->type);
+ trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_RESTART, 0, 0, 2);
+
+ set_bit(IRQ_PEND_RESTART, &li->pending_irqs);
return 0;
}
static int __inject_sigp_emergency(struct kvm_vcpu *vcpu,
- struct kvm_s390_interrupt *s390int,
- struct kvm_s390_interrupt_info *inti)
+ struct kvm_s390_irq *irq)
{
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
+ struct kvm_s390_emerg_info *emerg = &li->irq.emerg;
- VCPU_EVENT(vcpu, 3, "inject: emergency %u\n", s390int->parm);
- if (s390int->parm & 0xffff0000)
- return -EINVAL;
- inti->emerg.code = s390int->parm;
- list_add_tail(&inti->list, &li->list);
- atomic_set(&li->active, 1);
+ VCPU_EVENT(vcpu, 3, "inject: emergency %u\n",
+ irq->u.emerg.code);
+ trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_INT_EMERGENCY,
+ emerg->code, 0, 2);
+
+ set_bit(emerg->code, li->sigp_emerg_pending);
+ set_bit(IRQ_PEND_EXT_EMERGENCY, &li->pending_irqs);
atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
return 0;
}
-static int __inject_mchk(struct kvm_vcpu *vcpu,
- struct kvm_s390_interrupt *s390int,
- struct kvm_s390_interrupt_info *inti)
+static int __inject_mchk(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
{
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
+ struct kvm_s390_mchk_info *mchk = &li->irq.mchk;
VCPU_EVENT(vcpu, 5, "inject: machine check parm64:%llx",
- s390int->parm64);
- inti->mchk.mcic = s390int->parm64;
- list_add_tail(&inti->list, &li->list);
- atomic_set(&li->active, 1);
+ mchk->mcic);
+ trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_MCHK, 0,
+ mchk->mcic, 2);
+
+ /*
+ * Combine mcic with previously injected machine checks and
+ * indicate them all together as described in the Principles
+ * of Operation, Chapter 11, Interruption action
+ */
+ mchk->mcic |= irq->u.mchk.mcic;
+ if (mchk->mcic & MCHK_EX_MASK)
+ set_bit(IRQ_PEND_MCHK_EX, &li->pending_irqs);
+ else if (mchk->mcic & MCHK_REP_MASK)
+ set_bit(IRQ_PEND_MCHK_REP, &li->pending_irqs);
return 0;
}
-static int __inject_ckc(struct kvm_vcpu *vcpu,
- struct kvm_s390_interrupt *s390int,
- struct kvm_s390_interrupt_info *inti)
+static int __inject_ckc(struct kvm_vcpu *vcpu)
{
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
- VCPU_EVENT(vcpu, 3, "inject: type %x", s390int->type);
- list_add_tail(&inti->list, &li->list);
- atomic_set(&li->active, 1);
+ VCPU_EVENT(vcpu, 3, "inject: type %x", KVM_S390_INT_CLOCK_COMP);
+ trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_INT_CLOCK_COMP,
+ 0, 0, 2);
+
+ set_bit(IRQ_PEND_EXT_CLOCK_COMP, &li->pending_irqs);
atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
return 0;
}
-static int __inject_cpu_timer(struct kvm_vcpu *vcpu,
- struct kvm_s390_interrupt *s390int,
- struct kvm_s390_interrupt_info *inti)
+static int __inject_cpu_timer(struct kvm_vcpu *vcpu)
{
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
- VCPU_EVENT(vcpu, 3, "inject: type %x", s390int->type);
- list_add_tail(&inti->list, &li->list);
- atomic_set(&li->active, 1);
+ VCPU_EVENT(vcpu, 3, "inject: type %x", KVM_S390_INT_CPU_TIMER);
+ trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_INT_CPU_TIMER,
+ 0, 0, 2);
+
+ set_bit(IRQ_PEND_EXT_CPU_TIMER, &li->pending_irqs);
atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
return 0;
}
+
struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm,
u64 cr6, u64 schid)
{
@@ -1169,58 +1266,74 @@ void kvm_s390_reinject_io_int(struct kvm *kvm,
__inject_vm(kvm, inti);
}
-int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
- struct kvm_s390_interrupt *s390int)
+int s390int_to_s390irq(struct kvm_s390_interrupt *s390int,
+ struct kvm_s390_irq *irq)
+{
+ irq->type = s390int->type;
+ switch (irq->type) {
+ case KVM_S390_PROGRAM_INT:
+ if (s390int->parm & 0xffff0000)
+ return -EINVAL;
+ irq->u.pgm.code = s390int->parm;
+ break;
+ case KVM_S390_SIGP_SET_PREFIX:
+ irq->u.prefix.address = s390int->parm;
+ break;
+ case KVM_S390_INT_EXTERNAL_CALL:
+ if (irq->u.extcall.code & 0xffff0000)
+ return -EINVAL;
+ irq->u.extcall.code = s390int->parm;
+ break;
+ case KVM_S390_INT_EMERGENCY:
+ if (irq->u.emerg.code & 0xffff0000)
+ return -EINVAL;
+ irq->u.emerg.code = s390int->parm;
+ break;
+ case KVM_S390_MCHK:
+ irq->u.mchk.mcic = s390int->parm64;
+ break;
+ }
+ return 0;
+}
+
+int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
{
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
- struct kvm_s390_interrupt_info *inti;
int rc;
- inti = kzalloc(sizeof(*inti), GFP_KERNEL);
- if (!inti)
- return -ENOMEM;
-
- inti->type = s390int->type;
-
- trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, s390int->type,
- s390int->parm, 0, 2);
spin_lock(&li->lock);
- switch (inti->type) {
+ switch (irq->type) {
case KVM_S390_PROGRAM_INT:
VCPU_EVENT(vcpu, 3, "inject: program check %d (from user)",
- s390int->parm);
- inti->pgm.code = s390int->parm;
- if (s390int->parm & 0xffff0000)
- rc = -EINVAL;
- else
- rc = __inject_prog_irq(vcpu, inti);
+ irq->u.pgm.code);
+ rc = __inject_prog(vcpu, irq);
break;
case KVM_S390_SIGP_SET_PREFIX:
- rc = __inject_set_prefix(vcpu, s390int, inti);
+ rc = __inject_set_prefix(vcpu, irq);
break;
case KVM_S390_SIGP_STOP:
- rc = __inject_sigp_stop(vcpu, s390int, inti);
+ rc = __inject_sigp_stop(vcpu, irq);
break;
case KVM_S390_RESTART:
- rc = __inject_sigp_restart(vcpu, s390int, inti);
+ rc = __inject_sigp_restart(vcpu, irq);
break;
case KVM_S390_INT_CLOCK_COMP:
- rc = __inject_ckc(vcpu, s390int, inti);
+ rc = __inject_ckc(vcpu);
break;
case KVM_S390_INT_CPU_TIMER:
- rc = __inject_cpu_timer(vcpu, s390int, inti);
+ rc = __inject_cpu_timer(vcpu);
break;
case KVM_S390_INT_EXTERNAL_CALL:
- rc = __inject_extcall(vcpu, s390int, inti);
+ rc = __inject_extcall(vcpu, irq);
break;
case KVM_S390_INT_EMERGENCY:
- rc = __inject_sigp_emergency(vcpu, s390int, inti);
+ rc = __inject_sigp_emergency(vcpu, irq);
break;
case KVM_S390_MCHK:
- rc = __inject_mchk(vcpu, s390int, inti);
+ rc = __inject_mchk(vcpu, irq);
break;
case KVM_S390_INT_PFAULT_INIT:
- rc = __inject_pfault_init(vcpu, s390int, inti);
+ rc = __inject_pfault_init(vcpu, irq);
break;
case KVM_S390_INT_VIRTIO:
case KVM_S390_INT_SERVICE:
@@ -1231,8 +1344,6 @@ int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
spin_unlock(&li->lock);
if (!rc)
kvm_s390_vcpu_wakeup(vcpu);
- else
- kfree(inti);
return rc;
}
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 06878bd..f66591e 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -719,7 +719,6 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
}
spin_lock_init(&vcpu->arch.local_int.lock);
- INIT_LIST_HEAD(&vcpu->arch.local_int.list);
vcpu->arch.local_int.float_int = &kvm->arch.float_int;
vcpu->arch.local_int.wq = &vcpu->wq;
vcpu->arch.local_int.cpuflags = &vcpu->arch.sie_block->cpuflags;
@@ -1122,13 +1121,15 @@ static void __kvm_inject_pfault_token(struct kvm_vcpu *vcpu, bool start_token,
unsigned long token)
{
struct kvm_s390_interrupt inti;
- inti.parm64 = token;
+ struct kvm_s390_irq irq;
if (start_token) {
- inti.type = KVM_S390_INT_PFAULT_INIT;
- WARN_ON_ONCE(kvm_s390_inject_vcpu(vcpu, &inti));
+ irq.u.ext.ext_params2 = token;
+ irq.type = KVM_S390_INT_PFAULT_INIT;
+ WARN_ON_ONCE(kvm_s390_inject_vcpu(vcpu, &irq));
} else {
inti.type = KVM_S390_INT_PFAULT_DONE;
+ inti.parm64 = token;
WARN_ON_ONCE(kvm_s390_inject_vm(vcpu->kvm, &inti));
}
}
@@ -1622,11 +1623,14 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
switch (ioctl) {
case KVM_S390_INTERRUPT: {
struct kvm_s390_interrupt s390int;
+ struct kvm_s390_irq s390irq;
r = -EFAULT;
if (copy_from_user(&s390int, argp, sizeof(s390int)))
break;
- r = kvm_s390_inject_vcpu(vcpu, &s390int);
+ if (s390int_to_s390irq(&s390int, &s390irq))
+ return -EINVAL;
+ r = kvm_s390_inject_vcpu(vcpu, &s390irq);
break;
}
case KVM_S390_STORE_STATUS:
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index ff8d977..a8f3d9b 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -142,7 +142,7 @@ void kvm_s390_clear_float_irqs(struct kvm *kvm);
int __must_check kvm_s390_inject_vm(struct kvm *kvm,
struct kvm_s390_interrupt *s390int);
int __must_check kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
- struct kvm_s390_interrupt *s390int);
+ 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);
@@ -224,6 +224,9 @@ static inline int kvm_s390_inject_prog_cond(struct kvm_vcpu *vcpu, int rc)
return kvm_s390_inject_prog_irq(vcpu, &vcpu->arch.pgm);
}
+int s390int_to_s390irq(struct kvm_s390_interrupt *s390int,
+ struct kvm_s390_irq *s390irq);
+
/* implemented in interrupt.c */
int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu);
int psw_extint_disabled(struct kvm_vcpu *vcpu);
diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c
index f7cd3f7..6651f9f 100644
--- a/arch/s390/kvm/sigp.c
+++ b/arch/s390/kvm/sigp.c
@@ -49,13 +49,13 @@ static int __sigp_sense(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu,
static int __inject_sigp_emergency(struct kvm_vcpu *vcpu,
struct kvm_vcpu *dst_vcpu)
{
- struct kvm_s390_interrupt s390int = {
+ struct kvm_s390_irq irq = {
.type = KVM_S390_INT_EMERGENCY,
- .parm = vcpu->vcpu_id,
+ .u.emerg.code = vcpu->vcpu_id,
};
int rc = 0;
- rc = kvm_s390_inject_vcpu(dst_vcpu, &s390int);
+ rc = kvm_s390_inject_vcpu(dst_vcpu, &irq);
if (!rc)
VCPU_EVENT(vcpu, 4, "sent sigp emerg to cpu %x",
dst_vcpu->vcpu_id);
@@ -98,13 +98,13 @@ static int __sigp_conditional_emergency(struct kvm_vcpu *vcpu,
static int __sigp_external_call(struct kvm_vcpu *vcpu,
struct kvm_vcpu *dst_vcpu)
{
- struct kvm_s390_interrupt s390int = {
+ struct kvm_s390_irq irq = {
.type = KVM_S390_INT_EXTERNAL_CALL,
- .parm = vcpu->vcpu_id,
+ .u.extcall.code = vcpu->vcpu_id,
};
int rc;
- rc = kvm_s390_inject_vcpu(dst_vcpu, &s390int);
+ rc = kvm_s390_inject_vcpu(dst_vcpu, &irq);
if (!rc)
VCPU_EVENT(vcpu, 4, "sent sigp ext call to cpu %x",
dst_vcpu->vcpu_id);
@@ -115,29 +115,20 @@ static int __sigp_external_call(struct kvm_vcpu *vcpu,
static int __inject_sigp_stop(struct kvm_vcpu *dst_vcpu, int action)
{
struct kvm_s390_local_interrupt *li = &dst_vcpu->arch.local_int;
- struct kvm_s390_interrupt_info *inti;
int rc = SIGP_CC_ORDER_CODE_ACCEPTED;
- inti = kzalloc(sizeof(*inti), GFP_ATOMIC);
- if (!inti)
- return -ENOMEM;
- inti->type = KVM_S390_SIGP_STOP;
-
spin_lock(&li->lock);
if (li->action_bits & ACTION_STOP_ON_STOP) {
/* another SIGP STOP is pending */
- kfree(inti);
rc = SIGP_CC_BUSY;
goto out;
}
if ((atomic_read(li->cpuflags) & CPUSTAT_STOPPED)) {
- kfree(inti);
if ((action & ACTION_STORE_ON_STOP) != 0)
rc = -ESHUTDOWN;
goto out;
}
- list_add_tail(&inti->list, &li->list);
- atomic_set(&li->active, 1);
+ set_bit(IRQ_PEND_SIGP_STOP, &li->pending_irqs);
li->action_bits |= action;
atomic_set_mask(CPUSTAT_STOP_INT, li->cpuflags);
kvm_s390_vcpu_wakeup(dst_vcpu);
@@ -207,7 +198,6 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu,
u32 address, u64 *reg)
{
struct kvm_s390_local_interrupt *li;
- struct kvm_s390_interrupt_info *inti;
int rc;
li = &dst_vcpu->arch.local_int;
@@ -224,25 +214,17 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu,
return SIGP_CC_STATUS_STORED;
}
- inti = kzalloc(sizeof(*inti), GFP_KERNEL);
- if (!inti)
- return SIGP_CC_BUSY;
-
spin_lock(&li->lock);
/* cpu must be in stopped state */
if (!(atomic_read(li->cpuflags) & CPUSTAT_STOPPED)) {
*reg &= 0xffffffff00000000UL;
*reg |= SIGP_STATUS_INCORRECT_STATE;
rc = SIGP_CC_STATUS_STORED;
- kfree(inti);
goto out_li;
}
- inti->type = KVM_S390_SIGP_SET_PREFIX;
- inti->prefix.address = address;
-
- list_add_tail(&inti->list, &li->list);
- atomic_set(&li->active, 1);
+ li->irq.prefix.address = address;
+ set_bit(IRQ_PEND_SET_PREFIX, &li->pending_irqs);
kvm_s390_vcpu_wakeup(dst_vcpu);
rc = SIGP_CC_ORDER_CODE_ACCEPTED;
--
1.9.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [GIT PULL 11/11] KVM: s390: allow injecting all kinds of machine checks
2014-11-28 13:25 [GIT PULL 00/11] KVM: s390: Several changes for 3.19 (kvm/next) Christian Borntraeger
` (9 preceding siblings ...)
2014-11-28 13:25 ` [GIT PULL 10/11] KVM: s390: handle pending local interrupts via bitmap Christian Borntraeger
@ 2014-11-28 13:25 ` Christian Borntraeger
2014-11-28 17:20 ` [GIT PULL 00/11] KVM: s390: Several changes for 3.19 (kvm/next) Paolo Bonzini
11 siblings, 0 replies; 23+ messages in thread
From: Christian Borntraeger @ 2014-11-28 13:25 UTC (permalink / raw)
To: Paolo Bonzini
Cc: KVM, Alexander Graf, Cornelia Huck, Jens Freimann, linux-s390,
Christian Borntraeger
From: Jens Freimann <jfrei@linux.vnet.ibm.com>
Allow to specify CR14, logout area, external damage code
and failed storage address.
Since more then one machine check can be indicated to the guest at
a time we need to combine all indication bits with already pending
requests.
Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com>
Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Reviewed-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
---
arch/s390/kvm/interrupt.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 1aa7f28..b3d4409 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -1063,11 +1063,19 @@ static int __inject_mchk(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
mchk->mcic, 2);
/*
- * Combine mcic with previously injected machine checks and
- * indicate them all together as described in the Principles
- * of Operation, Chapter 11, Interruption action
+ * Because repressible machine checks can be indicated along with
+ * exigent machine checks (PoP, Chapter 11, Interruption action)
+ * we need to combine cr14, mcic and external damage code.
+ * Failing storage address and the logout area should not be or'ed
+ * together, we just indicate the last occurrence of the corresponding
+ * machine check
*/
+ mchk->cr14 |= irq->u.mchk.cr14;
mchk->mcic |= irq->u.mchk.mcic;
+ mchk->ext_damage_code |= irq->u.mchk.ext_damage_code;
+ mchk->failing_storage_address = irq->u.mchk.failing_storage_address;
+ memcpy(&mchk->fixed_logout, &irq->u.mchk.fixed_logout,
+ sizeof(mchk->fixed_logout));
if (mchk->mcic & MCHK_EX_MASK)
set_bit(IRQ_PEND_MCHK_EX, &li->pending_irqs);
else if (mchk->mcic & MCHK_REP_MASK)
--
1.9.3
^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [GIT PULL 05/11] KVM: s390: refactor interrupt injection code
2014-11-28 13:25 ` [GIT PULL 05/11] KVM: s390: refactor interrupt injection code Christian Borntraeger
@ 2014-11-28 17:16 ` Paolo Bonzini
2014-12-01 8:00 ` Christian Borntraeger
2014-12-01 8:22 ` Jens Freimann
0 siblings, 2 replies; 23+ messages in thread
From: Paolo Bonzini @ 2014-11-28 17:16 UTC (permalink / raw)
To: Christian Borntraeger
Cc: KVM, Alexander Graf, Cornelia Huck, Jens Freimann, linux-s390
On 28/11/2014 14:25, Christian Borntraeger wrote:
>
> +static int __inject_prog_irq(struct kvm_vcpu *vcpu,
> + struct kvm_s390_interrupt_info *inti)
> +{
Why the __s? :)
Paolo
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [GIT PULL 08/11] KVM: s390: refactor interrupt delivery code
2014-11-28 13:25 ` [GIT PULL 08/11] KVM: s390: refactor interrupt delivery code Christian Borntraeger
@ 2014-11-28 17:17 ` Paolo Bonzini
0 siblings, 0 replies; 23+ messages in thread
From: Paolo Bonzini @ 2014-11-28 17:17 UTC (permalink / raw)
To: Christian Borntraeger
Cc: KVM, Alexander Graf, Cornelia Huck, Jens Freimann, linux-s390
On 28/11/2014 14:25, Christian Borntraeger wrote:
> +static int __must_check __deliver_cpu_timer(struct kvm_vcpu *vcpu)
> +{
> + int rc;
Same here...
Paolo
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [GIT PULL 09/11] KVM: s390: add bitmap for handling cpu-local interrupts
2014-11-28 13:25 ` [GIT PULL 09/11] KVM: s390: add bitmap for handling cpu-local interrupts Christian Borntraeger
@ 2014-11-28 17:18 ` Paolo Bonzini
2014-11-29 21:05 ` Christian Borntraeger
2014-12-01 8:18 ` Jens Freimann
0 siblings, 2 replies; 23+ messages in thread
From: Paolo Bonzini @ 2014-11-28 17:18 UTC (permalink / raw)
To: Christian Borntraeger
Cc: KVM, Alexander Graf, Cornelia Huck, Jens Freimann, linux-s390
On 28/11/2014 14:25, Christian Borntraeger wrote:
>
> +struct kvm_s390_irq_payload {
> + struct kvm_s390_io_info io;
> + struct kvm_s390_ext_info ext;
> + struct kvm_s390_pgm_info pgm;
> + struct kvm_s390_emerg_info emerg;
> + struct kvm_s390_extcall_info extcall;
> + struct kvm_s390_prefix_info prefix;
> + struct kvm_s390_mchk_info mchk;
> +};
> +
struct or union?
Paolo
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [GIT PULL 00/11] KVM: s390: Several changes for 3.19 (kvm/next)
2014-11-28 13:25 [GIT PULL 00/11] KVM: s390: Several changes for 3.19 (kvm/next) Christian Borntraeger
` (10 preceding siblings ...)
2014-11-28 13:25 ` [GIT PULL 11/11] KVM: s390: allow injecting all kinds of machine checks Christian Borntraeger
@ 2014-11-28 17:20 ` Paolo Bonzini
11 siblings, 0 replies; 23+ messages in thread
From: Paolo Bonzini @ 2014-11-28 17:20 UTC (permalink / raw)
To: Christian Borntraeger
Cc: KVM, Alexander Graf, Cornelia Huck, Jens Freimann, linux-s390
On 28/11/2014 14:25, Christian Borntraeger wrote:
> Paolo,
>
> here is a bunch of changes dealing mostly with architectural compliance.
> I have deferred the TOD clock interface (as well as a storage key
> read/write) as we found some issues in our final internal review.
> Depending on Linus schedule these might have to wait for the next merge
> window or might still come next week as I want to gives other a chance
> to comment on interface changes.
>
> The following changes since commit b65d6e17fe2239c9b2051727903955d922083fbf:
>
> kvm: x86: mask out XSAVES (2014-11-23 18:33:37 +0100)
>
> are available in the git repository at:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux.git tags/kvm-s390-next-20141128
>
> for you to fetch changes up to fc2020cfe9f8102d17dad79ed96dc68a9d84b19e:
>
> KVM: s390: allow injecting all kinds of machine checks (2014-11-28 13:59:05 +0100)
>
> ----------------------------------------------------------------
> KVM: s390: Several fixes,cleanups and reworks
>
> Here is a bunch of fixes that deal mostly with architectural compliance:
> - interrupt priorities
> - interrupt handling
> - intruction exit handling
>
> We also provide a helper function for getting the guest visible storage key.
>
> ----------------------------------------------------------------
> Christian Borntraeger (1):
> KVM: s390: trigger the right CPU exit for floating interrupts
>
> David Hildenbrand (1):
> KVM: s390: external param not valid for cpu timer and ckc
>
> Jason J. Herne (1):
> KVM: S390: Create helper function get_guest_storage_key
>
> Jens Freimann (6):
> KVM: s390: refactor interrupt injection code
> KVM: s390: add defines for virtio and pfault interrupt code
> KVM: s390: refactor interrupt delivery code
> KVM: s390: add bitmap for handling cpu-local interrupts
> KVM: s390: handle pending local interrupts via bitmap
> KVM: s390: allow injecting all kinds of machine checks
>
> Thomas Huth (2):
> KVM: s390: Small fixes for the PFMF handler
> KVM: s390: Fix rewinding of the PSW pointing to an EXECUTE instruction
>
> arch/s390/include/asm/kvm_host.h | 90 +++-
> arch/s390/include/asm/pgalloc.h | 1 +
> arch/s390/kvm/intercept.c | 20 +-
> arch/s390/kvm/interrupt.c | 1037 +++++++++++++++++++++++++-------------
> arch/s390/kvm/kvm-s390.c | 14 +-
> arch/s390/kvm/kvm-s390.h | 11 +-
> arch/s390/kvm/priv.c | 23 +-
> arch/s390/kvm/sigp.c | 36 +-
> arch/s390/mm/pgtable.c | 39 ++
> 9 files changed, 872 insertions(+), 399 deletions(-)
>
I could not really do more than generic stylistic comments, and I've
pulled the tree.
(To clarify the comment about "__", that usually means that there is
non-prefixed function that does the same thing and is generally the one
you want to call. For example, function foo might wrap __foo with a
spinlock).
Paolo
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [GIT PULL 09/11] KVM: s390: add bitmap for handling cpu-local interrupts
2014-11-28 17:18 ` Paolo Bonzini
@ 2014-11-29 21:05 ` Christian Borntraeger
2014-12-01 14:59 ` Jens Freimann
2014-12-01 8:18 ` Jens Freimann
1 sibling, 1 reply; 23+ messages in thread
From: Christian Borntraeger @ 2014-11-29 21:05 UTC (permalink / raw)
To: Paolo Bonzini
Cc: KVM, Alexander Graf, Cornelia Huck, Jens Freimann, linux-s390
Am 28.11.2014 um 18:18 schrieb Paolo Bonzini:
>
>
> On 28/11/2014 14:25, Christian Borntraeger wrote:
>>
>> +struct kvm_s390_irq_payload {
>> + struct kvm_s390_io_info io;
>> + struct kvm_s390_ext_info ext;
>> + struct kvm_s390_pgm_info pgm;
>> + struct kvm_s390_emerg_info emerg;
>> + struct kvm_s390_extcall_info extcall;
>> + struct kvm_s390_prefix_info prefix;
>> + struct kvm_s390_mchk_info mchk;
>> +};
>> +
>
> struct or union?
struct. This is used for keeping the payload of the interrupts. Multiple different interrupts can be pending and most of them have payload - we want to keep everything.
Now, looking at that code again, as I/O is floating and emergency is also handled via a separate bitmap we could get rid of these two in a follow-up patch. Jens, can you have a look and prepare a followup-cleanup if appropriate?
Christian
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [GIT PULL 05/11] KVM: s390: refactor interrupt injection code
2014-11-28 17:16 ` Paolo Bonzini
@ 2014-12-01 8:00 ` Christian Borntraeger
2014-12-01 8:22 ` Jens Freimann
1 sibling, 0 replies; 23+ messages in thread
From: Christian Borntraeger @ 2014-12-01 8:00 UTC (permalink / raw)
To: Paolo Bonzini
Cc: KVM, Alexander Graf, Cornelia Huck, Jens Freimann, linux-s390
Am 28.11.2014 um 18:16 schrieb Paolo Bonzini:
>
>
> On 28/11/2014 14:25, Christian Borntraeger wrote:
>>
>> +static int __inject_prog_irq(struct kvm_vcpu *vcpu,
>> + struct kvm_s390_interrupt_info *inti)
>> +{
>
> Why the __s? :)
In this case because its called with a lock already held. (from kvm_s390_inject_vcpu).
I usually extend the usage of the __ prefix to "heho, pay attention. YOu are calling this function, but you are maybe supposed to do something else).
Christian
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [GIT PULL 09/11] KVM: s390: add bitmap for handling cpu-local interrupts
2014-11-28 17:18 ` Paolo Bonzini
2014-11-29 21:05 ` Christian Borntraeger
@ 2014-12-01 8:18 ` Jens Freimann
1 sibling, 0 replies; 23+ messages in thread
From: Jens Freimann @ 2014-12-01 8:18 UTC (permalink / raw)
To: Paolo Bonzini
Cc: Christian Borntraeger, KVM, Alexander Graf, Cornelia Huck,
linux-s390
Excerpts from Paolo Bonzini's message of 2014-11-28 18:18:53 +0100:
>
> On 28/11/2014 14:25, Christian Borntraeger wrote:
> >
> > +struct kvm_s390_irq_payload {
> > + struct kvm_s390_io_info io;
> > + struct kvm_s390_ext_info ext;
> > + struct kvm_s390_pgm_info pgm;
> > + struct kvm_s390_emerg_info emerg;
> > + struct kvm_s390_extcall_info extcall;
> > + struct kvm_s390_prefix_info prefix;
> > + struct kvm_s390_mchk_info mchk;
> > +};
> > +
>
> struct or union?
This really should be a struct because we use it to keep payload data for
several parallel pending interrupts and don't want to write over other data.
Jens
>
> Paolo
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [GIT PULL 10/11] KVM: s390: handle pending local interrupts via bitmap
2014-11-28 13:25 ` [GIT PULL 10/11] KVM: s390: handle pending local interrupts via bitmap Christian Borntraeger
@ 2014-12-01 8:19 ` Heiko Carstens
2014-12-01 9:46 ` Jens Freimann
0 siblings, 1 reply; 23+ messages in thread
From: Heiko Carstens @ 2014-12-01 8:19 UTC (permalink / raw)
To: Christian Borntraeger
Cc: Paolo Bonzini, KVM, Alexander Graf, Cornelia Huck, Jens Freimann,
linux-s390
On Fri, Nov 28, 2014 at 02:25:38PM +0100, Christian Borntraeger wrote:
> +static int __must_check __deliver_mchk_floating(struct kvm_vcpu *vcpu,
> + struct kvm_s390_interrupt_info *inti)
> +{
> + struct kvm_s390_mchk_info *mchk = &inti->mchk;
> + int rc;
> +
> + VCPU_EVENT(vcpu, 4, "interrupt: machine check mcic=%llx",
> + mchk->mcic);
> + trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_MCHK,
> + mchk->cr14, mchk->mcic);
> +
> + rc = kvm_s390_vcpu_store_status(vcpu, KVM_S390_STORE_STATUS_PREFIXED);
> + rc |= put_guest_lc(vcpu, mchk->mcic,
> + (u64 __user *) __LC_MCCK_CODE);
> + rc |= put_guest_lc(vcpu, mchk->failing_storage_address,
> + (u64 __user *) __LC_MCCK_FAIL_STOR_ADDR);
> + rc |= write_guest_lc(vcpu, __LC_PSW_SAVE_AREA,
> + &mchk->fixed_logout, sizeof(mchk->fixed_logout));
> + rc |= write_guest_lc(vcpu, __LC_MCK_OLD_PSW,
> + &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
> + rc |= read_guest_lc(vcpu, __LC_MCK_NEW_PSW,
> + &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
> + return rc;
> +}
FWIW, rc handling seems to be a bit fragile.
The usual return statement for such a pattern is
return rc ? -EWHATEVER : 0;
so we don't get random or'ed return values.
> -static int __inject_prog_irq(struct kvm_vcpu *vcpu,
> - struct kvm_s390_interrupt_info *inti)
> +static int __inject_prog(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
> {
> struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
>
> - list_add(&inti->list, &li->list);
> - atomic_set(&li->active, 1);
> + li->irq.pgm = irq->u.pgm;
> + __set_bit(IRQ_PEND_PROG, &li->pending_irqs);
^^^^^^^^^
> +static int __inject_pfault_init(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
> {
> struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
>
> - inti->ext.ext_params2 = s390int->parm64;
> - list_add_tail(&inti->list, &li->list);
> - atomic_set(&li->active, 1);
> + VCPU_EVENT(vcpu, 3, "inject: external irq params:%x, params2:%llx",
> + irq->u.ext.ext_params, irq->u.ext.ext_params2);
> + trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_INT_PFAULT_INIT,
> + irq->u.ext.ext_params,
> + irq->u.ext.ext_params2, 2);
> +
> + li->irq.ext = irq->u.ext;
> + set_bit(IRQ_PEND_PFAULT_INIT, &li->pending_irqs);
^^^^^^^
You're using atomic and non-atomic bitops all over the place on the same
object(s). It would be very good to have some consistency here.
And as far as I remember the non-atomic variant is good enough anyway.
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [GIT PULL 05/11] KVM: s390: refactor interrupt injection code
2014-11-28 17:16 ` Paolo Bonzini
2014-12-01 8:00 ` Christian Borntraeger
@ 2014-12-01 8:22 ` Jens Freimann
1 sibling, 0 replies; 23+ messages in thread
From: Jens Freimann @ 2014-12-01 8:22 UTC (permalink / raw)
To: Paolo Bonzini
Cc: Christian Borntraeger, KVM, Alexander Graf, Cornelia Huck,
linux-s390
Excerpts from Paolo Bonzini's message of 2014-11-28 18:16:03 +0100:
>
> On 28/11/2014 14:25, Christian Borntraeger wrote:
> >
> > +static int __inject_prog_irq(struct kvm_vcpu *vcpu,
> > + struct kvm_s390_interrupt_info *inti)
> > +{
>
> Why the __s? :)
I used the __s here to say "careful, this is usually not called directly".
Jens
>
> Paolo
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [GIT PULL 10/11] KVM: s390: handle pending local interrupts via bitmap
2014-12-01 8:19 ` Heiko Carstens
@ 2014-12-01 9:46 ` Jens Freimann
0 siblings, 0 replies; 23+ messages in thread
From: Jens Freimann @ 2014-12-01 9:46 UTC (permalink / raw)
To: Heiko Carstens
Cc: Christian Borntraeger, Paolo Bonzini, KVM, Alexander Graf,
Cornelia Huck, linux-s390
Excerpts from Heiko Carstens's message of 2014-12-01 09:19:16 +0100:
> On Fri, Nov 28, 2014 at 02:25:38PM +0100, Christian Borntraeger wrote:
> > +static int __must_check __deliver_mchk_floating(struct kvm_vcpu *vcpu,
> > + struct kvm_s390_interrupt_info *inti)
> > +{
> > + struct kvm_s390_mchk_info *mchk = &inti->mchk;
> > + int rc;
> > +
> > + VCPU_EVENT(vcpu, 4, "interrupt: machine check mcic=%llx",
> > + mchk->mcic);
> > + trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_MCHK,
> > + mchk->cr14, mchk->mcic);
> > +
> > + rc = kvm_s390_vcpu_store_status(vcpu, KVM_S390_STORE_STATUS_PREFIXED);
> > + rc |= put_guest_lc(vcpu, mchk->mcic,
> > + (u64 __user *) __LC_MCCK_CODE);
> > + rc |= put_guest_lc(vcpu, mchk->failing_storage_address,
> > + (u64 __user *) __LC_MCCK_FAIL_STOR_ADDR);
> > + rc |= write_guest_lc(vcpu, __LC_PSW_SAVE_AREA,
> > + &mchk->fixed_logout, sizeof(mchk->fixed_logout));
> > + rc |= write_guest_lc(vcpu, __LC_MCK_OLD_PSW,
> > + &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
> > + rc |= read_guest_lc(vcpu, __LC_MCK_NEW_PSW,
> > + &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
> > + return rc;
> > +}
>
> FWIW, rc handling seems to be a bit fragile.
> The usual return statement for such a pattern is
> return rc ? -EWHATEVER : 0;
> so we don't get random or'ed return values.
Ok, I'll change this to return -EFAULT (need to double check) if rc is set.
>
> > -static int __inject_prog_irq(struct kvm_vcpu *vcpu,
> > - struct kvm_s390_interrupt_info *inti)
> > +static int __inject_prog(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
> > {
> > struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
> >
> > - list_add(&inti->list, &li->list);
> > - atomic_set(&li->active, 1);
> > + li->irq.pgm = irq->u.pgm;
> > + __set_bit(IRQ_PEND_PROG, &li->pending_irqs);
>
> ^^^^^^^^^
>
> > +static int __inject_pfault_init(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
> > {
> > struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
> >
> > - inti->ext.ext_params2 = s390int->parm64;
> > - list_add_tail(&inti->list, &li->list);
> > - atomic_set(&li->active, 1);
> > + VCPU_EVENT(vcpu, 3, "inject: external irq params:%x, params2:%llx",
> > + irq->u.ext.ext_params, irq->u.ext.ext_params2);
> > + trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_INT_PFAULT_INIT,
> > + irq->u.ext.ext_params,
> > + irq->u.ext.ext_params2, 2);
> > +
> > + li->irq.ext = irq->u.ext;
> > + set_bit(IRQ_PEND_PFAULT_INIT, &li->pending_irqs);
>
> ^^^^^^^
>
> You're using atomic and non-atomic bitops all over the place on the same
> object(s). It would be very good to have some consistency here.
> And as far as I remember the non-atomic variant is good enough anyway.
I think you are right. The non-atomic bitops are sufficient here. I'll fix this.
Paolo, is a follow-up patch good enough or should we fix this one?
regards
Jens
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [GIT PULL 09/11] KVM: s390: add bitmap for handling cpu-local interrupts
2014-11-29 21:05 ` Christian Borntraeger
@ 2014-12-01 14:59 ` Jens Freimann
0 siblings, 0 replies; 23+ messages in thread
From: Jens Freimann @ 2014-12-01 14:59 UTC (permalink / raw)
To: Christian Borntraeger
Cc: Paolo Bonzini, KVM, Alexander Graf, Cornelia Huck, linux-s390
Excerpts from Christian Borntraeger's message of 2014-11-29 22:05:10 +0100:
> Am 28.11.2014 um 18:18 schrieb Paolo Bonzini:
> >
> >
> > On 28/11/2014 14:25, Christian Borntraeger wrote:
> >>
> >> +struct kvm_s390_irq_payload {
> >> + struct kvm_s390_io_info io;
> >> + struct kvm_s390_ext_info ext;
> >> + struct kvm_s390_pgm_info pgm;
> >> + struct kvm_s390_emerg_info emerg;
> >> + struct kvm_s390_extcall_info extcall;
> >> + struct kvm_s390_prefix_info prefix;
> >> + struct kvm_s390_mchk_info mchk;
> >> +};
> >> +
> >
> > struct or union?
>
> struct. This is used for keeping the payload of the interrupts. Multiple different interrupts can be pending and most of them have payload - we want to keep everything.
>
> Now, looking at that code again, as I/O is floating and emergency is also handled via a separate bitmap we could get rid of these two in a follow-up patch. Jens, can you have a look and prepare a followup-cleanup if appropriate?
I/O is floating and currently not used in that struct, but I have a patch
series in the works to change floating interrupts as well and will need it then.
I will check if I can get rid of the emerg_info and sent a followup patch.
Jens
> Christian
^ permalink raw reply [flat|nested] 23+ messages in thread
end of thread, other threads:[~2014-12-01 14:59 UTC | newest]
Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-11-28 13:25 [GIT PULL 00/11] KVM: s390: Several changes for 3.19 (kvm/next) Christian Borntraeger
2014-11-28 13:25 ` [GIT PULL 01/11] KVM: s390: Small fixes for the PFMF handler Christian Borntraeger
2014-11-28 13:25 ` [GIT PULL 02/11] KVM: s390: Fix rewinding of the PSW pointing to an EXECUTE instruction Christian Borntraeger
2014-11-28 13:25 ` [GIT PULL 03/11] KVM: s390: trigger the right CPU exit for floating interrupts Christian Borntraeger
2014-11-28 13:25 ` [GIT PULL 04/11] KVM: S390: Create helper function get_guest_storage_key Christian Borntraeger
2014-11-28 13:25 ` [GIT PULL 05/11] KVM: s390: refactor interrupt injection code Christian Borntraeger
2014-11-28 17:16 ` Paolo Bonzini
2014-12-01 8:00 ` Christian Borntraeger
2014-12-01 8:22 ` Jens Freimann
2014-11-28 13:25 ` [GIT PULL 06/11] KVM: s390: external param not valid for cpu timer and ckc Christian Borntraeger
2014-11-28 13:25 ` [GIT PULL 07/11] KVM: s390: add defines for virtio and pfault interrupt code Christian Borntraeger
2014-11-28 13:25 ` [GIT PULL 08/11] KVM: s390: refactor interrupt delivery code Christian Borntraeger
2014-11-28 17:17 ` Paolo Bonzini
2014-11-28 13:25 ` [GIT PULL 09/11] KVM: s390: add bitmap for handling cpu-local interrupts Christian Borntraeger
2014-11-28 17:18 ` Paolo Bonzini
2014-11-29 21:05 ` Christian Borntraeger
2014-12-01 14:59 ` Jens Freimann
2014-12-01 8:18 ` Jens Freimann
2014-11-28 13:25 ` [GIT PULL 10/11] KVM: s390: handle pending local interrupts via bitmap Christian Borntraeger
2014-12-01 8:19 ` Heiko Carstens
2014-12-01 9:46 ` Jens Freimann
2014-11-28 13:25 ` [GIT PULL 11/11] KVM: s390: allow injecting all kinds of machine checks Christian Borntraeger
2014-11-28 17:20 ` [GIT PULL 00/11] KVM: s390: Several changes for 3.19 (kvm/next) Paolo Bonzini
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).