time_32.c 6.6 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5
/*
 *  arch/sh/kernel/time.c
 *
 *  Copyright (C) 1999  Tetsuya Okada & Niibe Yutaka
 *  Copyright (C) 2000  Philipp Rumpf <prumpf@tux.org>
6
 *  Copyright (C) 2002 - 2007  Paul Mundt
L
Linus Torvalds 已提交
7 8 9 10 11 12
 *  Copyright (C) 2002  M. R. Brown  <mrbrown@linux-sh.org>
 *
 *  Some code taken from i386 version.
 *    Copyright (C) 1991, 1992, 1995  Linus Torvalds
 */
#include <linux/kernel.h>
13
#include <linux/module.h>
L
Linus Torvalds 已提交
14 15
#include <linux/init.h>
#include <linux/profile.h>
P
Paul Mundt 已提交
16 17
#include <linux/timex.h>
#include <linux/sched.h>
18
#include <linux/clockchips.h>
19
#include <asm/clock.h>
L
Linus Torvalds 已提交
20
#include <asm/rtc.h>
21
#include <asm/timer.h>
L
Linus Torvalds 已提交
22 23
#include <asm/kgdb.h>

24 25 26 27 28
struct sys_timer *sys_timer;

/* Move this somewhere more sensible.. */
DEFINE_SPINLOCK(rtc_lock);
EXPORT_SYMBOL(rtc_lock);
L
Linus Torvalds 已提交
29

30 31 32 33 34 35 36 37 38 39 40 41
/* Dummy RTC ops */
static void null_rtc_get_time(struct timespec *tv)
{
	tv->tv_sec = mktime(2000, 1, 1, 0, 0, 0);
	tv->tv_nsec = 0;
}

static int null_rtc_set_time(const time_t secs)
{
	return 0;
}

42 43 44 45 46 47 48 49
/*
 * Null high precision timer functions for systems lacking one.
 */
static cycle_t null_hpt_read(void)
{
	return 0;
}

50 51
void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time;
int (*rtc_sh_set_time)(const time_t) = null_rtc_set_time;
L
Linus Torvalds 已提交
52

53
#ifndef CONFIG_GENERIC_TIME
L
Linus Torvalds 已提交
54 55
void do_gettimeofday(struct timeval *tv)
{
56
	unsigned long flags;
L
Linus Torvalds 已提交
57 58 59 60
	unsigned long seq;
	unsigned long usec, sec;

	do {
61 62 63 64 65
		/*
		 * Turn off IRQs when grabbing xtime_lock, so that
		 * the sys_timer get_offset code doesn't have to handle it.
		 */
		seq = read_seqbegin_irqsave(&xtime_lock, flags);
66
		usec = get_timer_offset();
L
Linus Torvalds 已提交
67
		sec = xtime.tv_sec;
68 69
		usec += xtime.tv_nsec / NSEC_PER_USEC;
	} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
L
Linus Torvalds 已提交
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95

	while (usec >= 1000000) {
		usec -= 1000000;
		sec++;
	}

	tv->tv_sec = sec;
	tv->tv_usec = usec;
}
EXPORT_SYMBOL(do_gettimeofday);

int do_settimeofday(struct timespec *tv)
{
	time_t wtm_sec, sec = tv->tv_sec;
	long wtm_nsec, nsec = tv->tv_nsec;

	if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
		return -EINVAL;

	write_seqlock_irq(&xtime_lock);
	/*
	 * This is revolting. We need to set "xtime" correctly. However, the
	 * value in this location is the value at the most recent update of
	 * wall time.  Discover what correction gettimeofday() would have
	 * made, and then undo it!
	 */
96
	nsec -= get_timer_offset() * NSEC_PER_USEC;
L
Linus Torvalds 已提交
97 98 99 100 101 102 103

	wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
	wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);

	set_normalized_timespec(&xtime, sec, nsec);
	set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);

J
john stultz 已提交
104
	ntp_clear();
L
Linus Torvalds 已提交
105 106 107 108 109 110
	write_sequnlock_irq(&xtime_lock);
	clock_was_set();

	return 0;
}
EXPORT_SYMBOL(do_settimeofday);
111
#endif /* !CONFIG_GENERIC_TIME */
L
Linus Torvalds 已提交
112

113
#ifndef CONFIG_GENERIC_CLOCKEVENTS
L
Linus Torvalds 已提交
114 115 116 117
/* last time the RTC clock got updated */
static long last_rtc_update;

/*
118
 * handle_timer_tick() needs to keep up the real-time clock,
L
Linus Torvalds 已提交
119 120
 * as well as call the "do_timer()" routine every clocktick
 */
P
Paul Mundt 已提交
121
void handle_timer_tick(void)
L
Linus Torvalds 已提交
122
{
P
Paul Mundt 已提交
123 124
	if (current->pid)
		profile_tick(CPU_PROFILING);
L
Linus Torvalds 已提交
125 126 127 128 129 130

#ifdef CONFIG_HEARTBEAT
	if (sh_mv.mv_heartbeat != NULL)
		sh_mv.mv_heartbeat();
#endif

P
Peter Zijlstra 已提交
131 132 133 134 135 136 137 138 139 140
	/*
	 * Here we are in the timer irq handler. We just have irqs locally
	 * disabled but we don't know if the timer_bh is running on the other
	 * CPU. We need to avoid to SMP race with it. NOTE: we don' t need
	 * the irq version of write_lock because as just said we have irq
	 * locally disabled. -arca
	 */
	write_seqlock(&xtime_lock);
	do_timer(1);

L
Linus Torvalds 已提交
141 142 143 144 145
	/*
	 * If we have an externally synchronized Linux clock, then update
	 * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
	 * called as close as possible to 500 ms before the new second starts.
	 */
J
john stultz 已提交
146
	if (ntp_synced() &&
L
Linus Torvalds 已提交
147 148 149
	    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) {
150
		if (rtc_sh_set_time(xtime.tv_sec) == 0)
L
Linus Torvalds 已提交
151 152
			last_rtc_update = xtime.tv_sec;
		else
153 154
			/* do it again in 60s */
			last_rtc_update = xtime.tv_sec - 600;
L
Linus Torvalds 已提交
155
	}
P
Peter Zijlstra 已提交
156 157 158 159 160
	write_sequnlock(&xtime_lock);

#ifndef CONFIG_SMP
	update_process_times(user_mode(get_irq_regs()));
#endif
L
Linus Torvalds 已提交
161
}
162
#endif /* !CONFIG_GENERIC_CLOCKEVENTS */
L
Linus Torvalds 已提交
163

