Merge branch 'x86-paravirt-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-block.git] / arch / x86 / events / intel / ds.c
index 50f647e131bc028936b3ccef52aa6ad3158a8bfe..2c8db2c19328bcbf95e8c14b4f58e0d2d6d7d7ba 100644 (file)
@@ -684,7 +684,7 @@ struct event_constraint intel_core2_pebs_event_constraints[] = {
        INTEL_FLAGS_UEVENT_CONSTRAINT(0x1fc7, 0x1), /* SIMD_INST_RETURED.ANY */
        INTEL_FLAGS_EVENT_CONSTRAINT(0xcb, 0x1),    /* MEM_LOAD_RETIRED.* */
        /* INST_RETIRED.ANY_P, inv=1, cmask=16 (cycles:p). */
-       INTEL_FLAGS_EVENT_CONSTRAINT(0x108000c0, 0x01),
+       INTEL_FLAGS_UEVENT_CONSTRAINT(0x108000c0, 0x01),
        EVENT_CONSTRAINT_END
 };
 
@@ -693,7 +693,7 @@ struct event_constraint intel_atom_pebs_event_constraints[] = {
        INTEL_FLAGS_UEVENT_CONSTRAINT(0x00c5, 0x1), /* MISPREDICTED_BRANCH_RETIRED */
        INTEL_FLAGS_EVENT_CONSTRAINT(0xcb, 0x1),    /* MEM_LOAD_RETIRED.* */
        /* INST_RETIRED.ANY_P, inv=1, cmask=16 (cycles:p). */
-       INTEL_FLAGS_EVENT_CONSTRAINT(0x108000c0, 0x01),
+       INTEL_FLAGS_UEVENT_CONSTRAINT(0x108000c0, 0x01),
        /* Allow all events as PEBS with no flags */
        INTEL_ALL_EVENT_CONSTRAINT(0, 0x1),
        EVENT_CONSTRAINT_END
@@ -701,7 +701,7 @@ struct event_constraint intel_atom_pebs_event_constraints[] = {
 
 struct event_constraint intel_slm_pebs_event_constraints[] = {
        /* INST_RETIRED.ANY_P, inv=1, cmask=16 (cycles:p). */
-       INTEL_FLAGS_EVENT_CONSTRAINT(0x108000c0, 0x1),
+       INTEL_FLAGS_UEVENT_CONSTRAINT(0x108000c0, 0x1),
        /* Allow all events as PEBS with no flags */
        INTEL_ALL_EVENT_CONSTRAINT(0, 0x1),
        EVENT_CONSTRAINT_END
@@ -726,7 +726,7 @@ struct event_constraint intel_nehalem_pebs_event_constraints[] = {
        INTEL_FLAGS_EVENT_CONSTRAINT(0xcb, 0xf),    /* MEM_LOAD_RETIRED.* */
        INTEL_FLAGS_EVENT_CONSTRAINT(0xf7, 0xf),    /* FP_ASSIST.* */
        /* INST_RETIRED.ANY_P, inv=1, cmask=16 (cycles:p). */
-       INTEL_FLAGS_EVENT_CONSTRAINT(0x108000c0, 0x0f),
+       INTEL_FLAGS_UEVENT_CONSTRAINT(0x108000c0, 0x0f),
        EVENT_CONSTRAINT_END
 };
 
@@ -743,7 +743,7 @@ struct event_constraint intel_westmere_pebs_event_constraints[] = {
        INTEL_FLAGS_EVENT_CONSTRAINT(0xcb, 0xf),    /* MEM_LOAD_RETIRED.* */
        INTEL_FLAGS_EVENT_CONSTRAINT(0xf7, 0xf),    /* FP_ASSIST.* */
        /* INST_RETIRED.ANY_P, inv=1, cmask=16 (cycles:p). */
-       INTEL_FLAGS_EVENT_CONSTRAINT(0x108000c0, 0x0f),
+       INTEL_FLAGS_UEVENT_CONSTRAINT(0x108000c0, 0x0f),
        EVENT_CONSTRAINT_END
 };
 
@@ -752,7 +752,7 @@ struct event_constraint intel_snb_pebs_event_constraints[] = {
        INTEL_PLD_CONSTRAINT(0x01cd, 0x8),    /* MEM_TRANS_RETIRED.LAT_ABOVE_THR */
        INTEL_PST_CONSTRAINT(0x02cd, 0x8),    /* MEM_TRANS_RETIRED.PRECISE_STORES */
        /* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */
-       INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf),
+       INTEL_FLAGS_UEVENT_CONSTRAINT(0x108001c2, 0xf),
         INTEL_EXCLEVT_CONSTRAINT(0xd0, 0xf),    /* MEM_UOP_RETIRED.* */
         INTEL_EXCLEVT_CONSTRAINT(0xd1, 0xf),    /* MEM_LOAD_UOPS_RETIRED.* */
         INTEL_EXCLEVT_CONSTRAINT(0xd2, 0xf),    /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */
@@ -767,9 +767,9 @@ struct event_constraint intel_ivb_pebs_event_constraints[] = {
         INTEL_PLD_CONSTRAINT(0x01cd, 0x8),    /* MEM_TRANS_RETIRED.LAT_ABOVE_THR */
        INTEL_PST_CONSTRAINT(0x02cd, 0x8),    /* MEM_TRANS_RETIRED.PRECISE_STORES */
        /* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */
-       INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf),
+       INTEL_FLAGS_UEVENT_CONSTRAINT(0x108001c2, 0xf),
        /* INST_RETIRED.PREC_DIST, inv=1, cmask=16 (cycles:ppp). */
-       INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c0, 0x2),
+       INTEL_FLAGS_UEVENT_CONSTRAINT(0x108001c0, 0x2),
        INTEL_EXCLEVT_CONSTRAINT(0xd0, 0xf),    /* MEM_UOP_RETIRED.* */
        INTEL_EXCLEVT_CONSTRAINT(0xd1, 0xf),    /* MEM_LOAD_UOPS_RETIRED.* */
        INTEL_EXCLEVT_CONSTRAINT(0xd2, 0xf),    /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */
@@ -783,9 +783,9 @@ struct event_constraint intel_hsw_pebs_event_constraints[] = {
        INTEL_FLAGS_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */
        INTEL_PLD_CONSTRAINT(0x01cd, 0xf),    /* MEM_TRANS_RETIRED.* */
        /* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */
-       INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf),
+       INTEL_FLAGS_UEVENT_CONSTRAINT(0x108001c2, 0xf),
        /* INST_RETIRED.PREC_DIST, inv=1, cmask=16 (cycles:ppp). */
-       INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c0, 0x2),
+       INTEL_FLAGS_UEVENT_CONSTRAINT(0x108001c0, 0x2),
        INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_NA(0x01c2, 0xf), /* UOPS_RETIRED.ALL */
        INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XLD(0x11d0, 0xf), /* MEM_UOPS_RETIRED.STLB_MISS_LOADS */
        INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XLD(0x21d0, 0xf), /* MEM_UOPS_RETIRED.LOCK_LOADS */
@@ -806,9 +806,9 @@ struct event_constraint intel_bdw_pebs_event_constraints[] = {
        INTEL_FLAGS_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */
        INTEL_PLD_CONSTRAINT(0x01cd, 0xf),    /* MEM_TRANS_RETIRED.* */
        /* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */
-       INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf),
+       INTEL_FLAGS_UEVENT_CONSTRAINT(0x108001c2, 0xf),
        /* INST_RETIRED.PREC_DIST, inv=1, cmask=16 (cycles:ppp). */
-       INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c0, 0x2),
+       INTEL_FLAGS_UEVENT_CONSTRAINT(0x108001c0, 0x2),
        INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_NA(0x01c2, 0xf), /* UOPS_RETIRED.ALL */
        INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x11d0, 0xf), /* MEM_UOPS_RETIRED.STLB_MISS_LOADS */
        INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x21d0, 0xf), /* MEM_UOPS_RETIRED.LOCK_LOADS */
