aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/mips/include/asm/kvm_host.h1
-rw-r--r--arch/mips/include/uapi/asm/kvm.h7
-rw-r--r--arch/mips/kvm/kvm_mips.c3
-rw-r--r--arch/mips/kvm/kvm_mips_emul.c48
-rw-r--r--arch/mips/kvm/kvm_trap_emul.c6
5 files changed, 65 insertions, 0 deletions
diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h
index 1deeaecbe73e..f9c672f729ea 100644
--- a/arch/mips/include/asm/kvm_host.h
+++ b/arch/mips/include/asm/kvm_host.h
@@ -720,6 +720,7 @@ void kvm_mips_write_compare(struct kvm_vcpu *vcpu, uint32_t compare);
720void kvm_mips_init_count(struct kvm_vcpu *vcpu); 720void kvm_mips_init_count(struct kvm_vcpu *vcpu);
721int kvm_mips_set_count_ctl(struct kvm_vcpu *vcpu, s64 count_ctl); 721int kvm_mips_set_count_ctl(struct kvm_vcpu *vcpu, s64 count_ctl);
722int kvm_mips_set_count_resume(struct kvm_vcpu *vcpu, s64 count_resume); 722int kvm_mips_set_count_resume(struct kvm_vcpu *vcpu, s64 count_resume);
723int kvm_mips_set_count_hz(struct kvm_vcpu *vcpu, s64 count_hz);
723void kvm_mips_count_enable_cause(struct kvm_vcpu *vcpu); 724void kvm_mips_count_enable_cause(struct kvm_vcpu *vcpu);
724void kvm_mips_count_disable_cause(struct kvm_vcpu *vcpu); 725void kvm_mips_count_disable_cause(struct kvm_vcpu *vcpu);
725enum hrtimer_restart kvm_mips_count_timeout(struct kvm_vcpu *vcpu); 726enum hrtimer_restart kvm_mips_count_timeout(struct kvm_vcpu *vcpu);
diff --git a/arch/mips/include/uapi/asm/kvm.h b/arch/mips/include/uapi/asm/kvm.h
index f859fbada1f7..2c04b6d9ff85 100644
--- a/arch/mips/include/uapi/asm/kvm.h
+++ b/arch/mips/include/uapi/asm/kvm.h
@@ -133,6 +133,13 @@ struct kvm_fpu {
133 */ 133 */
134#define KVM_REG_MIPS_COUNT_RESUME (KVM_REG_MIPS | KVM_REG_SIZE_U64 | \ 134#define KVM_REG_MIPS_COUNT_RESUME (KVM_REG_MIPS | KVM_REG_SIZE_U64 | \
135 0x20000 | 1) 135 0x20000 | 1)
136/*
137 * CP0_Count rate in Hz
138 * Specifies the rate of the CP0_Count timer in Hz. Modifications occur without
139 * discontinuities in CP0_Count.
140 */
141#define KVM_REG_MIPS_COUNT_HZ (KVM_REG_MIPS | KVM_REG_SIZE_U64 | \
142 0x20000 | 2)
136 143
137/* 144/*
138 * KVM MIPS specific structures and definitions 145 * KVM MIPS specific structures and definitions
diff --git a/arch/mips/kvm/kvm_mips.c b/arch/mips/kvm/kvm_mips.c
index a2d5d4243f51..7ccb7a532c55 100644
--- a/arch/mips/kvm/kvm_mips.c
+++ b/arch/mips/kvm/kvm_mips.c
@@ -546,6 +546,7 @@ static u64 kvm_mips_get_one_regs[] = {
546 546
547 KVM_REG_MIPS_COUNT_CTL, 547 KVM_REG_MIPS_COUNT_CTL,
548 KVM_REG_MIPS_COUNT_RESUME, 548 KVM_REG_MIPS_COUNT_RESUME,
549 KVM_REG_MIPS_COUNT_HZ,
549}; 550};
550 551
551static int kvm_mips_get_reg(struct kvm_vcpu *vcpu, 552static int kvm_mips_get_reg(struct kvm_vcpu *vcpu,
@@ -627,6 +628,7 @@ static int kvm_mips_get_reg(struct kvm_vcpu *vcpu,
627 case KVM_REG_MIPS_CP0_COUNT: 628 case KVM_REG_MIPS_CP0_COUNT:
628 case KVM_REG_MIPS_COUNT_CTL: 629 case KVM_REG_MIPS_COUNT_CTL:
629 case KVM_REG_MIPS_COUNT_RESUME: 630 case KVM_REG_MIPS_COUNT_RESUME:
631 case KVM_REG_MIPS_COUNT_HZ:
630 ret = kvm_mips_callbacks->get_one_reg(vcpu, reg, &v); 632 ret = kvm_mips_callbacks->get_one_reg(vcpu, reg, &v);
631 if (ret) 633 if (ret)
632 return ret; 634 return ret;
@@ -724,6 +726,7 @@ static int kvm_mips_set_reg(struct kvm_vcpu *vcpu,
724 case KVM_REG_MIPS_CP0_CAUSE: 726 case KVM_REG_MIPS_CP0_CAUSE:
725 case KVM_REG_MIPS_COUNT_CTL: 727 case KVM_REG_MIPS_COUNT_CTL:
726 case KVM_REG_MIPS_COUNT_RESUME: 728 case KVM_REG_MIPS_COUNT_RESUME:
729 case KVM_REG_MIPS_COUNT_HZ:
727 return kvm_mips_callbacks->set_one_reg(vcpu, reg, v); 730 return kvm_mips_callbacks->set_one_reg(vcpu, reg, v);
728 default: 731 default:
729 return -EINVAL; 732 return -EINVAL;
diff --git a/arch/mips/kvm/kvm_mips_emul.c b/arch/mips/kvm/kvm_mips_emul.c
index 65c8dea6d1f5..6d257384c9b4 100644
--- a/arch/mips/kvm/kvm_mips_emul.c
+++ b/arch/mips/kvm/kvm_mips_emul.c
@@ -498,6 +498,54 @@ void kvm_mips_init_count(struct kvm_vcpu *vcpu)
498} 498}
499 499
500/** 500/**
501 * kvm_mips_set_count_hz() - Update the frequency of the timer.
502 * @vcpu: Virtual CPU.
503 * @count_hz: Frequency of CP0_Count timer in Hz.
504 *
505 * Change the frequency of the CP0_Count timer. This is done atomically so that
506 * CP0_Count is continuous and no timer interrupt is lost.
507 *
508 * Returns: -EINVAL if @count_hz is out of range.
509 * 0 on success.
510 */
511int kvm_mips_set_count_hz(struct kvm_vcpu *vcpu, s64 count_hz)
512{
513 struct mips_coproc *cop0 = vcpu->arch.cop0;
514 int dc;
515 ktime_t now;
516 u32 count;
517
518 /* ensure the frequency is in a sensible range... */
519 if (count_hz <= 0 || count_hz > NSEC_PER_SEC)
520 return -EINVAL;
521 /* ... and has actually changed */
522 if (vcpu->arch.count_hz == count_hz)
523 return 0;
524
525 /* Safely freeze timer so we can keep it continuous */
526 dc = kvm_mips_count_disabled(vcpu);
527 if (dc) {
528 now = kvm_mips_count_time(vcpu);
529 count = kvm_read_c0_guest_count(cop0);
530 } else {
531 now = kvm_mips_freeze_hrtimer(vcpu, &count);
532 }
533
534 /* Update the frequency */
535 vcpu->arch.count_hz = count_hz;
536 vcpu->arch.count_period = div_u64((u64)NSEC_PER_SEC << 32, count_hz);
537 vcpu->arch.count_dyn_bias = 0;
538
539 /* Calculate adjusted bias so dynamic count is unchanged */
540 vcpu->arch.count_bias = count - kvm_mips_ktime_to_count(vcpu, now);
541
542 /* Update and resume hrtimer */
543 if (!dc)
544 kvm_mips_resume_hrtimer(vcpu, now, count);
545 return 0;
546}
547
548/**
501 * kvm_mips_write_compare() - Modify compare and update timer. 549 * kvm_mips_write_compare() - Modify compare and update timer.
502 * @vcpu: Virtual CPU. 550 * @vcpu: Virtual CPU.
503 * @compare: New CP0_Compare value. 551 * @compare: New CP0_Compare value.
diff --git a/arch/mips/kvm/kvm_trap_emul.c b/arch/mips/kvm/kvm_trap_emul.c
index 854502bcc749..b171db324cf0 100644
--- a/arch/mips/kvm/kvm_trap_emul.c
+++ b/arch/mips/kvm/kvm_trap_emul.c
@@ -415,6 +415,9 @@ static int kvm_trap_emul_get_one_reg(struct kvm_vcpu *vcpu,
415 case KVM_REG_MIPS_COUNT_RESUME: 415 case KVM_REG_MIPS_COUNT_RESUME:
416 *v = ktime_to_ns(vcpu->arch.count_resume); 416 *v = ktime_to_ns(vcpu->arch.count_resume);
417 break; 417 break;
418 case KVM_REG_MIPS_COUNT_HZ:
419 *v = vcpu->arch.count_hz;
420 break;
418 default: 421 default:
419 return -EINVAL; 422 return -EINVAL;
420 } 423 }
@@ -461,6 +464,9 @@ static int kvm_trap_emul_set_one_reg(struct kvm_vcpu *vcpu,
461 case KVM_REG_MIPS_COUNT_RESUME: 464 case KVM_REG_MIPS_COUNT_RESUME:
462 ret = kvm_mips_set_count_resume(vcpu, v); 465 ret = kvm_mips_set_count_resume(vcpu, v);
463 break; 466 break;
467 case KVM_REG_MIPS_COUNT_HZ:
468 ret = kvm_mips_set_count_hz(vcpu, v);
469 break;
464 default: 470 default:
465 return -EINVAL; 471 return -EINVAL;
466 } 472 }