Skip to content

Commit

Permalink
Merge tag 'perf-core-2022-03-21' of git://git.kernel.org/pub/scm/linu…
Browse files Browse the repository at this point in the history
…x/kernel/git/tip/tip

Pull x86 perf event updates from Ingo Molnar:

 - Fix address filtering for Intel/PT,ARM/CoreSight

 - Enable Intel/PEBS format 5

 - Allow more fixed-function counters for x86

 - Intel/PT: Enable not recording Taken-Not-Taken packets

 - Add a few branch-types

* tag 'perf-core-2022-03-21' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  perf/x86/intel/uncore: Fix the build on !CONFIG_PHYS_ADDR_T_64BIT
  perf: Add irq and exception return branch types
  perf/x86/intel/uncore: Make uncore_discovery clean for 64 bit addresses
  perf/x86/intel/pt: Add a capability and config bit for disabling TNTs
  perf/x86/intel/pt: Add a capability and config bit for event tracing
  perf/x86/intel: Increase max number of the fixed counters
  KVM: x86: use the KVM side max supported fixed counter
  perf/x86/intel: Enable PEBS format 5
  perf/core: Allow kernel address filter when not filtering the kernel
  perf/x86/intel/pt: Fix address filter config for 32-bit kernel
  perf/core: Fix address filter parser for multiple filters
  x86: Share definition of __is_canonical_address()
  perf/x86/intel/pt: Relax address filter validation
  • Loading branch information
torvalds committed Mar 22, 2022
2 parents 5191290 + 02a08d7 commit 95ab0e8
Show file tree
Hide file tree
Showing 23 changed files with 161 additions and 54 deletions.
40 changes: 39 additions & 1 deletion arch/x86/events/intel/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,27 @@ static struct event_constraint intel_gen_event_constraints[] __read_mostly =
EVENT_CONSTRAINT_END
};

static struct event_constraint intel_v5_gen_event_constraints[] __read_mostly =
{
FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */
FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */
FIXED_EVENT_CONSTRAINT(0x0300, 2), /* CPU_CLK_UNHALTED.REF */
FIXED_EVENT_CONSTRAINT(0x0400, 3), /* SLOTS */
FIXED_EVENT_CONSTRAINT(0x0500, 4),
FIXED_EVENT_CONSTRAINT(0x0600, 5),
FIXED_EVENT_CONSTRAINT(0x0700, 6),
FIXED_EVENT_CONSTRAINT(0x0800, 7),
FIXED_EVENT_CONSTRAINT(0x0900, 8),
FIXED_EVENT_CONSTRAINT(0x0a00, 9),
FIXED_EVENT_CONSTRAINT(0x0b00, 10),
FIXED_EVENT_CONSTRAINT(0x0c00, 11),
FIXED_EVENT_CONSTRAINT(0x0d00, 12),
FIXED_EVENT_CONSTRAINT(0x0e00, 13),
FIXED_EVENT_CONSTRAINT(0x0f00, 14),
FIXED_EVENT_CONSTRAINT(0x1000, 15),
EVENT_CONSTRAINT_END
};

static struct event_constraint intel_slm_event_constraints[] __read_mostly =
{
FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */
Expand Down Expand Up @@ -6308,14 +6329,31 @@ __init int intel_pmu_init(void)
pr_cont("generic architected perfmon v1, ");
name = "generic_arch_v1";
break;
default:
case 2:
case 3:
case 4:
/*
* default constraints for v2 and up
*/
x86_pmu.event_constraints = intel_gen_event_constraints;
pr_cont("generic architected perfmon, ");
name = "generic_arch_v2+";
break;
default:
/*
* The default constraints for v5 and up can support up to
* 16 fixed counters. For the fixed counters 4 and later,
* the pseudo-encoding is applied.
* The constraints may be cut according to the CPUID enumeration
* by inserting the EVENT_CONSTRAINT_END.
*/
if (x86_pmu.num_counters_fixed > INTEL_PMC_MAX_FIXED)
x86_pmu.num_counters_fixed = INTEL_PMC_MAX_FIXED;
intel_v5_gen_event_constraints[x86_pmu.num_counters_fixed].weight = -1;
x86_pmu.event_constraints = intel_v5_gen_event_constraints;
pr_cont("generic architected perfmon, ");
name = "generic_arch_v5+";
break;
}
}