@@ -829,9 +829,9 @@ struct event_constraint intel_bdw_pebs_event_constraints[] = {
 struct event_constraint intel_skl_pebs_event_constraints[] = {
        INTEL_FLAGS_UEVENT_CONSTRAINT(0x1c0, 0x2),      /* INST_RETIRED.PREC_DIST */
        /* INST_RETIRED.PREC_DIST, inv=1, cmask=16 (cycles:ppp). */
-       INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c0, 0x2),
+       INTEL_FLAGS_UEVENT_CONSTRAINT(0x108001c0, 0x2),
        /* INST_RETIRED.TOTAL_CYCLES_PS (inv=1, cmask=16) (cycles:p). */
-       INTEL_FLAGS_EVENT_CONSTRAINT(0x108000c0, 0x0f),
+       INTEL_FLAGS_UEVENT_CONSTRAINT(0x108000c0, 0x0f),
        INTEL_PLD_CONSTRAINT(0x1cd, 0xf),                     /* MEM_TRANS_RETIRED.* */
        INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x11d0, 0xf), /* MEM_INST_RETIRED.STLB_MISS_LOADS */
        INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x12d0, 0xf), /* MEM_INST_RETIRED.STLB_MISS_STORES */
@@ -849,6 +849,26 @@ struct event_constraint intel_skl_pebs_event_constraints[] = {
        EVENT_CONSTRAINT_END
 };
 
