xref: /illumos-gate/usr/src/uts/sun4/os/ddi_impl.c (revision bdcaf82257ab2deb6b46efaaa4bc93a1a44b3885)
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 = add_softintr(hdlp->ih_pri, hdlp->ih_cb_func,
559 	    hdlp->ih_cb_arg1)) == 0) {
560 
561 		return (DDI_FAILURE);
562 	}
563 
564 	/* use uintptr_t to suppress the gcc warning */
565 	hdlp->ih_private = (void *)(uintptr_t)rval;
566 
567 	return (DDI_SUCCESS);
568 }
569 
570 void
571 i_ddi_remove_softint(ddi_softint_hdl_impl_t *hdlp)
572 {
573 	uint_t		intr_id;
574 
575 	/* disable */
576 	ASSERT(hdlp->ih_private != NULL);
577 	/* use uintptr_t to suppress the gcc warning */
578 	intr_id = (uint_t)(uintptr_t)hdlp->ih_private;
579 	rem_softintr(intr_id);
580 	hdlp->ih_private = NULL;
581 }
582 
583 int
584 i_ddi_trigger_softint(ddi_softint_hdl_impl_t *hdlp, void *arg2)
585 {
586 	uint_t		intr_id;
587 	int		ret;
588 
589 	ASSERT(hdlp != NULL);
590 	ASSERT(hdlp->ih_private != NULL);
591 
592 	intr_id = (uint_t)hdlp->ih_private;
593 
594 	/* update the vector table for the 2nd arg */
595 	ret = update_softint_arg2(intr_id, arg2);
596 	if (ret == DDI_SUCCESS)
597 		setsoftint(intr_id);
598 
599 	return (ret);
600 }
601 
602 /* ARGSUSED */
603 int
604 i_ddi_set_softint_pri(ddi_softint_hdl_impl_t *hdlp, uint_t old_pri)
605 {
606 	uint_t		intr_id;
607 	int		ret;
608 
609 	ASSERT(hdlp != NULL);
610 	ASSERT(hdlp->ih_private != NULL);
611 
612 	intr_id = (uint_t)hdlp->ih_private;
613 
614 	/* update the vector table for the new priority */
615 	ret = update_softint_pri(intr_id, hdlp->ih_pri);
616 
617 	return (ret);
618 }
619 
620 /*
621  * Support routine for allocating and initializing an interrupt specification.
622  * The bus interrupt value will be allocated at the end of this structure, so
623  * the corresponding routine i_ddi_free_ispec() should be used to free the
624  * interrupt specification.
625  */
626 void
627 i_ddi_alloc_ispec(dev_info_t *dip, uint_t inumber, ddi_intrspec_t *intrspecp)
628 {
629 	int32_t intrlen, intr_cells, max_intrs;
630 	prop_1275_cell_t *ip;
631 	prop_1275_cell_t intr_sz;
632 	ddi_ispec_t **ispecp = (ddi_ispec_t **)intrspecp;
633 
634 	*ispecp = NULL;
635 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS |
636 	    DDI_PROP_CANSLEEP,
637 	    "interrupts", (caddr_t)&ip, &intrlen) == DDI_SUCCESS) {
638 
639 		intr_cells = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
640 		    "#interrupt-cells", 1);
641 
642 		/* adjust for number of bytes */
643 		intr_sz = CELLS_1275_TO_BYTES(intr_cells);
644 
645 		/* Calculate the number of interrupts */
646 		max_intrs = intrlen / intr_sz;
647 
648 		if (inumber < max_intrs) {
649 			prop_1275_cell_t *intrp = ip;
650 
651 			*ispecp = kmem_zalloc(
652 			    (sizeof (ddi_ispec_t) + intr_sz), KM_SLEEP);
653 
654 			(*ispecp)->is_intr =
655 			    (uint32_t *)(*ispecp + 1);
656 
657 			/* Index into interrupt property */
658 			intrp += (inumber * intr_cells);
659 
660 			cells_1275_copy(intrp,
661 			    (*ispecp)->is_intr, intr_cells);
662 
663 			(*ispecp)->is_intr_sz = intr_sz;
664 
665 			(*ispecp)->is_pil = i_ddi_get_intr_pri(dip, inumber);
666 		}
667 
668 		kmem_free(ip, intrlen);
669 	}
670 }
671 
672 /*
673  * Analog routine to i_ddi_alloc_ispec() used to free the interrupt
674  * specification and the associated bus interrupt value.
675  */
676 void
677 i_ddi_free_ispec(ddi_intrspec_t intrspecp)
678 {
679 	ddi_ispec_t *ispecp = (ddi_ispec_t *)intrspecp;
680 
681 	kmem_free(ispecp, sizeof (ddi_ispec_t) + (ispecp->is_intr_sz));
682 }
683 
684 /*
685  * i_ddi_get_intr_pri - Get the interrupt-priorities property from
686  * the specified device.
687  */
688 uint32_t
689 i_ddi_get_intr_pri(dev_info_t *dip, uint_t inumber)
690 {
691 	uint32_t *intr_prio_p;
692 	uint32_t pri = 0;
693 	int32_t i;
694 
695 	/*
696 	 * Use the "interrupt-priorities" property to determine the
697 	 * the pil/ipl for the interrupt handler.
698 	 */
699 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
700 	    "interrupt-priorities", (caddr_t)&intr_prio_p,
701 	    &i) == DDI_SUCCESS) {
702 		if (inumber < (i / sizeof (int32_t)))
703 			pri = intr_prio_p[inumber];
704 		kmem_free(intr_prio_p, i);
705 	}
706 
707 	return (pri);
708 }
709 
710 /*
711  * SECTION: DDI Memory/DMA
712  */
713 
714 static vmem_t *little_endian_arena;
715 static vmem_t *big_endian_arena;
716 
717 static void *
718 segkmem_alloc_le(vmem_t *vmp, size_t size, int flag)
719 {
720 	return (segkmem_xalloc(vmp, NULL, size, flag, HAT_STRUCTURE_LE,
721 	    segkmem_page_create, NULL));
722 }
723 
724 static void *
725 segkmem_alloc_be(vmem_t *vmp, size_t size, int flag)
726 {
727 	return (segkmem_xalloc(vmp, NULL, size, flag, HAT_STRUCTURE_BE,
728 	    segkmem_page_create, NULL));
729 }
730 
731 void
732 ka_init(void)
733 {
734 	little_endian_arena = vmem_create("little_endian", NULL, 0, 1,
735 	    segkmem_alloc_le, segkmem_free, heap_arena, 0, VM_SLEEP);
736 	big_endian_arena = vmem_create("big_endian", NULL, 0, 1,
737 	    segkmem_alloc_be, segkmem_free, heap_arena, 0, VM_SLEEP);
738 }
739 
740 /*
741  * Allocate from the system, aligned on a specific boundary.
742  * The alignment, if non-zero, must be a power of 2.
743  */
744 static void *
745 kalloca(size_t size, size_t align, int cansleep, uint_t endian_flags)
746 {
747 	size_t *addr, *raddr, rsize;
748 	size_t hdrsize = 4 * sizeof (size_t);	/* must be power of 2 */
749 
750 	align = MAX(align, hdrsize);
751 	ASSERT((align & (align - 1)) == 0);
752 
753 	/*
754 	 * We need to allocate
755 	 *    rsize = size + hdrsize + align - MIN(hdrsize, buffer_alignment)
756 	 * bytes to be sure we have enough freedom to satisfy the request.
757 	 * Since the buffer alignment depends on the request size, this is
758 	 * not straightforward to use directly.
759 	 *
760 	 * kmem guarantees that any allocation of a 64-byte multiple will be
761 	 * 64-byte aligned.  Since rounding up the request could add more
762 	 * than we save, we compute the size with and without alignment, and
763 	 * use the smaller of the two.
764 	 */
765 	rsize = size + hdrsize + align;
766 
767 	if (endian_flags == DDI_STRUCTURE_LE_ACC) {
768 		raddr = vmem_alloc(little_endian_arena, rsize,
769 		    cansleep ? VM_SLEEP : VM_NOSLEEP);
770 	} else {
771 		raddr = vmem_alloc(big_endian_arena, rsize,
772 		    cansleep ? VM_SLEEP : VM_NOSLEEP);
773 	}
774 
775 	if (raddr == NULL)
776 		return (NULL);
777 
778 	addr = (size_t *)P2ROUNDUP((uintptr_t)raddr + hdrsize, align);
779 	ASSERT((uintptr_t)addr + size - (uintptr_t)raddr <= rsize);
780 
781 	addr[-3] = (size_t)endian_flags;
782 	addr[-2] = (size_t)raddr;
783 	addr[-1] = rsize;
784 
785 	return (addr);
786 }
787 
788 static void
789 kfreea(void *addr)
790 {
791 	size_t *saddr = addr;
792 
793 	if (saddr[-3] == DDI_STRUCTURE_LE_ACC)
794 		vmem_free(little_endian_arena, (void *)saddr[-2], saddr[-1]);
795 	else
796 		vmem_free(big_endian_arena, (void *)saddr[-2], saddr[-1]);
797 }
798 
799 int
800 i_ddi_mem_alloc(dev_info_t *dip, ddi_dma_attr_t *attr,
801     size_t length, int cansleep, int streaming,
802     ddi_device_acc_attr_t *accattrp,
803     caddr_t *kaddrp, size_t *real_length, ddi_acc_hdl_t *handlep)
804 {
805 	caddr_t a;
806 	int iomin, align;
807 	uint_t endian_flags = DDI_NEVERSWAP_ACC;
808 
809 #if defined(lint)
810 	*handlep = *handlep;
811 #endif
812 
813 	/*
814 	 * Check legality of arguments
815 	 */
816 	if (length == 0 || kaddrp == NULL || attr == NULL) {
817 		return (DDI_FAILURE);
818 	}
819 	if (attr->dma_attr_minxfer == 0 || attr->dma_attr_align == 0 ||
820 	    (attr->dma_attr_align & (attr->dma_attr_align - 1)) ||
821 	    (attr->dma_attr_minxfer & (attr->dma_attr_minxfer - 1))) {
822 		return (DDI_FAILURE);
823 	}
824 
825 	/*
826 	 * Drivers for 64-bit capable SBus devices will encode
827 	 * the burtsizes for 64-bit xfers in the upper 16-bits.
828 	 * For DMA alignment, we use the most restrictive
829 	 * alignment of 32-bit and 64-bit xfers.
830 	 */
831 	iomin = (attr->dma_attr_burstsizes & 0xffff) |
832 	    ((attr->dma_attr_burstsizes >> 16) & 0xffff);
833 	/*
834 	 * If a driver set burtsizes to 0, we give him byte alignment.
835 	 * Otherwise align at the burtsizes boundary.
836 	 */
837 	if (iomin == 0)
838 		iomin = 1;
839 	else
840 		iomin = 1 << (ddi_fls(iomin) - 1);
841 	iomin = maxbit(iomin, attr->dma_attr_minxfer);
842 	iomin = maxbit(iomin, attr->dma_attr_align);
843 	iomin = ddi_iomin(dip, iomin, streaming);
844 	if (iomin == 0)
845 		return (DDI_FAILURE);
846 
847 	ASSERT((iomin & (iomin - 1)) == 0);
848 	ASSERT(iomin >= attr->dma_attr_minxfer);
849 	ASSERT(iomin >= attr->dma_attr_align);
850 
851 	length = P2ROUNDUP(length, iomin);
852 	align = iomin;
853 
854 	if (accattrp != NULL)
855 		endian_flags = accattrp->devacc_attr_endian_flags;
856 
857 	a = kalloca(length, align, cansleep, endian_flags);
858 	if ((*kaddrp = a) == 0) {
859 		return (DDI_FAILURE);
860 	} else {
861 		if (real_length) {
862 			*real_length = length;
863 		}
864 		if (handlep) {
865 			/*
866 			 * assign handle information
867 			 */
868 			impl_acc_hdl_init(handlep);
869 		}
870 		return (DDI_SUCCESS);
871 	}
872 }
873 
874 /*
875  * covert old DMA limits structure to DMA attribute structure
876  * and continue
877  */
878 int
879 i_ddi_mem_alloc_lim(dev_info_t *dip, ddi_dma_lim_t *limits,
880     size_t length, int cansleep, int streaming,
881     ddi_device_acc_attr_t *accattrp, caddr_t *kaddrp,
882     uint_t *real_length, ddi_acc_hdl_t *ap)
883 {
884 	ddi_dma_attr_t dma_attr, *attrp;
885 	size_t rlen;
886 	int ret;
887 
888 	ASSERT(limits);
889 	attrp = &dma_attr;
890 	attrp->dma_attr_version = DMA_ATTR_V0;
891 	attrp->dma_attr_addr_lo = (uint64_t)limits->dlim_addr_lo;
892 	attrp->dma_attr_addr_hi = (uint64_t)limits->dlim_addr_hi;
893 	attrp->dma_attr_count_max = (uint64_t)-1;
894 	attrp->dma_attr_align = 1;
895 	attrp->dma_attr_burstsizes = (uint_t)limits->dlim_burstsizes;
896 	attrp->dma_attr_minxfer = (uint32_t)limits->dlim_minxfer;
897 	attrp->dma_attr_maxxfer = (uint64_t)-1;
898 	attrp->dma_attr_seg = (uint64_t)limits->dlim_cntr_max;
899 	attrp->dma_attr_sgllen = 1;
900 	attrp->dma_attr_granular = 1;
901 	attrp->dma_attr_flags = 0;
902 
903 	ret = i_ddi_mem_alloc(dip, attrp, length, cansleep, streaming,
904 	    accattrp, kaddrp, &rlen, ap);
905 	if (ret == DDI_SUCCESS) {
906 		if (real_length)
907 			*real_length = (uint_t)rlen;
908 	}
909 	return (ret);
910 }
911 
912 /* ARGSUSED */
913 void
914 i_ddi_mem_free(caddr_t kaddr, int stream)
915 {
916 	kfreea(kaddr);
917 }
918 
919 /*
920  * SECTION: DDI Data Access
921  */
922 
923 static uintptr_t impl_acc_hdl_id = 0;
924 
925 /*
926  * access handle allocator
927  */
928 ddi_acc_hdl_t *
929 impl_acc_hdl_get(ddi_acc_handle_t hdl)
930 {
931 	/*
932 	 * Extract the access handle address from the DDI implemented
933 	 * access handle
934 	 */
935 	return (&((ddi_acc_impl_t *)hdl)->ahi_common);
936 }
937 
938 ddi_acc_handle_t
939 impl_acc_hdl_alloc(int (*waitfp)(caddr_t), caddr_t arg)
940 {
941 	ddi_acc_impl_t *hp;
942 	on_trap_data_t *otp;
943 	int sleepflag;
944 
945 	sleepflag = ((waitfp == (int (*)())KM_SLEEP) ? KM_SLEEP : KM_NOSLEEP);
946 
947 	/*
948 	 * Allocate and initialize the data access handle and error status.
949 	 */
950 	if ((hp = kmem_zalloc(sizeof (ddi_acc_impl_t), sleepflag)) == NULL)
951 		goto fail;
952 	if ((hp->ahi_err = (ndi_err_t *)kmem_zalloc(
953 	    sizeof (ndi_err_t), sleepflag)) == NULL) {
954 		kmem_free(hp, sizeof (ddi_acc_impl_t));
955 		goto fail;
956 	}
957 	if ((otp = (on_trap_data_t *)kmem_zalloc(
958 	    sizeof (on_trap_data_t), sleepflag)) == NULL) {
959 		kmem_free(hp->ahi_err, sizeof (ndi_err_t));
960 		kmem_free(hp, sizeof (ddi_acc_impl_t));
961 		goto fail;
962 	}
963 	hp->ahi_err->err_ontrap = otp;
964 	hp->ahi_common.ah_platform_private = (void *)hp;
965 
966 	return ((ddi_acc_handle_t)hp);
967 fail:
968 	if ((waitfp != (int (*)())KM_SLEEP) &&
969 	    (waitfp != (int (*)())KM_NOSLEEP))
970 		ddi_set_callback(waitfp, arg, &impl_acc_hdl_id);
971 	return (NULL);
972 }
973 
974 void
975 impl_acc_hdl_free(ddi_acc_handle_t handle)
976 {
977 	ddi_acc_impl_t *hp;
978 
979 	/*
980 	 * The supplied (ddi_acc_handle_t) is actually a (ddi_acc_impl_t *),
981 	 * because that's what we allocated in impl_acc_hdl_alloc() above.
982 	 */
983 	hp = (ddi_acc_impl_t *)handle;
984 	if (hp) {
985 		kmem_free(hp->ahi_err->err_ontrap, sizeof (on_trap_data_t));
986 		kmem_free(hp->ahi_err, sizeof (ndi_err_t));
987 		kmem_free(hp, sizeof (ddi_acc_impl_t));
988 		if (impl_acc_hdl_id)
989 			ddi_run_callback(&impl_acc_hdl_id);
990 	}
991 }
992 
993 void
994 impl_acc_err_init(ddi_acc_hdl_t *handlep)
995 {
996 	int fmcap;
997 	ndi_err_t *errp;
998 	on_trap_data_t *otp;
999 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)handlep;
1000 
1001 	fmcap = ddi_fm_capable(handlep->ah_dip);
1002 
1003 	if (handlep->ah_acc.devacc_attr_version < DDI_DEVICE_ATTR_V1 ||
1004 	    !DDI_FM_ACC_ERR_CAP(fmcap)) {
1005 		handlep->ah_acc.devacc_attr_access = DDI_DEFAULT_ACC;
1006 	} else if (DDI_FM_ACC_ERR_CAP(fmcap)) {
1007 		if (handlep->ah_acc.devacc_attr_access == DDI_DEFAULT_ACC) {
1008 			i_ddi_drv_ereport_post(handlep->ah_dip, DVR_EFMCAP,
1009 			    NULL, DDI_NOSLEEP);
1010 		} else {
1011 			errp = hp->ahi_err;
1012 			otp = (on_trap_data_t *)errp->err_ontrap;
1013 			otp->ot_handle = (void *)(hp);
1014 			otp->ot_prot = OT_DATA_ACCESS;
1015 			if (handlep->ah_acc.devacc_attr_access ==
1016 			    DDI_CAUTIOUS_ACC)
1017 				otp->ot_trampoline =
1018 				    (uintptr_t)&i_ddi_caut_trampoline;
1019 			else
1020 				otp->ot_trampoline =
1021 				    (uintptr_t)&i_ddi_prot_trampoline;
1022 			errp->err_status = DDI_FM_OK;
1023 			errp->err_expected = DDI_FM_ERR_UNEXPECTED;
1024 		}
1025 	}
1026 }
1027 
1028 void
1029 impl_acc_hdl_init(ddi_acc_hdl_t *handlep)
1030 {
1031 	ddi_acc_impl_t *hp;
1032 
1033 	ASSERT(handlep);
1034 
1035 	hp = (ddi_acc_impl_t *)handlep;
1036 
1037 	/*
1038 	 * check for SW byte-swapping
1039 	 */
1040 	hp->ahi_get8 = i_ddi_get8;
1041 	hp->ahi_put8 = i_ddi_put8;
1042 	hp->ahi_rep_get8 = i_ddi_rep_get8;
1043 	hp->ahi_rep_put8 = i_ddi_rep_put8;
1044 	if (handlep->ah_acc.devacc_attr_endian_flags & DDI_STRUCTURE_LE_ACC) {
1045 		hp->ahi_get16 = i_ddi_swap_get16;
1046 		hp->ahi_get32 = i_ddi_swap_get32;
1047 		hp->ahi_get64 = i_ddi_swap_get64;
1048 		hp->ahi_put16 = i_ddi_swap_put16;
1049 		hp->ahi_put32 = i_ddi_swap_put32;
1050 		hp->ahi_put64 = i_ddi_swap_put64;
1051 		hp->ahi_rep_get16 = i_ddi_swap_rep_get16;
1052 		hp->ahi_rep_get32 = i_ddi_swap_rep_get32;
1053 		hp->ahi_rep_get64 = i_ddi_swap_rep_get64;
1054 		hp->ahi_rep_put16 = i_ddi_swap_rep_put16;
1055 		hp->ahi_rep_put32 = i_ddi_swap_rep_put32;
1056 		hp->ahi_rep_put64 = i_ddi_swap_rep_put64;
1057 	} else {
1058 		hp->ahi_get16 = i_ddi_get16;
1059 		hp->ahi_get32 = i_ddi_get32;
1060 		hp->ahi_get64 = i_ddi_get64;
1061 		hp->ahi_put16 = i_ddi_put16;
1062 		hp->ahi_put32 = i_ddi_put32;
1063 		hp->ahi_put64 = i_ddi_put64;
1064 		hp->ahi_rep_get16 = i_ddi_rep_get16;
1065 		hp->ahi_rep_get32 = i_ddi_rep_get32;
1066 		hp->ahi_rep_get64 = i_ddi_rep_get64;
1067 		hp->ahi_rep_put16 = i_ddi_rep_put16;
1068 		hp->ahi_rep_put32 = i_ddi_rep_put32;
1069 		hp->ahi_rep_put64 = i_ddi_rep_put64;
1070 	}
1071 
1072 	/* Legacy fault flags and support */
1073 	hp->ahi_fault_check = i_ddi_acc_fault_check;
1074 	hp->ahi_fault_notify = i_ddi_acc_fault_notify;
1075 	hp->ahi_fault = 0;
1076 	impl_acc_err_init(handlep);
1077 }
1078 
1079 void
1080 i_ddi_acc_set_fault(ddi_acc_handle_t handle)
1081 {
1082 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)handle;
1083 
1084 	if (!hp->ahi_fault) {
1085 		hp->ahi_fault = 1;
1086 			(*hp->ahi_fault_notify)(hp);
1087 	}
1088 }
1089 
1090 void
1091 i_ddi_acc_clr_fault(ddi_acc_handle_t handle)
1092 {
1093 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)handle;
1094 
1095 	if (hp->ahi_fault) {
1096 		hp->ahi_fault = 0;
1097 			(*hp->ahi_fault_notify)(hp);
1098 	}
1099 }
1100 
1101 /* ARGSUSED */
1102 void
1103 i_ddi_acc_fault_notify(ddi_acc_impl_t *hp)
1104 {
1105 	/* Default version, does nothing */
1106 }
1107 
1108 /*
1109  * SECTION: Misc functions
1110  */
1111 
1112 /*
1113  * instance wrappers
1114  */
1115 /*ARGSUSED*/
1116 uint_t
1117 impl_assign_instance(dev_info_t *dip)
1118 {
1119 	return ((uint_t)-1);
1120 }
1121 
1122 /*ARGSUSED*/
1123 int
1124 impl_keep_instance(dev_info_t *dip)
1125 {
1126 	return (DDI_FAILURE);
1127 }
1128 
1129 /*ARGSUSED*/
1130 int
1131 impl_free_instance(dev_info_t *dip)
1132 {
1133 	return (DDI_FAILURE);
1134 }
1135 
1136 /*ARGSUSED*/
1137 int
1138 impl_check_cpu(dev_info_t *devi)
1139 {
1140 	return (DDI_SUCCESS);
1141 }
1142 
1143 
1144 static const char *nocopydevs[] = {
1145 	"SUNW,ffb",
1146 	"SUNW,afb",
1147 	NULL
1148 };
1149 
1150 /*
1151  * Perform a copy from a memory mapped device (whose devinfo pointer is devi)
1152  * separately mapped at devaddr in the kernel to a kernel buffer at kaddr.
1153  */
1154 /*ARGSUSED*/
1155 int
1156 e_ddi_copyfromdev(dev_info_t *devi,
1157     off_t off, const void *devaddr, void *kaddr, size_t len)
1158 {
1159 	const char **argv;
1160 
1161 	for (argv = nocopydevs; *argv; argv++)
1162 		if (strcmp(ddi_binding_name(devi), *argv) == 0) {
1163 			bzero(kaddr, len);
1164 			return (0);
1165 		}
1166 
1167 	bcopy(devaddr, kaddr, len);
1168 	return (0);
1169 }
1170 
1171 /*
1172  * Perform a copy to a memory mapped device (whose devinfo pointer is devi)
1173  * separately mapped at devaddr in the kernel from a kernel buffer at kaddr.
1174  */
1175 /*ARGSUSED*/
1176 int
1177 e_ddi_copytodev(dev_info_t *devi,
1178     off_t off, const void *kaddr, void *devaddr, size_t len)
1179 {
1180 	const char **argv;
1181 
1182 	for (argv = nocopydevs; *argv; argv++)
1183 		if (strcmp(ddi_binding_name(devi), *argv) == 0)
1184 			return (1);
1185 
1186 	bcopy(kaddr, devaddr, len);
1187 	return (0);
1188 }
1189 
1190 /*
1191  * Boot Configuration
1192  */
1193 idprom_t idprom;
1194 
1195 /*
1196  * Configure the hardware on the system.
1197  * Called before the rootfs is mounted
1198  */
1199 void
1200 configure(void)
1201 {
1202 	extern void i_ddi_init_root();
1203 
1204 	/* We better have released boot by this time! */
1205 	ASSERT(!bootops);
1206 
1207 	/*
1208 	 * Determine whether or not to use the fpu, V9 SPARC cpus
1209 	 * always have one. Could check for existence of a fp queue,
1210 	 * Ultra I, II and IIa do not have a fp queue.
1211 	 */
1212 	if (fpu_exists)
1213 		fpu_probe();
1214 	else
1215 		cmn_err(CE_CONT, "FPU not in use\n");
1216 
1217 #if 0 /* XXXQ - not necessary for sun4u */
1218 	/*
1219 	 * This following line fixes bugid 1041296; we need to do a
1220 	 * prom_nextnode(0) because this call ALSO patches the DMA+
1221 	 * bug in Campus-B and Phoenix. The prom uncaches the traptable
1222 	 * page as a side-effect of devr_next(0) (which prom_nextnode calls),
1223 	 * so this *must* be executed early on. (XXX This is untrue for sun4u)
1224 	 */
1225 	(void) prom_nextnode((dnode_t)0);
1226 #endif
1227 
1228 	/*
1229 	 * Initialize devices on the machine.
1230 	 * Uses configuration tree built by the PROMs to determine what
1231 	 * is present, and builds a tree of prototype dev_info nodes
1232 	 * corresponding to the hardware which identified itself.
1233 	 */
1234 	i_ddi_init_root();
1235 
1236 #ifdef	DDI_PROP_DEBUG
1237 	(void) ddi_prop_debug(1);	/* Enable property debugging */
1238 #endif	/* DDI_PROP_DEBUG */
1239 }
1240 
1241 /*
1242  * The "status" property indicates the operational status of a device.
1243  * If this property is present, the value is a string indicating the
1244  * status of the device as follows:
1245  *
1246  *	"okay"		operational.
1247  *	"disabled"	not operational, but might become operational.
1248  *	"fail"		not operational because a fault has been detected,
1249  *			and it is unlikely that the device will become
1250  *			operational without repair. no additional details
1251  *			are available.
1252  *	"fail-xxx"	not operational because a fault has been detected,
1253  *			and it is unlikely that the device will become
1254  *			operational without repair. "xxx" is additional
1255  *			human-readable information about the particular
1256  *			fault condition that was detected.
1257  *
1258  * The absence of this property means that the operational status is
1259  * unknown or okay.
1260  *
1261  * This routine checks the status property of the specified device node
1262  * and returns 0 if the operational status indicates failure, and 1 otherwise.
1263  *
1264  * The property may exist on plug-in cards the existed before IEEE 1275-1994.
1265  * And, in that case, the property may not even be a string. So we carefully
1266  * check for the value "fail", in the beginning of the string, noting
1267  * the property length.
1268  */
1269 int
1270 status_okay(int id, char *buf, int buflen)
1271 {
1272 	char status_buf[OBP_MAXPROPNAME];
1273 	char *bufp = buf;
1274 	int len = buflen;
1275 	int proplen;
1276 	static const char *status = "status";
1277 	static const char *fail = "fail";
1278 	size_t fail_len = strlen(fail);
1279 
1280 	/*
1281 	 * Get the proplen ... if it's smaller than "fail",
1282 	 * or doesn't exist ... then we don't care, since
1283 	 * the value can't begin with the char string "fail".
1284 	 *
1285 	 * NB: proplen, if it's a string, includes the NULL in the
1286 	 * the size of the property, and fail_len does not.
1287 	 */
1288 	proplen = prom_getproplen((dnode_t)id, (caddr_t)status);
1289 	if (proplen <= fail_len)	/* nonexistent or uninteresting len */
1290 		return (1);
1291 
1292 	/*
1293 	 * if a buffer was provided, use it
1294 	 */
1295 	if ((buf == (char *)NULL) || (buflen <= 0)) {
1296 		bufp = status_buf;
1297 		len = sizeof (status_buf);
1298 	}
1299 	*bufp = (char)0;
1300 
1301 	/*
1302 	 * Get the property into the buffer, to the extent of the buffer,
1303 	 * and in case the buffer is smaller than the property size,
1304 	 * NULL terminate the buffer. (This handles the case where
1305 	 * a buffer was passed in and the caller wants to print the
1306 	 * value, but the buffer was too small).
1307 	 */
1308 	(void) prom_bounded_getprop((dnode_t)id, (caddr_t)status,
1309 	    (caddr_t)bufp, len);
1310 	*(bufp + len - 1) = (char)0;
1311 
1312 	/*
1313 	 * If the value begins with the char string "fail",
1314 	 * then it means the node is failed. We don't care
1315 	 * about any other values. We assume the node is ok
1316 	 * although it might be 'disabled'.
1317 	 */
1318 	if (strncmp(bufp, fail, fail_len) == 0)
1319 		return (0);
1320 
1321 	return (1);
1322 }
1323 
1324 
1325 /*
1326  * We set the cpu type from the idprom, if we can.
1327  * Note that we just read out the contents of it, for the most part.
1328  */
1329 void
1330 setcputype(void)
1331 {
1332 	/*
1333 	 * We cache the idprom info early on so that we don't
1334 	 * rummage through the NVRAM unnecessarily later.
1335 	 */
1336 	(void) prom_getidprom((caddr_t)&idprom, sizeof (idprom));
1337 }
1338 
1339 /*
1340  *  Here is where we actually infer meanings to the members of idprom_t
1341  */
1342 void
1343 parse_idprom(void)
1344 {
1345 	if (idprom.id_format == IDFORM_1) {
1346 		uint_t i;
1347 
1348 		(void) localetheraddr((struct ether_addr *)idprom.id_ether,
1349 		    (struct ether_addr *)NULL);
1350 
1351 		i = idprom.id_machine << 24;
1352 		i = i + idprom.id_serial;
1353 		numtos((ulong_t)i, hw_serial);
1354 	} else
1355 		prom_printf("Invalid format code in IDprom.\n");
1356 }
1357 
1358 /*
1359  * Allow for implementation specific correction of PROM property values.
1360  */
1361 /*ARGSUSED*/
1362 void
1363 impl_fix_props(dev_info_t *dip, dev_info_t *ch_dip, char *name, int len,
1364     caddr_t buffer)
1365 {
1366 	/*
1367 	 * There are no adjustments needed in this implementation.
1368 	 */
1369 }
1370 
1371 /*
1372  * SECTION: DDI Interrupt
1373  */
1374 
1375 /*
1376  * get_intr_parent() is a generic routine that process a 1275 interrupt
1377  * map (imap) property.  This function returns a dev_info_t structure
1378  * which claims ownership of the interrupt domain.
1379  * It also returns the new interrupt translation within this new domain.
1380  * If an interrupt-parent or interrupt-map property are not found,
1381  * then we fallback to using the device tree's parent.
1382  *
1383  * imap entry format:
1384  * <reg>,<interrupt>,<phandle>,<translated interrupt>
1385  * reg - The register specification in the interrupts domain
1386  * interrupt - The interrupt specification
1387  * phandle - PROM handle of the device that owns the xlated interrupt domain
1388  * translated interrupt - interrupt specifier in the parents domain
1389  * note: <reg>,<interrupt> - The reg and interrupt can be combined to create
1390  *	a unique entry called a unit interrupt specifier.
1391  *
1392  * Here's the processing steps:
1393  * step1 - If the interrupt-parent property exists, create the ispec and
1394  *	return the dip of the interrupt parent.
1395  * step2 - Extract the interrupt-map property and the interrupt-map-mask
1396  *	If these don't exist, just return the device tree parent.
1397  * step3 - build up the unit interrupt specifier to match against the
1398  *	interrupt map property
1399  * step4 - Scan the interrupt-map property until a match is found
1400  * step4a - Extract the interrupt parent
1401  * step4b - Compare the unit interrupt specifier
1402  */
1403 dev_info_t *
1404 get_intr_parent(dev_info_t *pdip, dev_info_t *dip,
1405     ddi_ispec_t *child_ispecp, ddi_ispec_t **new_ispecp)
1406 {
1407 	prop_1275_cell_t *imap, *imap_mask, *scan, *reg_p, *match_req;
1408 	int32_t imap_sz, imap_cells, imap_scan_cells, imap_mask_sz,
1409 	    addr_cells, intr_cells, reg_len, i, j;
1410 	int32_t match_found = 0;
1411 	dev_info_t *intr_parent_dip = NULL;
1412 	ddi_ispec_t *ispecp;
1413 	uint32_t *intr = child_ispecp->is_intr;
1414 	uint32_t nodeid;
1415 	static ddi_ispec_t *dup_ispec(ddi_ispec_t *ispecp);
1416 #ifdef DEBUG
1417 	static int debug = 0;
1418 #endif
1419 
1420 	*new_ispecp = (ddi_ispec_t *)NULL;
1421 
1422 	/*
1423 	 * step1
1424 	 * If we have an interrupt-parent property, this property represents
1425 	 * the nodeid of our interrupt parent.
1426 	 */
1427 	if ((nodeid = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
1428 	    "interrupt-parent", -1)) != -1) {
1429 		intr_parent_dip = e_ddi_nodeid_to_dip(nodeid);
1430 		ASSERT(intr_parent_dip);
1431 		/*
1432 		 * Attach the interrupt parent.
1433 		 *
1434 		 * N.B. e_ddi_nodeid_to_dip() isn't safe under DR.
1435 		 *	Also, interrupt parent isn't held. This needs
1436 		 *	to be revisited if DR-capable platforms implement
1437 		 *	interrupt redirection.
1438 		 */
1439 		if (i_ddi_attach_node_hierarchy(intr_parent_dip)
1440 		    != DDI_SUCCESS) {
1441 			ndi_rele_devi(intr_parent_dip);
1442 			return (NULL);
1443 		}
1444 
1445 		/* Create a new interrupt info struct and initialize it. */
1446 		ispecp = dup_ispec(child_ispecp);
1447 
1448 		*new_ispecp = ispecp;
1449 		return (intr_parent_dip);
1450 	}
1451 
1452 	/*
1453 	 * step2
1454 	 * Get interrupt map structure from PROM property
1455 	 */
1456 	if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
1457 	    "interrupt-map", (caddr_t)&imap, &imap_sz)
1458 	    != DDI_PROP_SUCCESS) {
1459 		/*
1460 		 * If we don't have an imap property, default to using the
1461 		 * device tree.
1462 		 */
1463 		/* Create a new interrupt info struct and initialize it. */
1464 		ispecp = dup_ispec(child_ispecp);
1465 
1466 		*new_ispecp = ispecp;
1467 		ndi_hold_devi(pdip);
1468 		return (pdip);
1469 	}
1470 
1471 	/* Get the interrupt mask property */
1472 	if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
1473 	    "interrupt-map-mask", (caddr_t)&imap_mask, &imap_mask_sz)
1474 	    != DDI_PROP_SUCCESS) {
1475 		/*
1476 		 * If we don't find this property, we have to fail the request
1477 		 * because the 1275 imap property wasn't defined correctly.
1478 		 */
1479 		ASSERT(intr_parent_dip == NULL);
1480 		goto exit2;
1481 	}
1482 
1483 	/* Get the address cell size */
1484 	addr_cells = ddi_getprop(DDI_DEV_T_ANY, pdip, 0,
1485 	    "#address-cells", 2);
1486 
1487 	/* Get the interrupts cell size */
1488 	intr_cells = ddi_getprop(DDI_DEV_T_ANY, pdip, 0,
1489 	    "#interrupt-cells", 1);
1490 
1491 	/*
1492 	 * step3
1493 	 * Now lets build up the unit interrupt specifier e.g. reg,intr
1494 	 * and apply the imap mask.  match_req will hold this when we're
1495 	 * through.
1496 	 */
1497 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
1498 	    (caddr_t)&reg_p, &reg_len) != DDI_SUCCESS) {
1499 		ASSERT(intr_parent_dip == NULL);
1500 		goto exit3;
1501 	}
1502 
1503 	match_req = kmem_alloc(CELLS_1275_TO_BYTES(addr_cells) +
1504 	    CELLS_1275_TO_BYTES(intr_cells), KM_SLEEP);
1505 
1506 	for (i = 0; i < addr_cells; i++)
1507 		match_req[i] = (reg_p[i] & imap_mask[i]);
1508 
1509 	for (j = 0; j < intr_cells; i++, j++)
1510 		match_req[i] = (intr[j] & imap_mask[i]);
1511 
1512 	/* Calculate the imap size in cells */
1513 	imap_cells = BYTES_TO_1275_CELLS(imap_sz);
1514 
1515 #ifdef DEBUG
1516 	if (debug)
1517 		prom_printf("reg cell size 0x%x, intr cell size 0x%x, "
1518 		    "match_request 0x%p, imap 0x%p\n", addr_cells, intr_cells,
1519 		    match_req, imap);
1520 #endif
1521 
1522 	/*
1523 	 * Scan the imap property looking for a match of the interrupt unit
1524 	 * specifier.  This loop is rather complex since the data within the
1525 	 * imap property may vary in size.
1526 	 */
1527 	for (scan = imap, imap_scan_cells = i = 0;
1528 	    imap_scan_cells < imap_cells; scan += i, imap_scan_cells += i) {
1529 		int new_intr_cells;
1530 
1531 		/* Set the index to the nodeid field */
1532 		i = addr_cells + intr_cells;
1533 
1534 		/*
1535 		 * step4a
1536 		 * Translate the nodeid field to a dip
1537 		 */
1538 		ASSERT(intr_parent_dip == NULL);
1539 		intr_parent_dip = e_ddi_nodeid_to_dip((uint_t)scan[i++]);
1540 
1541 		ASSERT(intr_parent_dip != 0);
1542 #ifdef DEBUG
1543 		if (debug)
1544 			prom_printf("scan 0x%p\n", scan);
1545 #endif
1546 		/*
1547 		 * The tmp_dip describes the new domain, get it's interrupt
1548 		 * cell size
1549 		 */
1550 		new_intr_cells = ddi_getprop(DDI_DEV_T_ANY, intr_parent_dip, 0,
1551 		    "#interrupts-cells", 1);
1552 
1553 		/*
1554 		 * step4b
1555 		 * See if we have a match on the interrupt unit specifier
1556 		 */
1557 		if (cells_1275_cmp(match_req, scan, addr_cells + intr_cells)
1558 		    == 0) {
1559 			ddi_ispec_t ispec;
1560 			uint32_t *intr;
1561 
1562 			/*
1563 			 * Copy The childs ispec info excluding the interrupt
1564 			 */
1565 			ispec = *child_ispecp;
1566 
1567 			match_found = 1;
1568 
1569 			/*
1570 			 * If we have an imap parent whose not in our device
1571 			 * tree path, we need to hold and install that driver.
1572 			 */
1573 			if (i_ddi_attach_node_hierarchy(intr_parent_dip)
1574 			    != DDI_SUCCESS) {
1575 				ndi_rele_devi(intr_parent_dip);
1576 				intr_parent_dip = (dev_info_t *)NULL;
1577 				goto exit4;
1578 			}
1579 
1580 			/*
1581 			 * We need to handcraft an ispec along with a bus
1582 			 * interrupt value, so we can dup it into our
1583 			 * standard ispec structure.
1584 			 */
1585 			/* Extract the translated interrupt information */
1586 			intr = kmem_alloc(
1587 			    CELLS_1275_TO_BYTES(new_intr_cells), KM_SLEEP);
1588 
1589 			for (j = 0; j < new_intr_cells; j++, i++)
1590 				intr[j] = scan[i];
1591 
1592 			ispec.is_intr_sz =
1593 			    CELLS_1275_TO_BYTES(new_intr_cells);
1594 			ispec.is_intr = intr;
1595 
1596 			ispecp = dup_ispec(&ispec);
1597 
1598 			kmem_free(intr, CELLS_1275_TO_BYTES(new_intr_cells));
1599 
1600 #ifdef DEBUG
1601 			if (debug)
1602 				prom_printf("dip 0x%p, intr info 0x%p\n",
1603 				    intr_parent_dip, ispecp);
1604 #endif
1605 
1606 			break;
1607 		} else {
1608 #ifdef DEBUG
1609 			if (debug)
1610 				prom_printf("dip 0x%p\n", intr_parent_dip);
1611 #endif
1612 			ndi_rele_devi(intr_parent_dip);
1613 			intr_parent_dip = NULL;
1614 			i += new_intr_cells;
1615 		}
1616 	}
1617 
1618 	/*
1619 	 * If we haven't found our interrupt parent at this point, fallback
1620 	 * to using the device tree.
1621 	 */
1622 	if (!match_found) {
1623 		/* Create a new interrupt info struct and initialize it. */
1624 		ispecp = dup_ispec(child_ispecp);
1625 
1626 		ndi_hold_devi(pdip);
1627 		ASSERT(intr_parent_dip == NULL);
1628 		intr_parent_dip = pdip;
1629 	}
1630 
1631 	ASSERT(ispecp != NULL);
1632 	ASSERT(intr_parent_dip != NULL);
1633 	*new_ispecp = ispecp;
1634 
1635 exit4:
1636 	kmem_free(reg_p, reg_len);
1637 	kmem_free(match_req, CELLS_1275_TO_BYTES(addr_cells) +
1638 	    CELLS_1275_TO_BYTES(intr_cells));
1639 
1640 exit3:
1641 	kmem_free(imap_mask, imap_mask_sz);
1642 
1643 exit2:
1644 	kmem_free(imap, imap_sz);
1645 
1646 	return (intr_parent_dip);
1647 }
1648 
1649 /*
1650  * Support routine for duplicating and initializing an interrupt specification.
1651  * The bus interrupt value will be allocated at the end of this structure, so
1652  * the corresponding routine i_ddi_free_ispec() should be used to free the
1653  * interrupt specification.
1654  */
1655 static ddi_ispec_t *
1656 dup_ispec(ddi_ispec_t *ispecp)
1657 {
1658 	ddi_ispec_t *new_ispecp;
1659 
1660 	new_ispecp = kmem_alloc(sizeof (ddi_ispec_t) + ispecp->is_intr_sz,
1661 	    KM_SLEEP);
1662 
1663 	/* Copy the contents of the ispec */
1664 	*new_ispecp = *ispecp;
1665 
1666 	/* Reset the intr pointer to the one just created */
1667 	new_ispecp->is_intr = (uint32_t *)(new_ispecp + 1);
1668 
1669 	cells_1275_copy(ispecp->is_intr, new_ispecp->is_intr,
1670 	    BYTES_TO_1275_CELLS(ispecp->is_intr_sz));
1671 
1672 	return (new_ispecp);
1673 }
1674 
1675 int
1676 i_ddi_get_nintrs(dev_info_t *dip)
1677 {
1678 	int32_t intrlen;
1679 	prop_1275_cell_t intr_sz;
1680 	prop_1275_cell_t *ip;
1681 	int32_t ret = 0;
1682 
1683 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS |
1684 	    DDI_PROP_CANSLEEP,
1685 	    "interrupts", (caddr_t)&ip, &intrlen) == DDI_SUCCESS) {
1686 
1687 		intr_sz = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
1688 		    "#interrupt-cells", 1);
1689 		/* adjust for number of bytes */
1690 		intr_sz = CELLS_1275_TO_BYTES(intr_sz);
1691 
1692 		ret = intrlen / intr_sz;
1693 
1694 		kmem_free(ip, intrlen);
1695 	}
1696 
1697 	return (ret);
1698 }
1699 
1700 /*ARGSUSED*/
1701 uint_t
1702 softlevel1(caddr_t arg)
1703 {
1704 	softint();
1705 	return (1);
1706 }
1707 
1708 /*
1709  * indirection table, to save us some large switch statements
1710  * NOTE: This must agree with "INTLEVEL_foo" constants in
1711  *	<sys/avintr.h>
1712  */
1713 struct autovec *const vectorlist[] = { 0 };
1714 
1715 /*
1716  * This value is exported here for the functions in avintr.c
1717  */
1718 const uint_t maxautovec = (sizeof (vectorlist) / sizeof (vectorlist[0]));
1719 
1720 /*
1721  * Check for machine specific interrupt levels which cannot be reassigned by
1722  * settrap(), sun4u version.
1723  *
1724  * sun4u does not support V8 SPARC "fast trap" handlers.
1725  */
1726 /*ARGSUSED*/
1727 int
1728 exclude_settrap(int lvl)
1729 {
1730 	return (1);
1731 }
1732 
1733 /*
1734  * Check for machine specific interrupt levels which cannot have interrupt
1735  * handlers added. We allow levels 1 through 15; level 0 is nonsense.
1736  */
1737 /*ARGSUSED*/
1738 int
1739 exclude_level(int lvl)
1740 {
1741 	return ((lvl < 1) || (lvl > 15));
1742 }
1743 
1744 /*
1745  * The following functions ready a cautious request to go up to the nexus
1746  * driver.  It is up to the nexus driver to decide how to process the request.
1747  * It may choose to call i_ddi_do_caut_get/put in this file, or do it
1748  * differently.
1749  */
1750 
1751 static void
1752 i_ddi_caut_getput_ctlops(
1753     ddi_acc_impl_t *hp, uint64_t host_addr, uint64_t dev_addr, size_t size,
1754     size_t repcount, uint_t flags, ddi_ctl_enum_t cmd)
1755 {
1756 	peekpoke_ctlops_t	cautacc_ctlops_arg;
1757 
1758 	cautacc_ctlops_arg.size = size;
1759 	cautacc_ctlops_arg.dev_addr = dev_addr;
1760 	cautacc_ctlops_arg.host_addr = host_addr;
1761 	cautacc_ctlops_arg.handle = (ddi_acc_handle_t)hp;
1762 	cautacc_ctlops_arg.repcount = repcount;
1763 	cautacc_ctlops_arg.flags = flags;
1764 
1765 	(void) ddi_ctlops(hp->ahi_common.ah_dip, hp->ahi_common.ah_dip, cmd,
1766 	    &cautacc_ctlops_arg, NULL);
1767 }
1768 
1769 uint8_t
1770 i_ddi_caut_get8(ddi_acc_impl_t *hp, uint8_t *addr)
1771 {
1772 	uint8_t value;
1773 	i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr,
1774 	    sizeof (uint8_t), 1, 0, DDI_CTLOPS_PEEK);
1775 
1776 	return (value);
1777 }
1778 
1779 uint16_t
1780 i_ddi_caut_get16(ddi_acc_impl_t *hp, uint16_t *addr)
1781 {
1782 	uint16_t value;
1783 	i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr,
1784 	    sizeof (uint16_t), 1, 0, DDI_CTLOPS_PEEK);
1785 
1786 	return (value);
1787 }
1788 
1789 uint32_t
1790 i_ddi_caut_get32(ddi_acc_impl_t *hp, uint32_t *addr)
1791 {
1792 	uint32_t value;
1793 	i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr,
1794 	    sizeof (uint32_t), 1, 0, DDI_CTLOPS_PEEK);
1795 
1796 	return (value);
1797 }
1798 
1799 uint64_t
1800 i_ddi_caut_get64(ddi_acc_impl_t *hp, uint64_t *addr)
1801 {
1802 	uint64_t value;
1803 	i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr,
1804 	    sizeof (uint64_t), 1, 0, DDI_CTLOPS_PEEK);
1805 
1806 	return (value);
1807 }
1808 
1809 void
1810 i_ddi_caut_put8(ddi_acc_impl_t *hp, uint8_t *addr, uint8_t value)
1811 {
1812 	i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr,
1813 	    sizeof (uint8_t), 1, 0, DDI_CTLOPS_POKE);
1814 }
1815 
1816 void
1817 i_ddi_caut_put16(ddi_acc_impl_t *hp, uint16_t *addr, uint16_t value)
1818 {
1819 	i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr,
1820 	    sizeof (uint16_t), 1, 0, DDI_CTLOPS_POKE);
1821 }
1822 
1823 void
1824 i_ddi_caut_put32(ddi_acc_impl_t *hp, uint32_t *addr, uint32_t value)
1825 {
1826 	i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr,
1827 	    sizeof (uint32_t), 1, 0, DDI_CTLOPS_POKE);
1828 }
1829 
1830 void
1831 i_ddi_caut_put64(ddi_acc_impl_t *hp, uint64_t *addr, uint64_t value)
1832 {
1833 	i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr,
1834 	    sizeof (uint64_t), 1, 0, DDI_CTLOPS_POKE);
1835 }
1836 
1837 void
1838 i_ddi_caut_rep_get8(ddi_acc_impl_t *hp, uint8_t *host_addr, uint8_t *dev_addr,
1839 	size_t repcount, uint_t flags)
1840 {
1841 	i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr,
1842 	    sizeof (uint8_t), repcount, flags, DDI_CTLOPS_PEEK);
1843 }
1844 
1845 void
1846 i_ddi_caut_rep_get16(ddi_acc_impl_t *hp, uint16_t *host_addr,
1847     uint16_t *dev_addr, size_t repcount, uint_t flags)
1848 {
1849 	i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr,
1850 	    sizeof (uint16_t), repcount, flags, DDI_CTLOPS_PEEK);
1851 }
1852 
1853 void
1854 i_ddi_caut_rep_get32(ddi_acc_impl_t *hp, uint32_t *host_addr,
1855     uint32_t *dev_addr, size_t repcount, uint_t flags)
1856 {
1857 	i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr,
1858 	    sizeof (uint32_t), repcount, flags, DDI_CTLOPS_PEEK);
1859 }
1860 
1861 void
1862 i_ddi_caut_rep_get64(ddi_acc_impl_t *hp, uint64_t *host_addr,
1863     uint64_t *dev_addr, size_t repcount, uint_t flags)
1864 {
1865 	i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr,
1866 	    sizeof (uint64_t), repcount, flags, DDI_CTLOPS_PEEK);
1867 }
1868 
1869 void
1870 i_ddi_caut_rep_put8(ddi_acc_impl_t *hp, uint8_t *host_addr, uint8_t *dev_addr,
1871 	size_t repcount, uint_t flags)
1872 {
1873 	i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr,
1874 	    sizeof (uint8_t), repcount, flags, DDI_CTLOPS_POKE);
1875 }
1876 
1877 void
1878 i_ddi_caut_rep_put16(ddi_acc_impl_t *hp, uint16_t *host_addr,
1879     uint16_t *dev_addr, size_t repcount, uint_t flags)
1880 {
1881 	i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr,
1882 	    sizeof (uint16_t), repcount, flags, DDI_CTLOPS_POKE);
1883 }
1884 
1885 void
1886 i_ddi_caut_rep_put32(ddi_acc_impl_t *hp, uint32_t *host_addr,
1887     uint32_t *dev_addr, size_t repcount, uint_t flags)
1888 {
1889 	i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr,
1890 	    sizeof (uint32_t), repcount, flags, DDI_CTLOPS_POKE);
1891 }
1892 
1893 void
1894 i_ddi_caut_rep_put64(ddi_acc_impl_t *hp, uint64_t *host_addr,
1895     uint64_t *dev_addr, size_t repcount, uint_t flags)
1896 {
1897 	i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr,
1898 	    sizeof (uint64_t), repcount, flags, DDI_CTLOPS_POKE);
1899 }
1900 
1901 /*
1902  * This is called only to process peek/poke when the DIP is NULL.
1903  * Assume that this is for memory, as nexi take care of device safe accesses.
1904  */
1905 int
1906 peekpoke_mem(ddi_ctl_enum_t cmd, peekpoke_ctlops_t *in_args)
1907 {
1908 	int err = DDI_SUCCESS;
1909 	on_trap_data_t otd;
1910 
1911 	/* Set up protected environment. */
1912 	if (!on_trap(&otd, OT_DATA_ACCESS)) {
1913 		uintptr_t tramp = otd.ot_trampoline;
1914 
1915 		if (cmd == DDI_CTLOPS_POKE) {
1916 			otd.ot_trampoline = (uintptr_t)&poke_fault;
1917 			err = do_poke(in_args->size, (void *)in_args->dev_addr,
1918 			    (void *)in_args->host_addr);
1919 		} else {
1920 			otd.ot_trampoline = (uintptr_t)&peek_fault;
1921 			err = do_peek(in_args->size, (void *)in_args->dev_addr,
1922 			    (void *)in_args->host_addr);
1923 		}
1924 		otd.ot_trampoline = tramp;
1925 	} else
1926 		err = DDI_FAILURE;
1927 
1928 	/* Take down protected environment. */
1929 	no_trap();
1930 
1931 	return (err);
1932 }
1933