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