10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 52791Srab * Common Development and Distribution License (the "License"). 62791Srab * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 227120Svk226950 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #include <libcpc.h> 270Sstevel@tonic-gate #include <stdio.h> 280Sstevel@tonic-gate #include <stdlib.h> 290Sstevel@tonic-gate #include <errno.h> 300Sstevel@tonic-gate #include <strings.h> 310Sstevel@tonic-gate #include <unistd.h> 320Sstevel@tonic-gate #include <stropts.h> 330Sstevel@tonic-gate #include <libintl.h> 340Sstevel@tonic-gate #include <signal.h> 350Sstevel@tonic-gate #include <sys/syscall.h> 360Sstevel@tonic-gate #include <sys/types.h> 370Sstevel@tonic-gate #include <sys/processor.h> 380Sstevel@tonic-gate #include <sys/procset.h> 390Sstevel@tonic-gate 400Sstevel@tonic-gate #include "libcpc_impl.h" 410Sstevel@tonic-gate 420Sstevel@tonic-gate #define MASK32 0xFFFFFFFF 430Sstevel@tonic-gate 440Sstevel@tonic-gate /* 450Sstevel@tonic-gate * The library uses the cpc_lock field of the cpc_t struct to protect access to 460Sstevel@tonic-gate * the linked lists inside the cpc_t, and only the linked lists. It is NOT used 470Sstevel@tonic-gate * to protect against a user shooting his/herself in the foot (such as, for 480Sstevel@tonic-gate * instance, destroying the same set at the same time from different threads.). 490Sstevel@tonic-gate * 500Sstevel@tonic-gate * SIGEMT needs to be blocked while holding the lock, to prevent deadlock among 510Sstevel@tonic-gate * an app holding the lock and a signal handler attempting to sample or bind. 520Sstevel@tonic-gate */ 530Sstevel@tonic-gate 540Sstevel@tonic-gate static char *cpc_get_list(int which, int arg); 550Sstevel@tonic-gate static void cpc_err(cpc_t *cpc, const char *fn, int subcode, ...); 560Sstevel@tonic-gate static int cpc_set_valid(cpc_t *cpc, cpc_set_t *set); 570Sstevel@tonic-gate static int cpc_lock(cpc_t *cpc); 580Sstevel@tonic-gate static void cpc_unlock(cpc_t *cpc, int blocked); 590Sstevel@tonic-gate static int cpc_valid_event(cpc_t *cpc, uint_t pic, const char *ev); 600Sstevel@tonic-gate static int cpc_valid_attr(cpc_t *cpc, char *attr); 610Sstevel@tonic-gate static void cpc_invalidate_pctx(cpc_t *cpc, pctx_t *pctx); 620Sstevel@tonic-gate 630Sstevel@tonic-gate cpc_t * 640Sstevel@tonic-gate cpc_open(int ver) 650Sstevel@tonic-gate { 660Sstevel@tonic-gate cpc_t *cpc; 670Sstevel@tonic-gate void (*sigsaved)(); 680Sstevel@tonic-gate int error = 0; 690Sstevel@tonic-gate int i; 700Sstevel@tonic-gate int j; 710Sstevel@tonic-gate 720Sstevel@tonic-gate if (ver != CPC_VER_CURRENT) { 730Sstevel@tonic-gate /* 740Sstevel@tonic-gate * v1 clients must stick to the v1 interface: cpc_version() 750Sstevel@tonic-gate */ 760Sstevel@tonic-gate errno = EINVAL; 770Sstevel@tonic-gate return (NULL); 780Sstevel@tonic-gate } 790Sstevel@tonic-gate 800Sstevel@tonic-gate /* 810Sstevel@tonic-gate * Call the syscall with invalid parameters. If we get ENOSYS this CPU 820Sstevel@tonic-gate * has no CPC support. We need to block SIGSYS because the syscall code 830Sstevel@tonic-gate * will send the signal if the system call fails to load. 840Sstevel@tonic-gate */ 850Sstevel@tonic-gate sigsaved = signal(SIGSYS, SIG_IGN); 860Sstevel@tonic-gate if (syscall(SYS_cpc, -1, -1, -1, -1, -1) != -1) { 870Sstevel@tonic-gate (void) signal(SIGSYS, sigsaved); 880Sstevel@tonic-gate errno = EINVAL; 890Sstevel@tonic-gate return (NULL); 900Sstevel@tonic-gate } 910Sstevel@tonic-gate error = errno; 920Sstevel@tonic-gate (void) signal(SIGSYS, sigsaved); 930Sstevel@tonic-gate 940Sstevel@tonic-gate if (error != EINVAL) { 950Sstevel@tonic-gate errno = error; 960Sstevel@tonic-gate return (NULL); 970Sstevel@tonic-gate } 980Sstevel@tonic-gate 990Sstevel@tonic-gate if ((cpc = malloc(sizeof (cpc_t))) == NULL) { 1000Sstevel@tonic-gate errno = ENOMEM; 1010Sstevel@tonic-gate return (NULL); 1020Sstevel@tonic-gate } 1030Sstevel@tonic-gate 1040Sstevel@tonic-gate cpc->cpc_npic = syscall(SYS_cpc, CPC_NPIC, -1, 0, 0, 0); 1050Sstevel@tonic-gate cpc->cpc_caps = syscall(SYS_cpc, CPC_CAPS, -1, 0, 0, 0); 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate if (syscall(SYS_cpc, CPC_IMPL_NAME, -1, &cpc->cpc_cciname, 0, 0) != 0) 1080Sstevel@tonic-gate return (NULL); 1090Sstevel@tonic-gate if (syscall(SYS_cpc, CPC_CPUREF, -1, &cpc->cpc_cpuref, 0, 0) != 0) 1100Sstevel@tonic-gate return (NULL); 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate 1130Sstevel@tonic-gate if ((cpc->cpc_attrlist = cpc_get_list(CPC_LIST_ATTRS, 0)) == NULL) { 1140Sstevel@tonic-gate free(cpc); 1150Sstevel@tonic-gate return (NULL); 1160Sstevel@tonic-gate } 1170Sstevel@tonic-gate 1180Sstevel@tonic-gate if ((cpc->cpc_evlist = malloc(cpc->cpc_npic * sizeof (char *))) == 1190Sstevel@tonic-gate NULL) { 1200Sstevel@tonic-gate free(cpc->cpc_attrlist); 1210Sstevel@tonic-gate free(cpc); 1220Sstevel@tonic-gate return (NULL); 1230Sstevel@tonic-gate } 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate for (i = 0; i < cpc->cpc_npic; i++) { 1260Sstevel@tonic-gate if ((cpc->cpc_evlist[i] = cpc_get_list(CPC_LIST_EVENTS, i)) == 1270Sstevel@tonic-gate NULL) 1280Sstevel@tonic-gate break; 1290Sstevel@tonic-gate } 1300Sstevel@tonic-gate if (i != cpc->cpc_npic) { 1310Sstevel@tonic-gate for (j = 0; j < i; j++) 1320Sstevel@tonic-gate free(cpc->cpc_evlist[j]); 1330Sstevel@tonic-gate free(cpc->cpc_evlist); 1340Sstevel@tonic-gate free(cpc->cpc_attrlist); 1350Sstevel@tonic-gate free(cpc); 1360Sstevel@tonic-gate return (NULL); 1370Sstevel@tonic-gate } 1380Sstevel@tonic-gate 1390Sstevel@tonic-gate cpc->cpc_sets = NULL; 1400Sstevel@tonic-gate cpc->cpc_bufs = NULL; 1410Sstevel@tonic-gate cpc->cpc_errfn = NULL; 1420Sstevel@tonic-gate (void) mutex_init(&cpc->cpc_lock, USYNC_THREAD, NULL); 1430Sstevel@tonic-gate __pctx_cpc_register_callback(cpc_invalidate_pctx); 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate return (cpc); 1460Sstevel@tonic-gate } 1470Sstevel@tonic-gate 1480Sstevel@tonic-gate /* 1490Sstevel@tonic-gate * Ensure state is cleaned up: 1500Sstevel@tonic-gate * 1510Sstevel@tonic-gate * - Hardware is unbound 1520Sstevel@tonic-gate * - Sets are all destroyed 1530Sstevel@tonic-gate * - Bufs are all freed 1540Sstevel@tonic-gate */ 1550Sstevel@tonic-gate int 1560Sstevel@tonic-gate cpc_close(cpc_t *cpc) 1570Sstevel@tonic-gate { 1580Sstevel@tonic-gate while (cpc->cpc_sets != NULL) { 1590Sstevel@tonic-gate if (cpc->cpc_sets->cs_state != CS_UNBOUND) 1600Sstevel@tonic-gate (void) cpc_unbind(cpc, cpc->cpc_sets); 1610Sstevel@tonic-gate (void) cpc_set_destroy(cpc, cpc->cpc_sets); 1620Sstevel@tonic-gate } 1630Sstevel@tonic-gate 1640Sstevel@tonic-gate while (cpc->cpc_bufs != NULL) 1650Sstevel@tonic-gate (void) cpc_buf_destroy(cpc, cpc->cpc_bufs); 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate free(cpc); 1680Sstevel@tonic-gate return (0); 1690Sstevel@tonic-gate } 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate cpc_set_t * 1720Sstevel@tonic-gate cpc_set_create(cpc_t *cpc) 1730Sstevel@tonic-gate { 1740Sstevel@tonic-gate cpc_set_t *set; 1750Sstevel@tonic-gate int sigblocked; 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate if ((set = malloc(sizeof (*set))) == NULL) { 1780Sstevel@tonic-gate errno = ENOMEM; 1790Sstevel@tonic-gate return (NULL); 1800Sstevel@tonic-gate } 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate set->cs_request = NULL; 1830Sstevel@tonic-gate set->cs_nreqs = 0; 1840Sstevel@tonic-gate set->cs_state = CS_UNBOUND; 1850Sstevel@tonic-gate set->cs_fd = -1; 1860Sstevel@tonic-gate set->cs_pctx = NULL; 1870Sstevel@tonic-gate set->cs_id = -1; 1880Sstevel@tonic-gate set->cs_thr = NULL; 1890Sstevel@tonic-gate 1900Sstevel@tonic-gate sigblocked = cpc_lock(cpc); 1910Sstevel@tonic-gate set->cs_next = cpc->cpc_sets; 1920Sstevel@tonic-gate cpc->cpc_sets = set; 1930Sstevel@tonic-gate cpc_unlock(cpc, sigblocked); 1940Sstevel@tonic-gate 1950Sstevel@tonic-gate return (set); 1960Sstevel@tonic-gate } 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate int 1990Sstevel@tonic-gate cpc_set_destroy(cpc_t *cpc, cpc_set_t *set) 2000Sstevel@tonic-gate { 2010Sstevel@tonic-gate cpc_set_t *csp, *prev; 2020Sstevel@tonic-gate cpc_request_t *req, *next; 2030Sstevel@tonic-gate int sigblocked; 2040Sstevel@tonic-gate 2050Sstevel@tonic-gate /* 2060Sstevel@tonic-gate * Remove this set from the cpc handle's list of sets. 2070Sstevel@tonic-gate */ 2080Sstevel@tonic-gate sigblocked = cpc_lock(cpc); 2090Sstevel@tonic-gate for (csp = prev = cpc->cpc_sets; csp != NULL; csp = csp->cs_next) { 2100Sstevel@tonic-gate if (csp == set) 2110Sstevel@tonic-gate break; 2120Sstevel@tonic-gate prev = csp; 2130Sstevel@tonic-gate } 2140Sstevel@tonic-gate if (csp == NULL) { 2150Sstevel@tonic-gate cpc_unlock(cpc, sigblocked); 2160Sstevel@tonic-gate errno = EINVAL; 2170Sstevel@tonic-gate return (-1); 2180Sstevel@tonic-gate } 2190Sstevel@tonic-gate if (csp == cpc->cpc_sets) 2200Sstevel@tonic-gate cpc->cpc_sets = csp->cs_next; 2210Sstevel@tonic-gate prev->cs_next = csp->cs_next; 2220Sstevel@tonic-gate cpc_unlock(cpc, sigblocked); 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate if (csp->cs_state != CS_UNBOUND) 2250Sstevel@tonic-gate (void) cpc_unbind(cpc, csp); 2260Sstevel@tonic-gate 2270Sstevel@tonic-gate for (req = csp->cs_request; req != NULL; req = next) { 2280Sstevel@tonic-gate next = req->cr_next; 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate if (req->cr_nattrs != 0) 2310Sstevel@tonic-gate free(req->cr_attr); 2320Sstevel@tonic-gate 2330Sstevel@tonic-gate free(req); 2340Sstevel@tonic-gate } 2350Sstevel@tonic-gate 2360Sstevel@tonic-gate 2370Sstevel@tonic-gate free(set); 2380Sstevel@tonic-gate 2390Sstevel@tonic-gate return (0); 2400Sstevel@tonic-gate } 2410Sstevel@tonic-gate 2420Sstevel@tonic-gate /*ARGSUSED*/ 2430Sstevel@tonic-gate int 2440Sstevel@tonic-gate cpc_set_add_request(cpc_t *cpc, cpc_set_t *set, const char *event, 2450Sstevel@tonic-gate uint64_t preset, uint_t flags, uint_t nattrs, const cpc_attr_t *attrs) 2460Sstevel@tonic-gate { 2470Sstevel@tonic-gate cpc_request_t *req; 2480Sstevel@tonic-gate const char *fn = "cpc_set_add_request"; 2490Sstevel@tonic-gate int i; 2500Sstevel@tonic-gate int npics = cpc_npic(cpc); 2510Sstevel@tonic-gate 2520Sstevel@tonic-gate if (cpc_set_valid(cpc, set) != 0 || set->cs_state != CS_UNBOUND) { 2530Sstevel@tonic-gate errno = EINVAL; 2540Sstevel@tonic-gate return (-1); 2550Sstevel@tonic-gate } 2560Sstevel@tonic-gate 2570Sstevel@tonic-gate for (i = 0; i < npics; i++) 2580Sstevel@tonic-gate if (cpc_valid_event(cpc, i, event)) 2590Sstevel@tonic-gate break; 2600Sstevel@tonic-gate if (i == npics) { 2610Sstevel@tonic-gate cpc_err(cpc, fn, CPC_INVALID_EVENT); 2620Sstevel@tonic-gate errno = EINVAL; 2630Sstevel@tonic-gate return (-1); 2640Sstevel@tonic-gate } 2650Sstevel@tonic-gate 2660Sstevel@tonic-gate if ((req = malloc(sizeof (*req))) == NULL) { 2670Sstevel@tonic-gate errno = ENOMEM; 2680Sstevel@tonic-gate return (-1); 2690Sstevel@tonic-gate } 2700Sstevel@tonic-gate 2710Sstevel@tonic-gate (void) strncpy(req->cr_event, event, CPC_MAX_EVENT_LEN); 2720Sstevel@tonic-gate req->cr_preset = preset; 2730Sstevel@tonic-gate req->cr_flags = flags; 2740Sstevel@tonic-gate req->cr_nattrs = nattrs; 2750Sstevel@tonic-gate req->cr_index = set->cs_nreqs; 2760Sstevel@tonic-gate req->cr_attr = NULL; 2770Sstevel@tonic-gate 2780Sstevel@tonic-gate if (nattrs != 0) { 2790Sstevel@tonic-gate for (i = 0; i < nattrs; i++) { 2800Sstevel@tonic-gate /* 2810Sstevel@tonic-gate * Verify that each attribute name is legal and valid. 2820Sstevel@tonic-gate */ 2830Sstevel@tonic-gate if (attrs[i].ca_name[0] == '\0' || 2840Sstevel@tonic-gate cpc_valid_attr(cpc, attrs[i].ca_name) == 0) { 2850Sstevel@tonic-gate cpc_err(cpc, fn, CPC_INVALID_ATTRIBUTE); 2860Sstevel@tonic-gate goto inval; 2870Sstevel@tonic-gate } 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate /* 2900Sstevel@tonic-gate * If the user requested a specific picnum, ensure that 2910Sstevel@tonic-gate * the pic can count the requested event. 2920Sstevel@tonic-gate */ 2930Sstevel@tonic-gate if (strncmp("picnum", attrs[i].ca_name, 8) == 0) { 2940Sstevel@tonic-gate if (attrs[i].ca_val >= npics) { 2950Sstevel@tonic-gate cpc_err(cpc, fn, CPC_INVALID_PICNUM); 2960Sstevel@tonic-gate goto inval; 2970Sstevel@tonic-gate } 2980Sstevel@tonic-gate 2990Sstevel@tonic-gate if (cpc_valid_event(cpc, attrs[i].ca_val, 3000Sstevel@tonic-gate req->cr_event) == 0) { 3010Sstevel@tonic-gate cpc_err(cpc, fn, CPC_PIC_NOT_CAPABLE); 3020Sstevel@tonic-gate goto inval; 3030Sstevel@tonic-gate } 3040Sstevel@tonic-gate } 3050Sstevel@tonic-gate } 3060Sstevel@tonic-gate 3070Sstevel@tonic-gate if ((req->cr_attr = malloc(nattrs * sizeof (kcpc_attr_t))) 3080Sstevel@tonic-gate == NULL) { 3090Sstevel@tonic-gate free(req); 3100Sstevel@tonic-gate return (-1); 3110Sstevel@tonic-gate } 3120Sstevel@tonic-gate 3130Sstevel@tonic-gate for (i = 0; i < nattrs; i++) { 3140Sstevel@tonic-gate req->cr_attr[i].ka_val = attrs[i].ca_val; 3150Sstevel@tonic-gate (void) strncpy(req->cr_attr[i].ka_name, 3160Sstevel@tonic-gate attrs[i].ca_name, CPC_MAX_ATTR_LEN); 3170Sstevel@tonic-gate } 3180Sstevel@tonic-gate } else 3190Sstevel@tonic-gate req->cr_attr = NULL; 3200Sstevel@tonic-gate 3210Sstevel@tonic-gate req->cr_next = set->cs_request; 3220Sstevel@tonic-gate set->cs_request = req; 3230Sstevel@tonic-gate set->cs_nreqs++; 3240Sstevel@tonic-gate 3250Sstevel@tonic-gate return (req->cr_index); 3260Sstevel@tonic-gate 3270Sstevel@tonic-gate inval: 3280Sstevel@tonic-gate free(req); 3290Sstevel@tonic-gate errno = EINVAL; 3300Sstevel@tonic-gate return (-1); 3310Sstevel@tonic-gate } 3320Sstevel@tonic-gate 3330Sstevel@tonic-gate cpc_buf_t * 3340Sstevel@tonic-gate cpc_buf_create(cpc_t *cpc, cpc_set_t *set) 3350Sstevel@tonic-gate { 3360Sstevel@tonic-gate cpc_buf_t *buf; 3370Sstevel@tonic-gate int sigblocked; 3380Sstevel@tonic-gate 3390Sstevel@tonic-gate if (cpc_set_valid(cpc, set) != 0) { 3400Sstevel@tonic-gate errno = EINVAL; 3410Sstevel@tonic-gate return (NULL); 3420Sstevel@tonic-gate } 3430Sstevel@tonic-gate 3440Sstevel@tonic-gate if ((buf = malloc(sizeof (*buf))) == NULL) 3450Sstevel@tonic-gate return (NULL); 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate buf->cb_size = set->cs_nreqs * sizeof (uint64_t); 3480Sstevel@tonic-gate if ((buf->cb_data = malloc(buf->cb_size)) == NULL) { 3490Sstevel@tonic-gate free(buf); 3500Sstevel@tonic-gate return (NULL); 3510Sstevel@tonic-gate } 3520Sstevel@tonic-gate 3530Sstevel@tonic-gate bzero(buf->cb_data, buf->cb_size); 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate buf->cb_hrtime = 0; 3560Sstevel@tonic-gate buf->cb_tick = 0; 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate sigblocked = cpc_lock(cpc); 3590Sstevel@tonic-gate buf->cb_next = cpc->cpc_bufs; 3600Sstevel@tonic-gate cpc->cpc_bufs = buf; 3610Sstevel@tonic-gate cpc_unlock(cpc, sigblocked); 3620Sstevel@tonic-gate 3630Sstevel@tonic-gate return (buf); 3640Sstevel@tonic-gate } 3650Sstevel@tonic-gate 3660Sstevel@tonic-gate int 3670Sstevel@tonic-gate cpc_buf_destroy(cpc_t *cpc, cpc_buf_t *buf) 3680Sstevel@tonic-gate { 3690Sstevel@tonic-gate cpc_buf_t *cbp, *prev; 3700Sstevel@tonic-gate int sigblocked; 3710Sstevel@tonic-gate 3720Sstevel@tonic-gate /* 3730Sstevel@tonic-gate * Remove this buf from the cpc handle's list of bufs. 3740Sstevel@tonic-gate */ 3750Sstevel@tonic-gate sigblocked = cpc_lock(cpc); 3760Sstevel@tonic-gate for (cbp = prev = cpc->cpc_bufs; cbp != NULL; cbp = cbp->cb_next) { 3770Sstevel@tonic-gate if (cbp == buf) 3780Sstevel@tonic-gate break; 3790Sstevel@tonic-gate prev = cbp; 3800Sstevel@tonic-gate } 3810Sstevel@tonic-gate if (cbp == NULL) { 3820Sstevel@tonic-gate cpc_unlock(cpc, sigblocked); 3830Sstevel@tonic-gate errno = EINVAL; 3840Sstevel@tonic-gate return (-1); 3850Sstevel@tonic-gate } 3860Sstevel@tonic-gate if (cbp == cpc->cpc_bufs) 3870Sstevel@tonic-gate cpc->cpc_bufs = cbp->cb_next; 3880Sstevel@tonic-gate prev->cb_next = cbp->cb_next; 3890Sstevel@tonic-gate 3900Sstevel@tonic-gate cpc_unlock(cpc, sigblocked); 3910Sstevel@tonic-gate free(cbp->cb_data); 3920Sstevel@tonic-gate free(cbp); 3930Sstevel@tonic-gate 3940Sstevel@tonic-gate return (0); 3950Sstevel@tonic-gate } 3960Sstevel@tonic-gate 3970Sstevel@tonic-gate /*ARGSUSED*/ 3980Sstevel@tonic-gate int 3990Sstevel@tonic-gate cpc_bind_curlwp(cpc_t *cpc, cpc_set_t *set, uint_t flags) 4000Sstevel@tonic-gate { 4010Sstevel@tonic-gate char *packed_set; 4020Sstevel@tonic-gate size_t packsize; 4030Sstevel@tonic-gate int ret; 4040Sstevel@tonic-gate int subcode = -1; 4050Sstevel@tonic-gate 4060Sstevel@tonic-gate /* 4070Sstevel@tonic-gate * We don't bother checking cpc_set_valid() here, because this is in the 4080Sstevel@tonic-gate * fast path of an app doing SIGEMT-based profiling as they restart the 4090Sstevel@tonic-gate * counters from their signal handler. 4100Sstevel@tonic-gate */ 4110Sstevel@tonic-gate if (CPC_SET_VALID_FLAGS(flags) == 0 || set->cs_nreqs <= 0) { 4120Sstevel@tonic-gate errno = EINVAL; 4130Sstevel@tonic-gate return (-1); 4140Sstevel@tonic-gate } 4150Sstevel@tonic-gate 4160Sstevel@tonic-gate if ((packed_set = __cpc_pack_set(set, flags, &packsize)) == NULL) { 4170Sstevel@tonic-gate errno = ENOMEM; 4180Sstevel@tonic-gate return (-1); 4190Sstevel@tonic-gate } 4200Sstevel@tonic-gate 4210Sstevel@tonic-gate ret = syscall(SYS_cpc, CPC_BIND, -1, packed_set, packsize, &subcode); 4220Sstevel@tonic-gate free(packed_set); 4230Sstevel@tonic-gate 4240Sstevel@tonic-gate if (ret != 0) { 4250Sstevel@tonic-gate if (subcode != -1) 4260Sstevel@tonic-gate cpc_err(cpc, "cpc_bind_curlwp", subcode); 4270Sstevel@tonic-gate return (-1); 4280Sstevel@tonic-gate } 4290Sstevel@tonic-gate 4300Sstevel@tonic-gate set->cs_thr = thr_self(); 4310Sstevel@tonic-gate set->cs_state = CS_BOUND_CURLWP; 4320Sstevel@tonic-gate return (ret); 4330Sstevel@tonic-gate } 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate /*ARGSUSED*/ 4360Sstevel@tonic-gate int 4370Sstevel@tonic-gate cpc_bind_pctx(cpc_t *cpc, pctx_t *pctx, id_t id, cpc_set_t *set, uint_t flags) 4380Sstevel@tonic-gate { 4390Sstevel@tonic-gate char *packed_set; 4400Sstevel@tonic-gate size_t packsize; 4410Sstevel@tonic-gate int ret; 4420Sstevel@tonic-gate int subcode = -1; 4430Sstevel@tonic-gate 4440Sstevel@tonic-gate /* 4450Sstevel@tonic-gate * cpc_bind_pctx() currently has no valid flags. 4460Sstevel@tonic-gate */ 4470Sstevel@tonic-gate if (flags != 0 || cpc_set_valid(cpc, set) != 0 || set->cs_nreqs <= 0) { 4480Sstevel@tonic-gate errno = EINVAL; 4490Sstevel@tonic-gate return (-1); 4500Sstevel@tonic-gate } 4510Sstevel@tonic-gate 4520Sstevel@tonic-gate if ((packed_set = __cpc_pack_set(set, flags, &packsize)) == NULL) { 4530Sstevel@tonic-gate errno = ENOMEM; 4540Sstevel@tonic-gate return (-1); 4550Sstevel@tonic-gate } 4560Sstevel@tonic-gate 4570Sstevel@tonic-gate ret = __pctx_cpc(pctx, cpc, CPC_BIND, id, packed_set, (void *)packsize, 4580Sstevel@tonic-gate (void *)&subcode, -1); 4590Sstevel@tonic-gate 4600Sstevel@tonic-gate free(packed_set); 4610Sstevel@tonic-gate 4620Sstevel@tonic-gate if (ret == 0) { 4630Sstevel@tonic-gate set->cs_pctx = pctx; 4640Sstevel@tonic-gate set->cs_id = id; 4650Sstevel@tonic-gate set->cs_state = CS_BOUND_PCTX; 4660Sstevel@tonic-gate } else if (subcode != -1) 4670Sstevel@tonic-gate cpc_err(cpc, "cpc_bind_pctx", subcode); 4680Sstevel@tonic-gate 4690Sstevel@tonic-gate return (ret); 4700Sstevel@tonic-gate } 4710Sstevel@tonic-gate 4720Sstevel@tonic-gate /*ARGSUSED*/ 4730Sstevel@tonic-gate int 4740Sstevel@tonic-gate cpc_bind_cpu(cpc_t *cpc, processorid_t id, cpc_set_t *set, uint_t flags) 4750Sstevel@tonic-gate { 4760Sstevel@tonic-gate int fd; 4770Sstevel@tonic-gate char *packed_set; 4780Sstevel@tonic-gate size_t packsize; 4790Sstevel@tonic-gate __cpc_args_t cpc_args; 4800Sstevel@tonic-gate int error; 4810Sstevel@tonic-gate const char *fn = "cpc_bind_cpu"; 4820Sstevel@tonic-gate int subcode = -1; 4830Sstevel@tonic-gate 4840Sstevel@tonic-gate /* 4850Sstevel@tonic-gate * cpc_bind_cpu() currently has no valid flags. 4860Sstevel@tonic-gate */ 4870Sstevel@tonic-gate if (flags != 0 || cpc_set_valid(cpc, set) != 0 || set->cs_nreqs <= 0) { 4880Sstevel@tonic-gate errno = EINVAL; 4890Sstevel@tonic-gate return (-1); 4900Sstevel@tonic-gate } 4910Sstevel@tonic-gate 4920Sstevel@tonic-gate if (processor_bind(P_LWPID, P_MYID, id, &set->cs_obind) == -1) { 4930Sstevel@tonic-gate cpc_err(cpc, fn, CPC_PBIND_FAILED); 4940Sstevel@tonic-gate return (-1); 4950Sstevel@tonic-gate } 4960Sstevel@tonic-gate 4970Sstevel@tonic-gate if ((fd = open(CPUDRV_SHARED, O_RDWR)) < 0) { 4980Sstevel@tonic-gate error = errno; 4990Sstevel@tonic-gate (void) processor_bind(P_LWPID, P_MYID, set->cs_obind, NULL); 5000Sstevel@tonic-gate errno = error; 5010Sstevel@tonic-gate return (-1); 5020Sstevel@tonic-gate } 5030Sstevel@tonic-gate 5040Sstevel@tonic-gate /* 5050Sstevel@tonic-gate * To avoid leaking file descriptors, if we find an existing fd here we 5060Sstevel@tonic-gate * just close it. This is only a problem if a user attempts to bind the 5070Sstevel@tonic-gate * same set to different CPUs without first unbinding it. 5080Sstevel@tonic-gate */ 5090Sstevel@tonic-gate if (set->cs_fd != -1) 5100Sstevel@tonic-gate (void) close(set->cs_fd); 5110Sstevel@tonic-gate set->cs_fd = fd; 5120Sstevel@tonic-gate 5130Sstevel@tonic-gate if ((packed_set = __cpc_pack_set(set, flags, &packsize)) == NULL) { 5140Sstevel@tonic-gate (void) close(fd); 5150Sstevel@tonic-gate (void) processor_bind(P_LWPID, P_MYID, set->cs_obind, NULL); 5160Sstevel@tonic-gate errno = ENOMEM; 5170Sstevel@tonic-gate return (-1); 5180Sstevel@tonic-gate } 5190Sstevel@tonic-gate 5200Sstevel@tonic-gate cpc_args.udata1 = packed_set; 5210Sstevel@tonic-gate cpc_args.udata2 = (void *)packsize; 5220Sstevel@tonic-gate cpc_args.udata3 = (void *)&subcode; 5230Sstevel@tonic-gate 5240Sstevel@tonic-gate if (ioctl(fd, CPCIO_BIND, &cpc_args) != 0) { 5250Sstevel@tonic-gate error = errno; 5260Sstevel@tonic-gate free(packed_set); 5270Sstevel@tonic-gate (void) close(fd); 5280Sstevel@tonic-gate (void) processor_bind(P_LWPID, P_MYID, set->cs_obind, NULL); 5290Sstevel@tonic-gate if (subcode != -1) 5300Sstevel@tonic-gate cpc_err(cpc, fn, subcode); 5310Sstevel@tonic-gate errno = error; 5320Sstevel@tonic-gate return (-1); 5330Sstevel@tonic-gate } 5340Sstevel@tonic-gate 5350Sstevel@tonic-gate free(packed_set); 5360Sstevel@tonic-gate 5370Sstevel@tonic-gate set->cs_thr = thr_self(); 5380Sstevel@tonic-gate set->cs_state = CS_BOUND_CPU; 5390Sstevel@tonic-gate 5400Sstevel@tonic-gate return (0); 5410Sstevel@tonic-gate } 5420Sstevel@tonic-gate 5430Sstevel@tonic-gate /*ARGSUSED*/ 5440Sstevel@tonic-gate int 5450Sstevel@tonic-gate cpc_request_preset(cpc_t *cpc, int index, uint64_t preset) 5460Sstevel@tonic-gate { 5470Sstevel@tonic-gate return (syscall(SYS_cpc, CPC_PRESET, -1, index, 5480Sstevel@tonic-gate (uint32_t)(preset >> 32), (uint32_t)(preset & MASK32))); 5490Sstevel@tonic-gate } 5500Sstevel@tonic-gate 5510Sstevel@tonic-gate /*ARGSUSED*/ 5520Sstevel@tonic-gate int 5530Sstevel@tonic-gate cpc_set_restart(cpc_t *cpc, cpc_set_t *set) 5540Sstevel@tonic-gate { 5550Sstevel@tonic-gate return (syscall(SYS_cpc, CPC_RESTART, -1, 0, 0, 0)); 5560Sstevel@tonic-gate } 5570Sstevel@tonic-gate 5580Sstevel@tonic-gate /*ARGSUSED*/ 5590Sstevel@tonic-gate int 5600Sstevel@tonic-gate cpc_unbind(cpc_t *cpc, cpc_set_t *set) 5610Sstevel@tonic-gate { 5620Sstevel@tonic-gate int ret = 0; 5630Sstevel@tonic-gate int error; 5640Sstevel@tonic-gate 5650Sstevel@tonic-gate if (cpc_set_valid(cpc, set) != 0) { 5660Sstevel@tonic-gate errno = EINVAL; 5670Sstevel@tonic-gate return (-1); 5680Sstevel@tonic-gate } 5690Sstevel@tonic-gate 5700Sstevel@tonic-gate switch (set->cs_state) { 5710Sstevel@tonic-gate case CS_UNBOUND: 5720Sstevel@tonic-gate errno = EINVAL; 5730Sstevel@tonic-gate return (-1); 5740Sstevel@tonic-gate case CS_BOUND_CURLWP: 5750Sstevel@tonic-gate ret = syscall(SYS_cpc, CPC_RELE, -1, 0, 0, 0); 5760Sstevel@tonic-gate error = errno; 5770Sstevel@tonic-gate break; 5780Sstevel@tonic-gate case CS_BOUND_CPU: 5790Sstevel@tonic-gate ret = ioctl(set->cs_fd, CPCIO_RELE, NULL); 5800Sstevel@tonic-gate error = errno; 5810Sstevel@tonic-gate (void) close(set->cs_fd); 5820Sstevel@tonic-gate set->cs_fd = -1; 5830Sstevel@tonic-gate (void) processor_bind(P_LWPID, P_MYID, set->cs_obind, NULL); 5840Sstevel@tonic-gate break; 5850Sstevel@tonic-gate case CS_BOUND_PCTX: 5860Sstevel@tonic-gate if (set->cs_pctx != NULL) { 5870Sstevel@tonic-gate ret = __pctx_cpc(set->cs_pctx, cpc, CPC_RELE, 5880Sstevel@tonic-gate set->cs_id, 0, 0, 0, 0); 5890Sstevel@tonic-gate error = errno; 5900Sstevel@tonic-gate } 5910Sstevel@tonic-gate break; 5920Sstevel@tonic-gate } 5930Sstevel@tonic-gate 5940Sstevel@tonic-gate set->cs_thr = NULL; 5950Sstevel@tonic-gate set->cs_id = -1; 5960Sstevel@tonic-gate set->cs_state = CS_UNBOUND; 5970Sstevel@tonic-gate if (ret != 0) 5980Sstevel@tonic-gate errno = error; 5990Sstevel@tonic-gate return (ret); 6000Sstevel@tonic-gate } 6010Sstevel@tonic-gate 6020Sstevel@tonic-gate /*ARGSUSED*/ 6030Sstevel@tonic-gate int 6040Sstevel@tonic-gate cpc_set_sample(cpc_t *cpc, cpc_set_t *set, cpc_buf_t *buf) 6050Sstevel@tonic-gate { 6060Sstevel@tonic-gate __cpc_args_t args; 6070Sstevel@tonic-gate 6080Sstevel@tonic-gate /* 6090Sstevel@tonic-gate * The following check ensures that only the most recently bound set 6100Sstevel@tonic-gate * can be sampled, as binding a set invalidates all other sets in the 6110Sstevel@tonic-gate * cpc_t. 6120Sstevel@tonic-gate */ 6130Sstevel@tonic-gate if (set->cs_state == CS_UNBOUND || 6140Sstevel@tonic-gate buf->cb_size != set->cs_nreqs * sizeof (uint64_t)) { 6150Sstevel@tonic-gate errno = EINVAL; 6160Sstevel@tonic-gate return (-1); 6170Sstevel@tonic-gate } 6180Sstevel@tonic-gate 6190Sstevel@tonic-gate switch (set->cs_state) { 6200Sstevel@tonic-gate case CS_BOUND_CURLWP: 6210Sstevel@tonic-gate return (syscall(SYS_cpc, CPC_SAMPLE, -1, buf->cb_data, 6220Sstevel@tonic-gate &buf->cb_hrtime, &buf->cb_tick)); 6230Sstevel@tonic-gate case CS_BOUND_CPU: 6240Sstevel@tonic-gate args.udata1 = buf->cb_data; 6250Sstevel@tonic-gate args.udata2 = &buf->cb_hrtime; 6260Sstevel@tonic-gate args.udata3 = &buf->cb_tick; 6270Sstevel@tonic-gate return (ioctl(set->cs_fd, CPCIO_SAMPLE, &args)); 6280Sstevel@tonic-gate case CS_BOUND_PCTX: 6290Sstevel@tonic-gate return (__pctx_cpc(set->cs_pctx, cpc, CPC_SAMPLE, set->cs_id, 6300Sstevel@tonic-gate buf->cb_data, &buf->cb_hrtime, &buf->cb_tick, 6310Sstevel@tonic-gate buf->cb_size)); 6320Sstevel@tonic-gate } 6330Sstevel@tonic-gate 6340Sstevel@tonic-gate errno = EINVAL; 6350Sstevel@tonic-gate return (-1); 6360Sstevel@tonic-gate } 6370Sstevel@tonic-gate 6380Sstevel@tonic-gate /*ARGSUSED*/ 6390Sstevel@tonic-gate void 6400Sstevel@tonic-gate cpc_buf_sub(cpc_t *cpc, cpc_buf_t *ds, cpc_buf_t *a, cpc_buf_t *b) 6410Sstevel@tonic-gate { 6420Sstevel@tonic-gate int i; 6430Sstevel@tonic-gate 6440Sstevel@tonic-gate if (a->cb_size != ds->cb_size || b->cb_size != ds->cb_size) 6450Sstevel@tonic-gate return; 6460Sstevel@tonic-gate 6470Sstevel@tonic-gate ds->cb_hrtime = (a->cb_hrtime > b->cb_hrtime) ? 6480Sstevel@tonic-gate a->cb_hrtime : b->cb_hrtime; 6490Sstevel@tonic-gate ds->cb_tick = a->cb_tick - b->cb_tick; 6500Sstevel@tonic-gate 6510Sstevel@tonic-gate for (i = 0; i < ds->cb_size / sizeof (uint64_t); i++) 6520Sstevel@tonic-gate ds->cb_data[i] = a->cb_data[i] - b->cb_data[i]; 6530Sstevel@tonic-gate } 6540Sstevel@tonic-gate 6550Sstevel@tonic-gate /*ARGSUSED*/ 6560Sstevel@tonic-gate void 6570Sstevel@tonic-gate cpc_buf_add(cpc_t *cpc, cpc_buf_t *ds, cpc_buf_t *a, cpc_buf_t *b) 6580Sstevel@tonic-gate { 6590Sstevel@tonic-gate int i; 6600Sstevel@tonic-gate 6610Sstevel@tonic-gate if (a->cb_size != ds->cb_size || b->cb_size != ds->cb_size) 6620Sstevel@tonic-gate return; 6630Sstevel@tonic-gate 6640Sstevel@tonic-gate ds->cb_hrtime = (a->cb_hrtime > b->cb_hrtime) ? 6650Sstevel@tonic-gate a->cb_hrtime : b->cb_hrtime; 6660Sstevel@tonic-gate ds->cb_tick = a->cb_tick + b->cb_tick; 6670Sstevel@tonic-gate 6680Sstevel@tonic-gate for (i = 0; i < ds->cb_size / sizeof (uint64_t); i++) 6690Sstevel@tonic-gate ds->cb_data[i] = a->cb_data[i] + b->cb_data[i]; 6700Sstevel@tonic-gate } 6710Sstevel@tonic-gate 6720Sstevel@tonic-gate /*ARGSUSED*/ 6730Sstevel@tonic-gate void 6740Sstevel@tonic-gate cpc_buf_copy(cpc_t *cpc, cpc_buf_t *ds, cpc_buf_t *src) 6750Sstevel@tonic-gate { 6760Sstevel@tonic-gate if (ds->cb_size != src->cb_size) 6770Sstevel@tonic-gate return; 6780Sstevel@tonic-gate 6790Sstevel@tonic-gate bcopy(src->cb_data, ds->cb_data, ds->cb_size); 6800Sstevel@tonic-gate ds->cb_hrtime = src->cb_hrtime; 6810Sstevel@tonic-gate ds->cb_tick = src->cb_tick; 6820Sstevel@tonic-gate } 6830Sstevel@tonic-gate 6840Sstevel@tonic-gate /*ARGSUSED*/ 6850Sstevel@tonic-gate void 6860Sstevel@tonic-gate cpc_buf_zero(cpc_t *cpc, cpc_buf_t *buf) 6870Sstevel@tonic-gate { 6880Sstevel@tonic-gate bzero(buf->cb_data, buf->cb_size); 6890Sstevel@tonic-gate buf->cb_hrtime = 0; 6900Sstevel@tonic-gate buf->cb_tick = 0; 6910Sstevel@tonic-gate } 6920Sstevel@tonic-gate 6930Sstevel@tonic-gate /* 6940Sstevel@tonic-gate * Gets or sets the value of the request specified by index. 6950Sstevel@tonic-gate */ 6960Sstevel@tonic-gate /*ARGSUSED*/ 6970Sstevel@tonic-gate int 6980Sstevel@tonic-gate cpc_buf_get(cpc_t *cpc, cpc_buf_t *buf, int index, uint64_t *val) 6990Sstevel@tonic-gate { 7000Sstevel@tonic-gate *val = buf->cb_data[index]; 7010Sstevel@tonic-gate 7020Sstevel@tonic-gate return (0); 7030Sstevel@tonic-gate } 7040Sstevel@tonic-gate 7050Sstevel@tonic-gate /*ARGSUSED*/ 7060Sstevel@tonic-gate int 7070Sstevel@tonic-gate cpc_buf_set(cpc_t *cpc, cpc_buf_t *buf, int index, uint64_t val) 7080Sstevel@tonic-gate { 7090Sstevel@tonic-gate buf->cb_data[index] = val; 7100Sstevel@tonic-gate 7110Sstevel@tonic-gate return (0); 7120Sstevel@tonic-gate } 7130Sstevel@tonic-gate 7140Sstevel@tonic-gate /*ARGSUSED*/ 7150Sstevel@tonic-gate hrtime_t 7160Sstevel@tonic-gate cpc_buf_hrtime(cpc_t *cpc, cpc_buf_t *buf) 7170Sstevel@tonic-gate { 7180Sstevel@tonic-gate return (buf->cb_hrtime); 7190Sstevel@tonic-gate } 7200Sstevel@tonic-gate 7210Sstevel@tonic-gate /*ARGSUSED*/ 7220Sstevel@tonic-gate uint64_t 7230Sstevel@tonic-gate cpc_buf_tick(cpc_t *cpc, cpc_buf_t *buf) 7240Sstevel@tonic-gate { 7250Sstevel@tonic-gate return (buf->cb_tick); 7260Sstevel@tonic-gate } 7270Sstevel@tonic-gate 7280Sstevel@tonic-gate static char * 7290Sstevel@tonic-gate cpc_get_list(int which, int arg) 7300Sstevel@tonic-gate { 7310Sstevel@tonic-gate int szcmd; 7320Sstevel@tonic-gate int size; 7330Sstevel@tonic-gate char *list; 7340Sstevel@tonic-gate 7350Sstevel@tonic-gate if (which == CPC_LIST_ATTRS) 7360Sstevel@tonic-gate szcmd = CPC_ATTRLIST_SIZE; 7370Sstevel@tonic-gate else 7380Sstevel@tonic-gate szcmd = CPC_EVLIST_SIZE; 7390Sstevel@tonic-gate 7400Sstevel@tonic-gate if (syscall(SYS_cpc, szcmd, -1, &size, arg, 0) != 0) 7410Sstevel@tonic-gate return (NULL); 7420Sstevel@tonic-gate 7430Sstevel@tonic-gate if ((list = malloc(size)) == NULL) 7440Sstevel@tonic-gate return (NULL); 7450Sstevel@tonic-gate 7460Sstevel@tonic-gate if (syscall(SYS_cpc, which, -1, list, arg, 0) != 0) { 7470Sstevel@tonic-gate free(list); 7480Sstevel@tonic-gate return (NULL); 7490Sstevel@tonic-gate } 7500Sstevel@tonic-gate 7510Sstevel@tonic-gate return (list); 7520Sstevel@tonic-gate } 7530Sstevel@tonic-gate 7540Sstevel@tonic-gate /*ARGSUSED*/ 7550Sstevel@tonic-gate void 7560Sstevel@tonic-gate cpc_walk_requests(cpc_t *cpc, cpc_set_t *set, void *arg, 7570Sstevel@tonic-gate void (*action)(void *arg, int index, const char *event, uint64_t preset, 7580Sstevel@tonic-gate uint_t flags, int nattrs, const cpc_attr_t *attrs)) 7590Sstevel@tonic-gate { 7600Sstevel@tonic-gate cpc_request_t *rp; 7610Sstevel@tonic-gate cpc_attr_t *attrs = NULL; 7620Sstevel@tonic-gate int i; 7630Sstevel@tonic-gate 7640Sstevel@tonic-gate for (rp = set->cs_request; rp != NULL; rp = rp->cr_next) { 7650Sstevel@tonic-gate /* 7660Sstevel@tonic-gate * Need to reconstruct a temporary cpc_attr_t array for req. 7670Sstevel@tonic-gate */ 7680Sstevel@tonic-gate if (rp->cr_nattrs != 0) 7690Sstevel@tonic-gate if ((attrs = malloc(rp->cr_nattrs * 7700Sstevel@tonic-gate sizeof (cpc_attr_t))) == NULL) 7710Sstevel@tonic-gate return; 7720Sstevel@tonic-gate for (i = 0; i < rp->cr_nattrs; i++) { 7730Sstevel@tonic-gate attrs[i].ca_name = rp->cr_attr[i].ka_name; 7740Sstevel@tonic-gate attrs[i].ca_val = rp->cr_attr[i].ka_val; 7750Sstevel@tonic-gate } 7760Sstevel@tonic-gate 7770Sstevel@tonic-gate action(arg, rp->cr_index, rp->cr_event, rp->cr_preset, 7780Sstevel@tonic-gate rp->cr_flags, rp->cr_nattrs, attrs); 7790Sstevel@tonic-gate 7800Sstevel@tonic-gate if (rp->cr_nattrs != 0) 7810Sstevel@tonic-gate free(attrs); 7820Sstevel@tonic-gate } 7830Sstevel@tonic-gate } 7840Sstevel@tonic-gate 7850Sstevel@tonic-gate /*ARGSUSED*/ 7860Sstevel@tonic-gate void 7870Sstevel@tonic-gate cpc_walk_events_all(cpc_t *cpc, void *arg, 7880Sstevel@tonic-gate void (*action)(void *arg, const char *event)) 7890Sstevel@tonic-gate { 7900Sstevel@tonic-gate char **list; 7910Sstevel@tonic-gate char *p, *e; 7920Sstevel@tonic-gate int i; 7930Sstevel@tonic-gate int ncounters = cpc_npic(cpc); 7940Sstevel@tonic-gate cpc_strhash_t *hash; 7950Sstevel@tonic-gate 7960Sstevel@tonic-gate if ((list = malloc(ncounters * sizeof (char *))) == NULL) 7970Sstevel@tonic-gate return; 7980Sstevel@tonic-gate 7990Sstevel@tonic-gate if ((hash = __cpc_strhash_alloc()) == NULL) { 8000Sstevel@tonic-gate free(list); 8010Sstevel@tonic-gate return; 8020Sstevel@tonic-gate } 8030Sstevel@tonic-gate 8040Sstevel@tonic-gate for (i = 0; i < ncounters; i++) { 8050Sstevel@tonic-gate if ((list[i] = strdup(cpc->cpc_evlist[i])) == NULL) 8060Sstevel@tonic-gate goto err; 8070Sstevel@tonic-gate p = list[i]; 8080Sstevel@tonic-gate while ((e = strchr(p, ',')) != NULL) { 8090Sstevel@tonic-gate *e = '\0'; 810*7640SJonathan.Haslam@Sun.COM 811*7640SJonathan.Haslam@Sun.COM /* Skip any generic event names we find. */ 812*7640SJonathan.Haslam@Sun.COM if ((strncmp(p, "PAPI", 4)) == 0) { 813*7640SJonathan.Haslam@Sun.COM p = e + 1; 814*7640SJonathan.Haslam@Sun.COM continue; 815*7640SJonathan.Haslam@Sun.COM } 816*7640SJonathan.Haslam@Sun.COM 8170Sstevel@tonic-gate if (__cpc_strhash_add(hash, p) == -1) 8180Sstevel@tonic-gate goto err; 8190Sstevel@tonic-gate p = e + 1; 8200Sstevel@tonic-gate } 821*7640SJonathan.Haslam@Sun.COM if ((strncmp(p, "PAPI", 4)) != 0) { 822*7640SJonathan.Haslam@Sun.COM if (__cpc_strhash_add(hash, p) == -1) 823*7640SJonathan.Haslam@Sun.COM goto err; 824*7640SJonathan.Haslam@Sun.COM } 825*7640SJonathan.Haslam@Sun.COM } 826*7640SJonathan.Haslam@Sun.COM 827*7640SJonathan.Haslam@Sun.COM while ((p = __cpc_strhash_next(hash)) != NULL) 828*7640SJonathan.Haslam@Sun.COM action(arg, p); 829*7640SJonathan.Haslam@Sun.COM 830*7640SJonathan.Haslam@Sun.COM err: 831*7640SJonathan.Haslam@Sun.COM __cpc_strhash_free(hash); 832*7640SJonathan.Haslam@Sun.COM for (i = 0; i < ncounters; i++) 833*7640SJonathan.Haslam@Sun.COM free(list[i]); 834*7640SJonathan.Haslam@Sun.COM free(list); 835*7640SJonathan.Haslam@Sun.COM } 836*7640SJonathan.Haslam@Sun.COM 837*7640SJonathan.Haslam@Sun.COM /*ARGSUSED*/ 838*7640SJonathan.Haslam@Sun.COM void 839*7640SJonathan.Haslam@Sun.COM cpc_walk_generic_events_all(cpc_t *cpc, void *arg, 840*7640SJonathan.Haslam@Sun.COM void (*action)(void *arg, const char *event)) 841*7640SJonathan.Haslam@Sun.COM { 842*7640SJonathan.Haslam@Sun.COM char **list; 843*7640SJonathan.Haslam@Sun.COM char *p, *e; 844*7640SJonathan.Haslam@Sun.COM int i; 845*7640SJonathan.Haslam@Sun.COM int ncounters = cpc_npic(cpc); 846*7640SJonathan.Haslam@Sun.COM cpc_strhash_t *hash; 847*7640SJonathan.Haslam@Sun.COM 848*7640SJonathan.Haslam@Sun.COM if ((list = malloc(ncounters * sizeof (char *))) == NULL) 849*7640SJonathan.Haslam@Sun.COM return; 850*7640SJonathan.Haslam@Sun.COM 851*7640SJonathan.Haslam@Sun.COM if ((hash = __cpc_strhash_alloc()) == NULL) { 852*7640SJonathan.Haslam@Sun.COM free(list); 853*7640SJonathan.Haslam@Sun.COM return; 854*7640SJonathan.Haslam@Sun.COM } 855*7640SJonathan.Haslam@Sun.COM 856*7640SJonathan.Haslam@Sun.COM for (i = 0; i < ncounters; i++) { 857*7640SJonathan.Haslam@Sun.COM if ((list[i] = strdup(cpc->cpc_evlist[i])) == NULL) 8580Sstevel@tonic-gate goto err; 859*7640SJonathan.Haslam@Sun.COM p = list[i]; 860*7640SJonathan.Haslam@Sun.COM while ((e = strchr(p, ',')) != NULL) { 861*7640SJonathan.Haslam@Sun.COM *e = '\0'; 862*7640SJonathan.Haslam@Sun.COM 863*7640SJonathan.Haslam@Sun.COM /* Skip any platform specific event names we find. */ 864*7640SJonathan.Haslam@Sun.COM if ((strncmp(p, "PAPI", 4)) != 0) { 865*7640SJonathan.Haslam@Sun.COM p = e + 1; 866*7640SJonathan.Haslam@Sun.COM continue; 867*7640SJonathan.Haslam@Sun.COM } 868*7640SJonathan.Haslam@Sun.COM 869*7640SJonathan.Haslam@Sun.COM if (__cpc_strhash_add(hash, p) == -1) 870*7640SJonathan.Haslam@Sun.COM goto err; 871*7640SJonathan.Haslam@Sun.COM p = e + 1; 872*7640SJonathan.Haslam@Sun.COM } 873*7640SJonathan.Haslam@Sun.COM if ((strncmp(p, "PAPI", 4)) == 0) { 874*7640SJonathan.Haslam@Sun.COM if (__cpc_strhash_add(hash, p) == -1) 875*7640SJonathan.Haslam@Sun.COM goto err; 876*7640SJonathan.Haslam@Sun.COM } 8770Sstevel@tonic-gate } 8780Sstevel@tonic-gate 8790Sstevel@tonic-gate while ((p = __cpc_strhash_next(hash)) != NULL) 8800Sstevel@tonic-gate action(arg, p); 8810Sstevel@tonic-gate 8820Sstevel@tonic-gate err: 8830Sstevel@tonic-gate __cpc_strhash_free(hash); 8840Sstevel@tonic-gate for (i = 0; i < ncounters; i++) 8850Sstevel@tonic-gate free(list[i]); 8860Sstevel@tonic-gate free(list); 8870Sstevel@tonic-gate } 8880Sstevel@tonic-gate 8890Sstevel@tonic-gate /*ARGSUSED*/ 8900Sstevel@tonic-gate void 8910Sstevel@tonic-gate cpc_walk_events_pic(cpc_t *cpc, uint_t picno, void *arg, 8920Sstevel@tonic-gate void (*action)(void *arg, uint_t picno, const char *event)) 8930Sstevel@tonic-gate { 8940Sstevel@tonic-gate char *p; 8950Sstevel@tonic-gate char *e; 8960Sstevel@tonic-gate char *list; 8970Sstevel@tonic-gate 8980Sstevel@tonic-gate if (picno >= cpc->cpc_npic) { 8990Sstevel@tonic-gate errno = EINVAL; 9000Sstevel@tonic-gate return; 9010Sstevel@tonic-gate } 9020Sstevel@tonic-gate 9030Sstevel@tonic-gate if ((list = strdup(cpc->cpc_evlist[picno])) == NULL) 9040Sstevel@tonic-gate return; 9050Sstevel@tonic-gate 9060Sstevel@tonic-gate /* 9070Sstevel@tonic-gate * List now points to a comma-separated list of events supported by 9080Sstevel@tonic-gate * the designated pic. 9090Sstevel@tonic-gate */ 9100Sstevel@tonic-gate p = list; 9110Sstevel@tonic-gate while ((e = strchr(p, ',')) != NULL) { 9120Sstevel@tonic-gate *e = '\0'; 913*7640SJonathan.Haslam@Sun.COM 914*7640SJonathan.Haslam@Sun.COM /* Skip any generic event names we find. */ 915*7640SJonathan.Haslam@Sun.COM if ((strncmp(p, "PAPI", 4)) == 0) { 916*7640SJonathan.Haslam@Sun.COM p = e + 1; 917*7640SJonathan.Haslam@Sun.COM continue; 918*7640SJonathan.Haslam@Sun.COM } 919*7640SJonathan.Haslam@Sun.COM 9200Sstevel@tonic-gate action(arg, picno, p); 9210Sstevel@tonic-gate p = e + 1; 9220Sstevel@tonic-gate } 923*7640SJonathan.Haslam@Sun.COM 924*7640SJonathan.Haslam@Sun.COM if ((strncmp(p, "PAPI", 4)) == 0) 925*7640SJonathan.Haslam@Sun.COM goto out; 926*7640SJonathan.Haslam@Sun.COM 9270Sstevel@tonic-gate action(arg, picno, p); 9280Sstevel@tonic-gate 929*7640SJonathan.Haslam@Sun.COM out: 930*7640SJonathan.Haslam@Sun.COM free(list); 931*7640SJonathan.Haslam@Sun.COM } 932*7640SJonathan.Haslam@Sun.COM 933*7640SJonathan.Haslam@Sun.COM /*ARGSUSED*/ 934*7640SJonathan.Haslam@Sun.COM void 935*7640SJonathan.Haslam@Sun.COM cpc_walk_generic_events_pic(cpc_t *cpc, uint_t picno, void *arg, 936*7640SJonathan.Haslam@Sun.COM void (*action)(void *arg, uint_t picno, const char *event)) 937*7640SJonathan.Haslam@Sun.COM { 938*7640SJonathan.Haslam@Sun.COM char *p; 939*7640SJonathan.Haslam@Sun.COM char *e; 940*7640SJonathan.Haslam@Sun.COM char *list; 941*7640SJonathan.Haslam@Sun.COM 942*7640SJonathan.Haslam@Sun.COM if (picno >= cpc->cpc_npic) { 943*7640SJonathan.Haslam@Sun.COM errno = EINVAL; 944*7640SJonathan.Haslam@Sun.COM return; 945*7640SJonathan.Haslam@Sun.COM } 946*7640SJonathan.Haslam@Sun.COM 947*7640SJonathan.Haslam@Sun.COM if ((list = strdup(cpc->cpc_evlist[picno])) == NULL) 948*7640SJonathan.Haslam@Sun.COM return; 949*7640SJonathan.Haslam@Sun.COM 950*7640SJonathan.Haslam@Sun.COM /* 951*7640SJonathan.Haslam@Sun.COM * List now points to a comma-separated list of events supported by 952*7640SJonathan.Haslam@Sun.COM * the designated pic. 953*7640SJonathan.Haslam@Sun.COM */ 954*7640SJonathan.Haslam@Sun.COM p = list; 955*7640SJonathan.Haslam@Sun.COM while ((e = strchr(p, ',')) != NULL) { 956*7640SJonathan.Haslam@Sun.COM *e = '\0'; 957*7640SJonathan.Haslam@Sun.COM 958*7640SJonathan.Haslam@Sun.COM /* Skip any platform specific event names we find. */ 959*7640SJonathan.Haslam@Sun.COM if ((strncmp(p, "PAPI", 4)) != 0) { 960*7640SJonathan.Haslam@Sun.COM p = e + 1; 961*7640SJonathan.Haslam@Sun.COM continue; 962*7640SJonathan.Haslam@Sun.COM } 963*7640SJonathan.Haslam@Sun.COM 964*7640SJonathan.Haslam@Sun.COM action(arg, picno, p); 965*7640SJonathan.Haslam@Sun.COM p = e + 1; 966*7640SJonathan.Haslam@Sun.COM } 967*7640SJonathan.Haslam@Sun.COM 968*7640SJonathan.Haslam@Sun.COM if ((strncmp(p, "PAPI", 4)) != 0) 969*7640SJonathan.Haslam@Sun.COM goto out; 970*7640SJonathan.Haslam@Sun.COM 971*7640SJonathan.Haslam@Sun.COM action(arg, picno, p); 972*7640SJonathan.Haslam@Sun.COM 973*7640SJonathan.Haslam@Sun.COM out: 9740Sstevel@tonic-gate free(list); 9750Sstevel@tonic-gate } 9760Sstevel@tonic-gate 9770Sstevel@tonic-gate /*ARGSUSED*/ 9780Sstevel@tonic-gate void 9790Sstevel@tonic-gate cpc_walk_attrs(cpc_t *cpc, void *arg, 9800Sstevel@tonic-gate void (*action)(void *arg, const char *attr)) 9810Sstevel@tonic-gate { 9820Sstevel@tonic-gate char *p; 9830Sstevel@tonic-gate char *e; 9840Sstevel@tonic-gate char *list; 9850Sstevel@tonic-gate 9860Sstevel@tonic-gate if ((list = strdup(cpc->cpc_attrlist)) == NULL) 9870Sstevel@tonic-gate return; 9880Sstevel@tonic-gate 9890Sstevel@tonic-gate /* 9900Sstevel@tonic-gate * Platforms with no attributes will return an empty string. 9910Sstevel@tonic-gate */ 9920Sstevel@tonic-gate if (*list == '\0') 9930Sstevel@tonic-gate return; 9940Sstevel@tonic-gate 9950Sstevel@tonic-gate /* 9960Sstevel@tonic-gate * List now points to a comma-separated list of attributes supported by 9970Sstevel@tonic-gate * the underlying platform. 9980Sstevel@tonic-gate */ 9990Sstevel@tonic-gate p = list; 10000Sstevel@tonic-gate while ((e = strchr(p, ',')) != NULL) { 10010Sstevel@tonic-gate *e = '\0'; 10020Sstevel@tonic-gate action(arg, p); 10030Sstevel@tonic-gate p = e + 1; 10040Sstevel@tonic-gate } 10050Sstevel@tonic-gate action(arg, p); 10060Sstevel@tonic-gate 10070Sstevel@tonic-gate free(list); 10080Sstevel@tonic-gate } 10090Sstevel@tonic-gate 10100Sstevel@tonic-gate /*ARGSUSED*/ 10110Sstevel@tonic-gate int 10120Sstevel@tonic-gate cpc_enable(cpc_t *cpc) 10130Sstevel@tonic-gate { 10140Sstevel@tonic-gate return (syscall(SYS_cpc, CPC_ENABLE, -1, 0, 0, 0)); 10150Sstevel@tonic-gate } 10160Sstevel@tonic-gate 10170Sstevel@tonic-gate /*ARGSUSED*/ 10180Sstevel@tonic-gate int 10190Sstevel@tonic-gate cpc_disable(cpc_t *cpc) 10200Sstevel@tonic-gate { 10210Sstevel@tonic-gate return (syscall(SYS_cpc, CPC_DISABLE, -1, 0, 0, 0)); 10220Sstevel@tonic-gate } 10230Sstevel@tonic-gate 10240Sstevel@tonic-gate /*ARGSUSED*/ 10250Sstevel@tonic-gate uint_t 10260Sstevel@tonic-gate cpc_npic(cpc_t *cpc) 10270Sstevel@tonic-gate { 10280Sstevel@tonic-gate return (cpc->cpc_npic); 10290Sstevel@tonic-gate } 10300Sstevel@tonic-gate 10310Sstevel@tonic-gate /*ARGSUSED*/ 10320Sstevel@tonic-gate uint_t 10330Sstevel@tonic-gate cpc_caps(cpc_t *cpc) 10340Sstevel@tonic-gate { 10350Sstevel@tonic-gate return (cpc->cpc_caps); 10360Sstevel@tonic-gate } 10370Sstevel@tonic-gate 10380Sstevel@tonic-gate const char * 10390Sstevel@tonic-gate cpc_cciname(cpc_t *cpc) 10400Sstevel@tonic-gate { 10410Sstevel@tonic-gate return (cpc->cpc_cciname); 10420Sstevel@tonic-gate } 10430Sstevel@tonic-gate 10440Sstevel@tonic-gate const char * 10450Sstevel@tonic-gate cpc_cpuref(cpc_t *cpc) 10460Sstevel@tonic-gate { 10470Sstevel@tonic-gate return (cpc->cpc_cpuref); 10480Sstevel@tonic-gate } 10490Sstevel@tonic-gate 10500Sstevel@tonic-gate int 10510Sstevel@tonic-gate cpc_seterrhndlr(cpc_t *cpc, cpc_errhndlr_t *fn) 10520Sstevel@tonic-gate { 10530Sstevel@tonic-gate cpc->cpc_errfn = fn; 10540Sstevel@tonic-gate return (0); 10550Sstevel@tonic-gate } 10560Sstevel@tonic-gate 10570Sstevel@tonic-gate /* 10580Sstevel@tonic-gate * These strings may contain printf() conversion specifiers. 10590Sstevel@tonic-gate */ 10600Sstevel@tonic-gate static const char *errstr[] = { 10610Sstevel@tonic-gate "", /* zero slot filler */ 10620Sstevel@tonic-gate "Unknown event\n", /* CPC_INVALID_EVENT */ 10630Sstevel@tonic-gate "Invalid counter number\n", /* CPC_INVALID_PICNUM */ 10640Sstevel@tonic-gate "Unknown attribute\n", /* CPC_INVALID_ATTRIBUTE */ 10650Sstevel@tonic-gate "Attribute out of range\n", /* CPC_ATTRIBUTE_OUT_OF_RANGE */ 10660Sstevel@tonic-gate "Hardware resource unavailable\n", /* CPC_RESOURCE_UNAVAIL */ 10670Sstevel@tonic-gate "Counter cannot count requested event\n", /* CPC_PIC_NOT_CAPABLE */ 10680Sstevel@tonic-gate "Invalid flags in a request\n", /* CPC_REQ_INVALID_FLAGS */ 10690Sstevel@tonic-gate "Requests conflict with each other\n", /* CPC_CONFLICTING_REQS */ 10700Sstevel@tonic-gate "Attribute requires the cpc_cpu privilege\n", /* CPC_ATTR_REQUIRES_PRIVILEGE */ 10713732Sae112802 "Couldn't bind LWP to requested processor\n", /* CPC_PBIND_FAILED */ 10723732Sae112802 "Hypervisor event access denied\n" /* CPC_HV_NO_ACCESS */ 10730Sstevel@tonic-gate }; 10740Sstevel@tonic-gate 10750Sstevel@tonic-gate /*VARARGS3*/ 10760Sstevel@tonic-gate static void 10770Sstevel@tonic-gate cpc_err(cpc_t *cpc, const char *fn, int subcode, ...) 10780Sstevel@tonic-gate { 10790Sstevel@tonic-gate va_list ap; 10800Sstevel@tonic-gate const char *str; 10810Sstevel@tonic-gate int error; 10820Sstevel@tonic-gate 10830Sstevel@tonic-gate /* 10840Sstevel@tonic-gate * If subcode is -1, there is no specific description for this error. 10850Sstevel@tonic-gate */ 10860Sstevel@tonic-gate if (subcode == -1) 10870Sstevel@tonic-gate return; 10880Sstevel@tonic-gate 10890Sstevel@tonic-gate /* 10900Sstevel@tonic-gate * We need to preserve errno across calls to this function to prevent it 10910Sstevel@tonic-gate * from being clobbered while here, or in the user's error handler. 10920Sstevel@tonic-gate */ 10930Sstevel@tonic-gate error = errno; 10940Sstevel@tonic-gate 10950Sstevel@tonic-gate str = dgettext(TEXT_DOMAIN, errstr[subcode]); 10960Sstevel@tonic-gate 10970Sstevel@tonic-gate va_start(ap, subcode); 10980Sstevel@tonic-gate if (cpc->cpc_errfn != NULL) 10990Sstevel@tonic-gate cpc->cpc_errfn(fn, subcode, str, ap); 11000Sstevel@tonic-gate else { 11010Sstevel@tonic-gate /* 11020Sstevel@tonic-gate * If printf() conversion specifiers are added to the errstr[] 11030Sstevel@tonic-gate * table, this call needs to be changed to vfprintf(). 11040Sstevel@tonic-gate */ 11050Sstevel@tonic-gate (void) fprintf(stderr, "libcpc: %s: %s", fn, str); 11060Sstevel@tonic-gate } 11070Sstevel@tonic-gate va_end(ap); 11080Sstevel@tonic-gate 11090Sstevel@tonic-gate errno = error; 11100Sstevel@tonic-gate } 11110Sstevel@tonic-gate 11120Sstevel@tonic-gate /* 11130Sstevel@tonic-gate * Hook used by libpctx to alert libcpc when a pctx handle is going away. 11140Sstevel@tonic-gate * This is necessary to prevent libcpc from attempting a libpctx operation on a 11150Sstevel@tonic-gate * stale and invalid pctx_t handle. Since pctx_t's are cached by libcpc, we need 11160Sstevel@tonic-gate * to be notified when they go away. 11170Sstevel@tonic-gate */ 11180Sstevel@tonic-gate static void 11190Sstevel@tonic-gate cpc_invalidate_pctx(cpc_t *cpc, pctx_t *pctx) 11200Sstevel@tonic-gate { 11210Sstevel@tonic-gate cpc_set_t *set; 11220Sstevel@tonic-gate int sigblocked; 11230Sstevel@tonic-gate 11240Sstevel@tonic-gate sigblocked = cpc_lock(cpc); 11250Sstevel@tonic-gate for (set = cpc->cpc_sets; set != NULL; set = set->cs_next) 11260Sstevel@tonic-gate if (set->cs_pctx == pctx) 11270Sstevel@tonic-gate set->cs_pctx = NULL; 11280Sstevel@tonic-gate cpc_unlock(cpc, sigblocked); 11290Sstevel@tonic-gate } 11300Sstevel@tonic-gate 11310Sstevel@tonic-gate /* 11320Sstevel@tonic-gate * Check that the set is valid; if so it will be in the cpc handle's 11330Sstevel@tonic-gate * list of sets. The lock protects the list of sets, but not the set 11340Sstevel@tonic-gate * itself. 11350Sstevel@tonic-gate */ 11360Sstevel@tonic-gate static int 11370Sstevel@tonic-gate cpc_set_valid(cpc_t *cpc, cpc_set_t *set) 11380Sstevel@tonic-gate { 11390Sstevel@tonic-gate cpc_set_t *csp; 11400Sstevel@tonic-gate int sigblocked; 11410Sstevel@tonic-gate 11420Sstevel@tonic-gate sigblocked = cpc_lock(cpc); 11430Sstevel@tonic-gate for (csp = cpc->cpc_sets; csp != NULL; csp = csp->cs_next) 11440Sstevel@tonic-gate if (csp == set) 11450Sstevel@tonic-gate break; 11460Sstevel@tonic-gate cpc_unlock(cpc, sigblocked); 11470Sstevel@tonic-gate if (csp == NULL) 11480Sstevel@tonic-gate return (-1); 11490Sstevel@tonic-gate return (0); 11500Sstevel@tonic-gate } 11510Sstevel@tonic-gate 11520Sstevel@tonic-gate static int 11530Sstevel@tonic-gate cpc_lock(cpc_t *cpc) 11540Sstevel@tonic-gate { 11550Sstevel@tonic-gate int ret = (sigset(SIGEMT, SIG_HOLD) == SIG_HOLD); 11560Sstevel@tonic-gate (void) mutex_lock(&cpc->cpc_lock); 11570Sstevel@tonic-gate return (ret); 11580Sstevel@tonic-gate } 11590Sstevel@tonic-gate 11600Sstevel@tonic-gate static void 11610Sstevel@tonic-gate cpc_unlock(cpc_t *cpc, int sigblocked) 11620Sstevel@tonic-gate { 11630Sstevel@tonic-gate (void) mutex_unlock(&cpc->cpc_lock); 11640Sstevel@tonic-gate if (sigblocked == 0) 11650Sstevel@tonic-gate (void) sigrelse(SIGEMT); 11660Sstevel@tonic-gate } 11670Sstevel@tonic-gate 11680Sstevel@tonic-gate struct priv { 11690Sstevel@tonic-gate const char *name; 11700Sstevel@tonic-gate int found; 11710Sstevel@tonic-gate }; 11720Sstevel@tonic-gate 11730Sstevel@tonic-gate /*ARGSUSED*/ 11740Sstevel@tonic-gate static void 11750Sstevel@tonic-gate ev_walker(void *arg, uint_t picno, const char *ev) 11760Sstevel@tonic-gate { 11770Sstevel@tonic-gate if (strcmp(((struct priv *)arg)->name, ev) == 0) 11780Sstevel@tonic-gate ((struct priv *)arg)->found = 1; 11790Sstevel@tonic-gate } 11800Sstevel@tonic-gate 11810Sstevel@tonic-gate static void 11820Sstevel@tonic-gate at_walker(void *arg, const char *at) 11830Sstevel@tonic-gate { 11840Sstevel@tonic-gate if (strcmp(((struct priv *)arg)->name, at) == 0) 11850Sstevel@tonic-gate ((struct priv *)arg)->found = 1; 11860Sstevel@tonic-gate } 11870Sstevel@tonic-gate 11880Sstevel@tonic-gate static int 11890Sstevel@tonic-gate cpc_valid_event(cpc_t *cpc, uint_t pic, const char *ev) 11900Sstevel@tonic-gate { 11910Sstevel@tonic-gate struct priv pr = { NULL, 0 }; 11927120Svk226950 char *end_ev; 11930Sstevel@tonic-gate 11940Sstevel@tonic-gate pr.name = ev; 11950Sstevel@tonic-gate cpc_walk_events_pic(cpc, pic, &pr, ev_walker); 11962791Srab if (pr.found) 11972791Srab return (1); 11982791Srab 1199*7640SJonathan.Haslam@Sun.COM cpc_walk_generic_events_pic(cpc, pic, &pr, ev_walker); 1200*7640SJonathan.Haslam@Sun.COM if (pr.found) 1201*7640SJonathan.Haslam@Sun.COM return (1); 1202*7640SJonathan.Haslam@Sun.COM 12032791Srab /* 12042791Srab * Before assuming this is an invalid event, see if we have been given 12052791Srab * a raw event code. An event code of '0' is not recognized, as it 12062791Srab * already has a corresponding event name in existing backends and it 12072791Srab * is the only reasonable way to know if strtol() succeeded. 12087120Svk226950 * Check the second argument of strtol() to ensure invalid events 12097120Svk226950 * beginning with number do not go through. 12102791Srab */ 12117120Svk226950 if ((strtol(ev, &end_ev, 0) != 0) && (*end_ev == '\0')) 12122791Srab /* 12132791Srab * Success - this is a valid raw code in hex, decimal, or octal. 12142791Srab */ 12152791Srab return (1); 12162791Srab 12172791Srab return (0); 12180Sstevel@tonic-gate } 12190Sstevel@tonic-gate 12200Sstevel@tonic-gate static int 12210Sstevel@tonic-gate cpc_valid_attr(cpc_t *cpc, char *attr) 12220Sstevel@tonic-gate { 12230Sstevel@tonic-gate struct priv pr = { NULL, 0 }; 12240Sstevel@tonic-gate 12250Sstevel@tonic-gate pr.name = attr; 12260Sstevel@tonic-gate cpc_walk_attrs(cpc, &pr, at_walker); 12270Sstevel@tonic-gate return (pr.found); 12280Sstevel@tonic-gate } 1229