1 #include <linux/time_history.h>
2 #include <linux/time.h>
3 #include <linux/hrtimer.h>
4 #include <linux/alarmtimer.h>
5 #include <linux/sched.h>
6 #include <linux/proc_fs.h>
7 #include <linux/seq_file.h>
8 #include <linux/spinlock.h>
10 #ifdef CONFIG_SLP_KERNEL_ENG
11 #define TIME_LOG_MAX (1000)
12 #define ALARM_LOG_MAX (3000)
14 #define TIME_LOG_MAX (500)
15 #define ALARM_LOG_MAX (1500)
18 #define ALARM_ID_MAX (32)
19 #define OWNER_LEN (32)
21 #define for_each_alarm(_alarm_table, _alarm) \
22 for (_alarm = _alarm_table; \
23 (_alarm < _alarm_table + ALARM_ID_MAX) && (_alarm->alarmid); \
26 struct time_log_entry {
28 enum time_history_type history_type;
30 struct timespec realtime;
31 struct timespec monotonic;
32 #ifdef CONFIG_TIME_HISTORY_SAVE_BOOTTIME
33 struct timespec boottime;
35 struct timespec oldtime;
36 struct timespec newtime;
40 char comm[TASK_COMM_LEN + 1];
44 struct time_history_log_buf {
45 struct time_log_entry *buf;
56 char owner[OWNER_LEN + 1];
61 struct alarm_info alarm_table[ALARM_ID_MAX];
69 static struct time_log_entry time_log_buf[TIME_LOG_MAX];
70 static struct time_log_entry alarm_log_buf[ALARM_LOG_MAX];
72 static struct time_history_log_buf time_log = {
74 .buf_size = ARRAY_SIZE(time_log_buf),
77 static struct time_history_log_buf alarm_log = {
79 .buf_size = ARRAY_SIZE(alarm_log_buf),
82 static struct time_history th_ctxt = {
88 static bool is_realtime(struct timespec *time)
90 const struct timespec realtime = {
91 .tv_sec = 946684800, // 2000-01-01 00:00:00 //
95 * lhs == rhs: return 0
96 * lhs > rhs: return >0
98 return (timespec_compare(time, &realtime) >= 0);
101 static void set_alarm_owner(struct alarm_info *alarm_info, void *caller)
103 const char *remove_str[] = {
111 snprintf(alarm_info->owner, OWNER_LEN, "%pf", caller);
113 for (i = 0; i < ARRAY_SIZE(remove_str); i++) {
114 pos = strstr(alarm_info->owner, remove_str[i]);
115 if (pos && pos != alarm_info->owner)
120 static struct alarm_info *time_history_get_alarm_by_id(const void *alarmid)
122 struct alarm_info *alarm;
124 for_each_alarm(th_ctxt.alarm_table, alarm) {
125 if (alarmid == alarm->alarmid)
132 static int time_history_ringbuf_tail(struct time_history_log_buf *log_buf)
134 /* overwrite ring buf */
135 if (log_buf->cnt >= log_buf->buf_size)
138 if (log_buf->head >= log_buf->buf_size)
144 if (log_buf->tail >= log_buf->buf_size)
149 return log_buf->tail;
152 static time_t time_history_timezone_offset(void)
156 /* except first char '+' or '-' */
157 if (sscanf(&th_ctxt.timezone[1], "%d:%d", &tz_hour, &tz_min) < 0)
160 if (tz_hour == 0 && tz_min == 0)
163 if (th_ctxt.timezone[0] == '-') {
164 tz_hour = 0 - tz_hour;
168 return ((tz_hour * 3600) + (tz_min * 60));
171 static struct time_log_entry *time_history_init_log_entry(
172 struct time_history_log_buf *log_buf)
174 struct time_log_entry *entry;
177 tail = time_history_ringbuf_tail(log_buf);
178 entry = &log_buf->buf[tail];
180 memset(entry, 0, sizeof(struct time_log_entry));
182 entry->history_idx = th_ctxt.history_cnt;
183 ktime_get_ts(&entry->monotonic);
184 getnstimeofday(&entry->realtime);
185 #ifdef CONFIG_TIME_HISTORY_SAVE_BOOTTIME
186 get_monotonic_boottime(&entry->boottime);
188 entry->tz_offset = time_history_timezone_offset();
193 #ifdef CONFIG_TIME_HISTORY_LOG_FILTER
194 static const char *alarm_owner_filter[] = {
198 static int time_history_check_log_filter(const void *alarmid)
200 struct alarm_info *alarm_info;
203 alarm_info = time_history_get_alarm_by_id(alarmid);
207 for (i = 0; i < ARRAY_SIZE(alarm_owner_filter); i++) {
208 if (strcasecmp(alarm_owner_filter[i], alarm_info->owner) == 0)
213 #endif /* CONFIG_TIME_HISTORY_LOG_FILTER */
215 static int time_history_insert_alarm_log(enum time_history_type type,
216 const struct alarm *alarm, void *caller)
218 struct time_log_entry *entry;
221 #ifdef CONFIG_TIME_HISTORY_LOG_FILTER
222 if (time_history_check_log_filter(&alarm->node.node) != 0)
226 spin_lock_irqsave(&th_ctxt.lock, flags);
227 entry = time_history_init_log_entry(&alarm_log);
228 entry->history_type = type;
229 entry->newtime = ktime_to_timespec(alarm->node.expires);
230 entry->caller = caller;
231 entry->alarmid = (void*)&alarm->node.node;
232 entry->pid = current->pid;
233 memcpy(entry->comm, current->comm, TASK_COMM_LEN);
235 th_ctxt.history_cnt++;
236 spin_unlock_irqrestore(&th_ctxt.lock, flags);
241 static int time_history_insert_time_log(enum time_history_type type,
242 const struct timespec *oldtime, const struct timespec *newtime,
243 void *caller, int err)
245 struct time_log_entry *entry;
248 spin_lock_irqsave(&th_ctxt.lock, flags);
249 entry = time_history_init_log_entry(&time_log);
250 entry->history_type = type;
251 if (type == TIME_HISTORY_TYPE_TIME_SET)
252 entry->realtime = *oldtime;
253 entry->oldtime = *oldtime;
254 entry->newtime = *newtime;
255 entry->caller = caller;
256 entry->pid = current->pid;
258 memcpy(entry->comm, current->comm, TASK_COMM_LEN);
260 th_ctxt.history_cnt++;
261 spin_unlock_irqrestore(&th_ctxt.lock, flags);
266 static int time_history_insert_timezone_log(char *old_tz, char *new_tz)
268 struct time_log_entry *entry;
271 spin_lock_irqsave(&th_ctxt.lock, flags);
272 entry = time_history_init_log_entry(&time_log);
273 entry->history_type = TIME_HISTORY_TYPE_TIMEZONE_SET;
274 snprintf(entry->comm, sizeof(entry->comm) - 1, "%s > %s", old_tz, new_tz);
276 th_ctxt.history_cnt++;
277 spin_unlock_irqrestore(&th_ctxt.lock, flags);
282 static int time_history_insert_setting_log(enum time_history_type type,
285 struct time_log_entry *entry;
288 spin_lock_irqsave(&th_ctxt.lock, flags);
289 entry = time_history_init_log_entry(&time_log);
290 entry->history_type = type;
291 entry->oldtime.tv_sec = old;
292 entry->newtime.tv_sec = new;
294 th_ctxt.history_cnt++;
295 spin_unlock_irqrestore(&th_ctxt.lock, flags);
300 void __time_history_alarm_init(const struct alarm *alarm, void *caller)
302 struct alarm_info *alarm_info;
304 if (th_ctxt.alarmid_cnt >= ALARM_ID_MAX) {
305 pr_err("%s: no space in alarm id table\n", __func__);
309 alarm_info = &th_ctxt.alarm_table[th_ctxt.alarmid_cnt++];
311 alarm_info->alarmid = (void*)(&alarm->node.node);
312 alarm_info->caller = caller;
313 alarm_info->handler = alarm->function;
314 set_alarm_owner(alarm_info, caller);
319 void __time_history_alarm_start(const struct alarm *alarm, void *caller)
321 time_history_insert_alarm_log( TIME_HISTORY_TYPE_ALARM_START, alarm, caller);
324 void __time_history_alarm_restart(const struct alarm *alarm, void *caller)
326 time_history_insert_alarm_log(TIME_HISTORY_TYPE_ALARM_RESTART, alarm, caller);
329 void __time_history_alarm_expired(const struct alarm *alarm, ktime_t now)
331 time_history_insert_alarm_log(TIME_HISTORY_TYPE_ALARM_EXPIRED,
332 alarm, __builtin_return_address(0));
335 void __time_history_alarm_del(const struct alarm *alarm, void *caller)
337 if (time_history_get_alarm_by_id(&alarm->node.node) == NULL)
340 time_history_insert_alarm_log(TIME_HISTORY_TYPE_ALARM_DEL, alarm, caller);
343 void __time_history_time_set(const struct timespec *oldtime,
344 const struct timespec *newtime, void *caller)
346 time_history_insert_time_log(TIME_HISTORY_TYPE_TIME_SET,
347 oldtime, newtime, caller, 0);
350 void __time_history_rtc_time_set(const struct timespec *newtime,
351 void *caller, int err)
353 time_history_insert_time_log(TIME_HISTORY_TYPE_RTC_TIME_SET,
354 newtime, newtime, caller, err);
357 void __time_history_rtc_alarm_init(const struct rtc_timer *timer,
360 struct alarm_info *alarm_info;
362 if (th_ctxt.alarmid_cnt >= ALARM_ID_MAX) {
363 pr_err("%s: no space in alarm id table\n", __func__);
367 alarm_info = &th_ctxt.alarm_table[th_ctxt.alarmid_cnt++];
369 alarm_info->alarmid = (void*)(&timer->node.node);
370 alarm_info->caller = caller;
371 alarm_info->handler = timer->task.func;
372 set_alarm_owner(alarm_info, caller);
377 void __time_history_rtc_alarm_set(struct rtc_device *rtc,
378 const struct rtc_wkalrm *wkalrm, void *caller, int err)
380 struct timerqueue_node *tq_node;
381 struct alarm_info *alarm;
382 struct time_log_entry *entry;
385 tq_node = timerqueue_getnext(&rtc->timerqueue);
387 pr_err("%s: timerqueue is empty\n", __func__);
391 alarm = time_history_get_alarm_by_id(&tq_node->node);
393 pr_err("%s: can't find alarm\n", __func__);
397 #ifdef CONFIG_TIME_HISTORY_LOG_FILTER
398 if (time_history_check_log_filter(&tq_node->node) != 0)
402 spin_lock_irqsave(&th_ctxt.lock, flags);
403 entry = time_history_init_log_entry(&alarm_log);
404 entry->history_type = TIME_HISTORY_TYPE_RTC_ALARM_SET;
405 entry->newtime = ktime_to_timespec(tq_node->expires);
406 entry->caller = caller;
407 entry->alarmid = (void*)&tq_node->node;
408 entry->pid = current->pid;
410 memcpy(entry->comm, current->comm, TASK_COMM_LEN);
412 th_ctxt.history_cnt++;
413 spin_unlock_irqrestore(&th_ctxt.lock, flags);
418 static const char *history_type_name[] = {
419 [TIME_HISTORY_TYPE_TIME_SET] = "time_set",
420 [TIME_HISTORY_TYPE_RTC_TIME_SET] = "rtc_time_set",
421 [TIME_HISTORY_TYPE_HOST_TIME_SET] = "host_time",
422 [TIME_HISTORY_TYPE_NETWORK_TIME_SET] = "network_time",
423 [TIME_HISTORY_TYPE_TIMEZONE_SET] = "timezone_set",
424 [TIME_HISTORY_TYPE_NITZ_UPDATE_SET] = "nitz_update",
425 [TIME_HISTORY_TYPE_ALARM_START] = "alarm_start",
426 [TIME_HISTORY_TYPE_ALARM_RESTART] = "alarm_restart",
427 [TIME_HISTORY_TYPE_ALARM_EXPIRED] = "alarm_expired",
428 [TIME_HISTORY_TYPE_ALARM_DEL] = "alarm_delete",
429 [TIME_HISTORY_TYPE_RTC_ALARM_SET] = "rtc_alarm_set",
432 struct time_history_iter {
433 struct time_history_log_buf *curr_log;
435 struct time_history_log_buf *comp_log;
439 static char owner_filter[32] = "-";
441 static inline void seq_print_difftime(struct seq_file *seq,
442 struct timespec old, struct timespec new)
444 struct timespec diff = timespec_sub(new, old);
446 if (diff.tv_sec < 0 && diff.tv_nsec > 0) {
447 /* It's normalized time, convert to human readable time format */
448 diff.tv_nsec = -(diff.tv_nsec - NSEC_PER_SEC);
452 seq_printf(seq, " (%s%ld.%03ld)", (diff.tv_sec >= 0)? "+" : "",
453 diff.tv_sec, diff.tv_nsec/NSEC_PER_MSEC);
457 static inline void seq_print_realtime(struct seq_file *seq, struct timespec *ts,
462 time_to_tm(ts->tv_sec + tz_offset, 0, &tm);
464 seq_printf(seq, "%4ld-%02d-%02d %02d:%02d:%02d",
465 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
466 tm.tm_hour, tm.tm_min, tm.tm_sec);
469 static void time_history_show_header(struct seq_file *seq)
472 struct rtc_device *rtc_dev;
473 char *tz, *tz_id, *nitz;
474 time_t tz_offset = time_history_timezone_offset();
476 tz = th_ctxt.timezone;
477 tz_id = th_ctxt.timezone_id;
479 switch (th_ctxt.nitz_update) {
491 seq_puts(seq, "\n********** time_history v0.2 **********\n\n");
492 seq_puts(seq, "system time : ");
493 seq_print_realtime(seq, &ts, tz_offset);
494 seq_printf(seq, " (%ld.%03ld)\n", ts.tv_sec, ts.tv_nsec/NSEC_PER_MSEC);
495 rtc_dev = rtc_class_open("rtc0");
499 rtc_read_time(rtc_dev, &tm);
500 rtc_tm_to_time(&tm, &time);
501 seq_printf(seq, "rtc time : %d-%02d-%02d %02d:%02d:%02d (%ld)\n",
502 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
503 tm.tm_hour, tm.tm_min, tm.tm_sec, time);
504 rtc_class_close(rtc_dev);
506 seq_printf(seq, "timezone : %s (%s)\n", tz_id, tz);
507 seq_printf(seq, "nitz update : %s\n", nitz);
509 seq_printf(seq, "total alarmtimer : %4d/%-d\n",
510 th_ctxt.alarmid_cnt, ARRAY_SIZE(th_ctxt.alarm_table));
511 seq_printf(seq, "total time set : %4lld/%-d\n",
512 time_log.cnt, time_log.buf_size);
513 seq_printf(seq, "total alarm log : %4lld/%-d\n\n",
514 alarm_log.cnt, alarm_log.buf_size);
516 #ifdef CONFIG_TIME_HISTORY_DEBUG
518 struct alarm_info *alarm;
519 seq_printf(seq, "log_entry sz: %d\n\n", sizeof(struct time_log_entry));
520 for_each_alarm(th_ctxt.alarm_table, alarm) {
521 seq_printf(seq, "id : %p\n", alarm->alarmid);
522 seq_printf(seq, "owner : %s\n", alarm->owner);
523 seq_printf(seq, "handler : %pf\n", alarm->handler);
524 seq_printf(seq, "caller : %pf\n\n", alarm->caller);
528 seq_puts(seq, " real_time tz [ kernel_time ");
529 #ifdef CONFIG_TIME_HISTORY_SAVE_BOOTTIME
530 seq_puts(seq, " / boot_time");
532 seq_puts(seq, "] idx type worker "
533 "function time epoch"
537 static inline void seq_print_timestamp(struct seq_file *seq,
538 struct time_log_entry *entry)
540 char tz[8] = "+00:00";
542 if (entry->tz_offset) {
545 tz_offset = (entry->tz_offset < 0)? -(entry->tz_offset) : entry->tz_offset;
546 tz_hour = tz_offset/3600;
547 tz_min = (tz_offset%3600)/60;
548 snprintf(tz, sizeof(tz) - 1, "%c%02d:%02d",
549 (entry->tz_offset < 0)? '-' : '+', tz_hour, tz_min);
552 seq_print_realtime(seq, &entry->realtime, entry->tz_offset);
553 seq_printf(seq, " %s [%6lu.%06lu", tz,
554 entry->monotonic.tv_sec, entry->monotonic.tv_nsec/NSEC_PER_USEC);
555 #ifdef CONFIG_TIME_HISTORY_SAVE_BOOTTIME
556 seq_printf(seq, " / %5lu.%03lu",
557 entry->boottime.tv_sec, entry->boottime.tv_nsec/NSEC_PER_MSEC);
562 static int time_history_show(struct seq_file *seq, void *v)
564 struct time_history_iter *iter = seq->private;
565 struct time_log_entry *entry;
566 struct alarm_info *alarm = NULL;
573 entry = &iter->curr_log->buf[iter->curr_idx];
575 switch (entry->history_type) {
576 case TIME_HISTORY_TYPE_TIME_SET ... TIME_HISTORY_TYPE_NETWORK_TIME_SET:
579 case TIME_HISTORY_TYPE_ALARM_START ... TIME_HISTORY_TYPE_ALARM_DEL:
580 case TIME_HISTORY_TYPE_RTC_ALARM_SET:
581 log_type = ALARM_LOG;
583 case TIME_HISTORY_TYPE_TIMEZONE_SET:
584 case TIME_HISTORY_TYPE_NITZ_UPDATE_SET:
591 if (log_type == ALARM_LOG) {
592 alarm = time_history_get_alarm_by_id(entry->alarmid);
594 if ((owner_filter[0] != '-' && alarm
595 && strcasecmp(alarm->owner, owner_filter) != 0))
599 seq_print_timestamp(seq, entry);
600 seq_printf(seq, "%4lld %-13s ", entry->history_idx,
601 history_type_name[entry->history_type]);
603 if ((entry->history_type == TIME_HISTORY_TYPE_ALARM_EXPIRED ||
604 entry->history_type == TIME_HISTORY_TYPE_RTC_ALARM_SET) && alarm) {
605 seq_printf(seq, "%-16s ", alarm->owner);
606 } else if (entry->history_type == TIME_HISTORY_TYPE_NITZ_UPDATE_SET) {
607 if (entry->oldtime.tv_sec == -1)
608 seq_printf(seq, "init: %ld", entry->newtime.tv_sec);
610 seq_printf(seq, "%ld > %ld", entry->oldtime.tv_sec, entry->newtime.tv_sec);
612 seq_printf(seq, "%-16s ", entry->comm);
615 if (log_type == ETC_LOG) {
620 if (entry->history_type == TIME_HISTORY_TYPE_ALARM_EXPIRED && alarm)
621 seq_printf(seq, "%-22pf ", alarm->handler);
622 else if (entry->caller)
623 seq_printf(seq, "%-22pf ", entry->caller);
625 seq_printf(seq, "%24s", "");
627 if (log_type == TIME_LOG || is_realtime(&entry->newtime)) {
628 seq_print_realtime(seq, &entry->newtime, entry->tz_offset);
629 seq_printf(seq, " %10ld ", entry->newtime.tv_sec);
631 seq_printf(seq, "%15lu.%03lu",
632 entry->newtime.tv_sec, entry->newtime.tv_nsec/NSEC_PER_MSEC);
635 if (log_type == TIME_LOG)
636 seq_print_difftime(seq, entry->realtime, entry->newtime);
639 seq_printf(seq, " -> err: %d", entry->err);
645 static struct time_history_iter *swap_log(struct time_history_iter *iter)
647 struct time_history_log_buf *temp_log = iter->curr_log;
648 int temp_idx = iter->curr_idx;
653 /* Keep current log buf */
655 return (iter->curr_log)? iter : NULL;
657 iter->curr_log = iter->comp_log;
658 iter->comp_log = temp_log;
660 iter->curr_idx = iter->comp_idx;
661 iter->comp_idx = temp_idx;
666 static void *move_iter(struct time_history_iter *iter)
671 if (iter->curr_idx == iter->curr_log->tail) {
672 iter->curr_log = NULL;
673 return swap_log(iter);
674 } else if (iter->curr_idx + 1 >= iter->curr_log->buf_size) {
680 if (iter->comp_log && (iter->curr_log->buf[iter->curr_idx].history_idx
681 > iter->comp_log->buf[iter->comp_idx].history_idx)) {
682 return swap_log(iter);
688 static void *time_history_start(struct seq_file *seq, loff_t *pos)
690 struct time_history_iter *iter = seq->private;
692 if (*pos >= th_ctxt.history_cnt)
696 return move_iter(iter);
698 time_history_show_header(seq);
700 if (time_log.buf[time_log.head].history_idx
701 < alarm_log.buf[alarm_log.head].history_idx) {
702 iter->curr_log = &time_log;
703 iter->curr_idx = time_log.head;
704 iter->comp_log = &alarm_log;
705 iter->comp_idx = alarm_log.head;
707 iter->curr_log = &alarm_log;
708 iter->curr_idx = alarm_log.head;
709 iter->comp_log = &time_log;
710 iter->comp_idx = time_log.head;
716 static void *time_history_next(struct seq_file *seq, void *v, loff_t *pos)
718 struct time_history_iter *iter = seq->private;
722 if (*pos >= th_ctxt.history_cnt)
725 return move_iter(iter);
728 static void time_history_stop(struct seq_file *seq, void *v)
732 static const struct seq_operations time_history_seq_ops = {
733 .start = time_history_start,
734 .show = time_history_show,
735 .next = time_history_next,
736 .stop = time_history_stop,
739 static int time_history_open(struct inode *inode, struct file *file)
741 return seq_open_private(file, &time_history_seq_ops,
742 sizeof(struct time_history_iter));
745 /* return true if valid timezone format */
746 static int time_history_valid_tz_format(char *timezone)
751 if (unlikely(!timezone))
754 len = strlen(timezone);
755 if (len < 5 || len > 6)
758 if (timezone[0] != '+' && timezone[0] != '-')
761 if (sscanf(&timezone[1], "%d:%d", &tz_hour, &tz_min) < 0)
767 if (tz_min != 0 && tz_min != 30 && tz_min != 45)
773 static ssize_t time_history_write(struct file *file,
774 const char __user *buf, size_t count, loff_t *pos)
776 char option[32] = {0};
779 if (sscanf(buf, "%s %s", option, val) < 0)
782 if (strcasecmp(option, "timezone") == 0) {
783 if (!time_history_valid_tz_format(val)) {
784 pr_err("%s: Invalid timezone format: %s\n", __func__, val);
787 time_history_insert_timezone_log(th_ctxt.timezone, val);
788 memset(th_ctxt.timezone, 0, sizeof(th_ctxt.timezone));
789 snprintf(th_ctxt.timezone, sizeof(th_ctxt.timezone) - 1, "%s", val);
790 } else if (strcasecmp(option, "timezone_id") == 0) {
791 memset(th_ctxt.timezone_id, 0, sizeof(th_ctxt.timezone_id));
792 snprintf(th_ctxt.timezone_id, sizeof(th_ctxt.timezone_id) - 1, "%s", val);
793 } else if (strcasecmp(option, "host") == 0) {
794 struct timespec newtime = {0, 0};
795 sscanf(val, "%ld", &newtime.tv_sec);
796 time_history_insert_time_log(TIME_HISTORY_TYPE_HOST_TIME_SET,
797 &newtime, &newtime, NULL, 0);
798 } else if (strcasecmp(option, "nitz") == 0) {
799 struct timespec newtime = {0, 0};
800 sscanf(val, "%ld", &newtime.tv_sec);
801 time_history_insert_time_log(TIME_HISTORY_TYPE_NETWORK_TIME_SET,
802 &newtime, &newtime, NULL, 0);
803 } else if (strcasecmp(option, "nitz_update") == 0) {
804 int nitz_update = -1;
805 sscanf(val, "%d", &nitz_update);
806 time_history_insert_setting_log(TIME_HISTORY_TYPE_NITZ_UPDATE_SET,
807 th_ctxt.nitz_update, nitz_update);
808 th_ctxt.nitz_update = nitz_update;
809 } else if (strcasecmp(option, "filter") == 0) {
811 memset(owner_filter, 0, sizeof(owner_filter));
812 snprintf(owner_filter, sizeof(owner_filter), "%s", val);
813 memset(th_ctxt.timezone, 0, sizeof(th_ctxt.timezone));
814 cur = strchr(owner_filter, '\n');
818 pr_info("%s: Failed to parse option\n", __func__);
825 static const struct file_operations time_history_fops = {
826 .open = time_history_open,
828 .write = time_history_write,
830 .release = seq_release_private,
833 static int __init time_history_init(void)
835 struct proc_dir_entry *pe;
837 pe = proc_create("time_history", 0444, NULL, &time_history_fops);
842 spin_lock_init(&th_ctxt.lock);
844 time_log.buf[0].history_idx = ULLONG_MAX;
845 alarm_log.buf[0].history_idx = ULLONG_MAX;
849 arch_initcall(time_history_init);