aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2013-09-21 00:35:02 -0400
committerAlexander Graf <agraf@suse.de>2013-10-17 08:45:02 -0400
commit388cc6e133132e6c9b64e7d5361114a3a7d57663 (patch)
tree15414bef7bf1bc0d190d4b5cdb6d55fc2589fa44 /arch/powerpc
parent4b8473c9c19dff1b0c672f182cc50b9952cf42e7 (diff)
KVM: PPC: Book3S HV: Support POWER6 compatibility mode on POWER7
This enables us to use the Processor Compatibility Register (PCR) on POWER7 to put the processor into architecture 2.05 compatibility mode when running a guest. In this mode the new instructions and registers that were introduced on POWER7 are disabled in user mode. This includes all the VSX facilities plus several other instructions such as ldbrx, stdbrx, popcntw, popcntd, etc. To select this mode, we have a new register accessible through the set/get_one_reg interface, called KVM_REG_PPC_ARCH_COMPAT. Setting this to zero gives the full set of capabilities of the processor. Setting it to one of the "logical" PVR values defined in PAPR puts the vcpu into the compatibility mode for the corresponding architecture level. The supported values are: 0x0f000002 Architecture 2.05 (POWER6) 0x0f000003 Architecture 2.06 (POWER7) 0x0f100003 Architecture 2.06+ (POWER7+) Since the PCR is per-core, the architecture compatibility level and the corresponding PCR value are stored in the struct kvmppc_vcore, and are therefore shared between all vcpus in a virtual core. Signed-off-by: Paul Mackerras <paulus@samba.org> [agraf: squash in fix to add missing break statements and documentation] Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/include/asm/kvm_host.h2
-rw-r--r--arch/powerpc/include/asm/reg.h11
-rw-r--r--arch/powerpc/include/uapi/asm/kvm.h3
-rw-r--r--arch/powerpc/kernel/asm-offsets.c1
-rw-r--r--arch/powerpc/kvm/book3s_hv.c35
-rw-r--r--arch/powerpc/kvm/book3s_hv_rmhandlers.S16
6 files changed, 66 insertions, 2 deletions
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index 4934e13fb23c..b1e8f2ba2a9d 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -291,6 +291,8 @@ struct kvmppc_vcore {
291 struct kvm_vcpu *runner; 291 struct kvm_vcpu *runner;
292 u64 tb_offset; /* guest timebase - host timebase */ 292 u64 tb_offset; /* guest timebase - host timebase */
293 ulong lpcr; 293 ulong lpcr;
294 u32 arch_compat;
295 ulong pcr;
294}; 296};
295 297
296#define VCORE_ENTRY_COUNT(vc) ((vc)->entry_exit_count & 0xff) 298#define VCORE_ENTRY_COUNT(vc) ((vc)->entry_exit_count & 0xff)
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 4bec4df3fb98..e294673e9d4b 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -314,6 +314,10 @@
314#define LPID_RSVD 0x3ff /* Reserved LPID for partn switching */ 314#define LPID_RSVD 0x3ff /* Reserved LPID for partn switching */
315#define SPRN_HMER 0x150 /* Hardware m? error recovery */ 315#define SPRN_HMER 0x150 /* Hardware m? error recovery */
316#define SPRN_HMEER 0x151 /* Hardware m? enable error recovery */ 316#define SPRN_HMEER 0x151 /* Hardware m? enable error recovery */
317#define SPRN_PCR 0x152 /* Processor compatibility register */
318#define PCR_VEC_DIS (1ul << (63-0)) /* Vec. disable (bit NA since POWER8) */
319#define PCR_VSX_DIS (1ul << (63-1)) /* VSX disable (bit NA since POWER8) */
320#define PCR_ARCH_205 0x2 /* Architecture 2.05 */
317#define SPRN_HEIR 0x153 /* Hypervisor Emulated Instruction Register */ 321#define SPRN_HEIR 0x153 /* Hypervisor Emulated Instruction Register */
318#define SPRN_TLBINDEXR 0x154 /* P7 TLB control register */ 322#define SPRN_TLBINDEXR 0x154 /* P7 TLB control register */
319#define SPRN_TLBVPNR 0x155 /* P7 TLB control register */ 323#define SPRN_TLBVPNR 0x155 /* P7 TLB control register */
@@ -1106,6 +1110,13 @@
1106#define PVR_BE 0x0070 1110#define PVR_BE 0x0070
1107#define PVR_PA6T 0x0090 1111#define PVR_PA6T 0x0090
1108 1112
1113/* "Logical" PVR values defined in PAPR, representing architecture levels */
1114#define PVR_ARCH_204 0x0f000001
1115#define PVR_ARCH_205 0x0f000002
1116#define PVR_ARCH_206 0x0f000003
1117#define PVR_ARCH_206p 0x0f100003
1118#define PVR_ARCH_207 0x0f000004
1119
1109/* Macros for setting and retrieving special purpose registers */ 1120/* Macros for setting and retrieving special purpose registers */
1110#ifndef __ASSEMBLY__ 1121#ifndef __ASSEMBLY__
1111#define mfmsr() ({unsigned long rval; \ 1122#define mfmsr() ({unsigned long rval; \
diff --git a/arch/powerpc/include/uapi/asm/kvm.h b/arch/powerpc/include/uapi/asm/kvm.h
index fab6bc1f8e90..e420d46d363f 100644
--- a/arch/powerpc/include/uapi/asm/kvm.h
+++ b/arch/powerpc/include/uapi/asm/kvm.h
@@ -536,6 +536,9 @@ struct kvm_get_htab_header {
536#define KVM_REG_PPC_LPCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb5) 536#define KVM_REG_PPC_LPCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb5)
537#define KVM_REG_PPC_PPR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb6) 537#define KVM_REG_PPC_PPR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb6)
538 538
539/* Architecture compatibility level */
540#define KVM_REG_PPC_ARCH_COMPAT (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb7)
541
539/* Transactional Memory checkpointed state: 542/* Transactional Memory checkpointed state:
540 * This is all GPRs, all VSX regs and a subset of SPRs 543 * This is all GPRs, all VSX regs and a subset of SPRs
541 */ 544 */
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 5fda4ef489ad..5a285efba174 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -526,6 +526,7 @@ int main(void)
526 DEFINE(VCORE_NAPPING_THREADS, offsetof(struct kvmppc_vcore, napping_threads)); 526 DEFINE(VCORE_NAPPING_THREADS, offsetof(struct kvmppc_vcore, napping_threads));
527 DEFINE(VCORE_TB_OFFSET, offsetof(struct kvmppc_vcore, tb_offset)); 527 DEFINE(VCORE_TB_OFFSET, offsetof(struct kvmppc_vcore, tb_offset));
528 DEFINE(VCORE_LPCR, offsetof(struct kvmppc_vcore, lpcr)); 528 DEFINE(VCORE_LPCR, offsetof(struct kvmppc_vcore, lpcr));
529 DEFINE(VCORE_PCR, offsetof(struct kvmppc_vcore, pcr));
529 DEFINE(VCPU_SVCPU, offsetof(struct kvmppc_vcpu_book3s, shadow_vcpu) - 530 DEFINE(VCPU_SVCPU, offsetof(struct kvmppc_vcpu_book3s, shadow_vcpu) -
530 offsetof(struct kvmppc_vcpu_book3s, vcpu)); 531 offsetof(struct kvmppc_vcpu_book3s, vcpu));
531 DEFINE(VCPU_SLB_E, offsetof(struct kvmppc_slb, orige)); 532 DEFINE(VCPU_SLB_E, offsetof(struct kvmppc_slb, orige));
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 2a0e38feec1d..e42fb5448608 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -166,6 +166,35 @@ void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr)
166 vcpu->arch.pvr = pvr; 166 vcpu->arch.pvr = pvr;
167} 167}
168 168
169int kvmppc_set_arch_compat(struct kvm_vcpu *vcpu, u32 arch_compat)
170{
171 unsigned long pcr = 0;
172 struct kvmppc_vcore *vc = vcpu->arch.vcore;
173
174 if (arch_compat) {
175 if (!cpu_has_feature(CPU_FTR_ARCH_206))
176 return -EINVAL; /* 970 has no compat mode support */
177
178 switch (arch_compat) {
179 case PVR_ARCH_205:
180 pcr = PCR_ARCH_205;
181 break;
182 case PVR_ARCH_206:
183 case PVR_ARCH_206p:
184 break;
185 default:
186 return -EINVAL;
187 }
188 }
189
190 spin_lock(&vc->lock);
191 vc->arch_compat = arch_compat;
192 vc->pcr = pcr;
193 spin_unlock(&vc->lock);
194
195 return 0;
196}
197
169void kvmppc_dump_regs(struct kvm_vcpu *vcpu) 198void kvmppc_dump_regs(struct kvm_vcpu *vcpu)
170{ 199{
171 int r; 200 int r;
@@ -826,6 +855,9 @@ int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val)
826 case KVM_REG_PPC_PPR: 855 case KVM_REG_PPC_PPR:
827 *val = get_reg_val(id, vcpu->arch.ppr); 856 *val = get_reg_val(id, vcpu->arch.ppr);
828 break; 857 break;
858 case KVM_REG_PPC_ARCH_COMPAT:
859 *val = get_reg_val(id, vcpu->arch.vcore->arch_compat);
860 break;
829 default: 861 default:
830 r = -EINVAL; 862 r = -EINVAL;
831 break; 863 break;
@@ -936,6 +968,9 @@ int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val)
936 case KVM_REG_PPC_PPR: 968 case KVM_REG_PPC_PPR:
937 vcpu->arch.ppr = set_reg_val(id, *val); 969 vcpu->arch.ppr = set_reg_val(id, *val);
938 break; 970 break;
971 case KVM_REG_PPC_ARCH_COMPAT:
972 r = kvmppc_set_arch_compat(vcpu, set_reg_val(id, *val));
973 break;
939 default: 974 default:
940 r = -EINVAL; 975 r = -EINVAL;
941 break; 976 break;
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index a81979becf41..cd39632a646e 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -499,7 +499,13 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
499 addis r8,r8,0x100 /* if so, increment upper 40 bits */ 499 addis r8,r8,0x100 /* if so, increment upper 40 bits */
500 mtspr SPRN_TBU40,r8 500 mtspr SPRN_TBU40,r8
501 501
50237: li r0,1 502 /* Load guest PCR value to select appropriate compat mode */
50337: ld r7, VCORE_PCR(r5)
504 cmpdi r7, 0
505 beq 38f
506 mtspr SPRN_PCR, r7
50738:
508 li r0,1
503 stb r0,VCORE_IN_GUEST(r5) /* signal secondaries to continue */ 509 stb r0,VCORE_IN_GUEST(r5) /* signal secondaries to continue */
504 b 10f 510 b 10f
505 511
@@ -1094,8 +1100,14 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
1094 addis r8,r8,0x100 /* if so, increment upper 40 bits */ 1100 addis r8,r8,0x100 /* if so, increment upper 40 bits */
1095 mtspr SPRN_TBU40,r8 1101 mtspr SPRN_TBU40,r8
1096 1102
1103 /* Reset PCR */
110417: ld r0, VCORE_PCR(r5)
1105 cmpdi r0, 0
1106 beq 18f
1107 li r0, 0
1108 mtspr SPRN_PCR, r0
110918:
1097 /* Signal secondary CPUs to continue */ 1110 /* Signal secondary CPUs to continue */
109817: li r0,0
1099 stb r0,VCORE_IN_GUEST(r5) 1111 stb r0,VCORE_IN_GUEST(r5)
1100 lis r8,0x7fff /* MAX_INT@h */ 1112 lis r8,0x7fff /* MAX_INT@h */
1101 mtspr SPRN_HDEC,r8 1113 mtspr SPRN_HDEC,r8