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