1233334Sgonzo/*-
2233334Sgonzo * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org>
3233334Sgonzo * All rights reserved.
4233334Sgonzo *
5233334Sgonzo * Redistribution and use in source and binary forms, with or without
6233334Sgonzo * modification, are permitted provided that the following conditions
7233334Sgonzo * are met:
8233334Sgonzo * 1. Redistributions of source code must retain the above copyright
9233334Sgonzo *    notice, this list of conditions and the following disclaimer.
10233334Sgonzo * 2. Redistributions in binary form must reproduce the above copyright
11233334Sgonzo *    notice, this list of conditions and the following disclaimer in the
12233334Sgonzo *    documentation and/or other materials provided with the distribution.
13233334Sgonzo *
14233334Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15233334Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16233334Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17233334Sgonzo * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18233334Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19233334Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20233334Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21233334Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22233334Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23233334Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24233334Sgonzo * SUCH DAMAGE.
25233334Sgonzo *
26233334Sgonzo */
27233334Sgonzo
28233334Sgonzo#include <sys/cdefs.h>
29233334Sgonzo__FBSDID("$FreeBSD: releng/10.3/sys/dev/hwpmc/hwpmc_octeon.c 283884 2015-06-01 17:57:05Z jhb $");
30233334Sgonzo
31233334Sgonzo#include <sys/param.h>
32233334Sgonzo#include <sys/systm.h>
33233334Sgonzo#include <sys/pmc.h>
34233334Sgonzo#include <sys/pmckern.h>
35233334Sgonzo
36233334Sgonzo#include <machine/cpu.h>
37233334Sgonzo#include <machine/cpufunc.h>
38233334Sgonzo#include <machine/pmc_mdep.h>
39233334Sgonzo
40233334Sgonzo#include <contrib/octeon-sdk/cvmx.h>
41233334Sgonzo#include <contrib/octeon-sdk/cvmx-core.h>
42233334Sgonzo
43233334Sgonzo#define	OCTEON_PMC_CAPS	(PMC_CAP_INTERRUPT | PMC_CAP_USER |     \
44233334Sgonzo				 PMC_CAP_SYSTEM | PMC_CAP_EDGE |	\
45233334Sgonzo				 PMC_CAP_THRESHOLD | PMC_CAP_READ |	\
46233334Sgonzo				 PMC_CAP_WRITE | PMC_CAP_INVERT |	\
47233334Sgonzo				 PMC_CAP_QUALIFIER)
48233334Sgonzo
49233334Sgonzoconst struct mips_event_code_map mips_event_codes[] =
50233334Sgonzo{
51233334Sgonzo    { PMC_EV_OCTEON_CLK, MIPS_CTR_ALL, CVMX_CORE_PERF_CLK },
52233334Sgonzo    { PMC_EV_OCTEON_ISSUE, MIPS_CTR_ALL, CVMX_CORE_PERF_ISSUE },
53233334Sgonzo    { PMC_EV_OCTEON_RET, MIPS_CTR_ALL, CVMX_CORE_PERF_RET },
54233334Sgonzo    { PMC_EV_OCTEON_NISSUE, MIPS_CTR_ALL, CVMX_CORE_PERF_NISSUE },
55233334Sgonzo    { PMC_EV_OCTEON_SISSUE, MIPS_CTR_ALL, CVMX_CORE_PERF_SISSUE },
56233334Sgonzo    { PMC_EV_OCTEON_DISSUE, MIPS_CTR_ALL, CVMX_CORE_PERF_DISSUE },
57233334Sgonzo    { PMC_EV_OCTEON_IFI, MIPS_CTR_ALL, CVMX_CORE_PERF_IFI },
58233334Sgonzo    { PMC_EV_OCTEON_BR, MIPS_CTR_ALL, CVMX_CORE_PERF_BR },
59233334Sgonzo    { PMC_EV_OCTEON_BRMIS, MIPS_CTR_ALL, CVMX_CORE_PERF_BRMIS },
60233334Sgonzo    { PMC_EV_OCTEON_J, MIPS_CTR_ALL, CVMX_CORE_PERF_J },
61233334Sgonzo    { PMC_EV_OCTEON_JMIS, MIPS_CTR_ALL, CVMX_CORE_PERF_JMIS },
62233334Sgonzo    { PMC_EV_OCTEON_REPLAY, MIPS_CTR_ALL, CVMX_CORE_PERF_REPLAY },
63233334Sgonzo    { PMC_EV_OCTEON_IUNA, MIPS_CTR_ALL, CVMX_CORE_PERF_IUNA },
64233334Sgonzo    { PMC_EV_OCTEON_TRAP, MIPS_CTR_ALL, CVMX_CORE_PERF_TRAP },
65233334Sgonzo    { PMC_EV_OCTEON_UULOAD, MIPS_CTR_ALL, CVMX_CORE_PERF_UULOAD },
66233334Sgonzo    { PMC_EV_OCTEON_UUSTORE, MIPS_CTR_ALL, CVMX_CORE_PERF_UUSTORE },
67233334Sgonzo    { PMC_EV_OCTEON_ULOAD, MIPS_CTR_ALL, CVMX_CORE_PERF_ULOAD },
68233334Sgonzo    { PMC_EV_OCTEON_USTORE, MIPS_CTR_ALL, CVMX_CORE_PERF_USTORE },
69233334Sgonzo    { PMC_EV_OCTEON_EC, MIPS_CTR_ALL, CVMX_CORE_PERF_EC },
70233334Sgonzo    { PMC_EV_OCTEON_MC, MIPS_CTR_ALL, CVMX_CORE_PERF_MC },
71233334Sgonzo    { PMC_EV_OCTEON_CC, MIPS_CTR_ALL, CVMX_CORE_PERF_CC },
72233334Sgonzo    { PMC_EV_OCTEON_CSRC, MIPS_CTR_ALL, CVMX_CORE_PERF_CSRC },
73233334Sgonzo    { PMC_EV_OCTEON_CFETCH, MIPS_CTR_ALL, CVMX_CORE_PERF_CFETCH },
74233334Sgonzo    { PMC_EV_OCTEON_CPREF, MIPS_CTR_ALL, CVMX_CORE_PERF_CPREF },
75233334Sgonzo    { PMC_EV_OCTEON_ICA, MIPS_CTR_ALL, CVMX_CORE_PERF_ICA },
76233334Sgonzo    { PMC_EV_OCTEON_II, MIPS_CTR_ALL, CVMX_CORE_PERF_II },
77233334Sgonzo    { PMC_EV_OCTEON_IP, MIPS_CTR_ALL, CVMX_CORE_PERF_IP },
78233334Sgonzo    { PMC_EV_OCTEON_CIMISS, MIPS_CTR_ALL, CVMX_CORE_PERF_CIMISS },
79233334Sgonzo    { PMC_EV_OCTEON_WBUF, MIPS_CTR_ALL, CVMX_CORE_PERF_WBUF },
80233334Sgonzo    { PMC_EV_OCTEON_WDAT, MIPS_CTR_ALL, CVMX_CORE_PERF_WDAT },
81233334Sgonzo    { PMC_EV_OCTEON_WBUFLD, MIPS_CTR_ALL, CVMX_CORE_PERF_WBUFLD },
82233334Sgonzo    { PMC_EV_OCTEON_WBUFFL, MIPS_CTR_ALL, CVMX_CORE_PERF_WBUFFL },
83233334Sgonzo    { PMC_EV_OCTEON_WBUFTR, MIPS_CTR_ALL, CVMX_CORE_PERF_WBUFTR },
84233334Sgonzo    { PMC_EV_OCTEON_BADD, MIPS_CTR_ALL, CVMX_CORE_PERF_BADD },
85233334Sgonzo    { PMC_EV_OCTEON_BADDL2, MIPS_CTR_ALL, CVMX_CORE_PERF_BADDL2 },
86233334Sgonzo    { PMC_EV_OCTEON_BFILL, MIPS_CTR_ALL, CVMX_CORE_PERF_BFILL },
87233334Sgonzo    { PMC_EV_OCTEON_DDIDS, MIPS_CTR_ALL, CVMX_CORE_PERF_DDIDS },
88233334Sgonzo    { PMC_EV_OCTEON_IDIDS, MIPS_CTR_ALL, CVMX_CORE_PERF_IDIDS },
89233334Sgonzo    { PMC_EV_OCTEON_DIDNA, MIPS_CTR_ALL, CVMX_CORE_PERF_DIDNA },
90233334Sgonzo    { PMC_EV_OCTEON_LDS, MIPS_CTR_ALL, CVMX_CORE_PERF_LDS },
91233334Sgonzo    { PMC_EV_OCTEON_LMLDS, MIPS_CTR_ALL, CVMX_CORE_PERF_LMLDS },
92233334Sgonzo    { PMC_EV_OCTEON_IOLDS, MIPS_CTR_ALL, CVMX_CORE_PERF_IOLDS },
93233334Sgonzo    { PMC_EV_OCTEON_DMLDS, MIPS_CTR_ALL, CVMX_CORE_PERF_DMLDS },
94233334Sgonzo    { PMC_EV_OCTEON_STS, MIPS_CTR_ALL, CVMX_CORE_PERF_STS },
95233334Sgonzo    { PMC_EV_OCTEON_LMSTS, MIPS_CTR_ALL, CVMX_CORE_PERF_LMSTS },
96233334Sgonzo    { PMC_EV_OCTEON_IOSTS, MIPS_CTR_ALL, CVMX_CORE_PERF_IOSTS },
97233334Sgonzo    { PMC_EV_OCTEON_IOBDMA, MIPS_CTR_ALL, CVMX_CORE_PERF_IOBDMA },
98233334Sgonzo    { PMC_EV_OCTEON_DTLB, MIPS_CTR_ALL, CVMX_CORE_PERF_DTLB },
99233334Sgonzo    { PMC_EV_OCTEON_DTLBAD, MIPS_CTR_ALL, CVMX_CORE_PERF_DTLBAD },
100233334Sgonzo    { PMC_EV_OCTEON_ITLB, MIPS_CTR_ALL, CVMX_CORE_PERF_ITLB },
101233334Sgonzo    { PMC_EV_OCTEON_SYNC, MIPS_CTR_ALL, CVMX_CORE_PERF_SYNC },
102233334Sgonzo    { PMC_EV_OCTEON_SYNCIOB, MIPS_CTR_ALL, CVMX_CORE_PERF_SYNCIOB },
103233334Sgonzo    { PMC_EV_OCTEON_SYNCW, MIPS_CTR_ALL, CVMX_CORE_PERF_SYNCW },
104233334Sgonzo};
105233334Sgonzo
106233334Sgonzoconst int mips_event_codes_size =
107233334Sgonzo	sizeof(mips_event_codes) / sizeof(mips_event_codes[0]);
108233334Sgonzo
109233334Sgonzostruct mips_pmc_spec mips_pmc_spec = {
110233334Sgonzo	.ps_cpuclass = PMC_CLASS_OCTEON,
111233334Sgonzo	.ps_cputype = PMC_CPU_MIPS_OCTEON,
112233334Sgonzo	.ps_capabilities = OCTEON_PMC_CAPS,
113233334Sgonzo	.ps_counter_width = 64
114233334Sgonzo};
115233334Sgonzo
116233334Sgonzo/*
117233334Sgonzo * Performance Count Register N
118233334Sgonzo */
119233334Sgonzouint64_t
120233334Sgonzomips_pmcn_read(unsigned int pmc)
121233334Sgonzo{
122233334Sgonzo	uint64_t reg = 0;
123233334Sgonzo
124233334Sgonzo	KASSERT(pmc < mips_npmcs, ("[mips,%d] illegal PMC number %d",
125233334Sgonzo				   __LINE__, pmc));
126233334Sgonzo
127233334Sgonzo	/* The counter value is the next value after the control register. */
128233334Sgonzo	switch (pmc) {
129233334Sgonzo	case 0:
130233334Sgonzo		CVMX_MF_COP0(reg, COP0_PERFVALUE0);
131233334Sgonzo		break;
132233334Sgonzo	case 1:
133233334Sgonzo		CVMX_MF_COP0(reg, COP0_PERFVALUE1);
134233334Sgonzo		break;
135233334Sgonzo	default:
136233334Sgonzo		return 0;
137233334Sgonzo	}
138233334Sgonzo	return (reg);
139233334Sgonzo}
140233334Sgonzo
141233334Sgonzouint64_t
142233334Sgonzomips_pmcn_write(unsigned int pmc, uint64_t reg)
143233334Sgonzo{
144233334Sgonzo
145233334Sgonzo	KASSERT(pmc < mips_npmcs, ("[mips,%d] illegal PMC number %d",
146233334Sgonzo				   __LINE__, pmc));
147233334Sgonzo
148233334Sgonzo	switch (pmc) {
149233334Sgonzo	case 0:
150233334Sgonzo		CVMX_MT_COP0(reg, COP0_PERFVALUE0);
151233334Sgonzo		break;
152233334Sgonzo	case 1:
153233334Sgonzo		CVMX_MT_COP0(reg, COP0_PERFVALUE1);
154233334Sgonzo		break;
155233334Sgonzo	default:
156233334Sgonzo		return 0;
157233334Sgonzo	}
158233334Sgonzo	return (reg);
159233334Sgonzo}
160233334Sgonzo
161233334Sgonzouint32_t
162233334Sgonzomips_get_perfctl(int cpu, int ri, uint32_t event, uint32_t caps)
163233334Sgonzo{
164233334Sgonzo	cvmx_core_perf_control_t control;
165233334Sgonzo
166233334Sgonzo	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
167233334Sgonzo	    ("[mips,%d] illegal CPU value %d", __LINE__, cpu));
168233334Sgonzo	KASSERT(ri >= 0 && ri < mips_npmcs,
169233334Sgonzo	    ("[mips,%d] illegal row index %d", __LINE__, ri));
170233334Sgonzo
171233334Sgonzo	control.s.event = event;
172233334Sgonzo
173233334Sgonzo	if (caps & PMC_CAP_SYSTEM) {
174233334Sgonzo		control.s.k = 1;
175233334Sgonzo		control.s.s = 1;
176233334Sgonzo		control.s.ex = 1;
177233334Sgonzo	}
178233334Sgonzo
179233334Sgonzo	if (caps & PMC_CAP_USER)
180233334Sgonzo		control.s.u = 1;
181233334Sgonzo
182233334Sgonzo	if ((caps & (PMC_CAP_USER | PMC_CAP_SYSTEM)) == 0) {
183233334Sgonzo		control.s.k = 1;
184233334Sgonzo		control.s.s = 1;
185233334Sgonzo		control.s.u = 1;
186233334Sgonzo		control.s.ex = 1;
187233334Sgonzo	}
188233334Sgonzo
189233334Sgonzo	if (caps & PMC_CAP_INTERRUPT)
190233334Sgonzo		control.s.ie = 1;
191233334Sgonzo
192283884Sjhb	PMCDBG2(MDP,ALL,2,"mips-allocate ri=%d -> config=0x%x", ri,
193283884Sjhb	    control.u32);
194233334Sgonzo
195233334Sgonzo	return (control.u32);
196233334Sgonzo}
197