diff options
Diffstat (limited to 'arch/x86/kernel')
| -rw-r--r-- | arch/x86/kernel/cpu/amd.c | 19 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/perf_event.h | 4 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/perf_event_amd_ibs.c | 15 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/perf_event_intel_ds.c | 81 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c | 8 | ||||
| -rw-r--r-- | arch/x86/kernel/hw_breakpoint.c | 45 | 
6 files changed, 115 insertions, 57 deletions
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 813d29d00a17..abe4ec760db3 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -870,3 +870,22 @@ static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum)  	return false;  } + +void set_dr_addr_mask(unsigned long mask, int dr) +{ +	if (!cpu_has_bpext) +		return; + +	switch (dr) { +	case 0: +		wrmsr(MSR_F16H_DR0_ADDR_MASK, mask, 0); +		break; +	case 1: +	case 2: +	case 3: +		wrmsr(MSR_F16H_DR1_ADDR_MASK - 1 + dr, mask, 0); +		break; +	default: +		break; +	} +} diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h index fc5eb390b368..4e6cdb0ddc70 100644 --- a/arch/x86/kernel/cpu/perf_event.h +++ b/arch/x86/kernel/cpu/perf_event.h @@ -253,6 +253,10 @@ struct cpu_hw_events {  #define INTEL_UEVENT_CONSTRAINT(c, n)	\  	EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK) +/* Like UEVENT_CONSTRAINT, but match flags too */ +#define INTEL_FLAGS_UEVENT_CONSTRAINT(c, n)	\ +	EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS) +  #define INTEL_PLD_CONSTRAINT(c, n)	\  	__EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \  			   HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_LDLAT) diff --git a/arch/x86/kernel/cpu/perf_event_amd_ibs.c b/arch/x86/kernel/cpu/perf_event_amd_ibs.c index cbb1be3ed9e4..a61f5c6911da 100644 --- a/arch/x86/kernel/cpu/perf_event_amd_ibs.c +++ b/arch/x86/kernel/cpu/perf_event_amd_ibs.c @@ -565,6 +565,21 @@ static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs)  				       perf_ibs->offset_max,  				       offset + 1);  	} while (offset < offset_max); +	if (event->attr.sample_type & PERF_SAMPLE_RAW) { +		/* +		 * Read IbsBrTarget and IbsOpData4 separately +		 * depending on their availability. +		 * Can't add to offset_max as they are staggered +		 */ +		if (ibs_caps & IBS_CAPS_BRNTRGT) { +			rdmsrl(MSR_AMD64_IBSBRTARGET, *buf++); +			size++; +		} +		if (ibs_caps & IBS_CAPS_OPDATA4) { +			rdmsrl(MSR_AMD64_IBSOPDATA4, *buf++); +			size++; +		} +	}  	ibs_data.size = sizeof(u64) * size;  	regs = *iregs; diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c index 46211bcc813e..495ae9793628 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_ds.c +++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c @@ -552,18 +552,18 @@ int intel_pmu_drain_bts_buffer(void)   * PEBS   */  struct event_constraint intel_core2_pebs_event_constraints[] = { -	INTEL_UEVENT_CONSTRAINT(0x00c0, 0x1), /* INST_RETIRED.ANY */ -	INTEL_UEVENT_CONSTRAINT(0xfec1, 0x1), /* X87_OPS_RETIRED.ANY */ -	INTEL_UEVENT_CONSTRAINT(0x00c5, 0x1), /* BR_INST_RETIRED.MISPRED */ -	INTEL_UEVENT_CONSTRAINT(0x1fc7, 0x1), /* SIMD_INST_RETURED.ANY */ -	INTEL_EVENT_CONSTRAINT(0xcb, 0x1),    /* MEM_LOAD_RETIRED.* */ +	INTEL_FLAGS_UEVENT_CONSTRAINT(0x00c0, 0x1), /* INST_RETIRED.ANY */ +	INTEL_FLAGS_UEVENT_CONSTRAINT(0xfec1, 0x1), /* X87_OPS_RETIRED.ANY */ +	INTEL_FLAGS_UEVENT_CONSTRAINT(0x00c5, 0x1), /* BR_INST_RETIRED.MISPRED */ +	INTEL_FLAGS_UEVENT_CONSTRAINT(0x1fc7, 0x1), /* SIMD_INST_RETURED.ANY */ +	INTEL_FLAGS_EVENT_CONSTRAINT(0xcb, 0x1),    /* MEM_LOAD_RETIRED.* */  	EVENT_CONSTRAINT_END  };  struct event_constraint intel_atom_pebs_event_constraints[] = { -	INTEL_UEVENT_CONSTRAINT(0x00c0, 0x1), /* INST_RETIRED.ANY */ -	INTEL_UEVENT_CONSTRAINT(0x00c5, 0x1), /* MISPREDICTED_BRANCH_RETIRED */ -	INTEL_EVENT_CONSTRAINT(0xcb, 0x1),    /* MEM_LOAD_RETIRED.* */ +	INTEL_FLAGS_UEVENT_CONSTRAINT(0x00c0, 0x1), /* INST_RETIRED.ANY */ +	INTEL_FLAGS_UEVENT_CONSTRAINT(0x00c5, 0x1), /* MISPREDICTED_BRANCH_RETIRED */ +	INTEL_FLAGS_EVENT_CONSTRAINT(0xcb, 0x1),    /* MEM_LOAD_RETIRED.* */  	EVENT_CONSTRAINT_END  }; @@ -577,36 +577,36 @@ struct event_constraint intel_slm_pebs_event_constraints[] = {  struct event_constraint intel_nehalem_pebs_event_constraints[] = {  	INTEL_PLD_CONSTRAINT(0x100b, 0xf),      /* MEM_INST_RETIRED.* */ -	INTEL_EVENT_CONSTRAINT(0x0f, 0xf),    /* MEM_UNCORE_RETIRED.* */ -	INTEL_UEVENT_CONSTRAINT(0x010c, 0xf), /* MEM_STORE_RETIRED.DTLB_MISS */ -	INTEL_EVENT_CONSTRAINT(0xc0, 0xf),    /* INST_RETIRED.ANY */ +	INTEL_FLAGS_EVENT_CONSTRAINT(0x0f, 0xf),    /* MEM_UNCORE_RETIRED.* */ +	INTEL_FLAGS_UEVENT_CONSTRAINT(0x010c, 0xf), /* MEM_STORE_RETIRED.DTLB_MISS */ +	INTEL_FLAGS_EVENT_CONSTRAINT(0xc0, 0xf),    /* INST_RETIRED.ANY */  	INTEL_EVENT_CONSTRAINT(0xc2, 0xf),    /* UOPS_RETIRED.* */ -	INTEL_EVENT_CONSTRAINT(0xc4, 0xf),    /* BR_INST_RETIRED.* */ -	INTEL_UEVENT_CONSTRAINT(0x02c5, 0xf), /* BR_MISP_RETIRED.NEAR_CALL */ -	INTEL_EVENT_CONSTRAINT(0xc7, 0xf),    /* SSEX_UOPS_RETIRED.* */ -	INTEL_UEVENT_CONSTRAINT(0x20c8, 0xf), /* ITLB_MISS_RETIRED */ -	INTEL_EVENT_CONSTRAINT(0xcb, 0xf),    /* MEM_LOAD_RETIRED.* */ -	INTEL_EVENT_CONSTRAINT(0xf7, 0xf),    /* FP_ASSIST.* */ +	INTEL_FLAGS_EVENT_CONSTRAINT(0xc4, 0xf),    /* BR_INST_RETIRED.* */ +	INTEL_FLAGS_UEVENT_CONSTRAINT(0x02c5, 0xf), /* BR_MISP_RETIRED.NEAR_CALL */ +	INTEL_FLAGS_EVENT_CONSTRAINT(0xc7, 0xf),    /* SSEX_UOPS_RETIRED.* */ +	INTEL_FLAGS_UEVENT_CONSTRAINT(0x20c8, 0xf), /* ITLB_MISS_RETIRED */ +	INTEL_FLAGS_EVENT_CONSTRAINT(0xcb, 0xf),    /* MEM_LOAD_RETIRED.* */ +	INTEL_FLAGS_EVENT_CONSTRAINT(0xf7, 0xf),    /* FP_ASSIST.* */  	EVENT_CONSTRAINT_END  };  struct event_constraint intel_westmere_pebs_event_constraints[] = {  	INTEL_PLD_CONSTRAINT(0x100b, 0xf),      /* MEM_INST_RETIRED.* */ -	INTEL_EVENT_CONSTRAINT(0x0f, 0xf),    /* MEM_UNCORE_RETIRED.* */ -	INTEL_UEVENT_CONSTRAINT(0x010c, 0xf), /* MEM_STORE_RETIRED.DTLB_MISS */ -	INTEL_EVENT_CONSTRAINT(0xc0, 0xf),    /* INSTR_RETIRED.* */ +	INTEL_FLAGS_EVENT_CONSTRAINT(0x0f, 0xf),    /* MEM_UNCORE_RETIRED.* */ +	INTEL_FLAGS_UEVENT_CONSTRAINT(0x010c, 0xf), /* MEM_STORE_RETIRED.DTLB_MISS */ +	INTEL_FLAGS_EVENT_CONSTRAINT(0xc0, 0xf),    /* INSTR_RETIRED.* */  	INTEL_EVENT_CONSTRAINT(0xc2, 0xf),    /* UOPS_RETIRED.* */ -	INTEL_EVENT_CONSTRAINT(0xc4, 0xf),    /* BR_INST_RETIRED.* */ -	INTEL_EVENT_CONSTRAINT(0xc5, 0xf),    /* BR_MISP_RETIRED.* */ -	INTEL_EVENT_CONSTRAINT(0xc7, 0xf),    /* SSEX_UOPS_RETIRED.* */ -	INTEL_UEVENT_CONSTRAINT(0x20c8, 0xf), /* ITLB_MISS_RETIRED */ -	INTEL_EVENT_CONSTRAINT(0xcb, 0xf),    /* MEM_LOAD_RETIRED.* */ -	INTEL_EVENT_CONSTRAINT(0xf7, 0xf),    /* FP_ASSIST.* */ +	INTEL_FLAGS_EVENT_CONSTRAINT(0xc4, 0xf),    /* BR_INST_RETIRED.* */ +	INTEL_FLAGS_EVENT_CONSTRAINT(0xc5, 0xf),    /* BR_MISP_RETIRED.* */ +	INTEL_FLAGS_EVENT_CONSTRAINT(0xc7, 0xf),    /* SSEX_UOPS_RETIRED.* */ +	INTEL_FLAGS_UEVENT_CONSTRAINT(0x20c8, 0xf), /* ITLB_MISS_RETIRED */ +	INTEL_FLAGS_EVENT_CONSTRAINT(0xcb, 0xf),    /* MEM_LOAD_RETIRED.* */ +	INTEL_FLAGS_EVENT_CONSTRAINT(0xf7, 0xf),    /* FP_ASSIST.* */  	EVENT_CONSTRAINT_END  };  struct event_constraint intel_snb_pebs_event_constraints[] = { -	INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */ +	INTEL_FLAGS_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */  	INTEL_PLD_CONSTRAINT(0x01cd, 0x8),    /* MEM_TRANS_RETIRED.LAT_ABOVE_THR */  	INTEL_PST_CONSTRAINT(0x02cd, 0x8),    /* MEM_TRANS_RETIRED.PRECISE_STORES */  	/* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */ @@ -617,7 +617,7 @@ struct event_constraint intel_snb_pebs_event_constraints[] = {  };  struct event_constraint intel_ivb_pebs_event_constraints[] = { -        INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */ +        INTEL_FLAGS_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */          INTEL_PLD_CONSTRAINT(0x01cd, 0x8),    /* MEM_TRANS_RETIRED.LAT_ABOVE_THR */  	INTEL_PST_CONSTRAINT(0x02cd, 0x8),    /* MEM_TRANS_RETIRED.PRECISE_STORES */  	/* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */ @@ -628,7 +628,7 @@ struct event_constraint intel_ivb_pebs_event_constraints[] = {  };  struct event_constraint intel_hsw_pebs_event_constraints[] = { -	INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */ +	INTEL_FLAGS_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */  	INTEL_PLD_CONSTRAINT(0x01cd, 0xf),    /* MEM_TRANS_RETIRED.* */  	/* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */  	INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf), @@ -886,6 +886,29 @@ static void __intel_pmu_pebs_event(struct perf_event *event,  	regs.bp = pebs->bp;  	regs.sp = pebs->sp; +	if (sample_type & PERF_SAMPLE_REGS_INTR) { +		regs.ax = pebs->ax; +		regs.bx = pebs->bx; +		regs.cx = pebs->cx; +		regs.dx = pebs->dx; +		regs.si = pebs->si; +		regs.di = pebs->di; +		regs.bp = pebs->bp; +		regs.sp = pebs->sp; + +		regs.flags = pebs->flags; +#ifndef CONFIG_X86_32 +		regs.r8 = pebs->r8; +		regs.r9 = pebs->r9; +		regs.r10 = pebs->r10; +		regs.r11 = pebs->r11; +		regs.r12 = pebs->r12; +		regs.r13 = pebs->r13; +		regs.r14 = pebs->r14; +		regs.r15 = pebs->r15; +#endif +	} +  	if (event->attr.precise_ip > 1 && x86_pmu.intel_cap.pebs_format >= 2) {  		regs.ip = pebs->real_ip;  		regs.flags |= PERF_EFLAGS_EXACT; diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c b/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c index f9ed429d6e4f..745b158e9a65 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c @@ -449,7 +449,11 @@ static struct attribute *snbep_uncore_qpi_formats_attr[] = {  static struct uncore_event_desc snbep_uncore_imc_events[] = {  	INTEL_UNCORE_EVENT_DESC(clockticks,      "event=0xff,umask=0x00"),  	INTEL_UNCORE_EVENT_DESC(cas_count_read,  "event=0x04,umask=0x03"), +	INTEL_UNCORE_EVENT_DESC(cas_count_read.scale, "6.103515625e-5"), +	INTEL_UNCORE_EVENT_DESC(cas_count_read.unit, "MiB"),  	INTEL_UNCORE_EVENT_DESC(cas_count_write, "event=0x04,umask=0x0c"), +	INTEL_UNCORE_EVENT_DESC(cas_count_write.scale, "6.103515625e-5"), +	INTEL_UNCORE_EVENT_DESC(cas_count_write.unit, "MiB"),  	{ /* end: all zeroes */ },  }; @@ -2036,7 +2040,11 @@ static struct intel_uncore_type hswep_uncore_ha = {  static struct uncore_event_desc hswep_uncore_imc_events[] = {  	INTEL_UNCORE_EVENT_DESC(clockticks,      "event=0x00,umask=0x00"),  	INTEL_UNCORE_EVENT_DESC(cas_count_read,  "event=0x04,umask=0x03"), +	INTEL_UNCORE_EVENT_DESC(cas_count_read.scale, "6.103515625e-5"), +	INTEL_UNCORE_EVENT_DESC(cas_count_read.unit, "MiB"),  	INTEL_UNCORE_EVENT_DESC(cas_count_write, "event=0x04,umask=0x0c"), +	INTEL_UNCORE_EVENT_DESC(cas_count_write.scale, "6.103515625e-5"), +	INTEL_UNCORE_EVENT_DESC(cas_count_write.unit, "MiB"),  	{ /* end: all zeroes */ },  }; diff --git a/arch/x86/kernel/hw_breakpoint.c b/arch/x86/kernel/hw_breakpoint.c index 3d5fb509bdeb..7114ba220fd4 100644 --- a/arch/x86/kernel/hw_breakpoint.c +++ b/arch/x86/kernel/hw_breakpoint.c @@ -126,6 +126,8 @@ int arch_install_hw_breakpoint(struct perf_event *bp)  	*dr7 |= encode_dr7(i, info->len, info->type);  	set_debugreg(*dr7, 7); +	if (info->mask) +		set_dr_addr_mask(info->mask, i);  	return 0;  } @@ -161,29 +163,8 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp)  	*dr7 &= ~__encode_dr7(i, info->len, info->type);  	set_debugreg(*dr7, 7); -} - -static int get_hbp_len(u8 hbp_len) -{ -	unsigned int len_in_bytes = 0; - -	switch (hbp_len) { -	case X86_BREAKPOINT_LEN_1: -		len_in_bytes = 1; -		break; -	case X86_BREAKPOINT_LEN_2: -		len_in_bytes = 2; -		break; -	case X86_BREAKPOINT_LEN_4: -		len_in_bytes = 4; -		break; -#ifdef CONFIG_X86_64 -	case X86_BREAKPOINT_LEN_8: -		len_in_bytes = 8; -		break; -#endif -	} -	return len_in_bytes; +	if (info->mask) +		set_dr_addr_mask(0, i);  }  /* @@ -196,7 +177,7 @@ int arch_check_bp_in_kernelspace(struct perf_event *bp)  	struct arch_hw_breakpoint *info = counter_arch_bp(bp);  	va = info->address; -	len = get_hbp_len(info->len); +	len = bp->attr.bp_len;  	return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE);  } @@ -277,6 +258,8 @@ static int arch_build_bp_info(struct perf_event *bp)  	}  	/* Len */ +	info->mask = 0; +  	switch (bp->attr.bp_len) {  	case HW_BREAKPOINT_LEN_1:  		info->len = X86_BREAKPOINT_LEN_1; @@ -293,11 +276,17 @@ static int arch_build_bp_info(struct perf_event *bp)  		break;  #endif  	default: -		return -EINVAL; +		if (!is_power_of_2(bp->attr.bp_len)) +			return -EINVAL; +		if (!cpu_has_bpext) +			return -EOPNOTSUPP; +		info->mask = bp->attr.bp_len - 1; +		info->len = X86_BREAKPOINT_LEN_1;  	}  	return 0;  } +  /*   * Validate the arch-specific HW Breakpoint register settings   */ @@ -312,11 +301,11 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)  	if (ret)  		return ret; -	ret = -EINVAL; -  	switch (info->len) {  	case X86_BREAKPOINT_LEN_1:  		align = 0; +		if (info->mask) +			align = info->mask;  		break;  	case X86_BREAKPOINT_LEN_2:  		align = 1; @@ -330,7 +319,7 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)  		break;  #endif  	default: -		return ret; +		WARN_ON_ONCE(1);  	}  	/*  | 
