1 /* 2 * Copyright (c) 2020 Takanori Watanabe 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26 #include <sys/param.h> 27 #include <sys/systm.h> 28 #include <sys/kernel.h> 29 #include <sys/module.h> 30 #include <sys/errno.h> 31 #include <sys/lock.h> 32 #include <sys/mutex.h> 33 #include <sys/sysctl.h> 34 #include <sys/syslog.h> 35 #include <sys/bus.h> 36 37 #include <machine/bus.h> 38 #include <sys/rman.h> 39 #include <machine/resource.h> 40 #include <dev/pci/pcivar.h> 41 #include <dev/pci/pcireg.h> 42 43 #define PCHTHERM_REG_TEMP 0 44 #define PCHTHERM_REG_TSC 4 45 #define PCHTHERM_REG_TSS 6 46 #define PCHTHERM_REG_TSEL 8 47 #define PCHTHERM_REG_TSREL 0xa 48 #define PCHTHERM_REG_TSMIC 0xc 49 #define PCHTHERM_REG_CTT 0x10 50 #define PCHTHERM_REG_TAHV 0x14 51 #define PCHTHERM_REG_TALV 0x18 52 #define PCHTHERM_REG_TSPM 0x1c 53 #define PCHTHERM_REG_TL 0x40 54 #define PCHTHERM_REG_TL2 0x50 55 #define PCHTHERM_REG_PHL 0x60 56 #define PCHTHERM_REG_PHLC 0x62 57 #define PCHTHERM_REG_TAS 0x80 58 #define PCHTHERM_REG_TSPIEN 0x82 59 #define PCHTHERM_REG_TSGPEN 0x84 60 #define PCHTHERM_REG_TCFD 0xf0 61 #define PCHTHERM_GEN_LOCKDOWN 0x80 62 #define PCHTHERM_GEN_ENABLE 1 63 #define PCHTHERM_TEMP_FACTOR 5 64 #define PCHTHERM_TEMP_ZERO 2231 65 #define PCHTHERM_TEMP_MASK 0x1ff 66 #define PCHTHERM_TL_T0 0 67 #define PCHTHERM_TL_T1 10 68 #define PCHTHERM_TL_T2 20 69 #define PCHTHERM_TEMP_TO_IK(val) (((val) & PCHTHERM_TEMP_MASK) * \ 70 PCHTHERM_TEMP_FACTOR + \ 71 PCHTHERM_TEMP_ZERO) 72 73 struct pchtherm_softc 74 { 75 int tbarrid; 76 struct resource *tbar; 77 int enable; 78 int ctten; 79 int pmtemp; 80 unsigned int pmtime; 81 }; 82 83 static const struct pci_device_table pchtherm_devices[] = 84 { 85 { PCI_DEV(0x8086, 0x9c24), 86 PCI_DESCR("Haswell Thermal Subsystem")}, 87 { PCI_DEV(0x8086, 0x8c24), 88 PCI_DESCR("Haswell Thermal Subsystem")}, 89 { PCI_DEV(0x8086, 0x9ca4), 90 PCI_DESCR("Wildcat Point Thermal Subsystem")}, 91 { PCI_DEV(0x8086, 0x9d31), 92 PCI_DESCR("Skylake PCH Thermal Subsystem")}, 93 { PCI_DEV(0x8086, 0xa131), 94 PCI_DESCR("Skylake PCH 100 Thermal Subsystem")}, 95 { PCI_DEV(0x8086, 0x9df9), 96 PCI_DESCR("CannonLake-LP Thermal Subsystem")}, 97 { PCI_DEV(0x8086, 0xa379), 98 PCI_DESCR("CannonLake-H Thermal Subsystem")}, 99 { PCI_DEV(0x8086, 0x02f9), 100 PCI_DESCR("CometLake-LP Thermal Subsystem")}, 101 { PCI_DEV(0x8086, 0x06f9), 102 PCI_DESCR("CometLake-H Thermal Subsystem")}, 103 { PCI_DEV(0x8086, 0xa1b1), 104 PCI_DESCR("Lewisburg Thermal Subsystem")}, 105 { PCI_DEV(0x8086, 0x8d24), 106 PCI_DESCR("Wellsburg Thermal Subsystem")}, 107 }; 108 109 static int pchtherm_probe(device_t dev) 110 { 111 const struct pci_device_table *tbl; 112 113 tbl = PCI_MATCH(dev, pchtherm_devices); 114 if (tbl == NULL) 115 return (ENXIO); 116 device_set_desc(dev, tbl->descr); 117 118 return (BUS_PROBE_DEFAULT); 119 120 } 121 static int pchtherm_tltemp_sysctl(SYSCTL_HANDLER_ARGS) 122 { 123 struct pchtherm_softc *sc = oidp->oid_arg1; 124 int regshift = oidp->oid_arg2; 125 int temp; 126 127 temp = bus_read_4(sc->tbar, PCHTHERM_REG_TL); 128 temp >>= regshift; 129 temp = PCHTHERM_TEMP_TO_IK(temp); 130 131 return sysctl_handle_int(oidp, &temp, 0, req); 132 } 133 static int pchtherm_temp_sysctl(SYSCTL_HANDLER_ARGS) 134 { 135 struct pchtherm_softc *sc = oidp->oid_arg1; 136 int regoff = oidp->oid_arg2; 137 int temp; 138 139 temp = bus_read_2(sc->tbar, regoff); 140 temp = PCHTHERM_TEMP_TO_IK(temp); 141 142 return sysctl_handle_int(oidp, &temp, 0, req); 143 } 144 145 #define FLAG_PRINT(dev, str, val) device_printf \ 146 (dev, str " %s %sable\n", \ 147 ((val) & 0x80)? "Locked" : "", \ 148 ((val) & 0x1)? "En" : "Dis") 149 150 static int pchtherm_attach(device_t dev) 151 { 152 struct pchtherm_softc *sc = device_get_softc(dev); 153 unsigned int val; 154 int flag; 155 int temp; 156 157 sc->tbarrid = PCIR_BAR(0); 158 sc->tbar = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 159 &sc->tbarrid, RF_ACTIVE|RF_SHAREABLE); 160 if (sc->tbar == NULL) { 161 return (ENOMEM); 162 } 163 sc->enable = bus_read_1(sc->tbar, PCHTHERM_REG_TSEL); 164 if (!(sc->enable & PCHTHERM_GEN_ENABLE )) { 165 if (sc->enable & PCHTHERM_GEN_LOCKDOWN) { 166 device_printf(dev, "Sensor not available\n"); 167 return 0; 168 } else { 169 device_printf(dev, "Enabling Sensor\n"); 170 bus_write_1(sc->tbar, PCHTHERM_REG_TSEL, 171 PCHTHERM_GEN_ENABLE); 172 sc->enable = bus_read_1(sc->tbar, PCHTHERM_REG_TSEL); 173 if (!(sc->enable & PCHTHERM_GEN_ENABLE)) { 174 device_printf(dev, "Sensor enable failed\n"); 175 return 0; 176 } 177 } 178 } 179 180 sc->ctten = bus_read_1(sc->tbar, PCHTHERM_REG_TSC); 181 if (bootverbose) { 182 FLAG_PRINT(dev, "Catastrophic Power Down", sc->ctten); 183 } 184 val = bus_read_1(sc->tbar, PCHTHERM_REG_TSREL); 185 if (bootverbose) { 186 FLAG_PRINT(dev, "SMBus report", val); 187 } 188 val = bus_read_1(sc->tbar, PCHTHERM_REG_TSMIC); 189 if (bootverbose) { 190 FLAG_PRINT(dev, "SMI on alert", val); 191 } 192 val = bus_read_2(sc->tbar, PCHTHERM_REG_TSPM); 193 flag = val >> 13; 194 if (bootverbose) { 195 device_printf(dev, "TSPM: %b\n", 196 flag, "\20\3Lock\2DTSS0EN\1DSSOC0"); 197 device_printf(dev, "MAX Thermal Sensor Shutdown Time %ds\n", 198 1<<((val>>9)&7)); 199 } 200 201 temp = val & PCHTHERM_TEMP_MASK; 202 sc->pmtemp = PCHTHERM_TEMP_TO_IK(temp); 203 sc->pmtime = 1<<((val>>9)&7); 204 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 205 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 206 OID_AUTO, "pmtemp", CTLTYPE_INT|CTLFLAG_RD, 207 sc, PCHTHERM_REG_TSPM, pchtherm_temp_sysctl, 208 "IK", "Thermal sensor idle temperature"); 209 SYSCTL_ADD_U32(device_get_sysctl_ctx(dev), 210 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 211 OID_AUTO, "pmtime", CTLFLAG_RD, 212 &sc->pmtime, 0,"Thermal sensor idle duration"); 213 214 val = bus_read_4(sc->tbar, PCHTHERM_REG_TL); 215 flag = val>>29; 216 217 if (bootverbose) { 218 device_printf(dev, "Throttling %b\n", 219 flag, "\20\3Lock\2TT13EN\1TTEN"); 220 } 221 222 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 223 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 224 OID_AUTO, "t0temp", CTLTYPE_INT |CTLFLAG_RD, 225 sc, PCHTHERM_TL_T0, pchtherm_tltemp_sysctl, 226 "IK", "T0 temperature"); 227 228 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 229 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 230 OID_AUTO, "t1temp", CTLTYPE_INT |CTLFLAG_RD, 231 sc, PCHTHERM_TL_T1, pchtherm_tltemp_sysctl, 232 "IK", "T1 temperature"); 233 234 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 235 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 236 OID_AUTO, "t2temp", CTLTYPE_INT |CTLFLAG_RD, 237 sc, PCHTHERM_TL_T2, pchtherm_tltemp_sysctl, 238 "IK", "T2 temperature"); 239 240 val = bus_read_2(sc->tbar, PCHTHERM_REG_TL2); 241 if (bootverbose) { 242 flag = val >>14; 243 device_printf(dev, "TL2 flag %b\n", 244 flag, "\20\1PMCTEN\2Lock"); 245 } 246 247 /* If PHL is disable and lockdown, don't export it.*/ 248 val = bus_read_2(sc->tbar, PCHTHERM_REG_PHLC); 249 val <<= 16; 250 val |= bus_read_2(sc->tbar, PCHTHERM_REG_PHL); 251 if ((val & 0x10000) != 0x10000) { 252 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 253 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 254 OID_AUTO, "pch_hot_level", 255 CTLTYPE_INT |CTLFLAG_RD, 256 sc, PCHTHERM_REG_PHL, 257 pchtherm_temp_sysctl, "IK", 258 "PCH Hot level Temperature"); 259 } 260 261 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 262 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 263 OID_AUTO, "temperature", CTLTYPE_INT |CTLFLAG_RD, 264 sc, PCHTHERM_REG_TEMP, 265 pchtherm_temp_sysctl, "IK", "Current temperature"); 266 /* 267 * If sensor enable bit is locked down, there is no way to change 268 * alart values effectively. 269 */ 270 if (!(sc->enable & PCHTHERM_GEN_LOCKDOWN) || 271 bus_read_2(sc->tbar, PCHTHERM_REG_TAHV) != 0) { 272 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 273 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 274 OID_AUTO, "tahv", CTLTYPE_INT |CTLFLAG_RD, 275 sc, PCHTHERM_REG_TAHV, 276 pchtherm_temp_sysctl, "IK", 277 "Alart High temperature"); 278 } 279 280 if (!(sc->enable & PCHTHERM_GEN_LOCKDOWN) || 281 bus_read_2(sc->tbar, PCHTHERM_REG_TALV) != 0) { 282 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 283 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 284 OID_AUTO, "talv", CTLTYPE_INT |CTLFLAG_RD, 285 sc, PCHTHERM_REG_TALV, 286 pchtherm_temp_sysctl, "IK", 287 "Alart Low temperature"); 288 } 289 if (!(sc->ctten& PCHTHERM_GEN_LOCKDOWN) || 290 sc->ctten& PCHTHERM_GEN_ENABLE) { 291 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 292 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 293 OID_AUTO, "ctt", 294 CTLTYPE_INT |CTLFLAG_RD, 295 sc, PCHTHERM_REG_CTT, 296 pchtherm_temp_sysctl, "IK", 297 "Catastrophic Trip Point"); 298 } 299 300 return 0; 301 } 302 static int pchtherm_detach(device_t dev) 303 { 304 struct pchtherm_softc *sc = device_get_softc(dev); 305 bus_release_resource(dev, SYS_RES_MEMORY, sc->tbarrid, sc->tbar); 306 307 return 0; 308 } 309 310 static device_method_t pchtherm_methods[] = 311 { 312 DEVMETHOD(device_probe, pchtherm_probe), 313 DEVMETHOD(device_attach, pchtherm_attach), 314 DEVMETHOD(device_detach, pchtherm_detach), 315 316 DEVMETHOD_END 317 }; 318 319 static driver_t pchtherm_driver = { 320 "pchtherm", 321 pchtherm_methods, 322 sizeof(struct pchtherm_softc) 323 }; 324 325 DRIVER_MODULE(pchtherm, pci, pchtherm_driver, 0, 0); 326 PCI_PNP_INFO(pchtherm_devices); 327