xref: /onnv-gate/usr/src/uts/common/os/ftrace.c (revision 3647:76d3d42bd153)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*3647Sbs21162  * Common Development and Distribution License (the "License").
6*3647Sbs21162  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*3647Sbs21162  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <sys/types.h>
290Sstevel@tonic-gate #include <sys/kmem.h>
300Sstevel@tonic-gate #include <sys/mutex.h>
310Sstevel@tonic-gate #include <sys/cpuvar.h>
320Sstevel@tonic-gate #include <sys/cmn_err.h>
330Sstevel@tonic-gate #include <sys/systm.h>
340Sstevel@tonic-gate #include <sys/ddi.h>
350Sstevel@tonic-gate #include <sys/sunddi.h>
360Sstevel@tonic-gate #include <sys/debug.h>
370Sstevel@tonic-gate #include <sys/param.h>
380Sstevel@tonic-gate #include <sys/atomic.h>
390Sstevel@tonic-gate #include <sys/ftrace.h>
400Sstevel@tonic-gate 
410Sstevel@tonic-gate /*
420Sstevel@tonic-gate  * Tunable parameters:
430Sstevel@tonic-gate  *
440Sstevel@tonic-gate  * ftrace_atboot	- whether to start fast tracing at boot.
450Sstevel@tonic-gate  * ftrace_nent		- size of the per-CPU event ring buffer.
460Sstevel@tonic-gate  */
470Sstevel@tonic-gate int ftrace_atboot = 0;
480Sstevel@tonic-gate int ftrace_nent = FTRACE_NENT;
490Sstevel@tonic-gate 
500Sstevel@tonic-gate /*
51*3647Sbs21162  * Global Tracing State:
52*3647Sbs21162  *
53*3647Sbs21162  *                NOTREADY(=0)
54*3647Sbs21162  *                  |
55*3647Sbs21162  *            ftrace_init()
56*3647Sbs21162  *                  |
57*3647Sbs21162  *                  |
58*3647Sbs21162  *                  v
59*3647Sbs21162  *      +-------->READY-------+
60*3647Sbs21162  *      |                     |
61*3647Sbs21162  *  ftrace_stop()         ftrace_start()
62*3647Sbs21162  *      |                     |
63*3647Sbs21162  *      +---(ENABLED|READY)<--+
64*3647Sbs21162  *
65*3647Sbs21162  * During boot, ftrace_init() is called and the state becomes
66*3647Sbs21162  * READY. If ftrace_atboot is set, ftrace_start() is called at
67*3647Sbs21162  * this time.
68*3647Sbs21162  *
690Sstevel@tonic-gate  * If FTRACE_READY is set, then tracing can be enabled.
700Sstevel@tonic-gate  * If FTRACE_ENABLED is set, tracing is enabled on the set of CPUs
710Sstevel@tonic-gate  *   which are currently FTRACE_READY.
720Sstevel@tonic-gate  */
730Sstevel@tonic-gate static int ftrace_state = 0;
740Sstevel@tonic-gate 
750Sstevel@tonic-gate /*
76*3647Sbs21162  * Per-CPU Tracing State:
77*3647Sbs21162  *
78*3647Sbs21162  *     +-----------------READY<--------------+
79*3647Sbs21162  *     |                 ^   |               |
80*3647Sbs21162  *     |                 | ftrace_cpu_fini() |
81*3647Sbs21162  *     |                 |   |               |
82*3647Sbs21162  *     |   ftrace_cpu_init() |               |
83*3647Sbs21162  *     |                 |   v     ftrace_cpu_stop()
84*3647Sbs21162  *     |              NOTREADY(=0)           |
85*3647Sbs21162  *     |                   ^                 |
86*3647Sbs21162  * ftrace_cpu_start()      |                 |
87*3647Sbs21162  *     |              ftrace_cpu_fini()      |
88*3647Sbs21162  *     |                   |                 |
89*3647Sbs21162  *     +----------->(ENABLED|READY)----------+
90*3647Sbs21162  *
91*3647Sbs21162  */
92*3647Sbs21162 
93*3647Sbs21162 /*
94*3647Sbs21162  * Locking :
95*3647Sbs21162  *
96*3647Sbs21162  * Trace context code does not use any lock. There is a per-cpu circular trace
97*3647Sbs21162  * buffer that has a head, a tail and a current pointer. Each record of this
98*3647Sbs21162  * buffer is of equal length. Before doing anything, trace context code checks
99*3647Sbs21162  * the per-cpu ENABLED bit. Trace buffer is allocated in non-trace context and
100*3647Sbs21162  * it sets this bit only after allocating and setting up the buffer. So trace
101*3647Sbs21162  * context code can't access the buffer till it is set up completely. The
102*3647Sbs21162  * buffer is freed also in non-trace context. The code that frees the buffer is
103*3647Sbs21162  * executed only after the corresponding cpu is powered off. So when this
104*3647Sbs21162  * happens, no trace context code can be running on it. We only need to make
105*3647Sbs21162  * sure that trace context code is not preempted from the cpu in the middle of
106*3647Sbs21162  * accessing the trace buffer. This can be achieved simply by disabling
107*3647Sbs21162  * interrupts temporarily. This approach makes the least assumption about the
108*3647Sbs21162  * state of the callers of tracing functions.
109*3647Sbs21162  *
110*3647Sbs21162  * A single global lock, ftrace_lock protects assignments to all global and
111*3647Sbs21162  * per-cpu trace variables. It does not protect reading of those in some cases.
112*3647Sbs21162  *
113*3647Sbs21162  * More specifically, it protects assignments to:
114*3647Sbs21162  *
1150Sstevel@tonic-gate  *   ftrace_state
1160Sstevel@tonic-gate  *   cpu[N]->cpu_ftrace.ftd_state
1170Sstevel@tonic-gate  *   cpu[N]->cpu_ftrace.ftd_first
1180Sstevel@tonic-gate  *   cpu[N]->cpu_ftrace.ftd_last
119*3647Sbs21162  *
120*3647Sbs21162  * Does _not_ protect reading of cpu[N]->cpu_ftrace.ftd_state
121*3647Sbs21162  * Does _not_ protect cpu[N]->cpu_ftrace.ftd_cur
122*3647Sbs21162  * Does _not_ protect reading of ftrace_state
1230Sstevel@tonic-gate  */
1240Sstevel@tonic-gate static kmutex_t ftrace_lock;
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate /*
1270Sstevel@tonic-gate  * Check whether a CPU is installed.
1280Sstevel@tonic-gate  */
1290Sstevel@tonic-gate #define	IS_CPU(i) (cpu[i] != NULL)
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate static void
ftrace_cpu_init(int cpuid)1320Sstevel@tonic-gate ftrace_cpu_init(int cpuid)
1330Sstevel@tonic-gate {
1340Sstevel@tonic-gate 	ftrace_data_t *ftd;
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 	/*
1370Sstevel@tonic-gate 	 * This can be called with "cpu[cpuid]->cpu_flags & CPU_EXISTS"
1380Sstevel@tonic-gate 	 * being false - e.g. when a CPU is DR'ed in.
1390Sstevel@tonic-gate 	 */
1400Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ftrace_lock));
1410Sstevel@tonic-gate 	ASSERT(IS_CPU(cpuid));
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate 	ftd = &cpu[cpuid]->cpu_ftrace;
1440Sstevel@tonic-gate 	if (ftd->ftd_state & FTRACE_READY)
1450Sstevel@tonic-gate 		return;
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 	/*
1480Sstevel@tonic-gate 	 * We don't allocate the buffers until the first time
1490Sstevel@tonic-gate 	 *   ftrace_cpu_start() is called, so that they're not
1500Sstevel@tonic-gate 	 *   allocated if ftrace is never enabled.
1510Sstevel@tonic-gate 	 */
1520Sstevel@tonic-gate 	ftd->ftd_state |= FTRACE_READY;
1530Sstevel@tonic-gate 	ASSERT(!(ftd->ftd_state & FTRACE_ENABLED));
1540Sstevel@tonic-gate }
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate /*
1570Sstevel@tonic-gate  * Only called from cpu_unconfigure() (and cpu_configure() on error).
1580Sstevel@tonic-gate  * At this point, cpu[cpuid] is about to be freed and NULLed out,
1590Sstevel@tonic-gate  *   so we'd better clean up after ourselves.
1600Sstevel@tonic-gate  */
1610Sstevel@tonic-gate static void
ftrace_cpu_fini(int cpuid)1620Sstevel@tonic-gate ftrace_cpu_fini(int cpuid)
1630Sstevel@tonic-gate {
1640Sstevel@tonic-gate 	ftrace_data_t *ftd;
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ftrace_lock));
1670Sstevel@tonic-gate 	ASSERT(IS_CPU(cpuid));
1680Sstevel@tonic-gate 	ASSERT((cpu[cpuid]->cpu_flags & CPU_POWEROFF) != 0);
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 	ftd = &cpu[cpuid]->cpu_ftrace;
1710Sstevel@tonic-gate 	if (!(ftd->ftd_state & FTRACE_READY))
1720Sstevel@tonic-gate 		return;
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate 	/*
175*3647Sbs21162 	 * This cpu is powered off and no code can be executing on it. So
176*3647Sbs21162 	 * we can simply finish our cleanup. There is no need for a xcall
177*3647Sbs21162 	 * to make sure that this cpu is out of trace context.
178*3647Sbs21162 	 *
179*3647Sbs21162 	 * The cpu structure will be cleared soon. But, for the sake of
180*3647Sbs21162 	 * debugging, clear our pointers and state.
1810Sstevel@tonic-gate 	 */
182*3647Sbs21162 	if (ftd->ftd_first != NULL) {
183*3647Sbs21162 		kmem_free(ftd->ftd_first,
184*3647Sbs21162 		    ftrace_nent * sizeof (ftrace_record_t));
185*3647Sbs21162 	}
186*3647Sbs21162 	bzero(ftd, sizeof (ftrace_data_t));
1870Sstevel@tonic-gate }
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate static void
ftrace_cpu_start(int cpuid)1900Sstevel@tonic-gate ftrace_cpu_start(int cpuid)
1910Sstevel@tonic-gate {
1920Sstevel@tonic-gate 	ftrace_data_t *ftd;
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ftrace_lock));
1950Sstevel@tonic-gate 	ASSERT(IS_CPU(cpuid));
1960Sstevel@tonic-gate 	ASSERT(ftrace_state & FTRACE_ENABLED);
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 	ftd = &cpu[cpuid]->cpu_ftrace;
1990Sstevel@tonic-gate 	if (ftd->ftd_state & FTRACE_READY) {
2000Sstevel@tonic-gate 		if (ftd->ftd_first == NULL) {
2010Sstevel@tonic-gate 			ftrace_record_t *ptrs;
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 			mutex_exit(&ftrace_lock);
2040Sstevel@tonic-gate 			ptrs = kmem_zalloc(ftrace_nent *
2050Sstevel@tonic-gate 			    sizeof (ftrace_record_t), KM_SLEEP);
2060Sstevel@tonic-gate 			mutex_enter(&ftrace_lock);
207*3647Sbs21162 			if (ftd->ftd_first != NULL) {
208*3647Sbs21162 				/*
209*3647Sbs21162 				 * Someone else beat us to it. The winner will
210*3647Sbs21162 				 * set up the pointers and the state.
211*3647Sbs21162 				 */
212*3647Sbs21162 				kmem_free(ptrs,
213*3647Sbs21162 				    ftrace_nent * sizeof (ftrace_record_t));
214*3647Sbs21162 				return;
215*3647Sbs21162 			}
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 			ftd->ftd_first = ptrs;
2180Sstevel@tonic-gate 			ftd->ftd_last = ptrs + (ftrace_nent - 1);
2190Sstevel@tonic-gate 			ftd->ftd_cur = ptrs;
2200Sstevel@tonic-gate 			membar_producer();
2210Sstevel@tonic-gate 		}
2220Sstevel@tonic-gate 		ftd->ftd_state |= FTRACE_ENABLED;
2230Sstevel@tonic-gate 	}
2240Sstevel@tonic-gate }
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate static void
ftrace_cpu_stop(int cpuid)2270Sstevel@tonic-gate ftrace_cpu_stop(int cpuid)
2280Sstevel@tonic-gate {
2290Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ftrace_lock));
2300Sstevel@tonic-gate 	ASSERT(IS_CPU(cpuid));
2310Sstevel@tonic-gate 	cpu[cpuid]->cpu_ftrace.ftd_state &= ~(FTRACE_ENABLED);
2320Sstevel@tonic-gate }
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate /*
2350Sstevel@tonic-gate  * Hook for DR.
2360Sstevel@tonic-gate  */
2370Sstevel@tonic-gate /*ARGSUSED*/
2380Sstevel@tonic-gate int
ftrace_cpu_setup(cpu_setup_t what,int id,void * arg)2390Sstevel@tonic-gate ftrace_cpu_setup(cpu_setup_t what, int id, void *arg)
2400Sstevel@tonic-gate {
2410Sstevel@tonic-gate 	if (!(ftrace_state & FTRACE_READY))
2420Sstevel@tonic-gate 		return (0);
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 	switch (what) {
2450Sstevel@tonic-gate 	case CPU_CONFIG:
2460Sstevel@tonic-gate 		mutex_enter(&ftrace_lock);
2470Sstevel@tonic-gate 		ftrace_cpu_init(id);
2480Sstevel@tonic-gate 		if (ftrace_state & FTRACE_ENABLED)
2490Sstevel@tonic-gate 			ftrace_cpu_start(id);
2500Sstevel@tonic-gate 		mutex_exit(&ftrace_lock);
2510Sstevel@tonic-gate 		break;
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate 	case CPU_UNCONFIG:
2540Sstevel@tonic-gate 		mutex_enter(&ftrace_lock);
2550Sstevel@tonic-gate 		ftrace_cpu_fini(id);
2560Sstevel@tonic-gate 		mutex_exit(&ftrace_lock);
2570Sstevel@tonic-gate 		break;
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate 	default:
2600Sstevel@tonic-gate 		break;
2610Sstevel@tonic-gate 	}
2620Sstevel@tonic-gate 	return (0);
2630Sstevel@tonic-gate }
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate void
ftrace_init(void)2660Sstevel@tonic-gate ftrace_init(void)
2670Sstevel@tonic-gate {
2680Sstevel@tonic-gate 	int i;
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate 	ASSERT(!(ftrace_state & FTRACE_READY));
2710Sstevel@tonic-gate 	mutex_init(&ftrace_lock, NULL, MUTEX_DEFAULT, NULL);
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 	mutex_enter(&ftrace_lock);
2740Sstevel@tonic-gate 	for (i = 0; i < NCPU; i++) {
2750Sstevel@tonic-gate 		if (IS_CPU(i)) {
2760Sstevel@tonic-gate 			/* should have been kmem_zalloc()'ed */
2770Sstevel@tonic-gate 			ASSERT(cpu[i]->cpu_ftrace.ftd_state == 0);
2780Sstevel@tonic-gate 			ASSERT(cpu[i]->cpu_ftrace.ftd_first == NULL);
2790Sstevel@tonic-gate 			ASSERT(cpu[i]->cpu_ftrace.ftd_last == NULL);
2800Sstevel@tonic-gate 			ASSERT(cpu[i]->cpu_ftrace.ftd_cur == NULL);
2810Sstevel@tonic-gate 		}
2820Sstevel@tonic-gate 	}
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 	if (ftrace_nent < 1) {
2850Sstevel@tonic-gate 		mutex_exit(&ftrace_lock);
2860Sstevel@tonic-gate 		return;
2870Sstevel@tonic-gate 	}
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 	for (i = 0; i < NCPU; i++)
2900Sstevel@tonic-gate 		if (IS_CPU(i))
2910Sstevel@tonic-gate 			ftrace_cpu_init(i);
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 	ftrace_state |= FTRACE_READY;
2940Sstevel@tonic-gate 	mutex_enter(&cpu_lock);
2950Sstevel@tonic-gate 	register_cpu_setup_func(ftrace_cpu_setup, NULL);
2960Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
2970Sstevel@tonic-gate 	mutex_exit(&ftrace_lock);
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 	if (ftrace_atboot)
3000Sstevel@tonic-gate 		(void) ftrace_start();
3010Sstevel@tonic-gate }
3020Sstevel@tonic-gate 
303*3647Sbs21162 /*
304*3647Sbs21162  * Called from uadmin ioctl, or via mp_init_table[] during boot.
305*3647Sbs21162  */
3060Sstevel@tonic-gate int
ftrace_start(void)3070Sstevel@tonic-gate ftrace_start(void)
3080Sstevel@tonic-gate {
3090Sstevel@tonic-gate 	int i, was_enabled = 0;
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 	if (ftrace_state & FTRACE_READY) {
3120Sstevel@tonic-gate 		mutex_enter(&ftrace_lock);
3130Sstevel@tonic-gate 		was_enabled = ((ftrace_state & FTRACE_ENABLED) != 0);
3140Sstevel@tonic-gate 		ftrace_state |= FTRACE_ENABLED;
3150Sstevel@tonic-gate 		for (i = 0; i < NCPU; i++)
3160Sstevel@tonic-gate 			if (IS_CPU(i))
3170Sstevel@tonic-gate 				ftrace_cpu_start(i);
3180Sstevel@tonic-gate 		mutex_exit(&ftrace_lock);
3190Sstevel@tonic-gate 	}
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	return (was_enabled);
3220Sstevel@tonic-gate }
3230Sstevel@tonic-gate 
324*3647Sbs21162 /*
325*3647Sbs21162  * Called from uadmin ioctl, to stop tracing.
326*3647Sbs21162  */
3270Sstevel@tonic-gate int
ftrace_stop(void)3280Sstevel@tonic-gate ftrace_stop(void)
3290Sstevel@tonic-gate {
3300Sstevel@tonic-gate 	int i, was_enabled = 0;
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	if (ftrace_state & FTRACE_READY) {
3330Sstevel@tonic-gate 		mutex_enter(&ftrace_lock);
3340Sstevel@tonic-gate 		if (ftrace_state & FTRACE_ENABLED) {
3350Sstevel@tonic-gate 			was_enabled = 1;
3360Sstevel@tonic-gate 			for (i = 0; i < NCPU; i++)
3370Sstevel@tonic-gate 				if (IS_CPU(i))
3380Sstevel@tonic-gate 					ftrace_cpu_stop(i);
3390Sstevel@tonic-gate 			ftrace_state &= ~(FTRACE_ENABLED);
3400Sstevel@tonic-gate 		}
3410Sstevel@tonic-gate 		mutex_exit(&ftrace_lock);
3420Sstevel@tonic-gate 	}
3430Sstevel@tonic-gate 	return (was_enabled);
3440Sstevel@tonic-gate }
3450Sstevel@tonic-gate 
346*3647Sbs21162 /*
347*3647Sbs21162  * ftrace_X() functions are called from trace context. All callers of ftrace_X()
348*3647Sbs21162  * tests FTRACE_ENABLED first. Although this is not very accurate, it keeps the
349*3647Sbs21162  * overhead very low when tracing is not enabled.
350*3647Sbs21162  *
351*3647Sbs21162  * gethrtime_unscaled() appears to be safe to be called in trace context. As an
352*3647Sbs21162  * added precaution, we call these before we disable interrupts on this cpu.
353*3647Sbs21162  */
354*3647Sbs21162 
3550Sstevel@tonic-gate void
ftrace_0(char * str,caddr_t caller)356*3647Sbs21162 ftrace_0(char *str, caddr_t caller)
3570Sstevel@tonic-gate {
3580Sstevel@tonic-gate 	ftrace_record_t *r;
359*3647Sbs21162 	struct cpu *cp;
360*3647Sbs21162 	ftrace_data_t *ftd;
361*3647Sbs21162 	ftrace_icookie_t cookie;
362*3647Sbs21162 	hrtime_t  timestamp;
363*3647Sbs21162 
364*3647Sbs21162 	timestamp = gethrtime_unscaled();
365*3647Sbs21162 
366*3647Sbs21162 	cookie = ftrace_interrupt_disable();
3670Sstevel@tonic-gate 
368*3647Sbs21162 	cp = CPU;
369*3647Sbs21162 	ftd = &cp->cpu_ftrace;
370*3647Sbs21162 
371*3647Sbs21162 	if (!(ftd->ftd_state & FTRACE_ENABLED)) {
372*3647Sbs21162 		ftrace_interrupt_enable(cookie);
373*3647Sbs21162 		return;
3740Sstevel@tonic-gate 	}
375*3647Sbs21162 
3760Sstevel@tonic-gate 	r = ftd->ftd_cur;
3770Sstevel@tonic-gate 	r->ftr_event = str;
3780Sstevel@tonic-gate 	r->ftr_thread = curthread;
379*3647Sbs21162 	r->ftr_tick = timestamp;
380*3647Sbs21162 	r->ftr_caller = caller;
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 	if (r++ == ftd->ftd_last)
3830Sstevel@tonic-gate 		r = ftd->ftd_first;
3840Sstevel@tonic-gate 	ftd->ftd_cur = r;
385*3647Sbs21162 
386*3647Sbs21162 	ftrace_interrupt_enable(cookie);
3870Sstevel@tonic-gate }
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate void
ftrace_1(char * str,ulong_t arg1,caddr_t caller)390*3647Sbs21162 ftrace_1(char *str, ulong_t arg1, caddr_t caller)
3910Sstevel@tonic-gate {
3920Sstevel@tonic-gate 	ftrace_record_t *r;
393*3647Sbs21162 	struct cpu *cp;
394*3647Sbs21162 	ftrace_data_t *ftd;
395*3647Sbs21162 	ftrace_icookie_t cookie;
396*3647Sbs21162 	hrtime_t  timestamp;
397*3647Sbs21162 
398*3647Sbs21162 	timestamp = gethrtime_unscaled();
399*3647Sbs21162 
400*3647Sbs21162 	cookie = ftrace_interrupt_disable();
4010Sstevel@tonic-gate 
402*3647Sbs21162 	cp = CPU;
403*3647Sbs21162 	ftd = &cp->cpu_ftrace;
404*3647Sbs21162 
405*3647Sbs21162 	if (!(ftd->ftd_state & FTRACE_ENABLED)) {
406*3647Sbs21162 		ftrace_interrupt_enable(cookie);
407*3647Sbs21162 		return;
4080Sstevel@tonic-gate 	}
409*3647Sbs21162 
4100Sstevel@tonic-gate 	r = ftd->ftd_cur;
4110Sstevel@tonic-gate 	r->ftr_event = str;
4120Sstevel@tonic-gate 	r->ftr_thread = curthread;
413*3647Sbs21162 	r->ftr_tick = timestamp;
414*3647Sbs21162 	r->ftr_caller = caller;
4150Sstevel@tonic-gate 	r->ftr_data1 = arg1;
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate 	if (r++ == ftd->ftd_last)
4180Sstevel@tonic-gate 		r = ftd->ftd_first;
4190Sstevel@tonic-gate 	ftd->ftd_cur = r;
420*3647Sbs21162 
421*3647Sbs21162 	ftrace_interrupt_enable(cookie);
4220Sstevel@tonic-gate }
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate void
ftrace_2(char * str,ulong_t arg1,ulong_t arg2,caddr_t caller)425*3647Sbs21162 ftrace_2(char *str, ulong_t arg1, ulong_t arg2, caddr_t caller)
4260Sstevel@tonic-gate {
4270Sstevel@tonic-gate 	ftrace_record_t *r;
428*3647Sbs21162 	struct cpu *cp;
429*3647Sbs21162 	ftrace_data_t *ftd;
430*3647Sbs21162 	ftrace_icookie_t cookie;
431*3647Sbs21162 	hrtime_t  timestamp;
432*3647Sbs21162 
433*3647Sbs21162 	timestamp = gethrtime_unscaled();
434*3647Sbs21162 
435*3647Sbs21162 	cookie = ftrace_interrupt_disable();
4360Sstevel@tonic-gate 
437*3647Sbs21162 	cp = CPU;
438*3647Sbs21162 	ftd = &cp->cpu_ftrace;
439*3647Sbs21162 
440*3647Sbs21162 	if (!(ftd->ftd_state & FTRACE_ENABLED)) {
441*3647Sbs21162 		ftrace_interrupt_enable(cookie);
442*3647Sbs21162 		return;
4430Sstevel@tonic-gate 	}
444*3647Sbs21162 
4450Sstevel@tonic-gate 	r = ftd->ftd_cur;
4460Sstevel@tonic-gate 	r->ftr_event = str;
4470Sstevel@tonic-gate 	r->ftr_thread = curthread;
448*3647Sbs21162 	r->ftr_tick = timestamp;
449*3647Sbs21162 	r->ftr_caller = caller;
4500Sstevel@tonic-gate 	r->ftr_data1 = arg1;
4510Sstevel@tonic-gate 	r->ftr_data2 = arg2;
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate 	if (r++ == ftd->ftd_last)
4540Sstevel@tonic-gate 		r = ftd->ftd_first;
4550Sstevel@tonic-gate 	ftd->ftd_cur = r;
456*3647Sbs21162 
457*3647Sbs21162 	ftrace_interrupt_enable(cookie);
4580Sstevel@tonic-gate }
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate void
ftrace_3(char * str,ulong_t arg1,ulong_t arg2,ulong_t arg3,caddr_t caller)461*3647Sbs21162 ftrace_3(char *str, ulong_t arg1, ulong_t arg2, ulong_t arg3, caddr_t caller)
4620Sstevel@tonic-gate {
4630Sstevel@tonic-gate 	ftrace_record_t *r;
464*3647Sbs21162 	struct cpu *cp;
465*3647Sbs21162 	ftrace_data_t *ftd;
466*3647Sbs21162 	ftrace_icookie_t cookie;
467*3647Sbs21162 	hrtime_t  timestamp;
468*3647Sbs21162 
469*3647Sbs21162 	timestamp = gethrtime_unscaled();
470*3647Sbs21162 
471*3647Sbs21162 	cookie = ftrace_interrupt_disable();
4720Sstevel@tonic-gate 
473*3647Sbs21162 	cp = CPU;
474*3647Sbs21162 	ftd = &cp->cpu_ftrace;
475*3647Sbs21162 
476*3647Sbs21162 	if (!(ftd->ftd_state & FTRACE_ENABLED)) {
477*3647Sbs21162 		ftrace_interrupt_enable(cookie);
478*3647Sbs21162 		return;
4790Sstevel@tonic-gate 	}
480*3647Sbs21162 
4810Sstevel@tonic-gate 	r = ftd->ftd_cur;
4820Sstevel@tonic-gate 	r->ftr_event = str;
4830Sstevel@tonic-gate 	r->ftr_thread = curthread;
484*3647Sbs21162 	r->ftr_tick = timestamp;
485*3647Sbs21162 	r->ftr_caller = caller;
4860Sstevel@tonic-gate 	r->ftr_data1 = arg1;
4870Sstevel@tonic-gate 	r->ftr_data2 = arg2;
4880Sstevel@tonic-gate 	r->ftr_data3 = arg3;
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 	if (r++ == ftd->ftd_last)
4910Sstevel@tonic-gate 		r = ftd->ftd_first;
4920Sstevel@tonic-gate 	ftd->ftd_cur = r;
493*3647Sbs21162 
494*3647Sbs21162 	ftrace_interrupt_enable(cookie);
4950Sstevel@tonic-gate }
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate void
ftrace_3_notick(char * str,ulong_t arg1,ulong_t arg2,ulong_t arg3,caddr_t caller)498*3647Sbs21162 ftrace_3_notick(char *str, ulong_t arg1, ulong_t arg2,
499*3647Sbs21162     ulong_t arg3, caddr_t caller)
5000Sstevel@tonic-gate {
5010Sstevel@tonic-gate 	ftrace_record_t *r;
502*3647Sbs21162 	struct cpu *cp;
503*3647Sbs21162 	ftrace_data_t *ftd;
504*3647Sbs21162 	ftrace_icookie_t cookie;
505*3647Sbs21162 
506*3647Sbs21162 	cookie = ftrace_interrupt_disable();
5070Sstevel@tonic-gate 
508*3647Sbs21162 	cp = CPU;
509*3647Sbs21162 	ftd = &cp->cpu_ftrace;
510*3647Sbs21162 
511*3647Sbs21162 	if (!(ftd->ftd_state & FTRACE_ENABLED)) {
512*3647Sbs21162 		ftrace_interrupt_enable(cookie);
513*3647Sbs21162 		return;
5140Sstevel@tonic-gate 	}
515*3647Sbs21162 
5160Sstevel@tonic-gate 	r = ftd->ftd_cur;
5170Sstevel@tonic-gate 	r->ftr_event = str;
5180Sstevel@tonic-gate 	r->ftr_thread = curthread;
5190Sstevel@tonic-gate 	r->ftr_tick = 0;
520*3647Sbs21162 	r->ftr_caller = caller;
5210Sstevel@tonic-gate 	r->ftr_data1 = arg1;
5220Sstevel@tonic-gate 	r->ftr_data2 = arg2;
5230Sstevel@tonic-gate 	r->ftr_data3 = arg3;
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 	if (r++ == ftd->ftd_last)
5260Sstevel@tonic-gate 		r = ftd->ftd_first;
5270Sstevel@tonic-gate 	ftd->ftd_cur = r;
528*3647Sbs21162 
529*3647Sbs21162 	ftrace_interrupt_enable(cookie);
5300Sstevel@tonic-gate }
531