xref: /illumos-gate/usr/src/uts/common/os/ftrace.c (revision 2d6eb4a5)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*4df4bd60Sbs  * Common Development and Distribution License (the "License").
6*4df4bd60Sbs  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*4df4bd60Sbs  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <sys/types.h>
277c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
287c478bd9Sstevel@tonic-gate #include <sys/mutex.h>
297c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
307c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
317c478bd9Sstevel@tonic-gate #include <sys/systm.h>
327c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
337c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
347c478bd9Sstevel@tonic-gate #include <sys/debug.h>
357c478bd9Sstevel@tonic-gate #include <sys/param.h>
367c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
377c478bd9Sstevel@tonic-gate #include <sys/ftrace.h>
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate /*
407c478bd9Sstevel@tonic-gate  * Tunable parameters:
417c478bd9Sstevel@tonic-gate  *
427c478bd9Sstevel@tonic-gate  * ftrace_atboot	- whether to start fast tracing at boot.
437c478bd9Sstevel@tonic-gate  * ftrace_nent		- size of the per-CPU event ring buffer.
447c478bd9Sstevel@tonic-gate  */
457c478bd9Sstevel@tonic-gate int ftrace_atboot = 0;
467c478bd9Sstevel@tonic-gate int ftrace_nent = FTRACE_NENT;
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate /*
49*4df4bd60Sbs  * Global Tracing State:
50*4df4bd60Sbs  *
51*4df4bd60Sbs  *                NOTREADY(=0)
52*4df4bd60Sbs  *                  |
53*4df4bd60Sbs  *            ftrace_init()
54*4df4bd60Sbs  *                  |
55*4df4bd60Sbs  *                  |
56*4df4bd60Sbs  *                  v
57*4df4bd60Sbs  *      +-------->READY-------+
58*4df4bd60Sbs  *      |                     |
59*4df4bd60Sbs  *  ftrace_stop()         ftrace_start()
60*4df4bd60Sbs  *      |                     |
61*4df4bd60Sbs  *      +---(ENABLED|READY)<--+
62*4df4bd60Sbs  *
63*4df4bd60Sbs  * During boot, ftrace_init() is called and the state becomes
64*4df4bd60Sbs  * READY. If ftrace_atboot is set, ftrace_start() is called at
65*4df4bd60Sbs  * this time.
66*4df4bd60Sbs  *
677c478bd9Sstevel@tonic-gate  * If FTRACE_READY is set, then tracing can be enabled.
687c478bd9Sstevel@tonic-gate  * If FTRACE_ENABLED is set, tracing is enabled on the set of CPUs
697c478bd9Sstevel@tonic-gate  *   which are currently FTRACE_READY.
707c478bd9Sstevel@tonic-gate  */
717c478bd9Sstevel@tonic-gate static int ftrace_state = 0;
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate /*
74*4df4bd60Sbs  * Per-CPU Tracing State:
75*4df4bd60Sbs  *
76*4df4bd60Sbs  *     +-----------------READY<--------------+
77*4df4bd60Sbs  *     |                 ^   |               |
78*4df4bd60Sbs  *     |                 | ftrace_cpu_fini() |
79*4df4bd60Sbs  *     |                 |   |               |
80*4df4bd60Sbs  *     |   ftrace_cpu_init() |               |
81*4df4bd60Sbs  *     |                 |   v     ftrace_cpu_stop()
82*4df4bd60Sbs  *     |              NOTREADY(=0)           |
83*4df4bd60Sbs  *     |                   ^                 |
84*4df4bd60Sbs  * ftrace_cpu_start()      |                 |
85*4df4bd60Sbs  *     |              ftrace_cpu_fini()      |
86*4df4bd60Sbs  *     |                   |                 |
87*4df4bd60Sbs  *     +----------->(ENABLED|READY)----------+
88*4df4bd60Sbs  *
89*4df4bd60Sbs  */
90*4df4bd60Sbs 
91*4df4bd60Sbs /*
92*4df4bd60Sbs  * Locking :
93*4df4bd60Sbs  *
94*4df4bd60Sbs  * Trace context code does not use any lock. There is a per-cpu circular trace
95*4df4bd60Sbs  * buffer that has a head, a tail and a current pointer. Each record of this
96*4df4bd60Sbs  * buffer is of equal length. Before doing anything, trace context code checks
97*4df4bd60Sbs  * the per-cpu ENABLED bit. Trace buffer is allocated in non-trace context and
98*4df4bd60Sbs  * it sets this bit only after allocating and setting up the buffer. So trace
99*4df4bd60Sbs  * context code can't access the buffer till it is set up completely. The
100*4df4bd60Sbs  * buffer is freed also in non-trace context. The code that frees the buffer is
101*4df4bd60Sbs  * executed only after the corresponding cpu is powered off. So when this
102*4df4bd60Sbs  * happens, no trace context code can be running on it. We only need to make
103*4df4bd60Sbs  * sure that trace context code is not preempted from the cpu in the middle of
104*4df4bd60Sbs  * accessing the trace buffer. This can be achieved simply by disabling
105*4df4bd60Sbs  * interrupts temporarily. This approach makes the least assumption about the
106*4df4bd60Sbs  * state of the callers of tracing functions.
107*4df4bd60Sbs  *
108*4df4bd60Sbs  * A single global lock, ftrace_lock protects assignments to all global and
109*4df4bd60Sbs  * per-cpu trace variables. It does not protect reading of those in some cases.
110*4df4bd60Sbs  *
111*4df4bd60Sbs  * More specifically, it protects assignments to:
112*4df4bd60Sbs  *
1137c478bd9Sstevel@tonic-gate  *   ftrace_state
1147c478bd9Sstevel@tonic-gate  *   cpu[N]->cpu_ftrace.ftd_state
1157c478bd9Sstevel@tonic-gate  *   cpu[N]->cpu_ftrace.ftd_first
1167c478bd9Sstevel@tonic-gate  *   cpu[N]->cpu_ftrace.ftd_last
117*4df4bd60Sbs  *
118*4df4bd60Sbs  * Does _not_ protect reading of cpu[N]->cpu_ftrace.ftd_state
119*4df4bd60Sbs  * Does _not_ protect cpu[N]->cpu_ftrace.ftd_cur
120*4df4bd60Sbs  * Does _not_ protect reading of ftrace_state
1217c478bd9Sstevel@tonic-gate  */
1227c478bd9Sstevel@tonic-gate static kmutex_t ftrace_lock;
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate /*
1257c478bd9Sstevel@tonic-gate  * Check whether a CPU is installed.
1267c478bd9Sstevel@tonic-gate  */
1277c478bd9Sstevel@tonic-gate #define	IS_CPU(i) (cpu[i] != NULL)
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate static void
ftrace_cpu_init(int cpuid)1307c478bd9Sstevel@tonic-gate ftrace_cpu_init(int cpuid)
1317c478bd9Sstevel@tonic-gate {
1327c478bd9Sstevel@tonic-gate 	ftrace_data_t *ftd;
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 	/*
1357c478bd9Sstevel@tonic-gate 	 * This can be called with "cpu[cpuid]->cpu_flags & CPU_EXISTS"
1367c478bd9Sstevel@tonic-gate 	 * being false - e.g. when a CPU is DR'ed in.
1377c478bd9Sstevel@tonic-gate 	 */
1387c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ftrace_lock));
1397c478bd9Sstevel@tonic-gate 	ASSERT(IS_CPU(cpuid));
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 	ftd = &cpu[cpuid]->cpu_ftrace;
1427c478bd9Sstevel@tonic-gate 	if (ftd->ftd_state & FTRACE_READY)
1437c478bd9Sstevel@tonic-gate 		return;
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 	/*
1467c478bd9Sstevel@tonic-gate 	 * We don't allocate the buffers until the first time
1477c478bd9Sstevel@tonic-gate 	 *   ftrace_cpu_start() is called, so that they're not
1487c478bd9Sstevel@tonic-gate 	 *   allocated if ftrace is never enabled.
1497c478bd9Sstevel@tonic-gate 	 */
1507c478bd9Sstevel@tonic-gate 	ftd->ftd_state |= FTRACE_READY;
1517c478bd9Sstevel@tonic-gate 	ASSERT(!(ftd->ftd_state & FTRACE_ENABLED));
1527c478bd9Sstevel@tonic-gate }
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate /*
1557c478bd9Sstevel@tonic-gate  * Only called from cpu_unconfigure() (and cpu_configure() on error).
1567c478bd9Sstevel@tonic-gate  * At this point, cpu[cpuid] is about to be freed and NULLed out,
1577c478bd9Sstevel@tonic-gate  *   so we'd better clean up after ourselves.
1587c478bd9Sstevel@tonic-gate  */
1597c478bd9Sstevel@tonic-gate static void
ftrace_cpu_fini(int cpuid)1607c478bd9Sstevel@tonic-gate ftrace_cpu_fini(int cpuid)
1617c478bd9Sstevel@tonic-gate {
1627c478bd9Sstevel@tonic-gate 	ftrace_data_t *ftd;
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ftrace_lock));
1657c478bd9Sstevel@tonic-gate 	ASSERT(IS_CPU(cpuid));
1667c478bd9Sstevel@tonic-gate 	ASSERT((cpu[cpuid]->cpu_flags & CPU_POWEROFF) != 0);
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	ftd = &cpu[cpuid]->cpu_ftrace;
1697c478bd9Sstevel@tonic-gate 	if (!(ftd->ftd_state & FTRACE_READY))
1707c478bd9Sstevel@tonic-gate 		return;
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 	/*
173*4df4bd60Sbs 	 * This cpu is powered off and no code can be executing on it. So
174*4df4bd60Sbs 	 * we can simply finish our cleanup. There is no need for a xcall
175*4df4bd60Sbs 	 * to make sure that this cpu is out of trace context.
176*4df4bd60Sbs 	 *
177*4df4bd60Sbs 	 * The cpu structure will be cleared soon. But, for the sake of
178*4df4bd60Sbs 	 * debugging, clear our pointers and state.
1797c478bd9Sstevel@tonic-gate 	 */
180*4df4bd60Sbs 	if (ftd->ftd_first != NULL) {
181*4df4bd60Sbs 		kmem_free(ftd->ftd_first,
182*4df4bd60Sbs 		    ftrace_nent * sizeof (ftrace_record_t));
183*4df4bd60Sbs 	}
184*4df4bd60Sbs 	bzero(ftd, sizeof (ftrace_data_t));
1857c478bd9Sstevel@tonic-gate }
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate static void
ftrace_cpu_start(int cpuid)1887c478bd9Sstevel@tonic-gate ftrace_cpu_start(int cpuid)
1897c478bd9Sstevel@tonic-gate {
1907c478bd9Sstevel@tonic-gate 	ftrace_data_t *ftd;
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ftrace_lock));
1937c478bd9Sstevel@tonic-gate 	ASSERT(IS_CPU(cpuid));
1947c478bd9Sstevel@tonic-gate 	ASSERT(ftrace_state & FTRACE_ENABLED);
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 	ftd = &cpu[cpuid]->cpu_ftrace;
1977c478bd9Sstevel@tonic-gate 	if (ftd->ftd_state & FTRACE_READY) {
1987c478bd9Sstevel@tonic-gate 		if (ftd->ftd_first == NULL) {
1997c478bd9Sstevel@tonic-gate 			ftrace_record_t *ptrs;
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 			mutex_exit(&ftrace_lock);
2027c478bd9Sstevel@tonic-gate 			ptrs = kmem_zalloc(ftrace_nent *
2037c478bd9Sstevel@tonic-gate 			    sizeof (ftrace_record_t), KM_SLEEP);
2047c478bd9Sstevel@tonic-gate 			mutex_enter(&ftrace_lock);
205*4df4bd60Sbs 			if (ftd->ftd_first != NULL) {
206*4df4bd60Sbs 				/*
207*4df4bd60Sbs 				 * Someone else beat us to it. The winner will
208*4df4bd60Sbs 				 * set up the pointers and the state.
209*4df4bd60Sbs 				 */
210*4df4bd60Sbs 				kmem_free(ptrs,
211*4df4bd60Sbs 				    ftrace_nent * sizeof (ftrace_record_t));
212*4df4bd60Sbs 				return;
213*4df4bd60Sbs 			}
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 			ftd->ftd_first = ptrs;
2167c478bd9Sstevel@tonic-gate 			ftd->ftd_last = ptrs + (ftrace_nent - 1);
2177c478bd9Sstevel@tonic-gate 			ftd->ftd_cur = ptrs;
2187c478bd9Sstevel@tonic-gate 			membar_producer();
2197c478bd9Sstevel@tonic-gate 		}
2207c478bd9Sstevel@tonic-gate 		ftd->ftd_state |= FTRACE_ENABLED;
2217c478bd9Sstevel@tonic-gate 	}
2227c478bd9Sstevel@tonic-gate }
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate static void
ftrace_cpu_stop(int cpuid)2257c478bd9Sstevel@tonic-gate ftrace_cpu_stop(int cpuid)
2267c478bd9Sstevel@tonic-gate {
2277c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ftrace_lock));
2287c478bd9Sstevel@tonic-gate 	ASSERT(IS_CPU(cpuid));
2297c478bd9Sstevel@tonic-gate 	cpu[cpuid]->cpu_ftrace.ftd_state &= ~(FTRACE_ENABLED);
2307c478bd9Sstevel@tonic-gate }
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate /*
2337c478bd9Sstevel@tonic-gate  * Hook for DR.
2347c478bd9Sstevel@tonic-gate  */
2357c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2367c478bd9Sstevel@tonic-gate int
ftrace_cpu_setup(cpu_setup_t what,int id,void * arg)2377c478bd9Sstevel@tonic-gate ftrace_cpu_setup(cpu_setup_t what, int id, void *arg)
2387c478bd9Sstevel@tonic-gate {
2397c478bd9Sstevel@tonic-gate 	if (!(ftrace_state & FTRACE_READY))
2407c478bd9Sstevel@tonic-gate 		return (0);
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 	switch (what) {
2437c478bd9Sstevel@tonic-gate 	case CPU_CONFIG:
2447c478bd9Sstevel@tonic-gate 		mutex_enter(&ftrace_lock);
2457c478bd9Sstevel@tonic-gate 		ftrace_cpu_init(id);
2467c478bd9Sstevel@tonic-gate 		if (ftrace_state & FTRACE_ENABLED)
2477c478bd9Sstevel@tonic-gate 			ftrace_cpu_start(id);
2487c478bd9Sstevel@tonic-gate 		mutex_exit(&ftrace_lock);
2497c478bd9Sstevel@tonic-gate 		break;
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 	case CPU_UNCONFIG:
2527c478bd9Sstevel@tonic-gate 		mutex_enter(&ftrace_lock);
2537c478bd9Sstevel@tonic-gate 		ftrace_cpu_fini(id);
2547c478bd9Sstevel@tonic-gate 		mutex_exit(&ftrace_lock);
2557c478bd9Sstevel@tonic-gate 		break;
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	default:
2587c478bd9Sstevel@tonic-gate 		break;
2597c478bd9Sstevel@tonic-gate 	}
2607c478bd9Sstevel@tonic-gate 	return (0);
2617c478bd9Sstevel@tonic-gate }
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate void
ftrace_init(void)2647c478bd9Sstevel@tonic-gate ftrace_init(void)
2657c478bd9Sstevel@tonic-gate {
2667c478bd9Sstevel@tonic-gate 	int i;
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	ASSERT(!(ftrace_state & FTRACE_READY));
2697c478bd9Sstevel@tonic-gate 	mutex_init(&ftrace_lock, NULL, MUTEX_DEFAULT, NULL);
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 	mutex_enter(&ftrace_lock);
2727c478bd9Sstevel@tonic-gate 	for (i = 0; i < NCPU; i++) {
2737c478bd9Sstevel@tonic-gate 		if (IS_CPU(i)) {
2747c478bd9Sstevel@tonic-gate 			/* should have been kmem_zalloc()'ed */
2757c478bd9Sstevel@tonic-gate 			ASSERT(cpu[i]->cpu_ftrace.ftd_state == 0);
2767c478bd9Sstevel@tonic-gate 			ASSERT(cpu[i]->cpu_ftrace.ftd_first == NULL);
2777c478bd9Sstevel@tonic-gate 			ASSERT(cpu[i]->cpu_ftrace.ftd_last == NULL);
2787c478bd9Sstevel@tonic-gate 			ASSERT(cpu[i]->cpu_ftrace.ftd_cur == NULL);
2797c478bd9Sstevel@tonic-gate 		}
2807c478bd9Sstevel@tonic-gate 	}
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 	if (ftrace_nent < 1) {
2837c478bd9Sstevel@tonic-gate 		mutex_exit(&ftrace_lock);
2847c478bd9Sstevel@tonic-gate 		return;
2857c478bd9Sstevel@tonic-gate 	}
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 	for (i = 0; i < NCPU; i++)
2887c478bd9Sstevel@tonic-gate 		if (IS_CPU(i))
2897c478bd9Sstevel@tonic-gate 			ftrace_cpu_init(i);
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	ftrace_state |= FTRACE_READY;
2927c478bd9Sstevel@tonic-gate 	mutex_enter(&cpu_lock);
2937c478bd9Sstevel@tonic-gate 	register_cpu_setup_func(ftrace_cpu_setup, NULL);
2947c478bd9Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
2957c478bd9Sstevel@tonic-gate 	mutex_exit(&ftrace_lock);
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	if (ftrace_atboot)
2987c478bd9Sstevel@tonic-gate 		(void) ftrace_start();
2997c478bd9Sstevel@tonic-gate }
3007c478bd9Sstevel@tonic-gate 
301*4df4bd60Sbs /*
302*4df4bd60Sbs  * Called from uadmin ioctl, or via mp_init_table[] during boot.
303*4df4bd60Sbs  */
3047c478bd9Sstevel@tonic-gate int
ftrace_start(void)3057c478bd9Sstevel@tonic-gate ftrace_start(void)
3067c478bd9Sstevel@tonic-gate {
3077c478bd9Sstevel@tonic-gate 	int i, was_enabled = 0;
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	if (ftrace_state & FTRACE_READY) {
3107c478bd9Sstevel@tonic-gate 		mutex_enter(&ftrace_lock);
3117c478bd9Sstevel@tonic-gate 		was_enabled = ((ftrace_state & FTRACE_ENABLED) != 0);
3127c478bd9Sstevel@tonic-gate 		ftrace_state |= FTRACE_ENABLED;
3137c478bd9Sstevel@tonic-gate 		for (i = 0; i < NCPU; i++)
3147c478bd9Sstevel@tonic-gate 			if (IS_CPU(i))
3157c478bd9Sstevel@tonic-gate 				ftrace_cpu_start(i);
3167c478bd9Sstevel@tonic-gate 		mutex_exit(&ftrace_lock);
3177c478bd9Sstevel@tonic-gate 	}
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	return (was_enabled);
3207c478bd9Sstevel@tonic-gate }
3217c478bd9Sstevel@tonic-gate 
322*4df4bd60Sbs /*
323*4df4bd60Sbs  * Called from uadmin ioctl, to stop tracing.
324*4df4bd60Sbs  */
3257c478bd9Sstevel@tonic-gate int
ftrace_stop(void)3267c478bd9Sstevel@tonic-gate ftrace_stop(void)
3277c478bd9Sstevel@tonic-gate {
3287c478bd9Sstevel@tonic-gate 	int i, was_enabled = 0;
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	if (ftrace_state & FTRACE_READY) {
3317c478bd9Sstevel@tonic-gate 		mutex_enter(&ftrace_lock);
3327c478bd9Sstevel@tonic-gate 		if (ftrace_state & FTRACE_ENABLED) {
3337c478bd9Sstevel@tonic-gate 			was_enabled = 1;
3347c478bd9Sstevel@tonic-gate 			for (i = 0; i < NCPU; i++)
3357c478bd9Sstevel@tonic-gate 				if (IS_CPU(i))
3367c478bd9Sstevel@tonic-gate 					ftrace_cpu_stop(i);
3377c478bd9Sstevel@tonic-gate 			ftrace_state &= ~(FTRACE_ENABLED);
3387c478bd9Sstevel@tonic-gate 		}
3397c478bd9Sstevel@tonic-gate 		mutex_exit(&ftrace_lock);
3407c478bd9Sstevel@tonic-gate 	}
3417c478bd9Sstevel@tonic-gate 	return (was_enabled);
3427c478bd9Sstevel@tonic-gate }
3437c478bd9Sstevel@tonic-gate 
344*4df4bd60Sbs /*
345*4df4bd60Sbs  * ftrace_X() functions are called from trace context. All callers of ftrace_X()
346*4df4bd60Sbs  * tests FTRACE_ENABLED first. Although this is not very accurate, it keeps the
347*4df4bd60Sbs  * overhead very low when tracing is not enabled.
348*4df4bd60Sbs  *
349*4df4bd60Sbs  * gethrtime_unscaled() appears to be safe to be called in trace context. As an
350*4df4bd60Sbs  * added precaution, we call these before we disable interrupts on this cpu.
351*4df4bd60Sbs  */
352*4df4bd60Sbs 
3537c478bd9Sstevel@tonic-gate void
ftrace_0(char * str,caddr_t caller)354*4df4bd60Sbs ftrace_0(char *str, caddr_t caller)
3557c478bd9Sstevel@tonic-gate {
3567c478bd9Sstevel@tonic-gate 	ftrace_record_t *r;
357*4df4bd60Sbs 	struct cpu *cp;
358*4df4bd60Sbs 	ftrace_data_t *ftd;
359*4df4bd60Sbs 	ftrace_icookie_t cookie;
360*4df4bd60Sbs 	hrtime_t  timestamp;
361*4df4bd60Sbs 
362*4df4bd60Sbs 	timestamp = gethrtime_unscaled();
363*4df4bd60Sbs 
364*4df4bd60Sbs 	cookie = ftrace_interrupt_disable();
365*4df4bd60Sbs 
366*4df4bd60Sbs 	cp = CPU;
367*4df4bd60Sbs 	ftd = &cp->cpu_ftrace;
368*4df4bd60Sbs 
369*4df4bd60Sbs 	if (!(ftd->ftd_state & FTRACE_ENABLED)) {
370*4df4bd60Sbs 		ftrace_interrupt_enable(cookie);
371*4df4bd60Sbs 		return;
3727c478bd9Sstevel@tonic-gate 	}
373*4df4bd60Sbs 
3747c478bd9Sstevel@tonic-gate 	r = ftd->ftd_cur;
3757c478bd9Sstevel@tonic-gate 	r->ftr_event = str;
3767c478bd9Sstevel@tonic-gate 	r->ftr_thread = curthread;
377*4df4bd60Sbs 	r->ftr_tick = timestamp;
378*4df4bd60Sbs 	r->ftr_caller = caller;
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	if (r++ == ftd->ftd_last)
3817c478bd9Sstevel@tonic-gate 		r = ftd->ftd_first;
3827c478bd9Sstevel@tonic-gate 	ftd->ftd_cur = r;
383*4df4bd60Sbs 
384*4df4bd60Sbs 	ftrace_interrupt_enable(cookie);
3857c478bd9Sstevel@tonic-gate }
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate void
ftrace_1(char * str,ulong_t arg1,caddr_t caller)388*4df4bd60Sbs ftrace_1(char *str, ulong_t arg1, caddr_t caller)
3897c478bd9Sstevel@tonic-gate {
3907c478bd9Sstevel@tonic-gate 	ftrace_record_t *r;
391*4df4bd60Sbs 	struct cpu *cp;
392*4df4bd60Sbs 	ftrace_data_t *ftd;
393*4df4bd60Sbs 	ftrace_icookie_t cookie;
394*4df4bd60Sbs 	hrtime_t  timestamp;
395*4df4bd60Sbs 
396*4df4bd60Sbs 	timestamp = gethrtime_unscaled();
397*4df4bd60Sbs 
398*4df4bd60Sbs 	cookie = ftrace_interrupt_disable();
399*4df4bd60Sbs 
400*4df4bd60Sbs 	cp = CPU;
401*4df4bd60Sbs 	ftd = &cp->cpu_ftrace;
402*4df4bd60Sbs 
403*4df4bd60Sbs 	if (!(ftd->ftd_state & FTRACE_ENABLED)) {
404*4df4bd60Sbs 		ftrace_interrupt_enable(cookie);
405*4df4bd60Sbs 		return;
4067c478bd9Sstevel@tonic-gate 	}
407*4df4bd60Sbs 
4087c478bd9Sstevel@tonic-gate 	r = ftd->ftd_cur;
4097c478bd9Sstevel@tonic-gate 	r->ftr_event = str;
4107c478bd9Sstevel@tonic-gate 	r->ftr_thread = curthread;
411*4df4bd60Sbs 	r->ftr_tick = timestamp;
412*4df4bd60Sbs 	r->ftr_caller = caller;
4137c478bd9Sstevel@tonic-gate 	r->ftr_data1 = arg1;
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	if (r++ == ftd->ftd_last)
4167c478bd9Sstevel@tonic-gate 		r = ftd->ftd_first;
4177c478bd9Sstevel@tonic-gate 	ftd->ftd_cur = r;
418*4df4bd60Sbs 
419*4df4bd60Sbs 	ftrace_interrupt_enable(cookie);
4207c478bd9Sstevel@tonic-gate }
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate void
ftrace_2(char * str,ulong_t arg1,ulong_t arg2,caddr_t caller)423*4df4bd60Sbs ftrace_2(char *str, ulong_t arg1, ulong_t arg2, caddr_t caller)
4247c478bd9Sstevel@tonic-gate {
4257c478bd9Sstevel@tonic-gate 	ftrace_record_t *r;
426*4df4bd60Sbs 	struct cpu *cp;
427*4df4bd60Sbs 	ftrace_data_t *ftd;
428*4df4bd60Sbs 	ftrace_icookie_t cookie;
429*4df4bd60Sbs 	hrtime_t  timestamp;
430*4df4bd60Sbs 
431*4df4bd60Sbs 	timestamp = gethrtime_unscaled();
432*4df4bd60Sbs 
433*4df4bd60Sbs 	cookie = ftrace_interrupt_disable();
434*4df4bd60Sbs 
435*4df4bd60Sbs 	cp = CPU;
436*4df4bd60Sbs 	ftd = &cp->cpu_ftrace;
437*4df4bd60Sbs 
438*4df4bd60Sbs 	if (!(ftd->ftd_state & FTRACE_ENABLED)) {
439*4df4bd60Sbs 		ftrace_interrupt_enable(cookie);
440*4df4bd60Sbs 		return;
4417c478bd9Sstevel@tonic-gate 	}
442*4df4bd60Sbs 
4437c478bd9Sstevel@tonic-gate 	r = ftd->ftd_cur;
4447c478bd9Sstevel@tonic-gate 	r->ftr_event = str;
4457c478bd9Sstevel@tonic-gate 	r->ftr_thread = curthread;
446*4df4bd60Sbs 	r->ftr_tick = timestamp;
447*4df4bd60Sbs 	r->ftr_caller = caller;
4487c478bd9Sstevel@tonic-gate 	r->ftr_data1 = arg1;
4497c478bd9Sstevel@tonic-gate 	r->ftr_data2 = arg2;
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 	if (r++ == ftd->ftd_last)
4527c478bd9Sstevel@tonic-gate 		r = ftd->ftd_first;
4537c478bd9Sstevel@tonic-gate 	ftd->ftd_cur = r;
454*4df4bd60Sbs 
455*4df4bd60Sbs 	ftrace_interrupt_enable(cookie);
4567c478bd9Sstevel@tonic-gate }
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate void
ftrace_3(char * str,ulong_t arg1,ulong_t arg2,ulong_t arg3,caddr_t caller)459*4df4bd60Sbs ftrace_3(char *str, ulong_t arg1, ulong_t arg2, ulong_t arg3, caddr_t caller)
4607c478bd9Sstevel@tonic-gate {
4617c478bd9Sstevel@tonic-gate 	ftrace_record_t *r;
462*4df4bd60Sbs 	struct cpu *cp;
463*4df4bd60Sbs 	ftrace_data_t *ftd;
464*4df4bd60Sbs 	ftrace_icookie_t cookie;
465*4df4bd60Sbs 	hrtime_t  timestamp;
466*4df4bd60Sbs 
467*4df4bd60Sbs 	timestamp = gethrtime_unscaled();
468*4df4bd60Sbs 
469*4df4bd60Sbs 	cookie = ftrace_interrupt_disable();
470*4df4bd60Sbs 
471*4df4bd60Sbs 	cp = CPU;
472*4df4bd60Sbs 	ftd = &cp->cpu_ftrace;
473*4df4bd60Sbs 
474*4df4bd60Sbs 	if (!(ftd->ftd_state & FTRACE_ENABLED)) {
475*4df4bd60Sbs 		ftrace_interrupt_enable(cookie);
476*4df4bd60Sbs 		return;
4777c478bd9Sstevel@tonic-gate 	}
478*4df4bd60Sbs 
4797c478bd9Sstevel@tonic-gate 	r = ftd->ftd_cur;
4807c478bd9Sstevel@tonic-gate 	r->ftr_event = str;
4817c478bd9Sstevel@tonic-gate 	r->ftr_thread = curthread;
482*4df4bd60Sbs 	r->ftr_tick = timestamp;
483*4df4bd60Sbs 	r->ftr_caller = caller;
4847c478bd9Sstevel@tonic-gate 	r->ftr_data1 = arg1;
4857c478bd9Sstevel@tonic-gate 	r->ftr_data2 = arg2;
4867c478bd9Sstevel@tonic-gate 	r->ftr_data3 = arg3;
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 	if (r++ == ftd->ftd_last)
4897c478bd9Sstevel@tonic-gate 		r = ftd->ftd_first;
4907c478bd9Sstevel@tonic-gate 	ftd->ftd_cur = r;
491*4df4bd60Sbs 
492*4df4bd60Sbs 	ftrace_interrupt_enable(cookie);
4937c478bd9Sstevel@tonic-gate }
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate void
ftrace_3_notick(char * str,ulong_t arg1,ulong_t arg2,ulong_t arg3,caddr_t caller)496*4df4bd60Sbs ftrace_3_notick(char *str, ulong_t arg1, ulong_t arg2,
497*4df4bd60Sbs     ulong_t arg3, caddr_t caller)
4987c478bd9Sstevel@tonic-gate {
4997c478bd9Sstevel@tonic-gate 	ftrace_record_t *r;
500*4df4bd60Sbs 	struct cpu *cp;
501*4df4bd60Sbs 	ftrace_data_t *ftd;
502*4df4bd60Sbs 	ftrace_icookie_t cookie;
503*4df4bd60Sbs 
504*4df4bd60Sbs 	cookie = ftrace_interrupt_disable();
505*4df4bd60Sbs 
506*4df4bd60Sbs 	cp = CPU;
507*4df4bd60Sbs 	ftd = &cp->cpu_ftrace;
508*4df4bd60Sbs 
509*4df4bd60Sbs 	if (!(ftd->ftd_state & FTRACE_ENABLED)) {
510*4df4bd60Sbs 		ftrace_interrupt_enable(cookie);
511*4df4bd60Sbs 		return;
5127c478bd9Sstevel@tonic-gate 	}
513*4df4bd60Sbs 
5147c478bd9Sstevel@tonic-gate 	r = ftd->ftd_cur;
5157c478bd9Sstevel@tonic-gate 	r->ftr_event = str;
5167c478bd9Sstevel@tonic-gate 	r->ftr_thread = curthread;
5177c478bd9Sstevel@tonic-gate 	r->ftr_tick = 0;
518*4df4bd60Sbs 	r->ftr_caller = caller;
5197c478bd9Sstevel@tonic-gate 	r->ftr_data1 = arg1;
5207c478bd9Sstevel@tonic-gate 	r->ftr_data2 = arg2;
5217c478bd9Sstevel@tonic-gate 	r->ftr_data3 = arg3;
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 	if (r++ == ftd->ftd_last)
5247c478bd9Sstevel@tonic-gate 		r = ftd->ftd_first;
5257c478bd9Sstevel@tonic-gate 	ftd->ftd_cur = r;
526*4df4bd60Sbs 
527*4df4bd60Sbs 	ftrace_interrupt_enable(cookie);
5287c478bd9Sstevel@tonic-gate }
529