From patchwork Thu May 14 20:43:05 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kiszka X-Patchwork-Id: 23836 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n4EKiJMp032651 for ; Thu, 14 May 2009 20:44:19 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755883AbZENUoM (ORCPT ); Thu, 14 May 2009 16:44:12 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1755368AbZENUoL (ORCPT ); Thu, 14 May 2009 16:44:11 -0400 Received: from fmmailgate01.web.de ([217.72.192.221]:43632 "EHLO fmmailgate01.web.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754972AbZENUoK (ORCPT ); Thu, 14 May 2009 16:44:10 -0400 Received: from smtp07.web.de (fmsmtp07.dlan.cinetic.de [172.20.5.215]) by fmmailgate01.web.de (Postfix) with ESMTP id 5E1861021138D; Thu, 14 May 2009 22:43:06 +0200 (CEST) Received: from [88.64.19.145] (helo=[192.168.1.3]) by smtp07.web.de with asmtp (TLSv1:AES256-SHA:256) (WEB.DE 4.110 #277) id 1M4hli-0000SR-00; Thu, 14 May 2009 22:43:06 +0200 Message-ID: <4A0C8259.4010701@web.de> Date: Thu, 14 May 2009 22:43:05 +0200 From: Jan Kiszka User-Agent: Mozilla/5.0 (X11; U; Linux i686 (x86_64); de; rv:1.8.1.12) Gecko/20080226 SUSE/2.0.0.12-1.1 Thunderbird/2.0.0.12 Mnenhy/0.7.5.666 MIME-Version: 1.0 To: Avi Kivity CC: kvm-devel Subject: [PATCH v4] qemu-kvm: Make PC speaker emulation aware of in-kernel PIT References: <4A092506.9090308@web.de> <4A09F0F9.7080804@web.de> In-Reply-To: <4A09F0F9.7080804@web.de> X-Enigmail-Version: 0.95.7 X-Sender: jan.kiszka@web.de X-Provags-ID: V01U2FsdGVkX19mVuwK/UAfdGEC5gAgpIuMp2hY8VMy/7V65WUu PQZz99FxYdnLlKZ48VipH+2BJuvHYGcATUnGgG75l9dQVxwqE9 fsNo0zPGo= Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org When using the in-kernel PIT the speaker emulation has to synchronize the PIT state with KVM. Enhance the existing speaker sound device and allow it to take over port 0x61 by using KVM_CREATE_PIT2 where available. This unbreaks -soundhw pcspk in KVM mode. Changes in v4: - preserve full PIT state across read-modify-write - update kvm.h Changes in v3: - re-added incorrectly dropped kvm_enabled checks Changes in v2: - rebased over qemu-kvm and KVM_CREATE_PIT2 - refactored hooks in pcspk Signed-off-by: Jan Kiszka --- hw/pcspk.c | 48 ++++++++++++++++++++++++++++++++++++++++ kvm/kernel/include/linux/kvm.h | 10 ++++++++ kvm/libkvm/libkvm-x86.c | 26 +++++++++++++++------- 3 files changed, 76 insertions(+), 8 deletions(-) diff --git a/hw/pcspk.c b/hw/pcspk.c index ec1d0c6..c0b8347 100644 --- a/hw/pcspk.c +++ b/hw/pcspk.c @@ -27,6 +27,8 @@ #include "isa.h" #include "audio/audio.h" #include "qemu-timer.h" +#include "i8254.h" +#include "qemu-kvm.h" #define PCSPK_BUF_LEN 1792 #define PCSPK_SAMPLE_RATE 32000 @@ -48,6 +50,43 @@ typedef struct { static const char *s_spk = "pcspk"; static PCSpkState pcspk_state; +#ifdef USE_KVM_PIT +static void kvm_get_pit_ch2(PITState *pit, + struct kvm_pit_state *inkernel_state) +{ + struct kvm_pit_state pit_state; + + if (kvm_enabled() && qemu_kvm_pit_in_kernel()) { + kvm_get_pit(kvm_context, &pit_state); + pit->channels[2].mode = pit_state.channels[2].mode; + pit->channels[2].count = pit_state.channels[2].count; + pit->channels[2].count_load_time = pit_state.channels[2].count_load_time; + pit->channels[2].gate = pit_state.channels[2].gate; + if (inkernel_state) { + memcpy(inkernel_state, &pit_state, sizeof(*inkernel_state)); + } + } +} + +static void kvm_set_pit_ch2(PITState *pit, + struct kvm_pit_state *inkernel_state) +{ + if (kvm_enabled() && qemu_kvm_pit_in_kernel()) { + inkernel_state->channels[2].mode = pit->channels[2].mode; + inkernel_state->channels[2].count = pit->channels[2].count; + inkernel_state->channels[2].count_load_time = + pit->channels[2].count_load_time; + inkernel_state->channels[2].gate = pit->channels[2].gate; + kvm_set_pit(kvm_context, inkernel_state); + } +} +#else +static inline void kvm_get_pit_ch2(PITState *pit, + kvm_pit_state *inkernel_state) { } +static inline void kvm_set_pit_ch2(PITState *pit, + kvm_pit_state *inkernel_state) { } +#endif + static inline void generate_samples(PCSpkState *s) { unsigned int i; @@ -72,6 +111,8 @@ static void pcspk_callback(void *opaque, int free) PCSpkState *s = opaque; unsigned int n; + kvm_get_pit_ch2(s->pit, NULL); + if (pit_get_mode(s->pit, 2) != 3) return; @@ -121,6 +162,8 @@ static uint32_t pcspk_ioport_read(void *opaque, uint32_t addr) PCSpkState *s = opaque; int out; + kvm_get_pit_ch2(s->pit, NULL); + s->dummy_refresh_clock ^= (1 << 4); out = pit_get_out(s->pit, 2, qemu_get_clock(vm_clock)) << 5; @@ -129,9 +172,12 @@ static uint32_t pcspk_ioport_read(void *opaque, uint32_t addr) static void pcspk_ioport_write(void *opaque, uint32_t addr, uint32_t val) { + struct kvm_pit_state inkernel_state; PCSpkState *s = opaque; const int gate = val & 1; + kvm_get_pit_ch2(s->pit, &inkernel_state); + s->data_on = (val >> 1) & 1; pit_set_gate(s->pit, 2, gate); if (s->voice) { @@ -139,6 +185,8 @@ static void pcspk_ioport_write(void *opaque, uint32_t addr, uint32_t val) s->play_pos = 0; AUD_set_active_out(s->voice, gate & s->data_on); } + + kvm_set_pit_ch2(s->pit, &inkernel_state); } void pcspk_init(PITState *pit) diff --git a/kvm/kernel/include/linux/kvm.h b/kvm/kernel/include/linux/kvm.h index f5e9d66..5b4b90c 100644 --- a/kvm/kernel/include/linux/kvm.h +++ b/kvm/kernel/include/linux/kvm.h @@ -110,6 +110,14 @@ struct kvm_irqchip { } chip; }; +/* for KVM_CREATE_PIT2 */ +struct kvm_pit_config { + __u32 flags; + __u32 pad[15]; +}; + +#define KVM_PIT_SPEAKER_DUMMY 1 + #define KVM_EXIT_UNKNOWN 0 #define KVM_EXIT_EXCEPTION 1 #define KVM_EXIT_IO 2 @@ -455,6 +463,7 @@ struct kvm_trace_rec { #define KVM_CAP_ASSIGN_DEV_IRQ 29 /* Another bug in KVM_SET_USER_MEMORY_REGION fixed: */ #define KVM_CAP_JOIN_MEMORY_REGIONS_WORKS 30 +#define KVM_CAP_PIT2 31 #ifdef KVM_CAP_IRQ_ROUTING @@ -538,6 +547,7 @@ struct kvm_irq_routing { #define KVM_ASSIGN_SET_MSIX_ENTRY \ _IOW(KVMIO, 0x74, struct kvm_assigned_msix_entry) #define KVM_DEASSIGN_DEV_IRQ _IOW(KVMIO, 0x75, struct kvm_assigned_irq) +#define KVM_CREATE_PIT2 _IOW(KVMIO, 0x76, struct kvm_pit_config) /* * ioctls for vcpu fds diff --git a/kvm/libkvm/libkvm-x86.c b/kvm/libkvm/libkvm-x86.c index a2f6320..9c0d967 100644 --- a/kvm/libkvm/libkvm-x86.c +++ b/kvm/libkvm/libkvm-x86.c @@ -59,16 +59,26 @@ static int kvm_create_pit(kvm_context_t kvm) kvm->pit_in_kernel = 0; if (!kvm->no_pit_creation) { - r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_PIT); - if (r > 0) { +#ifdef KVM_CAP_PIT2 + struct kvm_pit_config config = { .flags = 0 }; + + r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_PIT2); + if (r > 0) + r = ioctl(kvm->vm_fd, KVM_CREATE_PIT2, &config); + else +#endif + { + r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_PIT); + if (r <= 0) + return 0; + r = ioctl(kvm->vm_fd, KVM_CREATE_PIT); - if (r >= 0) - kvm->pit_in_kernel = 1; - else { - fprintf(stderr, "Create kernel PIC irqchip failed\n"); - return r; - } } + if (r < 0) { + fprintf(stderr, "Create kernel PIC irqchip failed\n"); + return r; + } + kvm->pit_in_kernel = 1; } #endif return 0;