]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - arch/s390/kernel/perf_cpum_cf.c
Merge remote-tracking branch 'input-current/for-linus'
[karo-tx-linux.git] / arch / s390 / kernel / perf_cpum_cf.c
index a9563409c36ea7bc37bfb405411b9c6ac70c2a50..929c147e07b40c19370e621a4ba96e99c13a994e 100644 (file)
@@ -72,6 +72,7 @@ struct cpu_hw_events {
        atomic_t                ctr_set[CPUMF_CTR_SET_MAX];
        u64                     state, tx_state;
        unsigned int            flags;
+       unsigned int            txn_flags;
 };
 static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = {
        .ctr_set = {
@@ -82,6 +83,7 @@ static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = {
        },
        .state = 0,
        .flags = 0,
+       .txn_flags = 0,
 };
 
 static int get_counter_set(u64 event)
@@ -538,7 +540,7 @@ static int cpumf_pmu_add(struct perf_event *event, int flags)
         * For group events transaction, the authorization check is
         * done in cpumf_pmu_commit_txn().
         */
-       if (!(cpuhw->flags & PERF_EVENT_TXN))
+       if (!(cpuhw->txn_flags & PERF_PMU_TXN_ADD))
                if (validate_ctr_auth(&event->hw))
                        return -ENOENT;
 
@@ -576,13 +578,22 @@ static void cpumf_pmu_del(struct perf_event *event, int flags)
 /*
  * Start group events scheduling transaction.
  * Set flags to perform a single test at commit time.
+ *
+ * We only support PERF_PMU_TXN_ADD transactions. Save the
+ * transaction flags but otherwise ignore non-PERF_PMU_TXN_ADD
+ * transactions.
  */
-static void cpumf_pmu_start_txn(struct pmu *pmu)
+static void cpumf_pmu_start_txn(struct pmu *pmu, unsigned int txn_flags)
 {
        struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events);
 
+       WARN_ON_ONCE(cpuhw->txn_flags);         /* txn already in flight */
+
+       cpuhw->txn_flags = txn_flags;
+       if (txn_flags & ~PERF_PMU_TXN_ADD)
+               return;
+
        perf_pmu_disable(pmu);
-       cpuhw->flags |= PERF_EVENT_TXN;
        cpuhw->tx_state = cpuhw->state;
 }
 
@@ -593,11 +604,18 @@ static void cpumf_pmu_start_txn(struct pmu *pmu)
  */
 static void cpumf_pmu_cancel_txn(struct pmu *pmu)
 {
+       unsigned int txn_flags;
        struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events);
 
+       WARN_ON_ONCE(!cpuhw->txn_flags);        /* no txn in flight */
+
+       txn_flags = cpuhw->txn_flags;
+       cpuhw->txn_flags = 0;
+       if (txn_flags & ~PERF_PMU_TXN_ADD)
+               return;
+
        WARN_ON(cpuhw->tx_state != cpuhw->state);
 
-       cpuhw->flags &= ~PERF_EVENT_TXN;
        perf_pmu_enable(pmu);
 }
 
@@ -611,13 +629,20 @@ static int cpumf_pmu_commit_txn(struct pmu *pmu)
        struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events);
        u64 state;
 
+       WARN_ON_ONCE(!cpuhw->txn_flags);        /* no txn in flight */
+
+       if (cpuhw->txn_flags & ~PERF_PMU_TXN_ADD) {
+               cpuhw->txn_flags = 0;
+               return 0;
+       }
+
        /* check if the updated state can be scheduled */
        state = cpuhw->state & ~((1 << CPUMF_LCCTL_ENABLE_SHIFT) - 1);
        state >>= CPUMF_LCCTL_ENABLE_SHIFT;
        if ((state & cpuhw->info.auth_ctl) != state)
                return -ENOENT;
 
-       cpuhw->flags &= ~PERF_EVENT_TXN;
+       cpuhw->txn_flags = 0;
        perf_pmu_enable(pmu);
        return 0;
 }