diff options
| -rw-r--r-- | arch/sparc/kernel/perf_event.c | 145 |
1 files changed, 139 insertions, 6 deletions
diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c index 2d6a1b10c81d..48375f694673 100644 --- a/arch/sparc/kernel/perf_event.c +++ b/arch/sparc/kernel/perf_event.c | |||
| @@ -68,8 +68,19 @@ struct perf_event_map { | |||
| 68 | #define PIC_LOWER 0x02 | 68 | #define PIC_LOWER 0x02 |
| 69 | }; | 69 | }; |
| 70 | 70 | ||
| 71 | #define C(x) PERF_COUNT_HW_CACHE_##x | ||
| 72 | |||
| 73 | #define CACHE_OP_UNSUPPORTED 0xfffe | ||
| 74 | #define CACHE_OP_NONSENSE 0xffff | ||
| 75 | |||
| 76 | typedef struct perf_event_map cache_map_t | ||
| 77 | [PERF_COUNT_HW_CACHE_MAX] | ||
| 78 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
| 79 | [PERF_COUNT_HW_CACHE_RESULT_MAX]; | ||
| 80 | |||
| 71 | struct sparc_pmu { | 81 | struct sparc_pmu { |
| 72 | const struct perf_event_map *(*event_map)(int); | 82 | const struct perf_event_map *(*event_map)(int); |
| 83 | const cache_map_t *cache_map; | ||
| 73 | int max_events; | 84 | int max_events; |
| 74 | int upper_shift; | 85 | int upper_shift; |
| 75 | int lower_shift; | 86 | int lower_shift; |
| @@ -92,8 +103,96 @@ static const struct perf_event_map *ultra3i_event_map(int event_id) | |||
| 92 | return &ultra3i_perfmon_event_map[event_id]; | 103 | return &ultra3i_perfmon_event_map[event_id]; |
| 93 | } | 104 | } |
| 94 | 105 | ||
| 106 | static const cache_map_t ultra3i_cache_map = { | ||
| 107 | [C(L1D)] = { | ||
| 108 | [C(OP_READ)] = { | ||
| 109 | [C(RESULT_ACCESS)] = { 0x09, PIC_LOWER, }, | ||
| 110 | [C(RESULT_MISS)] = { 0x09, PIC_UPPER, }, | ||
| 111 | }, | ||
| 112 | [C(OP_WRITE)] = { | ||
| 113 | [C(RESULT_ACCESS)] = { 0x0a, PIC_LOWER }, | ||
| 114 | [C(RESULT_MISS)] = { 0x0a, PIC_UPPER }, | ||
| 115 | }, | ||
| 116 | [C(OP_PREFETCH)] = { | ||
| 117 | [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED }, | ||
| 118 | [C(RESULT_MISS)] = { CACHE_OP_UNSUPPORTED }, | ||
| 119 | }, | ||
| 120 | }, | ||
| 121 | [C(L1I)] = { | ||
| 122 | [C(OP_READ)] = { | ||
| 123 | [C(RESULT_ACCESS)] = { 0x09, PIC_LOWER, }, | ||
| 124 | [C(RESULT_MISS)] = { 0x09, PIC_UPPER, }, | ||
| 125 | }, | ||
| 126 | [ C(OP_WRITE) ] = { | ||
| 127 | [ C(RESULT_ACCESS) ] = { CACHE_OP_NONSENSE }, | ||
| 128 | [ C(RESULT_MISS) ] = { CACHE_OP_NONSENSE }, | ||
| 129 | }, | ||
| 130 | [ C(OP_PREFETCH) ] = { | ||
| 131 | [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED }, | ||
| 132 | [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED }, | ||
| 133 | }, | ||
| 134 | }, | ||
| 135 | [C(LL)] = { | ||
| 136 | [C(OP_READ)] = { | ||
| 137 | [C(RESULT_ACCESS)] = { 0x0c, PIC_LOWER, }, | ||
| 138 | [C(RESULT_MISS)] = { 0x0c, PIC_UPPER, }, | ||
| 139 | }, | ||
| 140 | [C(OP_WRITE)] = { | ||
| 141 | [C(RESULT_ACCESS)] = { 0x0c, PIC_LOWER }, | ||
| 142 | [C(RESULT_MISS)] = { 0x0c, PIC_UPPER }, | ||
| 143 | }, | ||
| 144 | [C(OP_PREFETCH)] = { | ||
| 145 | [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED }, | ||
| 146 | [C(RESULT_MISS)] = { CACHE_OP_UNSUPPORTED }, | ||
| 147 | }, | ||
| 148 | }, | ||
| 149 | [C(DTLB)] = { | ||
| 150 | [C(OP_READ)] = { | ||
| 151 | [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED }, | ||
| 152 | [C(RESULT_MISS)] = { 0x12, PIC_UPPER, }, | ||
| 153 | }, | ||
| 154 | [ C(OP_WRITE) ] = { | ||
| 155 | [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED }, | ||
| 156 | [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED }, | ||
| 157 | }, | ||
| 158 | [ C(OP_PREFETCH) ] = { | ||
| 159 | [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED }, | ||
| 160 | [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED }, | ||
| 161 | }, | ||
| 162 | }, | ||
| 163 | [C(ITLB)] = { | ||
| 164 | [C(OP_READ)] = { | ||
| 165 | [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED }, | ||
| 166 | [C(RESULT_MISS)] = { 0x11, PIC_UPPER, }, | ||
| 167 | }, | ||
| 168 | [ C(OP_WRITE) ] = { | ||
| 169 | [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED }, | ||
| 170 | [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED }, | ||
| 171 | }, | ||
| 172 | [ C(OP_PREFETCH) ] = { | ||
| 173 | [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED }, | ||
| 174 | [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED }, | ||
| 175 | }, | ||
| 176 | }, | ||
| 177 | [C(BPU)] = { | ||
| 178 | [C(OP_READ)] = { | ||
| 179 | [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED }, | ||
| 180 | [C(RESULT_MISS)] = { CACHE_OP_UNSUPPORTED }, | ||
| 181 | }, | ||
| 182 | [ C(OP_WRITE) ] = { | ||
| 183 | [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED }, | ||
| 184 | [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED }, | ||
| 185 | }, | ||
| 186 | [ C(OP_PREFETCH) ] = { | ||
| 187 | [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED }, | ||
| 188 | [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED }, | ||
| 189 | }, | ||
| 190 | }, | ||
| 191 | }; | ||
| 192 | |||
| 95 | static const struct sparc_pmu ultra3i_pmu = { | 193 | static const struct sparc_pmu ultra3i_pmu = { |
| 96 | .event_map = ultra3i_event_map, | 194 | .event_map = ultra3i_event_map, |
| 195 | .cache_map = &ultra3i_cache_map, | ||
| 97 | .max_events = ARRAY_SIZE(ultra3i_perfmon_event_map), | 196 | .max_events = ARRAY_SIZE(ultra3i_perfmon_event_map), |
| 98 | .upper_shift = 11, | 197 | .upper_shift = 11, |
| 99 | .lower_shift = 4, | 198 | .lower_shift = 4, |
| @@ -375,6 +474,37 @@ void perf_event_release_pmc(void) | |||
| 375 | } | 474 | } |
| 376 | } | 475 | } |
| 377 | 476 | ||
| 477 | static const struct perf_event_map *sparc_map_cache_event(u64 config) | ||
| 478 | { | ||
| 479 | unsigned int cache_type, cache_op, cache_result; | ||
| 480 | const struct perf_event_map *pmap; | ||
| 481 | |||
| 482 | if (!sparc_pmu->cache_map) | ||
| 483 | return ERR_PTR(-ENOENT); | ||
| 484 | |||
| 485 | cache_type = (config >> 0) & 0xff; | ||
| 486 | if (cache_type >= PERF_COUNT_HW_CACHE_MAX) | ||
| 487 | return ERR_PTR(-EINVAL); | ||
| 488 | |||
| 489 | cache_op = (config >> 8) & 0xff; | ||
| 490 | if (cache_op >= PERF_COUNT_HW_CACHE_OP_MAX) | ||
| 491 | return ERR_PTR(-EINVAL); | ||
| 492 | |||
| 493 | cache_result = (config >> 16) & 0xff; | ||
| 494 | if (cache_result >= PERF_COUNT_HW_CACHE_RESULT_MAX) | ||
| 495 | return ERR_PTR(-EINVAL); | ||
| 496 | |||
| 497 | pmap = &((*sparc_pmu->cache_map)[cache_type][cache_op][cache_result]); | ||
| 498 | |||
| 499 | if (pmap->encoding == CACHE_OP_UNSUPPORTED) | ||
| 500 | return ERR_PTR(-ENOENT); | ||
| 501 | |||
| 502 | if (pmap->encoding == CACHE_OP_NONSENSE) | ||
| 503 | return ERR_PTR(-EINVAL); | ||
| 504 | |||
| 505 | return pmap; | ||
| 506 | } | ||
| 507 | |||
| 378 | static void hw_perf_event_destroy(struct perf_event *event) | 508 | static void hw_perf_event_destroy(struct perf_event *event) |
| 379 | { | 509 | { |
| 380 | perf_event_release_pmc(); | 510 | perf_event_release_pmc(); |
| @@ -390,12 +520,17 @@ static int __hw_perf_event_init(struct perf_event *event) | |||
| 390 | if (atomic_read(&nmi_active) < 0) | 520 | if (atomic_read(&nmi_active) < 0) |
| 391 | return -ENODEV; | 521 | return -ENODEV; |
| 392 | 522 | ||
| 393 | if (attr->type != PERF_TYPE_HARDWARE) | 523 | if (attr->type == PERF_TYPE_HARDWARE) { |
| 524 | if (attr->config >= sparc_pmu->max_events) | ||
| 525 | return -EINVAL; | ||
| 526 | pmap = sparc_pmu->event_map(attr->config); | ||
| 527 | } else if (attr->type == PERF_TYPE_HW_CACHE) { | ||
| 528 | pmap = sparc_map_cache_event(attr->config); | ||
| 529 | if (IS_ERR(pmap)) | ||
| 530 | return PTR_ERR(pmap); | ||
| 531 | } else | ||
| 394 | return -EOPNOTSUPP; | 532 | return -EOPNOTSUPP; |
| 395 | 533 | ||
| 396 | if (attr->config >= sparc_pmu->max_events) | ||
| 397 | return -EINVAL; | ||
| 398 | |||
| 399 | perf_event_grab_pmc(); | 534 | perf_event_grab_pmc(); |
| 400 | event->destroy = hw_perf_event_destroy; | 535 | event->destroy = hw_perf_event_destroy; |
| 401 | 536 | ||
| @@ -417,8 +552,6 @@ static int __hw_perf_event_init(struct perf_event *event) | |||
| 417 | atomic64_set(&hwc->period_left, hwc->sample_period); | 552 | atomic64_set(&hwc->period_left, hwc->sample_period); |
| 418 | } | 553 | } |
| 419 | 554 | ||
| 420 | pmap = sparc_pmu->event_map(attr->config); | ||
| 421 | |||
| 422 | enc = pmap->encoding; | 555 | enc = pmap->encoding; |
| 423 | if (pmap->pic_mask & PIC_UPPER) { | 556 | if (pmap->pic_mask & PIC_UPPER) { |
| 424 | hwc->idx = PIC_UPPER_INDEX; | 557 | hwc->idx = PIC_UPPER_INDEX; |
