diff mbox

add acpi pmtimer support

Message ID 1344863050-8959-1-git-send-email-kraxel@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Gerd Hoffmann Aug. 13, 2012, 1:04 p.m. UTC
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.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 src/clock.c   |   29 +++++++++++++++++++++++++++++
 src/pciinit.c |    5 +++++
 src/util.h    |    1 +
 3 files changed, 35 insertions(+), 0 deletions(-)

Comments

Marcelo Tosatti Aug. 13, 2012, 10:31 p.m. UTC | #1
On Mon, Aug 13, 2012 at 03:04:10PM +0200, Gerd Hoffmann wrote:
> 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.
> 
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  src/clock.c   |   29 +++++++++++++++++++++++++++++
>  src/pciinit.c |    5 +++++
>  src/util.h    |    1 +
>  3 files changed, 35 insertions(+), 0 deletions(-)
> 
> diff --git a/src/clock.c b/src/clock.c
> index 69e9f17..59f269b 100644
> --- a/src/clock.c
> +++ b/src/clock.c
> @@ -129,11 +129,40 @@ emulate_tsc(void)
>      return ret;
>  }
>  
> +u16 pmtimer_ioport VAR16VISIBLE;
> +u32 pmtimer_wraps VARLOW;
> +u32 pmtimer_last VARLOW;
> +
> +void pmtimer_init(u16 ioport, u32 khz)
> +{
> +    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 (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 89e928c..1603a57 100644
> --- a/src/util.h
> +++ b/src/util.h
> @@ -312,6 +312,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);

Looks good.

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Kevin O'Connor Aug. 13, 2012, 10:47 p.m. UTC | #2
On Mon, Aug 13, 2012 at 03:04:10PM +0200, Gerd Hoffmann wrote:
> 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.

It looks okay to me.  It'd be nice to have a CONFIG_PMTIMER for it,
but it can be added on top.

-Kevin
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/src/clock.c b/src/clock.c
index 69e9f17..59f269b 100644
--- a/src/clock.c
+++ b/src/clock.c
@@ -129,11 +129,40 @@  emulate_tsc(void)
     return ret;
 }
 
+u16 pmtimer_ioport VAR16VISIBLE;
+u32 pmtimer_wraps VARLOW;
+u32 pmtimer_last VARLOW;
+
+void pmtimer_init(u16 ioport, u32 khz)
+{
+    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 (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 89e928c..1603a57 100644
--- a/src/util.h
+++ b/src/util.h
@@ -312,6 +312,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);