Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

David Howells and committed by
Linus Torvalds
08ec3c2d b4f151ff

+41 -11
+41 -11
arch/mn10300/kernel/time.c
··· 1 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 4 * Written by David Howells (dhowells@redhat.com) 5 5 * - Derived from arch/i386/kernel/time.c 6 6 * ··· 16 16 #include <linux/init.h> 17 17 #include <linux/smp.h> 18 18 #include <linux/profile.h> 19 + #include <linux/cnt32_to_63.h> 19 20 #include <asm/irq.h> 20 21 #include <asm/div64.h> 21 22 #include <asm/processor.h> ··· 41 40 .name = "timer", 42 41 }; 43 42 43 + static unsigned long sched_clock_multiplier; 44 + 44 45 /* 45 46 * scheduler clock - returns current time in nanosec units. 46 47 */ 47 48 unsigned long long sched_clock(void) 48 49 { 49 50 union { 50 - unsigned long long l; 51 - u32 w[2]; 52 - } quot; 51 + unsigned long long ll; 52 + unsigned l[2]; 53 + } tsc64, result; 54 + unsigned long tsc, tmp; 55 + unsigned product[3]; /* 96-bit intermediate value */ 53 56 54 - quot.w[0] = mn10300_last_tsc - get_cycles(); 55 - quot.w[1] = 1000000000; 57 + /* read the TSC value 58 + */ 59 + tsc = 0 - get_cycles(); /* get_cycles() counts down */ 56 60 57 - asm("mulu %2,%3,%0,%1" 58 - : "=r"(quot.w[1]), "=r"(quot.w[0]) 59 - : "0"(quot.w[1]), "1"(quot.w[0]) 61 + /* expand to 64-bits. 62 + * - sched_clock() must be called once a minute or better or the 63 + * following will go horribly wrong - see cnt32_to_63() 64 + */ 65 + tsc64.ll = cnt32_to_63(tsc) & 0x7fffffffffffffffULL; 66 + 67 + /* scale the 64-bit TSC value to a nanosecond value via a 96-bit 68 + * intermediate 69 + */ 70 + asm("mulu %2,%0,%3,%0 \n" /* LSW * mult -> 0:%3:%0 */ 71 + "mulu %2,%1,%2,%1 \n" /* MSW * mult -> %2:%1:0 */ 72 + "add %3,%1 \n" 73 + "addc 0,%2 \n" /* result in %2:%1:%0 */ 74 + : "=r"(product[0]), "=r"(product[1]), "=r"(product[2]), "=r"(tmp) 75 + : "0"(tsc64.l[0]), "1"(tsc64.l[1]), "2"(sched_clock_multiplier) 60 76 : "cc"); 61 77 62 - do_div(quot.l, MN10300_TSCCLK); 78 + result.l[0] = product[1] << 16 | product[0] >> 16; 79 + result.l[1] = product[2] << 16 | product[1] >> 16; 63 80 64 - return quot.l; 81 + return result.ll; 82 + } 83 + 84 + /* 85 + * initialise the scheduler clock 86 + */ 87 + static void __init mn10300_sched_clock_init(void) 88 + { 89 + sched_clock_multiplier = 90 + __muldiv64u(NSEC_PER_SEC, 1 << 16, MN10300_TSCCLK); 65 91 } 66 92 67 93 /* ··· 156 128 /* start the watchdog timer */ 157 129 watchdog_go(); 158 130 #endif 131 + 132 + mn10300_sched_clock_init(); 159 133 }