+struct event_constraint intel_icl_pebs_event_constraints[] = {
+       INTEL_FLAGS_UEVENT_CONSTRAINT(0x1c0, 0x100000000ULL),   /* INST_RETIRED.PREC_DIST */
+       INTEL_FLAGS_UEVENT_CONSTRAINT(0x0400, 0x400000000ULL),  /* SLOTS */
+
+       INTEL_PLD_CONSTRAINT(0x1cd, 0xff),                      /* MEM_TRANS_RETIRED.LOAD_LATENCY */
+       INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x1d0, 0xf),    /* MEM_INST_RETIRED.LOAD */
+       INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x2d0, 0xf),    /* MEM_INST_RETIRED.STORE */
+
+       INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD_RANGE(0xd1, 0xd4, 0xf), /* MEM_LOAD_*_RETIRED.* */
+
+       INTEL_FLAGS_EVENT_CONSTRAINT(0xd0, 0xf),                /* MEM_INST_RETIRED.* */
+
+       /*
+        * Everything else is handled by PMU_FL_PEBS_ALL, because we
+        * need the full constraints from the main table.
+        */
+
+       EVENT_CONSTRAINT_END
+};
+
 struct event_constraint *intel_pebs_constraints(struct perf_event *event)
 {
        struct event_constraint *c;
@@ -858,7 +878,7 @@ struct event_constraint *intel_pebs_constraints(struct perf_event *event)
 
        if (x86_pmu.pebs_constraints) {
                for_each_event_constraint(c, x86_pmu.pebs_constraints) {
-                       if ((event->hw.config & c->cmask) == c->code) {
+                       if (constraint_match(c, event->hw.config)) {
                                event->hw.flags |= c->flags;
                                return c;
                        }
@@ -906,17 +926,87 @@ static inline void pebs_update_threshold(struct cpu_hw_events *cpuc)
 
        if (cpuc->n_pebs == cpuc->n_large_pebs) {
                threshold = ds->pebs_absolute_maximum -
-                       reserved * x86_pmu.pebs_record_size;
+                       reserved * cpuc->pebs_record_size;
        } else {
-               threshold = ds->pebs_buffer_base + x86_pmu.pebs_record_size;
+               threshold = ds->pebs_buffer_base + cpuc->pebs_record_size;
        }
 
        ds->pebs_interrupt_threshold = threshold;
 }
 
+static void adaptive_pebs_record_size_update(void)
+{
+       struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+       u64 pebs_data_cfg = cpuc->pebs_data_cfg;
+       int sz = sizeof(struct pebs_basic);
+
+       if (pebs_data_cfg & PEBS_DATACFG_MEMINFO)
+               sz += sizeof(struct pebs_meminfo);
+       if (pebs_data_cfg & PEBS_DATACFG_GP)
+               sz += sizeof(struct pebs_gprs);
+       if (pebs_data_cfg & PEBS_DATACFG_XMMS)
+               sz += sizeof(struct pebs_xmm);
+       if (pebs_data_cfg & PEBS_DATACFG_LBRS)
+               sz += x86_pmu.lbr_nr * sizeof(struct pebs_lbr_entry);
+
+       cpuc->pebs_record_size = sz;
+}
+
+#define PERF_PEBS_MEMINFO_TYPE (PERF_SAMPLE_ADDR | PERF_SAMPLE_DATA_SRC |   \
+                               PERF_SAMPLE_PHYS_ADDR | PERF_SAMPLE_WEIGHT | \
+                               PERF_SAMPLE_TRANSACTION)
+
+static u64 pebs_update_adaptive_cfg(struct perf_event *event)
+{
+       struct perf_event_attr *attr = &event->attr;
+       u64 sample_type = attr->sample_type;
+       u64 pebs_data_cfg = 0;
+       bool gprs, tsx_weight;
+
+       if (!(sample_type & ~(PERF_SAMPLE_IP|PERF_SAMPLE_TIME)) &&
+           attr->precise_ip > 1)
+               return pebs_data_cfg;
+
+       if (sample_type & PERF_PEBS_MEMINFO_TYPE)
+               pebs_data_cfg |= PEBS_DATACFG_MEMINFO;
+
+       /*
+        * We need GPRs when:
+        * + user requested them
+        * + precise_ip < 2 for the non event IP
+        * + For RTM TSX weight we need GPRs for the abort code.
+        */
+       gprs = (sample_type & PERF_SAMPLE_REGS_INTR) &&
+              (attr->sample_regs_intr & PEBS_GP_REGS);
+
+       tsx_weight = (sample_type & PERF_SAMPLE_WEIGHT) &&
+                    ((attr->config & INTEL_ARCH_EVENT_MASK) ==
+                     x86_pmu.rtm_abort_event);
+
+       if (gprs || (attr->precise_ip < 2) || tsx_weight)
+               pebs_data_cfg |= PEBS_DATACFG_GP;
+
+       if ((sample_type & PERF_SAMPLE_REGS_INTR) &&
+           (attr->sample_regs_intr & PERF_REG_EXTENDED_MASK))
+               pebs_data_cfg |= PEBS_DATACFG_XMMS;
+
+       if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
+               /*
+                * For now always log all LBRs. Could configure this
+                * later.
+                */
+               pebs_data_cfg |= PEBS_DATACFG_LBRS |
+                       ((x86_pmu.lbr_nr-1) << PEBS_DATACFG_LBR_SHIFT);
+       }
+
+       return pebs_data_cfg;
+}
+
 static void
-pebs_update_state(bool needed_cb, struct cpu_hw_events *cpuc, struct pmu *pmu)
+pebs_update_state(bool needed_cb, struct cpu_hw_events *cpuc,
+                 struct perf_event *event, bool add)
 {
+       struct pmu *pmu = event->ctx->pmu;
        /*
         * Make sure we get updated with the first PEBS
         * event. It will trigger also during removal, but
@@ -933,6 +1023,29 @@ pebs_update_state(bool needed_cb, struct cpu_hw_events *cpuc, struct pmu *pmu)
                update = true;
        }
 
+       /*
+        * The PEBS record doesn't shrink on pmu::del(). Doing so would require
+        * iterating all remaining PEBS events to reconstruct the config.
+        */
+       if (x86_pmu.intel_cap.pebs_baseline && add) {
+               u64 pebs_data_cfg;
+
+               /* Clear pebs_data_cfg and pebs_record_size for first PEBS. */
+               if (cpuc->n_pebs == 1) {
+                       cpuc->pebs_data_cfg = 0;
+                       cpuc->pebs_record_size = sizeof(struct pebs_basic);
+               }
+
+               pebs_data_cfg = pebs_update_adaptive_cfg(event);
+
+               /* Update pebs_record_size if new event requires more data. */
+               if (pebs_data_cfg & ~cpuc->pebs_data_cfg) {
+                       cpuc->pebs_data_cfg |= pebs_data_cfg;
+                       adaptive_pebs_record_size_update();
+                       update = true;
+               }
+       }
+
        if (update)
                pebs_update_threshold(cpuc);
 }
@@ -947,7 +1060,7 @@ void intel_pmu_pebs_add(struct perf_event *event)
        if (hwc->flags & PERF_X86_EVENT_LARGE_PEBS)
                cpuc->n_large_pebs++;
 
-       pebs_update_state(needed_cb, cpuc, event->ctx->pmu);
+       pebs_update_state(needed_cb, cpuc, event, true);
 }
 
 void intel_pmu_pebs_enable(struct perf_event *event)
