const unsigned char *buf;
        size_t len;
        bool return_compression;
+       bool mtc_insn;
        bool pge;
+       bool have_tma;
        uint64_t pos;
        uint64_t last_ip;
        uint64_t ip;
        uint64_t tsc_timestamp;
        uint64_t ref_timestamp;
        uint64_t ret_addr;
+       uint64_t ctc_timestamp;
+       uint64_t ctc_delta;
+       uint32_t last_mtc;
+       uint32_t tsc_ctc_ratio_n;
+       uint32_t tsc_ctc_ratio_d;
+       uint32_t tsc_ctc_mult;
+       uint32_t tsc_slip;
+       uint32_t ctc_rem_mask;
+       int mtc_shift;
        struct intel_pt_stack stack;
        enum intel_pt_pkt_state pkt_state;
        struct intel_pt_pkt packet;
        }
 }
 
+static uint64_t multdiv(uint64_t t, uint32_t n, uint32_t d)
+{
+       if (!d)
+               return 0;
+       return (t / d) * n + ((t % d) * n) / d;
+}
+
 struct intel_pt_decoder *intel_pt_decoder_new(struct intel_pt_params *params)
 {
        struct intel_pt_decoder *decoder;
 
        intel_pt_setup_period(decoder);
 
+       decoder->mtc_shift = params->mtc_period;
+       decoder->ctc_rem_mask = (1 << decoder->mtc_shift) - 1;
+
+       decoder->tsc_ctc_ratio_n = params->tsc_ctc_ratio_n;
+       decoder->tsc_ctc_ratio_d = params->tsc_ctc_ratio_d;
+
+       if (!decoder->tsc_ctc_ratio_n)
+               decoder->tsc_ctc_ratio_d = 0;
+
+       if (decoder->tsc_ctc_ratio_d) {
+               if (!(decoder->tsc_ctc_ratio_n % decoder->tsc_ctc_ratio_d))
+                       decoder->tsc_ctc_mult = decoder->tsc_ctc_ratio_n /
+                                               decoder->tsc_ctc_ratio_d;
+
+               /*
+                * Allow for timestamps appearing to backwards because a TSC
+                * packet has slipped past a MTC packet, so allow 2 MTC ticks
+                * or ...
+                */
+               decoder->tsc_slip = multdiv(2 << decoder->mtc_shift,
+                                       decoder->tsc_ctc_ratio_n,
+                                       decoder->tsc_ctc_ratio_d);
+       }
+       /* ... or 0x100 paranoia */
+       if (decoder->tsc_slip < 0x100)
+               decoder->tsc_slip = 0x100;
+
+       intel_pt_log("timestamp: mtc_shift %u\n", decoder->mtc_shift);
+       intel_pt_log("timestamp: tsc_ctc_ratio_n %u\n", decoder->tsc_ctc_ratio_n);
+       intel_pt_log("timestamp: tsc_ctc_ratio_d %u\n", decoder->tsc_ctc_ratio_d);
+       intel_pt_log("timestamp: tsc_ctc_mult %u\n", decoder->tsc_ctc_mult);
+       intel_pt_log("timestamp: tsc_slip %#x\n", decoder->tsc_slip);
+
        return decoder;
 }
 
 static int intel_pt_bad_packet(struct intel_pt_decoder *decoder)
 {
        intel_pt_clear_tx_flags(decoder);
+       decoder->have_tma = false;
        decoder->pkt_len = 1;
        decoder->pkt_step = 1;
        intel_pt_decoder_log_packet(decoder);
                decoder->pkt_state = INTEL_PT_STATE_NO_PSB;
                decoder->ref_timestamp = buffer.ref_timestamp;
                decoder->timestamp = 0;
+               decoder->have_tma = false;
                decoder->state.trace_nr = buffer.trace_nr;
                intel_pt_log("Reference timestamp 0x%" PRIx64 "\n",
                             decoder->ref_timestamp);
        case INTEL_PT_PERIOD_TICKS:
                return intel_pt_next_period(decoder);
        case INTEL_PT_PERIOD_NONE:
+       case INTEL_PT_PERIOD_MTC:
        default:
                return 0;
        }
                decoder->last_masked_timestamp = masked_timestamp;
                break;
        case INTEL_PT_PERIOD_NONE:
