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