xref: /illumos-gate/usr/src/uts/sun4v/promif/promif_prop.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 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/types.h>
30 #include <sys/ddi.h>
31 #include <sys/sunddi.h>
32 #include <sys/promif_impl.h>
33 #include <sys/ds.h>
34 #include <sys/modctl.h>
35 #include <sys/ksynch.h>
36 #include <sys/varconfig.h>
37 
38 #ifndef _KMDB
39 
40 #define	PROMIF_DS_TIMEOUT_SEC 15
41 
42 static kmutex_t promif_prop_lock;
43 static kcondvar_t promif_prop_cv;
44 static var_config_msg_t promif_ds_resp;
45 static var_config_resp_t *cfg_rsp = &promif_ds_resp.var_config_resp;
46 static int (*ds_send)();
47 static int (*ds_init)();
48 
49 /*
50  * Domains Services interaction
51  */
52 static ds_svc_hdl_t	ds_primary_handle;
53 static ds_svc_hdl_t	ds_backup_handle;
54 
55 static ds_ver_t		vc_version[] = { { 1, 0 } };
56 
57 #define	VC_NVERS	(sizeof (vc_version) / sizeof (vc_version[0]))
58 
59 static ds_capability_t vc_primary_cap = {
60 	"var-config",		/* svc_id */
61 	vc_version,		/* vers */
62 	VC_NVERS		/* nvers */
63 };
64 
65 static ds_capability_t vc_backup_cap = {
66 	"var-config-backup",	/* svc_id */
67 	vc_version,		/* vers */
68 	VC_NVERS		/* nvers */
69 };
70 
71 static void vc_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t);
72 static void vc_unreg_handler(ds_cb_arg_t);
73 static void vc_data_handler(ds_cb_arg_t, void *, size_t);
74 
75 static ds_clnt_ops_t vc_primary_ops = {
76 	vc_reg_handler,		/* ds_primary_reg_cb */
77 	vc_unreg_handler,	/* ds_primary_unreg_cb */
78 	vc_data_handler,	/* ds_data_cb */
79 	&ds_primary_handle	/* cb_arg */
80 };
81 
82 static ds_clnt_ops_t vc_backup_ops = {
83 	vc_reg_handler,		/* ds_backup_reg_cb */
84 	vc_unreg_handler,	/* ds_backup_unreg_cb */
85 	vc_data_handler,	/* ds_data_cb */
86 	&ds_backup_handle	/* cb_arg */
87 };
88 
89 static void
90 vc_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl)
91 {
92 	_NOTE(ARGUNUSED(ver))
93 
94 	if ((ds_svc_hdl_t *)arg == &ds_primary_handle)
95 		ds_primary_handle = hdl;
96 	else if ((ds_svc_hdl_t *)arg == &ds_backup_handle)
97 		ds_backup_handle = hdl;
98 }
99 
100 static void
101 vc_unreg_handler(ds_cb_arg_t arg)
102 {
103 	if ((ds_svc_hdl_t *)arg == &ds_primary_handle)
104 		ds_primary_handle = DS_INVALID_HDL;
105 	else if ((ds_svc_hdl_t *)arg == &ds_backup_handle)
106 		ds_backup_handle = DS_INVALID_HDL;
107 }
108 
109 static void
110 vc_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
111 {
112 	_NOTE(ARGUNUSED(arg))
113 
114 	bcopy(buf, &promif_ds_resp, buflen);
115 	mutex_enter(&promif_prop_lock);
116 	cv_signal(&promif_prop_cv);
117 	mutex_exit(&promif_prop_lock);
118 }
119 
120 /*
121  * Initialize the linkage with DS (Domain Services).  We assume that
122  * the DS module has already been loaded by the platmod.
123  *
124  * The call to the DS init functions will eventually result in the
125  * invocation of our registration callback handlers, at which time DS
126  * is able to accept requests.
127  */
128 static void
129 promif_ds_init(void)
130 {
131 	static char *me = "promif_ds_init";
132 	int rv;
133 
134 	if ((ds_init =
135 	    (int (*)())modgetsymvalue("ds_cap_init", 0)) == 0) {
136 		cmn_err(CE_WARN, "%s: can't find ds_cap_init", me);
137 		return;
138 	}
139 
140 	if ((ds_send =
141 	    (int (*)())modgetsymvalue("ds_cap_send", 0)) == 0) {
142 		cmn_err(CE_WARN, "%s: can't find ds_cap_send", me);
143 		return;
144 	}
145 
146 	if ((rv = (*ds_init)(&vc_primary_cap, &vc_primary_ops)) != 0) {
147 		cmn_err(CE_NOTE,
148 		    "%s: ds_cap_init failed (primary): %d", me, rv);
149 	}
150 
151 
152 	if ((rv = (*ds_init)(&vc_backup_cap, &vc_backup_ops)) != 0) {
153 		cmn_err(CE_NOTE,
154 		    "%s: ds_cap_init failed (backup): %d", me, rv);
155 	}
156 }
157 
158 /*
159  * Prepare for ldom variable requests.
160  */
161 void
162 promif_prop_init(void)
163 {
164 	mutex_init(&promif_prop_lock, NULL, MUTEX_DEFAULT, NULL);
165 	cv_init(&promif_prop_cv, NULL, CV_DEFAULT, NULL);
166 
167 	promif_ds_init();
168 }
169 
170 
171 /*
172  * Replace the current value of a property string given its name and
173  * new value.
174  */
175 int
176 promif_ldom_setprop(char *name, void *value, int valuelen)
177 {
178 	var_config_msg_t *req;
179 	var_config_set_req_t *setp;
180 	var_config_cmd_t cmd;
181 	ds_svc_hdl_t ds_handle;
182 	int rv;
183 	int namelen = strlen(name);
184 	int paylen = namelen + 1 + valuelen; /* valuelen includes the null */
185 	static char *me = "promif_ldom_setprop";
186 
187 	if (ds_primary_handle != DS_INVALID_HDL)
188 		ds_handle = ds_primary_handle;
189 	else if (ds_backup_handle != DS_INVALID_HDL)
190 		ds_handle = ds_backup_handle;
191 	else
192 		return (-1);
193 
194 	/*
195 	 * Since we are emulating OBP, we must comply with the promif
196 	 * infrastructure and execute only on the originating cpu.
197 	 */
198 	thread_affinity_set(curthread, CPU->cpu_id);
199 
200 	req = kmem_zalloc(sizeof (var_config_hdr_t) + paylen, KM_SLEEP);
201 	req->var_config_cmd = VAR_CONFIG_SET_REQ;
202 	setp = &req->var_config_set;
203 	(void) strcpy(setp->name_and_value, name);
204 	(void) strncpy(&setp->name_and_value[namelen + 1], value, valuelen);
205 
206 	if ((rv = (*ds_send)(ds_handle, req,
207 	    sizeof (var_config_hdr_t) + paylen)) != 0) {
208 		cmn_err(CE_WARN, "%s: ds_cap_send failed: %d", me, rv);
209 		kmem_free(req, sizeof (var_config_hdr_t) + paylen);
210 		thread_affinity_clear(curthread);
211 		return (-1);
212 	}
213 
214 	kmem_free(req, sizeof (var_config_hdr_t) + paylen);
215 
216 	mutex_enter(&promif_prop_lock);
217 	if (cv_timedwait(&promif_prop_cv,
218 	    &promif_prop_lock, lbolt + PROMIF_DS_TIMEOUT_SEC * hz) == -1) {
219 		cmn_err(CE_WARN, "%s: ds response timeout", me);
220 		rv = -1;
221 		goto out;
222 	}
223 
224 	cmd = promif_ds_resp.vc_hdr.cmd;
225 	if (cmd != VAR_CONFIG_SET_RESP) {
226 		cmn_err(CE_WARN, "%s: bad response type: %d", me, cmd);
227 		rv = -1;
228 		goto out;
229 	}
230 	rv = (cfg_rsp->result == VAR_CONFIG_SUCCESS) ? valuelen : -1;
231 
232 out:
233 	mutex_exit(&promif_prop_lock);
234 	thread_affinity_clear(curthread);
235 	return (rv);
236 }
237 
238 int
239 promif_setprop(void *p)
240 {
241 	cell_t	*ci = (cell_t *)p;
242 	pnode_t node;
243 	caddr_t	name;
244 	caddr_t	value;
245 	int	len;
246 
247 	ASSERT(ci[1] == 4);
248 
249 	node  = p1275_cell2dnode(ci[3]);
250 	ASSERT(node == prom_optionsnode());
251 	name  = p1275_cell2ptr(ci[4]);
252 	value = p1275_cell2ptr(ci[5]);
253 	len = p1275_cell2int(ci[6]);
254 
255 	if (promif_stree_getproplen(node, name) != -1)
256 		len = promif_ldom_setprop(name, value, len);
257 
258 	if (len >= 0)
259 		len = promif_stree_setprop(node, name, (void *)value, len);
260 
261 
262 	ci[7] = p1275_int2cell(len);
263 
264 	return ((len == -1) ? len : 0);
265 }
266 
267 #endif
268 
269 int
270 promif_getprop(void *p)
271 {
272 	cell_t	*ci = (cell_t *)p;
273 	pnode_t	node;
274 	caddr_t	name;
275 	caddr_t	value;
276 	int	len;
277 
278 	ASSERT(ci[1] == 4);
279 
280 	node  = p1275_cell2dnode(ci[3]);
281 	name  = p1275_cell2ptr(ci[4]);
282 	value = p1275_cell2ptr(ci[5]);
283 
284 	len = promif_stree_getprop(node, name, value);
285 
286 	ci[7] = p1275_int2cell(len);
287 
288 	return ((len == -1) ? len : 0);
289 }
290 
291 int
292 promif_getproplen(void *p)
293 {
294 	cell_t	*ci = (cell_t *)p;
295 	pnode_t	node;
296 	caddr_t	name;
297 	int	len;
298 
299 	ASSERT(ci[1] == 2);
300 
301 	node = p1275_cell2dnode(ci[3]);
302 	name = p1275_cell2ptr(ci[4]);
303 
304 	len = promif_stree_getproplen(node, name);
305 
306 	ci[5] = p1275_int2cell(len);
307 
308 	return (0);
309 }
310 
311 int
312 promif_nextprop(void *p)
313 {
314 	cell_t	*ci = (cell_t *)p;
315 	pnode_t	node;
316 	caddr_t	prev;
317 	caddr_t	next;
318 
319 	ASSERT(ci[1] == 3);
320 
321 	node = p1275_cell2dnode(ci[3]);
322 	prev = p1275_cell2ptr(ci[4]);
323 	next = p1275_cell2ptr(ci[5]);
324 
325 	(void) promif_stree_nextprop(node, prev, next);
326 
327 	return (0);
328 }
329