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