aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2013-04-17 16:32:26 -0400
committerAlexander Graf <agraf@suse.de>2013-04-26 14:27:34 -0400
commit8b78645c93b5d469e8006d68dbc92edc2640c654 (patch)
tree5f558213cc4bd2677069232d7dc1a78c96aee165 /arch
parentd19bd86204f85d42873e07bb64a27587fc380b5b (diff)
KVM: PPC: Book3S: Facilities to save/restore XICS presentation ctrler state
This adds the ability for userspace to save and restore the state of the XICS interrupt presentation controllers (ICPs) via the KVM_GET/SET_ONE_REG interface. Since there is one ICP per vcpu, we simply define a new 64-bit register in the ONE_REG space for the ICP state. The state includes the CPU priority setting, the pending IPI priority, and the priority and source number of any pending external interrupt. Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/include/asm/kvm_ppc.h2
-rw-r--r--arch/powerpc/include/uapi/asm/kvm.h12
-rw-r--r--arch/powerpc/kvm/book3s.c19
-rw-r--r--arch/powerpc/kvm/book3s_xics.c90
4 files changed, 123 insertions, 0 deletions
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index cfaa47995c0e..d7339df19259 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -313,6 +313,8 @@ extern void kvmppc_xics_free_icp(struct kvm_vcpu *vcpu);
313extern int kvmppc_xics_create_icp(struct kvm_vcpu *vcpu, unsigned long server); 313extern int kvmppc_xics_create_icp(struct kvm_vcpu *vcpu, unsigned long server);
314extern int kvm_vm_ioctl_xics_irq(struct kvm *kvm, struct kvm_irq_level *args); 314extern int kvm_vm_ioctl_xics_irq(struct kvm *kvm, struct kvm_irq_level *args);
315extern int kvmppc_xics_hcall(struct kvm_vcpu *vcpu, u32 cmd); 315extern int kvmppc_xics_hcall(struct kvm_vcpu *vcpu, u32 cmd);
316extern u64 kvmppc_xics_get_icp(struct kvm_vcpu *vcpu);
317extern int kvmppc_xics_set_icp(struct kvm_vcpu *vcpu, u64 icpval);
316#else 318#else
317static inline int kvmppc_xics_enabled(struct kvm_vcpu *vcpu) 319static inline int kvmppc_xics_enabled(struct kvm_vcpu *vcpu)
318 { return 0; } 320 { return 0; }
diff --git a/arch/powerpc/include/uapi/asm/kvm.h b/arch/powerpc/include/uapi/asm/kvm.h
index eb9e25c194ad..427b9aca2a0f 100644
--- a/arch/powerpc/include/uapi/asm/kvm.h
+++ b/arch/powerpc/include/uapi/asm/kvm.h
@@ -390,6 +390,18 @@ struct kvm_get_htab_header {
390 __u16 n_invalid; 390 __u16 n_invalid;
391}; 391};
392 392
393/* Per-vcpu XICS interrupt controller state */
394#define KVM_REG_PPC_ICP_STATE (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x8c)
395
396#define KVM_REG_PPC_ICP_CPPR_SHIFT 56 /* current proc priority */
397#define KVM_REG_PPC_ICP_CPPR_MASK 0xff
398#define KVM_REG_PPC_ICP_XISR_SHIFT 32 /* interrupt status field */
399#define KVM_REG_PPC_ICP_XISR_MASK 0xffffff
400#define KVM_REG_PPC_ICP_MFRR_SHIFT 24 /* pending IPI priority */
401#define KVM_REG_PPC_ICP_MFRR_MASK 0xff
402#define KVM_REG_PPC_ICP_PPRI_SHIFT 16 /* pending irq priority */
403#define KVM_REG_PPC_ICP_PPRI_MASK 0xff
404
393/* Device control API: PPC-specific devices */ 405/* Device control API: PPC-specific devices */
394#define KVM_DEV_MPIC_GRP_MISC 1 406#define KVM_DEV_MPIC_GRP_MISC 1
395#define KVM_DEV_MPIC_BASE_ADDR 0 /* 64-bit */ 407#define KVM_DEV_MPIC_BASE_ADDR 0 /* 64-bit */
diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c
index 1a4d787df507..700df6f1d32c 100644
--- a/arch/powerpc/kvm/book3s.c
+++ b/arch/powerpc/kvm/book3s.c
@@ -535,6 +535,15 @@ int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
535 &opcode, sizeof(u32)); 535 &opcode, sizeof(u32));
536 break; 536 break;
537 } 537 }
538#ifdef CONFIG_KVM_XICS
539 case KVM_REG_PPC_ICP_STATE:
540 if (!vcpu->arch.icp) {
541 r = -ENXIO;
542 break;
543 }
544 val = get_reg_val(reg->id, kvmppc_xics_get_icp(vcpu));
545 break;
546#endif /* CONFIG_KVM_XICS */
538 default: 547 default:
539 r = -EINVAL; 548 r = -EINVAL;
540 break; 549 break;
@@ -597,6 +606,16 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
597 vcpu->arch.vscr.u[3] = set_reg_val(reg->id, val); 606 vcpu->arch.vscr.u[3] = set_reg_val(reg->id, val);
598 break; 607 break;
599#endif /* CONFIG_ALTIVEC */ 608#endif /* CONFIG_ALTIVEC */
609#ifdef CONFIG_KVM_XICS
610 case KVM_REG_PPC_ICP_STATE:
611 if (!vcpu->arch.icp) {
612 r = -ENXIO;
613 break;
614 }
615 r = kvmppc_xics_set_icp(vcpu,
616 set_reg_val(reg->id, val));
617 break;
618#endif /* CONFIG_KVM_XICS */
600 default: 619 default:
601 r = -EINVAL; 620 r = -EINVAL;
602 break; 621 break;
diff --git a/arch/powerpc/kvm/book3s_xics.c b/arch/powerpc/kvm/book3s_xics.c
index 9fb2d3909c46..ee841ed8a690 100644
--- a/arch/powerpc/kvm/book3s_xics.c
+++ b/arch/powerpc/kvm/book3s_xics.c
@@ -954,6 +954,96 @@ int kvmppc_xics_create_icp(struct kvm_vcpu *vcpu, unsigned long server_num)
954 return 0; 954 return 0;
955} 955}
956 956
957u64 kvmppc_xics_get_icp(struct kvm_vcpu *vcpu)
958{
959 struct kvmppc_icp *icp = vcpu->arch.icp;
960 union kvmppc_icp_state state;
961
962 if (!icp)
963 return 0;
964 state = icp->state;
965 return ((u64)state.cppr << KVM_REG_PPC_ICP_CPPR_SHIFT) |
966 ((u64)state.xisr << KVM_REG_PPC_ICP_XISR_SHIFT) |
967 ((u64)state.mfrr << KVM_REG_PPC_ICP_MFRR_SHIFT) |
968 ((u64)state.pending_pri << KVM_REG_PPC_ICP_PPRI_SHIFT);
969}
970
971int kvmppc_xics_set_icp(struct kvm_vcpu *vcpu, u64 icpval)
972{
973 struct kvmppc_icp *icp = vcpu->arch.icp;
974 struct kvmppc_xics *xics = vcpu->kvm->arch.xics;
975 union kvmppc_icp_state old_state, new_state;
976 struct kvmppc_ics *ics;
977 u8 cppr, mfrr, pending_pri;
978 u32 xisr;
979 u16 src;
980 bool resend;
981
982 if (!icp || !xics)
983 return -ENOENT;
984
985 cppr = icpval >> KVM_REG_PPC_ICP_CPPR_SHIFT;
986 xisr = (icpval >> KVM_REG_PPC_ICP_XISR_SHIFT) &
987 KVM_REG_PPC_ICP_XISR_MASK;
988 mfrr = icpval >> KVM_REG_PPC_ICP_MFRR_SHIFT;
989 pending_pri = icpval >> KVM_REG_PPC_ICP_PPRI_SHIFT;
990
991 /* Require the new state to be internally consistent */
992 if (xisr == 0) {
993 if (pending_pri != 0xff)
994 return -EINVAL;
995 } else if (xisr == XICS_IPI) {
996 if (pending_pri != mfrr || pending_pri >= cppr)
997 return -EINVAL;
998 } else {
999 if (pending_pri >= mfrr || pending_pri >= cppr)
1000 return -EINVAL;
1001 ics = kvmppc_xics_find_ics(xics, xisr, &src);
1002 if (!ics)
1003 return -EINVAL;
1004 }
1005
1006 new_state.raw = 0;
1007 new_state.cppr = cppr;
1008 new_state.xisr = xisr;
1009 new_state.mfrr = mfrr;
1010 new_state.pending_pri = pending_pri;
1011
1012 /*
1013 * Deassert the CPU interrupt request.
1014 * icp_try_update will reassert it if necessary.
1015 */
1016 kvmppc_book3s_dequeue_irqprio(icp->vcpu,
1017 BOOK3S_INTERRUPT_EXTERNAL_LEVEL);
1018
1019 /*
1020 * Note that if we displace an interrupt from old_state.xisr,
1021 * we don't mark it as rejected. We expect userspace to set
1022 * the state of the interrupt sources to be consistent with
1023 * the ICP states (either before or afterwards, which doesn't
1024 * matter). We do handle resends due to CPPR becoming less
1025 * favoured because that is necessary to end up with a
1026 * consistent state in the situation where userspace restores
1027 * the ICS states before the ICP states.
1028 */
1029 do {
1030 old_state = ACCESS_ONCE(icp->state);
1031
1032 if (new_state.mfrr <= old_state.mfrr) {
1033 resend = false;
1034 new_state.need_resend = old_state.need_resend;
1035 } else {
1036 resend = old_state.need_resend;
1037 new_state.need_resend = 0;
1038 }
1039 } while (!icp_try_update(icp, old_state, new_state, false));
1040
1041 if (resend)
1042 icp_check_resend(xics, icp);
1043
1044 return 0;
1045}
1046
957/* -- ioctls -- */ 1047/* -- ioctls -- */
958 1048
959int kvm_vm_ioctl_xics_irq(struct kvm *kvm, struct kvm_irq_level *args) 1049int kvm_vm_ioctl_xics_irq(struct kvm *kvm, struct kvm_irq_level *args)