hwpmc_mips24k.c revision 227395
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: head/sys/dev/hwpmc/hwpmc_mips24k.c 227395 2011-11-09 17:38:27Z adrian $"); 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 if (caps & PMC_CAP_INTERRUPT) 258 config |= MIPS24K_PMC_INTERRUPT_ENABLE; 259 260 pm->pm_md.pm_mips24k.pm_mips24k_evsel = config; 261 262 PMCDBG(MDP,ALL,2,"mips-allocate ri=%d -> config=0x%x", ri, config); 263 264 return 0; 265} 266 267 268static int 269mips24k_read_pmc(int cpu, int ri, pmc_value_t *v) 270{ 271 struct pmc *pm; 272 pmc_value_t tmp; 273 274 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 275 ("[mips,%d] illegal CPU value %d", __LINE__, cpu)); 276 KASSERT(ri >= 0 && ri < mips24k_npmcs, 277 ("[mips,%d] illegal row index %d", __LINE__, ri)); 278 279 pm = mips24k_pcpu[cpu]->pc_mipspmcs[ri].phw_pmc; 280 tmp = mips24k_pmcn_read(ri); 281 PMCDBG(MDP,REA,2,"mips-read id=%d -> %jd", ri, tmp); 282 if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) 283 *v = MIPS24K_PERFCTR_VALUE_TO_RELOAD_COUNT(tmp); 284 else 285 *v = tmp; 286 287 return 0; 288} 289 290static int 291mips24k_write_pmc(int cpu, int ri, pmc_value_t v) 292{ 293 struct pmc *pm; 294 295 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 296 ("[mips,%d] illegal CPU value %d", __LINE__, cpu)); 297 KASSERT(ri >= 0 && ri < mips24k_npmcs, 298 ("[mips,%d] illegal row-index %d", __LINE__, ri)); 299 300 pm = mips24k_pcpu[cpu]->pc_mipspmcs[ri].phw_pmc; 301 302 if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) 303 v = MIPS24K_RELOAD_COUNT_TO_PERFCTR_VALUE(v); 304 305 PMCDBG(MDP,WRI,1,"mips-write cpu=%d ri=%d v=%jx", cpu, ri, v); 306 307 mips24k_pmcn_write(ri, v); 308 309 return 0; 310} 311 312static int 313mips24k_config_pmc(int cpu, int ri, struct pmc *pm) 314{ 315 struct pmc_hw *phw; 316 317 PMCDBG(MDP,CFG,1, "cpu=%d ri=%d pm=%p", cpu, ri, pm); 318 319 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 320 ("[mips,%d] illegal CPU value %d", __LINE__, cpu)); 321 KASSERT(ri >= 0 && ri < mips24k_npmcs, 322 ("[mips,%d] illegal row-index %d", __LINE__, ri)); 323 324 phw = &mips24k_pcpu[cpu]->pc_mipspmcs[ri]; 325 326 KASSERT(pm == NULL || phw->phw_pmc == NULL, 327 ("[mips,%d] pm=%p phw->pm=%p hwpmc not unconfigured", 328 __LINE__, pm, phw->phw_pmc)); 329 330 phw->phw_pmc = pm; 331 332 return 0; 333} 334 335static int 336mips24k_start_pmc(int cpu, int ri) 337{ 338 uint32_t config; 339 struct pmc *pm; 340 struct pmc_hw *phw; 341 342 phw = &mips24k_pcpu[cpu]->pc_mipspmcs[ri]; 343 pm = phw->phw_pmc; 344 config = pm->pm_md.pm_mips24k.pm_mips24k_evsel; 345 346 /* Enable the PMC. */ 347 switch (ri) { 348 case 0: 349 mips_wr_perfcnt0(config); 350 break; 351 case 1: 352 mips_wr_perfcnt2(config); 353 break; 354 default: 355 break; 356 } 357 358 return 0; 359} 360 361static int 362mips24k_stop_pmc(int cpu, int ri) 363{ 364 struct pmc *pm; 365 struct pmc_hw *phw; 366 367 phw = &mips24k_pcpu[cpu]->pc_mipspmcs[ri]; 368 pm = phw->phw_pmc; 369 370 /* 371 * Disable the PMCs. 372 * 373 * Clearing the entire register turns the counter off as well 374 * as removes the previously sampled event. 375 */ 376 switch (ri) { 377 case 0: 378 mips_wr_perfcnt0(0); 379 break; 380 case 1: 381 mips_wr_perfcnt2(0); 382 break; 383 default: 384 break; 385 } 386 return 0; 387} 388 389static int 390mips24k_release_pmc(int cpu, int ri, struct pmc *pmc) 391{ 392 struct pmc_hw *phw; 393 394 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 395 ("[mips,%d] illegal CPU value %d", __LINE__, cpu)); 396 KASSERT(ri >= 0 && ri < mips24k_npmcs, 397 ("[mips,%d] illegal row-index %d", __LINE__, ri)); 398 399 phw = &mips24k_pcpu[cpu]->pc_mipspmcs[ri]; 400 KASSERT(phw->phw_pmc == NULL, 401 ("[mips,%d] PHW pmc %p non-NULL", __LINE__, phw->phw_pmc)); 402 403 return 0; 404} 405 406static int 407mips24k_intr(int cpu, struct trapframe *tf) 408{ 409 int error; 410 int retval, ri; 411 struct pmc *pm; 412 struct mips24k_cpu *pc; 413 uint32_t r, r0, r2; 414 415 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 416 ("[mips24k,%d] CPU %d out of range", __LINE__, cpu)); 417 418 retval = 0; 419 pc = mips24k_pcpu[cpu]; 420 421 /* Stop PMCs without clearing the counter */ 422 r0 = mips_rd_perfcnt0(); 423 mips_wr_perfcnt0(r0 & ~(0x1f)); 424 r2 = mips_rd_perfcnt2(); 425 mips_wr_perfcnt2(r2 & ~(0x1f)); 426 427 for (ri = 0; ri < mips24k_npmcs; ri++) { 428 pm = mips24k_pcpu[cpu]->pc_mipspmcs[ri].phw_pmc; 429 if (pm == NULL) 430 continue; 431 if (! PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) 432 continue; 433 434 r = mips24k_pmcn_read(ri); 435 436 /* If bit 31 is set, the counter has overflowed */ 437 if ((r & 0x80000000) == 0) 438 continue; 439 440 retval = 1; 441 if (pm->pm_state != PMC_STATE_RUNNING) 442 continue; 443 error = pmc_process_interrupt(cpu, pm, tf, 444 TRAPF_USERMODE(tf)); 445 if (error) { 446 /* Clear/disable the relevant counter */ 447 if (ri == 0) 448 r0 = 0; 449 else if (ri == 1) 450 r2 = 0; 451 mips24k_stop_pmc(cpu, ri); 452 } 453 454 /* Reload sampling count */ 455 mips24k_write_pmc(cpu, ri, pm->pm_sc.pm_reloadcount); 456 } 457 458 /* 459 * Re-enable the PMC counters where they left off. 460 * 461 * Any counter which overflowed will have its sample count 462 * reloaded in the loop above. 463 */ 464 mips_wr_perfcnt0(r0); 465 mips_wr_perfcnt2(r2); 466 467 return retval; 468} 469 470static int 471mips24k_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc) 472{ 473 int error; 474 struct pmc_hw *phw; 475 char mips24k_name[PMC_NAME_MAX]; 476 477 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 478 ("[mips,%d], illegal CPU %d", __LINE__, cpu)); 479 KASSERT(ri >= 0 && ri < mips24k_npmcs, 480 ("[mips,%d] row-index %d out of range", __LINE__, ri)); 481 482 phw = &mips24k_pcpu[cpu]->pc_mipspmcs[ri]; 483 snprintf(mips24k_name, sizeof(mips24k_name), "MIPS-%d", ri); 484 if ((error = copystr(mips24k_name, pi->pm_name, PMC_NAME_MAX, 485 NULL)) != 0) 486 return error; 487 pi->pm_class = PMC_CLASS_MIPS24K; 488 if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) { 489 pi->pm_enabled = TRUE; 490 *ppmc = phw->phw_pmc; 491 } else { 492 pi->pm_enabled = FALSE; 493 *ppmc = NULL; 494 } 495 496 return (0); 497} 498 499static int 500mips24k_get_config(int cpu, int ri, struct pmc **ppm) 501{ 502 *ppm = mips24k_pcpu[cpu]->pc_mipspmcs[ri].phw_pmc; 503 504 return 0; 505} 506 507/* 508 * XXX don't know what we should do here. 509 */ 510static int 511mips24k_switch_in(struct pmc_cpu *pc, struct pmc_process *pp) 512{ 513 return 0; 514} 515 516static int 517mips24k_switch_out(struct pmc_cpu *pc, struct pmc_process *pp) 518{ 519 return 0; 520} 521 522static int 523mips24k_pcpu_init(struct pmc_mdep *md, int cpu) 524{ 525 int first_ri, i; 526 struct pmc_cpu *pc; 527 struct mips24k_cpu *pac; 528 struct pmc_hw *phw; 529 530 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 531 ("[mips,%d] wrong cpu number %d", __LINE__, cpu)); 532 PMCDBG(MDP,INI,1,"mips-init cpu=%d", cpu); 533 534 mips24k_pcpu[cpu] = pac = malloc(sizeof(struct mips24k_cpu), M_PMC, 535 M_WAITOK|M_ZERO); 536 pac->pc_mipspmcs = malloc(sizeof(struct pmc_hw) * mips24k_npmcs, 537 M_PMC, M_WAITOK|M_ZERO); 538 pc = pmc_pcpu[cpu]; 539 first_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_MIPS24K].pcd_ri; 540 KASSERT(pc != NULL, ("[mips,%d] NULL per-cpu pointer", __LINE__)); 541 542 for (i = 0, phw = pac->pc_mipspmcs; i < mips24k_npmcs; i++, phw++) { 543 phw->phw_state = PMC_PHW_FLAG_IS_ENABLED | 544 PMC_PHW_CPU_TO_STATE(cpu) | PMC_PHW_INDEX_TO_STATE(i); 545 phw->phw_pmc = NULL; 546 pc->pc_hwpmcs[i + first_ri] = phw; 547 } 548 549 /* 550 * Clear the counter control register which has the effect 551 * of disabling counting. 552 */ 553 for (i = 0; i < mips24k_npmcs; i++) 554 mips24k_pmcn_write(i, 0); 555 556 return 0; 557} 558 559static int 560mips24k_pcpu_fini(struct pmc_mdep *md, int cpu) 561{ 562 return 0; 563} 564 565struct pmc_mdep * 566pmc_mips24k_initialize() 567{ 568 struct pmc_mdep *pmc_mdep; 569 struct pmc_classdep *pcd; 570 571 /* 572 * Read the counter control registers from CP0 573 * to determine the number of available PMCs. 574 * The control registers use bit 31 as a "more" bit. 575 * 576 * XXX: With the current macros it is hard to read the 577 * CP0 registers in any varied way. 578 */ 579 mips24k_npmcs = 2; 580 581 PMCDBG(MDP,INI,1,"mips-init npmcs=%d", mips24k_npmcs); 582 583 /* 584 * Allocate space for pointers to PMC HW descriptors and for 585 * the MDEP structure used by MI code. 586 */ 587 mips24k_pcpu = malloc(sizeof(struct mips24k_cpu *) * pmc_cpu_max(), M_PMC, 588 M_WAITOK|M_ZERO); 589 590 /* Just one class */ 591 pmc_mdep = malloc(sizeof(struct pmc_mdep) + sizeof(struct pmc_classdep), 592 M_PMC, M_WAITOK|M_ZERO); 593 594 pmc_mdep->pmd_cputype = PMC_CPU_MIPS_24K; 595 pmc_mdep->pmd_nclass = 1; 596 597 pcd = &pmc_mdep->pmd_classdep[PMC_MDEP_CLASS_INDEX_MIPS24K]; 598 pcd->pcd_caps = MIPS24K_PMC_CAPS; 599 pcd->pcd_class = PMC_CLASS_MIPS24K; 600 pcd->pcd_num = mips24k_npmcs; 601 pcd->pcd_ri = pmc_mdep->pmd_npmc; 602 pcd->pcd_width = 32; /* XXX: Fix for 64 bit MIPS */ 603 604 pcd->pcd_allocate_pmc = mips24k_allocate_pmc; 605 pcd->pcd_config_pmc = mips24k_config_pmc; 606 pcd->pcd_pcpu_fini = mips24k_pcpu_fini; 607 pcd->pcd_pcpu_init = mips24k_pcpu_init; 608 pcd->pcd_describe = mips24k_describe; 609 pcd->pcd_get_config = mips24k_get_config; 610 pcd->pcd_read_pmc = mips24k_read_pmc; 611 pcd->pcd_release_pmc = mips24k_release_pmc; 612 pcd->pcd_start_pmc = mips24k_start_pmc; 613 pcd->pcd_stop_pmc = mips24k_stop_pmc; 614 pcd->pcd_write_pmc = mips24k_write_pmc; 615 616 pmc_mdep->pmd_intr = mips24k_intr; 617 pmc_mdep->pmd_switch_in = mips24k_switch_in; 618 pmc_mdep->pmd_switch_out = mips24k_switch_out; 619 620 pmc_mdep->pmd_npmc += mips24k_npmcs; 621 622 return (pmc_mdep); 623} 624 625void 626pmc_mips24k_finalize(struct pmc_mdep *md) 627{ 628 (void) md; 629} 630 631