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 device present", name); 95 return (0); 96 } 97 98 if ((auth = topo_mod_auth(mod, pnode)) == NULL) { 99 topo_mod_dprintf(mod, "chipset_enum: failed to get topo " 100 "auth: %s", topo_mod_errmsg(mod)); 101 /* topo_mod_auth() sets the module error */ 102 ret = -1; 103 goto err; 104 } 105 106 if ((fmri = topo_mod_hcfmri(mod, pnode, FM_HC_SCHEME_VERSION, 107 CHIPSET, inst, NULL, auth, NULL, NULL, NULL)) == NULL) { 108 topo_mod_dprintf(mod, "chipset_enum: failed to get FMRI: %s", 109 topo_mod_errmsg(mod)); 110 /* topo_mod_hcfmri() sets the module error */ 111 ret = -1; 112 goto err; 113 } 114 115 if ((tn = topo_node_bind(mod, pnode, CHIPSET, inst, fmri)) == NULL) { 116 topo_mod_dprintf(mod, "chipset_enum: failed to bind node: %s", 117 topo_mod_errmsg(mod)); 118 ret = -1; 119 goto err; 120 } 121 122 if (topo_node_resource(pnode, &presource, &ret) != 0) { 123 topo_mod_dprintf(mod, "chipset_enum: failed to get parent " 124 "resource %s\n", topo_strerror(ret)); 125 ret = topo_mod_seterrno(mod, ret); 126 goto err; 127 } 128 129 if (topo_node_fru_set(tn, presource, 0, &ret) != 0) { 130 topo_mod_dprintf(mod, "chipset_enum: failed to set FRU: %s", 131 topo_strerror(ret)); 132 ret = topo_mod_seterrno(mod, ret); 133 goto err; 134 } 135 136 /* 137 * Finally, create the temperature sensor. 138 */ 139 if ((ret = topo_sensor_create_scalar_sensor(mod, tn, 140 topo_chipset_temp_sensor, "temp")) != 0) { 141 topo_mod_dprintf(mod, "failed to create chipset temperature " 142 "sensor"); 143 goto err; 144 } 145 146 nvlist_free(auth); 147 nvlist_free(fmri); 148 nvlist_free(presource); 149 return (0); 150 err: 151 nvlist_free(auth); 152 nvlist_free(fmri); 153 nvlist_free(presource); 154 topo_node_unbind(tn); 155 return (ret); 156 } 157 158 static const topo_modops_t chipset_ops = { 159 topo_chipset_enum, NULL 160 }; 161 162 static topo_modinfo_t chipset_mod = { 163 CHIPSET, FM_FMRI_SCHEME_HC, CHIPSET_VERSION, &chipset_ops 164 }; 165 166 int 167 _topo_init(topo_mod_t *mod, topo_version_t version) 168 { 169 if (getenv("TOPOCHIPSETDEBUG") != NULL) { 170 topo_mod_setdebug(mod); 171 } 172 173 topo_mod_dprintf(mod, "_mod_init: initializing %s enumerator\n", 174 CHIPSET); 175 176 if (version != -1) { 177 178 } 179 180 if (topo_mod_register(mod, &chipset_mod, TOPO_VERSION) != 0) { 181 return (-1); 182 } 183 184 return (0); 185 } 186 187 void 188 _topo_fini(topo_mod_t *mod) 189 { 190 } 191