summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornp146283 <none@none>2008-05-15 14:31:32 -0700
committernp146283 <none@none>2008-05-15 14:31:32 -0700
commita9da3307db733eb1739ba859952610bba3d894ab (patch)
tree56f6c91c49074ff9e3b55d5a65514e911b9383d4
parent9fc20c6dac37dd2cce567cc320b59cd5315ab36d (diff)
downloadillumos-joyent-a9da3307db733eb1739ba859952610bba3d894ab.tar.gz
PSARC 2007/679 CPUFreq HAL
6647034 CPUFreq support into HAL
-rw-r--r--usr/src/cmd/hal/addons/Makefile4
-rw-r--r--usr/src/cmd/hal/addons/cpufreq/Makefile68
-rw-r--r--usr/src/cmd/hal/addons/cpufreq/addon-cpufreq.c1424
-rw-r--r--usr/src/cmd/hal/fdi/Makefile1
-rw-r--r--usr/src/cmd/hal/fdi/policy/10osvendor/10-cpufreq.fdi10
-rw-r--r--usr/src/cmd/hal/hald/Makefile5
-rw-r--r--usr/src/cmd/hal/hald/solaris/Makefile4
-rw-r--r--usr/src/cmd/hal/hald/solaris/devinfo.c1
-rw-r--r--usr/src/cmd/hal/hald/solaris/devinfo_cpu.c247
-rw-r--r--usr/src/cmd/hal/hald/solaris/devinfo_cpu.h21
-rw-r--r--usr/src/cmd/hal/hald/solaris/devinfo_misc.c32
-rw-r--r--usr/src/cmd/hal/hald/solaris/devinfo_misc.h1
-rw-r--r--usr/src/cmd/hal/hald/solaris/sysevent.c199
-rw-r--r--usr/src/cmd/hal/tools/Makefile15
-rw-r--r--usr/src/cmd/hal/tools/hal-storage-shared.c84
-rw-r--r--usr/src/cmd/hal/tools/hal-storage-shared.h3
-rw-r--r--usr/src/cmd/hal/utils/adt_data.c106
-rw-r--r--usr/src/cmd/hal/utils/adt_data.h25
-rw-r--r--usr/src/lib/libbsm/audit_event.txt4
-rw-r--r--usr/src/lib/libbsm/common/adt.xml64
-rw-r--r--usr/src/lib/libsecdb/auth_attr.txt1
-rw-r--r--usr/src/lib/libsecdb/help/auths/Makefile3
-rw-r--r--usr/src/lib/libsecdb/help/auths/SysCpuPowerMgmt.html42
-rw-r--r--usr/src/lib/libsecdb/help/profiles/Makefile3
-rw-r--r--usr/src/lib/libsecdb/help/profiles/RtCPUPowerManagement.html38
-rw-r--r--usr/src/lib/libsecdb/prof_attr.txt3
-rw-r--r--usr/src/lib/policykit/libpolkit/common/libpolkit-rbac.c2
-rw-r--r--usr/src/pkgdefs/SUNW0on/prototype_com2
-rw-r--r--usr/src/pkgdefs/SUNWcsu/prototype_com2
-rw-r--r--usr/src/pkgdefs/SUNWhal/prototype_com1
-rw-r--r--usr/src/pkgdefs/SUNWhalr/prototype_com1
31 files changed, 2283 insertions, 133 deletions
diff --git a/usr/src/cmd/hal/addons/Makefile b/usr/src/cmd/hal/addons/Makefile
index 9afe789d5c..b676ffdf4b 100644
--- a/usr/src/cmd/hal/addons/Makefile
+++ b/usr/src/cmd/hal/addons/Makefile
@@ -19,13 +19,13 @@
# CDDL HEADER END
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
#
-SUBDIRS = storage acpi network-devices
+SUBDIRS = storage acpi network-devices cpufreq
all := TARGET= all
install := TARGET= install
diff --git a/usr/src/cmd/hal/addons/cpufreq/Makefile b/usr/src/cmd/hal/addons/cpufreq/Makefile
new file mode 100644
index 0000000000..b631fbf33b
--- /dev/null
+++ b/usr/src/cmd/hal/addons/cpufreq/Makefile
@@ -0,0 +1,68 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+
+#
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident "%Z%%M% %I% %E% SMI"
+#
+
+PROG = hald-addon-cpufreq
+OBJS = addon-cpufreq.o logger.o adt_data.o
+SRCS = addon-cpufreq.c ../../hald/logger.c ../../utils/adt_data.c
+
+include ../../../Makefile.cmd
+include ../../Makefile.hal
+
+ROOTCMDDIR = $(ROOTLIB_HAL)
+
+LDLIBS += -lc -ldbus-1 -lhal -lglib-2.0 -ldbus-glib-1 -lpolkit -lbsm
+
+CPPFLAGS += $(HAL_DBUS_CPPFLAGS) $(HAL_GLIB_CPPFLAGS) $(HAL_CONFIG_CPPFLAGS)
+CPPFLAGS += -I$(ROOT)/usr/include/hal -I../../hald
+CPPFLAGS += -I$(ROOT)/usr/include/libpolkit -g
+C99MODE = $(C99_ENABLE)
+
+.KEEP_STATE:
+
+all:$(PROG)
+
+logger.o: ../../hald/logger.c
+ $(COMPILE.c) -o $@ ../../hald/logger.c
+ $(POST_PROCESS_O)
+
+adt_data.o: ../../utils/adt_data.c
+ $(COMPILE.c) -o $@ ../../utils/adt_data.c
+ $(POST_PROCESS_O)
+
+$(PROG): $(OBJS)
+ $(LINK.c) -o $@ $(OBJS) $(LDLIBS)
+ $(POST_PROCESS)
+
+install: all $(ROOTCMD)
+
+clean:
+ $(RM) $(OBJS)
+
+FRC:
+
+include ../../../Makefile.targ
diff --git a/usr/src/cmd/hal/addons/cpufreq/addon-cpufreq.c b/usr/src/cmd/hal/addons/cpufreq/addon-cpufreq.c
new file mode 100644
index 0000000000..770853f0f0
--- /dev/null
+++ b/usr/src/cmd/hal/addons/cpufreq/addon-cpufreq.c
@@ -0,0 +1,1424 @@
+/***************************************************************************
+ *
+ * addon-cpufreq.c : Routines to support CPUFreq interface
+ *
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ ***************************************************************************/
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <strings.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/dkio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+#include <dbus/dbus-glib.h>
+#include <priv.h>
+#include <pwd.h>
+
+#include <syslog.h>
+
+#include <libhal.h>
+#include "../../hald/logger.h"
+#include "../../utils/adt_data.h"
+
+#include <pwd.h>
+#ifdef HAVE_POLKIT
+#include <libpolkit.h>
+#endif
+
+#ifdef sun
+#include <bsm/adt.h>
+#include <bsm/adt_event.h>
+#include <sys/pm.h>
+#endif
+
+#define POWER_CONF_FILE "/etc/power.conf"
+#define PMCONFIG "/usr/sbin/pmconfig -f"
+#define PM "/dev/pm"
+
+#define FILE_ARR_SIZE 256
+#define EDIT_TYPE_SIZE 64
+#define ERR_BUF_SIZE 256
+
+#define WAIT_TIME 30
+
+char TMP_CONF_FILE[64] = "/tmp/power.conf.XXXXXX";
+const char *sender;
+unsigned long uid;
+
+/*
+ * Specify different CPUFreq related HAL activities that can be done
+ */
+enum hal_type {
+ CPU_GOV,
+ CPU_PERFORMANCE
+};
+typedef enum hal_type power_conf_hal_type;
+
+/*
+ * Various CPUFreq related editable parameters in the power.conf file
+ */
+typedef struct {
+ char cpu_gov[EDIT_TYPE_SIZE];
+ int cpu_th;
+} pconf_edit_type;
+
+/*
+ * CPUFreq interospect XML that exports the various CPUFreq HAL interface
+ * supported methods
+ */
+const char *cpufreq_introspect_xml = \
+ " <method name= \"SetCPUFreqGovernor\">\n \
+ <arg type= \"s\" name= \"governor\" direction= \"in\"/>\n \
+ </method>\n \
+ <method name= \"GetCPUFreqGovernor\">\n \
+ <type= \"s\" direction= \"out\"/>\n \
+ </method>\n \
+ <method name= \"SetCPUFreqPerformance\">\n \
+ <arg type=\"i\" direction=\"in\"/>\n \
+ </method>\n \
+ <method name= \"GetCPUFreqPerformance\">\n \
+ <type=\"i\" direction=\"out\"/>\n \
+ </method>\n \
+ <method name= \"GetCPUFreqAvailableGovernors\">\n \
+ <<type=\"s\" direction=\"out\"/>\n \
+ </method>\n";
+
+/*
+ * List of governors that are currently supported
+ */
+char *const gov_list[] = {
+ "ondemand",
+ "performance",
+ NULL
+};
+
+static char current_gov[EDIT_TYPE_SIZE];
+
+/*
+ * Free up the mem allocated to hold the DBusError
+ */
+static void
+check_and_free_error(DBusError *error)
+{
+ if (dbus_error_is_set (error)) {
+ dbus_error_free (error);
+ }
+}
+
+/*
+ * Edit the /etc/power.conf file to update the cpupm and cpupm_threshold values
+ * Return 0 on success
+ * 1 if the governor is not available or supported
+ * -1 all other errors
+ * NOTE: Before modifying power.conf, it is first copied into a temp file, and
+ * pmconfig is executed on the temp file with -f option, which uses temp file
+ * to set the PM config and then replaces power.conf with the temp file.
+ */
+static int
+edit_power_conf_file(pconf_edit_type pc_edit_type,
+ power_conf_hal_type pc_hal_type, char *tmp_file)
+{
+ FILE *pfile;
+ char tstr[FILE_ARR_SIZE];
+ char temp_str[FILE_ARR_SIZE];
+ long fset = 0;
+ long next_fset = 0;
+ char *file_edit_type;
+ char *file_edit_value;
+ char file_edit_threshold[FILE_ARR_SIZE];
+ char file_update_str[FILE_ARR_SIZE];
+ int res = 0;
+ char cp_cmd_str[128];
+ int tmp_fd;
+
+ /*
+ * Copy /etc/power.conf to temp file
+ */
+ if (tmp_file == NULL) {
+ HAL_INFO ((" Invalid temp file name"));
+ return (EINVAL);
+ }
+ sprintf (cp_cmd_str, "/usr/bin/cp %s %s", POWER_CONF_FILE, tmp_file);
+ if (system (cp_cmd_str) != 0) {
+ HAL_ERROR ((" Error in copying %s to %s, %s",
+ POWER_CONF_FILE, tmp_file, strerror (errno)));
+ return (errno);
+ }
+
+ pfile = fopen (tmp_file, "r+");
+ if (pfile == NULL) {
+ HAL_INFO (("Cannot open file %s: %s",
+ tmp_file, strerror (errno)));
+ return (errno);
+ }
+
+ switch (pc_hal_type) {
+ case CPU_GOV:
+ if ((pc_edit_type.cpu_gov == NULL) ||
+ ((strcmp (pc_edit_type.cpu_gov, "ondemand") != 0) &&
+ (strcmp (pc_edit_type.cpu_gov, "performance") != 0))) {
+ HAL_INFO ((" CPU governor is not available/valid."
+ " Should be either ondemand or performance"));
+ res = EINVAL;
+ goto out;
+ }
+ file_edit_type = "cpupm";
+ if (strcmp (pc_edit_type.cpu_gov, "ondemand") == 0) {
+ file_edit_value = " enable";
+ } else {
+ file_edit_value = "disable";
+ }
+ break;
+ case CPU_PERFORMANCE:
+ if (pc_edit_type.cpu_th == NULL) {
+ HAL_INFO ((" CPU Threshold is not valid."));
+ res = EINVAL;
+ goto out;
+ }
+ file_edit_type = "cpu-threshold";
+ sprintf (file_edit_threshold, "%d", pc_edit_type.cpu_th);
+ file_edit_value = file_edit_threshold;
+ break;
+ default:
+ HAL_DEBUG ((" Cannot recognize the type of change being"
+ " made to /etc/power.conf"));
+ res = EINVAL;
+ goto out;
+ }
+
+ while (fgets (tstr, FILE_ARR_SIZE, pfile) != NULL) {
+ if ((tstr == NULL) || (strlen (tstr) <= 0))
+ continue;
+ /*
+ * Look for line containing "cpupm" or "cpu-threshold"
+ */
+
+ if (strstr (tstr, file_edit_type) == NULL) {
+ fset = fset + strlen (tstr);
+ continue;
+ }
+ /*
+ * If the required value already present. Just
+ * return
+ */
+ if (strstr (tstr, file_edit_value) != NULL) {
+ res = 0;
+ goto out;
+ }
+
+ if (fseek (pfile, fset, SEEK_SET) != 0) {
+ HAL_ERROR (("\n Error in fseek %s: %s",
+ POWER_CONF_FILE, strerror (errno)));
+ res = errno;
+ goto out;
+ }
+ /*
+ * Update the file with new values
+ */
+ sprintf (file_update_str, "%s %s \n",
+ file_edit_type, file_edit_value);
+
+ /*
+ * Check if the currrent line is the last one. If not,
+ * to avoid overwriting and wasting space, move remaining
+ * lines upwards and update at the end
+ */
+ next_fset = fset + strlen(tstr);
+ if (fseek (pfile, next_fset, SEEK_SET) != 0) {
+ HAL_ERROR (("\n Error in fseek %s: %s",
+ tmp_file, strerror (errno)));
+ res = errno;
+ goto out;
+ }
+ if (fgets (tstr, FILE_ARR_SIZE, pfile) != NULL) {
+ do {
+ snprintf (temp_str, FILE_ARR_SIZE,
+ "%s\n", tstr);
+ fseek (pfile, fset, SEEK_SET);
+ fputs (temp_str, pfile);
+ fset = fset + strlen(tstr);
+ next_fset = next_fset + strlen(tstr);
+ fseek (pfile, next_fset, SEEK_SET);
+
+ } while (fgets (tstr, FILE_ARR_SIZE, pfile) != NULL);
+ }
+
+ fseek (pfile, fset, SEEK_SET);
+
+ if (fputs (file_update_str, pfile) == EOF) {
+ HAL_ERROR (("\n Error in writing to"
+ " %s: %s", POWER_CONF_FILE,
+ strerror (errno)));
+ res = errno;
+ goto out;
+ }
+
+ if (fflush (pfile) == EOF) {
+ HAL_ERROR (("\n Error in flushing to"
+ " %s: %s", POWER_CONF_FILE,
+ strerror (errno)));
+ }
+ res = 0;
+ goto out;
+ }
+
+ /*
+ * If the pointer comes here, then the property is not already present.
+ * Have to append to the file
+ */
+ HAL_DEBUG (("\n Passed value not found. Will append to the file"));
+ if (fseek (pfile, 0, SEEK_END) != 0) {
+ HAL_ERROR (("\n Error in fseek to %s: %s",
+ POWER_CONF_FILE, strerror (errno)));
+ res = errno;
+ goto out;
+ }
+
+ /*
+ * Update the file with new values
+ */
+ sprintf (file_update_str, "%s %s \n", file_edit_type, file_edit_value);
+
+ if (fputs (file_update_str, pfile) == EOF) {
+ HAL_ERROR (("Error in writing to file %s: %s",
+ POWER_CONF_FILE, strerror (errno)));
+ res = errno;
+ goto out;
+ }
+
+ if (fflush (pfile) == EOF) {
+ HAL_ERROR (("\n Error in flushing to %s: %s",
+ POWER_CONF_FILE, strerror (errno)));
+ }
+ res = 0;
+out:
+ fclose (pfile);
+ return (res);
+}
+
+/*
+ * Depending on the type(cpupm or cpu-threshold) to read, check if they are
+ * present. If present, return the corresponding value through pc_value arg
+ * and return 1 from the function. If there is no corresponding entry,return 0.
+ * Return -1 on error
+ */
+
+static int
+read_power_conf_file(pconf_edit_type *pc_value,
+ power_conf_hal_type pc_hal_type)
+{
+
+ FILE *pfile;
+ char tstr[FILE_ARR_SIZE];
+ long fset = 0;
+ char *file_edit_type;
+ char *tpstr;
+ int res = 0;
+
+ pfile = fopen (POWER_CONF_FILE, "r");
+ if (pfile == NULL) {
+ HAL_INFO (("\n Cannot open the file %s: %s",
+ POWER_CONF_FILE, strerror (errno)));
+ return (-1);
+ }
+
+ switch (pc_hal_type) {
+ case CPU_GOV:
+ file_edit_type = "cpupm";
+ break;
+ case CPU_PERFORMANCE:
+ file_edit_type = "cpu-threshold";
+ break;
+ default :
+ HAL_DEBUG (("Cannot recognize the HAL type to get value"));
+ res = -1;
+ goto out;
+ }
+
+ while (fgets (tstr, FILE_ARR_SIZE, pfile) != NULL) {
+ if ((tstr == NULL) || (strlen (tstr) <= 0))
+ continue;
+ /*
+ * Look for line containing "cpupm" or "cpu-threshold"
+ */
+ if (strstr (tstr, file_edit_type) == NULL)
+ continue;
+
+ /*
+ * If the required value already present. Just
+ * get the value
+ */
+ tpstr = strtok (tstr, " ");
+ tpstr = strtok (NULL, " ");
+ if (tpstr == NULL) {
+ HAL_INFO (("Value of %s in %s is not valid",
+ file_edit_type, POWER_CONF_FILE));
+ res = -1;
+ goto out;
+ }
+
+ if (pc_hal_type == CPU_GOV) {
+ /*
+ * Copy the corresponding governor
+ */
+ if (strcmp (tpstr, "enable") == 0) {
+ sprintf (pc_value->cpu_gov,
+ "%s", "ondemand");
+ } else {
+ sprintf (pc_value->cpu_gov,
+ "%s", "performance");
+ }
+ } else {
+ pc_value->cpu_th = atoi (tpstr);
+ }
+ res = 1;
+ goto out;
+ }
+ /*
+ * Entry not found in the file
+ */
+ HAL_DEBUG ((" No entry of %s in %s", file_edit_type, POWER_CONF_FILE));
+ res = 0;
+
+out:
+ fclose (pfile);
+ return (res);
+}
+
+
+/*
+ * Depending on the type(Governor or Perfromance) to read, get the current
+ * values through PM ioctls().
+ * For "Governor", return the cpupm state and for "Performance" return the
+ * current cpu threshold.
+ * Return the corresponding value through cur_value and return 1 from the
+ * function for success. Return -1 on error
+ */
+
+static int
+get_cur_val(pconf_edit_type *cur_value,
+ power_conf_hal_type pc_hal_type)
+{
+
+ int pm_fd;
+ int res = -1;
+ int pm_ret;
+
+ pm_fd = open (PM, O_RDONLY);
+ if (pm_fd == -1) {
+ HAL_ERROR (("Error opening %s: %s \n", PM, strerror (errno)));
+ return (res);
+ }
+
+ switch (pc_hal_type) {
+ case CPU_GOV:
+ /*
+ * First check the PM_GET_CPUPM_STATE. If it is not available
+ * then check PM_GET_PM_STATE
+ */
+ pm_ret = ioctl (pm_fd, PM_GET_CPUPM_STATE);
+ if (pm_ret < 0) {
+ HAL_ERROR (("Error in ioctl PM_GET_CPUPM_STATE: %s \n",
+ strerror (errno)));
+ goto out;
+ }
+ switch (pm_ret) {
+ case PM_CPU_PM_ENABLED:
+ sprintf (cur_value->cpu_gov, "%s", "ondemand");
+ res = 1;
+ goto out;
+ case PM_CPU_PM_DISABLED:
+ sprintf (cur_value->cpu_gov, "%s", "performance");
+ res = 1;
+ goto out;
+ case PM_CPU_PM_NOTSET:
+ /*
+ * Check for PM_GET_PM_STATE
+ */
+ pm_ret = ioctl (pm_fd, PM_GET_PM_STATE);
+ if (pm_ret < 0) {
+ HAL_ERROR (("Error in ioctl PM_GET_PM_STATE: "
+ "%s", strerror (errno)));
+ goto out;
+ }
+ switch (pm_ret) {
+ case PM_SYSTEM_PM_ENABLED:
+ sprintf (cur_value->cpu_gov, "%s", "ondemand");
+ res = 1;
+ goto out;
+ case PM_SYSTEM_PM_DISABLED:
+ sprintf (cur_value->cpu_gov, "%s",
+ "performance");
+ res = 1;
+ goto out;
+ default:
+ HAL_ERROR (("PM Internal error during ioctl "
+ "PM_GET_PM_STATE"));
+ goto out;
+ }
+ default:
+ HAL_ERROR (("Unknown value ioctl PM_GET_CPUPM_STATE"));
+ goto out;
+ }
+ case CPU_PERFORMANCE:
+ /*
+ * First check the PM_GET_CPU_THRESHOLD. If it is not available
+ * then check PM_GET_SYSTEM_THRESHOLD
+ */
+ pm_ret = ioctl (pm_fd, PM_GET_CPU_THRESHOLD);
+ if (pm_ret >= 0) {
+ cur_value->cpu_th = pm_ret;
+ res = 1;
+ goto out;
+ } else if ((pm_ret == EINVAL) || (pm_ret == ENOTTY)) {
+ /*
+ * PM_GET_CPU_THRESHOLD is not available
+ */
+ pm_ret = ioctl (pm_fd, PM_GET_SYSTEM_THRESHOLD);
+ if (res >= 0) {
+ cur_value->cpu_th = pm_ret;
+ res = 1;
+ goto out;
+ } else {
+ HAL_ERROR (("Error in PM_GET_CPU_THRESHOLD: %s",
+ strerror (errno)));
+ goto out;
+ }
+ } else {
+ HAL_ERROR ((" Error in ioctl PM_GET_CPU_THRESHOLD: %s",
+ strerror (errno)));
+ goto out;
+ }
+ default :
+ HAL_DEBUG (("Cannot recognize the HAL type to get value"));
+ goto out;
+ }
+out:
+ close (pm_fd);
+ return (res);
+}
+/*
+ * Send an error message as a response to the pending call
+ */
+static void
+generate_err_msg(DBusConnection *con,
+ DBusMessage *msg,
+ const char *err_name,
+ char *fmt, ...)
+{
+
+ DBusMessage *err_msg;
+ char err_buf[ERR_BUF_SIZE];
+ va_list va_args;
+
+ va_start (va_args, fmt);
+ vsnprintf (err_buf, ERR_BUF_SIZE, fmt, va_args);
+ va_end (va_args);
+
+ HAL_DEBUG ((" Sending error message: %s", err_buf));
+
+ err_msg = dbus_message_new_error (msg, err_name, err_buf);
+ if (err_msg == NULL) {
+ HAL_ERROR (("No Memory for DBUS error msg"));
+ return;
+ }
+
+ if (!dbus_connection_send (con, err_msg, NULL)) {
+ HAL_ERROR ((" Out Of Memory!"));
+ }
+ dbus_connection_flush (con);
+
+}
+
+static void
+gen_unknown_gov_err(DBusConnection *con,
+ DBusMessage *msg,
+ char *err_str)
+{
+
+ generate_err_msg (con,
+ msg,
+ "org.freedesktop.Hal.CPUFreq.UnknownGovernor",
+ "Unknown CPUFreq Governor: %s",
+ err_str);
+}
+
+static void
+gen_no_suitable_gov_err(DBusConnection *con,
+ DBusMessage *msg,
+ char *err_str)
+{
+
+ generate_err_msg (con,
+ msg,
+ "org.freedesktop.Hal.CPUFreq.NoSuitableGovernor",
+ "Could not find a suitable governor: %s",
+ err_str);
+}
+
+static void
+gen_cpufreq_err(DBusConnection *con,
+ DBusMessage *msg,
+ char *err_str)
+{
+ generate_err_msg (con,
+ msg,
+ "org.freedesktop.Hal.CPUFreq.Error",
+ "%s: Syslog might give more information",
+ err_str);
+}
+
+
+/*
+ * Puts the required cpufreq audit data and calls adt_put_event()
+ * to generate auditing
+ */
+static void
+audit_cpufreq(const adt_export_data_t *imported_state, au_event_t event_id,
+ int result, const char *auth_used, const int cpu_thr_value)
+{
+ adt_session_data_t *ah;
+ adt_event_data_t *event;
+ struct passwd *msg_pwd;
+ uid_t gid;
+
+ if (adt_start_session (&ah, imported_state, 0) != 0) {
+ HAL_INFO (("adt_start_session failed: %s", strerror (errno)));
+ return;
+ }
+
+ if ((event = adt_alloc_event (ah, event_id)) == NULL) {
+ HAL_INFO(("adt_alloc_event audit_cpufreq failed: %s",
+ strerror (errno)));
+ return;
+ }
+
+ switch (event_id) {
+ case ADT_cpu_ondemand:
+ event->adt_cpu_ondemand.auth_used = (char *)auth_used;
+ break;
+ case ADT_cpu_performance:
+ event->adt_cpu_performance.auth_used = (char *)auth_used;
+ break;
+ case ADT_cpu_threshold:
+ event->adt_cpu_threshold.auth_used = (char *)auth_used;
+ event->adt_cpu_threshold.threshold = cpu_thr_value;
+ break;
+ default:
+ goto clean;
+ }
+
+ if (result == 0) {
+ if (adt_put_event (event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
+ HAL_INFO (("adt_put_event(%d, ADT_SUCCESS) failed",
+ event_id));
+ }
+ } else {
+ if (adt_put_event (event, ADT_FAILURE, result) != 0) {
+ HAL_INFO (("adt_put_event(%d, ADT_FAILURE) failed",
+ event_id));
+ }
+ }
+
+clean:
+ adt_free_event (event);
+ (void) adt_end_session (ah);
+}
+
+/*
+ * Check if the cpufreq related operations are authorized
+ */
+
+static int
+check_authorization(DBusConnection *con, DBusMessage *msg)
+{
+ int adt_res = 0;
+#ifdef HAVE_POLKIT
+ char user_id[128];
+ char *udi;
+ char *privilege;
+ DBusError error;
+ gboolean is_priv_allowed;
+ gboolean is_priv_temporary;
+ DBusConnection *system_bus = NULL;
+ LibPolKitContext *pol_ctx = NULL;
+
+ /*
+ * Check for authorization before proceeding
+ */
+ udi = getenv ("HAL_PROP_INFO_UDI");
+ privilege = "hal-power-cpu";
+
+ dbus_error_init (&error);
+ system_bus = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
+ if (system_bus == NULL) {
+ HAL_INFO (("Cannot connect to the system bus"));
+ LIBHAL_FREE_DBUS_ERROR (&error);
+ gen_cpufreq_err (con, msg, "Cannot connect to the system bus");
+ adt_res = EINVAL;
+ goto out;
+ }
+
+ sender = dbus_message_get_sender (msg);
+ HAL_INFO (("Auth Sender: %s", sender));
+
+ if (sender == NULL) {
+ HAL_INFO (("Could not get the sender of the message"));
+ gen_cpufreq_err (con, msg,
+ "Could not get the sender of the message");
+ adt_res = ADT_FAIL_VALUE_AUTH;
+ goto out;
+ }
+
+ dbus_error_init (&error);
+ uid = dbus_bus_get_unix_user (system_bus, sender, &error);
+ if (dbus_error_is_set (&error)) {
+ HAL_INFO (("Could not get the user id of the message"));
+ LIBHAL_FREE_DBUS_ERROR (&error);
+ gen_cpufreq_err (con, msg,
+ "Could not get the user id of the message sender");
+ adt_res = ADT_FAIL_VALUE_AUTH;
+ goto out;
+ }
+
+ snprintf (user_id, sizeof (user_id), "%d", uid);
+ HAL_DEBUG ((" User id is : %d", uid));
+
+ pol_ctx = libpolkit_new_context (system_bus);
+ if (pol_ctx == NULL) {
+ HAL_INFO (("Cannot get libpolkit context"));
+ gen_cpufreq_err (con, msg,
+ "Cannot get libpolkit context to check privileges");
+ adt_res = ADT_FAIL_VALUE_AUTH;
+ goto out;
+ }
+
+ if (libpolkit_is_uid_allowed_for_privilege (pol_ctx,
+ NULL,
+ user_id,
+ privilege,
+ udi,
+ &is_priv_allowed,
+ &is_priv_temporary,
+ NULL) != LIBPOLKIT_RESULT_OK) {
+ HAL_INFO (("Cannot lookup privilege from PolicyKit"));
+ gen_cpufreq_err (con, msg,
+ "Error looking up privileges from Policykit");
+ adt_res = ADT_FAIL_VALUE_AUTH;
+ goto out;
+ }
+
+ if (!is_priv_allowed) {
+ HAL_INFO (("Caller doesn't possess required privilege to"
+ " change the governor"));
+ gen_cpufreq_err (con, msg,
+ "Caller doesn't possess required "
+ "privilege to change the governor");
+ adt_res = ADT_FAIL_VALUE_AUTH;
+ goto out;
+ }
+
+ HAL_DEBUG ((" Privilege Succeed"));
+
+#endif
+out:
+ return (adt_res);
+}
+
+/*
+ * Sets the CPU Freq governor. It sets the gov name in the /etc/power.conf
+ * and executes pmconfig. If governor is "ondemand" then "cpupm" is enabled in
+ * and if governor is performance, then "cpupm" is disabled
+ */
+static void
+set_cpufreq_gov(DBusConnection *con, DBusMessage *msg, void *udata)
+{
+ DBusMessageIter arg_iter;
+ DBusMessage *msg_reply;
+ char *arg_val;
+ int arg_type;
+ int pid;
+ int done_flag = 0;
+ int sleep_time = 0;
+ int status;
+ int adt_res = 0;
+ char tmp_conf_file[64] = "/tmp/power.conf.XXXXXX";
+ int tmp_fd;
+ char pmconfig_cmd[128];
+ pconf_edit_type pc_edit_type;
+#ifdef sun
+ adt_export_data_t *adt_data;
+ size_t adt_data_size;
+ DBusConnection *system_bus = NULL;
+ DBusError error;
+#endif
+
+ if (! dbus_message_iter_init (msg, &arg_iter)) {
+ HAL_DEBUG (("Incoming message has no arguments"));
+ gen_unknown_gov_err (con, msg, "No governor specified");
+ adt_res = EINVAL;
+ goto out;
+ }
+ arg_type = dbus_message_iter_get_arg_type (&arg_iter);
+
+ if (arg_type != DBUS_TYPE_STRING) {
+ HAL_DEBUG (("Incomming message arg type is not string"));
+ gen_unknown_gov_err (con, msg,
+ "Specified governor is not a string");
+ adt_res = EINVAL;
+ goto out;
+ }
+ dbus_message_iter_get_basic (&arg_iter, &arg_val);
+ if (arg_val != NULL) {
+ HAL_DEBUG (("SetCPUFreqGov is: %s", arg_val));
+ } else {
+ HAL_DEBUG (("Could not get SetCPUFreqGov from message iter"));
+ adt_res = EINVAL;
+ goto out;
+ }
+
+ adt_res = check_authorization (con, msg);
+
+ if (adt_res != 0) {
+ goto out;
+ }
+
+ /*
+ * Update the /etc/power.conf file.
+ */
+ tmp_fd = mkstemp (tmp_conf_file);
+ if (tmp_fd == -1) {
+ HAL_ERROR ((" Error in creating a temp conf file"));
+ adt_res = EINVAL;
+ goto out;
+ }
+ strcpy (pc_edit_type.cpu_gov, arg_val);
+ adt_res = edit_power_conf_file (pc_edit_type, CPU_GOV, tmp_conf_file);
+ if (adt_res != 0) {
+ HAL_DEBUG (("Error in edit /etc/power.conf"));
+ gen_cpufreq_err (con, msg,
+ "Internal Error while setting the governor");
+ unlink (tmp_conf_file);
+ goto out;
+ }
+
+ /*
+ * Execute pmconfig
+ */
+ sprintf (pmconfig_cmd, "%s %s", PMCONFIG, tmp_conf_file);
+ if (system (pmconfig_cmd) != 0) {
+ HAL_ERROR ((" Error in executing pmconfig: %s",
+ strerror (errno)));
+ adt_res = errno;
+ gen_cpufreq_err (con, msg, "Error in executing pmconfig");
+ unlink (tmp_conf_file);
+ goto out;
+ }
+ unlink (tmp_conf_file);
+ HAL_DEBUG (("Executed pmconfig"));
+ sprintf (current_gov, "%s", arg_val);
+
+ /*
+ * Just return an empty response, so that if the client
+ * is waiting for any response will not keep waiting
+ */
+ msg_reply = dbus_message_new_method_return (msg);
+ if (msg_reply == NULL) {
+ HAL_ERROR (("Out of memory to msg reply"));
+ gen_cpufreq_err (con, msg,
+ "Out of memory to create a response");
+ adt_res = ENOMEM;
+ goto out;
+ }
+
+ if (!dbus_connection_send (con, msg_reply, NULL)) {
+ HAL_ERROR (("Out of memory to msg reply"));
+ gen_cpufreq_err (con, msg,
+ "Out of memory to create a response");
+ adt_res = ENOMEM;
+ goto out;
+ }
+
+ dbus_connection_flush (con);
+
+out:
+
+#ifdef sun
+ /*
+ * Audit the new governor change
+ */
+ dbus_error_init (&error);
+ system_bus = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
+ if (system_bus == NULL) {
+ HAL_INFO (("Cannot connect to the system bus %s",
+ error.message));
+ LIBHAL_FREE_DBUS_ERROR (&error);
+ return;
+ }
+
+ adt_data = get_audit_export_data (system_bus, sender, &adt_data_size);
+ if (adt_data != NULL) {
+ if (strcmp (arg_val, "ondemand") == 0) {
+ audit_cpufreq (adt_data, ADT_cpu_ondemand, adt_res,
+ "solaris.system.power.cpu", 0);
+ } else if (strcmp (arg_val, "performance") == 0) {
+ audit_cpufreq (adt_data, ADT_cpu_performance, adt_res,
+ "solaris.system.power.cpu", 0);
+ }
+ free (adt_data);
+ } else {
+ HAL_INFO ((" Could not get audit export data"));
+ }
+#endif /* sun */
+}
+
+/*
+ * Sets the CPU Freq performance. It sets the cpu-threshold in the
+ * /etc/power.conf and executes pmconfig. The performnace value should
+ * be between 1 to 100. The cpu-threshold = ((performance val) * 15) secs.
+ */
+static void
+set_cpufreq_performance(DBusConnection *con, DBusMessage *msg, void *udata)
+{
+
+ DBusMessageIter arg_iter;
+ DBusMessage *msg_reply;
+ int arg_val;
+ int arg_type;
+ int pid;
+ int done_flag = 0;
+ int sleep_time = 0;
+ int adt_res = 0;
+ char tmp_conf_file[64] = "/tmp/power.conf.XXXXXX";
+ int tmp_fd;
+ char pmconfig_cmd[128];
+ pconf_edit_type pc_edit_type;
+#ifdef sun
+ adt_export_data_t *adt_data;
+ size_t adt_data_size;
+ DBusConnection *system_bus = NULL;
+ DBusError error;
+#endif
+
+ adt_res = check_authorization (con, msg);
+
+ if (adt_res != 0) {
+ goto out;
+ }
+
+ /*
+ * Performance can only be set to dynamic governors. Currently the
+ * only supported dynamic governor is ondemand.
+ */
+ if (current_gov[0] == 0) {
+ /*
+ * Read the current governor from /etc/power.conf
+ */
+ if (read_power_conf_file (&pc_edit_type, CPU_GOV) != 1) {
+ HAL_ERROR ((" Error in reading from /etc/power.conf"));
+ gen_cpufreq_err (con, msg, "Internal error while "
+ "getting the governor");
+ adt_res = EINVAL;
+ goto out;
+ }
+ sprintf (current_gov, "%s", pc_edit_type.cpu_gov);
+ }
+
+ if (strcmp (current_gov, "ondemand") != 0) {
+ HAL_DEBUG (("To set performance the current gov should be "
+ "dynamic like ondemand"));
+ gen_no_suitable_gov_err (con, msg, "Cannot set performance "
+ "to the current governor");
+ adt_res = EINVAL;
+ goto out;
+ }
+
+ if (! dbus_message_iter_init (msg, &arg_iter)) {
+ HAL_DEBUG (("Incoming message has no arguments"));
+ gen_no_suitable_gov_err(con, msg, "No performance specified");
+ adt_res = EINVAL;
+ goto out;
+ }
+ arg_type = dbus_message_iter_get_arg_type (&arg_iter);
+
+ if (arg_type != DBUS_TYPE_INT32) {
+ HAL_DEBUG (("Incomming message arg type is not Integer"));
+ gen_no_suitable_gov_err (con, msg,
+ "Specified performance is not a Integer");
+ adt_res = EINVAL;
+ goto out;
+ }
+ dbus_message_iter_get_basic (&arg_iter, &arg_val);
+ if ((arg_val < 1) || (arg_val > 100)) {
+ HAL_INFO (("SetCPUFreqPerformance should be between 1 to 100"
+ ": %d", arg_val));
+ gen_no_suitable_gov_err (con, msg,
+ "Performance value should be between 1 and 100");
+ adt_res = EINVAL;
+ goto out;
+ }
+
+ HAL_DEBUG (("SetCPUFreqPerformance is: %d", arg_val));
+
+ /*
+ * Update the /etc/power.conf file
+ */
+ tmp_fd = mkstemp (tmp_conf_file);
+ if (tmp_fd == -1) {
+ HAL_ERROR ((" Error in creating a temp conf file"));
+ adt_res = EINVAL;
+ goto out;
+ }
+ pc_edit_type.cpu_th = arg_val * 15;
+ adt_res = edit_power_conf_file (pc_edit_type, CPU_PERFORMANCE,
+ tmp_conf_file);
+ if (adt_res != 0) {
+ HAL_DEBUG (("Error while editing /etc/power.conf"));
+ gen_cpufreq_err (con, msg,
+ "Internal error while setting the performance");
+ unlink (tmp_conf_file);
+ goto out;
+ }
+
+ /*
+ * Execute pmconfig
+ */
+ sprintf (pmconfig_cmd, "%s %s", PMCONFIG, tmp_conf_file);
+ if (system (pmconfig_cmd) != 0) {
+ HAL_ERROR ((" Error in executing pmconfig: %s",
+ strerror (errno)));
+ adt_res = errno;
+ gen_cpufreq_err (con, msg,
+ "Internal error while setting the performance");
+ unlink (tmp_conf_file);
+ goto out;
+ }
+ unlink (tmp_conf_file);
+ HAL_DEBUG (("Executed pmconfig"));
+
+ /*
+ * Just return an empty response, so that if the client
+ * is waiting for any response will not keep waiting
+ */
+
+ msg_reply = dbus_message_new_method_return (msg);
+ if (msg_reply == NULL) {
+ HAL_ERROR (("Out of memory to msg reply"));
+ gen_cpufreq_err (con, msg,
+ "Out of memory to create a response");
+ adt_res = ENOMEM;
+ goto out;
+ }
+
+ if (!dbus_connection_send (con, msg_reply, NULL)) {
+ HAL_ERROR (("Out of memory to msg reply"));
+ gen_cpufreq_err (con, msg,
+ "Out of memory to create a response");
+ adt_res = ENOMEM;
+ goto out;
+ }
+
+ dbus_connection_flush (con);
+out:
+#ifdef sun
+
+ /*
+ * Audit the new performance change
+ */
+ dbus_error_init (&error);
+ system_bus = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
+ if (system_bus == NULL) {
+ HAL_INFO (("Cannot connect to the system bus %s",
+ error.message));
+ LIBHAL_FREE_DBUS_ERROR (&error);
+ return;
+ }
+
+ adt_data = get_audit_export_data (system_bus, sender, &adt_data_size);
+ if (adt_data != NULL) {
+ audit_cpufreq (adt_data, ADT_cpu_threshold, adt_res,
+ "solaris.system.power.cpu", arg_val);
+ free (adt_data);
+ } else {
+ HAL_INFO ((" Could not get audit export data"));
+ }
+
+#endif /* sun */
+}
+
+/*
+ * Returns in the dbus message the current gov.
+ */
+static void
+get_cpufreq_gov(DBusConnection *con, DBusMessage *msg, void *udata)
+{
+
+ DBusMessageIter rep_iter;
+ DBusMessage *msg_reply;
+ int res;
+ pconf_edit_type pc_type;
+ char *param;
+
+ /*
+ * Get the governor type from /etc/power.conf if it is present.
+ */
+ res = get_cur_val (&pc_type, CPU_GOV);
+ if (res != 1) {
+ HAL_INFO ((" Error in getting the current governor"));
+ gen_cpufreq_err (con, msg, "Internal error while getting"
+ " the governor");
+ return;
+ }
+
+ HAL_DEBUG ((" Current governor is: %s", pc_type.cpu_gov));
+
+ msg_reply = dbus_message_new_method_return (msg);
+ if (msg_reply == NULL) {
+ HAL_ERROR (("Out of memory to msg reply"));
+ gen_cpufreq_err (con, msg,
+ "Internal error while getting the governor");
+ return;
+ }
+
+ /*
+ * Append reply arguments
+ */
+ param = (char *) malloc (sizeof (char) * 250);
+ if (param == NULL) {
+ HAL_ERROR (("\n Could not allocate mem to param"));
+ gen_cpufreq_err (con, msg, "Internal error while getting"
+ " the governor");
+ return;
+ }
+ sprintf (param, "%s", pc_type.cpu_gov);
+
+ dbus_message_iter_init_append (msg_reply, &rep_iter);
+ if (!dbus_message_iter_append_basic (&rep_iter, DBUS_TYPE_STRING,
+ &param)) {
+ HAL_ERROR (("\n Out Of Memory!\n"));
+ gen_cpufreq_err (con, msg, "Internal error while getting"
+ " the governor");
+ free (param);
+ return;
+ }
+
+ if (!dbus_connection_send (con, msg_reply, NULL)) {
+ HAL_ERROR (("\n Out Of Memory!\n"));
+ gen_cpufreq_err (con, msg, "Internal error while getting"
+ " the governor");
+ free (param);
+ return;
+ }
+ dbus_connection_flush (con);
+ free (param);
+}
+
+/*
+ * Returns in the dbus message the current performance value
+ */
+static void
+get_cpufreq_performance(DBusConnection *con, DBusMessage *msg, void *udata)
+{
+
+ DBusMessageIter rep_iter;
+ DBusMessage *msg_reply;
+ int res;
+ pconf_edit_type pc_type;
+ int param_int;
+
+ /*
+ * Get the performance value
+ */
+ res = get_cur_val (&pc_type, CPU_PERFORMANCE);
+ if (res != 1) {
+ HAL_INFO ((" Error in getting current performance"));
+ gen_cpufreq_err (con, msg, "Internal error while getting"
+ " the performance value");
+ return;
+ }
+
+ HAL_DEBUG ((" The current performance: %d", pc_type.cpu_th));
+
+ msg_reply = dbus_message_new_method_return (msg);
+ if (msg_reply == NULL) {
+ HAL_ERROR (("Out of memory to msg reply"));
+ gen_cpufreq_err (con, msg, "Internal error while getting"
+ " the performance value");
+ return;
+ }
+
+ /*
+ * Append reply arguments.pc_type.cpu_th gives the current cputhreshold
+ * vlaue in seconds. Have to convert it into CPU HAL interface
+ * performance value
+ */
+ if (pc_type.cpu_th < 15)
+ param_int = 1;
+ else
+ param_int = (pc_type.cpu_th / 15);
+
+ HAL_DEBUG (("Performance: %d \n", param_int));
+
+ dbus_message_iter_init_append (msg_reply, &rep_iter);
+ if (!dbus_message_iter_append_basic (&rep_iter, DBUS_TYPE_INT32,
+ &param_int)) {
+ HAL_ERROR (("\n Out Of Memory!\n"));
+ gen_cpufreq_err (con, msg, "Internal error while getting"
+ " the performance value");
+ return;
+ }
+
+ if (!dbus_connection_send (con, msg_reply, NULL)) {
+ HAL_ERROR (("\n Out Of Memory!\n"));
+ gen_cpufreq_err (con, msg, "Internal error while getting"
+ " the performance value");
+ return;
+ }
+ dbus_connection_flush (con);
+}
+
+/*
+ * Returns list of available governors. Currently just two governors are
+ * supported. They are "ondemand" and "performance"
+ */
+
+static void
+get_cpufreq_avail_gov(DBusConnection *con, DBusMessage *msg, void *udata)
+{
+
+ DBusMessageIter rep_iter;
+ DBusMessageIter array_iter;
+ DBusMessage *msg_reply;
+ int ngov;
+
+ msg_reply = dbus_message_new_method_return (msg);
+ if (msg_reply == NULL) {
+ HAL_ERROR (("Out of memory to msg reply"));
+ gen_cpufreq_err (con, msg, "Internal error while getting"
+ " the list of governors");
+ return;
+ }
+
+ /*
+ * Append reply arguments
+ */
+ dbus_message_iter_init_append (msg_reply, &rep_iter);
+
+ if (!dbus_message_iter_open_container (&rep_iter,
+ DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING,
+ &array_iter)) {
+ HAL_ERROR (("\n Out of memory to msg reply array"));
+ gen_cpufreq_err (con, msg, "Internal error while getting"
+ " the list of governors");
+ return;
+ }
+
+ for (ngov = 0; gov_list[ngov] != NULL; ngov++) {
+ if (gov_list[ngov])
+ HAL_DEBUG (("\n%d Gov Name: %s", ngov, gov_list[ngov]));
+ dbus_message_iter_append_basic (&array_iter,
+ DBUS_TYPE_STRING,
+ &gov_list[ngov]);
+ }
+ dbus_message_iter_close_container (&rep_iter, &array_iter);
+
+ if (!dbus_connection_send (con, msg_reply, NULL)) {
+ HAL_ERROR (("\n Out Of Memory!\n"));
+ gen_cpufreq_err (con, msg, "Internal error while getting"
+ " the list of governors");
+ return;
+ }
+ dbus_connection_flush (con);
+}
+
+static DBusHandlerResult
+hald_dbus_cpufreq_filter(DBusConnection *con, DBusMessage *msg, void *udata)
+{
+ HAL_DEBUG ((" Inside CPUFreq filter:%s", dbus_message_get_path(msg)));
+ /*
+ * Check for method types
+ */
+ if (!dbus_connection_get_is_connected (con))
+ HAL_DEBUG (("Connection disconnected in cpufreq addon"));
+
+ if (dbus_message_is_method_call (msg,
+ "org.freedesktop.Hal.Device.CPUFreq",
+ "SetCPUFreqGovernor")) {
+ HAL_DEBUG (("---- SetCPUFreqGovernor is called "));
+
+ set_cpufreq_gov (con, msg, udata);
+
+ } else if (dbus_message_is_method_call (msg,
+ "org.freedesktop.Hal.Device.CPUFreq",
+ "GetCPUFreqGovernor")) {
+ HAL_DEBUG (("---- GetCPUFreqGovernor is called "));
+
+ get_cpufreq_gov (con, msg, udata);
+ } else if (dbus_message_is_method_call (msg,
+ "org.freedesktop.Hal.Device.CPUFreq",
+ "GetCPUFreqAvailableGovernors")) {
+ HAL_DEBUG (("---- GetCPUFreqAvailableGovernors is called "));
+
+ get_cpufreq_avail_gov (con, msg, udata);
+ } else if (dbus_message_is_method_call (msg,
+ "org.freedesktop.Hal.Device.CPUFreq",
+ "SetCPUFreqPerformance")) {
+ HAL_DEBUG (("---- SetCPUFreqPerformance is called "));
+
+ set_cpufreq_performance (con, msg, udata);
+ } else if (dbus_message_is_method_call (msg,
+ "org.freedesktop.Hal.Device.CPUFreq",
+ "GetCPUFreqPerformance")) {
+ HAL_DEBUG (("---- GetCPUFreqPerformance is called "));
+
+ get_cpufreq_performance (con, msg, udata);
+ } else {
+ HAL_DEBUG (("---Not Set/Get cpufreq gov---"));
+ }
+
+ return (DBUS_HANDLER_RESULT_HANDLED);
+
+}
+
+static void
+drop_privileges()
+{
+ priv_set_t *pPrivSet = NULL;
+ priv_set_t *lPrivSet = NULL;
+
+ /*
+ * Start with the 'basic' privilege set and then add any
+ * of the privileges that will be required.
+ */
+ if ((pPrivSet = priv_str_to_set ("basic", ",", NULL)) == NULL) {
+ HAL_INFO (("Error in setting the priv"));
+ return;
+ }
+
+ (void) priv_addset (pPrivSet, PRIV_SYS_DEVICES);
+
+ if (setppriv (PRIV_SET, PRIV_INHERITABLE, pPrivSet) != 0) {
+ HAL_INFO (("Could not set the privileges"));
+ priv_freeset (pPrivSet);
+ return;
+ }
+
+ (void) priv_addset (pPrivSet, PRIV_PROC_AUDIT);
+ (void) priv_addset (pPrivSet, PRIV_SYS_CONFIG);
+
+ if (setppriv (PRIV_SET, PRIV_PERMITTED, pPrivSet) != 0) {
+ HAL_INFO (("Could not set the privileges"));
+ priv_freeset (pPrivSet);
+ return;
+ }
+
+ priv_freeset (pPrivSet);
+
+}
+
+int
+main(int argc, char **argv)
+{
+
+ LibHalContext *ctx = NULL;
+ char *udi;
+ DBusError error;
+ DBusConnection *conn;
+
+ GMainLoop *loop = g_main_loop_new (NULL, FALSE);
+
+ drop_privileges ();
+ openlog ("hald-addon-cpufreq", LOG_PID, LOG_DAEMON);
+ setup_logger ();
+
+ bzero (current_gov, EDIT_TYPE_SIZE-1);
+
+ if ((udi = getenv ("UDI")) == NULL) {
+ HAL_INFO (("\n Could not get the UDI in addon-cpufreq"));
+ return (0);
+ }
+
+ dbus_error_init (&error);
+ if ((ctx = libhal_ctx_init_direct (&error)) == NULL) {
+ HAL_ERROR (("main(): init_direct failed\n"));
+ return (0);
+ }
+ dbus_error_init (&error);
+ if (!libhal_device_addon_is_ready (ctx, getenv ("UDI"), &error)) {
+ check_and_free_error (&error);
+ return (0);
+ }
+
+ /*
+ * Claim the cpufreq interface
+ */
+
+ HAL_DEBUG (("cpufreq Introspect XML: %s", cpufreq_introspect_xml));
+
+ if (!libhal_device_claim_interface (ctx,
+ udi,
+ "org.freedesktop.Hal.Device.CPUFreq",
+ cpufreq_introspect_xml,
+ &error)) {
+ HAL_DEBUG ((" Cannot claim the CPUFreq interface"));
+ check_and_free_error (&error);
+ return (0);
+ }
+
+ conn = libhal_ctx_get_dbus_connection (ctx);
+
+ /*
+ * Add the cpufreq capability
+ */
+ if (!libhal_device_add_capability (ctx,
+ udi,
+ "cpufreq_control",
+ &error)) {
+ HAL_DEBUG ((" Could not add cpufreq_control capability"));
+ check_and_free_error (&error);
+ return (0);
+ }
+ /*
+ * Watches and times incoming messages
+ */
+
+ dbus_connection_setup_with_g_main (conn, NULL);
+
+ /*
+ * Add a filter function which gets called when a message comes in
+ * and processes the message
+ */
+
+ if (!dbus_connection_add_filter (conn,
+ hald_dbus_cpufreq_filter,
+ NULL,
+ NULL)) {
+ HAL_INFO ((" Cannot add the CPUFreq filter function"));
+ return (0);
+ }
+
+ dbus_connection_set_exit_on_disconnect (conn, 0);
+
+ g_main_loop_run (loop);
+}
diff --git a/usr/src/cmd/hal/fdi/Makefile b/usr/src/cmd/hal/fdi/Makefile
index 786b66510d..7e3553d585 100644
--- a/usr/src/cmd/hal/fdi/Makefile
+++ b/usr/src/cmd/hal/fdi/Makefile
@@ -45,6 +45,7 @@ FDIS = information/10freedesktop/10-camera-ptp.fdi \
policy/10osvendor/10-laptop-panel-mgmt-policy.fdi \
policy/10osvendor/10-network-attached.fdi \
policy/10osvendor/10-power-mgmt-policy.fdi \
+ policy/10osvendor/10-cpufreq.fdi \
policy/10osvendor/10-toshiba-buttons.fdi \
policy/10osvendor/20-storage-methods.fdi \
policy/10osvendor/20-zfs-methods.fdi \
diff --git a/usr/src/cmd/hal/fdi/policy/10osvendor/10-cpufreq.fdi b/usr/src/cmd/hal/fdi/policy/10osvendor/10-cpufreq.fdi
new file mode 100644
index 0000000000..abff0c23f8
--- /dev/null
+++ b/usr/src/cmd/hal/fdi/policy/10osvendor/10-cpufreq.fdi
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<deviceinfo version="0.2">
+
+ <device>
+ <match key="info.udi" string="/org/freedesktop/Hal/devices/computer">
+ <append key="info.addons" type="strlist">hald-addon-cpufreq</append>
+ </match>
+ </device>
+</deviceinfo>
diff --git a/usr/src/cmd/hal/hald/Makefile b/usr/src/cmd/hal/hald/Makefile
index b13b4bf4d6..fbc557b482 100644
--- a/usr/src/cmd/hal/hald/Makefile
+++ b/usr/src/cmd/hal/hald/Makefile
@@ -32,7 +32,8 @@ OBJS = hald_marshal.o device.o device_info.o device_store.o hald.o \
hald_dbus.o hald_runner.o ids.o logger.o property.o util.o \
util_helper.o util_pm.o
OBJS_SOL = devinfo.o devinfo_ieee1394.o devinfo_misc.o devinfo_pci.o devinfo_storage.o \
- devinfo_usb.o hotplug.o osspec.o sysevent.o devinfo_acpi.o
+ devinfo_usb.o hotplug.o osspec.o sysevent.o devinfo_acpi.o \
+ devinfo_cpu.o
OBJS_ALL = $(OBJS) $(OBJS_SOL:%=solaris/%)
SRCS = $(OBJS:%.o=%.c)
@@ -42,7 +43,7 @@ include ../Makefile.hal
ROOTCMDDIR = $(ROOTLIB_HAL)
LDLIBS += -lc -lm -ldbus-1 -ldbus-glib-1 -lglib-2.0 -lgobject-2.0 \
- -ldevinfo -lsysevent -lnvpair
+ -ldevinfo -lsysevent -lnvpair -lkstat -lcfgadm
all install $(PROG) := LDLIBS += -lexpat
diff --git a/usr/src/cmd/hal/hald/solaris/Makefile b/usr/src/cmd/hal/hald/solaris/Makefile
index 44d2291b3f..842488233f 100644
--- a/usr/src/cmd/hal/hald/solaris/Makefile
+++ b/usr/src/cmd/hal/hald/solaris/Makefile
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -27,7 +27,7 @@
OBJS = devinfo.o devinfo_ieee1394.o devinfo_misc.o devinfo_pci.o \
devinfo_storage.o devinfo_usb.o hotplug.o osspec.o sysevent.o \
- devinfo_acpi.o
+ devinfo_acpi.o devinfo_cpu.o
SRCS = $(OBJS:%.o=%.c)
diff --git a/usr/src/cmd/hal/hald/solaris/devinfo.c b/usr/src/cmd/hal/hald/solaris/devinfo.c
index 40af76486e..b7c61d6d22 100644
--- a/usr/src/cmd/hal/hald/solaris/devinfo.c
+++ b/usr/src/cmd/hal/hald/solaris/devinfo.c
@@ -35,6 +35,7 @@
#include "devinfo_usb.h"
#include "devinfo_misc.h"
#include "devinfo_acpi.h"
+#include "devinfo_cpu.h"
void devinfo_add_subtree(HalDevice *parent, di_node_t node, gboolean is_root);
HalDevice *devinfo_add_node(HalDevice *parent, di_node_t node);
diff --git a/usr/src/cmd/hal/hald/solaris/devinfo_cpu.c b/usr/src/cmd/hal/hald/solaris/devinfo_cpu.c
new file mode 100644
index 0000000000..25128d4de9
--- /dev/null
+++ b/usr/src/cmd/hal/hald/solaris/devinfo_cpu.c
@@ -0,0 +1,247 @@
+/***************************************************************************
+ *
+ * devinfo_cpu : cpu devices
+ *
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <kstat.h>
+#include <sys/utsname.h>
+#include <libdevinfo.h>
+#include <sys/systeminfo.h>
+
+#include "../osspec.h"
+#include "../logger.h"
+#include "../hald.h"
+#include "../hald_dbus.h"
+#include "../device_info.h"
+#include "../util.h"
+#include "devinfo_cpu.h"
+
+static HalDevice *devinfo_cpu_add(HalDevice *, di_node_t, char *, char *);
+
+DevinfoDevHandler devinfo_cpu_handler = {
+ devinfo_cpu_add,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+static HalDevice *
+devinfo_cpu_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
+{
+
+ HalDevice *d;
+ char *prom_device_type = NULL;
+ int *int_cpu_id;
+ static int cpu_id = -1;
+ uint64_t clock_mhz;
+ di_prom_handle_t phdl;
+ kstat_ctl_t *kc;
+ kstat_t *ksp;
+ kstat_named_t *ksdata;
+ dbus_bool_t is_supp_freqs;
+ char udi[HAL_PATH_MAX];
+ char *driver_name, *s;
+ char cpu_devfs_path[HAL_PATH_MAX];
+
+ /*
+ * If it is x86, the software device tree node will have the
+ * device_type information which is the one passed above. If it is
+ * NULL, check if the node has a PROM entry, and check the device_type
+ * in case of sparc. Else return NULL
+ */
+ if (device_type == NULL) {
+ /*
+ * Check the device type if it has a PROM entry. Because
+ * in sparc, the device_type entry will in the PROM node
+ */
+ if (di_nodeid (node) == DI_PROM_NODEID) {
+ phdl = di_prom_init ();
+ if (phdl == DI_PROM_HANDLE_NIL) {
+ HAL_ERROR (("Error in Initializing the PROM "
+ "handle to find cpu device: %s",
+ strerror (errno)));
+ return (NULL);
+ }
+ if (di_prom_prop_lookup_strings (phdl, node,
+ "device_type", &prom_device_type) == -1) {
+ di_prom_fini (phdl);
+ return (NULL);
+ }
+ if (strcmp (prom_device_type, "cpu") != 0) {
+ di_prom_fini (phdl);
+ return (NULL);
+ }
+ /*
+ * Get cpuid if available
+ */
+ if (di_prom_prop_lookup_ints (phdl, node,
+ "cpuid", &int_cpu_id) > 0) {
+ cpu_id = *int_cpu_id;
+ } else {
+ /*
+ * There is no cpuid entry in this arch.Just
+ * increment the cpuid which will be the
+ * current instance
+ */
+ ++cpu_id;
+ }
+ di_prom_fini (phdl);
+ } else {
+ return (NULL);
+ }
+
+ } else if (strcmp (device_type, "cpu") == 0) {
+ /*
+ * This is a x86 arch, because software device tree node
+ * has the device_type entry for cpu. The "reg" property
+ * will have the cpuid. If not just increment the cpuid
+ * which will be the current cpu instance in the kstat
+ */
+ if (di_prop_lookup_ints (DDI_DEV_T_ANY, node,
+ "reg", &int_cpu_id) > 0) {
+ cpu_id = *int_cpu_id;
+ } else {
+ /*
+ * There is no cpuid entry in this arch. Just
+ * increment the cpuid which will be the
+ * current instance
+ */
+ ++cpu_id;
+ }
+
+ } else {
+ return (NULL);
+ }
+
+ HAL_DEBUG (("CPUID=> %x", cpu_id));
+
+ d = hal_device_new ();
+
+ /*
+ * devinfo_set_default_properties () uses di_instance() as part of
+ * the udi. For some solaris devices like cpu di_instance() is not
+ * present and it returns -1. For the udi to be unique can use the
+ * cpu_id.
+ */
+ hal_device_property_set_string (d, "info.parent",
+ "/org/freedesktop/Hal/devices/local");
+
+ /*
+ * If cpu driver is not installed, then devfs_path returned by
+ * libdevinfo will be same for all cpu's.
+ * Since HAL stores the devices in its tree based on the devfs_path,
+ * To make it unique, will be concatenating devfs_path with cpu_id
+ */
+ if (di_driver_name (node) == NULL) {
+ snprintf (cpu_devfs_path, HAL_PATH_MAX, "%s_%d",
+ devfs_path, cpu_id);
+ } else {
+ snprintf (cpu_devfs_path, HAL_PATH_MAX, "%s", devfs_path);
+ }
+
+ HAL_DEBUG(("DevfsPath=> %s, CPUID=> %d", cpu_devfs_path, cpu_id));
+
+ hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
+ "/org/freedesktop/Hal/devices%s_%d", cpu_devfs_path, cpu_id);
+ hal_device_set_udi (d, udi);
+ hal_device_property_set_string (d, "info.udi", udi);
+ if (di_prop_lookup_strings (DDI_DEV_T_ANY, node, "model", &s) > 0) {
+ hal_device_property_set_string (d, "info.product", s);
+ } else {
+ hal_device_property_set_string (d, "info.product",
+ di_node_name (node));
+ }
+ hal_device_property_set_string (d, "solaris.devfs_path",
+ cpu_devfs_path);
+ if ((driver_name = di_driver_name (node)) != NULL) {
+ hal_device_property_set_string (d, "info.solaris.driver",
+ driver_name);
+ }
+
+ hal_device_add_capability (d, "processor");
+
+ hal_device_property_set_int (d, "processor.number", cpu_id);
+
+ /*
+ * Get the cpu related info from the kstat
+ */
+ kc = kstat_open ();
+ if (kc == NULL) {
+ HAL_ERROR (("Could not open kstat to get cpu info: %s",
+ strerror (errno)));
+ goto next;
+ }
+
+ ksp = kstat_lookup (kc, "cpu_info", cpu_id, NULL);
+ if (ksp == NULL) {
+ HAL_ERROR (("Could not lookup kstat to get cpu info: %s",
+ strerror (errno)));
+ if (kc) {
+ kstat_close (kc);
+ }
+ return (NULL);
+ }
+
+ kstat_read (kc, ksp, NULL);
+ ksdata = (kstat_named_t *)kstat_data_lookup (ksp, "clock_MHz");
+ if (ksdata == NULL) {
+ HAL_ERROR (("Could not get kstat clock_MHz data for cpu: %s",
+ strerror (errno)));
+ goto next;
+ }
+ clock_mhz = (uint64_t)ksdata->value.l;
+
+ if (hal_device_property_set_uint64 (d, "processor.maximum_speed",
+ clock_mhz) == FALSE) {
+ HAL_INFO (("Could not set the processor speed device prop"));
+ }
+
+
+ ksdata = (kstat_named_t *)kstat_data_lookup (ksp,
+ "supported_frequencies_Hz");
+ if (ksdata == NULL) {
+ HAL_INFO (("Could not get kstat supported_frequencies_Hz data"
+ " for cpu: %s", strerror (errno)));
+ is_supp_freqs = FALSE;
+ } else {
+ /*
+ * If more than one freq is supported, then they are seperated
+ * by a ":"
+ */
+ if (strstr (ksdata->value.str.addr.ptr, ":") == NULL) {
+ is_supp_freqs = FALSE;
+ } else {
+ is_supp_freqs = TRUE;
+ }
+ }
+
+ if (hal_device_property_set_bool (d, "processor.can_throttle",
+ is_supp_freqs) == FALSE) {
+ HAL_INFO (("Could not set the processor.can_throttle"
+ " device prop"));
+ }
+
+next:
+ if (kc) {
+ kstat_close (kc);
+ }
+
+ devinfo_add_enqueue (d, cpu_devfs_path, &devinfo_cpu_handler);
+ return (d);
+}
diff --git a/usr/src/cmd/hal/hald/solaris/devinfo_cpu.h b/usr/src/cmd/hal/hald/solaris/devinfo_cpu.h
new file mode 100644
index 0000000000..8f0423f7d0
--- /dev/null
+++ b/usr/src/cmd/hal/hald/solaris/devinfo_cpu.h
@@ -0,0 +1,21 @@
+/***************************************************************************
+ *
+ * devinfo_cpu.h : definition for cpu devices
+ *
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifndef DEVINFO_CPU_H
+#define DEVINFO_CPU_H
+
+#include "devinfo.h"
+
+extern DevinfoDevHandler devinfo_cpu_handler;
+
+#endif /* DEVINFO_CPU_H */
diff --git a/usr/src/cmd/hal/hald/solaris/devinfo_misc.c b/usr/src/cmd/hal/hald/solaris/devinfo_misc.c
index 408fd12f83..4d26b0b831 100644
--- a/usr/src/cmd/hal/hald/solaris/devinfo_misc.c
+++ b/usr/src/cmd/hal/hald/solaris/devinfo_misc.c
@@ -12,7 +12,7 @@
#pragma ident "%Z%%M% %I% %E% SMI"
#ifdef HAVE_CONFIG_H
-# include <config.h>
+#include <config.h>
#endif
#include <stdio.h>
@@ -30,7 +30,6 @@
#include "devinfo_misc.h"
static HalDevice *devinfo_computer_add(HalDevice *, di_node_t, char *, char *);
-static HalDevice *devinfo_cpu_add(HalDevice *, di_node_t, char *, char *);
static HalDevice *devinfo_keyboard_add(HalDevice *, di_node_t, char *, char *);
static HalDevice *devinfo_default_add(HalDevice *, di_node_t, char *, char *);
@@ -42,14 +41,7 @@ DevinfoDevHandler devinfo_computer_handler = {
NULL,
NULL
};
-DevinfoDevHandler devinfo_cpu_handler = {
- devinfo_cpu_add,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL
-};
+
DevinfoDevHandler devinfo_keyboard_handler = {
devinfo_keyboard_add,
NULL,
@@ -58,6 +50,7 @@ DevinfoDevHandler devinfo_keyboard_handler = {
NULL,
NULL
};
+
DevinfoDevHandler devinfo_default_handler = {
devinfo_default_add,
NULL,
@@ -122,25 +115,6 @@ devinfo_computer_add(HalDevice *parent, di_node_t node, char *devfs_path, char *
}
static HalDevice *
-devinfo_cpu_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
-{
- HalDevice *d;
-
- if ((device_type == NULL) || (strcmp(device_type, "cpu") != 0)) {
- return (NULL);
- }
-
- d = hal_device_new ();
-
- devinfo_set_default_properties (d, parent, node, devfs_path);
- hal_device_add_capability (d, "processor");
-
- devinfo_add_enqueue (d, devfs_path, &devinfo_cpu_handler);
-
- return (d);
-}
-
-static HalDevice *
devinfo_keyboard_add(HalDevice *parent, di_node_t node, char *devfs_path,
char *device_type)
{
diff --git a/usr/src/cmd/hal/hald/solaris/devinfo_misc.h b/usr/src/cmd/hal/hald/solaris/devinfo_misc.h
index 609f53e93d..ea5237f174 100644
--- a/usr/src/cmd/hal/hald/solaris/devinfo_misc.h
+++ b/usr/src/cmd/hal/hald/solaris/devinfo_misc.h
@@ -16,7 +16,6 @@
#include "devinfo.h"
-extern DevinfoDevHandler devinfo_cpu_handler;
extern DevinfoDevHandler devinfo_computer_handler;
extern DevinfoDevHandler devinfo_keyboard_handler;
extern DevinfoDevHandler devinfo_default_handler;
diff --git a/usr/src/cmd/hal/hald/solaris/sysevent.c b/usr/src/cmd/hal/hald/solaris/sysevent.c
index 7fabccfaf4..d245c0a901 100644
--- a/usr/src/cmd/hal/hald/solaris/sysevent.c
+++ b/usr/src/cmd/hal/hald/solaris/sysevent.c
@@ -12,7 +12,7 @@
#pragma ident "%Z%%M% %I% %E% SMI"
#ifdef HAVE_CONFIG_H
-# include <config.h>
+#include <config.h>
#endif
#include <stdio.h>
@@ -27,7 +27,10 @@
#include <libsysevent.h>
#include <sys/sysevent/dev.h>
#include <sys/sysevent/pwrctl.h>
+#include <sys/sysevent/dr.h>
#include <glib.h>
+#include <config_admin.h>
+#include <kstat.h>
#include "../osspec.h"
#include "../logger.h"
@@ -42,6 +45,8 @@
#include "devinfo_acpi.h"
#include "devinfo_usb.h"
#include "sysevent.h"
+#include "devinfo_misc.h"
+#include "devinfo_cpu.h"
#ifndef ESC_LOFI
#define ESC_LOFI "lofi"
@@ -57,6 +62,7 @@ static void sysevent_lofi_remove(gchar *, gchar *);
static void sysevent_devfs_add(gchar *);
static void sysevent_pwrctl(gchar *, gchar *, gchar *, gchar *, gchar *,
gchar *, uint_t);
+static void sysevent_process_dr(gchar *, gchar *);
static sysevent_handle_t *shp;
@@ -132,6 +138,14 @@ sysevent_init(void)
return (FALSE);
}
+ subcl[0] = ESC_DR_AP_STATE_CHANGE;
+ if (sysevent_subscribe_event(shp, EC_DR, subcl, 1) != 0) {
+ HAL_INFO (("subscribe(dynamic reconfiguration) failed %d",
+ errno));
+ sysevent_unbind_handle(shp);
+ return (FALSE);
+ }
+
return (B_TRUE);
}
@@ -183,12 +197,24 @@ sysevent_dev_handler(sysevent_t *ev)
&phys_path) != 0) {
goto out;
}
+ } else if (strcmp(class, EC_DR) == 0) {
+ if (nvlist_lookup_string(attr_list, DR_AP_ID,
+ &phys_path) != 0) {
+ goto out;
+ }
} else if (nvlist_lookup_string(attr_list, DEV_PHYS_PATH, &phys_path)
!= 0) {
goto out;
}
- if (nvlist_lookup_string(attr_list, DEV_NAME, &dev_name) != 0) {
+ /*
+ * In case of EC_DR, use dev_name to store DR_HINT val
+ */
+ if (strcmp(class, EC_DR) == 0) {
+ if (nvlist_lookup_string(attr_list, DR_HINT, &dev_name) != 0) {
+ goto out;
+ }
+ } else if (nvlist_lookup_string(attr_list, DEV_NAME, &dev_name) != 0) {
if (strcmp(class, EC_PWRCTL) == 0) {
dev_name = "noname";
} else {
@@ -241,7 +267,7 @@ sysevent_iochannel_data (GIOChannel *source,
if (len == 0) {
break;
}
-
+ HAL_INFO (("IOChannel val => %s", s));
class[0] = subclass[0] = phys_path[0] = dev_name[0] =
dev_hid[0] = dev_uid[0] = '\0';
matches = sscanf(s, "%s %s %s %s %s %s %d", class, subclass,
@@ -276,6 +302,17 @@ sysevent_iochannel_data (GIOChannel *source,
if (strcmp(subclass, ESC_DEVFS_DEVI_ADD) == 0) {
sysevent_devfs_add(phys_path);
}
+ } else if (strcmp(class, EC_DR) == 0) {
+ /*
+ * Note: AP_ID is stored in phys_path and HINT is
+ * stored in dev_name, to avoid creating seperate
+ * variables and multiple conditions checking
+ */
+ HAL_DEBUG (("In %s, AP_ID-> %s, Hint-> %s", class,
+ phys_path, dev_name));
+ if (strcmp(subclass, ESC_DR_AP_STATE_CHANGE) == 0) {
+ sysevent_process_dr(phys_path, dev_name);
+ }
}
}
@@ -467,3 +504,159 @@ sysevent_pwrctl(gchar *class, gchar *subclass, gchar *phys_path,
HAL_INFO(("Unmatched EC_PWRCTL"));
}
}
+
+static void
+sysevent_dr_remove_cpu()
+{
+
+ HalDeviceStore *gdl;
+ GSList *iter;
+ HalDevice *d, *del_dev;
+ int cpu_id, del_cpuid;
+ kstat_ctl_t *kc;
+ kstat_t *ksp;
+ kstat_named_t *ksdata;
+ const char *cpu_devfs_path;
+ /*
+ * Find the CPU's that are DR removed. For each "processor" device in
+ * HAL device tree, check if it has its corresponding kstat_info. If
+ * not, then, that cpu has been removed and can remove the entry from
+ * HAL entry
+ */
+
+ HAL_DEBUG (("sysevent_dr_remove_cpu()"));
+ kc = kstat_open ();
+ if (kc == NULL) {
+ HAL_INFO (("Error in removing HAL cpu entry during DR. Could"
+ " not open kstat to get cpu info: %s", strerror (errno)));
+ return;
+ }
+
+ /*
+ * Iterate through the HAL device list to get the processor devices
+ */
+ gdl = hald_get_gdl ();
+ iter = gdl->devices;
+
+ while (iter != NULL) {
+ d = HAL_DEVICE (iter->data);
+
+ if (!hal_device_has_property (d, "processor.number")) {
+ iter = iter->next;
+ continue;
+ }
+
+ cpu_id = hal_device_property_get_int (d, "processor.number");
+
+ /*
+ * Check if the above cpu_id has its info in kstat
+ */
+
+ ksp = kstat_lookup (kc, "cpu_info", cpu_id, NULL);
+ if (ksp != NULL) {
+ iter = iter->next;
+ continue;
+ }
+ /*
+ * kstat info not found. Delete the device entry
+ */
+ HAL_INFO ((" Remove CPU entry: %d", cpu_id));
+ iter = iter->next;
+ cpu_devfs_path = hal_device_property_get_string (d,
+ "solaris.devfs_path");
+ if (cpu_devfs_path == NULL) {
+ HAL_INFO (("Could not get cpu_devfs_path to "
+ "remove for cpu_id %d", cpu_id));
+ } else {
+ /*
+ * Remove the cpu device
+ */
+ HAL_DEBUG (("Queue %s for removal", cpu_devfs_path));
+ devinfo_remove_enqueue ((char *)cpu_devfs_path, NULL);
+ hotplug_event_process_queue ();
+ }
+ }
+
+ if (kc) {
+ kstat_close (kc);
+ }
+}
+
+int
+sysevent_dr_insert_cpu(di_node_t node, void *arg)
+{
+ char *devfs_path;
+ char *device_type = NULL;
+ DevinfoDevHandler *dh;
+
+ dh = &devinfo_cpu_handler;
+ devfs_path = di_devfs_path (node);
+
+ (void) di_prop_lookup_strings (DDI_DEV_T_ANY, node, "device_type",
+ &device_type);
+
+ dh->add (NULL, node, devfs_path, device_type);
+
+ di_devfs_path_free (devfs_path);
+ return (DI_WALK_CONTINUE);
+}
+
+/*
+ * Remove/Add the DR event device
+ * Note: Currently it supports only CPU DR events
+ */
+static void
+sysevent_process_dr(gchar *ap_id, gchar *hint_val)
+{
+ cfga_err_t cfgerr;
+ cfga_list_data_t *cfg_stat;
+ int nlist;
+ char *errstr;
+ di_node_t root_node;
+
+ if ((ap_id == NULL) || (hint_val == NULL))
+ return;
+ HAL_DEBUG (("sysevent_process_dr: %s", ap_id));
+
+ cfgerr = config_list_ext (1, (char *const *)&ap_id, &cfg_stat, &nlist,
+ NULL, NULL, &errstr, 0);
+
+ if (cfgerr != CFGA_OK) {
+ HAL_INFO (("DR sysevent process %d config_list_ext error: %s",
+ ap_id, errstr));
+ goto out;
+ }
+ /*
+ * Check if the device type is CPU
+ */
+ HAL_DEBUG ((" Ap-Type: %s, State: %d", cfg_stat->ap_type,
+ cfg_stat->ap_r_state));
+ if (strcmp (cfg_stat->ap_type, "CPU") == 0) {
+ if (strcmp (hint_val, DR_HINT_REMOVE) == 0) {
+ sysevent_dr_remove_cpu();
+ } else if (strcmp (hint_val, DR_HINT_INSERT) == 0) {
+ /*
+ * Go through the device list and add the new cpu
+ * entries into HAL
+ */
+ if ((root_node =
+ di_init ("/", DINFOCPYALL)) == DI_NODE_NIL) {
+ HAL_INFO (("di_init failed. "\
+ "Cannot insert CPU"));
+ goto out;
+ }
+ di_walk_node (root_node, DI_WALK_CLDFIRST, NULL,
+ sysevent_dr_insert_cpu);
+ di_fini (root_node);
+ hotplug_event_process_queue ();
+ }
+ } else {
+ HAL_INFO (("Not a CPU, so cannot DR"));
+ }
+
+out:
+ if (cfg_stat)
+ free (cfg_stat);
+ if (errstr)
+ free (errstr);
+}
diff --git a/usr/src/cmd/hal/tools/Makefile b/usr/src/cmd/hal/tools/Makefile
index 84f577c141..3cce4d6d23 100644
--- a/usr/src/cmd/hal/tools/Makefile
+++ b/usr/src/cmd/hal/tools/Makefile
@@ -48,9 +48,10 @@ STORAGE_PROG = $(STORAGE_METHOD_PROG) \
PROGSRCS = $(PROG:%=%.c) $(STORAGE_PROG:%=%.c)
+
STORAGE_OBJS = $(STORAGE_PROG:%=%.o)
-STORAGE_SHAREDOBJS = hal-storage-shared.o
-STORAGE_SHAREDSRCS = $(STORAGE_SHAREDOBJS:%.o=%.c)
+STORAGE_SHAREDOBJS = hal-storage-shared.o adt_data.o logger.o
+STORAGE_SHAREDSRCS = $(STORAGE_SHAREDOBJS:%.o=%.c) $(STORAGE_SHAREDOBJS:%.o=../utils/%.c) $(STORAGE_SHAREDOBJS:%.o=../hald/%.c)
SRCS = $(PROGSRCS) $(STORAGE_SHAREDSRCS)
@@ -92,8 +93,14 @@ clobber := TARGET= clobber
all: $(HAL_PROG) $(STORAGE_PROG) $(SCRIPT_BIN) $(SCRIPT_LIB) $(HAL_LIB) $(SUBDIR)
-$(STORAGE_SHAREDOBJS): $(STORAGE_SHAREDSRCS)
- $(COMPILE.c) $(STORAGE_SHAREDSRCS)
+hal-storage-shared.o: hal-storage-shared.c
+ $(COMPILE.c) -o $@ hal-storage-shared.c
+
+adt_data.o: ../utils/adt_data.c
+ $(COMPILE.c) -o $@ ../utils/adt_data.c
+
+logger.o: ../hald/logger.c
+ $(COMPILE.c) -o $@ ../hald/logger.c
hal-storage-closetray: hal-storage-closetray.o $(STORAGE_SHAREDOBJS)
$(LINK.c) hal-storage-closetray.o $(STORAGE_SHAREDOBJS) -o $@ $(LDLIBS)
diff --git a/usr/src/cmd/hal/tools/hal-storage-shared.c b/usr/src/cmd/hal/tools/hal-storage-shared.c
index 05a1c43a36..4adbfd61f8 100644
--- a/usr/src/cmd/hal/tools/hal-storage-shared.c
+++ b/usr/src/cmd/hal/tools/hal-storage-shared.c
@@ -698,90 +698,6 @@ auth_from_privilege(const char *privilege)
return (authname);
}
-adt_export_data_t *
-get_audit_export_data(DBusConnection *bus, const char *invoked_by_syscon_name, size_t *data_size)
-{
- DBusMessage *message;
- DBusMessage *reply;
- DBusMessageIter iter, subiter;
- DBusError error;
- int count, bufsize;
- uchar_t *buf;
- uchar_t value;
-
- message = dbus_message_new_method_call ("org.freedesktop.DBus",
- "/org/freedesktop/DBus",
- "org.freedesktop.DBus",
- "GetAuditSessionData");
- if (message == NULL) {
- printf ("cannot get message\n");
- return NULL;
- }
-
- if (!dbus_message_append_args(message, DBUS_TYPE_STRING, &invoked_by_syscon_name,
- DBUS_TYPE_INVALID)) {
- dbus_message_unref(message);
- return NULL;
- }
-
- dbus_error_init (&error);
- reply = dbus_connection_send_with_reply_and_block (bus,
- message, -1,
- &error);
- if (dbus_error_is_set (&error)) {
- printf ("send failed %s\n", error.message);
- dbus_error_free (&error);
- dbus_message_unref (message);
- return NULL;
- }
- if (reply == NULL) {
- dbus_message_unref (message);
- return NULL;
- }
-
- dbus_message_iter_init (reply, &iter);
-
- if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY ||
- dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_BYTE) {
- printf ("expecting an array of byte entries\n");
- dbus_message_unref (message);
- dbus_message_unref (reply);
- return NULL;
- }
- dbus_message_iter_recurse (&iter, &subiter);
-
- count = 0;
- bufsize = 256;
- buf = (uchar_t *)malloc (bufsize);
-
- while (dbus_message_iter_get_arg_type (&subiter) == DBUS_TYPE_BYTE) {
- if (count == bufsize) {
- bufsize += 256;
- buf = realloc (buf, bufsize);
- if (buf == NULL) {
- dbus_message_unref (message);
- dbus_message_unref (reply);
- return NULL;
- }
- }
-
- dbus_message_iter_get_basic (&subiter, &value);
- buf[count++] = value;
- dbus_message_iter_next(&subiter);
- }
-
- dbus_message_unref (message);
- dbus_message_unref (reply);
-
- *data_size = count;
- if (count == 0) {
- free (buf);
- buf = NULL;
- }
-
- return (adt_export_data_t *)buf;
-}
-
void
audit_volume(const adt_export_data_t *imported_state, au_event_t event_id,
int result, const char *auth_used, const char *mount_point,
diff --git a/usr/src/cmd/hal/tools/hal-storage-shared.h b/usr/src/cmd/hal/tools/hal-storage-shared.h
index 8238011e2f..f48e116335 100644
--- a/usr/src/cmd/hal/tools/hal-storage-shared.h
+++ b/usr/src/cmd/hal/tools/hal-storage-shared.h
@@ -32,6 +32,7 @@
#ifdef sun
#include <bsm/adt.h>
#include <bsm/adt_event.h>
+#include "../utils/adt_data.h"
#endif
/*#define DEBUG*/
@@ -71,8 +72,6 @@ void handle_eject (LibHalContext *hal_ctx,
#ifdef sun
char *auth_from_privilege(const char *privilege);
-adt_export_data_t *get_audit_export_data(DBusConnection *bus, const char *invoked_by_syscon_name,
- size_t *data_size);
void audit_volume(const adt_export_data_t *imported_state, au_event_t event_id, int result,
const char *auth_used, const char *mount_point, const char *device, const char *options);
#endif /* sun */
diff --git a/usr/src/cmd/hal/utils/adt_data.c b/usr/src/cmd/hal/utils/adt_data.c
new file mode 100644
index 0000000000..059e4273b2
--- /dev/null
+++ b/usr/src/cmd/hal/utils/adt_data.c
@@ -0,0 +1,106 @@
+/***************************************************************************
+ *
+ * adt_data.c : Provides Audit functionalities
+ *
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ ***************************************************************************/
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+#include <dbus/dbus-glib.h>
+#include "../hald/logger.h"
+#include "adt_data.h"
+
+adt_export_data_t *
+get_audit_export_data(DBusConnection *bus, const char *invoked_by_syscon_name, size_t *data_size)
+{
+ DBusMessage *message;
+ DBusMessage *reply;
+ DBusMessageIter iter, subiter;
+ DBusError error;
+ int count, bufsize;
+ uchar_t *buf;
+ uchar_t value;
+
+ message = dbus_message_new_method_call ("org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus",
+ "GetAuditSessionData");
+ if (message == NULL) {
+ HAL_INFO (("cannot get GetAuditSessionData message\n"));
+ return NULL;
+ }
+
+ if (!dbus_message_append_args(message, DBUS_TYPE_STRING, &invoked_by_syscon_name,
+ DBUS_TYPE_INVALID)) {
+ dbus_message_unref(message);
+ return NULL;
+ }
+
+ dbus_error_init (&error);
+ reply = dbus_connection_send_with_reply_and_block (bus,
+ message, -1,
+ &error);
+ if (dbus_error_is_set (&error)) {
+ HAL_INFO (("send failed %s\n", error.message));
+ dbus_error_free (&error);
+ dbus_message_unref (message);
+ return NULL;
+ }
+ if (reply == NULL) {
+ dbus_message_unref (message);
+ return NULL;
+ }
+
+ dbus_message_iter_init (reply, &iter);
+
+ if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY ||
+ dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_BYTE) {
+ HAL_INFO (("expecting an array of byte entries\n"));
+ dbus_message_unref (message);
+ dbus_message_unref (reply);
+ return NULL;
+ }
+ dbus_message_iter_recurse (&iter, &subiter);
+
+ count = 0;
+ bufsize = 256;
+ buf = (uchar_t *)malloc (bufsize);
+
+ while (dbus_message_iter_get_arg_type (&subiter) == DBUS_TYPE_BYTE) {
+ if (count == bufsize) {
+ bufsize += 256;
+ buf = realloc (buf, bufsize);
+ if (buf == NULL) {
+ dbus_message_unref (message);
+ dbus_message_unref (reply);
+ return NULL;
+ }
+ }
+
+ dbus_message_iter_get_basic (&subiter, &value);
+ buf[count++] = value;
+ dbus_message_iter_next(&subiter);
+ }
+
+ dbus_message_unref (message);
+ dbus_message_unref (reply);
+
+ *data_size = count;
+ if (count == 0) {
+ free (buf);
+ buf = NULL;
+ }
+
+ return (adt_export_data_t *)buf;
+}
diff --git a/usr/src/cmd/hal/utils/adt_data.h b/usr/src/cmd/hal/utils/adt_data.h
new file mode 100644
index 0000000000..66e36e61cc
--- /dev/null
+++ b/usr/src/cmd/hal/utils/adt_data.h
@@ -0,0 +1,25 @@
+/***************************************************************************
+ *
+ * adt_data.h : Audit facility
+ *
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ ***************************************************************************/
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifndef ADT_DATA_H
+#define ADT_DATA_H
+
+#ifdef sun
+#include <bsm/adt.h>
+#include <bsm/adt_event.h>
+
+adt_export_data_t *get_audit_export_data(DBusConnection *bus, const char *invoked_by_syscon_name, size_t *data_size);
+
+#endif /* sun */
+
+#endif /* ADT_DATA_H */
diff --git a/usr/src/lib/libbsm/audit_event.txt b/usr/src/lib/libbsm/audit_event.txt
index eeb88dde79..4672437b51 100644
--- a/usr/src/lib/libbsm/audit_event.txt
+++ b/usr/src/lib/libbsm/audit_event.txt
@@ -452,6 +452,10 @@
6248:AUE_ndmp_disconnect:ndmp disconnect:na
6249:AUE_ndmp_backup:ndmp backup:na
6250:AUE_ndmp_restore:ndmp restore:na
+6251:AUE_cpu_ondemand:set ondemand CPU freq governor:ss
+6252:AUE_cpu_performance:set max CPU freq governor:ss
+6253:AUE_cpu_threshold:set CPU freq threshold:ss
+
#
# SMF(5) svc.configd events (svcadm(1M) related)
#
diff --git a/usr/src/lib/libbsm/common/adt.xml b/usr/src/lib/libbsm/common/adt.xml
index 589eb9744b..72ab42e18d 100644
--- a/usr/src/lib/libbsm/common/adt.xml
+++ b/usr/src/lib/libbsm/common/adt.xml
@@ -1756,8 +1756,70 @@ Use is subject to license terms.
<see>svccfg(1M)</see>
</event>
+<!-- CPUFreq related events -->
+
+ <event id="AUE_cpu_ondemand" header="0" idNo="93" omit="JNI">
+ <title>set CPU freq to minimal unless load increases</title>
+ <program>/usr/lib/hal/hald-addon-cpufreq</program>
+ <see>hald(1M)</see>
+ <entry id="subject">
+ <internal token="subject"/>
+ <external opt="none"/>
+ </entry>
+ <entry id="auth_used">
+ <internal token="uauth"/>
+ <external opt="required" type="char *"/>
+ <comment>authorization used</comment>
+ </entry>
+ <entry id="return">
+ <internal token="return"/>
+ <external opt="none"/>
+ </entry>
+ </event>
+ <event id="AUE_cpu_performance" header="0" idNo="94" omit="JNI">
+ <title>set CPU freq to Max</title>
+ <program>/usr/lib/hal/hald-addon-cpufreq</program>
+ <see>hald(1M)</see>
+ <entry id="subject">
+ <internal token="subject"/>
+ <external opt="none"/>
+ </entry>
+ <entry id="auth_used">
+ <internal token="uauth"/>
+ <external opt="required" type="char *"/>
+ <comment>authorization used</comment>
+ </entry>
+ <entry id="return">
+ <internal token="return"/>
+ <external opt="none"/>
+ </entry>
+ </event>
+ <event id="AUE_cpu_threshold" header="0" idNo="95" omit="JNI">
+ <title>set CPU frequency threshold percentage</title>
+ <program>/usr/lib/hal/hald-addon-cpufreq</program>
+ <see>hald(1M)</see>
+ <entry id="subject">
+ <internal token="subject"/>
+ <external opt="none"/>
+ </entry>
+ <entry id="auth_used">
+ <internal token="uauth"/>
+ <external opt="required" type="char *"/>
+ <comment>authorization used</comment>
+ </entry>
+ <entry id="threshold">
+ <internal token="text"/>
+ <external opt="required" type="int"/>
+ <comment>threshold percent 1-100</comment>
+ </entry>
+ <entry id="return">
+ <internal token="return"/>
+ <external opt="none"/>
+ </entry>
+ </event>
+
<!-- add new events here with the next higher idNo -->
-<!-- Highest idNo is 92, so next is 93, then fix this comment -->
+<!-- Highest idNo is 95, so next is 96, then fix this comment -->
<!-- end of C Only events -->
diff --git a/usr/src/lib/libsecdb/auth_attr.txt b/usr/src/lib/libsecdb/auth_attr.txt
index 06d85dff7c..1a30841a04 100644
--- a/usr/src/lib/libsecdb/auth_attr.txt
+++ b/usr/src/lib/libsecdb/auth_attr.txt
@@ -157,6 +157,7 @@ solaris.system.power.suspend.:::Suspend the System::help=SysPowerMgmtSuspend.htm
solaris.system.power.suspend.disk:::Suspend to Disk::help=SysPowerMgmtSuspendtoDisk.html
solaris.system.power.suspend.ram:::Suspend to RAM::help=SysPowerMgmtSuspendToRAM.html
solaris.system.power.brightness:::Control LCD Brightness::help=SysPowerMgmtBrightness.html
+solaris.system.power.cpu:::Manage CPU related power::help=SysCpuPowerMgmt.html
#
solaris.smf.manage.iscsitgt:::Manage ISCSI Target Service States::help=SmfValueIscsitgt.html
solaris.smf.read.iscsitgt:::Read ISCSI Target secrets::help=SmfValueIscsitgt.html
diff --git a/usr/src/lib/libsecdb/help/auths/Makefile b/usr/src/lib/libsecdb/help/auths/Makefile
index e168b9ed64..1edf262f78 100644
--- a/usr/src/lib/libsecdb/help/auths/Makefile
+++ b/usr/src/lib/libsecdb/help/auths/Makefile
@@ -136,7 +136,8 @@ HTMLENTS = \
SysPowerMgmtSuspend.html \
SysPowerMgmtSuspendtoDisk.html \
SysPowerMgmtSuspendtoRAM.html \
- SysPowerMgmtBrightness.html
+ SysPowerMgmtBrightness.html \
+ SysCpuPowerMgmt.html
HELPDIR=$(ROOT)/usr/lib/help
AUTHDIR=$(HELPDIR)/auths
diff --git a/usr/src/lib/libsecdb/help/auths/SysCpuPowerMgmt.html b/usr/src/lib/libsecdb/help/auths/SysCpuPowerMgmt.html
new file mode 100644
index 0000000000..b33e17eb8f
--- /dev/null
+++ b/usr/src/lib/libsecdb/help/auths/SysCpuPowerMgmt.html
@@ -0,0 +1,42 @@
+<HTML>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+ Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ Use is subject to license terms.
+-->
+<!-- SCCS keyword
+#pragma ident "%Z%%M% %I% %E% SMI"
+-->
+<HEAD>
+<!--
+META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"
+-->
+<!--
+META NAME="GENERATOR" CONTENT="Mozilla/4.02 [en] (X11; U; SunOS 5.6 sun4u) [Netscape]"
+-->
+</HEAD>
+<BODY>
+When Manage CPU related power is in the Authorizations Included column, it grants the authorization to modify the system cpu power management policies.
+<p>
+If Manage CPU related power is grayed, then you are not entitled to Add or Remove this authorization.
+<BR>&nbsp;
+</BODY>
+</HTML>
diff --git a/usr/src/lib/libsecdb/help/profiles/Makefile b/usr/src/lib/libsecdb/help/profiles/Makefile
index b8cc361a40..b6f704ccd1 100644
--- a/usr/src/lib/libsecdb/help/profiles/Makefile
+++ b/usr/src/lib/libsecdb/help/profiles/Makefile
@@ -85,7 +85,8 @@ HTMLENTS = \
RtSysPowerMgmtSuspend.html \
RtSysPowerMgmtSuspendtoDisk.html \
RtSysPowerMgmtSuspendtoRAM.html \
- RtSysPowerMgmtBrightness.html
+ RtSysPowerMgmtBrightness.html \
+ RtCPUPowerManagement.html
HELPDIR = $(ROOT)/usr/lib/help
diff --git a/usr/src/lib/libsecdb/help/profiles/RtCPUPowerManagement.html b/usr/src/lib/libsecdb/help/profiles/RtCPUPowerManagement.html
new file mode 100644
index 0000000000..1efbcee585
--- /dev/null
+++ b/usr/src/lib/libsecdb/help/profiles/RtCPUPowerManagement.html
@@ -0,0 +1,38 @@
+<HTML>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+-- Use is subject to license terms.
+-->
+<HEAD>
+ <TITLE> </TITLE>
+
+
+</HEAD>
+<BODY>
+<!-- ident "%Z%%M% %I% %E% SMI" -->
+
+When CPU Power Management is in the Rights Included column, it grants the right to configure CPU power management policies.
+<p>
+If CPU Power Management is grayed, then you are not entitled to Add or Remove this right.
+<p>
+</BODY>
+</HTML>
diff --git a/usr/src/lib/libsecdb/prof_attr.txt b/usr/src/lib/libsecdb/prof_attr.txt
index 0384d74bf4..45656f7e10 100644
--- a/usr/src/lib/libsecdb/prof_attr.txt
+++ b/usr/src/lib/libsecdb/prof_attr.txt
@@ -34,7 +34,7 @@
All:::Execute any command as the user or role:help=RtAll.html
Audit Control:::Configure Solaris Auditing:auths=solaris.audit.config,solaris.jobs.admin;help=RtAuditCtrl.html
Audit Review:::Review Solaris Auditing logs:auths=solaris.audit.read;help=RtAuditReview.html
-Console User:::Manage System as the Console User:profiles=Suspend To RAM,Suspend To Disk,Brightness;auths=solaris.system.shutdown;help=RtConsUser.html
+Console User:::Manage System as the Console User:profiles=Suspend To RAM,Suspend To Disk,Brightness,CPU Power Management;auths=solaris.system.shutdown;help=RtConsUser.html
Contract Observer:::Reliably observe any/all contract events:help=RtContractObserver.html
Device Management:::Control Access to Removable Media:auths=solaris.device.*;help=RtDeviceMngmnt.html
Printer Management:::Manage printers, daemons, spooling:auths=solaris.print.*,solaris.label.print,solaris.smf.manage.discovery.printers.*,solaris.smf.value.discovery.printers.*;help=RtPrntAdmin.html
@@ -101,3 +101,4 @@ Suspend:::For authorized users to Suspend system:auths=solaris.system.power.susp
Suspend To Disk:::For authorized users to Suspend to Disk:auths=solaris.system.power.suspend.disk;help=RtSysPowerMgmtSuspendToDisk.html
Suspend To RAM:::For authorized users to Suspend to RAM:auths=solaris.system.power.suspend.ram;help=RtSysPowerMgmtSuspendToRAM.html
Brightness:::For authorized users to Control LCD Brightness:auths=solaris.system.power.brightness;help=RtSysPowerMgmtBrightness.html
+CPU Power Management:::For authorized users to manage CPU Power:auths=solaris.system.power.cpu;help=RtCPUPowerManagement.html
diff --git a/usr/src/lib/policykit/libpolkit/common/libpolkit-rbac.c b/usr/src/lib/policykit/libpolkit/common/libpolkit-rbac.c
index f57d72a20c..40fad7fbfb 100644
--- a/usr/src/lib/policykit/libpolkit/common/libpolkit-rbac.c
+++ b/usr/src/lib/policykit/libpolkit/common/libpolkit-rbac.c
@@ -161,6 +161,8 @@ libpolkit_is_uid_allowed_for_privilege (LibPolKitContext *ctx,
authname = "solaris.system.power.cpu";
} else if (strcmp(privilege, "hal-power-brightness") == 0) {
authname = "solaris.system.power.brightness";
+ } else if (strcmp (privilege, "hal-power-cpu") == 0) {
+ authname = "solaris.system.power.cpu";
} else {
/* replace '-' with '.' */
authname = g_strdup (privilege);
diff --git a/usr/src/pkgdefs/SUNW0on/prototype_com b/usr/src/pkgdefs/SUNW0on/prototype_com
index 0baa381f90..6845e29791 100644
--- a/usr/src/pkgdefs/SUNW0on/prototype_com
+++ b/usr/src/pkgdefs/SUNW0on/prototype_com
@@ -313,6 +313,7 @@ f none usr/lib/help/auths/locale/SysPowerMgmtSuspend.html 444 root bin
f none usr/lib/help/auths/locale/SysPowerMgmtSuspendtoDisk.html 444 root bin
f none usr/lib/help/auths/locale/SysPowerMgmtSuspendtoRAM.html 444 root bin
f none usr/lib/help/auths/locale/SysPowerMgmtBrightness.html 444 root bin
+f none usr/lib/help/auths/locale/SysCpuPowerMgmt.html 444 root bin
#
d none usr/lib/help/profiles 755 root bin
d none usr/lib/help/profiles/locale 755 root bin
@@ -373,6 +374,7 @@ f none usr/lib/help/profiles/locale/RtSysPowerMgmtSuspend.html 444 root bin
f none usr/lib/help/profiles/locale/RtSysPowerMgmtSuspendtoDisk.html 444 root bin
f none usr/lib/help/profiles/locale/RtSysPowerMgmtSuspendtoRAM.html 444 root bin
f none usr/lib/help/profiles/locale/RtSysPowerMgmtBrightness.html 444 root bin
+f none usr/lib/help/profiles/locale/RtCPUPowerManagement.html 444 root bin
#
#
# OCF Messages
diff --git a/usr/src/pkgdefs/SUNWcsu/prototype_com b/usr/src/pkgdefs/SUNWcsu/prototype_com
index 64b01337b1..df409402f9 100644
--- a/usr/src/pkgdefs/SUNWcsu/prototype_com
+++ b/usr/src/pkgdefs/SUNWcsu/prototype_com
@@ -527,6 +527,7 @@ f none usr/lib/help/auths/locale/C/SysPowerMgmtSuspend.html 0444 root bin
f none usr/lib/help/auths/locale/C/SysPowerMgmtSuspendtoDisk.html 0444 root bin
f none usr/lib/help/auths/locale/C/SysPowerMgmtSuspendtoRAM.html 0444 root bin
f none usr/lib/help/auths/locale/C/SysPowerMgmtBrightness.html 0444 root bin
+f none usr/lib/help/auths/locale/C/SysCpuPowerMgmt.html 0444 root bin
d none usr/lib/help/profiles 755 root bin
d none usr/lib/help/profiles/locale 755 root bin
d none usr/lib/help/profiles/locale/C 755 root bin
@@ -584,6 +585,7 @@ f none usr/lib/help/profiles/locale/C/RtSysPowerMgmtSuspend.html 444 root bin
f none usr/lib/help/profiles/locale/C/RtSysPowerMgmtSuspendtoDisk.html 444 root bin
f none usr/lib/help/profiles/locale/C/RtSysPowerMgmtSuspendtoRAM.html 444 root bin
f none usr/lib/help/profiles/locale/C/RtSysPowerMgmtBrightness.html 444 root bin
+f none usr/lib/help/profiles/locale/C/RtCPUPowerManagement.html 444 root bin
d none usr/lib/iconv 755 root bin
f none usr/lib/iconv/646da.8859.t 444 root bin
f none usr/lib/iconv/646de.8859.t 444 root bin
diff --git a/usr/src/pkgdefs/SUNWhal/prototype_com b/usr/src/pkgdefs/SUNWhal/prototype_com
index 5f795202d4..664662161b 100644
--- a/usr/src/pkgdefs/SUNWhal/prototype_com
+++ b/usr/src/pkgdefs/SUNWhal/prototype_com
@@ -49,6 +49,7 @@ d none usr/lib/hal 755 root bin
f none usr/lib/hal/hald 555 root bin
f none usr/lib/hal/hald-addon-acpi 555 root bin
f none usr/lib/hal/hald-addon-network-discovery 555 root bin
+f none usr/lib/hal/hald-addon-cpufreq 555 root bin
f none usr/lib/hal/hald-addon-storage 555 root bin
f none usr/lib/hal/hald-probe-acpi 555 root bin
f none usr/lib/hal/hald-probe-network-printer 555 root bin
diff --git a/usr/src/pkgdefs/SUNWhalr/prototype_com b/usr/src/pkgdefs/SUNWhalr/prototype_com
index 8452322a9f..cb9021afc0 100644
--- a/usr/src/pkgdefs/SUNWhalr/prototype_com
+++ b/usr/src/pkgdefs/SUNWhalr/prototype_com
@@ -69,6 +69,7 @@ d none etc/hal/fdi/policy/10osvendor 755 root bin
f none etc/hal/fdi/policy/10osvendor/10-laptop-panel-mgmt-policy.fdi 444 root bin
f none etc/hal/fdi/policy/10osvendor/10-network-attached.fdi 444 root bin
f none etc/hal/fdi/policy/10osvendor/10-power-mgmt-policy.fdi 444 root bin
+f none etc/hal/fdi/policy/10osvendor/10-cpufreq.fdi 444 root bin
f none etc/hal/fdi/policy/10osvendor/10-toshiba-buttons.fdi 444 root bin
f none etc/hal/fdi/policy/10osvendor/20-storage-methods.fdi 444 root bin
f none etc/hal/fdi/policy/10osvendor/20-zfs-methods.fdi 444 root bin