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