xref: /onnv-gate/usr/src/uts/sun4u/io/mach_rootnex.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 /*
30*0Sstevel@tonic-gate  * sun4u root nexus driver
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate #include <sys/conf.h>
33*0Sstevel@tonic-gate #include <sys/cpuvar.h>
34*0Sstevel@tonic-gate #include <sys/sysiosbus.h>
35*0Sstevel@tonic-gate #include <sys/intreg.h>
36*0Sstevel@tonic-gate #include <sys/ddi_subrdefs.h>
37*0Sstevel@tonic-gate #include <sys/sunndi.h>
38*0Sstevel@tonic-gate #include <sys/async.h>
39*0Sstevel@tonic-gate 
40*0Sstevel@tonic-gate /* Useful debugging Stuff */
41*0Sstevel@tonic-gate #include <sys/nexusdebug.h>
42*0Sstevel@tonic-gate #define	ROOTNEX_MAP_DEBUG		0x1
43*0Sstevel@tonic-gate #define	ROOTNEX_INTR_DEBUG		0x2
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate /*
46*0Sstevel@tonic-gate  * Extern declarations
47*0Sstevel@tonic-gate  */
48*0Sstevel@tonic-gate extern uint_t	root_phys_addr_lo_mask;
49*0Sstevel@tonic-gate extern int rootnex_name_child(dev_info_t *child, char *name, int namelen);
50*0Sstevel@tonic-gate extern int rootnex_ctl_uninitchild(dev_info_t *dip);
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate uint_t	root_phys_addr_hi_mask = 0xffffffff;
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate /*
55*0Sstevel@tonic-gate  * config information
56*0Sstevel@tonic-gate  */
57*0Sstevel@tonic-gate int
58*0Sstevel@tonic-gate rootnex_add_intr_impl(dev_info_t *dip, dev_info_t *rdip,
59*0Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp);
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate int
62*0Sstevel@tonic-gate rootnex_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip,
63*0Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp);
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate void
66*0Sstevel@tonic-gate rootnex_get_intr_pri(dev_info_t *dip, dev_info_t *rdip,
67*0Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp);
68*0Sstevel@tonic-gate 
69*0Sstevel@tonic-gate ddi_iblock_cookie_t rootnex_err_ibc;
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate /*
72*0Sstevel@tonic-gate  * rootnex_add_intr_impl:
73*0Sstevel@tonic-gate  */
74*0Sstevel@tonic-gate /*ARGSUSED*/
75*0Sstevel@tonic-gate int
76*0Sstevel@tonic-gate rootnex_add_intr_impl(dev_info_t *dip, dev_info_t *rdip,
77*0Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp)
78*0Sstevel@tonic-gate {
79*0Sstevel@tonic-gate 	ddi_ispec_t		*ip = (ddi_ispec_t *)hdlp->ih_private;
80*0Sstevel@tonic-gate 	volatile uint64_t	*intr_mapping_reg;
81*0Sstevel@tonic-gate 	volatile uint64_t	mondo_vector;
82*0Sstevel@tonic-gate 	int32_t			r_upaid = -1;
83*0Sstevel@tonic-gate 	int32_t			slave = 0;
84*0Sstevel@tonic-gate 	int32_t			upa_portid;
85*0Sstevel@tonic-gate 	int			len, ret;
86*0Sstevel@tonic-gate 
87*0Sstevel@tonic-gate 	if ((upa_portid = ddi_prop_get_int(DDI_DEV_T_ANY, rdip,
88*0Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "upa-portid", -1)) != -1) {
89*0Sstevel@tonic-gate 		if (ddi_getprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
90*0Sstevel@tonic-gate 		    "upa-interrupt-slave", 0) != 0) {
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate 			/* Give slave devices pri of 5. e.g. fb's */
93*0Sstevel@tonic-gate 			ip->is_pil = 5;
94*0Sstevel@tonic-gate 			hdlp->ih_pri = ip->is_pil;
95*0Sstevel@tonic-gate 		}
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate 		/*
98*0Sstevel@tonic-gate 		 * Translate the interrupt property by stuffing in the
99*0Sstevel@tonic-gate 		 * portid for those devices which have a upa-portid.
100*0Sstevel@tonic-gate 		 */
101*0Sstevel@tonic-gate 		*ip->is_intr |= (UPAID_TO_IGN(upa_portid) << 6);
102*0Sstevel@tonic-gate 	}
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate 	/*
105*0Sstevel@tonic-gate 	 * Hack to support the UPA slave devices before the 1275
106*0Sstevel@tonic-gate 	 * support for imap was introduced.
107*0Sstevel@tonic-gate 	 */
108*0Sstevel@tonic-gate 	if (ddi_getproplen(DDI_DEV_T_ANY, dip, NULL, "interrupt-map",
109*0Sstevel@tonic-gate 	    &len) != DDI_PROP_SUCCESS && ddi_getprop(DDI_DEV_T_ANY,
110*0Sstevel@tonic-gate 	    rdip, DDI_PROP_DONTPASS, "upa-interrupt-slave", 0) != 0 &&
111*0Sstevel@tonic-gate 	    ddi_get_parent(rdip) == dip) {
112*0Sstevel@tonic-gate 		slave = 1;
113*0Sstevel@tonic-gate 
114*0Sstevel@tonic-gate 		if ((r_upaid = ddi_prop_get_int(DDI_DEV_T_ANY, rdip,
115*0Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, "upa-portid", -1)) != -1) {
116*0Sstevel@tonic-gate 			extern uint64_t *get_intr_mapping_reg(int, int);
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate 			if ((intr_mapping_reg = get_intr_mapping_reg(
119*0Sstevel@tonic-gate 			    r_upaid, 1)) == NULL)
120*0Sstevel@tonic-gate 				return (DDI_FAILURE);
121*0Sstevel@tonic-gate 		} else
122*0Sstevel@tonic-gate 			return (DDI_FAILURE);
123*0Sstevel@tonic-gate 	}
124*0Sstevel@tonic-gate 
125*0Sstevel@tonic-gate 	hdlp->ih_vector = *ip->is_intr;
126*0Sstevel@tonic-gate 	if ((ret = i_ddi_add_ivintr(hdlp)) != DDI_SUCCESS)
127*0Sstevel@tonic-gate 		return (ret);
128*0Sstevel@tonic-gate 
129*0Sstevel@tonic-gate 	/*
130*0Sstevel@tonic-gate 	 * Hack to support the UPA slave devices before the 1275
131*0Sstevel@tonic-gate 	 * support for imap was introduced.
132*0Sstevel@tonic-gate 	 */
133*0Sstevel@tonic-gate 	if (slave) {
134*0Sstevel@tonic-gate 		/*
135*0Sstevel@tonic-gate 		 * Program the interrupt mapping register.
136*0Sstevel@tonic-gate 		 * Interrupts from the slave UPA devices are
137*0Sstevel@tonic-gate 		 * directed at the boot CPU until it is known
138*0Sstevel@tonic-gate 		 * that they can be safely redirected while
139*0Sstevel@tonic-gate 		 * running under load.
140*0Sstevel@tonic-gate 		 */
141*0Sstevel@tonic-gate 		mondo_vector = cpu0.cpu_id << IMR_TID_SHIFT;
142*0Sstevel@tonic-gate 		mondo_vector |= (IMR_VALID | (uint64_t)*ip->is_intr);
143*0Sstevel@tonic-gate 
144*0Sstevel@tonic-gate 		/* Set the mapping register */
145*0Sstevel@tonic-gate 		*intr_mapping_reg = mondo_vector;
146*0Sstevel@tonic-gate 
147*0Sstevel@tonic-gate 		/* Flush write buffers */
148*0Sstevel@tonic-gate 		mondo_vector = *intr_mapping_reg;
149*0Sstevel@tonic-gate 	}
150*0Sstevel@tonic-gate 
151*0Sstevel@tonic-gate 	return (ret);
152*0Sstevel@tonic-gate }
153*0Sstevel@tonic-gate 
154*0Sstevel@tonic-gate /*
155*0Sstevel@tonic-gate  * rootnex_remove_intr_impl:
156*0Sstevel@tonic-gate  */
157*0Sstevel@tonic-gate /*ARGSUSED*/
158*0Sstevel@tonic-gate int
159*0Sstevel@tonic-gate rootnex_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip,
160*0Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp)
161*0Sstevel@tonic-gate {
162*0Sstevel@tonic-gate 	ddi_ispec_t	*ip = (ddi_ispec_t *)hdlp->ih_private;
163*0Sstevel@tonic-gate 	int32_t		upa_portid;
164*0Sstevel@tonic-gate 	int		len;
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate 	if ((upa_portid = ddi_prop_get_int(DDI_DEV_T_ANY, rdip,
167*0Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "upa-portid", -1)) != -1) {
168*0Sstevel@tonic-gate 		/*
169*0Sstevel@tonic-gate 		 * Translate the interrupt property by stuffing in the
170*0Sstevel@tonic-gate 		 * portid for those devices which have a upa-portid.
171*0Sstevel@tonic-gate 		 */
172*0Sstevel@tonic-gate 		*ip->is_intr |= (UPAID_TO_IGN(upa_portid) << 6);
173*0Sstevel@tonic-gate 	}
174*0Sstevel@tonic-gate 
175*0Sstevel@tonic-gate 	/*
176*0Sstevel@tonic-gate 	 * Hack to support the UPA slave devices before the 1275
177*0Sstevel@tonic-gate 	 * support for imap was introduced.
178*0Sstevel@tonic-gate 	 */
179*0Sstevel@tonic-gate 	if (ddi_getproplen(DDI_DEV_T_ANY, dip, NULL, "interrupt-map",
180*0Sstevel@tonic-gate 	    &len) != DDI_PROP_SUCCESS && ddi_getprop(DDI_DEV_T_ANY,
181*0Sstevel@tonic-gate 	    rdip, DDI_PROP_DONTPASS, "upa-interrupt-slave", 0) != 0) {
182*0Sstevel@tonic-gate 		int32_t r_upaid = -1;
183*0Sstevel@tonic-gate 
184*0Sstevel@tonic-gate 		if ((r_upaid = ddi_prop_get_int(DDI_DEV_T_ANY, rdip,
185*0Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, "upa-portid", -1)) != -1 &&
186*0Sstevel@tonic-gate 		    ddi_get_parent(rdip) == dip) {
187*0Sstevel@tonic-gate 			volatile uint64_t *intr_mapping_reg;
188*0Sstevel@tonic-gate 			volatile uint64_t flush_data;
189*0Sstevel@tonic-gate 			extern uint64_t *get_intr_mapping_reg(int, int);
190*0Sstevel@tonic-gate 
191*0Sstevel@tonic-gate 			if ((intr_mapping_reg = get_intr_mapping_reg(
192*0Sstevel@tonic-gate 			    r_upaid, 1)) == NULL)
193*0Sstevel@tonic-gate 				return (DDI_SUCCESS);
194*0Sstevel@tonic-gate 
195*0Sstevel@tonic-gate 			/* Clear the mapping register */
196*0Sstevel@tonic-gate 			*intr_mapping_reg = 0x0ull;
197*0Sstevel@tonic-gate 
198*0Sstevel@tonic-gate 			/* Flush write buffers */
199*0Sstevel@tonic-gate 			flush_data = *intr_mapping_reg;
200*0Sstevel@tonic-gate #ifdef lint
201*0Sstevel@tonic-gate 			flush_data = flush_data;
202*0Sstevel@tonic-gate #endif /* lint */
203*0Sstevel@tonic-gate 		}
204*0Sstevel@tonic-gate 	}
205*0Sstevel@tonic-gate 
206*0Sstevel@tonic-gate 	hdlp->ih_vector = *ip->is_intr;
207*0Sstevel@tonic-gate 	i_ddi_rem_ivintr(hdlp);
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
210*0Sstevel@tonic-gate }
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate /*
213*0Sstevel@tonic-gate  * rootnex_get_intr_pri:
214*0Sstevel@tonic-gate  */
215*0Sstevel@tonic-gate /*ARGSUSED*/
216*0Sstevel@tonic-gate void
217*0Sstevel@tonic-gate rootnex_get_intr_pri(dev_info_t *dip, dev_info_t *rdip,
218*0Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp)
219*0Sstevel@tonic-gate {
220*0Sstevel@tonic-gate 	ddi_ispec_t	*ip = (ddi_ispec_t *)hdlp->ih_private;
221*0Sstevel@tonic-gate 
222*0Sstevel@tonic-gate 	if (ddi_prop_get_int(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
223*0Sstevel@tonic-gate 	    "upa-portid", -1) != -1) {
224*0Sstevel@tonic-gate 		if (ddi_getprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
225*0Sstevel@tonic-gate 		    "upa-interrupt-slave", 0) != 0) {
226*0Sstevel@tonic-gate 
227*0Sstevel@tonic-gate 			/* Give slave devices pri of 5. e.g. fb's */
228*0Sstevel@tonic-gate 			ip->is_pil = 5;
229*0Sstevel@tonic-gate 		}
230*0Sstevel@tonic-gate 	}
231*0Sstevel@tonic-gate }
232*0Sstevel@tonic-gate 
233*0Sstevel@tonic-gate int
234*0Sstevel@tonic-gate rootnex_ctl_reportdev_impl(dev_info_t *dev)
235*0Sstevel@tonic-gate {
236*0Sstevel@tonic-gate 	struct regspec *rp;
237*0Sstevel@tonic-gate 	char buf[80];
238*0Sstevel@tonic-gate 	char *p = buf;
239*0Sstevel@tonic-gate 	register int n;
240*0Sstevel@tonic-gate 	int	portid;
241*0Sstevel@tonic-gate 	int	nodeid;
242*0Sstevel@tonic-gate 
243*0Sstevel@tonic-gate 	(void) sprintf(p, "%s%d at root", ddi_driver_name(dev),
244*0Sstevel@tonic-gate 	    ddi_get_instance(dev));
245*0Sstevel@tonic-gate 	p += strlen(p);
246*0Sstevel@tonic-gate 
247*0Sstevel@tonic-gate 	if ((n = sparc_pd_getnreg(dev)) > 0) {
248*0Sstevel@tonic-gate 		rp = sparc_pd_getreg(dev, 0);
249*0Sstevel@tonic-gate 
250*0Sstevel@tonic-gate 		(void) strcpy(p, ": ");
251*0Sstevel@tonic-gate 		p += strlen(p);
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate 		/*
254*0Sstevel@tonic-gate 		 * This stuff needs to be fixed correctly for the FFB
255*0Sstevel@tonic-gate 		 * devices and the UPA add-on devices.
256*0Sstevel@tonic-gate 		 */
257*0Sstevel@tonic-gate 		portid = ddi_prop_get_int(DDI_DEV_T_ANY, dev,
258*0Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, "upa-portid", -1);
259*0Sstevel@tonic-gate 		if (portid != -1)
260*0Sstevel@tonic-gate 			(void) sprintf(p, "UPA 0x%x 0x%x%s",
261*0Sstevel@tonic-gate 			    portid,
262*0Sstevel@tonic-gate 			    rp->regspec_addr, (n > 1 ? "" : " ..."));
263*0Sstevel@tonic-gate 		else {
264*0Sstevel@tonic-gate 			portid = ddi_prop_get_int(DDI_DEV_T_ANY, dev,
265*0Sstevel@tonic-gate 			    DDI_PROP_DONTPASS, "portid", -1);
266*0Sstevel@tonic-gate 			nodeid = ddi_prop_get_int(DDI_DEV_T_ANY, dev,
267*0Sstevel@tonic-gate 			    DDI_PROP_DONTPASS, "nodeid", -1);
268*0Sstevel@tonic-gate 			if (portid == -1 && nodeid == -1)
269*0Sstevel@tonic-gate 				printf("could not find portid "
270*0Sstevel@tonic-gate 				    "or nodeid property in %s\n",
271*0Sstevel@tonic-gate 				    DEVI(dev)->devi_node_name);
272*0Sstevel@tonic-gate 
273*0Sstevel@tonic-gate 			if (portid != -1)
274*0Sstevel@tonic-gate 				(void) sprintf(p, "SAFARI 0x%x 0x%x%s",
275*0Sstevel@tonic-gate 				    portid,
276*0Sstevel@tonic-gate 				    rp->regspec_addr &
277*0Sstevel@tonic-gate 				    root_phys_addr_lo_mask,
278*0Sstevel@tonic-gate 				    (n > 1 ? "" : " ..."));
279*0Sstevel@tonic-gate 			if (nodeid != -1)
280*0Sstevel@tonic-gate 				(void) sprintf(p, "SSM Node %d", nodeid);
281*0Sstevel@tonic-gate 		}
282*0Sstevel@tonic-gate 		p += strlen(p);
283*0Sstevel@tonic-gate 	}
284*0Sstevel@tonic-gate 
285*0Sstevel@tonic-gate 	/*
286*0Sstevel@tonic-gate 	 * This is where we need to print out the interrupt specifications
287*0Sstevel@tonic-gate 	 * for the FFB device and any UPA add-on devices.  Not sure how to
288*0Sstevel@tonic-gate 	 * do this yet?
289*0Sstevel@tonic-gate 	 */
290*0Sstevel@tonic-gate 	cmn_err(CE_CONT, "?%s\n", buf);
291*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
292*0Sstevel@tonic-gate }
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate int
295*0Sstevel@tonic-gate rootnex_name_child_impl(dev_info_t *child, char *name, int namelen)
296*0Sstevel@tonic-gate {
297*0Sstevel@tonic-gate 	struct ddi_parent_private_data *pdptr;
298*0Sstevel@tonic-gate 	int portid, nodeid;
299*0Sstevel@tonic-gate 	char *node_name;
300*0Sstevel@tonic-gate 	struct regspec *rp;
301*0Sstevel@tonic-gate 
302*0Sstevel@tonic-gate 	extern uint_t root_phys_addr_lo_mask;
303*0Sstevel@tonic-gate 	extern void make_ddi_ppd(
304*0Sstevel@tonic-gate 	    dev_info_t *, struct ddi_parent_private_data **);
305*0Sstevel@tonic-gate 
306*0Sstevel@tonic-gate 	/*
307*0Sstevel@tonic-gate 	 * Fill in parent-private data and this function returns to us
308*0Sstevel@tonic-gate 	 * an indication if it used "registers" to fill in the data.
309*0Sstevel@tonic-gate 	 */
310*0Sstevel@tonic-gate 	if (ddi_get_parent_data(child) == NULL) {
311*0Sstevel@tonic-gate 		make_ddi_ppd(child, &pdptr);
312*0Sstevel@tonic-gate 		ddi_set_parent_data(child, pdptr);
313*0Sstevel@tonic-gate 	}
314*0Sstevel@tonic-gate 
315*0Sstevel@tonic-gate 	/*
316*0Sstevel@tonic-gate 	 * No reg property, return null string as address (e.g. pseudo)
317*0Sstevel@tonic-gate 	 */
318*0Sstevel@tonic-gate 	name[0] = '\0';
319*0Sstevel@tonic-gate 	if (sparc_pd_getnreg(child) == 0) {
320*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
321*0Sstevel@tonic-gate 	}
322*0Sstevel@tonic-gate 	rp = sparc_pd_getreg(child, 0);
323*0Sstevel@tonic-gate 	ASSERT(rp != NULL);
324*0Sstevel@tonic-gate 
325*0Sstevel@tonic-gate 	/*
326*0Sstevel@tonic-gate 	 * Create portid property for fhc node under root(/fhc).
327*0Sstevel@tonic-gate 	 */
328*0Sstevel@tonic-gate 	node_name = ddi_node_name(child);
329*0Sstevel@tonic-gate 	if ((strcmp(node_name, "fhc") == 0) ||
330*0Sstevel@tonic-gate 	    (strcmp(node_name, "mem-unit") == 0) ||
331*0Sstevel@tonic-gate 	    (strcmp(node_name, "central") == 0)) {
332*0Sstevel@tonic-gate #ifdef  _STARFIRE
333*0Sstevel@tonic-gate 		portid = ((((rp->regspec_bustype) & 0x6) >> 1) |
334*0Sstevel@tonic-gate 		    (((rp->regspec_bustype) & 0xF0) >> 2) |
335*0Sstevel@tonic-gate 		    (((rp->regspec_bustype) & 0x8) << 3));
336*0Sstevel@tonic-gate #else
337*0Sstevel@tonic-gate 		portid = (rp->regspec_bustype >> 1) & 0x1f;
338*0Sstevel@tonic-gate #endif
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate 		/*
341*0Sstevel@tonic-gate 		 * The port-id must go on the hardware property list,
342*0Sstevel@tonic-gate 		 * otherwise, initchild may fail.
343*0Sstevel@tonic-gate 		 */
344*0Sstevel@tonic-gate 		if (ndi_prop_update_int(DDI_DEV_T_NONE, child, "upa-portid",
345*0Sstevel@tonic-gate 		    portid) != DDI_SUCCESS)
346*0Sstevel@tonic-gate 			cmn_err(CE_WARN,
347*0Sstevel@tonic-gate 			    "Error in creating upa-portid property for fhc.\n");
348*0Sstevel@tonic-gate 	}
349*0Sstevel@tonic-gate 
350*0Sstevel@tonic-gate 	/*
351*0Sstevel@tonic-gate 	 * Name node on behalf of child nexus.
352*0Sstevel@tonic-gate 	 */
353*0Sstevel@tonic-gate 	if (ddi_get_parent(child) != ddi_root_node()) {
354*0Sstevel@tonic-gate 		(void) snprintf(name, namelen, "%x,%x",
355*0Sstevel@tonic-gate 		    rp->regspec_bustype, rp->regspec_addr);
356*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
357*0Sstevel@tonic-gate 	}
358*0Sstevel@tonic-gate 
359*0Sstevel@tonic-gate 	/*
360*0Sstevel@tonic-gate 	 * On sun4u, the 'name' of children of the root node
361*0Sstevel@tonic-gate 	 * is foo@<upa-mid>,<offset>, which is derived from,
362*0Sstevel@tonic-gate 	 * but not identical to the physical address.
363*0Sstevel@tonic-gate 	 */
364*0Sstevel@tonic-gate 	portid = ddi_prop_get_int(DDI_DEV_T_ANY, child,
365*0Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "upa-portid", -1);
366*0Sstevel@tonic-gate 	if (portid == -1)
367*0Sstevel@tonic-gate 		portid = ddi_prop_get_int(DDI_DEV_T_ANY, child,
368*0Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, "portid", -1);
369*0Sstevel@tonic-gate 	nodeid = ddi_prop_get_int(DDI_DEV_T_ANY, child,
370*0Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "nodeid", -1);
371*0Sstevel@tonic-gate 
372*0Sstevel@tonic-gate 	/*
373*0Sstevel@tonic-gate 	 * Do not log message, to handle cases where OBP version
374*0Sstevel@tonic-gate 	 * does not have "portid" property for the root i2c node.
375*0Sstevel@tonic-gate 	 *
376*0Sstevel@tonic-gate 	 * Platforms supporting root i2c node (potentially without
377*0Sstevel@tonic-gate 	 * "portid" property) are :
378*0Sstevel@tonic-gate 	 *	SunBlade 1500, SunBlade 2500, V240, V250
379*0Sstevel@tonic-gate 	 */
380*0Sstevel@tonic-gate 	if (portid == -1 && nodeid == -1 &&
381*0Sstevel@tonic-gate 	    strncmp(node_name, "i2c", strlen("i2c")) != 0)
382*0Sstevel@tonic-gate 		cmn_err(CE_WARN,
383*0Sstevel@tonic-gate 		    "could not find portid or nodeid property in %s\n",
384*0Sstevel@tonic-gate 		    DEVI(child)->devi_node_name);
385*0Sstevel@tonic-gate 	if (nodeid != -1)
386*0Sstevel@tonic-gate 		(void) snprintf(name, namelen, "%x,0", nodeid);
387*0Sstevel@tonic-gate 	else
388*0Sstevel@tonic-gate 		(void) snprintf(name, namelen, "%x,%x", portid,
389*0Sstevel@tonic-gate 		    rp->regspec_addr & root_phys_addr_lo_mask);
390*0Sstevel@tonic-gate 
391*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
392*0Sstevel@tonic-gate }
393*0Sstevel@tonic-gate 
394*0Sstevel@tonic-gate int
395*0Sstevel@tonic-gate rootnex_ctl_initchild_impl(dev_info_t *dip)
396*0Sstevel@tonic-gate {
397*0Sstevel@tonic-gate 	struct regspec *rp;
398*0Sstevel@tonic-gate 	struct ddi_parent_private_data *pd;
399*0Sstevel@tonic-gate 	char name[MAXNAMELEN];
400*0Sstevel@tonic-gate 
401*0Sstevel@tonic-gate 	extern struct ddi_parent_private_data *init_regspec_64(dev_info_t *dip);
402*0Sstevel@tonic-gate 
403*0Sstevel@tonic-gate 	/* Name the child */
404*0Sstevel@tonic-gate 	(void) rootnex_name_child(dip, name, MAXNAMELEN);
405*0Sstevel@tonic-gate 	ddi_set_name_addr(dip, name);
406*0Sstevel@tonic-gate 
407*0Sstevel@tonic-gate 	/*
408*0Sstevel@tonic-gate 	 * Try to merge .conf node. If merge is successful, return
409*0Sstevel@tonic-gate 	 * DDI_FAILURE to allow caller to remove this node.
410*0Sstevel@tonic-gate 	 */
411*0Sstevel@tonic-gate 	if (ndi_dev_is_persistent_node(dip) == 0 &&
412*0Sstevel@tonic-gate 	    (ndi_merge_node(dip, rootnex_name_child) == DDI_SUCCESS)) {
413*0Sstevel@tonic-gate 		(void) rootnex_ctl_uninitchild(dip);
414*0Sstevel@tonic-gate 		return (DDI_FAILURE);
415*0Sstevel@tonic-gate 	}
416*0Sstevel@tonic-gate 
417*0Sstevel@tonic-gate 	/*
418*0Sstevel@tonic-gate 	 * If there are no "reg"s in the child node, return.
419*0Sstevel@tonic-gate 	 */
420*0Sstevel@tonic-gate 	pd = init_regspec_64(dip);
421*0Sstevel@tonic-gate 	if ((pd == NULL) || (pd->par_nreg == 0))
422*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
423*0Sstevel@tonic-gate 
424*0Sstevel@tonic-gate 	/*
425*0Sstevel@tonic-gate 	 * If this is a slave device sitting on the UPA, we assume that
426*0Sstevel@tonic-gate 	 * This device can accept DMA accesses from other devices.  We need
427*0Sstevel@tonic-gate 	 * to register this fact with the system by using the highest
428*0Sstevel@tonic-gate 	 * and lowest physical pfns of the devices register space.  This
429*0Sstevel@tonic-gate 	 * will then represent a physical block of addresses that are valid
430*0Sstevel@tonic-gate 	 * for DMA accesses.
431*0Sstevel@tonic-gate 	 */
432*0Sstevel@tonic-gate 	if ((ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "upa-portid",
433*0Sstevel@tonic-gate 	    -1) != -1) && ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
434*0Sstevel@tonic-gate 	    "upa-interrupt-slave", 0)) {
435*0Sstevel@tonic-gate 		pfn_t lopfn = (pfn_t)-1;
436*0Sstevel@tonic-gate 		pfn_t hipfn = 0;
437*0Sstevel@tonic-gate 		int i;
438*0Sstevel@tonic-gate 		extern void pf_set_dmacapable(pfn_t, pfn_t);
439*0Sstevel@tonic-gate 
440*0Sstevel@tonic-gate 		/* Scan the devices highest and lowest physical pfns */
441*0Sstevel@tonic-gate 		for (i = 0, rp = pd->par_reg; i < pd->par_nreg; i++, rp++) {
442*0Sstevel@tonic-gate 			uint64_t addr;
443*0Sstevel@tonic-gate 			pfn_t tmphipfn, tmplopfn;
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate 			addr = (unsigned long long)((unsigned long long)
446*0Sstevel@tonic-gate 			    rp->regspec_bustype << 32);
447*0Sstevel@tonic-gate 			addr |= (uint64_t)rp->regspec_addr;
448*0Sstevel@tonic-gate 			tmplopfn = (pfn_t)(addr >> MMU_PAGESHIFT);
449*0Sstevel@tonic-gate 			addr += (uint64_t)(rp->regspec_size - 1);
450*0Sstevel@tonic-gate 			tmphipfn = (pfn_t)(addr >> MMU_PAGESHIFT);
451*0Sstevel@tonic-gate 
452*0Sstevel@tonic-gate 			hipfn = (tmphipfn > hipfn) ? tmphipfn : hipfn;
453*0Sstevel@tonic-gate 			lopfn = (tmplopfn < lopfn) ? tmplopfn : lopfn;
454*0Sstevel@tonic-gate 		}
455*0Sstevel@tonic-gate 		pf_set_dmacapable(hipfn, lopfn);
456*0Sstevel@tonic-gate 	}
457*0Sstevel@tonic-gate 
458*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
459*0Sstevel@tonic-gate }
460*0Sstevel@tonic-gate 
461*0Sstevel@tonic-gate void
462*0Sstevel@tonic-gate rootnex_ctl_uninitchild_impl(dev_info_t *dip)
463*0Sstevel@tonic-gate {
464*0Sstevel@tonic-gate 	if ((ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "upa-portid",
465*0Sstevel@tonic-gate 	    -1) != -1) && (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
466*0Sstevel@tonic-gate 	    "upa-interrupt-slave", 0))) {
467*0Sstevel@tonic-gate 		struct regspec *rp;
468*0Sstevel@tonic-gate 		extern void pf_unset_dmacapable(pfn_t);
469*0Sstevel@tonic-gate 		unsigned long long addr;
470*0Sstevel@tonic-gate 		pfn_t pfn;
471*0Sstevel@tonic-gate 		struct ddi_parent_private_data *pd;
472*0Sstevel@tonic-gate 
473*0Sstevel@tonic-gate 		pd = ddi_get_parent_data(dip);
474*0Sstevel@tonic-gate 		ASSERT(pd != NULL);
475*0Sstevel@tonic-gate 		rp = pd->par_reg;
476*0Sstevel@tonic-gate 		addr = (unsigned long long) ((unsigned long long)
477*0Sstevel@tonic-gate 		    rp->regspec_bustype << 32);
478*0Sstevel@tonic-gate 		addr |= (unsigned long long) rp->regspec_addr;
479*0Sstevel@tonic-gate 		pfn = (pfn_t)(addr >> MMU_PAGESHIFT);
480*0Sstevel@tonic-gate 
481*0Sstevel@tonic-gate 		pf_unset_dmacapable(pfn);
482*0Sstevel@tonic-gate 	}
483*0Sstevel@tonic-gate }
484