@@ -160,7 +160,10 @@ struct perf_event;
/*
* Common implementation detail of pmu::{start,commit,cancel}_txn
*/
-#define PERF_EVENT_TXN 0x1
+#define PERF_EVENT_TXN_ADD 0x1 /* txn to add/schedule event on PMU */
+#define PERF_EVENT_TXN_READ 0x2 /* txn to add/schedule event on PMU */
+
+#define PERF_EVENT_TXN_MASK (PERF_EVENT_TXN_ADD|PERF_EVENT_TXN_READ)
/**
* pmu::capabilities flags
@@ -240,8 +243,10 @@ struct pmu {
*
* Start the transaction, after this ->add() doesn't need to
* do schedulability tests.
+ *
+ * Optional.
*/
- void (*start_txn) (struct pmu *pmu); /* optional */
+ void (*start_txn) (struct pmu *pmu, int flags);
/*
* If ->start_txn() disabled the ->add() schedulability test
* then ->commit_txn() is required to perform one. On success
@@ -534,6 +534,7 @@ struct perf_cpu_context {
ktime_t hrtimer_interval;
struct pmu *unique_pmu;
struct perf_cgroup *cgrp;
+ int group_flag;
};
struct perf_output_handle {
@@ -6746,18 +6746,35 @@ static int perf_pmu_nop_int(struct pmu *pmu)
static void perf_pmu_start_txn(struct pmu *pmu, int flags)
{
- perf_pmu_disable(pmu);
+ struct perf_cpu_context *cpuctx = this_cpu_ptr(pmu->pmu_cpu_context);
+
+ BUG_ON(cpuctx->group_flag);
+
+ cpuctx->group_flag = flags;
+
+ if (flags & PERF_EVENT_TXN_ADD)
+ perf_pmu_disable(pmu);
}
static int perf_pmu_commit_txn(struct pmu *pmu)
{
- perf_pmu_enable(pmu);
+ struct perf_cpu_context *cpuctx = this_cpu_ptr(pmu->pmu_cpu_context);
+
+ if (cpuctx->group_flag & PERF_EVENT_TXN_ADD)
+ perf_pmu_enable(pmu);
+
+ cpuctx->group_flag &= ~PERF_EVENT_TXN_MASK;
return 0;
}
static void perf_pmu_cancel_txn(struct pmu *pmu)
{
- perf_pmu_enable(pmu);
+ struct perf_cpu_context *cpuctx = this_cpu_ptr(pmu->pmu_cpu_context);
+
+ if (cpuctx->group_flag & PERF_EVENT_TXN_ADD)
+ perf_pmu_enable(pmu);
+
+ cpuctx->group_flag &= ~PERF_EVENT_TXN_MASK;
}
static int perf_event_idx_default(struct perf_event *event)