@@ -960,11 +1073,19 @@ void intel_pmu_pebs_enable(struct perf_event *event)
 
        cpuc->pebs_enabled |= 1ULL << hwc->idx;
 
-       if (event->hw.flags & PERF_X86_EVENT_PEBS_LDLAT)
+       if ((event->hw.flags & PERF_X86_EVENT_PEBS_LDLAT) && (x86_pmu.version < 5))
                cpuc->pebs_enabled |= 1ULL << (hwc->idx + 32);
        else if (event->hw.flags & PERF_X86_EVENT_PEBS_ST)
                cpuc->pebs_enabled |= 1ULL << 63;
 
+       if (x86_pmu.intel_cap.pebs_baseline) {
+               hwc->config |= ICL_EVENTSEL_ADAPTIVE;
+               if (cpuc->pebs_data_cfg != cpuc->active_pebs_data_cfg) {
+                       wrmsrl(MSR_PEBS_DATA_CFG, cpuc->pebs_data_cfg);
+                       cpuc->active_pebs_data_cfg = cpuc->pebs_data_cfg;
+               }
+       }
+
        /*
         * Use auto-reload if possible to save a MSR write in the PMI.
         * This must be done in pmu::start(), because PERF_EVENT_IOC_PERIOD.
@@ -991,7 +1112,7 @@ void intel_pmu_pebs_del(struct perf_event *event)
        if (hwc->flags & PERF_X86_EVENT_LARGE_PEBS)
                cpuc->n_large_pebs--;
 
-       pebs_update_state(needed_cb, cpuc, event->ctx->pmu);
+       pebs_update_state(needed_cb, cpuc, event, false);
 }
 
 void intel_pmu_pebs_disable(struct perf_event *event)
@@ -1004,7 +1125,8 @@ void intel_pmu_pebs_disable(struct perf_event *event)
 
        cpuc->pebs_enabled &= ~(1ULL << hwc->idx);
 
-       if (event->hw.flags & PERF_X86_EVENT_PEBS_LDLAT)
+       if ((event->hw.flags & PERF_X86_EVENT_PEBS_LDLAT) &&
+           (x86_pmu.version < 5))
                cpuc->pebs_enabled &= ~(1ULL << (hwc->idx + 32));
        else if (event->hw.flags & PERF_X86_EVENT_PEBS_ST)
                cpuc->pebs_enabled &= ~(1ULL << 63);
@@ -1125,34 +1247,57 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs)
        return 0;
 }
 
-static inline u64 intel_hsw_weight(struct pebs_record_skl *pebs)
+static inline u64 intel_get_tsx_weight(u64 tsx_tuning)
 {
-       if (pebs->tsx_tuning) {
-               union hsw_tsx_tuning tsx = { .value = pebs->tsx_tuning };
+       if (tsx_tuning) {
+               union hsw_tsx_tuning tsx = { .value = tsx_tuning };
                return tsx.cycles_last_block;
        }
        return 0;
 }
 
-static inline u64 intel_hsw_transaction(struct pebs_record_skl *pebs)
+static inline u64 intel_get_tsx_transaction(u64 tsx_tuning, u64 ax)
 {
-       u64 txn = (pebs->tsx_tuning & PEBS_HSW_TSX_FLAGS) >> 32;
+       u64 txn = (tsx_tuning & PEBS_HSW_TSX_FLAGS) >> 32;
 
        /* For RTM XABORTs also log the abort code from AX */
