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*4df4bd60Sbs21162 * Common Development and Distribution License (the "License").
6*4df4bd60Sbs21162 * 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*4df4bd60Sbs21162 * 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 #pragma ident "%Z%%M% %I% %E% SMI"
277c478bd9Sstevel@tonic-gate
287c478bd9Sstevel@tonic-gate #include <sys/types.h>
297c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
307c478bd9Sstevel@tonic-gate #include <sys/mutex.h>
317c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
327c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
337c478bd9Sstevel@tonic-gate #include <sys/systm.h>
347c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
357c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
367c478bd9Sstevel@tonic-gate #include <sys/debug.h>
377c478bd9Sstevel@tonic-gate #include <sys/param.h>
387c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
397c478bd9Sstevel@tonic-gate #include <sys/ftrace.h>
407c478bd9Sstevel@tonic-gate
417c478bd9Sstevel@tonic-gate /*
427c478bd9Sstevel@tonic-gate * Tunable parameters:
437c478bd9Sstevel@tonic-gate *
447c478bd9Sstevel@tonic-gate * ftrace_atboot - whether to start fast tracing at boot.
457c478bd9Sstevel@tonic-gate * ftrace_nent - size of the per-CPU event ring buffer.
467c478bd9Sstevel@tonic-gate */
477c478bd9Sstevel@tonic-gate int ftrace_atboot = 0;
487c478bd9Sstevel@tonic-gate int ftrace_nent = FTRACE_NENT;
497c478bd9Sstevel@tonic-gate
507c478bd9Sstevel@tonic-gate /*
51*4df4bd60Sbs21162 * Global Tracing State:
52*4df4bd60Sbs21162 *
53*4df4bd60Sbs21162 * NOTREADY(=0)
54*4df4bd60Sbs21162 * |
55*4df4bd60Sbs21162 * ftrace_init()
56*4df4bd60Sbs21162 * |
57*4df4bd60Sbs21162 * |
58*4df4bd60Sbs21162 * v
59*4df4bd60Sbs21162 * +-------->READY-------+
60*4df4bd60Sbs21162 * | |
61*4df4bd60Sbs21162 * ftrace_stop() ftrace_start()
62*4df4bd60Sbs21162 * | |
63*4df4bd60Sbs21162 * +---(ENABLED|READY)<--+
64*4df4bd60Sbs21162 *
65*4df4bd60Sbs21162 * During boot, ftrace_init() is called and the state becomes
66*4df4bd60Sbs21162 * READY. If ftrace_atboot is set, ftrace_start() is called at
67*4df4bd60Sbs21162 * this time.
68*4df4bd60Sbs21162 *
697c478bd9Sstevel@tonic-gate * If FTRACE_READY is set, then tracing can be enabled.
707c478bd9Sstevel@tonic-gate * If FTRACE_ENABLED is set, tracing is enabled on the set of CPUs
717c478bd9Sstevel@tonic-gate * which are currently FTRACE_READY.
727c478bd9Sstevel@tonic-gate */
737c478bd9Sstevel@tonic-gate static int ftrace_state = 0;
747c478bd9Sstevel@tonic-gate
757c478bd9Sstevel@tonic-gate /*
76*4df4bd60Sbs21162 * Per-CPU Tracing State:
77*4df4bd60Sbs21162 *
78*4df4bd60Sbs21162 * +-----------------READY<--------------+
79*4df4bd60Sbs21162 * | ^ | |
80*4df4bd60Sbs21162 * | | ftrace_cpu_fini() |
81*4df4bd60Sbs21162 * | | | |
82*4df4bd60Sbs21162 * | ftrace_cpu_init() | |
83*4df4bd60Sbs21162 * | | v ftrace_cpu_stop()
84*4df4bd60Sbs21162 * | NOTREADY(=0) |
85*4df4bd60Sbs21162 * | ^ |
86*4df4bd60Sbs21162 * ftrace_cpu_start() | |
87*4df4bd60Sbs21162 * | ftrace_cpu_fini() |
88*4df4bd60Sbs21162 * | | |
89*4df4bd60Sbs21162 * +----------->(ENABLED|READY)----------+
90*4df4bd60Sbs21162 *
91*4df4bd60Sbs21162 */
92*4df4bd60Sbs21162
93*4df4bd60Sbs21162 /*
94*4df4bd60Sbs21162 * Locking :
95*4df4bd60Sbs21162 *
96*4df4bd60Sbs21162 * Trace context code does not use any lock. There is a per-cpu circular trace
97*4df4bd60Sbs21162 * buffer that has a head, a tail and a current pointer. Each record of this
98*4df4bd60Sbs21162 * buffer is of equal length. Before doing anything, trace context code checks
99*4df4bd60Sbs21162 * the per-cpu ENABLED bit. Trace buffer is allocated in non-trace context and
100*4df4bd60Sbs21162 * it sets this bit only after allocating and setting up the buffer. So trace
101*4df4bd60Sbs21162 * context code can't access the buffer till it is set up completely. The
102*4df4bd60Sbs21162 * buffer is freed also in non-trace context. The code that frees the buffer is
103*4df4bd60Sbs21162 * executed only after the corresponding cpu is powered off. So when this
104*4df4bd60Sbs21162 * happens, no trace context code can be running on it. We only need to make
105*4df4bd60Sbs21162 * sure that trace context code is not preempted from the cpu in the middle of
106*4df4bd60Sbs21162 * accessing the trace buffer. This can be achieved simply by disabling
107*4df4bd60Sbs21162 * interrupts temporarily. This approach makes the least assumption about the
108*4df4bd60Sbs21162 * state of the callers of tracing functions.
109*4df4bd60Sbs21162 *
110*4df4bd60Sbs21162 * A single global lock, ftrace_lock protects assignments to all global and
111*4df4bd60Sbs21162 * per-cpu trace variables. It does not protect reading of those in some cases.
112*4df4bd60Sbs21162 *
113*4df4bd60Sbs21162 * More specifically, it protects assignments to:
114*4df4bd60Sbs21162 *
1157c478bd9Sstevel@tonic-gate * ftrace_state
1167c478bd9Sstevel@tonic-gate * cpu[N]->cpu_ftrace.ftd_state
1177c478bd9Sstevel@tonic-gate * cpu[N]->cpu_ftrace.ftd_first
1187c478bd9Sstevel@tonic-gate * cpu[N]->cpu_ftrace.ftd_last
119*4df4bd60Sbs21162 *
120*4df4bd60Sbs21162 * Does _not_ protect reading of cpu[N]->cpu_ftrace.ftd_state
121*4df4bd60Sbs21162 * Does _not_ protect cpu[N]->cpu_ftrace.ftd_cur
122*4df4bd60Sbs21162 * Does _not_ protect reading of ftrace_state
1237c478bd9Sstevel@tonic-gate */
1247c478bd9Sstevel@tonic-gate static kmutex_t ftrace_lock;
1257c478bd9Sstevel@tonic-gate
1267c478bd9Sstevel@tonic-gate /*
1277c478bd9Sstevel@tonic-gate * Check whether a CPU is installed.
1287c478bd9Sstevel@tonic-gate */
1297c478bd9Sstevel@tonic-gate #define IS_CPU(i) (cpu[i] != NULL)
1307c478bd9Sstevel@tonic-gate
1317c478bd9Sstevel@tonic-gate static void
ftrace_cpu_init(int cpuid)1327c478bd9Sstevel@tonic-gate ftrace_cpu_init(int cpuid)
1337c478bd9Sstevel@tonic-gate {
1347c478bd9Sstevel@tonic-gate ftrace_data_t *ftd;
1357c478bd9Sstevel@tonic-gate
1367c478bd9Sstevel@tonic-gate /*
1377c478bd9Sstevel@tonic-gate * This can be called with "cpu[cpuid]->cpu_flags & CPU_EXISTS"
1387c478bd9Sstevel@tonic-gate * being false - e.g. when a CPU is DR'ed in.
1397c478bd9Sstevel@tonic-gate */
1407c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ftrace_lock));
1417c478bd9Sstevel@tonic-gate ASSERT(IS_CPU(cpuid));
1427c478bd9Sstevel@tonic-gate
1437c478bd9Sstevel@tonic-gate ftd = &cpu[cpuid]->cpu_ftrace;
1447c478bd9Sstevel@tonic-gate if (ftd->ftd_state & FTRACE_READY)
1457c478bd9Sstevel@tonic-gate return;
1467c478bd9Sstevel@tonic-gate
1477c478bd9Sstevel@tonic-gate /*
1487c478bd9Sstevel@tonic-gate * We don't allocate the buffers until the first time
1497c478bd9Sstevel@tonic-gate * ftrace_cpu_start() is called, so that they're not
1507c478bd9Sstevel@tonic-gate * allocated if ftrace is never enabled.
1517c478bd9Sstevel@tonic-gate */
1527c478bd9Sstevel@tonic-gate ftd->ftd_state |= FTRACE_READY;
1537c478bd9Sstevel@tonic-gate ASSERT(!(ftd->ftd_state & FTRACE_ENABLED));
1547c478bd9Sstevel@tonic-gate }
1557c478bd9Sstevel@tonic-gate
1567c478bd9Sstevel@tonic-gate /*
1577c478bd9Sstevel@tonic-gate * Only called from cpu_unconfigure() (and cpu_configure() on error).
1587c478bd9Sstevel@tonic-gate * At this point, cpu[cpuid] is about to be freed and NULLed out,
1597c478bd9Sstevel@tonic-gate * so we'd better clean up after ourselves.
1607c478bd9Sstevel@tonic-gate */
1617c478bd9Sstevel@tonic-gate static void
ftrace_cpu_fini(int cpuid)1627c478bd9Sstevel@tonic-gate ftrace_cpu_fini(int cpuid)
1637c478bd9Sstevel@tonic-gate {
1647c478bd9Sstevel@tonic-gate ftrace_data_t *ftd;
1657c478bd9Sstevel@tonic-gate
1667c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ftrace_lock));
1677c478bd9Sstevel@tonic-gate ASSERT(IS_CPU(cpuid));
1687c478bd9Sstevel@tonic-gate ASSERT((cpu[cpuid]->cpu_flags & CPU_POWEROFF) != 0);
1697c478bd9Sstevel@tonic-gate
1707c478bd9Sstevel@tonic-gate ftd = &cpu[cpuid]->cpu_ftrace;
1717c478bd9Sstevel@tonic-gate if (!(ftd->ftd_state & FTRACE_READY))
1727c478bd9Sstevel@tonic-gate return;
1737c478bd9Sstevel@tonic-gate
1747c478bd9Sstevel@tonic-gate /*
175*4df4bd60Sbs21162 * This cpu is powered off and no code can be executing on it. So
176*4df4bd60Sbs21162 * we can simply finish our cleanup. There is no need for a xcall
177*4df4bd60Sbs21162 * to make sure that this cpu is out of trace context.
178*4df4bd60Sbs21162 *
179*4df4bd60Sbs21162 * The cpu structure will be cleared soon. But, for the sake of
180*4df4bd60Sbs21162 * debugging, clear our pointers and state.
1817c478bd9Sstevel@tonic-gate */
182*4df4bd60Sbs21162 if (ftd->ftd_first != NULL) {
183*4df4bd60Sbs21162 kmem_free(ftd->ftd_first,
184*4df4bd60Sbs21162 ftrace_nent * sizeof (ftrace_record_t));
185*4df4bd60Sbs21162 }
186*4df4bd60Sbs21162 bzero(ftd, sizeof (ftrace_data_t));
1877c478bd9Sstevel@tonic-gate }
1887c478bd9Sstevel@tonic-gate
1897c478bd9Sstevel@tonic-gate static void
ftrace_cpu_start(int cpuid)1907c478bd9Sstevel@tonic-gate ftrace_cpu_start(int cpuid)
1917c478bd9Sstevel@tonic-gate {
1927c478bd9Sstevel@tonic-gate ftrace_data_t *ftd;
1937c478bd9Sstevel@tonic-gate
1947c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ftrace_lock));
1957c478bd9Sstevel@tonic-gate ASSERT(IS_CPU(cpuid));
1967c478bd9Sstevel@tonic-gate ASSERT(ftrace_state & FTRACE_ENABLED);
1977c478bd9Sstevel@tonic-gate
1987c478bd9Sstevel@tonic-gate ftd = &cpu[cpuid]->cpu_ftrace;
1997c478bd9Sstevel@tonic-gate if (ftd->ftd_state & FTRACE_READY) {
2007c478bd9Sstevel@tonic-gate if (ftd->ftd_first == NULL) {
2017c478bd9Sstevel@tonic-gate ftrace_record_t *ptrs;
2027c478bd9Sstevel@tonic-gate
2037c478bd9Sstevel@tonic-gate mutex_exit(&ftrace_lock);
2047c478bd9Sstevel@tonic-gate ptrs = kmem_zalloc(ftrace_nent *
2057c478bd9Sstevel@tonic-gate sizeof (ftrace_record_t), KM_SLEEP);
2067c478bd9Sstevel@tonic-gate mutex_enter(&ftrace_lock);
207*4df4bd60Sbs21162 if (ftd->ftd_first != NULL) {
208*4df4bd60Sbs21162 /*
209*4df4bd60Sbs21162 * Someone else beat us to it. The winner will
210*4df4bd60Sbs21162 * set up the pointers and the state.
211*4df4bd60Sbs21162 */
212*4df4bd60Sbs21162 kmem_free(ptrs,
213*4df4bd60Sbs21162 ftrace_nent * sizeof (ftrace_record_t));
214*4df4bd60Sbs21162 return;
215*4df4bd60Sbs21162 }
2167c478bd9Sstevel@tonic-gate
2177c478bd9Sstevel@tonic-gate ftd->ftd_first = ptrs;
2187c478bd9Sstevel@tonic-gate ftd->ftd_last = ptrs + (ftrace_nent - 1);
2197c478bd9Sstevel@tonic-gate ftd->ftd_cur = ptrs;
2207c478bd9Sstevel@tonic-gate membar_producer();
2217c478bd9Sstevel@tonic-gate }
2227c478bd9Sstevel@tonic-gate ftd->ftd_state |= FTRACE_ENABLED;
2237c478bd9Sstevel@tonic-gate }
2247c478bd9Sstevel@tonic-gate }
2257c478bd9Sstevel@tonic-gate
2267c478bd9Sstevel@tonic-gate static void
ftrace_cpu_stop(int cpuid)2277c478bd9Sstevel@tonic-gate ftrace_cpu_stop(int cpuid)
2287c478bd9Sstevel@tonic-gate {
2297c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ftrace_lock));
2307c478bd9Sstevel@tonic-gate ASSERT(IS_CPU(cpuid));
2317c478bd9Sstevel@tonic-gate cpu[cpuid]->cpu_ftrace.ftd_state &= ~(FTRACE_ENABLED);
2327c478bd9Sstevel@tonic-gate }
2337c478bd9Sstevel@tonic-gate
2347c478bd9Sstevel@tonic-gate /*
2357c478bd9Sstevel@tonic-gate * Hook for DR.
2367c478bd9Sstevel@tonic-gate */
2377c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2387c478bd9Sstevel@tonic-gate int
ftrace_cpu_setup(cpu_setup_t what,int id,void * arg)2397c478bd9Sstevel@tonic-gate ftrace_cpu_setup(cpu_setup_t what, int id, void *arg)
2407c478bd9Sstevel@tonic-gate {
2417c478bd9Sstevel@tonic-gate if (!(ftrace_state & FTRACE_READY))
2427c478bd9Sstevel@tonic-gate return (0);
2437c478bd9Sstevel@tonic-gate
2447c478bd9Sstevel@tonic-gate switch (what) {
2457c478bd9Sstevel@tonic-gate case CPU_CONFIG:
2467c478bd9Sstevel@tonic-gate mutex_enter(&ftrace_lock);
2477c478bd9Sstevel@tonic-gate ftrace_cpu_init(id);
2487c478bd9Sstevel@tonic-gate if (ftrace_state & FTRACE_ENABLED)
2497c478bd9Sstevel@tonic-gate ftrace_cpu_start(id);
2507c478bd9Sstevel@tonic-gate mutex_exit(&ftrace_lock);
2517c478bd9Sstevel@tonic-gate break;
2527c478bd9Sstevel@tonic-gate
2537c478bd9Sstevel@tonic-gate case CPU_UNCONFIG:
2547c478bd9Sstevel@tonic-gate mutex_enter(&ftrace_lock);
2557c478bd9Sstevel@tonic-gate ftrace_cpu_fini(id);
2567c478bd9Sstevel@tonic-gate mutex_exit(&ftrace_lock);
2577c478bd9Sstevel@tonic-gate break;
2587c478bd9Sstevel@tonic-gate
2597c478bd9Sstevel@tonic-gate default:
2607c478bd9Sstevel@tonic-gate break;
2617c478bd9Sstevel@tonic-gate }
2627c478bd9Sstevel@tonic-gate return (0);
2637c478bd9Sstevel@tonic-gate }
2647c478bd9Sstevel@tonic-gate
2657c478bd9Sstevel@tonic-gate void
ftrace_init(void)2667c478bd9Sstevel@tonic-gate ftrace_init(void)
2677c478bd9Sstevel@tonic-gate {
2687c478bd9Sstevel@tonic-gate int i;
2697c478bd9Sstevel@tonic-gate
2707c478bd9Sstevel@tonic-gate ASSERT(!(ftrace_state & FTRACE_READY));
2717c478bd9Sstevel@tonic-gate mutex_init(&ftrace_lock, NULL, MUTEX_DEFAULT, NULL);
2727c478bd9Sstevel@tonic-gate
2737c478bd9Sstevel@tonic-gate mutex_enter(&ftrace_lock);
2747c478bd9Sstevel@tonic-gate for (i = 0; i < NCPU; i++) {
2757c478bd9Sstevel@tonic-gate if (IS_CPU(i)) {
2767c478bd9Sstevel@tonic-gate /* should have been kmem_zalloc()'ed */
2777c478bd9Sstevel@tonic-gate ASSERT(cpu[i]->cpu_ftrace.ftd_state == 0);
2787c478bd9Sstevel@tonic-gate ASSERT(cpu[i]->cpu_ftrace.ftd_first == NULL);
2797c478bd9Sstevel@tonic-gate ASSERT(cpu[i]->cpu_ftrace.ftd_last == NULL);
2807c478bd9Sstevel@tonic-gate ASSERT(cpu[i]->cpu_ftrace.ftd_cur == NULL);
2817c478bd9Sstevel@tonic-gate }
2827c478bd9Sstevel@tonic-gate }
2837c478bd9Sstevel@tonic-gate
2847c478bd9Sstevel@tonic-gate if (ftrace_nent < 1) {
2857c478bd9Sstevel@tonic-gate mutex_exit(&ftrace_lock);
2867c478bd9Sstevel@tonic-gate return;
2877c478bd9Sstevel@tonic-gate }
2887c478bd9Sstevel@tonic-gate
2897c478bd9Sstevel@tonic-gate for (i = 0; i < NCPU; i++)
2907c478bd9Sstevel@tonic-gate if (IS_CPU(i))
2917c478bd9Sstevel@tonic-gate ftrace_cpu_init(i);
2927c478bd9Sstevel@tonic-gate
2937c478bd9Sstevel@tonic-gate ftrace_state |= FTRACE_READY;
2947c478bd9Sstevel@tonic-gate mutex_enter(&cpu_lock);
2957c478bd9Sstevel@tonic-gate register_cpu_setup_func(ftrace_cpu_setup, NULL);
2967c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock);
2977c478bd9Sstevel@tonic-gate mutex_exit(&ftrace_lock);
2987c478bd9Sstevel@tonic-gate
2997c478bd9Sstevel@tonic-gate if (ftrace_atboot)
3007c478bd9Sstevel@tonic-gate (void) ftrace_start();
3017c478bd9Sstevel@tonic-gate }
3027c478bd9Sstevel@tonic-gate
303*4df4bd60Sbs21162 /*
304*4df4bd60Sbs21162 * Called from uadmin ioctl, or via mp_init_table[] during boot.
305*4df4bd60Sbs21162 */
3067c478bd9Sstevel@tonic-gate int
ftrace_start(void)3077c478bd9Sstevel@tonic-gate ftrace_start(void)
3087c478bd9Sstevel@tonic-gate {
3097c478bd9Sstevel@tonic-gate int i, was_enabled = 0;
3107c478bd9Sstevel@tonic-gate
3117c478bd9Sstevel@tonic-gate if (ftrace_state & FTRACE_READY) {
3127c478bd9Sstevel@tonic-gate mutex_enter(&ftrace_lock);
3137c478bd9Sstevel@tonic-gate was_enabled = ((ftrace_state & FTRACE_ENABLED) != 0);
3147c478bd9Sstevel@tonic-gate ftrace_state |= FTRACE_ENABLED;
3157c478bd9Sstevel@tonic-gate for (i = 0; i < NCPU; i++)
3167c478bd9Sstevel@tonic-gate if (IS_CPU(i))
3177c478bd9Sstevel@tonic-gate ftrace_cpu_start(i);
3187c478bd9Sstevel@tonic-gate mutex_exit(&ftrace_lock);
3197c478bd9Sstevel@tonic-gate }
3207c478bd9Sstevel@tonic-gate
3217c478bd9Sstevel@tonic-gate return (was_enabled);
3227c478bd9Sstevel@tonic-gate }
3237c478bd9Sstevel@tonic-gate
324*4df4bd60Sbs21162 /*
325*4df4bd60Sbs21162 * Called from uadmin ioctl, to stop tracing.
326*4df4bd60Sbs21162 */
3277c478bd9Sstevel@tonic-gate int
ftrace_stop(void)3287c478bd9Sstevel@tonic-gate ftrace_stop(void)
3297c478bd9Sstevel@tonic-gate {
3307c478bd9Sstevel@tonic-gate int i, was_enabled = 0;
3317c478bd9Sstevel@tonic-gate
3327c478bd9Sstevel@tonic-gate if (ftrace_state & FTRACE_READY) {
3337c478bd9Sstevel@tonic-gate mutex_enter(&ftrace_lock);
3347c478bd9Sstevel@tonic-gate if (ftrace_state & FTRACE_ENABLED) {
3357c478bd9Sstevel@tonic-gate was_enabled = 1;
3367c478bd9Sstevel@tonic-gate for (i = 0; i < NCPU; i++)
3377c478bd9Sstevel@tonic-gate if (IS_CPU(i))
3387c478bd9Sstevel@tonic-gate ftrace_cpu_stop(i);
3397c478bd9Sstevel@tonic-gate ftrace_state &= ~(FTRACE_ENABLED);
3407c478bd9Sstevel@tonic-gate }
3417c478bd9Sstevel@tonic-gate mutex_exit(&ftrace_lock);
3427c478bd9Sstevel@tonic-gate }
3437c478bd9Sstevel@tonic-gate return (was_enabled);
3447c478bd9Sstevel@tonic-gate }
3457c478bd9Sstevel@tonic-gate
346*4df4bd60Sbs21162 /*
347*4df4bd60Sbs21162 * ftrace_X() functions are called from trace context. All callers of ftrace_X()
348*4df4bd60Sbs21162 * tests FTRACE_ENABLED first. Although this is not very accurate, it keeps the
349*4df4bd60Sbs21162 * overhead very low when tracing is not enabled.
350*4df4bd60Sbs21162 *
351*4df4bd60Sbs21162 * gethrtime_unscaled() appears to be safe to be called in trace context. As an
352*4df4bd60Sbs21162 * added precaution, we call these before we disable interrupts on this cpu.
353*4df4bd60Sbs21162 */
354*4df4bd60Sbs21162
3557c478bd9Sstevel@tonic-gate void
ftrace_0(char * str,caddr_t caller)356*4df4bd60Sbs21162 ftrace_0(char *str, caddr_t caller)
3577c478bd9Sstevel@tonic-gate {
3587c478bd9Sstevel@tonic-gate ftrace_record_t *r;
359*4df4bd60Sbs21162 struct cpu *cp;
360*4df4bd60Sbs21162 ftrace_data_t *ftd;
361*4df4bd60Sbs21162 ftrace_icookie_t cookie;
362*4df4bd60Sbs21162 hrtime_t timestamp;
3637c478bd9Sstevel@tonic-gate
364*4df4bd60Sbs21162 timestamp = gethrtime_unscaled();
365*4df4bd60Sbs21162
366*4df4bd60Sbs21162 cookie = ftrace_interrupt_disable();
367*4df4bd60Sbs21162
368*4df4bd60Sbs21162 cp = CPU;
369*4df4bd60Sbs21162 ftd = &cp->cpu_ftrace;
370*4df4bd60Sbs21162
371*4df4bd60Sbs21162 if (!(ftd->ftd_state & FTRACE_ENABLED)) {
372*4df4bd60Sbs21162 ftrace_interrupt_enable(cookie);
3737c478bd9Sstevel@tonic-gate return;
3747c478bd9Sstevel@tonic-gate }
375*4df4bd60Sbs21162
3767c478bd9Sstevel@tonic-gate r = ftd->ftd_cur;
3777c478bd9Sstevel@tonic-gate r->ftr_event = str;
3787c478bd9Sstevel@tonic-gate r->ftr_thread = curthread;
379*4df4bd60Sbs21162 r->ftr_tick = timestamp;
380*4df4bd60Sbs21162 r->ftr_caller = caller;
3817c478bd9Sstevel@tonic-gate
3827c478bd9Sstevel@tonic-gate if (r++ == ftd->ftd_last)
3837c478bd9Sstevel@tonic-gate r = ftd->ftd_first;
3847c478bd9Sstevel@tonic-gate ftd->ftd_cur = r;
385*4df4bd60Sbs21162
386*4df4bd60Sbs21162 ftrace_interrupt_enable(cookie);
3877c478bd9Sstevel@tonic-gate }
3887c478bd9Sstevel@tonic-gate
3897c478bd9Sstevel@tonic-gate void
ftrace_1(char * str,ulong_t arg1,caddr_t caller)390*4df4bd60Sbs21162 ftrace_1(char *str, ulong_t arg1, caddr_t caller)
3917c478bd9Sstevel@tonic-gate {
3927c478bd9Sstevel@tonic-gate ftrace_record_t *r;
393*4df4bd60Sbs21162 struct cpu *cp;
394*4df4bd60Sbs21162 ftrace_data_t *ftd;
395*4df4bd60Sbs21162 ftrace_icookie_t cookie;
396*4df4bd60Sbs21162 hrtime_t timestamp;
3977c478bd9Sstevel@tonic-gate
398*4df4bd60Sbs21162 timestamp = gethrtime_unscaled();
399*4df4bd60Sbs21162
400*4df4bd60Sbs21162 cookie = ftrace_interrupt_disable();
401*4df4bd60Sbs21162
402*4df4bd60Sbs21162 cp = CPU;
403*4df4bd60Sbs21162 ftd = &cp->cpu_ftrace;
404*4df4bd60Sbs21162
405*4df4bd60Sbs21162 if (!(ftd->ftd_state & FTRACE_ENABLED)) {
406*4df4bd60Sbs21162 ftrace_interrupt_enable(cookie);
4077c478bd9Sstevel@tonic-gate return;
4087c478bd9Sstevel@tonic-gate }
409*4df4bd60Sbs21162
4107c478bd9Sstevel@tonic-gate r = ftd->ftd_cur;
4117c478bd9Sstevel@tonic-gate r->ftr_event = str;
4127c478bd9Sstevel@tonic-gate r->ftr_thread = curthread;
413*4df4bd60Sbs21162 r->ftr_tick = timestamp;
414*4df4bd60Sbs21162 r->ftr_caller = caller;
4157c478bd9Sstevel@tonic-gate r->ftr_data1 = arg1;
4167c478bd9Sstevel@tonic-gate
4177c478bd9Sstevel@tonic-gate if (r++ == ftd->ftd_last)
4187c478bd9Sstevel@tonic-gate r = ftd->ftd_first;
4197c478bd9Sstevel@tonic-gate ftd->ftd_cur = r;
420*4df4bd60Sbs21162
421*4df4bd60Sbs21162 ftrace_interrupt_enable(cookie);
4227c478bd9Sstevel@tonic-gate }
4237c478bd9Sstevel@tonic-gate
4247c478bd9Sstevel@tonic-gate void
ftrace_2(char * str,ulong_t arg1,ulong_t arg2,caddr_t caller)425*4df4bd60Sbs21162 ftrace_2(char *str, ulong_t arg1, ulong_t arg2, caddr_t caller)
4267c478bd9Sstevel@tonic-gate {
4277c478bd9Sstevel@tonic-gate ftrace_record_t *r;
428*4df4bd60Sbs21162 struct cpu *cp;
429*4df4bd60Sbs21162 ftrace_data_t *ftd;
430*4df4bd60Sbs21162 ftrace_icookie_t cookie;
431*4df4bd60Sbs21162 hrtime_t timestamp;
4327c478bd9Sstevel@tonic-gate
433*4df4bd60Sbs21162 timestamp = gethrtime_unscaled();
434*4df4bd60Sbs21162
435*4df4bd60Sbs21162 cookie = ftrace_interrupt_disable();
436*4df4bd60Sbs21162
437*4df4bd60Sbs21162 cp = CPU;
438*4df4bd60Sbs21162 ftd = &cp->cpu_ftrace;
439*4df4bd60Sbs21162
440*4df4bd60Sbs21162 if (!(ftd->ftd_state & FTRACE_ENABLED)) {
441*4df4bd60Sbs21162 ftrace_interrupt_enable(cookie);
4427c478bd9Sstevel@tonic-gate return;
4437c478bd9Sstevel@tonic-gate }
444*4df4bd60Sbs21162
4457c478bd9Sstevel@tonic-gate r = ftd->ftd_cur;
4467c478bd9Sstevel@tonic-gate r->ftr_event = str;
4477c478bd9Sstevel@tonic-gate r->ftr_thread = curthread;
448*4df4bd60Sbs21162 r->ftr_tick = timestamp;
449*4df4bd60Sbs21162 r->ftr_caller = caller;
4507c478bd9Sstevel@tonic-gate r->ftr_data1 = arg1;
4517c478bd9Sstevel@tonic-gate r->ftr_data2 = arg2;
4527c478bd9Sstevel@tonic-gate
4537c478bd9Sstevel@tonic-gate if (r++ == ftd->ftd_last)
4547c478bd9Sstevel@tonic-gate r = ftd->ftd_first;
4557c478bd9Sstevel@tonic-gate ftd->ftd_cur = r;
456*4df4bd60Sbs21162
457*4df4bd60Sbs21162 ftrace_interrupt_enable(cookie);
4587c478bd9Sstevel@tonic-gate }
4597c478bd9Sstevel@tonic-gate
4607c478bd9Sstevel@tonic-gate void
ftrace_3(char * str,ulong_t arg1,ulong_t arg2,ulong_t arg3,caddr_t caller)461*4df4bd60Sbs21162 ftrace_3(char *str, ulong_t arg1, ulong_t arg2, ulong_t arg3, caddr_t caller)
4627c478bd9Sstevel@tonic-gate {
4637c478bd9Sstevel@tonic-gate ftrace_record_t *r;
464*4df4bd60Sbs21162 struct cpu *cp;
465*4df4bd60Sbs21162 ftrace_data_t *ftd;
466*4df4bd60Sbs21162 ftrace_icookie_t cookie;
467*4df4bd60Sbs21162 hrtime_t timestamp;
4687c478bd9Sstevel@tonic-gate
469*4df4bd60Sbs21162 timestamp = gethrtime_unscaled();
470*4df4bd60Sbs21162
471*4df4bd60Sbs21162 cookie = ftrace_interrupt_disable();
472*4df4bd60Sbs21162
473*4df4bd60Sbs21162 cp = CPU;
474*4df4bd60Sbs21162 ftd = &cp->cpu_ftrace;
475*4df4bd60Sbs21162
476*4df4bd60Sbs21162 if (!(ftd->ftd_state & FTRACE_ENABLED)) {
477*4df4bd60Sbs21162 ftrace_interrupt_enable(cookie);
4787c478bd9Sstevel@tonic-gate return;
4797c478bd9Sstevel@tonic-gate }
480*4df4bd60Sbs21162
4817c478bd9Sstevel@tonic-gate r = ftd->ftd_cur;
4827c478bd9Sstevel@tonic-gate r->ftr_event = str;
4837c478bd9Sstevel@tonic-gate r->ftr_thread = curthread;
484*4df4bd60Sbs21162 r->ftr_tick = timestamp;
485*4df4bd60Sbs21162 r->ftr_caller = caller;
4867c478bd9Sstevel@tonic-gate r->ftr_data1 = arg1;
4877c478bd9Sstevel@tonic-gate r->ftr_data2 = arg2;
4887c478bd9Sstevel@tonic-gate r->ftr_data3 = arg3;
4897c478bd9Sstevel@tonic-gate
4907c478bd9Sstevel@tonic-gate if (r++ == ftd->ftd_last)
4917c478bd9Sstevel@tonic-gate r = ftd->ftd_first;
4927c478bd9Sstevel@tonic-gate ftd->ftd_cur = r;
493*4df4bd60Sbs21162
494*4df4bd60Sbs21162 ftrace_interrupt_enable(cookie);
4957c478bd9Sstevel@tonic-gate }
4967c478bd9Sstevel@tonic-gate
4977c478bd9Sstevel@tonic-gate void
ftrace_3_notick(char * str,ulong_t arg1,ulong_t arg2,ulong_t arg3,caddr_t caller)498*4df4bd60Sbs21162 ftrace_3_notick(char *str, ulong_t arg1, ulong_t arg2,
499*4df4bd60Sbs21162 ulong_t arg3, caddr_t caller)
5007c478bd9Sstevel@tonic-gate {
5017c478bd9Sstevel@tonic-gate ftrace_record_t *r;
502*4df4bd60Sbs21162 struct cpu *cp;
503*4df4bd60Sbs21162 ftrace_data_t *ftd;
504*4df4bd60Sbs21162 ftrace_icookie_t cookie;
5057c478bd9Sstevel@tonic-gate
506*4df4bd60Sbs21162 cookie = ftrace_interrupt_disable();
507*4df4bd60Sbs21162
508*4df4bd60Sbs21162 cp = CPU;
509*4df4bd60Sbs21162 ftd = &cp->cpu_ftrace;
510*4df4bd60Sbs21162
511*4df4bd60Sbs21162 if (!(ftd->ftd_state & FTRACE_ENABLED)) {
512*4df4bd60Sbs21162 ftrace_interrupt_enable(cookie);
5137c478bd9Sstevel@tonic-gate return;
5147c478bd9Sstevel@tonic-gate }
515*4df4bd60Sbs21162
5167c478bd9Sstevel@tonic-gate r = ftd->ftd_cur;
5177c478bd9Sstevel@tonic-gate r->ftr_event = str;
5187c478bd9Sstevel@tonic-gate r->ftr_thread = curthread;
5197c478bd9Sstevel@tonic-gate r->ftr_tick = 0;
520*4df4bd60Sbs21162 r->ftr_caller = caller;
5217c478bd9Sstevel@tonic-gate r->ftr_data1 = arg1;
5227c478bd9Sstevel@tonic-gate r->ftr_data2 = arg2;
5237c478bd9Sstevel@tonic-gate r->ftr_data3 = arg3;
5247c478bd9Sstevel@tonic-gate
5257c478bd9Sstevel@tonic-gate if (r++ == ftd->ftd_last)
5267c478bd9Sstevel@tonic-gate r = ftd->ftd_first;
5277c478bd9Sstevel@tonic-gate ftd->ftd_cur = r;
528*4df4bd60Sbs21162
529*4df4bd60Sbs21162 ftrace_interrupt_enable(cookie);
5307c478bd9Sstevel@tonic-gate }
531