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