diff options
| -rw-r--r-- | include/linux/perf_event.h | 1 | ||||
| -rw-r--r-- | kernel/perf_event.c | 95 |
2 files changed, 95 insertions, 1 deletions
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 21206d27466b..dda5b0a3ff60 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h | |||
| @@ -588,6 +588,7 @@ struct perf_event; | |||
| 588 | struct pmu { | 588 | struct pmu { |
| 589 | struct list_head entry; | 589 | struct list_head entry; |
| 590 | 590 | ||
| 591 | struct device *dev; | ||
| 591 | char *name; | 592 | char *name; |
| 592 | int type; | 593 | int type; |
| 593 | 594 | ||
diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 8f09bc877a30..11847bf1e8cc 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include <linux/ptrace.h> | 24 | #include <linux/ptrace.h> |
| 25 | #include <linux/reboot.h> | 25 | #include <linux/reboot.h> |
| 26 | #include <linux/vmstat.h> | 26 | #include <linux/vmstat.h> |
| 27 | #include <linux/device.h> | ||
| 27 | #include <linux/vmalloc.h> | 28 | #include <linux/vmalloc.h> |
| 28 | #include <linux/hardirq.h> | 29 | #include <linux/hardirq.h> |
| 29 | #include <linux/rculist.h> | 30 | #include <linux/rculist.h> |
| @@ -5308,6 +5309,58 @@ out: | |||
| 5308 | } | 5309 | } |
| 5309 | static struct idr pmu_idr; | 5310 | static struct idr pmu_idr; |
| 5310 | 5311 | ||
| 5312 | static ssize_t | ||
| 5313 | type_show(struct device *dev, struct device_attribute *attr, char *page) | ||
| 5314 | { | ||
| 5315 | struct pmu *pmu = dev_get_drvdata(dev); | ||
| 5316 | |||
| 5317 | return snprintf(page, PAGE_SIZE-1, "%d\n", pmu->type); | ||
| 5318 | } | ||
| 5319 | |||
| 5320 | static struct device_attribute pmu_dev_attrs[] = { | ||
| 5321 | __ATTR_RO(type), | ||
| 5322 | __ATTR_NULL, | ||
| 5323 | }; | ||
| 5324 | |||
| 5325 | static int pmu_bus_running; | ||
| 5326 | static struct bus_type pmu_bus = { | ||
| 5327 | .name = "event_source", | ||
| 5328 | .dev_attrs = pmu_dev_attrs, | ||
| 5329 | }; | ||
| 5330 | |||
| 5331 | static void pmu_dev_release(struct device *dev) | ||
| 5332 | { | ||
| 5333 | kfree(dev); | ||
| 5334 | } | ||
| 5335 | |||
| 5336 | static int pmu_dev_alloc(struct pmu *pmu) | ||
| 5337 | { | ||
| 5338 | int ret = -ENOMEM; | ||
| 5339 | |||
| 5340 | pmu->dev = kzalloc(sizeof(struct device), GFP_KERNEL); | ||
| 5341 | if (!pmu->dev) | ||
| 5342 | goto out; | ||
| 5343 | |||
| 5344 | device_initialize(pmu->dev); | ||
| 5345 | ret = dev_set_name(pmu->dev, "%s", pmu->name); | ||
| 5346 | if (ret) | ||
| 5347 | goto free_dev; | ||
| 5348 | |||
| 5349 | dev_set_drvdata(pmu->dev, pmu); | ||
| 5350 | pmu->dev->bus = &pmu_bus; | ||
| 5351 | pmu->dev->release = pmu_dev_release; | ||
| 5352 | ret = device_add(pmu->dev); | ||
| 5353 | if (ret) | ||
| 5354 | goto free_dev; | ||
| 5355 | |||
| 5356 | out: | ||
| 5357 | return ret; | ||
| 5358 | |||
| 5359 | free_dev: | ||
| 5360 | put_device(pmu->dev); | ||
| 5361 | goto out; | ||
| 5362 | } | ||
| 5363 | |||
| 5311 | int perf_pmu_register(struct pmu *pmu, char *name, int type) | 5364 | int perf_pmu_register(struct pmu *pmu, char *name, int type) |
| 5312 | { | 5365 | { |
| 5313 | int cpu, ret; | 5366 | int cpu, ret; |
| @@ -5336,6 +5389,12 @@ int perf_pmu_register(struct pmu *pmu, char *name, int type) | |||
| 5336 | } | 5389 | } |
| 5337 | pmu->type = type; | 5390 | pmu->type = type; |
| 5338 | 5391 | ||
| 5392 | if (pmu_bus_running) { | ||
| 5393 | ret = pmu_dev_alloc(pmu); | ||
| 5394 | if (ret) | ||
| 5395 | goto free_idr; | ||
| 5396 | } | ||
| 5397 | |||
| 5339 | skip_type: | 5398 | skip_type: |
| 5340 | pmu->pmu_cpu_context = find_pmu_context(pmu->task_ctx_nr); | 5399 | pmu->pmu_cpu_context = find_pmu_context(pmu->task_ctx_nr); |
| 5341 | if (pmu->pmu_cpu_context) | 5400 | if (pmu->pmu_cpu_context) |
| @@ -5343,7 +5402,7 @@ skip_type: | |||
| 5343 | 5402 | ||
| 5344 | pmu->pmu_cpu_context = alloc_percpu(struct perf_cpu_context); | 5403 | pmu->pmu_cpu_context = alloc_percpu(struct perf_cpu_context); |
| 5345 | if (!pmu->pmu_cpu_context) | 5404 | if (!pmu->pmu_cpu_context) |
| 5346 | goto free_ird; | 5405 | goto free_dev; |
| 5347 | 5406 | ||
| 5348 | for_each_possible_cpu(cpu) { | 5407 | for_each_possible_cpu(cpu) { |
| 5349 | struct perf_cpu_context *cpuctx; | 5408 | struct perf_cpu_context *cpuctx; |
| @@ -5387,6 +5446,10 @@ unlock: | |||
| 5387 | 5446 | ||
| 5388 | return ret; | 5447 | return ret; |
| 5389 | 5448 | ||
| 5449 | free_dev: | ||
| 5450 | device_del(pmu->dev); | ||
| 5451 | put_device(pmu->dev); | ||
| 5452 | |||
| 5390 | free_idr: | 5453 | free_idr: |
| 5391 | if (pmu->type >= PERF_TYPE_MAX) | 5454 | if (pmu->type >= PERF_TYPE_MAX) |
| 5392 | idr_remove(&pmu_idr, pmu->type); | 5455 | idr_remove(&pmu_idr, pmu->type); |
| @@ -5412,6 +5475,8 @@ void perf_pmu_unregister(struct pmu *pmu) | |||
| 5412 | free_percpu(pmu->pmu_disable_count); | 5475 | free_percpu(pmu->pmu_disable_count); |
| 5413 | if (pmu->type >= PERF_TYPE_MAX) | 5476 | if (pmu->type >= PERF_TYPE_MAX) |
| 5414 | idr_remove(&pmu_idr, pmu->type); | 5477 | idr_remove(&pmu_idr, pmu->type); |
| 5478 | device_del(pmu->dev); | ||
| 5479 | put_device(pmu->dev); | ||
| 5415 | free_pmu_context(pmu); | 5480 | free_pmu_context(pmu); |
| 5416 | } | 5481 | } |
| 5417 | 5482 | ||
| @@ -6603,3 +6668,31 @@ void __init perf_event_init(void) | |||
| 6603 | ret = init_hw_breakpoint(); | 6668 | ret = init_hw_breakpoint(); |
| 6604 | WARN(ret, "hw_breakpoint initialization failed with: %d", ret); | 6669 | WARN(ret, "hw_breakpoint initialization failed with: %d", ret); |
| 6605 | } | 6670 | } |
| 6671 | |||
| 6672 | static int __init perf_event_sysfs_init(void) | ||
| 6673 | { | ||
| 6674 | struct pmu *pmu; | ||
| 6675 | int ret; | ||
| 6676 | |||
| 6677 | mutex_lock(&pmus_lock); | ||
| 6678 | |||
| 6679 | ret = bus_register(&pmu_bus); | ||
| 6680 | if (ret) | ||
| 6681 | goto unlock; | ||
| 6682 | |||
| 6683 | list_for_each_entry(pmu, &pmus, entry) { | ||
| 6684 | if (!pmu->name || pmu->type < 0) | ||
| 6685 | continue; | ||
| 6686 | |||
| 6687 | ret = pmu_dev_alloc(pmu); | ||
| 6688 | WARN(ret, "Failed to register pmu: %s, reason %d\n", pmu->name, ret); | ||
| 6689 | } | ||
| 6690 | pmu_bus_running = 1; | ||
| 6691 | ret = 0; | ||
| 6692 | |||
| 6693 | unlock: | ||
| 6694 | mutex_unlock(&pmus_lock); | ||
| 6695 | |||
| 6696 | return ret; | ||
| 6697 | } | ||
| 6698 | device_initcall(perf_event_sysfs_init); | ||
