xref: /titanic_50/usr/src/uts/sun4u/starfire/os/starfire.c (revision 694c35faa87b858ecdadfe4fc592615f4eefbb07)
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
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
83 startup_platform(void)
84 {
85 }
86 
87 int
88 set_platform_tsb_spares()
89 {
90 	return (MIN(starfire_tsb_spares, MAX_UPA));
91 }
92 
93 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
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
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
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
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
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
229 plat_max_boards()
230 {
231 	return (starfire_boards);
232 }
233 
234 int
235 plat_max_cpu_units_per_board()
236 {
237 	return (starfire_cpu_per_board);
238 }
239 
240 int
241 plat_max_mem_units_per_board()
242 {
243 	return (starfire_mem_per_board);
244 }
245 
246 int
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
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
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
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
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
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
588 cpu_sgn_exists(int cpuid)
589 {
590 	return (cpu_sgnblkp[cpuid] != NULL);
591 }
592 
593 ushort_t
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
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
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
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
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