1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 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 #include <sys/param.h> 32 #include <sys/pmc.h> 33 #include <sys/pmckern.h> 34 #include <sys/systm.h> 35 36 #include <machine/pmc_mdep.h> 37 #include <machine/spr.h> 38 #include <machine/cpu.h> 39 40 #include "hwpmc_powerpc.h" 41 42 #define POWER8_MAX_PMCS 6 43 44 #define PM_EVENT_CODE(pe) (pe & 0xffff) 45 #define PM_EVENT_COUNTER(pe) ((pe >> 16) & 0xffff) 46 47 #define PM_CYC 0x1e 48 #define PM_INST_CMPL 0x02 49 50 static void 51 power8_set_pmc(int cpu, int ri, int config) 52 { 53 register_t mmcr; 54 55 /* Select event */ 56 switch (ri) { 57 case 0: 58 case 1: 59 case 2: 60 case 3: 61 mmcr = mfspr(SPR_MMCR1); 62 mmcr &= ~SPR_MMCR1_P8_PMCNSEL_MASK(ri); 63 mmcr |= SPR_MMCR1_P8_PMCNSEL(ri, config & ~POWERPC_PMC_ENABLE); 64 mtspr(SPR_MMCR1, mmcr); 65 break; 66 } 67 68 /* 69 * By default, freeze counter in all states. 70 * If counter is being started, unfreeze it in selected states. 71 */ 72 mmcr = mfspr(SPR_MMCR2) | SPR_MMCR2_FCNHSP(ri); 73 if (config != PMCN_NONE) { 74 if (config & POWERPC_PMC_USER_ENABLE) 75 mmcr &= ~(SPR_MMCR2_FCNP0(ri) | 76 SPR_MMCR2_FCNP1(ri)); 77 if (config & POWERPC_PMC_KERNEL_ENABLE) 78 mmcr &= ~(SPR_MMCR2_FCNH(ri) | 79 SPR_MMCR2_FCNS(ri)); 80 } 81 mtspr(SPR_MMCR2, mmcr); 82 } 83 84 static int 85 power8_pcpu_init(struct pmc_mdep *md, int cpu) 86 { 87 register_t mmcr0; 88 int i; 89 90 powerpc_pcpu_init(md, cpu); 91 92 /* Freeze all counters before modifying PMC registers */ 93 mmcr0 = mfspr(SPR_MMCR0) | SPR_MMCR0_FC; 94 mtspr(SPR_MMCR0, mmcr0); 95 96 /* 97 * Now setup MMCR0: 98 * - PMAO=0: clear alerts 99 * - FCPC=0, FCP=0: don't freeze counters in problem state 100 * - FCECE: Freeze Counters on Enabled Condition or Event 101 * - PMC1CE/PMCNCE: PMC1/N Condition Enable 102 */ 103 mmcr0 &= ~(SPR_MMCR0_PMAO | SPR_MMCR0_FCPC | SPR_MMCR0_FCP); 104 mmcr0 |= SPR_MMCR0_FCECE | SPR_MMCR0_PMC1CE | SPR_MMCR0_PMCNCE; 105 mtspr(SPR_MMCR0, mmcr0); 106 107 /* Clear all PMCs to prevent enabled condition interrupts */ 108 for (i = 0; i < POWER8_MAX_PMCS; i++) 109 powerpc_pmcn_write(i, 0); 110 111 /* Disable events in PMCs 1-4 */ 112 mtspr(SPR_MMCR1, mfspr(SPR_MMCR1) & ~SPR_MMCR1_P8_PMCSEL_ALL); 113 114 /* Freeze each counter, in all states */ 115 mtspr(SPR_MMCR2, mfspr(SPR_MMCR2) | 116 SPR_MMCR2_FCNHSP(0) | SPR_MMCR2_FCNHSP(1) | SPR_MMCR2_FCNHSP(2) | 117 SPR_MMCR2_FCNHSP(3) | SPR_MMCR2_FCNHSP(4) | SPR_MMCR2_FCNHSP(5)); 118 119 /* Enable interrupts, unset global freeze */ 120 mmcr0 &= ~SPR_MMCR0_FC; 121 mmcr0 |= SPR_MMCR0_PMAE; 122 mtspr(SPR_MMCR0, mmcr0); 123 return (0); 124 } 125 126 static int 127 power8_pcpu_fini(struct pmc_mdep *md, int cpu) 128 { 129 register_t mmcr0; 130 131 /* Freeze counters, disable interrupts */ 132 mmcr0 = mfspr(SPR_MMCR0); 133 mmcr0 &= ~SPR_MMCR0_PMAE; 134 mmcr0 |= SPR_MMCR0_FC; 135 mtspr(SPR_MMCR0, mmcr0); 136 137 return (powerpc_pcpu_fini(md, cpu)); 138 } 139 140 static void 141 power8_resume_pmc(bool ie) 142 { 143 register_t mmcr0; 144 145 /* Unfreeze counters and re-enable PERF exceptions if requested. */ 146 mmcr0 = mfspr(SPR_MMCR0); 147 mmcr0 &= ~(SPR_MMCR0_FC | SPR_MMCR0_PMAO | SPR_MMCR0_PMAE); 148 if (ie) 149 mmcr0 |= SPR_MMCR0_PMAE; 150 mtspr(SPR_MMCR0, mmcr0); 151 } 152 153 static int 154 power8_allocate_pmc(int cpu, int ri, struct pmc *pm, 155 const struct pmc_op_pmcallocate *a) 156 { 157 uint32_t caps, config, counter, pe; 158 159 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 160 ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu)); 161 KASSERT(ri >= 0 && ri < ppc_max_pmcs, 162 ("[powerpc,%d] illegal row index %d", __LINE__, ri)); 163 164 pe = a->pm_md.pm_event; 165 counter = PM_EVENT_COUNTER(pe); 166 config = PM_EVENT_CODE(pe); 167 168 if (a->pm_class != PMC_CLASS_POWER8) 169 return (EINVAL); 170 171 if ((a->pm_flags & PMC_F_EV_PMU) == 0) 172 return (EINVAL); 173 174 /* 175 * PMC5 and PMC6 are not programmable and always count instructions 176 * completed and cycles, respectively. 177 * 178 * When counter is 0 any of the 4 programmable PMCs may be used for 179 * the specified event, otherwise it must match ri + 1. 180 */ 181 if (counter == 0 && config == PM_INST_CMPL) 182 counter = 5; 183 else if (counter == 0 && config == PM_CYC) 184 counter = 6; 185 else if (counter > 4) 186 return (EINVAL); 187 188 if (counter != 0 && counter != ri + 1) 189 return (EINVAL); 190 191 caps = a->pm_caps; 192 193 if (caps & PMC_CAP_SYSTEM) 194 config |= POWERPC_PMC_KERNEL_ENABLE; 195 if (caps & PMC_CAP_USER) 196 config |= POWERPC_PMC_USER_ENABLE; 197 if ((caps & (PMC_CAP_USER | PMC_CAP_SYSTEM)) == 0) 198 config |= POWERPC_PMC_ENABLE; 199 200 pm->pm_md.pm_powerpc.pm_powerpc_evsel = config; 201 202 PMCDBG3(MDP,ALL,1,"powerpc-allocate cpu=%d ri=%d -> config=0x%x", 203 cpu, ri, config); 204 return (0); 205 } 206 207 int 208 pmc_power8_initialize(struct pmc_mdep *pmc_mdep) 209 { 210 struct pmc_classdep *pcd; 211 212 pmc_mdep->pmd_cputype = PMC_CPU_PPC_POWER8; 213 214 pcd = &pmc_mdep->pmd_classdep[PMC_MDEP_CLASS_INDEX_POWERPC]; 215 pcd->pcd_caps = POWERPC_PMC_CAPS; 216 pcd->pcd_class = PMC_CLASS_POWER8; 217 pcd->pcd_num = POWER8_MAX_PMCS; 218 pcd->pcd_ri = pmc_mdep->pmd_npmc; 219 pcd->pcd_width = 32; 220 221 pcd->pcd_pcpu_init = power8_pcpu_init; 222 pcd->pcd_pcpu_fini = power8_pcpu_fini; 223 pcd->pcd_allocate_pmc = power8_allocate_pmc; 224 pcd->pcd_release_pmc = powerpc_release_pmc; 225 pcd->pcd_start_pmc = powerpc_start_pmc; 226 pcd->pcd_stop_pmc = powerpc_stop_pmc; 227 pcd->pcd_get_config = powerpc_get_config; 228 pcd->pcd_config_pmc = powerpc_config_pmc; 229 pcd->pcd_describe = powerpc_describe; 230 pcd->pcd_read_pmc = powerpc_read_pmc; 231 pcd->pcd_write_pmc = powerpc_write_pmc; 232 233 pmc_mdep->pmd_npmc += POWER8_MAX_PMCS; 234 pmc_mdep->pmd_intr = powerpc_pmc_intr; 235 236 ppc_max_pmcs = POWER8_MAX_PMCS; 237 238 powerpc_set_pmc = power8_set_pmc; 239 powerpc_pmcn_read = powerpc_pmcn_read_default; 240 powerpc_pmcn_write = powerpc_pmcn_write_default; 241 powerpc_resume_pmc = power8_resume_pmc; 242 243 return (0); 244 } 245