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 }; 106 107 static int pchtherm_probe(device_t dev) 108 { 109 const struct pci_device_table *tbl; 110 111 tbl = PCI_MATCH(dev, pchtherm_devices); 112 if (tbl == NULL) 113 return (ENXIO); 114 device_set_desc(dev, tbl->descr); 115 116 return (BUS_PROBE_DEFAULT); 117 118 } 119 static int pchtherm_tltemp_sysctl(SYSCTL_HANDLER_ARGS) 120 { 121 struct pchtherm_softc *sc = oidp->oid_arg1; 122 int regshift = oidp->oid_arg2; 123 int temp; 124 125 temp = bus_read_4(sc->tbar, PCHTHERM_REG_TL); 126 temp >>= regshift; 127 temp = PCHTHERM_TEMP_TO_IK(temp); 128 129 return sysctl_handle_int(oidp, &temp, 0, req); 130 } 131 static int pchtherm_temp_sysctl(SYSCTL_HANDLER_ARGS) 132 { 133 struct pchtherm_softc *sc = oidp->oid_arg1; 134 int regoff = oidp->oid_arg2; 135 int temp; 136 137 temp = bus_read_2(sc->tbar, regoff); 138 temp = PCHTHERM_TEMP_TO_IK(temp); 139 140 return sysctl_handle_int(oidp, &temp, 0, req); 141 } 142 143 #define FLAG_PRINT(dev, str, val) device_printf \ 144 (dev, str " %s %sable\n", \ 145 ((val) & 0x80)? "Locked" : "", \ 146 ((val) & 0x1)? "En" : "Dis") 147 148 static int pchtherm_attach(device_t dev) 149 { 150 struct pchtherm_softc *sc = device_get_softc(dev); 151 unsigned int val; 152 int flag; 153 int temp; 154 155 sc->tbarrid = PCIR_BAR(0); 156 sc->tbar = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 157 &sc->tbarrid, RF_ACTIVE|RF_SHAREABLE); 158 if (sc->tbar == NULL) { 159 return (ENOMEM); 160 } 161 sc->enable = bus_read_1(sc->tbar, PCHTHERM_REG_TSEL); 162 if (!(sc->enable & PCHTHERM_GEN_ENABLE )) { 163 if (sc->enable & PCHTHERM_GEN_LOCKDOWN) { 164 device_printf(dev, "Sensor not available\n"); 165 return 0; 166 } else { 167 device_printf(dev, "Enabling Sensor\n"); 168 bus_write_1(sc->tbar, PCHTHERM_REG_TSEL, 169 PCHTHERM_GEN_ENABLE); 170 sc->enable = bus_read_1(sc->tbar, PCHTHERM_REG_TSEL); 171 if (!(sc->enable & PCHTHERM_GEN_ENABLE)) { 172 device_printf(dev, "Sensor enable failed\n"); 173 return 0; 174 } 175 } 176 } 177 178 sc->ctten = bus_read_1(sc->tbar, PCHTHERM_REG_TSC); 179 if (bootverbose) { 180 FLAG_PRINT(dev, "Catastrophic Power Down", sc->ctten); 181 } 182 val = bus_read_1(sc->tbar, PCHTHERM_REG_TSREL); 183 if (bootverbose) { 184 FLAG_PRINT(dev, "SMBus report", val); 185 } 186 val = bus_read_1(sc->tbar, PCHTHERM_REG_TSMIC); 187 if (bootverbose) { 188 FLAG_PRINT(dev, "SMI on alert", val); 189 } 190 val = bus_read_2(sc->tbar, PCHTHERM_REG_TSPM); 191 flag = val >> 13; 192 if (bootverbose) { 193 device_printf(dev, "TSPM: %b\n", 194 flag, "\20\3Lock\2DTSS0EN\1DSSOC0"); 195 device_printf(dev, "MAX Thermal Sensor Shutdown Time %ds\n", 196 1<<((val>>9)&7)); 197 } 198 199 temp = val & PCHTHERM_TEMP_MASK; 200 sc->pmtemp = PCHTHERM_TEMP_TO_IK(temp); 201 sc->pmtime = 1<<((val>>9)&7); 202 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 203 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 204 OID_AUTO, "pmtemp", CTLTYPE_INT|CTLFLAG_RD, 205 sc, PCHTHERM_REG_TSPM, pchtherm_temp_sysctl, 206 "IK", "Thermal sensor idle temperature"); 207 SYSCTL_ADD_U32(device_get_sysctl_ctx(dev), 208 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 209 OID_AUTO, "pmtime", CTLFLAG_RD, 210 &sc->pmtime, 0,"Thermal sensor idle duration"); 211 212 val = bus_read_4(sc->tbar, PCHTHERM_REG_TL); 213 flag = val>>29; 214 215 if (bootverbose) { 216 device_printf(dev, "Throttling %b\n", 217 flag, "\20\3Lock\2TT13EN\1TTEN"); 218 } 219 220 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 221 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 222 OID_AUTO, "t0temp", CTLTYPE_INT |CTLFLAG_RD, 223 sc, PCHTHERM_TL_T0, pchtherm_tltemp_sysctl, 224 "IK", "T0 temperature"); 225 226 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 227 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 228 OID_AUTO, "t1temp", CTLTYPE_INT |CTLFLAG_RD, 229 sc, PCHTHERM_TL_T1, pchtherm_tltemp_sysctl, 230 "IK", "T1 temperature"); 231 232 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 233 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 234 OID_AUTO, "t2temp", CTLTYPE_INT |CTLFLAG_RD, 235 sc, PCHTHERM_TL_T2, pchtherm_tltemp_sysctl, 236 "IK", "T2 temperature"); 237 238 val = bus_read_2(sc->tbar, PCHTHERM_REG_TL2); 239 if (bootverbose) { 240 flag = val >>14; 241 device_printf(dev, "TL2 flag %b\n", 242 flag, "\20\1PMCTEN\2Lock"); 243 } 244 245 /* If PHL is disable and lockdown, don't export it.*/ 246 val = bus_read_2(sc->tbar, PCHTHERM_REG_PHLC); 247 val <<= 16; 248 val |= bus_read_2(sc->tbar, PCHTHERM_REG_PHL); 249 if ((val & 0x10000) != 0x10000) { 250 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 251 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 252 OID_AUTO, "pch_hot_level", 253 CTLTYPE_INT |CTLFLAG_RD, 254 sc, PCHTHERM_REG_PHL, 255 pchtherm_temp_sysctl, "IK", 256 "PCH Hot level Temperature"); 257 } 258 259 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 260 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 261 OID_AUTO, "temperature", CTLTYPE_INT |CTLFLAG_RD, 262 sc, PCHTHERM_REG_TEMP, 263 pchtherm_temp_sysctl, "IK", "Current temperature"); 264 /* 265 * If sensor enable bit is locked down, there is no way to change 266 * alart values effectively. 267 */ 268 if (!(sc->enable & PCHTHERM_GEN_LOCKDOWN) || 269 bus_read_2(sc->tbar, PCHTHERM_REG_TAHV) != 0) { 270 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 271 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 272 OID_AUTO, "tahv", CTLTYPE_INT |CTLFLAG_RD, 273 sc, PCHTHERM_REG_TAHV, 274 pchtherm_temp_sysctl, "IK", 275 "Alart High temperature"); 276 } 277 278 if (!(sc->enable & PCHTHERM_GEN_LOCKDOWN) || 279 bus_read_2(sc->tbar, PCHTHERM_REG_TALV) != 0) { 280 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 281 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 282 OID_AUTO, "talv", CTLTYPE_INT |CTLFLAG_RD, 283 sc, PCHTHERM_REG_TALV, 284 pchtherm_temp_sysctl, "IK", 285 "Alart Low temperature"); 286 } 287 if (!(sc->ctten& PCHTHERM_GEN_LOCKDOWN) || 288 sc->ctten& PCHTHERM_GEN_ENABLE) { 289 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 290 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 291 OID_AUTO, "ctt", 292 CTLTYPE_INT |CTLFLAG_RD, 293 sc, PCHTHERM_REG_CTT, 294 pchtherm_temp_sysctl, "IK", 295 "Catastrophic Trip Point"); 296 } 297 298 return 0; 299 } 300 static int pchtherm_detach(device_t dev) 301 { 302 struct pchtherm_softc *sc = device_get_softc(dev); 303 bus_release_resource(dev, SYS_RES_MEMORY, sc->tbarrid, sc->tbar); 304 305 return 0; 306 } 307 308 static device_method_t pchtherm_methods[] = 309 { 310 DEVMETHOD(device_probe, pchtherm_probe), 311 DEVMETHOD(device_attach, pchtherm_attach), 312 DEVMETHOD(device_detach, pchtherm_detach), 313 314 DEVMETHOD_END 315 }; 316 317 static driver_t pchtherm_driver = { 318 "pchtherm", 319 pchtherm_methods, 320 sizeof(struct pchtherm_softc) 321 }; 322 323 DRIVER_MODULE(pchtherm, pci, pchtherm_driver, 0, 0); 324 PCI_PNP_INFO(pchtherm_devices); 325