11ae08745Sheppo /* 21ae08745Sheppo * CDDL HEADER START 31ae08745Sheppo * 41ae08745Sheppo * The contents of this file are subject to the terms of the 51ae08745Sheppo * Common Development and Distribution License (the "License"). 61ae08745Sheppo * You may not use this file except in compliance with the License. 71ae08745Sheppo * 81ae08745Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91ae08745Sheppo * or http://www.opensolaris.org/os/licensing. 101ae08745Sheppo * See the License for the specific language governing permissions 111ae08745Sheppo * and limitations under the License. 121ae08745Sheppo * 131ae08745Sheppo * When distributing Covered Code, include this CDDL HEADER in each 141ae08745Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151ae08745Sheppo * If applicable, add the following below this CDDL HEADER, with the 161ae08745Sheppo * fields enclosed by brackets "[]" replaced with your own identifying 171ae08745Sheppo * information: Portions Copyright [yyyy] [name of copyright owner] 181ae08745Sheppo * 191ae08745Sheppo * CDDL HEADER END 201ae08745Sheppo */ 211ae08745Sheppo 221ae08745Sheppo /* 231ae08745Sheppo * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 241ae08745Sheppo * Use is subject to license terms. 251ae08745Sheppo */ 261ae08745Sheppo 271ae08745Sheppo #pragma ident "%Z%%M% %I% %E% SMI" 281ae08745Sheppo 291ae08745Sheppo #include <sys/promif_impl.h> 301ae08745Sheppo #include <sys/machsystm.h> 311ae08745Sheppo #include <sys/lpad.h> 321ae08745Sheppo #include <sys/vmsystm.h> 331ae08745Sheppo #include <sys/prom_plat.h> 341ae08745Sheppo #include <sys/ldoms.h> 351ae08745Sheppo #include <sys/kobj.h> 361ae08745Sheppo #include <sys/reboot.h> 371ae08745Sheppo #include <sys/hypervisor_api.h> 38*4bac2208Snarayan #include <sys/mdesc.h> 39*4bac2208Snarayan #include <sys/mach_descrip.h> 401ae08745Sheppo 411ae08745Sheppo #ifndef _KMDB 421ae08745Sheppo static processorid_t cif_cpu; 431ae08745Sheppo static struct translation *cif_prom_trans; 441ae08745Sheppo static size_t cif_prom_ntrans; 451ae08745Sheppo 461ae08745Sheppo int cif_cpu_mp_ready; 471ae08745Sheppo int (*prom_cif_handler)(void *) = NULL; 481ae08745Sheppo #endif 491ae08745Sheppo 501ae08745Sheppo #ifdef DEBUG 511ae08745Sheppo uint_t cif_debug; 521ae08745Sheppo #endif /* DEBUG */ 531ae08745Sheppo 541ae08745Sheppo extern int (*cif_handler)(void *); 551ae08745Sheppo 561ae08745Sheppo typedef struct { 571ae08745Sheppo char *name; 581ae08745Sheppo cif_func_t func; 591ae08745Sheppo } cif_callback_t; 601ae08745Sheppo 611ae08745Sheppo static cif_callback_t cb_table[] = { 621ae08745Sheppo { "getprop", promif_getprop }, 631ae08745Sheppo { "getproplen", promif_getproplen }, 641ae08745Sheppo { "nextprop", promif_nextprop }, 651ae08745Sheppo { "peer", promif_nextnode }, 661ae08745Sheppo { "child", promif_childnode }, 671ae08745Sheppo { "parent", promif_parentnode }, 681ae08745Sheppo { "enter", promif_enter_mon }, 691ae08745Sheppo { "exit", promif_exit_to_mon }, 701ae08745Sheppo { "boot", promif_reboot }, 711ae08745Sheppo { "write", promif_write }, 721ae08745Sheppo { "read", promif_read }, 731ae08745Sheppo { "interpret", promif_interpret }, 741ae08745Sheppo { "finddevice", promif_finddevice }, 751ae08745Sheppo { "instance-to-package", promif_instance_to_package }, 761ae08745Sheppo #ifndef _KMDB 771ae08745Sheppo { "setprop", promif_setprop }, 781ae08745Sheppo { "test", promif_test }, 791ae08745Sheppo { "instance-to-path", promif_instance_to_path }, 801ae08745Sheppo { "SUNW,power-off", promif_power_off }, 811ae08745Sheppo { "SUNW,asr-list-keys-len", promif_asr_list_keys_len }, 821ae08745Sheppo { "SUNW,asr-list-keys", promif_asr_list_keys }, 831ae08745Sheppo { "SUNW,asr-export-len", promif_asr_export_len }, 841ae08745Sheppo { "SUNW,asr-export", promif_asr_export }, 851ae08745Sheppo { "SUNW,set-security-key", promif_set_security_key }, 861ae08745Sheppo { "SUNW,get-security-key", promif_get_security_key }, 871ae08745Sheppo { "SUNW,start-cpu-by-cpuid", promif_start_cpu }, 881ae08745Sheppo { "SUNW,set-trap-table", promif_set_mmfsa_traptable }, 891ae08745Sheppo { "SUNW,set-sun4v-api-version", promif_set_sun4v_api_version }, 901ae08745Sheppo { "SUNW,get-sun4v-api-version", promif_get_sun4v_api_version }, 911ae08745Sheppo #endif 921ae08745Sheppo { NULL, NULL } 931ae08745Sheppo }; 941ae08745Sheppo 951ae08745Sheppo cif_func_t 961ae08745Sheppo promif_find_cif_callback(char *opname) 971ae08745Sheppo { 981ae08745Sheppo cif_callback_t *cb; 991ae08745Sheppo 1001ae08745Sheppo if (opname == NULL) 1011ae08745Sheppo return (NULL); 1021ae08745Sheppo 1031ae08745Sheppo for (cb = cb_table; cb->name; cb++) { 1041ae08745Sheppo if (prom_strcmp(cb->name, opname) == 0) 1051ae08745Sheppo break; 1061ae08745Sheppo } 1071ae08745Sheppo 1081ae08745Sheppo return (cb->func); 1091ae08745Sheppo } 1101ae08745Sheppo 1111ae08745Sheppo static int 1121ae08745Sheppo kern_cif_handler(void *p) 1131ae08745Sheppo { 1141ae08745Sheppo cell_t *ci = (cell_t *)p; 1151ae08745Sheppo char *opname; 1161ae08745Sheppo cif_func_t func; 1171ae08745Sheppo int rv; 1181ae08745Sheppo 1191ae08745Sheppo ASSERT(cif_handler == kern_cif_handler); 1201ae08745Sheppo 1211ae08745Sheppo #ifndef _KMDB 1221ae08745Sheppo cif_cpu = getprocessorid(); 1231ae08745Sheppo #endif 1241ae08745Sheppo 1251ae08745Sheppo opname = p1275_cell2ptr(ci[0]); 1261ae08745Sheppo 1271ae08745Sheppo /* lookup the callback for the desired operation */ 1281ae08745Sheppo func = promif_find_cif_callback(opname); 1291ae08745Sheppo 1301ae08745Sheppo if (func == NULL) { 1311ae08745Sheppo #ifdef _KMDB 1321ae08745Sheppo prom_fatal_error("sun4v unsupported CIFs\n"); 1331ae08745Sheppo #else 1341ae08745Sheppo cmn_err(CE_CONT, "!sun4v unsupported CIF: %s\n", opname); 1351ae08745Sheppo return (-1); 1361ae08745Sheppo #endif 1371ae08745Sheppo } 1381ae08745Sheppo 1391ae08745Sheppo /* callback found, execute it */ 1401ae08745Sheppo rv = func(p); 1411ae08745Sheppo 1421ae08745Sheppo #ifndef _KMDB 1431ae08745Sheppo cif_cpu = -1; 1441ae08745Sheppo #endif 1451ae08745Sheppo 1461ae08745Sheppo return (rv); 1471ae08745Sheppo } 1481ae08745Sheppo 1491ae08745Sheppo #ifdef _KMDB 1501ae08745Sheppo 1511ae08745Sheppo void 1521ae08745Sheppo cif_init(char *pgmname, caddr_t root, ihandle_t in, ihandle_t out, 1531ae08745Sheppo phandle_t pin, phandle_t pout, pnode_t chosen, pnode_t options) 1541ae08745Sheppo { 1551ae08745Sheppo /* initialize pointer to a copy of OBP device tree */ 1561ae08745Sheppo promif_stree_setroot(root); 1571ae08745Sheppo 1581ae08745Sheppo promif_set_nodes(chosen, options); 1591ae08745Sheppo 1601ae08745Sheppo /* initialize io parameters */ 1611ae08745Sheppo promif_io_init(in, out, pin, pout); 1621ae08745Sheppo 1631ae08745Sheppo /* 1641ae08745Sheppo * Switch CIF handler to the kernel. 1651ae08745Sheppo */ 1661ae08745Sheppo if (pgmname != NULL) 1671ae08745Sheppo prom_init(pgmname, (void *)kern_cif_handler); 1681ae08745Sheppo else 1691ae08745Sheppo cif_handler = kern_cif_handler; 1701ae08745Sheppo } 1711ae08745Sheppo 1721ae08745Sheppo #else 1731ae08745Sheppo 1741ae08745Sheppo static void cache_prom_data(void); 1751ae08745Sheppo 1761ae08745Sheppo /* 1771ae08745Sheppo * This function returns 1 if the current thread is executing in 1781ae08745Sheppo * the CIF and 0 otherwise. This is useful information to know 1791ae08745Sheppo * since code that implements CIF handlers can assume that it has 1801ae08745Sheppo * gone through the kern_preprom() entry point, implying it is 1811ae08745Sheppo * running single threaded, has preemption disabled, etc. 1821ae08745Sheppo */ 1831ae08745Sheppo int 1841ae08745Sheppo promif_in_cif(void) 1851ae08745Sheppo { 1861ae08745Sheppo int mycpuid = getprocessorid(); 1871ae08745Sheppo 1881ae08745Sheppo return ((cif_cpu == mycpuid) ? 1 : 0); 1891ae08745Sheppo } 1901ae08745Sheppo 191*4bac2208Snarayan /* 192*4bac2208Snarayan * Check that all cpus in the MD are within range (< NCPU). Attempt 193*4bac2208Snarayan * to stop any that aren't. 194*4bac2208Snarayan */ 195*4bac2208Snarayan static void 196*4bac2208Snarayan cif_check_cpus(void) 197*4bac2208Snarayan { 198*4bac2208Snarayan md_t *mdp; 199*4bac2208Snarayan mde_cookie_t rootnode; 200*4bac2208Snarayan size_t listsz; 201*4bac2208Snarayan int i; 202*4bac2208Snarayan mde_cookie_t *listp = NULL; 203*4bac2208Snarayan int num_nodes; 204*4bac2208Snarayan uint64_t cpuid; 205*4bac2208Snarayan int status; 206*4bac2208Snarayan 207*4bac2208Snarayan mdp = md_get_handle(); 208*4bac2208Snarayan ASSERT(mdp); 209*4bac2208Snarayan 210*4bac2208Snarayan rootnode = md_root_node(mdp); 211*4bac2208Snarayan ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE); 212*4bac2208Snarayan 213*4bac2208Snarayan num_nodes = md_node_count(mdp); 214*4bac2208Snarayan ASSERT(num_nodes > 0); 215*4bac2208Snarayan 216*4bac2208Snarayan listsz = num_nodes * sizeof (mde_cookie_t); 217*4bac2208Snarayan listp = kmem_zalloc(listsz, KM_SLEEP); 218*4bac2208Snarayan 219*4bac2208Snarayan num_nodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "cpu"), 220*4bac2208Snarayan md_find_name(mdp, "fwd"), listp); 221*4bac2208Snarayan 222*4bac2208Snarayan if (num_nodes <= 0) 223*4bac2208Snarayan goto done; 224*4bac2208Snarayan 225*4bac2208Snarayan for (i = 0; i < num_nodes; i++) { 226*4bac2208Snarayan if (md_get_prop_val(mdp, listp[i], "id", &cpuid)) { 227*4bac2208Snarayan cmn_err(CE_WARN, "cif_check_cpus: " 228*4bac2208Snarayan "CPU instance %d has no 'id' property", i); 229*4bac2208Snarayan continue; 230*4bac2208Snarayan } 231*4bac2208Snarayan 232*4bac2208Snarayan mutex_enter(&cpu_lock); 233*4bac2208Snarayan 234*4bac2208Snarayan if (cpuid >= NCPU) { 235*4bac2208Snarayan status = stopcpu_bycpuid(cpuid); 236*4bac2208Snarayan if (status != 0 && status != ENOTSUP) 237*4bac2208Snarayan cmn_err(CE_PANIC, "failed to stop cpu %lu (%d)", 238*4bac2208Snarayan cpuid, status); 239*4bac2208Snarayan } 240*4bac2208Snarayan 241*4bac2208Snarayan mutex_exit(&cpu_lock); 242*4bac2208Snarayan } 243*4bac2208Snarayan 244*4bac2208Snarayan done: 245*4bac2208Snarayan kmem_free(listp, listsz); 246*4bac2208Snarayan } 247*4bac2208Snarayan 2481ae08745Sheppo void 2491ae08745Sheppo cif_init(void) 2501ae08745Sheppo { 2511ae08745Sheppo void (*kmdb_cb)(void); 2521ae08745Sheppo uint64_t rtba; 2531ae08745Sheppo uint64_t rv; 2541ae08745Sheppo 2551ae08745Sheppo /* 2561ae08745Sheppo * Check if domaining is enabled. If not, do not 2571ae08745Sheppo * initialize the kernel CIF handler. 2581ae08745Sheppo */ 259*4bac2208Snarayan if (!(domaining_capabilities & DOMAINING_ENABLED)) 2601ae08745Sheppo return; 2611ae08745Sheppo 2621ae08745Sheppo /* 2631ae08745Sheppo * Cache PROM data that is needed later, e.g. a shadow 2641ae08745Sheppo * copy of the device tree, IO mappings, etc. 2651ae08745Sheppo */ 2661ae08745Sheppo cache_prom_data(); 2671ae08745Sheppo 2681ae08745Sheppo /* 2691ae08745Sheppo * Prepare to take over the get/set of environmental variables. 2701ae08745Sheppo */ 2711ae08745Sheppo promif_prop_init(); 2721ae08745Sheppo 2731ae08745Sheppo /* 2741ae08745Sheppo * Switch CIF handler to the kernel. 2751ae08745Sheppo */ 2761ae08745Sheppo prom_cif_handler = cif_handler; 2771ae08745Sheppo 2781ae08745Sheppo promif_preprom(); 2791ae08745Sheppo cif_handler = kern_cif_handler; 2801ae08745Sheppo 2811ae08745Sheppo /* 2821ae08745Sheppo * Take over rtba for the boot CPU. The rtba for 2831ae08745Sheppo * all other CPUs are set as they enter the system. 2841ae08745Sheppo */ 2851ae08745Sheppo rtba = va_to_pa(&trap_table); 2861ae08745Sheppo if ((rv = hv_cpu_set_rtba(&rtba)) != H_EOK) 2871ae08745Sheppo panic("hv_cpu_set_rtba failed: %ld\n", rv); 2881ae08745Sheppo 2891ae08745Sheppo promif_postprom(); 2901ae08745Sheppo 2911ae08745Sheppo /* 2921ae08745Sheppo * If the system has been booted with kmdb we need kmdb to 2931ae08745Sheppo * use the kernel cif handler instead of the PROM cif handler. 2941ae08745Sheppo */ 2951ae08745Sheppo if (boothowto & RB_KMDB) { 2961ae08745Sheppo kmdb_cb = (void (*)(void))modlookup("misc/kmdbmod", 2971ae08745Sheppo "kctl_switch_promif"); 2981ae08745Sheppo ASSERT(kmdb_cb != NULL); 2991ae08745Sheppo (*kmdb_cb)(); 3001ae08745Sheppo } 301*4bac2208Snarayan 302*4bac2208Snarayan cif_check_cpus(); 3031ae08745Sheppo } 3041ae08745Sheppo 3051ae08745Sheppo static void 3061ae08745Sheppo cache_prom_data(void) 3071ae08745Sheppo { 3081ae08745Sheppo /* initialize copy of OBP device tree */ 3091ae08745Sheppo promif_stree_init(); 3101ae08745Sheppo 3111ae08745Sheppo /* initialize io parameters */ 3121ae08745Sheppo promif_io_init(); 3131ae08745Sheppo } 3141ae08745Sheppo 3151ae08745Sheppo 3161ae08745Sheppo /* 3171ae08745Sheppo * Platform-specific actions to be taken when all cpus are running 3181ae08745Sheppo * in the OS. 3191ae08745Sheppo */ 3201ae08745Sheppo void 3211ae08745Sheppo cpu_mp_init(void) 3221ae08745Sheppo { 323*4bac2208Snarayan if (!(domaining_capabilities & DOMAINING_ENABLED)) 3241ae08745Sheppo return; 3251ae08745Sheppo 3261ae08745Sheppo cif_cpu_mp_ready = 1; 3271ae08745Sheppo } 3281ae08745Sheppo 3291ae08745Sheppo #endif /* _KMDB */ 330