a9da3307db733eb1739ba859952610bba3d894abnp/***************************************************************************
a9da3307db733eb1739ba859952610bba3d894abnp *
a9da3307db733eb1739ba859952610bba3d894abnp * devinfo_cpu : cpu devices
a9da3307db733eb1739ba859952610bba3d894abnp *
a9da3307db733eb1739ba859952610bba3d894abnp * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
a9da3307db733eb1739ba859952610bba3d894abnp * Use is subject to license terms.
a9da3307db733eb1739ba859952610bba3d894abnp *
a9da3307db733eb1739ba859952610bba3d894abnp * Licensed under the Academic Free License version 2.1
a9da3307db733eb1739ba859952610bba3d894abnp *
a9da3307db733eb1739ba859952610bba3d894abnp **************************************************************************/
a9da3307db733eb1739ba859952610bba3d894abnp
a9da3307db733eb1739ba859952610bba3d894abnp#pragma ident "%Z%%M% %I% %E% SMI"
a9da3307db733eb1739ba859952610bba3d894abnp
a9da3307db733eb1739ba859952610bba3d894abnp#ifdef HAVE_CONFIG_H
a9da3307db733eb1739ba859952610bba3d894abnp#include <config.h>
a9da3307db733eb1739ba859952610bba3d894abnp#endif
a9da3307db733eb1739ba859952610bba3d894abnp
a9da3307db733eb1739ba859952610bba3d894abnp#include <stdio.h>
a9da3307db733eb1739ba859952610bba3d894abnp#include <string.h>
a9da3307db733eb1739ba859952610bba3d894abnp#include <kstat.h>
a9da3307db733eb1739ba859952610bba3d894abnp#include <sys/utsname.h>
a9da3307db733eb1739ba859952610bba3d894abnp#include <libdevinfo.h>
a9da3307db733eb1739ba859952610bba3d894abnp#include <sys/systeminfo.h>
a9da3307db733eb1739ba859952610bba3d894abnp
a9da3307db733eb1739ba859952610bba3d894abnp#include "../osspec.h"
a9da3307db733eb1739ba859952610bba3d894abnp#include "../logger.h"
a9da3307db733eb1739ba859952610bba3d894abnp#include "../hald.h"
a9da3307db733eb1739ba859952610bba3d894abnp#include "../hald_dbus.h"
a9da3307db733eb1739ba859952610bba3d894abnp#include "../device_info.h"
a9da3307db733eb1739ba859952610bba3d894abnp#include "../util.h"
a9da3307db733eb1739ba859952610bba3d894abnp#include "devinfo_cpu.h"
a9da3307db733eb1739ba859952610bba3d894abnp
a9da3307db733eb1739ba859952610bba3d894abnpstatic HalDevice *devinfo_cpu_add(HalDevice *, di_node_t, char *, char *);
a9da3307db733eb1739ba859952610bba3d894abnp
a9da3307db733eb1739ba859952610bba3d894abnpDevinfoDevHandler devinfo_cpu_handler = {
a9da3307db733eb1739ba859952610bba3d894abnp devinfo_cpu_add,
a9da3307db733eb1739ba859952610bba3d894abnp NULL,
a9da3307db733eb1739ba859952610bba3d894abnp NULL,
a9da3307db733eb1739ba859952610bba3d894abnp NULL,
a9da3307db733eb1739ba859952610bba3d894abnp NULL,
a9da3307db733eb1739ba859952610bba3d894abnp NULL
a9da3307db733eb1739ba859952610bba3d894abnp};
a9da3307db733eb1739ba859952610bba3d894abnp
a9da3307db733eb1739ba859952610bba3d894abnpstatic HalDevice *
a9da3307db733eb1739ba859952610bba3d894abnpdevinfo_cpu_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
a9da3307db733eb1739ba859952610bba3d894abnp{
a9da3307db733eb1739ba859952610bba3d894abnp
a9da3307db733eb1739ba859952610bba3d894abnp HalDevice *d;
a9da3307db733eb1739ba859952610bba3d894abnp char *prom_device_type = NULL;
a9da3307db733eb1739ba859952610bba3d894abnp int *int_cpu_id;
a9da3307db733eb1739ba859952610bba3d894abnp static int cpu_id = -1;
a9da3307db733eb1739ba859952610bba3d894abnp uint64_t clock_mhz;
a9da3307db733eb1739ba859952610bba3d894abnp di_prom_handle_t phdl;
a9da3307db733eb1739ba859952610bba3d894abnp kstat_ctl_t *kc;
a9da3307db733eb1739ba859952610bba3d894abnp kstat_t *ksp;
a9da3307db733eb1739ba859952610bba3d894abnp kstat_named_t *ksdata;
a9da3307db733eb1739ba859952610bba3d894abnp dbus_bool_t is_supp_freqs;
a9da3307db733eb1739ba859952610bba3d894abnp char udi[HAL_PATH_MAX];
a9da3307db733eb1739ba859952610bba3d894abnp char *driver_name, *s;
a9da3307db733eb1739ba859952610bba3d894abnp char cpu_devfs_path[HAL_PATH_MAX];
a9da3307db733eb1739ba859952610bba3d894abnp
a9da3307db733eb1739ba859952610bba3d894abnp /*
a9da3307db733eb1739ba859952610bba3d894abnp * If it is x86, the software device tree node will have the
a9da3307db733eb1739ba859952610bba3d894abnp * device_type information which is the one passed above. If it is
a9da3307db733eb1739ba859952610bba3d894abnp * NULL, check if the node has a PROM entry, and check the device_type
a9da3307db733eb1739ba859952610bba3d894abnp * in case of sparc. Else return NULL
a9da3307db733eb1739ba859952610bba3d894abnp */
a9da3307db733eb1739ba859952610bba3d894abnp if (device_type == NULL) {
a9da3307db733eb1739ba859952610bba3d894abnp /*
a9da3307db733eb1739ba859952610bba3d894abnp * Check the device type if it has a PROM entry. Because
a9da3307db733eb1739ba859952610bba3d894abnp * in sparc, the device_type entry will in the PROM node
a9da3307db733eb1739ba859952610bba3d894abnp */
a9da3307db733eb1739ba859952610bba3d894abnp if (di_nodeid (node) == DI_PROM_NODEID) {
a9da3307db733eb1739ba859952610bba3d894abnp phdl = di_prom_init ();
a9da3307db733eb1739ba859952610bba3d894abnp if (phdl == DI_PROM_HANDLE_NIL) {
a9da3307db733eb1739ba859952610bba3d894abnp HAL_ERROR (("Error in Initializing the PROM "
a9da3307db733eb1739ba859952610bba3d894abnp "handle to find cpu device: %s",
a9da3307db733eb1739ba859952610bba3d894abnp strerror (errno)));
a9da3307db733eb1739ba859952610bba3d894abnp return (NULL);
a9da3307db733eb1739ba859952610bba3d894abnp }
a9da3307db733eb1739ba859952610bba3d894abnp if (di_prom_prop_lookup_strings (phdl, node,
a9da3307db733eb1739ba859952610bba3d894abnp "device_type", &prom_device_type) == -1) {
a9da3307db733eb1739ba859952610bba3d894abnp di_prom_fini (phdl);
a9da3307db733eb1739ba859952610bba3d894abnp return (NULL);
a9da3307db733eb1739ba859952610bba3d894abnp }
a9da3307db733eb1739ba859952610bba3d894abnp if (strcmp (prom_device_type, "cpu") != 0) {
a9da3307db733eb1739ba859952610bba3d894abnp di_prom_fini (phdl);
a9da3307db733eb1739ba859952610bba3d894abnp return (NULL);
a9da3307db733eb1739ba859952610bba3d894abnp }
a9da3307db733eb1739ba859952610bba3d894abnp /*
a9da3307db733eb1739ba859952610bba3d894abnp * Get cpuid if available
a9da3307db733eb1739ba859952610bba3d894abnp */
a9da3307db733eb1739ba859952610bba3d894abnp if (di_prom_prop_lookup_ints (phdl, node,
a9da3307db733eb1739ba859952610bba3d894abnp "cpuid", &int_cpu_id) > 0) {
a9da3307db733eb1739ba859952610bba3d894abnp cpu_id = *int_cpu_id;
a9da3307db733eb1739ba859952610bba3d894abnp } else {
a9da3307db733eb1739ba859952610bba3d894abnp /*
a9da3307db733eb1739ba859952610bba3d894abnp * There is no cpuid entry in this arch.Just
a9da3307db733eb1739ba859952610bba3d894abnp * increment the cpuid which will be the
a9da3307db733eb1739ba859952610bba3d894abnp * current instance
a9da3307db733eb1739ba859952610bba3d894abnp */
a9da3307db733eb1739ba859952610bba3d894abnp ++cpu_id;
a9da3307db733eb1739ba859952610bba3d894abnp }
a9da3307db733eb1739ba859952610bba3d894abnp di_prom_fini (phdl);
a9da3307db733eb1739ba859952610bba3d894abnp } else {
a9da3307db733eb1739ba859952610bba3d894abnp return (NULL);
a9da3307db733eb1739ba859952610bba3d894abnp }
a9da3307db733eb1739ba859952610bba3d894abnp
a9da3307db733eb1739ba859952610bba3d894abnp } else if (strcmp (device_type, "cpu") == 0) {
a9da3307db733eb1739ba859952610bba3d894abnp /*
a9da3307db733eb1739ba859952610bba3d894abnp * This is a x86 arch, because software device tree node
a9da3307db733eb1739ba859952610bba3d894abnp * has the device_type entry for cpu. The "reg" property
a9da3307db733eb1739ba859952610bba3d894abnp * will have the cpuid. If not just increment the cpuid
a9da3307db733eb1739ba859952610bba3d894abnp * which will be the current cpu instance in the kstat
a9da3307db733eb1739ba859952610bba3d894abnp */
a9da3307db733eb1739ba859952610bba3d894abnp if (di_prop_lookup_ints (DDI_DEV_T_ANY, node,
a9da3307db733eb1739ba859952610bba3d894abnp "reg", &int_cpu_id) > 0) {
a9da3307db733eb1739ba859952610bba3d894abnp cpu_id = *int_cpu_id;
a9da3307db733eb1739ba859952610bba3d894abnp } else {
a9da3307db733eb1739ba859952610bba3d894abnp /*
a9da3307db733eb1739ba859952610bba3d894abnp * There is no cpuid entry in this arch. Just
a9da3307db733eb1739ba859952610bba3d894abnp * increment the cpuid which will be the
a9da3307db733eb1739ba859952610bba3d894abnp * current instance
a9da3307db733eb1739ba859952610bba3d894abnp */
a9da3307db733eb1739ba859952610bba3d894abnp ++cpu_id;
a9da3307db733eb1739ba859952610bba3d894abnp }
a9da3307db733eb1739ba859952610bba3d894abnp
a9da3307db733eb1739ba859952610bba3d894abnp } else {
a9da3307db733eb1739ba859952610bba3d894abnp return (NULL);
a9da3307db733eb1739ba859952610bba3d894abnp }
a9da3307db733eb1739ba859952610bba3d894abnp
a9da3307db733eb1739ba859952610bba3d894abnp HAL_DEBUG (("CPUID=> %x", cpu_id));
a9da3307db733eb1739ba859952610bba3d894abnp
a9da3307db733eb1739ba859952610bba3d894abnp d = hal_device_new ();
a9da3307db733eb1739ba859952610bba3d894abnp
a9da3307db733eb1739ba859952610bba3d894abnp /*
a9da3307db733eb1739ba859952610bba3d894abnp * devinfo_set_default_properties () uses di_instance() as part of
a9da3307db733eb1739ba859952610bba3d894abnp * the udi. For some solaris devices like cpu di_instance() is not
a9da3307db733eb1739ba859952610bba3d894abnp * present and it returns -1. For the udi to be unique can use the
a9da3307db733eb1739ba859952610bba3d894abnp * cpu_id.
a9da3307db733eb1739ba859952610bba3d894abnp */
a9da3307db733eb1739ba859952610bba3d894abnp hal_device_property_set_string (d, "info.parent",
a9da3307db733eb1739ba859952610bba3d894abnp "/org/freedesktop/Hal/devices/local");
a9da3307db733eb1739ba859952610bba3d894abnp
a9da3307db733eb1739ba859952610bba3d894abnp /*
a9da3307db733eb1739ba859952610bba3d894abnp * If cpu driver is not installed, then devfs_path returned by
a9da3307db733eb1739ba859952610bba3d894abnp * libdevinfo will be same for all cpu's.
a9da3307db733eb1739ba859952610bba3d894abnp * Since HAL stores the devices in its tree based on the devfs_path,
a9da3307db733eb1739ba859952610bba3d894abnp * To make it unique, will be concatenating devfs_path with cpu_id
a9da3307db733eb1739ba859952610bba3d894abnp */
a9da3307db733eb1739ba859952610bba3d894abnp if (di_driver_name (node) == NULL) {
a9da3307db733eb1739ba859952610bba3d894abnp snprintf (cpu_devfs_path, HAL_PATH_MAX, "%s_%d",
a9da3307db733eb1739ba859952610bba3d894abnp devfs_path, cpu_id);
a9da3307db733eb1739ba859952610bba3d894abnp } else {
a9da3307db733eb1739ba859952610bba3d894abnp snprintf (cpu_devfs_path, HAL_PATH_MAX, "%s", devfs_path);
a9da3307db733eb1739ba859952610bba3d894abnp }
a9da3307db733eb1739ba859952610bba3d894abnp
a9da3307db733eb1739ba859952610bba3d894abnp HAL_DEBUG(("DevfsPath=> %s, CPUID=> %d", cpu_devfs_path, cpu_id));
a9da3307db733eb1739ba859952610bba3d894abnp
a9da3307db733eb1739ba859952610bba3d894abnp hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
a9da3307db733eb1739ba859952610bba3d894abnp "/org/freedesktop/Hal/devices%s_%d", cpu_devfs_path, cpu_id);
a9da3307db733eb1739ba859952610bba3d894abnp hal_device_set_udi (d, udi);
a9da3307db733eb1739ba859952610bba3d894abnp hal_device_property_set_string (d, "info.udi", udi);
a9da3307db733eb1739ba859952610bba3d894abnp if (di_prop_lookup_strings (DDI_DEV_T_ANY, node, "model", &s) > 0) {
a9da3307db733eb1739ba859952610bba3d894abnp hal_device_property_set_string (d, "info.product", s);
a9da3307db733eb1739ba859952610bba3d894abnp } else {
a9da3307db733eb1739ba859952610bba3d894abnp hal_device_property_set_string (d, "info.product",
a9da3307db733eb1739ba859952610bba3d894abnp di_node_name (node));
a9da3307db733eb1739ba859952610bba3d894abnp }
a9da3307db733eb1739ba859952610bba3d894abnp hal_device_property_set_string (d, "solaris.devfs_path",
a9da3307db733eb1739ba859952610bba3d894abnp cpu_devfs_path);
a9da3307db733eb1739ba859952610bba3d894abnp if ((driver_name = di_driver_name (node)) != NULL) {
a9da3307db733eb1739ba859952610bba3d894abnp hal_device_property_set_string (d, "info.solaris.driver",
a9da3307db733eb1739ba859952610bba3d894abnp driver_name);
a9da3307db733eb1739ba859952610bba3d894abnp }
a9da3307db733eb1739ba859952610bba3d894abnp
a9da3307db733eb1739ba859952610bba3d894abnp hal_device_add_capability (d, "processor");
a9da3307db733eb1739ba859952610bba3d894abnp
a9da3307db733eb1739ba859952610bba3d894abnp hal_device_property_set_int (d, "processor.number", cpu_id);
a9da3307db733eb1739ba859952610bba3d894abnp
a9da3307db733eb1739ba859952610bba3d894abnp /*
a9da3307db733eb1739ba859952610bba3d894abnp * Get the cpu related info from the kstat
a9da3307db733eb1739ba859952610bba3d894abnp */
a9da3307db733eb1739ba859952610bba3d894abnp kc = kstat_open ();
a9da3307db733eb1739ba859952610bba3d894abnp if (kc == NULL) {
a9da3307db733eb1739ba859952610bba3d894abnp HAL_ERROR (("Could not open kstat to get cpu info: %s",
a9da3307db733eb1739ba859952610bba3d894abnp strerror (errno)));
a9da3307db733eb1739ba859952610bba3d894abnp goto next;
a9da3307db733eb1739ba859952610bba3d894abnp }
a9da3307db733eb1739ba859952610bba3d894abnp
a9da3307db733eb1739ba859952610bba3d894abnp ksp = kstat_lookup (kc, "cpu_info", cpu_id, NULL);
a9da3307db733eb1739ba859952610bba3d894abnp if (ksp == NULL) {
a9da3307db733eb1739ba859952610bba3d894abnp HAL_ERROR (("Could not lookup kstat to get cpu info: %s",
a9da3307db733eb1739ba859952610bba3d894abnp strerror (errno)));
a9da3307db733eb1739ba859952610bba3d894abnp if (kc) {
a9da3307db733eb1739ba859952610bba3d894abnp kstat_close (kc);
a9da3307db733eb1739ba859952610bba3d894abnp }
a9da3307db733eb1739ba859952610bba3d894abnp return (NULL);
a9da3307db733eb1739ba859952610bba3d894abnp }
a9da3307db733eb1739ba859952610bba3d894abnp
a9da3307db733eb1739ba859952610bba3d894abnp kstat_read (kc, ksp, NULL);
a9da3307db733eb1739ba859952610bba3d894abnp ksdata = (kstat_named_t *)kstat_data_lookup (ksp, "clock_MHz");
a9da3307db733eb1739ba859952610bba3d894abnp if (ksdata == NULL) {
a9da3307db733eb1739ba859952610bba3d894abnp HAL_ERROR (("Could not get kstat clock_MHz data for cpu: %s",
a9da3307db733eb1739ba859952610bba3d894abnp strerror (errno)));
a9da3307db733eb1739ba859952610bba3d894abnp goto next;
a9da3307db733eb1739ba859952610bba3d894abnp }
a9da3307db733eb1739ba859952610bba3d894abnp clock_mhz = (uint64_t)ksdata->value.l;
a9da3307db733eb1739ba859952610bba3d894abnp
a9da3307db733eb1739ba859952610bba3d894abnp if (hal_device_property_set_uint64 (d, "processor.maximum_speed",
a9da3307db733eb1739ba859952610bba3d894abnp clock_mhz) == FALSE) {
a9da3307db733eb1739ba859952610bba3d894abnp HAL_INFO (("Could not set the processor speed device prop"));
a9da3307db733eb1739ba859952610bba3d894abnp }
a9da3307db733eb1739ba859952610bba3d894abnp
a9da3307db733eb1739ba859952610bba3d894abnp
a9da3307db733eb1739ba859952610bba3d894abnp ksdata = (kstat_named_t *)kstat_data_lookup (ksp,
a9da3307db733eb1739ba859952610bba3d894abnp "supported_frequencies_Hz");
a9da3307db733eb1739ba859952610bba3d894abnp if (ksdata == NULL) {
a9da3307db733eb1739ba859952610bba3d894abnp HAL_INFO (("Could not get kstat supported_frequencies_Hz data"
a9da3307db733eb1739ba859952610bba3d894abnp " for cpu: %s", strerror (errno)));
a9da3307db733eb1739ba859952610bba3d894abnp is_supp_freqs = FALSE;
a9da3307db733eb1739ba859952610bba3d894abnp } else {
a9da3307db733eb1739ba859952610bba3d894abnp /*
a9da3307db733eb1739ba859952610bba3d894abnp * If more than one freq is supported, then they are seperated
a9da3307db733eb1739ba859952610bba3d894abnp * by a ":"
a9da3307db733eb1739ba859952610bba3d894abnp */
a9da3307db733eb1739ba859952610bba3d894abnp if (strstr (ksdata->value.str.addr.ptr, ":") == NULL) {
a9da3307db733eb1739ba859952610bba3d894abnp is_supp_freqs = FALSE;
a9da3307db733eb1739ba859952610bba3d894abnp } else {
a9da3307db733eb1739ba859952610bba3d894abnp is_supp_freqs = TRUE;
a9da3307db733eb1739ba859952610bba3d894abnp }
a9da3307db733eb1739ba859952610bba3d894abnp }
a9da3307db733eb1739ba859952610bba3d894abnp
a9da3307db733eb1739ba859952610bba3d894abnp if (hal_device_property_set_bool (d, "processor.can_throttle",
a9da3307db733eb1739ba859952610bba3d894abnp is_supp_freqs) == FALSE) {
a9da3307db733eb1739ba859952610bba3d894abnp HAL_INFO (("Could not set the processor.can_throttle"
a9da3307db733eb1739ba859952610bba3d894abnp " device prop"));
a9da3307db733eb1739ba859952610bba3d894abnp }
a9da3307db733eb1739ba859952610bba3d894abnp
a9da3307db733eb1739ba859952610bba3d894abnpnext:
a9da3307db733eb1739ba859952610bba3d894abnp if (kc) {
a9da3307db733eb1739ba859952610bba3d894abnp kstat_close (kc);
a9da3307db733eb1739ba859952610bba3d894abnp }
a9da3307db733eb1739ba859952610bba3d894abnp
a9da3307db733eb1739ba859952610bba3d894abnp devinfo_add_enqueue (d, cpu_devfs_path, &devinfo_cpu_handler);
a9da3307db733eb1739ba859952610bba3d894abnp return (d);
a9da3307db733eb1739ba859952610bba3d894abnp}