time.c 6.3 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
{
123
	do_timer(1);
L
Linus Torvalds 已提交
124
#ifndef CONFIG_SMP
P
Paul Mundt 已提交
125
	update_process_times(user_mode(get_irq_regs()));
L
Linus Torvalds 已提交
126
#endif
P
Paul Mundt 已提交
127 128
	if (current->pid)
		profile_tick(CPU_PROFILING);
L
Linus Torvalds 已提交
129 130 131 132 133 134 135 136 137 138 139

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

	/*
	 * 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 已提交
140
	if (ntp_synced() &&
L
Linus Torvalds 已提交
141 142 143
	    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) {
144
		if (rtc_sh_set_time(xtime.tv_sec) == 0)
L
Linus Torvalds 已提交
145 146
			last_rtc_update = xtime.tv_sec;
		else
147 148
			/* do it again in 60s */
			last_rtc_update = xtime.tv_sec - 600;
L
Linus Torvalds 已提交
149 150
	}
}
151
#endif /* !CONFIG_GENERIC_CLOCKEVENTS */
L
Linus Torvalds 已提交
152

A
Andriy Skulysh 已提交
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
#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

176 177
static struct sysdev_class timer_sysclass = {
	set_kset_name("timer"),
A
Andriy Skulysh 已提交
178 179
	.suspend = timer_suspend,
	.resume	 = timer_resume,
L
Linus Torvalds 已提交
180 181
};

182
static int __init timer_init_sysfs(void)
P
Paul Mundt 已提交
183
{
184 185 186
	int ret = sysdev_class_register(&timer_sysclass);
	if (ret != 0)
		return ret;
P
Paul Mundt 已提交
187

188 189
	sys_timer->dev.cls = &timer_sysclass;
	return sysdev_register(&sys_timer->dev);
P
Paul Mundt 已提交
190
}
191
device_initcall(timer_init_sysfs);
P
Paul Mundt 已提交
192

193
void (*board_time_init)(void);
P
Paul Mundt 已提交
194 195

/*
196
 * Shamelessly based on the MIPS and Sparc64 work.
P
Paul Mundt 已提交
197
 */
198 199 200 201 202 203 204 205 206 207 208 209 210
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 已提交
211

212
static void __init init_sh_clocksource(void)
P
Paul Mundt 已提交
213
{
214 215
	if (!sh_hpt_frequency || clocksource_sh.read == null_hpt_read)
		return;
P
Paul Mundt 已提交
216

217 218
	clocksource_sh.mult = clocksource_hz2mult(sh_hpt_frequency,
						  clocksource_sh.shift);
P
Paul Mundt 已提交
219

220 221
	timer_ticks_per_nsec_quotient =
		clocksource_hz2mult(sh_hpt_frequency, NSEC_PER_CYC_SHIFT);
P
Paul Mundt 已提交
222

223
	clocksource_register(&clocksource_sh);
P
Paul Mundt 已提交
224 225
}

226 227
#ifdef CONFIG_GENERIC_TIME
unsigned long long sched_clock(void)
P
Paul Mundt 已提交
228
{
229 230
	unsigned long long ticks = clocksource_sh.read();
	return (ticks * timer_ticks_per_nsec_quotient) >> NSEC_PER_CYC_SHIFT;
P
Paul Mundt 已提交
231 232 233
}
#endif

L
Linus Torvalds 已提交
234 235 236 237 238
void __init time_init(void)
{
	if (board_time_init)
		board_time_init();

239
	clk_init();
L
Linus Torvalds 已提交
240

241 242 243
	rtc_sh_get_time(&xtime);
	set_normalized_timespec(&wall_to_monotonic,
				-xtime.tv_sec, -xtime.tv_nsec);
L
Linus Torvalds 已提交
244 245

	/*
246 247
	 * Find the timer to use as the system timer, it will be
	 * initialized for us.
L
Linus Torvalds 已提交
248
	 */
249 250
	sys_timer = get_sys_timer();
	printk(KERN_INFO "Using %s for system timer\n", sys_timer->name);
L
Linus Torvalds 已提交
251

252 253 254 255 256 257 258 259 260
	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 已提交
261

L
Linus Torvalds 已提交
262 263 264 265 266 267 268 269
#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
}