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