@@ -168,6 +168,9 @@ struct hw_perf_event {
/* Last sync'ed generation of filters */
unsigned long addr_filters_gen;
+ /* HW specific configuration */
+ void *drv_configs;
+
/*
* hw_perf_event::state flags; used to track the PERF_EF_* state.
*/
@@ -442,6 +445,12 @@ struct pmu {
* Filter events for PMU-specific reasons.
*/
int (*filter_match) (struct perf_event *event); /* optional */
+
+ /*
+ * PMU driver specific configuration.
+ */
+ int (*set_drv_configs) (struct perf_event *event,
+ void __user *arg); /* optional */
};
/**
@@ -403,6 +403,7 @@ struct perf_event_attr {
#define PERF_EVENT_IOC_ID _IOR('$', 7, __u64 *)
#define PERF_EVENT_IOC_SET_BPF _IOW('$', 8, __u32)
#define PERF_EVENT_IOC_PAUSE_OUTPUT _IOW('$', 9, __u32)
+#define PERF_EVENT_IOC_SET_DRV_CONFIGS _IOW('$', 10, char *)
enum perf_event_ioc_flags {
PERF_IOC_FLAG_GROUP = 1U << 0,
@@ -4414,6 +4414,8 @@ static int perf_event_set_output(struct perf_event *event,
struct perf_event *output_event);
static int perf_event_set_filter(struct perf_event *event, void __user *arg);
static int perf_event_set_bpf_prog(struct perf_event *event, u32 prog_fd);
+static int perf_event_set_drv_configs(struct perf_event *event,
+ void __user *arg);
static long _perf_ioctl(struct perf_event *event, unsigned int cmd, unsigned long arg)
{
@@ -4483,6 +4485,10 @@ static long _perf_ioctl(struct perf_event *event, unsigned int cmd, unsigned lon
rcu_read_unlock();
return 0;
}
+
+ case PERF_EVENT_IOC_SET_DRV_CONFIGS:
+ return perf_event_set_drv_configs(event, (void __user *)arg);
+
default:
return -ENOTTY;
}
@@ -4515,6 +4521,7 @@ static long perf_compat_ioctl(struct file *file, unsigned int cmd,
switch (_IOC_NR(cmd)) {
case _IOC_NR(PERF_EVENT_IOC_SET_FILTER):
case _IOC_NR(PERF_EVENT_IOC_ID):
+ case _IOC_NR(PERF_EVENT_IOC_SET_DRV_CONFIGS):
/* Fix up pointer size (usually 4 -> 8 in 32-on-64-bit case */
if (_IOC_SIZE(cmd) == sizeof(compat_uptr_t)) {
cmd &= ~IOCSIZE_MASK;
@@ -7585,6 +7592,15 @@ void perf_bp_event(struct perf_event *bp, void *data)
}
#endif
+static int perf_event_set_drv_configs(struct perf_event *event,
+ void __user *arg)
+{
+ if (!event->pmu->set_drv_configs)
+ return -EINVAL;
+
+ return event->pmu->set_drv_configs(event, arg);
+}
+
/*
* Allocate a new address filter
*/
This patch somewhat mimics the work done on address filters to add the infrastructure needed to pass PMU specific HW configuration to the driver before a session starts. Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org> --- include/linux/perf_event.h | 9 +++++++++ include/uapi/linux/perf_event.h | 1 + kernel/events/core.c | 16 ++++++++++++++++ 3 files changed, 26 insertions(+) -- 2.7.4