aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/time
diff options
context:
space:
mode:
authorChristopher Kenna <cjk@cs.unc.edu>2012-09-28 13:46:28 -0400
committerChristopher Kenna <cjk@cs.unc.edu>2012-09-28 14:50:15 -0400
commitdaa22703f14c007e93b464c45fa60019a36f546d (patch)
treea1a130b6e128dc9d57c35c026977e1b4953105e1 /kernel/time
parent5aa287dcf1b5879aa0150b0511833c52885f5b4c (diff)
Apply k4412 kernel from HardKernel for ODROID-X.
Diffstat (limited to 'kernel/time')
-rw-r--r--kernel/time/Kconfig4
-rw-r--r--kernel/time/Makefile2
-rw-r--r--kernel/time/timekeeping.c131
3 files changed, 136 insertions, 1 deletions
diff --git a/kernel/time/Kconfig b/kernel/time/Kconfig
index f06a8a36564..689fe69629e 100644
--- a/kernel/time/Kconfig
+++ b/kernel/time/Kconfig
@@ -27,3 +27,7 @@ config GENERIC_CLOCKEVENTS_BUILD
27 default y 27 default y
28 depends on GENERIC_CLOCKEVENTS || GENERIC_CLOCKEVENTS_MIGR 28 depends on GENERIC_CLOCKEVENTS || GENERIC_CLOCKEVENTS_MIGR
29 29
30# Selectable by architectures which want to reuse the clocksource as
31# sched_clock
32config HAVE_CLKSRC_SCHED_CLOCK
33 bool
diff --git a/kernel/time/Makefile b/kernel/time/Makefile
index e2fd74b8e8c..cae2ad7491b 100644
--- a/kernel/time/Makefile
+++ b/kernel/time/Makefile
@@ -1,5 +1,5 @@
1obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o timecompare.o 1obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o timecompare.o
2obj-y += timeconv.o posix-clock.o alarmtimer.o 2obj-y += timeconv.o posix-clock.o #alarmtimer.o
3 3
4obj-$(CONFIG_GENERIC_CLOCKEVENTS_BUILD) += clockevents.o 4obj-$(CONFIG_GENERIC_CLOCKEVENTS_BUILD) += clockevents.o
5obj-$(CONFIG_GENERIC_CLOCKEVENTS) += tick-common.o 5obj-$(CONFIG_GENERIC_CLOCKEVENTS) += tick-common.o
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 678ae3184ef..796efe08e45 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -21,6 +21,9 @@
21#include <linux/tick.h> 21#include <linux/tick.h>
22#include <linux/stop_machine.h> 22#include <linux/stop_machine.h>
23 23
24static void notrace sched_clock_clksrc_install(struct clocksource *clock);
25static void notrace sched_clock_clksrc_update(void);
26
24/* Structure holding internal timekeeping values. */ 27/* Structure holding internal timekeeping values. */
25struct timekeeper { 28struct timekeeper {
26 /* Current clocksource used for timekeeping. */ 29 /* Current clocksource used for timekeeping. */
@@ -66,6 +69,9 @@ static void timekeeper_setup_internals(struct clocksource *clock)
66 cycle_t interval; 69 cycle_t interval;
67 u64 tmp, ntpinterval; 70 u64 tmp, ntpinterval;
68 71
72 if (clock->flags & CLOCK_SOURCE_SCHED_CLOCK)
73 sched_clock_clksrc_install(clock);
74
69 timekeeper.clock = clock; 75 timekeeper.clock = clock;
70 clock->cycle_last = clock->read(clock); 76 clock->cycle_last = clock->read(clock);
71 77
@@ -627,6 +633,12 @@ static void update_sleep_time(struct timespec t)
627 */ 633 */
628static void __timekeeping_inject_sleeptime(struct timespec *delta) 634static void __timekeeping_inject_sleeptime(struct timespec *delta)
629{ 635{
636 if (!timespec_valid(delta)) {
637 printk(KERN_WARNING "__timekeeping_inject_sleeptime: Invalid "
638 "sleep delta value!\n");
639 return;
640 }
641
630 xtime = timespec_add(xtime, *delta); 642 xtime = timespec_add(xtime, *delta);
631 wall_to_monotonic = timespec_sub(wall_to_monotonic, *delta); 643 wall_to_monotonic = timespec_sub(wall_to_monotonic, *delta);
632 update_sleep_time(timespec_add(total_sleep_time, *delta)); 644 update_sleep_time(timespec_add(total_sleep_time, *delta));
@@ -1104,6 +1116,7 @@ void do_timer(unsigned long ticks)
1104{ 1116{
1105 jiffies_64 += ticks; 1117 jiffies_64 += ticks;
1106 update_wall_time(); 1118 update_wall_time();
1119 sched_clock_clksrc_update();
1107 calc_global_load(ticks); 1120 calc_global_load(ticks);
1108} 1121}
1109 1122
@@ -1188,3 +1201,121 @@ void xtime_update(unsigned long ticks)
1188 do_timer(ticks); 1201 do_timer(ticks);
1189 write_sequnlock(&xtime_lock); 1202 write_sequnlock(&xtime_lock);
1190} 1203}
1204
1205/**
1206 * struct sched_clksrc - clocksource based sched_clock
1207 * @clock: Pointer to the clocksource
1208 * @nsecs: Nanoseconds base value
1209 * @seqcnt: Sequence counter for sched_clock
1210 * @last_update: Counter value at last update
1211 * @mult: Multiplier for nsec conversion
1212 * @shift: Shift value (divisor) for nsec conversion
1213 * @mask: Mask for the delta
1214 * @update_cycles: Cycles after which we update nsecs and last_update
1215 * @update_nsesc: Nanoseconds value corresponding to @update_cycles
1216 */
1217struct sched_clksrc {
1218 struct clocksource *clock;
1219 u64 nsecs;
1220 struct seqcount seqcnt;
1221 u64 last_update;
1222 u32 mult;
1223 u32 shift;
1224 u64 mask;
1225 u64 update_cycles;
1226 u64 update_nsecs;
1227};
1228
1229static struct sched_clksrc sched_clksrc;
1230
1231/*
1232 * Called from clocksource code when a clocksource usable for
1233 * sched_clock is installed.
1234 */
1235static void notrace sched_clock_clksrc_install(struct clocksource *clock)
1236{
1237 u64 nsecs, cyc = clock->mask & CLOCKSOURCE_MASK(32);
1238
1239 if (sched_clksrc.clock)
1240 return;
1241
1242 /* Make sure we get the wraparounds */
1243 cyc >>= 2;
1244
1245 /* Use the raw mult/shift values */
1246 sched_clksrc.mult = clock->mult;
1247 sched_clksrc.shift = clock->shift;
1248 sched_clksrc.mask = clock->mask;
1249 sched_clksrc.update_cycles = cyc;
1250 nsecs = clocksource_cyc2ns(cyc, sched_clksrc.mult, sched_clksrc.shift);
1251 sched_clksrc.update_nsecs = nsecs;
1252 /* Establish the base line */
1253 sched_clksrc.nsecs = (u64)(jiffies - INITIAL_JIFFIES) *
1254 (NSEC_PER_SEC / HZ);
1255 sched_clksrc.last_update = clock->read(clock) & sched_clksrc.mask;
1256 sched_clksrc.clock = clock;
1257}
1258
1259/*
1260 * Called from timekeeping code with xtime lock held and interrupts
1261 * disabled, so we have only one updater at a time. Note that readers
1262 * of sched_clock are _NOT_ affected by xtime_lock. We have our own
1263 * sequence counter for sched_clksrc.
1264 */
1265static void notrace sched_clock_clksrc_update(void)
1266{
1267 struct clocksource *clock = sched_clksrc.clock;
1268 u64 delta;
1269
1270 if (!clock)
1271 return;
1272
1273 delta = clock->read(clock) - sched_clksrc.last_update;
1274 delta &= sched_clksrc.mask;
1275 while (delta >= sched_clksrc.update_cycles) {
1276 delta -= sched_clksrc.update_cycles;
1277 write_seqcount_begin(&sched_clksrc.seqcnt);
1278 sched_clksrc.last_update += sched_clksrc.update_cycles;
1279 sched_clksrc.nsecs += sched_clksrc.update_nsecs;
1280 write_seqcount_end(&sched_clksrc.seqcnt);
1281 }
1282}
1283
1284/*
1285 * Scheduler clock clocksource based - returns current time in nanosec units.
1286 *
1287 * Can be called from the default implementation below or from
1288 * architecture code if it overrides the default implementation.
1289 */
1290unsigned long long notrace sched_clock_clksrc(void)
1291{
1292 struct clocksource *clock = sched_clksrc.clock;
1293 unsigned int seq;
1294 u64 nsecs, last, delta;
1295
1296 if (!sched_clksrc.clock)
1297 return (unsigned long long)(jiffies - INITIAL_JIFFIES) *
1298 (NSEC_PER_SEC / HZ);
1299
1300 do {
1301 seq = read_seqcount_begin(&sched_clksrc.seqcnt);
1302 last = sched_clksrc.last_update;
1303 nsecs = sched_clksrc.nsecs;
1304 } while (read_seqcount_retry(&sched_clksrc.seqcnt, seq));
1305
1306 delta = (clock->read(clock) - last) & sched_clksrc.mask;
1307
1308 return nsecs + clocksource_cyc2ns(delta, sched_clksrc.mult,
1309 sched_clksrc.shift);
1310}
1311
1312/*
1313 * Scheduler clock - returns current time in nanosec units.
1314 * This is default implementation.
1315 * Architectures and sub-architectures can override this.
1316 */
1317unsigned long long __attribute__((weak)) sched_clock(void)
1318{
1319 return sched_clock_clksrc();
1320}
1321EXPORT_SYMBOL_GPL(sched_clock);