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