xref: /openbmc/linux/arch/x86/events/amd/ibs.c (revision 060f35a317ef09101b128f399dce7ed13d019461)
1218cfe4eSBorislav Petkov /*
2218cfe4eSBorislav Petkov  * Performance events - AMD IBS
3218cfe4eSBorislav Petkov  *
4218cfe4eSBorislav Petkov  *  Copyright (C) 2011 Advanced Micro Devices, Inc., Robert Richter
5218cfe4eSBorislav Petkov  *
6218cfe4eSBorislav Petkov  *  For licencing details see kernel-base/COPYING
7218cfe4eSBorislav Petkov  */
8218cfe4eSBorislav Petkov 
9218cfe4eSBorislav Petkov #include <linux/perf_event.h>
10eb008eb6SPaul Gortmaker #include <linux/init.h>
11eb008eb6SPaul Gortmaker #include <linux/export.h>
12218cfe4eSBorislav Petkov #include <linux/pci.h>
13218cfe4eSBorislav Petkov #include <linux/ptrace.h>
14218cfe4eSBorislav Petkov #include <linux/syscore_ops.h>
15e6017571SIngo Molnar #include <linux/sched/clock.h>
16218cfe4eSBorislav Petkov 
17218cfe4eSBorislav Petkov #include <asm/apic.h>
18218cfe4eSBorislav Petkov 
1927f6d22bSBorislav Petkov #include "../perf_event.h"
20218cfe4eSBorislav Petkov 
21218cfe4eSBorislav Petkov static u32 ibs_caps;
22218cfe4eSBorislav Petkov 
23218cfe4eSBorislav Petkov #if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_AMD)
24218cfe4eSBorislav Petkov 
25218cfe4eSBorislav Petkov #include <linux/kprobes.h>
26218cfe4eSBorislav Petkov #include <linux/hardirq.h>
27218cfe4eSBorislav Petkov 
28218cfe4eSBorislav Petkov #include <asm/nmi.h>
296a371bafSKim Phillips #include <asm/amd-ibs.h>
30218cfe4eSBorislav Petkov 
31218cfe4eSBorislav Petkov #define IBS_FETCH_CONFIG_MASK	(IBS_FETCH_RAND_EN | IBS_FETCH_MAX_CNT)
32218cfe4eSBorislav Petkov #define IBS_OP_CONFIG_MASK	IBS_OP_MAX_CNT
33218cfe4eSBorislav Petkov 
3485dc6002SPeter Zijlstra 
3585dc6002SPeter Zijlstra /*
3685dc6002SPeter Zijlstra  * IBS states:
3785dc6002SPeter Zijlstra  *
3885dc6002SPeter Zijlstra  * ENABLED; tracks the pmu::add(), pmu::del() state, when set the counter is taken
3985dc6002SPeter Zijlstra  * and any further add()s must fail.
4085dc6002SPeter Zijlstra  *
4185dc6002SPeter Zijlstra  * STARTED/STOPPING/STOPPED; deal with pmu::start(), pmu::stop() state but are
4285dc6002SPeter Zijlstra  * complicated by the fact that the IBS hardware can send late NMIs (ie. after
4385dc6002SPeter Zijlstra  * we've cleared the EN bit).
4485dc6002SPeter Zijlstra  *
4585dc6002SPeter Zijlstra  * In order to consume these late NMIs we have the STOPPED state, any NMI that
4685dc6002SPeter Zijlstra  * happens after we've cleared the EN state will clear this bit and report the
4785dc6002SPeter Zijlstra  * NMI handled (this is fundamentally racy in the face or multiple NMI sources,
4885dc6002SPeter Zijlstra  * someone else can consume our BIT and our NMI will go unhandled).
4985dc6002SPeter Zijlstra  *
5085dc6002SPeter Zijlstra  * And since we cannot set/clear this separate bit together with the EN bit,
5185dc6002SPeter Zijlstra  * there are races; if we cleared STARTED early, an NMI could land in
5285dc6002SPeter Zijlstra  * between clearing STARTED and clearing the EN bit (in fact multiple NMIs
5385dc6002SPeter Zijlstra  * could happen if the period is small enough), and consume our STOPPED bit
5485dc6002SPeter Zijlstra  * and trigger streams of unhandled NMIs.
5585dc6002SPeter Zijlstra  *
5685dc6002SPeter Zijlstra  * If, however, we clear STARTED late, an NMI can hit between clearing the
5785dc6002SPeter Zijlstra  * EN bit and clearing STARTED, still see STARTED set and process the event.
5885dc6002SPeter Zijlstra  * If this event will have the VALID bit clear, we bail properly, but this
5985dc6002SPeter Zijlstra  * is not a given. With VALID set we can end up calling pmu::stop() again
6085dc6002SPeter Zijlstra  * (the throttle logic) and trigger the WARNs in there.
6185dc6002SPeter Zijlstra  *
6285dc6002SPeter Zijlstra  * So what we do is set STOPPING before clearing EN to avoid the pmu::stop()
6385dc6002SPeter Zijlstra  * nesting, and clear STARTED late, so that we have a well defined state over
6485dc6002SPeter Zijlstra  * the clearing of the EN bit.
6585dc6002SPeter Zijlstra  *
6685dc6002SPeter Zijlstra  * XXX: we could probably be using !atomic bitops for all this.
6785dc6002SPeter Zijlstra  */
6885dc6002SPeter Zijlstra 
69218cfe4eSBorislav Petkov enum ibs_states {
70218cfe4eSBorislav Petkov 	IBS_ENABLED	= 0,
71218cfe4eSBorislav Petkov 	IBS_STARTED	= 1,
72218cfe4eSBorislav Petkov 	IBS_STOPPING	= 2,
7385dc6002SPeter Zijlstra 	IBS_STOPPED	= 3,
74218cfe4eSBorislav Petkov 
75218cfe4eSBorislav Petkov 	IBS_MAX_STATES,
76218cfe4eSBorislav Petkov };
77218cfe4eSBorislav Petkov 
78218cfe4eSBorislav Petkov struct cpu_perf_ibs {
79218cfe4eSBorislav Petkov 	struct perf_event	*event;
80218cfe4eSBorislav Petkov 	unsigned long		state[BITS_TO_LONGS(IBS_MAX_STATES)];
81218cfe4eSBorislav Petkov };
82218cfe4eSBorislav Petkov 
83218cfe4eSBorislav Petkov struct perf_ibs {
84218cfe4eSBorislav Petkov 	struct pmu			pmu;
85218cfe4eSBorislav Petkov 	unsigned int			msr;
86218cfe4eSBorislav Petkov 	u64				config_mask;
87218cfe4eSBorislav Petkov 	u64				cnt_mask;
88218cfe4eSBorislav Petkov 	u64				enable_mask;
89218cfe4eSBorislav Petkov 	u64				valid_mask;
90218cfe4eSBorislav Petkov 	u64				max_period;
91218cfe4eSBorislav Petkov 	unsigned long			offset_mask[1];
92218cfe4eSBorislav Petkov 	int				offset_max;
93221bfce5SKim Phillips 	unsigned int			fetch_count_reset_broken : 1;
9426db2e0cSKim Phillips 	unsigned int			fetch_ignore_if_zero_rip : 1;
95218cfe4eSBorislav Petkov 	struct cpu_perf_ibs __percpu	*pcpu;
96218cfe4eSBorislav Petkov 
97218cfe4eSBorislav Petkov 	u64				(*get_count)(u64 config);
98218cfe4eSBorislav Petkov };
99218cfe4eSBorislav Petkov 
100218cfe4eSBorislav Petkov static int
perf_event_set_period(struct hw_perf_event * hwc,u64 min,u64 max,u64 * hw_period)101218cfe4eSBorislav Petkov perf_event_set_period(struct hw_perf_event *hwc, u64 min, u64 max, u64 *hw_period)
102218cfe4eSBorislav Petkov {
103218cfe4eSBorislav Petkov 	s64 left = local64_read(&hwc->period_left);
104218cfe4eSBorislav Petkov 	s64 period = hwc->sample_period;
105218cfe4eSBorislav Petkov 	int overflow = 0;
106218cfe4eSBorislav Petkov 
107218cfe4eSBorislav Petkov 	/*
108218cfe4eSBorislav Petkov 	 * If we are way outside a reasonable range then just skip forward:
109218cfe4eSBorislav Petkov 	 */
110218cfe4eSBorislav Petkov 	if (unlikely(left <= -period)) {
111218cfe4eSBorislav Petkov 		left = period;
112218cfe4eSBorislav Petkov 		local64_set(&hwc->period_left, left);
113218cfe4eSBorislav Petkov 		hwc->last_period = period;
114218cfe4eSBorislav Petkov 		overflow = 1;
115218cfe4eSBorislav Petkov 	}
116218cfe4eSBorislav Petkov 
117218cfe4eSBorislav Petkov 	if (unlikely(left < (s64)min)) {
118218cfe4eSBorislav Petkov 		left += period;
119218cfe4eSBorislav Petkov 		local64_set(&hwc->period_left, left);
120218cfe4eSBorislav Petkov 		hwc->last_period = period;
121218cfe4eSBorislav Petkov 		overflow = 1;
122218cfe4eSBorislav Petkov 	}
123218cfe4eSBorislav Petkov 
124218cfe4eSBorislav Petkov 	/*
125218cfe4eSBorislav Petkov 	 * If the hw period that triggers the sw overflow is too short
126218cfe4eSBorislav Petkov 	 * we might hit the irq handler. This biases the results.
127218cfe4eSBorislav Petkov 	 * Thus we shorten the next-to-last period and set the last
128218cfe4eSBorislav Petkov 	 * period to the max period.
129218cfe4eSBorislav Petkov 	 */
130218cfe4eSBorislav Petkov 	if (left > max) {
131218cfe4eSBorislav Petkov 		left -= max;
132218cfe4eSBorislav Petkov 		if (left > max)
133218cfe4eSBorislav Petkov 			left = max;
134218cfe4eSBorislav Petkov 		else if (left < min)
135218cfe4eSBorislav Petkov 			left = min;
136218cfe4eSBorislav Petkov 	}
137218cfe4eSBorislav Petkov 
138218cfe4eSBorislav Petkov 	*hw_period = (u64)left;
139218cfe4eSBorislav Petkov 
140218cfe4eSBorislav Petkov 	return overflow;
141218cfe4eSBorislav Petkov }
142218cfe4eSBorislav Petkov 
143218cfe4eSBorislav Petkov static  int
perf_event_try_update(struct perf_event * event,u64 new_raw_count,int width)144218cfe4eSBorislav Petkov perf_event_try_update(struct perf_event *event, u64 new_raw_count, int width)
145218cfe4eSBorislav Petkov {
146218cfe4eSBorislav Petkov 	struct hw_perf_event *hwc = &event->hw;
147218cfe4eSBorislav Petkov 	int shift = 64 - width;
148218cfe4eSBorislav Petkov 	u64 prev_raw_count;
149218cfe4eSBorislav Petkov 	u64 delta;
150218cfe4eSBorislav Petkov 
151218cfe4eSBorislav Petkov 	/*
152218cfe4eSBorislav Petkov 	 * Careful: an NMI might modify the previous event value.
153218cfe4eSBorislav Petkov 	 *
154218cfe4eSBorislav Petkov 	 * Our tactic to handle this is to first atomically read and
155218cfe4eSBorislav Petkov 	 * exchange a new raw count - then add that new-prev delta
156218cfe4eSBorislav Petkov 	 * count to the generic event atomically:
157218cfe4eSBorislav Petkov 	 */
158218cfe4eSBorislav Petkov 	prev_raw_count = local64_read(&hwc->prev_count);
1594c1c9deaSUros Bizjak 	if (!local64_try_cmpxchg(&hwc->prev_count,
1604c1c9deaSUros Bizjak 				 &prev_raw_count, new_raw_count))
161218cfe4eSBorislav Petkov 		return 0;
162218cfe4eSBorislav Petkov 
163218cfe4eSBorislav Petkov 	/*
164218cfe4eSBorislav Petkov 	 * Now we have the new raw value and have updated the prev
165218cfe4eSBorislav Petkov 	 * timestamp already. We can now calculate the elapsed delta
166218cfe4eSBorislav Petkov 	 * (event-)time and add that to the generic event.
167218cfe4eSBorislav Petkov 	 *
168218cfe4eSBorislav Petkov 	 * Careful, not all hw sign-extends above the physical width
169218cfe4eSBorislav Petkov 	 * of the count.
170218cfe4eSBorislav Petkov 	 */
171218cfe4eSBorislav Petkov 	delta = (new_raw_count << shift) - (prev_raw_count << shift);
172218cfe4eSBorislav Petkov 	delta >>= shift;
173218cfe4eSBorislav Petkov 
174218cfe4eSBorislav Petkov 	local64_add(delta, &event->count);
175218cfe4eSBorislav Petkov 	local64_sub(delta, &hwc->period_left);
176218cfe4eSBorislav Petkov 
177218cfe4eSBorislav Petkov 	return 1;
178218cfe4eSBorislav Petkov }
179218cfe4eSBorislav Petkov 
180218cfe4eSBorislav Petkov static struct perf_ibs perf_ibs_fetch;
181218cfe4eSBorislav Petkov static struct perf_ibs perf_ibs_op;
182218cfe4eSBorislav Petkov 
get_ibs_pmu(int type)183218cfe4eSBorislav Petkov static struct perf_ibs *get_ibs_pmu(int type)
184218cfe4eSBorislav Petkov {
185218cfe4eSBorislav Petkov 	if (perf_ibs_fetch.pmu.type == type)
186218cfe4eSBorislav Petkov 		return &perf_ibs_fetch;
187218cfe4eSBorislav Petkov 	if (perf_ibs_op.pmu.type == type)
188218cfe4eSBorislav Petkov 		return &perf_ibs_op;
189218cfe4eSBorislav Petkov 	return NULL;
190218cfe4eSBorislav Petkov }
191218cfe4eSBorislav Petkov 
192218cfe4eSBorislav Petkov /*
1932fad201fSRavi Bangoria  * core pmu config -> IBS config
194218cfe4eSBorislav Petkov  *
195218cfe4eSBorislav Petkov  *  perf record -a -e cpu-cycles:p ...    # use ibs op counting cycle count
196218cfe4eSBorislav Petkov  *  perf record -a -e r076:p ...          # same as -e cpu-cycles:p
197218cfe4eSBorislav Petkov  *  perf record -a -e r0C1:p ...          # use ibs op counting micro-ops
198218cfe4eSBorislav Petkov  *
199218cfe4eSBorislav Petkov  * IbsOpCntCtl (bit 19) of IBS Execution Control Register (IbsOpCtl,
200218cfe4eSBorislav Petkov  * MSRC001_1033) is used to select either cycle or micro-ops counting
201218cfe4eSBorislav Petkov  * mode.
202218cfe4eSBorislav Petkov  */
core_pmu_ibs_config(struct perf_event * event,u64 * config)2032fad201fSRavi Bangoria static int core_pmu_ibs_config(struct perf_event *event, u64 *config)
204218cfe4eSBorislav Petkov {
205218cfe4eSBorislav Petkov 	switch (event->attr.type) {
206218cfe4eSBorislav Petkov 	case PERF_TYPE_HARDWARE:
207218cfe4eSBorislav Petkov 		switch (event->attr.config) {
208218cfe4eSBorislav Petkov 		case PERF_COUNT_HW_CPU_CYCLES:
209218cfe4eSBorislav Petkov 			*config = 0;
210218cfe4eSBorislav Petkov 			return 0;
211218cfe4eSBorislav Petkov 		}
212218cfe4eSBorislav Petkov 		break;
213218cfe4eSBorislav Petkov 	case PERF_TYPE_RAW:
214218cfe4eSBorislav Petkov 		switch (event->attr.config) {
215218cfe4eSBorislav Petkov 		case 0x0076:
216218cfe4eSBorislav Petkov 			*config = 0;
217218cfe4eSBorislav Petkov 			return 0;
218218cfe4eSBorislav Petkov 		case 0x00C1:
219218cfe4eSBorislav Petkov 			*config = IBS_OP_CNT_CTL;
220218cfe4eSBorislav Petkov 			return 0;
221218cfe4eSBorislav Petkov 		}
222218cfe4eSBorislav Petkov 		break;
223218cfe4eSBorislav Petkov 	default:
224218cfe4eSBorislav Petkov 		return -ENOENT;
225218cfe4eSBorislav Petkov 	}
226218cfe4eSBorislav Petkov 
227218cfe4eSBorislav Petkov 	return -EOPNOTSUPP;
228218cfe4eSBorislav Petkov }
229218cfe4eSBorislav Petkov 
2302fad201fSRavi Bangoria /*
2312fad201fSRavi Bangoria  * The rip of IBS samples has skid 0. Thus, IBS supports precise
2322fad201fSRavi Bangoria  * levels 1 and 2 and the PERF_EFLAGS_EXACT is set. In rare cases the
2332fad201fSRavi Bangoria  * rip is invalid when IBS was not able to record the rip correctly.
2342fad201fSRavi Bangoria  * We clear PERF_EFLAGS_EXACT and take the rip from pt_regs then.
2352fad201fSRavi Bangoria  */
forward_event_to_ibs(struct perf_event * event)2362fad201fSRavi Bangoria int forward_event_to_ibs(struct perf_event *event)
2372fad201fSRavi Bangoria {
2382fad201fSRavi Bangoria 	u64 config = 0;
2392fad201fSRavi Bangoria 
2402fad201fSRavi Bangoria 	if (!event->attr.precise_ip || event->attr.precise_ip > 2)
2412fad201fSRavi Bangoria 		return -EOPNOTSUPP;
2422fad201fSRavi Bangoria 
2432fad201fSRavi Bangoria 	if (!core_pmu_ibs_config(event, &config)) {
2442fad201fSRavi Bangoria 		event->attr.type = perf_ibs_op.pmu.type;
2452fad201fSRavi Bangoria 		event->attr.config = config;
2462fad201fSRavi Bangoria 	}
2472fad201fSRavi Bangoria 	return -ENOENT;
2482fad201fSRavi Bangoria }
2492fad201fSRavi Bangoria 
2507c212823SRavi Bangoria /*
2517c212823SRavi Bangoria  * Grouping of IBS events is not possible since IBS can have only
2527c212823SRavi Bangoria  * one event active at any point in time.
2537c212823SRavi Bangoria  */
validate_group(struct perf_event * event)2547c212823SRavi Bangoria static int validate_group(struct perf_event *event)
2557c212823SRavi Bangoria {
2567c212823SRavi Bangoria 	struct perf_event *sibling;
2577c212823SRavi Bangoria 
2587c212823SRavi Bangoria 	if (event->group_leader == event)
2597c212823SRavi Bangoria 		return 0;
2607c212823SRavi Bangoria 
2617c212823SRavi Bangoria 	if (event->group_leader->pmu == event->pmu)
2627c212823SRavi Bangoria 		return -EINVAL;
2637c212823SRavi Bangoria 
2647c212823SRavi Bangoria 	for_each_sibling_event(sibling, event->group_leader) {
2657c212823SRavi Bangoria 		if (sibling->pmu == event->pmu)
2667c212823SRavi Bangoria 			return -EINVAL;
2677c212823SRavi Bangoria 	}
2687c212823SRavi Bangoria 	return 0;
2697c212823SRavi Bangoria }
2707c212823SRavi Bangoria 
perf_ibs_init(struct perf_event * event)271218cfe4eSBorislav Petkov static int perf_ibs_init(struct perf_event *event)
272218cfe4eSBorislav Petkov {
273218cfe4eSBorislav Petkov 	struct hw_perf_event *hwc = &event->hw;
274218cfe4eSBorislav Petkov 	struct perf_ibs *perf_ibs;
275218cfe4eSBorislav Petkov 	u64 max_cnt, config;
2767c212823SRavi Bangoria 	int ret;
277218cfe4eSBorislav Petkov 
278218cfe4eSBorislav Petkov 	perf_ibs = get_ibs_pmu(event->attr.type);
2792fad201fSRavi Bangoria 	if (!perf_ibs)
2802fad201fSRavi Bangoria 		return -ENOENT;
2812fad201fSRavi Bangoria 
282218cfe4eSBorislav Petkov 	config = event->attr.config;
283218cfe4eSBorislav Petkov 
284218cfe4eSBorislav Petkov 	if (event->pmu != &perf_ibs->pmu)
285218cfe4eSBorislav Petkov 		return -ENOENT;
286218cfe4eSBorislav Petkov 
287218cfe4eSBorislav Petkov 	if (config & ~perf_ibs->config_mask)
288218cfe4eSBorislav Petkov 		return -EINVAL;
289218cfe4eSBorislav Petkov 
2907c212823SRavi Bangoria 	ret = validate_group(event);
2917c212823SRavi Bangoria 	if (ret)
2927c212823SRavi Bangoria 		return ret;
2937c212823SRavi Bangoria 
294218cfe4eSBorislav Petkov 	if (hwc->sample_period) {
295218cfe4eSBorislav Petkov 		if (config & perf_ibs->cnt_mask)
296218cfe4eSBorislav Petkov 			/* raw max_cnt may not be set */
297218cfe4eSBorislav Petkov 			return -EINVAL;
298218cfe4eSBorislav Petkov 		if (!event->attr.sample_freq && hwc->sample_period & 0x0f)
299218cfe4eSBorislav Petkov 			/*
300218cfe4eSBorislav Petkov 			 * lower 4 bits can not be set in ibs max cnt,
301218cfe4eSBorislav Petkov 			 * but allowing it in case we adjust the
302218cfe4eSBorislav Petkov 			 * sample period to set a frequency.
303218cfe4eSBorislav Petkov 			 */
304218cfe4eSBorislav Petkov 			return -EINVAL;
305218cfe4eSBorislav Petkov 		hwc->sample_period &= ~0x0FULL;
306218cfe4eSBorislav Petkov 		if (!hwc->sample_period)
307218cfe4eSBorislav Petkov 			hwc->sample_period = 0x10;
308218cfe4eSBorislav Petkov 	} else {
309218cfe4eSBorislav Petkov 		max_cnt = config & perf_ibs->cnt_mask;
310218cfe4eSBorislav Petkov 		config &= ~perf_ibs->cnt_mask;
311218cfe4eSBorislav Petkov 		event->attr.sample_period = max_cnt << 4;
312218cfe4eSBorislav Petkov 		hwc->sample_period = event->attr.sample_period;
313218cfe4eSBorislav Petkov 	}
314218cfe4eSBorislav Petkov 
315218cfe4eSBorislav Petkov 	if (!hwc->sample_period)
316218cfe4eSBorislav Petkov 		return -EINVAL;
317218cfe4eSBorislav Petkov 
318218cfe4eSBorislav Petkov 	/*
319218cfe4eSBorislav Petkov 	 * If we modify hwc->sample_period, we also need to update
320218cfe4eSBorislav Petkov 	 * hwc->last_period and hwc->period_left.
321218cfe4eSBorislav Petkov 	 */
322218cfe4eSBorislav Petkov 	hwc->last_period = hwc->sample_period;
323218cfe4eSBorislav Petkov 	local64_set(&hwc->period_left, hwc->sample_period);
324218cfe4eSBorislav Petkov 
325218cfe4eSBorislav Petkov 	hwc->config_base = perf_ibs->msr;
326218cfe4eSBorislav Petkov 	hwc->config = config;
327218cfe4eSBorislav Petkov 
328218cfe4eSBorislav Petkov 	return 0;
329218cfe4eSBorislav Petkov }
330218cfe4eSBorislav Petkov 
perf_ibs_set_period(struct perf_ibs * perf_ibs,struct hw_perf_event * hwc,u64 * period)331218cfe4eSBorislav Petkov static int perf_ibs_set_period(struct perf_ibs *perf_ibs,
332218cfe4eSBorislav Petkov 			       struct hw_perf_event *hwc, u64 *period)
333218cfe4eSBorislav Petkov {
334218cfe4eSBorislav Petkov 	int overflow;
335218cfe4eSBorislav Petkov 
336218cfe4eSBorislav Petkov 	/* ignore lower 4 bits in min count: */
337218cfe4eSBorislav Petkov 	overflow = perf_event_set_period(hwc, 1<<4, perf_ibs->max_period, period);
338218cfe4eSBorislav Petkov 	local64_set(&hwc->prev_count, 0);
339218cfe4eSBorislav Petkov 
340218cfe4eSBorislav Petkov 	return overflow;
341218cfe4eSBorislav Petkov }
342218cfe4eSBorislav Petkov 
get_ibs_fetch_count(u64 config)343218cfe4eSBorislav Petkov static u64 get_ibs_fetch_count(u64 config)
344218cfe4eSBorislav Petkov {
3456a371bafSKim Phillips 	union ibs_fetch_ctl fetch_ctl = (union ibs_fetch_ctl)config;
3466a371bafSKim Phillips 
3476a371bafSKim Phillips 	return fetch_ctl.fetch_cnt << 4;
348218cfe4eSBorislav Petkov }
349218cfe4eSBorislav Petkov 
get_ibs_op_count(u64 config)350218cfe4eSBorislav Petkov static u64 get_ibs_op_count(u64 config)
351218cfe4eSBorislav Petkov {
3526a371bafSKim Phillips 	union ibs_op_ctl op_ctl = (union ibs_op_ctl)config;
353218cfe4eSBorislav Petkov 	u64 count = 0;
354218cfe4eSBorislav Petkov 
355680d6963SKim Phillips 	/*
356680d6963SKim Phillips 	 * If the internal 27-bit counter rolled over, the count is MaxCnt
357680d6963SKim Phillips 	 * and the lower 7 bits of CurCnt are randomized.
358680d6963SKim Phillips 	 * Otherwise CurCnt has the full 27-bit current counter value.
359680d6963SKim Phillips 	 */
3606a371bafSKim Phillips 	if (op_ctl.op_val) {
3616a371bafSKim Phillips 		count = op_ctl.opmaxcnt << 4;
3628b0bed7dSKim Phillips 		if (ibs_caps & IBS_CAPS_OPCNTEXT)
3636a371bafSKim Phillips 			count += op_ctl.opmaxcnt_ext << 20;
3648b0bed7dSKim Phillips 	} else if (ibs_caps & IBS_CAPS_RDWROPCNT) {
3656a371bafSKim Phillips 		count = op_ctl.opcurcnt;
3668b0bed7dSKim Phillips 	}
367218cfe4eSBorislav Petkov 
368218cfe4eSBorislav Petkov 	return count;
369218cfe4eSBorislav Petkov }
370218cfe4eSBorislav Petkov 
371218cfe4eSBorislav Petkov static void
perf_ibs_event_update(struct perf_ibs * perf_ibs,struct perf_event * event,u64 * config)372218cfe4eSBorislav Petkov perf_ibs_event_update(struct perf_ibs *perf_ibs, struct perf_event *event,
373218cfe4eSBorislav Petkov 		      u64 *config)
374218cfe4eSBorislav Petkov {
375218cfe4eSBorislav Petkov 	u64 count = perf_ibs->get_count(*config);
376218cfe4eSBorislav Petkov 
377218cfe4eSBorislav Petkov 	/*
378218cfe4eSBorislav Petkov 	 * Set width to 64 since we do not overflow on max width but
379218cfe4eSBorislav Petkov 	 * instead on max count. In perf_ibs_set_period() we clear
380218cfe4eSBorislav Petkov 	 * prev count manually on overflow.
381218cfe4eSBorislav Petkov 	 */
382218cfe4eSBorislav Petkov 	while (!perf_event_try_update(event, count, 64)) {
383218cfe4eSBorislav Petkov 		rdmsrl(event->hw.config_base, *config);
384218cfe4eSBorislav Petkov 		count = perf_ibs->get_count(*config);
385218cfe4eSBorislav Petkov 	}
386218cfe4eSBorislav Petkov }
387218cfe4eSBorislav Petkov 
perf_ibs_enable_event(struct perf_ibs * perf_ibs,struct hw_perf_event * hwc,u64 config)388218cfe4eSBorislav Petkov static inline void perf_ibs_enable_event(struct perf_ibs *perf_ibs,
389218cfe4eSBorislav Petkov 					 struct hw_perf_event *hwc, u64 config)
390218cfe4eSBorislav Petkov {
391221bfce5SKim Phillips 	u64 tmp = hwc->config | config;
392221bfce5SKim Phillips 
393221bfce5SKim Phillips 	if (perf_ibs->fetch_count_reset_broken)
394221bfce5SKim Phillips 		wrmsrl(hwc->config_base, tmp & ~perf_ibs->enable_mask);
395221bfce5SKim Phillips 
396221bfce5SKim Phillips 	wrmsrl(hwc->config_base, tmp | perf_ibs->enable_mask);
397218cfe4eSBorislav Petkov }
398218cfe4eSBorislav Petkov 
399218cfe4eSBorislav Petkov /*
400218cfe4eSBorislav Petkov  * Erratum #420 Instruction-Based Sampling Engine May Generate
401218cfe4eSBorislav Petkov  * Interrupt that Cannot Be Cleared:
402218cfe4eSBorislav Petkov  *
403218cfe4eSBorislav Petkov  * Must clear counter mask first, then clear the enable bit. See
404218cfe4eSBorislav Petkov  * Revision Guide for AMD Family 10h Processors, Publication #41322.
405218cfe4eSBorislav Petkov  */
perf_ibs_disable_event(struct perf_ibs * perf_ibs,struct hw_perf_event * hwc,u64 config)406218cfe4eSBorislav Petkov static inline void perf_ibs_disable_event(struct perf_ibs *perf_ibs,
407218cfe4eSBorislav Petkov 					  struct hw_perf_event *hwc, u64 config)
408218cfe4eSBorislav Petkov {
409218cfe4eSBorislav Petkov 	config &= ~perf_ibs->cnt_mask;
410e431e79bSKim Phillips 	if (boot_cpu_data.x86 == 0x10)
411218cfe4eSBorislav Petkov 		wrmsrl(hwc->config_base, config);
412218cfe4eSBorislav Petkov 	config &= ~perf_ibs->enable_mask;
413218cfe4eSBorislav Petkov 	wrmsrl(hwc->config_base, config);
414218cfe4eSBorislav Petkov }
415218cfe4eSBorislav Petkov 
416218cfe4eSBorislav Petkov /*
417218cfe4eSBorislav Petkov  * We cannot restore the ibs pmu state, so we always needs to update
418218cfe4eSBorislav Petkov  * the event while stopping it and then reset the state when starting
419218cfe4eSBorislav Petkov  * again. Thus, ignoring PERF_EF_RELOAD and PERF_EF_UPDATE flags in
420218cfe4eSBorislav Petkov  * perf_ibs_start()/perf_ibs_stop() and instead always do it.
421218cfe4eSBorislav Petkov  */
perf_ibs_start(struct perf_event * event,int flags)422218cfe4eSBorislav Petkov static void perf_ibs_start(struct perf_event *event, int flags)
423218cfe4eSBorislav Petkov {
424218cfe4eSBorislav Petkov 	struct hw_perf_event *hwc = &event->hw;
425218cfe4eSBorislav Petkov 	struct perf_ibs *perf_ibs = container_of(event->pmu, struct perf_ibs, pmu);
426218cfe4eSBorislav Petkov 	struct cpu_perf_ibs *pcpu = this_cpu_ptr(perf_ibs->pcpu);
4278b0bed7dSKim Phillips 	u64 period, config = 0;
428218cfe4eSBorislav Petkov 
429218cfe4eSBorislav Petkov 	if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED)))
430218cfe4eSBorislav Petkov 		return;
431218cfe4eSBorislav Petkov 
432218cfe4eSBorislav Petkov 	WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
433218cfe4eSBorislav Petkov 	hwc->state = 0;
434218cfe4eSBorislav Petkov 
435218cfe4eSBorislav Petkov 	perf_ibs_set_period(perf_ibs, hwc, &period);
4368b0bed7dSKim Phillips 	if (perf_ibs == &perf_ibs_op && (ibs_caps & IBS_CAPS_OPCNTEXT)) {
4378b0bed7dSKim Phillips 		config |= period & IBS_OP_MAX_CNT_EXT_MASK;
4388b0bed7dSKim Phillips 		period &= ~IBS_OP_MAX_CNT_EXT_MASK;
4398b0bed7dSKim Phillips 	}
4408b0bed7dSKim Phillips 	config |= period >> 4;
4418b0bed7dSKim Phillips 
4425a50f529SPeter Zijlstra 	/*
44385dc6002SPeter Zijlstra 	 * Set STARTED before enabling the hardware, such that a subsequent NMI
44485dc6002SPeter Zijlstra 	 * must observe it.
4455a50f529SPeter Zijlstra 	 */
446218cfe4eSBorislav Petkov 	set_bit(IBS_STARTED,    pcpu->state);
4475a50f529SPeter Zijlstra 	clear_bit(IBS_STOPPING, pcpu->state);
4488b0bed7dSKim Phillips 	perf_ibs_enable_event(perf_ibs, hwc, config);
449218cfe4eSBorislav Petkov 
450218cfe4eSBorislav Petkov 	perf_event_update_userpage(event);
451218cfe4eSBorislav Petkov }
452218cfe4eSBorislav Petkov 
perf_ibs_stop(struct perf_event * event,int flags)453218cfe4eSBorislav Petkov static void perf_ibs_stop(struct perf_event *event, int flags)
454218cfe4eSBorislav Petkov {
455218cfe4eSBorislav Petkov 	struct hw_perf_event *hwc = &event->hw;
456218cfe4eSBorislav Petkov 	struct perf_ibs *perf_ibs = container_of(event->pmu, struct perf_ibs, pmu);
457218cfe4eSBorislav Petkov 	struct cpu_perf_ibs *pcpu = this_cpu_ptr(perf_ibs->pcpu);
458218cfe4eSBorislav Petkov 	u64 config;
459218cfe4eSBorislav Petkov 	int stopping;
460218cfe4eSBorislav Petkov 
46185dc6002SPeter Zijlstra 	if (test_and_set_bit(IBS_STOPPING, pcpu->state))
46285dc6002SPeter Zijlstra 		return;
46385dc6002SPeter Zijlstra 
4645a50f529SPeter Zijlstra 	stopping = test_bit(IBS_STARTED, pcpu->state);
465218cfe4eSBorislav Petkov 
466218cfe4eSBorislav Petkov 	if (!stopping && (hwc->state & PERF_HES_UPTODATE))
467218cfe4eSBorislav Petkov 		return;
468218cfe4eSBorislav Petkov 
469218cfe4eSBorislav Petkov 	rdmsrl(hwc->config_base, config);
470218cfe4eSBorislav Petkov 
471218cfe4eSBorislav Petkov 	if (stopping) {
4725a50f529SPeter Zijlstra 		/*
47385dc6002SPeter Zijlstra 		 * Set STOPPED before disabling the hardware, such that it
4745a50f529SPeter Zijlstra 		 * must be visible to NMIs the moment we clear the EN bit,
4755a50f529SPeter Zijlstra 		 * at which point we can generate an !VALID sample which
4765a50f529SPeter Zijlstra 		 * we need to consume.
4775a50f529SPeter Zijlstra 		 */
47885dc6002SPeter Zijlstra 		set_bit(IBS_STOPPED, pcpu->state);
479218cfe4eSBorislav Petkov 		perf_ibs_disable_event(perf_ibs, hwc, config);
4805a50f529SPeter Zijlstra 		/*
4815a50f529SPeter Zijlstra 		 * Clear STARTED after disabling the hardware; if it were
4825a50f529SPeter Zijlstra 		 * cleared before an NMI hitting after the clear but before
4835a50f529SPeter Zijlstra 		 * clearing the EN bit might think it a spurious NMI and not
4845a50f529SPeter Zijlstra 		 * handle it.
4855a50f529SPeter Zijlstra 		 *
4865a50f529SPeter Zijlstra 		 * Clearing it after, however, creates the problem of the NMI
4875a50f529SPeter Zijlstra 		 * handler seeing STARTED but not having a valid sample.
4885a50f529SPeter Zijlstra 		 */
4895a50f529SPeter Zijlstra 		clear_bit(IBS_STARTED, pcpu->state);
490218cfe4eSBorislav Petkov 		WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
491218cfe4eSBorislav Petkov 		hwc->state |= PERF_HES_STOPPED;
492218cfe4eSBorislav Petkov 	}
493218cfe4eSBorislav Petkov 
494218cfe4eSBorislav Petkov 	if (hwc->state & PERF_HES_UPTODATE)
495218cfe4eSBorislav Petkov 		return;
496218cfe4eSBorislav Petkov 
497218cfe4eSBorislav Petkov 	/*
498218cfe4eSBorislav Petkov 	 * Clear valid bit to not count rollovers on update, rollovers
499218cfe4eSBorislav Petkov 	 * are only updated in the irq handler.
500218cfe4eSBorislav Petkov 	 */
501218cfe4eSBorislav Petkov 	config &= ~perf_ibs->valid_mask;
502218cfe4eSBorislav Petkov 
503218cfe4eSBorislav Petkov 	perf_ibs_event_update(perf_ibs, event, &config);
504218cfe4eSBorislav Petkov 	hwc->state |= PERF_HES_UPTODATE;
505218cfe4eSBorislav Petkov }
506218cfe4eSBorislav Petkov 
perf_ibs_add(struct perf_event * event,int flags)507218cfe4eSBorislav Petkov static int perf_ibs_add(struct perf_event *event, int flags)
508218cfe4eSBorislav Petkov {
509218cfe4eSBorislav Petkov 	struct perf_ibs *perf_ibs = container_of(event->pmu, struct perf_ibs, pmu);
510218cfe4eSBorislav Petkov 	struct cpu_perf_ibs *pcpu = this_cpu_ptr(perf_ibs->pcpu);
511218cfe4eSBorislav Petkov 
512218cfe4eSBorislav Petkov 	if (test_and_set_bit(IBS_ENABLED, pcpu->state))
513218cfe4eSBorislav Petkov 		return -ENOSPC;
514218cfe4eSBorislav Petkov 
515218cfe4eSBorislav Petkov 	event->hw.state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
516218cfe4eSBorislav Petkov 
517218cfe4eSBorislav Petkov 	pcpu->event = event;
518218cfe4eSBorislav Petkov 
519218cfe4eSBorislav Petkov 	if (flags & PERF_EF_START)
520218cfe4eSBorislav Petkov 		perf_ibs_start(event, PERF_EF_RELOAD);
521218cfe4eSBorislav Petkov 
522218cfe4eSBorislav Petkov 	return 0;
523218cfe4eSBorislav Petkov }
524218cfe4eSBorislav Petkov 
perf_ibs_del(struct perf_event * event,int flags)525218cfe4eSBorislav Petkov static void perf_ibs_del(struct perf_event *event, int flags)
526218cfe4eSBorislav Petkov {
527218cfe4eSBorislav Petkov 	struct perf_ibs *perf_ibs = container_of(event->pmu, struct perf_ibs, pmu);
528218cfe4eSBorislav Petkov 	struct cpu_perf_ibs *pcpu = this_cpu_ptr(perf_ibs->pcpu);
529218cfe4eSBorislav Petkov 
530218cfe4eSBorislav Petkov 	if (!test_and_clear_bit(IBS_ENABLED, pcpu->state))
531218cfe4eSBorislav Petkov 		return;
532218cfe4eSBorislav Petkov 
533218cfe4eSBorislav Petkov 	perf_ibs_stop(event, PERF_EF_UPDATE);
534218cfe4eSBorislav Petkov 
535218cfe4eSBorislav Petkov 	pcpu->event = NULL;
536218cfe4eSBorislav Petkov 
537218cfe4eSBorislav Petkov 	perf_event_update_userpage(event);
538218cfe4eSBorislav Petkov }
539218cfe4eSBorislav Petkov 
perf_ibs_read(struct perf_event * event)540218cfe4eSBorislav Petkov static void perf_ibs_read(struct perf_event *event) { }
541218cfe4eSBorislav Petkov 
5422a7a7e65SRavi Bangoria /*
5432a7a7e65SRavi Bangoria  * We need to initialize with empty group if all attributes in the
5442a7a7e65SRavi Bangoria  * group are dynamic.
5452a7a7e65SRavi Bangoria  */
5462a7a7e65SRavi Bangoria static struct attribute *attrs_empty[] = {
5472a7a7e65SRavi Bangoria 	NULL,
5482a7a7e65SRavi Bangoria };
5492a7a7e65SRavi Bangoria 
5502a7a7e65SRavi Bangoria static struct attribute_group empty_format_group = {
5512a7a7e65SRavi Bangoria 	.name = "format",
5522a7a7e65SRavi Bangoria 	.attrs = attrs_empty,
5532a7a7e65SRavi Bangoria };
5542a7a7e65SRavi Bangoria 
555838de1d8SRavi Bangoria static struct attribute_group empty_caps_group = {
556838de1d8SRavi Bangoria 	.name = "caps",
557838de1d8SRavi Bangoria 	.attrs = attrs_empty,
558838de1d8SRavi Bangoria };
559838de1d8SRavi Bangoria 
5602a7a7e65SRavi Bangoria static const struct attribute_group *empty_attr_groups[] = {
5612a7a7e65SRavi Bangoria 	&empty_format_group,
562838de1d8SRavi Bangoria 	&empty_caps_group,
5632a7a7e65SRavi Bangoria 	NULL,
5642a7a7e65SRavi Bangoria };
5652a7a7e65SRavi Bangoria 
566218cfe4eSBorislav Petkov PMU_FORMAT_ATTR(rand_en,	"config:57");
567218cfe4eSBorislav Petkov PMU_FORMAT_ATTR(cnt_ctl,	"config:19");
568ba5d35b4SRavi Bangoria PMU_EVENT_ATTR_STRING(l3missonly, fetch_l3missonly, "config:59");
569ba5d35b4SRavi Bangoria PMU_EVENT_ATTR_STRING(l3missonly, op_l3missonly, "config:16");
570838de1d8SRavi Bangoria PMU_EVENT_ATTR_STRING(zen4_ibs_extensions, zen4_ibs_extensions, "1");
571ba5d35b4SRavi Bangoria 
572ba5d35b4SRavi Bangoria static umode_t
zen4_ibs_extensions_is_visible(struct kobject * kobj,struct attribute * attr,int i)573ba5d35b4SRavi Bangoria zen4_ibs_extensions_is_visible(struct kobject *kobj, struct attribute *attr, int i)
574ba5d35b4SRavi Bangoria {
575ba5d35b4SRavi Bangoria 	return ibs_caps & IBS_CAPS_ZEN4 ? attr->mode : 0;
576ba5d35b4SRavi Bangoria }
577218cfe4eSBorislav Petkov 
5782a7a7e65SRavi Bangoria static struct attribute *rand_en_attrs[] = {
579218cfe4eSBorislav Petkov 	&format_attr_rand_en.attr,
580218cfe4eSBorislav Petkov 	NULL,
581218cfe4eSBorislav Petkov };
582218cfe4eSBorislav Petkov 
583ba5d35b4SRavi Bangoria static struct attribute *fetch_l3missonly_attrs[] = {
584ba5d35b4SRavi Bangoria 	&fetch_l3missonly.attr.attr,
585ba5d35b4SRavi Bangoria 	NULL,
586ba5d35b4SRavi Bangoria };
587ba5d35b4SRavi Bangoria 
588838de1d8SRavi Bangoria static struct attribute *zen4_ibs_extensions_attrs[] = {
589838de1d8SRavi Bangoria 	&zen4_ibs_extensions.attr.attr,
590838de1d8SRavi Bangoria 	NULL,
591838de1d8SRavi Bangoria };
592838de1d8SRavi Bangoria 
5932a7a7e65SRavi Bangoria static struct attribute_group group_rand_en = {
5942a7a7e65SRavi Bangoria 	.name = "format",
5952a7a7e65SRavi Bangoria 	.attrs = rand_en_attrs,
5962a7a7e65SRavi Bangoria };
5972a7a7e65SRavi Bangoria 
598ba5d35b4SRavi Bangoria static struct attribute_group group_fetch_l3missonly = {
599ba5d35b4SRavi Bangoria 	.name = "format",
600ba5d35b4SRavi Bangoria 	.attrs = fetch_l3missonly_attrs,
601ba5d35b4SRavi Bangoria 	.is_visible = zen4_ibs_extensions_is_visible,
602ba5d35b4SRavi Bangoria };
603ba5d35b4SRavi Bangoria 
604838de1d8SRavi Bangoria static struct attribute_group group_zen4_ibs_extensions = {
605838de1d8SRavi Bangoria 	.name = "caps",
606838de1d8SRavi Bangoria 	.attrs = zen4_ibs_extensions_attrs,
607838de1d8SRavi Bangoria 	.is_visible = zen4_ibs_extensions_is_visible,
608838de1d8SRavi Bangoria };
609838de1d8SRavi Bangoria 
6102a7a7e65SRavi Bangoria static const struct attribute_group *fetch_attr_groups[] = {
6112a7a7e65SRavi Bangoria 	&group_rand_en,
612838de1d8SRavi Bangoria 	&empty_caps_group,
6132a7a7e65SRavi Bangoria 	NULL,
6142a7a7e65SRavi Bangoria };
6152a7a7e65SRavi Bangoria 
616ba5d35b4SRavi Bangoria static const struct attribute_group *fetch_attr_update[] = {
617ba5d35b4SRavi Bangoria 	&group_fetch_l3missonly,
618838de1d8SRavi Bangoria 	&group_zen4_ibs_extensions,
619ba5d35b4SRavi Bangoria 	NULL,
620ba5d35b4SRavi Bangoria };
621ba5d35b4SRavi Bangoria 
6222a7a7e65SRavi Bangoria static umode_t
cnt_ctl_is_visible(struct kobject * kobj,struct attribute * attr,int i)6232a7a7e65SRavi Bangoria cnt_ctl_is_visible(struct kobject *kobj, struct attribute *attr, int i)
6242a7a7e65SRavi Bangoria {
6252a7a7e65SRavi Bangoria 	return ibs_caps & IBS_CAPS_OPCNT ? attr->mode : 0;
6262a7a7e65SRavi Bangoria }
6272a7a7e65SRavi Bangoria 
6282a7a7e65SRavi Bangoria static struct attribute *cnt_ctl_attrs[] = {
6292a7a7e65SRavi Bangoria 	&format_attr_cnt_ctl.attr,
6302a7a7e65SRavi Bangoria 	NULL,
6312a7a7e65SRavi Bangoria };
6322a7a7e65SRavi Bangoria 
633ba5d35b4SRavi Bangoria static struct attribute *op_l3missonly_attrs[] = {
634ba5d35b4SRavi Bangoria 	&op_l3missonly.attr.attr,
635ba5d35b4SRavi Bangoria 	NULL,
636ba5d35b4SRavi Bangoria };
637ba5d35b4SRavi Bangoria 
6382a7a7e65SRavi Bangoria static struct attribute_group group_cnt_ctl = {
6392a7a7e65SRavi Bangoria 	.name = "format",
6402a7a7e65SRavi Bangoria 	.attrs = cnt_ctl_attrs,
6412a7a7e65SRavi Bangoria 	.is_visible = cnt_ctl_is_visible,
6422a7a7e65SRavi Bangoria };
6432a7a7e65SRavi Bangoria 
644ba5d35b4SRavi Bangoria static struct attribute_group group_op_l3missonly = {
645ba5d35b4SRavi Bangoria 	.name = "format",
646ba5d35b4SRavi Bangoria 	.attrs = op_l3missonly_attrs,
647ba5d35b4SRavi Bangoria 	.is_visible = zen4_ibs_extensions_is_visible,
648ba5d35b4SRavi Bangoria };
649ba5d35b4SRavi Bangoria 
6502a7a7e65SRavi Bangoria static const struct attribute_group *op_attr_update[] = {
6512a7a7e65SRavi Bangoria 	&group_cnt_ctl,
652ba5d35b4SRavi Bangoria 	&group_op_l3missonly,
653838de1d8SRavi Bangoria 	&group_zen4_ibs_extensions,
654218cfe4eSBorislav Petkov 	NULL,
655218cfe4eSBorislav Petkov };
656218cfe4eSBorislav Petkov 
657218cfe4eSBorislav Petkov static struct perf_ibs perf_ibs_fetch = {
658218cfe4eSBorislav Petkov 	.pmu = {
65930093056SRavi Bangoria 		.task_ctx_nr	= perf_hw_context,
660218cfe4eSBorislav Petkov 
661218cfe4eSBorislav Petkov 		.event_init	= perf_ibs_init,
662218cfe4eSBorislav Petkov 		.add		= perf_ibs_add,
663218cfe4eSBorislav Petkov 		.del		= perf_ibs_del,
664218cfe4eSBorislav Petkov 		.start		= perf_ibs_start,
665218cfe4eSBorislav Petkov 		.stop		= perf_ibs_stop,
666218cfe4eSBorislav Petkov 		.read		= perf_ibs_read,
6672ff40250SAndrew Murray 		.capabilities	= PERF_PMU_CAP_NO_EXCLUDE,
668218cfe4eSBorislav Petkov 	},
669218cfe4eSBorislav Petkov 	.msr			= MSR_AMD64_IBSFETCHCTL,
670218cfe4eSBorislav Petkov 	.config_mask		= IBS_FETCH_CONFIG_MASK,
671218cfe4eSBorislav Petkov 	.cnt_mask		= IBS_FETCH_MAX_CNT,
672218cfe4eSBorislav Petkov 	.enable_mask		= IBS_FETCH_ENABLE,
673218cfe4eSBorislav Petkov 	.valid_mask		= IBS_FETCH_VAL,
674218cfe4eSBorislav Petkov 	.max_period		= IBS_FETCH_MAX_CNT << 4,
675218cfe4eSBorislav Petkov 	.offset_mask		= { MSR_AMD64_IBSFETCH_REG_MASK },
676218cfe4eSBorislav Petkov 	.offset_max		= MSR_AMD64_IBSFETCH_REG_COUNT,
677218cfe4eSBorislav Petkov 
678218cfe4eSBorislav Petkov 	.get_count		= get_ibs_fetch_count,
679218cfe4eSBorislav Petkov };
680218cfe4eSBorislav Petkov 
681218cfe4eSBorislav Petkov static struct perf_ibs perf_ibs_op = {
682218cfe4eSBorislav Petkov 	.pmu = {
68330093056SRavi Bangoria 		.task_ctx_nr	= perf_hw_context,
684218cfe4eSBorislav Petkov 
685218cfe4eSBorislav Petkov 		.event_init	= perf_ibs_init,
686218cfe4eSBorislav Petkov 		.add		= perf_ibs_add,
687218cfe4eSBorislav Petkov 		.del		= perf_ibs_del,
688218cfe4eSBorislav Petkov 		.start		= perf_ibs_start,
689218cfe4eSBorislav Petkov 		.stop		= perf_ibs_stop,
690218cfe4eSBorislav Petkov 		.read		= perf_ibs_read,
691f11dd0d8SKim Phillips 		.capabilities	= PERF_PMU_CAP_NO_EXCLUDE,
692218cfe4eSBorislav Petkov 	},
693218cfe4eSBorislav Petkov 	.msr			= MSR_AMD64_IBSOPCTL,
694218cfe4eSBorislav Petkov 	.config_mask		= IBS_OP_CONFIG_MASK,
695e431e79bSKim Phillips 	.cnt_mask		= IBS_OP_MAX_CNT | IBS_OP_CUR_CNT |
696e431e79bSKim Phillips 				  IBS_OP_CUR_CNT_RAND,
697218cfe4eSBorislav Petkov 	.enable_mask		= IBS_OP_ENABLE,
698218cfe4eSBorislav Petkov 	.valid_mask		= IBS_OP_VAL,
699218cfe4eSBorislav Petkov 	.max_period		= IBS_OP_MAX_CNT << 4,
700218cfe4eSBorislav Petkov 	.offset_mask		= { MSR_AMD64_IBSOP_REG_MASK },
701218cfe4eSBorislav Petkov 	.offset_max		= MSR_AMD64_IBSOP_REG_COUNT,
702218cfe4eSBorislav Petkov 
703218cfe4eSBorislav Petkov 	.get_count		= get_ibs_op_count,
704218cfe4eSBorislav Petkov };
705218cfe4eSBorislav Petkov 
perf_ibs_get_mem_op(union ibs_op_data3 * op_data3,struct perf_sample_data * data)7067c10dd0aSRavi Bangoria static void perf_ibs_get_mem_op(union ibs_op_data3 *op_data3,
7077c10dd0aSRavi Bangoria 				struct perf_sample_data *data)
7087c10dd0aSRavi Bangoria {
7097c10dd0aSRavi Bangoria 	union perf_mem_data_src *data_src = &data->data_src;
7107c10dd0aSRavi Bangoria 
7117c10dd0aSRavi Bangoria 	data_src->mem_op = PERF_MEM_OP_NA;
7127c10dd0aSRavi Bangoria 
7137c10dd0aSRavi Bangoria 	if (op_data3->ld_op)
7147c10dd0aSRavi Bangoria 		data_src->mem_op = PERF_MEM_OP_LOAD;
7157c10dd0aSRavi Bangoria 	else if (op_data3->st_op)
7167c10dd0aSRavi Bangoria 		data_src->mem_op = PERF_MEM_OP_STORE;
7177c10dd0aSRavi Bangoria }
7187c10dd0aSRavi Bangoria 
7197c10dd0aSRavi Bangoria /*
7207c10dd0aSRavi Bangoria  * Processors having CPUID_Fn8000001B_EAX[11] aka IBS_CAPS_ZEN4 has
7217c10dd0aSRavi Bangoria  * more fine granular DataSrc encodings. Others have coarse.
7227c10dd0aSRavi Bangoria  */
perf_ibs_data_src(union ibs_op_data2 * op_data2)7237c10dd0aSRavi Bangoria static u8 perf_ibs_data_src(union ibs_op_data2 *op_data2)
7247c10dd0aSRavi Bangoria {
7257c10dd0aSRavi Bangoria 	if (ibs_caps & IBS_CAPS_ZEN4)
7267c10dd0aSRavi Bangoria 		return (op_data2->data_src_hi << 3) | op_data2->data_src_lo;
7277c10dd0aSRavi Bangoria 
7287c10dd0aSRavi Bangoria 	return op_data2->data_src_lo;
7297c10dd0aSRavi Bangoria }
7307c10dd0aSRavi Bangoria 
7318bfc20baSNamhyung Kim #define	L(x)		(PERF_MEM_S(LVL, x) | PERF_MEM_S(LVL, HIT))
7328bfc20baSNamhyung Kim #define	LN(x)		PERF_MEM_S(LVLNUM, x)
7338bfc20baSNamhyung Kim #define	REM		PERF_MEM_S(REMOTE, REMOTE)
7348bfc20baSNamhyung Kim #define	HOPS(x)		PERF_MEM_S(HOPS, x)
7358bfc20baSNamhyung Kim 
7368bfc20baSNamhyung Kim static u64 g_data_src[8] = {
7378bfc20baSNamhyung Kim 	[IBS_DATA_SRC_LOC_CACHE]	  = L(L3) | L(REM_CCE1) | LN(ANY_CACHE) | HOPS(0),
7388bfc20baSNamhyung Kim 	[IBS_DATA_SRC_DRAM]		  = L(LOC_RAM) | LN(RAM),
7398bfc20baSNamhyung Kim 	[IBS_DATA_SRC_REM_CACHE]	  = L(REM_CCE2) | LN(ANY_CACHE) | REM | HOPS(1),
7408bfc20baSNamhyung Kim 	[IBS_DATA_SRC_IO]		  = L(IO) | LN(IO),
7418bfc20baSNamhyung Kim };
7428bfc20baSNamhyung Kim 
7438bfc20baSNamhyung Kim #define RMT_NODE_BITS			(1 << IBS_DATA_SRC_DRAM)
7448bfc20baSNamhyung Kim #define RMT_NODE_APPLICABLE(x)		(RMT_NODE_BITS & (1 << x))
7458bfc20baSNamhyung Kim 
7468bfc20baSNamhyung Kim static u64 g_zen4_data_src[32] = {
7478bfc20baSNamhyung Kim 	[IBS_DATA_SRC_EXT_LOC_CACHE]	  = L(L3) | LN(L3),
7488bfc20baSNamhyung Kim 	[IBS_DATA_SRC_EXT_NEAR_CCX_CACHE] = L(REM_CCE1) | LN(ANY_CACHE) | REM | HOPS(0),
7498bfc20baSNamhyung Kim 	[IBS_DATA_SRC_EXT_DRAM]		  = L(LOC_RAM) | LN(RAM),
7508bfc20baSNamhyung Kim 	[IBS_DATA_SRC_EXT_FAR_CCX_CACHE]  = L(REM_CCE2) | LN(ANY_CACHE) | REM | HOPS(1),
7518bfc20baSNamhyung Kim 	[IBS_DATA_SRC_EXT_PMEM]		  = LN(PMEM),
7528bfc20baSNamhyung Kim 	[IBS_DATA_SRC_EXT_IO]		  = L(IO) | LN(IO),
7538bfc20baSNamhyung Kim 	[IBS_DATA_SRC_EXT_EXT_MEM]	  = LN(CXL),
7548bfc20baSNamhyung Kim };
7558bfc20baSNamhyung Kim 
7568bfc20baSNamhyung Kim #define ZEN4_RMT_NODE_BITS		((1 << IBS_DATA_SRC_EXT_DRAM) | \
7578bfc20baSNamhyung Kim 					 (1 << IBS_DATA_SRC_EXT_PMEM) | \
7588bfc20baSNamhyung Kim 					 (1 << IBS_DATA_SRC_EXT_EXT_MEM))
7598bfc20baSNamhyung Kim #define ZEN4_RMT_NODE_APPLICABLE(x)	(ZEN4_RMT_NODE_BITS & (1 << x))
7608bfc20baSNamhyung Kim 
perf_ibs_get_mem_lvl(union ibs_op_data2 * op_data2,union ibs_op_data3 * op_data3,struct perf_sample_data * data)7618bfc20baSNamhyung Kim static __u64 perf_ibs_get_mem_lvl(union ibs_op_data2 *op_data2,
7627c10dd0aSRavi Bangoria 				  union ibs_op_data3 *op_data3,
7637c10dd0aSRavi Bangoria 				  struct perf_sample_data *data)
7647c10dd0aSRavi Bangoria {
7657c10dd0aSRavi Bangoria 	union perf_mem_data_src *data_src = &data->data_src;
7667c10dd0aSRavi Bangoria 	u8 ibs_data_src = perf_ibs_data_src(op_data2);
7677c10dd0aSRavi Bangoria 
7687c10dd0aSRavi Bangoria 	data_src->mem_lvl = 0;
7698bfc20baSNamhyung Kim 	data_src->mem_lvl_num = 0;
7707c10dd0aSRavi Bangoria 
7717c10dd0aSRavi Bangoria 	/*
7727c10dd0aSRavi Bangoria 	 * DcMiss, L2Miss, DataSrc, DcMissLat etc. are all invalid for Uncached
7737c10dd0aSRavi Bangoria 	 * memory accesses. So, check DcUcMemAcc bit early.
7747c10dd0aSRavi Bangoria 	 */
7758bfc20baSNamhyung Kim 	if (op_data3->dc_uc_mem_acc && ibs_data_src != IBS_DATA_SRC_EXT_IO)
7768bfc20baSNamhyung Kim 		return L(UNC) | LN(UNC);
7777c10dd0aSRavi Bangoria 
7787c10dd0aSRavi Bangoria 	/* L1 Hit */
7798bfc20baSNamhyung Kim 	if (op_data3->dc_miss == 0)
7808bfc20baSNamhyung Kim 		return L(L1) | LN(L1);
7817c10dd0aSRavi Bangoria 
7827c10dd0aSRavi Bangoria 	/* L2 Hit */
7837c10dd0aSRavi Bangoria 	if (op_data3->l2_miss == 0) {
7847c10dd0aSRavi Bangoria 		/* Erratum #1293 */
7857c10dd0aSRavi Bangoria 		if (boot_cpu_data.x86 != 0x19 || boot_cpu_data.x86_model > 0xF ||
7868bfc20baSNamhyung Kim 		    !(op_data3->sw_pf || op_data3->dc_miss_no_mab_alloc))
7878bfc20baSNamhyung Kim 			return L(L2) | LN(L2);
7887c10dd0aSRavi Bangoria 	}
7897c10dd0aSRavi Bangoria 
7907c10dd0aSRavi Bangoria 	/*
7917c10dd0aSRavi Bangoria 	 * OP_DATA2 is valid only for load ops. Skip all checks which
7927c10dd0aSRavi Bangoria 	 * uses OP_DATA2[DataSrc].
7937c10dd0aSRavi Bangoria 	 */
7947c10dd0aSRavi Bangoria 	if (data_src->mem_op != PERF_MEM_OP_LOAD)
7957c10dd0aSRavi Bangoria 		goto check_mab;
7967c10dd0aSRavi Bangoria 
7977c10dd0aSRavi Bangoria 	if (ibs_caps & IBS_CAPS_ZEN4) {
7988bfc20baSNamhyung Kim 		u64 val = g_zen4_data_src[ibs_data_src];
7997c10dd0aSRavi Bangoria 
8008bfc20baSNamhyung Kim 		if (!val)
8018bfc20baSNamhyung Kim 			goto check_mab;
8027c10dd0aSRavi Bangoria 
8038bfc20baSNamhyung Kim 		/* HOPS_1 because IBS doesn't provide remote socket detail */
8048bfc20baSNamhyung Kim 		if (op_data2->rmt_node && ZEN4_RMT_NODE_APPLICABLE(ibs_data_src)) {
8058bfc20baSNamhyung Kim 			if (ibs_data_src == IBS_DATA_SRC_EXT_DRAM)
8068bfc20baSNamhyung Kim 				val = L(REM_RAM1) | LN(RAM) | REM | HOPS(1);
8077c10dd0aSRavi Bangoria 			else
8088bfc20baSNamhyung Kim 				val |= REM | HOPS(1);
8097c10dd0aSRavi Bangoria 		}
8107c10dd0aSRavi Bangoria 
8118bfc20baSNamhyung Kim 		return val;
8128bfc20baSNamhyung Kim 	} else {
8138bfc20baSNamhyung Kim 		u64 val = g_data_src[ibs_data_src];
8148bfc20baSNamhyung Kim 
8158bfc20baSNamhyung Kim 		if (!val)
8168bfc20baSNamhyung Kim 			goto check_mab;
8178bfc20baSNamhyung Kim 
8188bfc20baSNamhyung Kim 		/* HOPS_1 because IBS doesn't provide remote socket detail */
8198bfc20baSNamhyung Kim 		if (op_data2->rmt_node && RMT_NODE_APPLICABLE(ibs_data_src)) {
8208bfc20baSNamhyung Kim 			if (ibs_data_src == IBS_DATA_SRC_DRAM)
8218bfc20baSNamhyung Kim 				val = L(REM_RAM1) | LN(RAM) | REM | HOPS(1);
8228bfc20baSNamhyung Kim 			else
8238bfc20baSNamhyung Kim 				val |= REM | HOPS(1);
8247c10dd0aSRavi Bangoria 		}
8257c10dd0aSRavi Bangoria 
8268bfc20baSNamhyung Kim 		return val;
8277c10dd0aSRavi Bangoria 	}
8287c10dd0aSRavi Bangoria 
8297c10dd0aSRavi Bangoria check_mab:
8307c10dd0aSRavi Bangoria 	/*
8317c10dd0aSRavi Bangoria 	 * MAB (Miss Address Buffer) Hit. MAB keeps track of outstanding
8327c10dd0aSRavi Bangoria 	 * DC misses. However, such data may come from any level in mem
8337c10dd0aSRavi Bangoria 	 * hierarchy. IBS provides detail about both MAB as well as actual
8347c10dd0aSRavi Bangoria 	 * DataSrc simultaneously. Prioritize DataSrc over MAB, i.e. set
8357c10dd0aSRavi Bangoria 	 * MAB only when IBS fails to provide DataSrc.
8367c10dd0aSRavi Bangoria 	 */
8378bfc20baSNamhyung Kim 	if (op_data3->dc_miss_no_mab_alloc)
8388bfc20baSNamhyung Kim 		return L(LFB) | LN(LFB);
8397c10dd0aSRavi Bangoria 
8408bfc20baSNamhyung Kim 	/* Don't set HIT with NA */
8418bfc20baSNamhyung Kim 	return PERF_MEM_S(LVL, NA) | LN(NA);
8427c10dd0aSRavi Bangoria }
8437c10dd0aSRavi Bangoria 
perf_ibs_cache_hit_st_valid(void)8447c10dd0aSRavi Bangoria static bool perf_ibs_cache_hit_st_valid(void)
8457c10dd0aSRavi Bangoria {
8467c10dd0aSRavi Bangoria 	/* 0: Uninitialized, 1: Valid, -1: Invalid */
8477c10dd0aSRavi Bangoria 	static int cache_hit_st_valid;
8487c10dd0aSRavi Bangoria 
8497c10dd0aSRavi Bangoria 	if (unlikely(!cache_hit_st_valid)) {
8507c10dd0aSRavi Bangoria 		if (boot_cpu_data.x86 == 0x19 &&
8517c10dd0aSRavi Bangoria 		    (boot_cpu_data.x86_model <= 0xF ||
8527c10dd0aSRavi Bangoria 		    (boot_cpu_data.x86_model >= 0x20 &&
8537c10dd0aSRavi Bangoria 		     boot_cpu_data.x86_model <= 0x5F))) {
8547c10dd0aSRavi Bangoria 			cache_hit_st_valid = -1;
8557c10dd0aSRavi Bangoria 		} else {
8567c10dd0aSRavi Bangoria 			cache_hit_st_valid = 1;
8577c10dd0aSRavi Bangoria 		}
8587c10dd0aSRavi Bangoria 	}
8597c10dd0aSRavi Bangoria 
8607c10dd0aSRavi Bangoria 	return cache_hit_st_valid == 1;
8617c10dd0aSRavi Bangoria }
8627c10dd0aSRavi Bangoria 
perf_ibs_get_mem_snoop(union ibs_op_data2 * op_data2,struct perf_sample_data * data)8637c10dd0aSRavi Bangoria static void perf_ibs_get_mem_snoop(union ibs_op_data2 *op_data2,
8647c10dd0aSRavi Bangoria 				   struct perf_sample_data *data)
8657c10dd0aSRavi Bangoria {
8667c10dd0aSRavi Bangoria 	union perf_mem_data_src *data_src = &data->data_src;
8677c10dd0aSRavi Bangoria 	u8 ibs_data_src;
8687c10dd0aSRavi Bangoria 
8697c10dd0aSRavi Bangoria 	data_src->mem_snoop = PERF_MEM_SNOOP_NA;
8707c10dd0aSRavi Bangoria 
8717c10dd0aSRavi Bangoria 	if (!perf_ibs_cache_hit_st_valid() ||
8727c10dd0aSRavi Bangoria 	    data_src->mem_op != PERF_MEM_OP_LOAD ||
8737c10dd0aSRavi Bangoria 	    data_src->mem_lvl & PERF_MEM_LVL_L1 ||
8747c10dd0aSRavi Bangoria 	    data_src->mem_lvl & PERF_MEM_LVL_L2 ||
8757c10dd0aSRavi Bangoria 	    op_data2->cache_hit_st)
8767c10dd0aSRavi Bangoria 		return;
8777c10dd0aSRavi Bangoria 
8787c10dd0aSRavi Bangoria 	ibs_data_src = perf_ibs_data_src(op_data2);
8797c10dd0aSRavi Bangoria 
8807c10dd0aSRavi Bangoria 	if (ibs_caps & IBS_CAPS_ZEN4) {
8817c10dd0aSRavi Bangoria 		if (ibs_data_src == IBS_DATA_SRC_EXT_LOC_CACHE ||
8827c10dd0aSRavi Bangoria 		    ibs_data_src == IBS_DATA_SRC_EXT_NEAR_CCX_CACHE ||
8837c10dd0aSRavi Bangoria 		    ibs_data_src == IBS_DATA_SRC_EXT_FAR_CCX_CACHE)
8847c10dd0aSRavi Bangoria 			data_src->mem_snoop = PERF_MEM_SNOOP_HITM;
8857c10dd0aSRavi Bangoria 	} else if (ibs_data_src == IBS_DATA_SRC_LOC_CACHE) {
8867c10dd0aSRavi Bangoria 		data_src->mem_snoop = PERF_MEM_SNOOP_HITM;
8877c10dd0aSRavi Bangoria 	}
8887c10dd0aSRavi Bangoria }
8897c10dd0aSRavi Bangoria 
perf_ibs_get_tlb_lvl(union ibs_op_data3 * op_data3,struct perf_sample_data * data)8907c10dd0aSRavi Bangoria static void perf_ibs_get_tlb_lvl(union ibs_op_data3 *op_data3,
8917c10dd0aSRavi Bangoria 				 struct perf_sample_data *data)
8927c10dd0aSRavi Bangoria {
8937c10dd0aSRavi Bangoria 	union perf_mem_data_src *data_src = &data->data_src;
8947c10dd0aSRavi Bangoria 
8957c10dd0aSRavi Bangoria 	data_src->mem_dtlb = PERF_MEM_TLB_NA;
8967c10dd0aSRavi Bangoria 
8977c10dd0aSRavi Bangoria 	if (!op_data3->dc_lin_addr_valid)
8987c10dd0aSRavi Bangoria 		return;
8997c10dd0aSRavi Bangoria 
9007c10dd0aSRavi Bangoria 	if (!op_data3->dc_l1tlb_miss) {
9017c10dd0aSRavi Bangoria 		data_src->mem_dtlb = PERF_MEM_TLB_L1 | PERF_MEM_TLB_HIT;
9027c10dd0aSRavi Bangoria 		return;
9037c10dd0aSRavi Bangoria 	}
9047c10dd0aSRavi Bangoria 
9057c10dd0aSRavi Bangoria 	if (!op_data3->dc_l2tlb_miss) {
9067c10dd0aSRavi Bangoria 		data_src->mem_dtlb = PERF_MEM_TLB_L2 | PERF_MEM_TLB_HIT;
9077c10dd0aSRavi Bangoria 		return;
9087c10dd0aSRavi Bangoria 	}
9097c10dd0aSRavi Bangoria 
9107c10dd0aSRavi Bangoria 	data_src->mem_dtlb = PERF_MEM_TLB_L2 | PERF_MEM_TLB_MISS;
9117c10dd0aSRavi Bangoria }
9127c10dd0aSRavi Bangoria 
perf_ibs_get_mem_lock(union ibs_op_data3 * op_data3,struct perf_sample_data * data)9137c10dd0aSRavi Bangoria static void perf_ibs_get_mem_lock(union ibs_op_data3 *op_data3,
9147c10dd0aSRavi Bangoria 				  struct perf_sample_data *data)
9157c10dd0aSRavi Bangoria {
9167c10dd0aSRavi Bangoria 	union perf_mem_data_src *data_src = &data->data_src;
9177c10dd0aSRavi Bangoria 
9187c10dd0aSRavi Bangoria 	data_src->mem_lock = PERF_MEM_LOCK_NA;
9197c10dd0aSRavi Bangoria 
9207c10dd0aSRavi Bangoria 	if (op_data3->dc_locked_op)
9217c10dd0aSRavi Bangoria 		data_src->mem_lock = PERF_MEM_LOCK_LOCKED;
9227c10dd0aSRavi Bangoria }
9237c10dd0aSRavi Bangoria 
9247c10dd0aSRavi Bangoria #define ibs_op_msr_idx(msr)	(msr - MSR_AMD64_IBSOPCTL)
9257c10dd0aSRavi Bangoria 
perf_ibs_get_data_src(struct perf_ibs_data * ibs_data,struct perf_sample_data * data,union ibs_op_data2 * op_data2,union ibs_op_data3 * op_data3)9267c10dd0aSRavi Bangoria static void perf_ibs_get_data_src(struct perf_ibs_data *ibs_data,
9277c10dd0aSRavi Bangoria 				  struct perf_sample_data *data,
9287c10dd0aSRavi Bangoria 				  union ibs_op_data2 *op_data2,
9297c10dd0aSRavi Bangoria 				  union ibs_op_data3 *op_data3)
9307c10dd0aSRavi Bangoria {
9318bfc20baSNamhyung Kim 	union perf_mem_data_src *data_src = &data->data_src;
9328bfc20baSNamhyung Kim 
9338bfc20baSNamhyung Kim 	data_src->val |= perf_ibs_get_mem_lvl(op_data2, op_data3, data);
9347c10dd0aSRavi Bangoria 	perf_ibs_get_mem_snoop(op_data2, data);
9357c10dd0aSRavi Bangoria 	perf_ibs_get_tlb_lvl(op_data3, data);
9367c10dd0aSRavi Bangoria 	perf_ibs_get_mem_lock(op_data3, data);
9377c10dd0aSRavi Bangoria }
9387c10dd0aSRavi Bangoria 
perf_ibs_get_op_data2(struct perf_ibs_data * ibs_data,union ibs_op_data3 * op_data3)9397c10dd0aSRavi Bangoria static __u64 perf_ibs_get_op_data2(struct perf_ibs_data *ibs_data,
9407c10dd0aSRavi Bangoria 				   union ibs_op_data3 *op_data3)
9417c10dd0aSRavi Bangoria {
9427c10dd0aSRavi Bangoria 	__u64 val = ibs_data->regs[ibs_op_msr_idx(MSR_AMD64_IBSOPDATA2)];
9437c10dd0aSRavi Bangoria 
9447c10dd0aSRavi Bangoria 	/* Erratum #1293 */
9457c10dd0aSRavi Bangoria 	if (boot_cpu_data.x86 == 0x19 && boot_cpu_data.x86_model <= 0xF &&
9467c10dd0aSRavi Bangoria 	    (op_data3->sw_pf || op_data3->dc_miss_no_mab_alloc)) {
9477c10dd0aSRavi Bangoria 		/*
9487c10dd0aSRavi Bangoria 		 * OP_DATA2 has only two fields on Zen3: DataSrc and RmtNode.
9497c10dd0aSRavi Bangoria 		 * DataSrc=0 is 'No valid status' and RmtNode is invalid when
9507c10dd0aSRavi Bangoria 		 * DataSrc=0.
9517c10dd0aSRavi Bangoria 		 */
9527c10dd0aSRavi Bangoria 		val = 0;
9537c10dd0aSRavi Bangoria 	}
9547c10dd0aSRavi Bangoria 	return val;
9557c10dd0aSRavi Bangoria }
9567c10dd0aSRavi Bangoria 
perf_ibs_parse_ld_st_data(__u64 sample_type,struct perf_ibs_data * ibs_data,struct perf_sample_data * data)9577c10dd0aSRavi Bangoria static void perf_ibs_parse_ld_st_data(__u64 sample_type,
9587c10dd0aSRavi Bangoria 				      struct perf_ibs_data *ibs_data,
9597c10dd0aSRavi Bangoria 				      struct perf_sample_data *data)
9607c10dd0aSRavi Bangoria {
9617c10dd0aSRavi Bangoria 	union ibs_op_data3 op_data3;
9627c10dd0aSRavi Bangoria 	union ibs_op_data2 op_data2;
9636b2ae495SRavi Bangoria 	union ibs_op_data op_data;
9647c10dd0aSRavi Bangoria 
9657c10dd0aSRavi Bangoria 	data->data_src.val = PERF_MEM_NA;
9667c10dd0aSRavi Bangoria 	op_data3.val = ibs_data->regs[ibs_op_msr_idx(MSR_AMD64_IBSOPDATA3)];
9677c10dd0aSRavi Bangoria 
9687c10dd0aSRavi Bangoria 	perf_ibs_get_mem_op(&op_data3, data);
9697c10dd0aSRavi Bangoria 	if (data->data_src.mem_op != PERF_MEM_OP_LOAD &&
9707c10dd0aSRavi Bangoria 	    data->data_src.mem_op != PERF_MEM_OP_STORE)
9717c10dd0aSRavi Bangoria 		return;
9727c10dd0aSRavi Bangoria 
9737c10dd0aSRavi Bangoria 	op_data2.val = perf_ibs_get_op_data2(ibs_data, &op_data3);
9747c10dd0aSRavi Bangoria 
9757c10dd0aSRavi Bangoria 	if (sample_type & PERF_SAMPLE_DATA_SRC) {
9767c10dd0aSRavi Bangoria 		perf_ibs_get_data_src(ibs_data, data, &op_data2, &op_data3);
9777c10dd0aSRavi Bangoria 		data->sample_flags |= PERF_SAMPLE_DATA_SRC;
9787c10dd0aSRavi Bangoria 	}
9796b2ae495SRavi Bangoria 
9806b2ae495SRavi Bangoria 	if (sample_type & PERF_SAMPLE_WEIGHT_TYPE && op_data3.dc_miss &&
9816b2ae495SRavi Bangoria 	    data->data_src.mem_op == PERF_MEM_OP_LOAD) {
9826b2ae495SRavi Bangoria 		op_data.val = ibs_data->regs[ibs_op_msr_idx(MSR_AMD64_IBSOPDATA)];
9836b2ae495SRavi Bangoria 
9846b2ae495SRavi Bangoria 		if (sample_type & PERF_SAMPLE_WEIGHT_STRUCT) {
9856b2ae495SRavi Bangoria 			data->weight.var1_dw = op_data3.dc_miss_lat;
9866b2ae495SRavi Bangoria 			data->weight.var2_w = op_data.tag_to_ret_ctr;
9876b2ae495SRavi Bangoria 		} else if (sample_type & PERF_SAMPLE_WEIGHT) {
9886b2ae495SRavi Bangoria 			data->weight.full = op_data3.dc_miss_lat;
9896b2ae495SRavi Bangoria 		}
9906b2ae495SRavi Bangoria 		data->sample_flags |= PERF_SAMPLE_WEIGHT_TYPE;
9916b2ae495SRavi Bangoria 	}
992cb2bb85fSRavi Bangoria 
993cb2bb85fSRavi Bangoria 	if (sample_type & PERF_SAMPLE_ADDR && op_data3.dc_lin_addr_valid) {
994cb2bb85fSRavi Bangoria 		data->addr = ibs_data->regs[ibs_op_msr_idx(MSR_AMD64_IBSDCLINAD)];
995cb2bb85fSRavi Bangoria 		data->sample_flags |= PERF_SAMPLE_ADDR;
996cb2bb85fSRavi Bangoria 	}
9975b26af6dSRavi Bangoria 
9985b26af6dSRavi Bangoria 	if (sample_type & PERF_SAMPLE_PHYS_ADDR && op_data3.dc_phy_addr_valid) {
9995b26af6dSRavi Bangoria 		data->phys_addr = ibs_data->regs[ibs_op_msr_idx(MSR_AMD64_IBSDCPHYSAD)];
10005b26af6dSRavi Bangoria 		data->sample_flags |= PERF_SAMPLE_PHYS_ADDR;
10015b26af6dSRavi Bangoria 	}
10027c10dd0aSRavi Bangoria }
10037c10dd0aSRavi Bangoria 
perf_ibs_get_offset_max(struct perf_ibs * perf_ibs,u64 sample_type,int check_rip)10047c10dd0aSRavi Bangoria static int perf_ibs_get_offset_max(struct perf_ibs *perf_ibs, u64 sample_type,
10057c10dd0aSRavi Bangoria 				   int check_rip)
10067c10dd0aSRavi Bangoria {
10077c10dd0aSRavi Bangoria 	if (sample_type & PERF_SAMPLE_RAW ||
10087c10dd0aSRavi Bangoria 	    (perf_ibs == &perf_ibs_op &&
10096b2ae495SRavi Bangoria 	     (sample_type & PERF_SAMPLE_DATA_SRC ||
1010cb2bb85fSRavi Bangoria 	      sample_type & PERF_SAMPLE_WEIGHT_TYPE ||
10115b26af6dSRavi Bangoria 	      sample_type & PERF_SAMPLE_ADDR ||
10125b26af6dSRavi Bangoria 	      sample_type & PERF_SAMPLE_PHYS_ADDR)))
10137c10dd0aSRavi Bangoria 		return perf_ibs->offset_max;
10147c10dd0aSRavi Bangoria 	else if (check_rip)
10157c10dd0aSRavi Bangoria 		return 3;
10167c10dd0aSRavi Bangoria 	return 1;
10177c10dd0aSRavi Bangoria }
10187c10dd0aSRavi Bangoria 
perf_ibs_handle_irq(struct perf_ibs * perf_ibs,struct pt_regs * iregs)1019218cfe4eSBorislav Petkov static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs)
1020218cfe4eSBorislav Petkov {
1021218cfe4eSBorislav Petkov 	struct cpu_perf_ibs *pcpu = this_cpu_ptr(perf_ibs->pcpu);
1022218cfe4eSBorislav Petkov 	struct perf_event *event = pcpu->event;
1023d2753e6bSThomas Gleixner 	struct hw_perf_event *hwc;
1024218cfe4eSBorislav Petkov 	struct perf_sample_data data;
1025218cfe4eSBorislav Petkov 	struct perf_raw_record raw;
1026218cfe4eSBorislav Petkov 	struct pt_regs regs;
1027218cfe4eSBorislav Petkov 	struct perf_ibs_data ibs_data;
1028218cfe4eSBorislav Petkov 	int offset, size, check_rip, offset_max, throttle = 0;
1029218cfe4eSBorislav Petkov 	unsigned int msr;
10308b0bed7dSKim Phillips 	u64 *buf, *config, period, new_config = 0;
1031218cfe4eSBorislav Petkov 
1032218cfe4eSBorislav Petkov 	if (!test_bit(IBS_STARTED, pcpu->state)) {
10335a50f529SPeter Zijlstra fail:
1034218cfe4eSBorislav Petkov 		/*
1035218cfe4eSBorislav Petkov 		 * Catch spurious interrupts after stopping IBS: After
1036218cfe4eSBorislav Petkov 		 * disabling IBS there could be still incoming NMIs
1037218cfe4eSBorislav Petkov 		 * with samples that even have the valid bit cleared.
1038218cfe4eSBorislav Petkov 		 * Mark all this NMIs as handled.
1039218cfe4eSBorislav Petkov 		 */
104085dc6002SPeter Zijlstra 		if (test_and_clear_bit(IBS_STOPPED, pcpu->state))
10415a50f529SPeter Zijlstra 			return 1;
10425a50f529SPeter Zijlstra 
10435a50f529SPeter Zijlstra 		return 0;
1044218cfe4eSBorislav Petkov 	}
1045218cfe4eSBorislav Petkov 
1046d2753e6bSThomas Gleixner 	if (WARN_ON_ONCE(!event))
1047d2753e6bSThomas Gleixner 		goto fail;
1048d2753e6bSThomas Gleixner 
1049d2753e6bSThomas Gleixner 	hwc = &event->hw;
1050218cfe4eSBorislav Petkov 	msr = hwc->config_base;
1051218cfe4eSBorislav Petkov 	buf = ibs_data.regs;
1052218cfe4eSBorislav Petkov 	rdmsrl(msr, *buf);
1053218cfe4eSBorislav Petkov 	if (!(*buf++ & perf_ibs->valid_mask))
10545a50f529SPeter Zijlstra 		goto fail;
1055218cfe4eSBorislav Petkov 
1056218cfe4eSBorislav Petkov 	config = &ibs_data.regs[0];
1057218cfe4eSBorislav Petkov 	perf_ibs_event_update(perf_ibs, event, config);
1058218cfe4eSBorislav Petkov 	perf_sample_data_init(&data, 0, hwc->last_period);
1059218cfe4eSBorislav Petkov 	if (!perf_ibs_set_period(perf_ibs, hwc, &period))
1060218cfe4eSBorislav Petkov 		goto out;	/* no sw counter overflow */
1061218cfe4eSBorislav Petkov 
1062218cfe4eSBorislav Petkov 	ibs_data.caps = ibs_caps;
1063218cfe4eSBorislav Petkov 	size = 1;
1064218cfe4eSBorislav Petkov 	offset = 1;
1065218cfe4eSBorislav Petkov 	check_rip = (perf_ibs == &perf_ibs_op && (ibs_caps & IBS_CAPS_RIPINVALIDCHK));
10667c10dd0aSRavi Bangoria 
10677c10dd0aSRavi Bangoria 	offset_max = perf_ibs_get_offset_max(perf_ibs, event->attr.sample_type, check_rip);
10687c10dd0aSRavi Bangoria 
1069218cfe4eSBorislav Petkov 	do {
1070218cfe4eSBorislav Petkov 		rdmsrl(msr + offset, *buf++);
1071218cfe4eSBorislav Petkov 		size++;
1072218cfe4eSBorislav Petkov 		offset = find_next_bit(perf_ibs->offset_mask,
1073218cfe4eSBorislav Petkov 				       perf_ibs->offset_max,
1074218cfe4eSBorislav Petkov 				       offset + 1);
1075218cfe4eSBorislav Petkov 	} while (offset < offset_max);
1076218cfe4eSBorislav Petkov 	/*
107736e1be8aSKim Phillips 	 * Read IbsBrTarget, IbsOpData4, and IbsExtdCtl separately
1078218cfe4eSBorislav Petkov 	 * depending on their availability.
1079218cfe4eSBorislav Petkov 	 * Can't add to offset_max as they are staggered
1080218cfe4eSBorislav Petkov 	 */
108136e1be8aSKim Phillips 	if (event->attr.sample_type & PERF_SAMPLE_RAW) {
108236e1be8aSKim Phillips 		if (perf_ibs == &perf_ibs_op) {
1083218cfe4eSBorislav Petkov 			if (ibs_caps & IBS_CAPS_BRNTRGT) {
1084218cfe4eSBorislav Petkov 				rdmsrl(MSR_AMD64_IBSBRTARGET, *buf++);
1085218cfe4eSBorislav Petkov 				size++;
1086218cfe4eSBorislav Petkov 			}
1087218cfe4eSBorislav Petkov 			if (ibs_caps & IBS_CAPS_OPDATA4) {
1088218cfe4eSBorislav Petkov 				rdmsrl(MSR_AMD64_IBSOPDATA4, *buf++);
1089218cfe4eSBorislav Petkov 				size++;
1090218cfe4eSBorislav Petkov 			}
1091218cfe4eSBorislav Petkov 		}
109236e1be8aSKim Phillips 		if (perf_ibs == &perf_ibs_fetch && (ibs_caps & IBS_CAPS_FETCHCTLEXTD)) {
109336e1be8aSKim Phillips 			rdmsrl(MSR_AMD64_ICIBSEXTDCTL, *buf++);
109436e1be8aSKim Phillips 			size++;
109536e1be8aSKim Phillips 		}
109636e1be8aSKim Phillips 	}
1097218cfe4eSBorislav Petkov 	ibs_data.size = sizeof(u64) * size;
1098218cfe4eSBorislav Petkov 
1099218cfe4eSBorislav Petkov 	regs = *iregs;
1100218cfe4eSBorislav Petkov 	if (check_rip && (ibs_data.regs[2] & IBS_RIP_INVALID)) {
1101218cfe4eSBorislav Petkov 		regs.flags &= ~PERF_EFLAGS_EXACT;
1102218cfe4eSBorislav Petkov 	} else {
110326db2e0cSKim Phillips 		/* Workaround for erratum #1197 */
110426db2e0cSKim Phillips 		if (perf_ibs->fetch_ignore_if_zero_rip && !(ibs_data.regs[1]))
110526db2e0cSKim Phillips 			goto out;
110626db2e0cSKim Phillips 
1107218cfe4eSBorislav Petkov 		set_linear_ip(&regs, ibs_data.regs[1]);
1108218cfe4eSBorislav Petkov 		regs.flags |= PERF_EFLAGS_EXACT;
1109218cfe4eSBorislav Petkov 	}
1110218cfe4eSBorislav Petkov 
1111218cfe4eSBorislav Petkov 	if (event->attr.sample_type & PERF_SAMPLE_RAW) {
11127e3f977eSDaniel Borkmann 		raw = (struct perf_raw_record){
11137e3f977eSDaniel Borkmann 			.frag = {
11147e3f977eSDaniel Borkmann 				.size = sizeof(u32) + ibs_data.size,
11157e3f977eSDaniel Borkmann 				.data = ibs_data.data,
11167e3f977eSDaniel Borkmann 			},
11177e3f977eSDaniel Borkmann 		};
1118*c0dbecb2SYabin Cui 		perf_sample_save_raw_data(&data, event, &raw);
1119218cfe4eSBorislav Petkov 	}
1120218cfe4eSBorislav Petkov 
11217c10dd0aSRavi Bangoria 	if (perf_ibs == &perf_ibs_op)
11227c10dd0aSRavi Bangoria 		perf_ibs_parse_ld_st_data(event->attr.sample_type, &ibs_data, &data);
11237c10dd0aSRavi Bangoria 
11243d47083bSRavi Bangoria 	/*
11253d47083bSRavi Bangoria 	 * rip recorded by IbsOpRip will not be consistent with rsp and rbp
11263d47083bSRavi Bangoria 	 * recorded as part of interrupt regs. Thus we need to use rip from
11273d47083bSRavi Bangoria 	 * interrupt regs while unwinding call stack.
11283d47083bSRavi Bangoria 	 */
112931046500SNamhyung Kim 	if (event->attr.sample_type & PERF_SAMPLE_CALLCHAIN)
113031046500SNamhyung Kim 		perf_sample_save_callchain(&data, event, iregs);
11313d47083bSRavi Bangoria 
1132218cfe4eSBorislav Petkov 	throttle = perf_event_overflow(event, &data, &regs);
1133218cfe4eSBorislav Petkov out:
11340f4cd769SKim Phillips 	if (throttle) {
11350158b83fSPeter Zijlstra 		perf_ibs_stop(event, 0);
11360f4cd769SKim Phillips 	} else {
11378b0bed7dSKim Phillips 		if (perf_ibs == &perf_ibs_op) {
11388b0bed7dSKim Phillips 			if (ibs_caps & IBS_CAPS_OPCNTEXT) {
11398b0bed7dSKim Phillips 				new_config = period & IBS_OP_MAX_CNT_EXT_MASK;
11408b0bed7dSKim Phillips 				period &= ~IBS_OP_MAX_CNT_EXT_MASK;
11418b0bed7dSKim Phillips 			}
11428b0bed7dSKim Phillips 			if ((ibs_caps & IBS_CAPS_RDWROPCNT) && (*config & IBS_OP_CNT_CTL))
11438b0bed7dSKim Phillips 				new_config |= *config & IBS_OP_CUR_CNT_RAND;
11448b0bed7dSKim Phillips 		}
11458b0bed7dSKim Phillips 		new_config |= period >> 4;
11460f4cd769SKim Phillips 
11478b0bed7dSKim Phillips 		perf_ibs_enable_event(perf_ibs, hwc, new_config);
11480f4cd769SKim Phillips 	}
1149218cfe4eSBorislav Petkov 
1150218cfe4eSBorislav Petkov 	perf_event_update_userpage(event);
1151218cfe4eSBorislav Petkov 
1152218cfe4eSBorislav Petkov 	return 1;
1153218cfe4eSBorislav Petkov }
1154218cfe4eSBorislav Petkov 
1155218cfe4eSBorislav Petkov static int
perf_ibs_nmi_handler(unsigned int cmd,struct pt_regs * regs)1156218cfe4eSBorislav Petkov perf_ibs_nmi_handler(unsigned int cmd, struct pt_regs *regs)
1157218cfe4eSBorislav Petkov {
1158c2872d38SPeter Zijlstra 	u64 stamp = sched_clock();
1159218cfe4eSBorislav Petkov 	int handled = 0;
1160218cfe4eSBorislav Petkov 
1161218cfe4eSBorislav Petkov 	handled += perf_ibs_handle_irq(&perf_ibs_fetch, regs);
1162218cfe4eSBorislav Petkov 	handled += perf_ibs_handle_irq(&perf_ibs_op, regs);
1163218cfe4eSBorislav Petkov 
1164218cfe4eSBorislav Petkov 	if (handled)
1165218cfe4eSBorislav Petkov 		inc_irq_stat(apic_perf_irqs);
1166218cfe4eSBorislav Petkov 
1167c2872d38SPeter Zijlstra 	perf_sample_event_took(sched_clock() - stamp);
1168c2872d38SPeter Zijlstra 
1169218cfe4eSBorislav Petkov 	return handled;
1170218cfe4eSBorislav Petkov }
1171218cfe4eSBorislav Petkov NOKPROBE_SYMBOL(perf_ibs_nmi_handler);
1172218cfe4eSBorislav Petkov 
perf_ibs_pmu_init(struct perf_ibs * perf_ibs,char * name)1173218cfe4eSBorislav Petkov static __init int perf_ibs_pmu_init(struct perf_ibs *perf_ibs, char *name)
1174218cfe4eSBorislav Petkov {
1175218cfe4eSBorislav Petkov 	struct cpu_perf_ibs __percpu *pcpu;
1176218cfe4eSBorislav Petkov 	int ret;
1177218cfe4eSBorislav Petkov 
1178218cfe4eSBorislav Petkov 	pcpu = alloc_percpu(struct cpu_perf_ibs);
1179218cfe4eSBorislav Petkov 	if (!pcpu)
1180218cfe4eSBorislav Petkov 		return -ENOMEM;
1181218cfe4eSBorislav Petkov 
1182218cfe4eSBorislav Petkov 	perf_ibs->pcpu = pcpu;
1183218cfe4eSBorislav Petkov 
1184218cfe4eSBorislav Petkov 	ret = perf_pmu_register(&perf_ibs->pmu, name, -1);
1185218cfe4eSBorislav Petkov 	if (ret) {
1186218cfe4eSBorislav Petkov 		perf_ibs->pcpu = NULL;
1187218cfe4eSBorislav Petkov 		free_percpu(pcpu);
1188218cfe4eSBorislav Petkov 	}
1189218cfe4eSBorislav Petkov 
1190218cfe4eSBorislav Petkov 	return ret;
1191218cfe4eSBorislav Petkov }
1192218cfe4eSBorislav Petkov 
perf_ibs_fetch_init(void)1193ba5d35b4SRavi Bangoria static __init int perf_ibs_fetch_init(void)
1194218cfe4eSBorislav Petkov {
1195221bfce5SKim Phillips 	/*
1196221bfce5SKim Phillips 	 * Some chips fail to reset the fetch count when it is written; instead
1197221bfce5SKim Phillips 	 * they need a 0-1 transition of IbsFetchEn.
1198221bfce5SKim Phillips 	 */
1199221bfce5SKim Phillips 	if (boot_cpu_data.x86 >= 0x16 && boot_cpu_data.x86 <= 0x18)
1200221bfce5SKim Phillips 		perf_ibs_fetch.fetch_count_reset_broken = 1;
1201221bfce5SKim Phillips 
120226db2e0cSKim Phillips 	if (boot_cpu_data.x86 == 0x19 && boot_cpu_data.x86_model < 0x10)
120326db2e0cSKim Phillips 		perf_ibs_fetch.fetch_ignore_if_zero_rip = 1;
120426db2e0cSKim Phillips 
1205ba5d35b4SRavi Bangoria 	if (ibs_caps & IBS_CAPS_ZEN4)
1206ba5d35b4SRavi Bangoria 		perf_ibs_fetch.config_mask |= IBS_FETCH_L3MISSONLY;
1207ba5d35b4SRavi Bangoria 
12082a7a7e65SRavi Bangoria 	perf_ibs_fetch.pmu.attr_groups = fetch_attr_groups;
1209ba5d35b4SRavi Bangoria 	perf_ibs_fetch.pmu.attr_update = fetch_attr_update;
12102a7a7e65SRavi Bangoria 
1211ba5d35b4SRavi Bangoria 	return perf_ibs_pmu_init(&perf_ibs_fetch, "ibs_fetch");
1212ba5d35b4SRavi Bangoria }
1213218cfe4eSBorislav Petkov 
perf_ibs_op_init(void)1214ba5d35b4SRavi Bangoria static __init int perf_ibs_op_init(void)
1215ba5d35b4SRavi Bangoria {
12162a7a7e65SRavi Bangoria 	if (ibs_caps & IBS_CAPS_OPCNT)
1217218cfe4eSBorislav Petkov 		perf_ibs_op.config_mask |= IBS_OP_CNT_CTL;
12188b0bed7dSKim Phillips 
12198b0bed7dSKim Phillips 	if (ibs_caps & IBS_CAPS_OPCNTEXT) {
12208b0bed7dSKim Phillips 		perf_ibs_op.max_period  |= IBS_OP_MAX_CNT_EXT_MASK;
12218b0bed7dSKim Phillips 		perf_ibs_op.config_mask	|= IBS_OP_MAX_CNT_EXT_MASK;
12228b0bed7dSKim Phillips 		perf_ibs_op.cnt_mask    |= IBS_OP_MAX_CNT_EXT_MASK;
12238b0bed7dSKim Phillips 	}
12248b0bed7dSKim Phillips 
1225ba5d35b4SRavi Bangoria 	if (ibs_caps & IBS_CAPS_ZEN4)
1226ba5d35b4SRavi Bangoria 		perf_ibs_op.config_mask |= IBS_OP_L3MISSONLY;
1227ba5d35b4SRavi Bangoria 
12282a7a7e65SRavi Bangoria 	perf_ibs_op.pmu.attr_groups = empty_attr_groups;
12292a7a7e65SRavi Bangoria 	perf_ibs_op.pmu.attr_update = op_attr_update;
12302a7a7e65SRavi Bangoria 
1231ba5d35b4SRavi Bangoria 	return perf_ibs_pmu_init(&perf_ibs_op, "ibs_op");
1232ba5d35b4SRavi Bangoria }
1233ba5d35b4SRavi Bangoria 
perf_event_ibs_init(void)1234ba5d35b4SRavi Bangoria static __init int perf_event_ibs_init(void)
1235ba5d35b4SRavi Bangoria {
1236ba5d35b4SRavi Bangoria 	int ret;
1237ba5d35b4SRavi Bangoria 
1238ba5d35b4SRavi Bangoria 	ret = perf_ibs_fetch_init();
1239ba5d35b4SRavi Bangoria 	if (ret)
1240ba5d35b4SRavi Bangoria 		return ret;
1241ba5d35b4SRavi Bangoria 
1242ba5d35b4SRavi Bangoria 	ret = perf_ibs_op_init();
124339b2ca75SRavi Bangoria 	if (ret)
124439b2ca75SRavi Bangoria 		goto err_op;
1245218cfe4eSBorislav Petkov 
124639b2ca75SRavi Bangoria 	ret = register_nmi_handler(NMI_LOCAL, perf_ibs_nmi_handler, 0, "perf_ibs");
124739b2ca75SRavi Bangoria 	if (ret)
124839b2ca75SRavi Bangoria 		goto err_nmi;
124939b2ca75SRavi Bangoria 
1250218cfe4eSBorislav Petkov 	pr_info("perf: AMD IBS detected (0x%08x)\n", ibs_caps);
125139b2ca75SRavi Bangoria 	return 0;
125239b2ca75SRavi Bangoria 
125339b2ca75SRavi Bangoria err_nmi:
125439b2ca75SRavi Bangoria 	perf_pmu_unregister(&perf_ibs_op.pmu);
125539b2ca75SRavi Bangoria 	free_percpu(perf_ibs_op.pcpu);
125639b2ca75SRavi Bangoria 	perf_ibs_op.pcpu = NULL;
125739b2ca75SRavi Bangoria err_op:
125839b2ca75SRavi Bangoria 	perf_pmu_unregister(&perf_ibs_fetch.pmu);
125939b2ca75SRavi Bangoria 	free_percpu(perf_ibs_fetch.pcpu);
126039b2ca75SRavi Bangoria 	perf_ibs_fetch.pcpu = NULL;
126139b2ca75SRavi Bangoria 
126239b2ca75SRavi Bangoria 	return ret;
1263218cfe4eSBorislav Petkov }
1264218cfe4eSBorislav Petkov 
1265218cfe4eSBorislav Petkov #else /* defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_AMD) */
1266218cfe4eSBorislav Petkov 
perf_event_ibs_init(void)126739b2ca75SRavi Bangoria static __init int perf_event_ibs_init(void)
126839b2ca75SRavi Bangoria {
126939b2ca75SRavi Bangoria 	return 0;
127039b2ca75SRavi Bangoria }
1271218cfe4eSBorislav Petkov 
1272218cfe4eSBorislav Petkov #endif
1273218cfe4eSBorislav Petkov 
1274218cfe4eSBorislav Petkov /* IBS - apic initialization, for perf and oprofile */
1275218cfe4eSBorislav Petkov 
__get_ibs_caps(void)1276218cfe4eSBorislav Petkov static __init u32 __get_ibs_caps(void)
1277218cfe4eSBorislav Petkov {
1278218cfe4eSBorislav Petkov 	u32 caps;
1279218cfe4eSBorislav Petkov 	unsigned int max_level;
1280218cfe4eSBorislav Petkov 
1281218cfe4eSBorislav Petkov 	if (!boot_cpu_has(X86_FEATURE_IBS))
1282218cfe4eSBorislav Petkov 		return 0;
1283218cfe4eSBorislav Petkov 
1284218cfe4eSBorislav Petkov 	/* check IBS cpuid feature flags */
1285218cfe4eSBorislav Petkov 	max_level = cpuid_eax(0x80000000);
1286218cfe4eSBorislav Petkov 	if (max_level < IBS_CPUID_FEATURES)
1287218cfe4eSBorislav Petkov 		return IBS_CAPS_DEFAULT;
1288218cfe4eSBorislav Petkov 
1289218cfe4eSBorislav Petkov 	caps = cpuid_eax(IBS_CPUID_FEATURES);
1290218cfe4eSBorislav Petkov 	if (!(caps & IBS_CAPS_AVAIL))
1291218cfe4eSBorislav Petkov 		/* cpuid flags not valid */
1292218cfe4eSBorislav Petkov 		return IBS_CAPS_DEFAULT;
1293218cfe4eSBorislav Petkov 
1294218cfe4eSBorislav Petkov 	return caps;
1295218cfe4eSBorislav Petkov }
1296218cfe4eSBorislav Petkov 
get_ibs_caps(void)1297218cfe4eSBorislav Petkov u32 get_ibs_caps(void)
1298218cfe4eSBorislav Petkov {
1299218cfe4eSBorislav Petkov 	return ibs_caps;
1300218cfe4eSBorislav Petkov }
1301218cfe4eSBorislav Petkov 
1302218cfe4eSBorislav Petkov EXPORT_SYMBOL(get_ibs_caps);
1303218cfe4eSBorislav Petkov 
get_eilvt(int offset)1304218cfe4eSBorislav Petkov static inline int get_eilvt(int offset)
1305218cfe4eSBorislav Petkov {
1306218cfe4eSBorislav Petkov 	return !setup_APIC_eilvt(offset, 0, APIC_EILVT_MSG_NMI, 1);
1307218cfe4eSBorislav Petkov }
1308218cfe4eSBorislav Petkov 
put_eilvt(int offset)1309218cfe4eSBorislav Petkov static inline int put_eilvt(int offset)
1310218cfe4eSBorislav Petkov {
1311218cfe4eSBorislav Petkov 	return !setup_APIC_eilvt(offset, 0, 0, 1);
1312218cfe4eSBorislav Petkov }
1313218cfe4eSBorislav Petkov 
1314218cfe4eSBorislav Petkov /*
1315218cfe4eSBorislav Petkov  * Check and reserve APIC extended interrupt LVT offset for IBS if available.
1316218cfe4eSBorislav Petkov  */
ibs_eilvt_valid(void)1317218cfe4eSBorislav Petkov static inline int ibs_eilvt_valid(void)
1318218cfe4eSBorislav Petkov {
1319218cfe4eSBorislav Petkov 	int offset;
1320218cfe4eSBorislav Petkov 	u64 val;
1321218cfe4eSBorislav Petkov 	int valid = 0;
1322218cfe4eSBorislav Petkov 
1323218cfe4eSBorislav Petkov 	preempt_disable();
1324218cfe4eSBorislav Petkov 
1325218cfe4eSBorislav Petkov 	rdmsrl(MSR_AMD64_IBSCTL, val);
1326218cfe4eSBorislav Petkov 	offset = val & IBSCTL_LVT_OFFSET_MASK;
1327218cfe4eSBorislav Petkov 
1328218cfe4eSBorislav Petkov 	if (!(val & IBSCTL_LVT_OFFSET_VALID)) {
1329218cfe4eSBorislav Petkov 		pr_err(FW_BUG "cpu %d, invalid IBS interrupt offset %d (MSR%08X=0x%016llx)\n",
1330218cfe4eSBorislav Petkov 		       smp_processor_id(), offset, MSR_AMD64_IBSCTL, val);
1331218cfe4eSBorislav Petkov 		goto out;
1332218cfe4eSBorislav Petkov 	}
1333218cfe4eSBorislav Petkov 
1334218cfe4eSBorislav Petkov 	if (!get_eilvt(offset)) {
1335218cfe4eSBorislav Petkov 		pr_err(FW_BUG "cpu %d, IBS interrupt offset %d not available (MSR%08X=0x%016llx)\n",
1336218cfe4eSBorislav Petkov 		       smp_processor_id(), offset, MSR_AMD64_IBSCTL, val);
1337218cfe4eSBorislav Petkov 		goto out;
1338218cfe4eSBorislav Petkov 	}
1339218cfe4eSBorislav Petkov 
1340218cfe4eSBorislav Petkov 	valid = 1;
1341218cfe4eSBorislav Petkov out:
1342218cfe4eSBorislav Petkov 	preempt_enable();
1343218cfe4eSBorislav Petkov 
1344218cfe4eSBorislav Petkov 	return valid;
1345218cfe4eSBorislav Petkov }
1346218cfe4eSBorislav Petkov 
setup_ibs_ctl(int ibs_eilvt_off)1347218cfe4eSBorislav Petkov static int setup_ibs_ctl(int ibs_eilvt_off)
1348218cfe4eSBorislav Petkov {
1349218cfe4eSBorislav Petkov 	struct pci_dev *cpu_cfg;
1350218cfe4eSBorislav Petkov 	int nodes;
1351218cfe4eSBorislav Petkov 	u32 value = 0;
1352218cfe4eSBorislav Petkov 
1353218cfe4eSBorislav Petkov 	nodes = 0;
1354218cfe4eSBorislav Petkov 	cpu_cfg = NULL;
1355218cfe4eSBorislav Petkov 	do {
1356218cfe4eSBorislav Petkov 		cpu_cfg = pci_get_device(PCI_VENDOR_ID_AMD,
1357218cfe4eSBorislav Petkov 					 PCI_DEVICE_ID_AMD_10H_NB_MISC,
1358218cfe4eSBorislav Petkov 					 cpu_cfg);
1359218cfe4eSBorislav Petkov 		if (!cpu_cfg)
1360218cfe4eSBorislav Petkov 			break;
1361218cfe4eSBorislav Petkov 		++nodes;
1362218cfe4eSBorislav Petkov 		pci_write_config_dword(cpu_cfg, IBSCTL, ibs_eilvt_off
1363218cfe4eSBorislav Petkov 				       | IBSCTL_LVT_OFFSET_VALID);
1364218cfe4eSBorislav Petkov 		pci_read_config_dword(cpu_cfg, IBSCTL, &value);
1365218cfe4eSBorislav Petkov 		if (value != (ibs_eilvt_off | IBSCTL_LVT_OFFSET_VALID)) {
1366218cfe4eSBorislav Petkov 			pci_dev_put(cpu_cfg);
1367218cfe4eSBorislav Petkov 			pr_debug("Failed to setup IBS LVT offset, IBSCTL = 0x%08x\n",
1368218cfe4eSBorislav Petkov 				 value);
1369218cfe4eSBorislav Petkov 			return -EINVAL;
1370218cfe4eSBorislav Petkov 		}
1371218cfe4eSBorislav Petkov 	} while (1);
1372218cfe4eSBorislav Petkov 
1373218cfe4eSBorislav Petkov 	if (!nodes) {
1374218cfe4eSBorislav Petkov 		pr_debug("No CPU node configured for IBS\n");
1375218cfe4eSBorislav Petkov 		return -ENODEV;
1376218cfe4eSBorislav Petkov 	}
1377218cfe4eSBorislav Petkov 
1378218cfe4eSBorislav Petkov 	return 0;
1379218cfe4eSBorislav Petkov }
1380218cfe4eSBorislav Petkov 
1381218cfe4eSBorislav Petkov /*
1382218cfe4eSBorislav Petkov  * This runs only on the current cpu. We try to find an LVT offset and
1383218cfe4eSBorislav Petkov  * setup the local APIC. For this we must disable preemption. On
1384218cfe4eSBorislav Petkov  * success we initialize all nodes with this offset. This updates then
1385218cfe4eSBorislav Petkov  * the offset in the IBS_CTL per-node msr. The per-core APIC setup of
1386218cfe4eSBorislav Petkov  * the IBS interrupt vector is handled by perf_ibs_cpu_notifier that
1387218cfe4eSBorislav Petkov  * is using the new offset.
1388218cfe4eSBorislav Petkov  */
force_ibs_eilvt_setup(void)1389218cfe4eSBorislav Petkov static void force_ibs_eilvt_setup(void)
1390218cfe4eSBorislav Petkov {
1391218cfe4eSBorislav Petkov 	int offset;
1392218cfe4eSBorislav Petkov 	int ret;
1393218cfe4eSBorislav Petkov 
1394218cfe4eSBorislav Petkov 	preempt_disable();
1395218cfe4eSBorislav Petkov 	/* find the next free available EILVT entry, skip offset 0 */
1396218cfe4eSBorislav Petkov 	for (offset = 1; offset < APIC_EILVT_NR_MAX; offset++) {
1397218cfe4eSBorislav Petkov 		if (get_eilvt(offset))
1398218cfe4eSBorislav Petkov 			break;
1399218cfe4eSBorislav Petkov 	}
1400218cfe4eSBorislav Petkov 	preempt_enable();
1401218cfe4eSBorislav Petkov 
1402218cfe4eSBorislav Petkov 	if (offset == APIC_EILVT_NR_MAX) {
1403218cfe4eSBorislav Petkov 		pr_debug("No EILVT entry available\n");
1404218cfe4eSBorislav Petkov 		return;
1405218cfe4eSBorislav Petkov 	}
1406218cfe4eSBorislav Petkov 
1407218cfe4eSBorislav Petkov 	ret = setup_ibs_ctl(offset);
1408218cfe4eSBorislav Petkov 	if (ret)
1409218cfe4eSBorislav Petkov 		goto out;
1410218cfe4eSBorislav Petkov 
1411218cfe4eSBorislav Petkov 	if (!ibs_eilvt_valid())
1412218cfe4eSBorislav Petkov 		goto out;
1413218cfe4eSBorislav Petkov 
14141de392f5SJoe Perches 	pr_info("LVT offset %d assigned\n", offset);
1415218cfe4eSBorislav Petkov 
1416218cfe4eSBorislav Petkov 	return;
1417218cfe4eSBorislav Petkov out:
1418218cfe4eSBorislav Petkov 	preempt_disable();
1419218cfe4eSBorislav Petkov 	put_eilvt(offset);
1420218cfe4eSBorislav Petkov 	preempt_enable();
1421218cfe4eSBorislav Petkov 	return;
1422218cfe4eSBorislav Petkov }
1423218cfe4eSBorislav Petkov 
ibs_eilvt_setup(void)1424218cfe4eSBorislav Petkov static void ibs_eilvt_setup(void)
1425218cfe4eSBorislav Petkov {
1426218cfe4eSBorislav Petkov 	/*
1427218cfe4eSBorislav Petkov 	 * Force LVT offset assignment for family 10h: The offsets are
1428218cfe4eSBorislav Petkov 	 * not assigned by the BIOS for this family, so the OS is
1429218cfe4eSBorislav Petkov 	 * responsible for doing it. If the OS assignment fails, fall
1430218cfe4eSBorislav Petkov 	 * back to BIOS settings and try to setup this.
1431218cfe4eSBorislav Petkov 	 */
1432218cfe4eSBorislav Petkov 	if (boot_cpu_data.x86 == 0x10)
1433218cfe4eSBorislav Petkov 		force_ibs_eilvt_setup();
1434218cfe4eSBorislav Petkov }
1435218cfe4eSBorislav Petkov 
get_ibs_lvt_offset(void)1436218cfe4eSBorislav Petkov static inline int get_ibs_lvt_offset(void)
1437218cfe4eSBorislav Petkov {
1438218cfe4eSBorislav Petkov 	u64 val;
1439218cfe4eSBorislav Petkov 
1440218cfe4eSBorislav Petkov 	rdmsrl(MSR_AMD64_IBSCTL, val);
1441218cfe4eSBorislav Petkov 	if (!(val & IBSCTL_LVT_OFFSET_VALID))
1442218cfe4eSBorislav Petkov 		return -EINVAL;
1443218cfe4eSBorislav Petkov 
1444218cfe4eSBorislav Petkov 	return val & IBSCTL_LVT_OFFSET_MASK;
1445218cfe4eSBorislav Petkov }
1446218cfe4eSBorislav Petkov 
setup_APIC_ibs(void)14479744f7b7SThomas Gleixner static void setup_APIC_ibs(void)
1448218cfe4eSBorislav Petkov {
1449218cfe4eSBorislav Petkov 	int offset;
1450218cfe4eSBorislav Petkov 
1451218cfe4eSBorislav Petkov 	offset = get_ibs_lvt_offset();
1452218cfe4eSBorislav Petkov 	if (offset < 0)
1453218cfe4eSBorislav Petkov 		goto failed;
1454218cfe4eSBorislav Petkov 
1455218cfe4eSBorislav Petkov 	if (!setup_APIC_eilvt(offset, 0, APIC_EILVT_MSG_NMI, 0))
1456218cfe4eSBorislav Petkov 		return;
1457218cfe4eSBorislav Petkov failed:
1458218cfe4eSBorislav Petkov 	pr_warn("perf: IBS APIC setup failed on cpu #%d\n",
1459218cfe4eSBorislav Petkov 		smp_processor_id());
1460218cfe4eSBorislav Petkov }
1461218cfe4eSBorislav Petkov 
clear_APIC_ibs(void)14629744f7b7SThomas Gleixner static void clear_APIC_ibs(void)
1463218cfe4eSBorislav Petkov {
1464218cfe4eSBorislav Petkov 	int offset;
1465218cfe4eSBorislav Petkov 
1466218cfe4eSBorislav Petkov 	offset = get_ibs_lvt_offset();
1467218cfe4eSBorislav Petkov 	if (offset >= 0)
1468218cfe4eSBorislav Petkov 		setup_APIC_eilvt(offset, 0, APIC_EILVT_MSG_FIX, 1);
1469218cfe4eSBorislav Petkov }
1470218cfe4eSBorislav Petkov 
x86_pmu_amd_ibs_starting_cpu(unsigned int cpu)14719744f7b7SThomas Gleixner static int x86_pmu_amd_ibs_starting_cpu(unsigned int cpu)
14729744f7b7SThomas Gleixner {
14739744f7b7SThomas Gleixner 	setup_APIC_ibs();
14749744f7b7SThomas Gleixner 	return 0;
14759744f7b7SThomas Gleixner }
14769744f7b7SThomas Gleixner 
1477218cfe4eSBorislav Petkov #ifdef CONFIG_PM
1478218cfe4eSBorislav Petkov 
perf_ibs_suspend(void)1479218cfe4eSBorislav Petkov static int perf_ibs_suspend(void)
1480218cfe4eSBorislav Petkov {
14819744f7b7SThomas Gleixner 	clear_APIC_ibs();
1482218cfe4eSBorislav Petkov 	return 0;
1483218cfe4eSBorislav Petkov }
1484218cfe4eSBorislav Petkov 
perf_ibs_resume(void)1485218cfe4eSBorislav Petkov static void perf_ibs_resume(void)
1486218cfe4eSBorislav Petkov {
1487218cfe4eSBorislav Petkov 	ibs_eilvt_setup();
14889744f7b7SThomas Gleixner 	setup_APIC_ibs();
1489218cfe4eSBorislav Petkov }
1490218cfe4eSBorislav Petkov 
1491218cfe4eSBorislav Petkov static struct syscore_ops perf_ibs_syscore_ops = {
1492218cfe4eSBorislav Petkov 	.resume		= perf_ibs_resume,
1493218cfe4eSBorislav Petkov 	.suspend	= perf_ibs_suspend,
1494218cfe4eSBorislav Petkov };
1495218cfe4eSBorislav Petkov 
perf_ibs_pm_init(void)1496218cfe4eSBorislav Petkov static void perf_ibs_pm_init(void)
1497218cfe4eSBorislav Petkov {
1498218cfe4eSBorislav Petkov 	register_syscore_ops(&perf_ibs_syscore_ops);
1499218cfe4eSBorislav Petkov }
1500218cfe4eSBorislav Petkov 
1501218cfe4eSBorislav Petkov #else
1502218cfe4eSBorislav Petkov 
perf_ibs_pm_init(void)1503218cfe4eSBorislav Petkov static inline void perf_ibs_pm_init(void) { }
1504218cfe4eSBorislav Petkov 
1505218cfe4eSBorislav Petkov #endif
1506218cfe4eSBorislav Petkov 
x86_pmu_amd_ibs_dying_cpu(unsigned int cpu)15079744f7b7SThomas Gleixner static int x86_pmu_amd_ibs_dying_cpu(unsigned int cpu)
1508218cfe4eSBorislav Petkov {
15099744f7b7SThomas Gleixner 	clear_APIC_ibs();
15109744f7b7SThomas Gleixner 	return 0;
1511218cfe4eSBorislav Petkov }
1512218cfe4eSBorislav Petkov 
amd_ibs_init(void)1513218cfe4eSBorislav Petkov static __init int amd_ibs_init(void)
1514218cfe4eSBorislav Petkov {
1515218cfe4eSBorislav Petkov 	u32 caps;
1516218cfe4eSBorislav Petkov 
1517218cfe4eSBorislav Petkov 	caps = __get_ibs_caps();
1518218cfe4eSBorislav Petkov 	if (!caps)
1519218cfe4eSBorislav Petkov 		return -ENODEV;	/* ibs not supported by the cpu */
1520218cfe4eSBorislav Petkov 
1521218cfe4eSBorislav Petkov 	ibs_eilvt_setup();
1522218cfe4eSBorislav Petkov 
1523218cfe4eSBorislav Petkov 	if (!ibs_eilvt_valid())
15249744f7b7SThomas Gleixner 		return -EINVAL;
1525218cfe4eSBorislav Petkov 
1526218cfe4eSBorislav Petkov 	perf_ibs_pm_init();
15279744f7b7SThomas Gleixner 
1528218cfe4eSBorislav Petkov 	ibs_caps = caps;
1529218cfe4eSBorislav Petkov 	/* make ibs_caps visible to other cpus: */
1530218cfe4eSBorislav Petkov 	smp_mb();
15319744f7b7SThomas Gleixner 	/*
15329744f7b7SThomas Gleixner 	 * x86_pmu_amd_ibs_starting_cpu will be called from core on
15339744f7b7SThomas Gleixner 	 * all online cpus.
15349744f7b7SThomas Gleixner 	 */
15359744f7b7SThomas Gleixner 	cpuhp_setup_state(CPUHP_AP_PERF_X86_AMD_IBS_STARTING,
15367e164ce4SSedat Dilek 			  "perf/x86/amd/ibs:starting",
15379744f7b7SThomas Gleixner 			  x86_pmu_amd_ibs_starting_cpu,
15389744f7b7SThomas Gleixner 			  x86_pmu_amd_ibs_dying_cpu);
1539218cfe4eSBorislav Petkov 
154039b2ca75SRavi Bangoria 	return perf_event_ibs_init();
1541218cfe4eSBorislav Petkov }
1542218cfe4eSBorislav Petkov 
1543218cfe4eSBorislav Petkov /* Since we need the pci subsystem to init ibs we can't do this earlier: */
1544218cfe4eSBorislav Petkov device_initcall(amd_ibs_init);
1545