xref: /titanic_51/usr/src/uts/sun4u/daktari/os/daktari.c (revision bdfc6d18da790deeec2e0eb09c625902defe2498)
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/cpuvar.h>
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/sunddi.h>
33 #include <sys/ddi.h>
34 #include <sys/sysmacros.h>
35 #include <sys/note.h>
36 
37 #include <sys/modctl.h>		/* for modload() */
38 #include <sys/platform_module.h>
39 #include <sys/errno.h>
40 #include <sys/daktari.h>
41 #include <sys/machsystm.h>
42 #include <sys/promif.h>
43 #include <vm/page.h>
44 #include <sys/memnode.h>
45 #include <vm/vm_dep.h>
46 
47 /* I2C Stuff */
48 #include <sys/i2c/clients/i2c_client.h>
49 
50 
51 int (*p2get_mem_unum)(int, uint64_t, char *, int, int *);
52 
53 /* Daktari Keyswitch Information */
54 #define	DAK_KEY_POLL_PORT	3
55 #define	DAK_KEY_POLL_BIT	2
56 #define	DAK_KEY_POLL_INTVL	10
57 
58 static	boolean_t	key_locked_bit;
59 static	clock_t		keypoll_timeout_hz;
60 
61 /*
62  * For software memory interleaving support.
63  */
64 static	void update_mem_bounds(int, int, int, uint64_t, uint64_t);
65 
66 static uint64_t
67 slice_table[DAK_SBD_SLOTS][DAK_CPUS_PER_BOARD][DAK_BANKS_PER_MC][2];
68 
69 #define	SLICE_PA	0
70 #define	SLICE_SPAN	1
71 
72 int (*daktari_ssc050_get_port_bit) (dev_info_t *, int, int, uint8_t *, int);
73 extern	void (*abort_seq_handler)();
74 static	int daktari_dev_search(dev_info_t *, void *);
75 static	void keyswitch_poll(void *);
76 static	void daktari_abort_seq_handler(char *msg);
77 
78 void
79 startup_platform(void)
80 {
81 	/*
82 	 * Disable an active h/w watchdog timer
83 	 * upon exit to OBP.
84 	 */
85 	extern int disable_watchdog_on_exit;
86 	disable_watchdog_on_exit = 1;
87 }
88 
89 int
90 set_platform_tsb_spares()
91 {
92 	return (0);
93 }
94 
95 #pragma weak mmu_init_large_pages
96 
97 void
98 set_platform_defaults(void)
99 {
100 	extern int ts_dispatch_extended;
101 	extern uchar_t *ctx_pgsz_array;
102 	extern void mmu_init_large_pages(size_t);
103 
104 	/*
105 	 * Use the alternate TS dispatch table for USIII+ forward,
106 	 * which is better tuned for large servers.
107 	 */
108 	if ((ts_dispatch_extended == -1) && (ctx_pgsz_array != NULL))
109 		ts_dispatch_extended = 1;
110 
111 	if ((mmu_page_sizes == max_mmu_page_sizes) &&
112 	    (mmu_ism_pagesize != MMU_PAGESIZE32M)) {
113 		if (&mmu_init_large_pages)
114 			mmu_init_large_pages(mmu_ism_pagesize);
115 	}
116 }
117 
118 void
119 load_platform_modules(void)
120 {
121 	if (modload("misc", "pcihp") < 0) {
122 		cmn_err(CE_NOTE, "pcihp driver failed to load");
123 	}
124 	if (modload("drv", "pmc") < 0) {
125 		cmn_err(CE_NOTE, "pmc driver failed to load");
126 	}
127 
128 }
129 
130 void
131 load_platform_drivers(void)
132 {
133 	char **drv;
134 	dev_info_t	*keysw_dip;
135 
136 	static char *boot_time_drivers[] = {
137 		"hpc3130",
138 		"todds1287",
139 		"mc-us3",
140 		"ssc050",
141 		"pcisch",
142 		NULL
143 	};
144 
145 	for (drv = boot_time_drivers; *drv; drv++) {
146 		if (i_ddi_attach_hw_nodes(*drv) != DDI_SUCCESS)
147 			cmn_err(CE_WARN, "Failed to install \"%s\" driver.",
148 			    *drv);
149 	}
150 
151 	/*
152 	 * mc-us3 & ssc050 must stay loaded for plat_get_mem_unum()
153 	 * and keyswitch_poll()
154 	 */
155 	(void) ddi_hold_driver(ddi_name_to_major("mc-us3"));
156 	(void) ddi_hold_driver(ddi_name_to_major("ssc050"));
157 
158 	/* Gain access into the ssc050_get_port function */
159 	daktari_ssc050_get_port_bit = (int (*) (dev_info_t *, int, int,
160 		uint8_t *, int)) modgetsymvalue("ssc050_get_port_bit", 0);
161 	if (daktari_ssc050_get_port_bit == NULL) {
162 		cmn_err(CE_WARN, "cannot find ssc050_get_port_bit");
163 		return;
164 	}
165 
166 	ddi_walk_devs(ddi_root_node(), daktari_dev_search, (void *)&keysw_dip);
167 	ASSERT(keysw_dip != NULL);
168 
169 	keypoll_timeout_hz = drv_usectohz(10 * MICROSEC);
170 	keyswitch_poll(keysw_dip);
171 	abort_seq_handler = daktari_abort_seq_handler;
172 }
173 
174 static int
175 daktari_dev_search(dev_info_t *dip, void *arg)
176 {
177 	char		*compatible = NULL; /* Search tree for "i2c-ssc050" */
178 	int		*dev_regs; /* Info about where the device is. */
179 	uint_t		len;
180 	int		err;
181 
182 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
183 				"compatible", &compatible) != DDI_PROP_SUCCESS)
184 		return (DDI_WALK_CONTINUE);
185 
186 	if (strcmp(compatible, "i2c-ssc050") == 0) {
187 		ddi_prop_free(compatible);
188 
189 		err = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
190 			DDI_PROP_DONTPASS, "reg", &dev_regs, &len);
191 		if (err != DDI_PROP_SUCCESS) {
192 			return (DDI_WALK_CONTINUE);
193 		}
194 		/*
195 		 * regs[0] contains the bus number and regs[1]
196 		 * contains the device address of the i2c device.
197 		 * 0x82 is the device address of the i2c device
198 		 * from which  the key switch position is read.
199 		 */
200 		if (dev_regs[0] == 0 && dev_regs[1] == 0x82) {
201 			*((dev_info_t **)arg) = dip;
202 			ddi_prop_free(dev_regs);
203 			return (DDI_WALK_TERMINATE);
204 		}
205 		ddi_prop_free(dev_regs);
206 	} else {
207 		ddi_prop_free(compatible);
208 	}
209 	return (DDI_WALK_CONTINUE);
210 }
211 
212 static void
213 keyswitch_poll(void *arg)
214 {
215 	dev_info_t	*dip = arg;
216 	uchar_t	port_byte;
217 	int	port = DAK_KEY_POLL_PORT;
218 	int	bit = DAK_KEY_POLL_BIT;
219 	int	err;
220 
221 	err = daktari_ssc050_get_port_bit(dip, port, bit,
222 		&port_byte, I2C_NOSLEEP);
223 	if (err != 0) {
224 		return;
225 	}
226 
227 	key_locked_bit = (boolean_t)((port_byte & 0x1));
228 	timeout(keyswitch_poll, (caddr_t)dip, keypoll_timeout_hz);
229 }
230 
231 static void
232 daktari_abort_seq_handler(char *msg)
233 {
234 	if (key_locked_bit == 0)
235 		cmn_err(CE_CONT, "KEY in LOCKED position, "
236 			"ignoring debug enter sequence");
237 	else  {
238 		debug_enter(msg);
239 	}
240 }
241 
242 
243 int
244 plat_cpu_poweron(struct cpu *cp)
245 {
246 	_NOTE(ARGUNUSED(cp))
247 	return (ENOTSUP);
248 }
249 
250 int
251 plat_cpu_poweroff(struct cpu *cp)
252 {
253 	_NOTE(ARGUNUSED(cp))
254 	return (ENOTSUP);
255 }
256 
257 /*
258  * Given a pfn, return the board and beginning/end of the page's
259  * memory controller's address range.
260  */
261 static int
262 plat_discover_slice(pfn_t pfn, pfn_t *first, pfn_t *last)
263 {
264 	int bd, cpu, bank;
265 
266 	for (bd = 0; bd < DAK_SBD_SLOTS; bd++) {
267 		for (cpu = 0; cpu < DAK_CPUS_PER_BOARD; cpu++) {
268 			for (bank = 0; bank < DAK_BANKS_PER_MC; bank++) {
269 				uint64_t *slice = slice_table[bd][cpu][bank];
270 				uint64_t base = btop(slice[SLICE_PA]);
271 				uint64_t len = btop(slice[SLICE_SPAN]);
272 				if (len && pfn >= base && pfn < (base + len)) {
273 					*first = base;
274 					*last = base + len - 1;
275 					return (bd);
276 				}
277 			}
278 		}
279 	}
280 	panic("plat_discover_slice: no slice for pfn 0x%lx\n", pfn);
281 	/* NOTREACHED */
282 }
283 
284 /*
285  * This index is used to associate a given pfn to a place on the freelist.
286  * This results in dispersing pfn assignment over all the boards in the
287  * system.
288  * Choose the index randomly to prevent clustering pages of different
289  * colors on the same board.
290  */
291 static uint_t random_idx(int ubound);
292 
293 /*
294  * Theory of operation:
295  *	- When the system walks the prom tree, it calls the platform
296  *	  function plat_fill_mc() for each memory-controller node found
297  *	  in map_wellknown().
298  *	- The plat_fill_mc() function interrogates the memory controller
299  *	  to find out if it controls memory.  If it does, the physical
300  *	  address and span are recorded in a lookup table.
301  *	- During VM init, the VM calls plat_freelist_process() to shuffle
302  *	  the page freelists.  This is done after the page freelists are
303  *	  coalesced, but before the system goes live, since we need to be
304  *	  able to get the exclusive lock on all the pages.
305  *	- plat_freelist_process() removes all pages from the freelists,
306  *	  and sorts them out into per-board freelists.  It does this by
307  *	  using the lookup table that was built earlier.  It then
308  *	  round-robins across the per-board freelists and frees each page,
309  *	  leaving an even distribution of pages across the system.
310  */
311 void
312 plat_freelist_process(int mnode)
313 {
314 	page_t		*page, **freelist;
315 	page_t		*bdlist[DAK_SBD_SLOTS];
316 	page_t		**sortlist[DAK_SBD_SLOTS];
317 	uint32_t	idx, idy, size, color, max_color, lbn;
318 	uint32_t	bd_flags, bd_cnt, result, bds;
319 	pfn_t		slice_start, slice_end, pfn;
320 	kmutex_t	*pcm;
321 	int		mtype;
322 
323 	/*
324 	 * Sort through freelists one memory type and size at a time.
325 	 */
326 	for (mtype = 0; mtype < MAX_MEM_TYPES; mtype++) {
327 		for (size = 0; size < mmu_page_sizes; size++) {
328 			/*
329 			 * Compute the maximum # of phys colors based on
330 			 * page size.
331 			 */
332 			max_color = page_get_pagecolors(size);
333 
334 			/*
335 			 * Sort through freelists one color at a time.
336 			 */
337 			for (color = 0; color < max_color; color++) {
338 				bd_cnt = 0;
339 				bd_flags = 0;
340 				slice_start = (pfn_t)-1;
341 				slice_end = (pfn_t)-1;
342 
343 				for (idx = 0; idx < DAK_SBD_SLOTS; idx++) {
344 					bdlist[idx] = NULL;
345 					sortlist[idx] = NULL;
346 				}
347 
348 				freelist = &PAGE_FREELISTS(mnode, size,
349 				    color, mtype);
350 
351 				if (*freelist == NULL)
352 					continue;
353 
354 				/*
355 				 * Acquire per-color freelist lock.
356 				 */
357 				pcm = PC_BIN_MUTEX(mnode, color, PG_FREE_LIST);
358 				mutex_enter(pcm);
359 
360 				/*
361 				 * Go through freelist, sorting pages out
362 				 * into per-board lists.
363 				 */
364 				while (*freelist) {
365 					page = *freelist;
366 					result = page_trylock(page, SE_EXCL);
367 					ASSERT(result);
368 
369 					/*
370 					 * Delete from freelist.
371 					 */
372 					if (size != 0) {
373 						page_vpsub(freelist, page);
374 					} else {
375 						mach_page_sub(freelist, page);
376 					}
377 
378 					pfn = page->p_pagenum;
379 					if (pfn < slice_start ||
380 					    pfn > slice_end)
381 						lbn = plat_discover_slice(pfn,
382 						    &slice_start, &slice_end);
383 
384 					/*
385 					 * Add to per-board list.
386 					 */
387 					if (size != 0) {
388 						page_vpadd(&bdlist[lbn], page);
389 					} else {
390 						mach_page_add(&bdlist[lbn],
391 						    page);
392 					}
393 
394 					/*
395 					 * Seen this board yet?
396 					 */
397 					if ((bd_flags & (1 << lbn)) == 0) {
398 						bd_flags |= (1 << lbn);
399 						bd_cnt++;
400 					}
401 					page_unlock(page);
402 				}
403 
404 				/*
405 				 * Make the sortlist so
406 				 * bd_cnt choices show up
407 				 */
408 				bds = 0;
409 				for (idx = 0; idx < DAK_SBD_SLOTS; idx++) {
410 					if (bdlist[idx])
411 						sortlist[bds++] = &bdlist[idx];
412 				}
413 
414 				/*
415 				 * Set random start.
416 				 */
417 				(void) random_idx(-color);
418 
419 				/*
420 				 * now rebuild the freelist by shuffling
421 				 * pages from bd lists
422 				 */
423 				while (bd_cnt) {
424 					/*
425 					 * get "random" index between 0 &
426 					 * bd_cnt
427 					 */
428 					ASSERT(bd_cnt &&
429 					    (bd_cnt < DAK_SBD_SLOTS+1));
430 
431 					idx = random_idx(bd_cnt);
432 
433 					page = *sortlist[idx];
434 					result = page_trylock(page, SE_EXCL);
435 					ASSERT(result);
436 
437 					/*
438 					 * Delete from sort list and add
439 					 * to freelist.
440 					 */
441 					if (size != 0) {
442 						page_vpsub(sortlist[idx], page);
443 						page_vpadd(freelist, page);
444 					} else {
445 						mach_page_sub(sortlist[idx],
446 						    page);
447 						mach_page_add(freelist, page);
448 					}
449 
450 					pfn = page->p_pagenum;
451 					if (pfn < slice_start ||
452 					    pfn > slice_end)
453 						lbn = plat_discover_slice(pfn,
454 						    &slice_start, &slice_end);
455 
456 					/*
457 					 * Is this the last page this list?
458 					 */
459 					if (*sortlist[idx] == NULL) {
460 						bd_flags &= ~(1 << lbn);
461 						--bd_cnt;
462 
463 						/*
464 						 * redo the sortlist so only
465 						 * bd_cnt choices show up
466 						 */
467 						bds = 0;
468 						for (idy = 0;
469 						    idy < DAK_SBD_SLOTS;
470 						    idy++) {
471 							if (bdlist[idy]) {
472 							    sortlist[bds++]
473 								= &bdlist[idy];
474 							}
475 						}
476 					}
477 					page_unlock(page);
478 				}
479 				mutex_exit(pcm);
480 			}
481 		}
482 	}
483 }
484 
485 /*
486  * If ubound > 0, will return an int between 0 & ubound
487  * If ubound < 0, will set "random seed"
488  */
489 static uint_t
490 random_idx(int ubound)
491 {
492 	static int idx = 0;
493 
494 	if (ubound > 0) {
495 		idx = (idx + 1) % ubound;
496 		return (idx);
497 	}
498 	idx = -ubound;
499 	return (0);
500 }
501 
502 /*
503  * Called for each board/cpu/PA range detected in plat_fill_mc().
504  */
505 static void
506 update_mem_bounds(int boardid, int cpuid, int bankid,
507 	uint64_t base, uint64_t size)
508 {
509 	slice_table[boardid][cpuid][bankid][SLICE_PA] = base;
510 	slice_table[boardid][cpuid][bankid][SLICE_SPAN] = size;
511 }
512 
513 /*
514  * Dynamically detect memory slices in the system by decoding
515  * the cpu memory decoder registers at boot time.
516  */
517 void
518 plat_fill_mc(dnode_t nodeid)
519 {
520 	uint64_t	mc_addr, saf_addr;
521 	uint64_t	mc_decode[DAK_BANKS_PER_MC];
522 	uint64_t	base, size;
523 	uint64_t	saf_mask;
524 	uint64_t	offset;
525 	uint32_t	regs[4];
526 	int		len;
527 	int		local_mc;
528 	int		portid;
529 	int		boardid;
530 	int		cpuid;
531 	int		i;
532 
533 	if ((prom_getprop(nodeid, "portid", (caddr_t)&portid) < 0) ||
534 	    (portid == -1))
535 		return;
536 
537 	/*
538 	 * Decode the board number from the MC portid.  Assumes
539 	 * portid == safari agentid.
540 	 */
541 	boardid = DAK_GETSLOT(portid);
542 	cpuid = DAK_GETSID(portid);
543 
544 	/*
545 	 * The "reg" property returns 4 32-bit values. The first two are
546 	 * combined to form a 64-bit address.  The second two are for a
547 	 * 64-bit size, but we don't actually need to look at that value.
548 	 */
549 	len = prom_getproplen(nodeid, "reg");
550 	if (len != (sizeof (uint32_t) * 4)) {
551 		prom_printf("Warning: malformed 'reg' property\n");
552 		return;
553 	}
554 	if (prom_getprop(nodeid, "reg", (caddr_t)regs) < 0)
555 		return;
556 	mc_addr = ((uint64_t)regs[0]) << 32;
557 	mc_addr |= (uint64_t)regs[1];
558 
559 	/*
560 	 * Figure out whether the memory controller we are examining
561 	 * belongs to this CPU or a different one.
562 	 */
563 	saf_addr = lddsafaddr(8);
564 	saf_mask = (uint64_t)SAF_MASK;
565 	if ((mc_addr & saf_mask) == saf_addr)
566 		local_mc = 1;
567 	else
568 		local_mc = 0;
569 
570 	for (i = 0; i < DAK_BANKS_PER_MC; i++) {
571 		/*
572 		 * Memory decode masks are at offsets 0x10 - 0x28.
573 		 */
574 		offset = 0x10 + (i << 3);
575 
576 		/*
577 		 * If the memory controller is local to this CPU, we use
578 		 * the special ASI to read the decode registers.
579 		 * Otherwise, we load the values from a magic address in
580 		 * I/O space.
581 		 */
582 		if (local_mc)
583 			mc_decode[i] = lddmcdecode(offset);
584 		else
585 			mc_decode[i] = lddphysio(mc_addr | offset);
586 
587 		/*
588 		 * If the upper bit is set, we have a valid mask
589 		 */
590 		if ((int64_t)mc_decode[i] < 0) {
591 			/*
592 			 * The memory decode register is a bitmask field,
593 			 * so we can decode that into both a base and
594 			 * a span.
595 			 */
596 			base = MC_BASE(mc_decode[i]) << PHYS2UM_SHIFT;
597 			size = MC_UK2SPAN(mc_decode[i]);
598 			update_mem_bounds(boardid, cpuid, i, base, size);
599 		}
600 	}
601 }
602 
603 /*
604  * No platform drivers on this platform
605  */
606 char *platform_module_list[] = {
607 	(char *)0
608 };
609 
610 /*ARGSUSED*/
611 void
612 plat_tod_fault(enum tod_fault_type tod_bad)
613 {
614 }
615 
616 /*ARGSUSED*/
617 int
618 plat_get_mem_unum(int synd_code, uint64_t flt_addr, int flt_bus_id,
619     int flt_in_memory, ushort_t flt_status, char *buf, int buflen, int *lenp)
620 {
621 	if (flt_in_memory && (p2get_mem_unum != NULL))
622 		return (p2get_mem_unum(synd_code, P2ALIGN(flt_addr, 8),
623 			buf, buflen, lenp));
624 	else
625 		return (ENOTSUP);
626 }
627 
628 /*
629  * This platform hook gets called from mc_add_mem_unum_label() in the mc-us3
630  * driver giving each platform the opportunity to add platform
631  * specific label information to the unum for ECC error logging purposes.
632  */
633 void
634 plat_add_mem_unum_label(char *unum, int mcid, int bank, int dimm)
635 {
636 	_NOTE(ARGUNUSED(bank, dimm))
637 
638 	char board = DAK_GETSLOT_LABEL(mcid);
639 	char old_unum[UNUM_NAMLEN];
640 
641 	strcpy(old_unum, unum);
642 	snprintf(unum, UNUM_NAMLEN, "Slot %c: %s", board, old_unum);
643 }
644 
645 int
646 plat_get_cpu_unum(int cpuid, char *buf, int buflen, int *lenp)
647 {
648 	char board = DAK_GETSLOT_LABEL(cpuid);
649 
650 	if (snprintf(buf, buflen, "Slot %c", board) >= buflen) {
651 		return (ENOSPC);
652 	} else {
653 		*lenp = strlen(buf);
654 		return (0);
655 	}
656 }
657 
658 /*
659  * The zuluvm module requires a dmv interrupt for each installed zulu board.
660  */
661 void
662 plat_dmv_params(uint_t *hwint, uint_t *swint)
663 {
664 	*hwint = 0;
665 	*swint = DAK_SBD_SLOTS - 1;
666 }
667