1ea1a228cSschwartz /* 2ea1a228cSschwartz * CDDL HEADER START 3ea1a228cSschwartz * 4ea1a228cSschwartz * The contents of this file are subject to the terms of the 5ea1a228cSschwartz * Common Development and Distribution License (the "License"). 6ea1a228cSschwartz * You may not use this file except in compliance with the License. 7ea1a228cSschwartz * 8ea1a228cSschwartz * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9ea1a228cSschwartz * or http://www.opensolaris.org/os/licensing. 10ea1a228cSschwartz * See the License for the specific language governing permissions 11ea1a228cSschwartz * and limitations under the License. 12ea1a228cSschwartz * 13ea1a228cSschwartz * When distributing Covered Code, include this CDDL HEADER in each 14ea1a228cSschwartz * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15ea1a228cSschwartz * If applicable, add the following below this CDDL HEADER, with the 16ea1a228cSschwartz * fields enclosed by brackets "[]" replaced with your own identifying 17ea1a228cSschwartz * information: Portions Copyright [yyyy] [name of copyright owner] 18ea1a228cSschwartz * 19ea1a228cSschwartz * CDDL HEADER END 20ea1a228cSschwartz */ 21ea1a228cSschwartz 22ea1a228cSschwartz /* 23*19397407SSherry Moore * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24ea1a228cSschwartz * Use is subject to license terms. 25ea1a228cSschwartz */ 26ea1a228cSschwartz 27ea1a228cSschwartz 28ea1a228cSschwartz /* 29ea1a228cSschwartz * Driver interconnect for the N2 PIU performance counter driver. 30ea1a228cSschwartz */ 31ea1a228cSschwartz 32ea1a228cSschwartz #include <sys/types.h> 33ea1a228cSschwartz #include <sys/ddi.h> 34ea1a228cSschwartz #include <sys/modctl.h> 35ea1a228cSschwartz #include <sys/hsvc.h> 36ea1a228cSschwartz #include <n2piupc_tables.h> 37ea1a228cSschwartz #include <n2piupc.h> 38ea1a228cSschwartz 39ea1a228cSschwartz /* Debugging level. */ 40ea1a228cSschwartz #ifdef DEBUG 41ea1a228cSschwartz int n2piupc_debug = 0; 42ea1a228cSschwartz #endif /* DEBUG */ 43ea1a228cSschwartz 44ea1a228cSschwartz /* State structure anchor. */ 45ea1a228cSschwartz void *n2piupc_state_p; 46ea1a228cSschwartz 47ea1a228cSschwartz static int n2piupc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 48ea1a228cSschwartz static int n2piupc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 49ea1a228cSschwartz 50ea1a228cSschwartz /* 51ea1a228cSschwartz * Support for hypervisor versioning. 52ea1a228cSschwartz * Need to negotiate for the N2PIU_PERF_COUNTER_GROUP 53ea1a228cSschwartz */ 54ea1a228cSschwartz 55ea1a228cSschwartz #define N2PIUPC_REQ_MAJOR_VER 1 56ea1a228cSschwartz #define N2PIUPC_REQ_MINOR_VER 0 57ea1a228cSschwartz 58ea1a228cSschwartz static hsvc_info_t n2piupc_hsvc = { 59ea1a228cSschwartz HSVC_REV_1, 60ea1a228cSschwartz NULL, 61ea1a228cSschwartz N2PIU_PERF_COUNTER_GROUP_ID, 62ea1a228cSschwartz N2PIUPC_REQ_MAJOR_VER, 63ea1a228cSschwartz N2PIUPC_REQ_MINOR_VER, 64ea1a228cSschwartz MODULE_NAME /* Passed in as a #define from Makefile */ 65ea1a228cSschwartz }; 66ea1a228cSschwartz 67ea1a228cSschwartz static uint64_t n2piupc_sup_minor; 68ea1a228cSschwartz 69ea1a228cSschwartz /* Driver boilerplate stuff. Having no minor nodes keep things very simple. */ 70ea1a228cSschwartz 71ea1a228cSschwartz static struct dev_ops n2piupc_ops = { 72ea1a228cSschwartz DEVO_REV, 73ea1a228cSschwartz 0, 74ea1a228cSschwartz nulldev, 75ea1a228cSschwartz nulldev, 76ea1a228cSschwartz nulldev, 77ea1a228cSschwartz n2piupc_attach, 78ea1a228cSschwartz n2piupc_detach, 79ea1a228cSschwartz nodev, 80ea1a228cSschwartz NULL, 81ea1a228cSschwartz NULL, 82*19397407SSherry Moore nodev, 83*19397407SSherry Moore ddi_quiesce_not_needed, 84ea1a228cSschwartz }; 85ea1a228cSschwartz 86ea1a228cSschwartz extern struct mod_ops mod_driverops; 87ea1a228cSschwartz 88ea1a228cSschwartz static struct modldrv md = { 89ea1a228cSschwartz &mod_driverops, 90*19397407SSherry Moore "N2 PIU Perf Counter", 91ea1a228cSschwartz &n2piupc_ops, 92ea1a228cSschwartz }; 93ea1a228cSschwartz 94ea1a228cSschwartz static struct modlinkage ml = { 95ea1a228cSschwartz MODREV_1, 96ea1a228cSschwartz (void *)&md, 97ea1a228cSschwartz NULL 98ea1a228cSschwartz }; 99ea1a228cSschwartz 100ea1a228cSschwartz 101ea1a228cSschwartz /* 102ea1a228cSschwartz * One-time module-wide initialization. 103ea1a228cSschwartz */ 104ea1a228cSschwartz int 105ea1a228cSschwartz _init(void) 106ea1a228cSschwartz { 107ea1a228cSschwartz int rval; 108ea1a228cSschwartz 109ea1a228cSschwartz /* Negotiate for hypervisor support. */ 110ea1a228cSschwartz if ((rval = hsvc_register(&n2piupc_hsvc, &n2piupc_sup_minor)) != 111ea1a228cSschwartz DDI_SUCCESS) { 112ea1a228cSschwartz N2PIUPC_DBG1("%s: Could not hsvc_register: %d\n", 113ea1a228cSschwartz MODULE_NAME, rval); 114ea1a228cSschwartz goto bad_hv_register; 115ea1a228cSschwartz } 116ea1a228cSschwartz 117ea1a228cSschwartz /* Initialize per-leaf soft state pointer. */ 118ea1a228cSschwartz if ((rval = ddi_soft_state_init(&n2piupc_state_p, 119ea1a228cSschwartz sizeof (n2piupc_t), 1)) != DDI_SUCCESS) 120ea1a228cSschwartz goto bad_softstate_init; 121ea1a228cSschwartz 122ea1a228cSschwartz /* Initialize one-time kstat structures. */ 123ea1a228cSschwartz if ((rval = n2piupc_kstat_init()) != DDI_SUCCESS) 124ea1a228cSschwartz goto bad_kstat_init; 125ea1a228cSschwartz 126ea1a228cSschwartz /* If all checks out, install the module. */ 127ea1a228cSschwartz if ((rval = mod_install(&ml)) == DDI_SUCCESS) 128ea1a228cSschwartz 129ea1a228cSschwartz return (DDI_SUCCESS); 130ea1a228cSschwartz 131ea1a228cSschwartz bad_mod_install: 132ea1a228cSschwartz n2piupc_kstat_fini(); 133ea1a228cSschwartz bad_kstat_init: 134ea1a228cSschwartz ddi_soft_state_fini(&n2piupc_state_p); 135ea1a228cSschwartz bad_softstate_init: 136ea1a228cSschwartz (void) hsvc_unregister(&n2piupc_hsvc); 137ea1a228cSschwartz bad_hv_register: 138ea1a228cSschwartz return (rval); 139ea1a228cSschwartz } 140ea1a228cSschwartz 141ea1a228cSschwartz /* 142ea1a228cSschwartz * One-time module-wide cleanup, after last detach is done. 143ea1a228cSschwartz */ 144ea1a228cSschwartz int 145ea1a228cSschwartz _fini(void) 146ea1a228cSschwartz { 147ea1a228cSschwartz int rval; 148ea1a228cSschwartz 149ea1a228cSschwartz /* 150ea1a228cSschwartz * Remove the module first as this operation is the only thing here 151ea1a228cSschwartz * which can fail. 152ea1a228cSschwartz */ 153ea1a228cSschwartz rval = mod_remove(&ml); 154ea1a228cSschwartz if (rval != DDI_SUCCESS) 155ea1a228cSschwartz return (rval); 156ea1a228cSschwartz 157ea1a228cSschwartz /* One-shot kstat data structure cleanup. */ 158ea1a228cSschwartz n2piupc_kstat_fini(); 159ea1a228cSschwartz 160ea1a228cSschwartz /* Free px soft state */ 161ea1a228cSschwartz ddi_soft_state_fini(&n2piupc_state_p); 162ea1a228cSschwartz 163ea1a228cSschwartz /* Unregister with hypervisor. */ 164ea1a228cSschwartz (void) hsvc_unregister(&n2piupc_hsvc); 165ea1a228cSschwartz 166ea1a228cSschwartz return (rval); 167ea1a228cSschwartz } 168ea1a228cSschwartz 169ea1a228cSschwartz int 170ea1a228cSschwartz _info(struct modinfo *modinfop) 171ea1a228cSschwartz { 172ea1a228cSschwartz return (mod_info(&ml, modinfop)); 173ea1a228cSschwartz } 174ea1a228cSschwartz 175ea1a228cSschwartz /* 176ea1a228cSschwartz * Per-instance initialization. Suspend/resume not supported. 177ea1a228cSschwartz */ 178ea1a228cSschwartz static int 179ea1a228cSschwartz n2piupc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 180ea1a228cSschwartz { 181ea1a228cSschwartz n2piupc_t *n2piupc_p; 182ea1a228cSschwartz uint32_t regprop[4]; 183ea1a228cSschwartz int len; 184ea1a228cSschwartz int instance = ddi_get_instance(dip); 185ea1a228cSschwartz 186ea1a228cSschwartz switch (cmd) { 187ea1a228cSschwartz case DDI_RESUME: 188ea1a228cSschwartz case DDI_ATTACH: 189ea1a228cSschwartz if (ddi_soft_state_zalloc(n2piupc_state_p, instance) != 190ea1a228cSschwartz DDI_SUCCESS) { 191ea1a228cSschwartz cmn_err(CE_WARN, "%s%d: Can't allocate softstate.\n", 192ea1a228cSschwartz NAMEINST(dip)); 193ea1a228cSschwartz goto bad_softstate; 194ea1a228cSschwartz } 195ea1a228cSschwartz 196ea1a228cSschwartz n2piupc_p = (n2piupc_t *)ddi_get_soft_state(n2piupc_state_p, 197ea1a228cSschwartz instance); 198ea1a228cSschwartz 199ea1a228cSschwartz n2piupc_p->n2piupc_dip = dip; 200ea1a228cSschwartz 201ea1a228cSschwartz /* Get handle for hypervisor access of performance counters. */ 202ea1a228cSschwartz len = sizeof (regprop); 203ea1a228cSschwartz if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 204ea1a228cSschwartz "reg", (caddr_t)regprop, &len) != DDI_SUCCESS) { 205ea1a228cSschwartz 206ea1a228cSschwartz cmn_err(CE_WARN, 207ea1a228cSschwartz "%s%d: Cannot get reg property\n", 208ea1a228cSschwartz NAMEINST(dip)); 209ea1a228cSschwartz goto bad_handle; 210ea1a228cSschwartz } 211ea1a228cSschwartz 212ea1a228cSschwartz /* Look only at the lower 28 bits of the highest cell. */ 213ea1a228cSschwartz n2piupc_p->n2piupc_handle = regprop[0] & 0xfffffff; 214ea1a228cSschwartz 215ea1a228cSschwartz /* Set up kstats. */ 216ea1a228cSschwartz if (n2piupc_kstat_attach(n2piupc_p) != DDI_SUCCESS) 217ea1a228cSschwartz goto bad_kstat_attach; 218ea1a228cSschwartz 219ea1a228cSschwartz return (DDI_SUCCESS); 220ea1a228cSschwartz 221ea1a228cSschwartz bad_kstat_attach: 222ea1a228cSschwartz bad_handle: 223ea1a228cSschwartz (void) ddi_soft_state_free(n2piupc_state_p, instance); 224ea1a228cSschwartz bad_softstate: 225ea1a228cSschwartz return (DDI_FAILURE); 226ea1a228cSschwartz 227ea1a228cSschwartz default: 228ea1a228cSschwartz return (DDI_FAILURE); 229ea1a228cSschwartz } 230ea1a228cSschwartz } 231ea1a228cSschwartz 232ea1a228cSschwartz /* 233ea1a228cSschwartz * Per-instance cleanup. Suspend/resume not supported. 234ea1a228cSschwartz */ 235ea1a228cSschwartz static int 236ea1a228cSschwartz n2piupc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 237ea1a228cSschwartz { 238ea1a228cSschwartz int instance = ddi_get_instance(dip); 239ea1a228cSschwartz 240ea1a228cSschwartz n2piupc_t *n2piupc_p = (n2piupc_t *)ddi_get_soft_state( 241ea1a228cSschwartz n2piupc_state_p, instance); 242ea1a228cSschwartz 243ea1a228cSschwartz switch (cmd) { 244ea1a228cSschwartz case DDI_SUSPEND: 245ea1a228cSschwartz case DDI_DETACH: 246ea1a228cSschwartz n2piupc_kstat_detach(n2piupc_p); 247ea1a228cSschwartz (void) ddi_soft_state_free(n2piupc_state_p, instance); 248ea1a228cSschwartz 249ea1a228cSschwartz return (DDI_SUCCESS); 250ea1a228cSschwartz 251ea1a228cSschwartz default: 252ea1a228cSschwartz return (DDI_FAILURE); 253ea1a228cSschwartz } 254ea1a228cSschwartz } 255