From patchwork Tue Apr 26 14:01:00 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kiszka X-Patchwork-Id: 732832 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p3QE1jq6001803 for ; Tue, 26 Apr 2011 14:01:46 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755705Ab1DZOBU (ORCPT ); Tue, 26 Apr 2011 10:01:20 -0400 Received: from fmmailgate01.web.de ([217.72.192.221]:41618 "EHLO fmmailgate01.web.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756181Ab1DZOBQ (ORCPT ); Tue, 26 Apr 2011 10:01:16 -0400 Received: from smtp02.web.de ( [172.20.0.184]) by fmmailgate01.web.de (Postfix) with ESMTP id 6C2C418D07CFC; Tue, 26 Apr 2011 16:01:01 +0200 (CEST) Received: from [88.64.17.9] (helo=mchn199C.mchp.siemens.de) by smtp02.web.de with asmtp (TLSv1:AES256-SHA:256) (WEB.DE 4.110 #2) id 1QEip3-0008Qh-00; Tue, 26 Apr 2011 16:01:01 +0200 Message-ID: <4DB6D01C.6080706@siemens.com> Date: Tue, 26 Apr 2011 16:01:00 +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 , Marcelo Tosatti CC: kvm@vger.kernel.org, "Michael S. Tsirkin" Subject: [PATCH v3 9/9] qemu-kvm: hpet: Add MSI support for in-kernel irqchip mode References: <3d089633897515a214af032ed633342a7001945f.1303823975.git.jan.kiszka@siemens.com> In-Reply-To: <3d089633897515a214af032ed633342a7001945f.1303823975.git.jan.kiszka@siemens.com> X-Sender: jan.kiszka@web.de X-Provags-ID: V01U2FsdGVkX18318WQuXICDgfTTQfPf0F0K9cM7d9tw6Q6XMoT e9YjSF1fr0FruEmRwAdmg0kJhTxS+TOT5dW4vW128+VWjq0fJO O8Ud1H9sk= Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Tue, 26 Apr 2011 14:01:46 +0000 (UTC) Just like PCI devices, the HPET requires special care to route MSI events to the in-kernel irqchip if enabled. Signed-off-by: Jan Kiszka --- hw/hpet.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 70 insertions(+), 1 deletions(-) v3: Let modifying_bit return bool to avoid unexpected results. diff --git a/hw/hpet.c b/hw/hpet.c index 6ce07bc..ed8018d 100644 --- a/hw/hpet.c +++ b/hw/hpet.c @@ -31,6 +31,7 @@ #include "hpet_emul.h" #include "sysbus.h" #include "mc146818rtc.h" +#include "kvm.h" //#define HPET_DEBUG #ifdef HPET_DEBUG @@ -55,6 +56,7 @@ typedef struct HPETTimer { /* timers */ uint8_t wrap_flag; /* timer pop will indicate wrap for one-shot 32-bit * mode. Next pop will be actual timer expiration. */ + KVMMsiMessage kmm; } HPETTimer; typedef struct HPETState { @@ -141,11 +143,59 @@ static int deactivating_bit(uint64_t old, uint64_t new, uint64_t mask) return ((old & mask) && !(new & mask)); } +static bool modifying_bit(uint64_t old, uint64_t new, uint64_t mask) +{ + return (old ^ new) & mask; +} + static uint64_t hpet_get_ticks(HPETState *s) { return ns_to_ticks(qemu_get_clock_ns(vm_clock) + s->hpet_offset); } +static void kvm_hpet_msi_update(HPETTimer *t) +{ + KVMMsiMessage new_entry; + int ret = 0; + + if (!kvm_enabled() || !kvm_irqchip_in_kernel()) { + return; + } + + if (timer_fsb_route(t)) { + new_entry.addr_hi = 0; + new_entry.addr_lo = t->fsb >> 32; + new_entry.data = t->fsb & 0xffffffff; + if (t->kmm.gsi == -1) { + kvm_msi_message_add(&new_entry); + ret = 1; + } else { + ret = kvm_msi_message_update(&t->kmm, &new_entry); + } + if (ret > 0) { + t->kmm = new_entry; + kvm_commit_irq_routes(); + } + } else if (t->kmm.gsi != -1) { + kvm_msi_message_del(&t->kmm); + t->kmm.gsi = -1; + } +} + +static void kvm_hpet_msi_free(HPETState *s) +{ + int i; + + for (i = 0; i < s->num_timers; i++) { + HPETTimer *timer = &s->timer[i]; + + if (timer->kmm.gsi != -1) { + kvm_msi_message_del(&timer->kmm); + timer->kmm.gsi = -1; + } + } +} + /* * calculate diff between comparator value and current ticks */ @@ -192,7 +242,11 @@ static void update_irq(struct HPETTimer *timer, int set) qemu_irq_lower(s->irqs[route]); } } else if (timer_fsb_route(timer)) { - stl_phys(timer->fsb >> 32, timer->fsb & 0xffffffff); + if (kvm_enabled() && kvm_irqchip_in_kernel()) { + kvm_set_irq(timer->kmm.gsi, 1, NULL); + } else { + stl_phys(timer->fsb >> 32, timer->fsb & 0xffffffff); + } } else if (timer->config & HPET_TN_TYPE_LEVEL) { s->isr |= mask; qemu_irq_raise(s->irqs[route]); @@ -214,6 +268,8 @@ static int hpet_pre_load(void *opaque) { HPETState *s = opaque; + kvm_hpet_msi_free(s); + /* version 1 only supports 3, later versions will load the actual value */ s->num_timers = HPET_MIN_TIMERS; return 0; @@ -222,6 +278,7 @@ static int hpet_pre_load(void *opaque) static int hpet_post_load(void *opaque, int version_id) { HPETState *s = opaque; + int i; /* Recalculate the offset between the main counter and guest time */ s->hpet_offset = ticks_to_ns(s->hpet_counter) - qemu_get_clock_ns(vm_clock); @@ -241,6 +298,10 @@ static int hpet_post_load(void *opaque, int version_id) hpet_pit_disable(); } + for (i = 0; i < s->num_timers; i++) { + kvm_hpet_msi_update(&s->timer[i]); + } + return 0; } @@ -485,6 +546,9 @@ static void hpet_ram_writel(void *opaque, target_phys_addr_t addr, } else if (deactivating_bit(old_val, new_val, HPET_TN_ENABLE)) { hpet_del_timer(timer); } + if (modifying_bit(old_val, new_val, HPET_TN_FSB_ENABLE)) { + kvm_hpet_msi_update(timer); + } break; case HPET_TN_CFG + 4: // Interrupt capabilities DPRINTF("qemu: invalid HPET_TN_CFG+4 write\n"); @@ -533,9 +597,11 @@ static void hpet_ram_writel(void *opaque, target_phys_addr_t addr, break; case HPET_TN_ROUTE: timer->fsb = (timer->fsb & 0xffffffff00000000ULL) | new_val; + kvm_hpet_msi_update(timer); break; case HPET_TN_ROUTE + 4: timer->fsb = (new_val << 32) | (timer->fsb & 0xffffffff); + kvm_hpet_msi_update(timer); break; default: DPRINTF("qemu: invalid hpet_ram_writel\n"); @@ -667,6 +733,8 @@ static void hpet_reset(DeviceState *d) hpet_cfg.hpet[s->hpet_id].event_timer_block_id = (uint32_t)s->capability; hpet_cfg.hpet[s->hpet_id].address = sysbus_from_qdev(d)->mmio[0].addr; count = 1; + + kvm_hpet_msi_free(s); } static void hpet_handle_rtc_irq(void *opaque, int n, int level) @@ -711,6 +779,7 @@ static int hpet_init(SysBusDevice *dev) timer->qemu_timer = qemu_new_timer_ns(vm_clock, hpet_timer, timer); timer->tn = i; timer->state = s; + timer->kmm.gsi = -1; } /* 64-bit main counter; LegacyReplacementRoute. */