You need to sign in or sign up before continuing.
未验证 提交 ba08f661 编写于 作者: O openeuler-ci-bot 提交者: Gitee

!119 Add new perf monitor features for amd epyc platforms

Merge Pull Request from: @haochengxie 
 
Add new perf features, backporting these patches from mainline:
1.Performance Monitor Global Controls
2.IBS(Instrument Based Sample)extensions
3.BRS(Branch Sample)

Patches been relied:
69372cf0   5.11   x86/cpu: Add VM page flush MSR availablility as a CPUID feature
fb35d30f   5.12   x86/cpufeatures: Assign dedicated feature word for CPUID_0x8000001F[EAX]

Perf BRS:
bfe4daf8   5.19   perf/core: Add perf_clear_branch_entry_bitfields() helper
a77d41ac   5.19   x86/cpufeatures: Add AMD Fam19h Branch Sampling feature
ada54345   5.19   perf/x86/amd: Add AMD Fam19h Branch Sampling support
44175993   5.19   perf/x86/amd: Add branch-brs helper event for Fam19h BRS
8910075d   5.19   perf/x86/amd: Enable branch sampling priv level filtering
ba2fe750   5.19   perf/x86/amd: Add AMD branch sampling period adjustment
cc37e520   5.19   perf/x86/amd: Make Zen3 branch sampling opt-in
2a606a18   5.19   ACPI: Add perf low power callback
d5616bac   5.19   perf/x86/amd: Add idle hooks for branch sampling

PerfmonV2 controls:
d6d0c7f6
089be16d
21d59e3e
56e026a7   5.19-rc1    PerfmonV2 Controls for Core PMU series
9622e67e
7685665c
bae19fdd  

