Skip to contentSkip to conversation

High-res-timers part 2 (x86 platform code) take 19

PATCH New george anzinger 1 participant 1 message Dec 6, 2002

lore
Share & tools
lore
#0 lore raw

PATCH 2/3 High-res-timers part 2 (x86 platform code) take 19

This is the platform part of the high-res timers for the x86.

This patch, in conjunction with the "core" high-res-timers patch implements high resolution timers on the i386 platforms. The high-res-timers use the periodic interrupt to "remind" the system to look at the clock. The clock should be relatively high resolution (1 micro second or better). This patch allows configuring of three possible clocks, the TSC, the ACPI pm timer, or the Programmable interrupt timer (PIT). Most of the changes in this patch are in the arch/i386/kernel/timer/* code.

This patch uses (if available) the APIC timer(s) to generate 1/HZ ticks and sub 1/HZ ticks as needed. The PIT still interrupts, but if the APIC timer is available, just causes the wall clock update. No attempt is made to make this interrupt happen on jiffie boundaries, however, the APIC timers are disciplined to expire on 1/HZ boundaries to give consistent timer latencies WRT to the system time.

With this patch applied and enabled (at config time in the processor feature section), the system clock will be the specified clock. The PIT is not used to keep track of time, but only to remind the system to look at the clock. Sub jiffies are kept and available for code that knows how to use them.

Depends on the core high res timers patch.

Patch is against 2.5.50-bk5

This patch as well as the POSIX clocks & timers patch is available on the project site:
http://sourceforge.net/projects/high-res-timers/

The 3 parts to the high res timers are:
core The core kernel (i.e. platform independent) changes
*i386 The high-res changes for the i386 (x86) platform
hrposix The changes to the POSIX clocks & timers patch to
use high-res timers

Please apply.

Signature · 5 lines
George Anzinger   [email protected]
High-res-timers: 
http://sourceforge.net/projects/high-res-timers/
Preemption patch:
http://www.kernel.org/pub/linux/kernel/people/rml
arch/i386/Kconfig +100 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk5-core/arch/i386/Kconfig linux/arch/i386/Kconfig
@@ -323,6 +323,106 @@
 
 	  If you don't know what to do here, say N.
 
+config HIGH_RES_TIMERS
+	bool "Configure High-Resolution-Timers"
+	help
+	  POSIX timers are available by default.  This option enables
+	  high resolution POSIX timers.  With this option the resolution
+	  is at least 1 micro second.  High resolution is not free.  If
+	  enabled this option will add a small overhead each time a
+	  timer expires that is not on a 1/HZ tick boundry.  If no such
+	  timers are used the overhead is nil.
+
+	  This option enables two additional POSIX CLOCKS,
+	  CLOCK_REALTIME_HR and CLOCK_MONOTONIC_HR.  Note that this
+	  option does not change the resolution of CLOCK_REALTIME or
+	  CLOCK_MONOTONIC which remain at 1/HZ resolution.
+
+choice
+	prompt "Clock source?"
+	default HIGH_RES_TIMER_TSC
+	help 
+	  This option allows you to choose the wall clock timer for your
+	  system.  With high resolution timers on the x86 platforms it
+	  is best to keep the interrupt generating timer separate from
+	  the time keeping timer.  On x86 platforms there are three
+	  possible sources implemented for the wall clock.  These are:
+ 
+  	  <timer>				<resolution>
+ 	  ACPI power management (pm) timer	~280 nano seconds
+  	  TSC (Time Stamp Counter)		1/CPU clock
+ 	  PIT (Programmable Interrupt Timer)	~838 nano seconds
+
+	  The PIT is always used to generate clock interrupts but, in
+	  SMP systems the APIC timers are used to drive the timer list
+	  code.  This means that, in SMP systems the PIT will not be
+	  programmed to generate sub jiffie events and can give
+	  reasonable service as the clock interrupt. In non SMP (UP)
+	  systems it will be programmed to interrupt when the next timer
+	  is to expire or on the next 1/HZ tick.  For this reason it is
+	  best to not use this timer as the wall clock timer in UP
+	  systems.  This timer has a resolution of 838 nano seconds.  IN
+	  UP SYSTEMS THIS OPTION SHOULD ONLY BE USED IF BOTH ACPI AND
+	  TSC ARE NOT AVAILABLE.
+
+	  The TSC runs at the cpu clock rate (i.e. its resolution is
+	  1/CPU clock) and it has a very low access time.  However, it
+	  is subject, in some (incorrect) processors, to throttling to
+	  cool the cpu, and to other slow downs during power management.
+	  If your system has power managment code active these changes
+	  are tracked by the TSC timer code.  If your cpu is correct and
+	  does not change the TSC frequency for throttling or power
+	  management outside of the power managment kernel code, this is
+	  the best clock timer.
+
+	  The ACPI pm timer is available on systems with Advanced
+	  Configuration and Power Interface support.  The pm timer is
+	  available on these systems even if you don't use or enable
+	  ACPI in the software or the BIOS (but see Default ACPI pm
+	  timer address).  The timer has a resolution of about 280
+	  nanoseconds, however, the access time is a bit higher than
+	  that of the TSC.  Since it is part of ACPI it is intended to
+	  keep track of time while the system is under power management,
+	  thus it is not subject to the power management problems of the
+	  TSC.
+
+	  If you enable the ACPI pm timer and it can not be found, it is
+	  possible that your BIOS is not producing the ACPI table or
+	  that your machine does not support ACPI.  In the former case,
+	  see "Default ACPI pm timer address".  If the timer is not
+	  found the boot will fail when trying to calibrate the 'delay'
+	  loop.
+
+config HIGH_RES_TIMER_ACPI_PM
+	bool "ACPI-pm-timer"
+	
+config HIGH_RES_TIMER_TSC
+	bool "Time-stamp-counter/TSC"
+	depends on X86_TSC
+
+config HIGH_RES_TIMER_PIT
+	bool "Programable-interrupt-timer/PIT"
+	  
+endchoice	  
+
+config HIGH_RES_TIMER_ACPI_PM_ADD
+	int "Default ACPI pm timer address"
+	depends on HIGH_RES_TIMER_ACPI_PM
+	default 0
+	help
+	  This option is available for use on systems where the BIOS
+	  does not generate the ACPI tables if ACPI is not enabled.  For
+	  example some BIOSes will not generate the ACPI tables if APM
+	  is enabled.  The ACPI pm timer is still available but can not
+	  be found by the software.  This option allows you to supply
+	  the needed address.  When the high resolution timers code
+	  finds a valid ACPI pm timer address it reports it in the boot
+	  messages log (look for lines that begin with
+	  "High-res-timers:").  You can turn on the ACPI support in the
+	  BIOS, boot the system and find this value.  You can then enter
+	  it at configure time.  Both the report and the entry are in
+	  decimal.
+
 config PREEMPT
 	bool "Preemptible Kernel"
 	help
arch/i386/kernel/apic.c +9 -4
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk5-core/arch/i386/kernel/apic.c linux/arch/i386/kernel/apic.c
@@ -23,6 +23,7 @@
 #include <linux/interrupt.h>
 #include <linux/mc146818rtc.h>
 #include <linux/kernel_stat.h>
+#include <linux/hrtime.h>
 
 #include <asm/atomic.h>
 #include <asm/smp.h>
@@ -800,7 +801,7 @@
  * P5 APIC double write bug.
  */
 
