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