Expand Down
14 changes: 11 additions & 3 deletions arch/x86/events/intel/ds.c
Original file line number Diff line number Diff line change
Expand Up @@ -1203,7 +1203,10 @@ static void intel_pmu_pebs_via_pt_enable(struct perf_event *event)
if (hwc->idx >= INTEL_PMC_IDX_FIXED) {
base = MSR_RELOAD_FIXED_CTR0;
idx = hwc->idx - INTEL_PMC_IDX_FIXED;
value = ds->pebs_event_reset[MAX_PEBS_EVENTS + idx];
if (x86_pmu.intel_cap.pebs_format < 5)
value = ds->pebs_event_reset[MAX_PEBS_EVENTS_FMT4 + idx];
else
value = ds->pebs_event_reset[MAX_PEBS_EVENTS + idx];
}
wrmsrl(base + idx, value);
}
Expand Down Expand Up @@ -1232,8 +1235,12 @@ void intel_pmu_pebs_enable(struct perf_event *event)
}
}

if (idx >= INTEL_PMC_IDX_FIXED)
idx = MAX_PEBS_EVENTS + (idx - INTEL_PMC_IDX_FIXED);
if (idx >= INTEL_PMC_IDX_FIXED) {
if (x86_pmu.intel_cap.pebs_format < 5)
idx = MAX_PEBS_EVENTS_FMT4 + (idx - INTEL_PMC_IDX_FIXED);
else
idx = MAX_PEBS_EVENTS + (idx - INTEL_PMC_IDX_FIXED);
}

/*
* Use auto-reload if possible to save a MSR write in the PMI.
Expand Down Expand Up @@ -2204,6 +2211,7 @@ void __init intel_ds_init(void)
break;

case 4:
case 5:
x86_pmu.drain_pebs = intel_pmu_drain_pebs_icl;
x86_pmu.pebs_record_size = sizeof(struct pebs_basic);
if (x86_pmu.intel_cap.pebs_baseline) {
Expand Down
4 changes: 2 additions & 2 deletions arch/x86/events/intel/lbr.c
Original file line number Diff line number Diff line change
Expand Up @@ -1329,10 +1329,10 @@ static int branch_map[X86_BR_TYPE_MAP_MAX] = {
PERF_BR_SYSCALL, /* X86_BR_SYSCALL */
PERF_BR_SYSRET, /* X86_BR_SYSRET */
PERF_BR_UNKNOWN, /* X86_BR_INT */
PERF_BR_UNKNOWN, /* X86_BR_IRET */
PERF_BR_ERET, /* X86_BR_IRET */
PERF_BR_COND, /* X86_BR_JCC */
PERF_BR_UNCOND, /* X86_BR_JMP */
PERF_BR_UNKNOWN, /* X86_BR_IRQ */
PERF_BR_IRQ, /* X86_BR_IRQ */
PERF_BR_IND_CALL, /* X86_BR_IND_CALL */
PERF_BR_UNKNOWN, /* X86_BR_ABORT */
PERF_BR_UNKNOWN, /* X86_BR_IN_TX */
Expand Down
71 changes: 57 additions & 14 deletions arch/x86/events/intel/pt.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/types.h>
#include <linux/bits.h>
#include <linux/limits.h>
#include <linux/slab.h>
#include <linux/device.h>

