xref: /titanic_50/usr/src/uts/sun4/os/ddi_impl.c (revision de710d24d2fae4468e64da999e1d952a247f142c)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
500d0963fSdilpreet  * Common Development and Distribution License (the "License").
600d0963fSdilpreet  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217b93957cSeota 
227c478bd9Sstevel@tonic-gate /*
235679c89fSjv227347  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
26cd21e7c5SGarrett D'Amore /*
27b89e420aSGarrett D'Amore  * Copyright 2014 Garrett D'Amore <garrett@damore.org>
28cd21e7c5SGarrett D'Amore  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate  * sun4 specific DDI implementation
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
347c478bd9Sstevel@tonic-gate #include <sys/ddi_subrdefs.h>
357c478bd9Sstevel@tonic-gate #include <sys/machsystm.h>
367c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
377c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
387c478bd9Sstevel@tonic-gate #include <sys/ontrap.h>
397c478bd9Sstevel@tonic-gate #include <vm/seg_kmem.h>
407c478bd9Sstevel@tonic-gate #include <sys/membar.h>
417c478bd9Sstevel@tonic-gate #include <sys/dditypes.h>
427c478bd9Sstevel@tonic-gate #include <sys/ndifm.h>
437c478bd9Sstevel@tonic-gate #include <sys/fm/io/ddi.h>
447c478bd9Sstevel@tonic-gate #include <sys/ivintr.h>
457c478bd9Sstevel@tonic-gate #include <sys/bootconf.h>
467c478bd9Sstevel@tonic-gate #include <sys/conf.h>
477c478bd9Sstevel@tonic-gate #include <sys/ethernet.h>
487c478bd9Sstevel@tonic-gate #include <sys/idprom.h>
497c478bd9Sstevel@tonic-gate #include <sys/promif.h>
507c478bd9Sstevel@tonic-gate #include <sys/prom_plat.h>
517c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h>
527c478bd9Sstevel@tonic-gate #include <sys/fpu/fpusystm.h>
537c478bd9Sstevel@tonic-gate #include <sys/vm.h>
547c478bd9Sstevel@tonic-gate #include <sys/ddi_isa.h>
5525e8c5aaSvikram #include <sys/modctl.h>
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate dev_info_t *get_intr_parent(dev_info_t *, dev_info_t *,
58a195726fSgovinda     ddi_intr_handle_impl_t *);
597c478bd9Sstevel@tonic-gate #pragma weak get_intr_parent
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate int process_intr_ops(dev_info_t *, dev_info_t *, ddi_intr_op_t,
627c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *, void *);
637c478bd9Sstevel@tonic-gate #pragma weak process_intr_ops
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate void cells_1275_copy(prop_1275_cell_t *, prop_1275_cell_t *, int32_t);
667c478bd9Sstevel@tonic-gate     prop_1275_cell_t *cells_1275_cmp(prop_1275_cell_t *, prop_1275_cell_t *,
677c478bd9Sstevel@tonic-gate     int32_t len);
687c478bd9Sstevel@tonic-gate #pragma weak cells_1275_copy
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate /*
717c478bd9Sstevel@tonic-gate  * Wrapper for ddi_prop_lookup_int_array().
727c478bd9Sstevel@tonic-gate  * This is handy because it returns the prop length in
737c478bd9Sstevel@tonic-gate  * bytes which is what most of the callers require.
747c478bd9Sstevel@tonic-gate  */
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate static int
get_prop_int_array(dev_info_t * di,char * pname,int ** pval,uint_t * plen)777c478bd9Sstevel@tonic-gate get_prop_int_array(dev_info_t *di, char *pname, int **pval, uint_t *plen)
787c478bd9Sstevel@tonic-gate {
797c478bd9Sstevel@tonic-gate 	int ret;
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate 	if ((ret = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, di,
827c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, pname, pval, plen)) == DDI_PROP_SUCCESS) {
837c478bd9Sstevel@tonic-gate 		*plen = (*plen) * (uint_t)sizeof (int);
847c478bd9Sstevel@tonic-gate 	}
857c478bd9Sstevel@tonic-gate 	return (ret);
867c478bd9Sstevel@tonic-gate }
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate /*
897c478bd9Sstevel@tonic-gate  * SECTION: DDI Node Configuration
907c478bd9Sstevel@tonic-gate  */
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate /*
937c478bd9Sstevel@tonic-gate  * init_regspec_64:
947c478bd9Sstevel@tonic-gate  *
957c478bd9Sstevel@tonic-gate  * If the parent #size-cells is 2, convert the upa-style or
967c478bd9Sstevel@tonic-gate  * safari-style reg property from 2-size cells to 1 size cell
977c478bd9Sstevel@tonic-gate  * format, ignoring the size_hi, which must be zero for devices.
987c478bd9Sstevel@tonic-gate  * (It won't be zero in the memory list properties in the memory
997c478bd9Sstevel@tonic-gate  * nodes, but that doesn't matter here.)
1007c478bd9Sstevel@tonic-gate  */
1017c478bd9Sstevel@tonic-gate struct ddi_parent_private_data *
init_regspec_64(dev_info_t * dip)1027c478bd9Sstevel@tonic-gate init_regspec_64(dev_info_t *dip)
1037c478bd9Sstevel@tonic-gate {
1047c478bd9Sstevel@tonic-gate 	struct ddi_parent_private_data *pd;
1057c478bd9Sstevel@tonic-gate 	dev_info_t *parent;
1067c478bd9Sstevel@tonic-gate 	int size_cells;
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 	/*
1097c478bd9Sstevel@tonic-gate 	 * If there are no "reg"s in the child node, return.
1107c478bd9Sstevel@tonic-gate 	 */
1117c478bd9Sstevel@tonic-gate 	pd = ddi_get_parent_data(dip);
1127c478bd9Sstevel@tonic-gate 	if ((pd == NULL) || (pd->par_nreg == 0)) {
1137c478bd9Sstevel@tonic-gate 		return (pd);
1147c478bd9Sstevel@tonic-gate 	}
1157c478bd9Sstevel@tonic-gate 	parent = ddi_get_parent(dip);
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate 	size_cells = ddi_prop_get_int(DDI_DEV_T_ANY, parent,
1187c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "#size-cells", 1);
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	if (size_cells != 1)  {
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate 		int n, j;
1237c478bd9Sstevel@tonic-gate 		struct regspec *irp;
1247c478bd9Sstevel@tonic-gate 		struct reg_64 {
1257c478bd9Sstevel@tonic-gate 			uint_t addr_hi, addr_lo, size_hi, size_lo;
1267c478bd9Sstevel@tonic-gate 		};
1277c478bd9Sstevel@tonic-gate 		struct reg_64 *r64_rp;
1287c478bd9Sstevel@tonic-gate 		struct regspec *rp;
1297c478bd9Sstevel@tonic-gate 		uint_t len = 0;
1307c478bd9Sstevel@tonic-gate 		int *reg_prop;
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 		ASSERT(size_cells == 2);
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 		/*
1357c478bd9Sstevel@tonic-gate 		 * We already looked the property up once before if
1367c478bd9Sstevel@tonic-gate 		 * pd is non-NULL.
1377c478bd9Sstevel@tonic-gate 		 */
1387c478bd9Sstevel@tonic-gate 		(void) ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
1397c478bd9Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, OBP_REG, &reg_prop, &len);
1407c478bd9Sstevel@tonic-gate 		ASSERT(len != 0);
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 		n = sizeof (struct reg_64) / sizeof (int);
1437c478bd9Sstevel@tonic-gate 		n = len / n;
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 		/*
1467c478bd9Sstevel@tonic-gate 		 * We're allocating a buffer the size of the PROM's property,
1477c478bd9Sstevel@tonic-gate 		 * but we're only using a smaller portion when we assign it
1487c478bd9Sstevel@tonic-gate 		 * to a regspec.  We do this so that in the
1497c478bd9Sstevel@tonic-gate 		 * impl_ddi_sunbus_removechild function, we will
1507c478bd9Sstevel@tonic-gate 		 * always free the right amount of memory.
1517c478bd9Sstevel@tonic-gate 		 */
1527c478bd9Sstevel@tonic-gate 		irp = rp = (struct regspec *)reg_prop;
1537c478bd9Sstevel@tonic-gate 		r64_rp = (struct reg_64 *)pd->par_reg;
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 		for (j = 0; j < n; ++j, ++rp, ++r64_rp) {
1567c478bd9Sstevel@tonic-gate 			ASSERT(r64_rp->size_hi == 0);
1577c478bd9Sstevel@tonic-gate 			rp->regspec_bustype = r64_rp->addr_hi;
1587c478bd9Sstevel@tonic-gate 			rp->regspec_addr = r64_rp->addr_lo;
1597c478bd9Sstevel@tonic-gate 			rp->regspec_size = r64_rp->size_lo;
1607c478bd9Sstevel@tonic-gate 		}
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 		ddi_prop_free((void *)pd->par_reg);
1637c478bd9Sstevel@tonic-gate 		pd->par_nreg = n;
1647c478bd9Sstevel@tonic-gate 		pd->par_reg = irp;
1657c478bd9Sstevel@tonic-gate 	}
1667c478bd9Sstevel@tonic-gate 	return (pd);
1677c478bd9Sstevel@tonic-gate }
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate /*
1707c478bd9Sstevel@tonic-gate  * Create a ddi_parent_private_data structure from the ddi properties of
1717c478bd9Sstevel@tonic-gate  * the dev_info node.
1727c478bd9Sstevel@tonic-gate  *
1737c478bd9Sstevel@tonic-gate  * The "reg" is required if the driver wishes to create mappings on behalf
1747c478bd9Sstevel@tonic-gate  * of the device. The "reg" property is assumed to be a list of at least
1757c478bd9Sstevel@tonic-gate  * one triplet
1767c478bd9Sstevel@tonic-gate  *
1777c478bd9Sstevel@tonic-gate  *	<bustype, address, size>*1
1787c478bd9Sstevel@tonic-gate  *
1797c478bd9Sstevel@tonic-gate  * The "interrupt" property is no longer part of parent private data on
1807c478bd9Sstevel@tonic-gate  * sun4u. The interrupt parent is may not be the device tree parent.
1817c478bd9Sstevel@tonic-gate  *
1827c478bd9Sstevel@tonic-gate  * The "ranges" property describes the mapping of child addresses to parent
1837c478bd9Sstevel@tonic-gate  * addresses.
1847c478bd9Sstevel@tonic-gate  *
1857c478bd9Sstevel@tonic-gate  * N.B. struct rangespec is defined for the following default values:
1867c478bd9Sstevel@tonic-gate  *			parent  child
1877c478bd9Sstevel@tonic-gate  *	#address-cells	2	2
1887c478bd9Sstevel@tonic-gate  *	#size-cells	1	1
1897c478bd9Sstevel@tonic-gate  * This function doesn't deal with non-default cells and will not create
1907c478bd9Sstevel@tonic-gate  * ranges in such cases.
1917c478bd9Sstevel@tonic-gate  */
1927c478bd9Sstevel@tonic-gate void
make_ddi_ppd(dev_info_t * child,struct ddi_parent_private_data ** ppd)1937c478bd9Sstevel@tonic-gate make_ddi_ppd(dev_info_t *child, struct ddi_parent_private_data **ppd)
1947c478bd9Sstevel@tonic-gate {
1957c478bd9Sstevel@tonic-gate 	struct ddi_parent_private_data *pdptr;
1967c478bd9Sstevel@tonic-gate 	int *reg_prop, *rng_prop;
1977c478bd9Sstevel@tonic-gate 	uint_t reg_len = 0, rng_len = 0;
1987c478bd9Sstevel@tonic-gate 	dev_info_t *parent;
1997c478bd9Sstevel@tonic-gate 	int parent_addr_cells, parent_size_cells;
2007c478bd9Sstevel@tonic-gate 	int child_addr_cells, child_size_cells;
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	*ppd = pdptr = kmem_zalloc(sizeof (*pdptr), KM_SLEEP);
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	/*
2057c478bd9Sstevel@tonic-gate 	 * root node has no parent private data, so *ppd should
2067c478bd9Sstevel@tonic-gate 	 * be initialized for naming to work properly.
2077c478bd9Sstevel@tonic-gate 	 */
2087c478bd9Sstevel@tonic-gate 	if ((parent = ddi_get_parent(child)) == NULL)
2097c478bd9Sstevel@tonic-gate 		return;
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 	/*
2127c478bd9Sstevel@tonic-gate 	 * Set reg field of parent data from "reg" property
2137c478bd9Sstevel@tonic-gate 	 */
2147c478bd9Sstevel@tonic-gate 	if ((get_prop_int_array(child, OBP_REG, &reg_prop, &reg_len)
2157c478bd9Sstevel@tonic-gate 	    == DDI_PROP_SUCCESS) && (reg_len != 0)) {
2167c478bd9Sstevel@tonic-gate 		pdptr->par_nreg = (int)(reg_len / sizeof (struct regspec));
2177c478bd9Sstevel@tonic-gate 		pdptr->par_reg = (struct regspec *)reg_prop;
2187c478bd9Sstevel@tonic-gate 	}
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 	/*
2217c478bd9Sstevel@tonic-gate 	 * "ranges" property ...
2227c478bd9Sstevel@tonic-gate 	 *
2237c478bd9Sstevel@tonic-gate 	 * This function does not handle cases where #address-cells != 2
2247c478bd9Sstevel@tonic-gate 	 * and * min(parent, child) #size-cells != 1 (see bugid 4211124).
2257c478bd9Sstevel@tonic-gate 	 *
2267c478bd9Sstevel@tonic-gate 	 * Nexus drivers with such exceptions (e.g. pci ranges)
2277c478bd9Sstevel@tonic-gate 	 * should either create a separate function for handling
2287c478bd9Sstevel@tonic-gate 	 * ranges or not use parent private data to store ranges.
2297c478bd9Sstevel@tonic-gate 	 */
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 	/* root node has no ranges */
2327c478bd9Sstevel@tonic-gate 	if ((parent = ddi_get_parent(child)) == NULL)
2337c478bd9Sstevel@tonic-gate 		return;
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	child_addr_cells = ddi_prop_get_int(DDI_DEV_T_ANY, child,
2367c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "#address-cells", 2);
2377c478bd9Sstevel@tonic-gate 	child_size_cells = ddi_prop_get_int(DDI_DEV_T_ANY, child,
2387c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "#size-cells", 1);
2397c478bd9Sstevel@tonic-gate 	parent_addr_cells = ddi_prop_get_int(DDI_DEV_T_ANY, parent,
2407c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "#address-cells", 2);
2417c478bd9Sstevel@tonic-gate 	parent_size_cells = ddi_prop_get_int(DDI_DEV_T_ANY, parent,
2427c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "#size-cells", 1);
2437c478bd9Sstevel@tonic-gate 	if (child_addr_cells != 2 || parent_addr_cells != 2 ||
2447c478bd9Sstevel@tonic-gate 	    (child_size_cells != 1 && parent_size_cells != 1)) {
2457c478bd9Sstevel@tonic-gate 		NDI_CONFIG_DEBUG((CE_NOTE, "!ranges not made in parent data; "
2467c478bd9Sstevel@tonic-gate 		    "#address-cells or #size-cells have non-default value"));
2477c478bd9Sstevel@tonic-gate 		return;
2487c478bd9Sstevel@tonic-gate 	}
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 	if (get_prop_int_array(child, OBP_RANGES, &rng_prop, &rng_len)
2517c478bd9Sstevel@tonic-gate 	    == DDI_PROP_SUCCESS) {
2527c478bd9Sstevel@tonic-gate 		pdptr->par_nrng = rng_len / (int)(sizeof (struct rangespec));
2537c478bd9Sstevel@tonic-gate 		pdptr->par_rng = (struct rangespec *)rng_prop;
2547c478bd9Sstevel@tonic-gate 	}
2557c478bd9Sstevel@tonic-gate }
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate /*
2587c478bd9Sstevel@tonic-gate  * Free ddi_parent_private_data structure
2597c478bd9Sstevel@tonic-gate  */
2607c478bd9Sstevel@tonic-gate void
impl_free_ddi_ppd(dev_info_t * dip)2617c478bd9Sstevel@tonic-gate impl_free_ddi_ppd(dev_info_t *dip)
2627c478bd9Sstevel@tonic-gate {
2637c478bd9Sstevel@tonic-gate 	struct ddi_parent_private_data *pdptr = ddi_get_parent_data(dip);
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 	if (pdptr == NULL)
2667c478bd9Sstevel@tonic-gate 		return;
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	if (pdptr->par_nrng != 0)
2697c478bd9Sstevel@tonic-gate 		ddi_prop_free((void *)pdptr->par_rng);
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 	if (pdptr->par_nreg != 0)
2727c478bd9Sstevel@tonic-gate 		ddi_prop_free((void *)pdptr->par_reg);
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	kmem_free(pdptr, sizeof (*pdptr));
2757c478bd9Sstevel@tonic-gate 	ddi_set_parent_data(dip, NULL);
2767c478bd9Sstevel@tonic-gate }
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate /*
2797c478bd9Sstevel@tonic-gate  * Name a child of sun busses based on the reg spec.
2807c478bd9Sstevel@tonic-gate  * Handles the following properties:
2817c478bd9Sstevel@tonic-gate  *
2827c478bd9Sstevel@tonic-gate  *	Property	value
2837c478bd9Sstevel@tonic-gate  *	Name		type
2847c478bd9Sstevel@tonic-gate  *
2857c478bd9Sstevel@tonic-gate  *	reg		register spec
2867c478bd9Sstevel@tonic-gate  *	interrupts	new (bus-oriented) interrupt spec
2877c478bd9Sstevel@tonic-gate  *	ranges		range spec
2887c478bd9Sstevel@tonic-gate  *
2897c478bd9Sstevel@tonic-gate  * This may be called multiple times, independent of
2907c478bd9Sstevel@tonic-gate  * initchild calls.
2917c478bd9Sstevel@tonic-gate  */
2927c478bd9Sstevel@tonic-gate static int
impl_sunbus_name_child(dev_info_t * child,char * name,int namelen)2937c478bd9Sstevel@tonic-gate impl_sunbus_name_child(dev_info_t *child, char *name, int namelen)
2947c478bd9Sstevel@tonic-gate {
2957c478bd9Sstevel@tonic-gate 	struct ddi_parent_private_data *pdptr;
2967c478bd9Sstevel@tonic-gate 	struct regspec *rp;
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	/*
2997c478bd9Sstevel@tonic-gate 	 * Fill in parent-private data and this function returns to us
3007c478bd9Sstevel@tonic-gate 	 * an indication if it used "registers" to fill in the data.
3017c478bd9Sstevel@tonic-gate 	 */
3027c478bd9Sstevel@tonic-gate 	if (ddi_get_parent_data(child) == NULL) {
3037c478bd9Sstevel@tonic-gate 		make_ddi_ppd(child, &pdptr);
3047c478bd9Sstevel@tonic-gate 		ddi_set_parent_data(child, pdptr);
3057c478bd9Sstevel@tonic-gate 	}
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	/*
3087c478bd9Sstevel@tonic-gate 	 * No reg property, return null string as address
3097c478bd9Sstevel@tonic-gate 	 * (e.g. root node)
3107c478bd9Sstevel@tonic-gate 	 */
3117c478bd9Sstevel@tonic-gate 	name[0] = '\0';
3127c478bd9Sstevel@tonic-gate 	if (sparc_pd_getnreg(child) == 0) {
3137c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
3147c478bd9Sstevel@tonic-gate 	}
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	rp = sparc_pd_getreg(child, 0);
3177c478bd9Sstevel@tonic-gate 	(void) snprintf(name, namelen, "%x,%x",
3187c478bd9Sstevel@tonic-gate 	    rp->regspec_bustype, rp->regspec_addr);
3197c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
3207c478bd9Sstevel@tonic-gate }
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate /*
3247c478bd9Sstevel@tonic-gate  * Called from the bus_ctl op of some drivers.
3257c478bd9Sstevel@tonic-gate  * to implement the DDI_CTLOPS_INITCHILD operation.
3267c478bd9Sstevel@tonic-gate  *
3277c478bd9Sstevel@tonic-gate  * NEW drivers should NOT use this function, but should declare
3287c478bd9Sstevel@tonic-gate  * there own initchild/uninitchild handlers. (This function assumes
3297c478bd9Sstevel@tonic-gate  * the layout of the parent private data and the format of "reg",
3307c478bd9Sstevel@tonic-gate  * "ranges", "interrupts" properties and that #address-cells and
3317c478bd9Sstevel@tonic-gate  * #size-cells of the parent bus are defined to be default values.)
3327c478bd9Sstevel@tonic-gate  */
3337c478bd9Sstevel@tonic-gate int
impl_ddi_sunbus_initchild(dev_info_t * child)3347c478bd9Sstevel@tonic-gate impl_ddi_sunbus_initchild(dev_info_t *child)
3357c478bd9Sstevel@tonic-gate {
3367c478bd9Sstevel@tonic-gate 	char name[MAXNAMELEN];
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	(void) impl_sunbus_name_child(child, name, MAXNAMELEN);
3397c478bd9Sstevel@tonic-gate 	ddi_set_name_addr(child, name);
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 	/*
3427c478bd9Sstevel@tonic-gate 	 * Try to merge .conf node. If successful, return failure to
3437c478bd9Sstevel@tonic-gate 	 * remove this child.
3447c478bd9Sstevel@tonic-gate 	 */
3457c478bd9Sstevel@tonic-gate 	if ((ndi_dev_is_persistent_node(child) == 0) &&
3467c478bd9Sstevel@tonic-gate 	    (ndi_merge_node(child, impl_sunbus_name_child) == DDI_SUCCESS)) {
3477c478bd9Sstevel@tonic-gate 		impl_ddi_sunbus_removechild(child);
3487c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3497c478bd9Sstevel@tonic-gate 	}
3507c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
3517c478bd9Sstevel@tonic-gate }
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate /*
3547c478bd9Sstevel@tonic-gate  * A better name for this function would be impl_ddi_sunbus_uninitchild()
3557c478bd9Sstevel@tonic-gate  * It does not remove the child, it uninitializes it, reclaiming the
3567c478bd9Sstevel@tonic-gate  * resources taken by impl_ddi_sunbus_initchild.
3577c478bd9Sstevel@tonic-gate  */
3587c478bd9Sstevel@tonic-gate void
impl_ddi_sunbus_removechild(dev_info_t * dip)3597c478bd9Sstevel@tonic-gate impl_ddi_sunbus_removechild(dev_info_t *dip)
3607c478bd9Sstevel@tonic-gate {
3617c478bd9Sstevel@tonic-gate 	impl_free_ddi_ppd(dip);
3627c478bd9Sstevel@tonic-gate 	ddi_set_name_addr(dip, NULL);
3637c478bd9Sstevel@tonic-gate 	/*
3647c478bd9Sstevel@tonic-gate 	 * Strip the node to properly convert it back to prototype form
3657c478bd9Sstevel@tonic-gate 	 */
3667c478bd9Sstevel@tonic-gate 	impl_rem_dev_props(dip);
3677c478bd9Sstevel@tonic-gate }
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate /*
3707c478bd9Sstevel@tonic-gate  * SECTION: DDI Interrupt
3717c478bd9Sstevel@tonic-gate  */
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate void
cells_1275_copy(prop_1275_cell_t * from,prop_1275_cell_t * to,int32_t len)3747c478bd9Sstevel@tonic-gate cells_1275_copy(prop_1275_cell_t *from, prop_1275_cell_t *to, int32_t len)
3757c478bd9Sstevel@tonic-gate {
3767c478bd9Sstevel@tonic-gate 	int i;
3777c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i++)
3787c478bd9Sstevel@tonic-gate 		*to = *from;
3797c478bd9Sstevel@tonic-gate }
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate prop_1275_cell_t *
cells_1275_cmp(prop_1275_cell_t * cell1,prop_1275_cell_t * cell2,int32_t len)3827c478bd9Sstevel@tonic-gate cells_1275_cmp(prop_1275_cell_t *cell1, prop_1275_cell_t *cell2, int32_t len)
3837c478bd9Sstevel@tonic-gate {
3847c478bd9Sstevel@tonic-gate 	prop_1275_cell_t *match_cell = 0;
3857c478bd9Sstevel@tonic-gate 	int32_t i;
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i++)
3887c478bd9Sstevel@tonic-gate 		if (cell1[i] != cell2[i]) {
3897c478bd9Sstevel@tonic-gate 			match_cell = &cell1[i];
3907c478bd9Sstevel@tonic-gate 			break;
3917c478bd9Sstevel@tonic-gate 		}
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 	return (match_cell);
3947c478bd9Sstevel@tonic-gate }
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate /*
397a195726fSgovinda  * get_intr_parent() is a generic routine that process a 1275 interrupt
398a195726fSgovinda  * map (imap) property.  This function returns a dev_info_t structure
399a195726fSgovinda  * which claims ownership of the interrupt domain.
400a195726fSgovinda  * It also returns the new interrupt translation within this new domain.
401a195726fSgovinda  * If an interrupt-parent or interrupt-map property are not found,
402a195726fSgovinda  * then we fallback to using the device tree's parent.
403a195726fSgovinda  *
404a195726fSgovinda  * imap entry format:
405a195726fSgovinda  * <reg>,<interrupt>,<phandle>,<translated interrupt>
406a195726fSgovinda  * reg - The register specification in the interrupts domain
407a195726fSgovinda  * interrupt - The interrupt specification
408a195726fSgovinda  * phandle - PROM handle of the device that owns the xlated interrupt domain
409a195726fSgovinda  * translated interrupt - interrupt specifier in the parents domain
410a195726fSgovinda  * note: <reg>,<interrupt> - The reg and interrupt can be combined to create
411a195726fSgovinda  *	a unique entry called a unit interrupt specifier.
412a195726fSgovinda  *
413a195726fSgovinda  * Here's the processing steps:
414a195726fSgovinda  * step1 - If the interrupt-parent property exists, create the ispec and
415a195726fSgovinda  *	return the dip of the interrupt parent.
416a195726fSgovinda  * step2 - Extract the interrupt-map property and the interrupt-map-mask
417a195726fSgovinda  *	If these don't exist, just return the device tree parent.
418a195726fSgovinda  * step3 - build up the unit interrupt specifier to match against the
419a195726fSgovinda  *	interrupt map property
420a195726fSgovinda  * step4 - Scan the interrupt-map property until a match is found
421a195726fSgovinda  * step4a - Extract the interrupt parent
422a195726fSgovinda  * step4b - Compare the unit interrupt specifier
4237c478bd9Sstevel@tonic-gate  */
424a195726fSgovinda dev_info_t *
get_intr_parent(dev_info_t * pdip,dev_info_t * dip,ddi_intr_handle_impl_t * hdlp)425a195726fSgovinda get_intr_parent(dev_info_t *pdip, dev_info_t *dip, ddi_intr_handle_impl_t *hdlp)
4267c478bd9Sstevel@tonic-gate {
427a195726fSgovinda 	prop_1275_cell_t *imap, *imap_mask, *scan, *reg_p, *match_req;
428a195726fSgovinda 	int32_t imap_sz, imap_cells, imap_scan_cells, imap_mask_sz,
429a195726fSgovinda 	    addr_cells, intr_cells, reg_len, i, j;
430a195726fSgovinda 	int32_t match_found = 0;
431a195726fSgovinda 	dev_info_t *intr_parent_dip = NULL;
432a195726fSgovinda 	uint32_t *intr = &hdlp->ih_vector;
433a195726fSgovinda 	uint32_t nodeid;
434a195726fSgovinda #ifdef DEBUG
435a195726fSgovinda 	static int debug = 0;
436a195726fSgovinda #endif
4377c478bd9Sstevel@tonic-gate 
438a195726fSgovinda 	/*
439a195726fSgovinda 	 * step1
440a195726fSgovinda 	 * If we have an interrupt-parent property, this property represents
441a195726fSgovinda 	 * the nodeid of our interrupt parent.
442a195726fSgovinda 	 */
443a195726fSgovinda 	if ((nodeid = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
444a195726fSgovinda 	    "interrupt-parent", -1)) != -1) {
445a195726fSgovinda 		intr_parent_dip = e_ddi_nodeid_to_dip(nodeid);
446a195726fSgovinda 		ASSERT(intr_parent_dip);
4477c478bd9Sstevel@tonic-gate 
448a195726fSgovinda 		/*
449a195726fSgovinda 		 * Attach the interrupt parent.
450a195726fSgovinda 		 *
451a195726fSgovinda 		 * N.B. e_ddi_nodeid_to_dip() isn't safe under DR.
452a195726fSgovinda 		 *	Also, interrupt parent isn't held. This needs
453a195726fSgovinda 		 *	to be revisited if DR-capable platforms implement
454a195726fSgovinda 		 *	interrupt redirection.
455a195726fSgovinda 		 */
456a195726fSgovinda 		if (i_ddi_attach_node_hierarchy(intr_parent_dip)
457a195726fSgovinda 		    != DDI_SUCCESS) {
458a195726fSgovinda 			ndi_rele_devi(intr_parent_dip);
459a195726fSgovinda 			return (NULL);
460a195726fSgovinda 		}
4617c478bd9Sstevel@tonic-gate 
462a195726fSgovinda 		return (intr_parent_dip);
4637c478bd9Sstevel@tonic-gate 	}
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	/*
466a195726fSgovinda 	 * step2
467a195726fSgovinda 	 * Get interrupt map structure from PROM property
4687c478bd9Sstevel@tonic-gate 	 */
469a195726fSgovinda 	if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
470a195726fSgovinda 	    "interrupt-map", (caddr_t)&imap, &imap_sz)
471a195726fSgovinda 	    != DDI_PROP_SUCCESS) {
472a195726fSgovinda 		/*
473a195726fSgovinda 		 * If we don't have an imap property, default to using the
474a195726fSgovinda 		 * device tree.
475a195726fSgovinda 		 */
4767c478bd9Sstevel@tonic-gate 
477a195726fSgovinda 		ndi_hold_devi(pdip);
478a195726fSgovinda 		return (pdip);
479a195726fSgovinda 	}
4807c478bd9Sstevel@tonic-gate 
481a195726fSgovinda 	/* Get the interrupt mask property */
482a195726fSgovinda 	if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
483a195726fSgovinda 	    "interrupt-map-mask", (caddr_t)&imap_mask, &imap_mask_sz)
484a195726fSgovinda 	    != DDI_PROP_SUCCESS) {
485a195726fSgovinda 		/*
486a195726fSgovinda 		 * If we don't find this property, we have to fail the request
487a195726fSgovinda 		 * because the 1275 imap property wasn't defined correctly.
488a195726fSgovinda 		 */
489a195726fSgovinda 		ASSERT(intr_parent_dip == NULL);
490a195726fSgovinda 		goto exit2;
491a195726fSgovinda 	}
492a195726fSgovinda 
493a195726fSgovinda 	/* Get the address cell size */
494a195726fSgovinda 	addr_cells = ddi_getprop(DDI_DEV_T_ANY, pdip, 0,
495a195726fSgovinda 	    "#address-cells", 2);
496a195726fSgovinda 
497a195726fSgovinda 	/* Get the interrupts cell size */
498a195726fSgovinda 	intr_cells = ddi_getprop(DDI_DEV_T_ANY, pdip, 0,
499a195726fSgovinda 	    "#interrupt-cells", 1);
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 	/*
502a195726fSgovinda 	 * step3
503a195726fSgovinda 	 * Now lets build up the unit interrupt specifier e.g. reg,intr
504a195726fSgovinda 	 * and apply the imap mask.  match_req will hold this when we're
505a195726fSgovinda 	 * through.
5067c478bd9Sstevel@tonic-gate 	 */
507a195726fSgovinda 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
508a195726fSgovinda 	    (caddr_t)&reg_p, &reg_len) != DDI_SUCCESS) {
509a195726fSgovinda 		ASSERT(intr_parent_dip == NULL);
510a195726fSgovinda 		goto exit3;
5117c478bd9Sstevel@tonic-gate 	}
5127c478bd9Sstevel@tonic-gate 
513a195726fSgovinda 	match_req = kmem_alloc(CELLS_1275_TO_BYTES(addr_cells) +
514a195726fSgovinda 	    CELLS_1275_TO_BYTES(intr_cells), KM_SLEEP);
5157c478bd9Sstevel@tonic-gate 
516a195726fSgovinda 	for (i = 0; i < addr_cells; i++)
517a195726fSgovinda 		match_req[i] = (reg_p[i] & imap_mask[i]);
5187c478bd9Sstevel@tonic-gate 
519a195726fSgovinda 	for (j = 0; j < intr_cells; i++, j++)
520a195726fSgovinda 		match_req[i] = (intr[j] & imap_mask[i]);
5217c478bd9Sstevel@tonic-gate 
522a195726fSgovinda 	/* Calculate the imap size in cells */
523a195726fSgovinda 	imap_cells = BYTES_TO_1275_CELLS(imap_sz);
524a195726fSgovinda 
525a195726fSgovinda #ifdef DEBUG
526a195726fSgovinda 	if (debug)
527a195726fSgovinda 		prom_printf("reg cell size 0x%x, intr cell size 0x%x, "
528a195726fSgovinda 		    "match_request 0x%p, imap 0x%p\n", addr_cells, intr_cells,
529903a11ebSrh87107 		    (void *)match_req, (void *)imap);
530a195726fSgovinda #endif
531a195726fSgovinda 
532a195726fSgovinda 	/*
533a195726fSgovinda 	 * Scan the imap property looking for a match of the interrupt unit
534a195726fSgovinda 	 * specifier.  This loop is rather complex since the data within the
535a195726fSgovinda 	 * imap property may vary in size.
536a195726fSgovinda 	 */
537a195726fSgovinda 	for (scan = imap, imap_scan_cells = i = 0;
538a195726fSgovinda 	    imap_scan_cells < imap_cells; scan += i, imap_scan_cells += i) {
539a195726fSgovinda 		int new_intr_cells;
540a195726fSgovinda 
541a195726fSgovinda 		/* Set the index to the nodeid field */
542a195726fSgovinda 		i = addr_cells + intr_cells;
543a195726fSgovinda 
544a195726fSgovinda 		/*
545a195726fSgovinda 		 * step4a
546a195726fSgovinda 		 * Translate the nodeid field to a dip
547a195726fSgovinda 		 */
548a195726fSgovinda 		ASSERT(intr_parent_dip == NULL);
549a195726fSgovinda 		intr_parent_dip = e_ddi_nodeid_to_dip((uint_t)scan[i++]);
550a195726fSgovinda 
551a195726fSgovinda 		ASSERT(intr_parent_dip != 0);
552a195726fSgovinda #ifdef DEBUG
553a195726fSgovinda 		if (debug)
554903a11ebSrh87107 			prom_printf("scan 0x%p\n", (void *)scan);
555a195726fSgovinda #endif
556a195726fSgovinda 		/*
557a195726fSgovinda 		 * The tmp_dip describes the new domain, get it's interrupt
558a195726fSgovinda 		 * cell size
559a195726fSgovinda 		 */
560a195726fSgovinda 		new_intr_cells = ddi_getprop(DDI_DEV_T_ANY, intr_parent_dip, 0,
561a195726fSgovinda 		    "#interrupts-cells", 1);
562a195726fSgovinda 
563a195726fSgovinda 		/*
564a195726fSgovinda 		 * step4b
565a195726fSgovinda 		 * See if we have a match on the interrupt unit specifier
566a195726fSgovinda 		 */
567a195726fSgovinda 		if (cells_1275_cmp(match_req, scan, addr_cells + intr_cells)
568a195726fSgovinda 		    == 0) {
569a195726fSgovinda 			uint32_t *intr;
570a195726fSgovinda 
571a195726fSgovinda 			match_found = 1;
572a195726fSgovinda 
573a195726fSgovinda 			/*
574a195726fSgovinda 			 * If we have an imap parent whose not in our device
575a195726fSgovinda 			 * tree path, we need to hold and install that driver.
576a195726fSgovinda 			 */
577a195726fSgovinda 			if (i_ddi_attach_node_hierarchy(intr_parent_dip)
578a195726fSgovinda 			    != DDI_SUCCESS) {
579a195726fSgovinda 				ndi_rele_devi(intr_parent_dip);
580a195726fSgovinda 				intr_parent_dip = (dev_info_t *)NULL;
581a195726fSgovinda 				goto exit4;
5827c478bd9Sstevel@tonic-gate 			}
5837c478bd9Sstevel@tonic-gate 
584a195726fSgovinda 			/*
585a195726fSgovinda 			 * We need to handcraft an ispec along with a bus
586a195726fSgovinda 			 * interrupt value, so we can dup it into our
587a195726fSgovinda 			 * standard ispec structure.
588a195726fSgovinda 			 */
589a195726fSgovinda 			/* Extract the translated interrupt information */
590a195726fSgovinda 			intr = kmem_alloc(
591a195726fSgovinda 			    CELLS_1275_TO_BYTES(new_intr_cells), KM_SLEEP);
592a195726fSgovinda 
593a195726fSgovinda 			for (j = 0; j < new_intr_cells; j++, i++)
594a195726fSgovinda 				intr[j] = scan[i];
595a195726fSgovinda 
596a195726fSgovinda 			cells_1275_copy(intr, &hdlp->ih_vector, new_intr_cells);
597a195726fSgovinda 
598a195726fSgovinda 			kmem_free(intr, CELLS_1275_TO_BYTES(new_intr_cells));
599a195726fSgovinda 
600a195726fSgovinda #ifdef DEBUG
601a195726fSgovinda 			if (debug)
602903a11ebSrh87107 				prom_printf("dip 0x%p\n",
603903a11ebSrh87107 				    (void *)intr_parent_dip);
604a195726fSgovinda #endif
605a195726fSgovinda 			break;
606a195726fSgovinda 		} else {
607a195726fSgovinda #ifdef DEBUG
608a195726fSgovinda 			if (debug)
609903a11ebSrh87107 				prom_printf("dip 0x%p\n",
610903a11ebSrh87107 				    (void *)intr_parent_dip);
611a195726fSgovinda #endif
612a195726fSgovinda 			ndi_rele_devi(intr_parent_dip);
613a195726fSgovinda 			intr_parent_dip = NULL;
614a195726fSgovinda 			i += new_intr_cells;
615a195726fSgovinda 		}
6167c478bd9Sstevel@tonic-gate 	}
6177c478bd9Sstevel@tonic-gate 
618a195726fSgovinda 	/*
619a195726fSgovinda 	 * If we haven't found our interrupt parent at this point, fallback
620a195726fSgovinda 	 * to using the device tree.
621a195726fSgovinda 	 */
622a195726fSgovinda 	if (!match_found) {
623a195726fSgovinda 		ndi_hold_devi(pdip);
624a195726fSgovinda 		ASSERT(intr_parent_dip == NULL);
625a195726fSgovinda 		intr_parent_dip = pdip;
626a195726fSgovinda 	}
627a195726fSgovinda 
628a195726fSgovinda 	ASSERT(intr_parent_dip != NULL);
629a195726fSgovinda 
630a195726fSgovinda exit4:
631a195726fSgovinda 	kmem_free(reg_p, reg_len);
632a195726fSgovinda 	kmem_free(match_req, CELLS_1275_TO_BYTES(addr_cells) +
633a195726fSgovinda 	    CELLS_1275_TO_BYTES(intr_cells));
634a195726fSgovinda 
635a195726fSgovinda exit3:
636a195726fSgovinda 	kmem_free(imap_mask, imap_mask_sz);
637a195726fSgovinda 
638a195726fSgovinda exit2:
639a195726fSgovinda 	kmem_free(imap, imap_sz);
640a195726fSgovinda 
641a195726fSgovinda 	return (intr_parent_dip);
6427c478bd9Sstevel@tonic-gate }
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate /*
6457c478bd9Sstevel@tonic-gate  * process_intr_ops:
6467c478bd9Sstevel@tonic-gate  *
6477c478bd9Sstevel@tonic-gate  * Process the interrupt op via the interrupt parent.
6487c478bd9Sstevel@tonic-gate  */
6497c478bd9Sstevel@tonic-gate int
process_intr_ops(dev_info_t * pdip,dev_info_t * rdip,ddi_intr_op_t op,ddi_intr_handle_impl_t * hdlp,void * result)6507c478bd9Sstevel@tonic-gate process_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t op,
6517c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result)
6527c478bd9Sstevel@tonic-gate {
6537c478bd9Sstevel@tonic-gate 	int		ret = DDI_FAILURE;
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 	if (NEXUS_HAS_INTR_OP(pdip)) {
6567c478bd9Sstevel@tonic-gate 		ret = (*(DEVI(pdip)->devi_ops->devo_bus_ops->
6577c478bd9Sstevel@tonic-gate 		    bus_intr_op)) (pdip, rdip, op, hdlp, result);
6587c478bd9Sstevel@tonic-gate 	} else {
6597c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "Failed to process interrupt "
6607c478bd9Sstevel@tonic-gate 		    "for %s%d due to down-rev nexus driver %s%d",
6617c478bd9Sstevel@tonic-gate 		    ddi_get_name(rdip), ddi_get_instance(rdip),
6627c478bd9Sstevel@tonic-gate 		    ddi_get_name(pdip), ddi_get_instance(pdip));
6637c478bd9Sstevel@tonic-gate 	}
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 	return (ret);
6667c478bd9Sstevel@tonic-gate }
6677c478bd9Sstevel@tonic-gate 
668a195726fSgovinda /*ARGSUSED*/
669a195726fSgovinda uint_t
softlevel1(caddr_t arg)670a195726fSgovinda softlevel1(caddr_t arg)
671a195726fSgovinda {
672a195726fSgovinda 	softint();
673a195726fSgovinda 	return (1);
674a195726fSgovinda }
675a195726fSgovinda 
676a195726fSgovinda /*
677a195726fSgovinda  * indirection table, to save us some large switch statements
678a195726fSgovinda  * NOTE: This must agree with "INTLEVEL_foo" constants in
679a195726fSgovinda  *	<sys/avintr.h>
680a195726fSgovinda  */
681a195726fSgovinda struct autovec *const vectorlist[] = { 0 };
682a195726fSgovinda 
683a195726fSgovinda /*
684a195726fSgovinda  * This value is exported here for the functions in avintr.c
685a195726fSgovinda  */
686a195726fSgovinda const uint_t maxautovec = (sizeof (vectorlist) / sizeof (vectorlist[0]));
687a195726fSgovinda 
688a195726fSgovinda /*
689a195726fSgovinda  * Check for machine specific interrupt levels which cannot be reassigned by
690a195726fSgovinda  * settrap(), sun4u version.
691a195726fSgovinda  *
692a195726fSgovinda  * sun4u does not support V8 SPARC "fast trap" handlers.
693a195726fSgovinda  */
694a195726fSgovinda /*ARGSUSED*/
695a195726fSgovinda int
exclude_settrap(int lvl)696a195726fSgovinda exclude_settrap(int lvl)
697a195726fSgovinda {
698a195726fSgovinda 	return (1);
699a195726fSgovinda }
700a195726fSgovinda 
701a195726fSgovinda /*
702a195726fSgovinda  * Check for machine specific interrupt levels which cannot have interrupt
703a195726fSgovinda  * handlers added. We allow levels 1 through 15; level 0 is nonsense.
704a195726fSgovinda  */
705a195726fSgovinda /*ARGSUSED*/
706a195726fSgovinda int
exclude_level(int lvl)707a195726fSgovinda exclude_level(int lvl)
708a195726fSgovinda {
709a195726fSgovinda 	return ((lvl < 1) || (lvl > 15));
710a195726fSgovinda }
711a195726fSgovinda 
712a195726fSgovinda /*
713a195726fSgovinda  * Wrapper functions used by New DDI interrupt framework.
714a195726fSgovinda  */
715a195726fSgovinda 
716a195726fSgovinda /*
717a195726fSgovinda  * i_ddi_intr_ops:
718a195726fSgovinda  */
719a195726fSgovinda int
i_ddi_intr_ops(dev_info_t * dip,dev_info_t * rdip,ddi_intr_op_t op,ddi_intr_handle_impl_t * hdlp,void * result)720a195726fSgovinda i_ddi_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t op,
721a195726fSgovinda     ddi_intr_handle_impl_t *hdlp, void *result)
722a195726fSgovinda {
723a195726fSgovinda 	dev_info_t	*pdip = ddi_get_parent(dip);
724a195726fSgovinda 	int		ret = DDI_FAILURE;
725a195726fSgovinda 
726a195726fSgovinda 	/*
727a195726fSgovinda 	 * The following check is required to address
728a195726fSgovinda 	 * one of the test case of ADDI test suite.
729a195726fSgovinda 	 */
730a195726fSgovinda 	if (pdip == NULL)
731a195726fSgovinda 		return (DDI_FAILURE);
732a195726fSgovinda 
733a195726fSgovinda 	if (hdlp->ih_type != DDI_INTR_TYPE_FIXED)
734a195726fSgovinda 		return (process_intr_ops(pdip, rdip, op, hdlp, result));
735a195726fSgovinda 
736a195726fSgovinda 	if (hdlp->ih_vector == 0)
737a195726fSgovinda 		hdlp->ih_vector = i_ddi_get_inum(rdip, hdlp->ih_inum);
738a195726fSgovinda 
739a195726fSgovinda 	if (hdlp->ih_pri == 0)
740a195726fSgovinda 		hdlp->ih_pri = i_ddi_get_intr_pri(rdip, hdlp->ih_inum);
741a195726fSgovinda 
742a195726fSgovinda 	switch (op) {
743a195726fSgovinda 	case DDI_INTROP_ADDISR:
744a195726fSgovinda 	case DDI_INTROP_REMISR:
74509b1eac2SEvan Yan 	case DDI_INTROP_GETTARGET:
74609b1eac2SEvan Yan 	case DDI_INTROP_SETTARGET:
747a195726fSgovinda 	case DDI_INTROP_ENABLE:
748a195726fSgovinda 	case DDI_INTROP_DISABLE:
749a195726fSgovinda 	case DDI_INTROP_BLOCKENABLE:
750a195726fSgovinda 	case DDI_INTROP_BLOCKDISABLE:
751a195726fSgovinda 		/*
752a195726fSgovinda 		 * Try and determine our parent and possibly an interrupt
753a195726fSgovinda 		 * translation. intr parent dip returned held
754a195726fSgovinda 		 */
755a195726fSgovinda 		if ((pdip = get_intr_parent(pdip, dip, hdlp)) == NULL)
756a195726fSgovinda 			goto done;
757a195726fSgovinda 	}
758a195726fSgovinda 
759a195726fSgovinda 	ret = process_intr_ops(pdip, rdip, op, hdlp, result);
760a195726fSgovinda 
761a195726fSgovinda done:
762a195726fSgovinda 	switch (op) {
763a195726fSgovinda 	case DDI_INTROP_ADDISR:
764a195726fSgovinda 	case DDI_INTROP_REMISR:
765a195726fSgovinda 	case DDI_INTROP_ENABLE:
766a195726fSgovinda 	case DDI_INTROP_DISABLE:
767a195726fSgovinda 	case DDI_INTROP_BLOCKENABLE:
768a195726fSgovinda 	case DDI_INTROP_BLOCKDISABLE:
769a195726fSgovinda 		/* Release hold acquired in get_intr_parent() */
770a195726fSgovinda 		if (pdip)
771a195726fSgovinda 			ndi_rele_devi(pdip);
772a195726fSgovinda 	}
773a195726fSgovinda 
774a195726fSgovinda 	hdlp->ih_vector = 0;
775a195726fSgovinda 
776a195726fSgovinda 	return (ret);
777a195726fSgovinda }
778a195726fSgovinda 
7797c478bd9Sstevel@tonic-gate /*
7807c478bd9Sstevel@tonic-gate  * i_ddi_add_ivintr:
7817c478bd9Sstevel@tonic-gate  */
7827c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7837c478bd9Sstevel@tonic-gate int
i_ddi_add_ivintr(ddi_intr_handle_impl_t * hdlp)7847c478bd9Sstevel@tonic-gate i_ddi_add_ivintr(ddi_intr_handle_impl_t *hdlp)
7857c478bd9Sstevel@tonic-gate {
7867c478bd9Sstevel@tonic-gate 	/*
7877c478bd9Sstevel@tonic-gate 	 * If the PIL was set and is valid use it, otherwise
7887c478bd9Sstevel@tonic-gate 	 * default it to 1
7897c478bd9Sstevel@tonic-gate 	 */
7907c478bd9Sstevel@tonic-gate 	if ((hdlp->ih_pri < 1) || (hdlp->ih_pri > PIL_MAX))
7917c478bd9Sstevel@tonic-gate 		hdlp->ih_pri = 1;
7927c478bd9Sstevel@tonic-gate 
7937c478bd9Sstevel@tonic-gate 	VERIFY(add_ivintr(hdlp->ih_vector, hdlp->ih_pri,
794b0fc0e77Sgovinda 	    (intrfunc)hdlp->ih_cb_func, hdlp->ih_cb_arg1,
795b0fc0e77Sgovinda 	    hdlp->ih_cb_arg2, NULL) == 0);
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
7987c478bd9Sstevel@tonic-gate }
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate /*
8017c478bd9Sstevel@tonic-gate  * i_ddi_rem_ivintr:
8027c478bd9Sstevel@tonic-gate  */
8037c478bd9Sstevel@tonic-gate /*ARGSUSED*/
8047c478bd9Sstevel@tonic-gate void
i_ddi_rem_ivintr(ddi_intr_handle_impl_t * hdlp)8057c478bd9Sstevel@tonic-gate i_ddi_rem_ivintr(ddi_intr_handle_impl_t *hdlp)
8067c478bd9Sstevel@tonic-gate {
807b0fc0e77Sgovinda 	VERIFY(rem_ivintr(hdlp->ih_vector, hdlp->ih_pri) == 0);
8087c478bd9Sstevel@tonic-gate }
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate /*
811a195726fSgovinda  * i_ddi_get_inum - Get the interrupt number property from the
812a195726fSgovinda  * specified device. Note that this function is called only for
813a195726fSgovinda  * the FIXED interrupt type.
814a195726fSgovinda  */
815a195726fSgovinda uint32_t
i_ddi_get_inum(dev_info_t * dip,uint_t inumber)816a195726fSgovinda i_ddi_get_inum(dev_info_t *dip, uint_t inumber)
817a195726fSgovinda {
818a195726fSgovinda 	int32_t			intrlen, intr_cells, max_intrs;
819a195726fSgovinda 	prop_1275_cell_t	*ip, intr_sz;
820a195726fSgovinda 	uint32_t		intr = 0;
821a195726fSgovinda 
822a195726fSgovinda 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS |
823a195726fSgovinda 	    DDI_PROP_CANSLEEP,
824a195726fSgovinda 	    "interrupts", (caddr_t)&ip, &intrlen) == DDI_SUCCESS) {
825a195726fSgovinda 
826a195726fSgovinda 		intr_cells = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
827a195726fSgovinda 		    "#interrupt-cells", 1);
828a195726fSgovinda 
829a195726fSgovinda 		/* adjust for number of bytes */
830a195726fSgovinda 		intr_sz = CELLS_1275_TO_BYTES(intr_cells);
831a195726fSgovinda 
832a195726fSgovinda 		/* Calculate the number of interrupts */
833a195726fSgovinda 		max_intrs = intrlen / intr_sz;
834a195726fSgovinda 
835a195726fSgovinda 		if (inumber < max_intrs) {
836a195726fSgovinda 			prop_1275_cell_t *intrp = ip;
837a195726fSgovinda 
838a195726fSgovinda 			/* Index into interrupt property */
839a195726fSgovinda 			intrp += (inumber * intr_cells);
840a195726fSgovinda 
841a195726fSgovinda 			cells_1275_copy(intrp, &intr, intr_cells);
842a195726fSgovinda 		}
843a195726fSgovinda 
844a195726fSgovinda 		kmem_free(ip, intrlen);
845a195726fSgovinda 	}
846a195726fSgovinda 
847a195726fSgovinda 	return (intr);
848a195726fSgovinda }
849a195726fSgovinda 
850a195726fSgovinda /*
851a195726fSgovinda  * i_ddi_get_intr_pri - Get the interrupt-priorities property from
852a195726fSgovinda  * the specified device. Note that this function is called only for
853a195726fSgovinda  * the FIXED interrupt type.
854a195726fSgovinda  */
855a195726fSgovinda uint32_t
i_ddi_get_intr_pri(dev_info_t * dip,uint_t inumber)856a195726fSgovinda i_ddi_get_intr_pri(dev_info_t *dip, uint_t inumber)
857a195726fSgovinda {
858a195726fSgovinda 	uint32_t	*intr_prio_p;
859a195726fSgovinda 	uint32_t	pri = 0;
860a195726fSgovinda 	int32_t		i;
861a195726fSgovinda 
862a195726fSgovinda 	/*
863a195726fSgovinda 	 * Use the "interrupt-priorities" property to determine the
864a195726fSgovinda 	 * the pil/ipl for the interrupt handler.
865a195726fSgovinda 	 */
866a195726fSgovinda 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
867a195726fSgovinda 	    "interrupt-priorities", (caddr_t)&intr_prio_p,
868a195726fSgovinda 	    &i) == DDI_SUCCESS) {
869a195726fSgovinda 		if (inumber < (i / sizeof (int32_t)))
870a195726fSgovinda 			pri = intr_prio_p[inumber];
871a195726fSgovinda 		kmem_free(intr_prio_p, i);
872a195726fSgovinda 	}
873a195726fSgovinda 
874a195726fSgovinda 	return (pri);
875a195726fSgovinda }
876a195726fSgovinda 
877a195726fSgovinda int
i_ddi_get_intx_nintrs(dev_info_t * dip)878a54f81fbSanish i_ddi_get_intx_nintrs(dev_info_t *dip)
879a195726fSgovinda {
880a195726fSgovinda 	int32_t intrlen;
881a195726fSgovinda 	prop_1275_cell_t intr_sz;
882a195726fSgovinda 	prop_1275_cell_t *ip;
883a195726fSgovinda 	int32_t ret = 0;
884a195726fSgovinda 
885a195726fSgovinda 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS |
886a195726fSgovinda 	    DDI_PROP_CANSLEEP,
887a195726fSgovinda 	    "interrupts", (caddr_t)&ip, &intrlen) == DDI_SUCCESS) {
888a195726fSgovinda 
889a195726fSgovinda 		intr_sz = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
890a195726fSgovinda 		    "#interrupt-cells", 1);
891a195726fSgovinda 		/* adjust for number of bytes */
892a195726fSgovinda 		intr_sz = CELLS_1275_TO_BYTES(intr_sz);
893a195726fSgovinda 
894a195726fSgovinda 		ret = intrlen / intr_sz;
895a195726fSgovinda 
896a195726fSgovinda 		kmem_free(ip, intrlen);
897a195726fSgovinda 	}
898a195726fSgovinda 
899a195726fSgovinda 	return (ret);
900a195726fSgovinda }
901a195726fSgovinda 
902a195726fSgovinda /*
903b0fc0e77Sgovinda  * i_ddi_add_softint - allocate and add a software interrupt.
904b0fc0e77Sgovinda  *
905b0fc0e77Sgovinda  * NOTE: All software interrupts that are registered through DDI
906b0fc0e77Sgovinda  *	 should be triggered only on a single target or CPU.
9077c478bd9Sstevel@tonic-gate  */
9087c478bd9Sstevel@tonic-gate int
i_ddi_add_softint(ddi_softint_hdl_impl_t * hdlp)9097c478bd9Sstevel@tonic-gate i_ddi_add_softint(ddi_softint_hdl_impl_t *hdlp)
9107c478bd9Sstevel@tonic-gate {
911b0fc0e77Sgovinda 	if ((hdlp->ih_private = (void *)add_softintr(hdlp->ih_pri,
912b0fc0e77Sgovinda 	    hdlp->ih_cb_func, hdlp->ih_cb_arg1, SOFTINT_ST)) == NULL)
9137c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
9167c478bd9Sstevel@tonic-gate }
9177c478bd9Sstevel@tonic-gate 
918b0fc0e77Sgovinda /*
919b0fc0e77Sgovinda  * i_ddi_remove_softint - remove and free a software interrupt.
920b0fc0e77Sgovinda  */
9217c478bd9Sstevel@tonic-gate void
i_ddi_remove_softint(ddi_softint_hdl_impl_t * hdlp)9227c478bd9Sstevel@tonic-gate i_ddi_remove_softint(ddi_softint_hdl_impl_t *hdlp)
9237c478bd9Sstevel@tonic-gate {
9247c478bd9Sstevel@tonic-gate 	ASSERT(hdlp->ih_private != NULL);
925a195726fSgovinda 
926b0fc0e77Sgovinda 	if (rem_softintr((uint64_t)hdlp->ih_private) == 0)
9277c478bd9Sstevel@tonic-gate 		hdlp->ih_private = NULL;
9287c478bd9Sstevel@tonic-gate }
9297c478bd9Sstevel@tonic-gate 
930b0fc0e77Sgovinda /*
931b0fc0e77Sgovinda  * i_ddi_trigger_softint - trigger a software interrupt.
932b0fc0e77Sgovinda  */
9337c478bd9Sstevel@tonic-gate int
i_ddi_trigger_softint(ddi_softint_hdl_impl_t * hdlp,void * arg2)934b08160e2Sgovinda i_ddi_trigger_softint(ddi_softint_hdl_impl_t *hdlp, void *arg2)
9357c478bd9Sstevel@tonic-gate {
9367c478bd9Sstevel@tonic-gate 	int	ret;
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 	ASSERT(hdlp->ih_private != NULL);
9397c478bd9Sstevel@tonic-gate 
940b0fc0e77Sgovinda 	/* Update the second argument for the software interrupt */
941b0fc0e77Sgovinda 	if ((ret = update_softint_arg2((uint64_t)hdlp->ih_private, arg2)) == 0)
942b0fc0e77Sgovinda 		setsoftint((uint64_t)hdlp->ih_private);
9437c478bd9Sstevel@tonic-gate 
944b0fc0e77Sgovinda 	return (ret ? DDI_EPENDING : DDI_SUCCESS);
9457c478bd9Sstevel@tonic-gate }
9467c478bd9Sstevel@tonic-gate 
947b0fc0e77Sgovinda /*
948b0fc0e77Sgovinda  * i_ddi_set_softint_pri - change software interrupt priority.
949b0fc0e77Sgovinda  */
9507c478bd9Sstevel@tonic-gate /* ARGSUSED */
9517c478bd9Sstevel@tonic-gate int
i_ddi_set_softint_pri(ddi_softint_hdl_impl_t * hdlp,uint_t old_pri)9527c478bd9Sstevel@tonic-gate i_ddi_set_softint_pri(ddi_softint_hdl_impl_t *hdlp, uint_t old_pri)
9537c478bd9Sstevel@tonic-gate {
9547c478bd9Sstevel@tonic-gate 	int	ret;
9557c478bd9Sstevel@tonic-gate 
9567c478bd9Sstevel@tonic-gate 	ASSERT(hdlp->ih_private != NULL);
9577c478bd9Sstevel@tonic-gate 
958b0fc0e77Sgovinda 	/* Update the interrupt priority for the software interrupt */
959b0fc0e77Sgovinda 	ret = update_softint_pri((uint64_t)hdlp->ih_private, hdlp->ih_pri);
9607c478bd9Sstevel@tonic-gate 
961b0fc0e77Sgovinda 	return (ret ? DDI_FAILURE : DDI_SUCCESS);
9627c478bd9Sstevel@tonic-gate }
9637c478bd9Sstevel@tonic-gate 
9647a364d25Sschwartz /*ARGSUSED*/
9657a364d25Sschwartz void
i_ddi_alloc_intr_phdl(ddi_intr_handle_impl_t * hdlp)9667a364d25Sschwartz i_ddi_alloc_intr_phdl(ddi_intr_handle_impl_t *hdlp)
9677a364d25Sschwartz {
9687a364d25Sschwartz }
9697a364d25Sschwartz 
9707a364d25Sschwartz /*ARGSUSED*/
9717a364d25Sschwartz void
i_ddi_free_intr_phdl(ddi_intr_handle_impl_t * hdlp)9727a364d25Sschwartz i_ddi_free_intr_phdl(ddi_intr_handle_impl_t *hdlp)
9737a364d25Sschwartz {
9747a364d25Sschwartz }
9757a364d25Sschwartz 
9767c478bd9Sstevel@tonic-gate /*
9777c478bd9Sstevel@tonic-gate  * SECTION: DDI Memory/DMA
9787c478bd9Sstevel@tonic-gate  */
9797c478bd9Sstevel@tonic-gate 
9807b93957cSeota /* set HAT endianess attributes from ddi_device_acc_attr */
9817b93957cSeota void
i_ddi_devacc_to_hatacc(ddi_device_acc_attr_t * devaccp,uint_t * hataccp)9827b93957cSeota i_ddi_devacc_to_hatacc(ddi_device_acc_attr_t *devaccp, uint_t *hataccp)
9837b93957cSeota {
9847b93957cSeota 	if (devaccp != NULL) {
9857b93957cSeota 		if (devaccp->devacc_attr_endian_flags == DDI_STRUCTURE_LE_ACC) {
9867b93957cSeota 			*hataccp &= ~HAT_ENDIAN_MASK;
9877b93957cSeota 			*hataccp |= HAT_STRUCTURE_LE;
9887b93957cSeota 		}
9897b93957cSeota 	}
9907b93957cSeota }
9917b93957cSeota 
9927b93957cSeota /*
9937b93957cSeota  * Check if the specified cache attribute is supported on the platform.
9947b93957cSeota  * This function must be called before i_ddi_cacheattr_to_hatacc().
9957b93957cSeota  */
9967b93957cSeota boolean_t
i_ddi_check_cache_attr(uint_t flags)9977b93957cSeota i_ddi_check_cache_attr(uint_t flags)
9987b93957cSeota {
9997b93957cSeota 	/*
10007b93957cSeota 	 * The cache attributes are mutually exclusive. Any combination of
10017b93957cSeota 	 * the attributes leads to a failure.
10027b93957cSeota 	 */
10037b93957cSeota 	uint_t cache_attr = IOMEM_CACHE_ATTR(flags);
1004*de710d24SJosef 'Jeff' Sipek 	if ((cache_attr != 0) && !ISP2(cache_attr))
10057b93957cSeota 		return (B_FALSE);
10067b93957cSeota 
10077b93957cSeota 	/*
10087b93957cSeota 	 * On the sparc architecture, only IOMEM_DATA_CACHED is meaningful,
10097b93957cSeota 	 * but others lead to a failure.
10107b93957cSeota 	 */
10117b93957cSeota 	if (cache_attr & IOMEM_DATA_CACHED)
10127b93957cSeota 		return (B_TRUE);
10137b93957cSeota 	else
10147b93957cSeota 		return (B_FALSE);
10157b93957cSeota }
10167b93957cSeota 
10177b93957cSeota /* set HAT cache attributes from the cache attributes */
10187b93957cSeota void
i_ddi_cacheattr_to_hatacc(uint_t flags,uint_t * hataccp)10197b93957cSeota i_ddi_cacheattr_to_hatacc(uint_t flags, uint_t *hataccp)
10207b93957cSeota {
10217b93957cSeota 	uint_t cache_attr = IOMEM_CACHE_ATTR(flags);
10227b93957cSeota 	static char *fname = "i_ddi_cacheattr_to_hatacc";
10237b93957cSeota #if defined(lint)
10247b93957cSeota 	*hataccp = *hataccp;
10257b93957cSeota #endif
10267b93957cSeota 	/*
10277b93957cSeota 	 * set HAT attrs according to the cache attrs.
10287b93957cSeota 	 */
10297b93957cSeota 	switch (cache_attr) {
10307b93957cSeota 	/*
10317b93957cSeota 	 * The cache coherency is always maintained on SPARC, and
10327b93957cSeota 	 * nothing is required.
10337b93957cSeota 	 */
10347b93957cSeota 	case IOMEM_DATA_CACHED:
10357b93957cSeota 		break;
10367b93957cSeota 	/*
10377b93957cSeota 	 * Both IOMEM_DATA_UC_WRITE_COMBINED and IOMEM_DATA_UNCACHED are
10387b93957cSeota 	 * not supported on SPARC -- this case must not occur because the
10397b93957cSeota 	 * cache attribute is scrutinized before this function is called.
10407b93957cSeota 	 */
10417b93957cSeota 	case IOMEM_DATA_UNCACHED:
10427b93957cSeota 	case IOMEM_DATA_UC_WR_COMBINE:
10437b93957cSeota 	default:
10447b93957cSeota 		cmn_err(CE_WARN, "%s: cache_attr=0x%x is ignored.",
10457b93957cSeota 		    fname, cache_attr);
10467b93957cSeota 	}
10477b93957cSeota }
10487b93957cSeota 
10497c478bd9Sstevel@tonic-gate static vmem_t *little_endian_arena;
10507c478bd9Sstevel@tonic-gate static vmem_t *big_endian_arena;
10517c478bd9Sstevel@tonic-gate 
10527c478bd9Sstevel@tonic-gate static void *
segkmem_alloc_le(vmem_t * vmp,size_t size,int flag)10537c478bd9Sstevel@tonic-gate segkmem_alloc_le(vmem_t *vmp, size_t size, int flag)
10547c478bd9Sstevel@tonic-gate {
10557c478bd9Sstevel@tonic-gate 	return (segkmem_xalloc(vmp, NULL, size, flag, HAT_STRUCTURE_LE,
10567c478bd9Sstevel@tonic-gate 	    segkmem_page_create, NULL));
10577c478bd9Sstevel@tonic-gate }
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate static void *
segkmem_alloc_be(vmem_t * vmp,size_t size,int flag)10607c478bd9Sstevel@tonic-gate segkmem_alloc_be(vmem_t *vmp, size_t size, int flag)
10617c478bd9Sstevel@tonic-gate {
10627c478bd9Sstevel@tonic-gate 	return (segkmem_xalloc(vmp, NULL, size, flag, HAT_STRUCTURE_BE,
10637c478bd9Sstevel@tonic-gate 	    segkmem_page_create, NULL));
10647c478bd9Sstevel@tonic-gate }
10657c478bd9Sstevel@tonic-gate 
10667c478bd9Sstevel@tonic-gate void
ka_init(void)10677c478bd9Sstevel@tonic-gate ka_init(void)
10687c478bd9Sstevel@tonic-gate {
10697c478bd9Sstevel@tonic-gate 	little_endian_arena = vmem_create("little_endian", NULL, 0, 1,
10707c478bd9Sstevel@tonic-gate 	    segkmem_alloc_le, segkmem_free, heap_arena, 0, VM_SLEEP);
10717c478bd9Sstevel@tonic-gate 	big_endian_arena = vmem_create("big_endian", NULL, 0, 1,
10727c478bd9Sstevel@tonic-gate 	    segkmem_alloc_be, segkmem_free, heap_arena, 0, VM_SLEEP);
10737c478bd9Sstevel@tonic-gate }
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate /*
10767c478bd9Sstevel@tonic-gate  * Allocate from the system, aligned on a specific boundary.
10777c478bd9Sstevel@tonic-gate  * The alignment, if non-zero, must be a power of 2.
10787c478bd9Sstevel@tonic-gate  */
10797c478bd9Sstevel@tonic-gate static void *
kalloca(size_t size,size_t align,int cansleep,uint_t endian_flags)10807c478bd9Sstevel@tonic-gate kalloca(size_t size, size_t align, int cansleep, uint_t endian_flags)
10817c478bd9Sstevel@tonic-gate {
10827c478bd9Sstevel@tonic-gate 	size_t *addr, *raddr, rsize;
10837c478bd9Sstevel@tonic-gate 	size_t hdrsize = 4 * sizeof (size_t);	/* must be power of 2 */
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate 	align = MAX(align, hdrsize);
10867c478bd9Sstevel@tonic-gate 	ASSERT((align & (align - 1)) == 0);
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate 	/*
10897c478bd9Sstevel@tonic-gate 	 * We need to allocate
10907c478bd9Sstevel@tonic-gate 	 *    rsize = size + hdrsize + align - MIN(hdrsize, buffer_alignment)
10917c478bd9Sstevel@tonic-gate 	 * bytes to be sure we have enough freedom to satisfy the request.
10927c478bd9Sstevel@tonic-gate 	 * Since the buffer alignment depends on the request size, this is
10937c478bd9Sstevel@tonic-gate 	 * not straightforward to use directly.
10947c478bd9Sstevel@tonic-gate 	 *
10957c478bd9Sstevel@tonic-gate 	 * kmem guarantees that any allocation of a 64-byte multiple will be
10967c478bd9Sstevel@tonic-gate 	 * 64-byte aligned.  Since rounding up the request could add more
10977c478bd9Sstevel@tonic-gate 	 * than we save, we compute the size with and without alignment, and
10987c478bd9Sstevel@tonic-gate 	 * use the smaller of the two.
10997c478bd9Sstevel@tonic-gate 	 */
11007c478bd9Sstevel@tonic-gate 	rsize = size + hdrsize + align;
11017c478bd9Sstevel@tonic-gate 
11027c478bd9Sstevel@tonic-gate 	if (endian_flags == DDI_STRUCTURE_LE_ACC) {
11037c478bd9Sstevel@tonic-gate 		raddr = vmem_alloc(little_endian_arena, rsize,
11047c478bd9Sstevel@tonic-gate 		    cansleep ? VM_SLEEP : VM_NOSLEEP);
11057c478bd9Sstevel@tonic-gate 	} else {
11067c478bd9Sstevel@tonic-gate 		raddr = vmem_alloc(big_endian_arena, rsize,
11077c478bd9Sstevel@tonic-gate 		    cansleep ? VM_SLEEP : VM_NOSLEEP);
11087c478bd9Sstevel@tonic-gate 	}
11097c478bd9Sstevel@tonic-gate 
11107c478bd9Sstevel@tonic-gate 	if (raddr == NULL)
11117c478bd9Sstevel@tonic-gate 		return (NULL);
11127c478bd9Sstevel@tonic-gate 
11137c478bd9Sstevel@tonic-gate 	addr = (size_t *)P2ROUNDUP((uintptr_t)raddr + hdrsize, align);
11147c478bd9Sstevel@tonic-gate 	ASSERT((uintptr_t)addr + size - (uintptr_t)raddr <= rsize);
11157c478bd9Sstevel@tonic-gate 
11167c478bd9Sstevel@tonic-gate 	addr[-3] = (size_t)endian_flags;
11177c478bd9Sstevel@tonic-gate 	addr[-2] = (size_t)raddr;
11187c478bd9Sstevel@tonic-gate 	addr[-1] = rsize;
11197c478bd9Sstevel@tonic-gate 
11207c478bd9Sstevel@tonic-gate 	return (addr);
11217c478bd9Sstevel@tonic-gate }
11227c478bd9Sstevel@tonic-gate 
11237c478bd9Sstevel@tonic-gate static void
kfreea(void * addr)11247c478bd9Sstevel@tonic-gate kfreea(void *addr)
11257c478bd9Sstevel@tonic-gate {
11267c478bd9Sstevel@tonic-gate 	size_t *saddr = addr;
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate 	if (saddr[-3] == DDI_STRUCTURE_LE_ACC)
11297c478bd9Sstevel@tonic-gate 		vmem_free(little_endian_arena, (void *)saddr[-2], saddr[-1]);
11307c478bd9Sstevel@tonic-gate 	else
11317c478bd9Sstevel@tonic-gate 		vmem_free(big_endian_arena, (void *)saddr[-2], saddr[-1]);
11327c478bd9Sstevel@tonic-gate }
11337c478bd9Sstevel@tonic-gate 
1134b89e420aSGarrett D'Amore /*
1135b89e420aSGarrett D'Amore  * This used to be ddi_iomin, but we were the only remaining caller, so
1136b89e420aSGarrett D'Amore  * we've made it private and moved it here.
1137b89e420aSGarrett D'Amore  */
1138b89e420aSGarrett D'Amore static int
i_ddi_iomin(dev_info_t * a,int i,int stream)1139b89e420aSGarrett D'Amore i_ddi_iomin(dev_info_t *a, int i, int stream)
1140b89e420aSGarrett D'Amore {
1141b89e420aSGarrett D'Amore 	int r;
1142b89e420aSGarrett D'Amore 
1143b89e420aSGarrett D'Amore 	/*
1144b89e420aSGarrett D'Amore 	 * Make sure that the initial value is sane
1145b89e420aSGarrett D'Amore 	 */
1146*de710d24SJosef 'Jeff' Sipek 	if (!ISP2(i))
1147b89e420aSGarrett D'Amore 		return (0);
1148b89e420aSGarrett D'Amore 	if (i == 0)
1149b89e420aSGarrett D'Amore 		i = (stream) ? 4 : 1;
1150b89e420aSGarrett D'Amore 
1151b89e420aSGarrett D'Amore 	r = ddi_ctlops(a, a,
1152b89e420aSGarrett D'Amore 	    DDI_CTLOPS_IOMIN, (void *)(uintptr_t)stream, (void *)&i);
1153*de710d24SJosef 'Jeff' Sipek 	if (r != DDI_SUCCESS || !ISP2(i))
1154b89e420aSGarrett D'Amore 		return (0);
1155b89e420aSGarrett D'Amore 	return (i);
1156b89e420aSGarrett D'Amore }
1157b89e420aSGarrett D'Amore 
11587c478bd9Sstevel@tonic-gate int
i_ddi_mem_alloc(dev_info_t * dip,ddi_dma_attr_t * attr,size_t length,int cansleep,int flags,ddi_device_acc_attr_t * accattrp,caddr_t * kaddrp,size_t * real_length,ddi_acc_hdl_t * handlep)11597c478bd9Sstevel@tonic-gate i_ddi_mem_alloc(dev_info_t *dip, ddi_dma_attr_t *attr,
11607b93957cSeota     size_t length, int cansleep, int flags,
11617c478bd9Sstevel@tonic-gate     ddi_device_acc_attr_t *accattrp,
11627c478bd9Sstevel@tonic-gate     caddr_t *kaddrp, size_t *real_length, ddi_acc_hdl_t *handlep)
11637c478bd9Sstevel@tonic-gate {
11647c478bd9Sstevel@tonic-gate 	caddr_t a;
11657b93957cSeota 	int iomin, align, streaming;
11667c478bd9Sstevel@tonic-gate 	uint_t endian_flags = DDI_NEVERSWAP_ACC;
11677c478bd9Sstevel@tonic-gate 
11687c478bd9Sstevel@tonic-gate #if defined(lint)
11697c478bd9Sstevel@tonic-gate 	*handlep = *handlep;
11707c478bd9Sstevel@tonic-gate #endif
11717c478bd9Sstevel@tonic-gate 
11727c478bd9Sstevel@tonic-gate 	/*
11737c478bd9Sstevel@tonic-gate 	 * Check legality of arguments
11747c478bd9Sstevel@tonic-gate 	 */
11757c478bd9Sstevel@tonic-gate 	if (length == 0 || kaddrp == NULL || attr == NULL) {
11767c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
11777c478bd9Sstevel@tonic-gate 	}
11787b93957cSeota 
11797c478bd9Sstevel@tonic-gate 	if (attr->dma_attr_minxfer == 0 || attr->dma_attr_align == 0 ||
1180*de710d24SJosef 'Jeff' Sipek 	    !ISP2(attr->dma_attr_align) || !ISP2(attr->dma_attr_minxfer)) {
11817c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
11827c478bd9Sstevel@tonic-gate 	}
11837c478bd9Sstevel@tonic-gate 
11847c478bd9Sstevel@tonic-gate 	/*
11857b93957cSeota 	 * check if a streaming sequential xfer is requested.
11867b93957cSeota 	 */
11877b93957cSeota 	streaming = (flags & DDI_DMA_STREAMING) ? 1 : 0;
11887b93957cSeota 
11897b93957cSeota 	/*
11907c478bd9Sstevel@tonic-gate 	 * Drivers for 64-bit capable SBus devices will encode
11917c478bd9Sstevel@tonic-gate 	 * the burtsizes for 64-bit xfers in the upper 16-bits.
11927c478bd9Sstevel@tonic-gate 	 * For DMA alignment, we use the most restrictive
11937c478bd9Sstevel@tonic-gate 	 * alignment of 32-bit and 64-bit xfers.
11947c478bd9Sstevel@tonic-gate 	 */
11957c478bd9Sstevel@tonic-gate 	iomin = (attr->dma_attr_burstsizes & 0xffff) |
11967c478bd9Sstevel@tonic-gate 	    ((attr->dma_attr_burstsizes >> 16) & 0xffff);
11977c478bd9Sstevel@tonic-gate 	/*
11987c478bd9Sstevel@tonic-gate 	 * If a driver set burtsizes to 0, we give him byte alignment.
11997c478bd9Sstevel@tonic-gate 	 * Otherwise align at the burtsizes boundary.
12007c478bd9Sstevel@tonic-gate 	 */
12017c478bd9Sstevel@tonic-gate 	if (iomin == 0)
12027c478bd9Sstevel@tonic-gate 		iomin = 1;
12037c478bd9Sstevel@tonic-gate 	else
12047c478bd9Sstevel@tonic-gate 		iomin = 1 << (ddi_fls(iomin) - 1);
12057c478bd9Sstevel@tonic-gate 	iomin = maxbit(iomin, attr->dma_attr_minxfer);
12067c478bd9Sstevel@tonic-gate 	iomin = maxbit(iomin, attr->dma_attr_align);
1207b89e420aSGarrett D'Amore 	iomin = i_ddi_iomin(dip, iomin, streaming);
12087c478bd9Sstevel@tonic-gate 	if (iomin == 0)
12097c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
12107c478bd9Sstevel@tonic-gate 
12117c478bd9Sstevel@tonic-gate 	ASSERT((iomin & (iomin - 1)) == 0);
12127c478bd9Sstevel@tonic-gate 	ASSERT(iomin >= attr->dma_attr_minxfer);
12137c478bd9Sstevel@tonic-gate 	ASSERT(iomin >= attr->dma_attr_align);
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate 	length = P2ROUNDUP(length, iomin);
12167c478bd9Sstevel@tonic-gate 	align = iomin;
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate 	if (accattrp != NULL)
12197c478bd9Sstevel@tonic-gate 		endian_flags = accattrp->devacc_attr_endian_flags;
12207c478bd9Sstevel@tonic-gate 
12217c478bd9Sstevel@tonic-gate 	a = kalloca(length, align, cansleep, endian_flags);
12227c478bd9Sstevel@tonic-gate 	if ((*kaddrp = a) == 0) {
12237c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
12247c478bd9Sstevel@tonic-gate 	} else {
12257c478bd9Sstevel@tonic-gate 		if (real_length) {
12267c478bd9Sstevel@tonic-gate 			*real_length = length;
12277c478bd9Sstevel@tonic-gate 		}
12287c478bd9Sstevel@tonic-gate 		if (handlep) {
12297c478bd9Sstevel@tonic-gate 			/*
12307c478bd9Sstevel@tonic-gate 			 * assign handle information
12317c478bd9Sstevel@tonic-gate 			 */
12327c478bd9Sstevel@tonic-gate 			impl_acc_hdl_init(handlep);
12337c478bd9Sstevel@tonic-gate 		}
12347c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
12357c478bd9Sstevel@tonic-gate 	}
12367c478bd9Sstevel@tonic-gate }
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate /* ARGSUSED */
12397c478bd9Sstevel@tonic-gate void
i_ddi_mem_free(caddr_t kaddr,ddi_acc_hdl_t * ap)12407b93957cSeota i_ddi_mem_free(caddr_t kaddr, ddi_acc_hdl_t *ap)
12417c478bd9Sstevel@tonic-gate {
12427c478bd9Sstevel@tonic-gate 	kfreea(kaddr);
12437c478bd9Sstevel@tonic-gate }
12447c478bd9Sstevel@tonic-gate 
12457c478bd9Sstevel@tonic-gate /*
12467c478bd9Sstevel@tonic-gate  * SECTION: DDI Data Access
12477c478bd9Sstevel@tonic-gate  */
12487c478bd9Sstevel@tonic-gate 
12497c478bd9Sstevel@tonic-gate static uintptr_t impl_acc_hdl_id = 0;
12507c478bd9Sstevel@tonic-gate 
12517c478bd9Sstevel@tonic-gate /*
12527c478bd9Sstevel@tonic-gate  * access handle allocator
12537c478bd9Sstevel@tonic-gate  */
12547c478bd9Sstevel@tonic-gate ddi_acc_hdl_t *
impl_acc_hdl_get(ddi_acc_handle_t hdl)12557c478bd9Sstevel@tonic-gate impl_acc_hdl_get(ddi_acc_handle_t hdl)
12567c478bd9Sstevel@tonic-gate {
12577c478bd9Sstevel@tonic-gate 	/*
12587c478bd9Sstevel@tonic-gate 	 * Extract the access handle address from the DDI implemented
12597c478bd9Sstevel@tonic-gate 	 * access handle
12607c478bd9Sstevel@tonic-gate 	 */
12617c478bd9Sstevel@tonic-gate 	return (&((ddi_acc_impl_t *)hdl)->ahi_common);
12627c478bd9Sstevel@tonic-gate }
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate ddi_acc_handle_t
impl_acc_hdl_alloc(int (* waitfp)(caddr_t),caddr_t arg)12657c478bd9Sstevel@tonic-gate impl_acc_hdl_alloc(int (*waitfp)(caddr_t), caddr_t arg)
12667c478bd9Sstevel@tonic-gate {
12677c478bd9Sstevel@tonic-gate 	ddi_acc_impl_t *hp;
12687c478bd9Sstevel@tonic-gate 	on_trap_data_t *otp;
12697c478bd9Sstevel@tonic-gate 	int sleepflag;
12707c478bd9Sstevel@tonic-gate 
12717c478bd9Sstevel@tonic-gate 	sleepflag = ((waitfp == (int (*)())KM_SLEEP) ? KM_SLEEP : KM_NOSLEEP);
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate 	/*
12747c478bd9Sstevel@tonic-gate 	 * Allocate and initialize the data access handle and error status.
12757c478bd9Sstevel@tonic-gate 	 */
12767c478bd9Sstevel@tonic-gate 	if ((hp = kmem_zalloc(sizeof (ddi_acc_impl_t), sleepflag)) == NULL)
12777c478bd9Sstevel@tonic-gate 		goto fail;
12787c478bd9Sstevel@tonic-gate 	if ((hp->ahi_err = (ndi_err_t *)kmem_zalloc(
12797c478bd9Sstevel@tonic-gate 	    sizeof (ndi_err_t), sleepflag)) == NULL) {
12807c478bd9Sstevel@tonic-gate 		kmem_free(hp, sizeof (ddi_acc_impl_t));
12817c478bd9Sstevel@tonic-gate 		goto fail;
12827c478bd9Sstevel@tonic-gate 	}
12837c478bd9Sstevel@tonic-gate 	if ((otp = (on_trap_data_t *)kmem_zalloc(
12847c478bd9Sstevel@tonic-gate 	    sizeof (on_trap_data_t), sleepflag)) == NULL) {
12857c478bd9Sstevel@tonic-gate 		kmem_free(hp->ahi_err, sizeof (ndi_err_t));
12867c478bd9Sstevel@tonic-gate 		kmem_free(hp, sizeof (ddi_acc_impl_t));
12877c478bd9Sstevel@tonic-gate 		goto fail;
12887c478bd9Sstevel@tonic-gate 	}
12897c478bd9Sstevel@tonic-gate 	hp->ahi_err->err_ontrap = otp;
12907c478bd9Sstevel@tonic-gate 	hp->ahi_common.ah_platform_private = (void *)hp;
12917c478bd9Sstevel@tonic-gate 
12927c478bd9Sstevel@tonic-gate 	return ((ddi_acc_handle_t)hp);
12937c478bd9Sstevel@tonic-gate fail:
12947c478bd9Sstevel@tonic-gate 	if ((waitfp != (int (*)())KM_SLEEP) &&
12957c478bd9Sstevel@tonic-gate 	    (waitfp != (int (*)())KM_NOSLEEP))
12967c478bd9Sstevel@tonic-gate 		ddi_set_callback(waitfp, arg, &impl_acc_hdl_id);
12977c478bd9Sstevel@tonic-gate 	return (NULL);
12987c478bd9Sstevel@tonic-gate }
12997c478bd9Sstevel@tonic-gate 
13007c478bd9Sstevel@tonic-gate void
impl_acc_hdl_free(ddi_acc_handle_t handle)13017c478bd9Sstevel@tonic-gate impl_acc_hdl_free(ddi_acc_handle_t handle)
13027c478bd9Sstevel@tonic-gate {
13037c478bd9Sstevel@tonic-gate 	ddi_acc_impl_t *hp;
13047c478bd9Sstevel@tonic-gate 
13057c478bd9Sstevel@tonic-gate 	/*
13067c478bd9Sstevel@tonic-gate 	 * The supplied (ddi_acc_handle_t) is actually a (ddi_acc_impl_t *),
13077c478bd9Sstevel@tonic-gate 	 * because that's what we allocated in impl_acc_hdl_alloc() above.
13087c478bd9Sstevel@tonic-gate 	 */
13097c478bd9Sstevel@tonic-gate 	hp = (ddi_acc_impl_t *)handle;
13107c478bd9Sstevel@tonic-gate 	if (hp) {
13117c478bd9Sstevel@tonic-gate 		kmem_free(hp->ahi_err->err_ontrap, sizeof (on_trap_data_t));
13127c478bd9Sstevel@tonic-gate 		kmem_free(hp->ahi_err, sizeof (ndi_err_t));
13137c478bd9Sstevel@tonic-gate 		kmem_free(hp, sizeof (ddi_acc_impl_t));
13147c478bd9Sstevel@tonic-gate 		if (impl_acc_hdl_id)
13157c478bd9Sstevel@tonic-gate 			ddi_run_callback(&impl_acc_hdl_id);
13167c478bd9Sstevel@tonic-gate 	}
13177c478bd9Sstevel@tonic-gate }
13187c478bd9Sstevel@tonic-gate 
131900d0963fSdilpreet #define	PCI_GET_MP_PFN(mp, page_no)	((mp)->dmai_ndvmapages == 1 ? \
132000d0963fSdilpreet 	(pfn_t)(mp)->dmai_iopte:(((pfn_t *)(mp)->dmai_iopte)[page_no]))
132100d0963fSdilpreet 
132200d0963fSdilpreet /*
132300d0963fSdilpreet  * Function called after a dma fault occurred to find out whether the
132400d0963fSdilpreet  * fault address is associated with a driver that is able to handle faults
132500d0963fSdilpreet  * and recover from faults.
132600d0963fSdilpreet  */
132700d0963fSdilpreet /* ARGSUSED */
132800d0963fSdilpreet int
impl_dma_check(dev_info_t * dip,const void * handle,const void * addr,const void * not_used)132900d0963fSdilpreet impl_dma_check(dev_info_t *dip, const void *handle, const void *addr,
133000d0963fSdilpreet     const void *not_used)
133100d0963fSdilpreet {
133200d0963fSdilpreet 	ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle;
133300d0963fSdilpreet 	pfn_t fault_pfn = mmu_btop(*(uint64_t *)addr);
133400d0963fSdilpreet 	pfn_t comp_pfn;
133500d0963fSdilpreet 
133600d0963fSdilpreet 	/*
133700d0963fSdilpreet 	 * The driver has to set DDI_DMA_FLAGERR to recover from dma faults.
133800d0963fSdilpreet 	 */
133900d0963fSdilpreet 	int page;
134000d0963fSdilpreet 
134100d0963fSdilpreet 	ASSERT(mp);
134200d0963fSdilpreet 	for (page = 0; page < mp->dmai_ndvmapages; page++) {
134300d0963fSdilpreet 		comp_pfn = PCI_GET_MP_PFN(mp, page);
134400d0963fSdilpreet 		if (fault_pfn == comp_pfn)
134500d0963fSdilpreet 			return (DDI_FM_NONFATAL);
134600d0963fSdilpreet 	}
134700d0963fSdilpreet 	return (DDI_FM_UNKNOWN);
134800d0963fSdilpreet }
134900d0963fSdilpreet 
135000d0963fSdilpreet /*
135100d0963fSdilpreet  * Function used to check if a given access handle owns the failing address.
135200d0963fSdilpreet  * Called by ndi_fmc_error, when we detect a PIO error.
135300d0963fSdilpreet  */
135400d0963fSdilpreet /* ARGSUSED */
135500d0963fSdilpreet static int
impl_acc_check(dev_info_t * dip,const void * handle,const void * addr,const void * not_used)135600d0963fSdilpreet impl_acc_check(dev_info_t *dip, const void *handle, const void *addr,
135700d0963fSdilpreet     const void *not_used)
135800d0963fSdilpreet {
135900d0963fSdilpreet 	pfn_t pfn, fault_pfn;
136000d0963fSdilpreet 	ddi_acc_hdl_t *hp;
136100d0963fSdilpreet 
136200d0963fSdilpreet 	hp = impl_acc_hdl_get((ddi_acc_handle_t)handle);
136300d0963fSdilpreet 
136400d0963fSdilpreet 	ASSERT(hp);
136500d0963fSdilpreet 
136600d0963fSdilpreet 	if (addr != NULL) {
136700d0963fSdilpreet 		pfn = hp->ah_pfn;
136800d0963fSdilpreet 		fault_pfn = mmu_btop(*(uint64_t *)addr);
136900d0963fSdilpreet 		if (fault_pfn >= pfn && fault_pfn < (pfn + hp->ah_pnum))
137000d0963fSdilpreet 			return (DDI_FM_NONFATAL);
137100d0963fSdilpreet 	}
137200d0963fSdilpreet 	return (DDI_FM_UNKNOWN);
137300d0963fSdilpreet }
137400d0963fSdilpreet 
13757c478bd9Sstevel@tonic-gate void
impl_acc_err_init(ddi_acc_hdl_t * handlep)13767c478bd9Sstevel@tonic-gate impl_acc_err_init(ddi_acc_hdl_t *handlep)
13777c478bd9Sstevel@tonic-gate {
13787c478bd9Sstevel@tonic-gate 	int fmcap;
13797c478bd9Sstevel@tonic-gate 	ndi_err_t *errp;
13807c478bd9Sstevel@tonic-gate 	on_trap_data_t *otp;
13817c478bd9Sstevel@tonic-gate 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)handlep;
13827c478bd9Sstevel@tonic-gate 
13837c478bd9Sstevel@tonic-gate 	fmcap = ddi_fm_capable(handlep->ah_dip);
13847c478bd9Sstevel@tonic-gate 
13857c478bd9Sstevel@tonic-gate 	if (handlep->ah_acc.devacc_attr_version < DDI_DEVICE_ATTR_V1 ||
13867c478bd9Sstevel@tonic-gate 	    !DDI_FM_ACC_ERR_CAP(fmcap)) {
13877c478bd9Sstevel@tonic-gate 		handlep->ah_acc.devacc_attr_access = DDI_DEFAULT_ACC;
13887c478bd9Sstevel@tonic-gate 	} else if (DDI_FM_ACC_ERR_CAP(fmcap)) {
13897c478bd9Sstevel@tonic-gate 		if (handlep->ah_acc.devacc_attr_access == DDI_DEFAULT_ACC) {
1390837c1ac4SStephen Hanson 			if (handlep->ah_xfermodes)
1391837c1ac4SStephen Hanson 				return;
13927c478bd9Sstevel@tonic-gate 			i_ddi_drv_ereport_post(handlep->ah_dip, DVR_EFMCAP,
13937c478bd9Sstevel@tonic-gate 			    NULL, DDI_NOSLEEP);
13947c478bd9Sstevel@tonic-gate 		} else {
13957c478bd9Sstevel@tonic-gate 			errp = hp->ahi_err;
13967c478bd9Sstevel@tonic-gate 			otp = (on_trap_data_t *)errp->err_ontrap;
13977c478bd9Sstevel@tonic-gate 			otp->ot_handle = (void *)(hp);
13987c478bd9Sstevel@tonic-gate 			otp->ot_prot = OT_DATA_ACCESS;
13997c478bd9Sstevel@tonic-gate 			if (handlep->ah_acc.devacc_attr_access ==
14007c478bd9Sstevel@tonic-gate 			    DDI_CAUTIOUS_ACC)
14017c478bd9Sstevel@tonic-gate 				otp->ot_trampoline =
14027c478bd9Sstevel@tonic-gate 				    (uintptr_t)&i_ddi_caut_trampoline;
14037c478bd9Sstevel@tonic-gate 			else
14047c478bd9Sstevel@tonic-gate 				otp->ot_trampoline =
14057c478bd9Sstevel@tonic-gate 				    (uintptr_t)&i_ddi_prot_trampoline;
14067c478bd9Sstevel@tonic-gate 			errp->err_status = DDI_FM_OK;
14077c478bd9Sstevel@tonic-gate 			errp->err_expected = DDI_FM_ERR_UNEXPECTED;
140800d0963fSdilpreet 			errp->err_cf = impl_acc_check;
14097c478bd9Sstevel@tonic-gate 		}
14107c478bd9Sstevel@tonic-gate 	}
14117c478bd9Sstevel@tonic-gate }
14127c478bd9Sstevel@tonic-gate 
14137c478bd9Sstevel@tonic-gate void
impl_acc_hdl_init(ddi_acc_hdl_t * handlep)14147c478bd9Sstevel@tonic-gate impl_acc_hdl_init(ddi_acc_hdl_t *handlep)
14157c478bd9Sstevel@tonic-gate {
14167c478bd9Sstevel@tonic-gate 	ddi_acc_impl_t *hp;
14177c478bd9Sstevel@tonic-gate 
14187c478bd9Sstevel@tonic-gate 	ASSERT(handlep);
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate 	hp = (ddi_acc_impl_t *)handlep;
14217c478bd9Sstevel@tonic-gate 
14227c478bd9Sstevel@tonic-gate 	/*
14237c478bd9Sstevel@tonic-gate 	 * check for SW byte-swapping
14247c478bd9Sstevel@tonic-gate 	 */
14257c478bd9Sstevel@tonic-gate 	hp->ahi_get8 = i_ddi_get8;
14267c478bd9Sstevel@tonic-gate 	hp->ahi_put8 = i_ddi_put8;
14277c478bd9Sstevel@tonic-gate 	hp->ahi_rep_get8 = i_ddi_rep_get8;
14287c478bd9Sstevel@tonic-gate 	hp->ahi_rep_put8 = i_ddi_rep_put8;
14297c478bd9Sstevel@tonic-gate 	if (handlep->ah_acc.devacc_attr_endian_flags & DDI_STRUCTURE_LE_ACC) {
14307c478bd9Sstevel@tonic-gate 		hp->ahi_get16 = i_ddi_swap_get16;
14317c478bd9Sstevel@tonic-gate 		hp->ahi_get32 = i_ddi_swap_get32;
14327c478bd9Sstevel@tonic-gate 		hp->ahi_get64 = i_ddi_swap_get64;
14337c478bd9Sstevel@tonic-gate 		hp->ahi_put16 = i_ddi_swap_put16;
14347c478bd9Sstevel@tonic-gate 		hp->ahi_put32 = i_ddi_swap_put32;
14357c478bd9Sstevel@tonic-gate 		hp->ahi_put64 = i_ddi_swap_put64;
14367c478bd9Sstevel@tonic-gate 		hp->ahi_rep_get16 = i_ddi_swap_rep_get16;
14377c478bd9Sstevel@tonic-gate 		hp->ahi_rep_get32 = i_ddi_swap_rep_get32;
14387c478bd9Sstevel@tonic-gate 		hp->ahi_rep_get64 = i_ddi_swap_rep_get64;
14397c478bd9Sstevel@tonic-gate 		hp->ahi_rep_put16 = i_ddi_swap_rep_put16;
14407c478bd9Sstevel@tonic-gate 		hp->ahi_rep_put32 = i_ddi_swap_rep_put32;
14417c478bd9Sstevel@tonic-gate 		hp->ahi_rep_put64 = i_ddi_swap_rep_put64;
14427c478bd9Sstevel@tonic-gate 	} else {
14437c478bd9Sstevel@tonic-gate 		hp->ahi_get16 = i_ddi_get16;
14447c478bd9Sstevel@tonic-gate 		hp->ahi_get32 = i_ddi_get32;
14457c478bd9Sstevel@tonic-gate 		hp->ahi_get64 = i_ddi_get64;
14467c478bd9Sstevel@tonic-gate 		hp->ahi_put16 = i_ddi_put16;
14477c478bd9Sstevel@tonic-gate 		hp->ahi_put32 = i_ddi_put32;
14487c478bd9Sstevel@tonic-gate 		hp->ahi_put64 = i_ddi_put64;
14497c478bd9Sstevel@tonic-gate 		hp->ahi_rep_get16 = i_ddi_rep_get16;
14507c478bd9Sstevel@tonic-gate 		hp->ahi_rep_get32 = i_ddi_rep_get32;
14517c478bd9Sstevel@tonic-gate 		hp->ahi_rep_get64 = i_ddi_rep_get64;
14527c478bd9Sstevel@tonic-gate 		hp->ahi_rep_put16 = i_ddi_rep_put16;
14537c478bd9Sstevel@tonic-gate 		hp->ahi_rep_put32 = i_ddi_rep_put32;
14547c478bd9Sstevel@tonic-gate 		hp->ahi_rep_put64 = i_ddi_rep_put64;
14557c478bd9Sstevel@tonic-gate 	}
14567c478bd9Sstevel@tonic-gate 
14577c478bd9Sstevel@tonic-gate 	/* Legacy fault flags and support */
14587c478bd9Sstevel@tonic-gate 	hp->ahi_fault_check = i_ddi_acc_fault_check;
14597c478bd9Sstevel@tonic-gate 	hp->ahi_fault_notify = i_ddi_acc_fault_notify;
14607c478bd9Sstevel@tonic-gate 	hp->ahi_fault = 0;
14617c478bd9Sstevel@tonic-gate 	impl_acc_err_init(handlep);
14627c478bd9Sstevel@tonic-gate }
14637c478bd9Sstevel@tonic-gate 
14647c478bd9Sstevel@tonic-gate void
i_ddi_acc_set_fault(ddi_acc_handle_t handle)14657c478bd9Sstevel@tonic-gate i_ddi_acc_set_fault(ddi_acc_handle_t handle)
14667c478bd9Sstevel@tonic-gate {
14677c478bd9Sstevel@tonic-gate 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)handle;
14687c478bd9Sstevel@tonic-gate 
14697c478bd9Sstevel@tonic-gate 	if (!hp->ahi_fault) {
14707c478bd9Sstevel@tonic-gate 		hp->ahi_fault = 1;
14717c478bd9Sstevel@tonic-gate 			(*hp->ahi_fault_notify)(hp);
14727c478bd9Sstevel@tonic-gate 	}
14737c478bd9Sstevel@tonic-gate }
14747c478bd9Sstevel@tonic-gate 
14757c478bd9Sstevel@tonic-gate void
i_ddi_acc_clr_fault(ddi_acc_handle_t handle)14767c478bd9Sstevel@tonic-gate i_ddi_acc_clr_fault(ddi_acc_handle_t handle)
14777c478bd9Sstevel@tonic-gate {
14787c478bd9Sstevel@tonic-gate 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)handle;
14797c478bd9Sstevel@tonic-gate 
14807c478bd9Sstevel@tonic-gate 	if (hp->ahi_fault) {
14817c478bd9Sstevel@tonic-gate 		hp->ahi_fault = 0;
14827c478bd9Sstevel@tonic-gate 			(*hp->ahi_fault_notify)(hp);
14837c478bd9Sstevel@tonic-gate 	}
14847c478bd9Sstevel@tonic-gate }
14857c478bd9Sstevel@tonic-gate 
14867c478bd9Sstevel@tonic-gate /* ARGSUSED */
14877c478bd9Sstevel@tonic-gate void
i_ddi_acc_fault_notify(ddi_acc_impl_t * hp)14887c478bd9Sstevel@tonic-gate i_ddi_acc_fault_notify(ddi_acc_impl_t *hp)
14897c478bd9Sstevel@tonic-gate {
14907c478bd9Sstevel@tonic-gate 	/* Default version, does nothing */
14917c478bd9Sstevel@tonic-gate }
14927c478bd9Sstevel@tonic-gate 
14937c478bd9Sstevel@tonic-gate /*
14947c478bd9Sstevel@tonic-gate  * SECTION: Misc functions
14957c478bd9Sstevel@tonic-gate  */
14967c478bd9Sstevel@tonic-gate 
14977c478bd9Sstevel@tonic-gate /*
14987c478bd9Sstevel@tonic-gate  * instance wrappers
14997c478bd9Sstevel@tonic-gate  */
15007c478bd9Sstevel@tonic-gate /*ARGSUSED*/
15017c478bd9Sstevel@tonic-gate uint_t
impl_assign_instance(dev_info_t * dip)15027c478bd9Sstevel@tonic-gate impl_assign_instance(dev_info_t *dip)
15037c478bd9Sstevel@tonic-gate {
15047c478bd9Sstevel@tonic-gate 	return ((uint_t)-1);
15057c478bd9Sstevel@tonic-gate }
15067c478bd9Sstevel@tonic-gate 
15077c478bd9Sstevel@tonic-gate /*ARGSUSED*/
15087c478bd9Sstevel@tonic-gate int
impl_keep_instance(dev_info_t * dip)15097c478bd9Sstevel@tonic-gate impl_keep_instance(dev_info_t *dip)
15107c478bd9Sstevel@tonic-gate {
15117c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
15127c478bd9Sstevel@tonic-gate }
15137c478bd9Sstevel@tonic-gate 
15147c478bd9Sstevel@tonic-gate /*ARGSUSED*/
15157c478bd9Sstevel@tonic-gate int
impl_free_instance(dev_info_t * dip)15167c478bd9Sstevel@tonic-gate impl_free_instance(dev_info_t *dip)
15177c478bd9Sstevel@tonic-gate {
15187c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
15197c478bd9Sstevel@tonic-gate }
15207c478bd9Sstevel@tonic-gate 
15217c478bd9Sstevel@tonic-gate /*ARGSUSED*/
15227c478bd9Sstevel@tonic-gate int
impl_check_cpu(dev_info_t * devi)15237c478bd9Sstevel@tonic-gate impl_check_cpu(dev_info_t *devi)
15247c478bd9Sstevel@tonic-gate {
15257c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
15267c478bd9Sstevel@tonic-gate }
15277c478bd9Sstevel@tonic-gate 
15287c478bd9Sstevel@tonic-gate 
15297c478bd9Sstevel@tonic-gate static const char *nocopydevs[] = {
15307c478bd9Sstevel@tonic-gate 	"SUNW,ffb",
15317c478bd9Sstevel@tonic-gate 	"SUNW,afb",
15327c478bd9Sstevel@tonic-gate 	NULL
15337c478bd9Sstevel@tonic-gate };
15347c478bd9Sstevel@tonic-gate 
15357c478bd9Sstevel@tonic-gate /*
15367c478bd9Sstevel@tonic-gate  * Perform a copy from a memory mapped device (whose devinfo pointer is devi)
15377c478bd9Sstevel@tonic-gate  * separately mapped at devaddr in the kernel to a kernel buffer at kaddr.
15387c478bd9Sstevel@tonic-gate  */
15397c478bd9Sstevel@tonic-gate /*ARGSUSED*/
15407c478bd9Sstevel@tonic-gate int
e_ddi_copyfromdev(dev_info_t * devi,off_t off,const void * devaddr,void * kaddr,size_t len)15417c478bd9Sstevel@tonic-gate e_ddi_copyfromdev(dev_info_t *devi,
15427c478bd9Sstevel@tonic-gate     off_t off, const void *devaddr, void *kaddr, size_t len)
15437c478bd9Sstevel@tonic-gate {
15447c478bd9Sstevel@tonic-gate 	const char **argv;
15457c478bd9Sstevel@tonic-gate 
15467c478bd9Sstevel@tonic-gate 	for (argv = nocopydevs; *argv; argv++)
15477c478bd9Sstevel@tonic-gate 		if (strcmp(ddi_binding_name(devi), *argv) == 0) {
15487c478bd9Sstevel@tonic-gate 			bzero(kaddr, len);
15497c478bd9Sstevel@tonic-gate 			return (0);
15507c478bd9Sstevel@tonic-gate 		}
15517c478bd9Sstevel@tonic-gate 
15527c478bd9Sstevel@tonic-gate 	bcopy(devaddr, kaddr, len);
15537c478bd9Sstevel@tonic-gate 	return (0);
15547c478bd9Sstevel@tonic-gate }
15557c478bd9Sstevel@tonic-gate 
15567c478bd9Sstevel@tonic-gate /*
15577c478bd9Sstevel@tonic-gate  * Perform a copy to a memory mapped device (whose devinfo pointer is devi)
15587c478bd9Sstevel@tonic-gate  * separately mapped at devaddr in the kernel from a kernel buffer at kaddr.
15597c478bd9Sstevel@tonic-gate  */
15607c478bd9Sstevel@tonic-gate /*ARGSUSED*/
15617c478bd9Sstevel@tonic-gate int
e_ddi_copytodev(dev_info_t * devi,off_t off,const void * kaddr,void * devaddr,size_t len)15627c478bd9Sstevel@tonic-gate e_ddi_copytodev(dev_info_t *devi,
15637c478bd9Sstevel@tonic-gate     off_t off, const void *kaddr, void *devaddr, size_t len)
15647c478bd9Sstevel@tonic-gate {
15657c478bd9Sstevel@tonic-gate 	const char **argv;
15667c478bd9Sstevel@tonic-gate 
15677c478bd9Sstevel@tonic-gate 	for (argv = nocopydevs; *argv; argv++)
15687c478bd9Sstevel@tonic-gate 		if (strcmp(ddi_binding_name(devi), *argv) == 0)
15697c478bd9Sstevel@tonic-gate 			return (1);
15707c478bd9Sstevel@tonic-gate 
15717c478bd9Sstevel@tonic-gate 	bcopy(kaddr, devaddr, len);
15727c478bd9Sstevel@tonic-gate 	return (0);
15737c478bd9Sstevel@tonic-gate }
15747c478bd9Sstevel@tonic-gate 
15757c478bd9Sstevel@tonic-gate /*
15767c478bd9Sstevel@tonic-gate  * Boot Configuration
15777c478bd9Sstevel@tonic-gate  */
15787c478bd9Sstevel@tonic-gate idprom_t idprom;
15797c478bd9Sstevel@tonic-gate 
15807c478bd9Sstevel@tonic-gate /*
15817c478bd9Sstevel@tonic-gate  * Configure the hardware on the system.
15827c478bd9Sstevel@tonic-gate  * Called before the rootfs is mounted
15837c478bd9Sstevel@tonic-gate  */
15847c478bd9Sstevel@tonic-gate void
configure(void)15857c478bd9Sstevel@tonic-gate configure(void)
15867c478bd9Sstevel@tonic-gate {
15877c478bd9Sstevel@tonic-gate 	extern void i_ddi_init_root();
15887c478bd9Sstevel@tonic-gate 
15897c478bd9Sstevel@tonic-gate 	/* We better have released boot by this time! */
15907c478bd9Sstevel@tonic-gate 	ASSERT(!bootops);
15917c478bd9Sstevel@tonic-gate 
15927c478bd9Sstevel@tonic-gate 	/*
15937c478bd9Sstevel@tonic-gate 	 * Determine whether or not to use the fpu, V9 SPARC cpus
15947c478bd9Sstevel@tonic-gate 	 * always have one. Could check for existence of a fp queue,
15957c478bd9Sstevel@tonic-gate 	 * Ultra I, II and IIa do not have a fp queue.
15967c478bd9Sstevel@tonic-gate 	 */
15977c478bd9Sstevel@tonic-gate 	if (fpu_exists)
15987c478bd9Sstevel@tonic-gate 		fpu_probe();
15997c478bd9Sstevel@tonic-gate 	else
16007c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "FPU not in use\n");
16017c478bd9Sstevel@tonic-gate 
16027c478bd9Sstevel@tonic-gate #if 0 /* XXXQ - not necessary for sun4u */
16037c478bd9Sstevel@tonic-gate 	/*
16047c478bd9Sstevel@tonic-gate 	 * This following line fixes bugid 1041296; we need to do a
16057c478bd9Sstevel@tonic-gate 	 * prom_nextnode(0) because this call ALSO patches the DMA+
16067c478bd9Sstevel@tonic-gate 	 * bug in Campus-B and Phoenix. The prom uncaches the traptable
16077c478bd9Sstevel@tonic-gate 	 * page as a side-effect of devr_next(0) (which prom_nextnode calls),
16087c478bd9Sstevel@tonic-gate 	 * so this *must* be executed early on. (XXX This is untrue for sun4u)
16097c478bd9Sstevel@tonic-gate 	 */
1610fa9e4066Sahrens 	(void) prom_nextnode((pnode_t)0);
16117c478bd9Sstevel@tonic-gate #endif
16127c478bd9Sstevel@tonic-gate 
16137c478bd9Sstevel@tonic-gate 	/*
16147c478bd9Sstevel@tonic-gate 	 * Initialize devices on the machine.
16157c478bd9Sstevel@tonic-gate 	 * Uses configuration tree built by the PROMs to determine what
16167c478bd9Sstevel@tonic-gate 	 * is present, and builds a tree of prototype dev_info nodes
16177c478bd9Sstevel@tonic-gate 	 * corresponding to the hardware which identified itself.
16187c478bd9Sstevel@tonic-gate 	 */
16197c478bd9Sstevel@tonic-gate 	i_ddi_init_root();
16207c478bd9Sstevel@tonic-gate 
16217c478bd9Sstevel@tonic-gate #ifdef	DDI_PROP_DEBUG
16227c478bd9Sstevel@tonic-gate 	(void) ddi_prop_debug(1);	/* Enable property debugging */
16237c478bd9Sstevel@tonic-gate #endif	/* DDI_PROP_DEBUG */
16247c478bd9Sstevel@tonic-gate }
16257c478bd9Sstevel@tonic-gate 
16267c478bd9Sstevel@tonic-gate /*
16277c478bd9Sstevel@tonic-gate  * The "status" property indicates the operational status of a device.
16287c478bd9Sstevel@tonic-gate  * If this property is present, the value is a string indicating the
16297c478bd9Sstevel@tonic-gate  * status of the device as follows:
16307c478bd9Sstevel@tonic-gate  *
16317c478bd9Sstevel@tonic-gate  *	"okay"		operational.
16327c478bd9Sstevel@tonic-gate  *	"disabled"	not operational, but might become operational.
16337c478bd9Sstevel@tonic-gate  *	"fail"		not operational because a fault has been detected,
16347c478bd9Sstevel@tonic-gate  *			and it is unlikely that the device will become
16357c478bd9Sstevel@tonic-gate  *			operational without repair. no additional details
16367c478bd9Sstevel@tonic-gate  *			are available.
16377c478bd9Sstevel@tonic-gate  *	"fail-xxx"	not operational because a fault has been detected,
16387c478bd9Sstevel@tonic-gate  *			and it is unlikely that the device will become
16397c478bd9Sstevel@tonic-gate  *			operational without repair. "xxx" is additional
16407c478bd9Sstevel@tonic-gate  *			human-readable information about the particular
16417c478bd9Sstevel@tonic-gate  *			fault condition that was detected.
16427c478bd9Sstevel@tonic-gate  *
16437c478bd9Sstevel@tonic-gate  * The absence of this property means that the operational status is
16447c478bd9Sstevel@tonic-gate  * unknown or okay.
16457c478bd9Sstevel@tonic-gate  *
16467c478bd9Sstevel@tonic-gate  * This routine checks the status property of the specified device node
16477c478bd9Sstevel@tonic-gate  * and returns 0 if the operational status indicates failure, and 1 otherwise.
16487c478bd9Sstevel@tonic-gate  *
16497c478bd9Sstevel@tonic-gate  * The property may exist on plug-in cards the existed before IEEE 1275-1994.
16507c478bd9Sstevel@tonic-gate  * And, in that case, the property may not even be a string. So we carefully
16517c478bd9Sstevel@tonic-gate  * check for the value "fail", in the beginning of the string, noting
16527c478bd9Sstevel@tonic-gate  * the property length.
16537c478bd9Sstevel@tonic-gate  */
16547c478bd9Sstevel@tonic-gate int
status_okay(int id,char * buf,int buflen)16557c478bd9Sstevel@tonic-gate status_okay(int id, char *buf, int buflen)
16567c478bd9Sstevel@tonic-gate {
16577c478bd9Sstevel@tonic-gate 	char status_buf[OBP_MAXPROPNAME];
16587c478bd9Sstevel@tonic-gate 	char *bufp = buf;
16597c478bd9Sstevel@tonic-gate 	int len = buflen;
16607c478bd9Sstevel@tonic-gate 	int proplen;
16617c478bd9Sstevel@tonic-gate 	static const char *status = "status";
16627c478bd9Sstevel@tonic-gate 	static const char *fail = "fail";
16637c478bd9Sstevel@tonic-gate 	size_t fail_len = strlen(fail);
16647c478bd9Sstevel@tonic-gate 
16657c478bd9Sstevel@tonic-gate 	/*
16667c478bd9Sstevel@tonic-gate 	 * Get the proplen ... if it's smaller than "fail",
16677c478bd9Sstevel@tonic-gate 	 * or doesn't exist ... then we don't care, since
16687c478bd9Sstevel@tonic-gate 	 * the value can't begin with the char string "fail".
16697c478bd9Sstevel@tonic-gate 	 *
16707c478bd9Sstevel@tonic-gate 	 * NB: proplen, if it's a string, includes the NULL in the
16717c478bd9Sstevel@tonic-gate 	 * the size of the property, and fail_len does not.
16727c478bd9Sstevel@tonic-gate 	 */
1673fa9e4066Sahrens 	proplen = prom_getproplen((pnode_t)id, (caddr_t)status);
16747c478bd9Sstevel@tonic-gate 	if (proplen <= fail_len)	/* nonexistent or uninteresting len */
16757c478bd9Sstevel@tonic-gate 		return (1);
16767c478bd9Sstevel@tonic-gate 
16777c478bd9Sstevel@tonic-gate 	/*
16787c478bd9Sstevel@tonic-gate 	 * if a buffer was provided, use it
16797c478bd9Sstevel@tonic-gate 	 */
16807c478bd9Sstevel@tonic-gate 	if ((buf == (char *)NULL) || (buflen <= 0)) {
16817c478bd9Sstevel@tonic-gate 		bufp = status_buf;
16827c478bd9Sstevel@tonic-gate 		len = sizeof (status_buf);
16837c478bd9Sstevel@tonic-gate 	}
16847c478bd9Sstevel@tonic-gate 	*bufp = (char)0;
16857c478bd9Sstevel@tonic-gate 
16867c478bd9Sstevel@tonic-gate 	/*
16877c478bd9Sstevel@tonic-gate 	 * Get the property into the buffer, to the extent of the buffer,
16887c478bd9Sstevel@tonic-gate 	 * and in case the buffer is smaller than the property size,
16897c478bd9Sstevel@tonic-gate 	 * NULL terminate the buffer. (This handles the case where
16907c478bd9Sstevel@tonic-gate 	 * a buffer was passed in and the caller wants to print the
16917c478bd9Sstevel@tonic-gate 	 * value, but the buffer was too small).
16927c478bd9Sstevel@tonic-gate 	 */
1693fa9e4066Sahrens 	(void) prom_bounded_getprop((pnode_t)id, (caddr_t)status,
16947c478bd9Sstevel@tonic-gate 	    (caddr_t)bufp, len);
16957c478bd9Sstevel@tonic-gate 	*(bufp + len - 1) = (char)0;
16967c478bd9Sstevel@tonic-gate 
16977c478bd9Sstevel@tonic-gate 	/*
16987c478bd9Sstevel@tonic-gate 	 * If the value begins with the char string "fail",
16997c478bd9Sstevel@tonic-gate 	 * then it means the node is failed. We don't care
17007c478bd9Sstevel@tonic-gate 	 * about any other values. We assume the node is ok
17017c478bd9Sstevel@tonic-gate 	 * although it might be 'disabled'.
17027c478bd9Sstevel@tonic-gate 	 */
17037c478bd9Sstevel@tonic-gate 	if (strncmp(bufp, fail, fail_len) == 0)
17047c478bd9Sstevel@tonic-gate 		return (0);
17057c478bd9Sstevel@tonic-gate 
17067c478bd9Sstevel@tonic-gate 	return (1);
17077c478bd9Sstevel@tonic-gate }
17087c478bd9Sstevel@tonic-gate 
17097c478bd9Sstevel@tonic-gate 
17107c478bd9Sstevel@tonic-gate /*
17117c478bd9Sstevel@tonic-gate  * We set the cpu type from the idprom, if we can.
17127c478bd9Sstevel@tonic-gate  * Note that we just read out the contents of it, for the most part.
17137c478bd9Sstevel@tonic-gate  */
17147c478bd9Sstevel@tonic-gate void
setcputype(void)17157c478bd9Sstevel@tonic-gate setcputype(void)
17167c478bd9Sstevel@tonic-gate {
17177c478bd9Sstevel@tonic-gate 	/*
17187c478bd9Sstevel@tonic-gate 	 * We cache the idprom info early on so that we don't
17197c478bd9Sstevel@tonic-gate 	 * rummage through the NVRAM unnecessarily later.
17207c478bd9Sstevel@tonic-gate 	 */
17217c478bd9Sstevel@tonic-gate 	(void) prom_getidprom((caddr_t)&idprom, sizeof (idprom));
17227c478bd9Sstevel@tonic-gate }
17237c478bd9Sstevel@tonic-gate 
17247c478bd9Sstevel@tonic-gate /*
17257c478bd9Sstevel@tonic-gate  *  Here is where we actually infer meanings to the members of idprom_t
17267c478bd9Sstevel@tonic-gate  */
17277c478bd9Sstevel@tonic-gate void
parse_idprom(void)17287c478bd9Sstevel@tonic-gate parse_idprom(void)
17297c478bd9Sstevel@tonic-gate {
17307c478bd9Sstevel@tonic-gate 	if (idprom.id_format == IDFORM_1) {
17317c478bd9Sstevel@tonic-gate 		(void) localetheraddr((struct ether_addr *)idprom.id_ether,
17327c478bd9Sstevel@tonic-gate 		    (struct ether_addr *)NULL);
17335679c89fSjv227347 		(void) snprintf(hw_serial, HW_HOSTID_LEN, "%u",
17345679c89fSjv227347 		    (idprom.id_machine << 24) + idprom.id_serial);
17357c478bd9Sstevel@tonic-gate 	} else
17367c478bd9Sstevel@tonic-gate 		prom_printf("Invalid format code in IDprom.\n");
17377c478bd9Sstevel@tonic-gate }
17387c478bd9Sstevel@tonic-gate 
17397c478bd9Sstevel@tonic-gate /*
17407c478bd9Sstevel@tonic-gate  * Allow for implementation specific correction of PROM property values.
17417c478bd9Sstevel@tonic-gate  */
17427c478bd9Sstevel@tonic-gate /*ARGSUSED*/
17437c478bd9Sstevel@tonic-gate void
impl_fix_props(dev_info_t * dip,dev_info_t * ch_dip,char * name,int len,caddr_t buffer)17447c478bd9Sstevel@tonic-gate impl_fix_props(dev_info_t *dip, dev_info_t *ch_dip, char *name, int len,
17457c478bd9Sstevel@tonic-gate     caddr_t buffer)
17467c478bd9Sstevel@tonic-gate {
17477c478bd9Sstevel@tonic-gate 	/*
17487c478bd9Sstevel@tonic-gate 	 * There are no adjustments needed in this implementation.
17497c478bd9Sstevel@tonic-gate 	 */
17507c478bd9Sstevel@tonic-gate }
17517c478bd9Sstevel@tonic-gate 
17527c478bd9Sstevel@tonic-gate /*
17537c478bd9Sstevel@tonic-gate  * The following functions ready a cautious request to go up to the nexus
17547c478bd9Sstevel@tonic-gate  * driver.  It is up to the nexus driver to decide how to process the request.
17557c478bd9Sstevel@tonic-gate  * It may choose to call i_ddi_do_caut_get/put in this file, or do it
17567c478bd9Sstevel@tonic-gate  * differently.
17577c478bd9Sstevel@tonic-gate  */
17587c478bd9Sstevel@tonic-gate 
17597c478bd9Sstevel@tonic-gate static void
i_ddi_caut_getput_ctlops(ddi_acc_impl_t * hp,uint64_t host_addr,uint64_t dev_addr,size_t size,size_t repcount,uint_t flags,ddi_ctl_enum_t cmd)17607c478bd9Sstevel@tonic-gate i_ddi_caut_getput_ctlops(
17617c478bd9Sstevel@tonic-gate     ddi_acc_impl_t *hp, uint64_t host_addr, uint64_t dev_addr, size_t size,
17627c478bd9Sstevel@tonic-gate     size_t repcount, uint_t flags, ddi_ctl_enum_t cmd)
17637c478bd9Sstevel@tonic-gate {
17647c478bd9Sstevel@tonic-gate 	peekpoke_ctlops_t	cautacc_ctlops_arg;
17657c478bd9Sstevel@tonic-gate 
17667c478bd9Sstevel@tonic-gate 	cautacc_ctlops_arg.size = size;
17677c478bd9Sstevel@tonic-gate 	cautacc_ctlops_arg.dev_addr = dev_addr;
17687c478bd9Sstevel@tonic-gate 	cautacc_ctlops_arg.host_addr = host_addr;
17697c478bd9Sstevel@tonic-gate 	cautacc_ctlops_arg.handle = (ddi_acc_handle_t)hp;
17707c478bd9Sstevel@tonic-gate 	cautacc_ctlops_arg.repcount = repcount;
17717c478bd9Sstevel@tonic-gate 	cautacc_ctlops_arg.flags = flags;
17727c478bd9Sstevel@tonic-gate 
17737c478bd9Sstevel@tonic-gate 	(void) ddi_ctlops(hp->ahi_common.ah_dip, hp->ahi_common.ah_dip, cmd,
17747c478bd9Sstevel@tonic-gate 	    &cautacc_ctlops_arg, NULL);
17757c478bd9Sstevel@tonic-gate }
17767c478bd9Sstevel@tonic-gate 
17777c478bd9Sstevel@tonic-gate uint8_t
i_ddi_caut_get8(ddi_acc_impl_t * hp,uint8_t * addr)17787c478bd9Sstevel@tonic-gate i_ddi_caut_get8(ddi_acc_impl_t *hp, uint8_t *addr)
17797c478bd9Sstevel@tonic-gate {
17807c478bd9Sstevel@tonic-gate 	uint8_t value;
17817c478bd9Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr,
17827c478bd9Sstevel@tonic-gate 	    sizeof (uint8_t), 1, 0, DDI_CTLOPS_PEEK);
17837c478bd9Sstevel@tonic-gate 
17847c478bd9Sstevel@tonic-gate 	return (value);
17857c478bd9Sstevel@tonic-gate }
17867c478bd9Sstevel@tonic-gate 
17877c478bd9Sstevel@tonic-gate uint16_t
i_ddi_caut_get16(ddi_acc_impl_t * hp,uint16_t * addr)17887c478bd9Sstevel@tonic-gate i_ddi_caut_get16(ddi_acc_impl_t *hp, uint16_t *addr)
17897c478bd9Sstevel@tonic-gate {
17907c478bd9Sstevel@tonic-gate 	uint16_t value;
17917c478bd9Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr,
17927c478bd9Sstevel@tonic-gate 	    sizeof (uint16_t), 1, 0, DDI_CTLOPS_PEEK);
17937c478bd9Sstevel@tonic-gate 
17947c478bd9Sstevel@tonic-gate 	return (value);
17957c478bd9Sstevel@tonic-gate }
17967c478bd9Sstevel@tonic-gate 
17977c478bd9Sstevel@tonic-gate uint32_t
i_ddi_caut_get32(ddi_acc_impl_t * hp,uint32_t * addr)17987c478bd9Sstevel@tonic-gate i_ddi_caut_get32(ddi_acc_impl_t *hp, uint32_t *addr)
17997c478bd9Sstevel@tonic-gate {
18007c478bd9Sstevel@tonic-gate 	uint32_t value;
18017c478bd9Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr,
18027c478bd9Sstevel@tonic-gate 	    sizeof (uint32_t), 1, 0, DDI_CTLOPS_PEEK);
18037c478bd9Sstevel@tonic-gate 
18047c478bd9Sstevel@tonic-gate 	return (value);
18057c478bd9Sstevel@tonic-gate }
18067c478bd9Sstevel@tonic-gate 
18077c478bd9Sstevel@tonic-gate uint64_t
i_ddi_caut_get64(ddi_acc_impl_t * hp,uint64_t * addr)18087c478bd9Sstevel@tonic-gate i_ddi_caut_get64(ddi_acc_impl_t *hp, uint64_t *addr)
18097c478bd9Sstevel@tonic-gate {
18107c478bd9Sstevel@tonic-gate 	uint64_t value;
18117c478bd9Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr,
18127c478bd9Sstevel@tonic-gate 	    sizeof (uint64_t), 1, 0, DDI_CTLOPS_PEEK);
18137c478bd9Sstevel@tonic-gate 
18147c478bd9Sstevel@tonic-gate 	return (value);
18157c478bd9Sstevel@tonic-gate }
18167c478bd9Sstevel@tonic-gate 
18177c478bd9Sstevel@tonic-gate void
i_ddi_caut_put8(ddi_acc_impl_t * hp,uint8_t * addr,uint8_t value)18187c478bd9Sstevel@tonic-gate i_ddi_caut_put8(ddi_acc_impl_t *hp, uint8_t *addr, uint8_t value)
18197c478bd9Sstevel@tonic-gate {
18207c478bd9Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr,
18217c478bd9Sstevel@tonic-gate 	    sizeof (uint8_t), 1, 0, DDI_CTLOPS_POKE);
18227c478bd9Sstevel@tonic-gate }
18237c478bd9Sstevel@tonic-gate 
18247c478bd9Sstevel@tonic-gate void
i_ddi_caut_put16(ddi_acc_impl_t * hp,uint16_t * addr,uint16_t value)18257c478bd9Sstevel@tonic-gate i_ddi_caut_put16(ddi_acc_impl_t *hp, uint16_t *addr, uint16_t value)
18267c478bd9Sstevel@tonic-gate {
18277c478bd9Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr,
18287c478bd9Sstevel@tonic-gate 	    sizeof (uint16_t), 1, 0, DDI_CTLOPS_POKE);
18297c478bd9Sstevel@tonic-gate }
18307c478bd9Sstevel@tonic-gate 
18317c478bd9Sstevel@tonic-gate void
i_ddi_caut_put32(ddi_acc_impl_t * hp,uint32_t * addr,uint32_t value)18327c478bd9Sstevel@tonic-gate i_ddi_caut_put32(ddi_acc_impl_t *hp, uint32_t *addr, uint32_t value)
18337c478bd9Sstevel@tonic-gate {
18347c478bd9Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr,
18357c478bd9Sstevel@tonic-gate 	    sizeof (uint32_t), 1, 0, DDI_CTLOPS_POKE);
18367c478bd9Sstevel@tonic-gate }
18377c478bd9Sstevel@tonic-gate 
18387c478bd9Sstevel@tonic-gate void
i_ddi_caut_put64(ddi_acc_impl_t * hp,uint64_t * addr,uint64_t value)18397c478bd9Sstevel@tonic-gate i_ddi_caut_put64(ddi_acc_impl_t *hp, uint64_t *addr, uint64_t value)
18407c478bd9Sstevel@tonic-gate {
18417c478bd9Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr,
18427c478bd9Sstevel@tonic-gate 	    sizeof (uint64_t), 1, 0, DDI_CTLOPS_POKE);
18437c478bd9Sstevel@tonic-gate }
18447c478bd9Sstevel@tonic-gate 
18457c478bd9Sstevel@tonic-gate void
i_ddi_caut_rep_get8(ddi_acc_impl_t * hp,uint8_t * host_addr,uint8_t * dev_addr,size_t repcount,uint_t flags)18467c478bd9Sstevel@tonic-gate i_ddi_caut_rep_get8(ddi_acc_impl_t *hp, uint8_t *host_addr, uint8_t *dev_addr,
18477c478bd9Sstevel@tonic-gate 	size_t repcount, uint_t flags)
18487c478bd9Sstevel@tonic-gate {
18497c478bd9Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr,
18507c478bd9Sstevel@tonic-gate 	    sizeof (uint8_t), repcount, flags, DDI_CTLOPS_PEEK);
18517c478bd9Sstevel@tonic-gate }
18527c478bd9Sstevel@tonic-gate 
18537c478bd9Sstevel@tonic-gate void
i_ddi_caut_rep_get16(ddi_acc_impl_t * hp,uint16_t * host_addr,uint16_t * dev_addr,size_t repcount,uint_t flags)18547c478bd9Sstevel@tonic-gate i_ddi_caut_rep_get16(ddi_acc_impl_t *hp, uint16_t *host_addr,
18557c478bd9Sstevel@tonic-gate     uint16_t *dev_addr, size_t repcount, uint_t flags)
18567c478bd9Sstevel@tonic-gate {
18577c478bd9Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr,
18587c478bd9Sstevel@tonic-gate 	    sizeof (uint16_t), repcount, flags, DDI_CTLOPS_PEEK);
18597c478bd9Sstevel@tonic-gate }
18607c478bd9Sstevel@tonic-gate 
18617c478bd9Sstevel@tonic-gate void
i_ddi_caut_rep_get32(ddi_acc_impl_t * hp,uint32_t * host_addr,uint32_t * dev_addr,size_t repcount,uint_t flags)18627c478bd9Sstevel@tonic-gate i_ddi_caut_rep_get32(ddi_acc_impl_t *hp, uint32_t *host_addr,
18637c478bd9Sstevel@tonic-gate     uint32_t *dev_addr, size_t repcount, uint_t flags)
18647c478bd9Sstevel@tonic-gate {
18657c478bd9Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr,
18667c478bd9Sstevel@tonic-gate 	    sizeof (uint32_t), repcount, flags, DDI_CTLOPS_PEEK);
18677c478bd9Sstevel@tonic-gate }
18687c478bd9Sstevel@tonic-gate 
18697c478bd9Sstevel@tonic-gate void
i_ddi_caut_rep_get64(ddi_acc_impl_t * hp,uint64_t * host_addr,uint64_t * dev_addr,size_t repcount,uint_t flags)18707c478bd9Sstevel@tonic-gate i_ddi_caut_rep_get64(ddi_acc_impl_t *hp, uint64_t *host_addr,
18717c478bd9Sstevel@tonic-gate     uint64_t *dev_addr, size_t repcount, uint_t flags)
18727c478bd9Sstevel@tonic-gate {
18737c478bd9Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr,
18747c478bd9Sstevel@tonic-gate 	    sizeof (uint64_t), repcount, flags, DDI_CTLOPS_PEEK);
18757c478bd9Sstevel@tonic-gate }
18767c478bd9Sstevel@tonic-gate 
18777c478bd9Sstevel@tonic-gate void
i_ddi_caut_rep_put8(ddi_acc_impl_t * hp,uint8_t * host_addr,uint8_t * dev_addr,size_t repcount,uint_t flags)18787c478bd9Sstevel@tonic-gate i_ddi_caut_rep_put8(ddi_acc_impl_t *hp, uint8_t *host_addr, uint8_t *dev_addr,
18797c478bd9Sstevel@tonic-gate 	size_t repcount, uint_t flags)
18807c478bd9Sstevel@tonic-gate {
18817c478bd9Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr,
18827c478bd9Sstevel@tonic-gate 	    sizeof (uint8_t), repcount, flags, DDI_CTLOPS_POKE);
18837c478bd9Sstevel@tonic-gate }
18847c478bd9Sstevel@tonic-gate 
18857c478bd9Sstevel@tonic-gate void
i_ddi_caut_rep_put16(ddi_acc_impl_t * hp,uint16_t * host_addr,uint16_t * dev_addr,size_t repcount,uint_t flags)18867c478bd9Sstevel@tonic-gate i_ddi_caut_rep_put16(ddi_acc_impl_t *hp, uint16_t *host_addr,
18877c478bd9Sstevel@tonic-gate     uint16_t *dev_addr, size_t repcount, uint_t flags)
18887c478bd9Sstevel@tonic-gate {
18897c478bd9Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr,
18907c478bd9Sstevel@tonic-gate 	    sizeof (uint16_t), repcount, flags, DDI_CTLOPS_POKE);
18917c478bd9Sstevel@tonic-gate }
18927c478bd9Sstevel@tonic-gate 
18937c478bd9Sstevel@tonic-gate void
i_ddi_caut_rep_put32(ddi_acc_impl_t * hp,uint32_t * host_addr,uint32_t * dev_addr,size_t repcount,uint_t flags)18947c478bd9Sstevel@tonic-gate i_ddi_caut_rep_put32(ddi_acc_impl_t *hp, uint32_t *host_addr,
18957c478bd9Sstevel@tonic-gate     uint32_t *dev_addr, size_t repcount, uint_t flags)
18967c478bd9Sstevel@tonic-gate {
18977c478bd9Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr,
18987c478bd9Sstevel@tonic-gate 	    sizeof (uint32_t), repcount, flags, DDI_CTLOPS_POKE);
18997c478bd9Sstevel@tonic-gate }
19007c478bd9Sstevel@tonic-gate 
19017c478bd9Sstevel@tonic-gate void
i_ddi_caut_rep_put64(ddi_acc_impl_t * hp,uint64_t * host_addr,uint64_t * dev_addr,size_t repcount,uint_t flags)19027c478bd9Sstevel@tonic-gate i_ddi_caut_rep_put64(ddi_acc_impl_t *hp, uint64_t *host_addr,
19037c478bd9Sstevel@tonic-gate     uint64_t *dev_addr, size_t repcount, uint_t flags)
19047c478bd9Sstevel@tonic-gate {
19057c478bd9Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr,
19067c478bd9Sstevel@tonic-gate 	    sizeof (uint64_t), repcount, flags, DDI_CTLOPS_POKE);
19077c478bd9Sstevel@tonic-gate }
19087c478bd9Sstevel@tonic-gate 
19097c478bd9Sstevel@tonic-gate /*
19107c478bd9Sstevel@tonic-gate  * This is called only to process peek/poke when the DIP is NULL.
19117c478bd9Sstevel@tonic-gate  * Assume that this is for memory, as nexi take care of device safe accesses.
19127c478bd9Sstevel@tonic-gate  */
19137c478bd9Sstevel@tonic-gate int
peekpoke_mem(ddi_ctl_enum_t cmd,peekpoke_ctlops_t * in_args)19147c478bd9Sstevel@tonic-gate peekpoke_mem(ddi_ctl_enum_t cmd, peekpoke_ctlops_t *in_args)
19157c478bd9Sstevel@tonic-gate {
19167c478bd9Sstevel@tonic-gate 	int err = DDI_SUCCESS;
19177c478bd9Sstevel@tonic-gate 	on_trap_data_t otd;
19187c478bd9Sstevel@tonic-gate 
19197c478bd9Sstevel@tonic-gate 	/* Set up protected environment. */
19207c478bd9Sstevel@tonic-gate 	if (!on_trap(&otd, OT_DATA_ACCESS)) {
19217c478bd9Sstevel@tonic-gate 		uintptr_t tramp = otd.ot_trampoline;
19227c478bd9Sstevel@tonic-gate 
19237c478bd9Sstevel@tonic-gate 		if (cmd == DDI_CTLOPS_POKE) {
19247c478bd9Sstevel@tonic-gate 			otd.ot_trampoline = (uintptr_t)&poke_fault;
19257c478bd9Sstevel@tonic-gate 			err = do_poke(in_args->size, (void *)in_args->dev_addr,
19267c478bd9Sstevel@tonic-gate 			    (void *)in_args->host_addr);
19277c478bd9Sstevel@tonic-gate 		} else {
19287c478bd9Sstevel@tonic-gate 			otd.ot_trampoline = (uintptr_t)&peek_fault;
19297c478bd9Sstevel@tonic-gate 			err = do_peek(in_args->size, (void *)in_args->dev_addr,
19307c478bd9Sstevel@tonic-gate 			    (void *)in_args->host_addr);
19317c478bd9Sstevel@tonic-gate 		}
19327c478bd9Sstevel@tonic-gate 		otd.ot_trampoline = tramp;
19337c478bd9Sstevel@tonic-gate 	} else
19347c478bd9Sstevel@tonic-gate 		err = DDI_FAILURE;
19357c478bd9Sstevel@tonic-gate 
19367c478bd9Sstevel@tonic-gate 	/* Take down protected environment. */
19377c478bd9Sstevel@tonic-gate 	no_trap();
19387c478bd9Sstevel@tonic-gate 
19397c478bd9Sstevel@tonic-gate 	return (err);
19407c478bd9Sstevel@tonic-gate }
1941