11 #define KMSG_COMPONENT "cpum_cf"
12 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
14 #include <linux/kernel.h>
16 #include <linux/perf_event.h>
20 #include <linux/export.h>
43 #define CPUMF_LCCTL_ENABLE_SHIFT 16
44 #define CPUMF_LCCTL_ACTCTL_SHIFT 0
52 static void ctr_set_enable(
u64 *
state,
int ctr_set)
56 static void ctr_set_disable(
u64 *
state,
int ctr_set)
60 static void ctr_set_start(
u64 *
state,
int ctr_set)
64 static void ctr_set_stop(
u64 *
state,
int ctr_set)
87 static int get_counter_set(
u64 event)
105 switch (hwc->config_base) {
111 if ((hwc->config >= 6 && hwc->config <= 31) ||
112 (hwc->config >= 38 && hwc->config <= 63) ||
113 (hwc->config >= 80 && hwc->config <= 127))
123 static int validate_ctr_version(
const struct hw_perf_event *hwc)
131 switch (hwc->config_base) {
134 if (cpuhw->
info.cfvn < 1)
139 if (cpuhw->
info.csvn < 1)
141 if ((cpuhw->
info.csvn == 1 && hwc->config > 159) ||
142 (cpuhw->
info.csvn == 2 && hwc->config > 175) ||
143 (cpuhw->
info.csvn > 2 && hwc->config > 255))
152 static int validate_ctr_auth(
const struct hw_perf_event *hwc)
161 ctrs_state = cpumf_state_ctl[hwc->config_base];
162 if (!(ctrs_state & cpuhw->
info.auth_ctl))
174 static void cpumf_pmu_enable(
struct pmu *
pmu)
182 err = lcctl(cpuhw->
state);
184 pr_err(
"Enabling the performance measuring unit "
185 "failed with rc=%x\n", err);
197 static void cpumf_pmu_disable(
struct pmu *pmu)
207 err = lcctl(inactive);
209 pr_err(
"Disabling the performance measuring unit "
210 "failed with rc=%x\n", err);
225 unsigned int alert,
unsigned long unused)
250 #define PMC_RELEASE 1
251 static void setup_pmc_cpu(
void *
flags)
255 switch (*((
int *) flags)) {
292 static void hw_perf_event_destroy(
struct perf_event *event)
294 if (!atomic_add_unless(&num_events, -1, 1)) {
303 static const int cpumf_generic_events_basic[] = {
313 static const int cpumf_generic_events_user[] = {
323 static int __hw_perf_event_init(
struct perf_event *event)
330 switch (attr->
type) {
344 if (ev >=
ARRAY_SIZE(cpumf_generic_events_user))
346 ev = cpumf_generic_events_user[ev];
354 if (ev >=
ARRAY_SIZE(cpumf_generic_events_basic))
356 ev = cpumf_generic_events_basic[ev];
374 if (hwc->sample_period)
383 hwc->config_base = get_counter_set(ev);
390 err = validate_event(hwc);
403 event->destroy = hw_perf_event_destroy;
406 err = validate_ctr_auth(hwc);
408 err = validate_ctr_version(hwc);
413 static int cpumf_pmu_event_init(
struct perf_event *event)
417 switch (event->
attr.type) {
421 err = __hw_perf_event_init(event);
427 if (
unlikely(err) && event->destroy)
428 event->destroy(event);
433 static int hw_perf_event_reset(
struct perf_event *event)
440 err = ecctr(event->hw.config, &
new);
456 static int hw_perf_event_update(
struct perf_event *event)
463 err = ecctr(event->hw.config, &
new);
468 delta = (prev <=
new) ?
new - prev
469 : (-1ULL - prev) +
new + 1;
475 static void cpumf_pmu_read(
struct perf_event *event)
480 hw_perf_event_update(event);
500 ctr_set_enable(&cpuhw->
state, hwc->config_base);
501 ctr_set_start(&cpuhw->
state, hwc->config_base);
508 hw_perf_event_reset(event);
514 static void cpumf_pmu_stop(
struct perf_event *event,
int flags)
525 ctr_set_stop(&cpuhw->
state, hwc->config_base);
530 hw_perf_event_update(event);
535 static int cpumf_pmu_add(
struct perf_event *event,
int flags)
545 if (validate_ctr_auth(&event->hw))
548 ctr_set_enable(&cpuhw->
state, event->hw.config_base);
552 cpumf_pmu_start(event, PERF_EF_RELOAD);
559 static void cpumf_pmu_del(
struct perf_event *event,
int flags)
563 cpumf_pmu_stop(event, PERF_EF_UPDATE);
574 ctr_set_disable(&cpuhw->
state, event->hw.config_base);
583 static void cpumf_pmu_start_txn(
struct pmu *pmu)
597 static void cpumf_pmu_cancel_txn(
struct pmu *pmu)
612 static int cpumf_pmu_commit_txn(
struct pmu *pmu)
620 if ((state & cpuhw->
info.auth_ctl) !=
state)
629 static struct pmu cpumf_pmu = {
630 .pmu_enable = cpumf_pmu_enable,
631 .pmu_disable = cpumf_pmu_disable,
632 .event_init = cpumf_pmu_event_init,
633 .add = cpumf_pmu_add,
634 .del = cpumf_pmu_del,
635 .start = cpumf_pmu_start,
636 .stop = cpumf_pmu_stop,
637 .read = cpumf_pmu_read,
638 .start_txn = cpumf_pmu_start_txn,
639 .commit_txn = cpumf_pmu_commit_txn,
640 .cancel_txn = cpumf_pmu_cancel_txn,
644 unsigned long action,
void *hcpu)
646 unsigned int cpu = (
long) hcpu;
665 static int __init cpumf_pmu_init(
void)
669 if (!cpum_cf_avail())
679 pr_err(
"Registering for CPU-measurement alerts "
680 "failed with rc=%i\n", rc);
686 pr_err(
"Registering the cpum_cf PMU failed with rc=%i\n", rc);