aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--Documentation/virtual/kvm/api.txt1
-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
5 files changed, 124 insertions, 0 deletions
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index fb308be8521b..c09d1832e935 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -1808,6 +1808,7 @@ registers, find a list below:
1808 PPC | KVM_REG_PPC_TLB2PS | 32 1808 PPC | KVM_REG_PPC_TLB2PS | 32
1809 PPC | KVM_REG_PPC_TLB3PS | 32 1809 PPC | KVM_REG_PPC_TLB3PS | 32
1810 PPC | KVM_REG_PPC_EPTCFG | 32 1810 PPC | KVM_REG_PPC_EPTCFG | 32
1811 PPC | KVM_REG_PPC_ICP_STATE | 64
1811 1812
1812ARM registers are mapped using the lower 32 bits. The upper 16 of that 1813ARM registers are mapped using the lower 32 bits. The upper 16 of that
1813is the register group type, or coprocessor number: 1814is the register group type, or coprocessor number:
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)