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