xref: /illumos-gate/usr/src/uts/sun4u/opl/io/drmach.c (revision bbe1232e)
125cf1a30Sjl /*
225cf1a30Sjl  * CDDL HEADER START
325cf1a30Sjl  *
425cf1a30Sjl  * The contents of this file are subject to the terms of the
525cf1a30Sjl  * Common Development and Distribution License (the "License").
625cf1a30Sjl  * You may not use this file except in compliance with the License.
725cf1a30Sjl  *
825cf1a30Sjl  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
925cf1a30Sjl  * or http://www.opensolaris.org/os/licensing.
1025cf1a30Sjl  * See the License for the specific language governing permissions
1125cf1a30Sjl  * and limitations under the License.
1225cf1a30Sjl  *
1325cf1a30Sjl  * When distributing Covered Code, include this CDDL HEADER in each
1425cf1a30Sjl  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1525cf1a30Sjl  * If applicable, add the following below this CDDL HEADER, with the
1625cf1a30Sjl  * fields enclosed by brackets "[]" replaced with your own identifying
1725cf1a30Sjl  * information: Portions Copyright [yyyy] [name of copyright owner]
1825cf1a30Sjl  *
1925cf1a30Sjl  * CDDL HEADER END
2025cf1a30Sjl  */
2107d06da5SSurya Prakki 
2225cf1a30Sjl /*
2356f33205SJonathan Adams  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
2425cf1a30Sjl  * Use is subject to license terms.
2525cf1a30Sjl  */
2625cf1a30Sjl 
2725cf1a30Sjl #include <sys/debug.h>
2825cf1a30Sjl #include <sys/types.h>
2925cf1a30Sjl #include <sys/varargs.h>
3025cf1a30Sjl #include <sys/errno.h>
3125cf1a30Sjl #include <sys/cred.h>
3225cf1a30Sjl #include <sys/dditypes.h>
3325cf1a30Sjl #include <sys/devops.h>
3425cf1a30Sjl #include <sys/modctl.h>
3525cf1a30Sjl #include <sys/poll.h>
3625cf1a30Sjl #include <sys/conf.h>
3725cf1a30Sjl #include <sys/ddi.h>
3825cf1a30Sjl #include <sys/sunddi.h>
3925cf1a30Sjl #include <sys/sunndi.h>
4025cf1a30Sjl #include <sys/ndi_impldefs.h>
4125cf1a30Sjl #include <sys/stat.h>
4225cf1a30Sjl #include <sys/kmem.h>
4325cf1a30Sjl #include <sys/vmem.h>
4425cf1a30Sjl #include <sys/opl_olympus_regs.h>
4525cf1a30Sjl #include <sys/cpuvar.h>
4625cf1a30Sjl #include <sys/cpupart.h>
4725cf1a30Sjl #include <sys/mem_config.h>
4825cf1a30Sjl #include <sys/ddi_impldefs.h>
4925cf1a30Sjl #include <sys/systm.h>
5025cf1a30Sjl #include <sys/machsystm.h>
5125cf1a30Sjl #include <sys/autoconf.h>
5225cf1a30Sjl #include <sys/cmn_err.h>
5325cf1a30Sjl #include <sys/sysmacros.h>
5425cf1a30Sjl #include <sys/x_call.h>
5525cf1a30Sjl #include <sys/promif.h>
5625cf1a30Sjl #include <sys/prom_plat.h>
5725cf1a30Sjl #include <sys/membar.h>
5825cf1a30Sjl #include <vm/seg_kmem.h>
5925cf1a30Sjl #include <sys/mem_cage.h>
6025cf1a30Sjl #include <sys/stack.h>
6125cf1a30Sjl #include <sys/archsystm.h>
6225cf1a30Sjl #include <vm/hat_sfmmu.h>
6325cf1a30Sjl #include <sys/pte.h>
6425cf1a30Sjl #include <sys/mmu.h>
6525cf1a30Sjl #include <sys/cpu_module.h>
6625cf1a30Sjl #include <sys/obpdefs.h>
6725cf1a30Sjl #include <sys/note.h>
6825cf1a30Sjl #include <sys/ontrap.h>
6925cf1a30Sjl #include <sys/cpu_sgnblk_defs.h>
7025cf1a30Sjl #include <sys/opl.h>
71e98fafb9Sjl #include <sys/cpu_impl.h>
7225cf1a30Sjl 
7325cf1a30Sjl 
7425cf1a30Sjl #include <sys/promimpl.h>
7525cf1a30Sjl #include <sys/prom_plat.h>
7625cf1a30Sjl #include <sys/kobj.h>
7725cf1a30Sjl 
7825cf1a30Sjl #include <sys/sysevent.h>
7925cf1a30Sjl #include <sys/sysevent/dr.h>
8025cf1a30Sjl #include <sys/sysevent/eventdefs.h>
8125cf1a30Sjl 
8225cf1a30Sjl #include <sys/drmach.h>
8325cf1a30Sjl #include <sys/dr_util.h>
8425cf1a30Sjl 
8525cf1a30Sjl #include <sys/fcode.h>
8625cf1a30Sjl #include <sys/opl_cfg.h>
8725cf1a30Sjl 
8825cf1a30Sjl extern void		bcopy32_il(uint64_t, uint64_t);
8925cf1a30Sjl extern void		flush_cache_il(void);
9025cf1a30Sjl extern void		drmach_sleep_il(void);
9125cf1a30Sjl 
9225cf1a30Sjl typedef struct {
9325cf1a30Sjl 	struct drmach_node	*node;
9425cf1a30Sjl 	void			*data;
9525cf1a30Sjl } drmach_node_walk_args_t;
9625cf1a30Sjl 
9725cf1a30Sjl typedef struct drmach_node {
9825cf1a30Sjl 	void		*here;
9925cf1a30Sjl 
10025cf1a30Sjl 	pnode_t		(*get_dnode)(struct drmach_node *node);
10125cf1a30Sjl 	int		(*walk)(struct drmach_node *node, void *data,
10225cf1a30Sjl 				int (*cb)(drmach_node_walk_args_t *args));
10325cf1a30Sjl 	dev_info_t	*(*n_getdip)(struct drmach_node *node);
10425cf1a30Sjl 	int		(*n_getproplen)(struct drmach_node *node, char *name,
10525cf1a30Sjl 				int *len);
10625cf1a30Sjl 	int		(*n_getprop)(struct drmach_node *node, char *name,
10725cf1a30Sjl 				void *buf, int len);
10825cf1a30Sjl 	int		(*get_parent)(struct drmach_node *node,
10925cf1a30Sjl 				struct drmach_node *pnode);
11025cf1a30Sjl } drmach_node_t;
11125cf1a30Sjl 
11225cf1a30Sjl typedef struct {
11325cf1a30Sjl 	int		 min_index;
11425cf1a30Sjl 	int		 max_index;
11525cf1a30Sjl 	int		 arr_sz;
11625cf1a30Sjl 	drmachid_t	*arr;
11725cf1a30Sjl } drmach_array_t;
11825cf1a30Sjl 
11925cf1a30Sjl typedef struct {
12025cf1a30Sjl 	void		*isa;
12125cf1a30Sjl 
12225cf1a30Sjl 	void		(*dispose)(drmachid_t);
12325cf1a30Sjl 	sbd_error_t	*(*release)(drmachid_t);
12425cf1a30Sjl 	sbd_error_t	*(*status)(drmachid_t, drmach_status_t *);
12525cf1a30Sjl 
12625cf1a30Sjl 	char		 name[MAXNAMELEN];
12725cf1a30Sjl } drmach_common_t;
12825cf1a30Sjl 
12925cf1a30Sjl typedef	struct {
13025cf1a30Sjl 	uint32_t	core_present;
13125cf1a30Sjl 	uint32_t	core_hotadded;
13225cf1a30Sjl 	uint32_t	core_started;
13325cf1a30Sjl } drmach_cmp_t;
13425cf1a30Sjl 
13525cf1a30Sjl typedef struct {
13625cf1a30Sjl 	drmach_common_t	 cm;
13725cf1a30Sjl 	int		 bnum;
13825cf1a30Sjl 	int		 assigned;
13925cf1a30Sjl 	int		 powered;
14025cf1a30Sjl 	int		 connected;
14125cf1a30Sjl 	int		 cond;
14225cf1a30Sjl 	drmach_node_t	*tree;
14325cf1a30Sjl 	drmach_array_t	*devices;
14425cf1a30Sjl 	int		boot_board;	/* if board exists on bootup */
14525cf1a30Sjl 	drmach_cmp_t	cores[OPL_MAX_COREID_PER_BOARD];
14625cf1a30Sjl } drmach_board_t;
14725cf1a30Sjl 
14825cf1a30Sjl typedef struct {
14925cf1a30Sjl 	drmach_common_t	 cm;
15025cf1a30Sjl 	drmach_board_t	*bp;
15125cf1a30Sjl 	int		 unum;
15225cf1a30Sjl 	int		portid;
15325cf1a30Sjl 	int		 busy;
15425cf1a30Sjl 	int		 powered;
15525cf1a30Sjl 	const char	*type;
15625cf1a30Sjl 	drmach_node_t	*node;
15725cf1a30Sjl } drmach_device_t;
15825cf1a30Sjl 
15925cf1a30Sjl typedef struct drmach_cpu {
16025cf1a30Sjl 	drmach_device_t  dev;
16125cf1a30Sjl 	processorid_t    cpuid;
16225cf1a30Sjl 	int		sb;
16325cf1a30Sjl 	int		chipid;
16425cf1a30Sjl 	int		coreid;
16525cf1a30Sjl 	int		strandid;
16625cf1a30Sjl 	int		status;
16725cf1a30Sjl #define	OPL_CPU_HOTADDED	1
16825cf1a30Sjl } drmach_cpu_t;
16925cf1a30Sjl 
17025cf1a30Sjl typedef struct drmach_mem {
17125cf1a30Sjl 	drmach_device_t  dev;
17225cf1a30Sjl 	uint64_t	slice_base;
17325cf1a30Sjl 	uint64_t	slice_size;
17425cf1a30Sjl 	uint64_t	base_pa;	/* lowest installed memory base */
17525cf1a30Sjl 	uint64_t	nbytes;		/* size of installed memory */
17625cf1a30Sjl 	struct memlist *memlist;
17725cf1a30Sjl } drmach_mem_t;
17825cf1a30Sjl 
17925cf1a30Sjl typedef struct drmach_io {
18025cf1a30Sjl 	drmach_device_t  dev;
18125cf1a30Sjl 	int	channel;
18225cf1a30Sjl 	int	leaf;
18325cf1a30Sjl } drmach_io_t;
18425cf1a30Sjl 
18525cf1a30Sjl typedef struct drmach_domain_info {
18625cf1a30Sjl 	uint32_t	floating;
18725cf1a30Sjl 	int		allow_dr;
18825cf1a30Sjl } drmach_domain_info_t;
18925cf1a30Sjl 
19025cf1a30Sjl drmach_domain_info_t drmach_domain;
19125cf1a30Sjl 
19225cf1a30Sjl typedef struct {
19325cf1a30Sjl 	int		 flags;
19425cf1a30Sjl 	drmach_device_t	*dp;
19525cf1a30Sjl 	sbd_error_t	*err;
19625cf1a30Sjl 	dev_info_t	*dip;
19725cf1a30Sjl } drmach_config_args_t;
19825cf1a30Sjl 
19925cf1a30Sjl typedef struct {
20025cf1a30Sjl 	drmach_board_t	*obj;
20125cf1a30Sjl 	int		 ndevs;
20225cf1a30Sjl 	void		*a;
20325cf1a30Sjl 	sbd_error_t	*(*found)(void *a, const char *, int, drmachid_t);
20425cf1a30Sjl 	sbd_error_t	*err;
20525cf1a30Sjl } drmach_board_cb_data_t;
20625cf1a30Sjl 
20725cf1a30Sjl static drmach_array_t	*drmach_boards;
20825cf1a30Sjl 
20925cf1a30Sjl static sbd_error_t	*drmach_device_new(drmach_node_t *,
21025cf1a30Sjl 				drmach_board_t *, int, drmachid_t *);
21125cf1a30Sjl static sbd_error_t	*drmach_cpu_new(drmach_device_t *, drmachid_t *);
21225cf1a30Sjl static sbd_error_t	*drmach_mem_new(drmach_device_t *, drmachid_t *);
21325cf1a30Sjl static sbd_error_t	*drmach_io_new(drmach_device_t *, drmachid_t *);
21425cf1a30Sjl 
21525cf1a30Sjl static dev_info_t	*drmach_node_ddi_get_dip(drmach_node_t *np);
21625cf1a30Sjl static int		 drmach_node_ddi_get_prop(drmach_node_t *np,
21725cf1a30Sjl 				char *name, void *buf, int len);
21825cf1a30Sjl static int		 drmach_node_ddi_get_proplen(drmach_node_t *np,
21925cf1a30Sjl 				char *name, int *len);
22025cf1a30Sjl 
221*bbe1232eSToomas Soome static int		drmach_get_portid(drmach_node_t *);
22225cf1a30Sjl static	sbd_error_t	*drmach_i_status(drmachid_t, drmach_status_t *);
22325cf1a30Sjl static int		opl_check_dr_status();
22425cf1a30Sjl static void		drmach_io_dispose(drmachid_t);
22525cf1a30Sjl static sbd_error_t	*drmach_io_release(drmachid_t);
22625cf1a30Sjl static sbd_error_t	*drmach_io_status(drmachid_t, drmach_status_t *);
227*bbe1232eSToomas Soome static int		drmach_init(void);
228*bbe1232eSToomas Soome static void		drmach_fini(void);
22925cf1a30Sjl static void		drmach_swap_pa(drmach_mem_t *, drmach_mem_t *);
23025cf1a30Sjl static drmach_board_t	*drmach_get_board_by_bnum(int);
23125cf1a30Sjl 
2328682d1efSRichard Lowe static sbd_error_t	*drmach_board_release(drmachid_t);
2338682d1efSRichard Lowe static sbd_error_t	*drmach_board_status(drmachid_t, drmach_status_t *);
2348682d1efSRichard Lowe static void		drmach_cpu_dispose(drmachid_t);
2358682d1efSRichard Lowe static sbd_error_t	*drmach_cpu_release(drmachid_t);
2368682d1efSRichard Lowe static sbd_error_t	*drmach_cpu_status(drmachid_t, drmach_status_t *);
2378682d1efSRichard Lowe static void		drmach_mem_dispose(drmachid_t);
2388682d1efSRichard Lowe static sbd_error_t	*drmach_mem_release(drmachid_t);
2398682d1efSRichard Lowe static sbd_error_t	*drmach_mem_status(drmachid_t, drmach_status_t *);
2408682d1efSRichard Lowe 
24125cf1a30Sjl /* options for the second argument in drmach_add_remove_cpu() */
24225cf1a30Sjl #define	HOTADD_CPU	1
24325cf1a30Sjl #define	HOTREMOVE_CPU	2
24425cf1a30Sjl 
24525cf1a30Sjl #define	ON_BOARD_CORE_NUM(x)	(((uint_t)(x) / OPL_MAX_STRANDID_PER_CORE) & \
24625cf1a30Sjl 	(OPL_MAX_COREID_PER_BOARD - 1))
24725cf1a30Sjl 
24825cf1a30Sjl extern struct cpu	*SIGBCPU;
24925cf1a30Sjl 
25025cf1a30Sjl static int		drmach_name2type_idx(char *);
25125cf1a30Sjl static drmach_board_t	*drmach_board_new(int, int);
25225cf1a30Sjl 
25325cf1a30Sjl #ifdef DEBUG
25425cf1a30Sjl 
25525cf1a30Sjl #define	DRMACH_PR		if (drmach_debug) printf
25625cf1a30Sjl int drmach_debug = 1;		 /* set to non-zero to enable debug messages */
25725cf1a30Sjl #else
25825cf1a30Sjl 
25925cf1a30Sjl #define	DRMACH_PR		_NOTE(CONSTANTCONDITION) if (0) printf
26025cf1a30Sjl #endif /* DEBUG */
26125cf1a30Sjl 
26225cf1a30Sjl 
26325cf1a30Sjl #define	DRMACH_OBJ(id)		((drmach_common_t *)id)
26425cf1a30Sjl 
265ddf95635Sbm #define	DRMACH_NULL_ID(id)	((id) == 0)
266ddf95635Sbm 
26725cf1a30Sjl #define	DRMACH_IS_BOARD_ID(id)	\
26825cf1a30Sjl 	((id != 0) &&		\
26925cf1a30Sjl 	(DRMACH_OBJ(id)->isa == (void *)drmach_board_new))
27025cf1a30Sjl 
27125cf1a30Sjl #define	DRMACH_IS_CPU_ID(id)	\
27225cf1a30Sjl 	((id != 0) &&		\
27325cf1a30Sjl 	(DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new))
27425cf1a30Sjl 
27525cf1a30Sjl #define	DRMACH_IS_MEM_ID(id)	\
27625cf1a30Sjl 	((id != 0) &&		\
27725cf1a30Sjl 	(DRMACH_OBJ(id)->isa == (void *)drmach_mem_new))
27825cf1a30Sjl 
27925cf1a30Sjl #define	DRMACH_IS_IO_ID(id)	\
28025cf1a30Sjl 	((id != 0) &&		\
28125cf1a30Sjl 	(DRMACH_OBJ(id)->isa == (void *)drmach_io_new))
28225cf1a30Sjl 
28325cf1a30Sjl #define	DRMACH_IS_DEVICE_ID(id)					\
28425cf1a30Sjl 	((id != 0) &&						\
28525cf1a30Sjl 	(DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new ||	\
28625cf1a30Sjl 	    DRMACH_OBJ(id)->isa == (void *)drmach_mem_new ||	\
28725cf1a30Sjl 	    DRMACH_OBJ(id)->isa == (void *)drmach_io_new))
28825cf1a30Sjl 
28925cf1a30Sjl #define	DRMACH_IS_ID(id)					\
29025cf1a30Sjl 	((id != 0) &&						\
29125cf1a30Sjl 	(DRMACH_OBJ(id)->isa == (void *)drmach_board_new ||	\
29225cf1a30Sjl 	    DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new ||	\
29325cf1a30Sjl 	    DRMACH_OBJ(id)->isa == (void *)drmach_mem_new ||	\
29425cf1a30Sjl 	    DRMACH_OBJ(id)->isa == (void *)drmach_io_new))
29525cf1a30Sjl 
29625cf1a30Sjl #define	DRMACH_INTERNAL_ERROR() \
29725cf1a30Sjl 	drerr_new(1, EOPL_INTERNAL, drmach_ie_fmt, __LINE__)
29825cf1a30Sjl 
29925cf1a30Sjl static char		*drmach_ie_fmt = "drmach.c %d";
30025cf1a30Sjl 
30125cf1a30Sjl static struct {
30225cf1a30Sjl 	const char	*name;
30325cf1a30Sjl 	const char	*type;
30425cf1a30Sjl 	sbd_error_t	*(*new)(drmach_device_t *, drmachid_t *);
30525cf1a30Sjl } drmach_name2type[] = {
30625cf1a30Sjl 	{ "cpu",	DRMACH_DEVTYPE_CPU,		drmach_cpu_new },
30725cf1a30Sjl 	{ "pseudo-mc",	DRMACH_DEVTYPE_MEM,		drmach_mem_new },
30825cf1a30Sjl 	{ "pci",	DRMACH_DEVTYPE_PCI,		drmach_io_new  },
30925cf1a30Sjl };
31025cf1a30Sjl 
31125cf1a30Sjl /* utility */
31225cf1a30Sjl #define	MBYTE	(1048576ull)
31325cf1a30Sjl 
31425cf1a30Sjl /*
31525cf1a30Sjl  * drmach autoconfiguration data structures and interfaces
31625cf1a30Sjl  */
31725cf1a30Sjl 
31825cf1a30Sjl extern struct mod_ops mod_miscops;
31925cf1a30Sjl 
32025cf1a30Sjl static struct modlmisc modlmisc = {
32125cf1a30Sjl 	&mod_miscops,
32225cf1a30Sjl 	"OPL DR 1.1"
32325cf1a30Sjl };
32425cf1a30Sjl 
32525cf1a30Sjl static struct modlinkage modlinkage = {
32625cf1a30Sjl 	MODREV_1,
32725cf1a30Sjl 	(void *)&modlmisc,
32825cf1a30Sjl 	NULL
32925cf1a30Sjl };
33025cf1a30Sjl 
33125cf1a30Sjl static krwlock_t drmach_boards_rwlock;
33225cf1a30Sjl 
33325cf1a30Sjl typedef const char	*fn_t;
33425cf1a30Sjl 
33525cf1a30Sjl int
_init(void)33625cf1a30Sjl _init(void)
33725cf1a30Sjl {
33825cf1a30Sjl 	int err;
33925cf1a30Sjl 
34025cf1a30Sjl 	if ((err = drmach_init()) != 0) {
34125cf1a30Sjl 		return (err);
34225cf1a30Sjl 	}
34325cf1a30Sjl 
34425cf1a30Sjl 	if ((err = mod_install(&modlinkage)) != 0) {
34525cf1a30Sjl 		drmach_fini();
34625cf1a30Sjl 	}
34725cf1a30Sjl 
34825cf1a30Sjl 	return (err);
34925cf1a30Sjl }
35025cf1a30Sjl 
35125cf1a30Sjl int
_fini(void)35225cf1a30Sjl _fini(void)
35325cf1a30Sjl {
35425cf1a30Sjl 	int	err;
35525cf1a30Sjl 
35625cf1a30Sjl 	if ((err = mod_remove(&modlinkage)) == 0)
35725cf1a30Sjl 		drmach_fini();
35825cf1a30Sjl 
35925cf1a30Sjl 	return (err);
36025cf1a30Sjl }
36125cf1a30Sjl 
36225cf1a30Sjl int
_info(struct modinfo * modinfop)36325cf1a30Sjl _info(struct modinfo *modinfop)
36425cf1a30Sjl {
36525cf1a30Sjl 	return (mod_info(&modlinkage, modinfop));
36625cf1a30Sjl }
36725cf1a30Sjl 
36825cf1a30Sjl struct drmach_mc_lookup {
36925cf1a30Sjl 	int	bnum;
37025cf1a30Sjl 	drmach_board_t	*bp;
37125cf1a30Sjl 	dev_info_t *dip;	/* rv - set if found */
37225cf1a30Sjl };
37325cf1a30Sjl 
37425cf1a30Sjl #define	_ptob64(p) ((uint64_t)(p) << PAGESHIFT)
37525cf1a30Sjl #define	_b64top(b) ((pgcnt_t)((b) >> PAGESHIFT))
37625cf1a30Sjl 
37725cf1a30Sjl static int
drmach_setup_mc_info(dev_info_t * dip,drmach_mem_t * mp)37825cf1a30Sjl drmach_setup_mc_info(dev_info_t *dip, drmach_mem_t *mp)
37925cf1a30Sjl {
38025cf1a30Sjl 	uint64_t	memory_ranges[128];
38125cf1a30Sjl 	int len;
38225cf1a30Sjl 	struct memlist	*ml;
38325cf1a30Sjl 	int rv;
38425cf1a30Sjl 	hwd_sb_t *hwd;
38525cf1a30Sjl 	hwd_memory_t *pm;
38625cf1a30Sjl 
38725cf1a30Sjl 	len = sizeof (memory_ranges);
388e98fafb9Sjl 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
389e98fafb9Sjl 	    "sb-mem-ranges", (caddr_t)&memory_ranges[0], &len) !=
390e98fafb9Sjl 	    DDI_PROP_SUCCESS) {
39125cf1a30Sjl 		mp->slice_base = 0;
39225cf1a30Sjl 		mp->slice_size = 0;
39325cf1a30Sjl 		return (-1);
39425cf1a30Sjl 	}
39525cf1a30Sjl 	mp->slice_base = memory_ranges[0];
39625cf1a30Sjl 	mp->slice_size = memory_ranges[1];
39725cf1a30Sjl 
39825cf1a30Sjl 	if (!mp->dev.bp->boot_board) {
39925cf1a30Sjl 		int i;
40025cf1a30Sjl 
40125cf1a30Sjl 		rv = opl_read_hwd(mp->dev.bp->bnum, NULL,  NULL, NULL, &hwd);
40225cf1a30Sjl 
40325cf1a30Sjl 		if (rv != 0) {
40425cf1a30Sjl 			return (-1);
40525cf1a30Sjl 		}
40625cf1a30Sjl 
40725cf1a30Sjl 		ml = NULL;
40825cf1a30Sjl 		pm = &hwd->sb_cmu.cmu_memory;
40925cf1a30Sjl 		for (i = 0; i < HWD_MAX_MEM_CHUNKS; i++) {
41025cf1a30Sjl 			if (pm->mem_chunks[i].chnk_size > 0) {
41125cf1a30Sjl 				ml = memlist_add_span(ml,
412e98fafb9Sjl 				    pm->mem_chunks[i].chnk_start_address,
413e98fafb9Sjl 				    pm->mem_chunks[i].chnk_size);
41425cf1a30Sjl 			}
41525cf1a30Sjl 		}
41625cf1a30Sjl 	} else {
41725cf1a30Sjl 		/*
41825cf1a30Sjl 		 * we intersect phys_install to get base_pa.
41925cf1a30Sjl 		 * This only works at bootup time.
42025cf1a30Sjl 		 */
42125cf1a30Sjl 
42225cf1a30Sjl 		memlist_read_lock();
42325cf1a30Sjl 		ml = memlist_dup(phys_install);
42425cf1a30Sjl 		memlist_read_unlock();
42525cf1a30Sjl 
42625cf1a30Sjl 		ml = memlist_del_span(ml, 0ull, mp->slice_base);
42725cf1a30Sjl 		if (ml) {
42825cf1a30Sjl 			uint64_t basepa, endpa;
42925cf1a30Sjl 			endpa = _ptob64(physmax + 1);
43025cf1a30Sjl 
43125cf1a30Sjl 			basepa = mp->slice_base + mp->slice_size;
43225cf1a30Sjl 
43325cf1a30Sjl 			ml = memlist_del_span(ml, basepa, endpa - basepa);
43425cf1a30Sjl 		}
43525cf1a30Sjl 	}
43625cf1a30Sjl 
43725cf1a30Sjl 	if (ml) {
43825cf1a30Sjl 		uint64_t nbytes = 0;
43925cf1a30Sjl 		struct memlist *p;
44056f33205SJonathan Adams 		for (p = ml; p; p = p->ml_next) {
44156f33205SJonathan Adams 			nbytes += p->ml_size;
44225cf1a30Sjl 		}
44325cf1a30Sjl 		if ((mp->nbytes = nbytes) > 0)
44456f33205SJonathan Adams 			mp->base_pa = ml->ml_address;
44525cf1a30Sjl 		else
44625cf1a30Sjl 			mp->base_pa = 0;
44725cf1a30Sjl 		mp->memlist = ml;
44825cf1a30Sjl 	} else {
44925cf1a30Sjl 		mp->base_pa = 0;
45025cf1a30Sjl 		mp->nbytes = 0;
45125cf1a30Sjl 	}
45225cf1a30Sjl 	return (0);
45325cf1a30Sjl }
45425cf1a30Sjl 
45525cf1a30Sjl 
45625cf1a30Sjl struct drmach_hotcpu {
45725cf1a30Sjl 	drmach_board_t *bp;
45825cf1a30Sjl 	int	bnum;
45925cf1a30Sjl 	int	core_id;
460*bbe1232eSToomas Soome 	int	rv;
46125cf1a30Sjl 	int	option;
46225cf1a30Sjl };
46325cf1a30Sjl 
46425cf1a30Sjl static int
drmach_cpu_cb(dev_info_t * dip,void * arg)46525cf1a30Sjl drmach_cpu_cb(dev_info_t *dip, void *arg)
46625cf1a30Sjl {
46725cf1a30Sjl 	struct drmach_hotcpu *p = (struct drmach_hotcpu *)arg;
46825cf1a30Sjl 	char name[OBP_MAXDRVNAME];
46925cf1a30Sjl 	int len = OBP_MAXDRVNAME;
47025cf1a30Sjl 	int bnum, core_id, strand_id;
47125cf1a30Sjl 	drmach_board_t *bp;
47225cf1a30Sjl 
47325cf1a30Sjl 	if (dip == ddi_root_node()) {
47425cf1a30Sjl 		return (DDI_WALK_CONTINUE);
47525cf1a30Sjl 	}
47625cf1a30Sjl 
47725cf1a30Sjl 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
47825cf1a30Sjl 	    DDI_PROP_DONTPASS, "name",
47925cf1a30Sjl 	    (caddr_t)name, &len) != DDI_PROP_SUCCESS) {
48025cf1a30Sjl 		return (DDI_WALK_PRUNECHILD);
48125cf1a30Sjl 	}
48225cf1a30Sjl 
48325cf1a30Sjl 	/* only cmp has board number */
48425cf1a30Sjl 	bnum = -1;
48525cf1a30Sjl 	len = sizeof (bnum);
48625cf1a30Sjl 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
48725cf1a30Sjl 	    DDI_PROP_DONTPASS, OBP_BOARDNUM,
48825cf1a30Sjl 	    (caddr_t)&bnum, &len) != DDI_PROP_SUCCESS) {
48925cf1a30Sjl 		bnum = -1;
49025cf1a30Sjl 	}
49125cf1a30Sjl 
49225cf1a30Sjl 	if (strcmp(name, "cmp") == 0) {
49325cf1a30Sjl 		if (bnum != p->bnum)
49425cf1a30Sjl 			return (DDI_WALK_PRUNECHILD);
49525cf1a30Sjl 		return (DDI_WALK_CONTINUE);
49625cf1a30Sjl 	}
49725cf1a30Sjl 	/* we have already pruned all unwanted cores and cpu's above */
49825cf1a30Sjl 	if (strcmp(name, "core") == 0) {
49925cf1a30Sjl 		return (DDI_WALK_CONTINUE);
50025cf1a30Sjl 	}
50125cf1a30Sjl 	if (strcmp(name, "cpu") == 0) {
50225cf1a30Sjl 		processorid_t cpuid;
50325cf1a30Sjl 		len = sizeof (cpuid);
50425cf1a30Sjl 		if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
50525cf1a30Sjl 		    DDI_PROP_DONTPASS, "cpuid",
50625cf1a30Sjl 		    (caddr_t)&cpuid, &len) != DDI_PROP_SUCCESS) {
50725cf1a30Sjl 			p->rv = -1;
50825cf1a30Sjl 			return (DDI_WALK_TERMINATE);
50925cf1a30Sjl 		}
51025cf1a30Sjl 
51125cf1a30Sjl 		core_id = p->core_id;
51225cf1a30Sjl 
51325cf1a30Sjl 		bnum = LSB_ID(cpuid);
51425cf1a30Sjl 
51525cf1a30Sjl 		if (ON_BOARD_CORE_NUM(cpuid) != core_id)
51625cf1a30Sjl 			return (DDI_WALK_CONTINUE);
51725cf1a30Sjl 
51825cf1a30Sjl 		bp = p->bp;
51925cf1a30Sjl 		ASSERT(bnum == bp->bnum);
52025cf1a30Sjl 
52125cf1a30Sjl 		if (p->option == HOTADD_CPU) {
52225cf1a30Sjl 			if (prom_hotaddcpu(cpuid) != 0) {
52325cf1a30Sjl 				p->rv = -1;
52425cf1a30Sjl 				return (DDI_WALK_TERMINATE);
52525cf1a30Sjl 			}
52625cf1a30Sjl 			strand_id = STRAND_ID(cpuid);
52725cf1a30Sjl 			bp->cores[core_id].core_hotadded |= (1 << strand_id);
52825cf1a30Sjl 		} else if (p->option == HOTREMOVE_CPU) {
52925cf1a30Sjl 			if (prom_hotremovecpu(cpuid) != 0) {
53025cf1a30Sjl 				p->rv = -1;
53125cf1a30Sjl 				return (DDI_WALK_TERMINATE);
53225cf1a30Sjl 			}
53325cf1a30Sjl 			strand_id = STRAND_ID(cpuid);
53425cf1a30Sjl 			bp->cores[core_id].core_hotadded &= ~(1 << strand_id);
53525cf1a30Sjl 		}
53625cf1a30Sjl 		return (DDI_WALK_CONTINUE);
53725cf1a30Sjl 	}
53825cf1a30Sjl 
53925cf1a30Sjl 	return (DDI_WALK_PRUNECHILD);
54025cf1a30Sjl }
54125cf1a30Sjl 
54225cf1a30Sjl 
54325cf1a30Sjl static int
drmach_add_remove_cpu(int bnum,int core_id,int option)54425cf1a30Sjl drmach_add_remove_cpu(int bnum, int core_id, int option)
54525cf1a30Sjl {
54625cf1a30Sjl 	struct drmach_hotcpu arg;
54725cf1a30Sjl 	drmach_board_t *bp;
54825cf1a30Sjl 
54925cf1a30Sjl 	bp = drmach_get_board_by_bnum(bnum);
55025cf1a30Sjl 	ASSERT(bp);
55125cf1a30Sjl 
55225cf1a30Sjl 	arg.bp = bp;
55325cf1a30Sjl 	arg.bnum = bnum;
55425cf1a30Sjl 	arg.core_id = core_id;
55525cf1a30Sjl 	arg.rv = 0;
55625cf1a30Sjl 	arg.option = option;
55725cf1a30Sjl 	ddi_walk_devs(ddi_root_node(), drmach_cpu_cb, (void *)&arg);
55825cf1a30Sjl 	return (arg.rv);
55925cf1a30Sjl }
56025cf1a30Sjl 
56125cf1a30Sjl struct drmach_setup_core_arg {
56225cf1a30Sjl 	drmach_board_t *bp;
56325cf1a30Sjl };
56425cf1a30Sjl 
56525cf1a30Sjl static int
drmach_setup_core_cb(dev_info_t * dip,void * arg)56625cf1a30Sjl drmach_setup_core_cb(dev_info_t *dip, void *arg)
56725cf1a30Sjl {
56825cf1a30Sjl 	struct drmach_setup_core_arg *p = (struct drmach_setup_core_arg *)arg;
56925cf1a30Sjl 	char name[OBP_MAXDRVNAME];
57025cf1a30Sjl 	int len = OBP_MAXDRVNAME;
57125cf1a30Sjl 	int bnum;
57225cf1a30Sjl 	int core_id, strand_id;
57325cf1a30Sjl 
57425cf1a30Sjl 	if (dip == ddi_root_node()) {
57525cf1a30Sjl 		return (DDI_WALK_CONTINUE);
57625cf1a30Sjl 	}
57725cf1a30Sjl 
57825cf1a30Sjl 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
57925cf1a30Sjl 	    DDI_PROP_DONTPASS, "name",
58025cf1a30Sjl 	    (caddr_t)name, &len) != DDI_PROP_SUCCESS) {
58125cf1a30Sjl 		return (DDI_WALK_PRUNECHILD);
58225cf1a30Sjl 	}
58325cf1a30Sjl 
58425cf1a30Sjl 	/* only cmp has board number */
58525cf1a30Sjl 	bnum = -1;
58625cf1a30Sjl 	len = sizeof (bnum);
58725cf1a30Sjl 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
58825cf1a30Sjl 	    DDI_PROP_DONTPASS, OBP_BOARDNUM,
58925cf1a30Sjl 	    (caddr_t)&bnum, &len) != DDI_PROP_SUCCESS) {
59025cf1a30Sjl 		bnum = -1;
59125cf1a30Sjl 	}
59225cf1a30Sjl 
59325cf1a30Sjl 	if (strcmp(name, "cmp") == 0) {
59425cf1a30Sjl 		if (bnum != p->bp->bnum)
59525cf1a30Sjl 			return (DDI_WALK_PRUNECHILD);
59625cf1a30Sjl 		return (DDI_WALK_CONTINUE);
59725cf1a30Sjl 	}
59825cf1a30Sjl 	/* we have already pruned all unwanted cores and cpu's above */
59925cf1a30Sjl 	if (strcmp(name, "core") == 0) {
60025cf1a30Sjl 		return (DDI_WALK_CONTINUE);
60125cf1a30Sjl 	}
60225cf1a30Sjl 	if (strcmp(name, "cpu") == 0) {
60325cf1a30Sjl 		processorid_t cpuid;
60425cf1a30Sjl 		len = sizeof (cpuid);
60525cf1a30Sjl 		if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
60625cf1a30Sjl 		    DDI_PROP_DONTPASS, "cpuid",
60725cf1a30Sjl 		    (caddr_t)&cpuid, &len) != DDI_PROP_SUCCESS) {
60825cf1a30Sjl 			return (DDI_WALK_TERMINATE);
60925cf1a30Sjl 		}
61025cf1a30Sjl 		bnum = LSB_ID(cpuid);
61125cf1a30Sjl 		ASSERT(bnum == p->bp->bnum);
61225cf1a30Sjl 		core_id = ON_BOARD_CORE_NUM(cpuid);
61325cf1a30Sjl 		strand_id = STRAND_ID(cpuid);
61425cf1a30Sjl 		p->bp->cores[core_id].core_present |= (1 << strand_id);
61525cf1a30Sjl 		return (DDI_WALK_CONTINUE);
61625cf1a30Sjl 	}
61725cf1a30Sjl 
61825cf1a30Sjl 	return (DDI_WALK_PRUNECHILD);
61925cf1a30Sjl }
62025cf1a30Sjl 
62125cf1a30Sjl 
62225cf1a30Sjl static void
drmach_setup_core_info(drmach_board_t * obj)62325cf1a30Sjl drmach_setup_core_info(drmach_board_t *obj)
62425cf1a30Sjl {
62525cf1a30Sjl 	struct drmach_setup_core_arg arg;
62625cf1a30Sjl 	int i;
62725cf1a30Sjl 
62825cf1a30Sjl 	for (i = 0; i < OPL_MAX_COREID_PER_BOARD; i++) {
62925cf1a30Sjl 		obj->cores[i].core_present = 0;
63025cf1a30Sjl 		obj->cores[i].core_hotadded = 0;
63125cf1a30Sjl 		obj->cores[i].core_started = 0;
63225cf1a30Sjl 	}
63325cf1a30Sjl 	arg.bp = obj;
63425cf1a30Sjl 	ddi_walk_devs(ddi_root_node(), drmach_setup_core_cb, (void *)&arg);
63525cf1a30Sjl 
63625cf1a30Sjl 	for (i = 0; i < OPL_MAX_COREID_PER_BOARD; i++) {
63725cf1a30Sjl 		if (obj->boot_board) {
63825cf1a30Sjl 			obj->cores[i].core_hotadded =
639e98fafb9Sjl 			    obj->cores[i].core_started =
640e98fafb9Sjl 			    obj->cores[i].core_present;
64125cf1a30Sjl 		}
64225cf1a30Sjl 	}
64325cf1a30Sjl }
64425cf1a30Sjl 
64525cf1a30Sjl /*
64625cf1a30Sjl  * drmach_node_* routines serve the purpose of separating the
64725cf1a30Sjl  * rest of the code from the device tree and OBP.  This is necessary
64825cf1a30Sjl  * because of In-Kernel-Probing.  Devices probed after stod, are probed
64925cf1a30Sjl  * by the in-kernel-prober, not OBP.  These devices, therefore, do not
65025cf1a30Sjl  * have dnode ids.
65125cf1a30Sjl  */
65225cf1a30Sjl 
65325cf1a30Sjl typedef struct {
65425cf1a30Sjl 	drmach_node_walk_args_t	*nwargs;
655*bbe1232eSToomas Soome 	int			(*cb)(drmach_node_walk_args_t *args);
65625cf1a30Sjl 	int			err;
65725cf1a30Sjl } drmach_node_ddi_walk_args_t;
65825cf1a30Sjl 
65925cf1a30Sjl static int
drmach_node_ddi_walk_cb(dev_info_t * dip,void * arg)66025cf1a30Sjl drmach_node_ddi_walk_cb(dev_info_t *dip, void *arg)
66125cf1a30Sjl {
66225cf1a30Sjl 	drmach_node_ddi_walk_args_t	*nargs;
66325cf1a30Sjl 
66425cf1a30Sjl 	nargs = (drmach_node_ddi_walk_args_t *)arg;
66525cf1a30Sjl 
66625cf1a30Sjl 	/*
66725cf1a30Sjl 	 * dip doesn't have to be held here as we are called
66825cf1a30Sjl 	 * from ddi_walk_devs() which holds the dip.
66925cf1a30Sjl 	 */
67025cf1a30Sjl 	nargs->nwargs->node->here = (void *)dip;
67125cf1a30Sjl 
67225cf1a30Sjl 	nargs->err = nargs->cb(nargs->nwargs);
67325cf1a30Sjl 
67425cf1a30Sjl 
67525cf1a30Sjl 	/*
67625cf1a30Sjl 	 * Set "here" to NULL so that unheld dip is not accessible
67725cf1a30Sjl 	 * outside ddi_walk_devs()
67825cf1a30Sjl 	 */
67925cf1a30Sjl 	nargs->nwargs->node->here = NULL;
68025cf1a30Sjl 
68125cf1a30Sjl 	if (nargs->err)
68225cf1a30Sjl 		return (DDI_WALK_TERMINATE);
68325cf1a30Sjl 	else
68425cf1a30Sjl 		return (DDI_WALK_CONTINUE);
68525cf1a30Sjl }
68625cf1a30Sjl 
68725cf1a30Sjl static int
drmach_node_ddi_walk(drmach_node_t * np,void * data,int (* cb)(drmach_node_walk_args_t * args))68825cf1a30Sjl drmach_node_ddi_walk(drmach_node_t *np, void *data,
689*bbe1232eSToomas Soome     int (*cb)(drmach_node_walk_args_t *args))
69025cf1a30Sjl {
69125cf1a30Sjl 	drmach_node_walk_args_t		args;
69225cf1a30Sjl 	drmach_node_ddi_walk_args_t	nargs;
69325cf1a30Sjl 
69425cf1a30Sjl 
69525cf1a30Sjl 	/* initialized args structure for callback */
69625cf1a30Sjl 	args.node = np;
69725cf1a30Sjl 	args.data = data;
69825cf1a30Sjl 
69925cf1a30Sjl 	nargs.nwargs = &args;
70025cf1a30Sjl 	nargs.cb = cb;
70125cf1a30Sjl 	nargs.err = 0;
70225cf1a30Sjl 
70325cf1a30Sjl 	/*
70425cf1a30Sjl 	 * Root node doesn't have to be held in any way.
70525cf1a30Sjl 	 */
706e98fafb9Sjl 	ddi_walk_devs(ddi_root_node(), drmach_node_ddi_walk_cb, (void *)&nargs);
70725cf1a30Sjl 
70825cf1a30Sjl 	return (nargs.err);
70925cf1a30Sjl }
71025cf1a30Sjl 
71125cf1a30Sjl static int
drmach_node_ddi_get_parent(drmach_node_t * np,drmach_node_t * pp)71225cf1a30Sjl drmach_node_ddi_get_parent(drmach_node_t *np, drmach_node_t *pp)
71325cf1a30Sjl {
71425cf1a30Sjl 	dev_info_t	*ndip;
71525cf1a30Sjl 	static char	*fn = "drmach_node_ddi_get_parent";
71625cf1a30Sjl 
71725cf1a30Sjl 	ndip = np->n_getdip(np);
71825cf1a30Sjl 	if (ndip == NULL) {
71925cf1a30Sjl 		cmn_err(CE_WARN, "%s: NULL dip", fn);
72025cf1a30Sjl 		return (-1);
72125cf1a30Sjl 	}
72225cf1a30Sjl 
72325cf1a30Sjl 	bcopy(np, pp, sizeof (drmach_node_t));
72425cf1a30Sjl 
72525cf1a30Sjl 	pp->here = (void *)ddi_get_parent(ndip);
72625cf1a30Sjl 	if (pp->here == NULL) {
72725cf1a30Sjl 		cmn_err(CE_WARN, "%s: NULL parent dip", fn);
72825cf1a30Sjl 		return (-1);
72925cf1a30Sjl 	}
73025cf1a30Sjl 
73125cf1a30Sjl 	return (0);
73225cf1a30Sjl }
73325cf1a30Sjl 
73425cf1a30Sjl /*ARGSUSED*/
73525cf1a30Sjl static pnode_t
drmach_node_ddi_get_dnode(drmach_node_t * np)73625cf1a30Sjl drmach_node_ddi_get_dnode(drmach_node_t *np)
73725cf1a30Sjl {
738*bbe1232eSToomas Soome 	return (0);
73925cf1a30Sjl }
74025cf1a30Sjl 
74125cf1a30Sjl static drmach_node_t *
drmach_node_new(void)74225cf1a30Sjl drmach_node_new(void)
74325cf1a30Sjl {
74425cf1a30Sjl 	drmach_node_t *np;
74525cf1a30Sjl 
74625cf1a30Sjl 	np = kmem_zalloc(sizeof (drmach_node_t), KM_SLEEP);
74725cf1a30Sjl 
74825cf1a30Sjl 	np->get_dnode = drmach_node_ddi_get_dnode;
74925cf1a30Sjl 	np->walk = drmach_node_ddi_walk;
75025cf1a30Sjl 	np->n_getdip = drmach_node_ddi_get_dip;
75125cf1a30Sjl 	np->n_getproplen = drmach_node_ddi_get_proplen;
75225cf1a30Sjl 	np->n_getprop = drmach_node_ddi_get_prop;
75325cf1a30Sjl 	np->get_parent = drmach_node_ddi_get_parent;
75425cf1a30Sjl 
75525cf1a30Sjl 	return (np);
75625cf1a30Sjl }
75725cf1a30Sjl 
75825cf1a30Sjl static void
drmach_node_dispose(drmach_node_t * np)75925cf1a30Sjl drmach_node_dispose(drmach_node_t *np)
76025cf1a30Sjl {
76125cf1a30Sjl 	kmem_free(np, sizeof (*np));
76225cf1a30Sjl }
76325cf1a30Sjl 
76425cf1a30Sjl static dev_info_t *
drmach_node_ddi_get_dip(drmach_node_t * np)76525cf1a30Sjl drmach_node_ddi_get_dip(drmach_node_t *np)
76625cf1a30Sjl {
76725cf1a30Sjl 	return ((dev_info_t *)np->here);
76825cf1a30Sjl }
76925cf1a30Sjl 
77025cf1a30Sjl static int
drmach_node_walk(drmach_node_t * np,void * param,int (* cb)(drmach_node_walk_args_t * args))77125cf1a30Sjl drmach_node_walk(drmach_node_t *np, void *param,
772*bbe1232eSToomas Soome     int (*cb)(drmach_node_walk_args_t *args))
77325cf1a30Sjl {
77425cf1a30Sjl 	return (np->walk(np, param, cb));
77525cf1a30Sjl }
77625cf1a30Sjl 
77725cf1a30Sjl static int
drmach_node_ddi_get_prop(drmach_node_t * np,char * name,void * buf,int len)77825cf1a30Sjl drmach_node_ddi_get_prop(drmach_node_t *np, char *name, void *buf, int len)
77925cf1a30Sjl {
78025cf1a30Sjl 	int		rv = 0;
78125cf1a30Sjl 	dev_info_t	*ndip;
78225cf1a30Sjl 	static char	*fn = "drmach_node_ddi_get_prop";
78325cf1a30Sjl 
78425cf1a30Sjl 
78525cf1a30Sjl 	ndip = np->n_getdip(np);
78625cf1a30Sjl 	if (ndip == NULL) {
78725cf1a30Sjl 		cmn_err(CE_WARN, "%s: NULL dip", fn);
78825cf1a30Sjl 		rv = -1;
78925cf1a30Sjl 	} else if (ddi_getlongprop_buf(DDI_DEV_T_ANY, ndip,
79025cf1a30Sjl 	    DDI_PROP_DONTPASS, name,
79125cf1a30Sjl 	    (caddr_t)buf, &len) != DDI_PROP_SUCCESS) {
79225cf1a30Sjl 		rv = -1;
79325cf1a30Sjl 	}
79425cf1a30Sjl 
79525cf1a30Sjl 	return (rv);
79625cf1a30Sjl }
79725cf1a30Sjl 
79825cf1a30Sjl static int
drmach_node_ddi_get_proplen(drmach_node_t * np,char * name,int * len)79925cf1a30Sjl drmach_node_ddi_get_proplen(drmach_node_t *np, char *name, int *len)
80025cf1a30Sjl {
80125cf1a30Sjl 	int		rv = 0;
80225cf1a30Sjl 	dev_info_t	*ndip;
80325cf1a30Sjl 
80425cf1a30Sjl 	ndip = np->n_getdip(np);
80525cf1a30Sjl 	if (ndip == NULL) {
80625cf1a30Sjl 		rv = -1;
807e98fafb9Sjl 	} else if (ddi_getproplen(DDI_DEV_T_ANY, ndip, DDI_PROP_DONTPASS, name,
808e98fafb9Sjl 	    len) != DDI_PROP_SUCCESS) {
80925cf1a30Sjl 		rv = -1;
81025cf1a30Sjl 	}
81125cf1a30Sjl 
81225cf1a30Sjl 	return (rv);
81325cf1a30Sjl }
81425cf1a30Sjl 
81525cf1a30Sjl static drmachid_t
drmach_node_dup(drmach_node_t * np)81625cf1a30Sjl drmach_node_dup(drmach_node_t *np)
81725cf1a30Sjl {
81825cf1a30Sjl 	drmach_node_t *dup;
81925cf1a30Sjl 
82025cf1a30Sjl 	dup = drmach_node_new();
82125cf1a30Sjl 	dup->here = np->here;
82225cf1a30Sjl 	dup->get_dnode = np->get_dnode;
82325cf1a30Sjl 	dup->walk = np->walk;
82425cf1a30Sjl 	dup->n_getdip = np->n_getdip;
82525cf1a30Sjl 	dup->n_getproplen = np->n_getproplen;
82625cf1a30Sjl 	dup->n_getprop = np->n_getprop;
82725cf1a30Sjl 	dup->get_parent = np->get_parent;
82825cf1a30Sjl 
82925cf1a30Sjl 	return (dup);
83025cf1a30Sjl }
83125cf1a30Sjl 
83225cf1a30Sjl /*
83325cf1a30Sjl  * drmach_array provides convenient array construction, access,
83425cf1a30Sjl  * bounds checking and array destruction logic.
83525cf1a30Sjl  */
83625cf1a30Sjl 
83725cf1a30Sjl static drmach_array_t *
drmach_array_new(int min_index,int max_index)83825cf1a30Sjl drmach_array_new(int min_index, int max_index)
83925cf1a30Sjl {
84025cf1a30Sjl 	drmach_array_t *arr;
84125cf1a30Sjl 
84225cf1a30Sjl 	arr = kmem_zalloc(sizeof (drmach_array_t), KM_SLEEP);
84325cf1a30Sjl 
84425cf1a30Sjl 	arr->arr_sz = (max_index - min_index + 1) * sizeof (void *);
84525cf1a30Sjl 	if (arr->arr_sz > 0) {
84625cf1a30Sjl 		arr->min_index = min_index;
84725cf1a30Sjl 		arr->max_index = max_index;
84825cf1a30Sjl 
84925cf1a30Sjl 		arr->arr = kmem_zalloc(arr->arr_sz, KM_SLEEP);
85025cf1a30Sjl 		return (arr);
85125cf1a30Sjl 	} else {
85225cf1a30Sjl 		kmem_free(arr, sizeof (*arr));
85325cf1a30Sjl 		return (0);
85425cf1a30Sjl 	}
855