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