1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2013 Justin Hibbits 5 * Copyright (c) 2020 Leandro Lupori 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 #include <sys/param.h> 34 #include <sys/pmc.h> 35 #include <sys/pmckern.h> 36 #include <sys/systm.h> 37 38 #include <machine/pmc_mdep.h> 39 #include <machine/spr.h> 40 #include <machine/cpu.h> 41 42 #include "hwpmc_powerpc.h" 43 44 #define POWER8_MAX_PMCS 6 45 46 static struct pmc_ppc_event power8_event_codes[] = { 47 {PMC_EV_POWER8_INSTR_COMPLETED, 48 .pe_flags = PMC_FLAG_PMC5, 49 .pe_code = 0x00 50 }, 51 /* 52 * PMC1 can also count cycles, but as PMC6 can only count cycles 53 * it's better to always use it and leave PMC1 free to count 54 * other events. 55 */ 56 {PMC_EV_POWER8_CYCLES, 57 .pe_flags = PMC_FLAG_PMC6, 58 .pe_code = 0xf0 59 }, 60 {PMC_EV_POWER8_CYCLES_WITH_INSTRS_COMPLETED, 61 .pe_flags = PMC_FLAG_PMC1, 62 .pe_code = 0xf2 63 }, 64 {PMC_EV_POWER8_FPU_INSTR_COMPLETED, 65 .pe_flags = PMC_FLAG_PMC1, 66 .pe_code = 0xf4 67 }, 68 {PMC_EV_POWER8_ERAT_INSTR_MISS, 69 .pe_flags = PMC_FLAG_PMC1, 70 .pe_code = 0xf6 71 }, 72 {PMC_EV_POWER8_CYCLES_IDLE, 73 .pe_flags = PMC_FLAG_PMC1, 74 .pe_code = 0xf8 75 }, 76 {PMC_EV_POWER8_CYCLES_WITH_ANY_THREAD_RUNNING, 77 .pe_flags = PMC_FLAG_PMC1, 78 .pe_code = 0xfa 79 }, 80 {PMC_EV_POWER8_STORE_COMPLETED, 81 .pe_flags = PMC_FLAG_PMC2, 82 .pe_code = 0xf0 83 }, 84 {PMC_EV_POWER8_INSTR_DISPATCHED, 85 .pe_flags = PMC_FLAG_PMC2 | PMC_FLAG_PMC3, 86 .pe_code = 0xf2 87 }, 88 {PMC_EV_POWER8_CYCLES_RUNNING, 89 .pe_flags = PMC_FLAG_PMC2, 90 .pe_code = 0xf4 91 }, 92 {PMC_EV_POWER8_ERAT_DATA_MISS, 93 .pe_flags = PMC_FLAG_PMC2, 94 .pe_code = 0xf6 95 }, 96 {PMC_EV_POWER8_EXTERNAL_INTERRUPT, 97 .pe_flags = PMC_FLAG_PMC2, 98 .pe_code = 0xf8 99 }, 100 {PMC_EV_POWER8_BRANCH_TAKEN, 101 .pe_flags = PMC_FLAG_PMC2, 102 .pe_code = 0xfa 103 }, 104 {PMC_EV_POWER8_L1_INSTR_MISS, 105 .pe_flags = PMC_FLAG_PMC2, 106 .pe_code = 0xfc 107 }, 108 {PMC_EV_POWER8_L2_LOAD_MISS, 109 .pe_flags = PMC_FLAG_PMC2, 110 .pe_code = 0xfe 111 }, 112 {PMC_EV_POWER8_STORE_NO_REAL_ADDR, 113 .pe_flags = PMC_FLAG_PMC3, 114 .pe_code = 0xf0 115 }, 116 {PMC_EV_POWER8_INSTR_COMPLETED_WITH_ALL_THREADS_RUNNING, 117 .pe_flags = PMC_FLAG_PMC3, 118 .pe_code = 0xf4 119 }, 120 {PMC_EV_POWER8_L1_LOAD_MISS, 121 .pe_flags = PMC_FLAG_PMC3, 122 .pe_code = 0xf6 123 }, 124 {PMC_EV_POWER8_TIMEBASE_EVENT, 125 .pe_flags = PMC_FLAG_PMC3, 126 .pe_code = 0xf8 127 }, 128 {PMC_EV_POWER8_L3_INSTR_MISS, 129 .pe_flags = PMC_FLAG_PMC3, 130 .pe_code = 0xfa 131 }, 132 {PMC_EV_POWER8_TLB_DATA_MISS, 133 .pe_flags = PMC_FLAG_PMC3, 134 .pe_code = 0xfc 135 }, 136 {PMC_EV_POWER8_L3_LOAD_MISS, 137 .pe_flags = PMC_FLAG_PMC3, 138 .pe_code = 0xfe 139 }, 140 {PMC_EV_POWER8_LOAD_NO_REAL_ADDR, 141 .pe_flags = PMC_FLAG_PMC4, 142 .pe_code = 0xf0 143 }, 144 {PMC_EV_POWER8_CYCLES_WITH_INSTRS_DISPATCHED, 145 .pe_flags = PMC_FLAG_PMC4, 146 .pe_code = 0xf2 147 }, 148 {PMC_EV_POWER8_CYCLES_RUNNING_PURR_INC, 149 .pe_flags = PMC_FLAG_PMC4, 150 .pe_code = 0xf4 151 }, 152 {PMC_EV_POWER8_BRANCH_MISPREDICTED, 153 .pe_flags = PMC_FLAG_PMC4, 154 .pe_code = 0xf6 155 }, 156 {PMC_EV_POWER8_PREFETCHED_INSTRS_DISCARDED, 157 .pe_flags = PMC_FLAG_PMC4, 158 .pe_code = 0xf8 159 }, 160 {PMC_EV_POWER8_INSTR_COMPLETED_RUNNING, 161 .pe_flags = PMC_FLAG_PMC4, 162 .pe_code = 0xfa 163 }, 164 {PMC_EV_POWER8_TLB_INSTR_MISS, 165 .pe_flags = PMC_FLAG_PMC4, 166 .pe_code = 0xfc 167 }, 168 {PMC_EV_POWER8_CACHE_LOAD_MISS, 169 .pe_flags = PMC_FLAG_PMC4, 170 .pe_code = 0xfe 171 } 172 }; 173 static size_t power8_event_codes_size = nitems(power8_event_codes); 174 175 static void 176 power8_set_pmc(int cpu, int ri, int config) 177 { 178 register_t mmcr; 179 180 /* Select event */ 181 switch (ri) { 182 case 0: 183 case 1: 184 case 2: 185 case 3: 186 mmcr = mfspr(SPR_MMCR1); 187 mmcr &= ~SPR_MMCR1_P8_PMCNSEL_MASK(ri); 188 mmcr |= SPR_MMCR1_P8_PMCNSEL(ri, config & ~POWERPC_PMC_ENABLE); 189 mtspr(SPR_MMCR1, mmcr); 190 break; 191 } 192 193 /* 194 * By default, freeze counter in all states. 195 * If counter is being started, unfreeze it in selected states. 196 */ 197 mmcr = mfspr(SPR_MMCR2) | SPR_MMCR2_FCNHSP(ri); 198 if (config != PMCN_NONE) { 199 if (config & POWERPC_PMC_USER_ENABLE) 200 mmcr &= ~(SPR_MMCR2_FCNP0(ri) | 201 SPR_MMCR2_FCNP1(ri)); 202 if (config & POWERPC_PMC_KERNEL_ENABLE) 203 mmcr &= ~(SPR_MMCR2_FCNH(ri) | 204 SPR_MMCR2_FCNS(ri)); 205 } 206 mtspr(SPR_MMCR2, mmcr); 207 } 208 209 static int 210 power8_pcpu_init(struct pmc_mdep *md, int cpu) 211 { 212 register_t mmcr0; 213 int i; 214 215 powerpc_pcpu_init(md, cpu); 216 217 /* Freeze all counters before modifying PMC registers */ 218 mmcr0 = mfspr(SPR_MMCR0) | SPR_MMCR0_FC; 219 mtspr(SPR_MMCR0, mmcr0); 220 221 /* 222 * Now setup MMCR0: 223 * - PMAO=0: clear alerts 224 * - FCPC=0, FCP=0: don't freeze counters in problem state 225 * - FCECE: Freeze Counters on Enabled Condition or Event 226 * - PMC1CE/PMCNCE: PMC1/N Condition Enable 227 */ 228 mmcr0 &= ~(SPR_MMCR0_PMAO | SPR_MMCR0_FCPC | SPR_MMCR0_FCP); 229 mmcr0 |= SPR_MMCR0_FCECE | SPR_MMCR0_PMC1CE | SPR_MMCR0_PMCNCE; 230 mtspr(SPR_MMCR0, mmcr0); 231 232 /* Clear all PMCs to prevent enabled condition interrupts */ 233 for (i = 0; i < POWER8_MAX_PMCS; i++) 234 powerpc_pmcn_write(i, 0); 235 236 /* Disable events in PMCs 1-4 */ 237 mtspr(SPR_MMCR1, mfspr(SPR_MMCR1) & ~SPR_MMCR1_P8_PMCSEL_ALL); 238 239 /* Freeze each counter, in all states */ 240 mtspr(SPR_MMCR2, mfspr(SPR_MMCR2) | 241 SPR_MMCR2_FCNHSP(0) | SPR_MMCR2_FCNHSP(1) | SPR_MMCR2_FCNHSP(2) | 242 SPR_MMCR2_FCNHSP(3) | SPR_MMCR2_FCNHSP(4) | SPR_MMCR2_FCNHSP(5)); 243 244 /* Enable interrupts, unset global freeze */ 245 mmcr0 &= ~SPR_MMCR0_FC; 246 mmcr0 |= SPR_MMCR0_PMAE; 247 mtspr(SPR_MMCR0, mmcr0); 248 return (0); 249 } 250 251 static int 252 power8_pcpu_fini(struct pmc_mdep *md, int cpu) 253 { 254 register_t mmcr0; 255 256 /* Freeze counters, disable interrupts */ 257 mmcr0 = mfspr(SPR_MMCR0); 258 mmcr0 &= ~SPR_MMCR0_PMAE; 259 mmcr0 |= SPR_MMCR0_FC; 260 mtspr(SPR_MMCR0, mmcr0); 261 262 return (powerpc_pcpu_fini(md, cpu)); 263 } 264 265 static void 266 power8_resume_pmc(bool ie) 267 { 268 register_t mmcr0; 269 270 /* Unfreeze counters and re-enable PERF exceptions if requested. */ 271 mmcr0 = mfspr(SPR_MMCR0); 272 mmcr0 &= ~(SPR_MMCR0_FC | SPR_MMCR0_PMAO | SPR_MMCR0_PMAE); 273 if (ie) 274 mmcr0 |= SPR_MMCR0_PMAE; 275 mtspr(SPR_MMCR0, mmcr0); 276 } 277 278 int 279 pmc_power8_initialize(struct pmc_mdep *pmc_mdep) 280 { 281 struct pmc_classdep *pcd; 282 283 pmc_mdep->pmd_cputype = PMC_CPU_PPC_POWER8; 284 285 pcd = &pmc_mdep->pmd_classdep[PMC_MDEP_CLASS_INDEX_POWERPC]; 286 pcd->pcd_caps = POWERPC_PMC_CAPS; 287 pcd->pcd_class = PMC_CLASS_POWER8; 288 pcd->pcd_num = POWER8_MAX_PMCS; 289 pcd->pcd_ri = pmc_mdep->pmd_npmc; 290 pcd->pcd_width = 32; 291 292 pcd->pcd_pcpu_init = power8_pcpu_init; 293 pcd->pcd_pcpu_fini = power8_pcpu_fini; 294 pcd->pcd_allocate_pmc = powerpc_allocate_pmc; 295 pcd->pcd_release_pmc = powerpc_release_pmc; 296 pcd->pcd_start_pmc = powerpc_start_pmc; 297 pcd->pcd_stop_pmc = powerpc_stop_pmc; 298 pcd->pcd_get_config = powerpc_get_config; 299 pcd->pcd_config_pmc = powerpc_config_pmc; 300 pcd->pcd_describe = powerpc_describe; 301 pcd->pcd_read_pmc = powerpc_read_pmc; 302 pcd->pcd_write_pmc = powerpc_write_pmc; 303 304 pmc_mdep->pmd_npmc += POWER8_MAX_PMCS; 305 pmc_mdep->pmd_intr = powerpc_pmc_intr; 306 307 ppc_event_codes = power8_event_codes; 308 ppc_event_codes_size = power8_event_codes_size; 309 ppc_event_first = PMC_EV_POWER8_FIRST; 310 ppc_event_last = PMC_EV_POWER8_LAST; 311 ppc_max_pmcs = POWER8_MAX_PMCS; 312 313 powerpc_set_pmc = power8_set_pmc; 314 powerpc_pmcn_read = powerpc_pmcn_read_default; 315 powerpc_pmcn_write = powerpc_pmcn_write_default; 316 powerpc_resume_pmc = power8_resume_pmc; 317 318 return (0); 319 } 320