1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/promif.h> 30 #include <sys/promimpl.h> 31 32 /* 33 * The functions in this file are used to control the pre- and post-processing 34 * functions that bracket calls to the OBP CIF handler. One set, promif_preprom 35 * and promif_postprom, are provided for general kernel use. The other set, 36 * promif_preout and promif_postout, are used by the power management subsystem 37 * to ensure that the framebuffer is active when PROM functions that interact 38 * with the console are invoked. 39 * 40 * In some cases, the operation of these functions must be suppressed. As such, 41 * this file provides the ability to suspend and resume use of both sets 42 * simultaneously. Complicating matters is the fact that both current uses of 43 * the pre- and post-processor suspension and resume facilities, kmdb and CPR 44 * may be used simultaneously. We therefore support normal operation and two 45 * levels of suspension. The pre- and post-processing functions are only 46 * called during normal operation. With each suspension request, this 47 * subsystem enters the first suspension level, or passes to the second 48 * suspension level, as appropriate. Resume calls decrement the suspension 49 * level. Only two nested suspensions are supported. 50 * 51 * As indicated above, the two current users are CPR and kmdb. CPR must prevent 52 * kernel accesses outside of the nucleus page during the late stages of system 53 * suspension and during the early stages of system resumption. As such, the 54 * PM-related processing must not occur during these times. 55 * 56 * The platform-specific portions of kmdb live in the platmods, and thus execute 57 * in the linker environment of the platmods. That is, any promif calls they 58 * may make are executed by the kernel copies of those functions, rather than 59 * the versions included with kmdb. The only difference between the two copies 60 * being the nonuse of the pre- and post-processing functions in the kmdb 61 * versions, we must ensure that these functions are not used when the kmdb 62 * platmod code executes. Accordingly, kmdb disables the pre- and post- 63 * processing functions via the KDI prior to passing control to the platmod 64 * debugger code. 65 */ 66 67 static int promif_suspendlevel; 68 69 static promif_preprom_f *promif_preprom_fn; 70 static promif_postprom_f *promif_postprom_fn; 71 72 void 73 prom_set_preprom(promif_preprom_f *new) 74 { 75 promif_preprom_fn = new; 76 } 77 78 void 79 prom_set_postprom(promif_postprom_f *new) 80 { 81 promif_postprom_fn = new; 82 } 83 84 void 85 promif_preprom(void) 86 { 87 if (promif_suspendlevel == 0 && promif_preprom_fn != NULL) 88 promif_preprom_fn(); 89 } 90 91 void 92 promif_postprom(void) 93 { 94 if (promif_suspendlevel == 0 && promif_postprom_fn != NULL) 95 promif_postprom_fn(); 96 } 97 98 /* 99 * The reader will note that the layout and calling conventions of the 100 * prom_preout and prom_postout functions differ from the prom_preprom and 101 * prom_postprom functions, above. At the time the preout and postout 102 * functions are initialized, kernel startup is well underway. There exists 103 * a race condition whereby a PROM call may begin before preout has been 104 * initialized, and may end after postout has been initialized. In such 105 * cases, there will be a call to postout without a corresponding preout 106 * call. The preprom and postprom calls above are initialized early enough 107 * that this race condition does not occur. 108 * 109 * To avoid the race condition, the preout/postout functions are designed 110 * such that the initialization is atomic. Further, the preout call returns 111 * a data structure that includes a pointer to the postout function that 112 * corresponds to the invoked preout function. This ensures that the preout 113 * and postout functions will only be used as a matched set. 114 */ 115 116 static void 117 null_outfunc(void) 118 { 119 } 120 121 static promif_owrap_t nullwrapper = 122 { 123 null_outfunc, 124 null_outfunc 125 }; 126 127 static promif_owrap_t *wrapper = &nullwrapper; 128 static promif_owrap_t pmwrapper; 129 130 promif_owrap_t 131 *promif_preout(void) 132 { 133 promif_owrap_t *ow; 134 135 if (promif_suspendlevel > 0) 136 return (&nullwrapper); 137 138 ow = wrapper; 139 if (ow->preout != NULL) 140 (ow->preout)(); 141 return (ow); 142 } 143 144 void 145 promif_postout(promif_owrap_t *ow) 146 { 147 if (ow->postout != NULL) 148 (ow->postout)(); 149 } 150 151 void 152 prom_set_outfuncs(void (*pref)(void), void (*postf)(void)) 153 { 154 pmwrapper.preout = pref; 155 pmwrapper.postout = postf; 156 wrapper = &pmwrapper; 157 } 158 159 void 160 prom_suspend_prepost(void) 161 { 162 ASSERT(promif_suspendlevel < 2); 163 164 promif_suspendlevel++; 165 } 166 167 void 168 prom_resume_prepost(void) 169 { 170 ASSERT(promif_suspendlevel >= 0); 171 172 promif_suspendlevel--; 173 } 174