time.c 11.8 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
/*
 * Copyright 2001 MontaVista Software Inc.
 * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
 * Copyright (c) 2003, 2004  Maciej W. Rozycki
 *
 * Common time service routines for MIPS machines. See
 * Documentation/mips/time.README.
 *
 * This program is free software; you can redistribute  it and/or modify it
 * under  the terms of  the GNU General  Public License as published by the
 * Free Software Foundation;  either version 2 of the  License, or (at your
 * option) any later version.
 */
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/param.h>
#include <linux/time.h>
#include <linux/timex.h>
#include <linux/smp.h>
#include <linux/kernel_stat.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/module.h>

#include <asm/bootinfo.h>
R
Ralf Baechle 已提交
28
#include <asm/cache.h>
L
Linus Torvalds 已提交
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
#include <asm/compiler.h>
#include <asm/cpu.h>
#include <asm/cpu-features.h>
#include <asm/div64.h>
#include <asm/sections.h>
#include <asm/time.h>

/*
 * The integer part of the number of usecs per jiffy is taken from tick,
 * but the fractional part is not recorded, so we calculate it using the
 * initial value of HZ.  This aids systems where tick isn't really an
 * integer (e.g. for HZ = 128).
 */
#define USECS_PER_JIFFY		TICK_SIZE
#define USECS_PER_JIFFY_FRAC	((unsigned long)(u32)((1000000ULL << 32) / HZ))

#define TICK_SIZE	(tick_nsec / 1000)

/*
 * forward reference
 */
DEFINE_SPINLOCK(rtc_lock);

/*
 * By default we provide the null RTC ops
 */
static unsigned long null_rtc_get_time(void)
{
	return mktime(2000, 1, 1, 0, 0, 0);
}

static int null_rtc_set_time(unsigned long sec)
{
	return 0;
}

65 66 67
unsigned long (*rtc_mips_get_time)(void) = null_rtc_get_time;
int (*rtc_mips_set_time)(unsigned long) = null_rtc_set_time;
int (*rtc_mips_set_mmss)(unsigned long);
L
Linus Torvalds 已提交
68 69 70


/* how many counter cycles in a jiffy */
R
Ralf Baechle 已提交
71
static unsigned long cycles_per_jiffy __read_mostly;
L
Linus Torvalds 已提交
72 73 74 75 76 77 78 79 80 81 82 83 84

/* expirelo is the count value for next CPU timer interrupt */
static unsigned int expirelo;


/*
 * Null timer ack for systems not needing one (e.g. i8254).
 */
static void null_timer_ack(void) { /* nothing */ }

/*
 * Null high precision timer functions for systems lacking one.
 */
85
static cycle_t null_hpt_read(void)
L
Linus Torvalds 已提交
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
{
	return 0;
}

/*
 * Timer ack for an R4k-compatible timer of a known frequency.
 */
static void c0_timer_ack(void)
{
	unsigned int count;

	/* Ack this timer interrupt and set the next one.  */
	expirelo += cycles_per_jiffy;
	write_c0_compare(expirelo);

	/* Check to see if we have missed any timer interrupts.  */
102
	while (((count = read_c0_count()) - expirelo) < 0x7fffffff) {
L
Linus Torvalds 已提交
103 104 105 106 107 108 109 110 111
		/* missed_timer_count++; */
		expirelo = count + cycles_per_jiffy;
		write_c0_compare(expirelo);
	}
}

/*
 * High precision timer functions for a R4k-compatible timer.
 */
112
static cycle_t c0_hpt_read(void)
L
Linus Torvalds 已提交
113 114 115 116 117
{
	return read_c0_count();
}

/* For use both as a high precision timer and an interrupt source.  */
118
static void __init c0_hpt_timer_init(void)
L
Linus Torvalds 已提交
119
{
120
	expirelo = read_c0_count() + cycles_per_jiffy;
L
Linus Torvalds 已提交
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
	write_c0_compare(expirelo);
}

int (*mips_timer_state)(void);
void (*mips_timer_ack)(void);

/* last time when xtime and rtc are sync'ed up */
static long last_rtc_update;

/*
 * local_timer_interrupt() does profiling and process accounting
 * on a per-CPU basis.
 *
 * In UP mode, it is invoked from the (global) timer_interrupt.
 *
 * In SMP mode, it might invoked by per-CPU timer interrupt, or
 * a broadcasted inter-processor interrupt which itself is triggered
 * by the global timer interrupt.
 */
