xref: /illumos-gate/usr/src/uts/sun4v/os/fillsysinfo.c (revision de710d24)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 #include <sys/errno.h>
26 #include <sys/types.h>
27 #include <sys/param.h>
28 #include <sys/cpu.h>
29 #include <sys/cpuvar.h>
30 #include <sys/clock.h>
31 #include <sys/promif.h>
32 #include <sys/promimpl.h>
33 #include <sys/systm.h>
34 #include <sys/machsystm.h>
35 #include <sys/debug.h>
36 #include <sys/sunddi.h>
37 #include <sys/modctl.h>
38 #include <sys/cpu_module.h>
39 #include <sys/kobj.h>
40 #include <sys/cmp.h>
41 #include <sys/async.h>
42 #include <vm/page.h>
43 #include <vm/hat_sfmmu.h>
44 #include <sys/sysmacros.h>
45 #include <sys/mach_descrip.h>
46 #include <sys/mdesc.h>
47 #include <sys/archsystm.h>
48 #include <sys/error.h>
49 #include <sys/mmu.h>
50 #include <sys/bitmap.h>
51 #include <sys/intreg.h>
52 #include <sys/instance.h>
53 
54 struct cpu_node cpunodes[NCPU];
55 
56 uint64_t cpu_q_entries;
57 uint64_t dev_q_entries;
58 uint64_t cpu_rq_entries;
59 uint64_t cpu_nrq_entries;
60 uint64_t ncpu_guest_max;
61 
62 void fill_cpu(md_t *, mde_cookie_t);
63 
64 static uint64_t get_mmu_ctx_bits(md_t *, mde_cookie_t);
65 static uint64_t get_mmu_tsbs(md_t *, mde_cookie_t);
66 static uint64_t	get_mmu_shcontexts(md_t *, mde_cookie_t);
67 static uint64_t get_cpu_pagesizes(md_t *, mde_cookie_t);
68 static char *construct_isalist(md_t *, mde_cookie_t, char **);
69 static void init_md_broken(md_t *, mde_cookie_t *);
70 static int get_l2_cache_info(md_t *, mde_cookie_t, uint64_t *, uint64_t *,
71     uint64_t *);
72 static void get_hwcaps(md_t *, mde_cookie_t);
73 static void get_weakest_mem_model(md_t *, mde_cookie_t);
74 static void get_q_sizes(md_t *, mde_cookie_t);
75 static void get_va_bits(md_t *, mde_cookie_t);
76 static size_t get_ra_limit(md_t *, mde_cookie_t);
77 static int get_l2_cache_node_count(md_t *);
78 static unsigned long names2bits(char *tokens, size_t tokenslen,
79     char *bit_formatter, char *warning);
80 
81 uint64_t	system_clock_freq;
82 uint_t		niommu_tsbs = 0;
83 
84 static int n_l2_caches = 0;
85 
86 /* prevent compilation with VAC defined */
87 #ifdef VAC
88 #error "The sun4v architecture does not support VAC"
89 #endif
90 
91 #define	S_VAC_SIZE	MMU_PAGESIZE
92 #define	S_VAC_SHIFT	MMU_PAGESHIFT
93 
94 int		vac_size = S_VAC_SIZE;
95 uint_t		vac_mask = MMU_PAGEMASK & (S_VAC_SIZE - 1);
96 int		vac_shift = S_VAC_SHIFT;
97 uintptr_t	shm_alignment = S_VAC_SIZE;
98 
99 void
map_wellknown_devices()100 map_wellknown_devices()
101 {
102 }
103 
104 void
fill_cpu(md_t * mdp,mde_cookie_t cpuc)105 fill_cpu(md_t *mdp, mde_cookie_t cpuc)
106 {
107 	struct cpu_node *cpunode;
108 	uint64_t cpuid;
109 	uint64_t clk_freq;
110 	char *namebuf;
111 	char *namebufp;
112 	int namelen;
113 	uint64_t associativity = 0, linesize = 0, size = 0;
114 
115 	if (md_get_prop_val(mdp, cpuc, "id", &cpuid)) {
116 		return;
117 	}
118 
119 	/* All out-of-range cpus will be stopped later. */
120 	if (cpuid >= NCPU) {
121 		cmn_err(CE_CONT, "fill_cpu: out of range cpuid %ld - "
122 		    "cpu excluded from configuration\n", cpuid);
123 
124 		return;
125 	}
126 
127 	cpunode = &cpunodes[cpuid];
128 	cpunode->cpuid = (int)cpuid;
129 	cpunode->device_id = cpuid;
130 
131 	if (sizeof (cpunode->fru_fmri) > strlen(CPU_FRU_FMRI))
132 		(void) strcpy(cpunode->fru_fmri, CPU_FRU_FMRI);
133 
134 	if (md_get_prop_data(mdp, cpuc,
135 	    "compatible", (uint8_t **)&namebuf, &namelen)) {
136 		cmn_err(CE_PANIC, "fill_cpu: Cannot read compatible "
137 		    "property");
138 	}
139 	namebufp = namebuf;
140 	if (strncmp(namebufp, "SUNW,", 5) == 0)
141 		namebufp += 5;
142 	if (strlen(namebufp) > sizeof (cpunode->name))
143 		cmn_err(CE_PANIC, "Compatible property too big to "
144 		    "fit into the cpunode name buffer");
145 	(void) strcpy(cpunode->name, namebufp);
146 
147 	if (md_get_prop_val(mdp, cpuc,
148 	    "clock-frequency", &clk_freq)) {
149 			clk_freq = 0;
150 	}
151 	cpunode->clock_freq = clk_freq;
152 
153 	ASSERT(cpunode->clock_freq != 0);
154 	/*
155 	 * Compute scaling factor based on rate of %tick. This is used
156 	 * to convert from ticks derived from %tick to nanoseconds. See
157 	 * comment in sun4u/sys/clock.h for details.
158 	 */
159 	cpunode->tick_nsec_scale = (uint_t)(((uint64_t)NANOSEC <<
160 	    (32 - TICK_NSEC_SHIFT)) / cpunode->clock_freq);
161 
162 	/*
163 	 * The nodeid is not used in sun4v at all. Setting it
164 	 * to positive value to make starting of slave CPUs
165 	 * code happy.
166 	 */
167 	cpunode->nodeid = cpuid + 1;
168 
169 	/*
170 	 * Obtain the L2 cache information from MD.
171 	 * If "Cache" node exists, then set L2 cache properties
172 	 * as read from MD.
173 	 * If node does not exists, then set the L2 cache properties
174 	 * in individual CPU module.
175 	 */
176 	if ((!get_l2_cache_info(mdp, cpuc,
177 	    &associativity, &size, &linesize)) ||
178 	    associativity == 0 || size == 0 || linesize == 0) {
179 		cpu_fiximp(cpunode);
180 	} else {
181 		/*
182 		 * Do not expect L2 cache properties to be bigger
183 		 * than 32-bit quantity.
184 		 */
185 		cpunode->ecache_associativity = (int)associativity;
186 		cpunode->ecache_size = (int)size;
187 		cpunode->ecache_linesize = (int)linesize;
188 	}
189 
190 	cpunode->ecache_setsize =
191 	    cpunode->ecache_size / cpunode->ecache_associativity;
192 
193 	/*
194 	 * Initialize the mapping for exec unit, chip and core.
195 	 */
196 	cpunode->exec_unit_mapping = NO_EU_MAPPING_FOUND;
197 	cpunode->l2_cache_mapping = NO_MAPPING_FOUND;
198 	cpunode->core_mapping = NO_CORE_MAPPING_FOUND;
199 
200 	if (ecache_setsize == 0)
201 		ecache_setsize = cpunode->ecache_setsize;
202 	if (ecache_alignsize == 0)
203 		ecache_alignsize = cpunode->ecache_linesize;
204 
205 }
206 
207 void
empty_cpu(int cpuid)208 empty_cpu(int cpuid)
209 {
210 	bzero(&cpunodes[cpuid], sizeof (struct cpu_node));
211 }
212 
213 /*
214  * Use L2 cache node to derive the chip mapping.
215  */
216 void
setup_chip_mappings(md_t * mdp)217 setup_chip_mappings(md_t *mdp)
218 {
219 	int ncache, ncpu;
220 	mde_cookie_t *node, *cachelist;
221 	int i, j;
222 	processorid_t cpuid;
223 	int idx = 0;
224 
225 	ncache = md_alloc_scan_dag(mdp, md_root_node(mdp), "cache",
226 	    "fwd", &cachelist);
227 
228 	/*
229 	 * The "cache" node is optional in MD, therefore ncaches can be 0.
230 	 */
231 	if (ncache < 1) {
232 		return;
233 	}
234 
235 	for (i = 0; i < ncache; i++) {
236 		uint64_t cache_level;
237 		uint64_t lcpuid;
238 
239 		if (md_get_prop_val(mdp, cachelist[i], "level", &cache_level))
240 			continue;
241 
242 		if (cache_level != 2)
243 			continue;
244 
245 		/*
246 		 * Found a l2 cache node. Find out the cpu nodes it
247 		 * points to.
248 		 */
249 		ncpu = md_alloc_scan_dag(mdp, cachelist[i], "cpu",
250 		    "back", &node);
251 
252 		if (ncpu < 1)
253 			continue;
254 
255 		for (j = 0; j < ncpu; j++) {
256 			if (md_get_prop_val(mdp, node[j], "id", &lcpuid))
257 				continue;
258 			if (lcpuid >= NCPU)
259 				continue;
260 			cpuid = (processorid_t)lcpuid;
261 			cpunodes[cpuid].l2_cache_mapping = idx;
262 		}
263 		md_free_scan_dag(mdp, &node);
264 
265 		idx++;
266 	}
267 
268 	md_free_scan_dag(mdp, &cachelist);
269 }
270 
271 void
setup_exec_unit_mappings(md_t * mdp)272 setup_exec_unit_mappings(md_t *mdp)
273 {
274 	int num, num_eunits;
275 	mde_cookie_t cpus_node;
276 	mde_cookie_t *node, *eunit;
277 	int idx, i, j;
278 	processorid_t cpuid;
279 	char *eunit_name = broken_md_flag ? "exec_unit" : "exec-unit";
280 	enum eu_type { INTEGER, FPU } etype;
281 
282 	/*
283 	 * Find the cpu integer exec units - and
284 	 * setup the mappings appropriately.
285 	 */
286 	num = md_alloc_scan_dag(mdp, md_root_node(mdp), "cpus", "fwd", &node);
287 	if (num < 1)
288 		cmn_err(CE_PANIC, "No cpus node in machine description");
289 	if (num > 1)
290 		cmn_err(CE_PANIC, "More than 1 cpus node in machine"
291 		    " description");
292 
293 	cpus_node = node[0];
294 	md_free_scan_dag(mdp, &node);
295 
296 	num_eunits = md_alloc_scan_dag(mdp, cpus_node, eunit_name,
297 	    "fwd", &eunit);
298 	if (num_eunits > 0) {
299 		char *int_str = broken_md_flag ? "int" : "integer";
300 		char *fpu_str = "fp";
301 
302 		/* Spin through and find all the integer exec units */
303 		for (i = 0; i < num_eunits; i++) {
304 			char *p;
305 			char *val;
306 			int vallen;
307 			uint64_t lcpuid;
308 
309 			/* ignore nodes with no type */
310 			if (md_get_prop_data(mdp, eunit[i], "type",
311 			    (uint8_t **)&val, &vallen))
312 				continue;
313 
314 			for (p = val; *p != '\0'; p += strlen(p) + 1) {
315 				if (strcmp(p, int_str) == 0) {
316 					etype = INTEGER;
317 					goto found;
318 				}
319 				if (strcmp(p, fpu_str) == 0) {
320 					etype = FPU;
321 					goto found;
322 				}
323 			}
324 
325 			continue;
326 found:
327 			idx = NCPU + i;
328 			/*
329 			 * find the cpus attached to this EU and
330 			 * update their mapping indices
331 			 */
332 			num = md_alloc_scan_dag(mdp, eunit[i], "cpu",
333 			    "back", &node);
334 
335 			if (num < 1)
336 				cmn_err(CE_PANIC, "exec-unit node in MD"
337 				    " not attached to a cpu node");
338 
339 			for (j = 0; j < num; j++) {
340 				if (md_get_prop_val(mdp, node[j], "id",
341 				    &lcpuid))
342 					continue;
343 				if (lcpuid >= NCPU)
344 					continue;
345 				cpuid = (processorid_t)lcpuid;
346 				switch (etype) {
347 				case INTEGER:
348 					cpunodes[cpuid].exec_unit_mapping = idx;
349 					break;
350 				case FPU:
351 					cpunodes[cpuid].fpu_mapping = idx;
352 					break;
353 				}
354 			}
355 			md_free_scan_dag(mdp, &node);
356 		}
357 
358 
359 		md_free_scan_dag(mdp, &eunit);
360 	}
361 }
362 
363 /*
364  * All the common setup of sun4v CPU modules is done by this routine.
365  */
366 void
cpu_setup_common(char ** cpu_module_isa_set)367 cpu_setup_common(char **cpu_module_isa_set)
368 {
369 	extern int mmu_exported_pagesize_mask;
370 	int nocpus, i;
371 	size_t ra_limit;
372 	mde_cookie_t *cpulist;
373 	md_t *mdp;
374 
375 	if ((mdp = md_get_handle()) == NULL)
376 		cmn_err(CE_PANIC, "Unable to initialize machine description");
377 
378 	boot_ncpus = nocpus = md_alloc_scan_dag(mdp,
379 	    md_root_node(mdp), "cpu", "fwd", &cpulist);
380 	if (nocpus < 1) {
381 		cmn_err(CE_PANIC, "cpu_common_setup: cpulist allocation "
382 		    "failed or incorrect number of CPUs in MD");
383 	}
384 
385 	init_md_broken(mdp, cpulist);
386 
387 	if (use_page_coloring) {
388 		do_pg_coloring = 1;
389 	}
390 
391 	/*
392 	 * Get the valid mmu page sizes mask, Q sizes and isalist/r
393 	 * from the MD for the first available CPU in cpulist.
394 	 *
395 	 * Do not expect the MMU page sizes mask to be more than 32-bit.
396 	 */
397 	mmu_exported_pagesize_mask = (int)get_cpu_pagesizes(mdp, cpulist[0]);
398 
399 	/*
400 	 * Get the number of contexts and tsbs supported.
401 	 */
402 	if (get_mmu_shcontexts(mdp, cpulist[0]) >= MIN_NSHCONTEXTS &&
403 	    get_mmu_tsbs(mdp, cpulist[0]) >= MIN_NTSBS) {
404 		shctx_on = 1;
405 	}
406 
407 	for (i = 0; i < nocpus; i++)
408 		fill_cpu(mdp, cpulist[i]);
409 
410 	/* setup l2 cache count. */
411 	n_l2_caches = get_l2_cache_node_count(mdp);
412 
413 	setup_chip_mappings(mdp);
414 	setup_exec_unit_mappings(mdp);
415 
416 	/*
417 	 * If MD is broken then append the passed ISA set,
418 	 * otherwise trust the MD.
419 	 */
420 
421 	if (broken_md_flag)
422 		isa_list = construct_isalist(mdp, cpulist[0],
423 		    cpu_module_isa_set);
424 	else
425 		isa_list = construct_isalist(mdp, cpulist[0], NULL);
426 
427 	get_hwcaps(mdp, cpulist[0]);
428 	get_weakest_mem_model(mdp, cpulist[0]);
429 	get_q_sizes(mdp, cpulist[0]);
430 	get_va_bits(mdp, cpulist[0]);
431 
432 	/*
433 	 * ra_limit is the highest real address in the machine.
434 	 */
435 	ra_limit = get_ra_limit(mdp, cpulist[0]);
436 
437 	md_free_scan_dag(mdp, &cpulist);
438 
439 	(void) md_fini_handle(mdp);
440 
441 	/*
442 	 * Block stores invalidate all pages of the d$ so pagecopy
443 	 * et. al. do not need virtual translations with virtual
444 	 * coloring taken into consideration.
445 	 */
446 	pp_consistent_coloring = 0;
447 
448 	/*
449 	 * The kpm mapping window.
450 	 * kpm_size:
451 	 *	The size of a single kpm range.
452 	 *	The overall size will be: kpm_size * vac_colors.
453 	 * kpm_vbase:
454 	 *	The virtual start address of the kpm range within the kernel
455 	 *	virtual address space. kpm_vbase has to be kpm_size aligned.
456 	 */
457 
458 	/*
459 	 * Make kpm_vbase, kpm_size aligned to kpm_size_shift.
460 	 * To do this find the nearest power of 2 size that the
461 	 * actual ra_limit fits within.
462 	 * If it is an even power of two use that, otherwise use the
463 	 * next power of two larger than ra_limit.
464 	 */
465 
466 	ASSERT(ra_limit != 0);
467 
468 	kpm_size_shift = !ISP2(ra_limit) ?
469 	    highbit(ra_limit) : highbit(ra_limit) - 1;
470 
471 	/*
472 	 * No virtual caches on sun4v so size matches size shift
473 	 */
474 	kpm_size = 1ul << kpm_size_shift;
475 
476 	if (va_bits < VA_ADDRESS_SPACE_BITS) {
477 		/*
478 		 * In case of VA hole
479 		 * kpm_base = hole_end + 1TB
480 		 * Starting 1TB beyond where VA hole ends because on Niagara
481 		 * processor software must not use pages within 4GB of the
482 		 * VA hole as instruction pages to avoid problems with
483 		 * prefetching into the VA hole.
484 		 */
485 		kpm_vbase = (caddr_t)((0ull - (1ull << (va_bits - 1))) +
486 		    (1ull << 40));
487 	} else {		/* Number of VA bits 64 ... no VA hole */
488 		kpm_vbase = (caddr_t)0x8000000000000000ull;	/* 8 EB */
489 	}
490 
491 	/*
492 	 * The traptrace code uses either %tick or %stick for
493 	 * timestamping.  The sun4v require use of %stick.
494 	 */
495 	traptrace_use_stick = 1;
496 }
497 
498 /*
499  * Get the nctxs from MD. If absent panic.
500  */
501 static uint64_t
get_mmu_ctx_bits(md_t * mdp,mde_cookie_t cpu_node_cookie)502 get_mmu_ctx_bits(md_t *mdp, mde_cookie_t cpu_node_cookie)
503 {
504 	uint64_t ctx_bits;
505 
506 	if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#context-bits",
507 	    &ctx_bits))
508 		ctx_bits = 0;
509 
510 	if (ctx_bits < MIN_NCTXS_BITS || ctx_bits > MAX_NCTXS_BITS)
511 		cmn_err(CE_PANIC, "Incorrect %ld number of contexts bits "
512 		    "returned by MD", ctx_bits);
513 
514 	return (ctx_bits);
515 }
516 
517 /*
518  * Get the number of tsbs from MD. If absent the default value is 0.
519  */
520 static uint64_t
get_mmu_tsbs(md_t * mdp,mde_cookie_t cpu_node_cookie)521 get_mmu_tsbs(md_t *mdp, mde_cookie_t cpu_node_cookie)
522 {
523 	uint64_t number_tsbs;
524 
525 	if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-max-#tsbs",
526 	    &number_tsbs))
527 		number_tsbs = 0;
528 
529 	return (number_tsbs);
530 }
531 
532 /*
533  * Get the number of shared contexts from MD. If absent the default value is 0.
534  *
535  */
536 static uint64_t
get_mmu_shcontexts(md_t * mdp,mde_cookie_t cpu_node_cookie)537 get_mmu_shcontexts(md_t *mdp, mde_cookie_t cpu_node_cookie)
538 {
539 	uint64_t number_contexts;
540 
541 	if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#shared-contexts",
542 	    &number_contexts))
543 		number_contexts = 0;
544 
545 	return (number_contexts);
546 }
547 
548 /*
549  * Initalize supported page sizes information.
550  * Set to 0, if the page sizes mask information is absent in MD.
551  */
552 static uint64_t
get_cpu_pagesizes(md_t * mdp,mde_cookie_t cpu_node_cookie)553 get_cpu_pagesizes(md_t *mdp, mde_cookie_t cpu_node_cookie)
554 {
555 	uint64_t mmu_page_size_list;
556 
557 	if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-page-size-list",
558 	    &mmu_page_size_list))
559 		mmu_page_size_list = 0;
560 
561 	if (mmu_page_size_list == 0 || mmu_page_size_list > MAX_PAGESIZE_MASK)
562 		cmn_err(CE_PANIC, "Incorrect 0x%lx pagesize mask returned"
563 		    "by MD", mmu_page_size_list);
564 
565 	return (mmu_page_size_list);
566 }
567 
568 /*
569  * This routine gets the isalist information from MD and appends
570  * the CPU module ISA set if required.
571  */
572 static char *
construct_isalist(md_t * mdp,mde_cookie_t cpu_node_cookie,char ** cpu_module_isa_set)573 construct_isalist(md_t *mdp, mde_cookie_t cpu_node_cookie,
574     char **cpu_module_isa_set)
575 {
576 	extern int at_flags;
577 	char *md_isalist;
578 	int md_isalen;
579 	char *isabuf;
580 	int isalen;
581 	char **isa_set;
582 	char *p, *q;
583 	int cpu_module_isalen = 0, found = 0;
584 
585 	(void) md_get_prop_data(mdp, cpu_node_cookie,
586 	    "isalist", (uint8_t **)&isabuf, &isalen);
587 
588 	/*
589 	 * We support binaries for all the cpus that have shipped so far.
590 	 * The kernel emulates instructions that are not supported by hardware.
591 	 */
592 	at_flags = EF_SPARC_SUN_US3 | EF_SPARC_32PLUS | EF_SPARC_SUN_US1;
593 
594 	/*
595 	 * Construct the space separated isa_list.
596 	 */
597 	if (cpu_module_isa_set != NULL) {
598 		for (isa_set = cpu_module_isa_set; *isa_set != NULL;
599 		    isa_set++) {
600 			cpu_module_isalen += strlen(*isa_set);
601 			cpu_module_isalen++;	/* for space character */
602 		}
603 	}
604 
605 	/*
606 	 * Allocate the buffer of MD isa buffer length + CPU module
607 	 * isa buffer length.
608 	 */
609 	md_isalen = isalen + cpu_module_isalen + 2;
610 	md_isalist = (char *)prom_alloc((caddr_t)0, md_isalen, 0);
611 	if (md_isalist == NULL)
612 		cmn_err(CE_PANIC, "construct_isalist: Allocation failed for "
613 		    "md_isalist");
614 
615 	md_isalist[0] = '\0'; /* create an empty string to start */
616 	for (p = isabuf, q = p + isalen; p < q; p += strlen(p) + 1) {
617 		(void) strlcat(md_isalist, p, md_isalen);
618 		(void) strcat(md_isalist, " ");
619 	}
620 
621 	/*
622 	 * Check if the isa_set is present in isalist returned by MD.
623 	 * If yes, then no need to append it, if no then append it to
624 	 * isalist returned by MD.
625 	 */
626 	if (cpu_module_isa_set != NULL) {
627 		for (isa_set = cpu_module_isa_set; *isa_set != NULL;
628 		    isa_set++) {
629 			found = 0;
630 			for (p = isabuf, q = p + isalen; p < q;
631 			    p += strlen(p) + 1) {
632 				if (strcmp(p, *isa_set) == 0) {
633 					found = 1;
634 					break;
635 				}
636 			}
637 			if (!found) {
638 				(void) strlcat(md_isalist, *isa_set, md_isalen);
639 				(void) strcat(md_isalist, " ");
640 			}
641 		}
642 	}
643 
644 	/* Get rid of any trailing white spaces */
645 	md_isalist[strlen(md_isalist) - 1] = '\0';
646 
647 	return (md_isalist);
648 }
649 
650 static void
get_hwcaps(md_t * mdp,mde_cookie_t cpu_node_cookie)651 get_hwcaps(md_t *mdp, mde_cookie_t cpu_node_cookie)
652 {
653 	char *hwcapbuf;
654 	int hwcaplen;
655 
656 	if (md_get_prop_data(mdp, cpu_node_cookie,
657 	    "hwcap-list", (uint8_t **)&hwcapbuf, &hwcaplen)) {
658 		/* Property not found */
659 		return;
660 	}
661 
662 	cpu_hwcap_flags |= names2bits(hwcapbuf, hwcaplen, FMT_AV_SPARC,
663 	    "unrecognized token: %s");
664 }
665 
666 static void
get_weakest_mem_model(md_t * mdp,mde_cookie_t cpu_node_cookie)667 get_weakest_mem_model(md_t *mdp, mde_cookie_t cpu_node_cookie)
668 {
669 	char *mmbuf;
670 	int mmlen;
671 	uint_t wmm;
672 	char *p, *q;
673 
674 	if (md_get_prop_data(mdp, cpu_node_cookie,
675 	    "memory-model-list", (uint8_t **)&mmbuf, &mmlen)) {
676 		/* Property not found */
677 		return;
678 	}
679 
680 	wmm = TSTATE_MM_TSO;
681 	for (p = mmbuf, q = p + mmlen; p < q; p += strlen(p) + 1) {
682 		if (strcmp(p, "wc") == 0)
683 			wmm = TSTATE_MM_WC;
684 	}
685 	weakest_mem_model = wmm;
686 }
687 
688 /*
689  * Does the opposite of cmn_err(9f) "%b" conversion specification:
690  * Given a list of strings, converts them to a bit-vector.
691  *
692  *  tokens - is a buffer of [NUL-terminated] strings.
693  *  tokenslen - length of tokenbuf in bytes.
694  *  bit_formatter - is a %b format string, such as FMT_AV_SPARC
695  *    from /usr/include/sys/auxv_SPARC.h, of the form:
696  *    <base-char>[<bit-char><token-string>]...
697  *        <base-char> is ignored.
698  *        <bit-char>  is [1-32], as per cmn_err(9f).
699  *  warning - is a printf-style format string containing "%s",
700  *    which is used to print a warning message when an unrecognized
701  *    token is found.  If warning is NULL, no warning is printed.
702  * Returns a bit-vector corresponding to the specified tokens.
703  */
704 
705 static unsigned long
names2bits(char * tokens,size_t tokenslen,char * bit_formatter,char * warning)706 names2bits(char *tokens, size_t tokenslen, char *bit_formatter, char *warning)
707 {
708 	char *cur;
709 	size_t  curlen;
710 	unsigned long ul = 0;
711 	char *hit;
712 	char *bs;
713 
714 	bit_formatter++;	/* skip base; not needed for input */
715 	cur = tokens;
716 	while (tokenslen) {
717 		curlen = strlen(cur);
718 		bs = bit_formatter;
719 		/*
720 		 * We need a complicated while loop and the >=32 check,
721 		 * instead of a simple "if (strstr())" so that when the
722 		 * token is "vis", we don't match on "vis2" (for example).
723 		 */
724 		/* LINTED E_EQUALITY_NOT_ASSIGNMENT */
725 		while ((hit = strstr(bs, cur)) &&
726 		    *(hit + curlen) >= 32) {
727 			/*
728 			 * We're still in the middle of a word, i.e., not
729 			 * pointing at a <bit-char>.  So advance ptr
730 			 * to ensure forward progress.
731 			 */
732 			bs = hit + curlen + 1;
733 		}
734 
735 		if (hit != NULL) {
736 			ul |= (1<<(*(hit-1) - 1));
737 		} else {
738 			/* The token wasn't found in bit_formatter */
739 			if (warning != NULL)
740 				cmn_err(CE_WARN, warning, cur);
741 		}
742 		tokenslen -= curlen + 1;
743 		cur += curlen + 1;
744 	}
745 	return (ul);
746 }
747 
748 uint64_t
get_ra_limit(md_t * mdp,mde_cookie_t cpu_node_cookie)749 get_ra_limit(md_t *mdp, mde_cookie_t cpu_node_cookie)
750 {
751 	extern int ppvm_enable;
752 	extern int meta_alloc_enable;
753 	mde_cookie_t *mem_list;
754 	mde_cookie_t *mblock_list;
755 	int i;
756 	int memnodes;
757 	int nmblock;
758 	uint64_t r;
759 	uint64_t base;
760 	uint64_t size;
761 	uint64_t ra_limit = 0, new_limit = 0;
762 
763 	if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#ra-bits", &r) == 0) {
764 		if (r == 0 || r > RA_ADDRESS_SPACE_BITS)
765 			cmn_err(CE_PANIC, "Incorrect number of ra bits in MD");
766 		else {
767 			/*
768 			 * Enable memory DR and metadata (page_t)
769 			 * allocation from existing memory.
770 			 */
771 			ppvm_enable = 1;
772 			meta_alloc_enable = 1;
773 			return (1ULL << r);
774 		}
775 	}
776 
777 	memnodes = md_alloc_scan_dag(mdp,
778 	    md_root_node(mdp), "memory", "fwd", &mem_list);
779 
780 	ASSERT(memnodes == 1);
781 
782 	nmblock = md_alloc_scan_dag(mdp,
783 	    mem_list[0], "mblock", "fwd", &mblock_list);
784 	if (nmblock < 1)
785 		cmn_err(CE_PANIC, "cannot find mblock nodes in MD");
786 
787 	for (i = 0; i < nmblock; i++) {
788 		if (md_get_prop_val(mdp, mblock_list[i], "base", &base))
789 			cmn_err(CE_PANIC, "base property missing from MD"
790 			    " mblock node");
791 		if (md_get_prop_val(mdp, mblock_list[i], "size", &size))
792 			cmn_err(CE_PANIC, "size property missing from MD"
793 			    " mblock node");
794 
795 		ASSERT(size != 0);
796 
797 		new_limit = base + size;
798 
799 		if (base > new_limit)
800 			cmn_err(CE_PANIC, "mblock in MD wrapped around");
801 
802 		if (new_limit > ra_limit)
803 			ra_limit = new_limit;
804 	}
805 
806 	ASSERT(ra_limit != 0);
807 
808 	if (ra_limit > MAX_REAL_ADDRESS) {
809 		cmn_err(CE_WARN, "Highest real address in MD too large"
810 		    " clipping to %llx\n", MAX_REAL_ADDRESS);
811 		ra_limit = MAX_REAL_ADDRESS;
812 	}
813 
814 	md_free_scan_dag(mdp, &mblock_list);
815 
816 	md_free_scan_dag(mdp, &mem_list);
817 
818 	return (ra_limit);
819 }
820 
821 /*
822  * This routine sets the globals for CPU and DEV mondo queue entries and
823  * resumable and non-resumable error queue entries.
824  *
825  * First, look up the number of bits available to pass an entry number.
826  * This can vary by platform and may result in allocating an unreasonably
827  * (or impossibly) large amount of memory for the corresponding table,
828  * so we clamp it by 'max_entries'.  Finally, since the q size is used when
829  * calling contig_mem_alloc(), which expects a power of 2, clamp the q size
830  * down to a power of 2.  If the prop is missing, use 'default_entries'.
831  */
832 static uint64_t
get_single_q_size(md_t * mdp,mde_cookie_t cpu_node_cookie,char * qnamep,uint64_t default_entries,uint64_t max_entries)833 get_single_q_size(md_t *mdp, mde_cookie_t cpu_node_cookie,
834     char *qnamep, uint64_t default_entries, uint64_t max_entries)
835 {
836 	uint64_t entries;
837 
838 	if (default_entries > max_entries)
839 		cmn_err(CE_CONT, "!get_single_q_size: dflt %ld > "
840 		    "max %ld for %s\n", default_entries, max_entries, qnamep);
841 
842 	if (md_get_prop_val(mdp, cpu_node_cookie, qnamep, &entries)) {
843 		if (!broken_md_flag)
844 			cmn_err(CE_PANIC, "Missing %s property in MD cpu node",
845 			    qnamep);
846 		entries = default_entries;
847 	} else {
848 		entries = 1 << entries;
849 	}
850 
851 	entries = MIN(entries, max_entries);
852 	/* If not a power of 2, truncate to a power of 2. */
853 	if (!ISP2(entries)) {
854 		entries = 1 << (highbit(entries) - 1);
855 	}
856 
857 	return (entries);
858 }
859 
860 /* Scaling constant used to compute size of cpu mondo queue */
861 #define	CPU_MONDO_Q_MULTIPLIER	8
862 
863 static void
get_q_sizes(md_t * mdp,mde_cookie_t cpu_node_cookie)864 get_q_sizes(md_t *mdp, mde_cookie_t cpu_node_cookie)
865 {
866 	uint64_t max_qsize;
867 	mde_cookie_t *platlist;
868 	int nrnode;
869 
870 	/*
871 	 * Compute the maximum number of entries for the cpu mondo queue.
872 	 * Use the appropriate property in the platform node, if it is
873 	 * available.  Else, base it on NCPU.
874 	 */
875 	nrnode = md_alloc_scan_dag(mdp,
876 	    md_root_node(mdp), "platform", "fwd", &platlist);
877 
878 	ASSERT(nrnode == 1);
879 
880 	ncpu_guest_max = NCPU;
881 	(void) md_get_prop_val(mdp, platlist[0], "max-cpus", &ncpu_guest_max);
882 	max_qsize = ncpu_guest_max * CPU_MONDO_Q_MULTIPLIER;
883 
884 	md_free_scan_dag(mdp, &platlist);
885 
886 	cpu_q_entries = get_single_q_size(mdp, cpu_node_cookie,
887 	    "q-cpu-mondo-#bits", DEFAULT_CPU_Q_ENTRIES, max_qsize);
888 
889 	dev_q_entries = get_single_q_size(mdp, cpu_node_cookie,
890 	    "q-dev-mondo-#bits", DEFAULT_DEV_Q_ENTRIES, MAXIVNUM);
891 
892 	cpu_rq_entries = get_single_q_size(mdp, cpu_node_cookie,
893 	    "q-resumable-#bits", CPU_RQ_ENTRIES, MAX_CPU_RQ_ENTRIES);
894 
895 	cpu_nrq_entries = get_single_q_size(mdp, cpu_node_cookie,
896 	    "q-nonresumable-#bits", CPU_NRQ_ENTRIES, MAX_CPU_NRQ_ENTRIES);
897 }
898 
899 
900 static void
get_va_bits(md_t * mdp,mde_cookie_t cpu_node_cookie)901 get_va_bits(md_t *mdp, mde_cookie_t cpu_node_cookie)
902 {
903 	uint64_t value = VA_ADDRESS_SPACE_BITS;
904 
905 	if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#va-bits", &value))
906 		cmn_err(CE_PANIC, "mmu-#va-bits property  not found in MD");
907 
908 
909 	if (value == 0 || value > VA_ADDRESS_SPACE_BITS)
910 		cmn_err(CE_PANIC, "Incorrect number of va bits in MD");
911 
912 	/* Do not expect number of VA bits to be more than 32-bit quantity */
913 
914 	va_bits = (int)value;
915 
916 	/*
917 	 * Correct the value for VA bits on UltraSPARC-T1 based systems
918 	 * in case of broken MD.
919 	 */
920 	if (broken_md_flag)
921 		va_bits = DEFAULT_VA_ADDRESS_SPACE_BITS;
922 }
923 
924 int
l2_cache_node_count(void)925 l2_cache_node_count(void)
926 {
927 	return (n_l2_caches);
928 }
929 
930 /*
931  * count the number of l2 caches.
932  */
933 int
get_l2_cache_node_count(md_t * mdp)934 get_l2_cache_node_count(md_t *mdp)
935 {
936 	int i;
937 	mde_cookie_t *cachenodes;
938 	uint64_t level;
939 	int n_cachenodes = md_alloc_scan_dag(mdp, md_root_node(mdp),
940 	    "cache", "fwd", &cachenodes);
941 	int l2_caches = 0;
942 
943 	for (i = 0; i < n_cachenodes; i++) {
944 		if (md_get_prop_val(mdp, cachenodes[i], "level", &level) != 0) {
945 			level = 0;
946 		}
947 		if (level == 2) {
948 			l2_caches++;
949 		}
950 	}
951 	md_free_scan_dag(mdp, &cachenodes);
952 	return (l2_caches);
953 }
954 
955 /*
956  * This routine returns the L2 cache information such as -- associativity,
957  * size and linesize.
958  */
959 static int
get_l2_cache_info(md_t * mdp,mde_cookie_t cpu_node_cookie,uint64_t * associativity,uint64_t * size,uint64_t * linesize)960 get_l2_cache_info(md_t *mdp, mde_cookie_t cpu_node_cookie,
961 	    uint64_t *associativity, uint64_t *size, uint64_t *linesize)
962 {
963 	mde_cookie_t *cachelist;
964 	int ncaches, i;
965 	uint64_t cache_level = 0;
966 
967 	ncaches = md_alloc_scan_dag(mdp, cpu_node_cookie, "cache",
968 	    "fwd", &cachelist);
969 	/*
970 	 * The "cache" node is optional in MD, therefore ncaches can be 0.
971 	 */
972 	if (ncaches < 1) {
973 		return (0);
974 	}
975 
976 	for (i = 0; i < ncaches; i++) {
977 		uint64_t local_assoc;
978 		uint64_t local_size;
979 		uint64_t local_lsize;
980 
981 		if (md_get_prop_val(mdp, cachelist[i], "level", &cache_level))
982 			continue;
983 
984 		if (cache_level != 2) continue;
985 
986 		/* If properties are missing from this cache ignore it */
987 
988 		if ((md_get_prop_val(mdp, cachelist[i],
989 		    "associativity", &local_assoc))) {
990 			continue;
991 		}
992 
993 		if ((md_get_prop_val(mdp, cachelist[i],
994 		    "size", &local_size))) {
995 			continue;
996 		}
997 
998 		if ((md_get_prop_val(mdp, cachelist[i],
999 		    "line-size", &local_lsize))) {
1000 			continue;
1001 		}
1002 
1003 		*associativity = local_assoc;
1004 		*size = local_size;
1005 		*linesize = local_lsize;
1006 		break;
1007 	}
1008 
1009 	md_free_scan_dag(mdp, &cachelist);
1010 
1011 	return ((cache_level == 2) ? 1 : 0);
1012 }
1013 
1014 
1015 /*
1016  * Set the broken_md_flag to 1 if the MD doesn't have
1017  * the domaining-enabled property in the platform node and the
1018  * platform uses the UltraSPARC-T1 cpu. This flag is used to
1019  * workaround some of the incorrect MD properties.
1020  */
1021 static void
init_md_broken(md_t * mdp,mde_cookie_t * cpulist)1022 init_md_broken(md_t *mdp, mde_cookie_t *cpulist)
1023 {
1024 	int nrnode;
1025 	mde_cookie_t *platlist, rootnode;
1026 	uint64_t val = 0;
1027 	char *namebuf;
1028 	int namelen;
1029 
1030 	rootnode = md_root_node(mdp);
1031 	ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE);
1032 	ASSERT(cpulist);
1033 
1034 	nrnode = md_alloc_scan_dag(mdp, rootnode, "platform", "fwd",
1035 	    &platlist);
1036 
1037 	if (nrnode < 1)
1038 		cmn_err(CE_PANIC, "init_md_broken: platform node missing");
1039 
1040 	if (md_get_prop_data(mdp, cpulist[0],
1041 	    "compatible", (uint8_t **)&namebuf, &namelen)) {
1042 		cmn_err(CE_PANIC, "init_md_broken: "
1043 		    "Cannot read 'compatible' property of 'cpu' node");
1044 	}
1045 
1046 	if (md_get_prop_val(mdp, platlist[0],
1047 	    "domaining-enabled", &val) == -1 &&
1048 	    strcmp(namebuf, "SUNW,UltraSPARC-T1") == 0)
1049 		broken_md_flag = 1;
1050 
1051 	md_free_scan_dag(mdp, &platlist);
1052 }
1053 
1054 #define	PLAT_MAX_IOALIASES	8
1055 
1056 static plat_alias_t *plat_ioaliases;
1057 static uint64_t plat_num_ioaliases;
1058 
1059 /*
1060  * split the aliases property into its
1061  * component strings for easy searching.
1062  */
1063 static void
split_alias(plat_alias_t * pali,char * str)1064 split_alias(plat_alias_t *pali, char *str)
1065 {
1066 	char *aliasv[PLAT_MAX_IOALIASES], *p;
1067 	int i, duplen;
1068 	char *dup;
1069 
1070 	/* skip leading space */
1071 	str = dup = strdup(str);
1072 	duplen = strlen(dup) + 1;
1073 	str += strspn(str, " ");
1074 	for (i = 0; *str != '\0'; str = p) {
1075 
1076 		p = strpbrk(str, " ");
1077 		if (p != NULL) {
1078 			*p++ = '\0';
1079 		}
1080 
1081 		VERIFY(i < PLAT_MAX_IOALIASES);
1082 		aliasv[i++] = strdup(str);
1083 		if (p == NULL)
1084 			break;
1085 		p += strspn(p, " ");
1086 	}
1087 
1088 	kmem_free(dup, duplen);
1089 
1090 	if (i == 0) {
1091 		pali->pali_naliases = 0;
1092 		pali->pali_aliases = NULL;
1093 		return;
1094 	}
1095 
1096 	pali->pali_naliases = i;
1097 	pali->pali_aliases = kmem_alloc(i * sizeof (char *), KM_SLEEP);
1098 	for (i = 0; i < pali->pali_naliases; i++) {
1099 		pali->pali_aliases[i] = aliasv[i];
1100 	}
1101 }
1102 
1103 /*
1104  * retrieve the ioalias info from the MD,
1105  * and init the ioalias struct.
1106  *
1107  * NOTE: Assumes that the ioalias info does not change at runtime
1108  * This routine is invoked only once at boot time.
1109  *
1110  * No lock needed as this is called at boot with a DDI lock held
1111  */
1112 void
plat_ioaliases_init(void)1113 plat_ioaliases_init(void)
1114 {
1115 	md_t *mdp;
1116 	mde_cookie_t *ionodes, alinode;
1117 	plat_alias_t *pali;
1118 	int nio;
1119 	int i;
1120 	int err;
1121 
1122 	mdp = md_get_handle();
1123 	if (mdp == NULL) {
1124 		cmn_err(CE_PANIC, "no machine description (MD)");
1125 		/*NOTREACHED*/
1126 	}
1127 
1128 	nio = md_alloc_scan_dag(mdp, md_root_node(mdp),
1129 	    "ioaliases", "fwd", &ionodes);
1130 
1131 
1132 	/* not all platforms support aliases */
1133 	if (nio < 1) {
1134 		(void) md_fini_handle(mdp);
1135 		return;
1136 	}
1137 	if (nio > 1) {
1138 		cmn_err(CE_PANIC, "multiple ioalias nodes in MD");
1139 		/*NOTREACHED*/
1140 	}
1141 
1142 	alinode = ionodes[0];
1143 	md_free_scan_dag(mdp, &ionodes);
1144 
1145 	nio = md_alloc_scan_dag(mdp, alinode, "ioalias", "fwd", &ionodes);
1146 	if (nio <= 0) {
1147 		cmn_err(CE_PANIC, "MD alias node has no aliases");
1148 		/*NOTREACHED*/
1149 	}
1150 
1151 	plat_num_ioaliases = nio;
1152 	plat_ioaliases = pali = kmem_zalloc(nio * sizeof (plat_alias_t),
1153 	    KM_SLEEP);
1154 
1155 	/*
1156 	 * Each ioalias map will have a composite property of
1157 	 * aliases and the current valid path.
1158 	 */
1159 	for (i = 0; i < nio; i++) {
1160 		char *str;
1161 
1162 		err = md_get_prop_str(mdp, ionodes[i], "current", &str);
1163 		if (err != 0) {
1164 			cmn_err(CE_PANIC, "malformed ioalias node");
1165 			/*NOTREACHED*/
1166 		}
1167 		pali->pali_current = strdup(str);
1168 
1169 		err = md_get_prop_str(mdp, ionodes[i], "aliases", &str);
1170 		if (err != 0) {
1171 			cmn_err(CE_PANIC, "malformed aliases");
1172 			/*NOTREACHED*/
1173 		}
1174 		DDI_MP_DBG((CE_NOTE, "path: %s aliases %s",
1175 		    pali->pali_current, str));
1176 
1177 		split_alias(pali, str);
1178 		pali++;
1179 	}
1180 
1181 	md_free_scan_dag(mdp, &ionodes);
1182 
1183 	/*
1184 	 * Register the io-aliases array with the DDI framework
1185 	 * The DDI framework assumes that this array and its contents
1186 	 * will not change post-register. The DDI framework will
1187 	 * cache this array and is free to access this array at
1188 	 * any time without any locks.
1189 	 */
1190 	ddi_register_aliases(plat_ioaliases, plat_num_ioaliases);
1191 
1192 	(void) md_fini_handle(mdp);
1193 }
1194 
1195 /*
1196  * Number of bits forming a valid context for use in a sun4v TTE and the MMU
1197  * context registers. Sun4v defines the minimum default value to be 13 if this
1198  * property is not specified in a cpu node in machine descriptor graph.
1199  */
1200 #define	MMU_INFO_CTXBITS_MIN		13
1201 
1202 /* Convert context bits to number of contexts */
1203 #define	MMU_INFO_BNCTXS(nbits)		((uint_t)(1u<<(nbits)))
1204 
1205 /*
1206  * Read machine descriptor and load TLB to CPU mappings.
1207  * Returned values: cpuid2pset[NCPU], nctxs[NCPU], md_gen
1208  * - cpuid2pset is initialized so it can convert cpuids to processor set of CPUs
1209  *   that are shared between TLBs.
1210  * - nctxs is initialized to number of contexts for each CPU
1211  * - md_gen is set to generation number of machine descriptor from which this
1212  *   data was.
1213  * Return: zero on success.
1214  */
1215 static int
load_tlb_cpu_mappings(cpuset_t ** cpuid2pset,uint_t * nctxs,uint64_t * md_gen)1216 load_tlb_cpu_mappings(cpuset_t **cpuid2pset, uint_t *nctxs, uint64_t *md_gen)
1217 {
1218 	mde_str_cookie_t cpu_sc, bck_sc;
1219 	int		tlbs_idx, cp_idx;
1220 	mde_cookie_t	root;
1221 	md_t		*mdp = NULL;
1222 	mde_cookie_t	*tlbs = NULL;
1223 	mde_cookie_t	*cp = NULL;
1224 	uint64_t	*cpids = NULL;
1225 	uint64_t	nbit;
1226 	int		ntlbs;
1227 	int		ncp;
1228 	int		retval = 1;
1229 	cpuset_t	*ppset;
1230 
1231 	/* get MD handle, and string cookies for cpu and back nodes */
1232 	if ((mdp = md_get_handle()) == NULL ||
1233 	    (cpu_sc = md_find_name(mdp, "cpu")) == MDE_INVAL_STR_COOKIE ||
1234 	    (bck_sc = md_find_name(mdp, "back")) == MDE_INVAL_STR_COOKIE)
1235 		goto cleanup;
1236 
1237 	/* set generation number of current MD handle */
1238 	*md_gen = md_get_gen(mdp);
1239 
1240 	/* Find root element, and search for all TLBs in MD */
1241 	if ((root = md_root_node(mdp)) == MDE_INVAL_ELEM_COOKIE ||
1242 	    (ntlbs = md_alloc_scan_dag(mdp, root, "tlb", "fwd", &tlbs)) <= 0)
1243 		goto cleanup;
1244 
1245 	cp = kmem_alloc(sizeof (mde_cookie_t) * NCPU, KM_SLEEP);
1246 	cpids = kmem_alloc(sizeof (uint64_t) * NCPU, KM_SLEEP);
1247 
1248 	/*
1249 	 * Build processor sets, one per possible context domain.  For each tlb,
1250 	 * search for connected CPUs.  If any CPU is already in a set, then add
1251 	 * all the TLB's CPUs to that set.  Otherwise, create and populate a new
1252 	 * pset.  Thus, a single pset is built to represent multiple TLBs if
1253 	 * they have CPUs in common.
1254 	 */
1255 	for (tlbs_idx = 0; tlbs_idx < ntlbs; tlbs_idx++) {
1256 		ncp = md_scan_dag(mdp, tlbs[tlbs_idx], cpu_sc, bck_sc, cp);
1257 		if (ncp < 0)
1258 			goto cleanup;
1259 		else if (ncp == 0)
1260 			continue;
1261 
1262 		/* Get the id and number of contexts for each cpu */
1263 		for (cp_idx = 0; cp_idx < ncp; cp_idx++) {
1264 			mde_cookie_t c = cp[cp_idx];
1265 
1266 			if (md_get_prop_val(mdp, c, "id", &cpids[cp_idx]))
1267 				goto cleanup;
1268 			if (md_get_prop_val(mdp, c, "mmu-#context-bits", &nbit))
1269 				nbit = MMU_INFO_CTXBITS_MIN;
1270 			nctxs[cpids[cp_idx]] = MMU_INFO_BNCTXS(nbit);
1271 		}
1272 
1273 		/*
1274 		 * If a CPU is already in a set as shown by cpuid2pset[], then
1275 		 * use that set.
1276 		 */
1277 		for (cp_idx = 0; cp_idx < ncp; cp_idx++) {
1278 			ASSERT(cpids[cp_idx] < NCPU);
1279 			ppset = cpuid2pset[cpids[cp_idx]];
1280 			if (ppset != NULL)
1281 				break;
1282 		}
1283 
1284 		/* No CPU has a set. Create a new one. */
1285 		if (ppset == NULL) {
1286 			ppset = kmem_alloc(sizeof (cpuset_t), KM_SLEEP);
1287 			CPUSET_ZERO(*ppset);
1288 		}
1289 
1290 		/* Add every CPU to the set, and record the set assignment. */
1291 		for (cp_idx = 0; cp_idx < ncp; cp_idx++) {
1292 			cpuid2pset[cpids[cp_idx]] = ppset;
1293 			CPUSET_ADD(*ppset, cpids[cp_idx]);
1294 		}
1295 	}
1296 
1297 	retval = 0;
1298 
1299 cleanup:
1300 	if (tlbs != NULL)
1301 		md_free_scan_dag(mdp, &tlbs);
1302 	if (cp != NULL)
1303 		kmem_free(cp, sizeof (mde_cookie_t) * NCPU);
1304 	if (cpids != NULL)
1305 		kmem_free(cpids, sizeof (uint64_t) * NCPU);
1306 	if (mdp != NULL)
1307 		(void) md_fini_handle(mdp);
1308 
1309 	return (retval);
1310 }
1311 
1312 /*
1313  * Return MMU info based on cpuid.
1314  *
1315  * Algorithm:
1316  * Read machine descriptor and find all CPUs that share the same TLB with CPU
1317  * specified by cpuid. Go through found CPUs and see if any one of them already
1318  * has MMU index, if so, set index based on that value. If CPU does not share
1319  * TLB with any other CPU or if none of those CPUs has mmu_ctx pointer, find the
1320  * smallest available MMU index and give it to current CPU. If no available
1321  * domain, perform a round robin, and start assigning from the beginning.
1322  *
1323  * For optimization reasons, this function uses a cache to store all TLB to CPU
1324  * mappings, and updates them only when machine descriptor graph is changed.
1325  * Because of this, and because we search MMU table for smallest index id, this
1326  * function needs to be serialized which is protected by cpu_lock.
1327  */
1328 void
plat_cpuid_to_mmu_ctx_info(processorid_t cpuid,mmu_ctx_info_t * info)1329 plat_cpuid_to_mmu_ctx_info(processorid_t cpuid, mmu_ctx_info_t *info)
1330 {
1331 	static cpuset_t	**cpuid2pset = NULL;
1332 	static uint_t	*nctxs;
1333 	static uint_t	next_domain = 0;
1334 	static uint64_t	md_gen = MDESC_INVAL_GEN;
1335 	uint64_t	current_gen;
1336 	int		idx;
1337 	cpuset_t	cpuid_pset;
1338 	processorid_t	id;
1339 	cpu_t		*cp;
1340 
1341 	ASSERT(MUTEX_HELD(&cpu_lock));
1342 
1343 	current_gen = md_get_current_gen();
1344 
1345 	/*
1346 	 * Load TLB CPU mappings only if MD generation has changed, FW that do
1347 	 * not provide generation number, always return MDESC_INVAL_GEN, and as
1348 	 * result MD is read here only once on such machines: when cpuid2pset is
1349 	 * NULL
1350 	 */
1351 	if (current_gen != md_gen || cpuid2pset == NULL) {
1352 		if (cpuid2pset == NULL) {
1353 			cpuid2pset = kmem_zalloc(sizeof (cpuset_t *) * NCPU,
1354 			    KM_SLEEP);
1355 			nctxs = kmem_alloc(sizeof (uint_t) * NCPU, KM_SLEEP);
1356 		} else {
1357 			/* clean cpuid2pset[NCPU], before loading new values */
1358 			for (idx = 0; idx < NCPU; idx++) {
1359 				cpuset_t *pset = cpuid2pset[idx];
1360 
1361 				if (pset != NULL) {
1362 					for (;;) {
1363 						CPUSET_FIND(*pset, id);
1364 						if (id == CPUSET_NOTINSET)
1365 							break;
1366 						CPUSET_DEL(*pset, id);
1367 						ASSERT(id < NCPU);
1368 						cpuid2pset[id] = NULL;
1369 					}
1370 					ASSERT(cpuid2pset[idx] == NULL);
1371 					kmem_free(pset, sizeof (cpuset_t));
1372 				}
1373 			}
1374 		}
1375 
1376 		if (load_tlb_cpu_mappings(cpuid2pset, nctxs, &md_gen))
1377 			goto error_panic;
1378 	}
1379 
1380 	info->mmu_nctxs = nctxs[cpuid];
1381 
1382 	if (cpuid2pset[cpuid] == NULL)
1383 		goto error_panic;
1384 
1385 	cpuid_pset = *cpuid2pset[cpuid];
1386 	CPUSET_DEL(cpuid_pset, cpuid);
1387 
1388 	/* Search for a processor in the same TLB pset with MMU context */
1389 	for (;;) {
1390 		CPUSET_FIND(cpuid_pset, id);
1391 
1392 		if (id == CPUSET_NOTINSET)
1393 			break;
1394 
1395 		ASSERT(id < NCPU);
1396 		cp = cpu[id];
1397 		if (cp != NULL && CPU_MMU_CTXP(cp) != NULL) {
1398 			info->mmu_idx = CPU_MMU_IDX(cp);
1399 
1400 			return;
1401 		}
1402 		CPUSET_DEL(cpuid_pset, id);
1403 	}
1404 
1405 	/*
1406 	 * No CPU in the TLB pset has a context domain yet.
1407 	 * Use next_domain if available, or search for an unused domain, or
1408 	 * overload next_domain, in that order.  Overloading is necessary when
1409 	 * the number of TLB psets is greater than max_mmu_ctxdoms.
1410 	 */
1411 	idx = next_domain;
1412 
1413 	if (mmu_ctxs_tbl[idx] != NULL) {
1414 		for (idx = 0; idx < max_mmu_ctxdoms; idx++)
1415 			if (mmu_ctxs_tbl[idx] == NULL)
1416 				break;
1417 		if (idx == max_mmu_ctxdoms) {
1418 			/* overload next_domain */
1419 			idx = next_domain;
1420 
1421 			if (info->mmu_nctxs < sfmmu_ctxdom_nctxs(idx))
1422 				cmn_err(CE_PANIC, "max_mmu_ctxdoms is too small"
1423 				    " to support CPUs with different nctxs");
1424 		}
1425 	}
1426 
1427 	info->mmu_idx = idx;
1428 	next_domain = (idx + 1) % max_mmu_ctxdoms;
1429 
1430 	return;
1431 
1432 error_panic:
1433 	cmn_err(CE_PANIC, "!cpu%d: failed to get MMU CTX domain index", cpuid);
1434 }
1435