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
5*fea9cb91Slq  * Common Development and Distribution License (the "License").
6*fea9cb91Slq  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21*fea9cb91Slq 
227c478bd9Sstevel@tonic-gate /*
23*fea9cb91Slq  * Copyright 2006 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/promif.h>
307c478bd9Sstevel@tonic-gate #include <sys/promimpl.h>
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate /*
337c478bd9Sstevel@tonic-gate  * The functions in this file are used to control the pre- and post-processing
347c478bd9Sstevel@tonic-gate  * functions that bracket calls to the OBP CIF handler.  One set, promif_preprom
357c478bd9Sstevel@tonic-gate  * and promif_postprom, are provided for general kernel use.  The other set,
367c478bd9Sstevel@tonic-gate  * promif_preout and promif_postout, are used by the power management subsystem
377c478bd9Sstevel@tonic-gate  * to ensure that the framebuffer is active when PROM functions that interact
387c478bd9Sstevel@tonic-gate  * with the console are invoked.
397c478bd9Sstevel@tonic-gate  *
407c478bd9Sstevel@tonic-gate  * In some cases, the operation of these functions must be suppressed.  As such,
417c478bd9Sstevel@tonic-gate  * this file provides the ability to suspend and resume use of both sets
427c478bd9Sstevel@tonic-gate  * simultaneously.  Complicating matters is the fact that both current uses of
437c478bd9Sstevel@tonic-gate  * the pre- and post-processor suspension and resume facilities, kmdb and CPR
447c478bd9Sstevel@tonic-gate  * may be used simultaneously.  We therefore support normal operation and two
457c478bd9Sstevel@tonic-gate  * levels of suspension.  The pre- and post-processing functions are only
467c478bd9Sstevel@tonic-gate  * called during normal operation.  With each suspension request, this
477c478bd9Sstevel@tonic-gate  * subsystem enters the first suspension level, or passes to the second
487c478bd9Sstevel@tonic-gate  * suspension level, as appropriate.  Resume calls decrement the suspension
497c478bd9Sstevel@tonic-gate  * level.  Only two nested suspensions are supported.
507c478bd9Sstevel@tonic-gate  *
517c478bd9Sstevel@tonic-gate  * As indicated above, the two current users are CPR and kmdb.  CPR must prevent
527c478bd9Sstevel@tonic-gate  * kernel accesses outside of the nucleus page during the late stages of system
537c478bd9Sstevel@tonic-gate  * suspension and during the early stages of system resumption.  As such, the
547c478bd9Sstevel@tonic-gate  * PM-related processing must not occur during these times.
557c478bd9Sstevel@tonic-gate  *
567c478bd9Sstevel@tonic-gate  * The platform-specific portions of kmdb live in the platmods, and thus execute
577c478bd9Sstevel@tonic-gate  * in the linker environment of the platmods.  That is, any promif calls they
587c478bd9Sstevel@tonic-gate  * may make are executed by the kernel copies of those functions, rather than
597c478bd9Sstevel@tonic-gate  * the versions included with kmdb.  The only difference between the two copies
607c478bd9Sstevel@tonic-gate  * being the nonuse of the pre- and post-processing functions in the kmdb
617c478bd9Sstevel@tonic-gate  * versions, we must ensure that these functions are not used when the kmdb
627c478bd9Sstevel@tonic-gate  * platmod code executes.  Accordingly, kmdb disables the pre- and post-
637c478bd9Sstevel@tonic-gate  * processing functions via the KDI prior to passing control to the platmod
647c478bd9Sstevel@tonic-gate  * debugger code.
657c478bd9Sstevel@tonic-gate  */
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate static int promif_suspendlevel;
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate static promif_preprom_f *promif_preprom_fn;
707c478bd9Sstevel@tonic-gate static promif_postprom_f *promif_postprom_fn;
717c478bd9Sstevel@tonic-gate 
72*fea9cb91Slq /*
73*fea9cb91Slq  * When this is set, the PROM output functions attempt to
74*fea9cb91Slq  * redirect output to the kernel terminal emulator.
75*fea9cb91Slq  */
76*fea9cb91Slq promif_redir_t promif_redirect;
77*fea9cb91Slq promif_redir_arg_t promif_redirect_arg;
78*fea9cb91Slq 
79*fea9cb91Slq /*
80*fea9cb91Slq  * Sets new callback and argument, returns previous callback.
81*fea9cb91Slq  */
82*fea9cb91Slq void
prom_set_stdout_redirect(promif_redir_t new_fn,promif_redir_arg_t opaque_arg)83*fea9cb91Slq prom_set_stdout_redirect(promif_redir_t new_fn, promif_redir_arg_t opaque_arg)
84*fea9cb91Slq {
85*fea9cb91Slq 	promif_redirect_arg = opaque_arg;
86*fea9cb91Slq 	promif_redirect = new_fn;
87*fea9cb91Slq }
88*fea9cb91Slq 
897c478bd9Sstevel@tonic-gate void
prom_set_preprom(promif_preprom_f * new)907c478bd9Sstevel@tonic-gate prom_set_preprom(promif_preprom_f *new)
917c478bd9Sstevel@tonic-gate {
927c478bd9Sstevel@tonic-gate 	promif_preprom_fn = new;
937c478bd9Sstevel@tonic-gate }
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate void
prom_set_postprom(promif_postprom_f * new)967c478bd9Sstevel@tonic-gate prom_set_postprom(promif_postprom_f *new)
977c478bd9Sstevel@tonic-gate {
987c478bd9Sstevel@tonic-gate 	promif_postprom_fn = new;
997c478bd9Sstevel@tonic-gate }
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate void
promif_preprom(void)1027c478bd9Sstevel@tonic-gate promif_preprom(void)
1037c478bd9Sstevel@tonic-gate {
1047c478bd9Sstevel@tonic-gate 	if (promif_suspendlevel == 0 && promif_preprom_fn != NULL)
1057c478bd9Sstevel@tonic-gate 		promif_preprom_fn();
1067c478bd9Sstevel@tonic-gate }
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate void
promif_postprom(void)1097c478bd9Sstevel@tonic-gate promif_postprom(void)
1107c478bd9Sstevel@tonic-gate {
1117c478bd9Sstevel@tonic-gate 	if (promif_suspendlevel == 0 && promif_postprom_fn != NULL)
1127c478bd9Sstevel@tonic-gate 		promif_postprom_fn();
1137c478bd9Sstevel@tonic-gate }
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate /*
1167c478bd9Sstevel@tonic-gate  * The reader will note that the layout and calling conventions of the
1177c478bd9Sstevel@tonic-gate  * prom_preout and prom_postout functions differ from the prom_preprom and
1187c478bd9Sstevel@tonic-gate  * prom_postprom functions, above.  At the time the preout and postout
1197c478bd9Sstevel@tonic-gate  * functions are initialized, kernel startup is well underway.  There exists
1207c478bd9Sstevel@tonic-gate  * a race condition whereby a PROM call may begin before preout has been
1217c478bd9Sstevel@tonic-gate  * initialized, and may end after postout has been initialized.  In such
1227c478bd9Sstevel@tonic-gate  * cases, there will be a call to postout without a corresponding preout
1237c478bd9Sstevel@tonic-gate  * call.  The preprom and postprom calls above are initialized early enough
1247c478bd9Sstevel@tonic-gate  * that this race condition does not occur.
1257c478bd9Sstevel@tonic-gate  *
1267c478bd9Sstevel@tonic-gate  * To avoid the race condition, the preout/postout functions are designed
1277c478bd9Sstevel@tonic-gate  * such that the initialization is atomic.  Further, the preout call returns
1287c478bd9Sstevel@tonic-gate  * a data structure that includes a pointer to the postout function that
1297c478bd9Sstevel@tonic-gate  * corresponds to the invoked preout function.  This ensures that the preout
1307c478bd9Sstevel@tonic-gate  * and postout functions will only be used as a matched set.
1317c478bd9Sstevel@tonic-gate  */
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate static void
null_outfunc(void)1347c478bd9Sstevel@tonic-gate null_outfunc(void)
1357c478bd9Sstevel@tonic-gate {
1367c478bd9Sstevel@tonic-gate }
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate static promif_owrap_t nullwrapper =
1397c478bd9Sstevel@tonic-gate {
1407c478bd9Sstevel@tonic-gate 	null_outfunc,
1417c478bd9Sstevel@tonic-gate 	null_outfunc
1427c478bd9Sstevel@tonic-gate };
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate static promif_owrap_t *wrapper = &nullwrapper;
1457c478bd9Sstevel@tonic-gate static promif_owrap_t pmwrapper;
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate promif_owrap_t
promif_preout(void)1487c478bd9Sstevel@tonic-gate *promif_preout(void)
1497c478bd9Sstevel@tonic-gate {
1507c478bd9Sstevel@tonic-gate 	promif_owrap_t *ow;
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	if (promif_suspendlevel > 0)
1537c478bd9Sstevel@tonic-gate 		return (&nullwrapper);
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	ow = wrapper;
1567c478bd9Sstevel@tonic-gate 	if (ow->preout != NULL)
1577c478bd9Sstevel@tonic-gate 		(ow->preout)();
1587c478bd9Sstevel@tonic-gate 	return (ow);
1597c478bd9Sstevel@tonic-gate }
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate void
promif_postout(promif_owrap_t * ow)1627c478bd9Sstevel@tonic-gate promif_postout(promif_owrap_t *ow)
1637c478bd9Sstevel@tonic-gate {
1647c478bd9Sstevel@tonic-gate 	if (ow->postout != NULL)
1657c478bd9Sstevel@tonic-gate 		(ow->postout)();
1667c478bd9Sstevel@tonic-gate }
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate void
prom_set_outfuncs(void (* pref)(void),void (* postf)(void))1697c478bd9Sstevel@tonic-gate prom_set_outfuncs(void (*pref)(void), void (*postf)(void))
1707c478bd9Sstevel@tonic-gate {
1717c478bd9Sstevel@tonic-gate 	pmwrapper.preout = pref;
1727c478bd9Sstevel@tonic-gate 	pmwrapper.postout = postf;
1737c478bd9Sstevel@tonic-gate 	wrapper = &pmwrapper;
1747c478bd9Sstevel@tonic-gate }
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate void
prom_suspend_prepost(void)1777c478bd9Sstevel@tonic-gate prom_suspend_prepost(void)
1787c478bd9Sstevel@tonic-gate {
1797c478bd9Sstevel@tonic-gate 	ASSERT(promif_suspendlevel < 2);
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	promif_suspendlevel++;
1827c478bd9Sstevel@tonic-gate }
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate void
prom_resume_prepost(void)1857c478bd9Sstevel@tonic-gate prom_resume_prepost(void)
1867c478bd9Sstevel@tonic-gate {
1877c478bd9Sstevel@tonic-gate 	ASSERT(promif_suspendlevel >= 0);
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	promif_suspendlevel--;
1907c478bd9Sstevel@tonic-gate }
191