1 /* 2 * Copyright (c) 2026 Abdelkader Boudih <seuros@FreeBSD.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7 /* 8 * hfsts(4) - Intel Management Engine Interface (MEI/HECI) debug probe. 9 * 10 * This is deliberately *not* a full MEI host-client driver: it only 11 * attaches to the PCI function and decodes the Host Firmware Status 12 * registers (HFSTS1-6, as supported by the device generation), which live 13 * entirely in PCI configuration space. 14 * BAR0 (the circular-buffer messaging ring) is never mapped. 15 * 16 * Register counts and layout follow Linux drivers/misc/mei/hw-me.c: 17 * ICH10 provides HFS1, PCH5 through PCH7 provide HFS1-2, and PCH8 and 18 * later provide HFS1-6 at PCI config offsets 0x40/0x48/0x60/0x64/0x68/0x6c. 19 */ 20 21 #include <sys/param.h> 22 #include <sys/bus.h> 23 #include <sys/kernel.h> 24 #include <sys/module.h> 25 #include <sys/sysctl.h> 26 27 #include <dev/pci/pcivar.h> 28 #include <dev/pci/pcireg.h> 29 #include <dev/ichwd/ichwd.h> 30 #include <dev/intel/hfsts.h> 31 32 /* Host Firmware Status Registers - PCI configuration space offsets. */ 33 #define HFSTS_CFG_HFS_1 0x40 34 #define HFSTS_HFS_1_CWS_MSK 0x0000000f 35 #define HFSTS_HFS_1_MFG_MODE_MSK 0x00000010 36 #define HFSTS_HFS_1_FPT_BAD_MSK 0x00000020 37 #define HFSTS_HFS_1_OPSTATE_MSK 0x000001c0 38 #define HFSTS_HFS_1_OPSTATE_SHIFT 6 39 #define HFSTS_HFS_1_FW_INIT_CMPL_MSK 0x00000200 40 #define HFSTS_HFS_1_BUP_FAIL_MSK 0x00000400 41 #define HFSTS_HFS_1_UPDATE_INPROG_MSK 0x00000800 42 #define HFSTS_HFS_1_ERROR_MSK 0x0000f000 43 #define HFSTS_HFS_1_ERROR_SHIFT 12 44 #define HFSTS_HFS_1_OPMODE_MSK 0x000f0000 45 #define HFSTS_HFS_1_OPMODE_SHIFT 16 46 #define HFSTS_HFS_1_BOOT_OPT_MSK 0x01000000 47 #define HFSTS_HFS_1_D0I3_MSK 0x80000000 48 #define HFSTS_CFG_HFS_2 0x48 49 #define HFSTS_HFS_2_PM_EVENT_MSK 0x0f000000 50 #define HFSTS_HFS_2_PM_EVENT_SHIFT 24 51 #define HFSTS_CFG_HFS_3 0x60 52 #define HFSTS_HFS_3_FW_SKU_MSK 0x00000070 53 #define HFSTS_HFS_3_FW_SKU_SHIFT 4 54 #define HFSTS_CFG_HFS_4 0x64 55 #define HFSTS_CFG_HFS_5 0x68 56 #define HFSTS_CFG_HFS_6 0x6c 57 58 /* HFS1 field values. Operation state and mode are sparse encodings. */ 59 #define HFSTS_HFS_CWS_RESET 0 60 #define HFSTS_HFS_CWS_INIT 1 61 #define HFSTS_HFS_CWS_RECOVERY 2 62 #define HFSTS_HFS_CWS_TEST 3 63 #define HFSTS_HFS_CWS_DISABLED 4 64 #define HFSTS_HFS_CWS_NORMAL 5 65 #define HFSTS_HFS_CWS_WAIT 6 66 #define HFSTS_HFS_CWS_TRANS 7 67 #define HFSTS_HFS_CWS_INVALID 8 68 69 #define HFSTS_HFS_OPSTATE_PREBOOT 0 70 #define HFSTS_HFS_OPSTATE_M0_UMA 1 71 #define HFSTS_HFS_OPSTATE_M3 4 72 #define HFSTS_HFS_OPSTATE_M0 5 73 #define HFSTS_HFS_OPSTATE_BRINGUP 6 74 #define HFSTS_HFS_OPSTATE_IMAGE_ERROR 7 75 76 #define HFSTS_HFS_OPMODE_NORMAL 0 77 #define HFSTS_HFS_OPMODE_DEBUG 2 78 #define HFSTS_HFS_OPMODE_TEMP_DISABLED 3 79 #define HFSTS_HFS_OPMODE_JUMPER_OVERRIDE 4 80 #define HFSTS_HFS_OPMODE_MEI_OVERRIDE 5 81 #define HFSTS_HFS_OPMODE_SPS 15 82 83 #define HFSTS_HFS_ERROR_NONE 0 84 #define HFSTS_HFS_ERROR_UNCATEGORIZED 1 85 #define HFSTS_HFS_ERROR_DISABLED 2 86 #define HFSTS_HFS_ERROR_IMAGE 3 87 #define HFSTS_HFS_ERROR_DEBUG 4 88 89 static const char *const hfsts_cws_values[] = { 90 [HFSTS_HFS_CWS_RESET] = "Reset", 91 [HFSTS_HFS_CWS_INIT] = "Initializing", 92 [HFSTS_HFS_CWS_RECOVERY] = "Recovery", 93 [HFSTS_HFS_CWS_TEST] = "Test", 94 [HFSTS_HFS_CWS_DISABLED] = "Disabled", 95 [HFSTS_HFS_CWS_NORMAL] = "Normal", 96 [HFSTS_HFS_CWS_WAIT] = "Platform Disable Wait", 97 [HFSTS_HFS_CWS_TRANS] = "OP State Transition", 98 [HFSTS_HFS_CWS_INVALID] = "Invalid CPU Plugged In", 99 }; 100 101 static const char *const hfsts_opstate_values[] = { 102 [HFSTS_HFS_OPSTATE_PREBOOT] = "Preboot", 103 [HFSTS_HFS_OPSTATE_M0_UMA] = "M0 (UMA)", 104 [HFSTS_HFS_OPSTATE_M3] = "M3 (no UMA)", 105 [HFSTS_HFS_OPSTATE_M0] = "M0 (no UMA)", 106 [HFSTS_HFS_OPSTATE_BRINGUP] = "Bring up", 107 [HFSTS_HFS_OPSTATE_IMAGE_ERROR] = "M0 (invalid firmware image)", 108 }; 109 110 static const char *const hfsts_opmode_values[] = { 111 [HFSTS_HFS_OPMODE_NORMAL] = "Normal", 112 [HFSTS_HFS_OPMODE_DEBUG] = "Debug", 113 [HFSTS_HFS_OPMODE_TEMP_DISABLED] = "Temporarily disabled", 114 [HFSTS_HFS_OPMODE_JUMPER_OVERRIDE] = "Security override (jumper)", 115 [HFSTS_HFS_OPMODE_MEI_OVERRIDE] = "Security override (MEI)", 116 [HFSTS_HFS_OPMODE_SPS] = "Server Platform Services", 117 }; 118 119 static const char *const hfsts_error_values[] = { 120 [HFSTS_HFS_ERROR_NONE] = "None", 121 [HFSTS_HFS_ERROR_UNCATEGORIZED] = "Uncategorized", 122 [HFSTS_HFS_ERROR_DISABLED] = "Disabled", 123 [HFSTS_HFS_ERROR_IMAGE] = "Firmware image", 124 [HFSTS_HFS_ERROR_DEBUG] = "Debug", 125 }; 126 127 static const char * 128 hfsts_decode(const char *const *tbl, size_t tbl_sz, uint32_t idx) 129 { 130 131 if (idx >= tbl_sz || tbl[idx] == NULL) 132 return ("Unknown"); 133 return (tbl[idx]); 134 } 135 #define HFSTS_DECODE(tbl, idx) hfsts_decode((tbl), nitems(tbl), (idx)) 136 137 /* HFS1-6 PCI configuration offsets, indexed 0-5. */ 138 static const uint32_t hfsts_hfs_off[6] = { 139 HFSTS_CFG_HFS_1, HFSTS_CFG_HFS_2, HFSTS_CFG_HFS_3, 140 HFSTS_CFG_HFS_4, HFSTS_CFG_HFS_5, HFSTS_CFG_HFS_6, 141 }; 142 143 /* 144 * All HFS fields are re-read from PCI configuration space on every sysctl 145 * access: the ME can transition CWS/opstate/error post-boot (watchdog 146 * resets, HAP toggles, S0i3/M0-M3 power events), so an attach-time snapshot 147 * would go stale under a running system. 148 */ 149 static uint32_t 150 hfsts_read_hfs(device_t dev, u_int idx) 151 { 152 153 return (pci_read_config(dev, hfsts_hfs_off[idx], 4)); 154 } 155 156 /* 157 * One-word summary for the log/sysctl consumer who doesn't want to parse 158 * the raw HFS fields: Absent (register read didn't land on a real state), 159 * Disabled (ME explicitly turned off), Active (busy, transitional, or in an 160 * exceptional mode), or Normal (steady-state, with no reported error). 161 */ 162 static const char * 163 hfsts_state_summary(uint32_t cws, uint32_t opmode, uint32_t error, 164 uint32_t mfg_mode, uint32_t fpt_bad, uint32_t bup_fail, 165 uint32_t fw_init_cmpl, uint32_t update_inprog) 166 { 167 168 if (cws >= nitems(hfsts_cws_values) || hfsts_cws_values[cws] == NULL) 169 return ("Absent"); 170 if (cws == HFSTS_HFS_CWS_DISABLED || cws == HFSTS_HFS_CWS_WAIT || 171 opmode == HFSTS_HFS_OPMODE_TEMP_DISABLED || 172 error == HFSTS_HFS_ERROR_DISABLED) 173 return ("Disabled"); 174 if (cws != HFSTS_HFS_CWS_NORMAL || opmode != HFSTS_HFS_OPMODE_NORMAL || 175 error != HFSTS_HFS_ERROR_NONE || mfg_mode || fpt_bad || bup_fail || 176 !fw_init_cmpl || update_inprog) 177 return ("Active"); 178 return ("Normal"); 179 } 180 181 struct hfsts_device { 182 uint16_t device; 183 uint8_t hfs_count; 184 const char *name; 185 }; 186 187 /* 188 * Intel MEI/HECI PCI functions with usable Host Firmware Status registers. 189 * ICH10 has HFS1, PCH5 through PCH7 have HFS1-2, and PCH8 and newer have 190 * HFS1-6. Legacy ICH devices, for which no HFS register is defined, are 191 * deliberately not matched. 192 */ 193 #define HFSTS_DEV_ICH10(id, desc) { (id), 1, (desc) } 194 #define HFSTS_DEV_PCH(id, desc) { (id), 2, (desc) } 195 #define HFSTS_DEV_PCH8(id, desc) { (id), 6, (desc) } 196 197 static const struct hfsts_device hfsts_devices[] = { 198 HFSTS_DEV_ICH10(0x2e04, "Eaglelake MEI"), 199 HFSTS_DEV_ICH10(0x2e14, "Eaglelake MEI"), 200 HFSTS_DEV_ICH10(0x2e24, "Eaglelake MEI"), 201 HFSTS_DEV_ICH10(0x2e34, "Eaglelake MEI"), 202 HFSTS_DEV_PCH(0x3b64, "Calpella MEI"), 203 HFSTS_DEV_PCH(0x3b65, "Calpella MEI"), 204 HFSTS_DEV_PCH(0x1c3a, "Cougar Point MEI"), 205 HFSTS_DEV_PCH(0x1d3a, "C600/X79 Patsburg MEI"), 206 HFSTS_DEV_PCH(0x1e3a, "Panther Point MEI"), 207 HFSTS_DEV_PCH(0x1cba, "Panther Point MEI"), 208 HFSTS_DEV_PCH(0x1dba, "Panther Point MEI"), 209 HFSTS_DEV_PCH8(0x8c3a, "Lynx Point H MEI"), 210 HFSTS_DEV_PCH8(0x8d3a, "Lynx Point Wellsburg MEI"), 211 HFSTS_DEV_PCH8(0x9c3a, "Lynx Point LP MEI"), 212 HFSTS_DEV_PCH8(0x8cba, "Lynx Point H Refresh MEI"), 213 HFSTS_DEV_PCH8(0x9cba, "Wildcat Point LP MEI"), 214 HFSTS_DEV_PCH8(0x9cbb, "Wildcat Point LP 2 MEI"), 215 HFSTS_DEV_PCH8(0x9d3a, "Sunrise Point MEI"), 216 HFSTS_DEV_PCH8(0x9d3b, "Sunrise Point 2 MEI"), 217 HFSTS_DEV_PCH8(0x9d3e, "Sunrise Point 3 (iTouch) MEI"), 218 HFSTS_DEV_PCH8(0xa13a, "Sunrise Point H MEI"), 219 HFSTS_DEV_PCH8(0xa13b, "Sunrise Point H 2 MEI"), 220 HFSTS_DEV_PCH8(0xa1ba, "Lewisburg (SPT) MEI"), 221 HFSTS_DEV_PCH8(0x1a9a, "Broxton M MEI"), 222 HFSTS_DEV_PCH8(0x5a9a, "Apollo Lake I MEI"), 223 HFSTS_DEV_PCH8(0x19e5, "Denverton IE MEI"), 224 HFSTS_DEV_PCH8(0x319a, "Gemini Lake MEI"), 225 HFSTS_DEV_PCH8(0xa2ba, "Kaby Point MEI"), 226 HFSTS_DEV_PCH8(0xa2bb, "Kaby Point 2 MEI"), 227 HFSTS_DEV_PCH8(0xa2be, "Kaby Point 3 (iTouch) MEI"), 228 HFSTS_DEV_PCH8(0x9de0, "Cannon Point LP MEI"), 229 HFSTS_DEV_PCH8(0x9de4, "Cannon Point LP 3 (iTouch) MEI"), 230 HFSTS_DEV_PCH8(0xa360, "Cannon Point H MEI"), 231 HFSTS_DEV_PCH8(0xa364, "Cannon Point H 3 (iTouch) MEI"), 232 HFSTS_DEV_PCH8(0x02e0, "Comet Point LP MEI"), 233 HFSTS_DEV_PCH8(0x02e4, "Comet Point LP 3 (iTouch) MEI"), 234 HFSTS_DEV_PCH8(0xa3ba, "Comet Point Lake V MEI"), 235 HFSTS_DEV_PCH8(0x06e0, "Comet Lake H MEI"), 236 HFSTS_DEV_PCH8(0x06e4, "Comet Lake H 3 (iTouch) MEI"), 237 HFSTS_DEV_PCH8(0x18d3, "Cedar Fork MEI"), 238 HFSTS_DEV_PCH8(0x34e0, "Ice Lake Point LP MEI"), 239 HFSTS_DEV_PCH8(0x38e0, "Ice Lake Point N MEI"), 240 HFSTS_DEV_PCH8(0x4de0, "Jasper Lake Point N MEI"), 241 HFSTS_DEV_PCH8(0xa0e0, "Tiger Lake Point LP MEI"), 242 HFSTS_DEV_PCH8(0x43e0, "Tiger Lake Point H MEI"), 243 HFSTS_DEV_PCH8(0x4b70, "Mule Creek Canyon (EHL) MEI"), 244 HFSTS_DEV_PCH8(0x4b75, "Mule Creek Canyon 4 (EHL) MEI"), 245 HFSTS_DEV_PCH8(0x1be0, "Emmitsburg WS MEI"), 246 HFSTS_DEV_PCH8(0x7ae8, "Alder Lake Point S MEI"), 247 HFSTS_DEV_PCH8(0x7a60, "Alder Lake Point LP MEI"), 248 HFSTS_DEV_PCH8(0x51e0, "Alder Lake Point P MEI"), 249 HFSTS_DEV_PCH8(0x54e0, "Alder Lake Point N MEI"), 250 HFSTS_DEV_PCH8(0x7a68, "Raptor Lake Point S MEI"), 251 HFSTS_DEV_PCH8(0x7e70, "Meteor Lake Point M MEI"), 252 HFSTS_DEV_PCH8(0x7f68, "Arrow Lake Point S MEI"), 253 HFSTS_DEV_PCH8(0x7770, "Arrow Lake Point H MEI"), 254 HFSTS_DEV_PCH8(0xa870, "Lunar Lake Point M MEI"), 255 HFSTS_DEV_PCH8(0xe370, "Panther Lake H MEI"), 256 HFSTS_DEV_PCH8(0xe470, "Panther Lake P MEI"), 257 HFSTS_DEV_PCH8(0x4d70, "Wildcat Lake P MEI"), 258 HFSTS_DEV_PCH8(0x6e68, "Nova Lake Point S MEI"), 259 HFSTS_DEV_PCH8(0xd370, "Nova Lake Point H MEI"), 260 { 0, 0, NULL } 261 }; 262 263 static const struct hfsts_device * 264 hfsts_find_device(device_t dev) 265 { 266 const struct hfsts_device *id; 267 268 for (id = hfsts_devices; id->name != NULL; id++) { 269 if (pci_get_device(dev) == id->device) 270 return (id); 271 } 272 return (NULL); 273 } 274 275 /* 276 * The isa-side Function Disable check is only meaningful when no known 277 * MEI/HECI function enumerated on PCI. 278 */ 279 bool 280 hfsts_pci_present(void) 281 { 282 const struct hfsts_device *id; 283 284 for (id = hfsts_devices; id->name != NULL; id++) { 285 if (pci_find_device(VENDORID_INTEL, id->device) != NULL) 286 return (true); 287 } 288 return (false); 289 } 290 291 struct hfsts_softc { 292 device_t sc_dev; 293 struct sysctl_ctx_list *sc_sysctlctx; 294 struct sysctl_oid *sc_sysctlnode; 295 uint8_t sc_hfs_count; 296 }; 297 298 /* Simple masked/shifted HFS sub-fields, read live via a common handler. */ 299 enum hfsts_field_id { 300 HFSTS_FLD_D0I3_SUPPORTED, 301 HFSTS_FLD_OPMODE, 302 HFSTS_FLD_PM_EVENT, 303 HFSTS_FLD_FW_SKU, 304 HFSTS_FLD_MFG_MODE, 305 HFSTS_FLD_UPDATE_INPROG, 306 }; 307 308 struct hfsts_field { 309 uint8_t hfs_idx; 310 uint32_t mask; 311 uint8_t shift; 312 }; 313 314 static const struct hfsts_field hfsts_fields[] = { 315 [HFSTS_FLD_D0I3_SUPPORTED] = { 0, HFSTS_HFS_1_D0I3_MSK, 31 }, 316 [HFSTS_FLD_OPMODE] = { 0, HFSTS_HFS_1_OPMODE_MSK, 317 HFSTS_HFS_1_OPMODE_SHIFT }, 318 [HFSTS_FLD_PM_EVENT] = { 1, HFSTS_HFS_2_PM_EVENT_MSK, 319 HFSTS_HFS_2_PM_EVENT_SHIFT }, 320 [HFSTS_FLD_FW_SKU] = { 2, HFSTS_HFS_3_FW_SKU_MSK, 321 HFSTS_HFS_3_FW_SKU_SHIFT }, 322 [HFSTS_FLD_MFG_MODE] = { 0, HFSTS_HFS_1_MFG_MODE_MSK, 4 }, 323 [HFSTS_FLD_UPDATE_INPROG] = { 0, HFSTS_HFS_1_UPDATE_INPROG_MSK, 11 }, 324 }; 325 326 static int 327 hfsts_sysctl_raw(SYSCTL_HANDLER_ARGS) 328 { 329 struct hfsts_softc *sc = arg1; 330 uint32_t val; 331 332 val = hfsts_read_hfs(sc->sc_dev, (u_int)arg2); 333 return (sysctl_handle_32(oidp, &val, 0, req)); 334 } 335 336 static int 337 hfsts_sysctl_field(SYSCTL_HANDLER_ARGS) 338 { 339 struct hfsts_softc *sc = arg1; 340 const struct hfsts_field *f = &hfsts_fields[arg2]; 341 uint32_t val; 342 343 val = (hfsts_read_hfs(sc->sc_dev, f->hfs_idx) & f->mask) >> f->shift; 344 return (sysctl_handle_32(oidp, &val, 0, req)); 345 } 346 347 /* HFS1 sub-fields that decode to a string via a lookup table. */ 348 enum hfsts_decode_id { 349 HFSTS_DEC_CWS, 350 HFSTS_DEC_OPSTATE, 351 HFSTS_DEC_OPMODE, 352 HFSTS_DEC_ERROR, 353 }; 354 355 struct hfsts_decode { 356 uint32_t mask; 357 uint8_t shift; 358 const char *const *tbl; 359 size_t tbl_sz; 360 }; 361 362 static const struct hfsts_decode hfsts_decodes[] = { 363 [HFSTS_DEC_CWS] = { HFSTS_HFS_1_CWS_MSK, 0, 364 hfsts_cws_values, nitems(hfsts_cws_values) }, 365 [HFSTS_DEC_OPSTATE] = { HFSTS_HFS_1_OPSTATE_MSK, 366 HFSTS_HFS_1_OPSTATE_SHIFT, 367 hfsts_opstate_values, 368 nitems(hfsts_opstate_values) }, 369 [HFSTS_DEC_OPMODE] = { HFSTS_HFS_1_OPMODE_MSK, 370 HFSTS_HFS_1_OPMODE_SHIFT, 371 hfsts_opmode_values, 372 nitems(hfsts_opmode_values) }, 373 [HFSTS_DEC_ERROR] = { HFSTS_HFS_1_ERROR_MSK, HFSTS_HFS_1_ERROR_SHIFT, 374 hfsts_error_values, nitems(hfsts_error_values) }, 375 }; 376 377 static int 378 hfsts_sysctl_decode(SYSCTL_HANDLER_ARGS) 379 { 380 struct hfsts_softc *sc = arg1; 381 const struct hfsts_decode *d = &hfsts_decodes[arg2]; 382 uint32_t val; 383 384 val = (hfsts_read_hfs(sc->sc_dev, 0) & d->mask) >> d->shift; 385 return (SYSCTL_OUT_STR(req, hfsts_decode(d->tbl, d->tbl_sz, val))); 386 } 387 388 static int 389 hfsts_sysctl_summary(SYSCTL_HANDLER_ARGS) 390 { 391 struct hfsts_softc *sc = arg1; 392 uint32_t hfs1, cws, opmode, error; 393 uint32_t mfg_mode, fpt_bad, bup_fail, fw_init_cmpl, update_inprog; 394 395 hfs1 = hfsts_read_hfs(sc->sc_dev, 0); 396 cws = hfs1 & HFSTS_HFS_1_CWS_MSK; 397 opmode = (hfs1 & HFSTS_HFS_1_OPMODE_MSK) >> HFSTS_HFS_1_OPMODE_SHIFT; 398 error = (hfs1 & HFSTS_HFS_1_ERROR_MSK) >> HFSTS_HFS_1_ERROR_SHIFT; 399 mfg_mode = (hfs1 & HFSTS_HFS_1_MFG_MODE_MSK) != 0; 400 fpt_bad = (hfs1 & HFSTS_HFS_1_FPT_BAD_MSK) != 0; 401 bup_fail = (hfs1 & HFSTS_HFS_1_BUP_FAIL_MSK) != 0; 402 fw_init_cmpl = (hfs1 & HFSTS_HFS_1_FW_INIT_CMPL_MSK) != 0; 403 update_inprog = (hfs1 & HFSTS_HFS_1_UPDATE_INPROG_MSK) != 0; 404 405 return (SYSCTL_OUT_STR(req, hfsts_state_summary(cws, opmode, error, 406 mfg_mode, fpt_bad, bup_fail, fw_init_cmpl, update_inprog))); 407 } 408 409 /* Table-driven sysctl registration; skipped when sc_hfs_count < min_hfs. */ 410 typedef int hfsts_sysctl_handler_t(SYSCTL_HANDLER_ARGS); 411 412 struct hfsts_sysctl_def { 413 const char *name; 414 int ctltype; 415 intmax_t arg2; 416 hfsts_sysctl_handler_t *handler; 417 const char *fmt; 418 const char *descr; 419 uint8_t min_hfs; 420 }; 421 422 static const struct hfsts_sysctl_def hfsts_sysctls[] = { 423 { "hfs1", CTLTYPE_U32, 0, hfsts_sysctl_raw, "IU", 424 "Host Firmware Status 1 (raw, live)", 1 }, 425 { "hfs2", CTLTYPE_U32, 1, hfsts_sysctl_raw, "IU", 426 "Host Firmware Status 2 (raw, live)", 2 }, 427 { "hfs3", CTLTYPE_U32, 2, hfsts_sysctl_raw, "IU", 428 "Host Firmware Status 3 (raw, live)", 6 }, 429 { "hfs4", CTLTYPE_U32, 3, hfsts_sysctl_raw, "IU", 430 "Host Firmware Status 4 (raw, live)", 6 }, 431 { "hfs5", CTLTYPE_U32, 4, hfsts_sysctl_raw, "IU", 432 "Host Firmware Status 5 (raw, live)", 6 }, 433 { "hfs6", CTLTYPE_U32, 5, hfsts_sysctl_raw, "IU", 434 "Host Firmware Status 6 (raw, live)", 6 }, 435 { "d0i3_supported", CTLTYPE_U32, HFSTS_FLD_D0I3_SUPPORTED, 436 hfsts_sysctl_field, "IU", 437 "ME D0i3 capability (from HFS1, live)", 6 }, 438 { "opmode", CTLTYPE_U32, HFSTS_FLD_OPMODE, hfsts_sysctl_field, "IU", 439 "ME operation mode (from HFS1, live)", 1 }, 440 { "pm_event", CTLTYPE_U32, HFSTS_FLD_PM_EVENT, hfsts_sysctl_field, 441 "IU", "ME power management event (from HFS2, live)", 2 }, 442 { "fw_sku", CTLTYPE_U32, HFSTS_FLD_FW_SKU, hfsts_sysctl_field, "IU", 443 "ME firmware SKU (from HFS3, live)", 6 }, 444 { "mfg_mode", CTLTYPE_U32, HFSTS_FLD_MFG_MODE, hfsts_sysctl_field, 445 "IU", "ME running in Manufacturing Mode (from HFS1, live)", 1 }, 446 { "update_in_progress", CTLTYPE_U32, HFSTS_FLD_UPDATE_INPROG, 447 hfsts_sysctl_field, "IU", 448 "ME firmware update in progress (from HFS1, live)", 1 }, 449 { "state", CTLTYPE_STRING, HFSTS_DEC_CWS, hfsts_sysctl_decode, "A", 450 "ME Current Working State (from HFS1, live)", 1 }, 451 { "opstate", CTLTYPE_STRING, HFSTS_DEC_OPSTATE, hfsts_sysctl_decode, 452 "A", "ME Current Operation State (from HFS1, live)", 1 }, 453 { "opmode_str", CTLTYPE_STRING, HFSTS_DEC_OPMODE, hfsts_sysctl_decode, 454 "A", "ME Current Operation Mode (from HFS1, live)", 1 }, 455 { "error", CTLTYPE_STRING, HFSTS_DEC_ERROR, hfsts_sysctl_decode, "A", 456 "ME Error Code (from HFS1, live)", 1 }, 457 { "summary", CTLTYPE_STRING, 0, hfsts_sysctl_summary, "A", 458 "One-word ME state summary (live)", 1 }, 459 }; 460 461 static int 462 hfsts_probe(device_t dev) 463 { 464 const struct hfsts_device *id; 465 466 if (pci_get_vendor(dev) != VENDORID_INTEL) 467 return (ENXIO); 468 469 id = hfsts_find_device(dev); 470 if (id == NULL) 471 return (ENXIO); 472 device_set_desc(dev, id->name); 473 return (BUS_PROBE_GENERIC); 474 } 475 476 static int 477 hfsts_attach(device_t dev) 478 { 479 const struct hfsts_device *id; 480 struct hfsts_softc *sc; 481 struct sysctl_oid_list *children; 482 const char *summary; 483 uint32_t hfs1; 484 uint32_t opmode; 485 uint32_t cws, opstate, error, mfg_mode, fpt_bad, fw_init_cmpl; 486 uint32_t bup_fail, update_inprog, boot_opt; 487 u_int i; 488 489 sc = device_get_softc(dev); 490 sc->sc_dev = dev; 491 id = hfsts_find_device(dev); 492 if (id == NULL) 493 return (ENXIO); 494 sc->sc_hfs_count = id->hfs_count; 495 496 /* One-shot read for the attach-time log line only; sysctls re-read. */ 497 hfs1 = hfsts_read_hfs(dev, 0); 498 opmode = (hfs1 & HFSTS_HFS_1_OPMODE_MSK) >> HFSTS_HFS_1_OPMODE_SHIFT; 499 cws = hfs1 & HFSTS_HFS_1_CWS_MSK; 500 opstate = (hfs1 & HFSTS_HFS_1_OPSTATE_MSK) >> HFSTS_HFS_1_OPSTATE_SHIFT; 501 error = (hfs1 & HFSTS_HFS_1_ERROR_MSK) >> HFSTS_HFS_1_ERROR_SHIFT; 502 mfg_mode = (hfs1 & HFSTS_HFS_1_MFG_MODE_MSK) != 0; 503 fpt_bad = (hfs1 & HFSTS_HFS_1_FPT_BAD_MSK) != 0; 504 fw_init_cmpl = (hfs1 & HFSTS_HFS_1_FW_INIT_CMPL_MSK) != 0; 505 bup_fail = (hfs1 & HFSTS_HFS_1_BUP_FAIL_MSK) != 0; 506 update_inprog = (hfs1 & HFSTS_HFS_1_UPDATE_INPROG_MSK) != 0; 507 boot_opt = (hfs1 & HFSTS_HFS_1_BOOT_OPT_MSK) != 0; 508 summary = hfsts_state_summary(cws, opmode, error, mfg_mode, fpt_bad, 509 bup_fail, fw_init_cmpl, update_inprog); 510 511 if (bootverbose) { 512 device_printf(dev, 513 "state=%s opstate=\"%s\" opmode=\"%s\" error=\"%s\" " 514 "mfg_mode=%u fpt_bad=%u fw_init_complete=%u " 515 "update_in_progress=%u boot_options_present=%u\n", 516 HFSTS_DECODE(hfsts_cws_values, cws), 517 HFSTS_DECODE(hfsts_opstate_values, opstate), 518 HFSTS_DECODE(hfsts_opmode_values, opmode), 519 HFSTS_DECODE(hfsts_error_values, error), 520 mfg_mode, fpt_bad, fw_init_cmpl, update_inprog, boot_opt); 521 } 522 523 device_printf(dev, "ME state: %s\n", summary); 524 525 sc->sc_sysctlctx = device_get_sysctl_ctx(dev); 526 sc->sc_sysctlnode = device_get_sysctl_tree(dev); 527 children = SYSCTL_CHILDREN(sc->sc_sysctlnode); 528 529 for (i = 0; i < nitems(hfsts_sysctls); i++) { 530 const struct hfsts_sysctl_def *d = &hfsts_sysctls[i]; 531 532 if (sc->sc_hfs_count < d->min_hfs) 533 continue; 534 sysctl_add_oid(sc->sc_sysctlctx, children, OID_AUTO, d->name, 535 d->ctltype | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, d->arg2, 536 d->handler, d->fmt, __DESCR(d->descr), NULL); 537 } 538 539 return (0); 540 } 541 542 static int 543 hfsts_detach(device_t dev) 544 { 545 546 return (0); 547 } 548 549 static device_method_t hfsts_methods[] = { 550 DEVMETHOD(device_probe, hfsts_probe), 551 DEVMETHOD(device_attach, hfsts_attach), 552 DEVMETHOD(device_detach, hfsts_detach), 553 DEVMETHOD_END 554 }; 555 556 static driver_t hfsts_driver = { 557 "hfsts", 558 hfsts_methods, 559 sizeof(struct hfsts_softc) 560 }; 561 562 DRIVER_MODULE(hfsts, pci, hfsts_driver, 0, 0); 563 MODULE_VERSION(hfsts, 1); 564 MODULE_DEPEND(hfsts, pci, 1, 1, 1); 565