From patchwork Sat Jun 12 10:23:31 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kiszka X-Patchwork-Id: 55386 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 6DCBFB7D7F for ; Sat, 12 Jun 2010 20:25:53 +1000 (EST) Received: from localhost ([127.0.0.1]:40227 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1ONNuP-0006Uj-2h for incoming@patchwork.ozlabs.org; Sat, 12 Jun 2010 06:25:49 -0400 Received: from [140.186.70.92] (port=49302 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1ONNsG-0005l0-LK for qemu-devel@nongnu.org; Sat, 12 Jun 2010 06:23:38 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1ONNsF-0008UX-1w for qemu-devel@nongnu.org; Sat, 12 Jun 2010 06:23:36 -0400 Received: from fmmailgate01.web.de ([217.72.192.221]:41164) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1ONNsE-0008UM-M0 for qemu-devel@nongnu.org; Sat, 12 Jun 2010 06:23:35 -0400 Received: from smtp04.web.de ( [172.20.0.225]) by fmmailgate01.web.de (Postfix) with ESMTP id 1354D15EC26E0; Sat, 12 Jun 2010 12:23:32 +0200 (CEST) Received: from [88.66.126.39] (helo=[192.168.1.10]) by smtp04.web.de with asmtp (TLSv1:AES256-SHA:256) (WEB.DE 4.110 #4) id 1ONNsB-0003R3-00; Sat, 12 Jun 2010 12:23:31 +0200 Message-ID: <4C136023.30306@web.de> Date: Sat, 12 Jun 2010 12:23:31 +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: Paul Brook References: <086631bfe97458f12d1e4adbc3585483dc7e178f.1275811861.git.jan.kiszka@web.de> <201006112231.31926.paul@codesourcery.com> In-Reply-To: <201006112231.31926.paul@codesourcery.com> X-Enigmail-Version: 0.95.7 X-Sender: jan.kiszka@web.de X-Provags-ID: V01U2FsdGVkX18oe0V1YR59nuS+LNKIz1euhKrd4ZvgOiPlXSKT y9Jpqo0UEyHgOo6e3AKxqtuZ4CWTwTa8gry/lFlRgae3bR/1Wt bGYX9qFuE= X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.4-2.6 Cc: blue Swirl , Jan Kiszka , qemu-devel@nongnu.org, Gleb Natapov , Juan Quintela Subject: [Qemu-devel] [PATCH v3 16/16] hpet: Add MSI support X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Paul Brook wrote: >> + } else if (timer_fsb_route(timer)) { >> + apic_send_msi(timer->fsb >> 32, timer->fsb & 0xffffffff); > > This should use a regular memory write, like the PCI MSI-X code does. > Indeed, here we go: ----------> From: Jan Kiszka This implements the HPET capability of routing IRQs to the front-side bus, aka MSI support. This feature can be enabled via the qdev property "msi" and is off by default. Note that switching it on can cause guests (at least Linux) to use the HPET as timer instead of the LAPIC. KVM users should recall that only the latter is currently available as fast in-kernel model. Signed-off-by: Jan Kiszka --- hw/hpet.c | 38 ++++++++++++++++++++++++++++++++++---- hw/hpet_emul.h | 4 +++- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/hw/hpet.c b/hw/hpet.c index 7219967..117c598 100644 --- a/hw/hpet.c +++ b/hw/hpet.c @@ -39,6 +39,8 @@ #define DPRINTF(...) #endif +#define HPET_MSI_SUPPORT 0 + struct HPETState; typedef struct HPETTimer { /* timers */ uint8_t tn; /*timer number*/ @@ -47,7 +49,7 @@ typedef struct HPETTimer { /* timers */ /* Memory-mapped, software visible timer registers */ uint64_t config; /* configuration/cap */ uint64_t cmp; /* comparator */ - uint64_t fsb; /* FSB route, not supported now */ + uint64_t fsb; /* FSB route */ /* Hidden register state */ uint64_t period; /* Last value written to comparator */ uint8_t wrap_flag; /* timer pop will indicate wrap for one-shot 32-bit @@ -59,6 +61,7 @@ typedef struct HPETState { SysBusDevice busdev; uint64_t hpet_offset; qemu_irq irqs[HPET_NUM_IRQ_ROUTES]; + uint32_t flags; uint8_t rtc_irq_level; uint8_t num_timers; HPETTimer timer[HPET_MAX_TIMERS]; @@ -80,6 +83,11 @@ static uint32_t timer_int_route(struct HPETTimer *timer) return (timer->config & HPET_TN_INT_ROUTE_MASK) >> HPET_TN_INT_ROUTE_SHIFT; } +static uint32_t timer_fsb_route(HPETTimer *t) +{ + return t->config & HPET_TN_FSB_ENABLE; +} + static uint32_t hpet_enabled(HPETState *s) { return s->config & HPET_CFG_ENABLE; @@ -179,7 +187,11 @@ static void update_irq(struct HPETTimer *timer, int set) mask = 1 << timer->tn; if (!set || !timer_enabled(timer) || !hpet_enabled(timer->state)) { s->isr &= ~mask; - qemu_irq_lower(s->irqs[route]); + if (!timer_fsb_route(timer)) { + qemu_irq_lower(s->irqs[route]); + } + } else if (timer_fsb_route(timer)) { + 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]); @@ -216,6 +228,12 @@ static int hpet_post_load(void *opaque, int version_id) /* Push number of timers into capability returned via HPET_ID */ s->capability &= ~HPET_ID_NUM_TIM_MASK; s->capability |= (s->num_timers - 1) << HPET_ID_NUM_TIM_SHIFT; + + /* Derive HPET_MSI_SUPPORT from the capability of the first timer. */ + s->flags &= ~(1 << HPET_MSI_SUPPORT); + if (s->timer[0].config & HPET_TN_FSB_CAP) { + s->flags |= 1 << HPET_MSI_SUPPORT; + } return 0; } @@ -361,6 +379,8 @@ static uint32_t hpet_ram_readl(void *opaque, target_phys_addr_t addr) case HPET_TN_CMP + 4: return timer->cmp >> 32; case HPET_TN_ROUTE: + return timer->fsb; + case HPET_TN_ROUTE + 4: return timer->fsb >> 32; default: DPRINTF("qemu: invalid hpet_ram_readl\n"); @@ -444,6 +464,9 @@ static void hpet_ram_writel(void *opaque, target_phys_addr_t addr, switch ((addr - 0x100) % 0x20) { case HPET_TN_CFG: DPRINTF("qemu: hpet_ram_writel HPET_TN_CFG\n"); + if (activating_bit(old_val, new_val, HPET_TN_FSB_ENABLE)) { + update_irq(timer, 0); + } val = hpet_fixup_reg(new_val, old_val, HPET_TN_CFG_WRITE_MASK); timer->config = (timer->config & 0xffffffff00000000ULL) | val; if (new_val & HPET_TN_32BIT) { @@ -501,8 +524,11 @@ static void hpet_ram_writel(void *opaque, target_phys_addr_t addr, hpet_set_timer(timer); } break; + case HPET_TN_ROUTE: + timer->fsb = (timer->fsb & 0xffffffff00000000ULL) | new_val; + break; case HPET_TN_ROUTE + 4: - DPRINTF("qemu: hpet_ram_writel HPET_TN_ROUTE + 4\n"); + timer->fsb = (new_val << 32) | (timer->fsb & 0xffffffff); break; default: DPRINTF("qemu: invalid hpet_ram_writel\n"); @@ -610,7 +636,10 @@ static void hpet_reset(DeviceState *d) hpet_del_timer(timer); timer->cmp = ~0ULL; - timer->config = HPET_TN_PERIODIC_CAP | HPET_TN_SIZE_CAP; + timer->config = HPET_TN_PERIODIC_CAP | HPET_TN_SIZE_CAP; + if (s->flags & (1 << HPET_MSI_SUPPORT)) { + timer->config |= HPET_TN_FSB_CAP; + } /* advertise availability of ioapic inti2 */ timer->config |= 0x00000004ULL << 32; timer->period = 0ULL; @@ -700,6 +729,7 @@ static SysBusDeviceInfo hpet_device_info = { .init = hpet_init, .qdev.props = (Property[]) { DEFINE_PROP_UINT8("timers", HPETState, num_timers, HPET_MIN_TIMERS), + DEFINE_PROP_BIT("msi", HPETState, flags, HPET_MSI_SUPPORT, false), DEFINE_PROP_END_OF_LIST(), }, }; diff --git a/hw/hpet_emul.h b/hw/hpet_emul.h index e8b794c..d7bc102 100644 --- a/hw/hpet_emul.h +++ b/hw/hpet_emul.h @@ -46,7 +46,9 @@ #define HPET_TN_SETVAL 0x040 #define HPET_TN_32BIT 0x100 #define HPET_TN_INT_ROUTE_MASK 0x3e00 -#define HPET_TN_CFG_WRITE_MASK 0x3f4e +#define HPET_TN_FSB_ENABLE 0x4000 +#define HPET_TN_FSB_CAP 0x8000 +#define HPET_TN_CFG_WRITE_MASK 0x7f4e #define HPET_TN_INT_ROUTE_SHIFT 9 #define HPET_TN_INT_ROUTE_CAP_SHIFT 32 #define HPET_TN_CFG_BITS_READONLY_OR_RESERVED 0xffff80b1U