aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2013-09-05 23:17:46 -0400
committerAlexander Graf <agraf@suse.de>2013-10-17 08:44:59 -0400
commit93b0f4dc29c5f077a1c97bd1d484147230c3779a (patch)
tree29a0e8bb164c461d26abc4aeaae8504b2ddc296b
parent14941789f2a13cd89e2dd567c4f708e571ab714e (diff)
KVM: PPC: Book3S HV: Implement timebase offset for guests
This allows guests to have a different timebase origin from the host. This is needed for migration, where a guest can migrate from one host to another and the two hosts might have a different timebase origin. However, the timebase seen by the guest must not go backwards, and should go forwards only by a small amount corresponding to the time taken for the migration. Therefore this provides a new per-vcpu value accessed via the one_reg interface using the new KVM_REG_PPC_TB_OFFSET identifier. This value defaults to 0 and is not modified by KVM. On entering the guest, this value is added onto the timebase, and on exiting the guest, it is subtracted from the timebase. This is only supported for recent POWER hardware which has the TBU40 (timebase upper 40 bits) register. Writing to the TBU40 register only alters the upper 40 bits of the timebase, leaving the lower 24 bits unchanged. This provides a way to modify the timebase for guest migration without disturbing the synchronization of the timebase registers across CPU cores. The kernel rounds up the value given to a multiple of 2^24. Timebase values stored in KVM structures (struct kvm_vcpu, struct kvmppc_vcore, etc.) are stored as host timebase values. The timebase values in the dispatch trace log need to be guest timebase values, however, since that is read directly by the guest. This moves the setting of vcpu->arch.dec_expires on guest exit to a point after we have restored the host timebase so that vcpu->arch.dec_expires is a host timebase value. 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_host.h1
-rw-r--r--arch/powerpc/include/asm/reg.h1
-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.c10
-rw-r--r--arch/powerpc/kvm/book3s_hv_rmhandlers.S50
7 files changed, 57 insertions, 10 deletions
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 354a51ba456b..e43c6f14c225 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -1810,6 +1810,7 @@ registers, find a list below:
1810 PPC | KVM_REG_PPC_TLB3PS | 32 1810 PPC | KVM_REG_PPC_TLB3PS | 32
1811 PPC | KVM_REG_PPC_EPTCFG | 32 1811 PPC | KVM_REG_PPC_EPTCFG | 32
1812 PPC | KVM_REG_PPC_ICP_STATE | 64 1812 PPC | KVM_REG_PPC_ICP_STATE | 64
1813 PPC | KVM_REG_PPC_TB_OFFSET | 64
1813 PPC | KVM_REG_PPC_SPMC1 | 32 1814 PPC | KVM_REG_PPC_SPMC1 | 32
1814 PPC | KVM_REG_PPC_SPMC2 | 32 1815 PPC | KVM_REG_PPC_SPMC2 | 32
1815 PPC | KVM_REG_PPC_IAMR | 64 1816 PPC | KVM_REG_PPC_IAMR | 64
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index d9b21af62610..e4d67a606e43 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -289,6 +289,7 @@ struct kvmppc_vcore {
289 u64 stolen_tb; 289 u64 stolen_tb;
290 u64 preempt_tb; 290 u64 preempt_tb;
291 struct kvm_vcpu *runner; 291 struct kvm_vcpu *runner;
292 u64 tb_offset; /* guest timebase - host timebase */
292}; 293};
293 294
294#define VCORE_ENTRY_COUNT(vc) ((vc)->entry_exit_count & 0xff) 295#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 10d1ef016bf1..fd4db15e6f2a 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -243,6 +243,7 @@
243#define SPRN_TBRU 0x10D /* Time Base Read Upper Register (user, R/O) */ 243#define SPRN_TBRU 0x10D /* Time Base Read Upper Register (user, R/O) */
244#define SPRN_TBWL 0x11C /* Time Base Lower Register (super, R/W) */ 244#define SPRN_TBWL 0x11C /* Time Base Lower Register (super, R/W) */
245#define SPRN_TBWU 0x11D /* Time Base Upper Register (super, R/W) */ 245#define SPRN_TBWU 0x11D /* Time Base Upper Register (super, R/W) */
246#define SPRN_TBU40 0x11E /* Timebase upper 40 bits (hyper, R/W) */
246#define SPRN_SPURR 0x134 /* Scaled PURR */ 247#define SPRN_SPURR 0x134 /* Scaled PURR */
247#define SPRN_HSPRG0 0x130 /* Hypervisor Scratch 0 */ 248#define SPRN_HSPRG0 0x130 /* Hypervisor Scratch 0 */
248#define SPRN_HSPRG1 0x131 /* Hypervisor Scratch 1 */ 249#define SPRN_HSPRG1 0x131 /* Hypervisor Scratch 1 */
diff --git a/arch/powerpc/include/uapi/asm/kvm.h b/arch/powerpc/include/uapi/asm/kvm.h
index 7ed41c0b4045..a8124fe93fb9 100644
--- a/arch/powerpc/include/uapi/asm/kvm.h
+++ b/arch/powerpc/include/uapi/asm/kvm.h
@@ -504,6 +504,9 @@ struct kvm_get_htab_header {
504#define KVM_REG_PPC_TLB3PS (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x9a) 504#define KVM_REG_PPC_TLB3PS (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x9a)
505#define KVM_REG_PPC_EPTCFG (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x9b) 505#define KVM_REG_PPC_EPTCFG (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x9b)
506 506
507/* Timebase offset */
508#define KVM_REG_PPC_TB_OFFSET (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x9c)
509
507/* POWER8 registers */ 510/* POWER8 registers */
508#define KVM_REG_PPC_SPMC1 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x9d) 511#define KVM_REG_PPC_SPMC1 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x9d)
509#define KVM_REG_PPC_SPMC2 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x9e) 512#define KVM_REG_PPC_SPMC2 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x9e)
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 19e699d747b7..34d63d871917 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -523,6 +523,7 @@ int main(void)
523 DEFINE(VCORE_NAP_COUNT, offsetof(struct kvmppc_vcore, nap_count)); 523 DEFINE(VCORE_NAP_COUNT, offsetof(struct kvmppc_vcore, nap_count));
524 DEFINE(VCORE_IN_GUEST, offsetof(struct kvmppc_vcore, in_guest)); 524 DEFINE(VCORE_IN_GUEST, offsetof(struct kvmppc_vcore, in_guest));
525 DEFINE(VCORE_NAPPING_THREADS, offsetof(struct kvmppc_vcore, napping_threads)); 525 DEFINE(VCORE_NAPPING_THREADS, offsetof(struct kvmppc_vcore, napping_threads));
526 DEFINE(VCORE_TB_OFFSET, offsetof(struct kvmppc_vcore, tb_offset));
526 DEFINE(VCPU_SVCPU, offsetof(struct kvmppc_vcpu_book3s, shadow_vcpu) - 527 DEFINE(VCPU_SVCPU, offsetof(struct kvmppc_vcpu_book3s, shadow_vcpu) -
527 offsetof(struct kvmppc_vcpu_book3s, vcpu)); 528 offsetof(struct kvmppc_vcpu_book3s, vcpu));
528 DEFINE(VCPU_SLB_E, offsetof(struct kvmppc_slb, orige)); 529 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 45a9b876b0a0..56f57af7e738 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -489,7 +489,7 @@ static void kvmppc_create_dtl_entry(struct kvm_vcpu *vcpu,
489 memset(dt, 0, sizeof(struct dtl_entry)); 489 memset(dt, 0, sizeof(struct dtl_entry));
490 dt->dispatch_reason = 7; 490 dt->dispatch_reason = 7;
491 dt->processor_id = vc->pcpu + vcpu->arch.ptid; 491 dt->processor_id = vc->pcpu + vcpu->arch.ptid;
492 dt->timebase = now; 492 dt->timebase = now + vc->tb_offset;
493 dt->enqueue_to_dispatch_time = stolen; 493 dt->enqueue_to_dispatch_time = stolen;
494 dt->srr0 = kvmppc_get_pc(vcpu); 494 dt->srr0 = kvmppc_get_pc(vcpu);
495 dt->srr1 = vcpu->arch.shregs.msr; 495 dt->srr1 = vcpu->arch.shregs.msr;
@@ -793,6 +793,9 @@ int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val)
793 val->vpaval.length = vcpu->arch.dtl.len; 793 val->vpaval.length = vcpu->arch.dtl.len;
794 spin_unlock(&vcpu->arch.vpa_update_lock); 794 spin_unlock(&vcpu->arch.vpa_update_lock);
795 break; 795 break;
796 case KVM_REG_PPC_TB_OFFSET:
797 *val = get_reg_val(id, vcpu->arch.vcore->tb_offset);
798 break;
796 default: 799 default:
797 r = -EINVAL; 800 r = -EINVAL;
798 break; 801 break;
@@ -892,6 +895,11 @@ int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val)
892 len -= len % sizeof(struct dtl_entry); 895 len -= len % sizeof(struct dtl_entry);
893 r = set_vpa(vcpu, &vcpu->arch.dtl, addr, len); 896 r = set_vpa(vcpu, &vcpu->arch.dtl, addr, len);
894 break; 897 break;
898 case KVM_REG_PPC_TB_OFFSET:
899 /* round up to multiple of 2^24 */
900 vcpu->arch.vcore->tb_offset =
901 ALIGN(set_reg_val(id, *val), 1UL << 24);
902 break;
895 default: 903 default:
896 r = -EINVAL; 904 r = -EINVAL;
897 break; 905 break;
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index 541aea0ce91a..82b06dfe2d27 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -347,7 +347,22 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
347 bdnz 28b 347 bdnz 28b
348 ptesync 348 ptesync
349 349
35022: li r0,1 350 /* Add timebase offset onto timebase */
35122: ld r8,VCORE_TB_OFFSET(r5)
352 cmpdi r8,0
353 beq 37f
354 mftb r6 /* current host timebase */
355 add r8,r8,r6
356 mtspr SPRN_TBU40,r8 /* update upper 40 bits */
357 mftb r7 /* check if lower 24 bits overflowed */
358 clrldi r6,r6,40
359 clrldi r7,r7,40
360 cmpld r7,r6
361 bge 37f
362 addis r8,r8,0x100 /* if so, increment upper 40 bits */
363 mtspr SPRN_TBU40,r8
364
36537: li r0,1
351 stb r0,VCORE_IN_GUEST(r5) /* signal secondaries to continue */ 366 stb r0,VCORE_IN_GUEST(r5) /* signal secondaries to continue */
352 b 10f 367 b 10f
353 368
@@ -782,13 +797,6 @@ ext_stash_for_host:
782ext_interrupt_to_host: 797ext_interrupt_to_host:
783 798
784guest_exit_cont: /* r9 = vcpu, r12 = trap, r13 = paca */ 799guest_exit_cont: /* r9 = vcpu, r12 = trap, r13 = paca */
785 /* Save DEC */
786 mfspr r5,SPRN_DEC
787 mftb r6
788 extsw r5,r5
789 add r5,r5,r6
790 std r5,VCPU_DEC_EXPIRES(r9)
791
792 /* Save more register state */ 800 /* Save more register state */
793 mfdar r6 801 mfdar r6
794 mfdsisr r7 802 mfdsisr r7
@@ -958,7 +966,24 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
958 mtspr SPRN_SDR1,r6 /* switch to partition page table */ 966 mtspr SPRN_SDR1,r6 /* switch to partition page table */
959 mtspr SPRN_LPID,r7 967 mtspr SPRN_LPID,r7
960 isync 968 isync
961 li r0,0 969
970 /* Subtract timebase offset from timebase */
971 ld r8,VCORE_TB_OFFSET(r5)
972 cmpdi r8,0
973 beq 17f
974 mftb r6 /* current host timebase */
975 subf r8,r8,r6
976 mtspr SPRN_TBU40,r8 /* update upper 40 bits */
977 mftb r7 /* check if lower 24 bits overflowed */
978 clrldi r6,r6,40
979 clrldi r7,r7,40
980 cmpld r7,r6
981 bge 17f
982 addis r8,r8,0x100 /* if so, increment upper 40 bits */
983 mtspr SPRN_TBU40,r8
984
985 /* Signal secondary CPUs to continue */
98617: li r0,0
962 stb r0,VCORE_IN_GUEST(r5) 987 stb r0,VCORE_IN_GUEST(r5)
963 lis r8,0x7fff /* MAX_INT@h */ 988 lis r8,0x7fff /* MAX_INT@h */
964 mtspr SPRN_HDEC,r8 989 mtspr SPRN_HDEC,r8
@@ -1056,6 +1081,13 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
10561: addi r8,r8,16 10811: addi r8,r8,16
1057 .endr 1082 .endr
1058 1083
1084 /* Save DEC */
1085 mfspr r5,SPRN_DEC
1086 mftb r6
1087 extsw r5,r5
1088 add r5,r5,r6
1089 std r5,VCPU_DEC_EXPIRES(r9)
1090
1059 /* Save and reset AMR and UAMOR before turning on the MMU */ 1091 /* Save and reset AMR and UAMOR before turning on the MMU */
1060BEGIN_FTR_SECTION 1092BEGIN_FTR_SECTION
1061 mfspr r5,SPRN_AMR 1093 mfspr r5,SPRN_AMR