1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2003-2008 Joseph Koshy 5 * Copyright (c) 2007 The FreeBSD Foundation 6 * Copyright (c) 2021 Ampere Computing LLC 7 * 8 * Portions of this software were developed by A. Joseph Koshy under 9 * sponsorship from the FreeBSD Foundation and Google, Inc. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 /* Support for ARM DMC-620 Memory Controller PMU */ 34 35 #include <sys/param.h> 36 #include <sys/lock.h> 37 #include <sys/malloc.h> 38 #include <sys/mutex.h> 39 #include <sys/pmc.h> 40 #include <sys/pmckern.h> 41 #include <sys/systm.h> 42 43 #include <dev/hwpmc/pmu_dmc620_reg.h> 44 45 #define DMC620_TYPE_CLKDIV2 0 46 #define DMC620_TYPE_CLK 1 47 #define CLASS2TYPE(c) ((c) - PMC_CLASS_DMC620_PMU_CD2) 48 49 /* Create wrapper for each class. */ 50 #define CLASSDEP_FN2(fn, t1, a1, t2, a2) \ 51 static int fn(int class, t1 a1, t2 a2); \ 52 static int fn ## _cd2(t1 a1, t2 a2) \ 53 { \ 54 return (fn(PMC_CLASS_DMC620_PMU_CD2, a1, a2)); \ 55 } \ 56 static int fn ## _c(t1 a1, t2 a2) \ 57 { \ 58 return (fn(PMC_CLASS_DMC620_PMU_C, a1, a2)); \ 59 } \ 60 static int fn(int class, t1 a1, t2 a2) 61 62 #define CLASSDEP_FN3(fn, t1, a1, t2, a2, t3, a3) \ 63 static int fn(int class, t1 a1, t2 a2, t3 a3); \ 64 static int fn ## _cd2(t1 a1, t2 a2, t3 a3) \ 65 { \ 66 return (fn(PMC_CLASS_DMC620_PMU_CD2, a1, a2, a3)); \ 67 } \ 68 static int fn ## _c(t1 a1, t2 a2, t3 a3) \ 69 { \ 70 return (fn(PMC_CLASS_DMC620_PMU_C, a1, a2, a3)); \ 71 } \ 72 static int fn(int class, t1 a1, t2 a2, t3 a3) 73 74 #define CLASSDEP_FN4(fn, t1, a1, t2, a2, t3, a3, t4, a4) \ 75 static int fn(int class, t1 a1, t2 a2, t3 a3, t4 a4); \ 76 static int fn ## _cd2(t1 a1, t2 a2, t3 a3, t4 a4) \ 77 { \ 78 return (fn(PMC_CLASS_DMC620_PMU_CD2, a1, a2, a3, a4)); \ 79 } \ 80 static int fn ## _c(t1 a1, t2 a2, t3 a3, t4 a4) \ 81 { \ 82 return (fn(PMC_CLASS_DMC620_PMU_C, a1, a2, a3, a4)); \ 83 } \ 84 static int fn(int class, t1 a1, t2 a2, t3 a3, t4 a4) 85 86 struct dmc620_pmc { 87 void *arg; 88 int domain; 89 }; 90 91 struct dmc620_descr { 92 struct pmc_descr pd_descr; /* "base class" */ 93 void *pd_rw_arg; /* Argument to use with read/write */ 94 struct pmc *pd_pmc; 95 struct pmc_hw *pd_phw; 96 uint32_t pd_config; 97 uint32_t pd_match; 98 uint32_t pd_mask; 99 uint32_t pd_evsel; /* address of EVSEL register */ 100 uint32_t pd_perfctr; /* address of PERFCTR register */ 101 102 }; 103 104 static struct dmc620_descr **dmc620_pmcdesc[2]; 105 static struct dmc620_pmc dmc620_pmcs[DMC620_UNIT_MAX]; 106 static int dmc620_npmcs = 0; 107 108 void 109 dmc620_pmc_register(int unit, void *arg, int domain) 110 { 111 112 if (unit >= DMC620_UNIT_MAX) { 113 /* TODO */ 114 return; 115 } 116 117 dmc620_pmcs[unit].arg = arg; 118 dmc620_pmcs[unit].domain = domain; 119 dmc620_npmcs++; 120 } 121 122 void 123 dmc620_pmc_unregister(int unit) 124 { 125 126 dmc620_pmcs[unit].arg = NULL; 127 dmc620_npmcs--; 128 } 129 130 int 131 pmc_dmc620_nclasses(void) 132 { 133 134 if (dmc620_npmcs > 0) 135 return (2); 136 return (0); 137 } 138 139 static inline struct dmc620_descr * 140 dmc620desc(int class, int cpu, int ri) 141 { 142 int c; 143 144 c = CLASS2TYPE(class); 145 KASSERT((c & 0xfffffffe) == 0, ("[dmc620,%d] 'c' can only be 0 or 1. " 146 "now %d", __LINE__, c)); 147 148 return (dmc620_pmcdesc[c][ri]); 149 } 150 151 static inline int 152 cntr(int class, int ri) 153 { 154 int c; 155 156 c = CLASS2TYPE(class); 157 KASSERT((c & 0xfffffffe) == 0, ("[dmc620,%d] 'c' can only be 0 or 1. " 158 "now %d", __LINE__, c)); 159 160 if (c == DMC620_TYPE_CLKDIV2) 161 return (ri % DMC620_CLKDIV2_COUNTERS_N); 162 return ((ri % DMC620_CLK_COUNTERS_N) + DMC620_CLKDIV2_COUNTERS_N); 163 } 164 165 static inline int 166 class2mdep(int class) 167 { 168 169 switch (class) { 170 case PMC_CLASS_DMC620_PMU_CD2: 171 return (PMC_MDEP_CLASS_INDEX_DMC620_CD2); 172 case PMC_CLASS_DMC620_PMU_C: 173 return (PMC_MDEP_CLASS_INDEX_DMC620_C); 174 } 175 return (-1); 176 } 177 178 static inline int 179 class_ri2unit(int class, int ri) 180 { 181 182 if (class == PMC_CLASS_DMC620_PMU_CD2) 183 return (ri / DMC620_CLKDIV2_COUNTERS_N); 184 else 185 return (ri / DMC620_CLK_COUNTERS_N); 186 } 187 188 /* 189 * read a pmc register 190 */ 191 192 CLASSDEP_FN4(dmc620_read_pmc, int, cpu, int, ri, struct pmc *, pm, 193 pmc_value_t *, v) 194 { 195 struct dmc620_descr *desc; 196 197 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 198 ("[dmc620,%d] illegal CPU value %d", __LINE__, cpu)); 199 KASSERT(ri >= 0, ("[dmc620,%d] row-index %d out of range", __LINE__, 200 ri)); 201 202 desc = dmc620desc(class, cpu, ri); 203 204 PMCDBG3(MDP,REA,1,"%s id=%d class=%d", __func__, ri, class); 205 206 /* 207 * Should emulate 64bits, because 32 bits counter overflows faster than 208 * pmcstat default period. 209 */ 210 /* Always CPU0. Single controller for all CPUs. */ 211 *v = ((uint64_t)pm->pm_pcpu_state[0].pps_overflowcnt << 32) | 212 pmu_dmc620_rd4(desc->pd_rw_arg, cntr(class, ri), 213 DMC620_COUNTER_VALUE_LO); 214 215 PMCDBG3(MDP, REA, 2, "%s id=%d -> %jd", __func__, ri, *v); 216 217 return (0); 218 } 219 220 /* 221 * Write a pmc register. 222 */ 223 224 CLASSDEP_FN4(dmc620_write_pmc, int, cpu, int, ri, struct pmc *, pm, 225 pmc_value_t, v) 226 { 227 struct dmc620_descr *desc; 228 229 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 230 ("[dmc620,%d] illegal CPU value %d", __LINE__, cpu)); 231 KASSERT(ri >= 0, ("[dmc620,%d] row-index %d out of range", __LINE__, 232 ri)); 233 234 desc = dmc620desc(class, cpu, ri); 235 236 PMCDBG4(MDP, WRI, 1, "%s cpu=%d ri=%d v=%jx", __func__, cpu, ri, v); 237 238 pmu_dmc620_wr4(desc->pd_rw_arg, cntr(class, ri), 239 DMC620_COUNTER_VALUE_LO, v); 240 return (0); 241 } 242 243 /* 244 * configure hardware pmc according to the configuration recorded in 245 * pmc 'pm'. 246 */ 247 248 CLASSDEP_FN3(dmc620_config_pmc, int, cpu, int, ri, struct pmc *, pm) 249 { 250 struct pmc_hw *phw; 251 252 PMCDBG4(MDP, CFG, 1, "%s cpu=%d ri=%d pm=%p", __func__, cpu, ri, pm); 253 254 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 255 ("[dmc620,%d] illegal CPU value %d", __LINE__, cpu)); 256 KASSERT(ri >= 0, ("[dmc620,%d] row-index %d out of range", __LINE__, 257 ri)); 258 259 phw = dmc620desc(class, cpu, ri)->pd_phw; 260 261 KASSERT(pm == NULL || phw->phw_pmc == NULL, 262 ("[dmc620,%d] pm=%p phw->pm=%p hwpmc not unconfigured", 263 __LINE__, pm, phw->phw_pmc)); 264 265 phw->phw_pmc = pm; 266 return (0); 267 } 268 269 /* 270 * Retrieve a configured PMC pointer from hardware state. 271 */ 272 273 CLASSDEP_FN3(dmc620_get_config, int, cpu, int, ri, struct pmc **, ppm) 274 { 275 276 *ppm = dmc620desc(class, cpu, ri)->pd_phw->phw_pmc; 277 278 return (0); 279 } 280 281 /* 282 * Check if a given allocation is feasible. 283 */ 284 285 CLASSDEP_FN4(dmc620_allocate_pmc, int, cpu, int, ri, struct pmc *,pm, 286 const struct pmc_op_pmcallocate *, a) 287 { 288 const struct pmc_descr *pd; 289 uint64_t caps, control; 290 enum pmc_event pe; 291 uint8_t e; 292 293 (void) cpu; 294 295 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 296 ("[dmc620,%d] illegal CPU value %d", __LINE__, cpu)); 297 KASSERT(ri >= 0, ("[dmc620,%d] row-index %d out of range", __LINE__, 298 ri)); 299 300 pd = &dmc620desc(class, cpu, ri)->pd_descr; 301 if (dmc620_pmcs[class_ri2unit(class, ri)].domain != 302 pcpu_find(cpu)->pc_domain) 303 return (EINVAL); 304 305 /* check class match */ 306 if (pd->pd_class != a->pm_class) 307 return (EINVAL); 308 309 caps = pm->pm_caps; 310 311 PMCDBG3(MDP, ALL, 1, "%s ri=%d caps=0x%x", __func__, ri, caps); 312 313 pe = a->pm_ev; 314 if (class == PMC_CLASS_DMC620_PMU_CD2) 315 e = pe - PMC_EV_DMC620_PMU_CD2_FIRST; 316 else 317 e = pe - PMC_EV_DMC620_PMU_C_FIRST; 318 319 control = (e << DMC620_COUNTER_CONTROL_EVENT_SHIFT) & 320 DMC620_COUNTER_CONTROL_EVENT_MASK; 321 322 if (caps & PMC_CAP_INVERT) 323 control |= DMC620_COUNTER_CONTROL_INVERT; 324 325 pm->pm_md.pm_dmc620.pm_control = control; 326 pm->pm_md.pm_dmc620.pm_match = a->pm_md.pm_dmc620.pm_dmc620_match; 327 pm->pm_md.pm_dmc620.pm_mask = a->pm_md.pm_dmc620.pm_dmc620_mask; 328 329 PMCDBG3(MDP, ALL, 2, "%s ri=%d -> control=0x%x", __func__, ri, control); 330 331 return (0); 332 } 333 334 /* 335 * Release machine dependent state associated with a PMC. This is a 336 * no-op on this architecture. 337 * 338 */ 339 340 /* ARGSUSED0 */ 341 CLASSDEP_FN3(dmc620_release_pmc, int, cpu, int, ri, struct pmc *, pmc) 342 { 343 struct pmc_hw *phw __diagused; 344 345 (void) pmc; 346 347 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 348 ("[dmc620,%d] illegal CPU value %d", __LINE__, cpu)); 349 KASSERT(ri >= 0, ("[dmc620,%d] row-index %d out of range", __LINE__, 350 ri)); 351 352 phw = dmc620desc(class, cpu, ri)->pd_phw; 353 354 KASSERT(phw->phw_pmc == NULL, 355 ("[dmc620,%d] PHW pmc %p non-NULL", __LINE__, phw->phw_pmc)); 356 357 return (0); 358 } 359 360 /* 361 * start a PMC. 362 */ 363 364 CLASSDEP_FN3(dmc620_start_pmc, int, cpu, int, ri, struct pmc *, pm) 365 { 366 struct dmc620_descr *desc; 367 uint64_t control; 368 369 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 370 ("[dmc620,%d] illegal CPU value %d", __LINE__, cpu)); 371 KASSERT(ri >= 0, ("[dmc620,%d] row-index %d out of range", __LINE__, 372 ri)); 373 374 desc = dmc620desc(class, cpu, ri); 375 376 PMCDBG3(MDP, STA, 1, "%s cpu=%d ri=%d", __func__, cpu, ri); 377 378 pmu_dmc620_wr4(desc->pd_rw_arg, cntr(class, ri), 379 DMC620_COUNTER_MASK_LO, pm->pm_md.pm_dmc620.pm_mask & 0xffffffff); 380 pmu_dmc620_wr4(desc->pd_rw_arg, cntr(class, ri), 381 DMC620_COUNTER_MASK_HI, pm->pm_md.pm_dmc620.pm_mask >> 32); 382 pmu_dmc620_wr4(desc->pd_rw_arg, cntr(class, ri), 383 DMC620_COUNTER_MATCH_LO, pm->pm_md.pm_dmc620.pm_match & 0xffffffff); 384 pmu_dmc620_wr4(desc->pd_rw_arg, cntr(class, ri), 385 DMC620_COUNTER_MATCH_HI, pm->pm_md.pm_dmc620.pm_match >> 32); 386 /* turn on the PMC ENABLE bit */ 387 control = pm->pm_md.pm_dmc620.pm_control | DMC620_COUNTER_CONTROL_ENABLE; 388 389 PMCDBG2(MDP, STA, 2, "%s control=0x%x", __func__, control); 390 391 pmu_dmc620_wr4(desc->pd_rw_arg, cntr(class, ri), 392 DMC620_COUNTER_CONTROL, control); 393 return (0); 394 } 395 396 /* 397 * Stop a PMC. 398 */ 399 400 CLASSDEP_FN3(dmc620_stop_pmc, int, cpu, int, ri, struct pmc *, pm) 401 { 402 struct dmc620_descr *desc; 403 uint64_t control; 404 405 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 406 ("[dmc620,%d] illegal CPU value %d", __LINE__, cpu)); 407 KASSERT(ri >= 0, ("[dmc620,%d] row-index %d out of range", __LINE__, 408 ri)); 409 410 desc = dmc620desc(class, cpu, ri); 411 412 PMCDBG2(MDP, STO, 1, "%s ri=%d", __func__, ri); 413 414 /* turn off the PMC ENABLE bit */ 415 control = pm->pm_md.pm_dmc620.pm_control & ~DMC620_COUNTER_CONTROL_ENABLE; 416 pmu_dmc620_wr4(desc->pd_rw_arg, cntr(class, ri), 417 DMC620_COUNTER_CONTROL, control); 418 419 return (0); 420 } 421 422 /* 423 * describe a PMC 424 */ 425 CLASSDEP_FN4(dmc620_describe, int, cpu, int, ri, struct pmc_info *, pi, 426 struct pmc **, ppmc) 427 { 428 struct pmc_descr *pd; 429 struct pmc_hw *phw; 430 431 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 432 ("[dmc620,%d] illegal CPU %d", __LINE__, cpu)); 433 KASSERT(ri >= 0, ("[dmc620,%d] row-index %d out of range", __LINE__, 434 ri)); 435 436 phw = dmc620desc(class, cpu, ri)->pd_phw; 437 pd = &dmc620desc(class, cpu, ri)->pd_descr; 438 439 strlcpy(pi->pm_name, pd->pd_name, sizeof(pi->pm_name)); 440 pi->pm_class = pd->pd_class; 441 442 if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) { 443 pi->pm_enabled = TRUE; 444 *ppmc = phw->phw_pmc; 445 } else { 446 pi->pm_enabled = FALSE; 447 *ppmc = NULL; 448 } 449 450 return (0); 451 } 452 453 /* 454 * processor dependent initialization. 455 */ 456 457 CLASSDEP_FN2(dmc620_pcpu_init, struct pmc_mdep *, md, int, cpu) 458 { 459 int first_ri, n, npmc; 460 struct pmc_hw *phw; 461 struct pmc_cpu *pc; 462 int mdep_class; 463 464 mdep_class = class2mdep(class); 465 KASSERT(mdep_class != -1, ("[dmc620,%d] wrong class %d", __LINE__, 466 class)); 467 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 468 ("[dmc620,%d] insane cpu number %d", __LINE__, cpu)); 469 470 PMCDBG1(MDP, INI, 1, "dmc620-init cpu=%d", cpu); 471 472 /* 473 * Set the content of the hardware descriptors to a known 474 * state and initialize pointers in the MI per-cpu descriptor. 475 */ 476 477 pc = pmc_pcpu[cpu]; 478 first_ri = md->pmd_classdep[mdep_class].pcd_ri; 479 npmc = md->pmd_classdep[mdep_class].pcd_num; 480 481 for (n = 0; n < npmc; n++, phw++) { 482 phw = dmc620desc(class, cpu, n)->pd_phw; 483 phw->phw_state = PMC_PHW_CPU_TO_STATE(cpu) | 484 PMC_PHW_INDEX_TO_STATE(n); 485 /* Set enabled only if unit present. */ 486 if (dmc620_pmcs[class_ri2unit(class, n)].arg != NULL) 487 phw->phw_state |= PMC_PHW_FLAG_IS_ENABLED; 488 phw->phw_pmc = NULL; 489 pc->pc_hwpmcs[n + first_ri] = phw; 490 } 491 return (0); 492 } 493 494 /* 495 * processor dependent cleanup prior to the KLD 496 * being unloaded 497 */ 498 499 CLASSDEP_FN2(dmc620_pcpu_fini, struct pmc_mdep *, md, int, cpu) 500 { 501 502 return (0); 503 } 504 505 int 506 dmc620_intr(struct trapframe *tf, int class, int unit, int i) 507 { 508 struct pmc_cpu *pc __diagused; 509 struct pmc_hw *phw; 510 struct pmc *pm; 511 int error, cpu, ri; 512 513 ri = i + unit * ((class == PMC_CLASS_DMC620_PMU_CD2) ? 514 DMC620_CLKDIV2_COUNTERS_N : DMC620_CLK_COUNTERS_N); 515 cpu = curcpu; 516 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 517 ("[dmc620,%d] CPU %d out of range", __LINE__, cpu)); 518 pc = pmc_pcpu[cpu]; 519 KASSERT(pc != NULL, ("pc != NULL")); 520 521 phw = dmc620desc(class, cpu, ri)->pd_phw; 522 KASSERT(phw != NULL, ("phw != NULL")); 523 pm = phw->phw_pmc; 524 if (pm == NULL) 525 return (0); 526 527 if (!PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) { 528 /* Always CPU0. */ 529 pm->pm_pcpu_state[0].pps_overflowcnt += 1; 530 return (0); 531 } 532 533 if (pm->pm_state != PMC_STATE_RUNNING) 534 return (0); 535 536 error = pmc_process_interrupt(PMC_HR, pm, tf); 537 if (error) 538 dmc620_stop_pmc(class, cpu, ri, pm); 539 540 /* Reload sampling count */ 541 dmc620_write_pmc(class, cpu, ri, pm, pm->pm_sc.pm_reloadcount); 542 543 return (0); 544 } 545 546 /* 547 * Initialize ourselves. 548 */ 549 550 int 551 pmc_dmc620_initialize_cd2(struct pmc_mdep *md) 552 { 553 struct pmc_classdep *pcd; 554 int i, npmc, unit; 555 556 KASSERT(md != NULL, ("[dmc620,%d] md is NULL", __LINE__)); 557 KASSERT(dmc620_npmcs <= DMC620_UNIT_MAX, 558 ("[dmc620,%d] dmc620_npmcs too big", __LINE__)); 559 560 PMCDBG0(MDP,INI,1, "dmc620-initialize"); 561 562 npmc = DMC620_CLKDIV2_COUNTERS_N * dmc620_npmcs; 563 pcd = &md->pmd_classdep[PMC_MDEP_CLASS_INDEX_DMC620_CD2]; 564 565 pcd->pcd_caps = PMC_CAP_SYSTEM | PMC_CAP_READ | 566 PMC_CAP_WRITE | PMC_CAP_INVERT | PMC_CAP_QUALIFIER | 567 PMC_CAP_INTERRUPT | PMC_CAP_DOMWIDE; 568 pcd->pcd_class = PMC_CLASS_DMC620_PMU_CD2; 569 pcd->pcd_num = npmc; 570 pcd->pcd_ri = md->pmd_npmc; 571 pcd->pcd_width = 32; 572 573 pcd->pcd_allocate_pmc = dmc620_allocate_pmc_cd2; 574 pcd->pcd_config_pmc = dmc620_config_pmc_cd2; 575 pcd->pcd_describe = dmc620_describe_cd2; 576 pcd->pcd_get_config = dmc620_get_config_cd2; 577 pcd->pcd_get_msr = NULL; 578 pcd->pcd_pcpu_fini = dmc620_pcpu_fini_cd2; 579 pcd->pcd_pcpu_init = dmc620_pcpu_init_cd2; 580 pcd->pcd_read_pmc = dmc620_read_pmc_cd2; 581 pcd->pcd_release_pmc = dmc620_release_pmc_cd2; 582 pcd->pcd_start_pmc = dmc620_start_pmc_cd2; 583 pcd->pcd_stop_pmc = dmc620_stop_pmc_cd2; 584 pcd->pcd_write_pmc = dmc620_write_pmc_cd2; 585 586 md->pmd_npmc += npmc; 587 dmc620_pmcdesc[0] = malloc(sizeof(struct dmc620_descr *) * npmc * 588 DMC620_PMU_DEFAULT_UNITS_N, M_PMC, M_WAITOK|M_ZERO); 589 for (i = 0; i < npmc; i++) { 590 dmc620_pmcdesc[0][i] = malloc(sizeof(struct dmc620_descr), 591 M_PMC, M_WAITOK|M_ZERO); 592 593 unit = i / DMC620_CLKDIV2_COUNTERS_N; 594 KASSERT(unit >= 0, ("unit >= 0")); 595 KASSERT(dmc620_pmcs[unit].arg != NULL, ("arg != NULL")); 596 597 dmc620_pmcdesc[0][i]->pd_rw_arg = dmc620_pmcs[unit].arg; 598 dmc620_pmcdesc[0][i]->pd_descr.pd_class = 599 PMC_CLASS_DMC620_PMU_CD2; 600 dmc620_pmcdesc[0][i]->pd_descr.pd_caps = pcd->pcd_caps; 601 dmc620_pmcdesc[0][i]->pd_phw = malloc(sizeof(struct pmc_hw), 602 M_PMC, M_WAITOK|M_ZERO); 603 snprintf(dmc620_pmcdesc[0][i]->pd_descr.pd_name, 63, 604 "DMC620_CD2_%d", i); 605 } 606 607 return (0); 608 } 609 610 int 611 pmc_dmc620_initialize_c(struct pmc_mdep *md) 612 { 613 struct pmc_classdep *pcd; 614 int i, npmc, unit; 615 616 KASSERT(md != NULL, ("[dmc620,%d] md is NULL", __LINE__)); 617 KASSERT(dmc620_npmcs <= DMC620_UNIT_MAX, 618 ("[dmc620,%d] dmc620_npmcs too big", __LINE__)); 619 620 PMCDBG0(MDP,INI,1, "dmc620-initialize"); 621 622 npmc = DMC620_CLK_COUNTERS_N * dmc620_npmcs; 623 pcd = &md->pmd_classdep[PMC_MDEP_CLASS_INDEX_DMC620_C]; 624 625 pcd->pcd_caps = PMC_CAP_SYSTEM | PMC_CAP_READ | 626 PMC_CAP_WRITE | PMC_CAP_INVERT | PMC_CAP_QUALIFIER | 627 PMC_CAP_INTERRUPT | PMC_CAP_DOMWIDE; 628 pcd->pcd_class = PMC_CLASS_DMC620_PMU_C; 629 pcd->pcd_num = npmc; 630 pcd->pcd_ri = md->pmd_npmc; 631 pcd->pcd_width = 32; 632 633 pcd->pcd_allocate_pmc = dmc620_allocate_pmc_c; 634 pcd->pcd_config_pmc = dmc620_config_pmc_c; 635 pcd->pcd_describe = dmc620_describe_c; 636 pcd->pcd_get_config = dmc620_get_config_c; 637 pcd->pcd_get_msr = NULL; 638 pcd->pcd_pcpu_fini = dmc620_pcpu_fini_c; 639 pcd->pcd_pcpu_init = dmc620_pcpu_init_c; 640 pcd->pcd_read_pmc = dmc620_read_pmc_c; 641 pcd->pcd_release_pmc = dmc620_release_pmc_c; 642 pcd->pcd_start_pmc = dmc620_start_pmc_c; 643 pcd->pcd_stop_pmc = dmc620_stop_pmc_c; 644 pcd->pcd_write_pmc = dmc620_write_pmc_c; 645 646 md->pmd_npmc += npmc; 647 dmc620_pmcdesc[1] = malloc(sizeof(struct dmc620_descr *) * npmc * 648 DMC620_PMU_DEFAULT_UNITS_N, M_PMC, M_WAITOK|M_ZERO); 649 for (i = 0; i < npmc; i++) { 650 dmc620_pmcdesc[1][i] = malloc(sizeof(struct dmc620_descr), 651 M_PMC, M_WAITOK|M_ZERO); 652 653 unit = i / DMC620_CLK_COUNTERS_N; 654 KASSERT(unit >= 0, ("unit >= 0")); 655 KASSERT(dmc620_pmcs[unit].arg != NULL, ("arg != NULL")); 656 657 dmc620_pmcdesc[1][i]->pd_rw_arg = dmc620_pmcs[unit].arg; 658 dmc620_pmcdesc[1][i]->pd_descr.pd_class = PMC_CLASS_DMC620_PMU_C; 659 dmc620_pmcdesc[1][i]->pd_descr.pd_caps = pcd->pcd_caps; 660 dmc620_pmcdesc[1][i]->pd_phw = malloc(sizeof(struct pmc_hw), 661 M_PMC, M_WAITOK|M_ZERO); 662 snprintf(dmc620_pmcdesc[1][i]->pd_descr.pd_name, 63, 663 "DMC620_C_%d", i); 664 } 665 666 return (0); 667 } 668 669 void 670 pmc_dmc620_finalize_cd2(struct pmc_mdep *md) 671 { 672 struct pmc_classdep *pcd; 673 int i, npmc; 674 675 KASSERT(md->pmd_classdep[PMC_MDEP_CLASS_INDEX_DMC620_CD2].pcd_class == 676 PMC_CLASS_DMC620_PMU_CD2, ("[dmc620,%d] pmc class mismatch", 677 __LINE__)); 678 679 pcd = &md->pmd_classdep[PMC_MDEP_CLASS_INDEX_DMC620_CD2]; 680 681 npmc = pcd->pcd_num; 682 for (i = 0; i < npmc; i++) { 683 free(dmc620_pmcdesc[0][i]->pd_phw, M_PMC); 684 free(dmc620_pmcdesc[0][i], M_PMC); 685 } 686 free(dmc620_pmcdesc[0], M_PMC); 687 dmc620_pmcdesc[0] = NULL; 688 } 689 690 void 691 pmc_dmc620_finalize_c(struct pmc_mdep *md) 692 { 693 struct pmc_classdep *pcd; 694 int i, npmc; 695 696 KASSERT(md->pmd_classdep[PMC_MDEP_CLASS_INDEX_DMC620_C].pcd_class == 697 PMC_CLASS_DMC620_PMU_C, ("[dmc620,%d] pmc class mismatch", 698 __LINE__)); 699 700 pcd = &md->pmd_classdep[PMC_MDEP_CLASS_INDEX_DMC620_C]; 701 702 npmc = pcd->pcd_num; 703 for (i = 0; i < npmc; i++) { 704 free(dmc620_pmcdesc[1][i]->pd_phw, M_PMC); 705 free(dmc620_pmcdesc[1][i], M_PMC); 706 } 707 free(dmc620_pmcdesc[1], M_PMC); 708 dmc620_pmcdesc[1] = NULL; 709 } 710