diff options
Diffstat (limited to 'arch/mips/kvm/kvm_mips_emul.c')
-rw-r--r-- | arch/mips/kvm/kvm_mips_emul.c | 48 |
1 files changed, 48 insertions, 0 deletions
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 | */ | ||
511 | int 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. |