static int kvm_arch_tsc_set_attr(struct kvm_vcpu *vcpu,
				 struct kvm_device_attr *attr)
{
	u64 __user *uaddr = kvm_get_attr_addr(attr);
	struct kvm *kvm = vcpu->kvm;
	int r;

	if (IS_ERR(uaddr))
		return PTR_ERR(uaddr);

	switch (attr->attr) {
	case KVM_VCPU_TSC_OFFSET: {
		u64 offset, tsc, ns;
		unsigned long flags;
		bool matched;

		r = -EFAULT;
		if (get_user(offset, uaddr))
			break;

		raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags);

		matched = (vcpu->arch.virtual_tsc_khz &&
			   kvm->arch.last_tsc_khz == vcpu->arch.virtual_tsc_khz &&
			   kvm->arch.last_tsc_offset == offset);

		tsc = kvm_scale_tsc(rdtsc(), vcpu->arch.l1_tsc_scaling_ratio) + offset;
		ns = get_kvmclock_base_ns();

		__kvm_synchronize_tsc(vcpu, offset, tsc, ns, matched);
		raw_spin_unlock_irqrestore(&kvm->arch.tsc_write_lock, flags);

		r = 0;
		break;
	}
	default:
		r = -ENXIO;
	}

	return r;
}
static int kvm_arch_tsc_set_attr(struct kvm_vcpu *vcpu,
				 struct kvm_device_attr *attr)
{
	u64 __user *uaddr = kvm_get_attr_addr(attr);
	struct kvm *kvm = vcpu->kvm;
	int r;

	if (IS_ERR(uaddr))
		return PTR_ERR(uaddr);

	switch (attr->attr) {
	case KVM_VCPU_TSC_OFFSET: {
		u64 offset, tsc, ns;
		unsigned long flags;
		bool matched;

		r = -EFAULT;
		if (get_user(offset, uaddr))
			break;

		raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags);

		matched = (vcpu->arch.virtual_tsc_khz &&
			   kvm->arch.last_tsc_khz == vcpu->arch.virtual_tsc_khz &&
			   kvm->arch.last_tsc_offset == offset);

		tsc = kvm_scale_tsc(rdtsc(), vcpu->arch.l1_tsc_scaling_ratio) + offset;
		ns = get_kvmclock_base_ns();

		__kvm_synchronize_tsc(vcpu, offset, tsc, ns, matched);
		raw_spin_unlock_irqrestore(&kvm->arch.tsc_write_lock, flags);

		r = 0;
		break;
	}
	default:
		r = -ENXIO;
	}

	return r;
}