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