new timeofday core subsystem (v A4)
Subsystems (5)
RFC PATCH 1/1 new timeofday core subsystem (v A4)
All,
This patch implements the architecture independent portion of
the time of day subsystem. For a brief description on the rework, see
here: http://lwn.net/Articles/120850/ (Many thanks to the LWN team for that clear writeup!)
Mostly this version is just a cleanup of the last release. One neat feature is the new sysfs interface which allows you to manually override the selected timesource while the system is running.
Included below is timeofday.c (which includes all the time of day management and accessor functions), ntp.c (which includes the ntp scaling calculation code, leapsecond processing, and ntp kernel state machine code), timesource.c (for timesource specific management functions), interface definition .h files, the example jiffies timesource (lowest common denominator time source, mainly for use as example code) and minimal hooks into arch independent code.
The patch does not function without minimal architecture specific hooks (i386, x86-64, ppc32, ppc64, ia64 and s390 examples to follow), and it should be able to be applied to a tree without affecting the code.
New in this version:
o Improved cyc2ns remainder handling
o Added getnstimeofday() interface
o Better timesource management
o Sysfs interface for overriding timesources
o Cleanups from Nish Aravamudan and Matt Mackall
Items still on the TODO list:
o make ntp adjustments be in ppb instead of ppm
o posix-timers integration
o boot time "timesource=" override option
I look forward to your comments and feedback.
thanks
-john
linux-2.6.12-rc2_timeofday-core_A4.patch
=========================================
drivers/Makefile +1 -0
@@ -64,3 +64,4 @@ obj-$(CONFIG_BLK_DEV_SGIIOC4) += sn/ obj-y += firmware/ obj-$(CONFIG_CRYPTO) += crypto/ +obj-$(CONFIG_NEWTOD) += timesource/
drivers/timesource/Makefile new file +1 -0
@@ -0,0 +1 @@ +obj-y += jiffies.o
drivers/timesource/jiffies.c new file +45 -0
45 lines not on this page · raw message
include/linux/ntp.h new file +22 -0
@@ -0,0 +1,22 @@ +/* linux/include/linux/ntp.h +* +* Copyright (C) 2003, 2004, 2005 IBM, John Stultz ([email protected]) +* +* This file NTP state machine accessor functions. +*/ + +#ifndef _LINUX_NTP_H +#define _LINUX_NTP_H +#include <linux/types.h> +#include <linux/time.h> +#include <linux/timex.h> + +/* NTP state machine interfaces */ +nsec_t ntp_scale (nsec_t value); +int ntp_advance (nsec_t value); +int ntp_adjtimex (struct timex *); +int ntp_leapsecond (struct timespec now); +void ntp_clear (void ); +int get_ntp_status (void ); + +#endif
include/linux/time.h +4 -0
@@ -27,6 +27,10 @@#ifdef __KERNEL__ +/* timeofday base types */ +typedef u64 nsec_t ; +typedef u64 cycle_t ; +/* Parameters used to convert the timespec values */ #ifndef USEC_PER_SEC #define USEC_PER_SEC (1000000L)
include/linux/timeofday.h new file +65 -0
65 lines not on this page · raw message
include/linux/timesource.h new file +159 -0
159 lines not on this page · raw message
init/main.c +2 -0
@@ -47,6 +47,7 @@#include <linux/rmap.h> #include <linux/mempolicy.h> #include <linux/key.h> +#include <linux/timeofday.h> #include <asm/io.h> #include <asm/bugs.h>
@@ -467,6 +468,7 @@pidhash_init ();init_timers ();softirq_init (); +timeofday_init ();time_init ();/*
kernel/Makefile +1 -0
@@ -9,6 +9,7 @@ rcupdate.o intermodule.o extable.o params.o posix-timers.o \ kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o +obj-$(CONFIG_NEWTOD) += timeofday.o timesource.o ntp.o obj-$(CONFIG_FUTEX) += futex.o obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o obj-$(CONFIG_SMP) += cpu.o spinlock.o
kernel/ntp.c new file +498 -0
498 lines not on this page · raw message
kernel/time.c +5 -0
@@ -38,6 +38,7 @@#include <asm/uaccess.h> #include <asm/unistd.h> +#include <linux/timeofday.h> /* * The timezone where the local system is located. Used as a default by some
@@ -227,6 +228,7 @@/* adjtimex mainly allows reading (and writing, if superuser) of * kernel time-keeping variables. used by xntpd. */ +#ifndef CONFIG_NEWTOD int do_adjtimex (struct timex *txc) {long ltemp, mtemp, save_adjust;
@@ -410,6 +412,7 @@notify_arch_cmos_timer (); return(result); } +#endif asmlinkage long sys_adjtimex (struct timex __user *txc_p) {
@@ -566,6 +569,7 @@#else +#ifndef CONFIG_NEWTOD /* * Simulate gettimeofday using do_gettimeofday which only allows a timeval * and therefore only yields usec accuracy
@@ -578,6 +582,7 @@ tv->tv_sec = x.tv_sec; tv->tv_nsec = x.tv_usec *NSEC_PER_USEC ; } +#endif /* CONFIG_NEWTOD */ #endif #if (BITS_PER_LONG <64 )
kernel/timeofday.c new file +522 -0
522 lines not on this page · raw message
kernel/timer.c +4 -0
@@ -577,6 +577,7 @@int tickadj =500 /HZ ? :1 ;/* microsecs */ +#ifndef CONFIG_NEWTOD /* * phase-lock loop variables */
@@ -807,6 +808,9 @@ } }while (ticks); } +#else /* CONFIG_NEWTOD */ +#define update_wall_time (x) +#endif /* CONFIG_NEWTOD */ /* * Called from the timer interrupt handler to charge one tick to the current
kernel/timesource.c new file +210 -0
210 lines not on this page · raw message
RFC PATCH 1/1 new timeofday arch specific hooks (v A4)
All,
This patch implements the minimal architecture specific hooks to
enable the new time of day subsystem code for i386, x86-64, ia64, ppc32, ppc64 and s390. It applies on top of my linux-2.6.12-rc2_timeofday- core_A4 patch and with this patch applied, you can test the new time of day subsystem.
Basically it configs in the NEWTOD code and cuts alot of code out of the build via #ifdefs. I know, I know, #ifdefs' are ugly and bad, and the final patch will just remove the old code. For now this allows us to be flexible and easily switch between the two implementations with a single define.
While there is code for all of the arches above, I am unable to fully test all of them with the limited time I have to spend on this work. i386 and x86-64 are reasonably well tested, ppc32 less so and the others hopefully still compile :)
New in this version:
o s390 arch support! (Big thanks to Martin Schwidefsky!)
Items still on the TODO list:
o Break up each arch into its own patch
o Get rid of #ifdefs
I look forward to your comments and feedback.
thanks
-john
linux-2.6.12-rc2_timeofday-arch_A4.patch
========================================
arch/i386/Kconfig +4 -0
@@ -14,6 +14,10 @@ 486, 586, Pentiums, and various instruction-set-compatible chips by AMD, Cyrix, and others. +config NEWTOD + bool + default y + config MMU bool default y
arch/i386/kernel/apm.c +3 -0
@@ -224,6 +224,7 @@#include <linux/smp_lock.h> #include <linux/dmi.h> #include <linux/suspend.h> +#include <linux/timeofday.h> #include <asm/system.h> #include <asm/uaccess.h>
@@ -1205,6 +1206,7 @@local_irq_disable ();device_power_down (PMSG_SUSPEND ); +timeofday_suspend_hook ();/* serialize with the timer interrupt */ write_seqlock (&xtime_lock);
@@ -1234,6 +1236,7 @@spin_unlock (&i8253_lock);write_sequnlock (&xtime_lock); +timeofday_resume_hook ();if (err ==APM_NO_ERROR ) err =APM_SUCCESS ;if (err !=APM_SUCCESS )
arch/i386/kernel/time.c +68 -4
167 lines not on this page · raw message
arch/i386/lib/delay.c +19 -0
@@ -23,10 +23,29 @@extern struct timer_opts * timer; +#ifndef CONFIG_NEWTOD void __delay (unsigned long loops) { cur_timer->delay (loops); } +#else +#include <linux/timeofday.h> +/* XXX - For now just use a simple loop delay +* This has cpufreq issues, but so did the old method. +*/ +void __delay (unsigned long loops) +{ +int d0; + __asm__ __volatile__( +"\tjmp 1f\n" +".align 16\n" +"1:\tjmp 2f\n" +".align 16\n" +"2:\tdecl %0\n\tjns 2b" + :"=&a" (d0) + :"0" (loops)); +} +#endif inline void __const_udelay (unsigned long xloops) {
arch/ia64/Kconfig +5 -1
@@ -18,6 +18,10 @@ page at <http://www.linuxia64.org/> and a mailing list at <[email protected]>. +config NEWTOD + bool + default y + config 64BIT bool default y
@@ -36,7 +40,7 @@ config TIME_INTERPOLATION bool - default y + default n config EFI bool
arch/ia64/kernel/asm-offsets.c +2 -0
@@ -222,6 +222,7 @@DEFINE (IA64_MCA_CPU_INIT_STACK_OFFSET , offsetof (struct ia64_mca_cpu , init_stack));BLANK (); +#ifndef CONFIG_NEWTOD /* used by fsys_gettimeofday in arch/ia64/kernel/fsys.S */ DEFINE (IA64_TIME_INTERPOLATOR_ADDRESS_OFFSET , offsetof (struct time_interpolator , addr));DEFINE (IA64_TIME_INTERPOLATOR_SOURCE_OFFSET , offsetof (struct time_interpolator , source));
@@ -235,5 +236,6 @@DEFINE (IA64_TIME_SOURCE_CPU ,TIME_SOURCE_CPU );DEFINE (IA64_TIME_SOURCE_MMIO64 ,TIME_SOURCE_MMIO64 );DEFINE (IA64_TIME_SOURCE_MMIO32 ,TIME_SOURCE_MMIO32 ); +#endif /* CONFIG_NEWTOD */ DEFINE (IA64_TIMESPEC_TV_NSEC_OFFSET , offsetof (struct timespec , tv_nsec)); }
arch/ia64/kernel/fsys.S +12 -0
@@ -145,6 +145,7 @@ FSYS_RETURN END(fsys_set_tid_address) +#ifndef CONFIG_NEWTOD /* * Ensure that the time interpolator structure is compatible with the asm code */
@@ -326,6 +327,7 @@ EX(.fail_efault, st8 [r31] = r9) EX(.fail_efault, st8 [r23] = r21) FSYS_RETURN +#endif /* !CONFIG_NEWTOD */ .fail_einval: mov r8 = EINVAL mov r10 = -1
@@ -334,6 +336,7 @@ mov r8 = EFAULT mov r10 = -1 FSYS_RETURN +#ifndef CONFIG_NEWTOD END(fsys_gettimeofday) ENTRY(fsys_clock_gettime)
@@ -347,6 +350,7 @@ shl r30 = r32,15 br.many .gettime END(fsys_clock_gettime) +#endif /* !CONFIG_NEWTOD */ /* * long fsys_rt_sigprocmask (int how, sigset_t *set, sigset_t *oset, size_t sigsetsize).
@@ -687,7 +691,11 @@ data8 0 // setrlimit data8 0 // getrlimit // 1085 data8 0 // getrusage +#ifdef CONFIG_NEWTOD + data8 0 // gettimeofday +#else data8 fsys_gettimeofday // gettimeofday +#endif data8 0 // settimeofday data8 0 // select data8 0 // poll // 1090
@@ -854,7 +862,11 @@ data8 0 // timer_getoverrun data8 0 // timer_delete data8 0 // clock_settime +#ifdef CONFIG_NEWTOD + data8 0 // clock_gettime +#else data8 fsys_clock_gettime // clock_gettime +#endif data8 0 // clock_getres // 1255 data8 0 // clock_nanosleep data8 0 // fstatfs64
arch/ia64/kernel/time.c +19 -0
@@ -21,6 +21,7 @@#include <linux/efi.h> #include <linux/profile.h> #include <linux/timex.h> +#include <linux/timeofday.h> #include <asm/machvec.h> #include <asm/delay.h>
@@ -45,11 +46,13 @@#endif +#ifndef CONFIG_NEWTOD static struct time_interpolator itc_interpolator = { .shift =16 , .mask =0xffffffffffffffffLL , .source =TIME_SOURCE_CPU }; +#endif /* CONFIG_NEWTOD */ static irqreturn_t timer_interrupt (int irq,void *dev_id,struct pt_regs *regs)
@@ -211,6 +214,7 @@ local_cpu_data->nsec_per_cyc = ((NSEC_PER_SEC <<IA64_NSEC_PER_CYC_SHIFT ) + itc_freq/2 )/itc_freq; +#ifndef CONFIG_NEWTOD if (!(sal_platform_features &IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT )) { itc_interpolator.frequency = local_cpu_data->itc_freq; itc_interpolator.drift = itc_drift;
@@ -229,6 +233,7 @@#endif register_time_interpolator(&itc_interpolator); } +#endif /* CONFIG_NEWTOD */ /* Setup the CPU local timer tick */ ia64_cpu_local_tick ();
@@ -253,3 +258,17 @@*/ set_normalized_timespec (&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec); } + +/* arch specific timeofday hooks */ +nsec_t read_persistent_clock (void ) +{ +struct timespec ts; +efi_gettimeofday (&ts); +return (nsec_t)(ts.tv_sec *NSEC_PER_SEC + ts.tv_nsec); +} + +void sync_persistent_clock (struct timespec ts) +{ +/* XXX - Something should go here, no? */ +} +
arch/ia64/sn/kernel/sn2/timer.c +6 -0
@@ -19,6 +19,7 @@#include <asm/sn/shub_mmr.h> #include <asm/sn/clksupport.h> +#ifndef CONFIG_NEWTOD extern unsigned long sn_rtc_cycles_per_second; static struct time_interpolator sn2_interpolator = {
@@ -34,3 +35,8 @@ sn2_interpolator.addr =RTC_COUNTER_ADDR ; register_time_interpolator(&sn2_interpolator); } +#else +void __init sn_timer_init (void ) +{ +} +#endif
arch/ppc/Kconfig +4 -0
@@ -8,6 +8,10 @@ bool default y +config NEWTOD + bool + default y + config UID16 bool
arch/ppc/kernel/time.c +48 -0
93 lines not on this page · raw message
arch/ppc/platforms/chrp_time.c +2 -0
@@ -115,8 +115,10 @@chrp_cmos_clock_write (save_control,RTC_CONTROL );chrp_cmos_clock_write (save_freq_select,RTC_FREQ_SELECT ); +#ifndef CONFIG_NEWTOD if ( (time_state ==TIME_ERROR ) || (time_state ==TIME_BAD ) ) time_state =TIME_OK ; +#endif spin_unlock (&rtc_lock);return 0 ; }
arch/ppc64/Kconfig +4 -0
@@ -10,6 +10,10 @@ bool default y +config NEWTOD + bool + default y + config UID16 bool
arch/ppc64/kernel/sys_ppc32.c +2 -0
@@ -322,8 +322,10 @@ ret =do_adjtimex (&txc); +#ifndef CONFIG_NEWTOD /* adjust the conversion of TB to time of day to track adjtimex */ ppc_adjtimex (); +#endif if(put_user(txc.modes, &utp->modes) || __put_user(txc.offset, &utp->offset) ||
arch/ppc64/kernel/time.c +60 -0
132 lines not on this page · raw message
arch/s390/Kconfig +4 -0
@@ -127,6 +127,10 @@ This allows you to run 32-bit Linux/ELF binaries on your zSeries in 64 bit mode. Everybody wants this; say Y. +config NEWTOD + bool + default y + comment "Code generation options" choice
arch/s390/kernel/time.c +22 -0
@@ -29,6 +29,7 @@#include <linux/profile.h> #include <linux/timex.h> #include <linux/notifier.h> +#include <linux/timeofday.h> #include <asm/uaccess.h> #include <asm/delay.h>
@@ -89,6 +90,7 @@return (unsigned long ) now; } +#ifndef CONFIG_NEWTOD /* * This version of gettimeofday has microsecond resolution. */
@@ -149,7 +151,27 @@ }EXPORT_SYMBOL (do_settimeofday); +#endif +nsec_t read_persistent_clock (void ) +{ +unsigned long long nsecs; +/* +* The TOD clock counts from 1900-01-01. Bit 2^12 of the +* 64 bit register is micro-seconds. +*/ + nsecs =get_clock () -0x7d91048bca000000LL ; +/* +* Calc nsecs * 1000 / 4096 without overflow and +* without loosing too many bits. +*/ + nsecs = (((((nsecs >>3 ) *5 ) >>3 ) *5 ) >>3 ) *5 ; +return (nsec_t ) nsecs; +} + +void sync_persistent_clock (struct timespec ts) +{ +}#ifdef CONFIG_PROFILING #define s390_do_profile (regs) profile_tick(CPU_PROFILING, regs)
arch/x86_64/Kconfig +4 -0
@@ -24,6 +24,10 @@ bool default y +config NEWTOD + bool + default y + config MMU bool default y
arch/x86_64/kernel/time.c +56 -1
141 lines not on this page · raw message
arch/x86_64/kernel/vsyscall.c +5 -0
@@ -217,8 +217,13 @@BUG_ON ((unsigned long ) &vtime !=VSYSCALL_ADDR (__NR_vtime));BUG_ON ((VSYSCALL_ADDR (0 ) !=__fix_to_virt (VSYSCALL_FIRST_PAGE )));map_vsyscall (); +/* XXX - disable vsyscall gettimeofday for now */ +#ifndef CONFIG_NEWTOD sysctl_vsyscall =1 ;register_sysctl_table (kernel_root_table2,0 ); +#else + sysctl_vsyscall =0 ; +#endif return 0 ; }
include/asm-generic/div64.h +9 -0
@@ -55,4 +55,13 @@#endif /* BITS_PER_LONG */ +#ifndef div_long_long_rem +#define div_long_long_rem (dividend,divisor,remainder) \ +({ \ + u64 result = dividend; \ + *remainder = do_div(result,divisor); \ + result; \ +}) +#endif +#endif /* _ASM_GENERIC_DIV64_H */
include/asm-ppc64/time.h +1 -0
@@ -21,6 +21,7 @@#include <asm/processor.h> #include <asm/paca.h> #include <asm/iSeries/HvCall.h> +#include <asm/percpu.h> /* time.c */ extern unsigned long tb_ticks_per_jiffy;
include/linux/timeofday.h +1 -0
@@ -9,6 +9,7 @@#include <linux/types.h> #include <linux/time.h> #include <linux/timex.h> +#include <linux/jiffies.h> /* For div_long_long_rem */ #include <asm/div64.h> #ifdef CONFIG_NEWTOD
RFC PATCH 1/1 new timeofday arch specific timesource drivers (v A4)
All,
This patch implements most of the time sources for i386, x86-64,
ppc32 and ppc64 (tsc, pit, cyclone, acpi-pm, hpet and timebase). There are also initial untested sketches for s390 and the ia64 itc and sn2_rtc timesources. It applies ontop of my linux-2.6.12-rc2_timeofday-arch_A4 patch. It provides real hardware timesources (opposed to the example jiffies timesource) that can be used for more realistic testing.
This patch is the shabbiest of the three. It needs to be broken up, and cleaned. The i386_pit.c is broken. The hpet and cyclone code have been attempted to be cleaned up so they can be shared between x86-64, i386 and ia64, but they still need testing. acpi_pm also needs to be made arch generic, but for now it will get you going so you can test and play with the core code.
New in this release:
o s390 support (Big thanks to Martin Schwidefsky!)
Items still on the TODO list:
o Fix TSC C3 stalls
o real ia64 timesources
o make cyclone/apci_pm arch generic
o example interpolation timesource
o fix i386_pit timesource
o all other arch timesources (volunteers wanted!)
o lots of cleanups
o lots of testing
thanks
-john
linux-2.6.12-rc2_timeofday-timesources_A4.patch
===============================================
arch/i386/kernel/Makefile +2 -2
@@ -7,10 +7,10 @@ obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \ ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_i386.o \ pci-dma.o i386_ksyms.o i387.o dmi_scan.o bootflag.o \ - doublefault.o quirks.o + doublefault.o quirks.o tsc.o obj-y += cpu/ -obj-y += timers/ +obj-$(!CONFIG_NEWTOD) += timers/ obj-$(CONFIG_ACPI_BOOT) += acpi/ obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o obj-$(CONFIG_MCA) += mca.o
arch/i386/kernel/acpi/boot.c +3 -9
@@ -547,7 +547,7 @@#ifdef CONFIG_HPET_TIMER - +#include <asm/hpet.h> static int __init acpi_parse_hpet (unsigned long phys,unsigned long size) {struct acpi_table_hpet *hpet_tbl;
@@ -570,18 +570,12 @@#ifdef CONFIG_X86_64 vxtime.hpet_address = hpet_tbl->addr.addrl | ((long ) hpet_tbl->addr.addrh <<32 ); - - printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n", - hpet_tbl->id, vxtime.hpet_address); + hpet_address = vxtime.hpet_address;#else /* X86 */ - { -extern unsigned long hpet_address; - hpet_address = hpet_tbl->addr.addrl; +#endif /* X86 */ printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n", hpet_tbl->id, hpet_address); - } -#endif /* X86 */ return 0 ; }
arch/i386/kernel/i8259.c +42 -0
48 lines not on this page · raw message
arch/i386/kernel/setup.c +2 -0
@@ -50,6 +50,7 @@#include <asm/io_apic.h> #include <asm/ist.h> #include <asm/io.h> +#include <asm/tsc.h> #include "setup_arch_pre.h" #include <bios_ebda.h>
@@ -1523,6 +1524,7 @@ conswitchp = &dummy_con;#endif #endif +tsc_init (); }#include "setup_arch_post.h"
arch/i386/kernel/time.c +2 -0
@@ -88,7 +88,9 @@DEFINE_SPINLOCK (i8253_lock);EXPORT_SYMBOL (i8253_lock); +#ifndef CONFIG_NEWTOD struct timer_opts *cur_timer = &timer_none; +#endif /* * This is a special lock that is owned by the CPU and holds the index
arch/i386/kernel/timers/common.c +0 -2
@@ -22,8 +22,6 @@* device. */ -#define CALIBRATE_TIME (5 * 1000020/HZ) -unsigned long __init calibrate_tsc (void ) {mach_prepare_counter ();
arch/i386/kernel/tsc.c new file +111 -0
111 lines not on this page · raw message
arch/x86_64/kernel/time.c +1 -0
@@ -59,6 +59,7 @@#undef HPET_HACK_ENABLE_DANGEROUSunsigned int cpu_khz;/* TSC clocks / usec, not used here */ +unsigned long hpet_address;static unsigned long hpet_period;/* fsecs / HPET clock */ unsigned long hpet_tick;/* HPET clocks / interrupt */ unsigned long vxtime_hz =PIT_TICK_RATE ;
drivers/timesource/Makefile +14 -0
@@ -1 +1,15 @@ obj-y += jiffies.o +obj-$(CONFIG_X86) += tsc.o +obj-$(CONFIG_X86_CYCLONE_TIMER) += cyclone.o +obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o +obj-$(CONFIG_HPET_TIMER) += hpet.o +obj-$(CONFIG_PPC64) += ppc64_timebase.o +obj-$(CONFIG_PPC) += ppc_timebase.o +obj-$(CONFIG_ARCH_S390) += s390_tod.o + +# XXX - Known broken +#obj-$(CONFIG_X86) += i386_pit.o + +# XXX - Untested/Uncompiled +#obj-$(CONFIG_IA64) += itc.c +#obj-$(CONFIG_IA64_SGI_SN2) += sn2_rtc.c
drivers/timesource/acpi_pm.c new file +116 -0
116 lines not on this page · raw message
drivers/timesource/cyclone.c new file +135 -0
135 lines not on this page · raw message
drivers/timesource/hpet.c new file +59 -0
59 lines not on this page · raw message
drivers/timesource/i386_pit.c new file +100 -0
100 lines not on this page · raw message
drivers/timesource/itc.c new file +35 -0
@@ -0,0 +1,35 @@ +/* XXX - this is totally untested and uncompiled +* TODO: +* o cpufreq issues +* o unsynched ITCs ? +*/ +#include <linux/timesource.h> + +/* XXX - Other includes needed for: +* sal_platform_features, IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT, +* local_cpu_data->itc_freq +* See arch/ia64/kernel/time.c for ideas +*/ + +static struct timesource_t timesource_itc = { + .name ="itc" , + .priority =25 , + .type =TIMESOURCE_CYCLES , + .mask = (cycle_t)-1 , + .mult =0 ,/* to be set */ + .shift =22 , +}; + +static int init_itc_timesource (void ) +{ +if (!(sal_platform_features &IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT )) { +/* XXX - I'm not really sure if itc_freq is in cyc/sec */ + timesource_itc.mult =timesource_hz2mult (local_cpu_data->itc_freq, + timesource_itc.shift); +register_timesource (×ource_itc); + } +return 0 ; +} + +module_init (init_itc_timesource); +
drivers/timesource/ppc64_timebase.c new file +33 -0
@@ -0,0 +1,33 @@ +#include <linux/timesource.h> +#include <asm/time.h> + +static cycle_t timebase_read (void ) +{ +return (cycle_t )get_tb (); +} + +struct timesource_t timesource_timebase = { + .name ="timebase" , + .priority =200 , + .type =TIMESOURCE_FUNCTION , + .read_fnct = timebase_read, + .mask = (cycle_t)-1 , + .mult =0 , + .shift =22 , +}; + + +/* XXX - this should be calculated or properly externed! */ +extern unsigned long tb_to_ns_scale; +extern unsigned long tb_to_ns_shift; +extern unsigned long tb_ticks_per_sec; + +static int init_timebase_timesource (void ) +{ + timesource_timebase.mult =timesource_hz2mult (tb_ticks_per_sec, + timesource_timebase.shift); +register_timesource (×ource_timebase); +return 0 ; +} + +module_init (init_timebase_timesource);
drivers/timesource/ppc_timebase.c new file +56 -0
56 lines not on this page · raw message
drivers/timesource/s390_tod.c new file +37 -0
@@ -0,0 +1,37 @@ +/* +* linux/drivers/timesource/s390_tod.c +* +* (C) Copyright IBM Corp. 2004 +* +* Author(s): Martin Schwidefsky ([email protected]), +* +* s390 TOD clock time source. +*/ + +#include <linux/timesource.h> +#include <linux/timex.h> +#include <linux/init.h> + +static cycle_t s390_tod_read (void ) +{ +return get_clock (); +} + +struct timesource_t timesource_s390_tod = { + .name ="TOD" , + .priority =100 , + .type =TIMESOURCE_FUNCTION , + .read_fnct = s390_tod_read, + .mask =-1ULL , + .mult =1000 , + .shift =12 +}; + + +static int init_s390_timesource (void ) +{ +register_timesource (×ource_s390_tod); +return 0 ; +} + +module_init (init_s390_timesource);
drivers/timesource/sn2_rtc.c new file +29 -0
@@ -0,0 +1,29 @@ +#include <linux/timesource.h> +/* XXX this will need some includes +* to find: sn_rtc_cycles_per_second and RTC_COUNTER_ADDR +* See arch/ia64/sn/kernel/sn2/timer.c for likely suspects +*/ + +#define SN2_RTC_MASK ((1LL << 55) - 1) +#define SN2_SHIFT 10 + +struct timesource_t timesource_sn2_rtc = { + .name ="sn2_rtc" , + .priority =300 ,/* XXX - not sure what this should be */ + .type =TIMESOURCE_MMIO_64 , + .mmio_ptr =NULL , + .mask = (cycle_t )SN2_RTC_MASK , + .mult =0 ,/* set below */ + .shift =SN2_SHIFT , +}; + +static void init_sn2_timesource (void ) +{ + timesource_sn2_rtc.mult =timesource_hz2mult (sn_rtc_cycles_per_second, +SN2_SHIFT ); + timesource_sn2_rtc.mmio_ptr =RTC_COUNTER_ADDR ; + +register_time_interpolator (×ource_sn2_rtc); +return 0 ; +} +module_init (init_sn2_timesource);
drivers/timesource/tsc.c new file +46 -0
46 lines not on this page · raw message
include/asm-i386/mach-default/mach_timer.h +5 -1
@@ -14,8 +14,12 @@*/ #ifndef _MACH_TIMER_H#define _MACH_TIMER_H +#include <linux/jiffies.h> +#include <asm/io.h> -#define CALIBRATE_LATCH (5 * LATCH) +#define CALIBRATE_ITERATION 50 +#define CALIBRATE_LATCH (CALIBRATE_ITERATION * LATCH) +#define CALIBRATE_TIME (CALIBRATE_ITERATION * 1000020/HZ)static inline void mach_prepare_counter (void ) {
include/asm-i386/timer.h +8 -8
@@ -2,6 +2,13 @@#define _ASMi386_TIMER_H#include <linux/init.h> +#define TICK_SIZE (tick_nsec / 1000) +void setup_pit_timer (void ); +/* Modifiers for buggy PIT handling */ +extern int pit_latch_buggy; +extern int timer_ack; + +#ifndef CONFIG_NEWTOD /** * struct timer_ops - used to define a timer source *
@@ -29,18 +36,10 @@struct timer_opts *opts; }; -#define TICK_SIZE (tick_nsec / 1000) -extern struct timer_opts *__init select_timer (void );extern void clock_fallback (void ); -void setup_pit_timer (void ); - -/* Modifiers for buggy PIT handling */ - -extern int pit_latch_buggy;extern struct timer_opts *cur_timer; -extern int timer_ack;/* list of externed timers */ extern struct timer_opts timer_none;
@@ -60,5 +59,6 @@#ifdef CONFIG_X86_PM_TIMER extern struct init_timer_opts timer_pmtmr_init; +#endif #endif #endif
include/asm-i386/tsc.h new file +6 -0
@@ -0,0 +1,6 @@ +#ifndef _ASM_I386_TSC_H +#define _ASM_I386_TSC_H +extern unsigned long cpu_freq_khz; +void tsc_init (void ); + +#endif
include/asm-x86_64/hpet.h +2 -1
@@ -1,6 +1,6 @@#ifndef _ASM_X8664_HPET_H#define _ASM_X8664_HPET_H 1 - +#include <asm/fixmap.h> /* * Documentation on HPET can be found at: * http://www.intel.com/ial/home/sp/pcmmspec.htm
@@ -44,6 +44,7 @@#define HPET_TN_SETVAL 0x040#define HPET_TN_32BIT 0x100 +extern unsigned long hpet_address;/* hpet memory map physical address */ extern int is_hpet_enabled (void );extern int hpet_rtc_timer_init (void );extern int oem_force_hpet_timer (void );
include/linux/sched.h +4 -0
@@ -825,7 +825,11 @@ }#endif +#ifndef CONFIG_NEWTOD extern unsigned long long sched_clock (void ); +#else +#define sched_clock () 0 +#endif extern unsigned long long current_sched_time (const task_t *current_task);/* sched_exec is called by processes performing an exec */
RFC PATCH 1/1 new timeofday vsyscall proof of concept (v A4)
All,
This patch implements vsyscall-gettimeofday() functions for i386 and
x86-64 using the new timeofday core code. This is just a hackish proof of concept that shows how it could be done and what interfaces are needed to have a clean separation of the arch independent time keeping and the very arch specific vsyscall code.
I look forward to your comments and feedback.
thanks
-john
linux-2.6.12-rc2_timeofday-vsyscall_A4.patch
===============================================
arch/i386/Kconfig +4 -0
@@ -464,6 +464,10 @@ bool "Provide RTC interrupt" depends on HPET_TIMER && RTC=y +config NEWTOD_VSYSCALL + depends on EXPERIMENTAL + bool "VSYSCALL gettimeofday() interface" + config SMP bool "Symmetric multi-processing support" ---help---
arch/i386/kernel/Makefile +1 -0
@@ -11,6 +11,7 @@ obj-y += cpu/ obj-$(!CONFIG_NEWTOD) += timers/ +obj-$(CONFIG_NEWTOD_VSYSCALL) += vsyscall-gtod.o obj-$(CONFIG_ACPI_BOOT) += acpi/ obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o obj-$(CONFIG_MCA) += mca.o
arch/i386/kernel/setup.c +2 -0
@@ -51,6 +51,7 @@#include <asm/ist.h> #include <asm/io.h> #include <asm/tsc.h> +#include <asm/vsyscall-gtod.h> #include "setup_arch_pre.h" #include <bios_ebda.h>
@@ -1525,6 +1526,7 @@#endif #endif tsc_init (); +vsyscall_init (); }#include "setup_arch_post.h"
arch/i386/kernel/vmlinux.lds.S +27 -0
@@ -5,6 +5,8 @@ #include <asm-generic/vmlinux.lds.h> #include <asm/thread_info.h> #include <asm/page.h> +#include <linux/config.h> +#include <asm/vsyscall-gtod.h> OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") OUTPUT_ARCH(i386)
@@ -51,6 +53,31 @@ .data.cacheline_aligned : { *(.data.cacheline_aligned) } _edata = .; /* End of data section */ + +/* VSYSCALL_GTOD data */ +#ifdef CONFIG_NEWTOD_VSYSCALL + + /* vsyscall entry */ + . = ALIGN(64); + .data.cacheline_aligned : { *(.data.cacheline_aligned) } + + .vsyscall_0 VSYSCALL_GTOD_START: AT ((LOADADDR(.data.cacheline_aligned) + SIZEOF(.data.cacheline_aligned) + 4095) & ~(4095)) { *(.vsyscall_0) } + __vsyscall_0 = LOADADDR(.vsyscall_0); + + + /* generic gtod variables */ + . = ALIGN(64); + .vsyscall_gtod_data : AT ((LOADADDR(.vsyscall_0) + SIZEOF(.vsyscall_0) + 63) & ~(63)) { *(.vsyscall_gtod_data) } + vsyscall_gtod_data = LOADADDR(.vsyscall_gtod_data); + + . = ALIGN(16); + .vsyscall_gtod_lock : AT ((LOADADDR(.vsyscall_gtod_data) + SIZEOF(.vsyscall_gtod_data) + 15) & ~(15)) { *(.vsyscall_gtod_lock) } + vsyscall_gtod_lock = LOADADDR(.vsyscall_gtod_lock); + + .vsyscall_1 ADDR(.vsyscall_0) + 1024: AT (LOADADDR(.vsyscall_0) + 1024) { *(.vsyscall_1) } + . = LOADADDR(.vsyscall_0) + 4096; +#endif +/* END of VSYSCALL_GTOD data*/ . = ALIGN(THREAD_SIZE); /* init_task */ .data.init_task : { *(.data.init_task) }
arch/i386/kernel/vsyscall-gtod.c new file +193 -0
193 lines not on this page · raw message
arch/x86_64/Kconfig +4 -0
@@ -57,6 +57,10 @@ bool default y +config NEWTOD_VSYSCALL + depends on EXPERIMENTAL + bool "VSYSCALL gettimeofday() interface" + config GENERIC_ISA_DMA bool default y
arch/x86_64/kernel/time.c +3 -1
@@ -81,6 +81,7 @@rdtscll (*tsc); } +#ifndef CONFIG_NEWTOD /* * do_gettimeoffset() returns microseconds since last timer interrupt was * triggered by hardware. A memory read of HPET is slower than a register read
@@ -108,7 +109,6 @@unsigned int (*do_gettimeoffset)(void ) = do_gettimeoffset_tsc; -#ifndef CONFIG_NEWTOD /* * This version of gettimeofday() has microsecond resolution and better than * microsecond precision, as we're using at least a 10 MHz (usually 14.31818
@@ -976,6 +976,7 @@/* Some systems will want to disable TSC and use HPET. */ if (oem_force_hpet_timer ()) notsc =1 ; +#ifndef CONFIG_NEWTOD if (vxtime.hpet_address && notsc) { timetype ="HPET" ; vxtime.last =hpet_readl (HPET_T0_CMP ) - hpet_tick;
@@ -987,6 +988,7 @@ }printk (KERN_INFO "time.c: Using %s based timekeeping.\n" , timetype); +#endif /* CONFIG_NEWTOD */ }__setup ("report_lost_ticks" , time_setup);
arch/x86_64/kernel/vmlinux.lds.S +7 -0
@@ -71,6 +71,13 @@ . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); .jiffies : AT CACHE_ALIGN(AFTER(.xtime)) { *(.jiffies) } jiffies = LOADADDR(.jiffies); + + .vsyscall_gtod_data : AT AFTER(.jiffies) { *(.vsyscall_gtod_data) } + vsyscall_gtod_data = LOADADDR(.vsyscall_gtod_data); + .vsyscall_gtod_lock : AT AFTER(.vsyscall_gtod_data) { *(.vsyscall_gtod_lock) } + vsyscall_gtod_lock = LOADADDR(.vsyscall_gtod_lock); + + .vsyscall_1 ADDR(.vsyscall_0) + 1024: AT (LOADADDR(.vsyscall_0) + 1024) { *(.vsyscall_1) } . = LOADADDR(.vsyscall_0) + 4096;
arch/x86_64/kernel/vsyscall.c +106 -6
150 lines not on this page · raw message
include/asm-i386/fixmap.h +6 -0
@@ -27,6 +27,7 @@#include <asm/acpi.h> #include <asm/apicdef.h> #include <asm/page.h> +#include <asm/vsyscall-gtod.h> #ifdef CONFIG_HIGHMEM #include <linux/threads.h> #include <asm/kmap_types.h>
@@ -53,6 +54,11 @@enum fixed_addresses {FIX_HOLE ,FIX_VSYSCALL , +#ifdef CONFIG_NEWTOD_VSYSCALL +FIX_VSYSCALL_GTOD_LAST_PAGE , +FIX_VSYSCALL_GTOD_FIRST_PAGE =FIX_VSYSCALL_GTOD_LAST_PAGE + +VSYSCALL_GTOD_NUMPAGES -1 , +#endif #ifdef CONFIG_X86_LOCAL_APIC FIX_APIC_BASE ,/* local (CPU) APIC) -- required for SMP or not */ #endif
include/asm-i386/pgtable.h +4 -0
@@ -159,6 +159,8 @@#define __PAGE_KERNEL_NOCACHE (__PAGE_KERNEL | _PAGE_PCD)#define __PAGE_KERNEL_LARGE (__PAGE_KERNEL | _PAGE_PSE)#define __PAGE_KERNEL_LARGE_EXEC (__PAGE_KERNEL_EXEC | _PAGE_PSE) +#define __PAGE_KERNEL_VSYSCALL \ + (_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)#define PAGE_KERNEL __pgprot(__PAGE_KERNEL)#define PAGE_KERNEL_RO __pgprot(__PAGE_KERNEL_RO)
@@ -166,6 +168,8 @@#define PAGE_KERNEL_NOCACHE __pgprot(__PAGE_KERNEL_NOCACHE)#define PAGE_KERNEL_LARGE __pgprot(__PAGE_KERNEL_LARGE)#define PAGE_KERNEL_LARGE_EXEC __pgprot(__PAGE_KERNEL_LARGE_EXEC) +#define PAGE_KERNEL_VSYSCALL __pgprot(__PAGE_KERNEL_VSYSCALL) +#define PAGE_KERNEL_VSYSCALL_NOCACHE __pgprot(__PAGE_KERNEL_VSYSCALL|(__PAGE_KERNEL_RO | _PAGE_PCD))/* * The i386 can't do page protection for execute, and considers that
include/asm-i386/vsyscall-gtod.h new file +41 -0
41 lines not on this page · raw message
include/asm-x86_64/vsyscall.h +2 -0
@@ -22,6 +22,8 @@#define __section_sysctl_vsyscall __attribute__ ((unused, __section__ (".sysctl_vsyscall"), aligned(16)))#define __section_xtime __attribute__ ((unused, __section__ (".xtime"), aligned(16)))#define __section_xtime_lock __attribute__ ((unused, __section__ (".xtime_lock"), aligned(16))) +#define __section_vsyscall_gtod_data __attribute__ ((unused, __section__ (".vsyscall_gtod_data"),aligned(16))) +#define __section_vsyscall_gtod_lock __attribute__ ((unused, __section__ (".vsyscall_gtod_lock"),aligned(16)))#define VXTIME_TSC 1#define VXTIME_HPET 2
kernel/timeofday.c +15 -1
@@ -41,7 +41,6 @@* o Added getnstimeofday * o Cleanups from Nish Aravamudan * TODO List: -* o vsyscall/fsyscall infrastructure * o clock_was_set hook **********************************************************************/
@@ -116,6 +115,12 @@*/ extern nsec_t read_persistent_clock (void );extern void sync_persistent_clock (struct timespec ts); +#ifdef CONFIG_NEWTOD_VSYSCALL +extern void arch_update_vsyscall_gtod (nsec_t wall_time,cycle_t offset_base, +struct timesource_t * timesource,int ntp_adj); +#else +#define arch_update_vsyscall_gtod (x,y,z,w) {} +#endif /* get_lowres_timestamp():
@@ -282,6 +287,9 @@update_legacy_time_values (); +arch_update_vsyscall_gtod (system_time + wall_time_offset, offset_base, + timesource, ntp_adj); +write_sequnlock_irqrestore (&system_time_lock, flags);return 0 ;
@@ -473,6 +481,9 @@/* sync legacy values */ update_legacy_time_values (); +arch_update_vsyscall_gtod (system_time + wall_time_offset, offset_base, + timesource, ntp_adj); +write_sequnlock_irqrestore (&system_time_lock, flags);/* Set us up to go off on the next interval */
@@ -501,6 +512,9 @@/* clear NTP scaling factor & state machine */ ntp_adj =0 ;ntp_clear (); + +arch_update_vsyscall_gtod (system_time + wall_time_offset, offset_base, + timesource, ntp_adj);/* initialize legacy time values */ update_legacy_time_values ();
Re: [RFC][PATCH (2/4)] new timeofday arch specific hooks (v A4)
In reply to john stultzHi!
Quoted 3 lines
ppc64 and s390. It applies on top of my linux-2.6.12-rc2_timeofday-
core_A4patch and with this patch applied, you can test the new time of day subsystem.
....
arch/i386/kernel/apm.c line 1210
Quoted 4 lines
device_power_down(PMSG_SUSPEND);arch/i386/kernel/apm.c +1
-0+timeofday_suspend_hook ();/* serialize with the timer interrupt */
You should not add hooks like this. Just add your own [sys]_device.
Pavel
Signature · 1 line
64 bytes from 195.113.31.123: icmp_seq=28 ttl=51 time=448769.1 ms
Re: [RFC][PATCH (2/4)] new timeofday arch specific hooks (v A4)
Quoted 5 lines · Pavel Machek
Hi!
Quoted 3 lines
ppc64 and s390. It applies on top of my linux-2.6.12-rc2_timeofday-
core_A4patch and with this patch applied, you can test the new time of day subsystem.
Quoted 7 lines
....
arch/i386/kernel/apm.c line 1210
Quoted 4 lines
device_power_down(PMSG_SUSPEND);arch/i386/kernel/apm.c +1
-0+timeofday_suspend_hook ();/* serialize with the timer interrupt */ You should not add hooks like this. Just add your own [sys]_device.
Agreed. Sorry I didn't get to it the last time you mentioned it.
thanks
-john
RFC PATCH 1/1 new timeofday-based soft-timer subsystem
In reply to john stultzQuoted 5 lines · john stultz
All,
This patch implements the architecture independent portion of
the time of day subsystem. For a brief description on the rework, see
here: http://lwn.net/Articles/120850/ (Many thanks to the LWN team for that clear writeup!)
I have been working closely with John to re-work the soft-timer subsytem to use the new timeofday() subsystem. The following patch attempts to being this process. I would greatly appreciate any comments.
Some design points:
1) The patch is small but does a lot.
a) Renames timer_jiffies to last_timer_time (now that we are not jiffies-based).
b) Converts the soft-timer time-vector's/bucket's entries to timerinterval (a new unit) width, instead of jiffy width.
c) Defines timerintervals to be the current time as reported by the new timeofday-subsystem shifted down by 20 bits and masked to only grab the lower 32 bits. This effectively emulates a 32-bit millisecond value.
d) Uses do_monotonic_clock() (converted to timerintervals) as the basis for addition and expiration instead of jiffies.
e) Adds some new helper functions for dealing with nanosecond values.
2) Currently, the patch is dependent upon John's timeofday core rework. For arches that will not have the new timeofday (or for which the rework is still in progress), I can emulate the existing system with a separate patch. The goal of this patch, though, is just to show how easy the new system can be implemented and the benefits.
3) The reason for the re-work?: Many people complain about all of the adding of 1 jiffy here or there to fix bugs. This new systems is fundamentally human-time oriented and deals with those issues correctly.
The code is reasonably well commented, but does expect readers to understand the current system to some degree.
This is my first posting of this re-work, so I expect criticism, but am happy to make changes.
Thanks,
Nish
include/linux/jiffies.h +31 -2
@@ -263,7 +263,7 @@ static inline unsigned int jiffies_to_ms#endif } -static inline unsigned int jiffies_to_usecs (const unsigned long j) +static inline unsigned long jiffies_to_usecs (const unsigned long j) {#if HZ <=1000000 && !(1000000 %HZ )return (1000000 /HZ ) * j;
@@ -274,6 +274,17 @@ static inline unsigned int jiffies_to_us#endif } +static inline nsec_t jiffies_to_nsecs (const unsigned long j) +{ +#if HZ <=NSEC_PER_SEC && !(NSEC_PER_SEC %HZ ) +return (NSEC_PER_SEC /HZ ) * (nsec_t )j; +#elif HZ >NSEC_PER_SEC && !(HZ %NSEC_PER_SEC ) +return ((nsec_t )j + (HZ /NSEC_PER_SEC ) -1 )/(HZ /NSEC_PER_SEC ); +#else +return ((nsec_t )j *NSEC_PER_SEC ) /HZ ; +#endif +} +static inline unsigned long msecs_to_jiffies (const unsigned int m) {if (m >jiffies_to_msecs (MAX_JIFFY_OFFSET ))
@@ -287,7 +298,7 @@ static inline unsigned long msecs_to_jif#endif } -static inline unsigned long usecs_to_jiffies (const unsigned int u) +static inline unsigned long usecs_to_jiffies (const unsigned long u) {if (u >jiffies_to_usecs (MAX_JIFFY_OFFSET ))return MAX_JIFFY_OFFSET ;
@@ -300,6 +311,24 @@ static inline unsigned long usecs_to_jif#endif } +static inline unsigned long nsecs_to_jiffies (const nsec_t n) +{ +nsec_t temp; +if (n >jiffies_to_nsecs (MAX_JIFFY_OFFSET )) +return MAX_JIFFY_OFFSET ; +#if HZ <=NSEC_PER_SEC && !(NSEC_PER_SEC %HZ ) + temp = n + (NSEC_PER_SEC /HZ ) -1 ; +do_div (temp, (NSEC_PER_SEC /HZ )); +return (unsigned long )temp; +#elif HZ >NSEC_PER_SEC && !(HZ %NSEC_PER_SEC ) +return n * (HZ /NSEC_PER_SEC ); +#else + temp = n *HZ +NSEC_PER_SEC -1 ; +do_div (temp,NSEC_PER_SEC ); +return (unsigned long )temp; +#endif +} +/* * The TICK_NSEC - 1 rounds up the value to the next resolution. Note * that a remainder subtract here would not do the right thing as the
include/linux/sched.h +6 -0
@@ -182,7 +182,13 @@ extern void scheduler_tick(void);extern int in_sched_functions (unsigned long addr);#define MAX_SCHEDULE_TIMEOUT LONG_MAX +#define MAX_SCHEDULE_TIMEOUT_NSECS ((nsec_t)(-1)) +#define MAX_SCHEDULE_TIMEOUT_MSECS ULONG_MAX +#define MAX_SCHEDULE_TIMEOUT_USECS UINT_MAXextern signed long FASTCALL (schedule_timeout (signed long timeout)); +extern nsec_t FASTCALL (schedule_timeout_nsecs (nsec_t timeout_nsecs)); +extern unsigned long FASTCALL (schedule_timeout_usecs (unsigned long timeout_usecs)); +extern unsigned int FASTCALL (schedule_timeout_msecs (unsigned int timeout_msesc)); asmlinkage void schedule(void);struct namespace ;
include/linux/timer.h +3 -18
@@ -5,6 +5,7 @@#include <linux/list.h> #include <linux/spinlock.h> #include <linux/stddef.h> +#include <linux/timeofday.h> struct tvec_t_base_s ;
@@ -65,27 +66,11 @@ extern void add_timer_on(struct timer_liextern int del_timer (struct timer_list * timer);extern int __mod_timer (struct timer_list *timer,unsigned long expires);extern int mod_timer (struct timer_list *timer,unsigned long expires); +extern void add_timer (struct timer_list *timer); +extern int set_timer_nsecs (struct timer_list *timer,nsec_t expires_nsecs);extern unsigned long next_timer_interrupt (void ); -/*** -* add_timer - start a timer -* @timer: the timer to be added -* -* The kernel will do a ->function(->data) callback from the -* timer interrupt at the ->expired point in the future. The -* current time is 'jiffies'. -* -* The timer's ->expired, ->function (and if the handler uses it, ->data) -* fields must be set prior calling this function. -* -* Timers with an ->expired field in the past will be executed in the next -* timer tick. -*/ -static inline void add_timer (struct timer_list * timer) -{ -__mod_timer (timer, timer->expires); -}#ifdef CONFIG_SMP extern int del_timer_sync (struct timer_list *timer);
kernel/timer.c +190 -16
336 lines not on this page · raw message
Re: [RFC][PATCH] new timeofday-based soft-timer subsystem
Quoted 10 lines · Nishanth Aravamudan
Quoted 5 lines · john stultz
All,
This patch implements the architecture independent portion of
the time of day subsystem. For a brief description on the rework, see
here: http://lwn.net/Articles/120850/ (Many thanks to the LWN team for that clear writeup!)
Quoted 5 lines
I have been working closely with John to re-work the soft-timer subsytem to use the new
timeofday()subsystem. The following patch attempts to being this process. I would greatly appreciate any comments.
Also working closely with John and Nish, I have been taking advantage of the new human-time soft-timer subsystem and the NO_IDLE_HZ code to dynamically schedule interrupts as needed. The idea is to have interrupt source drivers (PIT, Local APIC, HPET, ppc decrementers, etc) similar to the time sources in John's timeofday patches.
Because the resolution of the soft-timer sybsystem is configurable via TIMER_INTERVAL_BITS, and the timeofday code is now free of the periodic system tick, we can move the soft-timers to a dynamically scheduled interrupt system. We can achieve both sub-millisecond timer resolution and NO_IDLE_HZ simply by adjusting TIMER_INTERVAL_BITS and scheduling the next timer interrupt appropriately whenever a soft-timer is added or removed.
In general at the end of set_timer_nsecs(), we see when the next timer is due to expire and pass that value (in absolute nanoseconds) to schedule_next_timer_interrupt(). Each interrupt source driver is then free to reprogram the hard-timer to the "best" interval. For something like the local APIC, that may be exactly when the next timer needs to go off. For the PIT, it may do nothing at all and just fire periodically.
I have a prototype using the PIT, which just demonstrates that the system will still run this way. Obviously other timers will perform much better since the PIT is so slow to program.
I feel that this is a clean approach to two soft-timer issues: resolution and NO_IDLE_HZ. It integrates well with the patches from John and Nish and is a direct approach to these issues, rather than an attempt to add support on top of a jiffies based soft-timer subsystem.
I'd appreciate any feedback people have to offer. Particularly those that have been working on alternative approaches to things like high resolution timers and NO_IDLE_HZ.
Thanks,
Signature · 5 lines
Darren Hart IBM Linux Technology Center Linux Kernel Team Phone: 503 578 3185 T/L: 775 3185
Re: [RFC][PATCH] new timeofday-based soft-timer subsystem
In reply to Nishanth AravamudanQuoted 11 lines · Nishanth Aravamudan
Quoted 5 lines · john stultz
All,
This patch implements the architecture independent portion of
the time of day subsystem. For a brief description on the rework, see
here: http://lwn.net/Articles/120850/ (Many thanks to the LWN team for that clear writeup!)I have been working closely with John to re-work the soft-timer subsytem to use the new
timeofday()subsystem. The following patch attempts to being this process. I would greatly appreciate any comments.
I am not sure if anyone has looked at this patch closely, but I have noticed one issue: My code assumes that all the rounding will be done internally (rounding up on addition to find to the nearest timerinterval); however, current interfaces do much of the rounding before passing on structures on to the soft-timer subsystem, because the jiffies-based one always rounds down.
This is most clear in sys_nanosleep(). Without any modifications to the syscall, but with my patch applied, one will see around 5 millisecond sleeps for a 1 millisecond request. This occurs, I believe, because jiffies_to_timespec() rounds up once, we add one if there is any value and then in internally I round up once more. If I rewrite sys_nanosleep() to use schedule_timeout_nsecs() and thus never convert from nanoseconds, I see 2 millisecond sleeps for 1 millisecond requests, which is much closer (and accurate, as our granularity is slightly greater than 1 millisecond and we are interruptiing at HZ=1000 slightly more often than ever millisecond). This seems to be the right solution, but then there is another issue: the restart_block used by sys_nanosleep() only allows for 4 unsigned long arguments, when, in fact, nanoseconds are a 64-bit quantity in the kernel. As long as the nanosleep() request is no more than around 4 seconds, we should be ok using unsigned longs. But anything longer will simply truncate currently. I am not certain of a clean way to modify the restart_block to incorporate a 64-bit quantity, as it is used by other interfaces as well.
I still need to update the other version of nanosleep() (nsleep() and posix) before I post an updated patch. Just wanted to let everyone know of the issue.
Thanks,
Nish
Re: [RFC][PATCH] new timeofday-based soft-timer subsystem
Quoted 5 lines · Nishanth Aravamudan
but then there is another issue: the
restart_blockused bysys_nanosleep()only allows for 4 unsigned long arguments, when, in fact, nanoseconds are a 64-bit quantity in the kernel. As long as thenanosleep()request is no more than around 4 seconds, we should be ok using unsigned longs.
My man page for nanosleep specifies that the "nanoseconds" portion of the timespec must be under 1 billion and is of type "long". Is that no longer valid?
Chris
Re: [RFC][PATCH] new timeofday-based soft-timer subsystem
Quoted 11 lines · Chris Friesen
Quoted 5 lines · Nishanth Aravamudan
but then there is another issue: the
restart_blockused bysys_nanosleep()only allows for 4 unsigned long arguments, when, in fact, nanoseconds are a 64-bit quantity in the kernel. As long as thenanosleep()request is no more than around 4 seconds, we should be ok using unsigned longs.My man page for nanosleep specifies that the "nanoseconds" portion of the timespec must be under 1 billion and is of type "long". Is that no longer valid?
Certainly would be, but the problem is if you pass in a timespec ts, where
ts.tv_sec = 10;
ts.tv_nsec = 99999;This will overflow a 32-bit nanosecond representation internally (10000099999 > 4294967296). Sorry for the confusion, the unsigned long I was referring to was the internal representation of the nanoseconds converted from the timespec parameter.
Thanks,
Nish
Re: [RFC][PATCH] new timeofday-based soft-timer subsystem
In reply to Nishanth AravamudanQuoted 13 lines · Nishanth Aravamudan
Quoted 11 lines · Nishanth Aravamudan
Quoted 5 lines · john stultz
All,
This patch implements the architecture independent portion of
the time of day subsystem. For a brief description on the rework, see
here: http://lwn.net/Articles/120850/ (Many thanks to the LWN team for that clear writeup!)I have been working closely with John to re-work the soft-timer subsytem to use the new
timeofday()subsystem. The following patch attempts to being this process. I would greatly appreciate any comments.
Quoted 6 lines
I am not sure if anyone has looked at this patch closely, but I have noticed one issue: My code assumes that all the rounding will be done internally (rounding up on addition to find to the nearest timerinterval); however, current interfaces do much of the rounding before passing on structures on to the soft-timer subsystem, because the jiffies-based one always rounds down.
A for instance: sys_nanosleep() assumes (correctly) that the jiffies-based soft-timer subsystem rounds down, so it rounds up (twice). But since I now round-up internally, that is not necessary. Fix sys_nanosleep() to do this right.
Still todo: change restart->arg0 to be a pointer to an nsec_t.
kernel/timer.c +11 -11
@@ -1141,21 +1311,21 @@ asmlinkage long sys_gettid(void)static long __sched nanosleep_restart (struct restart_block *restart) { -unsigned long expire = restart->arg0, now = jiffies; +nsec_t expire = restart->arg0, now =do_monotonic_clock ();struct timespec __user *rmtp = (struct timespec __user *) restart->arg1;long ret;/* Did it expire while we handled signals? */ -if (!time_after (expire, now)) +if (now > expire)return 0 ; - current->state =TASK_INTERRUPTIBLE ; - expire =schedule_timeout (expire - now); +set_current_state (TASK_INTERRUPTIBLE ); + expire =schedule_timeout_nsecs (expire - now); ret =0 ;if (expire) {struct timespec t; -jiffies_to_timespec (expire, &t); + t =ns2timespec (expire); ret = -ERESTART_RESTARTBLOCK ;if (rmtp &©_to_user (rmtp, &t,sizeof (t)))
@@ -1168,7 +1338,7 @@ static long __sched nanosleep_restart(stasmlinkage long sys_nanosleep (struct timespec __user *rqtp,struct timespec __user *rmtp) {struct timespec t; -unsigned long expire; +nsec_t expire;long ret;if (copy_from_user (&t, rqtp,sizeof (t)))
@@ -1177,20 +1347,20 @@ asmlinkage long sys_nanosleep(struct timif ((t.tv_nsec >=1000000000L ) || (t.tv_nsec <0 ) || (t.tv_sec <0 ))return -EINVAL ; - expire =timespec_to_jiffies (&t) + (t.tv_sec || t.tv_nsec); - current->state =TASK_INTERRUPTIBLE ; - expire =schedule_timeout (expire); + expire =timespec2ns (&t); +set_current_state (TASK_INTERRUPTIBLE ); + expire =schedule_timeout_nsecs (expire); ret =0 ;if (expire) {struct restart_block *restart; -jiffies_to_timespec (expire, &t); + t =ns2timespec (expire);if (rmtp &©_to_user (rmtp, &t,sizeof (t)))return -EFAULT ; restart = ¤t_thread_info ()->restart_block; restart->fn = nanosleep_restart; - restart->arg0 = jiffies + expire; + restart->arg0 =do_monotonic_clock () + expire; restart->arg1 = (unsigned long ) rmtp; ret = -ERESTART_RESTARTBLOCK ; }
Ack. At the last minute I accidentally committed a line I didn't mean to, so the timeofday-core_A4 patch doesn't build.
This patch fixes the problem. Please use it instead.
linux-2.6.12-rc2_timeofday-core_A4fix.patch
===========================================
drivers/Makefile +1 -0
@@ -64,3 +64,4 @@ obj-$(CONFIG_BLK_DEV_SGIIOC4) += sn/ obj-y += firmware/ obj-$(CONFIG_CRYPTO) += crypto/ +obj-$(CONFIG_NEWTOD) += timesource/
drivers/timesource/Makefile new file +1 -0
@@ -0,0 +1 @@ +obj-y += jiffies.o
drivers/timesource/jiffies.c new file +45 -0
45 lines not on this page · raw message
include/linux/ntp.h new file +22 -0
@@ -0,0 +1,22 @@ +/* linux/include/linux/ntp.h +* +* Copyright (C) 2003, 2004, 2005 IBM, John Stultz ([email protected]) +* +* This file NTP state machine accessor functions. +*/ + +#ifndef _LINUX_NTP_H +#define _LINUX_NTP_H +#include <linux/types.h> +#include <linux/time.h> +#include <linux/timex.h> + +/* NTP state machine interfaces */ +nsec_t ntp_scale (nsec_t value); +int ntp_advance (nsec_t value); +int ntp_adjtimex (struct timex *); +int ntp_leapsecond (struct timespec now); +void ntp_clear (void ); +int get_ntp_status (void ); + +#endif
include/linux/time.h +4 -0
@@ -27,6 +27,10 @@#ifdef __KERNEL__ +/* timeofday base types */ +typedef u64 nsec_t ; +typedef u64 cycle_t ; +/* Parameters used to convert the timespec values */ #ifndef USEC_PER_SEC #define USEC_PER_SEC (1000000L)
include/linux/timeofday.h new file +65 -0
65 lines not on this page · raw message
include/linux/timesource.h new file +159 -0
159 lines not on this page · raw message
init/main.c +2 -0
@@ -47,6 +47,7 @@#include <linux/rmap.h> #include <linux/mempolicy.h> #include <linux/key.h> +#include <linux/timeofday.h> #include <asm/io.h> #include <asm/bugs.h>
@@ -467,6 +468,7 @@pidhash_init ();init_timers ();softirq_init (); +timeofday_init ();time_init ();/*
kernel/Makefile +1 -0
@@ -9,6 +9,7 @@ rcupdate.o intermodule.o extable.o params.o posix-timers.o \ kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o +obj-$(CONFIG_NEWTOD) += timeofday.o timesource.o ntp.o obj-$(CONFIG_FUTEX) += futex.o obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o obj-$(CONFIG_SMP) += cpu.o spinlock.o
kernel/ntp.c new file +500 -0
500 lines not on this page · raw message
kernel/time.c +5 -0
@@ -38,6 +38,7 @@#include <asm/uaccess.h> #include <asm/unistd.h> +#include <linux/timeofday.h> /* * The timezone where the local system is located. Used as a default by some
@@ -227,6 +228,7 @@/* adjtimex mainly allows reading (and writing, if superuser) of * kernel time-keeping variables. used by xntpd. */ +#ifndef CONFIG_NEWTOD int do_adjtimex (struct timex *txc) {long ltemp, mtemp, save_adjust;
@@ -410,6 +412,7 @@notify_arch_cmos_timer (); return(result); } +#endif asmlinkage long sys_adjtimex (struct timex __user *txc_p) {
@@ -566,6 +569,7 @@#else +#ifndef CONFIG_NEWTOD /* * Simulate gettimeofday using do_gettimeofday which only allows a timeval * and therefore only yields usec accuracy
@@ -578,6 +582,7 @@ tv->tv_sec = x.tv_sec; tv->tv_nsec = x.tv_usec *NSEC_PER_USEC ; } +#endif /* CONFIG_NEWTOD */ #endif #if (BITS_PER_LONG <64 )
kernel/timeofday.c new file +521 -0
521 lines not on this page · raw message
kernel/timer.c +4 -0
@@ -577,6 +577,7 @@int tickadj =500 /HZ ? :1 ;/* microsecs */ +#ifndef CONFIG_NEWTOD /* * phase-lock loop variables */
@@ -807,6 +808,9 @@ } }while (ticks); } +#else /* CONFIG_NEWTOD */ +#define update_wall_time (x) +#endif /* CONFIG_NEWTOD */ /* * Called from the timer interrupt handler to charge one tick to the current
kernel/timesource.c new file +210 -0
210 lines not on this page · raw message
Quoted 18 lines · john stultz
All,
This patch implements the architecture independent portion of
the time of day subsystem. For a brief description on the rework, see
here: http://lwn.net/Articles/120850/ (Many thanks to the LWN team for that clear writeup!)Mostly this version is just a cleanup of the last release. One neat feature is the new sysfs interface which allows you to manually override the selected timesource while the system is running.
Included below is
timeofday.c(which includes all the time of day management and accessor functions),ntp.c(which includes the ntp scaling calculation code, leapsecond processing, and ntp kernel state machine code),timesource.c(for timesource specific management functions), interface definition .h files, the example jiffies timesource (lowest common denominator time source, mainly for use as example code) and minimal hooks into arch independent code.
Quoted 3 lines
The patch does not function without minimal architecture specific hooks (i386, x86-64, ppc32, ppc64, ia64 and s390 examples to follow), and it should be able to be applied to a tree without affecting the code.
My concern at this point is how to deal with the userland gettimofday implementation in the ppc64 vDSO ...
Ben.
Quoted 19 lines · Benjamin Herrenschmidt
Quoted 18 lines · john stultz
All,
This patch implements the architecture independent portion of
the time of day subsystem. For a brief description on the rework, see
here: http://lwn.net/Articles/120850/ (Many thanks to the LWN team for that clear writeup!)Mostly this version is just a cleanup of the last release. One neat feature is the new sysfs interface which allows you to manually override the selected timesource while the system is running.
Included below is
timeofday.c(which includes all the time of day management and accessor functions),ntp.c(which includes the ntp scaling calculation code, leapsecond processing, and ntp kernel state machine code),timesource.c(for timesource specific management functions), interface definition .h files, the example jiffies timesource (lowest common denominator time source, mainly for use as example code) and minimal hooks into arch independent code.
Quoted 6 lines
Quoted 3 lines
The patch does not function without minimal architecture specific hooks (i386, x86-64, ppc32, ppc64, ia64 and s390 examples to follow), and it should be able to be applied to a tree without affecting the code.
My concern at this point is how to deal with the userland gettimofday implementation in the ppc64 vDSO ...
Hopefully in a method very similar to the way the vsyscall patch does for i386/x86-64. The idea being that the core code makes an arch specific call passing the core timekeeping values whenever they are changed. Then the arch specific implementation can use those values in a similar fashion to calculate time.
I'm not very familiar with ppc64's vDSO implementation, so please let me know if there is a constraint that would make this difficult.
thanks
-john