-       if ((txn & PERF_TXN_TRANSACTION) && (pebs->ax & 1))
-               txn |= ((pebs->ax >> 24) & 0xff) << PERF_TXN_ABORT_SHIFT;
+       if ((txn & PERF_TXN_TRANSACTION) && (ax & 1))
+               txn |= ((ax >> 24) & 0xff) << PERF_TXN_ABORT_SHIFT;
        return txn;
 }
 
-static void setup_pebs_sample_data(struct perf_event *event,
-                                  struct pt_regs *iregs, void *__pebs,
-                                  struct perf_sample_data *data,
-                                  struct pt_regs *regs)
+static inline u64 get_pebs_status(void *n)
 {
+       if (x86_pmu.intel_cap.pebs_format < 4)
+               return ((struct pebs_record_nhm *)n)->status;
+       return ((struct pebs_basic *)n)->applicable_counters;
+}
+
 #define PERF_X86_EVENT_PEBS_HSW_PREC \
                (PERF_X86_EVENT_PEBS_ST_HSW | \
                 PERF_X86_EVENT_PEBS_LD_HSW | \
                 PERF_X86_EVENT_PEBS_NA_HSW)
+
+static u64 get_data_src(struct perf_event *event, u64 aux)
+{
+       u64 val = PERF_MEM_NA;
+       int fl = event->hw.flags;
+       bool fst = fl & (PERF_X86_EVENT_PEBS_ST | PERF_X86_EVENT_PEBS_HSW_PREC);
+
+       if (fl & PERF_X86_EVENT_PEBS_LDLAT)
+               val = load_latency_data(aux);
+       else if (fst && (fl & PERF_X86_EVENT_PEBS_HSW_PREC))
+               val = precise_datala_hsw(event, aux);
+       else if (fst)
+               val = precise_store_data(aux);
+       return val;
+}
+
+static void setup_pebs_fixed_sample_data(struct perf_event *event,
+                                  struct pt_regs *iregs, void *__pebs,
+                                  struct perf_sample_data *data,
+                                  struct pt_regs *regs)
+{
        /*
         * We cast to the biggest pebs_record but are careful not to
         * unconditionally access the 'extra' entries.
@@ -1160,17 +1305,13 @@ static void setup_pebs_sample_data(struct perf_event *event,
        struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
        struct pebs_record_skl *pebs = __pebs;
        u64 sample_type;
-       int fll, fst, dsrc;
-       int fl = event->hw.flags;
+       int fll;
 
        if (pebs == NULL)
                return;
 
        sample_type = event->attr.sample_type;
-       dsrc = sample_type & PERF_SAMPLE_DATA_SRC;
-
-       fll = fl & PERF_X86_EVENT_PEBS_LDLAT;
-       fst = fl & (PERF_X86_EVENT_PEBS_ST | PERF_X86_EVENT_PEBS_HSW_PREC);
+       fll = event->hw.flags & PERF_X86_EVENT_PEBS_LDLAT;
 
        perf_sample_data_init(data, 0, event->hw.last_period);
 
@@ -1185,16 +1326,8 @@ static void setup_pebs_sample_data(struct perf_event *event,
        /*
         * data.data_src encodes the data source
         */
-       if (dsrc) {
-               u64 val = PERF_MEM_NA;
-               if (fll)
-                       val = load_latency_data(pebs->dse);
-               else if (fst && (fl & PERF_X86_EVENT_PEBS_HSW_PREC))
-                       val = precise_datala_hsw(event, pebs->dse);
-               else if (fst)
-                       val = precise_store_data(pebs->dse);
-               data->data_src.val = val;
-       }
+       if (sample_type & PERF_SAMPLE_DATA_SRC)
+               data->data_src.val = get_data_src(event, pebs->dse);
 
        /*
         * We must however always use iregs for the unwinder to stay sane; the
@@ -1281,10 +1414,11 @@ static void setup_pebs_sample_data(struct perf_event *event,
        if (x86_pmu.intel_cap.pebs_format >= 2) {
                /* Only set the TSX weight when no memory weight. */
                if ((sample_type & PERF_SAMPLE_WEIGHT) && !fll)
-                       data->weight = intel_hsw_weight(pebs);
+                       data->weight = intel_get_tsx_weight(pebs->tsx_tuning);
 
                if (sample_type & PERF_SAMPLE_TRANSACTION)
-                       data->txn = intel_hsw_transaction(pebs);
+                       data->txn = intel_get_tsx_transaction(pebs->tsx_tuning,
+                                                             pebs->ax);
        }
 
        /*
@@ -1301,6 +1435,140 @@ static void setup_pebs_sample_data(struct perf_event *event,
                data->br_stack = &cpuc->lbr_stack;
 }
 
+static void adaptive_pebs_save_regs(struct pt_regs *regs,
+                                   struct pebs_gprs *gprs)
+{
+       regs->ax = gprs->ax;
+       regs->bx = gprs->bx;
+       regs->cx = gprs->cx;
+       regs->dx = gprs->dx;
+       regs->si = gprs->si;
+       regs->di = gprs->di;
+       regs->bp = gprs->bp;
+       regs->sp = gprs->sp;
+#ifndef CONFIG_X86_32
+       regs->r8 = gprs->r8;
+       regs->r9 = gprs->r9;
+       regs->r10 = gprs->r10;
+       regs->r11 = gprs->r11;
+       regs->r12 = gprs->r12;
+       regs->r13 = gprs->r13;
+       regs->r14 = gprs->r14;
+       regs->r15 = gprs->r15;
+#endif
+}
+
+/*
+ * With adaptive PEBS the layout depends on what fields are configured.
+ */
+
+static void setup_pebs_adaptive_sample_data(struct perf_event *event,
+                                           struct pt_regs *iregs, void *__pebs,
+                                           struct perf_sample_data *data,
+                                           struct pt_regs *regs)
+{
+       struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+       struct pebs_basic *basic = __pebs;
+       void *next_record = basic + 1;
+       u64 sample_type;
+       u64 format_size;
+       struct pebs_meminfo *meminfo = NULL;
+       struct pebs_gprs *gprs = NULL;
+       struct x86_perf_regs *perf_regs;
+
+       if (basic == NULL)
+               return;
+
+       perf_regs = container_of(regs, struct x86_perf_regs, regs);
+       perf_regs->xmm_regs = NULL;
+
+       sample_type = event->attr.sample_type;
+       format_size = basic->format_size;
+       perf_sample_data_init(data, 0, event->hw.last_period);
+       data->period = event->hw.last_period;
+
+       if (event->attr.use_clockid == 0)
+               data->time = native_sched_clock_from_tsc(basic->tsc);
+
+       /*
+        * We must however always use iregs for the unwinder to stay sane; the
+        * record BP,SP,IP can point into thin air when the record is from a
+        * previous PMI context or an (I)RET happened between the record and
+        * PMI.
+        */
+       if (sample_type & PERF_SAMPLE_CALLCHAIN)
+               data->callchain = perf_callchain(event, iregs);
+
+       *regs = *iregs;
+       /* The ip in basic is EventingIP */
+       set_linear_ip(regs, basic->ip);
+       regs->flags = PERF_EFLAGS_EXACT;
+
+       /*
+        * The record for MEMINFO is in front of GP
+        * But PERF_SAMPLE_TRANSACTION needs gprs->ax.
+        * Save the pointer here but process later.
+        */
+       if (format_size & PEBS_DATACFG_MEMINFO) {
+               meminfo = next_record;
+               next_record = meminfo + 1;
+       }
+
+       if (format_size & PEBS_DATACFG_GP) {
+               gprs = next_record;
+               next_record = gprs + 1;
+
+               if (event->attr.precise_ip < 2) {
+                       set_linear_ip(regs, gprs->ip);
+                       regs->flags &= ~PERF_EFLAGS_EXACT;
+               }
+
+               if (sample_type & PERF_SAMPLE_REGS_INTR)
+                       adaptive_pebs_save_regs(regs, gprs);
+       }
+
+       if (format_size & PEBS_DATACFG_MEMINFO) {
+               if (sample_type & PERF_SAMPLE_WEIGHT)
+                       data->weight = meminfo->latency ?:
+                               intel_get_tsx_weight(meminfo->tsx_tuning);
+
+               if (sample_type & PERF_SAMPLE_DATA_SRC)
+                       data->data_src.val = get_data_src(event, meminfo->aux);
+
+               if (sample_type & (PERF_SAMPLE_ADDR | PERF_SAMPLE_PHYS_ADDR))
+                       data->addr = meminfo->address;
+
+               if (sample_type & PERF_SAMPLE_TRANSACTION)
+                       data->txn = intel_get_tsx_transaction(meminfo->tsx_tuning,
+                                                         gprs ? gprs->ax : 0);
+       }
+
+       if (format_size & PEBS_DATACFG_XMMS) {
+               struct pebs_xmm *xmm = next_record;
+
+               next_record = xmm + 1;
+               perf_regs->xmm_regs = xmm->xmm;
+       }
+
+       if (format_size & PEBS_DATACFG_LBRS) {
+               struct pebs_lbr *lbr = next_record;
+               int num_lbr = ((format_size >> PEBS_DATACFG_LBR_SHIFT)
+                                       & 0xff) + 1;
+               next_record = next_record + num_lbr*sizeof(struct pebs_lbr_entry);
+
+               if (has_branch_stack(event)) {
+                       intel_pmu_store_pebs_lbrs(lbr);
+                       data->br_stack = &cpuc->lbr_stack;
+               }
+       }
+
+       WARN_ONCE(next_record != __pebs + (format_size >> 48),
+                       "PEBS record size %llu, expected %llu, config %llx\n",
+                       format_size >> 48,
+                       (u64)(next_record - __pebs),
+                       basic->format_size);
+}
+
 static inline void *
 get_next_pebs_record_by_bit(void *base, void *top, int bit)
 {
@@ -1318,19 +1586,19 @@ get_next_pebs_record_by_bit(void *base, void *top, int bit)
        if (base == NULL)
                return NULL;
 
-       for (at = base; at < top; at += x86_pmu.pebs_record_size) {
-               struct pebs_record_nhm *p = at;
+       for (at = base; at < top; at += cpuc->pebs_record_size) {
+               unsigned long status = get_pebs_status(at);
 
-               if (test_bit(bit, (unsigned long *)&p->status)) {
+               if (test_bit(bit, (unsigned long *)&status)) {
                        /* PEBS v3 has accurate status bits */
                        if (x86_pmu.intel_cap.pebs_format >= 3)
                                return at;
 
-                       if (p->status == (1 << bit))
+                       if (status == (1 << bit))
                                return at;
 
                        /* clear non-PEBS bit and re-check */
-                       pebs_status = p->status & cpuc->pebs_enabled;
+                       pebs_status = status & cpuc->pebs_enabled;
                        pebs_status &= PEBS_COUNTER_MASK;
                        if (pebs_status == (1 << bit))
                                return at;
@@ -1410,11 +1678,18 @@ intel_pmu_save_and_restart_reload(struct perf_event *event, int count)
 static void __intel_pmu_pebs_event(struct perf_event *event,
                                   struct pt_regs *iregs,
                                   void *base, void *top,
-                                  int bit, int count)
+                                  int bit, int count,
+                                  void (*setup_sample)(struct perf_event *,
+                                               struct pt_regs *,
+                                               void *,
+                                               struct perf_sample_data *,
+                                               struct pt_regs *))
 {
+       struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
        struct hw_perf_event *hwc = &event->hw;
        struct perf_sample_data data;
-       struct pt_regs regs;
+       struct x86_perf_regs perf_regs;
+       struct pt_regs *regs = &perf_regs.regs;
        void *at = get_next_pebs_record_by_bit(base, top, bit);
 
        if (hwc->flags & PERF_X86_EVENT_AUTO_RELOAD) {
@@ -1429,20 +1704,20 @@ static void __intel_pmu_pebs_event(struct perf_event *event,
                return;
 
        while (count > 1) {
-               setup_pebs_sample_data(event, iregs, at, &data, &regs);
-               perf_event_output(event, &data, &regs);
-               at += x86_pmu.pebs_record_size;
+               setup_sample(event, iregs, at, &data, regs);
+               perf_event_output(event, &data, regs);
+               at += cpuc->pebs_record_size;
                at = get_next_pebs_record_by_bit(at, top, bit);
                count--;
        }
 
-       setup_pebs_sample_data(event, iregs, at, &data, &regs);
+       setup_sample(event, iregs, at, &data, regs);
 
        /*
         * All but the last records are processed.
         * The last one is left to be able to call the overflow handler.
         */
-       if (perf_event_overflow(event, &data, &regs)) {
+       if (perf_event_overflow(event, &data, regs)) {
                x86_pmu_stop(event, 0);
                return;
        }
@@ -1483,7 +1758,27 @@ static void intel_pmu_drain_pebs_core(struct pt_regs *iregs)
                return;
        }
 
-       __intel_pmu_pebs_event(event, iregs, at, top, 0, n);
+       __intel_pmu_pebs_event(event, iregs, at, top, 0, n,
+                              setup_pebs_fixed_sample_data);
+}
+
+static void intel_pmu_pebs_event_update_no_drain(struct cpu_hw_events *cpuc, int size)
+{
+       struct perf_event *event;
+       int bit;
+
+       /*
+        * The drain_pebs() could be called twice in a short period
+        * for auto-reload event in pmu::read(). There are no
+        * overflows have happened in between.
+        * It needs to call intel_pmu_save_and_restart_reload() to
+        * update the event->count for this case.
+        */
+       for_each_set_bit(bit, (unsigned long *)&cpuc->pebs_enabled, size) {
+               event = cpuc->events[bit];
+               if (event->hw.flags & PERF_X86_EVENT_AUTO_RELOAD)
+                       intel_pmu_save_and_restart_reload(event, 0);
+       }
 }
 
 static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs)
@@ -1513,19 +1808,7 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs)
        }
 
        if (unlikely(base >= top)) {
-               /*
-                * The drain_pebs() could be called twice in a short period
-                * for auto-reload event in pmu::read(). There are no
-                * overflows have happened in between.
-                * It needs to call intel_pmu_save_and_restart_reload() to
-                * update the event->count for this case.
-                */
-               for_each_set_bit(bit, (unsigned long *)&cpuc->pebs_enabled,
-                                size) {
-                       event = cpuc->events[bit];
-                       if (event->hw.flags & PERF_X86_EVENT_AUTO_RELOAD)
-                               intel_pmu_save_and_restart_reload(event, 0);
-               }
+               intel_pmu_pebs_event_update_no_drain(cpuc, size);
                return;
        }
 
@@ -1538,8 +1821,7 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs)
 
                /* PEBS v3 has more accurate status bits */
                if (x86_pmu.intel_cap.pebs_format >= 3) {
-                       for_each_set_bit(bit, (unsigned long *)&pebs_status,
-                                        size)
+                       for_each_set_bit(bit, (unsigned long *)&pebs_status, size)
                                counts[bit]++;
 
                        continue;
@@ -1578,8 +1860,7 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs)
                 * If collision happened, the record will be dropped.
                 */
                if (p->status != (1ULL << bit)) {
-                       for_each_set_bit(i, (unsigned long *)&pebs_status,
-                                        x86_pmu.max_pebs_events)
+                       for_each_set_bit(i, (unsigned long *)&pebs_status, size)
                                error[i]++;
                        continue;
                }
@@ -1587,7 +1868,7 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs)
                counts[bit]++;
        }
 
