xref: /titanic_44/usr/src/uts/sun4u/starfire/os/starfire.c (revision 2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1f)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/sysmacros.h>
31 #include <sys/sunddi.h>
32 #include <sys/modctl.h>
33 #include <sys/promif.h>
34 #include <sys/machparam.h>
35 #include <sys/kobj.h>
36 #include <sys/mem_cage.h>
37 #include <sys/starfire.h>
38 
39 #include <sys/platform_module.h>
40 #include <sys/errno.h>
41 #include <vm/page.h>
42 #include <vm/hat_sfmmu.h>
43 #include <sys/memnode.h>
44 #include <vm/vm_dep.h>
45 #include <sys/cpu_sgnblk_defs.h>
46 #include <sys/cpu_sgn.h>
47 #include <sys/kdi_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 		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 								= &bdlist[idy];
422 							}
423 						}
424 					}
425 					page_unlock(page);
426 				}
427 				mutex_exit(pcm);
428 			}
429 		}
430 	}
431 }
432 
433 /*
434  * If ubound > 0, will return an int between 0 & ubound
435  * If ubound < 0, will set "random seed"
436  */
437 static uint_t
438 random_idx(int ubound)
439 {
440 	static int idx = 0;
441 
442 	if (ubound > 0) {
443 		idx = (idx + 1) % ubound;
444 		return (idx);
445 	}
446 	idx = -ubound;
447 	return (0);
448 }
449 
450 /*
451  * No platform drivers on this platform
452  */
453 char *platform_module_list[] = {
454 	(char *)0
455 };
456 
457 /*ARGSUSED*/
458 void
459 plat_tod_fault(enum tod_fault_type tod_bad)
460 {
461 }
462 
463 /*
464  * Update signature block and the signature ring buffer of a given cpu_id.
465  */
466 void
467 cpu_sgn_update(ushort_t sgn, uchar_t state, uchar_t sub_state, int cpuid)
468 {
469 	uchar_t idx;
470 	cpu_sgnblk_t *cpu_sgnblkptr;
471 
472 	/*
473 	 * cpuid == -1 indicates that the operation applies to all cpus.
474 	 */
475 	if (cpuid < 0) {
476 		sgn_update_all_cpus(sgn, state, sub_state);
477 		return;
478 	}
479 
480 	if (cpu_sgnblkp[cpuid] == NULL)
481 		return;
482 
483 	cpu_sgnblkptr = cpu_sgnblkp[cpuid];
484 
485 	/*
486 	 *  Map new generic cpu states to older Starfire states.
487 	 */
488 	switch (state) {
489 	case SIGST_OFFLINE:
490 		state = SIGBST_OFFLINE;
491 		break;
492 	case SIGST_RESUME_INPROGRESS:
493 		state = SIGBST_RESUME_INPROGRESS;
494 		break;
495 	case SIGST_QUIESCE_INPROGRESS:
496 		state = SIGBST_QUIESCE_INPROGRESS;
497 		break;
498 	case SIGST_QUIESCED:
499 		state = SIGBST_QUIESCED;
500 		break;
501 	case SIGST_EXIT:
502 		switch (sub_state) {
503 		case SIGSUBST_DEBUG:
504 			state = SIGBST_RUN;
505 			sub_state = EXIT_NULL;
506 			break;
507 		case SIGSUBST_PANIC_CONT:
508 			state = SIGBST_RUN;
509 			sub_state = EXIT_PANIC2;
510 			break;
511 		case SIGSUBST_DUMP:
512 			state = SIGBST_EXIT;
513 			sub_state = EXIT_PANIC2;
514 			break;
515 		default:
516 			break;
517 		}
518 		break;
519 	default:
520 		break;
521 	}
522 
523 	cpu_sgnblkptr->sigb_signature.state_t.sig = sgn;
524 	cpu_sgnblkptr->sigb_signature.state_t.state = state;
525 	cpu_sgnblkptr->sigb_signature.state_t.sub_state = sub_state;
526 
527 	/* Update the ring buffer */
528 	idx = cpu_sgnblkptr->sigb_ringbuf.wr_ptr;
529 	cpu_sgnblkptr->sigb_ringbuf.ringbuf[idx].state_t.sig = sgn;
530 	cpu_sgnblkptr->sigb_ringbuf.ringbuf[idx].state_t.state = state;
531 	cpu_sgnblkptr->sigb_ringbuf.ringbuf[idx].state_t.sub_state = sub_state;
532 	cpu_sgnblkptr->sigb_ringbuf.wr_ptr += 1;
533 	cpu_sgnblkptr->sigb_ringbuf.wr_ptr &= RB_IDX_MASK;
534 }
535 
536 /*
537  * Update signature block and the signature ring buffer of all CPUs.
538  */
539 void
540 sgn_update_all_cpus(ushort_t sgn, uchar_t state, uchar_t sub_state)
541 {
542 	int i = 0;
543 	uchar_t cpu_state;
544 	uchar_t cpu_sub_state;
545 
546 	for (i = 0; i < NCPU; i++) {
547 		cpu_sgnblk_t *sblkp;
548 
549 		sblkp = cpu_sgnblkp[i];
550 		cpu_sub_state = sub_state;
551 
552 		if ((sblkp != NULL) && (cpu[i] != NULL && (cpu[i]->cpu_flags &
553 				(CPU_EXISTS|CPU_QUIESCED)))) {
554 
555 			if (sub_state == EXIT_REBOOT) {
556 				cpu_sub_state =
557 					sblkp->sigb_signature.state_t.sub_state;
558 
559 				if ((cpu_sub_state == EXIT_PANIC1) ||
560 					(cpu_sub_state == EXIT_PANIC2))
561 					cpu_sub_state = EXIT_PANIC_REBOOT;
562 				else
563 					cpu_sub_state = EXIT_REBOOT;
564 			}
565 
566 			/*
567 			 * If we get here from an OBP sync after watchdog,
568 			 * we need to retain the watchdog sync state so that
569 			 * hostmon knows what's going on.  So if we're in
570 			 * watchdog we don't update the state.
571 			 */
572 
573 			cpu_state = sblkp->sigb_signature.state_t.state;
574 			if (cpu_state == SIGBST_WATCHDOG_SYNC)
575 				cpu_sgn_update(sgn, SIGBST_WATCHDOG_SYNC,
576 					cpu_sub_state, i);
577 			else if (cpu_state == SIGBST_REDMODE_SYNC)
578 				cpu_sgn_update(sgn, SIGBST_REDMODE_SYNC,
579 					cpu_sub_state, i);
580 			else
581 				cpu_sgn_update(sgn, state, cpu_sub_state, i);
582 		}
583 	}
584 }
585 
586 int
587 cpu_sgn_exists(int cpuid)
588 {
589 	return (cpu_sgnblkp[cpuid] != NULL);
590 }
591 
592 ushort_t
593 get_cpu_sgn(int cpuid)
594 {
595 	if (cpu_sgnblkp[cpuid] == NULL)
596 		return ((ushort_t)-1);
597 
598 	return (cpu_sgnblkp[cpuid]->sigb_signature.state_t.sig);
599 }
600 
601 uchar_t
602 get_cpu_sgn_state(int cpuid)
603 {
604 	if (cpu_sgnblkp[cpuid] == NULL)
605 		return ((uchar_t)-1);
606 
607 	return (cpu_sgnblkp[cpuid]->sigb_signature.state_t.state);
608 }
609 
610 /*
611  * KDI functions - used by the in-situ kernel debugger (kmdb) to perform
612  * platform-specific operations.  These functions execute when the world is
613  * stopped, and as such cannot make any blocking calls, hold locks, etc.
614  * promif functions are a special case, and may be used.
615  */
616 
617 static void
618 starfire_system_claim(void)
619 {
620 	prom_interpret("sigb-sig! my-sigb-sig!", OBP_SIG, OBP_SIG, 0, 0, 0);
621 }
622 
623 static void
624 starfire_system_release(void)
625 {
626 	prom_interpret("sigb-sig! my-sigb-sig!", OS_SIG, OS_SIG, 0, 0, 0);
627 }
628 
629 void
630 plat_kdi_init(kdi_t *kdi)
631 {
632 	kdi->pkdi_system_claim = starfire_system_claim;
633 	kdi->pkdi_system_release = starfire_system_release;
634 }
635