From patchwork Wed Sep 5 05:28:15 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gerd Hoffman X-Patchwork-Id: 1405181 Return-Path: X-Original-To: patchwork-kvm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork1.kernel.org (Postfix) with ESMTP id 9B88C40220 for ; Wed, 5 Sep 2012 05:28:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1750886Ab2IEF23 (ORCPT ); Wed, 5 Sep 2012 01:28:29 -0400 Received: from mx1.redhat.com ([209.132.183.28]:53714 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750706Ab2IEF21 (ORCPT ); Wed, 5 Sep 2012 01:28:27 -0400 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q855SHi9017837 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Wed, 5 Sep 2012 01:28:17 -0400 Received: from rincewind.home.kraxel.org (ovpn-116-25.ams2.redhat.com [10.36.116.25]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id q855SGIO019170; Wed, 5 Sep 2012 01:28:17 -0400 Received: by rincewind.home.kraxel.org (Postfix, from userid 500) id 251A140BDF; Wed, 5 Sep 2012 07:28:16 +0200 (CEST) From: Gerd Hoffmann To: seabios@seabios.org Cc: kvm@vger.kernel.org, Gerd Hoffmann Subject: [PATCH v3] add acpi pmtimer support Date: Wed, 5 Sep 2012 07:28:15 +0200 Message-Id: <1346822895-19196-1-git-send-email-kraxel@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org This patch makes seabios use the acpi pmtimer instead of tsc for timekeeping. The pmtimer has a fixed frequency and doesn't need calibration, thus it doesn't suffer from calibration errors due to a loaded host machine. [ v3: mask port ioport read ] [ v2: add CONFIG_PMTIMER ] Signed-off-by: Gerd Hoffmann --- src/Kconfig | 6 ++++++ src/clock.c | 31 +++++++++++++++++++++++++++++++ src/pciinit.c | 5 +++++ src/util.h | 1 + 4 files changed, 43 insertions(+), 0 deletions(-) diff --git a/src/Kconfig b/src/Kconfig index 6de3e71..b5dd63b 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -222,6 +222,12 @@ menu "Hardware support" default y help Initialize the Memory Type Range Registers (on emulators). + config PMTIMER + depends on !COREBOOT + bool "Use ACPI timer" + default y + help + Use the ACPI timer instead of the TSC for timekeeping (on qemu). endmenu menu "BIOS interfaces" diff --git a/src/clock.c b/src/clock.c index 69e9f17..b4abf37 100644 --- a/src/clock.c +++ b/src/clock.c @@ -129,11 +129,42 @@ emulate_tsc(void) return ret; } +u16 pmtimer_ioport VAR16VISIBLE; +u32 pmtimer_wraps VARLOW; +u32 pmtimer_last VARLOW; + +void pmtimer_init(u16 ioport, u32 khz) +{ + if (!CONFIG_PMTIMER) + return; + dprintf(1, "Using pmtimer, ioport 0x%x, freq %d kHz\n", ioport, khz); + SET_GLOBAL(pmtimer_ioport, ioport); + SET_GLOBAL(cpu_khz, khz); +} + +static u64 pmtimer_get(void) +{ + u16 ioport = GET_GLOBAL(pmtimer_ioport); + u32 wraps = GET_LOW(pmtimer_wraps); + u32 pmtimer = inl(ioport); + + if (pmtimer < GET_LOW(pmtimer_last)) { + wraps++; + SET_LOW(pmtimer_wraps, wraps); + } + SET_LOW(pmtimer_last, pmtimer); + + dprintf(9, "pmtimer: %u:%u\n", wraps, pmtimer); + return (u64)wraps << 24 | pmtimer; +} + static u64 get_tsc(void) { if (unlikely(GET_GLOBAL(no_tsc))) return emulate_tsc(); + if (CONFIG_PMTIMER && GET_GLOBAL(pmtimer_ioport)) + return pmtimer_get(); return rdtscll(); } diff --git a/src/pciinit.c b/src/pciinit.c index 68f302a..31115ee 100644 --- a/src/pciinit.c +++ b/src/pciinit.c @@ -180,6 +180,9 @@ static const struct pci_device_id pci_class_tbl[] = { PCI_DEVICE_END, }; +/* PM Timer ticks per second (HZ) */ +#define PM_TIMER_FREQUENCY 3579545 + /* PIIX4 Power Management device (for ACPI) */ static void piix4_pm_init(struct pci_device *pci, void *arg) { @@ -191,6 +194,8 @@ static void piix4_pm_init(struct pci_device *pci, void *arg) pci_config_writeb(bdf, 0x80, 0x01); /* enable PM io space */ pci_config_writel(bdf, 0x90, PORT_SMB_BASE | 1); pci_config_writeb(bdf, 0xd2, 0x09); /* enable SMBus io space */ + + pmtimer_init(PORT_ACPI_PM_BASE + 0x08, PM_TIMER_FREQUENCY / 1000); } static const struct pci_device_id pci_device_tbl[] = { diff --git a/src/util.h b/src/util.h index 062eea3..7723bb1 100644 --- a/src/util.h +++ b/src/util.h @@ -282,6 +282,7 @@ void lpt_setup(void); // clock.c #define PIT_TICK_RATE 1193180 // Underlying HZ of PIT #define PIT_TICK_INTERVAL 65536 // Default interval for 18.2Hz timer +void pmtimer_init(u16 ioport, u32 khz); int check_tsc(u64 end); void timer_setup(void); void ndelay(u32 count);