1*b9e93c10SJonathan Haslam /* 2*b9e93c10SJonathan Haslam * CDDL HEADER START 3*b9e93c10SJonathan Haslam * 4*b9e93c10SJonathan Haslam * The contents of this file are subject to the terms of the 5*b9e93c10SJonathan Haslam * Common Development and Distribution License (the "License"). 6*b9e93c10SJonathan Haslam * You may not use this file except in compliance with the License. 7*b9e93c10SJonathan Haslam * 8*b9e93c10SJonathan Haslam * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*b9e93c10SJonathan Haslam * or http://www.opensolaris.org/os/licensing. 10*b9e93c10SJonathan Haslam * See the License for the specific language governing permissions 11*b9e93c10SJonathan Haslam * and limitations under the License. 12*b9e93c10SJonathan Haslam * 13*b9e93c10SJonathan Haslam * When distributing Covered Code, include this CDDL HEADER in each 14*b9e93c10SJonathan Haslam * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*b9e93c10SJonathan Haslam * If applicable, add the following below this CDDL HEADER, with the 16*b9e93c10SJonathan Haslam * fields enclosed by brackets "[]" replaced with your own identifying 17*b9e93c10SJonathan Haslam * information: Portions Copyright [yyyy] [name of copyright owner] 18*b9e93c10SJonathan Haslam * 19*b9e93c10SJonathan Haslam * CDDL HEADER END 20*b9e93c10SJonathan Haslam */ 21*b9e93c10SJonathan Haslam 22*b9e93c10SJonathan Haslam /* 23*b9e93c10SJonathan Haslam * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24*b9e93c10SJonathan Haslam * Use is subject to license terms. 25*b9e93c10SJonathan Haslam */ 26*b9e93c10SJonathan Haslam 27*b9e93c10SJonathan Haslam #include <sys/errno.h> 28*b9e93c10SJonathan Haslam #include <sys/cpuvar.h> 29*b9e93c10SJonathan Haslam #include <sys/stat.h> 30*b9e93c10SJonathan Haslam #include <sys/modctl.h> 31*b9e93c10SJonathan Haslam #include <sys/cmn_err.h> 32*b9e93c10SJonathan Haslam #include <sys/ddi.h> 33*b9e93c10SJonathan Haslam #include <sys/sunddi.h> 34*b9e93c10SJonathan Haslam #include <sys/ksynch.h> 35*b9e93c10SJonathan Haslam #include <sys/conf.h> 36*b9e93c10SJonathan Haslam #include <sys/kmem.h> 37*b9e93c10SJonathan Haslam #include <sys/kcpc.h> 38*b9e93c10SJonathan Haslam #include <sys/cpc_pcbe.h> 39*b9e93c10SJonathan Haslam #include <sys/cpc_impl.h> 40*b9e93c10SJonathan Haslam #include <sys/dtrace_impl.h> 41*b9e93c10SJonathan Haslam 42*b9e93c10SJonathan Haslam /* 43*b9e93c10SJonathan Haslam * DTrace CPU Performance Counter Provider 44*b9e93c10SJonathan Haslam * --------------------------------------- 45*b9e93c10SJonathan Haslam * 46*b9e93c10SJonathan Haslam * The DTrace cpc provider allows DTrace consumers to access the CPU 47*b9e93c10SJonathan Haslam * performance counter overflow mechanism of a CPU. The configuration 48*b9e93c10SJonathan Haslam * presented in a probe specification is programmed into the performance 49*b9e93c10SJonathan Haslam * counter hardware of all available CPUs on a system. Programming the 50*b9e93c10SJonathan Haslam * hardware causes a counter on each CPU to begin counting events of the 51*b9e93c10SJonathan Haslam * given type. When the specified number of events have occurred, an overflow 52*b9e93c10SJonathan Haslam * interrupt will be generated and the probe is fired. 53*b9e93c10SJonathan Haslam * 54*b9e93c10SJonathan Haslam * The required configuration for the performance counter is encoded into 55*b9e93c10SJonathan Haslam * the probe specification and this includes the performance counter event 56*b9e93c10SJonathan Haslam * name, processor mode, overflow rate and an optional unit mask. 57*b9e93c10SJonathan Haslam * 58*b9e93c10SJonathan Haslam * Most processors provide several counters (PICs) which can count all or a 59*b9e93c10SJonathan Haslam * subset of the events available for a given CPU. However, when overflow 60*b9e93c10SJonathan Haslam * profiling is being used, not all CPUs can detect which counter generated the 61*b9e93c10SJonathan Haslam * overflow interrupt. In this case we cannot reliably determine which counter 62*b9e93c10SJonathan Haslam * overflowed and we therefore only allow such CPUs to configure one event at 63*b9e93c10SJonathan Haslam * a time. Processors that can determine the counter which overflowed are 64*b9e93c10SJonathan Haslam * allowed to program as many events at one time as possible (in theory up to 65*b9e93c10SJonathan Haslam * the number of instrumentation counters supported by that platform). 66*b9e93c10SJonathan Haslam * Therefore, multiple consumers can enable multiple probes at the same time 67*b9e93c10SJonathan Haslam * on such platforms. Platforms which cannot determine the source of an 68*b9e93c10SJonathan Haslam * overflow interrupt are only allowed to program a single event at one time. 69*b9e93c10SJonathan Haslam * 70*b9e93c10SJonathan Haslam * The performance counter hardware is made available to consumers on a 71*b9e93c10SJonathan Haslam * first-come, first-served basis. Only a finite amount of hardware resource 72*b9e93c10SJonathan Haslam * is available and, while we make every attempt to accomodate requests from 73*b9e93c10SJonathan Haslam * consumers, we must deny requests when hardware resources have been exhausted. 74*b9e93c10SJonathan Haslam * A consumer will fail to enable probes when resources are currently in use. 75*b9e93c10SJonathan Haslam * 76*b9e93c10SJonathan Haslam * The cpc provider contends for shared hardware resources along with other 77*b9e93c10SJonathan Haslam * consumers of the kernel CPU performance counter subsystem (e.g. cpustat(1M)). 78*b9e93c10SJonathan Haslam * Only one such consumer can use the performance counters at any one time and 79*b9e93c10SJonathan Haslam * counters are made available on a first-come, first-served basis. As with 80*b9e93c10SJonathan Haslam * cpustat, the cpc provider has priority over per-LWP libcpc usage (e.g. 81*b9e93c10SJonathan Haslam * cputrack(1)). Invoking the cpc provider will cause all existing per-LWP 82*b9e93c10SJonathan Haslam * counter contexts to be invalidated. 83*b9e93c10SJonathan Haslam */ 84*b9e93c10SJonathan Haslam 85*b9e93c10SJonathan Haslam typedef struct dcpc_probe { 86*b9e93c10SJonathan Haslam char dcpc_event_name[CPC_MAX_EVENT_LEN]; 87*b9e93c10SJonathan Haslam int dcpc_flag; /* flags (USER/SYS) */ 88*b9e93c10SJonathan Haslam uint32_t dcpc_ovfval; /* overflow value */ 89*b9e93c10SJonathan Haslam int64_t dcpc_umask; /* umask/emask for this event */ 90*b9e93c10SJonathan Haslam int dcpc_picno; /* pic this event is programmed in */ 91*b9e93c10SJonathan Haslam int dcpc_enabled; /* probe is actually enabled? */ 92*b9e93c10SJonathan Haslam int dcpc_disabling; /* probe is currently being disabled */ 93*b9e93c10SJonathan Haslam dtrace_id_t dcpc_id; /* probeid this request is enabling */ 94*b9e93c10SJonathan Haslam int dcpc_actv_req_idx; /* idx into dcpc_actv_reqs[] */ 95*b9e93c10SJonathan Haslam } dcpc_probe_t; 96*b9e93c10SJonathan Haslam 97*b9e93c10SJonathan Haslam static dev_info_t *dcpc_devi; 98*b9e93c10SJonathan Haslam static dtrace_provider_id_t dcpc_pid; 99*b9e93c10SJonathan Haslam static dcpc_probe_t **dcpc_actv_reqs; 100*b9e93c10SJonathan Haslam static uint32_t dcpc_enablings = 0; 101*b9e93c10SJonathan Haslam static int dcpc_ovf_mask = 0; 102*b9e93c10SJonathan Haslam static int dcpc_mult_ovf_cap = 0; 103*b9e93c10SJonathan Haslam static int dcpc_mask_type = 0; 104*b9e93c10SJonathan Haslam 105*b9e93c10SJonathan Haslam /* 106*b9e93c10SJonathan Haslam * When the dcpc provider is loaded, dcpc_min_overflow is set to either 107*b9e93c10SJonathan Haslam * DCPC_MIN_OVF_DEFAULT or the value that dcpc-min-overflow is set to in 108*b9e93c10SJonathan Haslam * the dcpc.conf file. Decrease this value to set probes with smaller 109*b9e93c10SJonathan Haslam * overflow values. Remember that very small values could render a system 110*b9e93c10SJonathan Haslam * unusable with frequently occurring events. 111*b9e93c10SJonathan Haslam */ 112*b9e93c10SJonathan Haslam #define DCPC_MIN_OVF_DEFAULT 5000 113*b9e93c10SJonathan Haslam static uint32_t dcpc_min_overflow; 114*b9e93c10SJonathan Haslam 115*b9e93c10SJonathan Haslam static int dcpc_aframes = 0; /* override for artificial frame setting */ 116*b9e93c10SJonathan Haslam #if defined(__x86) 117*b9e93c10SJonathan Haslam #define DCPC_ARTIFICIAL_FRAMES 8 118*b9e93c10SJonathan Haslam #elif defined(__sparc) 119*b9e93c10SJonathan Haslam #define DCPC_ARTIFICIAL_FRAMES 2 120*b9e93c10SJonathan Haslam #endif 121*b9e93c10SJonathan Haslam 122*b9e93c10SJonathan Haslam /* 123*b9e93c10SJonathan Haslam * Called from the platform overflow interrupt handler. 'bitmap' is a mask 124*b9e93c10SJonathan Haslam * which contains the pic(s) that have overflowed. 125*b9e93c10SJonathan Haslam */ 126*b9e93c10SJonathan Haslam static void 127*b9e93c10SJonathan Haslam dcpc_fire(uint64_t bitmap) 128*b9e93c10SJonathan Haslam { 129*b9e93c10SJonathan Haslam int i; 130*b9e93c10SJonathan Haslam 131*b9e93c10SJonathan Haslam /* 132*b9e93c10SJonathan Haslam * No counter was marked as overflowing. Shout about it and get out. 133*b9e93c10SJonathan Haslam */ 134*b9e93c10SJonathan Haslam if ((bitmap & dcpc_ovf_mask) == 0) { 135*b9e93c10SJonathan Haslam cmn_err(CE_NOTE, "dcpc_fire: no counter overflow found\n"); 136*b9e93c10SJonathan Haslam return; 137*b9e93c10SJonathan Haslam } 138*b9e93c10SJonathan Haslam 139*b9e93c10SJonathan Haslam /* 140*b9e93c10SJonathan Haslam * This is the common case of a processor that doesn't support 141*b9e93c10SJonathan Haslam * multiple overflow events. Such systems are only allowed a single 142*b9e93c10SJonathan Haslam * enabling and therefore we just look for the first entry in 143*b9e93c10SJonathan Haslam * the active request array. 144*b9e93c10SJonathan Haslam */ 145*b9e93c10SJonathan Haslam if (!dcpc_mult_ovf_cap) { 146*b9e93c10SJonathan Haslam for (i = 0; i < cpc_ncounters; i++) { 147*b9e93c10SJonathan Haslam if (dcpc_actv_reqs[i] != NULL) { 148*b9e93c10SJonathan Haslam dtrace_probe(dcpc_actv_reqs[i]->dcpc_id, 149*b9e93c10SJonathan Haslam CPU->cpu_cpcprofile_pc, 150*b9e93c10SJonathan Haslam CPU->cpu_cpcprofile_upc, 0, 0, 0); 151*b9e93c10SJonathan Haslam return; 152*b9e93c10SJonathan Haslam } 153*b9e93c10SJonathan Haslam } 154*b9e93c10SJonathan Haslam return; 155*b9e93c10SJonathan Haslam } 156*b9e93c10SJonathan Haslam 157*b9e93c10SJonathan Haslam /* 158*b9e93c10SJonathan Haslam * This is a processor capable of handling multiple overflow events. 159*b9e93c10SJonathan Haslam * Iterate over the array of active requests and locate the counters 160*b9e93c10SJonathan Haslam * that overflowed (note: it is possible for more than one counter to 161*b9e93c10SJonathan Haslam * have overflowed at the same time). 162*b9e93c10SJonathan Haslam */ 163*b9e93c10SJonathan Haslam for (i = 0; i < cpc_ncounters; i++) { 164*b9e93c10SJonathan Haslam if (dcpc_actv_reqs[i] != NULL && 165*b9e93c10SJonathan Haslam (bitmap & (1ULL << dcpc_actv_reqs[i]->dcpc_picno))) { 166*b9e93c10SJonathan Haslam dtrace_probe(dcpc_actv_reqs[i]->dcpc_id, 167*b9e93c10SJonathan Haslam CPU->cpu_cpcprofile_pc, 168*b9e93c10SJonathan Haslam CPU->cpu_cpcprofile_upc, 0, 0, 0); 169*b9e93c10SJonathan Haslam } 170*b9e93c10SJonathan Haslam } 171*b9e93c10SJonathan Haslam } 172*b9e93c10SJonathan Haslam 173*b9e93c10SJonathan Haslam static void 174*b9e93c10SJonathan Haslam dcpc_create_probe(dtrace_provider_id_t id, const char *probename, 175*b9e93c10SJonathan Haslam char *eventname, int64_t umask, uint32_t ovfval, char flag) 176*b9e93c10SJonathan Haslam { 177*b9e93c10SJonathan Haslam dcpc_probe_t *pp; 178*b9e93c10SJonathan Haslam int nr_frames = DCPC_ARTIFICIAL_FRAMES + dtrace_mach_aframes(); 179*b9e93c10SJonathan Haslam 180*b9e93c10SJonathan Haslam if (dcpc_aframes) 181*b9e93c10SJonathan Haslam nr_frames = dcpc_aframes; 182*b9e93c10SJonathan Haslam 183*b9e93c10SJonathan Haslam if (dtrace_probe_lookup(id, NULL, NULL, probename) != 0) 184*b9e93c10SJonathan Haslam return; 185*b9e93c10SJonathan Haslam 186*b9e93c10SJonathan Haslam pp = kmem_zalloc(sizeof (dcpc_probe_t), KM_SLEEP); 187*b9e93c10SJonathan Haslam (void) strncpy(pp->dcpc_event_name, eventname, 188*b9e93c10SJonathan Haslam sizeof (pp->dcpc_event_name) - 1); 189*b9e93c10SJonathan Haslam pp->dcpc_event_name[sizeof (pp->dcpc_event_name) - 1] = '\0'; 190*b9e93c10SJonathan Haslam pp->dcpc_flag = flag | CPC_OVF_NOTIFY_EMT; 191*b9e93c10SJonathan Haslam pp->dcpc_ovfval = ovfval; 192*b9e93c10SJonathan Haslam pp->dcpc_umask = umask; 193*b9e93c10SJonathan Haslam pp->dcpc_actv_req_idx = pp->dcpc_picno = pp->dcpc_disabling = -1; 194*b9e93c10SJonathan Haslam 195*b9e93c10SJonathan Haslam pp->dcpc_id = dtrace_probe_create(id, NULL, NULL, probename, 196*b9e93c10SJonathan Haslam nr_frames, pp); 197*b9e93c10SJonathan Haslam } 198*b9e93c10SJonathan Haslam 199*b9e93c10SJonathan Haslam /*ARGSUSED*/ 200*b9e93c10SJonathan Haslam static void 201*b9e93c10SJonathan Haslam dcpc_provide(void *arg, const dtrace_probedesc_t *desc) 202*b9e93c10SJonathan Haslam { 203*b9e93c10SJonathan Haslam /* 204*b9e93c10SJonathan Haslam * The format of a probe is: 205*b9e93c10SJonathan Haslam * 206*b9e93c10SJonathan Haslam * event_name-mode-{optional_umask}-overflow_rate 207*b9e93c10SJonathan Haslam * e.g. 208*b9e93c10SJonathan Haslam * DC_refill_from_system-user-0x1e-50000, or, 209*b9e93c10SJonathan Haslam * DC_refill_from_system-all-10000 210*b9e93c10SJonathan Haslam * 211*b9e93c10SJonathan Haslam */ 212*b9e93c10SJonathan Haslam char *str, *end, *p; 213*b9e93c10SJonathan Haslam int i, flag = 0; 214*b9e93c10SJonathan Haslam char event[CPC_MAX_EVENT_LEN]; 215*b9e93c10SJonathan Haslam long umask = -1, val = 0; 216*b9e93c10SJonathan Haslam size_t evlen, len; 217*b9e93c10SJonathan Haslam 218*b9e93c10SJonathan Haslam /* 219*b9e93c10SJonathan Haslam * The 'cpc' provider offers no probes by default. 220*b9e93c10SJonathan Haslam */ 221*b9e93c10SJonathan Haslam if (desc == NULL) 222*b9e93c10SJonathan Haslam return; 223*b9e93c10SJonathan Haslam 224*b9e93c10SJonathan Haslam len = strlen(desc->dtpd_name); 225*b9e93c10SJonathan Haslam p = str = kmem_alloc(len + 1, KM_SLEEP); 226*b9e93c10SJonathan Haslam (void) strcpy(str, desc->dtpd_name); 227*b9e93c10SJonathan Haslam 228*b9e93c10SJonathan Haslam /* 229*b9e93c10SJonathan Haslam * We have a poor man's strtok() going on here. Replace any hyphens 230*b9e93c10SJonathan Haslam * in the the probe name with NULL characters in order to make it 231*b9e93c10SJonathan Haslam * easy to parse the string with regular string functions. 232*b9e93c10SJonathan Haslam */ 233*b9e93c10SJonathan Haslam for (i = 0; i < len; i++) { 234*b9e93c10SJonathan Haslam if (str[i] == '-') 235*b9e93c10SJonathan Haslam str[i] = '\0'; 236*b9e93c10SJonathan Haslam } 237*b9e93c10SJonathan Haslam 238*b9e93c10SJonathan Haslam /* 239*b9e93c10SJonathan Haslam * The first part of the string must be either a platform event 240*b9e93c10SJonathan Haslam * name or a generic event name. 241*b9e93c10SJonathan Haslam */ 242*b9e93c10SJonathan Haslam evlen = strlen(p); 243*b9e93c10SJonathan Haslam (void) strncpy(event, p, CPC_MAX_EVENT_LEN - 1); 244*b9e93c10SJonathan Haslam event[CPC_MAX_EVENT_LEN - 1] = '\0'; 245*b9e93c10SJonathan Haslam 246*b9e93c10SJonathan Haslam /* 247*b9e93c10SJonathan Haslam * The next part of the name is the mode specification. Valid 248*b9e93c10SJonathan Haslam * settings are "user", "kernel" or "all". 249*b9e93c10SJonathan Haslam */ 250*b9e93c10SJonathan Haslam p += evlen + 1; 251*b9e93c10SJonathan Haslam 252*b9e93c10SJonathan Haslam if (strcmp(p, "user") == 0) 253*b9e93c10SJonathan Haslam flag |= CPC_COUNT_USER; 254*b9e93c10SJonathan Haslam else if (strcmp(p, "kernel") == 0) 255*b9e93c10SJonathan Haslam flag |= CPC_COUNT_SYSTEM; 256*b9e93c10SJonathan Haslam else if (strcmp(p, "all") == 0) 257*b9e93c10SJonathan Haslam flag |= CPC_COUNT_USER | CPC_COUNT_SYSTEM; 258*b9e93c10SJonathan Haslam else 259*b9e93c10SJonathan Haslam goto err; 260*b9e93c10SJonathan Haslam 261*b9e93c10SJonathan Haslam /* 262*b9e93c10SJonathan Haslam * Next we either have a mask specification followed by an overflow 263*b9e93c10SJonathan Haslam * rate or just an overflow rate on its own. 264*b9e93c10SJonathan Haslam */ 265*b9e93c10SJonathan Haslam p += strlen(p) + 1; 266*b9e93c10SJonathan Haslam if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { 267*b9e93c10SJonathan Haslam /* 268*b9e93c10SJonathan Haslam * A unit mask can only be specified if: 269*b9e93c10SJonathan Haslam * 1) this performance counter back end supports masks. 270*b9e93c10SJonathan Haslam * 2) the specified event is platform specific. 271*b9e93c10SJonathan Haslam * 3) a valid hex number is converted. 272*b9e93c10SJonathan Haslam * 4) no extraneous characters follow the mask specification. 273*b9e93c10SJonathan Haslam */ 274*b9e93c10SJonathan Haslam if (dcpc_mask_type != 0 && strncmp(event, "PAPI", 4) != 0 && 275*b9e93c10SJonathan Haslam ddi_strtol(p, &end, 16, &umask) == 0 && 276*b9e93c10SJonathan Haslam end == p + strlen(p)) { 277*b9e93c10SJonathan Haslam p += strlen(p) + 1; 278*b9e93c10SJonathan Haslam } else { 279*b9e93c10SJonathan Haslam goto err; 280*b9e93c10SJonathan Haslam } 281*b9e93c10SJonathan Haslam } 282*b9e93c10SJonathan Haslam 283*b9e93c10SJonathan Haslam /* 284*b9e93c10SJonathan Haslam * This final part must be an overflow value which has to be greater 285*b9e93c10SJonathan Haslam * than the minimum permissible overflow rate. 286*b9e93c10SJonathan Haslam */ 287*b9e93c10SJonathan Haslam if ((ddi_strtol(p, &end, 10, &val) != 0) || end != p + strlen(p) || 288*b9e93c10SJonathan Haslam val < dcpc_min_overflow) 289*b9e93c10SJonathan Haslam goto err; 290*b9e93c10SJonathan Haslam 291*b9e93c10SJonathan Haslam /* 292*b9e93c10SJonathan Haslam * Validate the event and create the probe. 293*b9e93c10SJonathan Haslam */ 294*b9e93c10SJonathan Haslam for (i = 0; i < cpc_ncounters; i++) { 295*b9e93c10SJonathan Haslam if (strstr(kcpc_list_events(i), event) != NULL) 296*b9e93c10SJonathan Haslam dcpc_create_probe(dcpc_pid, desc->dtpd_name, event, 297*b9e93c10SJonathan Haslam umask, (uint32_t)val, flag); 298*b9e93c10SJonathan Haslam } 299*b9e93c10SJonathan Haslam 300*b9e93c10SJonathan Haslam err: 301*b9e93c10SJonathan Haslam kmem_free(str, len + 1); 302*b9e93c10SJonathan Haslam } 303*b9e93c10SJonathan Haslam 304*b9e93c10SJonathan Haslam /*ARGSUSED*/ 305*b9e93c10SJonathan Haslam static void 306*b9e93c10SJonathan Haslam dcpc_destroy(void *arg, dtrace_id_t id, void *parg) 307*b9e93c10SJonathan Haslam { 308*b9e93c10SJonathan Haslam dcpc_probe_t *pp = parg; 309*b9e93c10SJonathan Haslam 310*b9e93c10SJonathan Haslam ASSERT(pp->dcpc_enabled == 0); 311*b9e93c10SJonathan Haslam kmem_free(pp, sizeof (dcpc_probe_t)); 312*b9e93c10SJonathan Haslam } 313*b9e93c10SJonathan Haslam 314*b9e93c10SJonathan Haslam /*ARGSUSED*/ 315*b9e93c10SJonathan Haslam static int 316*b9e93c10SJonathan Haslam dcpc_usermode(void *arg, dtrace_id_t id, void *parg) 317*b9e93c10SJonathan Haslam { 318*b9e93c10SJonathan Haslam return (CPU->cpu_cpcprofile_pc == 0); 319*b9e93c10SJonathan Haslam } 320*b9e93c10SJonathan Haslam 321*b9e93c10SJonathan Haslam static void 322*b9e93c10SJonathan Haslam dcpc_populate_set(cpu_t *c, dcpc_probe_t *pp, kcpc_set_t *set, int reqno) 323*b9e93c10SJonathan Haslam { 324*b9e93c10SJonathan Haslam kcpc_set_t *oset; 325*b9e93c10SJonathan Haslam int i; 326*b9e93c10SJonathan Haslam 327*b9e93c10SJonathan Haslam (void) strncpy(set->ks_req[reqno].kr_event, pp->dcpc_event_name, 328*b9e93c10SJonathan Haslam CPC_MAX_EVENT_LEN); 329*b9e93c10SJonathan Haslam set->ks_req[reqno].kr_config = NULL; 330*b9e93c10SJonathan Haslam set->ks_req[reqno].kr_index = reqno; 331*b9e93c10SJonathan Haslam set->ks_req[reqno].kr_picnum = -1; 332*b9e93c10SJonathan Haslam set->ks_req[reqno].kr_flags = pp->dcpc_flag; 333*b9e93c10SJonathan Haslam 334*b9e93c10SJonathan Haslam /* 335*b9e93c10SJonathan Haslam * If a unit mask has been specified then detect which attribute 336*b9e93c10SJonathan Haslam * the platform needs. For now, it's either "umask" or "emask". 337*b9e93c10SJonathan Haslam */ 338*b9e93c10SJonathan Haslam if (pp->dcpc_umask >= 0) { 339*b9e93c10SJonathan Haslam set->ks_req[reqno].kr_attr = 340*b9e93c10SJonathan Haslam kmem_zalloc(sizeof (kcpc_attr_t), KM_SLEEP); 341*b9e93c10SJonathan Haslam set->ks_req[reqno].kr_nattrs = 1; 342*b9e93c10SJonathan Haslam if (dcpc_mask_type & DCPC_UMASK) 343*b9e93c10SJonathan Haslam (void) strncpy(set->ks_req[reqno].kr_attr->ka_name, 344*b9e93c10SJonathan Haslam "umask", 5); 345*b9e93c10SJonathan Haslam else 346*b9e93c10SJonathan Haslam (void) strncpy(set->ks_req[reqno].kr_attr->ka_name, 347*b9e93c10SJonathan Haslam "emask", 5); 348*b9e93c10SJonathan Haslam set->ks_req[reqno].kr_attr->ka_val = pp->dcpc_umask; 349*b9e93c10SJonathan Haslam } else { 350*b9e93c10SJonathan Haslam set->ks_req[reqno].kr_attr = NULL; 351*b9e93c10SJonathan Haslam set->ks_req[reqno].kr_nattrs = 0; 352*b9e93c10SJonathan Haslam } 353*b9e93c10SJonathan Haslam 354*b9e93c10SJonathan Haslam /* 355*b9e93c10SJonathan Haslam * If this probe is enabled, obtain its current countdown value 356*b9e93c10SJonathan Haslam * and use that. The CPUs cpc context might not exist yet if we 357*b9e93c10SJonathan Haslam * are dealing with a CPU that is just coming online. 358*b9e93c10SJonathan Haslam */ 359*b9e93c10SJonathan Haslam if (pp->dcpc_enabled && (c->cpu_cpc_ctx != NULL)) { 360*b9e93c10SJonathan Haslam oset = c->cpu_cpc_ctx->kc_set; 361*b9e93c10SJonathan Haslam 362*b9e93c10SJonathan Haslam for (i = 0; i < oset->ks_nreqs; i++) { 363*b9e93c10SJonathan Haslam if (strcmp(oset->ks_req[i].kr_event, 364*b9e93c10SJonathan Haslam set->ks_req[reqno].kr_event) == 0) { 365*b9e93c10SJonathan Haslam set->ks_req[reqno].kr_preset = 366*b9e93c10SJonathan Haslam *(oset->ks_req[i].kr_data); 367*b9e93c10SJonathan Haslam } 368*b9e93c10SJonathan Haslam } 369*b9e93c10SJonathan Haslam } else { 370*b9e93c10SJonathan Haslam set->ks_req[reqno].kr_preset = UINT64_MAX - pp->dcpc_ovfval; 371*b9e93c10SJonathan Haslam } 372*b9e93c10SJonathan Haslam 373*b9e93c10SJonathan Haslam set->ks_nreqs++; 374*b9e93c10SJonathan Haslam } 375*b9e93c10SJonathan Haslam 376*b9e93c10SJonathan Haslam 377*b9e93c10SJonathan Haslam /* 378*b9e93c10SJonathan Haslam * Create a fresh request set for the enablings represented in the 379*b9e93c10SJonathan Haslam * 'dcpc_actv_reqs' array which contains the probes we want to be 380*b9e93c10SJonathan Haslam * in the set. This can be called for several reasons: 381*b9e93c10SJonathan Haslam * 382*b9e93c10SJonathan Haslam * 1) We are on a single or multi overflow platform and we have no 383*b9e93c10SJonathan Haslam * current events so we can just create the set and initialize it. 384*b9e93c10SJonathan Haslam * 2) We are on a multi-overflow platform and we already have one or 385*b9e93c10SJonathan Haslam * more existing events and we are adding a new enabling. Create a 386*b9e93c10SJonathan Haslam * new set and copy old requests in and then add the new request. 387*b9e93c10SJonathan Haslam * 3) We are on a multi-overflow platform and we have just removed an 388*b9e93c10SJonathan Haslam * enabling but we still have enablings whch are valid. Create a new 389*b9e93c10SJonathan Haslam * set and copy in still valid requests. 390*b9e93c10SJonathan Haslam */ 391*b9e93c10SJonathan Haslam static kcpc_set_t * 392*b9e93c10SJonathan Haslam dcpc_create_set(cpu_t *c) 393*b9e93c10SJonathan Haslam { 394*b9e93c10SJonathan Haslam int i, reqno = 0; 395*b9e93c10SJonathan Haslam int active_requests = 0; 396*b9e93c10SJonathan Haslam kcpc_set_t *set; 397*b9e93c10SJonathan Haslam 398*b9e93c10SJonathan Haslam /* 399*b9e93c10SJonathan Haslam * First get a count of the number of currently active requests. 400*b9e93c10SJonathan Haslam * Note that dcpc_actv_reqs[] should always reflect which requests 401*b9e93c10SJonathan Haslam * we want to be in the set that is to be created. It is the 402*b9e93c10SJonathan Haslam * responsibility of the caller of dcpc_create_set() to adjust that 403*b9e93c10SJonathan Haslam * array accordingly beforehand. 404*b9e93c10SJonathan Haslam */ 405*b9e93c10SJonathan Haslam for (i = 0; i < cpc_ncounters; i++) { 406*b9e93c10SJonathan Haslam if (dcpc_actv_reqs[i] != NULL) 407*b9e93c10SJonathan Haslam active_requests++; 408*b9e93c10SJonathan Haslam } 409*b9e93c10SJonathan Haslam 410*b9e93c10SJonathan Haslam set = kmem_zalloc(sizeof (kcpc_set_t), KM_SLEEP); 411*b9e93c10SJonathan Haslam 412*b9e93c10SJonathan Haslam set->ks_req = 413*b9e93c10SJonathan Haslam kmem_zalloc(sizeof (kcpc_request_t) * active_requests, KM_SLEEP); 414*b9e93c10SJonathan Haslam 415*b9e93c10SJonathan Haslam set->ks_data = 416*b9e93c10SJonathan Haslam kmem_zalloc(active_requests * sizeof (uint64_t), KM_SLEEP); 417*b9e93c10SJonathan Haslam 418*b9e93c10SJonathan Haslam /* 419*b9e93c10SJonathan Haslam * Look for valid entries in the active requests array and populate 420*b9e93c10SJonathan Haslam * the request set for any entries found. 421*b9e93c10SJonathan Haslam */ 422*b9e93c10SJonathan Haslam for (i = 0; i < cpc_ncounters; i++) { 423*b9e93c10SJonathan Haslam if (dcpc_actv_reqs[i] != NULL) { 424*b9e93c10SJonathan Haslam dcpc_populate_set(c, dcpc_actv_reqs[i], set, reqno); 425*b9e93c10SJonathan Haslam reqno++; 426*b9e93c10SJonathan Haslam } 427*b9e93c10SJonathan Haslam } 428*b9e93c10SJonathan Haslam 429*b9e93c10SJonathan Haslam return (set); 430*b9e93c10SJonathan Haslam } 431*b9e93c10SJonathan Haslam 432*b9e93c10SJonathan Haslam static int 433*b9e93c10SJonathan Haslam dcpc_program_cpu_event(cpu_t *c) 434*b9e93c10SJonathan Haslam { 435*b9e93c10SJonathan Haslam int i, j, subcode; 436*b9e93c10SJonathan Haslam kcpc_ctx_t *ctx, *octx; 437*b9e93c10SJonathan Haslam kcpc_set_t *set; 438*b9e93c10SJonathan Haslam 439*b9e93c10SJonathan Haslam set = dcpc_create_set(c); 440*b9e93c10SJonathan Haslam 441*b9e93c10SJonathan Haslam octx = NULL; 442*b9e93c10SJonathan Haslam set->ks_ctx = ctx = kcpc_ctx_alloc(); 443*b9e93c10SJonathan Haslam ctx->kc_set = set; 444*b9e93c10SJonathan Haslam ctx->kc_cpuid = c->cpu_id; 445*b9e93c10SJonathan Haslam 446*b9e93c10SJonathan Haslam if (kcpc_assign_reqs(set, ctx) != 0) 447*b9e93c10SJonathan Haslam goto err; 448*b9e93c10SJonathan Haslam 449*b9e93c10SJonathan Haslam if (kcpc_configure_reqs(ctx, set, &subcode) != 0) 450*b9e93c10SJonathan Haslam goto err; 451*b9e93c10SJonathan Haslam 452*b9e93c10SJonathan Haslam for (i = 0; i < set->ks_nreqs; i++) { 453*b9e93c10SJonathan Haslam for (j = 0; j < cpc_ncounters; j++) { 454*b9e93c10SJonathan Haslam if (dcpc_actv_reqs[j] != NULL && 455*b9e93c10SJonathan Haslam strcmp(set->ks_req[i].kr_event, 456*b9e93c10SJonathan Haslam dcpc_actv_reqs[j]->dcpc_event_name) == 0) { 457*b9e93c10SJonathan Haslam dcpc_actv_reqs[j]->dcpc_picno = 458*b9e93c10SJonathan Haslam set->ks_req[i].kr_picnum; 459*b9e93c10SJonathan Haslam } 460*b9e93c10SJonathan Haslam } 461*b9e93c10SJonathan Haslam } 462*b9e93c10SJonathan Haslam 463*b9e93c10SJonathan Haslam /* 464*b9e93c10SJonathan Haslam * If we already have an active enabling then save the current cpc 465*b9e93c10SJonathan Haslam * context away. 466*b9e93c10SJonathan Haslam */ 467*b9e93c10SJonathan Haslam if (c->cpu_cpc_ctx != NULL) 468*b9e93c10SJonathan Haslam octx = c->cpu_cpc_ctx; 469*b9e93c10SJonathan Haslam 470*b9e93c10SJonathan Haslam c->cpu_cpc_ctx = ctx; 471*b9e93c10SJonathan Haslam kcpc_remote_program(c); 472*b9e93c10SJonathan Haslam 473*b9e93c10SJonathan Haslam if (octx != NULL) { 474*b9e93c10SJonathan Haslam kcpc_set_t *oset = octx->kc_set; 475*b9e93c10SJonathan Haslam kmem_free(oset->ks_data, oset->ks_nreqs * sizeof (uint64_t)); 476*b9e93c10SJonathan Haslam kcpc_free_set(oset); 477*b9e93c10SJonathan Haslam kcpc_ctx_free(octx); 478*b9e93c10SJonathan Haslam } 479*b9e93c10SJonathan Haslam 480*b9e93c10SJonathan Haslam return (0); 481*b9e93c10SJonathan Haslam 482*b9e93c10SJonathan Haslam err: 483*b9e93c10SJonathan Haslam /* 484*b9e93c10SJonathan Haslam * We failed to configure this request up so free things up and 485*b9e93c10SJonathan Haslam * get out. 486*b9e93c10SJonathan Haslam */ 487*b9e93c10SJonathan Haslam kmem_free(set->ks_data, set->ks_nreqs * sizeof (uint64_t)); 488*b9e93c10SJonathan Haslam kcpc_free_set(set); 489*b9e93c10SJonathan Haslam kcpc_ctx_free(ctx); 490*b9e93c10SJonathan Haslam 491*b9e93c10SJonathan Haslam return (-1); 492*b9e93c10SJonathan Haslam } 493*b9e93c10SJonathan Haslam 494*b9e93c10SJonathan Haslam static void 495*b9e93c10SJonathan Haslam dcpc_disable_cpu(cpu_t *c) 496*b9e93c10SJonathan Haslam { 497*b9e93c10SJonathan Haslam kcpc_ctx_t *ctx; 498*b9e93c10SJonathan Haslam kcpc_set_t *set; 499*b9e93c10SJonathan Haslam 500*b9e93c10SJonathan Haslam /* 501*b9e93c10SJonathan Haslam * Leave this CPU alone if it's already offline. 502*b9e93c10SJonathan Haslam */ 503*b9e93c10SJonathan Haslam if (c->cpu_flags & CPU_OFFLINE) 504*b9e93c10SJonathan Haslam return; 505*b9e93c10SJonathan Haslam 506*b9e93c10SJonathan Haslam kcpc_remote_stop(c); 507*b9e93c10SJonathan Haslam 508*b9e93c10SJonathan Haslam ctx = c->cpu_cpc_ctx; 509*b9e93c10SJonathan Haslam set = ctx->kc_set; 510*b9e93c10SJonathan Haslam 511*b9e93c10SJonathan Haslam kcpc_free_configs(set); 512*b9e93c10SJonathan Haslam 513*b9e93c10SJonathan Haslam kmem_free(set->ks_data, set->ks_nreqs * sizeof (uint64_t)); 514*b9e93c10SJonathan Haslam kcpc_free_set(set); 515*b9e93c10SJonathan Haslam kcpc_ctx_free(ctx); 516*b9e93c10SJonathan Haslam c->cpu_cpc_ctx = NULL; 517*b9e93c10SJonathan Haslam } 518*b9e93c10SJonathan Haslam 519*b9e93c10SJonathan Haslam /* 520*b9e93c10SJonathan Haslam * Stop overflow interrupts being actively processed so that per-CPU 521*b9e93c10SJonathan Haslam * configuration state can be changed safely and correctly. Each CPU has a 522*b9e93c10SJonathan Haslam * dcpc interrupt state byte which is transitioned from DCPC_INTR_FREE (the 523*b9e93c10SJonathan Haslam * "free" state) to DCPC_INTR_CONFIG (the "configuration in process" state) 524*b9e93c10SJonathan Haslam * before any configuration state is changed on any CPUs. The hardware overflow 525*b9e93c10SJonathan Haslam * handler, kcpc_hw_overflow_intr(), will only process an interrupt when a 526*b9e93c10SJonathan Haslam * configuration is not in process (i.e. the state is marked as free). During 527*b9e93c10SJonathan Haslam * interrupt processing the state is set to DCPC_INTR_PROCESSING by the 528*b9e93c10SJonathan Haslam * overflow handler. 529*b9e93c10SJonathan Haslam */ 530*b9e93c10SJonathan Haslam static void 531*b9e93c10SJonathan Haslam dcpc_block_interrupts(void) 532*b9e93c10SJonathan Haslam { 533*b9e93c10SJonathan Haslam cpu_t *c; 534*b9e93c10SJonathan Haslam uint8_t *state; 535*b9e93c10SJonathan Haslam 536*b9e93c10SJonathan Haslam c = cpu_list; 537*b9e93c10SJonathan Haslam 538*b9e93c10SJonathan Haslam do { 539*b9e93c10SJonathan Haslam state = &cpu_core[c->cpu_id].cpuc_dcpc_intr_state; 540*b9e93c10SJonathan Haslam 541*b9e93c10SJonathan Haslam while (atomic_cas_8(state, DCPC_INTR_FREE, 542*b9e93c10SJonathan Haslam DCPC_INTR_CONFIG) != DCPC_INTR_FREE) 543*b9e93c10SJonathan Haslam continue; 544*b9e93c10SJonathan Haslam 545*b9e93c10SJonathan Haslam } while ((c = c->cpu_next) != cpu_list); 546*b9e93c10SJonathan Haslam } 547*b9e93c10SJonathan Haslam 548*b9e93c10SJonathan Haslam /* 549*b9e93c10SJonathan Haslam * Set all CPUs dcpc interrupt state to DCPC_INTR_FREE to indicate that 550*b9e93c10SJonathan Haslam * overflow interrupts can be processed safely. 551*b9e93c10SJonathan Haslam */ 552*b9e93c10SJonathan Haslam static void 553*b9e93c10SJonathan Haslam dcpc_release_interrupts(void) 554*b9e93c10SJonathan Haslam { 555*b9e93c10SJonathan Haslam cpu_t *c = cpu_list; 556*b9e93c10SJonathan Haslam 557*b9e93c10SJonathan Haslam do { 558*b9e93c10SJonathan Haslam cpu_core[c->cpu_id].cpuc_dcpc_intr_state = DCPC_INTR_FREE; 559*b9e93c10SJonathan Haslam membar_producer(); 560*b9e93c10SJonathan Haslam } while ((c = c->cpu_next) != cpu_list); 561*b9e93c10SJonathan Haslam } 562*b9e93c10SJonathan Haslam 563*b9e93c10SJonathan Haslam /* 564*b9e93c10SJonathan Haslam * dcpc_program_event() can be called owing to a new enabling or if a multi 565*b9e93c10SJonathan Haslam * overflow platform has disabled a request but needs to program the requests 566*b9e93c10SJonathan Haslam * that are still valid. 567*b9e93c10SJonathan Haslam * 568*b9e93c10SJonathan Haslam * Every invocation of dcpc_program_event() will create a new kcpc_ctx_t 569*b9e93c10SJonathan Haslam * and a new request set which contains the new enabling and any old enablings 570*b9e93c10SJonathan Haslam * which are still valid (possible with multi-overflow platforms). 571*b9e93c10SJonathan Haslam */ 572*b9e93c10SJonathan Haslam static int 573*b9e93c10SJonathan Haslam dcpc_program_event(dcpc_probe_t *pp) 574*b9e93c10SJonathan Haslam { 575*b9e93c10SJonathan Haslam cpu_t *c; 576*b9e93c10SJonathan Haslam int ret = 0; 577*b9e93c10SJonathan Haslam 578*b9e93c10SJonathan Haslam ASSERT(MUTEX_HELD(&cpu_lock)); 579*b9e93c10SJonathan Haslam 580*b9e93c10SJonathan Haslam kpreempt_disable(); 581*b9e93c10SJonathan Haslam 582*b9e93c10SJonathan Haslam dcpc_block_interrupts(); 583*b9e93c10SJonathan Haslam 584*b9e93c10SJonathan Haslam c = cpu_list; 585*b9e93c10SJonathan Haslam 586*b9e93c10SJonathan Haslam do { 587*b9e93c10SJonathan Haslam /* 588*b9e93c10SJonathan Haslam * Skip CPUs that are currently offline. 589*b9e93c10SJonathan Haslam */ 590*b9e93c10SJonathan Haslam if (c->cpu_flags & CPU_OFFLINE) 591*b9e93c10SJonathan Haslam continue; 592*b9e93c10SJonathan Haslam 593*b9e93c10SJonathan Haslam if (c->cpu_cpc_ctx != NULL) 594*b9e93c10SJonathan Haslam kcpc_remote_stop(c); 595*b9e93c10SJonathan Haslam } while ((c = c->cpu_next) != cpu_list); 596*b9e93c10SJonathan Haslam 597*b9e93c10SJonathan Haslam dcpc_release_interrupts(); 598*b9e93c10SJonathan Haslam 599*b9e93c10SJonathan Haslam /* 600*b9e93c10SJonathan Haslam * If this enabling is being removed (in the case of a multi event 601*b9e93c10SJonathan Haslam * capable system with more than one active enabling), we can now 602*b9e93c10SJonathan Haslam * update the active request array to reflect the enablings that need 603*b9e93c10SJonathan Haslam * to be reprogrammed. 604*b9e93c10SJonathan Haslam */ 605*b9e93c10SJonathan Haslam if (pp->dcpc_disabling == 1) 606*b9e93c10SJonathan Haslam dcpc_actv_reqs[pp->dcpc_actv_req_idx] = NULL; 607*b9e93c10SJonathan Haslam 608*b9e93c10SJonathan Haslam do { 609*b9e93c10SJonathan Haslam /* 610*b9e93c10SJonathan Haslam * Skip CPUs that are currently offline. 611*b9e93c10SJonathan Haslam */ 612*b9e93c10SJonathan Haslam if (c->cpu_flags & CPU_OFFLINE) 613*b9e93c10SJonathan Haslam continue; 614*b9e93c10SJonathan Haslam 615*b9e93c10SJonathan Haslam ret = dcpc_program_cpu_event(c); 616*b9e93c10SJonathan Haslam } while ((c = c->cpu_next) != cpu_list && ret == 0); 617*b9e93c10SJonathan Haslam 618*b9e93c10SJonathan Haslam /* 619*b9e93c10SJonathan Haslam * If dcpc_program_cpu_event() fails then it is because we couldn't 620*b9e93c10SJonathan Haslam * configure the requests in the set for the CPU and not because of 621*b9e93c10SJonathan Haslam * an error programming the hardware. If we have a failure here then 622*b9e93c10SJonathan Haslam * we assume no CPUs have been programmed in the above step as they 623*b9e93c10SJonathan Haslam * are all configured identically. 624*b9e93c10SJonathan Haslam */ 625*b9e93c10SJonathan Haslam if (ret != 0) { 626*b9e93c10SJonathan Haslam pp->dcpc_enabled = 0; 627*b9e93c10SJonathan Haslam kpreempt_enable(); 628*b9e93c10SJonathan Haslam return (-1); 629*b9e93c10SJonathan Haslam } 630*b9e93c10SJonathan Haslam 631*b9e93c10SJonathan Haslam if (pp->dcpc_disabling != 1) 632*b9e93c10SJonathan Haslam pp->dcpc_enabled = 1; 633*b9e93c10SJonathan Haslam 634*b9e93c10SJonathan Haslam kpreempt_enable(); 635*b9e93c10SJonathan Haslam 636*b9e93c10SJonathan Haslam return (0); 637*b9e93c10SJonathan Haslam } 638*b9e93c10SJonathan Haslam 639*b9e93c10SJonathan Haslam /*ARGSUSED*/ 640*b9e93c10SJonathan Haslam static int 641*b9e93c10SJonathan Haslam dcpc_enable(void *arg, dtrace_id_t id, void *parg) 642*b9e93c10SJonathan Haslam { 643*b9e93c10SJonathan Haslam dcpc_probe_t *pp = parg; 644*b9e93c10SJonathan Haslam int i, found = 0; 645*b9e93c10SJonathan Haslam cpu_t *c; 646*b9e93c10SJonathan Haslam 647*b9e93c10SJonathan Haslam ASSERT(MUTEX_HELD(&cpu_lock)); 648*b9e93c10SJonathan Haslam 649*b9e93c10SJonathan Haslam /* 650*b9e93c10SJonathan Haslam * Bail out if the counters are being used by a libcpc consumer. 651*b9e93c10SJonathan Haslam */ 652*b9e93c10SJonathan Haslam rw_enter(&kcpc_cpuctx_lock, RW_READER); 653*b9e93c10SJonathan Haslam if (kcpc_cpuctx > 0) { 654*b9e93c10SJonathan Haslam rw_exit(&kcpc_cpuctx_lock); 655*b9e93c10SJonathan Haslam return (-1); 656*b9e93c10SJonathan Haslam } 657*b9e93c10SJonathan Haslam 658*b9e93c10SJonathan Haslam dtrace_cpc_in_use++; 659*b9e93c10SJonathan Haslam rw_exit(&kcpc_cpuctx_lock); 660*b9e93c10SJonathan Haslam 661*b9e93c10SJonathan Haslam /* 662*b9e93c10SJonathan Haslam * Locate this enabling in the first free entry of the active 663*b9e93c10SJonathan Haslam * request array. 664*b9e93c10SJonathan Haslam */ 665*b9e93c10SJonathan Haslam for (i = 0; i < cpc_ncounters; i++) { 666*b9e93c10SJonathan Haslam if (dcpc_actv_reqs[i] == NULL) { 667*b9e93c10SJonathan Haslam dcpc_actv_reqs[i] = pp; 668*b9e93c10SJonathan Haslam pp->dcpc_actv_req_idx = i; 669*b9e93c10SJonathan Haslam found = 1; 670*b9e93c10SJonathan Haslam break; 671*b9e93c10SJonathan Haslam } 672*b9e93c10SJonathan Haslam } 673*b9e93c10SJonathan Haslam 674*b9e93c10SJonathan Haslam /* 675*b9e93c10SJonathan Haslam * If we couldn't find a slot for this probe then there is no 676*b9e93c10SJonathan Haslam * room at the inn. 677*b9e93c10SJonathan Haslam */ 678*b9e93c10SJonathan Haslam if (!found) { 679*b9e93c10SJonathan Haslam dtrace_cpc_in_use--; 680*b9e93c10SJonathan Haslam return (-1); 681*b9e93c10SJonathan Haslam } 682*b9e93c10SJonathan Haslam 683*b9e93c10SJonathan Haslam ASSERT(pp->dcpc_actv_req_idx >= 0); 684*b9e93c10SJonathan Haslam 685*b9e93c10SJonathan Haslam /* 686*b9e93c10SJonathan Haslam * The following must hold true if we are to (attempt to) enable 687*b9e93c10SJonathan Haslam * this request: 688*b9e93c10SJonathan Haslam * 689*b9e93c10SJonathan Haslam * 1) No enablings currently exist. We allow all platforms to 690*b9e93c10SJonathan Haslam * proceed if this is true. 691*b9e93c10SJonathan Haslam * 692*b9e93c10SJonathan Haslam * OR 693*b9e93c10SJonathan Haslam * 694*b9e93c10SJonathan Haslam * 2) If the platform is multi overflow capable and there are 695*b9e93c10SJonathan Haslam * less valid enablings than there are counters. There is no 696*b9e93c10SJonathan Haslam * guarantee that a platform can accommodate as many events as 697*b9e93c10SJonathan Haslam * it has counters for but we will at least try to program 698*b9e93c10SJonathan Haslam * up to that many requests. 699*b9e93c10SJonathan Haslam * 700*b9e93c10SJonathan Haslam * The 'dcpc_enablings' variable is implictly protected by locking 701*b9e93c10SJonathan Haslam * provided by the DTrace framework and the cpu management framework. 702*b9e93c10SJonathan Haslam */ 703*b9e93c10SJonathan Haslam if (dcpc_enablings == 0 || (dcpc_mult_ovf_cap && 704*b9e93c10SJonathan Haslam dcpc_enablings < cpc_ncounters)) { 705*b9e93c10SJonathan Haslam /* 706*b9e93c10SJonathan Haslam * Before attempting to program the first enabling we need to 707*b9e93c10SJonathan Haslam * invalidate any lwp-based contexts. 708*b9e93c10SJonathan Haslam */ 709*b9e93c10SJonathan Haslam if (dcpc_enablings == 0) 710*b9e93c10SJonathan Haslam kcpc_invalidate_all(); 711*b9e93c10SJonathan Haslam 712*b9e93c10SJonathan Haslam if (dcpc_program_event(pp) == 0) { 713*b9e93c10SJonathan Haslam dcpc_enablings++; 714*b9e93c10SJonathan Haslam return (0); 715*b9e93c10SJonathan Haslam } 716*b9e93c10SJonathan Haslam } 717*b9e93c10SJonathan Haslam 718*b9e93c10SJonathan Haslam /* 719*b9e93c10SJonathan Haslam * If active enablings existed before we failed to enable this probe 720*b9e93c10SJonathan Haslam * on a multi event capable platform then we need to restart counters 721*b9e93c10SJonathan Haslam * as they will have been stopped in the attempted configuration. The 722*b9e93c10SJonathan Haslam * context should now just contain the request prior to this failed 723*b9e93c10SJonathan Haslam * enabling. 724*b9e93c10SJonathan Haslam */ 725*b9e93c10SJonathan Haslam if (dcpc_enablings > 0 && dcpc_mult_ovf_cap) { 726*b9e93c10SJonathan Haslam c = cpu_list; 727*b9e93c10SJonathan Haslam 728*b9e93c10SJonathan Haslam ASSERT(dcpc_mult_ovf_cap == 1); 729*b9e93c10SJonathan Haslam do { 730*b9e93c10SJonathan Haslam /* 731*b9e93c10SJonathan Haslam * Skip CPUs that are currently offline. 732*b9e93c10SJonathan Haslam */ 733*b9e93c10SJonathan Haslam if (c->cpu_flags & CPU_OFFLINE) 734*b9e93c10SJonathan Haslam continue; 735*b9e93c10SJonathan Haslam 736*b9e93c10SJonathan Haslam kcpc_remote_program(c); 737*b9e93c10SJonathan Haslam } while ((c = c->cpu_next) != cpu_list); 738*b9e93c10SJonathan Haslam } 739*b9e93c10SJonathan Haslam 740*b9e93c10SJonathan Haslam dtrace_cpc_in_use--; 741*b9e93c10SJonathan Haslam dcpc_actv_reqs[pp->dcpc_actv_req_idx] = NULL; 742*b9e93c10SJonathan Haslam pp->dcpc_actv_req_idx = pp->dcpc_picno = -1; 743*b9e93c10SJonathan Haslam 744*b9e93c10SJonathan Haslam return (-1); 745*b9e93c10SJonathan Haslam } 746*b9e93c10SJonathan Haslam 747*b9e93c10SJonathan Haslam /* 748*b9e93c10SJonathan Haslam * If only one enabling is active then remove the context and free 749*b9e93c10SJonathan Haslam * everything up. If there are multiple enablings active then remove this 750*b9e93c10SJonathan Haslam * one, its associated meta-data and re-program the hardware. 751*b9e93c10SJonathan Haslam */ 752*b9e93c10SJonathan Haslam /*ARGSUSED*/ 753*b9e93c10SJonathan Haslam static void 754*b9e93c10SJonathan Haslam dcpc_disable(void *arg, dtrace_id_t id, void *parg) 755*b9e93c10SJonathan Haslam { 756*b9e93c10SJonathan Haslam cpu_t *c; 757*b9e93c10SJonathan Haslam dcpc_probe_t *pp = parg; 758*b9e93c10SJonathan Haslam 759*b9e93c10SJonathan Haslam ASSERT(MUTEX_HELD(&cpu_lock)); 760*b9e93c10SJonathan Haslam 761*b9e93c10SJonathan Haslam kpreempt_disable(); 762*b9e93c10SJonathan Haslam 763*b9e93c10SJonathan Haslam /* 764*b9e93c10SJonathan Haslam * This probe didn't actually make it as far as being fully enabled 765*b9e93c10SJonathan Haslam * so we needn't do anything with it. 766*b9e93c10SJonathan Haslam */ 767*b9e93c10SJonathan Haslam if (pp->dcpc_enabled == 0) { 768*b9e93c10SJonathan Haslam /* 769*b9e93c10SJonathan Haslam * If we actually allocated this request a slot in the 770*b9e93c10SJonathan Haslam * request array but failed to enabled it then remove the 771*b9e93c10SJonathan Haslam * entry in the array. 772*b9e93c10SJonathan Haslam */ 773*b9e93c10SJonathan Haslam if (pp->dcpc_actv_req_idx >= 0) { 774*b9e93c10SJonathan Haslam dcpc_actv_reqs[pp->dcpc_actv_req_idx] = NULL; 775*b9e93c10SJonathan Haslam pp->dcpc_actv_req_idx = pp->dcpc_picno = 776*b9e93c10SJonathan Haslam pp->dcpc_disabling = -1; 777*b9e93c10SJonathan Haslam } 778*b9e93c10SJonathan Haslam 779*b9e93c10SJonathan Haslam kpreempt_enable(); 780*b9e93c10SJonathan Haslam return; 781*b9e93c10SJonathan Haslam } 782*b9e93c10SJonathan Haslam 783*b9e93c10SJonathan Haslam /* 784*b9e93c10SJonathan Haslam * If this is the only enabling then stop all the counters and 785*b9e93c10SJonathan Haslam * free up the meta-data. 786*b9e93c10SJonathan Haslam */ 787*b9e93c10SJonathan Haslam if (dcpc_enablings == 1) { 788*b9e93c10SJonathan Haslam ASSERT(dtrace_cpc_in_use == 1); 789*b9e93c10SJonathan Haslam 790*b9e93c10SJonathan Haslam dcpc_block_interrupts(); 791*b9e93c10SJonathan Haslam 792*b9e93c10SJonathan Haslam c = cpu_list; 793*b9e93c10SJonathan Haslam 794*b9e93c10SJonathan Haslam do { 795*b9e93c10SJonathan Haslam dcpc_disable_cpu(c); 796*b9e93c10SJonathan Haslam } while ((c = c->cpu_next) != cpu_list); 797*b9e93c10SJonathan Haslam 798*b9e93c10SJonathan Haslam dcpc_actv_reqs[pp->dcpc_actv_req_idx] = NULL; 799*b9e93c10SJonathan Haslam dcpc_release_interrupts(); 800*b9e93c10SJonathan Haslam } else { 801*b9e93c10SJonathan Haslam /* 802*b9e93c10SJonathan Haslam * This platform can support multiple overflow events and 803*b9e93c10SJonathan Haslam * the enabling being disabled is not the last one. Remove this 804*b9e93c10SJonathan Haslam * enabling and re-program the hardware with the new config. 805*b9e93c10SJonathan Haslam */ 806*b9e93c10SJonathan Haslam ASSERT(dcpc_mult_ovf_cap); 807*b9e93c10SJonathan Haslam ASSERT(dcpc_enablings > 1); 808*b9e93c10SJonathan Haslam 809*b9e93c10SJonathan Haslam pp->dcpc_disabling = 1; 810*b9e93c10SJonathan Haslam (void) dcpc_program_event(pp); 811*b9e93c10SJonathan Haslam } 812*b9e93c10SJonathan Haslam 813*b9e93c10SJonathan Haslam kpreempt_enable(); 814*b9e93c10SJonathan Haslam 815*b9e93c10SJonathan Haslam dcpc_enablings--; 816*b9e93c10SJonathan Haslam dtrace_cpc_in_use--; 817*b9e93c10SJonathan Haslam pp->dcpc_enabled = 0; 818*b9e93c10SJonathan Haslam pp->dcpc_actv_req_idx = pp->dcpc_picno = pp->dcpc_disabling = -1; 819*b9e93c10SJonathan Haslam } 820*b9e93c10SJonathan Haslam 821*b9e93c10SJonathan Haslam /*ARGSUSED*/ 822*b9e93c10SJonathan Haslam static int 823*b9e93c10SJonathan Haslam dcpc_cpu_setup(cpu_setup_t what, processorid_t cpu, void *arg) 824*b9e93c10SJonathan Haslam { 825*b9e93c10SJonathan Haslam cpu_t *c; 826*b9e93c10SJonathan Haslam uint8_t *state; 827*b9e93c10SJonathan Haslam 828*b9e93c10SJonathan Haslam ASSERT(MUTEX_HELD(&cpu_lock)); 829*b9e93c10SJonathan Haslam 830*b9e93c10SJonathan Haslam switch (what) { 831*b9e93c10SJonathan Haslam case CPU_OFF: 832*b9e93c10SJonathan Haslam /* 833*b9e93c10SJonathan Haslam * Offline CPUs are not allowed to take part so remove this 834*b9e93c10SJonathan Haslam * CPU if we are actively tracing. 835*b9e93c10SJonathan Haslam */ 836*b9e93c10SJonathan Haslam if (dtrace_cpc_in_use) { 837*b9e93c10SJonathan Haslam c = cpu_get(cpu); 838*b9e93c10SJonathan Haslam state = &cpu_core[c->cpu_id].cpuc_dcpc_intr_state; 839*b9e93c10SJonathan Haslam 840*b9e93c10SJonathan Haslam /* 841*b9e93c10SJonathan Haslam * Indicate that a configuration is in process in 842*b9e93c10SJonathan Haslam * order to stop overflow interrupts being processed 843*b9e93c10SJonathan Haslam * on this CPU while we disable it. 844*b9e93c10SJonathan Haslam */ 845*b9e93c10SJonathan Haslam while (atomic_cas_8(state, DCPC_INTR_FREE, 846*b9e93c10SJonathan Haslam DCPC_INTR_CONFIG) != DCPC_INTR_FREE) 847*b9e93c10SJonathan Haslam continue; 848*b9e93c10SJonathan Haslam 849*b9e93c10SJonathan Haslam dcpc_disable_cpu(c); 850*b9e93c10SJonathan Haslam 851*b9e93c10SJonathan Haslam /* 852*b9e93c10SJonathan Haslam * Reset this CPUs interrupt state as the configuration 853*b9e93c10SJonathan Haslam * has ended. 854*b9e93c10SJonathan Haslam */ 855*b9e93c10SJonathan Haslam cpu_core[c->cpu_id].cpuc_dcpc_intr_state = 856*b9e93c10SJonathan Haslam DCPC_INTR_FREE; 857*b9e93c10SJonathan Haslam membar_producer(); 858*b9e93c10SJonathan Haslam } 859*b9e93c10SJonathan Haslam break; 860*b9e93c10SJonathan Haslam 861*b9e93c10SJonathan Haslam case CPU_ON: 862*b9e93c10SJonathan Haslam case CPU_SETUP: 863*b9e93c10SJonathan Haslam /* 864*b9e93c10SJonathan Haslam * This CPU is being initialized or brought online so program 865*b9e93c10SJonathan Haslam * it with the current request set if we are actively tracing. 866*b9e93c10SJonathan Haslam */ 867*b9e93c10SJonathan Haslam if (dtrace_cpc_in_use) { 868*b9e93c10SJonathan Haslam c = cpu_get(cpu); 869*b9e93c10SJonathan Haslam 870*b9e93c10SJonathan Haslam (void) dcpc_program_cpu_event(c); 871*b9e93c10SJonathan Haslam } 872*b9e93c10SJonathan Haslam break; 873*b9e93c10SJonathan Haslam 874*b9e93c10SJonathan Haslam default: 875*b9e93c10SJonathan Haslam break; 876*b9e93c10SJonathan Haslam } 877*b9e93c10SJonathan Haslam 878*b9e93c10SJonathan Haslam return (0); 879*b9e93c10SJonathan Haslam } 880*b9e93c10SJonathan Haslam 881*b9e93c10SJonathan Haslam static dtrace_pattr_t dcpc_attr = { 882*b9e93c10SJonathan Haslam { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, 883*b9e93c10SJonathan Haslam { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, 884*b9e93c10SJonathan Haslam { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, 885*b9e93c10SJonathan Haslam { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_CPU }, 886*b9e93c10SJonathan Haslam { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, 887*b9e93c10SJonathan Haslam }; 888*b9e93c10SJonathan Haslam 889*b9e93c10SJonathan Haslam static dtrace_pops_t dcpc_pops = { 890*b9e93c10SJonathan Haslam dcpc_provide, 891*b9e93c10SJonathan Haslam NULL, 892*b9e93c10SJonathan Haslam dcpc_enable, 893*b9e93c10SJonathan Haslam dcpc_disable, 894*b9e93c10SJonathan Haslam NULL, 895*b9e93c10SJonathan Haslam NULL, 896*b9e93c10SJonathan Haslam NULL, 897*b9e93c10SJonathan Haslam NULL, 898*b9e93c10SJonathan Haslam dcpc_usermode, 899*b9e93c10SJonathan Haslam dcpc_destroy 900*b9e93c10SJonathan Haslam }; 901*b9e93c10SJonathan Haslam 902*b9e93c10SJonathan Haslam /*ARGSUSED*/ 903*b9e93c10SJonathan Haslam static int 904*b9e93c10SJonathan Haslam dcpc_open(dev_t *devp, int flag, int otyp, cred_t *cred_p) 905*b9e93c10SJonathan Haslam { 906*b9e93c10SJonathan Haslam return (0); 907*b9e93c10SJonathan Haslam } 908*b9e93c10SJonathan Haslam 909*b9e93c10SJonathan Haslam /*ARGSUSED*/ 910*b9e93c10SJonathan Haslam static int 911*b9e93c10SJonathan Haslam dcpc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 912*b9e93c10SJonathan Haslam { 913*b9e93c10SJonathan Haslam int error; 914*b9e93c10SJonathan Haslam 915*b9e93c10SJonathan Haslam switch (infocmd) { 916*b9e93c10SJonathan Haslam case DDI_INFO_DEVT2DEVINFO: 917*b9e93c10SJonathan Haslam *result = (void *)dcpc_devi; 918*b9e93c10SJonathan Haslam error = DDI_SUCCESS; 919*b9e93c10SJonathan Haslam break; 920*b9e93c10SJonathan Haslam case DDI_INFO_DEVT2INSTANCE: 921*b9e93c10SJonathan Haslam *result = (void *)0; 922*b9e93c10SJonathan Haslam error = DDI_SUCCESS; 923*b9e93c10SJonathan Haslam break; 924*b9e93c10SJonathan Haslam default: 925*b9e93c10SJonathan Haslam error = DDI_FAILURE; 926*b9e93c10SJonathan Haslam } 927*b9e93c10SJonathan Haslam return (error); 928*b9e93c10SJonathan Haslam } 929*b9e93c10SJonathan Haslam 930*b9e93c10SJonathan Haslam static int 931*b9e93c10SJonathan Haslam dcpc_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 932*b9e93c10SJonathan Haslam { 933*b9e93c10SJonathan Haslam switch (cmd) { 934*b9e93c10SJonathan Haslam case DDI_DETACH: 935*b9e93c10SJonathan Haslam break; 936*b9e93c10SJonathan Haslam case DDI_SUSPEND: 937*b9e93c10SJonathan Haslam return (DDI_SUCCESS); 938*b9e93c10SJonathan Haslam default: 939*b9e93c10SJonathan Haslam return (DDI_FAILURE); 940*b9e93c10SJonathan Haslam } 941*b9e93c10SJonathan Haslam 942*b9e93c10SJonathan Haslam if (dtrace_unregister(dcpc_pid) != 0) 943*b9e93c10SJonathan Haslam return (DDI_FAILURE); 944*b9e93c10SJonathan Haslam 945*b9e93c10SJonathan Haslam ddi_remove_minor_node(devi, NULL); 946*b9e93c10SJonathan Haslam 947*b9e93c10SJonathan Haslam mutex_enter(&cpu_lock); 948*b9e93c10SJonathan Haslam unregister_cpu_setup_func(dcpc_cpu_setup, NULL); 949*b9e93c10SJonathan Haslam mutex_exit(&cpu_lock); 950*b9e93c10SJonathan Haslam 951*b9e93c10SJonathan Haslam kmem_free(dcpc_actv_reqs, cpc_ncounters * sizeof (dcpc_probe_t *)); 952*b9e93c10SJonathan Haslam 953*b9e93c10SJonathan Haslam kcpc_unregister_dcpc(); 954*b9e93c10SJonathan Haslam 955*b9e93c10SJonathan Haslam return (DDI_SUCCESS); 956*b9e93c10SJonathan Haslam } 957*b9e93c10SJonathan Haslam 958*b9e93c10SJonathan Haslam static int 959*b9e93c10SJonathan Haslam dcpc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 960*b9e93c10SJonathan Haslam { 961*b9e93c10SJonathan Haslam uint_t caps; 962*b9e93c10SJonathan Haslam char *attrs; 963*b9e93c10SJonathan Haslam 964*b9e93c10SJonathan Haslam switch (cmd) { 965*b9e93c10SJonathan Haslam case DDI_ATTACH: 966*b9e93c10SJonathan Haslam break; 967*b9e93c10SJonathan Haslam case DDI_RESUME: 968*b9e93c10SJonathan Haslam return (DDI_SUCCESS); 969*b9e93c10SJonathan Haslam default: 970*b9e93c10SJonathan Haslam return (DDI_FAILURE); 971*b9e93c10SJonathan Haslam } 972*b9e93c10SJonathan Haslam 973*b9e93c10SJonathan Haslam if (kcpc_pcbe_loaded() == -1) 974*b9e93c10SJonathan Haslam return (DDI_FAILURE); 975*b9e93c10SJonathan Haslam 976*b9e93c10SJonathan Haslam caps = kcpc_pcbe_capabilities(); 977*b9e93c10SJonathan Haslam 978*b9e93c10SJonathan Haslam if (!(caps & CPC_CAP_OVERFLOW_INTERRUPT)) { 979*b9e93c10SJonathan Haslam cmn_err(CE_WARN, "dcpc: Counter Overflow not supported"\ 980*b9e93c10SJonathan Haslam " on this processor\n"); 981*b9e93c10SJonathan Haslam return (DDI_FAILURE); 982*b9e93c10SJonathan Haslam } 983*b9e93c10SJonathan Haslam 984*b9e93c10SJonathan Haslam if (ddi_create_minor_node(devi, "dcpc", S_IFCHR, 0, 985*b9e93c10SJonathan Haslam DDI_PSEUDO, NULL) == DDI_FAILURE || 986*b9e93c10SJonathan Haslam dtrace_register("cpc", &dcpc_attr, DTRACE_PRIV_KERNEL, 987*b9e93c10SJonathan Haslam NULL, &dcpc_pops, NULL, &dcpc_pid) != 0) { 988*b9e93c10SJonathan Haslam ddi_remove_minor_node(devi, NULL); 989*b9e93c10SJonathan Haslam return (DDI_FAILURE); 990*b9e93c10SJonathan Haslam } 991*b9e93c10SJonathan Haslam 992*b9e93c10SJonathan Haslam mutex_enter(&cpu_lock); 993*b9e93c10SJonathan Haslam register_cpu_setup_func(dcpc_cpu_setup, NULL); 994*b9e93c10SJonathan Haslam mutex_exit(&cpu_lock); 995*b9e93c10SJonathan Haslam 996*b9e93c10SJonathan Haslam dcpc_ovf_mask = (1 << cpc_ncounters) - 1; 997*b9e93c10SJonathan Haslam ASSERT(dcpc_ovf_mask != 0); 998*b9e93c10SJonathan Haslam 999*b9e93c10SJonathan Haslam if (caps & CPC_CAP_OVERFLOW_PRECISE) 1000*b9e93c10SJonathan Haslam dcpc_mult_ovf_cap = 1; 1001*b9e93c10SJonathan Haslam 1002*b9e93c10SJonathan Haslam /* 1003*b9e93c10SJonathan Haslam * Determine which, if any, mask attribute the back-end can use. 1004*b9e93c10SJonathan Haslam */ 1005*b9e93c10SJonathan Haslam attrs = kcpc_list_attrs(); 1006*b9e93c10SJonathan Haslam if (strstr(attrs, "umask") != NULL) 1007*b9e93c10SJonathan Haslam dcpc_mask_type |= DCPC_UMASK; 1008*b9e93c10SJonathan Haslam else if (strstr(attrs, "emask") != NULL) 1009*b9e93c10SJonathan Haslam dcpc_mask_type |= DCPC_EMASK; 1010*b9e93c10SJonathan Haslam 1011*b9e93c10SJonathan Haslam /* 1012*b9e93c10SJonathan Haslam * The dcpc_actv_reqs array is used to store the requests that 1013*b9e93c10SJonathan Haslam * we currently have programmed. The order of requests in this 1014*b9e93c10SJonathan Haslam * array is not necessarily the order that the event appears in 1015*b9e93c10SJonathan Haslam * the kcpc_request_t array. Once entered into a slot in the array 1016*b9e93c10SJonathan Haslam * the entry is not moved until it's removed. 1017*b9e93c10SJonathan Haslam */ 1018*b9e93c10SJonathan Haslam dcpc_actv_reqs = 1019*b9e93c10SJonathan Haslam kmem_zalloc(cpc_ncounters * sizeof (dcpc_probe_t *), KM_SLEEP); 1020*b9e93c10SJonathan Haslam 1021*b9e93c10SJonathan Haslam dcpc_min_overflow = ddi_prop_get_int(DDI_DEV_T_ANY, devi, 1022*b9e93c10SJonathan Haslam DDI_PROP_DONTPASS, "dcpc-min-overflow", DCPC_MIN_OVF_DEFAULT); 1023*b9e93c10SJonathan Haslam 1024*b9e93c10SJonathan Haslam kcpc_register_dcpc(dcpc_fire); 1025*b9e93c10SJonathan Haslam 1026*b9e93c10SJonathan Haslam ddi_report_dev(devi); 1027*b9e93c10SJonathan Haslam dcpc_devi = devi; 1028*b9e93c10SJonathan Haslam 1029*b9e93c10SJonathan Haslam return (DDI_SUCCESS); 1030*b9e93c10SJonathan Haslam } 1031*b9e93c10SJonathan Haslam 1032*b9e93c10SJonathan Haslam static struct cb_ops dcpc_cb_ops = { 1033*b9e93c10SJonathan Haslam dcpc_open, /* open */ 1034*b9e93c10SJonathan Haslam nodev, /* close */ 1035*b9e93c10SJonathan Haslam nulldev, /* strategy */ 1036*b9e93c10SJonathan Haslam nulldev, /* print */ 1037*b9e93c10SJonathan Haslam nodev, /* dump */ 1038*b9e93c10SJonathan Haslam nodev, /* read */ 1039*b9e93c10SJonathan Haslam nodev, /* write */ 1040*b9e93c10SJonathan Haslam nodev, /* ioctl */ 1041*b9e93c10SJonathan Haslam nodev, /* devmap */ 1042*b9e93c10SJonathan Haslam nodev, /* mmap */ 1043*b9e93c10SJonathan Haslam nodev, /* segmap */ 1044*b9e93c10SJonathan Haslam nochpoll, /* poll */ 1045*b9e93c10SJonathan Haslam ddi_prop_op, /* cb_prop_op */ 1046*b9e93c10SJonathan Haslam 0, /* streamtab */ 1047*b9e93c10SJonathan Haslam D_NEW | D_MP /* Driver compatibility flag */ 1048*b9e93c10SJonathan Haslam }; 1049*b9e93c10SJonathan Haslam 1050*b9e93c10SJonathan Haslam static struct dev_ops dcpc_ops = { 1051*b9e93c10SJonathan Haslam DEVO_REV, /* devo_rev, */ 1052*b9e93c10SJonathan Haslam 0, /* refcnt */ 1053*b9e93c10SJonathan Haslam dcpc_info, /* get_dev_info */ 1054*b9e93c10SJonathan Haslam nulldev, /* identify */ 1055*b9e93c10SJonathan Haslam nulldev, /* probe */ 1056*b9e93c10SJonathan Haslam dcpc_attach, /* attach */ 1057*b9e93c10SJonathan Haslam dcpc_detach, /* detach */ 1058*b9e93c10SJonathan Haslam nodev, /* reset */ 1059*b9e93c10SJonathan Haslam &dcpc_cb_ops, /* driver operations */ 1060*b9e93c10SJonathan Haslam NULL, /* bus operations */ 1061*b9e93c10SJonathan Haslam nodev, /* dev power */ 1062*b9e93c10SJonathan Haslam ddi_quiesce_not_needed /* quiesce */ 1063*b9e93c10SJonathan Haslam }; 1064*b9e93c10SJonathan Haslam 1065*b9e93c10SJonathan Haslam /* 1066*b9e93c10SJonathan Haslam * Module linkage information for the kernel. 1067*b9e93c10SJonathan Haslam */ 1068*b9e93c10SJonathan Haslam static struct modldrv modldrv = { 1069*b9e93c10SJonathan Haslam &mod_driverops, /* module type */ 1070*b9e93c10SJonathan Haslam "DTrace CPC Module", /* name of module */ 1071*b9e93c10SJonathan Haslam &dcpc_ops, /* driver ops */ 1072*b9e93c10SJonathan Haslam }; 1073*b9e93c10SJonathan Haslam 1074*b9e93c10SJonathan Haslam static struct modlinkage modlinkage = { 1075*b9e93c10SJonathan Haslam MODREV_1, 1076*b9e93c10SJonathan Haslam (void *)&modldrv, 1077*b9e93c10SJonathan Haslam NULL 1078*b9e93c10SJonathan Haslam }; 1079*b9e93c10SJonathan Haslam 1080*b9e93c10SJonathan Haslam int 1081*b9e93c10SJonathan Haslam _init(void) 1082*b9e93c10SJonathan Haslam { 1083*b9e93c10SJonathan Haslam return (mod_install(&modlinkage)); 1084*b9e93c10SJonathan Haslam } 1085*b9e93c10SJonathan Haslam 1086*b9e93c10SJonathan Haslam int 1087*b9e93c10SJonathan Haslam _info(struct modinfo *modinfop) 1088*b9e93c10SJonathan Haslam { 1089*b9e93c10SJonathan Haslam return (mod_info(&modlinkage, modinfop)); 1090*b9e93c10SJonathan Haslam } 1091*b9e93c10SJonathan Haslam 1092*b9e93c10SJonathan Haslam int 1093*b9e93c10SJonathan Haslam _fini(void) 1094*b9e93c10SJonathan Haslam { 1095*b9e93c10SJonathan Haslam return (mod_remove(&modlinkage)); 1096*b9e93c10SJonathan Haslam } 1097