11459a227SAleksandr Rybalko /*- 25ec1d020SAndrew Turner * SPDX-License-Identifier: BSD-2-Clause 31459a227SAleksandr Rybalko * 41459a227SAleksandr Rybalko * Copyright (c) 2003-2008 Joseph Koshy 51459a227SAleksandr Rybalko * Copyright (c) 2007 The FreeBSD Foundation 61459a227SAleksandr Rybalko * Copyright (c) 2021 Ampere Computing LLC 71459a227SAleksandr Rybalko * 81459a227SAleksandr Rybalko * Portions of this software were developed by A. Joseph Koshy under 91459a227SAleksandr Rybalko * sponsorship from the FreeBSD Foundation and Google, Inc. 101459a227SAleksandr Rybalko * 111459a227SAleksandr Rybalko * Redistribution and use in source and binary forms, with or without 121459a227SAleksandr Rybalko * modification, are permitted provided that the following conditions 131459a227SAleksandr Rybalko * are met: 141459a227SAleksandr Rybalko * 1. Redistributions of source code must retain the above copyright 151459a227SAleksandr Rybalko * notice, this list of conditions and the following disclaimer. 161459a227SAleksandr Rybalko * 2. Redistributions in binary form must reproduce the above copyright 171459a227SAleksandr Rybalko * notice, this list of conditions and the following disclaimer in the 181459a227SAleksandr Rybalko * documentation and/or other materials provided with the distribution. 191459a227SAleksandr Rybalko * 201459a227SAleksandr Rybalko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 211459a227SAleksandr Rybalko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221459a227SAleksandr Rybalko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231459a227SAleksandr Rybalko * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 241459a227SAleksandr Rybalko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251459a227SAleksandr Rybalko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261459a227SAleksandr Rybalko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271459a227SAleksandr Rybalko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281459a227SAleksandr Rybalko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291459a227SAleksandr Rybalko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301459a227SAleksandr Rybalko * SUCH DAMAGE. 311459a227SAleksandr Rybalko */ 321459a227SAleksandr Rybalko 331459a227SAleksandr Rybalko /* Support for ARM DMC-620 Memory Controller PMU */ 341459a227SAleksandr Rybalko 351459a227SAleksandr Rybalko #include <sys/cdefs.h> 361459a227SAleksandr Rybalko __FBSDID("$FreeBSD$"); 371459a227SAleksandr Rybalko 381459a227SAleksandr Rybalko #include <sys/param.h> 391459a227SAleksandr Rybalko #include <sys/lock.h> 401459a227SAleksandr Rybalko #include <sys/malloc.h> 411459a227SAleksandr Rybalko #include <sys/mutex.h> 421459a227SAleksandr Rybalko #include <sys/pmc.h> 431459a227SAleksandr Rybalko #include <sys/pmckern.h> 441459a227SAleksandr Rybalko #include <sys/systm.h> 451459a227SAleksandr Rybalko 461459a227SAleksandr Rybalko #include <dev/hwpmc/pmu_dmc620_reg.h> 471459a227SAleksandr Rybalko 481459a227SAleksandr Rybalko #define DMC620_TYPE_CLKDIV2 0 491459a227SAleksandr Rybalko #define DMC620_TYPE_CLK 1 501459a227SAleksandr Rybalko #define CLASS2TYPE(c) ((c) - PMC_CLASS_DMC620_PMU_CD2) 511459a227SAleksandr Rybalko 521459a227SAleksandr Rybalko /* Create wrapper for each class. */ 531459a227SAleksandr Rybalko #define CLASSDEP_FN2(fn, t1, a1, t2, a2) \ 541459a227SAleksandr Rybalko static int fn(int class, t1 a1, t2 a2); \ 551459a227SAleksandr Rybalko static int fn ## _cd2(t1 a1, t2 a2) \ 561459a227SAleksandr Rybalko { \ 571459a227SAleksandr Rybalko return (fn(PMC_CLASS_DMC620_PMU_CD2, a1, a2)); \ 581459a227SAleksandr Rybalko } \ 591459a227SAleksandr Rybalko static int fn ## _c(t1 a1, t2 a2) \ 601459a227SAleksandr Rybalko { \ 611459a227SAleksandr Rybalko return (fn(PMC_CLASS_DMC620_PMU_C, a1, a2)); \ 621459a227SAleksandr Rybalko } \ 631459a227SAleksandr Rybalko static int fn(int class, t1 a1, t2 a2) 641459a227SAleksandr Rybalko 651459a227SAleksandr Rybalko #define CLASSDEP_FN3(fn, t1, a1, t2, a2, t3, a3) \ 661459a227SAleksandr Rybalko static int fn(int class, t1 a1, t2 a2, t3 a3); \ 671459a227SAleksandr Rybalko static int fn ## _cd2(t1 a1, t2 a2, t3 a3) \ 681459a227SAleksandr Rybalko { \ 691459a227SAleksandr Rybalko return (fn(PMC_CLASS_DMC620_PMU_CD2, a1, a2, a3)); \ 701459a227SAleksandr Rybalko } \ 711459a227SAleksandr Rybalko static int fn ## _c(t1 a1, t2 a2, t3 a3) \ 721459a227SAleksandr Rybalko { \ 731459a227SAleksandr Rybalko return (fn(PMC_CLASS_DMC620_PMU_C, a1, a2, a3)); \ 741459a227SAleksandr Rybalko } \ 751459a227SAleksandr Rybalko static int fn(int class, t1 a1, t2 a2, t3 a3) 761459a227SAleksandr Rybalko 771459a227SAleksandr Rybalko #define CLASSDEP_FN4(fn, t1, a1, t2, a2, t3, a3, t4, a4) \ 781459a227SAleksandr Rybalko static int fn(int class, t1 a1, t2 a2, t3 a3, t4 a4); \ 791459a227SAleksandr Rybalko static int fn ## _cd2(t1 a1, t2 a2, t3 a3, t4 a4) \ 801459a227SAleksandr Rybalko { \ 811459a227SAleksandr Rybalko return (fn(PMC_CLASS_DMC620_PMU_CD2, a1, a2, a3, a4)); \ 821459a227SAleksandr Rybalko } \ 831459a227SAleksandr Rybalko static int fn ## _c(t1 a1, t2 a2, t3 a3, t4 a4) \ 841459a227SAleksandr Rybalko { \ 851459a227SAleksandr Rybalko return (fn(PMC_CLASS_DMC620_PMU_C, a1, a2, a3, a4)); \ 861459a227SAleksandr Rybalko } \ 871459a227SAleksandr Rybalko static int fn(int class, t1 a1, t2 a2, t3 a3, t4 a4) 881459a227SAleksandr Rybalko 891459a227SAleksandr Rybalko struct dmc620_pmc { 901459a227SAleksandr Rybalko void *arg; 911459a227SAleksandr Rybalko int domain; 921459a227SAleksandr Rybalko }; 931459a227SAleksandr Rybalko 941459a227SAleksandr Rybalko struct dmc620_descr { 951459a227SAleksandr Rybalko struct pmc_descr pd_descr; /* "base class" */ 961459a227SAleksandr Rybalko void *pd_rw_arg; /* Argument to use with read/write */ 971459a227SAleksandr Rybalko struct pmc *pd_pmc; 981459a227SAleksandr Rybalko struct pmc_hw *pd_phw; 991459a227SAleksandr Rybalko uint32_t pd_config; 1001459a227SAleksandr Rybalko uint32_t pd_match; 1011459a227SAleksandr Rybalko uint32_t pd_mask; 1021459a227SAleksandr Rybalko uint32_t pd_evsel; /* address of EVSEL register */ 1031459a227SAleksandr Rybalko uint32_t pd_perfctr; /* address of PERFCTR register */ 1041459a227SAleksandr Rybalko 1051459a227SAleksandr Rybalko }; 1061459a227SAleksandr Rybalko 1071459a227SAleksandr Rybalko static struct dmc620_descr **dmc620_pmcdesc[2]; 1081459a227SAleksandr Rybalko static struct dmc620_pmc dmc620_pmcs[DMC620_UNIT_MAX]; 1091459a227SAleksandr Rybalko static int dmc620_npmcs = 0; 1101459a227SAleksandr Rybalko 1111459a227SAleksandr Rybalko void 1121459a227SAleksandr Rybalko dmc620_pmc_register(int unit, void *arg, int domain) 1131459a227SAleksandr Rybalko { 1141459a227SAleksandr Rybalko 1151459a227SAleksandr Rybalko if (unit >= DMC620_UNIT_MAX) { 1161459a227SAleksandr Rybalko /* TODO */ 1171459a227SAleksandr Rybalko return; 1181459a227SAleksandr Rybalko } 1191459a227SAleksandr Rybalko 1201459a227SAleksandr Rybalko dmc620_pmcs[unit].arg = arg; 1211459a227SAleksandr Rybalko dmc620_pmcs[unit].domain = domain; 1221459a227SAleksandr Rybalko dmc620_npmcs++; 1231459a227SAleksandr Rybalko } 1241459a227SAleksandr Rybalko 1251459a227SAleksandr Rybalko void 1261459a227SAleksandr Rybalko dmc620_pmc_unregister(int unit) 1271459a227SAleksandr Rybalko { 1281459a227SAleksandr Rybalko 1291459a227SAleksandr Rybalko dmc620_pmcs[unit].arg = NULL; 1301459a227SAleksandr Rybalko dmc620_npmcs--; 1311459a227SAleksandr Rybalko } 1321459a227SAleksandr Rybalko 1331459a227SAleksandr Rybalko int 13405cef747SAndrew Turner pmc_dmc620_nclasses(void) 1351459a227SAleksandr Rybalko { 1361459a227SAleksandr Rybalko 1371459a227SAleksandr Rybalko if (dmc620_npmcs > 0) 1381459a227SAleksandr Rybalko return (2); 1391459a227SAleksandr Rybalko return (0); 1401459a227SAleksandr Rybalko } 1411459a227SAleksandr Rybalko 1421459a227SAleksandr Rybalko static inline struct dmc620_descr * 1431459a227SAleksandr Rybalko dmc620desc(int class, int cpu, int ri) 1441459a227SAleksandr Rybalko { 1451459a227SAleksandr Rybalko int c; 1461459a227SAleksandr Rybalko 1471459a227SAleksandr Rybalko c = CLASS2TYPE(class); 1481459a227SAleksandr Rybalko KASSERT((c & 0xfffffffe) == 0, ("[dmc620,%d] 'c' can only be 0 or 1. " 1491459a227SAleksandr Rybalko "now %d", __LINE__, c)); 1501459a227SAleksandr Rybalko 1511459a227SAleksandr Rybalko return (dmc620_pmcdesc[c][ri]); 1521459a227SAleksandr Rybalko } 1531459a227SAleksandr Rybalko 1541459a227SAleksandr Rybalko static inline int 1551459a227SAleksandr Rybalko cntr(int class, int ri) 1561459a227SAleksandr Rybalko { 1571459a227SAleksandr Rybalko int c; 1581459a227SAleksandr Rybalko 1591459a227SAleksandr Rybalko c = CLASS2TYPE(class); 1601459a227SAleksandr Rybalko KASSERT((c & 0xfffffffe) == 0, ("[dmc620,%d] 'c' can only be 0 or 1. " 1611459a227SAleksandr Rybalko "now %d", __LINE__, c)); 1621459a227SAleksandr Rybalko 1631459a227SAleksandr Rybalko if (c == DMC620_TYPE_CLKDIV2) 1641459a227SAleksandr Rybalko return (ri % DMC620_CLKDIV2_COUNTERS_N); 1651459a227SAleksandr Rybalko return ((ri % DMC620_CLK_COUNTERS_N) + DMC620_CLKDIV2_COUNTERS_N); 1661459a227SAleksandr Rybalko } 1671459a227SAleksandr Rybalko 1681459a227SAleksandr Rybalko static inline int 1691459a227SAleksandr Rybalko class2mdep(int class) 1701459a227SAleksandr Rybalko { 1711459a227SAleksandr Rybalko 1721459a227SAleksandr Rybalko switch (class) { 1731459a227SAleksandr Rybalko case PMC_CLASS_DMC620_PMU_CD2: 1741459a227SAleksandr Rybalko return (PMC_MDEP_CLASS_INDEX_DMC620_CD2); 1751459a227SAleksandr Rybalko case PMC_CLASS_DMC620_PMU_C: 1761459a227SAleksandr Rybalko return (PMC_MDEP_CLASS_INDEX_DMC620_C); 1771459a227SAleksandr Rybalko } 1781459a227SAleksandr Rybalko return (-1); 1791459a227SAleksandr Rybalko } 1801459a227SAleksandr Rybalko 1811459a227SAleksandr Rybalko static inline int 1821459a227SAleksandr Rybalko class_ri2unit(int class, int ri) 1831459a227SAleksandr Rybalko { 1841459a227SAleksandr Rybalko 1851459a227SAleksandr Rybalko if (class == PMC_CLASS_DMC620_PMU_CD2) 1861459a227SAleksandr Rybalko return (ri / DMC620_CLKDIV2_COUNTERS_N); 1871459a227SAleksandr Rybalko else 1881459a227SAleksandr Rybalko return (ri / DMC620_CLK_COUNTERS_N); 1891459a227SAleksandr Rybalko } 1901459a227SAleksandr Rybalko 1911459a227SAleksandr Rybalko /* 1921459a227SAleksandr Rybalko * read a pmc register 1931459a227SAleksandr Rybalko */ 1941459a227SAleksandr Rybalko 1951459a227SAleksandr Rybalko CLASSDEP_FN3(dmc620_read_pmc, int, cpu, int, ri, pmc_value_t *, v) 1961459a227SAleksandr Rybalko { 1971459a227SAleksandr Rybalko struct dmc620_descr *desc; 1981459a227SAleksandr Rybalko struct pmc *pm; 1991459a227SAleksandr Rybalko 2001459a227SAleksandr Rybalko KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 2011459a227SAleksandr Rybalko ("[dmc620,%d] illegal CPU value %d", __LINE__, cpu)); 2021459a227SAleksandr Rybalko KASSERT(ri >= 0, ("[dmc620,%d] row-index %d out of range", __LINE__, 2031459a227SAleksandr Rybalko ri)); 2041459a227SAleksandr Rybalko 2051459a227SAleksandr Rybalko desc = dmc620desc(class, cpu, ri); 2061459a227SAleksandr Rybalko pm = desc->pd_phw->phw_pmc; 2071459a227SAleksandr Rybalko 2081459a227SAleksandr Rybalko KASSERT(pm != NULL, 2091459a227SAleksandr Rybalko ("[dmc620,%d] No owner for HWPMC [cpu%d,pmc%d]", __LINE__, 2101459a227SAleksandr Rybalko cpu, ri)); 2111459a227SAleksandr Rybalko 2121459a227SAleksandr Rybalko PMCDBG3(MDP,REA,1,"%s id=%d class=%d", __func__, ri, class); 2131459a227SAleksandr Rybalko 2141459a227SAleksandr Rybalko /* 2151459a227SAleksandr Rybalko * Should emulate 64bits, because 32 bits counter overflows faster than 2161459a227SAleksandr Rybalko * pmcstat default period. 2171459a227SAleksandr Rybalko */ 2181459a227SAleksandr Rybalko /* Always CPU0. Single controller for all CPUs. */ 2191459a227SAleksandr Rybalko *v = ((uint64_t)pm->pm_pcpu_state[0].pps_overflowcnt << 32) | 2201459a227SAleksandr Rybalko pmu_dmc620_rd4(desc->pd_rw_arg, cntr(class, ri), 2211459a227SAleksandr Rybalko DMC620_COUNTER_VALUE_LO); 2221459a227SAleksandr Rybalko 2231459a227SAleksandr Rybalko PMCDBG3(MDP, REA, 2, "%s id=%d -> %jd", __func__, ri, *v); 2241459a227SAleksandr Rybalko 2251459a227SAleksandr Rybalko return (0); 2261459a227SAleksandr Rybalko } 2271459a227SAleksandr Rybalko 2281459a227SAleksandr Rybalko /* 2291459a227SAleksandr Rybalko * Write a pmc register. 2301459a227SAleksandr Rybalko */ 2311459a227SAleksandr Rybalko 2321459a227SAleksandr Rybalko CLASSDEP_FN3(dmc620_write_pmc, int, cpu, int, ri, pmc_value_t, v) 2331459a227SAleksandr Rybalko { 2341459a227SAleksandr Rybalko struct dmc620_descr *desc; 235d78bef0eSBjoern A. Zeeb struct pmc *pm __diagused; 2361459a227SAleksandr Rybalko 2371459a227SAleksandr Rybalko KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 2381459a227SAleksandr Rybalko ("[dmc620,%d] illegal CPU value %d", __LINE__, cpu)); 2391459a227SAleksandr Rybalko KASSERT(ri >= 0, ("[dmc620,%d] row-index %d out of range", __LINE__, 2401459a227SAleksandr Rybalko ri)); 2411459a227SAleksandr Rybalko 2421459a227SAleksandr Rybalko desc = dmc620desc(class, cpu, ri); 2431459a227SAleksandr Rybalko pm = desc->pd_phw->phw_pmc; 2441459a227SAleksandr Rybalko 2451459a227SAleksandr Rybalko KASSERT(pm != NULL, 2461459a227SAleksandr Rybalko ("[dmc620,%d] PMC not owned (cpu%d,pmc%d)", __LINE__, 2471459a227SAleksandr Rybalko cpu, ri)); 2481459a227SAleksandr Rybalko 2491459a227SAleksandr Rybalko PMCDBG4(MDP, WRI, 1, "%s cpu=%d ri=%d v=%jx", __func__, cpu, ri, v); 2501459a227SAleksandr Rybalko 2511459a227SAleksandr Rybalko pmu_dmc620_wr4(desc->pd_rw_arg, cntr(class, ri), 2521459a227SAleksandr Rybalko DMC620_COUNTER_VALUE_LO, v); 2531459a227SAleksandr Rybalko return (0); 2541459a227SAleksandr Rybalko } 2551459a227SAleksandr Rybalko 2561459a227SAleksandr Rybalko /* 2571459a227SAleksandr Rybalko * configure hardware pmc according to the configuration recorded in 2581459a227SAleksandr Rybalko * pmc 'pm'. 2591459a227SAleksandr Rybalko */ 2601459a227SAleksandr Rybalko 2611459a227SAleksandr Rybalko CLASSDEP_FN3(dmc620_config_pmc, int, cpu, int, ri, struct pmc *, pm) 2621459a227SAleksandr Rybalko { 2631459a227SAleksandr Rybalko struct pmc_hw *phw; 2641459a227SAleksandr Rybalko 2651459a227SAleksandr Rybalko PMCDBG4(MDP, CFG, 1, "%s cpu=%d ri=%d pm=%p", __func__, cpu, ri, pm); 2661459a227SAleksandr Rybalko 2671459a227SAleksandr Rybalko KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 2681459a227SAleksandr Rybalko ("[dmc620,%d] illegal CPU value %d", __LINE__, cpu)); 2691459a227SAleksandr Rybalko KASSERT(ri >= 0, ("[dmc620,%d] row-index %d out of range", __LINE__, 2701459a227SAleksandr Rybalko ri)); 2711459a227SAleksandr Rybalko 2721459a227SAleksandr Rybalko phw = dmc620desc(class, cpu, ri)->pd_phw; 2731459a227SAleksandr Rybalko 2741459a227SAleksandr Rybalko KASSERT(pm == NULL || phw->phw_pmc == NULL, 2751459a227SAleksandr Rybalko ("[dmc620,%d] pm=%p phw->pm=%p hwpmc not unconfigured", 2761459a227SAleksandr Rybalko __LINE__, pm, phw->phw_pmc)); 2771459a227SAleksandr Rybalko 2781459a227SAleksandr Rybalko phw->phw_pmc = pm; 2791459a227SAleksandr Rybalko return (0); 2801459a227SAleksandr Rybalko } 2811459a227SAleksandr Rybalko 2821459a227SAleksandr Rybalko /* 2831459a227SAleksandr Rybalko * Retrieve a configured PMC pointer from hardware state. 2841459a227SAleksandr Rybalko */ 2851459a227SAleksandr Rybalko 2861459a227SAleksandr Rybalko CLASSDEP_FN3(dmc620_get_config, int, cpu, int, ri, struct pmc **, ppm) 2871459a227SAleksandr Rybalko { 2881459a227SAleksandr Rybalko 2891459a227SAleksandr Rybalko *ppm = dmc620desc(class, cpu, ri)->pd_phw->phw_pmc; 2901459a227SAleksandr Rybalko 2911459a227SAleksandr Rybalko return (0); 2921459a227SAleksandr Rybalko } 2931459a227SAleksandr Rybalko 2941459a227SAleksandr Rybalko /* 2951459a227SAleksandr Rybalko * Check if a given allocation is feasible. 2961459a227SAleksandr Rybalko */ 2971459a227SAleksandr Rybalko 2981459a227SAleksandr Rybalko CLASSDEP_FN4(dmc620_allocate_pmc, int, cpu, int, ri, struct pmc *,pm, 2991459a227SAleksandr Rybalko const struct pmc_op_pmcallocate *, a) 3001459a227SAleksandr Rybalko { 3011459a227SAleksandr Rybalko const struct pmc_descr *pd; 3021459a227SAleksandr Rybalko uint64_t caps, control; 3031459a227SAleksandr Rybalko enum pmc_event pe; 3041459a227SAleksandr Rybalko uint8_t e; 3051459a227SAleksandr Rybalko 3061459a227SAleksandr Rybalko (void) cpu; 3071459a227SAleksandr Rybalko 3081459a227SAleksandr Rybalko KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 3091459a227SAleksandr Rybalko ("[dmc620,%d] illegal CPU value %d", __LINE__, cpu)); 3101459a227SAleksandr Rybalko KASSERT(ri >= 0, ("[dmc620,%d] row-index %d out of range", __LINE__, 3111459a227SAleksandr Rybalko ri)); 3121459a227SAleksandr Rybalko 3131459a227SAleksandr Rybalko pd = &dmc620desc(class, cpu, ri)->pd_descr; 3141459a227SAleksandr Rybalko if (dmc620_pmcs[class_ri2unit(class, ri)].domain != 3151459a227SAleksandr Rybalko pcpu_find(cpu)->pc_domain) 3161459a227SAleksandr Rybalko return (EINVAL); 3171459a227SAleksandr Rybalko 3181459a227SAleksandr Rybalko /* check class match */ 3191459a227SAleksandr Rybalko if (pd->pd_class != a->pm_class) 3201459a227SAleksandr Rybalko return (EINVAL); 3211459a227SAleksandr Rybalko 3221459a227SAleksandr Rybalko caps = pm->pm_caps; 3231459a227SAleksandr Rybalko 3241459a227SAleksandr Rybalko PMCDBG3(MDP, ALL, 1, "%s ri=%d caps=0x%x", __func__, ri, caps); 3251459a227SAleksandr Rybalko 3261459a227SAleksandr Rybalko pe = a->pm_ev; 3271459a227SAleksandr Rybalko if (class == PMC_CLASS_DMC620_PMU_CD2) 3281459a227SAleksandr Rybalko e = pe - PMC_EV_DMC620_PMU_CD2_FIRST; 3291459a227SAleksandr Rybalko else 3301459a227SAleksandr Rybalko e = pe - PMC_EV_DMC620_PMU_C_FIRST; 3311459a227SAleksandr Rybalko 3321459a227SAleksandr Rybalko control = (e << DMC620_COUNTER_CONTROL_EVENT_SHIFT) & 3331459a227SAleksandr Rybalko DMC620_COUNTER_CONTROL_EVENT_MASK; 3341459a227SAleksandr Rybalko 3351459a227SAleksandr Rybalko if (caps & PMC_CAP_INVERT) 3361459a227SAleksandr Rybalko control |= DMC620_COUNTER_CONTROL_INVERT; 3371459a227SAleksandr Rybalko 3381459a227SAleksandr Rybalko pm->pm_md.pm_dmc620.pm_control = control; 3391459a227SAleksandr Rybalko pm->pm_md.pm_dmc620.pm_match = a->pm_md.pm_dmc620.pm_dmc620_match; 3401459a227SAleksandr Rybalko pm->pm_md.pm_dmc620.pm_mask = a->pm_md.pm_dmc620.pm_dmc620_mask; 3411459a227SAleksandr Rybalko 3421459a227SAleksandr Rybalko PMCDBG3(MDP, ALL, 2, "%s ri=%d -> control=0x%x", __func__, ri, control); 3431459a227SAleksandr Rybalko 3441459a227SAleksandr Rybalko return (0); 3451459a227SAleksandr Rybalko } 3461459a227SAleksandr Rybalko 3471459a227SAleksandr Rybalko /* 3481459a227SAleksandr Rybalko * Release machine dependent state associated with a PMC. This is a 3491459a227SAleksandr Rybalko * no-op on this architecture. 3501459a227SAleksandr Rybalko * 3511459a227SAleksandr Rybalko */ 3521459a227SAleksandr Rybalko 3531459a227SAleksandr Rybalko /* ARGSUSED0 */ 3541459a227SAleksandr Rybalko CLASSDEP_FN3(dmc620_release_pmc, int, cpu, int, ri, struct pmc *, pmc) 3551459a227SAleksandr Rybalko { 356d78bef0eSBjoern A. Zeeb struct pmc_hw *phw __diagused; 3571459a227SAleksandr Rybalko 3581459a227SAleksandr Rybalko (void) pmc; 3591459a227SAleksandr Rybalko 3601459a227SAleksandr Rybalko KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 3611459a227SAleksandr Rybalko ("[dmc620,%d] illegal CPU value %d", __LINE__, cpu)); 3621459a227SAleksandr Rybalko KASSERT(ri >= 0, ("[dmc620,%d] row-index %d out of range", __LINE__, 3631459a227SAleksandr Rybalko ri)); 3641459a227SAleksandr Rybalko 3651459a227SAleksandr Rybalko phw = dmc620desc(class, cpu, ri)->pd_phw; 3661459a227SAleksandr Rybalko 3671459a227SAleksandr Rybalko KASSERT(phw->phw_pmc == NULL, 3681459a227SAleksandr Rybalko ("[dmc620,%d] PHW pmc %p non-NULL", __LINE__, phw->phw_pmc)); 3691459a227SAleksandr Rybalko 3701459a227SAleksandr Rybalko return (0); 3711459a227SAleksandr Rybalko } 3721459a227SAleksandr Rybalko 3731459a227SAleksandr Rybalko /* 3741459a227SAleksandr Rybalko * start a PMC. 3751459a227SAleksandr Rybalko */ 3761459a227SAleksandr Rybalko 3771459a227SAleksandr Rybalko CLASSDEP_FN2(dmc620_start_pmc, int, cpu, int, ri) 3781459a227SAleksandr Rybalko { 3791459a227SAleksandr Rybalko struct dmc620_descr *desc; 3801459a227SAleksandr Rybalko struct pmc_hw *phw; 3811459a227SAleksandr Rybalko uint64_t control; 3821459a227SAleksandr Rybalko struct pmc *pm; 3831459a227SAleksandr Rybalko 3841459a227SAleksandr Rybalko KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 3851459a227SAleksandr Rybalko ("[dmc620,%d] illegal CPU value %d", __LINE__, cpu)); 3861459a227SAleksandr Rybalko KASSERT(ri >= 0, ("[dmc620,%d] row-index %d out of range", __LINE__, 3871459a227SAleksandr Rybalko ri)); 3881459a227SAleksandr Rybalko 3891459a227SAleksandr Rybalko desc = dmc620desc(class, cpu, ri); 3901459a227SAleksandr Rybalko phw = desc->pd_phw; 3911459a227SAleksandr Rybalko pm = phw->phw_pmc; 3921459a227SAleksandr Rybalko 3931459a227SAleksandr Rybalko KASSERT(pm != NULL, 3941459a227SAleksandr Rybalko ("[dmc620,%d] starting cpu%d,pmc%d with null pmc record", __LINE__, 3951459a227SAleksandr Rybalko cpu, ri)); 3961459a227SAleksandr Rybalko 3971459a227SAleksandr Rybalko PMCDBG3(MDP, STA, 1, "%s cpu=%d ri=%d", __func__, cpu, ri); 3981459a227SAleksandr Rybalko 3991459a227SAleksandr Rybalko pmu_dmc620_wr4(desc->pd_rw_arg, cntr(class, ri), 4001459a227SAleksandr Rybalko DMC620_COUNTER_MASK_LO, pm->pm_md.pm_dmc620.pm_mask & 0xffffffff); 4011459a227SAleksandr Rybalko pmu_dmc620_wr4(desc->pd_rw_arg, cntr(class, ri), 4021459a227SAleksandr Rybalko DMC620_COUNTER_MASK_HI, pm->pm_md.pm_dmc620.pm_mask >> 32); 4031459a227SAleksandr Rybalko pmu_dmc620_wr4(desc->pd_rw_arg, cntr(class, ri), 4041459a227SAleksandr Rybalko DMC620_COUNTER_MATCH_LO, pm->pm_md.pm_dmc620.pm_match & 0xffffffff); 4051459a227SAleksandr Rybalko pmu_dmc620_wr4(desc->pd_rw_arg, cntr(class, ri), 4061459a227SAleksandr Rybalko DMC620_COUNTER_MATCH_HI, pm->pm_md.pm_dmc620.pm_match >> 32); 4071459a227SAleksandr Rybalko /* turn on the PMC ENABLE bit */ 4081459a227SAleksandr Rybalko control = pm->pm_md.pm_dmc620.pm_control | DMC620_COUNTER_CONTROL_ENABLE; 4091459a227SAleksandr Rybalko 4101459a227SAleksandr Rybalko PMCDBG2(MDP, STA, 2, "%s control=0x%x", __func__, control); 4111459a227SAleksandr Rybalko 4121459a227SAleksandr Rybalko pmu_dmc620_wr4(desc->pd_rw_arg, cntr(class, ri), 4131459a227SAleksandr Rybalko DMC620_COUNTER_CONTROL, control); 4141459a227SAleksandr Rybalko return (0); 4151459a227SAleksandr Rybalko } 4161459a227SAleksandr Rybalko 4171459a227SAleksandr Rybalko /* 4181459a227SAleksandr Rybalko * Stop a PMC. 4191459a227SAleksandr Rybalko */ 4201459a227SAleksandr Rybalko 4211459a227SAleksandr Rybalko CLASSDEP_FN2(dmc620_stop_pmc, int, cpu, int, ri) 4221459a227SAleksandr Rybalko { 4231459a227SAleksandr Rybalko struct dmc620_descr *desc; 4241459a227SAleksandr Rybalko struct pmc_hw *phw; 4251459a227SAleksandr Rybalko struct pmc *pm; 4261459a227SAleksandr Rybalko uint64_t control; 4271459a227SAleksandr Rybalko 4281459a227SAleksandr Rybalko KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 4291459a227SAleksandr Rybalko ("[dmc620,%d] illegal CPU value %d", __LINE__, cpu)); 4301459a227SAleksandr Rybalko KASSERT(ri >= 0, ("[dmc620,%d] row-index %d out of range", __LINE__, 4311459a227SAleksandr Rybalko ri)); 4321459a227SAleksandr Rybalko 4331459a227SAleksandr Rybalko desc = dmc620desc(class, cpu, ri); 4341459a227SAleksandr Rybalko phw = desc->pd_phw; 4351459a227SAleksandr Rybalko pm = phw->phw_pmc; 4361459a227SAleksandr Rybalko 4371459a227SAleksandr Rybalko KASSERT(pm != NULL, 4381459a227SAleksandr Rybalko ("[dmc620,%d] cpu%d,pmc%d no PMC to stop", __LINE__, 4391459a227SAleksandr Rybalko cpu, ri)); 4401459a227SAleksandr Rybalko 4411459a227SAleksandr Rybalko PMCDBG2(MDP, STO, 1, "%s ri=%d", __func__, ri); 4421459a227SAleksandr Rybalko 4431459a227SAleksandr Rybalko /* turn off the PMC ENABLE bit */ 4441459a227SAleksandr Rybalko control = pm->pm_md.pm_dmc620.pm_control & ~DMC620_COUNTER_CONTROL_ENABLE; 4451459a227SAleksandr Rybalko pmu_dmc620_wr4(desc->pd_rw_arg, cntr(class, ri), 4461459a227SAleksandr Rybalko DMC620_COUNTER_CONTROL, control); 4471459a227SAleksandr Rybalko 4481459a227SAleksandr Rybalko return (0); 4491459a227SAleksandr Rybalko } 4501459a227SAleksandr Rybalko 4511459a227SAleksandr Rybalko /* 4521459a227SAleksandr Rybalko * describe a PMC 4531459a227SAleksandr Rybalko */ 4541459a227SAleksandr Rybalko CLASSDEP_FN4(dmc620_describe, int, cpu, int, ri, struct pmc_info *, pi, 4551459a227SAleksandr Rybalko struct pmc **, ppmc) 4561459a227SAleksandr Rybalko { 457*31610e34SMitchell Horne struct pmc_descr *pd; 4581459a227SAleksandr Rybalko struct pmc_hw *phw; 4591459a227SAleksandr Rybalko 4601459a227SAleksandr Rybalko KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 4611459a227SAleksandr Rybalko ("[dmc620,%d] illegal CPU %d", __LINE__, cpu)); 4621459a227SAleksandr Rybalko KASSERT(ri >= 0, ("[dmc620,%d] row-index %d out of range", __LINE__, 4631459a227SAleksandr Rybalko ri)); 4641459a227SAleksandr Rybalko 4651459a227SAleksandr Rybalko phw = dmc620desc(class, cpu, ri)->pd_phw; 466*31610e34SMitchell Horne pd = &dmc620desc(class, cpu, ri)->pd_descr; 4671459a227SAleksandr Rybalko 468*31610e34SMitchell Horne strlcpy(pi->pm_name, pd->pd_name, sizeof(pi->pm_name)); 469*31610e34SMitchell Horne pi->pm_class = pd->pd_class; 4701459a227SAleksandr Rybalko 4711459a227SAleksandr Rybalko if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) { 4721459a227SAleksandr Rybalko pi->pm_enabled = TRUE; 4731459a227SAleksandr Rybalko *ppmc = phw->phw_pmc; 4741459a227SAleksandr Rybalko } else { 4751459a227SAleksandr Rybalko pi->pm_enabled = FALSE; 4761459a227SAleksandr Rybalko *ppmc = NULL; 4771459a227SAleksandr Rybalko } 4781459a227SAleksandr Rybalko 4791459a227SAleksandr Rybalko return (0); 4801459a227SAleksandr Rybalko } 4811459a227SAleksandr Rybalko 4821459a227SAleksandr Rybalko /* 4831459a227SAleksandr Rybalko * processor dependent initialization. 4841459a227SAleksandr Rybalko */ 4851459a227SAleksandr Rybalko 4861459a227SAleksandr Rybalko CLASSDEP_FN2(dmc620_pcpu_init, struct pmc_mdep *, md, int, cpu) 4871459a227SAleksandr Rybalko { 4881459a227SAleksandr Rybalko int first_ri, n, npmc; 4891459a227SAleksandr Rybalko struct pmc_hw *phw; 4901459a227SAleksandr Rybalko struct pmc_cpu *pc; 4911459a227SAleksandr Rybalko int mdep_class; 4921459a227SAleksandr Rybalko 4931459a227SAleksandr Rybalko mdep_class = class2mdep(class); 4941459a227SAleksandr Rybalko KASSERT(mdep_class != -1, ("[dmc620,%d] wrong class %d", __LINE__, 4951459a227SAleksandr Rybalko class)); 4961459a227SAleksandr Rybalko KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 4971459a227SAleksandr Rybalko ("[dmc620,%d] insane cpu number %d", __LINE__, cpu)); 4981459a227SAleksandr Rybalko 4991459a227SAleksandr Rybalko PMCDBG1(MDP, INI, 1, "dmc620-init cpu=%d", cpu); 5001459a227SAleksandr Rybalko 5011459a227SAleksandr Rybalko /* 5021459a227SAleksandr Rybalko * Set the content of the hardware descriptors to a known 5031459a227SAleksandr Rybalko * state and initialize pointers in the MI per-cpu descriptor. 5041459a227SAleksandr Rybalko */ 5051459a227SAleksandr Rybalko 5061459a227SAleksandr Rybalko pc = pmc_pcpu[cpu]; 5071459a227SAleksandr Rybalko first_ri = md->pmd_classdep[mdep_class].pcd_ri; 5081459a227SAleksandr Rybalko npmc = md->pmd_classdep[mdep_class].pcd_num; 5091459a227SAleksandr Rybalko 5101459a227SAleksandr Rybalko for (n = 0; n < npmc; n++, phw++) { 5111459a227SAleksandr Rybalko phw = dmc620desc(class, cpu, n)->pd_phw; 5121459a227SAleksandr Rybalko phw->phw_state = PMC_PHW_CPU_TO_STATE(cpu) | 5131459a227SAleksandr Rybalko PMC_PHW_INDEX_TO_STATE(n); 5141459a227SAleksandr Rybalko /* Set enabled only if unit present. */ 5151459a227SAleksandr Rybalko if (dmc620_pmcs[class_ri2unit(class, n)].arg != NULL) 5161459a227SAleksandr Rybalko phw->phw_state |= PMC_PHW_FLAG_IS_ENABLED; 5171459a227SAleksandr Rybalko phw->phw_pmc = NULL; 5181459a227SAleksandr Rybalko pc->pc_hwpmcs[n + first_ri] = phw; 5191459a227SAleksandr Rybalko } 5201459a227SAleksandr Rybalko return (0); 5211459a227SAleksandr Rybalko } 5221459a227SAleksandr Rybalko 5231459a227SAleksandr Rybalko /* 5241459a227SAleksandr Rybalko * processor dependent cleanup prior to the KLD 5251459a227SAleksandr Rybalko * being unloaded 5261459a227SAleksandr Rybalko */ 5271459a227SAleksandr Rybalko 5281459a227SAleksandr Rybalko CLASSDEP_FN2(dmc620_pcpu_fini, struct pmc_mdep *, md, int, cpu) 5291459a227SAleksandr Rybalko { 5301459a227SAleksandr Rybalko 5311459a227SAleksandr Rybalko return (0); 5321459a227SAleksandr Rybalko } 5331459a227SAleksandr Rybalko 5341459a227SAleksandr Rybalko int 5351459a227SAleksandr Rybalko dmc620_intr(struct trapframe *tf, int class, int unit, int i) 5361459a227SAleksandr Rybalko { 537d78bef0eSBjoern A. Zeeb struct pmc_cpu *pc __diagused; 5381459a227SAleksandr Rybalko struct pmc_hw *phw; 5391459a227SAleksandr Rybalko struct pmc *pm; 5401459a227SAleksandr Rybalko int error, cpu, ri; 5411459a227SAleksandr Rybalko 5421459a227SAleksandr Rybalko ri = i + unit * ((class == PMC_CLASS_DMC620_PMU_CD2) ? 5431459a227SAleksandr Rybalko DMC620_CLKDIV2_COUNTERS_N : DMC620_CLK_COUNTERS_N); 5441459a227SAleksandr Rybalko cpu = curcpu; 5451459a227SAleksandr Rybalko KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 5461459a227SAleksandr Rybalko ("[dmc620,%d] CPU %d out of range", __LINE__, cpu)); 5471459a227SAleksandr Rybalko pc = pmc_pcpu[cpu]; 5481459a227SAleksandr Rybalko KASSERT(pc != NULL, ("pc != NULL")); 5491459a227SAleksandr Rybalko 5501459a227SAleksandr Rybalko phw = dmc620desc(class, cpu, ri)->pd_phw; 5511459a227SAleksandr Rybalko KASSERT(phw != NULL, ("phw != NULL")); 5521459a227SAleksandr Rybalko pm = phw->phw_pmc; 5531459a227SAleksandr Rybalko if (pm == NULL) 5541459a227SAleksandr Rybalko return (0); 5551459a227SAleksandr Rybalko 5561459a227SAleksandr Rybalko if (!PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) { 5571459a227SAleksandr Rybalko /* Always CPU0. */ 5581459a227SAleksandr Rybalko pm->pm_pcpu_state[0].pps_overflowcnt += 1; 5591459a227SAleksandr Rybalko return (0); 5601459a227SAleksandr Rybalko } 5611459a227SAleksandr Rybalko 5621459a227SAleksandr Rybalko if (pm->pm_state != PMC_STATE_RUNNING) 5631459a227SAleksandr Rybalko return (0); 5641459a227SAleksandr Rybalko 5651459a227SAleksandr Rybalko error = pmc_process_interrupt(PMC_HR, pm, tf); 5661459a227SAleksandr Rybalko if (error) 5671459a227SAleksandr Rybalko dmc620_stop_pmc(class, cpu, ri); 5681459a227SAleksandr Rybalko 5691459a227SAleksandr Rybalko /* Reload sampling count */ 5701459a227SAleksandr Rybalko dmc620_write_pmc(class, cpu, ri, pm->pm_sc.pm_reloadcount); 5711459a227SAleksandr Rybalko 5721459a227SAleksandr Rybalko return (0); 5731459a227SAleksandr Rybalko } 5741459a227SAleksandr Rybalko 5751459a227SAleksandr Rybalko /* 5761459a227SAleksandr Rybalko * Initialize ourselves. 5771459a227SAleksandr Rybalko */ 5781459a227SAleksandr Rybalko 5791459a227SAleksandr Rybalko int 5801459a227SAleksandr Rybalko pmc_dmc620_initialize_cd2(struct pmc_mdep *md) 5811459a227SAleksandr Rybalko { 5821459a227SAleksandr Rybalko struct pmc_classdep *pcd; 5831459a227SAleksandr Rybalko int i, npmc, unit; 5841459a227SAleksandr Rybalko 5851459a227SAleksandr Rybalko KASSERT(md != NULL, ("[dmc620,%d] md is NULL", __LINE__)); 5861459a227SAleksandr Rybalko KASSERT(dmc620_npmcs <= DMC620_UNIT_MAX, 5871459a227SAleksandr Rybalko ("[dmc620,%d] dmc620_npmcs too big", __LINE__)); 5881459a227SAleksandr Rybalko 5891459a227SAleksandr Rybalko PMCDBG0(MDP,INI,1, "dmc620-initialize"); 5901459a227SAleksandr Rybalko 5911459a227SAleksandr Rybalko npmc = DMC620_CLKDIV2_COUNTERS_N * dmc620_npmcs; 5921459a227SAleksandr Rybalko pcd = &md->pmd_classdep[PMC_MDEP_CLASS_INDEX_DMC620_CD2]; 5931459a227SAleksandr Rybalko 5941459a227SAleksandr Rybalko pcd->pcd_caps = PMC_CAP_SYSTEM | PMC_CAP_READ | 5951459a227SAleksandr Rybalko PMC_CAP_WRITE | PMC_CAP_INVERT | PMC_CAP_QUALIFIER | 5961459a227SAleksandr Rybalko PMC_CAP_INTERRUPT | PMC_CAP_DOMWIDE; 5971459a227SAleksandr Rybalko pcd->pcd_class = PMC_CLASS_DMC620_PMU_CD2; 5981459a227SAleksandr Rybalko pcd->pcd_num = npmc; 5991459a227SAleksandr Rybalko pcd->pcd_ri = md->pmd_npmc; 6001459a227SAleksandr Rybalko pcd->pcd_width = 32; 6011459a227SAleksandr Rybalko 6021459a227SAleksandr Rybalko pcd->pcd_allocate_pmc = dmc620_allocate_pmc_cd2; 6031459a227SAleksandr Rybalko pcd->pcd_config_pmc = dmc620_config_pmc_cd2; 6041459a227SAleksandr Rybalko pcd->pcd_describe = dmc620_describe_cd2; 6051459a227SAleksandr Rybalko pcd->pcd_get_config = dmc620_get_config_cd2; 6061459a227SAleksandr Rybalko pcd->pcd_get_msr = NULL; 6071459a227SAleksandr Rybalko pcd->pcd_pcpu_fini = dmc620_pcpu_fini_cd2; 6081459a227SAleksandr Rybalko pcd->pcd_pcpu_init = dmc620_pcpu_init_cd2; 6091459a227SAleksandr Rybalko pcd->pcd_read_pmc = dmc620_read_pmc_cd2; 6101459a227SAleksandr Rybalko pcd->pcd_release_pmc = dmc620_release_pmc_cd2; 6111459a227SAleksandr Rybalko pcd->pcd_start_pmc = dmc620_start_pmc_cd2; 6121459a227SAleksandr Rybalko pcd->pcd_stop_pmc = dmc620_stop_pmc_cd2; 6131459a227SAleksandr Rybalko pcd->pcd_write_pmc = dmc620_write_pmc_cd2; 6141459a227SAleksandr Rybalko 6151459a227SAleksandr Rybalko md->pmd_npmc += npmc; 6161459a227SAleksandr Rybalko dmc620_pmcdesc[0] = malloc(sizeof(struct dmc620_descr *) * npmc * 6171459a227SAleksandr Rybalko DMC620_PMU_DEFAULT_UNITS_N, M_PMC, M_WAITOK|M_ZERO); 6181459a227SAleksandr Rybalko for (i = 0; i < npmc; i++) { 6191459a227SAleksandr Rybalko dmc620_pmcdesc[0][i] = malloc(sizeof(struct dmc620_descr), 6201459a227SAleksandr Rybalko M_PMC, M_WAITOK|M_ZERO); 6211459a227SAleksandr Rybalko 6221459a227SAleksandr Rybalko unit = i / DMC620_CLKDIV2_COUNTERS_N; 6231459a227SAleksandr Rybalko KASSERT(unit >= 0, ("unit >= 0")); 6241459a227SAleksandr Rybalko KASSERT(dmc620_pmcs[unit].arg != NULL, ("arg != NULL")); 6251459a227SAleksandr Rybalko 6261459a227SAleksandr Rybalko dmc620_pmcdesc[0][i]->pd_rw_arg = dmc620_pmcs[unit].arg; 6271459a227SAleksandr Rybalko dmc620_pmcdesc[0][i]->pd_descr.pd_class = 6281459a227SAleksandr Rybalko PMC_CLASS_DMC620_PMU_CD2; 6291459a227SAleksandr Rybalko dmc620_pmcdesc[0][i]->pd_descr.pd_caps = pcd->pcd_caps; 6301459a227SAleksandr Rybalko dmc620_pmcdesc[0][i]->pd_phw = malloc(sizeof(struct pmc_hw), 6311459a227SAleksandr Rybalko M_PMC, M_WAITOK|M_ZERO); 6321459a227SAleksandr Rybalko snprintf(dmc620_pmcdesc[0][i]->pd_descr.pd_name, 63, 6331459a227SAleksandr Rybalko "DMC620_CD2_%d", i); 6341459a227SAleksandr Rybalko } 6351459a227SAleksandr Rybalko 6361459a227SAleksandr Rybalko return (0); 6371459a227SAleksandr Rybalko } 6381459a227SAleksandr Rybalko 6391459a227SAleksandr Rybalko int 6401459a227SAleksandr Rybalko pmc_dmc620_initialize_c(struct pmc_mdep *md) 6411459a227SAleksandr Rybalko { 6421459a227SAleksandr Rybalko struct pmc_classdep *pcd; 6431459a227SAleksandr Rybalko int i, npmc, unit; 6441459a227SAleksandr Rybalko 6451459a227SAleksandr Rybalko KASSERT(md != NULL, ("[dmc620,%d] md is NULL", __LINE__)); 6461459a227SAleksandr Rybalko KASSERT(dmc620_npmcs <= DMC620_UNIT_MAX, 6471459a227SAleksandr Rybalko ("[dmc620,%d] dmc620_npmcs too big", __LINE__)); 6481459a227SAleksandr Rybalko 6491459a227SAleksandr Rybalko PMCDBG0(MDP,INI,1, "dmc620-initialize"); 6501459a227SAleksandr Rybalko 6511459a227SAleksandr Rybalko npmc = DMC620_CLK_COUNTERS_N * dmc620_npmcs; 6521459a227SAleksandr Rybalko pcd = &md->pmd_classdep[PMC_MDEP_CLASS_INDEX_DMC620_C]; 6531459a227SAleksandr Rybalko 6541459a227SAleksandr Rybalko pcd->pcd_caps = PMC_CAP_SYSTEM | PMC_CAP_READ | 6551459a227SAleksandr Rybalko PMC_CAP_WRITE | PMC_CAP_INVERT | PMC_CAP_QUALIFIER | 6561459a227SAleksandr Rybalko PMC_CAP_INTERRUPT | PMC_CAP_DOMWIDE; 6571459a227SAleksandr Rybalko pcd->pcd_class = PMC_CLASS_DMC620_PMU_C; 6581459a227SAleksandr Rybalko pcd->pcd_num = npmc; 6591459a227SAleksandr Rybalko pcd->pcd_ri = md->pmd_npmc; 6601459a227SAleksandr Rybalko pcd->pcd_width = 32; 6611459a227SAleksandr Rybalko 6621459a227SAleksandr Rybalko pcd->pcd_allocate_pmc = dmc620_allocate_pmc_c; 6631459a227SAleksandr Rybalko pcd->pcd_config_pmc = dmc620_config_pmc_c; 6641459a227SAleksandr Rybalko pcd->pcd_describe = dmc620_describe_c; 6651459a227SAleksandr Rybalko pcd->pcd_get_config = dmc620_get_config_c; 6661459a227SAleksandr Rybalko pcd->pcd_get_msr = NULL; 6671459a227SAleksandr Rybalko pcd->pcd_pcpu_fini = dmc620_pcpu_fini_c; 6681459a227SAleksandr Rybalko pcd->pcd_pcpu_init = dmc620_pcpu_init_c; 6691459a227SAleksandr Rybalko pcd->pcd_read_pmc = dmc620_read_pmc_c; 6701459a227SAleksandr Rybalko pcd->pcd_release_pmc = dmc620_release_pmc_c; 6711459a227SAleksandr Rybalko pcd->pcd_start_pmc = dmc620_start_pmc_c; 6721459a227SAleksandr Rybalko pcd->pcd_stop_pmc = dmc620_stop_pmc_c; 6731459a227SAleksandr Rybalko pcd->pcd_write_pmc = dmc620_write_pmc_c; 6741459a227SAleksandr Rybalko 6751459a227SAleksandr Rybalko md->pmd_npmc += npmc; 6761459a227SAleksandr Rybalko dmc620_pmcdesc[1] = malloc(sizeof(struct dmc620_descr *) * npmc * 6771459a227SAleksandr Rybalko DMC620_PMU_DEFAULT_UNITS_N, M_PMC, M_WAITOK|M_ZERO); 6781459a227SAleksandr Rybalko for (i = 0; i < npmc; i++) { 6791459a227SAleksandr Rybalko dmc620_pmcdesc[1][i] = malloc(sizeof(struct dmc620_descr), 6801459a227SAleksandr Rybalko M_PMC, M_WAITOK|M_ZERO); 6811459a227SAleksandr Rybalko 6821459a227SAleksandr Rybalko unit = i / DMC620_CLK_COUNTERS_N; 6831459a227SAleksandr Rybalko KASSERT(unit >= 0, ("unit >= 0")); 6841459a227SAleksandr Rybalko KASSERT(dmc620_pmcs[unit].arg != NULL, ("arg != NULL")); 6851459a227SAleksandr Rybalko 6861459a227SAleksandr Rybalko dmc620_pmcdesc[1][i]->pd_rw_arg = dmc620_pmcs[unit].arg; 6871459a227SAleksandr Rybalko dmc620_pmcdesc[1][i]->pd_descr.pd_class = PMC_CLASS_DMC620_PMU_C; 6881459a227SAleksandr Rybalko dmc620_pmcdesc[1][i]->pd_descr.pd_caps = pcd->pcd_caps; 6891459a227SAleksandr Rybalko dmc620_pmcdesc[1][i]->pd_phw = malloc(sizeof(struct pmc_hw), 6901459a227SAleksandr Rybalko M_PMC, M_WAITOK|M_ZERO); 6911459a227SAleksandr Rybalko snprintf(dmc620_pmcdesc[1][i]->pd_descr.pd_name, 63, 6921459a227SAleksandr Rybalko "DMC620_C_%d", i); 6931459a227SAleksandr Rybalko } 6941459a227SAleksandr Rybalko 6951459a227SAleksandr Rybalko return (0); 6961459a227SAleksandr Rybalko } 6971459a227SAleksandr Rybalko 6981459a227SAleksandr Rybalko void 6991459a227SAleksandr Rybalko pmc_dmc620_finalize_cd2(struct pmc_mdep *md) 7001459a227SAleksandr Rybalko { 7011459a227SAleksandr Rybalko struct pmc_classdep *pcd; 7021459a227SAleksandr Rybalko int i, npmc; 7031459a227SAleksandr Rybalko 7041459a227SAleksandr Rybalko KASSERT(md->pmd_classdep[PMC_MDEP_CLASS_INDEX_DMC620_CD2].pcd_class == 7051459a227SAleksandr Rybalko PMC_CLASS_DMC620_PMU_CD2, ("[dmc620,%d] pmc class mismatch", 7061459a227SAleksandr Rybalko __LINE__)); 7071459a227SAleksandr Rybalko 7081459a227SAleksandr Rybalko pcd = &md->pmd_classdep[PMC_MDEP_CLASS_INDEX_DMC620_CD2]; 7091459a227SAleksandr Rybalko 7101459a227SAleksandr Rybalko npmc = pcd->pcd_num; 7111459a227SAleksandr Rybalko for (i = 0; i < npmc; i++) { 7121459a227SAleksandr Rybalko free(dmc620_pmcdesc[0][i]->pd_phw, M_PMC); 7131459a227SAleksandr Rybalko free(dmc620_pmcdesc[0][i], M_PMC); 7141459a227SAleksandr Rybalko } 7151459a227SAleksandr Rybalko free(dmc620_pmcdesc[0], M_PMC); 7161459a227SAleksandr Rybalko dmc620_pmcdesc[0] = NULL; 7171459a227SAleksandr Rybalko } 7181459a227SAleksandr Rybalko 7191459a227SAleksandr Rybalko void 7201459a227SAleksandr Rybalko pmc_dmc620_finalize_c(struct pmc_mdep *md) 7211459a227SAleksandr Rybalko { 7221459a227SAleksandr Rybalko struct pmc_classdep *pcd; 7231459a227SAleksandr Rybalko int i, npmc; 7241459a227SAleksandr Rybalko 7251459a227SAleksandr Rybalko KASSERT(md->pmd_classdep[PMC_MDEP_CLASS_INDEX_DMC620_C].pcd_class == 7261459a227SAleksandr Rybalko PMC_CLASS_DMC620_PMU_C, ("[dmc620,%d] pmc class mismatch", 7271459a227SAleksandr Rybalko __LINE__)); 7281459a227SAleksandr Rybalko 7291459a227SAleksandr Rybalko pcd = &md->pmd_classdep[PMC_MDEP_CLASS_INDEX_DMC620_C]; 7301459a227SAleksandr Rybalko 7311459a227SAleksandr Rybalko npmc = pcd->pcd_num; 7321459a227SAleksandr Rybalko for (i = 0; i < npmc; i++) { 7331459a227SAleksandr Rybalko free(dmc620_pmcdesc[1][i]->pd_phw, M_PMC); 7341459a227SAleksandr Rybalko free(dmc620_pmcdesc[1][i], M_PMC); 7351459a227SAleksandr Rybalko } 7361459a227SAleksandr Rybalko free(dmc620_pmcdesc[1], M_PMC); 7371459a227SAleksandr Rybalko dmc620_pmcdesc[1] = NULL; 7381459a227SAleksandr Rybalko } 739