A
Andriy Skulysh 已提交
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
#ifdef CONFIG_PM
int timer_suspend(struct sys_device *dev, pm_message_t state)
{
	struct sys_timer *sys_timer = container_of(dev, struct sys_timer, dev);

	sys_timer->ops->stop();

	return 0;
}

int timer_resume(struct sys_device *dev)
{
	struct sys_timer *sys_timer = container_of(dev, struct sys_timer, dev);

	sys_timer->ops->start();

	return 0;
}
#else
#define timer_suspend NULL
#define timer_resume NULL
#endif

187
static struct sysdev_class timer_sysclass = {
188
	.name	 = "timer",
A
Andriy Skulysh 已提交
189 190
	.suspend = timer_suspend,
	.resume	 = timer_resume,
L
Linus Torvalds 已提交
191 192
};

193
static int __init timer_init_sysfs(void)
P
Paul Mundt 已提交
194
{
195 196 197
	int ret = sysdev_class_register(&timer_sysclass);
	if (ret != 0)
		return ret;
P
Paul Mundt 已提交
198

199 200
	sys_timer->dev.cls = &timer_sysclass;
	return sysdev_register(&sys_timer->dev);
P
Paul Mundt 已提交
201
}
202
device_initcall(timer_init_sysfs);
P
Paul Mundt 已提交
203

204
void (*board_time_init)(void);
P
Paul Mundt 已提交
205 206

/*
207
 * Shamelessly based on the MIPS and Sparc64 work.
P
Paul Mundt 已提交
208
 */
209 210 211 212 213 214 215 216 217 218 219 220 221
static unsigned long timer_ticks_per_nsec_quotient __read_mostly;
unsigned long sh_hpt_frequency = 0;

#define NSEC_PER_CYC_SHIFT	10

struct clocksource clocksource_sh = {
	.name		= "SuperH",
	.rating		= 200,
	.mask		= CLOCKSOURCE_MASK(32),
	.read		= null_hpt_read,
	.shift		= 16,
	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
};
P
Paul Mundt 已提交
222

223
static void __init init_sh_clocksource(void)
P
Paul Mundt 已提交
224
{
225 226
	if (!sh_hpt_frequency || clocksource_sh.read == null_hpt_read)
		return;
P
Paul Mundt 已提交
227

228 229
	clocksource_sh.mult = clocksource_hz2mult(sh_hpt_frequency,
						  clocksource_sh.shift);
P
Paul Mundt 已提交
230

231 232
	timer_ticks_per_nsec_quotient =
		clocksource_hz2mult(sh_hpt_frequency, NSEC_PER_CYC_SHIFT);
P
Paul Mundt 已提交
233

234
	clocksource_register(&clocksource_sh);
P
Paul Mundt 已提交
235 236
}

237 238
#ifdef CONFIG_GENERIC_TIME
unsigned long long sched_clock(void)
P
Paul Mundt 已提交
239
{
240 241
	unsigned long long ticks = clocksource_sh.read();
	return (ticks * timer_ticks_per_nsec_quotient) >> NSEC_PER_CYC_SHIFT;
P
Paul Mundt 已提交
242 243 244
}
#endif

L
Linus Torvalds 已提交
245 246 247 248 249
void __init time_init(void)
{
	if (board_time_init)
		board_time_init();

250
	clk_init();
L
Linus Torvalds 已提交
251

252 253 254
	rtc_sh_get_time(&xtime);
	set_normalized_timespec(&wall_to_monotonic,
				-xtime.tv_sec, -xtime.tv_nsec);
L
Linus Torvalds 已提交
255 256

	/*
257 258
	 * Find the timer to use as the system timer, it will be
	 * initialized for us.
L
Linus Torvalds 已提交
259
	 */
260 261
	sys_timer = get_sys_timer();
	printk(KERN_INFO "Using %s for system timer\n", sys_timer->name);
L
Linus Torvalds 已提交
262

263 264 265 266 267 268 269 270 271
	if (sys_timer->ops->read)
		clocksource_sh.read = sys_timer->ops->read;

	init_sh_clocksource();

	if (sh_hpt_frequency)
		printk("Using %lu.%03lu MHz high precision timer.\n",
		       ((sh_hpt_frequency + 500) / 1000) / 1000,
		       ((sh_hpt_frequency + 500) / 1000) % 1000);
P
Paul Mundt 已提交
272

L
Linus Torvalds 已提交
273 274 275 276 277 278 279 280
#if defined(CONFIG_SH_KGDB)
	/*
	 * Set up kgdb as requested. We do it here because the serial
	 * init uses the timer vars we just set up for figuring baud.
	 */
	kgdb_init();
#endif
}