xref: /onnv-gate/usr/src/psm/stand/cpr/sparcv9/sun4u/machdep.c (revision 785:a0797646b335)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*785Seota  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate #include <sys/cpr.h>
310Sstevel@tonic-gate #include <sys/promimpl.h>
320Sstevel@tonic-gate #include <sys/privregs.h>
330Sstevel@tonic-gate #include <sys/stack.h>
340Sstevel@tonic-gate #include <sys/cpuvar.h>
350Sstevel@tonic-gate #include "cprboot.h"
360Sstevel@tonic-gate 
370Sstevel@tonic-gate 
380Sstevel@tonic-gate #define	TIMEOUT_MSECS	1000
390Sstevel@tonic-gate 
400Sstevel@tonic-gate 
410Sstevel@tonic-gate /*
420Sstevel@tonic-gate  * globals
430Sstevel@tonic-gate  */
440Sstevel@tonic-gate int cpr_test_mode;
450Sstevel@tonic-gate csu_md_t mdinfo;
460Sstevel@tonic-gate caddr_t tmp_stack;
470Sstevel@tonic-gate uint_t cb_mid;
480Sstevel@tonic-gate uint_t cb_clock_freq;
490Sstevel@tonic-gate uint_t cpu_delay;
500Sstevel@tonic-gate 
510Sstevel@tonic-gate 
520Sstevel@tonic-gate /*
530Sstevel@tonic-gate  * file scope
540Sstevel@tonic-gate  */
550Sstevel@tonic-gate typedef void (*tlb_func_t)(int, caddr_t, tte_t *);
560Sstevel@tonic-gate static uint_t mdlen;
570Sstevel@tonic-gate static cpuset_t slave_set;
580Sstevel@tonic-gate static int has_scbc;
590Sstevel@tonic-gate 
600Sstevel@tonic-gate 
610Sstevel@tonic-gate /*
620Sstevel@tonic-gate  * check machdep desc and cpr_machdep info
630Sstevel@tonic-gate  *
640Sstevel@tonic-gate  * sets globals:
650Sstevel@tonic-gate  *	mdinfo
660Sstevel@tonic-gate  *	mdlen
670Sstevel@tonic-gate  */
680Sstevel@tonic-gate int
cb_check_machdep(void)690Sstevel@tonic-gate cb_check_machdep(void)
700Sstevel@tonic-gate {
710Sstevel@tonic-gate 	uint16_t wst32, wst64;
720Sstevel@tonic-gate 	char *fmt, *str;
730Sstevel@tonic-gate 	cmd_t cmach;
740Sstevel@tonic-gate 
750Sstevel@tonic-gate 	str = "cb_check_machdep";
760Sstevel@tonic-gate 	CB_VPRINTF((ent_fmt, str, entry));
770Sstevel@tonic-gate 
780Sstevel@tonic-gate 	/*
790Sstevel@tonic-gate 	 * get machdep desc and set length of prom words
800Sstevel@tonic-gate 	 */
810Sstevel@tonic-gate 	SF_DCOPY(cmach);
820Sstevel@tonic-gate 	if (cmach.md_magic != CPR_MACHDEP_MAGIC) {
830Sstevel@tonic-gate 		prom_printf("%s: bad machdep magic 0x%x, expect 0x%x\n",
840Sstevel@tonic-gate 		    str, cmach.md_magic, CPR_MACHDEP_MAGIC);
850Sstevel@tonic-gate 		return (ERR);
860Sstevel@tonic-gate 	}
870Sstevel@tonic-gate 	mdlen = cmach.md_size - sizeof (csu_md_t);
880Sstevel@tonic-gate 
890Sstevel@tonic-gate 	/*
900Sstevel@tonic-gate 	 * get machep info, check for valid stack bias and wstate
910Sstevel@tonic-gate 	 */
920Sstevel@tonic-gate 	SF_DCOPY(mdinfo);
930Sstevel@tonic-gate 	fmt = "found bad statefile data: %s (0x%x), expect 0x%x or 0x%x\n";
940Sstevel@tonic-gate 	if (mdinfo.ksb != 0x0 && mdinfo.ksb != V9BIAS64) {
950Sstevel@tonic-gate 		prom_printf(fmt, "stack bias", mdinfo.ksb, 0, V9BIAS64);
960Sstevel@tonic-gate 		return (ERR);
970Sstevel@tonic-gate 	}
980Sstevel@tonic-gate 	wst32 = WSTATE(WSTATE_U32, WSTATE_K32);
990Sstevel@tonic-gate 	wst64 = WSTATE(WSTATE_U32, WSTATE_K64);
1000Sstevel@tonic-gate 	if (mdinfo.kwstate != wst32 && mdinfo.kwstate != wst64) {
1010Sstevel@tonic-gate 		prom_printf(fmt, "wstate", mdinfo.kwstate, wst32, wst64);
1020Sstevel@tonic-gate 		return (ERR);
1030Sstevel@tonic-gate 	}
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate 	return (0);
1060Sstevel@tonic-gate }
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate /*
1100Sstevel@tonic-gate  * interpret saved prom words
1110Sstevel@tonic-gate  */
1120Sstevel@tonic-gate int
cb_interpret(void)1130Sstevel@tonic-gate cb_interpret(void)
1140Sstevel@tonic-gate {
1150Sstevel@tonic-gate 	int bytes, wlen, s;
1160Sstevel@tonic-gate 	char minibuf[60];
1170Sstevel@tonic-gate 	char *words;
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate 	CB_VENTRY(cb_interpret);
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 	/*
1220Sstevel@tonic-gate 	 * The variable length machdep section for sun4u consists of
1230Sstevel@tonic-gate 	 * a sequence of null-terminated strings stored contiguously.
1240Sstevel@tonic-gate 	 *
1250Sstevel@tonic-gate 	 * The first string defines Forth words which help the prom
1260Sstevel@tonic-gate 	 * handle kernel translations.
1270Sstevel@tonic-gate 	 *
1280Sstevel@tonic-gate 	 * The second string defines Forth words required by kadb to
1290Sstevel@tonic-gate 	 * interface with the prom when a trap is taken.
1300Sstevel@tonic-gate 	 */
1310Sstevel@tonic-gate 	words = SF_DATA();
1320Sstevel@tonic-gate 	bytes = mdlen;
1330Sstevel@tonic-gate 	while (bytes) {
1340Sstevel@tonic-gate 		wlen = prom_strlen(words) + 1;	/* include the null */
1350Sstevel@tonic-gate 		if (verbose) {
1360Sstevel@tonic-gate 			s = sizeof (minibuf) - 4;
1370Sstevel@tonic-gate 			(void) prom_strncpy(minibuf, words, s);
1380Sstevel@tonic-gate 			if (wlen > s)
1390Sstevel@tonic-gate 				(void) prom_strcpy(&minibuf[s], "...");
1400Sstevel@tonic-gate 			prom_printf("    interpret \"%s\"\n", minibuf);
1410Sstevel@tonic-gate 		}
1420Sstevel@tonic-gate 		prom_interpret(words, 0, 0, 0, 0, 0);
1430Sstevel@tonic-gate 		words += wlen;
1440Sstevel@tonic-gate 		bytes -= wlen;
1450Sstevel@tonic-gate 	}
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 	/* advance past prom words */
1480Sstevel@tonic-gate 	SF_ADV(mdlen);
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate 	return (0);
1510Sstevel@tonic-gate }
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate /*
1550Sstevel@tonic-gate  * write dtlb/itlb entries
1560Sstevel@tonic-gate  */
1570Sstevel@tonic-gate static void
restore_tlb(struct sun4u_tlb * utp,int cpu_id)1580Sstevel@tonic-gate restore_tlb(struct sun4u_tlb *utp, int cpu_id)
1590Sstevel@tonic-gate {
1600Sstevel@tonic-gate 	struct sun4u_tlb *tail;
1610Sstevel@tonic-gate 	tlb_func_t tfunc;
1620Sstevel@tonic-gate 	caddr_t virt;
1630Sstevel@tonic-gate 	char tname;
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 	if (utp == mdinfo.dtte) {
1660Sstevel@tonic-gate 		tfunc = set_dtlb_entry;
1670Sstevel@tonic-gate 		tname = 'd';
1680Sstevel@tonic-gate 	} else if (utp == mdinfo.itte) {
1690Sstevel@tonic-gate 		tfunc = set_itlb_entry;
1700Sstevel@tonic-gate 		tname = 'i';
1710Sstevel@tonic-gate 	}
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 	for (tail = utp + CPR_MAX_TLB; utp < tail; utp++) {
1740Sstevel@tonic-gate 		if (utp->va_tag == NULL)
1750Sstevel@tonic-gate 			continue;
1760Sstevel@tonic-gate 		virt = (caddr_t)utp->va_tag;
1770Sstevel@tonic-gate 		(*tfunc)(utp->index, virt, &utp->tte);
1780Sstevel@tonic-gate 		if (verbose || CPR_DBG(4)) {
1790Sstevel@tonic-gate 			prom_printf("    cpu_id %d: write %ctlb "
180*785Seota 			    "(index %x, virt 0x%lx, size 0x%x)\n",
1810Sstevel@tonic-gate 			    cpu_id, tname, utp->index, utp->va_tag,
1820Sstevel@tonic-gate 			    TTEBYTES(utp->tte.tte_size));
1830Sstevel@tonic-gate 		}
1840Sstevel@tonic-gate 	}
1850Sstevel@tonic-gate }
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate /*
1890Sstevel@tonic-gate  * install locked tlb entries for the kernel and cpr module;
1900Sstevel@tonic-gate  * also sets up the tmp stack
1910Sstevel@tonic-gate  */
1920Sstevel@tonic-gate int
cb_ksetup(void)1930Sstevel@tonic-gate cb_ksetup(void)
1940Sstevel@tonic-gate {
1950Sstevel@tonic-gate 	CB_VENTRY(cb_ksetup);
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 	restore_tlb(mdinfo.dtte, cb_mid);
1980Sstevel@tonic-gate 	restore_tlb(mdinfo.itte, cb_mid);
1990Sstevel@tonic-gate 	tmp_stack = (caddr_t)(mdinfo.tmp_stack + mdinfo.tmp_stacksize);
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	return (0);
2020Sstevel@tonic-gate }
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate static void
cb_park_err(int cpu_id)2060Sstevel@tonic-gate cb_park_err(int cpu_id)
2070Sstevel@tonic-gate {
2080Sstevel@tonic-gate 	prom_printf("\ncpu_id %d did not stop!...\n", cpu_id);
2090Sstevel@tonic-gate 	cb_exit_to_mon();
2100Sstevel@tonic-gate }
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate /*
2140Sstevel@tonic-gate  * local copy of an older interface for OBP revs < 4.6
2150Sstevel@tonic-gate  */
2160Sstevel@tonic-gate static int
cb_prom_stop_self(void)2170Sstevel@tonic-gate cb_prom_stop_self(void)
2180Sstevel@tonic-gate {
2190Sstevel@tonic-gate 	cell_t ci[3];
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 	ci[0] = p1275_ptr2cell("SUNW,stop-self");	/* Service name */
2220Sstevel@tonic-gate 	ci[1] = (cell_t)0;			/* #argument cells */
2230Sstevel@tonic-gate 	ci[2] = (cell_t)0;			/* #result cells */
2240Sstevel@tonic-gate 	(void) p1275_cif_handler(&ci);		/* Do NOT lock */
2250Sstevel@tonic-gate 	return (0);
2260Sstevel@tonic-gate }
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate /*
2300Sstevel@tonic-gate  * install locked tlb entries and spin or park in a prom idle-loop
2310Sstevel@tonic-gate  */
2320Sstevel@tonic-gate void
slave_init(int cpu_id)2330Sstevel@tonic-gate slave_init(int cpu_id)
2340Sstevel@tonic-gate {
2350Sstevel@tonic-gate 	restore_tlb(mdinfo.dtte, cpu_id);
2360Sstevel@tonic-gate 	restore_tlb(mdinfo.itte, cpu_id);
2370Sstevel@tonic-gate 	CPUSET_ADD(slave_set, cpu_id);
2380Sstevel@tonic-gate 	membar_stld();
2390Sstevel@tonic-gate 	if (has_scbc) {
2400Sstevel@tonic-gate 		/* just spin, master will park this cpu */
2410Sstevel@tonic-gate 		/* CONSTCOND */
2420Sstevel@tonic-gate 		while (1);
2430Sstevel@tonic-gate 	} else {
2440Sstevel@tonic-gate 		(void) cb_prom_stop_self();
2450Sstevel@tonic-gate 		cb_park_err(cpu_id);
2460Sstevel@tonic-gate 	}
2470Sstevel@tonic-gate }
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate /*
2510Sstevel@tonic-gate  * when any cpu is started, they naturally rely on the prom for all
2520Sstevel@tonic-gate  * text/data translations until switching to the kernel trap table.
2530Sstevel@tonic-gate  * to jump back into the cpr module and to restart slave cpus, cprboot
2540Sstevel@tonic-gate  * needs to reinstall translations for the nucleus and some cpr pages.
2550Sstevel@tonic-gate  *
2560Sstevel@tonic-gate  * the easy method is creating one set of global translations available
2570Sstevel@tonic-gate  * to all cpus with prom_map(); unfortunately, a 4MB "map" request will
2580Sstevel@tonic-gate  * allocate and overwrite a few pages, and these are often kernel pages
2590Sstevel@tonic-gate  * that were just restored.
2600Sstevel@tonic-gate  *
2610Sstevel@tonic-gate  * to solve the "map" problem, all cpus install their own set of locked
2620Sstevel@tonic-gate  * tlb entries to translate the nucleus and parts of the cpr module;
2630Sstevel@tonic-gate  * after all cpus have switched to kernel traps, any of these locked
2640Sstevel@tonic-gate  * tlb entries for pages outside the nucleus will be cleared.
2650Sstevel@tonic-gate  */
2660Sstevel@tonic-gate int
cb_mpsetup(void)2670Sstevel@tonic-gate cb_mpsetup(void)
2680Sstevel@tonic-gate {
2690Sstevel@tonic-gate 	struct sun4u_cpu_info *scip, *tail;
2700Sstevel@tonic-gate 	int timeout, ncpu;
2710Sstevel@tonic-gate 	char *str, *intf;
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 	intf = "SUNW,stop-cpu-by-cpuid";
2740Sstevel@tonic-gate 	has_scbc = (prom_test(intf) == 0);
2750Sstevel@tonic-gate 	CB_VPRINTF(("\n\"%s\" test %d\n", intf, has_scbc));
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 	str = "cb_mp_setup";
2780Sstevel@tonic-gate 	CB_VPRINTF((ent_fmt, str, entry));
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	/*
2810Sstevel@tonic-gate 	 * launch any slave cpus from the .sci array into cprboot text
2820Sstevel@tonic-gate 	 * and wait about a second for them to checkin with slave_set
2830Sstevel@tonic-gate 	 */
2840Sstevel@tonic-gate 	ncpu = 0;
2850Sstevel@tonic-gate 	CPUSET_ZERO(slave_set);
2860Sstevel@tonic-gate 	for (scip = mdinfo.sci, tail = scip + NCPU; scip < tail; scip++) {
2870Sstevel@tonic-gate 		if (scip->node == 0 || scip->cpu_id == cb_mid)
2880Sstevel@tonic-gate 			continue;
2890Sstevel@tonic-gate 		(void) prom_startcpu(scip->node,
2900Sstevel@tonic-gate 		    (caddr_t)cpu_launch, scip->cpu_id);
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 		for (timeout = TIMEOUT_MSECS; timeout; timeout--) {
2930Sstevel@tonic-gate 			if (CPU_IN_SET(slave_set, scip->cpu_id))
2940Sstevel@tonic-gate 				break;
2950Sstevel@tonic-gate 			cb_usec_wait(MILLISEC);
2960Sstevel@tonic-gate 		}
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 		if (timeout == 0) {
2990Sstevel@tonic-gate 			prom_printf("\n%s: cpu did not start, "
3000Sstevel@tonic-gate 			    "cpu_id %d, node 0x%x\n",
3010Sstevel@tonic-gate 			    prog, scip->cpu_id, scip->node);
3020Sstevel@tonic-gate 			return (ERR);
3030Sstevel@tonic-gate 		}
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 		if (has_scbc && prom_stopcpu_bycpuid(scip->cpu_id))
3060Sstevel@tonic-gate 			cb_park_err(scip->cpu_id);
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 		ncpu++;
3090Sstevel@tonic-gate 	}
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 	if (verbose && ncpu)
3120Sstevel@tonic-gate 		prom_printf("\n%s: slave cpu count: %d\n", str, ncpu);
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	return (0);
3150Sstevel@tonic-gate }
316