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); |