140
void local_timer_interrupt(int irq, void *dev_id)
L
Linus Torvalds 已提交
141
{
142
	profile_tick(CPU_PROFILING);
143
	update_process_times(user_mode(get_irq_regs()));
L
Linus Torvalds 已提交
144 145 146 147 148 149
}

/*
 * High-level timer interrupt service routines.  This function
 * is set as irqaction->handler and is invoked through do_IRQ.
 */
150
irqreturn_t timer_interrupt(int irq, void *dev_id)
L
Linus Torvalds 已提交
151
{
152 153
	write_seqlock(&xtime_lock);

L
Linus Torvalds 已提交
154 155 156 157 158
	mips_timer_ack();

	/*
	 * call the generic timer interrupt handling
	 */
159
	do_timer(1);
L
Linus Torvalds 已提交
160 161 162

	/*
	 * If we have an externally synchronized Linux clock, then update
163
	 * CMOS clock accordingly every ~11 minutes. rtc_mips_set_time() has to be
L
Linus Torvalds 已提交
164 165
	 * called as close as possible to 500 ms before the new second starts.
	 */
J
john stultz 已提交
166
	if (ntp_synced() &&
L
Linus Torvalds 已提交
167 168 169
	    xtime.tv_sec > last_rtc_update + 660 &&
	    (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
	    (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
170
		if (rtc_mips_set_mmss(xtime.tv_sec) == 0) {
L
Linus Torvalds 已提交
171 172 173 174 175 176 177
			last_rtc_update = xtime.tv_sec;
		} else {
			/* do it again in 60 s */
			last_rtc_update = xtime.tv_sec - 600;
		}
	}

178 179
	write_sequnlock(&xtime_lock);

L
Linus Torvalds 已提交
180 181 182 183 184 185 186
	/*
	 * In UP mode, we call local_timer_interrupt() to do profiling
	 * and process accouting.
	 *
	 * In SMP mode, local_timer_interrupt() is invoked by appropriate
	 * low-level local timer interrupt handler.
	 */
187
	local_timer_interrupt(irq, dev_id);
L
Linus Torvalds 已提交
188 189 190 191

	return IRQ_HANDLED;
}

192
int null_perf_irq(void)
193 194 195 196
{
	return 0;
}

197
int (*perf_irq)(void) = null_perf_irq;
198 199 200 201

EXPORT_SYMBOL(null_perf_irq);
EXPORT_SYMBOL(perf_irq);

202 203 204 205 206
/*
 * Timer interrupt
 */
int cp0_compare_irq;

207 208 209
/*
 * Performance counter IRQ or -1 if shared with timer
 */
210 211
int cp0_perfcount_irq;
EXPORT_SYMBOL_GPL(cp0_perfcount_irq);
212 213 214 215 216 217 218 219 220

/*
 * Possibly handle a performance counter interrupt.
 * Return true if the timer interrupt should not be checked
 */
static inline int handle_perf_irq (int r2)
{
	/*
	 * The performance counter overflow interrupt may be shared with the
221
	 * timer interrupt (cp0_perfcount_irq < 0). If it is and a
222 223 224 225
	 * performance counter has overflowed (perf_irq() == IRQ_HANDLED)
	 * and we can't reliably determine if a counter interrupt has also
	 * happened (!r2) then don't check for a timer interrupt.
	 */
226
	return (cp0_perfcount_irq < 0) &&
227 228 229 230
		perf_irq() == IRQ_HANDLED &&
		!r2;
}

231
asmlinkage void ll_timer_interrupt(int irq)
L
Linus Torvalds 已提交
232
{
233 234
	int r2 = cpu_has_mips_r2;

L
Linus Torvalds 已提交
235 236 237
	irq_enter();
	kstat_this_cpu.irqs[irq]++;

238 239
	if (handle_perf_irq(r2))
		goto out;
240

241 242 243 244
	if (r2 && ((read_c0_cause() & (1 << 30)) == 0))
		goto out;

	timer_interrupt(irq, NULL);
L
Linus Torvalds 已提交
245

246
out:
L
Linus Torvalds 已提交
247 248 249
	irq_exit();
}

250
asmlinkage void ll_local_timer_interrupt(int irq)
L
Linus Torvalds 已提交
251 252 253 254 255 256
{
	irq_enter();
	if (smp_processor_id() != 0)
		kstat_this_cpu.irqs[irq]++;

	/* we keep interrupt disabled all the time */
257
	local_timer_interrupt(irq, NULL);
L
Linus Torvalds 已提交
258 259 260 261 262 263 264 265 266 267

	irq_exit();
}

/*
 * time_init() - it does the following things.
 *
 * 1) board_time_init() -
 * 	a) (optional) set up RTC routines,
 *      b) (optional) calibrate and set the mips_hpt_frequency
268 269
 *	    (only needed if you intended to use cpu counter as timer interrupt
 *	     source)
270
 * 2) setup xtime based on rtc_mips_get_time().
271 272
 * 3) calculate a couple of cached variables for later usage
 * 4) plat_timer_setup() -
L
Linus Torvalds 已提交
273 274 275 276 277 278 279 280 281 282 283
 *	a) (optional) over-write any choices made above by time_init().
 *	b) machine specific code should setup the timer irqaction.
 *	c) enable the timer interrupt
 */

void (*board_time_init)(void);

unsigned int mips_hpt_frequency;

static struct irqaction timer_irqaction = {
	.handler = timer_interrupt,
284
	.flags = IRQF_DISABLED | IRQF_PERCPU,
L
Linus Torvalds 已提交
285 286 287 288 289
	.name = "timer",
};

static unsigned int __init calibrate_hpt(void)
{
290
	cycle_t frequency, hpt_start, hpt_end, hpt_count, hz;
L
Linus Torvalds 已提交
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315

	const int loops = HZ / 10;
	int log_2_loops = 0;
	int i;

	/*
	 * We want to calibrate for 0.1s, but to avoid a 64-bit
	 * division we round the number of loops up to the nearest
	 * power of 2.
	 */
	while (loops > 1 << log_2_loops)
		log_2_loops++;
	i = 1 << log_2_loops;

	/*
	 * Wait for a rising edge of the timer interrupt.
	 */
	while (mips_timer_state());
	while (!mips_timer_state());

	/*
	 * Now see how many high precision timer ticks happen
	 * during the calculated number of periods between timer
	 * interrupts.
	 */
316
	hpt_start = clocksource_mips.read();
L
Linus Torvalds 已提交
317 318 319 320
	do {
		while (mips_timer_state());
		while (!mips_timer_state());
	} while (--i);
321
	hpt_end = clocksource_mips.read();
L
Linus Torvalds 已提交
322

323
	hpt_count = (hpt_end - hpt_start) & clocksource_mips.mask;
L
Linus Torvalds 已提交
324
	hz = HZ;
325
	frequency = hpt_count * hz;
L
Linus Torvalds 已提交
326 327 328 329

	return frequency >> log_2_loops;
}

330
struct clocksource clocksource_mips = {
331
	.name		= "MIPS",
332
	.mask		= CLOCKSOURCE_MASK(32),
333
	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
334 335 336 337 338 339 340
};

static void __init init_mips_clocksource(void)
{
	u64 temp;
	u32 shift;

341
	if (!mips_hpt_frequency || clocksource_mips.read == null_hpt_read)
342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
		return;

	/* Calclate a somewhat reasonable rating value */
	clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000;
	/* Find a shift value */
	for (shift = 32; shift > 0; shift--) {
		temp = (u64) NSEC_PER_SEC << shift;
		do_div(temp, mips_hpt_frequency);
		if ((temp >> 32) == 0)
			break;
	}
	clocksource_mips.shift = shift;
	clocksource_mips.mult = (u32)temp;

	clocksource_register(&clocksource_mips);
}

L
Linus Torvalds 已提交
359 360 361 362 363
void __init time_init(void)
{
	if (board_time_init)
		board_time_init();

364 365
	if (!rtc_mips_set_mmss)
		rtc_mips_set_mmss = rtc_mips_set_time;
L
Linus Torvalds 已提交
366

367
	xtime.tv_sec = rtc_mips_get_time();
L
Linus Torvalds 已提交
368 369 370 371 372 373
	xtime.tv_nsec = 0;

	set_normalized_timespec(&wall_to_monotonic,
	                        -xtime.tv_sec, -xtime.tv_nsec);

	/* Choose appropriate high precision timer routines.  */
374
	if (!cpu_has_counter && !clocksource_mips.read)
L
Linus Torvalds 已提交
375
		/* No high precision timer -- sorry.  */
376
		clocksource_mips.read = null_hpt_read;
377
	else if (!mips_hpt_frequency && !mips_timer_state) {
L
Linus Torvalds 已提交
378
		/* A high precision timer of unknown frequency.  */
379
		if (!clocksource_mips.read)
L
Linus Torvalds 已提交
380
			/* No external high precision timer -- use R4k.  */
381
			clocksource_mips.read = c0_hpt_read;
L
Linus Torvalds 已提交
382 383
	} else {
		/* We know counter frequency.  Or we can get it.  */
384
		if (!clocksource_mips.read) {
L
Linus Torvalds 已提交
385
			/* No external high precision timer -- use R4k.  */
386
			clocksource_mips.read = c0_hpt_read;
L
Linus Torvalds 已提交
387

388
			if (!mips_timer_state) {
L
Linus Torvalds 已提交
389 390
				/* No external timer interrupt -- use R4k.  */
				mips_timer_ack = c0_timer_ack;
391 392 393 394 395 396 397 398
				/* Calculate cache parameters.  */
				cycles_per_jiffy =
					(mips_hpt_frequency + HZ / 2) / HZ;
				/*
				 * This sets up the high precision
				 * timer for the first interrupt.
				 */
				c0_hpt_timer_init();
L
Linus Torvalds 已提交
399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424
			}
		}
		if (!mips_hpt_frequency)
			mips_hpt_frequency = calibrate_hpt();

		/* Report the high precision timer rate for a reference.  */
		printk("Using %u.%03u MHz high precision timer.\n",
		       ((mips_hpt_frequency + 500) / 1000) / 1000,
		       ((mips_hpt_frequency + 500) / 1000) % 1000);
	}

	if (!mips_timer_ack)
		/* No timer interrupt ack (e.g. i8254).  */
		mips_timer_ack = null_timer_ack;

	/*
	 * Call board specific timer interrupt setup.
	 *
	 * this pointer must be setup in machine setup routine.
	 *
	 * Even if a machine chooses to use a low-level timer interrupt,
	 * it still needs to setup the timer_irqaction.
	 * In that case, it might be better to set timer_irqaction.handler
	 * to be NULL function so that we are sure the high-level code
	 * is not invoked accidentally.
	 */
425
	plat_timer_setup(&timer_irqaction);
426 427

	init_mips_clocksource();
L
Linus Torvalds 已提交
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
}

#define FEBRUARY		2
#define STARTOFTIME		1970
#define SECDAY			86400L
#define SECYR			(SECDAY * 365)
#define leapyear(y)		((!((y) % 4) && ((y) % 100)) || !((y) % 400))
#define days_in_year(y)		(leapyear(y) ? 366 : 365)
#define days_in_month(m)	(month_days[(m) - 1])

static int month_days[12] = {
	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};

void to_tm(unsigned long tim, struct rtc_time *tm)
{
	long hms, day, gday;
	int i;

	gday = day = tim / SECDAY;
	hms = tim % SECDAY;

	/* Hours, minutes, seconds are easy */
	tm->tm_hour = hms / 3600;
	tm->tm_min = (hms % 3600) / 60;
	tm->tm_sec = (hms % 3600) % 60;

	/* Number of years in days */
	for (i = STARTOFTIME; day >= days_in_year(i); i++)
		day -= days_in_year(i);
	tm->tm_year = i;

	/* Number of months in days left */
	if (leapyear(tm->tm_year))
		days_in_month(FEBRUARY) = 29;
	for (i = 1; day >= days_in_month(i); i++)
		day -= days_in_month(i);
	days_in_month(FEBRUARY) = 28;
	tm->tm_mon = i - 1;		/* tm_mon starts from 0 to 11 */

	/* Days are what is left over (+1) from all that. */
	tm->tm_mday = day + 1;

	/*
	 * Determine the day of week
	 */
	tm->tm_wday = (gday + 4) % 7;	/* 1970/1/1 was Thursday */
}

EXPORT_SYMBOL(rtc_lock);
EXPORT_SYMBOL(to_tm);
479 480
EXPORT_SYMBOL(rtc_mips_set_time);
EXPORT_SYMBOL(rtc_mips_get_time);