diff mbox

[5/5] HPET interaction with in-kernel PIT (v6)

Message ID 1244771206-19872-5-git-send-email-eak@us.ibm.com (mailing list archive)
State New, archived
Headers show

Commit Message

Beth Kon June 12, 2009, 1:46 a.m. UTC
Signed-off-by: Beth Kon <eak@us.ibm.com>

---
 arch/x86/include/asm/kvm.h |    1 +
 arch/x86/kvm/i8254.c       |   24 +++++++++++++++++++-----
 arch/x86/kvm/i8254.h       |    3 ++-
 arch/x86/kvm/x86.c         |    5 ++++-
 4 files changed, 26 insertions(+), 7 deletions(-)

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Avi Kivity June 14, 2009, 8:53 a.m. UTC | #1
Beth Kon wrote:
> Signed-off-by: Beth Kon <eak@us.ibm.com>
>
>   

Please write a few words on what this patch does and why.

> ---
>  arch/x86/include/asm/kvm.h |    1 +
>  arch/x86/kvm/i8254.c       |   24 +++++++++++++++++++-----
>  arch/x86/kvm/i8254.h       |    3 ++-
>  arch/x86/kvm/x86.c         |    5 ++++-
>  4 files changed, 26 insertions(+), 7 deletions(-)
>
> diff --git a/arch/x86/include/asm/kvm.h b/arch/x86/include/asm/kvm.h
> index 708b9c3..3c44923 100644
> --- a/arch/x86/include/asm/kvm.h
> +++ b/arch/x86/include/asm/kvm.h
> @@ -235,6 +235,7 @@ struct kvm_guest_debug_arch {
>  
>  struct kvm_pit_state {
>  	struct kvm_pit_channel_state channels[3];
> +	u8 hpet_legacy_mode;
>  };
>   

This changes the ABI, breaking older binaries running on newer kernels, 
or newer binaries running on older kernels.

> @@ -340,10 +340,20 @@ static void pit_load_count(struct kvm *kvm, int channel, u32 val)
>  	}
>  }
>  
> -void kvm_pit_load_count(struct kvm *kvm, int channel, u32 val)
> +void kvm_pit_load_count(struct kvm *kvm, int channel, u32 val, int hpet_legacy_start)
>  {
> +	u8 saved_mode;
>  	mutex_lock(&kvm->arch.vpit->pit_state.lock);
> -	pit_load_count(kvm, channel, val);
> +	if (hpet_legacy_start) {
> +		/* save existing mode for later reenablement */
> +		saved_mode = kvm->arch.vpit->pit_state.channels[0].mode;
> +		kvm->arch.vpit->pit_state.channels[0].mode = 0xff; /* disable timer */
> +		pit_load_count(kvm, channel, val);
> +		kvm->arch.vpit->pit_state.channels[0].mode = saved_mode;
> +	} else {
> +			if (!(channel == 0 && kvm->arch.vpit->pit_state.hpet_legacy_mode))
> +			pit_load_count(kvm, channel, val);
>   

Overindented.
Jan Kiszka June 14, 2009, 9:10 a.m. UTC | #2
Avi Kivity wrote:
> Beth Kon wrote:
>> Signed-off-by: Beth Kon <eak@us.ibm.com>
>>
>>   
> 
> Please write a few words on what this patch does and why.
> 
>> ---
>>  arch/x86/include/asm/kvm.h |    1 +
>>  arch/x86/kvm/i8254.c       |   24 +++++++++++++++++++-----
>>  arch/x86/kvm/i8254.h       |    3 ++-
>>  arch/x86/kvm/x86.c         |    5 ++++-
>>  4 files changed, 26 insertions(+), 7 deletions(-)
>>
>> diff --git a/arch/x86/include/asm/kvm.h b/arch/x86/include/asm/kvm.h
>> index 708b9c3..3c44923 100644
>> --- a/arch/x86/include/asm/kvm.h
>> +++ b/arch/x86/include/asm/kvm.h
>> @@ -235,6 +235,7 @@ struct kvm_guest_debug_arch {
>>  
>>  struct kvm_pit_state {
>>      struct kvm_pit_channel_state channels[3];
>> +    u8 hpet_legacy_mode;
>>  };
>>   
> 
> This changes the ABI, breaking older binaries running on newer kernels,
> or newer binaries running on older kernels.

As we have KVM_CREATE_PIT2 now, which includes struct kvm_pit_config
with a lot of unused flags, it should be straightforward to negotiate
the kvm_pit_state format between kernel and user space: kernel
advertises support for the new one via capability, user space requests
it via a bit in kvm_pit_state.flags.

Jan
Avi Kivity June 14, 2009, 9:18 a.m. UTC | #3
Jan Kiszka wrote:
>>>  
>>>  struct kvm_pit_state {
>>>      struct kvm_pit_channel_state channels[3];
>>> +    u8 hpet_legacy_mode;
>>>  };
>>>   
>>>       
>> This changes the ABI, breaking older binaries running on newer kernels,
>> or newer binaries running on older kernels.
>>     
>
> As we have KVM_CREATE_PIT2 now, which includes struct kvm_pit_config
> with a lot of unused flags, it should be straightforward to negotiate
> the kvm_pit_state format between kernel and user space: kernel
> advertises support for the new one via capability, user space requests
> it via a bit in kvm_pit_state.flags.
>   

We still need a new ioctl.  The structure size is embedded in the ioctl 
number, so any additions automatically cause version mismatches.

I sent patches some time ago to have the kernel automatically adjust for 
this, but they weren't well received.
Jan Kiszka June 14, 2009, 9:26 a.m. UTC | #4
Avi Kivity wrote:
> Jan Kiszka wrote:
>>>>  
>>>>  struct kvm_pit_state {
>>>>      struct kvm_pit_channel_state channels[3];
>>>> +    u8 hpet_legacy_mode;
>>>>  };
>>>>         
>>> This changes the ABI, breaking older binaries running on newer kernels,
>>> or newer binaries running on older kernels.
>>>     
>>
>> As we have KVM_CREATE_PIT2 now, which includes struct kvm_pit_config
>> with a lot of unused flags, it should be straightforward to negotiate
>> the kvm_pit_state format between kernel and user space: kernel
>> advertises support for the new one via capability, user space requests
>> it via a bit in kvm_pit_state.flags.
>>   
> 
> We still need a new ioctl.  The structure size is embedded in the ioctl
> number, so any additions automatically cause version mismatches.
> 
> I sent patches some time ago to have the kernel automatically adjust for
> this, but they weren't well received.

Unfortunate. But on the one hand, nothing technically prevents defining
the IOCTL base on existing kvm_pit_state, but passing down extended
kvm_pit_state2 if that negotiation took place. On the other hand, we are
not yet running out of IOCTL numbers...

However, I guess kvm_pit_state2 will also need some flags field and a
bit tail room for potential future extensions.

Jan
Avi Kivity June 14, 2009, 9:35 a.m. UTC | #5
Jan Kiszka wrote:
> Unfortunate. But on the one hand, nothing technically prevents defining
> the IOCTL base on existing kvm_pit_state, but passing down extended
> kvm_pit_state2 if that negotiation took place. On the other hand, we are
> not yet running out of IOCTL numbers...
>   

Right, and we are not in any competition for most obfuscated interface 
yet (though we'd probably get an honourable mention if we were to apply).

> However, I guess kvm_pit_state2 will also need some flags field and a
> bit tail room for potential future extensions.
>   

Yes, it's a common pattern in kvm.
diff mbox

Patch

diff --git a/arch/x86/include/asm/kvm.h b/arch/x86/include/asm/kvm.h
index 708b9c3..3c44923 100644
--- a/arch/x86/include/asm/kvm.h
+++ b/arch/x86/include/asm/kvm.h
@@ -235,6 +235,7 @@  struct kvm_guest_debug_arch {
 
 struct kvm_pit_state {
 	struct kvm_pit_channel_state channels[3];
+	u8 hpet_legacy_mode;
 };
 
 struct kvm_reinject_control {
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c
index 331705f..bb8382b 100644
--- a/arch/x86/kvm/i8254.c
+++ b/arch/x86/kvm/i8254.c
@@ -340,10 +340,20 @@  static void pit_load_count(struct kvm *kvm, int channel, u32 val)
 	}
 }
 
-void kvm_pit_load_count(struct kvm *kvm, int channel, u32 val)
+void kvm_pit_load_count(struct kvm *kvm, int channel, u32 val, int hpet_legacy_start)
 {
+	u8 saved_mode;
 	mutex_lock(&kvm->arch.vpit->pit_state.lock);
-	pit_load_count(kvm, channel, val);
+	if (hpet_legacy_start) {
+		/* save existing mode for later reenablement */
+		saved_mode = kvm->arch.vpit->pit_state.channels[0].mode;
+		kvm->arch.vpit->pit_state.channels[0].mode = 0xff; /* disable timer */
+		pit_load_count(kvm, channel, val);
+		kvm->arch.vpit->pit_state.channels[0].mode = saved_mode;
+	} else {
+			if (!(channel == 0 && kvm->arch.vpit->pit_state.hpet_legacy_mode))
+			pit_load_count(kvm, channel, val);
+	}
 	mutex_unlock(&kvm->arch.vpit->pit_state.lock);
 }
 
@@ -411,17 +421,20 @@  static void pit_ioport_write(struct kvm_io_device *this,
 		switch (s->write_state) {
 		default:
 		case RW_STATE_LSB:
-			pit_load_count(kvm, addr, val);
+			if (!(addr == 0 && pit_state->hpet_legacy_mode))
+				pit_load_count(kvm, addr, val);
 			break;
 		case RW_STATE_MSB:
-			pit_load_count(kvm, addr, val << 8);
+			if (!(addr == 0 && pit_state->hpet_legacy_mode))
+				pit_load_count(kvm, addr, val << 8);
 			break;
 		case RW_STATE_WORD0:
 			s->write_latch = val;
 			s->write_state = RW_STATE_WORD1;
 			break;
 		case RW_STATE_WORD1:
-			pit_load_count(kvm, addr, s->write_latch | (val << 8));
+			if (!(addr == 0 && pit_state->hpet_legacy_mode))
+				pit_load_count(kvm, addr, s->write_latch | (val << 8));
 			s->write_state = RW_STATE_WORD0;
 			break;
 		}
@@ -548,6 +561,7 @@  void kvm_pit_reset(struct kvm_pit *pit)
 	struct kvm_kpit_channel_state *c;
 
 	mutex_lock(&pit->pit_state.lock);
+	pit->pit_state.hpet_legacy_mode = 0;
 	for (i = 0; i < 3; i++) {
 		c = &pit->pit_state.channels[i];
 		c->mode = 0xff;
diff --git a/arch/x86/kvm/i8254.h b/arch/x86/kvm/i8254.h
index b267018..b5967ca 100644
--- a/arch/x86/kvm/i8254.h
+++ b/arch/x86/kvm/i8254.h
@@ -21,6 +21,7 @@  struct kvm_kpit_channel_state {
 
 struct kvm_kpit_state {
 	struct kvm_kpit_channel_state channels[3];
+	u8 hpet_legacy_mode;
 	struct kvm_timer pit_timer;
 	bool is_periodic;
 	u32    speaker_data_on;
@@ -49,7 +50,7 @@  struct kvm_pit {
 #define KVM_PIT_CHANNEL_MASK	    0x3
 
 void kvm_inject_pit_timer_irqs(struct kvm_vcpu *vcpu);
-void kvm_pit_load_count(struct kvm *kvm, int channel, u32 val);
+void kvm_pit_load_count(struct kvm *kvm, int channel, u32 val, int hpet_legacy_start);
 struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags);
 void kvm_free_pit(struct kvm *kvm);
 void kvm_pit_reset(struct kvm_pit *pit);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 1b91ea7..3c70545 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1948,9 +1948,12 @@  static int kvm_vm_ioctl_get_pit(struct kvm *kvm, struct kvm_pit_state *ps)
 static int kvm_vm_ioctl_set_pit(struct kvm *kvm, struct kvm_pit_state *ps)
 {
 	int r = 0;
+	int hpet_legacy_start = 0;
 
+	if (ps->hpet_legacy_mode && !kvm->arch.vpit->pit_state.hpet_legacy_mode)
+		hpet_legacy_start = 1;
 	memcpy(&kvm->arch.vpit->pit_state, ps, sizeof(struct kvm_pit_state));
-	kvm_pit_load_count(kvm, 0, ps->channels[0].count);
+	kvm_pit_load_count(kvm, 0, ps->channels[0].count, hpet_legacy_start);
 	return r;
 }