1145256Sjkoshy/*-
2183436Sjkoshy * Copyright (c) 2003-2008, Joseph Koshy
3174214Sjkoshy * Copyright (c) 2007 The FreeBSD Foundation
4145256Sjkoshy * All rights reserved.
5145256Sjkoshy *
6174214Sjkoshy * Portions of this software were developed by A. Joseph Koshy under
7174214Sjkoshy * sponsorship from the FreeBSD Foundation and Google, Inc.
8174214Sjkoshy *
9145256Sjkoshy * Redistribution and use in source and binary forms, with or without
10145256Sjkoshy * modification, are permitted provided that the following conditions
11145256Sjkoshy * are met:
12145256Sjkoshy * 1. Redistributions of source code must retain the above copyright
13145256Sjkoshy *    notice, this list of conditions and the following disclaimer.
14145256Sjkoshy * 2. Redistributions in binary form must reproduce the above copyright
15145256Sjkoshy *    notice, this list of conditions and the following disclaimer in the
16145256Sjkoshy *    documentation and/or other materials provided with the distribution.
17145256Sjkoshy *
18145256Sjkoshy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19145256Sjkoshy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20145256Sjkoshy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21145256Sjkoshy * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22145256Sjkoshy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23145256Sjkoshy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24145256Sjkoshy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25145256Sjkoshy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26145256Sjkoshy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27145256Sjkoshy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28145256Sjkoshy * SUCH DAMAGE.
29145256Sjkoshy *
30145256Sjkoshy * $FreeBSD$
31145256Sjkoshy */
32145256Sjkoshy
33145256Sjkoshy#ifndef _SYS_PMC_H_
34145256Sjkoshy#define	_SYS_PMC_H_
35145256Sjkoshy
36147191Sjkoshy#include <dev/hwpmc/pmc_events.h>
37147191Sjkoshy
38145336Smarcel#include <machine/pmc_mdep.h>
39147191Sjkoshy#include <machine/profile.h>
40145336Smarcel
41145256Sjkoshy#define	PMC_MODULE_NAME		"hwpmc"
42233628Sfabient#define	PMC_NAME_MAX		64 /* HW counter name size */
43233628Sfabient#define	PMC_CLASS_MAX		8  /* max #classes of PMCs per-system */
44145256Sjkoshy
45147191Sjkoshy/*
46147191Sjkoshy * Kernel<->userland API version number [MMmmpppp]
47147191Sjkoshy *
48147191Sjkoshy * Major numbers are to be incremented when an incompatible change to
49147191Sjkoshy * the ABI occurs that older clients will not be able to handle.
50147191Sjkoshy *
51147191Sjkoshy * Minor numbers are incremented when a backwards compatible change
52147191Sjkoshy * occurs that allows older correct programs to run unchanged.  For
53147191Sjkoshy * example, when support for a new PMC type is added.
54147191Sjkoshy *
55147191Sjkoshy * The patch version is incremented for every bug fix.
56147191Sjkoshy */
57175314Sjkoshy#define	PMC_VERSION_MAJOR	0x03
58185363Sjkoshy#define	PMC_VERSION_MINOR	0x01
59157144Sjkoshy#define	PMC_VERSION_PATCH	0x0000
60145256Sjkoshy
61145256Sjkoshy#define	PMC_VERSION		(PMC_VERSION_MAJOR << 24 |		\
62145256Sjkoshy	PMC_VERSION_MINOR << 16 | PMC_VERSION_PATCH)
63145256Sjkoshy
64145256Sjkoshy/*
65183725Sjkoshy * Kinds of CPUs known.
66183725Sjkoshy *
67183725Sjkoshy * We keep track of CPU variants that need to be distinguished in
68183725Sjkoshy * some way for PMC operations.  CPU names are grouped by manufacturer
69183725Sjkoshy * and numbered sparsely in order to minimize changes to the ABI involved
70183725Sjkoshy * when new CPUs are added.
71145256Sjkoshy */
72145256Sjkoshy
73183725Sjkoshy#define	__PMC_CPUS()						\
74183725Sjkoshy	__PMC_CPU(AMD_K7,	0x00,	"AMD K7")		\
75183725Sjkoshy	__PMC_CPU(AMD_K8,	0x01,	"AMD K8")		\
76183725Sjkoshy	__PMC_CPU(INTEL_P5,	0x80,	"Intel Pentium")	\
77183725Sjkoshy	__PMC_CPU(INTEL_P6,	0x81,	"Intel Pentium Pro")	\
78183725Sjkoshy	__PMC_CPU(INTEL_CL,	0x82,	"Intel Celeron")	\
79183725Sjkoshy	__PMC_CPU(INTEL_PII,	0x83,	"Intel Pentium II")	\
80183725Sjkoshy	__PMC_CPU(INTEL_PIII,	0x84,	"Intel Pentium III")	\
81183725Sjkoshy	__PMC_CPU(INTEL_PM,	0x85,	"Intel Pentium M")	\
82183725Sjkoshy	__PMC_CPU(INTEL_PIV,	0x86,	"Intel Pentium IV")	\
83183725Sjkoshy	__PMC_CPU(INTEL_CORE,	0x87,	"Intel Core Solo/Duo")	\
84183725Sjkoshy	__PMC_CPU(INTEL_CORE2,	0x88,	"Intel Core2")		\
85185363Sjkoshy	__PMC_CPU(INTEL_CORE2EXTREME,	0x89,	"Intel Core2 Extreme")	\
86233628Sfabient	__PMC_CPU(INTEL_ATOM,	0x8A,	"Intel Atom")		\
87233628Sfabient	__PMC_CPU(INTEL_COREI7, 0x8B,   "Intel Core i7")	\
88233628Sfabient	__PMC_CPU(INTEL_WESTMERE, 0x8C,   "Intel Westmere")	\
89233628Sfabient	__PMC_CPU(INTEL_SANDYBRIDGE, 0x8D,   "Intel Sandy Bridge")	\
90240164Sfabient	__PMC_CPU(INTEL_IVYBRIDGE, 0x8E,   "Intel Ivy Bridge")	\
91241738Ssbruno	__PMC_CPU(INTEL_SANDYBRIDGE_XEON, 0x8F,   "Intel Sandy Bridge Xeon")	\
92246166Ssbruno	__PMC_CPU(INTEL_IVYBRIDGE_XEON, 0x90,   "Intel Ivy Bridge Xeon")	\
93248842Ssbruno	__PMC_CPU(INTEL_HASWELL, 0x91,   "Intel Haswell")	\
94266911Shiren	__PMC_CPU(INTEL_ATOM_SILVERMONT, 0x92,	"Intel Atom Silvermont")    \
95267602Skib	__PMC_CPU(INTEL_NEHALEM_EX, 0x93,   "Intel Nehalem Xeon 7500")	\
96267602Skib	__PMC_CPU(INTEL_WESTMERE_EX, 0x94,   "Intel Westmere Xeon E7")	\
97233628Sfabient	__PMC_CPU(INTEL_XSCALE,	0x100,	"Intel XScale")		\
98233628Sfabient	__PMC_CPU(MIPS_24K,     0x200,  "MIPS 24K")		\
99233628Sfabient	__PMC_CPU(MIPS_OCTEON,  0x201,  "Cavium Octeon")	\
100233628Sfabient	__PMC_CPU(PPC_7450,     0x300,  "PowerPC MPC7450")	\
101263122Sjhibbits	__PMC_CPU(PPC_970,      0x380,  "IBM PowerPC 970")	\
102233628Sfabient	__PMC_CPU(GENERIC, 	0x400,  "Generic")
103145256Sjkoshy
104145256Sjkoshyenum pmc_cputype {
105145256Sjkoshy#undef	__PMC_CPU
106183725Sjkoshy#define	__PMC_CPU(S,V,D)	PMC_CPU_##S = V,
107145256Sjkoshy	__PMC_CPUS()
108145256Sjkoshy};
109145256Sjkoshy
110145256Sjkoshy#define	PMC_CPU_FIRST	PMC_CPU_AMD_K7
111233628Sfabient#define	PMC_CPU_LAST	PMC_CPU_GENERIC
112145256Sjkoshy
113145256Sjkoshy/*
114145256Sjkoshy * Classes of PMCs
115145256Sjkoshy */
116145256Sjkoshy
117145256Sjkoshy#define	__PMC_CLASSES()							\
118145256Sjkoshy	__PMC_CLASS(TSC)	/* CPU Timestamp counter */		\
119145256Sjkoshy	__PMC_CLASS(K7)		/* AMD K7 performance counters */	\
120145256Sjkoshy	__PMC_CLASS(K8)		/* AMD K8 performance counters */	\
121145256Sjkoshy	__PMC_CLASS(P5)		/* Intel Pentium counters */		\
122145256Sjkoshy	__PMC_CLASS(P6)		/* Intel Pentium Pro counters */	\
123183436Sjkoshy	__PMC_CLASS(P4)		/* Intel Pentium-IV counters */		\
124183436Sjkoshy	__PMC_CLASS(IAF)	/* Intel Core2/Atom, fixed function */	\
125209196Sfabient	__PMC_CLASS(IAP)	/* Intel Core...Atom, programmable */	\
126209196Sfabient	__PMC_CLASS(UCF)	/* Intel Uncore fixed function */	\
127209196Sfabient	__PMC_CLASS(UCP)	/* Intel Uncore programmable */		\
128209196Sfabient	__PMC_CLASS(XSCALE)	/* Intel XScale counters */		\
129233332Sgonzo	__PMC_CLASS(MIPS24K)	/* MIPS 24K */				\
130233332Sgonzo	__PMC_CLASS(OCTEON)	/* Cavium Octeon */			\
131233628Sfabient	__PMC_CLASS(PPC7450)	/* Motorola MPC7450 class */		\
132263122Sjhibbits	__PMC_CLASS(PPC970)	/* IBM PowerPC 970 class */		\
133233628Sfabient	__PMC_CLASS(SOFT)	/* Software events */
134145256Sjkoshy
135145256Sjkoshyenum pmc_class {
136145256Sjkoshy#undef  __PMC_CLASS
137145256Sjkoshy#define	__PMC_CLASS(N)	PMC_CLASS_##N ,
138145256Sjkoshy	__PMC_CLASSES()
139145256Sjkoshy};
140145256Sjkoshy
141145256Sjkoshy#define	PMC_CLASS_FIRST	PMC_CLASS_TSC
142233628Sfabient#define	PMC_CLASS_LAST	PMC_CLASS_SOFT
143145256Sjkoshy
144145256Sjkoshy/*
145145256Sjkoshy * A PMC can be in the following states:
146145256Sjkoshy *
147145256Sjkoshy * Hardware states:
148145256Sjkoshy *   DISABLED   -- administratively prohibited from being used.
149145256Sjkoshy *   FREE       -- HW available for use
150145256Sjkoshy * Software states:
151145256Sjkoshy *   ALLOCATED  -- allocated
152145256Sjkoshy *   STOPPED    -- allocated, but not counting events
153145256Sjkoshy *   RUNNING    -- allocated, and in operation; 'pm_runcount'
154145256Sjkoshy *                 holds the number of CPUs using this PMC at
155145256Sjkoshy *                 a given instant
156145256Sjkoshy *   DELETED    -- being destroyed
157145256Sjkoshy */
158145256Sjkoshy
159145256Sjkoshy#define	__PMC_HWSTATES()			\
160145256Sjkoshy	__PMC_STATE(DISABLED)			\
161145256Sjkoshy	__PMC_STATE(FREE)
162145256Sjkoshy
163145256Sjkoshy#define	__PMC_SWSTATES()			\
164145256Sjkoshy	__PMC_STATE(ALLOCATED)			\
165145256Sjkoshy	__PMC_STATE(STOPPED)			\
166145256Sjkoshy	__PMC_STATE(RUNNING)			\
167145256Sjkoshy	__PMC_STATE(DELETED)
168145256Sjkoshy
169145256Sjkoshy#define	__PMC_STATES()				\
170145256Sjkoshy	__PMC_HWSTATES()			\
171145256Sjkoshy	__PMC_SWSTATES()
172145256Sjkoshy
173145256Sjkoshyenum pmc_state {
174145256Sjkoshy#undef	__PMC_STATE
175145256Sjkoshy#define	__PMC_STATE(S)	PMC_STATE_##S,
176145256Sjkoshy	__PMC_STATES()
177145256Sjkoshy	__PMC_STATE(MAX)
178145256Sjkoshy};
179145256Sjkoshy
180145256Sjkoshy#define	PMC_STATE_FIRST	PMC_STATE_DISABLED
181145256Sjkoshy#define	PMC_STATE_LAST	PMC_STATE_DELETED
182145256Sjkoshy
183145256Sjkoshy/*
184145256Sjkoshy * An allocated PMC may used as a 'global' counter or as a
185145256Sjkoshy * 'thread-private' one.  Each such mode of use can be in either
186145256Sjkoshy * statistical sampling mode or in counting mode.  Thus a PMC in use
187145256Sjkoshy *
188145256Sjkoshy * SS i.e., SYSTEM STATISTICAL  -- system-wide statistical profiling
189145256Sjkoshy * SC i.e., SYSTEM COUNTER      -- system-wide counting mode
190145256Sjkoshy * TS i.e., THREAD STATISTICAL  -- thread virtual, statistical profiling
191145256Sjkoshy * TC i.e., THREAD COUNTER      -- thread virtual, counting mode
192145256Sjkoshy *
193145256Sjkoshy * Statistical profiling modes rely on the PMC periodically delivering
194145256Sjkoshy * a interrupt to the CPU (when the configured number of events have
195145256Sjkoshy * been measured), so the PMC must have the ability to generate
196145256Sjkoshy * interrupts.
197145256Sjkoshy *
198145256Sjkoshy * In counting modes, the PMC counts its configured events, with the
199145256Sjkoshy * value of the PMC being read whenever needed by its owner process.
200145256Sjkoshy *
201145256Sjkoshy * The thread specific modes "virtualize" the PMCs -- the PMCs appear
202145256Sjkoshy * to be thread private and count events only when the profiled thread
203145256Sjkoshy * actually executes on the CPU.
204145256Sjkoshy *
205145256Sjkoshy * The system-wide "global" modes keep the PMCs running all the time
206145256Sjkoshy * and are used to measure the behaviour of the whole system.
207145256Sjkoshy */
208145256Sjkoshy
209145256Sjkoshy#define	__PMC_MODES()				\
210145256Sjkoshy	__PMC_MODE(SS,	0)			\
211145256Sjkoshy	__PMC_MODE(SC,	1)			\
212145256Sjkoshy	__PMC_MODE(TS,	2)			\
213145256Sjkoshy	__PMC_MODE(TC,	3)
214145256Sjkoshy
215145256Sjkoshyenum pmc_mode {
216145256Sjkoshy#undef	__PMC_MODE
217145256Sjkoshy#define	__PMC_MODE(M,N)	PMC_MODE_##M = N,
218145256Sjkoshy	__PMC_MODES()
219145256Sjkoshy};
220145256Sjkoshy
221145256Sjkoshy#define	PMC_MODE_FIRST	PMC_MODE_SS
222145256Sjkoshy#define	PMC_MODE_LAST	PMC_MODE_TC
223145256Sjkoshy
224145256Sjkoshy#define	PMC_IS_COUNTING_MODE(mode)				\
225145256Sjkoshy	((mode) == PMC_MODE_SC || (mode) == PMC_MODE_TC)
226145256Sjkoshy#define	PMC_IS_SYSTEM_MODE(mode)				\
227145256Sjkoshy	((mode) == PMC_MODE_SS || (mode) == PMC_MODE_SC)
228145256Sjkoshy#define	PMC_IS_SAMPLING_MODE(mode)				\
229145256Sjkoshy	((mode) == PMC_MODE_SS || (mode) == PMC_MODE_TS)
230145256Sjkoshy#define	PMC_IS_VIRTUAL_MODE(mode)				\
231145256Sjkoshy	((mode) == PMC_MODE_TS || (mode) == PMC_MODE_TC)
232145256Sjkoshy
233145256Sjkoshy/*
234145256Sjkoshy * PMC row disposition
235145256Sjkoshy */
236145256Sjkoshy
237145256Sjkoshy#define	__PMC_DISPOSITIONS(N)					\
238145256Sjkoshy	__PMC_DISP(STANDALONE)	/* global/disabled counters */	\
239145256Sjkoshy	__PMC_DISP(FREE)	/* free/available */		\
240145256Sjkoshy	__PMC_DISP(THREAD)	/* thread-virtual PMCs */	\
241145256Sjkoshy	__PMC_DISP(UNKNOWN)	/* sentinel */
242145256Sjkoshy
243145256Sjkoshyenum pmc_disp {
244145256Sjkoshy#undef	__PMC_DISP
245145256Sjkoshy#define	__PMC_DISP(D)	PMC_DISP_##D ,
246145256Sjkoshy	__PMC_DISPOSITIONS()
247145256Sjkoshy};
248145256Sjkoshy
249145256Sjkoshy#define	PMC_DISP_FIRST	PMC_DISP_STANDALONE
250145256Sjkoshy#define	PMC_DISP_LAST	PMC_DISP_THREAD
251145256Sjkoshy
252145256Sjkoshy/*
253145256Sjkoshy * Counter capabilities
254145256Sjkoshy *
255145256Sjkoshy * __PMC_CAPS(NAME, VALUE, DESCRIPTION)
256145256Sjkoshy */
257145256Sjkoshy
258145256Sjkoshy#define	__PMC_CAPS()							\
259145256Sjkoshy	__PMC_CAP(INTERRUPT,	0, "generate interrupts")		\
260145256Sjkoshy	__PMC_CAP(USER,		1, "count user-mode events")		\
261145256Sjkoshy	__PMC_CAP(SYSTEM,	2, "count system-mode events")		\
262145256Sjkoshy	__PMC_CAP(EDGE,		3, "do edge detection of events")	\
263145256Sjkoshy	__PMC_CAP(THRESHOLD,	4, "ignore events below a threshold")	\
264145256Sjkoshy	__PMC_CAP(READ,		5, "read PMC counter")			\
265145256Sjkoshy	__PMC_CAP(WRITE,	6, "reprogram PMC counter")		\
266145256Sjkoshy	__PMC_CAP(INVERT,	7, "invert comparision sense")		\
267145256Sjkoshy	__PMC_CAP(QUALIFIER,	8, "further qualify monitored events")	\
268145256Sjkoshy	__PMC_CAP(PRECISE,	9, "perform precise sampling")		\
269145256Sjkoshy	__PMC_CAP(TAGGING,	10, "tag upstream events")		\
270145256Sjkoshy	__PMC_CAP(CASCADE,	11, "cascade counters")
271145256Sjkoshy
272145256Sjkoshyenum pmc_caps
273145256Sjkoshy{
274145256Sjkoshy#undef	__PMC_CAP
275145256Sjkoshy#define	__PMC_CAP(NAME, VALUE, DESCR)	PMC_CAP_##NAME = (1 << VALUE) ,
276145256Sjkoshy	__PMC_CAPS()
277145256Sjkoshy};
278145256Sjkoshy
279145256Sjkoshy#define	PMC_CAP_FIRST		PMC_CAP_INTERRUPT
280145256Sjkoshy#define	PMC_CAP_LAST		PMC_CAP_CASCADE
281145256Sjkoshy
282145256Sjkoshy/*
283147191Sjkoshy * PMC Event Numbers
284147191Sjkoshy *
285147191Sjkoshy * These are generated from the definitions in "dev/hwpmc/pmc_events.h".
286147191Sjkoshy */
287147191Sjkoshy
288147191Sjkoshyenum pmc_event {
289147191Sjkoshy#undef	__PMC_EV
290183725Sjkoshy#undef	__PMC_EV_BLOCK
291183725Sjkoshy#define	__PMC_EV_BLOCK(C,V)	PMC_EV_ ## C ## __BLOCK_START = (V) - 1 ,
292183725Sjkoshy#define	__PMC_EV(C,N)		PMC_EV_ ## C ## _ ## N ,
293147191Sjkoshy	__PMC_EVENTS()
294147191Sjkoshy};
295147191Sjkoshy
296147191Sjkoshy/*
297145256Sjkoshy * PMC SYSCALL INTERFACE
298145256Sjkoshy */
299145256Sjkoshy
300145256Sjkoshy/*
301145256Sjkoshy * "PMC_OPS" -- these are the commands recognized by the kernel
302145256Sjkoshy * module, and are used when performing a system call from userland.
303145256Sjkoshy */
304145256Sjkoshy#define	__PMC_OPS()							\
305145256Sjkoshy	__PMC_OP(CONFIGURELOG, "Set log file")				\
306147191Sjkoshy	__PMC_OP(FLUSHLOG, "Flush log file")				\
307145256Sjkoshy	__PMC_OP(GETCPUINFO, "Get system CPU information")		\
308145256Sjkoshy	__PMC_OP(GETDRIVERSTATS, "Get driver statistics")		\
309145256Sjkoshy	__PMC_OP(GETMODULEVERSION, "Get module version")		\
310145256Sjkoshy	__PMC_OP(GETPMCINFO, "Get per-cpu PMC information")		\
311145256Sjkoshy	__PMC_OP(PMCADMIN, "Set PMC state")				\
312145256Sjkoshy	__PMC_OP(PMCALLOCATE, "Allocate and configure a PMC")		\
313145256Sjkoshy	__PMC_OP(PMCATTACH, "Attach a PMC to a process")		\
314145256Sjkoshy	__PMC_OP(PMCDETACH, "Detach a PMC from a process")		\
315147191Sjkoshy	__PMC_OP(PMCGETMSR, "Get a PMC's hardware address")		\
316145256Sjkoshy	__PMC_OP(PMCRELEASE, "Release a PMC")				\
317145256Sjkoshy	__PMC_OP(PMCRW, "Read/Set a PMC")				\
318145256Sjkoshy	__PMC_OP(PMCSETCOUNT, "Set initial count/sampling rate")	\
319145256Sjkoshy	__PMC_OP(PMCSTART, "Start a PMC")				\
320205122Sjkoshy	__PMC_OP(PMCSTOP, "Stop a PMC")					\
321226514Sfabient	__PMC_OP(WRITELOG, "Write a cookie to the log file")		\
322233628Sfabient	__PMC_OP(CLOSELOG, "Close log file")				\
323233628Sfabient	__PMC_OP(GETDYNEVENTINFO, "Get dynamic events list")
324145256Sjkoshy
325183725Sjkoshy
326145256Sjkoshyenum pmc_ops {
327145256Sjkoshy#undef	__PMC_OP
328145256Sjkoshy#define	__PMC_OP(N, D)	PMC_OP_##N,
329145256Sjkoshy	__PMC_OPS()
330145256Sjkoshy};
331145256Sjkoshy
332145256Sjkoshy
333145256Sjkoshy/*
334145774Sjkoshy * Flags used in operations on PMCs.
335145256Sjkoshy */
336145256Sjkoshy
337145256Sjkoshy#define	PMC_F_FORCE		0x00000001 /*OP ADMIN force operation */
338145256Sjkoshy#define	PMC_F_DESCENDANTS	0x00000002 /*OP ALLOCATE track descendants */
339147191Sjkoshy#define	PMC_F_LOG_PROCCSW	0x00000004 /*OP ALLOCATE track ctx switches */
340147191Sjkoshy#define	PMC_F_LOG_PROCEXIT	0x00000008 /*OP ALLOCATE log proc exits */
341145256Sjkoshy#define	PMC_F_NEWVALUE		0x00000010 /*OP RW write new value */
342145256Sjkoshy#define	PMC_F_OLDVALUE		0x00000020 /*OP RW get old value */
343147191Sjkoshy#define	PMC_F_KGMON		0x00000040 /*OP ALLOCATE kgmon(8) profiling */
344174214Sjkoshy/* V2 API */
345174214Sjkoshy#define	PMC_F_CALLCHAIN		0x00000080 /*OP ALLOCATE capture callchains */
346147191Sjkoshy
347147191Sjkoshy/* internal flags */
348145774Sjkoshy#define	PMC_F_ATTACHED_TO_OWNER	0x00010000 /*attached to owner*/
349147191Sjkoshy#define	PMC_F_NEEDS_LOGFILE	0x00020000 /*needs log file */
350147191Sjkoshy#define	PMC_F_ATTACH_DONE	0x00040000 /*attached at least once */
351145256Sjkoshy
352174214Sjkoshy#define	PMC_CALLCHAIN_DEPTH_MAX	32
353233628Sfabient
354174214Sjkoshy#define	PMC_CC_F_USERSPACE	0x01	   /*userspace callchain*/
355174214Sjkoshy
356145256Sjkoshy/*
357145256Sjkoshy * Cookies used to denote allocated PMCs, and the values of PMCs.
358145256Sjkoshy */
359145256Sjkoshy
360145256Sjkoshytypedef uint32_t	pmc_id_t;
361145256Sjkoshytypedef uint64_t	pmc_value_t;
362145256Sjkoshy
363145774Sjkoshy#define	PMC_ID_INVALID		(~ (pmc_id_t) 0)
364145256Sjkoshy
365145256Sjkoshy/*
366145774Sjkoshy * PMC IDs have the following format:
367145774Sjkoshy *
368145774Sjkoshy * +--------+----------+-----------+-----------+
369145774Sjkoshy * |   CPU  | PMC MODE | PMC CLASS | ROW INDEX |
370145774Sjkoshy * +--------+----------+-----------+-----------+
371145774Sjkoshy *
372145774Sjkoshy * where each field is 8 bits wide.  Field 'CPU' is set to the
373145774Sjkoshy * requested CPU for system-wide PMCs or PMC_CPU_ANY for process-mode
374145774Sjkoshy * PMCs.  Field 'PMC MODE' is the allocated PMC mode.  Field 'PMC
375145774Sjkoshy * CLASS' is the class of the PMC.  Field 'ROW INDEX' is the row index
376145774Sjkoshy * for the PMC.
377145774Sjkoshy *
378145774Sjkoshy * The 'ROW INDEX' ranges over 0..NWPMCS where NHWPMCS is the total
379145774Sjkoshy * number of hardware PMCs on this cpu.
380145774Sjkoshy */
381145774Sjkoshy
382145774Sjkoshy
383145774Sjkoshy#define	PMC_ID_TO_ROWINDEX(ID)	((ID) & 0xFF)
384145774Sjkoshy#define	PMC_ID_TO_CLASS(ID)	(((ID) & 0xFF00) >> 8)
385145774Sjkoshy#define	PMC_ID_TO_MODE(ID)	(((ID) & 0xFF0000) >> 16)
386145774Sjkoshy#define	PMC_ID_TO_CPU(ID)	(((ID) & 0xFF000000) >> 24)
387145774Sjkoshy#define	PMC_ID_MAKE_ID(CPU,MODE,CLASS,ROWINDEX)			\
388145774Sjkoshy	((((CPU) & 0xFF) << 24) | (((MODE) & 0xFF) << 16) |	\
389145774Sjkoshy	(((CLASS) & 0xFF) << 8) | ((ROWINDEX) & 0xFF))
390145774Sjkoshy
391145774Sjkoshy/*
392145256Sjkoshy * Data structures for system calls supported by the pmc driver.
393145256Sjkoshy */
394145256Sjkoshy
395145256Sjkoshy/*
396145256Sjkoshy * OP PMCALLOCATE
397145256Sjkoshy *
398145256Sjkoshy * Allocate a PMC on the named CPU.
399145256Sjkoshy */
400145256Sjkoshy
401145256Sjkoshy#define	PMC_CPU_ANY	~0
402145256Sjkoshy
403145256Sjkoshystruct pmc_op_pmcallocate {
404145256Sjkoshy	uint32_t	pm_caps;	/* PMC_CAP_* */
405145256Sjkoshy	uint32_t	pm_cpu;		/* CPU number or PMC_CPU_ANY */
406145256Sjkoshy	enum pmc_class	pm_class;	/* class of PMC desired */
407145256Sjkoshy	enum pmc_event	pm_ev;		/* [enum pmc_event] desired */
408145256Sjkoshy	uint32_t	pm_flags;	/* additional modifiers PMC_F_* */
409145256Sjkoshy	enum pmc_mode	pm_mode;	/* desired mode */
410145256Sjkoshy	pmc_id_t	pm_pmcid;	/* [return] process pmc id */
411145256Sjkoshy
412147191Sjkoshy	union pmc_md_op_pmcallocate pm_md; /* MD layer extensions */
413145256Sjkoshy};
414145256Sjkoshy
415145256Sjkoshy/*
416145256Sjkoshy * OP PMCADMIN
417145256Sjkoshy *
418145256Sjkoshy * Set the administrative state (i.e., whether enabled or disabled) of
419145256Sjkoshy * a PMC 'pm_pmc' on CPU 'pm_cpu'.  Note that 'pm_pmc' specifies an
420145256Sjkoshy * absolute PMC number and need not have been first allocated by the
421145256Sjkoshy * calling process.
422145256Sjkoshy */
423145256Sjkoshy
424145256Sjkoshystruct pmc_op_pmcadmin {
425145256Sjkoshy	int		pm_cpu;		/* CPU# */
426145256Sjkoshy	uint32_t	pm_flags;	/* flags */
427145256Sjkoshy	int		pm_pmc;         /* PMC# */
428145256Sjkoshy	enum pmc_state  pm_state;	/* desired state */
429145256Sjkoshy};
430145256Sjkoshy
431145256Sjkoshy/*
432145256Sjkoshy * OP PMCATTACH / OP PMCDETACH
433145256Sjkoshy *
434145256Sjkoshy * Attach/detach a PMC and a process.
435145256Sjkoshy */
436145256Sjkoshy
437145256Sjkoshystruct pmc_op_pmcattach {
438145256Sjkoshy	pmc_id_t	pm_pmc;		/* PMC to attach to */
439145256Sjkoshy	pid_t		pm_pid;		/* target process */
440145256Sjkoshy};
441145256Sjkoshy
442145256Sjkoshy/*
443145256Sjkoshy * OP PMCSETCOUNT
444145256Sjkoshy *
445145256Sjkoshy * Set the sampling rate (i.e., the reload count) for statistical counters.
446145256Sjkoshy * 'pm_pmcid' need to have been previously allocated using PMCALLOCATE.
447145256Sjkoshy */
448145256Sjkoshy
449145256Sjkoshystruct pmc_op_pmcsetcount {
450145256Sjkoshy	pmc_value_t	pm_count;	/* initial/sample count */
451145256Sjkoshy	pmc_id_t	pm_pmcid;	/* PMC id to set */
452145256Sjkoshy};
453145256Sjkoshy
454145256Sjkoshy
455145256Sjkoshy/*
456145256Sjkoshy * OP PMCRW
457145256Sjkoshy *
458145256Sjkoshy * Read the value of a PMC named by 'pm_pmcid'.  'pm_pmcid' needs
459145256Sjkoshy * to have been previously allocated using PMCALLOCATE.
460145256Sjkoshy */
461145256Sjkoshy
462145256Sjkoshy
463145256Sjkoshystruct pmc_op_pmcrw {
464145256Sjkoshy	uint32_t	pm_flags;	/* PMC_F_{OLD,NEW}VALUE*/
465145256Sjkoshy	pmc_id_t	pm_pmcid;	/* pmc id */
466145256Sjkoshy	pmc_value_t	pm_value;	/* new&returned value */
467145256Sjkoshy};
468145256Sjkoshy
469145256Sjkoshy
470145256Sjkoshy/*
471145256Sjkoshy * OP GETPMCINFO
472145256Sjkoshy *
473145256Sjkoshy * retrieve PMC state for a named CPU.  The caller is expected to
474145256Sjkoshy * allocate 'npmc' * 'struct pmc_info' bytes of space for the return
475145256Sjkoshy * values.
476145256Sjkoshy */
477145256Sjkoshy
478145256Sjkoshystruct pmc_info {
479145774Sjkoshy	char		pm_name[PMC_NAME_MAX]; /* pmc name */
480145256Sjkoshy	enum pmc_class	pm_class;	/* enum pmc_class */
481145256Sjkoshy	int		pm_enabled;	/* whether enabled */
482145774Sjkoshy	enum pmc_disp	pm_rowdisp;	/* FREE, THREAD or STANDLONE */
483145774Sjkoshy	pid_t		pm_ownerpid;	/* owner, or -1 */
484145774Sjkoshy	enum pmc_mode	pm_mode;	/* current mode [enum pmc_mode] */
485145256Sjkoshy	enum pmc_event	pm_event;	/* current event */
486145774Sjkoshy	uint32_t	pm_flags;	/* current flags */
487145256Sjkoshy	pmc_value_t	pm_reloadcount;	/* sampling counters only */
488145256Sjkoshy};
489145256Sjkoshy
490145256Sjkoshystruct pmc_op_getpmcinfo {
491145256Sjkoshy	int32_t		pm_cpu;		/* 0 <= cpu < mp_maxid */
492145256Sjkoshy	struct pmc_info	pm_pmcs[];	/* space for 'npmc' structures */
493145256Sjkoshy};
494145256Sjkoshy
495145256Sjkoshy
496145256Sjkoshy/*
497145256Sjkoshy * OP GETCPUINFO
498145256Sjkoshy *
499145256Sjkoshy * Retrieve system CPU information.
500145256Sjkoshy */
501145256Sjkoshy
502233628Sfabient
503145774Sjkoshystruct pmc_classinfo {
504184802Sjkoshy	enum pmc_class	pm_class;	/* class id */
505145774Sjkoshy	uint32_t	pm_caps;	/* counter capabilities */
506145774Sjkoshy	uint32_t	pm_width;	/* width of the PMC */
507184802Sjkoshy	uint32_t	pm_num;		/* number of PMCs in class */
508145774Sjkoshy};
509145774Sjkoshy
510145256Sjkoshystruct pmc_op_getcpuinfo {
511145256Sjkoshy	enum pmc_cputype pm_cputype; /* what kind of CPU */
512183435Sjkoshy	uint32_t	pm_ncpu;    /* max CPU number */
513145256Sjkoshy	uint32_t	pm_npmc;    /* #PMCs per CPU */
514145774Sjkoshy	uint32_t	pm_nclass;  /* #classes of PMCs */
515145774Sjkoshy	struct pmc_classinfo  pm_classes[PMC_CLASS_MAX];
516145256Sjkoshy};
517145256Sjkoshy
518145256Sjkoshy/*
519145256Sjkoshy * OP CONFIGURELOG
520145256Sjkoshy *
521145256Sjkoshy * Configure a log file for writing system-wide statistics to.
522145256Sjkoshy */
523145256Sjkoshy
524145256Sjkoshystruct pmc_op_configurelog {
525145256Sjkoshy	int		pm_flags;
526145256Sjkoshy	int		pm_logfd;   /* logfile fd (or -1) */
527145256Sjkoshy};
528145256Sjkoshy
529145256Sjkoshy/*
530145256Sjkoshy * OP GETDRIVERSTATS
531145256Sjkoshy *
532145256Sjkoshy * Retrieve pmc(4) driver-wide statistics.
533145256Sjkoshy */
534145256Sjkoshy
535145256Sjkoshystruct pmc_op_getdriverstats {
536145256Sjkoshy	int	pm_intr_ignored;	/* #interrupts ignored */
537145256Sjkoshy	int	pm_intr_processed;	/* #interrupts processed */
538147191Sjkoshy	int	pm_intr_bufferfull;	/* #interrupts with ENOSPC */
539145256Sjkoshy	int	pm_syscalls;		/* #syscalls */
540145256Sjkoshy	int	pm_syscall_errors;	/* #syscalls with errors */
541147191Sjkoshy	int	pm_buffer_requests;	/* #buffer requests */
542147191Sjkoshy	int	pm_buffer_requests_failed; /* #failed buffer requests */
543147191Sjkoshy	int	pm_log_sweeps;		/* #sample buffer processing passes */
544145256Sjkoshy};
545145256Sjkoshy
546145256Sjkoshy/*
547145256Sjkoshy * OP RELEASE / OP START / OP STOP
548145256Sjkoshy *
549145256Sjkoshy * Simple operations on a PMC id.
550145256Sjkoshy */
551145256Sjkoshy
552145256Sjkoshystruct pmc_op_simple {
553145256Sjkoshy	pmc_id_t	pm_pmcid;
554145256Sjkoshy};
555145256Sjkoshy
556147191Sjkoshy/*
557147191Sjkoshy * OP WRITELOG
558147191Sjkoshy *
559147191Sjkoshy * Flush the current log buffer and write 4 bytes of user data to it.
560147191Sjkoshy */
561145256Sjkoshy
562147191Sjkoshystruct pmc_op_writelog {
563147191Sjkoshy	uint32_t	pm_userdata;
564147191Sjkoshy};
565147191Sjkoshy
566145256Sjkoshy/*
567147191Sjkoshy * OP GETMSR
568145256Sjkoshy *
569147191Sjkoshy * Retrieve the machine specific address assoicated with the allocated
570147191Sjkoshy * PMC.  This number can be used subsequently with a read-performance-counter
571147191Sjkoshy * instruction.
572145256Sjkoshy */
573145256Sjkoshy
574147191Sjkoshystruct pmc_op_getmsr {
575147191Sjkoshy	uint32_t	pm_msr;		/* machine specific address */
576145256Sjkoshy	pmc_id_t	pm_pmcid;	/* allocated pmc id */
577145256Sjkoshy};
578145256Sjkoshy
579233628Sfabient/*
580233628Sfabient * OP GETDYNEVENTINFO
581233628Sfabient *
582233628Sfabient * Retrieve a PMC dynamic class events list.
583233628Sfabient */
584233628Sfabient
585233628Sfabientstruct pmc_dyn_event_descr {
586233628Sfabient	char		pm_ev_name[PMC_NAME_MAX];
587233628Sfabient	enum pmc_event	pm_ev_code;
588233628Sfabient};
589233628Sfabient
590233628Sfabientstruct pmc_op_getdyneventinfo {
591233628Sfabient	enum pmc_class			pm_class;
592233628Sfabient	unsigned int			pm_nevent;
593233628Sfabient	struct pmc_dyn_event_descr	pm_events[PMC_EV_DYN_COUNT];
594233628Sfabient};
595233628Sfabient
596145256Sjkoshy#ifdef _KERNEL
597145256Sjkoshy
598145256Sjkoshy#include <sys/malloc.h>
599145256Sjkoshy#include <sys/sysctl.h>
600145256Sjkoshy
601174395Sjkoshy#include <machine/frame.h>
602174395Sjkoshy
603266888Sgnn#define	PMC_HASH_SIZE				1024
604266888Sgnn#define	PMC_MTXPOOL_SIZE			2048
605147191Sjkoshy#define	PMC_LOG_BUFFER_SIZE			4
606266888Sgnn#define	PMC_NLOGBUFFERS				1024
607266888Sgnn#define	PMC_NSAMPLES				1024
608266888Sgnn#define	PMC_CALLCHAIN_DEPTH			16
609145256Sjkoshy
610147191Sjkoshy#define PMC_SYSCTL_NAME_PREFIX "kern." PMC_MODULE_NAME "."
611147191Sjkoshy
612145256Sjkoshy/*
613147191Sjkoshy * Locking keys
614147191Sjkoshy *
615147191Sjkoshy * (b) - pmc_bufferlist_mtx (spin lock)
616147191Sjkoshy * (k) - pmc_kthread_mtx (sleep lock)
617147191Sjkoshy * (o) - po->po_mtx (spin lock)
618147191Sjkoshy */
619147191Sjkoshy
620147191Sjkoshy/*
621145256Sjkoshy * PMC commands
622145256Sjkoshy */
623145256Sjkoshy
624145256Sjkoshystruct pmc_syscall_args {
625233316Sgonzo	register_t	pmop_code;	/* one of PMC_OP_* */
626145256Sjkoshy	void		*pmop_data;	/* syscall parameter */
627145256Sjkoshy};
628145256Sjkoshy
629145256Sjkoshy/*
630145256Sjkoshy * Interface to processor specific s1tuff
631145256Sjkoshy */
632145256Sjkoshy
633145256Sjkoshy/*
634145256Sjkoshy * struct pmc_descr
635145256Sjkoshy *
636145256Sjkoshy * Machine independent (i.e., the common parts) of a human readable
637145256Sjkoshy * PMC description.
638145256Sjkoshy */
639145256Sjkoshy
640145256Sjkoshystruct pmc_descr {
641147191Sjkoshy	char		pd_name[PMC_NAME_MAX]; /* name */
642145256Sjkoshy	uint32_t	pd_caps;	/* capabilities */
643145256Sjkoshy	enum pmc_class	pd_class;	/* class of the PMC */
644145256Sjkoshy	uint32_t	pd_width;	/* width in bits */
645145256Sjkoshy};
646145256Sjkoshy
647145256Sjkoshy/*
648145256Sjkoshy * struct pmc_target
649145256Sjkoshy *
650145256Sjkoshy * This structure records all the target processes associated with a
651145256Sjkoshy * PMC.
652145256Sjkoshy */
653145256Sjkoshy
654145256Sjkoshystruct pmc_target {
655145256Sjkoshy	LIST_ENTRY(pmc_target)	pt_next;
656145256Sjkoshy	struct pmc_process	*pt_process; /* target descriptor */
657145256Sjkoshy};
658145256Sjkoshy
659145256Sjkoshy/*
660145256Sjkoshy * struct pmc
661145256Sjkoshy *
662145256Sjkoshy * Describes each allocated PMC.
663145256Sjkoshy *
664145256Sjkoshy * Each PMC has precisely one owner, namely the process that allocated
665145256Sjkoshy * the PMC.
666145256Sjkoshy *
667145774Sjkoshy * A PMC may be attached to multiple target processes.  The
668145256Sjkoshy * 'pm_targets' field links all the target processes being monitored
669145256Sjkoshy * by this PMC.
670145256Sjkoshy *
671145256Sjkoshy * The 'pm_savedvalue' field is protected by a mutex.
672145256Sjkoshy *
673145256Sjkoshy * On a multi-cpu machine, multiple target threads associated with a
674145256Sjkoshy * process-virtual PMC could be concurrently executing on different
675145256Sjkoshy * CPUs.  The 'pm_runcount' field is atomically incremented every time
676145256Sjkoshy * the PMC gets scheduled on a CPU and atomically decremented when it
677145256Sjkoshy * get descheduled.  Deletion of a PMC is only permitted when this
678145256Sjkoshy * field is '0'.
679145256Sjkoshy *
680145256Sjkoshy */
681145256Sjkoshy
682145256Sjkoshystruct pmc {
683147191Sjkoshy	LIST_HEAD(,pmc_target)	pm_targets;	/* list of target processes */
684184802Sjkoshy	LIST_ENTRY(pmc)		pm_next;	/* owner's list */
685145256Sjkoshy
686145256Sjkoshy	/*
687145774Sjkoshy	 * System-wide PMCs are allocated on a CPU and are not moved
688145774Sjkoshy	 * around.  For system-wide PMCs we record the CPU the PMC was
689145774Sjkoshy	 * allocated on in the 'CPU' field of the pmc ID.
690145256Sjkoshy	 *
691145256Sjkoshy	 * Virtual PMCs run on whichever CPU is currently executing
692145774Sjkoshy	 * their targets' threads.  For these PMCs we need to save
693145774Sjkoshy	 * their current PMC counter values when they are taken off
694145774Sjkoshy	 * CPU.
695145256Sjkoshy	 */
696145256Sjkoshy
697145256Sjkoshy	union {
698145256Sjkoshy		pmc_value_t	pm_savedvalue;	/* Virtual PMCS */
699145256Sjkoshy	} pm_gv;
700145256Sjkoshy
701145256Sjkoshy	/*
702145774Sjkoshy	 * For sampling mode PMCs, we keep track of the PMC's "reload
703145256Sjkoshy	 * count", which is the counter value to be loaded in when
704145256Sjkoshy	 * arming the PMC for the next counting session.  For counting
705145256Sjkoshy	 * modes on PMCs that are read-only (e.g., the x86 TSC), we
706145256Sjkoshy	 * keep track of the initial value at the start of
707145256Sjkoshy	 * counting-mode operation.
708145256Sjkoshy	 */
709145256Sjkoshy
710145256Sjkoshy	union {
711145256Sjkoshy		pmc_value_t	pm_reloadcount;	/* sampling PMC modes */
712145256Sjkoshy		pmc_value_t	pm_initial;	/* counting PMC modes */
713145256Sjkoshy	} pm_sc;
714145256Sjkoshy
715174395Sjkoshy	uint32_t	pm_stalled;	/* marks stalled sampling PMCs */
716145256Sjkoshy	uint32_t	pm_caps;	/* PMC capabilities */
717145256Sjkoshy	enum pmc_event	pm_event;	/* event being measured */
718145256Sjkoshy	uint32_t	pm_flags;	/* additional flags PMC_F_... */
719145256Sjkoshy	struct pmc_owner *pm_owner;	/* owner thread state */
720208861Sfabient	int		pm_runcount;	/* #cpus currently on */
721145774Sjkoshy	enum pmc_state	pm_state;	/* current PMC state */
722145256Sjkoshy
723145774Sjkoshy	/*
724145774Sjkoshy	 * The PMC ID field encodes the row-index for the PMC, its
725145774Sjkoshy	 * mode, class and the CPU# associated with the PMC.
726145774Sjkoshy	 */
727145774Sjkoshy
728184802Sjkoshy	pmc_id_t	pm_id;		/* allocated PMC id */
729145774Sjkoshy
730145256Sjkoshy	/* md extensions */
731147191Sjkoshy	union pmc_md_pmc	pm_md;
732145256Sjkoshy};
733145256Sjkoshy
734145256Sjkoshy/*
735145774Sjkoshy * Accessor macros for 'struct pmc'
736145774Sjkoshy */
737145774Sjkoshy
738145774Sjkoshy#define	PMC_TO_MODE(P)		PMC_ID_TO_MODE((P)->pm_id)
739145774Sjkoshy#define	PMC_TO_CLASS(P)		PMC_ID_TO_CLASS((P)->pm_id)
740145774Sjkoshy#define	PMC_TO_ROWINDEX(P)	PMC_ID_TO_ROWINDEX((P)->pm_id)
741145774Sjkoshy#define	PMC_TO_CPU(P)		PMC_ID_TO_CPU((P)->pm_id)
742145774Sjkoshy
743174395Sjkoshy
744145774Sjkoshy/*
745145256Sjkoshy * struct pmc_process
746145256Sjkoshy *
747145256Sjkoshy * Record a 'target' process being profiled.
748145256Sjkoshy *
749145256Sjkoshy * The target process being profiled could be different from the owner
750145256Sjkoshy * process which allocated the PMCs.  Each target process descriptor
751145256Sjkoshy * is associated with NHWPMC 'struct pmc *' pointers.  Each PMC at a
752145256Sjkoshy * given hardware row-index 'n' will use slot 'n' of the 'pp_pmcs[]'
753145256Sjkoshy * array.  The size of this structure is thus PMC architecture
754145256Sjkoshy * dependent.
755145256Sjkoshy *
756145256Sjkoshy */
757145256Sjkoshy
758145256Sjkoshystruct pmc_targetstate {
759145256Sjkoshy	struct pmc	*pp_pmc;   /* target PMC */
760145256Sjkoshy	pmc_value_t	pp_pmcval; /* per-process value */
761145256Sjkoshy};
762145256Sjkoshy
763145256Sjkoshystruct pmc_process {
764145256Sjkoshy	LIST_ENTRY(pmc_process) pp_next;	/* hash chain */
765145256Sjkoshy	int		pp_refcnt;		/* reference count */
766184802Sjkoshy	uint32_t	pp_flags;		/* flags PMC_PP_* */
767145256Sjkoshy	struct proc	*pp_proc;		/* target thread */
768145256Sjkoshy	struct pmc_targetstate pp_pmcs[];       /* NHWPMCs */
769145256Sjkoshy};
770145256Sjkoshy
771145774Sjkoshy#define	PMC_PP_ENABLE_MSR_ACCESS	0x00000001
772145256Sjkoshy
773145256Sjkoshy/*
774145256Sjkoshy * struct pmc_owner
775145256Sjkoshy *
776145256Sjkoshy * We associate a PMC with an 'owner' process.
777145256Sjkoshy *
778145256Sjkoshy * A process can be associated with 0..NCPUS*NHWPMC PMCs during its
779145256Sjkoshy * lifetime, where NCPUS is the numbers of CPUS in the system and
780145256Sjkoshy * NHWPMC is the number of hardware PMCs per CPU.  These are
781145256Sjkoshy * maintained in the list headed by the 'po_pmcs' to save on space.
782145256Sjkoshy *
783145256Sjkoshy */
784145256Sjkoshy
785145256Sjkoshystruct pmc_owner  {
786147191Sjkoshy	LIST_ENTRY(pmc_owner)	po_next;	/* hash chain */
787147191Sjkoshy	LIST_ENTRY(pmc_owner)	po_ssnext;	/* list of SS PMC owners */
788147191Sjkoshy	LIST_HEAD(, pmc)	po_pmcs;	/* owned PMC list */
789147191Sjkoshy	TAILQ_HEAD(, pmclog_buffer) po_logbuffers; /* (o) logbuffer list */
790147191Sjkoshy	struct mtx		po_mtx;		/* spin lock for (o) */
791147191Sjkoshy	struct proc		*po_owner;	/* owner proc */
792147191Sjkoshy	uint32_t		po_flags;	/* (k) flags PMC_PO_* */
793147191Sjkoshy	struct proc		*po_kthread;	/* (k) helper kthread */
794147191Sjkoshy	struct pmclog_buffer	*po_curbuf;	/* current log buffer */
795147191Sjkoshy	struct file		*po_file;	/* file reference */
796147191Sjkoshy	int			po_error;	/* recorded error */
797201021Sjkoshy	short			po_sscount;	/* # SS PMCs owned */
798201021Sjkoshy	short			po_logprocmaps;	/* global mappings done */
799145256Sjkoshy};
800145256Sjkoshy
801147191Sjkoshy#define	PMC_PO_OWNS_LOGFILE		0x00000001 /* has a log file */
802204878Sfabient#define	PMC_PO_SHUTDOWN			0x00000010 /* in the process of shutdown */
803174395Sjkoshy#define	PMC_PO_INITIAL_MAPPINGS_DONE	0x00000020
804145256Sjkoshy
805145256Sjkoshy/*
806145256Sjkoshy * struct pmc_hw -- describe the state of the PMC hardware
807145256Sjkoshy *
808145256Sjkoshy * When in use, a HW PMC is associated with one allocated 'struct pmc'
809145256Sjkoshy * pointed to by field 'phw_pmc'.  When inactive, this field is NULL.
810145256Sjkoshy *
811145256Sjkoshy * On an SMP box, one or more HW PMC's in process virtual mode with
812145256Sjkoshy * the same 'phw_pmc' could be executing on different CPUs.  In order
813145256Sjkoshy * to handle this case correctly, we need to ensure that only
814145256Sjkoshy * incremental counts get added to the saved value in the associated
815145256Sjkoshy * 'struct pmc'.  The 'phw_save' field is used to keep the saved PMC
816145256Sjkoshy * value at the time the hardware is started during this context
817145256Sjkoshy * switch (i.e., the difference between the new (hardware) count and
818145256Sjkoshy * the saved count is atomically added to the count field in 'struct
819145256Sjkoshy * pmc' at context switch time).
820145256Sjkoshy *
821145256Sjkoshy */
822145256Sjkoshy
823145256Sjkoshystruct pmc_hw {
824145256Sjkoshy	uint32_t	phw_state;	/* see PHW_* macros below */
825145256Sjkoshy	struct pmc	*phw_pmc;	/* current thread PMC */
826145256Sjkoshy};
827145256Sjkoshy
828145256Sjkoshy#define	PMC_PHW_RI_MASK		0x000000FF
829145256Sjkoshy#define	PMC_PHW_CPU_SHIFT	8
830145256Sjkoshy#define	PMC_PHW_CPU_MASK	0x0000FF00
831145256Sjkoshy#define	PMC_PHW_FLAGS_SHIFT	16
832145256Sjkoshy#define	PMC_PHW_FLAGS_MASK	0xFFFF0000
833145256Sjkoshy
834145256Sjkoshy#define	PMC_PHW_INDEX_TO_STATE(ri)	((ri) & PMC_PHW_RI_MASK)
835145256Sjkoshy#define	PMC_PHW_STATE_TO_INDEX(state)	((state) & PMC_PHW_RI_MASK)
836145256Sjkoshy#define	PMC_PHW_CPU_TO_STATE(cpu)	(((cpu) << PMC_PHW_CPU_SHIFT) & \
837145256Sjkoshy	PMC_PHW_CPU_MASK)
838145256Sjkoshy#define	PMC_PHW_STATE_TO_CPU(state)	(((state) & PMC_PHW_CPU_MASK) >> \
839145256Sjkoshy	PMC_PHW_CPU_SHIFT)
840145256Sjkoshy#define	PMC_PHW_FLAGS_TO_STATE(flags)	(((flags) << PMC_PHW_FLAGS_SHIFT) & \
841145256Sjkoshy	PMC_PHW_FLAGS_MASK)
842145256Sjkoshy#define	PMC_PHW_STATE_TO_FLAGS(state)	(((state) & PMC_PHW_FLAGS_MASK) >> \
843145256Sjkoshy	PMC_PHW_FLAGS_SHIFT)
844145256Sjkoshy#define	PMC_PHW_FLAG_IS_ENABLED		(PMC_PHW_FLAGS_TO_STATE(0x01))
845145256Sjkoshy#define	PMC_PHW_FLAG_IS_SHAREABLE	(PMC_PHW_FLAGS_TO_STATE(0x02))
846145256Sjkoshy
847145256Sjkoshy/*
848147191Sjkoshy * struct pmc_sample
849147191Sjkoshy *
850147191Sjkoshy * Space for N (tunable) PC samples and associated control data.
851147191Sjkoshy */
852147191Sjkoshy
853147191Sjkoshystruct pmc_sample {
854174395Sjkoshy	uint16_t		ps_nsamples;	/* callchain depth */
855174395Sjkoshy	uint8_t			ps_cpu;		/* cpu number */
856174395Sjkoshy	uint8_t			ps_flags;	/* other flags */
857174395Sjkoshy	pid_t			ps_pid;		/* process PID or -1 */
858185989Sjkoshy	struct thread		*ps_td;		/* which thread */
859147191Sjkoshy	struct pmc		*ps_pmc;	/* interrupting PMC */
860174395Sjkoshy	uintptr_t		*ps_pc;		/* (const) callchain start */
861147191Sjkoshy};
862147191Sjkoshy
863233628Sfabient#define 	PMC_SAMPLE_FREE		((uint16_t) 0)
864233628Sfabient#define 	PMC_SAMPLE_INUSE	((uint16_t) 0xFFFF)
865174395Sjkoshy
866147191Sjkoshystruct pmc_samplebuffer {
867147191Sjkoshy	struct pmc_sample * volatile ps_read;	/* read pointer */
868147191Sjkoshy	struct pmc_sample * volatile ps_write;	/* write pointer */
869174395Sjkoshy	uintptr_t		*ps_callchains;	/* all saved call chains */
870147191Sjkoshy	struct pmc_sample	*ps_fence;	/* one beyond ps_samples[] */
871147191Sjkoshy	struct pmc_sample	ps_samples[];	/* array of sample entries */
872147191Sjkoshy};
873147191Sjkoshy
874147191Sjkoshy
875147191Sjkoshy/*
876145256Sjkoshy * struct pmc_cpustate
877145256Sjkoshy *
878145256Sjkoshy * A CPU is modelled as a collection of HW PMCs with space for additional
879145256Sjkoshy * flags.
880145256Sjkoshy */
881145256Sjkoshy
882145256Sjkoshystruct pmc_cpu {
883145256Sjkoshy	uint32_t	pc_state;	/* physical cpu number + flags */
884233628Sfabient	struct pmc_samplebuffer *pc_sb[2]; /* space for samples */
885145256Sjkoshy	struct pmc_hw	*pc_hwpmcs[];	/* 'npmc' pointers */
886145256Sjkoshy};
887145256Sjkoshy
888145256Sjkoshy#define	PMC_PCPU_CPU_MASK		0x000000FF
889145256Sjkoshy#define	PMC_PCPU_FLAGS_MASK		0xFFFFFF00
890145256Sjkoshy#define	PMC_PCPU_FLAGS_SHIFT		8
891145256Sjkoshy#define	PMC_PCPU_STATE_TO_CPU(S)	((S) & PMC_PCPU_CPU_MASK)
892145256Sjkoshy#define	PMC_PCPU_STATE_TO_FLAGS(S)	(((S) & PMC_PCPU_FLAGS_MASK) >> PMC_PCPU_FLAGS_SHIFT)
893145256Sjkoshy#define	PMC_PCPU_FLAGS_TO_STATE(F)	(((F) << PMC_PCPU_FLAGS_SHIFT) & PMC_PCPU_FLAGS_MASK)
894145256Sjkoshy#define	PMC_PCPU_CPU_TO_STATE(C)	((C) & PMC_PCPU_CPU_MASK)
895145256Sjkoshy#define	PMC_PCPU_FLAG_HTT		(PMC_PCPU_FLAGS_TO_STATE(0x1))
896145256Sjkoshy
897145256Sjkoshy/*
898145256Sjkoshy * struct pmc_binding
899145256Sjkoshy *
900145256Sjkoshy * CPU binding information.
901145256Sjkoshy */
902145256Sjkoshy
903145256Sjkoshystruct pmc_binding {
904145256Sjkoshy	int	pb_bound;	/* is bound? */
905145256Sjkoshy	int	pb_cpu;		/* if so, to which CPU */
906145256Sjkoshy};
907145256Sjkoshy
908184802Sjkoshy
909184802Sjkoshystruct pmc_mdep;
910184802Sjkoshy
911145256Sjkoshy/*
912184802Sjkoshy * struct pmc_classdep
913184802Sjkoshy *
914184802Sjkoshy * PMC class-dependent operations.
915184802Sjkoshy */
916184802Sjkoshystruct pmc_classdep {
917184802Sjkoshy	uint32_t	pcd_caps;	/* class capabilities */
918184802Sjkoshy	enum pmc_class	pcd_class;	/* class id */
919184802Sjkoshy	int		pcd_num;	/* number of PMCs */
920184802Sjkoshy	int		pcd_ri;		/* row index of the first PMC in class */
921184802Sjkoshy	int		pcd_width;	/* width of the PMC */
922184802Sjkoshy
923184802Sjkoshy	/* configuring/reading/writing the hardware PMCs */
924184802Sjkoshy	int (*pcd_config_pmc)(int _cpu, int _ri, struct pmc *_pm);
925184802Sjkoshy	int (*pcd_get_config)(int _cpu, int _ri, struct pmc **_ppm);
926184802Sjkoshy	int (*pcd_read_pmc)(int _cpu, int _ri, pmc_value_t *_value);
927184802Sjkoshy	int (*pcd_write_pmc)(int _cpu, int _ri, pmc_value_t _value);
928184802Sjkoshy
929184802Sjkoshy	/* pmc allocation/release */
930184802Sjkoshy	int (*pcd_allocate_pmc)(int _cpu, int _ri, struct pmc *_t,
931184802Sjkoshy		const struct pmc_op_pmcallocate *_a);
932184802Sjkoshy	int (*pcd_release_pmc)(int _cpu, int _ri, struct pmc *_pm);
933184802Sjkoshy
934184802Sjkoshy	/* starting and stopping PMCs */
935184802Sjkoshy	int (*pcd_start_pmc)(int _cpu, int _ri);
936184802Sjkoshy	int (*pcd_stop_pmc)(int _cpu, int _ri);
937184802Sjkoshy
938184802Sjkoshy	/* description */
939184802Sjkoshy	int (*pcd_describe)(int _cpu, int _ri, struct pmc_info *_pi,
940184802Sjkoshy		struct pmc **_ppmc);
941184802Sjkoshy
942184802Sjkoshy	/* class-dependent initialization & finalization */
943184802Sjkoshy	int (*pcd_pcpu_init)(struct pmc_mdep *_md, int _cpu);
944184802Sjkoshy	int (*pcd_pcpu_fini)(struct pmc_mdep *_md, int _cpu);
945184802Sjkoshy
946184802Sjkoshy	/* machine-specific interface */
947184802Sjkoshy	int (*pcd_get_msr)(int _ri, uint32_t *_msr);
948184802Sjkoshy};
949184802Sjkoshy
950184802Sjkoshy/*
951145256Sjkoshy * struct pmc_mdep
952145256Sjkoshy *
953145256Sjkoshy * Machine dependent bits needed per CPU type.
954145256Sjkoshy */
955145256Sjkoshy
956145256Sjkoshystruct pmc_mdep  {
957145256Sjkoshy	uint32_t	pmd_cputype;    /* from enum pmc_cputype */
958184802Sjkoshy	uint32_t	pmd_npmc;	/* number of PMCs per CPU */
959184802Sjkoshy	uint32_t	pmd_nclass;	/* number of PMC classes present */
960145256Sjkoshy
961145256Sjkoshy	/*
962184802Sjkoshy	 * Machine dependent methods.
963145256Sjkoshy	 */
964145256Sjkoshy
965184802Sjkoshy	/* per-cpu initialization and finalization */
966185363Sjkoshy	int (*pmd_pcpu_init)(struct pmc_mdep *_md, int _cpu);
967185363Sjkoshy	int (*pmd_pcpu_fini)(struct pmc_mdep *_md, int _cpu);
968145256Sjkoshy
969145615Sjkoshy	/* thread context switch in/out */
970145615Sjkoshy	int (*pmd_switch_in)(struct pmc_cpu *_p, struct pmc_process *_pp);
971145615Sjkoshy	int (*pmd_switch_out)(struct pmc_cpu *_p, struct pmc_process *_pp);
972145256Sjkoshy
973145256Sjkoshy	/* handle a PMC interrupt */
974174395Sjkoshy	int (*pmd_intr)(int _cpu, struct trapframe *_tf);
975145256Sjkoshy
976184802Sjkoshy	/*
977184802Sjkoshy	 * PMC class dependent information.
978184802Sjkoshy	 */
979184802Sjkoshy	struct pmc_classdep pmd_classdep[];
980145256Sjkoshy};
981145256Sjkoshy
982145256Sjkoshy/*
983145256Sjkoshy * Per-CPU state.  This is an array of 'mp_ncpu' pointers
984145256Sjkoshy * to struct pmc_cpu descriptors.
985145256Sjkoshy */
986145256Sjkoshy
987145256Sjkoshyextern struct pmc_cpu **pmc_pcpu;
988145256Sjkoshy
989145256Sjkoshy/* driver statistics */
990145256Sjkoshyextern struct pmc_op_getdriverstats pmc_stats;
991145256Sjkoshy
992233628Sfabient#if	defined(DEBUG)
993145256Sjkoshy
994147191Sjkoshy/* debug flags, major flag groups */
995147191Sjkoshystruct pmc_debugflags {
996147191Sjkoshy	int	pdb_CPU;
997147191Sjkoshy	int	pdb_CSW;
998147191Sjkoshy	int	pdb_LOG;
999147191Sjkoshy	int	pdb_MDP;
1000147191Sjkoshy	int	pdb_MOD;
1001147191Sjkoshy	int	pdb_OWN;
1002147191Sjkoshy	int	pdb_PMC;
1003147191Sjkoshy	int	pdb_PRC;
1004147191Sjkoshy	int	pdb_SAM;
1005147191Sjkoshy};
1006145256Sjkoshy
1007147191Sjkoshyextern struct pmc_debugflags pmc_debugflags;
1008147191Sjkoshy
1009145256Sjkoshy#define	PMC_DEBUG_STRSIZE		128
1010147191Sjkoshy#define	PMC_DEBUG_DEFAULT_FLAGS		{ 0, 0, 0, 0, 0, 0, 0, 0 }
1011145256Sjkoshy
1012145256Sjkoshy#define	PMCDBG(M,N,L,F,...) do {					\
1013147867Sjkoshy	if (pmc_debugflags.pdb_ ## M & (1 << PMC_DEBUG_MIN_ ## N))	\
1014147191Sjkoshy		printf(#M ":" #N ":" #L  ": " F "\n", __VA_ARGS__);	\
1015145256Sjkoshy} while (0)
1016145256Sjkoshy
1017145256Sjkoshy/* Major numbers */
1018147191Sjkoshy#define	PMC_DEBUG_MAJ_CPU		0 /* cpu switches */
1019147191Sjkoshy#define	PMC_DEBUG_MAJ_CSW		1 /* context switches */
1020147191Sjkoshy#define	PMC_DEBUG_MAJ_LOG		2 /* logging */
1021147191Sjkoshy#define	PMC_DEBUG_MAJ_MDP		3 /* machine dependent */
1022147191Sjkoshy#define	PMC_DEBUG_MAJ_MOD		4 /* misc module infrastructure */
1023147191Sjkoshy#define	PMC_DEBUG_MAJ_OWN		5 /* owner */
1024147191Sjkoshy#define	PMC_DEBUG_MAJ_PMC		6 /* pmc management */
1025147191Sjkoshy#define	PMC_DEBUG_MAJ_PRC		7 /* processes */
1026147191Sjkoshy#define	PMC_DEBUG_MAJ_SAM		8 /* sampling */
1027145256Sjkoshy
1028145256Sjkoshy/* Minor numbers */
1029145256Sjkoshy
1030145256Sjkoshy/* Common (8 bits) */
1031145256Sjkoshy#define	PMC_DEBUG_MIN_ALL		0 /* allocation */
1032145256Sjkoshy#define	PMC_DEBUG_MIN_REL		1 /* release */
1033145256Sjkoshy#define	PMC_DEBUG_MIN_OPS		2 /* ops: start, stop, ... */
1034145256Sjkoshy#define	PMC_DEBUG_MIN_INI		3 /* init */
1035145256Sjkoshy#define	PMC_DEBUG_MIN_FND		4 /* find */
1036145256Sjkoshy
1037145256Sjkoshy/* MODULE */
1038184802Sjkoshy#define	PMC_DEBUG_MIN_PMH	       14 /* pmc_hook */
1039145256Sjkoshy#define	PMC_DEBUG_MIN_PMS	       15 /* pmc_syscall */
1040145256Sjkoshy
1041145256Sjkoshy/* OWN */
1042145256Sjkoshy#define	PMC_DEBUG_MIN_ORM		8 /* owner remove */
1043145256Sjkoshy#define	PMC_DEBUG_MIN_OMR		9 /* owner maybe remove */
1044145256Sjkoshy
1045145256Sjkoshy/* PROCESSES */
1046145256Sjkoshy#define	PMC_DEBUG_MIN_TLK		8 /* link target */
1047145256Sjkoshy#define	PMC_DEBUG_MIN_TUL		9 /* unlink target */
1048145256Sjkoshy#define	PMC_DEBUG_MIN_EXT	       10 /* process exit */
1049145256Sjkoshy#define	PMC_DEBUG_MIN_EXC	       11 /* process exec */
1050145256Sjkoshy#define	PMC_DEBUG_MIN_FRK	       12 /* process fork */
1051145256Sjkoshy#define	PMC_DEBUG_MIN_ATT	       13 /* attach/detach */
1052147191Sjkoshy#define	PMC_DEBUG_MIN_SIG	       14 /* signalling */
1053145256Sjkoshy
1054145256Sjkoshy/* CONTEXT SWITCHES */
1055145256Sjkoshy#define	PMC_DEBUG_MIN_SWI		8 /* switch in */
1056145256Sjkoshy#define	PMC_DEBUG_MIN_SWO		9 /* switch out */
1057145256Sjkoshy
1058145256Sjkoshy/* PMC */
1059145256Sjkoshy#define	PMC_DEBUG_MIN_REG		8 /* pmc register */
1060145256Sjkoshy#define	PMC_DEBUG_MIN_ALR		9 /* allocate row */
1061145256Sjkoshy
1062145256Sjkoshy/* MACHINE DEPENDENT LAYER */
1063145256Sjkoshy#define	PMC_DEBUG_MIN_REA		8 /* read */
1064145256Sjkoshy#define	PMC_DEBUG_MIN_WRI		9 /* write */
1065145256Sjkoshy#define	PMC_DEBUG_MIN_CFG	       10 /* config */
1066145256Sjkoshy#define	PMC_DEBUG_MIN_STA	       11 /* start */
1067145256Sjkoshy#define	PMC_DEBUG_MIN_STO	       12 /* stop */
1068145774Sjkoshy#define	PMC_DEBUG_MIN_INT	       13 /* interrupts */
1069145256Sjkoshy
1070145256Sjkoshy/* CPU */
1071184802Sjkoshy#define	PMC_DEBUG_MIN_BND		8 /* bind */
1072145256Sjkoshy#define	PMC_DEBUG_MIN_SEL		9 /* select */
1073145256Sjkoshy
1074147191Sjkoshy/* LOG */
1075147191Sjkoshy#define	PMC_DEBUG_MIN_GTB		8 /* get buf */
1076147191Sjkoshy#define	PMC_DEBUG_MIN_SIO		9 /* schedule i/o */
1077147191Sjkoshy#define	PMC_DEBUG_MIN_FLS	       10 /* flush */
1078147191Sjkoshy#define	PMC_DEBUG_MIN_SAM	       11 /* sample */
1079226526Sfabient#define	PMC_DEBUG_MIN_CLO	       12 /* close */
1080147191Sjkoshy
1081145256Sjkoshy#else
1082145256Sjkoshy#define	PMCDBG(M,N,L,F,...)		/* nothing */
1083145256Sjkoshy#endif
1084145256Sjkoshy
1085145256Sjkoshy/* declare a dedicated memory pool */
1086145256SjkoshyMALLOC_DECLARE(M_PMC);
1087145256Sjkoshy
1088145256Sjkoshy/*
1089145256Sjkoshy * Functions
1090145256Sjkoshy */
1091145256Sjkoshy
1092147191Sjkoshystruct pmc_mdep *pmc_md_initialize(void);	/* MD init function */
1093184802Sjkoshyvoid	pmc_md_finalize(struct pmc_mdep *_md);	/* MD fini function */
1094147191Sjkoshyint	pmc_getrowdisp(int _ri);
1095233628Sfabientint	pmc_process_interrupt(int _cpu, int _soft, struct pmc *_pm,
1096174395Sjkoshy    struct trapframe *_tf, int _inuserspace);
1097174395Sjkoshyint	pmc_save_kernel_callchain(uintptr_t *_cc, int _maxsamples,
1098174395Sjkoshy    struct trapframe *_tf);
1099174395Sjkoshyint	pmc_save_user_callchain(uintptr_t *_cc, int _maxsamples,
1100174395Sjkoshy    struct trapframe *_tf);
1101233628Sfabientstruct pmc_mdep *pmc_mdep_alloc(int nclasses);
1102233628Sfabientvoid pmc_mdep_free(struct pmc_mdep *md);
1103145256Sjkoshy#endif /* _KERNEL */
1104145256Sjkoshy#endif /* _SYS_PMC_H_ */
1105