From patchwork Sun Jun 6 08:11:05 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kiszka X-Patchwork-Id: 54813 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 3ED02B7D5B for ; Sun, 6 Jun 2010 18:57:15 +1000 (EST) Received: from localhost ([127.0.0.1]:60105 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OLBSS-0003hZ-17 for incoming@patchwork.ozlabs.org; Sun, 06 Jun 2010 04:43:52 -0400 Received: from [140.186.70.92] (port=60272 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OLAx1-0002O2-Fd for qemu-devel@nongnu.org; Sun, 06 Jun 2010 04:11:27 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1OLAwv-0004of-Ts for qemu-devel@nongnu.org; Sun, 06 Jun 2010 04:11:23 -0400 Received: from fmmailgate02.web.de ([217.72.192.227]:54479) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1OLAwv-0004oM-E0 for qemu-devel@nongnu.org; Sun, 06 Jun 2010 04:11:17 -0400 Received: from smtp04.web.de ( [172.20.0.225]) by fmmailgate02.web.de (Postfix) with ESMTP id C29A6164DD88F; Sun, 6 Jun 2010 10:11:16 +0200 (CEST) Received: from [88.66.126.39] (helo=localhost.localdomain) by smtp04.web.de with asmtp (TLSv1:AES256-SHA:256) (WEB.DE 4.110 #4) id 1OLAwu-000200-02; Sun, 06 Jun 2010 10:11:16 +0200 From: Jan Kiszka To: qemu-devel@nongnu.org Date: Sun, 6 Jun 2010 10:11:05 +0200 Message-Id: <086631bfe97458f12d1e4adbc3585483dc7e178f.1275811861.git.jan.kiszka@web.de> X-Mailer: git-send-email 1.6.0.2 In-Reply-To: References: In-Reply-To: References: X-Sender: jan.kiszka@web.de X-Provags-ID: V01U2FsdGVkX1+iOKvlhcqupCz/vUTjQfBdvmMzI4Hl8sOmrhzi eGncf+hmojaK+8bfsyNcPbPj5gRcYrL7QdEONA1mWZBdyhORLY uHzkNQ0wg= X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.4-2.6 Cc: blue Swirl , Jan Kiszka , Paul Brook , Gleb Natapov , Juan Quintela Subject: [Qemu-devel] [PATCH 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 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/apic.c | 2 +- hw/apic.h | 1 + hw/hpet.c | 39 +++++++++++++++++++++++++++++++++++---- hw/hpet_emul.h | 4 +++- 4 files changed, 40 insertions(+), 6 deletions(-) diff --git a/hw/apic.c b/hw/apic.c index f9587d1..f33d20a 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -776,7 +776,7 @@ static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr) return val; } -static void apic_send_msi(target_phys_addr_t addr, uint32 data) +void apic_send_msi(target_phys_addr_t addr, uint32 data) { uint8_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT; uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT; diff --git a/hw/apic.h b/hw/apic.h index 738d98a..9c646f0 100644 --- a/hw/apic.h +++ b/hw/apic.h @@ -5,6 +5,7 @@ typedef struct IOAPICState IOAPICState; int apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode, uint8_t vector_num, uint8_t polarity, uint8_t trigger_mode); +void apic_send_msi(target_phys_addr_t addr, uint32 data); int apic_init(CPUState *env); int apic_accept_pic_intr(CPUState *env); void apic_deliver_pic_intr(CPUState *env, int level); diff --git a/hw/hpet.c b/hw/hpet.c index 7219967..490a804 100644 --- a/hw/hpet.c +++ b/hw/hpet.c @@ -31,6 +31,7 @@ #include "hpet_emul.h" #include "sysbus.h" #include "mc146818rtc.h" +#include "apic.h" //#define HPET_DEBUG #ifdef HPET_DEBUG @@ -39,6 +40,8 @@ #define DPRINTF(...) #endif +#define HPET_MSI_SUPPORT 0 + struct HPETState; typedef struct HPETTimer { /* timers */ uint8_t tn; /*timer number*/ @@ -47,7 +50,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 +62,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 +84,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 +188,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)) { + apic_send_msi(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 +229,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 +380,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 +465,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 +525,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 +637,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 +730,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