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