From patchwork Sun Jun 13 12:15:44 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kiszka X-Patchwork-Id: 55427 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 54DB5B7D43 for ; Sun, 13 Jun 2010 22:36:58 +1000 (EST) Received: from localhost ([127.0.0.1]:52964 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1ONmQp-0001vp-7u for incoming@patchwork.ozlabs.org; Sun, 13 Jun 2010 08:36:55 -0400 Received: from [140.186.70.92] (port=44658 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1ONm6a-0001k9-61 for qemu-devel@nongnu.org; Sun, 13 Jun 2010 08:16:02 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1ONm6X-00033f-6t for qemu-devel@nongnu.org; Sun, 13 Jun 2010 08:16:00 -0400 Received: from fmmailgate03.web.de ([217.72.192.234]:45870) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1ONm6W-000339-K7 for qemu-devel@nongnu.org; Sun, 13 Jun 2010 08:15:57 -0400 Received: from smtp01.web.de ( [172.20.0.243]) by fmmailgate03.web.de (Postfix) with ESMTP id 1A81A155EE322; Sun, 13 Jun 2010 14:15:56 +0200 (CEST) Received: from [92.74.52.35] (helo=localhost.localdomain) by smtp01.web.de with asmtp (TLSv1:AES256-SHA:256) (WEB.DE 4.110 #4) id 1ONm6V-0004oR-02; Sun, 13 Jun 2010 14:15:56 +0200 From: Jan Kiszka To: Anthony Liguori , qemu-devel@nongnu.org Date: Sun, 13 Jun 2010 14:15:44 +0200 Message-Id: <8352e5e6493c31c93af5f46fe4b519a27b41e252.1276431335.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/+kB8A962TI6GbhdRcLMoSUHbyro6REnsU0zRu MOOlBGYvfFVuo4QispIDzFR70d7I1mRG93KqZVYGgDPN5hLjAJ dnduseQKw= 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 v4 11/13] hpet: Make number of timers configurable 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 One HPET block supports up to 32 timers. Allow to instantiate more than the recommended and implemented minimum of 3. The number is configured via the qdev property "timers". It is also saved/restored so that it need not match between migration peers. Signed-off-by: Jan Kiszka --- hw/hpet.c | 53 ++++++++++++++++++++++++++++++++++++++++------------- hw/hpet_emul.h | 6 +++++- 2 files changed, 45 insertions(+), 14 deletions(-) diff --git a/hw/hpet.c b/hw/hpet.c index f24b227..6187e5e 100644 --- a/hw/hpet.c +++ b/hw/hpet.c @@ -60,7 +60,8 @@ typedef struct HPETState { uint64_t hpet_offset; qemu_irq irqs[HPET_NUM_IRQ_ROUTES]; uint8_t rtc_irq_level; - HPETTimer timer[HPET_NUM_TIMERS]; + uint8_t num_timers; + HPETTimer timer[HPET_MAX_TIMERS]; /* Memory-mapped, software visible registers */ uint64_t capability; /* capabilities */ @@ -196,12 +197,25 @@ static void hpet_pre_save(void *opaque) s->hpet_counter = hpet_get_ticks(s); } +static int hpet_pre_load(void *opaque) +{ + HPETState *s = opaque; + + /* version 1 only supports 3, later versions will load the actual value */ + s->num_timers = HPET_MIN_TIMERS; + return 0; +} + static int hpet_post_load(void *opaque, int version_id) { HPETState *s = opaque; /* Recalculate the offset between the main counter and guest time */ s->hpet_offset = ticks_to_ns(s->hpet_counter) - qemu_get_clock(vm_clock); + + /* 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; return 0; } @@ -224,17 +238,19 @@ static const VMStateDescription vmstate_hpet_timer = { static const VMStateDescription vmstate_hpet = { .name = "hpet", - .version_id = 1, + .version_id = 2, .minimum_version_id = 1, .minimum_version_id_old = 1, .pre_save = hpet_pre_save, + .pre_load = hpet_pre_load, .post_load = hpet_post_load, .fields = (VMStateField []) { VMSTATE_UINT64(config, HPETState), VMSTATE_UINT64(isr, HPETState), VMSTATE_UINT64(hpet_counter, HPETState), - VMSTATE_STRUCT_ARRAY(timer, HPETState, HPET_NUM_TIMERS, 0, - vmstate_hpet_timer, HPETTimer), + VMSTATE_UINT8_V(num_timers, HPETState, 2), + VMSTATE_STRUCT_VARRAY_UINT8(timer, HPETState, num_timers, 0, + vmstate_hpet_timer, HPETTimer), VMSTATE_END_OF_LIST() } }; @@ -330,7 +346,7 @@ static uint32_t hpet_ram_readl(void *opaque, target_phys_addr_t addr) uint8_t timer_id = (addr - 0x100) / 0x20; HPETTimer *timer = &s->timer[timer_id]; - if (timer_id > HPET_NUM_TIMERS - 1) { + if (timer_id > s->num_timers) { DPRINTF("qemu: timer id out of range\n"); return 0; } @@ -421,7 +437,7 @@ static void hpet_ram_writel(void *opaque, target_phys_addr_t addr, HPETTimer *timer = &s->timer[timer_id]; DPRINTF("qemu: hpet_ram_writel timer_id = %#x \n", timer_id); - if (timer_id > HPET_NUM_TIMERS - 1) { + if (timer_id > s->num_timers) { DPRINTF("qemu: timer id out of range\n"); return; } @@ -504,7 +520,7 @@ static void hpet_ram_writel(void *opaque, target_phys_addr_t addr, /* Enable main counter and interrupt generation. */ s->hpet_offset = ticks_to_ns(s->hpet_counter) - qemu_get_clock(vm_clock); - for (i = 0; i < HPET_NUM_TIMERS; i++) { + for (i = 0; i < s->num_timers; i++) { if ((&s->timer[i])->cmp != ~0ULL) { hpet_set_timer(&s->timer[i]); } @@ -512,7 +528,7 @@ static void hpet_ram_writel(void *opaque, target_phys_addr_t addr, } else if (deactivating_bit(old_val, new_val, HPET_CFG_ENABLE)) { /* Halt main counter and disable interrupt generation. */ s->hpet_counter = hpet_get_ticks(s); - for (i = 0; i < HPET_NUM_TIMERS; i++) { + for (i = 0; i < s->num_timers; i++) { hpet_del_timer(&s->timer[i]); } } @@ -530,7 +546,7 @@ static void hpet_ram_writel(void *opaque, target_phys_addr_t addr, break; case HPET_STATUS: val = new_val & s->isr; - for (i = 0; i < HPET_NUM_TIMERS; i++) { + for (i = 0; i < s->num_timers; i++) { if (val & (1 << i)) { update_irq(&s->timer[i], 0); } @@ -589,7 +605,7 @@ static void hpet_reset(DeviceState *d) int i; static int count = 0; - for (i = 0; i < HPET_NUM_TIMERS; i++) { + for (i = 0; i < s->num_timers; i++) { HPETTimer *timer = &s->timer[i]; hpet_del_timer(timer); @@ -603,8 +619,9 @@ static void hpet_reset(DeviceState *d) s->hpet_counter = 0ULL; s->hpet_offset = 0ULL; - /* 64-bit main counter; 3 timers supported; LegacyReplacementRoute. */ - s->capability = 0x8086a201ULL; + /* 64-bit main counter; LegacyReplacementRoute. */ + s->capability = 0x8086a001ULL; + s->capability |= (s->num_timers - 1) << HPET_ID_NUM_TIM_SHIFT; s->capability |= ((HPET_CLK_PERIOD) << 32); s->config = 0ULL; if (count > 0) { @@ -637,7 +654,13 @@ static int hpet_init(SysBusDevice *dev) for (i = 0; i < HPET_NUM_IRQ_ROUTES; i++) { sysbus_init_irq(dev, &s->irqs[i]); } - for (i = 0; i < HPET_NUM_TIMERS; i++) { + + if (s->num_timers < HPET_MIN_TIMERS) { + s->num_timers = HPET_MIN_TIMERS; + } else if (s->num_timers > HPET_MAX_TIMERS) { + s->num_timers = HPET_MAX_TIMERS; + } + for (i = 0; i < HPET_MAX_TIMERS; i++) { timer = &s->timer[i]; timer->qemu_timer = qemu_new_timer(vm_clock, hpet_timer, timer); timer->tn = i; @@ -661,6 +684,10 @@ static SysBusDeviceInfo hpet_device_info = { .qdev.vmsd = &vmstate_hpet, .qdev.reset = hpet_reset, .init = hpet_init, + .qdev.props = (Property[]) { + DEFINE_PROP_UINT8("timers", HPETState, num_timers, HPET_MIN_TIMERS), + DEFINE_PROP_END_OF_LIST(), + }, }; static void hpet_register_device(void) diff --git a/hw/hpet_emul.h b/hw/hpet_emul.h index 9c268cc..e8b794c 100644 --- a/hw/hpet_emul.h +++ b/hw/hpet_emul.h @@ -17,7 +17,8 @@ #define HPET_CLK_PERIOD 10000000ULL /* 10000000 femtoseconds == 10ns*/ #define FS_PER_NS 1000000 -#define HPET_NUM_TIMERS 3 +#define HPET_MIN_TIMERS 3 +#define HPET_MAX_TIMERS 32 #define HPET_NUM_IRQ_ROUTES 32 @@ -34,6 +35,9 @@ #define HPET_TN_ROUTE 0x010 #define HPET_CFG_WRITE_MASK 0x3 +#define HPET_ID_NUM_TIM_SHIFT 8 +#define HPET_ID_NUM_TIM_MASK 0x1f00 + #define HPET_TN_TYPE_LEVEL 0x002 #define HPET_TN_ENABLE 0x004 #define HPET_TN_PERIODIC 0x008