xref: /illumos-gate/usr/src/uts/sun4u/io/pmubus.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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 		    &reglen) != 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