diff options
author | Christopher Kenna <cjk@cs.unc.edu> | 2012-09-28 13:46:28 -0400 |
---|---|---|
committer | Christopher Kenna <cjk@cs.unc.edu> | 2012-09-28 14:50:15 -0400 |
commit | daa22703f14c007e93b464c45fa60019a36f546d (patch) | |
tree | a1a130b6e128dc9d57c35c026977e1b4953105e1 /kernel/time | |
parent | 5aa287dcf1b5879aa0150b0511833c52885f5b4c (diff) |
Apply k4412 kernel from HardKernel for ODROID-X.
Diffstat (limited to 'kernel/time')
-rw-r--r-- | kernel/time/Kconfig | 4 | ||||
-rw-r--r-- | kernel/time/Makefile | 2 | ||||
-rw-r--r-- | kernel/time/timekeeping.c | 131 |
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 | ||
32 | config 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 @@ | |||
1 | obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o timecompare.o | 1 | obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o timecompare.o |
2 | obj-y += timeconv.o posix-clock.o alarmtimer.o | 2 | obj-y += timeconv.o posix-clock.o #alarmtimer.o |
3 | 3 | ||
4 | obj-$(CONFIG_GENERIC_CLOCKEVENTS_BUILD) += clockevents.o | 4 | obj-$(CONFIG_GENERIC_CLOCKEVENTS_BUILD) += clockevents.o |
5 | obj-$(CONFIG_GENERIC_CLOCKEVENTS) += tick-common.o | 5 | obj-$(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 | ||
24 | static void notrace sched_clock_clksrc_install(struct clocksource *clock); | ||
25 | static void notrace sched_clock_clksrc_update(void); | ||
26 | |||
24 | /* Structure holding internal timekeeping values. */ | 27 | /* Structure holding internal timekeeping values. */ |
25 | struct timekeeper { | 28 | struct 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 | */ |
628 | static void __timekeeping_inject_sleeptime(struct timespec *delta) | 634 | static 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 | */ | ||
1217 | struct 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 | |||
1229 | static struct sched_clksrc sched_clksrc; | ||
1230 | |||
1231 | /* | ||
1232 | * Called from clocksource code when a clocksource usable for | ||
1233 | * sched_clock is installed. | ||
1234 | */ | ||
1235 | static 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 | */ | ||
1265 | static 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 | */ | ||
1290 | unsigned 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 | */ | ||
1317 | unsigned long long __attribute__((weak)) sched_clock(void) | ||
1318 | { | ||
1319 | return sched_clock_clksrc(); | ||
1320 | } | ||
1321 | EXPORT_SYMBOL_GPL(sched_clock); | ||