[SeaBIOS] [PATCH] add acpi pmtimer support

Don Slutz Don at CloudSwitch.Com
Thu Sep 6 14:18:48 CEST 2012


On 09/06/12 02:01, 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.
>
> [ v4: mask port ioport read ]
> [ v2: add CONFIG_PMTIMER ]
>
> Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
> ---
>   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..71b913e 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) & 0xffffff;
> +
> +    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();
Should this be moved up before the 1st if?  Looks like no_tsc will 
override this change.
>       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);
   -Don



More information about the SeaBIOS mailing list