xref: /titanic_54/usr/src/uts/sun4u/io/mc-us3.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
30*7c478bd9Sstevel@tonic-gate #include <sys/conf.h>
31*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
32*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/obpdefs.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/open.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/thread.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/x_call.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/ivintr.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/intr.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/intreg.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/autoconf.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
50*7c478bd9Sstevel@tonic-gate #include <sys/spl.h>
51*7c478bd9Sstevel@tonic-gate #include <sys/async.h>
52*7c478bd9Sstevel@tonic-gate #include <sys/mc.h>
53*7c478bd9Sstevel@tonic-gate #include <sys/mc-us3.h>
54*7c478bd9Sstevel@tonic-gate #include <sys/cpu_module.h>
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate /*
57*7c478bd9Sstevel@tonic-gate  * Function prototypes
58*7c478bd9Sstevel@tonic-gate  */
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate static int mc_open(dev_t *, int, int, cred_t *);
61*7c478bd9Sstevel@tonic-gate static int mc_close(dev_t, int, int, cred_t *);
62*7c478bd9Sstevel@tonic-gate static int mc_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
63*7c478bd9Sstevel@tonic-gate static int mc_attach(dev_info_t *, ddi_attach_cmd_t);
64*7c478bd9Sstevel@tonic-gate static int mc_detach(dev_info_t *, ddi_detach_cmd_t);
65*7c478bd9Sstevel@tonic-gate 
66*7c478bd9Sstevel@tonic-gate /*
67*7c478bd9Sstevel@tonic-gate  * Configuration data structures
68*7c478bd9Sstevel@tonic-gate  */
69*7c478bd9Sstevel@tonic-gate static struct cb_ops mc_cb_ops = {
70*7c478bd9Sstevel@tonic-gate 	mc_open,			/* open */
71*7c478bd9Sstevel@tonic-gate 	mc_close,			/* close */
72*7c478bd9Sstevel@tonic-gate 	nulldev,			/* strategy */
73*7c478bd9Sstevel@tonic-gate 	nulldev,			/* print */
74*7c478bd9Sstevel@tonic-gate 	nodev,				/* dump */
75*7c478bd9Sstevel@tonic-gate 	nulldev,			/* read */
76*7c478bd9Sstevel@tonic-gate 	nulldev,			/* write */
77*7c478bd9Sstevel@tonic-gate 	mc_ioctl,			/* ioctl */
78*7c478bd9Sstevel@tonic-gate 	nodev,				/* devmap */
79*7c478bd9Sstevel@tonic-gate 	nodev,				/* mmap */
80*7c478bd9Sstevel@tonic-gate 	nodev,				/* segmap */
81*7c478bd9Sstevel@tonic-gate 	nochpoll,			/* poll */
82*7c478bd9Sstevel@tonic-gate 	ddi_prop_op,			/* cb_prop_op */
83*7c478bd9Sstevel@tonic-gate 	0,				/* streamtab */
84*7c478bd9Sstevel@tonic-gate 	D_MP | D_NEW | D_HOTPLUG,	/* Driver compatibility flag */
85*7c478bd9Sstevel@tonic-gate 	CB_REV,				/* rev */
86*7c478bd9Sstevel@tonic-gate 	nodev,				/* cb_aread */
87*7c478bd9Sstevel@tonic-gate 	nodev				/* cb_awrite */
88*7c478bd9Sstevel@tonic-gate };
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate static struct dev_ops mc_ops = {
91*7c478bd9Sstevel@tonic-gate 	DEVO_REV,			/* rev */
92*7c478bd9Sstevel@tonic-gate 	0,				/* refcnt  */
93*7c478bd9Sstevel@tonic-gate 	ddi_getinfo_1to1,		/* getinfo */
94*7c478bd9Sstevel@tonic-gate 	nulldev,			/* identify */
95*7c478bd9Sstevel@tonic-gate 	nulldev,			/* probe */
96*7c478bd9Sstevel@tonic-gate 	mc_attach,			/* attach */
97*7c478bd9Sstevel@tonic-gate 	mc_detach,			/* detach */
98*7c478bd9Sstevel@tonic-gate 	nulldev,			/* reset */
99*7c478bd9Sstevel@tonic-gate 	&mc_cb_ops,			/* cb_ops */
100*7c478bd9Sstevel@tonic-gate 	(struct bus_ops *)0,		/* bus_ops */
101*7c478bd9Sstevel@tonic-gate 	nulldev				/* power */
102*7c478bd9Sstevel@tonic-gate };
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate /*
105*7c478bd9Sstevel@tonic-gate  * Driver globals
106*7c478bd9Sstevel@tonic-gate  */
107*7c478bd9Sstevel@tonic-gate static void *mcp;
108*7c478bd9Sstevel@tonic-gate static int nmcs = 0;
109*7c478bd9Sstevel@tonic-gate static int seg_id = 0;
110*7c478bd9Sstevel@tonic-gate static int nsegments = 0;
111*7c478bd9Sstevel@tonic-gate static uint64_t memsize = 0;
112*7c478bd9Sstevel@tonic-gate static int maxbanks = 0;
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate static mc_dlist_t *seg_head, *seg_tail, *bank_head, *bank_tail;
115*7c478bd9Sstevel@tonic-gate static mc_dlist_t *mctrl_head, *mctrl_tail, *dgrp_head, *dgrp_tail;
116*7c478bd9Sstevel@tonic-gate static mc_dlist_t *device_head, *device_tail;
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate static kmutex_t	mcmutex;
119*7c478bd9Sstevel@tonic-gate static kmutex_t	mcdatamutex;
120*7c478bd9Sstevel@tonic-gate static int mc_is_open = 0;
121*7c478bd9Sstevel@tonic-gate 
122*7c478bd9Sstevel@tonic-gate extern struct mod_ops mod_driverops;
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
125*7c478bd9Sstevel@tonic-gate 	&mod_driverops,			/* module type, this one is a driver */
126*7c478bd9Sstevel@tonic-gate 	"Memory-controller: %I%",	/* module name */
127*7c478bd9Sstevel@tonic-gate 	&mc_ops,			/* driver ops */
128*7c478bd9Sstevel@tonic-gate };
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
131*7c478bd9Sstevel@tonic-gate 	MODREV_1,		/* rev */
132*7c478bd9Sstevel@tonic-gate 	(void *)&modldrv,
133*7c478bd9Sstevel@tonic-gate 	NULL
134*7c478bd9Sstevel@tonic-gate };
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate static int mc_get_mem_unum(int synd_code, uint64_t paddr, char *buf,
137*7c478bd9Sstevel@tonic-gate     int buflen, int *lenp);
138*7c478bd9Sstevel@tonic-gate static int mc_get_mem_info(int synd_code, uint64_t paddr,
139*7c478bd9Sstevel@tonic-gate     uint64_t *mem_sizep, uint64_t *seg_sizep, uint64_t *bank_sizep,
140*7c478bd9Sstevel@tonic-gate     int *segsp, int *banksp, int *mcidp);
141*7c478bd9Sstevel@tonic-gate static int mc_get_mcregs(struct mc_soft_state *);
142*7c478bd9Sstevel@tonic-gate static void mc_construct(int mc_id, void *dimminfop);
143*7c478bd9Sstevel@tonic-gate static int mlayout_add(int mc_id, int bank_no, uint64_t reg, void *dimminfop);
144*7c478bd9Sstevel@tonic-gate static void mlayout_del(int mc_id);
145*7c478bd9Sstevel@tonic-gate static struct seg_info *seg_match_base(u_longlong_t base);
146*7c478bd9Sstevel@tonic-gate static void mc_node_add(mc_dlist_t *node, mc_dlist_t **head, mc_dlist_t **tail);
147*7c478bd9Sstevel@tonic-gate static void mc_node_del(mc_dlist_t *node, mc_dlist_t **head, mc_dlist_t **tail);
148*7c478bd9Sstevel@tonic-gate static mc_dlist_t *mc_node_get(int id, mc_dlist_t *head);
149*7c478bd9Sstevel@tonic-gate static void mc_add_mem_unum_label(char *buf, int mcid, int bank, int dimm);
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate #pragma weak p2get_mem_unum
152*7c478bd9Sstevel@tonic-gate #pragma weak p2get_mem_info
153*7c478bd9Sstevel@tonic-gate #pragma weak plat_add_mem_unum_label
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate /*
156*7c478bd9Sstevel@tonic-gate  * These are the module initialization routines.
157*7c478bd9Sstevel@tonic-gate  */
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate int
160*7c478bd9Sstevel@tonic-gate _init(void)
161*7c478bd9Sstevel@tonic-gate {
162*7c478bd9Sstevel@tonic-gate 	int error;
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate 	if ((error = ddi_soft_state_init(&mcp,
165*7c478bd9Sstevel@tonic-gate 	    sizeof (struct mc_soft_state), 1)) != 0)
166*7c478bd9Sstevel@tonic-gate 		return (error);
167*7c478bd9Sstevel@tonic-gate 
168*7c478bd9Sstevel@tonic-gate 	error =  mod_install(&modlinkage);
169*7c478bd9Sstevel@tonic-gate 	if (error == 0) {
170*7c478bd9Sstevel@tonic-gate 		mutex_init(&mcmutex, NULL, MUTEX_DRIVER, NULL);
171*7c478bd9Sstevel@tonic-gate 		mutex_init(&mcdatamutex, NULL, MUTEX_DRIVER, NULL);
172*7c478bd9Sstevel@tonic-gate 	}
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate 	return (error);
175*7c478bd9Sstevel@tonic-gate }
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate int
178*7c478bd9Sstevel@tonic-gate _fini(void)
179*7c478bd9Sstevel@tonic-gate {
180*7c478bd9Sstevel@tonic-gate 	int error;
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate 	if ((error = mod_remove(&modlinkage)) != 0)
183*7c478bd9Sstevel@tonic-gate 		return (error);
184*7c478bd9Sstevel@tonic-gate 
185*7c478bd9Sstevel@tonic-gate 	ddi_soft_state_fini(&mcp);
186*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&mcmutex);
187*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&mcdatamutex);
188*7c478bd9Sstevel@tonic-gate 
189*7c478bd9Sstevel@tonic-gate 	return (0);
190*7c478bd9Sstevel@tonic-gate }
191*7c478bd9Sstevel@tonic-gate 
192*7c478bd9Sstevel@tonic-gate int
193*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
194*7c478bd9Sstevel@tonic-gate {
195*7c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
196*7c478bd9Sstevel@tonic-gate }
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate static int
199*7c478bd9Sstevel@tonic-gate mc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
200*7c478bd9Sstevel@tonic-gate {
201*7c478bd9Sstevel@tonic-gate 	struct mc_soft_state *softsp;
202*7c478bd9Sstevel@tonic-gate 	struct dimm_info *dimminfop;
203*7c478bd9Sstevel@tonic-gate 	int instance, len, err;
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate 	/* get the instance of this devi */
206*7c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(devi);
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
209*7c478bd9Sstevel@tonic-gate 	case DDI_ATTACH:
210*7c478bd9Sstevel@tonic-gate 		break;
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate 	case DDI_RESUME:
213*7c478bd9Sstevel@tonic-gate 		/* get the soft state pointer for this device node */
214*7c478bd9Sstevel@tonic-gate 		softsp = ddi_get_soft_state(mcp, instance);
215*7c478bd9Sstevel@tonic-gate 		DPRINTF(MC_ATTACH_DEBUG, ("mc%d: DDI_RESUME: updating MADRs\n",
216*7c478bd9Sstevel@tonic-gate 		    instance));
217*7c478bd9Sstevel@tonic-gate 		/*
218*7c478bd9Sstevel@tonic-gate 		 * During resume, the source and target board's bank_infos
219*7c478bd9Sstevel@tonic-gate 		 * need to be updated with the new mc MADR values.  This is
220*7c478bd9Sstevel@tonic-gate 		 * implemented with existing functionality by first removing
221*7c478bd9Sstevel@tonic-gate 		 * the props and allocated data structs, and then adding them
222*7c478bd9Sstevel@tonic-gate 		 * back in.
223*7c478bd9Sstevel@tonic-gate 		 */
224*7c478bd9Sstevel@tonic-gate 		if (ddi_prop_exists(DDI_DEV_T_ANY, softsp->dip,
225*7c478bd9Sstevel@tonic-gate 		    DDI_PROP_NOTPROM | DDI_PROP_DONTPASS,
226*7c478bd9Sstevel@tonic-gate 		    MEM_CFG_PROP_NAME) == 1) {
227*7c478bd9Sstevel@tonic-gate 			(void) ddi_prop_remove(DDI_DEV_T_NONE, softsp->dip,
228*7c478bd9Sstevel@tonic-gate 			    MEM_CFG_PROP_NAME);
229*7c478bd9Sstevel@tonic-gate 		}
230*7c478bd9Sstevel@tonic-gate 		mlayout_del(softsp->portid);
231*7c478bd9Sstevel@tonic-gate 		if (mc_get_mcregs(softsp) == -1) {
232*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "mc_attach: mc%d DDI_RESUME failure\n",
233*7c478bd9Sstevel@tonic-gate 			    instance);
234*7c478bd9Sstevel@tonic-gate 		}
235*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate 	default:
238*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
239*7c478bd9Sstevel@tonic-gate 	}
240*7c478bd9Sstevel@tonic-gate 
241*7c478bd9Sstevel@tonic-gate 	if (ddi_soft_state_zalloc(mcp, instance) != DDI_SUCCESS)
242*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
243*7c478bd9Sstevel@tonic-gate 
244*7c478bd9Sstevel@tonic-gate 	softsp = ddi_get_soft_state(mcp, instance);
245*7c478bd9Sstevel@tonic-gate 
246*7c478bd9Sstevel@tonic-gate 	/* Set the dip in the soft state */
247*7c478bd9Sstevel@tonic-gate 	softsp->dip = devi;
248*7c478bd9Sstevel@tonic-gate 
249*7c478bd9Sstevel@tonic-gate 	if ((softsp->portid = (int)ddi_getprop(DDI_DEV_T_ANY, softsp->dip,
250*7c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "portid", -1)) == -1) {
251*7c478bd9Sstevel@tonic-gate 		DPRINTF(MC_ATTACH_DEBUG, ("mc%d: unable to get %s property",
252*7c478bd9Sstevel@tonic-gate 		    instance, "portid"));
253*7c478bd9Sstevel@tonic-gate 		goto bad;
254*7c478bd9Sstevel@tonic-gate 	}
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate 	DPRINTF(MC_ATTACH_DEBUG, ("mc%d ATTACH: portid %d, cpuid %d\n",
257*7c478bd9Sstevel@tonic-gate 	    instance, softsp->portid, CPU->cpu_id));
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate 	/* map in the registers for this device. */
260*7c478bd9Sstevel@tonic-gate 	if (ddi_map_regs(softsp->dip, 0, (caddr_t *)&softsp->mc_base, 0, 0)) {
261*7c478bd9Sstevel@tonic-gate 		DPRINTF(MC_ATTACH_DEBUG, ("mc%d: unable to map registers",
262*7c478bd9Sstevel@tonic-gate 		    instance));
263*7c478bd9Sstevel@tonic-gate 		goto bad;
264*7c478bd9Sstevel@tonic-gate 	}
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate 	/*
267*7c478bd9Sstevel@tonic-gate 	 * Get the label of dimms and pin routing information at memory-layout
268*7c478bd9Sstevel@tonic-gate 	 * property if the memory controller is enabled.
269*7c478bd9Sstevel@tonic-gate 	 *
270*7c478bd9Sstevel@tonic-gate 	 * Basically every memory-controller node on every machine should
271*7c478bd9Sstevel@tonic-gate 	 * have one of these properties unless the memory controller is
272*7c478bd9Sstevel@tonic-gate 	 * physically not capable of having memory attached to it, e.g.
273*7c478bd9Sstevel@tonic-gate 	 * Excalibur's slave processor.
274*7c478bd9Sstevel@tonic-gate 	 */
275*7c478bd9Sstevel@tonic-gate 	err = ddi_getlongprop(DDI_DEV_T_ANY, softsp->dip, DDI_PROP_DONTPASS,
276*7c478bd9Sstevel@tonic-gate 	    "memory-layout", (caddr_t)&dimminfop, &len);
277*7c478bd9Sstevel@tonic-gate 	if (err == DDI_PROP_SUCCESS) {
278*7c478bd9Sstevel@tonic-gate 		/*
279*7c478bd9Sstevel@tonic-gate 		 * Set the pointer and size of property in the soft state
280*7c478bd9Sstevel@tonic-gate 		 */
281*7c478bd9Sstevel@tonic-gate 		softsp->memlayoutp = dimminfop;
282*7c478bd9Sstevel@tonic-gate 		softsp->size = len;
283*7c478bd9Sstevel@tonic-gate 	} else if (err == DDI_PROP_NOT_FOUND) {
284*7c478bd9Sstevel@tonic-gate 		/*
285*7c478bd9Sstevel@tonic-gate 		 * This is a disable MC. Clear out the pointer and size
286*7c478bd9Sstevel@tonic-gate 		 * of property in the soft state
287*7c478bd9Sstevel@tonic-gate 		 */
288*7c478bd9Sstevel@tonic-gate 		softsp->memlayoutp = NULL;
289*7c478bd9Sstevel@tonic-gate 		softsp->size = 0;
290*7c478bd9Sstevel@tonic-gate 	} else {
291*7c478bd9Sstevel@tonic-gate 		DPRINTF(MC_ATTACH_DEBUG, ("mc%d is disabled: dimminfop %p\n",
292*7c478bd9Sstevel@tonic-gate 		    instance, dimminfop));
293*7c478bd9Sstevel@tonic-gate 		goto bad2;
294*7c478bd9Sstevel@tonic-gate 	}
295*7c478bd9Sstevel@tonic-gate 
296*7c478bd9Sstevel@tonic-gate 	DPRINTF(MC_ATTACH_DEBUG, ("mc%d: dimminfop=0x%p data=0x%llx len=%d\n",
297*7c478bd9Sstevel@tonic-gate 	    instance, dimminfop, *dimminfop, len));
298*7c478bd9Sstevel@tonic-gate 
299*7c478bd9Sstevel@tonic-gate 	/* Get MC registers and construct all needed data structure */
300*7c478bd9Sstevel@tonic-gate 	if (mc_get_mcregs(softsp) == -1)
301*7c478bd9Sstevel@tonic-gate 		goto bad1;
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mcmutex);
304*7c478bd9Sstevel@tonic-gate 	if (nmcs == 1) {
305*7c478bd9Sstevel@tonic-gate 		if (&p2get_mem_unum)
306*7c478bd9Sstevel@tonic-gate 			p2get_mem_unum = mc_get_mem_unum;
307*7c478bd9Sstevel@tonic-gate 		if (&p2get_mem_info)
308*7c478bd9Sstevel@tonic-gate 			p2get_mem_info = mc_get_mem_info;
309*7c478bd9Sstevel@tonic-gate 	}
310*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mcmutex);
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate 	if (ddi_create_minor_node(devi, "mc-us3", S_IFCHR, instance,
313*7c478bd9Sstevel@tonic-gate 	    "ddi_mem_ctrl", 0) != DDI_SUCCESS) {
314*7c478bd9Sstevel@tonic-gate 		DPRINTF(MC_ATTACH_DEBUG, ("mc_attach: create_minor_node"
315*7c478bd9Sstevel@tonic-gate 		    " failed \n"));
316*7c478bd9Sstevel@tonic-gate 		goto bad1;
317*7c478bd9Sstevel@tonic-gate 	}
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate 	ddi_report_dev(devi);
320*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate bad1:
323*7c478bd9Sstevel@tonic-gate 	/* release all allocated data struture for this MC */
324*7c478bd9Sstevel@tonic-gate 	mlayout_del(softsp->portid);
325*7c478bd9Sstevel@tonic-gate 	if (softsp->memlayoutp != NULL)
326*7c478bd9Sstevel@tonic-gate 		kmem_free(softsp->memlayoutp, softsp->size);
327*7c478bd9Sstevel@tonic-gate 
328*7c478bd9Sstevel@tonic-gate 	/* remove the libdevinfo property */
329*7c478bd9Sstevel@tonic-gate 	if (ddi_prop_exists(DDI_DEV_T_ANY, softsp->dip,
330*7c478bd9Sstevel@tonic-gate 	    DDI_PROP_NOTPROM | DDI_PROP_DONTPASS,
331*7c478bd9Sstevel@tonic-gate 	    MEM_CFG_PROP_NAME) == 1) {
332*7c478bd9Sstevel@tonic-gate 		(void) ddi_prop_remove(DDI_DEV_T_NONE, softsp->dip,
333*7c478bd9Sstevel@tonic-gate 			MEM_CFG_PROP_NAME);
334*7c478bd9Sstevel@tonic-gate 	}
335*7c478bd9Sstevel@tonic-gate 
336*7c478bd9Sstevel@tonic-gate bad2:
337*7c478bd9Sstevel@tonic-gate 	/* unmap the registers for this device. */
338*7c478bd9Sstevel@tonic-gate 	ddi_unmap_regs(softsp->dip, 0, (caddr_t *)&softsp->mc_base, 0, 0);
339*7c478bd9Sstevel@tonic-gate 
340*7c478bd9Sstevel@tonic-gate bad:
341*7c478bd9Sstevel@tonic-gate 	ddi_soft_state_free(mcp, instance);
342*7c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
343*7c478bd9Sstevel@tonic-gate }
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
346*7c478bd9Sstevel@tonic-gate static int
347*7c478bd9Sstevel@tonic-gate mc_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
348*7c478bd9Sstevel@tonic-gate {
349*7c478bd9Sstevel@tonic-gate 	int instance;
350*7c478bd9Sstevel@tonic-gate 	struct mc_soft_state *softsp;
351*7c478bd9Sstevel@tonic-gate 
352*7c478bd9Sstevel@tonic-gate 	/* get the instance of this devi */
353*7c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(devi);
354*7c478bd9Sstevel@tonic-gate 
355*7c478bd9Sstevel@tonic-gate 	/* get the soft state pointer for this device node */
356*7c478bd9Sstevel@tonic-gate 	softsp = ddi_get_soft_state(mcp, instance);
357*7c478bd9Sstevel@tonic-gate 
358*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
359*7c478bd9Sstevel@tonic-gate 	case DDI_SUSPEND:
360*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
363*7c478bd9Sstevel@tonic-gate 		break;
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate 	default:
366*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
367*7c478bd9Sstevel@tonic-gate 	}
368*7c478bd9Sstevel@tonic-gate 
369*7c478bd9Sstevel@tonic-gate 	DPRINTF(MC_DETACH_DEBUG, ("mc%d DETACH: portid= %d, table 0x%p\n",
370*7c478bd9Sstevel@tonic-gate 	    instance, softsp->portid, softsp->memlayoutp));
371*7c478bd9Sstevel@tonic-gate 
372*7c478bd9Sstevel@tonic-gate 	/* remove the libdevinfo property */
373*7c478bd9Sstevel@tonic-gate 	if (ddi_prop_exists(DDI_DEV_T_ANY, softsp->dip,
374*7c478bd9Sstevel@tonic-gate 	    DDI_PROP_NOTPROM | DDI_PROP_DONTPASS,
375*7c478bd9Sstevel@tonic-gate 	    MEM_CFG_PROP_NAME) == 1) {
376*7c478bd9Sstevel@tonic-gate 		(void) ddi_prop_remove(DDI_DEV_T_NONE, softsp->dip,
377*7c478bd9Sstevel@tonic-gate 			MEM_CFG_PROP_NAME);
378*7c478bd9Sstevel@tonic-gate 	}
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate 	/* release all allocated data struture for this MC */
381*7c478bd9Sstevel@tonic-gate 	mlayout_del(softsp->portid);
382*7c478bd9Sstevel@tonic-gate 	if (softsp->memlayoutp != NULL)
383*7c478bd9Sstevel@tonic-gate 		kmem_free(softsp->memlayoutp, softsp->size);
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate 	/* unmap the registers */
386*7c478bd9Sstevel@tonic-gate 	ddi_unmap_regs(softsp->dip, 0, (caddr_t *)&softsp->mc_base, 0, 0);
387*7c478bd9Sstevel@tonic-gate 
388*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mcmutex);
389*7c478bd9Sstevel@tonic-gate 	if (nmcs == 0) {
390*7c478bd9Sstevel@tonic-gate 		if (&p2get_mem_unum)
391*7c478bd9Sstevel@tonic-gate 			p2get_mem_unum = NULL;
392*7c478bd9Sstevel@tonic-gate 		if (&p2get_mem_info)
393*7c478bd9Sstevel@tonic-gate 			p2get_mem_info = NULL;
394*7c478bd9Sstevel@tonic-gate 	}
395*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mcmutex);
396*7c478bd9Sstevel@tonic-gate 
397*7c478bd9Sstevel@tonic-gate 	ddi_remove_minor_node(devi, NULL);
398*7c478bd9Sstevel@tonic-gate 
399*7c478bd9Sstevel@tonic-gate 	/* free up the soft state */
400*7c478bd9Sstevel@tonic-gate 	ddi_soft_state_free(mcp, instance);
401*7c478bd9Sstevel@tonic-gate 
402*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
403*7c478bd9Sstevel@tonic-gate }
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
406*7c478bd9Sstevel@tonic-gate static int
407*7c478bd9Sstevel@tonic-gate mc_open(dev_t *devp, int flag, int otyp, cred_t *credp)
408*7c478bd9Sstevel@tonic-gate {
409*7c478bd9Sstevel@tonic-gate 	int status = 0;
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate 	/* verify that otyp is appropriate */
412*7c478bd9Sstevel@tonic-gate 	if (otyp != OTYP_CHR) {
413*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
414*7c478bd9Sstevel@tonic-gate 	}
415*7c478bd9Sstevel@tonic-gate 
416*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mcmutex);
417*7c478bd9Sstevel@tonic-gate 	if (mc_is_open) {
418*7c478bd9Sstevel@tonic-gate 		status = EBUSY;
419*7c478bd9Sstevel@tonic-gate 		goto bad;
420*7c478bd9Sstevel@tonic-gate 	}
421*7c478bd9Sstevel@tonic-gate 	mc_is_open = 1;
422*7c478bd9Sstevel@tonic-gate bad:
423*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mcmutex);
424*7c478bd9Sstevel@tonic-gate 	return (status);
425*7c478bd9Sstevel@tonic-gate }
426*7c478bd9Sstevel@tonic-gate 
427*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
428*7c478bd9Sstevel@tonic-gate static int
429*7c478bd9Sstevel@tonic-gate mc_close(dev_t devp, int flag, int otyp, cred_t *credp)
430*7c478bd9Sstevel@tonic-gate {
431*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mcmutex);
432*7c478bd9Sstevel@tonic-gate 	mc_is_open = 0;
433*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mcmutex);
434*7c478bd9Sstevel@tonic-gate 
435*7c478bd9Sstevel@tonic-gate 	return (0);
436*7c478bd9Sstevel@tonic-gate }
437*7c478bd9Sstevel@tonic-gate 
438*7c478bd9Sstevel@tonic-gate /*
439*7c478bd9Sstevel@tonic-gate  * cmd includes MCIOC_MEMCONF, MCIOC_MEM, MCIOC_SEG, MCIOC_BANK, MCIOC_DEVGRP,
440*7c478bd9Sstevel@tonic-gate  * MCIOC_CTRLCONF, MCIOC_CONTROL.
441*7c478bd9Sstevel@tonic-gate  *
442*7c478bd9Sstevel@tonic-gate  * MCIOC_MEM, MCIOC_SEG, MCIOC_CTRLCONF, and MCIOC_CONTROL are
443*7c478bd9Sstevel@tonic-gate  * associated with various length struct. If given number is less than the
444*7c478bd9Sstevel@tonic-gate  * number in kernel, update the number and return EINVAL so that user could
445*7c478bd9Sstevel@tonic-gate  * allocate enough space for it.
446*7c478bd9Sstevel@tonic-gate  *
447*7c478bd9Sstevel@tonic-gate  */
448*7c478bd9Sstevel@tonic-gate 
449*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
450*7c478bd9Sstevel@tonic-gate static int
451*7c478bd9Sstevel@tonic-gate mc_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred_p,
452*7c478bd9Sstevel@tonic-gate 	int *rval_p)
453*7c478bd9Sstevel@tonic-gate {
454*7c478bd9Sstevel@tonic-gate 	size_t	size;
455*7c478bd9Sstevel@tonic-gate 	struct mc_memconf mcmconf;
456*7c478bd9Sstevel@tonic-gate 	struct mc_memory *mcmem, mcmem_in;
457*7c478bd9Sstevel@tonic-gate 	struct mc_segment *mcseg, mcseg_in;
458*7c478bd9Sstevel@tonic-gate 	struct mc_bank mcbank;
459*7c478bd9Sstevel@tonic-gate 	struct mc_devgrp mcdevgrp;
460*7c478bd9Sstevel@tonic-gate 	struct mc_ctrlconf *mcctrlconf, mcctrlconf_in;
461*7c478bd9Sstevel@tonic-gate 	struct mc_control *mccontrol, mccontrol_in;
462*7c478bd9Sstevel@tonic-gate 	struct seg_info *seg = NULL;
463*7c478bd9Sstevel@tonic-gate 	struct bank_info *bank = NULL;
464*7c478bd9Sstevel@tonic-gate 	struct dgrp_info *dgrp = NULL;
465*7c478bd9Sstevel@tonic-gate 	struct mctrl_info *mcport;
466*7c478bd9Sstevel@tonic-gate 	mc_dlist_t *mctrl;
467*7c478bd9Sstevel@tonic-gate 	int i, status = 0;
468*7c478bd9Sstevel@tonic-gate 	cpu_t *cpu;
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
471*7c478bd9Sstevel@tonic-gate 	case MCIOC_MEMCONF:
472*7c478bd9Sstevel@tonic-gate 		mutex_enter(&mcdatamutex);
473*7c478bd9Sstevel@tonic-gate 
474*7c478bd9Sstevel@tonic-gate 		mcmconf.nmcs = nmcs;
475*7c478bd9Sstevel@tonic-gate 		mcmconf.nsegments = nsegments;
476*7c478bd9Sstevel@tonic-gate 		mcmconf.nbanks = maxbanks;
477*7c478bd9Sstevel@tonic-gate 		mcmconf.ndevgrps = NDGRPS;
478*7c478bd9Sstevel@tonic-gate 		mcmconf.ndevs = NDIMMS;
479*7c478bd9Sstevel@tonic-gate 		mcmconf.len_dev = MAX_DEVLEN;
480*7c478bd9Sstevel@tonic-gate 		mcmconf.xfer_size = TRANSFER_SIZE;
481*7c478bd9Sstevel@tonic-gate 
482*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mcdatamutex);
483*7c478bd9Sstevel@tonic-gate 
484*7c478bd9Sstevel@tonic-gate 		if (copyout(&mcmconf, (void *)arg, sizeof (struct mc_memconf)))
485*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
486*7c478bd9Sstevel@tonic-gate 		return (0);
487*7c478bd9Sstevel@tonic-gate 
488*7c478bd9Sstevel@tonic-gate 	/*
489*7c478bd9Sstevel@tonic-gate 	 * input: nsegments and allocate space for various length of segmentids
490*7c478bd9Sstevel@tonic-gate 	 *
491*7c478bd9Sstevel@tonic-gate 	 * return    0: size, number of segments, and all segment ids,
492*7c478bd9Sstevel@tonic-gate 	 *		where glocal and local ids are identical.
493*7c478bd9Sstevel@tonic-gate 	 *	EINVAL: if the given nsegments is less than that in kernel and
494*7c478bd9Sstevel@tonic-gate 	 *		nsegments of struct will be updated.
495*7c478bd9Sstevel@tonic-gate 	 *	EFAULT: if other errors in kernel.
496*7c478bd9Sstevel@tonic-gate 	 */
497*7c478bd9Sstevel@tonic-gate 	case MCIOC_MEM:
498*7c478bd9Sstevel@tonic-gate 		if (copyin((void *)arg, &mcmem_in,
499*7c478bd9Sstevel@tonic-gate 		    sizeof (struct mc_memory)) != 0)
500*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
501*7c478bd9Sstevel@tonic-gate 
502*7c478bd9Sstevel@tonic-gate 		mutex_enter(&mcdatamutex);
503*7c478bd9Sstevel@tonic-gate 		if (mcmem_in.nsegments < nsegments) {
504*7c478bd9Sstevel@tonic-gate 			mcmem_in.nsegments = nsegments;
505*7c478bd9Sstevel@tonic-gate 			if (copyout(&mcmem_in, (void *)arg,
506*7c478bd9Sstevel@tonic-gate 			    sizeof (struct mc_memory)))
507*7c478bd9Sstevel@tonic-gate 				status = EFAULT;
508*7c478bd9Sstevel@tonic-gate 			else
509*7c478bd9Sstevel@tonic-gate 				status = EINVAL;
510*7c478bd9Sstevel@tonic-gate 
511*7c478bd9Sstevel@tonic-gate 			mutex_exit(&mcdatamutex);
512*7c478bd9Sstevel@tonic-gate 			return (status);
513*7c478bd9Sstevel@tonic-gate 		}
514*7c478bd9Sstevel@tonic-gate 
515*7c478bd9Sstevel@tonic-gate 		size = sizeof (struct mc_memory) + (nsegments - 1) *
516*7c478bd9Sstevel@tonic-gate 		    sizeof (mcmem->segmentids[0]);
517*7c478bd9Sstevel@tonic-gate 		mcmem = kmem_zalloc(size, KM_SLEEP);
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate 		mcmem->size = memsize;
520*7c478bd9Sstevel@tonic-gate 		mcmem->nsegments = nsegments;
521*7c478bd9Sstevel@tonic-gate 		seg = (struct seg_info *)seg_head;
522*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < nsegments; i++) {
523*7c478bd9Sstevel@tonic-gate 			ASSERT(seg != NULL);
524*7c478bd9Sstevel@tonic-gate 			mcmem->segmentids[i].globalid = seg->seg_node.id;
525*7c478bd9Sstevel@tonic-gate 			mcmem->segmentids[i].localid = seg->seg_node.id;
526*7c478bd9Sstevel@tonic-gate 			seg = (struct seg_info *)seg->seg_node.next;
527*7c478bd9Sstevel@tonic-gate 		}
528*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mcdatamutex);
529*7c478bd9Sstevel@tonic-gate 
530*7c478bd9Sstevel@tonic-gate 		if (copyout(mcmem, (void *)arg, size))
531*7c478bd9Sstevel@tonic-gate 			status = EFAULT;
532*7c478bd9Sstevel@tonic-gate 
533*7c478bd9Sstevel@tonic-gate 		kmem_free(mcmem, size);
534*7c478bd9Sstevel@tonic-gate 		return (status);
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate 	/*
537*7c478bd9Sstevel@tonic-gate 	 * input: id, nbanks and allocate space for various length of bankids
538*7c478bd9Sstevel@tonic-gate 	 *
539*7c478bd9Sstevel@tonic-gate 	 * return    0: base, size, number of banks, and all bank ids,
540*7c478bd9Sstevel@tonic-gate 	 *		where global id is unique of all banks and local id
541*7c478bd9Sstevel@tonic-gate 	 *		is only unique for mc.
542*7c478bd9Sstevel@tonic-gate 	 *	EINVAL: either id isn't found or if given nbanks is less than
543*7c478bd9Sstevel@tonic-gate 	 *		that in kernel and nbanks of struct will be updated.
544*7c478bd9Sstevel@tonic-gate 	 *	EFAULT: if other errors in kernel.
545*7c478bd9Sstevel@tonic-gate 	 */
546*7c478bd9Sstevel@tonic-gate 	case MCIOC_SEG:
547*7c478bd9Sstevel@tonic-gate 
548*7c478bd9Sstevel@tonic-gate 		if (copyin((void *)arg, &mcseg_in,
549*7c478bd9Sstevel@tonic-gate 		    sizeof (struct mc_segment)) != 0)
550*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
551*7c478bd9Sstevel@tonic-gate 
552*7c478bd9Sstevel@tonic-gate 		mutex_enter(&mcdatamutex);
553*7c478bd9Sstevel@tonic-gate 		if ((seg = (struct seg_info *)mc_node_get(mcseg_in.id,
554*7c478bd9Sstevel@tonic-gate 		    seg_head)) == NULL) {
555*7c478bd9Sstevel@tonic-gate 			DPRINTF(MC_CMD_DEBUG, ("MCIOC_SEG: seg not match, "
556*7c478bd9Sstevel@tonic-gate 			    "id %d\n", mcseg_in.id));
557*7c478bd9Sstevel@tonic-gate 			mutex_exit(&mcdatamutex);
558*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
559*7c478bd9Sstevel@tonic-gate 		}
560*7c478bd9Sstevel@tonic-gate 
561*7c478bd9Sstevel@tonic-gate 		if (mcseg_in.nbanks < seg->nbanks) {
562*7c478bd9Sstevel@tonic-gate 			mcseg_in.nbanks = seg->nbanks;
563*7c478bd9Sstevel@tonic-gate 			if (copyout(&mcseg_in, (void *)arg,
564*7c478bd9Sstevel@tonic-gate 			    sizeof (struct mc_segment)))
565*7c478bd9Sstevel@tonic-gate 				status = EFAULT;
566*7c478bd9Sstevel@tonic-gate 			else
567*7c478bd9Sstevel@tonic-gate 				status = EINVAL;
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate 			mutex_exit(&mcdatamutex);
570*7c478bd9Sstevel@tonic-gate 			return (status);
571*7c478bd9Sstevel@tonic-gate 		}
572*7c478bd9Sstevel@tonic-gate 
573*7c478bd9Sstevel@tonic-gate 		size = sizeof (struct mc_segment) + (seg->nbanks - 1) *
574*7c478bd9Sstevel@tonic-gate 		    sizeof (mcseg->bankids[0]);
575*7c478bd9Sstevel@tonic-gate 		mcseg = kmem_zalloc(size, KM_SLEEP);
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate 		mcseg->id = seg->seg_node.id;
578*7c478bd9Sstevel@tonic-gate 		mcseg->ifactor = seg->ifactor;
579*7c478bd9Sstevel@tonic-gate 		mcseg->base = seg->base;
580*7c478bd9Sstevel@tonic-gate 		mcseg->size = seg->size;
581*7c478bd9Sstevel@tonic-gate 		mcseg->nbanks = seg->nbanks;
582*7c478bd9Sstevel@tonic-gate 
583*7c478bd9Sstevel@tonic-gate 		bank = seg->hb_inseg;
584*7c478bd9Sstevel@tonic-gate 
585*7c478bd9Sstevel@tonic-gate 		DPRINTF(MC_CMD_DEBUG, ("MCIOC_SEG:nbanks %d seg 0x%p bank %p\n",
586*7c478bd9Sstevel@tonic-gate 		    seg->nbanks, seg, bank));
587*7c478bd9Sstevel@tonic-gate 
588*7c478bd9Sstevel@tonic-gate 		i = 0;
589*7c478bd9Sstevel@tonic-gate 		while (bank != NULL) {
590*7c478bd9Sstevel@tonic-gate 			DPRINTF(MC_CMD_DEBUG, ("MCIOC_SEG:idx %d bank_id %d\n",
591*7c478bd9Sstevel@tonic-gate 			    i, bank->bank_node.id));
592*7c478bd9Sstevel@tonic-gate 			mcseg->bankids[i].globalid = bank->bank_node.id;
593*7c478bd9Sstevel@tonic-gate 			mcseg->bankids[i++].localid =
594*7c478bd9Sstevel@tonic-gate 			    bank->local_id;
595*7c478bd9Sstevel@tonic-gate 			bank = bank->n_inseg;
596*7c478bd9Sstevel@tonic-gate 		}
597*7c478bd9Sstevel@tonic-gate 		ASSERT(i == seg->nbanks);
598*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mcdatamutex);
599*7c478bd9Sstevel@tonic-gate 
600*7c478bd9Sstevel@tonic-gate 		if (copyout(mcseg, (void *)arg, size))
601*7c478bd9Sstevel@tonic-gate 			status = EFAULT;
602*7c478bd9Sstevel@tonic-gate 
603*7c478bd9Sstevel@tonic-gate 		kmem_free(mcseg, size);
604*7c478bd9Sstevel@tonic-gate 		return (status);
605*7c478bd9Sstevel@tonic-gate 
606*7c478bd9Sstevel@tonic-gate 	/*
607*7c478bd9Sstevel@tonic-gate 	 * input: id
608*7c478bd9Sstevel@tonic-gate 	 *
609*7c478bd9Sstevel@tonic-gate 	 * return    0: mask, match, size, and devgrpid,
610*7c478bd9Sstevel@tonic-gate 	 *		where global id is unique of all devgrps and local id
611*7c478bd9Sstevel@tonic-gate 	 *		is only unique for mc.
612*7c478bd9Sstevel@tonic-gate 	 *	EINVAL: if id isn't found
613*7c478bd9Sstevel@tonic-gate 	 *	EFAULT: if other errors in kernel.
614*7c478bd9Sstevel@tonic-gate 	 */
615*7c478bd9Sstevel@tonic-gate 	case MCIOC_BANK:
616*7c478bd9Sstevel@tonic-gate 		if (copyin((void *)arg, &mcbank, sizeof (struct mc_bank)) != 0)
617*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
618*7c478bd9Sstevel@tonic-gate 
619*7c478bd9Sstevel@tonic-gate 		DPRINTF(MC_CMD_DEBUG, ("MCIOC_BANK: bank id %d\n", mcbank.id));
620*7c478bd9Sstevel@tonic-gate 
621*7c478bd9Sstevel@tonic-gate 		mutex_enter(&mcdatamutex);
622*7c478bd9Sstevel@tonic-gate 
623*7c478bd9Sstevel@tonic-gate 		if ((bank = (struct bank_info *)mc_node_get(mcbank.id,
624*7c478bd9Sstevel@tonic-gate 		    bank_head)) == NULL) {
625*7c478bd9Sstevel@tonic-gate 			mutex_exit(&mcdatamutex);
626*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
627*7c478bd9Sstevel@tonic-gate 		}
628*7c478bd9Sstevel@tonic-gate 
629*7c478bd9Sstevel@tonic-gate 		DPRINTF(MC_CMD_DEBUG, ("MCIOC_BANK: bank 0x%p valid %d\n",
630*7c478bd9Sstevel@tonic-gate 		    bank->bank_node.id, bank, bank->valid));
631*7c478bd9Sstevel@tonic-gate 
632*7c478bd9Sstevel@tonic-gate 		/*
633*7c478bd9Sstevel@tonic-gate 		 * If (Physic Address & MASK) == MATCH, Physic Address is
634*7c478bd9Sstevel@tonic-gate 		 * located at this bank. The lower physical address bits
635*7c478bd9Sstevel@tonic-gate 		 * are at [9-6].
636*7c478bd9Sstevel@tonic-gate 		 */
637*7c478bd9Sstevel@tonic-gate 		mcbank.mask = (~(bank->lk | ~(MADR_LK_MASK >>
638*7c478bd9Sstevel@tonic-gate 		    MADR_LK_SHIFT))) << MADR_LPA_SHIFT;
639*7c478bd9Sstevel@tonic-gate 		mcbank.match = bank->lm << MADR_LPA_SHIFT;
640*7c478bd9Sstevel@tonic-gate 		mcbank.size = bank->size;
641*7c478bd9Sstevel@tonic-gate 		mcbank.devgrpid.globalid = bank->devgrp_id;
642*7c478bd9Sstevel@tonic-gate 		mcbank.devgrpid.localid = bank->devgrp_id % NDGRPS;
643*7c478bd9Sstevel@tonic-gate 
644*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mcdatamutex);
645*7c478bd9Sstevel@tonic-gate 
646*7c478bd9Sstevel@tonic-gate 		if (copyout(&mcbank, (void *)arg, sizeof (struct mc_bank)))
647*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
648*7c478bd9Sstevel@tonic-gate 		return (0);
649*7c478bd9Sstevel@tonic-gate 
650*7c478bd9Sstevel@tonic-gate 	/*
651*7c478bd9Sstevel@tonic-gate 	 * input:id and allocate space for various length of deviceids
652*7c478bd9Sstevel@tonic-gate 	 *
653*7c478bd9Sstevel@tonic-gate 	 * return    0: size and number of devices.
654*7c478bd9Sstevel@tonic-gate 	 *	EINVAL: id isn't found
655*7c478bd9Sstevel@tonic-gate 	 *	EFAULT: if other errors in kernel.
656*7c478bd9Sstevel@tonic-gate 	 */
657*7c478bd9Sstevel@tonic-gate 	case MCIOC_DEVGRP:
658*7c478bd9Sstevel@tonic-gate 
659*7c478bd9Sstevel@tonic-gate 		if (copyin((void *)arg, &mcdevgrp,
660*7c478bd9Sstevel@tonic-gate 		    sizeof (struct mc_devgrp)) != 0)
661*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
662*7c478bd9Sstevel@tonic-gate 
663*7c478bd9Sstevel@tonic-gate 		mutex_enter(&mcdatamutex);
664*7c478bd9Sstevel@tonic-gate 		if ((dgrp = (struct dgrp_info *)mc_node_get(mcdevgrp.id,
665*7c478bd9Sstevel@tonic-gate 		    dgrp_head)) == NULL) {
666*7c478bd9Sstevel@tonic-gate 			DPRINTF(MC_CMD_DEBUG, ("MCIOC_DEVGRP: not match, id "
667*7c478bd9Sstevel@tonic-gate 			    "%d\n", mcdevgrp.id));
668*7c478bd9Sstevel@tonic-gate 			mutex_exit(&mcdatamutex);
669*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
670*7c478bd9Sstevel@tonic-gate 		}
671*7c478bd9Sstevel@tonic-gate 
672*7c478bd9Sstevel@tonic-gate 		mcdevgrp.ndevices = dgrp->ndevices;
673*7c478bd9Sstevel@tonic-gate 		mcdevgrp.size = dgrp->size;
674*7c478bd9Sstevel@tonic-gate 
675*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mcdatamutex);
676*7c478bd9Sstevel@tonic-gate 
677*7c478bd9Sstevel@tonic-gate 		if (copyout(&mcdevgrp, (void *)arg, sizeof (struct mc_devgrp)))
678*7c478bd9Sstevel@tonic-gate 			status = EFAULT;
679*7c478bd9Sstevel@tonic-gate 
680*7c478bd9Sstevel@tonic-gate 		return (status);
681*7c478bd9Sstevel@tonic-gate 
682*7c478bd9Sstevel@tonic-gate 	/*
683*7c478bd9Sstevel@tonic-gate 	 * input: nmcs and allocate space for various length of mcids
684*7c478bd9Sstevel@tonic-gate 	 *
685*7c478bd9Sstevel@tonic-gate 	 * return    0: number of mc, and all mcids,
686*7c478bd9Sstevel@tonic-gate 	 *		where glocal and local ids are identical.
687*7c478bd9Sstevel@tonic-gate 	 *	EINVAL: if the given nmcs is less than that in kernel and
688*7c478bd9Sstevel@tonic-gate 	 *		nmcs of struct will be updated.
689*7c478bd9Sstevel@tonic-gate 	 *	EFAULT: if other errors in kernel.
690*7c478bd9Sstevel@tonic-gate 	 */
691*7c478bd9Sstevel@tonic-gate 	case MCIOC_CTRLCONF:
692*7c478bd9Sstevel@tonic-gate 		if (copyin((void *)arg, &mcctrlconf_in,
693*7c478bd9Sstevel@tonic-gate 		    sizeof (struct mc_ctrlconf)) != 0)
694*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
695*7c478bd9Sstevel@tonic-gate 
696*7c478bd9Sstevel@tonic-gate 		mutex_enter(&mcdatamutex);
697*7c478bd9Sstevel@tonic-gate 		if (mcctrlconf_in.nmcs < nmcs) {
698*7c478bd9Sstevel@tonic-gate 			mcctrlconf_in.nmcs = nmcs;
699*7c478bd9Sstevel@tonic-gate 			if (copyout(&mcctrlconf_in, (void *)arg,
700*7c478bd9Sstevel@tonic-gate 			    sizeof (struct mc_ctrlconf)))
701*7c478bd9Sstevel@tonic-gate 				status = EFAULT;
702*7c478bd9Sstevel@tonic-gate 			else
703*7c478bd9Sstevel@tonic-gate 				status = EINVAL;
704*7c478bd9Sstevel@tonic-gate 
705*7c478bd9Sstevel@tonic-gate 			mutex_exit(&mcdatamutex);
706*7c478bd9Sstevel@tonic-gate 			return (status);
707*7c478bd9Sstevel@tonic-gate 		}
708*7c478bd9Sstevel@tonic-gate 
709*7c478bd9Sstevel@tonic-gate 		/*
710*7c478bd9Sstevel@tonic-gate 		 * Cannot just use the size of the struct because of the various
711*7c478bd9Sstevel@tonic-gate 		 * length struct
712*7c478bd9Sstevel@tonic-gate 		 */
713*7c478bd9Sstevel@tonic-gate 		size = sizeof (struct mc_ctrlconf) + ((nmcs - 1) *
714*7c478bd9Sstevel@tonic-gate 		    sizeof (mcctrlconf->mcids[0]));
715*7c478bd9Sstevel@tonic-gate 		mcctrlconf = kmem_zalloc(size, KM_SLEEP);
716*7c478bd9Sstevel@tonic-gate 
717*7c478bd9Sstevel@tonic-gate 		mcctrlconf->nmcs = nmcs;
718*7c478bd9Sstevel@tonic-gate 
719*7c478bd9Sstevel@tonic-gate 		/* Get all MC ids and add to mcctrlconf */
720*7c478bd9Sstevel@tonic-gate 		mctrl = mctrl_head;
721*7c478bd9Sstevel@tonic-gate 		i = 0;
722*7c478bd9Sstevel@tonic-gate 		while (mctrl != NULL) {
723*7c478bd9Sstevel@tonic-gate 			mcctrlconf->mcids[i].globalid = mctrl->id;
724*7c478bd9Sstevel@tonic-gate 			mcctrlconf->mcids[i].localid = mctrl->id;
725*7c478bd9Sstevel@tonic-gate 			i++;
726*7c478bd9Sstevel@tonic-gate 			mctrl = mctrl->next;
727*7c478bd9Sstevel@tonic-gate 		}
728*7c478bd9Sstevel@tonic-gate 		ASSERT(i == nmcs);
729*7c478bd9Sstevel@tonic-gate 
730*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mcdatamutex);
731*7c478bd9Sstevel@tonic-gate 
732*7c478bd9Sstevel@tonic-gate 		if (copyout(mcctrlconf, (void *)arg, size))
733*7c478bd9Sstevel@tonic-gate 			status = EFAULT;
734*7c478bd9Sstevel@tonic-gate 
735*7c478bd9Sstevel@tonic-gate 		kmem_free(mcctrlconf, size);
736*7c478bd9Sstevel@tonic-gate 		return (status);
737*7c478bd9Sstevel@tonic-gate 
738*7c478bd9Sstevel@tonic-gate 	/*
739*7c478bd9Sstevel@tonic-gate 	 * input:id, ndevgrps and allocate space for various length of devgrpids
740*7c478bd9Sstevel@tonic-gate 	 *
741*7c478bd9Sstevel@tonic-gate 	 * return    0: number of devgrp, and all devgrpids,
742*7c478bd9Sstevel@tonic-gate 	 *		is unique of all devgrps and local id is only unique
743*7c478bd9Sstevel@tonic-gate 	 *		for mc.
744*7c478bd9Sstevel@tonic-gate 	 *	EINVAL: either if id isn't found or if the given ndevgrps is
745*7c478bd9Sstevel@tonic-gate 	 *		less than that in kernel and ndevgrps of struct will
746*7c478bd9Sstevel@tonic-gate 	 *		be updated.
747*7c478bd9Sstevel@tonic-gate 	 *	EFAULT: if other errors in kernel.
748*7c478bd9Sstevel@tonic-gate 	 */
749*7c478bd9Sstevel@tonic-gate 	case MCIOC_CONTROL:
750*7c478bd9Sstevel@tonic-gate 		if (copyin((void *)arg, &mccontrol_in,
751*7c478bd9Sstevel@tonic-gate 		    sizeof (struct mc_control)) != 0)
752*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
753*7c478bd9Sstevel@tonic-gate 
754*7c478bd9Sstevel@tonic-gate 		mutex_enter(&mcdatamutex);
755*7c478bd9Sstevel@tonic-gate 		if ((mcport = (struct mctrl_info *)mc_node_get(mccontrol_in.id,
756*7c478bd9Sstevel@tonic-gate 		    mctrl_head)) == NULL) {
757*7c478bd9Sstevel@tonic-gate 			mutex_exit(&mcdatamutex);
758*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
759*7c478bd9Sstevel@tonic-gate 		}
760*7c478bd9Sstevel@tonic-gate 
761*7c478bd9Sstevel@tonic-gate 		/*
762*7c478bd9Sstevel@tonic-gate 		 * mcport->ndevgrps zero means Memory Controller is disable.
763*7c478bd9Sstevel@tonic-gate 		 */
764*7c478bd9Sstevel@tonic-gate 		if ((mccontrol_in.ndevgrps < mcport->ndevgrps) ||
765*7c478bd9Sstevel@tonic-gate 		    (mcport->ndevgrps == 0)) {
766*7c478bd9Sstevel@tonic-gate 			mccontrol_in.ndevgrps = mcport->ndevgrps;
767*7c478bd9Sstevel@tonic-gate 			if (copyout(&mccontrol_in, (void *)arg,
768*7c478bd9Sstevel@tonic-gate 			    sizeof (struct mc_control)))
769*7c478bd9Sstevel@tonic-gate 				status = EFAULT;
770*7c478bd9Sstevel@tonic-gate 			else if (mcport->ndevgrps != 0)
771*7c478bd9Sstevel@tonic-gate 				status = EINVAL;
772*7c478bd9Sstevel@tonic-gate 
773*7c478bd9Sstevel@tonic-gate 			mutex_exit(&mcdatamutex);
774*7c478bd9Sstevel@tonic-gate 			return (status);
775*7c478bd9Sstevel@tonic-gate 		}
776*7c478bd9Sstevel@tonic-gate 
777*7c478bd9Sstevel@tonic-gate 		size = sizeof (struct mc_control) + (mcport->ndevgrps - 1) *
778*7c478bd9Sstevel@tonic-gate 		    sizeof (mccontrol->devgrpids[0]);
779*7c478bd9Sstevel@tonic-gate 		mccontrol = kmem_zalloc(size, KM_SLEEP);
780*7c478bd9Sstevel@tonic-gate 
781*7c478bd9Sstevel@tonic-gate 		mccontrol->id = mcport->mctrl_node.id;
782*7c478bd9Sstevel@tonic-gate 		mccontrol->ndevgrps = mcport->ndevgrps;
783*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < mcport->ndevgrps; i++) {
784*7c478bd9Sstevel@tonic-gate 			mccontrol->devgrpids[i].globalid = mcport->devgrpids[i];
785*7c478bd9Sstevel@tonic-gate 			mccontrol->devgrpids[i].localid =
786*7c478bd9Sstevel@tonic-gate 			    mcport->devgrpids[i] % NDGRPS;
787*7c478bd9Sstevel@tonic-gate 			DPRINTF(MC_CMD_DEBUG, ("MCIOC_CONTROL: devgrp id %d\n",
788*7c478bd9Sstevel@tonic-gate 			    mccontrol->devgrpids[i]));
789*7c478bd9Sstevel@tonic-gate 		}
790*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mcdatamutex);
791*7c478bd9Sstevel@tonic-gate 
792*7c478bd9Sstevel@tonic-gate 		if (copyout(mccontrol, (void *)arg, size))
793*7c478bd9Sstevel@tonic-gate 			status = EFAULT;
794*7c478bd9Sstevel@tonic-gate 
795*7c478bd9Sstevel@tonic-gate 		kmem_free(mccontrol, size);
796*7c478bd9Sstevel@tonic-gate 		return (status);
797*7c478bd9Sstevel@tonic-gate 
798*7c478bd9Sstevel@tonic-gate 	/*
799*7c478bd9Sstevel@tonic-gate 	 * input:id
800*7c478bd9Sstevel@tonic-gate 	 *
801*7c478bd9Sstevel@tonic-gate 	 * return    0: CPU flushed successfully.
802*7c478bd9Sstevel@tonic-gate 	 *	EINVAL: the id wasn't found
803*7c478bd9Sstevel@tonic-gate 	 */
804*7c478bd9Sstevel@tonic-gate 	case MCIOC_ECFLUSH:
805*7c478bd9Sstevel@tonic-gate 		mutex_enter(&cpu_lock);
806*7c478bd9Sstevel@tonic-gate 		cpu = cpu_get((processorid_t)arg);
807*7c478bd9Sstevel@tonic-gate 		mutex_exit(&cpu_lock);
808*7c478bd9Sstevel@tonic-gate 		if (cpu == NULL)
809*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
810*7c478bd9Sstevel@tonic-gate 
811*7c478bd9Sstevel@tonic-gate 		xc_one(arg, (xcfunc_t *)cpu_flush_ecache, 0, 0);
812*7c478bd9Sstevel@tonic-gate 
813*7c478bd9Sstevel@tonic-gate 		return (0);
814*7c478bd9Sstevel@tonic-gate 
815*7c478bd9Sstevel@tonic-gate 	default:
816*7c478bd9Sstevel@tonic-gate 		DPRINTF(MC_CMD_DEBUG, ("DEFAULT: cmd is wrong\n"));
817*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
818*7c478bd9Sstevel@tonic-gate 	}
819*7c478bd9Sstevel@tonic-gate }
820*7c478bd9Sstevel@tonic-gate 
821*7c478bd9Sstevel@tonic-gate /*
822*7c478bd9Sstevel@tonic-gate  * Get Memory Address Decoding Registers and construct list.
823*7c478bd9Sstevel@tonic-gate  * flag is to workaround Cheetah's restriction where register cannot be mapped
824*7c478bd9Sstevel@tonic-gate  * if port id(MC registers on it) == cpu id(process is running on it).
825*7c478bd9Sstevel@tonic-gate  */
826*7c478bd9Sstevel@tonic-gate static int
827*7c478bd9Sstevel@tonic-gate mc_get_mcregs(struct mc_soft_state *softsp)
828*7c478bd9Sstevel@tonic-gate {
829*7c478bd9Sstevel@tonic-gate 	int i;
830*7c478bd9Sstevel@tonic-gate 	int err = 0;
831*7c478bd9Sstevel@tonic-gate 	uint64_t madreg;
832*7c478bd9Sstevel@tonic-gate 	uint64_t ma_reg_array[NBANKS];	/* there are NBANKS of madrs */
833*7c478bd9Sstevel@tonic-gate 
834*7c478bd9Sstevel@tonic-gate 	/* Construct lists for MC, mctrl_info, dgrp_info, and device_info */
835*7c478bd9Sstevel@tonic-gate 	mc_construct(softsp->portid, softsp->memlayoutp);
836*7c478bd9Sstevel@tonic-gate 
837*7c478bd9Sstevel@tonic-gate 	/*
838*7c478bd9Sstevel@tonic-gate 	 * If memlayoutp is NULL, the Memory Controller is disable, and
839*7c478bd9Sstevel@tonic-gate 	 * doesn't need to create any bank and segment.
840*7c478bd9Sstevel@tonic-gate 	 */
841*7c478bd9Sstevel@tonic-gate 	if (softsp->memlayoutp == NULL)
842*7c478bd9Sstevel@tonic-gate 		goto exit;
843*7c478bd9Sstevel@tonic-gate 
844*7c478bd9Sstevel@tonic-gate 	/*
845*7c478bd9Sstevel@tonic-gate 	 * Get the content of 4 Memory Address Decoding Registers, and
846*7c478bd9Sstevel@tonic-gate 	 * construct lists of logical banks and segments.
847*7c478bd9Sstevel@tonic-gate 	 */
848*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < NBANKS; i++) {
849*7c478bd9Sstevel@tonic-gate 		DPRINTF(MC_REG_DEBUG, ("get_mcregs: mapreg=0x%p portid=%d "
850*7c478bd9Sstevel@tonic-gate 		    "cpu=%d\n", softsp->mc_base, softsp->portid, CPU->cpu_id));
851*7c478bd9Sstevel@tonic-gate 
852*7c478bd9Sstevel@tonic-gate 		kpreempt_disable();
853*7c478bd9Sstevel@tonic-gate 		if (softsp->portid == (cpunodes[CPU->cpu_id].portid))
854*7c478bd9Sstevel@tonic-gate 			madreg = get_mcr(MADR0OFFSET + (i * REGOFFSET));
855*7c478bd9Sstevel@tonic-gate 		else
856*7c478bd9Sstevel@tonic-gate 			madreg = *((uint64_t *)(softsp->mc_base + MADR0OFFSET +
857*7c478bd9Sstevel@tonic-gate 			    (i * REGOFFSET)));
858*7c478bd9Sstevel@tonic-gate 		kpreempt_enable();
859*7c478bd9Sstevel@tonic-gate 
860*7c478bd9Sstevel@tonic-gate 		DPRINTF(MC_REG_DEBUG, ("get_mcregs 2: memlayoutp=0x%p madreg "
861*7c478bd9Sstevel@tonic-gate 		    "reg=0x%llx\n", softsp->memlayoutp, madreg));
862*7c478bd9Sstevel@tonic-gate 
863*7c478bd9Sstevel@tonic-gate 		ma_reg_array[i] = madreg;
864*7c478bd9Sstevel@tonic-gate 
865*7c478bd9Sstevel@tonic-gate 		if ((err = mlayout_add(softsp->portid, i, madreg,
866*7c478bd9Sstevel@tonic-gate 		    softsp->memlayoutp)) == -1)
867*7c478bd9Sstevel@tonic-gate 			break;
868*7c478bd9Sstevel@tonic-gate 	}
869*7c478bd9Sstevel@tonic-gate 
870*7c478bd9Sstevel@tonic-gate 	/*
871*7c478bd9Sstevel@tonic-gate 	 * Create the logical bank property for this mc node. This
872*7c478bd9Sstevel@tonic-gate 	 * property is an encoded array of the madr for each logical
873*7c478bd9Sstevel@tonic-gate 	 * bank (there are NBANKS of these).
874*7c478bd9Sstevel@tonic-gate 	 */
875*7c478bd9Sstevel@tonic-gate 	if (ddi_prop_exists(DDI_DEV_T_ANY, softsp->dip,
876*7c478bd9Sstevel@tonic-gate 	    DDI_PROP_NOTPROM | DDI_PROP_DONTPASS,
877*7c478bd9Sstevel@tonic-gate 	    MEM_CFG_PROP_NAME) != 1) {
878*7c478bd9Sstevel@tonic-gate 		(void) ddi_prop_create(DDI_DEV_T_NONE, softsp->dip,
879*7c478bd9Sstevel@tonic-gate 			DDI_PROP_CANSLEEP, MEM_CFG_PROP_NAME,
880*7c478bd9Sstevel@tonic-gate 			(caddr_t)&ma_reg_array, sizeof (ma_reg_array));
881*7c478bd9Sstevel@tonic-gate 	}
882*7c478bd9Sstevel@tonic-gate 
883*7c478bd9Sstevel@tonic-gate exit:
884*7c478bd9Sstevel@tonic-gate 	if (!err) {
885*7c478bd9Sstevel@tonic-gate 		mutex_enter(&mcdatamutex);
886*7c478bd9Sstevel@tonic-gate 		nmcs++;
887*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mcdatamutex);
888*7c478bd9Sstevel@tonic-gate 	}
889*7c478bd9Sstevel@tonic-gate 	return (err);
890*7c478bd9Sstevel@tonic-gate }
891*7c478bd9Sstevel@tonic-gate 
892*7c478bd9Sstevel@tonic-gate /*
893*7c478bd9Sstevel@tonic-gate  * A cache line is composed of four quadwords with the associated ECC, the
894*7c478bd9Sstevel@tonic-gate  * MTag along with its associated ECC. This is depicted below:
895*7c478bd9Sstevel@tonic-gate  *
896*7c478bd9Sstevel@tonic-gate  * |                    Data                    |   ECC   | Mtag |MTag ECC|
897*7c478bd9Sstevel@tonic-gate  *  127                                         0 8       0 2    0 3      0
898*7c478bd9Sstevel@tonic-gate  *
899*7c478bd9Sstevel@tonic-gate  * synd_code will be mapped as the following order to mc_get_mem_unum.
900*7c478bd9Sstevel@tonic-gate  *  143                                         16        7      4        0
901*7c478bd9Sstevel@tonic-gate  *
902*7c478bd9Sstevel@tonic-gate  * |  Quadword  0  |  Quadword  1  |  Quadword  2  |  Quadword  3  |
903*7c478bd9Sstevel@tonic-gate  *  575         432 431         288 287         144 143		   0
904*7c478bd9Sstevel@tonic-gate  *
905*7c478bd9Sstevel@tonic-gate  * dimm table: each bit at a cache line needs two bits to present one of
906*7c478bd9Sstevel@tonic-gate  *      four dimms. So it needs 144 bytes(576 * 2 / 8). The content is in
907*7c478bd9Sstevel@tonic-gate  *      big edian order, i.e. dimm_table[0] presents for bit 572 to 575.
908*7c478bd9Sstevel@tonic-gate  *
909*7c478bd9Sstevel@tonic-gate  * pin table: each bit at a cache line needs one byte to present pin position,
910*7c478bd9Sstevel@tonic-gate  *      where max. is 230. So it needs 576 bytes. The order of table index is
911*7c478bd9Sstevel@tonic-gate  *      the same as bit position at a cache line, i.e. pin_table[0] presents
912*7c478bd9Sstevel@tonic-gate  *      for bit 0, Mtag ECC 0 of Quadword 3.
913*7c478bd9Sstevel@tonic-gate  *
914*7c478bd9Sstevel@tonic-gate  * This is a mapping from syndrome code to QuadWord Logical layout at Safari.
915*7c478bd9Sstevel@tonic-gate  * Referring to Figure 3-4, Excalibur Architecture Manual.
916*7c478bd9Sstevel@tonic-gate  * This table could be moved to cheetah.c if other platform teams agree with
917*7c478bd9Sstevel@tonic-gate  * the bit layout at QuadWord.
918*7c478bd9Sstevel@tonic-gate  */
919*7c478bd9Sstevel@tonic-gate 
920*7c478bd9Sstevel@tonic-gate static uint8_t qwordmap[] =
921*7c478bd9Sstevel@tonic-gate {
922*7c478bd9Sstevel@tonic-gate 16,   17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,
923*7c478bd9Sstevel@tonic-gate 32,   33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,
924*7c478bd9Sstevel@tonic-gate 48,   49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,
925*7c478bd9Sstevel@tonic-gate 64,   65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,
926*7c478bd9Sstevel@tonic-gate 80,   81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,
927*7c478bd9Sstevel@tonic-gate 96,   97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
928*7c478bd9Sstevel@tonic-gate 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
929*7c478bd9Sstevel@tonic-gate 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
930*7c478bd9Sstevel@tonic-gate 7,    8,   9,  10,  11,  12,  13,  14,  15,   4,   5,   6,   0,   1,   2,   3,
931*7c478bd9Sstevel@tonic-gate };
932*7c478bd9Sstevel@tonic-gate 
933*7c478bd9Sstevel@tonic-gate #define	QWORD_SIZE	144
934*7c478bd9Sstevel@tonic-gate 
935*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
936*7c478bd9Sstevel@tonic-gate static int
937*7c478bd9Sstevel@tonic-gate mc_get_mem_unum(int synd_code, uint64_t paddr, char *buf, int buflen, int *lenp)
938*7c478bd9Sstevel@tonic-gate {
939*7c478bd9Sstevel@tonic-gate 	int i, upper_pa, lower_pa, dimmoffset;
940*7c478bd9Sstevel@tonic-gate 	int quadword, pos_cacheline, position, index, idx4dimm;
941*7c478bd9Sstevel@tonic-gate 	int qwlayout = synd_code;
942*7c478bd9Sstevel@tonic-gate 	short offset, data;
943*7c478bd9Sstevel@tonic-gate 	char unum[UNUM_NAMLEN];
944*7c478bd9Sstevel@tonic-gate 	struct dimm_info *dimmp;
945*7c478bd9Sstevel@tonic-gate 	struct pin_info *pinp;
946*7c478bd9Sstevel@tonic-gate 	struct bank_info *bank;
947*7c478bd9Sstevel@tonic-gate 
948*7c478bd9Sstevel@tonic-gate 	/*
949*7c478bd9Sstevel@tonic-gate 	 * Enforce old Openboot requirement for synd code, either a single-bit
950*7c478bd9Sstevel@tonic-gate 	 * code from 0..QWORD_SIZE-1 or -1 (multi-bit error).
951*7c478bd9Sstevel@tonic-gate 	 */
952*7c478bd9Sstevel@tonic-gate 	if (qwlayout < -1 || qwlayout >= QWORD_SIZE)
953*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
954*7c478bd9Sstevel@tonic-gate 
955*7c478bd9Sstevel@tonic-gate 	unum[0] = '\0';
956*7c478bd9Sstevel@tonic-gate 
957*7c478bd9Sstevel@tonic-gate 	upper_pa = (paddr & MADR_UPA_MASK) >> MADR_UPA_SHIFT;
958*7c478bd9Sstevel@tonic-gate 	lower_pa = (paddr & MADR_LPA_MASK) >> MADR_LPA_SHIFT;
959*7c478bd9Sstevel@tonic-gate 
960*7c478bd9Sstevel@tonic-gate 	DPRINTF(MC_GUNUM_DEBUG, ("qwlayout %d\n", qwlayout));
961*7c478bd9Sstevel@tonic-gate 
962*7c478bd9Sstevel@tonic-gate 	/*
963*7c478bd9Sstevel@tonic-gate 	 * Scan all logical banks to get one responding to the physical
964*7c478bd9Sstevel@tonic-gate 	 * address. Then compute the index to look up dimm and pin tables
965*7c478bd9Sstevel@tonic-gate 	 * to generate the unmuber.
966*7c478bd9Sstevel@tonic-gate 	 */
967*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mcdatamutex);
968*7c478bd9Sstevel@tonic-gate 	bank = (struct bank_info *)bank_head;
969*7c478bd9Sstevel@tonic-gate 	while (bank != NULL) {
970*7c478bd9Sstevel@tonic-gate 		int bankid, mcid, bankno_permc;
971*7c478bd9Sstevel@tonic-gate 
972*7c478bd9Sstevel@tonic-gate 		bankid = bank->bank_node.id;
973*7c478bd9Sstevel@tonic-gate 		bankno_permc = bankid % NBANKS;
974*7c478bd9Sstevel@tonic-gate 		mcid = bankid / NBANKS;
975*7c478bd9Sstevel@tonic-gate 
976*7c478bd9Sstevel@tonic-gate 		/*
977*7c478bd9Sstevel@tonic-gate 		 * The Address Decoding logic decodes the different fields
978*7c478bd9Sstevel@tonic-gate 		 * in the Memory Address Drcoding register to determine
979*7c478bd9Sstevel@tonic-gate 		 * whether a particular logic bank should respond to a
980*7c478bd9Sstevel@tonic-gate 		 * physical address.
981*7c478bd9Sstevel@tonic-gate 		 */
982*7c478bd9Sstevel@tonic-gate 		if ((!bank->valid) || ((~(~(upper_pa ^ bank->um) |
983*7c478bd9Sstevel@tonic-gate 		    bank->uk)) || (~(~(lower_pa ^ bank->lm) | bank->lk)))) {
984*7c478bd9Sstevel@tonic-gate 			bank = (struct bank_info *)bank->bank_node.next;
985*7c478bd9Sstevel@tonic-gate 			continue;
986*7c478bd9Sstevel@tonic-gate 		}
987*7c478bd9Sstevel@tonic-gate 
988*7c478bd9Sstevel@tonic-gate 		dimmoffset = (bankno_permc % NDGRPS) * NDIMMS;
989*7c478bd9Sstevel@tonic-gate 
990*7c478bd9Sstevel@tonic-gate 		dimmp = (struct dimm_info *)bank->dimminfop;
991*7c478bd9Sstevel@tonic-gate 		ASSERT(dimmp != NULL);
992*7c478bd9Sstevel@tonic-gate 
993*7c478bd9Sstevel@tonic-gate 		if ((qwlayout >= 0) && (qwlayout < QWORD_SIZE)) {
994*7c478bd9Sstevel@tonic-gate 			/*
995*7c478bd9Sstevel@tonic-gate 			 * single-bit error handling, we can identify specific
996*7c478bd9Sstevel@tonic-gate 			 * DIMM.
997*7c478bd9Sstevel@tonic-gate 			 */
998*7c478bd9Sstevel@tonic-gate 
999*7c478bd9Sstevel@tonic-gate 			pinp = (struct pin_info *)&dimmp->data[0];
1000*7c478bd9Sstevel@tonic-gate 
1001*7c478bd9Sstevel@tonic-gate 			if (!dimmp->sym_flag)
1002*7c478bd9Sstevel@tonic-gate 				pinp++;
1003*7c478bd9Sstevel@tonic-gate 
1004*7c478bd9Sstevel@tonic-gate 			quadword = (paddr & 0x3f) / 16;
1005*7c478bd9Sstevel@tonic-gate 			/* or quadword = (paddr >> 4) % 4; */
1006*7c478bd9Sstevel@tonic-gate 			pos_cacheline = ((3 - quadword) * 144) +
1007*7c478bd9Sstevel@tonic-gate 			    qwordmap[qwlayout];
1008*7c478bd9Sstevel@tonic-gate 			position = 575 - pos_cacheline;
1009*7c478bd9Sstevel@tonic-gate 			index = position * 2 / 8;
1010*7c478bd9Sstevel@tonic-gate 			offset = position % 4;
1011*7c478bd9Sstevel@tonic-gate 
1012*7c478bd9Sstevel@tonic-gate 			/*
1013*7c478bd9Sstevel@tonic-gate 			 * Trade-off: We cound't add pin number to
1014*7c478bd9Sstevel@tonic-gate 			 * unumber string because statistic number
1015*7c478bd9Sstevel@tonic-gate 			 * pumps up at the corresponding dimm not pin.
1016*7c478bd9Sstevel@tonic-gate 			 * (void) sprintf(unum, "Pin %1u ", (uint_t)
1017*7c478bd9Sstevel@tonic-gate 			 * pinp->pintable[pos_cacheline]);
1018*7c478bd9Sstevel@tonic-gate 			 */
1019*7c478bd9Sstevel@tonic-gate 			DPRINTF(MC_GUNUM_DEBUG, ("Pin number %1u\n",
1020*7c478bd9Sstevel@tonic-gate 			    (uint_t)pinp->pintable[pos_cacheline]));
1021*7c478bd9Sstevel@tonic-gate 			data = pinp->dimmtable[index];
1022*7c478bd9Sstevel@tonic-gate 			idx4dimm = (data >> ((3 - offset) * 2)) & 3;
1023*7c478bd9Sstevel@tonic-gate 
1024*7c478bd9Sstevel@tonic-gate 			(void) strncpy(unum,
1025*7c478bd9Sstevel@tonic-gate 			    (char *)dimmp->label[dimmoffset + idx4dimm],
1026*7c478bd9Sstevel@tonic-gate 			    UNUM_NAMLEN);
1027*7c478bd9Sstevel@tonic-gate 			DPRINTF(MC_GUNUM_DEBUG, ("unum %s\n", unum));
1028*7c478bd9Sstevel@tonic-gate 			/*
1029*7c478bd9Sstevel@tonic-gate 			 * platform hook for adding label information to unum.
1030*7c478bd9Sstevel@tonic-gate 			 */
1031*7c478bd9Sstevel@tonic-gate 			mc_add_mem_unum_label(unum, mcid, bankno_permc,
1032*7c478bd9Sstevel@tonic-gate 			    idx4dimm);
1033*7c478bd9Sstevel@tonic-gate 		} else {
1034*7c478bd9Sstevel@tonic-gate 			char *p = unum;
1035*7c478bd9Sstevel@tonic-gate 			size_t res = UNUM_NAMLEN;
1036*7c478bd9Sstevel@tonic-gate 
1037*7c478bd9Sstevel@tonic-gate 			/*
1038*7c478bd9Sstevel@tonic-gate 			 * multi-bit error handling, we can only identify
1039*7c478bd9Sstevel@tonic-gate 			 * bank of DIMMs.
1040*7c478bd9Sstevel@tonic-gate 			 */
1041*7c478bd9Sstevel@tonic-gate 
1042*7c478bd9Sstevel@tonic-gate 			for (i = 0; (i < NDIMMS) && (res > 0); i++) {
1043*7c478bd9Sstevel@tonic-gate 				(void) snprintf(p, res, "%s%s",
1044*7c478bd9Sstevel@tonic-gate 				    i == 0 ? "" : " ",
1045*7c478bd9Sstevel@tonic-gate 				    (char *)dimmp->label[dimmoffset + i]);
1046*7c478bd9Sstevel@tonic-gate 				res -= strlen(p);
1047*7c478bd9Sstevel@tonic-gate 				p += strlen(p);
1048*7c478bd9Sstevel@tonic-gate 			}
1049*7c478bd9Sstevel@tonic-gate 
1050*7c478bd9Sstevel@tonic-gate 			/*
1051*7c478bd9Sstevel@tonic-gate 			 * platform hook for adding label information
1052*7c478bd9Sstevel@tonic-gate 			 * to unum.
1053*7c478bd9Sstevel@tonic-gate 			 */
1054*7c478bd9Sstevel@tonic-gate 			mc_add_mem_unum_label(unum, mcid, bankno_permc, -1);
1055*7c478bd9Sstevel@tonic-gate 		}
1056*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mcdatamutex);
1057*7c478bd9Sstevel@tonic-gate 		if ((strlen(unum) >= UNUM_NAMLEN) ||
1058*7c478bd9Sstevel@tonic-gate 		    (strlen(unum) >= buflen)) {
1059*7c478bd9Sstevel@tonic-gate 			return (ENOSPC);
1060*7c478bd9Sstevel@tonic-gate 		} else {
1061*7c478bd9Sstevel@tonic-gate 			(void) strncpy(buf, unum, buflen);
1062*7c478bd9Sstevel@tonic-gate 			*lenp = strlen(buf);
1063*7c478bd9Sstevel@tonic-gate 			return (0);
1064*7c478bd9Sstevel@tonic-gate 		}
1065*7c478bd9Sstevel@tonic-gate 	}	/* end of while loop for logic bank list */
1066*7c478bd9Sstevel@tonic-gate 
1067*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mcdatamutex);
1068*7c478bd9Sstevel@tonic-gate 	return (ENXIO);
1069*7c478bd9Sstevel@tonic-gate }
1070*7c478bd9Sstevel@tonic-gate 
1071*7c478bd9Sstevel@tonic-gate static int
1072*7c478bd9Sstevel@tonic-gate mc_get_mem_info(int synd_code, uint64_t paddr,
1073*7c478bd9Sstevel@tonic-gate     uint64_t *mem_sizep, uint64_t *seg_sizep, uint64_t *bank_sizep,
1074*7c478bd9Sstevel@tonic-gate     int *segsp, int *banksp, int *mcidp)
1075*7c478bd9Sstevel@tonic-gate {
1076*7c478bd9Sstevel@tonic-gate 	int upper_pa, lower_pa;
1077*7c478bd9Sstevel@tonic-gate 	struct bank_info *bankp;
1078*7c478bd9Sstevel@tonic-gate 
1079*7c478bd9Sstevel@tonic-gate 	if (synd_code < -1 || synd_code >= QWORD_SIZE)
1080*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
1081*7c478bd9Sstevel@tonic-gate 
1082*7c478bd9Sstevel@tonic-gate 	upper_pa = (paddr & MADR_UPA_MASK) >> MADR_UPA_SHIFT;
1083*7c478bd9Sstevel@tonic-gate 	lower_pa = (paddr & MADR_LPA_MASK) >> MADR_LPA_SHIFT;
1084*7c478bd9Sstevel@tonic-gate 
1085*7c478bd9Sstevel@tonic-gate 	/*
1086*7c478bd9Sstevel@tonic-gate 	 * Scan all logical banks to get one responding to the physical
1087*7c478bd9Sstevel@tonic-gate 	 * address.
1088*7c478bd9Sstevel@tonic-gate 	 */
1089*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mcdatamutex);
1090*7c478bd9Sstevel@tonic-gate 	bankp = (struct bank_info *)bank_head;
1091*7c478bd9Sstevel@tonic-gate 	while (bankp != NULL) {
1092*7c478bd9Sstevel@tonic-gate 		struct seg_info *segp;
1093*7c478bd9Sstevel@tonic-gate 		int bankid, mcid;
1094*7c478bd9Sstevel@tonic-gate 
1095*7c478bd9Sstevel@tonic-gate 		bankid = bankp->bank_node.id;
1096*7c478bd9Sstevel@tonic-gate 		mcid = bankid / NBANKS;
1097*7c478bd9Sstevel@tonic-gate 
1098*7c478bd9Sstevel@tonic-gate 		/*
1099*7c478bd9Sstevel@tonic-gate 		 * The Address Decoding logic decodes the different fields
1100*7c478bd9Sstevel@tonic-gate 		 * in the Memory Address Decoding register to determine
1101*7c478bd9Sstevel@tonic-gate 		 * whether a particular logic bank should respond to a
1102*7c478bd9Sstevel@tonic-gate 		 * physical address.
1103*7c478bd9Sstevel@tonic-gate 		 */
1104*7c478bd9Sstevel@tonic-gate 		if ((!bankp->valid) || ((~(~(upper_pa ^ bankp->um) |
1105*7c478bd9Sstevel@tonic-gate 		    bankp->uk)) || (~(~(lower_pa ^ bankp->lm) | bankp->lk)))) {
1106*7c478bd9Sstevel@tonic-gate 			bankp = (struct bank_info *)bankp->bank_node.next;
1107*7c478bd9Sstevel@tonic-gate 			continue;
1108*7c478bd9Sstevel@tonic-gate 		}
1109*7c478bd9Sstevel@tonic-gate 
1110*7c478bd9Sstevel@tonic-gate 		/*
1111*7c478bd9Sstevel@tonic-gate 		 * Get the corresponding segment.
1112*7c478bd9Sstevel@tonic-gate 		 */
1113*7c478bd9Sstevel@tonic-gate 		if ((segp = (struct seg_info *)mc_node_get(bankp->seg_id,
1114*7c478bd9Sstevel@tonic-gate 		    seg_head)) == NULL) {
1115*7c478bd9Sstevel@tonic-gate 			mutex_exit(&mcdatamutex);
1116*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
1117*7c478bd9Sstevel@tonic-gate 		}
1118*7c478bd9Sstevel@tonic-gate 
1119*7c478bd9Sstevel@tonic-gate 		*mem_sizep = memsize;
1120*7c478bd9Sstevel@tonic-gate 		*seg_sizep = segp->size;
1121*7c478bd9Sstevel@tonic-gate 		*bank_sizep = bankp->size;
1122*7c478bd9Sstevel@tonic-gate 		*segsp = nsegments;
1123*7c478bd9Sstevel@tonic-gate 		*banksp = segp->nbanks;
1124*7c478bd9Sstevel@tonic-gate 		*mcidp = mcid;
1125*7c478bd9Sstevel@tonic-gate 
1126*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mcdatamutex);
1127*7c478bd9Sstevel@tonic-gate 
1128*7c478bd9Sstevel@tonic-gate 		return (0);
1129*7c478bd9Sstevel@tonic-gate 
1130*7c478bd9Sstevel@tonic-gate 	}	/* end of while loop for logic bank list */
1131*7c478bd9Sstevel@tonic-gate 
1132*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mcdatamutex);
1133*7c478bd9Sstevel@tonic-gate 	return (ENXIO);
1134*7c478bd9Sstevel@tonic-gate }
1135*7c478bd9Sstevel@tonic-gate 
1136*7c478bd9Sstevel@tonic-gate /*
1137*7c478bd9Sstevel@tonic-gate  * Construct lists for an enabled MC where size of memory is 0.
1138*7c478bd9Sstevel@tonic-gate  * The lists are connected as follows:
1139*7c478bd9Sstevel@tonic-gate  * Attached MC -> device group list -> device list(per devgrp).
1140*7c478bd9Sstevel@tonic-gate  */
1141*7c478bd9Sstevel@tonic-gate static void
1142*7c478bd9Sstevel@tonic-gate mc_construct(int mc_id, void *dimminfop)
1143*7c478bd9Sstevel@tonic-gate {
1144*7c478bd9Sstevel@tonic-gate 	int i, j, idx, dmidx;
1145*7c478bd9Sstevel@tonic-gate 	struct mctrl_info *mctrl;
1146*7c478bd9Sstevel@tonic-gate 	struct dgrp_info *dgrp;
1147*7c478bd9Sstevel@tonic-gate 	struct device_info *dev;
1148*7c478bd9Sstevel@tonic-gate 	struct	dimm_info *dimmp = (struct  dimm_info *)dimminfop;
1149*7c478bd9Sstevel@tonic-gate 
1150*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mcdatamutex);
1151*7c478bd9Sstevel@tonic-gate 	/* allocate for mctrl_info and bank_info */
1152*7c478bd9Sstevel@tonic-gate 	if ((mctrl = (struct mctrl_info *)mc_node_get(mc_id,
1153*7c478bd9Sstevel@tonic-gate 	    mctrl_head)) != NULL) {
1154*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "mc_construct: mctrl %d exists\n", mc_id);
1155*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mcdatamutex);
1156*7c478bd9Sstevel@tonic-gate 		return;
1157*7c478bd9Sstevel@tonic-gate 	}
1158*7c478bd9Sstevel@tonic-gate 
1159*7c478bd9Sstevel@tonic-gate 	mctrl = kmem_zalloc(sizeof (struct mctrl_info), KM_SLEEP);
1160*7c478bd9Sstevel@tonic-gate 
1161*7c478bd9Sstevel@tonic-gate 	/*
1162*7c478bd9Sstevel@tonic-gate 	 * If dimminfop is NULL, the Memory Controller is disable, and
1163*7c478bd9Sstevel@tonic-gate 	 * the number of device group will be zero.
1164*7c478bd9Sstevel@tonic-gate 	 */
1165*7c478bd9Sstevel@tonic-gate 	if (dimminfop == NULL) {
1166*7c478bd9Sstevel@tonic-gate 		mctrl->mctrl_node.id = mc_id;
1167*7c478bd9Sstevel@tonic-gate 		mctrl->ndevgrps = 0;
1168*7c478bd9Sstevel@tonic-gate 		mc_node_add((mc_dlist_t *)mctrl, &mctrl_head, &mctrl_tail);
1169*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mcdatamutex);
1170*7c478bd9Sstevel@tonic-gate 		return;
1171*7c478bd9Sstevel@tonic-gate 	}
1172*7c478bd9Sstevel@tonic-gate 
1173*7c478bd9Sstevel@tonic-gate 	/* add the entry on dgrp_info list */
1174*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < NDGRPS; i++) {
1175*7c478bd9Sstevel@tonic-gate 		idx = mc_id * NDGRPS + i;
1176*7c478bd9Sstevel@tonic-gate 		mctrl->devgrpids[i] = idx;
1177*7c478bd9Sstevel@tonic-gate 		if ((dgrp = (struct dgrp_info *)mc_node_get(idx, dgrp_head))
1178*7c478bd9Sstevel@tonic-gate 		    != NULL) {
1179*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "mc_construct: devgrp %d exists\n",
1180*7c478bd9Sstevel@tonic-gate 			    idx);
1181*7c478bd9Sstevel@tonic-gate 			continue;
1182*7c478bd9Sstevel@tonic-gate 		}
1183*7c478bd9Sstevel@tonic-gate 
1184*7c478bd9Sstevel@tonic-gate 		dgrp = kmem_zalloc(sizeof (struct dgrp_info), KM_SLEEP);
1185*7c478bd9Sstevel@tonic-gate 
1186*7c478bd9Sstevel@tonic-gate 		/* add the entry on device_info list */
1187*7c478bd9Sstevel@tonic-gate 		for (j = 0; j < NDIMMS; j++) {
1188*7c478bd9Sstevel@tonic-gate 			dmidx = idx * NDIMMS + j;
1189*7c478bd9Sstevel@tonic-gate 			dgrp->deviceids[j] = dmidx;
1190*7c478bd9Sstevel@tonic-gate 			if ((dev = (struct device_info *)
1191*7c478bd9Sstevel@tonic-gate 			    mc_node_get(dmidx, device_head)) != NULL) {
1192*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "mc_construct: device %d "
1193*7c478bd9Sstevel@tonic-gate 				    "exists\n", dmidx);
1194*7c478bd9Sstevel@tonic-gate 				continue;
1195*7c478bd9Sstevel@tonic-gate 			}
1196*7c478bd9Sstevel@tonic-gate 			dev = kmem_zalloc(sizeof (struct device_info),
1197*7c478bd9Sstevel@tonic-gate 			    KM_SLEEP);
1198*7c478bd9Sstevel@tonic-gate 			dev->dev_node.id = dmidx;
1199*7c478bd9Sstevel@tonic-gate 			dev->size = 0;
1200*7c478bd9Sstevel@tonic-gate 			(void) strncpy(dev->label, (char *)
1201*7c478bd9Sstevel@tonic-gate 			    dimmp->label[i * NDIMMS + j], MAX_DEVLEN);
1202*7c478bd9Sstevel@tonic-gate 
1203*7c478bd9Sstevel@tonic-gate 			mc_node_add((mc_dlist_t *)dev, &device_head,
1204*7c478bd9Sstevel@tonic-gate 			    &device_tail);
1205*7c478bd9Sstevel@tonic-gate 		}	/* for loop for constructing device_info */
1206*7c478bd9Sstevel@tonic-gate 
1207*7c478bd9Sstevel@tonic-gate 		dgrp->dgrp_node.id = idx;
1208*7c478bd9Sstevel@tonic-gate 		dgrp->ndevices = NDIMMS;
1209*7c478bd9Sstevel@tonic-gate 		dgrp->size = 0;
1210*7c478bd9Sstevel@tonic-gate 		mc_node_add((mc_dlist_t *)dgrp, &dgrp_head, &dgrp_tail);
1211*7c478bd9Sstevel@tonic-gate 
1212*7c478bd9Sstevel@tonic-gate 	}	/* end of for loop for constructing dgrp_info list */
1213*7c478bd9Sstevel@tonic-gate 
1214*7c478bd9Sstevel@tonic-gate 	mctrl->mctrl_node.id = mc_id;
1215*7c478bd9Sstevel@tonic-gate 	mctrl->ndevgrps = NDGRPS;
1216*7c478bd9Sstevel@tonic-gate 	mc_node_add((mc_dlist_t *)mctrl, &mctrl_head, &mctrl_tail);
1217*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mcdatamutex);
1218*7c478bd9Sstevel@tonic-gate }
1219*7c478bd9Sstevel@tonic-gate 
1220*7c478bd9Sstevel@tonic-gate /*
1221*7c478bd9Sstevel@tonic-gate  * Construct lists for Memory Configuration at logical viewpoint.
1222*7c478bd9Sstevel@tonic-gate  *
1223*7c478bd9Sstevel@tonic-gate  * Retrieve information from Memory Address Decoding Register and set up
1224*7c478bd9Sstevel@tonic-gate  * bank and segment lists. Link bank to its corresponding device group, and
1225*7c478bd9Sstevel@tonic-gate  * update size of device group and devices. Also connect bank to the segment.
1226*7c478bd9Sstevel@tonic-gate  *
1227*7c478bd9Sstevel@tonic-gate  * Memory Address Decoding Register
1228*7c478bd9Sstevel@tonic-gate  * -------------------------------------------------------------------------
1229*7c478bd9Sstevel@tonic-gate  * |63|62    53|52      41|40  37|36     20|19 18|17  14|13 12|11  8|7     0|
1230*7c478bd9Sstevel@tonic-gate  * |-----------|----------|------|---------|-----|------|-----|-----|-------|
1231*7c478bd9Sstevel@tonic-gate  * |V |    -   |    UK    |   -  |    UM   |  -  |  LK  |  -  | LM  |   -   |
1232*7c478bd9Sstevel@tonic-gate  * -------------------------------------------------------------------------
1233*7c478bd9Sstevel@tonic-gate  *
1234*7c478bd9Sstevel@tonic-gate  */
1235*7c478bd9Sstevel@tonic-gate 
1236*7c478bd9Sstevel@tonic-gate static int
1237*7c478bd9Sstevel@tonic-gate mlayout_add(int mc_id, int bank_no, uint64_t reg, void *dimminfop)
1238*7c478bd9Sstevel@tonic-gate {
1239*7c478bd9Sstevel@tonic-gate 	int i, dmidx, idx;
1240*7c478bd9Sstevel@tonic-gate 	uint32_t ifactor;
1241*7c478bd9Sstevel@tonic-gate 	int status = 0;
1242*7c478bd9Sstevel@tonic-gate 	uint64_t size, base;
1243*7c478bd9Sstevel@tonic-gate 	struct seg_info *seg_curr;
1244*7c478bd9Sstevel@tonic-gate 	struct bank_info *bank_curr;
1245*7c478bd9Sstevel@tonic-gate 	struct dgrp_info *dgrp;
1246*7c478bd9Sstevel@tonic-gate 	struct device_info *dev;
1247*7c478bd9Sstevel@tonic-gate 	union {
1248*7c478bd9Sstevel@tonic-gate 		struct {
1249*7c478bd9Sstevel@tonic-gate 			uint64_t valid	: 1;
1250*7c478bd9Sstevel@tonic-gate 			uint64_t resrv1	: 10;
1251*7c478bd9Sstevel@tonic-gate 			uint64_t uk	: 12;
1252*7c478bd9Sstevel@tonic-gate 			uint64_t resrv2	: 4;
1253*7c478bd9Sstevel@tonic-gate 			uint64_t um	: 17;
1254*7c478bd9Sstevel@tonic-gate 			uint64_t resrv3	: 2;
1255*7c478bd9Sstevel@tonic-gate 			uint64_t lk	: 4;
1256*7c478bd9Sstevel@tonic-gate 			uint64_t resrv4	: 2;
1257*7c478bd9Sstevel@tonic-gate 			uint64_t lm	: 4;
1258*7c478bd9Sstevel@tonic-gate 			uint64_t resrv5	: 8;
1259*7c478bd9Sstevel@tonic-gate 		} _s;
1260*7c478bd9Sstevel@tonic-gate 		uint64_t madreg;
1261*7c478bd9Sstevel@tonic-gate 	} mcreg;
1262*7c478bd9Sstevel@tonic-gate 
1263*7c478bd9Sstevel@tonic-gate 	mcreg.madreg = reg;
1264*7c478bd9Sstevel@tonic-gate 
1265*7c478bd9Sstevel@tonic-gate 	DPRINTF(MC_CNSTRC_DEBUG, ("mlayout_add: mc_id %d, bank num "
1266*7c478bd9Sstevel@tonic-gate 	    "%d, reg 0x%llx\n", mc_id, bank_no, reg));
1267*7c478bd9Sstevel@tonic-gate 
1268*7c478bd9Sstevel@tonic-gate 	/* add the entry on bank_info list */
1269*7c478bd9Sstevel@tonic-gate 	idx = mc_id * NBANKS + bank_no;
1270*7c478bd9Sstevel@tonic-gate 
1271*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mcdatamutex);
1272*7c478bd9Sstevel@tonic-gate 	if ((bank_curr = (struct bank_info *)mc_node_get(idx, bank_head))
1273*7c478bd9Sstevel@tonic-gate 	    != NULL) {
1274*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "mlayout_add: bank %d exists\n", bank_no);
1275*7c478bd9Sstevel@tonic-gate 		goto exit;
1276*7c478bd9Sstevel@tonic-gate 	}
1277*7c478bd9Sstevel@tonic-gate 
1278*7c478bd9Sstevel@tonic-gate 	bank_curr = kmem_zalloc(sizeof (struct bank_info), KM_SLEEP);
1279*7c478bd9Sstevel@tonic-gate 	bank_curr->bank_node.id = idx;
1280*7c478bd9Sstevel@tonic-gate 	bank_curr->valid = mcreg._s.valid;
1281*7c478bd9Sstevel@tonic-gate 	bank_curr->dimminfop = dimminfop;
1282*7c478bd9Sstevel@tonic-gate 
1283*7c478bd9Sstevel@tonic-gate 	if (!mcreg._s.valid) {
1284*7c478bd9Sstevel@tonic-gate 		mc_node_add((mc_dlist_t *)bank_curr, &bank_head, &bank_tail);
1285*7c478bd9Sstevel@tonic-gate 		goto exit;
1286*7c478bd9Sstevel@tonic-gate 	}
1287*7c478bd9Sstevel@tonic-gate 
1288*7c478bd9Sstevel@tonic-gate 	/*
1289*7c478bd9Sstevel@tonic-gate 	 * size of a logical bank = size of segment / interleave factor
1290*7c478bd9Sstevel@tonic-gate 	 * This fomula is not only working for regular configuration,
1291*7c478bd9Sstevel@tonic-gate 	 * i.e. number of banks at a segment equals to the max
1292*7c478bd9Sstevel@tonic-gate 	 * interleave factor, but also for special case, say 3 bank
1293*7c478bd9Sstevel@tonic-gate 	 * interleave. One bank is 2 way interleave and other two are
1294*7c478bd9Sstevel@tonic-gate 	 * 4 way. So the sizes of banks are size of segment/2 and /4
1295*7c478bd9Sstevel@tonic-gate 	 * respectively.
1296*7c478bd9Sstevel@tonic-gate 	 */
1297*7c478bd9Sstevel@tonic-gate 	ifactor = (mcreg._s.lk ^ 0xF) + 1;
1298*7c478bd9Sstevel@tonic-gate 	size = (((mcreg._s.uk & 0x3FF) + 1) * 0x4000000) / ifactor;
1299*7c478bd9Sstevel@tonic-gate 	base = mcreg._s.um & ~mcreg._s.uk;
1300*7c478bd9Sstevel@tonic-gate 	base <<= MADR_UPA_SHIFT;
1301*7c478bd9Sstevel@tonic-gate 
1302*7c478bd9Sstevel@tonic-gate 	bank_curr->uk = mcreg._s.uk;
1303*7c478bd9Sstevel@tonic-gate 	bank_curr->um = mcreg._s.um;
1304*7c478bd9Sstevel@tonic-gate 	bank_curr->lk = mcreg._s.lk;
1305*7c478bd9Sstevel@tonic-gate 	bank_curr->lm = mcreg._s.lm;
1306*7c478bd9Sstevel@tonic-gate 	bank_curr->size = size;
1307*7c478bd9Sstevel@tonic-gate 
1308*7c478bd9Sstevel@tonic-gate 	DPRINTF(MC_CNSTRC_DEBUG, ("mlayout_add 3: logical bank num %d, "
1309*7c478bd9Sstevel@tonic-gate 	"lk 0x%x uk 0x%x um 0x%x ifactor 0x%x size 0x%llx base 0x%llx\n",
1310*7c478bd9Sstevel@tonic-gate 	    mcreg._s.lk, mcreg._s.uk, mcreg._s.um, ifactor, size, base));
1311*7c478bd9Sstevel@tonic-gate 
1312*7c478bd9Sstevel@tonic-gate 	/* connect the entry and update the size on dgrp_info list */
1313*7c478bd9Sstevel@tonic-gate 	idx = mc_id * NDGRPS + (bank_no % NDGRPS);
1314*7c478bd9Sstevel@tonic-gate 	if ((dgrp = (struct dgrp_info *)mc_node_get(idx, dgrp_head)) == NULL) {
1315*7c478bd9Sstevel@tonic-gate 		/* all avaiable dgrp should be linked at mc_construct */
1316*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "mlayout_add: dgrp %d doesn't exist\n", idx);
1317*7c478bd9Sstevel@tonic-gate 		kmem_free(bank_curr, sizeof (struct bank_info));
1318*7c478bd9Sstevel@tonic-gate 		status = -1;
1319*7c478bd9Sstevel@tonic-gate 		goto exit;
1320*7c478bd9Sstevel@tonic-gate 	}
1321*7c478bd9Sstevel@tonic-gate 
1322*7c478bd9Sstevel@tonic-gate 	bank_curr->devgrp_id = idx;
1323*7c478bd9Sstevel@tonic-gate 	dgrp->size += size;
1324*7c478bd9Sstevel@tonic-gate 
1325*7c478bd9Sstevel@tonic-gate 	/* Update the size of entry on device_info list */
1326*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < NDIMMS; i++) {
1327*7c478bd9Sstevel@tonic-gate 		dmidx = dgrp->dgrp_node.id * NDIMMS + i;
1328*7c478bd9Sstevel@tonic-gate 		dgrp->deviceids[i] = dmidx;
1329*7c478bd9Sstevel@tonic-gate 
1330*7c478bd9Sstevel@tonic-gate 		/* avaiable device should be linked at mc_construct */
1331*7c478bd9Sstevel@tonic-gate 		if ((dev = (struct device_info *)mc_node_get(dmidx,
1332*7c478bd9Sstevel@tonic-gate 		    device_head)) == NULL) {
1333*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "mlayout_add:dev %d doesn't exist\n",
1334*7c478bd9Sstevel@tonic-gate 			    dmidx);
1335*7c478bd9Sstevel@tonic-gate 			kmem_free(bank_curr, sizeof (struct bank_info));
1336*7c478bd9Sstevel@tonic-gate 			status = -1;
1337*7c478bd9Sstevel@tonic-gate 			goto exit;
1338*7c478bd9Sstevel@tonic-gate 		}
1339*7c478bd9Sstevel@tonic-gate 
1340*7c478bd9Sstevel@tonic-gate 		dev->size += (size / NDIMMS);
1341*7c478bd9Sstevel@tonic-gate 
1342*7c478bd9Sstevel@tonic-gate 		DPRINTF(MC_CNSTRC_DEBUG, ("mlayout_add DIMM:id %d, size %d\n",
1343*7c478bd9Sstevel@tonic-gate 		    dmidx, size));
1344*7c478bd9Sstevel@tonic-gate 	}
1345*7c478bd9Sstevel@tonic-gate 
1346*7c478bd9Sstevel@tonic-gate 	/*
1347*7c478bd9Sstevel@tonic-gate 	 * Get the segment by matching the base address, link this bank
1348*7c478bd9Sstevel@tonic-gate 	 * to the segment. If not matched, allocate a new segment and
1349*7c478bd9Sstevel@tonic-gate 	 * add it at segment list.
1350*7c478bd9Sstevel@tonic-gate 	 */
1351*7c478bd9Sstevel@tonic-gate 	if (seg_curr = seg_match_base(base)) {
1352*7c478bd9Sstevel@tonic-gate 		seg_curr->nbanks++;
1353*7c478bd9Sstevel@tonic-gate 		seg_curr->size += size;
1354*7c478bd9Sstevel@tonic-gate 		if (ifactor > seg_curr->ifactor)
1355*7c478bd9Sstevel@tonic-gate 			seg_curr->ifactor = ifactor;
1356*7c478bd9Sstevel@tonic-gate 		bank_curr->seg_id = seg_curr->seg_node.id;
1357*7c478bd9Sstevel@tonic-gate 	} else {
1358*7c478bd9Sstevel@tonic-gate 		seg_curr = (struct seg_info *)
1359*7c478bd9Sstevel@tonic-gate 		kmem_zalloc(sizeof (struct seg_info), KM_SLEEP);
1360*7c478bd9Sstevel@tonic-gate 		bank_curr->seg_id = seg_id;
1361*7c478bd9Sstevel@tonic-gate 		seg_curr->seg_node.id = seg_id++;
1362*7c478bd9Sstevel@tonic-gate 		seg_curr->base = base;
1363*7c478bd9Sstevel@tonic-gate 		seg_curr->size = size;
1364*7c478bd9Sstevel@tonic-gate 		seg_curr->nbanks = 1;
1365*7c478bd9Sstevel@tonic-gate 		seg_curr->ifactor = ifactor;
1366*7c478bd9Sstevel@tonic-gate 		mc_node_add((mc_dlist_t *)seg_curr, &seg_head, &seg_tail);
1367*7c478bd9Sstevel@tonic-gate 
1368*7c478bd9Sstevel@tonic-gate 		nsegments++;
1369*7c478bd9Sstevel@tonic-gate 	}
1370*7c478bd9Sstevel@tonic-gate 
1371*7c478bd9Sstevel@tonic-gate 	/* Get the local id of bank which is only unique per segment. */
1372*7c478bd9Sstevel@tonic-gate 	bank_curr->local_id = seg_curr->nbanks - 1;
1373*7c478bd9Sstevel@tonic-gate 
1374*7c478bd9Sstevel@tonic-gate 	/* add bank at the end of the list; not sorted by bankid */
1375*7c478bd9Sstevel@tonic-gate 	if (seg_curr->hb_inseg != NULL) {
1376*7c478bd9Sstevel@tonic-gate 		bank_curr->p_inseg = seg_curr->tb_inseg;
1377*7c478bd9Sstevel@tonic-gate 		bank_curr->n_inseg = seg_curr->tb_inseg->n_inseg;
1378*7c478bd9Sstevel@tonic-gate 		seg_curr->tb_inseg->n_inseg = bank_curr;
1379*7c478bd9Sstevel@tonic-gate 		seg_curr->tb_inseg = bank_curr;
1380*7c478bd9Sstevel@tonic-gate 	} else {
1381*7c478bd9Sstevel@tonic-gate 		bank_curr->n_inseg = bank_curr->p_inseg = NULL;
1382*7c478bd9Sstevel@tonic-gate 		seg_curr->hb_inseg = seg_curr->tb_inseg = bank_curr;
1383*7c478bd9Sstevel@tonic-gate 	}
1384*7c478bd9Sstevel@tonic-gate 	DPRINTF(MC_CNSTRC_DEBUG, ("mlayout_add: + bank to seg, id %d\n",
1385*7c478bd9Sstevel@tonic-gate 	    seg_curr->seg_node.id));
1386*7c478bd9Sstevel@tonic-gate 
1387*7c478bd9Sstevel@tonic-gate 	mc_node_add((mc_dlist_t *)bank_curr, &bank_head, &bank_tail);
1388*7c478bd9Sstevel@tonic-gate 
1389*7c478bd9Sstevel@tonic-gate 	memsize += size;
1390*7c478bd9Sstevel@tonic-gate 	if (seg_curr->nbanks > maxbanks)
1391*7c478bd9Sstevel@tonic-gate 		maxbanks = seg_curr->nbanks;
1392*7c478bd9Sstevel@tonic-gate 
1393*7c478bd9Sstevel@tonic-gate exit:
1394*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mcdatamutex);
1395*7c478bd9Sstevel@tonic-gate 	return (status);
1396*7c478bd9Sstevel@tonic-gate }
1397*7c478bd9Sstevel@tonic-gate 
1398*7c478bd9Sstevel@tonic-gate /*
1399*7c478bd9Sstevel@tonic-gate  * Delete nodes related to the given MC on mc, device group, device,
1400*7c478bd9Sstevel@tonic-gate  * and bank lists. Moreover, delete corresponding segment if its connected
1401*7c478bd9Sstevel@tonic-gate  * banks are all removed.
1402*7c478bd9Sstevel@tonic-gate  */
1403*7c478bd9Sstevel@tonic-gate static void
1404*7c478bd9Sstevel@tonic-gate mlayout_del(int mc_id)
1405*7c478bd9Sstevel@tonic-gate {
1406*7c478bd9Sstevel@tonic-gate 	int i, j, dgrpid, devid, bankid, ndevgrps;
1407*7c478bd9Sstevel@tonic-gate 	struct seg_info *seg;
1408*7c478bd9Sstevel@tonic-gate 	struct bank_info *bank_curr;
1409*7c478bd9Sstevel@tonic-gate 	struct mctrl_info *mctrl;
1410*7c478bd9Sstevel@tonic-gate 	mc_dlist_t *dgrp_ptr;
1411*7c478bd9Sstevel@tonic-gate 	mc_dlist_t *dev_ptr;
1412*7c478bd9Sstevel@tonic-gate 	uint64_t base;
1413*7c478bd9Sstevel@tonic-gate 
1414*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mcdatamutex);
1415*7c478bd9Sstevel@tonic-gate 
1416*7c478bd9Sstevel@tonic-gate 	/* delete mctrl_info */
1417*7c478bd9Sstevel@tonic-gate 	if ((mctrl = (struct mctrl_info *)mc_node_get(mc_id, mctrl_head)) !=
1418*7c478bd9Sstevel@tonic-gate 	    NULL) {
1419*7c478bd9Sstevel@tonic-gate 		ndevgrps = mctrl->ndevgrps;
1420*7c478bd9Sstevel@tonic-gate 		mc_node_del((mc_dlist_t *)mctrl, &mctrl_head, &mctrl_tail);
1421*7c478bd9Sstevel@tonic-gate 		kmem_free(mctrl, sizeof (struct mctrl_info));
1422*7c478bd9Sstevel@tonic-gate 		nmcs--;
1423*7c478bd9Sstevel@tonic-gate 
1424*7c478bd9Sstevel@tonic-gate 		/*
1425*7c478bd9Sstevel@tonic-gate 		 * There is no other list left for disabled MC.
1426*7c478bd9Sstevel@tonic-gate 		 */
1427*7c478bd9Sstevel@tonic-gate 		if (ndevgrps == 0) {
1428*7c478bd9Sstevel@tonic-gate 			mutex_exit(&mcdatamutex);
1429*7c478bd9Sstevel@tonic-gate 			return;
1430*7c478bd9Sstevel@tonic-gate 		}
1431*7c478bd9Sstevel@tonic-gate 	} else
1432*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "MC mlayout_del: mctrl is not found\n");
1433*7c478bd9Sstevel@tonic-gate 
1434*7c478bd9Sstevel@tonic-gate 	/* Delete device groups and devices of the detached MC */
1435*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < NDGRPS; i++) {
1436*7c478bd9Sstevel@tonic-gate 		dgrpid = mc_id * NDGRPS + i;
1437*7c478bd9Sstevel@tonic-gate 		if (!(dgrp_ptr = mc_node_get(dgrpid, dgrp_head))) {
1438*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "mlayout_del: no devgrp %d\n", dgrpid);
1439*7c478bd9Sstevel@tonic-gate 			continue;
1440*7c478bd9Sstevel@tonic-gate 		}
1441*7c478bd9Sstevel@tonic-gate 
1442*7c478bd9Sstevel@tonic-gate 		for (j = 0; j < NDIMMS; j++) {
1443*7c478bd9Sstevel@tonic-gate 			devid = dgrpid * NDIMMS + j;
1444*7c478bd9Sstevel@tonic-gate 			if (dev_ptr = mc_node_get(devid, device_head)) {
1445*7c478bd9Sstevel@tonic-gate 				mc_node_del(dev_ptr, &device_head,
1446*7c478bd9Sstevel@tonic-gate 				    &device_tail);
1447*7c478bd9Sstevel@tonic-gate 				kmem_free(dev_ptr, sizeof (struct device_info));
1448*7c478bd9Sstevel@tonic-gate 			} else {
1449*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "mlayout_del: no dev %d\n",
1450*7c478bd9Sstevel@tonic-gate 				    devid);
1451*7c478bd9Sstevel@tonic-gate 			}
1452*7c478bd9Sstevel@tonic-gate 		}
1453*7c478bd9Sstevel@tonic-gate 
1454*7c478bd9Sstevel@tonic-gate 		mc_node_del(dgrp_ptr, &dgrp_head, &dgrp_tail);
1455*7c478bd9Sstevel@tonic-gate 		kmem_free(dgrp_ptr, sizeof (struct dgrp_info));
1456*7c478bd9Sstevel@tonic-gate 	}
1457*7c478bd9Sstevel@tonic-gate 
1458*7c478bd9Sstevel@tonic-gate 	/* Delete banks and segments if it has no bank */
1459*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < NBANKS; i++) {
1460*7c478bd9Sstevel@tonic-gate 		bankid = mc_id * NBANKS + i;
1461*7c478bd9Sstevel@tonic-gate 		DPRINTF(MC_DESTRC_DEBUG, ("bank id %d\n", bankid));
1462*7c478bd9Sstevel@tonic-gate 		if (!(bank_curr = (struct bank_info *)mc_node_get(bankid,
1463*7c478bd9Sstevel@tonic-gate 		    bank_head))) {
1464*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "mlayout_del: no bank %d\n", bankid);
1465*7c478bd9Sstevel@tonic-gate 			continue;
1466*7c478bd9Sstevel@tonic-gate 		}
1467*7c478bd9Sstevel@tonic-gate 
1468*7c478bd9Sstevel@tonic-gate 		if (bank_curr->valid) {
1469*7c478bd9Sstevel@tonic-gate 			base = bank_curr->um & ~bank_curr->uk;
1470*7c478bd9Sstevel@tonic-gate 			base <<= MADR_UPA_SHIFT;
1471*7c478bd9Sstevel@tonic-gate 			bank_curr->valid = 0;
1472*7c478bd9Sstevel@tonic-gate 			memsize -= bank_curr->size;
1473*7c478bd9Sstevel@tonic-gate 
1474*7c478bd9Sstevel@tonic-gate 			/* Delete bank at segment and segment if no bank left */
1475*7c478bd9Sstevel@tonic-gate 			if (!(seg = seg_match_base(base))) {
1476*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "mlayout_del: no seg\n");
1477*7c478bd9Sstevel@tonic-gate 				mc_node_del((mc_dlist_t *)bank_curr, &bank_head,
1478*7c478bd9Sstevel@tonic-gate 				    &bank_tail);
1479*7c478bd9Sstevel@tonic-gate 				kmem_free(bank_curr, sizeof (struct bank_info));
1480*7c478bd9Sstevel@tonic-gate 				continue;
1481*7c478bd9Sstevel@tonic-gate 			}
1482*7c478bd9Sstevel@tonic-gate 
1483*7c478bd9Sstevel@tonic-gate 			/* update the bank list at the segment */
1484*7c478bd9Sstevel@tonic-gate 			if (bank_curr->n_inseg == NULL) {
1485*7c478bd9Sstevel@tonic-gate 				/* node is at the tail of list */
1486*7c478bd9Sstevel@tonic-gate 				seg->tb_inseg = bank_curr->p_inseg;
1487*7c478bd9Sstevel@tonic-gate 			} else {
1488*7c478bd9Sstevel@tonic-gate 				bank_curr->n_inseg->p_inseg =
1489*7c478bd9Sstevel@tonic-gate 				    bank_curr->p_inseg;
1490*7c478bd9Sstevel@tonic-gate 			}
1491*7c478bd9Sstevel@tonic-gate 
1492*7c478bd9Sstevel@tonic-gate 			if (bank_curr->p_inseg == NULL) {
1493*7c478bd9Sstevel@tonic-gate 				/* node is at the head of list */
1494*7c478bd9Sstevel@tonic-gate 				seg->hb_inseg = bank_curr->n_inseg;
1495*7c478bd9Sstevel@tonic-gate 			} else {
1496*7c478bd9Sstevel@tonic-gate 				bank_curr->p_inseg->n_inseg =
1497*7c478bd9Sstevel@tonic-gate 				    bank_curr->n_inseg;
1498*7c478bd9Sstevel@tonic-gate 			}
1499*7c478bd9Sstevel@tonic-gate 
1500*7c478bd9Sstevel@tonic-gate 			seg->nbanks--;
1501*7c478bd9Sstevel@tonic-gate 			seg->size -= bank_curr->size;
1502*7c478bd9Sstevel@tonic-gate 
1503*7c478bd9Sstevel@tonic-gate 			if (seg->nbanks == 0) {
1504*7c478bd9Sstevel@tonic-gate 				mc_node_del((mc_dlist_t *)seg, &seg_head,
1505*7c478bd9Sstevel@tonic-gate 				    &seg_tail);
1506*7c478bd9Sstevel@tonic-gate 				kmem_free(seg, sizeof (struct seg_info));
1507*7c478bd9Sstevel@tonic-gate 				nsegments--;
1508*7c478bd9Sstevel@tonic-gate 			}
1509*7c478bd9Sstevel@tonic-gate 
1510*7c478bd9Sstevel@tonic-gate 		}
1511*7c478bd9Sstevel@tonic-gate 		mc_node_del((mc_dlist_t *)bank_curr, &bank_head, &bank_tail);
1512*7c478bd9Sstevel@tonic-gate 		kmem_free(bank_curr, sizeof (struct bank_info));
1513*7c478bd9Sstevel@tonic-gate 	}	/* end of for loop for four banks */
1514*7c478bd9Sstevel@tonic-gate 
1515*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mcdatamutex);
1516*7c478bd9Sstevel@tonic-gate }
1517*7c478bd9Sstevel@tonic-gate 
1518*7c478bd9Sstevel@tonic-gate /*
1519*7c478bd9Sstevel@tonic-gate  * Search the segment in the list starting at seg_head by base address
1520*7c478bd9Sstevel@tonic-gate  * input: base address
1521*7c478bd9Sstevel@tonic-gate  * return: pointer of found segment or null if not found.
1522*7c478bd9Sstevel@tonic-gate  */
1523*7c478bd9Sstevel@tonic-gate static struct seg_info *
1524*7c478bd9Sstevel@tonic-gate seg_match_base(u_longlong_t base)
1525*7c478bd9Sstevel@tonic-gate {
1526*7c478bd9Sstevel@tonic-gate 	static struct seg_info *seg_ptr;
1527*7c478bd9Sstevel@tonic-gate 
1528*7c478bd9Sstevel@tonic-gate 	seg_ptr = (struct seg_info *)seg_head;
1529*7c478bd9Sstevel@tonic-gate 	while (seg_ptr != NULL) {
1530*7c478bd9Sstevel@tonic-gate 		DPRINTF(MC_LIST_DEBUG, ("seg_match: base %d,given base %d\n",
1531*7c478bd9Sstevel@tonic-gate 		    seg_ptr->base, base));
1532*7c478bd9Sstevel@tonic-gate 		if (seg_ptr->base == base)
1533*7c478bd9Sstevel@tonic-gate 			break;
1534*7c478bd9Sstevel@tonic-gate 		seg_ptr = (struct seg_info *)seg_ptr->seg_node.next;
1535*7c478bd9Sstevel@tonic-gate 	}
1536*7c478bd9Sstevel@tonic-gate 	return (seg_ptr);
1537*7c478bd9Sstevel@tonic-gate }
1538*7c478bd9Sstevel@tonic-gate 
1539*7c478bd9Sstevel@tonic-gate /*
1540*7c478bd9Sstevel@tonic-gate  * mc_dlist is a double linking list, including unique id, and pointers to
1541*7c478bd9Sstevel@tonic-gate  * next, and previous nodes. seg_info, bank_info, dgrp_info, device_info,
1542*7c478bd9Sstevel@tonic-gate  * and mctrl_info has it at the top to share the operations, add, del, and get.
1543*7c478bd9Sstevel@tonic-gate  *
1544*7c478bd9Sstevel@tonic-gate  * The new node is added at the tail and is not sorted.
1545*7c478bd9Sstevel@tonic-gate  *
1546*7c478bd9Sstevel@tonic-gate  * Input: The pointer of node to be added, head and tail of the list
1547*7c478bd9Sstevel@tonic-gate  */
1548*7c478bd9Sstevel@tonic-gate 
1549*7c478bd9Sstevel@tonic-gate static void
1550*7c478bd9Sstevel@tonic-gate mc_node_add(mc_dlist_t *node, mc_dlist_t **head, mc_dlist_t **tail)
1551*7c478bd9Sstevel@tonic-gate {
1552*7c478bd9Sstevel@tonic-gate 	DPRINTF(MC_LIST_DEBUG, ("mc_node_add: node->id %d head %p tail %p\n",
1553*7c478bd9Sstevel@tonic-gate 		node->id, *head, *tail));
1554*7c478bd9Sstevel@tonic-gate 
1555*7c478bd9Sstevel@tonic-gate 	if (*head != NULL) {
1556*7c478bd9Sstevel@tonic-gate 		node->prev = *tail;
1557*7c478bd9Sstevel@tonic-gate 		node->next = (*tail)->next;
1558*7c478bd9Sstevel@tonic-gate 		(*tail)->next = node;
1559*7c478bd9Sstevel@tonic-gate 		*tail = node;
1560*7c478bd9Sstevel@tonic-gate 	} else {
1561*7c478bd9Sstevel@tonic-gate 		node->next = node->prev = NULL;
1562*7c478bd9Sstevel@tonic-gate 		*head = *tail = node;
1563*7c478bd9Sstevel@tonic-gate 	}
1564*7c478bd9Sstevel@tonic-gate }
1565*7c478bd9Sstevel@tonic-gate 
1566*7c478bd9Sstevel@tonic-gate /*
1567*7c478bd9Sstevel@tonic-gate  * Input: The pointer of node to be deleted, head and tail of the list
1568*7c478bd9Sstevel@tonic-gate  *
1569*7c478bd9Sstevel@tonic-gate  * Deleted node will be at the following positions
1570*7c478bd9Sstevel@tonic-gate  * 1. At the tail of the list
1571*7c478bd9Sstevel@tonic-gate  * 2. At the head of the list
1572*7c478bd9Sstevel@tonic-gate  * 3. At the head and tail of the list, i.e. only one left.
1573*7c478bd9Sstevel@tonic-gate  * 4. At the middle of the list
1574*7c478bd9Sstevel@tonic-gate  */
1575*7c478bd9Sstevel@tonic-gate 
1576*7c478bd9Sstevel@tonic-gate static void
1577*7c478bd9Sstevel@tonic-gate mc_node_del(mc_dlist_t *node, mc_dlist_t **head, mc_dlist_t **tail)
1578*7c478bd9Sstevel@tonic-gate {
1579*7c478bd9Sstevel@tonic-gate 	if (node->next == NULL) {
1580*7c478bd9Sstevel@tonic-gate 		/* deleted node is at the tail of list */
1581*7c478bd9Sstevel@tonic-gate 		*tail = node->prev;
1582*7c478bd9Sstevel@tonic-gate 	} else {
1583*7c478bd9Sstevel@tonic-gate 		node->next->prev = node->prev;
1584*7c478bd9Sstevel@tonic-gate 	}
1585*7c478bd9Sstevel@tonic-gate 
1586*7c478bd9Sstevel@tonic-gate 	if (node->prev == NULL) {
1587*7c478bd9Sstevel@tonic-gate 		/* deleted node is at the head of list */
1588*7c478bd9Sstevel@tonic-gate 		*head = node->next;
1589*7c478bd9Sstevel@tonic-gate 	} else {
1590*7c478bd9Sstevel@tonic-gate 		node->prev->next = node->next;
1591*7c478bd9Sstevel@tonic-gate 	}
1592*7c478bd9Sstevel@tonic-gate }
1593*7c478bd9Sstevel@tonic-gate 
1594*7c478bd9Sstevel@tonic-gate /*
1595*7c478bd9Sstevel@tonic-gate  * Search the list from the head of the list to match the given id
1596*7c478bd9Sstevel@tonic-gate  * Input: id and the head of the list
1597*7c478bd9Sstevel@tonic-gate  * Return: pointer of found node
1598*7c478bd9Sstevel@tonic-gate  */
1599*7c478bd9Sstevel@tonic-gate static mc_dlist_t *
1600*7c478bd9Sstevel@tonic-gate mc_node_get(int id, mc_dlist_t *head)
1601*7c478bd9Sstevel@tonic-gate {
1602*7c478bd9Sstevel@tonic-gate 	mc_dlist_t *node;
1603*7c478bd9Sstevel@tonic-gate 
1604*7c478bd9Sstevel@tonic-gate 	node = head;
1605*7c478bd9Sstevel@tonic-gate 	while (node != NULL) {
1606*7c478bd9Sstevel@tonic-gate 		DPRINTF(MC_LIST_DEBUG, ("mc_node_get: id %d, given id %d\n",
1607*7c478bd9Sstevel@tonic-gate 		    node->id, id));
1608*7c478bd9Sstevel@tonic-gate 		if (node->id == id)
1609*7c478bd9Sstevel@tonic-gate 			break;
1610*7c478bd9Sstevel@tonic-gate 		node = node->next;
1611*7c478bd9Sstevel@tonic-gate 	}
1612*7c478bd9Sstevel@tonic-gate 	return (node);
1613*7c478bd9Sstevel@tonic-gate }
1614*7c478bd9Sstevel@tonic-gate 
1615*7c478bd9Sstevel@tonic-gate /*
1616*7c478bd9Sstevel@tonic-gate  * mc-us3 driver allows a platform to add extra label
1617*7c478bd9Sstevel@tonic-gate  * information to the unum string. If a platform implements a
1618*7c478bd9Sstevel@tonic-gate  * kernel function called plat_add_mem_unum_label() it will be
1619*7c478bd9Sstevel@tonic-gate  * executed. This would typically be implemented in the platmod.
1620*7c478bd9Sstevel@tonic-gate  */
1621*7c478bd9Sstevel@tonic-gate static void
1622*7c478bd9Sstevel@tonic-gate mc_add_mem_unum_label(char *buf, int mcid, int bank, int dimm)
1623*7c478bd9Sstevel@tonic-gate {
1624*7c478bd9Sstevel@tonic-gate 	if (&plat_add_mem_unum_label)
1625*7c478bd9Sstevel@tonic-gate 		plat_add_mem_unum_label(buf, mcid, bank, dimm);
1626*7c478bd9Sstevel@tonic-gate }
1627