diff options
Diffstat (limited to 'arch/arm/kernel/pmu.c')
-rw-r--r-- | arch/arm/kernel/pmu.c | 87 |
1 files changed, 70 insertions, 17 deletions
diff --git a/arch/arm/kernel/pmu.c b/arch/arm/kernel/pmu.c index 2c79eec19262..2b70709376c3 100644 --- a/arch/arm/kernel/pmu.c +++ b/arch/arm/kernel/pmu.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/of_device.h> | ||
20 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
21 | 22 | ||
22 | #include <asm/pmu.h> | 23 | #include <asm/pmu.h> |
@@ -25,36 +26,88 @@ static volatile long pmu_lock; | |||
25 | 26 | ||
26 | static struct platform_device *pmu_devices[ARM_NUM_PMU_DEVICES]; | 27 | static struct platform_device *pmu_devices[ARM_NUM_PMU_DEVICES]; |
27 | 28 | ||
28 | static int __devinit pmu_device_probe(struct platform_device *pdev) | 29 | static int __devinit pmu_register(struct platform_device *pdev, |
30 | enum arm_pmu_type type) | ||
29 | { | 31 | { |
30 | 32 | if (type < 0 || type >= ARM_NUM_PMU_DEVICES) { | |
31 | if (pdev->id < 0 || pdev->id >= ARM_NUM_PMU_DEVICES) { | ||
32 | pr_warning("received registration request for unknown " | 33 | pr_warning("received registration request for unknown " |
33 | "device %d\n", pdev->id); | 34 | "device %d\n", type); |
34 | return -EINVAL; | 35 | return -EINVAL; |
35 | } | 36 | } |
36 | 37 | ||
37 | if (pmu_devices[pdev->id]) | 38 | if (pmu_devices[type]) { |
38 | pr_warning("registering new PMU device type %d overwrites " | 39 | pr_warning("rejecting duplicate registration of PMU device " |
39 | "previous registration!\n", pdev->id); | 40 | "type %d.", type); |
40 | else | 41 | return -ENOSPC; |
41 | pr_info("registered new PMU device of type %d\n", | 42 | } |
42 | pdev->id); | ||
43 | 43 | ||
44 | pmu_devices[pdev->id] = pdev; | 44 | pr_info("registered new PMU device of type %d\n", type); |
45 | pmu_devices[type] = pdev; | ||
45 | return 0; | 46 | return 0; |
46 | } | 47 | } |
47 | 48 | ||
48 | static struct platform_driver pmu_driver = { | 49 | #define OF_MATCH_PMU(_name, _type) { \ |
50 | .compatible = _name, \ | ||
51 | .data = (void *)_type, \ | ||
52 | } | ||
53 | |||
54 | #define OF_MATCH_CPU(name) OF_MATCH_PMU(name, ARM_PMU_DEVICE_CPU) | ||
55 | |||
56 | static struct of_device_id armpmu_of_device_ids[] = { | ||
57 | OF_MATCH_CPU("arm,cortex-a9-pmu"), | ||
58 | OF_MATCH_CPU("arm,cortex-a8-pmu"), | ||
59 | OF_MATCH_CPU("arm,arm1136-pmu"), | ||
60 | OF_MATCH_CPU("arm,arm1176-pmu"), | ||
61 | {}, | ||
62 | }; | ||
63 | |||
64 | #define PLAT_MATCH_PMU(_name, _type) { \ | ||
65 | .name = _name, \ | ||
66 | .driver_data = _type, \ | ||
67 | } | ||
68 | |||
69 | #define PLAT_MATCH_CPU(_name) PLAT_MATCH_PMU(_name, ARM_PMU_DEVICE_CPU) | ||
70 | |||
71 | static struct platform_device_id armpmu_plat_device_ids[] = { | ||
72 | PLAT_MATCH_CPU("arm-pmu"), | ||
73 | {}, | ||
74 | }; | ||
75 | |||
76 | enum arm_pmu_type armpmu_device_type(struct platform_device *pdev) | ||
77 | { | ||
78 | const struct of_device_id *of_id; | ||
79 | const struct platform_device_id *pdev_id; | ||
80 | |||
81 | /* provided by of_device_id table */ | ||
82 | if (pdev->dev.of_node) { | ||
83 | of_id = of_match_device(armpmu_of_device_ids, &pdev->dev); | ||
84 | BUG_ON(!of_id); | ||
85 | return (enum arm_pmu_type)of_id->data; | ||
86 | } | ||
87 | |||
88 | /* Provided by platform_device_id table */ | ||
89 | pdev_id = platform_get_device_id(pdev); | ||
90 | BUG_ON(!pdev_id); | ||
91 | return pdev_id->driver_data; | ||
92 | } | ||
93 | |||
94 | static int __devinit armpmu_device_probe(struct platform_device *pdev) | ||
95 | { | ||
96 | return pmu_register(pdev, armpmu_device_type(pdev)); | ||
97 | } | ||
98 | |||
99 | static struct platform_driver armpmu_driver = { | ||
49 | .driver = { | 100 | .driver = { |
50 | .name = "arm-pmu", | 101 | .name = "arm-pmu", |
102 | .of_match_table = armpmu_of_device_ids, | ||
51 | }, | 103 | }, |
52 | .probe = pmu_device_probe, | 104 | .probe = armpmu_device_probe, |
105 | .id_table = armpmu_plat_device_ids, | ||
53 | }; | 106 | }; |
54 | 107 | ||
55 | static int __init register_pmu_driver(void) | 108 | static int __init register_pmu_driver(void) |
56 | { | 109 | { |
57 | return platform_driver_register(&pmu_driver); | 110 | return platform_driver_register(&armpmu_driver); |
58 | } | 111 | } |
59 | device_initcall(register_pmu_driver); | 112 | device_initcall(register_pmu_driver); |
60 | 113 | ||
@@ -77,11 +130,11 @@ reserve_pmu(enum arm_pmu_type device) | |||
77 | EXPORT_SYMBOL_GPL(reserve_pmu); | 130 | EXPORT_SYMBOL_GPL(reserve_pmu); |
78 | 131 | ||
79 | int | 132 | int |
80 | release_pmu(struct platform_device *pdev) | 133 | release_pmu(enum arm_pmu_type device) |
81 | { | 134 | { |
82 | if (WARN_ON(pdev != pmu_devices[pdev->id])) | 135 | if (WARN_ON(!pmu_devices[device])) |
83 | return -EINVAL; | 136 | return -EINVAL; |
84 | clear_bit_unlock(pdev->id, &pmu_lock); | 137 | clear_bit_unlock(device, &pmu_lock); |
85 | return 0; | 138 | return 0; |
86 | } | 139 | } |
87 | EXPORT_SYMBOL_GPL(release_pmu); | 140 | EXPORT_SYMBOL_GPL(release_pmu); |