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