-       for (bit = 0; bit < size; bit++) {
+       for_each_set_bit(bit, (unsigned long *)&mask, size) {
                if ((counts[bit] == 0) && (error[bit] == 0))
                        continue;
 
@@ -1608,11 +1889,66 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs)
 
                if (counts[bit]) {
                        __intel_pmu_pebs_event(event, iregs, base,
-                                              top, bit, counts[bit]);
+                                              top, bit, counts[bit],
+                                              setup_pebs_fixed_sample_data);
                }
        }
 }
 
+static void intel_pmu_drain_pebs_icl(struct pt_regs *iregs)
+{
+       short counts[INTEL_PMC_IDX_FIXED + MAX_FIXED_PEBS_EVENTS] = {};
+       struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+       struct debug_store *ds = cpuc->ds;
+       struct perf_event *event;
+       void *base, *at, *top;
+       int bit, size;
+       u64 mask;
+
+       if (!x86_pmu.pebs_active)
+               return;
+
+       base = (struct pebs_basic *)(unsigned long)ds->pebs_buffer_base;
+       top = (struct pebs_basic *)(unsigned long)ds->pebs_index;
+
+       ds->pebs_index = ds->pebs_buffer_base;
+
+       mask = ((1ULL << x86_pmu.max_pebs_events) - 1) |
+              (((1ULL << x86_pmu.num_counters_fixed) - 1) << INTEL_PMC_IDX_FIXED);
+       size = INTEL_PMC_IDX_FIXED + x86_pmu.num_counters_fixed;
+
+       if (unlikely(base >= top)) {
+               intel_pmu_pebs_event_update_no_drain(cpuc, size);
+               return;
+       }
+
+       for (at = base; at < top; at += cpuc->pebs_record_size) {
+               u64 pebs_status;
+
+               pebs_status = get_pebs_status(at) & cpuc->pebs_enabled;
+               pebs_status &= mask;
+
+               for_each_set_bit(bit, (unsigned long *)&pebs_status, size)
+                       counts[bit]++;
+       }
+
+       for_each_set_bit(bit, (unsigned long *)&mask, size) {
+               if (counts[bit] == 0)
+                       continue;
+
+               event = cpuc->events[bit];
+               if (WARN_ON_ONCE(!event))
+                       continue;
+
+               if (WARN_ON_ONCE(!event->attr.precise_ip))
+                       continue;
+
+               __intel_pmu_pebs_event(event, iregs, base,
+                                      top, bit, counts[bit],
+                                      setup_pebs_adaptive_sample_data);
+       }
+}
+
 /*
  * BTS, PEBS probe and setup
  */
