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