diff options
| author | Mark Rutland <mark.rutland@arm.com> | 2011-04-28 10:47:10 -0400 |
|---|---|---|
| committer | Will Deacon <will.deacon@arm.com> | 2011-08-31 05:50:09 -0400 |
| commit | e1f431b57ef9e4a68281540933fa74865cbb7a74 (patch) | |
| tree | 895e018faee0a504c82c02b69a8784433c3a057e | |
| parent | 7ae18a5717cbbf1879bdd5b66d7009a9958e5aef (diff) | |
ARM: perf: refactor event mapping
Currently mapping an event type to a hardware configuration value
depends on the data being pointed to from struct arm_pmu. These fields
(cache_map, event_map, raw_event_mask) are currently specific to CPU
PMUs, and do not serve the general case well.
This patch replaces the event map pointers on struct arm_pmu with a new
'map_event' function pointer. Small shim functions are used to reuse
the existing common code.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Reviewed-by: Will Deacon <will.deacon@arm.com>
Reviewed-by: Jamie Iles <jamie@jamieiles.com>
Reviewed-by: Ashwin Chaugule <ashwinc@codeaurora.org>
Signed-off-by: Will Deacon <will.deacon@arm.com>
| -rw-r--r-- | arch/arm/kernel/perf_event.c | 67 | ||||
| -rw-r--r-- | arch/arm/kernel/perf_event_v6.c | 21 | ||||
| -rw-r--r-- | arch/arm/kernel/perf_event_v7.c | 37 | ||||
| -rw-r--r-- | arch/arm/kernel/perf_event_xscale.c | 14 |
4 files changed, 87 insertions, 52 deletions
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index 1a2ebbf07fb7..b13bf23ceba3 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c | |||
| @@ -75,11 +75,7 @@ struct arm_pmu { | |||
| 75 | void (*start)(void); | 75 | void (*start)(void); |
| 76 | void (*stop)(void); | 76 | void (*stop)(void); |
| 77 | void (*reset)(void *); | 77 | void (*reset)(void *); |
| 78 | const unsigned (*cache_map)[PERF_COUNT_HW_CACHE_MAX] | 78 | int (*map_event)(struct perf_event *event); |
| 79 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
| 80 | [PERF_COUNT_HW_CACHE_RESULT_MAX]; | ||
| 81 | const unsigned (*event_map)[PERF_COUNT_HW_MAX]; | ||
| 82 | u32 raw_event_mask; | ||
| 83 | int num_events; | 79 | int num_events; |
| 84 | atomic_t active_events; | 80 | atomic_t active_events; |
| 85 | struct mutex reserve_mutex; | 81 | struct mutex reserve_mutex; |
| @@ -129,7 +125,11 @@ EXPORT_SYMBOL_GPL(perf_num_counters); | |||
| 129 | #define CACHE_OP_UNSUPPORTED 0xFFFF | 125 | #define CACHE_OP_UNSUPPORTED 0xFFFF |
| 130 | 126 | ||
| 131 | static int | 127 | static int |
| 132 | armpmu_map_cache_event(u64 config) | 128 | armpmu_map_cache_event(const unsigned (*cache_map) |
| 129 | [PERF_COUNT_HW_CACHE_MAX] | ||
| 130 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
| 131 | [PERF_COUNT_HW_CACHE_RESULT_MAX], | ||
| 132 | u64 config) | ||
| 133 | { | 133 | { |
| 134 | unsigned int cache_type, cache_op, cache_result, ret; | 134 | unsigned int cache_type, cache_op, cache_result, ret; |
| 135 | 135 | ||
| @@ -145,7 +145,7 @@ armpmu_map_cache_event(u64 config) | |||
| 145 | if (cache_result >= PERF_COUNT_HW_CACHE_RESULT_MAX) | 145 | if (cache_result >= PERF_COUNT_HW_CACHE_RESULT_MAX) |
| 146 | return -EINVAL; | 146 | return -EINVAL; |
| 147 | 147 | ||
| 148 | ret = (int)(*armpmu->cache_map)[cache_type][cache_op][cache_result]; | 148 | ret = (int)(*cache_map)[cache_type][cache_op][cache_result]; |
| 149 | 149 | ||
| 150 | if (ret == CACHE_OP_UNSUPPORTED) | 150 | if (ret == CACHE_OP_UNSUPPORTED) |
| 151 | return -ENOENT; | 151 | return -ENOENT; |
| @@ -154,16 +154,38 @@ armpmu_map_cache_event(u64 config) | |||
| 154 | } | 154 | } |
| 155 | 155 | ||
| 156 | static int | 156 | static int |
| 157 | armpmu_map_event(u64 config) | 157 | armpmu_map_event(const unsigned (*event_map)[PERF_COUNT_HW_MAX], u64 config) |
| 158 | { | 158 | { |
| 159 | int mapping = (*armpmu->event_map)[config]; | 159 | int mapping = (*event_map)[config]; |
| 160 | return mapping == HW_OP_UNSUPPORTED ? -EOPNOTSUPP : mapping; | 160 | return mapping == HW_OP_UNSUPPORTED ? -ENOENT : mapping; |
| 161 | } | 161 | } |
| 162 | 162 | ||
| 163 | static int | 163 | static int |
| 164 | armpmu_map_raw_event(u64 config) | 164 | armpmu_map_raw_event(u32 raw_event_mask, u64 config) |
| 165 | { | 165 | { |
| 166 | return (int)(config & armpmu->raw_event_mask); | 166 | return (int)(config & raw_event_mask); |
| 167 | } | ||
| 168 | |||
| 169 | static int map_cpu_event(struct perf_event *event, | ||
| 170 | const unsigned (*event_map)[PERF_COUNT_HW_MAX], | ||
| 171 | const unsigned (*cache_map) | ||
| 172 | [PERF_COUNT_HW_CACHE_MAX] | ||
| 173 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
| 174 | [PERF_COUNT_HW_CACHE_RESULT_MAX], | ||
| 175 | u32 raw_event_mask) | ||
| 176 | { | ||
| 177 | u64 config = event->attr.config; | ||
| 178 | |||
| 179 | switch (event->attr.type) { | ||
| 180 | case PERF_TYPE_HARDWARE: | ||
| 181 | return armpmu_map_event(event_map, config); | ||
| 182 | case PERF_TYPE_HW_CACHE: | ||
| 183 | return armpmu_map_cache_event(cache_map, config); | ||
| 184 | case PERF_TYPE_RAW: | ||
| 185 | return armpmu_map_raw_event(raw_event_mask, config); | ||
| 186 | } | ||
| 187 | |||
| 188 | return -ENOENT; | ||
| 167 | } | 189 | } |
| 168 | 190 | ||
| 169 | static int | 191 | static int |
| @@ -484,17 +506,7 @@ __hw_perf_event_init(struct perf_event *event) | |||
| 484 | struct hw_perf_event *hwc = &event->hw; | 506 | struct hw_perf_event *hwc = &event->hw; |
| 485 | int mapping, err; | 507 | int mapping, err; |
| 486 | 508 | ||
| 487 | /* Decode the generic type into an ARM event identifier. */ | 509 | mapping = armpmu->map_event(event); |
| 488 | if (PERF_TYPE_HARDWARE == event->attr.type) { | ||
| 489 | mapping = armpmu_map_event(event->attr.config); | ||
| 490 | } else if (PERF_TYPE_HW_CACHE == event->attr.type) { | ||
| 491 | mapping = armpmu_map_cache_event(event->attr.config); | ||
| 492 | } else if (PERF_TYPE_RAW == event->attr.type) { | ||
| 493 | mapping = armpmu_map_raw_event(event->attr.config); | ||
| 494 | } else { | ||
| 495 | pr_debug("event type %x not supported\n", event->attr.type); | ||
| 496 | return -EOPNOTSUPP; | ||
| 497 | } | ||
| 498 | 510 | ||
| 499 | if (mapping < 0) { | 511 | if (mapping < 0) { |
| 500 | pr_debug("event %x:%llx not supported\n", event->attr.type, | 512 | pr_debug("event %x:%llx not supported\n", event->attr.type, |
| @@ -550,15 +562,8 @@ static int armpmu_event_init(struct perf_event *event) | |||
| 550 | int err = 0; | 562 | int err = 0; |
| 551 | atomic_t *active_events = &armpmu->active_events; | 563 | atomic_t *active_events = &armpmu->active_events; |
| 552 | 564 | ||
| 553 | switch (event->attr.type) { | 565 | if (armpmu->map_event(event) == -ENOENT) |
| 554 | case PERF_TYPE_RAW: | ||
| 555 | case PERF_TYPE_HARDWARE: | ||
| 556 | case PERF_TYPE_HW_CACHE: | ||
| 557 | break; | ||
| 558 | |||
| 559 | default: | ||
| 560 | return -ENOENT; | 566 | return -ENOENT; |
| 561 | } | ||
| 562 | 567 | ||
| 563 | event->destroy = hw_perf_event_destroy; | 568 | event->destroy = hw_perf_event_destroy; |
| 564 | 569 | ||
diff --git a/arch/arm/kernel/perf_event_v6.c b/arch/arm/kernel/perf_event_v6.c index 68cf70425f2f..a4c5aa9baa44 100644 --- a/arch/arm/kernel/perf_event_v6.c +++ b/arch/arm/kernel/perf_event_v6.c | |||
| @@ -657,6 +657,12 @@ armv6mpcore_pmu_disable_event(struct hw_perf_event *hwc, | |||
| 657 | raw_spin_unlock_irqrestore(&events->pmu_lock, flags); | 657 | raw_spin_unlock_irqrestore(&events->pmu_lock, flags); |
| 658 | } | 658 | } |
| 659 | 659 | ||
| 660 | static int armv6_map_event(struct perf_event *event) | ||
| 661 | { | ||
| 662 | return map_cpu_event(event, &armv6_perf_map, | ||
| 663 | &armv6_perf_cache_map, 0xFF); | ||
| 664 | } | ||
| 665 | |||
| 660 | static struct arm_pmu armv6pmu = { | 666 | static struct arm_pmu armv6pmu = { |
| 661 | .id = ARM_PERF_PMU_ID_V6, | 667 | .id = ARM_PERF_PMU_ID_V6, |
| 662 | .name = "v6", | 668 | .name = "v6", |
| @@ -668,9 +674,7 @@ static struct arm_pmu armv6pmu = { | |||
| 668 | .get_event_idx = armv6pmu_get_event_idx, | 674 | .get_event_idx = armv6pmu_get_event_idx, |
| 669 | .start = armv6pmu_start, | 675 | .start = armv6pmu_start, |
| 670 | .stop = armv6pmu_stop, | 676 | .stop = armv6pmu_stop, |
| 671 | .cache_map = &armv6_perf_cache_map, | 677 | .map_event = armv6_map_event, |
| 672 | .event_map = &armv6_perf_map, | ||
| 673 | .raw_event_mask = 0xFF, | ||
| 674 | .num_events = 3, | 678 | .num_events = 3, |
| 675 | .max_period = (1LLU << 32) - 1, | 679 | .max_period = (1LLU << 32) - 1, |
| 676 | }; | 680 | }; |
| @@ -687,6 +691,13 @@ static struct arm_pmu *__init armv6pmu_init(void) | |||
| 687 | * disable the interrupt reporting and update the event. When unthrottling we | 691 | * disable the interrupt reporting and update the event. When unthrottling we |
| 688 | * reset the period and enable the interrupt reporting. | 692 | * reset the period and enable the interrupt reporting. |
| 689 | */ | 693 | */ |
| 694 | |||
| 695 | static int armv6mpcore_map_event(struct perf_event *event) | ||
| 696 | { | ||
| 697 | return map_cpu_event(event, &armv6mpcore_perf_map, | ||
| 698 | &armv6mpcore_perf_cache_map, 0xFF); | ||
| 699 | } | ||
| 700 | |||
| 690 | static struct arm_pmu armv6mpcore_pmu = { | 701 | static struct arm_pmu armv6mpcore_pmu = { |
| 691 | .id = ARM_PERF_PMU_ID_V6MP, | 702 | .id = ARM_PERF_PMU_ID_V6MP, |
| 692 | .name = "v6mpcore", | 703 | .name = "v6mpcore", |
| @@ -698,9 +709,7 @@ static struct arm_pmu armv6mpcore_pmu = { | |||
| 698 | .get_event_idx = armv6pmu_get_event_idx, | 709 | .get_event_idx = armv6pmu_get_event_idx, |
| 699 | .start = armv6pmu_start, | 710 | .start = armv6pmu_start, |
| 700 | .stop = armv6pmu_stop, | 711 | .stop = armv6pmu_stop, |
| 701 | .cache_map = &armv6mpcore_perf_cache_map, | 712 | .map_event = armv6mpcore_map_event, |
| 702 | .event_map = &armv6mpcore_perf_map, | ||
| 703 | .raw_event_mask = 0xFF, | ||
| 704 | .num_events = 3, | 713 | .num_events = 3, |
| 705 | .max_period = (1LLU << 32) - 1, | 714 | .max_period = (1LLU << 32) - 1, |
| 706 | }; | 715 | }; |
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c index 68ac522fd940..be7b58a2cc6f 100644 --- a/arch/arm/kernel/perf_event_v7.c +++ b/arch/arm/kernel/perf_event_v7.c | |||
| @@ -1140,6 +1140,30 @@ static void armv7pmu_reset(void *info) | |||
| 1140 | armv7_pmnc_write(ARMV7_PMNC_P | ARMV7_PMNC_C); | 1140 | armv7_pmnc_write(ARMV7_PMNC_P | ARMV7_PMNC_C); |
| 1141 | } | 1141 | } |
| 1142 | 1142 | ||
| 1143 | static int armv7_a8_map_event(struct perf_event *event) | ||
| 1144 | { | ||
| 1145 | return map_cpu_event(event, &armv7_a8_perf_map, | ||
| 1146 | &armv7_a8_perf_cache_map, 0xFF); | ||
| 1147 | } | ||
| 1148 | |||
| 1149 | static int armv7_a9_map_event(struct perf_event *event) | ||
| 1150 | { | ||
| 1151 | return map_cpu_event(event, &armv7_a9_perf_map, | ||
| 1152 | &armv7_a9_perf_cache_map, 0xFF); | ||
| 1153 | } | ||
| 1154 | |||
| 1155 | static int armv7_a5_map_event(struct perf_event *event) | ||
| 1156 | { | ||
| 1157 | return map_cpu_event(event, &armv7_a5_perf_map, | ||
| 1158 | &armv7_a5_perf_cache_map, 0xFF); | ||
| 1159 | } | ||
| 1160 | |||
| 1161 | static int armv7_a15_map_event(struct perf_event *event) | ||
| 1162 | { | ||
| 1163 | return map_cpu_event(event, &armv7_a15_perf_map, | ||
| 1164 | &armv7_a15_perf_cache_map, 0xFF); | ||
| 1165 | } | ||
| 1166 | |||
| 1143 | static struct arm_pmu armv7pmu = { | 1167 | static struct arm_pmu armv7pmu = { |
| 1144 | .handle_irq = armv7pmu_handle_irq, | 1168 | .handle_irq = armv7pmu_handle_irq, |
| 1145 | .enable = armv7pmu_enable_event, | 1169 | .enable = armv7pmu_enable_event, |
| @@ -1150,7 +1174,6 @@ static struct arm_pmu armv7pmu = { | |||
| 1150 | .start = armv7pmu_start, | 1174 | .start = armv7pmu_start, |
| 1151 | .stop = armv7pmu_stop, | 1175 | .stop = armv7pmu_stop, |
| 1152 | .reset = armv7pmu_reset, | 1176 | .reset = armv7pmu_reset, |
| 1153 | .raw_event_mask = 0xFF, | ||
| 1154 | .max_period = (1LLU << 32) - 1, | 1177 | .max_period = (1LLU << 32) - 1, |
| 1155 | }; | 1178 | }; |
| 1156 | 1179 | ||
| @@ -1169,8 +1192,7 @@ static struct arm_pmu *__init armv7_a8_pmu_init(void) | |||
| 1169 | { | 1192 | { |
| 1170 | armv7pmu.id = ARM_PERF_PMU_ID_CA8; | 1193 | armv7pmu.id = ARM_PERF_PMU_ID_CA8; |
| 1171 | armv7pmu.name = "ARMv7 Cortex-A8"; | 1194 | armv7pmu.name = "ARMv7 Cortex-A8"; |
| 1172 | armv7pmu.cache_map = &armv7_a8_perf_cache_map; | 1195 | armv7pmu.map_event = armv7_a8_map_event; |
| 1173 | armv7pmu.event_map = &armv7_a8_perf_map; | ||
| 1174 | armv7pmu.num_events = armv7_read_num_pmnc_events(); | 1196 | armv7pmu.num_events = armv7_read_num_pmnc_events(); |
| 1175 | return &armv7pmu; | 1197 | return &armv7pmu; |
| 1176 | } | 1198 | } |
| @@ -1179,8 +1201,7 @@ static struct arm_pmu *__init armv7_a9_pmu_init(void) | |||
| 1179 | { | 1201 | { |
| 1180 | armv7pmu.id = ARM_PERF_PMU_ID_CA9; | 1202 | armv7pmu.id = ARM_PERF_PMU_ID_CA9; |
| 1181 | armv7pmu.name = "ARMv7 Cortex-A9"; | 1203 | armv7pmu.name = "ARMv7 Cortex-A9"; |
| 1182 | armv7pmu.cache_map = &armv7_a9_perf_cache_map; | 1204 | armv7pmu.map_event = armv7_a9_map_event; |
| 1183 | armv7pmu.event_map = &armv7_a9_perf_map; | ||
| 1184 | armv7pmu.num_events = armv7_read_num_pmnc_events(); | 1205 | armv7pmu.num_events = armv7_read_num_pmnc_events(); |
| 1185 | return &armv7pmu; | 1206 | return &armv7pmu; |
| 1186 | } | 1207 | } |
| @@ -1189,8 +1210,7 @@ static struct arm_pmu *__init armv7_a5_pmu_init(void) | |||
| 1189 | { | 1210 | { |
| 1190 | armv7pmu.id = ARM_PERF_PMU_ID_CA5; | 1211 | armv7pmu.id = ARM_PERF_PMU_ID_CA5; |
| 1191 | armv7pmu.name = "ARMv7 Cortex-A5"; | 1212 | armv7pmu.name = "ARMv7 Cortex-A5"; |
| 1192 | armv7pmu.cache_map = &armv7_a5_perf_cache_map; | 1213 | armv7pmu.map_event = armv7_a5_map_event; |
| 1193 | armv7pmu.event_map = &armv7_a5_perf_map; | ||
| 1194 | armv7pmu.num_events = armv7_read_num_pmnc_events(); | 1214 | armv7pmu.num_events = armv7_read_num_pmnc_events(); |
| 1195 | return &armv7pmu; | 1215 | return &armv7pmu; |
| 1196 | } | 1216 | } |
| @@ -1199,8 +1219,7 @@ static struct arm_pmu *__init armv7_a15_pmu_init(void) | |||
| 1199 | { | 1219 | { |
| 1200 | armv7pmu.id = ARM_PERF_PMU_ID_CA15; | 1220 | armv7pmu.id = ARM_PERF_PMU_ID_CA15; |
| 1201 | armv7pmu.name = "ARMv7 Cortex-A15"; | 1221 | armv7pmu.name = "ARMv7 Cortex-A15"; |
| 1202 | armv7pmu.cache_map = &armv7_a15_perf_cache_map; | 1222 | armv7pmu.map_event = armv7_a15_map_event; |
| 1203 | armv7pmu.event_map = &armv7_a15_perf_map; | ||
| 1204 | armv7pmu.num_events = armv7_read_num_pmnc_events(); | 1223 | armv7pmu.num_events = armv7_read_num_pmnc_events(); |
| 1205 | armv7pmu.set_event_filter = armv7pmu_set_event_filter; | 1224 | armv7pmu.set_event_filter = armv7pmu_set_event_filter; |
| 1206 | return &armv7pmu; | 1225 | return &armv7pmu; |
diff --git a/arch/arm/kernel/perf_event_xscale.c b/arch/arm/kernel/perf_event_xscale.c index 18e4823a0a62..d4c7610d25b9 100644 --- a/arch/arm/kernel/perf_event_xscale.c +++ b/arch/arm/kernel/perf_event_xscale.c | |||
| @@ -425,6 +425,12 @@ xscale1pmu_write_counter(int counter, u32 val) | |||
| 425 | } | 425 | } |
| 426 | } | 426 | } |
| 427 | 427 | ||
| 428 | static int xscale_map_event(struct perf_event *event) | ||
| 429 | { | ||
| 430 | return map_cpu_event(event, &xscale_perf_map, | ||
| 431 | &xscale_perf_cache_map, 0xFF); | ||
| 432 | } | ||
| 433 | |||
| 428 | static struct arm_pmu xscale1pmu = { | 434 | static struct arm_pmu xscale1pmu = { |
| 429 | .id = ARM_PERF_PMU_ID_XSCALE1, | 435 | .id = ARM_PERF_PMU_ID_XSCALE1, |
| 430 | .name = "xscale1", | 436 | .name = "xscale1", |
| @@ -436,9 +442,7 @@ static struct arm_pmu xscale1pmu = { | |||
| 436 | .get_event_idx = xscale1pmu_get_event_idx, | 442 | .get_event_idx = xscale1pmu_get_event_idx, |
| 437 | .start = xscale1pmu_start, | 443 | .start = xscale1pmu_start, |
| 438 | .stop = xscale1pmu_stop, | 444 | .stop = xscale1pmu_stop, |
| 439 | .cache_map = &xscale_perf_cache_map, | 445 | .map_event = xscale_map_event, |
| 440 | .event_map = &xscale_perf_map, | ||
| 441 | .raw_event_mask = 0xFF, | ||
| 442 | .num_events = 3, | 446 | .num_events = 3, |
| 443 | .max_period = (1LLU << 32) - 1, | 447 | .max_period = (1LLU << 32) - 1, |
| 444 | }; | 448 | }; |
| @@ -799,9 +803,7 @@ static struct arm_pmu xscale2pmu = { | |||
| 799 | .get_event_idx = xscale2pmu_get_event_idx, | 803 | .get_event_idx = xscale2pmu_get_event_idx, |
| 800 | .start = xscale2pmu_start, | 804 | .start = xscale2pmu_start, |
| 801 | .stop = xscale2pmu_stop, | 805 | .stop = xscale2pmu_stop, |
| 802 | .cache_map = &xscale_perf_cache_map, | 806 | .map_event = xscale_map_event, |
| 803 | .event_map = &xscale_perf_map, | ||
| 804 | .raw_event_mask = 0xFF, | ||
| 805 | .num_events = 5, | 807 | .num_events = 5, |
| 806 | .max_period = (1LLU << 32) - 1, | 808 | .max_period = (1LLU << 32) - 1, |
| 807 | }; | 809 | }; |
