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$");
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
106298431Spfgconst int mips_event_codes_size = nitems(mips_event_codes);
107233334Sgonzo
108233334Sgonzostruct mips_pmc_spec mips_pmc_spec = {
109233334Sgonzo	.ps_cpuclass = PMC_CLASS_OCTEON,
110233334Sgonzo	.ps_cputype = PMC_CPU_MIPS_OCTEON,
111233334Sgonzo	.ps_capabilities = OCTEON_PMC_CAPS,
112233334Sgonzo	.ps_counter_width = 64
113233334Sgonzo};
114233334Sgonzo
115233334Sgonzo/*
116233334Sgonzo * Performance Count Register N
117233334Sgonzo */
118233334Sgonzouint64_t
119233334Sgonzomips_pmcn_read(unsigned int pmc)
120233334Sgonzo{
121233334Sgonzo	uint64_t reg = 0;
122233334Sgonzo
123233334Sgonzo	KASSERT(pmc < mips_npmcs, ("[mips,%d] illegal PMC number %d",
124233334Sgonzo				   __LINE__, pmc));
125233334Sgonzo
126233334Sgonzo	/* The counter value is the next value after the control register. */
127233334Sgonzo	switch (pmc) {
128233334Sgonzo	case 0:
129233334Sgonzo		CVMX_MF_COP0(reg, COP0_PERFVALUE0);
130233334Sgonzo		break;
131233334Sgonzo	case 1:
132233334Sgonzo		CVMX_MF_COP0(reg, COP0_PERFVALUE1);
133233334Sgonzo		break;
134233334Sgonzo	default:
135233334Sgonzo		return 0;
136233334Sgonzo	}
137233334Sgonzo	return (reg);
138233334Sgonzo}
139233334Sgonzo
140233334Sgonzouint64_t
141233334Sgonzomips_pmcn_write(unsigned int pmc, uint64_t reg)
142233334Sgonzo{
143233334Sgonzo
144233334Sgonzo	KASSERT(pmc < mips_npmcs, ("[mips,%d] illegal PMC number %d",
145233334Sgonzo				   __LINE__, pmc));
146233334Sgonzo
147233334Sgonzo	switch (pmc) {
148233334Sgonzo	case 0:
149233334Sgonzo		CVMX_MT_COP0(reg, COP0_PERFVALUE0);
150233334Sgonzo		break;
151233334Sgonzo	case 1:
152233334Sgonzo		CVMX_MT_COP0(reg, COP0_PERFVALUE1);
153233334Sgonzo		break;
154233334Sgonzo	default:
155233334Sgonzo		return 0;
156233334Sgonzo	}
157233334Sgonzo	return (reg);
158233334Sgonzo}
159233334Sgonzo
160233334Sgonzouint32_t
161233334Sgonzomips_get_perfctl(int cpu, int ri, uint32_t event, uint32_t caps)
162233334Sgonzo{
163233334Sgonzo	cvmx_core_perf_control_t control;
164233334Sgonzo
165233334Sgonzo	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
166233334Sgonzo	    ("[mips,%d] illegal CPU value %d", __LINE__, cpu));
167233334Sgonzo	KASSERT(ri >= 0 && ri < mips_npmcs,
168233334Sgonzo	    ("[mips,%d] illegal row index %d", __LINE__, ri));
169233334Sgonzo
170233334Sgonzo	control.s.event = event;
171233334Sgonzo
172233334Sgonzo	if (caps & PMC_CAP_SYSTEM) {
173233334Sgonzo		control.s.k = 1;
174233334Sgonzo		control.s.s = 1;
175233334Sgonzo		control.s.ex = 1;
176233334Sgonzo	}
177233334Sgonzo
178233334Sgonzo	if (caps & PMC_CAP_USER)
179233334Sgonzo		control.s.u = 1;
180233334Sgonzo
181233334Sgonzo	if ((caps & (PMC_CAP_USER | PMC_CAP_SYSTEM)) == 0) {
182233334Sgonzo		control.s.k = 1;
183233334Sgonzo		control.s.s = 1;
184233334Sgonzo		control.s.u = 1;
185233334Sgonzo		control.s.ex = 1;
186233334Sgonzo	}
187233334Sgonzo
188233334Sgonzo	if (caps & PMC_CAP_INTERRUPT)
189233334Sgonzo		control.s.ie = 1;
190233334Sgonzo
191282658Sjhb	PMCDBG2(MDP,ALL,2,"mips-allocate ri=%d -> config=0x%x", ri,
192282658Sjhb	    control.u32);
193233334Sgonzo
194233334Sgonzo	return (control.u32);
195233334Sgonzo}
196