-#define APIC_DIVISOR 16
+#define APIC_DIVISOR 1
 
 void __setup_APIC_LVTT(unsigned int clocks)
 {
@@ -811,12 +812,12 @@
 	apic_write_around(APIC_LVTT, lvtt1_value);
 
 	/*
-	 * Divide PICLK by 16
+	 * Divide PICLK by 1
 	 */
 	tmp_value = apic_read(APIC_TDCR);
 	apic_write_around(APIC_TDCR, (tmp_value
 				& ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE))
-				| APIC_TDR_DIV_16);
+				| APIC_TDR_DIV_1);
 
 	apic_write_around(APIC_TMICT, clocks/APIC_DIVISOR);
 }
@@ -914,7 +915,7 @@
 	return result;
 }
 
-static unsigned int calibration_result;
+static unsigned int calibration_result = 1000;
 
 int dont_use_local_apic_timer __initdata = 0;
 
@@ -935,6 +936,8 @@
 	 */
 	setup_APIC_timer(calibration_result);
 
+	compute_latch(calibration_result);
+
 	local_irq_enable();
 }
 
@@ -1025,6 +1028,8 @@
 			__setup_APIC_LVTT(calibration_result/prof_counter[cpu]);
 			prof_old_multiplier[cpu] = prof_counter[cpu];
 		}
+
+		discipline_timer(cpu);
 
 #ifdef CONFIG_SMP
 		update_process_times(user_mode(regs));
arch/i386/kernel/time.c +98 -25

199 lines not on this page · raw message

arch/i386/kernel/timers/Makefile +6 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk5-core/arch/i386/kernel/timers/Makefile linux/arch/i386/kernel/timers/Makefile
@@ -6,6 +6,12 @@
 
 obj-y += timer_tsc.o
 obj-y += timer_pit.o
