xref: /openbmc/linux/arch/x86/events/zhaoxin/core.c (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
13a4ac121SCodyYao-oc // SPDX-License-Identifier: GPL-2.0-only
23a4ac121SCodyYao-oc /*
32ac5413eSHu Haowen  * Zhaoxin PMU; like Intel Architectural PerfMon-v2
43a4ac121SCodyYao-oc  */
53a4ac121SCodyYao-oc 
63a4ac121SCodyYao-oc #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
73a4ac121SCodyYao-oc 
83a4ac121SCodyYao-oc #include <linux/stddef.h>
93a4ac121SCodyYao-oc #include <linux/types.h>
103a4ac121SCodyYao-oc #include <linux/init.h>
113a4ac121SCodyYao-oc #include <linux/slab.h>
123a4ac121SCodyYao-oc #include <linux/export.h>
133a4ac121SCodyYao-oc #include <linux/nmi.h>
143a4ac121SCodyYao-oc 
153a4ac121SCodyYao-oc #include <asm/cpufeature.h>
163a4ac121SCodyYao-oc #include <asm/hardirq.h>
173a4ac121SCodyYao-oc #include <asm/apic.h>
183a4ac121SCodyYao-oc 
193a4ac121SCodyYao-oc #include "../perf_event.h"
203a4ac121SCodyYao-oc 
213a4ac121SCodyYao-oc /*
223a4ac121SCodyYao-oc  * Zhaoxin PerfMon, used on zxc and later.
233a4ac121SCodyYao-oc  */
243a4ac121SCodyYao-oc static u64 zx_pmon_event_map[PERF_COUNT_HW_MAX] __read_mostly = {
253a4ac121SCodyYao-oc 
263a4ac121SCodyYao-oc 	[PERF_COUNT_HW_CPU_CYCLES]        = 0x0082,
273a4ac121SCodyYao-oc 	[PERF_COUNT_HW_INSTRUCTIONS]      = 0x00c0,
283a4ac121SCodyYao-oc 	[PERF_COUNT_HW_CACHE_REFERENCES]  = 0x0515,
293a4ac121SCodyYao-oc 	[PERF_COUNT_HW_CACHE_MISSES]      = 0x051a,
303a4ac121SCodyYao-oc 	[PERF_COUNT_HW_BUS_CYCLES]        = 0x0083,
313a4ac121SCodyYao-oc };
323a4ac121SCodyYao-oc 
333a4ac121SCodyYao-oc static struct event_constraint zxc_event_constraints[] __read_mostly = {
343a4ac121SCodyYao-oc 
353a4ac121SCodyYao-oc 	FIXED_EVENT_CONSTRAINT(0x0082, 1), /* unhalted core clock cycles */
363a4ac121SCodyYao-oc 	EVENT_CONSTRAINT_END
373a4ac121SCodyYao-oc };
383a4ac121SCodyYao-oc 
393a4ac121SCodyYao-oc static struct event_constraint zxd_event_constraints[] __read_mostly = {
403a4ac121SCodyYao-oc 
413a4ac121SCodyYao-oc 	FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* retired instructions */
423a4ac121SCodyYao-oc 	FIXED_EVENT_CONSTRAINT(0x0082, 1), /* unhalted core clock cycles */
433a4ac121SCodyYao-oc 	FIXED_EVENT_CONSTRAINT(0x0083, 2), /* unhalted bus clock cycles */
443a4ac121SCodyYao-oc 	EVENT_CONSTRAINT_END
453a4ac121SCodyYao-oc };
463a4ac121SCodyYao-oc 
473a4ac121SCodyYao-oc static __initconst const u64 zxd_hw_cache_event_ids
483a4ac121SCodyYao-oc 				[PERF_COUNT_HW_CACHE_MAX]
493a4ac121SCodyYao-oc 				[PERF_COUNT_HW_CACHE_OP_MAX]
503a4ac121SCodyYao-oc 				[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
513a4ac121SCodyYao-oc [C(L1D)] = {
523a4ac121SCodyYao-oc 	[C(OP_READ)] = {
533a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = 0x0042,
543a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = 0x0538,
553a4ac121SCodyYao-oc 	},
563a4ac121SCodyYao-oc 	[C(OP_WRITE)] = {
573a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = 0x0043,
583a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = 0x0562,
593a4ac121SCodyYao-oc 	},
603a4ac121SCodyYao-oc 	[C(OP_PREFETCH)] = {
613a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = -1,
623a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = -1,
633a4ac121SCodyYao-oc 	},
643a4ac121SCodyYao-oc },
653a4ac121SCodyYao-oc [C(L1I)] = {
663a4ac121SCodyYao-oc 	[C(OP_READ)] = {
673a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = 0x0300,
683a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = 0x0301,
693a4ac121SCodyYao-oc 	},
703a4ac121SCodyYao-oc 	[C(OP_WRITE)] = {
713a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = -1,
723a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = -1,
733a4ac121SCodyYao-oc 	},
743a4ac121SCodyYao-oc 	[C(OP_PREFETCH)] = {
753a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = 0x030a,
763a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = 0x030b,
773a4ac121SCodyYao-oc 	},
783a4ac121SCodyYao-oc },
793a4ac121SCodyYao-oc [C(LL)] = {
803a4ac121SCodyYao-oc 	[C(OP_READ)] = {
813a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = -1,
823a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = -1,
833a4ac121SCodyYao-oc 	},
843a4ac121SCodyYao-oc 	[C(OP_WRITE)] = {
853a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = -1,
863a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = -1,
873a4ac121SCodyYao-oc 	},
883a4ac121SCodyYao-oc 	[C(OP_PREFETCH)] = {
893a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = -1,
903a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = -1,
913a4ac121SCodyYao-oc 	},
923a4ac121SCodyYao-oc },
933a4ac121SCodyYao-oc [C(DTLB)] = {
943a4ac121SCodyYao-oc 	[C(OP_READ)] = {
953a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = 0x0042,
963a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = 0x052c,
973a4ac121SCodyYao-oc 	},
983a4ac121SCodyYao-oc 	[C(OP_WRITE)] = {
993a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = 0x0043,
1003a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = 0x0530,
1013a4ac121SCodyYao-oc 	},
1023a4ac121SCodyYao-oc 	[C(OP_PREFETCH)] = {
1033a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = 0x0564,
1043a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = 0x0565,
1053a4ac121SCodyYao-oc 	},
1063a4ac121SCodyYao-oc },
1073a4ac121SCodyYao-oc [C(ITLB)] = {
1083a4ac121SCodyYao-oc 	[C(OP_READ)] = {
1093a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = 0x00c0,
1103a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = 0x0534,
1113a4ac121SCodyYao-oc 	},
1123a4ac121SCodyYao-oc 	[C(OP_WRITE)] = {
1133a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = -1,
1143a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = -1,
1153a4ac121SCodyYao-oc 	},
1163a4ac121SCodyYao-oc 	[C(OP_PREFETCH)] = {
1173a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = -1,
1183a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = -1,
1193a4ac121SCodyYao-oc 	},
1203a4ac121SCodyYao-oc },
1213a4ac121SCodyYao-oc [C(BPU)] = {
1223a4ac121SCodyYao-oc 	[C(OP_READ)] = {
1233a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = 0x0700,
1243a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = 0x0709,
1253a4ac121SCodyYao-oc 	},
1263a4ac121SCodyYao-oc 	[C(OP_WRITE)] = {
1273a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = -1,
1283a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = -1,
1293a4ac121SCodyYao-oc 	},
1303a4ac121SCodyYao-oc 	[C(OP_PREFETCH)] = {
1313a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = -1,
1323a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = -1,
1333a4ac121SCodyYao-oc 	},
1343a4ac121SCodyYao-oc },
1353a4ac121SCodyYao-oc [C(NODE)] = {
1363a4ac121SCodyYao-oc 	[C(OP_READ)] = {
1373a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = -1,
1383a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = -1,
1393a4ac121SCodyYao-oc 	},
1403a4ac121SCodyYao-oc 	[C(OP_WRITE)] = {
1413a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = -1,
1423a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = -1,
1433a4ac121SCodyYao-oc 	},
1443a4ac121SCodyYao-oc 	[C(OP_PREFETCH)] = {
1453a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = -1,
1463a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = -1,
1473a4ac121SCodyYao-oc 	},
1483a4ac121SCodyYao-oc },
1493a4ac121SCodyYao-oc };
1503a4ac121SCodyYao-oc 
1513a4ac121SCodyYao-oc static __initconst const u64 zxe_hw_cache_event_ids
1523a4ac121SCodyYao-oc 				[PERF_COUNT_HW_CACHE_MAX]
1533a4ac121SCodyYao-oc 				[PERF_COUNT_HW_CACHE_OP_MAX]
1543a4ac121SCodyYao-oc 				[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
1553a4ac121SCodyYao-oc [C(L1D)] = {
1563a4ac121SCodyYao-oc 	[C(OP_READ)] = {
1573a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = 0x0568,
1583a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = 0x054b,
1593a4ac121SCodyYao-oc 	},
1603a4ac121SCodyYao-oc 	[C(OP_WRITE)] = {
1613a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = 0x0669,
1623a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = 0x0562,
1633a4ac121SCodyYao-oc 	},
1643a4ac121SCodyYao-oc 	[C(OP_PREFETCH)] = {
1653a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = -1,
1663a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = -1,
1673a4ac121SCodyYao-oc 	},
1683a4ac121SCodyYao-oc },
1693a4ac121SCodyYao-oc [C(L1I)] = {
1703a4ac121SCodyYao-oc 	[C(OP_READ)] = {
1713a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = 0x0300,
1723a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = 0x0301,
1733a4ac121SCodyYao-oc 	},
1743a4ac121SCodyYao-oc 	[C(OP_WRITE)] = {
1753a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = -1,
1763a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = -1,
1773a4ac121SCodyYao-oc 	},
1783a4ac121SCodyYao-oc 	[C(OP_PREFETCH)] = {
1793a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = 0x030a,
1803a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = 0x030b,
1813a4ac121SCodyYao-oc 	},
1823a4ac121SCodyYao-oc },
1833a4ac121SCodyYao-oc [C(LL)] = {
1843a4ac121SCodyYao-oc 	[C(OP_READ)] = {
1853a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = 0x0,
1863a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = 0x0,
1873a4ac121SCodyYao-oc 	},
1883a4ac121SCodyYao-oc 	[C(OP_WRITE)] = {
1893a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = 0x0,
1903a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = 0x0,
1913a4ac121SCodyYao-oc 	},
1923a4ac121SCodyYao-oc 	[C(OP_PREFETCH)] = {
1933a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = 0x0,
1943a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = 0x0,
1953a4ac121SCodyYao-oc 	},
1963a4ac121SCodyYao-oc },
1973a4ac121SCodyYao-oc [C(DTLB)] = {
1983a4ac121SCodyYao-oc 	[C(OP_READ)] = {
1993a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = 0x0568,
2003a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = 0x052c,
2013a4ac121SCodyYao-oc 	},
2023a4ac121SCodyYao-oc 	[C(OP_WRITE)] = {
2033a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = 0x0669,
2043a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = 0x0530,
2053a4ac121SCodyYao-oc 	},
2063a4ac121SCodyYao-oc 	[C(OP_PREFETCH)] = {
2073a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = 0x0564,
2083a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = 0x0565,
2093a4ac121SCodyYao-oc 	},
2103a4ac121SCodyYao-oc },
2113a4ac121SCodyYao-oc [C(ITLB)] = {
2123a4ac121SCodyYao-oc 	[C(OP_READ)] = {
2133a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = 0x00c0,
2143a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = 0x0534,
2153a4ac121SCodyYao-oc 	},
2163a4ac121SCodyYao-oc 	[C(OP_WRITE)] = {
2173a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = -1,
2183a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = -1,
2193a4ac121SCodyYao-oc 	},
2203a4ac121SCodyYao-oc 	[C(OP_PREFETCH)] = {
2213a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = -1,
2223a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = -1,
2233a4ac121SCodyYao-oc 	},
2243a4ac121SCodyYao-oc },
2253a4ac121SCodyYao-oc [C(BPU)] = {
2263a4ac121SCodyYao-oc 	[C(OP_READ)] = {
2273a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = 0x0028,
2283a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = 0x0029,
2293a4ac121SCodyYao-oc 	},
2303a4ac121SCodyYao-oc 	[C(OP_WRITE)] = {
2313a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = -1,
2323a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = -1,
2333a4ac121SCodyYao-oc 	},
2343a4ac121SCodyYao-oc 	[C(OP_PREFETCH)] = {
2353a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = -1,
2363a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = -1,
2373a4ac121SCodyYao-oc 	},
2383a4ac121SCodyYao-oc },
2393a4ac121SCodyYao-oc [C(NODE)] = {
2403a4ac121SCodyYao-oc 	[C(OP_READ)] = {
2413a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = -1,
2423a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = -1,
2433a4ac121SCodyYao-oc 	},
2443a4ac121SCodyYao-oc 	[C(OP_WRITE)] = {
2453a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = -1,
2463a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = -1,
2473a4ac121SCodyYao-oc 	},
2483a4ac121SCodyYao-oc 	[C(OP_PREFETCH)] = {
2493a4ac121SCodyYao-oc 		[C(RESULT_ACCESS)] = -1,
2503a4ac121SCodyYao-oc 		[C(RESULT_MISS)] = -1,
2513a4ac121SCodyYao-oc 	},
2523a4ac121SCodyYao-oc },
2533a4ac121SCodyYao-oc };
2543a4ac121SCodyYao-oc 
zhaoxin_pmu_disable_all(void)2553a4ac121SCodyYao-oc static void zhaoxin_pmu_disable_all(void)
2563a4ac121SCodyYao-oc {
2573a4ac121SCodyYao-oc 	wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0);
2583a4ac121SCodyYao-oc }
2593a4ac121SCodyYao-oc 
zhaoxin_pmu_enable_all(int added)2603a4ac121SCodyYao-oc static void zhaoxin_pmu_enable_all(int added)
2613a4ac121SCodyYao-oc {
2623a4ac121SCodyYao-oc 	wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, x86_pmu.intel_ctrl);
2633a4ac121SCodyYao-oc }
2643a4ac121SCodyYao-oc 
zhaoxin_pmu_get_status(void)2653a4ac121SCodyYao-oc static inline u64 zhaoxin_pmu_get_status(void)
2663a4ac121SCodyYao-oc {
2673a4ac121SCodyYao-oc 	u64 status;
2683a4ac121SCodyYao-oc 
2693a4ac121SCodyYao-oc 	rdmsrl(MSR_CORE_PERF_GLOBAL_STATUS, status);
2703a4ac121SCodyYao-oc 
2713a4ac121SCodyYao-oc 	return status;
2723a4ac121SCodyYao-oc }
2733a4ac121SCodyYao-oc 
zhaoxin_pmu_ack_status(u64 ack)2743a4ac121SCodyYao-oc static inline void zhaoxin_pmu_ack_status(u64 ack)
2753a4ac121SCodyYao-oc {
2763a4ac121SCodyYao-oc 	wrmsrl(MSR_CORE_PERF_GLOBAL_OVF_CTRL, ack);
2773a4ac121SCodyYao-oc }
2783a4ac121SCodyYao-oc 
zxc_pmu_ack_status(u64 ack)2793a4ac121SCodyYao-oc static inline void zxc_pmu_ack_status(u64 ack)
2803a4ac121SCodyYao-oc {
2813a4ac121SCodyYao-oc 	/*
2823a4ac121SCodyYao-oc 	 * ZXC needs global control enabled in order to clear status bits.
2833a4ac121SCodyYao-oc 	 */
2843a4ac121SCodyYao-oc 	zhaoxin_pmu_enable_all(0);
2853a4ac121SCodyYao-oc 	zhaoxin_pmu_ack_status(ack);
2863a4ac121SCodyYao-oc 	zhaoxin_pmu_disable_all();
2873a4ac121SCodyYao-oc }
2883a4ac121SCodyYao-oc 
zhaoxin_pmu_disable_fixed(struct hw_perf_event * hwc)2893a4ac121SCodyYao-oc static void zhaoxin_pmu_disable_fixed(struct hw_perf_event *hwc)
2903a4ac121SCodyYao-oc {
2913a4ac121SCodyYao-oc 	int idx = hwc->idx - INTEL_PMC_IDX_FIXED;
2923a4ac121SCodyYao-oc 	u64 ctrl_val, mask;
2933a4ac121SCodyYao-oc 
2943a4ac121SCodyYao-oc 	mask = 0xfULL << (idx * 4);
2953a4ac121SCodyYao-oc 
2963a4ac121SCodyYao-oc 	rdmsrl(hwc->config_base, ctrl_val);
2973a4ac121SCodyYao-oc 	ctrl_val &= ~mask;
2983a4ac121SCodyYao-oc 	wrmsrl(hwc->config_base, ctrl_val);
2993a4ac121SCodyYao-oc }
3003a4ac121SCodyYao-oc 
zhaoxin_pmu_disable_event(struct perf_event * event)3013a4ac121SCodyYao-oc static void zhaoxin_pmu_disable_event(struct perf_event *event)
3023a4ac121SCodyYao-oc {
3033a4ac121SCodyYao-oc 	struct hw_perf_event *hwc = &event->hw;
3043a4ac121SCodyYao-oc 
3053a4ac121SCodyYao-oc 	if (unlikely(hwc->config_base == MSR_ARCH_PERFMON_FIXED_CTR_CTRL)) {
3063a4ac121SCodyYao-oc 		zhaoxin_pmu_disable_fixed(hwc);
3073a4ac121SCodyYao-oc 		return;
3083a4ac121SCodyYao-oc 	}
3093a4ac121SCodyYao-oc 
3103a4ac121SCodyYao-oc 	x86_pmu_disable_event(event);
3113a4ac121SCodyYao-oc }
3123a4ac121SCodyYao-oc 
zhaoxin_pmu_enable_fixed(struct hw_perf_event * hwc)3133a4ac121SCodyYao-oc static void zhaoxin_pmu_enable_fixed(struct hw_perf_event *hwc)
3143a4ac121SCodyYao-oc {
3153a4ac121SCodyYao-oc 	int idx = hwc->idx - INTEL_PMC_IDX_FIXED;
3163a4ac121SCodyYao-oc 	u64 ctrl_val, bits, mask;
3173a4ac121SCodyYao-oc 
3183a4ac121SCodyYao-oc 	/*
3193a4ac121SCodyYao-oc 	 * Enable IRQ generation (0x8),
3203a4ac121SCodyYao-oc 	 * and enable ring-3 counting (0x2) and ring-0 counting (0x1)
3213a4ac121SCodyYao-oc 	 * if requested:
3223a4ac121SCodyYao-oc 	 */
3233a4ac121SCodyYao-oc 	bits = 0x8ULL;
3243a4ac121SCodyYao-oc 	if (hwc->config & ARCH_PERFMON_EVENTSEL_USR)
3253a4ac121SCodyYao-oc 		bits |= 0x2;
3263a4ac121SCodyYao-oc 	if (hwc->config & ARCH_PERFMON_EVENTSEL_OS)
3273a4ac121SCodyYao-oc 		bits |= 0x1;
3283a4ac121SCodyYao-oc 
3293a4ac121SCodyYao-oc 	bits <<= (idx * 4);
3303a4ac121SCodyYao-oc 	mask = 0xfULL << (idx * 4);
3313a4ac121SCodyYao-oc 
3323a4ac121SCodyYao-oc 	rdmsrl(hwc->config_base, ctrl_val);
3333a4ac121SCodyYao-oc 	ctrl_val &= ~mask;
3343a4ac121SCodyYao-oc 	ctrl_val |= bits;
3353a4ac121SCodyYao-oc 	wrmsrl(hwc->config_base, ctrl_val);
3363a4ac121SCodyYao-oc }
3373a4ac121SCodyYao-oc 
zhaoxin_pmu_enable_event(struct perf_event * event)3383a4ac121SCodyYao-oc static void zhaoxin_pmu_enable_event(struct perf_event *event)
3393a4ac121SCodyYao-oc {
3403a4ac121SCodyYao-oc 	struct hw_perf_event *hwc = &event->hw;
3413a4ac121SCodyYao-oc 
3423a4ac121SCodyYao-oc 	if (unlikely(hwc->config_base == MSR_ARCH_PERFMON_FIXED_CTR_CTRL)) {
3433a4ac121SCodyYao-oc 		zhaoxin_pmu_enable_fixed(hwc);
3443a4ac121SCodyYao-oc 		return;
3453a4ac121SCodyYao-oc 	}
3463a4ac121SCodyYao-oc 
3473a4ac121SCodyYao-oc 	__x86_pmu_enable_event(hwc, ARCH_PERFMON_EVENTSEL_ENABLE);
3483a4ac121SCodyYao-oc }
3493a4ac121SCodyYao-oc 
3503a4ac121SCodyYao-oc /*
3513a4ac121SCodyYao-oc  * This handler is triggered by the local APIC, so the APIC IRQ handling
3523a4ac121SCodyYao-oc  * rules apply:
3533a4ac121SCodyYao-oc  */
zhaoxin_pmu_handle_irq(struct pt_regs * regs)3543a4ac121SCodyYao-oc static int zhaoxin_pmu_handle_irq(struct pt_regs *regs)
3553a4ac121SCodyYao-oc {
3563a4ac121SCodyYao-oc 	struct perf_sample_data data;
3573a4ac121SCodyYao-oc 	struct cpu_hw_events *cpuc;
3583a4ac121SCodyYao-oc 	int handled = 0;
3593a4ac121SCodyYao-oc 	u64 status;
3603a4ac121SCodyYao-oc 	int bit;
3613a4ac121SCodyYao-oc 
3623a4ac121SCodyYao-oc 	cpuc = this_cpu_ptr(&cpu_hw_events);
3633a4ac121SCodyYao-oc 	apic_write(APIC_LVTPC, APIC_DM_NMI);
3643a4ac121SCodyYao-oc 	zhaoxin_pmu_disable_all();
3653a4ac121SCodyYao-oc 	status = zhaoxin_pmu_get_status();
3663a4ac121SCodyYao-oc 	if (!status)
3673a4ac121SCodyYao-oc 		goto done;
3683a4ac121SCodyYao-oc 
3693a4ac121SCodyYao-oc again:
3703a4ac121SCodyYao-oc 	if (x86_pmu.enabled_ack)
3713a4ac121SCodyYao-oc 		zxc_pmu_ack_status(status);
3723a4ac121SCodyYao-oc 	else
3733a4ac121SCodyYao-oc 		zhaoxin_pmu_ack_status(status);
3743a4ac121SCodyYao-oc 
3753a4ac121SCodyYao-oc 	inc_irq_stat(apic_perf_irqs);
3763a4ac121SCodyYao-oc 
3773a4ac121SCodyYao-oc 	/*
3783a4ac121SCodyYao-oc 	 * CondChgd bit 63 doesn't mean any overflow status. Ignore
3793a4ac121SCodyYao-oc 	 * and clear the bit.
3803a4ac121SCodyYao-oc 	 */
3813a4ac121SCodyYao-oc 	if (__test_and_clear_bit(63, (unsigned long *)&status)) {
3823a4ac121SCodyYao-oc 		if (!status)
3833a4ac121SCodyYao-oc 			goto done;
3843a4ac121SCodyYao-oc 	}
3853a4ac121SCodyYao-oc 
3863a4ac121SCodyYao-oc 	for_each_set_bit(bit, (unsigned long *)&status, X86_PMC_IDX_MAX) {
3873a4ac121SCodyYao-oc 		struct perf_event *event = cpuc->events[bit];
3883a4ac121SCodyYao-oc 
3893a4ac121SCodyYao-oc 		handled++;
3903a4ac121SCodyYao-oc 
3913a4ac121SCodyYao-oc 		if (!test_bit(bit, cpuc->active_mask))
3923a4ac121SCodyYao-oc 			continue;
3933a4ac121SCodyYao-oc 
3943a4ac121SCodyYao-oc 		x86_perf_event_update(event);
3953a4ac121SCodyYao-oc 		perf_sample_data_init(&data, 0, event->hw.last_period);
3963a4ac121SCodyYao-oc 
3973a4ac121SCodyYao-oc 		if (!x86_perf_event_set_period(event))
3983a4ac121SCodyYao-oc 			continue;
3993a4ac121SCodyYao-oc 
4003a4ac121SCodyYao-oc 		if (perf_event_overflow(event, &data, regs))
4013a4ac121SCodyYao-oc 			x86_pmu_stop(event, 0);
4023a4ac121SCodyYao-oc 	}
4033a4ac121SCodyYao-oc 
4043a4ac121SCodyYao-oc 	/*
4053a4ac121SCodyYao-oc 	 * Repeat if there is more work to be done:
4063a4ac121SCodyYao-oc 	 */
4073a4ac121SCodyYao-oc 	status = zhaoxin_pmu_get_status();
4083a4ac121SCodyYao-oc 	if (status)
4093a4ac121SCodyYao-oc 		goto again;
4103a4ac121SCodyYao-oc 
4113a4ac121SCodyYao-oc done:
4123a4ac121SCodyYao-oc 	zhaoxin_pmu_enable_all(0);
4133a4ac121SCodyYao-oc 	return handled;
4143a4ac121SCodyYao-oc }
4153a4ac121SCodyYao-oc 
zhaoxin_pmu_event_map(int hw_event)4163a4ac121SCodyYao-oc static u64 zhaoxin_pmu_event_map(int hw_event)
4173a4ac121SCodyYao-oc {
4183a4ac121SCodyYao-oc 	return zx_pmon_event_map[hw_event];
4193a4ac121SCodyYao-oc }
4203a4ac121SCodyYao-oc 
4213a4ac121SCodyYao-oc static struct event_constraint *
zhaoxin_get_event_constraints(struct cpu_hw_events * cpuc,int idx,struct perf_event * event)4223a4ac121SCodyYao-oc zhaoxin_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
4233a4ac121SCodyYao-oc 			struct perf_event *event)
4243a4ac121SCodyYao-oc {
4253a4ac121SCodyYao-oc 	struct event_constraint *c;
4263a4ac121SCodyYao-oc 
4273a4ac121SCodyYao-oc 	if (x86_pmu.event_constraints) {
4283a4ac121SCodyYao-oc 		for_each_event_constraint(c, x86_pmu.event_constraints) {
4293a4ac121SCodyYao-oc 			if ((event->hw.config & c->cmask) == c->code)
4303a4ac121SCodyYao-oc 				return c;
4313a4ac121SCodyYao-oc 		}
4323a4ac121SCodyYao-oc 	}
4333a4ac121SCodyYao-oc 
4343a4ac121SCodyYao-oc 	return &unconstrained;
4353a4ac121SCodyYao-oc }
4363a4ac121SCodyYao-oc 
4373a4ac121SCodyYao-oc PMU_FORMAT_ATTR(event,	"config:0-7");
4383a4ac121SCodyYao-oc PMU_FORMAT_ATTR(umask,	"config:8-15");
4393a4ac121SCodyYao-oc PMU_FORMAT_ATTR(edge,	"config:18");
4403a4ac121SCodyYao-oc PMU_FORMAT_ATTR(inv,	"config:23");
4413a4ac121SCodyYao-oc PMU_FORMAT_ATTR(cmask,	"config:24-31");
4423a4ac121SCodyYao-oc 
4433a4ac121SCodyYao-oc static struct attribute *zx_arch_formats_attr[] = {
4443a4ac121SCodyYao-oc 	&format_attr_event.attr,
4453a4ac121SCodyYao-oc 	&format_attr_umask.attr,
4463a4ac121SCodyYao-oc 	&format_attr_edge.attr,
4473a4ac121SCodyYao-oc 	&format_attr_inv.attr,
4483a4ac121SCodyYao-oc 	&format_attr_cmask.attr,
4493a4ac121SCodyYao-oc 	NULL,
4503a4ac121SCodyYao-oc };
4513a4ac121SCodyYao-oc 
zhaoxin_event_sysfs_show(char * page,u64 config)4523a4ac121SCodyYao-oc static ssize_t zhaoxin_event_sysfs_show(char *page, u64 config)
4533a4ac121SCodyYao-oc {
4543a4ac121SCodyYao-oc 	u64 event = (config & ARCH_PERFMON_EVENTSEL_EVENT);
4553a4ac121SCodyYao-oc 
4563a4ac121SCodyYao-oc 	return x86_event_sysfs_show(page, config, event);
4573a4ac121SCodyYao-oc }
4583a4ac121SCodyYao-oc 
4593a4ac121SCodyYao-oc static const struct x86_pmu zhaoxin_pmu __initconst = {
4603a4ac121SCodyYao-oc 	.name			= "zhaoxin",
4613a4ac121SCodyYao-oc 	.handle_irq		= zhaoxin_pmu_handle_irq,
4623a4ac121SCodyYao-oc 	.disable_all		= zhaoxin_pmu_disable_all,
4633a4ac121SCodyYao-oc 	.enable_all		= zhaoxin_pmu_enable_all,
4643a4ac121SCodyYao-oc 	.enable			= zhaoxin_pmu_enable_event,
4653a4ac121SCodyYao-oc 	.disable		= zhaoxin_pmu_disable_event,
4663a4ac121SCodyYao-oc 	.hw_config		= x86_pmu_hw_config,
4673a4ac121SCodyYao-oc 	.schedule_events	= x86_schedule_events,
4683a4ac121SCodyYao-oc 	.eventsel		= MSR_ARCH_PERFMON_EVENTSEL0,
4693a4ac121SCodyYao-oc 	.perfctr		= MSR_ARCH_PERFMON_PERFCTR0,
4703a4ac121SCodyYao-oc 	.event_map		= zhaoxin_pmu_event_map,
4713a4ac121SCodyYao-oc 	.max_events		= ARRAY_SIZE(zx_pmon_event_map),
4723a4ac121SCodyYao-oc 	.apic			= 1,
4733a4ac121SCodyYao-oc 	/*
4743a4ac121SCodyYao-oc 	 * For zxd/zxe, read/write operation for PMCx MSR is 48 bits.
4753a4ac121SCodyYao-oc 	 */
4763a4ac121SCodyYao-oc 	.max_period		= (1ULL << 47) - 1,
4773a4ac121SCodyYao-oc 	.get_event_constraints	= zhaoxin_get_event_constraints,
4783a4ac121SCodyYao-oc 
4793a4ac121SCodyYao-oc 	.format_attrs		= zx_arch_formats_attr,
4803a4ac121SCodyYao-oc 	.events_sysfs_show	= zhaoxin_event_sysfs_show,
4813a4ac121SCodyYao-oc };
4823a4ac121SCodyYao-oc 
4833a4ac121SCodyYao-oc static const struct { int id; char *name; } zx_arch_events_map[] __initconst = {
4843a4ac121SCodyYao-oc 	{ PERF_COUNT_HW_CPU_CYCLES, "cpu cycles" },
4853a4ac121SCodyYao-oc 	{ PERF_COUNT_HW_INSTRUCTIONS, "instructions" },
4863a4ac121SCodyYao-oc 	{ PERF_COUNT_HW_BUS_CYCLES, "bus cycles" },
4873a4ac121SCodyYao-oc 	{ PERF_COUNT_HW_CACHE_REFERENCES, "cache references" },
4883a4ac121SCodyYao-oc 	{ PERF_COUNT_HW_CACHE_MISSES, "cache misses" },
4893a4ac121SCodyYao-oc 	{ PERF_COUNT_HW_BRANCH_INSTRUCTIONS, "branch instructions" },
4903a4ac121SCodyYao-oc 	{ PERF_COUNT_HW_BRANCH_MISSES, "branch misses" },
4913a4ac121SCodyYao-oc };
4923a4ac121SCodyYao-oc 
zhaoxin_arch_events_quirk(void)4933a4ac121SCodyYao-oc static __init void zhaoxin_arch_events_quirk(void)
4943a4ac121SCodyYao-oc {
4953a4ac121SCodyYao-oc 	int bit;
4963a4ac121SCodyYao-oc 
497d9f6e12fSIngo Molnar 	/* disable event that reported as not present by cpuid */
4983a4ac121SCodyYao-oc 	for_each_set_bit(bit, x86_pmu.events_mask, ARRAY_SIZE(zx_arch_events_map)) {
4993a4ac121SCodyYao-oc 		zx_pmon_event_map[zx_arch_events_map[bit].id] = 0;
5003a4ac121SCodyYao-oc 		pr_warn("CPUID marked event: \'%s\' unavailable\n",
5013a4ac121SCodyYao-oc 			zx_arch_events_map[bit].name);
5023a4ac121SCodyYao-oc 	}
5033a4ac121SCodyYao-oc }
5043a4ac121SCodyYao-oc 
zhaoxin_pmu_init(void)5053a4ac121SCodyYao-oc __init int zhaoxin_pmu_init(void)
5063a4ac121SCodyYao-oc {
5073a4ac121SCodyYao-oc 	union cpuid10_edx edx;
5083a4ac121SCodyYao-oc 	union cpuid10_eax eax;
5093a4ac121SCodyYao-oc 	union cpuid10_ebx ebx;
5103a4ac121SCodyYao-oc 	struct event_constraint *c;
5113a4ac121SCodyYao-oc 	unsigned int unused;
5123a4ac121SCodyYao-oc 	int version;
5133a4ac121SCodyYao-oc 
5143a4ac121SCodyYao-oc 	pr_info("Welcome to zhaoxin pmu!\n");
5153a4ac121SCodyYao-oc 
5163a4ac121SCodyYao-oc 	/*
5173a4ac121SCodyYao-oc 	 * Check whether the Architectural PerfMon supports
5183a4ac121SCodyYao-oc 	 * hw_event or not.
5193a4ac121SCodyYao-oc 	 */
5203a4ac121SCodyYao-oc 	cpuid(10, &eax.full, &ebx.full, &unused, &edx.full);
5213a4ac121SCodyYao-oc 
5223a4ac121SCodyYao-oc 	if (eax.split.mask_length < ARCH_PERFMON_EVENTS_COUNT - 1)
5233a4ac121SCodyYao-oc 		return -ENODEV;
5243a4ac121SCodyYao-oc 
5253a4ac121SCodyYao-oc 	version = eax.split.version_id;
5263a4ac121SCodyYao-oc 	if (version != 2)
5273a4ac121SCodyYao-oc 		return -ENODEV;
5283a4ac121SCodyYao-oc 
5293a4ac121SCodyYao-oc 	x86_pmu = zhaoxin_pmu;
5303a4ac121SCodyYao-oc 	pr_info("Version check pass!\n");
5313a4ac121SCodyYao-oc 
5323a4ac121SCodyYao-oc 	x86_pmu.version			= version;
5333a4ac121SCodyYao-oc 	x86_pmu.num_counters		= eax.split.num_counters;
5343a4ac121SCodyYao-oc 	x86_pmu.cntval_bits		= eax.split.bit_width;
5353a4ac121SCodyYao-oc 	x86_pmu.cntval_mask		= (1ULL << eax.split.bit_width) - 1;
5363a4ac121SCodyYao-oc 	x86_pmu.events_maskl		= ebx.full;
5373a4ac121SCodyYao-oc 	x86_pmu.events_mask_len		= eax.split.mask_length;
5383a4ac121SCodyYao-oc 
5393a4ac121SCodyYao-oc 	x86_pmu.num_counters_fixed = edx.split.num_counters_fixed;
5403a4ac121SCodyYao-oc 	x86_add_quirk(zhaoxin_arch_events_quirk);
5413a4ac121SCodyYao-oc 
5423a4ac121SCodyYao-oc 	switch (boot_cpu_data.x86) {
5433a4ac121SCodyYao-oc 	case 0x06:
544*fd636b6aSsilviazhao 		/*
545*fd636b6aSsilviazhao 		 * Support Zhaoxin CPU from ZXC series, exclude Nano series through FMS.
546*fd636b6aSsilviazhao 		 * Nano FMS: Family=6, Model=F, Stepping=[0-A][C-D]
547*fd636b6aSsilviazhao 		 * ZXC FMS: Family=6, Model=F, Stepping=E-F OR Family=6, Model=0x19, Stepping=0-3
548*fd636b6aSsilviazhao 		 */
549*fd636b6aSsilviazhao 		if ((boot_cpu_data.x86_model == 0x0f && boot_cpu_data.x86_stepping >= 0x0e) ||
550*fd636b6aSsilviazhao 			boot_cpu_data.x86_model == 0x19) {
5513a4ac121SCodyYao-oc 
5523a4ac121SCodyYao-oc 			x86_pmu.max_period = x86_pmu.cntval_mask >> 1;
5533a4ac121SCodyYao-oc 
5543a4ac121SCodyYao-oc 			/* Clearing status works only if the global control is enable on zxc. */
5553a4ac121SCodyYao-oc 			x86_pmu.enabled_ack = 1;
5563a4ac121SCodyYao-oc 
5573a4ac121SCodyYao-oc 			x86_pmu.event_constraints = zxc_event_constraints;
5583a4ac121SCodyYao-oc 			zx_pmon_event_map[PERF_COUNT_HW_INSTRUCTIONS] = 0;
5593a4ac121SCodyYao-oc 			zx_pmon_event_map[PERF_COUNT_HW_CACHE_REFERENCES] = 0;
5603a4ac121SCodyYao-oc 			zx_pmon_event_map[PERF_COUNT_HW_CACHE_MISSES] = 0;
5613a4ac121SCodyYao-oc 			zx_pmon_event_map[PERF_COUNT_HW_BUS_CYCLES] = 0;
5623a4ac121SCodyYao-oc 
5633a4ac121SCodyYao-oc 			pr_cont("ZXC events, ");
5643a4ac121SCodyYao-oc 			break;
5653a4ac121SCodyYao-oc 		}
5663a4ac121SCodyYao-oc 		return -ENODEV;
5673a4ac121SCodyYao-oc 
5683a4ac121SCodyYao-oc 	case 0x07:
5693a4ac121SCodyYao-oc 		zx_pmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] =
5703a4ac121SCodyYao-oc 			X86_CONFIG(.event = 0x01, .umask = 0x01, .inv = 0x01, .cmask = 0x01);
5713a4ac121SCodyYao-oc 
5723a4ac121SCodyYao-oc 		zx_pmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] =
5733a4ac121SCodyYao-oc 			X86_CONFIG(.event = 0x0f, .umask = 0x04, .inv = 0, .cmask = 0);
5743a4ac121SCodyYao-oc 
5753a4ac121SCodyYao-oc 		switch (boot_cpu_data.x86_model) {
5763a4ac121SCodyYao-oc 		case 0x1b:
5773a4ac121SCodyYao-oc 			memcpy(hw_cache_event_ids, zxd_hw_cache_event_ids,
5783a4ac121SCodyYao-oc 			       sizeof(hw_cache_event_ids));
5793a4ac121SCodyYao-oc 
5803a4ac121SCodyYao-oc 			x86_pmu.event_constraints = zxd_event_constraints;
5813a4ac121SCodyYao-oc 
5823a4ac121SCodyYao-oc 			zx_pmon_event_map[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x0700;
5833a4ac121SCodyYao-oc 			zx_pmon_event_map[PERF_COUNT_HW_BRANCH_MISSES] = 0x0709;
5843a4ac121SCodyYao-oc 
5853a4ac121SCodyYao-oc 			pr_cont("ZXD events, ");
5863a4ac121SCodyYao-oc 			break;
5873a4ac121SCodyYao-oc 		case 0x3b:
5883a4ac121SCodyYao-oc 			memcpy(hw_cache_event_ids, zxe_hw_cache_event_ids,
5893a4ac121SCodyYao-oc 			       sizeof(hw_cache_event_ids));
5903a4ac121SCodyYao-oc 
5913a4ac121SCodyYao-oc 			x86_pmu.event_constraints = zxd_event_constraints;
5923a4ac121SCodyYao-oc 
5933a4ac121SCodyYao-oc 			zx_pmon_event_map[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x0028;
5943a4ac121SCodyYao-oc 			zx_pmon_event_map[PERF_COUNT_HW_BRANCH_MISSES] = 0x0029;
5953a4ac121SCodyYao-oc 
5963a4ac121SCodyYao-oc 			pr_cont("ZXE events, ");
5973a4ac121SCodyYao-oc 			break;
5983a4ac121SCodyYao-oc 		default:
5993a4ac121SCodyYao-oc 			return -ENODEV;
6003a4ac121SCodyYao-oc 		}
6013a4ac121SCodyYao-oc 		break;
6023a4ac121SCodyYao-oc 
6033a4ac121SCodyYao-oc 	default:
6043a4ac121SCodyYao-oc 		return -ENODEV;
6053a4ac121SCodyYao-oc 	}
6063a4ac121SCodyYao-oc 
6073a4ac121SCodyYao-oc 	x86_pmu.intel_ctrl = (1 << (x86_pmu.num_counters)) - 1;
6083a4ac121SCodyYao-oc 	x86_pmu.intel_ctrl |= ((1LL << x86_pmu.num_counters_fixed)-1) << INTEL_PMC_IDX_FIXED;
6093a4ac121SCodyYao-oc 
6103a4ac121SCodyYao-oc 	if (x86_pmu.event_constraints) {
6113a4ac121SCodyYao-oc 		for_each_event_constraint(c, x86_pmu.event_constraints) {
6123a4ac121SCodyYao-oc 			c->idxmsk64 |= (1ULL << x86_pmu.num_counters) - 1;
6133a4ac121SCodyYao-oc 			c->weight += x86_pmu.num_counters;
6143a4ac121SCodyYao-oc 		}
6153a4ac121SCodyYao-oc 	}
6163a4ac121SCodyYao-oc 
6173a4ac121SCodyYao-oc 	return 0;
6183a4ac121SCodyYao-oc }
6193a4ac121SCodyYao-oc 
620