Expand Down Expand Up @@ -57,6 +59,8 @@ static struct pt_cap_desc {
PT_CAP(mtc, 0, CPUID_EBX, BIT(3)),
PT_CAP(ptwrite, 0, CPUID_EBX, BIT(4)),
PT_CAP(power_event_trace, 0, CPUID_EBX, BIT(5)),
PT_CAP(event_trace, 0, CPUID_EBX, BIT(7)),
PT_CAP(tnt_disable, 0, CPUID_EBX, BIT(8)),
PT_CAP(topa_output, 0, CPUID_ECX, BIT(0)),
PT_CAP(topa_multiple_entries, 0, CPUID_ECX, BIT(1)),
PT_CAP(single_range_output, 0, CPUID_ECX, BIT(2)),
Expand Down Expand Up @@ -108,6 +112,8 @@ PMU_FORMAT_ATTR(tsc, "config:10" );
PMU_FORMAT_ATTR(noretcomp, "config:11" );
PMU_FORMAT_ATTR(ptw, "config:12" );
PMU_FORMAT_ATTR(branch, "config:13" );
PMU_FORMAT_ATTR(event, "config:31" );
PMU_FORMAT_ATTR(notnt, "config:55" );
PMU_FORMAT_ATTR(mtc_period, "config:14-17" );
PMU_FORMAT_ATTR(cyc_thresh, "config:19-22" );
PMU_FORMAT_ATTR(psb_period, "config:24-27" );
Expand All @@ -116,6 +122,8 @@ static struct attribute *pt_formats_attr[] = {
&format_attr_pt.attr,
&format_attr_cyc.attr,
&format_attr_pwr_evt.attr,
&format_attr_event.attr,
&format_attr_notnt.attr,
&format_attr_fup_on_ptw.attr,
&format_attr_mtc.attr,
&format_attr_tsc.attr,
Expand Down Expand Up @@ -296,6 +304,8 @@ static int __init pt_pmu_hw_init(void)
RTIT_CTL_CYC_PSB | \
RTIT_CTL_MTC | \
RTIT_CTL_PWR_EVT_EN | \
RTIT_CTL_EVENT_EN | \
RTIT_CTL_NOTNT | \
RTIT_CTL_FUP_ON_PTW | \
RTIT_CTL_PTW_EN)

Expand Down Expand Up @@ -350,6 +360,14 @@ static bool pt_event_valid(struct perf_event *event)
!intel_pt_validate_hw_cap(PT_CAP_power_event_trace))
return false;

if (config & RTIT_CTL_EVENT_EN &&
!intel_pt_validate_hw_cap(PT_CAP_event_trace))
return false;

if (config & RTIT_CTL_NOTNT &&
!intel_pt_validate_hw_cap(PT_CAP_tnt_disable))
return false;

if (config & RTIT_CTL_PTW) {
if (!intel_pt_validate_hw_cap(PT_CAP_ptwrite))
return false;
Expand Down Expand Up @@ -472,7 +490,7 @@ static u64 pt_config_filters(struct perf_event *event)
pt->filters.filter[range].msr_b = filter->msr_b;
}

rtit_ctl |= filter->config << pt_address_ranges[range].reg_off;
rtit_ctl |= (u64)filter->config << pt_address_ranges[range].reg_off;
}

return rtit_ctl;
Expand Down Expand Up @@ -1348,10 +1366,26 @@ static void pt_addr_filters_fini(struct perf_event *event)
event->hw.addr_filters = NULL;
}

static inline bool valid_kernel_ip(unsigned long ip)
#ifdef CONFIG_X86_64
/* Clamp to a canonical address greater-than-or-equal-to the address given */
static u64 clamp_to_ge_canonical_addr(u64 vaddr, u8 vaddr_bits)
{
return __is_canonical_address(vaddr, vaddr_bits) ?
vaddr :
-BIT_ULL(vaddr_bits - 1);
}

/* Clamp to a canonical address less-than-or-equal-to the address given */
static u64 clamp_to_le_canonical_addr(u64 vaddr, u8 vaddr_bits)
{
return virt_addr_valid(ip) && kernel_ip(ip);
return __is_canonical_address(vaddr, vaddr_bits) ?
vaddr :
BIT_ULL(vaddr_bits - 1) - 1;
}
#else
#define clamp_to_ge_canonical_addr(x, y) (x)
#define clamp_to_le_canonical_addr(x, y) (x)
#endif

static int pt_event_addr_filters_validate(struct list_head *filters)
{
Expand All @@ -1367,14 +1401,6 @@ static int pt_event_addr_filters_validate(struct list_head *filters)
filter->action == PERF_ADDR_FILTER_ACTION_START)
return -EOPNOTSUPP;

if (!filter->path.dentry) {
if (!valid_kernel_ip(filter->offset))
return -EINVAL;

if (!valid_kernel_ip(filter->offset + filter->size))
return -EINVAL;
}

