1 /*************************************************************************** 2 * 3 * devinfo_cpu : cpu devices 4 * 5 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 6 * Use is subject to license terms. 7 * 8 * Licensed under the Academic Free License version 2.1 9 * 10 **************************************************************************/ 11 12 #pragma ident "%Z%%M% %I% %E% SMI" 13 14 #ifdef HAVE_CONFIG_H 15 #include <config.h> 16 #endif 17 18 #include <stdio.h> 19 #include <string.h> 20 #include <kstat.h> 21 #include <sys/utsname.h> 22 #include <libdevinfo.h> 23 #include <sys/systeminfo.h> 24 25 #include "../osspec.h" 26 #include "../logger.h" 27 #include "../hald.h" 28 #include "../hald_dbus.h" 29 #include "../device_info.h" 30 #include "../util.h" 31 #include "devinfo_cpu.h" 32 33 static HalDevice *devinfo_cpu_add(HalDevice *, di_node_t, char *, char *); 34 35 DevinfoDevHandler devinfo_cpu_handler = { 36 devinfo_cpu_add, 37 NULL, 38 NULL, 39 NULL, 40 NULL, 41 NULL 42 }; 43 44 static HalDevice * 45 devinfo_cpu_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type) 46 { 47 48 HalDevice *d; 49 char *prom_device_type = NULL; 50 int *int_cpu_id; 51 static int cpu_id = -1; 52 uint64_t clock_mhz; 53 di_prom_handle_t phdl; 54 kstat_ctl_t *kc; 55 kstat_t *ksp; 56 kstat_named_t *ksdata; 57 dbus_bool_t is_supp_freqs; 58 char udi[HAL_PATH_MAX]; 59 char *driver_name, *s; 60 char cpu_devfs_path[HAL_PATH_MAX]; 61 62 /* 63 * If it is x86, the software device tree node will have the 64 * device_type information which is the one passed above. If it is 65 * NULL, check if the node has a PROM entry, and check the device_type 66 * in case of sparc. Else return NULL 67 */ 68 if (device_type == NULL) { 69 /* 70 * Check the device type if it has a PROM entry. Because 71 * in sparc, the device_type entry will in the PROM node 72 */ 73 if (di_nodeid (node) == DI_PROM_NODEID) { 74 phdl = di_prom_init (); 75 if (phdl == DI_PROM_HANDLE_NIL) { 76 HAL_ERROR (("Error in Initializing the PROM " 77 "handle to find cpu device: %s", 78 strerror (errno))); 79 return (NULL); 80 } 81 if (di_prom_prop_lookup_strings (phdl, node, 82 "device_type", &prom_device_type) == -1) { 83 di_prom_fini (phdl); 84 return (NULL); 85 } 86 if (strcmp (prom_device_type, "cpu") != 0) { 87 di_prom_fini (phdl); 88 return (NULL); 89 } 90 /* 91 * Get cpuid if available 92 */ 93 if (di_prom_prop_lookup_ints (phdl, node, 94 "cpuid", &int_cpu_id) > 0) { 95 cpu_id = *int_cpu_id; 96 } else { 97 /* 98 * There is no cpuid entry in this arch.Just 99 * increment the cpuid which will be the 100 * current instance 101 */ 102 ++cpu_id; 103 } 104 di_prom_fini (phdl); 105 } else { 106 return (NULL); 107 } 108 109 } else if (strcmp (device_type, "cpu") == 0) { 110 /* 111 * This is a x86 arch, because software device tree node 112 * has the device_type entry for cpu. The "reg" property 113 * will have the cpuid. If not just increment the cpuid 114 * which will be the current cpu instance in the kstat 115 */ 116 if (di_prop_lookup_ints (DDI_DEV_T_ANY, node, 117 "reg", &int_cpu_id) > 0) { 118 cpu_id = *int_cpu_id; 119 } else { 120 /* 121 * There is no cpuid entry in this arch. Just 122 * increment the cpuid which will be the 123 * current instance 124 */ 125 ++cpu_id; 126 } 127 128 } else { 129 return (NULL); 130 } 131 132 HAL_DEBUG (("CPUID=> %x", cpu_id)); 133 134 d = hal_device_new (); 135 136 /* 137 * devinfo_set_default_properties () uses di_instance() as part of 138 * the udi. For some solaris devices like cpu di_instance() is not 139 * present and it returns -1. For the udi to be unique can use the 140 * cpu_id. 141 */ 142 hal_device_property_set_string (d, "info.parent", 143 "/org/freedesktop/Hal/devices/local"); 144 145 /* 146 * If cpu driver is not installed, then devfs_path returned by 147 * libdevinfo will be same for all cpu's. 148 * Since HAL stores the devices in its tree based on the devfs_path, 149 * To make it unique, will be concatenating devfs_path with cpu_id 150 */ 151 if (di_driver_name (node) == NULL) { 152 snprintf (cpu_devfs_path, HAL_PATH_MAX, "%s_%d", 153 devfs_path, cpu_id); 154 } else { 155 snprintf (cpu_devfs_path, HAL_PATH_MAX, "%s", devfs_path); 156 } 157 158 HAL_DEBUG(("DevfsPath=> %s, CPUID=> %d", cpu_devfs_path, cpu_id)); 159 160 hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi), 161 "/org/freedesktop/Hal/devices%s_%d", cpu_devfs_path, cpu_id); 162 hal_device_set_udi (d, udi); 163 hal_device_property_set_string (d, "info.udi", udi); 164 if (di_prop_lookup_strings (DDI_DEV_T_ANY, node, "model", &s) > 0) { 165 hal_device_property_set_string (d, "info.product", s); 166 } else { 167 hal_device_property_set_string (d, "info.product", 168 di_node_name (node)); 169 } 170 hal_device_property_set_string (d, "solaris.devfs_path", 171 cpu_devfs_path); 172 if ((driver_name = di_driver_name (node)) != NULL) { 173 hal_device_property_set_string (d, "info.solaris.driver", 174 driver_name); 175 } 176 177 hal_device_add_capability (d, "processor"); 178 179 hal_device_property_set_int (d, "processor.number", cpu_id); 180 181 /* 182 * Get the cpu related info from the kstat 183 */ 184 kc = kstat_open (); 185 if (kc == NULL) { 186 HAL_ERROR (("Could not open kstat to get cpu info: %s", 187 strerror (errno))); 188 goto next; 189 } 190 191 ksp = kstat_lookup (kc, "cpu_info", cpu_id, NULL); 192 if (ksp == NULL) { 193 HAL_ERROR (("Could not lookup kstat to get cpu info: %s", 194 strerror (errno))); 195 if (kc) { 196 kstat_close (kc); 197 } 198 return (NULL); 199 } 200 201 kstat_read (kc, ksp, NULL); 202 ksdata = (kstat_named_t *)kstat_data_lookup (ksp, "clock_MHz"); 203 if (ksdata == NULL) { 204 HAL_ERROR (("Could not get kstat clock_MHz data for cpu: %s", 205 strerror (errno))); 206 goto next; 207 } 208 clock_mhz = (uint64_t)ksdata->value.l; 209 210 if (hal_device_property_set_uint64 (d, "processor.maximum_speed", 211 clock_mhz) == FALSE) { 212 HAL_INFO (("Could not set the processor speed device prop")); 213 } 214 215 216 ksdata = (kstat_named_t *)kstat_data_lookup (ksp, 217 "supported_frequencies_Hz"); 218 if (ksdata == NULL) { 219 HAL_INFO (("Could not get kstat supported_frequencies_Hz data" 220 " for cpu: %s", strerror (errno))); 221 is_supp_freqs = FALSE; 222 } else { 223 /* 224 * If more than one freq is supported, then they are seperated 225 * by a ":" 226 */ 227 if (strstr (ksdata->value.str.addr.ptr, ":") == NULL) { 228 is_supp_freqs = FALSE; 229 } else { 230 is_supp_freqs = TRUE; 231 } 232 } 233 234 if (hal_device_property_set_bool (d, "processor.can_throttle", 235 is_supp_freqs) == FALSE) { 236 HAL_INFO (("Could not set the processor.can_throttle" 237 " device prop")); 238 } 239 240 next: 241 if (kc) { 242 kstat_close (kc); 243 } 244 245 devinfo_add_enqueue (d, cpu_devfs_path, &devinfo_cpu_handler); 246 return (d); 247 } 248