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
topo_chipset_present(void)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
topo_chipset_enum(topo_mod_t * mod,tnode_t * pnode,const char * name,topo_instance_t min,topo_instance_t max,void * modarg,void * data)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
_topo_init(topo_mod_t * mod,topo_version_t version)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
_topo_fini(topo_mod_t * mod)189 _topo_fini(topo_mod_t *mod)
190 {
191 }
192