xref: /titanic_53/usr/src/uts/sun4u/io/upa64s.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/autoconf.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/ddi_subrdefs.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/spl.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/async.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/dvma.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/upa64s.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/machsystm.h>
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate /*
48*7c478bd9Sstevel@tonic-gate  * driver global data:
49*7c478bd9Sstevel@tonic-gate  */
50*7c478bd9Sstevel@tonic-gate static void *per_upa64s_state;		/* soft state pointer */
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate /*
53*7c478bd9Sstevel@tonic-gate  * function prototypes for bus ops routines:
54*7c478bd9Sstevel@tonic-gate  */
55*7c478bd9Sstevel@tonic-gate static int
56*7c478bd9Sstevel@tonic-gate upa64s_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
57*7c478bd9Sstevel@tonic-gate     off_t offset, off_t len, caddr_t *addrp);
58*7c478bd9Sstevel@tonic-gate static int
59*7c478bd9Sstevel@tonic-gate upa64s_ctlops(dev_info_t *dip, dev_info_t *rdip,
60*7c478bd9Sstevel@tonic-gate     ddi_ctl_enum_t op, void *arg, void *result);
61*7c478bd9Sstevel@tonic-gate static int
62*7c478bd9Sstevel@tonic-gate upa64_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
63*7c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result);
64*7c478bd9Sstevel@tonic-gate static int
65*7c478bd9Sstevel@tonic-gate upa64s_add_intr_impl(dev_info_t *dip, dev_info_t *rdip,
66*7c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp);
67*7c478bd9Sstevel@tonic-gate static int
68*7c478bd9Sstevel@tonic-gate upa64s_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip,
69*7c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp);
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate /*
72*7c478bd9Sstevel@tonic-gate  * function prototypes for dev ops routines:
73*7c478bd9Sstevel@tonic-gate  */
74*7c478bd9Sstevel@tonic-gate static int upa64s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
75*7c478bd9Sstevel@tonic-gate static int upa64s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
76*7c478bd9Sstevel@tonic-gate static int upa64s_power(dev_info_t *dip, int component, int level);
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate /*
79*7c478bd9Sstevel@tonic-gate  * bus ops and dev ops structures:
80*7c478bd9Sstevel@tonic-gate  */
81*7c478bd9Sstevel@tonic-gate static struct bus_ops upa64s_bus_ops = {
82*7c478bd9Sstevel@tonic-gate 	BUSO_REV,
83*7c478bd9Sstevel@tonic-gate 	upa64s_map,
84*7c478bd9Sstevel@tonic-gate 	0,
85*7c478bd9Sstevel@tonic-gate 	0,
86*7c478bd9Sstevel@tonic-gate 	0,
87*7c478bd9Sstevel@tonic-gate 	i_ddi_map_fault,
88*7c478bd9Sstevel@tonic-gate 	ddi_no_dma_map,
89*7c478bd9Sstevel@tonic-gate 	ddi_no_dma_allochdl,
90*7c478bd9Sstevel@tonic-gate 	ddi_no_dma_freehdl,
91*7c478bd9Sstevel@tonic-gate 	ddi_no_dma_bindhdl,
92*7c478bd9Sstevel@tonic-gate 	ddi_no_dma_unbindhdl,
93*7c478bd9Sstevel@tonic-gate 	ddi_no_dma_flush,
94*7c478bd9Sstevel@tonic-gate 	ddi_no_dma_win,
95*7c478bd9Sstevel@tonic-gate 	ddi_no_dma_mctl,
96*7c478bd9Sstevel@tonic-gate 	upa64s_ctlops,
97*7c478bd9Sstevel@tonic-gate 	ddi_bus_prop_op,
98*7c478bd9Sstevel@tonic-gate 	0,
99*7c478bd9Sstevel@tonic-gate 	0,
100*7c478bd9Sstevel@tonic-gate 	0,
101*7c478bd9Sstevel@tonic-gate 	0,
102*7c478bd9Sstevel@tonic-gate 	0,
103*7c478bd9Sstevel@tonic-gate 	0,
104*7c478bd9Sstevel@tonic-gate 	0,
105*7c478bd9Sstevel@tonic-gate 	0,
106*7c478bd9Sstevel@tonic-gate 	0,
107*7c478bd9Sstevel@tonic-gate 	0,
108*7c478bd9Sstevel@tonic-gate 	0,
109*7c478bd9Sstevel@tonic-gate 	0,
110*7c478bd9Sstevel@tonic-gate 	upa64_intr_ops
111*7c478bd9Sstevel@tonic-gate };
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate static struct dev_ops upa64s_ops = {
114*7c478bd9Sstevel@tonic-gate 	DEVO_REV,
115*7c478bd9Sstevel@tonic-gate 	0,
116*7c478bd9Sstevel@tonic-gate 	ddi_no_info,
117*7c478bd9Sstevel@tonic-gate 	nulldev,
118*7c478bd9Sstevel@tonic-gate 	0,
119*7c478bd9Sstevel@tonic-gate 	upa64s_attach,
120*7c478bd9Sstevel@tonic-gate 	upa64s_detach,
121*7c478bd9Sstevel@tonic-gate 	nodev,
122*7c478bd9Sstevel@tonic-gate 	(struct cb_ops *)0,
123*7c478bd9Sstevel@tonic-gate 	&upa64s_bus_ops,
124*7c478bd9Sstevel@tonic-gate 	upa64s_power
125*7c478bd9Sstevel@tonic-gate };
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate /*
128*7c478bd9Sstevel@tonic-gate  * module definitions:
129*7c478bd9Sstevel@tonic-gate  */
130*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
131*7c478bd9Sstevel@tonic-gate extern struct mod_ops mod_driverops;
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
134*7c478bd9Sstevel@tonic-gate 	&mod_driverops, 		/* type of module */
135*7c478bd9Sstevel@tonic-gate 	"UPA64S nexus driver %I%",	/* name of module */
136*7c478bd9Sstevel@tonic-gate 	&upa64s_ops,			/* driver ops */
137*7c478bd9Sstevel@tonic-gate };
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
140*7c478bd9Sstevel@tonic-gate 	MODREV_1, (void *)&modldrv, NULL
141*7c478bd9Sstevel@tonic-gate };
142*7c478bd9Sstevel@tonic-gate 
143*7c478bd9Sstevel@tonic-gate int
144*7c478bd9Sstevel@tonic-gate _init(void)
145*7c478bd9Sstevel@tonic-gate {
146*7c478bd9Sstevel@tonic-gate 	int e;
147*7c478bd9Sstevel@tonic-gate 
148*7c478bd9Sstevel@tonic-gate 	/*
149*7c478bd9Sstevel@tonic-gate 	 * Initialize per instance bus soft state pointer.
150*7c478bd9Sstevel@tonic-gate 	 */
151*7c478bd9Sstevel@tonic-gate 	if (e = ddi_soft_state_init(&per_upa64s_state,
152*7c478bd9Sstevel@tonic-gate 	    sizeof (upa64s_devstate_t), 2))
153*7c478bd9Sstevel@tonic-gate 		return (e);
154*7c478bd9Sstevel@tonic-gate 	/*
155*7c478bd9Sstevel@tonic-gate 	 * Install the module.
156*7c478bd9Sstevel@tonic-gate 	 */
157*7c478bd9Sstevel@tonic-gate 	if (e = mod_install(&modlinkage))
158*7c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini(&per_upa64s_state);
159*7c478bd9Sstevel@tonic-gate 	return (e);
160*7c478bd9Sstevel@tonic-gate }
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate int
163*7c478bd9Sstevel@tonic-gate _fini(void)
164*7c478bd9Sstevel@tonic-gate {
165*7c478bd9Sstevel@tonic-gate 	int e = mod_remove(&modlinkage);
166*7c478bd9Sstevel@tonic-gate 	if (e)
167*7c478bd9Sstevel@tonic-gate 		return (e);
168*7c478bd9Sstevel@tonic-gate 	ddi_soft_state_fini(&per_upa64s_state);
169*7c478bd9Sstevel@tonic-gate 	return (e);
170*7c478bd9Sstevel@tonic-gate }
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate int
173*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
174*7c478bd9Sstevel@tonic-gate {
175*7c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
176*7c478bd9Sstevel@tonic-gate }
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate /*
180*7c478bd9Sstevel@tonic-gate  * forward declarations:
181*7c478bd9Sstevel@tonic-gate  */
182*7c478bd9Sstevel@tonic-gate static void upa64s_intrdist(void *arg);
183*7c478bd9Sstevel@tonic-gate static int init_child(dev_info_t *child);
184*7c478bd9Sstevel@tonic-gate static int report_dev(dev_info_t *dip);
185*7c478bd9Sstevel@tonic-gate static int get_properties(upa64s_devstate_t *upa64s_p, dev_info_t *dip);
186*7c478bd9Sstevel@tonic-gate static void save_state(upa64s_devstate_t *upa64s_p);
187*7c478bd9Sstevel@tonic-gate static void restore_state(upa64s_devstate_t *upa64s_p);
188*7c478bd9Sstevel@tonic-gate static int xlate_reg_prop(dev_info_t *dip, upa64s_regspec_t *upa64s_rp,
189*7c478bd9Sstevel@tonic-gate     off_t off, off_t len, struct regspec *rp);
190*7c478bd9Sstevel@tonic-gate static int get_reg_set(dev_info_t *dip, dev_info_t *child, int rnumber,
191*7c478bd9Sstevel@tonic-gate     off_t off, off_t len, struct regspec *rp);
192*7c478bd9Sstevel@tonic-gate static off_t get_reg_set_size(dev_info_t *child, int rnumber);
193*7c478bd9Sstevel@tonic-gate static uint_t get_nreg_set(dev_info_t *child);
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate /* device driver entry points */
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate /*
199*7c478bd9Sstevel@tonic-gate  * attach entry point:
200*7c478bd9Sstevel@tonic-gate  */
201*7c478bd9Sstevel@tonic-gate static int
202*7c478bd9Sstevel@tonic-gate upa64s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
203*7c478bd9Sstevel@tonic-gate {
204*7c478bd9Sstevel@tonic-gate 	upa64s_devstate_t *upa64s_p;	/* per upa64s state pointer */
205*7c478bd9Sstevel@tonic-gate 	ddi_device_acc_attr_t attr;
206*7c478bd9Sstevel@tonic-gate 	int instance;
207*7c478bd9Sstevel@tonic-gate 	char *pmc[] = { "NAME=Framebuffer Power", "0=Off", "1=On", NULL };
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
210*7c478bd9Sstevel@tonic-gate 	case DDI_ATTACH:
211*7c478bd9Sstevel@tonic-gate 		/*
212*7c478bd9Sstevel@tonic-gate 		 * Allocate and get the per instance soft state structure.
213*7c478bd9Sstevel@tonic-gate 		 */
214*7c478bd9Sstevel@tonic-gate 		instance = ddi_get_instance(dip);
215*7c478bd9Sstevel@tonic-gate 		if (alloc_upa64s_soft_state(instance) != DDI_SUCCESS) {
216*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s%d: can't allocate upa64s state",
217*7c478bd9Sstevel@tonic-gate 			    ddi_get_name(dip), instance);
218*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
219*7c478bd9Sstevel@tonic-gate 		}
220*7c478bd9Sstevel@tonic-gate 		upa64s_p = get_upa64s_soft_state(instance);
221*7c478bd9Sstevel@tonic-gate 		upa64s_p->dip = dip;
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate 		/*
224*7c478bd9Sstevel@tonic-gate 		 * Get key properties of the bridge node.
225*7c478bd9Sstevel@tonic-gate 		 */
226*7c478bd9Sstevel@tonic-gate 		if (get_properties(upa64s_p, dip) != DDI_SUCCESS)
227*7c478bd9Sstevel@tonic-gate 			goto fail;
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate 		/*
230*7c478bd9Sstevel@tonic-gate 		 * Create "pm-components" property for the purpose of
231*7c478bd9Sstevel@tonic-gate 		 * doing Power Management.
232*7c478bd9Sstevel@tonic-gate 		 */
233*7c478bd9Sstevel@tonic-gate 		if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip,
234*7c478bd9Sstevel@tonic-gate 		    "pm-components", pmc, ((sizeof (pmc)/sizeof (char *)) - 1))
235*7c478bd9Sstevel@tonic-gate 		    != DDI_PROP_SUCCESS) {
236*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s%d: failed to create pm-components "
237*7c478bd9Sstevel@tonic-gate 			    "property.", ddi_get_name(dip), instance);
238*7c478bd9Sstevel@tonic-gate 			goto fail;
239*7c478bd9Sstevel@tonic-gate 		}
240*7c478bd9Sstevel@tonic-gate 
241*7c478bd9Sstevel@tonic-gate 		/* Map in the UPA's registers */
242*7c478bd9Sstevel@tonic-gate 		attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
243*7c478bd9Sstevel@tonic-gate 		attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
244*7c478bd9Sstevel@tonic-gate 		attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
245*7c478bd9Sstevel@tonic-gate 		if (ddi_regs_map_setup(dip, 0,
246*7c478bd9Sstevel@tonic-gate 		    (caddr_t *)&upa64s_p->config_base, 0, 0, &attr,
247*7c478bd9Sstevel@tonic-gate 		    &upa64s_p->config_base_ah) != DDI_SUCCESS) {
248*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s%d: failed to map reg1.",
249*7c478bd9Sstevel@tonic-gate 			    ddi_get_name(dip), instance);
250*7c478bd9Sstevel@tonic-gate 			goto fail;
251*7c478bd9Sstevel@tonic-gate 		}
252*7c478bd9Sstevel@tonic-gate 
253*7c478bd9Sstevel@tonic-gate 		upa64s_p->upa0_config = (uint64_t *)(upa64s_p->config_base +
254*7c478bd9Sstevel@tonic-gate 		    UPA64S_UPA0_CONFIG_OFFSET);
255*7c478bd9Sstevel@tonic-gate 		upa64s_p->upa1_config = (uint64_t *)(upa64s_p->config_base +
256*7c478bd9Sstevel@tonic-gate 		    UPA64S_UPA1_CONFIG_OFFSET);
257*7c478bd9Sstevel@tonic-gate 		upa64s_p->if_config = (uint64_t *)(upa64s_p->config_base +
258*7c478bd9Sstevel@tonic-gate 		    UPA64S_IF_CONFIG_OFFSET);
259*7c478bd9Sstevel@tonic-gate 		upa64s_p->estar = (uint64_t *)(upa64s_p->config_base +
260*7c478bd9Sstevel@tonic-gate 		    UPA64S_ESTAR_OFFSET);
261*7c478bd9Sstevel@tonic-gate 
262*7c478bd9Sstevel@tonic-gate 		if (ddi_regs_map_setup(dip, 1, (caddr_t *)&upa64s_p->imr[0],
263*7c478bd9Sstevel@tonic-gate 		    0, 0, &attr, &upa64s_p->imr_ah[0]) != DDI_SUCCESS) {
264*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s%d: failed to map reg2.",
265*7c478bd9Sstevel@tonic-gate 			    ddi_get_name(dip), instance);
266*7c478bd9Sstevel@tonic-gate 			goto fail1;
267*7c478bd9Sstevel@tonic-gate 		}
268*7c478bd9Sstevel@tonic-gate 
269*7c478bd9Sstevel@tonic-gate 		if (ddi_regs_map_setup(dip, 2, (caddr_t *)&upa64s_p->imr[1],
270*7c478bd9Sstevel@tonic-gate 		    0, 0, &attr, &upa64s_p->imr_ah[1]) != DDI_SUCCESS) {
271*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s%d: failed to map reg3.",
272*7c478bd9Sstevel@tonic-gate 			    ddi_get_name(dip), instance);
273*7c478bd9Sstevel@tonic-gate 			goto fail2;
274*7c478bd9Sstevel@tonic-gate 		}
275*7c478bd9Sstevel@tonic-gate 
276*7c478bd9Sstevel@tonic-gate 		/*
277*7c478bd9Sstevel@tonic-gate 		 * Power level of a component is unknown at attach time.
278*7c478bd9Sstevel@tonic-gate 		 * Bring the power level to what is needed for normal operation.
279*7c478bd9Sstevel@tonic-gate 		 */
280*7c478bd9Sstevel@tonic-gate 		upa64s_p->power_level = UPA64S_PM_UNKNOWN;
281*7c478bd9Sstevel@tonic-gate 		if (pm_raise_power(dip, UPA64S_PM_COMP, UPA64S_PM_NORMOP) !=
282*7c478bd9Sstevel@tonic-gate 		    DDI_SUCCESS) {
283*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s%d: failed to raise the power.",
284*7c478bd9Sstevel@tonic-gate 			    ddi_get_name(dip), instance);
285*7c478bd9Sstevel@tonic-gate 			goto fail3;
286*7c478bd9Sstevel@tonic-gate 		}
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate 		intr_dist_add(upa64s_intrdist, dip);
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate 		ddi_report_dev(dip);
291*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
292*7c478bd9Sstevel@tonic-gate 
293*7c478bd9Sstevel@tonic-gate 	case DDI_RESUME:
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate 		upa64s_p = get_upa64s_soft_state(ddi_get_instance(dip));
296*7c478bd9Sstevel@tonic-gate 		DBG(D_ATTACH, dip, "DDI_RESUME\n");
297*7c478bd9Sstevel@tonic-gate 		restore_state(upa64s_p);
298*7c478bd9Sstevel@tonic-gate 
299*7c478bd9Sstevel@tonic-gate 		/*
300*7c478bd9Sstevel@tonic-gate 		 * Power level of a component is unknown at resume time.
301*7c478bd9Sstevel@tonic-gate 		 * Bring the power level to what it was before suspend.
302*7c478bd9Sstevel@tonic-gate 		 */
303*7c478bd9Sstevel@tonic-gate 		upa64s_p->power_level = UPA64S_PM_UNKNOWN;
304*7c478bd9Sstevel@tonic-gate 		if (pm_raise_power(dip, UPA64S_PM_COMP,
305*7c478bd9Sstevel@tonic-gate 		    upa64s_p->saved_power_level) != DDI_SUCCESS)
306*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s%d: failed to change power level "
307*7c478bd9Sstevel@tonic-gate 			    "during resume!", ddi_get_name(dip), instance);
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 	default:
312*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
313*7c478bd9Sstevel@tonic-gate 	}
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate fail3:
316*7c478bd9Sstevel@tonic-gate 	ddi_regs_map_free(&upa64s_p->imr_ah[1]);
317*7c478bd9Sstevel@tonic-gate fail2:
318*7c478bd9Sstevel@tonic-gate 	ddi_regs_map_free(&upa64s_p->imr_ah[0]);
319*7c478bd9Sstevel@tonic-gate fail1:
320*7c478bd9Sstevel@tonic-gate 	ddi_regs_map_free(&upa64s_p->config_base_ah);
321*7c478bd9Sstevel@tonic-gate fail:
322*7c478bd9Sstevel@tonic-gate 	free_upa64s_soft_state(instance);
323*7c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
324*7c478bd9Sstevel@tonic-gate }
325*7c478bd9Sstevel@tonic-gate 
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate /*
328*7c478bd9Sstevel@tonic-gate  * detach entry point:
329*7c478bd9Sstevel@tonic-gate  */
330*7c478bd9Sstevel@tonic-gate static int
331*7c478bd9Sstevel@tonic-gate upa64s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
332*7c478bd9Sstevel@tonic-gate {
333*7c478bd9Sstevel@tonic-gate 	int instance = ddi_get_instance(dip);
334*7c478bd9Sstevel@tonic-gate 	upa64s_devstate_t *upa64s_p = get_upa64s_soft_state(instance);
335*7c478bd9Sstevel@tonic-gate 
336*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
337*7c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 		DBG(D_DETACH, dip, "DDI_DETACH\n");
340*7c478bd9Sstevel@tonic-gate 
341*7c478bd9Sstevel@tonic-gate 		/*
342*7c478bd9Sstevel@tonic-gate 		 * Power down the device.
343*7c478bd9Sstevel@tonic-gate 		 */
344*7c478bd9Sstevel@tonic-gate 		if (pm_lower_power(dip, UPA64S_PM_COMP, UPA64S_PM_RESET) !=
345*7c478bd9Sstevel@tonic-gate 		    DDI_SUCCESS)
346*7c478bd9Sstevel@tonic-gate 			DBG(D_DETACH, dip, "failed to power off!\n");
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate 		intr_dist_rem(upa64s_intrdist, dip);
349*7c478bd9Sstevel@tonic-gate 
350*7c478bd9Sstevel@tonic-gate 		ddi_regs_map_free(&upa64s_p->config_base_ah);
351*7c478bd9Sstevel@tonic-gate 		ddi_regs_map_free(&upa64s_p->imr_ah[0]);
352*7c478bd9Sstevel@tonic-gate 		ddi_regs_map_free(&upa64s_p->imr_ah[1]);
353*7c478bd9Sstevel@tonic-gate 		free_upa64s_soft_state(instance);
354*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
355*7c478bd9Sstevel@tonic-gate 
356*7c478bd9Sstevel@tonic-gate 	case DDI_SUSPEND:
357*7c478bd9Sstevel@tonic-gate 
358*7c478bd9Sstevel@tonic-gate 		DBG(D_DETACH, dip, "DDI_SUSPEND\n");
359*7c478bd9Sstevel@tonic-gate 		save_state(upa64s_p);
360*7c478bd9Sstevel@tonic-gate 		upa64s_p->saved_power_level = upa64s_p->power_level;
361*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
362*7c478bd9Sstevel@tonic-gate 	}
363*7c478bd9Sstevel@tonic-gate 
364*7c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
365*7c478bd9Sstevel@tonic-gate }
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate /*
368*7c478bd9Sstevel@tonic-gate  * power entry point:
369*7c478bd9Sstevel@tonic-gate  *
370*7c478bd9Sstevel@tonic-gate  * This entry point is called by Power Management framework to
371*7c478bd9Sstevel@tonic-gate  * reset upa bus and slow down/speed up the upa interface of
372*7c478bd9Sstevel@tonic-gate  * Schizo chip.
373*7c478bd9Sstevel@tonic-gate  */
374*7c478bd9Sstevel@tonic-gate static int
375*7c478bd9Sstevel@tonic-gate upa64s_power(dev_info_t *dip, int component, int level)
376*7c478bd9Sstevel@tonic-gate {
377*7c478bd9Sstevel@tonic-gate 	int instance = ddi_get_instance(dip);
378*7c478bd9Sstevel@tonic-gate 	upa64s_devstate_t *upa64s_p = get_upa64s_soft_state(instance);
379*7c478bd9Sstevel@tonic-gate 	volatile uint64_t uint64_data;
380*7c478bd9Sstevel@tonic-gate 
381*7c478bd9Sstevel@tonic-gate 	DBG2(D_POWER, dip, "component=%d, level=%d\n", component, level);
382*7c478bd9Sstevel@tonic-gate 	if (component != UPA64S_PM_COMP ||
383*7c478bd9Sstevel@tonic-gate 	    level < UPA64S_PM_RESET || level > UPA64S_PM_NORMOP)
384*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate 	/*
387*7c478bd9Sstevel@tonic-gate 	 * We can't set the hardware to the state that it is
388*7c478bd9Sstevel@tonic-gate 	 * already in.  So if the power state is not known, inquire the
389*7c478bd9Sstevel@tonic-gate 	 * state of the hardware.  If it is already in that state,
390*7c478bd9Sstevel@tonic-gate 	 * record and return, otherwise make the state change.
391*7c478bd9Sstevel@tonic-gate 	 */
392*7c478bd9Sstevel@tonic-gate 	if (upa64s_p->power_level == UPA64S_PM_UNKNOWN) {
393*7c478bd9Sstevel@tonic-gate 		uint64_data = ddi_get64(upa64s_p->config_base_ah,
394*7c478bd9Sstevel@tonic-gate 		    upa64s_p->if_config);
395*7c478bd9Sstevel@tonic-gate 		if ((level == UPA64S_PM_RESET &&
396*7c478bd9Sstevel@tonic-gate 		    uint64_data == UPA64S_NOT_POK_RST_L) ||
397*7c478bd9Sstevel@tonic-gate 		    (level == UPA64S_PM_NORMOP &&
398*7c478bd9Sstevel@tonic-gate 		    uint64_data == UPA64S_POK_NOT_RST_L)) {
399*7c478bd9Sstevel@tonic-gate 			upa64s_p->power_level = level;
400*7c478bd9Sstevel@tonic-gate 			return (DDI_SUCCESS);
401*7c478bd9Sstevel@tonic-gate 		}
402*7c478bd9Sstevel@tonic-gate 	}
403*7c478bd9Sstevel@tonic-gate 
404*7c478bd9Sstevel@tonic-gate 	if (level == upa64s_p->power_level) {
405*7c478bd9Sstevel@tonic-gate 		DBG1(D_POWER, dip, "device is already at power level %d\n",
406*7c478bd9Sstevel@tonic-gate 		    level);
407*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
408*7c478bd9Sstevel@tonic-gate 	}
409*7c478bd9Sstevel@tonic-gate 
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate 	if (level == UPA64S_PM_RESET) {
412*7c478bd9Sstevel@tonic-gate 		/*
413*7c478bd9Sstevel@tonic-gate 		 * Assert UPA64S_RESET
414*7c478bd9Sstevel@tonic-gate 		 */
415*7c478bd9Sstevel@tonic-gate 		ddi_put64(upa64s_p->config_base_ah, upa64s_p->if_config,
416*7c478bd9Sstevel@tonic-gate 		    UPA64S_POK_RST_L);
417*7c478bd9Sstevel@tonic-gate 
418*7c478bd9Sstevel@tonic-gate 		/*
419*7c478bd9Sstevel@tonic-gate 		 * Deassert UPA64S_POK.  Flush the store buffer.
420*7c478bd9Sstevel@tonic-gate 		 */
421*7c478bd9Sstevel@tonic-gate 		ddi_put64(upa64s_p->config_base_ah, upa64s_p->if_config,
422*7c478bd9Sstevel@tonic-gate 		    UPA64S_NOT_POK_RST_L);
423*7c478bd9Sstevel@tonic-gate 		uint64_data = ddi_get64(upa64s_p->config_base_ah,
424*7c478bd9Sstevel@tonic-gate 		    upa64s_p->if_config);
425*7c478bd9Sstevel@tonic-gate 
426*7c478bd9Sstevel@tonic-gate 		/*
427*7c478bd9Sstevel@tonic-gate 		 * Internal UPA clock to 1/2 speed
428*7c478bd9Sstevel@tonic-gate 		 */
429*7c478bd9Sstevel@tonic-gate 		ddi_put64(upa64s_p->config_base_ah, upa64s_p->estar,
430*7c478bd9Sstevel@tonic-gate 		    UPA64S_1_2_SPEED);
431*7c478bd9Sstevel@tonic-gate 
432*7c478bd9Sstevel@tonic-gate 		/*
433*7c478bd9Sstevel@tonic-gate 		 * Internal UPA clock to 1/64 speed.  Flush the store buffer.
434*7c478bd9Sstevel@tonic-gate 		 */
435*7c478bd9Sstevel@tonic-gate 		ddi_put64(upa64s_p->config_base_ah, upa64s_p->estar,
436*7c478bd9Sstevel@tonic-gate 		    UPA64S_1_64_SPEED);
437*7c478bd9Sstevel@tonic-gate 		uint64_data = ddi_get64(upa64s_p->config_base_ah,
438*7c478bd9Sstevel@tonic-gate 		    upa64s_p->estar);
439*7c478bd9Sstevel@tonic-gate 	} else {
440*7c478bd9Sstevel@tonic-gate 		/*
441*7c478bd9Sstevel@tonic-gate 		 * Internal UPA clock to 1/2 speed
442*7c478bd9Sstevel@tonic-gate 		 */
443*7c478bd9Sstevel@tonic-gate 		ddi_put64(upa64s_p->config_base_ah, upa64s_p->estar,
444*7c478bd9Sstevel@tonic-gate 		    UPA64S_1_2_SPEED);
445*7c478bd9Sstevel@tonic-gate 
446*7c478bd9Sstevel@tonic-gate 		/*
447*7c478bd9Sstevel@tonic-gate 		 * Internal UPA clock to full speed.  Flush the store buffer.
448*7c478bd9Sstevel@tonic-gate 		 */
449*7c478bd9Sstevel@tonic-gate 		ddi_put64(upa64s_p->config_base_ah, upa64s_p->estar,
450*7c478bd9Sstevel@tonic-gate 		    UPA64S_FULL_SPEED);
451*7c478bd9Sstevel@tonic-gate 		uint64_data = ddi_get64(upa64s_p->config_base_ah,
452*7c478bd9Sstevel@tonic-gate 		    upa64s_p->estar);
453*7c478bd9Sstevel@tonic-gate 
454*7c478bd9Sstevel@tonic-gate 		/*
455*7c478bd9Sstevel@tonic-gate 		 * Assert UPA64S_POK.  Flush the store buffer before
456*7c478bd9Sstevel@tonic-gate 		 * the wait delay.
457*7c478bd9Sstevel@tonic-gate 		 */
458*7c478bd9Sstevel@tonic-gate 		ddi_put64(upa64s_p->config_base_ah, upa64s_p->if_config,
459*7c478bd9Sstevel@tonic-gate 		    UPA64S_POK_RST_L);
460*7c478bd9Sstevel@tonic-gate 		uint64_data = ddi_get64(upa64s_p->config_base_ah,
461*7c478bd9Sstevel@tonic-gate 		    upa64s_p->if_config);
462*7c478bd9Sstevel@tonic-gate 
463*7c478bd9Sstevel@tonic-gate 		/*
464*7c478bd9Sstevel@tonic-gate 		 * Delay 20 milliseconds for the signals to settle down.
465*7c478bd9Sstevel@tonic-gate 		 */
466*7c478bd9Sstevel@tonic-gate 		delay(drv_usectohz(20*1000));
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate 		/*
469*7c478bd9Sstevel@tonic-gate 		 * Deassert UPA64S_RESET.  Flush the store buffer.
470*7c478bd9Sstevel@tonic-gate 		 */
471*7c478bd9Sstevel@tonic-gate 		ddi_put64(upa64s_p->config_base_ah, upa64s_p->if_config,
472*7c478bd9Sstevel@tonic-gate 		    UPA64S_POK_NOT_RST_L);
473*7c478bd9Sstevel@tonic-gate 		uint64_data = ddi_get64(upa64s_p->config_base_ah,
474*7c478bd9Sstevel@tonic-gate 		    upa64s_p->if_config);
475*7c478bd9Sstevel@tonic-gate 	}
476*7c478bd9Sstevel@tonic-gate 	upa64s_p->power_level = level;
477*7c478bd9Sstevel@tonic-gate 
478*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
479*7c478bd9Sstevel@tonic-gate }
480*7c478bd9Sstevel@tonic-gate 
481*7c478bd9Sstevel@tonic-gate /* bus driver entry points */
482*7c478bd9Sstevel@tonic-gate 
483*7c478bd9Sstevel@tonic-gate /*
484*7c478bd9Sstevel@tonic-gate  * bus map entry point:
485*7c478bd9Sstevel@tonic-gate  *
486*7c478bd9Sstevel@tonic-gate  * 	if map request is for an rnumber
487*7c478bd9Sstevel@tonic-gate  *		get the corresponding regspec from device node
488*7c478bd9Sstevel@tonic-gate  * 	build a new regspec in our parent's format
489*7c478bd9Sstevel@tonic-gate  *	build a new map_req with the new regspec
490*7c478bd9Sstevel@tonic-gate  *	call up the tree to complete the mapping
491*7c478bd9Sstevel@tonic-gate  */
492*7c478bd9Sstevel@tonic-gate static int
493*7c478bd9Sstevel@tonic-gate upa64s_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
494*7c478bd9Sstevel@tonic-gate     off_t off, off_t len, caddr_t *addrp)
495*7c478bd9Sstevel@tonic-gate {
496*7c478bd9Sstevel@tonic-gate 	struct regspec regspec;
497*7c478bd9Sstevel@tonic-gate 	ddi_map_req_t p_map_request;
498*7c478bd9Sstevel@tonic-gate 	int rnumber, rval;
499*7c478bd9Sstevel@tonic-gate 
500*7c478bd9Sstevel@tonic-gate 	DBG4(D_MAP, dip, "upa64s_map() mp=%x.%x addrp=%x.%08x\n",
501*7c478bd9Sstevel@tonic-gate 	    HI32(mp), LO32(mp), HI32(addrp), LO32(addrp));
502*7c478bd9Sstevel@tonic-gate 
503*7c478bd9Sstevel@tonic-gate 	/*
504*7c478bd9Sstevel@tonic-gate 	 * User level mappings are not supported yet.
505*7c478bd9Sstevel@tonic-gate 	 */
506*7c478bd9Sstevel@tonic-gate 	if (mp->map_flags & DDI_MF_USER_MAPPING) {
507*7c478bd9Sstevel@tonic-gate 		DBG2(D_MAP, dip, "rdip=%s%d: no user level mappings yet!\n",
508*7c478bd9Sstevel@tonic-gate 		    ddi_get_name(rdip), ddi_get_instance(rdip));
509*7c478bd9Sstevel@tonic-gate 		return (DDI_ME_UNIMPLEMENTED);
510*7c478bd9Sstevel@tonic-gate 	}
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate 	/*
513*7c478bd9Sstevel@tonic-gate 	 * Now handle the mapping according to its type.
514*7c478bd9Sstevel@tonic-gate 	 */
515*7c478bd9Sstevel@tonic-gate 	switch (mp->map_type) {
516*7c478bd9Sstevel@tonic-gate 	case DDI_MT_REGSPEC:
517*7c478bd9Sstevel@tonic-gate 
518*7c478bd9Sstevel@tonic-gate 		/*
519*7c478bd9Sstevel@tonic-gate 		 * We assume the register specification is in PCI format.
520*7c478bd9Sstevel@tonic-gate 		 * We must convert it into a regspec of our parent's
521*7c478bd9Sstevel@tonic-gate 		 * and pass the request to our parent.
522*7c478bd9Sstevel@tonic-gate 		 */
523*7c478bd9Sstevel@tonic-gate 		DBG3(D_MAP, dip, "rdip=%s%d: REGSPEC - handlep=%x\n",
524*7c478bd9Sstevel@tonic-gate 		    ddi_get_name(rdip), ddi_get_instance(rdip),
525*7c478bd9Sstevel@tonic-gate 		    mp->map_handlep);
526*7c478bd9Sstevel@tonic-gate 		rval = xlate_reg_prop(dip, (upa64s_regspec_t *)mp->map_obj.rp,
527*7c478bd9Sstevel@tonic-gate 		    off, len, &regspec);
528*7c478bd9Sstevel@tonic-gate 		break;
529*7c478bd9Sstevel@tonic-gate 
530*7c478bd9Sstevel@tonic-gate 	case DDI_MT_RNUMBER:
531*7c478bd9Sstevel@tonic-gate 
532*7c478bd9Sstevel@tonic-gate 		/*
533*7c478bd9Sstevel@tonic-gate 		 * Get the "reg" property from the device node and convert
534*7c478bd9Sstevel@tonic-gate 		 * it to our parent's format.
535*7c478bd9Sstevel@tonic-gate 		 */
536*7c478bd9Sstevel@tonic-gate 		DBG4(D_MAP, dip, "rdip=%s%d: rnumber=%x handlep=%x\n",
537*7c478bd9Sstevel@tonic-gate 		    ddi_get_name(rdip), ddi_get_instance(rdip),
538*7c478bd9Sstevel@tonic-gate 		    mp->map_obj.rnumber, mp->map_handlep);
539*7c478bd9Sstevel@tonic-gate 		rnumber = mp->map_obj.rnumber;
540*7c478bd9Sstevel@tonic-gate 		if (rnumber < 0)
541*7c478bd9Sstevel@tonic-gate 			return (DDI_ME_RNUMBER_RANGE);
542*7c478bd9Sstevel@tonic-gate 		rval = get_reg_set(dip, rdip,  rnumber, off, len, &regspec);
543*7c478bd9Sstevel@tonic-gate 		break;
544*7c478bd9Sstevel@tonic-gate 
545*7c478bd9Sstevel@tonic-gate 	default:
546*7c478bd9Sstevel@tonic-gate 		return (DDI_ME_INVAL);
547*7c478bd9Sstevel@tonic-gate 
548*7c478bd9Sstevel@tonic-gate 	}
549*7c478bd9Sstevel@tonic-gate 	if (rval != DDI_SUCCESS) {
550*7c478bd9Sstevel@tonic-gate 		DBG(D_MAP, dip, "failed on regspec\n\n");
551*7c478bd9Sstevel@tonic-gate 		return (rval);
552*7c478bd9Sstevel@tonic-gate 	}
553*7c478bd9Sstevel@tonic-gate 
554*7c478bd9Sstevel@tonic-gate 	/*
555*7c478bd9Sstevel@tonic-gate 	 * Now we have a copy of the upa64s regspec converted to our parent's
556*7c478bd9Sstevel@tonic-gate 	 * format.  Build a new map request based on this regspec and pass
557*7c478bd9Sstevel@tonic-gate 	 * it to our parent.
558*7c478bd9Sstevel@tonic-gate 	 */
559*7c478bd9Sstevel@tonic-gate 	p_map_request = *mp;
560*7c478bd9Sstevel@tonic-gate 	p_map_request.map_type = DDI_MT_REGSPEC;
561*7c478bd9Sstevel@tonic-gate 	p_map_request.map_obj.rp = &regspec;
562*7c478bd9Sstevel@tonic-gate 	rval = ddi_map(dip, &p_map_request, 0, 0, addrp);
563*7c478bd9Sstevel@tonic-gate 	DBG3(D_MAP, dip, "ddi_map returns: rval=%x addrp=%x.%08x\n\n",
564*7c478bd9Sstevel@tonic-gate 	    rval, HI32(*addrp), LO32(*addrp));
565*7c478bd9Sstevel@tonic-gate 	return (rval);
566*7c478bd9Sstevel@tonic-gate }
567*7c478bd9Sstevel@tonic-gate 
568*7c478bd9Sstevel@tonic-gate /*
569*7c478bd9Sstevel@tonic-gate  * Translate the UPA devices interrupt property.  This is the only case I
570*7c478bd9Sstevel@tonic-gate  * know of where the interrupts property is meaningless.  As a result, we
571*7c478bd9Sstevel@tonic-gate  * just use UPA_BASE_INO as our interrupt value and add to it the upa port id.
572*7c478bd9Sstevel@tonic-gate  * UPA portid is returned too.
573*7c478bd9Sstevel@tonic-gate  */
574*7c478bd9Sstevel@tonic-gate #define	UPA_BASE_INO	0x2a
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate static int
577*7c478bd9Sstevel@tonic-gate upa64s_xlate_intr(dev_info_t *rdip, int32_t safariport, ddi_ispec_t *ispecp)
578*7c478bd9Sstevel@tonic-gate {
579*7c478bd9Sstevel@tonic-gate 	uint32_t ino = UPA_BASE_INO;
580*7c478bd9Sstevel@tonic-gate 	int32_t portid;
581*7c478bd9Sstevel@tonic-gate 
582*7c478bd9Sstevel@tonic-gate 	/* Clear the ffb's interrupts property, it's meaningless */
583*7c478bd9Sstevel@tonic-gate 	*ispecp->is_intr = 0;
584*7c478bd9Sstevel@tonic-gate 
585*7c478bd9Sstevel@tonic-gate 	if ((portid = ddi_getprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
586*7c478bd9Sstevel@tonic-gate 	    "upa-portid", -1)) == -1)
587*7c478bd9Sstevel@tonic-gate 		return (-1);
588*7c478bd9Sstevel@tonic-gate 
589*7c478bd9Sstevel@tonic-gate 	ino += portid;
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate 	*ispecp->is_intr = UPA64S_MAKE_MONDO(safariport, ino);
592*7c478bd9Sstevel@tonic-gate 
593*7c478bd9Sstevel@tonic-gate 	DBG5(D_A_ISPEC, rdip, "upa64s_xlate_intr: rdip=%s%d: upa portid %d "
594*7c478bd9Sstevel@tonic-gate 	    "ino=%x mondo 0x%x\n", ddi_get_name(rdip), ddi_get_instance(rdip),
595*7c478bd9Sstevel@tonic-gate 	    portid, ino, *ispecp->is_intr);
596*7c478bd9Sstevel@tonic-gate 
597*7c478bd9Sstevel@tonic-gate 	return (portid);
598*7c478bd9Sstevel@tonic-gate }
599*7c478bd9Sstevel@tonic-gate 
600*7c478bd9Sstevel@tonic-gate /*
601*7c478bd9Sstevel@tonic-gate  * bus add intrspec entry point:
602*7c478bd9Sstevel@tonic-gate  */
603*7c478bd9Sstevel@tonic-gate static int
604*7c478bd9Sstevel@tonic-gate upa64s_add_intr_impl(dev_info_t *dip, dev_info_t *rdip,
605*7c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp)
606*7c478bd9Sstevel@tonic-gate {
607*7c478bd9Sstevel@tonic-gate 	int upaport, instance = ddi_get_instance(dip);
608*7c478bd9Sstevel@tonic-gate 	upa64s_devstate_t *upa64s_p = get_upa64s_soft_state(instance);
609*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
610*7c478bd9Sstevel@tonic-gate 	uint_t (*int_handler)(caddr_t, caddr_t) = hdlp->ih_cb_func;
611*7c478bd9Sstevel@tonic-gate 	caddr_t int_handler_arg1 = hdlp->ih_cb_arg1;
612*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
613*7c478bd9Sstevel@tonic-gate 	ddi_ispec_t *ip = (ddi_ispec_t *)hdlp->ih_private;
614*7c478bd9Sstevel@tonic-gate 	uint_t cpu_id;
615*7c478bd9Sstevel@tonic-gate 	volatile uint64_t imr_data;
616*7c478bd9Sstevel@tonic-gate 
617*7c478bd9Sstevel@tonic-gate 	upaport = upa64s_xlate_intr(rdip, upa64s_p->safari_id, ip);
618*7c478bd9Sstevel@tonic-gate 
619*7c478bd9Sstevel@tonic-gate 	if (*ip->is_intr == 0)
620*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
621*7c478bd9Sstevel@tonic-gate 
622*7c478bd9Sstevel@tonic-gate 	DBG3(D_A_ISPEC, dip,
623*7c478bd9Sstevel@tonic-gate 	    "rdip=%s%d - IDDI_INTR_TYPE_NORMAL, mondo=%x\n",
624*7c478bd9Sstevel@tonic-gate 	    ddi_get_name(rdip), ddi_get_instance(rdip), *ip->is_intr);
625*7c478bd9Sstevel@tonic-gate 
626*7c478bd9Sstevel@tonic-gate 	/*
627*7c478bd9Sstevel@tonic-gate 	 * Make sure an interrupt handler isn't already installed.
628*7c478bd9Sstevel@tonic-gate 	 */
629*7c478bd9Sstevel@tonic-gate 	if (upa64s_p->ino_state[upaport] != INO_FREE) {
630*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
631*7c478bd9Sstevel@tonic-gate 	}
632*7c478bd9Sstevel@tonic-gate 
633*7c478bd9Sstevel@tonic-gate 	/*
634*7c478bd9Sstevel@tonic-gate 	 * Install the handler in the system table.
635*7c478bd9Sstevel@tonic-gate 	 */
636*7c478bd9Sstevel@tonic-gate #ifdef	DEBUG
637*7c478bd9Sstevel@tonic-gate 	DBG2(D_A_ISPEC, dip, "i_ddi_add_ivintr: hdlr=%p arg=%p\n",
638*7c478bd9Sstevel@tonic-gate 	    int_handler, int_handler_arg1);
639*7c478bd9Sstevel@tonic-gate #endif
640*7c478bd9Sstevel@tonic-gate 	hdlp->ih_vector = *ip->is_intr;
641*7c478bd9Sstevel@tonic-gate 	if (i_ddi_add_ivintr(hdlp) != DDI_SUCCESS)
642*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
643*7c478bd9Sstevel@tonic-gate 
644*7c478bd9Sstevel@tonic-gate 	cpu_id = intr_dist_cpuid();
645*7c478bd9Sstevel@tonic-gate 
646*7c478bd9Sstevel@tonic-gate 	/*
647*7c478bd9Sstevel@tonic-gate 	 * Enable the interrupt through its interrupt mapping register.
648*7c478bd9Sstevel@tonic-gate 	 */
649*7c478bd9Sstevel@tonic-gate 	imr_data = UPA64S_CPUID_TO_IMR(cpu_id);
650*7c478bd9Sstevel@tonic-gate 	imr_data = UPA64S_GET_MAP_REG(hdlp->ih_vector, imr_data);
651*7c478bd9Sstevel@tonic-gate 
652*7c478bd9Sstevel@tonic-gate 	DBG4(D_A_ISPEC, dip, "IMR [upaport=%d mapping reg 0x%p] = %x.%x\n",
653*7c478bd9Sstevel@tonic-gate 	    upaport, upa64s_p->imr[upaport], HI32(imr_data), LO32(imr_data));
654*7c478bd9Sstevel@tonic-gate 
655*7c478bd9Sstevel@tonic-gate 	ddi_put64(upa64s_p->imr_ah[upaport], upa64s_p->imr[upaport], imr_data);
656*7c478bd9Sstevel@tonic-gate 	/* Read the data back to flush store buffers. */
657*7c478bd9Sstevel@tonic-gate 	imr_data = ddi_get64(upa64s_p->imr_ah[upaport], upa64s_p->imr[upaport]);
658*7c478bd9Sstevel@tonic-gate 	upa64s_p->ino_state[upaport] = INO_INUSE;
659*7c478bd9Sstevel@tonic-gate 
660*7c478bd9Sstevel@tonic-gate 	DBG(D_A_ISPEC, dip, "add_intrspec success!\n");
661*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
662*7c478bd9Sstevel@tonic-gate }
663*7c478bd9Sstevel@tonic-gate 
664*7c478bd9Sstevel@tonic-gate 
665*7c478bd9Sstevel@tonic-gate /*
666*7c478bd9Sstevel@tonic-gate  * bus remove intrspec entry point
667*7c478bd9Sstevel@tonic-gate  */
668*7c478bd9Sstevel@tonic-gate static int
669*7c478bd9Sstevel@tonic-gate upa64s_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip,
670*7c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp)
671*7c478bd9Sstevel@tonic-gate {
672*7c478bd9Sstevel@tonic-gate 	upa64s_devstate_t *upa64s_p =
673*7c478bd9Sstevel@tonic-gate 	    get_upa64s_soft_state(ddi_get_instance(dip));
674*7c478bd9Sstevel@tonic-gate 	ddi_ispec_t *ip = (ddi_ispec_t *)hdlp->ih_private;
675*7c478bd9Sstevel@tonic-gate 	int upaport;
676*7c478bd9Sstevel@tonic-gate #ifndef lint
677*7c478bd9Sstevel@tonic-gate 	volatile uint64_t tmp;
678*7c478bd9Sstevel@tonic-gate #endif
679*7c478bd9Sstevel@tonic-gate 
680*7c478bd9Sstevel@tonic-gate 	/*
681*7c478bd9Sstevel@tonic-gate 	 * Make sure the mondo is valid.
682*7c478bd9Sstevel@tonic-gate 	 */
683*7c478bd9Sstevel@tonic-gate 	upaport = upa64s_xlate_intr(rdip, upa64s_p->safari_id, ip);
684*7c478bd9Sstevel@tonic-gate 
685*7c478bd9Sstevel@tonic-gate 	if (*ip->is_intr == 0)
686*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
687*7c478bd9Sstevel@tonic-gate 
688*7c478bd9Sstevel@tonic-gate 	DBG3(D_R_ISPEC, dip,
689*7c478bd9Sstevel@tonic-gate 	    "rdip=%s%d - IDDI_INTR_TYPE_NORMAL, mondo=%x\n",
690*7c478bd9Sstevel@tonic-gate 	    ddi_get_name(rdip), ddi_get_instance(rdip), *ip->is_intr);
691*7c478bd9Sstevel@tonic-gate 
692*7c478bd9Sstevel@tonic-gate 	if (upa64s_p->ino_state[upaport] != INO_INUSE) {
693*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
694*7c478bd9Sstevel@tonic-gate 	}
695*7c478bd9Sstevel@tonic-gate 
696*7c478bd9Sstevel@tonic-gate 	/* Call up to our parent to handle the removal */
697*7c478bd9Sstevel@tonic-gate 	hdlp->ih_vector = *ip->is_intr;
698*7c478bd9Sstevel@tonic-gate 	i_ddi_rem_ivintr(hdlp);
699*7c478bd9Sstevel@tonic-gate 
700*7c478bd9Sstevel@tonic-gate 	ddi_put64(upa64s_p->imr_ah[upaport], upa64s_p->imr[upaport], 0);
701*7c478bd9Sstevel@tonic-gate #ifndef lint
702*7c478bd9Sstevel@tonic-gate 	/* Flush store buffers */
703*7c478bd9Sstevel@tonic-gate 	tmp = ddi_get64(upa64s_p->imr_ah[upaport], upa64s_p->imr[upaport]);
704*7c478bd9Sstevel@tonic-gate #endif
705*7c478bd9Sstevel@tonic-gate 
706*7c478bd9Sstevel@tonic-gate 	upa64s_p->ino_state[upaport] = INO_FREE;
707*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
708*7c478bd9Sstevel@tonic-gate }
709*7c478bd9Sstevel@tonic-gate 
710*7c478bd9Sstevel@tonic-gate 
711*7c478bd9Sstevel@tonic-gate /* new intr_ops structure */
712*7c478bd9Sstevel@tonic-gate static int
713*7c478bd9Sstevel@tonic-gate upa64_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
714*7c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result)
715*7c478bd9Sstevel@tonic-gate {
716*7c478bd9Sstevel@tonic-gate 	ddi_ispec_t	*ip = (ddi_ispec_t *)hdlp->ih_private;
717*7c478bd9Sstevel@tonic-gate 	int		ret = DDI_SUCCESS;
718*7c478bd9Sstevel@tonic-gate 
719*7c478bd9Sstevel@tonic-gate 	switch (intr_op) {
720*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_GETCAP:
721*7c478bd9Sstevel@tonic-gate 		*(int *)result = 0;
722*7c478bd9Sstevel@tonic-gate 		break;
723*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_ALLOC:
724*7c478bd9Sstevel@tonic-gate 		*(int *)result = hdlp->ih_scratch1;
725*7c478bd9Sstevel@tonic-gate 		break;
726*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_FREE:
727*7c478bd9Sstevel@tonic-gate 		break;
728*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_GETPRI:
729*7c478bd9Sstevel@tonic-gate 		/*
730*7c478bd9Sstevel@tonic-gate 		 * We only have slave UPA devices so force the PIL to 5.
731*7c478bd9Sstevel@tonic-gate 		 * this is done since all slave UPA devices have historically
732*7c478bd9Sstevel@tonic-gate 		 * had their PILs set to 5.  Only do it if the PIL is not
733*7c478bd9Sstevel@tonic-gate 		 * being preset.
734*7c478bd9Sstevel@tonic-gate 		 */
735*7c478bd9Sstevel@tonic-gate 		*(int *)result = ip->is_pil ? ip->is_pil : 5;
736*7c478bd9Sstevel@tonic-gate 		break;
737*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_SETPRI:
738*7c478bd9Sstevel@tonic-gate 		ip->is_pil = (*(int *)result);
739*7c478bd9Sstevel@tonic-gate 		break;
740*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_ADDISR:
741*7c478bd9Sstevel@tonic-gate 		hdlp->ih_vector = *ip->is_intr;
742*7c478bd9Sstevel@tonic-gate 
743*7c478bd9Sstevel@tonic-gate 		ret = upa64s_add_intr_impl(dip, rdip, hdlp);
744*7c478bd9Sstevel@tonic-gate 		break;
745*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_REMISR:
746*7c478bd9Sstevel@tonic-gate 		hdlp->ih_vector = *ip->is_intr;
747*7c478bd9Sstevel@tonic-gate 
748*7c478bd9Sstevel@tonic-gate 		ret = upa64s_remove_intr_impl(dip, rdip, hdlp);
749*7c478bd9Sstevel@tonic-gate 		break;
750*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_ENABLE:
751*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_DISABLE:
752*7c478bd9Sstevel@tonic-gate 		break;
753*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_NINTRS:
754*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_NAVAIL:
755*7c478bd9Sstevel@tonic-gate 		*(int *)result = i_ddi_get_nintrs(rdip);
756*7c478bd9Sstevel@tonic-gate 		break;
757*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_SETCAP:
758*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_SETMASK:
759*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_CLRMASK:
760*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_GETPENDING:
761*7c478bd9Sstevel@tonic-gate 		ret = DDI_ENOTSUP;
762*7c478bd9Sstevel@tonic-gate 		break;
763*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_SUPPORTED_TYPES:
764*7c478bd9Sstevel@tonic-gate 		/* only support fixed interrupts */
765*7c478bd9Sstevel@tonic-gate 		*(int *)result = i_ddi_get_nintrs(rdip) ?
766*7c478bd9Sstevel@tonic-gate 		    DDI_INTR_TYPE_FIXED : 0;
767*7c478bd9Sstevel@tonic-gate 		break;
768*7c478bd9Sstevel@tonic-gate 	default:
769*7c478bd9Sstevel@tonic-gate 		ret = i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result);
770*7c478bd9Sstevel@tonic-gate 		break;
771*7c478bd9Sstevel@tonic-gate 	}
772*7c478bd9Sstevel@tonic-gate 
773*7c478bd9Sstevel@tonic-gate 	return (ret);
774*7c478bd9Sstevel@tonic-gate }
775*7c478bd9Sstevel@tonic-gate 
776*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
777*7c478bd9Sstevel@tonic-gate uint_t upa64s_debug_flags = (uint_t)0;
778*7c478bd9Sstevel@tonic-gate 
779*7c478bd9Sstevel@tonic-gate extern void prom_printf(const char *, ...);
780*7c478bd9Sstevel@tonic-gate #endif
781*7c478bd9Sstevel@tonic-gate 
782*7c478bd9Sstevel@tonic-gate /*
783*7c478bd9Sstevel@tonic-gate  * control ops entry point:
784*7c478bd9Sstevel@tonic-gate  *
785*7c478bd9Sstevel@tonic-gate  * Requests handled completely:
786*7c478bd9Sstevel@tonic-gate  *	DDI_CTLOPS_INITCHILD	see init_child() for details
787*7c478bd9Sstevel@tonic-gate  *	DDI_CTLOPS_UNINITCHILD
788*7c478bd9Sstevel@tonic-gate  *	DDI_CTLOPS_REPORTDEV	see report_dev() for details
789*7c478bd9Sstevel@tonic-gate  *	DDI_CTLOPS_XLATE_INTRS	nothing to do
790*7c478bd9Sstevel@tonic-gate  *	DDI_CTLOPS_REGSIZE
791*7c478bd9Sstevel@tonic-gate  *	DDI_CTLOPS_NREGS
792*7c478bd9Sstevel@tonic-gate  *	DDI_CTLOPS_NINTRS
793*7c478bd9Sstevel@tonic-gate  *
794*7c478bd9Sstevel@tonic-gate  * All others passed to parent.
795*7c478bd9Sstevel@tonic-gate  */
796*7c478bd9Sstevel@tonic-gate static int
797*7c478bd9Sstevel@tonic-gate upa64s_ctlops(dev_info_t *dip, dev_info_t *rdip,
798*7c478bd9Sstevel@tonic-gate     ddi_ctl_enum_t op, void *arg, void *result)
799*7c478bd9Sstevel@tonic-gate {
800*7c478bd9Sstevel@tonic-gate 	DBG5(D_CTLOPS, dip, "dip=%x.%x rdip=%x.%x op=%x",
801*7c478bd9Sstevel@tonic-gate 	    HI32(dip), LO32(dip), HI32(rdip), LO32(rdip), op);
802*7c478bd9Sstevel@tonic-gate 	DBG4(D_CTLOPS|D_CONT, dip, " arg=%x.%x result=%x.%x\n",
803*7c478bd9Sstevel@tonic-gate 	    HI32(arg), LO32(arg), HI32(result), LO32(result));
804*7c478bd9Sstevel@tonic-gate 
805*7c478bd9Sstevel@tonic-gate 	switch (op) {
806*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_INITCHILD:
807*7c478bd9Sstevel@tonic-gate 		DBG2(D_CTLOPS, dip, "DDI_CTLOPS_INITCHILD: rdip=%s%d\n",
808*7c478bd9Sstevel@tonic-gate 		    ddi_get_name(rdip), ddi_get_instance(rdip));
809*7c478bd9Sstevel@tonic-gate 		return (init_child((dev_info_t *)arg));
810*7c478bd9Sstevel@tonic-gate 
811*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_UNINITCHILD:
812*7c478bd9Sstevel@tonic-gate 		DBG2(D_CTLOPS, dip, "DDI_CTLOPS_UNINITCHILD: rdip=%s%d\n",
813*7c478bd9Sstevel@tonic-gate 		    ddi_get_name(rdip), ddi_get_instance(rdip));
814*7c478bd9Sstevel@tonic-gate 		ddi_set_name_addr((dev_info_t *)arg, NULL);
815*7c478bd9Sstevel@tonic-gate 		ddi_remove_minor_node((dev_info_t *)arg, NULL);
816*7c478bd9Sstevel@tonic-gate 		impl_rem_dev_props((dev_info_t *)arg);
817*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
818*7c478bd9Sstevel@tonic-gate 
819*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTDEV:
820*7c478bd9Sstevel@tonic-gate 		DBG2(D_CTLOPS, dip, "DDI_CTLOPS_REPORTDEV: rdip=%s%d\n",
821*7c478bd9Sstevel@tonic-gate 		    ddi_get_name(rdip), ddi_get_instance(rdip));
822*7c478bd9Sstevel@tonic-gate 		return (report_dev(rdip));
823*7c478bd9Sstevel@tonic-gate 
824*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_XLATE_INTRS:
825*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
826*7c478bd9Sstevel@tonic-gate 
827*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_REGSIZE:
828*7c478bd9Sstevel@tonic-gate 		DBG2(D_CTLOPS, dip, "DDI_CTLOPS_REGSIZE: rdip=%s%d\n",
829*7c478bd9Sstevel@tonic-gate 		    ddi_get_name(rdip), ddi_get_instance(rdip));
830*7c478bd9Sstevel@tonic-gate 		*((off_t *)result) = get_reg_set_size(rdip, *((int *)arg));
831*7c478bd9Sstevel@tonic-gate 		return (*((off_t *)result) == -1 ? DDI_FAILURE : DDI_SUCCESS);
832*7c478bd9Sstevel@tonic-gate 
833*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_NREGS:
834*7c478bd9Sstevel@tonic-gate 		DBG2(D_CTLOPS, dip, "DDI_CTLOPS_NREGS: rdip=%s%d\n",
835*7c478bd9Sstevel@tonic-gate 		    ddi_get_name(rdip), ddi_get_instance(rdip));
836*7c478bd9Sstevel@tonic-gate 		*((uint_t *)result) = get_nreg_set(rdip);
837*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
838*7c478bd9Sstevel@tonic-gate 
839*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_NINTRS:
840*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
841*7c478bd9Sstevel@tonic-gate 	}
842*7c478bd9Sstevel@tonic-gate 
843*7c478bd9Sstevel@tonic-gate 	/*
844*7c478bd9Sstevel@tonic-gate 	 * Now pass the request up to our parent.
845*7c478bd9Sstevel@tonic-gate 	 */
846*7c478bd9Sstevel@tonic-gate 	DBG3(D_CTLOPS, dip, "passing request to parent: rdip=%s%d op=%x\n\n",
847*7c478bd9Sstevel@tonic-gate 	    ddi_get_name(rdip), ddi_get_instance(rdip), op);
848*7c478bd9Sstevel@tonic-gate 	return (ddi_ctlops(dip, rdip, op, arg, result));
849*7c478bd9Sstevel@tonic-gate }
850*7c478bd9Sstevel@tonic-gate 
851*7c478bd9Sstevel@tonic-gate 
852*7c478bd9Sstevel@tonic-gate /* support routines */
853*7c478bd9Sstevel@tonic-gate 
854*7c478bd9Sstevel@tonic-gate /*
855*7c478bd9Sstevel@tonic-gate  * get_properties
856*7c478bd9Sstevel@tonic-gate  *
857*7c478bd9Sstevel@tonic-gate  * This function is called from the attach routine to get the key
858*7c478bd9Sstevel@tonic-gate  * properties of the upa64s node.
859*7c478bd9Sstevel@tonic-gate  *
860*7c478bd9Sstevel@tonic-gate  * used by: upa64s_attach()
861*7c478bd9Sstevel@tonic-gate  *
862*7c478bd9Sstevel@tonic-gate  * return value: none
863*7c478bd9Sstevel@tonic-gate  */
864*7c478bd9Sstevel@tonic-gate static int
865*7c478bd9Sstevel@tonic-gate get_properties(upa64s_devstate_t *upa64s_p, dev_info_t *dip)
866*7c478bd9Sstevel@tonic-gate {
867*7c478bd9Sstevel@tonic-gate 	int safari_id;
868*7c478bd9Sstevel@tonic-gate 
869*7c478bd9Sstevel@tonic-gate 	/*
870*7c478bd9Sstevel@tonic-gate 	 * Get the device's safari id.
871*7c478bd9Sstevel@tonic-gate 	 */
872*7c478bd9Sstevel@tonic-gate 	safari_id = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
873*7c478bd9Sstevel@tonic-gate 	    "portid", -1);
874*7c478bd9Sstevel@tonic-gate 	if (safari_id == -1) {
875*7c478bd9Sstevel@tonic-gate 		int instance = ddi_get_instance(dip);
876*7c478bd9Sstevel@tonic-gate 		panic("%s%d: no portid property", ddi_get_name(dip), instance);
877*7c478bd9Sstevel@tonic-gate 	}
878*7c478bd9Sstevel@tonic-gate 	upa64s_p->safari_id = safari_id;
879*7c478bd9Sstevel@tonic-gate 
880*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
881*7c478bd9Sstevel@tonic-gate }
882*7c478bd9Sstevel@tonic-gate 
883*7c478bd9Sstevel@tonic-gate 
884*7c478bd9Sstevel@tonic-gate /*
885*7c478bd9Sstevel@tonic-gate  * save_state
886*7c478bd9Sstevel@tonic-gate  *
887*7c478bd9Sstevel@tonic-gate  * This routine saves a copy of the upa64s register state.
888*7c478bd9Sstevel@tonic-gate  *
889*7c478bd9Sstevel@tonic-gate  * used by: upa64s_detach() on a suspend operation
890*7c478bd9Sstevel@tonic-gate  */
891*7c478bd9Sstevel@tonic-gate static void
892*7c478bd9Sstevel@tonic-gate save_state(upa64s_devstate_t *upa64s_p)
893*7c478bd9Sstevel@tonic-gate {
894*7c478bd9Sstevel@tonic-gate 	upa64s_p->imr_data[0] = ddi_get64(upa64s_p->imr_ah[0],
895*7c478bd9Sstevel@tonic-gate 	    upa64s_p->imr[0]);
896*7c478bd9Sstevel@tonic-gate 	upa64s_p->imr_data[1] = ddi_get64(upa64s_p->imr_ah[1],
897*7c478bd9Sstevel@tonic-gate 	    upa64s_p->imr[1]);
898*7c478bd9Sstevel@tonic-gate }
899*7c478bd9Sstevel@tonic-gate 
900*7c478bd9Sstevel@tonic-gate 
901*7c478bd9Sstevel@tonic-gate /*
902*7c478bd9Sstevel@tonic-gate  * restore_state
903*7c478bd9Sstevel@tonic-gate  *
904*7c478bd9Sstevel@tonic-gate  * This routine restores a copy of the upa64s register state.
905*7c478bd9Sstevel@tonic-gate  *
906*7c478bd9Sstevel@tonic-gate  * used by: upa64s_attach() on a resume operation
907*7c478bd9Sstevel@tonic-gate  */
908*7c478bd9Sstevel@tonic-gate static void
909*7c478bd9Sstevel@tonic-gate restore_state(upa64s_devstate_t *upa64s_p)
910*7c478bd9Sstevel@tonic-gate {
911*7c478bd9Sstevel@tonic-gate #ifndef lint
912*7c478bd9Sstevel@tonic-gate 	volatile uint64_t tmp;
913*7c478bd9Sstevel@tonic-gate #endif
914*7c478bd9Sstevel@tonic-gate 	ddi_put64(upa64s_p->imr_ah[0], upa64s_p->imr[0],
915*7c478bd9Sstevel@tonic-gate 	    upa64s_p->imr_data[0]);
916*7c478bd9Sstevel@tonic-gate 	ddi_put64(upa64s_p->imr_ah[1], upa64s_p->imr[1],
917*7c478bd9Sstevel@tonic-gate 	    upa64s_p->imr_data[1]);
918*7c478bd9Sstevel@tonic-gate #ifndef lint
919*7c478bd9Sstevel@tonic-gate 	/* Flush the store buffer */
920*7c478bd9Sstevel@tonic-gate 	tmp = ddi_get64(upa64s_p->imr_ah[0], upa64s_p->imr[0]);
921*7c478bd9Sstevel@tonic-gate 	tmp = ddi_get64(upa64s_p->imr_ah[1], upa64s_p->imr[1]);
922*7c478bd9Sstevel@tonic-gate #endif
923*7c478bd9Sstevel@tonic-gate }
924*7c478bd9Sstevel@tonic-gate 
925*7c478bd9Sstevel@tonic-gate 
926*7c478bd9Sstevel@tonic-gate /*
927*7c478bd9Sstevel@tonic-gate  * get_reg_set
928*7c478bd9Sstevel@tonic-gate  *
929*7c478bd9Sstevel@tonic-gate  * This routine will get a upa64s format regspec for a given
930*7c478bd9Sstevel@tonic-gate  * device node and register number.
931*7c478bd9Sstevel@tonic-gate  *
932*7c478bd9Sstevel@tonic-gate  * used by: upa64s_map()
933*7c478bd9Sstevel@tonic-gate  *
934*7c478bd9Sstevel@tonic-gate  * return value:
935*7c478bd9Sstevel@tonic-gate  *
936*7c478bd9Sstevel@tonic-gate  *	DDI_SUCCESS		- on success
937*7c478bd9Sstevel@tonic-gate  *	DDI_ME_INVAL		- regspec is invalid
938*7c478bd9Sstevel@tonic-gate  *	DDI_ME_RNUMBER_RANGE	- rnumber out of range
939*7c478bd9Sstevel@tonic-gate  */
940*7c478bd9Sstevel@tonic-gate static int
941*7c478bd9Sstevel@tonic-gate get_reg_set(dev_info_t *dip, dev_info_t *child, int rnumber,
942*7c478bd9Sstevel@tonic-gate     off_t off, off_t len, struct regspec *rp)
943*7c478bd9Sstevel@tonic-gate {
944*7c478bd9Sstevel@tonic-gate 	upa64s_regspec_t *upa64s_rp;
945*7c478bd9Sstevel@tonic-gate 	int i, n, rval;
946*7c478bd9Sstevel@tonic-gate 
947*7c478bd9Sstevel@tonic-gate 	/*
948*7c478bd9Sstevel@tonic-gate 	 * Get child device "reg" property
949*7c478bd9Sstevel@tonic-gate 	 */
950*7c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop(DDI_DEV_T_NONE, child, DDI_PROP_DONTPASS, "reg",
951*7c478bd9Sstevel@tonic-gate 	    (caddr_t)&upa64s_rp, &i) != DDI_SUCCESS)
952*7c478bd9Sstevel@tonic-gate 		return (DDI_ME_RNUMBER_RANGE);
953*7c478bd9Sstevel@tonic-gate 
954*7c478bd9Sstevel@tonic-gate 	n = i / (int)sizeof (upa64s_regspec_t);
955*7c478bd9Sstevel@tonic-gate 	if (rnumber >= n) {
956*7c478bd9Sstevel@tonic-gate 		kmem_free(upa64s_rp, i);
957*7c478bd9Sstevel@tonic-gate 		return (DDI_ME_RNUMBER_RANGE);
958*7c478bd9Sstevel@tonic-gate 	}
959*7c478bd9Sstevel@tonic-gate 
960*7c478bd9Sstevel@tonic-gate 	/*
961*7c478bd9Sstevel@tonic-gate 	 * Convert each the upa64s format register specification to
962*7c478bd9Sstevel@tonic-gate 	 * out parent format.
963*7c478bd9Sstevel@tonic-gate 	 */
964*7c478bd9Sstevel@tonic-gate 	rval = xlate_reg_prop(dip, &upa64s_rp[rnumber], off, len, rp);
965*7c478bd9Sstevel@tonic-gate 	kmem_free(upa64s_rp, i);
966*7c478bd9Sstevel@tonic-gate 	return (rval);
967*7c478bd9Sstevel@tonic-gate }
968*7c478bd9Sstevel@tonic-gate 
969*7c478bd9Sstevel@tonic-gate 
970*7c478bd9Sstevel@tonic-gate /*
971*7c478bd9Sstevel@tonic-gate  * xlate_reg_prop
972*7c478bd9Sstevel@tonic-gate  *
973*7c478bd9Sstevel@tonic-gate  * This routine converts a upa64s format regspec to a standard
974*7c478bd9Sstevel@tonic-gate  * regspec containing the corresponding system address.
975*7c478bd9Sstevel@tonic-gate  *
976*7c478bd9Sstevel@tonic-gate  * used by: upa64s_map()
977*7c478bd9Sstevel@tonic-gate  *
978*7c478bd9Sstevel@tonic-gate  * return value:
979*7c478bd9Sstevel@tonic-gate  *
980*7c478bd9Sstevel@tonic-gate  *	DDI_SUCCESS
981*7c478bd9Sstevel@tonic-gate  *	DDI_FAILURE	- off + len is beyond device address range
982*7c478bd9Sstevel@tonic-gate  *	DDI_ME_INVAL	- regspec is invalid
983*7c478bd9Sstevel@tonic-gate  */
984*7c478bd9Sstevel@tonic-gate static int
985*7c478bd9Sstevel@tonic-gate xlate_reg_prop(dev_info_t *dip, upa64s_regspec_t *child_rp, off_t off,
986*7c478bd9Sstevel@tonic-gate     off_t len, struct regspec *rp)
987*7c478bd9Sstevel@tonic-gate {
988*7c478bd9Sstevel@tonic-gate 	int n_ranges, ranges_len, i;
989*7c478bd9Sstevel@tonic-gate 	uint64_t child_beg, child_end;
990*7c478bd9Sstevel@tonic-gate 	upa64s_ranges_t *range_p, *rng_p;
991*7c478bd9Sstevel@tonic-gate 
992*7c478bd9Sstevel@tonic-gate 	DBG4(D_MAP, dip, "upa64s regspec - ((%x,%x) (%x,%x))\n",
993*7c478bd9Sstevel@tonic-gate 	    HI32(child_rp->upa64s_phys), LO32(child_rp->upa64s_phys),
994*7c478bd9Sstevel@tonic-gate 	    HI32(child_rp->upa64s_size), LO32(child_rp->upa64s_size));
995*7c478bd9Sstevel@tonic-gate 	DBG2(D_MAP, dip, "upa64s xlate_reg_prp - off=%lx len=%lx\n", off, len);
996*7c478bd9Sstevel@tonic-gate #if 0
997*7c478bd9Sstevel@tonic-gate 	/*
998*7c478bd9Sstevel@tonic-gate 	 * both FFB and AFB have broken "reg" properties, all mapping
999*7c478bd9Sstevel@tonic-gate 	 * requests are done through reg-0 with very long offsets.
1000*7c478bd9Sstevel@tonic-gate 	 * Hence this safety check is always violated.
1001*7c478bd9Sstevel@tonic-gate 	 */
1002*7c478bd9Sstevel@tonic-gate 	if (off + len > child_rp->upa64s_size) {
1003*7c478bd9Sstevel@tonic-gate 		DBG(D_MAP, dip, "upa64s xlate_reg_prp: bad off + len\n");
1004*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
1005*7c478bd9Sstevel@tonic-gate 	}
1006*7c478bd9Sstevel@tonic-gate #endif
1007*7c478bd9Sstevel@tonic-gate 	/*
1008*7c478bd9Sstevel@tonic-gate 	 * current "struct regspec" only supports 32-bit sizes.
1009*7c478bd9Sstevel@tonic-gate 	 */
1010*7c478bd9Sstevel@tonic-gate 	if (child_rp->upa64s_size >= (1ull << 32))
1011*7c478bd9Sstevel@tonic-gate 		panic("upa64s: reg size must be less than 4 Gb");
1012*7c478bd9Sstevel@tonic-gate 
1013*7c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
1014*7c478bd9Sstevel@tonic-gate 	    "ranges", (caddr_t)&range_p, &ranges_len) != DDI_SUCCESS) {
1015*7c478bd9Sstevel@tonic-gate 		ranges_len = 0;
1016*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s%d: no ranges property",
1017*7c478bd9Sstevel@tonic-gate 		    ddi_get_name(dip), ddi_get_instance(dip));
1018*7c478bd9Sstevel@tonic-gate 	}
1019*7c478bd9Sstevel@tonic-gate 
1020*7c478bd9Sstevel@tonic-gate 	n_ranges = ranges_len / sizeof (upa64s_regspec_t);
1021*7c478bd9Sstevel@tonic-gate 	child_beg = child_rp->upa64s_phys;
1022*7c478bd9Sstevel@tonic-gate #if 0
1023*7c478bd9Sstevel@tonic-gate 	/*
1024*7c478bd9Sstevel@tonic-gate 	 * again, this safety checking can not be performed.
1025*7c478bd9Sstevel@tonic-gate 	 * Hack by adding a pratical max child reg bank length.
1026*7c478bd9Sstevel@tonic-gate 	 */
1027*7c478bd9Sstevel@tonic-gate 	child_end = child_beg + child_rp->upa64s_size;
1028*7c478bd9Sstevel@tonic-gate #else
1029*7c478bd9Sstevel@tonic-gate #define	UPA64S_MAX_CHILD_LEN	0xe000000
1030*7c478bd9Sstevel@tonic-gate 	child_end = child_beg + UPA64S_MAX_CHILD_LEN;
1031*7c478bd9Sstevel@tonic-gate #endif
1032*7c478bd9Sstevel@tonic-gate 	for (i = 0, rng_p = range_p; i < n_ranges; i++, rng_p++) {
1033*7c478bd9Sstevel@tonic-gate 		uint64_t rng_beg = rng_p->upa64s_child;
1034*7c478bd9Sstevel@tonic-gate 		uint64_t rng_end = rng_beg + rng_p->upa64s_size;
1035*7c478bd9Sstevel@tonic-gate 		if ((rng_beg <= child_beg) && (rng_end >= child_end)) {
1036*7c478bd9Sstevel@tonic-gate 			uint64_t addr = child_beg - rng_beg + off;
1037*7c478bd9Sstevel@tonic-gate 			addr += rng_p->upa64s_parent;
1038*7c478bd9Sstevel@tonic-gate 			rp->regspec_bustype = HI32(addr);
1039*7c478bd9Sstevel@tonic-gate 			rp->regspec_addr = LO32(addr);
1040*7c478bd9Sstevel@tonic-gate 			rp->regspec_size = len ? len : child_rp->upa64s_size;
1041*7c478bd9Sstevel@tonic-gate 			break;
1042*7c478bd9Sstevel@tonic-gate 		}
1043*7c478bd9Sstevel@tonic-gate 	}
1044*7c478bd9Sstevel@tonic-gate 	if (ranges_len)
1045*7c478bd9Sstevel@tonic-gate 		kmem_free(range_p, ranges_len);
1046*7c478bd9Sstevel@tonic-gate 	DBG4(D_MAP, dip, "regspec (%x,%x,%x) i=%x\n",
1047*7c478bd9Sstevel@tonic-gate 	    rp->regspec_bustype, rp->regspec_addr, rp->regspec_size, i);
1048*7c478bd9Sstevel@tonic-gate 	return (i < n_ranges? DDI_SUCCESS : DDI_ME_INVAL);
1049*7c478bd9Sstevel@tonic-gate }
1050*7c478bd9Sstevel@tonic-gate 
1051*7c478bd9Sstevel@tonic-gate 
1052*7c478bd9Sstevel@tonic-gate /*
1053*7c478bd9Sstevel@tonic-gate  * report_dev
1054*7c478bd9Sstevel@tonic-gate  *
1055*7c478bd9Sstevel@tonic-gate  * This function is called from our control ops routine on a
1056*7c478bd9Sstevel@tonic-gate  * DDI_CTLOPS_REPORTDEV request.
1057*7c478bd9Sstevel@tonic-gate  */
1058*7c478bd9Sstevel@tonic-gate static int
1059*7c478bd9Sstevel@tonic-gate report_dev(dev_info_t *dip)
1060*7c478bd9Sstevel@tonic-gate {
1061*7c478bd9Sstevel@tonic-gate 	if (dip == (dev_info_t *)0)
1062*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
1063*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "?UPA64S-device: %s@%s, %s #%d\n",
1064*7c478bd9Sstevel@tonic-gate 	    ddi_node_name(dip), ddi_get_name_addr(dip),
1065*7c478bd9Sstevel@tonic-gate 	    ddi_major_to_name(ddi_name_to_major(ddi_get_name(dip))),
1066*7c478bd9Sstevel@tonic-gate 	    ddi_get_instance(dip));
1067*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
1068*7c478bd9Sstevel@tonic-gate }
1069*7c478bd9Sstevel@tonic-gate 
1070*7c478bd9Sstevel@tonic-gate 
1071*7c478bd9Sstevel@tonic-gate /*
1072*7c478bd9Sstevel@tonic-gate  * init_child
1073*7c478bd9Sstevel@tonic-gate  *
1074*7c478bd9Sstevel@tonic-gate  * This function is called from our control ops routine on a
1075*7c478bd9Sstevel@tonic-gate  * DDI_CTLOPS_INITCHILD request.  It builds and sets the device's
1076*7c478bd9Sstevel@tonic-gate  * parent private data area.
1077*7c478bd9Sstevel@tonic-gate  *
1078*7c478bd9Sstevel@tonic-gate  * used by: upa64s_ctlops()
1079*7c478bd9Sstevel@tonic-gate  *
1080*7c478bd9Sstevel@tonic-gate  * return value: none
1081*7c478bd9Sstevel@tonic-gate  */
1082*7c478bd9Sstevel@tonic-gate static int
1083*7c478bd9Sstevel@tonic-gate init_child(dev_info_t *child)
1084*7c478bd9Sstevel@tonic-gate {
1085*7c478bd9Sstevel@tonic-gate 	upa64s_regspec_t *child_rp;
1086*7c478bd9Sstevel@tonic-gate 	int i;
1087*7c478bd9Sstevel@tonic-gate 	char addr[256];
1088*7c478bd9Sstevel@tonic-gate 	int32_t portid;
1089*7c478bd9Sstevel@tonic-gate 
1090*7c478bd9Sstevel@tonic-gate 	if ((portid = ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
1091*7c478bd9Sstevel@tonic-gate 	    "upa-portid", -1)) == -1)
1092*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
1093*7c478bd9Sstevel@tonic-gate 
1094*7c478bd9Sstevel@tonic-gate 	/*
1095*7c478bd9Sstevel@tonic-gate 	 * Set the address portion of the node name based on
1096*7c478bd9Sstevel@tonic-gate 	 * the function and device number.
1097*7c478bd9Sstevel@tonic-gate 	 */
1098*7c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop(DDI_DEV_T_NONE, child, DDI_PROP_DONTPASS, "reg",
1099*7c478bd9Sstevel@tonic-gate 	    (caddr_t)&child_rp, &i) != DDI_SUCCESS) {
1100*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
1101*7c478bd9Sstevel@tonic-gate 	}
1102*7c478bd9Sstevel@tonic-gate 
1103*7c478bd9Sstevel@tonic-gate 	(void) sprintf(addr, "%x,%x", portid, LO32(child_rp->upa64s_phys));
1104*7c478bd9Sstevel@tonic-gate 	ddi_set_name_addr(child, addr);
1105*7c478bd9Sstevel@tonic-gate 
1106*7c478bd9Sstevel@tonic-gate 	ddi_set_parent_data(child, NULL);
1107*7c478bd9Sstevel@tonic-gate 	kmem_free(child_rp, i);
1108*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
1109*7c478bd9Sstevel@tonic-gate }
1110*7c478bd9Sstevel@tonic-gate 
1111*7c478bd9Sstevel@tonic-gate 
1112*7c478bd9Sstevel@tonic-gate /*
1113*7c478bd9Sstevel@tonic-gate  * get_reg_set_size
1114*7c478bd9Sstevel@tonic-gate  *
1115*7c478bd9Sstevel@tonic-gate  * Given a dev info pointer to a child and a register number, this
1116*7c478bd9Sstevel@tonic-gate  * routine returns the size element of that reg set property.
1117*7c478bd9Sstevel@tonic-gate  *
1118*7c478bd9Sstevel@tonic-gate  * used by: upa64s_ctlops() - DDI_CTLOPS_REGSIZE
1119*7c478bd9Sstevel@tonic-gate  *
1120*7c478bd9Sstevel@tonic-gate  * return value: size of reg set on success, -1 on error
1121*7c478bd9Sstevel@tonic-gate  */
1122*7c478bd9Sstevel@tonic-gate static off_t
1123*7c478bd9Sstevel@tonic-gate get_reg_set_size(dev_info_t *child, int rnumber)
1124*7c478bd9Sstevel@tonic-gate {
1125*7c478bd9Sstevel@tonic-gate 	upa64s_regspec_t *upa64s_rp;
1126*7c478bd9Sstevel@tonic-gate 	uint_t size;
1127*7c478bd9Sstevel@tonic-gate 	int i;
1128*7c478bd9Sstevel@tonic-gate 
1129*7c478bd9Sstevel@tonic-gate 	if (rnumber < 0)
1130*7c478bd9Sstevel@tonic-gate 		return (-1);
1131*7c478bd9Sstevel@tonic-gate 
1132*7c478bd9Sstevel@tonic-gate 	/*
1133*7c478bd9Sstevel@tonic-gate 	 * Get the reg property for the device.
1134*7c478bd9Sstevel@tonic-gate 	 */
1135*7c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop(DDI_DEV_T_NONE, child, DDI_PROP_DONTPASS, "reg",
1136*7c478bd9Sstevel@tonic-gate 	    (caddr_t)&upa64s_rp, &i) != DDI_SUCCESS)
1137*7c478bd9Sstevel@tonic-gate 		return (-1);
1138*7c478bd9Sstevel@tonic-gate 
1139*7c478bd9Sstevel@tonic-gate 	if (rnumber >= (i / (int)sizeof (upa64s_regspec_t))) {
1140*7c478bd9Sstevel@tonic-gate 		kmem_free(upa64s_rp, i);
1141*7c478bd9Sstevel@tonic-gate 		return (-1);
1142*7c478bd9Sstevel@tonic-gate 	}
1143*7c478bd9Sstevel@tonic-gate 
1144*7c478bd9Sstevel@tonic-gate 	/*  >4G reg size not supported */
1145*7c478bd9Sstevel@tonic-gate 	size = (uint32_t)upa64s_rp[rnumber].upa64s_size;
1146*7c478bd9Sstevel@tonic-gate 	kmem_free(upa64s_rp, i);
1147*7c478bd9Sstevel@tonic-gate 	return (size);
1148*7c478bd9Sstevel@tonic-gate }
1149*7c478bd9Sstevel@tonic-gate 
1150*7c478bd9Sstevel@tonic-gate 
1151*7c478bd9Sstevel@tonic-gate /*
1152*7c478bd9Sstevel@tonic-gate  * get_nreg_set
1153*7c478bd9Sstevel@tonic-gate  *
1154*7c478bd9Sstevel@tonic-gate  * Given a dev info pointer to a child, this routine returns the
1155*7c478bd9Sstevel@tonic-gate  * number of sets in its "reg" property.
1156*7c478bd9Sstevel@tonic-gate  *
1157*7c478bd9Sstevel@tonic-gate  * used by: upa64s_ctlops() - DDI_CTLOPS_NREGS
1158*7c478bd9Sstevel@tonic-gate  *
1159*7c478bd9Sstevel@tonic-gate  * return value: # of reg sets on success, zero on error
1160*7c478bd9Sstevel@tonic-gate  */
1161*7c478bd9Sstevel@tonic-gate static uint_t
1162*7c478bd9Sstevel@tonic-gate get_nreg_set(dev_info_t *child)
1163*7c478bd9Sstevel@tonic-gate {
1164*7c478bd9Sstevel@tonic-gate 	upa64s_regspec_t *upa64s_rp;
1165*7c478bd9Sstevel@tonic-gate 	int i, n;
1166*7c478bd9Sstevel@tonic-gate 
1167*7c478bd9Sstevel@tonic-gate 	/*
1168*7c478bd9Sstevel@tonic-gate 	 * Get the reg property for the device.
1169*7c478bd9Sstevel@tonic-gate 	 */
1170*7c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop(DDI_DEV_T_NONE, child, DDI_PROP_DONTPASS, "reg",
1171*7c478bd9Sstevel@tonic-gate 	    (caddr_t)&upa64s_rp, &i) != DDI_SUCCESS)
1172*7c478bd9Sstevel@tonic-gate 		return (0);
1173*7c478bd9Sstevel@tonic-gate 
1174*7c478bd9Sstevel@tonic-gate 	n =  i / (int)sizeof (upa64s_regspec_t);
1175*7c478bd9Sstevel@tonic-gate 	kmem_free(upa64s_rp, i);
1176*7c478bd9Sstevel@tonic-gate 	return (n);
1177*7c478bd9Sstevel@tonic-gate }
1178*7c478bd9Sstevel@tonic-gate 
1179*7c478bd9Sstevel@tonic-gate 
1180*7c478bd9Sstevel@tonic-gate /*
1181*7c478bd9Sstevel@tonic-gate  * upa64s_intrdist
1182*7c478bd9Sstevel@tonic-gate  *
1183*7c478bd9Sstevel@tonic-gate  * The following routine is the callback function for this nexus driver
1184*7c478bd9Sstevel@tonic-gate  * to support interrupt distribution on sun4u systems. When this
1185*7c478bd9Sstevel@tonic-gate  * function is called by the interrupt distribution framework, it will
1186*7c478bd9Sstevel@tonic-gate  * reprogram all the active the mondo registers.
1187*7c478bd9Sstevel@tonic-gate  */
1188*7c478bd9Sstevel@tonic-gate static void
1189*7c478bd9Sstevel@tonic-gate upa64s_intrdist(void *arg)
1190*7c478bd9Sstevel@tonic-gate {
1191*7c478bd9Sstevel@tonic-gate 	dev_info_t *dip = (dev_info_t *)arg;
1192*7c478bd9Sstevel@tonic-gate 	int instance = ddi_get_instance(dip);
1193*7c478bd9Sstevel@tonic-gate 	upa64s_devstate_t *upa64s_p = get_upa64s_soft_state(instance);
1194*7c478bd9Sstevel@tonic-gate 	uint_t upaport;
1195*7c478bd9Sstevel@tonic-gate 
1196*7c478bd9Sstevel@tonic-gate 	for (upaport = 0; upaport < UPA64S_PORTS; upaport++) {
1197*7c478bd9Sstevel@tonic-gate 		volatile uint64_t *imr;
1198*7c478bd9Sstevel@tonic-gate 		volatile uint64_t imr_dat;
1199*7c478bd9Sstevel@tonic-gate 		uint_t mondo;
1200*7c478bd9Sstevel@tonic-gate 		uint32_t cpuid;
1201*7c478bd9Sstevel@tonic-gate 
1202*7c478bd9Sstevel@tonic-gate 		if (upa64s_p->ino_state[upaport] != INO_INUSE)
1203*7c478bd9Sstevel@tonic-gate 			continue;
1204*7c478bd9Sstevel@tonic-gate 
1205*7c478bd9Sstevel@tonic-gate 		imr = upa64s_p->imr[upaport];
1206*7c478bd9Sstevel@tonic-gate 		mondo = UPA64S_IMR_TO_MONDO(*imr);
1207*7c478bd9Sstevel@tonic-gate 		cpuid = intr_dist_cpuid();
1208*7c478bd9Sstevel@tonic-gate 		imr_dat = UPA64S_CPUID_TO_IMR(cpuid);
1209*7c478bd9Sstevel@tonic-gate 		imr_dat = UPA64S_GET_MAP_REG(mondo, imr_dat);
1210*7c478bd9Sstevel@tonic-gate 
1211*7c478bd9Sstevel@tonic-gate 		/* Check and re-program cpu target if necessary */
1212*7c478bd9Sstevel@tonic-gate 		DBG2(D_INTRDIST, dip, "mondo=%x cpuid=%x\n", mondo, cpuid);
1213*7c478bd9Sstevel@tonic-gate 		if (UPA64S_IMR_TO_CPUID(*imr) == cpuid) {
1214*7c478bd9Sstevel@tonic-gate 			DBG(D_INTRDIST, dip, "same cpuid\n");
1215*7c478bd9Sstevel@tonic-gate 			continue;
1216*7c478bd9Sstevel@tonic-gate 		}
1217*7c478bd9Sstevel@tonic-gate 		ddi_put64(upa64s_p->imr_ah[upaport], (uint64_t *)imr, imr_dat);
1218*7c478bd9Sstevel@tonic-gate 		imr_dat = ddi_get64(upa64s_p->imr_ah[upaport], (uint64_t *)imr);
1219*7c478bd9Sstevel@tonic-gate 	}
1220*7c478bd9Sstevel@tonic-gate }
1221*7c478bd9Sstevel@tonic-gate 
1222*7c478bd9Sstevel@tonic-gate 
1223*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1224*7c478bd9Sstevel@tonic-gate static void
1225*7c478bd9Sstevel@tonic-gate upa64s_debug(uint_t flag, dev_info_t *dip, char *fmt,
1226*7c478bd9Sstevel@tonic-gate     uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5)
1227*7c478bd9Sstevel@tonic-gate {
1228*7c478bd9Sstevel@tonic-gate 	char *s = NULL;
1229*7c478bd9Sstevel@tonic-gate 	uint_t cont = 0;
1230*7c478bd9Sstevel@tonic-gate 	if (flag & D_CONT) {
1231*7c478bd9Sstevel@tonic-gate 		flag &= ~D_CONT;
1232*7c478bd9Sstevel@tonic-gate 		cont = 1;
1233*7c478bd9Sstevel@tonic-gate 	}
1234*7c478bd9Sstevel@tonic-gate 	if (!(upa64s_debug_flags & flag))
1235*7c478bd9Sstevel@tonic-gate 		return;
1236*7c478bd9Sstevel@tonic-gate 
1237*7c478bd9Sstevel@tonic-gate 	switch (flag) {
1238*7c478bd9Sstevel@tonic-gate 	case D_ATTACH:		s = "attach";		break;
1239*7c478bd9Sstevel@tonic-gate 	case D_DETACH:		s = "detach";		break;
1240*7c478bd9Sstevel@tonic-gate 	case D_POWER:		s = "power";		break;
1241*7c478bd9Sstevel@tonic-gate 	case D_MAP:		s = "map";		break;
1242*7c478bd9Sstevel@tonic-gate 	case D_CTLOPS:		s = "ctlops";		break;
1243*7c478bd9Sstevel@tonic-gate 	case D_G_ISPEC:		s = "get_intrspec";	break;
1244*7c478bd9Sstevel@tonic-gate 	case D_A_ISPEC:		s = "add_intrspec";	break;
1245*7c478bd9Sstevel@tonic-gate 	case D_R_ISPEC:		s = "remove_intrspec";	break;
1246*7c478bd9Sstevel@tonic-gate 	case D_INIT_CLD:	s = "init_child";	break;
1247*7c478bd9Sstevel@tonic-gate 	case D_INTRDIST:	s = "intrdist";		break;
1248*7c478bd9Sstevel@tonic-gate 	}
1249*7c478bd9Sstevel@tonic-gate 
1250*7c478bd9Sstevel@tonic-gate 	if (s && cont == 0) {
1251*7c478bd9Sstevel@tonic-gate 		prom_printf("%s(%d): %s: ", ddi_get_name(dip),
1252*7c478bd9Sstevel@tonic-gate 		    ddi_get_instance(dip), s);
1253*7c478bd9Sstevel@tonic-gate 	}
1254*7c478bd9Sstevel@tonic-gate 	prom_printf(fmt, a1, a2, a3, a4, a5);
1255*7c478bd9Sstevel@tonic-gate }
1256*7c478bd9Sstevel@tonic-gate #endif
1257