+       case INTEL_PT_PERIOD_MTC:
        default:
                break;
        }
        uint64_t max_insn_cnt, insn_cnt = 0;
        int err;
 
+       if (!decoder->mtc_insn)
+               decoder->mtc_insn = true;
+
        max_insn_cnt = intel_pt_next_sample(decoder);
 
        err = decoder->walk_insn(intel_pt_insn, &insn_cnt, &decoder->ip, ip,
 {
        uint64_t timestamp;
 
+       decoder->have_tma = false;
+
        if (decoder->ref_timestamp) {
                timestamp = decoder->packet.payload |
                            (decoder->ref_timestamp & (0xffULL << 56));
        } else if (decoder->timestamp) {
                timestamp = decoder->packet.payload |
                            (decoder->timestamp & (0xffULL << 56));
+               decoder->tsc_timestamp = timestamp;
                if (timestamp < decoder->timestamp &&
-                   decoder->timestamp - timestamp < 0x100) {
-                       intel_pt_log_to("ERROR: Suppressing backwards timestamp",
+                   decoder->timestamp - timestamp < decoder->tsc_slip) {
+                       intel_pt_log_to("Suppressing backwards timestamp",
                                        timestamp);
                        timestamp = decoder->timestamp;
                }
                while (timestamp < decoder->timestamp) {
                        intel_pt_log_to("Wraparound timestamp", timestamp);
                        timestamp += (1ULL << 56);
+                       decoder->tsc_timestamp = timestamp;
                }
-               decoder->tsc_timestamp = timestamp;
                decoder->timestamp = timestamp;
                decoder->timestamp_insn_cnt = 0;
        }
 {
        intel_pt_log("ERROR: Buffer overflow\n");
        intel_pt_clear_tx_flags(decoder);
+       decoder->have_tma = false;
        decoder->pkt_state = INTEL_PT_STATE_ERR_RESYNC;
        decoder->overflow = true;
        return -EOVERFLOW;
 }
 
+static void intel_pt_calc_tma(struct intel_pt_decoder *decoder)
+{
+       uint32_t ctc = decoder->packet.payload;
+       uint32_t fc = decoder->packet.count;
+       uint32_t ctc_rem = ctc & decoder->ctc_rem_mask;
+
+       if (!decoder->tsc_ctc_ratio_d)
+               return;
+
+       decoder->last_mtc = (ctc >> decoder->mtc_shift) & 0xff;
+       decoder->ctc_timestamp = decoder->tsc_timestamp - fc;
+       if (decoder->tsc_ctc_mult) {
+               decoder->ctc_timestamp -= ctc_rem * decoder->tsc_ctc_mult;
+       } else {
+               decoder->ctc_timestamp -= multdiv(ctc_rem,
+                                                 decoder->tsc_ctc_ratio_n,
+                                                 decoder->tsc_ctc_ratio_d);
+       }
+       decoder->ctc_delta = 0;
+       decoder->have_tma = true;
+       intel_pt_log("CTC timestamp " x64_fmt " last MTC %#x  CTC rem %#x\n",
+                    decoder->ctc_timestamp, decoder->last_mtc, ctc_rem);
+}
+
+static void intel_pt_calc_mtc_timestamp(struct intel_pt_decoder *decoder)
+{
+       uint64_t timestamp;
+       uint32_t mtc, mtc_delta;
+
+       if (!decoder->have_tma)
+               return;
+
+       mtc = decoder->packet.payload;
+
+       if (mtc > decoder->last_mtc)
+               mtc_delta = mtc - decoder->last_mtc;
+       else
+               mtc_delta = mtc + 256 - decoder->last_mtc;
+
+       decoder->ctc_delta += mtc_delta << decoder->mtc_shift;
+
+       if (decoder->tsc_ctc_mult) {
+               timestamp = decoder->ctc_timestamp +
+                           decoder->ctc_delta * decoder->tsc_ctc_mult;
+       } else {
+               timestamp = decoder->ctc_timestamp +
+                           multdiv(decoder->ctc_delta,
+                                   decoder->tsc_ctc_ratio_n,
+                                   decoder->tsc_ctc_ratio_d);
+       }
+
+       if (timestamp < decoder->timestamp)
+               intel_pt_log("Suppressing MTC timestamp " x64_fmt " less than current timestamp " x64_fmt "\n",
+                            timestamp, decoder->timestamp);
+       else
+               decoder->timestamp = timestamp;
+
+       decoder->timestamp_insn_cnt = 0;
+       decoder->last_mtc = mtc;
+}
+
 /* Walk PSB+ packets when already in sync. */
 static int intel_pt_walk_psbend(struct intel_pt_decoder *decoder)
 {
                case INTEL_PT_TRACESTOP:
                case INTEL_PT_BAD:
                case INTEL_PT_PSB:
+                       decoder->have_tma = false;
                        intel_pt_log("ERROR: Unexpected packet\n");
                        return -EAGAIN;
 
                        break;
 
                case INTEL_PT_TMA:
+                       intel_pt_calc_tma(decoder);
                        break;
 
                case INTEL_PT_CBR:
                        break;
 
                case INTEL_PT_MTC:
+                       intel_pt_calc_mtc_timestamp(decoder);
+                       if (decoder->period_type == INTEL_PT_PERIOD_MTC)
+                               decoder->state.type |= INTEL_PT_INSTRUCTION;
                        break;
 
                case INTEL_PT_CYC:
                        break;
 
                case INTEL_PT_MTC:
+                       intel_pt_calc_mtc_timestamp(decoder);
+                       if (decoder->period_type == INTEL_PT_PERIOD_MTC)
+                               decoder->state.type |= INTEL_PT_INSTRUCTION;
                        break;
 
                case INTEL_PT_CYC:
                        break;
 
                case INTEL_PT_MTC:
-                       break;
+                       intel_pt_calc_mtc_timestamp(decoder);
+                       if (decoder->period_type != INTEL_PT_PERIOD_MTC)
+                               break;
+                       /*
+                        * Ensure that there has been an instruction since the
+                        * last MTC.
+                        */
+                       if (!decoder->mtc_insn)
+                               break;
+                       decoder->mtc_insn = false;
+                       /* Ensure that there is a timestamp */
+                       if (!decoder->timestamp)
+                               break;
+                       decoder->state.type = INTEL_PT_INSTRUCTION;
+                       decoder->state.from_ip = decoder->ip;
+                       decoder->state.to_ip = 0;
+                       decoder->mtc_insn = false;
+                       return 0;
 
                case INTEL_PT_TSC:
                        intel_pt_calc_tsc_timestamp(decoder);
                        break;
 
                case INTEL_PT_TMA:
+                       intel_pt_calc_tma(decoder);
                        break;
 
                case INTEL_PT_CYC:
                        break;
 
                case INTEL_PT_MTC:
+                       intel_pt_calc_mtc_timestamp(decoder);
                        break;
 
                case INTEL_PT_TSC:
                        break;
 
                case INTEL_PT_TMA:
+                       intel_pt_calc_tma(decoder);
                        break;
 
                case INTEL_PT_CYC:
 
                case INTEL_PT_TRACESTOP:
                case INTEL_PT_TNT:
+                       decoder->have_tma = false;
                        intel_pt_log("ERROR: Unexpected packet\n");
                        if (decoder->ip)
                                decoder->pkt_state = INTEL_PT_STATE_ERR4;
                        break;
 
                case INTEL_PT_MTC:
+                       intel_pt_calc_mtc_timestamp(decoder);
                        break;
 
                case INTEL_PT_TSC:
                        break;
 
                case INTEL_PT_TMA:
+                       intel_pt_calc_tma(decoder);
                        break;
 
                case INTEL_PT_CYC: