10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7240Srh87107 * Common Development and Distribution License (the "License"). 6*7240Srh87107 * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*7240Srh87107 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate #include <sys/types.h> 290Sstevel@tonic-gate #include <sys/conf.h> 300Sstevel@tonic-gate #include <sys/ddi.h> 310Sstevel@tonic-gate #include <sys/sunddi.h> 320Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 330Sstevel@tonic-gate #include <sys/ddi_subrdefs.h> 340Sstevel@tonic-gate #include <sys/pci.h> 350Sstevel@tonic-gate #include <sys/autoconf.h> 360Sstevel@tonic-gate #include <sys/cmn_err.h> 370Sstevel@tonic-gate #include <sys/errno.h> 380Sstevel@tonic-gate #include <sys/kmem.h> 390Sstevel@tonic-gate #include <sys/debug.h> 400Sstevel@tonic-gate #include <sys/sysmacros.h> 410Sstevel@tonic-gate #include <sys/pmubus.h> 420Sstevel@tonic-gate 430Sstevel@tonic-gate #include <sys/nexusdebug.h> 440Sstevel@tonic-gate /* Bitfield debugging definitions for this file */ 450Sstevel@tonic-gate #define PMUBUS_MAP_DEBUG 0x1 460Sstevel@tonic-gate #define PMUBUS_REGACCESS_DEBUG 0x2 470Sstevel@tonic-gate #define PMUBUS_RW_DEBUG 0x4 480Sstevel@tonic-gate 490Sstevel@tonic-gate /* 500Sstevel@tonic-gate * The pmubus nexus is used to manage a shared register space. Rather 510Sstevel@tonic-gate * than having several driver's physically alias register mappings and 520Sstevel@tonic-gate * have potential problems with register collisions, this nexus will 530Sstevel@tonic-gate * serialize the access to this space. 540Sstevel@tonic-gate * 550Sstevel@tonic-gate * There are two types of sharing going on here: 560Sstevel@tonic-gate * 1) Registers within the address space may be shared, however the registers 570Sstevel@tonic-gate * themselves are unique. The upper bit of the child's high address being zero 580Sstevel@tonic-gate * signifies this register type. 590Sstevel@tonic-gate * 600Sstevel@tonic-gate * 2) The second type of register is one where a device may only own a few 610Sstevel@tonic-gate * bits in the register. I'll term this as "bit lane" access. This is a more 620Sstevel@tonic-gate * complicated scenario. The drivers themselves are responsible for knowing 630Sstevel@tonic-gate * which bit lanes in the register they own. The read of a register only 640Sstevel@tonic-gate * guarantees that those bits the driver is interested in are valid. If a 650Sstevel@tonic-gate * driver needs to set bits in a register, a read must be done first to 660Sstevel@tonic-gate * identify the state of the drivers bits. Depending on which way a bit needs 670Sstevel@tonic-gate * to be driven, the driver will write a 1 to the bit to toggle it. If a bit 680Sstevel@tonic-gate * is to remain unchanged, a 0 is written to the bit. So the access to the 690Sstevel@tonic-gate * bit lane is an xor operation. 700Sstevel@tonic-gate */ 710Sstevel@tonic-gate /* 720Sstevel@tonic-gate * Function prototypes for busops routines: 730Sstevel@tonic-gate */ 740Sstevel@tonic-gate static int pmubus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 750Sstevel@tonic-gate off_t off, off_t len, caddr_t *addrp); 760Sstevel@tonic-gate static int pmubus_ctlops(dev_info_t *dip, dev_info_t *rdip, 770Sstevel@tonic-gate ddi_ctl_enum_t op, void *arg, void *result); 780Sstevel@tonic-gate 790Sstevel@tonic-gate /* 800Sstevel@tonic-gate * function prototypes for dev ops routines: 810Sstevel@tonic-gate */ 820Sstevel@tonic-gate static int pmubus_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 830Sstevel@tonic-gate static int pmubus_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 840Sstevel@tonic-gate 850Sstevel@tonic-gate /* 860Sstevel@tonic-gate * general function prototypes: 870Sstevel@tonic-gate */ 880Sstevel@tonic-gate 890Sstevel@tonic-gate /* 900Sstevel@tonic-gate * bus ops and dev ops structures: 910Sstevel@tonic-gate */ 920Sstevel@tonic-gate static struct bus_ops pmubus_bus_ops = { 930Sstevel@tonic-gate BUSO_REV, 940Sstevel@tonic-gate pmubus_map, 950Sstevel@tonic-gate NULL, 960Sstevel@tonic-gate NULL, 970Sstevel@tonic-gate NULL, 980Sstevel@tonic-gate i_ddi_map_fault, 990Sstevel@tonic-gate ddi_dma_map, 1000Sstevel@tonic-gate ddi_dma_allochdl, 1010Sstevel@tonic-gate ddi_dma_freehdl, 1020Sstevel@tonic-gate ddi_dma_bindhdl, 1030Sstevel@tonic-gate ddi_dma_unbindhdl, 1040Sstevel@tonic-gate ddi_dma_flush, 1050Sstevel@tonic-gate ddi_dma_win, 1060Sstevel@tonic-gate ddi_dma_mctl, 1070Sstevel@tonic-gate pmubus_ctlops, 1080Sstevel@tonic-gate ddi_bus_prop_op, 1090Sstevel@tonic-gate 0, /* (*bus_get_eventcookie)(); */ 1100Sstevel@tonic-gate 0, /* (*bus_add_eventcall)(); */ 1110Sstevel@tonic-gate 0, /* (*bus_remove_eventcall)(); */ 1120Sstevel@tonic-gate 0, /* (*bus_post_event)(); */ 1130Sstevel@tonic-gate 0, /* interrupt control */ 1140Sstevel@tonic-gate 0, /* bus_config */ 1150Sstevel@tonic-gate 0, /* bus_unconfig */ 1160Sstevel@tonic-gate 0, /* bus_fm_init */ 1170Sstevel@tonic-gate 0, /* bus_fm_fini */ 1180Sstevel@tonic-gate 0, /* bus_fm_access_enter */ 1190Sstevel@tonic-gate 0, /* bus_fm_access_exit */ 1200Sstevel@tonic-gate 0, /* bus_power */ 1210Sstevel@tonic-gate i_ddi_intr_ops /* bus_intr_op */ 1220Sstevel@tonic-gate }; 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate static struct dev_ops pmubus_ops = { 1250Sstevel@tonic-gate DEVO_REV, 1260Sstevel@tonic-gate 0, 1270Sstevel@tonic-gate ddi_no_info, 1280Sstevel@tonic-gate nulldev, 1290Sstevel@tonic-gate 0, 1300Sstevel@tonic-gate pmubus_attach, 1310Sstevel@tonic-gate pmubus_detach, 1320Sstevel@tonic-gate nodev, 1330Sstevel@tonic-gate (struct cb_ops *)0, 1340Sstevel@tonic-gate &pmubus_bus_ops 1350Sstevel@tonic-gate }; 1360Sstevel@tonic-gate 1370Sstevel@tonic-gate /* 1380Sstevel@tonic-gate * module definitions: 1390Sstevel@tonic-gate */ 1400Sstevel@tonic-gate #include <sys/modctl.h> 1410Sstevel@tonic-gate extern struct mod_ops mod_driverops; 1420Sstevel@tonic-gate 1430Sstevel@tonic-gate static struct modldrv modldrv = { 1440Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */ 1450Sstevel@tonic-gate "pmubus nexus driver", /* Name of module. */ 1460Sstevel@tonic-gate &pmubus_ops, /* driver ops */ 1470Sstevel@tonic-gate }; 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate static struct modlinkage modlinkage = { 1500Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL 1510Sstevel@tonic-gate }; 1520Sstevel@tonic-gate 1530Sstevel@tonic-gate /* 1540Sstevel@tonic-gate * driver global data: 1550Sstevel@tonic-gate */ 1560Sstevel@tonic-gate static void *per_pmubus_state; /* per-pmubus soft state pointer */ 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate int 1590Sstevel@tonic-gate _init(void) 1600Sstevel@tonic-gate { 1610Sstevel@tonic-gate int e; 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate /* 1640Sstevel@tonic-gate * Initialize per-pmubus soft state pointer. 1650Sstevel@tonic-gate */ 1660Sstevel@tonic-gate e = ddi_soft_state_init(&per_pmubus_state, 1670Sstevel@tonic-gate sizeof (pmubus_devstate_t), 1); 1680Sstevel@tonic-gate if (e != 0) 1690Sstevel@tonic-gate return (e); 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate /* 1720Sstevel@tonic-gate * Install the module. 1730Sstevel@tonic-gate */ 1740Sstevel@tonic-gate e = mod_install(&modlinkage); 1750Sstevel@tonic-gate if (e != 0) 1760Sstevel@tonic-gate ddi_soft_state_fini(&per_pmubus_state); 1770Sstevel@tonic-gate 1780Sstevel@tonic-gate return (e); 1790Sstevel@tonic-gate } 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate int 1820Sstevel@tonic-gate _fini(void) 1830Sstevel@tonic-gate { 1840Sstevel@tonic-gate int e; 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate /* 1870Sstevel@tonic-gate * Remove the module. 1880Sstevel@tonic-gate */ 1890Sstevel@tonic-gate e = mod_remove(&modlinkage); 1900Sstevel@tonic-gate if (e != 0) 1910Sstevel@tonic-gate return (e); 1920Sstevel@tonic-gate 1930Sstevel@tonic-gate /* 1940Sstevel@tonic-gate * Free the soft state info. 1950Sstevel@tonic-gate */ 1960Sstevel@tonic-gate ddi_soft_state_fini(&per_pmubus_state); 1970Sstevel@tonic-gate return (e); 1980Sstevel@tonic-gate } 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate int 2010Sstevel@tonic-gate _info(struct modinfo *modinfop) 2020Sstevel@tonic-gate { 2030Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2040Sstevel@tonic-gate } 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate /* device driver entry points */ 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate /* 2090Sstevel@tonic-gate * attach entry point: 2100Sstevel@tonic-gate * 2110Sstevel@tonic-gate * normal attach: 2120Sstevel@tonic-gate * 2130Sstevel@tonic-gate * create soft state structure (dip, reg, nreg and state fields) 2140Sstevel@tonic-gate * map in configuration header 2150Sstevel@tonic-gate * make sure device is properly configured 2160Sstevel@tonic-gate * report device 2170Sstevel@tonic-gate */ 2180Sstevel@tonic-gate static int 2190Sstevel@tonic-gate pmubus_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2200Sstevel@tonic-gate { 2210Sstevel@tonic-gate pmubus_devstate_t *pmubusp; /* per pmubus state pointer */ 2220Sstevel@tonic-gate int32_t instance; 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate switch (cmd) { 2250Sstevel@tonic-gate case DDI_ATTACH: 2260Sstevel@tonic-gate /* 2270Sstevel@tonic-gate * Allocate soft state for this instance. 2280Sstevel@tonic-gate */ 2290Sstevel@tonic-gate instance = ddi_get_instance(dip); 2300Sstevel@tonic-gate if (ddi_soft_state_zalloc(per_pmubus_state, instance) != 2310Sstevel@tonic-gate DDI_SUCCESS) { 2320Sstevel@tonic-gate cmn_err(CE_WARN, "pmubus_attach: Can't allocate soft " 2330Sstevel@tonic-gate "state.\n"); 2340Sstevel@tonic-gate goto fail_exit; 2350Sstevel@tonic-gate } 2360Sstevel@tonic-gate 2370Sstevel@tonic-gate pmubusp = ddi_get_soft_state(per_pmubus_state, instance); 2380Sstevel@tonic-gate pmubusp->pmubus_dip = dip; 2390Sstevel@tonic-gate 2400Sstevel@tonic-gate /* Cache our register property */ 241506Scth if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 2420Sstevel@tonic-gate "reg", (caddr_t)&pmubusp->pmubus_regp, 2430Sstevel@tonic-gate &pmubusp->pmubus_reglen) != DDI_SUCCESS) { 2440Sstevel@tonic-gate cmn_err(CE_WARN, "pmubus_attach: Can't acquire reg " 2450Sstevel@tonic-gate "property.\n"); 2460Sstevel@tonic-gate goto fail_get_regs; 2470Sstevel@tonic-gate } 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate /* Cache our ranges property */ 250506Scth if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 2510Sstevel@tonic-gate "ranges", (caddr_t)&pmubusp->pmubus_rangep, 2520Sstevel@tonic-gate &pmubusp->pmubus_rnglen) != DDI_SUCCESS) { 2530Sstevel@tonic-gate cmn_err(CE_WARN, "pmubus_attach: Can't acquire the " 2540Sstevel@tonic-gate "ranges property.\n"); 2550Sstevel@tonic-gate goto fail_get_ranges; 2560Sstevel@tonic-gate 2570Sstevel@tonic-gate } 2580Sstevel@tonic-gate 2590Sstevel@tonic-gate /* Calculate the number of ranges */ 2600Sstevel@tonic-gate pmubusp->pmubus_nranges = 2610Sstevel@tonic-gate pmubusp->pmubus_rnglen / sizeof (pmu_rangespec_t); 2620Sstevel@tonic-gate 2630Sstevel@tonic-gate /* Set up the mapping to our registers */ 2640Sstevel@tonic-gate if (pci_config_setup(dip, &pmubusp->pmubus_reghdl) != 2650Sstevel@tonic-gate DDI_SUCCESS) { 2660Sstevel@tonic-gate cmn_err(CE_WARN, "pmubus_attach: Can't map in " 2670Sstevel@tonic-gate "register space.\n"); 2680Sstevel@tonic-gate goto fail_map_regs; 2690Sstevel@tonic-gate } 2700Sstevel@tonic-gate 2710Sstevel@tonic-gate /* Initialize our register access mutex */ 2720Sstevel@tonic-gate mutex_init(&pmubusp->pmubus_reg_access_lock, NULL, 2730Sstevel@tonic-gate MUTEX_DRIVER, NULL); 2740Sstevel@tonic-gate 2750Sstevel@tonic-gate ddi_report_dev(dip); 2760Sstevel@tonic-gate return (DDI_SUCCESS); 2770Sstevel@tonic-gate 2780Sstevel@tonic-gate case DDI_RESUME: 2790Sstevel@tonic-gate return (DDI_SUCCESS); 2800Sstevel@tonic-gate } 2810Sstevel@tonic-gate 2820Sstevel@tonic-gate fail_map_regs: 2830Sstevel@tonic-gate kmem_free(pmubusp->pmubus_rangep, pmubusp->pmubus_rnglen); 2840Sstevel@tonic-gate 2850Sstevel@tonic-gate fail_get_ranges: 2860Sstevel@tonic-gate kmem_free(pmubusp->pmubus_regp, pmubusp->pmubus_reglen); 2870Sstevel@tonic-gate 2880Sstevel@tonic-gate fail_get_regs: 2890Sstevel@tonic-gate ddi_soft_state_free(per_pmubus_state, instance); 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate fail_exit: 2920Sstevel@tonic-gate return (DDI_FAILURE); 2930Sstevel@tonic-gate } 2940Sstevel@tonic-gate 2950Sstevel@tonic-gate /* 2960Sstevel@tonic-gate * detach entry point: 2970Sstevel@tonic-gate */ 2980Sstevel@tonic-gate static int 2990Sstevel@tonic-gate pmubus_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 3000Sstevel@tonic-gate { 3010Sstevel@tonic-gate int instance = ddi_get_instance(dip); 3020Sstevel@tonic-gate pmubus_devstate_t *pmubusp = ddi_get_soft_state(per_pmubus_state, 3030Sstevel@tonic-gate instance); 3040Sstevel@tonic-gate 3050Sstevel@tonic-gate switch (cmd) { 3060Sstevel@tonic-gate case DDI_DETACH: 3070Sstevel@tonic-gate mutex_destroy(&pmubusp->pmubus_reg_access_lock); 3080Sstevel@tonic-gate 3090Sstevel@tonic-gate /* Tear down our register mappings */ 3100Sstevel@tonic-gate pci_config_teardown(&pmubusp->pmubus_reghdl); 3110Sstevel@tonic-gate 3120Sstevel@tonic-gate /* Free our ranges property */ 3130Sstevel@tonic-gate kmem_free(pmubusp->pmubus_rangep, pmubusp->pmubus_rnglen); 3140Sstevel@tonic-gate 3150Sstevel@tonic-gate /* Free the register property */ 3160Sstevel@tonic-gate kmem_free(pmubusp->pmubus_regp, pmubusp->pmubus_reglen); 3170Sstevel@tonic-gate 3180Sstevel@tonic-gate ddi_soft_state_free(per_pmubus_state, instance); 3190Sstevel@tonic-gate break; 3200Sstevel@tonic-gate 3210Sstevel@tonic-gate case DDI_SUSPEND: 3220Sstevel@tonic-gate default: 3230Sstevel@tonic-gate break; 3240Sstevel@tonic-gate } 3250Sstevel@tonic-gate 3260Sstevel@tonic-gate return (DDI_SUCCESS); 3270Sstevel@tonic-gate } 3280Sstevel@tonic-gate 3290Sstevel@tonic-gate /*ARGSUSED*/ 3300Sstevel@tonic-gate void 3310Sstevel@tonic-gate pmubus_norep_get8(ddi_acc_impl_t *handle, uint8_t *host_addr, 3320Sstevel@tonic-gate uint8_t *dev_addr, size_t repcount, uint_t flags) 3330Sstevel@tonic-gate { 3340Sstevel@tonic-gate } 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate /*ARGSUSED*/ 3370Sstevel@tonic-gate void 3380Sstevel@tonic-gate pmubus_norep_get16(ddi_acc_impl_t *handle, uint16_t *host_addr, 3390Sstevel@tonic-gate uint16_t *dev_addr, size_t repcount, uint_t flags) 3400Sstevel@tonic-gate { 3410Sstevel@tonic-gate } 3420Sstevel@tonic-gate 3430Sstevel@tonic-gate /*ARGSUSED*/ 3440Sstevel@tonic-gate void 3450Sstevel@tonic-gate pmubus_norep_get32(ddi_acc_impl_t *handle, uint32_t *host_addr, 3460Sstevel@tonic-gate uint32_t *dev_addr, size_t repcount, uint_t flags) 3470Sstevel@tonic-gate { 3480Sstevel@tonic-gate } 3490Sstevel@tonic-gate 3500Sstevel@tonic-gate /*ARGSUSED*/ 3510Sstevel@tonic-gate void 3520Sstevel@tonic-gate pmubus_norep_get64(ddi_acc_impl_t *handle, uint64_t *host_addr, 3530Sstevel@tonic-gate uint64_t *dev_addr, size_t repcount, uint_t flags) 3540Sstevel@tonic-gate { 3550Sstevel@tonic-gate } 3560Sstevel@tonic-gate 3570Sstevel@tonic-gate /*ARGSUSED*/ 3580Sstevel@tonic-gate void 3590Sstevel@tonic-gate pmubus_norep_put8(ddi_acc_impl_t *handle, uint8_t *host_addr, 3600Sstevel@tonic-gate uint8_t *dev_addr, size_t repcount, uint_t flags) 3610Sstevel@tonic-gate { 3620Sstevel@tonic-gate } 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate /*ARGSUSED*/ 3650Sstevel@tonic-gate void 3660Sstevel@tonic-gate pmubus_norep_put16(ddi_acc_impl_t *handle, uint16_t *host_addr, 3670Sstevel@tonic-gate uint16_t *dev_addr, size_t repcount, uint_t flags) 3680Sstevel@tonic-gate { 3690Sstevel@tonic-gate } 3700Sstevel@tonic-gate 3710Sstevel@tonic-gate /*ARGSUSED*/ 3720Sstevel@tonic-gate void 3730Sstevel@tonic-gate pmubus_norep_put32(ddi_acc_impl_t *handle, uint32_t *host_addr, 3740Sstevel@tonic-gate uint32_t *dev_addr, size_t repcount, uint_t flags) 3750Sstevel@tonic-gate { 3760Sstevel@tonic-gate } 3770Sstevel@tonic-gate 3780Sstevel@tonic-gate /*ARGSUSED*/ 3790Sstevel@tonic-gate void 3800Sstevel@tonic-gate pmubus_norep_put64(ddi_acc_impl_t *handle, uint64_t *host_addr, 3810Sstevel@tonic-gate uint64_t *dev_addr, size_t repcount, uint_t flags) 3820Sstevel@tonic-gate { 3830Sstevel@tonic-gate } 3840Sstevel@tonic-gate 3850Sstevel@tonic-gate /*ARGSUSED*/ 3860Sstevel@tonic-gate uint8_t 3870Sstevel@tonic-gate pmubus_get8(ddi_acc_impl_t *hdlp, uint8_t *addr) 3880Sstevel@tonic-gate { 3890Sstevel@tonic-gate ddi_acc_hdl_t *hp = (ddi_acc_hdl_t *)hdlp; 3900Sstevel@tonic-gate pmubus_mapreq_t *pmubus_mapreqp = hp->ah_bus_private; 3910Sstevel@tonic-gate pmubus_devstate_t *softsp = pmubus_mapreqp->mapreq_softsp; 3920Sstevel@tonic-gate off_t offset; 3930Sstevel@tonic-gate uint8_t value; 3940Sstevel@tonic-gate uint8_t mask; 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate offset = pmubus_mapreqp->mapreq_addr + (uintptr_t)addr; 3970Sstevel@tonic-gate offset &= PMUBUS_REGOFFSET; 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate if ((pmubus_mapreqp->mapreq_flags) & MAPREQ_SHARED_BITS) { 4000Sstevel@tonic-gate if (addr != 0 || 4010Sstevel@tonic-gate pmubus_mapreqp->mapreq_size != sizeof (value)) { 4020Sstevel@tonic-gate cmn_err(CE_WARN, "pmubus_get8: load discarded, " 4030Sstevel@tonic-gate "incorrect access addr/size"); 4040Sstevel@tonic-gate return ((uint8_t)-1); 4050Sstevel@tonic-gate } 4060Sstevel@tonic-gate mask = pmubus_mapreqp->mapreq_mask; 4070Sstevel@tonic-gate } else { 4080Sstevel@tonic-gate mask = (uint8_t)-1; 4090Sstevel@tonic-gate } 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate /* gets are simple, we just issue them no locking necessary */ 4120Sstevel@tonic-gate value = pci_config_get8(softsp->pmubus_reghdl, offset) & mask; 4130Sstevel@tonic-gate 414946Smathue DPRINTF(PMUBUS_RW_DEBUG, ("pmubus_get8: addr=%p offset=%lx value=%x " 415*7240Srh87107 "mask=%x\n", (void *)addr, offset, value, mask)); 4160Sstevel@tonic-gate 4170Sstevel@tonic-gate return (value); 4180Sstevel@tonic-gate } 4190Sstevel@tonic-gate 4200Sstevel@tonic-gate 4210Sstevel@tonic-gate /*ARGSUSED*/ 4220Sstevel@tonic-gate uint16_t 4230Sstevel@tonic-gate pmubus_noget16(ddi_acc_impl_t *hdlp, uint16_t *addr) 4240Sstevel@tonic-gate { 4250Sstevel@tonic-gate return ((uint16_t)-1); 4260Sstevel@tonic-gate } 4270Sstevel@tonic-gate 4280Sstevel@tonic-gate /*ARGSUSED*/ 4290Sstevel@tonic-gate uint32_t 4300Sstevel@tonic-gate pmubus_get32(ddi_acc_impl_t *hdlp, uint32_t *addr) 4310Sstevel@tonic-gate { 4320Sstevel@tonic-gate ddi_acc_hdl_t *hp = (ddi_acc_hdl_t *)hdlp; 4330Sstevel@tonic-gate pmubus_mapreq_t *pmubus_mapreqp = hp->ah_bus_private; 4340Sstevel@tonic-gate pmubus_devstate_t *softsp = pmubus_mapreqp->mapreq_softsp; 4350Sstevel@tonic-gate off_t offset = (uintptr_t)addr & PMUBUS_REGOFFSET; 4360Sstevel@tonic-gate uint32_t value; 4370Sstevel@tonic-gate uint32_t mask; 4380Sstevel@tonic-gate 4390Sstevel@tonic-gate offset = pmubus_mapreqp->mapreq_addr + (uintptr_t)addr; 4400Sstevel@tonic-gate offset &= PMUBUS_REGOFFSET; 4410Sstevel@tonic-gate 4420Sstevel@tonic-gate if ((pmubus_mapreqp->mapreq_flags) & MAPREQ_SHARED_BITS) { 4430Sstevel@tonic-gate if (addr != 0 || 4440Sstevel@tonic-gate pmubus_mapreqp->mapreq_size != sizeof (value)) { 4450Sstevel@tonic-gate cmn_err(CE_WARN, "pmubus_get32: load discarded, " 4460Sstevel@tonic-gate "incorrect access addr/size"); 4470Sstevel@tonic-gate return ((uint32_t)-1); 4480Sstevel@tonic-gate } 4490Sstevel@tonic-gate mask = pmubus_mapreqp->mapreq_mask; 4500Sstevel@tonic-gate } else { 4510Sstevel@tonic-gate mask = (uint32_t)-1; 4520Sstevel@tonic-gate } 4530Sstevel@tonic-gate 4540Sstevel@tonic-gate /* gets are simple, we just issue them no locking necessary */ 4550Sstevel@tonic-gate value = pci_config_get32(softsp->pmubus_reghdl, offset) & mask; 4560Sstevel@tonic-gate 457946Smathue DPRINTF(PMUBUS_RW_DEBUG, ("pmubus_get32: addr=%p offset=%lx value=%x " 458*7240Srh87107 "mask=%x\n", (void *)addr, offset, value, mask)); 4590Sstevel@tonic-gate 4600Sstevel@tonic-gate return (value); 4610Sstevel@tonic-gate } 4620Sstevel@tonic-gate 4630Sstevel@tonic-gate /*ARGSUSED*/ 4640Sstevel@tonic-gate uint64_t 4650Sstevel@tonic-gate pmubus_noget64(ddi_acc_impl_t *hdlp, uint64_t *addr) 4660Sstevel@tonic-gate { 4670Sstevel@tonic-gate return ((uint64_t)-1); 4680Sstevel@tonic-gate } 4690Sstevel@tonic-gate 4700Sstevel@tonic-gate /*ARGSUSED*/ 4710Sstevel@tonic-gate void 4720Sstevel@tonic-gate pmubus_put8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value) 4730Sstevel@tonic-gate { 4740Sstevel@tonic-gate ddi_acc_hdl_t *hp = (ddi_acc_hdl_t *)hdlp; 4750Sstevel@tonic-gate pmubus_mapreq_t *pmubus_mapreqp = hp->ah_bus_private; 4760Sstevel@tonic-gate pmubus_devstate_t *softsp = pmubus_mapreqp->mapreq_softsp; 4770Sstevel@tonic-gate off_t offset; 4780Sstevel@tonic-gate uint8_t tmp; 4790Sstevel@tonic-gate 4800Sstevel@tonic-gate offset = pmubus_mapreqp->mapreq_addr + (uintptr_t)addr; 4810Sstevel@tonic-gate offset &= PMUBUS_REGOFFSET; 4820Sstevel@tonic-gate 4830Sstevel@tonic-gate if ((pmubus_mapreqp->mapreq_flags) & MAPREQ_SHARED_BITS) { 4840Sstevel@tonic-gate /* 4850Sstevel@tonic-gate * Process "bit lane" register 4860Sstevel@tonic-gate */ 487946Smathue DPRINTF(PMUBUS_RW_DEBUG, ("pmubus_put8: addr=%p offset=%lx " 488*7240Srh87107 "value=%x mask=%lx\n", (void *)addr, offset, value, 4890Sstevel@tonic-gate pmubus_mapreqp->mapreq_mask)); 4900Sstevel@tonic-gate 4910Sstevel@tonic-gate if (addr != 0 || 4920Sstevel@tonic-gate pmubus_mapreqp->mapreq_size != sizeof (value)) { 4930Sstevel@tonic-gate cmn_err(CE_WARN, "pmubus_put8: store discarded, " 4940Sstevel@tonic-gate "incorrect access addr/size"); 4950Sstevel@tonic-gate return; 4960Sstevel@tonic-gate } 4970Sstevel@tonic-gate 4980Sstevel@tonic-gate mutex_enter(&softsp->pmubus_reg_access_lock); 4990Sstevel@tonic-gate tmp = pci_config_get8(softsp->pmubus_reghdl, offset); 5000Sstevel@tonic-gate tmp &= ~pmubus_mapreqp->mapreq_mask; 5010Sstevel@tonic-gate value &= pmubus_mapreqp->mapreq_mask; 5020Sstevel@tonic-gate tmp |= value; 5030Sstevel@tonic-gate pci_config_put8(softsp->pmubus_reghdl, offset, tmp); 5040Sstevel@tonic-gate mutex_exit(&softsp->pmubus_reg_access_lock); 5050Sstevel@tonic-gate } else { 5060Sstevel@tonic-gate /* 5070Sstevel@tonic-gate * Process shared register 5080Sstevel@tonic-gate */ 509946Smathue DPRINTF(PMUBUS_RW_DEBUG, ("pmubus_put8: addr=%p offset=%lx " 510*7240Srh87107 "value=%x\n", (void *)addr, offset, value)); 5110Sstevel@tonic-gate pci_config_put8(softsp->pmubus_reghdl, offset, value); 5120Sstevel@tonic-gate } 5130Sstevel@tonic-gate 5140Sstevel@tonic-gate /* Flush store buffers XXX Should let drivers do this. */ 5150Sstevel@tonic-gate tmp = pci_config_get8(softsp->pmubus_reghdl, offset); 5160Sstevel@tonic-gate } 5170Sstevel@tonic-gate 5180Sstevel@tonic-gate /*ARGSUSED*/ 5190Sstevel@tonic-gate void 5200Sstevel@tonic-gate pmubus_noput16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value) 5210Sstevel@tonic-gate { 5220Sstevel@tonic-gate } 5230Sstevel@tonic-gate 5240Sstevel@tonic-gate /*ARGSUSED*/ 5250Sstevel@tonic-gate void 5260Sstevel@tonic-gate pmubus_put32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value) 5270Sstevel@tonic-gate { 5280Sstevel@tonic-gate ddi_acc_hdl_t *hp = (ddi_acc_hdl_t *)hdlp; 5290Sstevel@tonic-gate pmubus_mapreq_t *pmubus_mapreqp = hp->ah_bus_private; 5300Sstevel@tonic-gate pmubus_devstate_t *softsp = pmubus_mapreqp->mapreq_softsp; 5310Sstevel@tonic-gate off_t offset; 5320Sstevel@tonic-gate uint32_t tmp; 5330Sstevel@tonic-gate 5340Sstevel@tonic-gate offset = pmubus_mapreqp->mapreq_addr + (uintptr_t)addr; 5350Sstevel@tonic-gate offset &= PMUBUS_REGOFFSET; 5360Sstevel@tonic-gate 5370Sstevel@tonic-gate if ((pmubus_mapreqp->mapreq_flags) & MAPREQ_SHARED_BITS) { 5380Sstevel@tonic-gate /* 5390Sstevel@tonic-gate * Process "bit lane" register 5400Sstevel@tonic-gate */ 541946Smathue DPRINTF(PMUBUS_RW_DEBUG, ("pmubus_put32: addr=%p offset=%lx " 542*7240Srh87107 "value=%x mask=%lx\n", (void *)addr, offset, value, 5430Sstevel@tonic-gate pmubus_mapreqp->mapreq_mask)); 5440Sstevel@tonic-gate 5450Sstevel@tonic-gate if (addr != 0 || 5460Sstevel@tonic-gate pmubus_mapreqp->mapreq_size != sizeof (value)) { 5470Sstevel@tonic-gate cmn_err(CE_WARN, "pmubus_put32: store discarded, " 5480Sstevel@tonic-gate "incorrect access addr/size"); 5490Sstevel@tonic-gate return; 5500Sstevel@tonic-gate } 5510Sstevel@tonic-gate 5520Sstevel@tonic-gate mutex_enter(&softsp->pmubus_reg_access_lock); 5530Sstevel@tonic-gate tmp = pci_config_get32(softsp->pmubus_reghdl, offset); 5540Sstevel@tonic-gate tmp &= ~pmubus_mapreqp->mapreq_mask; 5550Sstevel@tonic-gate value &= pmubus_mapreqp->mapreq_mask; 5560Sstevel@tonic-gate tmp |= value; 5570Sstevel@tonic-gate pci_config_put32(softsp->pmubus_reghdl, offset, tmp); 5580Sstevel@tonic-gate mutex_exit(&softsp->pmubus_reg_access_lock); 5590Sstevel@tonic-gate } else { 5600Sstevel@tonic-gate /* 5610Sstevel@tonic-gate * Process shared register 5620Sstevel@tonic-gate */ 563946Smathue DPRINTF(PMUBUS_RW_DEBUG, ("pmubus_put32: addr=%p offset=%lx " 564*7240Srh87107 "value=%x\n", (void *)addr, offset, value)); 5650Sstevel@tonic-gate pci_config_put32(softsp->pmubus_reghdl, offset, value); 5660Sstevel@tonic-gate } 5670Sstevel@tonic-gate 5680Sstevel@tonic-gate /* Flush store buffers XXX Should let drivers do this. */ 5690Sstevel@tonic-gate tmp = pci_config_get32(softsp->pmubus_reghdl, offset); 5700Sstevel@tonic-gate } 5710Sstevel@tonic-gate 5720Sstevel@tonic-gate /*ARGSUSED*/ 5730Sstevel@tonic-gate void 5740Sstevel@tonic-gate pmubus_noput64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value) 5750Sstevel@tonic-gate { 5760Sstevel@tonic-gate } 5770Sstevel@tonic-gate 5780Sstevel@tonic-gate /* 5790Sstevel@tonic-gate * This routine is used to translate our children's register properties. 5800Sstevel@tonic-gate * The return value specifies which type of register has been translated. 5810Sstevel@tonic-gate */ 5820Sstevel@tonic-gate /*ARGSUSED*/ 5830Sstevel@tonic-gate int 5840Sstevel@tonic-gate pmubus_apply_range(pmubus_devstate_t *pmubusp, dev_info_t *rdip, 5850Sstevel@tonic-gate pmubus_regspec_t *regp, pci_regspec_t *pci_regp) 5860Sstevel@tonic-gate { 5870Sstevel@tonic-gate pmu_rangespec_t *rangep; 5880Sstevel@tonic-gate int nranges = pmubusp->pmubus_nranges; 5890Sstevel@tonic-gate int i; 5900Sstevel@tonic-gate off_t offset; 5910Sstevel@tonic-gate int ret = DDI_ME_REGSPEC_RANGE; 5920Sstevel@tonic-gate uint64_t addr; 5930Sstevel@tonic-gate 5940Sstevel@tonic-gate addr = regp->reg_addr & ~MAPPING_SHARED_BITS_MASK; 5950Sstevel@tonic-gate 5960Sstevel@tonic-gate /* Scan the ranges for a match */ 5970Sstevel@tonic-gate for (i = 0, rangep = pmubusp->pmubus_rangep; i < nranges; i++, rangep++) 5980Sstevel@tonic-gate if ((rangep->rng_child <= addr) && 5990Sstevel@tonic-gate ((addr + regp->reg_size) <= 6000Sstevel@tonic-gate (rangep->rng_child + rangep->rng_size))) { 6010Sstevel@tonic-gate ret = DDI_SUCCESS; 6020Sstevel@tonic-gate break; 6030Sstevel@tonic-gate } 6040Sstevel@tonic-gate 6050Sstevel@tonic-gate if (ret != DDI_SUCCESS) 6060Sstevel@tonic-gate return (ret); 6070Sstevel@tonic-gate 6080Sstevel@tonic-gate /* Get the translated register */ 6090Sstevel@tonic-gate offset = addr - rangep->rng_child; 6100Sstevel@tonic-gate pci_regp->pci_phys_hi = rangep->rng_parent_hi; 6110Sstevel@tonic-gate pci_regp->pci_phys_mid = rangep->rng_parent_mid; 6120Sstevel@tonic-gate pci_regp->pci_phys_low = rangep->rng_parent_low + offset; 6130Sstevel@tonic-gate pci_regp->pci_size_hi = 0; 6140Sstevel@tonic-gate pci_regp->pci_size_low = MIN(regp->reg_size, rangep->rng_size); 6150Sstevel@tonic-gate 6160Sstevel@tonic-gate /* Figure out the type of reg space we have */ 6170Sstevel@tonic-gate if (pci_regp->pci_phys_hi == pmubusp->pmubus_regp->pci_phys_hi) { 6180Sstevel@tonic-gate ret = MAPREQ_SHARED_REG; 6190Sstevel@tonic-gate if (regp->reg_addr & MAPPING_SHARED_BITS_MASK) 6200Sstevel@tonic-gate ret |= MAPREQ_SHARED_BITS; 6210Sstevel@tonic-gate } 6220Sstevel@tonic-gate 6230Sstevel@tonic-gate return (ret); 6240Sstevel@tonic-gate } 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate static uint64_t 6270Sstevel@tonic-gate pmubus_mask(pmubus_obpregspec_t *regs, int32_t rnumber, 6280Sstevel@tonic-gate uint64_t *masks) 6290Sstevel@tonic-gate { 6300Sstevel@tonic-gate int i; 6310Sstevel@tonic-gate long n = -1; 6320Sstevel@tonic-gate 6330Sstevel@tonic-gate for (i = 0; i <= rnumber; i++) 6340Sstevel@tonic-gate if (regs[i].reg_addr_hi & 0x80000000) 6350Sstevel@tonic-gate n++; 6360Sstevel@tonic-gate 6370Sstevel@tonic-gate if (n == -1) { 6380Sstevel@tonic-gate cmn_err(CE_WARN, "pmubus_mask: missing mask"); 6390Sstevel@tonic-gate return (0); 6400Sstevel@tonic-gate } 6410Sstevel@tonic-gate 6420Sstevel@tonic-gate return (masks[n]); 6430Sstevel@tonic-gate } 6440Sstevel@tonic-gate 6450Sstevel@tonic-gate /* 6460Sstevel@tonic-gate * The pmubus_map routine determines if it's child is attempting to map a 6470Sstevel@tonic-gate * shared reg. If it is, it installs it's own vectors and bus private pointer. 6480Sstevel@tonic-gate */ 6490Sstevel@tonic-gate static int 6500Sstevel@tonic-gate pmubus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 6510Sstevel@tonic-gate off_t off, off_t len, caddr_t *addrp) 6520Sstevel@tonic-gate { 6530Sstevel@tonic-gate pmubus_devstate_t *pmubusp = ddi_get_soft_state(per_pmubus_state, 6540Sstevel@tonic-gate ddi_get_instance(dip)); 6550Sstevel@tonic-gate dev_info_t *pdip = (dev_info_t *)DEVI(dip)->devi_parent; 6560Sstevel@tonic-gate pmubus_regspec_t pmubus_rp; 6570Sstevel@tonic-gate pmubus_obpregspec_t *pmubus_regs = NULL; 6580Sstevel@tonic-gate int pmubus_regs_size; 6590Sstevel@tonic-gate uint64_t *pmubus_regmask = NULL; 6600Sstevel@tonic-gate int pmubus_regmask_size; 6610Sstevel@tonic-gate pci_regspec_t pci_reg; 6620Sstevel@tonic-gate int32_t rnumber = mp->map_obj.rnumber; 6630Sstevel@tonic-gate pmubus_mapreq_t *pmubus_mapreqp; 6640Sstevel@tonic-gate int ret = DDI_SUCCESS; 6650Sstevel@tonic-gate char *map_fail1 = "Map Type Unknown"; 6660Sstevel@tonic-gate char *map_fail2 = "DDI_MT_REGSPEC"; 6670Sstevel@tonic-gate char *s = map_fail1; 6680Sstevel@tonic-gate 6690Sstevel@tonic-gate *addrp = NULL; 6700Sstevel@tonic-gate 6710Sstevel@tonic-gate /* 6720Sstevel@tonic-gate * Handle the mapping according to its type. 6730Sstevel@tonic-gate */ 674946Smathue DPRINTF(PMUBUS_MAP_DEBUG, ("rdip=%s%d: off=%lx len=%lx\n", 6750Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip), off, len)); 6760Sstevel@tonic-gate switch (mp->map_type) { 6770Sstevel@tonic-gate case DDI_MT_RNUMBER: { 6780Sstevel@tonic-gate int n; 6790Sstevel@tonic-gate 6800Sstevel@tonic-gate /* 6810Sstevel@tonic-gate * Get the "reg" property from the device node and convert 6820Sstevel@tonic-gate * it to our parent's format. 6830Sstevel@tonic-gate */ 6840Sstevel@tonic-gate rnumber = mp->map_obj.rnumber; 6850Sstevel@tonic-gate DPRINTF(PMUBUS_MAP_DEBUG, ("rdip=%s%d: rnumber=%x " 686946Smathue "handlep=%p\n", ddi_get_name(rdip), ddi_get_instance(rdip), 687*7240Srh87107 rnumber, (void *)mp->map_handlep)); 6880Sstevel@tonic-gate 689506Scth if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 6900Sstevel@tonic-gate "reg", (caddr_t)&pmubus_regs, &pmubus_regs_size) != 6910Sstevel@tonic-gate DDI_SUCCESS) { 6920Sstevel@tonic-gate DPRINTF(PMUBUS_MAP_DEBUG, ("can't get reg " 6930Sstevel@tonic-gate "property\n")); 6940Sstevel@tonic-gate ret = DDI_ME_RNUMBER_RANGE; 6950Sstevel@tonic-gate goto done; 6960Sstevel@tonic-gate } 6970Sstevel@tonic-gate n = pmubus_regs_size / sizeof (pmubus_obpregspec_t); 6980Sstevel@tonic-gate 6990Sstevel@tonic-gate if (rnumber < 0 || rnumber >= n) { 7000Sstevel@tonic-gate DPRINTF(PMUBUS_MAP_DEBUG, ("rnumber out of range\n")); 7010Sstevel@tonic-gate ret = DDI_ME_RNUMBER_RANGE; 7020Sstevel@tonic-gate goto done; 7030Sstevel@tonic-gate } 7040Sstevel@tonic-gate 7050Sstevel@tonic-gate pmubus_rp.reg_addr = ((uint64_t) 7060Sstevel@tonic-gate pmubus_regs[rnumber].reg_addr_hi << 32) | 7070Sstevel@tonic-gate (uint64_t)pmubus_regs[rnumber].reg_addr_lo; 7080Sstevel@tonic-gate pmubus_rp.reg_size = pmubus_regs[rnumber].reg_size; 7090Sstevel@tonic-gate 710506Scth (void) ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 7110Sstevel@tonic-gate "register-mask", (caddr_t)&pmubus_regmask, 7120Sstevel@tonic-gate &pmubus_regmask_size); 7130Sstevel@tonic-gate 7140Sstevel@tonic-gate /* Create our own mapping private structure */ 7150Sstevel@tonic-gate break; 7160Sstevel@tonic-gate 7170Sstevel@tonic-gate } 7180Sstevel@tonic-gate case DDI_MT_REGSPEC: 7190Sstevel@tonic-gate /* 7200Sstevel@tonic-gate * This bus has no bus children that have to map in an address 7210Sstevel@tonic-gate * space, so we can assume that we'll never see an 7220Sstevel@tonic-gate * DDI_MT_REGSPEC request 7230Sstevel@tonic-gate */ 7240Sstevel@tonic-gate s = map_fail2; 7250Sstevel@tonic-gate ret = DDI_ME_REGSPEC_RANGE; 7260Sstevel@tonic-gate /*FALLTHROUGH*/ 7270Sstevel@tonic-gate 7280Sstevel@tonic-gate default: 7290Sstevel@tonic-gate if (ret == DDI_SUCCESS) 7300Sstevel@tonic-gate ret = DDI_ME_INVAL; 7310Sstevel@tonic-gate DPRINTF(PMUBUS_MAP_DEBUG, ("rdip=%s%d: pmubus_map: " 7320Sstevel@tonic-gate "%s is an invalid map type.\nmap request handlep=0x%p\n", 733*7240Srh87107 ddi_get_name(rdip), ddi_get_instance(rdip), s, (void *)mp)); 7340Sstevel@tonic-gate 7350Sstevel@tonic-gate ret = DDI_ME_RNUMBER_RANGE; 7360Sstevel@tonic-gate goto done; 7370Sstevel@tonic-gate } 7380Sstevel@tonic-gate 7390Sstevel@tonic-gate /* Adjust our reg property with offset and length */ 7400Sstevel@tonic-gate if ((pmubus_rp.reg_addr + off) > 7410Sstevel@tonic-gate (pmubus_rp.reg_addr + pmubus_rp.reg_size)) { 7420Sstevel@tonic-gate ret = DDI_ME_INVAL; 7430Sstevel@tonic-gate goto done; 7440Sstevel@tonic-gate } 7450Sstevel@tonic-gate 7460Sstevel@tonic-gate pmubus_rp.reg_addr += off; 7470Sstevel@tonic-gate if (len && (len < pmubus_rp.reg_size)) 7480Sstevel@tonic-gate pmubus_rp.reg_size = len; 7490Sstevel@tonic-gate 7500Sstevel@tonic-gate /* Translate our child regspec into our parents address domain */ 7510Sstevel@tonic-gate ret = pmubus_apply_range(pmubusp, rdip, &pmubus_rp, &pci_reg); 7520Sstevel@tonic-gate 7530Sstevel@tonic-gate /* Check if the apply range failed */ 7540Sstevel@tonic-gate if (ret < DDI_SUCCESS) 7550Sstevel@tonic-gate goto done; 7560Sstevel@tonic-gate 7570Sstevel@tonic-gate /* 7580Sstevel@tonic-gate * If our childs xlated address falls into our shared address range, 7590Sstevel@tonic-gate * setup our mapping handle. 7600Sstevel@tonic-gate */ 7610Sstevel@tonic-gate if (ret > DDI_SUCCESS) { 7620Sstevel@tonic-gate /* Figure out if we're mapping or unmapping */ 7630Sstevel@tonic-gate switch (mp->map_op) { 7640Sstevel@tonic-gate case DDI_MO_MAP_LOCKED: { 7650Sstevel@tonic-gate ddi_acc_impl_t *hp = (ddi_acc_impl_t *)mp->map_handlep; 7660Sstevel@tonic-gate 7670Sstevel@tonic-gate pmubus_mapreqp = kmem_alloc(sizeof (*pmubus_mapreqp), 7680Sstevel@tonic-gate KM_SLEEP); 7690Sstevel@tonic-gate 7700Sstevel@tonic-gate pmubus_mapreqp->mapreq_flags = ret; 7710Sstevel@tonic-gate pmubus_mapreqp->mapreq_softsp = pmubusp; 7720Sstevel@tonic-gate pmubus_mapreqp->mapreq_addr = pmubus_rp.reg_addr; 7730Sstevel@tonic-gate pmubus_mapreqp->mapreq_size = pmubus_rp.reg_size; 7740Sstevel@tonic-gate 7750Sstevel@tonic-gate if (ret & MAPREQ_SHARED_BITS) { 7760Sstevel@tonic-gate pmubus_mapreqp->mapreq_mask = 7770Sstevel@tonic-gate pmubus_mask(pmubus_regs, rnumber, 7780Sstevel@tonic-gate pmubus_regmask); 7790Sstevel@tonic-gate DPRINTF(PMUBUS_MAP_DEBUG, ("rnumber=%d " 780946Smathue "mask=%lx\n", rnumber, 7810Sstevel@tonic-gate pmubus_mapreqp->mapreq_mask)); 7820Sstevel@tonic-gate if (pmubus_mapreqp->mapreq_mask == 0) { 7830Sstevel@tonic-gate kmem_free(pmubus_mapreqp, 7840Sstevel@tonic-gate sizeof (pmubus_mapreq_t)); 7850Sstevel@tonic-gate ret = DDI_ME_INVAL; 7860Sstevel@tonic-gate break; 7870Sstevel@tonic-gate } 7880Sstevel@tonic-gate } 7890Sstevel@tonic-gate 7900Sstevel@tonic-gate hp->ahi_common.ah_bus_private = pmubus_mapreqp; 7910Sstevel@tonic-gate 7920Sstevel@tonic-gate /* Initialize the access vectors */ 7930Sstevel@tonic-gate hp->ahi_get8 = pmubus_get8; 7940Sstevel@tonic-gate hp->ahi_get16 = pmubus_noget16; 7950Sstevel@tonic-gate hp->ahi_get32 = pmubus_get32; 7960Sstevel@tonic-gate hp->ahi_get64 = pmubus_noget64; 7970Sstevel@tonic-gate hp->ahi_put8 = pmubus_put8; 7980Sstevel@tonic-gate hp->ahi_put16 = pmubus_noput16; 7990Sstevel@tonic-gate hp->ahi_put32 = pmubus_put32; 8000Sstevel@tonic-gate hp->ahi_put64 = pmubus_noput64; 8010Sstevel@tonic-gate hp->ahi_rep_get8 = pmubus_norep_get8; 8020Sstevel@tonic-gate hp->ahi_rep_get16 = pmubus_norep_get16; 8030Sstevel@tonic-gate hp->ahi_rep_get32 = pmubus_norep_get32; 8040Sstevel@tonic-gate hp->ahi_rep_get64 = pmubus_norep_get64; 8050Sstevel@tonic-gate hp->ahi_rep_put8 = pmubus_norep_put8; 8060Sstevel@tonic-gate hp->ahi_rep_put16 = pmubus_norep_put16; 8070Sstevel@tonic-gate hp->ahi_rep_put32 = pmubus_norep_put32; 8080Sstevel@tonic-gate hp->ahi_rep_put64 = pmubus_norep_put64; 8090Sstevel@tonic-gate 8100Sstevel@tonic-gate ret = DDI_SUCCESS; 8110Sstevel@tonic-gate break; 8120Sstevel@tonic-gate } 8130Sstevel@tonic-gate 8140Sstevel@tonic-gate case DDI_MO_UNMAP: { 8150Sstevel@tonic-gate ddi_acc_impl_t *hp = (ddi_acc_impl_t *)mp->map_handlep; 8160Sstevel@tonic-gate 8170Sstevel@tonic-gate pmubus_mapreqp = hp->ahi_common.ah_bus_private; 8180Sstevel@tonic-gate 8190Sstevel@tonic-gate /* Free the our map request struct */ 8200Sstevel@tonic-gate kmem_free(pmubus_mapreqp, sizeof (pmubus_mapreq_t)); 8210Sstevel@tonic-gate 8220Sstevel@tonic-gate ret = DDI_SUCCESS; 8230Sstevel@tonic-gate break; 8240Sstevel@tonic-gate } 8250Sstevel@tonic-gate 8260Sstevel@tonic-gate default: 8270Sstevel@tonic-gate ret = DDI_ME_UNSUPPORTED; 8280Sstevel@tonic-gate } 8290Sstevel@tonic-gate } else { 8300Sstevel@tonic-gate /* Prepare the map request struct for a call to our parent */ 8310Sstevel@tonic-gate mp->map_type = DDI_MT_REGSPEC; 8320Sstevel@tonic-gate mp->map_obj.rp = (struct regspec *)&pci_reg; 8330Sstevel@tonic-gate 8340Sstevel@tonic-gate /* Pass the mapping operation up the device tree */ 8350Sstevel@tonic-gate ret = (DEVI(pdip)->devi_ops->devo_bus_ops->bus_map) 8360Sstevel@tonic-gate (pdip, rdip, mp, off, len, addrp); 8370Sstevel@tonic-gate } 8380Sstevel@tonic-gate 8390Sstevel@tonic-gate done: 8400Sstevel@tonic-gate if (pmubus_regs != NULL) 8410Sstevel@tonic-gate kmem_free(pmubus_regs, pmubus_regs_size); 8420Sstevel@tonic-gate if (pmubus_regmask != NULL) 8430Sstevel@tonic-gate kmem_free(pmubus_regmask, pmubus_regmask_size); 8440Sstevel@tonic-gate return (ret); 8450Sstevel@tonic-gate } 8460Sstevel@tonic-gate 8470Sstevel@tonic-gate static int 8480Sstevel@tonic-gate pmubus_ctlops(dev_info_t *dip, dev_info_t *rdip, 8490Sstevel@tonic-gate ddi_ctl_enum_t op, void *arg, void *result) 8500Sstevel@tonic-gate { 8510Sstevel@tonic-gate dev_info_t *child = (dev_info_t *)arg; 8520Sstevel@tonic-gate pmubus_obpregspec_t *pmubus_rp; 8530Sstevel@tonic-gate char name[9]; 8540Sstevel@tonic-gate int reglen; 8550Sstevel@tonic-gate 8560Sstevel@tonic-gate switch (op) { 8570Sstevel@tonic-gate case DDI_CTLOPS_INITCHILD: 8580Sstevel@tonic-gate 859506Scth if (ddi_getlongprop(DDI_DEV_T_ANY, child, 8600Sstevel@tonic-gate DDI_PROP_DONTPASS, "reg", (caddr_t)&pmubus_rp, 8610Sstevel@tonic-gate ®len) != DDI_SUCCESS) { 8620Sstevel@tonic-gate 8630Sstevel@tonic-gate return (DDI_FAILURE); 8640Sstevel@tonic-gate } 8650Sstevel@tonic-gate 8660Sstevel@tonic-gate if ((reglen % sizeof (pmubus_obpregspec_t)) != 0) { 8670Sstevel@tonic-gate cmn_err(CE_WARN, 8680Sstevel@tonic-gate "pmubus: reg property not well-formed for " 8690Sstevel@tonic-gate "%s size=%d\n", ddi_node_name(child), reglen); 8700Sstevel@tonic-gate kmem_free(pmubus_rp, reglen); 8710Sstevel@tonic-gate 8720Sstevel@tonic-gate return (DDI_FAILURE); 8730Sstevel@tonic-gate } 8740Sstevel@tonic-gate (void) snprintf(name, sizeof (name), "%x,%x", 8750Sstevel@tonic-gate pmubus_rp->reg_addr_hi, pmubus_rp->reg_addr_lo); 8760Sstevel@tonic-gate ddi_set_name_addr(child, name); 8770Sstevel@tonic-gate kmem_free(pmubus_rp, reglen); 8780Sstevel@tonic-gate 8790Sstevel@tonic-gate return (DDI_SUCCESS); 8800Sstevel@tonic-gate 8810Sstevel@tonic-gate case DDI_CTLOPS_UNINITCHILD: 8820Sstevel@tonic-gate 8830Sstevel@tonic-gate ddi_set_name_addr(child, NULL); 8840Sstevel@tonic-gate ddi_remove_minor_node(child, NULL); 8850Sstevel@tonic-gate impl_rem_dev_props(child); 8860Sstevel@tonic-gate 8870Sstevel@tonic-gate return (DDI_SUCCESS); 8880Sstevel@tonic-gate default: 8890Sstevel@tonic-gate break; 8900Sstevel@tonic-gate } 8910Sstevel@tonic-gate 8920Sstevel@tonic-gate return (ddi_ctlops(dip, rdip, op, arg, result)); 8930Sstevel@tonic-gate } 894