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 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 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 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 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 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 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 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 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 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 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 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 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 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