17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 55d3a5ad8Srab * Common Development and Distribution License (the "License"). 65d3a5ad8Srab * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*e850fb01SKuriakose Kuruvilla * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <libcpc.h> 277c478bd9Sstevel@tonic-gate #include <stdio.h> 287c478bd9Sstevel@tonic-gate #include <stdlib.h> 297c478bd9Sstevel@tonic-gate #include <errno.h> 307c478bd9Sstevel@tonic-gate #include <strings.h> 317c478bd9Sstevel@tonic-gate #include <unistd.h> 327c478bd9Sstevel@tonic-gate #include <stropts.h> 337c478bd9Sstevel@tonic-gate #include <libintl.h> 347c478bd9Sstevel@tonic-gate #include <signal.h> 357c478bd9Sstevel@tonic-gate #include <sys/syscall.h> 367c478bd9Sstevel@tonic-gate #include <sys/types.h> 377c478bd9Sstevel@tonic-gate #include <sys/processor.h> 387c478bd9Sstevel@tonic-gate #include <sys/procset.h> 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate #include "libcpc_impl.h" 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate #define MASK32 0xFFFFFFFF 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate /* 457c478bd9Sstevel@tonic-gate * The library uses the cpc_lock field of the cpc_t struct to protect access to 467c478bd9Sstevel@tonic-gate * the linked lists inside the cpc_t, and only the linked lists. It is NOT used 477c478bd9Sstevel@tonic-gate * to protect against a user shooting his/herself in the foot (such as, for 487c478bd9Sstevel@tonic-gate * instance, destroying the same set at the same time from different threads.). 497c478bd9Sstevel@tonic-gate * 507c478bd9Sstevel@tonic-gate * SIGEMT needs to be blocked while holding the lock, to prevent deadlock among 517c478bd9Sstevel@tonic-gate * an app holding the lock and a signal handler attempting to sample or bind. 527c478bd9Sstevel@tonic-gate */ 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate static char *cpc_get_list(int which, int arg); 557c478bd9Sstevel@tonic-gate static void cpc_err(cpc_t *cpc, const char *fn, int subcode, ...); 567c478bd9Sstevel@tonic-gate static int cpc_set_valid(cpc_t *cpc, cpc_set_t *set); 577c478bd9Sstevel@tonic-gate static int cpc_lock(cpc_t *cpc); 587c478bd9Sstevel@tonic-gate static void cpc_unlock(cpc_t *cpc, int blocked); 597c478bd9Sstevel@tonic-gate static int cpc_valid_event(cpc_t *cpc, uint_t pic, const char *ev); 607c478bd9Sstevel@tonic-gate static int cpc_valid_attr(cpc_t *cpc, char *attr); 617c478bd9Sstevel@tonic-gate static void cpc_invalidate_pctx(cpc_t *cpc, pctx_t *pctx); 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate cpc_t * 647c478bd9Sstevel@tonic-gate cpc_open(int ver) 657c478bd9Sstevel@tonic-gate { 667c478bd9Sstevel@tonic-gate cpc_t *cpc; 677c478bd9Sstevel@tonic-gate void (*sigsaved)(); 687c478bd9Sstevel@tonic-gate int error = 0; 697c478bd9Sstevel@tonic-gate int i; 707c478bd9Sstevel@tonic-gate int j; 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate if (ver != CPC_VER_CURRENT) { 737c478bd9Sstevel@tonic-gate /* 747c478bd9Sstevel@tonic-gate * v1 clients must stick to the v1 interface: cpc_version() 757c478bd9Sstevel@tonic-gate */ 767c478bd9Sstevel@tonic-gate errno = EINVAL; 777c478bd9Sstevel@tonic-gate return (NULL); 787c478bd9Sstevel@tonic-gate } 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate /* 817c478bd9Sstevel@tonic-gate * Call the syscall with invalid parameters. If we get ENOSYS this CPU 827c478bd9Sstevel@tonic-gate * has no CPC support. We need to block SIGSYS because the syscall code 837c478bd9Sstevel@tonic-gate * will send the signal if the system call fails to load. 847c478bd9Sstevel@tonic-gate */ 857c478bd9Sstevel@tonic-gate sigsaved = signal(SIGSYS, SIG_IGN); 867c478bd9Sstevel@tonic-gate if (syscall(SYS_cpc, -1, -1, -1, -1, -1) != -1) { 877c478bd9Sstevel@tonic-gate (void) signal(SIGSYS, sigsaved); 887c478bd9Sstevel@tonic-gate errno = EINVAL; 897c478bd9Sstevel@tonic-gate return (NULL); 907c478bd9Sstevel@tonic-gate } 917c478bd9Sstevel@tonic-gate error = errno; 927c478bd9Sstevel@tonic-gate (void) signal(SIGSYS, sigsaved); 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate if (error != EINVAL) { 957c478bd9Sstevel@tonic-gate errno = error; 967c478bd9Sstevel@tonic-gate return (NULL); 977c478bd9Sstevel@tonic-gate } 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate if ((cpc = malloc(sizeof (cpc_t))) == NULL) { 1007c478bd9Sstevel@tonic-gate errno = ENOMEM; 1017c478bd9Sstevel@tonic-gate return (NULL); 1027c478bd9Sstevel@tonic-gate } 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate cpc->cpc_npic = syscall(SYS_cpc, CPC_NPIC, -1, 0, 0, 0); 1057c478bd9Sstevel@tonic-gate cpc->cpc_caps = syscall(SYS_cpc, CPC_CAPS, -1, 0, 0, 0); 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate if (syscall(SYS_cpc, CPC_IMPL_NAME, -1, &cpc->cpc_cciname, 0, 0) != 0) 1087c478bd9Sstevel@tonic-gate return (NULL); 1097c478bd9Sstevel@tonic-gate if (syscall(SYS_cpc, CPC_CPUREF, -1, &cpc->cpc_cpuref, 0, 0) != 0) 1107c478bd9Sstevel@tonic-gate return (NULL); 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate if ((cpc->cpc_attrlist = cpc_get_list(CPC_LIST_ATTRS, 0)) == NULL) { 1147c478bd9Sstevel@tonic-gate free(cpc); 1157c478bd9Sstevel@tonic-gate return (NULL); 1167c478bd9Sstevel@tonic-gate } 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate if ((cpc->cpc_evlist = malloc(cpc->cpc_npic * sizeof (char *))) == 1197c478bd9Sstevel@tonic-gate NULL) { 1207c478bd9Sstevel@tonic-gate free(cpc->cpc_attrlist); 1217c478bd9Sstevel@tonic-gate free(cpc); 1227c478bd9Sstevel@tonic-gate return (NULL); 1237c478bd9Sstevel@tonic-gate } 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate for (i = 0; i < cpc->cpc_npic; i++) { 1267c478bd9Sstevel@tonic-gate if ((cpc->cpc_evlist[i] = cpc_get_list(CPC_LIST_EVENTS, i)) == 1277c478bd9Sstevel@tonic-gate NULL) 1287c478bd9Sstevel@tonic-gate break; 1297c478bd9Sstevel@tonic-gate } 1307c478bd9Sstevel@tonic-gate if (i != cpc->cpc_npic) { 1317c478bd9Sstevel@tonic-gate for (j = 0; j < i; j++) 1327c478bd9Sstevel@tonic-gate free(cpc->cpc_evlist[j]); 1337c478bd9Sstevel@tonic-gate free(cpc->cpc_evlist); 1347c478bd9Sstevel@tonic-gate free(cpc->cpc_attrlist); 1357c478bd9Sstevel@tonic-gate free(cpc); 1367c478bd9Sstevel@tonic-gate return (NULL); 1377c478bd9Sstevel@tonic-gate } 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate cpc->cpc_sets = NULL; 1407c478bd9Sstevel@tonic-gate cpc->cpc_bufs = NULL; 1417c478bd9Sstevel@tonic-gate cpc->cpc_errfn = NULL; 1427c478bd9Sstevel@tonic-gate (void) mutex_init(&cpc->cpc_lock, USYNC_THREAD, NULL); 1437c478bd9Sstevel@tonic-gate __pctx_cpc_register_callback(cpc_invalidate_pctx); 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate return (cpc); 1467c478bd9Sstevel@tonic-gate } 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate /* 1497c478bd9Sstevel@tonic-gate * Ensure state is cleaned up: 1507c478bd9Sstevel@tonic-gate * 1517c478bd9Sstevel@tonic-gate * - Hardware is unbound 1527c478bd9Sstevel@tonic-gate * - Sets are all destroyed 1537c478bd9Sstevel@tonic-gate * - Bufs are all freed 1547c478bd9Sstevel@tonic-gate */ 1557c478bd9Sstevel@tonic-gate int 1567c478bd9Sstevel@tonic-gate cpc_close(cpc_t *cpc) 1577c478bd9Sstevel@tonic-gate { 1587c478bd9Sstevel@tonic-gate while (cpc->cpc_sets != NULL) { 1597c478bd9Sstevel@tonic-gate if (cpc->cpc_sets->cs_state != CS_UNBOUND) 1607c478bd9Sstevel@tonic-gate (void) cpc_unbind(cpc, cpc->cpc_sets); 1617c478bd9Sstevel@tonic-gate (void) cpc_set_destroy(cpc, cpc->cpc_sets); 1627c478bd9Sstevel@tonic-gate } 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate while (cpc->cpc_bufs != NULL) 1657c478bd9Sstevel@tonic-gate (void) cpc_buf_destroy(cpc, cpc->cpc_bufs); 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate free(cpc); 1687c478bd9Sstevel@tonic-gate return (0); 1697c478bd9Sstevel@tonic-gate } 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate cpc_set_t * 1727c478bd9Sstevel@tonic-gate cpc_set_create(cpc_t *cpc) 1737c478bd9Sstevel@tonic-gate { 1747c478bd9Sstevel@tonic-gate cpc_set_t *set; 1757c478bd9Sstevel@tonic-gate int sigblocked; 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate if ((set = malloc(sizeof (*set))) == NULL) { 1787c478bd9Sstevel@tonic-gate errno = ENOMEM; 1797c478bd9Sstevel@tonic-gate return (NULL); 1807c478bd9Sstevel@tonic-gate } 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate set->cs_request = NULL; 1837c478bd9Sstevel@tonic-gate set->cs_nreqs = 0; 1847c478bd9Sstevel@tonic-gate set->cs_state = CS_UNBOUND; 1857c478bd9Sstevel@tonic-gate set->cs_fd = -1; 1867c478bd9Sstevel@tonic-gate set->cs_pctx = NULL; 1877c478bd9Sstevel@tonic-gate set->cs_id = -1; 1887c478bd9Sstevel@tonic-gate set->cs_thr = NULL; 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate sigblocked = cpc_lock(cpc); 1917c478bd9Sstevel@tonic-gate set->cs_next = cpc->cpc_sets; 1927c478bd9Sstevel@tonic-gate cpc->cpc_sets = set; 1937c478bd9Sstevel@tonic-gate cpc_unlock(cpc, sigblocked); 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate return (set); 1967c478bd9Sstevel@tonic-gate } 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate int 1997c478bd9Sstevel@tonic-gate cpc_set_destroy(cpc_t *cpc, cpc_set_t *set) 2007c478bd9Sstevel@tonic-gate { 2017c478bd9Sstevel@tonic-gate cpc_set_t *csp, *prev; 2027c478bd9Sstevel@tonic-gate cpc_request_t *req, *next; 2037c478bd9Sstevel@tonic-gate int sigblocked; 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate /* 2067c478bd9Sstevel@tonic-gate * Remove this set from the cpc handle's list of sets. 2077c478bd9Sstevel@tonic-gate */ 2087c478bd9Sstevel@tonic-gate sigblocked = cpc_lock(cpc); 2097c478bd9Sstevel@tonic-gate for (csp = prev = cpc->cpc_sets; csp != NULL; csp = csp->cs_next) { 2107c478bd9Sstevel@tonic-gate if (csp == set) 2117c478bd9Sstevel@tonic-gate break; 2127c478bd9Sstevel@tonic-gate prev = csp; 2137c478bd9Sstevel@tonic-gate } 2147c478bd9Sstevel@tonic-gate if (csp == NULL) { 2157c478bd9Sstevel@tonic-gate cpc_unlock(cpc, sigblocked); 2167c478bd9Sstevel@tonic-gate errno = EINVAL; 2177c478bd9Sstevel@tonic-gate return (-1); 2187c478bd9Sstevel@tonic-gate } 2197c478bd9Sstevel@tonic-gate if (csp == cpc->cpc_sets) 2207c478bd9Sstevel@tonic-gate cpc->cpc_sets = csp->cs_next; 2217c478bd9Sstevel@tonic-gate prev->cs_next = csp->cs_next; 2227c478bd9Sstevel@tonic-gate cpc_unlock(cpc, sigblocked); 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate if (csp->cs_state != CS_UNBOUND) 2257c478bd9Sstevel@tonic-gate (void) cpc_unbind(cpc, csp); 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate for (req = csp->cs_request; req != NULL; req = next) { 2287c478bd9Sstevel@tonic-gate next = req->cr_next; 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate if (req->cr_nattrs != 0) 2317c478bd9Sstevel@tonic-gate free(req->cr_attr); 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate free(req); 2347c478bd9Sstevel@tonic-gate } 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate free(set); 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate return (0); 2407c478bd9Sstevel@tonic-gate } 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2437c478bd9Sstevel@tonic-gate int 2447c478bd9Sstevel@tonic-gate cpc_set_add_request(cpc_t *cpc, cpc_set_t *set, const char *event, 2457c478bd9Sstevel@tonic-gate uint64_t preset, uint_t flags, uint_t nattrs, const cpc_attr_t *attrs) 2467c478bd9Sstevel@tonic-gate { 2477c478bd9Sstevel@tonic-gate cpc_request_t *req; 2487c478bd9Sstevel@tonic-gate const char *fn = "cpc_set_add_request"; 2497c478bd9Sstevel@tonic-gate int i; 2507c478bd9Sstevel@tonic-gate int npics = cpc_npic(cpc); 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate if (cpc_set_valid(cpc, set) != 0 || set->cs_state != CS_UNBOUND) { 2537c478bd9Sstevel@tonic-gate errno = EINVAL; 2547c478bd9Sstevel@tonic-gate return (-1); 2557c478bd9Sstevel@tonic-gate } 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate for (i = 0; i < npics; i++) 2587c478bd9Sstevel@tonic-gate if (cpc_valid_event(cpc, i, event)) 2597c478bd9Sstevel@tonic-gate break; 2607c478bd9Sstevel@tonic-gate if (i == npics) { 2617c478bd9Sstevel@tonic-gate cpc_err(cpc, fn, CPC_INVALID_EVENT); 2627c478bd9Sstevel@tonic-gate errno = EINVAL; 2637c478bd9Sstevel@tonic-gate return (-1); 2647c478bd9Sstevel@tonic-gate } 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate if ((req = malloc(sizeof (*req))) == NULL) { 2677c478bd9Sstevel@tonic-gate errno = ENOMEM; 2687c478bd9Sstevel@tonic-gate return (-1); 2697c478bd9Sstevel@tonic-gate } 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate (void) strncpy(req->cr_event, event, CPC_MAX_EVENT_LEN); 2727c478bd9Sstevel@tonic-gate req->cr_preset = preset; 2737c478bd9Sstevel@tonic-gate req->cr_flags = flags; 2747c478bd9Sstevel@tonic-gate req->cr_nattrs = nattrs; 2757c478bd9Sstevel@tonic-gate req->cr_index = set->cs_nreqs; 2767c478bd9Sstevel@tonic-gate req->cr_attr = NULL; 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate if (nattrs != 0) { 2797c478bd9Sstevel@tonic-gate for (i = 0; i < nattrs; i++) { 2807c478bd9Sstevel@tonic-gate /* 2817c478bd9Sstevel@tonic-gate * Verify that each attribute name is legal and valid. 2827c478bd9Sstevel@tonic-gate */ 2837c478bd9Sstevel@tonic-gate if (attrs[i].ca_name[0] == '\0' || 2847c478bd9Sstevel@tonic-gate cpc_valid_attr(cpc, attrs[i].ca_name) == 0) { 2857c478bd9Sstevel@tonic-gate cpc_err(cpc, fn, CPC_INVALID_ATTRIBUTE); 2867c478bd9Sstevel@tonic-gate goto inval; 2877c478bd9Sstevel@tonic-gate } 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate /* 2907c478bd9Sstevel@tonic-gate * If the user requested a specific picnum, ensure that 2917c478bd9Sstevel@tonic-gate * the pic can count the requested event. 2927c478bd9Sstevel@tonic-gate */ 2937c478bd9Sstevel@tonic-gate if (strncmp("picnum", attrs[i].ca_name, 8) == 0) { 2947c478bd9Sstevel@tonic-gate if (attrs[i].ca_val >= npics) { 2957c478bd9Sstevel@tonic-gate cpc_err(cpc, fn, CPC_INVALID_PICNUM); 2967c478bd9Sstevel@tonic-gate goto inval; 2977c478bd9Sstevel@tonic-gate } 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate if (cpc_valid_event(cpc, attrs[i].ca_val, 3007c478bd9Sstevel@tonic-gate req->cr_event) == 0) { 3017c478bd9Sstevel@tonic-gate cpc_err(cpc, fn, CPC_PIC_NOT_CAPABLE); 3027c478bd9Sstevel@tonic-gate goto inval; 3037c478bd9Sstevel@tonic-gate } 3047c478bd9Sstevel@tonic-gate } 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate if ((req->cr_attr = malloc(nattrs * sizeof (kcpc_attr_t))) 3087c478bd9Sstevel@tonic-gate == NULL) { 3097c478bd9Sstevel@tonic-gate free(req); 3107c478bd9Sstevel@tonic-gate return (-1); 3117c478bd9Sstevel@tonic-gate } 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate for (i = 0; i < nattrs; i++) { 3147c478bd9Sstevel@tonic-gate req->cr_attr[i].ka_val = attrs[i].ca_val; 3157c478bd9Sstevel@tonic-gate (void) strncpy(req->cr_attr[i].ka_name, 3167c478bd9Sstevel@tonic-gate attrs[i].ca_name, CPC_MAX_ATTR_LEN); 3177c478bd9Sstevel@tonic-gate } 3187c478bd9Sstevel@tonic-gate } else 3197c478bd9Sstevel@tonic-gate req->cr_attr = NULL; 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate req->cr_next = set->cs_request; 3227c478bd9Sstevel@tonic-gate set->cs_request = req; 3237c478bd9Sstevel@tonic-gate set->cs_nreqs++; 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate return (req->cr_index); 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate inval: 3287c478bd9Sstevel@tonic-gate free(req); 3297c478bd9Sstevel@tonic-gate errno = EINVAL; 3307c478bd9Sstevel@tonic-gate return (-1); 3317c478bd9Sstevel@tonic-gate } 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate cpc_buf_t * 3347c478bd9Sstevel@tonic-gate cpc_buf_create(cpc_t *cpc, cpc_set_t *set) 3357c478bd9Sstevel@tonic-gate { 3367c478bd9Sstevel@tonic-gate cpc_buf_t *buf; 3377c478bd9Sstevel@tonic-gate int sigblocked; 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate if (cpc_set_valid(cpc, set) != 0) { 3407c478bd9Sstevel@tonic-gate errno = EINVAL; 3417c478bd9Sstevel@tonic-gate return (NULL); 3427c478bd9Sstevel@tonic-gate } 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate if ((buf = malloc(sizeof (*buf))) == NULL) 3457c478bd9Sstevel@tonic-gate return (NULL); 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate buf->cb_size = set->cs_nreqs * sizeof (uint64_t); 3487c478bd9Sstevel@tonic-gate if ((buf->cb_data = malloc(buf->cb_size)) == NULL) { 3497c478bd9Sstevel@tonic-gate free(buf); 3507c478bd9Sstevel@tonic-gate return (NULL); 3517c478bd9Sstevel@tonic-gate } 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate bzero(buf->cb_data, buf->cb_size); 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate buf->cb_hrtime = 0; 3567c478bd9Sstevel@tonic-gate buf->cb_tick = 0; 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate sigblocked = cpc_lock(cpc); 3597c478bd9Sstevel@tonic-gate buf->cb_next = cpc->cpc_bufs; 3607c478bd9Sstevel@tonic-gate cpc->cpc_bufs = buf; 3617c478bd9Sstevel@tonic-gate cpc_unlock(cpc, sigblocked); 3627c478bd9Sstevel@tonic-gate 3637c478bd9Sstevel@tonic-gate return (buf); 3647c478bd9Sstevel@tonic-gate } 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate int 3677c478bd9Sstevel@tonic-gate cpc_buf_destroy(cpc_t *cpc, cpc_buf_t *buf) 3687c478bd9Sstevel@tonic-gate { 3697c478bd9Sstevel@tonic-gate cpc_buf_t *cbp, *prev; 3707c478bd9Sstevel@tonic-gate int sigblocked; 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate /* 3737c478bd9Sstevel@tonic-gate * Remove this buf from the cpc handle's list of bufs. 3747c478bd9Sstevel@tonic-gate */ 3757c478bd9Sstevel@tonic-gate sigblocked = cpc_lock(cpc); 3767c478bd9Sstevel@tonic-gate for (cbp = prev = cpc->cpc_bufs; cbp != NULL; cbp = cbp->cb_next) { 3777c478bd9Sstevel@tonic-gate if (cbp == buf) 3787c478bd9Sstevel@tonic-gate break; 3797c478bd9Sstevel@tonic-gate prev = cbp; 3807c478bd9Sstevel@tonic-gate } 3817c478bd9Sstevel@tonic-gate if (cbp == NULL) { 3827c478bd9Sstevel@tonic-gate cpc_unlock(cpc, sigblocked); 3837c478bd9Sstevel@tonic-gate errno = EINVAL; 3847c478bd9Sstevel@tonic-gate return (-1); 3857c478bd9Sstevel@tonic-gate } 3867c478bd9Sstevel@tonic-gate if (cbp == cpc->cpc_bufs) 3877c478bd9Sstevel@tonic-gate cpc->cpc_bufs = cbp->cb_next; 3887c478bd9Sstevel@tonic-gate prev->cb_next = cbp->cb_next; 3897c478bd9Sstevel@tonic-gate 3907c478bd9Sstevel@tonic-gate cpc_unlock(cpc, sigblocked); 3917c478bd9Sstevel@tonic-gate free(cbp->cb_data); 3927c478bd9Sstevel@tonic-gate free(cbp); 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate return (0); 3957c478bd9Sstevel@tonic-gate } 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3987c478bd9Sstevel@tonic-gate int 3997c478bd9Sstevel@tonic-gate cpc_bind_curlwp(cpc_t *cpc, cpc_set_t *set, uint_t flags) 4007c478bd9Sstevel@tonic-gate { 4017c478bd9Sstevel@tonic-gate char *packed_set; 4027c478bd9Sstevel@tonic-gate size_t packsize; 4037c478bd9Sstevel@tonic-gate int ret; 4047c478bd9Sstevel@tonic-gate int subcode = -1; 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate /* 4077c478bd9Sstevel@tonic-gate * We don't bother checking cpc_set_valid() here, because this is in the 4087c478bd9Sstevel@tonic-gate * fast path of an app doing SIGEMT-based profiling as they restart the 4097c478bd9Sstevel@tonic-gate * counters from their signal handler. 4107c478bd9Sstevel@tonic-gate */ 4117c478bd9Sstevel@tonic-gate if (CPC_SET_VALID_FLAGS(flags) == 0 || set->cs_nreqs <= 0) { 4127c478bd9Sstevel@tonic-gate errno = EINVAL; 4137c478bd9Sstevel@tonic-gate return (-1); 4147c478bd9Sstevel@tonic-gate } 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate if ((packed_set = __cpc_pack_set(set, flags, &packsize)) == NULL) { 4177c478bd9Sstevel@tonic-gate errno = ENOMEM; 4187c478bd9Sstevel@tonic-gate return (-1); 4197c478bd9Sstevel@tonic-gate } 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate ret = syscall(SYS_cpc, CPC_BIND, -1, packed_set, packsize, &subcode); 4227c478bd9Sstevel@tonic-gate free(packed_set); 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate if (ret != 0) { 4257c478bd9Sstevel@tonic-gate if (subcode != -1) 4267c478bd9Sstevel@tonic-gate cpc_err(cpc, "cpc_bind_curlwp", subcode); 4277c478bd9Sstevel@tonic-gate return (-1); 4287c478bd9Sstevel@tonic-gate } 4297c478bd9Sstevel@tonic-gate 4307c478bd9Sstevel@tonic-gate set->cs_thr = thr_self(); 4317c478bd9Sstevel@tonic-gate set->cs_state = CS_BOUND_CURLWP; 4327c478bd9Sstevel@tonic-gate return (ret); 4337c478bd9Sstevel@tonic-gate } 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4367c478bd9Sstevel@tonic-gate int 4377c478bd9Sstevel@tonic-gate cpc_bind_pctx(cpc_t *cpc, pctx_t *pctx, id_t id, cpc_set_t *set, uint_t flags) 4387c478bd9Sstevel@tonic-gate { 4397c478bd9Sstevel@tonic-gate char *packed_set; 4407c478bd9Sstevel@tonic-gate size_t packsize; 4417c478bd9Sstevel@tonic-gate int ret; 4427c478bd9Sstevel@tonic-gate int subcode = -1; 4437c478bd9Sstevel@tonic-gate 4447c478bd9Sstevel@tonic-gate /* 4457c478bd9Sstevel@tonic-gate * cpc_bind_pctx() currently has no valid flags. 4467c478bd9Sstevel@tonic-gate */ 4477c478bd9Sstevel@tonic-gate if (flags != 0 || cpc_set_valid(cpc, set) != 0 || set->cs_nreqs <= 0) { 4487c478bd9Sstevel@tonic-gate errno = EINVAL; 4497c478bd9Sstevel@tonic-gate return (-1); 4507c478bd9Sstevel@tonic-gate } 4517c478bd9Sstevel@tonic-gate 4527c478bd9Sstevel@tonic-gate if ((packed_set = __cpc_pack_set(set, flags, &packsize)) == NULL) { 4537c478bd9Sstevel@tonic-gate errno = ENOMEM; 4547c478bd9Sstevel@tonic-gate return (-1); 4557c478bd9Sstevel@tonic-gate } 4567c478bd9Sstevel@tonic-gate 4577c478bd9Sstevel@tonic-gate ret = __pctx_cpc(pctx, cpc, CPC_BIND, id, packed_set, (void *)packsize, 4587c478bd9Sstevel@tonic-gate (void *)&subcode, -1); 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate free(packed_set); 4617c478bd9Sstevel@tonic-gate 4627c478bd9Sstevel@tonic-gate if (ret == 0) { 4637c478bd9Sstevel@tonic-gate set->cs_pctx = pctx; 4647c478bd9Sstevel@tonic-gate set->cs_id = id; 4657c478bd9Sstevel@tonic-gate set->cs_state = CS_BOUND_PCTX; 4667c478bd9Sstevel@tonic-gate } else if (subcode != -1) 4677c478bd9Sstevel@tonic-gate cpc_err(cpc, "cpc_bind_pctx", subcode); 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate return (ret); 4707c478bd9Sstevel@tonic-gate } 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4737c478bd9Sstevel@tonic-gate int 4747c478bd9Sstevel@tonic-gate cpc_bind_cpu(cpc_t *cpc, processorid_t id, cpc_set_t *set, uint_t flags) 4757c478bd9Sstevel@tonic-gate { 4767c478bd9Sstevel@tonic-gate int fd; 4777c478bd9Sstevel@tonic-gate char *packed_set; 4787c478bd9Sstevel@tonic-gate size_t packsize; 4797c478bd9Sstevel@tonic-gate __cpc_args_t cpc_args; 4807c478bd9Sstevel@tonic-gate int error; 4817c478bd9Sstevel@tonic-gate const char *fn = "cpc_bind_cpu"; 4827c478bd9Sstevel@tonic-gate int subcode = -1; 4837c478bd9Sstevel@tonic-gate 4847c478bd9Sstevel@tonic-gate /* 4857c478bd9Sstevel@tonic-gate * cpc_bind_cpu() currently has no valid flags. 4867c478bd9Sstevel@tonic-gate */ 4877c478bd9Sstevel@tonic-gate if (flags != 0 || cpc_set_valid(cpc, set) != 0 || set->cs_nreqs <= 0) { 4887c478bd9Sstevel@tonic-gate errno = EINVAL; 4897c478bd9Sstevel@tonic-gate return (-1); 4907c478bd9Sstevel@tonic-gate } 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate if (processor_bind(P_LWPID, P_MYID, id, &set->cs_obind) == -1) { 4937c478bd9Sstevel@tonic-gate cpc_err(cpc, fn, CPC_PBIND_FAILED); 4947c478bd9Sstevel@tonic-gate return (-1); 4957c478bd9Sstevel@tonic-gate } 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate if ((fd = open(CPUDRV_SHARED, O_RDWR)) < 0) { 4987c478bd9Sstevel@tonic-gate error = errno; 4997c478bd9Sstevel@tonic-gate (void) processor_bind(P_LWPID, P_MYID, set->cs_obind, NULL); 5007c478bd9Sstevel@tonic-gate errno = error; 5017c478bd9Sstevel@tonic-gate return (-1); 5027c478bd9Sstevel@tonic-gate } 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate /* 5057c478bd9Sstevel@tonic-gate * To avoid leaking file descriptors, if we find an existing fd here we 5067c478bd9Sstevel@tonic-gate * just close it. This is only a problem if a user attempts to bind the 5077c478bd9Sstevel@tonic-gate * same set to different CPUs without first unbinding it. 5087c478bd9Sstevel@tonic-gate */ 5097c478bd9Sstevel@tonic-gate if (set->cs_fd != -1) 5107c478bd9Sstevel@tonic-gate (void) close(set->cs_fd); 5117c478bd9Sstevel@tonic-gate set->cs_fd = fd; 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate if ((packed_set = __cpc_pack_set(set, flags, &packsize)) == NULL) { 5147c478bd9Sstevel@tonic-gate (void) close(fd); 5157c478bd9Sstevel@tonic-gate (void) processor_bind(P_LWPID, P_MYID, set->cs_obind, NULL); 5167c478bd9Sstevel@tonic-gate errno = ENOMEM; 5177c478bd9Sstevel@tonic-gate return (-1); 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate cpc_args.udata1 = packed_set; 5217c478bd9Sstevel@tonic-gate cpc_args.udata2 = (void *)packsize; 5227c478bd9Sstevel@tonic-gate cpc_args.udata3 = (void *)&subcode; 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate if (ioctl(fd, CPCIO_BIND, &cpc_args) != 0) { 5257c478bd9Sstevel@tonic-gate error = errno; 5267c478bd9Sstevel@tonic-gate free(packed_set); 5277c478bd9Sstevel@tonic-gate (void) close(fd); 5287c478bd9Sstevel@tonic-gate (void) processor_bind(P_LWPID, P_MYID, set->cs_obind, NULL); 5297c478bd9Sstevel@tonic-gate if (subcode != -1) 5307c478bd9Sstevel@tonic-gate cpc_err(cpc, fn, subcode); 5317c478bd9Sstevel@tonic-gate errno = error; 5327c478bd9Sstevel@tonic-gate return (-1); 5337c478bd9Sstevel@tonic-gate } 5347c478bd9Sstevel@tonic-gate 5357c478bd9Sstevel@tonic-gate free(packed_set); 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate set->cs_thr = thr_self(); 5387c478bd9Sstevel@tonic-gate set->cs_state = CS_BOUND_CPU; 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate return (0); 5417c478bd9Sstevel@tonic-gate } 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5447c478bd9Sstevel@tonic-gate int 5457c478bd9Sstevel@tonic-gate cpc_request_preset(cpc_t *cpc, int index, uint64_t preset) 5467c478bd9Sstevel@tonic-gate { 5477c478bd9Sstevel@tonic-gate return (syscall(SYS_cpc, CPC_PRESET, -1, index, 5487c478bd9Sstevel@tonic-gate (uint32_t)(preset >> 32), (uint32_t)(preset & MASK32))); 5497c478bd9Sstevel@tonic-gate } 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5527c478bd9Sstevel@tonic-gate int 5537c478bd9Sstevel@tonic-gate cpc_set_restart(cpc_t *cpc, cpc_set_t *set) 5547c478bd9Sstevel@tonic-gate { 5557c478bd9Sstevel@tonic-gate return (syscall(SYS_cpc, CPC_RESTART, -1, 0, 0, 0)); 5567c478bd9Sstevel@tonic-gate } 5577c478bd9Sstevel@tonic-gate 5587c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5597c478bd9Sstevel@tonic-gate int 5607c478bd9Sstevel@tonic-gate cpc_unbind(cpc_t *cpc, cpc_set_t *set) 5617c478bd9Sstevel@tonic-gate { 5627c478bd9Sstevel@tonic-gate int ret = 0; 5637c478bd9Sstevel@tonic-gate int error; 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate if (cpc_set_valid(cpc, set) != 0) { 5667c478bd9Sstevel@tonic-gate errno = EINVAL; 5677c478bd9Sstevel@tonic-gate return (-1); 5687c478bd9Sstevel@tonic-gate } 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate switch (set->cs_state) { 5717c478bd9Sstevel@tonic-gate case CS_UNBOUND: 5727c478bd9Sstevel@tonic-gate errno = EINVAL; 5737c478bd9Sstevel@tonic-gate return (-1); 5747c478bd9Sstevel@tonic-gate case CS_BOUND_CURLWP: 5757c478bd9Sstevel@tonic-gate ret = syscall(SYS_cpc, CPC_RELE, -1, 0, 0, 0); 5767c478bd9Sstevel@tonic-gate error = errno; 5777c478bd9Sstevel@tonic-gate break; 5787c478bd9Sstevel@tonic-gate case CS_BOUND_CPU: 5797c478bd9Sstevel@tonic-gate ret = ioctl(set->cs_fd, CPCIO_RELE, NULL); 5807c478bd9Sstevel@tonic-gate error = errno; 5817c478bd9Sstevel@tonic-gate (void) close(set->cs_fd); 5827c478bd9Sstevel@tonic-gate set->cs_fd = -1; 5837c478bd9Sstevel@tonic-gate (void) processor_bind(P_LWPID, P_MYID, set->cs_obind, NULL); 5847c478bd9Sstevel@tonic-gate break; 5857c478bd9Sstevel@tonic-gate case CS_BOUND_PCTX: 5867c478bd9Sstevel@tonic-gate if (set->cs_pctx != NULL) { 5877c478bd9Sstevel@tonic-gate ret = __pctx_cpc(set->cs_pctx, cpc, CPC_RELE, 5887c478bd9Sstevel@tonic-gate set->cs_id, 0, 0, 0, 0); 5897c478bd9Sstevel@tonic-gate error = errno; 5907c478bd9Sstevel@tonic-gate } 5917c478bd9Sstevel@tonic-gate break; 5927c478bd9Sstevel@tonic-gate } 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate set->cs_thr = NULL; 5957c478bd9Sstevel@tonic-gate set->cs_id = -1; 5967c478bd9Sstevel@tonic-gate set->cs_state = CS_UNBOUND; 5977c478bd9Sstevel@tonic-gate if (ret != 0) 5987c478bd9Sstevel@tonic-gate errno = error; 5997c478bd9Sstevel@tonic-gate return (ret); 6007c478bd9Sstevel@tonic-gate } 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6037c478bd9Sstevel@tonic-gate int 6047c478bd9Sstevel@tonic-gate cpc_set_sample(cpc_t *cpc, cpc_set_t *set, cpc_buf_t *buf) 6057c478bd9Sstevel@tonic-gate { 6067c478bd9Sstevel@tonic-gate __cpc_args_t args; 6077c478bd9Sstevel@tonic-gate 6087c478bd9Sstevel@tonic-gate /* 6097c478bd9Sstevel@tonic-gate * The following check ensures that only the most recently bound set 6107c478bd9Sstevel@tonic-gate * can be sampled, as binding a set invalidates all other sets in the 6117c478bd9Sstevel@tonic-gate * cpc_t. 6127c478bd9Sstevel@tonic-gate */ 6137c478bd9Sstevel@tonic-gate if (set->cs_state == CS_UNBOUND || 6147c478bd9Sstevel@tonic-gate buf->cb_size != set->cs_nreqs * sizeof (uint64_t)) { 6157c478bd9Sstevel@tonic-gate errno = EINVAL; 6167c478bd9Sstevel@tonic-gate return (-1); 6177c478bd9Sstevel@tonic-gate } 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate switch (set->cs_state) { 6207c478bd9Sstevel@tonic-gate case CS_BOUND_CURLWP: 6217c478bd9Sstevel@tonic-gate return (syscall(SYS_cpc, CPC_SAMPLE, -1, buf->cb_data, 6227c478bd9Sstevel@tonic-gate &buf->cb_hrtime, &buf->cb_tick)); 6237c478bd9Sstevel@tonic-gate case CS_BOUND_CPU: 6247c478bd9Sstevel@tonic-gate args.udata1 = buf->cb_data; 6257c478bd9Sstevel@tonic-gate args.udata2 = &buf->cb_hrtime; 6267c478bd9Sstevel@tonic-gate args.udata3 = &buf->cb_tick; 6277c478bd9Sstevel@tonic-gate return (ioctl(set->cs_fd, CPCIO_SAMPLE, &args)); 6287c478bd9Sstevel@tonic-gate case CS_BOUND_PCTX: 6297c478bd9Sstevel@tonic-gate return (__pctx_cpc(set->cs_pctx, cpc, CPC_SAMPLE, set->cs_id, 6307c478bd9Sstevel@tonic-gate buf->cb_data, &buf->cb_hrtime, &buf->cb_tick, 6317c478bd9Sstevel@tonic-gate buf->cb_size)); 6327c478bd9Sstevel@tonic-gate } 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate errno = EINVAL; 6357c478bd9Sstevel@tonic-gate return (-1); 6367c478bd9Sstevel@tonic-gate } 6377c478bd9Sstevel@tonic-gate 6387c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6397c478bd9Sstevel@tonic-gate void 6407c478bd9Sstevel@tonic-gate cpc_buf_sub(cpc_t *cpc, cpc_buf_t *ds, cpc_buf_t *a, cpc_buf_t *b) 6417c478bd9Sstevel@tonic-gate { 6427c478bd9Sstevel@tonic-gate int i; 6437c478bd9Sstevel@tonic-gate 6447c478bd9Sstevel@tonic-gate if (a->cb_size != ds->cb_size || b->cb_size != ds->cb_size) 6457c478bd9Sstevel@tonic-gate return; 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate ds->cb_hrtime = (a->cb_hrtime > b->cb_hrtime) ? 6487c478bd9Sstevel@tonic-gate a->cb_hrtime : b->cb_hrtime; 6497c478bd9Sstevel@tonic-gate ds->cb_tick = a->cb_tick - b->cb_tick; 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate for (i = 0; i < ds->cb_size / sizeof (uint64_t); i++) 6527c478bd9Sstevel@tonic-gate ds->cb_data[i] = a->cb_data[i] - b->cb_data[i]; 6537c478bd9Sstevel@tonic-gate } 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6567c478bd9Sstevel@tonic-gate void 6577c478bd9Sstevel@tonic-gate cpc_buf_add(cpc_t *cpc, cpc_buf_t *ds, cpc_buf_t *a, cpc_buf_t *b) 6587c478bd9Sstevel@tonic-gate { 6597c478bd9Sstevel@tonic-gate int i; 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate if (a->cb_size != ds->cb_size || b->cb_size != ds->cb_size) 6627c478bd9Sstevel@tonic-gate return; 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate ds->cb_hrtime = (a->cb_hrtime > b->cb_hrtime) ? 6657c478bd9Sstevel@tonic-gate a->cb_hrtime : b->cb_hrtime; 6667c478bd9Sstevel@tonic-gate ds->cb_tick = a->cb_tick + b->cb_tick; 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate for (i = 0; i < ds->cb_size / sizeof (uint64_t); i++) 6697c478bd9Sstevel@tonic-gate ds->cb_data[i] = a->cb_data[i] + b->cb_data[i]; 6707c478bd9Sstevel@tonic-gate } 6717c478bd9Sstevel@tonic-gate 6727c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6737c478bd9Sstevel@tonic-gate void 6747c478bd9Sstevel@tonic-gate cpc_buf_copy(cpc_t *cpc, cpc_buf_t *ds, cpc_buf_t *src) 6757c478bd9Sstevel@tonic-gate { 6767c478bd9Sstevel@tonic-gate if (ds->cb_size != src->cb_size) 6777c478bd9Sstevel@tonic-gate return; 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate bcopy(src->cb_data, ds->cb_data, ds->cb_size); 6807c478bd9Sstevel@tonic-gate ds->cb_hrtime = src->cb_hrtime; 6817c478bd9Sstevel@tonic-gate ds->cb_tick = src->cb_tick; 6827c478bd9Sstevel@tonic-gate } 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6857c478bd9Sstevel@tonic-gate void 6867c478bd9Sstevel@tonic-gate cpc_buf_zero(cpc_t *cpc, cpc_buf_t *buf) 6877c478bd9Sstevel@tonic-gate { 6887c478bd9Sstevel@tonic-gate bzero(buf->cb_data, buf->cb_size); 6897c478bd9Sstevel@tonic-gate buf->cb_hrtime = 0; 6907c478bd9Sstevel@tonic-gate buf->cb_tick = 0; 6917c478bd9Sstevel@tonic-gate } 6927c478bd9Sstevel@tonic-gate 6937c478bd9Sstevel@tonic-gate /* 6947c478bd9Sstevel@tonic-gate * Gets or sets the value of the request specified by index. 6957c478bd9Sstevel@tonic-gate */ 6967c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6977c478bd9Sstevel@tonic-gate int 6987c478bd9Sstevel@tonic-gate cpc_buf_get(cpc_t *cpc, cpc_buf_t *buf, int index, uint64_t *val) 6997c478bd9Sstevel@tonic-gate { 7007c478bd9Sstevel@tonic-gate *val = buf->cb_data[index]; 7017c478bd9Sstevel@tonic-gate 7027c478bd9Sstevel@tonic-gate return (0); 7037c478bd9Sstevel@tonic-gate } 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 7067c478bd9Sstevel@tonic-gate int 7077c478bd9Sstevel@tonic-gate cpc_buf_set(cpc_t *cpc, cpc_buf_t *buf, int index, uint64_t val) 7087c478bd9Sstevel@tonic-gate { 7097c478bd9Sstevel@tonic-gate buf->cb_data[index] = val; 7107c478bd9Sstevel@tonic-gate 7117c478bd9Sstevel@tonic-gate return (0); 7127c478bd9Sstevel@tonic-gate } 7137c478bd9Sstevel@tonic-gate 7147c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 7157c478bd9Sstevel@tonic-gate hrtime_t 7167c478bd9Sstevel@tonic-gate cpc_buf_hrtime(cpc_t *cpc, cpc_buf_t *buf) 7177c478bd9Sstevel@tonic-gate { 7187c478bd9Sstevel@tonic-gate return (buf->cb_hrtime); 7197c478bd9Sstevel@tonic-gate } 7207c478bd9Sstevel@tonic-gate 7217c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 7227c478bd9Sstevel@tonic-gate uint64_t 7237c478bd9Sstevel@tonic-gate cpc_buf_tick(cpc_t *cpc, cpc_buf_t *buf) 7247c478bd9Sstevel@tonic-gate { 7257c478bd9Sstevel@tonic-gate return (buf->cb_tick); 7267c478bd9Sstevel@tonic-gate } 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate static char * 7297c478bd9Sstevel@tonic-gate cpc_get_list(int which, int arg) 7307c478bd9Sstevel@tonic-gate { 7317c478bd9Sstevel@tonic-gate int szcmd; 7327c478bd9Sstevel@tonic-gate int size; 7337c478bd9Sstevel@tonic-gate char *list; 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate if (which == CPC_LIST_ATTRS) 7367c478bd9Sstevel@tonic-gate szcmd = CPC_ATTRLIST_SIZE; 7377c478bd9Sstevel@tonic-gate else 7387c478bd9Sstevel@tonic-gate szcmd = CPC_EVLIST_SIZE; 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate if (syscall(SYS_cpc, szcmd, -1, &size, arg, 0) != 0) 7417c478bd9Sstevel@tonic-gate return (NULL); 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate if ((list = malloc(size)) == NULL) 7447c478bd9Sstevel@tonic-gate return (NULL); 7457c478bd9Sstevel@tonic-gate 7467c478bd9Sstevel@tonic-gate if (syscall(SYS_cpc, which, -1, list, arg, 0) != 0) { 7477c478bd9Sstevel@tonic-gate free(list); 7487c478bd9Sstevel@tonic-gate return (NULL); 7497c478bd9Sstevel@tonic-gate } 7507c478bd9Sstevel@tonic-gate 7517c478bd9Sstevel@tonic-gate return (list); 7527c478bd9Sstevel@tonic-gate } 7537c478bd9Sstevel@tonic-gate 7547c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 7557c478bd9Sstevel@tonic-gate void 7567c478bd9Sstevel@tonic-gate cpc_walk_requests(cpc_t *cpc, cpc_set_t *set, void *arg, 7577c478bd9Sstevel@tonic-gate void (*action)(void *arg, int index, const char *event, uint64_t preset, 7587c478bd9Sstevel@tonic-gate uint_t flags, int nattrs, const cpc_attr_t *attrs)) 7597c478bd9Sstevel@tonic-gate { 7607c478bd9Sstevel@tonic-gate cpc_request_t *rp; 7617c478bd9Sstevel@tonic-gate cpc_attr_t *attrs = NULL; 7627c478bd9Sstevel@tonic-gate int i; 7637c478bd9Sstevel@tonic-gate 7647c478bd9Sstevel@tonic-gate for (rp = set->cs_request; rp != NULL; rp = rp->cr_next) { 7657c478bd9Sstevel@tonic-gate /* 7667c478bd9Sstevel@tonic-gate * Need to reconstruct a temporary cpc_attr_t array for req. 7677c478bd9Sstevel@tonic-gate */ 7687c478bd9Sstevel@tonic-gate if (rp->cr_nattrs != 0) 7697c478bd9Sstevel@tonic-gate if ((attrs = malloc(rp->cr_nattrs * 7707c478bd9Sstevel@tonic-gate sizeof (cpc_attr_t))) == NULL) 7717c478bd9Sstevel@tonic-gate return; 7727c478bd9Sstevel@tonic-gate for (i = 0; i < rp->cr_nattrs; i++) { 7737c478bd9Sstevel@tonic-gate attrs[i].ca_name = rp->cr_attr[i].ka_name; 7747c478bd9Sstevel@tonic-gate attrs[i].ca_val = rp->cr_attr[i].ka_val; 7757c478bd9Sstevel@tonic-gate } 7767c478bd9Sstevel@tonic-gate 7777c478bd9Sstevel@tonic-gate action(arg, rp->cr_index, rp->cr_event, rp->cr_preset, 7787c478bd9Sstevel@tonic-gate rp->cr_flags, rp->cr_nattrs, attrs); 7797c478bd9Sstevel@tonic-gate 7807c478bd9Sstevel@tonic-gate if (rp->cr_nattrs != 0) 7817c478bd9Sstevel@tonic-gate free(attrs); 7827c478bd9Sstevel@tonic-gate } 7837c478bd9Sstevel@tonic-gate } 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 786*e850fb01SKuriakose Kuruvilla static void 787*e850fb01SKuriakose Kuruvilla cpc_walk_events_impl(cpc_t *cpc, void *arg, 788*e850fb01SKuriakose Kuruvilla void (*action)(void *arg, const char *event), int is_generic) 7897c478bd9Sstevel@tonic-gate { 7907c478bd9Sstevel@tonic-gate char **list; 7917c478bd9Sstevel@tonic-gate char *p, *e; 7927c478bd9Sstevel@tonic-gate int i; 793*e850fb01SKuriakose Kuruvilla int is_papi; 7947c478bd9Sstevel@tonic-gate int ncounters = cpc_npic(cpc); 7957c478bd9Sstevel@tonic-gate cpc_strhash_t *hash; 7967c478bd9Sstevel@tonic-gate 7977c478bd9Sstevel@tonic-gate if ((list = malloc(ncounters * sizeof (char *))) == NULL) 7987c478bd9Sstevel@tonic-gate return; 7997c478bd9Sstevel@tonic-gate 8007c478bd9Sstevel@tonic-gate if ((hash = __cpc_strhash_alloc()) == NULL) { 8017c478bd9Sstevel@tonic-gate free(list); 8027c478bd9Sstevel@tonic-gate return; 8037c478bd9Sstevel@tonic-gate } 8047c478bd9Sstevel@tonic-gate 8057c478bd9Sstevel@tonic-gate for (i = 0; i < ncounters; i++) { 8067c478bd9Sstevel@tonic-gate if ((list[i] = strdup(cpc->cpc_evlist[i])) == NULL) 8077c478bd9Sstevel@tonic-gate goto err; 8087c478bd9Sstevel@tonic-gate p = list[i]; 8097c478bd9Sstevel@tonic-gate while ((e = strchr(p, ',')) != NULL) { 8107c478bd9Sstevel@tonic-gate *e = '\0'; 811c7a079a8SJonathan Haslam 812*e850fb01SKuriakose Kuruvilla /* 813*e850fb01SKuriakose Kuruvilla * Based on is_generic flag, skip appropriate 814*e850fb01SKuriakose Kuruvilla * event names. 815*e850fb01SKuriakose Kuruvilla */ 816*e850fb01SKuriakose Kuruvilla is_papi = (strncmp(p, "PAPI", 4) == 0); 817*e850fb01SKuriakose Kuruvilla if (is_generic != is_papi) { 818c7a079a8SJonathan Haslam p = e + 1; 819c7a079a8SJonathan Haslam continue; 820c7a079a8SJonathan Haslam } 821c7a079a8SJonathan Haslam 8227c478bd9Sstevel@tonic-gate if (__cpc_strhash_add(hash, p) == -1) 8237c478bd9Sstevel@tonic-gate goto err; 824*e850fb01SKuriakose Kuruvilla 8257c478bd9Sstevel@tonic-gate p = e + 1; 8267c478bd9Sstevel@tonic-gate } 827*e850fb01SKuriakose Kuruvilla 828*e850fb01SKuriakose Kuruvilla is_papi = (strncmp(p, "PAPI", 4) == 0); 829*e850fb01SKuriakose Kuruvilla if (is_generic == is_papi) { 8307c478bd9Sstevel@tonic-gate if (__cpc_strhash_add(hash, p) == -1) 8317c478bd9Sstevel@tonic-gate goto err; 8327c478bd9Sstevel@tonic-gate } 833c7a079a8SJonathan Haslam } 834c7a079a8SJonathan Haslam 835c7a079a8SJonathan Haslam while ((p = __cpc_strhash_next(hash)) != NULL) 836c7a079a8SJonathan Haslam action(arg, p); 837c7a079a8SJonathan Haslam 838c7a079a8SJonathan Haslam err: 839c7a079a8SJonathan Haslam __cpc_strhash_free(hash); 840c7a079a8SJonathan Haslam for (i = 0; i < ncounters; i++) 841c7a079a8SJonathan Haslam free(list[i]); 842c7a079a8SJonathan Haslam free(list); 843c7a079a8SJonathan Haslam } 844c7a079a8SJonathan Haslam 845c7a079a8SJonathan Haslam /*ARGSUSED*/ 846c7a079a8SJonathan Haslam void 847*e850fb01SKuriakose Kuruvilla cpc_walk_events_all(cpc_t *cpc, void *arg, 848*e850fb01SKuriakose Kuruvilla void (*action)(void *arg, const char *event)) 849*e850fb01SKuriakose Kuruvilla { 850*e850fb01SKuriakose Kuruvilla cpc_walk_events_impl(cpc, arg, action, 0); 851*e850fb01SKuriakose Kuruvilla } 852*e850fb01SKuriakose Kuruvilla 853*e850fb01SKuriakose Kuruvilla 854*e850fb01SKuriakose Kuruvilla /*ARGSUSED*/ 855*e850fb01SKuriakose Kuruvilla void 856c7a079a8SJonathan Haslam cpc_walk_generic_events_all(cpc_t *cpc, void *arg, 857c7a079a8SJonathan Haslam void (*action)(void *arg, const char *event)) 858c7a079a8SJonathan Haslam { 859*e850fb01SKuriakose Kuruvilla cpc_walk_events_impl(cpc, arg, action, 1); 860*e850fb01SKuriakose Kuruvilla } 861c7a079a8SJonathan Haslam 862*e850fb01SKuriakose Kuruvilla /*ARGSUSED*/ 863*e850fb01SKuriakose Kuruvilla static void 864*e850fb01SKuriakose Kuruvilla cpc_walk_events_pic_impl(cpc_t *cpc, uint_t picno, void *arg, 865*e850fb01SKuriakose Kuruvilla void (*action)(void *arg, uint_t picno, const char *event), int is_generic) 866*e850fb01SKuriakose Kuruvilla { 867*e850fb01SKuriakose Kuruvilla char *p; 868*e850fb01SKuriakose Kuruvilla char *e; 869*e850fb01SKuriakose Kuruvilla char *list; 870*e850fb01SKuriakose Kuruvilla int is_papi; 871c7a079a8SJonathan Haslam 872*e850fb01SKuriakose Kuruvilla if (picno >= cpc->cpc_npic) { 873*e850fb01SKuriakose Kuruvilla errno = EINVAL; 874c7a079a8SJonathan Haslam return; 875c7a079a8SJonathan Haslam } 876c7a079a8SJonathan Haslam 877*e850fb01SKuriakose Kuruvilla if ((list = strdup(cpc->cpc_evlist[picno])) == NULL) 878*e850fb01SKuriakose Kuruvilla return; 879*e850fb01SKuriakose Kuruvilla 880*e850fb01SKuriakose Kuruvilla /* 881*e850fb01SKuriakose Kuruvilla * List now points to a comma-separated list of events supported by 882*e850fb01SKuriakose Kuruvilla * the designated pic. 883*e850fb01SKuriakose Kuruvilla */ 884*e850fb01SKuriakose Kuruvilla p = list; 885c7a079a8SJonathan Haslam while ((e = strchr(p, ',')) != NULL) { 886c7a079a8SJonathan Haslam *e = '\0'; 887c7a079a8SJonathan Haslam 888*e850fb01SKuriakose Kuruvilla /* 889*e850fb01SKuriakose Kuruvilla * Based on is_generic flag, skip appropriate 890*e850fb01SKuriakose Kuruvilla * event names. 891*e850fb01SKuriakose Kuruvilla */ 892*e850fb01SKuriakose Kuruvilla is_papi = (strncmp(p, "PAPI", 4) == 0); 893*e850fb01SKuriakose Kuruvilla if (is_generic != is_papi) { 894c7a079a8SJonathan Haslam p = e + 1; 895c7a079a8SJonathan Haslam continue; 896c7a079a8SJonathan Haslam } 897c7a079a8SJonathan Haslam 898*e850fb01SKuriakose Kuruvilla action(arg, picno, p); 899c7a079a8SJonathan Haslam p = e + 1; 900c7a079a8SJonathan Haslam } 9017c478bd9Sstevel@tonic-gate 902*e850fb01SKuriakose Kuruvilla is_papi = (strncmp(p, "PAPI", 4) == 0); 903*e850fb01SKuriakose Kuruvilla if (is_generic == is_papi) 904*e850fb01SKuriakose Kuruvilla action(arg, picno, p); 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate free(list); 9077c478bd9Sstevel@tonic-gate } 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 9107c478bd9Sstevel@tonic-gate void 9117c478bd9Sstevel@tonic-gate cpc_walk_events_pic(cpc_t *cpc, uint_t picno, void *arg, 9127c478bd9Sstevel@tonic-gate void (*action)(void *arg, uint_t picno, const char *event)) 9137c478bd9Sstevel@tonic-gate { 914*e850fb01SKuriakose Kuruvilla cpc_walk_events_pic_impl(cpc, picno, arg, action, 0); 915c7a079a8SJonathan Haslam } 916c7a079a8SJonathan Haslam 917c7a079a8SJonathan Haslam /*ARGSUSED*/ 918c7a079a8SJonathan Haslam void 919c7a079a8SJonathan Haslam cpc_walk_generic_events_pic(cpc_t *cpc, uint_t picno, void *arg, 920c7a079a8SJonathan Haslam void (*action)(void *arg, uint_t picno, const char *event)) 921c7a079a8SJonathan Haslam { 922*e850fb01SKuriakose Kuruvilla cpc_walk_events_pic_impl(cpc, picno, arg, action, 1); 9237c478bd9Sstevel@tonic-gate } 9247c478bd9Sstevel@tonic-gate 9257c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 9267c478bd9Sstevel@tonic-gate void 9277c478bd9Sstevel@tonic-gate cpc_walk_attrs(cpc_t *cpc, void *arg, 9287c478bd9Sstevel@tonic-gate void (*action)(void *arg, const char *attr)) 9297c478bd9Sstevel@tonic-gate { 9307c478bd9Sstevel@tonic-gate char *p; 9317c478bd9Sstevel@tonic-gate char *e; 9327c478bd9Sstevel@tonic-gate char *list; 9337c478bd9Sstevel@tonic-gate 9347c478bd9Sstevel@tonic-gate if ((list = strdup(cpc->cpc_attrlist)) == NULL) 9357c478bd9Sstevel@tonic-gate return; 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate /* 9387c478bd9Sstevel@tonic-gate * Platforms with no attributes will return an empty string. 9397c478bd9Sstevel@tonic-gate */ 9407c478bd9Sstevel@tonic-gate if (*list == '\0') 9417c478bd9Sstevel@tonic-gate return; 9427c478bd9Sstevel@tonic-gate 9437c478bd9Sstevel@tonic-gate /* 9447c478bd9Sstevel@tonic-gate * List now points to a comma-separated list of attributes supported by 9457c478bd9Sstevel@tonic-gate * the underlying platform. 9467c478bd9Sstevel@tonic-gate */ 9477c478bd9Sstevel@tonic-gate p = list; 9487c478bd9Sstevel@tonic-gate while ((e = strchr(p, ',')) != NULL) { 9497c478bd9Sstevel@tonic-gate *e = '\0'; 9507c478bd9Sstevel@tonic-gate action(arg, p); 9517c478bd9Sstevel@tonic-gate p = e + 1; 9527c478bd9Sstevel@tonic-gate } 9537c478bd9Sstevel@tonic-gate action(arg, p); 9547c478bd9Sstevel@tonic-gate 9557c478bd9Sstevel@tonic-gate free(list); 9567c478bd9Sstevel@tonic-gate } 9577c478bd9Sstevel@tonic-gate 9587c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 9597c478bd9Sstevel@tonic-gate int 9607c478bd9Sstevel@tonic-gate cpc_enable(cpc_t *cpc) 9617c478bd9Sstevel@tonic-gate { 9627c478bd9Sstevel@tonic-gate return (syscall(SYS_cpc, CPC_ENABLE, -1, 0, 0, 0)); 9637c478bd9Sstevel@tonic-gate } 9647c478bd9Sstevel@tonic-gate 9657c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 9667c478bd9Sstevel@tonic-gate int 9677c478bd9Sstevel@tonic-gate cpc_disable(cpc_t *cpc) 9687c478bd9Sstevel@tonic-gate { 9697c478bd9Sstevel@tonic-gate return (syscall(SYS_cpc, CPC_DISABLE, -1, 0, 0, 0)); 9707c478bd9Sstevel@tonic-gate } 9717c478bd9Sstevel@tonic-gate 9727c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 9737c478bd9Sstevel@tonic-gate uint_t 9747c478bd9Sstevel@tonic-gate cpc_npic(cpc_t *cpc) 9757c478bd9Sstevel@tonic-gate { 9767c478bd9Sstevel@tonic-gate return (cpc->cpc_npic); 9777c478bd9Sstevel@tonic-gate } 9787c478bd9Sstevel@tonic-gate 9797c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 9807c478bd9Sstevel@tonic-gate uint_t 9817c478bd9Sstevel@tonic-gate cpc_caps(cpc_t *cpc) 9827c478bd9Sstevel@tonic-gate { 9837c478bd9Sstevel@tonic-gate return (cpc->cpc_caps); 9847c478bd9Sstevel@tonic-gate } 9857c478bd9Sstevel@tonic-gate 9867c478bd9Sstevel@tonic-gate const char * 9877c478bd9Sstevel@tonic-gate cpc_cciname(cpc_t *cpc) 9887c478bd9Sstevel@tonic-gate { 9897c478bd9Sstevel@tonic-gate return (cpc->cpc_cciname); 9907c478bd9Sstevel@tonic-gate } 9917c478bd9Sstevel@tonic-gate 9927c478bd9Sstevel@tonic-gate const char * 9937c478bd9Sstevel@tonic-gate cpc_cpuref(cpc_t *cpc) 9947c478bd9Sstevel@tonic-gate { 9957c478bd9Sstevel@tonic-gate return (cpc->cpc_cpuref); 9967c478bd9Sstevel@tonic-gate } 9977c478bd9Sstevel@tonic-gate 9987c478bd9Sstevel@tonic-gate int 9997c478bd9Sstevel@tonic-gate cpc_seterrhndlr(cpc_t *cpc, cpc_errhndlr_t *fn) 10007c478bd9Sstevel@tonic-gate { 10017c478bd9Sstevel@tonic-gate cpc->cpc_errfn = fn; 10027c478bd9Sstevel@tonic-gate return (0); 10037c478bd9Sstevel@tonic-gate } 10047c478bd9Sstevel@tonic-gate 10057c478bd9Sstevel@tonic-gate /* 10067c478bd9Sstevel@tonic-gate * These strings may contain printf() conversion specifiers. 10077c478bd9Sstevel@tonic-gate */ 10087c478bd9Sstevel@tonic-gate static const char *errstr[] = { 10097c478bd9Sstevel@tonic-gate "", /* zero slot filler */ 10107c478bd9Sstevel@tonic-gate "Unknown event\n", /* CPC_INVALID_EVENT */ 10117c478bd9Sstevel@tonic-gate "Invalid counter number\n", /* CPC_INVALID_PICNUM */ 10127c478bd9Sstevel@tonic-gate "Unknown attribute\n", /* CPC_INVALID_ATTRIBUTE */ 10137c478bd9Sstevel@tonic-gate "Attribute out of range\n", /* CPC_ATTRIBUTE_OUT_OF_RANGE */ 10147c478bd9Sstevel@tonic-gate "Hardware resource unavailable\n", /* CPC_RESOURCE_UNAVAIL */ 10157c478bd9Sstevel@tonic-gate "Counter cannot count requested event\n", /* CPC_PIC_NOT_CAPABLE */ 10167c478bd9Sstevel@tonic-gate "Invalid flags in a request\n", /* CPC_REQ_INVALID_FLAGS */ 10177c478bd9Sstevel@tonic-gate "Requests conflict with each other\n", /* CPC_CONFLICTING_REQS */ 10187c478bd9Sstevel@tonic-gate "Attribute requires the cpc_cpu privilege\n", /* CPC_ATTR_REQUIRES_PRIVILEGE */ 10198d4e547dSae112802 "Couldn't bind LWP to requested processor\n", /* CPC_PBIND_FAILED */ 10208d4e547dSae112802 "Hypervisor event access denied\n" /* CPC_HV_NO_ACCESS */ 10217c478bd9Sstevel@tonic-gate }; 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate /*VARARGS3*/ 10247c478bd9Sstevel@tonic-gate static void 10257c478bd9Sstevel@tonic-gate cpc_err(cpc_t *cpc, const char *fn, int subcode, ...) 10267c478bd9Sstevel@tonic-gate { 10277c478bd9Sstevel@tonic-gate va_list ap; 10287c478bd9Sstevel@tonic-gate const char *str; 10297c478bd9Sstevel@tonic-gate int error; 10307c478bd9Sstevel@tonic-gate 10317c478bd9Sstevel@tonic-gate /* 10327c478bd9Sstevel@tonic-gate * If subcode is -1, there is no specific description for this error. 10337c478bd9Sstevel@tonic-gate */ 10347c478bd9Sstevel@tonic-gate if (subcode == -1) 10357c478bd9Sstevel@tonic-gate return; 10367c478bd9Sstevel@tonic-gate 10377c478bd9Sstevel@tonic-gate /* 10387c478bd9Sstevel@tonic-gate * We need to preserve errno across calls to this function to prevent it 10397c478bd9Sstevel@tonic-gate * from being clobbered while here, or in the user's error handler. 10407c478bd9Sstevel@tonic-gate */ 10417c478bd9Sstevel@tonic-gate error = errno; 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate str = dgettext(TEXT_DOMAIN, errstr[subcode]); 10447c478bd9Sstevel@tonic-gate 10457c478bd9Sstevel@tonic-gate va_start(ap, subcode); 10467c478bd9Sstevel@tonic-gate if (cpc->cpc_errfn != NULL) 10477c478bd9Sstevel@tonic-gate cpc->cpc_errfn(fn, subcode, str, ap); 10487c478bd9Sstevel@tonic-gate else { 10497c478bd9Sstevel@tonic-gate /* 10507c478bd9Sstevel@tonic-gate * If printf() conversion specifiers are added to the errstr[] 10517c478bd9Sstevel@tonic-gate * table, this call needs to be changed to vfprintf(). 10527c478bd9Sstevel@tonic-gate */ 10537c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "libcpc: %s: %s", fn, str); 10547c478bd9Sstevel@tonic-gate } 10557c478bd9Sstevel@tonic-gate va_end(ap); 10567c478bd9Sstevel@tonic-gate 10577c478bd9Sstevel@tonic-gate errno = error; 10587c478bd9Sstevel@tonic-gate } 10597c478bd9Sstevel@tonic-gate 10607c478bd9Sstevel@tonic-gate /* 10617c478bd9Sstevel@tonic-gate * Hook used by libpctx to alert libcpc when a pctx handle is going away. 10627c478bd9Sstevel@tonic-gate * This is necessary to prevent libcpc from attempting a libpctx operation on a 10637c478bd9Sstevel@tonic-gate * stale and invalid pctx_t handle. Since pctx_t's are cached by libcpc, we need 10647c478bd9Sstevel@tonic-gate * to be notified when they go away. 10657c478bd9Sstevel@tonic-gate */ 10667c478bd9Sstevel@tonic-gate static void 10677c478bd9Sstevel@tonic-gate cpc_invalidate_pctx(cpc_t *cpc, pctx_t *pctx) 10687c478bd9Sstevel@tonic-gate { 10697c478bd9Sstevel@tonic-gate cpc_set_t *set; 10707c478bd9Sstevel@tonic-gate int sigblocked; 10717c478bd9Sstevel@tonic-gate 10727c478bd9Sstevel@tonic-gate sigblocked = cpc_lock(cpc); 10737c478bd9Sstevel@tonic-gate for (set = cpc->cpc_sets; set != NULL; set = set->cs_next) 10747c478bd9Sstevel@tonic-gate if (set->cs_pctx == pctx) 10757c478bd9Sstevel@tonic-gate set->cs_pctx = NULL; 10767c478bd9Sstevel@tonic-gate cpc_unlock(cpc, sigblocked); 10777c478bd9Sstevel@tonic-gate } 10787c478bd9Sstevel@tonic-gate 10797c478bd9Sstevel@tonic-gate /* 10807c478bd9Sstevel@tonic-gate * Check that the set is valid; if so it will be in the cpc handle's 10817c478bd9Sstevel@tonic-gate * list of sets. The lock protects the list of sets, but not the set 10827c478bd9Sstevel@tonic-gate * itself. 10837c478bd9Sstevel@tonic-gate */ 10847c478bd9Sstevel@tonic-gate static int 10857c478bd9Sstevel@tonic-gate cpc_set_valid(cpc_t *cpc, cpc_set_t *set) 10867c478bd9Sstevel@tonic-gate { 10877c478bd9Sstevel@tonic-gate cpc_set_t *csp; 10887c478bd9Sstevel@tonic-gate int sigblocked; 10897c478bd9Sstevel@tonic-gate 10907c478bd9Sstevel@tonic-gate sigblocked = cpc_lock(cpc); 10917c478bd9Sstevel@tonic-gate for (csp = cpc->cpc_sets; csp != NULL; csp = csp->cs_next) 10927c478bd9Sstevel@tonic-gate if (csp == set) 10937c478bd9Sstevel@tonic-gate break; 10947c478bd9Sstevel@tonic-gate cpc_unlock(cpc, sigblocked); 10957c478bd9Sstevel@tonic-gate if (csp == NULL) 10967c478bd9Sstevel@tonic-gate return (-1); 10977c478bd9Sstevel@tonic-gate return (0); 10987c478bd9Sstevel@tonic-gate } 10997c478bd9Sstevel@tonic-gate 11007c478bd9Sstevel@tonic-gate static int 11017c478bd9Sstevel@tonic-gate cpc_lock(cpc_t *cpc) 11027c478bd9Sstevel@tonic-gate { 11037c478bd9Sstevel@tonic-gate int ret = (sigset(SIGEMT, SIG_HOLD) == SIG_HOLD); 11047c478bd9Sstevel@tonic-gate (void) mutex_lock(&cpc->cpc_lock); 11057c478bd9Sstevel@tonic-gate return (ret); 11067c478bd9Sstevel@tonic-gate } 11077c478bd9Sstevel@tonic-gate 11087c478bd9Sstevel@tonic-gate static void 11097c478bd9Sstevel@tonic-gate cpc_unlock(cpc_t *cpc, int sigblocked) 11107c478bd9Sstevel@tonic-gate { 11117c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cpc->cpc_lock); 11127c478bd9Sstevel@tonic-gate if (sigblocked == 0) 11137c478bd9Sstevel@tonic-gate (void) sigrelse(SIGEMT); 11147c478bd9Sstevel@tonic-gate } 11157c478bd9Sstevel@tonic-gate 11167c478bd9Sstevel@tonic-gate struct priv { 11177c478bd9Sstevel@tonic-gate const char *name; 11187c478bd9Sstevel@tonic-gate int found; 11197c478bd9Sstevel@tonic-gate }; 11207c478bd9Sstevel@tonic-gate 11217c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 11227c478bd9Sstevel@tonic-gate static void 11237c478bd9Sstevel@tonic-gate ev_walker(void *arg, uint_t picno, const char *ev) 11247c478bd9Sstevel@tonic-gate { 11257c478bd9Sstevel@tonic-gate if (strcmp(((struct priv *)arg)->name, ev) == 0) 11267c478bd9Sstevel@tonic-gate ((struct priv *)arg)->found = 1; 11277c478bd9Sstevel@tonic-gate } 11287c478bd9Sstevel@tonic-gate 11297c478bd9Sstevel@tonic-gate static void 11307c478bd9Sstevel@tonic-gate at_walker(void *arg, const char *at) 11317c478bd9Sstevel@tonic-gate { 11327c478bd9Sstevel@tonic-gate if (strcmp(((struct priv *)arg)->name, at) == 0) 11337c478bd9Sstevel@tonic-gate ((struct priv *)arg)->found = 1; 11347c478bd9Sstevel@tonic-gate } 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate static int 11377c478bd9Sstevel@tonic-gate cpc_valid_event(cpc_t *cpc, uint_t pic, const char *ev) 11387c478bd9Sstevel@tonic-gate { 11397c478bd9Sstevel@tonic-gate struct priv pr = { NULL, 0 }; 1140d0ecda70Svk226950 char *end_ev; 1141*e850fb01SKuriakose Kuruvilla int err; 11427c478bd9Sstevel@tonic-gate 11437c478bd9Sstevel@tonic-gate pr.name = ev; 11447c478bd9Sstevel@tonic-gate cpc_walk_events_pic(cpc, pic, &pr, ev_walker); 11455d3a5ad8Srab if (pr.found) 11465d3a5ad8Srab return (1); 11475d3a5ad8Srab 1148c7a079a8SJonathan Haslam cpc_walk_generic_events_pic(cpc, pic, &pr, ev_walker); 1149c7a079a8SJonathan Haslam if (pr.found) 1150c7a079a8SJonathan Haslam return (1); 1151c7a079a8SJonathan Haslam 11525d3a5ad8Srab /* 11535d3a5ad8Srab * Before assuming this is an invalid event, see if we have been given 1154*e850fb01SKuriakose Kuruvilla * a raw event code. 1155d0ecda70Svk226950 * Check the second argument of strtol() to ensure invalid events 1156d0ecda70Svk226950 * beginning with number do not go through. 11575d3a5ad8Srab */ 1158*e850fb01SKuriakose Kuruvilla err = errno; 1159*e850fb01SKuriakose Kuruvilla errno = 0; 1160*e850fb01SKuriakose Kuruvilla (void) strtol(ev, &end_ev, 0); 1161*e850fb01SKuriakose Kuruvilla if ((errno == 0) && (*end_ev == '\0')) { 11625d3a5ad8Srab /* 11635d3a5ad8Srab * Success - this is a valid raw code in hex, decimal, or octal. 11645d3a5ad8Srab */ 1165*e850fb01SKuriakose Kuruvilla errno = err; 11665d3a5ad8Srab return (1); 1167*e850fb01SKuriakose Kuruvilla } 11685d3a5ad8Srab 1169*e850fb01SKuriakose Kuruvilla errno = err; 11705d3a5ad8Srab return (0); 11717c478bd9Sstevel@tonic-gate } 11727c478bd9Sstevel@tonic-gate 11737c478bd9Sstevel@tonic-gate static int 11747c478bd9Sstevel@tonic-gate cpc_valid_attr(cpc_t *cpc, char *attr) 11757c478bd9Sstevel@tonic-gate { 11767c478bd9Sstevel@tonic-gate struct priv pr = { NULL, 0 }; 11777c478bd9Sstevel@tonic-gate 11787c478bd9Sstevel@tonic-gate pr.name = attr; 11797c478bd9Sstevel@tonic-gate cpc_walk_attrs(cpc, &pr, at_walker); 11807c478bd9Sstevel@tonic-gate return (pr.found); 11817c478bd9Sstevel@tonic-gate } 1182