18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <linux/perf_event.h> 38c2ecf20Sopenharmony_ci#include <linux/types.h> 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include "../perf_event.h" 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci/* 88c2ecf20Sopenharmony_ci * Not sure about some of these 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_cistatic const u64 p6_perfmon_event_map[] = 118c2ecf20Sopenharmony_ci{ 128c2ecf20Sopenharmony_ci [PERF_COUNT_HW_CPU_CYCLES] = 0x0079, /* CPU_CLK_UNHALTED */ 138c2ecf20Sopenharmony_ci [PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0, /* INST_RETIRED */ 148c2ecf20Sopenharmony_ci [PERF_COUNT_HW_CACHE_REFERENCES] = 0x0f2e, /* L2_RQSTS:M:E:S:I */ 158c2ecf20Sopenharmony_ci [PERF_COUNT_HW_CACHE_MISSES] = 0x012e, /* L2_RQSTS:I */ 168c2ecf20Sopenharmony_ci [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x00c4, /* BR_INST_RETIRED */ 178c2ecf20Sopenharmony_ci [PERF_COUNT_HW_BRANCH_MISSES] = 0x00c5, /* BR_MISS_PRED_RETIRED */ 188c2ecf20Sopenharmony_ci [PERF_COUNT_HW_BUS_CYCLES] = 0x0062, /* BUS_DRDY_CLOCKS */ 198c2ecf20Sopenharmony_ci [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x00a2, /* RESOURCE_STALLS */ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci}; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic const u64 __initconst p6_hw_cache_event_ids 248c2ecf20Sopenharmony_ci [PERF_COUNT_HW_CACHE_MAX] 258c2ecf20Sopenharmony_ci [PERF_COUNT_HW_CACHE_OP_MAX] 268c2ecf20Sopenharmony_ci [PERF_COUNT_HW_CACHE_RESULT_MAX] = 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci [ C(L1D) ] = { 298c2ecf20Sopenharmony_ci [ C(OP_READ) ] = { 308c2ecf20Sopenharmony_ci [ C(RESULT_ACCESS) ] = 0x0043, /* DATA_MEM_REFS */ 318c2ecf20Sopenharmony_ci [ C(RESULT_MISS) ] = 0x0045, /* DCU_LINES_IN */ 328c2ecf20Sopenharmony_ci }, 338c2ecf20Sopenharmony_ci [ C(OP_WRITE) ] = { 348c2ecf20Sopenharmony_ci [ C(RESULT_ACCESS) ] = 0, 358c2ecf20Sopenharmony_ci [ C(RESULT_MISS) ] = 0x0f29, /* L2_LD:M:E:S:I */ 368c2ecf20Sopenharmony_ci }, 378c2ecf20Sopenharmony_ci [ C(OP_PREFETCH) ] = { 388c2ecf20Sopenharmony_ci [ C(RESULT_ACCESS) ] = 0, 398c2ecf20Sopenharmony_ci [ C(RESULT_MISS) ] = 0, 408c2ecf20Sopenharmony_ci }, 418c2ecf20Sopenharmony_ci }, 428c2ecf20Sopenharmony_ci [ C(L1I ) ] = { 438c2ecf20Sopenharmony_ci [ C(OP_READ) ] = { 448c2ecf20Sopenharmony_ci [ C(RESULT_ACCESS) ] = 0x0080, /* IFU_IFETCH */ 458c2ecf20Sopenharmony_ci [ C(RESULT_MISS) ] = 0x0f28, /* L2_IFETCH:M:E:S:I */ 468c2ecf20Sopenharmony_ci }, 478c2ecf20Sopenharmony_ci [ C(OP_WRITE) ] = { 488c2ecf20Sopenharmony_ci [ C(RESULT_ACCESS) ] = -1, 498c2ecf20Sopenharmony_ci [ C(RESULT_MISS) ] = -1, 508c2ecf20Sopenharmony_ci }, 518c2ecf20Sopenharmony_ci [ C(OP_PREFETCH) ] = { 528c2ecf20Sopenharmony_ci [ C(RESULT_ACCESS) ] = 0, 538c2ecf20Sopenharmony_ci [ C(RESULT_MISS) ] = 0, 548c2ecf20Sopenharmony_ci }, 558c2ecf20Sopenharmony_ci }, 568c2ecf20Sopenharmony_ci [ C(LL ) ] = { 578c2ecf20Sopenharmony_ci [ C(OP_READ) ] = { 588c2ecf20Sopenharmony_ci [ C(RESULT_ACCESS) ] = 0, 598c2ecf20Sopenharmony_ci [ C(RESULT_MISS) ] = 0, 608c2ecf20Sopenharmony_ci }, 618c2ecf20Sopenharmony_ci [ C(OP_WRITE) ] = { 628c2ecf20Sopenharmony_ci [ C(RESULT_ACCESS) ] = 0, 638c2ecf20Sopenharmony_ci [ C(RESULT_MISS) ] = 0x0025, /* L2_M_LINES_INM */ 648c2ecf20Sopenharmony_ci }, 658c2ecf20Sopenharmony_ci [ C(OP_PREFETCH) ] = { 668c2ecf20Sopenharmony_ci [ C(RESULT_ACCESS) ] = 0, 678c2ecf20Sopenharmony_ci [ C(RESULT_MISS) ] = 0, 688c2ecf20Sopenharmony_ci }, 698c2ecf20Sopenharmony_ci }, 708c2ecf20Sopenharmony_ci [ C(DTLB) ] = { 718c2ecf20Sopenharmony_ci [ C(OP_READ) ] = { 728c2ecf20Sopenharmony_ci [ C(RESULT_ACCESS) ] = 0x0043, /* DATA_MEM_REFS */ 738c2ecf20Sopenharmony_ci [ C(RESULT_MISS) ] = 0, 748c2ecf20Sopenharmony_ci }, 758c2ecf20Sopenharmony_ci [ C(OP_WRITE) ] = { 768c2ecf20Sopenharmony_ci [ C(RESULT_ACCESS) ] = 0, 778c2ecf20Sopenharmony_ci [ C(RESULT_MISS) ] = 0, 788c2ecf20Sopenharmony_ci }, 798c2ecf20Sopenharmony_ci [ C(OP_PREFETCH) ] = { 808c2ecf20Sopenharmony_ci [ C(RESULT_ACCESS) ] = 0, 818c2ecf20Sopenharmony_ci [ C(RESULT_MISS) ] = 0, 828c2ecf20Sopenharmony_ci }, 838c2ecf20Sopenharmony_ci }, 848c2ecf20Sopenharmony_ci [ C(ITLB) ] = { 858c2ecf20Sopenharmony_ci [ C(OP_READ) ] = { 868c2ecf20Sopenharmony_ci [ C(RESULT_ACCESS) ] = 0x0080, /* IFU_IFETCH */ 878c2ecf20Sopenharmony_ci [ C(RESULT_MISS) ] = 0x0085, /* ITLB_MISS */ 888c2ecf20Sopenharmony_ci }, 898c2ecf20Sopenharmony_ci [ C(OP_WRITE) ] = { 908c2ecf20Sopenharmony_ci [ C(RESULT_ACCESS) ] = -1, 918c2ecf20Sopenharmony_ci [ C(RESULT_MISS) ] = -1, 928c2ecf20Sopenharmony_ci }, 938c2ecf20Sopenharmony_ci [ C(OP_PREFETCH) ] = { 948c2ecf20Sopenharmony_ci [ C(RESULT_ACCESS) ] = -1, 958c2ecf20Sopenharmony_ci [ C(RESULT_MISS) ] = -1, 968c2ecf20Sopenharmony_ci }, 978c2ecf20Sopenharmony_ci }, 988c2ecf20Sopenharmony_ci [ C(BPU ) ] = { 998c2ecf20Sopenharmony_ci [ C(OP_READ) ] = { 1008c2ecf20Sopenharmony_ci [ C(RESULT_ACCESS) ] = 0x00c4, /* BR_INST_RETIRED */ 1018c2ecf20Sopenharmony_ci [ C(RESULT_MISS) ] = 0x00c5, /* BR_MISS_PRED_RETIRED */ 1028c2ecf20Sopenharmony_ci }, 1038c2ecf20Sopenharmony_ci [ C(OP_WRITE) ] = { 1048c2ecf20Sopenharmony_ci [ C(RESULT_ACCESS) ] = -1, 1058c2ecf20Sopenharmony_ci [ C(RESULT_MISS) ] = -1, 1068c2ecf20Sopenharmony_ci }, 1078c2ecf20Sopenharmony_ci [ C(OP_PREFETCH) ] = { 1088c2ecf20Sopenharmony_ci [ C(RESULT_ACCESS) ] = -1, 1098c2ecf20Sopenharmony_ci [ C(RESULT_MISS) ] = -1, 1108c2ecf20Sopenharmony_ci }, 1118c2ecf20Sopenharmony_ci }, 1128c2ecf20Sopenharmony_ci}; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic u64 p6_pmu_event_map(int hw_event) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci return p6_perfmon_event_map[hw_event]; 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci/* 1208c2ecf20Sopenharmony_ci * Event setting that is specified not to count anything. 1218c2ecf20Sopenharmony_ci * We use this to effectively disable a counter. 1228c2ecf20Sopenharmony_ci * 1238c2ecf20Sopenharmony_ci * L2_RQSTS with 0 MESI unit mask. 1248c2ecf20Sopenharmony_ci */ 1258c2ecf20Sopenharmony_ci#define P6_NOP_EVENT 0x0000002EULL 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic struct event_constraint p6_event_constraints[] = 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci INTEL_EVENT_CONSTRAINT(0xc1, 0x1), /* FLOPS */ 1308c2ecf20Sopenharmony_ci INTEL_EVENT_CONSTRAINT(0x10, 0x1), /* FP_COMP_OPS_EXE */ 1318c2ecf20Sopenharmony_ci INTEL_EVENT_CONSTRAINT(0x11, 0x2), /* FP_ASSIST */ 1328c2ecf20Sopenharmony_ci INTEL_EVENT_CONSTRAINT(0x12, 0x2), /* MUL */ 1338c2ecf20Sopenharmony_ci INTEL_EVENT_CONSTRAINT(0x13, 0x2), /* DIV */ 1348c2ecf20Sopenharmony_ci INTEL_EVENT_CONSTRAINT(0x14, 0x1), /* CYCLES_DIV_BUSY */ 1358c2ecf20Sopenharmony_ci EVENT_CONSTRAINT_END 1368c2ecf20Sopenharmony_ci}; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic void p6_pmu_disable_all(void) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci u64 val; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci /* p6 only has one enable register */ 1438c2ecf20Sopenharmony_ci rdmsrl(MSR_P6_EVNTSEL0, val); 1448c2ecf20Sopenharmony_ci val &= ~ARCH_PERFMON_EVENTSEL_ENABLE; 1458c2ecf20Sopenharmony_ci wrmsrl(MSR_P6_EVNTSEL0, val); 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic void p6_pmu_enable_all(int added) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci unsigned long val; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci /* p6 only has one enable register */ 1538c2ecf20Sopenharmony_ci rdmsrl(MSR_P6_EVNTSEL0, val); 1548c2ecf20Sopenharmony_ci val |= ARCH_PERFMON_EVENTSEL_ENABLE; 1558c2ecf20Sopenharmony_ci wrmsrl(MSR_P6_EVNTSEL0, val); 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic inline void 1598c2ecf20Sopenharmony_cip6_pmu_disable_event(struct perf_event *event) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci struct hw_perf_event *hwc = &event->hw; 1628c2ecf20Sopenharmony_ci u64 val = P6_NOP_EVENT; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci (void)wrmsrl_safe(hwc->config_base, val); 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic void p6_pmu_enable_event(struct perf_event *event) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci struct hw_perf_event *hwc = &event->hw; 1708c2ecf20Sopenharmony_ci u64 val; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci val = hwc->config; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci /* 1758c2ecf20Sopenharmony_ci * p6 only has a global event enable, set on PerfEvtSel0 1768c2ecf20Sopenharmony_ci * We "disable" events by programming P6_NOP_EVENT 1778c2ecf20Sopenharmony_ci * and we rely on p6_pmu_enable_all() being called 1788c2ecf20Sopenharmony_ci * to actually enable the events. 1798c2ecf20Sopenharmony_ci */ 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci (void)wrmsrl_safe(hwc->config_base, val); 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ciPMU_FORMAT_ATTR(event, "config:0-7" ); 1858c2ecf20Sopenharmony_ciPMU_FORMAT_ATTR(umask, "config:8-15" ); 1868c2ecf20Sopenharmony_ciPMU_FORMAT_ATTR(edge, "config:18" ); 1878c2ecf20Sopenharmony_ciPMU_FORMAT_ATTR(pc, "config:19" ); 1888c2ecf20Sopenharmony_ciPMU_FORMAT_ATTR(inv, "config:23" ); 1898c2ecf20Sopenharmony_ciPMU_FORMAT_ATTR(cmask, "config:24-31" ); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic struct attribute *intel_p6_formats_attr[] = { 1928c2ecf20Sopenharmony_ci &format_attr_event.attr, 1938c2ecf20Sopenharmony_ci &format_attr_umask.attr, 1948c2ecf20Sopenharmony_ci &format_attr_edge.attr, 1958c2ecf20Sopenharmony_ci &format_attr_pc.attr, 1968c2ecf20Sopenharmony_ci &format_attr_inv.attr, 1978c2ecf20Sopenharmony_ci &format_attr_cmask.attr, 1988c2ecf20Sopenharmony_ci NULL, 1998c2ecf20Sopenharmony_ci}; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic __initconst const struct x86_pmu p6_pmu = { 2028c2ecf20Sopenharmony_ci .name = "p6", 2038c2ecf20Sopenharmony_ci .handle_irq = x86_pmu_handle_irq, 2048c2ecf20Sopenharmony_ci .disable_all = p6_pmu_disable_all, 2058c2ecf20Sopenharmony_ci .enable_all = p6_pmu_enable_all, 2068c2ecf20Sopenharmony_ci .enable = p6_pmu_enable_event, 2078c2ecf20Sopenharmony_ci .disable = p6_pmu_disable_event, 2088c2ecf20Sopenharmony_ci .hw_config = x86_pmu_hw_config, 2098c2ecf20Sopenharmony_ci .schedule_events = x86_schedule_events, 2108c2ecf20Sopenharmony_ci .eventsel = MSR_P6_EVNTSEL0, 2118c2ecf20Sopenharmony_ci .perfctr = MSR_P6_PERFCTR0, 2128c2ecf20Sopenharmony_ci .event_map = p6_pmu_event_map, 2138c2ecf20Sopenharmony_ci .max_events = ARRAY_SIZE(p6_perfmon_event_map), 2148c2ecf20Sopenharmony_ci .apic = 1, 2158c2ecf20Sopenharmony_ci .max_period = (1ULL << 31) - 1, 2168c2ecf20Sopenharmony_ci .version = 0, 2178c2ecf20Sopenharmony_ci .num_counters = 2, 2188c2ecf20Sopenharmony_ci /* 2198c2ecf20Sopenharmony_ci * Events have 40 bits implemented. However they are designed such 2208c2ecf20Sopenharmony_ci * that bits [32-39] are sign extensions of bit 31. As such the 2218c2ecf20Sopenharmony_ci * effective width of a event for P6-like PMU is 32 bits only. 2228c2ecf20Sopenharmony_ci * 2238c2ecf20Sopenharmony_ci * See IA-32 Intel Architecture Software developer manual Vol 3B 2248c2ecf20Sopenharmony_ci */ 2258c2ecf20Sopenharmony_ci .cntval_bits = 32, 2268c2ecf20Sopenharmony_ci .cntval_mask = (1ULL << 32) - 1, 2278c2ecf20Sopenharmony_ci .get_event_constraints = x86_get_event_constraints, 2288c2ecf20Sopenharmony_ci .event_constraints = p6_event_constraints, 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci .format_attrs = intel_p6_formats_attr, 2318c2ecf20Sopenharmony_ci .events_sysfs_show = intel_event_sysfs_show, 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci}; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic __init void p6_pmu_rdpmc_quirk(void) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci if (boot_cpu_data.x86_stepping < 9) { 2388c2ecf20Sopenharmony_ci /* 2398c2ecf20Sopenharmony_ci * PPro erratum 26; fixed in stepping 9 and above. 2408c2ecf20Sopenharmony_ci */ 2418c2ecf20Sopenharmony_ci pr_warn("Userspace RDPMC support disabled due to a CPU erratum\n"); 2428c2ecf20Sopenharmony_ci x86_pmu.attr_rdpmc_broken = 1; 2438c2ecf20Sopenharmony_ci x86_pmu.attr_rdpmc = 0; 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci__init int p6_pmu_init(void) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci x86_pmu = p6_pmu; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci switch (boot_cpu_data.x86_model) { 2528c2ecf20Sopenharmony_ci case 1: /* Pentium Pro */ 2538c2ecf20Sopenharmony_ci x86_add_quirk(p6_pmu_rdpmc_quirk); 2548c2ecf20Sopenharmony_ci break; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci case 3: /* Pentium II - Klamath */ 2578c2ecf20Sopenharmony_ci case 5: /* Pentium II - Deschutes */ 2588c2ecf20Sopenharmony_ci case 6: /* Pentium II - Mendocino */ 2598c2ecf20Sopenharmony_ci break; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci case 7: /* Pentium III - Katmai */ 2628c2ecf20Sopenharmony_ci case 8: /* Pentium III - Coppermine */ 2638c2ecf20Sopenharmony_ci case 10: /* Pentium III Xeon */ 2648c2ecf20Sopenharmony_ci case 11: /* Pentium III - Tualatin */ 2658c2ecf20Sopenharmony_ci break; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci case 9: /* Pentium M - Banias */ 2688c2ecf20Sopenharmony_ci case 13: /* Pentium M - Dothan */ 2698c2ecf20Sopenharmony_ci break; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci default: 2728c2ecf20Sopenharmony_ci pr_cont("unsupported p6 CPU model %d ", boot_cpu_data.x86_model); 2738c2ecf20Sopenharmony_ci return -ENODEV; 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci memcpy(hw_cache_event_ids, p6_hw_cache_event_ids, 2778c2ecf20Sopenharmony_ci sizeof(hw_cache_event_ids)); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci return 0; 2808c2ecf20Sopenharmony_ci} 281