xref: /onnv-gate/usr/src/cmd/hal/hald/solaris/devinfo_cpu.c (revision 6654:e02478f0bcde)
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 *
devinfo_cpu_add(HalDevice * parent,di_node_t node,char * devfs_path,char * device_type)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