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 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <sys/param.h>
28 #include <sys/systm.h>
29 #include <sys/sysmacros.h>
30 #include <sys/sunddi.h>
31 #include <sys/modctl.h>
32 #include <sys/promif.h>
33 #include <sys/machparam.h>
34 #include <sys/kobj.h>
35 #include <sys/mem_cage.h>
36 #include <sys/starfire.h>
37
38 #include <sys/platform_module.h>
39 #include <sys/errno.h>
40 #include <vm/page.h>
41 #include <vm/hat_sfmmu.h>
42 #include <sys/memnode.h>
43 #include <vm/vm_dep.h>
44 #include <sys/cpu_sgnblk_defs.h>
45 #include <sys/cpu_sgn.h>
46 #include <sys/kdi_impl.h>
47 #include <sys/clock_impl.h>
48
49 extern cpu_sgnblk_t *cpu_sgnblkp[];
50
51 /* Preallocation of spare tsb's for DR - none for now */
52 int starfire_tsb_spares = STARFIRE_MAX_BOARDS << 1;
53
54 /* Set the maximum number of boards... for DR */
55 int starfire_boards = STARFIRE_MAX_BOARDS;
56
57 /* Maximum number of cpus per board... for DR */
58 int starfire_cpu_per_board = 4;
59
60 /* Maximum number of mem-units per board... for DR */
61 int starfire_mem_per_board = 1;
62
63 /* Maximum number of io-units (buses) per board... for DR */
64 int starfire_io_per_board = 2;
65
66 /* Preferred minimum cage size (expressed in pages)... for DR */
67 pgcnt_t starfire_startup_cage_size = 0;
68
69 void sgn_update_all_cpus(ushort_t, uchar_t, uchar_t);
70
71 int
set_platform_max_ncpus(void)72 set_platform_max_ncpus(void)
73 {
74 starfire_boards = MIN(starfire_boards, STARFIRE_MAX_BOARDS);
75
76 if (starfire_boards < 1)
77 starfire_boards = 1;
78
79 return (starfire_boards * starfire_cpu_per_board);
80 }
81
82 void
startup_platform(void)83 startup_platform(void)
84 {
85 }
86
87 int
set_platform_tsb_spares()88 set_platform_tsb_spares()
89 {
90 return (MIN(starfire_tsb_spares, MAX_UPA));
91 }
92
93 void
set_platform_defaults(void)94 set_platform_defaults(void)
95 {
96 extern char *tod_module_name;
97 extern int ts_dispatch_extended;
98 extern void cpu_sgn_update(ushort_t, uchar_t, uchar_t, int);
99
100 uint32_t revlevel;
101 char buf[20];
102
103 #ifdef DEBUG
104 ce_verbose_memory = 2;
105 ce_verbose_other = 2;
106 #endif
107
108 /*
109 * Check to see if we have the right firmware
110 * We simply do a prom_test to see if
111 * "SUNW,UE10000-prom-version" interface exist.
112 */
113 if (prom_test("SUNW,UE10000-prom-version") != 0) {
114 halt("Firmware upgrade is required to boot this OS!");
115 } else {
116 /*
117 * Versions 5 to 50 and 150 or above can support this OS
118 */
119 (void) sprintf(buf, "cpu-prom-version swap l!");
120 prom_interpret(buf, (uintptr_t)&revlevel, 0, 0, 0, 0);
121 if ((revlevel < 5) || ((revlevel > 50) && (revlevel < 150)))
122 halt("Firmware upgrade is required to boot this OS!");
123 }
124
125 /* Set the CPU signature function pointer */
126 cpu_sgn_func = cpu_sgn_update;
127
128 /* Set appropriate tod module for starfire */
129 ASSERT(tod_module_name == NULL);
130 tod_module_name = "todstarfire";
131
132 /*
133 * Use the alternate TS dispatch table, which is better
134 * tuned for large servers.
135 */
136 if (ts_dispatch_extended == -1) /* use platform default */
137 ts_dispatch_extended = 1;
138 }
139
140 #ifdef DEBUG
141 pgcnt_t starfire_cage_size_limit;
142 #endif
143
144 void
set_platform_cage_params(void)145 set_platform_cage_params(void)
146 {
147 extern pgcnt_t total_pages;
148 extern struct memlist *phys_avail;
149
150 if (kernel_cage_enable) {
151 pgcnt_t preferred_cage_size;
152
153 preferred_cage_size =
154 MAX(starfire_startup_cage_size, total_pages / 256);
155
156 #ifdef DEBUG
157 if (starfire_cage_size_limit)
158 preferred_cage_size = starfire_cage_size_limit;
159 #endif
160 /*
161 * Note: we are assuming that post has load the
162 * whole show in to the high end of memory. Having
163 * taken this leap, we copy the whole of phys_avail
164 * the glist and arrange for the cage to grow
165 * downward (descending pfns).
166 */
167 kcage_range_init(phys_avail, KCAGE_DOWN, preferred_cage_size);
168 }
169
170 if (kcage_on)
171 cmn_err(CE_NOTE, "!DR Kernel Cage is ENABLED");
172 else
173 cmn_err(CE_NOTE, "!DR Kernel Cage is DISABLED");
174 }
175
176 void
load_platform_drivers(void)177 load_platform_drivers(void)
178 {
179 /* load the NGDR driver */
180 if (i_ddi_attach_pseudo_node("ngdr") == NULL) {
181 cmn_err(CE_WARN, "ngdr failed to load");
182 }
183 }
184
185 /*
186 * Starfire does not support power control of CPUs from the OS.
187 */
188 /*ARGSUSED*/
189 int
plat_cpu_poweron(struct cpu * cp)190 plat_cpu_poweron(struct cpu *cp)
191 {
192 int (*starfire_cpu_poweron)(struct cpu *) = NULL;
193
194 starfire_cpu_poweron =
195 (int (*)(struct cpu *))kobj_getsymvalue("drmach_cpu_poweron", 0);
196
197 if (starfire_cpu_poweron == NULL)
198 return (ENOTSUP);
199 else
200 return ((starfire_cpu_poweron)(cp));
201 }
202
203 /*ARGSUSED*/
204 int
plat_cpu_poweroff(struct cpu * cp)205 plat_cpu_poweroff(struct cpu *cp)
206 {
207 int (*starfire_cpu_poweroff)(struct cpu *) = NULL;
208
209 starfire_cpu_poweroff =
210 (int (*)(struct cpu *))kobj_getsymvalue("drmach_cpu_poweroff", 0);
211
212 if (starfire_cpu_poweroff == NULL)
213 return (ENOTSUP);
214 else
215 return ((starfire_cpu_poweroff)(cp));
216 }
217
218 void
plat_dmv_params(uint_t * hwint,uint_t * swint)219 plat_dmv_params(uint_t *hwint, uint_t *swint)
220 {
221 *hwint = STARFIRE_DMV_HWINT;
222 *swint = 0;
223 }
224
225 /*
226 * The following our currently private to Starfire DR
227 */
228 int
plat_max_boards()229 plat_max_boards()
230 {
231 return (starfire_boards);
232 }
233
234 int
plat_max_cpu_units_per_board()235 plat_max_cpu_units_per_board()
236 {
237 return (starfire_cpu_per_board);
238 }
239
240 int
plat_max_mem_units_per_board()241 plat_max_mem_units_per_board()
242 {
243 return (starfire_mem_per_board);
244 }
245
246 int
plat_max_io_units_per_board()247 plat_max_io_units_per_board()
248 {
249 return (starfire_io_per_board);
250 }
251
252
253 /*
254 * This index is used to associate a given pfn to a place on the freelist.
255 * This results in dispersing pfn assignment over all the boards in the
256 * system.
257 * Choose the index randomly to prevent clustering pages of different
258 * colors on the same board.
259 */
260 static uint_t random_idx(int ubound);
261
262 #define PFN_2_LBN(pfn) (((pfn) >> (STARFIRE_MC_MEMBOARD_SHIFT - PAGESHIFT)) % \
263 STARFIRE_MAX_BOARDS)
264
265 void
plat_freelist_process(int mnode)266 plat_freelist_process(int mnode)
267 {
268 page_t *page, **freelist;
269 page_t *bdlist[STARFIRE_MAX_BOARDS];
270 page_t **sortlist[STARFIRE_MAX_BOARDS];
271 uint32_t idx, idy, size, color, max_color, lbn;
272 uint32_t bd_flags, bd_cnt, result, bds;
273 kmutex_t *pcm;
274 int mtype;
275
276 /* for each page size */
277 for (mtype = 0; mtype < MAX_MEM_TYPES; mtype++) {
278 for (size = 0; size < mmu_page_sizes; size++) {
279
280 /*
281 * Compute the maximum # of phys colors based on
282 * page size.
283 */
284 max_color = page_get_pagecolors(size);
285
286 /* for each color */
287 for (color = 0; color < max_color; color++) {
288
289 bd_cnt = 0;
290 bd_flags = 0;
291 for (idx = 0; idx < STARFIRE_MAX_BOARDS;
292 idx++) {
293 bdlist[idx] = NULL;
294 sortlist[idx] = NULL;
295 }
296
297 /* find freelist */
298 freelist = &PAGE_FREELISTS(mnode, size,
299 color, mtype);
300
301 if (*freelist == NULL)
302 continue;
303
304 /* acquire locks */
305 pcm = PC_BIN_MUTEX(mnode, color, PG_FREE_LIST);
306 mutex_enter(pcm);
307
308 /*
309 * read freelist & sort pages by logical
310 * board number
311 */
312 /* grab pages till last one. */
313 while (*freelist) {
314 page = *freelist;
315 result = page_trylock(page, SE_EXCL);
316
317 ASSERT(result);
318
319 /* Delete from freelist */
320 if (size != 0) {
321 page_vpsub(freelist, page);
322 } else {
323 mach_page_sub(freelist, page);
324 }
325
326 /* detect the lbn */
327 lbn = PFN_2_LBN(page->p_pagenum);
328
329 /* add to bdlist[lbn] */
330 if (size != 0) {
331 page_vpadd(&bdlist[lbn], page);
332 } else {
333 mach_page_add(&bdlist[lbn],
334 page);
335 }
336
337 /* if lbn new */
338 if ((bd_flags & (1 << lbn)) == 0) {
339 bd_flags |= (1 << lbn);
340 bd_cnt++;
341 }
342 page_unlock(page);
343 }
344
345 /*
346 * Make the sortlist so
347 * bd_cnt choices show up
348 */
349 bds = 0;
350 for (idx = 0; idx < STARFIRE_MAX_BOARDS;
351 idx++) {
352 if (bdlist[idx])
353 sortlist[bds++] = &bdlist[idx];
354 }
355
356 /*
357 * Set random start.
358 */
359 (void) random_idx(-color);
360
361 /*
362 * now rebuild the freelist by shuffling
363 * pages from bd lists
364 */
365 while (bd_cnt) {
366
367 /*
368 * get "random" index between 0 &
369 * bd_cnt
370 */
371
372 ASSERT(bd_cnt &&
373 (bd_cnt < STARFIRE_MAX_BOARDS+1));
374
375 idx = random_idx(bd_cnt);
376
377 page = *sortlist[idx];
378 result = page_trylock(page, SE_EXCL);
379
380 ASSERT(result);
381
382 /* Delete from sort_list */
383 /* & Append to freelist */
384 /* Big pages use vp_add - 8k don't */
385 if (size != 0) {
386 page_vpsub(sortlist[idx], page);
387 page_vpadd(freelist, page);
388 } else {
389 mach_page_sub(sortlist[idx],
390 page);
391 mach_page_add(freelist, page);
392 }
393
394 /* needed for indexing tmp lists */
395 lbn = PFN_2_LBN(page->p_pagenum);
396
397 /*
398 * if this was the last page on this
399 * list?
400 */
401 if (*sortlist[idx] == NULL) {
402
403 /* have to find brd list */
404
405 /* idx is lbn? -- No! */
406 /* sortlist, brdlist */
407 /* have diff indexs */
408 bd_flags &= ~(1 << lbn);
409 --bd_cnt;
410
411 /*
412 * redo the sortlist so only
413 * bd_cnt choices show up
414 */
415 bds = 0;
416 for (idy = 0;
417 idy < STARFIRE_MAX_BOARDS;
418 idy++) {
419 if (bdlist[idy]) {
420 sortlist[bds++]
421 /* CSTYLED */
422 = &bdlist[idy];
423 }
424 }
425 }
426 page_unlock(page);
427 }
428 mutex_exit(pcm);
429 }
430 }
431 }
432 }
433
434 /*
435 * If ubound > 0, will return an int between 0 & ubound
436 * If ubound < 0, will set "random seed"
437 */
438 static uint_t
random_idx(int ubound)439 random_idx(int ubound)
440 {
441 static int idx = 0;
442
443 if (ubound > 0) {
444 idx = (idx + 1) % ubound;
445 return (idx);
446 }
447 idx = -ubound;
448 return (0);
449 }
450
451 /*
452 * No platform drivers on this platform
453 */
454 char *platform_module_list[] = {
455 (char *)0
456 };
457
458 /*ARGSUSED*/
459 void
plat_tod_fault(enum tod_fault_type tod_bad)460 plat_tod_fault(enum tod_fault_type tod_bad)
461 {
462 }
463
464 /*
465 * Update signature block and the signature ring buffer of a given cpu_id.
466 */
467 void
cpu_sgn_update(ushort_t sgn,uchar_t state,uchar_t sub_state,int cpuid)468 cpu_sgn_update(ushort_t sgn, uchar_t state, uchar_t sub_state, int cpuid)
469 {
470 uchar_t idx;
471 cpu_sgnblk_t *cpu_sgnblkptr;
472
473 /*
474 * cpuid == -1 indicates that the operation applies to all cpus.
475 */
476 if (cpuid < 0) {
477 sgn_update_all_cpus(sgn, state, sub_state);
478 return;
479 }
480
481 if (cpu_sgnblkp[cpuid] == NULL)
482 return;
483
484 cpu_sgnblkptr = cpu_sgnblkp[cpuid];
485
486 /*
487 * Map new generic cpu states to older Starfire states.
488 */
489 switch (state) {
490 case SIGST_OFFLINE:
491 state = SIGBST_OFFLINE;
492 break;
493 case SIGST_RESUME_INPROGRESS:
494 state = SIGBST_RESUME_INPROGRESS;
495 break;
496 case SIGST_QUIESCE_INPROGRESS:
497 state = SIGBST_QUIESCE_INPROGRESS;
498 break;
499 case SIGST_QUIESCED:
500 state = SIGBST_QUIESCED;
501 break;
502 case SIGST_EXIT:
503 switch (sub_state) {
504 case SIGSUBST_DEBUG:
505 state = SIGBST_RUN;
506 sub_state = EXIT_NULL;
507 break;
508 case SIGSUBST_PANIC_CONT:
509 state = SIGBST_RUN;
510 sub_state = EXIT_PANIC2;
511 break;
512 case SIGSUBST_DUMP:
513 state = SIGBST_EXIT;
514 sub_state = EXIT_PANIC2;
515 break;
516 default:
517 break;
518 }
519 break;
520 default:
521 break;
522 }
523
524 cpu_sgnblkptr->sigb_signature.state_t.sig = sgn;
525 cpu_sgnblkptr->sigb_signature.state_t.state = state;
526 cpu_sgnblkptr->sigb_signature.state_t.sub_state = sub_state;
527
528 /* Update the ring buffer */
529 idx = cpu_sgnblkptr->sigb_ringbuf.wr_ptr;
530 cpu_sgnblkptr->sigb_ringbuf.ringbuf[idx].state_t.sig = sgn;
531 cpu_sgnblkptr->sigb_ringbuf.ringbuf[idx].state_t.state = state;
532 cpu_sgnblkptr->sigb_ringbuf.ringbuf[idx].state_t.sub_state = sub_state;
533 cpu_sgnblkptr->sigb_ringbuf.wr_ptr += 1;
534 cpu_sgnblkptr->sigb_ringbuf.wr_ptr &= RB_IDX_MASK;
535 }
536
537 /*
538 * Update signature block and the signature ring buffer of all CPUs.
539 */
540 void
sgn_update_all_cpus(ushort_t sgn,uchar_t state,uchar_t sub_state)541 sgn_update_all_cpus(ushort_t sgn, uchar_t state, uchar_t sub_state)
542 {
543 int i = 0;
544 uchar_t cpu_state;
545 uchar_t cpu_sub_state;
546
547 for (i = 0; i < NCPU; i++) {
548 cpu_sgnblk_t *sblkp;
549
550 sblkp = cpu_sgnblkp[i];
551 cpu_sub_state = sub_state;
552
553 if ((sblkp != NULL) && (cpu[i] != NULL && (cpu[i]->cpu_flags &
554 (CPU_EXISTS|CPU_QUIESCED)))) {
555
556 if (sub_state == EXIT_REBOOT) {
557 cpu_sub_state =
558 sblkp->sigb_signature.state_t.sub_state;
559
560 if ((cpu_sub_state == EXIT_PANIC1) ||
561 (cpu_sub_state == EXIT_PANIC2))
562 cpu_sub_state = EXIT_PANIC_REBOOT;
563 else
564 cpu_sub_state = EXIT_REBOOT;
565 }
566
567 /*
568 * If we get here from an OBP sync after watchdog,
569 * we need to retain the watchdog sync state so that
570 * hostmon knows what's going on. So if we're in
571 * watchdog we don't update the state.
572 */
573
574 cpu_state = sblkp->sigb_signature.state_t.state;
575 if (cpu_state == SIGBST_WATCHDOG_SYNC)
576 cpu_sgn_update(sgn, SIGBST_WATCHDOG_SYNC,
577 cpu_sub_state, i);
578 else if (cpu_state == SIGBST_REDMODE_SYNC)
579 cpu_sgn_update(sgn, SIGBST_REDMODE_SYNC,
580 cpu_sub_state, i);
581 else
582 cpu_sgn_update(sgn, state, cpu_sub_state, i);
583 }
584 }
585 }
586
587 int
cpu_sgn_exists(int cpuid)588 cpu_sgn_exists(int cpuid)
589 {
590 return (cpu_sgnblkp[cpuid] != NULL);
591 }
592
593 ushort_t
get_cpu_sgn(int cpuid)594 get_cpu_sgn(int cpuid)
595 {
596 if (cpu_sgnblkp[cpuid] == NULL)
597 return ((ushort_t)-1);
598
599 return (cpu_sgnblkp[cpuid]->sigb_signature.state_t.sig);
600 }
601
602 uchar_t
get_cpu_sgn_state(int cpuid)603 get_cpu_sgn_state(int cpuid)
604 {
605 if (cpu_sgnblkp[cpuid] == NULL)
606 return ((uchar_t)-1);
607
608 return (cpu_sgnblkp[cpuid]->sigb_signature.state_t.state);
609 }
610
611 /*
612 * KDI functions - used by the in-situ kernel debugger (kmdb) to perform
613 * platform-specific operations. These functions execute when the world is
614 * stopped, and as such cannot make any blocking calls, hold locks, etc.
615 * promif functions are a special case, and may be used.
616 */
617
618 static void
starfire_system_claim(void)619 starfire_system_claim(void)
620 {
621 lbolt_debug_entry();
622
623 prom_interpret("sigb-sig! my-sigb-sig!", OBP_SIG, OBP_SIG, 0, 0, 0);
624 }
625
626 static void
starfire_system_release(void)627 starfire_system_release(void)
628 {
629 prom_interpret("sigb-sig! my-sigb-sig!", OS_SIG, OS_SIG, 0, 0, 0);
630
631 lbolt_debug_return();
632 }
633
634 void
plat_kdi_init(kdi_t * kdi)635 plat_kdi_init(kdi_t *kdi)
636 {
637 kdi->pkdi_system_claim = starfire_system_claim;
638 kdi->pkdi_system_release = starfire_system_release;
639 }
640