#include <asm/local.h>
 
+/*
+ * The "absolute" timestamp in the buffer is only 59 bits.
+ * If a clock has the 5 MSBs set, it needs to be saved and
+ * reinserted.
+ */
+#define TS_MSB         (0xf8ULL << 56)
+#define ABS_TS_MASK    (~TS_MSB)
+
 static void update_pages_handler(struct work_struct *work);
 
 /*
 }
 #endif
 
+/*
+ * The absolute time stamp drops the 5 MSBs and some clocks may
+ * require them. The rb_fix_abs_ts() will take a previous full
+ * time stamp, and add the 5 MSB of that time stamp on to the
+ * saved absolute time stamp. Then they are compared in case of
+ * the unlikely event that the latest time stamp incremented
+ * the 5 MSB.
+ */
+static inline u64 rb_fix_abs_ts(u64 abs, u64 save_ts)
+{
+       if (save_ts & TS_MSB) {
+               abs |= save_ts & TS_MSB;
+               /* Check for overflow */
+               if (unlikely(abs < save_ts))
+                       abs += 1ULL << 59;
+       }
+       return abs;
+}
 
 static inline u64 rb_time_stamp(struct trace_buffer *buffer);
 
        u64 ts;
 
        /* If the event includes an absolute time, then just use that */
-       if (event->type_len == RINGBUF_TYPE_TIME_STAMP)
-               return rb_event_time_stamp(event);
+       if (event->type_len == RINGBUF_TYPE_TIME_STAMP) {
+               ts = rb_event_time_stamp(event);
+               return rb_fix_abs_ts(ts, cpu_buffer->tail_page->page->time_stamp);
+       }
 
        nest = local_read(&cpu_buffer->committing);
        verify_event(cpu_buffer, event);
                (RB_ADD_STAMP_FORCE | RB_ADD_STAMP_ABSOLUTE);
 
        if (unlikely(info->delta > (1ULL << 59))) {
+               /*
+                * Some timers can use more than 59 bits, and when a timestamp
+                * is added to the buffer, it will lose those bits.
+                */
+               if (abs && (info->ts & TS_MSB)) {
+                       info->delta &= ABS_TS_MASK;
+
                /* did the clock go backwards */
-               if (info->before == info->after && info->before > info->ts) {
+               } else if (info->before == info->after && info->before > info->ts) {
                        /* not interrupted */
                        static int once;
 
 
                case RINGBUF_TYPE_TIME_STAMP:
                        delta = rb_event_time_stamp(event);
-                       ts = delta;
+                       ts = rb_fix_abs_ts(delta, ts);
                        pr_warn("  [%lld] absolute:%lld TIME STAMP\n", ts, delta);
                        break;
 
 
                case RINGBUF_TYPE_TIME_STAMP:
                        delta = rb_event_time_stamp(event);
-                       ts = delta;
+                       ts = rb_fix_abs_ts(delta, ts);
                        break;
 
                case RINGBUF_TYPE_PADDING:
 
        case RINGBUF_TYPE_TIME_STAMP:
                delta = rb_event_time_stamp(event);
+               delta = rb_fix_abs_ts(delta, cpu_buffer->read_stamp);
                cpu_buffer->read_stamp = delta;
                return;
 
 
        case RINGBUF_TYPE_TIME_STAMP:
                delta = rb_event_time_stamp(event);
+               delta = rb_fix_abs_ts(delta, iter->read_stamp);
                iter->read_stamp = delta;
                return;
 
        case RINGBUF_TYPE_TIME_STAMP:
                if (ts) {
                        *ts = rb_event_time_stamp(event);
+                       *ts = rb_fix_abs_ts(*ts, reader->page->time_stamp);
                        ring_buffer_normalize_time_stamp(cpu_buffer->buffer,
                                                         cpu_buffer->cpu, ts);
                }
        case RINGBUF_TYPE_TIME_STAMP:
                if (ts) {
                        *ts = rb_event_time_stamp(event);
+                       *ts = rb_fix_abs_ts(*ts, iter->head_page->page->time_stamp);
                        ring_buffer_normalize_time_stamp(cpu_buffer->buffer,
                                                         cpu_buffer->cpu, ts);
                }