Commit 0aa366f3 authored by Tony Luck's avatar Tony Luck

[IA64] Convert to generic timekeeping/clocksource

This is a merge of Peter Keilty's initial patch (which was
revived by Bob Picco) for this with Hidetoshi Seto's fixes
and scaling improvements.
Acked-by: default avatarBob Picco <bob.picco@hp.com>
Signed-off-by: default avatarTony Luck <tony.luck@intel.com>
parent 5bae7ac9
...@@ -1154,6 +1154,8 @@ and is between 256 and 4096 characters. It is defined in the file ...@@ -1154,6 +1154,8 @@ and is between 256 and 4096 characters. It is defined in the file
nointroute [IA-64] nointroute [IA-64]
nojitter [IA64] Disables jitter checking for ITC timers.
nolapic [IA-32,APIC] Do not enable or use the local APIC. nolapic [IA-32,APIC] Do not enable or use the local APIC.
nolapic_timer [IA-32,APIC] Do not use the local APIC timer. nolapic_timer [IA-32,APIC] Do not use the local APIC timer.
......
...@@ -62,7 +62,11 @@ config GENERIC_CALIBRATE_DELAY ...@@ -62,7 +62,11 @@ config GENERIC_CALIBRATE_DELAY
bool bool
default y default y
config TIME_INTERPOLATION config GENERIC_TIME
bool
default y
config GENERIC_TIME_VSYSCALL
bool bool
default y default y
......
...@@ -85,7 +85,7 @@ CONFIG_MMU=y ...@@ -85,7 +85,7 @@ CONFIG_MMU=y
CONFIG_SWIOTLB=y CONFIG_SWIOTLB=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_TIME_INTERPOLATION=y CONFIG_GENERIC_TIME=y
CONFIG_EFI=y CONFIG_EFI=y
CONFIG_GENERIC_IOMAP=y CONFIG_GENERIC_IOMAP=y
CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
......
...@@ -86,7 +86,7 @@ CONFIG_MMU=y ...@@ -86,7 +86,7 @@ CONFIG_MMU=y
CONFIG_SWIOTLB=y CONFIG_SWIOTLB=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_TIME_INTERPOLATION=y CONFIG_GENERIC_TIME=y
CONFIG_EFI=y CONFIG_EFI=y
CONFIG_GENERIC_IOMAP=y CONFIG_GENERIC_IOMAP=y
CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
......
...@@ -86,7 +86,7 @@ CONFIG_MMU=y ...@@ -86,7 +86,7 @@ CONFIG_MMU=y
CONFIG_SWIOTLB=y CONFIG_SWIOTLB=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_TIME_INTERPOLATION=y CONFIG_GENERIC_TIME=y
CONFIG_EFI=y CONFIG_EFI=y
CONFIG_GENERIC_IOMAP=y CONFIG_GENERIC_IOMAP=y
CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
......
...@@ -93,7 +93,7 @@ CONFIG_SWIOTLB=y ...@@ -93,7 +93,7 @@ CONFIG_SWIOTLB=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_GENERIC_FIND_NEXT_BIT=y CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_TIME_INTERPOLATION=y CONFIG_GENERIC_TIME=y
CONFIG_DMI=y CONFIG_DMI=y
CONFIG_EFI=y CONFIG_EFI=y
CONFIG_GENERIC_IOMAP=y CONFIG_GENERIC_IOMAP=y
......
...@@ -98,7 +98,7 @@ CONFIG_RWSEM_XCHGADD_ALGORITHM=y ...@@ -98,7 +98,7 @@ CONFIG_RWSEM_XCHGADD_ALGORITHM=y
# CONFIG_ARCH_HAS_ILOG2_U64 is not set # CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_GENERIC_FIND_NEXT_BIT=y CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_TIME_INTERPOLATION=y CONFIG_GENERIC_TIME=y
CONFIG_DMI=y CONFIG_DMI=y
CONFIG_EFI=y CONFIG_EFI=y
CONFIG_GENERIC_IOMAP=y CONFIG_GENERIC_IOMAP=y
......
...@@ -96,7 +96,7 @@ CONFIG_RWSEM_XCHGADD_ALGORITHM=y ...@@ -96,7 +96,7 @@ CONFIG_RWSEM_XCHGADD_ALGORITHM=y
# CONFIG_ARCH_HAS_ILOG2_U64 is not set # CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_GENERIC_FIND_NEXT_BIT=y CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_TIME_INTERPOLATION=y CONFIG_GENERIC_TIME=y
CONFIG_DMI=y CONFIG_DMI=y
CONFIG_EFI=y CONFIG_EFI=y
CONFIG_GENERIC_IOMAP=y CONFIG_GENERIC_IOMAP=y
......
...@@ -98,7 +98,7 @@ CONFIG_RWSEM_XCHGADD_ALGORITHM=y ...@@ -98,7 +98,7 @@ CONFIG_RWSEM_XCHGADD_ALGORITHM=y
# CONFIG_ARCH_HAS_ILOG2_U64 is not set # CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_GENERIC_FIND_NEXT_BIT=y CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_TIME_INTERPOLATION=y CONFIG_GENERIC_TIME=y
CONFIG_DMI=y CONFIG_DMI=y
CONFIG_EFI=y CONFIG_EFI=y
CONFIG_GENERIC_IOMAP=y CONFIG_GENERIC_IOMAP=y
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#define ASM_OFFSETS_C 1 #define ASM_OFFSETS_C 1
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/clocksource.h>
#include <asm-ia64/processor.h> #include <asm-ia64/processor.h>
#include <asm-ia64/ptrace.h> #include <asm-ia64/ptrace.h>
...@@ -15,6 +16,7 @@ ...@@ -15,6 +16,7 @@
#include <asm-ia64/mca.h> #include <asm-ia64/mca.h>
#include "../kernel/sigframe.h" #include "../kernel/sigframe.h"
#include "../kernel/fsyscall_gtod_data.h"
#define DEFINE(sym, val) \ #define DEFINE(sym, val) \
asm volatile("\n->" #sym " %0 " #val : : "i" (val)) asm volatile("\n->" #sym " %0 " #val : : "i" (val))
...@@ -256,17 +258,24 @@ void foo(void) ...@@ -256,17 +258,24 @@ void foo(void)
BLANK(); BLANK();
/* used by fsys_gettimeofday in arch/ia64/kernel/fsys.S */ /* used by fsys_gettimeofday in arch/ia64/kernel/fsys.S */
DEFINE(IA64_TIME_INTERPOLATOR_ADDRESS_OFFSET, offsetof (struct time_interpolator, addr)); DEFINE(IA64_GTOD_LOCK_OFFSET,
DEFINE(IA64_TIME_INTERPOLATOR_SOURCE_OFFSET, offsetof (struct time_interpolator, source)); offsetof (struct fsyscall_gtod_data_t, lock));
DEFINE(IA64_TIME_INTERPOLATOR_SHIFT_OFFSET, offsetof (struct time_interpolator, shift)); DEFINE(IA64_GTOD_WALL_TIME_OFFSET,
DEFINE(IA64_TIME_INTERPOLATOR_NSEC_OFFSET, offsetof (struct time_interpolator, nsec_per_cyc)); offsetof (struct fsyscall_gtod_data_t, wall_time));
DEFINE(IA64_TIME_INTERPOLATOR_OFFSET_OFFSET, offsetof (struct time_interpolator, offset)); DEFINE(IA64_GTOD_MONO_TIME_OFFSET,
DEFINE(IA64_TIME_INTERPOLATOR_LAST_CYCLE_OFFSET, offsetof (struct time_interpolator, last_cycle)); offsetof (struct fsyscall_gtod_data_t, monotonic_time));
DEFINE(IA64_TIME_INTERPOLATOR_LAST_COUNTER_OFFSET, offsetof (struct time_interpolator, last_counter)); DEFINE(IA64_CLKSRC_MASK_OFFSET,
DEFINE(IA64_TIME_INTERPOLATOR_JITTER_OFFSET, offsetof (struct time_interpolator, jitter)); offsetof (struct fsyscall_gtod_data_t, clk_mask));
DEFINE(IA64_TIME_INTERPOLATOR_MASK_OFFSET, offsetof (struct time_interpolator, mask)); DEFINE(IA64_CLKSRC_MULT_OFFSET,
DEFINE(IA64_TIME_SOURCE_CPU, TIME_SOURCE_CPU); offsetof (struct fsyscall_gtod_data_t, clk_mult));
DEFINE(IA64_TIME_SOURCE_MMIO64, TIME_SOURCE_MMIO64); DEFINE(IA64_CLKSRC_SHIFT_OFFSET,
DEFINE(IA64_TIME_SOURCE_MMIO32, TIME_SOURCE_MMIO32); offsetof (struct fsyscall_gtod_data_t, clk_shift));
DEFINE(IA64_TIMESPEC_TV_NSEC_OFFSET, offsetof (struct timespec, tv_nsec)); DEFINE(IA64_CLKSRC_MMIO_OFFSET,
offsetof (struct fsyscall_gtod_data_t, clk_fsys_mmio));
DEFINE(IA64_CLKSRC_CYCLE_LAST_OFFSET,
offsetof (struct fsyscall_gtod_data_t, clk_cycle_last));
DEFINE(IA64_ITC_JITTER_OFFSET,
offsetof (struct itc_jitter_data_t, itc_jitter));
DEFINE(IA64_ITC_LASTCYCLE_OFFSET,
offsetof (struct itc_jitter_data_t, itc_lastcycle));
} }
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include <linux/time.h> #include <linux/time.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/timex.h> #include <linux/timex.h>
#include <linux/clocksource.h>
#include <asm/io.h> #include <asm/io.h>
/* IBM Summit (EXA) Cyclone counter code*/ /* IBM Summit (EXA) Cyclone counter code*/
...@@ -18,13 +19,21 @@ void __init cyclone_setup(void) ...@@ -18,13 +19,21 @@ void __init cyclone_setup(void)
use_cyclone = 1; use_cyclone = 1;
} }
static void __iomem *cyclone_mc;
struct time_interpolator cyclone_interpolator = { static cycle_t read_cyclone(void)
.source = TIME_SOURCE_MMIO64, {
.shift = 16, return (cycle_t)readq((void __iomem *)cyclone_mc);
.frequency = CYCLONE_TIMER_FREQ, }
.drift = -100,
.mask = (1LL << 40) - 1 static struct clocksource clocksource_cyclone = {
.name = "cyclone",
.rating = 300,
.read = read_cyclone,
.mask = (1LL << 40) - 1,
.mult = 0, /*to be caluclated*/
.shift = 16,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
}; };
int __init init_cyclone_clock(void) int __init init_cyclone_clock(void)
...@@ -44,13 +53,15 @@ int __init init_cyclone_clock(void) ...@@ -44,13 +53,15 @@ int __init init_cyclone_clock(void)
offset = (CYCLONE_CBAR_ADDR); offset = (CYCLONE_CBAR_ADDR);
reg = (u64*)ioremap_nocache(offset, sizeof(u64)); reg = (u64*)ioremap_nocache(offset, sizeof(u64));
if(!reg){ if(!reg){
printk(KERN_ERR "Summit chipset: Could not find valid CBAR register.\n"); printk(KERN_ERR "Summit chipset: Could not find valid CBAR"
" register.\n");
use_cyclone = 0; use_cyclone = 0;
return -ENODEV; return -ENODEV;
} }
base = readq(reg); base = readq(reg);
if(!base){ if(!base){
printk(KERN_ERR "Summit chipset: Could not find valid CBAR value.\n"); printk(KERN_ERR "Summit chipset: Could not find valid CBAR"
" value.\n");
use_cyclone = 0; use_cyclone = 0;
return -ENODEV; return -ENODEV;
} }
...@@ -60,7 +71,8 @@ int __init init_cyclone_clock(void) ...@@ -60,7 +71,8 @@ int __init init_cyclone_clock(void)
offset = (base + CYCLONE_PMCC_OFFSET); offset = (base + CYCLONE_PMCC_OFFSET);
reg = (u64*)ioremap_nocache(offset, sizeof(u64)); reg = (u64*)ioremap_nocache(offset, sizeof(u64));
if(!reg){ if(!reg){
printk(KERN_ERR "Summit chipset: Could not find valid PMCC register.\n"); printk(KERN_ERR "Summit chipset: Could not find valid PMCC"
" register.\n");
use_cyclone = 0; use_cyclone = 0;
return -ENODEV; return -ENODEV;
} }
...@@ -71,7 +83,8 @@ int __init init_cyclone_clock(void) ...@@ -71,7 +83,8 @@ int __init init_cyclone_clock(void)
offset = (base + CYCLONE_MPCS_OFFSET); offset = (base + CYCLONE_MPCS_OFFSET);
reg = (u64*)ioremap_nocache(offset, sizeof(u64)); reg = (u64*)ioremap_nocache(offset, sizeof(u64));
if(!reg){ if(!reg){
printk(KERN_ERR "Summit chipset: Could not find valid MPCS register.\n"); printk(KERN_ERR "Summit chipset: Could not find valid MPCS"
" register.\n");
use_cyclone = 0; use_cyclone = 0;
return -ENODEV; return -ENODEV;
} }
...@@ -82,7 +95,8 @@ int __init init_cyclone_clock(void) ...@@ -82,7 +95,8 @@ int __init init_cyclone_clock(void)
offset = (base + CYCLONE_MPMC_OFFSET); offset = (base + CYCLONE_MPMC_OFFSET);
cyclone_timer = (u32*)ioremap_nocache(offset, sizeof(u32)); cyclone_timer = (u32*)ioremap_nocache(offset, sizeof(u32));
if(!cyclone_timer){ if(!cyclone_timer){
printk(KERN_ERR "Summit chipset: Could not find valid MPMC register.\n"); printk(KERN_ERR "Summit chipset: Could not find valid MPMC"
" register.\n");
use_cyclone = 0; use_cyclone = 0;
return -ENODEV; return -ENODEV;
} }
...@@ -93,7 +107,8 @@ int __init init_cyclone_clock(void) ...@@ -93,7 +107,8 @@ int __init init_cyclone_clock(void)
int stall = 100; int stall = 100;
while(stall--) barrier(); while(stall--) barrier();
if(readl(cyclone_timer) == old){ if(readl(cyclone_timer) == old){
printk(KERN_ERR "Summit chipset: Counter not counting! DISABLED\n"); printk(KERN_ERR "Summit chipset: Counter not counting!"
" DISABLED\n");
iounmap(cyclone_timer); iounmap(cyclone_timer);
cyclone_timer = 0; cyclone_timer = 0;
use_cyclone = 0; use_cyclone = 0;
...@@ -101,8 +116,11 @@ int __init init_cyclone_clock(void) ...@@ -101,8 +116,11 @@ int __init init_cyclone_clock(void)
} }
} }
/* initialize last tick */ /* initialize last tick */
cyclone_interpolator.addr = cyclone_timer; cyclone_mc = cyclone_timer;
register_time_interpolator(&cyclone_interpolator); clocksource_cyclone.fsys_mmio = cyclone_timer;
clocksource_cyclone.mult = clocksource_hz2mult(CYCLONE_TIMER_FREQ,
clocksource_cyclone.shift);
clocksource_register(&clocksource_cyclone);
return 0; return 0;
} }
......
This diff is collapsed.
/*
* (c) Copyright 2007 Hewlett-Packard Development Company, L.P.
* Contributed by Peter Keilty <peter.keilty@hp.com>
*
* fsyscall gettimeofday data
*/
struct fsyscall_gtod_data_t {
seqlock_t lock;
struct timespec wall_time;
struct timespec monotonic_time;
cycle_t clk_mask;
u32 clk_mult;
u32 clk_shift;
void *clk_fsys_mmio;
cycle_t clk_cycle_last;
} __attribute__ ((aligned (L1_CACHE_BYTES)));
struct itc_jitter_data_t {
int itc_jitter;
cycle_t itc_lastcycle;
} __attribute__ ((aligned (L1_CACHE_BYTES)));
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/efi.h> #include <linux/efi.h>
#include <linux/timex.h> #include <linux/timex.h>
#include <linux/clocksource.h>
#include <asm/machvec.h> #include <asm/machvec.h>
#include <asm/delay.h> #include <asm/delay.h>
...@@ -28,6 +29,16 @@ ...@@ -28,6 +29,16 @@
#include <asm/sections.h> #include <asm/sections.h>
#include <asm/system.h> #include <asm/system.h>
#include "fsyscall_gtod_data.h"
static cycle_t itc_get_cycles(void);
struct fsyscall_gtod_data_t fsyscall_gtod_data = {
.lock = SEQLOCK_UNLOCKED,
};
struct itc_jitter_data_t itc_jitter_data;
volatile int time_keeper_id = 0; /* smp_processor_id() of time-keeper */ volatile int time_keeper_id = 0; /* smp_processor_id() of time-keeper */
#ifdef CONFIG_IA64_DEBUG_IRQ #ifdef CONFIG_IA64_DEBUG_IRQ
...@@ -37,11 +48,16 @@ EXPORT_SYMBOL(last_cli_ip); ...@@ -37,11 +48,16 @@ EXPORT_SYMBOL(last_cli_ip);
#endif #endif
static struct time_interpolator itc_interpolator = { static struct clocksource clocksource_itc = {
.shift = 16, .name = "itc",
.mask = 0xffffffffffffffffLL, .rating = 350,
.source = TIME_SOURCE_CPU .read = itc_get_cycles,
.mask = 0xffffffffffffffff,
.mult = 0, /*to be caluclated*/
.shift = 16,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
}; };
static struct clocksource *itc_clocksource;
static irqreturn_t static irqreturn_t
timer_interrupt (int irq, void *dev_id) timer_interrupt (int irq, void *dev_id)
...@@ -210,8 +226,6 @@ ia64_init_itm (void) ...@@ -210,8 +226,6 @@ ia64_init_itm (void)
+ itc_freq/2)/itc_freq; + itc_freq/2)/itc_freq;
if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT)) { if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT)) {
itc_interpolator.frequency = local_cpu_data->itc_freq;
itc_interpolator.drift = itc_drift;
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
/* On IA64 in an SMP configuration ITCs are never accurately synchronized. /* On IA64 in an SMP configuration ITCs are never accurately synchronized.
* Jitter compensation requires a cmpxchg which may limit * Jitter compensation requires a cmpxchg which may limit
...@@ -223,15 +237,50 @@ ia64_init_itm (void) ...@@ -223,15 +237,50 @@ ia64_init_itm (void)
* even going backward) if the ITC offsets between the individual CPUs * even going backward) if the ITC offsets between the individual CPUs
* are too large. * are too large.
*/ */
if (!nojitter) itc_interpolator.jitter = 1; if (!nojitter)
itc_jitter_data.itc_jitter = 1;
#endif #endif
register_time_interpolator(&itc_interpolator);
} }
/* Setup the CPU local timer tick */ /* Setup the CPU local timer tick */
ia64_cpu_local_tick(); ia64_cpu_local_tick();
if (!itc_clocksource) {
/* Sort out mult/shift values: */
clocksource_itc.mult =
clocksource_hz2mult(local_cpu_data->itc_freq,
clocksource_itc.shift);
clocksource_register(&clocksource_itc);
itc_clocksource = &clocksource_itc;
}
} }
static cycle_t itc_get_cycles()
{
u64 lcycle, now, ret;
if (!itc_jitter_data.itc_jitter)
return get_cycles();
lcycle = itc_jitter_data.itc_lastcycle;
now = get_cycles();
if (lcycle && time_after(lcycle, now))
return lcycle;
/*
* Keep track of the last timer value returned.
* In an SMP environment, you could lose out in contention of
* cmpxchg. If so, your cmpxchg returns new value which the
* winner of contention updated to. Use the new value instead.
*/
ret = cmpxchg(&itc_jitter_data.itc_lastcycle, lcycle, now);
if (unlikely(ret != lcycle))
return ret;
return now;
}
static struct irqaction timer_irqaction = { static struct irqaction timer_irqaction = {
.handler = timer_interrupt, .handler = timer_interrupt,
.flags = IRQF_DISABLED | IRQF_IRQPOLL, .flags = IRQF_DISABLED | IRQF_IRQPOLL,
...@@ -307,3 +356,34 @@ ia64_setup_printk_clock(void) ...@@ -307,3 +356,34 @@ ia64_setup_printk_clock(void)
if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT)) if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT))
ia64_printk_clock = ia64_itc_printk_clock; ia64_printk_clock = ia64_itc_printk_clock;
} }
void update_vsyscall(struct timespec *wall, struct clocksource *c)
{
unsigned long flags;
write_seqlock_irqsave(&fsyscall_gtod_data.lock, flags);
/* copy fsyscall clock data */
fsyscall_gtod_data.clk_mask = c->mask;
fsyscall_gtod_data.clk_mult = c->mult;
fsyscall_gtod_data.clk_shift = c->shift;
fsyscall_gtod_data.clk_fsys_mmio = c->fsys_mmio;
fsyscall_gtod_data.clk_cycle_last = c->cycle_last;
/* copy kernel time structures */
fsyscall_gtod_data.wall_time.tv_sec = wall->tv_sec;
fsyscall_gtod_data.wall_time.tv_nsec = wall->tv_nsec;
fsyscall_gtod_data.monotonic_time.tv_sec = wall_to_monotonic.tv_sec
+ wall->tv_sec;
fsyscall_gtod_data.monotonic_time.tv_nsec = wall_to_monotonic.tv_nsec
+ wall->tv_nsec;
/* normalize */
while (fsyscall_gtod_data.monotonic_time.tv_nsec >= NSEC_PER_SEC) {
fsyscall_gtod_data.monotonic_time.tv_nsec -= NSEC_PER_SEC;
fsyscall_gtod_data.monotonic_time.tv_sec++;
}
write_sequnlock_irqrestore(&fsyscall_gtod_data.lock, flags);
}
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/time.h> #include <linux/time.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/clocksource.h>
#include <asm/hw_irq.h> #include <asm/hw_irq.h>
#include <asm/system.h> #include <asm/system.h>
...@@ -22,11 +23,21 @@ ...@@ -22,11 +23,21 @@
extern unsigned long sn_rtc_cycles_per_second; extern unsigned long sn_rtc_cycles_per_second;
static struct time_interpolator sn2_interpolator = { static void __iomem *sn2_mc;
.drift = -1,
.shift = 10, static cycle_t read_sn2(void)
.mask = (1LL << 55) - 1, {
.source = TIME_SOURCE_MMIO64 return (cycle_t)readq(sn2_mc);
}
static struct clocksource clocksource_sn2 = {
.name = "sn2_rtc",
.rating = 300,
.read = read_sn2,
.mask = (1LL << 55) - 1,
.mult = 0,
.shift = 10,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
}; };
/* /*
...@@ -47,9 +58,11 @@ ia64_sn_udelay (unsigned long usecs) ...@@ -47,9 +58,11 @@ ia64_sn_udelay (unsigned long usecs)
void __init sn_timer_init(void) void __init sn_timer_init(void)
{ {
sn2_interpolator.frequency = sn_rtc_cycles_per_second; sn2_mc = RTC_COUNTER_ADDR;
sn2_interpolator.addr = RTC_COUNTER_ADDR; clocksource_sn2.fsys_mmio = RTC_COUNTER_ADDR;
register_time_interpolator(&sn2_interpolator); clocksource_sn2.mult = clocksource_hz2mult(sn_rtc_cycles_per_second,
clocksource_sn2.shift);
clocksource_register(&clocksource_sn2);
ia64_udelay = &ia64_sn_udelay; ia64_udelay = &ia64_sn_udelay;
} }
...@@ -475,7 +475,7 @@ static void acpi_processor_idle(void) ...@@ -475,7 +475,7 @@ static void acpi_processor_idle(void)
/* Get end time (ticks) */ /* Get end time (ticks) */
t2 = inl(acpi_gbl_FADT.xpm_timer_block.address); t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
#ifdef CONFIG_GENERIC_TIME #if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
/* TSC halts in C2, so notify users */ /* TSC halts in C2, so notify users */
mark_tsc_unstable("possible TSC halt in C2"); mark_tsc_unstable("possible TSC halt in C2");
#endif #endif
...@@ -517,7 +517,7 @@ static void acpi_processor_idle(void) ...@@ -517,7 +517,7 @@ static void acpi_processor_idle(void)
acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0); acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
} }
#ifdef CONFIG_GENERIC_TIME #if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
/* TSC halts in C3, so notify users */ /* TSC halts in C3, so notify users */
mark_tsc_unstable("TSC halts in C3"); mark_tsc_unstable("TSC halts in C3");
#endif #endif
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <linux/bcd.h> #include <linux/bcd.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/clocksource.h>
#include <asm/current.h> #include <asm/current.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -51,8 +52,34 @@ ...@@ -51,8 +52,34 @@
#define HPET_RANGE_SIZE 1024 /* from HPET spec */ #define HPET_RANGE_SIZE 1024 /* from HPET spec */
#if BITS_PER_LONG == 64
#define write_counter(V, MC) writeq(V, MC)
#define read_counter(MC) readq(MC)
#else
#define write_counter(V, MC) writel(V, MC)
#define read_counter(MC) readl(MC)
#endif
static u32 hpet_nhpet, hpet_max_freq = HPET_USER_FREQ; static u32 hpet_nhpet, hpet_max_freq = HPET_USER_FREQ;
static void __iomem *hpet_mctr;
static cycle_t read_hpet(void)
{
return (cycle_t)read_counter((void __iomem *)hpet_mctr);
}
static struct clocksource clocksource_hpet = {
.name = "hpet",
.rating = 250,
.read = read_hpet,
.mask = 0xffffffffffffffff,
.mult = 0, /*to be caluclated*/
.shift = 10,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
static struct clocksource *hpet_clocksource;
/* A lock for concurrent access by app and isr hpet activity. */ /* A lock for concurrent access by app and isr hpet activity. */
static DEFINE_SPINLOCK(hpet_lock); static DEFINE_SPINLOCK(hpet_lock);
/* A lock for concurrent intermodule access to hpet and isr hpet activity. */ /* A lock for concurrent intermodule access to hpet and isr hpet activity. */
...@@ -79,7 +106,7 @@ struct hpets { ...@@ -79,7 +106,7 @@ struct hpets {
struct hpets *hp_next; struct hpets *hp_next;
struct hpet __iomem *hp_hpet; struct hpet __iomem *hp_hpet;
unsigned long hp_hpet_phys; unsigned long hp_hpet_phys;
struct time_interpolator *hp_interpolator; struct clocksource *hp_clocksource;
unsigned long long hp_tick_freq; unsigned long long hp_tick_freq;
unsigned long hp_delta; unsigned long hp_delta;
unsigned int hp_ntimer; unsigned int hp_ntimer;
...@@ -94,13 +121,6 @@ static struct hpets *hpets; ...@@ -94,13 +121,6 @@ static struct hpets *hpets;
#define HPET_PERIODIC 0x0004 #define HPET_PERIODIC 0x0004
#define HPET_SHARED_IRQ 0x0008 #define HPET_SHARED_IRQ 0x0008
#if BITS_PER_LONG == 64
#define write_counter(V, MC) writeq(V, MC)
#define read_counter(MC) readq(MC)
#else
#define write_counter(V, MC) writel(V, MC)
#define read_counter(MC) readl(MC)
#endif
#ifndef readq #ifndef readq
static inline unsigned long long readq(void __iomem *addr) static inline unsigned long long readq(void __iomem *addr)
...@@ -737,27 +757,6 @@ static ctl_table dev_root[] = { ...@@ -737,27 +757,6 @@ static ctl_table dev_root[] = {
static struct ctl_table_header *sysctl_header; static struct ctl_table_header *sysctl_header;
static void hpet_register_interpolator(struct hpets *hpetp)
{
#ifdef CONFIG_TIME_INTERPOLATION
struct time_interpolator *ti;
ti = kzalloc(sizeof(*ti), GFP_KERNEL);
if (!ti)
return;
ti->source = TIME_SOURCE_MMIO64;
ti->shift = 10;
ti->addr = &hpetp->hp_hpet->hpet_mc;
ti->frequency = hpetp->hp_tick_freq;
ti->drift = HPET_DRIFT;
ti->mask = -1;
hpetp->hp_interpolator = ti;
register_time_interpolator(ti);
#endif
}
/* /*
* Adjustment for when arming the timer with * Adjustment for when arming the timer with
* initial conditions. That is, main counter * initial conditions. That is, main counter
...@@ -909,7 +908,16 @@ int hpet_alloc(struct hpet_data *hdp) ...@@ -909,7 +908,16 @@ int hpet_alloc(struct hpet_data *hdp)
} }
hpetp->hp_delta = hpet_calibrate(hpetp); hpetp->hp_delta = hpet_calibrate(hpetp);
hpet_register_interpolator(hpetp);
if (!hpet_clocksource) {
hpet_mctr = (void __iomem *)&hpetp->hp_hpet->hpet_mc;
CLKSRC_FSYS_MMIO_SET(clocksource_hpet.fsys_mmio, hpet_mctr);
clocksource_hpet.mult = clocksource_hz2mult(hpetp->hp_tick_freq,
clocksource_hpet.shift);
clocksource_register(&clocksource_hpet);
hpetp->hp_clocksource = &clocksource_hpet;
hpet_clocksource = &clocksource_hpet;
}
return 0; return 0;
} }
...@@ -995,7 +1003,7 @@ static int hpet_acpi_add(struct acpi_device *device) ...@@ -995,7 +1003,7 @@ static int hpet_acpi_add(struct acpi_device *device)
static int hpet_acpi_remove(struct acpi_device *device, int type) static int hpet_acpi_remove(struct acpi_device *device, int type)
{ {
/* XXX need to unregister interpolator, dealloc mem, etc */ /* XXX need to unregister clocksource, dealloc mem, etc */
return -EINVAL; return -EINVAL;
} }
......
...@@ -67,6 +67,12 @@ struct clocksource { ...@@ -67,6 +67,12 @@ struct clocksource {
unsigned long flags; unsigned long flags;
cycle_t (*vread)(void); cycle_t (*vread)(void);
void (*resume)(void); void (*resume)(void);
#ifdef CONFIG_IA64
void *fsys_mmio; /* used by fsyscall asm code */
#define CLKSRC_FSYS_MMIO_SET(mmio, addr) ((mmio) = (addr))
#else
#define CLKSRC_FSYS_MMIO_SET(mmio, addr) do { } while (0)
#endif
/* timekeeping specific data, ignore */ /* timekeeping specific data, ignore */
cycle_t cycle_interval; cycle_t cycle_interval;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment