xref: /titanic_44/usr/src/uts/sun4u/starfire/os/starfire.c (revision 8de5c4f463386063e184a851437d58080c6c626c)
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 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/param.h>
27 #include <sys/systm.h>
28 #include <sys/sysmacros.h>
29 #include <sys/sunddi.h>
30 #include <sys/modctl.h>
31 #include <sys/promif.h>
32 #include <sys/machparam.h>
33 #include <sys/kobj.h>
34 #include <sys/mem_cage.h>
35 #include <sys/starfire.h>
36 
37 #include <sys/platform_module.h>
38 #include <sys/errno.h>
39 #include <vm/page.h>
40 #include <vm/hat_sfmmu.h>
41 #include <sys/memnode.h>
42 #include <vm/vm_dep.h>
43 #include <sys/cpu_sgnblk_defs.h>
44 #include <sys/cpu_sgn.h>
45 #include <sys/kdi_impl.h>
46 #include <sys/clock_impl.h>
47 
48 extern cpu_sgnblk_t *cpu_sgnblkp[];
49 
50 /* Preallocation of spare tsb's for DR - none for now */
51 int starfire_tsb_spares = STARFIRE_MAX_BOARDS << 1;
52 
53 /* Set the maximum number of boards... for DR */
54 int starfire_boards = STARFIRE_MAX_BOARDS;
55 
56 /* Maximum number of cpus per board... for DR */
57 int starfire_cpu_per_board = 4;
58 
59 /* Maximum number of mem-units per board... for DR */
60 int starfire_mem_per_board = 1;
61 
62 /* Maximum number of io-units (buses) per board... for DR */
63 int starfire_io_per_board = 2;
64 
65 /* Preferred minimum cage size (expressed in pages)... for DR */
66 pgcnt_t starfire_startup_cage_size = 0;
67 
68 void sgn_update_all_cpus(ushort_t, uchar_t, uchar_t);
69 
70 int
71 set_platform_max_ncpus(void)
72 {
73 	starfire_boards = MIN(starfire_boards, STARFIRE_MAX_BOARDS);
74 
75 	if (starfire_boards < 1)
76 		starfire_boards = 1;
77 
78 	return (starfire_boards * starfire_cpu_per_board);
79 }
80 
81 void
82 startup_platform(void)
83 {
84 }
85 
86 int
87 set_platform_tsb_spares()
88 {
89 	return (MIN(starfire_tsb_spares, MAX_UPA));
90 }
91 
92 void
93 set_platform_defaults(void)
94 {
95 	extern char *tod_module_name;
96 	extern int ts_dispatch_extended;
97 	extern void cpu_sgn_update(ushort_t, uchar_t, uchar_t, int);
98 
99 	uint32_t	revlevel;
100 	char		buf[20];
101 
102 #ifdef DEBUG
103 	ce_verbose_memory = 2;
104 	ce_verbose_other = 2;
105 #endif
106 
107 	/*
108 	 * Check to see if we have the right firmware
109 	 * We simply do a prom_test to see if
110 	 * "SUNW,UE10000-prom-version" interface exist.
111 	 */
112 	if (prom_test("SUNW,UE10000-prom-version") != 0) {
113 		halt("Firmware upgrade is required to boot this OS!");
114 	} else {
115 		/*
116 		 * Versions 5 to 50 and 150 or above  can support this OS
117 		 */
118 		sprintf(buf, "cpu-prom-version swap l!");
119 		prom_interpret(buf, (uintptr_t)&revlevel, 0, 0, 0, 0);
120 		if ((revlevel < 5) || ((revlevel > 50) && (revlevel < 150)))
121 			halt("Firmware upgrade is required to boot this OS!");
122 	}
123 
124 	/* Set the CPU signature function pointer */
125 	cpu_sgn_func = cpu_sgn_update;
126 
127 	/* Set appropriate tod module for starfire */
128 	ASSERT(tod_module_name == NULL);
129 	tod_module_name = "todstarfire";
130 
131 	/*
132 	 * Use the alternate TS dispatch table, which is better
133 	 * tuned for large servers.
134 	 */
135 	if (ts_dispatch_extended == -1) /* use platform default */
136 		ts_dispatch_extended = 1;
137 }
138 
139 #ifdef DEBUG
140 pgcnt_t starfire_cage_size_limit;
141 #endif
142 
143 void
144 set_platform_cage_params(void)
145 {
146 	extern pgcnt_t total_pages;
147 	extern struct memlist *phys_avail;
148 
149 	if (kernel_cage_enable) {
150 		pgcnt_t preferred_cage_size;
151 
152 		preferred_cage_size =
153 		    MAX(starfire_startup_cage_size, total_pages / 256);
154 
155 #ifdef DEBUG
156 		if (starfire_cage_size_limit)
157 			preferred_cage_size = starfire_cage_size_limit;
158 #endif
159 		/*
160 		 * Note: we are assuming that post has load the
161 		 * whole show in to the high end of memory. Having
162 		 * taken this leap, we copy the whole of phys_avail
163 		 * the glist and arrange for the cage to grow
164 		 * downward (descending pfns).
165 		 */
166 		kcage_range_init(phys_avail, KCAGE_DOWN, preferred_cage_size);
167 	}
168 
169 	if (kcage_on)
170 		cmn_err(CE_NOTE, "!DR Kernel Cage is ENABLED");
171 	else
172 		cmn_err(CE_NOTE, "!DR Kernel Cage is DISABLED");
173 }
174 
175 void
176 load_platform_drivers(void)
177 {
178 	/* load the NGDR driver */
179 	if (i_ddi_attach_pseudo_node("ngdr") == NULL) {
180 		cmn_err(CE_WARN, "ngdr failed to load");
181 	}
182 }
183 
184 /*
185  * Starfire does not support power control of CPUs from the OS.
186  */
187 /*ARGSUSED*/
188 int
189 plat_cpu_poweron(struct cpu *cp)
190 {
191 	int (*starfire_cpu_poweron)(struct cpu *) = NULL;
192 
193 	starfire_cpu_poweron =
194 	    (int (*)(struct cpu *))kobj_getsymvalue("drmach_cpu_poweron", 0);
195 
196 	if (starfire_cpu_poweron == NULL)
197 		return (ENOTSUP);
198 	else
199 		return ((starfire_cpu_poweron)(cp));
200 }
201 
202 /*ARGSUSED*/
203 int
204 plat_cpu_poweroff(struct cpu *cp)
205 {
206 	int (*starfire_cpu_poweroff)(struct cpu *) = NULL;
207 
208 	starfire_cpu_poweroff =
209 	    (int (*)(struct cpu *))kobj_getsymvalue("drmach_cpu_poweroff", 0);
210 
211 	if (starfire_cpu_poweroff == NULL)
212 		return (ENOTSUP);
213 	else
214 		return ((starfire_cpu_poweroff)(cp));
215 }
216 
217 void
218 plat_dmv_params(uint_t *hwint, uint_t *swint)
219 {
220 	*hwint = STARFIRE_DMV_HWINT;
221 	*swint = 0;
222 }
223 
224 /*
225  * The following our currently private to Starfire DR
226  */
227 int
228 plat_max_boards()
229 {
230 	return (starfire_boards);
231 }
232 
233 int
234 plat_max_cpu_units_per_board()
235 {
236 	return (starfire_cpu_per_board);
237 }
238 
239 int
240 plat_max_mem_units_per_board()
241 {
242 	return (starfire_mem_per_board);
243 }
244 
245 int
246 plat_max_io_units_per_board()
247 {
248 	return (starfire_io_per_board);
249 }
250 
251 
252 /*
253  * This index is used to associate a given pfn to a place on the freelist.
254  * This results in dispersing pfn assignment over all the boards in the
255  * system.
256  * Choose the index randomly to prevent clustering pages of different
257  * colors on the same board.
258  */
259 static uint_t random_idx(int ubound);
260 
261 #define	PFN_2_LBN(pfn)	(((pfn) >> (STARFIRE_MC_MEMBOARD_SHIFT - PAGESHIFT)) % \
262 			STARFIRE_MAX_BOARDS)
263 
264 void
265 plat_freelist_process(int mnode)
266 {
267 	page_t		*page, **freelist;
268 	page_t		*bdlist[STARFIRE_MAX_BOARDS];
269 	page_t		 **sortlist[STARFIRE_MAX_BOARDS];
270 	uint32_t	idx, idy, size, color, max_color, lbn;
271 	uint32_t	bd_flags, bd_cnt, result, bds;
272 	kmutex_t	*pcm;
273 	int 		mtype;
274 
275 	/* for each page size */
276 	for (mtype = 0; mtype < MAX_MEM_TYPES; mtype++) {
277 		for (size = 0; size < mmu_page_sizes; size++) {
278 
279 			/*
280 			 * Compute the maximum # of phys colors based on
281 			 * page size.
282 			 */
283 			max_color = page_get_pagecolors(size);
284 
285 			/* for each color */
286 			for (color = 0; color < max_color; color++) {
287 
288 				bd_cnt = 0;
289 				bd_flags = 0;
290 				for (idx = 0; idx < STARFIRE_MAX_BOARDS;
291 				    idx++) {
292 					bdlist[idx] = NULL;
293 					sortlist[idx] = NULL;
294 				}
295 
296 				/* find freelist */
297 				freelist = &PAGE_FREELISTS(mnode, size,
298 				    color, mtype);
299 
300 				if (*freelist == NULL)
301 					continue;
302 
303 				/* acquire locks */
304 				pcm = PC_BIN_MUTEX(mnode, color, PG_FREE_LIST);
305 				mutex_enter(pcm);
306 
307 				/*
308 				 * read freelist & sort pages by logical
309 				 * board number
310 				 */
311 				/* grab pages till last one. */
312 				while (*freelist) {
313 					page = *freelist;
314 					result = page_trylock(page, SE_EXCL);
315 
316 					ASSERT(result);
317 
318 					/* Delete from freelist */
319 					if (size != 0) {
320 						page_vpsub(freelist, page);
321 					} else {
322 						mach_page_sub(freelist, page);
323 					}
324 
325 					/* detect the lbn */
326 					lbn = PFN_2_LBN(page->p_pagenum);
327 
328 					/* add to bdlist[lbn] */
329 					if (size != 0) {
330 						page_vpadd(&bdlist[lbn], page);
331 					} else {
332 						mach_page_add(&bdlist[lbn],
333 						    page);
334 					}
335 
336 					/* if lbn new */
337 					if ((bd_flags & (1 << lbn)) == 0) {
338 						bd_flags |= (1 << lbn);
339 						bd_cnt++;
340 					}
341 					page_unlock(page);
342 				}
343 
344 				/*
345 				 * Make the sortlist so
346 				 * bd_cnt choices show up
347 				 */
348 				bds = 0;
349 				for (idx = 0; idx < STARFIRE_MAX_BOARDS;
350 				    idx++) {
351 					if (bdlist[idx])
352 						sortlist[bds++] = &bdlist[idx];
353 				}
354 
355 				/*
356 				 * Set random start.
357 				 */
358 				(void) random_idx(-color);
359 
360 				/*
361 				 * now rebuild the freelist by shuffling
362 				 * pages from bd lists
363 				 */
364 				while (bd_cnt) {
365 
366 					/*
367 					 * get "random" index between 0 &
368 					 * bd_cnt
369 					 */
370 
371 					ASSERT(bd_cnt &&
372 					    (bd_cnt < STARFIRE_MAX_BOARDS+1));
373 
374 					idx = random_idx(bd_cnt);
375 
376 					page = *sortlist[idx];
377 					result = page_trylock(page, SE_EXCL);
378 
379 					ASSERT(result);
380 
381 					/* Delete from sort_list */
382 					/*  & Append to freelist */
383 					/* Big pages use vp_add - 8k don't */
384 					if (size != 0) {
385 						page_vpsub(sortlist[idx], page);
386 						page_vpadd(freelist, page);
387 					} else {
388 						mach_page_sub(sortlist[idx],
389 						    page);
390 						mach_page_add(freelist, page);
391 					}
392 
393 					/* needed for indexing tmp lists */
394 					lbn = PFN_2_LBN(page->p_pagenum);
395 
396 					/*
397 					 * if this was the last page on this
398 					 * list?
399 					 */
400 					if (*sortlist[idx] == NULL) {
401 
402 						/* have to find brd list */
403 
404 						/* idx is lbn? -- No! */
405 						/* sortlist, brdlist */
406 						/*  have diff indexs */
407 						bd_flags &= ~(1 << lbn);
408 						--bd_cnt;
409 
410 						/*
411 						 * redo the sortlist so only
412 						 * bd_cnt choices show up
413 						 */
414 						bds = 0;
415 						for (idy = 0;
416 						    idy < STARFIRE_MAX_BOARDS;
417 						    idy++) {
418 							if (bdlist[idy]) {
419 								sortlist[bds++]
420 								/* CSTYLED */
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 	lbolt_debug_entry();
621 
622 	prom_interpret("sigb-sig! my-sigb-sig!", OBP_SIG, OBP_SIG, 0, 0, 0);
623 }
624 
625 static void
626 starfire_system_release(void)
627 {
628 	prom_interpret("sigb-sig! my-sigb-sig!", OS_SIG, OS_SIG, 0, 0, 0);
629 
630 	lbolt_debug_return();
631 }
632 
633 void
634 plat_kdi_init(kdi_t *kdi)
635 {
636 	kdi->pkdi_system_claim = starfire_system_claim;
637 	kdi->pkdi_system_release = starfire_system_release;
638 }
639