ia64/xen-unstable

changeset 14295:9f8e996a678d

[IA64] Add arch/ia64/kernel/time.c to spare tree for steal time accounting

Signed-off-by: Atsushi SAKAI <sakaia@jp.fujitsu.com>
author awilliam@xenbuild2.aw
date Wed Mar 07 12:45:08 2007 -0700 (2007-03-07)
parents 210858e4f6d5
children 4e367aa89895
files linux-2.6-xen-sparse/arch/ia64/kernel/time.c
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/linux-2.6-xen-sparse/arch/ia64/kernel/time.c	Wed Mar 07 12:45:08 2007 -0700
     1.3 @@ -0,0 +1,306 @@
     1.4 +/*
     1.5 + * linux/arch/ia64/kernel/time.c
     1.6 + *
     1.7 + * Copyright (C) 1998-2003 Hewlett-Packard Co
     1.8 + *	Stephane Eranian <eranian@hpl.hp.com>
     1.9 + *	David Mosberger <davidm@hpl.hp.com>
    1.10 + * Copyright (C) 1999 Don Dugger <don.dugger@intel.com>
    1.11 + * Copyright (C) 1999-2000 VA Linux Systems
    1.12 + * Copyright (C) 1999-2000 Walt Drummond <drummond@valinux.com>
    1.13 + */
    1.14 +
    1.15 +#include <linux/cpu.h>
    1.16 +#include <linux/init.h>
    1.17 +#include <linux/kernel.h>
    1.18 +#include <linux/module.h>
    1.19 +#include <linux/profile.h>
    1.20 +#include <linux/sched.h>
    1.21 +#include <linux/time.h>
    1.22 +#include <linux/interrupt.h>
    1.23 +#include <linux/efi.h>
    1.24 +#include <linux/profile.h>
    1.25 +#include <linux/timex.h>
    1.26 +
    1.27 +#include <asm/machvec.h>
    1.28 +#include <asm/delay.h>
    1.29 +#include <asm/hw_irq.h>
    1.30 +#include <asm/ptrace.h>
    1.31 +#include <asm/sal.h>
    1.32 +#include <asm/sections.h>
    1.33 +#include <asm/system.h>
    1.34 +
    1.35 +extern unsigned long wall_jiffies;
    1.36 +
    1.37 +volatile int time_keeper_id = 0; /* smp_processor_id() of time-keeper */
    1.38 +
    1.39 +#ifdef CONFIG_IA64_DEBUG_IRQ
    1.40 +
    1.41 +unsigned long last_cli_ip;
    1.42 +EXPORT_SYMBOL(last_cli_ip);
    1.43 +
    1.44 +#endif
    1.45 +
    1.46 +static struct time_interpolator itc_interpolator = {
    1.47 +	.shift = 16,
    1.48 +	.mask = 0xffffffffffffffffLL,
    1.49 +	.source = TIME_SOURCE_CPU
    1.50 +};
    1.51 +
    1.52 +static irqreturn_t
    1.53 +timer_interrupt (int irq, void *dev_id, struct pt_regs *regs)
    1.54 +{
    1.55 +	unsigned long new_itm;
    1.56 +
    1.57 +	if (unlikely(cpu_is_offline(smp_processor_id()))) {
    1.58 +		return IRQ_HANDLED;
    1.59 +	}
    1.60 +
    1.61 +	platform_timer_interrupt(irq, dev_id, regs);
    1.62 +
    1.63 +	new_itm = local_cpu_data->itm_next;
    1.64 +
    1.65 +	if (!time_after(ia64_get_itc(), new_itm))
    1.66 +		printk(KERN_ERR "Oops: timer tick before it's due (itc=%lx,itm=%lx)\n",
    1.67 +		       ia64_get_itc(), new_itm);
    1.68 +
    1.69 +	profile_tick(CPU_PROFILING, regs);
    1.70 +
    1.71 +	while (1) {
    1.72 +		update_process_times(user_mode(regs));
    1.73 +
    1.74 +		new_itm += local_cpu_data->itm_delta;
    1.75 +
    1.76 +		if (smp_processor_id() == time_keeper_id) {
    1.77 +			/*
    1.78 +			 * Here we are in the timer irq handler. We have irqs locally
    1.79 +			 * disabled, but we don't know if the timer_bh is running on
    1.80 +			 * another CPU. We need to avoid to SMP race by acquiring the
    1.81 +			 * xtime_lock.
    1.82 +			 */
    1.83 +			write_seqlock(&xtime_lock);
    1.84 +			do_timer(regs);
    1.85 +			local_cpu_data->itm_next = new_itm;
    1.86 +			write_sequnlock(&xtime_lock);
    1.87 +		} else
    1.88 +			local_cpu_data->itm_next = new_itm;
    1.89 +
    1.90 +		if (time_after(new_itm, ia64_get_itc()))
    1.91 +			break;
    1.92 +	}
    1.93 +
    1.94 +	do {
    1.95 +		/*
    1.96 +		 * If we're too close to the next clock tick for
    1.97 +		 * comfort, we increase the safety margin by
    1.98 +		 * intentionally dropping the next tick(s).  We do NOT
    1.99 +		 * update itm.next because that would force us to call
   1.100 +		 * do_timer() which in turn would let our clock run
   1.101 +		 * too fast (with the potentially devastating effect
   1.102 +		 * of losing monotony of time).
   1.103 +		 */
   1.104 +		while (!time_after(new_itm, ia64_get_itc() + local_cpu_data->itm_delta/2))
   1.105 +			new_itm += local_cpu_data->itm_delta;
   1.106 +		ia64_set_itm(new_itm);
   1.107 +		/* double check, in case we got hit by a (slow) PMI: */
   1.108 +	} while (time_after_eq(ia64_get_itc(), new_itm));
   1.109 +	return IRQ_HANDLED;
   1.110 +}
   1.111 +
   1.112 +/*
   1.113 + * Encapsulate access to the itm structure for SMP.
   1.114 + */
   1.115 +void
   1.116 +ia64_cpu_local_tick (void)
   1.117 +{
   1.118 +	int cpu = smp_processor_id();
   1.119 +	unsigned long shift = 0, delta;
   1.120 +
   1.121 +	/* arrange for the cycle counter to generate a timer interrupt: */
   1.122 +	ia64_set_itv(IA64_TIMER_VECTOR);
   1.123 +
   1.124 +	delta = local_cpu_data->itm_delta;
   1.125 +	/*
   1.126 +	 * Stagger the timer tick for each CPU so they don't occur all at (almost) the
   1.127 +	 * same time:
   1.128 +	 */
   1.129 +	if (cpu) {
   1.130 +		unsigned long hi = 1UL << ia64_fls(cpu);
   1.131 +		shift = (2*(cpu - hi) + 1) * delta/hi/2;
   1.132 +	}
   1.133 +	local_cpu_data->itm_next = ia64_get_itc() + delta + shift;
   1.134 +	ia64_set_itm(local_cpu_data->itm_next);
   1.135 +}
   1.136 +
   1.137 +static int nojitter;
   1.138 +
   1.139 +static int __init nojitter_setup(char *str)
   1.140 +{
   1.141 +	nojitter = 1;
   1.142 +	printk("Jitter checking for ITC timers disabled\n");
   1.143 +	return 1;
   1.144 +}
   1.145 +
   1.146 +__setup("nojitter", nojitter_setup);
   1.147 +
   1.148 +
   1.149 +void __devinit
   1.150 +ia64_init_itm (void)
   1.151 +{
   1.152 +	unsigned long platform_base_freq, itc_freq;
   1.153 +	struct pal_freq_ratio itc_ratio, proc_ratio;
   1.154 +	long status, platform_base_drift, itc_drift;
   1.155 +
   1.156 +	/*
   1.157 +	 * According to SAL v2.6, we need to use a SAL call to determine the platform base
   1.158 +	 * frequency and then a PAL call to determine the frequency ratio between the ITC
   1.159 +	 * and the base frequency.
   1.160 +	 */
   1.161 +	status = ia64_sal_freq_base(SAL_FREQ_BASE_PLATFORM,
   1.162 +				    &platform_base_freq, &platform_base_drift);
   1.163 +	if (status != 0) {
   1.164 +		printk(KERN_ERR "SAL_FREQ_BASE_PLATFORM failed: %s\n", ia64_sal_strerror(status));
   1.165 +	} else {
   1.166 +		status = ia64_pal_freq_ratios(&proc_ratio, NULL, &itc_ratio);
   1.167 +		if (status != 0)
   1.168 +			printk(KERN_ERR "PAL_FREQ_RATIOS failed with status=%ld\n", status);
   1.169 +	}
   1.170 +	if (status != 0) {
   1.171 +		/* invent "random" values */
   1.172 +		printk(KERN_ERR
   1.173 +		       "SAL/PAL failed to obtain frequency info---inventing reasonable values\n");
   1.174 +		platform_base_freq = 100000000;
   1.175 +		platform_base_drift = -1;	/* no drift info */
   1.176 +		itc_ratio.num = 3;
   1.177 +		itc_ratio.den = 1;
   1.178 +	}
   1.179 +	if (platform_base_freq < 40000000) {
   1.180 +		printk(KERN_ERR "Platform base frequency %lu bogus---resetting to 75MHz!\n",
   1.181 +		       platform_base_freq);
   1.182 +		platform_base_freq = 75000000;
   1.183 +		platform_base_drift = -1;
   1.184 +	}
   1.185 +	if (!proc_ratio.den)
   1.186 +		proc_ratio.den = 1;	/* avoid division by zero */
   1.187 +	if (!itc_ratio.den)
   1.188 +		itc_ratio.den = 1;	/* avoid division by zero */
   1.189 +
   1.190 +	itc_freq = (platform_base_freq*itc_ratio.num)/itc_ratio.den;
   1.191 +
   1.192 +	local_cpu_data->itm_delta = (itc_freq + HZ/2) / HZ;
   1.193 +	printk(KERN_DEBUG "CPU %d: base freq=%lu.%03luMHz, ITC ratio=%u/%u, "
   1.194 +	       "ITC freq=%lu.%03luMHz", smp_processor_id(),
   1.195 +	       platform_base_freq / 1000000, (platform_base_freq / 1000) % 1000,
   1.196 +	       itc_ratio.num, itc_ratio.den, itc_freq / 1000000, (itc_freq / 1000) % 1000);
   1.197 +
   1.198 +	if (platform_base_drift != -1) {
   1.199 +		itc_drift = platform_base_drift*itc_ratio.num/itc_ratio.den;
   1.200 +		printk("+/-%ldppm\n", itc_drift);
   1.201 +	} else {
   1.202 +		itc_drift = -1;
   1.203 +		printk("\n");
   1.204 +	}
   1.205 +
   1.206 +	local_cpu_data->proc_freq = (platform_base_freq*proc_ratio.num)/proc_ratio.den;
   1.207 +	local_cpu_data->itc_freq = itc_freq;
   1.208 +	local_cpu_data->cyc_per_usec = (itc_freq + USEC_PER_SEC/2) / USEC_PER_SEC;
   1.209 +	local_cpu_data->nsec_per_cyc = ((NSEC_PER_SEC<<IA64_NSEC_PER_CYC_SHIFT)
   1.210 +					+ itc_freq/2)/itc_freq;
   1.211 +
   1.212 +	if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT)) {
   1.213 +		itc_interpolator.frequency = local_cpu_data->itc_freq;
   1.214 +		itc_interpolator.drift = itc_drift;
   1.215 +#ifdef CONFIG_SMP
   1.216 +		/* On IA64 in an SMP configuration ITCs are never accurately synchronized.
   1.217 +		 * Jitter compensation requires a cmpxchg which may limit
   1.218 +		 * the scalability of the syscalls for retrieving time.
   1.219 +		 * The ITC synchronization is usually successful to within a few
   1.220 +		 * ITC ticks but this is not a sure thing. If you need to improve
   1.221 +		 * timer performance in SMP situations then boot the kernel with the
   1.222 +		 * "nojitter" option. However, doing so may result in time fluctuating (maybe
   1.223 +		 * even going backward) if the ITC offsets between the individual CPUs
   1.224 +		 * are too large.
   1.225 +		 */
   1.226 +		if (!nojitter) itc_interpolator.jitter = 1;
   1.227 +#endif
   1.228 +		register_time_interpolator(&itc_interpolator);
   1.229 +	}
   1.230 +
   1.231 +	/* Setup the CPU local timer tick */
   1.232 +	ia64_cpu_local_tick();
   1.233 +}
   1.234 +
   1.235 +static struct irqaction timer_irqaction = {
   1.236 +	.handler =	timer_interrupt,
   1.237 +	.flags =	IRQF_DISABLED,
   1.238 +	.name =		"timer"
   1.239 +};
   1.240 +
   1.241 +void __devinit ia64_disable_timer(void)
   1.242 +{
   1.243 +	ia64_set_itv(1 << 16);
   1.244 +}
   1.245 +
   1.246 +void __init
   1.247 +time_init (void)
   1.248 +{
   1.249 +	register_percpu_irq(IA64_TIMER_VECTOR, &timer_irqaction);
   1.250 +	efi_gettimeofday(&xtime);
   1.251 +	ia64_init_itm();
   1.252 +
   1.253 +	/*
   1.254 +	 * Initialize wall_to_monotonic such that adding it to xtime will yield zero, the
   1.255 +	 * tv_nsec field must be normalized (i.e., 0 <= nsec < NSEC_PER_SEC).
   1.256 +	 */
   1.257 +	set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec);
   1.258 +}
   1.259 +
   1.260 +/*
   1.261 + * Generic udelay assumes that if preemption is allowed and the thread
   1.262 + * migrates to another CPU, that the ITC values are synchronized across
   1.263 + * all CPUs.
   1.264 + */
   1.265 +static void
   1.266 +ia64_itc_udelay (unsigned long usecs)
   1.267 +{
   1.268 +	unsigned long start = ia64_get_itc();
   1.269 +	unsigned long end = start + usecs*local_cpu_data->cyc_per_usec;
   1.270 +
   1.271 +	while (time_before(ia64_get_itc(), end))
   1.272 +		cpu_relax();
   1.273 +}
   1.274 +
   1.275 +void (*ia64_udelay)(unsigned long usecs) = &ia64_itc_udelay;
   1.276 +
   1.277 +void
   1.278 +udelay (unsigned long usecs)
   1.279 +{
   1.280 +	(*ia64_udelay)(usecs);
   1.281 +}
   1.282 +EXPORT_SYMBOL(udelay);
   1.283 +
   1.284 +static unsigned long long ia64_itc_printk_clock(void)
   1.285 +{
   1.286 +	if (ia64_get_kr(IA64_KR_PER_CPU_DATA))
   1.287 +		return sched_clock();
   1.288 +	return 0;
   1.289 +}
   1.290 +
   1.291 +static unsigned long long ia64_default_printk_clock(void)
   1.292 +{
   1.293 +	return (unsigned long long)(jiffies_64 - INITIAL_JIFFIES) *
   1.294 +		(1000000000/HZ);
   1.295 +}
   1.296 +
   1.297 +unsigned long long (*ia64_printk_clock)(void) = &ia64_default_printk_clock;
   1.298 +
   1.299 +unsigned long long printk_clock(void)
   1.300 +{
   1.301 +	return ia64_printk_clock();
   1.302 +}
   1.303 +
   1.304 +void __init
   1.305 +ia64_setup_printk_clock(void)
   1.306 +{
   1.307 +	if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT))
   1.308 +		ia64_printk_clock = ia64_itc_printk_clock;
   1.309 +}