@@ -1630,10 +1966,15 @@ void __init intel_ds_init(void)
        x86_pmu.pebs_buffer_size = PEBS_BUFFER_SIZE;
        if (x86_pmu.version <= 4)
                x86_pmu.pebs_no_isolation = 1;
+
        if (x86_pmu.pebs) {
                char pebs_type = x86_pmu.intel_cap.pebs_trap ?  '+' : '-';
+               char *pebs_qual = "";
                int format = x86_pmu.intel_cap.pebs_format;
 
+               if (format < 4)
+                       x86_pmu.intel_cap.pebs_baseline = 0;
+
                switch (format) {
                case 0:
                        pr_cont("PEBS fmt0%c, ", pebs_type);
@@ -1669,6 +2010,29 @@ void __init intel_ds_init(void)
                        x86_pmu.large_pebs_flags |= PERF_SAMPLE_TIME;
                        break;
 
+               case 4:
+                       x86_pmu.drain_pebs = intel_pmu_drain_pebs_icl;
+                       x86_pmu.pebs_record_size = sizeof(struct pebs_basic);
+                       if (x86_pmu.intel_cap.pebs_baseline) {
+                               x86_pmu.large_pebs_flags |=
+                                       PERF_SAMPLE_BRANCH_STACK |
+                                       PERF_SAMPLE_TIME;
+                               x86_pmu.flags |= PMU_FL_PEBS_ALL;
+                               pebs_qual = "-baseline";
+                               x86_get_pmu()->capabilities |= PERF_PMU_CAP_EXTENDED_REGS;
+                       } else {
+                               /* Only basic record supported */
+                               x86_pmu.large_pebs_flags &=
+                                       ~(PERF_SAMPLE_ADDR |
+                                         PERF_SAMPLE_TIME |
+                                         PERF_SAMPLE_DATA_SRC |
+                                         PERF_SAMPLE_TRANSACTION |
+                                         PERF_SAMPLE_REGS_USER |
+                                         PERF_SAMPLE_REGS_INTR);
+                       }
+                       pr_cont("PEBS fmt4%c%s, ", pebs_type, pebs_qual);
+                       break;
+
                default:
                        pr_cont("no PEBS fmt%d%c, ", format, pebs_type);
                        x86_pmu.pebs = 0;