17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 23*53391bafSeota * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include <sys/types.h> 307c478bd9Sstevel@tonic-gate #include <sys/cpr.h> 317c478bd9Sstevel@tonic-gate #include <sys/promimpl.h> 327c478bd9Sstevel@tonic-gate #include <sys/privregs.h> 337c478bd9Sstevel@tonic-gate #include <sys/stack.h> 347c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 357c478bd9Sstevel@tonic-gate #include "cprboot.h" 367c478bd9Sstevel@tonic-gate 377c478bd9Sstevel@tonic-gate 387c478bd9Sstevel@tonic-gate #define TIMEOUT_MSECS 1000 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate /* 427c478bd9Sstevel@tonic-gate * globals 437c478bd9Sstevel@tonic-gate */ 447c478bd9Sstevel@tonic-gate int cpr_test_mode; 457c478bd9Sstevel@tonic-gate csu_md_t mdinfo; 467c478bd9Sstevel@tonic-gate caddr_t tmp_stack; 477c478bd9Sstevel@tonic-gate uint_t cb_mid; 487c478bd9Sstevel@tonic-gate uint_t cb_clock_freq; 497c478bd9Sstevel@tonic-gate uint_t cpu_delay; 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate /* 537c478bd9Sstevel@tonic-gate * file scope 547c478bd9Sstevel@tonic-gate */ 557c478bd9Sstevel@tonic-gate typedef void (*tlb_func_t)(int, caddr_t, tte_t *); 567c478bd9Sstevel@tonic-gate static uint_t mdlen; 577c478bd9Sstevel@tonic-gate static cpuset_t slave_set; 587c478bd9Sstevel@tonic-gate static int has_scbc; 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate /* 627c478bd9Sstevel@tonic-gate * check machdep desc and cpr_machdep info 637c478bd9Sstevel@tonic-gate * 647c478bd9Sstevel@tonic-gate * sets globals: 657c478bd9Sstevel@tonic-gate * mdinfo 667c478bd9Sstevel@tonic-gate * mdlen 677c478bd9Sstevel@tonic-gate */ 687c478bd9Sstevel@tonic-gate int 697c478bd9Sstevel@tonic-gate cb_check_machdep(void) 707c478bd9Sstevel@tonic-gate { 717c478bd9Sstevel@tonic-gate uint16_t wst32, wst64; 727c478bd9Sstevel@tonic-gate char *fmt, *str; 737c478bd9Sstevel@tonic-gate cmd_t cmach; 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate str = "cb_check_machdep"; 767c478bd9Sstevel@tonic-gate CB_VPRINTF((ent_fmt, str, entry)); 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate /* 797c478bd9Sstevel@tonic-gate * get machdep desc and set length of prom words 807c478bd9Sstevel@tonic-gate */ 817c478bd9Sstevel@tonic-gate SF_DCOPY(cmach); 827c478bd9Sstevel@tonic-gate if (cmach.md_magic != CPR_MACHDEP_MAGIC) { 837c478bd9Sstevel@tonic-gate prom_printf("%s: bad machdep magic 0x%x, expect 0x%x\n", 847c478bd9Sstevel@tonic-gate str, cmach.md_magic, CPR_MACHDEP_MAGIC); 857c478bd9Sstevel@tonic-gate return (ERR); 867c478bd9Sstevel@tonic-gate } 877c478bd9Sstevel@tonic-gate mdlen = cmach.md_size - sizeof (csu_md_t); 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate /* 907c478bd9Sstevel@tonic-gate * get machep info, check for valid stack bias and wstate 917c478bd9Sstevel@tonic-gate */ 927c478bd9Sstevel@tonic-gate SF_DCOPY(mdinfo); 937c478bd9Sstevel@tonic-gate fmt = "found bad statefile data: %s (0x%x), expect 0x%x or 0x%x\n"; 947c478bd9Sstevel@tonic-gate if (mdinfo.ksb != 0x0 && mdinfo.ksb != V9BIAS64) { 957c478bd9Sstevel@tonic-gate prom_printf(fmt, "stack bias", mdinfo.ksb, 0, V9BIAS64); 967c478bd9Sstevel@tonic-gate return (ERR); 977c478bd9Sstevel@tonic-gate } 987c478bd9Sstevel@tonic-gate wst32 = WSTATE(WSTATE_U32, WSTATE_K32); 997c478bd9Sstevel@tonic-gate wst64 = WSTATE(WSTATE_U32, WSTATE_K64); 1007c478bd9Sstevel@tonic-gate if (mdinfo.kwstate != wst32 && mdinfo.kwstate != wst64) { 1017c478bd9Sstevel@tonic-gate prom_printf(fmt, "wstate", mdinfo.kwstate, wst32, wst64); 1027c478bd9Sstevel@tonic-gate return (ERR); 1037c478bd9Sstevel@tonic-gate } 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate return (0); 1067c478bd9Sstevel@tonic-gate } 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate /* 1107c478bd9Sstevel@tonic-gate * interpret saved prom words 1117c478bd9Sstevel@tonic-gate */ 1127c478bd9Sstevel@tonic-gate int 1137c478bd9Sstevel@tonic-gate cb_interpret(void) 1147c478bd9Sstevel@tonic-gate { 1157c478bd9Sstevel@tonic-gate int bytes, wlen, s; 1167c478bd9Sstevel@tonic-gate char minibuf[60]; 1177c478bd9Sstevel@tonic-gate char *words; 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate CB_VENTRY(cb_interpret); 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate /* 1227c478bd9Sstevel@tonic-gate * The variable length machdep section for sun4u consists of 1237c478bd9Sstevel@tonic-gate * a sequence of null-terminated strings stored contiguously. 1247c478bd9Sstevel@tonic-gate * 1257c478bd9Sstevel@tonic-gate * The first string defines Forth words which help the prom 1267c478bd9Sstevel@tonic-gate * handle kernel translations. 1277c478bd9Sstevel@tonic-gate * 1287c478bd9Sstevel@tonic-gate * The second string defines Forth words required by kadb to 1297c478bd9Sstevel@tonic-gate * interface with the prom when a trap is taken. 1307c478bd9Sstevel@tonic-gate */ 1317c478bd9Sstevel@tonic-gate words = SF_DATA(); 1327c478bd9Sstevel@tonic-gate bytes = mdlen; 1337c478bd9Sstevel@tonic-gate while (bytes) { 1347c478bd9Sstevel@tonic-gate wlen = prom_strlen(words) + 1; /* include the null */ 1357c478bd9Sstevel@tonic-gate if (verbose) { 1367c478bd9Sstevel@tonic-gate s = sizeof (minibuf) - 4; 1377c478bd9Sstevel@tonic-gate (void) prom_strncpy(minibuf, words, s); 1387c478bd9Sstevel@tonic-gate if (wlen > s) 1397c478bd9Sstevel@tonic-gate (void) prom_strcpy(&minibuf[s], "..."); 1407c478bd9Sstevel@tonic-gate prom_printf(" interpret \"%s\"\n", minibuf); 1417c478bd9Sstevel@tonic-gate } 1427c478bd9Sstevel@tonic-gate prom_interpret(words, 0, 0, 0, 0, 0); 1437c478bd9Sstevel@tonic-gate words += wlen; 1447c478bd9Sstevel@tonic-gate bytes -= wlen; 1457c478bd9Sstevel@tonic-gate } 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate /* advance past prom words */ 1487c478bd9Sstevel@tonic-gate SF_ADV(mdlen); 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate return (0); 1517c478bd9Sstevel@tonic-gate } 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate /* 1557c478bd9Sstevel@tonic-gate * write dtlb/itlb entries 1567c478bd9Sstevel@tonic-gate */ 1577c478bd9Sstevel@tonic-gate static void 1587c478bd9Sstevel@tonic-gate restore_tlb(struct sun4u_tlb *utp, int cpu_id) 1597c478bd9Sstevel@tonic-gate { 1607c478bd9Sstevel@tonic-gate struct sun4u_tlb *tail; 1617c478bd9Sstevel@tonic-gate tlb_func_t tfunc; 1627c478bd9Sstevel@tonic-gate caddr_t virt; 1637c478bd9Sstevel@tonic-gate char tname; 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate if (utp == mdinfo.dtte) { 1667c478bd9Sstevel@tonic-gate tfunc = set_dtlb_entry; 1677c478bd9Sstevel@tonic-gate tname = 'd'; 1687c478bd9Sstevel@tonic-gate } else if (utp == mdinfo.itte) { 1697c478bd9Sstevel@tonic-gate tfunc = set_itlb_entry; 1707c478bd9Sstevel@tonic-gate tname = 'i'; 1717c478bd9Sstevel@tonic-gate } 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate for (tail = utp + CPR_MAX_TLB; utp < tail; utp++) { 1747c478bd9Sstevel@tonic-gate if (utp->va_tag == NULL) 1757c478bd9Sstevel@tonic-gate continue; 1767c478bd9Sstevel@tonic-gate virt = (caddr_t)utp->va_tag; 1777c478bd9Sstevel@tonic-gate (*tfunc)(utp->index, virt, &utp->tte); 1787c478bd9Sstevel@tonic-gate if (verbose || CPR_DBG(4)) { 1797c478bd9Sstevel@tonic-gate prom_printf(" cpu_id %d: write %ctlb " 180*53391bafSeota "(index %x, virt 0x%lx, size 0x%x)\n", 1817c478bd9Sstevel@tonic-gate cpu_id, tname, utp->index, utp->va_tag, 1827c478bd9Sstevel@tonic-gate TTEBYTES(utp->tte.tte_size)); 1837c478bd9Sstevel@tonic-gate } 1847c478bd9Sstevel@tonic-gate } 1857c478bd9Sstevel@tonic-gate } 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate /* 1897c478bd9Sstevel@tonic-gate * install locked tlb entries for the kernel and cpr module; 1907c478bd9Sstevel@tonic-gate * also sets up the tmp stack 1917c478bd9Sstevel@tonic-gate */ 1927c478bd9Sstevel@tonic-gate int 1937c478bd9Sstevel@tonic-gate cb_ksetup(void) 1947c478bd9Sstevel@tonic-gate { 1957c478bd9Sstevel@tonic-gate CB_VENTRY(cb_ksetup); 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate restore_tlb(mdinfo.dtte, cb_mid); 1987c478bd9Sstevel@tonic-gate restore_tlb(mdinfo.itte, cb_mid); 1997c478bd9Sstevel@tonic-gate tmp_stack = (caddr_t)(mdinfo.tmp_stack + mdinfo.tmp_stacksize); 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate return (0); 2027c478bd9Sstevel@tonic-gate } 2037c478bd9Sstevel@tonic-gate 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate static void 2067c478bd9Sstevel@tonic-gate cb_park_err(int cpu_id) 2077c478bd9Sstevel@tonic-gate { 2087c478bd9Sstevel@tonic-gate prom_printf("\ncpu_id %d did not stop!...\n", cpu_id); 2097c478bd9Sstevel@tonic-gate cb_exit_to_mon(); 2107c478bd9Sstevel@tonic-gate } 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate /* 2147c478bd9Sstevel@tonic-gate * local copy of an older interface for OBP revs < 4.6 2157c478bd9Sstevel@tonic-gate */ 2167c478bd9Sstevel@tonic-gate static int 2177c478bd9Sstevel@tonic-gate cb_prom_stop_self(void) 2187c478bd9Sstevel@tonic-gate { 2197c478bd9Sstevel@tonic-gate cell_t ci[3]; 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate ci[0] = p1275_ptr2cell("SUNW,stop-self"); /* Service name */ 2227c478bd9Sstevel@tonic-gate ci[1] = (cell_t)0; /* #argument cells */ 2237c478bd9Sstevel@tonic-gate ci[2] = (cell_t)0; /* #result cells */ 2247c478bd9Sstevel@tonic-gate (void) p1275_cif_handler(&ci); /* Do NOT lock */ 2257c478bd9Sstevel@tonic-gate return (0); 2267c478bd9Sstevel@tonic-gate } 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate /* 2307c478bd9Sstevel@tonic-gate * install locked tlb entries and spin or park in a prom idle-loop 2317c478bd9Sstevel@tonic-gate */ 2327c478bd9Sstevel@tonic-gate void 2337c478bd9Sstevel@tonic-gate slave_init(int cpu_id) 2347c478bd9Sstevel@tonic-gate { 2357c478bd9Sstevel@tonic-gate restore_tlb(mdinfo.dtte, cpu_id); 2367c478bd9Sstevel@tonic-gate restore_tlb(mdinfo.itte, cpu_id); 2377c478bd9Sstevel@tonic-gate CPUSET_ADD(slave_set, cpu_id); 2387c478bd9Sstevel@tonic-gate membar_stld(); 2397c478bd9Sstevel@tonic-gate if (has_scbc) { 2407c478bd9Sstevel@tonic-gate /* just spin, master will park this cpu */ 2417c478bd9Sstevel@tonic-gate /* CONSTCOND */ 2427c478bd9Sstevel@tonic-gate while (1); 2437c478bd9Sstevel@tonic-gate } else { 2447c478bd9Sstevel@tonic-gate (void) cb_prom_stop_self(); 2457c478bd9Sstevel@tonic-gate cb_park_err(cpu_id); 2467c478bd9Sstevel@tonic-gate } 2477c478bd9Sstevel@tonic-gate } 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate 2507c478bd9Sstevel@tonic-gate /* 2517c478bd9Sstevel@tonic-gate * when any cpu is started, they naturally rely on the prom for all 2527c478bd9Sstevel@tonic-gate * text/data translations until switching to the kernel trap table. 2537c478bd9Sstevel@tonic-gate * to jump back into the cpr module and to restart slave cpus, cprboot 2547c478bd9Sstevel@tonic-gate * needs to reinstall translations for the nucleus and some cpr pages. 2557c478bd9Sstevel@tonic-gate * 2567c478bd9Sstevel@tonic-gate * the easy method is creating one set of global translations available 2577c478bd9Sstevel@tonic-gate * to all cpus with prom_map(); unfortunately, a 4MB "map" request will 2587c478bd9Sstevel@tonic-gate * allocate and overwrite a few pages, and these are often kernel pages 2597c478bd9Sstevel@tonic-gate * that were just restored. 2607c478bd9Sstevel@tonic-gate * 2617c478bd9Sstevel@tonic-gate * to solve the "map" problem, all cpus install their own set of locked 2627c478bd9Sstevel@tonic-gate * tlb entries to translate the nucleus and parts of the cpr module; 2637c478bd9Sstevel@tonic-gate * after all cpus have switched to kernel traps, any of these locked 2647c478bd9Sstevel@tonic-gate * tlb entries for pages outside the nucleus will be cleared. 2657c478bd9Sstevel@tonic-gate */ 2667c478bd9Sstevel@tonic-gate int 2677c478bd9Sstevel@tonic-gate cb_mpsetup(void) 2687c478bd9Sstevel@tonic-gate { 2697c478bd9Sstevel@tonic-gate struct sun4u_cpu_info *scip, *tail; 2707c478bd9Sstevel@tonic-gate int timeout, ncpu; 2717c478bd9Sstevel@tonic-gate char *str, *intf; 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate intf = "SUNW,stop-cpu-by-cpuid"; 2747c478bd9Sstevel@tonic-gate has_scbc = (prom_test(intf) == 0); 2757c478bd9Sstevel@tonic-gate CB_VPRINTF(("\n\"%s\" test %d\n", intf, has_scbc)); 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate str = "cb_mp_setup"; 2787c478bd9Sstevel@tonic-gate CB_VPRINTF((ent_fmt, str, entry)); 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate /* 2817c478bd9Sstevel@tonic-gate * launch any slave cpus from the .sci array into cprboot text 2827c478bd9Sstevel@tonic-gate * and wait about a second for them to checkin with slave_set 2837c478bd9Sstevel@tonic-gate */ 2847c478bd9Sstevel@tonic-gate ncpu = 0; 2857c478bd9Sstevel@tonic-gate CPUSET_ZERO(slave_set); 2867c478bd9Sstevel@tonic-gate for (scip = mdinfo.sci, tail = scip + NCPU; scip < tail; scip++) { 2877c478bd9Sstevel@tonic-gate if (scip->node == 0 || scip->cpu_id == cb_mid) 2887c478bd9Sstevel@tonic-gate continue; 2897c478bd9Sstevel@tonic-gate (void) prom_startcpu(scip->node, 2907c478bd9Sstevel@tonic-gate (caddr_t)cpu_launch, scip->cpu_id); 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate for (timeout = TIMEOUT_MSECS; timeout; timeout--) { 2937c478bd9Sstevel@tonic-gate if (CPU_IN_SET(slave_set, scip->cpu_id)) 2947c478bd9Sstevel@tonic-gate break; 2957c478bd9Sstevel@tonic-gate cb_usec_wait(MILLISEC); 2967c478bd9Sstevel@tonic-gate } 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate if (timeout == 0) { 2997c478bd9Sstevel@tonic-gate prom_printf("\n%s: cpu did not start, " 3007c478bd9Sstevel@tonic-gate "cpu_id %d, node 0x%x\n", 3017c478bd9Sstevel@tonic-gate prog, scip->cpu_id, scip->node); 3027c478bd9Sstevel@tonic-gate return (ERR); 3037c478bd9Sstevel@tonic-gate } 3047c478bd9Sstevel@tonic-gate 3057c478bd9Sstevel@tonic-gate if (has_scbc && prom_stopcpu_bycpuid(scip->cpu_id)) 3067c478bd9Sstevel@tonic-gate cb_park_err(scip->cpu_id); 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate ncpu++; 3097c478bd9Sstevel@tonic-gate } 3107c478bd9Sstevel@tonic-gate 3117c478bd9Sstevel@tonic-gate if (verbose && ncpu) 3127c478bd9Sstevel@tonic-gate prom_printf("\n%s: slave cpu count: %d\n", str, ncpu); 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate return (0); 3157c478bd9Sstevel@tonic-gate } 316