hwpmc_mips24k.c revision 267654
1/*- 2 * Copyright (c) 2010 George V. Neville-Neil <gnn@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 */ 27 28#include <sys/cdefs.h> 29__FBSDID("$FreeBSD: releng/9.3/sys/dev/hwpmc/hwpmc_mips24k.c 204635 2010-03-03 15:05:58Z gnn $"); 30 31#include <sys/param.h> 32#include <sys/systm.h> 33#include <sys/pmc.h> 34#include <sys/pmckern.h> 35 36#include <machine/cpu.h> 37#include <machine/cpufunc.h> 38#include <machine/cputypes.h> 39#include <machine/pmc_mdep.h> 40 41/* 42 * Support for MIPS CPUs 43 * 44 */ 45static int mips24k_npmcs; 46 47struct mips24k_event_code_map { 48 enum pmc_event pe_ev; /* enum value */ 49 uint8_t pe_counter; /* Which counter this can be counted in. */ 50 uint8_t pe_code; /* numeric code */ 51}; 52 53/* 54 * MIPS event codes are encoded with a select bit. The 55 * select bit is used when writing to CP0 so that we 56 * can select either counter 0/2 or 1/3. The cycle 57 * and instruction counters are special in that they 58 * can be counted on either 0/2 or 1/3. 59 */ 60 61#define MIPS24K_ALL 255 /* Count events in any counter. */ 62#define MIPS24K_CTR_0 0 /* Counter 0 Event */ 63#define MIPS24K_CTR_1 1 /* Counter 1 Event */ 64 65const struct mips24k_event_code_map mips24k_event_codes[] = { 66 { PMC_EV_MIPS24K_CYCLE, MIPS24K_ALL, 0}, 67 { PMC_EV_MIPS24K_INSTR_EXECUTED, MIPS24K_ALL, 1}, 68 { PMC_EV_MIPS24K_BRANCH_COMPLETED, MIPS24K_CTR_0, 2}, 69 { PMC_EV_MIPS24K_BRANCH_MISPRED, MIPS24K_CTR_1, 2}, 70 { PMC_EV_MIPS24K_RETURN, MIPS24K_CTR_0, 3}, 71 { PMC_EV_MIPS24K_RETURN_MISPRED, MIPS24K_CTR_1, 3}, 72 { PMC_EV_MIPS24K_RETURN_NOT_31, MIPS24K_CTR_0, 4}, 73 { PMC_EV_MIPS24K_RETURN_NOTPRED, MIPS24K_CTR_1, 4}, 74 { PMC_EV_MIPS24K_ITLB_ACCESS, MIPS24K_CTR_0, 5}, 75 { PMC_EV_MIPS24K_ITLB_MISS, MIPS24K_CTR_1, 5}, 76 { PMC_EV_MIPS24K_DTLB_ACCESS, MIPS24K_CTR_0, 6}, 77 { PMC_EV_MIPS24K_DTLB_MISS, MIPS24K_CTR_1, 6}, 78 { PMC_EV_MIPS24K_JTLB_IACCESS, MIPS24K_CTR_0, 7}, 79 { PMC_EV_MIPS24K_JTLB_IMISS, MIPS24K_CTR_1, 7}, 80 { PMC_EV_MIPS24K_JTLB_DACCESS, MIPS24K_CTR_0, 8}, 81 { PMC_EV_MIPS24K_JTLB_DMISS, MIPS24K_CTR_1, 8}, 82 { PMC_EV_MIPS24K_IC_FETCH, MIPS24K_CTR_0, 9}, 83 { PMC_EV_MIPS24K_IC_MISS, MIPS24K_CTR_1, 9}, 84 { PMC_EV_MIPS24K_DC_LOADSTORE, MIPS24K_CTR_0, 10}, 85 { PMC_EV_MIPS24K_DC_WRITEBACK, MIPS24K_CTR_1, 10}, 86 { PMC_EV_MIPS24K_DC_MISS, MIPS24K_ALL, 11}, 87 /* 12 reserved */ 88 { PMC_EV_MIPS24K_STORE_MISS, MIPS24K_CTR_0, 13}, 89 { PMC_EV_MIPS24K_LOAD_MISS, MIPS24K_CTR_1, 13}, 90 { PMC_EV_MIPS24K_INTEGER_COMPLETED, MIPS24K_CTR_0, 14}, 91 { PMC_EV_MIPS24K_FP_COMPLETED, MIPS24K_CTR_1, 14}, 92 { PMC_EV_MIPS24K_LOAD_COMPLETED, MIPS24K_CTR_0, 15}, 93 { PMC_EV_MIPS24K_STORE_COMPLETED, MIPS24K_CTR_1, 15}, 94 { PMC_EV_MIPS24K_BARRIER_COMPLETED, MIPS24K_CTR_0, 16}, 95 { PMC_EV_MIPS24K_MIPS16_COMPLETED, MIPS24K_CTR_1, 16}, 96 { PMC_EV_MIPS24K_NOP_COMPLETED, MIPS24K_CTR_0, 17}, 97 { PMC_EV_MIPS24K_INTEGER_MULDIV_COMPLETED, MIPS24K_CTR_1, 17}, 98 { PMC_EV_MIPS24K_RF_STALL, MIPS24K_CTR_0, 18}, 99 { PMC_EV_MIPS24K_INSTR_REFETCH, MIPS24K_CTR_1, 18}, 100 { PMC_EV_MIPS24K_STORE_COND_COMPLETED, MIPS24K_CTR_0, 19}, 101 { PMC_EV_MIPS24K_STORE_COND_FAILED, MIPS24K_CTR_1, 19}, 102 { PMC_EV_MIPS24K_ICACHE_REQUESTS, MIPS24K_CTR_0, 20}, 103 { PMC_EV_MIPS24K_ICACHE_HIT, MIPS24K_CTR_1, 20}, 104 { PMC_EV_MIPS24K_L2_WRITEBACK, MIPS24K_CTR_0, 21}, 105 { PMC_EV_MIPS24K_L2_ACCESS, MIPS24K_CTR_1, 21}, 106 { PMC_EV_MIPS24K_L2_MISS, MIPS24K_CTR_0, 22}, 107 { PMC_EV_MIPS24K_L2_ERR_CORRECTED, MIPS24K_CTR_1, 22}, 108 { PMC_EV_MIPS24K_EXCEPTIONS, MIPS24K_CTR_0, 23}, 109 /* Event 23 on COP0 1/3 is undefined */ 110 { PMC_EV_MIPS24K_RF_CYCLES_STALLED, MIPS24K_CTR_0, 24}, 111 { PMC_EV_MIPS24K_IFU_CYCLES_STALLED, MIPS24K_CTR_0, 25}, 112 { PMC_EV_MIPS24K_ALU_CYCLES_STALLED, MIPS24K_CTR_1, 25}, 113 /* Events 26 through 32 undefined or reserved to customers */ 114 { PMC_EV_MIPS24K_UNCACHED_LOAD, MIPS24K_CTR_0, 33}, 115 { PMC_EV_MIPS24K_UNCACHED_STORE, MIPS24K_CTR_1, 33}, 116 { PMC_EV_MIPS24K_CP2_REG_TO_REG_COMPLETED, MIPS24K_CTR_0, 35}, 117 { PMC_EV_MIPS24K_MFTC_COMPLETED, MIPS24K_CTR_1, 35}, 118 /* Event 36 reserved */ 119 { PMC_EV_MIPS24K_IC_BLOCKED_CYCLES, MIPS24K_CTR_0, 37}, 120 { PMC_EV_MIPS24K_DC_BLOCKED_CYCLES, MIPS24K_CTR_1, 37}, 121 { PMC_EV_MIPS24K_L2_IMISS_STALL_CYCLES, MIPS24K_CTR_0, 38}, 122 { PMC_EV_MIPS24K_L2_DMISS_STALL_CYCLES, MIPS24K_CTR_1, 38}, 123 { PMC_EV_MIPS24K_DMISS_CYCLES, MIPS24K_CTR_0, 39}, 124 { PMC_EV_MIPS24K_L2_MISS_CYCLES, MIPS24K_CTR_1, 39}, 125 { PMC_EV_MIPS24K_UNCACHED_BLOCK_CYCLES, MIPS24K_CTR_0, 40}, 126 { PMC_EV_MIPS24K_MDU_STALL_CYCLES, MIPS24K_CTR_0, 41}, 127 { PMC_EV_MIPS24K_FPU_STALL_CYCLES, MIPS24K_CTR_1, 41}, 128 { PMC_EV_MIPS24K_CP2_STALL_CYCLES, MIPS24K_CTR_0, 42}, 129 { PMC_EV_MIPS24K_COREXTEND_STALL_CYCLES, MIPS24K_CTR_1, 42}, 130 { PMC_EV_MIPS24K_ISPRAM_STALL_CYCLES, MIPS24K_CTR_0, 43}, 131 { PMC_EV_MIPS24K_DSPRAM_STALL_CYCLES, MIPS24K_CTR_1, 43}, 132 { PMC_EV_MIPS24K_CACHE_STALL_CYCLES, MIPS24K_CTR_0, 44}, 133 /* Event 44 undefined on 1/3 */ 134 { PMC_EV_MIPS24K_LOAD_TO_USE_STALLS, MIPS24K_CTR_0, 45}, 135 { PMC_EV_MIPS24K_BASE_MISPRED_STALLS, MIPS24K_CTR_1, 45}, 136 { PMC_EV_MIPS24K_CPO_READ_STALLS, MIPS24K_CTR_0, 46}, 137 { PMC_EV_MIPS24K_BRANCH_MISPRED_CYCLES, MIPS24K_CTR_1, 46}, 138 /* Event 47 reserved */ 139 { PMC_EV_MIPS24K_IFETCH_BUFFER_FULL, MIPS24K_CTR_0, 48}, 140 { PMC_EV_MIPS24K_FETCH_BUFFER_ALLOCATED, MIPS24K_CTR_1, 48}, 141 { PMC_EV_MIPS24K_EJTAG_ITRIGGER, MIPS24K_CTR_0, 49}, 142 { PMC_EV_MIPS24K_EJTAG_DTRIGGER, MIPS24K_CTR_1, 49}, 143 { PMC_EV_MIPS24K_FSB_LT_QUARTER, MIPS24K_CTR_0, 50}, 144 { PMC_EV_MIPS24K_FSB_QUARTER_TO_HALF, MIPS24K_CTR_1, 50}, 145 { PMC_EV_MIPS24K_FSB_GT_HALF, MIPS24K_CTR_0, 51}, 146 { PMC_EV_MIPS24K_FSB_FULL_PIPELINE_STALLS, MIPS24K_CTR_1, 51}, 147 { PMC_EV_MIPS24K_LDQ_LT_QUARTER, MIPS24K_CTR_0, 52}, 148 { PMC_EV_MIPS24K_LDQ_QUARTER_TO_HALF, MIPS24K_CTR_1, 52}, 149 { PMC_EV_MIPS24K_LDQ_GT_HALF, MIPS24K_CTR_0, 53}, 150 { PMC_EV_MIPS24K_LDQ_FULL_PIPELINE_STALLS, MIPS24K_CTR_1, 53}, 151 { PMC_EV_MIPS24K_WBB_LT_QUARTER, MIPS24K_CTR_0, 54}, 152 { PMC_EV_MIPS24K_WBB_QUARTER_TO_HALF, MIPS24K_CTR_1, 54}, 153 { PMC_EV_MIPS24K_WBB_GT_HALF, MIPS24K_CTR_0, 55}, 154 { PMC_EV_MIPS24K_WBB_FULL_PIPELINE_STALLS, MIPS24K_CTR_1, 55}, 155 /* Events 56-63 reserved */ 156 { PMC_EV_MIPS24K_REQUEST_LATENCY, MIPS24K_CTR_0, 61}, 157 { PMC_EV_MIPS24K_REQUEST_COUNT, MIPS24K_CTR_1, 61} 158 159}; 160 161const int mips24k_event_codes_size = 162 sizeof(mips24k_event_codes) / sizeof(mips24k_event_codes[0]); 163 164/* 165 * Per-processor information. 166 */ 167struct mips24k_cpu { 168 struct pmc_hw *pc_mipspmcs; 169}; 170 171static struct mips24k_cpu **mips24k_pcpu; 172 173/* 174 * Performance Count Register N 175 */ 176static uint32_t 177mips24k_pmcn_read(unsigned int pmc) 178{ 179 uint32_t reg = 0; 180 181 KASSERT(pmc < mips24k_npmcs, ("[mips,%d] illegal PMC number %d", 182 __LINE__, pmc)); 183 184 /* The counter value is the next value after the control register. */ 185 switch (pmc) { 186 case 0: 187 reg = mips_rd_perfcnt1(); 188 break; 189 case 1: 190 reg = mips_rd_perfcnt3(); 191 break; 192 default: 193 return 0; 194 } 195 return (reg); 196} 197 198static uint32_t 199mips24k_pmcn_write(unsigned int pmc, uint32_t reg) 200{ 201 202 KASSERT(pmc < mips24k_npmcs, ("[mips,%d] illegal PMC number %d", 203 __LINE__, pmc)); 204 205 switch (pmc) { 206 case 0: 207 mips_wr_perfcnt1(reg); 208 break; 209 case 1: 210 mips_wr_perfcnt3(reg); 211 break; 212 default: 213 return 0; 214 } 215 return (reg); 216} 217 218static int 219mips24k_allocate_pmc(int cpu, int ri, struct pmc *pm, 220 const struct pmc_op_pmcallocate *a) 221{ 222 enum pmc_event pe; 223 uint32_t caps, config, counter; 224 int i; 225 226 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 227 ("[mips,%d] illegal CPU value %d", __LINE__, cpu)); 228 KASSERT(ri >= 0 && ri < mips24k_npmcs, 229 ("[mips,%d] illegal row index %d", __LINE__, ri)); 230 231 caps = a->pm_caps; 232 if (a->pm_class != PMC_CLASS_MIPS24K) 233 return (EINVAL); 234 pe = a->pm_ev; 235 for (i = 0; i < mips24k_event_codes_size; i++) { 236 if (mips24k_event_codes[i].pe_ev == pe) { 237 config = mips24k_event_codes[i].pe_code; 238 counter = mips24k_event_codes[i].pe_counter; 239 break; 240 } 241 } 242 if (i == mips24k_event_codes_size) 243 return (EINVAL); 244 245 if ((counter != MIPS24K_ALL) && (counter != ri)) 246 return (EINVAL); 247 248 config <<= MIPS24K_PMC_SELECT; 249 250 if (caps & PMC_CAP_SYSTEM) 251 config |= (MIPS24K_PMC_SUPER_ENABLE | 252 MIPS24K_PMC_KERNEL_ENABLE); 253 if (caps & PMC_CAP_USER) 254 config |= MIPS24K_PMC_USER_ENABLE; 255 if ((caps & (PMC_CAP_USER | PMC_CAP_SYSTEM)) == 0) 256 config |= MIPS24K_PMC_ENABLE; 257 258 pm->pm_md.pm_mips24k.pm_mips24k_evsel = config; 259 260 PMCDBG(MDP,ALL,2,"mips-allocate ri=%d -> config=0x%x", ri, config); 261 262 return 0; 263} 264 265 266static int 267mips24k_read_pmc(int cpu, int ri, pmc_value_t *v) 268{ 269 struct pmc *pm; 270 pmc_value_t tmp; 271 272 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 273 ("[mips,%d] illegal CPU value %d", __LINE__, cpu)); 274 KASSERT(ri >= 0 && ri < mips24k_npmcs, 275 ("[mips,%d] illegal row index %d", __LINE__, ri)); 276 277 pm = mips24k_pcpu[cpu]->pc_mipspmcs[ri].phw_pmc; 278 tmp = mips24k_pmcn_read(ri); 279 PMCDBG(MDP,REA,2,"mips-read id=%d -> %jd", ri, tmp); 280 if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) 281 *v = MIPS24K_PERFCTR_VALUE_TO_RELOAD_COUNT(tmp); 282 else 283 *v = tmp; 284 285 return 0; 286} 287 288static int 289mips24k_write_pmc(int cpu, int ri, pmc_value_t v) 290{ 291 struct pmc *pm; 292 293 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 294 ("[mips,%d] illegal CPU value %d", __LINE__, cpu)); 295 KASSERT(ri >= 0 && ri < mips24k_npmcs, 296 ("[mips,%d] illegal row-index %d", __LINE__, ri)); 297 298 pm = mips24k_pcpu[cpu]->pc_mipspmcs[ri].phw_pmc; 299 300 if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) 301 v = MIPS24K_RELOAD_COUNT_TO_PERFCTR_VALUE(v); 302 303 PMCDBG(MDP,WRI,1,"mips-write cpu=%d ri=%d v=%jx", cpu, ri, v); 304 305 mips24k_pmcn_write(ri, v); 306 307 return 0; 308} 309 310static int 311mips24k_config_pmc(int cpu, int ri, struct pmc *pm) 312{ 313 struct pmc_hw *phw; 314 315 PMCDBG(MDP,CFG,1, "cpu=%d ri=%d pm=%p", cpu, ri, pm); 316 317 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 318 ("[mips,%d] illegal CPU value %d", __LINE__, cpu)); 319 KASSERT(ri >= 0 && ri < mips24k_npmcs, 320 ("[mips,%d] illegal row-index %d", __LINE__, ri)); 321 322 phw = &mips24k_pcpu[cpu]->pc_mipspmcs[ri]; 323 324 KASSERT(pm == NULL || phw->phw_pmc == NULL, 325 ("[mips,%d] pm=%p phw->pm=%p hwpmc not unconfigured", 326 __LINE__, pm, phw->phw_pmc)); 327 328 phw->phw_pmc = pm; 329 330 return 0; 331} 332 333static int 334mips24k_start_pmc(int cpu, int ri) 335{ 336 uint32_t config; 337 struct pmc *pm; 338 struct pmc_hw *phw; 339 340 phw = &mips24k_pcpu[cpu]->pc_mipspmcs[ri]; 341 pm = phw->phw_pmc; 342 config = pm->pm_md.pm_mips24k.pm_mips24k_evsel; 343 344 /* Enable the PMC. */ 345 switch (ri) { 346 case 0: 347 mips_wr_perfcnt0(config); 348 break; 349 case 1: 350 mips_wr_perfcnt2(config); 351 break; 352 default: 353 break; 354 } 355 356 return 0; 357} 358 359static int 360mips24k_stop_pmc(int cpu, int ri) 361{ 362 struct pmc *pm; 363 struct pmc_hw *phw; 364 365 phw = &mips24k_pcpu[cpu]->pc_mipspmcs[ri]; 366 pm = phw->phw_pmc; 367 368 /* 369 * Disable the PMCs. 370 * 371 * Clearing the entire register turns the counter off as well 372 * as removes the previously sampled event. 373 */ 374 switch (ri) { 375 case 0: 376 mips_wr_perfcnt0(0); 377 break; 378 case 1: 379 mips_wr_perfcnt2(0); 380 break; 381 default: 382 break; 383 } 384 return 0; 385} 386 387static int 388mips24k_release_pmc(int cpu, int ri, struct pmc *pmc) 389{ 390 struct pmc_hw *phw; 391 392 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 393 ("[mips,%d] illegal CPU value %d", __LINE__, cpu)); 394 KASSERT(ri >= 0 && ri < mips24k_npmcs, 395 ("[mips,%d] illegal row-index %d", __LINE__, ri)); 396 397 phw = &mips24k_pcpu[cpu]->pc_mipspmcs[ri]; 398 KASSERT(phw->phw_pmc == NULL, 399 ("[mips,%d] PHW pmc %p non-NULL", __LINE__, phw->phw_pmc)); 400 401 return 0; 402} 403 404static int 405mips24k_intr(int cpu, struct trapframe *tf) 406{ 407 return 0; 408} 409 410static int 411mips24k_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc) 412{ 413 int error; 414 struct pmc_hw *phw; 415 char mips24k_name[PMC_NAME_MAX]; 416 417 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 418 ("[mips,%d], illegal CPU %d", __LINE__, cpu)); 419 KASSERT(ri >= 0 && ri < mips24k_npmcs, 420 ("[mips,%d] row-index %d out of range", __LINE__, ri)); 421 422 phw = &mips24k_pcpu[cpu]->pc_mipspmcs[ri]; 423 snprintf(mips24k_name, sizeof(mips24k_name), "MIPS-%d", ri); 424 if ((error = copystr(mips24k_name, pi->pm_name, PMC_NAME_MAX, 425 NULL)) != 0) 426 return error; 427 pi->pm_class = PMC_CLASS_MIPS24K; 428 if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) { 429 pi->pm_enabled = TRUE; 430 *ppmc = phw->phw_pmc; 431 } else { 432 pi->pm_enabled = FALSE; 433 *ppmc = NULL; 434 } 435 436 return (0); 437} 438 439static int 440mips24k_get_config(int cpu, int ri, struct pmc **ppm) 441{ 442 *ppm = mips24k_pcpu[cpu]->pc_mipspmcs[ri].phw_pmc; 443 444 return 0; 445} 446 447/* 448 * XXX don't know what we should do here. 449 */ 450static int 451mips24k_switch_in(struct pmc_cpu *pc, struct pmc_process *pp) 452{ 453 return 0; 454} 455 456static int 457mips24k_switch_out(struct pmc_cpu *pc, struct pmc_process *pp) 458{ 459 return 0; 460} 461 462static int 463mips24k_pcpu_init(struct pmc_mdep *md, int cpu) 464{ 465 int first_ri, i; 466 struct pmc_cpu *pc; 467 struct mips24k_cpu *pac; 468 struct pmc_hw *phw; 469 470 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 471 ("[mips,%d] wrong cpu number %d", __LINE__, cpu)); 472 PMCDBG(MDP,INI,1,"mips-init cpu=%d", cpu); 473 474 mips24k_pcpu[cpu] = pac = malloc(sizeof(struct mips24k_cpu), M_PMC, 475 M_WAITOK|M_ZERO); 476 pac->pc_mipspmcs = malloc(sizeof(struct pmc_hw) * mips24k_npmcs, 477 M_PMC, M_WAITOK|M_ZERO); 478 pc = pmc_pcpu[cpu]; 479 first_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_MIPS24K].pcd_ri; 480 KASSERT(pc != NULL, ("[mips,%d] NULL per-cpu pointer", __LINE__)); 481 482 for (i = 0, phw = pac->pc_mipspmcs; i < mips24k_npmcs; i++, phw++) { 483 phw->phw_state = PMC_PHW_FLAG_IS_ENABLED | 484 PMC_PHW_CPU_TO_STATE(cpu) | PMC_PHW_INDEX_TO_STATE(i); 485 phw->phw_pmc = NULL; 486 pc->pc_hwpmcs[i + first_ri] = phw; 487 } 488 489 /* 490 * Clear the counter control register which has the effect 491 * of disabling counting. 492 */ 493 for (i = 0; i < mips24k_npmcs; i++) 494 mips24k_pmcn_write(i, 0); 495 496 return 0; 497} 498 499static int 500mips24k_pcpu_fini(struct pmc_mdep *md, int cpu) 501{ 502 return 0; 503} 504 505struct pmc_mdep * 506pmc_mips24k_initialize() 507{ 508 struct pmc_mdep *pmc_mdep; 509 struct pmc_classdep *pcd; 510 511 /* 512 * Read the counter control registers from CP0 513 * to determine the number of available PMCs. 514 * The control registers use bit 31 as a "more" bit. 515 * 516 * XXX: With the current macros it is hard to read the 517 * CP0 registers in any varied way. 518 */ 519 mips24k_npmcs = 2; 520 521 PMCDBG(MDP,INI,1,"mips-init npmcs=%d", mips24k_npmcs); 522 523 /* 524 * Allocate space for pointers to PMC HW descriptors and for 525 * the MDEP structure used by MI code. 526 */ 527 mips24k_pcpu = malloc(sizeof(struct mips24k_cpu *) * pmc_cpu_max(), M_PMC, 528 M_WAITOK|M_ZERO); 529 530 /* Just one class */ 531 pmc_mdep = malloc(sizeof(struct pmc_mdep) + sizeof(struct pmc_classdep), 532 M_PMC, M_WAITOK|M_ZERO); 533 534 pmc_mdep->pmd_cputype = PMC_CPU_MIPS_24K; 535 pmc_mdep->pmd_nclass = 1; 536 537 pcd = &pmc_mdep->pmd_classdep[PMC_MDEP_CLASS_INDEX_MIPS24K]; 538 pcd->pcd_caps = MIPS24K_PMC_CAPS; 539 pcd->pcd_class = PMC_CLASS_MIPS24K; 540 pcd->pcd_num = mips24k_npmcs; 541 pcd->pcd_ri = pmc_mdep->pmd_npmc; 542 pcd->pcd_width = 32; /* XXX: Fix for 64 bit MIPS */ 543 544 pcd->pcd_allocate_pmc = mips24k_allocate_pmc; 545 pcd->pcd_config_pmc = mips24k_config_pmc; 546 pcd->pcd_pcpu_fini = mips24k_pcpu_fini; 547 pcd->pcd_pcpu_init = mips24k_pcpu_init; 548 pcd->pcd_describe = mips24k_describe; 549 pcd->pcd_get_config = mips24k_get_config; 550 pcd->pcd_read_pmc = mips24k_read_pmc; 551 pcd->pcd_release_pmc = mips24k_release_pmc; 552 pcd->pcd_start_pmc = mips24k_start_pmc; 553 pcd->pcd_stop_pmc = mips24k_stop_pmc; 554 pcd->pcd_write_pmc = mips24k_write_pmc; 555 556 pmc_mdep->pmd_intr = mips24k_intr; 557 pmc_mdep->pmd_switch_in = mips24k_switch_in; 558 pmc_mdep->pmd_switch_out = mips24k_switch_out; 559 560 pmc_mdep->pmd_npmc += mips24k_npmcs; 561 562 return (pmc_mdep); 563} 564 565void 566pmc_mips24k_finalize(struct pmc_mdep *md) 567{ 568 (void) md; 569} 570 571