xref: /illumos-gate/usr/src/lib/fm/topo/modules/i86pc/chipset/chipset.c (revision 8c4267180173328ebba9487634f0f232387d067f)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2019 Joyent, Inc.
14  */
15 
16 /*
17  * Chipset Enumeration
18  *
19  * Most x86 systems have some form of chipset which are components that exist on
20  * the motherboard that provide additional services that range from I/O such as
21  * memory and PCIe controllers (though as of this writing those mostly are a
22  * part of the CPU now) to additional functionality like Ethernet and USB
23  * controllers. At the moment, this module opts to enumerate a chipset node if
24  * there's something that exists under it that we care about such as:
25  *
26  *   o Temperature sensors
27  *   o Firmware modules
28  *
29  * If we do not detect anything, then we do not bother enumerating and trying to
30  * determine the different chipsets that are on the system. Currently, the only
31  * method for doing this is the presence of an Intel platform controller hub
32  * (PCH) temperature sensor.
33  */
34 
35 #include <fcntl.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <string.h>
39 
40 #include <sys/fm/protocol.h>
41 #include <fm/topo_mod.h>
42 #include <fm/topo_list.h>
43 #include <fm/topo_method.h>
44 
45 #include <topo_sensor.h>
46 
47 #define	CHIPSET_VERSION	1
48 
49 /*
50  * This is the path to the temperature sensor that, if present, indicates we
51  * should construct a chipset node.
52  */
53 static const char *topo_chipset_temp_sensor =
54 	"/dev/sensors/temperature/pch/ts.0";
55 
56 /*
57  * Attempt to determine if there is enough information for us to enumerate a
58  * chipset node, which usually means that we would enumerate something under it
59  * such as a temperature sensor or provide information about some piece of
60  * firmware that it has. Currently, if there is no temperature sensor, then we
61  * don't consider one to be present and don't do anything else.
62  */
63 static boolean_t
64 topo_chipset_present(void)
65 {
66 	struct stat st;
67 
68 	if (stat(topo_chipset_temp_sensor, &st) == 0 &&
69 	    S_ISCHR(st.st_mode)) {
70 		return (B_TRUE);
71 	}
72 
73 	return (B_FALSE);
74 }
75 
76 static int
77 topo_chipset_enum(topo_mod_t *mod, tnode_t *pnode, const char *name,
78     topo_instance_t min, topo_instance_t max, void *modarg, void *data)
79 {
80 	int ret;
81 	nvlist_t *fmri = NULL, *auth = NULL, *presource = NULL;
82 	tnode_t *tn = NULL;
83 	const topo_instance_t inst = 0;
84 
85 	topo_mod_dprintf(mod, "chipset_enum: asked to enumerate %s", name);
86 
87 	if (strcmp(name, CHIPSET) != 0) {
88 		topo_mod_dprintf(mod, "chipset_enum: asked to enumerate "
89 		    "unknown component");
90 		return (topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM));
91 	}
92 
93 	if (!topo_chipset_present()) {
94 		topo_mod_dprintf(mod, "chipset_enum: no %s device present",
95 		    name);
96 		return (0);
97 	}
98 
99 	if ((auth = topo_mod_auth(mod, pnode)) == NULL) {
100 		topo_mod_dprintf(mod, "chipset_enum: failed to get topo "
101 		    "auth: %s", topo_mod_errmsg(mod));
102 		/* topo_mod_auth() sets the module error */
103 		ret = -1;
104 		goto err;
105 	}
106 
107 	if ((fmri = topo_mod_hcfmri(mod, pnode, FM_HC_SCHEME_VERSION,
108 	    CHIPSET, inst, NULL, auth, NULL, NULL, NULL)) == NULL) {
109 		topo_mod_dprintf(mod, "chipset_enum: failed to get FMRI: %s",
110 		    topo_mod_errmsg(mod));
111 		/* topo_mod_hcfmri() sets the module error */
112 		ret = -1;
113 		goto err;
114 	}
115 
116 	if ((tn = topo_node_bind(mod, pnode, CHIPSET, inst, fmri)) == NULL) {
117 		topo_mod_dprintf(mod, "chipset_enum: failed to bind node: %s",
118 		    topo_mod_errmsg(mod));
119 		ret = -1;
120 		goto err;
121 	}
122 
123 	if (topo_node_resource(pnode, &presource, &ret) != 0) {
124 		topo_mod_dprintf(mod, "chipset_enum: failed to get parent "
125 		    "resource %s\n", topo_strerror(ret));
126 		ret = topo_mod_seterrno(mod, ret);
127 		goto err;
128 	}
129 
130 	if (topo_node_fru_set(tn, presource, 0, &ret) != 0) {
131 		topo_mod_dprintf(mod, "chipset_enum: failed to set FRU: %s",
132 		    topo_strerror(ret));
133 		ret = topo_mod_seterrno(mod, ret);
134 		goto err;
135 	}
136 
137 	/*
138 	 * Finally, create the temperature sensor.
139 	 */
140 	if ((ret = topo_sensor_create_scalar_sensor(mod, tn,
141 	    topo_chipset_temp_sensor, "temp")) != 0) {
142 		topo_mod_dprintf(mod, "failed to create chipset temperature "
143 		    "sensor");
144 		goto err;
145 	}
146 
147 	nvlist_free(auth);
148 	nvlist_free(fmri);
149 	nvlist_free(presource);
150 	return (0);
151 err:
152 	nvlist_free(auth);
153 	nvlist_free(fmri);
154 	nvlist_free(presource);
155 	topo_node_unbind(tn);
156 	return (ret);
157 }
158 
159 static const topo_modops_t chipset_ops = {
160 	topo_chipset_enum, NULL
161 };
162 
163 static topo_modinfo_t chipset_mod = {
164 	CHIPSET, FM_FMRI_SCHEME_HC, CHIPSET_VERSION, &chipset_ops
165 };
166 
167 int
168 _topo_init(topo_mod_t *mod, topo_version_t version)
169 {
170 	if (getenv("TOPOCHIPSETDEBUG") != NULL) {
171 		topo_mod_setdebug(mod);
172 	}
173 
174 	topo_mod_dprintf(mod, "_mod_init: initializing %s enumerator\n",
175 	    CHIPSET);
176 
177 	if (version != -1) {
178 
179 	}
180 
181 	if (topo_mod_register(mod, &chipset_mod, TOPO_VERSION) != 0) {
182 		return (-1);
183 	}
184 
185 	return (0);
186 }
187 
188 void
189 _topo_fini(topo_mod_t *mod)
190 {
191 }
192