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:
CKI KWF Bot
2026-08-20 12:21:15 +00:00
29 changed files with 3970 additions and 1365 deletions
@@ -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.
+1 -2
View File
@@ -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, &regs);
+69 -20
View File
@@ -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);
+6 -2
View File
@@ -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);
File diff suppressed because it is too large Load Diff
+25 -7
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -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);
+1 -1
View File
@@ -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
View File
@@ -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;
}
+27
View File
@@ -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);
+76 -59
View File
@@ -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,
+7 -1
View File
@@ -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);
+85
View File
@@ -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
+115 -6
View File
@@ -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)
+9 -1
View File
@@ -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
+5 -5
View File
@@ -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
+37 -6
View File
@@ -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 */
+147 -8
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
+2 -2
View File
@@ -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;
+20 -16
View File
@@ -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);
}
}
+10
View File
@@ -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);
/*
File diff suppressed because it is too large Load Diff
+8 -6
View File
@@ -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
+8 -6
View File
@@ -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)