+obj-$(CONFIG_X86_TSC) -= timer_pit.o
+obj-$(CONFIG_HIGH_RES_TIMERS) -= timer_tsc.o
 obj-$(CONFIG_X86_CYCLONE)   += timer_cyclone.o
+obj-$(CONFIG_HIGH_RES_TIMER_ACPI_PM) += hrtimer_pm.o
+obj-$(CONFIG_HIGH_RES_TIMER_ACPI_PM) += high-res-tbxfroot.o
+obj-$(CONFIG_HIGH_RES_TIMER_TSC) += hrtimer_tsc.o
+obj-$(CONFIG_HIGH_RES_TIMER_PIT) += hrtimer_pit.o
 
 include $(TOPDIR)/Rules.make
arch/i386/kernel/timers/high-res-tbxfroot.c +263 -0

263 lines not on this page · raw message

arch/i386/kernel/timers/hrtimer_pit.c +165 -0

165 lines not on this page · raw message

arch/i386/kernel/timers/hrtimer_pm.c +198 -0

198 lines not on this page · raw message

arch/i386/kernel/timers/hrtimer_tsc.c +289 -0

289 lines not on this page · raw message

arch/i386/kernel/timers/timer.c +18 -1
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk5-core/arch/i386/kernel/timers/timer.c linux/arch/i386/kernel/timers/timer.c
@@ -1,15 +1,32 @@
 #include <linux/kernel.h>
+#include <linux/hrtime.h>
 #include <asm/timer.h>
-
+/*
+ * export this here so it can be used by more than one clock source
+ */
+unsigned long fast_gettimeoffset_quotient;
 /* list of externed timers */
 extern struct timer_opts timer_pit;
 extern struct timer_opts timer_tsc;
+extern struct timer_opts hrtimer_tsc;
+extern struct timer_opts hrtimer_pm;
+extern struct timer_opts hrtimer_pit;
 
 /* list of timers, ordered by preference, NULL terminated */
 static struct timer_opts* timers[] = {
+#ifdef CONFIG_HIGH_RES_TIMERS
+#ifdef CONFIG_HIGH_RES_TIMER_ACPI_PM
+	&hrtimer_pm,
+#elif  CONFIG_HIGH_RES_TIMER_TSC
+	&hrtimer_tsc,
+#elif  CONFIG_HIGH_RES_TIMER_PIT
+	&hrtimer_pit,
+#endif
+#else
 	&timer_tsc,
 #ifndef CONFIG_X86_TSC
 	&timer_pit,
+#endif
 #endif
 	NULL,
 };
arch/i386/kernel/timers/timer_pit.c +1 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk5-core/arch/i386/kernel/timers/timer_pit.c linux/arch/i386/kernel/timers/timer_pit.c
@@ -10,6 +10,7 @@
 #include <asm/mpspec.h>
 #include <asm/timer.h>
 #include <asm/io.h>
+#include <linux/hrtime.h>
 
 extern spinlock_t i8259A_lock;
 extern spinlock_t i8253_lock;
arch/i386/kernel/timers/timer_tsc.c +1 -1
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk5-core/arch/i386/kernel/timers/timer_tsc.c linux/arch/i386/kernel/timers/timer_tsc.c
@@ -26,7 +26,7 @@
  * Equal to 2^32 * (1 / (clocks per usec) ).
  * Initialized in time_init.
  */
-unsigned long fast_gettimeoffset_quotient;
+extern unsigned long fast_gettimeoffset_quotient;
 
 static unsigned long get_offset_tsc(void)
 {
arch/i386/mach-generic/do_timer.h +5 -0
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude linux-2.5.50-bk5-core/arch/i386/mach-generic/do_timer.h linux/arch/i386/mach-generic/do_timer.h
@@ -16,6 +16,11 @@
 static inline void do_timer_interrupt_hook(struct pt_regs *regs)
 {
 	do_timer(regs);
+        IF_HIGH_RES(
+                if (!(new_jiffie() & 1))
+                        return;
+                jiffies_intr = 0;
+                )
 /*
  * In the SMP case we use the local APIC timer interrupt to do the
  * profiling, except when we simulate SMP mode on a uniprocessor
include/asm-i386/hrtime-M386.h +272 -0

272 lines not on this page · raw message

include/asm-i386/hrtime-M586.h +170 -0

170 lines not on this page · raw message

include/asm-i386/hrtime-Macpi.h +190 -0

190 lines not on this page · raw message

include/asm-i386/hrtime.h +523 -0

523 lines not on this page · raw message

include/asm-i386/sc_math.h +139 -0

139 lines not on this page · raw message