mirror of
https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9.git
synced 2026-09-09 00:08:12 +08:00
Merge: perf: Intel NVL, DMR and WCL support plus ACR and PEBS update
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/8584 JIRA: https://redhat.atlassian.net/browse/RHEL-45125 JIRA: https://redhat.atlassian.net/browse/RHEL-115121 JIRA: https://redhat.atlassian.net/browse/RHEL-115123 JIRA: https://redhat.atlassian.net/browse/RHEL-115125 JIRA: https://redhat.atlassian.net/browse/RHEL-117336 JIRA: https://redhat.atlassian.net/browse/RHEL-117338 JIRA: https://redhat.atlassian.net/browse/RHEL-120358 JIRA: https://redhat.atlassian.net/browse/RHEL-95669 This batch covers multiple issues, however logically tied-together. * cstate support for Intel NVL, DMR and WCL * uncore support for Intel NVL and DMR * many fixes and pre-requisities for the uncore and core support * core PMU support for Intel NVL and DMR * ACR functionality which the NVL and DMR core take advantage of * Architectural PEBS (by Anubhav Shelat) Signed-off-by: Michael Petlan <mpetlan@redhat.com> Signed-off-by: Anubhav Shelat <ashelat@redhat.com> Approved-by: Steve Best <sbest@redhat.com> Approved-by: ashelat <ashelat@redhat.com> Approved-by: tallison1 <tallison@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: CKI GitLab Kmaint Pipeline Bot <26919896-cki-kmaint-pipeline-bot@users.noreply.gitlab.com>
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
What: /sys/bus/event_source/devices/cpu.../rdpmc
|
||||
Date: November 2011
|
||||
KernelVersion: 3.10
|
||||
Contact: Linux kernel mailing list linux-kernel@vger.kernel.org
|
||||
Description: The /sys/bus/event_source/devices/cpu.../rdpmc attribute
|
||||
is used to show/manage if rdpmc instruction can be
|
||||
executed in user space. This attribute supports 3 numbers.
|
||||
- rdpmc = 0
|
||||
user space rdpmc is globally disabled for all PMU
|
||||
counters.
|
||||
- rdpmc = 1
|
||||
user space rdpmc is globally enabled only in event mmap
|
||||
ioctl called time window. If the mmap region is unmapped,
|
||||
user space rdpmc is disabled again.
|
||||
- rdpmc = 2
|
||||
user space rdpmc is globally enabled for all PMU
|
||||
counters.
|
||||
|
||||
In the Intel platforms supporting counter level's user
|
||||
space rdpmc disable feature (CPUID.23H.EBX[2] = 1), the
|
||||
meaning of 3 numbers is extended to
|
||||
- rdpmc = 0
|
||||
global user space rdpmc and counter level's user space
|
||||
rdpmc of all counters are both disabled.
|
||||
- rdpmc = 1
|
||||
No changes on behavior of global user space rdpmc.
|
||||
counter level's rdpmc of system-wide events is disabled
|
||||
but counter level's rdpmc of non-system-wide events is
|
||||
enabled.
|
||||
- rdpmc = 2
|
||||
global user space rdpmc and counter level's user space
|
||||
rdpmc of all counters are both enabled unconditionally.
|
||||
|
||||
The default value of rdpmc is 1.
|
||||
|
||||
Please notice:
|
||||
- global user space rdpmc's behavior would change
|
||||
immediately along with the rdpmc value's change,
|
||||
but the behavior of counter level's user space rdpmc
|
||||
won't take effect immediately until the event is
|
||||
reactivated or recreated.
|
||||
- The rdpmc attribute is global, even for x86 hybrid
|
||||
platforms. For example, changing cpu_core/rdpmc will
|
||||
also change cpu_atom/rdpmc.
|
||||
@@ -1368,8 +1368,7 @@ fail:
|
||||
* recorded as part of interrupt regs. Thus we need to use rip from
|
||||
* interrupt regs while unwinding call stack.
|
||||
*/
|
||||
if (event->attr.sample_type & PERF_SAMPLE_CALLCHAIN)
|
||||
perf_sample_save_callchain(&data, event, iregs);
|
||||
perf_sample_save_callchain(&data, event, iregs);
|
||||
|
||||
throttle = perf_event_overflow(event, &data, ®s);
|
||||
|
||||
|
||||
+69
-20
@@ -96,6 +96,11 @@ DEFINE_STATIC_CALL_NULL(x86_pmu_filter, *x86_pmu.filter);
|
||||
|
||||
DEFINE_STATIC_CALL_NULL(x86_pmu_late_setup, *x86_pmu.late_setup);
|
||||
|
||||
DEFINE_STATIC_CALL_NULL(x86_pmu_pebs_enable, *x86_pmu.pebs_enable);
|
||||
DEFINE_STATIC_CALL_NULL(x86_pmu_pebs_disable, *x86_pmu.pebs_disable);
|
||||
DEFINE_STATIC_CALL_NULL(x86_pmu_pebs_enable_all, *x86_pmu.pebs_enable_all);
|
||||
DEFINE_STATIC_CALL_NULL(x86_pmu_pebs_disable_all, *x86_pmu.pebs_disable_all);
|
||||
|
||||
/*
|
||||
* This one is magic, it will get called even when PMU init fails (because
|
||||
* there is no PMU), in which case it should simply return NULL.
|
||||
@@ -549,14 +554,22 @@ static inline int precise_br_compat(struct perf_event *event)
|
||||
return m == b;
|
||||
}
|
||||
|
||||
int x86_pmu_max_precise(void)
|
||||
int x86_pmu_max_precise(struct pmu *pmu)
|
||||
{
|
||||
int precise = 0;
|
||||
|
||||
/* Support for constant skid */
|
||||
if (x86_pmu.pebs_active && !x86_pmu.pebs_broken) {
|
||||
precise++;
|
||||
/* arch PEBS */
|
||||
if (x86_pmu.arch_pebs) {
|
||||
precise = 2;
|
||||
if (hybrid(pmu, arch_pebs_cap).pdists)
|
||||
precise++;
|
||||
|
||||
return precise;
|
||||
}
|
||||
|
||||
/* legacy PEBS - support for constant skid */
|
||||
precise++;
|
||||
/* Support for IP fixup */
|
||||
if (x86_pmu.lbr_nr || x86_pmu.intel_cap.pebs_format >= 2)
|
||||
precise++;
|
||||
@@ -564,13 +577,14 @@ int x86_pmu_max_precise(void)
|
||||
if (x86_pmu.pebs_prec_dist)
|
||||
precise++;
|
||||
}
|
||||
|
||||
return precise;
|
||||
}
|
||||
|
||||
int x86_pmu_hw_config(struct perf_event *event)
|
||||
{
|
||||
if (event->attr.precise_ip) {
|
||||
int precise = x86_pmu_max_precise();
|
||||
int precise = x86_pmu_max_precise(event->pmu);
|
||||
|
||||
if (event->attr.precise_ip > precise)
|
||||
return -EOPNOTSUPP;
|
||||
@@ -675,6 +689,7 @@ static int __x86_pmu_event_init(struct perf_event *event)
|
||||
event->hw.idx = -1;
|
||||
event->hw.last_cpu = -1;
|
||||
event->hw.last_tag = ~0ULL;
|
||||
event->hw.dyn_constraint = ~0ULL;
|
||||
|
||||
/* mark unused */
|
||||
event->hw.extra_reg.idx = EXTRA_REG_NONE;
|
||||
@@ -1274,13 +1289,16 @@ int x86_perf_rdpmc_index(struct perf_event *event)
|
||||
return event->hw.event_base_rdpmc;
|
||||
}
|
||||
|
||||
static inline int match_prev_assignment(struct hw_perf_event *hwc,
|
||||
static inline int match_prev_assignment(struct perf_event *event,
|
||||
struct cpu_hw_events *cpuc,
|
||||
int i)
|
||||
{
|
||||
struct hw_perf_event *hwc = &event->hw;
|
||||
|
||||
return hwc->idx == cpuc->assign[i] &&
|
||||
hwc->last_cpu == smp_processor_id() &&
|
||||
hwc->last_tag == cpuc->tags[i];
|
||||
hwc->last_cpu == smp_processor_id() &&
|
||||
hwc->last_tag == cpuc->tags[i] &&
|
||||
!is_acr_event_group(event);
|
||||
}
|
||||
|
||||
static void x86_pmu_start(struct perf_event *event, int flags);
|
||||
@@ -1326,7 +1344,7 @@ static void x86_pmu_enable(struct pmu *pmu)
|
||||
* - no other event has used the counter since
|
||||
*/
|
||||
if (hwc->idx == -1 ||
|
||||
match_prev_assignment(hwc, cpuc, i))
|
||||
match_prev_assignment(event, cpuc, i))
|
||||
continue;
|
||||
|
||||
/*
|
||||
@@ -1346,7 +1364,7 @@ static void x86_pmu_enable(struct pmu *pmu)
|
||||
event = cpuc->event_list[i];
|
||||
hwc = &event->hw;
|
||||
|
||||
if (!match_prev_assignment(hwc, cpuc, i))
|
||||
if (!match_prev_assignment(event, cpuc, i))
|
||||
x86_assign_hw_event(event, cpuc, i);
|
||||
else if (i < n_running)
|
||||
continue;
|
||||
@@ -2049,6 +2067,11 @@ static void x86_pmu_static_call_update(void)
|
||||
static_call_update(x86_pmu_filter, x86_pmu.filter);
|
||||
|
||||
static_call_update(x86_pmu_late_setup, x86_pmu.late_setup);
|
||||
|
||||
static_call_update(x86_pmu_pebs_enable, x86_pmu.pebs_enable);
|
||||
static_call_update(x86_pmu_pebs_disable, x86_pmu.pebs_disable);
|
||||
static_call_update(x86_pmu_pebs_enable_all, x86_pmu.pebs_enable_all);
|
||||
static_call_update(x86_pmu_pebs_disable_all, x86_pmu.pebs_disable_all);
|
||||
}
|
||||
|
||||
static void _x86_pmu_read(struct perf_event *event)
|
||||
@@ -2058,13 +2081,15 @@ static void _x86_pmu_read(struct perf_event *event)
|
||||
|
||||
void x86_pmu_show_pmu_cap(struct pmu *pmu)
|
||||
{
|
||||
pr_info("... version: %d\n", x86_pmu.version);
|
||||
pr_info("... bit width: %d\n", x86_pmu.cntval_bits);
|
||||
pr_info("... generic registers: %d\n", x86_pmu_num_counters(pmu));
|
||||
pr_info("... value mask: %016Lx\n", x86_pmu.cntval_mask);
|
||||
pr_info("... max period: %016Lx\n", x86_pmu.max_period);
|
||||
pr_info("... fixed-purpose events: %d\n", x86_pmu_num_counters_fixed(pmu));
|
||||
pr_info("... event mask: %016Lx\n", hybrid(pmu, intel_ctrl));
|
||||
pr_info("... version: %d\n", x86_pmu.version);
|
||||
pr_info("... bit width: %d\n", x86_pmu.cntval_bits);
|
||||
pr_info("... generic counters: %d\n", x86_pmu_num_counters(pmu));
|
||||
pr_info("... generic bitmap: %016llx\n", hybrid(pmu, cntr_mask64));
|
||||
pr_info("... fixed-purpose counters: %d\n", x86_pmu_num_counters_fixed(pmu));
|
||||
pr_info("... fixed-purpose bitmap: %016llx\n", hybrid(pmu, fixed_cntr_mask64));
|
||||
pr_info("... value mask: %016llx\n", x86_pmu.cntval_mask);
|
||||
pr_info("... max period: %016llx\n", x86_pmu.max_period);
|
||||
pr_info("... global_ctrl mask: %016llx\n", hybrid(pmu, intel_ctrl));
|
||||
}
|
||||
|
||||
static int __init init_hw_perf_events(void)
|
||||
@@ -2106,7 +2131,8 @@ static int __init init_hw_perf_events(void)
|
||||
|
||||
pr_cont("%s PMU driver.\n", x86_pmu.name);
|
||||
|
||||
x86_pmu.attr_rdpmc = 1; /* enable userspace RDPMC usage by default */
|
||||
/* enable userspace RDPMC usage by default */
|
||||
x86_pmu.attr_rdpmc = X86_USER_RDPMC_CONDITIONAL_ENABLE;
|
||||
|
||||
for (quirk = x86_pmu.quirks; quirk; quirk = quirk->next)
|
||||
quirk->func();
|
||||
@@ -2558,6 +2584,27 @@ static ssize_t get_attr_rdpmc(struct device *cdev,
|
||||
return snprintf(buf, 40, "%d\n", x86_pmu.attr_rdpmc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Behaviors of rdpmc value:
|
||||
* - rdpmc = 0
|
||||
* global user space rdpmc and counter level's user space rdpmc of all
|
||||
* counters are both disabled.
|
||||
* - rdpmc = 1
|
||||
* global user space rdpmc is enabled in mmap enabled time window and
|
||||
* counter level's user space rdpmc is enabled for only non system-wide
|
||||
* events. Counter level's user space rdpmc of system-wide events is
|
||||
* still disabled by default. This won't introduce counter data leak for
|
||||
* non system-wide events since their count data would be cleared when
|
||||
* context switches.
|
||||
* - rdpmc = 2
|
||||
* global user space rdpmc and counter level's user space rdpmc of all
|
||||
* counters are enabled unconditionally.
|
||||
*
|
||||
* Suppose the rdpmc value won't be changed frequently, don't dynamically
|
||||
* reschedule events to make the new rpdmc value take effect on active perf
|
||||
* events immediately, the new rdpmc value would only impact the new
|
||||
* activated perf events. This makes code simpler and cleaner.
|
||||
*/
|
||||
static ssize_t set_attr_rdpmc(struct device *cdev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
@@ -2586,12 +2633,12 @@ static ssize_t set_attr_rdpmc(struct device *cdev,
|
||||
*/
|
||||
if (val == 0)
|
||||
static_branch_inc(&rdpmc_never_available_key);
|
||||
else if (x86_pmu.attr_rdpmc == 0)
|
||||
else if (x86_pmu.attr_rdpmc == X86_USER_RDPMC_NEVER_ENABLE)
|
||||
static_branch_dec(&rdpmc_never_available_key);
|
||||
|
||||
if (val == 2)
|
||||
static_branch_inc(&rdpmc_always_available_key);
|
||||
else if (x86_pmu.attr_rdpmc == 2)
|
||||
else if (x86_pmu.attr_rdpmc == X86_USER_RDPMC_ALWAYS_ENABLE)
|
||||
static_branch_dec(&rdpmc_always_available_key);
|
||||
|
||||
on_each_cpu(cr4_update_pce, NULL, 1);
|
||||
@@ -2616,7 +2663,9 @@ static ssize_t max_precise_show(struct device *cdev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", x86_pmu_max_precise());
|
||||
struct pmu *pmu = dev_get_drvdata(cdev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", x86_pmu_max_precise(pmu));
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(max_precise);
|
||||
|
||||
@@ -584,7 +584,11 @@ static void bts_event_read(struct perf_event *event)
|
||||
|
||||
static __init int bts_init(void)
|
||||
{
|
||||
if (!boot_cpu_has(X86_FEATURE_DTES64) || !x86_pmu.bts)
|
||||
if (!boot_cpu_has(X86_FEATURE_DTES64))
|
||||
return -ENODEV;
|
||||
|
||||
x86_pmu.bts = boot_cpu_has(X86_FEATURE_BTS);
|
||||
if (!x86_pmu.bts)
|
||||
return -ENODEV;
|
||||
|
||||
if (boot_cpu_has(X86_FEATURE_PTI)) {
|
||||
@@ -619,4 +623,4 @@ static __init int bts_init(void)
|
||||
|
||||
return perf_pmu_register(&bts_pmu, "intel_bts", -1);
|
||||
}
|
||||
arch_initcall(bts_init);
|
||||
early_initcall(bts_init);
|
||||
|
||||
+1156
-72
File diff suppressed because it is too large
Load Diff
@@ -41,7 +41,7 @@
|
||||
* MSR_CORE_C1_RES: CORE C1 Residency Counter
|
||||
* perf code: 0x00
|
||||
* Available model: SLM,AMT,GLM,CNL,ICX,TNT,ADL,RPL
|
||||
* MTL,SRF,GRR,ARL,LNL,PTL
|
||||
* MTL,SRF,GRR,ARL,LNL,PTL,WCL,NVL
|
||||
* Scope: Core (each processor core has a MSR)
|
||||
* MSR_CORE_C3_RESIDENCY: CORE C3 Residency Counter
|
||||
* perf code: 0x01
|
||||
@@ -53,19 +53,20 @@
|
||||
* Available model: SLM,AMT,NHM,WSM,SNB,IVB,HSW,BDW,
|
||||
* SKL,KNL,GLM,CNL,KBL,CML,ICL,ICX,
|
||||
* TGL,TNT,RKL,ADL,RPL,SPR,MTL,SRF,
|
||||
* GRR,ARL,LNL,PTL
|
||||
* GRR,ARL,LNL,PTL,WCL,NVL
|
||||
* Scope: Core
|
||||
* MSR_CORE_C7_RESIDENCY: CORE C7 Residency Counter
|
||||
* perf code: 0x03
|
||||
* Available model: SNB,IVB,HSW,BDW,SKL,CNL,KBL,CML,
|
||||
* ICL,TGL,RKL,ADL,RPL,MTL,ARL,LNL,
|
||||
* PTL
|
||||
* PTL,WCL,NVL
|
||||
* Scope: Core
|
||||
* MSR_PKG_C2_RESIDENCY: Package C2 Residency Counter.
|
||||
* perf code: 0x00
|
||||
* Available model: SNB,IVB,HSW,BDW,SKL,KNL,GLM,CNL,
|
||||
* KBL,CML,ICL,ICX,TGL,TNT,RKL,ADL,
|
||||
* RPL,SPR,MTL,ARL,LNL,SRF,PTL
|
||||
* RPL,SPR,MTL,ARL,LNL,SRF,PTL,WCL,
|
||||
* NVL
|
||||
* Scope: Package (physical package)
|
||||
* MSR_PKG_C3_RESIDENCY: Package C3 Residency Counter.
|
||||
* perf code: 0x01
|
||||
@@ -78,7 +79,7 @@
|
||||
* Available model: SLM,AMT,NHM,WSM,SNB,IVB,HSW,BDW,
|
||||
* SKL,KNL,GLM,CNL,KBL,CML,ICL,ICX,
|
||||
* TGL,TNT,RKL,ADL,RPL,SPR,MTL,SRF,
|
||||
* ARL,LNL,PTL
|
||||
* ARL,LNL,PTL,WCL,NVL
|
||||
* Scope: Package (physical package)
|
||||
* MSR_PKG_C7_RESIDENCY: Package C7 Residency Counter.
|
||||
* perf code: 0x03
|
||||
@@ -97,11 +98,12 @@
|
||||
* MSR_PKG_C10_RESIDENCY: Package C10 Residency Counter.
|
||||
* perf code: 0x06
|
||||
* Available model: HSW ULT,KBL,GLM,CNL,CML,ICL,TGL,
|
||||
* TNT,RKL,ADL,RPL,MTL,ARL,LNL,PTL
|
||||
* TNT,RKL,ADL,RPL,MTL,ARL,LNL,PTL,
|
||||
* WCL,NVL
|
||||
* Scope: Package (physical package)
|
||||
* MSR_MODULE_C6_RES_MS: Module C6 Residency Counter.
|
||||
* perf code: 0x00
|
||||
* Available model: SRF,GRR
|
||||
* Available model: SRF,GRR,NVL
|
||||
* Scope: A cluster of cores shared L2 cache
|
||||
*
|
||||
*/
|
||||
@@ -527,6 +529,18 @@ static const struct cstate_model lnl_cstates __initconst = {
|
||||
BIT(PERF_CSTATE_PKG_C10_RES),
|
||||
};
|
||||
|
||||
static const struct cstate_model nvl_cstates __initconst = {
|
||||
.core_events = BIT(PERF_CSTATE_CORE_C1_RES) |
|
||||
BIT(PERF_CSTATE_CORE_C6_RES) |
|
||||
BIT(PERF_CSTATE_CORE_C7_RES),
|
||||
|
||||
.module_events = BIT(PERF_CSTATE_MODULE_C6_RES),
|
||||
|
||||
.pkg_events = BIT(PERF_CSTATE_PKG_C2_RES) |
|
||||
BIT(PERF_CSTATE_PKG_C6_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),
|
||||
@@ -638,6 +652,7 @@ static const struct x86_cpu_id intel_cstates_match[] __initconst = {
|
||||
X86_MATCH_VFM(INTEL_EMERALDRAPIDS_X, &icx_cstates),
|
||||
X86_MATCH_VFM(INTEL_GRANITERAPIDS_X, &icx_cstates),
|
||||
X86_MATCH_VFM(INTEL_GRANITERAPIDS_D, &icx_cstates),
|
||||
X86_MATCH_VFM(INTEL_DIAMONDRAPIDS_X, &srf_cstates),
|
||||
|
||||
X86_MATCH_VFM(INTEL_TIGERLAKE_L, &icl_cstates),
|
||||
X86_MATCH_VFM(INTEL_TIGERLAKE, &icl_cstates),
|
||||
@@ -654,6 +669,9 @@ static const struct x86_cpu_id intel_cstates_match[] __initconst = {
|
||||
X86_MATCH_VFM(INTEL_ARROWLAKE_U, &adl_cstates),
|
||||
X86_MATCH_VFM(INTEL_LUNARLAKE_M, &lnl_cstates),
|
||||
X86_MATCH_VFM(INTEL_PANTHERLAKE_L, &lnl_cstates),
|
||||
X86_MATCH_VFM(INTEL_WILDCATLAKE_L, &lnl_cstates),
|
||||
X86_MATCH_VFM(INTEL_NOVALAKE, &nvl_cstates),
|
||||
X86_MATCH_VFM(INTEL_NOVALAKE_L, &nvl_cstates),
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(x86cpu, intel_cstates_match);
|
||||
|
||||
+788
-131
File diff suppressed because it is too large
Load Diff
@@ -1609,7 +1609,7 @@ void __init intel_pmu_arch_lbr_init(void)
|
||||
x86_pmu.lbr_nr = lbr_nr;
|
||||
|
||||
if (!!x86_pmu.lbr_counters)
|
||||
x86_pmu.flags |= PMU_FL_BR_CNTR;
|
||||
x86_pmu.flags |= PMU_FL_BR_CNTR | PMU_FL_DYN_CONSTRAINT;
|
||||
|
||||
if (x86_pmu.lbr_mispred)
|
||||
static_branch_enable(&x86_lbr_mispred);
|
||||
|
||||
@@ -240,7 +240,7 @@ static __init void p6_pmu_rdpmc_quirk(void)
|
||||
*/
|
||||
pr_warn("Userspace RDPMC support disabled due to a CPU erratum\n");
|
||||
x86_pmu.attr_rdpmc_broken = 1;
|
||||
x86_pmu.attr_rdpmc = 0;
|
||||
x86_pmu.attr_rdpmc = X86_USER_RDPMC_NEVER_ENABLE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+121
-49
@@ -66,6 +66,7 @@ int uncore_die_to_segment(int die)
|
||||
return bus ? pci_domain_nr(bus) : -EINVAL;
|
||||
}
|
||||
|
||||
/* Note: This API can only be used when NUMA information is available. */
|
||||
int uncore_device_to_die(struct pci_dev *dev)
|
||||
{
|
||||
int node = pcibus_to_node(dev->bus);
|
||||
@@ -81,6 +82,25 @@ int uncore_device_to_die(struct pci_dev *dev)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Using cpus_read_lock() to ensure cpu is not going down between
|
||||
* looking at cpu_online_mask.
|
||||
*
|
||||
* The lock must be held by the caller.
|
||||
*/
|
||||
int uncore_die_to_cpu(int die)
|
||||
{
|
||||
int res = -1, cpu;
|
||||
|
||||
for_each_online_cpu(cpu) {
|
||||
if (topology_logical_die_id(cpu) == die) {
|
||||
res = cpu;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static void uncore_free_pcibus_map(void)
|
||||
{
|
||||
struct pci2phy_map *map, *tmp;
|
||||
@@ -435,7 +455,7 @@ uncore_get_event_constraint(struct intel_uncore_box *box, struct perf_event *eve
|
||||
|
||||
if (type->constraints) {
|
||||
for_each_event_constraint(c, type->constraints) {
|
||||
if ((event->hw.config & c->cmask) == c->code)
|
||||
if (constraint_match(c, event->hw.config))
|
||||
return c;
|
||||
}
|
||||
}
|
||||
@@ -1704,152 +1724,192 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct intel_uncore_init_fun {
|
||||
void (*cpu_init)(void);
|
||||
int (*pci_init)(void);
|
||||
void (*mmio_init)(void);
|
||||
/* Discovery table is required */
|
||||
bool use_discovery;
|
||||
/* The units in the discovery table should be ignored. */
|
||||
int *uncore_units_ignore;
|
||||
};
|
||||
static int uncore_mmio_global_init(int die, u64 ctl)
|
||||
{
|
||||
void __iomem *io_addr;
|
||||
|
||||
static const struct intel_uncore_init_fun nhm_uncore_init __initconst = {
|
||||
io_addr = ioremap(ctl, sizeof(ctl));
|
||||
if (!io_addr)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Clear freeze bit (0) to enable all counters. */
|
||||
writel(0, io_addr);
|
||||
|
||||
iounmap(io_addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uncore_msr_global_init(int die, u64 msr)
|
||||
{
|
||||
int cpu = uncore_die_to_cpu(die);
|
||||
|
||||
if (cpu == -1)
|
||||
return -ENODEV;
|
||||
|
||||
return wrmsrq_on_cpu(cpu, msr, 0);
|
||||
}
|
||||
|
||||
static const struct uncore_plat_init nhm_uncore_init __initconst = {
|
||||
.cpu_init = nhm_uncore_cpu_init,
|
||||
};
|
||||
|
||||
static const struct intel_uncore_init_fun snb_uncore_init __initconst = {
|
||||
static const struct uncore_plat_init snb_uncore_init __initconst = {
|
||||
.cpu_init = snb_uncore_cpu_init,
|
||||
.pci_init = snb_uncore_pci_init,
|
||||
};
|
||||
|
||||
static const struct intel_uncore_init_fun ivb_uncore_init __initconst = {
|
||||
static const struct uncore_plat_init ivb_uncore_init __initconst = {
|
||||
.cpu_init = snb_uncore_cpu_init,
|
||||
.pci_init = ivb_uncore_pci_init,
|
||||
};
|
||||
|
||||
static const struct intel_uncore_init_fun hsw_uncore_init __initconst = {
|
||||
static const struct uncore_plat_init hsw_uncore_init __initconst = {
|
||||
.cpu_init = snb_uncore_cpu_init,
|
||||
.pci_init = hsw_uncore_pci_init,
|
||||
};
|
||||
|
||||
static const struct intel_uncore_init_fun bdw_uncore_init __initconst = {
|
||||
static const struct uncore_plat_init bdw_uncore_init __initconst = {
|
||||
.cpu_init = snb_uncore_cpu_init,
|
||||
.pci_init = bdw_uncore_pci_init,
|
||||
};
|
||||
|
||||
static const struct intel_uncore_init_fun snbep_uncore_init __initconst = {
|
||||
static const struct uncore_plat_init snbep_uncore_init __initconst = {
|
||||
.cpu_init = snbep_uncore_cpu_init,
|
||||
.pci_init = snbep_uncore_pci_init,
|
||||
};
|
||||
|
||||
static const struct intel_uncore_init_fun nhmex_uncore_init __initconst = {
|
||||
static const struct uncore_plat_init nhmex_uncore_init __initconst = {
|
||||
.cpu_init = nhmex_uncore_cpu_init,
|
||||
};
|
||||
|
||||
static const struct intel_uncore_init_fun ivbep_uncore_init __initconst = {
|
||||
static const struct uncore_plat_init ivbep_uncore_init __initconst = {
|
||||
.cpu_init = ivbep_uncore_cpu_init,
|
||||
.pci_init = ivbep_uncore_pci_init,
|
||||
};
|
||||
|
||||
static const struct intel_uncore_init_fun hswep_uncore_init __initconst = {
|
||||
static const struct uncore_plat_init hswep_uncore_init __initconst = {
|
||||
.cpu_init = hswep_uncore_cpu_init,
|
||||
.pci_init = hswep_uncore_pci_init,
|
||||
};
|
||||
|
||||
static const struct intel_uncore_init_fun bdx_uncore_init __initconst = {
|
||||
static const struct uncore_plat_init bdx_uncore_init __initconst = {
|
||||
.cpu_init = bdx_uncore_cpu_init,
|
||||
.pci_init = bdx_uncore_pci_init,
|
||||
};
|
||||
|
||||
static const struct intel_uncore_init_fun knl_uncore_init __initconst = {
|
||||
static const struct uncore_plat_init knl_uncore_init __initconst = {
|
||||
.cpu_init = knl_uncore_cpu_init,
|
||||
.pci_init = knl_uncore_pci_init,
|
||||
};
|
||||
|
||||
static const struct intel_uncore_init_fun skl_uncore_init __initconst = {
|
||||
static const struct uncore_plat_init skl_uncore_init __initconst = {
|
||||
.cpu_init = skl_uncore_cpu_init,
|
||||
.pci_init = skl_uncore_pci_init,
|
||||
};
|
||||
|
||||
static const struct intel_uncore_init_fun skx_uncore_init __initconst = {
|
||||
static const struct uncore_plat_init skx_uncore_init __initconst = {
|
||||
.cpu_init = skx_uncore_cpu_init,
|
||||
.pci_init = skx_uncore_pci_init,
|
||||
};
|
||||
|
||||
static const struct intel_uncore_init_fun icl_uncore_init __initconst = {
|
||||
static const struct uncore_plat_init icl_uncore_init __initconst = {
|
||||
.cpu_init = icl_uncore_cpu_init,
|
||||
.pci_init = skl_uncore_pci_init,
|
||||
};
|
||||
|
||||
static const struct intel_uncore_init_fun tgl_uncore_init __initconst = {
|
||||
static const struct uncore_plat_init tgl_uncore_init __initconst = {
|
||||
.cpu_init = tgl_uncore_cpu_init,
|
||||
.mmio_init = tgl_uncore_mmio_init,
|
||||
};
|
||||
|
||||
static const struct intel_uncore_init_fun tgl_l_uncore_init __initconst = {
|
||||
static const struct uncore_plat_init tgl_l_uncore_init __initconst = {
|
||||
.cpu_init = tgl_uncore_cpu_init,
|
||||
.mmio_init = tgl_l_uncore_mmio_init,
|
||||
};
|
||||
|
||||
static const struct intel_uncore_init_fun rkl_uncore_init __initconst = {
|
||||
static const struct uncore_plat_init rkl_uncore_init __initconst = {
|
||||
.cpu_init = tgl_uncore_cpu_init,
|
||||
.pci_init = skl_uncore_pci_init,
|
||||
};
|
||||
|
||||
static const struct intel_uncore_init_fun adl_uncore_init __initconst = {
|
||||
static const struct uncore_plat_init adl_uncore_init __initconst = {
|
||||
.cpu_init = adl_uncore_cpu_init,
|
||||
.mmio_init = adl_uncore_mmio_init,
|
||||
};
|
||||
|
||||
static const struct intel_uncore_init_fun mtl_uncore_init __initconst = {
|
||||
static const struct uncore_plat_init mtl_uncore_init __initconst = {
|
||||
.cpu_init = mtl_uncore_cpu_init,
|
||||
.mmio_init = adl_uncore_mmio_init,
|
||||
};
|
||||
|
||||
static const struct intel_uncore_init_fun lnl_uncore_init __initconst = {
|
||||
static const struct uncore_plat_init lnl_uncore_init __initconst = {
|
||||
.cpu_init = lnl_uncore_cpu_init,
|
||||
.mmio_init = lnl_uncore_mmio_init,
|
||||
};
|
||||
|
||||
static const struct intel_uncore_init_fun ptl_uncore_init __initconst = {
|
||||
static const struct uncore_plat_init ptl_uncore_init __initconst = {
|
||||
.cpu_init = ptl_uncore_cpu_init,
|
||||
.mmio_init = ptl_uncore_mmio_init,
|
||||
.use_discovery = true,
|
||||
.domain[0].discovery_base = UNCORE_DISCOVERY_MSR,
|
||||
.domain[0].global_init = uncore_mmio_global_init,
|
||||
};
|
||||
|
||||
static const struct intel_uncore_init_fun icx_uncore_init __initconst = {
|
||||
static const struct uncore_plat_init nvl_uncore_init __initconst = {
|
||||
.cpu_init = nvl_uncore_cpu_init,
|
||||
.mmio_init = ptl_uncore_mmio_init,
|
||||
.domain[0].discovery_base = PACKAGE_UNCORE_DISCOVERY_MSR,
|
||||
.domain[0].global_init = uncore_mmio_global_init,
|
||||
};
|
||||
|
||||
static const struct uncore_plat_init icx_uncore_init __initconst = {
|
||||
.cpu_init = icx_uncore_cpu_init,
|
||||
.pci_init = icx_uncore_pci_init,
|
||||
.mmio_init = icx_uncore_mmio_init,
|
||||
};
|
||||
|
||||
static const struct intel_uncore_init_fun snr_uncore_init __initconst = {
|
||||
static const struct uncore_plat_init snr_uncore_init __initconst = {
|
||||
.cpu_init = snr_uncore_cpu_init,
|
||||
.pci_init = snr_uncore_pci_init,
|
||||
.mmio_init = snr_uncore_mmio_init,
|
||||
};
|
||||
|
||||
static const struct intel_uncore_init_fun spr_uncore_init __initconst = {
|
||||
static const struct uncore_plat_init spr_uncore_init __initconst = {
|
||||
.cpu_init = spr_uncore_cpu_init,
|
||||
.pci_init = spr_uncore_pci_init,
|
||||
.mmio_init = spr_uncore_mmio_init,
|
||||
.use_discovery = true,
|
||||
.uncore_units_ignore = spr_uncore_units_ignore,
|
||||
.domain[0].base_is_pci = true,
|
||||
.domain[0].discovery_base = UNCORE_DISCOVERY_TABLE_DEVICE,
|
||||
.domain[0].units_ignore = spr_uncore_units_ignore,
|
||||
};
|
||||
|
||||
static const struct intel_uncore_init_fun gnr_uncore_init __initconst = {
|
||||
static const struct uncore_plat_init gnr_uncore_init __initconst = {
|
||||
.cpu_init = gnr_uncore_cpu_init,
|
||||
.pci_init = gnr_uncore_pci_init,
|
||||
.mmio_init = gnr_uncore_mmio_init,
|
||||
.use_discovery = true,
|
||||
.uncore_units_ignore = gnr_uncore_units_ignore,
|
||||
.domain[0].base_is_pci = true,
|
||||
.domain[0].discovery_base = UNCORE_DISCOVERY_TABLE_DEVICE,
|
||||
.domain[0].units_ignore = gnr_uncore_units_ignore,
|
||||
.domain[0].global_init = uncore_msr_global_init,
|
||||
};
|
||||
|
||||
static const struct intel_uncore_init_fun generic_uncore_init __initconst = {
|
||||
static const struct uncore_plat_init dmr_uncore_init __initconst = {
|
||||
.pci_init = dmr_uncore_pci_init,
|
||||
.mmio_init = dmr_uncore_mmio_init,
|
||||
.domain[0].base_is_pci = true,
|
||||
.domain[0].discovery_base = DMR_UNCORE_DISCOVERY_TABLE_DEVICE,
|
||||
.domain[0].units_ignore = dmr_uncore_imh_units_ignore,
|
||||
.domain[1].discovery_base = CBB_UNCORE_DISCOVERY_MSR,
|
||||
.domain[1].units_ignore = dmr_uncore_cbb_units_ignore,
|
||||
.domain[1].global_init = uncore_mmio_global_init,
|
||||
};
|
||||
|
||||
static const struct uncore_plat_init generic_uncore_init __initconst = {
|
||||
.cpu_init = intel_uncore_generic_uncore_cpu_init,
|
||||
.pci_init = intel_uncore_generic_uncore_pci_init,
|
||||
.mmio_init = intel_uncore_generic_uncore_mmio_init,
|
||||
.domain[0].base_is_pci = true,
|
||||
.domain[0].discovery_base = PCI_ANY_ID,
|
||||
.domain[1].discovery_base = UNCORE_DISCOVERY_MSR,
|
||||
};
|
||||
|
||||
static const struct x86_cpu_id intel_uncore_match[] __initconst = {
|
||||
@@ -1901,6 +1961,8 @@ static const struct x86_cpu_id intel_uncore_match[] __initconst = {
|
||||
X86_MATCH_VFM(INTEL_LUNARLAKE_M, &lnl_uncore_init),
|
||||
X86_MATCH_VFM(INTEL_PANTHERLAKE_L, &ptl_uncore_init),
|
||||
X86_MATCH_VFM(INTEL_WILDCATLAKE_L, &ptl_uncore_init),
|
||||
X86_MATCH_VFM(INTEL_NOVALAKE, &nvl_uncore_init),
|
||||
X86_MATCH_VFM(INTEL_NOVALAKE_L, &nvl_uncore_init),
|
||||
X86_MATCH_VFM(INTEL_SAPPHIRERAPIDS_X, &spr_uncore_init),
|
||||
X86_MATCH_VFM(INTEL_EMERALDRAPIDS_X, &spr_uncore_init),
|
||||
X86_MATCH_VFM(INTEL_GRANITERAPIDS_X, &gnr_uncore_init),
|
||||
@@ -1910,14 +1972,25 @@ static const struct x86_cpu_id intel_uncore_match[] __initconst = {
|
||||
X86_MATCH_VFM(INTEL_ATOM_CRESTMONT_X, &gnr_uncore_init),
|
||||
X86_MATCH_VFM(INTEL_ATOM_CRESTMONT, &gnr_uncore_init),
|
||||
X86_MATCH_VFM(INTEL_ATOM_DARKMONT_X, &gnr_uncore_init),
|
||||
X86_MATCH_VFM(INTEL_DIAMONDRAPIDS_X, &dmr_uncore_init),
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(x86cpu, intel_uncore_match);
|
||||
|
||||
static bool uncore_use_discovery(struct uncore_plat_init *config)
|
||||
{
|
||||
for (int i = 0; i < UNCORE_DISCOVERY_DOMAINS; i++) {
|
||||
if (config->domain[i].discovery_base)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int __init intel_uncore_init(void)
|
||||
{
|
||||
const struct x86_cpu_id *id;
|
||||
struct intel_uncore_init_fun *uncore_init;
|
||||
struct uncore_plat_init *uncore_init;
|
||||
int pret = 0, cret = 0, mret = 0, ret;
|
||||
|
||||
if (boot_cpu_has(X86_FEATURE_HYPERVISOR))
|
||||
@@ -1928,16 +2001,15 @@ static int __init intel_uncore_init(void)
|
||||
|
||||
id = x86_match_cpu(intel_uncore_match);
|
||||
if (!id) {
|
||||
if (!uncore_no_discover && intel_uncore_has_discovery_tables(NULL))
|
||||
uncore_init = (struct intel_uncore_init_fun *)&generic_uncore_init;
|
||||
else
|
||||
uncore_init = (struct uncore_plat_init *)&generic_uncore_init;
|
||||
if (uncore_no_discover || !uncore_discovery(uncore_init))
|
||||
return -ENODEV;
|
||||
} else {
|
||||
uncore_init = (struct intel_uncore_init_fun *)id->driver_data;
|
||||
if (uncore_no_discover && uncore_init->use_discovery)
|
||||
uncore_init = (struct uncore_plat_init *)id->driver_data;
|
||||
if (uncore_no_discover && uncore_use_discovery(uncore_init))
|
||||
return -ENODEV;
|
||||
if (uncore_init->use_discovery &&
|
||||
!intel_uncore_has_discovery_tables(uncore_init->uncore_units_ignore))
|
||||
if (uncore_use_discovery(uncore_init) &&
|
||||
!uncore_discovery(uncore_init))
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
#define UNCORE_EXTRA_PCI_DEV_MAX 4
|
||||
|
||||
#define UNCORE_EVENT_CONSTRAINT(c, n) EVENT_CONSTRAINT(c, n, 0xff)
|
||||
#define UNCORE_EVENT_CONSTRAINT_RANGE(c, e, n) \
|
||||
EVENT_CONSTRAINT_RANGE(c, e, n, 0xff)
|
||||
|
||||
#define UNCORE_IGNORE_END -1
|
||||
|
||||
@@ -47,6 +49,25 @@ struct uncore_event_desc;
|
||||
struct freerunning_counters;
|
||||
struct intel_uncore_topology;
|
||||
|
||||
struct uncore_discovery_domain {
|
||||
/* MSR address or PCI device used as the discovery base */
|
||||
u32 discovery_base;
|
||||
bool base_is_pci;
|
||||
int (*global_init)(int die, u64 ctl);
|
||||
|
||||
/* The units in the discovery table should be ignored. */
|
||||
int *units_ignore;
|
||||
};
|
||||
|
||||
#define UNCORE_DISCOVERY_DOMAINS 2
|
||||
struct uncore_plat_init {
|
||||
void (*cpu_init)(void);
|
||||
int (*pci_init)(void);
|
||||
void (*mmio_init)(void);
|
||||
|
||||
struct uncore_discovery_domain domain[UNCORE_DISCOVERY_DOMAINS];
|
||||
};
|
||||
|
||||
struct intel_uncore_type {
|
||||
const char *name;
|
||||
int num_counters;
|
||||
@@ -215,6 +236,7 @@ struct pci2phy_map *__find_pci2phy_map(int segment);
|
||||
int uncore_pcibus_to_dieid(struct pci_bus *bus);
|
||||
int uncore_die_to_segment(int die);
|
||||
int uncore_device_to_die(struct pci_dev *dev);
|
||||
int uncore_die_to_cpu(int die);
|
||||
|
||||
ssize_t uncore_event_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf);
|
||||
@@ -598,6 +620,8 @@ extern struct pci_extra_dev *uncore_extra_pci_dev;
|
||||
extern struct event_constraint uncore_constraint_empty;
|
||||
extern int spr_uncore_units_ignore[];
|
||||
extern int gnr_uncore_units_ignore[];
|
||||
extern int dmr_uncore_imh_units_ignore[];
|
||||
extern int dmr_uncore_cbb_units_ignore[];
|
||||
|
||||
/* uncore_snb.c */
|
||||
int snb_uncore_pci_init(void);
|
||||
@@ -614,6 +638,7 @@ void adl_uncore_cpu_init(void);
|
||||
void lnl_uncore_cpu_init(void);
|
||||
void mtl_uncore_cpu_init(void);
|
||||
void ptl_uncore_cpu_init(void);
|
||||
void nvl_uncore_cpu_init(void);
|
||||
void tgl_uncore_mmio_init(void);
|
||||
void tgl_l_uncore_mmio_init(void);
|
||||
void adl_uncore_mmio_init(void);
|
||||
@@ -646,6 +671,8 @@ void spr_uncore_mmio_init(void);
|
||||
int gnr_uncore_pci_init(void);
|
||||
void gnr_uncore_cpu_init(void);
|
||||
void gnr_uncore_mmio_init(void);
|
||||
int dmr_uncore_pci_init(void);
|
||||
void dmr_uncore_mmio_init(void);
|
||||
|
||||
/* uncore_nhmex.c */
|
||||
void nhmex_uncore_cpu_init(void);
|
||||
|
||||
@@ -11,24 +11,6 @@
|
||||
static struct rb_root discovery_tables = RB_ROOT;
|
||||
static int num_discovered_types[UNCORE_ACCESS_MAX];
|
||||
|
||||
static bool has_generic_discovery_table(void)
|
||||
{
|
||||
struct pci_dev *dev;
|
||||
int dvsec;
|
||||
|
||||
dev = pci_get_device(PCI_VENDOR_ID_INTEL, UNCORE_DISCOVERY_TABLE_DEVICE, NULL);
|
||||
if (!dev)
|
||||
return false;
|
||||
|
||||
/* A discovery table device has the unique capability ID. */
|
||||
dvsec = pci_find_next_ext_capability(dev, 0, UNCORE_EXT_CAP_ID_DISCOVERY);
|
||||
pci_dev_put(dev);
|
||||
if (dvsec)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int logical_die_id;
|
||||
|
||||
static int get_device_die_id(struct pci_dev *dev)
|
||||
@@ -258,28 +240,30 @@ uncore_insert_box_info(struct uncore_unit_discovery *unit,
|
||||
}
|
||||
|
||||
static bool
|
||||
uncore_ignore_unit(struct uncore_unit_discovery *unit, int *ignore)
|
||||
uncore_ignore_unit(struct uncore_unit_discovery *unit,
|
||||
struct uncore_discovery_domain *domain)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!ignore)
|
||||
if (!domain || !domain->units_ignore)
|
||||
return false;
|
||||
|
||||
for (i = 0; ignore[i] != UNCORE_IGNORE_END ; i++) {
|
||||
if (unit->box_type == ignore[i])
|
||||
for (i = 0; domain->units_ignore[i] != UNCORE_IGNORE_END ; i++) {
|
||||
if (unit->box_type == domain->units_ignore[i])
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int __parse_discovery_table(resource_size_t addr, int die,
|
||||
bool *parsed, int *ignore)
|
||||
static int __parse_discovery_table(struct uncore_discovery_domain *domain,
|
||||
resource_size_t addr, int die, bool *parsed)
|
||||
{
|
||||
struct uncore_global_discovery global;
|
||||
struct uncore_unit_discovery unit;
|
||||
void __iomem *io_addr;
|
||||
unsigned long size;
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
size = UNCORE_DISCOVERY_GLOBAL_MAP_SIZE;
|
||||
@@ -289,19 +273,24 @@ static int __parse_discovery_table(resource_size_t addr, int die,
|
||||
|
||||
/* Read Global Discovery State */
|
||||
memcpy_fromio(&global, io_addr, sizeof(struct uncore_global_discovery));
|
||||
iounmap(io_addr);
|
||||
|
||||
if (uncore_discovery_invalid_unit(global)) {
|
||||
pr_info("Invalid Global Discovery State: 0x%llx 0x%llx 0x%llx\n",
|
||||
global.table1, global.ctl, global.table3);
|
||||
iounmap(io_addr);
|
||||
return -EINVAL;
|
||||
}
|
||||
iounmap(io_addr);
|
||||
|
||||
size = (1 + global.max_units) * global.stride * 8;
|
||||
io_addr = ioremap(addr, size);
|
||||
if (!io_addr)
|
||||
return -ENOMEM;
|
||||
|
||||
if (domain->global_init && domain->global_init(die, global.ctl)) {
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Parsing Unit Discovery State */
|
||||
for (i = 0; i < global.max_units; i++) {
|
||||
memcpy_fromio(&unit, io_addr + (i + 1) * (global.stride * 8),
|
||||
@@ -313,20 +302,22 @@ static int __parse_discovery_table(resource_size_t addr, int die,
|
||||
if (unit.access_type >= UNCORE_ACCESS_MAX)
|
||||
continue;
|
||||
|
||||
if (uncore_ignore_unit(&unit, ignore))
|
||||
if (uncore_ignore_unit(&unit, domain))
|
||||
continue;
|
||||
|
||||
uncore_insert_box_info(&unit, die);
|
||||
}
|
||||
|
||||
*parsed = true;
|
||||
|
||||
out:
|
||||
iounmap(io_addr);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int parse_discovery_table(struct pci_dev *dev, int die,
|
||||
u32 bar_offset, bool *parsed,
|
||||
int *ignore)
|
||||
static int parse_discovery_table(struct uncore_discovery_domain *domain,
|
||||
struct pci_dev *dev, int die,
|
||||
u32 bar_offset, bool *parsed)
|
||||
{
|
||||
resource_size_t addr;
|
||||
u32 val;
|
||||
@@ -346,20 +337,17 @@ static int parse_discovery_table(struct pci_dev *dev, int die,
|
||||
}
|
||||
#endif
|
||||
|
||||
return __parse_discovery_table(addr, die, parsed, ignore);
|
||||
return __parse_discovery_table(domain, addr, die, parsed);
|
||||
}
|
||||
|
||||
static bool intel_uncore_has_discovery_tables_pci(int *ignore)
|
||||
static bool uncore_discovery_pci(struct uncore_discovery_domain *domain)
|
||||
{
|
||||
u32 device, val, entry_id, bar_offset;
|
||||
int die, dvsec = 0, ret = true;
|
||||
struct pci_dev *dev = NULL;
|
||||
bool parsed = false;
|
||||
|
||||
if (has_generic_discovery_table())
|
||||
device = UNCORE_DISCOVERY_TABLE_DEVICE;
|
||||
else
|
||||
device = PCI_ANY_ID;
|
||||
device = domain->discovery_base;
|
||||
|
||||
/*
|
||||
* Start a new search and iterates through the list of
|
||||
@@ -382,10 +370,10 @@ static bool intel_uncore_has_discovery_tables_pci(int *ignore)
|
||||
(val & UNCORE_DISCOVERY_DVSEC2_BIR_MASK) * UNCORE_DISCOVERY_BIR_STEP;
|
||||
|
||||
die = get_device_die_id(dev);
|
||||
if (die < 0)
|
||||
if ((die < 0) || (die >= uncore_max_dies()))
|
||||
continue;
|
||||
|
||||
parse_discovery_table(dev, die, bar_offset, &parsed, ignore);
|
||||
parse_discovery_table(domain, dev, die, bar_offset, &parsed);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -398,7 +386,7 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool intel_uncore_has_discovery_tables_msr(int *ignore)
|
||||
static bool uncore_discovery_msr(struct uncore_discovery_domain *domain)
|
||||
{
|
||||
unsigned long *die_mask;
|
||||
bool parsed = false;
|
||||
@@ -410,31 +398,45 @@ static bool intel_uncore_has_discovery_tables_msr(int *ignore)
|
||||
if (!die_mask)
|
||||
return false;
|
||||
|
||||
cpus_read_lock();
|
||||
for_each_online_cpu(cpu) {
|
||||
die = topology_logical_die_id(cpu);
|
||||
if (__test_and_set_bit(die, die_mask))
|
||||
continue;
|
||||
|
||||
if (rdmsrl_safe_on_cpu(cpu, UNCORE_DISCOVERY_MSR, &base))
|
||||
if (rdmsrq_safe_on_cpu(cpu, domain->discovery_base, &base))
|
||||
continue;
|
||||
|
||||
if (!base)
|
||||
continue;
|
||||
|
||||
__parse_discovery_table(base, die, &parsed, ignore);
|
||||
__parse_discovery_table(domain, base, die, &parsed);
|
||||
}
|
||||
|
||||
cpus_read_unlock();
|
||||
|
||||
kfree(die_mask);
|
||||
return parsed;
|
||||
}
|
||||
|
||||
bool intel_uncore_has_discovery_tables(int *ignore)
|
||||
bool uncore_discovery(struct uncore_plat_init *init)
|
||||
{
|
||||
return intel_uncore_has_discovery_tables_msr(ignore) ||
|
||||
intel_uncore_has_discovery_tables_pci(ignore);
|
||||
struct uncore_discovery_domain *domain;
|
||||
bool ret = false;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < UNCORE_DISCOVERY_DOMAINS; i++) {
|
||||
domain = &init->domain[i];
|
||||
if (domain->discovery_base) {
|
||||
cpus_read_lock();
|
||||
|
||||
if (!domain->base_is_pci)
|
||||
ret |= uncore_discovery_msr(domain);
|
||||
else
|
||||
ret |= uncore_discovery_pci(domain);
|
||||
|
||||
cpus_read_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void intel_uncore_clear_discovery_tables(void)
|
||||
@@ -479,8 +481,8 @@ static u64 intel_generic_uncore_box_ctl(struct intel_uncore_box *box)
|
||||
struct intel_uncore_discovery_unit *unit;
|
||||
|
||||
unit = intel_uncore_find_discovery_unit(box->pmu->type->boxes,
|
||||
-1, box->pmu->pmu_idx);
|
||||
if (WARN_ON_ONCE(!unit))
|
||||
box->dieid, box->pmu->pmu_idx);
|
||||
if (!unit)
|
||||
return 0;
|
||||
|
||||
return unit->addr;
|
||||
@@ -488,17 +490,28 @@ static u64 intel_generic_uncore_box_ctl(struct intel_uncore_box *box)
|
||||
|
||||
void intel_generic_uncore_msr_init_box(struct intel_uncore_box *box)
|
||||
{
|
||||
wrmsrl(intel_generic_uncore_box_ctl(box), GENERIC_PMON_BOX_CTL_INT);
|
||||
u64 box_ctl = intel_generic_uncore_box_ctl(box);
|
||||
|
||||
if (!box_ctl)
|
||||
return;
|
||||
|
||||
wrmsrq(box_ctl, GENERIC_PMON_BOX_CTL_INT);
|
||||
}
|
||||
|
||||
void intel_generic_uncore_msr_disable_box(struct intel_uncore_box *box)
|
||||
{
|
||||
wrmsrl(intel_generic_uncore_box_ctl(box), GENERIC_PMON_BOX_CTL_FRZ);
|
||||
u64 box_ctl = intel_generic_uncore_box_ctl(box);
|
||||
|
||||
if (box_ctl)
|
||||
wrmsrq(box_ctl, GENERIC_PMON_BOX_CTL_FRZ);
|
||||
}
|
||||
|
||||
void intel_generic_uncore_msr_enable_box(struct intel_uncore_box *box)
|
||||
{
|
||||
wrmsrl(intel_generic_uncore_box_ctl(box), 0);
|
||||
u64 box_ctl = intel_generic_uncore_box_ctl(box);
|
||||
|
||||
if (box_ctl)
|
||||
wrmsrq(box_ctl, 0);
|
||||
}
|
||||
|
||||
static void intel_generic_uncore_msr_enable_event(struct intel_uncore_box *box,
|
||||
@@ -547,6 +560,7 @@ bool intel_generic_uncore_assign_hw_event(struct perf_event *event,
|
||||
|
||||
if (box->pci_dev) {
|
||||
box_ctl = UNCORE_DISCOVERY_PCI_BOX_CTRL(box_ctl);
|
||||
|
||||
hwc->config_base = box_ctl + uncore_pci_event_ctl(box, hwc->idx);
|
||||
hwc->event_base = box_ctl + uncore_pci_perf_ctr(box, hwc->idx);
|
||||
return true;
|
||||
@@ -565,27 +579,30 @@ static inline int intel_pci_uncore_box_ctl(struct intel_uncore_box *box)
|
||||
|
||||
void intel_generic_uncore_pci_init_box(struct intel_uncore_box *box)
|
||||
{
|
||||
struct pci_dev *pdev = box->pci_dev;
|
||||
int box_ctl = intel_pci_uncore_box_ctl(box);
|
||||
|
||||
if (!box_ctl)
|
||||
return;
|
||||
|
||||
__set_bit(UNCORE_BOX_FLAG_CTL_OFFS8, &box->flags);
|
||||
pci_write_config_dword(pdev, box_ctl, GENERIC_PMON_BOX_CTL_INT);
|
||||
pci_write_config_dword(box->pci_dev, box_ctl, GENERIC_PMON_BOX_CTL_INT);
|
||||
}
|
||||
|
||||
void intel_generic_uncore_pci_disable_box(struct intel_uncore_box *box)
|
||||
{
|
||||
struct pci_dev *pdev = box->pci_dev;
|
||||
int box_ctl = intel_pci_uncore_box_ctl(box);
|
||||
|
||||
pci_write_config_dword(pdev, box_ctl, GENERIC_PMON_BOX_CTL_FRZ);
|
||||
if (box_ctl)
|
||||
pci_write_config_dword(box->pci_dev, box_ctl,
|
||||
GENERIC_PMON_BOX_CTL_FRZ);
|
||||
}
|
||||
|
||||
void intel_generic_uncore_pci_enable_box(struct intel_uncore_box *box)
|
||||
{
|
||||
struct pci_dev *pdev = box->pci_dev;
|
||||
int box_ctl = intel_pci_uncore_box_ctl(box);
|
||||
|
||||
pci_write_config_dword(pdev, box_ctl, 0);
|
||||
if (box_ctl)
|
||||
pci_write_config_dword(box->pci_dev, box_ctl, 0);
|
||||
}
|
||||
|
||||
static void intel_generic_uncore_pci_enable_event(struct intel_uncore_box *box,
|
||||
|
||||
@@ -2,9 +2,15 @@
|
||||
|
||||
/* Store the full address of the global discovery table */
|
||||
#define UNCORE_DISCOVERY_MSR 0x201e
|
||||
/* Base address of uncore perfmon discovery table for CBB domain */
|
||||
#define CBB_UNCORE_DISCOVERY_MSR 0x710
|
||||
/* Base address of uncore perfmon discovery table for the package */
|
||||
#define PACKAGE_UNCORE_DISCOVERY_MSR 0x711
|
||||
|
||||
/* Generic device ID of a discovery table device */
|
||||
#define UNCORE_DISCOVERY_TABLE_DEVICE 0x09a7
|
||||
/* Device ID used on DMR */
|
||||
#define DMR_UNCORE_DISCOVERY_TABLE_DEVICE 0x09a1
|
||||
/* Capability ID for a discovery table device */
|
||||
#define UNCORE_EXT_CAP_ID_DISCOVERY 0x23
|
||||
/* First DVSEC offset */
|
||||
@@ -136,7 +142,7 @@ struct intel_uncore_discovery_type {
|
||||
u16 num_units; /* number of units */
|
||||
};
|
||||
|
||||
bool intel_uncore_has_discovery_tables(int *ignore);
|
||||
bool uncore_discovery(struct uncore_plat_init *init);
|
||||
void intel_uncore_clear_discovery_tables(void);
|
||||
void intel_uncore_generic_uncore_cpu_init(void);
|
||||
int intel_uncore_generic_uncore_pci_init(void);
|
||||
|
||||
@@ -244,6 +244,30 @@
|
||||
#define MTL_UNC_HBO_CTR 0x2048
|
||||
#define MTL_UNC_HBO_CTRL 0x2042
|
||||
|
||||
/* PTL Low Power Bridge register */
|
||||
#define PTL_UNC_IA_CORE_BRIDGE_PER_CTR0 0x2028
|
||||
#define PTL_UNC_IA_CORE_BRIDGE_PERFEVTSEL0 0x2022
|
||||
|
||||
/* PTL Santa register */
|
||||
#define PTL_UNC_SANTA_CTR0 0x2418
|
||||
#define PTL_UNC_SANTA_CTRL0 0x2412
|
||||
|
||||
/* PTL cNCU register */
|
||||
#define PTL_UNC_CNCU_MSR_OFFSET 0x140
|
||||
|
||||
/* NVL cNCU register */
|
||||
#define NVL_UNC_CNCU_BOX_CTL 0x202e
|
||||
#define NVL_UNC_CNCU_FIXED_CTR 0x2028
|
||||
#define NVL_UNC_CNCU_FIXED_CTRL 0x2022
|
||||
|
||||
/* NVL SANTA register */
|
||||
#define NVL_UNC_SANTA_CTR0 0x2048
|
||||
#define NVL_UNC_SANTA_CTRL0 0x2042
|
||||
|
||||
/* NVL CBOX register */
|
||||
#define NVL_UNC_CBOX_PER_CTR0 0x2108
|
||||
#define NVL_UNC_CBOX_PERFEVTSEL0 0x2102
|
||||
|
||||
DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15");
|
||||
DEFINE_UNCORE_FORMAT_ATTR(chmask, chmask, "config:8-11");
|
||||
@@ -1920,8 +1944,36 @@ void ptl_uncore_mmio_init(void)
|
||||
ptl_uncores);
|
||||
}
|
||||
|
||||
static struct intel_uncore_type ptl_uncore_ia_core_bridge = {
|
||||
.name = "ia_core_bridge",
|
||||
.num_counters = 2,
|
||||
.num_boxes = 1,
|
||||
.perf_ctr_bits = 48,
|
||||
.perf_ctr = PTL_UNC_IA_CORE_BRIDGE_PER_CTR0,
|
||||
.event_ctl = PTL_UNC_IA_CORE_BRIDGE_PERFEVTSEL0,
|
||||
.event_mask = ADL_UNC_RAW_EVENT_MASK,
|
||||
.ops = &icl_uncore_msr_ops,
|
||||
.format_group = &adl_uncore_format_group,
|
||||
};
|
||||
|
||||
static struct intel_uncore_type ptl_uncore_santa = {
|
||||
.name = "santa",
|
||||
.num_counters = 2,
|
||||
.num_boxes = 2,
|
||||
.perf_ctr_bits = 48,
|
||||
.perf_ctr = PTL_UNC_SANTA_CTR0,
|
||||
.event_ctl = PTL_UNC_SANTA_CTRL0,
|
||||
.event_mask = ADL_UNC_RAW_EVENT_MASK,
|
||||
.msr_offset = SNB_UNC_CBO_MSR_OFFSET,
|
||||
.ops = &icl_uncore_msr_ops,
|
||||
.format_group = &adl_uncore_format_group,
|
||||
};
|
||||
|
||||
static struct intel_uncore_type *ptl_msr_uncores[] = {
|
||||
&mtl_uncore_cbox,
|
||||
&ptl_uncore_ia_core_bridge,
|
||||
&ptl_uncore_santa,
|
||||
&mtl_uncore_cncu,
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -1929,7 +1981,40 @@ void ptl_uncore_cpu_init(void)
|
||||
{
|
||||
mtl_uncore_cbox.num_boxes = 6;
|
||||
mtl_uncore_cbox.ops = &lnl_uncore_msr_ops;
|
||||
|
||||
mtl_uncore_cncu.num_counters = 2;
|
||||
mtl_uncore_cncu.num_boxes = 2;
|
||||
mtl_uncore_cncu.msr_offset = PTL_UNC_CNCU_MSR_OFFSET;
|
||||
mtl_uncore_cncu.single_fixed = 0;
|
||||
|
||||
uncore_msr_uncores = ptl_msr_uncores;
|
||||
}
|
||||
|
||||
/* end of Panther Lake uncore support */
|
||||
|
||||
/* Nova Lake uncore support */
|
||||
|
||||
static struct intel_uncore_type *nvl_msr_uncores[] = {
|
||||
&mtl_uncore_cbox,
|
||||
&ptl_uncore_santa,
|
||||
&mtl_uncore_cncu,
|
||||
NULL
|
||||
};
|
||||
|
||||
void nvl_uncore_cpu_init(void)
|
||||
{
|
||||
mtl_uncore_cbox.num_boxes = 12;
|
||||
mtl_uncore_cbox.perf_ctr = NVL_UNC_CBOX_PER_CTR0;
|
||||
mtl_uncore_cbox.event_ctl = NVL_UNC_CBOX_PERFEVTSEL0;
|
||||
|
||||
ptl_uncore_santa.perf_ctr = NVL_UNC_SANTA_CTR0;
|
||||
ptl_uncore_santa.event_ctl = NVL_UNC_SANTA_CTRL0;
|
||||
|
||||
mtl_uncore_cncu.box_ctl = NVL_UNC_CNCU_BOX_CTL;
|
||||
mtl_uncore_cncu.fixed_ctr = NVL_UNC_CNCU_FIXED_CTR;
|
||||
mtl_uncore_cncu.fixed_ctl = NVL_UNC_CNCU_FIXED_CTRL;
|
||||
|
||||
uncore_msr_uncores = nvl_msr_uncores;
|
||||
}
|
||||
|
||||
/* end of Nova Lake uncore support */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -44,6 +44,10 @@ enum extra_reg_type {
|
||||
EXTRA_REG_FE = 4, /* fe_* */
|
||||
EXTRA_REG_SNOOP_0 = 5, /* snoop response 0 */
|
||||
EXTRA_REG_SNOOP_1 = 6, /* snoop response 1 */
|
||||
EXTRA_REG_OMR_0 = 7, /* OMR 0 */
|
||||
EXTRA_REG_OMR_1 = 8, /* OMR 1 */
|
||||
EXTRA_REG_OMR_2 = 9, /* OMR 2 */
|
||||
EXTRA_REG_OMR_3 = 10, /* OMR 3 */
|
||||
|
||||
EXTRA_REG_MAX /* number of entries needed */
|
||||
};
|
||||
@@ -127,6 +131,21 @@ static inline bool is_pebs_counter_event_group(struct perf_event *event)
|
||||
return check_leader_group(event->group_leader, PERF_X86_EVENT_PEBS_CNTR);
|
||||
}
|
||||
|
||||
static inline bool is_acr_event_group(struct perf_event *event)
|
||||
{
|
||||
return event->group_leader->hw.flags & PERF_X86_EVENT_ACR;
|
||||
}
|
||||
|
||||
static inline bool is_acr_self_reload_event(struct perf_event *event)
|
||||
{
|
||||
struct hw_perf_event *hwc = &event->hw;
|
||||
|
||||
if (hwc->idx < 0)
|
||||
return false;
|
||||
|
||||
return test_bit(hwc->idx, (unsigned long *)&hwc->config1);
|
||||
}
|
||||
|
||||
struct amd_nb {
|
||||
int nb_id; /* NorthBridge id */
|
||||
int refcnt; /* reference count */
|
||||
@@ -177,6 +196,13 @@ struct amd_nb {
|
||||
(1ULL << PERF_REG_X86_R14) | \
|
||||
(1ULL << PERF_REG_X86_R15))
|
||||
|
||||
/* user space rdpmc control values */
|
||||
enum {
|
||||
X86_USER_RDPMC_NEVER_ENABLE = 0,
|
||||
X86_USER_RDPMC_CONDITIONAL_ENABLE = 1,
|
||||
X86_USER_RDPMC_ALWAYS_ENABLE = 2,
|
||||
};
|
||||
|
||||
/*
|
||||
* Per register state.
|
||||
*/
|
||||
@@ -268,6 +294,7 @@ struct cpu_hw_events {
|
||||
struct event_constraint *event_constraint[X86_PMC_IDX_MAX];
|
||||
|
||||
int n_excl; /* the number of exclusive events */
|
||||
int n_late_setup; /* the num of events needs late setup */
|
||||
|
||||
unsigned int txn_flags;
|
||||
int is_fake;
|
||||
@@ -276,8 +303,9 @@ struct cpu_hw_events {
|
||||
* Intel DebugStore bits
|
||||
*/
|
||||
struct debug_store *ds;
|
||||
void *ds_pebs_vaddr;
|
||||
void *ds_bts_vaddr;
|
||||
/* DS based PEBS or arch-PEBS buffer address */
|
||||
void *pebs_vaddr;
|
||||
u64 pebs_enabled;
|
||||
int n_pebs;
|
||||
int n_large_pebs;
|
||||
@@ -293,6 +321,12 @@ struct cpu_hw_events {
|
||||
u64 fixed_ctrl_val;
|
||||
u64 active_fixed_ctrl_val;
|
||||
|
||||
/* Intel ACR configuration */
|
||||
u64 acr_cfg_b[X86_PMC_IDX_MAX];
|
||||
u64 acr_cfg_c[X86_PMC_IDX_MAX];
|
||||
/* Cached CFG_C values */
|
||||
u64 cfg_c_val[X86_PMC_IDX_MAX];
|
||||
|
||||
/*
|
||||
* Intel LBR bits
|
||||
*/
|
||||
@@ -714,6 +748,12 @@ enum atom_native_id {
|
||||
skt_native_id = 0x3, /* Skymont */
|
||||
};
|
||||
|
||||
struct arch_pebs_cap {
|
||||
u64 caps;
|
||||
u64 counters;
|
||||
u64 pdists;
|
||||
};
|
||||
|
||||
struct x86_hybrid_pmu {
|
||||
struct pmu pmu;
|
||||
const char *name;
|
||||
@@ -731,6 +771,15 @@ struct x86_hybrid_pmu {
|
||||
u64 fixed_cntr_mask64;
|
||||
unsigned long fixed_cntr_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
|
||||
};
|
||||
|
||||
union {
|
||||
u64 acr_cntr_mask64;
|
||||
unsigned long acr_cntr_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
|
||||
};
|
||||
union {
|
||||
u64 acr_cause_mask64;
|
||||
unsigned long acr_cause_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
|
||||
};
|
||||
struct event_constraint unconstrained;
|
||||
|
||||
u64 hw_cache_event_ids
|
||||
@@ -749,6 +798,8 @@ struct x86_hybrid_pmu {
|
||||
mid_ack :1,
|
||||
enabled_ack :1;
|
||||
|
||||
struct arch_pebs_cap arch_pebs_cap;
|
||||
|
||||
u64 pebs_data_source[PERF_PEBS_DATA_SOURCE_MAX];
|
||||
};
|
||||
|
||||
@@ -813,6 +864,10 @@ struct x86_pmu {
|
||||
int (*hw_config)(struct perf_event *event);
|
||||
int (*schedule_events)(struct cpu_hw_events *cpuc, int n, int *assign);
|
||||
void (*late_setup)(void);
|
||||
void (*pebs_enable)(struct perf_event *event);
|
||||
void (*pebs_disable)(struct perf_event *event);
|
||||
void (*pebs_enable_all)(void);
|
||||
void (*pebs_disable_all)(void);
|
||||
unsigned eventsel;
|
||||
unsigned perfctr;
|
||||
unsigned fixedctr;
|
||||
@@ -829,6 +884,14 @@ struct x86_pmu {
|
||||
u64 fixed_cntr_mask64;
|
||||
unsigned long fixed_cntr_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
|
||||
};
|
||||
union {
|
||||
u64 acr_cntr_mask64;
|
||||
unsigned long acr_cntr_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
|
||||
};
|
||||
union {
|
||||
u64 acr_cause_mask64;
|
||||
unsigned long acr_cause_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
|
||||
};
|
||||
int cntval_bits;
|
||||
u64 cntval_mask;
|
||||
union {
|
||||
@@ -891,18 +954,19 @@ struct x86_pmu {
|
||||
union perf_capabilities intel_cap;
|
||||
|
||||
/*
|
||||
* Intel DebugStore bits
|
||||
* Intel DebugStore and PEBS bits
|
||||
*/
|
||||
unsigned int bts :1,
|
||||
bts_active :1,
|
||||
pebs :1,
|
||||
ds_pebs :1,
|
||||
pebs_active :1,
|
||||
pebs_broken :1,
|
||||
pebs_prec_dist :1,
|
||||
pebs_no_tlb :1,
|
||||
pebs_no_isolation :1,
|
||||
pebs_block :1,
|
||||
pebs_ept :1;
|
||||
pebs_ept :1,
|
||||
arch_pebs :1;
|
||||
int pebs_record_size;
|
||||
int pebs_buffer_size;
|
||||
u64 pebs_events_mask;
|
||||
@@ -914,6 +978,11 @@ struct x86_pmu {
|
||||
u64 rtm_abort_event;
|
||||
u64 pebs_capable;
|
||||
|
||||
/*
|
||||
* Intel Architectural PEBS
|
||||
*/
|
||||
struct arch_pebs_cap arch_pebs_cap;
|
||||
|
||||
/*
|
||||
* Intel LBR
|
||||
*/
|
||||
@@ -1073,6 +1142,8 @@ do { \
|
||||
#define PMU_FL_MEM_LOADS_AUX 0x100 /* Require an auxiliary event for the complete memory info */
|
||||
#define PMU_FL_RETIRE_LATENCY 0x200 /* Support Retire Latency in PEBS */
|
||||
#define PMU_FL_BR_CNTR 0x400 /* Support branch counter logging */
|
||||
#define PMU_FL_DYN_CONSTRAINT 0x800 /* Needs dynamic constraint */
|
||||
#define PMU_FL_HAS_OMR 0x1000 /* has 4 equivalent OMR regs */
|
||||
|
||||
#define EVENT_VAR(_id) event_attr_##_id
|
||||
#define EVENT_PTR(_id) &event_attr_##_id.attr.attr
|
||||
@@ -1115,6 +1186,7 @@ static struct perf_pmu_format_hybrid_attr format_attr_hybrid_##_name = {\
|
||||
.pmu_type = _pmu, \
|
||||
}
|
||||
|
||||
int is_x86_event(struct perf_event *event);
|
||||
struct pmu *x86_get_pmu(unsigned int cpu);
|
||||
extern struct x86_pmu x86_pmu __read_mostly;
|
||||
|
||||
@@ -1122,6 +1194,10 @@ DECLARE_STATIC_CALL(x86_pmu_set_period, *x86_pmu.set_period);
|
||||
DECLARE_STATIC_CALL(x86_pmu_update, *x86_pmu.update);
|
||||
DECLARE_STATIC_CALL(x86_pmu_drain_pebs, *x86_pmu.drain_pebs);
|
||||
DECLARE_STATIC_CALL(x86_pmu_late_setup, *x86_pmu.late_setup);
|
||||
DECLARE_STATIC_CALL(x86_pmu_pebs_enable, *x86_pmu.pebs_enable);
|
||||
DECLARE_STATIC_CALL(x86_pmu_pebs_disable, *x86_pmu.pebs_disable);
|
||||
DECLARE_STATIC_CALL(x86_pmu_pebs_enable_all, *x86_pmu.pebs_enable_all);
|
||||
DECLARE_STATIC_CALL(x86_pmu_pebs_disable_all, *x86_pmu.pebs_disable_all);
|
||||
|
||||
static __always_inline struct x86_perf_task_context_opt *task_context_opt(void *ctx)
|
||||
{
|
||||
@@ -1203,7 +1279,7 @@ int x86_reserve_hardware(void);
|
||||
|
||||
void x86_release_hardware(void);
|
||||
|
||||
int x86_pmu_max_precise(void);
|
||||
int x86_pmu_max_precise(struct pmu *pmu);
|
||||
|
||||
void hw_perf_lbr_event_destroy(struct perf_event *event);
|
||||
|
||||
@@ -1291,6 +1367,12 @@ static inline u64 x86_pmu_get_event_config(struct perf_event *event)
|
||||
return event->attr.config & hybrid(event->pmu, config_mask);
|
||||
}
|
||||
|
||||
static inline bool x86_pmu_has_rdpmc_user_disable(struct pmu *pmu)
|
||||
{
|
||||
return !!(hybrid(pmu, config_mask) &
|
||||
ARCH_PERFMON_EVENTSEL_RDPMC_USER_DISABLE);
|
||||
}
|
||||
|
||||
extern struct event_constraint emptyconstraint;
|
||||
|
||||
extern struct event_constraint unconstrained;
|
||||
@@ -1587,6 +1669,14 @@ extern void intel_cpuc_finish(struct cpu_hw_events *cpuc);
|
||||
|
||||
int intel_pmu_init(void);
|
||||
|
||||
int alloc_arch_pebs_buf_on_cpu(int cpu);
|
||||
|
||||
void release_arch_pebs_buf_on_cpu(int cpu);
|
||||
|
||||
void init_arch_pebs_on_cpu(int cpu);
|
||||
|
||||
void fini_arch_pebs_on_cpu(int cpu);
|
||||
|
||||
void init_debug_store_on_cpu(int cpu);
|
||||
|
||||
void fini_debug_store_on_cpu(int cpu);
|
||||
@@ -1608,6 +1698,8 @@ void intel_pmu_disable_bts(void);
|
||||
|
||||
int intel_pmu_drain_bts_buffer(void);
|
||||
|
||||
void intel_pmu_late_setup(void);
|
||||
|
||||
u64 grt_latency_data(struct perf_event *event, u64 status);
|
||||
|
||||
u64 cmt_latency_data(struct perf_event *event, u64 status);
|
||||
@@ -1616,6 +1708,10 @@ u64 lnl_latency_data(struct perf_event *event, u64 status);
|
||||
|
||||
u64 arl_h_latency_data(struct perf_event *event, u64 status);
|
||||
|
||||
u64 pnc_latency_data(struct perf_event *event, u64 status);
|
||||
|
||||
u64 nvl_latency_data(struct perf_event *event, u64 status);
|
||||
|
||||
extern struct event_constraint intel_core2_pebs_event_constraints[];
|
||||
|
||||
extern struct event_constraint intel_atom_pebs_event_constraints[];
|
||||
@@ -1628,6 +1724,8 @@ extern struct event_constraint intel_glp_pebs_event_constraints[];
|
||||
|
||||
extern struct event_constraint intel_grt_pebs_event_constraints[];
|
||||
|
||||
extern struct event_constraint intel_arw_pebs_event_constraints[];
|
||||
|
||||
extern struct event_constraint intel_nehalem_pebs_event_constraints[];
|
||||
|
||||
extern struct event_constraint intel_westmere_pebs_event_constraints[];
|
||||
@@ -1648,6 +1746,8 @@ extern struct event_constraint intel_glc_pebs_event_constraints[];
|
||||
|
||||
extern struct event_constraint intel_lnc_pebs_event_constraints[];
|
||||
|
||||
extern struct event_constraint intel_pnc_pebs_event_constraints[];
|
||||
|
||||
struct event_constraint *intel_pebs_constraints(struct perf_event *event);
|
||||
|
||||
void intel_pmu_pebs_add(struct perf_event *event);
|
||||
@@ -1664,11 +1764,13 @@ void intel_pmu_pebs_disable_all(void);
|
||||
|
||||
void intel_pmu_pebs_sched_task(struct perf_event_pmu_context *pmu_ctx, bool sched_in);
|
||||
|
||||
void intel_pmu_pebs_late_setup(struct cpu_hw_events *cpuc);
|
||||
|
||||
void intel_pmu_drain_pebs_buffer(void);
|
||||
|
||||
void intel_pmu_store_pebs_lbrs(struct lbr_entry *lbr);
|
||||
|
||||
void intel_ds_init(void);
|
||||
void intel_pebs_init(void);
|
||||
|
||||
void intel_pmu_lbr_save_brstack(struct perf_sample_data *data,
|
||||
struct cpu_hw_events *cpuc,
|
||||
@@ -1741,6 +1843,8 @@ void intel_pmu_pebs_data_source_cmt(void);
|
||||
|
||||
void intel_pmu_pebs_data_source_lnl(void);
|
||||
|
||||
u64 intel_get_arch_pebs_data_config(struct perf_event *event);
|
||||
|
||||
int intel_pmu_setup_lbr_filter(struct perf_event *event);
|
||||
|
||||
void intel_pt_interrupt(void);
|
||||
@@ -1773,6 +1877,11 @@ static inline int intel_pmu_max_num_pebs(struct pmu *pmu)
|
||||
return fls((u32)hybrid(pmu, pebs_events_mask));
|
||||
}
|
||||
|
||||
static inline bool intel_pmu_has_pebs(void)
|
||||
{
|
||||
return x86_pmu.ds_pebs || x86_pmu.arch_pebs;
|
||||
}
|
||||
|
||||
#else /* CONFIG_CPU_SUP_INTEL */
|
||||
|
||||
static inline void reserve_ds_buffers(void)
|
||||
|
||||
@@ -4,7 +4,15 @@
|
||||
#include <linux/percpu-defs.h>
|
||||
|
||||
#define BTS_BUFFER_SIZE (PAGE_SIZE << 4)
|
||||
#define PEBS_BUFFER_SIZE (PAGE_SIZE << 4)
|
||||
#define PEBS_BUFFER_SHIFT 4
|
||||
#define PEBS_BUFFER_SIZE (PAGE_SIZE << PEBS_BUFFER_SHIFT)
|
||||
|
||||
/*
|
||||
* The largest PEBS record could consume a page, ensure
|
||||
* a record at least can be written after triggering PMI.
|
||||
*/
|
||||
#define ARCH_PEBS_THRESH_MULTI ((PEBS_BUFFER_SIZE - PAGE_SIZE) >> PEBS_BUFFER_SHIFT)
|
||||
#define ARCH_PEBS_THRESH_SINGLE 1
|
||||
|
||||
/* The maximal number of PEBS events: */
|
||||
#define MAX_PEBS_EVENTS_FMT4 8
|
||||
|
||||
@@ -550,12 +550,12 @@ struct kvm_pmu {
|
||||
unsigned nr_arch_fixed_counters;
|
||||
unsigned available_event_types;
|
||||
u64 fixed_ctr_ctrl;
|
||||
u64 fixed_ctr_ctrl_mask;
|
||||
u64 fixed_ctr_ctrl_rsvd;
|
||||
u64 global_ctrl;
|
||||
u64 global_status;
|
||||
u64 counter_bitmask[2];
|
||||
u64 global_ctrl_mask;
|
||||
u64 global_status_mask;
|
||||
u64 global_ctrl_rsvd;
|
||||
u64 global_status_rsvd;
|
||||
u64 reserved_bits;
|
||||
u64 raw_event_mask;
|
||||
struct kvm_pmc gp_counters[KVM_INTEL_PMC_MAX_GENERIC];
|
||||
@@ -575,9 +575,9 @@ struct kvm_pmu {
|
||||
|
||||
u64 ds_area;
|
||||
u64 pebs_enable;
|
||||
u64 pebs_enable_mask;
|
||||
u64 pebs_enable_rsvd;
|
||||
u64 pebs_data_cfg;
|
||||
u64 pebs_data_cfg_mask;
|
||||
u64 pebs_data_cfg_rsvd;
|
||||
|
||||
/*
|
||||
* If a guest counter is cross-mapped to host counter with different
|
||||
|
||||
@@ -232,6 +232,11 @@
|
||||
#define MSR_SNOOP_RSP_0 0x00001328
|
||||
#define MSR_SNOOP_RSP_1 0x00001329
|
||||
|
||||
#define MSR_OMR_0 0x000003e0
|
||||
#define MSR_OMR_1 0x000003e1
|
||||
#define MSR_OMR_2 0x000003e2
|
||||
#define MSR_OMR_3 0x000003e3
|
||||
|
||||
#define MSR_LBR_SELECT 0x000001c8
|
||||
#define MSR_LBR_TOS 0x000001c9
|
||||
|
||||
@@ -288,12 +293,34 @@
|
||||
#define PERF_CAP_PT_IDX 16
|
||||
|
||||
#define MSR_PEBS_LD_LAT_THRESHOLD 0x000003f6
|
||||
#define PERF_CAP_PEBS_TRAP BIT_ULL(6)
|
||||
#define PERF_CAP_ARCH_REG BIT_ULL(7)
|
||||
#define PERF_CAP_PEBS_FORMAT 0xf00
|
||||
#define PERF_CAP_PEBS_BASELINE BIT_ULL(14)
|
||||
#define PERF_CAP_PEBS_MASK (PERF_CAP_PEBS_TRAP | PERF_CAP_ARCH_REG | \
|
||||
PERF_CAP_PEBS_FORMAT | PERF_CAP_PEBS_BASELINE)
|
||||
#define PERF_CAP_PEBS_TRAP BIT_ULL(6)
|
||||
#define PERF_CAP_ARCH_REG BIT_ULL(7)
|
||||
#define PERF_CAP_PEBS_FORMAT 0xf00
|
||||
#define PERF_CAP_PEBS_BASELINE BIT_ULL(14)
|
||||
#define PERF_CAP_PEBS_TIMING_INFO BIT_ULL(17)
|
||||
#define PERF_CAP_PEBS_MASK (PERF_CAP_PEBS_TRAP | PERF_CAP_ARCH_REG | \
|
||||
PERF_CAP_PEBS_FORMAT | PERF_CAP_PEBS_BASELINE | \
|
||||
PERF_CAP_PEBS_TIMING_INFO)
|
||||
|
||||
/* Arch PEBS */
|
||||
#define MSR_IA32_PEBS_BASE 0x000003f4
|
||||
#define MSR_IA32_PEBS_INDEX 0x000003f5
|
||||
#define ARCH_PEBS_OFFSET_MASK 0x7fffff
|
||||
#define ARCH_PEBS_INDEX_WR_SHIFT 4
|
||||
|
||||
#define ARCH_PEBS_RELOAD 0xffffffff
|
||||
#define ARCH_PEBS_CNTR_ALLOW BIT_ULL(35)
|
||||
#define ARCH_PEBS_CNTR_GP BIT_ULL(36)
|
||||
#define ARCH_PEBS_CNTR_FIXED BIT_ULL(37)
|
||||
#define ARCH_PEBS_CNTR_METRICS BIT_ULL(38)
|
||||
#define ARCH_PEBS_LBR_SHIFT 40
|
||||
#define ARCH_PEBS_LBR (0x3ull << ARCH_PEBS_LBR_SHIFT)
|
||||
#define ARCH_PEBS_VECR_XMM BIT_ULL(49)
|
||||
#define ARCH_PEBS_GPR BIT_ULL(61)
|
||||
#define ARCH_PEBS_AUX BIT_ULL(62)
|
||||
#define ARCH_PEBS_EN BIT_ULL(63)
|
||||
#define ARCH_PEBS_CNTR_MASK (ARCH_PEBS_CNTR_GP | ARCH_PEBS_CNTR_FIXED | \
|
||||
ARCH_PEBS_CNTR_METRICS)
|
||||
|
||||
#define MSR_IA32_RTIT_CTL 0x00000570
|
||||
#define RTIT_CTL_TRACEEN BIT(0)
|
||||
@@ -570,7 +597,11 @@
|
||||
/* V6 PMON MSR range */
|
||||
#define MSR_IA32_PMC_V6_GP0_CTR 0x1900
|
||||
#define MSR_IA32_PMC_V6_GP0_CFG_A 0x1901
|
||||
#define MSR_IA32_PMC_V6_GP0_CFG_B 0x1902
|
||||
#define MSR_IA32_PMC_V6_GP0_CFG_C 0x1903
|
||||
#define MSR_IA32_PMC_V6_FX0_CTR 0x1980
|
||||
#define MSR_IA32_PMC_V6_FX0_CFG_B 0x1982
|
||||
#define MSR_IA32_PMC_V6_FX0_CFG_C 0x1983
|
||||
#define MSR_IA32_PMC_V6_STEP 4
|
||||
|
||||
/* KeyID partitioning between MKTME and TDX */
|
||||
|
||||
@@ -33,14 +33,15 @@
|
||||
#define ARCH_PERFMON_EVENTSEL_CMASK 0xFF000000ULL
|
||||
#define ARCH_PERFMON_EVENTSEL_BR_CNTR (1ULL << 35)
|
||||
#define ARCH_PERFMON_EVENTSEL_EQ (1ULL << 36)
|
||||
#define ARCH_PERFMON_EVENTSEL_RDPMC_USER_DISABLE (1ULL << 37)
|
||||
#define ARCH_PERFMON_EVENTSEL_UMASK2 (0xFFULL << 40)
|
||||
|
||||
#define INTEL_FIXED_BITS_MASK 0xFULL
|
||||
#define INTEL_FIXED_BITS_STRIDE 4
|
||||
#define INTEL_FIXED_0_KERNEL (1ULL << 0)
|
||||
#define INTEL_FIXED_0_USER (1ULL << 1)
|
||||
#define INTEL_FIXED_0_ANYTHREAD (1ULL << 2)
|
||||
#define INTEL_FIXED_0_ENABLE_PMI (1ULL << 3)
|
||||
#define INTEL_FIXED_0_RDPMC_USER_DISABLE (1ULL << 33)
|
||||
#define INTEL_FIXED_3_METRICS_CLEAR (1ULL << 2)
|
||||
|
||||
#define HSW_IN_TX (1ULL << 32)
|
||||
@@ -48,6 +49,11 @@
|
||||
#define ICL_EVENTSEL_ADAPTIVE (1ULL << 34)
|
||||
#define ICL_FIXED_0_ADAPTIVE (1ULL << 32)
|
||||
|
||||
#define INTEL_FIXED_BITS_MASK \
|
||||
(INTEL_FIXED_0_KERNEL | INTEL_FIXED_0_USER | \
|
||||
INTEL_FIXED_0_ANYTHREAD | INTEL_FIXED_0_ENABLE_PMI | \
|
||||
ICL_FIXED_0_ADAPTIVE | INTEL_FIXED_0_RDPMC_USER_DISABLE)
|
||||
|
||||
#define intel_fixed_bits_by_idx(_idx, _bits) \
|
||||
((_bits) << ((_idx) * INTEL_FIXED_BITS_STRIDE))
|
||||
|
||||
@@ -137,16 +143,16 @@
|
||||
#define ARCH_PERFMON_EVENTS_COUNT 7
|
||||
|
||||
#define PEBS_DATACFG_MEMINFO BIT_ULL(0)
|
||||
#define PEBS_DATACFG_GP BIT_ULL(1)
|
||||
#define PEBS_DATACFG_GP BIT_ULL(1)
|
||||
#define PEBS_DATACFG_XMMS BIT_ULL(2)
|
||||
#define PEBS_DATACFG_LBRS BIT_ULL(3)
|
||||
#define PEBS_DATACFG_LBR_SHIFT 24
|
||||
#define PEBS_DATACFG_CNTR BIT_ULL(4)
|
||||
#define PEBS_DATACFG_METRICS BIT_ULL(5)
|
||||
#define PEBS_DATACFG_LBR_SHIFT 24
|
||||
#define PEBS_DATACFG_CNTR_SHIFT 32
|
||||
#define PEBS_DATACFG_CNTR_MASK GENMASK_ULL(15, 0)
|
||||
#define PEBS_DATACFG_FIX_SHIFT 48
|
||||
#define PEBS_DATACFG_FIX_MASK GENMASK_ULL(7, 0)
|
||||
#define PEBS_DATACFG_METRICS BIT_ULL(5)
|
||||
|
||||
/* Steal the highest bit of pebs_data_cfg for SW usage */
|
||||
#define PEBS_UPDATE_DS_SW BIT_ULL(63)
|
||||
@@ -194,10 +200,40 @@ union cpuid10_edx {
|
||||
* detection/enumeration details:
|
||||
*/
|
||||
#define ARCH_PERFMON_EXT_LEAF 0x00000023
|
||||
#define ARCH_PERFMON_EXT_UMASK2 0x1
|
||||
#define ARCH_PERFMON_EXT_EQ 0x2
|
||||
#define ARCH_PERFMON_NUM_COUNTER_LEAF_BIT 0x1
|
||||
#define ARCH_PERFMON_NUM_COUNTER_LEAF 0x1
|
||||
#define ARCH_PERFMON_ACR_LEAF 0x2
|
||||
#define ARCH_PERFMON_PEBS_CAP_LEAF 0x4
|
||||
#define ARCH_PERFMON_PEBS_COUNTER_LEAF 0x5
|
||||
|
||||
union cpuid35_eax {
|
||||
struct {
|
||||
unsigned int leaf0:1;
|
||||
/* Counters Sub-Leaf */
|
||||
unsigned int cntr_subleaf:1;
|
||||
/* Auto Counter Reload Sub-Leaf */
|
||||
unsigned int acr_subleaf:1;
|
||||
/* Events Sub-Leaf */
|
||||
unsigned int events_subleaf:1;
|
||||
/* arch-PEBS Sub-Leaves */
|
||||
unsigned int pebs_caps_subleaf:1;
|
||||
unsigned int pebs_cnts_subleaf:1;
|
||||
unsigned int reserved:26;
|
||||
} split;
|
||||
unsigned int full;
|
||||
};
|
||||
|
||||
union cpuid35_ebx {
|
||||
struct {
|
||||
/* UnitMask2 Supported */
|
||||
unsigned int umask2:1;
|
||||
/* EQ-bit Supported */
|
||||
unsigned int eq:1;
|
||||
/* rdpmc user disable Supported */
|
||||
unsigned int rdpmc_user_disable:1;
|
||||
unsigned int reserved:29;
|
||||
} split;
|
||||
unsigned int full;
|
||||
};
|
||||
|
||||
/*
|
||||
* Intel Architectural LBR CPUID detection/enumeration details:
|
||||
@@ -405,9 +441,11 @@ static inline bool is_topdown_idx(int idx)
|
||||
#define GLOBAL_STATUS_LBRS_FROZEN BIT_ULL(GLOBAL_STATUS_LBRS_FROZEN_BIT)
|
||||
#define GLOBAL_STATUS_TRACE_TOPAPMI_BIT 55
|
||||
#define GLOBAL_STATUS_TRACE_TOPAPMI BIT_ULL(GLOBAL_STATUS_TRACE_TOPAPMI_BIT)
|
||||
#define GLOBAL_STATUS_ARCH_PEBS_THRESHOLD_BIT 54
|
||||
#define GLOBAL_STATUS_ARCH_PEBS_THRESHOLD BIT_ULL(GLOBAL_STATUS_ARCH_PEBS_THRESHOLD_BIT)
|
||||
#define GLOBAL_STATUS_PERF_METRICS_OVF_BIT 48
|
||||
|
||||
#define GLOBAL_CTRL_EN_PERF_METRICS 48
|
||||
#define GLOBAL_CTRL_EN_PERF_METRICS BIT_ULL(48)
|
||||
/*
|
||||
* We model guest LBR event tracing as another fixed-mode PMC like BTS.
|
||||
*
|
||||
@@ -475,6 +513,107 @@ struct pebs_cntr_header {
|
||||
|
||||
#define INTEL_CNTR_METRICS 0x3
|
||||
|
||||
/*
|
||||
* Arch PEBS
|
||||
*/
|
||||
union arch_pebs_index {
|
||||
struct {
|
||||
u64 rsvd:4,
|
||||
wr:23,
|
||||
rsvd2:4,
|
||||
full:1,
|
||||
en:1,
|
||||
rsvd3:3,
|
||||
thresh:23,
|
||||
rsvd4:5;
|
||||
};
|
||||
u64 whole;
|
||||
};
|
||||
|
||||
struct arch_pebs_header {
|
||||
union {
|
||||
u64 format;
|
||||
struct {
|
||||
u64 size:16, /* Record size */
|
||||
rsvd:14,
|
||||
mode:1, /* 64BIT_MODE */
|
||||
cont:1,
|
||||
rsvd2:3,
|
||||
cntr:5,
|
||||
lbr:2,
|
||||
rsvd3:7,
|
||||
xmm:1,
|
||||
ymmh:1,
|
||||
rsvd4:2,
|
||||
opmask:1,
|
||||
zmmh:1,
|
||||
h16zmm:1,
|
||||
rsvd5:5,
|
||||
gpr:1,
|
||||
aux:1,
|
||||
basic:1;
|
||||
};
|
||||
};
|
||||
u64 rsvd6;
|
||||
};
|
||||
|
||||
struct arch_pebs_basic {
|
||||
u64 ip;
|
||||
u64 applicable_counters;
|
||||
u64 tsc;
|
||||
u64 retire :16, /* Retire Latency */
|
||||
valid :1,
|
||||
rsvd :47;
|
||||
u64 rsvd2;
|
||||
u64 rsvd3;
|
||||
};
|
||||
|
||||
struct arch_pebs_aux {
|
||||
u64 address;
|
||||
u64 rsvd;
|
||||
u64 rsvd2;
|
||||
u64 rsvd3;
|
||||
u64 rsvd4;
|
||||
u64 aux;
|
||||
u64 instr_latency :16,
|
||||
pad2 :16,
|
||||
cache_latency :16,
|
||||
pad3 :16;
|
||||
u64 tsx_tuning;
|
||||
};
|
||||
|
||||
struct arch_pebs_gprs {
|
||||
u64 flags, ip, ax, cx, dx, bx, sp, bp, si, di;
|
||||
u64 r8, r9, r10, r11, r12, r13, r14, r15, ssp;
|
||||
u64 rsvd;
|
||||
};
|
||||
|
||||
struct arch_pebs_xer_header {
|
||||
u64 xstate;
|
||||
u64 rsvd;
|
||||
};
|
||||
|
||||
#define ARCH_PEBS_LBR_NAN 0x0
|
||||
#define ARCH_PEBS_LBR_NUM_8 0x1
|
||||
#define ARCH_PEBS_LBR_NUM_16 0x2
|
||||
#define ARCH_PEBS_LBR_NUM_VAR 0x3
|
||||
#define ARCH_PEBS_BASE_LBR_ENTRIES 8
|
||||
struct arch_pebs_lbr_header {
|
||||
u64 rsvd;
|
||||
u64 ctl;
|
||||
u64 depth;
|
||||
u64 ler_from;
|
||||
u64 ler_to;
|
||||
u64 ler_info;
|
||||
};
|
||||
|
||||
struct arch_pebs_cntr_header {
|
||||
u32 cntr;
|
||||
u32 fixed;
|
||||
u32 metrics;
|
||||
u32 reserved;
|
||||
};
|
||||
|
||||
/*
|
||||
* AMD Extended Performance Monitoring and Debug cpuid feature detection
|
||||
*/
|
||||
|
||||
+13
-13
@@ -469,11 +469,11 @@ static int reprogram_counter(struct kvm_pmc *pmc)
|
||||
if (pmc_is_fixed(pmc)) {
|
||||
fixed_ctr_ctrl = fixed_ctrl_field(pmu->fixed_ctr_ctrl,
|
||||
pmc->idx - KVM_FIXED_PMC_BASE_IDX);
|
||||
if (fixed_ctr_ctrl & 0x1)
|
||||
if (fixed_ctr_ctrl & INTEL_FIXED_0_KERNEL)
|
||||
eventsel |= ARCH_PERFMON_EVENTSEL_OS;
|
||||
if (fixed_ctr_ctrl & 0x2)
|
||||
if (fixed_ctr_ctrl & INTEL_FIXED_0_USER)
|
||||
eventsel |= ARCH_PERFMON_EVENTSEL_USR;
|
||||
if (fixed_ctr_ctrl & 0x8)
|
||||
if (fixed_ctr_ctrl & INTEL_FIXED_0_ENABLE_PMI)
|
||||
eventsel |= ARCH_PERFMON_EVENTSEL_INT;
|
||||
new_config = (u64)fixed_ctr_ctrl;
|
||||
}
|
||||
@@ -681,13 +681,13 @@ int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
||||
if (!msr_info->host_initiated)
|
||||
break;
|
||||
|
||||
if (data & pmu->global_status_mask)
|
||||
if (data & pmu->global_status_rsvd)
|
||||
return 1;
|
||||
|
||||
pmu->global_status = data;
|
||||
break;
|
||||
case MSR_AMD64_PERF_CNTR_GLOBAL_CTL:
|
||||
data &= ~pmu->global_ctrl_mask;
|
||||
data &= ~pmu->global_ctrl_rsvd;
|
||||
fallthrough;
|
||||
case MSR_CORE_PERF_GLOBAL_CTRL:
|
||||
if (!kvm_valid_perf_global_ctrl(pmu, data))
|
||||
@@ -704,7 +704,7 @@ int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
||||
* GLOBAL_OVF_CTRL, a.k.a. GLOBAL STATUS_RESET, clears bits in
|
||||
* GLOBAL_STATUS, and so the set of reserved bits is the same.
|
||||
*/
|
||||
if (data & pmu->global_status_mask)
|
||||
if (data & pmu->global_status_rsvd)
|
||||
return 1;
|
||||
fallthrough;
|
||||
case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR:
|
||||
@@ -768,11 +768,11 @@ void kvm_pmu_refresh(struct kvm_vcpu *vcpu)
|
||||
pmu->counter_bitmask[KVM_PMC_FIXED] = 0;
|
||||
pmu->reserved_bits = 0xffffffff00200000ull;
|
||||
pmu->raw_event_mask = X86_RAW_EVENT_MASK;
|
||||
pmu->global_ctrl_mask = ~0ull;
|
||||
pmu->global_status_mask = ~0ull;
|
||||
pmu->fixed_ctr_ctrl_mask = ~0ull;
|
||||
pmu->pebs_enable_mask = ~0ull;
|
||||
pmu->pebs_data_cfg_mask = ~0ull;
|
||||
pmu->global_ctrl_rsvd = ~0ull;
|
||||
pmu->global_status_rsvd = ~0ull;
|
||||
pmu->fixed_ctr_ctrl_rsvd = ~0ull;
|
||||
pmu->pebs_enable_rsvd = ~0ull;
|
||||
pmu->pebs_data_cfg_rsvd = ~0ull;
|
||||
bitmap_zero(pmu->all_valid_pmc_idx, X86_PMC_IDX_MAX);
|
||||
|
||||
if (!vcpu->kvm->arch.enable_pmu)
|
||||
@@ -846,8 +846,8 @@ static inline bool cpl_is_matched(struct kvm_pmc *pmc)
|
||||
} else {
|
||||
config = fixed_ctrl_field(pmc_to_pmu(pmc)->fixed_ctr_ctrl,
|
||||
pmc->idx - KVM_FIXED_PMC_BASE_IDX);
|
||||
select_os = config & 0x1;
|
||||
select_user = config & 0x2;
|
||||
select_os = config & INTEL_FIXED_0_KERNEL;
|
||||
select_user = config & INTEL_FIXED_0_USER;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+6
-4
@@ -13,8 +13,9 @@
|
||||
#define MSR_IA32_MISC_ENABLE_PMU_RO_MASK (MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL | \
|
||||
MSR_IA32_MISC_ENABLE_BTS_UNAVAIL)
|
||||
|
||||
/* retrieve the 4 bits for EN and PMI out of IA32_FIXED_CTR_CTRL */
|
||||
#define fixed_ctrl_field(ctrl_reg, idx) (((ctrl_reg) >> ((idx)*4)) & 0xf)
|
||||
/* retrieve a fixed counter bits out of IA32_FIXED_CTR_CTRL */
|
||||
#define fixed_ctrl_field(ctrl_reg, idx) \
|
||||
(((ctrl_reg) >> ((idx) * INTEL_FIXED_BITS_STRIDE)) & INTEL_FIXED_BITS_MASK)
|
||||
|
||||
#define VMWARE_BACKDOOR_PMC_HOST_TSC 0x10000
|
||||
#define VMWARE_BACKDOOR_PMC_REAL_TIME 0x10001
|
||||
@@ -129,7 +130,7 @@ static inline bool pmc_is_fixed(struct kvm_pmc *pmc)
|
||||
static inline bool kvm_valid_perf_global_ctrl(struct kvm_pmu *pmu,
|
||||
u64 data)
|
||||
{
|
||||
return !(pmu->global_ctrl_mask & data);
|
||||
return !(pmu->global_ctrl_rsvd & data);
|
||||
}
|
||||
|
||||
/* returns general purpose PMC with the specified MSR. Note that it can be
|
||||
@@ -170,7 +171,8 @@ static inline bool pmc_speculative_in_use(struct kvm_pmc *pmc)
|
||||
|
||||
if (pmc_is_fixed(pmc))
|
||||
return fixed_ctrl_field(pmu->fixed_ctr_ctrl,
|
||||
pmc->idx - KVM_FIXED_PMC_BASE_IDX) & 0x3;
|
||||
pmc->idx - KVM_FIXED_PMC_BASE_IDX) &
|
||||
(INTEL_FIXED_0_KERNEL | INTEL_FIXED_0_USER);
|
||||
|
||||
return pmc->eventsel & ARCH_PERFMON_EVENTSEL_ENABLE;
|
||||
}
|
||||
|
||||
@@ -199,8 +199,8 @@ static void amd_pmu_refresh(struct kvm_vcpu *vcpu)
|
||||
kvm_pmu_cap.num_counters_gp);
|
||||
|
||||
if (pmu->version > 1) {
|
||||
pmu->global_ctrl_mask = ~((1ull << pmu->nr_arch_gp_counters) - 1);
|
||||
pmu->global_status_mask = pmu->global_ctrl_mask;
|
||||
pmu->global_ctrl_rsvd = ~((1ull << pmu->nr_arch_gp_counters) - 1);
|
||||
pmu->global_status_rsvd = pmu->global_ctrl_rsvd;
|
||||
}
|
||||
|
||||
pmu->counter_bitmask[KVM_PMC_GP] = ((u64)1 << 48) - 1;
|
||||
|
||||
@@ -389,14 +389,14 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
||||
|
||||
switch (msr) {
|
||||
case MSR_CORE_PERF_FIXED_CTR_CTRL:
|
||||
if (data & pmu->fixed_ctr_ctrl_mask)
|
||||
if (data & pmu->fixed_ctr_ctrl_rsvd)
|
||||
return 1;
|
||||
|
||||
if (pmu->fixed_ctr_ctrl != data)
|
||||
reprogram_fixed_counters(pmu, data);
|
||||
break;
|
||||
case MSR_IA32_PEBS_ENABLE:
|
||||
if (data & pmu->pebs_enable_mask)
|
||||
if (data & pmu->pebs_enable_rsvd)
|
||||
return 1;
|
||||
|
||||
if (pmu->pebs_enable != data) {
|
||||
@@ -412,7 +412,7 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
||||
pmu->ds_area = data;
|
||||
break;
|
||||
case MSR_PEBS_DATA_CFG:
|
||||
if (data & pmu->pebs_data_cfg_mask)
|
||||
if (data & pmu->pebs_data_cfg_rsvd)
|
||||
return 1;
|
||||
|
||||
pmu->pebs_data_cfg = data;
|
||||
@@ -497,7 +497,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu)
|
||||
union cpuid10_eax eax;
|
||||
union cpuid10_edx edx;
|
||||
u64 perf_capabilities;
|
||||
u64 counter_mask;
|
||||
u64 counter_rsvd;
|
||||
int i;
|
||||
|
||||
if (!lbr_desc)
|
||||
@@ -546,21 +546,26 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu)
|
||||
}
|
||||
|
||||
for (i = 0; i < pmu->nr_arch_fixed_counters; i++)
|
||||
pmu->fixed_ctr_ctrl_mask &= ~(0xbull << (i * 4));
|
||||
counter_mask = ~(((1ull << pmu->nr_arch_gp_counters) - 1) |
|
||||
pmu->fixed_ctr_ctrl_rsvd &=
|
||||
~intel_fixed_bits_by_idx(i,
|
||||
INTEL_FIXED_0_KERNEL |
|
||||
INTEL_FIXED_0_USER |
|
||||
INTEL_FIXED_0_ENABLE_PMI);
|
||||
|
||||
counter_rsvd = ~(((1ull << pmu->nr_arch_gp_counters) - 1) |
|
||||
(((1ull << pmu->nr_arch_fixed_counters) - 1) << KVM_FIXED_PMC_BASE_IDX));
|
||||
pmu->global_ctrl_mask = counter_mask;
|
||||
pmu->global_ctrl_rsvd = counter_rsvd;
|
||||
|
||||
/*
|
||||
* GLOBAL_STATUS and GLOBAL_OVF_CONTROL (a.k.a. GLOBAL_STATUS_RESET)
|
||||
* share reserved bit definitions. The kernel just happens to use
|
||||
* OVF_CTRL for the names.
|
||||
*/
|
||||
pmu->global_status_mask = pmu->global_ctrl_mask
|
||||
pmu->global_status_rsvd = pmu->global_ctrl_rsvd
|
||||
& ~(MSR_CORE_PERF_GLOBAL_OVF_CTRL_OVF_BUF |
|
||||
MSR_CORE_PERF_GLOBAL_OVF_CTRL_COND_CHGD);
|
||||
if (vmx_pt_mode_is_host_guest())
|
||||
pmu->global_status_mask &=
|
||||
pmu->global_status_rsvd &=
|
||||
~MSR_CORE_PERF_GLOBAL_OVF_CTRL_TRACE_TOPA_PMI;
|
||||
|
||||
entry = kvm_find_cpuid_entry_index(vcpu, 7, 0);
|
||||
@@ -588,15 +593,14 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu)
|
||||
|
||||
if (perf_capabilities & PERF_CAP_PEBS_FORMAT) {
|
||||
if (perf_capabilities & PERF_CAP_PEBS_BASELINE) {
|
||||
pmu->pebs_enable_mask = counter_mask;
|
||||
pmu->pebs_enable_rsvd = counter_rsvd;
|
||||
pmu->reserved_bits &= ~ICL_EVENTSEL_ADAPTIVE;
|
||||
for (i = 0; i < pmu->nr_arch_fixed_counters; i++) {
|
||||
pmu->fixed_ctr_ctrl_mask &=
|
||||
~(1ULL << (KVM_FIXED_PMC_BASE_IDX + i * 4));
|
||||
}
|
||||
pmu->pebs_data_cfg_mask = ~0xff00000full;
|
||||
for (i = 0; i < pmu->nr_arch_fixed_counters; i++)
|
||||
pmu->fixed_ctr_ctrl_rsvd &=
|
||||
~intel_fixed_bits_by_idx(i, ICL_FIXED_0_ADAPTIVE);
|
||||
pmu->pebs_data_cfg_rsvd = ~0xff00000full;
|
||||
} else {
|
||||
pmu->pebs_enable_mask =
|
||||
pmu->pebs_enable_rsvd =
|
||||
~((1ull << pmu->nr_arch_gp_counters) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,7 +157,9 @@ struct hw_perf_event {
|
||||
union {
|
||||
struct { /* hardware */
|
||||
u64 config;
|
||||
u64 config1;
|
||||
u64 last_tag;
|
||||
u64 dyn_constraint;
|
||||
unsigned long config_base;
|
||||
unsigned long event_base;
|
||||
int event_base_rdpmc;
|
||||
@@ -1285,6 +1287,11 @@ static inline void perf_sample_save_callchain(struct perf_sample_data *data,
|
||||
{
|
||||
int size = 1;
|
||||
|
||||
if (!(event->attr.sample_type & PERF_SAMPLE_CALLCHAIN))
|
||||
return;
|
||||
if (WARN_ON_ONCE(data->sample_flags & PERF_SAMPLE_CALLCHAIN))
|
||||
return;
|
||||
|
||||
data->callchain = perf_callchain(event, regs);
|
||||
size += data->callchain->nr;
|
||||
|
||||
@@ -1324,6 +1331,9 @@ static inline void perf_sample_save_brstack(struct perf_sample_data *data,
|
||||
|
||||
if (branch_sample_hw_index(event))
|
||||
size += sizeof(u64);
|
||||
|
||||
brs->nr = min_t(u16, event->attr.sample_max_stack, brs->nr);
|
||||
|
||||
size += brs->nr * sizeof(struct perf_branch_entry);
|
||||
|
||||
/*
|
||||
|
||||
+343
-310
File diff suppressed because it is too large
Load Diff
@@ -281,12 +281,14 @@
|
||||
#define PERF_CAP_PT_IDX 16
|
||||
|
||||
#define MSR_PEBS_LD_LAT_THRESHOLD 0x000003f6
|
||||
#define PERF_CAP_PEBS_TRAP BIT_ULL(6)
|
||||
#define PERF_CAP_ARCH_REG BIT_ULL(7)
|
||||
#define PERF_CAP_PEBS_FORMAT 0xf00
|
||||
#define PERF_CAP_PEBS_BASELINE BIT_ULL(14)
|
||||
#define PERF_CAP_PEBS_MASK (PERF_CAP_PEBS_TRAP | PERF_CAP_ARCH_REG | \
|
||||
PERF_CAP_PEBS_FORMAT | PERF_CAP_PEBS_BASELINE)
|
||||
#define PERF_CAP_PEBS_TRAP BIT_ULL(6)
|
||||
#define PERF_CAP_ARCH_REG BIT_ULL(7)
|
||||
#define PERF_CAP_PEBS_FORMAT 0xf00
|
||||
#define PERF_CAP_PEBS_BASELINE BIT_ULL(14)
|
||||
#define PERF_CAP_PEBS_TIMING_INFO BIT_ULL(17)
|
||||
#define PERF_CAP_PEBS_MASK (PERF_CAP_PEBS_TRAP | PERF_CAP_ARCH_REG | \
|
||||
PERF_CAP_PEBS_FORMAT | PERF_CAP_PEBS_BASELINE | \
|
||||
PERF_CAP_PEBS_TIMING_INFO)
|
||||
|
||||
#define MSR_IA32_RTIT_CTL 0x00000570
|
||||
#define RTIT_CTL_TRACEEN BIT(0)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -880,6 +880,7 @@ static bool perf_pmu__match_ignoring_suffix(const char *pmu_name, const char *to
|
||||
{
|
||||
const char *p, *suffix;
|
||||
bool has_hex = false;
|
||||
bool has_underscore = false;
|
||||
|
||||
if (strncmp(pmu_name, tok, strlen(tok)))
|
||||
return false;
|
||||
@@ -888,13 +889,14 @@ static bool perf_pmu__match_ignoring_suffix(const char *pmu_name, const char *to
|
||||
if (*p == 0)
|
||||
return true;
|
||||
|
||||
if (*p == '_') {
|
||||
++p;
|
||||
++suffix;
|
||||
}
|
||||
|
||||
/* Ensure we end in a number */
|
||||
/* Ensure we end in a number or a mix of number and "_". */
|
||||
while (1) {
|
||||
if (!has_underscore && (*p == '_')) {
|
||||
has_underscore = true;
|
||||
++p;
|
||||
++suffix;
|
||||
}
|
||||
|
||||
if (!isxdigit(*p))
|
||||
return false;
|
||||
if (!has_hex)
|
||||
|
||||
Reference in New Issue
Block a user