Perf IBS:
6a371baf   5.15       perf/x86/amd/ibs: Add bitfield definitions in new <asm/amd-ibs.h> header
3d47083b   5.19       perf/amd/ibs: Use interrupt regs ip for stack unwinding
39b2ca75   5.19       perf/amd/ibs: Cascade pmu init functions' return value
2a7a7e65   5.19       perf/amd/ibs: Use ->is_visible callback for dynamic attributes
ba5d35b4   5.19-rc1   perf/amd/ibs: Add support for L3 miss filtering
838de1d8   5.19-rc1   perf/amd/ibs: Advertise zen4_ibs_extensions as pmu capability attribute
 
 
Link:https://gitee.com/openeuler/kernel/pulls/119 
Reviewed-by: Zheng Zengkai <zhengzengkai@huawei.com> 
Signed-off-by: Zheng Zengkai <zhengzengkai@huawei.com> 
...@@ -34,4 +34,11 @@ config PERF_EVENTS_AMD_POWER ...@@ -34,4 +34,11 @@ config PERF_EVENTS_AMD_POWER
(CPUID Fn8000_0007_EDX[12]) interface to calculate the (CPUID Fn8000_0007_EDX[12]) interface to calculate the
average power consumption on Family 15h processors. average power consumption on Family 15h processors.
config PERF_EVENTS_AMD_BRS
depends on PERF_EVENTS && CPU_SUP_AMD
bool "AMD Zen3 Branch Sampling support"
help
Enable AMD Zen3 branch sampling support (BRS) which samples up to
16 consecutive taken branches in registers.
endmenu endmenu
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_CPU_SUP_AMD) += core.o uncore.o obj-$(CONFIG_CPU_SUP_AMD) += core.o uncore.o
obj-$(CONFIG_PERF_EVENTS_AMD_BRS) += brs.o
obj-$(CONFIG_PERF_EVENTS_AMD_POWER) += power.o obj-$(CONFIG_PERF_EVENTS_AMD_POWER) += power.o
obj-$(CONFIG_X86_LOCAL_APIC) += ibs.o obj-$(CONFIG_X86_LOCAL_APIC) += ibs.o
ifdef CONFIG_AMD_IOMMU ifdef CONFIG_AMD_IOMMU
......
// SPDX-License-Identifier: GPL-2.0
/*
* Implement support for AMD Fam19h Branch Sampling feature
* Based on specifications published in AMD PPR Fam19 Model 01
*
* Copyright 2021 Google LLC
* Contributed by Stephane Eranian <eranian@google.com>
*/
#include <linux/kernel.h>
#include <linux/jump_label.h>
#include <asm/msr.h>
#include <asm/cpufeature.h>
#include "../perf_event.h"
#define BRS_POISON 0xFFFFFFFFFFFFFFFEULL /* mark limit of valid entries */
/* Debug Extension Configuration register layout */
union amd_debug_extn_cfg {
__u64 val;
struct {
__u64 rsvd0:2, /* reserved */
brsmen:1, /* branch sample enable */
rsvd4_3:2,/* reserved - must be 0x3 */
vb:1, /* valid branches recorded */
rsvd2:10, /* reserved */
msroff:4, /* index of next entry to write */
rsvd3:4, /* reserved */
pmc:3, /* #PMC holding the sampling event */
rsvd4:37; /* reserved */
};
};
static inline unsigned int brs_from(int idx)
{
return MSR_AMD_SAMP_BR_FROM + 2 * idx;
}
static inline unsigned int brs_to(int idx)
{
return MSR_AMD_SAMP_BR_FROM + 2 * idx + 1;
}
static inline void set_debug_extn_cfg(u64 val)
{
/* bits[4:3] must always be set to 11b */
wrmsrl(MSR_AMD_DBG_EXTN_CFG, val | 3ULL << 3);
}
static inline u64 get_debug_extn_cfg(void)
{
u64 val;
rdmsrl(MSR_AMD_DBG_EXTN_CFG, val);
return val;
}
static bool __init amd_brs_detect(void)
{
if (!boot_cpu_has(X86_FEATURE_BRS))
return false;
switch (boot_cpu_data.x86) {
case 0x19: /* AMD Fam19h (Zen3) */
x86_pmu.lbr_nr = 16;
/* No hardware filtering supported */
x86_pmu.lbr_sel_map = NULL;
x86_pmu.lbr_sel_mask = 0;
break;
default:
return false;
}
return true;
}
/*
* Current BRS implementation does not support branch type or privilege level
* filtering. Therefore, this function simply enforces these limitations. No need for
* a br_sel_map. Software filtering is not supported because it would not correlate well
* with a sampling period.
*/
int amd_brs_setup_filter(struct perf_event *event)
{
u64 type = event->attr.branch_sample_type;
/* No BRS support */
if (!x86_pmu.lbr_nr)
return -EOPNOTSUPP;
/* Can only capture all branches, i.e., no filtering */
if ((type & ~PERF_SAMPLE_BRANCH_PLM_ALL) != PERF_SAMPLE_BRANCH_ANY)
return -EINVAL;
return 0;
}
/* tos = top of stack, i.e., last valid entry written */
static inline int amd_brs_get_tos(union amd_debug_extn_cfg *cfg)
{
/*
* msroff: index of next entry to write so top-of-stack is one off
* if BRS is full then msroff is set back to 0.
*/
return (cfg->msroff ? cfg->msroff : x86_pmu.lbr_nr) - 1;
}
/*
* make sure we have a sane BRS offset to begin with
* especially with kexec
*/
void amd_brs_reset(void)
{
/*
* Reset config
*/
set_debug_extn_cfg(0);
/*
* Mark first entry as poisoned
*/
wrmsrl(brs_to(0), BRS_POISON);
}
int __init amd_brs_init(void)
{
if (!amd_brs_detect())
return -EOPNOTSUPP;
pr_cont("%d-deep BRS, ", x86_pmu.lbr_nr);
return 0;
}
void amd_brs_enable(void)
{
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
union amd_debug_extn_cfg cfg;
/* Activate only on first user */
if (++cpuc->brs_active > 1)
return;
cfg.val = 0; /* reset all fields */
cfg.brsmen = 1; /* enable branch sampling */
/* Set enable bit */
set_debug_extn_cfg(cfg.val);
}
void amd_brs_enable_all(void)
{
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
if (cpuc->lbr_users)
amd_brs_enable();
}
void amd_brs_disable(void)
{
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
union amd_debug_extn_cfg cfg;
/* Check if active (could be disabled via x86_pmu_disable_all()) */
if (!cpuc->brs_active)
return;
/* Only disable for last user */
if (--cpuc->brs_active)
return;
/*
* Clear the brsmen bit but preserve the others as they contain
* useful state such as vb and msroff
*/
cfg.val = get_debug_extn_cfg();
/*
* When coming in on interrupt and BRS is full, then hw will have
* already stopped BRS, no need to issue wrmsr again
*/
if (cfg.brsmen) {
cfg.brsmen = 0;
set_debug_extn_cfg(cfg.val);
}
}
void amd_brs_disable_all(void)
{
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
if (cpuc->lbr_users)
amd_brs_disable();
}
static bool amd_brs_match_plm(struct perf_event *event, u64 to)
{
int type = event->attr.branch_sample_type;
int plm_k = PERF_SAMPLE_BRANCH_KERNEL | PERF_SAMPLE_BRANCH_HV;
int plm_u = PERF_SAMPLE_BRANCH_USER;
if (!(type & plm_k) && kernel_ip(to))
return 0;
if (!(type & plm_u) && !kernel_ip(to))
return 0;
return 1;
}
/*
* Caller must ensure amd_brs_inuse() is true before calling
* return:
*/
void amd_brs_drain(void)
{
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
struct perf_event *event = cpuc->events[0];
struct perf_branch_entry *br = cpuc->lbr_entries;
union amd_debug_extn_cfg cfg;
u32 i, nr = 0, num, tos, start;
u32 shift = 64 - boot_cpu_data.x86_virt_bits;
/*
* BRS event forced on PMC0,
* so check if there is an event.
* It is possible to have lbr_users > 0 but the event
* not yet scheduled due to long latency PMU irq
*/
if (!event)
goto empty;
cfg.val = get_debug_extn_cfg();
/* Sanity check [0-x86_pmu.lbr_nr] */
if (WARN_ON_ONCE(cfg.msroff >= x86_pmu.lbr_nr))
goto empty;
/* No valid branch */
if (cfg.vb == 0)
goto empty;
/*
* msr.off points to next entry to be written
* tos = most recent entry index = msr.off - 1
* BRS register buffer saturates, so we know we have
* start < tos and that we have to read from start to tos
*/
start = 0;
tos = amd_brs_get_tos(&cfg);
num = tos - start + 1;
/*
* BRS is only one pass (saturation) from MSROFF to depth-1
* MSROFF wraps to zero when buffer is full
*/
for (i = 0; i < num; i++) {
u32 brs_idx = tos - i;
u64 from, to;
rdmsrl(brs_to(brs_idx), to);
/* Entry does not belong to us (as marked by kernel) */
if (to == BRS_POISON)
break;
/*
* Sign-extend SAMP_BR_TO to 64 bits, bits 61-63 are reserved.
* Necessary to generate proper virtual addresses suitable for
* symbolization
*/
to = (u64)(((s64)to << shift) >> shift);
if (!amd_brs_match_plm(event, to))
continue;
rdmsrl(brs_from(brs_idx), from);
perf_clear_branch_entry_bitfields(br+nr);
br[nr].from = from;
br[nr].to = to;
nr++;
}
empty:
/* Record number of sampled branches */
cpuc->lbr_stack.nr = nr;
}
/*
* Poison most recent entry to prevent reuse by next task
* required because BRS entry are not tagged by PID
*/
static void amd_brs_poison_buffer(void)
{
union amd_debug_extn_cfg cfg;
unsigned int idx;
/* Get current state */
cfg.val = get_debug_extn_cfg();
/* idx is most recently written entry */
idx = amd_brs_get_tos(&cfg);
/* Poison target of entry */
wrmsrl(brs_to(idx), BRS_POISON);
}
/*
* On context switch in, we need to make sure no samples from previous user
* are left in the BRS.
*
* On ctxswin, sched_in = true, called after the PMU has started
* On ctxswout, sched_in = false, called before the PMU is stopped
*/
void amd_pmu_brs_sched_task(struct perf_event_context *ctx, bool sched_in)
{
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
/* no active users */
if (!cpuc->lbr_users)
return;
/*
* On context switch in, we need to ensure we do not use entries
* from previous BRS user on that CPU, so we poison the buffer as
* a faster way compared to resetting all entries.
*/
if (sched_in)
amd_brs_poison_buffer();
}
/*
* called from ACPI processor_idle.c or acpi_pad.c
* with interrupts disabled
*/
void perf_amd_brs_lopwr_cb(bool lopwr_in)
{
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
union amd_debug_extn_cfg cfg;
/*
* on mwait in, we may end up in non C0 state.
* we must disable branch sampling to avoid holding the NMI
* for too long. We disable it in hardware but we
* keep the state in cpuc, so we can re-enable.
*
* The hardware will deliver the NMI if needed when brsmen cleared
*/
if (cpuc->brs_active) {
cfg.val = get_debug_extn_cfg();
cfg.brsmen = !lopwr_in;
set_debug_extn_cfg(cfg.val);
}
}
DEFINE_STATIC_CALL_NULL(perf_lopwr_cb, perf_amd_brs_lopwr_cb);
EXPORT_STATIC_CALL_TRAMP_GPL(perf_lopwr_cb);
void __init amd_brs_lopwr_init(void)
{
static_call_update(perf_lopwr_cb, perf_amd_brs_lopwr_cb);
}
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
#include <linux/perf_event.h> #include <linux/perf_event.h>
#include <linux/jump_label.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -7,6 +8,7 @@ ...@@ -7,6 +8,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <asm/apicdef.h> #include <asm/apicdef.h>
#include <asm/apic.h>
#include <asm/nmi.h> #include <asm/nmi.h>
#include "../perf_event.h" #include "../perf_event.h"
...@@ -18,6 +20,9 @@ static unsigned long perf_nmi_window; ...@@ -18,6 +20,9 @@ static unsigned long perf_nmi_window;
#define AMD_MERGE_EVENT ((0xFULL << 32) | 0xFFULL) #define AMD_MERGE_EVENT ((0xFULL << 32) | 0xFFULL)
#define AMD_MERGE_EVENT_ENABLE (AMD_MERGE_EVENT | ARCH_PERFMON_EVENTSEL_ENABLE) #define AMD_MERGE_EVENT_ENABLE (AMD_MERGE_EVENT | ARCH_PERFMON_EVENTSEL_ENABLE)
/* PMC Enable and Overflow bits for PerfCntrGlobal* registers */
static u64 amd_pmu_global_cntr_mask __read_mostly;
static __initconst const u64 amd_hw_cache_event_ids static __initconst const u64 amd_hw_cache_event_ids
[PERF_COUNT_HW_CACHE_MAX] [PERF_COUNT_HW_CACHE_MAX]
[PERF_COUNT_HW_CACHE_OP_MAX] [PERF_COUNT_HW_CACHE_OP_MAX]
...@@ -325,8 +330,16 @@ static inline bool amd_is_pair_event_code(struct hw_perf_event *hwc) ...@@ -325,8 +330,16 @@ static inline bool amd_is_pair_event_code(struct hw_perf_event *hwc)
} }
} }
#define AMD_FAM19H_BRS_EVENT 0xc4 /* RETIRED_TAKEN_BRANCH_INSTRUCTIONS */
static inline int amd_is_brs_event(struct perf_event *e)
{
return (e->hw.config & AMD64_RAW_EVENT_MASK) == AMD_FAM19H_BRS_EVENT;
}
static int amd_core_hw_config(struct perf_event *event) static int amd_core_hw_config(struct perf_event *event)
{ {
int ret = 0;
if (event->attr.exclude_host && event->attr.exclude_guest) if (event->attr.exclude_host && event->attr.exclude_guest)
/* /*
* When HO == GO == 1 the hardware treats that as GO == HO == 0 * When HO == GO == 1 the hardware treats that as GO == HO == 0
...@@ -343,7 +356,66 @@ static int amd_core_hw_config(struct perf_event *event) ...@@ -343,7 +356,66 @@ static int amd_core_hw_config(struct perf_event *event)
if ((x86_pmu.flags & PMU_FL_PAIR) && amd_is_pair_event_code(&event->hw)) if ((x86_pmu.flags & PMU_FL_PAIR) && amd_is_pair_event_code(&event->hw))
event->hw.flags |= PERF_X86_EVENT_PAIR; event->hw.flags |= PERF_X86_EVENT_PAIR;
return 0; /*
* if branch stack is requested
*/
if (has_branch_stack(event)) {
/*
* Due to interrupt holding, BRS is not recommended in
* counting mode.
*/
if (!is_sampling_event(event))
return -EINVAL;
/*
* Due to the way BRS operates by holding the interrupt until
* lbr_nr entries have been captured, it does not make sense
* to allow sampling on BRS with an event that does not match
* what BRS is capturing, i.e., retired taken branches.
* Otherwise the correlation with the event's period is even
* more loose:
*
* With retired taken branch:
* Effective P = P + 16 + X
* With any other event:
* Effective P = P + Y + X
*
* Where X is the number of taken branches due to interrupt
* skid. Skid is large.
*
* Where Y is the occurences of the event while BRS is
* capturing the lbr_nr entries.
*
* By using retired taken branches, we limit the impact on the
* Y variable. We know it cannot be more than the depth of
* BRS.
*/
if (!amd_is_brs_event(event))
return -EINVAL;
/*
* BRS implementation does not work with frequency mode
* reprogramming of the period.
*/
if (event->attr.freq)
return -EINVAL;
/*
* The kernel subtracts BRS depth from period, so it must
* be big enough.
*/
if (event->attr.sample_period <= x86_pmu.lbr_nr)
return -EINVAL;
/*
* Check if we can allow PERF_SAMPLE_BRANCH_STACK
*/
ret = amd_brs_setup_filter(event);
/* only set in case of success */
if (!ret)
event->hw.flags |= PERF_X86_EVENT_AMD_BRS;
}
return ret;
} }
static inline int amd_is_nb_event(struct hw_perf_event *hwc) static inline int amd_is_nb_event(struct hw_perf_event *hwc)
...@@ -366,7 +438,7 @@ static int amd_pmu_hw_config(struct perf_event *event) ...@@ -366,7 +438,7 @@ static int amd_pmu_hw_config(struct perf_event *event)
if (event->attr.precise_ip && get_ibs_caps()) if (event->attr.precise_ip && get_ibs_caps())
return -ENOENT; return -ENOENT;
if (has_branch_stack(event)) if (has_branch_stack(event) && !x86_pmu.lbr_nr)
return -EOPNOTSUPP; return -EOPNOTSUPP;
ret = x86_pmu_hw_config(event); ret = x86_pmu_hw_config(event);
...@@ -510,6 +582,18 @@ static struct amd_nb *amd_alloc_nb(int cpu) ...@@ -510,6 +582,18 @@ static struct amd_nb *amd_alloc_nb(int cpu)
return nb; return nb;
} }
static void amd_pmu_cpu_reset(int cpu)
{
if (x86_pmu.version < 2)
return;
/* Clear enable bits i.e. PerfCntrGlobalCtl.PerfCntrEn */
wrmsrl(MSR_AMD64_PERF_CNTR_GLOBAL_CTL, 0);
/* Clear overflow bits i.e. PerfCntrGLobalStatus.PerfCntrOvfl */
wrmsrl(MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR, amd_pmu_global_cntr_mask);
}
static int amd_pmu_cpu_prepare(int cpu) static int amd_pmu_cpu_prepare(int cpu)
{ {
struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu); struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu);
...@@ -555,6 +639,9 @@ static void amd_pmu_cpu_starting(int cpu) ...@@ -555,6 +639,9 @@ static void amd_pmu_cpu_starting(int cpu)
cpuc->amd_nb->nb_id = nb_id; cpuc->amd_nb->nb_id = nb_id;
cpuc->amd_nb->refcnt++; cpuc->amd_nb->refcnt++;
amd_brs_reset();
amd_pmu_cpu_reset(cpu);
} }
static void amd_pmu_cpu_dead(int cpu) static void amd_pmu_cpu_dead(int cpu)
...@@ -574,8 +661,54 @@ static void amd_pmu_cpu_dead(int cpu) ...@@ -574,8 +661,54 @@ static void amd_pmu_cpu_dead(int cpu)
cpuhw->amd_nb = NULL; cpuhw->amd_nb = NULL;
} }
amd_pmu_cpu_reset(cpu);
}
static inline void amd_pmu_set_global_ctl(u64 ctl)
{
wrmsrl(MSR_AMD64_PERF_CNTR_GLOBAL_CTL, ctl);
}
static inline u64 amd_pmu_get_global_status(void)
{
u64 status;
/* PerfCntrGlobalStatus is read-only */
rdmsrl(MSR_AMD64_PERF_CNTR_GLOBAL_STATUS, status);
return status & amd_pmu_global_cntr_mask;
}
static inline void amd_pmu_ack_global_status(u64 status)
{
/*
* PerfCntrGlobalStatus is read-only but an overflow acknowledgment
* mechanism exists; writing 1 to a bit in PerfCntrGlobalStatusClr
* clears the same bit in PerfCntrGlobalStatus
*/
/* Only allow modifications to PerfCntrGlobalStatus.PerfCntrOvfl */
status &= amd_pmu_global_cntr_mask;
wrmsrl(MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR, status);
}
static bool amd_pmu_test_overflow_topbit(int idx)
{
u64 counter;
rdmsrl(x86_pmu_event_addr(idx), counter);
return !(counter & BIT_ULL(x86_pmu.cntval_bits - 1));
}
static bool amd_pmu_test_overflow_status(int idx)
{
return amd_pmu_get_global_status() & BIT_ULL(idx);
} }
DEFINE_STATIC_CALL(amd_pmu_test_overflow, amd_pmu_test_overflow_topbit);
/* /*
* When a PMC counter overflows, an NMI is used to process the event and * When a PMC counter overflows, an NMI is used to process the event and
* reset the counter. NMI latency can result in the counter being updated * reset the counter. NMI latency can result in the counter being updated
...@@ -588,7 +721,6 @@ static void amd_pmu_cpu_dead(int cpu) ...@@ -588,7 +721,6 @@ static void amd_pmu_cpu_dead(int cpu)
static void amd_pmu_wait_on_overflow(int idx) static void amd_pmu_wait_on_overflow(int idx)
{ {
unsigned int i; unsigned int i;
u64 counter;
/* /*
* Wait for the counter to be reset if it has overflowed. This loop * Wait for the counter to be reset if it has overflowed. This loop
...@@ -596,8 +728,7 @@ static void amd_pmu_wait_on_overflow(int idx) ...@@ -596,8 +728,7 @@ static void amd_pmu_wait_on_overflow(int idx)
* forever... * forever...
*/ */
for (i = 0; i < OVERFLOW_WAIT_COUNT; i++) { for (i = 0; i < OVERFLOW_WAIT_COUNT; i++) {
rdmsrl(x86_pmu_event_addr(idx), counter); if (!static_call(amd_pmu_test_overflow)(idx))
if (counter & (1ULL << (x86_pmu.cntval_bits - 1)))
break; break;
/* Might be in IRQ context, so can't sleep */ /* Might be in IRQ context, so can't sleep */
...@@ -605,13 +736,11 @@ static void amd_pmu_wait_on_overflow(int idx) ...@@ -605,13 +736,11 @@ static void amd_pmu_wait_on_overflow(int idx)
} }
} }
static void amd_pmu_disable_all(void) static void amd_pmu_check_overflow(void)
{ {
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
int idx; int idx;
x86_pmu_disable_all();
/* /*
* This shouldn't be called from NMI context, but add a safeguard here * This shouldn't be called from NMI context, but add a safeguard here
* to return, since if we're in NMI context we can't wait for an NMI * to return, since if we're in NMI context we can't wait for an NMI
...@@ -634,6 +763,50 @@ static void amd_pmu_disable_all(void) ...@@ -634,6 +763,50 @@ static void amd_pmu_disable_all(void)
} }
} }
static void amd_pmu_enable_event(struct perf_event *event)
{
x86_pmu_enable_event(event);
}
static void amd_pmu_enable_all(int added)
{
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
struct hw_perf_event *hwc;
int idx;
amd_brs_enable_all();
for (idx = 0; idx < x86_pmu.num_counters; idx++) {
hwc = &cpuc->events[idx]->hw;
/* only activate events which are marked as active */
if (!test_bit(idx, cpuc->active_mask))
continue;
amd_pmu_enable_event(cpuc->events[idx]);
}
}
static void amd_pmu_v2_enable_event(struct perf_event *event)
{
struct hw_perf_event *hwc = &event->hw;
/*
* Testing cpu_hw_events.enabled should be skipped in this case unlike
* in x86_pmu_enable_event().
*
* Since cpu_hw_events.enabled is set only after returning from
* x86_pmu_start(), the PMCs must be programmed and kept ready.
* Counting starts only after x86_pmu_enable_all() is called.
*/
__x86_pmu_enable_event(hwc, ARCH_PERFMON_EVENTSEL_ENABLE);
}
static void amd_pmu_v2_enable_all(int added)
{
amd_pmu_set_global_ctl(amd_pmu_global_cntr_mask);
}
static void amd_pmu_disable_event(struct perf_event *event) static void amd_pmu_disable_event(struct perf_event *event)
{ {
x86_pmu_disable_event(event); x86_pmu_disable_event(event);
...@@ -651,6 +824,32 @@ static void amd_pmu_disable_event(struct perf_event *event) ...@@ -651,6 +824,32 @@ static void amd_pmu_disable_event(struct perf_event *event)
amd_pmu_wait_on_overflow(event->hw.idx); amd_pmu_wait_on_overflow(event->hw.idx);
} }
static void amd_pmu_disable_all(void)
{
amd_brs_disable_all();
x86_pmu_disable_all();
amd_pmu_check_overflow();
}
static void amd_pmu_v2_disable_all(void)
{
/* Disable all PMCs */
amd_pmu_set_global_ctl(0);
amd_pmu_check_overflow();
}
static void amd_pmu_add_event(struct perf_event *event)
{
if (needs_branch_stack(event))
amd_pmu_brs_add(event);
}
static void amd_pmu_del_event(struct perf_event *event)
{
if (needs_branch_stack(event))
amd_pmu_brs_del(event);
}
/* /*
* Because of NMI latency, if multiple PMC counters are active or other sources * Because of NMI latency, if multiple PMC counters are active or other sources
* of NMIs are received, the perf NMI handler can handle one or more overflowed * of NMIs are received, the perf NMI handler can handle one or more overflowed
...@@ -669,13 +868,8 @@ static void amd_pmu_disable_event(struct perf_event *event) ...@@ -669,13 +868,8 @@ static void amd_pmu_disable_event(struct perf_event *event)
* handled a counter. When an un-handled NMI is received, it will be claimed * handled a counter. When an un-handled NMI is received, it will be claimed
* only if arriving within that window. * only if arriving within that window.
*/ */
static int amd_pmu_handle_irq(struct pt_regs *regs) static inline int amd_pmu_adjust_nmi_window(int handled)
{ {
int handled;
/* Process any counter overflows */
handled = x86_pmu_handle_irq(regs);
/* /*
* If a counter was handled, record a timestamp such that un-handled * If a counter was handled, record a timestamp such that un-handled
* NMIs will be claimed if arriving within that window. * NMIs will be claimed if arriving within that window.
...@@ -692,6 +886,113 @@ static int amd_pmu_handle_irq(struct pt_regs *regs) ...@@ -692,6 +886,113 @@ static int amd_pmu_handle_irq(struct pt_regs *regs)
return NMI_HANDLED; return NMI_HANDLED;
} }
static int amd_pmu_handle_irq(struct pt_regs *regs)
{
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
int handled;
int pmu_enabled;
/*
* Save the PMU state.
* It needs to be restored when leaving the handler.
*/
pmu_enabled = cpuc->enabled;
cpuc->enabled = 0;
/* stop everything (includes BRS) */
amd_pmu_disable_all();
/* Drain BRS is in use (could be inactive) */
if (cpuc->lbr_users)
amd_brs_drain();
/* Process any counter overflows */
handled = x86_pmu_handle_irq(regs);
cpuc->enabled = pmu_enabled;
if (pmu_enabled)
amd_pmu_enable_all(0);
return amd_pmu_adjust_nmi_window(handled);
}
static int amd_pmu_v2_handle_irq(struct pt_regs *regs)
{
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
struct perf_sample_data data;
struct hw_perf_event *hwc;
struct perf_event *event;
int handled = 0, idx;
u64 status, mask;
bool pmu_enabled;
/*
* Save the PMU state as it needs to be restored when leaving the
* handler
*/
pmu_enabled = cpuc->enabled;
cpuc->enabled = 0;
/* Stop counting */
amd_pmu_v2_disable_all();
status = amd_pmu_get_global_status();
/* Check if any overflows are pending */
if (!status)
goto done;
for (idx = 0; idx < x86_pmu.num_counters; idx++) {
if (!test_bit(idx, cpuc->active_mask))
continue;
event = cpuc->events[idx];
hwc = &event->hw;
x86_perf_event_update(event);
mask = BIT_ULL(idx);
if (!(status & mask))
continue;
/* Event overflow */
handled++;
perf_sample_data_init(&data, 0, hwc->last_period);
if (!x86_perf_event_set_period(event))
continue;
if (perf_event_overflow(event, &data, regs))
x86_pmu_stop(event, 0);
status &= ~mask;
}
/*
* It should never be the case that some overflows are not handled as
* the corresponding PMCs are expected to be inactive according to the
* active_mask
*/
WARN_ON(status > 0);
/* Clear overflow bits */
amd_pmu_ack_global_status(~status);
/*
* Unmasking the LVTPC is not required as the Mask (M) bit of the LVT
* PMI entry is not set by the local APIC when a PMC overflow occurs
*/
inc_irq_stat(apic_perf_irqs);
done:
cpuc->enabled = pmu_enabled;
/* Resume counting only if PMU is active */
if (pmu_enabled)
amd_pmu_v2_enable_all(0);
return amd_pmu_adjust_nmi_window(handled);
}
static struct event_constraint * static struct event_constraint *
amd_get_event_constraints(struct cpu_hw_events *cpuc, int idx, amd_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
struct perf_event *event) struct perf_event *event)
...@@ -897,6 +1198,51 @@ static void amd_put_event_constraints_f17h(struct cpu_hw_events *cpuc, ...@@ -897,6 +1198,51 @@ static void amd_put_event_constraints_f17h(struct cpu_hw_events *cpuc,
--cpuc->n_pair; --cpuc->n_pair;
} }
/*
* Because of the way BRS operates with an inactive and active phases, and
* the link to one counter, it is not possible to have two events using BRS
* scheduled at the same time. There would be an issue with enforcing the
* period of each one and given that the BRS saturates, it would not be possible
* to guarantee correlated content for all events. Therefore, in situations
* where multiple events want to use BRS, the kernel enforces mutual exclusion.
* Exclusion is enforced by chosing only one counter for events using BRS.
* The event scheduling logic will then automatically multiplex the
* events and ensure that at most one event is actively using BRS.
*
* The BRS counter could be any counter, but there is no constraint on Fam19h,
* therefore all counters are equal and thus we pick the first one: PMC0
*/
static struct event_constraint amd_fam19h_brs_cntr0_constraint =
EVENT_CONSTRAINT(0, 0x1, AMD64_RAW_EVENT_MASK);
static struct event_constraint amd_fam19h_brs_pair_cntr0_constraint =
__EVENT_CONSTRAINT(0, 0x1, AMD64_RAW_EVENT_MASK, 1, 0, PERF_X86_EVENT_PAIR);
static struct event_constraint *
amd_get_event_constraints_f19h(struct cpu_hw_events *cpuc, int idx,
struct perf_event *event)
{
struct hw_perf_event *hwc = &event->hw;
bool has_brs = has_amd_brs(hwc);
/*
* In case BRS is used with an event requiring a counter pair,
* the kernel allows it but only on counter 0 & 1 to enforce
* multiplexing requiring to protect BRS in case of multiple
* BRS users
*/
if (amd_is_pair_event_code(hwc)) {
return has_brs ? &amd_fam19h_brs_pair_cntr0_constraint
: &pair_constraint;
}
if (has_brs)
return &amd_fam19h_brs_cntr0_constraint;
return &unconstrained;
}
static ssize_t amd_event_sysfs_show(char *page, u64 config) static ssize_t amd_event_sysfs_show(char *page, u64 config)
{ {
u64 event = (config & ARCH_PERFMON_EVENTSEL_EVENT) | u64 event = (config & ARCH_PERFMON_EVENTSEL_EVENT) |
...@@ -905,12 +1251,19 @@ static ssize_t amd_event_sysfs_show(char *page, u64 config) ...@@ -905,12 +1251,19 @@ static ssize_t amd_event_sysfs_show(char *page, u64 config)
return x86_event_sysfs_show(page, config, event); return x86_event_sysfs_show(page, config, event);
} }
static void amd_pmu_sched_task(struct perf_event_context *ctx,
bool sched_in)
{
if (sched_in && x86_pmu.lbr_nr)
amd_pmu_brs_sched_task(ctx, sched_in);
}
static __initconst const struct x86_pmu amd_pmu = { static __initconst const struct x86_pmu amd_pmu = {
.name = "AMD", .name = "AMD",
.handle_irq = amd_pmu_handle_irq, .handle_irq = amd_pmu_handle_irq,
.disable_all = amd_pmu_disable_all, .disable_all = amd_pmu_disable_all,
.enable_all = x86_pmu_enable_all, .enable_all = amd_pmu_enable_all,
.enable = x86_pmu_enable_event, .enable = amd_pmu_enable_event,
.disable = amd_pmu_disable_event, .disable = amd_pmu_disable_event,
.hw_config = amd_pmu_hw_config, .hw_config = amd_pmu_hw_config,
.schedule_events = x86_schedule_events, .schedule_events = x86_schedule_events,
...@@ -920,6 +1273,8 @@ static __initconst const struct x86_pmu amd_pmu = { ...@@ -920,6 +1273,8 @@ static __initconst const struct x86_pmu amd_pmu = {
.event_map = amd_pmu_event_map, .event_map = amd_pmu_event_map,
.max_events = ARRAY_SIZE(amd_perfmon_event_map), .max_events = ARRAY_SIZE(amd_perfmon_event_map),
.num_counters = AMD64_NUM_COUNTERS, .num_counters = AMD64_NUM_COUNTERS,
.add = amd_pmu_add_event,
.del = amd_pmu_del_event,
.cntval_bits = 48, .cntval_bits = 48,
.cntval_mask = (1ULL << 48) - 1, .cntval_mask = (1ULL << 48) - 1,
.apic = 1, .apic = 1,
...@@ -938,8 +1293,55 @@ static __initconst const struct x86_pmu amd_pmu = { ...@@ -938,8 +1293,55 @@ static __initconst const struct x86_pmu amd_pmu = {
.amd_nb_constraints = 1, .amd_nb_constraints = 1,
}; };
static ssize_t branches_show(struct device *cdev,
struct device_attribute *attr,
char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", x86_pmu.lbr_nr);
}
static DEVICE_ATTR_RO(branches);
static struct attribute *amd_pmu_brs_attrs[] = {
&dev_attr_branches.attr,
NULL,
};
static umode_t
amd_brs_is_visible(struct kobject *kobj, struct attribute *attr, int i)
{
return x86_pmu.lbr_nr ? attr->mode : 0;
}
static struct attribute_group group_caps_amd_brs = {
.name = "caps",
.attrs = amd_pmu_brs_attrs,
.is_visible = amd_brs_is_visible,
};
EVENT_ATTR_STR(branch-brs, amd_branch_brs,
"event=" __stringify(AMD_FAM19H_BRS_EVENT)"\n");
static struct attribute *amd_brs_events_attrs[] = {
EVENT_PTR(amd_branch_brs),
NULL,
};
static struct attribute_group group_events_amd_brs = {
.name = "events",
.attrs = amd_brs_events_attrs,
.is_visible = amd_brs_is_visible,
};
static const struct attribute_group *amd_attr_update[] = {
&group_caps_amd_brs,
&group_events_amd_brs,
NULL,
};
static int __init amd_core_pmu_init(void) static int __init amd_core_pmu_init(void)
{ {
union cpuid_0x80000022_ebx ebx;
u64 even_ctr_mask = 0ULL; u64 even_ctr_mask = 0ULL;
int i; int i;
...@@ -957,6 +1359,27 @@ static int __init amd_core_pmu_init(void) ...@@ -957,6 +1359,27 @@ static int __init amd_core_pmu_init(void)
x86_pmu.eventsel = MSR_F15H_PERF_CTL; x86_pmu.eventsel = MSR_F15H_PERF_CTL;
x86_pmu.perfctr = MSR_F15H_PERF_CTR; x86_pmu.perfctr = MSR_F15H_PERF_CTR;
x86_pmu.num_counters = AMD64_NUM_COUNTERS_CORE; x86_pmu.num_counters = AMD64_NUM_COUNTERS_CORE;
/* Check for Performance Monitoring v2 support */
if (boot_cpu_has(X86_FEATURE_PERFMON_V2)) {
ebx.full = cpuid_ebx(EXT_PERFMON_DEBUG_FEATURES);
/* Update PMU version for later usage */
x86_pmu.version = 2;
/* Find the number of available Core PMCs */
x86_pmu.num_counters = ebx.split.num_core_pmc;
amd_pmu_global_cntr_mask = (1ULL << x86_pmu.num_counters) - 1;
/* Update PMC handling functions */
x86_pmu.enable_all = amd_pmu_v2_enable_all;
x86_pmu.disable_all = amd_pmu_v2_disable_all;
x86_pmu.enable = amd_pmu_v2_enable_event;
x86_pmu.handle_irq = amd_pmu_v2_handle_irq;
static_call_update(amd_pmu_test_overflow, amd_pmu_test_overflow_status);
}
/* /*
* AMD Core perfctr has separate MSRs for the NB events, see * AMD Core perfctr has separate MSRs for the NB events, see
* the amd/uncore.c driver. * the amd/uncore.c driver.
...@@ -989,6 +1412,22 @@ static int __init amd_core_pmu_init(void) ...@@ -989,6 +1412,22 @@ static int __init amd_core_pmu_init(void)
x86_pmu.flags |= PMU_FL_PAIR; x86_pmu.flags |= PMU_FL_PAIR;
} }
/*
* BRS requires special event constraints and flushing on ctxsw.
*/
if (boot_cpu_data.x86 >= 0x19 && !amd_brs_init()) {
x86_pmu.get_event_constraints = amd_get_event_constraints_f19h;
x86_pmu.sched_task = amd_pmu_sched_task;
/*
* put_event_constraints callback same as Fam17h, set above
*/
/* branch sampling must be stopped when entering low power */
amd_brs_lopwr_init();
}
x86_pmu.attr_update = amd_attr_update;
pr_cont("core perfctr, "); pr_cont("core perfctr, ");
return 0; return 0;
} }
...@@ -1023,6 +1462,24 @@ __init int amd_pmu_init(void) ...@@ -1023,6 +1462,24 @@ __init int amd_pmu_init(void)
return 0; return 0;
} }
static inline void amd_pmu_reload_virt(void)
{
if (x86_pmu.version >= 2) {
/*
* Clear global enable bits, reprogram the PERF_CTL
* registers with updated perf_ctr_virt_mask and then
* set global enable bits once again
*/
amd_pmu_v2_disable_all();
amd_pmu_enable_all(0);
amd_pmu_v2_enable_all(0);
return;
}
amd_pmu_disable_all();
amd_pmu_enable_all(0);
}
void amd_pmu_enable_virt(void) void amd_pmu_enable_virt(void)
{ {
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
...@@ -1030,8 +1487,7 @@ void amd_pmu_enable_virt(void) ...@@ -1030,8 +1487,7 @@ void amd_pmu_enable_virt(void)
cpuc->perf_ctr_virt_mask = 0; cpuc->perf_ctr_virt_mask = 0;
/* Reload all events */ /* Reload all events */
amd_pmu_disable_all(); amd_pmu_reload_virt();
x86_pmu_enable_all(0);
} }
EXPORT_SYMBOL_GPL(amd_pmu_enable_virt); EXPORT_SYMBOL_GPL(amd_pmu_enable_virt);
...@@ -1048,7 +1504,6 @@ void amd_pmu_disable_virt(void) ...@@ -1048,7 +1504,6 @@ void amd_pmu_disable_virt(void)
cpuc->perf_ctr_virt_mask = AMD64_EVENTSEL_HOSTONLY; cpuc->perf_ctr_virt_mask = AMD64_EVENTSEL_HOSTONLY;
/* Reload all events */ /* Reload all events */
amd_pmu_disable_all(); amd_pmu_reload_virt();
x86_pmu_enable_all(0);
} }
EXPORT_SYMBOL_GPL(amd_pmu_disable_virt); EXPORT_SYMBOL_GPL(amd_pmu_disable_virt);
...@@ -26,6 +26,7 @@ static u32 ibs_caps; ...@@ -26,6 +26,7 @@ static u32 ibs_caps;
#include <linux/hardirq.h> #include <linux/hardirq.h>
#include <asm/nmi.h> #include <asm/nmi.h>
#include <asm/amd-ibs.h>
#define IBS_FETCH_CONFIG_MASK (IBS_FETCH_RAND_EN | IBS_FETCH_MAX_CNT) #define IBS_FETCH_CONFIG_MASK (IBS_FETCH_RAND_EN | IBS_FETCH_MAX_CNT)
#define IBS_OP_CONFIG_MASK IBS_OP_MAX_CNT #define IBS_OP_CONFIG_MASK IBS_OP_MAX_CNT
...@@ -93,22 +94,9 @@ struct perf_ibs { ...@@ -93,22 +94,9 @@ struct perf_ibs {
unsigned int fetch_ignore_if_zero_rip : 1; unsigned int fetch_ignore_if_zero_rip : 1;
struct cpu_perf_ibs __percpu *pcpu; struct cpu_perf_ibs __percpu *pcpu;
struct attribute **format_attrs;
struct attribute_group format_group;
const struct attribute_group *attr_groups[2];
u64 (*get_count)(u64 config); u64 (*get_count)(u64 config);
}; };
struct perf_ibs_data {
u32 size;
union {
u32 data[0]; /* data buffer starts here */
u32 caps;
};
u64 regs[MSR_AMD64_IBS_REG_COUNT_MAX];
};
static int static int
perf_event_set_period(struct hw_perf_event *hwc, u64 min, u64 max, u64 *hw_period) perf_event_set_period(struct hw_perf_event *hwc, u64 min, u64 max, u64 *hw_period)
{ {
...@@ -312,6 +300,16 @@ static int perf_ibs_init(struct perf_event *event) ...@@ -312,6 +300,16 @@ static int perf_ibs_init(struct perf_event *event)
hwc->config_base = perf_ibs->msr; hwc->config_base = perf_ibs->msr;
hwc->config = config; hwc->config = config;
/*
* rip recorded by IbsOpRip will not be consistent with rsp and rbp
* recorded as part of interrupt regs. Thus we need to use rip from
* interrupt regs while unwinding call stack. Setting _EARLY flag
* makes sure we unwind call-stack before perf sample rip is set to
* IbsOpRip.
*/
if (event->attr.sample_type & PERF_SAMPLE_CALLCHAIN)
event->attr.sample_type |= __PERF_SAMPLE_CALLCHAIN_EARLY;
return 0; return 0;
} }
...@@ -329,11 +327,14 @@ static int perf_ibs_set_period(struct perf_ibs *perf_ibs, ...@@ -329,11 +327,14 @@ static int perf_ibs_set_period(struct perf_ibs *perf_ibs,
static u64 get_ibs_fetch_count(u64 config) static u64 get_ibs_fetch_count(u64 config)
{ {
return (config & IBS_FETCH_CNT) >> 12; union ibs_fetch_ctl fetch_ctl = (union ibs_fetch_ctl)config;
return fetch_ctl.fetch_cnt << 4;
} }
static u64 get_ibs_op_count(u64 config) static u64 get_ibs_op_count(u64 config)
{ {
union ibs_op_ctl op_ctl = (union ibs_op_ctl)config;
u64 count = 0; u64 count = 0;
/* /*
...@@ -341,12 +342,12 @@ static u64 get_ibs_op_count(u64 config) ...@@ -341,12 +342,12 @@ static u64 get_ibs_op_count(u64 config)
* and the lower 7 bits of CurCnt are randomized. * and the lower 7 bits of CurCnt are randomized.
* Otherwise CurCnt has the full 27-bit current counter value. * Otherwise CurCnt has the full 27-bit current counter value.
*/ */
if (config & IBS_OP_VAL) { if (op_ctl.op_val) {
count = (config & IBS_OP_MAX_CNT) << 4; count = op_ctl.opmaxcnt << 4;
if (ibs_caps & IBS_CAPS_OPCNTEXT) if (ibs_caps & IBS_CAPS_OPCNTEXT)
count += config & IBS_OP_MAX_CNT_EXT_MASK; count += op_ctl.opmaxcnt_ext << 20;
} else if (ibs_caps & IBS_CAPS_RDWROPCNT) { } else if (ibs_caps & IBS_CAPS_RDWROPCNT) {
count = (config & IBS_OP_CUR_CNT) >> 32; count = op_ctl.opcurcnt;
} }
return count; return count;
...@@ -523,16 +524,118 @@ static void perf_ibs_del(struct perf_event *event, int flags) ...@@ -523,16 +524,118 @@ static void perf_ibs_del(struct perf_event *event, int flags)
static void perf_ibs_read(struct perf_event *event) { } static void perf_ibs_read(struct perf_event *event) { }
/*
* We need to initialize with empty group if all attributes in the
* group are dynamic.
*/
static struct attribute *attrs_empty[] = {
NULL,
};
static struct attribute_group empty_format_group = {
.name = "format",
.attrs = attrs_empty,
};
static struct attribute_group empty_caps_group = {
.name = "caps",
.attrs = attrs_empty,
};
static const struct attribute_group *empty_attr_groups[] = {
&empty_format_group,
&empty_caps_group,
NULL,
};
PMU_FORMAT_ATTR(rand_en, "config:57"); PMU_FORMAT_ATTR(rand_en, "config:57");
PMU_FORMAT_ATTR(cnt_ctl, "config:19"); PMU_FORMAT_ATTR(cnt_ctl, "config:19");
PMU_EVENT_ATTR_STRING(l3missonly, fetch_l3missonly, "config:59");
PMU_EVENT_ATTR_STRING(l3missonly, op_l3missonly, "config:16");
PMU_EVENT_ATTR_STRING(zen4_ibs_extensions, zen4_ibs_extensions, "1");
static umode_t
zen4_ibs_extensions_is_visible(struct kobject *kobj, struct attribute *attr, int i)
{
return ibs_caps & IBS_CAPS_ZEN4 ? attr->mode : 0;
}
static struct attribute *ibs_fetch_format_attrs[] = { static struct attribute *rand_en_attrs[] = {
&format_attr_rand_en.attr, &format_attr_rand_en.attr,
NULL, NULL,
}; };
static struct attribute *ibs_op_format_attrs[] = { static struct attribute *fetch_l3missonly_attrs[] = {
NULL, /* &format_attr_cnt_ctl.attr if IBS_CAPS_OPCNT */ &fetch_l3missonly.attr.attr,
NULL,
};
static struct attribute *zen4_ibs_extensions_attrs[] = {
&zen4_ibs_extensions.attr.attr,
NULL,
};
static struct attribute_group group_rand_en = {
.name = "format",
.attrs = rand_en_attrs,
};
static struct attribute_group group_fetch_l3missonly = {
.name = "format",
.attrs = fetch_l3missonly_attrs,
.is_visible = zen4_ibs_extensions_is_visible,
};
static struct attribute_group group_zen4_ibs_extensions = {
.name = "caps",
.attrs = zen4_ibs_extensions_attrs,
.is_visible = zen4_ibs_extensions_is_visible,
};
static const struct attribute_group *fetch_attr_groups[] = {
&group_rand_en,
&empty_caps_group,
NULL,
};
static const struct attribute_group *fetch_attr_update[] = {
&group_fetch_l3missonly,
&group_zen4_ibs_extensions,
NULL,
};
static umode_t
cnt_ctl_is_visible(struct kobject *kobj, struct attribute *attr, int i)
{
return ibs_caps & IBS_CAPS_OPCNT ? attr->mode : 0;
}
static struct attribute *cnt_ctl_attrs[] = {
&format_attr_cnt_ctl.attr,
NULL,
};
static struct attribute *op_l3missonly_attrs[] = {
&op_l3missonly.attr.attr,
NULL,
};
static struct attribute_group group_cnt_ctl = {
.name = "format",
.attrs = cnt_ctl_attrs,
.is_visible = cnt_ctl_is_visible,
};
static struct attribute_group group_op_l3missonly = {
.name = "format",
.attrs = op_l3missonly_attrs,
.is_visible = zen4_ibs_extensions_is_visible,
};
static const struct attribute_group *op_attr_update[] = {
&group_cnt_ctl,
&group_op_l3missonly,
&group_zen4_ibs_extensions,
NULL, NULL,
}; };
...@@ -556,7 +659,6 @@ static struct perf_ibs perf_ibs_fetch = { ...@@ -556,7 +659,6 @@ static struct perf_ibs perf_ibs_fetch = {
.max_period = IBS_FETCH_MAX_CNT << 4, .max_period = IBS_FETCH_MAX_CNT << 4,
.offset_mask = { MSR_AMD64_IBSFETCH_REG_MASK }, .offset_mask = { MSR_AMD64_IBSFETCH_REG_MASK },
.offset_max = MSR_AMD64_IBSFETCH_REG_COUNT, .offset_max = MSR_AMD64_IBSFETCH_REG_COUNT,
.format_attrs = ibs_fetch_format_attrs,
.get_count = get_ibs_fetch_count, .get_count = get_ibs_fetch_count,
}; };
...@@ -582,7 +684,6 @@ static struct perf_ibs perf_ibs_op = { ...@@ -582,7 +684,6 @@ static struct perf_ibs perf_ibs_op = {
.max_period = IBS_OP_MAX_CNT << 4, .max_period = IBS_OP_MAX_CNT << 4,
.offset_mask = { MSR_AMD64_IBSOP_REG_MASK }, .offset_mask = { MSR_AMD64_IBSOP_REG_MASK },
.offset_max = MSR_AMD64_IBSOP_REG_COUNT, .offset_max = MSR_AMD64_IBSOP_REG_COUNT,
.format_attrs = ibs_op_format_attrs,
.get_count = get_ibs_op_count, .get_count = get_ibs_op_count,
}; };
...@@ -692,6 +793,14 @@ static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs) ...@@ -692,6 +793,14 @@ static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs)
data.raw = &raw; data.raw = &raw;
} }
/*
* rip recorded by IbsOpRip will not be consistent with rsp and rbp
* 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)
data.callchain = perf_callchain(event, iregs);
throttle = perf_event_overflow(event, &data, &regs); throttle = perf_event_overflow(event, &data, &regs);
out: out:
if (throttle) { if (throttle) {
...@@ -744,17 +853,6 @@ static __init int perf_ibs_pmu_init(struct perf_ibs *perf_ibs, char *name) ...@@ -744,17 +853,6 @@ static __init int perf_ibs_pmu_init(struct perf_ibs *perf_ibs, char *name)
perf_ibs->pcpu = pcpu; perf_ibs->pcpu = pcpu;
/* register attributes */
if (perf_ibs->format_attrs[0]) {
memset(&perf_ibs->format_group, 0, sizeof(perf_ibs->format_group));
perf_ibs->format_group.name = "format";
perf_ibs->format_group.attrs = perf_ibs->format_attrs;
memset(&perf_ibs->attr_groups, 0, sizeof(perf_ibs->attr_groups));
perf_ibs->attr_groups[0] = &perf_ibs->format_group;
perf_ibs->pmu.attr_groups = perf_ibs->attr_groups;
}
ret = perf_pmu_register(&perf_ibs->pmu, name, -1); ret = perf_pmu_register(&perf_ibs->pmu, name, -1);
if (ret) { if (ret) {
perf_ibs->pcpu = NULL; perf_ibs->pcpu = NULL;
...@@ -764,10 +862,8 @@ static __init int perf_ibs_pmu_init(struct perf_ibs *perf_ibs, char *name) ...@@ -764,10 +862,8 @@ static __init int perf_ibs_pmu_init(struct perf_ibs *perf_ibs, char *name)
return ret; return ret;
} }
static __init void perf_event_ibs_init(void) static __init int perf_ibs_fetch_init(void)
{ {
struct attribute **attr = ibs_op_format_attrs;
/* /*
* Some chips fail to reset the fetch count when it is written; instead * Some chips fail to reset the fetch count when it is written; instead
* they need a 0-1 transition of IbsFetchEn. * they need a 0-1 transition of IbsFetchEn.
...@@ -778,12 +874,19 @@ static __init void perf_event_ibs_init(void) ...@@ -778,12 +874,19 @@ static __init void perf_event_ibs_init(void)
if (boot_cpu_data.x86 == 0x19 && boot_cpu_data.x86_model < 0x10) if (boot_cpu_data.x86 == 0x19 && boot_cpu_data.x86_model < 0x10)
perf_ibs_fetch.fetch_ignore_if_zero_rip = 1; perf_ibs_fetch.fetch_ignore_if_zero_rip = 1;
perf_ibs_pmu_init(&perf_ibs_fetch, "ibs_fetch"); if (ibs_caps & IBS_CAPS_ZEN4)
perf_ibs_fetch.config_mask |= IBS_FETCH_L3MISSONLY;
if (ibs_caps & IBS_CAPS_OPCNT) { perf_ibs_fetch.pmu.attr_groups = fetch_attr_groups;
perf_ibs_fetch.pmu.attr_update = fetch_attr_update;
return perf_ibs_pmu_init(&perf_ibs_fetch, "ibs_fetch");
}
static __init int perf_ibs_op_init(void)
{
if (ibs_caps & IBS_CAPS_OPCNT)
perf_ibs_op.config_mask |= IBS_OP_CNT_CTL; perf_ibs_op.config_mask |= IBS_OP_CNT_CTL;
*attr++ = &format_attr_cnt_ctl.attr;
}
if (ibs_caps & IBS_CAPS_OPCNTEXT) { if (ibs_caps & IBS_CAPS_OPCNTEXT) {
perf_ibs_op.max_period |= IBS_OP_MAX_CNT_EXT_MASK; perf_ibs_op.max_period |= IBS_OP_MAX_CNT_EXT_MASK;
...@@ -791,15 +894,52 @@ static __init void perf_event_ibs_init(void) ...@@ -791,15 +894,52 @@ static __init void perf_event_ibs_init(void)
perf_ibs_op.cnt_mask |= IBS_OP_MAX_CNT_EXT_MASK; perf_ibs_op.cnt_mask |= IBS_OP_MAX_CNT_EXT_MASK;
} }
perf_ibs_pmu_init(&perf_ibs_op, "ibs_op"); if (ibs_caps & IBS_CAPS_ZEN4)
perf_ibs_op.config_mask |= IBS_OP_L3MISSONLY;
perf_ibs_op.pmu.attr_groups = empty_attr_groups;
perf_ibs_op.pmu.attr_update = op_attr_update;
return perf_ibs_pmu_init(&perf_ibs_op, "ibs_op");
}
static __init int perf_event_ibs_init(void)
{
int ret;
ret = perf_ibs_fetch_init();
if (ret)
return ret;
ret = perf_ibs_op_init();
if (ret)
goto err_op;
ret = register_nmi_handler(NMI_LOCAL, perf_ibs_nmi_handler, 0, "perf_ibs");
if (ret)
goto err_nmi;
register_nmi_handler(NMI_LOCAL, perf_ibs_nmi_handler, 0, "perf_ibs");
pr_info("perf: AMD IBS detected (0x%08x)\n", ibs_caps); pr_info("perf: AMD IBS detected (0x%08x)\n", ibs_caps);
return 0;
err_nmi:
perf_pmu_unregister(&perf_ibs_op.pmu);
free_percpu(perf_ibs_op.pcpu);
perf_ibs_op.pcpu = NULL;
err_op:
perf_pmu_unregister(&perf_ibs_fetch.pmu);
free_percpu(perf_ibs_fetch.pcpu);
perf_ibs_fetch.pcpu = NULL;
return ret;
} }
#else /* defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_AMD) */ #else /* defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_AMD) */
static __init void perf_event_ibs_init(void) { } static __init int perf_event_ibs_init(void)
{
return 0;
}
#endif #endif
...@@ -1069,9 +1209,7 @@ static __init int amd_ibs_init(void) ...@@ -1069,9 +1209,7 @@ static __init int amd_ibs_init(void)
x86_pmu_amd_ibs_starting_cpu, x86_pmu_amd_ibs_starting_cpu,
x86_pmu_amd_ibs_dying_cpu); x86_pmu_amd_ibs_dying_cpu);
perf_event_ibs_init(); return perf_event_ibs_init();
return 0;
} }
/* Since we need the pci subsystem to init ibs we can't do this earlier: */ /* Since we need the pci subsystem to init ibs we can't do this earlier: */
......
...@@ -1296,6 +1296,10 @@ static void x86_pmu_enable(struct pmu *pmu) ...@@ -1296,6 +1296,10 @@ static void x86_pmu_enable(struct pmu *pmu)
if (hwc->state & PERF_HES_ARCH) if (hwc->state & PERF_HES_ARCH)
continue; continue;
/*
* if cpuc->enabled = 0, then no wrmsr as
* per x86_pmu_enable_event()
*/
x86_pmu_start(event, PERF_EF_RELOAD); x86_pmu_start(event, PERF_EF_RELOAD);
} }
cpuc->n_added = 0; cpuc->n_added = 0;
...@@ -1328,6 +1332,13 @@ int x86_perf_event_set_period(struct perf_event *event) ...@@ -1328,6 +1332,13 @@ int x86_perf_event_set_period(struct perf_event *event)
x86_pmu.set_topdown_event_period) x86_pmu.set_topdown_event_period)
return x86_pmu.set_topdown_event_period(event); return x86_pmu.set_topdown_event_period(event);
/*
* decrease period by the depth of the BRS feature to get
* the last N taken branches and approximate the desired period
*/
if (has_branch_stack(event))
period = amd_brs_adjust_period(period);
/* /*
* If we are way outside a reasonable range then just skip forward: * If we are way outside a reasonable range then just skip forward:
*/ */
...@@ -1659,11 +1670,15 @@ int x86_pmu_handle_irq(struct pt_regs *regs) ...@@ -1659,11 +1670,15 @@ int x86_pmu_handle_irq(struct pt_regs *regs)
* event overflow * event overflow
*/ */
handled++; handled++;
perf_sample_data_init(&data, 0, event->hw.last_period);
if (!x86_perf_event_set_period(event)) if (!x86_perf_event_set_period(event))
continue; continue;
perf_sample_data_init(&data, 0, event->hw.last_period);
if (has_branch_stack(event))
data.br_stack = &cpuc->lbr_stack;
if (perf_event_overflow(event, &data, regs)) if (perf_event_overflow(event, &data, regs))
x86_pmu_stop(event, 0); x86_pmu_stop(event, 0);
} }
......
...@@ -786,6 +786,7 @@ void intel_pmu_lbr_disable_all(void) ...@@ -786,6 +786,7 @@ void intel_pmu_lbr_disable_all(void)
void intel_pmu_lbr_read_32(struct cpu_hw_events *cpuc) void intel_pmu_lbr_read_32(struct cpu_hw_events *cpuc)
{ {
unsigned long mask = x86_pmu.lbr_nr - 1; unsigned long mask = x86_pmu.lbr_nr - 1;
struct perf_branch_entry *br = cpuc->lbr_entries;
u64 tos = intel_pmu_lbr_tos(); u64 tos = intel_pmu_lbr_tos();
int i; int i;
...@@ -801,15 +802,11 @@ void intel_pmu_lbr_read_32(struct cpu_hw_events *cpuc) ...@@ -801,15 +802,11 @@ void intel_pmu_lbr_read_32(struct cpu_hw_events *cpuc)
rdmsrl(x86_pmu.lbr_from + lbr_idx, msr_lastbranch.lbr); rdmsrl(x86_pmu.lbr_from + lbr_idx, msr_lastbranch.lbr);
cpuc->lbr_entries[i].from = msr_lastbranch.from; perf_clear_branch_entry_bitfields(br);
cpuc->lbr_entries[i].to = msr_lastbranch.to;
cpuc->lbr_entries[i].mispred = 0; br->from = msr_lastbranch.from;
cpuc->lbr_entries[i].predicted = 0; br->to = msr_lastbranch.to;
cpuc->lbr_entries[i].in_tx = 0; br++;
cpuc->lbr_entries[i].abort = 0;
cpuc->lbr_entries[i].cycles = 0;
cpuc->lbr_entries[i].type = 0;
cpuc->lbr_entries[i].reserved = 0;
} }
cpuc->lbr_stack.nr = i; cpuc->lbr_stack.nr = i;
cpuc->lbr_stack.hw_idx = tos; cpuc->lbr_stack.hw_idx = tos;
...@@ -825,6 +822,7 @@ void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc) ...@@ -825,6 +822,7 @@ void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)
bool need_info = false, call_stack = false; bool need_info = false, call_stack = false;
unsigned long mask = x86_pmu.lbr_nr - 1; unsigned long mask = x86_pmu.lbr_nr - 1;
int lbr_format = x86_pmu.intel_cap.lbr_format; int lbr_format = x86_pmu.intel_cap.lbr_format;
struct perf_branch_entry *br = cpuc->lbr_entries;
u64 tos = intel_pmu_lbr_tos(); u64 tos = intel_pmu_lbr_tos();
int i; int i;
int out = 0; int out = 0;
...@@ -896,15 +894,14 @@ void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc) ...@@ -896,15 +894,14 @@ void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)
if (abort && x86_pmu.lbr_double_abort && out > 0) if (abort && x86_pmu.lbr_double_abort && out > 0)
out--; out--;
cpuc->lbr_entries[out].from = from; perf_clear_branch_entry_bitfields(br+out);
cpuc->lbr_entries[out].to = to; br[out].from = from;
cpuc->lbr_entries[out].mispred = mis; br[out].to = to;
cpuc->lbr_entries[out].predicted = pred; br[out].mispred = mis;
cpuc->lbr_entries[out].in_tx = in_tx; br[out].predicted = pred;
cpuc->lbr_entries[out].abort = abort; br[out].in_tx = in_tx;
cpuc->lbr_entries[out].cycles = cycles; br[out].abort = abort;
cpuc->lbr_entries[out].type = 0; br[out].cycles = cycles;
cpuc->lbr_entries[out].reserved = 0;
out++; out++;
} }
cpuc->lbr_stack.nr = out; cpuc->lbr_stack.nr = out;
...@@ -966,6 +963,8 @@ static void intel_pmu_store_lbr(struct cpu_hw_events *cpuc, ...@@ -966,6 +963,8 @@ static void intel_pmu_store_lbr(struct cpu_hw_events *cpuc,
to = rdlbr_to(i, lbr); to = rdlbr_to(i, lbr);
info = rdlbr_info(i, lbr); info = rdlbr_info(i, lbr);
perf_clear_branch_entry_bitfields(e);
e->from = from; e->from = from;
e->to = to; e->to = to;
e->mispred = get_lbr_mispred(info); e->mispred = get_lbr_mispred(info);
...@@ -974,7 +973,6 @@ static void intel_pmu_store_lbr(struct cpu_hw_events *cpuc, ...@@ -974,7 +973,6 @@ static void intel_pmu_store_lbr(struct cpu_hw_events *cpuc,
e->abort = !!(info & LBR_INFO_ABORT); e->abort = !!(info & LBR_INFO_ABORT);
e->cycles = get_lbr_cycles(info); e->cycles = get_lbr_cycles(info);
e->type = get_lbr_br_type(info); e->type = get_lbr_br_type(info);
e->reserved = 0;
} }
cpuc->lbr_stack.nr = i; cpuc->lbr_stack.nr = i;
......
...@@ -66,22 +66,23 @@ static inline bool constraint_match(struct event_constraint *c, u64 ecode) ...@@ -66,22 +66,23 @@ static inline bool constraint_match(struct event_constraint *c, u64 ecode)
/* /*
* struct hw_perf_event.flags flags * struct hw_perf_event.flags flags
*/ */
#define PERF_X86_EVENT_PEBS_LDLAT 0x0001 /* ld+ldlat data address sampling */ #define PERF_X86_EVENT_PEBS_LDLAT 0x00001 /* ld+ldlat data address sampling */
#define PERF_X86_EVENT_PEBS_ST 0x0002 /* st data address sampling */ #define PERF_X86_EVENT_PEBS_ST 0x00002 /* st data address sampling */
#define PERF_X86_EVENT_PEBS_ST_HSW 0x0004 /* haswell style datala, store */ #define PERF_X86_EVENT_PEBS_ST_HSW 0x00004 /* haswell style datala, store */
#define PERF_X86_EVENT_PEBS_LD_HSW 0x0008 /* haswell style datala, load */ #define PERF_X86_EVENT_PEBS_LD_HSW 0x00008 /* haswell style datala, load */
#define PERF_X86_EVENT_PEBS_NA_HSW 0x0010 /* haswell style datala, unknown */ #define PERF_X86_EVENT_PEBS_NA_HSW 0x00010 /* haswell style datala, unknown */
#define PERF_X86_EVENT_EXCL 0x0020 /* HT exclusivity on counter */ #define PERF_X86_EVENT_EXCL 0x00020 /* HT exclusivity on counter */
#define PERF_X86_EVENT_DYNAMIC 0x0040 /* dynamic alloc'd constraint */ #define PERF_X86_EVENT_DYNAMIC 0x00040 /* dynamic alloc'd constraint */
#define PERF_X86_EVENT_RDPMC_ALLOWED 0x0080 /* grant rdpmc permission */ #define PERF_X86_EVENT_RDPMC_ALLOWED 0x00080 /* grant rdpmc permission */
#define PERF_X86_EVENT_EXCL_ACCT 0x0100 /* accounted EXCL event */ #define PERF_X86_EVENT_EXCL_ACCT 0x00100 /* accounted EXCL event */
#define PERF_X86_EVENT_AUTO_RELOAD 0x0200 /* use PEBS auto-reload */ #define PERF_X86_EVENT_AUTO_RELOAD 0x00200 /* use PEBS auto-reload */
#define PERF_X86_EVENT_LARGE_PEBS 0x0400 /* use large PEBS */ #define PERF_X86_EVENT_LARGE_PEBS 0x00400 /* use large PEBS */
#define PERF_X86_EVENT_PEBS_VIA_PT 0x0800 /* use PT buffer for PEBS */ #define PERF_X86_EVENT_PEBS_VIA_PT 0x00800 /* use PT buffer for PEBS */
#define PERF_X86_EVENT_PAIR 0x1000 /* Large Increment per Cycle */ #define PERF_X86_EVENT_PAIR 0x01000 /* Large Increment per Cycle */
#define PERF_X86_EVENT_LBR_SELECT 0x2000 /* Save/Restore MSR_LBR_SELECT */ #define PERF_X86_EVENT_LBR_SELECT 0x02000 /* Save/Restore MSR_LBR_SELECT */
#define PERF_X86_EVENT_TOPDOWN 0x4000 /* Count Topdown slots/metrics events */ #define PERF_X86_EVENT_TOPDOWN 0x04000 /* Count Topdown slots/metrics events */
#define PERF_X86_EVENT_PEBS_STLAT 0x8000 /* st+stlat data address sampling */ #define PERF_X86_EVENT_PEBS_STLAT 0x08000 /* st+stlat data address sampling */
#define PERF_X86_EVENT_AMD_BRS 0x10000 /* AMD Branch Sampling */
static inline bool is_topdown_count(struct perf_event *event) static inline bool is_topdown_count(struct perf_event *event)
{ {
...@@ -323,6 +324,8 @@ struct cpu_hw_events { ...@@ -323,6 +324,8 @@ struct cpu_hw_events {
* AMD specific bits * AMD specific bits
*/ */
struct amd_nb *amd_nb; struct amd_nb *amd_nb;
int brs_active; /* BRS is enabled */
/* Inverted mask of bits to clear in the perf_ctr ctrl registers */ /* Inverted mask of bits to clear in the perf_ctr ctrl registers */
u64 perf_ctr_virt_mask; u64 perf_ctr_virt_mask;
int n_pair; /* Large increment events */ int n_pair; /* Large increment events */
...@@ -986,6 +989,11 @@ int x86_pmu_hw_config(struct perf_event *event); ...@@ -986,6 +989,11 @@ int x86_pmu_hw_config(struct perf_event *event);
void x86_pmu_disable_all(void); void x86_pmu_disable_all(void);
static inline bool has_amd_brs(struct hw_perf_event *hwc)
{
return hwc->flags & PERF_X86_EVENT_AMD_BRS;
}
static inline bool is_counter_pair(struct hw_perf_event *hwc) static inline bool is_counter_pair(struct hw_perf_event *hwc)
{ {
return hwc->flags & PERF_X86_EVENT_PAIR; return hwc->flags & PERF_X86_EVENT_PAIR;
...@@ -1082,6 +1090,88 @@ static inline bool fixed_counter_disabled(int i) ...@@ -1082,6 +1090,88 @@ static inline bool fixed_counter_disabled(int i)
int amd_pmu_init(void); int amd_pmu_init(void);
#ifdef CONFIG_PERF_EVENTS_AMD_BRS
int amd_brs_init(void);
void amd_brs_disable(void);
void amd_brs_enable(void);
void amd_brs_enable_all(void);
void amd_brs_disable_all(void);
void amd_brs_drain(void);
void amd_brs_lopwr_init(void);
void amd_brs_disable_all(void);
int amd_brs_setup_filter(struct perf_event *event);
void amd_brs_reset(void);
static inline void amd_pmu_brs_add(struct perf_event *event)
{
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
perf_sched_cb_inc(event->ctx->pmu);
cpuc->lbr_users++;
/*
* No need to reset BRS because it is reset
* on brs_enable() and it is saturating
*/
}
static inline void amd_pmu_brs_del(struct perf_event *event)
{
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
cpuc->lbr_users--;
WARN_ON_ONCE(cpuc->lbr_users < 0);
perf_sched_cb_dec(event->ctx->pmu);
}
void amd_pmu_brs_sched_task(struct perf_event_context *ctx, bool sched_in);
static inline s64 amd_brs_adjust_period(s64 period)
{
if (period > x86_pmu.lbr_nr)
return period - x86_pmu.lbr_nr;
return period;
}
#else
static inline int amd_brs_init(void)
{
return 0;
}
static inline void amd_brs_disable(void) {}
static inline void amd_brs_enable(void) {}
static inline void amd_brs_drain(void) {}
static inline void amd_brs_lopwr_init(void) {}
static inline void amd_brs_disable_all(void) {}
static inline int amd_brs_setup_filter(struct perf_event *event)
{
return 0;
}
static inline void amd_brs_reset(void) {}
static inline void amd_pmu_brs_add(struct perf_event *event)
{
}
static inline void amd_pmu_brs_del(struct perf_event *event)
{
}
static inline void amd_pmu_brs_sched_task(struct perf_event_context *ctx, bool sched_in)
{
}
static inline s64 amd_brs_adjust_period(s64 period)
{
return period;
}
static inline void amd_brs_enable_all(void)
{
}
#endif
#else /* CONFIG_CPU_SUP_AMD */ #else /* CONFIG_CPU_SUP_AMD */
static inline int amd_pmu_init(void) static inline int amd_pmu_init(void)
...@@ -1089,6 +1179,27 @@ static inline int amd_pmu_init(void) ...@@ -1089,6 +1179,27 @@ static inline int amd_pmu_init(void)
return 0; return 0;
} }
static inline int amd_brs_init(void)
{
return -EOPNOTSUPP;
}
static inline void amd_brs_drain(void)
{
}
static inline void amd_brs_enable_all(void)
{
}
static inline void amd_brs_disable_all(void)
{
}
static inline s64 amd_brs_adjust_period(s64 period)
{
return period;
}
#endif /* CONFIG_CPU_SUP_AMD */ #endif /* CONFIG_CPU_SUP_AMD */
static inline int is_pebs_pt(struct perf_event *event) static inline int is_pebs_pt(struct perf_event *event)
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* From PPR Vol 1 for AMD Family 19h Model 01h B1
* 55898 Rev 0.35 - Feb 5, 2021
*/
#include <asm/msr-index.h>
/*
* IBS Hardware MSRs
*/
/* MSR 0xc0011030: IBS Fetch Control */
union ibs_fetch_ctl {
__u64 val;
struct {
__u64 fetch_maxcnt:16,/* 0-15: instruction fetch max. count */
fetch_cnt:16, /* 16-31: instruction fetch count */
fetch_lat:16, /* 32-47: instruction fetch latency */
fetch_en:1, /* 48: instruction fetch enable */
fetch_val:1, /* 49: instruction fetch valid */
fetch_comp:1, /* 50: instruction fetch complete */
ic_miss:1, /* 51: i-cache miss */
phy_addr_valid:1,/* 52: physical address valid */
l1tlb_pgsz:2, /* 53-54: i-cache L1TLB page size
* (needs IbsPhyAddrValid) */
l1tlb_miss:1, /* 55: i-cache fetch missed in L1TLB */
l2tlb_miss:1, /* 56: i-cache fetch missed in L2TLB */
rand_en:1, /* 57: random tagging enable */
fetch_l2_miss:1,/* 58: L2 miss for sampled fetch
* (needs IbsFetchComp) */
reserved:5; /* 59-63: reserved */
};
};
/* MSR 0xc0011033: IBS Execution Control */
union ibs_op_ctl {
__u64 val;
struct {
__u64 opmaxcnt:16, /* 0-15: periodic op max. count */
reserved0:1, /* 16: reserved */
op_en:1, /* 17: op sampling enable */
op_val:1, /* 18: op sample valid */
cnt_ctl:1, /* 19: periodic op counter control */
opmaxcnt_ext:7, /* 20-26: upper 7 bits of periodic op maximum count */
reserved1:5, /* 27-31: reserved */
opcurcnt:27, /* 32-58: periodic op counter current count */
reserved2:5; /* 59-63: reserved */
};
};
/* MSR 0xc0011035: IBS Op Data 2 */
union ibs_op_data {
__u64 val;
struct {
__u64 comp_to_ret_ctr:16, /* 0-15: op completion to retire count */
tag_to_ret_ctr:16, /* 15-31: op tag to retire count */
reserved1:2, /* 32-33: reserved */
op_return:1, /* 34: return op */
op_brn_taken:1, /* 35: taken branch op */
op_brn_misp:1, /* 36: mispredicted branch op */
op_brn_ret:1, /* 37: branch op retired */
op_rip_invalid:1, /* 38: RIP is invalid */
op_brn_fuse:1, /* 39: fused branch op */
op_microcode:1, /* 40: microcode op */
reserved2:23; /* 41-63: reserved */
};
};
/* MSR 0xc0011036: IBS Op Data 2 */
union ibs_op_data2 {
__u64 val;
struct {
__u64 data_src:3, /* 0-2: data source */
reserved0:1, /* 3: reserved */
rmt_node:1, /* 4: destination node */
cache_hit_st:1, /* 5: cache hit state */
reserved1:57; /* 5-63: reserved */
};
};
/* MSR 0xc0011037: IBS Op Data 3 */
union ibs_op_data3 {
__u64 val;
struct {
__u64 ld_op:1, /* 0: load op */
st_op:1, /* 1: store op */
dc_l1tlb_miss:1, /* 2: data cache L1TLB miss */
dc_l2tlb_miss:1, /* 3: data cache L2TLB hit in 2M page */
dc_l1tlb_hit_2m:1, /* 4: data cache L1TLB hit in 2M page */
dc_l1tlb_hit_1g:1, /* 5: data cache L1TLB hit in 1G page */
dc_l2tlb_hit_2m:1, /* 6: data cache L2TLB hit in 2M page */
dc_miss:1, /* 7: data cache miss */
dc_mis_acc:1, /* 8: misaligned access */
reserved:4, /* 9-12: reserved */
dc_wc_mem_acc:1, /* 13: write combining memory access */
dc_uc_mem_acc:1, /* 14: uncacheable memory access */
dc_locked_op:1, /* 15: locked operation */
dc_miss_no_mab_alloc:1, /* 16: DC miss with no MAB allocated */
dc_lin_addr_valid:1, /* 17: data cache linear address valid */
dc_phy_addr_valid:1, /* 18: data cache physical address valid */
dc_l2_tlb_hit_1g:1, /* 19: data cache L2 hit in 1GB page */
l2_miss:1, /* 20: L2 cache miss */
sw_pf:1, /* 21: software prefetch */
op_mem_width:4, /* 22-25: load/store size in bytes */
op_dc_miss_open_mem_reqs:6, /* 26-31: outstanding mem reqs on DC fill */
dc_miss_lat:16, /* 32-47: data cache miss latency */
tlb_refill_lat:16; /* 48-63: L1 TLB refill latency */
};
};
/* MSR 0xc001103c: IBS Fetch Control Extended */
union ic_ibs_extd_ctl {
__u64 val;
struct {
__u64 itlb_refill_lat:16, /* 0-15: ITLB Refill latency for sampled fetch */
reserved:48; /* 16-63: reserved */
};
};
/*
* IBS driver related
*/
struct perf_ibs_data {
u32 size;
union {
u32 data[0]; /* data buffer starts here */
u32 caps;
};
u64 regs[MSR_AMD64_IBS_REG_COUNT_MAX];
};
...@@ -30,6 +30,7 @@ enum cpuid_leafs ...@@ -30,6 +30,7 @@ enum cpuid_leafs
CPUID_7_ECX, CPUID_7_ECX,
CPUID_8000_0007_EBX, CPUID_8000_0007_EBX,
CPUID_7_EDX, CPUID_7_EDX,
CPUID_8000_001F_EAX,
}; };
#ifdef CONFIG_X86_FEATURE_NAMES #ifdef CONFIG_X86_FEATURE_NAMES
...@@ -88,8 +89,9 @@ extern const char * const x86_bug_flags[NBUGINTS*32]; ...@@ -88,8 +89,9 @@ extern const char * const x86_bug_flags[NBUGINTS*32];
CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 16, feature_bit) || \ CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 16, feature_bit) || \
CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 17, feature_bit) || \ CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 17, feature_bit) || \
CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 18, feature_bit) || \ CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 18, feature_bit) || \
CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 19, feature_bit) || \
REQUIRED_MASK_CHECK || \ REQUIRED_MASK_CHECK || \
BUILD_BUG_ON_ZERO(NCAPINTS != 19)) BUILD_BUG_ON_ZERO(NCAPINTS != 20))
#define DISABLED_MASK_BIT_SET(feature_bit) \ #define DISABLED_MASK_BIT_SET(feature_bit) \
( CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 0, feature_bit) || \ ( CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 0, feature_bit) || \
...@@ -111,8 +113,9 @@ extern const char * const x86_bug_flags[NBUGINTS*32]; ...@@ -111,8 +113,9 @@ extern const char * const x86_bug_flags[NBUGINTS*32];
CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 16, feature_bit) || \ CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 16, feature_bit) || \
CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 17, feature_bit) || \ CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 17, feature_bit) || \
CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 18, feature_bit) || \ CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 18, feature_bit) || \
CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 19, feature_bit) || \
DISABLED_MASK_CHECK || \ DISABLED_MASK_CHECK || \
BUILD_BUG_ON_ZERO(NCAPINTS != 19)) BUILD_BUG_ON_ZERO(NCAPINTS != 20))
#define cpu_has(c, bit) \ #define cpu_has(c, bit) \
(__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 : \ (__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 : \
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
/* /*
* Defines x86 CPU feature bits * Defines x86 CPU feature bits
*/ */
#define NCAPINTS 19 /* N 32-bit words worth of info */ #define NCAPINTS 20 /* N 32-bit words worth of info */
#define NBUGINTS 1 /* N 32-bit bug flags */ #define NBUGINTS 1 /* N 32-bit bug flags */
/* /*
...@@ -96,7 +96,7 @@ ...@@ -96,7 +96,7 @@
#define X86_FEATURE_SYSCALL32 ( 3*32+14) /* "" syscall in IA32 userspace */ #define X86_FEATURE_SYSCALL32 ( 3*32+14) /* "" syscall in IA32 userspace */
#define X86_FEATURE_SYSENTER32 ( 3*32+15) /* "" sysenter in IA32 userspace */ #define X86_FEATURE_SYSENTER32 ( 3*32+15) /* "" sysenter in IA32 userspace */
#define X86_FEATURE_REP_GOOD ( 3*32+16) /* REP microcode works well */ #define X86_FEATURE_REP_GOOD ( 3*32+16) /* REP microcode works well */
#define X86_FEATURE_SME_COHERENT ( 3*32+17) /* "" AMD hardware-enforced cache coherency */ /* FREE! ( 3*32+17) */
#define X86_FEATURE_LFENCE_RDTSC ( 3*32+18) /* "" LFENCE synchronizes RDTSC */ #define X86_FEATURE_LFENCE_RDTSC ( 3*32+18) /* "" LFENCE synchronizes RDTSC */
#define X86_FEATURE_ACC_POWER ( 3*32+19) /* AMD Accumulated Power Mechanism */ #define X86_FEATURE_ACC_POWER ( 3*32+19) /* AMD Accumulated Power Mechanism */
#define X86_FEATURE_NOPL ( 3*32+20) /* The NOPL (0F 1F) instructions */ #define X86_FEATURE_NOPL ( 3*32+20) /* The NOPL (0F 1F) instructions */
...@@ -201,7 +201,7 @@ ...@@ -201,7 +201,7 @@
#define X86_FEATURE_INVPCID_SINGLE ( 7*32+ 7) /* Effectively INVPCID && CR4.PCIDE=1 */ #define X86_FEATURE_INVPCID_SINGLE ( 7*32+ 7) /* Effectively INVPCID && CR4.PCIDE=1 */
#define X86_FEATURE_HW_PSTATE ( 7*32+ 8) /* AMD HW-PState */ #define X86_FEATURE_HW_PSTATE ( 7*32+ 8) /* AMD HW-PState */
#define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */ #define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */
#define X86_FEATURE_SME ( 7*32+10) /* AMD Secure Memory Encryption */ /* FREE! ( 7*32+10) */
#define X86_FEATURE_PTI ( 7*32+11) /* Kernel Page Table Isolation enabled */ #define X86_FEATURE_PTI ( 7*32+11) /* Kernel Page Table Isolation enabled */
#define X86_FEATURE_RETPOLINE ( 7*32+12) /* "" Generic Retpoline mitigation for Spectre variant 2 */ #define X86_FEATURE_RETPOLINE ( 7*32+12) /* "" Generic Retpoline mitigation for Spectre variant 2 */
#define X86_FEATURE_RETPOLINE_LFENCE ( 7*32+13) /* "" Use LFENCE for Spectre variant 2 */ #define X86_FEATURE_RETPOLINE_LFENCE ( 7*32+13) /* "" Use LFENCE for Spectre variant 2 */
...@@ -211,7 +211,7 @@ ...@@ -211,7 +211,7 @@
#define X86_FEATURE_SSBD ( 7*32+17) /* Speculative Store Bypass Disable */ #define X86_FEATURE_SSBD ( 7*32+17) /* Speculative Store Bypass Disable */
#define X86_FEATURE_MBA ( 7*32+18) /* Memory Bandwidth Allocation */ #define X86_FEATURE_MBA ( 7*32+18) /* Memory Bandwidth Allocation */
#define X86_FEATURE_RSB_CTXSW ( 7*32+19) /* "" Fill RSB on context switches */ #define X86_FEATURE_RSB_CTXSW ( 7*32+19) /* "" Fill RSB on context switches */
#define X86_FEATURE_SEV ( 7*32+20) /* AMD Secure Encrypted Virtualization */ #define X86_FEATURE_PERFMON_V2 ( 7*32+20) /* AMD Performance Monitoring Version 2 */
#define X86_FEATURE_USE_IBPB ( 7*32+21) /* "" Indirect Branch Prediction Barrier enabled */ #define X86_FEATURE_USE_IBPB ( 7*32+21) /* "" Indirect Branch Prediction Barrier enabled */
#define X86_FEATURE_USE_IBRS_FW ( 7*32+22) /* "" Use IBRS during runtime firmware calls */ #define X86_FEATURE_USE_IBRS_FW ( 7*32+22) /* "" Use IBRS during runtime firmware calls */
#define X86_FEATURE_SPEC_STORE_BYPASS_DISABLE ( 7*32+23) /* "" Disable Speculative Store Bypass. */ #define X86_FEATURE_SPEC_STORE_BYPASS_DISABLE ( 7*32+23) /* "" Disable Speculative Store Bypass. */
...@@ -236,7 +236,6 @@ ...@@ -236,7 +236,6 @@
#define X86_FEATURE_EPT_AD ( 8*32+17) /* Intel Extended Page Table access-dirty bit */ #define X86_FEATURE_EPT_AD ( 8*32+17) /* Intel Extended Page Table access-dirty bit */
#define X86_FEATURE_VMCALL ( 8*32+18) /* "" Hypervisor supports the VMCALL instruction */ #define X86_FEATURE_VMCALL ( 8*32+18) /* "" Hypervisor supports the VMCALL instruction */
#define X86_FEATURE_VMW_VMMCALL ( 8*32+19) /* "" VMware prefers VMMCALL hypercall instruction */ #define X86_FEATURE_VMW_VMMCALL ( 8*32+19) /* "" VMware prefers VMMCALL hypercall instruction */
#define X86_FEATURE_SEV_ES ( 8*32+20) /* AMD Secure Encrypted Virtualization - Encrypted State */
/* Intel-defined CPU features, CPUID level 0x00000007:0 (EBX), word 9 */ /* Intel-defined CPU features, CPUID level 0x00000007:0 (EBX), word 9 */
#define X86_FEATURE_FSGSBASE ( 9*32+ 0) /* RDFSBASE, WRFSBASE, RDGSBASE, WRGSBASE instructions*/ #define X86_FEATURE_FSGSBASE ( 9*32+ 0) /* RDFSBASE, WRFSBASE, RDGSBASE, WRGSBASE instructions*/
...@@ -313,6 +312,7 @@ ...@@ -313,6 +312,7 @@
#define X86_FEATURE_AMD_SSBD (13*32+24) /* "" Speculative Store Bypass Disable */ #define X86_FEATURE_AMD_SSBD (13*32+24) /* "" Speculative Store Bypass Disable */
#define X86_FEATURE_VIRT_SSBD (13*32+25) /* Virtualized Speculative Store Bypass Disable */ #define X86_FEATURE_VIRT_SSBD (13*32+25) /* Virtualized Speculative Store Bypass Disable */
#define X86_FEATURE_AMD_SSB_NO (13*32+26) /* "" Speculative Store Bypass is fixed in hardware. */ #define X86_FEATURE_AMD_SSB_NO (13*32+26) /* "" Speculative Store Bypass is fixed in hardware. */
#define X86_FEATURE_BRS (13*32+31) /* Branch Sampling available */
/* Thermal and Power Management Leaf, CPUID level 0x00000006 (EAX), word 14 */ /* Thermal and Power Management Leaf, CPUID level 0x00000006 (EAX), word 14 */
#define X86_FEATURE_DTHERM (14*32+ 0) /* Digital Thermal Sensor */ #define X86_FEATURE_DTHERM (14*32+ 0) /* Digital Thermal Sensor */
...@@ -393,6 +393,13 @@ ...@@ -393,6 +393,13 @@
#define X86_FEATURE_CORE_CAPABILITIES (18*32+30) /* "" IA32_CORE_CAPABILITIES MSR */ #define X86_FEATURE_CORE_CAPABILITIES (18*32+30) /* "" IA32_CORE_CAPABILITIES MSR */
#define X86_FEATURE_SPEC_CTRL_SSBD (18*32+31) /* "" Speculative Store Bypass Disable */ #define X86_FEATURE_SPEC_CTRL_SSBD (18*32+31) /* "" Speculative Store Bypass Disable */
/* AMD-defined memory encryption features, CPUID level 0x8000001f (EAX), word 19 */
#define X86_FEATURE_SME (19*32+ 0) /* AMD Secure Memory Encryption */
#define X86_FEATURE_SEV (19*32+ 1) /* AMD Secure Encrypted Virtualization */
#define X86_FEATURE_VM_PAGE_FLUSH (19*32+ 2) /* "" VM Page Flush MSR is supported */
#define X86_FEATURE_SEV_ES (19*32+ 3) /* AMD Secure Encrypted Virtualization - Encrypted State */
#define X86_FEATURE_SME_COHERENT (19*32+10) /* "" AMD hardware-enforced cache coherency */
/* /*
* BUG word(s) * BUG word(s)
*/ */
......
...@@ -88,6 +88,7 @@ ...@@ -88,6 +88,7 @@
DISABLE_ENQCMD) DISABLE_ENQCMD)
#define DISABLED_MASK17 0 #define DISABLED_MASK17 0
#define DISABLED_MASK18 0 #define DISABLED_MASK18 0
#define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 19) #define DISABLED_MASK19 0
#define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 20)
#endif /* _ASM_X86_DISABLED_FEATURES_H */ #endif /* _ASM_X86_DISABLED_FEATURES_H */
...@@ -498,6 +498,7 @@ ...@@ -498,6 +498,7 @@
#define MSR_AMD64_IBSOPDATA4 0xc001103d #define MSR_AMD64_IBSOPDATA4 0xc001103d
#define MSR_AMD64_IBS_REG_COUNT_MAX 8 /* includes MSR_AMD64_IBSBRTARGET */ #define MSR_AMD64_IBS_REG_COUNT_MAX 8 /* includes MSR_AMD64_IBSBRTARGET */
#define MSR_AMD64_SVM_AVIC_DOORBELL 0xc001011b #define MSR_AMD64_SVM_AVIC_DOORBELL 0xc001011b
#define MSR_AMD64_VM_PAGE_FLUSH 0xc001011e
#define MSR_AMD64_SEV_ES_GHCB 0xc0010130 #define MSR_AMD64_SEV_ES_GHCB 0xc0010130
#define MSR_AMD64_SEV 0xc0010131 #define MSR_AMD64_SEV 0xc0010131
#define MSR_AMD64_SEV_ENABLED_BIT 0 #define MSR_AMD64_SEV_ENABLED_BIT 0
...@@ -507,6 +508,11 @@ ...@@ -507,6 +508,11 @@
#define MSR_AMD64_VIRT_SPEC_CTRL 0xc001011f #define MSR_AMD64_VIRT_SPEC_CTRL 0xc001011f
/* AMD Performance Counter Global Status and Control MSRs */
#define MSR_AMD64_PERF_CNTR_GLOBAL_STATUS 0xc0000300
#define MSR_AMD64_PERF_CNTR_GLOBAL_CTL 0xc0000301
#define MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR 0xc0000302
/* Fam 17h MSRs */ /* Fam 17h MSRs */
#define MSR_F17H_IRPERF 0xc00000e9 #define MSR_F17H_IRPERF 0xc00000e9
...@@ -673,6 +679,10 @@ ...@@ -673,6 +679,10 @@
#define MSR_IA32_PERF_CTL 0x00000199 #define MSR_IA32_PERF_CTL 0x00000199
#define INTEL_PERF_CTL_MASK 0xffff #define INTEL_PERF_CTL_MASK 0xffff
/* AMD Branch Sampling configuration */
#define MSR_AMD_DBG_EXTN_CFG 0xc000010f
#define MSR_AMD_SAMP_BR_FROM 0xc0010300
#define MSR_IA32_MPERF 0x000000e7 #define MSR_IA32_MPERF 0x000000e7
#define MSR_IA32_APERF 0x000000e8 #define MSR_IA32_APERF 0x000000e8
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
#ifndef _ASM_X86_PERF_EVENT_H #ifndef _ASM_X86_PERF_EVENT_H
#define _ASM_X86_PERF_EVENT_H #define _ASM_X86_PERF_EVENT_H
#include <linux/static_call.h>
/* /*
* Performance event hw details: * Performance event hw details:
*/ */
...@@ -184,6 +186,18 @@ union cpuid28_ecx { ...@@ -184,6 +186,18 @@ union cpuid28_ecx {
unsigned int full; unsigned int full;
}; };
/*
* AMD "Extended Performance Monitoring and Debug" CPUID
* detection/enumeration details:
*/
union cpuid_0x80000022_ebx {
struct {
/* Number of Core Performance Counters */
unsigned int num_core_pmc:4;
} split;
unsigned int full;
};
struct x86_pmu_capability { struct x86_pmu_capability {
int version; int version;
int num_counters_gp; int num_counters_gp;
...@@ -365,6 +379,11 @@ struct pebs_xmm { ...@@ -365,6 +379,11 @@ struct pebs_xmm {
u64 xmm[16*2]; /* two entries for each register */ u64 xmm[16*2]; /* two entries for each register */
}; };
/*
* AMD Extended Performance Monitoring and Debug cpuid feature detection
*/
#define EXT_PERFMON_DEBUG_FEATURES 0x80000022
/* /*
* IBS cpuid feature detection * IBS cpuid feature detection
*/ */
...@@ -386,6 +405,7 @@ struct pebs_xmm { ...@@ -386,6 +405,7 @@ struct pebs_xmm {
#define IBS_CAPS_OPBRNFUSE (1U<<8) #define IBS_CAPS_OPBRNFUSE (1U<<8)
#define IBS_CAPS_FETCHCTLEXTD (1U<<9) #define IBS_CAPS_FETCHCTLEXTD (1U<<9)
#define IBS_CAPS_OPDATA4 (1U<<10) #define IBS_CAPS_OPDATA4 (1U<<10)
#define IBS_CAPS_ZEN4 (1U<<11)
#define IBS_CAPS_DEFAULT (IBS_CAPS_AVAIL \ #define IBS_CAPS_DEFAULT (IBS_CAPS_AVAIL \
| IBS_CAPS_FETCHSAM \ | IBS_CAPS_FETCHSAM \
...@@ -399,6 +419,7 @@ struct pebs_xmm { ...@@ -399,6 +419,7 @@ struct pebs_xmm {
#define IBSCTL_LVT_OFFSET_MASK 0x0F #define IBSCTL_LVT_OFFSET_MASK 0x0F
/* IBS fetch bits/masks */ /* IBS fetch bits/masks */
#define IBS_FETCH_L3MISSONLY (1ULL<<59)
#define IBS_FETCH_RAND_EN (1ULL<<57) #define IBS_FETCH_RAND_EN (1ULL<<57)
#define IBS_FETCH_VAL (1ULL<<49) #define IBS_FETCH_VAL (1ULL<<49)
#define IBS_FETCH_ENABLE (1ULL<<48) #define IBS_FETCH_ENABLE (1ULL<<48)
...@@ -415,6 +436,7 @@ struct pebs_xmm { ...@@ -415,6 +436,7 @@ struct pebs_xmm {
#define IBS_OP_CNT_CTL (1ULL<<19) #define IBS_OP_CNT_CTL (1ULL<<19)
#define IBS_OP_VAL (1ULL<<18) #define IBS_OP_VAL (1ULL<<18)
#define IBS_OP_ENABLE (1ULL<<17) #define IBS_OP_ENABLE (1ULL<<17)
#define IBS_OP_L3MISSONLY (1ULL<<16)
#define IBS_OP_MAX_CNT 0x0000FFFFULL #define IBS_OP_MAX_CNT 0x0000FFFFULL
#define IBS_OP_MAX_CNT_EXT 0x007FFFFFULL /* not a register bit mask */ #define IBS_OP_MAX_CNT_EXT 0x007FFFFFULL /* not a register bit mask */
#define IBS_OP_MAX_CNT_EXT_MASK (0x7FULL<<20) /* separate upper 7 bits */ #define IBS_OP_MAX_CNT_EXT_MASK (0x7FULL<<20) /* separate upper 7 bits */
...@@ -516,6 +538,27 @@ static inline void intel_pt_handle_vmx(int on) ...@@ -516,6 +538,27 @@ static inline void intel_pt_handle_vmx(int on)
#if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_AMD) #if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_AMD)
extern void amd_pmu_enable_virt(void); extern void amd_pmu_enable_virt(void);
extern void amd_pmu_disable_virt(void); extern void amd_pmu_disable_virt(void);
#if defined(CONFIG_PERF_EVENTS_AMD_BRS)
#define PERF_NEEDS_LOPWR_CB 1
/*
* architectural low power callback impacts
* drivers/acpi/processor_idle.c
* drivers/acpi/acpi_pad.c
*/
extern void perf_amd_brs_lopwr_cb(bool lopwr_in);
DECLARE_STATIC_CALL(perf_lopwr_cb, perf_amd_brs_lopwr_cb);
static inline void perf_lopwr_cb(bool lopwr_in)
{
static_call_mod(perf_lopwr_cb)(lopwr_in);
}
#endif /* PERF_NEEDS_LOPWR_CB */
#else #else
static inline void amd_pmu_enable_virt(void) { } static inline void amd_pmu_enable_virt(void) { }
static inline void amd_pmu_disable_virt(void) { } static inline void amd_pmu_disable_virt(void) { }
......
...@@ -101,6 +101,7 @@ ...@@ -101,6 +101,7 @@
#define REQUIRED_MASK16 0 #define REQUIRED_MASK16 0
#define REQUIRED_MASK17 0 #define REQUIRED_MASK17 0
#define REQUIRED_MASK18 0 #define REQUIRED_MASK18 0
#define REQUIRED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 19) #define REQUIRED_MASK19 0
#define REQUIRED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 20)
#endif /* _ASM_X86_REQUIRED_FEATURES_H */ #endif /* _ASM_X86_REQUIRED_FEATURES_H */
...@@ -957,6 +957,9 @@ void get_cpu_cap(struct cpuinfo_x86 *c) ...@@ -957,6 +957,9 @@ void get_cpu_cap(struct cpuinfo_x86 *c)
if (c->extended_cpuid_level >= 0x8000000a) if (c->extended_cpuid_level >= 0x8000000a)
c->x86_capability[CPUID_8000_000A_EDX] = cpuid_edx(0x8000000a); c->x86_capability[CPUID_8000_000A_EDX] = cpuid_edx(0x8000000a);
if (c->extended_cpuid_level >= 0x8000001f)
c->x86_capability[CPUID_8000_001F_EAX] = cpuid_eax(0x8000001f);
init_scattered_cpuid_features(c); init_scattered_cpuid_features(c);
init_speculation_control(c); init_speculation_control(c);
......
...@@ -42,10 +42,7 @@ static const struct cpuid_bit cpuid_bits[] = { ...@@ -42,10 +42,7 @@ static const struct cpuid_bit cpuid_bits[] = {
{ X86_FEATURE_CPB, CPUID_EDX, 9, 0x80000007, 0 }, { X86_FEATURE_CPB, CPUID_EDX, 9, 0x80000007, 0 },
{ X86_FEATURE_PROC_FEEDBACK, CPUID_EDX, 11, 0x80000007, 0 }, { X86_FEATURE_PROC_FEEDBACK, CPUID_EDX, 11, 0x80000007, 0 },
{ X86_FEATURE_MBA, CPUID_EBX, 6, 0x80000008, 0 }, { X86_FEATURE_MBA, CPUID_EBX, 6, 0x80000008, 0 },
{ X86_FEATURE_SME, CPUID_EAX, 0, 0x8000001f, 0 }, { X86_FEATURE_PERFMON_V2, CPUID_EAX, 0, 0x80000022, 0 },
{ X86_FEATURE_SEV, CPUID_EAX, 1, 0x8000001f, 0 },
{ X86_FEATURE_SEV_ES, CPUID_EAX, 3, 0x8000001f, 0 },
{ X86_FEATURE_SME_COHERENT, CPUID_EAX, 10, 0x8000001f, 0 },
{ 0, 0, 0, 0, 0 } { 0, 0, 0, 0, 0 }
}; };
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/tick.h> #include <linux/tick.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/perf_event.h>
#include <asm/mwait.h> #include <asm/mwait.h>
#include <xen/xen.h> #include <xen/xen.h>
...@@ -163,6 +164,9 @@ static int power_saving_thread(void *data) ...@@ -163,6 +164,9 @@ static int power_saving_thread(void *data)
tsc_marked_unstable = 1; tsc_marked_unstable = 1;
} }
local_irq_disable(); local_irq_disable();
perf_lopwr_cb(true);
tick_broadcast_enable(); tick_broadcast_enable();
tick_broadcast_enter(); tick_broadcast_enter();
stop_critical_timings(); stop_critical_timings();
...@@ -171,6 +175,9 @@ static int power_saving_thread(void *data) ...@@ -171,6 +175,9 @@ static int power_saving_thread(void *data)
start_critical_timings(); start_critical_timings();
tick_broadcast_exit(); tick_broadcast_exit();
perf_lopwr_cb(false);
local_irq_enable(); local_irq_enable();
if (time_before(expire_time, jiffies)) { if (time_before(expire_time, jiffies)) {
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/tick.h> #include <linux/tick.h>
#include <linux/cpuidle.h> #include <linux/cpuidle.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/perf_event.h>
#include <acpi/processor.h> #include <acpi/processor.h>
/* /*
...@@ -551,6 +552,8 @@ static void wait_for_freeze(void) ...@@ -551,6 +552,8 @@ static void wait_for_freeze(void)
*/ */
static void __cpuidle acpi_idle_do_entry(struct acpi_processor_cx *cx) static void __cpuidle acpi_idle_do_entry(struct acpi_processor_cx *cx)
{ {
perf_lopwr_cb(true);
if (cx->entry_method == ACPI_CSTATE_FFH) { if (cx->entry_method == ACPI_CSTATE_FFH) {
/* Call into architectural FFH based C-state */ /* Call into architectural FFH based C-state */
acpi_processor_ffh_cstate_enter(cx); acpi_processor_ffh_cstate_enter(cx);
...@@ -561,6 +564,8 @@ static void __cpuidle acpi_idle_do_entry(struct acpi_processor_cx *cx) ...@@ -561,6 +564,8 @@ static void __cpuidle acpi_idle_do_entry(struct acpi_processor_cx *cx)
inb(cx->address); inb(cx->address);
wait_for_freeze(); wait_for_freeze();
} }
perf_lopwr_cb(false);
} }
/** /**
......
...@@ -1062,6 +1062,22 @@ static inline void perf_sample_data_init(struct perf_sample_data *data, ...@@ -1062,6 +1062,22 @@ static inline void perf_sample_data_init(struct perf_sample_data *data,
data->txn = 0; data->txn = 0;
} }
/*
* Clear all bitfields in the perf_branch_entry.
* The to and from fields are not cleared because they are
* systematically modified by caller.
*/
static inline void perf_clear_branch_entry_bitfields(struct perf_branch_entry *br)
{
br->mispred = 0;
br->predicted = 0;
br->in_tx = 0;
br->abort = 0;
br->cycles = 0;
br->type = 0;
br->reserved = 0;
}
extern void perf_output_sample(struct perf_output_handle *handle, extern void perf_output_sample(struct perf_output_handle *handle,
struct perf_event_header *header, struct perf_event_header *header,
struct perf_sample_data *data, struct perf_sample_data *data,
...@@ -1608,4 +1624,11 @@ extern void __weak arch_perf_update_userpage(struct perf_event *event, ...@@ -1608,4 +1624,11 @@ extern void __weak arch_perf_update_userpage(struct perf_event *event,
struct perf_event_mmap_page *userpg, struct perf_event_mmap_page *userpg,
u64 now); u64 now);
#ifndef PERF_NEEDS_LOPWR_CB
static inline void perf_lopwr_cb(bool mode)
{
}
#endif
#endif /* _LINUX_PERF_EVENT_H */ #endif /* _LINUX_PERF_EVENT_H */
...@@ -85,6 +85,7 @@ ...@@ -85,6 +85,7 @@
DISABLE_ENQCMD) DISABLE_ENQCMD)
#define DISABLED_MASK17 0 #define DISABLED_MASK17 0
#define DISABLED_MASK18 0 #define DISABLED_MASK18 0
#define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 19) #define DISABLED_MASK19 0
#define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 20)
#endif /* _ASM_X86_DISABLED_FEATURES_H */ #endif /* _ASM_X86_DISABLED_FEATURES_H */
...@@ -101,6 +101,7 @@ ...@@ -101,6 +101,7 @@
#define REQUIRED_MASK16 0 #define REQUIRED_MASK16 0
#define REQUIRED_MASK17 0 #define REQUIRED_MASK17 0
#define REQUIRED_MASK18 0 #define REQUIRED_MASK18 0
#define REQUIRED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 19) #define REQUIRED_MASK19 0
#define REQUIRED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 20)
#endif /* _ASM_X86_REQUIRED_FEATURES_H */ #endif /* _ASM_X86_REQUIRED_FEATURES_H */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册