promif_prop.c revision d3d50737e566cade9a08d73d2af95105ac7cd960
2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
3701N/A
2N/A/*
2N/A * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
32N/A * Use is subject to license terms.
32N/A */
313N/A
313N/A#include <sys/types.h>
313N/A#include <sys/ddi.h>
313N/A#include <sys/sunddi.h>
313N/A#include <sys/promif_impl.h>
313N/A#include <sys/ds.h>
313N/A#include <sys/modctl.h>
313N/A#include <sys/ksynch.h>
313N/A#include <sys/varconfig.h>
2104N/A
2104N/A#ifndef _KMDB
313N/A
313N/A#define PROMIF_DS_TIMEOUT_SEC 15
313N/A
313N/Astatic kmutex_t promif_prop_lock;
2104N/Astatic kcondvar_t promif_prop_cv;
313N/Astatic var_config_msg_t promif_ds_resp;
2104N/Astatic var_config_resp_t *cfg_rsp = &promif_ds_resp.var_config_resp;
127N/Astatic int (*ds_send)();
4357N/Astatic int (*ds_init)();
4357N/A
1256N/A/*
4357N/A * Domains Services interaction
4357N/A */
1256N/Astatic ds_svc_hdl_t ds_primary_handle;
127N/Astatic ds_svc_hdl_t ds_backup_handle;
3817N/A
3817N/Astatic ds_ver_t vc_version[] = { { 1, 0 } };
3817N/A
538N/A#define VC_NVERS (sizeof (vc_version) / sizeof (vc_version[0]))
538N/A
538N/Astatic ds_capability_t vc_primary_cap = {
4488N/A "var-config", /* svc_id */
538N/A vc_version, /* vers */
3817N/A VC_NVERS /* nvers */
538N/A};
327N/A
327N/Astatic ds_capability_t vc_backup_cap = {
327N/A "var-config-backup", /* svc_id */
327N/A vc_version, /* vers */
327N/A VC_NVERS /* nvers */
327N/A};
327N/A
327N/Astatic void vc_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t);
327N/Astatic void vc_unreg_handler(ds_cb_arg_t);
327N/Astatic void vc_data_handler(ds_cb_arg_t, void *, size_t);
327N/A
327N/Astatic ds_clnt_ops_t vc_primary_ops = {
3817N/A vc_reg_handler, /* ds_primary_reg_cb */
3817N/A vc_unreg_handler, /* ds_primary_unreg_cb */
3817N/A vc_data_handler, /* ds_data_cb */
2217N/A &ds_primary_handle /* cb_arg */
2217N/A};
2217N/A
2217N/Astatic ds_clnt_ops_t vc_backup_ops = {
177N/A vc_reg_handler, /* ds_backup_reg_cb */
177N/A vc_unreg_handler, /* ds_backup_unreg_cb */
3951N/A vc_data_handler, /* ds_data_cb */
3951N/A &ds_backup_handle /* cb_arg */
3951N/A};
2N/A
3951N/Astatic void
883N/Avc_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl)
26N/A{
38N/A _NOTE(ARGUNUSED(ver))
38N/A
4518N/A if ((ds_svc_hdl_t *)arg == &ds_primary_handle)
4518N/A ds_primary_handle = hdl;
4518N/A else if ((ds_svc_hdl_t *)arg == &ds_backup_handle)
4518N/A ds_backup_handle = hdl;
1043N/A}
1256N/A
26N/Astatic void
1043N/Avc_unreg_handler(ds_cb_arg_t arg)
1043N/A{
477N/A if ((ds_svc_hdl_t *)arg == &ds_primary_handle)
538N/A ds_primary_handle = DS_INVALID_HDL;
38N/A else if ((ds_svc_hdl_t *)arg == &ds_backup_handle)
3817N/A ds_backup_handle = DS_INVALID_HDL;
6N/A}
2818N/A
3936N/Astatic void
3936N/Avc_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
3936N/A{
2818N/A _NOTE(ARGUNUSED(arg))
2818N/A
2N/A bcopy(buf, &promif_ds_resp, buflen);
34N/A mutex_enter(&promif_prop_lock);
34N/A cv_signal(&promif_prop_cv);
94N/A mutex_exit(&promif_prop_lock);
94N/A}
156N/A
156N/A/*
34N/A * Initialize the linkage with DS (Domain Services). We assume that
59N/A * the DS module has already been loaded by the platmod.
1251N/A *
1251N/A * The call to the DS init functions will eventually result in the
1256N/A * invocation of our registration callback handlers, at which time DS
72N/A * is able to accept requests.
72N/A */
59N/Astatic void
2N/Apromif_ds_init(void)
85N/A{
61N/A static char *me = "promif_ds_init";
61N/A int rv;
220N/A
61N/A if ((ds_init =
61N/A (int (*)())modgetsymvalue("ds_cap_init", 0)) == 0) {
1119N/A cmn_err(CE_WARN, "%s: can't find ds_cap_init", me);
172N/A return;
61N/A }
61N/A
220N/A if ((ds_send =
220N/A (int (*)())modgetsymvalue("ds_cap_send", 0)) == 0) {
61N/A cmn_err(CE_WARN, "%s: can't find ds_cap_send", me);
172N/A return;
454N/A }
61N/A
172N/A if ((rv = (*ds_init)(&vc_primary_cap, &vc_primary_ops)) != 0) {
61N/A cmn_err(CE_NOTE,
152N/A "%s: ds_cap_init failed (primary): %d", me, rv);
74N/A }
61N/A
220N/A
85N/A if ((rv = (*ds_init)(&vc_backup_cap, &vc_backup_ops)) != 0) {
172N/A cmn_err(CE_NOTE,
61N/A "%s: ds_cap_init failed (backup): %d", me, rv);
172N/A }
61N/A}
1119N/A
172N/A/*
61N/A * Prepare for ldom variable requests.
61N/A */
220N/Avoid
61N/Apromif_prop_init(void)
454N/A{
61N/A mutex_init(&promif_prop_lock, NULL, MUTEX_DEFAULT, NULL);
172N/A cv_init(&promif_prop_cv, NULL, CV_DEFAULT, NULL);
61N/A
172N/A promif_ds_init();
61N/A}
152N/A
152N/A
220N/A/*
61N/A * Replace the current value of a property string given its name and
61N/A * new value.
43N/A */
220N/Aint
43N/Apromif_ldom_setprop(char *name, void *value, int valuelen)
120N/A{
64N/A var_config_msg_t *req;
64N/A var_config_set_req_t *setp;
64N/A var_config_cmd_t cmd;
43N/A ds_svc_hdl_t ds_handle;
43N/A int rv;
120N/A int namelen = strlen(name);
64N/A int paylen = namelen + 1 + valuelen; /* valuelen includes the null */
64N/A static char *me = "promif_ldom_setprop";
64N/A
220N/A if (ds_primary_handle != DS_INVALID_HDL)
64N/A ds_handle = ds_primary_handle;
64N/A else if (ds_backup_handle != DS_INVALID_HDL)
486N/A ds_handle = ds_backup_handle;
486N/A else
64N/A return (-1);
64N/A
64N/A /*
64N/A * Since we are emulating OBP, we must comply with the promif
64N/A * infrastructure and execute only on the originating cpu.
64N/A */
64N/A thread_affinity_set(curthread, CPU->cpu_id);
43N/A
16N/A req = kmem_zalloc(sizeof (var_config_hdr_t) + paylen, KM_SLEEP);
16N/A req->var_config_cmd = VAR_CONFIG_SET_REQ;
16N/A setp = &req->var_config_set;
34N/A (void) strcpy(setp->name_and_value, name);
34N/A (void) strncpy(&setp->name_and_value[namelen + 1], value, valuelen);
16N/A
6N/A if ((rv = (*ds_send)(ds_handle, req,
12N/A sizeof (var_config_hdr_t) + paylen)) != 0) {
1256N/A cmn_err(CE_WARN, "%s: ds_cap_send failed: %d", me, rv);
12N/A kmem_free(req, sizeof (var_config_hdr_t) + paylen);
12N/A thread_affinity_clear(curthread);
12N/A return (-1);
12N/A }
12N/A
12N/A kmem_free(req, sizeof (var_config_hdr_t) + paylen);
12N/A
12N/A mutex_enter(&promif_prop_lock);
12N/A if (cv_reltimedwait(&promif_prop_cv, &promif_prop_lock,
4085N/A PROMIF_DS_TIMEOUT_SEC * hz, TR_CLOCK_TICK) == -1) {
369N/A cmn_err(CE_WARN, "%s: ds response timeout", me);
369N/A rv = -1;
3056N/A goto out;
369N/A }
4085N/A
61N/A cmd = promif_ds_resp.vc_hdr.cmd;
61N/A if (cmd != VAR_CONFIG_SET_RESP) {
61N/A cmn_err(CE_WARN, "%s: bad response type: %d", me, cmd);
4085N/A rv = -1;
61N/A goto out;
61N/A }
12N/A rv = (cfg_rsp->result == VAR_CONFIG_SUCCESS) ? valuelen : -1;
4085N/A
4085N/Aout:
181N/A mutex_exit(&promif_prop_lock);
181N/A thread_affinity_clear(curthread);
12N/A return (rv);
4085N/A}
61N/A
61N/Aint
12N/Apromif_setprop(void *p)
4085N/A{
279N/A cell_t *ci = (cell_t *)p;
279N/A pnode_t node;
181N/A caddr_t name;
181N/A caddr_t value;
181N/A int len;
2N/A
3864N/A ASSERT(ci[1] == 4);
3864N/A
3864N/A node = p1275_cell2dnode(ci[3]);
3864N/A ASSERT(node == prom_optionsnode());
3558N/A name = p1275_cell2ptr(ci[4]);
4089N/A value = p1275_cell2ptr(ci[5]);
3558N/A len = p1275_cell2int(ci[6]);
3558N/A
3558N/A if (promif_stree_getproplen(node, name) != -1)
3558N/A len = promif_ldom_setprop(name, value, len);
3558N/A
3864N/A if (len >= 0)
3558N/A len = promif_stree_setprop(node, name, (void *)value, len);
3558N/A
3864N/A
3558N/A ci[7] = p1275_int2cell(len);
3558N/A
3864N/A return ((len == -1) ? len : 0);
3558N/A}
3747N/A
3747N/A#endif
3747N/A
3558N/Aint
3558N/Apromif_getprop(void *p)
3558N/A{
3558N/A cell_t *ci = (cell_t *)p;
3558N/A pnode_t node;
3558N/A caddr_t name;
3558N/A caddr_t value;
3558N/A int len;
3558N/A
3558N/A ASSERT(ci[1] == 4);
4286N/A
3558N/A node = p1275_cell2dnode(ci[3]);
3558N/A name = p1275_cell2ptr(ci[4]);
3747N/A value = p1275_cell2ptr(ci[5]);
3558N/A
3558N/A len = promif_stree_getprop(node, name, value);
3558N/A
3558N/A ci[7] = p1275_int2cell(len);
3558N/A
3558N/A return ((len == -1) ? len : 0);
3750N/A}
3750N/A
3750N/Aint
3558N/Apromif_getproplen(void *p)
3558N/A{
3558N/A cell_t *ci = (cell_t *)p;
3864N/A pnode_t node;
3558N/A caddr_t name;
3558N/A int len;
3558N/A
4286N/A ASSERT(ci[1] == 2);
3558N/A
3558N/A node = p1275_cell2dnode(ci[3]);
3750N/A name = p1275_cell2ptr(ci[4]);
3750N/A
3750N/A len = promif_stree_getproplen(node, name);
3558N/A
3558N/A ci[5] = p1275_int2cell(len);
3558N/A
3558N/A return (0);
3558N/A}
3558N/A
3558N/Aint
4286N/Apromif_nextprop(void *p)
3558N/A{
3558N/A cell_t *ci = (cell_t *)p;
3558N/A pnode_t node;
3558N/A caddr_t prev;
3558N/A caddr_t next;
3558N/A
3558N/A ASSERT(ci[1] == 3);
3558N/A
3558N/A node = p1275_cell2dnode(ci[3]);
3558N/A prev = p1275_cell2ptr(ci[4]);
3558N/A next = p1275_cell2ptr(ci[5]);
3558N/A
3558N/A (void) promif_stree_nextprop(node, prev, next);
3750N/A
3750N/A return (0);
3750N/A}
3558N/A