Re: ACPI PM-Timer rev.2 [Was: Re: ACPI PM-Timer [Was: Re: [RFC][PATCH] must fix lists]]

From: john stultz (johnstul_at_us.ibm.com)
Date: 11/04/03

  • Next message: Chris Vine: "Re: 2.6.0-test9 - poor swap performance on low end machines"
    To: Dominik Brodowski <linux@brodo.de>
    Date:	04 Nov 2003 14:03:20 -0800
    
    

    On Mon, 2003-10-27 at 15:01, Dominik Brodowski wrote:
    > On Mon, Oct 27, 2003 at 11:07:19AM -0800, john stultz wrote:
    > > Ah, OK. Well, I'd prefer the manual ACPI parsing personally, but having
    > > tried and failed to implement it once myself, I'd more prefer not to do
    > > it myself. ;)
    >
    > Here it is, and it is soooo much nicer than my previous implementation. It
    > lacks the "lost-ticks compensation" and math cleanup John is working on, but
    > otherwise:

    Finally, here are my fixes to Dominik's patch (meant to send these out
    last week, but got swamped). Basically it cleans up some of the math,
    adds lost-tick compensation and monotonic_clock, fixes up a bit of the
    ACPI table mapping, and moves the config option under the ACPI menu. Oh
    yea, and it compiles, too ;)

    Works well for me, but needs more testing.

    Applies on top of Dominik's ACPI PM-timer rev.2 patch.
    http://www.ussg.iu.edu/hypermail/linux/kernel/0310.3/0669.html

    Many thanks to Dominik for the great work and getting this started.
    -john

    diff -Nru a/Documentation/kernel-parameters.txt
    b/Documentation/kernel-parameters.txt
    --- a/Documentation/kernel-parameters.txt Tue Nov 4 13:30:42 2003
    +++ b/Documentation/kernel-parameters.txt Tue Nov 4 13:30:42 2003
    @@ -214,7 +214,7 @@
                             Forces specified timesource (if avaliable) to be used
                             when calculating gettimeofday(). If specicified timesource
                             is not avalible, it defaults to PIT.
    - Format: { pit | tsc | cyclone | ... }
    + Format: { pit | tsc | cyclone | pmtmr }
     
             hpet= [IA-32,HPET] option to disable HPET and use PIT.
                             Format: disable
    diff -Nru a/arch/i386/Kconfig b/arch/i386/Kconfig
    --- a/arch/i386/Kconfig Tue Nov 4 13:30:42 2003
    +++ b/arch/i386/Kconfig Tue Nov 4 13:30:42 2003
    @@ -411,24 +411,6 @@
     config HPET_EMULATE_RTC
             def_bool HPET_TIMER && RTC=y
     
    -config X86_PM_TIMER
    - bool "Power Management Timer Support"
    - depends on (!X86_VISWS && !X86_VISWS) && EXPERIMENTAL
    - default n
    - help
    - The Power Management Timer is available on all ACPI-capable,
    - in most cases even if ACPI is unusable or blacklisted.
    -
    - This timing source is not affected by powermanagement features
    - like aggressive processor idling, throttling, frequency and/or
    - voltage scaling, unlike the commonly used Time Stamp Counter
    - (TSC) timing source.
    -
    - So, if you see messages like 'Losing too many ticks!' in the
    - kernel logs, and/or you are using a this on a notebook which
    - does not yet have an HPET (see above), you should say "Y"
    - here. Otherwise, say "N".
    -
     config SMP
             bool "Symmetric multi-processing support"
             ---help---
    diff -Nru a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c
    --- a/arch/i386/kernel/acpi/boot.c Tue Nov 4 13:30:42 2003
    +++ b/arch/i386/kernel/acpi/boot.c Tue Nov 4 13:30:42 2003
    @@ -319,15 +319,19 @@
     }
     #endif
     
    -/* detect the location of the ACPI PM Timer
    +/* detect the location of the ACPI PM Timer */
     #ifdef CONFIG_X86_PM_TIMER
     extern u32 pmtmr_ioport;
     
     static int __init acpi_parse_fadt(unsigned long phys, unsigned long
    size)
     {
    - struct fadt_descriptor_rev2 *fadt;
    + struct fadt_descriptor_rev2 *fadt =0;
     
    - fadt = __va(phys);
    + fadt = (struct fadt_descriptor_rev2*) __acpi_map_table(phys,size);
    + if(!fadt) {
    + printk(KERN_WARNING PREFIX "Unable to map FADT\n");
    + return 0;
    + }
     
             if (fadt->revision >= FADT2_REVISION_ID) {
                     /* FADT rev. 2 */
    diff -Nru a/arch/i386/kernel/timers/timer_pm.c
    b/arch/i386/kernel/timers/timer_pm.c
    --- a/arch/i386/kernel/timers/timer_pm.c Tue Nov 4 13:30:42 2003
    +++ b/arch/i386/kernel/timers/timer_pm.c Tue Nov 4 13:30:42 2003
    @@ -30,7 +30,12 @@
     
     /* value of the Power timer at last timer interrupt */
     static u32 offset_tick;
    +static u32 offset_delay;
     
    +static unsigned long long monotonic_base;
    +static seqlock_t monotonic_lock = SEQLOCK_UNLOCKED;
    +
    +#define ACPI_PM_MASK 0xFFFFFF /* limit it to 24 bits */
     
     static int init_pmtmr(char* override)
     {
    @@ -62,23 +67,88 @@
             return -ENODEV;
     }
     
    +static inline u32 cyc2us(u32 cycles)
    +{
    + /* The Power Management Timer ticks at 3.579545 ticks per microsecond.
    + * 1 / PM_TIMER_FREQUENCY == 0.27936511 =~ 286/1024 [error: 0.024%]
    + *
    + * Even with HZ = 100, delta is at maximum 35796 ticks, so it can
    + * easily be multiplied with 286 (=0x11E) without having to fear
    + * u32 overflows.
    + */
    + cycles *= 286;
    + return (cycles >> 10);
    +}
     
     /*
      * this gets called during each timer interrupt
      */
     static void mark_offset_pmtmr(void)
     {
    + u32 lost, delta, last_offset;
    + static int first_run = 1;
    + last_offset = offset_tick;
    +
    + write_seqlock(&monotonic_lock);
    +
             offset_tick = inl(pmtmr_ioport);
    - offset_tick &= 0xFFFFFF; /* limit it to 24 bits */
    + offset_tick &= ACPI_PM_MASK; /* limit it to 24 bits */
    +
    + /* calculate tick interval */
    + delta = (offset_tick - last_offset) & ACPI_PM_MASK;
    +
    + /* convert to usecs */
    + delta = offset_delay + cyc2us(delta);
    +
    + /* convert to ticks */
    + lost = delta/(USEC_PER_SEC/HZ);
    + offset_delay = delta%(USEC_PER_SEC/HZ);
    +
    + /* update the monotonic base value */
    + monotonic_base += delta;
    + write_sequnlock(&monotonic_lock);
    +
    +
    + /* compensate for lost ticks */
    + if (lost >= 2)
    + jiffies += lost - 1;
    +
    + /* don't calculate delay for first run,
    + or if we've got less then a tick */
    + if (first_run || (lost < 1)) {
    + first_run = 0;
    + offset_delay = 0;
    + }
    +
             return;
     }
     
     
     static unsigned long long monotonic_clock_pmtmr(void)
     {
    - return 0;
    -}
    + u32 last_offset, this_offset;
    + unsigned long long base, ret;
    + unsigned seq;
    +
     
    + /* atomically read monotonic base & last_offset */
    + do {
    + seq = read_seqbegin(&monotonic_lock);
    + last_offset = offset_tick;
    + base = monotonic_base;
    + } while (read_seqretry(&monotonic_lock, seq));
    +
    +
    + /* Read the cyclone counter */
    +
    + this_offset = inl(pmtmr_ioport) & ACPI_PM_MASK;
    +
    +
    + /* convert to nanoseconds */
    + ret = base + ((this_offset - last_offset) & ACPI_PM_MASK);
    + ret = cyc2us(ret)*1000;
    + return ret;
    +}
     
     /*
      * copied from delay_pit
    @@ -106,21 +176,10 @@
     
             offset = offset_tick;
             now = inl(pmtmr_ioport);
    - now &= 0xFFFFFF;
    - if (likely(offset < now))
    - delta = now - offset;
    - else if (offset > now)
    - delta = (0xFFFFFF - offset) + now;
    + now &= ACPI_PM_MASK;
    + delta = (now - offset)&ACPI_PM_MASK;
     
    - /* The Power Management Timer ticks at 3.579545 ticks per microsecond.
    - * 1 / PM_TIMER_FREQUENCY == 0.27936511 =~ 286/1024 [error: 0.024%]
    - *
    - * Even with HZ = 100, delta is at maximum 35796 ticks, so it can
    - * easily be multiplied with 286 (=0x11E) without having to fear
    - * u32 overflows.
    - */
    - delta *= 286;
    - return (unsigned long) (delta >> 10);
    + return (unsigned long) offset_delay + cyc2us(delta);
     }
     
     
    diff -Nru a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
    --- a/drivers/acpi/Kconfig Tue Nov 4 13:30:42 2003
    +++ b/drivers/acpi/Kconfig Tue Nov 4 13:30:42 2003
    @@ -269,5 +269,24 @@
               particular, many Toshiba laptops require this for correct operation
               of the AC module.
     
    +config X86_PM_TIMER
    + bool "Power Management Timer Support"
    + depends on X86 && ACPI
    + depends on ACPI_BOOT && EXPERIMENTAL
    + default n
    + help
    + The Power Management Timer is available on all ACPI-capable,
    + in most cases even if ACPI is unusable or blacklisted.
    +
    + This timing source is not affected by powermanagement features
    + like aggressive processor idling, throttling, frequency and/or
    + voltage scaling, unlike the commonly used Time Stamp Counter
    + (TSC) timing source.
    +
    + So, if you see messages like 'Losing too many ticks!' in the
    + kernel logs, and/or you are using a this on a notebook which
    + does not yet have an HPET (see above), you should say "Y"
    + here.
    +
     endmenu
     

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/


  • Next message: Chris Vine: "Re: 2.6.0-test9 - poor swap performance on low end machines"

    Relevant Pages

    • Re: md patches in -mm
      ... Ignoring ACPI timer override. ... WDC WD2000JB-32EVA0, ATA DISK drive ... SCSI device sda: write cache: enabled, read cache: enabled, doesn't support DPO or FUA ...
      (Linux-Kernel)
    • Asus A8N-SLI Deluxe latest BIOS wants acpi_use_timer_override
      ... 8254 timer not connected to IO-APIC ... ...trying to set up timer as Virtual Wire IRQ... ... Is there some way we can tell, given we have a chipset with a potentially broken BIOS, from the configuration of the IOAPIC whether the timer override is needed or not? ... ACPI: ...
      (Linux-Kernel)
    • Re: [PATCH 4/4] x86_64 ioapic: Improve the heuristics for when check_timer fails.
      ... Using local APIC timer interrupts. ... Ignoring ACPI timer override. ... ACPI: PM-Timer IO Port: 0x1008 ... Using ACPI for SMP configuration information ...
      (Linux-Kernel)
    • [LOCKDEP] v2.6.23-rc4-rt1
      ... Ignoring ACPI timer override. ... CPU: L2 Cache: 1024K ... # AX.25 network device drivers ...
      (Linux-Kernel)
    • AMD64, 4GB, mttr questions
      ... ACPI: Local APIC address 0xfee00000 ... Using ACPI for SMP configuration information ... Calibrating delay using timer specific routine.. ... Allocate Port Service ...
      (Linux-Kernel)