1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 30*7c478bd9Sstevel@tonic-gate #include <sys/conf.h> 31*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 32*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 33*7c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/ddi_subrdefs.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/pci.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/autoconf.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/errno.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/debug.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/pmubus.h> 43*7c478bd9Sstevel@tonic-gate 44*7c478bd9Sstevel@tonic-gate #include <sys/nexusdebug.h> 45*7c478bd9Sstevel@tonic-gate /* Bitfield debugging definitions for this file */ 46*7c478bd9Sstevel@tonic-gate #define PMUBUS_MAP_DEBUG 0x1 47*7c478bd9Sstevel@tonic-gate #define PMUBUS_REGACCESS_DEBUG 0x2 48*7c478bd9Sstevel@tonic-gate #define PMUBUS_RW_DEBUG 0x4 49*7c478bd9Sstevel@tonic-gate 50*7c478bd9Sstevel@tonic-gate /* 51*7c478bd9Sstevel@tonic-gate * The pmubus nexus is used to manage a shared register space. Rather 52*7c478bd9Sstevel@tonic-gate * than having several driver's physically alias register mappings and 53*7c478bd9Sstevel@tonic-gate * have potential problems with register collisions, this nexus will 54*7c478bd9Sstevel@tonic-gate * serialize the access to this space. 55*7c478bd9Sstevel@tonic-gate * 56*7c478bd9Sstevel@tonic-gate * There are two types of sharing going on here: 57*7c478bd9Sstevel@tonic-gate * 1) Registers within the address space may be shared, however the registers 58*7c478bd9Sstevel@tonic-gate * themselves are unique. The upper bit of the child's high address being zero 59*7c478bd9Sstevel@tonic-gate * signifies this register type. 60*7c478bd9Sstevel@tonic-gate * 61*7c478bd9Sstevel@tonic-gate * 2) The second type of register is one where a device may only own a few 62*7c478bd9Sstevel@tonic-gate * bits in the register. I'll term this as "bit lane" access. This is a more 63*7c478bd9Sstevel@tonic-gate * complicated scenario. The drivers themselves are responsible for knowing 64*7c478bd9Sstevel@tonic-gate * which bit lanes in the register they own. The read of a register only 65*7c478bd9Sstevel@tonic-gate * guarantees that those bits the driver is interested in are valid. If a 66*7c478bd9Sstevel@tonic-gate * driver needs to set bits in a register, a read must be done first to 67*7c478bd9Sstevel@tonic-gate * identify the state of the drivers bits. Depending on which way a bit needs 68*7c478bd9Sstevel@tonic-gate * to be driven, the driver will write a 1 to the bit to toggle it. If a bit 69*7c478bd9Sstevel@tonic-gate * is to remain unchanged, a 0 is written to the bit. So the access to the 70*7c478bd9Sstevel@tonic-gate * bit lane is an xor operation. 71*7c478bd9Sstevel@tonic-gate */ 72*7c478bd9Sstevel@tonic-gate /* 73*7c478bd9Sstevel@tonic-gate * Function prototypes for busops routines: 74*7c478bd9Sstevel@tonic-gate */ 75*7c478bd9Sstevel@tonic-gate static int pmubus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 76*7c478bd9Sstevel@tonic-gate off_t off, off_t len, caddr_t *addrp); 77*7c478bd9Sstevel@tonic-gate static int pmubus_ctlops(dev_info_t *dip, dev_info_t *rdip, 78*7c478bd9Sstevel@tonic-gate ddi_ctl_enum_t op, void *arg, void *result); 79*7c478bd9Sstevel@tonic-gate 80*7c478bd9Sstevel@tonic-gate /* 81*7c478bd9Sstevel@tonic-gate * function prototypes for dev ops routines: 82*7c478bd9Sstevel@tonic-gate */ 83*7c478bd9Sstevel@tonic-gate static int pmubus_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 84*7c478bd9Sstevel@tonic-gate static int pmubus_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 85*7c478bd9Sstevel@tonic-gate 86*7c478bd9Sstevel@tonic-gate /* 87*7c478bd9Sstevel@tonic-gate * general function prototypes: 88*7c478bd9Sstevel@tonic-gate */ 89*7c478bd9Sstevel@tonic-gate 90*7c478bd9Sstevel@tonic-gate /* 91*7c478bd9Sstevel@tonic-gate * bus ops and dev ops structures: 92*7c478bd9Sstevel@tonic-gate */ 93*7c478bd9Sstevel@tonic-gate static struct bus_ops pmubus_bus_ops = { 94*7c478bd9Sstevel@tonic-gate BUSO_REV, 95*7c478bd9Sstevel@tonic-gate pmubus_map, 96*7c478bd9Sstevel@tonic-gate NULL, 97*7c478bd9Sstevel@tonic-gate NULL, 98*7c478bd9Sstevel@tonic-gate NULL, 99*7c478bd9Sstevel@tonic-gate i_ddi_map_fault, 100*7c478bd9Sstevel@tonic-gate ddi_dma_map, 101*7c478bd9Sstevel@tonic-gate ddi_dma_allochdl, 102*7c478bd9Sstevel@tonic-gate ddi_dma_freehdl, 103*7c478bd9Sstevel@tonic-gate ddi_dma_bindhdl, 104*7c478bd9Sstevel@tonic-gate ddi_dma_unbindhdl, 105*7c478bd9Sstevel@tonic-gate ddi_dma_flush, 106*7c478bd9Sstevel@tonic-gate ddi_dma_win, 107*7c478bd9Sstevel@tonic-gate ddi_dma_mctl, 108*7c478bd9Sstevel@tonic-gate pmubus_ctlops, 109*7c478bd9Sstevel@tonic-gate ddi_bus_prop_op, 110*7c478bd9Sstevel@tonic-gate 0, /* (*bus_get_eventcookie)(); */ 111*7c478bd9Sstevel@tonic-gate 0, /* (*bus_add_eventcall)(); */ 112*7c478bd9Sstevel@tonic-gate 0, /* (*bus_remove_eventcall)(); */ 113*7c478bd9Sstevel@tonic-gate 0, /* (*bus_post_event)(); */ 114*7c478bd9Sstevel@tonic-gate 0, /* interrupt control */ 115*7c478bd9Sstevel@tonic-gate 0, /* bus_config */ 116*7c478bd9Sstevel@tonic-gate 0, /* bus_unconfig */ 117*7c478bd9Sstevel@tonic-gate 0, /* bus_fm_init */ 118*7c478bd9Sstevel@tonic-gate 0, /* bus_fm_fini */ 119*7c478bd9Sstevel@tonic-gate 0, /* bus_fm_access_enter */ 120*7c478bd9Sstevel@tonic-gate 0, /* bus_fm_access_exit */ 121*7c478bd9Sstevel@tonic-gate 0, /* bus_power */ 122*7c478bd9Sstevel@tonic-gate i_ddi_intr_ops /* bus_intr_op */ 123*7c478bd9Sstevel@tonic-gate }; 124*7c478bd9Sstevel@tonic-gate 125*7c478bd9Sstevel@tonic-gate static struct dev_ops pmubus_ops = { 126*7c478bd9Sstevel@tonic-gate DEVO_REV, 127*7c478bd9Sstevel@tonic-gate 0, 128*7c478bd9Sstevel@tonic-gate ddi_no_info, 129*7c478bd9Sstevel@tonic-gate nulldev, 130*7c478bd9Sstevel@tonic-gate 0, 131*7c478bd9Sstevel@tonic-gate pmubus_attach, 132*7c478bd9Sstevel@tonic-gate pmubus_detach, 133*7c478bd9Sstevel@tonic-gate nodev, 134*7c478bd9Sstevel@tonic-gate (struct cb_ops *)0, 135*7c478bd9Sstevel@tonic-gate &pmubus_bus_ops 136*7c478bd9Sstevel@tonic-gate }; 137*7c478bd9Sstevel@tonic-gate 138*7c478bd9Sstevel@tonic-gate /* 139*7c478bd9Sstevel@tonic-gate * module definitions: 140*7c478bd9Sstevel@tonic-gate */ 141*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 142*7c478bd9Sstevel@tonic-gate extern struct mod_ops mod_driverops; 143*7c478bd9Sstevel@tonic-gate 144*7c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 145*7c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */ 146*7c478bd9Sstevel@tonic-gate "pmubus nexus driver", /* Name of module. */ 147*7c478bd9Sstevel@tonic-gate &pmubus_ops, /* driver ops */ 148*7c478bd9Sstevel@tonic-gate }; 149*7c478bd9Sstevel@tonic-gate 150*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 151*7c478bd9Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL 152*7c478bd9Sstevel@tonic-gate }; 153*7c478bd9Sstevel@tonic-gate 154*7c478bd9Sstevel@tonic-gate /* 155*7c478bd9Sstevel@tonic-gate * driver global data: 156*7c478bd9Sstevel@tonic-gate */ 157*7c478bd9Sstevel@tonic-gate static void *per_pmubus_state; /* per-pmubus soft state pointer */ 158*7c478bd9Sstevel@tonic-gate 159*7c478bd9Sstevel@tonic-gate int 160*7c478bd9Sstevel@tonic-gate _init(void) 161*7c478bd9Sstevel@tonic-gate { 162*7c478bd9Sstevel@tonic-gate int e; 163*7c478bd9Sstevel@tonic-gate 164*7c478bd9Sstevel@tonic-gate /* 165*7c478bd9Sstevel@tonic-gate * Initialize per-pmubus soft state pointer. 166*7c478bd9Sstevel@tonic-gate */ 167*7c478bd9Sstevel@tonic-gate e = ddi_soft_state_init(&per_pmubus_state, 168*7c478bd9Sstevel@tonic-gate sizeof (pmubus_devstate_t), 1); 169*7c478bd9Sstevel@tonic-gate if (e != 0) 170*7c478bd9Sstevel@tonic-gate return (e); 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate /* 173*7c478bd9Sstevel@tonic-gate * Install the module. 174*7c478bd9Sstevel@tonic-gate */ 175*7c478bd9Sstevel@tonic-gate e = mod_install(&modlinkage); 176*7c478bd9Sstevel@tonic-gate if (e != 0) 177*7c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&per_pmubus_state); 178*7c478bd9Sstevel@tonic-gate 179*7c478bd9Sstevel@tonic-gate return (e); 180*7c478bd9Sstevel@tonic-gate } 181*7c478bd9Sstevel@tonic-gate 182*7c478bd9Sstevel@tonic-gate int 183*7c478bd9Sstevel@tonic-gate _fini(void) 184*7c478bd9Sstevel@tonic-gate { 185*7c478bd9Sstevel@tonic-gate int e; 186*7c478bd9Sstevel@tonic-gate 187*7c478bd9Sstevel@tonic-gate /* 188*7c478bd9Sstevel@tonic-gate * Remove the module. 189*7c478bd9Sstevel@tonic-gate */ 190*7c478bd9Sstevel@tonic-gate e = mod_remove(&modlinkage); 191*7c478bd9Sstevel@tonic-gate if (e != 0) 192*7c478bd9Sstevel@tonic-gate return (e); 193*7c478bd9Sstevel@tonic-gate 194*7c478bd9Sstevel@tonic-gate /* 195*7c478bd9Sstevel@tonic-gate * Free the soft state info. 196*7c478bd9Sstevel@tonic-gate */ 197*7c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&per_pmubus_state); 198*7c478bd9Sstevel@tonic-gate return (e); 199*7c478bd9Sstevel@tonic-gate } 200*7c478bd9Sstevel@tonic-gate 201*7c478bd9Sstevel@tonic-gate int 202*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 203*7c478bd9Sstevel@tonic-gate { 204*7c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 205*7c478bd9Sstevel@tonic-gate } 206*7c478bd9Sstevel@tonic-gate 207*7c478bd9Sstevel@tonic-gate /* device driver entry points */ 208*7c478bd9Sstevel@tonic-gate 209*7c478bd9Sstevel@tonic-gate /* 210*7c478bd9Sstevel@tonic-gate * attach entry point: 211*7c478bd9Sstevel@tonic-gate * 212*7c478bd9Sstevel@tonic-gate * normal attach: 213*7c478bd9Sstevel@tonic-gate * 214*7c478bd9Sstevel@tonic-gate * create soft state structure (dip, reg, nreg and state fields) 215*7c478bd9Sstevel@tonic-gate * map in configuration header 216*7c478bd9Sstevel@tonic-gate * make sure device is properly configured 217*7c478bd9Sstevel@tonic-gate * report device 218*7c478bd9Sstevel@tonic-gate */ 219*7c478bd9Sstevel@tonic-gate static int 220*7c478bd9Sstevel@tonic-gate pmubus_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 221*7c478bd9Sstevel@tonic-gate { 222*7c478bd9Sstevel@tonic-gate pmubus_devstate_t *pmubusp; /* per pmubus state pointer */ 223*7c478bd9Sstevel@tonic-gate int32_t instance; 224*7c478bd9Sstevel@tonic-gate 225*7c478bd9Sstevel@tonic-gate switch (cmd) { 226*7c478bd9Sstevel@tonic-gate case DDI_ATTACH: 227*7c478bd9Sstevel@tonic-gate /* 228*7c478bd9Sstevel@tonic-gate * Allocate soft state for this instance. 229*7c478bd9Sstevel@tonic-gate */ 230*7c478bd9Sstevel@tonic-gate instance = ddi_get_instance(dip); 231*7c478bd9Sstevel@tonic-gate if (ddi_soft_state_zalloc(per_pmubus_state, instance) != 232*7c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 233*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pmubus_attach: Can't allocate soft " 234*7c478bd9Sstevel@tonic-gate "state.\n"); 235*7c478bd9Sstevel@tonic-gate goto fail_exit; 236*7c478bd9Sstevel@tonic-gate } 237*7c478bd9Sstevel@tonic-gate 238*7c478bd9Sstevel@tonic-gate pmubusp = ddi_get_soft_state(per_pmubus_state, instance); 239*7c478bd9Sstevel@tonic-gate pmubusp->pmubus_dip = dip; 240*7c478bd9Sstevel@tonic-gate 241*7c478bd9Sstevel@tonic-gate /* Cache our register property */ 242*7c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 243*7c478bd9Sstevel@tonic-gate "reg", (caddr_t)&pmubusp->pmubus_regp, 244*7c478bd9Sstevel@tonic-gate &pmubusp->pmubus_reglen) != DDI_SUCCESS) { 245*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pmubus_attach: Can't acquire reg " 246*7c478bd9Sstevel@tonic-gate "property.\n"); 247*7c478bd9Sstevel@tonic-gate goto fail_get_regs; 248*7c478bd9Sstevel@tonic-gate } 249*7c478bd9Sstevel@tonic-gate 250*7c478bd9Sstevel@tonic-gate /* Cache our ranges property */ 251*7c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 252*7c478bd9Sstevel@tonic-gate "ranges", (caddr_t)&pmubusp->pmubus_rangep, 253*7c478bd9Sstevel@tonic-gate &pmubusp->pmubus_rnglen) != DDI_SUCCESS) { 254*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pmubus_attach: Can't acquire the " 255*7c478bd9Sstevel@tonic-gate "ranges property.\n"); 256*7c478bd9Sstevel@tonic-gate goto fail_get_ranges; 257*7c478bd9Sstevel@tonic-gate 258*7c478bd9Sstevel@tonic-gate } 259*7c478bd9Sstevel@tonic-gate 260*7c478bd9Sstevel@tonic-gate /* Calculate the number of ranges */ 261*7c478bd9Sstevel@tonic-gate pmubusp->pmubus_nranges = 262*7c478bd9Sstevel@tonic-gate pmubusp->pmubus_rnglen / sizeof (pmu_rangespec_t); 263*7c478bd9Sstevel@tonic-gate 264*7c478bd9Sstevel@tonic-gate /* Set up the mapping to our registers */ 265*7c478bd9Sstevel@tonic-gate if (pci_config_setup(dip, &pmubusp->pmubus_reghdl) != 266*7c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 267*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pmubus_attach: Can't map in " 268*7c478bd9Sstevel@tonic-gate "register space.\n"); 269*7c478bd9Sstevel@tonic-gate goto fail_map_regs; 270*7c478bd9Sstevel@tonic-gate } 271*7c478bd9Sstevel@tonic-gate 272*7c478bd9Sstevel@tonic-gate /* Initialize our register access mutex */ 273*7c478bd9Sstevel@tonic-gate mutex_init(&pmubusp->pmubus_reg_access_lock, NULL, 274*7c478bd9Sstevel@tonic-gate MUTEX_DRIVER, NULL); 275*7c478bd9Sstevel@tonic-gate 276*7c478bd9Sstevel@tonic-gate ddi_report_dev(dip); 277*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 278*7c478bd9Sstevel@tonic-gate 279*7c478bd9Sstevel@tonic-gate case DDI_RESUME: 280*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 281*7c478bd9Sstevel@tonic-gate } 282*7c478bd9Sstevel@tonic-gate 283*7c478bd9Sstevel@tonic-gate fail_map_regs: 284*7c478bd9Sstevel@tonic-gate kmem_free(pmubusp->pmubus_rangep, pmubusp->pmubus_rnglen); 285*7c478bd9Sstevel@tonic-gate 286*7c478bd9Sstevel@tonic-gate fail_get_ranges: 287*7c478bd9Sstevel@tonic-gate kmem_free(pmubusp->pmubus_regp, pmubusp->pmubus_reglen); 288*7c478bd9Sstevel@tonic-gate 289*7c478bd9Sstevel@tonic-gate fail_get_regs: 290*7c478bd9Sstevel@tonic-gate ddi_soft_state_free(per_pmubus_state, instance); 291*7c478bd9Sstevel@tonic-gate 292*7c478bd9Sstevel@tonic-gate fail_exit: 293*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 294*7c478bd9Sstevel@tonic-gate } 295*7c478bd9Sstevel@tonic-gate 296*7c478bd9Sstevel@tonic-gate /* 297*7c478bd9Sstevel@tonic-gate * detach entry point: 298*7c478bd9Sstevel@tonic-gate */ 299*7c478bd9Sstevel@tonic-gate static int 300*7c478bd9Sstevel@tonic-gate pmubus_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 301*7c478bd9Sstevel@tonic-gate { 302*7c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 303*7c478bd9Sstevel@tonic-gate pmubus_devstate_t *pmubusp = ddi_get_soft_state(per_pmubus_state, 304*7c478bd9Sstevel@tonic-gate instance); 305*7c478bd9Sstevel@tonic-gate 306*7c478bd9Sstevel@tonic-gate switch (cmd) { 307*7c478bd9Sstevel@tonic-gate case DDI_DETACH: 308*7c478bd9Sstevel@tonic-gate mutex_destroy(&pmubusp->pmubus_reg_access_lock); 309*7c478bd9Sstevel@tonic-gate 310*7c478bd9Sstevel@tonic-gate /* Tear down our register mappings */ 311*7c478bd9Sstevel@tonic-gate pci_config_teardown(&pmubusp->pmubus_reghdl); 312*7c478bd9Sstevel@tonic-gate 313*7c478bd9Sstevel@tonic-gate /* Free our ranges property */ 314*7c478bd9Sstevel@tonic-gate kmem_free(pmubusp->pmubus_rangep, pmubusp->pmubus_rnglen); 315*7c478bd9Sstevel@tonic-gate 316*7c478bd9Sstevel@tonic-gate /* Free the register property */ 317*7c478bd9Sstevel@tonic-gate kmem_free(pmubusp->pmubus_regp, pmubusp->pmubus_reglen); 318*7c478bd9Sstevel@tonic-gate 319*7c478bd9Sstevel@tonic-gate ddi_soft_state_free(per_pmubus_state, instance); 320*7c478bd9Sstevel@tonic-gate break; 321*7c478bd9Sstevel@tonic-gate 322*7c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 323*7c478bd9Sstevel@tonic-gate default: 324*7c478bd9Sstevel@tonic-gate break; 325*7c478bd9Sstevel@tonic-gate } 326*7c478bd9Sstevel@tonic-gate 327*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 328*7c478bd9Sstevel@tonic-gate } 329*7c478bd9Sstevel@tonic-gate 330*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 331*7c478bd9Sstevel@tonic-gate void 332*7c478bd9Sstevel@tonic-gate pmubus_norep_get8(ddi_acc_impl_t *handle, uint8_t *host_addr, 333*7c478bd9Sstevel@tonic-gate uint8_t *dev_addr, size_t repcount, uint_t flags) 334*7c478bd9Sstevel@tonic-gate { 335*7c478bd9Sstevel@tonic-gate } 336*7c478bd9Sstevel@tonic-gate 337*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 338*7c478bd9Sstevel@tonic-gate void 339*7c478bd9Sstevel@tonic-gate pmubus_norep_get16(ddi_acc_impl_t *handle, uint16_t *host_addr, 340*7c478bd9Sstevel@tonic-gate uint16_t *dev_addr, size_t repcount, uint_t flags) 341*7c478bd9Sstevel@tonic-gate { 342*7c478bd9Sstevel@tonic-gate } 343*7c478bd9Sstevel@tonic-gate 344*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 345*7c478bd9Sstevel@tonic-gate void 346*7c478bd9Sstevel@tonic-gate pmubus_norep_get32(ddi_acc_impl_t *handle, uint32_t *host_addr, 347*7c478bd9Sstevel@tonic-gate uint32_t *dev_addr, size_t repcount, uint_t flags) 348*7c478bd9Sstevel@tonic-gate { 349*7c478bd9Sstevel@tonic-gate } 350*7c478bd9Sstevel@tonic-gate 351*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 352*7c478bd9Sstevel@tonic-gate void 353*7c478bd9Sstevel@tonic-gate pmubus_norep_get64(ddi_acc_impl_t *handle, uint64_t *host_addr, 354*7c478bd9Sstevel@tonic-gate uint64_t *dev_addr, size_t repcount, uint_t flags) 355*7c478bd9Sstevel@tonic-gate { 356*7c478bd9Sstevel@tonic-gate } 357*7c478bd9Sstevel@tonic-gate 358*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 359*7c478bd9Sstevel@tonic-gate void 360*7c478bd9Sstevel@tonic-gate pmubus_norep_put8(ddi_acc_impl_t *handle, uint8_t *host_addr, 361*7c478bd9Sstevel@tonic-gate uint8_t *dev_addr, size_t repcount, uint_t flags) 362*7c478bd9Sstevel@tonic-gate { 363*7c478bd9Sstevel@tonic-gate } 364*7c478bd9Sstevel@tonic-gate 365*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 366*7c478bd9Sstevel@tonic-gate void 367*7c478bd9Sstevel@tonic-gate pmubus_norep_put16(ddi_acc_impl_t *handle, uint16_t *host_addr, 368*7c478bd9Sstevel@tonic-gate uint16_t *dev_addr, size_t repcount, uint_t flags) 369*7c478bd9Sstevel@tonic-gate { 370*7c478bd9Sstevel@tonic-gate } 371*7c478bd9Sstevel@tonic-gate 372*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 373*7c478bd9Sstevel@tonic-gate void 374*7c478bd9Sstevel@tonic-gate pmubus_norep_put32(ddi_acc_impl_t *handle, uint32_t *host_addr, 375*7c478bd9Sstevel@tonic-gate uint32_t *dev_addr, size_t repcount, uint_t flags) 376*7c478bd9Sstevel@tonic-gate { 377*7c478bd9Sstevel@tonic-gate } 378*7c478bd9Sstevel@tonic-gate 379*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 380*7c478bd9Sstevel@tonic-gate void 381*7c478bd9Sstevel@tonic-gate pmubus_norep_put64(ddi_acc_impl_t *handle, uint64_t *host_addr, 382*7c478bd9Sstevel@tonic-gate uint64_t *dev_addr, size_t repcount, uint_t flags) 383*7c478bd9Sstevel@tonic-gate { 384*7c478bd9Sstevel@tonic-gate } 385*7c478bd9Sstevel@tonic-gate 386*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 387*7c478bd9Sstevel@tonic-gate uint8_t 388*7c478bd9Sstevel@tonic-gate pmubus_get8(ddi_acc_impl_t *hdlp, uint8_t *addr) 389*7c478bd9Sstevel@tonic-gate { 390*7c478bd9Sstevel@tonic-gate ddi_acc_hdl_t *hp = (ddi_acc_hdl_t *)hdlp; 391*7c478bd9Sstevel@tonic-gate pmubus_mapreq_t *pmubus_mapreqp = hp->ah_bus_private; 392*7c478bd9Sstevel@tonic-gate pmubus_devstate_t *softsp = pmubus_mapreqp->mapreq_softsp; 393*7c478bd9Sstevel@tonic-gate off_t offset; 394*7c478bd9Sstevel@tonic-gate uint8_t value; 395*7c478bd9Sstevel@tonic-gate uint8_t mask; 396*7c478bd9Sstevel@tonic-gate 397*7c478bd9Sstevel@tonic-gate offset = pmubus_mapreqp->mapreq_addr + (uintptr_t)addr; 398*7c478bd9Sstevel@tonic-gate offset &= PMUBUS_REGOFFSET; 399*7c478bd9Sstevel@tonic-gate 400*7c478bd9Sstevel@tonic-gate if ((pmubus_mapreqp->mapreq_flags) & MAPREQ_SHARED_BITS) { 401*7c478bd9Sstevel@tonic-gate if (addr != 0 || 402*7c478bd9Sstevel@tonic-gate pmubus_mapreqp->mapreq_size != sizeof (value)) { 403*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pmubus_get8: load discarded, " 404*7c478bd9Sstevel@tonic-gate "incorrect access addr/size"); 405*7c478bd9Sstevel@tonic-gate return ((uint8_t)-1); 406*7c478bd9Sstevel@tonic-gate } 407*7c478bd9Sstevel@tonic-gate mask = pmubus_mapreqp->mapreq_mask; 408*7c478bd9Sstevel@tonic-gate } else { 409*7c478bd9Sstevel@tonic-gate mask = (uint8_t)-1; 410*7c478bd9Sstevel@tonic-gate } 411*7c478bd9Sstevel@tonic-gate 412*7c478bd9Sstevel@tonic-gate /* gets are simple, we just issue them no locking necessary */ 413*7c478bd9Sstevel@tonic-gate value = pci_config_get8(softsp->pmubus_reghdl, offset) & mask; 414*7c478bd9Sstevel@tonic-gate 415*7c478bd9Sstevel@tonic-gate DPRINTF(PMUBUS_RW_DEBUG, ("pmubus_get8: addr=%p offset=%x value=%x " 416*7c478bd9Sstevel@tonic-gate "mask=%lx\n", addr, offset, value, mask)); 417*7c478bd9Sstevel@tonic-gate 418*7c478bd9Sstevel@tonic-gate return (value); 419*7c478bd9Sstevel@tonic-gate } 420*7c478bd9Sstevel@tonic-gate 421*7c478bd9Sstevel@tonic-gate 422*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 423*7c478bd9Sstevel@tonic-gate uint16_t 424*7c478bd9Sstevel@tonic-gate pmubus_noget16(ddi_acc_impl_t *hdlp, uint16_t *addr) 425*7c478bd9Sstevel@tonic-gate { 426*7c478bd9Sstevel@tonic-gate return ((uint16_t)-1); 427*7c478bd9Sstevel@tonic-gate } 428*7c478bd9Sstevel@tonic-gate 429*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 430*7c478bd9Sstevel@tonic-gate uint32_t 431*7c478bd9Sstevel@tonic-gate pmubus_get32(ddi_acc_impl_t *hdlp, uint32_t *addr) 432*7c478bd9Sstevel@tonic-gate { 433*7c478bd9Sstevel@tonic-gate ddi_acc_hdl_t *hp = (ddi_acc_hdl_t *)hdlp; 434*7c478bd9Sstevel@tonic-gate pmubus_mapreq_t *pmubus_mapreqp = hp->ah_bus_private; 435*7c478bd9Sstevel@tonic-gate pmubus_devstate_t *softsp = pmubus_mapreqp->mapreq_softsp; 436*7c478bd9Sstevel@tonic-gate off_t offset = (uintptr_t)addr & PMUBUS_REGOFFSET; 437*7c478bd9Sstevel@tonic-gate uint32_t value; 438*7c478bd9Sstevel@tonic-gate uint32_t mask; 439*7c478bd9Sstevel@tonic-gate 440*7c478bd9Sstevel@tonic-gate offset = pmubus_mapreqp->mapreq_addr + (uintptr_t)addr; 441*7c478bd9Sstevel@tonic-gate offset &= PMUBUS_REGOFFSET; 442*7c478bd9Sstevel@tonic-gate 443*7c478bd9Sstevel@tonic-gate if ((pmubus_mapreqp->mapreq_flags) & MAPREQ_SHARED_BITS) { 444*7c478bd9Sstevel@tonic-gate if (addr != 0 || 445*7c478bd9Sstevel@tonic-gate pmubus_mapreqp->mapreq_size != sizeof (value)) { 446*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pmubus_get32: load discarded, " 447*7c478bd9Sstevel@tonic-gate "incorrect access addr/size"); 448*7c478bd9Sstevel@tonic-gate return ((uint32_t)-1); 449*7c478bd9Sstevel@tonic-gate } 450*7c478bd9Sstevel@tonic-gate mask = pmubus_mapreqp->mapreq_mask; 451*7c478bd9Sstevel@tonic-gate } else { 452*7c478bd9Sstevel@tonic-gate mask = (uint32_t)-1; 453*7c478bd9Sstevel@tonic-gate } 454*7c478bd9Sstevel@tonic-gate 455*7c478bd9Sstevel@tonic-gate /* gets are simple, we just issue them no locking necessary */ 456*7c478bd9Sstevel@tonic-gate value = pci_config_get32(softsp->pmubus_reghdl, offset) & mask; 457*7c478bd9Sstevel@tonic-gate 458*7c478bd9Sstevel@tonic-gate DPRINTF(PMUBUS_RW_DEBUG, ("pmubus_get32: addr=%p offset=%x value=%x " 459*7c478bd9Sstevel@tonic-gate "mask=%lx\n", addr, offset, value, mask)); 460*7c478bd9Sstevel@tonic-gate 461*7c478bd9Sstevel@tonic-gate return (value); 462*7c478bd9Sstevel@tonic-gate } 463*7c478bd9Sstevel@tonic-gate 464*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 465*7c478bd9Sstevel@tonic-gate uint64_t 466*7c478bd9Sstevel@tonic-gate pmubus_noget64(ddi_acc_impl_t *hdlp, uint64_t *addr) 467*7c478bd9Sstevel@tonic-gate { 468*7c478bd9Sstevel@tonic-gate return ((uint64_t)-1); 469*7c478bd9Sstevel@tonic-gate } 470*7c478bd9Sstevel@tonic-gate 471*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 472*7c478bd9Sstevel@tonic-gate void 473*7c478bd9Sstevel@tonic-gate pmubus_put8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value) 474*7c478bd9Sstevel@tonic-gate { 475*7c478bd9Sstevel@tonic-gate ddi_acc_hdl_t *hp = (ddi_acc_hdl_t *)hdlp; 476*7c478bd9Sstevel@tonic-gate pmubus_mapreq_t *pmubus_mapreqp = hp->ah_bus_private; 477*7c478bd9Sstevel@tonic-gate pmubus_devstate_t *softsp = pmubus_mapreqp->mapreq_softsp; 478*7c478bd9Sstevel@tonic-gate off_t offset; 479*7c478bd9Sstevel@tonic-gate uint8_t tmp; 480*7c478bd9Sstevel@tonic-gate 481*7c478bd9Sstevel@tonic-gate offset = pmubus_mapreqp->mapreq_addr + (uintptr_t)addr; 482*7c478bd9Sstevel@tonic-gate offset &= PMUBUS_REGOFFSET; 483*7c478bd9Sstevel@tonic-gate 484*7c478bd9Sstevel@tonic-gate if ((pmubus_mapreqp->mapreq_flags) & MAPREQ_SHARED_BITS) { 485*7c478bd9Sstevel@tonic-gate /* 486*7c478bd9Sstevel@tonic-gate * Process "bit lane" register 487*7c478bd9Sstevel@tonic-gate */ 488*7c478bd9Sstevel@tonic-gate DPRINTF(PMUBUS_RW_DEBUG, ("pmubus_put8: addr=%p offset=%x " 489*7c478bd9Sstevel@tonic-gate "value=%x mask=%lx\n", addr, offset, value, 490*7c478bd9Sstevel@tonic-gate pmubus_mapreqp->mapreq_mask)); 491*7c478bd9Sstevel@tonic-gate 492*7c478bd9Sstevel@tonic-gate if (addr != 0 || 493*7c478bd9Sstevel@tonic-gate pmubus_mapreqp->mapreq_size != sizeof (value)) { 494*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pmubus_put8: store discarded, " 495*7c478bd9Sstevel@tonic-gate "incorrect access addr/size"); 496*7c478bd9Sstevel@tonic-gate return; 497*7c478bd9Sstevel@tonic-gate } 498*7c478bd9Sstevel@tonic-gate 499*7c478bd9Sstevel@tonic-gate mutex_enter(&softsp->pmubus_reg_access_lock); 500*7c478bd9Sstevel@tonic-gate tmp = pci_config_get8(softsp->pmubus_reghdl, offset); 501*7c478bd9Sstevel@tonic-gate tmp &= ~pmubus_mapreqp->mapreq_mask; 502*7c478bd9Sstevel@tonic-gate value &= pmubus_mapreqp->mapreq_mask; 503*7c478bd9Sstevel@tonic-gate tmp |= value; 504*7c478bd9Sstevel@tonic-gate pci_config_put8(softsp->pmubus_reghdl, offset, tmp); 505*7c478bd9Sstevel@tonic-gate mutex_exit(&softsp->pmubus_reg_access_lock); 506*7c478bd9Sstevel@tonic-gate } else { 507*7c478bd9Sstevel@tonic-gate /* 508*7c478bd9Sstevel@tonic-gate * Process shared register 509*7c478bd9Sstevel@tonic-gate */ 510*7c478bd9Sstevel@tonic-gate DPRINTF(PMUBUS_RW_DEBUG, ("pmubus_put8: addr=%p offset=%x " 511*7c478bd9Sstevel@tonic-gate "value=%x\n", addr, offset, value)); 512*7c478bd9Sstevel@tonic-gate pci_config_put8(softsp->pmubus_reghdl, offset, value); 513*7c478bd9Sstevel@tonic-gate } 514*7c478bd9Sstevel@tonic-gate 515*7c478bd9Sstevel@tonic-gate /* Flush store buffers XXX Should let drivers do this. */ 516*7c478bd9Sstevel@tonic-gate tmp = pci_config_get8(softsp->pmubus_reghdl, offset); 517*7c478bd9Sstevel@tonic-gate } 518*7c478bd9Sstevel@tonic-gate 519*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 520*7c478bd9Sstevel@tonic-gate void 521*7c478bd9Sstevel@tonic-gate pmubus_noput16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value) 522*7c478bd9Sstevel@tonic-gate { 523*7c478bd9Sstevel@tonic-gate } 524*7c478bd9Sstevel@tonic-gate 525*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 526*7c478bd9Sstevel@tonic-gate void 527*7c478bd9Sstevel@tonic-gate pmubus_put32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value) 528*7c478bd9Sstevel@tonic-gate { 529*7c478bd9Sstevel@tonic-gate ddi_acc_hdl_t *hp = (ddi_acc_hdl_t *)hdlp; 530*7c478bd9Sstevel@tonic-gate pmubus_mapreq_t *pmubus_mapreqp = hp->ah_bus_private; 531*7c478bd9Sstevel@tonic-gate pmubus_devstate_t *softsp = pmubus_mapreqp->mapreq_softsp; 532*7c478bd9Sstevel@tonic-gate off_t offset; 533*7c478bd9Sstevel@tonic-gate uint32_t tmp; 534*7c478bd9Sstevel@tonic-gate 535*7c478bd9Sstevel@tonic-gate offset = pmubus_mapreqp->mapreq_addr + (uintptr_t)addr; 536*7c478bd9Sstevel@tonic-gate offset &= PMUBUS_REGOFFSET; 537*7c478bd9Sstevel@tonic-gate 538*7c478bd9Sstevel@tonic-gate if ((pmubus_mapreqp->mapreq_flags) & MAPREQ_SHARED_BITS) { 539*7c478bd9Sstevel@tonic-gate /* 540*7c478bd9Sstevel@tonic-gate * Process "bit lane" register 541*7c478bd9Sstevel@tonic-gate */ 542*7c478bd9Sstevel@tonic-gate DPRINTF(PMUBUS_RW_DEBUG, ("pmubus_put32: addr=%p offset=%x " 543*7c478bd9Sstevel@tonic-gate "value=%x mask=%lx\n", addr, offset, value, 544*7c478bd9Sstevel@tonic-gate pmubus_mapreqp->mapreq_mask)); 545*7c478bd9Sstevel@tonic-gate 546*7c478bd9Sstevel@tonic-gate if (addr != 0 || 547*7c478bd9Sstevel@tonic-gate pmubus_mapreqp->mapreq_size != sizeof (value)) { 548*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pmubus_put32: store discarded, " 549*7c478bd9Sstevel@tonic-gate "incorrect access addr/size"); 550*7c478bd9Sstevel@tonic-gate return; 551*7c478bd9Sstevel@tonic-gate } 552*7c478bd9Sstevel@tonic-gate 553*7c478bd9Sstevel@tonic-gate mutex_enter(&softsp->pmubus_reg_access_lock); 554*7c478bd9Sstevel@tonic-gate tmp = pci_config_get32(softsp->pmubus_reghdl, offset); 555*7c478bd9Sstevel@tonic-gate tmp &= ~pmubus_mapreqp->mapreq_mask; 556*7c478bd9Sstevel@tonic-gate value &= pmubus_mapreqp->mapreq_mask; 557*7c478bd9Sstevel@tonic-gate tmp |= value; 558*7c478bd9Sstevel@tonic-gate pci_config_put32(softsp->pmubus_reghdl, offset, tmp); 559*7c478bd9Sstevel@tonic-gate mutex_exit(&softsp->pmubus_reg_access_lock); 560*7c478bd9Sstevel@tonic-gate } else { 561*7c478bd9Sstevel@tonic-gate /* 562*7c478bd9Sstevel@tonic-gate * Process shared register 563*7c478bd9Sstevel@tonic-gate */ 564*7c478bd9Sstevel@tonic-gate DPRINTF(PMUBUS_RW_DEBUG, ("pmubus_put32: addr=%p offset=%x " 565*7c478bd9Sstevel@tonic-gate "value=%x\n", addr, offset, value)); 566*7c478bd9Sstevel@tonic-gate pci_config_put32(softsp->pmubus_reghdl, offset, value); 567*7c478bd9Sstevel@tonic-gate } 568*7c478bd9Sstevel@tonic-gate 569*7c478bd9Sstevel@tonic-gate /* Flush store buffers XXX Should let drivers do this. */ 570*7c478bd9Sstevel@tonic-gate tmp = pci_config_get32(softsp->pmubus_reghdl, offset); 571*7c478bd9Sstevel@tonic-gate } 572*7c478bd9Sstevel@tonic-gate 573*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 574*7c478bd9Sstevel@tonic-gate void 575*7c478bd9Sstevel@tonic-gate pmubus_noput64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value) 576*7c478bd9Sstevel@tonic-gate { 577*7c478bd9Sstevel@tonic-gate } 578*7c478bd9Sstevel@tonic-gate 579*7c478bd9Sstevel@tonic-gate /* 580*7c478bd9Sstevel@tonic-gate * This routine is used to translate our children's register properties. 581*7c478bd9Sstevel@tonic-gate * The return value specifies which type of register has been translated. 582*7c478bd9Sstevel@tonic-gate */ 583*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 584*7c478bd9Sstevel@tonic-gate int 585*7c478bd9Sstevel@tonic-gate pmubus_apply_range(pmubus_devstate_t *pmubusp, dev_info_t *rdip, 586*7c478bd9Sstevel@tonic-gate pmubus_regspec_t *regp, pci_regspec_t *pci_regp) 587*7c478bd9Sstevel@tonic-gate { 588*7c478bd9Sstevel@tonic-gate pmu_rangespec_t *rangep; 589*7c478bd9Sstevel@tonic-gate int nranges = pmubusp->pmubus_nranges; 590*7c478bd9Sstevel@tonic-gate int i; 591*7c478bd9Sstevel@tonic-gate off_t offset; 592*7c478bd9Sstevel@tonic-gate int ret = DDI_ME_REGSPEC_RANGE; 593*7c478bd9Sstevel@tonic-gate uint64_t addr; 594*7c478bd9Sstevel@tonic-gate 595*7c478bd9Sstevel@tonic-gate addr = regp->reg_addr & ~MAPPING_SHARED_BITS_MASK; 596*7c478bd9Sstevel@tonic-gate 597*7c478bd9Sstevel@tonic-gate /* Scan the ranges for a match */ 598*7c478bd9Sstevel@tonic-gate for (i = 0, rangep = pmubusp->pmubus_rangep; i < nranges; i++, rangep++) 599*7c478bd9Sstevel@tonic-gate if ((rangep->rng_child <= addr) && 600*7c478bd9Sstevel@tonic-gate ((addr + regp->reg_size) <= 601*7c478bd9Sstevel@tonic-gate (rangep->rng_child + rangep->rng_size))) { 602*7c478bd9Sstevel@tonic-gate ret = DDI_SUCCESS; 603*7c478bd9Sstevel@tonic-gate break; 604*7c478bd9Sstevel@tonic-gate } 605*7c478bd9Sstevel@tonic-gate 606*7c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) 607*7c478bd9Sstevel@tonic-gate return (ret); 608*7c478bd9Sstevel@tonic-gate 609*7c478bd9Sstevel@tonic-gate /* Get the translated register */ 610*7c478bd9Sstevel@tonic-gate offset = addr - rangep->rng_child; 611*7c478bd9Sstevel@tonic-gate pci_regp->pci_phys_hi = rangep->rng_parent_hi; 612*7c478bd9Sstevel@tonic-gate pci_regp->pci_phys_mid = rangep->rng_parent_mid; 613*7c478bd9Sstevel@tonic-gate pci_regp->pci_phys_low = rangep->rng_parent_low + offset; 614*7c478bd9Sstevel@tonic-gate pci_regp->pci_size_hi = 0; 615*7c478bd9Sstevel@tonic-gate pci_regp->pci_size_low = MIN(regp->reg_size, rangep->rng_size); 616*7c478bd9Sstevel@tonic-gate 617*7c478bd9Sstevel@tonic-gate /* Figure out the type of reg space we have */ 618*7c478bd9Sstevel@tonic-gate if (pci_regp->pci_phys_hi == pmubusp->pmubus_regp->pci_phys_hi) { 619*7c478bd9Sstevel@tonic-gate ret = MAPREQ_SHARED_REG; 620*7c478bd9Sstevel@tonic-gate if (regp->reg_addr & MAPPING_SHARED_BITS_MASK) 621*7c478bd9Sstevel@tonic-gate ret |= MAPREQ_SHARED_BITS; 622*7c478bd9Sstevel@tonic-gate } 623*7c478bd9Sstevel@tonic-gate 624*7c478bd9Sstevel@tonic-gate return (ret); 625*7c478bd9Sstevel@tonic-gate } 626*7c478bd9Sstevel@tonic-gate 627*7c478bd9Sstevel@tonic-gate static uint64_t 628*7c478bd9Sstevel@tonic-gate pmubus_mask(pmubus_obpregspec_t *regs, int32_t rnumber, 629*7c478bd9Sstevel@tonic-gate uint64_t *masks) 630*7c478bd9Sstevel@tonic-gate { 631*7c478bd9Sstevel@tonic-gate int i; 632*7c478bd9Sstevel@tonic-gate long n = -1; 633*7c478bd9Sstevel@tonic-gate 634*7c478bd9Sstevel@tonic-gate for (i = 0; i <= rnumber; i++) 635*7c478bd9Sstevel@tonic-gate if (regs[i].reg_addr_hi & 0x80000000) 636*7c478bd9Sstevel@tonic-gate n++; 637*7c478bd9Sstevel@tonic-gate 638*7c478bd9Sstevel@tonic-gate if (n == -1) { 639*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pmubus_mask: missing mask"); 640*7c478bd9Sstevel@tonic-gate return (0); 641*7c478bd9Sstevel@tonic-gate } 642*7c478bd9Sstevel@tonic-gate 643*7c478bd9Sstevel@tonic-gate return (masks[n]); 644*7c478bd9Sstevel@tonic-gate } 645*7c478bd9Sstevel@tonic-gate 646*7c478bd9Sstevel@tonic-gate /* 647*7c478bd9Sstevel@tonic-gate * The pmubus_map routine determines if it's child is attempting to map a 648*7c478bd9Sstevel@tonic-gate * shared reg. If it is, it installs it's own vectors and bus private pointer. 649*7c478bd9Sstevel@tonic-gate */ 650*7c478bd9Sstevel@tonic-gate static int 651*7c478bd9Sstevel@tonic-gate pmubus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 652*7c478bd9Sstevel@tonic-gate off_t off, off_t len, caddr_t *addrp) 653*7c478bd9Sstevel@tonic-gate { 654*7c478bd9Sstevel@tonic-gate pmubus_devstate_t *pmubusp = ddi_get_soft_state(per_pmubus_state, 655*7c478bd9Sstevel@tonic-gate ddi_get_instance(dip)); 656*7c478bd9Sstevel@tonic-gate dev_info_t *pdip = (dev_info_t *)DEVI(dip)->devi_parent; 657*7c478bd9Sstevel@tonic-gate pmubus_regspec_t pmubus_rp; 658*7c478bd9Sstevel@tonic-gate pmubus_obpregspec_t *pmubus_regs = NULL; 659*7c478bd9Sstevel@tonic-gate int pmubus_regs_size; 660*7c478bd9Sstevel@tonic-gate uint64_t *pmubus_regmask = NULL; 661*7c478bd9Sstevel@tonic-gate int pmubus_regmask_size; 662*7c478bd9Sstevel@tonic-gate pci_regspec_t pci_reg; 663*7c478bd9Sstevel@tonic-gate int32_t rnumber = mp->map_obj.rnumber; 664*7c478bd9Sstevel@tonic-gate pmubus_mapreq_t *pmubus_mapreqp; 665*7c478bd9Sstevel@tonic-gate int ret = DDI_SUCCESS; 666*7c478bd9Sstevel@tonic-gate char *map_fail1 = "Map Type Unknown"; 667*7c478bd9Sstevel@tonic-gate char *map_fail2 = "DDI_MT_REGSPEC"; 668*7c478bd9Sstevel@tonic-gate char *s = map_fail1; 669*7c478bd9Sstevel@tonic-gate 670*7c478bd9Sstevel@tonic-gate *addrp = NULL; 671*7c478bd9Sstevel@tonic-gate 672*7c478bd9Sstevel@tonic-gate /* 673*7c478bd9Sstevel@tonic-gate * Handle the mapping according to its type. 674*7c478bd9Sstevel@tonic-gate */ 675*7c478bd9Sstevel@tonic-gate DPRINTF(PMUBUS_MAP_DEBUG, ("rdip=%s%d: off=%x len=%x\n", 676*7c478bd9Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip), off, len)); 677*7c478bd9Sstevel@tonic-gate switch (mp->map_type) { 678*7c478bd9Sstevel@tonic-gate case DDI_MT_RNUMBER: { 679*7c478bd9Sstevel@tonic-gate int n; 680*7c478bd9Sstevel@tonic-gate 681*7c478bd9Sstevel@tonic-gate /* 682*7c478bd9Sstevel@tonic-gate * Get the "reg" property from the device node and convert 683*7c478bd9Sstevel@tonic-gate * it to our parent's format. 684*7c478bd9Sstevel@tonic-gate */ 685*7c478bd9Sstevel@tonic-gate rnumber = mp->map_obj.rnumber; 686*7c478bd9Sstevel@tonic-gate DPRINTF(PMUBUS_MAP_DEBUG, ("rdip=%s%d: rnumber=%x " 687*7c478bd9Sstevel@tonic-gate "handlep=%x\n", ddi_get_name(rdip), ddi_get_instance(rdip), 688*7c478bd9Sstevel@tonic-gate rnumber, mp->map_handlep)); 689*7c478bd9Sstevel@tonic-gate 690*7c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_NONE, rdip, DDI_PROP_DONTPASS, 691*7c478bd9Sstevel@tonic-gate "reg", (caddr_t)&pmubus_regs, &pmubus_regs_size) != 692*7c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 693*7c478bd9Sstevel@tonic-gate DPRINTF(PMUBUS_MAP_DEBUG, ("can't get reg " 694*7c478bd9Sstevel@tonic-gate "property\n")); 695*7c478bd9Sstevel@tonic-gate ret = DDI_ME_RNUMBER_RANGE; 696*7c478bd9Sstevel@tonic-gate goto done; 697*7c478bd9Sstevel@tonic-gate } 698*7c478bd9Sstevel@tonic-gate n = pmubus_regs_size / sizeof (pmubus_obpregspec_t); 699*7c478bd9Sstevel@tonic-gate 700*7c478bd9Sstevel@tonic-gate if (rnumber < 0 || rnumber >= n) { 701*7c478bd9Sstevel@tonic-gate DPRINTF(PMUBUS_MAP_DEBUG, ("rnumber out of range\n")); 702*7c478bd9Sstevel@tonic-gate ret = DDI_ME_RNUMBER_RANGE; 703*7c478bd9Sstevel@tonic-gate goto done; 704*7c478bd9Sstevel@tonic-gate } 705*7c478bd9Sstevel@tonic-gate 706*7c478bd9Sstevel@tonic-gate pmubus_rp.reg_addr = ((uint64_t) 707*7c478bd9Sstevel@tonic-gate pmubus_regs[rnumber].reg_addr_hi << 32) | 708*7c478bd9Sstevel@tonic-gate (uint64_t)pmubus_regs[rnumber].reg_addr_lo; 709*7c478bd9Sstevel@tonic-gate pmubus_rp.reg_size = pmubus_regs[rnumber].reg_size; 710*7c478bd9Sstevel@tonic-gate 711*7c478bd9Sstevel@tonic-gate (void) ddi_getlongprop(DDI_DEV_T_NONE, rdip, DDI_PROP_DONTPASS, 712*7c478bd9Sstevel@tonic-gate "register-mask", (caddr_t)&pmubus_regmask, 713*7c478bd9Sstevel@tonic-gate &pmubus_regmask_size); 714*7c478bd9Sstevel@tonic-gate 715*7c478bd9Sstevel@tonic-gate /* Create our own mapping private structure */ 716*7c478bd9Sstevel@tonic-gate break; 717*7c478bd9Sstevel@tonic-gate 718*7c478bd9Sstevel@tonic-gate } 719*7c478bd9Sstevel@tonic-gate case DDI_MT_REGSPEC: 720*7c478bd9Sstevel@tonic-gate /* 721*7c478bd9Sstevel@tonic-gate * This bus has no bus children that have to map in an address 722*7c478bd9Sstevel@tonic-gate * space, so we can assume that we'll never see an 723*7c478bd9Sstevel@tonic-gate * DDI_MT_REGSPEC request 724*7c478bd9Sstevel@tonic-gate */ 725*7c478bd9Sstevel@tonic-gate s = map_fail2; 726*7c478bd9Sstevel@tonic-gate ret = DDI_ME_REGSPEC_RANGE; 727*7c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 728*7c478bd9Sstevel@tonic-gate 729*7c478bd9Sstevel@tonic-gate default: 730*7c478bd9Sstevel@tonic-gate if (ret == DDI_SUCCESS) 731*7c478bd9Sstevel@tonic-gate ret = DDI_ME_INVAL; 732*7c478bd9Sstevel@tonic-gate DPRINTF(PMUBUS_MAP_DEBUG, ("rdip=%s%d: pmubus_map: " 733*7c478bd9Sstevel@tonic-gate "%s is an invalid map type.\nmap request handlep=0x%p\n", 734*7c478bd9Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip), s, mp)); 735*7c478bd9Sstevel@tonic-gate 736*7c478bd9Sstevel@tonic-gate ret = DDI_ME_RNUMBER_RANGE; 737*7c478bd9Sstevel@tonic-gate goto done; 738*7c478bd9Sstevel@tonic-gate } 739*7c478bd9Sstevel@tonic-gate 740*7c478bd9Sstevel@tonic-gate /* Adjust our reg property with offset and length */ 741*7c478bd9Sstevel@tonic-gate if ((pmubus_rp.reg_addr + off) > 742*7c478bd9Sstevel@tonic-gate (pmubus_rp.reg_addr + pmubus_rp.reg_size)) { 743*7c478bd9Sstevel@tonic-gate ret = DDI_ME_INVAL; 744*7c478bd9Sstevel@tonic-gate goto done; 745*7c478bd9Sstevel@tonic-gate } 746*7c478bd9Sstevel@tonic-gate 747*7c478bd9Sstevel@tonic-gate pmubus_rp.reg_addr += off; 748*7c478bd9Sstevel@tonic-gate if (len && (len < pmubus_rp.reg_size)) 749*7c478bd9Sstevel@tonic-gate pmubus_rp.reg_size = len; 750*7c478bd9Sstevel@tonic-gate 751*7c478bd9Sstevel@tonic-gate /* Translate our child regspec into our parents address domain */ 752*7c478bd9Sstevel@tonic-gate ret = pmubus_apply_range(pmubusp, rdip, &pmubus_rp, &pci_reg); 753*7c478bd9Sstevel@tonic-gate 754*7c478bd9Sstevel@tonic-gate /* Check if the apply range failed */ 755*7c478bd9Sstevel@tonic-gate if (ret < DDI_SUCCESS) 756*7c478bd9Sstevel@tonic-gate goto done; 757*7c478bd9Sstevel@tonic-gate 758*7c478bd9Sstevel@tonic-gate /* 759*7c478bd9Sstevel@tonic-gate * If our childs xlated address falls into our shared address range, 760*7c478bd9Sstevel@tonic-gate * setup our mapping handle. 761*7c478bd9Sstevel@tonic-gate */ 762*7c478bd9Sstevel@tonic-gate if (ret > DDI_SUCCESS) { 763*7c478bd9Sstevel@tonic-gate /* Figure out if we're mapping or unmapping */ 764*7c478bd9Sstevel@tonic-gate switch (mp->map_op) { 765*7c478bd9Sstevel@tonic-gate case DDI_MO_MAP_LOCKED: { 766*7c478bd9Sstevel@tonic-gate ddi_acc_impl_t *hp = (ddi_acc_impl_t *)mp->map_handlep; 767*7c478bd9Sstevel@tonic-gate 768*7c478bd9Sstevel@tonic-gate pmubus_mapreqp = kmem_alloc(sizeof (*pmubus_mapreqp), 769*7c478bd9Sstevel@tonic-gate KM_SLEEP); 770*7c478bd9Sstevel@tonic-gate 771*7c478bd9Sstevel@tonic-gate pmubus_mapreqp->mapreq_flags = ret; 772*7c478bd9Sstevel@tonic-gate pmubus_mapreqp->mapreq_softsp = pmubusp; 773*7c478bd9Sstevel@tonic-gate pmubus_mapreqp->mapreq_addr = pmubus_rp.reg_addr; 774*7c478bd9Sstevel@tonic-gate pmubus_mapreqp->mapreq_size = pmubus_rp.reg_size; 775*7c478bd9Sstevel@tonic-gate 776*7c478bd9Sstevel@tonic-gate if (ret & MAPREQ_SHARED_BITS) { 777*7c478bd9Sstevel@tonic-gate pmubus_mapreqp->mapreq_mask = 778*7c478bd9Sstevel@tonic-gate pmubus_mask(pmubus_regs, rnumber, 779*7c478bd9Sstevel@tonic-gate pmubus_regmask); 780*7c478bd9Sstevel@tonic-gate DPRINTF(PMUBUS_MAP_DEBUG, ("rnumber=%d " 781*7c478bd9Sstevel@tonic-gate "mask=%llx\n", rnumber, 782*7c478bd9Sstevel@tonic-gate pmubus_mapreqp->mapreq_mask)); 783*7c478bd9Sstevel@tonic-gate if (pmubus_mapreqp->mapreq_mask == 0) { 784*7c478bd9Sstevel@tonic-gate kmem_free(pmubus_mapreqp, 785*7c478bd9Sstevel@tonic-gate sizeof (pmubus_mapreq_t)); 786*7c478bd9Sstevel@tonic-gate ret = DDI_ME_INVAL; 787*7c478bd9Sstevel@tonic-gate break; 788*7c478bd9Sstevel@tonic-gate } 789*7c478bd9Sstevel@tonic-gate } 790*7c478bd9Sstevel@tonic-gate 791*7c478bd9Sstevel@tonic-gate hp->ahi_common.ah_bus_private = pmubus_mapreqp; 792*7c478bd9Sstevel@tonic-gate 793*7c478bd9Sstevel@tonic-gate /* Initialize the access vectors */ 794*7c478bd9Sstevel@tonic-gate hp->ahi_get8 = pmubus_get8; 795*7c478bd9Sstevel@tonic-gate hp->ahi_get16 = pmubus_noget16; 796*7c478bd9Sstevel@tonic-gate hp->ahi_get32 = pmubus_get32; 797*7c478bd9Sstevel@tonic-gate hp->ahi_get64 = pmubus_noget64; 798*7c478bd9Sstevel@tonic-gate hp->ahi_put8 = pmubus_put8; 799*7c478bd9Sstevel@tonic-gate hp->ahi_put16 = pmubus_noput16; 800*7c478bd9Sstevel@tonic-gate hp->ahi_put32 = pmubus_put32; 801*7c478bd9Sstevel@tonic-gate hp->ahi_put64 = pmubus_noput64; 802*7c478bd9Sstevel@tonic-gate hp->ahi_rep_get8 = pmubus_norep_get8; 803*7c478bd9Sstevel@tonic-gate hp->ahi_rep_get16 = pmubus_norep_get16; 804*7c478bd9Sstevel@tonic-gate hp->ahi_rep_get32 = pmubus_norep_get32; 805*7c478bd9Sstevel@tonic-gate hp->ahi_rep_get64 = pmubus_norep_get64; 806*7c478bd9Sstevel@tonic-gate hp->ahi_rep_put8 = pmubus_norep_put8; 807*7c478bd9Sstevel@tonic-gate hp->ahi_rep_put16 = pmubus_norep_put16; 808*7c478bd9Sstevel@tonic-gate hp->ahi_rep_put32 = pmubus_norep_put32; 809*7c478bd9Sstevel@tonic-gate hp->ahi_rep_put64 = pmubus_norep_put64; 810*7c478bd9Sstevel@tonic-gate 811*7c478bd9Sstevel@tonic-gate ret = DDI_SUCCESS; 812*7c478bd9Sstevel@tonic-gate break; 813*7c478bd9Sstevel@tonic-gate } 814*7c478bd9Sstevel@tonic-gate 815*7c478bd9Sstevel@tonic-gate case DDI_MO_UNMAP: { 816*7c478bd9Sstevel@tonic-gate ddi_acc_impl_t *hp = (ddi_acc_impl_t *)mp->map_handlep; 817*7c478bd9Sstevel@tonic-gate 818*7c478bd9Sstevel@tonic-gate pmubus_mapreqp = hp->ahi_common.ah_bus_private; 819*7c478bd9Sstevel@tonic-gate 820*7c478bd9Sstevel@tonic-gate /* Free the our map request struct */ 821*7c478bd9Sstevel@tonic-gate kmem_free(pmubus_mapreqp, sizeof (pmubus_mapreq_t)); 822*7c478bd9Sstevel@tonic-gate 823*7c478bd9Sstevel@tonic-gate ret = DDI_SUCCESS; 824*7c478bd9Sstevel@tonic-gate break; 825*7c478bd9Sstevel@tonic-gate } 826*7c478bd9Sstevel@tonic-gate 827*7c478bd9Sstevel@tonic-gate default: 828*7c478bd9Sstevel@tonic-gate ret = DDI_ME_UNSUPPORTED; 829*7c478bd9Sstevel@tonic-gate } 830*7c478bd9Sstevel@tonic-gate } else { 831*7c478bd9Sstevel@tonic-gate /* Prepare the map request struct for a call to our parent */ 832*7c478bd9Sstevel@tonic-gate mp->map_type = DDI_MT_REGSPEC; 833*7c478bd9Sstevel@tonic-gate mp->map_obj.rp = (struct regspec *)&pci_reg; 834*7c478bd9Sstevel@tonic-gate 835*7c478bd9Sstevel@tonic-gate /* Pass the mapping operation up the device tree */ 836*7c478bd9Sstevel@tonic-gate ret = (DEVI(pdip)->devi_ops->devo_bus_ops->bus_map) 837*7c478bd9Sstevel@tonic-gate (pdip, rdip, mp, off, len, addrp); 838*7c478bd9Sstevel@tonic-gate } 839*7c478bd9Sstevel@tonic-gate 840*7c478bd9Sstevel@tonic-gate done: 841*7c478bd9Sstevel@tonic-gate if (pmubus_regs != NULL) 842*7c478bd9Sstevel@tonic-gate kmem_free(pmubus_regs, pmubus_regs_size); 843*7c478bd9Sstevel@tonic-gate if (pmubus_regmask != NULL) 844*7c478bd9Sstevel@tonic-gate kmem_free(pmubus_regmask, pmubus_regmask_size); 845*7c478bd9Sstevel@tonic-gate return (ret); 846*7c478bd9Sstevel@tonic-gate } 847*7c478bd9Sstevel@tonic-gate 848*7c478bd9Sstevel@tonic-gate static int 849*7c478bd9Sstevel@tonic-gate pmubus_ctlops(dev_info_t *dip, dev_info_t *rdip, 850*7c478bd9Sstevel@tonic-gate ddi_ctl_enum_t op, void *arg, void *result) 851*7c478bd9Sstevel@tonic-gate { 852*7c478bd9Sstevel@tonic-gate dev_info_t *child = (dev_info_t *)arg; 853*7c478bd9Sstevel@tonic-gate pmubus_obpregspec_t *pmubus_rp; 854*7c478bd9Sstevel@tonic-gate char name[9]; 855*7c478bd9Sstevel@tonic-gate int reglen; 856*7c478bd9Sstevel@tonic-gate 857*7c478bd9Sstevel@tonic-gate switch (op) { 858*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_INITCHILD: 859*7c478bd9Sstevel@tonic-gate 860*7c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_NONE, child, 861*7c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "reg", (caddr_t)&pmubus_rp, 862*7c478bd9Sstevel@tonic-gate ®len) != DDI_SUCCESS) { 863*7c478bd9Sstevel@tonic-gate 864*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 865*7c478bd9Sstevel@tonic-gate } 866*7c478bd9Sstevel@tonic-gate 867*7c478bd9Sstevel@tonic-gate if ((reglen % sizeof (pmubus_obpregspec_t)) != 0) { 868*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 869*7c478bd9Sstevel@tonic-gate "pmubus: reg property not well-formed for " 870*7c478bd9Sstevel@tonic-gate "%s size=%d\n", ddi_node_name(child), reglen); 871*7c478bd9Sstevel@tonic-gate kmem_free(pmubus_rp, reglen); 872*7c478bd9Sstevel@tonic-gate 873*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 874*7c478bd9Sstevel@tonic-gate } 875*7c478bd9Sstevel@tonic-gate (void) snprintf(name, sizeof (name), "%x,%x", 876*7c478bd9Sstevel@tonic-gate pmubus_rp->reg_addr_hi, pmubus_rp->reg_addr_lo); 877*7c478bd9Sstevel@tonic-gate ddi_set_name_addr(child, name); 878*7c478bd9Sstevel@tonic-gate kmem_free(pmubus_rp, reglen); 879*7c478bd9Sstevel@tonic-gate 880*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 881*7c478bd9Sstevel@tonic-gate 882*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_UNINITCHILD: 883*7c478bd9Sstevel@tonic-gate 884*7c478bd9Sstevel@tonic-gate ddi_set_name_addr(child, NULL); 885*7c478bd9Sstevel@tonic-gate ddi_remove_minor_node(child, NULL); 886*7c478bd9Sstevel@tonic-gate impl_rem_dev_props(child); 887*7c478bd9Sstevel@tonic-gate 888*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 889*7c478bd9Sstevel@tonic-gate default: 890*7c478bd9Sstevel@tonic-gate break; 891*7c478bd9Sstevel@tonic-gate } 892*7c478bd9Sstevel@tonic-gate 893*7c478bd9Sstevel@tonic-gate return (ddi_ctlops(dip, rdip, op, arg, result)); 894*7c478bd9Sstevel@tonic-gate } 895