if (++range > intel_pt_validate_hw_cap(PT_CAP_num_address_ranges))
return -EOPNOTSUPP;
}
Expand All @@ -1398,9 +1424,26 @@ static void pt_event_addr_filters_sync(struct perf_event *event)
if (filter->path.dentry && !fr[range].start) {
msr_a = msr_b = 0;
} else {
/* apply the offset */
msr_a = fr[range].start;
msr_b = msr_a + fr[range].size - 1;
unsigned long n = fr[range].size - 1;
unsigned long a = fr[range].start;
unsigned long b;

if (a > ULONG_MAX - n)
b = ULONG_MAX;
else
b = a + n;
/*
* Apply the offset. 64-bit addresses written to the
* MSRs must be canonical, but the range can encompass
* non-canonical addresses. Since software cannot
* execute at non-canonical addresses, adjusting to
* canonical addresses does not affect the result of the
* address filter.
*/
msr_a = clamp_to_ge_canonical_addr(a, boot_cpu_data.x86_virt_bits);
msr_b = clamp_to_le_canonical_addr(b, boot_cpu_data.x86_virt_bits);
if (msr_b < msr_a)
msr_a = msr_b = 0;
}

filters->filter[range].msr_a = msr_a;
Expand Down
16 changes: 12 additions & 4 deletions arch/x86/events/intel/uncore_discovery.c
Original file line number Diff line number Diff line change
Expand Up @@ -215,10 +215,18 @@ static int parse_discovery_table(struct pci_dev *dev, int die,

pci_read_config_dword(dev, bar_offset, &val);

if (val & UNCORE_DISCOVERY_MASK)
if (val & ~PCI_BASE_ADDRESS_MEM_MASK & ~PCI_BASE_ADDRESS_MEM_TYPE_64)
return -EINVAL;

addr = (resource_size_t)(val & ~UNCORE_DISCOVERY_MASK);
addr = (resource_size_t)(val & PCI_BASE_ADDRESS_MEM_MASK);
#ifdef CONFIG_PHYS_ADDR_T_64BIT
if ((val & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64) {
u32 val2;

pci_read_config_dword(dev, bar_offset + 4, &val2);
addr |= ((resource_size_t)val2) << 32;
}
#endif
size = UNCORE_DISCOVERY_GLOBAL_MAP_SIZE;
io_addr = ioremap(addr, size);
if (!io_addr)
Expand Down Expand Up @@ -444,7 +452,7 @@ static struct intel_uncore_ops generic_uncore_pci_ops = {

#define UNCORE_GENERIC_MMIO_SIZE 0x4000

static unsigned int generic_uncore_mmio_box_ctl(struct intel_uncore_box *box)
static u64 generic_uncore_mmio_box_ctl(struct intel_uncore_box *box)
{
struct intel_uncore_type *type = box->pmu->type;

Expand All @@ -456,7 +464,7 @@ static unsigned int generic_uncore_mmio_box_ctl(struct intel_uncore_box *box)

void intel_generic_uncore_mmio_init_box(struct intel_uncore_box *box)
{
unsigned int box_ctl = generic_uncore_mmio_box_ctl(box);
u64 box_ctl = generic_uncore_mmio_box_ctl(box);
struct intel_uncore_type *type = box->pmu->type;
resource_size_t addr;

Expand Down
2 changes: 0 additions & 2 deletions arch/x86/events/intel/uncore_discovery.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@
#define UNCORE_DISCOVERY_BIR_BASE 0x10
/* Discovery table BAR step */
#define UNCORE_DISCOVERY_BIR_STEP 0x4
/* Mask of the discovery table offset */
#define UNCORE_DISCOVERY_MASK 0xf
/* Global discovery table size */
#define UNCORE_DISCOVERY_GLOBAL_MAP_SIZE 0x20

Expand Down
5 changes: 3 additions & 2 deletions arch/x86/include/asm/intel_ds.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@
#define PEBS_BUFFER_SIZE (PAGE_SIZE << 4)

/* The maximal number of PEBS events: */
#define MAX_PEBS_EVENTS 8
#define MAX_FIXED_PEBS_EVENTS 4
#define MAX_PEBS_EVENTS_FMT4 8
#define MAX_PEBS_EVENTS 32
#define MAX_FIXED_PEBS_EVENTS 16

/*
* A debug store configuration.
Expand Down
2 changes: 2 additions & 0 deletions arch/x86/include/asm/intel_pt.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ enum pt_capabilities {
PT_CAP_mtc,
PT_CAP_ptwrite,
PT_CAP_power_event_trace,
PT_CAP_event_trace,
PT_CAP_tnt_disable,
PT_CAP_topa_output,
PT_CAP_topa_multiple_entries,
PT_CAP_single_range_output,
Expand Down
3 changes: 2 additions & 1 deletion arch/x86/include/asm/kvm_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,7 @@ struct kvm_pmc {
bool intr;
};

#define KVM_PMC_MAX_FIXED 3
struct kvm_pmu {
unsigned nr_arch_gp_counters;
unsigned nr_arch_fixed_counters;
Expand All @@ -511,7 +512,7 @@ struct kvm_pmu {
u64 reserved_bits;
u8 version;
struct kvm_pmc gp_counters[INTEL_PMC_MAX_GENERIC];
struct kvm_pmc fixed_counters[INTEL_PMC_MAX_FIXED];
struct kvm_pmc fixed_counters[KVM_PMC_MAX_FIXED];
struct irq_work irq_work;
DECLARE_BITMAP(reprogram_pmi, X86_PMC_IDX_MAX);
DECLARE_BITMAP(all_valid_pmc_idx, X86_PMC_IDX_MAX);
Expand Down
2 changes: 2 additions & 0 deletions arch/x86/include/asm/msr-index.h
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@
#define RTIT_CTL_DISRETC BIT(11)
#define RTIT_CTL_PTW_EN BIT(12)
#define RTIT_CTL_BRANCH_EN BIT(13)
#define RTIT_CTL_EVENT_EN BIT(31)
#define RTIT_CTL_NOTNT BIT_ULL(55)
#define RTIT_CTL_MTC_RANGE_OFFSET 14
#define RTIT_CTL_MTC_RANGE (0x0full << RTIT_CTL_MTC_RANGE_OFFSET)
#define RTIT_CTL_CYC_THRESH_OFFSET 19
Expand Down
10 changes: 10 additions & 0 deletions arch/x86/include/asm/page.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,16 @@ static inline void copy_user_page(void *to, void *from, unsigned long vaddr,
extern bool __virt_addr_valid(unsigned long kaddr);
#define virt_addr_valid(kaddr) __virt_addr_valid((unsigned long) (kaddr))

static __always_inline u64 __canonical_address(u64 vaddr, u8 vaddr_bits)
{
return ((s64)vaddr << (64 - vaddr_bits)) >> (64 - vaddr_bits);
}

static __always_inline u64 __is_canonical_address(u64 vaddr, u8 vaddr_bits)
{
return __canonical_address(vaddr, vaddr_bits) == vaddr;
}

#endif /* __ASSEMBLY__ */

#include <asm-generic/memory_model.h>
Expand Down
2 changes: 1 addition & 1 deletion arch/x86/include/asm/perf_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

#define INTEL_PMC_MAX_GENERIC 32
#define INTEL_PMC_MAX_FIXED 4
#define INTEL_PMC_MAX_FIXED 16
#define INTEL_PMC_IDX_FIXED 32

#define X86_PMC_IDX_MAX 64
Expand Down
3 changes: 2 additions & 1 deletion arch/x86/kvm/cpuid.c
Original file line number Diff line number Diff line change
Expand Up @@ -879,7 +879,8 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
eax.split.bit_width = cap.bit_width_gp;
eax.split.mask_length = cap.events_mask_len;

edx.split.num_counters_fixed = min(cap.num_counters_fixed, MAX_FIXED_COUNTERS);
edx.split.num_counters_fixed =
min(cap.num_counters_fixed, KVM_PMC_MAX_FIXED);
edx.split.bit_width_fixed = cap.bit_width_fixed;
if (cap.version)
edx.split.anythread_deprecated = 1;
Expand Down
Loading

0 comments on commit 95ab0e8

Please sign in to comment.