From: john stultz On Fri, 2003-11-21 at 11:53, Andrew Morton wrote: > > Also, I was going to sync up w/ you today and send you my latest version > > to reduce the number of little fix patches you have to manage, but if > > you'd prefer I can do that after I track down the issue you're seeing. > > OK, I'll do mm5 this afternoon. I'll be out of town this weekend, then out > of the country from Nov27->Dec14 so I'm likely to be even less than usually > useful for some time. Here it is then. This patch depends on Dominik Brodowski's "acpi-pm-timer" patch found in mm4. It fixes a compile bug, cleans up the math, adds lost-tick compensation and monotonic_clock, fixes a bug in the ACPI table mapping and moves the config option under the ACPI menu. Additionally the patch includes additional fixes found during testing in -mm3 and -mm4. This patch replaces the following broken out patches from -mm4: acpi-pm-timer-fixes.patch acpi-pm_timer-init-cpu_khz.patch timer_pm-fix-fix-fix.patch Many thanks to Dominik for the great work, and Thomas Schlichter for the excellent bug hunting! Documentation/kernel-parameters.txt | 2 arch/i386/Kconfig | 18 ----- arch/i386/kernel/acpi/boot.c | 10 ++- arch/i386/kernel/timers/common.c | 20 ++++++ arch/i386/kernel/timers/timer_cyclone.c | 21 ------ arch/i386/kernel/timers/timer_pm.c | 105 +++++++++++++++++++++++++------- drivers/acpi/Kconfig | 18 +++++ include/asm-i386/timer.h | 1 8 files changed, 132 insertions(+), 63 deletions(-) diff -puN arch/i386/Kconfig~acpi-pm-timer-fixes-2 arch/i386/Kconfig --- 25/arch/i386/Kconfig~acpi-pm-timer-fixes-2 2003-12-30 16:49:29.000000000 -0800 +++ 25-akpm/arch/i386/Kconfig 2003-12-30 16:49:29.000000000 -0800 @@ -416,24 +416,6 @@ config HPET_TIMER 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 -puN arch/i386/kernel/acpi/boot.c~acpi-pm-timer-fixes-2 arch/i386/kernel/acpi/boot.c --- 25/arch/i386/kernel/acpi/boot.c~acpi-pm-timer-fixes-2 2003-12-30 16:49:29.000000000 -0800 +++ 25-akpm/arch/i386/kernel/acpi/boot.c 2003-12-30 16:49:29.000000000 -0800 @@ -363,15 +363,19 @@ static int __init acpi_parse_hpet(unsign } #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 -puN arch/i386/kernel/timers/common.c~acpi-pm-timer-fixes-2 arch/i386/kernel/timers/common.c --- 25/arch/i386/kernel/timers/common.c~acpi-pm-timer-fixes-2 2003-12-30 16:49:29.000000000 -0800 +++ 25-akpm/arch/i386/kernel/timers/common.c 2003-12-30 16:49:29.000000000 -0800 @@ -137,3 +137,23 @@ bad_calibration: } #endif +/* calculate cpu_khz */ +void __init init_cpu_khz(void) +{ + if (cpu_has_tsc) { + unsigned long tsc_quotient = calibrate_tsc(); + if (tsc_quotient) { + /* report CPU clock rate in Hz. + * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) = + * clock/second. Our precision is about 100 ppm. + */ + { unsigned long eax=0, edx=1000; + __asm__("divl %2" + :"=a" (cpu_khz), "=d" (edx) + :"r" (tsc_quotient), + "0" (eax), "1" (edx)); + printk("Detected %lu.%03lu MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000); + } + } + } +} diff -puN arch/i386/kernel/timers/timer_cyclone.c~acpi-pm-timer-fixes-2 arch/i386/kernel/timers/timer_cyclone.c --- 25/arch/i386/kernel/timers/timer_cyclone.c~acpi-pm-timer-fixes-2 2003-12-30 16:49:29.000000000 -0800 +++ 25-akpm/arch/i386/kernel/timers/timer_cyclone.c 2003-12-30 16:49:29.000000000 -0800 @@ -212,26 +212,7 @@ static int __init init_cyclone(char* ove } } - /* init cpu_khz. - * XXX - This should really be done elsewhere, - * and in a more generic fashion. -johnstul@us.ibm.com - */ - if (cpu_has_tsc) { - unsigned long tsc_quotient = calibrate_tsc(); - if (tsc_quotient) { - /* report CPU clock rate in Hz. - * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) = - * clock/second. Our precision is about 100 ppm. - */ - { unsigned long eax=0, edx=1000; - __asm__("divl %2" - :"=a" (cpu_khz), "=d" (edx) - :"r" (tsc_quotient), - "0" (eax), "1" (edx)); - printk("Detected %lu.%03lu MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000); - } - } - } + init_cpu_khz(); /* Everything looks good! */ return 0; diff -puN arch/i386/kernel/timers/timer_pm.c~acpi-pm-timer-fixes-2 arch/i386/kernel/timers/timer_pm.c --- 25/arch/i386/kernel/timers/timer_pm.c~acpi-pm-timer-fixes-2 2003-12-30 16:49:29.000000000 -0800 +++ 25-akpm/arch/i386/kernel/timers/timer_pm.c 2003-12-30 16:49:29.000000000 -0800 @@ -30,7 +30,12 @@ u32 pmtmr_ioport = 0; /* 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) { @@ -45,41 +50,109 @@ static int init_pmtmr(char* override) /* "verify" this timing source */ value1 = inl(pmtmr_ioport); - value1 &= 0xFFFFFF; + value1 &= ACPI_PM_MASK; for (i=0; i < 10000; i++) { value2 = inl(pmtmr_ioport); - value2 &= 0xFFFFFF; + value2 &= ACPI_PM_MASK; if (value2 == value1) continue; if (value2 > value1) - return 0; + goto pm_good; if ((value2 < value1) && ((value2) < 0xFFF)) - return 0; + goto pm_good; printk(KERN_INFO "PM-Timer had inconsistent results: 0x%#x, 0x%#x - aborting.\n", value1, value2); return -EINVAL; } printk(KERN_INFO "PM-Timer had no reasonable result: 0x%#x - aborting.\n", value1); return -ENODEV; + +pm_good: + init_cpu_khz(); + return 0; } +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 + * - Called while holding the writer xtime_lock */ 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 = cyc2us(delta); + + /* update the monotonic base value */ + monotonic_base += delta*NSEC_PER_USEC; + write_sequnlock(&monotonic_lock); + + /* convert to ticks */ + delta += offset_delay; + lost = delta/(USEC_PER_SEC/HZ); + offset_delay = delta%(USEC_PER_SEC/HZ); + + + /* 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 pmtmr */ + this_offset = inl(pmtmr_ioport) & ACPI_PM_MASK; + + /* convert to nanoseconds */ + ret = (this_offset - last_offset) & ACPI_PM_MASK; + ret = base + (cyc2us(ret)*NSEC_PER_USEC); + return ret; } - /* * copied from delay_pit */ @@ -99,6 +172,7 @@ static void delay_pmtmr(unsigned long lo /* * get the offset (in microseconds) from the last call to mark_offset() + * - Called holding a reader xtime_lock */ static unsigned long get_offset_pmtmr(void) { @@ -106,21 +180,10 @@ static unsigned long get_offset_pmtmr(vo 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 -puN Documentation/kernel-parameters.txt~acpi-pm-timer-fixes-2 Documentation/kernel-parameters.txt --- 25/Documentation/kernel-parameters.txt~acpi-pm-timer-fixes-2 2003-12-30 16:49:29.000000000 -0800 +++ 25-akpm/Documentation/kernel-parameters.txt 2003-12-30 16:49:29.000000000 -0800 @@ -232,7 +232,7 @@ running once the system is up. 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 -puN drivers/acpi/Kconfig~acpi-pm-timer-fixes-2 drivers/acpi/Kconfig --- 25/drivers/acpi/Kconfig~acpi-pm-timer-fixes-2 2003-12-30 16:49:29.000000000 -0800 +++ 25-akpm/drivers/acpi/Kconfig 2003-12-30 16:49:29.000000000 -0800 @@ -263,5 +263,23 @@ config ACPI_RELAXED_AML 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, you should say "Y" here. + endmenu diff -puN include/asm-i386/timer.h~acpi-pm-timer-fixes-2 include/asm-i386/timer.h --- 25/include/asm-i386/timer.h~acpi-pm-timer-fixes-2 2003-12-30 16:49:29.000000000 -0800 +++ 25-akpm/include/asm-i386/timer.h 2003-12-30 16:49:29.000000000 -0800 @@ -40,6 +40,7 @@ extern struct timer_opts timer_cyclone; #endif extern unsigned long calibrate_tsc(void); +extern void init_cpu_khz(void); #ifdef CONFIG_HPET_TIMER extern struct timer_opts timer_hpet; extern unsigned long calibrate_tsc_hpet(unsigned long *tsc_hpet_quotient_ptr); _