aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2008-09-24 12:48:31 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-09-24 19:38:17 -0400
commit08ec3c2d45bac41c782acb4e3331ac5881b2c68a (patch)
treeed05cb5eed4f2a7abd689b005449d8f3f4556372
parentb4f151ff899362fec952c45d166252c9912c041f (diff)
MN10300: Make sched_clock() report time since boot
Make sched_clock() report time since boot rather than time since last timer interrupt. Make sched_clock() expand and scale the 32-bit TSC value running at IOCLK speed (~33MHz) to a 64-bit nanosecond counter, using cnt32_to_63() acquired from the ARM arch and without using slow DIVU instructions every call. Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--arch/mn10300/kernel/time.c52
1 files changed, 41 insertions, 11 deletions
diff --git a/arch/mn10300/kernel/time.c b/arch/mn10300/kernel/time.c
index babb7c2ac377..e4606586f94c 100644
--- a/arch/mn10300/kernel/time.c
+++ b/arch/mn10300/kernel/time.c
@@ -1,6 +1,6 @@
1/* MN10300 Low level time management 1/* MN10300 Low level time management
2 * 2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. 3 * Copyright (C) 2007-2008 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com) 4 * Written by David Howells (dhowells@redhat.com)
5 * - Derived from arch/i386/kernel/time.c 5 * - Derived from arch/i386/kernel/time.c
6 * 6 *
@@ -16,6 +16,7 @@
16#include <linux/init.h> 16#include <linux/init.h>
17#include <linux/smp.h> 17#include <linux/smp.h>
18#include <linux/profile.h> 18#include <linux/profile.h>
19#include <linux/cnt32_to_63.h>
19#include <asm/irq.h> 20#include <asm/irq.h>
20#include <asm/div64.h> 21#include <asm/div64.h>
21#include <asm/processor.h> 22#include <asm/processor.h>
@@ -40,27 +41,54 @@ static struct irqaction timer_irq = {
40 .name = "timer", 41 .name = "timer",
41}; 42};
42 43
44static unsigned long sched_clock_multiplier;
45
43/* 46/*
44 * scheduler clock - returns current time in nanosec units. 47 * scheduler clock - returns current time in nanosec units.
45 */ 48 */
46unsigned long long sched_clock(void) 49unsigned long long sched_clock(void)
47{ 50{
48 union { 51 union {
49 unsigned long long l; 52 unsigned long long ll;
50 u32 w[2]; 53 unsigned l[2];
51 } quot; 54 } tsc64, result;
55 unsigned long tsc, tmp;
56 unsigned product[3]; /* 96-bit intermediate value */
57
58 /* read the TSC value
59 */
60 tsc = 0 - get_cycles(); /* get_cycles() counts down */
52 61
53 quot.w[0] = mn10300_last_tsc - get_cycles(); 62 /* expand to 64-bits.
54 quot.w[1] = 1000000000; 63 * - sched_clock() must be called once a minute or better or the
64 * following will go horribly wrong - see cnt32_to_63()
65 */
66 tsc64.ll = cnt32_to_63(tsc) & 0x7fffffffffffffffULL;
55 67
56 asm("mulu %2,%3,%0,%1" 68 /* scale the 64-bit TSC value to a nanosecond value via a 96-bit
57 : "=r"(quot.w[1]), "=r"(quot.w[0]) 69 * intermediate
58 : "0"(quot.w[1]), "1"(quot.w[0]) 70 */
71 asm("mulu %2,%0,%3,%0 \n" /* LSW * mult -> 0:%3:%0 */
72 "mulu %2,%1,%2,%1 \n" /* MSW * mult -> %2:%1:0 */
73 "add %3,%1 \n"
74 "addc 0,%2 \n" /* result in %2:%1:%0 */
75 : "=r"(product[0]), "=r"(product[1]), "=r"(product[2]), "=r"(tmp)
76 : "0"(tsc64.l[0]), "1"(tsc64.l[1]), "2"(sched_clock_multiplier)
59 : "cc"); 77 : "cc");
60 78
61 do_div(quot.l, MN10300_TSCCLK); 79 result.l[0] = product[1] << 16 | product[0] >> 16;
80 result.l[1] = product[2] << 16 | product[1] >> 16;
62 81
63 return quot.l; 82 return result.ll;
83}
84
85/*
86 * initialise the scheduler clock
87 */
88static void __init mn10300_sched_clock_init(void)
89{
90 sched_clock_multiplier =
91 __muldiv64u(NSEC_PER_SEC, 1 << 16, MN10300_TSCCLK);
64} 92}
65 93
66/* 94/*
@@ -128,4 +156,6 @@ void __init time_init(void)
128 /* start the watchdog timer */ 156 /* start the watchdog timer */
129 watchdog_go(); 157 watchdog_go();
130#endif 158#endif
159
160 mn10300_sched_clock_init();
131} 161}