diff options
Diffstat (limited to 'kernel/perf_event.c')
| -rw-r--r-- | kernel/perf_event.c | 53 |
1 files changed, 52 insertions, 1 deletions
diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 5087125e2a0..98dc56b2ebe 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include <linux/kernel_stat.h> | 29 | #include <linux/kernel_stat.h> |
| 30 | #include <linux/perf_event.h> | 30 | #include <linux/perf_event.h> |
| 31 | #include <linux/ftrace_event.h> | 31 | #include <linux/ftrace_event.h> |
| 32 | #include <linux/hw_breakpoint.h> | ||
| 32 | 33 | ||
| 33 | #include <asm/irq_regs.h> | 34 | #include <asm/irq_regs.h> |
| 34 | 35 | ||
| @@ -4229,6 +4230,51 @@ static void perf_event_free_filter(struct perf_event *event) | |||
| 4229 | 4230 | ||
| 4230 | #endif /* CONFIG_EVENT_PROFILE */ | 4231 | #endif /* CONFIG_EVENT_PROFILE */ |
| 4231 | 4232 | ||
| 4233 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | ||
| 4234 | static void bp_perf_event_destroy(struct perf_event *event) | ||
| 4235 | { | ||
| 4236 | release_bp_slot(event); | ||
| 4237 | } | ||
| 4238 | |||
| 4239 | static const struct pmu *bp_perf_event_init(struct perf_event *bp) | ||
| 4240 | { | ||
| 4241 | int err; | ||
| 4242 | /* | ||
| 4243 | * The breakpoint is already filled if we haven't created the counter | ||
| 4244 | * through perf syscall | ||
| 4245 | * FIXME: manage to get trigerred to NULL if it comes from syscalls | ||
| 4246 | */ | ||
| 4247 | if (!bp->callback) | ||
| 4248 | err = register_perf_hw_breakpoint(bp); | ||
| 4249 | else | ||
| 4250 | err = __register_perf_hw_breakpoint(bp); | ||
| 4251 | if (err) | ||
| 4252 | return ERR_PTR(err); | ||
| 4253 | |||
| 4254 | bp->destroy = bp_perf_event_destroy; | ||
| 4255 | |||
| 4256 | return &perf_ops_bp; | ||
| 4257 | } | ||
| 4258 | |||
| 4259 | void perf_bp_event(struct perf_event *bp, void *regs) | ||
| 4260 | { | ||
| 4261 | /* TODO */ | ||
| 4262 | } | ||
| 4263 | #else | ||
| 4264 | static void bp_perf_event_destroy(struct perf_event *event) | ||
| 4265 | { | ||
| 4266 | } | ||
| 4267 | |||
| 4268 | static const struct pmu *bp_perf_event_init(struct perf_event *bp) | ||
| 4269 | { | ||
| 4270 | return NULL; | ||
| 4271 | } | ||
| 4272 | |||
| 4273 | void perf_bp_event(struct perf_event *bp, void *regs) | ||
| 4274 | { | ||
| 4275 | } | ||
| 4276 | #endif | ||
| 4277 | |||
| 4232 | atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX]; | 4278 | atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX]; |
| 4233 | 4279 | ||
| 4234 | static void sw_perf_event_destroy(struct perf_event *event) | 4280 | static void sw_perf_event_destroy(struct perf_event *event) |
| @@ -4375,6 +4421,11 @@ perf_event_alloc(struct perf_event_attr *attr, | |||
| 4375 | pmu = tp_perf_event_init(event); | 4421 | pmu = tp_perf_event_init(event); |
| 4376 | break; | 4422 | break; |
| 4377 | 4423 | ||
| 4424 | case PERF_TYPE_BREAKPOINT: | ||
| 4425 | pmu = bp_perf_event_init(event); | ||
| 4426 | break; | ||
| 4427 | |||
| 4428 | |||
| 4378 | default: | 4429 | default: |
| 4379 | break; | 4430 | break; |
| 4380 | } | 4431 | } |
| @@ -4686,7 +4737,7 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu, | |||
| 4686 | 4737 | ||
| 4687 | ctx = find_get_context(pid, cpu); | 4738 | ctx = find_get_context(pid, cpu); |
| 4688 | if (IS_ERR(ctx)) | 4739 | if (IS_ERR(ctx)) |
| 4689 | return NULL ; | 4740 | return NULL; |
| 4690 | 4741 | ||
| 4691 | event = perf_event_alloc(attr, cpu, ctx, NULL, | 4742 | event = perf_event_alloc(attr, cpu, ctx, NULL, |
| 4692 | NULL, callback, GFP_KERNEL); | 4743 | NULL, callback, GFP_KERNEL); |
