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