1261342Sjhibbits/*- 2261342Sjhibbits * Copyright (c) 2013 Justin Hibbits 3261342Sjhibbits * All rights reserved. 4261342Sjhibbits * 5261342Sjhibbits * Redistribution and use in source and binary forms, with or without 6261342Sjhibbits * modification, are permitted provided that the following conditions 7261342Sjhibbits * are met: 8261342Sjhibbits * 1. Redistributions of source code must retain the above copyright 9261342Sjhibbits * notice, this list of conditions and the following disclaimer. 10261342Sjhibbits * 2. Redistributions in binary form must reproduce the above copyright 11261342Sjhibbits * notice, this list of conditions and the following disclaimer in the 12261342Sjhibbits * documentation and/or other materials provided with the distribution. 13261342Sjhibbits * 14261342Sjhibbits * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15261342Sjhibbits * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16261342Sjhibbits * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17261342Sjhibbits * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18261342Sjhibbits * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19261342Sjhibbits * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20261342Sjhibbits * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21261342Sjhibbits * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22261342Sjhibbits * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23261342Sjhibbits * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24261342Sjhibbits * SUCH DAMAGE. 25261342Sjhibbits * 26261342Sjhibbits */ 27261342Sjhibbits 28261342Sjhibbits#include <sys/cdefs.h> 29261342Sjhibbits__FBSDID("$FreeBSD$"); 30261342Sjhibbits 31261342Sjhibbits#include <sys/param.h> 32261342Sjhibbits#include <sys/pmc.h> 33261342Sjhibbits#include <sys/pmckern.h> 34261342Sjhibbits#include <sys/systm.h> 35261342Sjhibbits 36261342Sjhibbits#include <machine/pmc_mdep.h> 37261342Sjhibbits#include <machine/spr.h> 38261342Sjhibbits#include <machine/cpu.h> 39261342Sjhibbits 40261342Sjhibbits#include "hwpmc_powerpc.h" 41261342Sjhibbits 42261342Sjhibbits#define PPC970_MAX_PMCS 8 43261342Sjhibbits 44261342Sjhibbits/* MMCR0, PMC1 is 8 bytes in, PMC2 is 1 byte in. */ 45261342Sjhibbits#define PPC970_SET_MMCR0_PMCSEL(r, x, i) \ 46261342Sjhibbits ((r & ~(0x1f << (7 * (1 - i) + 1))) | (x << (7 * (1 - i) + 1))) 47261342Sjhibbits/* MMCR1 has 6 PMC*SEL items (PMC3->PMC8), in sequence. */ 48261342Sjhibbits#define PPC970_SET_MMCR1_PMCSEL(r, x, i) \ 49261342Sjhibbits ((r & ~(0x1f << (5 * (7 - i) + 2))) | (x << (5 * (7 - i) + 2))) 50261342Sjhibbits 51261342Sjhibbits#define PPC970_PMC_HAS_OVERFLOWED(x) (ppc970_pmcn_read(x) & (0x1 << 31)) 52261342Sjhibbits 53261342Sjhibbits/* How PMC works on PPC970: 54261342Sjhibbits * 55261342Sjhibbits * Any PMC can count a direct event. Indirect events are handled specially. 56261342Sjhibbits * Direct events: As published. 57261342Sjhibbits * 58261342Sjhibbits * Encoding 00 000 -- Add byte lane bit counters 59261342Sjhibbits * MMCR1[24:31] -- select bit matching PMC being an adder. 60261342Sjhibbits * Bus events: 61261342Sjhibbits * PMCxSEL: 1x -- select from byte lane: 10 == lower lane (0/1), 11 == upper 62261342Sjhibbits * lane (2/3). 63261342Sjhibbits * PMCxSEL[2:4] -- bit in the byte lane selected. 64261342Sjhibbits * 65261342Sjhibbits * PMC[1,2,5,6] == lane 0/lane 2 66261342Sjhibbits * PMC[3,4,7,8] == lane 1,3 67261342Sjhibbits * 68261342Sjhibbits * 69261342Sjhibbits * Lanes: 70261342Sjhibbits * Lane 0 -- TTM0(FPU,ISU,IFU,VPU) 71261342Sjhibbits * TTM1(IDU,ISU,STS) 72261342Sjhibbits * LSU0 byte 0 73261342Sjhibbits * LSU1 byte 0 74261342Sjhibbits * Lane 1 -- TTM0 75261342Sjhibbits * TTM1 76261342Sjhibbits * LSU0 byte 1 77261342Sjhibbits * LSU1 byte 1 78261342Sjhibbits * Lane 2 -- TTM0 79261342Sjhibbits * TTM1 80261342Sjhibbits * LSU0 byte 2 81261342Sjhibbits * LSU1 byte 2 or byte 6 82261342Sjhibbits * Lane 3 -- TTM0 83261342Sjhibbits * TTM1 84261342Sjhibbits * LSU0 byte 3 85261342Sjhibbits * LSU1 byte 3 or byte 7 86261342Sjhibbits * 87261342Sjhibbits * Adders: 88261342Sjhibbits * Add byte lane for PMC (above), bit 0+4, 1+5, 2+6, 3+7 89261342Sjhibbits */ 90261342Sjhibbits 91261342Sjhibbitsstruct pmc_ppc970_event { 92261342Sjhibbits enum pmc_event pe_event; 93261342Sjhibbits uint32_t pe_flags; 94261342Sjhibbits#define PMC_PPC970_FLAG_PMCS 0x000000ff 95261342Sjhibbits#define PMC_PPC970_FLAG_PMC1 0x01 96261342Sjhibbits#define PMC_PPC970_FLAG_PMC2 0x02 97261342Sjhibbits#define PMC_PPC970_FLAG_PMC3 0x04 98261342Sjhibbits#define PMC_PPC970_FLAG_PMC4 0x08 99261342Sjhibbits#define PMC_PPC970_FLAG_PMC5 0x10 100261342Sjhibbits#define PMC_PPC970_FLAG_PMC6 0x20 101261342Sjhibbits#define PMC_PPC970_FLAG_PMC7 0x40 102261342Sjhibbits#define PMC_PPC970_FLAG_PMC8 0x80 103261342Sjhibbits uint32_t pe_code; 104261342Sjhibbits}; 105261342Sjhibbits 106261342Sjhibbitsstatic struct pmc_ppc970_event ppc970_event_codes[] = { 107261342Sjhibbits {PMC_EV_PPC970_INSTR_COMPLETED, 108261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMCS, 109261342Sjhibbits .pe_code = 0x09 110261342Sjhibbits }, 111261342Sjhibbits {PMC_EV_PPC970_MARKED_GROUP_DISPATCH, 112261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC1, 113261342Sjhibbits .pe_code = 0x2 114261342Sjhibbits }, 115261342Sjhibbits {PMC_EV_PPC970_MARKED_STORE_COMPLETED, 116261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC1, 117261342Sjhibbits .pe_code = 0x03 118261342Sjhibbits }, 119261342Sjhibbits {PMC_EV_PPC970_GCT_EMPTY, 120261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC1, 121261342Sjhibbits .pe_code = 0x04 122261342Sjhibbits }, 123261342Sjhibbits {PMC_EV_PPC970_RUN_CYCLES, 124261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC1, 125261342Sjhibbits .pe_code = 0x05 126261342Sjhibbits }, 127261342Sjhibbits {PMC_EV_PPC970_OVERFLOW, 128261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMCS, 129261342Sjhibbits .pe_code = 0x0a 130261342Sjhibbits }, 131261342Sjhibbits {PMC_EV_PPC970_CYCLES, 132261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMCS, 133261342Sjhibbits .pe_code = 0x0f 134261342Sjhibbits }, 135261342Sjhibbits {PMC_EV_PPC970_THRESHOLD_TIMEOUT, 136261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC2, 137261342Sjhibbits .pe_code = 0x3 138261342Sjhibbits }, 139261342Sjhibbits {PMC_EV_PPC970_GROUP_DISPATCH, 140261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC2, 141261342Sjhibbits .pe_code = 0x4 142261342Sjhibbits }, 143261342Sjhibbits {PMC_EV_PPC970_BR_MARKED_INSTR_FINISH, 144261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC2, 145261342Sjhibbits .pe_code = 0x5 146261342Sjhibbits }, 147261342Sjhibbits {PMC_EV_PPC970_GCT_EMPTY_BY_SRQ_FULL, 148261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC2, 149261342Sjhibbits .pe_code = 0xb 150261342Sjhibbits }, 151261342Sjhibbits {PMC_EV_PPC970_STOP_COMPLETION, 152261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC3, 153261342Sjhibbits .pe_code = 0x1 154261342Sjhibbits }, 155261342Sjhibbits {PMC_EV_PPC970_LSU_EMPTY, 156261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC3, 157261342Sjhibbits .pe_code = 0x2 158261342Sjhibbits }, 159261342Sjhibbits {PMC_EV_PPC970_MARKED_STORE_WITH_INTR, 160261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC3, 161261342Sjhibbits .pe_code = 0x3 162261342Sjhibbits }, 163261342Sjhibbits {PMC_EV_PPC970_CYCLES_IN_SUPER, 164261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC3, 165261342Sjhibbits .pe_code = 0x4 166261342Sjhibbits }, 167261342Sjhibbits {PMC_EV_PPC970_VPU_MARKED_INSTR_COMPLETED, 168261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC3, 169261342Sjhibbits .pe_code = 0x5 170261342Sjhibbits }, 171261342Sjhibbits {PMC_EV_PPC970_FXU0_IDLE_FXU1_BUSY, 172261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC4, 173261342Sjhibbits .pe_code = 0x2 174261342Sjhibbits }, 175261342Sjhibbits {PMC_EV_PPC970_SRQ_EMPTY, 176261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC4, 177261342Sjhibbits .pe_code = 0x3 178261342Sjhibbits }, 179261342Sjhibbits {PMC_EV_PPC970_MARKED_GROUP_COMPLETED, 180261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC4, 181261342Sjhibbits .pe_code = 0x4 182261342Sjhibbits }, 183261342Sjhibbits {PMC_EV_PPC970_CR_MARKED_INSTR_FINISH, 184261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC4, 185261342Sjhibbits .pe_code = 0x5 186261342Sjhibbits }, 187261342Sjhibbits {PMC_EV_PPC970_DISPATCH_SUCCESS, 188261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC5, 189261342Sjhibbits .pe_code = 0x1 190261342Sjhibbits }, 191261342Sjhibbits {PMC_EV_PPC970_FXU0_IDLE_FXU1_IDLE, 192261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC5, 193261342Sjhibbits .pe_code = 0x2 194261342Sjhibbits }, 195261342Sjhibbits {PMC_EV_PPC970_ONE_PLUS_INSTR_COMPLETED, 196261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC5, 197261342Sjhibbits .pe_code = 0x3 198261342Sjhibbits }, 199261342Sjhibbits {PMC_EV_PPC970_GROUP_MARKED_IDU, 200261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC5, 201261342Sjhibbits .pe_code = 0x4 202261342Sjhibbits }, 203261342Sjhibbits {PMC_EV_PPC970_MARKED_GROUP_COMPLETE_TIMEOUT, 204261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC5, 205261342Sjhibbits .pe_code = 0x5 206261342Sjhibbits }, 207261342Sjhibbits {PMC_EV_PPC970_FXU0_BUSY_FXU1_BUSY, 208261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC6, 209261342Sjhibbits .pe_code = 0x2 210261342Sjhibbits }, 211261342Sjhibbits {PMC_EV_PPC970_MARKED_STORE_SENT_TO_STS, 212261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC6, 213261342Sjhibbits .pe_code = 0x3 214261342Sjhibbits }, 215261342Sjhibbits {PMC_EV_PPC970_FXU_MARKED_INSTR_FINISHED, 216261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC6, 217261342Sjhibbits .pe_code = 0x4 218261342Sjhibbits }, 219261342Sjhibbits {PMC_EV_PPC970_MARKED_GROUP_ISSUED, 220261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC6, 221261342Sjhibbits .pe_code = 0x5 222261342Sjhibbits }, 223261342Sjhibbits {PMC_EV_PPC970_FXU0_BUSY_FXU1_IDLE, 224261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC7, 225261342Sjhibbits .pe_code = 0x2 226261342Sjhibbits }, 227261342Sjhibbits {PMC_EV_PPC970_GROUP_COMPLETED, 228261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC7, 229261342Sjhibbits .pe_code = 0x3 230261342Sjhibbits }, 231261342Sjhibbits {PMC_EV_PPC970_FPU_MARKED_INSTR_COMPLETED, 232261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC7, 233261342Sjhibbits .pe_code = 0x4 234261342Sjhibbits }, 235261342Sjhibbits {PMC_EV_PPC970_MARKED_INSTR_FINISH_ANY_UNIT, 236261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC7, 237261342Sjhibbits .pe_code = 0x5 238261342Sjhibbits }, 239261342Sjhibbits {PMC_EV_PPC970_EXTERNAL_INTERRUPT, 240261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC8, 241261342Sjhibbits .pe_code = 0x2 242261342Sjhibbits }, 243261342Sjhibbits {PMC_EV_PPC970_GROUP_DISPATCH_REJECT, 244261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC8, 245261342Sjhibbits .pe_code = 0x3 246261342Sjhibbits }, 247261342Sjhibbits {PMC_EV_PPC970_LSU_MARKED_INSTR_FINISH, 248261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC8, 249261342Sjhibbits .pe_code = 0x4 250261342Sjhibbits }, 251261342Sjhibbits {PMC_EV_PPC970_TIMEBASE_EVENT, 252261342Sjhibbits .pe_flags = PMC_PPC970_FLAG_PMC8, 253261342Sjhibbits .pe_code = 0x5 254261342Sjhibbits }, 255261342Sjhibbits#if 0 256261342Sjhibbits {PMC_EV_PPC970_LSU_COMPLETION_STALL, }, 257261342Sjhibbits {PMC_EV_PPC970_FXU_COMPLETION_STALL, }, 258261342Sjhibbits {PMC_EV_PPC970_DCACHE_MISS_COMPLETION_STALL, }, 259261342Sjhibbits {PMC_EV_PPC970_FPU_COMPLETION_STALL, }, 260261342Sjhibbits {PMC_EV_PPC970_FXU_LONG_INSTR_COMPLETION_STALL, }, 261261342Sjhibbits {PMC_EV_PPC970_REJECT_COMPLETION_STALL, }, 262261342Sjhibbits {PMC_EV_PPC970_FPU_LONG_INSTR_COMPLETION_STALL, }, 263261342Sjhibbits {PMC_EV_PPC970_GCT_EMPTY_BY_ICACHE_MISS, }, 264261342Sjhibbits {PMC_EV_PPC970_REJECT_COMPLETION_STALL_ERAT_MISS, }, 265261342Sjhibbits {PMC_EV_PPC970_GCT_EMPTY_BY_BRANCH_MISS_PREDICT, }, 266261342Sjhibbits#endif 267261342Sjhibbits}; 268261342Sjhibbitsstatic size_t ppc970_event_codes_size = nitems(ppc970_event_codes); 269261342Sjhibbits 270261342Sjhibbitsstatic pmc_value_t 271261342Sjhibbitsppc970_pmcn_read(unsigned int pmc) 272261342Sjhibbits{ 273261342Sjhibbits pmc_value_t val; 274261342Sjhibbits 275261342Sjhibbits switch (pmc) { 276261342Sjhibbits case 0: 277261342Sjhibbits val = mfspr(SPR_970PMC1); 278261342Sjhibbits break; 279261342Sjhibbits case 1: 280261342Sjhibbits val = mfspr(SPR_970PMC2); 281261342Sjhibbits break; 282261342Sjhibbits case 2: 283261342Sjhibbits val = mfspr(SPR_970PMC3); 284261342Sjhibbits break; 285261342Sjhibbits case 3: 286261342Sjhibbits val = mfspr(SPR_970PMC4); 287261342Sjhibbits break; 288261342Sjhibbits case 4: 289261342Sjhibbits val = mfspr(SPR_970PMC5); 290261342Sjhibbits break; 291261342Sjhibbits case 5: 292261342Sjhibbits val = mfspr(SPR_970PMC6); 293261342Sjhibbits break; 294261342Sjhibbits case 6: 295261342Sjhibbits val = mfspr(SPR_970PMC7); 296261342Sjhibbits break; 297261342Sjhibbits case 7: 298261342Sjhibbits val = mfspr(SPR_970PMC8); 299261342Sjhibbits break; 300261342Sjhibbits default: 301261342Sjhibbits panic("Invalid PMC number: %d\n", pmc); 302261342Sjhibbits } 303261342Sjhibbits 304261342Sjhibbits return (val); 305261342Sjhibbits} 306261342Sjhibbits 307261342Sjhibbitsstatic void 308261342Sjhibbitsppc970_pmcn_write(unsigned int pmc, uint32_t val) 309261342Sjhibbits{ 310261342Sjhibbits switch (pmc) { 311261342Sjhibbits case 0: 312261342Sjhibbits mtspr(SPR_970PMC1, val); 313261342Sjhibbits break; 314261342Sjhibbits case 1: 315261342Sjhibbits mtspr(SPR_970PMC2, val); 316261342Sjhibbits break; 317261342Sjhibbits case 2: 318261342Sjhibbits mtspr(SPR_970PMC3, val); 319261342Sjhibbits break; 320261342Sjhibbits case 3: 321261342Sjhibbits mtspr(SPR_970PMC4, val); 322261342Sjhibbits break; 323261342Sjhibbits case 4: 324261342Sjhibbits mtspr(SPR_970PMC5, val); 325261342Sjhibbits break; 326261342Sjhibbits case 5: 327261342Sjhibbits mtspr(SPR_970PMC6, val); 328261342Sjhibbits break; 329261342Sjhibbits case 6: 330261342Sjhibbits mtspr(SPR_970PMC7, val); 331261342Sjhibbits break; 332261342Sjhibbits case 7: 333261342Sjhibbits mtspr(SPR_970PMC8, val); 334261342Sjhibbits break; 335261342Sjhibbits default: 336261342Sjhibbits panic("Invalid PMC number: %d\n", pmc); 337261342Sjhibbits } 338261342Sjhibbits} 339261342Sjhibbits 340261342Sjhibbitsstatic int 341261342Sjhibbitsppc970_config_pmc(int cpu, int ri, struct pmc *pm) 342261342Sjhibbits{ 343261342Sjhibbits struct pmc_hw *phw; 344261342Sjhibbits 345283884Sjhb PMCDBG3(MDP,CFG,1, "cpu=%d ri=%d pm=%p", cpu, ri, pm); 346261342Sjhibbits 347261342Sjhibbits KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 348261342Sjhibbits ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu)); 349261342Sjhibbits KASSERT(ri >= 0 && ri < PPC970_MAX_PMCS, 350261342Sjhibbits ("[powerpc,%d] illegal row-index %d", __LINE__, ri)); 351261342Sjhibbits 352261342Sjhibbits phw = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri]; 353261342Sjhibbits 354261342Sjhibbits KASSERT(pm == NULL || phw->phw_pmc == NULL, 355261342Sjhibbits ("[powerpc,%d] pm=%p phw->pm=%p hwpmc not unconfigured", 356261342Sjhibbits __LINE__, pm, phw->phw_pmc)); 357261342Sjhibbits 358261342Sjhibbits phw->phw_pmc = pm; 359261342Sjhibbits 360261342Sjhibbits return 0; 361261342Sjhibbits} 362261342Sjhibbits 363261342Sjhibbitsstatic int 364261342Sjhibbitsppc970_set_pmc(int cpu, int ri, int config) 365261342Sjhibbits{ 366261342Sjhibbits struct pmc *pm; 367261342Sjhibbits struct pmc_hw *phw; 368261342Sjhibbits register_t pmc_mmcr; 369261342Sjhibbits 370261342Sjhibbits phw = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri]; 371261342Sjhibbits pm = phw->phw_pmc; 372261342Sjhibbits 373261342Sjhibbits /* 374261342Sjhibbits * Disable the PMCs. 375261342Sjhibbits */ 376261342Sjhibbits switch (ri) { 377261342Sjhibbits case 0: 378261342Sjhibbits case 1: 379261342Sjhibbits pmc_mmcr = mfspr(SPR_970MMCR0); 380261342Sjhibbits pmc_mmcr = PPC970_SET_MMCR0_PMCSEL(pmc_mmcr, config, ri); 381261342Sjhibbits mtspr(SPR_970MMCR0, pmc_mmcr); 382261342Sjhibbits break; 383261342Sjhibbits case 2: 384261342Sjhibbits case 3: 385261342Sjhibbits case 4: 386261342Sjhibbits case 5: 387261342Sjhibbits case 6: 388261342Sjhibbits case 7: 389261342Sjhibbits pmc_mmcr = mfspr(SPR_970MMCR1); 390261342Sjhibbits pmc_mmcr = PPC970_SET_MMCR1_PMCSEL(pmc_mmcr, config, ri); 391261342Sjhibbits mtspr(SPR_970MMCR1, pmc_mmcr); 392261342Sjhibbits break; 393261342Sjhibbits } 394261342Sjhibbits return 0; 395261342Sjhibbits} 396261342Sjhibbits 397261342Sjhibbitsstatic int 398261342Sjhibbitsppc970_start_pmc(int cpu, int ri) 399261342Sjhibbits{ 400261342Sjhibbits struct pmc *pm; 401261342Sjhibbits struct pmc_hw *phw; 402261342Sjhibbits register_t pmc_mmcr; 403261342Sjhibbits uint32_t config; 404261342Sjhibbits int error; 405261342Sjhibbits 406261342Sjhibbits phw = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri]; 407261342Sjhibbits pm = phw->phw_pmc; 408261342Sjhibbits config = pm->pm_md.pm_powerpc.pm_powerpc_evsel & ~POWERPC_PMC_ENABLE; 409261342Sjhibbits 410261342Sjhibbits error = ppc970_set_pmc(cpu, ri, config); 411261342Sjhibbits 412261342Sjhibbits /* The mask is inverted (enable is 1) compared to the flags in MMCR0, which 413261342Sjhibbits * are Freeze flags. 414261342Sjhibbits */ 415261342Sjhibbits config = ~pm->pm_md.pm_powerpc.pm_powerpc_evsel & POWERPC_PMC_ENABLE; 416261342Sjhibbits 417261342Sjhibbits pmc_mmcr = mfspr(SPR_970MMCR0); 418261342Sjhibbits pmc_mmcr &= ~SPR_MMCR0_FC; 419261342Sjhibbits pmc_mmcr |= config; 420261342Sjhibbits mtspr(SPR_970MMCR0, pmc_mmcr); 421261342Sjhibbits 422261342Sjhibbits return 0; 423261342Sjhibbits} 424261342Sjhibbits 425261342Sjhibbitsstatic int 426261342Sjhibbitsppc970_stop_pmc(int cpu, int ri) 427261342Sjhibbits{ 428261342Sjhibbits return ppc970_set_pmc(cpu, ri, PMC970N_NONE); 429261342Sjhibbits} 430261342Sjhibbits 431261342Sjhibbitsstatic int 432261342Sjhibbitsppc970_read_pmc(int cpu, int ri, pmc_value_t *v) 433261342Sjhibbits{ 434261342Sjhibbits struct pmc *pm; 435261342Sjhibbits pmc_value_t tmp; 436261342Sjhibbits 437261342Sjhibbits KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 438261342Sjhibbits ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu)); 439261342Sjhibbits KASSERT(ri >= 0 && ri < PPC970_MAX_PMCS, 440261342Sjhibbits ("[powerpc,%d] illegal row index %d", __LINE__, ri)); 441261342Sjhibbits 442261342Sjhibbits pm = powerpc_pcpu[cpu]->pc_ppcpmcs[ri].phw_pmc; 443261342Sjhibbits KASSERT(pm, 444261342Sjhibbits ("[core,%d] cpu %d ri %d pmc not configured", __LINE__, cpu, 445261342Sjhibbits ri)); 446261342Sjhibbits 447261342Sjhibbits tmp = ppc970_pmcn_read(ri); 448283884Sjhb PMCDBG2(MDP,REA,2,"ppc-read id=%d -> %jd", ri, tmp); 449261342Sjhibbits if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) 450261342Sjhibbits *v = POWERPC_PERFCTR_VALUE_TO_RELOAD_COUNT(tmp); 451261342Sjhibbits else 452261342Sjhibbits *v = tmp; 453261342Sjhibbits 454261342Sjhibbits return 0; 455261342Sjhibbits} 456261342Sjhibbits 457261342Sjhibbitsstatic int 458261342Sjhibbitsppc970_write_pmc(int cpu, int ri, pmc_value_t v) 459261342Sjhibbits{ 460261342Sjhibbits struct pmc *pm; 461261342Sjhibbits 462261342Sjhibbits KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 463261342Sjhibbits ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu)); 464261342Sjhibbits KASSERT(ri >= 0 && ri < PPC970_MAX_PMCS, 465261342Sjhibbits ("[powerpc,%d] illegal row-index %d", __LINE__, ri)); 466261342Sjhibbits 467261342Sjhibbits pm = powerpc_pcpu[cpu]->pc_ppcpmcs[ri].phw_pmc; 468261342Sjhibbits 469261342Sjhibbits if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) 470261342Sjhibbits v = POWERPC_RELOAD_COUNT_TO_PERFCTR_VALUE(v); 471261342Sjhibbits 472283884Sjhb PMCDBG3(MDP,WRI,1,"powerpc-write cpu=%d ri=%d v=%jx", cpu, ri, v); 473261342Sjhibbits 474261342Sjhibbits ppc970_pmcn_write(ri, v); 475261342Sjhibbits 476261342Sjhibbits return 0; 477261342Sjhibbits} 478261342Sjhibbits 479261342Sjhibbitsstatic int 480261342Sjhibbitsppc970_intr(int cpu, struct trapframe *tf) 481261342Sjhibbits{ 482261342Sjhibbits struct pmc *pm; 483261342Sjhibbits struct powerpc_cpu *pac; 484261342Sjhibbits pmc_value_t v; 485261342Sjhibbits uint32_t config; 486261342Sjhibbits int i, error, retval; 487261342Sjhibbits 488261342Sjhibbits KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 489261342Sjhibbits ("[powerpc,%d] out of range CPU %d", __LINE__, cpu)); 490261342Sjhibbits 491283884Sjhb PMCDBG3(MDP,INT,1, "cpu=%d tf=%p um=%d", cpu, (void *) tf, 492261342Sjhibbits TRAPF_USERMODE(tf)); 493261342Sjhibbits 494261342Sjhibbits retval = 0; 495261342Sjhibbits 496261342Sjhibbits pac = powerpc_pcpu[cpu]; 497261342Sjhibbits 498261342Sjhibbits /* 499261342Sjhibbits * look for all PMCs that have interrupted: 500261342Sjhibbits * - look for a running, sampling PMC which has overflowed 501261342Sjhibbits * and which has a valid 'struct pmc' association 502261342Sjhibbits * 503261342Sjhibbits * If found, we call a helper to process the interrupt. 504261342Sjhibbits */ 505261342Sjhibbits 506261342Sjhibbits config = mfspr(SPR_970MMCR0); 507261342Sjhibbits mtspr(SPR_970MMCR0, config | SPR_MMCR0_FC); 508261342Sjhibbits for (i = 0; i < PPC970_MAX_PMCS; i++) { 509261342Sjhibbits if ((pm = pac->pc_ppcpmcs[i].phw_pmc) == NULL || 510261342Sjhibbits !PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) { 511261342Sjhibbits continue; 512261342Sjhibbits } 513261342Sjhibbits 514261342Sjhibbits if (!PPC970_PMC_HAS_OVERFLOWED(i)) 515261342Sjhibbits continue; 516261342Sjhibbits 517261342Sjhibbits retval = 1; /* Found an interrupting PMC. */ 518261342Sjhibbits 519261342Sjhibbits if (pm->pm_state != PMC_STATE_RUNNING) 520261342Sjhibbits continue; 521261342Sjhibbits 522261342Sjhibbits /* Stop the PMC, reload count. */ 523261342Sjhibbits v = pm->pm_sc.pm_reloadcount; 524261342Sjhibbits 525261342Sjhibbits ppc970_pmcn_write(i, v); 526261342Sjhibbits 527261342Sjhibbits /* Restart the counter if logging succeeded. */ 528261342Sjhibbits error = pmc_process_interrupt(cpu, PMC_HR, pm, tf, 529261342Sjhibbits TRAPF_USERMODE(tf)); 530261342Sjhibbits mtspr(SPR_970MMCR0, config); 531261342Sjhibbits if (error != 0) 532261342Sjhibbits ppc970_stop_pmc(cpu, i); 533261342Sjhibbits atomic_add_int(retval ? &pmc_stats.pm_intr_processed : 534261342Sjhibbits &pmc_stats.pm_intr_ignored, 1); 535261342Sjhibbits 536261342Sjhibbits } 537261342Sjhibbits 538261342Sjhibbits /* Re-enable PERF exceptions. */ 539261342Sjhibbits mtspr(SPR_970MMCR0, mfspr(SPR_970MMCR0) | SPR_MMCR0_PMXE); 540261342Sjhibbits 541261342Sjhibbits return (retval); 542261342Sjhibbits} 543261342Sjhibbits 544261342Sjhibbitsstatic int 545261342Sjhibbitsppc970_pcpu_init(struct pmc_mdep *md, int cpu) 546261342Sjhibbits{ 547261342Sjhibbits struct pmc_cpu *pc; 548261342Sjhibbits struct powerpc_cpu *pac; 549261342Sjhibbits struct pmc_hw *phw; 550261342Sjhibbits int first_ri, i; 551261342Sjhibbits 552261342Sjhibbits KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 553261342Sjhibbits ("[powerpc,%d] wrong cpu number %d", __LINE__, cpu)); 554283884Sjhb PMCDBG1(MDP,INI,1,"powerpc-init cpu=%d", cpu); 555261342Sjhibbits 556261342Sjhibbits powerpc_pcpu[cpu] = pac = malloc(sizeof(struct powerpc_cpu), M_PMC, 557261342Sjhibbits M_WAITOK|M_ZERO); 558261342Sjhibbits pac->pc_ppcpmcs = malloc(sizeof(struct pmc_hw) * PPC970_MAX_PMCS, 559261342Sjhibbits M_PMC, M_WAITOK|M_ZERO); 560261342Sjhibbits pac->pc_class = PMC_CLASS_PPC970; 561261342Sjhibbits 562261342Sjhibbits pc = pmc_pcpu[cpu]; 563261342Sjhibbits first_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_PPC970].pcd_ri; 564261342Sjhibbits KASSERT(pc != NULL, ("[powerpc,%d] NULL per-cpu pointer", __LINE__)); 565261342Sjhibbits 566261342Sjhibbits for (i = 0, phw = pac->pc_ppcpmcs; i < PPC970_MAX_PMCS; i++, phw++) { 567261342Sjhibbits phw->phw_state = PMC_PHW_FLAG_IS_ENABLED | 568261342Sjhibbits PMC_PHW_CPU_TO_STATE(cpu) | PMC_PHW_INDEX_TO_STATE(i); 569261342Sjhibbits phw->phw_pmc = NULL; 570261342Sjhibbits pc->pc_hwpmcs[i + first_ri] = phw; 571261342Sjhibbits } 572261342Sjhibbits 573261342Sjhibbits /* Clear the MMCRs, and set FC, to disable all PMCs. */ 574261342Sjhibbits /* 970 PMC is not counted when set to 0x08 */ 575261342Sjhibbits mtspr(SPR_970MMCR0, SPR_MMCR0_FC | SPR_MMCR0_PMXE | SPR_MMCR0_PMC1CE | 576261342Sjhibbits SPR_MMCR0_PMCNCE | SPR_970MMCR0_PMC1SEL(0x8) | SPR_970MMCR0_PMC2SEL(0x8)); 577261342Sjhibbits mtspr(SPR_970MMCR1, 0x4218420); 578261342Sjhibbits 579261342Sjhibbits return 0; 580261342Sjhibbits} 581261342Sjhibbits 582261342Sjhibbitsstatic int 583261342Sjhibbitsppc970_pcpu_fini(struct pmc_mdep *md, int cpu) 584261342Sjhibbits{ 585261342Sjhibbits register_t mmcr0 = mfspr(SPR_MMCR0); 586261342Sjhibbits 587261342Sjhibbits mmcr0 |= SPR_MMCR0_FC; 588261342Sjhibbits mmcr0 &= ~SPR_MMCR0_PMXE; 589261342Sjhibbits mtspr(SPR_MMCR0, mmcr0); 590261342Sjhibbits free(powerpc_pcpu[cpu]->pc_ppcpmcs, M_PMC); 591261342Sjhibbits free(powerpc_pcpu[cpu], M_PMC); 592261342Sjhibbits return 0; 593261342Sjhibbits} 594261342Sjhibbits 595261342Sjhibbitsstatic int 596261342Sjhibbitsppc970_allocate_pmc(int cpu, int ri, struct pmc *pm, 597261342Sjhibbits const struct pmc_op_pmcallocate *a) 598261342Sjhibbits{ 599261342Sjhibbits enum pmc_event pe; 600261342Sjhibbits uint32_t caps, config = 0, counter = 0; 601261342Sjhibbits int i; 602261342Sjhibbits 603261342Sjhibbits KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 604261342Sjhibbits ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu)); 605261342Sjhibbits KASSERT(ri >= 0 && ri < PPC970_MAX_PMCS, 606261342Sjhibbits ("[powerpc,%d] illegal row index %d", __LINE__, ri)); 607261342Sjhibbits 608261342Sjhibbits caps = a->pm_caps; 609261342Sjhibbits 610261342Sjhibbits pe = a->pm_ev; 611261342Sjhibbits 612261342Sjhibbits if (pe < PMC_EV_PPC970_FIRST || pe > PMC_EV_PPC970_LAST) 613261342Sjhibbits return (EINVAL); 614261342Sjhibbits 615261342Sjhibbits for (i = 0; i < ppc970_event_codes_size; i++) { 616261342Sjhibbits if (ppc970_event_codes[i].pe_event == pe) { 617261342Sjhibbits config = ppc970_event_codes[i].pe_code; 618261342Sjhibbits counter = ppc970_event_codes[i].pe_flags; 619261342Sjhibbits break; 620261342Sjhibbits } 621261342Sjhibbits } 622261342Sjhibbits if (i == ppc970_event_codes_size) 623261342Sjhibbits return (EINVAL); 624261342Sjhibbits 625261342Sjhibbits if ((counter & (1 << ri)) == 0) 626261342Sjhibbits return (EINVAL); 627261342Sjhibbits 628261342Sjhibbits if (caps & PMC_CAP_SYSTEM) 629261342Sjhibbits config |= POWERPC_PMC_KERNEL_ENABLE; 630261342Sjhibbits if (caps & PMC_CAP_USER) 631261342Sjhibbits config |= POWERPC_PMC_USER_ENABLE; 632261342Sjhibbits if ((caps & (PMC_CAP_USER | PMC_CAP_SYSTEM)) == 0) 633261342Sjhibbits config |= POWERPC_PMC_ENABLE; 634261342Sjhibbits 635261342Sjhibbits pm->pm_md.pm_powerpc.pm_powerpc_evsel = config; 636261342Sjhibbits 637283884Sjhb PMCDBG2(MDP,ALL,2,"powerpc-allocate ri=%d -> config=0x%x", ri, config); 638261342Sjhibbits 639261342Sjhibbits return 0; 640261342Sjhibbits} 641261342Sjhibbits 642261342Sjhibbitsstatic int 643261342Sjhibbitsppc970_release_pmc(int cpu, int ri, struct pmc *pmc) 644261342Sjhibbits{ 645261342Sjhibbits struct pmc_hw *phw; 646261342Sjhibbits 647261342Sjhibbits KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 648261342Sjhibbits ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu)); 649261342Sjhibbits KASSERT(ri >= 0 && ri < PPC970_MAX_PMCS, 650261342Sjhibbits ("[powerpc,%d] illegal row-index %d", __LINE__, ri)); 651261342Sjhibbits 652261342Sjhibbits phw = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri]; 653261342Sjhibbits KASSERT(phw->phw_pmc == NULL, 654261342Sjhibbits ("[powerpc,%d] PHW pmc %p non-NULL", __LINE__, phw->phw_pmc)); 655261342Sjhibbits 656261342Sjhibbits return 0; 657261342Sjhibbits} 658261342Sjhibbits 659261342Sjhibbitsint 660261342Sjhibbitspmc_ppc970_initialize(struct pmc_mdep *pmc_mdep) 661261342Sjhibbits{ 662261342Sjhibbits struct pmc_classdep *pcd; 663261342Sjhibbits 664261342Sjhibbits pmc_mdep->pmd_cputype = PMC_CPU_PPC_970; 665261342Sjhibbits 666261342Sjhibbits pcd = &pmc_mdep->pmd_classdep[PMC_MDEP_CLASS_INDEX_PPC970]; 667261342Sjhibbits pcd->pcd_caps = POWERPC_PMC_CAPS; 668261342Sjhibbits pcd->pcd_class = PMC_CLASS_PPC970; 669261342Sjhibbits pcd->pcd_num = PPC970_MAX_PMCS; 670261342Sjhibbits pcd->pcd_ri = pmc_mdep->pmd_npmc; 671261342Sjhibbits pcd->pcd_width = 32; 672261342Sjhibbits 673261342Sjhibbits pcd->pcd_allocate_pmc = ppc970_allocate_pmc; 674261342Sjhibbits pcd->pcd_config_pmc = ppc970_config_pmc; 675261342Sjhibbits pcd->pcd_pcpu_fini = ppc970_pcpu_fini; 676261342Sjhibbits pcd->pcd_pcpu_init = ppc970_pcpu_init; 677261342Sjhibbits pcd->pcd_describe = powerpc_describe; 678261342Sjhibbits pcd->pcd_get_config = powerpc_get_config; 679261342Sjhibbits pcd->pcd_read_pmc = ppc970_read_pmc; 680261342Sjhibbits pcd->pcd_release_pmc = ppc970_release_pmc; 681261342Sjhibbits pcd->pcd_start_pmc = ppc970_start_pmc; 682261342Sjhibbits pcd->pcd_stop_pmc = ppc970_stop_pmc; 683261342Sjhibbits pcd->pcd_write_pmc = ppc970_write_pmc; 684261342Sjhibbits 685261342Sjhibbits pmc_mdep->pmd_npmc += PPC970_MAX_PMCS; 686261342Sjhibbits pmc_mdep->pmd_intr = ppc970_intr; 687261342Sjhibbits 688261342Sjhibbits return (0); 689261342Sjhibbits} 690