xref: /illumos-gate/usr/src/uts/sun4/os/ddi_impl.c (revision 48bbca81)
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 /*
235679c89fSjv  * 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>
28*48bbca81SDaniel Hoffman  * Copyright (c) 2016 by Delphix. All rights reserved.
29cd21e7c5SGarrett D'Amore  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate /*
327c478bd9Sstevel@tonic-gate  * sun4 specific DDI implementation
337c478bd9Sstevel@tonic-gate  */
347c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
357c478bd9Sstevel@tonic-gate #include <sys/ddi_subrdefs.h>
367c478bd9Sstevel@tonic-gate #include <sys/machsystm.h>
377c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
387c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
397c478bd9Sstevel@tonic-gate #include <sys/ontrap.h>
407c478bd9Sstevel@tonic-gate #include <vm/seg_kmem.h>
417c478bd9Sstevel@tonic-gate #include <sys/membar.h>
427c478bd9Sstevel@tonic-gate #include <sys/dditypes.h>
437c478bd9Sstevel@tonic-gate #include <sys/ndifm.h>
447c478bd9Sstevel@tonic-gate #include <sys/fm/io/ddi.h>
457c478bd9Sstevel@tonic-gate #include <sys/ivintr.h>
467c478bd9Sstevel@tonic-gate #include <sys/bootconf.h>
477c478bd9Sstevel@tonic-gate #include <sys/conf.h>
487c478bd9Sstevel@tonic-gate #include <sys/ethernet.h>
497c478bd9Sstevel@tonic-gate #include <sys/idprom.h>
507c478bd9Sstevel@tonic-gate #include <sys/promif.h>
517c478bd9Sstevel@tonic-gate #include <sys/prom_plat.h>
527c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h>
537c478bd9Sstevel@tonic-gate #include <sys/fpu/fpusystm.h>
547c478bd9Sstevel@tonic-gate #include <sys/vm.h>
557c478bd9Sstevel@tonic-gate #include <sys/ddi_isa.h>
5625e8c5aaSvikram #include <sys/modctl.h>
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate dev_info_t *get_intr_parent(dev_info_t *, dev_info_t *,
59a195726fSgovinda     ddi_intr_handle_impl_t *);
607c478bd9Sstevel@tonic-gate #pragma weak get_intr_parent
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate int process_intr_ops(dev_info_t *, dev_info_t *, ddi_intr_op_t,
637c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *, void *);
647c478bd9Sstevel@tonic-gate #pragma weak process_intr_ops
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate void cells_1275_copy(prop_1275_cell_t *, prop_1275_cell_t *, int32_t);
677c478bd9Sstevel@tonic-gate     prop_1275_cell_t *cells_1275_cmp(prop_1275_cell_t *, prop_1275_cell_t *,
687c478bd9Sstevel@tonic-gate     int32_t len);
697c478bd9Sstevel@tonic-gate #pragma weak cells_1275_copy
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate /*
727c478bd9Sstevel@tonic-gate  * Wrapper for ddi_prop_lookup_int_array().
737c478bd9Sstevel@tonic-gate  * This is handy because it returns the prop length in
747c478bd9Sstevel@tonic-gate  * bytes which is what most of the callers require.
757c478bd9Sstevel@tonic-gate  */
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate static int
get_prop_int_array(dev_info_t * di,char * pname,int ** pval,uint_t * plen)787c478bd9Sstevel@tonic-gate get_prop_int_array(dev_info_t *di, char *pname, int **pval, uint_t *plen)
797c478bd9Sstevel@tonic-gate {
807c478bd9Sstevel@tonic-gate 	int ret;
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 	if ((ret = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, di,
837c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, pname, pval, plen)) == DDI_PROP_SUCCESS) {
847c478bd9Sstevel@tonic-gate 		*plen = (*plen) * (uint_t)sizeof (int);
857c478bd9Sstevel@tonic-gate 	}
867c478bd9Sstevel@tonic-gate 	return (ret);
877c478bd9Sstevel@tonic-gate }
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate /*
907c478bd9Sstevel@tonic-gate  * SECTION: DDI Node Configuration
917c478bd9Sstevel@tonic-gate  */
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate /*
947c478bd9Sstevel@tonic-gate  * init_regspec_64:
957c478bd9Sstevel@tonic-gate  *
967c478bd9Sstevel@tonic-gate  * If the parent #size-cells is 2, convert the upa-style or
977c478bd9Sstevel@tonic-gate  * safari-style reg property from 2-size cells to 1 size cell
987c478bd9Sstevel@tonic-gate  * format, ignoring the size_hi, which must be zero for devices.
997c478bd9Sstevel@tonic-gate  * (It won't be zero in the memory list properties in the memory
1007c478bd9Sstevel@tonic-gate  * nodes, but that doesn't matter here.)
1017c478bd9Sstevel@tonic-gate  */
1027c478bd9Sstevel@tonic-gate struct ddi_parent_private_data *
init_regspec_64(dev_info_t * dip)1037c478bd9Sstevel@tonic-gate init_regspec_64(dev_info_t *dip)
1047c478bd9Sstevel@tonic-gate {
1057c478bd9Sstevel@tonic-gate 	struct ddi_parent_private_data *pd;
1067c478bd9Sstevel@tonic-gate 	dev_info_t *parent;
1077c478bd9Sstevel@tonic-gate 	int size_cells;
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate 	/*
1107c478bd9Sstevel@tonic-gate 	 * If there are no "reg"s in the child node, return.
1117c478bd9Sstevel@tonic-gate 	 */
1127c478bd9Sstevel@tonic-gate 	pd = ddi_get_parent_data(dip);
1137c478bd9Sstevel@tonic-gate 	if ((pd == NULL) || (pd->par_nreg == 0)) {
1147c478bd9Sstevel@tonic-gate 		return (pd);
1157c478bd9Sstevel@tonic-gate 	}
1167c478bd9Sstevel@tonic-gate 	parent = ddi_get_parent(dip);
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate 	size_cells = ddi_prop_get_int(DDI_DEV_T_ANY, parent,
1197c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "#size-cells", 1);
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate 	if (size_cells != 1)  {
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 		int n, j;
1247c478bd9Sstevel@tonic-gate 		struct regspec *irp;
1257c478bd9Sstevel@tonic-gate 		struct reg_64 {
1267c478bd9Sstevel@tonic-gate 			uint_t addr_hi, addr_lo, size_hi, size_lo;
1277c478bd9Sstevel@tonic-gate 		};
1287c478bd9Sstevel@tonic-gate 		struct reg_64 *r64_rp;
1297c478bd9Sstevel@tonic-gate 		struct regspec *rp;
1307c478bd9Sstevel@tonic-gate 		uint_t len = 0;
1317c478bd9Sstevel@tonic-gate 		int *reg_prop;
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 		ASSERT(size_cells == 2);
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 		/*
1367c478bd9Sstevel@tonic-gate 		 * We already looked the property up once before if
1377c478bd9Sstevel@tonic-gate 		 * pd is non-NULL.
1387c478bd9Sstevel@tonic-gate 		 */
1397c478bd9Sstevel@tonic-gate 		(void) ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
1407c478bd9Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, OBP_REG, &reg_prop, &len);
1417c478bd9Sstevel@tonic-gate 		ASSERT(len != 0);
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate 		n = sizeof (struct reg_64) / sizeof (int);
1447c478bd9Sstevel@tonic-gate 		n = len / n;
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 		/*
1477c478bd9Sstevel@tonic-gate 		 * We're allocating a buffer the size of the PROM's property,
1487c478bd9Sstevel@tonic-gate 		 * but we're only using a smaller portion when we assign it
1497c478bd9Sstevel@tonic-gate 		 * to a regspec.  We do this so that in the
1507c478bd9Sstevel@tonic-gate 		 * impl_ddi_sunbus_removechild function, we will
1517c478bd9Sstevel@tonic-gate 		 * always free the right amount of memory.
1527c478bd9Sstevel@tonic-gate 		 */
1537c478bd9Sstevel@tonic-gate 		irp = rp = (struct regspec *)reg_prop;
1547c478bd9Sstevel@tonic-gate 		r64_rp = (struct reg_64 *)pd->par_reg;
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 		for (j = 0; j < n; ++j, ++rp, ++r64_rp) {
1577c478bd9Sstevel@tonic-gate 			ASSERT(r64_rp->size_hi == 0);
1587c478bd9Sstevel@tonic-gate 			rp->regspec_bustype = r64_rp->addr_hi;
1597c478bd9Sstevel@tonic-gate 			rp->regspec_addr = r64_rp->addr_lo;
1607c478bd9Sstevel@tonic-gate 			rp->regspec_size = r64_rp->size_lo;
1617c478bd9Sstevel@tonic-gate 		}
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 		ddi_prop_free((void *)pd->par_reg);
1647c478bd9Sstevel@tonic-gate 		pd->par_nreg = n;
1657c478bd9Sstevel@tonic-gate 		pd->par_reg = irp;
1667c478bd9Sstevel@tonic-gate 	}
1677c478bd9Sstevel@tonic-gate 	return (pd);
1687c478bd9Sstevel@tonic-gate }
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate /*
1717c478bd9Sstevel@tonic-gate  * Create a ddi_parent_private_data structure from the ddi properties of
1727c478bd9Sstevel@tonic-gate  * the dev_info node.
1737c478bd9Sstevel@tonic-gate  *
1747c478bd9Sstevel@tonic-gate  * The "reg" is required if the driver wishes to create mappings on behalf
1757c478bd9Sstevel@tonic-gate  * of the device. The "reg" property is assumed to be a list of at least
1767c478bd9Sstevel@tonic-gate  * one triplet
1777c478bd9Sstevel@tonic-gate  *
1787c478bd9Sstevel@tonic-gate  *	<bustype, address, size>*1
1797c478bd9Sstevel@tonic-gate  *
1807c478bd9Sstevel@tonic-gate  * The "interrupt" property is no longer part of parent private data on
1817c478bd9Sstevel@tonic-gate  * sun4u. The interrupt parent is may not be the device tree parent.
1827c478bd9Sstevel@tonic-gate  *
1837c478bd9Sstevel@tonic-gate  * The "ranges" property describes the mapping of child addresses to parent
1847c478bd9Sstevel@tonic-gate  * addresses.
1857c478bd9Sstevel@tonic-gate  *
1867c478bd9Sstevel@tonic-gate  * N.B. struct rangespec is defined for the following default values:
1877c478bd9Sstevel@tonic-gate  *			parent  child
1887c478bd9Sstevel@tonic-gate  *	#address-cells	2	2
1897c478bd9Sstevel@tonic-gate  *	#size-cells	1	1
1907c478bd9Sstevel@tonic-gate  * This function doesn't deal with non-default cells and will not create
1917c478bd9Sstevel@tonic-gate  * ranges in such cases.
1927c478bd9Sstevel@tonic-gate  */
1937c478bd9Sstevel@tonic-gate void
make_ddi_ppd(dev_info_t * child,struct ddi_parent_private_data ** ppd)1947c478bd9Sstevel@tonic-gate make_ddi_ppd(dev_info_t *child, struct ddi_parent_private_data **ppd)
1957c478bd9Sstevel@tonic-gate {
1967c478bd9Sstevel@tonic-gate 	struct ddi_parent_private_data *pdptr;
1977c478bd9Sstevel@tonic-gate 	int *reg_prop, *rng_prop;
1987c478bd9Sstevel@tonic-gate 	uint_t reg_len = 0, rng_len = 0;
1997c478bd9Sstevel@tonic-gate 	dev_info_t *parent;
2007c478bd9Sstevel@tonic-gate 	int parent_addr_cells, parent_size_cells;
2017c478bd9Sstevel@tonic-gate 	int child_addr_cells, child_size_cells;
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 	*ppd = pdptr = kmem_zalloc(sizeof (*pdptr), KM_SLEEP);
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	/*
2067c478bd9Sstevel@tonic-gate 	 * root node has no parent private data, so *ppd should
2077c478bd9Sstevel@tonic-gate 	 * be initialized for naming to work properly.
2087c478bd9Sstevel@tonic-gate 	 */
2097c478bd9Sstevel@tonic-gate 	if ((parent = ddi_get_parent(child)) == NULL)
2107c478bd9Sstevel@tonic-gate 		return;
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	/*
2137c478bd9Sstevel@tonic-gate 	 * Set reg field of parent data from "reg" property
2147c478bd9Sstevel@tonic-gate 	 */
2157c478bd9Sstevel@tonic-gate 	if ((get_prop_int_array(child, OBP_REG, &reg_prop, &reg_len)
2167c478bd9Sstevel@tonic-gate 	    == DDI_PROP_SUCCESS) && (reg_len != 0)) {
2177c478bd9Sstevel@tonic-gate 		pdptr->par_nreg = (int)(reg_len / sizeof (struct regspec));
2187c478bd9Sstevel@tonic-gate 		pdptr->par_reg = (struct regspec *)reg_prop;
2197c478bd9Sstevel@tonic-gate 	}
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	/*
2227c478bd9Sstevel@tonic-gate 	 * "ranges" property ...
2237c478bd9Sstevel@tonic-gate 	 *
2247c478bd9Sstevel@tonic-gate 	 * This function does not handle cases where #address-cells != 2
2257c478bd9Sstevel@tonic-gate 	 * and * min(parent, child) #size-cells != 1 (see bugid 4211124).
2267c478bd9Sstevel@tonic-gate 	 *
2277c478bd9Sstevel@tonic-gate 	 * Nexus drivers with such exceptions (e.g. pci ranges)
2287c478bd9Sstevel@tonic-gate 	 * should either create a separate function for handling
2297c478bd9Sstevel@tonic-gate 	 * ranges or not use parent private data to store ranges.
2307c478bd9Sstevel@tonic-gate 	 */
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 	/* root node has no ranges */
2337c478bd9Sstevel@tonic-gate 	if ((parent = ddi_get_parent(child)) == NULL)
2347c478bd9Sstevel@tonic-gate 		return;
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 	child_addr_cells = ddi_prop_get_int(DDI_DEV_T_ANY, child,
2377c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "#address-cells", 2);
2387c478bd9Sstevel@tonic-gate 	child_size_cells = ddi_prop_get_int(DDI_DEV_T_ANY, child,
2397c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "#size-cells", 1);
2407c478bd9Sstevel@tonic-gate 	parent_addr_cells = ddi_prop_get_int(DDI_DEV_T_ANY, parent,
2417c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "#address-cells", 2);
2427c478bd9Sstevel@tonic-gate 	parent_size_cells = ddi_prop_get_int(DDI_DEV_T_ANY, parent,
2437c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "#size-cells", 1);
2447c478bd9Sstevel@tonic-gate 	if (child_addr_cells != 2 || parent_addr_cells != 2 ||
2457c478bd9Sstevel@tonic-gate 	    (child_size_cells != 1 && parent_size_cells != 1)) {
2467c478bd9Sstevel@tonic-gate 		NDI_CONFIG_DEBUG((CE_NOTE, "!ranges not made in parent data; "
2477c478bd9Sstevel@tonic-gate 		    "#address-cells or #size-cells have non-default value"));
2487c478bd9Sstevel@tonic-gate 		return;
2497c478bd9Sstevel@tonic-gate 	}
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 	if (get_prop_int_array(child, OBP_RANGES, &rng_prop, &rng_len)
2527c478bd9Sstevel@tonic-gate 	    == DDI_PROP_SUCCESS) {
2537c478bd9Sstevel@tonic-gate 		pdptr->par_nrng = rng_len / (int)(sizeof (struct rangespec));
2547c478bd9Sstevel@tonic-gate 		pdptr->par_rng = (struct rangespec *)rng_prop;
2557c478bd9Sstevel@tonic-gate 	}
2567c478bd9Sstevel@tonic-gate }
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate /*
2597c478bd9Sstevel@tonic-gate  * Free ddi_parent_private_data structure
2607c478bd9Sstevel@tonic-gate  */
2617c478bd9Sstevel@tonic-gate void
impl_free_ddi_ppd(dev_info_t * dip)2627c478bd9Sstevel@tonic-gate impl_free_ddi_ppd(dev_info_t *dip)
2637c478bd9Sstevel@tonic-gate {
2647c478bd9Sstevel@tonic-gate 	struct ddi_parent_private_data *pdptr = ddi_get_parent_data(dip);
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 	if (pdptr == NULL)
2677c478bd9Sstevel@tonic-gate 		return;
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 	if (pdptr->par_nrng != 0)
2707c478bd9Sstevel@tonic-gate 		ddi_prop_free((void *)pdptr->par_rng);
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	if (pdptr->par_nreg != 0)
2737c478bd9Sstevel@tonic-gate 		ddi_prop_free((void *)pdptr->par_reg);
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 	kmem_free(pdptr, sizeof (*pdptr));
2767c478bd9Sstevel@tonic-gate 	ddi_set_parent_data(dip, NULL);
2777c478bd9Sstevel@tonic-gate }
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate /*
2807c478bd9Sstevel@tonic-gate  * Name a child of sun busses based on the reg spec.
2817c478bd9Sstevel@tonic-gate  * Handles the following properties:
2827c478bd9Sstevel@tonic-gate  *
2837c478bd9Sstevel@tonic-gate  *	Property	value
2847c478bd9Sstevel@tonic-gate  *	Name		type
2857c478bd9Sstevel@tonic-gate  *
2867c478bd9Sstevel@tonic-gate  *	reg		register spec
2877c478bd9Sstevel@tonic-gate  *	interrupts	new (bus-oriented) interrupt spec
2887c478bd9Sstevel@tonic-gate  *	ranges		range spec
2897c478bd9Sstevel@tonic-gate  *
2907c478bd9Sstevel@tonic-gate  * This may be called multiple times, independent of
2917c478bd9Sstevel@tonic-gate  * initchild calls.
2927c478bd9Sstevel@tonic-gate  */
2937c478bd9Sstevel@tonic-gate static int
impl_sunbus_name_child(dev_info_t * child,char * name,int namelen)2947c478bd9Sstevel@tonic-gate impl_sunbus_name_child(dev_info_t *child, char *name, int namelen)
2957c478bd9Sstevel@tonic-gate {
2967c478bd9Sstevel@tonic-gate 	struct ddi_parent_private_data *pdptr;
2977c478bd9Sstevel@tonic-gate 	struct regspec *rp;
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	/*
3007c478bd9Sstevel@tonic-gate 	 * Fill in parent-private data and this function returns to us
3017c478bd9Sstevel@tonic-gate 	 * an indication if it used "registers" to fill in the data.
3027c478bd9Sstevel@tonic-gate 	 */
3037c478bd9Sstevel@tonic-gate 	if (ddi_get_parent_data(child) == NULL) {
3047c478bd9Sstevel@tonic-gate 		make_ddi_ppd(child, &pdptr);
3057c478bd9Sstevel@tonic-gate 		ddi_set_parent_data(child, pdptr);
3067c478bd9Sstevel@tonic-gate 	}
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 	/*
3097c478bd9Sstevel@tonic-gate 	 * No reg property, return null string as address
3107c478bd9Sstevel@tonic-gate 	 * (e.g. root node)
3117c478bd9Sstevel@tonic-gate 	 */
3127c478bd9Sstevel@tonic-gate 	name[0] = '\0';
3137c478bd9Sstevel@tonic-gate 	if (sparc_pd_getnreg(child) == 0) {
3147c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
3157c478bd9Sstevel@tonic-gate 	}
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	rp = sparc_pd_getreg(child, 0);
3187c478bd9Sstevel@tonic-gate 	(void) snprintf(name, namelen, "%x,%x",
3197c478bd9Sstevel@tonic-gate 	    rp->regspec_bustype, rp->regspec_addr);
3207c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
3217c478bd9Sstevel@tonic-gate }
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate /*
3257c478bd9Sstevel@tonic-gate  * Called from the bus_ctl op of some drivers.
3267c478bd9Sstevel@tonic-gate  * to implement the DDI_CTLOPS_INITCHILD operation.
3277c478bd9Sstevel@tonic-gate  *
3287c478bd9Sstevel@tonic-gate  * NEW drivers should NOT use this function, but should declare
3297c478bd9Sstevel@tonic-gate  * there own initchild/uninitchild handlers. (This function assumes
3307c478bd9Sstevel@tonic-gate  * the layout of the parent private data and the format of "reg",
3317c478bd9Sstevel@tonic-gate  * "ranges", "interrupts" properties and that #address-cells and
3327c478bd9Sstevel@tonic-gate  * #size-cells of the parent bus are defined to be default values.)
3337c478bd9Sstevel@tonic-gate  */
3347c478bd9Sstevel@tonic-gate int
impl_ddi_sunbus_initchild(dev_info_t * child)3357c478bd9Sstevel@tonic-gate impl_ddi_sunbus_initchild(dev_info_t *child)
3367c478bd9Sstevel@tonic-gate {
3377c478bd9Sstevel@tonic-gate 	char name[MAXNAMELEN];
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	(void) impl_sunbus_name_child(child, name, MAXNAMELEN);
3407c478bd9Sstevel@tonic-gate 	ddi_set_name_addr(child, name);
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	/*
3437c478bd9Sstevel@tonic-gate 	 * Try to merge .conf node. If successful, return failure to
3447c478bd9Sstevel@tonic-gate 	 * remove this child.
3457c478bd9Sstevel@tonic-gate 	 */
3467c478bd9Sstevel@tonic-gate 	if ((ndi_dev_is_persistent_node(child) == 0) &&
3477c478bd9Sstevel@tonic-gate 	    (ndi_merge_node(child, impl_sunbus_name_child) == DDI_SUCCESS)) {
3487c478bd9Sstevel@tonic-gate 		impl_ddi_sunbus_removechild(child);
3497c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3507c478bd9Sstevel@tonic-gate 	}
3517c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
3527c478bd9Sstevel@tonic-gate }
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate /*
3557c478bd9Sstevel@tonic-gate  * A better name for this function would be impl_ddi_sunbus_uninitchild()
3567c478bd9Sstevel@tonic-gate  * It does not remove the child, it uninitializes it, reclaiming the
3577c478bd9Sstevel@tonic-gate  * resources taken by impl_ddi_sunbus_initchild.
3587c478bd9Sstevel@tonic-gate  */
3597c478bd9Sstevel@tonic-gate void
impl_ddi_sunbus_removechild(dev_info_t * dip)3607c478bd9Sstevel@tonic-gate impl_ddi_sunbus_removechild(dev_info_t *dip)
3617c478bd9Sstevel@tonic-gate {
3627c478bd9Sstevel@tonic-gate 	impl_free_ddi_ppd(dip);
3637c478bd9Sstevel@tonic-gate 	ddi_set_name_addr(dip, NULL);
3647c478bd9Sstevel@tonic-gate 	/*
3657c478bd9Sstevel@tonic-gate 	 * Strip the node to properly convert it back to prototype form
3667c478bd9Sstevel@tonic-gate 	 */
3677c478bd9Sstevel@tonic-gate 	impl_rem_dev_props(dip);
3687c478bd9Sstevel@tonic-gate }
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate /*
3717c478bd9Sstevel@tonic-gate  * SECTION: DDI Interrupt
3727c478bd9Sstevel@tonic-gate  */
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate void
cells_1275_copy(prop_1275_cell_t * from,prop_1275_cell_t * to,int32_t len)3757c478bd9Sstevel@tonic-gate cells_1275_copy(prop_1275_cell_t *from, prop_1275_cell_t *to, int32_t len)
3767c478bd9Sstevel@tonic-gate {
3777c478bd9Sstevel@tonic-gate 	int i;
3787c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i++)
3797c478bd9Sstevel@tonic-gate 		*to = *from;
3807c478bd9Sstevel@tonic-gate }
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate prop_1275_cell_t *
cells_1275_cmp(prop_1275_cell_t * cell1,prop_1275_cell_t * cell2,int32_t len)3837c478bd9Sstevel@tonic-gate cells_1275_cmp(prop_1275_cell_t *cell1, prop_1275_cell_t *cell2, int32_t len)
3847c478bd9Sstevel@tonic-gate {
3857c478bd9Sstevel@tonic-gate 	prop_1275_cell_t *match_cell = 0;
3867c478bd9Sstevel@tonic-gate 	int32_t i;
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i++)
3897c478bd9Sstevel@tonic-gate 		if (cell1[i] != cell2[i]) {
3907c478bd9Sstevel@tonic-gate 			match_cell = &cell1[i];
3917c478bd9Sstevel@tonic-gate 			break;
3927c478bd9Sstevel@tonic-gate 		}
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	return (match_cell);
3957c478bd9Sstevel@tonic-gate }
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate /*
398a195726fSgovinda  * get_intr_parent() is a generic routine that process a 1275 interrupt
399a195726fSgovinda  * map (imap) property.  This function returns a dev_info_t structure
400a195726fSgovinda  * which claims ownership of the interrupt domain.
401a195726fSgovinda  * It also returns the new interrupt translation within this new domain.
402a195726fSgovinda  * If an interrupt-parent or interrupt-map property are not found,
403a195726fSgovinda  * then we fallback to using the device tree's parent.
404a195726fSgovinda  *
405a195726fSgovinda  * imap entry format:
406a195726fSgovinda  * <reg>,<interrupt>,<phandle>,<translated interrupt>
407a195726fSgovinda  * reg - The register specification in the interrupts domain
408a195726fSgovinda  * interrupt - The interrupt specification
409a195726fSgovinda  * phandle - PROM handle of the device that owns the xlated interrupt domain
410a195726fSgovinda  * translated interrupt - interrupt specifier in the parents domain
411a195726fSgovinda  * note: <reg>,<interrupt> - The reg and interrupt can be combined to create
412a195726fSgovinda  *	a unique entry called a unit interrupt specifier.
413a195726fSgovinda  *
414a195726fSgovinda  * Here's the processing steps:
415a195726fSgovinda  * step1 - If the interrupt-parent property exists, create the ispec and
416a195726fSgovinda  *	return the dip of the interrupt parent.
417a195726fSgovinda  * step2 - Extract the interrupt-map property and the interrupt-map-mask
418a195726fSgovinda  *	If these don't exist, just return the device tree parent.
419a195726fSgovinda  * step3 - build up the unit interrupt specifier to match against the
420a195726fSgovinda  *	interrupt map property
421a195726fSgovinda  * step4 - Scan the interrupt-map property until a match is found
422a195726fSgovinda  * step4a - Extract the interrupt parent
423a195726fSgovinda  * step4b - Compare the unit interrupt specifier
4247c478bd9Sstevel@tonic-gate  */
425a195726fSgovinda dev_info_t *
get_intr_parent(dev_info_t * pdip,dev_info_t * dip,ddi_intr_handle_impl_t * hdlp)426a195726fSgovinda get_intr_parent(dev_info_t *pdip, dev_info_t *dip, ddi_intr_handle_impl_t *hdlp)
4277c478bd9Sstevel@tonic-gate {
428a195726fSgovinda 	prop_1275_cell_t *imap, *imap_mask, *scan, *reg_p, *match_req;
429a195726fSgovinda 	int32_t imap_sz, imap_cells, imap_scan_cells, imap_mask_sz,
430a195726fSgovinda 	    addr_cells, intr_cells, reg_len, i, j;
431a195726fSgovinda 	int32_t match_found = 0;
432a195726fSgovinda 	dev_info_t *intr_parent_dip = NULL;
433a195726fSgovinda 	uint32_t *intr = &hdlp->ih_vector;
434a195726fSgovinda 	uint32_t nodeid;
435a195726fSgovinda #ifdef DEBUG
436a195726fSgovinda 	static int debug = 0;
437a195726fSgovinda #endif
4387c478bd9Sstevel@tonic-gate 
439a195726fSgovinda 	/*
440a195726fSgovinda 	 * step1
441a195726fSgovinda 	 * If we have an interrupt-parent property, this property represents
442a195726fSgovinda 	 * the nodeid of our interrupt parent.
443a195726fSgovinda 	 */
444a195726fSgovinda 	if ((nodeid = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
445a195726fSgovinda 	    "interrupt-parent", -1)) != -1) {
446a195726fSgovinda 		intr_parent_dip = e_ddi_nodeid_to_dip(nodeid);
447a195726fSgovinda 		ASSERT(intr_parent_dip);
4487c478bd9Sstevel@tonic-gate 
449a195726fSgovinda 		/*
450a195726fSgovinda 		 * Attach the interrupt parent.
451a195726fSgovinda 		 *
452a195726fSgovinda 		 * N.B. e_ddi_nodeid_to_dip() isn't safe under DR.
453a195726fSgovinda 		 *	Also, interrupt parent isn't held. This needs
454a195726fSgovinda 		 *	to be revisited if DR-capable platforms implement
455a195726fSgovinda 		 *	interrupt redirection.
456a195726fSgovinda 		 */
457a195726fSgovinda 		if (i_ddi_attach_node_hierarchy(intr_parent_dip)
458a195726fSgovinda 		    != DDI_SUCCESS) {
459a195726fSgovinda 			ndi_rele_devi(intr_parent_dip);
460a195726fSgovinda 			return (NULL);
461a195726fSgovinda 		}
4627c478bd9Sstevel@tonic-gate 
463a195726fSgovinda 		return (intr_parent_dip);
464a195726fSgovinda 	}
4657c478bd9Sstevel@tonic-gate 
466a195726fSgovinda 	/*
467a195726fSgovinda 	 * step2
468a195726fSgovinda 	 * Get interrupt map structure from PROM property
469a195726fSgovinda 	 */
470a195726fSgovinda 	if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
471a195726fSgovinda 	    "interrupt-map", (caddr_t)&imap, &imap_sz)
472a195726fSgovinda 	    != DDI_PROP_SUCCESS) {
473a195726fSgovinda 		/*
474a195726fSgovinda 		 * If we don't have an imap property, default to using the
475a195726fSgovinda 		 * device tree.
476a195726fSgovinda 		 */
4777c478bd9Sstevel@tonic-gate 
478a195726fSgovinda 		ndi_hold_devi(pdip);
479a195726fSgovinda 		return (pdip);
480a195726fSgovinda 	}
4817c478bd9Sstevel@tonic-gate 
482a195726fSgovinda 	/* Get the interrupt mask property */
483a195726fSgovinda 	if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
484a195726fSgovinda 	    "interrupt-map-mask", (caddr_t)&imap_mask, &imap_mask_sz)
485a195726fSgovinda 	    != DDI_PROP_SUCCESS) {
4867c478bd9Sstevel@tonic-gate 		/*
487a195726fSgovinda 		 * If we don't find this property, we have to fail the request
488a195726fSgovinda 		 * because the 1275 imap property wasn't defined correctly.
4897c478bd9Sstevel@tonic-gate 		 */
490a195726fSgovinda 		ASSERT(intr_parent_dip == NULL);
491a195726fSgovinda 		goto exit2;
4927c478bd9Sstevel@tonic-gate 	}
4937c478bd9Sstevel@tonic-gate 
494a195726fSgovinda 	/* Get the address cell size */
495a195726fSgovinda 	addr_cells = ddi_getprop(DDI_DEV_T_ANY, pdip, 0,
496a195726fSgovinda 	    "#address-cells", 2);
4977c478bd9Sstevel@tonic-gate 
498a195726fSgovinda 	/* Get the interrupts cell size */
499a195726fSgovinda 	intr_cells = ddi_getprop(DDI_DEV_T_ANY, pdip, 0,
500a195726fSgovinda 	    "#interrupt-cells", 1);
5017c478bd9Sstevel@tonic-gate 
502a195726fSgovinda 	/*
503a195726fSgovinda 	 * step3
504a195726fSgovinda 	 * Now lets build up the unit interrupt specifier e.g. reg,intr
505a195726fSgovinda 	 * and apply the imap mask.  match_req will hold this when we're
506a195726fSgovinda 	 * through.
507a195726fSgovinda 	 */
508a195726fSgovinda 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
509a195726fSgovinda 	    (caddr_t)&reg_p, &reg_len) != DDI_SUCCESS) {
510a195726fSgovinda 		ASSERT(intr_parent_dip == NULL);
511a195726fSgovinda 		goto exit3;
5127c478bd9Sstevel@tonic-gate 	}
5137c478bd9Sstevel@tonic-gate 
514a195726fSgovinda 	match_req = kmem_alloc(CELLS_1275_TO_BYTES(addr_cells) +
515a195726fSgovinda 	    CELLS_1275_TO_BYTES(intr_cells), KM_SLEEP);
5167c478bd9Sstevel@tonic-gate 
517a195726fSgovinda 	for (i = 0; i < addr_cells; i++)
518a195726fSgovinda 		match_req[i] = (reg_p[i] & imap_mask[i]);
5197c478bd9Sstevel@tonic-gate 
520a195726fSgovinda 	for (j = 0; j < intr_cells; i++, j++)
521a195726fSgovinda 		match_req[i] = (intr[j] & imap_mask[i]);
5227c478bd9Sstevel@tonic-gate 
523a195726fSgovinda 	/* Calculate the imap size in cells */
524a195726fSgovinda 	imap_cells = BYTES_TO_1275_CELLS(imap_sz);
5257c478bd9Sstevel@tonic-gate 
526a195726fSgovinda #ifdef DEBUG
527a195726fSgovinda 	if (debug)
528a195726fSgovinda 		prom_printf("reg cell size 0x%x, intr cell size 0x%x, "
529a195726fSgovinda 		    "match_request 0x%p, imap 0x%p\n", addr_cells, intr_cells,
530903a11ebSrh 		    (void *)match_req, (void *)imap);
531a195726fSgovinda #endif
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 	/*
534a195726fSgovinda 	 * Scan the imap property looking for a match of the interrupt unit
535a195726fSgovinda 	 * specifier.  This loop is rather complex since the data within the
536a195726fSgovinda 	 * imap property may vary in size.
5377c478bd9Sstevel@tonic-gate 	 */
538a195726fSgovinda 	for (scan = imap, imap_scan_cells = i = 0;
539a195726fSgovinda 	    imap_scan_cells < imap_cells; scan += i, imap_scan_cells += i) {
540a195726fSgovinda 		int new_intr_cells;
5417c478bd9Sstevel@tonic-gate 
542a195726fSgovinda 		/* Set the index to the nodeid field */
543a195726fSgovinda 		i = addr_cells + intr_cells;
5447c478bd9Sstevel@tonic-gate 
545a195726fSgovinda 		/*
546a195726fSgovinda 		 * step4a
547a195726fSgovinda 		 * Translate the nodeid field to a dip
548a195726fSgovinda 		 */
549a195726fSgovinda 		ASSERT(intr_parent_dip == NULL);
550a195726fSgovinda 		intr_parent_dip = e_ddi_nodeid_to_dip((uint_t)scan[i++]);
5517c478bd9Sstevel@tonic-gate 
552a195726fSgovinda 		ASSERT(intr_parent_dip != 0);
553a195726fSgovinda #ifdef DEBUG
554a195726fSgovinda 		if (debug)
555903a11ebSrh 			prom_printf("scan 0x%p\n", (void *)scan);
556a195726fSgovinda #endif
557a195726fSgovinda 		/*
558a195726fSgovinda 		 * The tmp_dip describes the new domain, get it's interrupt
559a195726fSgovinda 		 * cell size
560a195726fSgovinda 		 */
561a195726fSgovinda 		new_intr_cells = ddi_getprop(DDI_DEV_T_ANY, intr_parent_dip, 0,
562a195726fSgovinda 		    "#interrupts-cells", 1);
5637c478bd9Sstevel@tonic-gate 
564a195726fSgovinda 		/*
565a195726fSgovinda 		 * step4b
566a195726fSgovinda 		 * See if we have a match on the interrupt unit specifier
567a195726fSgovinda 		 */
568a195726fSgovinda 		if (cells_1275_cmp(match_req, scan, addr_cells + intr_cells)
569a195726fSgovinda 		    == 0) {
570a195726fSgovinda 			uint32_t *intr;
5717c478bd9Sstevel@tonic-gate 
572a195726fSgovinda 			match_found = 1;
5737c478bd9Sstevel@tonic-gate 
574a195726fSgovinda 			/*
575a195726fSgovinda 			 * If we have an imap parent whose not in our device
576a195726fSgovinda 			 * tree path, we need to hold and install that driver.
577a195726fSgovinda 			 */
578a195726fSgovinda 			if (i_ddi_attach_node_hierarchy(intr_parent_dip)
579a195726fSgovinda 			    != DDI_SUCCESS) {
580a195726fSgovinda 				ndi_rele_devi(intr_parent_dip);
581a195726fSgovinda 				intr_parent_dip = (dev_info_t *)NULL;
582a195726fSgovinda 				goto exit4;
583a195726fSgovinda 			}
5847c478bd9Sstevel@tonic-gate 
585a195726fSgovinda 			/*
586a195726fSgovinda 			 * We need to handcraft an ispec along with a bus
587a195726fSgovinda 			 * interrupt value, so we can dup it into our
588a195726fSgovinda 			 * standard ispec structure.
589a195726fSgovinda 			 */
590a195726fSgovinda 			/* Extract the translated interrupt information */
591a195726fSgovinda 			intr = kmem_alloc(
592a195726fSgovinda 			    CELLS_1275_TO_BYTES(new_intr_cells), KM_SLEEP);
593a195726fSgovinda 
594a195726fSgovinda 			for (j = 0; j < new_intr_cells; j++, i++)
595a195726fSgovinda 				intr[j] = scan[i];
596a195726fSgovinda 
597a195726fSgovinda 			cells_1275_copy(intr, &hdlp->ih_vector, new_intr_cells);
598a195726fSgovinda 
599a195726fSgovinda 			kmem_free(intr, CELLS_1275_TO_BYTES(new_intr_cells));
600a195726fSgovinda 
601a195726fSgovinda #ifdef DEBUG
602a195726fSgovinda 			if (debug)
603903a11ebSrh 				prom_printf("dip 0x%p\n",
604903a11ebSrh 				    (void *)intr_parent_dip);
605a195726fSgovinda #endif
606a195726fSgovinda 			break;
607a195726fSgovinda 		} else {
608a195726fSgovinda #ifdef DEBUG
609a195726fSgovinda 			if (debug)
610903a11ebSrh 				prom_printf("dip 0x%p\n",
611903a11ebSrh 				    (void *)intr_parent_dip);
612a195726fSgovinda #endif
613a195726fSgovinda 			ndi_rele_devi(intr_parent_dip);
614a195726fSgovinda 			intr_parent_dip = NULL;
615a195726fSgovinda 			i += new_intr_cells;
616a195726fSgovinda 		}
617a195726fSgovinda 	}
618a195726fSgovinda 
619a195726fSgovinda 	/*
620a195726fSgovinda 	 * If we haven't found our interrupt parent at this point, fallback
621a195726fSgovinda 	 * to using the device tree.
622a195726fSgovinda 	 */
623a195726fSgovinda 	if (!match_found) {
624a195726fSgovinda 		ndi_hold_devi(pdip);
625a195726fSgovinda 		ASSERT(intr_parent_dip == NULL);
626a195726fSgovinda 		intr_parent_dip = pdip;
627a195726fSgovinda 	}
628a195726fSgovinda 
629a195726fSgovinda 	ASSERT(intr_parent_dip != NULL);
630a195726fSgovinda 
631a195726fSgovinda exit4:
632a195726fSgovinda 	kmem_free(reg_p, reg_len);
633a195726fSgovinda 	kmem_free(match_req, CELLS_1275_TO_BYTES(addr_cells) +
634a195726fSgovinda 	    CELLS_1275_TO_BYTES(intr_cells));
635a195726fSgovinda 
636a195726fSgovinda exit3:
637a195726fSgovinda 	kmem_free(imap_mask, imap_mask_sz);
638a195726fSgovinda 
639a195726fSgovinda exit2:
640a195726fSgovinda 	kmem_free(imap, imap_sz);
641a195726fSgovinda 
642a195726fSgovinda 	return (intr_parent_dip);
6437c478bd9Sstevel@tonic-gate }
6447c478bd9Sstevel@tonic-gate 
645a195726fSgovinda /*
646a195726fSgovinda  * process_intr_ops:
647a195726fSgovinda  *
648a195726fSgovinda  * Process the interrupt op via the interrupt parent.
649a195726fSgovinda  */
650a195726fSgovinda 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)651a195726fSgovinda process_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t op,
652a195726fSgovinda     ddi_intr_handle_impl_t *hdlp, void *result)
6537c478bd9Sstevel@tonic-gate {
654a195726fSgovinda 	int		ret = DDI_FAILURE;
6557c478bd9Sstevel@tonic-gate 
656a195726fSgovinda 	if (NEXUS_HAS_INTR_OP(pdip)) {
657a195726fSgovinda 		ret = (*(DEVI(pdip)->devi_ops->devo_bus_ops->
658a195726fSgovinda 		    bus_intr_op)) (pdip, rdip, op, hdlp, result);
659a195726fSgovinda 	} else {
660a195726fSgovinda 		cmn_err(CE_WARN, "Failed to process interrupt "
661a195726fSgovinda 		    "for %s%d due to down-rev nexus driver %s%d",
662a195726fSgovinda 		    ddi_get_name(rdip), ddi_get_instance(rdip),
663a195726fSgovinda 		    ddi_get_name(pdip), ddi_get_instance(pdip));
664a195726fSgovinda 	}
665a195726fSgovinda 
666a195726fSgovinda 	return (ret);
6677c478bd9Sstevel@tonic-gate }
6687c478bd9Sstevel@tonic-gate 
669a195726fSgovinda /*ARGSUSED*/
670a195726fSgovinda uint_t
softlevel1(caddr_t arg)671a195726fSgovinda softlevel1(caddr_t arg)
6727c478bd9Sstevel@tonic-gate {
673a195726fSgovinda 	softint();
674a195726fSgovinda 	return (1);
675a195726fSgovinda }
6767c478bd9Sstevel@tonic-gate 
677a195726fSgovinda /*
678a195726fSgovinda  * indirection table, to save us some large switch statements
679a195726fSgovinda  * NOTE: This must agree with "INTLEVEL_foo" constants in
680a195726fSgovinda  *	<sys/avintr.h>
681a195726fSgovinda  */
682a195726fSgovinda struct autovec *const vectorlist[] = { 0 };
6837c478bd9Sstevel@tonic-gate 
684a195726fSgovinda /*
685a195726fSgovinda  * This value is exported here for the functions in avintr.c
686a195726fSgovinda  */
687a195726fSgovinda const uint_t maxautovec = (sizeof (vectorlist) / sizeof (vectorlist[0]));
6887c478bd9Sstevel@tonic-gate 
689a195726fSgovinda /*
690a195726fSgovinda  * Check for machine specific interrupt levels which cannot be reassigned by
691a195726fSgovinda  * settrap(), sun4u version.
692a195726fSgovinda  *
693a195726fSgovinda  * sun4u does not support V8 SPARC "fast trap" handlers.
694a195726fSgovinda  */
695a195726fSgovinda /*ARGSUSED*/
696a195726fSgovinda int
exclude_settrap(int lvl)697a195726fSgovinda exclude_settrap(int lvl)
698a195726fSgovinda {
699a195726fSgovinda 	return (1);
700a195726fSgovinda }
7017c478bd9Sstevel@tonic-gate 
702a195726fSgovinda /*
703a195726fSgovinda  * Check for machine specific interrupt levels which cannot have interrupt
704a195726fSgovinda  * handlers added. We allow levels 1 through 15; level 0 is nonsense.
705a195726fSgovinda  */
706a195726fSgovinda /*ARGSUSED*/
707a195726fSgovinda int
exclude_level(int lvl)708a195726fSgovinda exclude_level(int lvl)
709a195726fSgovinda {
710a195726fSgovinda 	return ((lvl < 1) || (lvl > 15));
7117c478bd9Sstevel@tonic-gate }
7127c478bd9Sstevel@tonic-gate 
713a195726fSgovinda /*
714a195726fSgovinda  * Wrapper functions used by New DDI interrupt framework.
715a195726fSgovinda  */
716a195726fSgovinda 
717a195726fSgovinda /*
718a195726fSgovinda  * i_ddi_intr_ops:
719a195726fSgovinda  */
7207c478bd9Sstevel@tonic-gate 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)721a195726fSgovinda i_ddi_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t op,
722a195726fSgovinda     ddi_intr_handle_impl_t *hdlp, void *result)
7237c478bd9Sstevel@tonic-gate {
724a195726fSgovinda 	dev_info_t	*pdip = ddi_get_parent(dip);
725a195726fSgovinda 	int		ret = DDI_FAILURE;
7267c478bd9Sstevel@tonic-gate 
727a195726fSgovinda 	/*
728a195726fSgovinda 	 * The following check is required to address
729a195726fSgovinda 	 * one of the test case of ADDI test suite.
730a195726fSgovinda 	 */
731a195726fSgovinda 	if (pdip == NULL)
732a195726fSgovinda 		return (DDI_FAILURE);
7337c478bd9Sstevel@tonic-gate 
734a195726fSgovinda 	if (hdlp->ih_type != DDI_INTR_TYPE_FIXED)
735a195726fSgovinda 		return (process_intr_ops(pdip, rdip, op, hdlp, result));
7367c478bd9Sstevel@tonic-gate 
737a195726fSgovinda 	if (hdlp->ih_vector == 0)
738a195726fSgovinda 		hdlp->ih_vector = i_ddi_get_inum(rdip, hdlp->ih_inum);
739a195726fSgovinda 
740a195726fSgovinda 	if (hdlp->ih_pri == 0)
741a195726fSgovinda 		hdlp->ih_pri = i_ddi_get_intr_pri(rdip, hdlp->ih_inum);
742a195726fSgovinda 
743a195726fSgovinda 	switch (op) {
744a195726fSgovinda 	case DDI_INTROP_ADDISR:
745a195726fSgovinda 	case DDI_INTROP_REMISR:
74609b1eac2SEvan Yan 	case DDI_INTROP_GETTARGET:
74709b1eac2SEvan Yan 	case DDI_INTROP_SETTARGET:
748a195726fSgovinda 	case DDI_INTROP_ENABLE:
749a195726fSgovinda 	case DDI_INTROP_DISABLE:
750a195726fSgovinda 	case DDI_INTROP_BLOCKENABLE:
751a195726fSgovinda 	case DDI_INTROP_BLOCKDISABLE:
752a195726fSgovinda 		/*
753a195726fSgovinda 		 * Try and determine our parent and possibly an interrupt
754a195726fSgovinda 		 * translation. intr parent dip returned held
755a195726fSgovinda 		 */
756a195726fSgovinda 		if ((pdip = get_intr_parent(pdip, dip, hdlp)) == NULL)
757a195726fSgovinda 			goto done;
758a195726fSgovinda 	}
759a195726fSgovinda 
760a195726fSgovinda 	ret = process_intr_ops(pdip, rdip, op, hdlp, result);
761a195726fSgovinda 
762a195726fSgovinda done:
763a195726fSgovinda 	switch (op) {
764a195726fSgovinda 	case DDI_INTROP_ADDISR:
765a195726fSgovinda 	case DDI_INTROP_REMISR:
766a195726fSgovinda 	case DDI_INTROP_ENABLE:
767a195726fSgovinda 	case DDI_INTROP_DISABLE:
768a195726fSgovinda 	case DDI_INTROP_BLOCKENABLE:
769a195726fSgovinda 	case DDI_INTROP_BLOCKDISABLE:
770a195726fSgovinda 		/* Release hold acquired in get_intr_parent() */
771a195726fSgovinda 		if (pdip)
772a195726fSgovinda 			ndi_rele_devi(pdip);
773a195726fSgovinda 	}
774a195726fSgovinda 
775a195726fSgovinda 	hdlp->ih_vector = 0;
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate 	return (ret);
7787c478bd9Sstevel@tonic-gate }
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate /*
781a195726fSgovinda  * i_ddi_add_ivintr:
782a195726fSgovinda  */
783a195726fSgovinda /*ARGSUSED*/
784a195726fSgovinda int
i_ddi_add_ivintr(ddi_intr_handle_impl_t * hdlp)785a195726fSgovinda i_ddi_add_ivintr(ddi_intr_handle_impl_t *hdlp)
786a195726fSgovinda {
787a195726fSgovinda 	/*
788a195726fSgovinda 	 * If the PIL was set and is valid use it, otherwise
789a195726fSgovinda 	 * default it to 1
790a195726fSgovinda 	 */
791a195726fSgovinda 	if ((hdlp->ih_pri < 1) || (hdlp->ih_pri > PIL_MAX))
792a195726fSgovinda 		hdlp->ih_pri = 1;
793a195726fSgovinda 
794a195726fSgovinda 	VERIFY(add_ivintr(hdlp->ih_vector, hdlp->ih_pri,
795b0fc0e77Sgovinda 	    (intrfunc)hdlp->ih_cb_func, hdlp->ih_cb_arg1,
796b0fc0e77Sgovinda 	    hdlp->ih_cb_arg2, NULL) == 0);
797a195726fSgovinda 
798a195726fSgovinda 	return (DDI_SUCCESS);
799a195726fSgovinda }
800a195726fSgovinda 
801a195726fSgovinda /*
802a195726fSgovinda  * i_ddi_rem_ivintr:
8037c478bd9Sstevel@tonic-gate  */
804a195726fSgovinda /*ARGSUSED*/
8057c478bd9Sstevel@tonic-gate void
i_ddi_rem_ivintr(ddi_intr_handle_impl_t * hdlp)806a195726fSgovinda i_ddi_rem_ivintr(ddi_intr_handle_impl_t *hdlp)
8077c478bd9Sstevel@tonic-gate {
808b0fc0e77Sgovinda 	VERIFY(rem_ivintr(hdlp->ih_vector, hdlp->ih_pri) == 0);
809a195726fSgovinda }
810a195726fSgovinda 
811a195726fSgovinda /*
812a195726fSgovinda  * i_ddi_get_inum - Get the interrupt number property from the
813a195726fSgovinda  * specified device. Note that this function is called only for
814a195726fSgovinda  * the FIXED interrupt type.
815a195726fSgovinda  */
816a195726fSgovinda uint32_t
i_ddi_get_inum(dev_info_t * dip,uint_t inumber)817a195726fSgovinda i_ddi_get_inum(dev_info_t *dip, uint_t inumber)
818a195726fSgovinda {
819a195726fSgovinda 	int32_t			intrlen, intr_cells, max_intrs;
820a195726fSgovinda 	prop_1275_cell_t	*ip, intr_sz;
821a195726fSgovinda 	uint32_t		intr = 0;
8227c478bd9Sstevel@tonic-gate 
823a3282898Scth 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS |
8247c478bd9Sstevel@tonic-gate 	    DDI_PROP_CANSLEEP,
8257c478bd9Sstevel@tonic-gate 	    "interrupts", (caddr_t)&ip, &intrlen) == DDI_SUCCESS) {
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 		intr_cells = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
8287c478bd9Sstevel@tonic-gate 		    "#interrupt-cells", 1);
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate 		/* adjust for number of bytes */
8317c478bd9Sstevel@tonic-gate 		intr_sz = CELLS_1275_TO_BYTES(intr_cells);
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate 		/* Calculate the number of interrupts */
8347c478bd9Sstevel@tonic-gate 		max_intrs = intrlen / intr_sz;
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate 		if (inumber < max_intrs) {
8377c478bd9Sstevel@tonic-gate 			prop_1275_cell_t *intrp = ip;
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate 			/* Index into interrupt property */
8407c478bd9Sstevel@tonic-gate 			intrp += (inumber * intr_cells);
8417c478bd9Sstevel@tonic-gate 
842a195726fSgovinda 			cells_1275_copy(intrp, &intr, intr_cells);
8437c478bd9Sstevel@tonic-gate 		}
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 		kmem_free(ip, intrlen);
8467c478bd9Sstevel@tonic-gate 	}
8477c478bd9Sstevel@tonic-gate 
848a195726fSgovinda 	return (intr);
8497c478bd9Sstevel@tonic-gate }
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate /*
8527c478bd9Sstevel@tonic-gate  * i_ddi_get_intr_pri - Get the interrupt-priorities property from
853a195726fSgovinda  * the specified device. Note that this function is called only for
854a195726fSgovinda  * the FIXED interrupt type.
8557c478bd9Sstevel@tonic-gate  */
8567c478bd9Sstevel@tonic-gate uint32_t
i_ddi_get_intr_pri(dev_info_t * dip,uint_t inumber)8577c478bd9Sstevel@tonic-gate i_ddi_get_intr_pri(dev_info_t *dip, uint_t inumber)
8587c478bd9Sstevel@tonic-gate {
859a195726fSgovinda 	uint32_t	*intr_prio_p;
860a195726fSgovinda 	uint32_t	pri = 0;
861a195726fSgovinda 	int32_t		i;
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate 	/*
8647c478bd9Sstevel@tonic-gate 	 * Use the "interrupt-priorities" property to determine the
8657c478bd9Sstevel@tonic-gate 	 * the pil/ipl for the interrupt handler.
8667c478bd9Sstevel@tonic-gate 	 */
8677c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
8687c478bd9Sstevel@tonic-gate 	    "interrupt-priorities", (caddr_t)&intr_prio_p,
8697c478bd9Sstevel@tonic-gate 	    &i) == DDI_SUCCESS) {
8707c478bd9Sstevel@tonic-gate 		if (inumber < (i / sizeof (int32_t)))
8717c478bd9Sstevel@tonic-gate 			pri = intr_prio_p[inumber];
8727c478bd9Sstevel@tonic-gate 		kmem_free(intr_prio_p, i);
8737c478bd9Sstevel@tonic-gate 	}
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 	return (pri);
8767c478bd9Sstevel@tonic-gate }
8777c478bd9Sstevel@tonic-gate 
878a195726fSgovinda int
i_ddi_get_intx_nintrs(dev_info_t * dip)879a54f81fbSanish i_ddi_get_intx_nintrs(dev_info_t *dip)
880a195726fSgovinda {
881a195726fSgovinda 	int32_t intrlen;
882a195726fSgovinda 	prop_1275_cell_t intr_sz;
883a195726fSgovinda 	prop_1275_cell_t *ip;
884a195726fSgovinda 	int32_t ret = 0;
885a195726fSgovinda 
886a195726fSgovinda 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS |
887a195726fSgovinda 	    DDI_PROP_CANSLEEP,
888a195726fSgovinda 	    "interrupts", (caddr_t)&ip, &intrlen) == DDI_SUCCESS) {
889a195726fSgovinda 
890a195726fSgovinda 		intr_sz = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
891a195726fSgovinda 		    "#interrupt-cells", 1);
892a195726fSgovinda 		/* adjust for number of bytes */
893a195726fSgovinda 		intr_sz = CELLS_1275_TO_BYTES(intr_sz);
894a195726fSgovinda 
895a195726fSgovinda 		ret = intrlen / intr_sz;
896a195726fSgovinda 
897a195726fSgovinda 		kmem_free(ip, intrlen);
898a195726fSgovinda 	}
899a195726fSgovinda 
900a195726fSgovinda 	return (ret);
901a195726fSgovinda }
902a195726fSgovinda 
903a195726fSgovinda /*
904b0fc0e77Sgovinda  * i_ddi_add_softint - allocate and add a software interrupt.
905b0fc0e77Sgovinda  *
906b0fc0e77Sgovinda  * NOTE: All software interrupts that are registered through DDI
907b0fc0e77Sgovinda  *	 should be triggered only on a single target or CPU.
908a195726fSgovinda  */
909a195726fSgovinda int
i_ddi_add_softint(ddi_softint_hdl_impl_t * hdlp)910a195726fSgovinda i_ddi_add_softint(ddi_softint_hdl_impl_t *hdlp)
911a195726fSgovinda {
912b0fc0e77Sgovinda 	if ((hdlp->ih_private = (void *)add_softintr(hdlp->ih_pri,
913b0fc0e77Sgovinda 	    hdlp->ih_cb_func, hdlp->ih_cb_arg1, SOFTINT_ST)) == NULL)
914a195726fSgovinda 		return (DDI_FAILURE);
915a195726fSgovinda 
916a195726fSgovinda 	return (DDI_SUCCESS);
917a195726fSgovinda }
918a195726fSgovinda 
919b0fc0e77Sgovinda /*
920b0fc0e77Sgovinda  * i_ddi_remove_softint - remove and free a software interrupt.
921b0fc0e77Sgovinda  */
922a195726fSgovinda void
i_ddi_remove_softint(ddi_softint_hdl_impl_t * hdlp)923a195726fSgovinda i_ddi_remove_softint(ddi_softint_hdl_impl_t *hdlp)
924a195726fSgovinda {
925a195726fSgovinda 	ASSERT(hdlp->ih_private != NULL);
926a195726fSgovinda 
927b0fc0e77Sgovinda 	if (rem_softintr((uint64_t)hdlp->ih_private) == 0)
928b0fc0e77Sgovinda 		hdlp->ih_private = NULL;
929a195726fSgovinda }
930a195726fSgovinda 
931b0fc0e77Sgovinda /*
932b0fc0e77Sgovinda  * i_ddi_trigger_softint - trigger a software interrupt.
933b0fc0e77Sgovinda  */
934a195726fSgovinda int
i_ddi_trigger_softint(ddi_softint_hdl_impl_t * hdlp,void * arg2)935a195726fSgovinda i_ddi_trigger_softint(ddi_softint_hdl_impl_t *hdlp, void *arg2)
936a195726fSgovinda {
937b0fc0e77Sgovinda 	int	ret;
938a195726fSgovinda 
939a195726fSgovinda 	ASSERT(hdlp->ih_private != NULL);
940a195726fSgovinda 
941b0fc0e77Sgovinda 	/* Update the second argument for the software interrupt */
942b0fc0e77Sgovinda 	if ((ret = update_softint_arg2((uint64_t)hdlp->ih_private, arg2)) == 0)
943b0fc0e77Sgovinda 		setsoftint((uint64_t)hdlp->ih_private);
944a195726fSgovinda 
945b0fc0e77Sgovinda 	return (ret ? DDI_EPENDING : DDI_SUCCESS);
946a195726fSgovinda }
947a195726fSgovinda 
948b0fc0e77Sgovinda /*
949b0fc0e77Sgovinda  * i_ddi_set_softint_pri - change software interrupt priority.
950b0fc0e77Sgovinda  */
951a195726fSgovinda /* ARGSUSED */
952a195726fSgovinda int
i_ddi_set_softint_pri(ddi_softint_hdl_impl_t * hdlp,uint_t old_pri)953a195726fSgovinda i_ddi_set_softint_pri(ddi_softint_hdl_impl_t *hdlp, uint_t old_pri)
954a195726fSgovinda {
955b0fc0e77Sgovinda 	int	ret;
956a195726fSgovinda 
957a195726fSgovinda 	ASSERT(hdlp->ih_private != NULL);
958a195726fSgovinda 
959b0fc0e77Sgovinda 	/* Update the interrupt priority for the software interrupt */
960b0fc0e77Sgovinda 	ret = update_softint_pri((uint64_t)hdlp->ih_private, hdlp->ih_pri);
961a195726fSgovinda 
962b0fc0e77Sgovinda 	return (ret ? DDI_FAILURE : DDI_SUCCESS);
963a195726fSgovinda }
964a195726fSgovinda 
9657a364d25Sschwartz /*ARGSUSED*/
9667a364d25Sschwartz void
i_ddi_alloc_intr_phdl(ddi_intr_handle_impl_t * hdlp)9677a364d25Sschwartz i_ddi_alloc_intr_phdl(ddi_intr_handle_impl_t *hdlp)
9687a364d25Sschwartz {
9697a364d25Sschwartz }
9707a364d25Sschwartz 
9717a364d25Sschwartz /*ARGSUSED*/
9727a364d25Sschwartz void
i_ddi_free_intr_phdl(ddi_intr_handle_impl_t * hdlp)9737a364d25Sschwartz i_ddi_free_intr_phdl(ddi_intr_handle_impl_t *hdlp)
9747a364d25Sschwartz {
9757a364d25Sschwartz }
9767a364d25Sschwartz 
977a195726fSgovinda /*
978a195726fSgovinda  * SECTION: DDI Memory/DMA
979a195726fSgovinda  */
980a195726fSgovinda 
9817b93957cSeota /* set HAT endianess attributes from ddi_device_acc_attr */
9827b93957cSeota void
i_ddi_devacc_to_hatacc(ddi_device_acc_attr_t * devaccp,uint_t * hataccp)9837b93957cSeota i_ddi_devacc_to_hatacc(ddi_device_acc_attr_t *devaccp, uint_t *hataccp)
9847b93957cSeota {
9857b93957cSeota 	if (devaccp != NULL) {
9867b93957cSeota 		if (devaccp->devacc_attr_endian_flags == DDI_STRUCTURE_LE_ACC) {
9877b93957cSeota 			*hataccp &= ~HAT_ENDIAN_MASK;
9887b93957cSeota 			*hataccp |= HAT_STRUCTURE_LE;
9897b93957cSeota 		}
9907b93957cSeota 	}
9917b93957cSeota }
9927b93957cSeota 
9937b93957cSeota /*
9947b93957cSeota  * Check if the specified cache attribute is supported on the platform.
9957b93957cSeota  * This function must be called before i_ddi_cacheattr_to_hatacc().
9967b93957cSeota  */
9977b93957cSeota boolean_t
i_ddi_check_cache_attr(uint_t flags)9987b93957cSeota i_ddi_check_cache_attr(uint_t flags)
9997b93957cSeota {
10007b93957cSeota 	/*
10017b93957cSeota 	 * The cache attributes are mutually exclusive. Any combination of
10027b93957cSeota 	 * the attributes leads to a failure.
10037b93957cSeota 	 */
10047b93957cSeota 	uint_t cache_attr = IOMEM_CACHE_ATTR(flags);
1005de710d24SJosef 'Jeff' Sipek 	if ((cache_attr != 0) && !ISP2(cache_attr))
10067b93957cSeota 		return (B_FALSE);
10077b93957cSeota 
10087b93957cSeota 	/*
10097b93957cSeota 	 * On the sparc architecture, only IOMEM_DATA_CACHED is meaningful,
10107b93957cSeota 	 * but others lead to a failure.
10117b93957cSeota 	 */
10127b93957cSeota 	if (cache_attr & IOMEM_DATA_CACHED)
10137b93957cSeota 		return (B_TRUE);
10147b93957cSeota 	else
10157b93957cSeota 		return (B_FALSE);
10167b93957cSeota }
10177b93957cSeota 
10187b93957cSeota /* set HAT cache attributes from the cache attributes */
10197b93957cSeota void
i_ddi_cacheattr_to_hatacc(uint_t flags,uint_t * hataccp)10207b93957cSeota i_ddi_cacheattr_to_hatacc(uint_t flags, uint_t *hataccp)
10217b93957cSeota {
10227b93957cSeota 	uint_t cache_attr = IOMEM_CACHE_ATTR(flags);
10237b93957cSeota 	static char *fname = "i_ddi_cacheattr_to_hatacc";
10247b93957cSeota #if defined(lint)
10257b93957cSeota 	*hataccp = *hataccp;
10267b93957cSeota #endif
10277b93957cSeota 	/*
10287b93957cSeota 	 * set HAT attrs according to the cache attrs.
10297b93957cSeota 	 */
10307b93957cSeota 	switch (cache_attr) {
10317b93957cSeota 	/*
10327b93957cSeota 	 * The cache coherency is always maintained on SPARC, and
10337b93957cSeota 	 * nothing is required.
10347b93957cSeota 	 */
10357b93957cSeota 	case IOMEM_DATA_CACHED:
10367b93957cSeota 		break;
10377b93957cSeota 	/*
10387b93957cSeota 	 * Both IOMEM_DATA_UC_WRITE_COMBINED and IOMEM_DATA_UNCACHED are
10397b93957cSeota 	 * not supported on SPARC -- this case must not occur because the
10407b93957cSeota 	 * cache attribute is scrutinized before this function is called.
10417b93957cSeota 	 */
10427b93957cSeota 	case IOMEM_DATA_UNCACHED:
10437b93957cSeota 	case IOMEM_DATA_UC_WR_COMBINE:
10447b93957cSeota 	default:
10457b93957cSeota 		cmn_err(CE_WARN, "%s: cache_attr=0x%x is ignored.",
10467b93957cSeota 		    fname, cache_attr);
10477b93957cSeota 	}
10487b93957cSeota }
10497b93957cSeota 
1050a195726fSgovinda static vmem_t *little_endian_arena;
1051a195726fSgovinda static vmem_t *big_endian_arena;
1052a195726fSgovinda 
10537c478bd9Sstevel@tonic-gate static void *
segkmem_alloc_le(vmem_t * vmp,size_t size,int flag)10547c478bd9Sstevel@tonic-gate segkmem_alloc_le(vmem_t *vmp, size_t size, int flag)
10557c478bd9Sstevel@tonic-gate {
10567c478bd9Sstevel@tonic-gate 	return (segkmem_xalloc(vmp, NULL, size, flag, HAT_STRUCTURE_LE,
10577c478bd9Sstevel@tonic-gate 	    segkmem_page_create, NULL));
10587c478bd9Sstevel@tonic-gate }
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate static void *
segkmem_alloc_be(vmem_t * vmp,size_t size,int flag)10617c478bd9Sstevel@tonic-gate segkmem_alloc_be(vmem_t *vmp, size_t size, int flag)
10627c478bd9Sstevel@tonic-gate {
10637c478bd9Sstevel@tonic-gate 	return (segkmem_xalloc(vmp, NULL, size, flag, HAT_STRUCTURE_BE,
10647c478bd9Sstevel@tonic-gate 	    segkmem_page_create, NULL));
10657c478bd9Sstevel@tonic-gate }
10667c478bd9Sstevel@tonic-gate 
10677c478bd9Sstevel@tonic-gate void
ka_init(void)10687c478bd9Sstevel@tonic-gate ka_init(void)
10697c478bd9Sstevel@tonic-gate {
10707c478bd9Sstevel@tonic-gate 	little_endian_arena = vmem_create("little_endian", NULL, 0, 1,
10717c478bd9Sstevel@tonic-gate 	    segkmem_alloc_le, segkmem_free, heap_arena, 0, VM_SLEEP);
10727c478bd9Sstevel@tonic-gate 	big_endian_arena = vmem_create("big_endian", NULL, 0, 1,
10737c478bd9Sstevel@tonic-gate 	    segkmem_alloc_be, segkmem_free, heap_arena, 0, VM_SLEEP);
10747c478bd9Sstevel@tonic-gate }
10757c478bd9Sstevel@tonic-gate 
10767c478bd9Sstevel@tonic-gate /*
10777c478bd9Sstevel@tonic-gate  * Allocate from the system, aligned on a specific boundary.
10787c478bd9Sstevel@tonic-gate  * The alignment, if non-zero, must be a power of 2.
10797c478bd9Sstevel@tonic-gate  */
10807c478bd9Sstevel@tonic-gate static void *
kalloca(size_t size,size_t align,int cansleep,uint_t endian_flags)10817c478bd9Sstevel@tonic-gate kalloca(size_t size, size_t align, int cansleep, uint_t endian_flags)
10827c478bd9Sstevel@tonic-gate {
10837c478bd9Sstevel@tonic-gate 	size_t *addr, *raddr, rsize;
10847c478bd9Sstevel@tonic-gate 	size_t hdrsize = 4 * sizeof (size_t);	/* must be power of 2 */
10857c478bd9Sstevel@tonic-gate 
10867c478bd9Sstevel@tonic-gate 	align = MAX(align, hdrsize);
10877c478bd9Sstevel@tonic-gate 	ASSERT((align & (align - 1)) == 0);
10887c478bd9Sstevel@tonic-gate 
10897c478bd9Sstevel@tonic-gate 	/*
10907c478bd9Sstevel@tonic-gate 	 * We need to allocate
10917c478bd9Sstevel@tonic-gate 	 *    rsize = size + hdrsize + align - MIN(hdrsize, buffer_alignment)
10927c478bd9Sstevel@tonic-gate 	 * bytes to be sure we have enough freedom to satisfy the request.
10937c478bd9Sstevel@tonic-gate 	 * Since the buffer alignment depends on the request size, this is
10947c478bd9Sstevel@tonic-gate 	 * not straightforward to use directly.
10957c478bd9Sstevel@tonic-gate 	 *
10967c478bd9Sstevel@tonic-gate 	 * kmem guarantees that any allocation of a 64-byte multiple will be
10977c478bd9Sstevel@tonic-gate 	 * 64-byte aligned.  Since rounding up the request could add more
10987c478bd9Sstevel@tonic-gate 	 * than we save, we compute the size with and without alignment, and
10997c478bd9Sstevel@tonic-gate 	 * use the smaller of the two.
11007c478bd9Sstevel@tonic-gate 	 */
11017c478bd9Sstevel@tonic-gate 	rsize = size + hdrsize + align;
11027c478bd9Sstevel@tonic-gate 
11037c478bd9Sstevel@tonic-gate 	if (endian_flags == DDI_STRUCTURE_LE_ACC) {
11047c478bd9Sstevel@tonic-gate 		raddr = vmem_alloc(little_endian_arena, rsize,
11057c478bd9Sstevel@tonic-gate 		    cansleep ? VM_SLEEP : VM_NOSLEEP);
11067c478bd9Sstevel@tonic-gate 	} else {
11077c478bd9Sstevel@tonic-gate 		raddr = vmem_alloc(big_endian_arena, rsize,
11087c478bd9Sstevel@tonic-gate 		    cansleep ? VM_SLEEP : VM_NOSLEEP);
11097c478bd9Sstevel@tonic-gate 	}
11107c478bd9Sstevel@tonic-gate 
11117c478bd9Sstevel@tonic-gate 	if (raddr == NULL)
11127c478bd9Sstevel@tonic-gate 		return (NULL);
11137c478bd9Sstevel@tonic-gate 
11147c478bd9Sstevel@tonic-gate 	addr = (size_t *)P2ROUNDUP((uintptr_t)raddr + hdrsize, align);
11157c478bd9Sstevel@tonic-gate 	ASSERT((uintptr_t)addr + size - (uintptr_t)raddr <= rsize);
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate 	addr[-3] = (size_t)endian_flags;
11187c478bd9Sstevel@tonic-gate 	addr[-2] = (size_t)raddr;
11197c478bd9Sstevel@tonic-gate 	addr[-1] = rsize;
11207c478bd9Sstevel@tonic-gate 
11217c478bd9Sstevel@tonic-gate 	return (addr);
11227c478bd9Sstevel@tonic-gate }
11237c478bd9Sstevel@tonic-gate 
11247c478bd9Sstevel@tonic-gate static void
kfreea(void * addr)11257c478bd9Sstevel@tonic-gate kfreea(void *addr)
11267c478bd9Sstevel@tonic-gate {
11277c478bd9Sstevel@tonic-gate 	size_t *saddr = addr;
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate 	if (saddr[-3] == DDI_STRUCTURE_LE_ACC)
11307c478bd9Sstevel@tonic-gate 		vmem_free(little_endian_arena, (void *)saddr[-2], saddr[-1]);
11317c478bd9Sstevel@tonic-gate 	else
11327c478bd9Sstevel@tonic-gate 		vmem_free(big_endian_arena, (void *)saddr[-2], saddr[-1]);
11337c478bd9Sstevel@tonic-gate }
11347c478bd9Sstevel@tonic-gate 
1135b89e420aSGarrett D'Amore /*
1136b89e420aSGarrett D'Amore  * This used to be ddi_iomin, but we were the only remaining caller, so
1137b89e420aSGarrett D'Amore  * we've made it private and moved it here.
1138b89e420aSGarrett D'Amore  */
1139b89e420aSGarrett D'Amore static int
i_ddi_iomin(dev_info_t * a,int i,int stream)1140b89e420aSGarrett D'Amore i_ddi_iomin(dev_info_t *a, int i, int stream)
1141b89e420aSGarrett D'Amore {
1142b89e420aSGarrett D'Amore 	int r;
1143b89e420aSGarrett D'Amore 
1144b89e420aSGarrett D'Amore 	/*
1145b89e420aSGarrett D'Amore 	 * Make sure that the initial value is sane
1146b89e420aSGarrett D'Amore 	 */
1147de710d24SJosef 'Jeff' Sipek 	if (!ISP2(i))
1148b89e420aSGarrett D'Amore 		return (0);
1149b89e420aSGarrett D'Amore 	if (i == 0)
1150b89e420aSGarrett D'Amore 		i = (stream) ? 4 : 1;
1151b89e420aSGarrett D'Amore 
1152b89e420aSGarrett D'Amore 	r = ddi_ctlops(a, a,
1153b89e420aSGarrett D'Amore 	    DDI_CTLOPS_IOMIN, (void *)(uintptr_t)stream, (void *)&i);
1154de710d24SJosef 'Jeff' Sipek 	if (r != DDI_SUCCESS || !ISP2(i))
1155b89e420aSGarrett D'Amore 		return (0);
1156b89e420aSGarrett D'Amore 	return (i);
1157b89e420aSGarrett D'Amore }
1158b89e420aSGarrett D'Amore 
11597c478bd9Sstevel@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)11607c478bd9Sstevel@tonic-gate i_ddi_mem_alloc(dev_info_t *dip, ddi_dma_attr_t *attr,
11617b93957cSeota     size_t length, int cansleep, int flags,
11627c478bd9Sstevel@tonic-gate     ddi_device_acc_attr_t *accattrp,
11637c478bd9Sstevel@tonic-gate     caddr_t *kaddrp, size_t *real_length, ddi_acc_hdl_t *handlep)
11647c478bd9Sstevel@tonic-gate {
11657c478bd9Sstevel@tonic-gate 	caddr_t a;
11667b93957cSeota 	int iomin, align, streaming;
11677c478bd9Sstevel@tonic-gate 	uint_t endian_flags = DDI_NEVERSWAP_ACC;
11687c478bd9Sstevel@tonic-gate 
11697c478bd9Sstevel@tonic-gate #if defined(lint)
11707c478bd9Sstevel@tonic-gate 	*handlep = *handlep;
11717c478bd9Sstevel@tonic-gate #endif
11727c478bd9Sstevel@tonic-gate 
11737c478bd9Sstevel@tonic-gate 	/*
11747c478bd9Sstevel@tonic-gate 	 * Check legality of arguments
11757c478bd9Sstevel@tonic-gate 	 */
11767c478bd9Sstevel@tonic-gate 	if (length == 0 || kaddrp == NULL || attr == NULL) {
11777c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
11787c478bd9Sstevel@tonic-gate 	}
11797b93957cSeota 
11807c478bd9Sstevel@tonic-gate 	if (attr->dma_attr_minxfer == 0 || attr->dma_attr_align == 0 ||
1181de710d24SJosef 'Jeff' Sipek 	    !ISP2(attr->dma_attr_align) || !ISP2(attr->dma_attr_minxfer)) {
11827c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
11837c478bd9Sstevel@tonic-gate 	}
11847c478bd9Sstevel@tonic-gate 
11857b93957cSeota 	/*
11867b93957cSeota 	 * check if a streaming sequential xfer is requested.
11877b93957cSeota 	 */
11887b93957cSeota 	streaming = (flags & DDI_DMA_STREAMING) ? 1 : 0;
11897b93957cSeota 
11907c478bd9Sstevel@tonic-gate 	/*
11917c478bd9Sstevel@tonic-gate 	 * Drivers for 64-bit capable SBus devices will encode
11927c478bd9Sstevel@tonic-gate 	 * the burtsizes for 64-bit xfers in the upper 16-bits.
11937c478bd9Sstevel@tonic-gate 	 * For DMA alignment, we use the most restrictive
11947c478bd9Sstevel@tonic-gate 	 * alignment of 32-bit and 64-bit xfers.
11957c478bd9Sstevel@tonic-gate 	 */
11967c478bd9Sstevel@tonic-gate 	iomin = (attr->dma_attr_burstsizes & 0xffff) |
11977c478bd9Sstevel@tonic-gate 	    ((attr->dma_attr_burstsizes >> 16) & 0xffff);
11987c478bd9Sstevel@tonic-gate 	/*
1199*48bbca81SDaniel Hoffman 	 * If a driver set burtsizes to 0, we give it byte alignment.
12007c478bd9Sstevel@tonic-gate 	 * Otherwise align at the burtsizes boundary.
12017c478bd9Sstevel@tonic-gate 	 */
12027c478bd9Sstevel@tonic-gate 	if (iomin == 0)
12037c478bd9Sstevel@tonic-gate 		iomin = 1;
12047c478bd9Sstevel@tonic-gate 	else
12057c478bd9Sstevel@tonic-gate 		iomin = 1 << (ddi_fls(iomin) - 1);
12067c478bd9Sstevel@tonic-gate 	iomin = maxbit(iomin, attr->dma_attr_minxfer);
12077c478bd9Sstevel@tonic-gate 	iomin = maxbit(iomin, attr->dma_attr_align);
1208b89e420aSGarrett D'Amore 	iomin = i_ddi_iomin(dip, iomin, streaming);
12097c478bd9Sstevel@tonic-gate 	if (iomin == 0)
12107c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
12117c478bd9Sstevel@tonic-gate 
12127c478bd9Sstevel@tonic-gate 	ASSERT((iomin & (iomin - 1)) == 0);
12137c478bd9Sstevel@tonic-gate 	ASSERT(iomin >= attr->dma_attr_minxfer);
12147c478bd9Sstevel@tonic-gate 	ASSERT(iomin >= attr->dma_attr_align);
12157c478bd9Sstevel@tonic-gate 
12167c478bd9Sstevel@tonic-gate 	length = P2ROUNDUP(length, iomin);
12177c478bd9Sstevel@tonic-gate 	align = iomin;
12187c478bd9Sstevel@tonic-gate 
12197c478bd9Sstevel@tonic-gate 	if (accattrp != NULL)
12207c478bd9Sstevel@tonic-gate 		endian_flags = accattrp->devacc_attr_endian_flags;
12217c478bd9Sstevel@tonic-gate 
12227c478bd9Sstevel@tonic-gate 	a = kalloca(length, align, cansleep, endian_flags);
12237c478bd9Sstevel@tonic-gate 	if ((*kaddrp = a) == 0) {
12247c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
12257c478bd9Sstevel@tonic-gate 	} else {
12267c478bd9Sstevel@tonic-gate 		if (real_length) {
12277c478bd9Sstevel@tonic-gate 			*real_length = length;
12287c478bd9Sstevel@tonic-gate 		}
12297c478bd9Sstevel@tonic-gate 		if (handlep) {
12307c478bd9Sstevel@tonic-gate 			/*
12317c478bd9Sstevel@tonic-gate 			 * assign handle information
12327c478bd9Sstevel@tonic-gate 			 */
12337c478bd9Sstevel@tonic-gate 			impl_acc_hdl_init(handlep);
12347c478bd9Sstevel@tonic-gate 		}
12357c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
12367c478bd9Sstevel@tonic-gate 	}
12377c478bd9Sstevel@tonic-gate }
12387c478bd9Sstevel@tonic-gate 
12397c478bd9Sstevel@tonic-gate /* ARGSUSED */
12407c478bd9Sstevel@tonic-gate void
i_ddi_mem_free(caddr_t kaddr,ddi_acc_hdl_t * ap)12417b93957cSeota i_ddi_mem_free(caddr_t kaddr, ddi_acc_hdl_t *ap)
12427c478bd9Sstevel@tonic-gate {
12437c478bd9Sstevel@tonic-gate 	kfreea(kaddr);
12447c478bd9Sstevel@tonic-gate }
12457c478bd9Sstevel@tonic-gate 
12467c478bd9Sstevel@tonic-gate /*
12477c478bd9Sstevel@tonic-gate  * SECTION: DDI Data Access
12487c478bd9Sstevel@tonic-gate  */
12497c478bd9Sstevel@tonic-gate 
12507c478bd9Sstevel@tonic-gate static uintptr_t impl_acc_hdl_id = 0;
12517c478bd9Sstevel@tonic-gate 
12527c478bd9Sstevel@tonic-gate /*
12537c478bd9Sstevel@tonic-gate  * access handle allocator
12547c478bd9Sstevel@tonic-gate  */
12557c478bd9Sstevel@tonic-gate ddi_acc_hdl_t *
impl_acc_hdl_get(ddi_acc_handle_t hdl)12567c478bd9Sstevel@tonic-gate impl_acc_hdl_get(ddi_acc_handle_t hdl)
12577c478bd9Sstevel@tonic-gate {
12587c478bd9Sstevel@tonic-gate 	/*
12597c478bd9Sstevel@tonic-gate 	 * Extract the access handle address from the DDI implemented
12607c478bd9Sstevel@tonic-gate 	 * access handle
12617c478bd9Sstevel@tonic-gate 	 */
12627c478bd9Sstevel@tonic-gate 	return (&((ddi_acc_impl_t *)hdl)->ahi_common);
12637c478bd9Sstevel@tonic-gate }
12647c478bd9Sstevel@tonic-gate 
12657c478bd9Sstevel@tonic-gate ddi_acc_handle_t
impl_acc_hdl_alloc(int (* waitfp)(caddr_t),caddr_t arg)12667c478bd9Sstevel@tonic-gate impl_acc_hdl_alloc(int (*waitfp)(caddr_t), caddr_t arg)
12677c478bd9Sstevel@tonic-gate {
12687c478bd9Sstevel@tonic-gate 	ddi_acc_impl_t *hp;
12697c478bd9Sstevel@tonic-gate 	on_trap_data_t *otp;
12707c478bd9Sstevel@tonic-gate 	int sleepflag;
12717c478bd9Sstevel@tonic-gate 
12727c478bd9Sstevel@tonic-gate 	sleepflag = ((waitfp == (int (*)())KM_SLEEP) ? KM_SLEEP : KM_NOSLEEP);
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate 	/*
12757c478bd9Sstevel@tonic-gate 	 * Allocate and initialize the data access handle and error status.
12767c478bd9Sstevel@tonic-gate 	 */
12777c478bd9Sstevel@tonic-gate 	if ((hp = kmem_zalloc(sizeof (ddi_acc_impl_t), sleepflag)) == NULL)
12787c478bd9Sstevel@tonic-gate 		goto fail;
12797c478bd9Sstevel@tonic-gate 	if ((hp->ahi_err = (ndi_err_t *)kmem_zalloc(
12807c478bd9Sstevel@tonic-gate 	    sizeof (ndi_err_t), sleepflag)) == NULL) {
12817c478bd9Sstevel@tonic-gate 		kmem_free(hp, sizeof (ddi_acc_impl_t));
12827c478bd9Sstevel@tonic-gate 		goto fail;
12837c478bd9Sstevel@tonic-gate 	}
12847c478bd9Sstevel@tonic-gate 	if ((otp = (on_trap_data_t *)kmem_zalloc(
12857c478bd9Sstevel@tonic-gate 	    sizeof (on_trap_data_t), sleepflag)) == NULL) {
12867c478bd9Sstevel@tonic-gate 		kmem_free(hp->ahi_err, sizeof (ndi_err_t));
12877c478bd9Sstevel@tonic-gate 		kmem_free(hp, sizeof (ddi_acc_impl_t));
12887c478bd9Sstevel@tonic-gate 		goto fail;
12897c478bd9Sstevel@tonic-gate 	}
12907c478bd9Sstevel@tonic-gate 	hp->ahi_err->err_ontrap = otp;
12917c478bd9Sstevel@tonic-gate 	hp->ahi_common.ah_platform_private = (void *)hp;
12927c478bd9Sstevel@tonic-gate 
12937c478bd9Sstevel@tonic-gate 	return ((ddi_acc_handle_t)hp);
12947c478bd9Sstevel@tonic-gate fail:
12957c478bd9Sstevel@tonic-gate 	if ((waitfp != (int (*)())KM_SLEEP) &&
12967c478bd9Sstevel@tonic-gate 	    (waitfp != (int (*)())KM_NOSLEEP))
12977c478bd9Sstevel@tonic-gate 		ddi_set_callback(waitfp, arg, &impl_acc_hdl_id);
12987c478bd9Sstevel@tonic-gate 	return (NULL);
12997c478bd9Sstevel@tonic-gate }
13007c478bd9Sstevel@tonic-gate 
13017c478bd9Sstevel@tonic-gate void
impl_acc_hdl_free(ddi_acc_handle_t handle)13027c478bd9Sstevel@tonic-gate impl_acc_hdl_free(ddi_acc_handle_t handle)
13037c478bd9Sstevel@tonic-gate {
13047c478bd9Sstevel@tonic-gate 	ddi_acc_impl_t *hp;
13057c478bd9Sstevel@tonic-gate 
13067c478bd9Sstevel@tonic-gate 	/*
13077c478bd9Sstevel@tonic-gate 	 * The supplied (ddi_acc_handle_t) is actually a (ddi_acc_impl_t *),
13087c478bd9Sstevel@tonic-gate 	 * because that's what we allocated in impl_acc_hdl_alloc() above.
13097c478bd9Sstevel@tonic-gate 	 */
13107c478bd9Sstevel@tonic-gate 	hp = (ddi_acc_impl_t *)handle;
13117c478bd9Sstevel@tonic-gate 	if (hp) {
13127c478bd9Sstevel@tonic-gate 		kmem_free(hp->ahi_err->err_ontrap, sizeof (on_trap_data_t));
13137c478bd9Sstevel@tonic-gate 		kmem_free(hp->ahi_err, sizeof (ndi_err_t));
13147c478bd9Sstevel@tonic-gate 		kmem_free(hp, sizeof (ddi_acc_impl_t));
13157c478bd9Sstevel@tonic-gate 		if (impl_acc_hdl_id)
13167c478bd9Sstevel@tonic-gate 			ddi_run_callback(&impl_acc_hdl_id);
13177c478bd9Sstevel@tonic-gate 	}
13187c478bd9Sstevel@tonic-gate }
13197c478bd9Sstevel@tonic-gate 
132000d0963fSdilpreet #define	PCI_GET_MP_PFN(mp, page_no)	((mp)->dmai_ndvmapages == 1 ? \
132100d0963fSdilpreet 	(pfn_t)(mp)->dmai_iopte:(((pfn_t *)(mp)->dmai_iopte)[page_no]))
132200d0963fSdilpreet 
132300d0963fSdilpreet /*
132400d0963fSdilpreet  * Function called after a dma fault occurred to find out whether the
132500d0963fSdilpreet  * fault address is associated with a driver that is able to handle faults
132600d0963fSdilpreet  * and recover from faults.
132700d0963fSdilpreet  */
132800d0963fSdilpreet /* ARGSUSED */
132900d0963fSdilpreet int
impl_dma_check(dev_info_t * dip,const void * handle,const void * addr,const void * not_used)133000d0963fSdilpreet impl_dma_check(dev_info_t *dip, const void *handle, const void *addr,
133100d0963fSdilpreet     const void *not_used)
133200d0963fSdilpreet {
133300d0963fSdilpreet 	ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle;
133400d0963fSdilpreet 	pfn_t fault_pfn = mmu_btop(*(uint64_t *)addr);
133500d0963fSdilpreet 	pfn_t comp_pfn;
133600d0963fSdilpreet 
133700d0963fSdilpreet 	/*
133800d0963fSdilpreet 	 * The driver has to set DDI_DMA_FLAGERR to recover from dma faults.
133900d0963fSdilpreet 	 */
134000d0963fSdilpreet 	int page;
134100d0963fSdilpreet 
134200d0963fSdilpreet 	ASSERT(mp);
134300d0963fSdilpreet 	for (page = 0; page < mp->dmai_ndvmapages; page++) {
134400d0963fSdilpreet 		comp_pfn = PCI_GET_MP_PFN(mp, page);
134500d0963fSdilpreet 		if (fault_pfn == comp_pfn)
134600d0963fSdilpreet 			return (DDI_FM_NONFATAL);
134700d0963fSdilpreet 	}
134800d0963fSdilpreet 	return (DDI_FM_UNKNOWN);
134900d0963fSdilpreet }
135000d0963fSdilpreet 
135100d0963fSdilpreet /*
135200d0963fSdilpreet  * Function used to check if a given access handle owns the failing address.
135300d0963fSdilpreet  * Called by ndi_fmc_error, when we detect a PIO error.
135400d0963fSdilpreet  */
135500d0963fSdilpreet /* ARGSUSED */
135600d0963fSdilpreet static int
impl_acc_check(dev_info_t * dip,const void * handle,const void * addr,const void * not_used)135700d0963fSdilpreet impl_acc_check(dev_info_t *dip, const void *handle, const void *addr,
135800d0963fSdilpreet     const void *not_used)
135900d0963fSdilpreet {
136000d0963fSdilpreet 	pfn_t pfn, fault_pfn;
136100d0963fSdilpreet 	ddi_acc_hdl_t *hp;
136200d0963fSdilpreet 
136300d0963fSdilpreet 	hp = impl_acc_hdl_get((ddi_acc_handle_t)handle);
136400d0963fSdilpreet 
136500d0963fSdilpreet 	ASSERT(hp);
136600d0963fSdilpreet 
136700d0963fSdilpreet 	if (addr != NULL) {
136800d0963fSdilpreet 		pfn = hp->ah_pfn;
136900d0963fSdilpreet 		fault_pfn = mmu_btop(*(uint64_t *)addr);
137000d0963fSdilpreet 		if (fault_pfn >= pfn && fault_pfn < (pfn + hp->ah_pnum))
137100d0963fSdilpreet 			return (DDI_FM_NONFATAL);
137200d0963fSdilpreet 	}
137300d0963fSdilpreet 	return (DDI_FM_UNKNOWN);
137400d0963fSdilpreet }
137500d0963fSdilpreet 
13767c478bd9Sstevel@tonic-gate void
impl_acc_err_init(ddi_acc_hdl_t * handlep)13777c478bd9Sstevel@tonic-gate impl_acc_err_init(ddi_acc_hdl_t *handlep)
13787c478bd9Sstevel@tonic-gate {
13797c478bd9Sstevel@tonic-gate 	int fmcap;
13807c478bd9Sstevel@tonic-gate 	ndi_err_t *errp;
13817c478bd9Sstevel@tonic-gate 	on_trap_data_t *otp;
13827c478bd9Sstevel@tonic-gate 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)handlep;
13837c478bd9Sstevel@tonic-gate 
13847c478bd9Sstevel@tonic-gate 	fmcap = ddi_fm_capable(handlep->ah_dip);
13857c478bd9Sstevel@tonic-gate 
13867c478bd9Sstevel@tonic-gate 	if (handlep->ah_acc.devacc_attr_version < DDI_DEVICE_ATTR_V1 ||
13877c478bd9Sstevel@tonic-gate 	    !DDI_FM_ACC_ERR_CAP(fmcap)) {
13887c478bd9Sstevel@tonic-gate 		handlep->ah_acc.devacc_attr_access = DDI_DEFAULT_ACC;
13897c478bd9Sstevel@tonic-gate 	} else if (DDI_FM_ACC_ERR_CAP(fmcap)) {
13907c478bd9Sstevel@tonic-gate 		if (handlep->ah_acc.devacc_attr_access == DDI_DEFAULT_ACC) {
1391837c1ac4SStephen Hanson 			if (handlep->ah_xfermodes)
1392837c1ac4SStephen Hanson 				return;
13937c478bd9Sstevel@tonic-gate 			i_ddi_drv_ereport_post(handlep->ah_dip, DVR_EFMCAP,
13947c478bd9Sstevel@tonic-gate 			    NULL, DDI_NOSLEEP);
13957c478bd9Sstevel@tonic-gate 		} else {
13967c478bd9Sstevel@tonic-gate 			errp = hp->ahi_err;
13977c478bd9Sstevel@tonic-gate 			otp = (on_trap_data_t *)errp->err_ontrap;
13987c478bd9Sstevel@tonic-gate 			otp->ot_handle = (void *)(hp);
13997c478bd9Sstevel@tonic-gate 			otp->ot_prot = OT_DATA_ACCESS;
14007c478bd9Sstevel@tonic-gate 			if (handlep->ah_acc.devacc_attr_access ==
14017c478bd9Sstevel@tonic-gate 			    DDI_CAUTIOUS_ACC)
14027c478bd9Sstevel@tonic-gate 				otp->ot_trampoline =
14037c478bd9Sstevel@tonic-gate 				    (uintptr_t)&i_ddi_caut_trampoline;
14047c478bd9Sstevel@tonic-gate 			else
14057c478bd9Sstevel@tonic-gate 				otp->ot_trampoline =
14067c478bd9Sstevel@tonic-gate 				    (uintptr_t)&i_ddi_prot_trampoline;
14077c478bd9Sstevel@tonic-gate 			errp->err_status = DDI_FM_OK;
14087c478bd9Sstevel@tonic-gate 			errp->err_expected = DDI_FM_ERR_UNEXPECTED;
140900d0963fSdilpreet 			errp->err_cf = impl_acc_check;
14107c478bd9Sstevel@tonic-gate 		}
14117c478bd9Sstevel@tonic-gate 	}
14127c478bd9Sstevel@tonic-gate }
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate void
impl_acc_hdl_init(ddi_acc_hdl_t * handlep)14157c478bd9Sstevel@tonic-gate impl_acc_hdl_init(ddi_acc_hdl_t *handlep)
14167c478bd9Sstevel@tonic-gate {
14177c478bd9Sstevel@tonic-gate 	ddi_acc_impl_t *hp;
14187c478bd9Sstevel@tonic-gate 
14197c478bd9Sstevel@tonic-gate 	ASSERT(handlep);
14207c478bd9Sstevel@tonic-gate 
14217c478bd9Sstevel@tonic-gate 	hp = (ddi_acc_impl_t *)handlep;
14227c478bd9Sstevel@tonic-gate 
14237c478bd9Sstevel@tonic-gate 	/*
14247c478bd9Sstevel@tonic-gate 	 * check for SW byte-swapping
14257c478bd9Sstevel@tonic-gate 	 */
14267c478bd9Sstevel@tonic-gate 	hp->ahi_get8 = i_ddi_get8;
14277c478bd9Sstevel@tonic-gate 	hp->ahi_put8 = i_ddi_put8;
14287c478bd9Sstevel@tonic-gate 	hp->ahi_rep_get8 = i_ddi_rep_get8;
14297c478bd9Sstevel@tonic-gate 	hp->ahi_rep_put8 = i_ddi_rep_put8;
14307c478bd9Sstevel@tonic-gate 	if (handlep->ah_acc.devacc_attr_endian_flags & DDI_STRUCTURE_LE_ACC) {
14317c478bd9Sstevel@tonic-gate 		hp->ahi_get16 = i_ddi_swap_get16;
14327c478bd9Sstevel@tonic-gate 		hp->ahi_get32 = i_ddi_swap_get32;
14337c478bd9Sstevel@tonic-gate 		hp->ahi_get64 = i_ddi_swap_get64;
14347c478bd9Sstevel@tonic-gate 		hp->ahi_put16 = i_ddi_swap_put16;
14357c478bd9Sstevel@tonic-gate 		hp->ahi_put32 = i_ddi_swap_put32;
14367c478bd9Sstevel@tonic-gate 		hp->ahi_put64 = i_ddi_swap_put64;
14377c478bd9Sstevel@tonic-gate 		hp->ahi_rep_get16 = i_ddi_swap_rep_get16;
14387c478bd9Sstevel@tonic-gate 		hp->ahi_rep_get32 = i_ddi_swap_rep_get32;
14397c478bd9Sstevel@tonic-gate 		hp->ahi_rep_get64 = i_ddi_swap_rep_get64;
14407c478bd9Sstevel@tonic-gate 		hp->ahi_rep_put16 = i_ddi_swap_rep_put16;
14417c478bd9Sstevel@tonic-gate 		hp->ahi_rep_put32 = i_ddi_swap_rep_put32;
14427c478bd9Sstevel@tonic-gate 		hp->ahi_rep_put64 = i_ddi_swap_rep_put64;
14437c478bd9Sstevel@tonic-gate 	} else {
14447c478bd9Sstevel@tonic-gate 		hp->ahi_get16 = i_ddi_get16;
14457c478bd9Sstevel@tonic-gate 		hp->ahi_get32 = i_ddi_get32;
14467c478bd9Sstevel@tonic-gate 		hp->ahi_get64 = i_ddi_get64;
14477c478bd9Sstevel@tonic-gate 		hp->ahi_put16 = i_ddi_put16;
14487c478bd9Sstevel@tonic-gate 		hp->ahi_put32 = i_ddi_put32;
14497c478bd9Sstevel@tonic-gate 		hp->ahi_put64 = i_ddi_put64;
14507c478bd9Sstevel@tonic-gate 		hp->ahi_rep_get16 = i_ddi_rep_get16;
14517c478bd9Sstevel@tonic-gate 		hp->ahi_rep_get32 = i_ddi_rep_get32;
14527c478bd9Sstevel@tonic-gate 		hp->ahi_rep_get64 = i_ddi_rep_get64;
14537c478bd9Sstevel@tonic-gate 		hp->ahi_rep_put16 = i_ddi_rep_put16;
14547c478bd9Sstevel@tonic-gate 		hp->ahi_rep_put32 = i_ddi_rep_put32;
14557c478bd9Sstevel@tonic-gate 		hp->ahi_rep_put64 = i_ddi_rep_put64;
14567c478bd9Sstevel@tonic-gate 	}
14577c478bd9Sstevel@tonic-gate 
14587c478bd9Sstevel@tonic-gate 	/* Legacy fault flags and support */
14597c478bd9Sstevel@tonic-gate 	hp->ahi_fault_check = i_ddi_acc_fault_check;
14607c478bd9Sstevel@tonic-gate 	hp->ahi_fault_notify = i_ddi_acc_fault_notify;
14617c478bd9Sstevel@tonic-gate 	hp->ahi_fault = 0;
14627c478bd9Sstevel@tonic-gate 	impl_acc_err_init(handlep);
14637c478bd9Sstevel@tonic-gate }
14647c478bd9Sstevel@tonic-gate 
14657c478bd9Sstevel@tonic-gate void
i_ddi_acc_set_fault(ddi_acc_handle_t handle)14667c478bd9Sstevel@tonic-gate i_ddi_acc_set_fault(ddi_acc_handle_t handle)
14677c478bd9Sstevel@tonic-gate {
14687c478bd9Sstevel@tonic-gate 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)handle;
14697c478bd9Sstevel@tonic-gate 
14707c478bd9Sstevel@tonic-gate 	if (!hp->ahi_fault) {
14717c478bd9Sstevel@tonic-gate 		hp->ahi_fault = 1;
14727c478bd9Sstevel@tonic-gate 			(*hp->ahi_fault_notify)(hp);
14737c478bd9Sstevel@tonic-gate 	}
14747c478bd9Sstevel@tonic-gate }
14757c478bd9Sstevel@tonic-gate 
14767c478bd9Sstevel@tonic-gate void
i_ddi_acc_clr_fault(ddi_acc_handle_t handle)14777c478bd9Sstevel@tonic-gate i_ddi_acc_clr_fault(ddi_acc_handle_t handle)
14787c478bd9Sstevel@tonic-gate {
14797c478bd9Sstevel@tonic-gate 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)handle;
14807c478bd9Sstevel@tonic-gate 
14817c478bd9Sstevel@tonic-gate 	if (hp->ahi_fault) {
14827c478bd9Sstevel@tonic-gate 		hp->ahi_fault = 0;
14837c478bd9Sstevel@tonic-gate 			(*hp->ahi_fault_notify)(hp);
14847c478bd9Sstevel@tonic-gate 	}
14857c478bd9Sstevel@tonic-gate }
14867c478bd9Sstevel@tonic-gate 
14877c478bd9Sstevel@tonic-gate /* ARGSUSED */
14887c478bd9Sstevel@tonic-gate void
i_ddi_acc_fault_notify(ddi_acc_impl_t * hp)14897c478bd9Sstevel@tonic-gate i_ddi_acc_fault_notify(ddi_acc_impl_t *hp)
14907c478bd9Sstevel@tonic-gate {
14917c478bd9Sstevel@tonic-gate 	/* Default version, does nothing */
14927c478bd9Sstevel@tonic-gate }
14937c478bd9Sstevel@tonic-gate 
14947c478bd9Sstevel@tonic-gate /*
14957c478bd9Sstevel@tonic-gate  * SECTION: Misc functions
14967c478bd9Sstevel@tonic-gate  */
14977c478bd9Sstevel@tonic-gate 
14987c478bd9Sstevel@tonic-gate /*
14997c478bd9Sstevel@tonic-gate  * instance wrappers
15007c478bd9Sstevel@tonic-gate  */
15017c478bd9Sstevel@tonic-gate /*ARGSUSED*/
15027c478bd9Sstevel@tonic-gate uint_t
impl_assign_instance(dev_info_t * dip)15037c478bd9Sstevel@tonic-gate impl_assign_instance(dev_info_t *dip)
15047c478bd9Sstevel@tonic-gate {
15057c478bd9Sstevel@tonic-gate 	return ((uint_t)-1);
15067c478bd9Sstevel@tonic-gate }
15077c478bd9Sstevel@tonic-gate 
15087c478bd9Sstevel@tonic-gate /*ARGSUSED*/
15097c478bd9Sstevel@tonic-gate int
impl_keep_instance(dev_info_t * dip)15107c478bd9Sstevel@tonic-gate impl_keep_instance(dev_info_t *dip)
15117c478bd9Sstevel@tonic-gate {
15127c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
15137c478bd9Sstevel@tonic-gate }
15147c478bd9Sstevel@tonic-gate 
15157c478bd9Sstevel@tonic-gate /*ARGSUSED*/
15167c478bd9Sstevel@tonic-gate int
impl_free_instance(dev_info_t * dip)15177c478bd9Sstevel@tonic-gate impl_free_instance(dev_info_t *dip)
15187c478bd9Sstevel@tonic-gate {
15197c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
1520a195726fSgovinda }
15217c478bd9Sstevel@tonic-gate 
1522a195726fSgovinda /*ARGSUSED*/
1523a195726fSgovinda int
impl_check_cpu(dev_info_t * devi)1524a195726fSgovinda impl_check_cpu(dev_info_t *devi)
1525a195726fSgovinda {
1526a195726fSgovinda 	return (DDI_SUCCESS);
1527a195726fSgovinda }
15287c478bd9Sstevel@tonic-gate 
15297c478bd9Sstevel@tonic-gate 
1530a195726fSgovinda static const char *nocopydevs[] = {
1531a195726fSgovinda 	"SUNW,ffb",
1532a195726fSgovinda 	"SUNW,afb",
1533a195726fSgovinda 	NULL
1534a195726fSgovinda };
15357c478bd9Sstevel@tonic-gate 
1536a195726fSgovinda /*
1537a195726fSgovinda  * Perform a copy from a memory mapped device (whose devinfo pointer is devi)
1538a195726fSgovinda  * separately mapped at devaddr in the kernel to a kernel buffer at kaddr.
1539a195726fSgovinda  */
1540a195726fSgovinda /*ARGSUSED*/
1541a195726fSgovinda int
e_ddi_copyfromdev(dev_info_t * devi,off_t off,const void * devaddr,void * kaddr,size_t len)1542a195726fSgovinda e_ddi_copyfromdev(dev_info_t *devi,
1543a195726fSgovinda     off_t off, const void *devaddr, void *kaddr, size_t len)
1544a195726fSgovinda {
1545a195726fSgovinda 	const char **argv;
15467c478bd9Sstevel@tonic-gate 
1547a195726fSgovinda 	for (argv = nocopydevs; *argv; argv++)
1548a195726fSgovinda 		if (strcmp(ddi_binding_name(devi), *argv) == 0) {
1549a195726fSgovinda 			bzero(kaddr, len);
1550a195726fSgovinda 			return (0);
1551a195726fSgovinda 		}
15527c478bd9Sstevel@tonic-gate 
1553a195726fSgovinda 	bcopy(devaddr, kaddr, len);
1554a195726fSgovinda 	return (0);
1555a195726fSgovinda }
15567c478bd9Sstevel@tonic-gate 
1557a195726fSgovinda /*
1558a195726fSgovinda  * Perform a copy to a memory mapped device (whose devinfo pointer is devi)
1559a195726fSgovinda  * separately mapped at devaddr in the kernel from a kernel buffer at kaddr.
1560a195726fSgovinda  */
1561a195726fSgovinda /*ARGSUSED*/
1562a195726fSgovinda int
e_ddi_copytodev(dev_info_t * devi,off_t off,const void * kaddr,void * devaddr,size_t len)1563a195726fSgovinda e_ddi_copytodev(dev_info_t *devi,
1564a195726fSgovinda     off_t off, const void *kaddr, void *devaddr, size_t len)
1565a195726fSgovinda {
1566a195726fSgovinda 	const char **argv;
1567a195726fSgovinda 
1568a195726fSgovinda 	for (argv = nocopydevs; *argv; argv++)
1569a195726fSgovinda 		if (strcmp(ddi_binding_name(devi), *argv) == 0)
1570a195726fSgovinda 			return (1);
1571a195726fSgovinda 
1572a195726fSgovinda 	bcopy(kaddr, devaddr, len);
1573a195726fSgovinda 	return (0);
15747c478bd9Sstevel@tonic-gate }
15757c478bd9Sstevel@tonic-gate 
15767c478bd9Sstevel@tonic-gate /*
1577a195726fSgovinda  * Boot Configuration
1578a195726fSgovinda  */
1579a195726fSgovinda idprom_t idprom;
1580a195726fSgovinda 
1581a195726fSgovinda /*
1582a195726fSgovinda  * Configure the hardware on the system.
1583a195726fSgovinda  * Called before the rootfs is mounted
15847c478bd9Sstevel@tonic-gate  */
1585a195726fSgovinda void
configure(void)1586a195726fSgovinda configure(void)
15877c478bd9Sstevel@tonic-gate {
1588a195726fSgovinda 	extern void i_ddi_init_root();
15897c478bd9Sstevel@tonic-gate 
1590a195726fSgovinda 	/* We better have released boot by this time! */
1591a195726fSgovinda 	ASSERT(!bootops);
15927c478bd9Sstevel@tonic-gate 
1593a195726fSgovinda 	/*
1594a195726fSgovinda 	 * Determine whether or not to use the fpu, V9 SPARC cpus
1595a195726fSgovinda 	 * always have one. Could check for existence of a fp queue,
1596a195726fSgovinda 	 * Ultra I, II and IIa do not have a fp queue.
1597a195726fSgovinda 	 */
1598a195726fSgovinda 	if (fpu_exists)
1599a195726fSgovinda 		fpu_probe();
1600a195726fSgovinda 	else
1601a195726fSgovinda 		cmn_err(CE_CONT, "FPU not in use\n");
16027c478bd9Sstevel@tonic-gate 
1603a195726fSgovinda #if 0 /* XXXQ - not necessary for sun4u */
1604a195726fSgovinda 	/*
1605a195726fSgovinda 	 * This following line fixes bugid 1041296; we need to do a
1606a195726fSgovinda 	 * prom_nextnode(0) because this call ALSO patches the DMA+
1607a195726fSgovinda 	 * bug in Campus-B and Phoenix. The prom uncaches the traptable
1608a195726fSgovinda 	 * page as a side-effect of devr_next(0) (which prom_nextnode calls),
1609a195726fSgovinda 	 * so this *must* be executed early on. (XXX This is untrue for sun4u)
1610a195726fSgovinda 	 */
1611fa9e4066Sahrens 	(void) prom_nextnode((pnode_t)0);
1612a195726fSgovinda #endif
16137c478bd9Sstevel@tonic-gate 
1614a195726fSgovinda 	/*
1615a195726fSgovinda 	 * Initialize devices on the machine.
1616a195726fSgovinda 	 * Uses configuration tree built by the PROMs to determine what
1617a195726fSgovinda 	 * is present, and builds a tree of prototype dev_info nodes
1618a195726fSgovinda 	 * corresponding to the hardware which identified itself.
1619a195726fSgovinda 	 */
1620a195726fSgovinda 	i_ddi_init_root();
16217c478bd9Sstevel@tonic-gate 
1622a195726fSgovinda #ifdef	DDI_PROP_DEBUG
1623a195726fSgovinda 	(void) ddi_prop_debug(1);	/* Enable property debugging */
1624a195726fSgovinda #endif	/* DDI_PROP_DEBUG */
16257c478bd9Sstevel@tonic-gate }
16267c478bd9Sstevel@tonic-gate 
1627a195726fSgovinda /*
1628a195726fSgovinda  * The "status" property indicates the operational status of a device.
1629a195726fSgovinda  * If this property is present, the value is a string indicating the
1630a195726fSgovinda  * status of the device as follows:
1631a195726fSgovinda  *
1632a195726fSgovinda  *	"okay"		operational.
1633a195726fSgovinda  *	"disabled"	not operational, but might become operational.
1634a195726fSgovinda  *	"fail"		not operational because a fault has been detected,
1635a195726fSgovinda  *			and it is unlikely that the device will become
1636a195726fSgovinda  *			operational without repair. no additional details
1637a195726fSgovinda  *			are available.
1638a195726fSgovinda  *	"fail-xxx"	not operational because a fault has been detected,
1639a195726fSgovinda  *			and it is unlikely that the device will become
1640a195726fSgovinda  *			operational without repair. "xxx" is additional
1641a195726fSgovinda  *			human-readable information about the particular
1642a195726fSgovinda  *			fault condition that was detected.
1643a195726fSgovinda  *
1644a195726fSgovinda  * The absence of this property means that the operational status is
1645a195726fSgovinda  * unknown or okay.
1646a195726fSgovinda  *
1647a195726fSgovinda  * This routine checks the status property of the specified device node
1648a195726fSgovinda  * and returns 0 if the operational status indicates failure, and 1 otherwise.
1649a195726fSgovinda  *
1650a195726fSgovinda  * The property may exist on plug-in cards the existed before IEEE 1275-1994.
1651a195726fSgovinda  * And, in that case, the property may not even be a string. So we carefully
1652a195726fSgovinda  * check for the value "fail", in the beginning of the string, noting
1653a195726fSgovinda  * the property length.
1654a195726fSgovinda  */
16557c478bd9Sstevel@tonic-gate int
status_okay(int id,char * buf,int buflen)1656a195726fSgovinda status_okay(int id, char *buf, int buflen)
16577c478bd9Sstevel@tonic-gate {
1658a195726fSgovinda 	char status_buf[OBP_MAXPROPNAME];
1659a195726fSgovinda 	char *bufp = buf;
1660a195726fSgovinda 	int len = buflen;
1661a195726fSgovinda 	int proplen;
1662a195726fSgovinda 	static const char *status = "status";
1663a195726fSgovinda 	static const char *fail = "fail";
1664a195726fSgovinda 	size_t fail_len = strlen(fail);
16657c478bd9Sstevel@tonic-gate 
1666a195726fSgovinda 	/*
1667a195726fSgovinda 	 * Get the proplen ... if it's smaller than "fail",
1668a195726fSgovinda 	 * or doesn't exist ... then we don't care, since
1669a195726fSgovinda 	 * the value can't begin with the char string "fail".
1670a195726fSgovinda 	 *
1671a195726fSgovinda 	 * NB: proplen, if it's a string, includes the NULL in the
1672a195726fSgovinda 	 * the size of the property, and fail_len does not.
1673a195726fSgovinda 	 */
1674fa9e4066Sahrens 	proplen = prom_getproplen((pnode_t)id, (caddr_t)status);
1675a195726fSgovinda 	if (proplen <= fail_len)	/* nonexistent or uninteresting len */
1676a195726fSgovinda 		return (1);
16777c478bd9Sstevel@tonic-gate 
1678a195726fSgovinda 	/*
1679a195726fSgovinda 	 * if a buffer was provided, use it
1680a195726fSgovinda 	 */
1681a195726fSgovinda 	if ((buf == (char *)NULL) || (buflen <= 0)) {
1682a195726fSgovinda 		bufp = status_buf;
1683a195726fSgovinda 		len = sizeof (status_buf);
16847c478bd9Sstevel@tonic-gate 	}
1685a195726fSgovinda 	*bufp = (char)0;
16867c478bd9Sstevel@tonic-gate 
1687a195726fSgovinda 	/*
1688a195726fSgovinda 	 * Get the property into the buffer, to the extent of the buffer,
1689a195726fSgovinda 	 * and in case the buffer is smaller than the property size,
1690a195726fSgovinda 	 * NULL terminate the buffer. (This handles the case where
1691a195726fSgovinda 	 * a buffer was passed in and the caller wants to print the
1692a195726fSgovinda 	 * value, but the buffer was too small).
1693a195726fSgovinda 	 */
1694fa9e4066Sahrens 	(void) prom_bounded_getprop((pnode_t)id, (caddr_t)status,
1695a195726fSgovinda 	    (caddr_t)bufp, len);
1696a195726fSgovinda 	*(bufp + len - 1) = (char)0;
1697a195726fSgovinda 
1698a195726fSgovinda 	/*
1699a195726fSgovinda 	 * If the value begins with the char string "fail",
1700a195726fSgovinda 	 * then it means the node is failed. We don't care
1701a195726fSgovinda 	 * about any other values. We assume the node is ok
1702a195726fSgovinda 	 * although it might be 'disabled'.
1703a195726fSgovinda 	 */
1704a195726fSgovinda 	if (strncmp(bufp, fail, fail_len) == 0)
1705a195726fSgovinda 		return (0);
17067c478bd9Sstevel@tonic-gate 
17077c478bd9Sstevel@tonic-gate 	return (1);
17087c478bd9Sstevel@tonic-gate }
17097c478bd9Sstevel@tonic-gate 
17107c478bd9Sstevel@tonic-gate 
17117c478bd9Sstevel@tonic-gate /*
1712a195726fSgovinda  * We set the cpu type from the idprom, if we can.
1713a195726fSgovinda  * Note that we just read out the contents of it, for the most part.
17147c478bd9Sstevel@tonic-gate  */
1715a195726fSgovinda void
setcputype(void)1716a195726fSgovinda setcputype(void)
1717a195726fSgovinda {
1718a195726fSgovinda 	/*
1719a195726fSgovinda 	 * We cache the idprom info early on so that we don't
1720a195726fSgovinda 	 * rummage through the NVRAM unnecessarily later.
1721a195726fSgovinda 	 */
1722a195726fSgovinda 	(void) prom_getidprom((caddr_t)&idprom, sizeof (idprom));
1723a195726fSgovinda }
17247c478bd9Sstevel@tonic-gate 
17257c478bd9Sstevel@tonic-gate /*
1726a195726fSgovinda  *  Here is where we actually infer meanings to the members of idprom_t
17277c478bd9Sstevel@tonic-gate  */
1728a195726fSgovinda void
parse_idprom(void)1729a195726fSgovinda parse_idprom(void)
17307c478bd9Sstevel@tonic-gate {
1731a195726fSgovinda 	if (idprom.id_format == IDFORM_1) {
1732a195726fSgovinda 		(void) localetheraddr((struct ether_addr *)idprom.id_ether,
1733a195726fSgovinda 		    (struct ether_addr *)NULL);
17345679c89fSjv 		(void) snprintf(hw_serial, HW_HOSTID_LEN, "%u",
17355679c89fSjv 		    (idprom.id_machine << 24) + idprom.id_serial);
1736a195726fSgovinda 	} else
1737a195726fSgovinda 		prom_printf("Invalid format code in IDprom.\n");
17387c478bd9Sstevel@tonic-gate }
17397c478bd9Sstevel@tonic-gate 
17407c478bd9Sstevel@tonic-gate /*
1741a195726fSgovinda  * Allow for implementation specific correction of PROM property values.
17427c478bd9Sstevel@tonic-gate  */
17437c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1744a195726fSgovinda void
impl_fix_props(dev_info_t * dip,dev_info_t * ch_dip,char * name,int len,caddr_t buffer)1745a195726fSgovinda impl_fix_props(dev_info_t *dip, dev_info_t *ch_dip, char *name, int len,
1746a195726fSgovinda     caddr_t buffer)
17477c478bd9Sstevel@tonic-gate {
1748a195726fSgovinda 	/*
1749a195726fSgovinda 	 * There are no adjustments needed in this implementation.
1750a195726fSgovinda 	 */
17517c478bd9Sstevel@tonic-gate }
17527c478bd9Sstevel@tonic-gate 
17537c478bd9Sstevel@tonic-gate /*
17547c478bd9Sstevel@tonic-gate  * The following functions ready a cautious request to go up to the nexus
17557c478bd9Sstevel@tonic-gate  * driver.  It is up to the nexus driver to decide how to process the request.
17567c478bd9Sstevel@tonic-gate  * It may choose to call i_ddi_do_caut_get/put in this file, or do it
17577c478bd9Sstevel@tonic-gate  * differently.
17587c478bd9Sstevel@tonic-gate  */
17597c478bd9Sstevel@tonic-gate 
17607c478bd9Sstevel@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)17617c478bd9Sstevel@tonic-gate i_ddi_caut_getput_ctlops(
17627c478bd9Sstevel@tonic-gate     ddi_acc_impl_t *hp, uint64_t host_addr, uint64_t dev_addr, size_t size,
17637c478bd9Sstevel@tonic-gate     size_t repcount, uint_t flags, ddi_ctl_enum_t cmd)
17647c478bd9Sstevel@tonic-gate {
17657c478bd9Sstevel@tonic-gate 	peekpoke_ctlops_t	cautacc_ctlops_arg;
17667c478bd9Sstevel@tonic-gate 
17677c478bd9Sstevel@tonic-gate 	cautacc_ctlops_arg.size = size;
17687c478bd9Sstevel@tonic-gate 	cautacc_ctlops_arg.dev_addr = dev_addr;
17697c478bd9Sstevel@tonic-gate 	cautacc_ctlops_arg.host_addr = host_addr;
17707c478bd9Sstevel@tonic-gate 	cautacc_ctlops_arg.handle = (ddi_acc_handle_t)hp;
17717c478bd9Sstevel@tonic-gate 	cautacc_ctlops_arg.repcount = repcount;
17727c478bd9Sstevel@tonic-gate 	cautacc_ctlops_arg.flags = flags;
17737c478bd9Sstevel@tonic-gate 
17747c478bd9Sstevel@tonic-gate 	(void) ddi_ctlops(hp->ahi_common.ah_dip, hp->ahi_common.ah_dip, cmd,
17757c478bd9Sstevel@tonic-gate 	    &cautacc_ctlops_arg, NULL);
17767c478bd9Sstevel@tonic-gate }
17777c478bd9Sstevel@tonic-gate 
17787c478bd9Sstevel@tonic-gate uint8_t
i_ddi_caut_get8(ddi_acc_impl_t * hp,uint8_t * addr)17797c478bd9Sstevel@tonic-gate i_ddi_caut_get8(ddi_acc_impl_t *hp, uint8_t *addr)
17807c478bd9Sstevel@tonic-gate {
17817c478bd9Sstevel@tonic-gate 	uint8_t value;
17827c478bd9Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr,
17837c478bd9Sstevel@tonic-gate 	    sizeof (uint8_t), 1, 0, DDI_CTLOPS_PEEK);
17847c478bd9Sstevel@tonic-gate 
17857c478bd9Sstevel@tonic-gate 	return (value);
17867c478bd9Sstevel@tonic-gate }
17877c478bd9Sstevel@tonic-gate 
17887c478bd9Sstevel@tonic-gate uint16_t
i_ddi_caut_get16(ddi_acc_impl_t * hp,uint16_t * addr)17897c478bd9Sstevel@tonic-gate i_ddi_caut_get16(ddi_acc_impl_t *hp, uint16_t *addr)
17907c478bd9Sstevel@tonic-gate {
17917c478bd9Sstevel@tonic-gate 	uint16_t value;
17927c478bd9Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr,
17937c478bd9Sstevel@tonic-gate 	    sizeof (uint16_t), 1, 0, DDI_CTLOPS_PEEK);
17947c478bd9Sstevel@tonic-gate 
17957c478bd9Sstevel@tonic-gate 	return (value);
17967c478bd9Sstevel@tonic-gate }
17977c478bd9Sstevel@tonic-gate 
17987c478bd9Sstevel@tonic-gate uint32_t
i_ddi_caut_get32(ddi_acc_impl_t * hp,uint32_t * addr)17997c478bd9Sstevel@tonic-gate i_ddi_caut_get32(ddi_acc_impl_t *hp, uint32_t *addr)
18007c478bd9Sstevel@tonic-gate {
18017c478bd9Sstevel@tonic-gate 	uint32_t value;
18027c478bd9Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr,
18037c478bd9Sstevel@tonic-gate 	    sizeof (uint32_t), 1, 0, DDI_CTLOPS_PEEK);
18047c478bd9Sstevel@tonic-gate 
18057c478bd9Sstevel@tonic-gate 	return (value);
18067c478bd9Sstevel@tonic-gate }
18077c478bd9Sstevel@tonic-gate 
18087c478bd9Sstevel@tonic-gate uint64_t
i_ddi_caut_get64(ddi_acc_impl_t * hp,uint64_t * addr)18097c478bd9Sstevel@tonic-gate i_ddi_caut_get64(ddi_acc_impl_t *hp, uint64_t *addr)
18107c478bd9Sstevel@tonic-gate {
18117c478bd9Sstevel@tonic-gate 	uint64_t value;
18127c478bd9Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr,
18137c478bd9Sstevel@tonic-gate 	    sizeof (uint64_t), 1, 0, DDI_CTLOPS_PEEK);
18147c478bd9Sstevel@tonic-gate 
18157c478bd9Sstevel@tonic-gate 	return (value);
18167c478bd9Sstevel@tonic-gate }
18177c478bd9Sstevel@tonic-gate 
18187c478bd9Sstevel@tonic-gate void
i_ddi_caut_put8(ddi_acc_impl_t * hp,uint8_t * addr,uint8_t value)18197c478bd9Sstevel@tonic-gate i_ddi_caut_put8(ddi_acc_impl_t *hp, uint8_t *addr, uint8_t value)
18207c478bd9Sstevel@tonic-gate {
18217c478bd9Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr,
18227c478bd9Sstevel@tonic-gate 	    sizeof (uint8_t), 1, 0, DDI_CTLOPS_POKE);
18237c478bd9Sstevel@tonic-gate }
18247c478bd9Sstevel@tonic-gate 
18257c478bd9Sstevel@tonic-gate void
i_ddi_caut_put16(ddi_acc_impl_t * hp,uint16_t * addr,uint16_t value)18267c478bd9Sstevel@tonic-gate i_ddi_caut_put16(ddi_acc_impl_t *hp, uint16_t *addr, uint16_t value)
18277c478bd9Sstevel@tonic-gate {
18287c478bd9Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr,
18297c478bd9Sstevel@tonic-gate 	    sizeof (uint16_t), 1, 0, DDI_CTLOPS_POKE);
18307c478bd9Sstevel@tonic-gate }
18317c478bd9Sstevel@tonic-gate 
18327c478bd9Sstevel@tonic-gate void
i_ddi_caut_put32(ddi_acc_impl_t * hp,uint32_t * addr,uint32_t value)18337c478bd9Sstevel@tonic-gate i_ddi_caut_put32(ddi_acc_impl_t *hp, uint32_t *addr, uint32_t value)
18347c478bd9Sstevel@tonic-gate {
18357c478bd9Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr,
18367c478bd9Sstevel@tonic-gate 	    sizeof (uint32_t), 1, 0, DDI_CTLOPS_POKE);
18377c478bd9Sstevel@tonic-gate }
18387c478bd9Sstevel@tonic-gate 
18397c478bd9Sstevel@tonic-gate void
i_ddi_caut_put64(ddi_acc_impl_t * hp,uint64_t * addr,uint64_t value)18407c478bd9Sstevel@tonic-gate i_ddi_caut_put64(ddi_acc_impl_t *hp, uint64_t *addr, uint64_t value)
18417c478bd9Sstevel@tonic-gate {
18427c478bd9Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)&value, (uint64_t)addr,
18437c478bd9Sstevel@tonic-gate 	    sizeof (uint64_t), 1, 0, DDI_CTLOPS_POKE);
18447c478bd9Sstevel@tonic-gate }
18457c478bd9Sstevel@tonic-gate 
18467c478bd9Sstevel@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)18477c478bd9Sstevel@tonic-gate i_ddi_caut_rep_get8(ddi_acc_impl_t *hp, uint8_t *host_addr, uint8_t *dev_addr,
18487c478bd9Sstevel@tonic-gate 	size_t repcount, uint_t flags)
18497c478bd9Sstevel@tonic-gate {
18507c478bd9Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr,
18517c478bd9Sstevel@tonic-gate 	    sizeof (uint8_t), repcount, flags, DDI_CTLOPS_PEEK);
18527c478bd9Sstevel@tonic-gate }
18537c478bd9Sstevel@tonic-gate 
18547c478bd9Sstevel@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)18557c478bd9Sstevel@tonic-gate i_ddi_caut_rep_get16(ddi_acc_impl_t *hp, uint16_t *host_addr,
18567c478bd9Sstevel@tonic-gate     uint16_t *dev_addr, size_t repcount, uint_t flags)
18577c478bd9Sstevel@tonic-gate {
18587c478bd9Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr,
18597c478bd9Sstevel@tonic-gate 	    sizeof (uint16_t), repcount, flags, DDI_CTLOPS_PEEK);
18607c478bd9Sstevel@tonic-gate }
18617c478bd9Sstevel@tonic-gate 
18627c478bd9Sstevel@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)18637c478bd9Sstevel@tonic-gate i_ddi_caut_rep_get32(ddi_acc_impl_t *hp, uint32_t *host_addr,
18647c478bd9Sstevel@tonic-gate     uint32_t *dev_addr, size_t repcount, uint_t flags)
18657c478bd9Sstevel@tonic-gate {
18667c478bd9Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr,
18677c478bd9Sstevel@tonic-gate 	    sizeof (uint32_t), repcount, flags, DDI_CTLOPS_PEEK);
18687c478bd9Sstevel@tonic-gate }
18697c478bd9Sstevel@tonic-gate 
18707c478bd9Sstevel@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)18717c478bd9Sstevel@tonic-gate i_ddi_caut_rep_get64(ddi_acc_impl_t *hp, uint64_t *host_addr,
18727c478bd9Sstevel@tonic-gate     uint64_t *dev_addr, size_t repcount, uint_t flags)
18737c478bd9Sstevel@tonic-gate {
18747c478bd9Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr,
18757c478bd9Sstevel@tonic-gate 	    sizeof (uint64_t), repcount, flags, DDI_CTLOPS_PEEK);
18767c478bd9Sstevel@tonic-gate }
18777c478bd9Sstevel@tonic-gate 
18787c478bd9Sstevel@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)18797c478bd9Sstevel@tonic-gate i_ddi_caut_rep_put8(ddi_acc_impl_t *hp, uint8_t *host_addr, uint8_t *dev_addr,
18807c478bd9Sstevel@tonic-gate 	size_t repcount, uint_t flags)
18817c478bd9Sstevel@tonic-gate {
18827c478bd9Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr,
18837c478bd9Sstevel@tonic-gate 	    sizeof (uint8_t), repcount, flags, DDI_CTLOPS_POKE);
18847c478bd9Sstevel@tonic-gate }
18857c478bd9Sstevel@tonic-gate 
18867c478bd9Sstevel@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)18877c478bd9Sstevel@tonic-gate i_ddi_caut_rep_put16(ddi_acc_impl_t *hp, uint16_t *host_addr,
18887c478bd9Sstevel@tonic-gate     uint16_t *dev_addr, size_t repcount, uint_t flags)
18897c478bd9Sstevel@tonic-gate {
18907c478bd9Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr,
18917c478bd9Sstevel@tonic-gate 	    sizeof (uint16_t), repcount, flags, DDI_CTLOPS_POKE);
18927c478bd9Sstevel@tonic-gate }
18937c478bd9Sstevel@tonic-gate 
18947c478bd9Sstevel@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)18957c478bd9Sstevel@tonic-gate i_ddi_caut_rep_put32(ddi_acc_impl_t *hp, uint32_t *host_addr,
18967c478bd9Sstevel@tonic-gate     uint32_t *dev_addr, size_t repcount, uint_t flags)
18977c478bd9Sstevel@tonic-gate {
18987c478bd9Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr,
18997c478bd9Sstevel@tonic-gate 	    sizeof (uint32_t), repcount, flags, DDI_CTLOPS_POKE);
19007c478bd9Sstevel@tonic-gate }
19017c478bd9Sstevel@tonic-gate 
19027c478bd9Sstevel@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)19037c478bd9Sstevel@tonic-gate i_ddi_caut_rep_put64(ddi_acc_impl_t *hp, uint64_t *host_addr,
19047c478bd9Sstevel@tonic-gate     uint64_t *dev_addr, size_t repcount, uint_t flags)
19057c478bd9Sstevel@tonic-gate {
19067c478bd9Sstevel@tonic-gate 	i_ddi_caut_getput_ctlops(hp, (uint64_t)host_addr, (uint64_t)dev_addr,
19077c478bd9Sstevel@tonic-gate 	    sizeof (uint64_t), repcount, flags, DDI_CTLOPS_POKE);
19087c478bd9Sstevel@tonic-gate }
19097c478bd9Sstevel@tonic-gate 
19107c478bd9Sstevel@tonic-gate /*
19117c478bd9Sstevel@tonic-gate  * This is called only to process peek/poke when the DIP is NULL.
19127c478bd9Sstevel@tonic-gate  * Assume that this is for memory, as nexi take care of device safe accesses.
19137c478bd9Sstevel@tonic-gate  */
19147c478bd9Sstevel@tonic-gate int
peekpoke_mem(ddi_ctl_enum_t cmd,peekpoke_ctlops_t * in_args)19157c478bd9Sstevel@tonic-gate peekpoke_mem(ddi_ctl_enum_t cmd, peekpoke_ctlops_t *in_args)
19167c478bd9Sstevel@tonic-gate {
19177c478bd9Sstevel@tonic-gate 	int err = DDI_SUCCESS;
19187c478bd9Sstevel@tonic-gate 	on_trap_data_t otd;
19197c478bd9Sstevel@tonic-gate 
19207c478bd9Sstevel@tonic-gate 	/* Set up protected environment. */
19217c478bd9Sstevel@tonic-gate 	if (!on_trap(&otd, OT_DATA_ACCESS)) {
19227c478bd9Sstevel@tonic-gate 		uintptr_t tramp = otd.ot_trampoline;
19237c478bd9Sstevel@tonic-gate 
19247c478bd9Sstevel@tonic-gate 		if (cmd == DDI_CTLOPS_POKE) {
19257c478bd9Sstevel@tonic-gate 			otd.ot_trampoline = (uintptr_t)&poke_fault;
19267c478bd9Sstevel@tonic-gate 			err = do_poke(in_args->size, (void *)in_args->dev_addr,
19277c478bd9Sstevel@tonic-gate 			    (void *)in_args->host_addr);
19287c478bd9Sstevel@tonic-gate 		} else {
19297c478bd9Sstevel@tonic-gate 			otd.ot_trampoline = (uintptr_t)&peek_fault;
19307c478bd9Sstevel@tonic-gate 			err = do_peek(in_args->size, (void *)in_args->dev_addr,
19317c478bd9Sstevel@tonic-gate 			    (void *)in_args->host_addr);
19327c478bd9Sstevel@tonic-gate 		}
19337c478bd9Sstevel@tonic-gate 		otd.ot_trampoline = tramp;
19347c478bd9Sstevel@tonic-gate 	} else
19357c478bd9Sstevel@tonic-gate 		err = DDI_FAILURE;
19367c478bd9Sstevel@tonic-gate 
19377c478bd9Sstevel@tonic-gate 	/* Take down protected environment. */
19387c478bd9Sstevel@tonic-gate 	no_trap();
19397c478bd9Sstevel@tonic-gate 
19407c478bd9Sstevel@tonic-gate 	return (err);
19417c478bd9Sstevel@tonic-gate }
1942