18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Performance counter support for MPC7450-family processors. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2008-2009 Paul Mackerras, IBM Corporation. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci#include <linux/string.h> 88c2ecf20Sopenharmony_ci#include <linux/perf_event.h> 98c2ecf20Sopenharmony_ci#include <asm/reg.h> 108c2ecf20Sopenharmony_ci#include <asm/cputable.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#define N_COUNTER 6 /* Number of hardware counters */ 138c2ecf20Sopenharmony_ci#define MAX_ALT 3 /* Maximum number of event alternative codes */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci/* 168c2ecf20Sopenharmony_ci * Bits in event code for MPC7450 family 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_ci#define PM_THRMULT_MSKS 0x40000 198c2ecf20Sopenharmony_ci#define PM_THRESH_SH 12 208c2ecf20Sopenharmony_ci#define PM_THRESH_MSK 0x3f 218c2ecf20Sopenharmony_ci#define PM_PMC_SH 8 228c2ecf20Sopenharmony_ci#define PM_PMC_MSK 7 238c2ecf20Sopenharmony_ci#define PM_PMCSEL_MSK 0x7f 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* 268c2ecf20Sopenharmony_ci * Classify events according to how specific their PMC requirements are. 278c2ecf20Sopenharmony_ci * Result is: 288c2ecf20Sopenharmony_ci * 0: can go on any PMC 298c2ecf20Sopenharmony_ci * 1: can go on PMCs 1-4 308c2ecf20Sopenharmony_ci * 2: can go on PMCs 1,2,4 318c2ecf20Sopenharmony_ci * 3: can go on PMCs 1 or 2 328c2ecf20Sopenharmony_ci * 4: can only go on one PMC 338c2ecf20Sopenharmony_ci * -1: event code is invalid 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_ci#define N_CLASSES 5 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic int mpc7450_classify_event(u32 event) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci int pmc; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci pmc = (event >> PM_PMC_SH) & PM_PMC_MSK; 428c2ecf20Sopenharmony_ci if (pmc) { 438c2ecf20Sopenharmony_ci if (pmc > N_COUNTER) 448c2ecf20Sopenharmony_ci return -1; 458c2ecf20Sopenharmony_ci return 4; 468c2ecf20Sopenharmony_ci } 478c2ecf20Sopenharmony_ci event &= PM_PMCSEL_MSK; 488c2ecf20Sopenharmony_ci if (event <= 1) 498c2ecf20Sopenharmony_ci return 0; 508c2ecf20Sopenharmony_ci if (event <= 7) 518c2ecf20Sopenharmony_ci return 1; 528c2ecf20Sopenharmony_ci if (event <= 13) 538c2ecf20Sopenharmony_ci return 2; 548c2ecf20Sopenharmony_ci if (event <= 22) 558c2ecf20Sopenharmony_ci return 3; 568c2ecf20Sopenharmony_ci return -1; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci/* 608c2ecf20Sopenharmony_ci * Events using threshold and possible threshold scale: 618c2ecf20Sopenharmony_ci * code scale? name 628c2ecf20Sopenharmony_ci * 11e N PM_INSTQ_EXCEED_CYC 638c2ecf20Sopenharmony_ci * 11f N PM_ALTV_IQ_EXCEED_CYC 648c2ecf20Sopenharmony_ci * 128 Y PM_DTLB_SEARCH_EXCEED_CYC 658c2ecf20Sopenharmony_ci * 12b Y PM_LD_MISS_EXCEED_L1_CYC 668c2ecf20Sopenharmony_ci * 220 N PM_CQ_EXCEED_CYC 678c2ecf20Sopenharmony_ci * 30c N PM_GPR_RB_EXCEED_CYC 688c2ecf20Sopenharmony_ci * 30d ? PM_FPR_IQ_EXCEED_CYC ? 698c2ecf20Sopenharmony_ci * 311 Y PM_ITLB_SEARCH_EXCEED 708c2ecf20Sopenharmony_ci * 410 N PM_GPR_IQ_EXCEED_CYC 718c2ecf20Sopenharmony_ci */ 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* 748c2ecf20Sopenharmony_ci * Return use of threshold and threshold scale bits: 758c2ecf20Sopenharmony_ci * 0 = uses neither, 1 = uses threshold, 2 = uses both 768c2ecf20Sopenharmony_ci */ 778c2ecf20Sopenharmony_cistatic int mpc7450_threshold_use(u32 event) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci int pmc, sel; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci pmc = (event >> PM_PMC_SH) & PM_PMC_MSK; 828c2ecf20Sopenharmony_ci sel = event & PM_PMCSEL_MSK; 838c2ecf20Sopenharmony_ci switch (pmc) { 848c2ecf20Sopenharmony_ci case 1: 858c2ecf20Sopenharmony_ci if (sel == 0x1e || sel == 0x1f) 868c2ecf20Sopenharmony_ci return 1; 878c2ecf20Sopenharmony_ci if (sel == 0x28 || sel == 0x2b) 888c2ecf20Sopenharmony_ci return 2; 898c2ecf20Sopenharmony_ci break; 908c2ecf20Sopenharmony_ci case 2: 918c2ecf20Sopenharmony_ci if (sel == 0x20) 928c2ecf20Sopenharmony_ci return 1; 938c2ecf20Sopenharmony_ci break; 948c2ecf20Sopenharmony_ci case 3: 958c2ecf20Sopenharmony_ci if (sel == 0xc || sel == 0xd) 968c2ecf20Sopenharmony_ci return 1; 978c2ecf20Sopenharmony_ci if (sel == 0x11) 988c2ecf20Sopenharmony_ci return 2; 998c2ecf20Sopenharmony_ci break; 1008c2ecf20Sopenharmony_ci case 4: 1018c2ecf20Sopenharmony_ci if (sel == 0x10) 1028c2ecf20Sopenharmony_ci return 1; 1038c2ecf20Sopenharmony_ci break; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci return 0; 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci/* 1098c2ecf20Sopenharmony_ci * Layout of constraint bits: 1108c2ecf20Sopenharmony_ci * 33222222222211111111110000000000 1118c2ecf20Sopenharmony_ci * 10987654321098765432109876543210 1128c2ecf20Sopenharmony_ci * |< >< > < > < ><><><><><><> 1138c2ecf20Sopenharmony_ci * TS TV G4 G3 G2P6P5P4P3P2P1 1148c2ecf20Sopenharmony_ci * 1158c2ecf20Sopenharmony_ci * P1 - P6 1168c2ecf20Sopenharmony_ci * 0 - 11: Count of events needing PMC1 .. PMC6 1178c2ecf20Sopenharmony_ci * 1188c2ecf20Sopenharmony_ci * G2 1198c2ecf20Sopenharmony_ci * 12 - 14: Count of events needing PMC1 or PMC2 1208c2ecf20Sopenharmony_ci * 1218c2ecf20Sopenharmony_ci * G3 1228c2ecf20Sopenharmony_ci * 16 - 18: Count of events needing PMC1, PMC2 or PMC4 1238c2ecf20Sopenharmony_ci * 1248c2ecf20Sopenharmony_ci * G4 1258c2ecf20Sopenharmony_ci * 20 - 23: Count of events needing PMC1, PMC2, PMC3 or PMC4 1268c2ecf20Sopenharmony_ci * 1278c2ecf20Sopenharmony_ci * TV 1288c2ecf20Sopenharmony_ci * 24 - 29: Threshold value requested 1298c2ecf20Sopenharmony_ci * 1308c2ecf20Sopenharmony_ci * TS 1318c2ecf20Sopenharmony_ci * 30: Threshold scale value requested 1328c2ecf20Sopenharmony_ci */ 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic u32 pmcbits[N_COUNTER][2] = { 1358c2ecf20Sopenharmony_ci { 0x00844002, 0x00111001 }, /* PMC1 mask, value: P1,G2,G3,G4 */ 1368c2ecf20Sopenharmony_ci { 0x00844008, 0x00111004 }, /* PMC2: P2,G2,G3,G4 */ 1378c2ecf20Sopenharmony_ci { 0x00800020, 0x00100010 }, /* PMC3: P3,G4 */ 1388c2ecf20Sopenharmony_ci { 0x00840080, 0x00110040 }, /* PMC4: P4,G3,G4 */ 1398c2ecf20Sopenharmony_ci { 0x00000200, 0x00000100 }, /* PMC5: P5 */ 1408c2ecf20Sopenharmony_ci { 0x00000800, 0x00000400 } /* PMC6: P6 */ 1418c2ecf20Sopenharmony_ci}; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic u32 classbits[N_CLASSES - 1][2] = { 1448c2ecf20Sopenharmony_ci { 0x00000000, 0x00000000 }, /* class 0: no constraint */ 1458c2ecf20Sopenharmony_ci { 0x00800000, 0x00100000 }, /* class 1: G4 */ 1468c2ecf20Sopenharmony_ci { 0x00040000, 0x00010000 }, /* class 2: G3 */ 1478c2ecf20Sopenharmony_ci { 0x00004000, 0x00001000 }, /* class 3: G2 */ 1488c2ecf20Sopenharmony_ci}; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic int mpc7450_get_constraint(u64 event, unsigned long *maskp, 1518c2ecf20Sopenharmony_ci unsigned long *valp) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci int pmc, class; 1548c2ecf20Sopenharmony_ci u32 mask, value; 1558c2ecf20Sopenharmony_ci int thresh, tuse; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci class = mpc7450_classify_event(event); 1588c2ecf20Sopenharmony_ci if (class < 0) 1598c2ecf20Sopenharmony_ci return -1; 1608c2ecf20Sopenharmony_ci if (class == 4) { 1618c2ecf20Sopenharmony_ci pmc = ((unsigned int)event >> PM_PMC_SH) & PM_PMC_MSK; 1628c2ecf20Sopenharmony_ci mask = pmcbits[pmc - 1][0]; 1638c2ecf20Sopenharmony_ci value = pmcbits[pmc - 1][1]; 1648c2ecf20Sopenharmony_ci } else { 1658c2ecf20Sopenharmony_ci mask = classbits[class][0]; 1668c2ecf20Sopenharmony_ci value = classbits[class][1]; 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci tuse = mpc7450_threshold_use(event); 1708c2ecf20Sopenharmony_ci if (tuse) { 1718c2ecf20Sopenharmony_ci thresh = ((unsigned int)event >> PM_THRESH_SH) & PM_THRESH_MSK; 1728c2ecf20Sopenharmony_ci mask |= 0x3f << 24; 1738c2ecf20Sopenharmony_ci value |= thresh << 24; 1748c2ecf20Sopenharmony_ci if (tuse == 2) { 1758c2ecf20Sopenharmony_ci mask |= 0x40000000; 1768c2ecf20Sopenharmony_ci if ((unsigned int)event & PM_THRMULT_MSKS) 1778c2ecf20Sopenharmony_ci value |= 0x40000000; 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci *maskp = mask; 1828c2ecf20Sopenharmony_ci *valp = value; 1838c2ecf20Sopenharmony_ci return 0; 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic const unsigned int event_alternatives[][MAX_ALT] = { 1878c2ecf20Sopenharmony_ci { 0x217, 0x317 }, /* PM_L1_DCACHE_MISS */ 1888c2ecf20Sopenharmony_ci { 0x418, 0x50f, 0x60f }, /* PM_SNOOP_RETRY */ 1898c2ecf20Sopenharmony_ci { 0x502, 0x602 }, /* PM_L2_HIT */ 1908c2ecf20Sopenharmony_ci { 0x503, 0x603 }, /* PM_L3_HIT */ 1918c2ecf20Sopenharmony_ci { 0x504, 0x604 }, /* PM_L2_ICACHE_MISS */ 1928c2ecf20Sopenharmony_ci { 0x505, 0x605 }, /* PM_L3_ICACHE_MISS */ 1938c2ecf20Sopenharmony_ci { 0x506, 0x606 }, /* PM_L2_DCACHE_MISS */ 1948c2ecf20Sopenharmony_ci { 0x507, 0x607 }, /* PM_L3_DCACHE_MISS */ 1958c2ecf20Sopenharmony_ci { 0x50a, 0x623 }, /* PM_LD_HIT_L3 */ 1968c2ecf20Sopenharmony_ci { 0x50b, 0x624 }, /* PM_ST_HIT_L3 */ 1978c2ecf20Sopenharmony_ci { 0x50d, 0x60d }, /* PM_L2_TOUCH_HIT */ 1988c2ecf20Sopenharmony_ci { 0x50e, 0x60e }, /* PM_L3_TOUCH_HIT */ 1998c2ecf20Sopenharmony_ci { 0x512, 0x612 }, /* PM_INT_LOCAL */ 2008c2ecf20Sopenharmony_ci { 0x513, 0x61d }, /* PM_L2_MISS */ 2018c2ecf20Sopenharmony_ci { 0x514, 0x61e }, /* PM_L3_MISS */ 2028c2ecf20Sopenharmony_ci}; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci/* 2058c2ecf20Sopenharmony_ci * Scan the alternatives table for a match and return the 2068c2ecf20Sopenharmony_ci * index into the alternatives table if found, else -1. 2078c2ecf20Sopenharmony_ci */ 2088c2ecf20Sopenharmony_cistatic int find_alternative(u32 event) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci int i, j; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(event_alternatives); ++i) { 2138c2ecf20Sopenharmony_ci if (event < event_alternatives[i][0]) 2148c2ecf20Sopenharmony_ci break; 2158c2ecf20Sopenharmony_ci for (j = 0; j < MAX_ALT && event_alternatives[i][j]; ++j) 2168c2ecf20Sopenharmony_ci if (event == event_alternatives[i][j]) 2178c2ecf20Sopenharmony_ci return i; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci return -1; 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistatic int mpc7450_get_alternatives(u64 event, unsigned int flags, u64 alt[]) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci int i, j, nalt = 1; 2258c2ecf20Sopenharmony_ci u32 ae; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci alt[0] = event; 2288c2ecf20Sopenharmony_ci nalt = 1; 2298c2ecf20Sopenharmony_ci i = find_alternative((u32)event); 2308c2ecf20Sopenharmony_ci if (i >= 0) { 2318c2ecf20Sopenharmony_ci for (j = 0; j < MAX_ALT; ++j) { 2328c2ecf20Sopenharmony_ci ae = event_alternatives[i][j]; 2338c2ecf20Sopenharmony_ci if (ae && ae != (u32)event) 2348c2ecf20Sopenharmony_ci alt[nalt++] = ae; 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci return nalt; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci/* 2418c2ecf20Sopenharmony_ci * Bitmaps of which PMCs each class can use for classes 0 - 3. 2428c2ecf20Sopenharmony_ci * Bit i is set if PMC i+1 is usable. 2438c2ecf20Sopenharmony_ci */ 2448c2ecf20Sopenharmony_cistatic const u8 classmap[N_CLASSES] = { 2458c2ecf20Sopenharmony_ci 0x3f, 0x0f, 0x0b, 0x03, 0 2468c2ecf20Sopenharmony_ci}; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci/* Bit position and width of each PMCSEL field */ 2498c2ecf20Sopenharmony_cistatic const int pmcsel_shift[N_COUNTER] = { 2508c2ecf20Sopenharmony_ci 6, 0, 27, 22, 17, 11 2518c2ecf20Sopenharmony_ci}; 2528c2ecf20Sopenharmony_cistatic const u32 pmcsel_mask[N_COUNTER] = { 2538c2ecf20Sopenharmony_ci 0x7f, 0x3f, 0x1f, 0x1f, 0x1f, 0x3f 2548c2ecf20Sopenharmony_ci}; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci/* 2578c2ecf20Sopenharmony_ci * Compute MMCR0/1/2 values for a set of events. 2588c2ecf20Sopenharmony_ci */ 2598c2ecf20Sopenharmony_cistatic int mpc7450_compute_mmcr(u64 event[], int n_ev, unsigned int hwc[], 2608c2ecf20Sopenharmony_ci struct mmcr_regs *mmcr, 2618c2ecf20Sopenharmony_ci struct perf_event *pevents[]) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci u8 event_index[N_CLASSES][N_COUNTER]; 2648c2ecf20Sopenharmony_ci int n_classevent[N_CLASSES]; 2658c2ecf20Sopenharmony_ci int i, j, class, tuse; 2668c2ecf20Sopenharmony_ci u32 pmc_inuse = 0, pmc_avail; 2678c2ecf20Sopenharmony_ci u32 mmcr0 = 0, mmcr1 = 0, mmcr2 = 0; 2688c2ecf20Sopenharmony_ci u32 ev, pmc, thresh; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci if (n_ev > N_COUNTER) 2718c2ecf20Sopenharmony_ci return -1; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci /* First pass: count usage in each class */ 2748c2ecf20Sopenharmony_ci for (i = 0; i < N_CLASSES; ++i) 2758c2ecf20Sopenharmony_ci n_classevent[i] = 0; 2768c2ecf20Sopenharmony_ci for (i = 0; i < n_ev; ++i) { 2778c2ecf20Sopenharmony_ci class = mpc7450_classify_event(event[i]); 2788c2ecf20Sopenharmony_ci if (class < 0) 2798c2ecf20Sopenharmony_ci return -1; 2808c2ecf20Sopenharmony_ci j = n_classevent[class]++; 2818c2ecf20Sopenharmony_ci event_index[class][j] = i; 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci /* Second pass: allocate PMCs from most specific event to least */ 2858c2ecf20Sopenharmony_ci for (class = N_CLASSES - 1; class >= 0; --class) { 2868c2ecf20Sopenharmony_ci for (i = 0; i < n_classevent[class]; ++i) { 2878c2ecf20Sopenharmony_ci ev = event[event_index[class][i]]; 2888c2ecf20Sopenharmony_ci if (class == 4) { 2898c2ecf20Sopenharmony_ci pmc = (ev >> PM_PMC_SH) & PM_PMC_MSK; 2908c2ecf20Sopenharmony_ci if (pmc_inuse & (1 << (pmc - 1))) 2918c2ecf20Sopenharmony_ci return -1; 2928c2ecf20Sopenharmony_ci } else { 2938c2ecf20Sopenharmony_ci /* Find a suitable PMC */ 2948c2ecf20Sopenharmony_ci pmc_avail = classmap[class] & ~pmc_inuse; 2958c2ecf20Sopenharmony_ci if (!pmc_avail) 2968c2ecf20Sopenharmony_ci return -1; 2978c2ecf20Sopenharmony_ci pmc = ffs(pmc_avail); 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci pmc_inuse |= 1 << (pmc - 1); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci tuse = mpc7450_threshold_use(ev); 3028c2ecf20Sopenharmony_ci if (tuse) { 3038c2ecf20Sopenharmony_ci thresh = (ev >> PM_THRESH_SH) & PM_THRESH_MSK; 3048c2ecf20Sopenharmony_ci mmcr0 |= thresh << 16; 3058c2ecf20Sopenharmony_ci if (tuse == 2 && (ev & PM_THRMULT_MSKS)) 3068c2ecf20Sopenharmony_ci mmcr2 = 0x80000000; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci ev &= pmcsel_mask[pmc - 1]; 3098c2ecf20Sopenharmony_ci ev <<= pmcsel_shift[pmc - 1]; 3108c2ecf20Sopenharmony_ci if (pmc <= 2) 3118c2ecf20Sopenharmony_ci mmcr0 |= ev; 3128c2ecf20Sopenharmony_ci else 3138c2ecf20Sopenharmony_ci mmcr1 |= ev; 3148c2ecf20Sopenharmony_ci hwc[event_index[class][i]] = pmc - 1; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci if (pmc_inuse & 1) 3198c2ecf20Sopenharmony_ci mmcr0 |= MMCR0_PMC1CE; 3208c2ecf20Sopenharmony_ci if (pmc_inuse & 0x3e) 3218c2ecf20Sopenharmony_ci mmcr0 |= MMCR0_PMCnCE; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci /* Return MMCRx values */ 3248c2ecf20Sopenharmony_ci mmcr->mmcr0 = mmcr0; 3258c2ecf20Sopenharmony_ci mmcr->mmcr1 = mmcr1; 3268c2ecf20Sopenharmony_ci mmcr->mmcr2 = mmcr2; 3278c2ecf20Sopenharmony_ci /* 3288c2ecf20Sopenharmony_ci * 32-bit doesn't have an MMCRA and uses SPRN_MMCR2 to define 3298c2ecf20Sopenharmony_ci * SPRN_MMCRA. So assign mmcra of cpu_hw_events with `mmcr2` 3308c2ecf20Sopenharmony_ci * value to ensure that any write to this SPRN_MMCRA will 3318c2ecf20Sopenharmony_ci * use mmcr2 value. 3328c2ecf20Sopenharmony_ci */ 3338c2ecf20Sopenharmony_ci mmcr->mmcra = mmcr2; 3348c2ecf20Sopenharmony_ci return 0; 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci/* 3388c2ecf20Sopenharmony_ci * Disable counting by a PMC. 3398c2ecf20Sopenharmony_ci * Note that the pmc argument is 0-based here, not 1-based. 3408c2ecf20Sopenharmony_ci */ 3418c2ecf20Sopenharmony_cistatic void mpc7450_disable_pmc(unsigned int pmc, struct mmcr_regs *mmcr) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci if (pmc <= 1) 3448c2ecf20Sopenharmony_ci mmcr->mmcr0 &= ~(pmcsel_mask[pmc] << pmcsel_shift[pmc]); 3458c2ecf20Sopenharmony_ci else 3468c2ecf20Sopenharmony_ci mmcr->mmcr1 &= ~(pmcsel_mask[pmc] << pmcsel_shift[pmc]); 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic int mpc7450_generic_events[] = { 3508c2ecf20Sopenharmony_ci [PERF_COUNT_HW_CPU_CYCLES] = 1, 3518c2ecf20Sopenharmony_ci [PERF_COUNT_HW_INSTRUCTIONS] = 2, 3528c2ecf20Sopenharmony_ci [PERF_COUNT_HW_CACHE_MISSES] = 0x217, /* PM_L1_DCACHE_MISS */ 3538c2ecf20Sopenharmony_ci [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x122, /* PM_BR_CMPL */ 3548c2ecf20Sopenharmony_ci [PERF_COUNT_HW_BRANCH_MISSES] = 0x41c, /* PM_BR_MPRED */ 3558c2ecf20Sopenharmony_ci}; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci#define C(x) PERF_COUNT_HW_CACHE_##x 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci/* 3608c2ecf20Sopenharmony_ci * Table of generalized cache-related events. 3618c2ecf20Sopenharmony_ci * 0 means not supported, -1 means nonsensical, other values 3628c2ecf20Sopenharmony_ci * are event codes. 3638c2ecf20Sopenharmony_ci */ 3648c2ecf20Sopenharmony_cistatic u64 mpc7450_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = { 3658c2ecf20Sopenharmony_ci [C(L1D)] = { /* RESULT_ACCESS RESULT_MISS */ 3668c2ecf20Sopenharmony_ci [C(OP_READ)] = { 0, 0x225 }, 3678c2ecf20Sopenharmony_ci [C(OP_WRITE)] = { 0, 0x227 }, 3688c2ecf20Sopenharmony_ci [C(OP_PREFETCH)] = { 0, 0 }, 3698c2ecf20Sopenharmony_ci }, 3708c2ecf20Sopenharmony_ci [C(L1I)] = { /* RESULT_ACCESS RESULT_MISS */ 3718c2ecf20Sopenharmony_ci [C(OP_READ)] = { 0x129, 0x115 }, 3728c2ecf20Sopenharmony_ci [C(OP_WRITE)] = { -1, -1 }, 3738c2ecf20Sopenharmony_ci [C(OP_PREFETCH)] = { 0x634, 0 }, 3748c2ecf20Sopenharmony_ci }, 3758c2ecf20Sopenharmony_ci [C(LL)] = { /* RESULT_ACCESS RESULT_MISS */ 3768c2ecf20Sopenharmony_ci [C(OP_READ)] = { 0, 0 }, 3778c2ecf20Sopenharmony_ci [C(OP_WRITE)] = { 0, 0 }, 3788c2ecf20Sopenharmony_ci [C(OP_PREFETCH)] = { 0, 0 }, 3798c2ecf20Sopenharmony_ci }, 3808c2ecf20Sopenharmony_ci [C(DTLB)] = { /* RESULT_ACCESS RESULT_MISS */ 3818c2ecf20Sopenharmony_ci [C(OP_READ)] = { 0, 0x312 }, 3828c2ecf20Sopenharmony_ci [C(OP_WRITE)] = { -1, -1 }, 3838c2ecf20Sopenharmony_ci [C(OP_PREFETCH)] = { -1, -1 }, 3848c2ecf20Sopenharmony_ci }, 3858c2ecf20Sopenharmony_ci [C(ITLB)] = { /* RESULT_ACCESS RESULT_MISS */ 3868c2ecf20Sopenharmony_ci [C(OP_READ)] = { 0, 0x223 }, 3878c2ecf20Sopenharmony_ci [C(OP_WRITE)] = { -1, -1 }, 3888c2ecf20Sopenharmony_ci [C(OP_PREFETCH)] = { -1, -1 }, 3898c2ecf20Sopenharmony_ci }, 3908c2ecf20Sopenharmony_ci [C(BPU)] = { /* RESULT_ACCESS RESULT_MISS */ 3918c2ecf20Sopenharmony_ci [C(OP_READ)] = { 0x122, 0x41c }, 3928c2ecf20Sopenharmony_ci [C(OP_WRITE)] = { -1, -1 }, 3938c2ecf20Sopenharmony_ci [C(OP_PREFETCH)] = { -1, -1 }, 3948c2ecf20Sopenharmony_ci }, 3958c2ecf20Sopenharmony_ci [C(NODE)] = { /* RESULT_ACCESS RESULT_MISS */ 3968c2ecf20Sopenharmony_ci [C(OP_READ)] = { -1, -1 }, 3978c2ecf20Sopenharmony_ci [C(OP_WRITE)] = { -1, -1 }, 3988c2ecf20Sopenharmony_ci [C(OP_PREFETCH)] = { -1, -1 }, 3998c2ecf20Sopenharmony_ci }, 4008c2ecf20Sopenharmony_ci}; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_cistruct power_pmu mpc7450_pmu = { 4038c2ecf20Sopenharmony_ci .name = "MPC7450 family", 4048c2ecf20Sopenharmony_ci .n_counter = N_COUNTER, 4058c2ecf20Sopenharmony_ci .max_alternatives = MAX_ALT, 4068c2ecf20Sopenharmony_ci .add_fields = 0x00111555ul, 4078c2ecf20Sopenharmony_ci .test_adder = 0x00301000ul, 4088c2ecf20Sopenharmony_ci .compute_mmcr = mpc7450_compute_mmcr, 4098c2ecf20Sopenharmony_ci .get_constraint = mpc7450_get_constraint, 4108c2ecf20Sopenharmony_ci .get_alternatives = mpc7450_get_alternatives, 4118c2ecf20Sopenharmony_ci .disable_pmc = mpc7450_disable_pmc, 4128c2ecf20Sopenharmony_ci .n_generic = ARRAY_SIZE(mpc7450_generic_events), 4138c2ecf20Sopenharmony_ci .generic_events = mpc7450_generic_events, 4148c2ecf20Sopenharmony_ci .cache_events = &mpc7450_cache_events, 4158c2ecf20Sopenharmony_ci}; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic int __init init_mpc7450_pmu(void) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci if (!cur_cpu_spec->oprofile_cpu_type || 4208c2ecf20Sopenharmony_ci strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc/7450")) 4218c2ecf20Sopenharmony_ci return -ENODEV; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci return register_power_pmu(&mpc7450_pmu); 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ciearly_initcall(init_mpc7450_pmu); 427