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  * sun4 specific DDI implementation
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate #include <sys/cpuvar.h>
33*0Sstevel@tonic-gate #include <sys/ddi_subrdefs.h>
34*0Sstevel@tonic-gate #include <sys/machsystm.h>
35*0Sstevel@tonic-gate #include <sys/sunndi.h>
36*0Sstevel@tonic-gate #include <sys/sysmacros.h>
37*0Sstevel@tonic-gate #include <sys/ontrap.h>
38*0Sstevel@tonic-gate #include <vm/seg_kmem.h>
39*0Sstevel@tonic-gate #include <sys/membar.h>
40*0Sstevel@tonic-gate #include <sys/dditypes.h>
41*0Sstevel@tonic-gate #include <sys/ndifm.h>
42*0Sstevel@tonic-gate #include <sys/fm/io/ddi.h>
43*0Sstevel@tonic-gate #include <sys/ivintr.h>
44*0Sstevel@tonic-gate #include <sys/bootconf.h>
45*0Sstevel@tonic-gate #include <sys/conf.h>
46*0Sstevel@tonic-gate #include <sys/ethernet.h>
47*0Sstevel@tonic-gate #include <sys/idprom.h>
48*0Sstevel@tonic-gate #include <sys/promif.h>
49*0Sstevel@tonic-gate #include <sys/prom_plat.h>
50*0Sstevel@tonic-gate #include <sys/systeminfo.h>
51*0Sstevel@tonic-gate #include <sys/fpu/fpusystm.h>
52*0Sstevel@tonic-gate #include <sys/vm.h>
53*0Sstevel@tonic-gate #include <sys/fs/dv_node.h>
54*0Sstevel@tonic-gate #include <sys/fs/snode.h>
55*0Sstevel@tonic-gate #include <sys/ddi_isa.h>
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate dev_info_t *get_intr_parent(dev_info_t *, dev_info_t *,
58*0Sstevel@tonic-gate     ddi_ispec_t *, ddi_ispec_t **);
59*0Sstevel@tonic-gate #pragma weak get_intr_parent
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate int process_intr_ops(dev_info_t *, dev_info_t *, ddi_intr_op_t,
62*0Sstevel@tonic-gate     ddi_intr_handle_impl_t *, void *);
63*0Sstevel@tonic-gate #pragma weak process_intr_ops
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate void cells_1275_copy(prop_1275_cell_t *, prop_1275_cell_t *, int32_t);
66*0Sstevel@tonic-gate     prop_1275_cell_t *cells_1275_cmp(prop_1275_cell_t *, prop_1275_cell_t *,
67*0Sstevel@tonic-gate     int32_t len);
68*0Sstevel@tonic-gate #pragma weak cells_1275_copy
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate /*
71*0Sstevel@tonic-gate  * Wrapper for ddi_prop_lookup_int_array().
72*0Sstevel@tonic-gate  * This is handy because it returns the prop length in
73*0Sstevel@tonic-gate  * bytes which is what most of the callers require.
74*0Sstevel@tonic-gate  */
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate static int
77*0Sstevel@tonic-gate get_prop_int_array(dev_info_t *di, char *pname, int **pval, uint_t *plen)
78*0Sstevel@tonic-gate {
79*0Sstevel@tonic-gate 	int ret;
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate 	if ((ret = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, di,
82*0Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, pname, pval, plen)) == DDI_PROP_SUCCESS) {
83*0Sstevel@tonic-gate 		*plen = (*plen) * (uint_t)sizeof (int);
84*0Sstevel@tonic-gate 	}
85*0Sstevel@tonic-gate 	return (ret);
86*0Sstevel@tonic-gate }
87*0Sstevel@tonic-gate 
88*0Sstevel@tonic-gate /*
89*0Sstevel@tonic-gate  * SECTION: DDI Node Configuration
90*0Sstevel@tonic-gate  */
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate /*
93*0Sstevel@tonic-gate  * init_regspec_64:
94*0Sstevel@tonic-gate  *
95*0Sstevel@tonic-gate  * If the parent #size-cells is 2, convert the upa-style or
96*0Sstevel@tonic-gate  * safari-style reg property from 2-size cells to 1 size cell
97*0Sstevel@tonic-gate  * format, ignoring the size_hi, which must be zero for devices.
98*0Sstevel@tonic-gate  * (It won't be zero in the memory list properties in the memory
99*0Sstevel@tonic-gate  * nodes, but that doesn't matter here.)
100*0Sstevel@tonic-gate  */
101*0Sstevel@tonic-gate struct ddi_parent_private_data *
102*0Sstevel@tonic-gate init_regspec_64(dev_info_t *dip)
103*0Sstevel@tonic-gate {
104*0Sstevel@tonic-gate 	struct ddi_parent_private_data *pd;
105*0Sstevel@tonic-gate 	dev_info_t *parent;
106*0Sstevel@tonic-gate 	int size_cells;
107*0Sstevel@tonic-gate 
108*0Sstevel@tonic-gate 	/*
109*0Sstevel@tonic-gate 	 * If there are no "reg"s in the child node, return.
110*0Sstevel@tonic-gate 	 */
111*0Sstevel@tonic-gate 	pd = ddi_get_parent_data(dip);
112*0Sstevel@tonic-gate 	if ((pd == NULL) || (pd->par_nreg == 0)) {
113*0Sstevel@tonic-gate 		return (pd);
114*0Sstevel@tonic-gate 	}
115*0Sstevel@tonic-gate 	parent = ddi_get_parent(dip);
116*0Sstevel@tonic-gate 
117*0Sstevel@tonic-gate 	size_cells = ddi_prop_get_int(DDI_DEV_T_ANY, parent,
118*0Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "#size-cells", 1);
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate 	if (size_cells != 1)  {
121*0Sstevel@tonic-gate 
122*0Sstevel@tonic-gate 		int n, j;
123*0Sstevel@tonic-gate 		struct regspec *irp;
124*0Sstevel@tonic-gate 		struct reg_64 {
125*0Sstevel@tonic-gate 			uint_t addr_hi, addr_lo, size_hi, size_lo;
126*0Sstevel@tonic-gate 		};
127*0Sstevel@tonic-gate 		struct reg_64 *r64_rp;
128*0Sstevel@tonic-gate 		struct regspec *rp;
129*0Sstevel@tonic-gate 		uint_t len = 0;
130*0Sstevel@tonic-gate 		int *reg_prop;
131*0Sstevel@tonic-gate 
132*0Sstevel@tonic-gate 		ASSERT(size_cells == 2);
133*0Sstevel@tonic-gate 
134*0Sstevel@tonic-gate 		/*
135*0Sstevel@tonic-gate 		 * We already looked the property up once before if
136*0Sstevel@tonic-gate 		 * pd is non-NULL.
137*0Sstevel@tonic-gate 		 */
138*0Sstevel@tonic-gate 		(void) ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
139*0Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, OBP_REG, &reg_prop, &len);
140*0Sstevel@tonic-gate 		ASSERT(len != 0);
141*0Sstevel@tonic-gate 
142*0Sstevel@tonic-gate 		n = sizeof (struct reg_64) / sizeof (int);
143*0Sstevel@tonic-gate 		n = len / n;
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate 		/*
146*0Sstevel@tonic-gate 		 * We're allocating a buffer the size of the PROM's property,
147*0Sstevel@tonic-gate 		 * but we're only using a smaller portion when we assign it
148*0Sstevel@tonic-gate 		 * to a regspec.  We do this so that in the
149*0Sstevel@tonic-gate 		 * impl_ddi_sunbus_removechild function, we will
150*0Sstevel@tonic-gate 		 * always free the right amount of memory.
151*0Sstevel@tonic-gate 		 */
152*0Sstevel@tonic-gate 		irp = rp = (struct regspec *)reg_prop;
153*0Sstevel@tonic-gate 		r64_rp = (struct reg_64 *)pd->par_reg;
154*0Sstevel@tonic-gate 
155*0Sstevel@tonic-gate 		for (j = 0; j < n; ++j, ++rp, ++r64_rp) {
156*0Sstevel@tonic-gate 			ASSERT(r64_rp->size_hi == 0);
157*0Sstevel@tonic-gate 			rp->regspec_bustype = r64_rp->addr_hi;
158*0Sstevel@tonic-gate 			rp->regspec_addr = r64_rp->addr_lo;
159*0Sstevel@tonic-gate 			rp->regspec_size = r64_rp->size_lo;
160*0Sstevel@tonic-gate 		}
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate 		ddi_prop_free((void *)pd->par_reg);
163*0Sstevel@tonic-gate 		pd->par_nreg = n;
164*0Sstevel@tonic-gate 		pd->par_reg = irp;
165*0Sstevel@tonic-gate 	}
166*0Sstevel@tonic-gate 	return (pd);
167*0Sstevel@tonic-gate }
168*0Sstevel@tonic-gate 
169*0Sstevel@tonic-gate /*
170*0Sstevel@tonic-gate  * Create a ddi_parent_private_data structure from the ddi properties of
171*0Sstevel@tonic-gate  * the dev_info node.
172*0Sstevel@tonic-gate  *
173*0Sstevel@tonic-gate  * The "reg" is required if the driver wishes to create mappings on behalf
174*0Sstevel@tonic-gate  * of the device. The "reg" property is assumed to be a list of at least
175*0Sstevel@tonic-gate  * one triplet
176*0Sstevel@tonic-gate  *
177*0Sstevel@tonic-gate  *	<bustype, address, size>*1
178*0Sstevel@tonic-gate  *
179*0Sstevel@tonic-gate  * The "interrupt" property is no longer part of parent private data on
180*0Sstevel@tonic-gate  * sun4u. The interrupt parent is may not be the device tree parent.
181*0Sstevel@tonic-gate  *
182*0Sstevel@tonic-gate  * The "ranges" property describes the mapping of child addresses to parent
183*0Sstevel@tonic-gate  * addresses.
184*0Sstevel@tonic-gate  *
185*0Sstevel@tonic-gate  * N.B. struct rangespec is defined for the following default values:
186*0Sstevel@tonic-gate  *			parent  child
187*0Sstevel@tonic-gate  *	#address-cells	2	2
188*0Sstevel@tonic-gate  *	#size-cells	1	1
189*0Sstevel@tonic-gate  * This function doesn't deal with non-default cells and will not create
190*0Sstevel@tonic-gate  * ranges in such cases.
191*0Sstevel@tonic-gate  */
192*0Sstevel@tonic-gate void
193*0Sstevel@tonic-gate make_ddi_ppd(dev_info_t *child, struct ddi_parent_private_data **ppd)
194*0Sstevel@tonic-gate {
195*0Sstevel@tonic-gate 	struct ddi_parent_private_data *pdptr;
196*0Sstevel@tonic-gate 	int *reg_prop, *rng_prop;
197*0Sstevel@tonic-gate 	uint_t reg_len = 0, rng_len = 0;
198*0Sstevel@tonic-gate 	dev_info_t *parent;
199*0Sstevel@tonic-gate 	int parent_addr_cells, parent_size_cells;
200*0Sstevel@tonic-gate 	int child_addr_cells, child_size_cells;
201*0Sstevel@tonic-gate 
202*0Sstevel@tonic-gate 	*ppd = pdptr = kmem_zalloc(sizeof (*pdptr), KM_SLEEP);
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate 	/*
205*0Sstevel@tonic-gate 	 * root node has no parent private data, so *ppd should
206*0Sstevel@tonic-gate 	 * be initialized for naming to work properly.
207*0Sstevel@tonic-gate 	 */
208*0Sstevel@tonic-gate 	if ((parent = ddi_get_parent(child)) == NULL)
209*0Sstevel@tonic-gate 		return;
210*0Sstevel@tonic-gate 
211*0Sstevel@tonic-gate 	/*
212*0Sstevel@tonic-gate 	 * Set reg field of parent data from "reg" property
213*0Sstevel@tonic-gate 	 */
214*0Sstevel@tonic-gate 	if ((get_prop_int_array(child, OBP_REG, &reg_prop, &reg_len)
215*0Sstevel@tonic-gate 	    == DDI_PROP_SUCCESS) && (reg_len != 0)) {
216*0Sstevel@tonic-gate 		pdptr->par_nreg = (int)(reg_len / sizeof (struct regspec));
217*0Sstevel@tonic-gate 		pdptr->par_reg = (struct regspec *)reg_prop;
218*0Sstevel@tonic-gate 	}
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate 	/*
221*0Sstevel@tonic-gate 	 * "ranges" property ...
222*0Sstevel@tonic-gate 	 *
223*0Sstevel@tonic-gate 	 * This function does not handle cases where #address-cells != 2
224*0Sstevel@tonic-gate 	 * and * min(parent, child) #size-cells != 1 (see bugid 4211124).
225*0Sstevel@tonic-gate 	 *
226*0Sstevel@tonic-gate 	 * Nexus drivers with such exceptions (e.g. pci ranges)
227*0Sstevel@tonic-gate 	 * should either create a separate function for handling
228*0Sstevel@tonic-gate 	 * ranges or not use parent private data to store ranges.
229*0Sstevel@tonic-gate 	 */
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate 	/* root node has no ranges */
232*0Sstevel@tonic-gate 	if ((parent = ddi_get_parent(child)) == NULL)
233*0Sstevel@tonic-gate 		return;
234*0Sstevel@tonic-gate 
235*0Sstevel@tonic-gate 	child_addr_cells = ddi_prop_get_int(DDI_DEV_T_ANY, child,
236*0Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "#address-cells", 2);
237*0Sstevel@tonic-gate 	child_size_cells = ddi_prop_get_int(DDI_DEV_T_ANY, child,
238*0Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "#size-cells", 1);
239*0Sstevel@tonic-gate 	parent_addr_cells = ddi_prop_get_int(DDI_DEV_T_ANY, parent,
240*0Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "#address-cells", 2);
241*0Sstevel@tonic-gate 	parent_size_cells = ddi_prop_get_int(DDI_DEV_T_ANY, parent,
242*0Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "#size-cells", 1);
243*0Sstevel@tonic-gate 	if (child_addr_cells != 2 || parent_addr_cells != 2 ||
244*0Sstevel@tonic-gate 	    (child_size_cells != 1 && parent_size_cells != 1)) {
245*0Sstevel@tonic-gate 		NDI_CONFIG_DEBUG((CE_NOTE, "!ranges not made in parent data; "
246*0Sstevel@tonic-gate 		    "#address-cells or #size-cells have non-default value"));
247*0Sstevel@tonic-gate 		return;
248*0Sstevel@tonic-gate 	}
249*0Sstevel@tonic-gate 
250*0Sstevel@tonic-gate 	if (get_prop_int_array(child, OBP_RANGES, &rng_prop, &rng_len)
251*0Sstevel@tonic-gate 	    == DDI_PROP_SUCCESS) {
252*0Sstevel@tonic-gate 		pdptr->par_nrng = rng_len / (int)(sizeof (struct rangespec));
253*0Sstevel@tonic-gate 		pdptr->par_rng = (struct rangespec *)rng_prop;
254*0Sstevel@tonic-gate 	}
255*0Sstevel@tonic-gate }
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate /*
258*0Sstevel@tonic-gate  * Free ddi_parent_private_data structure
259*0Sstevel@tonic-gate  */
260*0Sstevel@tonic-gate void
261*0Sstevel@tonic-gate impl_free_ddi_ppd(dev_info_t *dip)
262*0Sstevel@tonic-gate {
263*0Sstevel@tonic-gate 	struct ddi_parent_private_data *pdptr = ddi_get_parent_data(dip);
264*0Sstevel@tonic-gate 
265*0Sstevel@tonic-gate 	if (pdptr == NULL)
266*0Sstevel@tonic-gate 		return;
267*0Sstevel@tonic-gate 
268*0Sstevel@tonic-gate 	if (pdptr->par_nrng != 0)
269*0Sstevel@tonic-gate 		ddi_prop_free((void *)pdptr->par_rng);
270*0Sstevel@tonic-gate 
271*0Sstevel@tonic-gate 	if (pdptr->par_nreg != 0)
272*0Sstevel@tonic-gate 		ddi_prop_free((void *)pdptr->par_reg);
273*0Sstevel@tonic-gate 
274*0Sstevel@tonic-gate 	kmem_free(pdptr, sizeof (*pdptr));
275*0Sstevel@tonic-gate 	ddi_set_parent_data(dip, NULL);
276*0Sstevel@tonic-gate }
277*0Sstevel@tonic-gate 
278*0Sstevel@tonic-gate /*
279*0Sstevel@tonic-gate  * Name a child of sun busses based on the reg spec.
280*0Sstevel@tonic-gate  * Handles the following properties:
281*0Sstevel@tonic-gate  *
282*0Sstevel@tonic-gate  *	Property	value
283*0Sstevel@tonic-gate  *	Name		type
284*0Sstevel@tonic-gate  *
285*0Sstevel@tonic-gate  *	reg		register spec
286*0Sstevel@tonic-gate  *	interrupts	new (bus-oriented) interrupt spec
287*0Sstevel@tonic-gate  *	ranges		range spec
288*0Sstevel@tonic-gate  *
289*0Sstevel@tonic-gate  * This may be called multiple times, independent of
290*0Sstevel@tonic-gate  * initchild calls.
291*0Sstevel@tonic-gate  */
292*0Sstevel@tonic-gate static int
293*0Sstevel@tonic-gate impl_sunbus_name_child(dev_info_t *child, char *name, int namelen)
294*0Sstevel@tonic-gate {
295*0Sstevel@tonic-gate 	struct ddi_parent_private_data *pdptr;
296*0Sstevel@tonic-gate 	struct regspec *rp;
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate 	/*
299*0Sstevel@tonic-gate 	 * Fill in parent-private data and this function returns to us
300*0Sstevel@tonic-gate 	 * an indication if it used "registers" to fill in the data.
301*0Sstevel@tonic-gate 	 */
302*0Sstevel@tonic-gate 	if (ddi_get_parent_data(child) == NULL) {
303*0Sstevel@tonic-gate 		make_ddi_ppd(child, &pdptr);
304*0Sstevel@tonic-gate 		ddi_set_parent_data(child, pdptr);
305*0Sstevel@tonic-gate 	}
306*0Sstevel@tonic-gate 
307*0Sstevel@tonic-gate 	/*
308*0Sstevel@tonic-gate 	 * No reg property, return null string as address
309*0Sstevel@tonic-gate 	 * (e.g. root node)
310*0Sstevel@tonic-gate 	 */
311*0Sstevel@tonic-gate 	name[0] = '\0';
312*0Sstevel@tonic-gate 	if (sparc_pd_getnreg(child) == 0) {
313*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
314*0Sstevel@tonic-gate 	}
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate 	rp = sparc_pd_getreg(child, 0);
317*0Sstevel@tonic-gate 	(void) snprintf(name, namelen, "%x,%x",
318*0Sstevel@tonic-gate 	    rp->regspec_bustype, rp->regspec_addr);
319*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
320*0Sstevel@tonic-gate }
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate 
323*0Sstevel@tonic-gate /*
324*0Sstevel@tonic-gate  * Called from the bus_ctl op of some drivers.
325*0Sstevel@tonic-gate  * to implement the DDI_CTLOPS_INITCHILD operation.
326*0Sstevel@tonic-gate  *
327*0Sstevel@tonic-gate  * NEW drivers should NOT use this function, but should declare
328*0Sstevel@tonic-gate  * there own initchild/uninitchild handlers. (This function assumes
329*0Sstevel@tonic-gate  * the layout of the parent private data and the format of "reg",
330*0Sstevel@tonic-gate  * "ranges", "interrupts" properties and that #address-cells and
331*0Sstevel@tonic-gate  * #size-cells of the parent bus are defined to be default values.)
332*0Sstevel@tonic-gate  */
333*0Sstevel@tonic-gate int
334*0Sstevel@tonic-gate impl_ddi_sunbus_initchild(dev_info_t *child)
335*0Sstevel@tonic-gate {
336*0Sstevel@tonic-gate 	char name[MAXNAMELEN];
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate 	(void) impl_sunbus_name_child(child, name, MAXNAMELEN);
339*0Sstevel@tonic-gate 	ddi_set_name_addr(child, name);
340*0Sstevel@tonic-gate 
341*0Sstevel@tonic-gate 	/*
342*0Sstevel@tonic-gate 	 * Try to merge .conf node. If successful, return failure to
343*0Sstevel@tonic-gate 	 * remove this child.
344*0Sstevel@tonic-gate 	 */
345*0Sstevel@tonic-gate 	if ((ndi_dev_is_persistent_node(child) == 0) &&
346*0Sstevel@tonic-gate 	    (ndi_merge_node(child, impl_sunbus_name_child) == DDI_SUCCESS)) {
347*0Sstevel@tonic-gate 		impl_ddi_sunbus_removechild(child);
348*0Sstevel@tonic-gate 		return (DDI_FAILURE);
349*0Sstevel@tonic-gate 	}
350*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
351*0Sstevel@tonic-gate }
352*0Sstevel@tonic-gate 
353*0Sstevel@tonic-gate /*
354*0Sstevel@tonic-gate  * A better name for this function would be impl_ddi_sunbus_uninitchild()
355*0Sstevel@tonic-gate  * It does not remove the child, it uninitializes it, reclaiming the
356*0Sstevel@tonic-gate  * resources taken by impl_ddi_sunbus_initchild.
357*0Sstevel@tonic-gate  */
358*0Sstevel@tonic-gate void
359*0Sstevel@tonic-gate impl_ddi_sunbus_removechild(dev_info_t *dip)
360*0Sstevel@tonic-gate {
361*0Sstevel@tonic-gate 	impl_free_ddi_ppd(dip);
362*0Sstevel@tonic-gate 	ddi_set_name_addr(dip, NULL);
363*0Sstevel@tonic-gate 	/*
364*0Sstevel@tonic-gate 	 * Strip the node to properly convert it back to prototype form
365*0Sstevel@tonic-gate 	 */
366*0Sstevel@tonic-gate 	impl_rem_dev_props(dip);
367*0Sstevel@tonic-gate }
368*0Sstevel@tonic-gate 
369*0Sstevel@tonic-gate /*
370*0Sstevel@tonic-gate  * SECTION: DDI Interrupt
371*0Sstevel@tonic-gate  */
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate void
374*0Sstevel@tonic-gate cells_1275_copy(prop_1275_cell_t *from, prop_1275_cell_t *to, int32_t len)
375*0Sstevel@tonic-gate {
376*0Sstevel@tonic-gate 	int i;
377*0Sstevel@tonic-gate 	for (i = 0; i < len; i++)
378*0Sstevel@tonic-gate 		*to = *from;
379*0Sstevel@tonic-gate }
380*0Sstevel@tonic-gate 
381*0Sstevel@tonic-gate prop_1275_cell_t *
382*0Sstevel@tonic-gate cells_1275_cmp(prop_1275_cell_t *cell1, prop_1275_cell_t *cell2, int32_t len)
383*0Sstevel@tonic-gate {
384*0Sstevel@tonic-gate 	prop_1275_cell_t *match_cell = 0;
385*0Sstevel@tonic-gate 	int32_t i;
386*0Sstevel@tonic-gate 
387*0Sstevel@tonic-gate 	for (i = 0; i < len; i++)
388*0Sstevel@tonic-gate 		if (cell1[i] != cell2[i]) {
389*0Sstevel@tonic-gate 			match_cell = &cell1[i];
390*0Sstevel@tonic-gate 			break;
391*0Sstevel@tonic-gate 		}
392*0Sstevel@tonic-gate 
393*0Sstevel@tonic-gate 	return (match_cell);
394*0Sstevel@tonic-gate }
395*0Sstevel@tonic-gate 
396*0Sstevel@tonic-gate /*
397*0Sstevel@tonic-gate  * Wrapper functions used by New DDI interrupt framework.
398*0Sstevel@tonic-gate  */
399*0Sstevel@tonic-gate 
400*0Sstevel@tonic-gate /*
401*0Sstevel@tonic-gate  * i_ddi_handle_intr_ops:
402*0Sstevel@tonic-gate  */
403*0Sstevel@tonic-gate int
404*0Sstevel@tonic-gate i_ddi_handle_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t op,
405*0Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result)
406*0Sstevel@tonic-gate {
407*0Sstevel@tonic-gate 	ddi_intrspec_t		ispec;
408*0Sstevel@tonic-gate 	int			ret;
409*0Sstevel@tonic-gate 
410*0Sstevel@tonic-gate 	if (hdlp->ih_type != DDI_INTR_TYPE_FIXED)
411*0Sstevel@tonic-gate 		return (i_ddi_intr_ops(dip, rdip, op, hdlp, result));
412*0Sstevel@tonic-gate 
413*0Sstevel@tonic-gate 	i_ddi_alloc_ispec(dip, hdlp->ih_inum, &ispec);
414*0Sstevel@tonic-gate 	if ((ddi_ispec_t *)ispec == NULL)
415*0Sstevel@tonic-gate 		return (DDI_FAILURE);
416*0Sstevel@tonic-gate 
417*0Sstevel@tonic-gate 	hdlp->ih_private = (void *)ispec;
418*0Sstevel@tonic-gate 	ret = i_ddi_intr_ops(dip, rdip, op, hdlp, result);
419*0Sstevel@tonic-gate 	hdlp->ih_private = NULL;
420*0Sstevel@tonic-gate 
421*0Sstevel@tonic-gate 	i_ddi_free_ispec(ispec);
422*0Sstevel@tonic-gate 	return (ret);
423*0Sstevel@tonic-gate }
424*0Sstevel@tonic-gate 
425*0Sstevel@tonic-gate /*
426*0Sstevel@tonic-gate  * i_ddi_intr_ops:
427*0Sstevel@tonic-gate  */
428*0Sstevel@tonic-gate int
429*0Sstevel@tonic-gate i_ddi_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t op,
430*0Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result)
431*0Sstevel@tonic-gate {
432*0Sstevel@tonic-gate 	ddi_ispec_t	*sav_ip, *ip = NULL;
433*0Sstevel@tonic-gate 	dev_info_t	*pdip = ddi_get_parent(dip);
434*0Sstevel@tonic-gate 	int		ret = DDI_FAILURE;
435*0Sstevel@tonic-gate 
436*0Sstevel@tonic-gate 	if (hdlp->ih_type != DDI_INTR_TYPE_FIXED)
437*0Sstevel@tonic-gate 		return (process_intr_ops(pdip, rdip, op, hdlp, result));
438*0Sstevel@tonic-gate 
439*0Sstevel@tonic-gate 	switch (op) {
440*0Sstevel@tonic-gate 	case DDI_INTROP_ADDISR:
441*0Sstevel@tonic-gate 	case DDI_INTROP_REMISR:
442*0Sstevel@tonic-gate 	case DDI_INTROP_ENABLE:
443*0Sstevel@tonic-gate 	case DDI_INTROP_DISABLE:
444*0Sstevel@tonic-gate 	case DDI_INTROP_BLOCKENABLE:
445*0Sstevel@tonic-gate 	case DDI_INTROP_BLOCKDISABLE:
446*0Sstevel@tonic-gate 		/* Save the ispec */
447*0Sstevel@tonic-gate 		sav_ip = (ddi_ispec_t *)hdlp->ih_private;
448*0Sstevel@tonic-gate 
449*0Sstevel@tonic-gate 		/*
450*0Sstevel@tonic-gate 		 * If we have an ispec struct, try and determine our
451*0Sstevel@tonic-gate 		 * parent and possibly an interrupt translation.
452*0Sstevel@tonic-gate 		 * intr parent dip returned held
453*0Sstevel@tonic-gate 		 */
454*0Sstevel@tonic-gate 		if ((pdip = get_intr_parent(pdip, dip, sav_ip, &ip)) != NULL) {
455*0Sstevel@tonic-gate 			/* Insert the interrupt info structure */
456*0Sstevel@tonic-gate 			hdlp->ih_private = (void *)ip;
457*0Sstevel@tonic-gate 		} else
458*0Sstevel@tonic-gate 			goto done;
459*0Sstevel@tonic-gate 	}
460*0Sstevel@tonic-gate 
461*0Sstevel@tonic-gate 	ret = process_intr_ops(pdip, rdip, op, hdlp, result);
462*0Sstevel@tonic-gate 
463*0Sstevel@tonic-gate done:
464*0Sstevel@tonic-gate 	switch (op) {
465*0Sstevel@tonic-gate 	case DDI_INTROP_ADDISR:
466*0Sstevel@tonic-gate 	case DDI_INTROP_REMISR:
467*0Sstevel@tonic-gate 	case DDI_INTROP_ENABLE:
468*0Sstevel@tonic-gate 	case DDI_INTROP_DISABLE:
469*0Sstevel@tonic-gate 	case DDI_INTROP_BLOCKENABLE:
470*0Sstevel@tonic-gate 	case DDI_INTROP_BLOCKDISABLE:
471*0Sstevel@tonic-gate 		/* Release hold acquired in get_intr_parent() */
472*0Sstevel@tonic-gate 		if (pdip)
473*0Sstevel@tonic-gate 			ndi_rele_devi(pdip);
474*0Sstevel@tonic-gate 
475*0Sstevel@tonic-gate 		if (ip) {
476*0Sstevel@tonic-gate 			/* Set the PIL according to what the parent did */
477*0Sstevel@tonic-gate 			sav_ip->is_pil = ip->is_pil;
478*0Sstevel@tonic-gate 
479*0Sstevel@tonic-gate 			/* Free the stacked ispec structure */
480*0Sstevel@tonic-gate 			i_ddi_free_ispec((ddi_intrspec_t)ip);
481*0Sstevel@tonic-gate 		}
482*0Sstevel@tonic-gate 
483*0Sstevel@tonic-gate 		/* Restore the interrupt info */
484*0Sstevel@tonic-gate 		hdlp->ih_private = (void *)sav_ip;
485*0Sstevel@tonic-gate 	}
486*0Sstevel@tonic-gate 
487*0Sstevel@tonic-gate 	return (ret);
488*0Sstevel@tonic-gate }
489*0Sstevel@tonic-gate 
490*0Sstevel@tonic-gate /*
491*0Sstevel@tonic-gate  * process_intr_ops:
492*0Sstevel@tonic-gate  *
493*0Sstevel@tonic-gate  * Process the interrupt op via the interrupt parent.
494*0Sstevel@tonic-gate  */
495*0Sstevel@tonic-gate int
496*0Sstevel@tonic-gate process_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t op,
497*0Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result)
498*0Sstevel@tonic-gate {
499*0Sstevel@tonic-gate 	int		ret = DDI_FAILURE;
500*0Sstevel@tonic-gate 
501*0Sstevel@tonic-gate 	if (NEXUS_HAS_INTR_OP(pdip)) {
502*0Sstevel@tonic-gate 		ret = (*(DEVI(pdip)->devi_ops->devo_bus_ops->
503*0Sstevel@tonic-gate 		    bus_intr_op)) (pdip, rdip, op, hdlp, result);
504*0Sstevel@tonic-gate 	} else {
505*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "Failed to process interrupt "
506*0Sstevel@tonic-gate 		    "for %s%d due to down-rev nexus driver %s%d",
507*0Sstevel@tonic-gate 		    ddi_get_name(rdip), ddi_get_instance(rdip),
508*0Sstevel@tonic-gate 		    ddi_get_name(pdip), ddi_get_instance(pdip));
509*0Sstevel@tonic-gate 	}
510*0Sstevel@tonic-gate 
511*0Sstevel@tonic-gate 	return (ret);
512*0Sstevel@tonic-gate }
513*0Sstevel@tonic-gate 
514*0Sstevel@tonic-gate /*
515*0Sstevel@tonic-gate  * i_ddi_add_ivintr:
516*0Sstevel@tonic-gate  */
517*0Sstevel@tonic-gate /*ARGSUSED*/
518*0Sstevel@tonic-gate int
519*0Sstevel@tonic-gate i_ddi_add_ivintr(ddi_intr_handle_impl_t *hdlp)
520*0Sstevel@tonic-gate {
521*0Sstevel@tonic-gate 	/* Sanity check the entry we're about to add */
522*0Sstevel@tonic-gate 	if (GET_IVINTR(hdlp->ih_vector)) {
523*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "mondo 0x%x in use", hdlp->ih_vector);
524*0Sstevel@tonic-gate 		return (DDI_FAILURE);
525*0Sstevel@tonic-gate 	}
526*0Sstevel@tonic-gate 
527*0Sstevel@tonic-gate 	/*
528*0Sstevel@tonic-gate 	 * If the PIL was set and is valid use it, otherwise
529*0Sstevel@tonic-gate 	 * default it to 1
530*0Sstevel@tonic-gate 	 */
531*0Sstevel@tonic-gate 	if ((hdlp->ih_pri < 1) || (hdlp->ih_pri > PIL_MAX))
532*0Sstevel@tonic-gate 		hdlp->ih_pri = 1;
533*0Sstevel@tonic-gate 
534*0Sstevel@tonic-gate 	VERIFY(add_ivintr(hdlp->ih_vector, hdlp->ih_pri,
535*0Sstevel@tonic-gate 	    (intrfunc)hdlp->ih_cb_func, hdlp->ih_cb_arg1, NULL) == 0);
536*0Sstevel@tonic-gate 
537*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
538*0Sstevel@tonic-gate }
539*0Sstevel@tonic-gate 
540*0Sstevel@tonic-gate /*
541*0Sstevel@tonic-gate  * i_ddi_rem_ivintr:
542*0Sstevel@tonic-gate  */
543*0Sstevel@tonic-gate /*ARGSUSED*/
544*0Sstevel@tonic-gate void
545*0Sstevel@tonic-gate i_ddi_rem_ivintr(ddi_intr_handle_impl_t *hdlp)
546*0Sstevel@tonic-gate {
547*0Sstevel@tonic-gate 	rem_ivintr(hdlp->ih_vector, NULL);
548*0Sstevel@tonic-gate }
549*0Sstevel@tonic-gate 
550*0Sstevel@tonic-gate /*
551*0Sstevel@tonic-gate  * i_ddi_add_softint - allocate and add a soft interrupt to the system
552*0Sstevel@tonic-gate  */
553*0Sstevel@tonic-gate int
554*0Sstevel@tonic-gate i_ddi_add_softint(ddi_softint_hdl_impl_t *hdlp)
555*0Sstevel@tonic-gate {
556*0Sstevel@tonic-gate 	uint_t		rval;
557*0Sstevel@tonic-gate 
558*0Sstevel@tonic-gate 	if ((rval = (uint_t)add_softintr(hdlp->ih_pri,
559*0Sstevel@tonic-gate 	    hdlp->ih_cb_func, hdlp->ih_cb_arg1)) == 0) {
560*0Sstevel@tonic-gate 
561*0Sstevel@tonic-gate 		return (DDI_FAILURE);
562*0Sstevel@tonic-gate 	}
563*0Sstevel@tonic-gate 
564*0Sstevel@tonic-gate 	hdlp->ih_private = (void *)rval;
565*0Sstevel@tonic-gate 
566*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
567*0Sstevel@tonic-gate }
568*0Sstevel@tonic-gate 
569*0Sstevel@tonic-gate void
570*0Sstevel@tonic-gate i_ddi_remove_softint(ddi_softint_hdl_impl_t *hdlp)
571*0Sstevel@tonic-gate {
572*0Sstevel@tonic-gate 	uint_t		intr_id;
573*0Sstevel@tonic-gate 
574*0Sstevel@tonic-gate 	/* disable */
575*0Sstevel@tonic-gate 	ASSERT(hdlp->ih_private != NULL);
576*0Sstevel@tonic-gate 	intr_id = (uint_t)hdlp->ih_private;
577*0Sstevel@tonic-gate 	rem_softintr(intr_id);
578*0Sstevel@tonic-gate 	hdlp->ih_private = NULL;
579*0Sstevel@tonic-gate }
580*0Sstevel@tonic-gate 
581*0Sstevel@tonic-gate int
582*0Sstevel@tonic-gate i_ddi_trigger_softint(ddi_softint_hdl_impl_t *hdlp)
583*0Sstevel@tonic-gate {
584*0Sstevel@tonic-gate 	uint_t		intr_id;
585*0Sstevel@tonic-gate 	int		ret;
586*0Sstevel@tonic-gate 
587*0Sstevel@tonic-gate 	ASSERT(hdlp != NULL);
588*0Sstevel@tonic-gate 	ASSERT(hdlp->ih_private != NULL);
589*0Sstevel@tonic-gate 
590*0Sstevel@tonic-gate 	intr_id = (uint_t)hdlp->ih_private;
591*0Sstevel@tonic-gate 
592*0Sstevel@tonic-gate 	/* update the vector table for the 2nd arg */
593*0Sstevel@tonic-gate 	ret = update_softint_arg2(intr_id, hdlp->ih_cb_arg2);
594*0Sstevel@tonic-gate 	if (ret == DDI_SUCCESS)
595*0Sstevel@tonic-gate 		setsoftint(intr_id);
596*0Sstevel@tonic-gate 
597*0Sstevel@tonic-gate 	return (ret);
598*0Sstevel@tonic-gate }
599*0Sstevel@tonic-gate 
600*0Sstevel@tonic-gate /* ARGSUSED */
601*0Sstevel@tonic-gate int
602*0Sstevel@tonic-gate i_ddi_set_softint_pri(ddi_softint_hdl_impl_t *hdlp, uint_t old_pri)
603*0Sstevel@tonic-gate {
604*0Sstevel@tonic-gate 	uint_t		intr_id;
605*0Sstevel@tonic-gate 	int		ret;
606*0Sstevel@tonic-gate 
607*0Sstevel@tonic-gate 	ASSERT(hdlp != NULL);
608*0Sstevel@tonic-gate 	ASSERT(hdlp->ih_private != NULL);
609*0Sstevel@tonic-gate 
610*0Sstevel@tonic-gate 	intr_id = (uint_t)hdlp->ih_private;
611*0Sstevel@tonic-gate 
612*0Sstevel@tonic-gate 	/* update the vector table for the new priority */
613*0Sstevel@tonic-gate 	ret = update_softint_pri(intr_id, hdlp->ih_pri);
614*0Sstevel@tonic-gate 
615*0Sstevel@tonic-gate 	return (ret);
616*0Sstevel@tonic-gate }
617*0Sstevel@tonic-gate 
618*0Sstevel@tonic-gate /*
619*0Sstevel@tonic-gate  * Support routine for allocating and initializing an interrupt specification.
620*0Sstevel@tonic-gate  * The bus interrupt value will be allocated at the end of this structure, so
621*0Sstevel@tonic-gate  * the corresponding routine i_ddi_free_ispec() should be used to free the
622*0Sstevel@tonic-gate  * interrupt specification.
623*0Sstevel@tonic-gate  */
624*0Sstevel@tonic-gate void
625*0Sstevel@tonic-gate i_ddi_alloc_ispec(dev_info_t *dip, uint_t inumber, ddi_intrspec_t *intrspecp)
626*0Sstevel@tonic-gate {
627*0Sstevel@tonic-gate 	int32_t intrlen, intr_cells, max_intrs;
628*0Sstevel@tonic-gate 	prop_1275_cell_t *ip;
629*0Sstevel@tonic-gate 	prop_1275_cell_t intr_sz;
630*0Sstevel@tonic-gate 	ddi_ispec_t **ispecp = (ddi_ispec_t **)intrspecp;
631*0Sstevel@tonic-gate 
632*0Sstevel@tonic-gate 	*ispecp = NULL;
633*0Sstevel@tonic-gate 	if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS |
634*0Sstevel@tonic-gate 	    DDI_PROP_CANSLEEP,
635*0Sstevel@tonic-gate 	    "interrupts", (caddr_t)&ip, &intrlen) == DDI_SUCCESS) {
636*0Sstevel@tonic-gate 
637*0Sstevel@tonic-gate 		intr_cells = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
638*0Sstevel@tonic-gate 		    "#interrupt-cells", 1);
639*0Sstevel@tonic-gate 
640*0Sstevel@tonic-gate 		/* adjust for number of bytes */
641*0Sstevel@tonic-gate 		intr_sz = CELLS_1275_TO_BYTES(intr_cells);
642*0Sstevel@tonic-gate 
643*0Sstevel@tonic-gate 		/* Calculate the number of interrupts */
644*0Sstevel@tonic-gate 		max_intrs = intrlen / intr_sz;
645*0Sstevel@tonic-gate 
646*0Sstevel@tonic-gate 		if (inumber < max_intrs) {
647*0Sstevel@tonic-gate 			prop_1275_cell_t *intrp = ip;
648*0Sstevel@tonic-gate 
649*0Sstevel@tonic-gate 			*ispecp = kmem_zalloc(
650*0Sstevel@tonic-gate 			    (sizeof (ddi_ispec_t) + intr_sz), KM_SLEEP);
651*0Sstevel@tonic-gate 
652*0Sstevel@tonic-gate 			(*ispecp)->is_intr =
653*0Sstevel@tonic-gate 			    (uint32_t *)(*ispecp + 1);
654*0Sstevel@tonic-gate 
655*0Sstevel@tonic-gate 			/* Index into interrupt property */
656*0Sstevel@tonic-gate 			intrp += (inumber * intr_cells);
657*0Sstevel@tonic-gate 
658*0Sstevel@tonic-gate 			cells_1275_copy(intrp,
659*0Sstevel@tonic-gate 			    (*ispecp)->is_intr, intr_cells);
660*0Sstevel@tonic-gate 
661*0Sstevel@tonic-gate 			(*ispecp)->is_intr_sz = intr_sz;
662*0Sstevel@tonic-gate 
663*0Sstevel@tonic-gate 			(*ispecp)->is_pil = i_ddi_get_intr_pri(dip, inumber);
664*0Sstevel@tonic-gate 		}
665*0Sstevel@tonic-gate 
666*0Sstevel@tonic-gate 		kmem_free(ip, intrlen);
667*0Sstevel@tonic-gate 	}
668*0Sstevel@tonic-gate }
669*0Sstevel@tonic-gate 
670*0Sstevel@tonic-gate /*
671*0Sstevel@tonic-gate  * Analog routine to i_ddi_alloc_ispec() used to free the interrupt
672*0Sstevel@tonic-gate  * specification and the associated bus interrupt value.
673*0Sstevel@tonic-gate  */
674*0Sstevel@tonic-gate void
675*0Sstevel@tonic-gate i_ddi_free_ispec(ddi_intrspec_t intrspecp)
676*0Sstevel@tonic-gate {
677*0Sstevel@tonic-gate 	ddi_ispec_t *ispecp = (ddi_ispec_t *)intrspecp;
678*0Sstevel@tonic-gate 
679*0Sstevel@tonic-gate 	kmem_free(ispecp, sizeof (ddi_ispec_t) + (ispecp->is_intr_sz));
680*0Sstevel@tonic-gate }
681*0Sstevel@tonic-gate 
682*0Sstevel@tonic-gate /*
683*0Sstevel@tonic-gate  * i_ddi_get_intr_pri - Get the interrupt-priorities property from
684*0Sstevel@tonic-gate  * the specified device.
685*0Sstevel@tonic-gate  */
686*0Sstevel@tonic-gate uint32_t
687*0Sstevel@tonic-gate i_ddi_get_intr_pri(dev_info_t *dip, uint_t inumber)
688*0Sstevel@tonic-gate {
689*0Sstevel@tonic-gate 	uint32_t *intr_prio_p;
690*0Sstevel@tonic-gate 	uint32_t pri = 0;
691*0Sstevel@tonic-gate 	int32_t i;
692*0Sstevel@tonic-gate 
693*0Sstevel@tonic-gate 	/*
694*0Sstevel@tonic-gate 	 * Use the "interrupt-priorities" property to determine the
695*0Sstevel@tonic-gate 	 * the pil/ipl for the interrupt handler.
696*0Sstevel@tonic-gate 	 */
697*0Sstevel@tonic-gate 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
698*0Sstevel@tonic-gate 	    "interrupt-priorities", (caddr_t)&intr_prio_p,
699*0Sstevel@tonic-gate 	    &i) == DDI_SUCCESS) {
700*0Sstevel@tonic-gate 		if (inumber < (i / sizeof (int32_t)))
701*0Sstevel@tonic-gate 			pri = intr_prio_p[inumber];
702*0Sstevel@tonic-gate 		kmem_free(intr_prio_p, i);
703*0Sstevel@tonic-gate 	}
704*0Sstevel@tonic-gate 
705*0Sstevel@tonic-gate 	return (pri);
706*0Sstevel@tonic-gate }
707*0Sstevel@tonic-gate 
708*0Sstevel@tonic-gate /*
709*0Sstevel@tonic-gate  * SECTION: DDI Memory/DMA
710*0Sstevel@tonic-gate  */
711*0Sstevel@tonic-gate 
712*0Sstevel@tonic-gate static vmem_t *little_endian_arena;
713*0Sstevel@tonic-gate static vmem_t *big_endian_arena;
714*0Sstevel@tonic-gate 
715*0Sstevel@tonic-gate static void *
716*0Sstevel@tonic-gate segkmem_alloc_le(vmem_t *vmp, size_t size, int flag)
717*0Sstevel@tonic-gate {
718*0Sstevel@tonic-gate 	return (segkmem_xalloc(vmp, NULL, size, flag, HAT_STRUCTURE_LE,
719*0Sstevel@tonic-gate 	    segkmem_page_create, NULL));
720*0Sstevel@tonic-gate }
721*0Sstevel@tonic-gate 
722*0Sstevel@tonic-gate static void *
723*0Sstevel@tonic-gate segkmem_alloc_be(vmem_t *vmp, size_t size, int flag)
724*0Sstevel@tonic-gate {
725*0Sstevel@tonic-gate 	return (segkmem_xalloc(vmp, NULL, size, flag, HAT_STRUCTURE_BE,
726*0Sstevel@tonic-gate 	    segkmem_page_create, NULL));
727*0Sstevel@tonic-gate }
728*0Sstevel@tonic-gate 
729*0Sstevel@tonic-gate void
730*0Sstevel@tonic-gate ka_init(void)
731*0Sstevel@tonic-gate {
732*0Sstevel@tonic-gate 	little_endian_arena = vmem_create("little_endian", NULL, 0, 1,
733*0Sstevel@tonic-gate 	    segkmem_alloc_le, segkmem_free, heap_arena, 0, VM_SLEEP);
734*0Sstevel@tonic-gate 	big_endian_arena = vmem_create("big_endian", NULL, 0, 1,
735*0Sstevel@tonic-gate 	    segkmem_alloc_be, segkmem_free, heap_arena, 0, VM_SLEEP);
736*0Sstevel@tonic-gate }
737*0Sstevel@tonic-gate 
738*0Sstevel@tonic-gate /*
739*0Sstevel@tonic-gate  * Allocate from the system, aligned on a specific boundary.
740*0Sstevel@tonic-gate  * The alignment, if non-zero, must be a power of 2.
741*0Sstevel@tonic-gate  */
742*0Sstevel@tonic-gate static void *
743*0Sstevel@tonic-gate kalloca(size_t size, size_t align, int cansleep, uint_t endian_flags)
744*0Sstevel@tonic-gate {
745*0Sstevel@tonic-gate 	size_t *addr, *raddr, rsize;
746*0Sstevel@tonic-gate 	size_t hdrsize = 4 * sizeof (size_t);	/* must be power of 2 */
747*0Sstevel@tonic-gate 
748*0Sstevel@tonic-gate 	align = MAX(align, hdrsize);
749*0Sstevel@tonic-gate 	ASSERT((align & (align - 1)) == 0);
750*0Sstevel@tonic-gate 
751*0Sstevel@tonic-gate 	/*
752*0Sstevel@tonic-gate 	 * We need to allocate
753*0Sstevel@tonic-gate 	 *    rsize = size + hdrsize + align - MIN(hdrsize, buffer_alignment)
754*0Sstevel@tonic-gate 	 * bytes to be sure we have enough freedom to satisfy the request.
755*0Sstevel@tonic-gate 	 * Since the buffer alignment depends on the request size, this is
756*0Sstevel@tonic-gate 	 * not straightforward to use directly.
757*0Sstevel@tonic-gate 	 *
758*0Sstevel@tonic-gate 	 * kmem guarantees that any allocation of a 64-byte multiple will be
759*0Sstevel@tonic-gate 	 * 64-byte aligned.  Since rounding up the request could add more
760*0Sstevel@tonic-gate 	 * than we save, we compute the size with and without alignment, and
761*0Sstevel@tonic-gate 	 * use the smaller of the two.
762*0Sstevel@tonic-gate 	 */
763*0Sstevel@tonic-gate 	rsize = size + hdrsize + align;
764*0Sstevel@tonic-gate 
765*0Sstevel@tonic-gate 	if (endian_flags == DDI_STRUCTURE_LE_ACC) {
766*0Sstevel@tonic-gate 		raddr = vmem_alloc(little_endian_arena, rsize,
767*0Sstevel@tonic-gate 		    cansleep ? VM_SLEEP : VM_NOSLEEP);
768*0Sstevel@tonic-gate 	} else {
769*0Sstevel@tonic-gate 		raddr = vmem_alloc(big_endian_arena, rsize,
770*0Sstevel@tonic-gate 		    cansleep ? VM_SLEEP : VM_NOSLEEP);
771*0Sstevel@tonic-gate 	}
772*0Sstevel@tonic-gate 
773*0Sstevel@tonic-gate 	if (raddr == NULL)
774*0Sstevel@tonic-gate 		return (NULL);
775*0Sstevel@tonic-gate 
776*0Sstevel@tonic-gate 	addr = (size_t *)P2ROUNDUP((uintptr_t)raddr + hdrsize, align);
777*0Sstevel@tonic-gate 	ASSERT((uintptr_t)addr + size - (uintptr_t)raddr <= rsize);
778*0Sstevel@tonic-gate 
779*0Sstevel@tonic-gate 	addr[-3] = (size_t)endian_flags;
780*0Sstevel@tonic-gate 	addr[-2] = (size_t)raddr;
781*0Sstevel@tonic-gate 	addr[-1] = rsize;
782*0Sstevel@tonic-gate 
783*0Sstevel@tonic-gate 	return (addr);
784*0Sstevel@tonic-gate }
785*0Sstevel@tonic-gate 
786*0Sstevel@tonic-gate static void
787*0Sstevel@tonic-gate kfreea(void *addr)
788*0Sstevel@tonic-gate {
789*0Sstevel@tonic-gate 	size_t *saddr = addr;
790*0Sstevel@tonic-gate 
791*0Sstevel@tonic-gate 	if (saddr[-3] == DDI_STRUCTURE_LE_ACC)
792*0Sstevel@tonic-gate 		vmem_free(little_endian_arena, (void *)saddr[-2], saddr[-1]);
793*0Sstevel@tonic-gate 	else
794*0Sstevel@tonic-gate 		vmem_free(big_endian_arena, (void *)saddr[-2], saddr[-1]);
795*0Sstevel@tonic-gate }
796*0Sstevel@tonic-gate 
797*0Sstevel@tonic-gate int
798*0Sstevel@tonic-gate i_ddi_mem_alloc(dev_info_t *dip, ddi_dma_attr_t *attr,
799*0Sstevel@tonic-gate     size_t length, int cansleep, int streaming,
800*0Sstevel@tonic-gate     ddi_device_acc_attr_t *accattrp,
801*0Sstevel@tonic-gate     caddr_t *kaddrp, size_t *real_length, ddi_acc_hdl_t *handlep)
802*0Sstevel@tonic-gate {
803*0Sstevel@tonic-gate 	caddr_t a;
804*0Sstevel@tonic-gate 	int iomin, align;
805*0Sstevel@tonic-gate 	uint_t endian_flags = DDI_NEVERSWAP_ACC;
806*0Sstevel@tonic-gate 
807*0Sstevel@tonic-gate #if defined(lint)
808*0Sstevel@tonic-gate 	*handlep = *handlep;
809*0Sstevel@tonic-gate #endif
810*0Sstevel@tonic-gate 
811*0Sstevel@tonic-gate 	/*
812*0Sstevel@tonic-gate 	 * Check legality of arguments
813*0Sstevel@tonic-gate 	 */
814*0Sstevel@tonic-gate 	if (length == 0 || kaddrp == NULL || attr == NULL) {
815*0Sstevel@tonic-gate 		return (DDI_FAILURE);
816*0Sstevel@tonic-gate 	}
817*0Sstevel@tonic-gate 	if (attr->dma_attr_minxfer == 0 || attr->dma_attr_align == 0 ||
818*0Sstevel@tonic-gate 	    (attr->dma_attr_align & (attr->dma_attr_align - 1)) ||
819*0Sstevel@tonic-gate 	    (attr->dma_attr_minxfer & (attr->dma_attr_minxfer - 1))) {
820*0Sstevel@tonic-gate 		return (DDI_FAILURE);
821*0Sstevel@tonic-gate 	}
822*0Sstevel@tonic-gate 
823*0Sstevel@tonic-gate 	/*
824*0Sstevel@tonic-gate 	 * Drivers for 64-bit capable SBus devices will encode
825*0Sstevel@tonic-gate 	 * the burtsizes for 64-bit xfers in the upper 16-bits.
826*0Sstevel@tonic-gate 	 * For DMA alignment, we use the most restrictive
827*0Sstevel@tonic-gate 	 * alignment of 32-bit and 64-bit xfers.
828*0Sstevel@tonic-gate 	 */
829*0Sstevel@tonic-gate 	iomin = (attr->dma_attr_burstsizes & 0xffff) |
830*0Sstevel@tonic-gate 	    ((attr->dma_attr_burstsizes >> 16) & 0xffff);
831*0Sstevel@tonic-gate 	/*
832*0Sstevel@tonic-gate 	 * If a driver set burtsizes to 0, we give him byte alignment.
833*0Sstevel@tonic-gate 	 * Otherwise align at the burtsizes boundary.
834*0Sstevel@tonic-gate 	 */
835*0Sstevel@tonic-gate 	if (iomin == 0)
836*0Sstevel@tonic-gate 		iomin = 1;
837*0Sstevel@tonic-gate 	else
838*0Sstevel@tonic-gate 		iomin = 1 << (ddi_fls(iomin) - 1);
839*0Sstevel@tonic-gate 	iomin = maxbit(iomin, attr->dma_attr_minxfer);
840*0Sstevel@tonic-gate 	iomin = maxbit(iomin, attr->dma_attr_align);
841*0Sstevel@tonic-gate 	iomin = ddi_iomin(dip, iomin, streaming);
842*0Sstevel@tonic-gate 	if (iomin == 0)
843*0Sstevel@tonic-gate 		return (DDI_FAILURE);
844*0Sstevel@tonic-gate 
845*0Sstevel@tonic-gate 	ASSERT((iomin & (iomin - 1)) == 0);
846*0Sstevel@tonic-gate 	ASSERT(iomin >= attr->dma_attr_minxfer);
847*0Sstevel@tonic-gate 	ASSERT(iomin >= attr->dma_attr_align);
848*0Sstevel@tonic-gate 
849*0Sstevel@tonic-gate 	length = P2ROUNDUP(length, iomin);
850*0Sstevel@tonic-gate 	align = iomin;
851*0Sstevel@tonic-gate 
852*0Sstevel@tonic-gate 	if (accattrp != NULL)
853*0Sstevel@tonic-gate 		endian_flags = accattrp->devacc_attr_endian_flags;
854*0Sstevel@tonic-gate 
855*0Sstevel@tonic-gate 	a = kalloca(length, align, cansleep, endian_flags);
856*0Sstevel@tonic-gate 	if ((*kaddrp = a) == 0) {
857*0Sstevel@tonic-gate 		return (DDI_FAILURE);
858*0Sstevel@tonic-gate 	} else {
859*0Sstevel@tonic-gate 		if (real_length) {
860*0Sstevel@tonic-gate 			*real_length = length;
861*0Sstevel@tonic-gate 		}
862*0Sstevel@tonic-gate 		if (handlep) {
863*0Sstevel@tonic-gate 			/*
864*0Sstevel@tonic-gate 			 * assign handle information
865*0Sstevel@tonic-gate 			 */
866*0Sstevel@tonic-gate 			impl_acc_hdl_init(handlep);
867*0Sstevel@tonic-gate 		}
868*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
869*0Sstevel@tonic-gate 	}
870*0Sstevel@tonic-gate }
871*0Sstevel@tonic-gate 
872*0Sstevel@tonic-gate /*
873*0Sstevel@tonic-gate  * covert old DMA limits structure to DMA attribute structure
874*0Sstevel@tonic-gate  * and continue
875*0Sstevel@tonic-gate  */
876*0Sstevel@tonic-gate int
877*0Sstevel@tonic-gate i_ddi_mem_alloc_lim(dev_info_t *dip, ddi_dma_lim_t *limits,
878*0Sstevel@tonic-gate     size_t length, int cansleep, int streaming,
879*0Sstevel@tonic-gate     ddi_device_acc_attr_t *accattrp, caddr_t *kaddrp,
880*0Sstevel@tonic-gate     uint_t *real_length, ddi_acc_hdl_t *ap)
881*0Sstevel@tonic-gate {
882*0Sstevel@tonic-gate 	ddi_dma_attr_t dma_attr, *attrp;
883*0Sstevel@tonic-gate 	size_t rlen;
884*0Sstevel@tonic-gate 	int ret;
885*0Sstevel@tonic-gate 
886*0Sstevel@tonic-gate 	ASSERT(limits);
887*0Sstevel@tonic-gate 	attrp = &dma_attr;
888*0Sstevel@tonic-gate 	attrp->dma_attr_version = DMA_ATTR_V0;
889*0Sstevel@tonic-gate 	attrp->dma_attr_addr_lo = (uint64_t)limits->dlim_addr_lo;
890*0Sstevel@tonic-gate 	attrp->dma_attr_addr_hi = (uint64_t)limits->dlim_addr_hi;
891*0Sstevel@tonic-gate 	attrp->dma_attr_count_max = (uint64_t)-1;
892*0Sstevel@tonic-gate 	attrp->dma_attr_align = 1;
893*0Sstevel@tonic-gate 	attrp->dma_attr_burstsizes = (uint_t)limits->dlim_burstsizes;
894*0Sstevel@tonic-gate 	attrp->dma_attr_minxfer = (uint32_t)limits->dlim_minxfer;
895*0Sstevel@tonic-gate 	attrp->dma_attr_maxxfer = (uint64_t)-1;
896*0Sstevel@tonic-gate 	attrp->dma_attr_seg = (uint64_t)limits->dlim_cntr_max;
897*0Sstevel@tonic-gate 	attrp->dma_attr_sgllen = 1;
898*0Sstevel@tonic-gate 	attrp->dma_attr_granular = 1;
899*0Sstevel@tonic-gate 	attrp->dma_attr_flags = 0;
900*0Sstevel@tonic-gate 
901*0Sstevel@tonic-gate 	ret = i_ddi_mem_alloc(dip, attrp, length, cansleep, streaming,
902*0Sstevel@tonic-gate 	    accattrp, kaddrp, &rlen, ap);
903*0Sstevel@tonic-gate 	if (ret == DDI_SUCCESS) {
904*0Sstevel@tonic-gate 		if (real_length)
905*0Sstevel@tonic-gate 			*real_length = (uint_t)rlen;
906*0Sstevel@tonic-gate 	}
907*0Sstevel@tonic-gate 	return (ret);
908*0Sstevel@tonic-gate }
909*0Sstevel@tonic-gate 
910*0Sstevel@tonic-gate /* ARGSUSED */
911*0Sstevel@tonic-gate void
912*0Sstevel@tonic-gate i_ddi_mem_free(caddr_t kaddr, int stream)
913*0Sstevel@tonic-gate {
914*0Sstevel@tonic-gate 	kfreea(kaddr);
915*0Sstevel@tonic-gate }
916*0Sstevel@tonic-gate 
917*0Sstevel@tonic-gate /*
918*0Sstevel@tonic-gate  * SECTION: DDI Data Access
919*0Sstevel@tonic-gate  */
920*0Sstevel@tonic-gate 
921*0Sstevel@tonic-gate static uintptr_t impl_acc_hdl_id = 0;
922*0Sstevel@tonic-gate 
923*0Sstevel@tonic-gate /*
924*0Sstevel@tonic-gate  * access handle allocator
925*0Sstevel@tonic-gate  */
926*0Sstevel@tonic-gate ddi_acc_hdl_t *
927*0Sstevel@tonic-gate impl_acc_hdl_get(ddi_acc_handle_t hdl)
928*0Sstevel@tonic-gate {
929*0Sstevel@tonic-gate 	/*
930*0Sstevel@tonic-gate 	 * Extract the access handle address from the DDI implemented
931*0Sstevel@tonic-gate 	 * access handle
932*0Sstevel@tonic-gate 	 */
933*0Sstevel@tonic-gate 	return (&((ddi_acc_impl_t *)hdl)->ahi_common);
934*0Sstevel@tonic-gate }
935*0Sstevel@tonic-gate 
936*0Sstevel@tonic-gate ddi_acc_handle_t
937*0Sstevel@tonic-gate impl_acc_hdl_alloc(int (*waitfp)(caddr_t), caddr_t arg)
938*0Sstevel@tonic-gate {
939*0Sstevel@tonic-gate 	ddi_acc_impl_t *hp;
940*0Sstevel@tonic-gate 	on_trap_data_t *otp;
941*0Sstevel@tonic-gate 	int sleepflag;
942*0Sstevel@tonic-gate 
943*0Sstevel@tonic-gate 	sleepflag = ((waitfp == (int (*)())KM_SLEEP) ? KM_SLEEP : KM_NOSLEEP);
944*0Sstevel@tonic-gate 
945*0Sstevel@tonic-gate 	/*
946*0Sstevel@tonic-gate 	 * Allocate and initialize the data access handle and error status.
947*0Sstevel@tonic-gate 	 */
948*0Sstevel@tonic-gate 	if ((hp = kmem_zalloc(sizeof (ddi_acc_impl_t), sleepflag)) == NULL)
949*0Sstevel@tonic-gate 		goto fail;
950*0Sstevel@tonic-gate 	if ((hp->ahi_err = (ndi_err_t *)kmem_zalloc(
951*0Sstevel@tonic-gate 	    sizeof (ndi_err_t), sleepflag)) == NULL) {
952*0Sstevel@tonic-gate 		kmem_free(hp, sizeof (ddi_acc_impl_t));
953*0Sstevel@tonic-gate 		goto fail;
954*0Sstevel@tonic-gate 	}
955*0Sstevel@tonic-gate 	if ((otp = (on_trap_data_t *)kmem_zalloc(
956*0Sstevel@tonic-gate 	    sizeof (on_trap_data_t), sleepflag)) == NULL) {
957*0Sstevel@tonic-gate 		kmem_free(hp->ahi_err, sizeof (ndi_err_t));
958*0Sstevel@tonic-gate 		kmem_free(hp, sizeof (ddi_acc_impl_t));
959*0Sstevel@tonic-gate 		goto fail;
960*0Sstevel@tonic-gate 	}
961*0Sstevel@tonic-gate 	hp->ahi_err->err_ontrap = otp;
962*0Sstevel@tonic-gate 	hp->ahi_common.ah_platform_private = (void *)hp;
963*0Sstevel@tonic-gate 
964*0Sstevel@tonic-gate 	return ((ddi_acc_handle_t)hp);
965*0Sstevel@tonic-gate fail:
966*0Sstevel@tonic-gate 	if ((waitfp != (int (*)())KM_SLEEP) &&
967*0Sstevel@tonic-gate 	    (waitfp != (int (*)())KM_NOSLEEP))
968*0Sstevel@tonic-gate 		ddi_set_callback(waitfp, arg, &impl_acc_hdl_id);
969*0Sstevel@tonic-gate 	return (NULL);
970*0Sstevel@tonic-gate }
971*0Sstevel@tonic-gate 
972*0Sstevel@tonic-gate void
973*0Sstevel@tonic-gate impl_acc_hdl_free(ddi_acc_handle_t handle)
974*0Sstevel@tonic-gate {
975*0Sstevel@tonic-gate 	ddi_acc_impl_t *hp;
976*0Sstevel@tonic-gate 
977*0Sstevel@tonic-gate 	/*
978*0Sstevel@tonic-gate 	 * The supplied (ddi_acc_handle_t) is actually a (ddi_acc_impl_t *),
979*0Sstevel@tonic-gate 	 * because that's what we allocated in impl_acc_hdl_alloc() above.
980*0Sstevel@tonic-gate 	 */
981*0Sstevel@tonic-gate 	hp = (ddi_acc_impl_t *)handle;
982*0Sstevel@tonic-gate 	if (hp) {
983*0Sstevel@tonic-gate 		kmem_free(hp->ahi_err->err_ontrap, sizeof (on_trap_data_t));
984*0Sstevel@tonic-gate 		kmem_free(hp->ahi_err, sizeof (ndi_err_t));
985*0Sstevel@tonic-gate 		kmem_free(hp, sizeof (ddi_acc_impl_t));
986*0Sstevel@tonic-gate 		if (impl_acc_hdl_id)
987*0Sstevel@tonic-gate 			ddi_run_callback(&impl_acc_hdl_id);
988*0Sstevel@tonic-gate 	}
989*0Sstevel@tonic-gate }
990*0Sstevel@tonic-gate 
991*0Sstevel@tonic-gate void
992*0Sstevel@tonic-gate impl_acc_err_init(ddi_acc_hdl_t *handlep)
993*0Sstevel@tonic-gate {
994*0Sstevel@tonic-gate 	int fmcap;
995*0Sstevel@tonic-gate 	ndi_err_t *errp;
996*0Sstevel@tonic-gate 	on_trap_data_t *otp;
997*0Sstevel@tonic-gate 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)handlep;
998*0Sstevel@tonic-gate 
999*0Sstevel@tonic-gate 	fmcap = ddi_fm_capable(handlep->ah_dip);
1000*0Sstevel@tonic-gate 
1001*0Sstevel@tonic-gate 	if (handlep->ah_acc.devacc_attr_version < DDI_DEVICE_ATTR_V1 ||
1002*0Sstevel@tonic-gate 	    !DDI_FM_ACC_ERR_CAP(fmcap)) {
1003*0Sstevel@tonic-gate 		handlep->ah_acc.devacc_attr_access = DDI_DEFAULT_ACC;
1004*0Sstevel@tonic-gate 	} else if (DDI_FM_ACC_ERR_CAP(fmcap)) {
1005*0Sstevel@tonic-gate 		if (handlep->ah_acc.devacc_attr_access == DDI_DEFAULT_ACC) {
1006*0Sstevel@tonic-gate 			i_ddi_drv_ereport_post(handlep->ah_dip, DVR_EFMCAP,
1007*0Sstevel@tonic-gate 			    NULL, DDI_NOSLEEP);
1008*0Sstevel@tonic-gate 		} else {
1009*0Sstevel@tonic-gate 			errp = hp->ahi_err;
1010*0Sstevel@tonic-gate 			otp = (on_trap_data_t *)errp->err_ontrap;
1011*0Sstevel@tonic-gate 			otp->ot_handle = (void *)(hp);
1012*0Sstevel@tonic-gate 			otp->ot_prot = OT_DATA_ACCESS;
1013*0Sstevel@tonic-gate 			if (handlep->ah_acc.devacc_attr_access ==
1014*0Sstevel@tonic-gate 			    DDI_CAUTIOUS_ACC)
1015*0Sstevel@tonic-gate 				otp->ot_trampoline =
1016*0Sstevel@tonic-gate 				    (uintptr_t)&i_ddi_caut_trampoline;
1017*0Sstevel@tonic-gate 			else
1018*0Sstevel@tonic-gate 				otp->ot_trampoline =
1019*0Sstevel@tonic-gate 				    (uintptr_t)&i_ddi_prot_trampoline;
1020*0Sstevel@tonic-gate 			errp->err_status = DDI_FM_OK;
1021*0Sstevel@tonic-gate 			errp->err_expected = DDI_FM_ERR_UNEXPECTED;
1022*0Sstevel@tonic-gate 		}
1023*0Sstevel@tonic-gate 	}
1024*0Sstevel@tonic-gate }
1025*0Sstevel@tonic-gate 
1026*0Sstevel@tonic-gate void
1027*0Sstevel@tonic-gate impl_acc_hdl_init(ddi_acc_hdl_t *handlep)
1028*0Sstevel@tonic-gate {
1029*0Sstevel@tonic-gate 	ddi_acc_impl_t *hp;
1030*0Sstevel@tonic-gate 
1031*0Sstevel@tonic-gate 	ASSERT(handlep);
1032*0Sstevel@tonic-gate 
1033*0Sstevel@tonic-gate 	hp = (ddi_acc_impl_t *)handlep;
1034*0Sstevel@tonic-gate 
1035*0Sstevel@tonic-gate 	/*
1036*0Sstevel@tonic-gate 	 * check for SW byte-swapping
1037*0Sstevel@tonic-gate 	 */
1038*0Sstevel@tonic-gate 	hp->ahi_get8 = i_ddi_get8;
1039*0Sstevel@tonic-gate 	hp->ahi_put8 = i_ddi_put8;
1040*0Sstevel@tonic-gate 	hp->ahi_rep_get8 = i_ddi_rep_get8;
1041*0Sstevel@tonic-gate 	hp->ahi_rep_put8 = i_ddi_rep_put8;
1042*0Sstevel@tonic-gate 	if (handlep->ah_acc.devacc_attr_endian_flags & DDI_STRUCTURE_LE_ACC) {
1043*0Sstevel@tonic-gate 		hp->ahi_get16 = i_ddi_swap_get16;
1044*0Sstevel@tonic-gate 		hp->ahi_get32 = i_ddi_swap_get32;
1045*0Sstevel@tonic-gate 		hp->ahi_get64 = i_ddi_swap_get64;
1046*0Sstevel@tonic-gate 		hp->ahi_put16 = i_ddi_swap_put16;
1047*0Sstevel@tonic-gate 		hp->ahi_put32 = i_ddi_swap_put32;
1048*0Sstevel@tonic-gate 		hp->ahi_put64 = i_ddi_swap_put64;
1049*0Sstevel@tonic-gate 		hp->ahi_rep_get16 = i_ddi_swap_rep_get16;
1050*0Sstevel@tonic-gate 		hp->ahi_rep_get32 = i_ddi_swap_rep_get32;
1051*0Sstevel@tonic-gate 		hp->ahi_rep_get64 = i_ddi_swap_rep_get64;
1052*0Sstevel@tonic-gate 		hp->ahi_rep_put16 = i_ddi_swap_rep_put16;
1053*0Sstevel@tonic-gate 		hp->ahi_rep_put32 = i_ddi_swap_rep_put32;
1054*0Sstevel@tonic-gate 		hp->ahi_rep_put64 = i_ddi_swap_rep_put64;
1055*0Sstevel@tonic-gate 	} else {
1056*0Sstevel@tonic-gate 		hp->ahi_get16 = i_ddi_get16;
1057*0Sstevel@tonic-gate 		hp->ahi_get32 = i_ddi_get32;
1058*0Sstevel@tonic-gate 		hp->ahi_get64 = i_ddi_get64;
1059*0Sstevel@tonic-gate 		hp->ahi_put16 = i_ddi_put16;
1060*0Sstevel@tonic-gate 		hp->ahi_put32 = i_ddi_put32;
1061*0Sstevel@tonic-gate 		hp->ahi_put64 = i_ddi_put64;
1062*0Sstevel@tonic-gate 		hp->ahi_rep_get16 = i_ddi_rep_get16;
1063*0Sstevel@tonic-gate 		hp->ahi_rep_get32 = i_ddi_rep_get32;
1064*0Sstevel@tonic-gate 		hp->ahi_rep_get64 = i_ddi_rep_get64;
1065*0Sstevel@tonic-gate 		hp->ahi_rep_put16 = i_ddi_rep_put16;
1066*0Sstevel@tonic-gate 		hp->ahi_rep_put32 = i_ddi_rep_put32;
1067*0Sstevel@tonic-gate 		hp->ahi_rep_put64 = i_ddi_rep_put64;
1068*0Sstevel@tonic-gate 	}
1069*0Sstevel@tonic-gate 
1070*0Sstevel@tonic-gate 	/* Legacy fault flags and support */
1071*0Sstevel@tonic-gate 	hp->ahi_fault_check = i_ddi_acc_fault_check;
1072*0Sstevel@tonic-gate 	hp->ahi_fault_notify = i_ddi_acc_fault_notify;
1073*0Sstevel@tonic-gate 	hp->ahi_fault = 0;
1074*0Sstevel@tonic-gate 	impl_acc_err_init(handlep);
1075*0Sstevel@tonic-gate }
1076*0Sstevel@tonic-gate 
1077*0Sstevel@tonic-gate void
1078*0Sstevel@tonic-gate i_ddi_acc_set_fault(ddi_acc_handle_t handle)
1079*0Sstevel@tonic-gate {
1080*0Sstevel@tonic-gate 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)handle;
1081*0Sstevel@tonic-gate 
1082*0Sstevel@tonic-gate 	if (!hp->ahi_fault) {
1083*0Sstevel@tonic-gate 		hp->ahi_fault = 1;
1084*0Sstevel@tonic-gate 			(*hp->ahi_fault_notify)(hp);
1085*0Sstevel@tonic-gate 	}
1086*0Sstevel@tonic-gate }
1087*0Sstevel@tonic-gate 
1088*0Sstevel@tonic-gate void
1089*0Sstevel@tonic-gate i_ddi_acc_clr_fault(ddi_acc_handle_t handle)
1090*0Sstevel@tonic-gate {
1091*0Sstevel@tonic-gate 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)handle;
1092*0Sstevel@tonic-gate 
1093*0Sstevel@tonic-gate 	if (hp->ahi_fault) {
1094*0Sstevel@tonic-gate 		hp->ahi_fault = 0;
1095*0Sstevel@tonic-gate 			(*hp->ahi_fault_notify)(hp);
1096*0Sstevel@tonic-gate 	}
1097*0Sstevel@tonic-gate }
1098*0Sstevel@tonic-gate 
1099*0Sstevel@tonic-gate /* ARGSUSED */
1100*0Sstevel@tonic-gate void
1101*0Sstevel@tonic-gate i_ddi_acc_fault_notify(ddi_acc_impl_t *hp)
1102*0Sstevel@tonic-gate {
1103*0Sstevel@tonic-gate 	/* Default version, does nothing */
1104*0Sstevel@tonic-gate }
1105*0Sstevel@tonic-gate 
1106*0Sstevel@tonic-gate /*
1107*0Sstevel@tonic-gate  * SECTION: Misc functions
1108*0Sstevel@tonic-gate  */
1109*0Sstevel@tonic-gate 
1110*0Sstevel@tonic-gate /*
1111*0Sstevel@tonic-gate  * instance wrappers
1112*0Sstevel@tonic-gate  */
1113*0Sstevel@tonic-gate /*ARGSUSED*/
1114*0Sstevel@tonic-gate uint_t
1115*0Sstevel@tonic-gate impl_assign_instance(dev_info_t *dip)
1116*0Sstevel@tonic-gate {
1117*0Sstevel@tonic-gate 	return ((uint_t)-1);
1118*0Sstevel@tonic-gate }
1119*0Sstevel@tonic-gate 
1120*0Sstevel@tonic-gate /*ARGSUSED*/
1121*0Sstevel@tonic-gate int
1122*0Sstevel@tonic-gate impl_keep_instance(dev_info_t *dip)
1123*0Sstevel@tonic-gate {
1124*0Sstevel@tonic-gate 	return (DDI_FAILURE);
1125*0Sstevel@tonic-gate }
1126*0Sstevel@tonic-gate 
1127*0Sstevel@tonic-gate /*ARGSUSED*/
1128*0Sstevel@tonic-gate int
1129*0Sstevel@tonic-gate impl_free_instance(dev_info_t *dip)
1130*0Sstevel@tonic-gate {
1131*0Sstevel@tonic-gate 	return (DDI_FAILURE);
1132*0Sstevel@tonic-gate }
1133*0Sstevel@tonic-gate 
1134*0Sstevel@tonic-gate /*ARGSUSED*/
1135*0Sstevel@tonic-gate int
1136*0Sstevel@tonic-gate impl_check_cpu(dev_info_t *devi)
1137*0Sstevel@tonic-gate {
1138*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
1139*0Sstevel@tonic-gate }
1140*0Sstevel@tonic-gate 
1141*0Sstevel@tonic-gate 
1142*0Sstevel@tonic-gate static const char *nocopydevs[] = {
1143*0Sstevel@tonic-gate 	"SUNW,ffb",
1144*0Sstevel@tonic-gate 	"SUNW,afb",
1145*0Sstevel@tonic-gate 	NULL
1146*0Sstevel@tonic-gate };
1147*0Sstevel@tonic-gate 
1148*0Sstevel@tonic-gate /*
1149*0Sstevel@tonic-gate  * Perform a copy from a memory mapped device (whose devinfo pointer is devi)
1150*0Sstevel@tonic-gate  * separately mapped at devaddr in the kernel to a kernel buffer at kaddr.
1151*0Sstevel@tonic-gate  */
1152*0Sstevel@tonic-gate /*ARGSUSED*/
1153*0Sstevel@tonic-gate int
1154*0Sstevel@tonic-gate e_ddi_copyfromdev(dev_info_t *devi,
1155*0Sstevel@tonic-gate     off_t off, const void *devaddr, void *kaddr, size_t len)
1156*0Sstevel@tonic-gate {
1157*0Sstevel@tonic-gate 	const char **argv;
1158*0Sstevel@tonic-gate 
1159*0Sstevel@tonic-gate 	for (argv = nocopydevs; *argv; argv++)
1160*0Sstevel@tonic-gate 		if (strcmp(ddi_binding_name(devi), *argv) == 0) {
1161*0Sstevel@tonic-gate 			bzero(kaddr, len);
1162*0Sstevel@tonic-gate 			return (0);
1163*0Sstevel@tonic-gate 		}
1164*0Sstevel@tonic-gate 
1165*0Sstevel@tonic-gate 	bcopy(devaddr, kaddr, len);
1166*0Sstevel@tonic-gate 	return (0);
1167*0Sstevel@tonic-gate }
1168*0Sstevel@tonic-gate 
1169*0Sstevel@tonic-gate /*
1170*0Sstevel@tonic-gate  * Perform a copy to a memory mapped device (whose devinfo pointer is devi)
1171*0Sstevel@tonic-gate  * separately mapped at devaddr in the kernel from a kernel buffer at kaddr.
1172*0Sstevel@tonic-gate  */
1173*0Sstevel@tonic-gate /*ARGSUSED*/
1174*0Sstevel@tonic-gate int
1175*0Sstevel@tonic-gate e_ddi_copytodev(dev_info_t *devi,
1176*0Sstevel@tonic-gate     off_t off, const void *kaddr, void *devaddr, size_t len)
1177*0Sstevel@tonic-gate {
1178*0Sstevel@tonic-gate 	const char **argv;
1179*0Sstevel@tonic-gate 
1180*0Sstevel@tonic-gate 	for (argv = nocopydevs; *argv; argv++)
1181*0Sstevel@tonic-gate 		if (strcmp(ddi_binding_name(devi), *argv) == 0)
1182*0Sstevel@tonic-gate 			return (1);
1183*0Sstevel@tonic-gate 
1184*0Sstevel@tonic-gate 	bcopy(kaddr, devaddr, len);
1185*0Sstevel@tonic-gate 	return (0);
1186*0Sstevel@tonic-gate }
1187*0Sstevel@tonic-gate 
1188*0Sstevel@tonic-gate /*
1189*0Sstevel@tonic-gate  * Boot Configuration
1190*0Sstevel@tonic-gate  */
1191*0Sstevel@tonic-gate idprom_t idprom;
1192*0Sstevel@tonic-gate 
1193*0Sstevel@tonic-gate /*
1194*0Sstevel@tonic-gate  * Configure the hardware on the system.
1195*0Sstevel@tonic-gate  * Called before the rootfs is mounted
1196*0Sstevel@tonic-gate  */
1197*0Sstevel@tonic-gate void
1198*0Sstevel@tonic-gate configure(void)
1199*0Sstevel@tonic-gate {
1200*0Sstevel@tonic-gate 	extern void i_ddi_init_root();
1201*0Sstevel@tonic-gate 
1202*0Sstevel@tonic-gate 	/* We better have released boot by this time! */
1203*0Sstevel@tonic-gate 	ASSERT(!bootops);
1204*0Sstevel@tonic-gate 
1205*0Sstevel@tonic-gate 	/*
1206*0Sstevel@tonic-gate 	 * Determine whether or not to use the fpu, V9 SPARC cpus
1207*0Sstevel@tonic-gate 	 * always have one. Could check for existence of a fp queue,
1208*0Sstevel@tonic-gate 	 * Ultra I, II and IIa do not have a fp queue.
1209*0Sstevel@tonic-gate 	 */
1210*0Sstevel@tonic-gate 	if (fpu_exists)
1211*0Sstevel@tonic-gate 		fpu_probe();
1212*0Sstevel@tonic-gate 	else
1213*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "FPU not in use\n");
1214*0Sstevel@tonic-gate 
1215*0Sstevel@tonic-gate #if 0 /* XXXQ - not necessary for sun4u */
1216*0Sstevel@tonic-gate 	/*
1217*0Sstevel@tonic-gate 	 * This following line fixes bugid 1041296; we need to do a
1218*0Sstevel@tonic-gate 	 * prom_nextnode(0) because this call ALSO patches the DMA+
1219*0Sstevel@tonic-gate 	 * bug in Campus-B and Phoenix. The prom uncaches the traptable
1220*0Sstevel@tonic-gate 	 * page as a side-effect of devr_next(0) (which prom_nextnode calls),
1221*0Sstevel@tonic-gate 	 * so this *must* be executed early on. (XXX This is untrue for sun4u)
1222*0Sstevel@tonic-gate 	 */
1223*0Sstevel@tonic-gate 	(void) prom_nextnode((dnode_t)0);
1224*0Sstevel@tonic-gate #endif
1225*0Sstevel@tonic-gate 
1226*0Sstevel@tonic-gate 	/*
1227*0Sstevel@tonic-gate 	 * Initialize devices on the machine.
1228*0Sstevel@tonic-gate 	 * Uses configuration tree built by the PROMs to determine what
1229*0Sstevel@tonic-gate 	 * is present, and builds a tree of prototype dev_info nodes
1230*0Sstevel@tonic-gate 	 * corresponding to the hardware which identified itself.
1231*0Sstevel@tonic-gate 	 */
1232*0Sstevel@tonic-gate 	i_ddi_init_root();
1233*0Sstevel@tonic-gate 
1234*0Sstevel@tonic-gate #ifdef	DDI_PROP_DEBUG
1235*0Sstevel@tonic-gate 	(void) ddi_prop_debug(1);	/* Enable property debugging */
1236*0Sstevel@tonic-gate #endif	/* DDI_PROP_DEBUG */
1237*0Sstevel@tonic-gate }
1238*0Sstevel@tonic-gate 
1239*0Sstevel@tonic-gate /*
1240*0Sstevel@tonic-gate  * The "status" property indicates the operational status of a device.
1241*0Sstevel@tonic-gate  * If this property is present, the value is a string indicating the
1242*0Sstevel@tonic-gate  * status of the device as follows:
1243*0Sstevel@tonic-gate  *
1244*0Sstevel@tonic-gate  *	"okay"		operational.
1245*0Sstevel@tonic-gate  *	"disabled"	not operational, but might become operational.
1246*0Sstevel@tonic-gate  *	"fail"		not operational because a fault has been detected,
1247*0Sstevel@tonic-gate  *			and it is unlikely that the device will become
1248*0Sstevel@tonic-gate  *			operational without repair. no additional details
1249*0Sstevel@tonic-gate  *			are available.
1250*0Sstevel@tonic-gate  *	"fail-xxx"	not operational because a fault has been detected,
1251*0Sstevel@tonic-gate  *			and it is unlikely that the device will become
1252*0Sstevel@tonic-gate  *			operational without repair. "xxx" is additional
1253*0Sstevel@tonic-gate  *			human-readable information about the particular
1254*0Sstevel@tonic-gate  *			fault condition that was detected.
1255*0Sstevel@tonic-gate  *
1256*0Sstevel@tonic-gate  * The absence of this property means that the operational status is
1257*0Sstevel@tonic-gate  * unknown or okay.
1258*0Sstevel@tonic-gate  *
1259*0Sstevel@tonic-gate  * This routine checks the status property of the specified device node
1260*0Sstevel@tonic-gate  * and returns 0 if the operational status indicates failure, and 1 otherwise.
1261*0Sstevel@tonic-gate  *
1262*0Sstevel@tonic-gate  * The property may exist on plug-in cards the existed before IEEE 1275-1994.
1263*0Sstevel@tonic-gate  * And, in that case, the property may not even be a string. So we carefully
1264*0Sstevel@tonic-gate  * check for the value "fail", in the beginning of the string, noting
1265*0Sstevel@tonic-gate  * the property length.
1266*0Sstevel@tonic-gate  */
1267*0Sstevel@tonic-gate int
1268*0Sstevel@tonic-gate status_okay(int id, char *buf, int buflen)
1269*0Sstevel@tonic-gate {
1270*0Sstevel@tonic-gate 	char status_buf[OBP_MAXPROPNAME];
1271*0Sstevel@tonic-gate 	char *bufp = buf;
1272*0Sstevel@tonic-gate 	int len = buflen;
1273*0Sstevel@tonic-gate 	int proplen;
1274*0Sstevel@tonic-gate 	static const char *status = "status";
1275*0Sstevel@tonic-gate 	static const char *fail = "fail";
1276*0Sstevel@tonic-gate 	size_t fail_len = strlen(fail);
1277*0Sstevel@tonic-gate 
1278*0Sstevel@tonic-gate 	/*
1279*0Sstevel@tonic-gate 	 * Get the proplen ... if it's smaller than "fail",
1280*0Sstevel@tonic-gate 	 * or doesn't exist ... then we don't care, since
1281*0Sstevel@tonic-gate 	 * the value can't begin with the char string "fail".
1282*0Sstevel@tonic-gate 	 *
1283*0Sstevel@tonic-gate 	 * NB: proplen, if it's a string, includes the NULL in the
1284*0Sstevel@tonic-gate 	 * the size of the property, and fail_len does not.
1285*0Sstevel@tonic-gate 	 */
1286*0Sstevel@tonic-gate 	proplen = prom_getproplen((dnode_t)id, (caddr_t)status);
1287*0Sstevel@tonic-gate 	if (proplen <= fail_len)	/* nonexistent or uninteresting len */
1288*0Sstevel@tonic-gate 		return (1);
1289*0Sstevel@tonic-gate 
1290*0Sstevel@tonic-gate 	/*
1291*0Sstevel@tonic-gate 	 * if a buffer was provided, use it
1292*0Sstevel@tonic-gate 	 */
1293*0Sstevel@tonic-gate 	if ((buf == (char *)NULL) || (buflen <= 0)) {
1294*0Sstevel@tonic-gate 		bufp = status_buf;
1295*0Sstevel@tonic-gate 		len = sizeof (status_buf);
1296*0Sstevel@tonic-gate 	}
1297*0Sstevel@tonic-gate 	*bufp = (char)0;
1298*0Sstevel@tonic-gate 
1299*0Sstevel@tonic-gate 	/*
1300*0Sstevel@tonic-gate 	 * Get the property into the buffer, to the extent of the buffer,
1301*0Sstevel@tonic-gate 	 * and in case the buffer is smaller than the property size,
1302*0Sstevel@tonic-gate 	 * NULL terminate the buffer. (This handles the case where
1303*0Sstevel@tonic-gate 	 * a buffer was passed in and the caller wants to print the
1304*0Sstevel@tonic-gate 	 * value, but the buffer was too small).
1305*0Sstevel@tonic-gate 	 */
1306*0Sstevel@tonic-gate 	(void) prom_bounded_getprop((dnode_t)id, (caddr_t)status,
1307*0Sstevel@tonic-gate 	    (caddr_t)bufp, len);
1308*0Sstevel@tonic-gate 	*(bufp + len - 1) = (char)0;
1309*0Sstevel@tonic-gate 
1310*0Sstevel@tonic-gate 	/*
1311*0Sstevel@tonic-gate 	 * If the value begins with the char string "fail",
1312*0Sstevel@tonic-gate 	 * then it means the node is failed. We don't care
1313*0Sstevel@tonic-gate 	 * about any other values. We assume the node is ok
1314*0Sstevel@tonic-gate 	 * although it might be 'disabled'.
1315*0Sstevel@tonic-gate 	 */
1316*0Sstevel@tonic-gate 	if (strncmp(bufp, fail, fail_len) == 0)
1317*0Sstevel@tonic-gate 		return (0);
1318*0Sstevel@tonic-gate 
1319*0Sstevel@tonic-gate 	return (1);
1320*0Sstevel@tonic-gate }
1321*0Sstevel@tonic-gate 
1322*0Sstevel@tonic-gate 
1323*0Sstevel@tonic-gate /*
1324*0Sstevel@tonic-gate  * We set the cpu type from the idprom, if we can.
1325*0Sstevel@tonic-gate  * Note that we just read out the contents of it, for the most part.
1326*0Sstevel@tonic-gate  */
1327*0Sstevel@tonic-gate void
1328*0Sstevel@tonic-gate setcputype(void)
1329*0Sstevel@tonic-gate {
1330*0Sstevel@tonic-gate 	/*
1331*0Sstevel@tonic-gate 	 * We cache the idprom info early on so that we don't
1332*0Sstevel@tonic-gate 	 * rummage through the NVRAM unnecessarily later.
1333*0Sstevel@tonic-gate 	 */
1334*0Sstevel@tonic-gate 	(void) prom_getidprom((caddr_t)&idprom, sizeof (idprom));
1335*0Sstevel@tonic-gate }
1336*0Sstevel@tonic-gate 
1337*0Sstevel@tonic-gate /*
1338*0Sstevel@tonic-gate  *  Here is where we actually infer meanings to the members of idprom_t
1339*0Sstevel@tonic-gate  */
1340*0Sstevel@tonic-gate void
1341*0Sstevel@tonic-gate parse_idprom(void)
1342*0Sstevel@tonic-gate {
1343*0Sstevel@tonic-gate 	if (idprom.id_format == IDFORM_1) {
1344*0Sstevel@tonic-gate 		uint_t i;
1345*0Sstevel@tonic-gate 
1346*0Sstevel@tonic-gate 		(void) localetheraddr((struct ether_addr *)idprom.id_ether,
1347*0Sstevel@tonic-gate 		    (struct ether_addr *)NULL);
1348*0Sstevel@tonic-gate 
1349*0Sstevel@tonic-gate 		i = idprom.id_machine << 24;
1350*0Sstevel@tonic-gate 		i = i + idprom.id_serial;
1351*0Sstevel@tonic-gate 		numtos((ulong_t)i, hw_serial);
1352*0Sstevel@tonic-gate 	} else
1353*0Sstevel@tonic-gate 		prom_printf("Invalid format code in IDprom.\n");
1354*0Sstevel@tonic-gate }
1355*0Sstevel@tonic-gate 
1356*0Sstevel@tonic-gate /*
1357*0Sstevel@tonic-gate  * Allow for implementation specific correction of PROM property values.
1358*0Sstevel@tonic-gate  */
1359*0Sstevel@tonic-gate /*ARGSUSED*/
1360*0Sstevel@tonic-gate void
1361*0Sstevel@tonic-gate impl_fix_props(dev_info_t *dip, dev_info_t *ch_dip, char *name, int len,
1362*0Sstevel@tonic-gate     caddr_t buffer)
1363*0Sstevel@tonic-gate {
1364*0Sstevel@tonic-gate 	/*
1365*0Sstevel@tonic-gate 	 * There are no adjustments needed in this implementation.
1366*0Sstevel@tonic-gate 	 */
1367*0Sstevel@tonic-gate }
1368*0Sstevel@tonic-gate 
1369*0Sstevel@tonic-gate /*
1370*0Sstevel@tonic-gate  * SECTION: DDI Interrupt
1371*0Sstevel@tonic-gate  */
1372*0Sstevel@tonic-gate 
1373*0Sstevel@tonic-gate /*
1374*0Sstevel@tonic-gate  * get_intr_parent() is a generic routine that process a 1275 interrupt
1375*0Sstevel@tonic-gate  * map (imap) property.  This function returns a dev_info_t structure
1376*0Sstevel@tonic-gate  * which claims ownership of the interrupt domain.
1377*0Sstevel@tonic-gate  * It also returns the new interrupt translation within this new domain.
1378*0Sstevel@tonic-gate  * If an interrupt-parent or interrupt-map property are not found,
1379*0Sstevel@tonic-gate  * then we fallback to using the device tree's parent.
1380*0Sstevel@tonic-gate  *
1381*0Sstevel@tonic-gate  * imap entry format:
1382*0Sstevel@tonic-gate  * <reg>,<interrupt>,<phandle>,<translated interrupt>
1383*0Sstevel@tonic-gate  * reg - The register specification in the interrupts domain
1384*0Sstevel@tonic-gate  * interrupt - The interrupt specification
1385*0Sstevel@tonic-gate  * phandle - PROM handle of the device that owns the xlated interrupt domain
1386*0Sstevel@tonic-gate  * translated interrupt - interrupt specifier in the parents domain
1387*0Sstevel@tonic-gate  * note: <reg>,<interrupt> - The reg and interrupt can be combined to create
1388*0Sstevel@tonic-gate  *	a unique entry called a unit interrupt specifier.
1389*0Sstevel@tonic-gate  *
1390*0Sstevel@tonic-gate  * Here's the processing steps:
1391*0Sstevel@tonic-gate  * step1 - If the interrupt-parent property exists, create the ispec and
1392*0Sstevel@tonic-gate  *	return the dip of the interrupt parent.
1393*0Sstevel@tonic-gate  * step2 - Extract the interrupt-map property and the interrupt-map-mask
1394*0Sstevel@tonic-gate  *	If these don't exist, just return the device tree parent.
1395*0Sstevel@tonic-gate  * step3 - build up the unit interrupt specifier to match against the
1396*0Sstevel@tonic-gate  *	interrupt map property
1397*0Sstevel@tonic-gate  * step4 - Scan the interrupt-map property until a match is found
1398*0Sstevel@tonic-gate  * step4a - Extract the interrupt parent
1399*0Sstevel@tonic-gate  * step4b - Compare the unit interrupt specifier
1400*0Sstevel@tonic-gate  */
1401*0Sstevel@tonic-gate dev_info_t *
1402*0Sstevel@tonic-gate get_intr_parent(dev_info_t *pdip, dev_info_t *dip,
1403*0Sstevel@tonic-gate     ddi_ispec_t *child_ispecp, ddi_ispec_t **new_ispecp)
1404*0Sstevel@tonic-gate {
1405*0Sstevel@tonic-gate 	prop_1275_cell_t *imap, *imap_mask, *scan, *reg_p, *match_req;
1406*0Sstevel@tonic-gate 	int32_t imap_sz, imap_cells, imap_scan_cells, imap_mask_sz,
1407*0Sstevel@tonic-gate 	    addr_cells, intr_cells, reg_len, i, j;
1408*0Sstevel@tonic-gate 	int32_t match_found = 0;
1409*0Sstevel@tonic-gate 	dev_info_t *intr_parent_dip = NULL;
1410*0Sstevel@tonic-gate 	ddi_ispec_t *ispecp;
1411*0Sstevel@tonic-gate 	uint32_t *intr = child_ispecp->is_intr;
1412*0Sstevel@tonic-gate 	uint32_t nodeid;
1413*0Sstevel@tonic-gate 	static ddi_ispec_t *dup_ispec(ddi_ispec_t *ispecp);
1414*0Sstevel@tonic-gate #ifdef DEBUG
1415*0Sstevel@tonic-gate 	static int debug = 0;
1416*0Sstevel@tonic-gate #endif
1417*0Sstevel@tonic-gate 
1418*0Sstevel@tonic-gate 	*new_ispecp = (ddi_ispec_t *)NULL;
1419*0Sstevel@tonic-gate 
1420*0Sstevel@tonic-gate 	/*
1421*0Sstevel@tonic-gate 	 * step1
1422*0Sstevel@tonic-gate 	 * If we have an interrupt-parent property, this property represents
1423*0Sstevel@tonic-gate 	 * the nodeid of our interrupt parent.
1424*0Sstevel@tonic-gate 	 */
1425*0Sstevel@tonic-gate 	if ((nodeid = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
1426*0Sstevel@tonic-gate 	    "interrupt-parent", -1)) != -1) {
1427*0Sstevel@tonic-gate 		intr_parent_dip = e_ddi_nodeid_to_dip(nodeid);
1428*0Sstevel@tonic-gate 		ASSERT(intr_parent_dip);
1429*0Sstevel@tonic-gate 		/*
1430*0Sstevel@tonic-gate 		 * Attach the interrupt parent.
1431*0Sstevel@tonic-gate 		 *
1432*0Sstevel@tonic-gate 		 * N.B. e_ddi_nodeid_to_dip() isn't safe under DR.
1433*0Sstevel@tonic-gate 		 *	Also, interrupt parent isn't held. This needs
1434*0Sstevel@tonic-gate 		 *	to be revisited if DR-capable platforms implement
1435*0Sstevel@tonic-gate 		 *	interrupt redirection.
1436*0Sstevel@tonic-gate 		 */
1437*0Sstevel@tonic-gate 		if (i_ddi_attach_node_hierarchy(intr_parent_dip)
1438*0Sstevel@tonic-gate 		    != DDI_SUCCESS) {
1439*0Sstevel@tonic-gate 			ndi_rele_devi(intr_parent_dip);
1440*0Sstevel@tonic-gate 			return (NULL);
1441*0Sstevel@tonic-gate 		}
1442*0Sstevel@tonic-gate 
1443*0Sstevel@tonic-gate 		/* Create a new interrupt info struct and initialize it. */
1444*0Sstevel@tonic-gate 		ispecp = dup_ispec(child_ispecp);
1445*0Sstevel@tonic-gate 
1446*0Sstevel@tonic-gate 		*new_ispecp = ispecp;
1447*0Sstevel@tonic-gate 		return (intr_parent_dip);
1448*0Sstevel@tonic-gate 	}
1449*0Sstevel@tonic-gate 
1450*0Sstevel@tonic-gate 	/*
1451*0Sstevel@tonic-gate 	 * step2
1452*0Sstevel@tonic-gate 	 * Get interrupt map structure from PROM property
1453*0Sstevel@tonic-gate 	 */
1454*0Sstevel@tonic-gate 	if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
1455*0Sstevel@tonic-gate 	    "interrupt-map", (caddr_t)&imap, &imap_sz)
1456*0Sstevel@tonic-gate 	    != DDI_PROP_SUCCESS) {
1457*0Sstevel@tonic-gate 		/*
1458*0Sstevel@tonic-gate 		 * If we don't have an imap property, default to using the
1459*0Sstevel@tonic-gate 		 * device tree.
1460*0Sstevel@tonic-gate 		 */
1461*0Sstevel@tonic-gate 		/* Create a new interrupt info struct and initialize it. */
1462*0Sstevel@tonic-gate 		ispecp = dup_ispec(child_ispecp);
1463*0Sstevel@tonic-gate 
1464*0Sstevel@tonic-gate 		*new_ispecp = ispecp;
1465*0Sstevel@tonic-gate 		ndi_hold_devi(pdip);
1466*0Sstevel@tonic-gate 		return (pdip);
1467*0Sstevel@tonic-gate 	}
1468*0Sstevel@tonic-gate 
1469*0Sstevel@tonic-gate 	/* Get the interrupt mask property */
1470*0Sstevel@tonic-gate 	if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
1471*0Sstevel@tonic-gate 	    "interrupt-map-mask", (caddr_t)&imap_mask, &imap_mask_sz)
1472*0Sstevel@tonic-gate 	    != DDI_PROP_SUCCESS) {
1473*0Sstevel@tonic-gate 		/*
1474*0Sstevel@tonic-gate 		 * If we don't find this property, we have to fail the request
1475*0Sstevel@tonic-gate 		 * because the 1275 imap property wasn't defined correctly.
1476*0Sstevel@tonic-gate 		 */
1477*0Sstevel@tonic-gate 		ASSERT(intr_parent_dip == NULL);
1478*0Sstevel@tonic-gate 		goto exit2;
1479*0Sstevel@tonic-gate 	}
1480*0Sstevel@tonic-gate 
1481*0Sstevel@tonic-gate 	/* Get the address cell size */
1482*0Sstevel@tonic-gate 	addr_cells = ddi_getprop(DDI_DEV_T_ANY, pdip, 0,
1483*0Sstevel@tonic-gate 	    "#address-cells", 2);
1484*0Sstevel@tonic-gate 
1485*0Sstevel@tonic-gate 	/* Get the interrupts cell size */
1486*0Sstevel@tonic-gate 	intr_cells = ddi_getprop(DDI_DEV_T_ANY, pdip, 0,
1487*0Sstevel@tonic-gate 	    "#interrupt-cells", 1);
1488*0Sstevel@tonic-gate 
1489*0Sstevel@tonic-gate 	/*
1490*0Sstevel@tonic-gate 	 * step3
1491*0Sstevel@tonic-gate 	 * Now lets build up the unit interrupt specifier e.g. reg,intr
1492*0Sstevel@tonic-gate 	 * and apply the imap mask.  match_req will hold this when we're
1493*0Sstevel@tonic-gate 	 * through.
1494*0Sstevel@tonic-gate 	 */
1495*0Sstevel@tonic-gate 	if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, "reg",
1496*0Sstevel@tonic-gate 	    (caddr_t)&reg_p, &reg_len) != DDI_SUCCESS) {
1497*0Sstevel@tonic-gate 		ASSERT(intr_parent_dip == NULL);
1498*0Sstevel@tonic-gate 		goto exit3;
1499*0Sstevel@tonic-gate 	}
1500*0Sstevel@tonic-gate 
1501*0Sstevel@tonic-gate 	match_req = kmem_alloc(CELLS_1275_TO_BYTES(addr_cells) +
1502*0Sstevel@tonic-gate 	    CELLS_1275_TO_BYTES(intr_cells), KM_SLEEP);
1503*0Sstevel@tonic-gate 
1504*0Sstevel@tonic-gate 	for (i = 0; i < addr_cells; i++)
1505*0Sstevel@tonic-gate 		match_req[i] = (reg_p[i] & imap_mask[i]);
1506*0Sstevel@tonic-gate 
1507*0Sstevel@tonic-gate 	for (j = 0; j < intr_cells; i++, j++)
1508*0Sstevel@tonic-gate 		match_req[i] = (intr[j] & imap_mask[i]);
1509*0Sstevel@tonic-gate 
1510*0Sstevel@tonic-gate 	/* Calculate the imap size in cells */
1511*0Sstevel@tonic-gate 	imap_cells = BYTES_TO_1275_CELLS(imap_sz);
1512*0Sstevel@tonic-gate 
1513*0Sstevel@tonic-gate #ifdef DEBUG
1514*0Sstevel@tonic-gate 	if (debug)
1515*0Sstevel@tonic-gate 		prom_printf("reg cell size 0x%x, intr cell size 0x%x, "
1516*0Sstevel@tonic-gate 		    "match_request 0x%x, imap 0x%x\n", addr_cells, intr_cells,
1517*0Sstevel@tonic-gate 		    match_req, imap);
1518*0Sstevel@tonic-gate #endif
1519*0Sstevel@tonic-gate 
1520*0Sstevel@tonic-gate 	/*
1521*0Sstevel@tonic-gate 	 * Scan the imap property looking for a match of the interrupt unit
1522*0Sstevel@tonic-gate 	 * specifier.  This loop is rather complex since the data within the
1523*0Sstevel@tonic-gate 	 * imap property may vary in size.
1524*0Sstevel@tonic-gate 	 */
1525*0Sstevel@tonic-gate 	for (scan = imap, imap_scan_cells = i = 0;
1526*0Sstevel@tonic-gate 	    imap_scan_cells < imap_cells; scan += i, imap_scan_cells += i) {
1527*0Sstevel@tonic-gate 		int new_intr_cells;
1528*0Sstevel@tonic-gate 
1529*0Sstevel@tonic-gate 		/* Set the index to the nodeid field */
1530*0Sstevel@tonic-gate 		i = addr_cells + intr_cells;
1531*0Sstevel@tonic-gate 
1532*0Sstevel@tonic-gate 		/*
1533*0Sstevel@tonic-gate 		 * step4a
1534*0Sstevel@tonic-gate 		 * Translate the nodeid field to a dip
1535*0Sstevel@tonic-gate 		 */
1536*0Sstevel@tonic-gate 		ASSERT(intr_parent_dip == NULL);
1537*0Sstevel@tonic-gate 		intr_parent_dip = e_ddi_nodeid_to_dip((uint_t)scan[i++]);
1538*0Sstevel@tonic-gate 
1539*0Sstevel@tonic-gate 		ASSERT(intr_parent_dip != 0);
1540*0Sstevel@tonic-gate #ifdef DEBUG
1541*0Sstevel@tonic-gate 		if (debug)
1542*0Sstevel@tonic-gate 			prom_printf("scan 0x%x\n", scan);
1543*0Sstevel@tonic-gate #endif
1544*0Sstevel@tonic-gate 		/*
1545*0Sstevel@tonic-gate 		 * The tmp_dip describes the new domain, get it's interrupt
1546*0Sstevel@tonic-gate 		 * cell size
1547*0Sstevel@tonic-gate 		 */
1548*0Sstevel@tonic-gate 		new_intr_cells = ddi_getprop(DDI_DEV_T_ANY, intr_parent_dip, 0,
1549*0Sstevel@tonic-gate 		    "#interrupts-cells", 1);
1550*0Sstevel@tonic-gate 
1551*0Sstevel@tonic-gate 		/*
1552*0Sstevel@tonic-gate 		 * step4b
1553*0Sstevel@tonic-gate 		 * See if we have a match on the interrupt unit specifier
1554*0Sstevel@tonic-gate 		 */
1555*0Sstevel@tonic-gate 		if (cells_1275_cmp(match_req, scan, addr_cells + intr_cells)
1556*0Sstevel@tonic-gate 		    == 0) {
1557*0Sstevel@tonic-gate 			ddi_ispec_t ispec;
1558*0Sstevel@tonic-gate 			uint32_t *intr;
1559*0Sstevel@tonic-gate 
1560*0Sstevel@tonic-gate 			/*
1561*0Sstevel@tonic-gate 			 * Copy The childs ispec info excluding the interrupt
1562*0Sstevel@tonic-gate 			 */
1563*0Sstevel@tonic-gate 			ispec = *child_ispecp;
1564*0Sstevel@tonic-gate 
1565*0Sstevel@tonic-gate 			match_found = 1;
1566*0Sstevel@tonic-gate 
1567*0Sstevel@tonic-gate 			/*
1568*0Sstevel@tonic-gate 			 * If we have an imap parent whose not in our device
1569*0Sstevel@tonic-gate 			 * tree path, we need to hold and install that driver.
1570*0Sstevel@tonic-gate 			 */
1571*0Sstevel@tonic-gate 			if (i_ddi_attach_node_hierarchy(intr_parent_dip)
1572*0Sstevel@tonic-gate 			    != DDI_SUCCESS) {
1573*0Sstevel@tonic-gate 				ndi_rele_devi(intr_parent_dip);
1574*0Sstevel@tonic-gate 				intr_parent_dip = (dev_info_t *)NULL;
1575*0Sstevel@tonic-gate 				goto exit4;
1576*0Sstevel@tonic-gate 			}
1577*0Sstevel@tonic-gate 
1578*0Sstevel@tonic-gate 			/*
1579*0Sstevel@tonic-gate 			 * We need to handcraft an ispec along with a bus
1580*0Sstevel@tonic-gate 			 * interrupt value, so we can dup it into our
1581*0Sstevel@tonic-gate 			 * standard ispec structure.
1582*0Sstevel@tonic-gate 			 */
1583*0Sstevel@tonic-gate 			/* Extract the translated interrupt information */
1584*0Sstevel@tonic-gate 			intr = kmem_alloc(
1585*0Sstevel@tonic-gate 			    CELLS_1275_TO_BYTES(new_intr_cells), KM_SLEEP);
1586*0Sstevel@tonic-gate 
1587*0Sstevel@tonic-gate 			for (j = 0; j < new_intr_cells; j++, i++)
1588*0Sstevel@tonic-gate 				intr[j] = scan[i];
1589*0Sstevel@tonic-gate 
1590*0Sstevel@tonic-gate 			ispec.is_intr_sz =
1591*0Sstevel@tonic-gate 			    CELLS_1275_TO_BYTES(new_intr_cells);
1592*0Sstevel@tonic-gate 			ispec.is_intr = intr;
1593*0Sstevel@tonic-gate 
1594*0Sstevel@tonic-gate 			ispecp = dup_ispec(&ispec);
1595*0Sstevel@tonic-gate 
1596*0Sstevel@tonic-gate 			kmem_free(intr, CELLS_1275_TO_BYTES(new_intr_cells));
1597*0Sstevel@tonic-gate 
1598*0Sstevel@tonic-gate #ifdef DEBUG
1599*0Sstevel@tonic-gate 			if (debug)
1600*0Sstevel@tonic-gate 				prom_printf("dip 0x%x, intr info 0x%x\n",
1601*0Sstevel@tonic-gate 				    intr_parent_dip, ispecp);
1602*0Sstevel@tonic-gate #endif
1603*0Sstevel@tonic-gate 
1604*0Sstevel@tonic-gate 			break;
1605*0Sstevel@tonic-gate 		} else {
1606*0Sstevel@tonic-gate #ifdef DEBUG
1607*0Sstevel@tonic-gate 			if (debug)
1608*0Sstevel@tonic-gate 				prom_printf("dip 0x%x\n", intr_parent_dip);
1609*0Sstevel@tonic-gate #endif
1610*0Sstevel@tonic-gate 			ndi_rele_devi(intr_parent_dip);
1611*0Sstevel@tonic-gate 			intr_parent_dip = NULL;
1612*0Sstevel@tonic-gate 			i += new_intr_cells;
1613*0Sstevel@tonic-gate 		}
1614*0Sstevel@tonic-gate 	}
1615*0Sstevel@tonic-gate 
1616*0Sstevel@tonic-gate 	/*
1617*0Sstevel@tonic-gate 	 * If we haven't found our interrupt parent at this point, fallback
1618*0Sstevel@tonic-gate 	 * to using the device tree.
1619*0Sstevel@tonic-gate 	 */
1620*0Sstevel@tonic-gate 	if (!match_found) {
1621*0Sstevel@tonic-gate 		/* Create a new interrupt info struct and initialize it. */
1622*0Sstevel@tonic-gate 		ispecp = dup_ispec(child_ispecp);
1623*0Sstevel@tonic-gate 
1624*0Sstevel@tonic-gate 		ndi_hold_devi(pdip);
1625*0Sstevel@tonic-gate 		ASSERT(intr_parent_dip == NULL);
1626*0Sstevel@tonic-gate 		intr_parent_dip = pdip;
1627*0Sstevel@tonic-gate 	}
1628*0Sstevel@tonic-gate 
1629*0Sstevel@tonic-gate 	ASSERT(ispecp != NULL);
1630*0Sstevel@tonic-gate 	ASSERT(intr_parent_dip != NULL);
1631*0Sstevel@tonic-gate 	*new_ispecp = ispecp;
1632*0Sstevel@tonic-gate 
1633*0Sstevel@tonic-gate exit4:
1634*0Sstevel@tonic-gate 	kmem_free(reg_p, reg_len);
1635*0Sstevel@tonic-gate 	kmem_free(match_req, CELLS_1275_TO_BYTES(addr_cells) +
1636*0Sstevel@tonic-gate 	    CELLS_1275_TO_BYTES(intr_cells));
1637*0Sstevel@tonic-gate 
1638*0Sstevel@tonic-gate exit3:
1639*0Sstevel@tonic-gate 	kmem_free(imap_mask, imap_mask_sz);
1640*0Sstevel@tonic-gate 
1641*0Sstevel@tonic-gate exit2:
1642*0Sstevel@tonic-gate 	kmem_free(imap, imap_sz);
1643*0Sstevel@tonic-gate 
1644*0Sstevel@tonic-gate 	return (intr_parent_dip);
1645*0Sstevel@tonic-gate }
1646*0Sstevel@tonic-gate 
1647*0Sstevel@tonic-gate /*
1648*0Sstevel@tonic-gate  * Support routine for duplicating and initializing an interrupt specification.
1649*0Sstevel@tonic-gate  * The bus interrupt value will be allocated at the end of this structure, so
1650*0Sstevel@tonic-gate  * the corresponding routine i_ddi_free_ispec() should be used to free the
1651*0Sstevel@tonic-gate  * interrupt specification.
1652*0Sstevel@tonic-gate  */
1653*0Sstevel@tonic-gate static ddi_ispec_t *
1654*0Sstevel@tonic-gate dup_ispec(ddi_ispec_t *ispecp)
1655*0Sstevel@tonic-gate {
1656*0Sstevel@tonic-gate 	ddi_ispec_t *new_ispecp;
1657*0Sstevel@tonic-gate 
1658*0Sstevel@tonic-gate 	new_ispecp = kmem_alloc(sizeof (ddi_ispec_t) + ispecp->is_intr_sz,
1659*0Sstevel@tonic-gate 	    KM_SLEEP);
1660*0Sstevel@tonic-gate 
1661*0Sstevel@tonic-gate 	/* Copy the contents of the ispec */
1662*0Sstevel@tonic-gate 	*new_ispecp = *ispecp;
1663*0Sstevel@tonic-gate 
1664*0Sstevel@tonic-gate 	/* Reset the intr pointer to the one just created */
1665*0Sstevel@tonic-gate 	new_ispecp->is_intr = (uint32_t *)(new_ispecp + 1);
1666*0Sstevel@tonic-gate 
1667*0Sstevel@tonic-gate 	cells_1275_copy(ispecp->is_intr, new_ispecp->is_intr,
1668*0Sstevel@tonic-gate 	    BYTES_TO_1275_CELLS(ispecp->is_intr_sz));
1669*0Sstevel@tonic-gate 
1670*0Sstevel@tonic-gate 	return (new_ispecp);
1671*0Sstevel@tonic-gate }
1672*0Sstevel@tonic-gate 
1673*0Sstevel@tonic-gate int
1674*0Sstevel@tonic-gate i_ddi_get_nintrs(dev_info_t *dip)
1675*0Sstevel@tonic-gate {
1676*0Sstevel@tonic-gate 	int32_t intrlen;
1677*0Sstevel@tonic-gate 	prop_1275_cell_t intr_sz;
1678*0Sstevel@tonic-gate 	prop_1275_cell_t *ip;
1679*0Sstevel@tonic-gate 	int32_t ret = 0;
1680*0Sstevel@tonic-gate 
1681*0Sstevel@tonic-gate 	if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS |
1682*0Sstevel@tonic-gate 	    DDI_PROP_CANSLEEP,
1683*0Sstevel@tonic-gate 	    "interrupts", (caddr_t)&ip, &intrlen) == DDI_SUCCESS) {
1684*0Sstevel@tonic-gate 
1685*0Sstevel@tonic-gate 		intr_sz = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
1686*0Sstevel@tonic-gate 		    "#interrupt-cells", 1);
1687*0Sstevel@tonic-gate 		/* adjust for number of bytes */
1688*0Sstevel@tonic-gate 		intr_sz = CELLS_1275_TO_BYTES(intr_sz);
1689*0Sstevel@tonic-gate 
1690*0Sstevel@tonic-gate 		ret = intrlen / intr_sz;
1691*0Sstevel@tonic-gate 
1692*0Sstevel@tonic-gate 		kmem_free(ip, intrlen);
1693*0Sstevel@tonic-gate 	}
1694*0Sstevel@tonic-gate 
1695*0Sstevel@tonic-gate 	return (ret);
1696*0Sstevel@tonic-gate }
1697*0Sstevel@tonic-gate 
1698*0Sstevel@tonic-gate /*ARGSUSED*/
1699*0Sstevel@tonic-gate uint_t
1700*0Sstevel@tonic-gate softlevel1(caddr_t arg)
1701*0Sstevel@tonic-gate {
1702*0Sstevel@tonic-gate 	extern int siron_pending;
1703*0Sstevel@tonic-gate 
1704*0Sstevel@tonic-gate 	siron_pending = 0;
1705*0Sstevel@tonic-gate 	softint();
1706*0Sstevel@tonic-gate 	return (1);
1707*0Sstevel@tonic-gate }
1708*0Sstevel@tonic-gate 
1709*0Sstevel@tonic-gate /*
1710*0Sstevel@tonic-gate  * indirection table, to save us some large switch statements
1711*0Sstevel@tonic-gate  * NOTE: This must agree with "INTLEVEL_foo" constants in
1712*0Sstevel@tonic-gate  *	<sys/avintr.h>
1713*0Sstevel@tonic-gate  */
1714*0Sstevel@tonic-gate struct autovec *const vectorlist[] = { 0 };
1715*0Sstevel@tonic-gate 
1716*0Sstevel@tonic-gate /*
1717*0Sstevel@tonic-gate  * This value is exported here for the functions in avintr.c
1718*0Sstevel@tonic-gate  */
1719*0Sstevel@tonic-gate const uint_t maxautovec = (sizeof (vectorlist) / sizeof (vectorlist[0]));
1720*0Sstevel@tonic-gate 
1721*0Sstevel@tonic-gate /*
1722*0Sstevel@tonic-gate  * Check for machine specific interrupt levels which cannot be reassigned by
1723*0Sstevel@tonic-gate  * settrap(), sun4u version.
1724*0Sstevel@tonic-gate  *
1725*0Sstevel@tonic-gate  * sun4u does not support V8 SPARC "fast trap" handlers.
1726*0Sstevel@tonic-gate  */
1727*0Sstevel@tonic-gate /*ARGSUSED*/
1728*0Sstevel@tonic-gate int
1729*0Sstevel@tonic-gate exclude_settrap(int lvl)
1730*0Sstevel@tonic-gate {
1731*0Sstevel@tonic-gate 	return (1);
1732*0Sstevel@tonic-gate }
1733*0Sstevel@tonic-gate 
1734*0Sstevel@tonic-gate /*
1735*0Sstevel@tonic-gate  * Check for machine specific interrupt levels which cannot have interrupt
1736*0Sstevel@tonic-gate  * handlers added. We allow levels 1 through 15; level 0 is nonsense.
1737*0Sstevel@tonic-gate  */
1738*0Sstevel@tonic-gate /*ARGSUSED*/
1739*0Sstevel@tonic-gate int
1740*0Sstevel@tonic-gate exclude_level(int lvl)
1741*0Sstevel@tonic-gate {
1742*0Sstevel@tonic-gate 	return ((lvl < 1) || (lvl > 15));
1743*0Sstevel@tonic-gate }
1744*0Sstevel@tonic-gate 
1745*0Sstevel@tonic-gate /*
1746*0Sstevel@tonic-gate  * The following functions ready a cautious request to go up to the nexus
1747*0Sstevel@tonic-gate  * driver.  It is up to the nexus driver to decide how to process the request.
1748*0Sstevel@tonic-gate  * It may choose to call i_ddi_do_caut_get/put in this file, or do it
1749*0Sstevel@tonic-gate  * differently.
1750*0Sstevel@tonic-gate  */
1751*0Sstevel@tonic-gate 
1752*0Sstevel@tonic-gate static void
1753*0Sstevel@tonic-gate i_ddi_caut_getput_ctlops(
1754*0Sstevel@tonic-gate     ddi_acc_impl_t *hp, uint64_t host_addr, uint64_t dev_addr, size_t size,
1755*0Sstevel@tonic-gate     size_t repcount, uint_t flags, ddi_ctl_enum_t cmd)
1756*0Sstevel@tonic-gate {
1757*0Sstevel@tonic-gate 	peekpoke_ctlops_t	cautacc_ctlops_arg;
1758*0Sstevel@tonic-gate 
1759*0Sstevel@tonic-gate 	cautacc_ctlops_arg.size = size;
1760*0Sstevel@tonic-gate 	cautacc_ctlops_arg.dev_addr = dev_addr;
1761*0Sstevel@tonic-gate 	cautacc_ctlops_arg.host_addr = host_addr;
1762*0Sstevel@tonic-gate 	cautacc_ctlops_arg.handle = (ddi_acc_handle_t)hp;
1763*0Sstevel@tonic-gate 	cautacc_ctlops_arg.repcount = repcount;
1764*0Sstevel@tonic-gate 	cautacc_ctlops_arg.flags = flags;
1765*0Sstevel@tonic-gate 
1766*0Sstevel@tonic-gate 	(void) ddi_ctlops(hp->ahi_common.ah_dip, hp->ahi_common.ah_dip, cmd,
1767*0Sstevel@tonic-gate 	    &cautacc_ctlops_arg, NULL);
1768*0Sstevel@tonic-gate }
1769*0Sstevel@tonic-gate 
1770*0Sstevel@tonic-gate uint8_t
1771*0Sstevel@tonic-gate i_ddi_caut_get8(ddi_acc_impl_t *hp, uint8_t *addr)
1772*0Sstevel@tonic-gate {
1773*0Sstevel@tonic-gate 	uint8_t value;
1774*0Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr,
1775*0Sstevel@tonic-gate 	    sizeof (uint8_t), 1, 0, DDI_CTLOPS_PEEK);
1776*0Sstevel@tonic-gate 
1777*0Sstevel@tonic-gate 	return (value);
1778*0Sstevel@tonic-gate }
1779*0Sstevel@tonic-gate 
1780*0Sstevel@tonic-gate uint16_t
1781*0Sstevel@tonic-gate i_ddi_caut_get16(ddi_acc_impl_t *hp, uint16_t *addr)
1782*0Sstevel@tonic-gate {
1783*0Sstevel@tonic-gate 	uint16_t value;
1784*0Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr,
1785*0Sstevel@tonic-gate 	    sizeof (uint16_t), 1, 0, DDI_CTLOPS_PEEK);
1786*0Sstevel@tonic-gate 
1787*0Sstevel@tonic-gate 	return (value);
1788*0Sstevel@tonic-gate }
1789*0Sstevel@tonic-gate 
1790*0Sstevel@tonic-gate uint32_t
1791*0Sstevel@tonic-gate i_ddi_caut_get32(ddi_acc_impl_t *hp, uint32_t *addr)
1792*0Sstevel@tonic-gate {
1793*0Sstevel@tonic-gate 	uint32_t value;
1794*0Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr,
1795*0Sstevel@tonic-gate 	    sizeof (uint32_t), 1, 0, DDI_CTLOPS_PEEK);
1796*0Sstevel@tonic-gate 
1797*0Sstevel@tonic-gate 	return (value);
1798*0Sstevel@tonic-gate }
1799*0Sstevel@tonic-gate 
1800*0Sstevel@tonic-gate uint64_t
1801*0Sstevel@tonic-gate i_ddi_caut_get64(ddi_acc_impl_t *hp, uint64_t *addr)
1802*0Sstevel@tonic-gate {
1803*0Sstevel@tonic-gate 	uint64_t value;
1804*0Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr,
1805*0Sstevel@tonic-gate 	    sizeof (uint64_t), 1, 0, DDI_CTLOPS_PEEK);
1806*0Sstevel@tonic-gate 
1807*0Sstevel@tonic-gate 	return (value);
1808*0Sstevel@tonic-gate }
1809*0Sstevel@tonic-gate 
1810*0Sstevel@tonic-gate void
1811*0Sstevel@tonic-gate i_ddi_caut_put8(ddi_acc_impl_t *hp, uint8_t *addr, uint8_t value)
1812*0Sstevel@tonic-gate {
1813*0Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr,
1814*0Sstevel@tonic-gate 	    sizeof (uint8_t), 1, 0, DDI_CTLOPS_POKE);
1815*0Sstevel@tonic-gate }
1816*0Sstevel@tonic-gate 
1817*0Sstevel@tonic-gate void
1818*0Sstevel@tonic-gate i_ddi_caut_put16(ddi_acc_impl_t *hp, uint16_t *addr, uint16_t value)
1819*0Sstevel@tonic-gate {
1820*0Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr,
1821*0Sstevel@tonic-gate 	    sizeof (uint16_t), 1, 0, DDI_CTLOPS_POKE);
1822*0Sstevel@tonic-gate }
1823*0Sstevel@tonic-gate 
1824*0Sstevel@tonic-gate void
1825*0Sstevel@tonic-gate i_ddi_caut_put32(ddi_acc_impl_t *hp, uint32_t *addr, uint32_t value)
1826*0Sstevel@tonic-gate {
1827*0Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr,
1828*0Sstevel@tonic-gate 	    sizeof (uint32_t), 1, 0, DDI_CTLOPS_POKE);
1829*0Sstevel@tonic-gate }
1830*0Sstevel@tonic-gate 
1831*0Sstevel@tonic-gate void
1832*0Sstevel@tonic-gate i_ddi_caut_put64(ddi_acc_impl_t *hp, uint64_t *addr, uint64_t value)
1833*0Sstevel@tonic-gate {
1834*0Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr,
1835*0Sstevel@tonic-gate 	    sizeof (uint64_t), 1, 0, DDI_CTLOPS_POKE);
1836*0Sstevel@tonic-gate }
1837*0Sstevel@tonic-gate 
1838*0Sstevel@tonic-gate void
1839*0Sstevel@tonic-gate i_ddi_caut_rep_get8(ddi_acc_impl_t *hp, uint8_t *host_addr, uint8_t *dev_addr,
1840*0Sstevel@tonic-gate 	size_t repcount, uint_t flags)
1841*0Sstevel@tonic-gate {
1842*0Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr,
1843*0Sstevel@tonic-gate 	    sizeof (uint8_t), repcount, flags, DDI_CTLOPS_PEEK);
1844*0Sstevel@tonic-gate }
1845*0Sstevel@tonic-gate 
1846*0Sstevel@tonic-gate void
1847*0Sstevel@tonic-gate i_ddi_caut_rep_get16(ddi_acc_impl_t *hp, uint16_t *host_addr,
1848*0Sstevel@tonic-gate     uint16_t *dev_addr, size_t repcount, uint_t flags)
1849*0Sstevel@tonic-gate {
1850*0Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr,
1851*0Sstevel@tonic-gate 	    sizeof (uint16_t), repcount, flags, DDI_CTLOPS_PEEK);
1852*0Sstevel@tonic-gate }
1853*0Sstevel@tonic-gate 
1854*0Sstevel@tonic-gate void
1855*0Sstevel@tonic-gate i_ddi_caut_rep_get32(ddi_acc_impl_t *hp, uint32_t *host_addr,
1856*0Sstevel@tonic-gate     uint32_t *dev_addr, size_t repcount, uint_t flags)
1857*0Sstevel@tonic-gate {
1858*0Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr,
1859*0Sstevel@tonic-gate 	    sizeof (uint32_t), repcount, flags, DDI_CTLOPS_PEEK);
1860*0Sstevel@tonic-gate }
1861*0Sstevel@tonic-gate 
1862*0Sstevel@tonic-gate void
1863*0Sstevel@tonic-gate i_ddi_caut_rep_get64(ddi_acc_impl_t *hp, uint64_t *host_addr,
1864*0Sstevel@tonic-gate     uint64_t *dev_addr, size_t repcount, uint_t flags)
1865*0Sstevel@tonic-gate {
1866*0Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr,
1867*0Sstevel@tonic-gate 	    sizeof (uint64_t), repcount, flags, DDI_CTLOPS_PEEK);
1868*0Sstevel@tonic-gate }
1869*0Sstevel@tonic-gate 
1870*0Sstevel@tonic-gate void
1871*0Sstevel@tonic-gate i_ddi_caut_rep_put8(ddi_acc_impl_t *hp, uint8_t *host_addr, uint8_t *dev_addr,
1872*0Sstevel@tonic-gate 	size_t repcount, uint_t flags)
1873*0Sstevel@tonic-gate {
1874*0Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr,
1875*0Sstevel@tonic-gate 	    sizeof (uint8_t), repcount, flags, DDI_CTLOPS_POKE);
1876*0Sstevel@tonic-gate }
1877*0Sstevel@tonic-gate 
1878*0Sstevel@tonic-gate void
1879*0Sstevel@tonic-gate i_ddi_caut_rep_put16(ddi_acc_impl_t *hp, uint16_t *host_addr,
1880*0Sstevel@tonic-gate     uint16_t *dev_addr, size_t repcount, uint_t flags)
1881*0Sstevel@tonic-gate {
1882*0Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr,
1883*0Sstevel@tonic-gate 	    sizeof (uint16_t), repcount, flags, DDI_CTLOPS_POKE);
1884*0Sstevel@tonic-gate }
1885*0Sstevel@tonic-gate 
1886*0Sstevel@tonic-gate void
1887*0Sstevel@tonic-gate i_ddi_caut_rep_put32(ddi_acc_impl_t *hp, uint32_t *host_addr,
1888*0Sstevel@tonic-gate     uint32_t *dev_addr, size_t repcount, uint_t flags)
1889*0Sstevel@tonic-gate {
1890*0Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr,
1891*0Sstevel@tonic-gate 	    sizeof (uint32_t), repcount, flags, DDI_CTLOPS_POKE);
1892*0Sstevel@tonic-gate }
1893*0Sstevel@tonic-gate 
1894*0Sstevel@tonic-gate void
1895*0Sstevel@tonic-gate i_ddi_caut_rep_put64(ddi_acc_impl_t *hp, uint64_t *host_addr,
1896*0Sstevel@tonic-gate     uint64_t *dev_addr, size_t repcount, uint_t flags)
1897*0Sstevel@tonic-gate {
1898*0Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr,
1899*0Sstevel@tonic-gate 	    sizeof (uint64_t), repcount, flags, DDI_CTLOPS_POKE);
1900*0Sstevel@tonic-gate }
1901*0Sstevel@tonic-gate 
1902*0Sstevel@tonic-gate /*
1903*0Sstevel@tonic-gate  * This is called only to process peek/poke when the DIP is NULL.
1904*0Sstevel@tonic-gate  * Assume that this is for memory, as nexi take care of device safe accesses.
1905*0Sstevel@tonic-gate  */
1906*0Sstevel@tonic-gate int
1907*0Sstevel@tonic-gate peekpoke_mem(ddi_ctl_enum_t cmd, peekpoke_ctlops_t *in_args)
1908*0Sstevel@tonic-gate {
1909*0Sstevel@tonic-gate 	int err = DDI_SUCCESS;
1910*0Sstevel@tonic-gate 	on_trap_data_t otd;
1911*0Sstevel@tonic-gate 
1912*0Sstevel@tonic-gate 	/* Set up protected environment. */
1913*0Sstevel@tonic-gate 	if (!on_trap(&otd, OT_DATA_ACCESS)) {
1914*0Sstevel@tonic-gate 		uintptr_t tramp = otd.ot_trampoline;
1915*0Sstevel@tonic-gate 
1916*0Sstevel@tonic-gate 		if (cmd == DDI_CTLOPS_POKE) {
1917*0Sstevel@tonic-gate 			otd.ot_trampoline = (uintptr_t)&poke_fault;
1918*0Sstevel@tonic-gate 			err = do_poke(in_args->size, (void *)in_args->dev_addr,
1919*0Sstevel@tonic-gate 			    (void *)in_args->host_addr);
1920*0Sstevel@tonic-gate 		} else {
1921*0Sstevel@tonic-gate 			otd.ot_trampoline = (uintptr_t)&peek_fault;
1922*0Sstevel@tonic-gate 			err = do_peek(in_args->size, (void *)in_args->dev_addr,
1923*0Sstevel@tonic-gate 			    (void *)in_args->host_addr);
1924*0Sstevel@tonic-gate 		}
1925*0Sstevel@tonic-gate 		otd.ot_trampoline = tramp;
1926*0Sstevel@tonic-gate 	} else
1927*0Sstevel@tonic-gate 		err = DDI_FAILURE;
1928*0Sstevel@tonic-gate 
1929*0Sstevel@tonic-gate 	/* Take down protected environment. */
1930*0Sstevel@tonic-gate 	no_trap();
1931*0Sstevel@tonic-gate 
1932*0Sstevel@tonic-gate 	return (err);
1933*0Sstevel@tonic-gate }
1934