Commit 424646ee authored by Thomas Gleixner's avatar Thomas Gleixner Committed by Ingo Molnar

x86/perf/intel/cstate: Sanitize probing

The whole probing functionality can simply be expressed with model matching
and a bunch of structures describing the variants. This is a first step to
make that driver modular.

While at it, get rid of completely pointless comments and name the enums so
they are self explaining.
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
[ Reworked probing to clear msr[].attr for all !present msrs. ]
Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Kan Liang <kan.liang@intel.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Vince Weaver <vincent.weaver@maine.edu>
Link: http://lkml.kernel.org/r/20160320185623.500381872@linutronix.deSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent 49de0493
......@@ -106,22 +106,27 @@ static ssize_t cstate_get_attr_cpumask(struct device *dev,
struct device_attribute *attr,
char *buf);
/* Model -> events mapping */
struct cstate_model {
unsigned long core_events;
unsigned long pkg_events;
unsigned long quirks;
};
/* Quirk flags */
#define SLM_PKG_C6_USE_C7_MSR (1UL << 0)
struct perf_cstate_msr {
u64 msr;
struct perf_pmu_events_attr *attr;
bool (*test)(int idx);
};
/* cstate_core PMU */
static struct pmu cstate_core_pmu;
static bool has_cstate_core;
enum perf_cstate_core_id {
/*
* cstate_core events
*/
enum perf_cstate_core_events {
PERF_CSTATE_CORE_C1_RES = 0,
PERF_CSTATE_CORE_C3_RES,
PERF_CSTATE_CORE_C6_RES,
......@@ -130,69 +135,16 @@ enum perf_cstate_core_id {
PERF_CSTATE_CORE_EVENT_MAX,
};
bool test_core(int idx)
{
if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL ||
boot_cpu_data.x86 != 6)
return false;
switch (boot_cpu_data.x86_model) {
case 30: /* 45nm Nehalem */
case 26: /* 45nm Nehalem-EP */
case 46: /* 45nm Nehalem-EX */
case 37: /* 32nm Westmere */
case 44: /* 32nm Westmere-EP */
case 47: /* 32nm Westmere-EX */
if (idx == PERF_CSTATE_CORE_C3_RES ||
idx == PERF_CSTATE_CORE_C6_RES)
return true;
break;
case 42: /* 32nm SandyBridge */
case 45: /* 32nm SandyBridge-E/EN/EP */
case 58: /* 22nm IvyBridge */
case 62: /* 22nm IvyBridge-EP/EX */
case 60: /* 22nm Haswell Core */
case 63: /* 22nm Haswell Server */
case 69: /* 22nm Haswell ULT */
case 70: /* 22nm Haswell + GT3e (Intel Iris Pro graphics) */
case 61: /* 14nm Broadwell Core-M */
case 86: /* 14nm Broadwell Xeon D */
case 71: /* 14nm Broadwell + GT3e (Intel Iris Pro graphics) */
case 79: /* 14nm Broadwell Server */
case 78: /* 14nm Skylake Mobile */
case 94: /* 14nm Skylake Desktop */
if (idx == PERF_CSTATE_CORE_C3_RES ||
idx == PERF_CSTATE_CORE_C6_RES ||
idx == PERF_CSTATE_CORE_C7_RES)
return true;
break;
case 55: /* 22nm Atom "Silvermont" */
case 77: /* 22nm Atom "Silvermont Avoton/Rangely" */
case 76: /* 14nm Atom "Airmont" */
if (idx == PERF_CSTATE_CORE_C1_RES ||
idx == PERF_CSTATE_CORE_C6_RES)
return true;
break;
}
return false;
}
PMU_EVENT_ATTR_STRING(c1-residency, evattr_cstate_core_c1, "event=0x00");
PMU_EVENT_ATTR_STRING(c3-residency, evattr_cstate_core_c3, "event=0x01");
PMU_EVENT_ATTR_STRING(c6-residency, evattr_cstate_core_c6, "event=0x02");
PMU_EVENT_ATTR_STRING(c7-residency, evattr_cstate_core_c7, "event=0x03");
static struct perf_cstate_msr core_msr[] = {
[PERF_CSTATE_CORE_C1_RES] = { MSR_CORE_C1_RES, &evattr_cstate_core_c1, test_core, },
[PERF_CSTATE_CORE_C3_RES] = { MSR_CORE_C3_RESIDENCY, &evattr_cstate_core_c3, test_core, },
[PERF_CSTATE_CORE_C6_RES] = { MSR_CORE_C6_RESIDENCY, &evattr_cstate_core_c6, test_core, },
[PERF_CSTATE_CORE_C7_RES] = { MSR_CORE_C7_RESIDENCY, &evattr_cstate_core_c7, test_core, },
[PERF_CSTATE_CORE_C1_RES] = { MSR_CORE_C1_RES, &evattr_cstate_core_c1 },
[PERF_CSTATE_CORE_C3_RES] = { MSR_CORE_C3_RESIDENCY, &evattr_cstate_core_c3 },
[PERF_CSTATE_CORE_C6_RES] = { MSR_CORE_C6_RESIDENCY, &evattr_cstate_core_c6 },
[PERF_CSTATE_CORE_C7_RES] = { MSR_CORE_C7_RESIDENCY, &evattr_cstate_core_c7 },
};
static struct attribute *core_events_attrs[PERF_CSTATE_CORE_EVENT_MAX + 1] = {
......@@ -234,18 +186,11 @@ static const struct attribute_group *core_attr_groups[] = {
NULL,
};
/* cstate_core PMU end */
/* cstate_pkg PMU */
static struct pmu cstate_pkg_pmu;
static bool has_cstate_pkg;
enum perf_cstate_pkg_id {
/*
* cstate_pkg events
*/
enum perf_cstate_pkg_events {
PERF_CSTATE_PKG_C2_RES = 0,
PERF_CSTATE_PKG_C3_RES,
PERF_CSTATE_PKG_C6_RES,
......@@ -257,69 +202,6 @@ enum perf_cstate_pkg_id {
PERF_CSTATE_PKG_EVENT_MAX,
};
bool test_pkg(int idx)
{
if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL ||
boot_cpu_data.x86 != 6)
return false;
switch (boot_cpu_data.x86_model) {
case 30: /* 45nm Nehalem */
case 26: /* 45nm Nehalem-EP */
case 46: /* 45nm Nehalem-EX */
case 37: /* 32nm Westmere */
case 44: /* 32nm Westmere-EP */
case 47: /* 32nm Westmere-EX */
if (idx == PERF_CSTATE_CORE_C3_RES ||
idx == PERF_CSTATE_CORE_C6_RES ||
idx == PERF_CSTATE_CORE_C7_RES)
return true;
break;
case 42: /* 32nm SandyBridge */
case 45: /* 32nm SandyBridge-E/EN/EP */
case 58: /* 22nm IvyBridge */
case 62: /* 22nm IvyBridge-EP/EX */
case 60: /* 22nm Haswell Core */
case 63: /* 22nm Haswell Server */
case 70: /* 22nm Haswell + GT3e (Intel Iris Pro graphics) */
case 61: /* 14nm Broadwell Core-M */
case 86: /* 14nm Broadwell Xeon D */
case 71: /* 14nm Broadwell + GT3e (Intel Iris Pro graphics) */
case 79: /* 14nm Broadwell Server */
case 78: /* 14nm Skylake Mobile */
case 94: /* 14nm Skylake Desktop */
if (idx == PERF_CSTATE_PKG_C2_RES ||
idx == PERF_CSTATE_PKG_C3_RES ||
idx == PERF_CSTATE_PKG_C6_RES ||
idx == PERF_CSTATE_PKG_C7_RES)
return true;
break;
case 55: /* 22nm Atom "Silvermont" */
case 77: /* 22nm Atom "Silvermont Avoton/Rangely" */
case 76: /* 14nm Atom "Airmont" */
if (idx == PERF_CSTATE_CORE_C6_RES)
return true;
break;
case 69: /* 22nm Haswell ULT */
if (idx == PERF_CSTATE_PKG_C2_RES ||
idx == PERF_CSTATE_PKG_C3_RES ||
idx == PERF_CSTATE_PKG_C6_RES ||
idx == PERF_CSTATE_PKG_C7_RES ||
idx == PERF_CSTATE_PKG_C8_RES ||
idx == PERF_CSTATE_PKG_C9_RES ||
idx == PERF_CSTATE_PKG_C10_RES)
return true;
break;
}
return false;
}
PMU_EVENT_ATTR_STRING(c2-residency, evattr_cstate_pkg_c2, "event=0x00");
PMU_EVENT_ATTR_STRING(c3-residency, evattr_cstate_pkg_c3, "event=0x01");
PMU_EVENT_ATTR_STRING(c6-residency, evattr_cstate_pkg_c6, "event=0x02");
......@@ -329,13 +211,13 @@ PMU_EVENT_ATTR_STRING(c9-residency, evattr_cstate_pkg_c9, "event=0x05");
PMU_EVENT_ATTR_STRING(c10-residency, evattr_cstate_pkg_c10, "event=0x06");
static struct perf_cstate_msr pkg_msr[] = {
[PERF_CSTATE_PKG_C2_RES] = { MSR_PKG_C2_RESIDENCY, &evattr_cstate_pkg_c2, test_pkg, },
[PERF_CSTATE_PKG_C3_RES] = { MSR_PKG_C3_RESIDENCY, &evattr_cstate_pkg_c3, test_pkg, },
[PERF_CSTATE_PKG_C6_RES] = { MSR_PKG_C6_RESIDENCY, &evattr_cstate_pkg_c6, test_pkg, },
[PERF_CSTATE_PKG_C7_RES] = { MSR_PKG_C7_RESIDENCY, &evattr_cstate_pkg_c7, test_pkg, },
[PERF_CSTATE_PKG_C8_RES] = { MSR_PKG_C8_RESIDENCY, &evattr_cstate_pkg_c8, test_pkg, },
[PERF_CSTATE_PKG_C9_RES] = { MSR_PKG_C9_RESIDENCY, &evattr_cstate_pkg_c9, test_pkg, },
[PERF_CSTATE_PKG_C10_RES] = { MSR_PKG_C10_RESIDENCY, &evattr_cstate_pkg_c10, test_pkg, },
[PERF_CSTATE_PKG_C2_RES] = { MSR_PKG_C2_RESIDENCY, &evattr_cstate_pkg_c2 },
[PERF_CSTATE_PKG_C3_RES] = { MSR_PKG_C3_RESIDENCY, &evattr_cstate_pkg_c3 },
[PERF_CSTATE_PKG_C6_RES] = { MSR_PKG_C6_RESIDENCY, &evattr_cstate_pkg_c6 },
[PERF_CSTATE_PKG_C7_RES] = { MSR_PKG_C7_RESIDENCY, &evattr_cstate_pkg_c7 },
[PERF_CSTATE_PKG_C8_RES] = { MSR_PKG_C8_RESIDENCY, &evattr_cstate_pkg_c8 },
[PERF_CSTATE_PKG_C9_RES] = { MSR_PKG_C9_RESIDENCY, &evattr_cstate_pkg_c9 },
[PERF_CSTATE_PKG_C10_RES] = { MSR_PKG_C10_RESIDENCY, &evattr_cstate_pkg_c10 },
};
static struct attribute *pkg_events_attrs[PERF_CSTATE_PKG_EVENT_MAX + 1] = {
......@@ -366,8 +248,6 @@ static const struct attribute_group *pkg_attr_groups[] = {
NULL,
};
/* cstate_pkg PMU end*/
static ssize_t cstate_get_attr_cpumask(struct device *dev,
struct device_attribute *attr,
char *buf)
......@@ -552,48 +432,151 @@ static int cstate_cpu_notifier(struct notifier_block *self,
return NOTIFY_OK;
}
static struct pmu cstate_core_pmu = {
.attr_groups = core_attr_groups,
.name = "cstate_core",
.task_ctx_nr = perf_invalid_context,
.event_init = cstate_pmu_event_init,
.add = cstate_pmu_event_add,
.del = cstate_pmu_event_del,
.start = cstate_pmu_event_start,
.stop = cstate_pmu_event_stop,
.read = cstate_pmu_event_update,
.capabilities = PERF_PMU_CAP_NO_INTERRUPT,
};
static struct pmu cstate_pkg_pmu = {
.attr_groups = pkg_attr_groups,
.name = "cstate_pkg",
.task_ctx_nr = perf_invalid_context,
.event_init = cstate_pmu_event_init,
.add = cstate_pmu_event_add,
.del = cstate_pmu_event_del,
.start = cstate_pmu_event_start,
.stop = cstate_pmu_event_stop,
.read = cstate_pmu_event_update,
.capabilities = PERF_PMU_CAP_NO_INTERRUPT,
};
static const struct cstate_model nhm_cstates __initconst = {
.core_events = BIT(PERF_CSTATE_CORE_C3_RES) |
BIT(PERF_CSTATE_CORE_C6_RES),
.pkg_events = BIT(PERF_CSTATE_PKG_C3_RES) |
BIT(PERF_CSTATE_PKG_C6_RES) |
BIT(PERF_CSTATE_PKG_C7_RES),
};
static const struct cstate_model snb_cstates __initconst = {
.core_events = BIT(PERF_CSTATE_CORE_C3_RES) |
BIT(PERF_CSTATE_CORE_C6_RES) |
BIT(PERF_CSTATE_CORE_C7_RES),
.pkg_events = BIT(PERF_CSTATE_PKG_C2_RES) |
BIT(PERF_CSTATE_PKG_C3_RES) |
BIT(PERF_CSTATE_PKG_C6_RES) |
BIT(PERF_CSTATE_PKG_C7_RES),
};
static const struct cstate_model hswult_cstates __initconst = {
.core_events = BIT(PERF_CSTATE_CORE_C3_RES) |
BIT(PERF_CSTATE_CORE_C6_RES) |
BIT(PERF_CSTATE_CORE_C7_RES),
.pkg_events = BIT(PERF_CSTATE_PKG_C2_RES) |
BIT(PERF_CSTATE_PKG_C3_RES) |
BIT(PERF_CSTATE_PKG_C6_RES) |
BIT(PERF_CSTATE_PKG_C7_RES) |
BIT(PERF_CSTATE_PKG_C8_RES) |
BIT(PERF_CSTATE_PKG_C9_RES) |
BIT(PERF_CSTATE_PKG_C10_RES),
};
static const struct cstate_model slm_cstates __initconst = {
.core_events = BIT(PERF_CSTATE_CORE_C1_RES) |
BIT(PERF_CSTATE_CORE_C6_RES),
.pkg_events = BIT(PERF_CSTATE_PKG_C6_RES),
.quirks = SLM_PKG_C6_USE_C7_MSR,
};
#define X86_CSTATES_MODEL(model, states) \
{ X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long) &(states) }
static const struct x86_cpu_id intel_cstates_match[] __initconst = {
X86_CSTATES_MODEL(30, nhm_cstates), /* 45nm Nehalem */
X86_CSTATES_MODEL(26, nhm_cstates), /* 45nm Nehalem-EP */
X86_CSTATES_MODEL(46, nhm_cstates), /* 45nm Nehalem-EX */
X86_CSTATES_MODEL(37, nhm_cstates), /* 32nm Westmere */
X86_CSTATES_MODEL(44, nhm_cstates), /* 32nm Westmere-EP */
X86_CSTATES_MODEL(47, nhm_cstates), /* 32nm Westmere-EX */
X86_CSTATES_MODEL(42, snb_cstates), /* 32nm SandyBridge */
X86_CSTATES_MODEL(45, snb_cstates), /* 32nm SandyBridge-E/EN/EP */
X86_CSTATES_MODEL(58, snb_cstates), /* 22nm IvyBridge */
X86_CSTATES_MODEL(62, snb_cstates), /* 22nm IvyBridge-EP/EX */
X86_CSTATES_MODEL(60, snb_cstates), /* 22nm Haswell Core */
X86_CSTATES_MODEL(63, snb_cstates), /* 22nm Haswell Server */
X86_CSTATES_MODEL(70, snb_cstates), /* 22nm Haswell + GT3e */
X86_CSTATES_MODEL(69, hswult_cstates), /* 22nm Haswell ULT */
X86_CSTATES_MODEL(55, slm_cstates), /* 22nm Atom Silvermont */
X86_CSTATES_MODEL(77, slm_cstates), /* 22nm Atom Avoton/Rangely */
X86_CSTATES_MODEL(76, slm_cstates), /* 22nm Atom Airmont */
X86_CSTATES_MODEL(61, snb_cstates), /* 14nm Broadwell Core-M */
X86_CSTATES_MODEL(86, snb_cstates), /* 14nm Broadwell Xeon D */
X86_CSTATES_MODEL(71, snb_cstates), /* 14nm Broadwell + GT3e */
X86_CSTATES_MODEL(79, snb_cstates), /* 14nm Broadwell Server */
X86_CSTATES_MODEL(78, snb_cstates), /* 14nm Skylake Mobile */
X86_CSTATES_MODEL(94, snb_cstates), /* 14nm Skylake Desktop */
{ },
};
MODULE_DEVICE_TABLE(x86cpu, intel_cstates_match);
/*
* Probe the cstate events and insert the available one into sysfs attrs
* Return false if there is no available events.
* Return false if there are no available events.
*/
static bool cstate_probe_msr(struct perf_cstate_msr *msr,
struct attribute **events_attrs,
int max_event_nr)
static bool __init cstate_probe_msr(const unsigned long evmsk, int max,
struct perf_cstate_msr *msr,
struct attribute **attrs)
{
int i, j = 0;
bool found = false;
unsigned int bit;
u64 val;
/* Probe the cstate events. */
for (i = 0; i < max_event_nr; i++) {
if (!msr[i].test(i) || rdmsrl_safe(msr[i].msr, &val))
msr[i].attr = NULL;
}
/* List remaining events in the sysfs attrs. */
for (i = 0; i < max_event_nr; i++) {
if (msr[i].attr)
events_attrs[j++] = &msr[i].attr->attr.attr;
for (bit = 0; bit < max; bit++) {
if (test_bit(bit, &evmsk) && !rdmsrl_safe(msr[bit].msr, &val)) {
*attrs++ = &msr[bit].attr->attr.attr;
found = true;
} else {
msr[bit].attr = NULL;
}
}
events_attrs[j] = NULL;
*attrs = NULL;
return (j > 0) ? true : false;
return found;
}
static int __init cstate_init(void)
static int __init cstate_probe(const struct cstate_model *cm)
{
/* SLM has different MSR for PKG C6 */
switch (boot_cpu_data.x86_model) {
case 55:
case 76:
case 77:
if (cm->quirks & SLM_PKG_C6_USE_C7_MSR)
pkg_msr[PERF_CSTATE_PKG_C6_RES].msr = MSR_PKG_C7_RESIDENCY;
}
if (cstate_probe_msr(core_msr, core_events_attrs, PERF_CSTATE_CORE_EVENT_MAX))
has_cstate_core = true;
has_cstate_core = cstate_probe_msr(cm->core_events,
PERF_CSTATE_CORE_EVENT_MAX,
core_msr, core_events_attrs);
if (cstate_probe_msr(pkg_msr, pkg_events_attrs, PERF_CSTATE_PKG_EVENT_MAX))
has_cstate_pkg = true;
has_cstate_pkg = cstate_probe_msr(cm->pkg_events,
PERF_CSTATE_PKG_EVENT_MAX,
pkg_msr, pkg_events_attrs);
return (has_cstate_core || has_cstate_pkg) ? 0 : -ENODEV;
}
......@@ -612,32 +595,6 @@ static void __init cstate_cpumask_init(void)
cpu_notifier_register_done();
}
static struct pmu cstate_core_pmu = {
.attr_groups = core_attr_groups,
.name = "cstate_core",
.task_ctx_nr = perf_invalid_context,
.event_init = cstate_pmu_event_init,
.add = cstate_pmu_event_add, /* must have */
.del = cstate_pmu_event_del, /* must have */
.start = cstate_pmu_event_start,
.stop = cstate_pmu_event_stop,
.read = cstate_pmu_event_update,
.capabilities = PERF_PMU_CAP_NO_INTERRUPT,
};
static struct pmu cstate_pkg_pmu = {
.attr_groups = pkg_attr_groups,
.name = "cstate_pkg",
.task_ctx_nr = perf_invalid_context,
.event_init = cstate_pmu_event_init,
.add = cstate_pmu_event_add, /* must have */
.del = cstate_pmu_event_del, /* must have */
.start = cstate_pmu_event_start,
.stop = cstate_pmu_event_stop,
.read = cstate_pmu_event_update,
.capabilities = PERF_PMU_CAP_NO_INTERRUPT,
};
static void __init cstate_pmus_register(void)
{
int err;
......@@ -659,12 +616,17 @@ static void __init cstate_pmus_register(void)
static int __init cstate_pmu_init(void)
{
const struct x86_cpu_id *id;
int err;
if (cpu_has_hypervisor)
if (boot_cpu_has(X86_FEATURE_HYPERVISOR))
return -ENODEV;
err = cstate_init();
id = x86_match_cpu(intel_cstates_match);
if (!id)
return -ENODEV;
err = cstate_probe((const struct cstate_model *) id->driver_data);
if (err)
return err;
......@@ -674,5 +636,4 @@ static int __init cstate_pmu_init(void)
return 0;
}
device_initcall(cstate_pmu_init);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment