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